From 4c48653ccc17eb041526884a3c010e4c6f0797f6 Mon Sep 17 00:00:00 2001 From: dreamsourcelab tai Date: Thu, 30 Sep 2021 11:17:04 +0800 Subject: [PATCH 01/60] suppor make zip in memory --- DSView/pv/ZipMaker.cpp | 199 +++++++++++++++++++++++++++++++++++++++++ DSView/pv/ZipMaker.h | 60 +++++++++++++ 2 files changed, 259 insertions(+) create mode 100644 DSView/pv/ZipMaker.cpp create mode 100644 DSView/pv/ZipMaker.h diff --git a/DSView/pv/ZipMaker.cpp b/DSView/pv/ZipMaker.cpp new file mode 100644 index 00000000..cdda2d33 --- /dev/null +++ b/DSView/pv/ZipMaker.cpp @@ -0,0 +1,199 @@ + +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2012 Joel Holdsworth + * Copyright (C) 2013 DreamSourceLab + * + * 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 "ZipMaker.h" +#include +#include +#include +#include +#include +#include + + +ZipMaker::ZipMaker() : + m_docSource(NULL), + m_errobj(NULL) +{ + m_error[0] = 0; +} + +ZipMaker::~ZipMaker() +{ + Release(); +} + +bool ZipMaker::CreateNew() +{ + Release(); + + m_errobj = new zip_error_t(); + zip_error_init(m_errobj); + + if ((m_docSource = zip_source_buffer_create(NULL, 0, 0, m_errobj)) == NULL) { + sprintf(m_error, "can't create source: %s", zip_error_strerror(m_errobj)); + } + + return m_docSource != NULL; +} + +void ZipMaker::Release() +{ + if (m_errobj){ + zip_error_fini(m_errobj); //release the error obj + delete m_errobj; + m_errobj = NULL; + } + + if (m_docSource){ + zip_source_free(m_docSource); + m_docSource = NULL; + } +} + +bool ZipMaker::SaveToFile(const char *fileName){ + assert(fileName); + assert(m_docSource); + + zip_stat_t zst; + if (zip_source_stat(m_docSource, &zst) < 0) { + sprintf(m_error, "can't stat source: %s\n", zip_error_strerror(zip_source_error(m_docSource))); + return 1; + } + + long long size = zst.size; + void *data = NULL; + FILE *fp = NULL; + bool berr = false; + + if (zip_source_open(m_docSource) < 0) { + sprintf(m_error, "can't open source: %s\n", zip_error_strerror(zip_source_error(m_docSource))); + return false; + } + if (!berr && (data = malloc(size)) == NULL) { + sprintf(m_error, "malloc failed: %s\n", strerror(errno)); + berr = true; + } + + if ((zip_uint64_t)zip_source_read(m_docSource, data, size) < size) { + sprintf(m_error, "can't read data from source: %s\n", zip_error_strerror(zip_source_error(m_docSource))); + berr = true; + } + + if (!berr && (fp = fopen(fileName, "wb")) == NULL) { + sprintf(m_error, "can't open %s: %s\n", fileName, strerror(errno)); + berr = true; + } + if (!berr && fwrite(data, 1, size, fp) < size) { + sprintf(m_error, "can't write %s: %s\n", fileName, strerror(errno)); + berr = true; + fclose(fp); + } + if (!berr && fclose(fp) < 0) { + sprintf(m_error, "can't write %s: %s\n", fileName, strerror(errno)); + berr = true; + } + + zip_source_close(m_docSource); + if (data){ + free(data); + } + + return !berr; +} + +bool ZipMaker::AddFromBuffer(const char *innerFile, const char *buffer, int buferSize) +{ + assert(buffer); + assert(innerFile); + assert(m_docSource); + + zip_t *zip_archive = zip_open_from_source(m_docSource, 0, m_errobj); + if (zip_archive == NULL) + { + sprintf(m_error, "can't open zip from source: %s", zip_error_strerror(m_errobj)); + return false; + } + + zip_source_keep(m_docSource); + + zip_source_t *src = zip_source_buffer(zip_archive, buffer, buferSize, 0); + if (src == NULL){ + sprintf(m_error, "zip_source_buffer error: %s", zip_error_strerror(zip_source_error(m_docSource))); + return false; + } + + if (zip_file_add(zip_archive, innerFile, src, ZIP_FL_OVERWRITE) == -1) + { + sprintf(m_error, "zip_file_add error: %s", zip_error_strerror(zip_source_error(m_docSource))); + return false; + } + + if (zip_close(zip_archive) < 0) { + sprintf(m_error, "zip_close'%s'", zip_strerror(zip_archive)); + return false; + } + + return true; +} + +bool ZipMaker::AddFromFile(const char *localFile, const char *innerFile) +{ + assert(localFile); + assert(innerFile); + assert(m_docSource); + + zip_t *zip_archive = zip_open_from_source(m_docSource, 0, m_errobj); + if (zip_archive == NULL) + { + sprintf(m_error, "can't open zip from source: %s", zip_error_strerror(m_errobj)); + return false; + } + + zip_source_keep(m_docSource); + + zip_source_t *src = zip_source_file(zip_archive, localFile, 0, -1); + if (src == NULL){ + sprintf(m_error, "zip_source_buffer error: %s\n", zip_error_strerror(zip_source_error(m_docSource))); + return false; + } + + if (zip_add(zip_archive, innerFile, src) == -1) + { + sprintf(m_error, "zip_file_add error: %s\n", zip_error_strerror(zip_source_error(m_docSource))); + return false; + } + + if (zip_close(zip_archive) < 0) { + sprintf(m_error, "zip_close'%s'", zip_strerror(zip_archive)); + return false; + } + + return true; +} + +const char *ZipMaker::GetError() +{ + if (m_error[0]) + return m_error; + return NULL; +} diff --git a/DSView/pv/ZipMaker.h b/DSView/pv/ZipMaker.h new file mode 100644 index 00000000..621d16d7 --- /dev/null +++ b/DSView/pv/ZipMaker.h @@ -0,0 +1,60 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2012 Joel Holdsworth + * Copyright (C) 2013 DreamSourceLab + * + * 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 + */ + +#pragma once + +struct zip_source; +struct zip_error; + +typedef struct zip_source zip_archive_source_t; +typedef struct zip_error zip_err_t; + +class ZipMaker +{ +public: + ZipMaker(); + + ~ZipMaker(); + + //create new zip archive in the memory + bool CreateNew(); + + //free the source + void Release(); + + //save data to file + bool SaveToFile(const char *fileName); + + //add a inner file from buffer + bool AddFromBuffer(const char *innerFile, const char *buffer, int buferSize); + + //add a inner file from local file + bool AddFromFile(const char *localFile, const char *innerFile); + + //get the last error + const char *GetError(); + +private: + zip_archive_source_t *m_docSource; //zip file handle + zip_err_t *m_errobj; + char m_error[500]; +}; From 5933cc4b1b28aae44b196053beb9c0022896136f Mon Sep 17 00:00:00 2001 From: dreamsourcelab tai Date: Thu, 30 Sep 2021 11:40:45 +0800 Subject: [PATCH 02/60] zip marker --- DSView/main.cpp | 7 +- DSView/pv/devicemanager.cpp | 2 +- DSView/pv/dialogs/storeprogress.cpp | 2 +- DSView/pv/mainframe.cpp | 5 +- DSView/pv/mainwindow.cpp | 3 +- DSView/pv/mainwindow.h | 4 +- DSView/pv/sigsession.cpp | 9 +- DSView/pv/sigsession.h | 3 + DSView/pv/storesession.cpp | 70 +++++++++- DSView/pv/storesession.h | 2 + DSView/pv/toolbars/filebar.h | 12 +- DSView/pv/toolbars/logobar.h | 10 +- DSView/pv/toolbars/samplingbar.h | 198 ++++++++++++++-------------- DSView/pv/toolbars/titlebar.cpp | 3 +- DSView/pv/toolbars/titlebar.h | 75 ++++++----- DSView/pv/toolbars/trigbar.h | 8 +- DSView/pv/view/analogsignal.h | 2 + DSView/pv/view/cursor.h | 1 + DSView/pv/view/dsldial.cpp | 4 +- DSView/pv/view/dsldial.h | 2 + DSView/pv/view/dsosignal.h | 2 + DSView/pv/view/groupsignal.h | 1 + DSView/pv/view/header.cpp | 3 + DSView/pv/view/header.h | 2 + DSView/pv/view/lissajoustrace.h | 4 +- DSView/pv/view/logicsignal.h | 2 + DSView/pv/view/ruler.cpp | 2 +- DSView/pv/view/ruler.h | 2 + DSView/pv/view/selectableitem.h | 1 + DSView/pv/view/signal.h | 1 + DSView/pv/view/spectrumtrace.h | 2 + DSView/pv/view/timemarker.h | 1 + DSView/pv/view/view.h | 1 + DSView/pv/view/viewport.cpp | 13 +- DSView/pv/view/viewport.h | 3 + DSView/pv/view/viewstatus.h | 7 +- DSView/pv/view/xcursor.cpp | 2 +- DSView/pv/view/xcursor.h | 2 + libsigrok4DSL/hardware/demo/demo.h | 5 +- libsigrok4DSL/session_file.c | 1 + 40 files changed, 305 insertions(+), 174 deletions(-) diff --git a/DSView/main.cpp b/DSView/main.cpp index cb3d83ae..fa87b03c 100755 --- a/DSView/main.cpp +++ b/DSView/main.cpp @@ -161,16 +161,17 @@ int main(int argc, char *argv[]) dir.cd("share") && dir.cd(QApplication::applicationName()) && dir.cd("res")) { + // the path command like: cd ../share/DSView/res QString res_dir = dir.absolutePath() + "/"; strcpy(DS_RES_PATH, res_dir.toUtf8().data()); } else { - qDebug() << "ERROR: config files don't exist."; + qDebug() << "DSView run ERROR: config files don't exist."; return 1; } // Initialise libsigrok if (sr_init(&sr_ctx) != SR_OK) { - qDebug() << "ERROR: libsigrok init failed."; + qDebug() << "DSView run ERROR: libsigrok init failed."; return 1; } @@ -194,7 +195,7 @@ int main(int argc, char *argv[]) pv::MainFrame w(device_manager, open_file); w.show(); w.readSettings(); - w.show_doc(); + w.show_doc(); // to show the dailog for open help document // Run the application ret = a.exec(); diff --git a/DSView/pv/devicemanager.cpp b/DSView/pv/devicemanager.cpp index d7778be5..aacfd7d1 100755 --- a/DSView/pv/devicemanager.cpp +++ b/DSView/pv/devicemanager.cpp @@ -105,7 +105,7 @@ std::list > DeviceManager::driver_scan( } else { i++; } - } + } // Clear all the old device instances from this driver sr_dev_clear(driver); diff --git a/DSView/pv/dialogs/storeprogress.cpp b/DSView/pv/dialogs/storeprogress.cpp index 2bb91a18..b74daaa4 100755 --- a/DSView/pv/dialogs/storeprogress.cpp +++ b/DSView/pv/dialogs/storeprogress.cpp @@ -69,7 +69,7 @@ void StoreProgress::timeout() if (_done) { _store_session.session().set_saving(false); save_done(); - close(); + close(); } else { QTimer::singleShot(100, this, SLOT(timeout())); } diff --git a/DSView/pv/mainframe.cpp b/DSView/pv/mainframe.cpp index 4ed79087..714de50b 100755 --- a/DSView/pv/mainframe.cpp +++ b/DSView/pv/mainframe.cpp @@ -77,11 +77,10 @@ MainFrame::MainFrame(DeviceManager &device_manager, // Title _titleBar = new toolbars::TitleBar(true, this); _titleBar->installEventFilter(this); - + // MainWindow _mainWindow = new MainWindow(device_manager, open_file_name, this); _mainWindow->setWindowFlags(Qt::Widget); - _titleBar->setTitle(_mainWindow->windowTitle()); QVBoxLayout *vbox = new QVBoxLayout(); @@ -185,7 +184,7 @@ void MainFrame::hide_border() } void MainFrame::show_border() -{ +{ _top_left->setVisible(true); _top_right->setVisible(true); _top->setVisible(true); diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index 2fea92dd..746f34f2 100755 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -870,6 +870,7 @@ void MainWindow::on_screenShot() } } +//save file void MainWindow::on_save() { using pv::dialogs::StoreProgress; @@ -1227,7 +1228,7 @@ bool MainWindow::store_session(QString name) QJsonDocument sessionDoc(sessionVar); //sessionFile.write(QString::fromUtf8(sessionDoc.toJson())); outStream << QString::fromUtf8(sessionDoc.toJson()); - sessionFile.close(); + sessionFile.close(); return true; } diff --git a/DSView/pv/mainwindow.h b/DSView/pv/mainwindow.h index 0af21189..0069b1e5 100755 --- a/DSView/pv/mainwindow.h +++ b/DSView/pv/mainwindow.h @@ -63,6 +63,8 @@ namespace view { class View; } +//The mainwindow,referenced by MainFrame +//TODO: create graph view,toolbar,and show device list class MainWindow : public QMainWindow { Q_OBJECT @@ -186,7 +188,7 @@ private: toolbars::SamplingBar *_sampling_bar; toolbars::TrigBar *_trig_bar; toolbars::FileBar *_file_bar; - toolbars::LogoBar *_logo_bar; + toolbars::LogoBar *_logo_bar; //help button, on top right #ifdef ENABLE_DECODE QDockWidget *_protocol_dock; diff --git a/DSView/pv/sigsession.cpp b/DSView/pv/sigsession.cpp index f55f1058..df1afdc0 100755 --- a/DSView/pv/sigsession.cpp +++ b/DSView/pv/sigsession.cpp @@ -156,6 +156,9 @@ boost::shared_ptr SigSession::get_device() const return _dev_inst; } +/* + when be called, it will call 4DSL lib sr_session_new, and create a session struct in the lib +*/ void SigSession::set_device(boost::shared_ptr dev_inst) { using pv::device::Device; @@ -746,8 +749,8 @@ void SigSession::init_signals() switch(probe->type) { case SR_CHANNEL_LOGIC: if (probe->enabled) - signal = boost::shared_ptr( - new view::LogicSignal(_dev_inst, _logic_data, probe)); + signal = boost::shared_ptr( + new view::LogicSignal(_dev_inst, _logic_data, probe)); break; case SR_CHANNEL_DSO: @@ -803,7 +806,7 @@ void SigSession::reload() boost::shared_ptr logicSig; if ((logicSig = dynamic_pointer_cast(*i))) signal = boost::shared_ptr( - new view::LogicSignal(logicSig, _logic_data, probe)); + new view::LogicSignal(logicSig, _logic_data, probe)); break; } i++; diff --git a/DSView/pv/sigsession.h b/DSView/pv/sigsession.h index 96fd0649..0f9d46ca 100755 --- a/DSView/pv/sigsession.h +++ b/DSView/pv/sigsession.h @@ -92,6 +92,7 @@ class Decoder; class DecoderFactory; } +//created by MainWindow class SigSession : public QObject { Q_OBJECT @@ -291,8 +292,10 @@ private: void feed_in_logic(const sr_datafeed_logic &logic); void feed_in_dso(const sr_datafeed_dso &dso); void feed_in_analog(const sr_datafeed_analog &analog); + void data_feed_in(const struct sr_dev_inst *sdi, const struct sr_datafeed_packet *packet); + static void data_feed_in_proc(const struct sr_dev_inst *sdi, const struct sr_datafeed_packet *packet, void *cb_data); diff --git a/DSView/pv/storesession.cpp b/DSView/pv/storesession.cpp index d41881ac..18ad1bd5 100755 --- a/DSView/pv/storesession.cpp +++ b/DSView/pv/storesession.cpp @@ -60,6 +60,20 @@ using std::vector; namespace pv { + char chunk_name[30] = {0}; + + void MakeChunkName(int chunk_num, int index, int type, int version){ + if (version == 2) { + const char *type_name = NULL; + type_name = (type == SR_CHANNEL_LOGIC) ? "L" : + (type == SR_CHANNEL_DSO) ? "O" : + (type == SR_CHANNEL_ANALOG) ? "A" : "U"; + snprintf(chunk_name, 15, "%s-%d/%d", type_name, index, chunk_num); + } else { + snprintf(chunk_name, 15, "data"); + } + } + StoreSession::StoreSession(SigSession &session) : _session(session), _outModule(NULL), @@ -179,6 +193,8 @@ bool StoreSession::save_start(QString session_file) #else QString decoders_file = NULL; #endif + + /* if (meta_file == NULL) { _error = tr("Generate temp file failed."); } else { @@ -193,6 +209,23 @@ bool StoreSession::save_start(QString session_file) return !_has_error; } } + */ + + //make zip file + if (meta_file != NULL && m_zipDoc.CreateNew()) + { + if ( !m_zipDoc.AddFromFile(meta_file.toUtf8().data(), "header") + || !m_zipDoc.AddFromFile(decoders_file.toUtf8().data(), "decoders") + || !m_zipDoc.AddFromFile(session_file.toUtf8().data(), "session")) + { + _has_error = true; + _error = m_zipDoc.GetError(); + } + else{ + _thread = boost::thread(&StoreSession::save_proc, this, snapshot); + return !_has_error; + } + } } QFile::remove(_file_name); @@ -239,8 +272,13 @@ void StoreSession::save_proc(shared_ptr snapshot) memset(buf, sample ? 0xff : 0x0, size); } } - ret = sr_session_append(_file_name.toUtf8().data(), buf, size, - i, ch_index, ch_type, File_Version); + + // ret = sr_session_append(_file_name.toUtf8().data(), buf, size, + // i, ch_index, ch_type, File_Version); + + MakeChunkName(i, ch_index, ch_type, File_Version); + ret = m_zipDoc.AddFromBuffer(chunk_name, (const char*)buf, size) ? SR_OK : -1; + if (ret != SR_OK) { if (!_has_error) { _has_error = true; @@ -285,19 +323,30 @@ void StoreSession::save_proc(shared_ptr snapshot) memcpy(tmp, buf, buf_end-buf); memcpy(tmp+(buf_end-buf), buf_start, buf+size-buf_end); } - ret = sr_session_append(_file_name.toUtf8().data(), tmp, size, - i, 0, ch_type, File_Version); + + ret = sr_session_append(_file_name.toUtf8().data(), tmp, size, + i, 0, ch_type, File_Version); + + MakeChunkName(i, 0, ch_type, File_Version); + ret = m_zipDoc.AddFromBuffer(chunk_name, (const char*)tmp, size) ? SR_OK : -1; + buf += (size - _unit_count); if (tmp) free(tmp); } else { - ret = sr_session_append(_file_name.toUtf8().data(), buf, size, - i, 0, ch_type, File_Version); + + // ret = sr_session_append(_file_name.toUtf8().data(), buf, size, + // i, 0, ch_type, File_Version); + + MakeChunkName(i, 0, ch_type, File_Version); + ret = m_zipDoc.AddFromBuffer(chunk_name, (const char*)buf, size) ? SR_OK : -1; + buf += size; } if (ret != SR_OK) { if (!_has_error) { _has_error = true; + auto err = m_zipDoc.GetError(); _error = tr("Failed to create zip file. Please check write permission of this path."); } progress_updated(); @@ -314,6 +363,15 @@ void StoreSession::save_proc(shared_ptr snapshot) if (_canceled || num == 0) QFile::remove(_file_name); + else { + bool bret = m_zipDoc.SaveToFile(_file_name.toUtf8().data()); + m_zipDoc.Release(); + + if (!bret){ + _has_error = true; + _error = m_zipDoc.GetError(); + } + } } QString StoreSession::meta_gen(boost::shared_ptr snapshot) diff --git a/DSView/pv/storesession.h b/DSView/pv/storesession.h index 2f369385..09dc4e3a 100755 --- a/DSView/pv/storesession.h +++ b/DSView/pv/storesession.h @@ -31,6 +31,7 @@ #include #include +#include "ZipMaker.h" namespace pv { @@ -106,6 +107,7 @@ private: bool _has_error; QString _error; bool _canceled; + ZipMaker m_zipDoc; }; } // pv diff --git a/DSView/pv/toolbars/filebar.h b/DSView/pv/toolbars/filebar.h index 3696fab5..0f55c3db 100755 --- a/DSView/pv/toolbars/filebar.h +++ b/DSView/pv/toolbars/filebar.h @@ -33,6 +33,8 @@ namespace pv { namespace toolbars { +//toolbar button,referenced by MainWindow +//TODO: load session file, sorte session, load log data file, sorte data, export data class FileBar : public QToolBar { Q_OBJECT @@ -55,12 +57,12 @@ private: const QString text, const QString info_text); signals: - void load_file(QString); + void load_file(QString); void on_save(); void on_export(); - void on_screenShot(); - void load_session(QString); - void store_session(QString); + void on_screenShot(); //post screen capture event message + void load_session(QString); //post load session event message + void store_session(QString); //post store session event message private slots: void on_actionLoad_triggered(); @@ -77,7 +79,7 @@ private: QMenu *_menu; - QMenu *_menu_session; + QMenu *_menu_session; //when the hardware device is connected,it will be enable QAction *_action_load; QAction *_action_store; QAction *_action_default; diff --git a/DSView/pv/toolbars/logobar.h b/DSView/pv/toolbars/logobar.h index caf686c5..691793a7 100755 --- a/DSView/pv/toolbars/logobar.h +++ b/DSView/pv/toolbars/logobar.h @@ -35,6 +35,8 @@ namespace pv { namespace toolbars { +//The tool button for help,is a ui class,referenced by MainWindow +//TODO: switch language,submit bug descript, class LogoBar : public QToolBar { Q_OBJECT @@ -44,6 +46,7 @@ public: void enable_toggle(bool enable); + //show the hardware device conneted status with logo picture void dsl_connected(bool conn); private: @@ -57,8 +60,11 @@ private: const QString text, const QString info_text); signals: - void setLanguage(int language); - void openDoc(); + //post event message to set language, MainWindow class receive it + void setLanguage(int language); + + //post event message to open user help document, MainWindow class receive it + void openDoc(); private slots: void on_actionEn_triggered(); diff --git a/DSView/pv/toolbars/samplingbar.h b/DSView/pv/toolbars/samplingbar.h index 567eff1f..a19298b9 100755 --- a/DSView/pv/toolbars/samplingbar.h +++ b/DSView/pv/toolbars/samplingbar.h @@ -19,7 +19,6 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - #ifndef DSVIEW_PV_TOOLBARS_SAMPLINGBAR_H #define DSVIEW_PV_TOOLBARS_SAMPLINGBAR_H @@ -40,134 +39,137 @@ struct st_dev_inst; class QAction; -namespace pv { +namespace pv +{ + class SigSession; -class SigSession; + namespace device + { + // class DevInst; + } -namespace device { -class DevInst; -} + namespace dialogs + { + class deviceoptions; + class Calibration; + } -namespace dialogs { -class deviceoptions; -class Calibration; -} + namespace toolbars + { -namespace toolbars { + class SamplingBar : public QToolBar + { + Q_OBJECT -class SamplingBar : public QToolBar -{ - Q_OBJECT + private: + static const int ComboBoxMaxWidth = 200; + static const int RefreshShort = 500; + static const uint64_t LogicMaxSWDepth64 = SR_GB(16); + static const uint64_t LogicMaxSWDepth32 = SR_GB(8); + static const uint64_t AnalogMaxSWDepth = SR_Mn(100); + static const QString RLEString; + static const QString DIVString; + static const uint64_t ZeroTimeBase = SR_US(2); -private: - static const int ComboBoxMaxWidth = 200; - static const int RefreshShort = 500; - static const uint64_t LogicMaxSWDepth64 = SR_GB(16); - static const uint64_t LogicMaxSWDepth32 = SR_GB(8); - static const uint64_t AnalogMaxSWDepth = SR_Mn(100); - static const QString RLEString; - static const QString DIVString; - static const uint64_t ZeroTimeBase = SR_US(2); + public: + SamplingBar(SigSession &session, QWidget *parent); -public: - SamplingBar(SigSession &session, QWidget *parent); + void set_device_list(const std::list> &devices, + boost::shared_ptr selected); - void set_device_list(const std::list< boost::shared_ptr > &devices, - boost::shared_ptr selected); + boost::shared_ptr get_selected_device() const; - boost::shared_ptr get_selected_device() const; + void update_sample_rate_selector(); - void update_sample_rate_selector(); + void set_sampling(bool sampling); + bool get_sampling() const; + bool get_instant() const; - void set_sampling(bool sampling); - bool get_sampling() const; - bool get_instant() const; + void enable_toggle(bool enable); - void enable_toggle(bool enable); + void enable_run_stop(bool enable); - void enable_run_stop(bool enable); + void enable_instant(bool enable); - void enable_instant(bool enable); + double hori_knob(int dir); + double commit_hori_res(); + double get_hori_res(); - double hori_knob(int dir); - double commit_hori_res(); - double get_hori_res(); + public slots: + void set_sample_rate(uint64_t sample_rate); -public slots: - void set_sample_rate(uint64_t sample_rate); + signals: + void run_stop(); + void instant_stop(); + void device_selected(); + void device_updated(); + void duration_changed(); + void show_calibration(); + void hide_calibration(); -signals: - void run_stop(); - void instant_stop(); - void device_selected(); - void device_updated(); - void duration_changed(); - void show_calibration(); - void hide_calibration(); + private: + void changeEvent(QEvent *event); + void retranslateUi(); + void reStyle(); -private: - void changeEvent(QEvent *event); - void retranslateUi(); - void reStyle(); + void update_sample_rate_selector_value(); + void update_sample_count_selector(); + void update_sample_count_selector_value(); + void commit_settings(); + void setting_adj(); - void update_sample_rate_selector_value(); - void update_sample_count_selector(); - void update_sample_count_selector_value(); - void commit_settings(); - void setting_adj(); + private slots: + void on_mode(); + void on_run_stop(); + void on_instant_stop(); + void on_device_selected(); + void on_samplerate_sel(int index); + void on_samplecount_sel(int index); -private slots: - void on_mode(); - void on_run_stop(); - void on_instant_stop(); - void on_device_selected(); - void on_samplerate_sel(int index); - void on_samplecount_sel(int index); + void show_session_error( + const QString text, const QString info_text); - void show_session_error( - const QString text, const QString info_text); + public slots: + void on_configure(); + void zero_adj(); + void reload(); -public slots: - void on_configure(); - void zero_adj(); - void reload(); + private: + SigSession &_session; -private: - SigSession &_session; + mutable boost::recursive_mutex _sampling_mutex; + bool _enable; + bool _sampling; - mutable boost::recursive_mutex _sampling_mutex; - bool _enable; - bool _sampling; + QToolButton _device_type; - QToolButton _device_type; + QComboBox _device_selector; + std::map> + _device_selector_map; + bool _updating_device_selector; - QComboBox _device_selector; - std::map > - _device_selector_map; - bool _updating_device_selector; + QToolButton _configure_button; - QToolButton _configure_button; + QComboBox _sample_count; + QComboBox _sample_rate; + bool _updating_sample_rate; + bool _updating_sample_count; - QComboBox _sample_count; - QComboBox _sample_rate; - bool _updating_sample_rate; - bool _updating_sample_count; + QToolButton _run_stop_button; + QToolButton _instant_button; + QAction *_run_stop_action; + QAction *_instant_action; - QToolButton _run_stop_button; - QToolButton _instant_button; - QAction* _run_stop_action; - QAction* _instant_action; + QAction *_mode_action; + QToolButton _mode_button; + QMenu *_mode_menu; + QAction *_action_repeat; + QAction *_action_single; - QAction* _mode_action; - QToolButton _mode_button; - QMenu *_mode_menu; - QAction *_action_repeat; - QAction *_action_single; + bool _instant; + }; - bool _instant; -}; - -} // namespace toolbars + } // namespace toolbars } // namespace pv #endif // DSVIEW_PV_TOOLBARS_SAMPLINGBAR_H diff --git a/DSView/pv/toolbars/titlebar.cpp b/DSView/pv/toolbars/titlebar.cpp index ed595925..dffb4bc4 100755 --- a/DSView/pv/toolbars/titlebar.cpp +++ b/DSView/pv/toolbars/titlebar.cpp @@ -101,7 +101,7 @@ void TitleBar::reStyle() } void TitleBar::paintEvent(QPaintEvent *event) -{ +{ QStyleOption o; o.initFrom(this); QPainter p(this); @@ -109,6 +109,7 @@ void TitleBar::paintEvent(QPaintEvent *event) p.setRenderHint(QPainter::Antialiasing, true); + //To draw product logo const int xgap = 2; const int xstart = 10; p.setPen(QPen(QColor(213, 15, 37, 255), 2, Qt::SolidLine)); diff --git a/DSView/pv/toolbars/titlebar.h b/DSView/pv/toolbars/titlebar.h index d48878b1..5463af2f 100755 --- a/DSView/pv/toolbars/titlebar.h +++ b/DSView/pv/toolbars/titlebar.h @@ -26,50 +26,55 @@ class QLabel; class QToolButton; -namespace pv { -namespace toolbars { - -class TitleBar : public QWidget +namespace pv { - Q_OBJECT + namespace toolbars + { -public: - TitleBar(bool top, QWidget *parent, bool hasClose = false); - void setTitle(QString title); - QPoint get_startPos() const; - QString title() const; +//Window's titlebar, referenced by MainFrame, +//The title area above the main screen, +//Display logo and maximize \ minimize button + class TitleBar : public QWidget + { + Q_OBJECT -private: - void changeEvent(QEvent *event); - void reStyle(); + public: + TitleBar(bool top, QWidget *parent, bool hasClose = false); + void setTitle(QString title); + QPoint get_startPos() const; + QString title() const; -signals: - void normalShow(); - void maximizedShow(); + private: + void changeEvent(QEvent *event); + void reStyle(); -public slots: - void showMaxRestore(); - void setRestoreButton(bool max); + signals: + void normalShow(); + void maximizedShow(); -protected: - void paintEvent(QPaintEvent *event); - void mousePressEvent(QMouseEvent *event); - void mouseMoveEvent(QMouseEvent *event); - void mouseReleaseEvent(QMouseEvent *event); - void mouseDoubleClickEvent(QMouseEvent *event); + public slots: + void showMaxRestore(); + void setRestoreButton(bool max); - QLabel *_title; - QToolButton *_minimizeButton; - QToolButton *_maximizeButton; - QToolButton *_closeButton; + protected: + void paintEvent(QPaintEvent *event); + void mousePressEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void mouseDoubleClickEvent(QMouseEvent *event); - bool _moving; - bool _isTop; - bool _hasClose; - QPoint _startPos; -}; + QLabel *_title; + QToolButton *_minimizeButton; + QToolButton *_maximizeButton; + QToolButton *_closeButton; -} // namespace toolbars + bool _moving; + bool _isTop; + bool _hasClose; + QPoint _startPos; + }; + + } // namespace toolbars } // namespace pv #endif // DSVIEW_PV_TOOLBARS_TITLEBAR_H diff --git a/DSView/pv/toolbars/trigbar.h b/DSView/pv/toolbars/trigbar.h index 6a86218f..fbddf0e0 100755 --- a/DSView/pv/toolbars/trigbar.h +++ b/DSView/pv/toolbars/trigbar.h @@ -34,6 +34,8 @@ class SigSession; namespace toolbars { +//boolbar, referenced by MainWindow +//TODO:show the property panel about protocol\trigger class TrigBar : public QToolBar { Q_OBJECT @@ -57,9 +59,9 @@ private: signals: void setTheme(QString style); - void on_protocol(bool visible); - void on_trigger(bool visible); - void on_measure(bool visible); + void on_protocol(bool visible); //post decode button click event,to show or hide protocol property panel + void on_trigger(bool visible); //post decode button click event,to show or hide trigger property panel + void on_measure(bool visible);//post decode button click event,to show or hide measure property panel void on_search(bool visible); void show_lissajous(bool visible); diff --git a/DSView/pv/view/analogsignal.h b/DSView/pv/view/analogsignal.h index ac7ff67a..0555175d 100755 --- a/DSView/pv/view/analogsignal.h +++ b/DSView/pv/view/analogsignal.h @@ -37,6 +37,8 @@ class AnalogSnapshot; namespace view { +//when device is data acquisition model, to draw trace +//created by SigSession class AnalogSignal : public Signal { Q_OBJECT diff --git a/DSView/pv/view/cursor.h b/DSView/pv/view/cursor.h index 0248c9ce..2a33a8f2 100755 --- a/DSView/pv/view/cursor.h +++ b/DSView/pv/view/cursor.h @@ -33,6 +33,7 @@ class QPainter; namespace pv { namespace view { +//created by View class Cursor : public TimeMarker { Q_OBJECT diff --git a/DSView/pv/view/dsldial.cpp b/DSView/pv/view/dsldial.cpp index f20c872c..618817b1 100755 --- a/DSView/pv/view/dsldial.cpp +++ b/DSView/pv/view/dsldial.cpp @@ -48,7 +48,7 @@ dslDial::~dslDial() } void dslDial::paint(QPainter &p, QRectF dialRect, QColor dialColor, const QPoint pt, QString &pText) -{ +{ p.setPen(dialColor); p.setBrush(dialColor); @@ -108,6 +108,8 @@ void dslDial::paint(QPainter &p, QRectF dialRect, QColor dialColor, const QPoint inc ? 10 : -10, hoverRect.width()/2 + 4); p.restore(); } + + (void*)0; } void dslDial::set_sel(uint64_t sel) diff --git a/DSView/pv/view/dsldial.h b/DSView/pv/view/dsldial.h index 973e0e6e..120b491c 100755 --- a/DSView/pv/view/dsldial.h +++ b/DSView/pv/view/dsldial.h @@ -28,6 +28,8 @@ namespace pv { namespace view { +//when device is oscilloscope model, to draw the dail on the left +//created by DsoSignal class dslDial : public QObject { //Q_OBJECT diff --git a/DSView/pv/view/dsosignal.h b/DSView/pv/view/dsosignal.h index a1b040c4..a6f28ec2 100755 --- a/DSView/pv/view/dsosignal.h +++ b/DSView/pv/view/dsosignal.h @@ -38,6 +38,8 @@ class DsoSnapshot; namespace view { +//when device is oscilloscope model,to draw trace +//created by SigSession class DsoSignal : public Signal { Q_OBJECT diff --git a/DSView/pv/view/groupsignal.h b/DSView/pv/view/groupsignal.h index 358c300f..76f1a20f 100755 --- a/DSView/pv/view/groupsignal.h +++ b/DSView/pv/view/groupsignal.h @@ -40,6 +40,7 @@ class GroupSnapshot; namespace view { +//created by SigSession class GroupSignal : public Trace { private: diff --git a/DSView/pv/view/header.cpp b/DSView/pv/view/header.cpp index 40bcaa43..9d794020 100755 --- a/DSView/pv/view/header.cpp +++ b/DSView/pv/view/header.cpp @@ -131,12 +131,15 @@ void Header::paintEvent(QPaintEvent*) const vector< boost::shared_ptr > traces( _view.get_traces(ALL_VIEW)); + // auto num = traces.size(); + const bool dragging = !_drag_traces.empty(); QColor fore(QWidget::palette().color(QWidget::foregroundRole())); fore.setAlpha(View::ForeAlpha); BOOST_FOREACH(const boost::shared_ptr t, traces) { assert(t); + // auto ptr = t.get(); t->paint_label(painter, w, dragging ? QPoint(-1, -1) : _mouse_point, fore); } diff --git a/DSView/pv/view/header.h b/DSView/pv/view/header.h index 7362973a..1dc83c01 100755 --- a/DSView/pv/view/header.h +++ b/DSView/pv/view/header.h @@ -39,6 +39,8 @@ namespace view { class Trace; class View; +//the left panel of main graph +//created by View class Header : public QWidget { Q_OBJECT diff --git a/DSView/pv/view/lissajoustrace.h b/DSView/pv/view/lissajoustrace.h index 1b5dd2f3..f5245d30 100755 --- a/DSView/pv/view/lissajoustrace.h +++ b/DSView/pv/view/lissajoustrace.h @@ -38,12 +38,14 @@ class DsoSnapshot; namespace view { +//when device is oscilloscope mode, it can use to draw Lissajous graph +//created by SigSession class LissajousTrace : public Trace { Q_OBJECT private: - static const int DIV_NUM = 10; + static const int DIV_NUM = 10; public: LissajousTrace(bool enable, diff --git a/DSView/pv/view/logicsignal.h b/DSView/pv/view/logicsignal.h index 2cb30d4e..c9377c8a 100755 --- a/DSView/pv/view/logicsignal.h +++ b/DSView/pv/view/logicsignal.h @@ -39,6 +39,8 @@ class Analog; namespace view { +//when device is logic analyzer mode, to draw logic signal trace +//created by SigSession class LogicSignal : public Signal { Q_OBJECT diff --git a/DSView/pv/view/ruler.cpp b/DSView/pv/view/ruler.cpp index 86448b42..1108087b 100755 --- a/DSView/pv/view/ruler.cpp +++ b/DSView/pv/view/ruler.cpp @@ -168,7 +168,7 @@ void Ruler::rel_grabbed_cursor() } void Ruler::paintEvent(QPaintEvent*) -{ +{ QStyleOption o; o.initFrom(this); QPainter p(this); diff --git a/DSView/pv/view/ruler.h b/DSView/pv/view/ruler.h index f3cf204d..18b310c9 100755 --- a/DSView/pv/view/ruler.h +++ b/DSView/pv/view/ruler.h @@ -33,6 +33,8 @@ namespace view { class TimeMarker; class View; +//the rule panel on the top +//created by View class Ruler : public QWidget { Q_OBJECT diff --git a/DSView/pv/view/selectableitem.h b/DSView/pv/view/selectableitem.h index de9998a9..7859ee4e 100755 --- a/DSView/pv/view/selectableitem.h +++ b/DSView/pv/view/selectableitem.h @@ -35,6 +35,7 @@ namespace pv { namespace view { +//Trace's base class class SelectableItem : public QObject { Q_OBJECT diff --git a/DSView/pv/view/signal.h b/DSView/pv/view/signal.h index 0c37ca9d..ff7eb5b0 100755 --- a/DSView/pv/view/signal.h +++ b/DSView/pv/view/signal.h @@ -50,6 +50,7 @@ class DevInst; namespace view { +//draw signal trace base class class Signal : public Trace { Q_OBJECT diff --git a/DSView/pv/view/spectrumtrace.h b/DSView/pv/view/spectrumtrace.h index e8a08796..ea78082d 100755 --- a/DSView/pv/view/spectrumtrace.h +++ b/DSView/pv/view/spectrumtrace.h @@ -40,6 +40,8 @@ class SpectrumStack; namespace view { +//draw Scope signal trace +//created by SigSession class SpectrumTrace : public Trace { Q_OBJECT diff --git a/DSView/pv/view/timemarker.h b/DSView/pv/view/timemarker.h index 7a5425b8..abcb63d6 100755 --- a/DSView/pv/view/timemarker.h +++ b/DSView/pv/view/timemarker.h @@ -37,6 +37,7 @@ namespace view { class View; +//the Cursor's base class class TimeMarker : public QObject { Q_OBJECT diff --git a/DSView/pv/view/view.h b/DSView/pv/view/view.h index 58893ec8..e059d461 100755 --- a/DSView/pv/view/view.h +++ b/DSView/pv/view/view.h @@ -67,6 +67,7 @@ class Trace; class Viewport; class LissajousFigure; +//created by MainWindow class View : public QScrollArea { Q_OBJECT diff --git a/DSView/pv/view/viewport.cpp b/DSView/pv/view/viewport.cpp index 16cdce97..e5fa036a 100755 --- a/DSView/pv/view/viewport.cpp +++ b/DSView/pv/view/viewport.cpp @@ -138,7 +138,7 @@ bool Viewport::event(QEvent *event) } void Viewport::paintEvent(QPaintEvent *event) -{ +{ (void)event; using pv::view::Signal; @@ -156,12 +156,15 @@ void Viewport::paintEvent(QPaintEvent *event) const vector< boost::shared_ptr > traces(_view.get_traces(_type)); BOOST_FOREACH(const boost::shared_ptr t, traces) { - assert(t); + assert(t); + t->paint_back(p, 0, _view.get_view_width(), fore, back); if (_view.back_ready()) break; } + //auto st = _view.session().get_capture_state(); + if (_view.session().get_device()->dev_inst()->mode == LOGIC || _view.session().get_instant()) { switch(_view.session().get_capture_state()) { @@ -207,6 +210,10 @@ void Viewport::paintSignals(QPainter &p, QColor fore, QColor back) BOOST_FOREACH(const boost::shared_ptr t, traces) { assert(t); + // auto ptr = t.get(); + // ptr->paint_mid(p, 0, t->get_view_rect().right(), fore, back); + // continue; + if (t->enabled()) t->paint_mid(p, 0, t->get_view_rect().right(), fore, back); } @@ -228,7 +235,7 @@ void Viewport::paintSignals(QPainter &p, QColor fore, QColor back) { assert(t); if (t->enabled()) - t->paint_mid(dbp, 0, t->get_view_rect().right(), fore, back); + t->paint_mid(dbp, 0, t->get_view_rect().right(), fore, back); } _need_update = false; } diff --git a/DSView/pv/view/viewport.h b/DSView/pv/view/viewport.h index 9a9689cf..c1d298f1 100755 --- a/DSView/pv/view/viewport.h +++ b/DSView/pv/view/viewport.h @@ -48,6 +48,9 @@ namespace view { class Signal; class View; +//main graph view port, in the middle region +//draw the left and right rule scale +//created by View class Viewport : public QWidget { Q_OBJECT diff --git a/DSView/pv/view/viewstatus.h b/DSView/pv/view/viewstatus.h index 804dfbfa..c4a006eb 100755 --- a/DSView/pv/view/viewstatus.h +++ b/DSView/pv/view/viewstatus.h @@ -41,12 +41,15 @@ namespace view { class View; class DsoSignal; - +//created by View class ViewStatus : public QWidget { Q_OBJECT + public: - ViewStatus(SigSession &session, View &parent); + ViewStatus(SigSession &session, View &parent); + +public: void paintEvent(QPaintEvent *); void mousePressEvent(QMouseEvent *); diff --git a/DSView/pv/view/xcursor.cpp b/DSView/pv/view/xcursor.cpp index 2566505d..a96daf20 100755 --- a/DSView/pv/view/xcursor.cpp +++ b/DSView/pv/view/xcursor.cpp @@ -132,7 +132,7 @@ void XCursor::set_value(XCur_type type, double value) } void XCursor::paint(QPainter &p, const QRect &rect, XCur_type highlight, int order) -{ +{ const int arrow = 3; const int x = rect.left() + _yvalue * rect.width(); const int y0 = rect.top() + _value0 * rect.height(); diff --git a/DSView/pv/view/xcursor.h b/DSView/pv/view/xcursor.h index 7f5901ba..e64d80b8 100755 --- a/DSView/pv/view/xcursor.h +++ b/DSView/pv/view/xcursor.h @@ -41,9 +41,11 @@ namespace view { class View; class DsoSignal; +//created by View class XCursor : public QObject { Q_OBJECT + public: enum XCur_type { XCur_None = -2, diff --git a/libsigrok4DSL/hardware/demo/demo.h b/libsigrok4DSL/hardware/demo/demo.h index 08a6f421..5a474ea0 100755 --- a/libsigrok4DSL/hardware/demo/demo.h +++ b/libsigrok4DSL/hardware/demo/demo.h @@ -168,8 +168,9 @@ static const struct DEMO_profile supported_Demo[] = { (1 << DEMO_LOGIC100x16) | (1 << DEMO_ANALOG10x2) | (1 << DEMO_DSO200x2), - SR_Mn(100), - SR_Kn(20), + SR_Mn(100), + // SR_Gn(16), + SR_Kn(20), 0, vdivs10to2000, 0, diff --git a/libsigrok4DSL/session_file.c b/libsigrok4DSL/session_file.c index 4ae027db..ec76d4a5 100755 --- a/libsigrok4DSL/session_file.c +++ b/libsigrok4DSL/session_file.c @@ -621,6 +621,7 @@ SR_API int sr_session_append(const char *filename, const unsigned char *buf, goto err; } if (zip_file_add(archive, chunk_name, logicsrc, ZIP_FL_OVERWRITE) == -1) { + // if (zip_add(archive, chunk_name, logicsrc) == -1) { goto err; } if ((ret = zip_close(archive)) == -1) { From 386f19eaa856e09ed438f0a3cdfc0b1c367c64b0 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Fri, 8 Oct 2021 14:40:43 +0800 Subject: [PATCH 03/60] test git --- DSView/pv/ZipMaker.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DSView/pv/ZipMaker.h b/DSView/pv/ZipMaker.h index 621d16d7..5858dfb2 100644 --- a/DSView/pv/ZipMaker.h +++ b/DSView/pv/ZipMaker.h @@ -20,6 +20,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +//test git + #pragma once struct zip_source; From f9368d112c58154f28a40b15f975d0e9934d358c Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Fri, 8 Oct 2021 14:53:17 +0800 Subject: [PATCH 04/60] test git 2 --- DSView/pv/ZipMaker.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DSView/pv/ZipMaker.h b/DSView/pv/ZipMaker.h index 5858dfb2..2e988c12 100644 --- a/DSView/pv/ZipMaker.h +++ b/DSView/pv/ZipMaker.h @@ -20,7 +20,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -//test git +//test git 2 #pragma once From d679e240b51c68103301b88f840bfa880181fae3 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Mon, 11 Oct 2021 17:25:27 +0800 Subject: [PATCH 05/60] decoder's annotation string be from resource table --- DSView/pv/data/decode/AnnotationResTable.cpp | 56 ++++++++++++++++++++ DSView/pv/data/decode/AnnotationResTable.h | 48 +++++++++++++++++ DSView/pv/data/decode/annotation.cpp | 40 +++++++++++--- DSView/pv/data/decode/annotation.h | 16 ++++-- DSView/pv/data/decode/row.h | 2 +- DSView/pv/data/decoderstack.cpp | 2 +- DSView/pv/data/decoderstack.h | 4 +- DSView/pv/mainwindow.cpp | 6 ++- DSView/pv/view/analogsignal.h | 2 +- DSView/pv/view/devmode.cpp | 4 +- DSView/pv/view/devmode.h | 1 + DSView/pv/view/spectrumtrace.h | 2 +- DSView/pv/view/viewport.cpp | 11 +++- 13 files changed, 172 insertions(+), 22 deletions(-) create mode 100644 DSView/pv/data/decode/AnnotationResTable.cpp create mode 100644 DSView/pv/data/decode/AnnotationResTable.h diff --git a/DSView/pv/data/decode/AnnotationResTable.cpp b/DSView/pv/data/decode/AnnotationResTable.cpp new file mode 100644 index 00000000..805129f3 --- /dev/null +++ b/DSView/pv/data/decode/AnnotationResTable.cpp @@ -0,0 +1,56 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2013 Joel Holdsworth + * Copyright (C) 2014 DreamSourceLab + * + * 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 "AnnotationResTable.h" +#include + + +AnnotationResTable::AnnotationResTable(){ + +} + +AnnotationResTable::~AnnotationResTable(){ + +} + +int AnnotationResTable::MakeIndex(const std::string &key, AnnotationStringList *&ls) +{ + auto fd =m_indexs.find(key); + if (fd != m_indexs.end()){ + return (*fd).second; + } + + int dex = m_indexs.size(); + m_indexs[key] = dex; + + //make a new string vector + m_resourceTable.push_back(AnnotationStringList()); + ls = &m_resourceTable[dex]; + + return dex; +} + +const AnnotationStringList& AnnotationResTable::GetString(int index){ + int num = m_resourceTable.size(); + assert(index >= 0 && index < num); + return m_resourceTable[index]; +} + diff --git a/DSView/pv/data/decode/AnnotationResTable.h b/DSView/pv/data/decode/AnnotationResTable.h new file mode 100644 index 00000000..21639ae5 --- /dev/null +++ b/DSView/pv/data/decode/AnnotationResTable.h @@ -0,0 +1,48 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2013 Joel Holdsworth + * Copyright (C) 2014 DreamSourceLab + * + * 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 + */ + +#pragma once + +#include +#include +#include +#include + +typedef std::vector AnnotationStringList; + +class AnnotationResTable{ + + public: + AnnotationResTable(); + + ~AnnotationResTable(); + + int MakeIndex(const std::string &key, AnnotationStringList *&ls); + + const AnnotationStringList& GetString(int index); + + inline int GetCount(){return m_resourceTable.size();} + + + private: + std::map m_indexs; + std::vector m_resourceTable; +}; \ No newline at end of file diff --git a/DSView/pv/data/decode/annotation.cpp b/DSView/pv/data/decode/annotation.cpp index 7f23e36e..dbb10075 100755 --- a/DSView/pv/data/decode/annotation.cpp +++ b/DSView/pv/data/decode/annotation.cpp @@ -25,11 +25,16 @@ #include #include "annotation.h" - +#include "AnnotationResTable.h" +#include + namespace pv { namespace data { namespace decode { +//a find talbe instance +AnnotationResTable *Annotation::m_resTable = new AnnotationResTable(); + Annotation::Annotation(const srd_proto_data *const pdata) : _start_sample(pdata->start_sample), _end_sample(pdata->end_sample) @@ -40,13 +45,31 @@ Annotation::Annotation(const srd_proto_data *const pdata) : assert(pda); _format = pda->ann_class; - _type = pda->ann_type; + _type = pda->ann_type; + _strIndex = 0; + + std::string key; + //make resource find key const char *const *annotations = (char**)pda->ann_text; - while(*annotations) { - _annotations.push_back(QString::fromUtf8(*annotations)); - annotations++; + while(*annotations) { + const char *ptr = *annotations; + key.append(ptr, strlen(ptr)); + annotations++; } + + AnnotationStringList *annotationArray = NULL; + _strIndex = Annotation::m_resTable->MakeIndex(key, annotationArray); + + //save new string lines + if (annotationArray){ + annotations = (char **)pda->ann_text; + while (*annotations) + { + annotationArray->push_back(QString::fromUtf8(*annotations)); + annotations++; + } + } } Annotation::Annotation() @@ -57,7 +80,7 @@ Annotation::Annotation() Annotation::~Annotation() { - _annotations.clear(); + } uint64_t Annotation::start_sample() const @@ -82,8 +105,9 @@ int Annotation::type() const const std::vector& Annotation::annotations() const { - return _annotations; -} + return Annotation::m_resTable->GetString(_strIndex); +} + } // namespace decode } // namespace data diff --git a/DSView/pv/data/decode/annotation.h b/DSView/pv/data/decode/annotation.h index 03e208ef..f55035b0 100755 --- a/DSView/pv/data/decode/annotation.h +++ b/DSView/pv/data/decode/annotation.h @@ -26,6 +26,8 @@ #include +class AnnotationResTable; + struct srd_proto_data; namespace pv { @@ -37,20 +39,26 @@ class Annotation public: Annotation(const srd_proto_data *const pdata); Annotation(); +public: + ~Annotation(); uint64_t start_sample() const; uint64_t end_sample() const; int format() const; - int type() const; + int type() const; + +public: const std::vector& annotations() const; private: uint64_t _start_sample; uint64_t _end_sample; - int _format; - int _type; - std::vector _annotations; + short _format; + short _type; + short _strIndex; + + static AnnotationResTable * m_resTable; }; } // namespace decode diff --git a/DSView/pv/data/decode/row.h b/DSView/pv/data/decode/row.h index 9466a68d..1b2fb84f 100755 --- a/DSView/pv/data/decode/row.h +++ b/DSView/pv/data/decode/row.h @@ -52,7 +52,7 @@ public: private: const srd_decoder *_decoder; const srd_decoder_annotation_row *_row; - int _order; + int _order; }; } // decode diff --git a/DSView/pv/data/decoderstack.cpp b/DSView/pv/data/decoderstack.cpp index 60bb699e..1c4f6602 100755 --- a/DSView/pv/data/decoderstack.cpp +++ b/DSView/pv/data/decoderstack.cpp @@ -658,7 +658,7 @@ void DecoderStack::annotation_callback(srd_proto_data *pdata, void *decoder) // Add the annotation boost::lock_guard lock(d->_output_mutex); if (!(*row_iter).second.push_annotation(a)) - d->_no_memory = true; + d->_no_memory = true; } void DecoderStack::on_new_frame() diff --git a/DSView/pv/data/decoderstack.h b/DSView/pv/data/decoderstack.h index c7baf7cc..091a9d96 100755 --- a/DSView/pv/data/decoderstack.h +++ b/DSView/pv/data/decoderstack.h @@ -77,9 +77,11 @@ public: }; public: - DecoderStack(pv::SigSession &_session, + DecoderStack(pv::SigSession &_session, const srd_decoder *const decoder); +public: + virtual ~DecoderStack(); const std::list< boost::shared_ptr >& stack() const; diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index 746f34f2..b585a0f9 100755 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -518,9 +518,11 @@ void MainWindow::device_attach() struct sr_dev_driver **const drivers = sr_driver_list(); struct sr_dev_driver **driver; + for (driver = drivers; *driver; driver++) - if (*driver) - _device_manager.driver_scan(*driver); + if (*driver) + _device_manager.driver_scan(*driver); + _session.set_default_device(boost::bind(&MainWindow::session_error, this, QString(tr("Set Default Device failed")), _1)); diff --git a/DSView/pv/view/analogsignal.h b/DSView/pv/view/analogsignal.h index 0555175d..94e29290 100755 --- a/DSView/pv/view/analogsignal.h +++ b/DSView/pv/view/analogsignal.h @@ -37,7 +37,7 @@ class AnalogSnapshot; namespace view { -//when device is data acquisition model, to draw trace +//when device is data acquisition model, to draw signal trace //created by SigSession class AnalogSignal : public Signal { diff --git a/DSView/pv/view/devmode.cpp b/DSView/pv/view/devmode.cpp index f567a7a0..572f9651 100755 --- a/DSView/pv/view/devmode.cpp +++ b/DSView/pv/view/devmode.cpp @@ -90,7 +90,7 @@ void DevMode::changeEvent(QEvent *event) } void DevMode::set_device() -{ +{ const boost::shared_ptr dev_inst = _session.get_device(); assert(dev_inst); @@ -142,7 +142,7 @@ void DevMode::set_device() } void DevMode::paintEvent(QPaintEvent*) -{ +{ using pv::view::Trace; QStyleOption o; diff --git a/DSView/pv/view/devmode.h b/DSView/pv/view/devmode.h index 999f1df0..6dc2f5d9 100755 --- a/DSView/pv/view/devmode.h +++ b/DSView/pv/view/devmode.h @@ -50,6 +50,7 @@ class SigSession; namespace view { +//devece work mode select list class DevMode : public QWidget { Q_OBJECT diff --git a/DSView/pv/view/spectrumtrace.h b/DSView/pv/view/spectrumtrace.h index ea78082d..7173188b 100755 --- a/DSView/pv/view/spectrumtrace.h +++ b/DSView/pv/view/spectrumtrace.h @@ -40,7 +40,7 @@ class SpectrumStack; namespace view { -//draw Scope signal trace +//when device is oscillcopse mode, to draw signal trace //created by SigSession class SpectrumTrace : public Trace { diff --git a/DSView/pv/view/viewport.cpp b/DSView/pv/view/viewport.cpp index e5fa036a..4646fd9d 100755 --- a/DSView/pv/view/viewport.cpp +++ b/DSView/pv/view/viewport.cpp @@ -157,7 +157,7 @@ void Viewport::paintEvent(QPaintEvent *event) BOOST_FOREACH(const boost::shared_ptr t, traces) { assert(t); - + t->paint_back(p, 0, _view.get_view_width(), fore, back); if (_view.back_ready()) break; @@ -234,6 +234,15 @@ void Viewport::paintSignals(QPainter &p, QColor fore, QColor back) BOOST_FOREACH(const boost::shared_ptr t, traces) { assert(t); + + /* + auto ptr = t->get(); + if (ptr->enabled()){ + ptr->paint_mid(dbp, 0, t->get_view_rect().right(), fore, back); + continue; + } + */ + if (t->enabled()) t->paint_mid(dbp, 0, t->get_view_rect().right(), fore, back); } From ea11b484702236671fd40a341b0c677b3c48429d Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Mon, 11 Oct 2021 17:28:03 +0800 Subject: [PATCH 06/60] not change --- DSView/pv/data/decode/annotation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DSView/pv/data/decode/annotation.cpp b/DSView/pv/data/decode/annotation.cpp index dbb10075..1a0c0fce 100755 --- a/DSView/pv/data/decode/annotation.cpp +++ b/DSView/pv/data/decode/annotation.cpp @@ -61,7 +61,7 @@ Annotation::Annotation(const srd_proto_data *const pdata) : AnnotationStringList *annotationArray = NULL; _strIndex = Annotation::m_resTable->MakeIndex(key, annotationArray); - //save new string lines + //save new string lines if (annotationArray){ annotations = (char **)pda->ann_text; while (*annotations) From a80151e3c038bc7d24924c367497a01bd5e633e0 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Fri, 15 Oct 2021 17:26:50 +0800 Subject: [PATCH 07/60] able to specify the protocol's data display format, for bin/ocx/hex/dec/ascii.. --- DSView/main.cpp | 3 + DSView/pv/config/appconfig.cpp | 186 ++++++++++++++ DSView/pv/config/appconfig.h | 75 ++++++ DSView/pv/data/decode/annotation.cpp | 178 ++++++++++++- DSView/pv/data/decode/annotation.h | 6 +- DSView/pv/data/decode/decoder.cpp | 1 + DSView/pv/data/decode/decoderstatus.h | 38 +++ DSView/pv/data/decode/row.h | 5 +- DSView/pv/data/decoderstack.cpp | 7 +- DSView/pv/data/decoderstack.h | 7 +- DSView/pv/dialogs/dsmessagebox.cpp | 16 +- DSView/pv/dialogs/dsmessagebox.h | 6 +- DSView/pv/dock/protocoldock.cpp | 344 +++++++++++--------------- DSView/pv/dock/protocoldock.h | 30 +-- DSView/pv/dock/protocolitemlayer.cpp | 152 ++++++++++++ DSView/pv/dock/protocolitemlayer.h | 79 ++++++ DSView/pv/dsvdef.cpp | 46 ++++ DSView/pv/dsvdef.h | 39 +++ DSView/pv/mainwindow.cpp | 14 +- DSView/pv/prop/binding/binding.cpp | 14 +- DSView/pv/sigsession.cpp | 7 +- DSView/pv/sigsession.h | 4 +- DSView/pv/storesession.cpp | 1 - DSView/pv/ui/msgbox.cpp | 56 +++++ DSView/pv/ui/msgbox.h | 33 +++ DSView/pv/view/decodetrace.cpp | 36 ++- DSView/pv/view/decodetrace.h | 1 + 27 files changed, 1126 insertions(+), 258 deletions(-) create mode 100644 DSView/pv/config/appconfig.cpp create mode 100644 DSView/pv/config/appconfig.h create mode 100644 DSView/pv/data/decode/decoderstatus.h create mode 100644 DSView/pv/dock/protocolitemlayer.cpp create mode 100644 DSView/pv/dock/protocolitemlayer.h create mode 100644 DSView/pv/dsvdef.cpp create mode 100644 DSView/pv/dsvdef.h create mode 100644 DSView/pv/ui/msgbox.cpp create mode 100644 DSView/pv/ui/msgbox.h diff --git a/DSView/main.cpp b/DSView/main.cpp index fa87b03c..1a51a86f 100755 --- a/DSView/main.cpp +++ b/DSView/main.cpp @@ -41,6 +41,7 @@ #include "mystyle.h" #include "pv/devicemanager.h" #include "pv/mainframe.h" +#include "pv/config/appconfig.h" #include "config.h" @@ -186,6 +187,8 @@ int main(int argc, char *argv[]) // Load the protocol decoders srd_decoder_load_all(); #endif + //load app config + AppConfig::Instance().Load("./appconfig.json"); try { // Create the device manager, initialise the drivers diff --git a/DSView/pv/config/appconfig.cpp b/DSView/pv/config/appconfig.cpp new file mode 100644 index 00000000..ac5d1c28 --- /dev/null +++ b/DSView/pv/config/appconfig.cpp @@ -0,0 +1,186 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2012 Joel Holdsworth + * Copyright (C) 2013 DreamSourceLab + * + * 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 "appconfig.h" +#include +#include +#include +#include +#include +#include +#include + +#define MAX_PROTOCOL_FORMAT_LIST 15 + +StringPair::StringPair(const string &key, const string &value) +{ + m_key = key; + m_value = value; +} + +//------------function +QString FormatArrayToString(vector &protocolFormats){ + QString str; + + for (StringPair &o : protocolFormats){ + if (!str.isEmpty()){ + str += ";"; + } + std::string line; + line += o.m_key; + line += "="; + line += o.m_value; + str += line.c_str(); + } + + return str; +} + +void StringToFormatArray(const QString &str, vector &protocolFormats){ + QStringList arr = str.split(";"); + for (int i=0; i MAX_PROTOCOL_FORMAT_LIST){ + while (m_protocolFormats.size() < MAX_PROTOCOL_FORMAT_LIST) + { + m_protocolFormats.erase(m_protocolFormats.begin()); + } + } + + m_protocolFormats.push_back(StringPair(protocolName,value)); +} + +string AppConfig::GetProtocolFormat(const string &protocolName) +{ + for (StringPair &o : m_protocolFormats){ + if (o.m_key == protocolName){ + return o.m_value; + } + } + return ""; +} diff --git a/DSView/pv/config/appconfig.h b/DSView/pv/config/appconfig.h new file mode 100644 index 00000000..ec2b2ee1 --- /dev/null +++ b/DSView/pv/config/appconfig.h @@ -0,0 +1,75 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2012 Joel Holdsworth + * Copyright (C) 2013 DreamSourceLab + * + * 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 + */ + +#pragma once + +#include +#include + +using namespace std; + +struct app_status{ + + +}; + + +class StringPair +{ +public: + StringPair(const string &key, const string &value); + string m_key; + string m_value; +}; + +class config_data +{ + public: + + +}; + +class AppConfig +{ +private: + AppConfig(); + + ~AppConfig(); + +public: + static AppConfig &Instance(); + bool Load(const char *file); + bool Save(); + string ToJsonString(); + void FromJson(string &json); + + void SetProtocolFormat(const string &protocolName, const string &value); + string GetProtocolFormat(const string &protocolName); + +public: + config_data m_data; + app_status m_status; + +private: + string m_fileName; + vector m_protocolFormats; +}; diff --git a/DSView/pv/data/decode/annotation.cpp b/DSView/pv/data/decode/annotation.cpp index 1a0c0fce..c0838d04 100755 --- a/DSView/pv/data/decode/annotation.cpp +++ b/DSView/pv/data/decode/annotation.cpp @@ -27,7 +27,91 @@ #include "annotation.h" #include "AnnotationResTable.h" #include - +#include +#include +#include "../../config/appconfig.h" +#include "decoderstatus.h" +#include "../../dsvdef.h" + +#define DECODER_MAX_DATA_BLOCK_LEN 300 +#define FORMAT_TMP_BUFFER_SIZE 1200 + +const char g_bin_cvt_table[] = "0000000100100011010001010110011110001001101010111100110111101111"; +char g_bin_format_tmp_buffer[FORMAT_TMP_BUFFER_SIZE + 3]; +char g_oct_format_tmp_buffer[FORMAT_TMP_BUFFER_SIZE + 6]; +std::vector g_format_ret_vector; + +char* bin2oct_string(char *buf, int size, const char *bin, int len){ + char *wr = buf + size - 1; + *wr = 0; //end flag + + char *rd = (char*)bin + len - 1; //move to last byte + + char tmp[3]; + + while (rd >= bin && wr > buf) + { + wr--; + + int num = 0; + + while (rd >= bin && num < 3) + { + tmp[2-num] = *rd; + rd--; + num++; + } + + //fill + while (num < 3) + { + tmp[2-num] = '0'; + ++num; + } + + + if (strncmp(tmp, "000", 3) == 0) + *wr = '0'; + else if (strncmp(tmp, "001", 3) == 0) + *wr = '1'; + else if (strncmp(tmp, "010", 3) == 0) + *wr = '2'; + else if (strncmp(tmp, "011", 3) == 0) + *wr = '3'; + else if (strncmp(tmp, "100", 3) == 0) + *wr = '4'; + else if (strncmp(tmp, "101", 3) == 0) + *wr = '5'; + else if (strncmp(tmp, "110", 3) == 0) + *wr = '6'; + else if (strncmp(tmp, "111", 3) == 0) + *wr = '7'; + } + + return wr; +} + +long long bin2long_string(const char *bin, int len) +{ + char *rd = (char *)bin + len - 1; //move to last byte + int dex = 0; + long long value = 0; + long long bv = 0; + + while (rd >= bin) + { + if (*rd == '1') + { + bv = 1 << dex; + value += bv; + } + rd--; + ++dex; + } + + return value; +} + namespace pv { namespace data { namespace decode { @@ -35,7 +119,7 @@ namespace decode { //a find talbe instance AnnotationResTable *Annotation::m_resTable = new AnnotationResTable(); -Annotation::Annotation(const srd_proto_data *const pdata) : +Annotation::Annotation(const srd_proto_data *const pdata, DecoderStatus *status) : _start_sample(pdata->start_sample), _end_sample(pdata->end_sample) { @@ -45,7 +129,13 @@ Annotation::Annotation(const srd_proto_data *const pdata) : assert(pda); _format = pda->ann_class; - _type = pda->ann_type; + _type = pda->ann_type; + _status = status; + + //have numerical + if (_type >= 100 && _type < 200){ + status->m_bNumerical = true; + } _strIndex = 0; @@ -105,7 +195,87 @@ int Annotation::type() const const std::vector& Annotation::annotations() const { - return Annotation::m_resTable->GetString(_strIndex); + assert(_status); + + int fmt = _status->m_format; + const std::vector& vct = Annotation::m_resTable->GetString(_strIndex); + + if (!(_type >= 100 && _type < 200) || fmt == DecoderDataFormat::ascii || fmt == DecoderDataFormat::hex){ + return vct; + } + if (vct.size() != 1){ + return vct; + } + + //flow, convert to oct\dec\bin format + const char *data = vct[0].toStdString().c_str(); + if (*data == 0 || *data == '['){ + return vct; + } + + //convert to bin format + char *buf = g_bin_format_tmp_buffer + FORMAT_TMP_BUFFER_SIZE; + *(buf + 1) = 0; //set the end flag + *buf = 0; + + int len = strlen(data); + //buffer is not enough + if (len > DECODER_MAX_DATA_BLOCK_LEN){ + return vct; + } + + char *rd = (char*)data + len - 1; //move to last byte + char c = 0; + int dex = 0; + + while (rd >= data) + { + c = *rd; + dex = (int)(c <= '9' ? (c - '0') : (c - 'A' + 10)); + char *ptable = (char*)g_bin_cvt_table + dex * 4; + + buf -= 4; //move to left for 4 bytes + buf[0] = ptable[0]; + buf[1] = ptable[1]; + buf[2] = ptable[2]; + buf[3] = ptable[3]; + + rd--; + } + + std::vector &vct2 = g_format_ret_vector; + if (vct2.size() == 0){ + vct2.push_back(QString()); + } + + //get bin format + if (fmt == DecoderDataFormat::bin){ + vct2[0].clear(); + vct2[0].append(buf); + return vct2; + } + + //get oct format + if (fmt == DecoderDataFormat::oct){ + char *oct_buf = bin2oct_string(g_oct_format_tmp_buffer, + sizeof(g_oct_format_tmp_buffer), buf, len * 4); + vct2[0].clear(); + vct2[0].append(oct_buf); + return vct2; + } + + //64 bit integer + if (fmt == DecoderDataFormat::dec && len * 4 <= 64){ + long long lv = bin2long_string(buf, len *4); + char vbuf[30] = {0}; + sprintf(vbuf, "%lld", lv); + + vct2[0].clear(); + vct2[0].append(vbuf); + return vct2; + } + + return vct2; } diff --git a/DSView/pv/data/decode/annotation.h b/DSView/pv/data/decode/annotation.h index f55035b0..d45d0e5b 100755 --- a/DSView/pv/data/decode/annotation.h +++ b/DSView/pv/data/decode/annotation.h @@ -27,6 +27,7 @@ #include class AnnotationResTable; +class DecoderStatus; struct srd_proto_data; @@ -37,7 +38,7 @@ namespace decode { class Annotation { public: - Annotation(const srd_proto_data *const pdata); + Annotation(const srd_proto_data *const pdata, DecoderStatus *status); Annotation(); public: @@ -55,8 +56,9 @@ private: uint64_t _start_sample; uint64_t _end_sample; short _format; - short _type; + short _type; //100-199: is a numerical value type,can show hex/oct format short _strIndex; + DecoderStatus *_status; static AnnotationResTable * m_resTable; }; diff --git a/DSView/pv/data/decode/decoder.cpp b/DSView/pv/data/decode/decoder.cpp index 486340cc..94d1efe3 100755 --- a/DSView/pv/data/decode/decoder.cpp +++ b/DSView/pv/data/decode/decoder.cpp @@ -109,6 +109,7 @@ uint64_t Decoder::decode_end() const return _decode_end; } +//apply setting bool Decoder::commit() { if (_setted) { diff --git a/DSView/pv/data/decode/decoderstatus.h b/DSView/pv/data/decode/decoderstatus.h new file mode 100644 index 00000000..d80780b3 --- /dev/null +++ b/DSView/pv/data/decode/decoderstatus.h @@ -0,0 +1,38 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2013 Joel Holdsworth + * Copyright (C) 2014 DreamSourceLab + * + * 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 + */ + +#pragma once + +class DecoderStatus +{ +public: + DecoderStatus() + { + m_bNumerical = false; + m_format = 0; + sdr_decoder_handle = NULL; + } + +public: + bool m_bNumerical; //when decoder get any numerical data,it will be set + int m_format; //protocol format code + void *sdr_decoder_handle; +}; \ No newline at end of file diff --git a/DSView/pv/data/decode/row.h b/DSView/pv/data/decode/row.h index 1b2fb84f..d6fa4ac6 100755 --- a/DSView/pv/data/decode/row.h +++ b/DSView/pv/data/decode/row.h @@ -36,12 +36,15 @@ class Row { public: Row(); - ~Row(); Row(const srd_decoder *decoder, const srd_decoder_annotation_row *row = NULL, const int order = -1); +public: + + ~Row(); + const srd_decoder* decoder() const; const srd_decoder_annotation_row* row() const; diff --git a/DSView/pv/data/decoderstack.cpp b/DSView/pv/data/decoderstack.cpp index 1c4f6602..7f946dd1 100755 --- a/DSView/pv/data/decoderstack.cpp +++ b/DSView/pv/data/decoderstack.cpp @@ -53,7 +53,7 @@ const unsigned int DecoderStack::DecodeNotifyPeriod = 1024; boost::mutex DecoderStack::_global_decode_mutex; DecoderStack::DecoderStack(pv::SigSession &session, - const srd_decoder *const dec) : + const srd_decoder *const dec, DecoderStatus *decoder_status) : _session(session), _sample_count(0), _frame_complete(false), @@ -73,6 +73,8 @@ DecoderStack::DecoderStack(pv::SigSession &session, _stack.push_back(boost::shared_ptr( new decode::Decoder(dec))); + _decoder_status = decoder_status; + build_row(); } @@ -612,6 +614,7 @@ uint64_t DecoderStack::sample_rate() const return _samplerate; } +//the decode callback, annotation object will be create void DecoderStack::annotation_callback(srd_proto_data *pdata, void *decoder) { assert(pdata); @@ -626,7 +629,7 @@ void DecoderStack::annotation_callback(srd_proto_data *pdata, void *decoder) return; } - const Annotation a(pdata); + const Annotation a(pdata, d->_decoder_status); // Find the row assert(pdata->pdo); diff --git a/DSView/pv/data/decoderstack.h b/DSView/pv/data/decoderstack.h index 091a9d96..311a819f 100755 --- a/DSView/pv/data/decoderstack.h +++ b/DSView/pv/data/decoderstack.h @@ -36,10 +36,12 @@ #include "../data/decode/rowdata.h" #include "../data/signaldata.h" +class DecoderStatus; + namespace DecoderStackTest { class TwoDecoderStack; } - + namespace pv { class SigSession; @@ -78,7 +80,7 @@ public: public: DecoderStack(pv::SigSession &_session, - const srd_decoder *const decoder); + const srd_decoder *const decoder, DecoderStatus *decoder_status); public: @@ -203,6 +205,7 @@ private: bool _no_memory; int64_t _mark_index; + DecoderStatus *_decoder_status; friend class DecoderStackTest::TwoDecoderStack; }; diff --git a/DSView/pv/dialogs/dsmessagebox.cpp b/DSView/pv/dialogs/dsmessagebox.cpp index 70445d7e..6a2a225d 100755 --- a/DSView/pv/dialogs/dsmessagebox.cpp +++ b/DSView/pv/dialogs/dsmessagebox.cpp @@ -32,9 +32,10 @@ namespace pv { namespace dialogs { -DSMessageBox::DSMessageBox(QWidget *parent) : +DSMessageBox::DSMessageBox(QWidget *parent,const char *title) : QDialog(parent), - _moving(false) + _moving(false), + _clickType(0) { setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint); setAttribute(Qt::WA_TranslucentBackground); @@ -53,7 +54,14 @@ DSMessageBox::DSMessageBox(QWidget *parent) : _msg->setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint); _titlebar = new toolbars::TitleBar(false, this); - _titlebar->setTitle(tr("Message")); + + if (title){ + _titlebar->setTitle(QString(title)); + } + else{ + _titlebar->setTitle(tr("Message")); + } + _titlebar->installEventFilter(this); mlayout->addWidget(_titlebar); @@ -120,6 +128,8 @@ int DSMessageBox::exec() void DSMessageBox::on_button(QAbstractButton *btn) { QMessageBox::ButtonRole role = _msg->buttonRole(btn); + _clickType = (int)role; + if (role == QMessageBox::AcceptRole) accept(); else diff --git a/DSView/pv/dialogs/dsmessagebox.h b/DSView/pv/dialogs/dsmessagebox.h index 5fc2ea30..fa6a8dfb 100755 --- a/DSView/pv/dialogs/dsmessagebox.h +++ b/DSView/pv/dialogs/dsmessagebox.h @@ -38,10 +38,13 @@ class DSMessageBox : public QDialog Q_OBJECT public: - DSMessageBox(QWidget *parent); + DSMessageBox(QWidget *parent, const char *title=0); + QMessageBox *mBox(); int exec(); + + inline int GetLastClick(){return _clickType;} protected: void accept(); @@ -60,6 +63,7 @@ private: toolbars::TitleBar *_titlebar; bool _moving; QPoint _startPos; + int _clickType; }; } // namespace dialogs diff --git a/DSView/pv/dock/protocoldock.cpp b/DSView/pv/dock/protocoldock.cpp index 2039c9da..a811218e 100755 --- a/DSView/pv/dock/protocoldock.cpp +++ b/DSView/pv/dock/protocoldock.cpp @@ -26,8 +26,7 @@ #include "../data/decodermodel.h" #include "../data/decoderstack.h" #include "../dialogs/protocollist.h" -#include "../dialogs/protocolexp.h" -#include "../dialogs/dsmessagebox.h" +#include "../dialogs/protocolexp.h" #include "../view/view.h" #include @@ -44,14 +43,19 @@ #include #include #include +#include #include #include #include +#include "../ui/msgbox.h" +#include "../dsvdef.h" +#include "../config/appconfig.h" +#include "../data/decode/decoderstatus.h" namespace pv { namespace dock { - + ProtocolDock::ProtocolDock(QWidget *parent, view::View &view, SigSession &session) : QScrollArea(parent), _session(session), @@ -90,12 +94,7 @@ ProtocolDock::ProtocolDock(QWidget *parent, view::View &view, SigSession &sessio hori_layout->addWidget(_del_all_button); hori_layout->addWidget(_protocol_combobox); hori_layout->addStretch(1); - - connect(_add_button, SIGNAL(clicked()), - this, SLOT(add_protocol())); - connect(_del_all_button, SIGNAL(clicked()), - this, SLOT(del_protocol())); - + _up_layout = new QVBoxLayout(); _up_layout->addLayout(hori_layout); _up_layout->addStretch(1); @@ -111,18 +110,12 @@ ProtocolDock::ProtocolDock(QWidget *parent, view::View &view, SigSession &sessio _dn_set_button = new QPushButton(_dn_widget); _dn_set_button->setFlat(true); - connect(_dn_set_button, SIGNAL(clicked()), - this, SLOT(set_model())); _dn_save_button = new QPushButton(_dn_widget); - _dn_save_button->setFlat(true); - connect(_dn_save_button, SIGNAL(clicked()), - this, SLOT(export_table_view())); + _dn_save_button->setFlat(true); _dn_nav_button = new QPushButton(_dn_widget); - _dn_nav_button->setFlat(true); - connect(_dn_nav_button, SIGNAL(clicked()), - this, SLOT(nav_table_view())); + _dn_nav_button->setFlat(true); QHBoxLayout *dn_title_layout = new QHBoxLayout(); _dn_title_label = new QLabel(_dn_widget); @@ -142,10 +135,6 @@ ProtocolDock::ProtocolDock(QWidget *parent, view::View &view, SigSession &sessio _pre_button = new QPushButton(_dn_widget); _nxt_button = new QPushButton(_dn_widget); - connect(_pre_button, SIGNAL(clicked()), - this, SLOT(search_pre())); - connect(_nxt_button, SIGNAL(clicked()), - this, SLOT(search_nxt())); _search_button = new QPushButton(this); _search_button->setFixedWidth(_search_button->height()); @@ -194,6 +183,20 @@ ProtocolDock::ProtocolDock(QWidget *parent, view::View &view, SigSession &sessio //_split_widget->setGeometry(0, 0, sizeHint().width(), 500); _split_widget->setObjectName("protocolWidget"); + connect(_dn_nav_button, SIGNAL(clicked()),this, SLOT(nav_table_view())); + + connect(_dn_save_button, SIGNAL(clicked()),this, SLOT(export_table_view())); + + connect(_dn_set_button, SIGNAL(clicked()),this, SLOT(set_model())); + + connect(_pre_button, SIGNAL(clicked()),this, SLOT(search_pre())); + + connect(_nxt_button, SIGNAL(clicked()),this, SLOT(search_nxt())); + + connect(_add_button, SIGNAL(clicked()),this, SLOT(on_add_protocol())); + + connect(_del_all_button, SIGNAL(clicked()),this, SLOT(on_del_all_protocol())); + connect(&_session, SIGNAL(decode_done()), this, SLOT(update_model())); connect(this, SIGNAL(protocol_updated()), this, SLOT(update_model())); connect(_table_view, SIGNAL(clicked(QModelIndex)), this, SLOT(item_clicked(QModelIndex))); @@ -206,6 +209,11 @@ ProtocolDock::ProtocolDock(QWidget *parent, view::View &view, SigSession &sessio ProtocolDock::~ProtocolDock() { + //destroy protocol item layers + for (auto it = _protocolItems.begin(); it != _protocolItems.end(); it++){ + delete (*it); + } + _protocolItems.clear(); } void ProtocolDock::changeEvent(QEvent *event) @@ -237,21 +245,13 @@ void ProtocolDock::reStyle() _nxt_button->setIcon(QIcon(iconPath+"/next.svg")); _search_button->setIcon(QIcon(iconPath+"/search.svg")); - for (QVector ::const_iterator i = _del_button_list.begin(); - i != _del_button_list.end(); i++) - (*i)->setIcon(QIcon(iconPath+"/del.svg")); - - for (QVector ::const_iterator i = _set_button_list.begin(); - i != _set_button_list.end(); i++) - (*i)->setIcon(QIcon(iconPath+"/gear.svg")); + for (auto it = _protocolItems.begin(); it != _protocolItems.end(); it++){ + (*it)->ResetStyle(); + } } void ProtocolDock::paintEvent(QPaintEvent *) -{ -// QStyleOption opt; -// opt.init(this); -// QPainter p(this); -// style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); +{ } void ProtocolDock::resizeEvent(QResizeEvent *event) @@ -298,179 +298,72 @@ bool ProtocolDock::sel_protocol(QString id) return false; } -void ProtocolDock::add_protocol() +void ProtocolDock::on_add_protocol() { add_protocol(false); } void ProtocolDock::add_protocol(bool silent) -{ - if (_session.get_device()->dev_inst()->mode != LOGIC) { - dialogs::DSMessageBox msg(this); - msg.mBox()->setText(tr("Protocol Analyzer")); - msg.mBox()->setInformativeText(tr("Protocol Analyzer is only valid in Digital Mode!")); - msg.mBox()->setStandardButtons(QMessageBox::Ok); - msg.mBox()->setIcon(QMessageBox::Warning); - msg.exec(); - } else { - srd_decoder *const decoder = - (srd_decoder*)(_protocol_combobox->itemData(_protocol_combobox->currentIndex())).value(); - if (_session.add_decoder(decoder, silent)) { - //std::list _sel_probes = dlg.get_sel_probes(); - //QMap & _options = dlg.get_options(); - //QMap _options_index = dlg.get_options_index(); +{ + if (_session.get_device()->dev_inst()->mode != LOGIC) { + MsgBox::Show(NULL, "Protocol Analyzer\nProtocol Analyzer is only valid in Digital Mode!", this); + return; + } - QString iconPath = ":/icons/" + qApp->property("Style").toString(); - QPushButton *_del_button = new QPushButton(_up_widget); - QPushButton *_set_button = new QPushButton(_up_widget); - _del_button->setFlat(true); - _del_button->setIcon(QIcon(iconPath+"/del.svg")); - _set_button->setFlat(true); - _set_button->setIcon(QIcon(iconPath+"/gear.svg")); - QLabel *_protocol_label = new QLabel(_up_widget); - QLabel *_progress_label = new QLabel(_up_widget); + srd_decoder *const decoder = + (srd_decoder *)(_protocol_combobox->itemData(_protocol_combobox->currentIndex())).value(); - _del_button->setCheckable(true); - _protocol_label->setText(_protocol_combobox->currentText()); + DecoderStatus *dstatus = new DecoderStatus(); + dstatus->m_format = (int)DecoderDataFormat::hex; - connect(_del_button, SIGNAL(clicked()), - this, SLOT(del_protocol())); - connect(_set_button, SIGNAL(clicked()), - this, SLOT(rst_protocol())); + if (_session.add_decoder(decoder, silent, dstatus)) + { + //crate item layer + QString protocolName = _protocol_combobox->currentText(); + ProtocolItemLayer *layer = new ProtocolItemLayer(_up_widget, protocolName, this); + _protocolItems.push_back(layer); + _up_layout->insertLayout(_protocolItems.size(), layer); + layer->m_decoderStatus = dstatus; - _del_button_list.push_back(_del_button); - _set_button_list.push_back(_set_button); - _protocol_label_list.push_back(_protocol_label); - _progress_label_list.push_back(_progress_label); - _protocol_index_list.push_back(_protocol_combobox->currentIndex()); - - QHBoxLayout *hori_layout = new QHBoxLayout(); - hori_layout->addWidget(_set_button); - hori_layout->addWidget(_del_button); - hori_layout->addWidget(_protocol_label); - hori_layout->addWidget(_progress_label); - hori_layout->addStretch(1); - _hori_layout_list.push_back(hori_layout); - _up_layout->insertLayout(_del_button_list.size(), hori_layout); - - // progress connection - const std::vector< boost::shared_ptr > decode_sigs( - _session.get_decode_signals()); - connect(decode_sigs.back().get(), SIGNAL(decoded_progress(int)), this, SLOT(decoded_progress(int))); - - protocol_updated(); + //set current protocol format + string fmt = AppConfig::Instance().GetProtocolFormat(protocolName.toStdString()); + if (fmt != ""){ + layer->SetProtocolFormat(fmt.c_str()); + dstatus->m_format = DecoderDataFormat::Parse(fmt.c_str()); } + + //progress connection + const std::vector> decode_sigs(_session.get_decode_signals()); + + connect(decode_sigs.back().get(), SIGNAL(decoded_progress(int)), this, SLOT(decoded_progress(int))); + + protocol_updated(); } } + + void ProtocolDock::on_del_all_protocol(){ + if (_protocolItems.size() == 0){ + MsgBox::Show(NULL, "No Protocol Analyzer to delete!", this); + return; + } -void ProtocolDock::rst_protocol() -{ - int rst_index = 0; - for (QVector ::const_iterator i = _set_button_list.begin(); - i != _set_button_list.end(); i++) { - QPushButton *button = qobject_cast(sender()); - if ((*i) == button) { - //pv::decoder::DemoConfig dlg(this, _session.get_device(), _protocol_index_list.at(rst_index)); - //dlg.set_config(_session.get_decode_probes(rst_index), _session.get_decode_options_index(rst_index)); - //if (dlg.exec()) { - //std::list _sel_probes = dlg.get_sel_probes(); - //QMap & _options = dlg.get_options(); - //QMap _options_index = dlg.get_options_index(); - - //_session.rst_protocol_analyzer(rst_index, _sel_probes, _options, _options_index); - //} - _session.rst_decoder(rst_index); - break; - } - rst_index++; + if (MsgBox::Confirm("Are you sure to remove all protocol analyzer?", this)){ + del_all_protocol(); } - protocol_updated(); -} - -void ProtocolDock::del_protocol() -{ - if (_del_all_button->isChecked()) { - _del_all_button->setChecked(false); - if (_hori_layout_list.size() > 0) { - int del_index = 0; - for (QVector ::const_iterator i = _hori_layout_list.begin(); - i != _hori_layout_list.end(); i++) { - _up_layout->removeItem((*i)); - delete (*i); - delete _del_button_list.at(del_index); - delete _set_button_list.at(del_index); - delete _protocol_label_list.at(del_index); - delete _progress_label_list.at(del_index); - - _session.remove_decode_signal(0); - del_index++; - } - _hori_layout_list.clear(); - _del_button_list.clear(); - _set_button_list.clear(); - _protocol_label_list.clear(); - _progress_label_list.clear(); - _protocol_index_list.clear(); - } else { - dialogs::DSMessageBox msg(NULL); - msg.mBox()->setText(tr("Protocol Analyzer")); - msg.mBox()->setInformativeText(tr("No Protocol Analyzer to delete!")); - msg.mBox()->setStandardButtons(QMessageBox::Ok); - msg.mBox()->setIcon(QMessageBox::Warning); - msg.exec(); - } - } else { - int del_index = 0; - for (QVector ::const_iterator i = _del_button_list.begin(); - i != _del_button_list.end(); i++) { - if ((*i)->isChecked()) { - _up_layout->removeItem(_hori_layout_list.at(del_index)); - - delete _hori_layout_list.at(del_index); - delete _del_button_list.at(del_index); - delete _set_button_list.at(del_index); - delete _protocol_label_list.at(del_index); - delete _progress_label_list.at(del_index); - - _hori_layout_list.remove(del_index); - _del_button_list.remove(del_index); - _set_button_list.remove(del_index); - _protocol_label_list.remove(del_index); - _progress_label_list.remove(del_index); - _protocol_index_list.remove(del_index); - - _session.remove_decode_signal(del_index); - break; - } - del_index++; - } - } - protocol_updated(); -} + } + void ProtocolDock::del_all_protocol() -{ - if (_hori_layout_list.size() > 0) { - int del_index = 0; - for (QVector ::const_iterator i = _hori_layout_list.begin(); - i != _hori_layout_list.end(); i++) { - _up_layout->removeItem((*i)); - delete (*i); - delete _del_button_list.at(del_index); - delete _set_button_list.at(del_index); - delete _protocol_label_list.at(del_index); - delete _progress_label_list.at(del_index); - +{ + if (_protocolItems.size() > 0) + { + for (auto it = _protocolItems.begin(); it != _protocolItems.end(); it++) + { + _up_layout->removeItem((*it)); + delete (*it); //destory control _session.remove_decode_signal(0); - del_index++; } - _hori_layout_list.clear(); - _del_button_list.clear(); - _set_button_list.clear(); - _protocol_label_list.clear(); - _progress_label_list.clear(); - _protocol_index_list.clear(); - + _protocolItems.clear(); protocol_updated(); } } @@ -484,20 +377,33 @@ void ProtocolDock::decoded_progress(int progress) const std::vector< boost::shared_ptr > decode_sigs( _session.get_decode_signals()); int index = 0; + BOOST_FOREACH(boost::shared_ptr d, decode_sigs) { pg = d->get_progress(); if (d->decoder()->out_of_memory()) err = tr("(Out of Memory)"); - QString progress_str = QString::number(pg) + "%" + err; - if (pg == 100) - _progress_label_list.at(index)->setStyleSheet("color:green;"); - else - _progress_label_list.at(index)->setStyleSheet("color:red;"); - _progress_label_list.at(index)->setText(progress_str); + + if (index < _protocolItems.size()) + { + ProtocolItemLayer &lay = *(_protocolItems.at(index)); + lay.SetProgress(pg, err); + + //when decode complete, check data format + if (pg == 100) + { + // bool flag = ((DecoderStatus*)lay.m_decoderStatus)->m_bNumerical; + // lay.LoadFormatSelect(!flag); + // QString &protocolName = lay.GetProtocolName(); + // lay.SetProtocolFormat(protocolName.toStdString().c_str()); + } + } + index++; } - if (pg == 0 || pg % 10 == 1) - update_model(); + + if (pg == 0 || pg % 10 == 1){ + update_model(); + } } void ProtocolDock::set_model() @@ -836,6 +742,52 @@ void ProtocolDock::search_update() //search_done(); } + //-------------------IProtocolItemLayerCallback +void ProtocolDock::OnProtocolSetting(void *handle){ + int dex = 0; + for (auto it = _protocolItems.begin(); it != _protocolItems.end(); it++){ + if ((*it) == handle){ + _session.rst_decoder(dex); + protocol_updated(); + break; + } + dex++; + } +} + +void ProtocolDock::OnProtocolDelete(void *handle){ + if (!MsgBox::Confirm("Are you sure to remove this protocol analyzer?", this)){ + return; + } + + int dex = 0; + for (auto it = _protocolItems.begin(); it != _protocolItems.end(); it++){ + if ((*it) == handle){ + delete (*it); + _up_layout->removeItem((*it)); //remove child control + _protocolItems.remove(dex); + _session.remove_decode_signal(dex); + protocol_updated(); + break; + } + dex++; + } +} + +void ProtocolDock::OnProtocolFormatChanged(QString format, void *handle){ + for (auto it = _protocolItems.begin(); it != _protocolItems.end(); it++){ + if ((*it) == handle){ + QString &name = (*it)->GetProtocolName(); + AppConfig::Instance().SetProtocolFormat(name.toStdString(), format.toStdString()); + AppConfig::Instance().Save(); + (*it)->m_decoderStatus->m_format = DecoderDataFormat::Parse(format.toStdString().c_str()); + protocol_updated(); + break; + } + } +} +//------------------------- + } // namespace dock } // namespace pv diff --git a/DSView/pv/dock/protocoldock.h b/DSView/pv/dock/protocoldock.h index f5bc4534..d0d35af8 100755 --- a/DSView/pv/dock/protocoldock.h +++ b/DSView/pv/dock/protocoldock.h @@ -41,11 +41,11 @@ #include #include "../data/decodermodel.h" - +#include "protocolitemlayer.h" namespace pv { class SigSession; - + namespace data { class DecoderModel; } @@ -55,8 +55,8 @@ class View; } namespace dock { - -class ProtocolDock : public QScrollArea + +class ProtocolDock : public QScrollArea,public IProtocolItemLayerCallback { Q_OBJECT @@ -79,13 +79,18 @@ protected: void paintEvent(QPaintEvent *); void resizeEvent(QResizeEvent *); +private: + //IProtocolItemLayerCallback + void OnProtocolSetting(void *handle); + void OnProtocolDelete(void *handle); + void OnProtocolFormatChanged(QString format, void *handle); + signals: void protocol_updated(); private slots: - void add_protocol(); - void rst_protocol(); - void del_protocol(); + void on_add_protocol(); + void on_del_all_protocol(); void decoded_progress(int progress); void set_model(); void update_model(); @@ -125,19 +130,14 @@ private: QPushButton *_add_button; QPushButton *_del_all_button; - QComboBox *_protocol_combobox; - QVector _del_button_list; - QVector _set_button_list; - QVector _protocol_label_list; - QVector _progress_label_list; - QVector _protocol_index_list; - QVector _hori_layout_list; + QComboBox *_protocol_combobox; + QVector _protocol_index_list; QVBoxLayout *_up_layout; + QVector _protocolItems; //protocol item layers QPushButton *_dn_set_button; QPushButton *_dn_save_button; QPushButton *_dn_nav_button; - QPushButton *_search_button; mutable boost::mutex _search_mutex; diff --git a/DSView/pv/dock/protocolitemlayer.cpp b/DSView/pv/dock/protocolitemlayer.cpp new file mode 100644 index 00000000..1a0996e1 --- /dev/null +++ b/DSView/pv/dock/protocolitemlayer.cpp @@ -0,0 +1,152 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2013 DreamSourceLab + * + * 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 "protocolitemlayer.h" +#include "../dsvdef.h" +#include +#include + +namespace pv { +namespace dock { + +ProtocolItemLayer::ProtocolItemLayer(QWidget *parent, QString protocolName, IProtocolItemLayerCallback *callback){ + assert(parent); + assert(callback); + + m_callback = callback; + _protocolName = protocolName; + m_bSetting = false; + + _protocol_label = new QLabel(parent); + _progress_label = new QLabel(parent); + _set_button = new QPushButton(parent); + _del_button = new QPushButton(parent); + _format_combox = new QComboBox(parent); + + QString iconPath = ":/icons/" + qApp->property("Style").toString(); + _del_button->setFlat(true); + _del_button->setIcon(QIcon(iconPath + "/del.svg")); + _set_button->setFlat(true); + _set_button->setIcon(QIcon(iconPath + "/gear.svg")); + _protocol_label->setText(protocolName); + + m_singleFlag = true; + m_decoderStatus = NULL; + + LoadFormatSelect(false); + + QHBoxLayout *hori_layout = this; + hori_layout->addWidget(_set_button); + hori_layout->addWidget(_del_button); + hori_layout->addWidget(_format_combox); + hori_layout->addWidget(_protocol_label); + hori_layout->addWidget(_progress_label); + + hori_layout->addStretch(1); + + connect(_del_button, SIGNAL(clicked()),this, SLOT(on_del_protocol())); + + connect(_set_button, SIGNAL(clicked()),this, SLOT(on_set_protocol())); + + connect(_format_combox, SIGNAL(currentIndexChanged(int)),this, SLOT(on_format_select_changed(int))); +} + +ProtocolItemLayer::~ProtocolItemLayer(){ + DESTROY_OBJECT(_set_button); + DESTROY_OBJECT(_del_button); + DESTROY_OBJECT(_protocol_label); + DESTROY_OBJECT(_progress_label); + DESTROY_OBJECT(_format_combox); +} + +//-------------control event +void ProtocolItemLayer::on_set_protocol() +{ + m_callback->OnProtocolSetting(this); +} + +void ProtocolItemLayer::on_del_protocol(){ + m_callback->OnProtocolDelete(this); +} + +void ProtocolItemLayer::on_format_select_changed(int index){ + if (index >= 0 && !m_bSetting){ + QString text = _format_combox->currentText(); + m_callback->OnProtocolFormatChanged(text, this); + } +} +//----------------- + + void ProtocolItemLayer::SetProgress(int progress, QString text){ + QString str = QString::number(progress) + "%" + text; + + if (progress == 100) + _progress_label->setStyleSheet("color:green;"); + else + _progress_label->setStyleSheet("color:red;"); + _progress_label->setText(str); + } + +void ProtocolItemLayer::ResetStyle(){ + QString iconPath = ":/icons/" + qApp->property("Style").toString(); + _del_button->setIcon(QIcon(iconPath + "/del.svg")); + _set_button->setIcon(QIcon(iconPath + "/gear.svg")); +} + +void ProtocolItemLayer::LoadFormatSelect(bool bSingle) +{ + if (bSingle == m_singleFlag){ + return; + } + m_singleFlag = bSingle; + + m_bSetting = true; + _format_combox->clear(); + _format_combox->addItem("ascii"); + int dex = 0; + + if (!bSingle) + { + _format_combox->addItem("dec"); + _format_combox->addItem("hex"); + _format_combox->addItem("oct"); + _format_combox->addItem("bin"); + dex = 2; + } + + _format_combox->setCurrentIndex(dex); + m_bSetting = false; +} + + void ProtocolItemLayer::SetProtocolFormat(const char *format) + { + assert(format); + + m_bSetting = true; + int dex = DecoderDataFormat::Parse(format); + if (dex < (int)_format_combox->count()){ + _format_combox->setCurrentIndex(dex); + } + m_bSetting = false; + } + +} //dock +} //pv diff --git a/DSView/pv/dock/protocolitemlayer.h b/DSView/pv/dock/protocolitemlayer.h new file mode 100644 index 00000000..9f4c8b62 --- /dev/null +++ b/DSView/pv/dock/protocolitemlayer.h @@ -0,0 +1,79 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2013 DreamSourceLab + * + * 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 + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +class DecoderStatus; + +namespace pv{ +namespace dock{ + +class IProtocolItemLayerCallback + { + public: + virtual void OnProtocolSetting(void *handle)=0; + virtual void OnProtocolDelete(void *handle)=0; + virtual void OnProtocolFormatChanged(QString format, void *handle)=0; +}; + +class ProtocolItemLayer: public QHBoxLayout +{ + Q_OBJECT + +public: + ProtocolItemLayer(QWidget *parent, QString protocolName, IProtocolItemLayerCallback *callback); + ~ProtocolItemLayer(); + + void SetProgress(int progress, QString text); + void ResetStyle(); + void LoadFormatSelect(bool bSingle); + inline QString &GetProtocolName(){return _protocolName;} + void SetProtocolFormat(const char *format); + +private slots: + void on_set_protocol(); + void on_del_protocol(); + void on_format_select_changed(int index); + +public: + DecoderStatus *m_decoderStatus; //DecoderStatus + +private: + QLabel *_protocol_label; + QLabel *_progress_label; + QPushButton *_set_button; + QPushButton *_del_button; + QComboBox *_format_combox; + IProtocolItemLayerCallback *m_callback; + QString _protocolName; + bool m_bSetting; + bool m_singleFlag; +}; + + } //dock +} //pv diff --git a/DSView/pv/dsvdef.cpp b/DSView/pv/dsvdef.cpp new file mode 100644 index 00000000..c6478b51 --- /dev/null +++ b/DSView/pv/dsvdef.cpp @@ -0,0 +1,46 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2012 Joel Holdsworth + * Copyright (C) 2013 DreamSourceLab + * + * 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 "dsvdef.h" +#include + +namespace DecoderDataFormat +{ + int Parse(const char *name){ + if (strcmp(name, "ascii") == 0){ + return (int)ascii; + } + if (strcmp(name, "dec") == 0){ + return (int)dec; + } + if (strcmp(name, "hex") == 0){ + return (int)hex; + } + if (strcmp(name, "oct") == 0){ + return (int)oct; + } + if (strcmp(name, "bin") == 0){ + return (int)bin; + } + return (int)ascii; + } +} diff --git a/DSView/pv/dsvdef.h b/DSView/pv/dsvdef.h new file mode 100644 index 00000000..2647f613 --- /dev/null +++ b/DSView/pv/dsvdef.h @@ -0,0 +1,39 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2012 Joel Holdsworth + * Copyright (C) 2013 DreamSourceLab + * + * 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 + */ + +#pragma once + +#define DESTROY_OBJECT(p) if ((p)){delete (p); p = NULL;} + +namespace DecoderDataFormat +{ + enum _data_format + { + ascii = 0, + dec, + hex, + oct, + bin + }; + + int Parse(const char *name); +} diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index b585a0f9..06c30bc9 100755 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -90,6 +90,7 @@ #include #include #include +#include "../ui/msgbox.h" using boost::shared_ptr; using boost::dynamic_pointer_cast; @@ -938,12 +939,7 @@ bool MainWindow::load_session_json(QJsonDocument json, bool file_dev) const sr_dev_inst *const sdi = _session.get_device()->dev_inst(); if ((!file_dev && strcmp(sdi->driver->name, sessionObj["Device"].toString().toUtf8()) != 0) || sdi->mode != sessionObj["DeviceMode"].toDouble()) { - dialogs::DSMessageBox msg(this); - msg.mBox()->setText(tr("Session Error")); - msg.mBox()->setInformativeText(tr("Session File is not compatible with current device or mode!")); - msg.mBox()->setStandardButtons(QMessageBox::Ok); - msg.mBox()->setIcon(QMessageBox::Warning); - msg.exec(); + MsgBox::Show(NULL, "Session File is not compatible with current device or mode!", this); return false; } @@ -1128,12 +1124,6 @@ bool MainWindow::store_session(QString name) { QFile sessionFile(name); if (!sessionFile.open(QIODevice::WriteOnly | QIODevice::Text)) { -// dialogs::DSMessageBox msg(this); -// msg.mBox()->setText(tr("File Error")); -// msg.mBox()->setInformativeText(tr("Couldn't open session file to write!")); -// msg.mBox()->setStandardButtons(QMessageBox::Ok); -// msg.mBox()->setIcon(QMessageBox::Warning); -// msg.exec(); qDebug("Warning: Couldn't open session file to write!"); return false; } diff --git a/DSView/pv/prop/binding/binding.cpp b/DSView/pv/prop/binding/binding.cpp index c5252716..db9a0453 100755 --- a/DSView/pv/prop/binding/binding.cpp +++ b/DSView/pv/prop/binding/binding.cpp @@ -56,12 +56,18 @@ void Binding::add_properties_to_form(QFormLayout *layout, { assert(p); - QWidget *const widget = p->get_widget(layout->parentWidget(), - auto_commit); + QWidget *const widget = p->get_widget(layout->parentWidget(), auto_commit); + if (p->labeled_widget()) layout->addRow(widget); - else - layout->addRow(p->label(), widget); + else{ + const QString &lbstr = p->label(); + //remove data format options + if (lbstr == "Data format"){ + continue; + } + layout->addRow(p->label(), widget); + } } } diff --git a/DSView/pv/sigsession.cpp b/DSView/pv/sigsession.cpp index df1afdc0..1912088f 100755 --- a/DSView/pv/sigsession.cpp +++ b/DSView/pv/sigsession.cpp @@ -66,6 +66,7 @@ #include #include +#include "data/decode/decoderstatus.h" //using boost::dynamic_pointer_cast; //using boost::function; @@ -1366,8 +1367,8 @@ uint16_t SigSession::get_ch_num(int type) } #ifdef ENABLE_DECODE -bool SigSession::add_decoder(srd_decoder *const dec, bool silent) -{ +bool SigSession::add_decoder(srd_decoder *const dec, bool silent, DecoderStatus *dstatus) +{ bool ret = false; map probes; boost::shared_ptr decoder_stack; @@ -1377,7 +1378,7 @@ bool SigSession::add_decoder(srd_decoder *const dec, bool silent) // Create the decoder decoder_stack = boost::shared_ptr( - new data::DecoderStack(*this, dec)); + new data::DecoderStack(*this, dec, dstatus)); // Make a list of all the probes std::vector all_probes; diff --git a/DSView/pv/sigsession.h b/DSView/pv/sigsession.h index 0f9d46ca..c895c07e 100755 --- a/DSView/pv/sigsession.h +++ b/DSView/pv/sigsession.h @@ -55,6 +55,8 @@ struct srd_decoder; struct srd_channel; +class DecoderStatus; + namespace pv { class DeviceManager; @@ -178,7 +180,7 @@ public: get_group_signals(); #ifdef ENABLE_DECODE - bool add_decoder(srd_decoder *const dec, bool silent); + bool add_decoder(srd_decoder *const dec, bool silent, DecoderStatus *dstatus); std::vector< boost::shared_ptr > get_decode_signals() const; diff --git a/DSView/pv/storesession.cpp b/DSView/pv/storesession.cpp index 18ad1bd5..e77345bd 100755 --- a/DSView/pv/storesession.cpp +++ b/DSView/pv/storesession.cpp @@ -346,7 +346,6 @@ void StoreSession::save_proc(shared_ptr snapshot) if (ret != SR_OK) { if (!_has_error) { _has_error = true; - auto err = m_zipDoc.GetError(); _error = tr("Failed to create zip file. Please check write permission of this path."); } progress_updated(); diff --git a/DSView/pv/ui/msgbox.cpp b/DSView/pv/ui/msgbox.cpp new file mode 100644 index 00000000..4c9a6357 --- /dev/null +++ b/DSView/pv/ui/msgbox.cpp @@ -0,0 +1,56 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2012 Joel Holdsworth + * Copyright (C) 2013 DreamSourceLab + * + * 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 "msgbox.h" +#include "../dialogs/dsmessagebox.h" +#include +#include +#include + +//QMessageBox::information(NULL, "Title", "Content",QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); +//QMessageBox::information(NULL, "Title", "Content",QMessageBox::Yes|QMessageBox::No); +//QMessageBox::information(NULL, "Title", "Content"); +//QMessageBox::information(NULL, "Title", "Content",QMessageBox::Yes|QMessageBox::No|QMessageBox::Abort); + +void MsgBox::Show(const char *title, const char *text, QWidget *parent) +{ + assert(text); + + pv::dialogs::DSMessageBox msg(parent, title); + msg.mBox()->setText(QString(text)); + // msg.mBox()->setInformativeText(QString(text)); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); + msg.exec(); +} + +bool MsgBox::Confirm(const char *text, QWidget *parent) +{ + assert(text); + + pv::dialogs::DSMessageBox msg(parent, "Question"); + msg.mBox()->setText(QString(text)); + msg.mBox()->setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msg.mBox()->setIcon(QMessageBox::Question); + msg.exec(); + int click = msg.GetLastClick(); + return (click == (int)QMessageBox::YesRole); +} diff --git a/DSView/pv/ui/msgbox.h b/DSView/pv/ui/msgbox.h new file mode 100644 index 00000000..7b725158 --- /dev/null +++ b/DSView/pv/ui/msgbox.h @@ -0,0 +1,33 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2012 Joel Holdsworth + * Copyright (C) 2013 DreamSourceLab + * + * 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 + */ + +#pragma once + +class QWidget; + +class MsgBox +{ +public: + static void Show(const char *title, const char *text, QWidget *parent=0); + + static bool Confirm(const char *text, QWidget *parent=0); +}; \ No newline at end of file diff --git a/DSView/pv/view/decodetrace.cpp b/DSView/pv/view/decodetrace.cpp index 733497fb..e44f1dce 100755 --- a/DSView/pv/view/decodetrace.cpp +++ b/DSView/pv/view/decodetrace.cpp @@ -52,10 +52,11 @@ #include "../device/devinst.h" #include "../view/cursor.h" #include "../toolbars/titlebar.h" +#include "../dsvdef.h" using namespace boost; using namespace std; - + namespace pv { namespace view { @@ -138,14 +139,20 @@ DecodeTrace::DecodeTrace(pv::SigSession &session, this, SLOT(on_new_decode_data())); connect(_decoder_stack.get(), SIGNAL(decode_done()), this, SLOT(on_decode_done())); + + _start_comboBox = NULL; + _end_comboBox = NULL; + _pub_input_layer = NULL; } DecodeTrace::~DecodeTrace() { - if (_popup_form) - delete _popup_form; - if (_popup) - delete _popup; + DESTROY_OBJECT(_start_comboBox); + DESTROY_OBJECT(_end_comboBox); + DESTROY_OBJECT(_pub_input_layer); + DESTROY_OBJECT(_popup_form); + DESTROY_OBJECT(_popup); + _cur_row_headings.clear(); _decoder_forms.clear(); _probe_selectors.clear(); @@ -342,6 +349,7 @@ void DecodeTrace::paint_fore(QPainter &p, int left, int right, QColor fore, QCol (void)back; } +//to show decoder's property setting dialog bool DecodeTrace::create_popup() { int ret = false; @@ -363,10 +371,12 @@ bool DecodeTrace::create_popup() } } - delete _popup_form; - delete _popup; - _popup = NULL; - _popup_form = NULL; + //destroy object + DESTROY_OBJECT(_start_comboBox); + DESTROY_OBJECT(_end_comboBox); + DESTROY_OBJECT(_pub_input_layer); + DESTROY_OBJECT(_popup_form); + DESTROY_OBJECT(_popup); return ret; } @@ -409,7 +419,7 @@ void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form) if (stack.empty()) { QLabel *const l = new QLabel( - tr("

No decoders in the stack

")); + tr("

No decoders in the stack

")); l->setAlignment(Qt::AlignCenter); form->addRow(l); } else { @@ -422,7 +432,11 @@ void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form) tr("* Required channels"), parent)); } - // Add region combobox + //public input layer + // QFormLayout *publay = new QFormLayout(); + // form->addRow(publay); + + //Add region combobox _start_comboBox = new QComboBox(parent); _end_comboBox = new QComboBox(parent); _start_comboBox->addItem(RegionStart); diff --git a/DSView/pv/view/decodetrace.h b/DSView/pv/view/decodetrace.h index 1fcb1257..924cf333 100755 --- a/DSView/pv/view/decodetrace.h +++ b/DSView/pv/view/decodetrace.h @@ -213,6 +213,7 @@ private: int _start_index, _end_index; int _start_count, _end_count; QComboBox *_start_comboBox, *_end_comboBox; + QFormLayout *_pub_input_layer; int _progress; std::list< boost::shared_ptr > From 3de6eb1ada82438453310cbb9cadca4bb0cdef6d Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Tue, 19 Oct 2021 16:17:46 +0800 Subject: [PATCH 08/60] optimize save session speed --- DSView/main.cpp | 5 +- DSView/pv/ZipMaker.cpp | 312 +++-- DSView/pv/ZipMaker.h | 53 +- DSView/pv/minizip/crypt.h | 131 +++ DSView/pv/minizip/ioapi.c | 247 ++++ DSView/pv/minizip/ioapi.h | 208 ++++ DSView/pv/minizip/iowin32.c | 462 ++++++++ DSView/pv/minizip/iowin32.h | 28 + DSView/pv/minizip/miniunz.c | 660 +++++++++++ DSView/pv/minizip/minizip.c | 520 +++++++++ DSView/pv/minizip/mztools.c | 291 +++++ DSView/pv/minizip/mztools.h | 37 + DSView/pv/minizip/unzip.c | 2125 +++++++++++++++++++++++++++++++++++ DSView/pv/minizip/unzip.h | 437 +++++++ DSView/pv/minizip/zip.c | 2007 +++++++++++++++++++++++++++++++++ DSView/pv/minizip/zip.h | 362 ++++++ DSView/pv/storesession.cpp | 8 +- 17 files changed, 7755 insertions(+), 138 deletions(-) create mode 100644 DSView/pv/minizip/crypt.h create mode 100644 DSView/pv/minizip/ioapi.c create mode 100644 DSView/pv/minizip/ioapi.h create mode 100644 DSView/pv/minizip/iowin32.c create mode 100644 DSView/pv/minizip/iowin32.h create mode 100644 DSView/pv/minizip/miniunz.c create mode 100644 DSView/pv/minizip/minizip.c create mode 100644 DSView/pv/minizip/mztools.c create mode 100644 DSView/pv/minizip/mztools.h create mode 100644 DSView/pv/minizip/unzip.c create mode 100644 DSView/pv/minizip/unzip.h create mode 100644 DSView/pv/minizip/zip.c create mode 100644 DSView/pv/minizip/zip.h diff --git a/DSView/main.cpp b/DSView/main.cpp index 1a51a86f..04ad160e 100755 --- a/DSView/main.cpp +++ b/DSView/main.cpp @@ -42,7 +42,6 @@ #include "pv/devicemanager.h" #include "pv/mainframe.h" #include "pv/config/appconfig.h" - #include "config.h" char DS_RES_PATH[256]; @@ -58,10 +57,10 @@ void usage() " -V, --version Show release version\n" " -h, -?, --help Show help option\n" "\n", DS_BIN_NAME, DS_DESCRIPTION); -} +} int main(int argc, char *argv[]) -{ +{ int ret = 0; struct sr_context *sr_ctx = NULL; const char *open_file = NULL; diff --git a/DSView/pv/ZipMaker.cpp b/DSView/pv/ZipMaker.cpp index cdda2d33..69f6ef0d 100644 --- a/DSView/pv/ZipMaker.cpp +++ b/DSView/pv/ZipMaker.cpp @@ -21,20 +21,23 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "ZipMaker.h" -#include -#include +#include "ZipMaker.h" #include #include -#include #include +#include +#include + +#include "minizip/zip.h" +#include "minizip/unzip.h" ZipMaker::ZipMaker() : - m_docSource(NULL), - m_errobj(NULL) + m_zDoc(NULL) { - m_error[0] = 0; + m_error[0] = 0; + m_opt_compress_level = Z_DEFAULT_COMPRESSION; + m_zi = NULL; } ZipMaker::~ZipMaker() @@ -42,116 +45,78 @@ ZipMaker::~ZipMaker() Release(); } -bool ZipMaker::CreateNew() +bool ZipMaker::CreateNew(const char *fileName, bool bAppend) { + assert(fileName); + Release(); - - m_errobj = new zip_error_t(); - zip_error_init(m_errobj); - - if ((m_docSource = zip_source_buffer_create(NULL, 0, 0, m_errobj)) == NULL) { - sprintf(m_error, "can't create source: %s", zip_error_strerror(m_errobj)); - } - return m_docSource != NULL; + m_zDoc = zipOpen64(fileName, bAppend); + if (m_zDoc == NULL) { + strcpy(m_error, "zipOpen64 error"); + } + +//make zip inner file time + m_zi = new zip_fileinfo(); + + time_t rawtime; + time (&rawtime); + struct tm *tinf= localtime(&rawtime); + + struct tm &ti = *tinf; + zip_fileinfo &zi= *(zip_fileinfo*)m_zi; + + zi.tmz_date.tm_year = ti.tm_year; + zi.tmz_date.tm_mon = ti.tm_mon; + zi.tmz_date.tm_mday = ti.tm_mday; + zi.tmz_date.tm_hour = ti.tm_hour; + zi.tmz_date.tm_min = ti.tm_min; + zi.tmz_date.tm_sec = ti.tm_sec; + zi.dosDate = 0; + + return m_zDoc != NULL; } void ZipMaker::Release() -{ - if (m_errobj){ - zip_error_fini(m_errobj); //release the error obj - delete m_errobj; - m_errobj = NULL; - } - - if (m_docSource){ - zip_source_free(m_docSource); - m_docSource = NULL; +{ + if (m_zDoc){ + zipClose((zipFile)m_zDoc, NULL); + m_zDoc = NULL; + } + if (m_zi){ + delete ((zip_fileinfo*)m_zi); + m_zi = NULL; } } -bool ZipMaker::SaveToFile(const char *fileName){ - assert(fileName); - assert(m_docSource); - - zip_stat_t zst; - if (zip_source_stat(m_docSource, &zst) < 0) { - sprintf(m_error, "can't stat source: %s\n", zip_error_strerror(zip_source_error(m_docSource))); - return 1; - } - - long long size = zst.size; - void *data = NULL; - FILE *fp = NULL; - bool berr = false; - - if (zip_source_open(m_docSource) < 0) { - sprintf(m_error, "can't open source: %s\n", zip_error_strerror(zip_source_error(m_docSource))); - return false; - } - if (!berr && (data = malloc(size)) == NULL) { - sprintf(m_error, "malloc failed: %s\n", strerror(errno)); - berr = true; - } - - if ((zip_uint64_t)zip_source_read(m_docSource, data, size) < size) { - sprintf(m_error, "can't read data from source: %s\n", zip_error_strerror(zip_source_error(m_docSource))); - berr = true; - } - - if (!berr && (fp = fopen(fileName, "wb")) == NULL) { - sprintf(m_error, "can't open %s: %s\n", fileName, strerror(errno)); - berr = true; - } - if (!berr && fwrite(data, 1, size, fp) < size) { - sprintf(m_error, "can't write %s: %s\n", fileName, strerror(errno)); - berr = true; - fclose(fp); - } - if (!berr && fclose(fp) < 0) { - sprintf(m_error, "can't write %s: %s\n", fileName, strerror(errno)); - berr = true; - } - - zip_source_close(m_docSource); - if (data){ - free(data); - } - - return !berr; +bool ZipMaker::Close(){ + if (m_zDoc){ + zipClose((zipFile)m_zDoc, NULL); + m_zDoc = NULL; + return true; + } + return false; } -bool ZipMaker::AddFromBuffer(const char *innerFile, const char *buffer, int buferSize) +bool ZipMaker::AddFromBuffer(const char *innerFile, const char *buffer, unsigned int buferSize) { assert(buffer); assert(innerFile); - assert(m_docSource); + assert(m_zDoc); + int level = m_opt_compress_level; - zip_t *zip_archive = zip_open_from_source(m_docSource, 0, m_errobj); - if (zip_archive == NULL) - { - sprintf(m_error, "can't open zip from source: %s", zip_error_strerror(m_errobj)); - return false; + if (level < Z_DEFAULT_COMPRESSION || level > Z_BEST_COMPRESSION){ + level = Z_DEFAULT_COMPRESSION; } - zip_source_keep(m_docSource); + zipOpenNewFileInZip((zipFile)m_zDoc,innerFile,(zip_fileinfo*)m_zi, + NULL,0,NULL,0,NULL , + Z_DEFLATED, + level); - zip_source_t *src = zip_source_buffer(zip_archive, buffer, buferSize, 0); - if (src == NULL){ - sprintf(m_error, "zip_source_buffer error: %s", zip_error_strerror(zip_source_error(m_docSource))); - return false; - } + zipWriteInFileInZip((zipFile)m_zDoc, buffer, (unsigned int)buferSize); - if (zip_file_add(zip_archive, innerFile, src, ZIP_FL_OVERWRITE) == -1) - { - sprintf(m_error, "zip_file_add error: %s", zip_error_strerror(zip_source_error(m_docSource))); - return false; - } - - if (zip_close(zip_archive) < 0) { - sprintf(m_error, "zip_close'%s'", zip_strerror(zip_archive)); - return false; - } + zipCloseFileInZip((zipFile)m_zDoc); return true; } @@ -159,36 +124,41 @@ bool ZipMaker::AddFromBuffer(const char *innerFile, const char *buffer, int bufe bool ZipMaker::AddFromFile(const char *localFile, const char *innerFile) { assert(localFile); - assert(innerFile); - assert(m_docSource); - zip_t *zip_archive = zip_open_from_source(m_docSource, 0, m_errobj); - if (zip_archive == NULL) - { - sprintf(m_error, "can't open zip from source: %s", zip_error_strerror(m_errobj)); - return false; - } - - zip_source_keep(m_docSource); - - zip_source_t *src = zip_source_file(zip_archive, localFile, 0, -1); - if (src == NULL){ - sprintf(m_error, "zip_source_buffer error: %s\n", zip_error_strerror(zip_source_error(m_docSource))); + struct stat st; + FILE *fp; + char *data = NULL; + long long size = 0; + + if ((fp = fopen(localFile, "rb")) == NULL) { + strcpy(m_error, "fopen error"); return false; } - if (zip_add(zip_archive, innerFile, src) == -1) - { - sprintf(m_error, "zip_file_add error: %s\n", zip_error_strerror(zip_source_error(m_docSource))); + if (fstat(fileno(fp), &st) < 0) { + strcpy(m_error, "fstat error"); + fclose(fp); + return -1; + } + + if ((data = (char*)malloc((size_t)st.st_size)) == NULL) { + strcpy(m_error, "can't malloc buffer"); + fclose(fp); return false; } - if (zip_close(zip_archive) < 0) { - sprintf(m_error, "zip_close'%s'", zip_strerror(zip_archive)); - return false; + if (fread(data, 1, (size_t)st.st_size, fp) < (size_t)st.st_size) { + strcpy(m_error, "fread error"); + free(data); + fclose(fp); + return false; } - return true; + fclose(fp); + size = (size_t)st.st_size; + + bool ret = AddFromBuffer(innerFile, data, size); + return ret; } const char *ZipMaker::GetError() @@ -197,3 +167,107 @@ const char *ZipMaker::GetError() return m_error; return NULL; } + + +//------------------------ZipDecompress + ZipDecompress::ZipDecompress() + { + m_uzDoc = NULL; + m_curIndex = 0; + m_fileCount = 0; + m_bufferSize = 0; + m_buffer = NULL; + } + + ZipDecompress::~ZipDecompress() + { + Close(); + } + + bool ZipDecompress::Open(const char *fileName) + { + assert(fileName); + m_uzDoc = unzOpen64(fileName); + + if (m_uzDoc){ + m_uzi = new unz_file_info64(); + unz_global_info64 inf; + unzGetGlobalInfo64((unzFile)m_uzDoc, &inf); + m_fileCount = (int)inf.number_entry; + } + return m_uzDoc != NULL; + } + + void ZipDecompress::Close() + { + if (m_uzDoc) + { + unzClose((unzFile)m_uzDoc); + m_uzDoc = NULL; + } + if (m_uzi){ + delete ((unz_file_info64*)m_uzi); + m_uzi = NULL; + } + if (m_buffer){ + free(m_buffer); + m_buffer = NULL; + } + } + + bool ZipDecompress::ReadNextFileData(UnZipFileInfo &inf) +{ + assert(m_uzDoc); + + if (m_curIndex >= m_fileCount){ + strcpy(m_error, "read index is last"); + return false; + } + m_curIndex++; + + int ret = unzGetCurrentFileInfo64((unzFile)m_uzDoc, (unz_file_info64*)m_uzi, inf.inFileName, 256, NULL, 0, NULL, 0); + if (ret != UNZ_OK){ + strcpy(m_error, "unzGetCurrentFileInfo64 error"); + return false; + } + unz_file_info64 &uzinf = *(unz_file_info64*)m_uzi; + inf.dataLen = uzinf.uncompressed_size; + inf.inFileNameLen = uzinf.size_filename; + + // need malloc memory buffer + if (m_buffer == NULL || inf.dataLen > m_bufferSize){ + if (m_buffer) free(m_buffer); + m_buffer = NULL; + + m_buffer = malloc(inf.dataLen + 10); + if (m_buffer == NULL){ + strcpy(m_error, "malloc get null"); + return false; + } + } + + inf.pData = m_buffer; + + unzOpenCurrentFile((unzFile)m_uzDoc); + + //read file data to buffer + void *buf = inf.pData; + long long buflen = inf.dataLen; + long long rdlen = 0; + + while (rdlen < inf.dataLen) + { + int dlen = unzReadCurrentFile((unzFile)m_uzDoc, buf, buflen); + if (dlen == 0){ + break; + } + rdlen += dlen; + buf = buf + dlen; //move pointer + buflen = inf.dataLen - rdlen; + } + + unzCloseCurrentFile((unzFile)m_uzDoc); + unzGoToNextFile((unzFile)m_uzDoc); + + return true; +} diff --git a/DSView/pv/ZipMaker.h b/DSView/pv/ZipMaker.h index 2e988c12..703c440d 100644 --- a/DSView/pv/ZipMaker.h +++ b/DSView/pv/ZipMaker.h @@ -22,14 +22,17 @@ //test git 2 -#pragma once +#pragma once -struct zip_source; -struct zip_error; - -typedef struct zip_source zip_archive_source_t; -typedef struct zip_error zip_err_t; +typedef struct +{ + char inFileName[256]; + int inFileNameLen; + void *pData; + long long dataLen; +} UnZipFileInfo; + class ZipMaker { public: @@ -38,16 +41,16 @@ public: ~ZipMaker(); //create new zip archive in the memory - bool CreateNew(); + bool CreateNew(const char *fileName, bool bAppend); //free the source void Release(); //save data to file - bool SaveToFile(const char *fileName); + bool Close(); //add a inner file from buffer - bool AddFromBuffer(const char *innerFile, const char *buffer, int buferSize); + bool AddFromBuffer(const char *innerFile, const char *buffer, unsigned int buferSize); //add a inner file from local file bool AddFromFile(const char *localFile, const char *innerFile); @@ -55,8 +58,34 @@ public: //get the last error const char *GetError(); +public: + int m_opt_compress_level; + private: - zip_archive_source_t *m_docSource; //zip file handle - zip_err_t *m_errobj; - char m_error[500]; + void *m_zDoc; //zip file handle + void *m_zi; //life must as m_zDoc; + char m_error[500]; +}; + +class ZipDecompress +{ +public: + ZipDecompress(); + + ~ZipDecompress(); + + bool Open(const char *fileName); + + void Close(); + + bool ReadNextFileData(UnZipFileInfo &inf); + +private: + void *m_uzDoc; + void *m_uzi; + int m_fileCount; + int m_curIndex; + char m_error[500]; + void *m_buffer; // file read buffer + long long m_bufferSize; }; diff --git a/DSView/pv/minizip/crypt.h b/DSView/pv/minizip/crypt.h new file mode 100644 index 00000000..1e9e8200 --- /dev/null +++ b/DSView/pv/minizip/crypt.h @@ -0,0 +1,131 @@ +/* crypt.h -- base code for crypt/uncrypt ZIPfile + + + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant + + This code is a modified version of crypting code in Infozip distribution + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + If you don't need crypting in your application, just define symbols + NOCRYPT and NOUNCRYPT. + + This code support the "Traditional PKWARE Encryption". + + The new AES encryption added on Zip format by Winzip (see the page + http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong + Encryption is not supported. +*/ + +#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) + +/*********************************************************************** + * Return the next byte in the pseudo-random sequence + */ +static int decrypt_byte(unsigned long* pkeys, const z_crc_t* pcrc_32_tab) +{ + unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an + * unpredictable manner on 16-bit systems; not a problem + * with any known compiler so far, though */ + + temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; + return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); +} + +/*********************************************************************** + * Update the encryption keys with the next byte of plain text + */ +static int update_keys(unsigned long* pkeys,const z_crc_t* pcrc_32_tab,int c) +{ + (*(pkeys+0)) = CRC32((*(pkeys+0)), c); + (*(pkeys+1)) += (*(pkeys+0)) & 0xff; + (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; + { + register int keyshift = (int)((*(pkeys+1)) >> 24); + (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); + } + return c; +} + + +/*********************************************************************** + * Initialize the encryption keys and the random header according to + * the given password. + */ +static void init_keys(const char* passwd,unsigned long* pkeys,const z_crc_t* pcrc_32_tab) +{ + *(pkeys+0) = 305419896L; + *(pkeys+1) = 591751049L; + *(pkeys+2) = 878082192L; + while (*passwd != '\0') { + update_keys(pkeys,pcrc_32_tab,(int)*passwd); + passwd++; + } +} + +#define zdecode(pkeys,pcrc_32_tab,c) \ + (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) + +#define zencode(pkeys,pcrc_32_tab,c,t) \ + (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) + +#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED + +#define RAND_HEAD_LEN 12 + /* "last resort" source for second part of crypt seed pattern */ +# ifndef ZCR_SEED2 +# define ZCR_SEED2 3141592654UL /* use PI as default pattern */ +# endif + +static int crypthead(const char* passwd, /* password string */ + unsigned char* buf, /* where to write header */ + int bufSize, + unsigned long* pkeys, + const z_crc_t* pcrc_32_tab, + unsigned long crcForCrypting) +{ + int n; /* index in random header */ + int t; /* temporary */ + int c; /* random byte */ + unsigned char header[RAND_HEAD_LEN-2]; /* random header */ + static unsigned calls = 0; /* ensure different random header each time */ + + if (bufSize> 7) & 0xff; + header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); + } + /* Encrypt random header (last two bytes is high word of crc) */ + init_keys(passwd, pkeys, pcrc_32_tab); + for (n = 0; n < RAND_HEAD_LEN-2; n++) + { + buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); + } + buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); + buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); + return n; +} + +#endif diff --git a/DSView/pv/minizip/ioapi.c b/DSView/pv/minizip/ioapi.c new file mode 100644 index 00000000..7f5c191b --- /dev/null +++ b/DSView/pv/minizip/ioapi.c @@ -0,0 +1,247 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + +*/ + +#if defined(_WIN32) && (!(defined(_CRT_SECURE_NO_WARNINGS))) + #define _CRT_SECURE_NO_WARNINGS +#endif + +#if defined(__APPLE__) || defined(IOAPI_NO_64) +// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions +#define FOPEN_FUNC(filename, mode) fopen(filename, mode) +#define FTELLO_FUNC(stream) ftello(stream) +#define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin) +#else +#define FOPEN_FUNC(filename, mode) fopen64(filename, mode) +#define FTELLO_FUNC(stream) ftello64(stream) +#define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin) +#endif + + +#include "ioapi.h" + +voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode) +{ + if (pfilefunc->zfile_func64.zopen64_file != NULL) + return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode); + else + { + return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode); + } +} + +long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) +{ + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin); + else + { + uLong offsetTruncated = (uLong)offset; + if (offsetTruncated != offset) + return -1; + else + return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin); + } +} + +ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream) +{ + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream); + else + { + uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream); + if ((tell_uLong) == MAXU32) + return (ZPOS64_T)-1; + else + return tell_uLong; + } +} + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32) +{ + p_filefunc64_32->zfile_func64.zopen64_file = NULL; + p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file; + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; + p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file; + p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file; + p_filefunc64_32->zfile_func64.ztell64_file = NULL; + p_filefunc64_32->zfile_func64.zseek64_file = NULL; + p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file; + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; + p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque; + p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file; + p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file; +} + + + +static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode)); +static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size)); +static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream)); +static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream)); +static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream)); + +static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode) +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = fopen(filename, mode_fopen); + return file; +} + +static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode) +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = FOPEN_FUNC((const char*)filename, mode_fopen); + return file; +} + + +static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size) +{ + uLong ret; + ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size) +{ + uLong ret; + ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream) +{ + long ret; + ret = ftell((FILE *)stream); + return ret; +} + + +static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream) +{ + ZPOS64_T ret; + ret = FTELLO_FUNC((FILE *)stream); + return ret; +} + +static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin) +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + if (fseek((FILE *)stream, offset, fseek_origin) != 0) + ret = -1; + return ret; +} + +static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + + if(FSEEKO_FUNC((FILE *)stream, offset, fseek_origin) != 0) + ret = -1; + + return ret; +} + + +static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream) +{ + int ret; + ret = fclose((FILE *)stream); + return ret; +} + +static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream) +{ + int ret; + ret = ferror((FILE *)stream); + return ret; +} + +void fill_fopen_filefunc (pzlib_filefunc_def) + zlib_filefunc_def* pzlib_filefunc_def; +{ + pzlib_filefunc_def->zopen_file = fopen_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell_file = ftell_file_func; + pzlib_filefunc_def->zseek_file = fseek_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} + +void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = fopen64_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell64_file = ftell64_file_func; + pzlib_filefunc_def->zseek64_file = fseek64_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} diff --git a/DSView/pv/minizip/ioapi.h b/DSView/pv/minizip/ioapi.h new file mode 100644 index 00000000..8dcbdb06 --- /dev/null +++ b/DSView/pv/minizip/ioapi.h @@ -0,0 +1,208 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + Changes + + Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this) + Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux. + More if/def section may be needed to support other platforms + Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows. + (but you should use iowin32.c for windows instead) + +*/ + +#ifndef _ZLIBIOAPI64_H +#define _ZLIBIOAPI64_H + +#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__)) + + // Linux needs this to support file operation on files larger then 4+GB + // But might need better if/def to select just the platforms that needs them. + + #ifndef __USE_FILE_OFFSET64 + #define __USE_FILE_OFFSET64 + #endif + #ifndef __USE_LARGEFILE64 + #define __USE_LARGEFILE64 + #endif + #ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE + #endif + #ifndef _FILE_OFFSET_BIT + #define _FILE_OFFSET_BIT 64 + #endif + +#endif + +#include +#include +#include "zlib.h" + +#if defined(USE_FILE32API) +#define fopen64 fopen +#define ftello64 ftell +#define fseeko64 fseek +#else +#ifdef __FreeBSD__ +#define fopen64 fopen +#define ftello64 ftello +#define fseeko64 fseeko +#endif +#ifdef _MSC_VER + #define fopen64 fopen + #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) + #define ftello64 _ftelli64 + #define fseeko64 _fseeki64 + #else // old MSC + #define ftello64 ftell + #define fseeko64 fseek + #endif +#endif +#endif + +/* +#ifndef ZPOS64_T + #ifdef _WIN32 + #define ZPOS64_T fpos_t + #else + #include + #define ZPOS64_T uint64_t + #endif +#endif +*/ + +#ifdef HAVE_MINIZIP64_CONF_H +#include "mz64conf.h" +#endif + +/* a type choosen by DEFINE */ +#ifdef HAVE_64BIT_INT_CUSTOM +typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; +#else +#ifdef HAS_STDINT_H +#include "stdint.h" +typedef uint64_t ZPOS64_T; +#else + +/* Maximum unsigned 32-bit value used as placeholder for zip64 */ +#define MAXU32 0xffffffff + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef unsigned __int64 ZPOS64_T; +#else +typedef unsigned long long int ZPOS64_T; +#endif +#endif +#endif + + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define ZLIB_FILEFUNC_SEEK_CUR (1) +#define ZLIB_FILEFUNC_SEEK_END (2) +#define ZLIB_FILEFUNC_SEEK_SET (0) + +#define ZLIB_FILEFUNC_MODE_READ (1) +#define ZLIB_FILEFUNC_MODE_WRITE (2) +#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) + +#define ZLIB_FILEFUNC_MODE_EXISTING (4) +#define ZLIB_FILEFUNC_MODE_CREATE (8) + + +#ifndef ZCALLBACK + #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) + #define ZCALLBACK CALLBACK + #else + #define ZCALLBACK + #endif +#endif + + + + +typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); +typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); +typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); + +typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); + + +/* here is the "old" 32 bits structure structure */ +typedef struct zlib_filefunc_def_s +{ + open_file_func zopen_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell_file_func ztell_file; + seek_file_func zseek_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc_def; + +typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode)); + +typedef struct zlib_filefunc64_def_s +{ + open64_file_func zopen64_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell64_file_func ztell64_file; + seek64_file_func zseek64_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc64_def; + +void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); + +/* now internal definition, only for zip.c and unzip.h */ +typedef struct zlib_filefunc64_32_def_s +{ + zlib_filefunc64_def zfile_func64; + open_file_func zopen32_file; + tell_file_func ztell32_file; + seek_file_func zseek32_file; +} zlib_filefunc64_32_def; + + +#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +//#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream)) +//#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode)) +#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) +#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) + +voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)); +long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)); +ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)); + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32); + +#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) +#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) +#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode))) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/DSView/pv/minizip/iowin32.c b/DSView/pv/minizip/iowin32.c new file mode 100644 index 00000000..274f39eb --- /dev/null +++ b/DSView/pv/minizip/iowin32.c @@ -0,0 +1,462 @@ +/* iowin32.c -- IO base function header for compress/uncompress .zip + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + +*/ + +#include + +#include "zlib.h" +#include "ioapi.h" +#include "iowin32.h" + +#ifndef INVALID_HANDLE_VALUE +#define INVALID_HANDLE_VALUE (0xFFFFFFFF) +#endif + +#ifndef INVALID_SET_FILE_POINTER +#define INVALID_SET_FILE_POINTER ((DWORD)-1) +#endif + + +// see Include/shared/winapifamily.h in the Windows Kit +#if defined(WINAPI_FAMILY_PARTITION) && (!(defined(IOWIN32_USING_WINRT_API))) +#if WINAPI_FAMILY_ONE_PARTITION(WINAPI_FAMILY, WINAPI_PARTITION_APP) +#define IOWIN32_USING_WINRT_API 1 +#endif +#endif + +voidpf ZCALLBACK win32_open_file_func OF((voidpf opaque, const char* filename, int mode)); +uLong ZCALLBACK win32_read_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +uLong ZCALLBACK win32_write_file_func OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +ZPOS64_T ZCALLBACK win32_tell64_file_func OF((voidpf opaque, voidpf stream)); +long ZCALLBACK win32_seek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +int ZCALLBACK win32_close_file_func OF((voidpf opaque, voidpf stream)); +int ZCALLBACK win32_error_file_func OF((voidpf opaque, voidpf stream)); + +typedef struct +{ + HANDLE hf; + int error; +} WIN32FILE_IOWIN; + + +static void win32_translate_open_mode(int mode, + DWORD* lpdwDesiredAccess, + DWORD* lpdwCreationDisposition, + DWORD* lpdwShareMode, + DWORD* lpdwFlagsAndAttributes) +{ + *lpdwDesiredAccess = *lpdwShareMode = *lpdwFlagsAndAttributes = *lpdwCreationDisposition = 0; + + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + { + *lpdwDesiredAccess = GENERIC_READ; + *lpdwCreationDisposition = OPEN_EXISTING; + *lpdwShareMode = FILE_SHARE_READ; + } + else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + { + *lpdwDesiredAccess = GENERIC_WRITE | GENERIC_READ; + *lpdwCreationDisposition = OPEN_EXISTING; + } + else if (mode & ZLIB_FILEFUNC_MODE_CREATE) + { + *lpdwDesiredAccess = GENERIC_WRITE | GENERIC_READ; + *lpdwCreationDisposition = CREATE_ALWAYS; + } +} + +static voidpf win32_build_iowin(HANDLE hFile) +{ + voidpf ret=NULL; + + if ((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE)) + { + WIN32FILE_IOWIN w32fiow; + w32fiow.hf = hFile; + w32fiow.error = 0; + ret = malloc(sizeof(WIN32FILE_IOWIN)); + + if (ret==NULL) + CloseHandle(hFile); + else + *((WIN32FILE_IOWIN*)ret) = w32fiow; + } + return ret; +} + +voidpf ZCALLBACK win32_open64_file_func (voidpf opaque,const void* filename,int mode) +{ + const char* mode_fopen = NULL; + DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; + HANDLE hFile = NULL; + + win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); + +#ifdef IOWIN32_USING_WINRT_API +#ifdef UNICODE + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFile2((LPCTSTR)filename, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL); +#else + if ((filename!=NULL) && (dwDesiredAccess != 0)) + { + WCHAR filenameW[FILENAME_MAX + 0x200 + 1]; + MultiByteToWideChar(CP_ACP,0,(const char*)filename,-1,filenameW,FILENAME_MAX + 0x200); + hFile = CreateFile2(filenameW, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL); + } +#endif +#else + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); +#endif + + return win32_build_iowin(hFile); +} + + +voidpf ZCALLBACK win32_open64_file_funcA (voidpf opaque,const void* filename,int mode) +{ + const char* mode_fopen = NULL; + DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; + HANDLE hFile = NULL; + + win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); + +#ifdef IOWIN32_USING_WINRT_API + if ((filename!=NULL) && (dwDesiredAccess != 0)) + { + WCHAR filenameW[FILENAME_MAX + 0x200 + 1]; + MultiByteToWideChar(CP_ACP,0,(const char*)filename,-1,filenameW,FILENAME_MAX + 0x200); + hFile = CreateFile2(filenameW, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL); + } +#else + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFileA((LPCSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); +#endif + + return win32_build_iowin(hFile); +} + + +voidpf ZCALLBACK win32_open64_file_funcW (voidpf opaque,const void* filename,int mode) +{ + const char* mode_fopen = NULL; + DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; + HANDLE hFile = NULL; + + win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); + +#ifdef IOWIN32_USING_WINRT_API + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFile2((LPCWSTR)filename, dwDesiredAccess, dwShareMode, dwCreationDisposition,NULL); +#else + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFileW((LPCWSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); +#endif + + return win32_build_iowin(hFile); +} + + +voidpf ZCALLBACK win32_open_file_func (voidpf opaque,const char* filename,int mode) +{ + const char* mode_fopen = NULL; + DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; + HANDLE hFile = NULL; + + win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); + +#ifdef IOWIN32_USING_WINRT_API +#ifdef UNICODE + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFile2((LPCTSTR)filename, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL); +#else + if ((filename!=NULL) && (dwDesiredAccess != 0)) + { + WCHAR filenameW[FILENAME_MAX + 0x200 + 1]; + MultiByteToWideChar(CP_ACP,0,(const char*)filename,-1,filenameW,FILENAME_MAX + 0x200); + hFile = CreateFile2(filenameW, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL); + } +#endif +#else + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); +#endif + + return win32_build_iowin(hFile); +} + + +uLong ZCALLBACK win32_read_file_func (voidpf opaque, voidpf stream, void* buf,uLong size) +{ + uLong ret=0; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + + if (hFile != NULL) + { + if (!ReadFile(hFile, buf, size, &ret, NULL)) + { + DWORD dwErr = GetLastError(); + if (dwErr == ERROR_HANDLE_EOF) + dwErr = 0; + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + } + } + + return ret; +} + + +uLong ZCALLBACK win32_write_file_func (voidpf opaque,voidpf stream,const void* buf,uLong size) +{ + uLong ret=0; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + + if (hFile != NULL) + { + if (!WriteFile(hFile, buf, size, &ret, NULL)) + { + DWORD dwErr = GetLastError(); + if (dwErr == ERROR_HANDLE_EOF) + dwErr = 0; + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + } + } + + return ret; +} + +static BOOL MySetFilePointerEx(HANDLE hFile, LARGE_INTEGER pos, LARGE_INTEGER *newPos, DWORD dwMoveMethod) +{ +#ifdef IOWIN32_USING_WINRT_API + return SetFilePointerEx(hFile, pos, newPos, dwMoveMethod); +#else + LONG lHigh = pos.HighPart; + DWORD dwNewPos = SetFilePointer(hFile, pos.LowPart, &lHigh, dwMoveMethod); + BOOL fOk = TRUE; + if (dwNewPos == 0xFFFFFFFF) + if (GetLastError() != NO_ERROR) + fOk = FALSE; + if ((newPos != NULL) && (fOk)) + { + newPos->LowPart = dwNewPos; + newPos->HighPart = lHigh; + } + return fOk; +#endif +} + +long ZCALLBACK win32_tell_file_func (voidpf opaque,voidpf stream) +{ + long ret=-1; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + if (hFile != NULL) + { + LARGE_INTEGER pos; + pos.QuadPart = 0; + + if (!MySetFilePointerEx(hFile, pos, &pos, FILE_CURRENT)) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = -1; + } + else + ret=(long)pos.LowPart; + } + return ret; +} + +ZPOS64_T ZCALLBACK win32_tell64_file_func (voidpf opaque, voidpf stream) +{ + ZPOS64_T ret= (ZPOS64_T)-1; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream)->hf; + + if (hFile) + { + LARGE_INTEGER pos; + pos.QuadPart = 0; + + if (!MySetFilePointerEx(hFile, pos, &pos, FILE_CURRENT)) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = (ZPOS64_T)-1; + } + else + ret=pos.QuadPart; + } + return ret; +} + + +long ZCALLBACK win32_seek_file_func (voidpf opaque,voidpf stream,uLong offset,int origin) +{ + DWORD dwMoveMethod=0xFFFFFFFF; + HANDLE hFile = NULL; + + long ret=-1; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + dwMoveMethod = FILE_CURRENT; + break; + case ZLIB_FILEFUNC_SEEK_END : + dwMoveMethod = FILE_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + dwMoveMethod = FILE_BEGIN; + break; + default: return -1; + } + + if (hFile != NULL) + { + LARGE_INTEGER pos; + pos.QuadPart = offset; + if (!MySetFilePointerEx(hFile, pos, NULL, dwMoveMethod)) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = -1; + } + else + ret=0; + } + return ret; +} + +long ZCALLBACK win32_seek64_file_func (voidpf opaque, voidpf stream,ZPOS64_T offset,int origin) +{ + DWORD dwMoveMethod=0xFFFFFFFF; + HANDLE hFile = NULL; + long ret=-1; + + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream)->hf; + + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + dwMoveMethod = FILE_CURRENT; + break; + case ZLIB_FILEFUNC_SEEK_END : + dwMoveMethod = FILE_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + dwMoveMethod = FILE_BEGIN; + break; + default: return -1; + } + + if (hFile) + { + LARGE_INTEGER pos; + pos.QuadPart = offset; + if (!MySetFilePointerEx(hFile, pos, NULL, dwMoveMethod)) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = -1; + } + else + ret=0; + } + return ret; +} + +int ZCALLBACK win32_close_file_func (voidpf opaque, voidpf stream) +{ + int ret=-1; + + if (stream!=NULL) + { + HANDLE hFile; + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + if (hFile != NULL) + { + CloseHandle(hFile); + ret=0; + } + free(stream); + } + return ret; +} + +int ZCALLBACK win32_error_file_func (voidpf opaque,voidpf stream) +{ + int ret=-1; + if (stream!=NULL) + { + ret = ((WIN32FILE_IOWIN*)stream) -> error; + } + return ret; +} + +void fill_win32_filefunc (zlib_filefunc_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen_file = win32_open_file_func; + pzlib_filefunc_def->zread_file = win32_read_file_func; + pzlib_filefunc_def->zwrite_file = win32_write_file_func; + pzlib_filefunc_def->ztell_file = win32_tell_file_func; + pzlib_filefunc_def->zseek_file = win32_seek_file_func; + pzlib_filefunc_def->zclose_file = win32_close_file_func; + pzlib_filefunc_def->zerror_file = win32_error_file_func; + pzlib_filefunc_def->opaque = NULL; +} + +void fill_win32_filefunc64(zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = win32_open64_file_func; + pzlib_filefunc_def->zread_file = win32_read_file_func; + pzlib_filefunc_def->zwrite_file = win32_write_file_func; + pzlib_filefunc_def->ztell64_file = win32_tell64_file_func; + pzlib_filefunc_def->zseek64_file = win32_seek64_file_func; + pzlib_filefunc_def->zclose_file = win32_close_file_func; + pzlib_filefunc_def->zerror_file = win32_error_file_func; + pzlib_filefunc_def->opaque = NULL; +} + + +void fill_win32_filefunc64A(zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = win32_open64_file_funcA; + pzlib_filefunc_def->zread_file = win32_read_file_func; + pzlib_filefunc_def->zwrite_file = win32_write_file_func; + pzlib_filefunc_def->ztell64_file = win32_tell64_file_func; + pzlib_filefunc_def->zseek64_file = win32_seek64_file_func; + pzlib_filefunc_def->zclose_file = win32_close_file_func; + pzlib_filefunc_def->zerror_file = win32_error_file_func; + pzlib_filefunc_def->opaque = NULL; +} + + +void fill_win32_filefunc64W(zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = win32_open64_file_funcW; + pzlib_filefunc_def->zread_file = win32_read_file_func; + pzlib_filefunc_def->zwrite_file = win32_write_file_func; + pzlib_filefunc_def->ztell64_file = win32_tell64_file_func; + pzlib_filefunc_def->zseek64_file = win32_seek64_file_func; + pzlib_filefunc_def->zclose_file = win32_close_file_func; + pzlib_filefunc_def->zerror_file = win32_error_file_func; + pzlib_filefunc_def->opaque = NULL; +} diff --git a/DSView/pv/minizip/iowin32.h b/DSView/pv/minizip/iowin32.h new file mode 100644 index 00000000..0ca0969a --- /dev/null +++ b/DSView/pv/minizip/iowin32.h @@ -0,0 +1,28 @@ +/* iowin32.h -- IO base function header for compress/uncompress .zip + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + +*/ + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +void fill_win32_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); +void fill_win32_filefunc64 OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_win32_filefunc64A OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_win32_filefunc64W OF((zlib_filefunc64_def* pzlib_filefunc_def)); + +#ifdef __cplusplus +} +#endif diff --git a/DSView/pv/minizip/miniunz.c b/DSView/pv/minizip/miniunz.c new file mode 100644 index 00000000..3d65401b --- /dev/null +++ b/DSView/pv/minizip/miniunz.c @@ -0,0 +1,660 @@ +/* + miniunz.c + Version 1.1, February 14h, 2010 + sample part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) +*/ + +#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__)) + #ifndef __USE_FILE_OFFSET64 + #define __USE_FILE_OFFSET64 + #endif + #ifndef __USE_LARGEFILE64 + #define __USE_LARGEFILE64 + #endif + #ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE + #endif + #ifndef _FILE_OFFSET_BIT + #define _FILE_OFFSET_BIT 64 + #endif +#endif + +#ifdef __APPLE__ +// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions +#define FOPEN_FUNC(filename, mode) fopen(filename, mode) +#define FTELLO_FUNC(stream) ftello(stream) +#define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin) +#else +#define FOPEN_FUNC(filename, mode) fopen64(filename, mode) +#define FTELLO_FUNC(stream) ftello64(stream) +#define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin) +#endif + + +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +# include +# include +#else +# include +# include +#endif + + +#include "unzip.h" + +#define CASESENSITIVITY (0) +#define WRITEBUFFERSIZE (8192) +#define MAXFILENAME (256) + +#ifdef _WIN32 +#define USEWIN32IOAPI +#include "iowin32.h" +#endif +/* + mini unzip, demo of unzip package + + usage : + Usage : miniunz [-exvlo] file.zip [file_to_extract] [-d extractdir] + + list the file in the zipfile, and print the content of FILE_ID.ZIP or README.TXT + if it exists +*/ + + +/* change_file_date : change the date/time of a file + filename : the filename of the file where date/time must be modified + dosdate : the new date at the MSDos format (4 bytes) + tmu_date : the SAME new date at the tm_unz format */ +void change_file_date(filename,dosdate,tmu_date) + const char *filename; + uLong dosdate; + tm_unz tmu_date; +{ +#ifdef _WIN32 + HANDLE hFile; + FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite; + + hFile = CreateFileA(filename,GENERIC_READ | GENERIC_WRITE, + 0,NULL,OPEN_EXISTING,0,NULL); + GetFileTime(hFile,&ftCreate,&ftLastAcc,&ftLastWrite); + DosDateTimeToFileTime((WORD)(dosdate>>16),(WORD)dosdate,&ftLocal); + LocalFileTimeToFileTime(&ftLocal,&ftm); + SetFileTime(hFile,&ftm,&ftLastAcc,&ftm); + CloseHandle(hFile); +#else +#ifdef unix || __APPLE__ + struct utimbuf ut; + struct tm newdate; + newdate.tm_sec = tmu_date.tm_sec; + newdate.tm_min=tmu_date.tm_min; + newdate.tm_hour=tmu_date.tm_hour; + newdate.tm_mday=tmu_date.tm_mday; + newdate.tm_mon=tmu_date.tm_mon; + if (tmu_date.tm_year > 1900) + newdate.tm_year=tmu_date.tm_year - 1900; + else + newdate.tm_year=tmu_date.tm_year ; + newdate.tm_isdst=-1; + + ut.actime=ut.modtime=mktime(&newdate); + utime(filename,&ut); +#endif +#endif +} + + +/* mymkdir and change_file_date are not 100 % portable + As I don't know well Unix, I wait feedback for the unix portion */ + +int mymkdir(dirname) + const char* dirname; +{ + int ret=0; +#ifdef _WIN32 + ret = _mkdir(dirname); +#elif unix + ret = mkdir (dirname,0775); +#elif __APPLE__ + ret = mkdir (dirname,0775); +#endif + return ret; +} + +int makedir (newdir) + char *newdir; +{ + char *buffer ; + char *p; + int len = (int)strlen(newdir); + + if (len <= 0) + return 0; + + buffer = (char*)malloc(len+1); + if (buffer==NULL) + { + printf("Error allocating memory\n"); + return UNZ_INTERNALERROR; + } + strcpy(buffer,newdir); + + if (buffer[len-1] == '/') { + buffer[len-1] = '\0'; + } + if (mymkdir(buffer) == 0) + { + free(buffer); + return 1; + } + + p = buffer+1; + while (1) + { + char hold; + + while(*p && *p != '\\' && *p != '/') + p++; + hold = *p; + *p = 0; + if ((mymkdir(buffer) == -1) && (errno == ENOENT)) + { + printf("couldn't create directory %s\n",buffer); + free(buffer); + return 0; + } + if (hold == 0) + break; + *p++ = hold; + } + free(buffer); + return 1; +} + +void do_banner() +{ + printf("MiniUnz 1.01b, demo of zLib + Unz package written by Gilles Vollant\n"); + printf("more info at http://www.winimage.com/zLibDll/unzip.html\n\n"); +} + +void do_help() +{ + printf("Usage : miniunz [-e] [-x] [-v] [-l] [-o] [-p password] file.zip [file_to_extr.] [-d extractdir]\n\n" \ + " -e Extract without pathname (junk paths)\n" \ + " -x Extract with pathname\n" \ + " -v list files\n" \ + " -l list files\n" \ + " -d directory to extract into\n" \ + " -o overwrite files without prompting\n" \ + " -p extract crypted file using password\n\n"); +} + +void Display64BitsSize(ZPOS64_T n, int size_char) +{ + /* to avoid compatibility problem , we do here the conversion */ + char number[21]; + int offset=19; + int pos_string = 19; + number[20]=0; + for (;;) { + number[offset]=(char)((n%10)+'0'); + if (number[offset] != '0') + pos_string=offset; + n/=10; + if (offset==0) + break; + offset--; + } + { + int size_display_string = 19-pos_string; + while (size_char > size_display_string) + { + size_char--; + printf(" "); + } + } + + printf("%s",&number[pos_string]); +} + +int do_list(uf) + unzFile uf; +{ + uLong i; + unz_global_info64 gi; + int err; + + err = unzGetGlobalInfo64(uf,&gi); + if (err!=UNZ_OK) + printf("error %d with zipfile in unzGetGlobalInfo \n",err); + printf(" Length Method Size Ratio Date Time CRC-32 Name\n"); + printf(" ------ ------ ---- ----- ---- ---- ------ ----\n"); + for (i=0;i0) + ratio = (uLong)((file_info.compressed_size*100)/file_info.uncompressed_size); + + /* display a '*' if the file is crypted */ + if ((file_info.flag & 1) != 0) + charCrypt='*'; + + if (file_info.compression_method==0) + string_method="Stored"; + else + if (file_info.compression_method==Z_DEFLATED) + { + uInt iLevel=(uInt)((file_info.flag & 0x6)/2); + if (iLevel==0) + string_method="Defl:N"; + else if (iLevel==1) + string_method="Defl:X"; + else if ((iLevel==2) || (iLevel==3)) + string_method="Defl:F"; /* 2:fast , 3 : extra fast*/ + } + else + if (file_info.compression_method==Z_BZIP2ED) + { + string_method="BZip2 "; + } + else + string_method="Unkn. "; + + Display64BitsSize(file_info.uncompressed_size,7); + printf(" %6s%c",string_method,charCrypt); + Display64BitsSize(file_info.compressed_size,7); + printf(" %3lu%% %2.2lu-%2.2lu-%2.2lu %2.2lu:%2.2lu %8.8lx %s\n", + ratio, + (uLong)file_info.tmu_date.tm_mon + 1, + (uLong)file_info.tmu_date.tm_mday, + (uLong)file_info.tmu_date.tm_year % 100, + (uLong)file_info.tmu_date.tm_hour,(uLong)file_info.tmu_date.tm_min, + (uLong)file_info.crc,filename_inzip); + if ((i+1)='a') && (rep<='z')) + rep -= 0x20; + } + while ((rep!='Y') && (rep!='N') && (rep!='A')); + } + + if (rep == 'N') + skip = 1; + + if (rep == 'A') + *popt_overwrite=1; + } + + if ((skip==0) && (err==UNZ_OK)) + { + fout=FOPEN_FUNC(write_filename,"wb"); + /* some zipfile don't contain directory alone before file */ + if ((fout==NULL) && ((*popt_extract_without_path)==0) && + (filename_withoutpath!=(char*)filename_inzip)) + { + char c=*(filename_withoutpath-1); + *(filename_withoutpath-1)='\0'; + makedir(write_filename); + *(filename_withoutpath-1)=c; + fout=FOPEN_FUNC(write_filename,"wb"); + } + + if (fout==NULL) + { + printf("error opening %s\n",write_filename); + } + } + + if (fout!=NULL) + { + printf(" extracting: %s\n",write_filename); + + do + { + err = unzReadCurrentFile(uf,buf,size_buf); + if (err<0) + { + printf("error %d with zipfile in unzReadCurrentFile\n",err); + break; + } + if (err>0) + if (fwrite(buf,err,1,fout)!=1) + { + printf("error in writing extracted file\n"); + err=UNZ_ERRNO; + break; + } + } + while (err>0); + if (fout) + fclose(fout); + + if (err==0) + change_file_date(write_filename,file_info.dosDate, + file_info.tmu_date); + } + + if (err==UNZ_OK) + { + err = unzCloseCurrentFile (uf); + if (err!=UNZ_OK) + { + printf("error %d with zipfile in unzCloseCurrentFile\n",err); + } + } + else + unzCloseCurrentFile(uf); /* don't lose the error */ + } + + free(buf); + return err; +} + + +int do_extract(uf,opt_extract_without_path,opt_overwrite,password) + unzFile uf; + int opt_extract_without_path; + int opt_overwrite; + const char* password; +{ + uLong i; + unz_global_info64 gi; + int err; + FILE* fout=NULL; + + err = unzGetGlobalInfo64(uf,&gi); + if (err!=UNZ_OK) + printf("error %d with zipfile in unzGetGlobalInfo \n",err); + + for (i=0;i +#include +#include +#include +#include +#include + +#ifdef _WIN32 +# include +# include +#else +# include +# include +# include +# include +#endif + +#include "zip.h" + +#ifdef _WIN32 + #define USEWIN32IOAPI + #include "iowin32.h" +#endif + + + +#define WRITEBUFFERSIZE (16384) +#define MAXFILENAME (256) + +#ifdef _WIN32 +uLong filetime(f, tmzip, dt) + char *f; /* name of file to get info on */ + tm_zip *tmzip; /* return value: access, modific. and creation times */ + uLong *dt; /* dostime */ +{ + int ret = 0; + { + FILETIME ftLocal; + HANDLE hFind; + WIN32_FIND_DATAA ff32; + + hFind = FindFirstFileA(f,&ff32); + if (hFind != INVALID_HANDLE_VALUE) + { + FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal); + FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0); + FindClose(hFind); + ret = 1; + } + } + return ret; +} +#else +#ifdef unix || __APPLE__ +uLong filetime(f, tmzip, dt) + char *f; /* name of file to get info on */ + tm_zip *tmzip; /* return value: access, modific. and creation times */ + uLong *dt; /* dostime */ +{ + int ret=0; + struct stat s; /* results of stat() */ + struct tm* filedate; + time_t tm_t=0; + + if (strcmp(f,"-")!=0) + { + char name[MAXFILENAME+1]; + int len = strlen(f); + if (len > MAXFILENAME) + len = MAXFILENAME; + + strncpy(name, f,MAXFILENAME-1); + /* strncpy doesnt append the trailing NULL, of the string is too long. */ + name[ MAXFILENAME ] = '\0'; + + if (name[len - 1] == '/') + name[len - 1] = '\0'; + /* not all systems allow stat'ing a file with / appended */ + if (stat(name,&s)==0) + { + tm_t = s.st_mtime; + ret = 1; + } + } + filedate = localtime(&tm_t); + + tmzip->tm_sec = filedate->tm_sec; + tmzip->tm_min = filedate->tm_min; + tmzip->tm_hour = filedate->tm_hour; + tmzip->tm_mday = filedate->tm_mday; + tmzip->tm_mon = filedate->tm_mon ; + tmzip->tm_year = filedate->tm_year; + + return ret; +} +#else +uLong filetime(f, tmzip, dt) + char *f; /* name of file to get info on */ + tm_zip *tmzip; /* return value: access, modific. and creation times */ + uLong *dt; /* dostime */ +{ + return 0; +} +#endif +#endif + + + + +int check_exist_file(filename) + const char* filename; +{ + FILE* ftestexist; + int ret = 1; + ftestexist = FOPEN_FUNC(filename,"rb"); + if (ftestexist==NULL) + ret = 0; + else + fclose(ftestexist); + return ret; +} + +void do_banner() +{ + printf("MiniZip 1.1, demo of zLib + MiniZip64 package, written by Gilles Vollant\n"); + printf("more info on MiniZip at http://www.winimage.com/zLibDll/minizip.html\n\n"); +} + +void do_help() +{ + printf("Usage : minizip [-o] [-a] [-0 to -9] [-p password] [-j] file.zip [files_to_add]\n\n" \ + " -o Overwrite existing file.zip\n" \ + " -a Append to existing file.zip\n" \ + " -0 Store only\n" \ + " -1 Compress faster\n" \ + " -9 Compress better\n\n" \ + " -j exclude path. store only the file name.\n\n"); +} + +/* calculate the CRC32 of a file, + because to encrypt a file, we need known the CRC32 of the file before */ +int getFileCrc(const char* filenameinzip,void*buf,unsigned long size_buf,unsigned long* result_crc) +{ + unsigned long calculate_crc=0; + int err=ZIP_OK; + FILE * fin = FOPEN_FUNC(filenameinzip,"rb"); + + unsigned long size_read = 0; + unsigned long total_read = 0; + if (fin==NULL) + { + err = ZIP_ERRNO; + } + + if (err == ZIP_OK) + do + { + err = ZIP_OK; + size_read = (int)fread(buf,1,size_buf,fin); + if (size_read < size_buf) + if (feof(fin)==0) + { + printf("error in reading %s\n",filenameinzip); + err = ZIP_ERRNO; + } + + if (size_read>0) + calculate_crc = crc32(calculate_crc,buf,size_read); + total_read += size_read; + + } while ((err == ZIP_OK) && (size_read>0)); + + if (fin) + fclose(fin); + + *result_crc=calculate_crc; + printf("file %s crc %lx\n", filenameinzip, calculate_crc); + return err; +} + +int isLargeFile(const char* filename) +{ + int largeFile = 0; + ZPOS64_T pos = 0; + FILE* pFile = FOPEN_FUNC(filename, "rb"); + + if(pFile != NULL) + { + int n = FSEEKO_FUNC(pFile, 0, SEEK_END); + pos = FTELLO_FUNC(pFile); + + printf("File : %s is %lld bytes\n", filename, pos); + + if(pos >= 0xffffffff) + largeFile = 1; + + fclose(pFile); + } + + return largeFile; +} + +int main(argc,argv) + int argc; + char *argv[]; +{ + int i; + int opt_overwrite=0; + int opt_compress_level=Z_DEFAULT_COMPRESSION; + int opt_exclude_path=0; + int zipfilenamearg = 0; + char filename_try[MAXFILENAME+16]; + int zipok; + int err=0; + int size_buf=0; + void* buf=NULL; + const char* password=NULL; + + + do_banner(); + if (argc==1) + { + do_help(); + return 0; + } + else + { + for (i=1;i='0') && (c<='9')) + opt_compress_level = c-'0'; + if ((c=='j') || (c=='J')) + opt_exclude_path = 1; + + if (((c=='p') || (c=='P')) && (i+1='a') && (rep<='z')) + rep -= 0x20; + } + while ((rep!='Y') && (rep!='N') && (rep!='A')); + if (rep=='N') + zipok = 0; + if (rep=='A') + opt_overwrite = 2; + } + } + + if (zipok==1) + { + zipFile zf; + int errclose; +# ifdef USEWIN32IOAPI + zlib_filefunc64_def ffunc; + fill_win32_filefunc64A(&ffunc); + zf = zipOpen2_64(filename_try,(opt_overwrite==2) ? 2 : 0,NULL,&ffunc); +# else + zf = zipOpen64(filename_try,(opt_overwrite==2) ? 2 : 0); +# endif + + if (zf == NULL) + { + printf("error opening %s\n",filename_try); + err= ZIP_ERRNO; + } + else + printf("creating %s\n",filename_try); + + for (i=zipfilenamearg+1;(i='0') || (argv[i][1]<='9'))) && + (strlen(argv[i]) == 2))) + { + FILE * fin; + int size_read; + const char* filenameinzip = argv[i]; + const char *savefilenameinzip; + zip_fileinfo zi; + unsigned long crcFile=0; + int zip64 = 0; + + zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour = + zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0; + zi.dosDate = 0; + zi.internal_fa = 0; + zi.external_fa = 0; + filetime(filenameinzip,&zi.tmz_date,&zi.dosDate); + +/* + err = zipOpenNewFileInZip(zf,filenameinzip,&zi, + NULL,0,NULL,0,NULL / * comment * /, + (opt_compress_level != 0) ? Z_DEFLATED : 0, + opt_compress_level); +*/ + if ((password != NULL) && (err==ZIP_OK)) + err = getFileCrc(filenameinzip,buf,size_buf,&crcFile); + + zip64 = isLargeFile(filenameinzip); + + /* The path name saved, should not include a leading slash. */ + /*if it did, windows/xp and dynazip couldn't read the zip file. */ + savefilenameinzip = filenameinzip; + while( savefilenameinzip[0] == '\\' || savefilenameinzip[0] == '/' ) + { + savefilenameinzip++; + } + + /*should the zip file contain any path at all?*/ + if( opt_exclude_path ) + { + const char *tmpptr; + const char *lastslash = 0; + for( tmpptr = savefilenameinzip; *tmpptr; tmpptr++) + { + if( *tmpptr == '\\' || *tmpptr == '/') + { + lastslash = tmpptr; + } + } + if( lastslash != NULL ) + { + savefilenameinzip = lastslash+1; // base filename follows last slash. + } + } + + /**/ + err = zipOpenNewFileInZip3_64(zf,savefilenameinzip,&zi, + NULL,0,NULL,0,NULL /* comment*/, + (opt_compress_level != 0) ? Z_DEFLATED : 0, + opt_compress_level,0, + /* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */ + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + password,crcFile, zip64); + + if (err != ZIP_OK) + printf("error in opening %s in zipfile\n",filenameinzip); + else + { + fin = FOPEN_FUNC(filenameinzip,"rb"); + if (fin==NULL) + { + err=ZIP_ERRNO; + printf("error in opening %s for reading\n",filenameinzip); + } + } + + if (err == ZIP_OK) + do + { + err = ZIP_OK; + size_read = (int)fread(buf,1,size_buf,fin); + if (size_read < size_buf) + if (feof(fin)==0) + { + printf("error in reading %s\n",filenameinzip); + err = ZIP_ERRNO; + } + + if (size_read>0) + { + err = zipWriteInFileInZip (zf,buf,size_read); + if (err<0) + { + printf("error in writing %s in the zipfile\n", + filenameinzip); + } + + } + } while ((err == ZIP_OK) && (size_read>0)); + + if (fin) + fclose(fin); + + if (err<0) + err=ZIP_ERRNO; + else + { + err = zipCloseFileInZip(zf); + if (err!=ZIP_OK) + printf("error in closing %s in the zipfile\n", + filenameinzip); + } + } + } + errclose = zipClose(zf,NULL); + if (errclose != ZIP_OK) + printf("error in closing %s\n",filename_try); + } + else + { + do_help(); + } + + free(buf); + return 0; +} diff --git a/DSView/pv/minizip/mztools.c b/DSView/pv/minizip/mztools.c new file mode 100644 index 00000000..96891c2e --- /dev/null +++ b/DSView/pv/minizip/mztools.c @@ -0,0 +1,291 @@ +/* + Additional tools for Minizip + Code: Xavier Roche '2004 + License: Same as ZLIB (www.gzip.org) +*/ + +/* Code */ +#include +#include +#include +#include "zlib.h" +#include "unzip.h" + +#define READ_8(adr) ((unsigned char)*(adr)) +#define READ_16(adr) ( READ_8(adr) | (READ_8(adr+1) << 8) ) +#define READ_32(adr) ( READ_16(adr) | (READ_16((adr)+2) << 16) ) + +#define WRITE_8(buff, n) do { \ + *((unsigned char*)(buff)) = (unsigned char) ((n) & 0xff); \ +} while(0) +#define WRITE_16(buff, n) do { \ + WRITE_8((unsigned char*)(buff), n); \ + WRITE_8(((unsigned char*)(buff)) + 1, (n) >> 8); \ +} while(0) +#define WRITE_32(buff, n) do { \ + WRITE_16((unsigned char*)(buff), (n) & 0xffff); \ + WRITE_16((unsigned char*)(buff) + 2, (n) >> 16); \ +} while(0) + +extern int ZEXPORT unzRepair(file, fileOut, fileOutTmp, nRecovered, bytesRecovered) +const char* file; +const char* fileOut; +const char* fileOutTmp; +uLong* nRecovered; +uLong* bytesRecovered; +{ + int err = Z_OK; + FILE* fpZip = fopen(file, "rb"); + FILE* fpOut = fopen(fileOut, "wb"); + FILE* fpOutCD = fopen(fileOutTmp, "wb"); + if (fpZip != NULL && fpOut != NULL) { + int entries = 0; + uLong totalBytes = 0; + char header[30]; + char filename[1024]; + char extra[1024]; + int offset = 0; + int offsetCD = 0; + while ( fread(header, 1, 30, fpZip) == 30 ) { + int currentOffset = offset; + + /* File entry */ + if (READ_32(header) == 0x04034b50) { + unsigned int version = READ_16(header + 4); + unsigned int gpflag = READ_16(header + 6); + unsigned int method = READ_16(header + 8); + unsigned int filetime = READ_16(header + 10); + unsigned int filedate = READ_16(header + 12); + unsigned int crc = READ_32(header + 14); /* crc */ + unsigned int cpsize = READ_32(header + 18); /* compressed size */ + unsigned int uncpsize = READ_32(header + 22); /* uncompressed sz */ + unsigned int fnsize = READ_16(header + 26); /* file name length */ + unsigned int extsize = READ_16(header + 28); /* extra field length */ + filename[0] = extra[0] = '\0'; + + /* Header */ + if (fwrite(header, 1, 30, fpOut) == 30) { + offset += 30; + } else { + err = Z_ERRNO; + break; + } + + /* Filename */ + if (fnsize > 0) { + if (fnsize < sizeof(filename)) { + if (fread(filename, 1, fnsize, fpZip) == fnsize) { + if (fwrite(filename, 1, fnsize, fpOut) == fnsize) { + offset += fnsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_STREAM_ERROR; + break; + } + + /* Extra field */ + if (extsize > 0) { + if (extsize < sizeof(extra)) { + if (fread(extra, 1, extsize, fpZip) == extsize) { + if (fwrite(extra, 1, extsize, fpOut) == extsize) { + offset += extsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_ERRNO; + break; + } + } + + /* Data */ + { + int dataSize = cpsize; + if (dataSize == 0) { + dataSize = uncpsize; + } + if (dataSize > 0) { + char* data = malloc(dataSize); + if (data != NULL) { + if ((int)fread(data, 1, dataSize, fpZip) == dataSize) { + if ((int)fwrite(data, 1, dataSize, fpOut) == dataSize) { + offset += dataSize; + totalBytes += dataSize; + } else { + err = Z_ERRNO; + } + } else { + err = Z_ERRNO; + } + free(data); + if (err != Z_OK) { + break; + } + } else { + err = Z_MEM_ERROR; + break; + } + } + } + + /* Central directory entry */ + { + char header[46]; + char* comment = ""; + int comsize = (int) strlen(comment); + WRITE_32(header, 0x02014b50); + WRITE_16(header + 4, version); + WRITE_16(header + 6, version); + WRITE_16(header + 8, gpflag); + WRITE_16(header + 10, method); + WRITE_16(header + 12, filetime); + WRITE_16(header + 14, filedate); + WRITE_32(header + 16, crc); + WRITE_32(header + 20, cpsize); + WRITE_32(header + 24, uncpsize); + WRITE_16(header + 28, fnsize); + WRITE_16(header + 30, extsize); + WRITE_16(header + 32, comsize); + WRITE_16(header + 34, 0); /* disk # */ + WRITE_16(header + 36, 0); /* int attrb */ + WRITE_32(header + 38, 0); /* ext attrb */ + WRITE_32(header + 42, currentOffset); + /* Header */ + if (fwrite(header, 1, 46, fpOutCD) == 46) { + offsetCD += 46; + + /* Filename */ + if (fnsize > 0) { + if (fwrite(filename, 1, fnsize, fpOutCD) == fnsize) { + offsetCD += fnsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_STREAM_ERROR; + break; + } + + /* Extra field */ + if (extsize > 0) { + if (fwrite(extra, 1, extsize, fpOutCD) == extsize) { + offsetCD += extsize; + } else { + err = Z_ERRNO; + break; + } + } + + /* Comment field */ + if (comsize > 0) { + if ((int)fwrite(comment, 1, comsize, fpOutCD) == comsize) { + offsetCD += comsize; + } else { + err = Z_ERRNO; + break; + } + } + + + } else { + err = Z_ERRNO; + break; + } + } + + /* Success */ + entries++; + + } else { + break; + } + } + + /* Final central directory */ + { + int entriesZip = entries; + char header[22]; + char* comment = ""; // "ZIP File recovered by zlib/minizip/mztools"; + int comsize = (int) strlen(comment); + if (entriesZip > 0xffff) { + entriesZip = 0xffff; + } + WRITE_32(header, 0x06054b50); + WRITE_16(header + 4, 0); /* disk # */ + WRITE_16(header + 6, 0); /* disk # */ + WRITE_16(header + 8, entriesZip); /* hack */ + WRITE_16(header + 10, entriesZip); /* hack */ + WRITE_32(header + 12, offsetCD); /* size of CD */ + WRITE_32(header + 16, offset); /* offset to CD */ + WRITE_16(header + 20, comsize); /* comment */ + + /* Header */ + if (fwrite(header, 1, 22, fpOutCD) == 22) { + + /* Comment field */ + if (comsize > 0) { + if ((int)fwrite(comment, 1, comsize, fpOutCD) != comsize) { + err = Z_ERRNO; + } + } + + } else { + err = Z_ERRNO; + } + } + + /* Final merge (file + central directory) */ + fclose(fpOutCD); + if (err == Z_OK) { + fpOutCD = fopen(fileOutTmp, "rb"); + if (fpOutCD != NULL) { + int nRead; + char buffer[8192]; + while ( (nRead = (int)fread(buffer, 1, sizeof(buffer), fpOutCD)) > 0) { + if ((int)fwrite(buffer, 1, nRead, fpOut) != nRead) { + err = Z_ERRNO; + break; + } + } + fclose(fpOutCD); + } + } + + /* Close */ + fclose(fpZip); + fclose(fpOut); + + /* Wipe temporary file */ + (void)remove(fileOutTmp); + + /* Number of recovered entries */ + if (err == Z_OK) { + if (nRecovered != NULL) { + *nRecovered = entries; + } + if (bytesRecovered != NULL) { + *bytesRecovered = totalBytes; + } + } + } else { + err = Z_STREAM_ERROR; + } + return err; +} diff --git a/DSView/pv/minizip/mztools.h b/DSView/pv/minizip/mztools.h new file mode 100644 index 00000000..a49a426e --- /dev/null +++ b/DSView/pv/minizip/mztools.h @@ -0,0 +1,37 @@ +/* + Additional tools for Minizip + Code: Xavier Roche '2004 + License: Same as ZLIB (www.gzip.org) +*/ + +#ifndef _zip_tools_H +#define _zip_tools_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#include "unzip.h" + +/* Repair a ZIP file (missing central directory) + file: file to recover + fileOut: output file after recovery + fileOutTmp: temporary file name used for recovery +*/ +extern int ZEXPORT unzRepair(const char* file, + const char* fileOut, + const char* fileOutTmp, + uLong* nRecovered, + uLong* bytesRecovered); + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/DSView/pv/minizip/unzip.c b/DSView/pv/minizip/unzip.c new file mode 100644 index 00000000..bcfb9416 --- /dev/null +++ b/DSView/pv/minizip/unzip.c @@ -0,0 +1,2125 @@ +/* unzip.c -- IO for uncompress .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + + ------------------------------------------------------------------------------------ + Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of + compatibility with older software. The following is from the original crypt.c. + Code woven in by Terry Thorsen 1/2003. + + Copyright (c) 1990-2000 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 or later + (the contents of which are also included in zip.h) for terms of use. + If, for some reason, all these files are missing, the Info-ZIP license + also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html + + crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + ------------------------------------------------------------------------------------ + + Changes in unzip.c + + 2007-2008 - Even Rouault - Addition of cpl_unzGetCurrentFileZStreamPos + 2007-2008 - Even Rouault - Decoration of symbol names unz* -> cpl_unz* + 2007-2008 - Even Rouault - Remove old C style function prototypes + 2007-2008 - Even Rouault - Add unzip support for ZIP64 + + Copyright (C) 2007-2008 Even Rouault + + + Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again). + Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G + should only read the compressed/uncompressed size from the Zip64 format if + the size from normal header was 0xFFFFFFFF + Oct-2009 - Mathias Svensson - Applied some bug fixes from paches recived from Gilles Vollant + Oct-2009 - Mathias Svensson - Applied support to unzip files with compression mathod BZIP2 (bzip2 lib is required) + Patch created by Daniel Borca + + Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer + + Copyright (C) 1998 - 2010 Gilles Vollant, Even Rouault, Mathias Svensson + +*/ + + +#include +#include +#include + +#ifndef NOUNCRYPT + #define NOUNCRYPT +#endif + +#include "zlib.h" +#include "unzip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + + +#ifndef CASESENSITIVITYDEFAULT_NO +# if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) +# define CASESENSITIVITYDEFAULT_NO +# endif +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (16384) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + + +const char unz_copyright[] = + " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info64_internal_s +{ + ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */ +} unz_file_info64_internal; + + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + +#ifdef HAVE_BZIP2 + bz_stream bstream; /* bzLib stream structure for bziped */ +#endif + + ZPOS64_T pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ + uLong stream_initialised; /* flag set if stream structure is initialised*/ + + ZPOS64_T offset_local_extrafield;/* offset of the local extra field */ + uInt size_local_extrafield;/* size of the local extra field */ + ZPOS64_T pos_local_extrafield; /* position in the local extra field in read*/ + ZPOS64_T total_out_64; + + uLong crc32; /* crc32 of all data uncompressed */ + uLong crc32_wait; /* crc32 we must obtain after decompress all */ + ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */ + ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/ + zlib_filefunc64_32_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + uLong compression_method; /* compression method (0==store) */ + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + int raw; +} file_in_zip64_read_info_s; + + +/* unz64_s contain internal information about the zipfile +*/ +typedef struct +{ + zlib_filefunc64_32_def z_filefunc; + int is64bitOpenFunction; + voidpf filestream; /* io structore of the zipfile */ + unz_global_info64 gi; /* public global information */ + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + ZPOS64_T num_file; /* number of the current file in the zipfile*/ + ZPOS64_T pos_in_central_dir; /* pos of the current file in the central dir*/ + ZPOS64_T current_file_ok; /* flag about the usability of the current file*/ + ZPOS64_T central_pos; /* position of the beginning of the central dir*/ + + ZPOS64_T size_central_dir; /* size of the central directory */ + ZPOS64_T offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info64 cur_file_info; /* public info about the current file in zip*/ + unz_file_info64_internal cur_file_info_internal; /* private info about it*/ + file_in_zip64_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ + int encrypted; + + int isZip64; + +# ifndef NOUNCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const z_crc_t* pcrc_32_tab; +# endif +} unz64_s; + + +#ifndef NOUNCRYPT +#include "crypt.h" +#endif + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been successfully opened for reading. +*/ + + +local int unz64local_getByte OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + int *pi)); + +local int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi) +{ + unsigned char c; + int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ZERROR64(*pzlib_filefunc_def,filestream)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int unz64local_getShort OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unz64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) +{ + uLong x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unz64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) +{ + uLong x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong64 OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + ZPOS64_T *pX)); + + +local int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + ZPOS64_T *pX) +{ + ZPOS64_T x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (ZPOS64_T)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<8; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<16; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<24; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<32; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<40; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<48; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<56; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +/* My own strcmpi / strcasecmp */ +local int strcmpcasenosensitive_internal (const char* fileName1, const char* fileName2) +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + +*/ +extern int ZEXPORT unzStringFileNameCompare (const char* fileName1, + const char* fileName2, + int iCaseSensitivity) + +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif + +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); +local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + + +/* + Locate the Central directory 64 of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T unz64local_SearchCentralDir64 OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream)); + +local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + uLong uL; + ZPOS64_T relativeOffset; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + if (uPosFound == 0) + return 0; + + /* Zip64 end of central directory locator */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature, already checked */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + + /* number of the disk with the start of the zip64 end of central directory */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + if (uL != 0) + return 0; + + /* relative offset of the zip64 end of central directory record */ + if (unz64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK) + return 0; + + /* total number of disks */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + if (uL != 1) + return 0; + + /* Goto end of central directory record */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + + if (uL != 0x06064b50) + return 0; + + return relativeOffset; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer + "zlib/zlib114.zip". + If the zipfile cannot be opened (file doesn't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +local unzFile unzOpenInternal (const void *path, + zlib_filefunc64_32_def* pzlib_filefunc64_32_def, + int is64bitOpenFunction) +{ + unz64_s us; + unz64_s *s; + ZPOS64_T central_pos; + uLong uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + ZPOS64_T number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + if (unz_copyright[0]!=' ') + return NULL; + + us.z_filefunc.zseek32_file = NULL; + us.z_filefunc.ztell32_file = NULL; + if (pzlib_filefunc64_32_def==NULL) + fill_fopen64_filefunc(&us.z_filefunc.zfile_func64); + else + us.z_filefunc = *pzlib_filefunc64_32_def; + us.is64bitOpenFunction = is64bitOpenFunction; + + + + us.filestream = ZOPEN64(us.z_filefunc, + path, + ZLIB_FILEFUNC_MODE_READ | + ZLIB_FILEFUNC_MODE_EXISTING); + if (us.filestream==NULL) + return NULL; + + central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream); + if (central_pos) + { + uLong uS; + ZPOS64_T uL64; + + us.isZip64 = 1; + + if (ZSEEK64(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* size of zip64 end of central directory record */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&uL64)!=UNZ_OK) + err=UNZ_ERRNO; + + /* version made by */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) + err=UNZ_ERRNO; + + /* version needed to extract */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central directory on this disk */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central directory */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + us.gi.size_comment = 0; + } + else + { + central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream); + if (central_pos==0) + err=UNZ_ERRNO; + + us.isZip64 = 0; + + if (ZSEEK64(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.gi.number_entry = uL; + + /* total number of entries in the central dir */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + number_entry_CD = uL; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.size_central_dir = uL; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.offset_central_dir = uL; + + /* zipfile comment length */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + } + + if ((central_pospfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + ZCLOSE64(s->z_filefunc, s->filestream); + TRYFREE(s); + return UNZ_OK; +} + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +extern int ZEXPORT unzGetGlobalInfo64 (unzFile file, unz_global_info64* pglobal_info) +{ + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + +extern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info* pglobal_info32) +{ + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + /* to do : check if number_entry is not truncated */ + pglobal_info32->number_entry = (uLong)s->gi.number_entry; + pglobal_info32->size_comment = s->gi.size_comment; + return UNZ_OK; +} +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +local void unz64local_DosDateToTmuDate (ZPOS64_T ulDosDate, tm_unz* ptm) +{ + ZPOS64_T uDate; + uDate = (ZPOS64_T)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* + Get Info about the current file in the zipfile, with internal only info +*/ +local int unz64local_GetCurrentFileInfoInternal OF((unzFile file, + unz_file_info64 *pfile_info, + unz_file_info64_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +local int unz64local_GetCurrentFileInfoInternal (unzFile file, + unz_file_info64 *pfile_info, + unz_file_info64_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize) +{ + unz64_s* s; + unz_file_info64 file_info; + unz_file_info64_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + uLong uL; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (ZSEEK64(s->z_filefunc, s->filestream, + s->pos_in_central_dir+s->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK) + { + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + } + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unz64local_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info.compressed_size = uL; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info.uncompressed_size = uL; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + // relative offset of local header + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info_internal.offset_curfile = uL; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + // Read extrafield + if ((err==UNZ_OK) && (extraField!=NULL)) + { + ZPOS64_T uSizeRead ; + if (file_info.size_file_extraz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,extraField,(uLong)uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + + lSeek += file_info.size_file_extra - (uLong)uSizeRead; + } + else + lSeek += file_info.size_file_extra; + + + if ((err==UNZ_OK) && (file_info.size_file_extra != 0)) + { + uLong acc = 0; + + // since lSeek now points to after the extra field we need to move back + lSeek -= file_info.size_file_extra; + + if (lSeek!=0) + { + if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + while(acc < file_info.size_file_extra) + { + uLong headerId; + uLong dataSize; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&headerId) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK) + err=UNZ_ERRNO; + + /* ZIP64 extra fields */ + if (headerId == 0x0001) + { + uLong uL; + + if(file_info.uncompressed_size == MAXU32) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info.compressed_size == MAXU32) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info_internal.offset_curfile == MAXU32) + { + /* Relative Header offset */ + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info.disk_num_start == MAXU32) + { + /* Disk Start Number */ + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + } + + } + else + { + if (ZSEEK64(s->z_filefunc, s->filestream,dataSize,ZLIB_FILEFUNC_SEEK_CUR)!=0) + err=UNZ_ERRNO; + } + + acc += 2 + 2 + dataSize; + } + } + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek+=file_info.size_file_comment - uSizeRead; + } + else + lSeek+=file_info.size_file_comment; + + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. +*/ +extern int ZEXPORT unzGetCurrentFileInfo64 (unzFile file, + unz_file_info64 * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) +{ + return unz64local_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +extern int ZEXPORT unzGetCurrentFileInfo (unzFile file, + unz_file_info * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) +{ + int err; + unz_file_info64 file_info64; + err = unz64local_GetCurrentFileInfoInternal(file,&file_info64,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); + if ((err==UNZ_OK) && (pfile_info != NULL)) + { + pfile_info->version = file_info64.version; + pfile_info->version_needed = file_info64.version_needed; + pfile_info->flag = file_info64.flag; + pfile_info->compression_method = file_info64.compression_method; + pfile_info->dosDate = file_info64.dosDate; + pfile_info->crc = file_info64.crc; + + pfile_info->size_filename = file_info64.size_filename; + pfile_info->size_file_extra = file_info64.size_file_extra; + pfile_info->size_file_comment = file_info64.size_file_comment; + + pfile_info->disk_num_start = file_info64.disk_num_start; + pfile_info->internal_fa = file_info64.internal_fa; + pfile_info->external_fa = file_info64.external_fa; + + pfile_info->tmu_date = file_info64.tmu_date, + + + pfile_info->compressed_size = (uLong)file_info64.compressed_size; + pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size; + + } + return err; +} +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +extern int ZEXPORT unzGoToFirstFile (unzFile file) +{ + int err=UNZ_OK; + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +extern int ZEXPORT unzGoToNextFile (unzFile file) +{ + unz64_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +extern int ZEXPORT unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) +{ + unz64_s* s; + int err; + + /* We remember the 'current' position in the file so that we can jump + * back there if we fail. + */ + unz_file_info64 cur_file_infoSaved; + unz_file_info64_internal cur_file_info_internalSaved; + ZPOS64_T num_fileSaved; + ZPOS64_T pos_in_central_dirSaved; + + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + /* Save the current state */ + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + cur_file_infoSaved = s->cur_file_info; + cur_file_info_internalSaved = s->cur_file_info_internal; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + err = unzGetCurrentFileInfo64(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (err == UNZ_OK) + { + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + } + + /* We failed, so restore the state of the 'current file' to where we + * were. + */ + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + s->cur_file_info = cur_file_infoSaved; + s->cur_file_info_internal = cur_file_info_internalSaved; + return err; +} + + +/* +/////////////////////////////////////////// +// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net) +// I need random access +// +// Further optimization could be realized by adding an ability +// to cache the directory in memory. The goal being a single +// comprehensive file read to put the file I need in a memory. +*/ + +/* +typedef struct unz_file_pos_s +{ + ZPOS64_T pos_in_zip_directory; // offset in file + ZPOS64_T num_of_file; // # of file +} unz_file_pos; +*/ + +extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) +{ + unz64_s* s; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + file_pos->pos_in_zip_directory = s->pos_in_central_dir; + file_pos->num_of_file = s->num_file; + + return UNZ_OK; +} + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + int err = unzGetFilePos64(file,&file_pos64); + if (err==UNZ_OK) + { + file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory; + file_pos->num_of_file = (uLong)file_pos64.num_of_file; + } + return err; +} + +extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos) +{ + unz64_s* s; + int err; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + + /* jump to the right spot */ + s->pos_in_central_dir = file_pos->pos_in_zip_directory; + s->num_file = file_pos->num_of_file; + + /* set the current file */ + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + /* return results */ + s->current_file_ok = (err == UNZ_OK); + return err; +} + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + if (file_pos == NULL) + return UNZ_PARAMERROR; + + file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory; + file_pos64.num_of_file = file_pos->num_of_file; + return unzGoToFilePos64(file,&file_pos64); +} + +/* +// Unzip Helper Functions - should be here? +/////////////////////////////////////////// +*/ + +/* + Read the local header of the current zipfile + Check the coherency of the local header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in local header + (filename and size of extra field data) +*/ +local int unz64local_CheckCurrentFileCoherencyHeader (unz64_s* s, uInt* piSizeVar, + ZPOS64_T * poffset_local_extrafield, + uInt * psize_local_extrafield) +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (ZSEEK64(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) + { + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + } + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && +/* #ifdef HAVE_BZIP2 */ + (s->cur_file_info.compression_method!=Z_BZIP2ED) && +/* #endif */ + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int ZEXPORT unzOpenCurrentFile3 (unzFile file, int* method, + int* level, int raw, const char* password) +{ + int err=UNZ_OK; + uInt iSizeVar; + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + ZPOS64_T offset_local_extrafield; /* offset of the local extra field */ + uInt size_local_extrafield; /* size of the local extra field */ +# ifndef NOUNCRYPT + char source[12]; +# else + if (password != NULL) + return UNZ_PARAMERROR; +# endif + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unz64local_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + pfile_in_zip_read_info->raw=raw; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + TRYFREE(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if (method!=NULL) + *method = (int)s->cur_file_info.compression_method; + + if (level!=NULL) + { + *level = 6; + switch (s->cur_file_info.flag & 0x06) + { + case 6 : *level = 1; break; + case 4 : *level = 2; break; + case 2 : *level = 9; break; + } + } + + if ((s->cur_file_info.compression_method!=0) && +/* #ifdef HAVE_BZIP2 */ + (s->cur_file_info.compression_method!=Z_BZIP2ED) && +/* #endif */ + (s->cur_file_info.compression_method!=Z_DEFLATED)) + + err=UNZ_BADZIPFILE; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->total_out_64=0; + pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method; + pfile_in_zip_read_info->filestream=s->filestream; + pfile_in_zip_read_info->z_filefunc=s->z_filefunc; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if ((s->cur_file_info.compression_method==Z_BZIP2ED) && (!raw)) + { +#ifdef HAVE_BZIP2 + pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0; + pfile_in_zip_read_info->bstream.bzfree = (free_func)0; + pfile_in_zip_read_info->bstream.opaque = (voidpf)0; + pfile_in_zip_read_info->bstream.state = (voidpf)0; + + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = (voidpf)0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } +#else + pfile_in_zip_read_info->raw=1; +#endif + } + else if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw)) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = 0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_DEFLATED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + s->pfile_in_zip_read = pfile_in_zip_read_info; + s->encrypted = 0; + +# ifndef NOUNCRYPT + if (password != NULL) + { + int i; + s->pcrc_32_tab = get_crc_table(); + init_keys(password,s->keys,s->pcrc_32_tab); + if (ZSEEK64(s->z_filefunc, s->filestream, + s->pfile_in_zip_read->pos_in_zipfile + + s->pfile_in_zip_read->byte_before_the_zipfile, + SEEK_SET)!=0) + return UNZ_INTERNALERROR; + if(ZREAD64(s->z_filefunc, s->filestream,source, 12)<12) + return UNZ_INTERNALERROR; + + for (i = 0; i<12; i++) + zdecode(s->keys,s->pcrc_32_tab,source[i]); + + s->pfile_in_zip_read->pos_in_zipfile+=12; + s->encrypted=1; + } +# endif + + + return UNZ_OK; +} + +extern int ZEXPORT unzOpenCurrentFile (unzFile file) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); +} + +extern int ZEXPORT unzOpenCurrentFilePassword (unzFile file, const char* password) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, password); +} + +extern int ZEXPORT unzOpenCurrentFile2 (unzFile file, int* method, int* level, int raw) +{ + return unzOpenCurrentFile3(file, method, level, raw, NULL); +} + +/** Addition for GDAL : START */ + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64( unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + s=(unz64_s*)file; + if (file==NULL) + return 0; //UNZ_PARAMERROR; + pfile_in_zip_read_info=s->pfile_in_zip_read; + if (pfile_in_zip_read_info==NULL) + return 0; //UNZ_PARAMERROR; + return pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile; +} + +/** Addition for GDAL : END */ + +/* + Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ +extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len) +{ + int err=UNZ_OK; + uInt iRead = 0; + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if (pfile_in_zip_read_info->read_buffer == NULL) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if ((len>pfile_in_zip_read_info->rest_read_uncompressed) && + (!(pfile_in_zip_read_info->raw))) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + if ((len>pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in) && + (pfile_in_zip_read_info->raw)) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + if (ZREAD64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->read_buffer, + uReadThis)!=uReadThis) + return UNZ_ERRNO; + + +# ifndef NOUNCRYPT + if(s->encrypted) + { + uInt i; + for(i=0;iread_buffer[i] = + zdecode(s->keys,s->pcrc_32_tab, + pfile_in_zip_read_info->read_buffer[i]); + } +# endif + + + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Bytef*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) + { + uInt uDoCopy,i ; + + if ((pfile_in_zip_read_info->stream.avail_in == 0) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + return (iRead==0) ? UNZ_EOF : iRead; + + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uDoCopy; + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + uLong uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + uLong uOutThis; + + pfile_in_zip_read_info->bstream.next_in = (char*)pfile_in_zip_read_info->stream.next_in; + pfile_in_zip_read_info->bstream.avail_in = pfile_in_zip_read_info->stream.avail_in; + pfile_in_zip_read_info->bstream.total_in_lo32 = pfile_in_zip_read_info->stream.total_in; + pfile_in_zip_read_info->bstream.total_in_hi32 = 0; + pfile_in_zip_read_info->bstream.next_out = (char*)pfile_in_zip_read_info->stream.next_out; + pfile_in_zip_read_info->bstream.avail_out = pfile_in_zip_read_info->stream.avail_out; + pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out; + pfile_in_zip_read_info->bstream.total_out_hi32 = 0; + + uTotalOutBefore = pfile_in_zip_read_info->bstream.total_out_lo32; + bufBefore = (const Bytef *)pfile_in_zip_read_info->bstream.next_out; + + err=BZ2_bzDecompress(&pfile_in_zip_read_info->bstream); + + uTotalOutAfter = pfile_in_zip_read_info->bstream.total_out_lo32; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis)); + pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->bstream.next_in; + pfile_in_zip_read_info->stream.avail_in = pfile_in_zip_read_info->bstream.avail_in; + pfile_in_zip_read_info->stream.total_in = pfile_in_zip_read_info->bstream.total_in_lo32; + pfile_in_zip_read_info->stream.next_out = (Bytef*)pfile_in_zip_read_info->bstream.next_out; + pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out; + pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32; + + if (err==BZ_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=BZ_OK) + break; +#endif + } // end Z_BZIP2ED + else + { + ZPOS64_T uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + ZPOS64_T uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL)) + err = Z_DATA_ERROR; + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +extern z_off_t ZEXPORT unztell (unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (z_off_t)pfile_in_zip_read_info->stream.total_out; +} + +extern ZPOS64_T ZEXPORT unztell64 (unzFile file) +{ + + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return (ZPOS64_T)-1; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return (ZPOS64_T)-1; + + return pfile_in_zip_read_info->total_out_64; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int ZEXPORT unzeof (unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +/* +Read extra field from the current file (opened by unzOpenCurrentFile) +This is the local-header version of the extra field (sometimes, there is +more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +extern int ZEXPORT unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + uInt read_now; + ZPOS64_T size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (ZREAD64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + buf,read_now)!=read_now) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int ZEXPORT unzCloseCurrentFile (unzFile file) +{ + int err=UNZ_OK; + + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && + (!pfile_in_zip_read_info->raw)) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + TRYFREE(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED) + inflateEnd(&pfile_in_zip_read_info->stream); +#ifdef HAVE_BZIP2 + else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED) + BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream); +#endif + + + pfile_in_zip_read_info->stream_initialised = 0; + TRYFREE(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +extern int ZEXPORT unzGetGlobalComment (unzFile file, char * szComment, uLong uSizeBuf) +{ + unz64_s* s; + uLong uReadThis ; + if (file==NULL) + return (int)UNZ_PARAMERROR; + s=(unz64_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (ZSEEK64(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (ZREAD64(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} + +/* Additions by RX '2004 */ +extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) +{ + unz64_s* s; + + if (file==NULL) + return 0; //UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return 0; + if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) + if (s->num_file==s->gi.number_entry) + return 0; + return s->pos_in_central_dir; +} + +extern uLong ZEXPORT unzGetOffset (unzFile file) +{ + ZPOS64_T offset64; + + if (file==NULL) + return 0; //UNZ_PARAMERROR; + offset64 = unzGetOffset64(file); + return (uLong)offset64; +} + +extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) +{ + unz64_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + + s->pos_in_central_dir = pos; + s->num_file = s->gi.number_entry; /* hack */ + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos) +{ + return unzSetOffset64(file,pos); +} diff --git a/DSView/pv/minizip/unzip.h b/DSView/pv/minizip/unzip.h new file mode 100644 index 00000000..2104e391 --- /dev/null +++ b/DSView/pv/minizip/unzip.h @@ -0,0 +1,437 @@ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + --------------------------------------------------------------------------------- + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + --------------------------------------------------------------------------------- + + Changes + + See header of unzip64.c + +*/ + +#ifndef _unz64_H +#define _unz64_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef voidp unzFile; +#endif + + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info64_s +{ + ZPOS64_T number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info64; + +typedef struct unz_global_info_s +{ + uLong number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info64_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + ZPOS64_T compressed_size; /* compressed size 8 bytes */ + ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info64; + +typedef struct unz_file_info_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info; + +extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, + const char* fileName2, + int iCaseSensitivity)); +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + + +extern unzFile ZEXPORT unzOpen OF((const char *path)); +extern unzFile ZEXPORT unzOpen64 OF((const void *path)); +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer + "zlib/zlib113.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. + the "64" function take a const void* pointer, because the path is just the + value passed to the open64_file_func callback. + Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path + is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char* + does not describe the reality +*/ + + +extern unzFile ZEXPORT unzOpen2 OF((const char *path, + zlib_filefunc_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unzOpen, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern unzFile ZEXPORT unzOpen2_64 OF((const void *path, + zlib_filefunc64_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unz64Open, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern int ZEXPORT unzClose OF((unzFile file)); +/* + Close a ZipFile opened with unzOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzCloseCurrentFile before call unzClose. + return UNZ_OK if there is no problem. */ + +extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, + unz_global_info *pglobal_info)); + +extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file, + unz_global_info64 *pglobal_info)); +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int ZEXPORT unzGetGlobalComment OF((unzFile file, + char *szComment, + uLong uSizeBuf)); +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int ZEXPORT unzLocateFile OF((unzFile file, + const char *szFileName, + int iCaseSensitivity)); +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +/* ****************************************** */ +/* Ryan supplied functions */ +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_pos_s +{ + uLong pos_in_zip_directory; /* offset in zip file directory */ + uLong num_of_file; /* # of file */ +} unz_file_pos; + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos); + +typedef struct unz64_file_pos_s +{ + ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */ + ZPOS64_T num_of_file; /* # of file */ +} unz64_file_pos; + +extern int ZEXPORT unzGetFilePos64( + unzFile file, + unz64_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos64( + unzFile file, + const unz64_file_pos* file_pos); + +/* ****************************************** */ + +extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file, + unz_file_info64 *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + + +/** Addition for GDAL : START */ + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file)); + +/** Addition for GDAL : END */ + + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, + const char* password)); +/* + Open for reading data the current file in the zipfile. + password is a crypting password + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, + int* method, + int* level, + int raw)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + +extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, + int* method, + int* level, + int raw, + const char* password)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + + +extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + +extern int ZEXPORT unzReadCurrentFile OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern z_off_t ZEXPORT unztell OF((unzFile file)); + +extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file)); +/* + Give the current position in uncompressed data +*/ + +extern int ZEXPORT unzeof OF((unzFile file)); +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ + +/***************************************************************************/ + +/* Get the current file offset */ +extern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file); +extern uLong ZEXPORT unzGetOffset (unzFile file); + +/* Set the current file offset */ +extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos); +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); + + + +#ifdef __cplusplus +} +#endif + +#endif /* _unz64_H */ diff --git a/DSView/pv/minizip/zip.c b/DSView/pv/minizip/zip.c new file mode 100644 index 00000000..44e88a9c --- /dev/null +++ b/DSView/pv/minizip/zip.c @@ -0,0 +1,2007 @@ +/* zip.c -- IO on .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + Changes + Oct-2009 - Mathias Svensson - Remove old C style function prototypes + Oct-2009 - Mathias Svensson - Added Zip64 Support when creating new file archives + Oct-2009 - Mathias Svensson - Did some code cleanup and refactoring to get better overview of some functions. + Oct-2009 - Mathias Svensson - Added zipRemoveExtraInfoBlock to strip extra field data from its ZIP64 data + It is used when recreting zip archive with RAW when deleting items from a zip. + ZIP64 data is automatically added to items that needs it, and existing ZIP64 data need to be removed. + Oct-2009 - Mathias Svensson - Added support for BZIP2 as compression mode (bzip2 lib is required) + Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer + +*/ + + +#include +#include +#include +#include +#include "zlib.h" +#include "zip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +#ifndef VERSIONMADEBY +# define VERSIONMADEBY (0x0) /* platform depedent */ +#endif + +#ifndef Z_BUFSIZE +#define Z_BUFSIZE (64*1024) //(16384) +#endif + +#ifndef Z_MAXFILENAMEINZIP +#define Z_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +/* +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) +*/ + +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ + + +// NOT sure that this work on ALL platform +#define MAKEULONG64(a, b) ((ZPOS64_T)(((unsigned long)(a)) | ((ZPOS64_T)((unsigned long)(b))) << 32)) + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +#ifndef DEF_MEM_LEVEL +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +#endif +const char zip_copyright[] =" zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + + +#define SIZEDATA_INDATABLOCK (4096-(4*4)) + +#define LOCALHEADERMAGIC (0x04034b50) +#define CENTRALHEADERMAGIC (0x02014b50) +#define ENDHEADERMAGIC (0x06054b50) +#define ZIP64ENDHEADERMAGIC (0x6064b50) +#define ZIP64ENDLOCHEADERMAGIC (0x7064b50) + +#define FLAG_LOCALHEADER_OFFSET (0x06) +#define CRC_LOCALHEADER_OFFSET (0x0e) + +#define SIZECENTRALHEADER (0x2e) /* 46 */ + +typedef struct linkedlist_datablock_internal_s +{ + struct linkedlist_datablock_internal_s* next_datablock; + uLong avail_in_this_block; + uLong filled_in_this_block; + uLong unused; /* for future use and alignment */ + unsigned char data[SIZEDATA_INDATABLOCK]; +} linkedlist_datablock_internal; + +typedef struct linkedlist_data_s +{ + linkedlist_datablock_internal* first_block; + linkedlist_datablock_internal* last_block; +} linkedlist_data; + + +typedef struct +{ + z_stream stream; /* zLib stream structure for inflate */ +#ifdef HAVE_BZIP2 + bz_stream bstream; /* bzLib stream structure for bziped */ +#endif + + int stream_initialised; /* 1 is stream is initialised */ + uInt pos_in_buffered_data; /* last written byte in buffered_data */ + + ZPOS64_T pos_local_header; /* offset of the local header of the file + currenty writing */ + char* central_header; /* central header data for the current file */ + uLong size_centralExtra; + uLong size_centralheader; /* size of the central header for cur file */ + uLong size_centralExtraFree; /* Extra bytes allocated to the centralheader but that are not used */ + uLong flag; /* flag of the file currently writing */ + + int method; /* compression method of file currenty wr.*/ + int raw; /* 1 for directly writing raw data */ + Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/ + uLong dosDate; + uLong crc32; + int encrypt; + int zip64; /* Add ZIP64 extened information in the extra field */ + ZPOS64_T pos_zip64extrainfo; + ZPOS64_T totalCompressedData; + ZPOS64_T totalUncompressedData; +#ifndef NOCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const z_crc_t* pcrc_32_tab; + int crypt_header_size; +#endif +} curfile64_info; + +typedef struct +{ + zlib_filefunc64_32_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + linkedlist_data central_dir;/* datablock with central dir in construction*/ + int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ + curfile64_info ci; /* info on the file curretly writing */ + + ZPOS64_T begin_pos; /* position of the beginning of the zipfile */ + ZPOS64_T add_position_when_writing_offset; + ZPOS64_T number_entry; + +#ifndef NO_ADDFILEINEXISTINGZIP + char *globalcomment; +#endif + +} zip64_internal; + + +#ifndef NOCRYPT +#define INCLUDECRYPTINGCODE_IFCRYPTALLOWED +#include "crypt.h" +#endif + +local linkedlist_datablock_internal* allocate_new_datablock() +{ + linkedlist_datablock_internal* ldi; + ldi = (linkedlist_datablock_internal*) + ALLOC(sizeof(linkedlist_datablock_internal)); + if (ldi!=NULL) + { + ldi->next_datablock = NULL ; + ldi->filled_in_this_block = 0 ; + ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ; + } + return ldi; +} + +local void free_datablock(linkedlist_datablock_internal* ldi) +{ + while (ldi!=NULL) + { + linkedlist_datablock_internal* ldinext = ldi->next_datablock; + TRYFREE(ldi); + ldi = ldinext; + } +} + +local void init_linkedlist(linkedlist_data* ll) +{ + ll->first_block = ll->last_block = NULL; +} + +local void free_linkedlist(linkedlist_data* ll) +{ + free_datablock(ll->first_block); + ll->first_block = ll->last_block = NULL; +} + + +local int add_data_in_datablock(linkedlist_data* ll, const void* buf, uLong len) +{ + linkedlist_datablock_internal* ldi; + const unsigned char* from_copy; + + if (ll==NULL) + return ZIP_INTERNALERROR; + + if (ll->last_block == NULL) + { + ll->first_block = ll->last_block = allocate_new_datablock(); + if (ll->first_block == NULL) + return ZIP_INTERNALERROR; + } + + ldi = ll->last_block; + from_copy = (unsigned char*)buf; + + while (len>0) + { + uInt copy_this; + uInt i; + unsigned char* to_copy; + + if (ldi->avail_in_this_block==0) + { + ldi->next_datablock = allocate_new_datablock(); + if (ldi->next_datablock == NULL) + return ZIP_INTERNALERROR; + ldi = ldi->next_datablock ; + ll->last_block = ldi; + } + + if (ldi->avail_in_this_block < len) + copy_this = (uInt)ldi->avail_in_this_block; + else + copy_this = (uInt)len; + + to_copy = &(ldi->data[ldi->filled_in_this_block]); + + for (i=0;ifilled_in_this_block += copy_this; + ldi->avail_in_this_block -= copy_this; + from_copy += copy_this ; + len -= copy_this; + } + return ZIP_OK; +} + + + +/****************************************************************************/ + +#ifndef NO_ADDFILEINEXISTINGZIP +/* =========================================================================== + Inputs a long in LSB order to the given file + nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T) +*/ + +local int zip64local_putValue OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte)); +local int zip64local_putValue (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte) +{ + unsigned char buf[8]; + int n; + for (n = 0; n < nbByte; n++) + { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + if (x != 0) + { /* data overflow - hack for ZIP64 (X Roche) */ + for (n = 0; n < nbByte; n++) + { + buf[n] = 0xff; + } + } + + if (ZWRITE64(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte) + return ZIP_ERRNO; + else + return ZIP_OK; +} + +local void zip64local_putValue_inmemory OF((void* dest, ZPOS64_T x, int nbByte)); +local void zip64local_putValue_inmemory (void* dest, ZPOS64_T x, int nbByte) +{ + unsigned char* buf=(unsigned char*)dest; + int n; + for (n = 0; n < nbByte; n++) { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + + if (x != 0) + { /* data overflow - hack for ZIP64 */ + for (n = 0; n < nbByte; n++) + { + buf[n] = 0xff; + } + } +} + +/****************************************************************************/ + + +local uLong zip64local_TmzDateToDosDate(const tm_zip* ptm) +{ + uLong year = (uLong)ptm->tm_year; + if (year>=1980) + year-=1980; + else if (year>=80) + year-=80; + return + (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) | + ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); +} + + +/****************************************************************************/ + +local int zip64local_getByte OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi)); + +local int zip64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def,voidpf filestream,int* pi) +{ + unsigned char c; + int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return ZIP_OK; + } + else + { + if (ZERROR64(*pzlib_filefunc_def,filestream)) + return ZIP_ERRNO; + else + return ZIP_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int zip64local_getShort OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); + +local int zip64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) +{ + uLong x ; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int zip64local_getLong OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); + +local int zip64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) +{ + uLong x ; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<16; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int zip64local_getLong64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)); + + +local int zip64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX) +{ + ZPOS64_T x; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (ZPOS64_T)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<8; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<16; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<24; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<32; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<40; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<48; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<56; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + + return err; +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T zip64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); + +local ZPOS64_T zip64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + +/* +Locate the End of Zip64 Central directory locator and from there find the CD of a zipfile (at the end, just before +the global comment) +*/ +local ZPOS64_T zip64local_SearchCentralDir64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); + +local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + uLong uL; + ZPOS64_T relativeOffset; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + { + // Signature "0x07064b50" Zip64 end of central directory locater + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) + { + uPosFound = uReadPos+i; + break; + } + } + + if (uPosFound!=0) + break; + } + + TRYFREE(buf); + if (uPosFound == 0) + return 0; + + /* Zip64 end of central directory locator */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature, already checked */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + + /* number of the disk with the start of the zip64 end of central directory */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + if (uL != 0) + return 0; + + /* relative offset of the zip64 end of central directory record */ + if (zip64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=ZIP_OK) + return 0; + + /* total number of disks */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + if (uL != 1) + return 0; + + /* Goto Zip64 end of central directory record */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + + if (uL != 0x06064b50) // signature of 'Zip64 end of central directory' + return 0; + + return relativeOffset; +} + +int LoadCentralDirectoryRecord(zip64_internal* pziinit) +{ + int err=ZIP_OK; + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + + ZPOS64_T size_central_dir; /* size of the central directory */ + ZPOS64_T offset_central_dir; /* offset of start of central directory */ + ZPOS64_T central_pos; + uLong uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + ZPOS64_T number_entry; + ZPOS64_T number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + uLong VersionMadeBy; + uLong VersionNeeded; + uLong size_comment; + + int hasZIP64Record = 0; + + // check first if we find a ZIP64 record + central_pos = zip64local_SearchCentralDir64(&pziinit->z_filefunc,pziinit->filestream); + if(central_pos > 0) + { + hasZIP64Record = 1; + } + else if(central_pos == 0) + { + central_pos = zip64local_SearchCentralDir(&pziinit->z_filefunc,pziinit->filestream); + } + +/* disable to allow appending to empty ZIP archive + if (central_pos==0) + err=ZIP_ERRNO; +*/ + + if(hasZIP64Record) + { + ZPOS64_T sizeEndOfCentralDirectory; + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + /* the signature, already checked */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) + err=ZIP_ERRNO; + + /* size of zip64 end of central directory record */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &sizeEndOfCentralDirectory)!=ZIP_OK) + err=ZIP_ERRNO; + + /* version made by */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionMadeBy)!=ZIP_OK) + err=ZIP_ERRNO; + + /* version needed to extract */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionNeeded)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of this disk */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of the disk with the start of the central directory */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central directory on this disk */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &number_entry)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central directory */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&number_entry_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) + err=ZIP_BADZIPFILE; + + /* size of the central directory */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&size_central_dir)!=ZIP_OK) + err=ZIP_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&offset_central_dir)!=ZIP_OK) + err=ZIP_ERRNO; + + // TODO.. + // read the comment from the standard central header. + size_comment = 0; + } + else + { + // Read End of central Directory info + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=ZIP_ERRNO; + + /* the signature, already checked */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of this disk */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of the disk with the start of the central directory */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central dir on this disk */ + number_entry = 0; + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + number_entry = uL; + + /* total number of entries in the central dir */ + number_entry_CD = 0; + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + number_entry_CD = uL; + + if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) + err=ZIP_BADZIPFILE; + + /* size of the central directory */ + size_central_dir = 0; + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + size_central_dir = uL; + + /* offset of start of central directory with respect to the starting disk number */ + offset_central_dir = 0; + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + offset_central_dir = uL; + + + /* zipfile global comment length */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &size_comment)!=ZIP_OK) + err=ZIP_ERRNO; + } + + if ((central_posz_filefunc, pziinit->filestream); + return ZIP_ERRNO; + } + + if (size_comment>0) + { + pziinit->globalcomment = (char*)ALLOC(size_comment+1); + if (pziinit->globalcomment) + { + size_comment = ZREAD64(pziinit->z_filefunc, pziinit->filestream, pziinit->globalcomment,size_comment); + pziinit->globalcomment[size_comment]=0; + } + } + + byte_before_the_zipfile = central_pos - (offset_central_dir+size_central_dir); + pziinit->add_position_when_writing_offset = byte_before_the_zipfile; + + { + ZPOS64_T size_central_dir_to_read = size_central_dir; + size_t buf_size = SIZEDATA_INDATABLOCK; + void* buf_read = (void*)ALLOC(buf_size); + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + while ((size_central_dir_to_read>0) && (err==ZIP_OK)) + { + ZPOS64_T read_this = SIZEDATA_INDATABLOCK; + if (read_this > size_central_dir_to_read) + read_this = size_central_dir_to_read; + + if (ZREAD64(pziinit->z_filefunc, pziinit->filestream,buf_read,(uLong)read_this) != read_this) + err=ZIP_ERRNO; + + if (err==ZIP_OK) + err = add_data_in_datablock(&pziinit->central_dir,buf_read, (uLong)read_this); + + size_central_dir_to_read-=read_this; + } + TRYFREE(buf_read); + } + pziinit->begin_pos = byte_before_the_zipfile; + pziinit->number_entry = number_entry_CD; + + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + return err; +} + + +#endif /* !NO_ADDFILEINEXISTINGZIP*/ + + +/************************************************************/ +extern zipFile ZEXPORT zipOpen3 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_32_def* pzlib_filefunc64_32_def) +{ + zip64_internal ziinit; + zip64_internal* zi; + int err=ZIP_OK; + + ziinit.z_filefunc.zseek32_file = NULL; + ziinit.z_filefunc.ztell32_file = NULL; + if (pzlib_filefunc64_32_def==NULL) + fill_fopen64_filefunc(&ziinit.z_filefunc.zfile_func64); + else + ziinit.z_filefunc = *pzlib_filefunc64_32_def; + + ziinit.filestream = ZOPEN64(ziinit.z_filefunc, + pathname, + (append == APPEND_STATUS_CREATE) ? + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) : + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING)); + + if (ziinit.filestream == NULL) + return NULL; + + if (append == APPEND_STATUS_CREATEAFTER) + ZSEEK64(ziinit.z_filefunc,ziinit.filestream,0,SEEK_END); + + ziinit.begin_pos = ZTELL64(ziinit.z_filefunc,ziinit.filestream); + ziinit.in_opened_file_inzip = 0; + ziinit.ci.stream_initialised = 0; + ziinit.number_entry = 0; + ziinit.add_position_when_writing_offset = 0; + init_linkedlist(&(ziinit.central_dir)); + + + + zi = (zip64_internal*)ALLOC(sizeof(zip64_internal)); + if (zi==NULL) + { + ZCLOSE64(ziinit.z_filefunc,ziinit.filestream); + return NULL; + } + + /* now we add file in a zipfile */ +# ifndef NO_ADDFILEINEXISTINGZIP + ziinit.globalcomment = NULL; + if (append == APPEND_STATUS_ADDINZIP) + { + // Read and Cache Central Directory Records + err = LoadCentralDirectoryRecord(&ziinit); + } + + if (globalcomment) + { + *globalcomment = ziinit.globalcomment; + } +# endif /* !NO_ADDFILEINEXISTINGZIP*/ + + if (err != ZIP_OK) + { +# ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(ziinit.globalcomment); +# endif /* !NO_ADDFILEINEXISTINGZIP*/ + TRYFREE(zi); + return NULL; + } + else + { + *zi = ziinit; + return (zipFile)zi; + } +} + +extern zipFile ZEXPORT zipOpen2 (const char *pathname, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc32_def) +{ + if (pzlib_filefunc32_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def); + return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); + } + else + return zipOpen3(pathname, append, globalcomment, NULL); +} + +extern zipFile ZEXPORT zipOpen2_64 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def) +{ + if (pzlib_filefunc_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; + zlib_filefunc64_32_def_fill.ztell32_file = NULL; + zlib_filefunc64_32_def_fill.zseek32_file = NULL; + return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); + } + else + return zipOpen3(pathname, append, globalcomment, NULL); +} + + + +extern zipFile ZEXPORT zipOpen (const char* pathname, int append) +{ + return zipOpen3((const void*)pathname,append,NULL,NULL); +} + +extern zipFile ZEXPORT zipOpen64 (const void* pathname, int append) +{ + return zipOpen3(pathname,append,NULL,NULL); +} + +int Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local) +{ + /* write the local header */ + int err; + uInt size_filename = (uInt)strlen(filename); + uInt size_extrafield = size_extrafield_local; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC, 4); + + if (err==ZIP_OK) + { + if(zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);/* version needed to extract */ + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)20,2);/* version needed to extract */ + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2); + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2); + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4); + + // CRC / Compressed size / Uncompressed size will be filled in later and rewritten later + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */ + if (err==ZIP_OK) + { + if(zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* compressed size, unknown */ + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */ + } + if (err==ZIP_OK) + { + if(zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* uncompressed size, unknown */ + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */ + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2); + + if(zi->ci.zip64) + { + size_extrafield += 20; + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield,2); + + if ((err==ZIP_OK) && (size_filename > 0)) + { + if (ZWRITE64(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename) + err = ZIP_ERRNO; + } + + if ((err==ZIP_OK) && (size_extrafield_local > 0)) + { + if (ZWRITE64(zi->z_filefunc, zi->filestream, extrafield_local, size_extrafield_local) != size_extrafield_local) + err = ZIP_ERRNO; + } + + + if ((err==ZIP_OK) && (zi->ci.zip64)) + { + // write the Zip64 extended info + short HeaderID = 1; + short DataSize = 16; + ZPOS64_T CompressedSize = 0; + ZPOS64_T UncompressedSize = 0; + + // Remember position of Zip64 extended info for the local file header. (needed when we update size after done with file) + zi->ci.pos_zip64extrainfo = ZTELL64(zi->z_filefunc,zi->filestream); + + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)HeaderID,2); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)DataSize,2); + + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)UncompressedSize,8); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)CompressedSize,8); + } + + return err; +} + +/* + NOTE. + When writing RAW the ZIP64 extended information in extrafield_local and extrafield_global needs to be stripped + before calling this function it can be done with zipRemoveExtraInfoBlock + + It is not done here because then we need to realloc a new buffer since parameters are 'const' and I want to minimize + unnecessary allocations. + */ +extern int ZEXPORT zipOpenNewFileInZip4_64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting, + uLong versionMadeBy, uLong flagBase, int zip64) +{ + zip64_internal* zi; + uInt size_filename; + uInt size_comment; + uInt i; + int err = ZIP_OK; + +# ifdef NOCRYPT + (crcForCrypting); + if (password != NULL) + return ZIP_PARAMERROR; +# endif + + if (file == NULL) + return ZIP_PARAMERROR; + +#ifdef HAVE_BZIP2 + if ((method!=0) && (method!=Z_DEFLATED) && (method!=Z_BZIP2ED)) + return ZIP_PARAMERROR; +#else + if ((method!=0) && (method!=Z_DEFLATED)) + return ZIP_PARAMERROR; +#endif + + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + if (err != ZIP_OK) + return err; + } + + if (filename==NULL) + filename="-"; + + if (comment==NULL) + size_comment = 0; + else + size_comment = (uInt)strlen(comment); + + size_filename = (uInt)strlen(filename); + + if (zipfi == NULL) + zi->ci.dosDate = 0; + else + { + if (zipfi->dosDate != 0) + zi->ci.dosDate = zipfi->dosDate; + else + zi->ci.dosDate = zip64local_TmzDateToDosDate(&zipfi->tmz_date); + } + + zi->ci.flag = flagBase; + if ((level==8) || (level==9)) + zi->ci.flag |= 2; + if (level==2) + zi->ci.flag |= 4; + if (level==1) + zi->ci.flag |= 6; + if (password != NULL) + zi->ci.flag |= 1; + + zi->ci.crc32 = 0; + zi->ci.method = method; + zi->ci.encrypt = 0; + zi->ci.stream_initialised = 0; + zi->ci.pos_in_buffered_data = 0; + zi->ci.raw = raw; + zi->ci.pos_local_header = ZTELL64(zi->z_filefunc,zi->filestream); + + zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + size_extrafield_global + size_comment; + zi->ci.size_centralExtraFree = 32; // Extra space we have reserved in case we need to add ZIP64 extra info data + + zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader + zi->ci.size_centralExtraFree); + + zi->ci.size_centralExtra = size_extrafield_global; + zip64local_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4); + /* version info */ + zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)versionMadeBy,2); + zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2); + zip64local_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2); + zip64local_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2); + zip64local_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4); + zip64local_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/ + zip64local_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/ + zip64local_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/ + zip64local_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2); + zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2); + zip64local_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2); + zip64local_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/ + + if (zipfi==NULL) + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2); + else + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2); + + if (zipfi==NULL) + zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4); + else + zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4); + + if(zi->ci.pos_local_header >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)0xffffffff,4); + else + zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header - zi->add_position_when_writing_offset,4); + + for (i=0;ici.central_header+SIZECENTRALHEADER+i) = *(filename+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+i) = + *(((const char*)extrafield_global)+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+ + size_extrafield_global+i) = *(comment+i); + if (zi->ci.central_header == NULL) + return ZIP_INTERNALERROR; + + zi->ci.zip64 = zip64; + zi->ci.totalCompressedData = 0; + zi->ci.totalUncompressedData = 0; + zi->ci.pos_zip64extrainfo = 0; + + err = Write_LocalFileHeader(zi, filename, size_extrafield_local, extrafield_local); + +#ifdef HAVE_BZIP2 + zi->ci.bstream.avail_in = (uInt)0; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + zi->ci.bstream.total_in_hi32 = 0; + zi->ci.bstream.total_in_lo32 = 0; + zi->ci.bstream.total_out_hi32 = 0; + zi->ci.bstream.total_out_lo32 = 0; +#endif + + zi->ci.stream.avail_in = (uInt)0; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + zi->ci.stream.total_in = 0; + zi->ci.stream.total_out = 0; + zi->ci.stream.data_type = Z_BINARY; + +#ifdef HAVE_BZIP2 + if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED || zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) +#else + if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) +#endif + { + if(zi->ci.method == Z_DEFLATED) + { + zi->ci.stream.zalloc = (alloc_func)0; + zi->ci.stream.zfree = (free_func)0; + zi->ci.stream.opaque = (voidpf)0; + + if (windowBits>0) + windowBits = -windowBits; + + err = deflateInit2(&zi->ci.stream, level, Z_DEFLATED, windowBits, memLevel, strategy); + + if (err==Z_OK) + zi->ci.stream_initialised = Z_DEFLATED; + } + else if(zi->ci.method == Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + // Init BZip stuff here + zi->ci.bstream.bzalloc = 0; + zi->ci.bstream.bzfree = 0; + zi->ci.bstream.opaque = (voidpf)0; + + err = BZ2_bzCompressInit(&zi->ci.bstream, level, 0,35); + if(err == BZ_OK) + zi->ci.stream_initialised = Z_BZIP2ED; +#endif + } + + } + +# ifndef NOCRYPT + zi->ci.crypt_header_size = 0; + if ((err==Z_OK) && (password != NULL)) + { + unsigned char bufHead[RAND_HEAD_LEN]; + unsigned int sizeHead; + zi->ci.encrypt = 1; + zi->ci.pcrc_32_tab = get_crc_table(); + /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/ + + sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting); + zi->ci.crypt_header_size = sizeHead; + + if (ZWRITE64(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead) + err = ZIP_ERRNO; + } +# endif + + if (err==Z_OK) + zi->in_opened_file_inzip = 1; + return err; +} + +extern int ZEXPORT zipOpenNewFileInZip4 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting, + uLong versionMadeBy, uLong flagBase) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, versionMadeBy, flagBase, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip3 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, VERSIONMADEBY, 0, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting, int zip64) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip2(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, int zip64) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void*extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int zip64) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, 0, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void*extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, 0, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, 0); +} + +local int zip64FlushWriteBuffer(zip64_internal* zi) +{ + int err=ZIP_OK; + + if (zi->ci.encrypt != 0) + { +#ifndef NOCRYPT + uInt i; + int t; + for (i=0;ici.pos_in_buffered_data;i++) + zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, zi->ci.buffered_data[i],t); +#endif + } + + if (ZWRITE64(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) != zi->ci.pos_in_buffered_data) + err = ZIP_ERRNO; + + zi->ci.totalCompressedData += zi->ci.pos_in_buffered_data; + +#ifdef HAVE_BZIP2 + if(zi->ci.method == Z_BZIP2ED) + { + zi->ci.totalUncompressedData += zi->ci.bstream.total_in_lo32; + zi->ci.bstream.total_in_lo32 = 0; + zi->ci.bstream.total_in_hi32 = 0; + } + else +#endif + { + zi->ci.totalUncompressedData += zi->ci.stream.total_in; + zi->ci.stream.total_in = 0; + } + + + zi->ci.pos_in_buffered_data = 0; + + return err; +} + +extern int ZEXPORT zipWriteInFileInZip (zipFile file,const void* buf,unsigned int len) +{ + zip64_internal* zi; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + + zi->ci.crc32 = crc32(zi->ci.crc32,buf,(uInt)len); + +#ifdef HAVE_BZIP2 + if(zi->ci.method == Z_BZIP2ED && (!zi->ci.raw)) + { + zi->ci.bstream.next_in = (void*)buf; + zi->ci.bstream.avail_in = len; + err = BZ_RUN_OK; + + while ((err==BZ_RUN_OK) && (zi->ci.bstream.avail_in>0)) + { + if (zi->ci.bstream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + } + + + if(err != BZ_RUN_OK) + break; + + if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { + uLong uTotalOutBefore_lo = zi->ci.bstream.total_out_lo32; +// uLong uTotalOutBefore_hi = zi->ci.bstream.total_out_hi32; + err=BZ2_bzCompress(&zi->ci.bstream, BZ_RUN); + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore_lo) ; + } + } + + if(err == BZ_RUN_OK) + err = ZIP_OK; + } + else +#endif + { + zi->ci.stream.next_in = (Bytef*)buf; + zi->ci.stream.avail_in = len; + + while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0)) + { + if (zi->ci.stream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + + + if(err != ZIP_OK) + break; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + uLong uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_NO_FLUSH); + if(uTotalOutBefore > zi->ci.stream.total_out) + { + int bBreak = 0; + bBreak++; + } + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + } + else + { + uInt copy_this,i; + if (zi->ci.stream.avail_in < zi->ci.stream.avail_out) + copy_this = zi->ci.stream.avail_in; + else + copy_this = zi->ci.stream.avail_out; + + for (i = 0; i < copy_this; i++) + *(((char*)zi->ci.stream.next_out)+i) = + *(((const char*)zi->ci.stream.next_in)+i); + { + zi->ci.stream.avail_in -= copy_this; + zi->ci.stream.avail_out-= copy_this; + zi->ci.stream.next_in+= copy_this; + zi->ci.stream.next_out+= copy_this; + zi->ci.stream.total_in+= copy_this; + zi->ci.stream.total_out+= copy_this; + zi->ci.pos_in_buffered_data += copy_this; + } + } + }// while(...) + } + + return err; +} + +extern int ZEXPORT zipCloseFileInZipRaw (zipFile file, uLong uncompressed_size, uLong crc32) +{ + return zipCloseFileInZipRaw64 (file, uncompressed_size, crc32); +} + +extern int ZEXPORT zipCloseFileInZipRaw64 (zipFile file, ZPOS64_T uncompressed_size, uLong crc32) +{ + zip64_internal* zi; + ZPOS64_T compressed_size; + uLong invalidValue = 0xffffffff; + short datasize = 0; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + zi->ci.stream.avail_in = 0; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + while (err==ZIP_OK) + { + uLong uTotalOutBefore; + if (zi->ci.stream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_FINISH); + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + } + } + else if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { +#ifdef HAVE_BZIP2 + err = BZ_FINISH_OK; + while (err==BZ_FINISH_OK) + { + uLong uTotalOutBefore; + if (zi->ci.bstream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + } + uTotalOutBefore = zi->ci.bstream.total_out_lo32; + err=BZ2_bzCompress(&zi->ci.bstream, BZ_FINISH); + if(err == BZ_STREAM_END) + err = Z_STREAM_END; + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore); + } + + if(err == BZ_FINISH_OK) + err = ZIP_OK; +#endif + } + + if (err==Z_STREAM_END) + err=ZIP_OK; /* this is normal */ + + if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK)) + { + if (zip64FlushWriteBuffer(zi)==ZIP_ERRNO) + err = ZIP_ERRNO; + } + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + int tmp_err = deflateEnd(&zi->ci.stream); + if (err == ZIP_OK) + err = tmp_err; + zi->ci.stream_initialised = 0; + } +#ifdef HAVE_BZIP2 + else if((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { + int tmperr = BZ2_bzCompressEnd(&zi->ci.bstream); + if (err==ZIP_OK) + err = tmperr; + zi->ci.stream_initialised = 0; + } +#endif + + if (!zi->ci.raw) + { + crc32 = (uLong)zi->ci.crc32; + uncompressed_size = zi->ci.totalUncompressedData; + } + compressed_size = zi->ci.totalCompressedData; + +# ifndef NOCRYPT + compressed_size += zi->ci.crypt_header_size; +# endif + + // update Current Item crc and sizes, + if(compressed_size >= 0xffffffff || uncompressed_size >= 0xffffffff || zi->ci.pos_local_header >= 0xffffffff) + { + /*version Made by*/ + zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)45,2); + /*version needed*/ + zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)45,2); + + } + + zip64local_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/ + + + if(compressed_size >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+20, invalidValue,4); /*compr size*/ + else + zip64local_putValue_inmemory(zi->ci.central_header+20, compressed_size,4); /*compr size*/ + + /// set internal file attributes field + if (zi->ci.stream.data_type == Z_ASCII) + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2); + + if(uncompressed_size >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+24, invalidValue,4); /*uncompr size*/ + else + zip64local_putValue_inmemory(zi->ci.central_header+24, uncompressed_size,4); /*uncompr size*/ + + // Add ZIP64 extra info field for uncompressed size + if(uncompressed_size >= 0xffffffff) + datasize += 8; + + // Add ZIP64 extra info field for compressed size + if(compressed_size >= 0xffffffff) + datasize += 8; + + // Add ZIP64 extra info field for relative offset to local file header of current file + if(zi->ci.pos_local_header >= 0xffffffff) + datasize += 8; + + if(datasize > 0) + { + char* p = NULL; + + if((uLong)(datasize + 4) > zi->ci.size_centralExtraFree) + { + // we can not write more data to the buffer that we have room for. + return ZIP_BADZIPFILE; + } + + p = zi->ci.central_header + zi->ci.size_centralheader; + + // Add Extra Information Header for 'ZIP64 information' + zip64local_putValue_inmemory(p, 0x0001, 2); // HeaderID + p += 2; + zip64local_putValue_inmemory(p, datasize, 2); // DataSize + p += 2; + + if(uncompressed_size >= 0xffffffff) + { + zip64local_putValue_inmemory(p, uncompressed_size, 8); + p += 8; + } + + if(compressed_size >= 0xffffffff) + { + zip64local_putValue_inmemory(p, compressed_size, 8); + p += 8; + } + + if(zi->ci.pos_local_header >= 0xffffffff) + { + zip64local_putValue_inmemory(p, zi->ci.pos_local_header, 8); + p += 8; + } + + // Update how much extra free space we got in the memory buffer + // and increase the centralheader size so the new ZIP64 fields are included + // ( 4 below is the size of HeaderID and DataSize field ) + zi->ci.size_centralExtraFree -= datasize + 4; + zi->ci.size_centralheader += datasize + 4; + + // Update the extra info size field + zi->ci.size_centralExtra += datasize + 4; + zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)zi->ci.size_centralExtra,2); + } + + if (err==ZIP_OK) + err = add_data_in_datablock(&zi->central_dir, zi->ci.central_header, (uLong)zi->ci.size_centralheader); + + free(zi->ci.central_header); + + if (err==ZIP_OK) + { + // Update the LocalFileHeader with the new values. + + ZPOS64_T cur_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream); + + if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ + + if(uncompressed_size >= 0xffffffff || compressed_size >= 0xffffffff ) + { + if(zi->ci.pos_zip64extrainfo > 0) + { + // Update the size in the ZIP64 extended field. + if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_zip64extrainfo + 4,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + + if (err==ZIP_OK) /* compressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, uncompressed_size, 8); + + if (err==ZIP_OK) /* uncompressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, compressed_size, 8); + } + else + err = ZIP_BADZIPFILE; // Caller passed zip64 = 0, so no room for zip64 info -> fatal + } + else + { + if (err==ZIP_OK) /* compressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); + + if (err==ZIP_OK) /* uncompressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); + } + + if (ZSEEK64(zi->z_filefunc,zi->filestream, cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + } + + zi->number_entry ++; + zi->in_opened_file_inzip = 0; + + return err; +} + +extern int ZEXPORT zipCloseFileInZip (zipFile file) +{ + return zipCloseFileInZipRaw (file,0,0); +} + +int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip) +{ + int err = ZIP_OK; + ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writing_offset; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDLOCHEADERMAGIC,4); + + /*num disks*/ + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + /*relative offset*/ + if (err==ZIP_OK) /* Relative offset to the Zip64EndOfCentralDirectory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, pos,8); + + /*total disks*/ /* Do not support spawning of disk so always say 1 here*/ + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)1,4); + + return err; +} + +int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) +{ + int err = ZIP_OK; + + uLong Zip64DataSize = 44; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDHEADERMAGIC,4); + + if (err==ZIP_OK) /* size of this 'zip64 end of central directory' */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)Zip64DataSize,8); // why ZPOS64_T of this ? + + if (err==ZIP_OK) /* version made by */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); + + if (err==ZIP_OK) /* version needed */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); + + if (err==ZIP_OK) /* number of this disk */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); + + if (err==ZIP_OK) /* total number of entries in the central dir */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); + + if (err==ZIP_OK) /* size of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)size_centraldir,8); + + if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ + { + ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writing_offset; + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (ZPOS64_T)pos,8); + } + return err; +} +int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) +{ + int err = ZIP_OK; + + /*signature*/ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4); + + if (err==ZIP_OK) /* number of this disk */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); + + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); + + if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ + { + { + if(zi->number_entry >= 0xFFFF) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); + } + } + + if (err==ZIP_OK) /* total number of entries in the central dir */ + { + if(zi->number_entry >= 0xFFFF) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); + } + + if (err==ZIP_OK) /* size of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4); + + if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ + { + ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writing_offset; + if(pos >= 0xffffffff) + { + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)0xffffffff,4); + } + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)(centraldir_pos_inzip - zi->add_position_when_writing_offset),4); + } + + return err; +} + +int Write_GlobalComment(zip64_internal* zi, const char* global_comment) +{ + int err = ZIP_OK; + uInt size_global_comment = 0; + + if(global_comment != NULL) + size_global_comment = (uInt)strlen(global_comment); + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2); + + if (err == ZIP_OK && size_global_comment > 0) + { + if (ZWRITE64(zi->z_filefunc,zi->filestream, global_comment, size_global_comment) != size_global_comment) + err = ZIP_ERRNO; + } + return err; +} + +extern int ZEXPORT zipClose (zipFile file, const char* global_comment) +{ + zip64_internal* zi; + int err = 0; + uLong size_centraldir = 0; + ZPOS64_T centraldir_pos_inzip; + ZPOS64_T pos; + + if (file == NULL) + return ZIP_PARAMERROR; + + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + } + +#ifndef NO_ADDFILEINEXISTINGZIP + if (global_comment==NULL) + global_comment = zi->globalcomment; +#endif + + centraldir_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream); + + if (err==ZIP_OK) + { + linkedlist_datablock_internal* ldi = zi->central_dir.first_block; + while (ldi!=NULL) + { + if ((err==ZIP_OK) && (ldi->filled_in_this_block>0)) + { + if (ZWRITE64(zi->z_filefunc,zi->filestream, ldi->data, ldi->filled_in_this_block) != ldi->filled_in_this_block) + err = ZIP_ERRNO; + } + + size_centraldir += ldi->filled_in_this_block; + ldi = ldi->next_datablock; + } + } + free_linkedlist(&(zi->central_dir)); + + pos = centraldir_pos_inzip - zi->add_position_when_writing_offset; + if(pos >= 0xffffffff || zi->number_entry > 0xFFFF) + { + ZPOS64_T Zip64EOCDpos = ZTELL64(zi->z_filefunc,zi->filestream); + Write_Zip64EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); + + Write_Zip64EndOfCentralDirectoryLocator(zi, Zip64EOCDpos); + } + + if (err==ZIP_OK) + err = Write_EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); + + if(err == ZIP_OK) + err = Write_GlobalComment(zi, global_comment); + + if (ZCLOSE64(zi->z_filefunc,zi->filestream) != 0) + if (err == ZIP_OK) + err = ZIP_ERRNO; + +#ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(zi->globalcomment); +#endif + TRYFREE(zi); + + return err; +} + +extern int ZEXPORT zipRemoveExtraInfoBlock (char* pData, int* dataLen, short sHeader) +{ + char* p = pData; + int size = 0; + char* pNewHeader; + char* pTmp; + short header; + short dataSize; + + int retVal = ZIP_OK; + + if(pData == NULL || *dataLen < 4) + return ZIP_PARAMERROR; + + pNewHeader = (char*)ALLOC(*dataLen); + pTmp = pNewHeader; + + while(p < (pData + *dataLen)) + { + header = *(short*)p; + dataSize = *(((short*)p)+1); + + if( header == sHeader ) // Header found. + { + p += dataSize + 4; // skip it. do not copy to temp buffer + } + else + { + // Extra Info block should not be removed, So copy it to the temp buffer. + memcpy(pTmp, p, dataSize + 4); + p += dataSize + 4; + size += dataSize + 4; + } + + } + + if(size < *dataLen) + { + // clean old extra info block. + memset(pData,0, *dataLen); + + // copy the new extra info block over the old + if(size > 0) + memcpy(pData, pNewHeader, size); + + // set the new extra info size + *dataLen = size; + + retVal = ZIP_OK; + } + else + retVal = ZIP_ERRNO; + + TRYFREE(pNewHeader); + + return retVal; +} diff --git a/DSView/pv/minizip/zip.h b/DSView/pv/minizip/zip.h new file mode 100644 index 00000000..8aaebb62 --- /dev/null +++ b/DSView/pv/minizip/zip.h @@ -0,0 +1,362 @@ +/* zip.h -- IO on .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + --------------------------------------------------------------------------- + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + --------------------------------------------------------------------------- + + Changes + + See header of zip.h + +*/ + +#ifndef _zip12_H +#define _zip12_H + +#ifdef __cplusplus +extern "C" { +#endif + +//#define HAVE_BZIP2 + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagzipFile__ { int unused; } zipFile__; +typedef zipFile__ *zipFile; +#else +typedef voidp zipFile; +#endif + +#define ZIP_OK (0) +#define ZIP_EOF (0) +#define ZIP_ERRNO (Z_ERRNO) +#define ZIP_PARAMERROR (-102) +#define ZIP_BADZIPFILE (-103) +#define ZIP_INTERNALERROR (-104) + +#ifndef DEF_MEM_LEVEL +# if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +# else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +# endif +#endif +/* default memLevel */ + +/* tm_zip contain date/time info */ +typedef struct tm_zip_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_zip; + +typedef struct +{ + tm_zip tmz_date; /* date in understandable format */ + uLong dosDate; /* if dos_date == 0, tmu_date is used */ +/* uLong flag; */ /* general purpose bit flag 2 bytes */ + + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ +} zip_fileinfo; + +typedef const char* zipcharpc; + + +#define APPEND_STATUS_CREATE (0) +#define APPEND_STATUS_CREATEAFTER (1) +#define APPEND_STATUS_ADDINZIP (2) + +extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); +extern zipFile ZEXPORT zipOpen64 OF((const void *pathname, int append)); +/* + Create a zipfile. + pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on + an Unix computer "zlib/zlib113.zip". + if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip + will be created at the end of the file. + (useful if the file contain a self extractor code) + if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will + add files in existing zip (be sure you don't add file that doesn't exist) + If the zipfile cannot be opened, the return value is NULL. + Else, the return value is a zipFile Handle, usable with other function + of this zip package. +*/ + +/* Note : there is no delete function into a zipfile. + If you want delete file into a zipfile, you must open a zipfile, and create another + Of couse, you can use RAW reading and writing to copy the file you did not want delte +*/ + +extern zipFile ZEXPORT zipOpen2 OF((const char *pathname, + int append, + zipcharpc* globalcomment, + zlib_filefunc_def* pzlib_filefunc_def)); + +extern zipFile ZEXPORT zipOpen2_64 OF((const void *pathname, + int append, + zipcharpc* globalcomment, + zlib_filefunc64_def* pzlib_filefunc_def)); + +extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level)); + +extern int ZEXPORT zipOpenNewFileInZip64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int zip64)); + +/* + Open a file in the ZIP for writing. + filename : the filename in zip (if NULL, '-' without quote will be used + *zipfi contain supplemental information + if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local + contains the extrafield data the the local header + if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global + contains the extrafield data the the local header + if comment != NULL, comment contain the comment string + method contain the compression method (0 for store, Z_DEFLATED for deflate) + level contain the level of compression (can be Z_DEFAULT_COMPRESSION) + zip64 is set to 1 if a zip64 extended information block should be added to the local file header. + this MUST be '1' if the uncompressed size is >= 0xffffffff. + +*/ + + +extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw)); + + +extern int ZEXPORT zipOpenNewFileInZip2_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int zip64)); +/* + Same than zipOpenNewFileInZip, except if raw=1, we write raw file + */ + +extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting)); + +extern int ZEXPORT zipOpenNewFileInZip3_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + int zip64 + )); + +/* + Same than zipOpenNewFileInZip2, except + windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 + password : crypting password (NULL for no crypting) + crcForCrypting : crc of file to compress (needed for crypting) + */ + +extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + uLong versionMadeBy, + uLong flagBase + )); + + +extern int ZEXPORT zipOpenNewFileInZip4_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + uLong versionMadeBy, + uLong flagBase, + int zip64 + )); +/* + Same than zipOpenNewFileInZip4, except + versionMadeBy : value for Version made by field + flag : value for flag field (compression level info will be added) + */ + + +extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, + const void* buf, + unsigned len)); +/* + Write data in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); +/* + Close the current file in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, + uLong uncompressed_size, + uLong crc32)); + +extern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file, + ZPOS64_T uncompressed_size, + uLong crc32)); + +/* + Close the current file in the zipfile, for file opened with + parameter raw=1 in zipOpenNewFileInZip2 + uncompressed_size and crc32 are value for the uncompressed size +*/ + +extern int ZEXPORT zipClose OF((zipFile file, + const char* global_comment)); +/* + Close the zipfile +*/ + + +extern int ZEXPORT zipRemoveExtraInfoBlock OF((char* pData, int* dataLen, short sHeader)); +/* + zipRemoveExtraInfoBlock - Added by Mathias Svensson + + Remove extra information block from a extra information data for the local file header or central directory header + + It is needed to remove ZIP64 extra information blocks when before data is written if using RAW mode. + + 0x0001 is the signature header for the ZIP64 extra information blocks + + usage. + Remove ZIP64 Extra information from a central director extra field data + zipRemoveExtraInfoBlock(pCenDirExtraFieldData, &nCenDirExtraFieldDataLen, 0x0001); + + Remove ZIP64 Extra information from a Local File Header extra field data + zipRemoveExtraInfoBlock(pLocalHeaderExtraFieldData, &nLocalHeaderExtraFieldDataLen, 0x0001); +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _zip64_H */ diff --git a/DSView/pv/storesession.cpp b/DSView/pv/storesession.cpp index e77345bd..0d37207a 100755 --- a/DSView/pv/storesession.cpp +++ b/DSView/pv/storesession.cpp @@ -212,7 +212,7 @@ bool StoreSession::save_start(QString session_file) */ //make zip file - if (meta_file != NULL && m_zipDoc.CreateNew()) + if (meta_file != NULL && m_zipDoc.CreateNew(_file_name.toUtf8().data(), false)) { if ( !m_zipDoc.AddFromFile(meta_file.toUtf8().data(), "header") || !m_zipDoc.AddFromFile(decoders_file.toUtf8().data(), "decoders") @@ -324,8 +324,8 @@ void StoreSession::save_proc(shared_ptr snapshot) memcpy(tmp+(buf_end-buf), buf_start, buf+size-buf_end); } - ret = sr_session_append(_file_name.toUtf8().data(), tmp, size, - i, 0, ch_type, File_Version); + // ret = sr_session_append(_file_name.toUtf8().data(), tmp, size, + // i, 0, ch_type, File_Version); MakeChunkName(i, 0, ch_type, File_Version); ret = m_zipDoc.AddFromBuffer(chunk_name, (const char*)tmp, size) ? SR_OK : -1; @@ -363,7 +363,7 @@ void StoreSession::save_proc(shared_ptr snapshot) if (_canceled || num == 0) QFile::remove(_file_name); else { - bool bret = m_zipDoc.SaveToFile(_file_name.toUtf8().data()); + bool bret = m_zipDoc.Close(); m_zipDoc.Release(); if (!bret){ From dd2630c4fbc4effd0e1c3dddf189e685083435c1 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Fri, 22 Oct 2021 18:12:41 +0800 Subject: [PATCH 09/60] titlebar able process window move --- DSView/pv/ZipMaker.cpp | 2 +- DSView/pv/dialogs/applicationpardlg.cpp | 53 ++++++++ DSView/pv/dialogs/applicationpardlg.h | 52 ++++++++ DSView/pv/dialogs/deviceoptions.cpp | 3 +- DSView/pv/dialogs/dsdialog.cpp | 159 ++++++++++++------------ DSView/pv/dialogs/dsdialog.h | 46 ++++--- DSView/pv/dialogs/dsmessagebox.cpp | 105 +++++++--------- DSView/pv/dialogs/dsmessagebox.h | 29 ++--- DSView/pv/dock/protocoldock.cpp | 40 +++--- DSView/pv/dock/protocoldock.h | 2 +- DSView/pv/dock/protocolitemlayer.cpp | 19 +-- DSView/pv/dock/protocolitemlayer.h | 2 +- DSView/pv/dsvdef.cpp | 21 ++++ DSView/pv/dsvdef.h | 15 ++- DSView/pv/interface/uicallback.h | 8 ++ DSView/pv/mainframe.cpp | 93 ++++++++------ DSView/pv/mainframe.h | 16 ++- DSView/pv/toolbars/filebar.cpp | 26 ++-- DSView/pv/toolbars/titlebar.cpp | 91 +++++++++----- DSView/pv/toolbars/titlebar.h | 82 ++++++------ DSView/pv/toolbars/trigbar.cpp | 71 +++++++---- DSView/pv/toolbars/trigbar.h | 4 +- DSView/pv/ui/msgbox.cpp | 3 +- DSView/pv/view/decodetrace.cpp | 19 +-- DSView/pv/view/viewport.cpp | 2 +- libsigrok4DSL/hardware/demo/demo.h | 4 +- 26 files changed, 576 insertions(+), 391 deletions(-) create mode 100644 DSView/pv/dialogs/applicationpardlg.cpp create mode 100644 DSView/pv/dialogs/applicationpardlg.h create mode 100644 DSView/pv/interface/uicallback.h diff --git a/DSView/pv/ZipMaker.cpp b/DSView/pv/ZipMaker.cpp index 69f6ef0d..add6a080 100644 --- a/DSView/pv/ZipMaker.cpp +++ b/DSView/pv/ZipMaker.cpp @@ -36,7 +36,7 @@ ZipMaker::ZipMaker() : m_zDoc(NULL) { m_error[0] = 0; - m_opt_compress_level = Z_DEFAULT_COMPRESSION; + m_opt_compress_level = Z_BEST_SPEED; m_zi = NULL; } diff --git a/DSView/pv/dialogs/applicationpardlg.cpp b/DSView/pv/dialogs/applicationpardlg.cpp new file mode 100644 index 00000000..26e07484 --- /dev/null +++ b/DSView/pv/dialogs/applicationpardlg.cpp @@ -0,0 +1,53 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2015 DreamSourceLab + * + * 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 "applicationpardlg.h" +#include "dsdialog.h" + +namespace pv +{ +namespace dialogs +{ + +ApplicationParamDlg::ApplicationParamDlg() +{ + m_ret = false; +} + +ApplicationParamDlg::~ApplicationParamDlg() +{ +} + +bool ApplicationParamDlg::ShowDlg(QWidget *parent) +{ + DSDialog dlg(parent, true, true); + dlg.exec(); + return m_ret; +} + +//------------IDlgCallback +void ApplicationParamDlg::OnDlgResult(bool bYes){ + m_ret = bYes; + } + +} // +}// + diff --git a/DSView/pv/dialogs/applicationpardlg.h b/DSView/pv/dialogs/applicationpardlg.h new file mode 100644 index 00000000..71e35d51 --- /dev/null +++ b/DSView/pv/dialogs/applicationpardlg.h @@ -0,0 +1,52 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2015 DreamSourceLab + * + * 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 + */ + +#pragma once + +#include +#include +#include "../interface/uicallback.h" + +namespace pv +{ + namespace dialogs +{ + + class ApplicationParamDlg : private IDlgCallback + { + // Q_OBJECT + + public: + ApplicationParamDlg(); + ~ApplicationParamDlg(); + + bool ShowDlg(QWidget *parent); + + //IDlgCallback + private: + void OnDlgResult(bool bYes); + + private: + bool m_ret; + }; + +}// +}// diff --git a/DSView/pv/dialogs/deviceoptions.cpp b/DSView/pv/dialogs/deviceoptions.cpp index 8d5800dd..3ac73ad2 100755 --- a/DSView/pv/dialogs/deviceoptions.cpp +++ b/DSView/pv/dialogs/deviceoptions.cpp @@ -40,8 +40,7 @@ namespace dialogs { DeviceOptions::DeviceOptions(QWidget *parent, boost::shared_ptr dev_inst) : DSDialog(parent), _dev_inst(dev_inst), - _button_box(QDialogButtonBox::Ok, - Qt::Horizontal, this), + _button_box(QDialogButtonBox::Ok, Qt::Horizontal, this), _device_options_binding(_dev_inst->dev_inst()) { _props_box = new QGroupBox(tr("Mode"), this); diff --git a/DSView/pv/dialogs/dsdialog.cpp b/DSView/pv/dialogs/dsdialog.cpp index 359a4971..81165b3f 100755 --- a/DSView/pv/dialogs/dsdialog.cpp +++ b/DSView/pv/dialogs/dsdialog.cpp @@ -28,118 +28,121 @@ #include #include #include +#include "../dsvdef.h" namespace pv { namespace dialogs { -DSDialog::DSDialog(QWidget *parent, bool hasClose) : - QDialog(parent), - _moving(false) +DSDialog::DSDialog() : DSDialog(NULL, false, false) { +} + +DSDialog::DSDialog(QWidget *parent): DSDialog(parent, false, false) +{ +} + +DSDialog::DSDialog(QWidget *parent, bool hasClose): DSDialog(parent, hasClose, false) +{ +} + +DSDialog::DSDialog(QWidget *parent, bool hasClose, bool bBaseButton) : + QDialog(NULL), //must be null, otherwise window can not able to move + m_bBaseButton(bBaseButton) +{ + (void)parent; + + _base_layout = NULL; + _main_layout = NULL; + _main_widget = NULL; + _titlebar = NULL; + _shadow = NULL; + _base_button = NULL; + + m_callback = NULL; + setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint); setAttribute(Qt::WA_TranslucentBackground); - build_main(hasClose); + build_base(hasClose); +} - _layout = new QVBoxLayout(this); - _layout->addWidget(_main); - setLayout(_layout); +DSDialog::~DSDialog() +{ + DESTROY_QT_OBJECT(_base_layout); + DESTROY_QT_OBJECT(_main_layout); + DESTROY_QT_OBJECT(_main_widget); + DESTROY_QT_OBJECT(_titlebar); + DESTROY_QT_OBJECT(_shadow); + DESTROY_QT_OBJECT(_base_button); } void DSDialog::accept() { using namespace Qt; + if (m_callback){ + m_callback->OnDlgResult(true); + } + QDialog::accept(); } void DSDialog::reject() { using namespace Qt; + if (m_callback){ + m_callback->OnDlgResult(false); + } QDialog::reject(); } - -bool DSDialog::eventFilter(QObject *object, QEvent *event) -{ - (void)object; - const QEvent::Type type = event->type(); - const QMouseEvent *const mouse_event = (QMouseEvent*)event; - if (type == QEvent::MouseMove) { - if (_moving && mouse_event->buttons().testFlag(Qt::LeftButton)) { - move(mouse_event->globalPos() - _startPos); - } - return true; - } else if (type == QEvent::MouseButtonPress) { - if (mouse_event->buttons().testFlag(Qt::LeftButton)) { - _moving = true; -#ifndef _WIN32 - _startPos = mouse_event->pos() + - QPoint(_layout->margin(), _layout->margin()) + - QPoint(_layout->spacing(), _layout->spacing()) + - QPoint(_mlayout->margin(), _mlayout->margin()) + - QPoint(_mlayout->spacing(), _mlayout->spacing()); -#else - _startPos = mouse_event->pos() + - QPoint(_layout->margin(), _layout->margin()) + - QPoint(_layout->spacing(), _layout->spacing()); -#endif - } - } else if (type == QEvent::MouseButtonRelease) { - if (mouse_event->buttons().testFlag(Qt::LeftButton)) { - _moving = false; - } - } - return false; -} - -QVBoxLayout* DSDialog::layout() -{ - return _mlayout; -} - -QWidget* DSDialog::mainWidget() -{ - return _main; -} - + void DSDialog::setTitle(QString title) { - _titlebar->setTitle(title); + if (_titlebar){ + _titlebar->setTitle(title); + } } -void DSDialog::reload(bool hasClose) +void DSDialog::reload() { - QString title; - if (_titlebar) - title = _titlebar->title(); - if (_main) - delete _main; - - build_main(hasClose); - _titlebar->setTitle(title); - _layout->addWidget(_main); + show(); } -void DSDialog::build_main(bool hasClose) -{ - _main = new QWidget(this); - _mlayout = new QVBoxLayout(_main); - _main->setLayout(_mlayout); - //_mlayout->setMargin(5); - //_mlayout->setSpacing(5); +int DSDialog::exec() +{ + //ok,cancel + if (m_bBaseButton){ + _base_button = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel,Qt::Horizontal, this); + _main_layout->addWidget(_base_button);//, 5, 1, 1, 1, Qt::AlignHCenter | Qt::AlignBottom); + connect(_base_button, SIGNAL(rejected()), this, SLOT(reject())); + connect(_base_button, SIGNAL(accepted()), this, SLOT(accept())); + } + + return QDialog::exec(); +} - Shadow *bodyShadow = new Shadow(_main); - bodyShadow->setBlurRadius(10.0); - bodyShadow->setDistance(3.0); - bodyShadow->setColor(QColor(0, 0, 0, 80)); - _main->setAutoFillBackground(true); - _main->setGraphicsEffect(bodyShadow); +void DSDialog::build_base(bool hasClose) +{ + _main_widget = new QWidget(this); + _main_layout = new QVBoxLayout(_main_widget); _titlebar = new toolbars::TitleBar(false, this, hasClose); - _titlebar->installEventFilter(this); - _mlayout->addWidget(_titlebar); -} + _base_layout = new QVBoxLayout(this); + + _main_widget->setLayout(_main_layout); + _main_widget->setAutoFillBackground(true); + + _shadow = new Shadow(_main_widget); + _shadow->setBlurRadius(10.0); + _shadow->setDistance(3.0); + _shadow->setColor(QColor(0, 0, 0, 80)); + _main_widget->setGraphicsEffect(_shadow); + + _main_layout->addWidget(_titlebar); + _base_layout->addWidget(_main_widget); + setLayout(_base_layout); +} } // namespace dialogs } // namespace pv diff --git a/DSView/pv/dialogs/dsdialog.h b/DSView/pv/dialogs/dsdialog.h index cefc614d..22799aa2 100755 --- a/DSView/pv/dialogs/dsdialog.h +++ b/DSView/pv/dialogs/dsdialog.h @@ -26,40 +26,56 @@ #include #include #include +#include #include "../toolbars/titlebar.h" +#include "../interface/uicallback.h" +class QDialogButtonBox; + + namespace pv { namespace dialogs { + class Shadow; + +//DSView any dialog base class class DSDialog : public QDialog { Q_OBJECT public: - DSDialog(QWidget *parent = 0, bool hasClose = false); - QVBoxLayout *layout(); - QWidget *mainWidget(); + DSDialog(); + DSDialog(QWidget *parent); + DSDialog(QWidget *parent, bool hasClose); + DSDialog(QWidget *parent, bool hasClose, bool bBaseButton); + ~DSDialog(); + inline void SetCallback(IDlgCallback *callback){m_callback = callback;} + inline QVBoxLayout *layout(){return _main_layout;} void setTitle(QString title); - void reload(bool hasClose); + void reload(); + int exec(); protected: void accept(); void reject(); - //void mousePressEvent(QMouseEvent *event); - //void mouseReleaseEvent(QMouseEvent *event); - bool eventFilter(QObject *object, QEvent *event); -private: - void build_main(bool hasClose); private: - QVBoxLayout *_layout; - QVBoxLayout *_mlayout; - QWidget *_main; - toolbars::TitleBar *_titlebar; - bool _moving; - QPoint _startPos; + void build_base(bool hasClose); + +private: + QVBoxLayout *_base_layout; + QWidget *_main_widget; + QVBoxLayout *_main_layout; + toolbars::TitleBar *_titlebar; + Shadow *_shadow; + QDialogButtonBox *_base_button; + + QPoint _startPos; + bool m_bBaseButton; + + IDlgCallback *m_callback; }; } // namespace dialogs diff --git a/DSView/pv/dialogs/dsmessagebox.cpp b/DSView/pv/dialogs/dsmessagebox.cpp index 6a2a225d..eb8f8bbd 100755 --- a/DSView/pv/dialogs/dsmessagebox.cpp +++ b/DSView/pv/dialogs/dsmessagebox.cpp @@ -28,32 +28,42 @@ #include #include #include +#include "../dsvdef.h" namespace pv { namespace dialogs { DSMessageBox::DSMessageBox(QWidget *parent,const char *title) : - QDialog(parent), - _moving(false), - _clickType(0) + QDialog(NULL) //must be null, otherwise window can not able to move { + _layout = NULL; + _main_widget = NULL; + _msg = NULL; + _titlebar = NULL; + _shadow = NULL; + _main_layout = NULL; + + _bClickYes = false; + setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint); setAttribute(Qt::WA_TranslucentBackground); - _main = new QWidget(this); - QVBoxLayout *mlayout = new QVBoxLayout(_main); - _main->setLayout(mlayout); - Shadow *bodyShadow = new Shadow(); - bodyShadow->setBlurRadius(10.0); - bodyShadow->setDistance(3.0); - bodyShadow->setColor(QColor(0, 0, 0, 80)); - _main->setAutoFillBackground(true); - _main->setGraphicsEffect(bodyShadow); + _main_widget = new QWidget(this); + _main_layout = new QVBoxLayout(_main_widget); + _main_widget->setLayout(_main_layout); + _shadow = new Shadow(); _msg = new QMessageBox(this); - _msg->setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint); - _titlebar = new toolbars::TitleBar(false, this); + _layout = new QVBoxLayout(this); + + _shadow->setBlurRadius(10.0); + _shadow->setDistance(3.0); + _shadow->setColor(QColor(0, 0, 0, 80)); + + _main_widget->setAutoFillBackground(true); + _main_widget->setGraphicsEffect(_shadow); + _msg->setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint); if (title){ _titlebar->setTitle(QString(title)); @@ -61,20 +71,27 @@ DSMessageBox::DSMessageBox(QWidget *parent,const char *title) : else{ _titlebar->setTitle(tr("Message")); } - - _titlebar->installEventFilter(this); + + _main_layout->addWidget(_titlebar); + _main_layout->addWidget(_msg); + _layout->addWidget(_main_widget); - mlayout->addWidget(_titlebar); - mlayout->addWidget(_msg); - - _layout = new QVBoxLayout(this); - _layout->addWidget(_main); setLayout(_layout); - //connect(_msg, SIGNAL(finished(int)), this, SLOT(accept())); connect(_msg, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(on_button(QAbstractButton*))); } + +DSMessageBox::~DSMessageBox() +{ + DESTROY_QT_OBJECT(_layout); + DESTROY_QT_OBJECT(_main_widget); + DESTROY_QT_OBJECT(_msg); + DESTROY_QT_OBJECT(_titlebar); + DESTROY_QT_OBJECT(_shadow); + DESTROY_QT_OBJECT(_main_layout); +} + void DSMessageBox::accept() { using namespace Qt; @@ -88,50 +105,20 @@ void DSMessageBox::reject() QDialog::reject(); } - -bool DSMessageBox::eventFilter(QObject *object, QEvent *event) -{ - (void)object; - const QEvent::Type type = event->type(); - const QMouseEvent *const mouse_event = (QMouseEvent*)event; - if (type == QEvent::MouseMove) { - if (_moving && mouse_event->buttons().testFlag(Qt::LeftButton)) { - move(mouse_event->globalPos() - _startPos); - } - return true; - } else if (type == QEvent::MouseButtonPress) { - if (mouse_event->buttons().testFlag(Qt::LeftButton)) { - _moving = true; - _startPos = mouse_event->pos() + - QPoint(_layout->margin(), _layout->margin()) + - QPoint(_layout->spacing(), _layout->spacing()); - } - } else if (type == QEvent::MouseButtonRelease) { - if (mouse_event->buttons().testFlag(Qt::LeftButton)) { - _moving = false; - } - } - return false; -} - + QMessageBox* DSMessageBox::mBox() { return _msg; } - -int DSMessageBox::exec() -{ - //_msg->show(); - return QDialog::exec(); -} - + void DSMessageBox::on_button(QAbstractButton *btn) { QMessageBox::ButtonRole role = _msg->buttonRole(btn); - _clickType = (int)role; - - if (role == QMessageBox::AcceptRole) - accept(); + + if (role == QMessageBox::AcceptRole || role == QMessageBox::YesRole){ + _bClickYes = true; + accept(); + } else reject(); } diff --git a/DSView/pv/dialogs/dsmessagebox.h b/DSView/pv/dialogs/dsmessagebox.h index fa6a8dfb..7b2a1038 100755 --- a/DSView/pv/dialogs/dsmessagebox.h +++ b/DSView/pv/dialogs/dsmessagebox.h @@ -33,6 +33,8 @@ namespace pv { namespace dialogs { + class Shadow; + class DSMessageBox : public QDialog { Q_OBJECT @@ -40,30 +42,29 @@ class DSMessageBox : public QDialog public: DSMessageBox(QWidget *parent, const char *title=0); - QMessageBox *mBox(); + ~DSMessageBox(); - int exec(); + QMessageBox *mBox(); - inline int GetLastClick(){return _clickType;} + inline int IsYes(){return _bClickYes;} protected: void accept(); - void reject(); - //void mousePressEvent(QMouseEvent *event); - //void mouseReleaseEvent(QMouseEvent *event); - bool eventFilter(QObject *object, QEvent *event); + void reject(); private slots: void on_button(QAbstractButton* btn); private: - QVBoxLayout *_layout; - QWidget *_main; - QMessageBox *_msg; - toolbars::TitleBar *_titlebar; - bool _moving; - QPoint _startPos; - int _clickType; + QVBoxLayout *_layout; + QVBoxLayout *_main_layout; + QWidget *_main_widget; + QMessageBox *_msg; + toolbars::TitleBar *_titlebar; + Shadow *_shadow; + + QPoint _startPos; + bool _bClickYes; }; } // namespace dialogs diff --git a/DSView/pv/dock/protocoldock.cpp b/DSView/pv/dock/protocoldock.cpp index a811218e..9098ca94 100755 --- a/DSView/pv/dock/protocoldock.cpp +++ b/DSView/pv/dock/protocoldock.cpp @@ -210,10 +210,10 @@ ProtocolDock::ProtocolDock(QWidget *parent, view::View &view, SigSession &sessio ProtocolDock::~ProtocolDock() { //destroy protocol item layers - for (auto it = _protocolItems.begin(); it != _protocolItems.end(); it++){ - delete (*it); + for (auto it = _protocol_items.begin(); it != _protocol_items.end(); it++){ + DESTROY_QT_LATER(*it); } - _protocolItems.clear(); + _protocol_items.clear(); } void ProtocolDock::changeEvent(QEvent *event) @@ -245,7 +245,7 @@ void ProtocolDock::reStyle() _nxt_button->setIcon(QIcon(iconPath+"/next.svg")); _search_button->setIcon(QIcon(iconPath+"/search.svg")); - for (auto it = _protocolItems.begin(); it != _protocolItems.end(); it++){ + for (auto it = _protocol_items.begin(); it != _protocol_items.end(); it++){ (*it)->ResetStyle(); } } @@ -321,8 +321,8 @@ void ProtocolDock::add_protocol(bool silent) //crate item layer QString protocolName = _protocol_combobox->currentText(); ProtocolItemLayer *layer = new ProtocolItemLayer(_up_widget, protocolName, this); - _protocolItems.push_back(layer); - _up_layout->insertLayout(_protocolItems.size(), layer); + _protocol_items.push_back(layer); + _up_layout->insertLayout(_protocol_items.size(), layer); layer->m_decoderStatus = dstatus; //set current protocol format @@ -342,7 +342,7 @@ void ProtocolDock::add_protocol(bool silent) } void ProtocolDock::on_del_all_protocol(){ - if (_protocolItems.size() == 0){ + if (_protocol_items.size() == 0){ MsgBox::Show(NULL, "No Protocol Analyzer to delete!", this); return; } @@ -355,15 +355,14 @@ void ProtocolDock::add_protocol(bool silent) void ProtocolDock::del_all_protocol() { - if (_protocolItems.size() > 0) + if (_protocol_items.size() > 0) { - for (auto it = _protocolItems.begin(); it != _protocolItems.end(); it++) + for (auto it = _protocol_items.begin(); it != _protocol_items.end(); it++) { - _up_layout->removeItem((*it)); - delete (*it); //destory control + DESTROY_QT_LATER((*it)); //destory control _session.remove_decode_signal(0); } - _protocolItems.clear(); + _protocol_items.clear(); protocol_updated(); } } @@ -383,9 +382,9 @@ void ProtocolDock::decoded_progress(int progress) if (d->decoder()->out_of_memory()) err = tr("(Out of Memory)"); - if (index < _protocolItems.size()) + if (index < _protocol_items.size()) { - ProtocolItemLayer &lay = *(_protocolItems.at(index)); + ProtocolItemLayer &lay = *(_protocol_items.at(index)); lay.SetProgress(pg, err); //when decode complete, check data format @@ -745,7 +744,7 @@ void ProtocolDock::search_update() //-------------------IProtocolItemLayerCallback void ProtocolDock::OnProtocolSetting(void *handle){ int dex = 0; - for (auto it = _protocolItems.begin(); it != _protocolItems.end(); it++){ + for (auto it = _protocol_items.begin(); it != _protocol_items.end(); it++){ if ((*it) == handle){ _session.rst_decoder(dex); protocol_updated(); @@ -761,13 +760,12 @@ void ProtocolDock::OnProtocolDelete(void *handle){ } int dex = 0; - for (auto it = _protocolItems.begin(); it != _protocolItems.end(); it++){ + for (auto it = _protocol_items.begin(); it != _protocol_items.end(); it++){ if ((*it) == handle){ - delete (*it); - _up_layout->removeItem((*it)); //remove child control - _protocolItems.remove(dex); + DESTROY_QT_LATER(*it); + _protocol_items.remove(dex); _session.remove_decode_signal(dex); - protocol_updated(); + protocol_updated(); break; } dex++; @@ -775,7 +773,7 @@ void ProtocolDock::OnProtocolDelete(void *handle){ } void ProtocolDock::OnProtocolFormatChanged(QString format, void *handle){ - for (auto it = _protocolItems.begin(); it != _protocolItems.end(); it++){ + for (auto it = _protocol_items.begin(); it != _protocol_items.end(); it++){ if ((*it) == handle){ QString &name = (*it)->GetProtocolName(); AppConfig::Instance().SetProtocolFormat(name.toStdString(), format.toStdString()); diff --git a/DSView/pv/dock/protocoldock.h b/DSView/pv/dock/protocoldock.h index d0d35af8..8b7a1a39 100755 --- a/DSView/pv/dock/protocoldock.h +++ b/DSView/pv/dock/protocoldock.h @@ -133,7 +133,7 @@ private: QComboBox *_protocol_combobox; QVector _protocol_index_list; QVBoxLayout *_up_layout; - QVector _protocolItems; //protocol item layers + QVector _protocol_items; //protocol item layers QPushButton *_dn_set_button; QPushButton *_dn_save_button; diff --git a/DSView/pv/dock/protocolitemlayer.cpp b/DSView/pv/dock/protocolitemlayer.cpp index 1a0996e1..5a51dce1 100644 --- a/DSView/pv/dock/protocolitemlayer.cpp +++ b/DSView/pv/dock/protocolitemlayer.cpp @@ -22,11 +22,11 @@ #include "protocolitemlayer.h" #include "../dsvdef.h" #include -#include +#include namespace pv { namespace dock { - + ProtocolItemLayer::ProtocolItemLayer(QWidget *parent, QString protocolName, IProtocolItemLayerCallback *callback){ assert(parent); assert(callback); @@ -58,7 +58,7 @@ ProtocolItemLayer::ProtocolItemLayer(QWidget *parent, QString protocolName, IPro hori_layout->addWidget(_del_button); hori_layout->addWidget(_format_combox); hori_layout->addWidget(_protocol_label); - hori_layout->addWidget(_progress_label); + hori_layout->addWidget(_progress_label); hori_layout->addStretch(1); @@ -69,13 +69,14 @@ ProtocolItemLayer::ProtocolItemLayer(QWidget *parent, QString protocolName, IPro connect(_format_combox, SIGNAL(currentIndexChanged(int)),this, SLOT(on_format_select_changed(int))); } -ProtocolItemLayer::~ProtocolItemLayer(){ - DESTROY_OBJECT(_set_button); - DESTROY_OBJECT(_del_button); - DESTROY_OBJECT(_protocol_label); - DESTROY_OBJECT(_progress_label); - DESTROY_OBJECT(_format_combox); +ProtocolItemLayer::~ProtocolItemLayer(){ + DESTROY_QT_OBJECT(_progress_label); + DESTROY_QT_OBJECT(_protocol_label); + DESTROY_QT_OBJECT(_set_button); + DESTROY_QT_OBJECT(_del_button); + DESTROY_QT_OBJECT(_format_combox); } + //-------------control event void ProtocolItemLayer::on_set_protocol() diff --git a/DSView/pv/dock/protocolitemlayer.h b/DSView/pv/dock/protocolitemlayer.h index 9f4c8b62..45901ef4 100644 --- a/DSView/pv/dock/protocolitemlayer.h +++ b/DSView/pv/dock/protocolitemlayer.h @@ -54,7 +54,7 @@ public: void LoadFormatSelect(bool bSingle); inline QString &GetProtocolName(){return _protocolName;} void SetProtocolFormat(const char *format); - + private slots: void on_set_protocol(); void on_del_protocol(); diff --git a/DSView/pv/dsvdef.cpp b/DSView/pv/dsvdef.cpp index c6478b51..e5203dbe 100644 --- a/DSView/pv/dsvdef.cpp +++ b/DSView/pv/dsvdef.cpp @@ -44,3 +44,24 @@ namespace DecoderDataFormat return (int)ascii; } } + + +namespace app +{ + QWidget* get_app_window_instance(QWidget *ins, bool bSet){ + + static QWidget *g_ins = NULL; + if (bSet){ + g_ins = ins; + } + return g_ins; + } + + bool is_app_top_window(QWidget* w){ + QWidget *top =get_app_window_instance(NULL, NULL); + if (top && top == w){ + return true; + } + return false; + } +} diff --git a/DSView/pv/dsvdef.h b/DSView/pv/dsvdef.h index 2647f613..c35a7de0 100644 --- a/DSView/pv/dsvdef.h +++ b/DSView/pv/dsvdef.h @@ -21,8 +21,12 @@ */ #pragma once - -#define DESTROY_OBJECT(p) if ((p)){delete (p); p = NULL;} + +class QWidget; + +#define DESTROY_OBJECT(p) if((p)){delete (p); p = NULL;} +#define DESTROY_QT_OBJECT(p) if((p)){((p))->deleteLater(); p = NULL;} +#define DESTROY_QT_LATER(p) ((p))->deleteLater(); namespace DecoderDataFormat { @@ -37,3 +41,10 @@ namespace DecoderDataFormat int Parse(const char *name); } + +namespace app +{ + QWidget* get_app_window_instance(QWidget *ins, bool bSet); + + bool is_app_top_window(QWidget* w); +} diff --git a/DSView/pv/interface/uicallback.h b/DSView/pv/interface/uicallback.h new file mode 100644 index 00000000..8af7964b --- /dev/null +++ b/DSView/pv/interface/uicallback.h @@ -0,0 +1,8 @@ + +#pragma once + +class IDlgCallback +{ +public: + virtual void OnDlgResult(bool bYes)=0; +}; diff --git a/DSView/pv/mainframe.cpp b/DSView/pv/mainframe.cpp index 714de50b..50759235 100755 --- a/DSView/pv/mainframe.cpp +++ b/DSView/pv/mainframe.cpp @@ -42,6 +42,7 @@ #include #include #include +#include "dsvdef.h" #include @@ -68,15 +69,15 @@ MainFrame::MainFrame(DeviceManager &device_manager, QSize(), QIcon::Normal, QIcon::Off); setWindowIcon(icon); - _moving = false; - _draging = false; - _startPos = None; + app::get_app_window_instance(this, true); + + _bDraging = false; + _hit_border = None; _freezing = false; _minimized = false; // Title _titleBar = new toolbars::TitleBar(true, this); - _titleBar->installEventFilter(this); // MainWindow _mainWindow = new MainWindow(device_manager, open_file_name, this); @@ -223,41 +224,55 @@ bool MainFrame::eventFilter(QObject *object, QEvent *event) int newLeft; int newTop; - if (type == QEvent::MouseMove && !isMaximized()) { - if (!(mouse_event->buttons() || Qt::NoButton)) { - if (object == _top_left) { - _startPos = TopLeft; + if (type != QEvent::MouseMove + && type != QEvent::MouseButtonPress + && type != QEvent::MouseButtonRelease + && type != QEvent::Leave){ + return QFrame::eventFilter(object, event); + } + + //when window is maximized, or is moving, call return + if (isMaximized() || _titleBar->IsMoving()){ + return QFrame::eventFilter(object, event); + } + + if (!_bDraging && type == QEvent::MouseMove && (!(mouse_event->buttons() || Qt::NoButton))){ + if (object == _top_left) { + _hit_border = TopLeft; setCursor(Qt::SizeFDiagCursor); } else if (object == _bottom_right) { - _startPos = BottomRight; + _hit_border = BottomRight; setCursor(Qt::SizeFDiagCursor); } else if (object == _top_right) { - _startPos = TopRight; + _hit_border = TopRight; setCursor(Qt::SizeBDiagCursor); } else if (object == _bottom_left) { - _startPos = BottomLeft; + _hit_border = BottomLeft; setCursor(Qt::SizeBDiagCursor); } else if (object == _left) { - _startPos = Left; + _hit_border = Left; setCursor(Qt::SizeHorCursor); } else if (object == _right) { - _startPos = Right; + _hit_border = Right; setCursor(Qt::SizeHorCursor); } else if (object == _bottom) { - _startPos = Bottom; + _hit_border = Bottom; setCursor(Qt::SizeVerCursor); } else if (object == _top) { - _startPos = Top; + _hit_border = Top; setCursor(Qt::SizeVerCursor); } else { - _startPos = None; + _hit_border = None; setCursor(Qt::ArrowCursor); } - } else if(mouse_event->buttons().testFlag(Qt::LeftButton)) { - if (_moving) { - this->move(mouse_event->globalPos() - _lastMousePosition); - } else if (!_freezing) { - switch (_startPos) { + + return QFrame::eventFilter(object, event); + } + + if (type == QEvent::MouseMove) { + if(mouse_event->buttons().testFlag(Qt::LeftButton)) { + if (!_freezing) { + switch (_hit_border) { case TopLeft: newWidth = std::max(_dragStartGeometry.right() - mouse_event->globalX(), minimumWidth()); newHeight = std::max(_dragStartGeometry.bottom() - mouse_event->globalY(), minimumHeight()); @@ -325,31 +340,27 @@ bool MainFrame::eventFilter(QObject *object, QEvent *event) } return true; } - } else if (type == QEvent::MouseButtonPress) { - if (mouse_event->button() == Qt::LeftButton) - if (_titleBar->rect().contains(mouse_event->pos()) && - _startPos == None) { - _moving = true; - _lastMousePosition = mouse_event->pos() + - //QPoint(Margin, Margin) + - QPoint(geometry().left() - frameGeometry().left(), frameGeometry().right() - geometry().right()); - } - if (_startPos != None) - _draging = true; + } + else if (type == QEvent::MouseButtonPress) { + if (mouse_event->button() == Qt::LeftButton) + if (_hit_border != None) + _bDraging = true; _timer.start(50); _dragStartGeometry = geometry(); - } else if (type == QEvent::MouseButtonRelease) { + } + else if (type == QEvent::MouseButtonRelease) { if (mouse_event->button() == Qt::LeftButton) { - _moving = false; - _draging = false; + + _bDraging = false; _timer.stop(); } - } else if (!_draging && type == QEvent::Leave) { - _startPos = None; + } else if (!_bDraging && type == QEvent::Leave) { + _hit_border = None; setCursor(Qt::ArrowCursor); - } - - return QObject::eventFilter(object, event); + } + + + return QFrame::eventFilter(object, event); } void MainFrame::writeSettings() @@ -406,7 +417,7 @@ void MainFrame::show_doc() const QString DOC_KEY("ShowDocuments"); QSettings settings(QApplication::organizationName(), QApplication::applicationName()); if (!settings.contains(DOC_KEY)) { - dialogs::DSDialog dlg(this); + dialogs::DSDialog dlg(this, true); dlg.setTitle(tr("Document")); QLabel tipsLabel; diff --git a/DSView/pv/mainframe.h b/DSView/pv/mainframe.h index 615dd3f1..7e6711ce 100755 --- a/DSView/pv/mainframe.h +++ b/DSView/pv/mainframe.h @@ -104,15 +104,13 @@ private: widgets::Border *_top_right; widgets::Border *_bottom_left; widgets::Border *_bottom_right; - - bool _moving; - bool _draging; - QPoint _lastMousePosition; - QRect _dragStartGeometry; - int _startPos; - QTimer _timer; - bool _freezing; - bool _minimized; + + bool _bDraging; + QRect _dragStartGeometry; + int _hit_border; + QTimer _timer; + bool _freezing; + bool _minimized; }; } // namespace pv diff --git a/DSView/pv/toolbars/filebar.cpp b/DSView/pv/toolbars/filebar.cpp index a61939e6..5efbca7f 100755 --- a/DSView/pv/toolbars/filebar.cpp +++ b/DSView/pv/toolbars/filebar.cpp @@ -28,8 +28,8 @@ #include #include "filebar.h" -#include "../device/devinst.h" -#include "../dialogs/dsmessagebox.h" +#include "../device/devinst.h" +#include "../ui/msgbox.h" #include @@ -107,7 +107,7 @@ void FileBar::changeEvent(QEvent *event) void FileBar::retranslateUi() { _file_button.setText(tr("File")); - _menu_session->setTitle(tr("Settings")); + _menu_session->setTitle(tr("Con&fig...")); _action_load->setText(tr("&Load...")); _action_store->setText(tr("S&tore...")); _action_default->setText(tr("&Default...")); @@ -157,13 +157,8 @@ void FileBar::session_error( void FileBar::show_session_error( const QString text, const QString info_text) -{ - dialogs::DSMessageBox msg(this); - msg.mBox()->setText(text); - msg.mBox()->setInformativeText(info_text); - msg.mBox()->setStandardButtons(QMessageBox::Ok); - msg.mBox()->setIcon(QMessageBox::Warning); - msg.exec(); +{ + MsgBox::Show(NULL, info_text.toStdString().c_str(), this); } void FileBar::on_actionLoad_triggered() @@ -189,14 +184,9 @@ void FileBar::on_actionDefault_triggered() QDir dir(QCoreApplication::applicationDirPath()); assert(dir.cd("res")); #endif - if (!dir.exists()) { - dialogs::DSMessageBox msg(this); - msg.mBox()->setText(tr("Session Load")); - msg.mBox()->setInformativeText(tr("Cannot find default session file for this device!")); - msg.mBox()->setStandardButtons(QMessageBox::Ok); - msg.mBox()->setIcon(QMessageBox::Warning); - msg.exec(); - return; + if (!dir.exists()) { + MsgBox::Show(NULL, "Cannot find default session file for this device!", this); + return; } QString driver_name = _session.get_device()->name(); diff --git a/DSView/pv/toolbars/titlebar.cpp b/DSView/pv/toolbars/titlebar.cpp index dffb4bc4..fa2a6310 100755 --- a/DSView/pv/toolbars/titlebar.cpp +++ b/DSView/pv/toolbars/titlebar.cpp @@ -30,24 +30,35 @@ #include #include #include +#include +#include "../dsvdef.h" namespace pv { namespace toolbars { TitleBar::TitleBar(bool top, QWidget *parent, bool hasClose) : QWidget(parent), + _parent(parent), _moving(false), _isTop(top), _hasClose(hasClose) { + _title = NULL; + _minimizeButton = NULL; + _maximizeButton = NULL; + _closeButton = NULL; + _lay = NULL; + + assert(parent); + setObjectName("TitleBar"); setContentsMargins(0,0,0,0); setFixedHeight(32); _title = new QLabel(this); - QHBoxLayout *hbox = new QHBoxLayout(this); - hbox->addWidget(_title); + _lay = new QHBoxLayout(this); + _lay->addWidget(_title); if (_isTop) { _minimizeButton = new QToolButton(this); @@ -55,8 +66,8 @@ TitleBar::TitleBar(bool top, QWidget *parent, bool hasClose) : _maximizeButton = new QToolButton(this); _maximizeButton->setObjectName("MaximizeButton"); - hbox->addWidget(_minimizeButton); - hbox->addWidget(_maximizeButton); + _lay->addWidget(_minimizeButton); + _lay->addWidget(_maximizeButton); connect(this, SIGNAL( normalShow() ), parent, SLOT(showNormal() ) ); connect(this, SIGNAL( maximizedShow() ), parent, SLOT(showMaximized() ) ); @@ -67,17 +78,26 @@ TitleBar::TitleBar(bool top, QWidget *parent, bool hasClose) : if (_isTop || _hasClose) { _closeButton= new QToolButton(this); _closeButton->setObjectName("CloseButton"); - hbox->addWidget(_closeButton); + _lay->addWidget(_closeButton); connect(_closeButton, SIGNAL( clicked() ), parent, SLOT(close() ) ); } - hbox->insertStretch(0, 500); - hbox->insertStretch(2, 500); - hbox->setMargin(0); - hbox->setSpacing(0); + _lay->insertStretch(0, 500); + _lay->insertStretch(2, 500); + _lay->setMargin(0); + _lay->setSpacing(0); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); } +TitleBar::~TitleBar(){ + DESTROY_QT_OBJECT(_title); + DESTROY_QT_OBJECT(_minimizeButton); + DESTROY_QT_OBJECT(_maximizeButton); + DESTROY_QT_OBJECT(_closeButton); + DESTROY_QT_OBJECT(_lay); +} + void TitleBar::changeEvent(QEvent *event) { if (event->type() == QEvent::StyleChange) @@ -101,7 +121,8 @@ void TitleBar::reStyle() } void TitleBar::paintEvent(QPaintEvent *event) -{ +{ + //draw logo icon QStyleOption o; o.initFrom(this); QPainter p(this); @@ -109,7 +130,6 @@ void TitleBar::paintEvent(QPaintEvent *event) p.setRenderHint(QPainter::Antialiasing, true); - //To draw product logo const int xgap = 2; const int xstart = 10; p.setPen(QPen(QColor(213, 15, 37, 255), 2, Qt::SolidLine)); @@ -139,12 +159,7 @@ void TitleBar::setTitle(QString title) { _title->setText(title); } - -QPoint TitleBar::get_startPos() const -{ - return _startPos; -} - + QString TitleBar::title() const { return _title->text(); @@ -171,35 +186,49 @@ void TitleBar::setRestoreButton(bool max) _maximizeButton->setIcon(QIcon(iconPath+"/restore.svg")); } } - + void TitleBar::mousePressEvent(QMouseEvent* event) -{ +{ if(event->button() == Qt::LeftButton && !parentWidget()->isMaximized()) { - _moving = true; - _startPos = mapToParent(event->pos()); - } + int x = event->pos().x(); + int y = event->pos().y(); + bool bTopWidow = app::is_app_top_window(_parent); + bool bClick = (x >= 6 && y >= 5 && x <= width() - 6); //top window need resize hit check + + if (!bTopWidow || bClick ){ + _moving = true; + _startPos = event->globalPos() - _parent->frameGeometry().topLeft(); + event->accept(); + return; + } + } + QWidget::mousePressEvent(event); } void TitleBar::mouseMoveEvent(QMouseEvent *event) -{ - if(_moving && event->buttons().testFlag(Qt::LeftButton)) { - parentWidget()->move(event->globalPos() - _startPos); - } +{ + if(_moving){ + _parent->move(event->globalPos() - _startPos); + event->accept(); + return; + } + QWidget::mouseMoveEvent(event); } void TitleBar::mouseReleaseEvent(QMouseEvent* event) { - if(event->button() == Qt::LeftButton) { - _moving = false; - } + _moving = false; + QWidget::mouseReleaseEvent(event); } void TitleBar::mouseDoubleClickEvent(QMouseEvent *event) { - if (_isTop) - showMaxRestore(); + if (_isTop){ + showMaxRestore(); + } QWidget::mouseDoubleClickEvent(event); } + } // namespace toolbars } // namespace pv diff --git a/DSView/pv/toolbars/titlebar.h b/DSView/pv/toolbars/titlebar.h index 5463af2f..a216485b 100755 --- a/DSView/pv/toolbars/titlebar.h +++ b/DSView/pv/toolbars/titlebar.h @@ -25,56 +25,56 @@ #include class QLabel; class QToolButton; +class QHBoxLayout; -namespace pv +namespace pv { +namespace toolbars { + +class TitleBar : public QWidget { - namespace toolbars - { + Q_OBJECT -//Window's titlebar, referenced by MainFrame, -//The title area above the main screen, -//Display logo and maximize \ minimize button - class TitleBar : public QWidget - { - Q_OBJECT +public: + TitleBar(bool top, QWidget *parent, bool hasClose = false); + ~TitleBar(); + + void setTitle(QString title); + QString title() const; - public: - TitleBar(bool top, QWidget *parent, bool hasClose = false); - void setTitle(QString title); - QPoint get_startPos() const; - QString title() const; +private: + void changeEvent(QEvent *event); + void reStyle(); - private: - void changeEvent(QEvent *event); - void reStyle(); +signals: + void normalShow(); + void maximizedShow(); - signals: - void normalShow(); - void maximizedShow(); +public slots: + void showMaxRestore(); + void setRestoreButton(bool max); + inline bool IsMoving(){return _moving;} - public slots: - void showMaxRestore(); - void setRestoreButton(bool max); +protected: + void paintEvent(QPaintEvent *event); + void mousePressEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void mouseDoubleClickEvent(QMouseEvent *event); + + QLabel *_title; + QToolButton *_minimizeButton; + QToolButton *_maximizeButton; + QToolButton *_closeButton; + QHBoxLayout *_lay; - protected: - void paintEvent(QPaintEvent *event); - void mousePressEvent(QMouseEvent *event); - void mouseMoveEvent(QMouseEvent *event); - void mouseReleaseEvent(QMouseEvent *event); - void mouseDoubleClickEvent(QMouseEvent *event); + bool _moving; + bool _isTop; + bool _hasClose; + QPoint _startPos; + QWidget *_parent; +}; - QLabel *_title; - QToolButton *_minimizeButton; - QToolButton *_maximizeButton; - QToolButton *_closeButton; - - bool _moving; - bool _isTop; - bool _hasClose; - QPoint _startPos; - }; - - } // namespace toolbars +} // namespace toolbars } // namespace pv #endif // DSVIEW_PV_TOOLBARS_TITLEBAR_H diff --git a/DSView/pv/toolbars/trigbar.cpp b/DSView/pv/toolbars/trigbar.cpp index c4344027..d63d857b 100755 --- a/DSView/pv/toolbars/trigbar.cpp +++ b/DSView/pv/toolbars/trigbar.cpp @@ -30,6 +30,7 @@ #include #include #include +#include "../dialogs/applicationpardlg.h" namespace pv { namespace toolbars { @@ -50,16 +51,7 @@ TrigBar::TrigBar(SigSession &session, QWidget *parent) : { setMovable(false); setContentsMargins(0,0,0,0); - - connect(&_trig_button, SIGNAL(clicked()), - this, SLOT(trigger_clicked())); - connect(&_protocol_button, SIGNAL(clicked()), - this, SLOT(protocol_clicked())); - connect(&_measure_button, SIGNAL(clicked()), - this, SLOT(measure_clicked())); - connect(&_search_button, SIGNAL(clicked()), - this, SLOT(search_clicked())); - + _trig_button.setCheckable(true); #ifdef ENABLE_DECODE _protocol_button.setCheckable(true); @@ -69,12 +61,10 @@ TrigBar::TrigBar(SigSession &session, QWidget *parent) : _action_fft = new QAction(this); _action_fft->setObjectName(QString::fromUtf8("actionFft")); - connect(_action_fft, SIGNAL(triggered()), this, SLOT(on_actionFft_triggered())); - + _action_math = new QAction(this); _action_math->setObjectName(QString::fromUtf8("actionMath")); - connect(_action_math, SIGNAL(triggered()), this, SLOT(on_actionMath_triggered())); - + _function_menu = new QMenu(this); _function_menu->setContentsMargins(0,0,0,0); _function_menu->addAction(_action_fft); @@ -84,25 +74,27 @@ TrigBar::TrigBar(SigSession &session, QWidget *parent) : _action_lissajous = new QAction(this); _action_lissajous->setObjectName(QString::fromUtf8("actionLissajous")); - connect(_action_lissajous, SIGNAL(triggered()), this, SLOT(on_actionLissajous_triggered())); - + _dark_style = new QAction(this); _dark_style->setObjectName(QString::fromUtf8("actionDark")); - connect(_dark_style, SIGNAL(triggered()), this, SLOT(on_actionDark_triggered())); - + _light_style = new QAction(this); _light_style->setObjectName(QString::fromUtf8("actionLight")); - connect(_light_style, SIGNAL(triggered()), this, SLOT(on_actionLight_triggered())); - + _themes = new QMenu(this); _themes->setObjectName(QString::fromUtf8("menuThemes")); _themes->addAction(_light_style); _themes->addAction(_dark_style); + _appParam_action = new QAction(this); + _display_menu = new QMenu(this); _display_menu->setContentsMargins(0,0,0,0); + + _display_menu->addAction(_appParam_action); + _display_menu->addAction(_action_lissajous); _display_menu->addMenu(_themes); - _display_menu->addAction(_action_lissajous); + _display_button.setPopupMode(QToolButton::InstantPopup); _display_button.setMenu(_display_menu); @@ -119,10 +111,22 @@ TrigBar::TrigBar(SigSession &session, QWidget *parent) : _protocol_action = addWidget(&_protocol_button); _measure_action = addWidget(&_measure_button); _search_action = addWidget(&_search_button); - _function_action = addWidget(&_function_button); - _display_action = addWidget(&_display_button); - + _function_action = addWidget(&_function_button); + _display_action = addWidget(&_display_button); //must be created + retranslateUi(); + + connect(&_trig_button, SIGNAL(clicked()),this, SLOT(trigger_clicked())); + connect(&_protocol_button, SIGNAL(clicked()),this, SLOT(protocol_clicked())); + connect(&_measure_button, SIGNAL(clicked()),this, SLOT(measure_clicked())); + connect(&_search_button, SIGNAL(clicked()), this, SLOT(search_clicked())); + + connect(_action_fft, SIGNAL(triggered()), this, SLOT(on_actionFft_triggered())); + connect(_action_math, SIGNAL(triggered()), this, SLOT(on_actionMath_triggered())); + connect(_action_lissajous, SIGNAL(triggered()), this, SLOT(on_actionLissajous_triggered())); + connect(_dark_style, SIGNAL(triggered()), this, SLOT(on_actionDark_triggered())); + connect(_light_style, SIGNAL(triggered()), this, SLOT(on_actionLight_triggered())); + connect(_appParam_action, SIGNAL(triggered()), this, SLOT(on_application_param())); } void TrigBar::changeEvent(QEvent *event) @@ -141,14 +145,18 @@ void TrigBar::retranslateUi() _measure_button.setText(tr("Measure")); _search_button.setText(tr("Search")); _function_button.setText(tr("Function")); - _display_button.setText(tr("Display")); + _display_button.setText(tr("Setting")); + + _action_lissajous->setText(tr("&Lissajous")); + _themes->setTitle(tr("Themes")); _dark_style->setText(tr("Dark")); _light_style->setText(tr("Light")); - _action_lissajous->setText(tr("&Lissajous")); _action_fft->setText(tr("FFT")); _action_math->setText(tr("Math")); + + _appParam_action->setText(tr("Application")); } void TrigBar::reStyle() @@ -167,6 +175,9 @@ void TrigBar::reStyle() _action_lissajous->setIcon(QIcon(iconPath+"/lissajous.svg")); _dark_style->setIcon(QIcon(iconPath+"/dark.svg")); _light_style->setIcon(QIcon(iconPath+"/light.svg")); + + _appParam_action->setIcon(QIcon(iconPath+"/params.svg")); + _themes->setIcon(QIcon(iconPath+"/"+qApp->property("Style").toString()+".svg")); } @@ -304,5 +315,13 @@ void TrigBar::on_actionLissajous_triggered() lissajous_dlg.exec(); } + void TrigBar::on_application_param(){ + pv::dialogs::MathOptions math_dlg(_session, this); + math_dlg.exec(); + return; + pv::dialogs::ApplicationParamDlg dlg; + dlg.ShowDlg(this); + } + } // namespace toolbars } // namespace pv diff --git a/DSView/pv/toolbars/trigbar.h b/DSView/pv/toolbars/trigbar.h index fbddf0e0..c98e5366 100755 --- a/DSView/pv/toolbars/trigbar.h +++ b/DSView/pv/toolbars/trigbar.h @@ -83,6 +83,7 @@ public slots: void on_actionFft_triggered(); void on_actionMath_triggered(); + void on_application_param(); private: SigSession& _session; @@ -97,7 +98,7 @@ private: QAction* _protocol_action; QAction* _measure_action; QAction* _search_action; - QAction* _function_action; + QAction* _function_action; QAction* _display_action; QMenu* _function_menu; @@ -106,6 +107,7 @@ private: QMenu* _display_menu; QMenu *_themes; + QAction *_appParam_action; QAction *_dark_style; QAction *_light_style; QAction* _action_lissajous; diff --git a/DSView/pv/ui/msgbox.cpp b/DSView/pv/ui/msgbox.cpp index 4c9a6357..88b415db 100644 --- a/DSView/pv/ui/msgbox.cpp +++ b/DSView/pv/ui/msgbox.cpp @@ -51,6 +51,5 @@ bool MsgBox::Confirm(const char *text, QWidget *parent) msg.mBox()->setStandardButtons(QMessageBox::Yes | QMessageBox::No); msg.mBox()->setIcon(QMessageBox::Question); msg.exec(); - int click = msg.GetLastClick(); - return (click == (int)QMessageBox::YesRole); + return msg.IsYes(); } diff --git a/DSView/pv/view/decodetrace.cpp b/DSView/pv/view/decodetrace.cpp index e44f1dce..97e99f92 100755 --- a/DSView/pv/view/decodetrace.cpp +++ b/DSView/pv/view/decodetrace.cpp @@ -146,14 +146,7 @@ DecodeTrace::DecodeTrace(pv::SigSession &session, } DecodeTrace::~DecodeTrace() -{ - DESTROY_OBJECT(_start_comboBox); - DESTROY_OBJECT(_end_comboBox); - DESTROY_OBJECT(_pub_input_layer); - DESTROY_OBJECT(_popup_form); - DESTROY_OBJECT(_popup); - - _cur_row_headings.clear(); +{ _cur_row_headings.clear(); _decoder_forms.clear(); _probe_selectors.clear(); _bindings.clear(); @@ -371,13 +364,7 @@ bool DecodeTrace::create_popup() } } - //destroy object - DESTROY_OBJECT(_start_comboBox); - DESTROY_OBJECT(_end_comboBox); - DESTROY_OBJECT(_pub_input_layer); - DESTROY_OBJECT(_popup_form); - DESTROY_OBJECT(_popup); - + //destroy object return ret; } @@ -389,7 +376,7 @@ void DecodeTrace::create_popup_form() // which then goes out of scope destroying the layout and all the child // widgets. if (_popup_form) - _popup->reload(false); + _popup->reload(); _popup_form = new QFormLayout(); _popup_form->setVerticalSpacing(5); diff --git a/DSView/pv/view/viewport.cpp b/DSView/pv/view/viewport.cpp index 4646fd9d..141884c8 100755 --- a/DSView/pv/view/viewport.cpp +++ b/DSView/pv/view/viewport.cpp @@ -501,7 +501,7 @@ void Viewport::paintProgress(QPainter &p, QColor fore, QColor back) void Viewport::mousePressEvent(QMouseEvent *event) { assert(event); - + _mouse_down_point = event->pos(); _mouse_down_offset = _view.offset(); _drag_strength = 0; diff --git a/libsigrok4DSL/hardware/demo/demo.h b/libsigrok4DSL/hardware/demo/demo.h index 5a474ea0..7fbb87e5 100755 --- a/libsigrok4DSL/hardware/demo/demo.h +++ b/libsigrok4DSL/hardware/demo/demo.h @@ -168,8 +168,8 @@ static const struct DEMO_profile supported_Demo[] = { (1 << DEMO_LOGIC100x16) | (1 << DEMO_ANALOG10x2) | (1 << DEMO_DSO200x2), - SR_Mn(100), - // SR_Gn(16), + //SR_Mn(100), + SR_Gn(16), SR_Kn(20), 0, vdivs10to2000, From 1afaf9d53c9e67b7278e082d970be40c48656cad Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Mon, 25 Oct 2021 15:16:30 +0800 Subject: [PATCH 10/60] add view quick scroll check flag --- DSView/pv/config/appconfig.cpp | 14 +++++++- DSView/pv/config/appconfig.h | 22 ++++-------- DSView/pv/dialogs/applicationpardlg.cpp | 38 +++++++++++++++----- DSView/pv/dialogs/applicationpardlg.h | 6 ++-- DSView/pv/dialogs/calibration.cpp | 17 ++++++++- DSView/pv/dialogs/calibration.h | 4 +-- DSView/pv/dialogs/deviceoptions.cpp | 15 +++++++- DSView/pv/dialogs/deviceoptions.h | 5 +-- DSView/pv/dialogs/dsdialog.cpp | 13 +++++-- DSView/pv/dialogs/dsdialog.h | 2 ++ DSView/pv/dialogs/dsomeasure.cpp | 8 +++++ DSView/pv/dialogs/dsomeasure.h | 11 +++--- DSView/pv/dialogs/fftoptions.cpp | 20 +++++++++-- DSView/pv/dialogs/fftoptions.h | 5 +-- DSView/pv/dialogs/interval.cpp | 5 +++ DSView/pv/dialogs/lissajousoptions.cpp | 7 ++++ DSView/pv/dialogs/lissajousoptions.h | 5 +-- DSView/pv/toolbars/trigbar.cpp | 5 ++- DSView/pv/view/viewport.cpp | 47 +++++++++++++------------ 19 files changed, 175 insertions(+), 74 deletions(-) diff --git a/DSView/pv/config/appconfig.cpp b/DSView/pv/config/appconfig.cpp index ac5d1c28..44c62989 100644 --- a/DSView/pv/config/appconfig.cpp +++ b/DSView/pv/config/appconfig.cpp @@ -72,7 +72,7 @@ void StringToFormatArray(const QString &str, vector &protocolFormats AppConfig::AppConfig() { - + _appOptions.quickScroll = true; } AppConfig::~AppConfig() @@ -135,6 +135,12 @@ bool AppConfig::Save() QString profomats = FormatArrayToString(m_protocolFormats); jobj["ProtocolFormats"] = QJsonValue::fromVariant(profomats); + //application options + QJsonObject app; + app["QuickScroll"] = QJsonValue::fromVariant(_appOptions.quickScroll); + + jobj["Application"] = QJsonValue::fromVariant(app); + QJsonDocument jdoc(jobj); QByteArray bytes = jdoc.toJson(); string json; @@ -155,6 +161,12 @@ bool AppConfig::Save() m_protocolFormats.clear(); StringToFormatArray(jobj["ProtocolFormats"].toString(), m_protocolFormats); } + + //application node + if (jobj.contains("Application")){ + QJsonObject app = jobj["Application"].toObject(); + _appOptions.quickScroll = app["QuickScroll"].toBool(); + } } void AppConfig::SetProtocolFormat(const string &protocolName, const string &value) diff --git a/DSView/pv/config/appconfig.h b/DSView/pv/config/appconfig.h index ec2b2ee1..a5c93aea 100644 --- a/DSView/pv/config/appconfig.h +++ b/DSView/pv/config/appconfig.h @@ -26,13 +26,7 @@ #include using namespace std; - -struct app_status{ - - -}; - - + class StringPair { public: @@ -41,13 +35,12 @@ public: string m_value; }; -class config_data -{ - public: - - +struct AppOptions +{ + bool quickScroll; }; + class AppConfig { private: @@ -63,11 +56,10 @@ public: void FromJson(string &json); void SetProtocolFormat(const string &protocolName, const string &value); - string GetProtocolFormat(const string &protocolName); + string GetProtocolFormat(const string &protocolName); public: - config_data m_data; - app_status m_status; + AppOptions _appOptions; private: string m_fileName; diff --git a/DSView/pv/dialogs/applicationpardlg.cpp b/DSView/pv/dialogs/applicationpardlg.cpp index 26e07484..b27da3a5 100644 --- a/DSView/pv/dialogs/applicationpardlg.cpp +++ b/DSView/pv/dialogs/applicationpardlg.cpp @@ -21,6 +21,10 @@ #include "applicationpardlg.h" #include "dsdialog.h" +#include +#include +#include +#include "../config/appconfig.h" namespace pv { @@ -29,7 +33,7 @@ namespace dialogs ApplicationParamDlg::ApplicationParamDlg() { - m_ret = false; + } ApplicationParamDlg::~ApplicationParamDlg() @@ -39,14 +43,32 @@ ApplicationParamDlg::~ApplicationParamDlg() bool ApplicationParamDlg::ShowDlg(QWidget *parent) { DSDialog dlg(parent, true, true); - dlg.exec(); - return m_ret; -} + dlg.setMinimumSize(300, 200); + QFormLayout &lay = *(new QFormLayout()); + lay.setContentsMargins(0,20,0,30); -//------------IDlgCallback -void ApplicationParamDlg::OnDlgResult(bool bYes){ - m_ret = bYes; - } + //show config + AppOptions &_app = AppConfig::Instance()._appOptions; + + QCheckBox *ck_quickScroll = new QCheckBox(); + ck_quickScroll->setChecked(_app.quickScroll); + lay.addRow("Quick scroll", ck_quickScroll); + dlg.layout()->addLayout(&lay); + + dlg.exec(); + + bool ret = dlg.IsClickYes(); + + //save config + if (ret){ + _app.quickScroll = ck_quickScroll->isChecked(); + + AppConfig::Instance().Save(); + } + + return ret; +} + } // }// diff --git a/DSView/pv/dialogs/applicationpardlg.h b/DSView/pv/dialogs/applicationpardlg.h index 71e35d51..e890c985 100644 --- a/DSView/pv/dialogs/applicationpardlg.h +++ b/DSView/pv/dialogs/applicationpardlg.h @@ -23,14 +23,13 @@ #include #include -#include "../interface/uicallback.h" namespace pv { namespace dialogs { - class ApplicationParamDlg : private IDlgCallback + class ApplicationParamDlg { // Q_OBJECT @@ -44,8 +43,7 @@ namespace pv private: void OnDlgResult(bool bYes); - private: - bool m_ret; + }; }// diff --git a/DSView/pv/dialogs/calibration.cpp b/DSView/pv/dialogs/calibration.cpp index 36298622..e91d1722 100755 --- a/DSView/pv/dialogs/calibration.cpp +++ b/DSView/pv/dialogs/calibration.cpp @@ -31,6 +31,7 @@ #include "../view/trace.h" #include "../dialogs/dsmessagebox.h" +#include "../dsvdef.h" using namespace boost; using namespace std; @@ -44,7 +45,13 @@ const QString Calibration::VCOMB = QT_TR_NOOP(" VCOMB"); Calibration::Calibration(QWidget *parent) : DSDialog(parent) -{ +{ + _save_btn = NULL; + _abort_btn = NULL; + _reset_btn = NULL; + _exit_btn = NULL; + _flayout = NULL; + #ifdef Q_OS_DARWIN Qt::WindowFlags flags = windowFlags(); this->setWindowFlags(flags | Qt::Tool); @@ -89,6 +96,14 @@ Calibration::Calibration(QWidget *parent) : retranslateUi(); } +Calibration::~Calibration(){ + DESTROY_QT_OBJECT(_save_btn); + DESTROY_QT_OBJECT(_abort_btn); + DESTROY_QT_OBJECT(_reset_btn); + DESTROY_QT_OBJECT(_exit_btn); + DESTROY_QT_OBJECT(_flayout); +} + void Calibration::changeEvent(QEvent *event) { if (event->type() == QEvent::LanguageChange) diff --git a/DSView/pv/dialogs/calibration.h b/DSView/pv/dialogs/calibration.h index 97bf7ce2..8418606e 100755 --- a/DSView/pv/dialogs/calibration.h +++ b/DSView/pv/dialogs/calibration.h @@ -50,6 +50,7 @@ private: public: Calibration(QWidget *parent); + ~Calibration(); void set_device(boost::shared_ptr dev_inst); protected: @@ -69,8 +70,7 @@ private slots: private: boost::shared_ptr _dev_inst; - - toolbars::TitleBar *_titlebar; + QPushButton *_save_btn; QPushButton *_abort_btn; QPushButton *_reset_btn; diff --git a/DSView/pv/dialogs/deviceoptions.cpp b/DSView/pv/dialogs/deviceoptions.cpp index 3ac73ad2..fe8513ed 100755 --- a/DSView/pv/dialogs/deviceoptions.cpp +++ b/DSView/pv/dialogs/deviceoptions.cpp @@ -30,10 +30,11 @@ #include "dsmessagebox.h" #include +#include "../dsvdef.h" using namespace boost; using namespace std; - + namespace pv { namespace dialogs { @@ -43,6 +44,11 @@ DeviceOptions::DeviceOptions(QWidget *parent, boost::shared_ptrdev_inst()) { + _dynamic_box = NULL; + _props_box = NULL; + _config_button = NULL; + _cali_button = NULL; + _props_box = new QGroupBox(tr("Mode"), this); _props_box->setLayout(get_property_form(_props_box)); _layout.addWidget(_props_box); @@ -73,6 +79,13 @@ DeviceOptions::DeviceOptions(QWidget *parent, boost::shared_ptr dev_inst); + ~DeviceOptions(); + protected: void accept(); void reject(); @@ -84,8 +86,7 @@ private slots: private: boost::shared_ptr _dev_inst; - QVBoxLayout _layout; - toolbars::TitleBar *_titlebar; + QVBoxLayout _layout; QGroupBox *_dynamic_box; QGridLayout _dynamic_layout; diff --git a/DSView/pv/dialogs/dsdialog.cpp b/DSView/pv/dialogs/dsdialog.cpp index 81165b3f..1d8f15ff 100755 --- a/DSView/pv/dialogs/dsdialog.cpp +++ b/DSView/pv/dialogs/dsdialog.cpp @@ -59,6 +59,7 @@ DSDialog::DSDialog(QWidget *parent, bool hasClose, bool bBaseButton) : _base_button = NULL; m_callback = NULL; + _clickYes = false; setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint); setAttribute(Qt::WA_TranslucentBackground); @@ -80,19 +81,23 @@ void DSDialog::accept() { using namespace Qt; + _clickYes = true; if (m_callback){ m_callback->OnDlgResult(true); } + QDialog::accept(); } void DSDialog::reject() { using namespace Qt; + _clickYes = false; + if (m_callback){ m_callback->OnDlgResult(false); - } + } QDialog::reject(); } @@ -114,7 +119,8 @@ int DSDialog::exec() //ok,cancel if (m_bBaseButton){ _base_button = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel,Qt::Horizontal, this); - _main_layout->addWidget(_base_button);//, 5, 1, 1, 1, Qt::AlignHCenter | Qt::AlignBottom); + _main_layout->addWidget(_base_button);//, 5, 1, 1, 1, Qt::AlignHCenter | Qt::AlignBottom); + //_main_layout->addWidget(_base_button,0, Qt::AlignHCenter | Qt::AlignBottom); connect(_base_button, SIGNAL(rejected()), this, SLOT(reject())); connect(_base_button, SIGNAL(accepted()), this, SLOT(accept())); } @@ -142,6 +148,9 @@ void DSDialog::build_base(bool hasClose) _main_layout->addWidget(_titlebar); _base_layout->addWidget(_main_widget); setLayout(_base_layout); + + _main_layout->setAlignment(Qt::AlignCenter | Qt::AlignTop); + } } // namespace dialogs diff --git a/DSView/pv/dialogs/dsdialog.h b/DSView/pv/dialogs/dsdialog.h index 22799aa2..00f83ef7 100755 --- a/DSView/pv/dialogs/dsdialog.h +++ b/DSView/pv/dialogs/dsdialog.h @@ -56,6 +56,7 @@ public: void setTitle(QString title); void reload(); int exec(); + inline bool IsClickYes(){return _clickYes;} protected: void accept(); @@ -74,6 +75,7 @@ private: QPoint _startPos; bool m_bBaseButton; + bool _clickYes; IDlgCallback *m_callback; }; diff --git a/DSView/pv/dialogs/dsomeasure.cpp b/DSView/pv/dialogs/dsomeasure.cpp index d1acaa19..a454d86c 100755 --- a/DSView/pv/dialogs/dsomeasure.cpp +++ b/DSView/pv/dialogs/dsomeasure.cpp @@ -31,6 +31,7 @@ #include #include +#include "../dsvdef.h" using namespace boost; using namespace std; @@ -48,6 +49,8 @@ DsoMeasure::DsoMeasure(SigSession &session, View &parent, _button_box(QDialogButtonBox::Reset | QDialogButtonBox::Cancel, Qt::Horizontal, this) { + _measure_tab = NULL; + setMinimumSize(500, 400); _measure_tab = new QTabWidget(this); @@ -79,6 +82,10 @@ DsoMeasure::DsoMeasure(SigSession &session, View &parent, connect(_session.get_device().get(), SIGNAL(device_updated()), this, SLOT(reject())); } +DsoMeasure::~DsoMeasure(){ + DESTROY_QT_OBJECT(_measure_tab); +} + void DsoMeasure::add_measure(QWidget *widget, const boost::shared_ptr dsoSig) { const int Column = 5; @@ -86,6 +93,7 @@ void DsoMeasure::add_measure(QWidget *widget, const boost::shared_ptrsetMargin(0); layout->setSpacing(0); + for (int i=DSO_MS_BEGIN+1; isetProperty("id", QVariant(i)); diff --git a/DSView/pv/dialogs/dsomeasure.h b/DSView/pv/dialogs/dsomeasure.h index ab9c25ea..5016fda7 100755 --- a/DSView/pv/dialogs/dsomeasure.h +++ b/DSView/pv/dialogs/dsomeasure.h @@ -49,8 +49,9 @@ class DsoMeasure : public DSDialog Q_OBJECT public: - DsoMeasure(SigSession &session, view::View &parent, - unsigned int position, int last_sig_index); + DsoMeasure(SigSession &session, view::View &parent, unsigned int position, int last_sig_index); + + ~DsoMeasure(); static QString get_ms_icon(int ms_type); static QString get_ms_text(int ms_type); @@ -70,12 +71,10 @@ private: SigSession &_session; view::View &_view; unsigned int _position; - - toolbars::TitleBar *_titlebar; + QDialogButtonBox _button_box; QTabWidget *_measure_tab; - QVBoxLayout _layout; - std::vector _mbtn_vec; + QVBoxLayout _layout; }; } // namespace dialogs diff --git a/DSView/pv/dialogs/fftoptions.cpp b/DSView/pv/dialogs/fftoptions.cpp index 3436ff7f..9202500d 100755 --- a/DSView/pv/dialogs/fftoptions.cpp +++ b/DSView/pv/dialogs/fftoptions.cpp @@ -34,7 +34,7 @@ using namespace boost; using namespace std; - + namespace pv { namespace dialogs { @@ -44,6 +44,18 @@ FftOptions::FftOptions(QWidget *parent, SigSession &session) : _button_box(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this) { + _len_combobox = NULL; + _interval_combobox = NULL; + _en_checkbox = NULL; + _ch_combobox = NULL; + _window_combobox = NULL; + _dc_checkbox = NULL; + _view_combobox = NULL; + _dbv_combobox = NULL; + _hint_label = NULL; + _glayout = NULL; + _layout = NULL; + _en_checkbox = new QCheckBox(this); _len_combobox = new QComboBox(this); _interval_combobox = new QComboBox(this); @@ -173,7 +185,7 @@ FftOptions::FftOptions(QWidget *parent, SigSession &session) : QPixmap pixmap(hint_pic); _hint_label->setPixmap(pixmap); - _glayout = new QGridLayout(); + _glayout = new QGridLayout(); //QGridLayout _glayout->setVerticalSpacing(5); _glayout->addWidget(new QLabel(tr("FFT Enable: "), this), 0, 0); _glayout->addWidget(_en_checkbox, 0, 1); @@ -208,6 +220,10 @@ FftOptions::FftOptions(QWidget *parent, SigSession &session) : connect(_session.get_device().get(), SIGNAL(device_updated()), this, SLOT(reject())); } +FftOptions::~FftOptions(){ + +} + void FftOptions::accept() { using namespace Qt; diff --git a/DSView/pv/dialogs/fftoptions.h b/DSView/pv/dialogs/fftoptions.h index b16dfe60..2486c871 100755 --- a/DSView/pv/dialogs/fftoptions.h +++ b/DSView/pv/dialogs/fftoptions.h @@ -52,6 +52,8 @@ private: public: FftOptions(QWidget *parent, SigSession &session); + ~FftOptions(); + protected: void accept(); void reject(); @@ -63,8 +65,7 @@ private slots: private: SigSession &_session; uint64_t _sample_limit; - - toolbars::TitleBar *_titlebar; + QComboBox *_len_combobox; QComboBox *_interval_combobox; QCheckBox *_en_checkbox; diff --git a/DSView/pv/dialogs/interval.cpp b/DSView/pv/dialogs/interval.cpp index e2ff752b..7ab456b7 100755 --- a/DSView/pv/dialogs/interval.cpp +++ b/DSView/pv/dialogs/interval.cpp @@ -32,6 +32,11 @@ Interval::Interval(SigSession &session, QWidget *parent) : _button_box(QDialogButtonBox::Ok, Qt::Horizontal, this) { + _interval_label = NULL; + _interval_spinBox = NULL; + _interval_slider = NULL; + + setMinimumWidth(300); _interval_label = new QLabel(tr("Interval(s): "), this); _interval_spinBox = new QSpinBox(this); diff --git a/DSView/pv/dialogs/lissajousoptions.cpp b/DSView/pv/dialogs/lissajousoptions.cpp index 5f502f81..02c98167 100755 --- a/DSView/pv/dialogs/lissajousoptions.cpp +++ b/DSView/pv/dialogs/lissajousoptions.cpp @@ -33,6 +33,7 @@ #include + using namespace boost; using namespace std; using namespace pv::view; @@ -46,6 +47,12 @@ LissajousOptions::LissajousOptions(SigSession &session, QWidget *parent) : _button_box(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this) { + _enable = NULL; + _x_group = NULL; + _y_group = NULL; + _percent = NULL; + _layout = NULL; + setMinimumSize(300, 300); _enable = new QCheckBox(this); diff --git a/DSView/pv/dialogs/lissajousoptions.h b/DSView/pv/dialogs/lissajousoptions.h index b3fd13f1..b0653548 100755 --- a/DSView/pv/dialogs/lissajousoptions.h +++ b/DSView/pv/dialogs/lissajousoptions.h @@ -73,10 +73,11 @@ private: QGroupBox *_x_group; QGroupBox *_y_group; QSlider *_percent; + QGridLayout *_layout; + QVector _x_radio; QVector _y_radio; - QDialogButtonBox _button_box; - QGridLayout *_layout; + QDialogButtonBox _button_box; }; } // namespace dialogs diff --git a/DSView/pv/toolbars/trigbar.cpp b/DSView/pv/toolbars/trigbar.cpp index d63d857b..95f336f4 100755 --- a/DSView/pv/toolbars/trigbar.cpp +++ b/DSView/pv/toolbars/trigbar.cpp @@ -316,9 +316,8 @@ void TrigBar::on_actionLissajous_triggered() } void TrigBar::on_application_param(){ - pv::dialogs::MathOptions math_dlg(_session, this); - math_dlg.exec(); - return; + // pv::dialogs::MathOptions math_dlg(_session, this); math_dlg.exec(); return; + pv::dialogs::ApplicationParamDlg dlg; dlg.ShowDlg(this); } diff --git a/DSView/pv/view/viewport.cpp b/DSView/pv/view/viewport.cpp index 141884c8..1bf6720f 100755 --- a/DSView/pv/view/viewport.cpp +++ b/DSView/pv/view/viewport.cpp @@ -37,12 +37,12 @@ #include #include -#include - -#include - +#include +#include #include +#include "../config/appconfig.h" + using namespace boost; using namespace std; @@ -91,24 +91,20 @@ Viewport::Viewport(View &parent, View_type type) : // drag inertial _drag_strength = 0; _drag_timer.setSingleShot(true); - - connect(&trigger_timer, SIGNAL(timeout()), - this, SLOT(on_trigger_timer())); - connect(&_drag_timer, SIGNAL(timeout()), - this, SLOT(on_drag_timer())); - - connect(&_view.session(), &SigSession::receive_data, - this, &Viewport::set_receive_len); - + _cmenu = new QMenu(this); QAction *yAction = _cmenu->addAction(tr("Add Y-cursor")); QAction *xAction = _cmenu->addAction(tr("Add X-cursor")); + + setContextMenuPolicy(Qt::CustomContextMenu); + + connect(&trigger_timer, SIGNAL(timeout()),this, SLOT(on_trigger_timer())); + connect(&_drag_timer, SIGNAL(timeout()),this, SLOT(on_drag_timer())); + connect(&_view.session(), &SigSession::receive_data, this, &Viewport::set_receive_len); + connect(yAction, SIGNAL(triggered(bool)), this, SLOT(add_cursor_y())); connect(xAction, SIGNAL(triggered(bool)), this, SLOT(add_cursor_x())); - - setContextMenuPolicy(Qt::CustomContextMenu); - connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), - this, SLOT(show_contextmenu(const QPoint&))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint&)),this, SLOT(show_contextmenu(const QPoint&))); } int Viewport::get_total_height() const @@ -757,14 +753,19 @@ void Viewport::mouseMoveEvent(QMouseEvent *event) void Viewport::mouseReleaseEvent(QMouseEvent *event) { assert(event); - - if (_type == TIME_VIEW) { + + if (_type != TIME_VIEW){ + update(); + return; + } + if ((_action_type == NO_ACTION) && (event->button() == Qt::LeftButton)) { if (_view.session().get_device()->dev_inst()->mode == LOGIC && _view.session().get_capture_state() == SigSession::Stopped) { - // priority 1 - if (_action_type == NO_ACTION) { + //priority 1 + //try to quick scroll view + if (_action_type == NO_ACTION && AppConfig::Instance()._appOptions.quickScroll) { const double strength = _drag_strength*DragTimerInterval*1.0/_elapsed_time.elapsed(); if (_elapsed_time.elapsed() < 200 && abs(_drag_strength) < MinorDragOffsetUp && @@ -936,7 +937,7 @@ void Viewport::mouseReleaseEvent(QMouseEvent *event) } _action_type = NO_ACTION; } - } + update(); } @@ -1621,7 +1622,7 @@ void Viewport::on_trigger_timer() } void Viewport::on_drag_timer() -{ +{ const int64_t offset = _view.offset(); const double scale = _view.scale(); if (_view.session().get_capture_state() == SigSession::Stopped && From a2acb95deddfd7935942294a33befdad34f36c19 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Mon, 25 Oct 2021 15:24:58 +0800 Subject: [PATCH 11/60] none --- DSView/pv/view/viewport.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DSView/pv/view/viewport.cpp b/DSView/pv/view/viewport.cpp index 1bf6720f..f4c475f6 100755 --- a/DSView/pv/view/viewport.cpp +++ b/DSView/pv/view/viewport.cpp @@ -764,7 +764,7 @@ void Viewport::mouseReleaseEvent(QMouseEvent *event) if (_view.session().get_device()->dev_inst()->mode == LOGIC && _view.session().get_capture_state() == SigSession::Stopped) { //priority 1 - //try to quick scroll view + //try to quick scroll view... if (_action_type == NO_ACTION && AppConfig::Instance()._appOptions.quickScroll) { const double strength = _drag_strength*DragTimerInterval*1.0/_elapsed_time.elapsed(); if (_elapsed_time.elapsed() < 200 && From 91dd746f2d2aef3f950a594bc127ba67f951c429 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Mon, 25 Oct 2021 16:51:34 +0800 Subject: [PATCH 12/60] disable toolbar context menu --- DSView/pv/dialogs/applicationpardlg.cpp | 1 + DSView/pv/mainwindow.cpp | 136 ++++++++++-------------- DSView/pv/storesession.cpp | 23 +++- DSView/pv/toolbars/filebar.cpp | 30 +++--- 4 files changed, 90 insertions(+), 100 deletions(-) diff --git a/DSView/pv/dialogs/applicationpardlg.cpp b/DSView/pv/dialogs/applicationpardlg.cpp index b27da3a5..469e0657 100644 --- a/DSView/pv/dialogs/applicationpardlg.cpp +++ b/DSView/pv/dialogs/applicationpardlg.cpp @@ -43,6 +43,7 @@ ApplicationParamDlg::~ApplicationParamDlg() bool ApplicationParamDlg::ShowDlg(QWidget *parent) { DSDialog dlg(parent, true, true); + dlg.setTitle("Application options"); dlg.setMinimumSize(300, 200); QFormLayout &lay = *(new QFormLayout()); lay.setContentsMargins(0,20,0,30); diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index 06c30bc9..70828a2a 100755 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -109,6 +109,9 @@ MainWindow::MainWindow(DeviceManager &device_manager, _msg(NULL) { setup_ui(); + + setContextMenuPolicy(Qt::NoContextMenu); + if (open_file_name) { qDebug("Open file: %s", open_file_name); const QString s(QString::fromUtf8(open_file_name)); @@ -119,7 +122,7 @@ MainWindow::MainWindow(DeviceManager &device_manager, } void MainWindow::setup_ui() -{ +{ setObjectName(QString::fromUtf8("MainWindow")); setContentsMargins(0,0,0,0); layout()->setMargin(0); @@ -141,34 +144,7 @@ void MainWindow::setup_ui() _file_bar->setObjectName("file_bar"); _logo_bar = new toolbars::LogoBar(_session, this); _logo_bar->setObjectName("logo_bar"); - - connect(_trig_bar, SIGNAL(on_protocol(bool)), this, - SLOT(on_protocol(bool))); - connect(_trig_bar, SIGNAL(on_trigger(bool)), this, - SLOT(on_trigger(bool))); - connect(_trig_bar, SIGNAL(on_measure(bool)), this, - SLOT(on_measure(bool))); - connect(_trig_bar, SIGNAL(on_search(bool)), this, - SLOT(on_search(bool))); - connect(_trig_bar, SIGNAL(setTheme(QString)), this, - SLOT(switchTheme(QString))); - connect(_file_bar, SIGNAL(load_file(QString)), this, - SLOT(load_file(QString))); - connect(_file_bar, SIGNAL(on_save()), this, - SLOT(on_save())); - connect(_file_bar, SIGNAL(on_export()), this, - SLOT(on_export())); - connect(_file_bar, SIGNAL(on_screenShot()), this, - SLOT(on_screenShot()), Qt::QueuedConnection); - connect(_file_bar, SIGNAL(load_session(QString)), this, - SLOT(load_session(QString))); - connect(_file_bar, SIGNAL(store_session(QString)), this, - SLOT(store_session(QString))); - connect(_logo_bar, SIGNAL(setLanguage(int)), this, - SLOT(switchLanguage(int))); - connect(_logo_bar, SIGNAL(openDoc()), this, - SLOT(openDoc())); - + // trigger dock _trigger_dock=new QDockWidget(tr("Trigger Setting..."),this); _trigger_dock->setObjectName("trigger_dock"); @@ -190,28 +166,7 @@ void MainWindow::setup_ui() // Setup _view widget _view = new pv::view::View(_session, _sampling_bar, this); _vertical_layout->addWidget(_view); - - connect(_sampling_bar, SIGNAL(device_selected()), this, - SLOT(update_device_list())); - connect(_sampling_bar, SIGNAL(device_updated()), this, - SLOT(reload())); - connect(_sampling_bar, SIGNAL(run_stop()), this, - SLOT(run_stop())); - connect(_sampling_bar, SIGNAL(instant_stop()), this, - SLOT(instant_stop())); - connect(_sampling_bar, SIGNAL(duration_changed()), _trigger_widget, - SLOT(device_updated())); - connect(_sampling_bar, SIGNAL(duration_changed()), _view, - SLOT(timebase_changed())); - connect(_sampling_bar, SIGNAL(show_calibration()), _view, - SLOT(show_calibration())); - connect(_trig_bar, SIGNAL(show_lissajous(bool)), _view, - SLOT(show_lissajous(bool))); - connect(_dso_trigger_widget, SIGNAL(set_trig_pos(int)), _view, - SLOT(set_trig_pos(int))); - connect(_view, SIGNAL(auto_trig(int)), _dso_trigger_widget, - SLOT(auto_trig(int))); - + setIconSize(QSize(40,40)); addToolBar(_sampling_bar); addToolBar(_trig_bar); @@ -230,8 +185,7 @@ void MainWindow::setup_ui() _protocol_widget = new dock::ProtocolDock(_protocol_dock, *_view, _session); _protocol_dock->setWidget(_protocol_widget); qDebug() << "Protocol decoder enabled!\n"; - - connect(_protocol_widget, SIGNAL(protocol_updated()), _view, SLOT(signals_changed())); + #endif // measure dock _measure_dock=new QDockWidget(tr("Measurement"),this); @@ -265,35 +219,6 @@ void MainWindow::setup_ui() std::string std_title = title.toStdString(); setWindowTitle(QApplication::translate("MainWindow", std_title.c_str(), 0)); - // Setup _session events - connect(&_session, SIGNAL(capture_state_changed(int)), this, - SLOT(capture_state_changed(int))); - connect(&_session, SIGNAL(device_attach()), this, - SLOT(device_attach()), Qt::QueuedConnection); - connect(&_session, SIGNAL(device_detach()), this, - SLOT(device_detach()), Qt::QueuedConnection); - connect(&_session, SIGNAL(session_error()), this, - SLOT(show_error()), Qt::QueuedConnection); - connect(&_session, SIGNAL(session_save()), this, - SLOT(session_save())); - connect(&_session, SIGNAL(data_updated()), _measure_widget, - SLOT(reCalc())); - connect(&_session, SIGNAL(repeat_resume()), this, - SLOT(repeat_resume())); - connect(&_session, SIGNAL(update_capture()), _view, - SLOT(update_hori_res()), Qt::DirectConnection); - - connect(&_session, SIGNAL(cur_snap_samplerate_changed()), _measure_widget, - SLOT(cursor_update())); - connect(_view, SIGNAL(cursor_update()), _measure_widget, - SLOT(cursor_update())); - connect(_view, SIGNAL(cursor_moving()), _measure_widget, - SLOT(cursor_moving())); - connect(_view, SIGNAL(cursor_moved()), _measure_widget, - SLOT(reCalc())); - connect(_view, SIGNAL(prgRate(int)), this, SIGNAL(prgRate(int))); - connect(_view, SIGNAL(device_changed(bool)), - this, SLOT(device_changed(bool)), Qt::DirectConnection); // event filter _view->installEventFilter(this); @@ -330,6 +255,53 @@ void MainWindow::setup_ui() QString(tr("Hotplug failed")), _1)); retranslateUi(); + + + // Setup _session events + connect(&_session, SIGNAL(capture_state_changed(int)), this, SLOT(capture_state_changed(int))); + connect(&_session, SIGNAL(device_attach()), this, SLOT(device_attach()), Qt::QueuedConnection); + connect(&_session, SIGNAL(device_detach()), this, SLOT(device_detach()), Qt::QueuedConnection); + connect(&_session, SIGNAL(session_error()), this, SLOT(show_error()), Qt::QueuedConnection); + connect(&_session, SIGNAL(session_save()), this, SLOT(session_save())); + connect(&_session, SIGNAL(data_updated()), _measure_widget, SLOT(reCalc())); + connect(&_session, SIGNAL(repeat_resume()), this, SLOT(repeat_resume())); + connect(&_session, SIGNAL(update_capture()), _view, SLOT(update_hori_res()), Qt::DirectConnection); + connect(&_session, SIGNAL(cur_snap_samplerate_changed()), _measure_widget, SLOT(cursor_update())); + connect(_view, SIGNAL(cursor_update()), _measure_widget, SLOT(cursor_update())); + connect(_view, SIGNAL(cursor_moving()), _measure_widget, SLOT(cursor_moving())); + connect(_view, SIGNAL(cursor_moved()), _measure_widget, SLOT(reCalc())); + connect(_view, SIGNAL(prgRate(int)), this, SIGNAL(prgRate(int))); + connect(_view, SIGNAL(device_changed(bool)), this, SLOT(device_changed(bool)), Qt::DirectConnection); + + //tool bar event + connect(_trig_bar, SIGNAL(on_protocol(bool)), this, SLOT(on_protocol(bool))); + connect(_trig_bar, SIGNAL(on_trigger(bool)), this, SLOT(on_trigger(bool))); + connect(_trig_bar, SIGNAL(on_measure(bool)), this, SLOT(on_measure(bool))); + connect(_trig_bar, SIGNAL(on_search(bool)), this, SLOT(on_search(bool))); + connect(_trig_bar, SIGNAL(setTheme(QString)), this, SLOT(switchTheme(QString))); + connect(_file_bar, SIGNAL(load_file(QString)), this, SLOT(load_file(QString))); + connect(_file_bar, SIGNAL(on_save()), this, SLOT(on_save())); + connect(_file_bar, SIGNAL(on_export()), this, SLOT(on_export())); + connect(_file_bar, SIGNAL(on_screenShot()), this, SLOT(on_screenShot()), Qt::QueuedConnection); + connect(_file_bar, SIGNAL(load_session(QString)), this, SLOT(load_session(QString))); + connect(_file_bar, SIGNAL(store_session(QString)), this, SLOT(store_session(QString))); + connect(_logo_bar, SIGNAL(setLanguage(int)), this, SLOT(switchLanguage(int))); + connect(_logo_bar, SIGNAL(openDoc()), this, SLOT(openDoc())); + +#ifdef ENABLE_DECODE + connect(_protocol_widget, SIGNAL(protocol_updated()), _view, SLOT(signals_changed())); +#endif + + connect(_sampling_bar, SIGNAL(device_selected()), this, SLOT(update_device_list())); + connect(_sampling_bar, SIGNAL(device_updated()), this, SLOT(reload())); + connect(_sampling_bar, SIGNAL(run_stop()), this, SLOT(run_stop())); + connect(_sampling_bar, SIGNAL(instant_stop()), this, SLOT(instant_stop())); + connect(_sampling_bar, SIGNAL(duration_changed()), _trigger_widget, SLOT(device_updated())); + connect(_sampling_bar, SIGNAL(duration_changed()), _view, SLOT(timebase_changed())); + connect(_sampling_bar, SIGNAL(show_calibration()), _view, SLOT(show_calibration())); + connect(_trig_bar, SIGNAL(show_lissajous(bool)), _view, SLOT(show_lissajous(bool))); + connect(_dso_trigger_widget, SIGNAL(set_trig_pos(int)), _view, SLOT(set_trig_pos(int))); + connect(_view, SIGNAL(auto_trig(int)), _dso_trigger_widget, SLOT(auto_trig(int))); } diff --git a/DSView/pv/storesession.cpp b/DSView/pv/storesession.cpp index 0d37207a..ca8c51d2 100755 --- a/DSView/pv/storesession.cpp +++ b/DSView/pv/storesession.cpp @@ -568,6 +568,7 @@ QString StoreSession::meta_gen(boost::shared_ptr snapshot) return metafile; } +//export as csv file bool StoreSession::export_start() { std::set type_set; @@ -596,6 +597,7 @@ bool StoreSession::export_start() const QString DIR_KEY("ExportPath"); QSettings settings(QApplication::organizationName(), QApplication::applicationName()); QString default_name = settings.value(DIR_KEY).toString() + "/" + _session.get_device()->name() + "-"; + for (const GSList *l = _session.get_device()->get_dev_mode_list(); l; l = l->next) { const sr_dev_mode *mode = (const sr_dev_mode *)l->data; @@ -616,6 +618,7 @@ bool StoreSession::export_start() } _file_name = QFileDialog::getSaveFileName( NULL, tr("Export Data"), default_name,filter,&filter); + if (!_file_name.isEmpty()) { QFileInfo f(_file_name); QStringList list = filter.split('.').last().split(')'); @@ -681,6 +684,7 @@ void StoreSession::export_proc(shared_ptr snapshot) output.param = NULL; if(_outModule->init) _outModule->init(&output, params); + QFile file(_file_name); file.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream out(&file); @@ -692,9 +696,11 @@ void StoreSession::export_proc(shared_ptr snapshot) struct sr_datafeed_packet p; struct sr_datafeed_meta meta; struct sr_config *src; + src = sr_config_new(SR_CONF_SAMPLERATE, g_variant_new_uint64(_session.cur_snap_samplerate())); meta.config = g_slist_append(NULL, src); + src = sr_config_new(SR_CONF_LIMIT_SAMPLES, g_variant_new_uint64(snapshot->get_sample_count())); meta.config = g_slist_append(meta.config, src); @@ -743,6 +749,7 @@ void StoreSession::export_proc(shared_ptr snapshot) bool sample; std::vector buf_vec; std::vector buf_sample; + for (int blk = 0; !boost::this_thread::interruption_requested() && blk < blk_num; blk++) { uint64_t buf_sample_num = logic_snapshot->get_block_size(blk) * 8; @@ -764,6 +771,7 @@ void StoreSession::export_proc(shared_ptr snapshot) unsigned int usize = 8192; unsigned int size = usize; struct sr_datafeed_logic lp; + for(uint64_t i = 0; !boost::this_thread::interruption_requested() && i < buf_sample_num; i+=usize){ if(buf_sample_num - i < usize) @@ -773,8 +781,9 @@ void StoreSession::export_proc(shared_ptr snapshot) _has_error = true; _error = tr("xbuffer malloc failed."); return; - } + } memset(xbuf, 0, size * unitsize); + for (uint64_t j = 0; j < size; j++) { for (unsigned int k = 0; k < buf_vec.size(); k++) { if (buf_vec[k] == NULL && buf_sample[k]) @@ -783,6 +792,7 @@ void StoreSession::export_proc(shared_ptr snapshot) xbuf[j*unitsize+k/8] += 1 << k%8; } } + lp.data = xbuf; lp.length = size * unitsize; lp.unitsize = unitsize; @@ -790,6 +800,7 @@ void StoreSession::export_proc(shared_ptr snapshot) p.status = SR_PKT_OK; p.payload = &lp; _outModule->receive(&output, &p, &data_out); + if(data_out){ out << QString::fromUtf8((char*) data_out->str); g_string_free(data_out,TRUE); @@ -801,35 +812,41 @@ void StoreSession::export_proc(shared_ptr snapshot) progress_updated(); } } + } else if (channel_type == SR_CHANNEL_DSO) { _unit_count = snapshot->get_sample_count(); unsigned char* datat = (unsigned char*)snapshot->get_data(); unsigned int usize = 8192; unsigned int size = usize; - struct sr_datafeed_dso dp; + struct sr_datafeed_dso dp; + for(uint64_t i = 0; !boost::this_thread::interruption_requested() && i < _unit_count; i+=usize){ if(_unit_count - i < usize) size = _unit_count - i; + dp.data = &datat[i*snapshot->get_channel_num()]; dp.num_samples = size; p.type = SR_DF_DSO; p.status = SR_PKT_OK; p.payload = &dp; _outModule->receive(&output, &p, &data_out); + if(data_out){ out << (char*) data_out->str; g_string_free(data_out,TRUE); } - + _units_stored += size; progress_updated(); } + } else if (channel_type == SR_CHANNEL_ANALOG) { _unit_count = snapshot->get_sample_count(); unsigned char* datat = (unsigned char*)snapshot->get_data(); unsigned int usize = 8192; unsigned int size = usize; struct sr_datafeed_analog ap; + for(uint64_t i = 0; !boost::this_thread::interruption_requested() && i < _unit_count; i+=usize){ if(_unit_count - i < usize) size = _unit_count - i; diff --git a/DSView/pv/toolbars/filebar.cpp b/DSView/pv/toolbars/filebar.cpp index 5efbca7f..ea0b47ac 100755 --- a/DSView/pv/toolbars/filebar.cpp +++ b/DSView/pv/toolbars/filebar.cpp @@ -47,16 +47,13 @@ FileBar::FileBar(SigSession &session, QWidget *parent) : _action_load = new QAction(this); _action_load->setObjectName(QString::fromUtf8("actionLoad")); - connect(_action_load, SIGNAL(triggered()), this, SLOT(on_actionLoad_triggered())); - + _action_store = new QAction(this); _action_store->setObjectName(QString::fromUtf8("actionStore")); - connect(_action_store, SIGNAL(triggered()), this, SLOT(on_actionStore_triggered())); - + _action_default = new QAction(this); _action_default->setObjectName(QString::fromUtf8("actionDefault")); - connect(_action_default, SIGNAL(triggered()), this, SLOT(on_actionDefault_triggered())); - + _menu_session = new QMenu(this); _menu_session->setObjectName(QString::fromUtf8("menuSession")); _menu_session->addAction(_action_load); @@ -65,21 +62,16 @@ FileBar::FileBar(SigSession &session, QWidget *parent) : _action_open = new QAction(this); _action_open->setObjectName(QString::fromUtf8("actionOpen")); - connect(_action_open, SIGNAL(triggered()), this, SLOT(on_actionOpen_triggered())); - + _action_save = new QAction(this); _action_save->setObjectName(QString::fromUtf8("actionSave")); - connect(_action_save, SIGNAL(triggered()), this, SIGNAL(on_save())); - + _action_export = new QAction(this); _action_export->setObjectName(QString::fromUtf8("actionExport")); - connect(_action_export, SIGNAL(triggered()), this, SIGNAL(on_export())); - - + _action_capture = new QAction(this); _action_capture->setObjectName(QString::fromUtf8("actionCapture")); - connect(_action_capture, SIGNAL(triggered()), this, SLOT(on_actionCapture_triggered())); - + _file_button.setToolButtonStyle(Qt::ToolButtonTextUnderIcon); _file_button.setPopupMode(QToolButton::InstantPopup); @@ -93,6 +85,14 @@ FileBar::FileBar(SigSession &session, QWidget *parent) : addWidget(&_file_button); retranslateUi(); + + connect(_action_load, SIGNAL(triggered()), this, SLOT(on_actionLoad_triggered())); + connect(_action_store, SIGNAL(triggered()), this, SLOT(on_actionStore_triggered())); + connect(_action_default, SIGNAL(triggered()), this, SLOT(on_actionDefault_triggered())); + connect(_action_open, SIGNAL(triggered()), this, SLOT(on_actionOpen_triggered())); + connect(_action_save, SIGNAL(triggered()), this, SIGNAL(on_save())); + connect(_action_export, SIGNAL(triggered()), this, SIGNAL(on_export())); + connect(_action_capture, SIGNAL(triggered()), this, SLOT(on_actionCapture_triggered())); } void FileBar::changeEvent(QEvent *event) From fed30a0e572aeccb7e99145c553fcc3de1b4b0de Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Thu, 28 Oct 2021 11:03:50 +0800 Subject: [PATCH 13/60] update app config manager --- DSView/main.cpp | 17 +- DSView/pv/config/appconfig.cpp | 266 +++++++++++++++--------- DSView/pv/config/appconfig.h | 60 ++++-- DSView/pv/data/signaldata.cpp | 6 +- DSView/pv/data/signaldata.h | 8 +- DSView/pv/devicemanager.cpp | 3 +- DSView/pv/dialogs/about.cpp | 7 +- DSView/pv/dialogs/applicationpardlg.cpp | 9 +- DSView/pv/dialogs/protocolexp.cpp | 25 ++- DSView/pv/dialogs/waitingdialog.cpp | 3 +- DSView/pv/dock/dsotriggerdock.cpp | 2 +- DSView/pv/dock/measuredock.cpp | 9 +- DSView/pv/dock/protocoldock.cpp | 3 +- DSView/pv/dock/protocolitemlayer.cpp | 5 +- DSView/pv/dock/searchdock.cpp | 3 +- DSView/pv/dock/triggerdock.cpp | 2 +- DSView/pv/mainframe.cpp | 67 +++--- DSView/pv/mainwindow.cpp | 228 +++++++++++--------- DSView/pv/mainwindow.h | 8 +- DSView/pv/sigsession.cpp | 41 ++-- DSView/pv/sigsession.h | 8 +- DSView/pv/storesession.cpp | 115 ++++++---- DSView/pv/storesession.h | 10 +- DSView/pv/toolbars/filebar.cpp | 74 ++++--- DSView/pv/toolbars/logobar.cpp | 13 +- DSView/pv/toolbars/samplingbar.cpp | 61 +++--- DSView/pv/toolbars/titlebar.cpp | 10 +- DSView/pv/toolbars/trigbar.cpp | 28 +-- DSView/pv/toolbars/trigbar.h | 2 +- DSView/pv/view/decodetrace.cpp | 4 +- DSView/pv/view/devmode.cpp | 22 +- DSView/pv/view/header.cpp | 4 +- DSView/pv/view/selectableitem.cpp | 4 +- DSView/pv/view/signal.cpp | 3 +- DSView/pv/view/trace.cpp | 6 +- DSView/pv/view/view.cpp | 11 +- DSView/pv/widgets/border.cpp | 11 +- DSView/pv/widgets/decodergroupbox.cpp | 6 +- DSView/pv/widgets/decodergroupbox.h | 2 +- 39 files changed, 692 insertions(+), 474 deletions(-) diff --git a/DSView/main.cpp b/DSView/main.cpp index 04ad160e..e1714572 100755 --- a/DSView/main.cpp +++ b/DSView/main.cpp @@ -21,9 +21,7 @@ */ #include -#ifdef ENABLE_DECODE #include -#endif #include #include @@ -33,7 +31,6 @@ #include #include #include -#include #include #include @@ -130,9 +127,9 @@ int main(int argc, char *argv[]) const int loglevel = atoi(optarg); sr_log_loglevel_set(loglevel); -#ifdef ENABLE_DECODE + srd_log_loglevel_set(loglevel); -#endif + break; } @@ -176,7 +173,7 @@ int main(int argc, char *argv[]) } do { -#ifdef ENABLE_DECODE + // Initialise libsigrokdecode if (srd_init(NULL) != SRD_OK) { qDebug() << "ERROR: libsigrokdecode init failed."; @@ -185,9 +182,9 @@ int main(int argc, char *argv[]) // Load the protocol decoders srd_decoder_load_all(); -#endif + //load app config - AppConfig::Instance().Load("./appconfig.json"); + AppConfig::Instance().LoadAll(); try { // Create the device manager, initialise the drivers @@ -206,10 +203,10 @@ int main(int argc, char *argv[]) qDebug() << e.what(); } -#ifdef ENABLE_DECODE + // Destroy libsigrokdecode srd_exit(); -#endif + } while (0); diff --git a/DSView/pv/config/appconfig.cpp b/DSView/pv/config/appconfig.cpp index 44c62989..ae418bfc 100644 --- a/DSView/pv/config/appconfig.cpp +++ b/DSView/pv/config/appconfig.cpp @@ -20,15 +20,11 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "appconfig.h" -#include -#include -#include -#include -#include -#include -#include - +#include "appconfig.h" +#include +#include +#include + #define MAX_PROTOCOL_FORMAT_LIST 15 StringPair::StringPair(const string &key, const string &value) @@ -44,12 +40,10 @@ QString FormatArrayToString(vector &protocolFormats){ for (StringPair &o : protocolFormats){ if (!str.isEmpty()){ str += ";"; - } - std::string line; - line += o.m_key; - line += "="; - line += o.m_value; - str += line.c_str(); + } + str += o.m_key.c_str(); + str += "="; + str += o.m_value.c_str(); } return str; @@ -68,11 +62,112 @@ void StringToFormatArray(const QString &str, vector &protocolFormats } } +//read write field + +void getFiled(const char *key, QSettings &st, QString &f, const char *dv){ + f = st.value(key, dv).toString(); +} +void getFiled(const char *key, QSettings &st, int &f, int dv){ + f = st.value(key, dv).toInt(); +} +void getFiled(const char *key, QSettings &st, bool &f, bool dv){ + f = st.value(key, dv).toBool(); +} + +void setFiled(const char *key, QSettings &st, QString f){ + st.setValue(key, f); +} +void setFiled(const char *key, QSettings &st, int f){ + st.setValue(key, f); +} +void setFiled(const char *key, QSettings &st, bool f){ + st.setValue(key, f); +} + + +///------ app +void _loadApp(AppOptions &o, QSettings &st){ + st.beginGroup("Application"); + getFiled("quickScroll", st, o.quickScroll, true); + getFiled("warnofMultiTrig", st, o.warnofMultiTrig, true); + + + QString fmt; + getFiled("protocalFormats", st, fmt, ""); + if (fmt != ""){ + StringToFormatArray(fmt, o.m_protocolFormats); + } + + st.endGroup(); +} + +void _saveApp(AppOptions &o, QSettings &st){ + st.beginGroup("Application"); + setFiled("quickScroll", st, o.quickScroll); + setFiled("warnofMultiTrig", st, o.warnofMultiTrig); + + + QString fmt = FormatArrayToString(o.m_protocolFormats); + setFiled("protocalFormats", st, fmt); + st.endGroup(); +} + +//-----frame +void _loadFrame(FrameOptions &o, QSettings &st){ + st.beginGroup("MainFrame"); + getFiled("style", st, o.style, "dark"); + getFiled("language", st, o.language, -1); + getFiled("isMax", st, o.isMax, false); + o.geometry = st.value("geometry", QByteArray()).toByteArray(); + o.windowState = st.value("windowState", QByteArray()).toByteArray(); + st.endGroup(); + + if (o.language == -1){ + //get local language + QLocale locale; + o.language = locale.language(); + } +} + +void _saveFrame(FrameOptions &o, QSettings &st){ + st.beginGroup("MainFrame"); + setFiled("style", st, o.style); + setFiled("language", st, o.language); + setFiled("isMax", st, o.isMax); + st.setValue("geometry", o.geometry); + st.setValue("windowState", o.windowState); + st.endGroup(); +} + +//------history +void _loadHistory(UserHistory &o, QSettings &st){ + st.beginGroup("UserHistory"); + getFiled("exportDir", st, o.exportDir, ""); + getFiled("saveDir", st, o.saveDir, ""); + getFiled("showDocuments", st, o.showDocuments, true); + getFiled("screenShotPath", st, o.screenShotPath, ""); + getFiled("sessionDir", st, o.sessionDir, ""); + getFiled("openDir", st, o.openDir, ""); + getFiled("protocolExportPath", st, o.protocolExportPath, ""); + st.endGroup(); +} + +void _saveHistory(UserHistory &o, QSettings &st){ + st.beginGroup("UserHistory"); + setFiled("exportDir", st, o.exportDir); + setFiled("saveDir", st, o.saveDir); + setFiled("showDocuments", st, o.showDocuments); + setFiled("screenShotPath", st, o.screenShotPath); + setFiled("sessionDir", st, o.sessionDir); + setFiled("openDir", st, o.openDir); + setFiled("protocolExportPath", st, o.protocolExportPath); + st.endGroup(); +} + //------------AppConfig AppConfig::AppConfig() -{ - _appOptions.quickScroll = true; +{ } AppConfig::~AppConfig() @@ -88,111 +183,88 @@ AppConfig::~AppConfig() return *ins; } -bool AppConfig::Load(const char *file) -{ - assert(file); - m_fileName = file; - - QFile qf(file); - if (qf.open(QIODevice::ReadOnly)) - { - QByteArray bytes = qf.readAll(); - qf.close(); - - string json; - json.append(bytes.data(), bytes.size()); - FromJson(json); - return true; - } - - return false; +void AppConfig::LoadAll() +{ + QSettings st(QApplication::organizationName(), QApplication::applicationName()); + _loadApp(_appOptions, st); + _loadHistory(_userHistory, st); + _loadFrame(_frameOptions, st); } -bool AppConfig::Save() -{ - if (m_fileName != "") - { - QFile qf(m_fileName.c_str()); - if (qf.open(QIODevice::WriteOnly | QIODevice::Text)) - { - string json = ToJsonString(); - QByteArray bytes(json.c_str(), json.size()); - - QTextStream _stream(&qf); - _stream.setCodec("UTF-8"); - _stream << QString::fromUtf8(bytes); - qf.close(); - - return true; - } - } - return false; -} - - string AppConfig::ToJsonString() + void AppConfig::SaveApp() { - QJsonObject jobj; - QString profomats = FormatArrayToString(m_protocolFormats); - jobj["ProtocolFormats"] = QJsonValue::fromVariant(profomats); - - //application options - QJsonObject app; - app["QuickScroll"] = QJsonValue::fromVariant(_appOptions.quickScroll); - - jobj["Application"] = QJsonValue::fromVariant(app); - - QJsonDocument jdoc(jobj); - QByteArray bytes = jdoc.toJson(); - string json; - json.append(bytes.data(), bytes.size()); - return json; + QSettings st(QApplication::organizationName(), QApplication::applicationName()); + _saveApp(_appOptions, st); } - void AppConfig::FromJson(string &json) + void AppConfig::SaveHistory() { - if (!json.size()) - return; - - QByteArray bytes(json.c_str(), json.size()); - QJsonDocument jdoc = QJsonDocument::fromJson(bytes); - QJsonObject jobj = jdoc.object(); - - if (jobj.contains("ProtocolFormats")){ - m_protocolFormats.clear(); - StringToFormatArray(jobj["ProtocolFormats"].toString(), m_protocolFormats); - } - - //application node - if (jobj.contains("Application")){ - QJsonObject app = jobj["Application"].toObject(); - _appOptions.quickScroll = app["QuickScroll"].toBool(); - } + QSettings st(QApplication::organizationName(), QApplication::applicationName()); + _saveHistory(_userHistory, st); } + void AppConfig::SaveFrame() + { + QSettings st(QApplication::organizationName(), QApplication::applicationName()); + _saveFrame(_frameOptions, st); + } + + void AppConfig::SetProtocolFormat(const string &protocolName, const string &value) { - for (StringPair &o : m_protocolFormats){ + bool bChange = false; + for (StringPair &o : _appOptions.m_protocolFormats){ if (o.m_key == protocolName){ o.m_value = value; - return; + bChange = true; + break; } } - if (m_protocolFormats.size() > MAX_PROTOCOL_FORMAT_LIST){ - while (m_protocolFormats.size() < MAX_PROTOCOL_FORMAT_LIST) + + if (!bChange) + { + if (_appOptions.m_protocolFormats.size() > MAX_PROTOCOL_FORMAT_LIST) { - m_protocolFormats.erase(m_protocolFormats.begin()); + while (_appOptions.m_protocolFormats.size() < MAX_PROTOCOL_FORMAT_LIST) + { + _appOptions.m_protocolFormats.erase(_appOptions.m_protocolFormats.begin()); + } } + _appOptions.m_protocolFormats.push_back(StringPair(protocolName, value)); + bChange = true; } - m_protocolFormats.push_back(StringPair(protocolName,value)); + if (bChange){ + SaveApp(); + } } string AppConfig::GetProtocolFormat(const string &protocolName) { - for (StringPair &o : m_protocolFormats){ + for (StringPair &o : _appOptions.m_protocolFormats){ if (o.m_key == protocolName){ return o.m_value; } } return ""; } + +//-------------api +QString GetDirectoryName(QString path) +{ + int lstdex = path.lastIndexOf('/'); + if (lstdex != -1) + { + return path.left(lstdex); + } + return path; +} + +QString GetIconPath() +{ + QString style = AppConfig::Instance()._frameOptions.style; + if (style == ""){ + style = "dark"; + } + return ":/icons/" + style; +} diff --git a/DSView/pv/config/appconfig.h b/DSView/pv/config/appconfig.h index a5c93aea..14b1d5d6 100644 --- a/DSView/pv/config/appconfig.h +++ b/DSView/pv/config/appconfig.h @@ -24,8 +24,18 @@ #include #include +#include +#include using namespace std; + +//--------------------api + +QString GetDirectoryName(QString path); + +QString GetIconPath(); + +//------------------class class StringPair { @@ -35,33 +45,57 @@ public: string m_value; }; -struct AppOptions +class AppOptions { - bool quickScroll; + public: + bool quickScroll; + bool warnofMultiTrig; + + + vector m_protocolFormats; +}; + +class FrameOptions +{ +public: + QString style; + int language; + QByteArray geometry; + bool isMax; + QByteArray windowState; +}; + +class UserHistory +{ +public: + QString exportDir; + QString saveDir; + bool showDocuments; + QString screenShotPath; + QString sessionDir; + QString openDir; + QString protocolExportPath; }; - class AppConfig { private: AppConfig(); - ~AppConfig(); public: static AppConfig &Instance(); - bool Load(const char *file); - bool Save(); - string ToJsonString(); - void FromJson(string &json); + void LoadAll(); + void SaveApp(); + void SaveHistory(); + void SaveFrame(); + void SetProtocolFormat(const string &protocolName, const string &value); string GetProtocolFormat(const string &protocolName); public: - AppOptions _appOptions; - -private: - string m_fileName; - vector m_protocolFormats; + AppOptions _appOptions; + UserHistory _userHistory; + FrameOptions _frameOptions; }; diff --git a/DSView/pv/data/signaldata.cpp b/DSView/pv/data/signaldata.cpp index 19005905..31c60937 100755 --- a/DSView/pv/data/signaldata.cpp +++ b/DSView/pv/data/signaldata.cpp @@ -33,11 +33,7 @@ SignalData::SignalData() : } SignalData::~SignalData() {} - -double SignalData::samplerate() const -{ - return _samplerate; -} + void SignalData::set_samplerate(double samplerate) { diff --git a/DSView/pv/data/signaldata.h b/DSView/pv/data/signaldata.h index 7ade4ddd..76f9588a 100755 --- a/DSView/pv/data/signaldata.h +++ b/DSView/pv/data/signaldata.h @@ -35,17 +35,17 @@ class SignalData public: SignalData(); virtual ~SignalData() = 0; + public: - double samplerate() const; + inline double samplerate()const + {return _samplerate; } + void set_samplerate(double samplerate); - virtual void clear() = 0; - virtual void init() = 0; protected: mutable boost::recursive_mutex _mutex; - double _samplerate; }; diff --git a/DSView/pv/devicemanager.cpp b/DSView/pv/devicemanager.cpp index aacfd7d1..08bf0946 100755 --- a/DSView/pv/devicemanager.cpp +++ b/DSView/pv/devicemanager.cpp @@ -29,8 +29,7 @@ #include #include #include - -#include + #include #include #include diff --git a/DSView/pv/dialogs/about.cpp b/DSView/pv/dialogs/about.cpp index ef9079b5..a0a40099 100755 --- a/DSView/pv/dialogs/about.cpp +++ b/DSView/pv/dialogs/about.cpp @@ -31,6 +31,7 @@ #include #include "about.h" +#include "../config/appconfig.h" namespace pv { namespace dialogs { @@ -80,7 +81,11 @@ About::About(QWidget *parent) : QDir dir(DS_RES_PATH); dir.cdUp(); #endif - QString filename = dir.absolutePath() + "/NEWS" + QString::number(qApp->property("Language").toInt()); + + AppConfig &app = AppConfig::Instance(); + int lan = app._frameOptions.language; + + QString filename = dir.absolutePath() + "/NEWS" + QString::number(lan); QFile news(filename); if (news.open(QIODevice::ReadOnly)) { QTextCodec *code=QTextCodec::codecForName("UTF-8"); diff --git a/DSView/pv/dialogs/applicationpardlg.cpp b/DSView/pv/dialogs/applicationpardlg.cpp index 469e0657..ed4e99fc 100644 --- a/DSView/pv/dialogs/applicationpardlg.cpp +++ b/DSView/pv/dialogs/applicationpardlg.cpp @@ -49,10 +49,10 @@ bool ApplicationParamDlg::ShowDlg(QWidget *parent) lay.setContentsMargins(0,20,0,30); //show config - AppOptions &_app = AppConfig::Instance()._appOptions; + AppConfig &app = AppConfig::Instance(); QCheckBox *ck_quickScroll = new QCheckBox(); - ck_quickScroll->setChecked(_app.quickScroll); + ck_quickScroll->setChecked(app._appOptions.quickScroll); lay.addRow("Quick scroll", ck_quickScroll); dlg.layout()->addLayout(&lay); @@ -62,9 +62,8 @@ bool ApplicationParamDlg::ShowDlg(QWidget *parent) //save config if (ret){ - _app.quickScroll = ck_quickScroll->isChecked(); - - AppConfig::Instance().Save(); + app._appOptions.quickScroll = ck_quickScroll->isChecked(); + app.SaveApp(); } return ret; diff --git a/DSView/pv/dialogs/protocolexp.cpp b/DSView/pv/dialogs/protocolexp.cpp index 4d93b9f8..8956e4ad 100755 --- a/DSView/pv/dialogs/protocolexp.cpp +++ b/DSView/pv/dialogs/protocolexp.cpp @@ -22,8 +22,7 @@ #include "protocolexp.h" #include - -#include + #include #include #include @@ -39,6 +38,7 @@ #include "../data/decode/annotation.h" #include "../view/decodetrace.h" #include "../data/decodermodel.h" +#include "../config/appconfig.h" using namespace boost; using namespace std; @@ -118,15 +118,20 @@ void ProtocolExp::accept() if(i < supportedFormats.count() - 1) filter.append(";;"); } - const QString DIR_KEY("ProtocolExportPath"); - QSettings settings(QApplication::organizationName(), QApplication::applicationName()); + + AppConfig &app = AppConfig::Instance(); + QString default_filter = _format_combobox->currentText(); - QString default_name = settings.value(DIR_KEY).toString() + "/" + "decoder-"; + QString default_name = app._userHistory.protocolExportPath + "/" + "decoder-"; default_name += _session.get_session_time().toString("-yyMMdd-hhmmss"); QString file_name = QFileDialog::getSaveFileName( - this, tr("Export Data"), default_name,filter,&default_filter); + this, + tr("Export Data"), + default_name,filter, + &default_filter); + if (!file_name.isEmpty()) { QFileInfo f(file_name); QStringList list = default_filter.split('.').last().split(')'); @@ -134,8 +139,12 @@ void ProtocolExp::accept() if(f.suffix().compare(ext)) file_name+=tr(".")+ext; - QDir CurrentDir; - settings.setValue(DIR_KEY, CurrentDir.filePath(file_name)); + QString fname = GetDirectoryName(file_name); + if (fname != app._userHistory.openDir) + { + app._userHistory.protocolExportPath = fname; + app.SaveHistory(); + } QFile file(file_name); file.open(QIODevice::WriteOnly | QIODevice::Text); diff --git a/DSView/pv/dialogs/waitingdialog.cpp b/DSView/pv/dialogs/waitingdialog.cpp index f4144ec5..c901cbdf 100755 --- a/DSView/pv/dialogs/waitingdialog.cpp +++ b/DSView/pv/dialogs/waitingdialog.cpp @@ -32,6 +32,7 @@ #include "../view/trace.h" #include "../view/dsosignal.h" +#include "../config/appconfig.h" using namespace boost; using namespace std; @@ -62,7 +63,7 @@ WaitingDialog::WaitingDialog(QWidget *parent, SigSession &session, int key) : warning_tips->setFont(font); warning_tips->setAlignment(Qt::AlignCenter); - QString iconPath = ":/icons/" + qApp->property("Style").toString(); + QString iconPath = GetIconPath(); label = new QLabel(this); movie = new QMovie(iconPath+"/wait.gif"); label->setMovie(movie); diff --git a/DSView/pv/dock/dsotriggerdock.cpp b/DSView/pv/dock/dsotriggerdock.cpp index 5e54dce7..08bc64b6 100755 --- a/DSView/pv/dock/dsotriggerdock.cpp +++ b/DSView/pv/dock/dsotriggerdock.cpp @@ -200,7 +200,7 @@ void DsoTriggerDock::retranslateUi() void DsoTriggerDock::reStyle() { - //QString iconPath = ":/icons/" + qApp->property("Style").toString(); + } void DsoTriggerDock::paintEvent(QPaintEvent *) diff --git a/DSView/pv/dock/measuredock.cpp b/DSView/pv/dock/measuredock.cpp index 0892d229..fc7644f6 100755 --- a/DSView/pv/dock/measuredock.cpp +++ b/DSView/pv/dock/measuredock.cpp @@ -41,6 +41,7 @@ #include #include #include +#include "../config/appconfig.h" using namespace boost; @@ -183,7 +184,7 @@ void MeasureDock::retranslateUi() void MeasureDock::reStyle() { - QString iconPath = ":/icons/" + qApp->property("Style").toString(); + QString iconPath = GetIconPath(); _dist_add_btn->setIcon(QIcon(iconPath+"/add.svg")); _edge_add_btn->setIcon(QIcon(iconPath+"/add.svg")); @@ -247,7 +248,7 @@ void MeasureDock::cursor_update() update_edge(); int index = 1; - QString iconPath = ":/icons/" + qApp->property("Style").toString(); + QString iconPath = GetIconPath(); for(std::list::iterator i = _view.get_cursorList().begin(); i != _view.get_cursorList().end(); i++) { QString curCursor = QString::number(index); @@ -336,7 +337,7 @@ void MeasureDock::add_dist_measure() row_widget->setLayout(row_layout); _dist_row_widget_vec.push_back(row_widget); - QString iconPath = ":/icons/" + qApp->property("Style").toString(); + QString iconPath = GetIconPath(); QToolButton *del_btn = new QToolButton(row_widget); del_btn->setIcon(QIcon(iconPath+"/del.svg")); del_btn->setCheckable(true); @@ -402,7 +403,7 @@ void MeasureDock::add_edge_measure() row_widget->setLayout(row_layout); _edge_row_widget_vec.push_back(row_widget); - QString iconPath = ":/icons/" + qApp->property("Style").toString(); + QString iconPath = GetIconPath(); QToolButton *del_btn = new QToolButton(row_widget); del_btn->setIcon(QIcon(iconPath+"/del.svg")); del_btn->setCheckable(true); diff --git a/DSView/pv/dock/protocoldock.cpp b/DSView/pv/dock/protocoldock.cpp index 9098ca94..c4709222 100755 --- a/DSView/pv/dock/protocoldock.cpp +++ b/DSView/pv/dock/protocoldock.cpp @@ -234,7 +234,7 @@ void ProtocolDock::retranslateUi() void ProtocolDock::reStyle() { - QString iconPath = ":/icons/" + qApp->property("Style").toString(); + QString iconPath = GetIconPath(); _add_button->setIcon(QIcon(iconPath+"/add.svg")); _del_all_button->setIcon(QIcon(iconPath+"/del.svg")); @@ -777,7 +777,6 @@ void ProtocolDock::OnProtocolFormatChanged(QString format, void *handle){ if ((*it) == handle){ QString &name = (*it)->GetProtocolName(); AppConfig::Instance().SetProtocolFormat(name.toStdString(), format.toStdString()); - AppConfig::Instance().Save(); (*it)->m_decoderStatus->m_format = DecoderDataFormat::Parse(format.toStdString().c_str()); protocol_updated(); break; diff --git a/DSView/pv/dock/protocolitemlayer.cpp b/DSView/pv/dock/protocolitemlayer.cpp index 5a51dce1..bde54209 100644 --- a/DSView/pv/dock/protocolitemlayer.cpp +++ b/DSView/pv/dock/protocolitemlayer.cpp @@ -23,6 +23,7 @@ #include "../dsvdef.h" #include #include +#include "../config/appconfig.h" namespace pv { namespace dock { @@ -41,7 +42,7 @@ ProtocolItemLayer::ProtocolItemLayer(QWidget *parent, QString protocolName, IPro _del_button = new QPushButton(parent); _format_combox = new QComboBox(parent); - QString iconPath = ":/icons/" + qApp->property("Style").toString(); + QString iconPath = GetIconPath(); _del_button->setFlat(true); _del_button->setIcon(QIcon(iconPath + "/del.svg")); _set_button->setFlat(true); @@ -107,7 +108,7 @@ void ProtocolItemLayer::on_format_select_changed(int index){ } void ProtocolItemLayer::ResetStyle(){ - QString iconPath = ":/icons/" + qApp->property("Style").toString(); + QString iconPath = GetIconPath(); _del_button->setIcon(QIcon(iconPath + "/del.svg")); _set_button->setIcon(QIcon(iconPath + "/gear.svg")); } diff --git a/DSView/pv/dock/searchdock.cpp b/DSView/pv/dock/searchdock.cpp index 162b58a0..1372ca78 100755 --- a/DSView/pv/dock/searchdock.cpp +++ b/DSView/pv/dock/searchdock.cpp @@ -42,6 +42,7 @@ #include #include +#include "../config/appconfig.h" namespace pv { namespace dock { @@ -109,7 +110,7 @@ void SearchDock::retranslateUi() void SearchDock::reStyle() { - QString iconPath = ":/icons/" + qApp->property("Style").toString(); + QString iconPath = GetIconPath(); _pre_button.setIcon(QIcon(iconPath+"/pre.svg")); _nxt_button.setIcon(QIcon(iconPath+"/next.svg")); diff --git a/DSView/pv/dock/triggerdock.cpp b/DSView/pv/dock/triggerdock.cpp index 6c727e85..e38ea7dc 100755 --- a/DSView/pv/dock/triggerdock.cpp +++ b/DSView/pv/dock/triggerdock.cpp @@ -160,7 +160,7 @@ void TriggerDock::retranslateUi() void TriggerDock::reStyle() { - //QString iconPath = ":/icons/" + qApp->property("Style").toString(); + } void TriggerDock::paintEvent(QPaintEvent *) diff --git a/DSView/pv/mainframe.cpp b/DSView/pv/mainframe.cpp index 50759235..9beb1187 100755 --- a/DSView/pv/mainframe.cpp +++ b/DSView/pv/mainframe.cpp @@ -39,10 +39,13 @@ #include #include #include -#include -#include +#include #include +#include + #include "dsvdef.h" +#include "config/appconfig.h" +#include "../ui/msgbox.h" #include @@ -132,6 +135,7 @@ MainFrame::MainFrame(DeviceManager &device_manager, connect(&_timer, SIGNAL(timeout()), this, SLOT(unfreezing())); //readSettings(); + } void MainFrame::changeEvent(QEvent* event) @@ -364,34 +368,20 @@ bool MainFrame::eventFilter(QObject *object, QEvent *event) } void MainFrame::writeSettings() -{ - QSettings settings(QApplication::organizationName(), QApplication::applicationName()); - - settings.beginGroup("MainFrame"); - settings.setValue("style", qApp->property("Style").toString()); - settings.setValue("language", qApp->property("Language").toInt()); - settings.setValue("geometry", saveGeometry()); - settings.setValue("isMax", isMaximized()); - settings.endGroup(); +{ + AppConfig &app = AppConfig::Instance(); + app._frameOptions.isMax = isMaximized(); + app._frameOptions.geometry = saveGeometry(); + app.SaveFrame(); } void MainFrame::readSettings() { - QSettings settings(QApplication::organizationName(), QApplication::applicationName()); + AppConfig &app = AppConfig::Instance(); + + _mainWindow->switchLanguage(app._frameOptions.language); - settings.beginGroup("MainFrame"); - bool isMax = settings.value("isMax", false).toBool(); - const QByteArray geometry = settings.value("geometry", QByteArray()).toByteArray(); - // defaut language - if (settings.contains("language")) { - _mainWindow->switchLanguage(settings.value("language").toInt()); - } else { - QLocale locale; - _mainWindow->switchLanguage(locale.language()); - } - settings.endGroup(); - - if (geometry.isEmpty()) { + if (app._frameOptions.geometry.isEmpty()) { QScreen *screen=QGuiApplication::primaryScreen (); const QRect availableGeometry = screen->availableGeometry(); resize(availableGeometry.width() / 2, availableGeometry.height() / 1.5); @@ -399,12 +389,20 @@ void MainFrame::readSettings() const int origY = std::max(0, (availableGeometry.height() - height()) / 2); move(origX, origY); } else { - restoreGeometry(geometry); + try + { + QByteArray ge = app._frameOptions.geometry; + restoreGeometry(ge); + } + catch(...) + { + MsgBox::Show(NULL, "restore frame status error!"); + } } // restore dockwidgets _mainWindow->restore_dock(); - _titleBar->setRestoreButton(isMax); + _titleBar->setRestoreButton(app._frameOptions.isMax); } void MainFrame::setTaskbarProgress(int progress) @@ -414,14 +412,15 @@ void MainFrame::setTaskbarProgress(int progress) void MainFrame::show_doc() { - const QString DOC_KEY("ShowDocuments"); - QSettings settings(QApplication::organizationName(), QApplication::applicationName()); - if (!settings.contains(DOC_KEY)) { + AppConfig &app = AppConfig::Instance(); + int lan = app._frameOptions.language; + + if (app._userHistory.showDocuments) { dialogs::DSDialog dlg(this, true); dlg.setTitle(tr("Document")); QLabel tipsLabel; - tipsLabel.setPixmap(QPixmap(":/icons/showDoc"+QString::number(_mainWindow->language())+".png")); + tipsLabel.setPixmap(QPixmap(":/icons/showDoc"+QString::number(lan)+".png")); QMessageBox msg; msg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint); msg.setContentsMargins(0, 0, 0, 0); @@ -441,8 +440,10 @@ void MainFrame::show_doc() if (msg.clickedButton() == openButton) { _mainWindow->openDoc(); } - if (msg.clickedButton() == noMoreButton) - settings.setValue(DOC_KEY, false); + if (msg.clickedButton() == noMoreButton){ + app._userHistory.showDocuments = false; + app.SaveHistory(); + } } } diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index 70828a2a..0e6294fe 100755 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -21,17 +21,16 @@ */ -#ifdef ENABLE_DECODE + #include #include "dock/protocoldock.h" -#endif + #include #include #include #include -#include #include #include #include @@ -48,6 +47,7 @@ #include #include #include +#include #include "mainwindow.h" @@ -91,6 +91,7 @@ #include #include #include "../ui/msgbox.h" +#include "config/appconfig.h" using boost::shared_ptr; using boost::dynamic_pointer_cast; @@ -174,7 +175,7 @@ void MainWindow::setup_ui() addToolBar(_logo_bar); // Setup the dockWidget -#ifdef ENABLE_DECODE + // protocol dock _protocol_dock=new QDockWidget(tr("Protocol"),this); _protocol_dock->setObjectName("protocol_dock"); @@ -186,7 +187,7 @@ void MainWindow::setup_ui() _protocol_dock->setWidget(_protocol_widget); qDebug() << "Protocol decoder enabled!\n"; -#endif + // measure dock _measure_dock=new QDockWidget(tr("Measurement"),this); _measure_dock->setObjectName("measure_dock"); @@ -206,9 +207,9 @@ void MainWindow::setup_ui() _search_widget = new dock::SearchDock(_search_dock, *_view, _session); _search_dock->setWidget(_search_widget); -#ifdef ENABLE_DECODE + addDockWidget(Qt::RightDockWidgetArea,_protocol_dock); -#endif + addDockWidget(Qt::RightDockWidgetArea,_trigger_dock); addDockWidget(Qt::RightDockWidgetArea,_dso_trigger_dock); addDockWidget(Qt::RightDockWidgetArea, _measure_dock); @@ -228,9 +229,9 @@ void MainWindow::setup_ui() _logo_bar->installEventFilter(this); _dso_trigger_dock->installEventFilter(this); _trigger_dock->installEventFilter(this); -#ifdef ENABLE_DECODE + _protocol_dock->installEventFilter(this); -#endif + _measure_dock->installEventFilter(this); _search_dock->installEventFilter(this); @@ -239,13 +240,10 @@ void MainWindow::setup_ui() QString(tr("Set Default Device failed")), _1)); // defaut language - QSettings settings(QApplication::organizationName(), QApplication::applicationName()); - QLocale locale; - settings.beginGroup("MainFrame"); - switchLanguage(settings.value("language", locale.language()).toInt()); - switchTheme(settings.value("style", "dark").toString()); - settings.endGroup(); - + AppConfig &app = AppConfig::Instance(); + switchLanguage(app._frameOptions.language); + switchTheme(app._frameOptions.style); + // UI initial _measure_widget->add_dist_measure(); @@ -288,9 +286,9 @@ void MainWindow::setup_ui() connect(_logo_bar, SIGNAL(setLanguage(int)), this, SLOT(switchLanguage(int))); connect(_logo_bar, SIGNAL(openDoc()), this, SLOT(openDoc())); -#ifdef ENABLE_DECODE + connect(_protocol_widget, SIGNAL(protocol_updated()), _view, SLOT(signals_changed())); -#endif + connect(_sampling_bar, SIGNAL(device_selected()), this, SLOT(update_device_list())); connect(_sampling_bar, SIGNAL(device_updated()), this, SLOT(reload())); @@ -329,21 +327,23 @@ void MainWindow::update_device_list() if (_msg) _msg->close(); - switchLanguage(_language); + AppConfig &app = AppConfig::Instance(); + + switchLanguage(app._frameOptions.language); _session.stop_capture(); _view->reload(); _trigger_widget->device_updated(); -#ifdef ENABLE_DECODE + _protocol_widget->del_all_protocol(); -#endif + _trig_bar->reload(); - shared_ptr selected_device = _session.get_device(); + boost::shared_ptr selected_device = _session.get_device(); _device_manager.add_device(selected_device); _session.init_signals(); _sampling_bar->set_device_list(_device_manager.devices(), selected_device); - shared_ptr file_dev; + boost::shared_ptr file_dev; if((file_dev = dynamic_pointer_cast(selected_device))) { // check version if (selected_device->dev_inst()->mode == LOGIC) { @@ -360,11 +360,11 @@ void MainWindow::update_device_list() } } - #ifdef ENABLE_DECODE + // load decoders StoreSession ss(_session); ss.load_decoders(_protocol_widget, file_dev->get_decoders()); - #endif + // load session load_session_json(file_dev->get_session(), true); @@ -386,7 +386,7 @@ void MainWindow::update_device_list() #endif if (dir.exists()) { QString str = dir.absolutePath() + "/"; - QString lang_name = ".ses" + QString::number(_language); + QString lang_name = ".ses" + QString::number(app._frameOptions.language); QString ses_name = str + selected_device->name() + QString::number(selected_device->dev_inst()->mode) + @@ -712,11 +712,14 @@ void MainWindow::session_save() #else QString path = QStandardPaths::writableLocation(QStandardPaths::DataLocation); #endif + + AppConfig &app = AppConfig::Instance(); + if(dir.mkpath(path)) { dir.cd(path); QString driver_name = _session.get_device()->name(); QString mode_name = QString::number(_session.get_device()->dev_inst()->mode); - QString lang_name = ".ses" + QString::number(_language); + QString lang_name = ".ses" + QString::number(app._frameOptions.language); QString file_name = dir.absolutePath() + "/" + driver_name + mode_name + lang_name + ".dsc"; @@ -725,9 +728,9 @@ void MainWindow::session_save() store_session(file_name); } } - - QSettings settings(QApplication::organizationName(), QApplication::applicationName()); - settings.setValue("windowState", saveState()); + + app._frameOptions.windowState = saveState(); + app.SaveFrame(); } void MainWindow::closeEvent(QCloseEvent *event) @@ -739,9 +742,9 @@ void MainWindow::closeEvent(QCloseEvent *event) void MainWindow::on_protocol(bool visible) { -#ifdef ENABLE_DECODE + _protocol_dock->setVisible(visible); -#endif + } void MainWindow::on_trigger(bool visible) @@ -761,8 +764,8 @@ void MainWindow::on_trigger(bool visible) void MainWindow::commit_trigger(bool instant) { int i = 0; - const QString TRIG_KEY("WarnofMultiTrig"); - QSettings settings(QApplication::organizationName(), QApplication::applicationName()); + + AppConfig &app = AppConfig::Instance(); ds_trigger_init(); @@ -781,8 +784,7 @@ void MainWindow::commit_trigger(bool instant) i++; } } - if (!settings.contains(TRIG_KEY) && - i > 1) { + if (app._appOptions.warnofMultiTrig && i > 1) { dialogs::DSMessageBox msg(this); msg.mBox()->setText(tr("Trigger")); msg.mBox()->setInformativeText(tr("Trigger setted on multiple channels! " @@ -806,7 +808,10 @@ void MainWindow::commit_trigger(bool instant) } } if (msg.mBox()->clickedButton() == noMoreButton) - settings.setValue(TRIG_KEY, false); + { + app._appOptions.warnofMultiTrig = false; + app.SaveApp(); + } } } } @@ -824,9 +829,8 @@ void MainWindow::on_search(bool visible) void MainWindow::on_screenShot() { - const QString DIR_KEY("ScreenShotPath"); - QSettings settings(QApplication::organizationName(), QApplication::applicationName()); - QString default_name = settings.value(DIR_KEY).toString() + "/DSView" + QDateTime::currentDateTime().toString("-yyMMdd-hhmmss"); + AppConfig &app = AppConfig::Instance(); + QString default_name = app._userHistory.screenShotPath + "/DSView" + QDateTime::currentDateTime().toString("-yyMMdd-hhmmss"); QPixmap pixmap; QScreen *screen = QGuiApplication::primaryScreen(); QDesktopWidget *desktop = QApplication::desktop(); @@ -838,10 +842,16 @@ void MainWindow::on_screenShot() tr("Save As"), default_name, tr("%1 Files (*.%2);;All Files (*)") .arg(format.toUpper()).arg(format)); - if (!fileName.isEmpty()) { - QDir CurrentDir; - settings.setValue(DIR_KEY, CurrentDir.filePath(fileName)); + + if (!fileName.isEmpty()) { pixmap.save(fileName, format.toLatin1()); + + fileName = GetDirectoryName(fileName); + + if (app._userHistory.screenShotPath != fileName){ + app._userHistory.screenShotPath = fileName; + app.SaveHistory(); + } } } @@ -915,6 +925,8 @@ bool MainWindow::load_session_json(QJsonDocument json, bool file_dev) return false; } + AppConfig &app = AppConfig::Instance(); + // check language if (sessionObj.contains("Language")) { switchLanguage(sessionObj["Language"].toInt()); @@ -922,7 +934,7 @@ bool MainWindow::load_session_json(QJsonDocument json, bool file_dev) bool language_matched = _session.get_device()->set_config(NULL, NULL, SR_CONF_OPERATION_MODE, g_variant_new_string(sessionObj["Operation Mode"].toString().toUtf8())); if (!language_matched) { - if (_language != QLocale::Chinese) + if (app._frameOptions.language != QLocale::Chinese) switchLanguage(QLocale::Chinese); else switchLanguage(QLocale::English); @@ -930,11 +942,11 @@ bool MainWindow::load_session_json(QJsonDocument json, bool file_dev) } // clear decoders - #ifdef ENABLE_DECODE + if (sdi->mode == LOGIC) { _protocol_widget->del_all_protocol(); } - #endif + // load device settings GVariant *gvar_opts; @@ -1075,13 +1087,13 @@ bool MainWindow::load_session_json(QJsonDocument json, bool file_dev) } on_trigger(false); - #ifdef ENABLE_DECODE + // load decoders if (sessionObj.contains("decoder")) { StoreSession ss(_session); ss.load_decoders(_protocol_widget, sessionObj["decoder"].toArray()); } - #endif + // load measure if (sessionObj.contains("measure")) { @@ -1103,6 +1115,8 @@ bool MainWindow::store_session(QString name) outStream.setCodec("UTF-8"); //outStream.setGenerateByteOrderMark(true); // UTF-8 without BOM + AppConfig &app = AppConfig::Instance(); + GVariant *gvar_opts; GVariant *gvar; gsize num_opts; @@ -1112,7 +1126,7 @@ bool MainWindow::store_session(QString name) sessionVar["Version"]= QJsonValue::fromVariant(Session_Version); sessionVar["Device"] = QJsonValue::fromVariant(sdi->driver->name); sessionVar["DeviceMode"] = QJsonValue::fromVariant(sdi->mode); - sessionVar["Language"] = QJsonValue::fromVariant(_language); + sessionVar["Language"] = QJsonValue::fromVariant(app._frameOptions.language); if ((sr_config_list(sdi->driver, sdi, NULL, SR_CONF_DEVICE_SESSIONS, &gvar_opts) != SR_OK)) return false; /* Driver supports no device instance sessions. */ @@ -1180,10 +1194,10 @@ bool MainWindow::store_session(QString name) sessionVar["trigger"] = _trigger_widget->get_session(); } - #ifdef ENABLE_DECODE + StoreSession ss(_session); sessionVar["decoder"] = ss.json_decoders(); - #endif + if (_session.get_device()->dev_inst()->mode == DSO) { sessionVar["measure"] = _view->get_viewstatus()->get_session(); @@ -1198,9 +1212,20 @@ bool MainWindow::store_session(QString name) void MainWindow::restore_dock() { - // default dockwidget size - QSettings settings(QApplication::organizationName(), QApplication::applicationName()); - restoreState(settings.value("windowState").toByteArray()); + // default dockwidget size + AppConfig &app = AppConfig::Instance(); + QByteArray st = app._frameOptions.windowState; + if (!st.isEmpty()){ + try + { + restoreState(st); + } + catch(...) + { + MsgBox::Show(NULL, "restore window status error!"); + } + } + if (_session.get_device()->dev_inst()->mode != DSO) { _dso_trigger_dock->setVisible(false); _trig_bar->update_trig_btn(_trigger_dock->isVisible()); @@ -1209,9 +1234,9 @@ void MainWindow::restore_dock() _trig_bar->update_trig_btn(_dso_trigger_dock->isVisible()); } if (_session.get_device()->dev_inst()->mode != LOGIC) { -#ifdef ENABLE_DECODE + on_protocol(false); -#endif + } _trig_bar->update_protocol_btn(_protocol_dock->isVisible()); _trig_bar->update_measure_btn(_measure_dock->isVisible()); @@ -1223,7 +1248,7 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) (void) object; if ( event->type() == QEvent::KeyPress ) { - const vector< shared_ptr > sigs(_session.get_signals()); + const vector< boost::shared_ptr > sigs(_session.get_signals()); QKeyEvent *ke = (QKeyEvent *) event; switch(ke->key()) { case Qt::Key_S: @@ -1238,11 +1263,11 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) else on_trigger(!_trigger_dock->isVisible()); break; -#ifdef ENABLE_DECODE + case Qt::Key_D: on_protocol(!_protocol_dock->isVisible()); break; -#endif + case Qt::Key_M: on_measure(!_measure_dock->isVisible()); break; @@ -1268,8 +1293,8 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) _view->zoom(-1); break; case Qt::Key_0: - BOOST_FOREACH(const shared_ptr s, sigs) { - shared_ptr dsoSig; + BOOST_FOREACH(const boost::shared_ptr s, sigs) { + boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s))) { if (dsoSig->get_index() == 0) dsoSig->set_vDialActive(!dsoSig->get_vDialActive()); @@ -1281,8 +1306,8 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) update(); break; case Qt::Key_1: - BOOST_FOREACH(const shared_ptr s, sigs) { - shared_ptr dsoSig; + BOOST_FOREACH(const boost::shared_ptr s, sigs) { + boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s))) { if (dsoSig->get_index() == 1) dsoSig->set_vDialActive(!dsoSig->get_vDialActive()); @@ -1294,8 +1319,8 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) update(); break; case Qt::Key_Up: - BOOST_FOREACH(const shared_ptr s, sigs) { - shared_ptr dsoSig; + BOOST_FOREACH(const boost::shared_ptr s, sigs) { + boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s))) { if (dsoSig->get_vDialActive()) { dsoSig->go_vDialNext(true); @@ -1306,8 +1331,8 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) } break; case Qt::Key_Down: - BOOST_FOREACH(const shared_ptr s, sigs) { - shared_ptr dsoSig; + BOOST_FOREACH(const boost::shared_ptr s, sigs) { + boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s))) { if (dsoSig->get_vDialActive()) { dsoSig->go_vDialPre(true); @@ -1324,46 +1349,51 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) } return false; } - -int MainWindow::language() const -{ - return _language; -} - + void MainWindow::switchLanguage(int language) { - shared_ptr dev = _session.get_device(); + boost::shared_ptr dev = _session.get_device(); dev->set_config(NULL, NULL, SR_CONF_LANGUAGE, g_variant_new_int16(language)); + AppConfig &app = AppConfig::Instance(); - if (_language != language) { - _language = language; - if (_language != QLocale::English) { - _qtTrans.load(":/qt_"+QString::number(_language)); - qApp->installTranslator(&_qtTrans); - _myTrans.load(":/my_"+QString::number(_language)); - qApp->installTranslator(&_myTrans); - retranslateUi(); - } else { - qApp->removeTranslator(&_qtTrans); - qApp->removeTranslator(&_myTrans); - retranslateUi(); - } - qApp->setProperty("Language", _language); + if (app._frameOptions.language != language) + { + app._frameOptions.language = language; + app.SaveFrame(); + } + + if (language != QLocale::English) + { + _qtTrans.load(":/qt_" + QString::number(language)); + qApp->installTranslator(&_qtTrans); + _myTrans.load(":/my_" + QString::number(language)); + qApp->installTranslator(&_myTrans); + retranslateUi(); + } + else + { + qApp->removeTranslator(&_qtTrans); + qApp->removeTranslator(&_myTrans); + retranslateUi(); } } void MainWindow::switchTheme(QString style) { - if (_style != style) { - _style = style; - qApp->setProperty("Style", _style); - QString qssRes = ":/"+_style+".qss"; - QFile qss(qssRes); - qss.open(QFile::ReadOnly | QFile::Text); - qApp->setStyleSheet(qss.readAll()); - qss.close(); - _session.data_updated(); + AppConfig &app = AppConfig::Instance(); + + if (app._frameOptions.style != style) + { + app._frameOptions.style = style; + app.SaveFrame(); } + + QString qssRes = ":/" + style + ".qss"; + QFile qss(qssRes); + qss.open(QFile::ReadOnly | QFile::Text); + qApp->setStyleSheet(qss.readAll()); + qss.close(); + _session.data_updated(); } void MainWindow::openDoc() @@ -1374,8 +1404,10 @@ void MainWindow::openDoc() QDir dir(DS_RES_PATH); dir.cdUp(); #endif + AppConfig &app = AppConfig::Instance(); + int lan = app._frameOptions.language; QDesktopServices::openUrl( - QUrl("file:///"+dir.absolutePath() + "/ug"+QString::number(_language)+".pdf")); + QUrl("file:///"+dir.absolutePath() + "/ug"+QString::number(lan)+".pdf")); } } // namespace pv diff --git a/DSView/pv/mainwindow.h b/DSView/pv/mainwindow.h index 0069b1e5..59fd8d3b 100755 --- a/DSView/pv/mainwindow.h +++ b/DSView/pv/mainwindow.h @@ -88,7 +88,7 @@ private: public slots: void session_save(); - int language() const; + void openDoc(); void switchLanguage(int language); @@ -190,10 +190,10 @@ private: toolbars::FileBar *_file_bar; toolbars::LogoBar *_logo_bar; //help button, on top right -#ifdef ENABLE_DECODE + QDockWidget *_protocol_dock; dock::ProtocolDock *_protocol_widget; -#endif + QDockWidget *_trigger_dock; QDockWidget *_dso_trigger_dock; @@ -204,8 +204,6 @@ private: QDockWidget *_search_dock; dock::SearchDock * _search_widget; - int _language; - QString _style; QTranslator _qtTrans; QTranslator _myTrans; }; diff --git a/DSView/pv/sigsession.cpp b/DSView/pv/sigsession.cpp index 1912088f..7ceed522 100755 --- a/DSView/pv/sigsession.cpp +++ b/DSView/pv/sigsession.cpp @@ -20,9 +20,9 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifdef ENABLE_DECODE + #include -#endif + #include "sigsession.h" #include "mainwindow.h" @@ -110,9 +110,9 @@ SigSession::SigSession(DeviceManager &device_manager) : _noData_cnt = 0; _data_lock = false; _data_updated = false; - #ifdef ENABLE_DECODE + _decoder_model = new pv::data::DecoderModel(this); - #endif + _lissajous_trace = NULL; _math_trace = NULL; _saving = false; @@ -173,9 +173,9 @@ void SigSession::set_device(boost::shared_ptr dev_inst) } _dev_inst = dev_inst; -#ifdef ENABLE_DECODE + _decode_traces.clear(); -#endif + _group_traces.clear(); if (_dev_inst) { @@ -324,11 +324,11 @@ void SigSession::set_cur_snap_samplerate(uint64_t samplerate) if (_group_data) _group_data->set_samplerate(_cur_snap_samplerate); -#ifdef ENABLE_DECODE + // DecoderStack BOOST_FOREACH(const boost::shared_ptr d, _decode_traces) d->decoder()->set_samplerate(_cur_snap_samplerate); -#endif + // Math if (_math_trace && _math_trace->enabled()) _math_trace->get_math_stack()->set_samplerate(_dev_inst->get_sample_rate()); @@ -415,7 +415,7 @@ void SigSession::container_init() if (_math_trace) _math_trace->get_math_stack()->init(); -#ifdef ENABLE_DECODE + // DecoderModel //pv::data::DecoderModel *decoder_model = get_decoder_model(); //decoder_model->setDecoderStack(NULL); @@ -425,7 +425,7 @@ void SigSession::container_init() assert(d); d->decoder()->init(); } -#endif + } void SigSession::start_capture(bool instant, @@ -489,13 +489,13 @@ void SigSession::start_capture(bool instant, void SigSession::stop_capture() { data_unlock(); -#ifdef ENABLE_DECODE + for (vector< boost::shared_ptr >::iterator i = _decode_traces.begin(); i != _decode_traces.end(); i++) (*i)->decoder()->stop_decode(); -#endif + if (get_capture_state() != Running) return; @@ -707,10 +707,10 @@ void SigSession::init_signals() if (_group_data) _group_data->clear(); -#ifdef ENABLE_DECODE + // Clear the decode traces _decode_traces.clear(); -#endif + // Detect what data types we will receive if(_dev_inst) { @@ -865,13 +865,13 @@ void SigSession::refresh(int holdtime) if (_logic_data) { _logic_data->init(); //_cur_logic_snapshot.reset(); -#ifdef ENABLE_DECODE + BOOST_FOREACH(const boost::shared_ptr d, _decode_traces) { assert(d); d->decoder()->init(); } -#endif + } if (_dso_data) { _dso_data->init(); @@ -1143,6 +1143,7 @@ void SigSession::data_feed_in(const struct sr_dev_inst *sdi, if (_data_lock && packet->type != SR_DF_END) return; + if (packet->type != SR_DF_END && packet->status != SR_PKT_OK) { _error = Pkt_data_err; @@ -1207,10 +1208,10 @@ void SigSession::data_feed_in(const struct sr_dev_inst *sdi, _cur_logic_snapshot->capture_ended(); _cur_dso_snapshot->capture_ended(); _cur_analog_snapshot->capture_ended(); -#ifdef ENABLE_DECODE + BOOST_FOREACH(const boost::shared_ptr d, _decode_traces) d->frame_ended(); -#endif + } if (packet->status != SR_PKT_OK) { @@ -1366,7 +1367,7 @@ uint16_t SigSession::get_ch_num(int type) return num_channels; } -#ifdef ENABLE_DECODE + bool SigSession::add_decoder(srd_decoder *const dec, bool silent, DecoderStatus *dstatus) { bool ret = false; @@ -1506,7 +1507,7 @@ pv::data::DecoderModel* SigSession::get_decoder_model() const { return _decoder_model; } -#endif + void SigSession::spectrum_rebuild() { diff --git a/DSView/pv/sigsession.h b/DSView/pv/sigsession.h index c895c07e..6d66c0b5 100755 --- a/DSView/pv/sigsession.h +++ b/DSView/pv/sigsession.h @@ -179,7 +179,7 @@ public: std::vector< boost::shared_ptr > get_group_signals(); -#ifdef ENABLE_DECODE + bool add_decoder(srd_decoder *const dec, bool silent, DecoderStatus *dstatus); std::vector< boost::shared_ptr > @@ -194,7 +194,7 @@ public: void rst_decoder(view::DecodeTrace *signal); pv::data::DecoderModel* get_decoder_model() const; -#endif + std::vector< boost::shared_ptr > get_spectrum_traces(); @@ -323,10 +323,10 @@ private: //mutable boost::mutex _signals_mutex; std::vector< boost::shared_ptr > _signals; std::vector< boost::shared_ptr > _group_traces; -#ifdef ENABLE_DECODE + std::vector< boost::shared_ptr > _decode_traces; pv::data::DecoderModel *_decoder_model; -#endif + std::vector< boost::shared_ptr > _spectrum_traces; boost::shared_ptr _lissajous_trace; boost::shared_ptr _math_trace; diff --git a/DSView/pv/storesession.cpp b/DSView/pv/storesession.cpp index ca8c51d2..5c9c7eef 100755 --- a/DSView/pv/storesession.cpp +++ b/DSView/pv/storesession.cpp @@ -41,13 +41,13 @@ #include #include - -#include + #include +#include "config/appconfig.h" + using boost::dynamic_pointer_cast; using boost::mutex; -using boost::shared_ptr; using boost::thread; using boost::lock_guard; using std::deque; @@ -161,10 +161,20 @@ bool StoreSession::save_start(QString session_file) _error = tr("No data to save."); return false; } + + + //root dir + QString default_name; + + AppConfig &app = AppConfig::Instance(); + if (app._userHistory.saveDir != "") + { + default_name = app._userHistory.saveDir + "/" + _session.get_device()->name() + "-"; + } + else{ + default_name = _session.get_device()->name() + "-"; + } - const QString DIR_KEY("SavePath"); - QSettings settings(QApplication::organizationName(), QApplication::applicationName()); - QString default_name = settings.value(DIR_KEY).toString() + "/" + _session.get_device()->name() + "-"; for (const GSList *l = _session.get_device()->get_dev_mode_list(); l; l = l->next) { const sr_dev_mode *mode = (const sr_dev_mode *)l->data; @@ -173,26 +183,32 @@ bool StoreSession::save_start(QString session_file) break; } } + default_name += _session.get_session_time().toString("-yyMMdd-hhmmss"); // Show the dialog - _file_name = QFileDialog::getSaveFileName( - NULL, tr("Save File"), default_name, + QString svFilePath = QFileDialog::getSaveFileName( + NULL, + tr("Save File"), + default_name, tr("DSView Data (*.dsl)")); - if (!_file_name.isEmpty()) { - QFileInfo f(_file_name); + if (!svFilePath.isEmpty()) { + QFileInfo f(svFilePath); if(f.suffix().compare("dsl")) - _file_name.append(tr(".dsl")); - QDir CurrentDir; - settings.setValue(DIR_KEY, CurrentDir.filePath(_file_name)); + svFilePath.append(tr(".dsl")); + + _file_name = svFilePath; + svFilePath = GetDirectoryName(svFilePath); + + if (svFilePath != app._userHistory.saveDir){ + app._userHistory.saveDir = svFilePath; + app.SaveHistory(); + } QString meta_file = meta_gen(snapshot); - #ifdef ENABLE_DECODE + QString decoders_file = decoders_gen(); - #else - QString decoders_file = NULL; - #endif /* if (meta_file == NULL) { @@ -233,15 +249,15 @@ bool StoreSession::save_start(QString session_file) return false; } -void StoreSession::save_proc(shared_ptr snapshot) +void StoreSession::save_proc(boost::shared_ptr snapshot) { assert(snapshot); int ret = SR_ERR; int num = 0; - shared_ptr logic_snapshot; - shared_ptr analog_snapshot; - shared_ptr dso_snapshot; + boost::shared_ptr logic_snapshot; + boost::shared_ptr analog_snapshot; + boost::shared_ptr dso_snapshot; if ((logic_snapshot = boost::dynamic_pointer_cast(snapshot))) { uint16_t to_save_probes = 0; @@ -424,7 +440,7 @@ QString StoreSession::meta_gen(boost::shared_ptr snapshot) fprintf(meta, "total blocks = %d\n", snapshot->get_block_num()); } - shared_ptr logic_snapshot; + boost::shared_ptr logic_snapshot; if ((logic_snapshot = dynamic_pointer_cast(snapshot))) { uint16_t to_save_probes = 0; for (l = sdi->channels; l; l = l->next) { @@ -479,7 +495,7 @@ QString StoreSession::meta_gen(boost::shared_ptr snapshot) } else if (sdi->mode == LOGIC) { fprintf(meta, "trigger time = %lld\n", _session.get_session_time().toMSecsSinceEpoch()); } else if (sdi->mode == ANALOG) { - shared_ptr analog_snapshot; + boost::shared_ptr analog_snapshot; if ((analog_snapshot = dynamic_pointer_cast(snapshot))) { uint8_t tmp_u8 = analog_snapshot->get_unit_bytes(); fprintf(meta, "bits = %d\n", tmp_u8*8); @@ -574,7 +590,8 @@ bool StoreSession::export_start() std::set type_set; BOOST_FOREACH(const boost::shared_ptr sig, _session.get_signals()) { assert(sig); - type_set.insert(sig->get_type()); + int _tp = sig->get_type(); + type_set.insert(_tp); } if (type_set.size() > 1) { @@ -594,9 +611,16 @@ bool StoreSession::export_start() return false; } - const QString DIR_KEY("ExportPath"); - QSettings settings(QApplication::organizationName(), QApplication::applicationName()); - QString default_name = settings.value(DIR_KEY).toString() + "/" + _session.get_device()->name() + "-"; + AppConfig &app = AppConfig::Instance(); + + QString default_name; + if (app._userHistory.exportDir != "") + { + default_name = app._userHistory.exportDir + "/" + _session.get_device()->name() + "-"; + } + else{ + default_name = _session.get_device()->name() + "-"; + } for (const GSList *l = _session.get_device()->get_dev_mode_list(); l; l = l->next) { @@ -616,17 +640,28 @@ bool StoreSession::export_start() if(i < supportedFormats.count() - 1) filter.append(";;"); } - _file_name = QFileDialog::getSaveFileName( - NULL, tr("Export Data"), default_name,filter,&filter); - if (!_file_name.isEmpty()) { + QString svFilePath = QFileDialog::getSaveFileName( + NULL, + tr("Export Data"), + default_name, + filter, + &filter); + + if (!svFilePath.isEmpty()) { QFileInfo f(_file_name); QStringList list = filter.split('.').last().split(')'); _suffix = list.first(); if(f.suffix().compare(_suffix)) - _file_name += tr(".") + _suffix; - QDir CurrentDir; - settings.setValue(DIR_KEY, CurrentDir.filePath(_file_name)); + svFilePath += tr(".") + _suffix; + + _file_name = svFilePath; + svFilePath = GetDirectoryName(svFilePath); + + if (svFilePath != app._userHistory.exportDir ){ + app._userHistory.exportDir = svFilePath; + app.SaveHistory(); + } const struct sr_output_module** supportedModules = sr_output_list(); while(*supportedModules){ @@ -651,13 +686,13 @@ bool StoreSession::export_start() return false; } -void StoreSession::export_proc(shared_ptr snapshot) +void StoreSession::export_proc(boost::shared_ptr snapshot) { assert(snapshot); - shared_ptr logic_snapshot; - shared_ptr analog_snapshot; - shared_ptr dso_snapshot; + boost::shared_ptr logic_snapshot; + boost::shared_ptr analog_snapshot; + boost::shared_ptr dso_snapshot; int channel_type; if ((logic_snapshot = boost::dynamic_pointer_cast(snapshot))) { @@ -835,7 +870,7 @@ void StoreSession::export_proc(shared_ptr snapshot) out << (char*) data_out->str; g_string_free(data_out,TRUE); } - + _units_stored += size; progress_updated(); } @@ -876,7 +911,7 @@ void StoreSession::export_proc(shared_ptr snapshot) progress_updated(); } -#ifdef ENABLE_DECODE + QString StoreSession::decoders_gen() { QDir dir; @@ -1129,7 +1164,7 @@ void StoreSession::load_decoders(dock::ProtocolDock *widget, QJsonArray dec_arra } } -#endif + double StoreSession::get_integer(GVariant *var) { diff --git a/DSView/pv/storesession.h b/DSView/pv/storesession.h index 09dc4e3a..75dcbb2a 100755 --- a/DSView/pv/storesession.h +++ b/DSView/pv/storesession.h @@ -26,7 +26,7 @@ #include #include - +#include #include #include @@ -75,15 +75,15 @@ private: void save_proc(boost::shared_ptr snapshot); QString meta_gen(boost::shared_ptr snapshot); void export_proc(boost::shared_ptr snapshot); - #ifdef ENABLE_DECODE + QString decoders_gen(); - #endif + public: - #ifdef ENABLE_DECODE + QJsonArray json_decoders(); void load_decoders(dock::ProtocolDock *widget, QJsonArray dec_array); - #endif + private: QList getSuportedExportFormats(); diff --git a/DSView/pv/toolbars/filebar.cpp b/DSView/pv/toolbars/filebar.cpp index ea0b47ac..14a337f7 100755 --- a/DSView/pv/toolbars/filebar.cpp +++ b/DSView/pv/toolbars/filebar.cpp @@ -24,12 +24,12 @@ #include #include -#include -#include +#include #include "filebar.h" #include "../device/devinst.h" #include "../ui/msgbox.h" +#include "../config/appconfig.h" #include @@ -54,6 +54,7 @@ FileBar::FileBar(SigSession &session, QWidget *parent) : _action_default = new QAction(this); _action_default->setObjectName(QString::fromUtf8("actionDefault")); + //second level menu _menu_session = new QMenu(this); _menu_session->setObjectName(QString::fromUtf8("menuSession")); _menu_session->addAction(_action_load); @@ -107,7 +108,7 @@ void FileBar::changeEvent(QEvent *event) void FileBar::retranslateUi() { _file_button.setText(tr("File")); - _menu_session->setTitle(tr("Con&fig...")); + _menu_session->setTitle(tr("Con&fig...")); //load,save session file _action_load->setText(tr("&Load...")); _action_store->setText(tr("S&tore...")); _action_default->setText(tr("&Default...")); @@ -119,7 +120,7 @@ void FileBar::retranslateUi() void FileBar::reStyle() { - QString iconPath = ":/icons/" + qApp->property("Style").toString(); + QString iconPath = GetIconPath(); _action_load->setIcon(QIcon(iconPath+"/open.svg")); _action_store->setIcon(QIcon(iconPath+"/save.svg")); @@ -134,15 +135,23 @@ void FileBar::reStyle() void FileBar::on_actionOpen_triggered() { - const QString DIR_KEY("OpenPath"); - QSettings settings(QApplication::organizationName(), QApplication::applicationName()); + //open data file + AppConfig &app = AppConfig::Instance(); + // Show the dialog const QString file_name = QFileDialog::getOpenFileName( - this, tr("Open File"), settings.value(DIR_KEY).toString(), tr( - "DSView Data (*.dsl)")); - if (!file_name.isEmpty()) { - QDir CurrentDir; - settings.setValue(DIR_KEY, CurrentDir.absoluteFilePath(file_name)); + this, + tr("Open File"), + app._userHistory.openDir, + tr("DSView Data (*.dsl)")); + + if (!file_name.isEmpty()) { + QString fname = GetDirectoryName(file_name); + if (fname != app._userHistory.openDir){ + app._userHistory.openDir = fname; + app.SaveHistory(); + } + load_file(file_name); } } @@ -162,16 +171,23 @@ void FileBar::show_session_error( } void FileBar::on_actionLoad_triggered() -{ - const QString DIR_KEY("SessionLoadPath"); - QSettings settings(QApplication::organizationName(), QApplication::applicationName()); - // Show the dialog +{ + //load session file + AppConfig &app = AppConfig::Instance(); + const QString file_name = QFileDialog::getOpenFileName( - this, tr("Open Session"), settings.value(DIR_KEY).toString(), tr( - "DSView Session (*.dsc)")); + this, + tr("Open Session"), + app._userHistory.sessionDir, + tr("DSView Session (*.dsc)")); + if (!file_name.isEmpty()) { - QDir CurrentDir; - settings.setValue(DIR_KEY, CurrentDir.absoluteFilePath(file_name)); + QString fname = GetDirectoryName(file_name); + if (fname != app._userHistory.sessionDir){ + app._userHistory.sessionDir = fname; + app.SaveHistory(); + } + load_session(file_name); } } @@ -205,17 +221,27 @@ void FileBar::on_actionDefault_triggered() void FileBar::on_actionStore_triggered() { - const QString DIR_KEY("SessionStorePath"); - QSettings settings(QApplication::organizationName(), QApplication::applicationName()); + //store session file + + AppConfig &app = AppConfig::Instance(); + QString file_name = QFileDialog::getSaveFileName( - this, tr("Save Session"), settings.value(DIR_KEY).toString(), + this, + tr("Save Session"), + app._userHistory.sessionDir, tr("DSView Session (*.dsc)")); + if (!file_name.isEmpty()) { QFileInfo f(file_name); if(f.suffix().compare("dsc")) file_name.append(tr(".dsc")); - QDir CurrentDir; - settings.setValue(DIR_KEY, CurrentDir.absoluteFilePath(file_name)); + + QString fname = GetDirectoryName(file_name); + if (fname != app._userHistory.sessionDir){ + app._userHistory.sessionDir = fname; + app.SaveHistory(); + } + store_session(file_name); } } diff --git a/DSView/pv/toolbars/logobar.cpp b/DSView/pv/toolbars/logobar.cpp index 0904c12b..8b0f8a05 100755 --- a/DSView/pv/toolbars/logobar.cpp +++ b/DSView/pv/toolbars/logobar.cpp @@ -23,14 +23,14 @@ #include #include -#include -#include +#include #include #include #include "logobar.h" #include "../dialogs/about.h" #include "../dialogs/dsmessagebox.h" +#include "../config/appconfig.h" namespace pv { namespace toolbars { @@ -116,7 +116,8 @@ void LogoBar::retranslateUi() _manual->setText(tr("&Manual")); _issue->setText(tr("&Bug Report")); - if (qApp->property("Language") == QLocale::Chinese) + AppConfig &app = AppConfig::Instance(); + if (app._frameOptions.language == QLocale::Chinese) _language->setIcon(QIcon(":/icons/Chinese.svg")); else _language->setIcon(QIcon(":/icons/English.svg")); @@ -124,7 +125,7 @@ void LogoBar::retranslateUi() void LogoBar::reStyle() { - QString iconPath = ":/icons/" + qApp->property("Style").toString(); + QString iconPath = GetIconPath(); _about->setIcon(QIcon(iconPath+"/about.svg")); _manual->setIcon(QIcon(iconPath+"/manual.svg")); @@ -138,7 +139,7 @@ void LogoBar::reStyle() void LogoBar::dsl_connected(bool conn) { _connected = conn; - QString iconPath = ":/icons/" + qApp->property("Style").toString(); + QString iconPath = GetIconPath(); if (_connected) _logo_button.setIcon(QIcon(iconPath+"/logo_color.svg")); else @@ -175,7 +176,7 @@ void LogoBar::on_actionCn_triggered() { _language->setIcon(QIcon::fromTheme("file", QIcon(":/icons/Chinese.svg"))); - setLanguage(QLocale::Chinese); + setLanguage(QLocale::Chinese); } void LogoBar::on_actionAbout_triggered() diff --git a/DSView/pv/toolbars/samplingbar.cpp b/DSView/pv/toolbars/samplingbar.cpp index 7a06a71d..2f3bd4fb 100755 --- a/DSView/pv/toolbars/samplingbar.cpp +++ b/DSView/pv/toolbars/samplingbar.cpp @@ -30,7 +30,6 @@ #include #include #include -#include #include "../devicemanager.h" #include "../device/devinst.h" @@ -39,9 +38,9 @@ #include "../dialogs/dsmessagebox.h" #include "../view/dsosignal.h" #include "../dialogs/interval.h" +#include "../config/appconfig.h" + -using namespace boost; -using boost::shared_ptr; using std::map; using std::max; using std::min; @@ -149,7 +148,7 @@ void SamplingBar::changeEvent(QEvent *event) void SamplingBar::retranslateUi() { - shared_ptr dev_inst = get_selected_device(); + boost::shared_ptr dev_inst = get_selected_device(); if (dev_inst && dev_inst->dev_inst()) { if (dev_inst->name().contains("virtual-demo")) _device_type.setText(tr("Demo")); @@ -194,7 +193,7 @@ void SamplingBar::retranslateUi() void SamplingBar::reStyle() { - shared_ptr dev_inst = get_selected_device(); + boost::shared_ptr dev_inst = get_selected_device(); if (dev_inst && dev_inst->dev_inst()) { if (dev_inst->name().contains("virtual-demo")) _device_type.setIcon(QIcon(":/icons/demo.svg")); @@ -215,8 +214,8 @@ void SamplingBar::reStyle() } } - if (!qApp->property("Style").isNull()) { - QString iconPath = ":/icons/" + qApp->property("Style").toString(); + if (true) { + QString iconPath = GetIconPath(); _configure_button.setIcon(QIcon(iconPath+"/params.svg")); _mode_button.setIcon(_session.get_run_mode() == pv::SigSession::Single ? QIcon(iconPath+"/modes.svg") : QIcon(iconPath+"/moder.svg")); @@ -229,8 +228,8 @@ void SamplingBar::reStyle() } void SamplingBar::set_device_list( - const std::list< shared_ptr > &devices, - shared_ptr selected) + const std::list > &devices, + boost::shared_ptr selected) { int selected_index = -1; @@ -241,7 +240,7 @@ void SamplingBar::set_device_list( _device_selector.clear(); _device_selector_map.clear(); - BOOST_FOREACH (shared_ptr dev_inst, devices) { + BOOST_FOREACH (boost::shared_ptr dev_inst, devices) { assert(dev_inst); const QString title = dev_inst->format_device_title(); const void *id = dev_inst->get_id(); @@ -267,11 +266,11 @@ void SamplingBar::set_device_list( _updating_device_selector = false; } -shared_ptr SamplingBar::get_selected_device() const +boost::shared_ptr SamplingBar::get_selected_device() const { const int index = _device_selector.currentIndex(); if (index < 0) - return shared_ptr(); + return boost::shared_ptr(); const void *const id = _device_selector.itemData(index).value(); @@ -280,9 +279,9 @@ shared_ptr SamplingBar::get_selected_device() const map >:: const_iterator iter = _device_selector_map.find(id); if (iter == _device_selector_map.end()) - return shared_ptr(); + return boost::shared_ptr(); - return shared_ptr((*iter).second); + return boost::shared_ptr((*iter).second); } void SamplingBar::on_configure() @@ -290,7 +289,7 @@ void SamplingBar::on_configure() hide_calibration(); int ret; - shared_ptr dev_inst = get_selected_device(); + boost::shared_ptr dev_inst = get_selected_device(); assert(dev_inst); pv::dialogs::DeviceOptions dlg(this, dev_inst); @@ -401,8 +400,8 @@ void SamplingBar::set_sampling(bool sampling) _configure_button.setEnabled(!sampling); _device_selector.setEnabled(!sampling); - if (!qApp->property("Style").isNull()) { - QString iconPath = ":/icons/" + qApp->property("Style").toString(); + if (true) { + QString iconPath = GetIconPath(); if (_instant) { _instant_button.setIcon(sampling ? QIcon(iconPath+"/stop.svg") : QIcon(iconPath+"/single.svg")); } else { @@ -439,7 +438,7 @@ void SamplingBar::update_sample_rate_selector() disconnect(&_sample_rate, SIGNAL(currentIndexChanged(int)), this, SLOT(on_samplerate_sel(int))); - const shared_ptr dev_inst = get_selected_device(); + const boost::shared_ptr dev_inst = get_selected_device(); if (!dev_inst) return; @@ -513,7 +512,7 @@ void SamplingBar::update_sample_rate_selector_value() void SamplingBar::on_samplerate_sel(int index) { (void)index; - const shared_ptr dev_inst = get_selected_device(); + const boost::shared_ptr dev_inst = get_selected_device(); if (dev_inst->dev_inst()->mode != DSO) update_sample_count_selector(); } @@ -539,7 +538,7 @@ void SamplingBar::update_sample_count_selector() assert(!_updating_sample_count); _updating_sample_count = true; - const shared_ptr dev_inst = get_selected_device(); + const boost::shared_ptr dev_inst = get_selected_device(); GVariant* gvar = dev_inst->get_config(NULL, NULL, SR_CONF_STREAM); if (gvar != NULL) { stream_mode = g_variant_get_boolean(gvar); @@ -672,7 +671,7 @@ void SamplingBar::update_sample_count_selector_value() GVariant* gvar; double duration; - const shared_ptr dev_inst = get_selected_device(); + const boost::shared_ptr dev_inst = get_selected_device(); if (dev_inst->dev_inst()->mode == DSO) { gvar = dev_inst->get_config(NULL, NULL, SR_CONF_TIMEBASE); if (gvar != NULL) { @@ -715,7 +714,7 @@ void SamplingBar::on_samplecount_sel(int index) { (void)index; - const shared_ptr dev_inst = get_selected_device(); + const boost::shared_ptr dev_inst = get_selected_device(); if (dev_inst->dev_inst()->mode == DSO) commit_hori_res(); duration_changed(); @@ -753,7 +752,7 @@ double SamplingBar::commit_hori_res() const double hori_res = _sample_count.itemData( _sample_count.currentIndex()).value(); - const shared_ptr dev_inst = get_selected_device(); + const boost::shared_ptr dev_inst = get_selected_device(); const uint64_t sample_limit = dev_inst->get_sample_limit(); GVariant* gvar; uint64_t max_sample_rate; @@ -781,7 +780,7 @@ double SamplingBar::commit_hori_res() void SamplingBar::commit_settings() { bool test = false; - const shared_ptr dev_inst = get_selected_device(); + const boost::shared_ptr dev_inst = get_selected_device(); if (dev_inst && dev_inst->owner()) { GVariant *gvar = dev_inst->get_config(NULL, NULL, SR_CONF_TEST); if (gvar != NULL) { @@ -799,7 +798,7 @@ void SamplingBar::commit_settings() const uint64_t sample_rate = _sample_rate.itemData( _sample_rate.currentIndex()).value(); - const shared_ptr dev_inst = get_selected_device(); + const boost::shared_ptr dev_inst = get_selected_device(); if (dev_inst) { if (sample_rate != dev_inst->get_sample_rate()) dev_inst->set_config(NULL, NULL, @@ -831,7 +830,7 @@ void SamplingBar::on_run_stop() enable_instant(false); commit_settings(); _instant = false; - const shared_ptr dev_inst = get_selected_device(); + const boost::shared_ptr dev_inst = get_selected_device(); if (!dev_inst) return; if (dev_inst->dev_inst()->mode == DSO) { @@ -883,7 +882,7 @@ void SamplingBar::on_instant_stop() enable_instant(false); commit_settings(); _instant = true; - const shared_ptr dev_inst = get_selected_device(); + const boost::shared_ptr dev_inst = get_selected_device(); if (!dev_inst) return; if (dev_inst->dev_inst()->mode == DSO) { @@ -922,7 +921,7 @@ void SamplingBar::on_device_selected() _session.stop_capture(); _session.session_save(); - const shared_ptr dev_inst = get_selected_device(); + const boost::shared_ptr dev_inst = get_selected_device(); if (!dev_inst) return; @@ -937,7 +936,7 @@ void SamplingBar::on_device_selected() void SamplingBar::enable_toggle(bool enable) { bool test = false; - const shared_ptr dev_inst = get_selected_device(); + const boost::shared_ptr dev_inst = get_selected_device(); if (dev_inst && dev_inst->owner()) { GVariant *gvar = dev_inst->get_config(NULL, NULL, SR_CONF_TEST); if (gvar != NULL) { @@ -985,7 +984,7 @@ void SamplingBar::show_session_error( void SamplingBar::reload() { - QString iconPath = ":/icons/" + qApp->property("Style").toString(); + QString iconPath = GetIconPath(); if (_session.get_device()->dev_inst()->mode == LOGIC) { if (_session.get_device()->name() == "virtual-session") { _mode_action->setVisible(false); @@ -1016,7 +1015,7 @@ void SamplingBar::reload() void SamplingBar::on_mode() { - QString iconPath = ":/icons/" + qApp->property("Style").toString(); + QString iconPath = GetIconPath(); QAction *act = qobject_cast(sender()); if (act == _action_single) { _mode_button.setIcon(QIcon(iconPath+"/modes.svg")); diff --git a/DSView/pv/toolbars/titlebar.cpp b/DSView/pv/toolbars/titlebar.cpp index fa2a6310..42c2fc64 100755 --- a/DSView/pv/toolbars/titlebar.cpp +++ b/DSView/pv/toolbars/titlebar.cpp @@ -26,11 +26,11 @@ #include #include #include -#include -#include +#include #include #include #include +#include "../config/appconfig.h" #include "../dsvdef.h" @@ -107,7 +107,7 @@ void TitleBar::changeEvent(QEvent *event) void TitleBar::reStyle() { - QString iconPath = ":/icons/" + qApp->property("Style").toString(); + QString iconPath = GetIconPath(); if (_isTop) { _minimizeButton->setIcon(QIcon(iconPath+"/minimize.svg")); @@ -167,7 +167,7 @@ QString TitleBar::title() const void TitleBar::showMaxRestore() { - QString iconPath = ":/icons/" + qApp->property("Style").toString(); + QString iconPath = GetIconPath(); if (parentWidget()->isMaximized()) { _maximizeButton->setIcon(QIcon(iconPath+"/maximize.svg")); normalShow(); @@ -179,7 +179,7 @@ void TitleBar::showMaxRestore() void TitleBar::setRestoreButton(bool max) { - QString iconPath = ":/icons/" + qApp->property("Style").toString(); + QString iconPath = GetIconPath(); if (!max) { _maximizeButton->setIcon(QIcon(iconPath+"/maximize.svg")); } else { diff --git a/DSView/pv/toolbars/trigbar.cpp b/DSView/pv/toolbars/trigbar.cpp index 95f336f4..dcccb3ea 100755 --- a/DSView/pv/toolbars/trigbar.cpp +++ b/DSView/pv/toolbars/trigbar.cpp @@ -27,10 +27,10 @@ #include "../dialogs/mathoptions.h" #include "../view/trace.h" -#include #include #include #include "../dialogs/applicationpardlg.h" +#include "../config/appconfig.h" namespace pv { namespace toolbars { @@ -47,15 +47,15 @@ TrigBar::TrigBar(SigSession &session, QWidget *parent) : _measure_button(this), _search_button(this), _function_button(this), - _display_button(this) + _setting_button(this) { setMovable(false); setContentsMargins(0,0,0,0); _trig_button.setCheckable(true); -#ifdef ENABLE_DECODE + _protocol_button.setCheckable(true); -#endif + _measure_button.setCheckable(true); _search_button.setCheckable(true); @@ -95,15 +95,15 @@ TrigBar::TrigBar(SigSession &session, QWidget *parent) : _display_menu->addAction(_action_lissajous); _display_menu->addMenu(_themes); - _display_button.setPopupMode(QToolButton::InstantPopup); - _display_button.setMenu(_display_menu); + _setting_button.setPopupMode(QToolButton::InstantPopup); + _setting_button.setMenu(_display_menu); _trig_button.setToolButtonStyle(Qt::ToolButtonTextUnderIcon); _protocol_button.setToolButtonStyle(Qt::ToolButtonTextUnderIcon); _measure_button.setToolButtonStyle(Qt::ToolButtonTextUnderIcon); _search_button.setToolButtonStyle(Qt::ToolButtonTextUnderIcon); _function_button.setToolButtonStyle(Qt::ToolButtonTextUnderIcon); - _display_button.setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + _setting_button.setToolButtonStyle(Qt::ToolButtonTextUnderIcon); _protocol_button.setContentsMargins(0,0,0,0); @@ -112,7 +112,7 @@ TrigBar::TrigBar(SigSession &session, QWidget *parent) : _measure_action = addWidget(&_measure_button); _search_action = addWidget(&_search_button); _function_action = addWidget(&_function_button); - _display_action = addWidget(&_display_button); //must be created + _display_action = addWidget(&_setting_button); //must be created retranslateUi(); @@ -145,7 +145,7 @@ void TrigBar::retranslateUi() _measure_button.setText(tr("Measure")); _search_button.setText(tr("Search")); _function_button.setText(tr("Function")); - _display_button.setText(tr("Setting")); + _setting_button.setText(tr("Setting")); _action_lissajous->setText(tr("&Lissajous")); @@ -161,14 +161,14 @@ void TrigBar::retranslateUi() void TrigBar::reStyle() { - QString iconPath = ":/icons/" + qApp->property("Style").toString(); + QString iconPath = GetIconPath(); _trig_button.setIcon(QIcon(iconPath+"/trigger.svg")); _protocol_button.setIcon(QIcon(iconPath+"/protocol.svg")); _measure_button.setIcon(QIcon(iconPath+"/measure.svg")); _search_button.setIcon(QIcon(iconPath+"/search-bar.svg")); _function_button.setIcon(QIcon(iconPath+"/function.svg")); - _display_button.setIcon(QIcon(iconPath+"/display.svg")); + _setting_button.setIcon(QIcon(iconPath+"/display.svg")); _action_fft->setIcon(QIcon(iconPath+"/fft.svg")); _action_math->setIcon(QIcon(iconPath+"/math.svg")); @@ -178,7 +178,9 @@ void TrigBar::reStyle() _appParam_action->setIcon(QIcon(iconPath+"/params.svg")); - _themes->setIcon(QIcon(iconPath+"/"+qApp->property("Style").toString()+".svg")); + AppConfig &app = AppConfig::Instance(); + + _themes->setIcon(QIcon(iconPath+"/"+ app._frameOptions.language +".svg")); } void TrigBar::protocol_clicked() @@ -228,7 +230,7 @@ void TrigBar::enable_toggle(bool enable) _measure_button.setDisabled(!enable); _search_button.setDisabled(!enable); _function_button.setDisabled(!enable); - _display_button.setDisabled(!enable); + _setting_button.setDisabled(!enable); } void TrigBar::enable_protocol(bool enable) diff --git a/DSView/pv/toolbars/trigbar.h b/DSView/pv/toolbars/trigbar.h index c98e5366..65764299 100755 --- a/DSView/pv/toolbars/trigbar.h +++ b/DSView/pv/toolbars/trigbar.h @@ -93,7 +93,7 @@ private: QToolButton _measure_button; QToolButton _search_button; QToolButton _function_button; - QToolButton _display_button; + QToolButton _setting_button; QAction* _trig_action; QAction* _protocol_action; QAction* _measure_action; diff --git a/DSView/pv/view/decodetrace.cpp b/DSView/pv/view/decodetrace.cpp index 97e99f92..0fa24f1a 100755 --- a/DSView/pv/view/decodetrace.cpp +++ b/DSView/pv/view/decodetrace.cpp @@ -26,8 +26,7 @@ #include #include -#include -#include +#include #include #include #include @@ -36,6 +35,7 @@ #include #include #include +#include #include "decodetrace.h" diff --git a/DSView/pv/view/devmode.cpp b/DSView/pv/view/devmode.cpp index 572f9651..2c99e95b 100755 --- a/DSView/pv/view/devmode.cpp +++ b/DSView/pv/view/devmode.cpp @@ -29,13 +29,13 @@ #include #include - -#include + #include #include #include #include #include +#include "../config/appconfig.h" using boost::shared_ptr; using namespace std; @@ -105,8 +105,11 @@ void DevMode::set_device() _close_button->setDisabled(true); disconnect(_close_button, SIGNAL(clicked()), this, SLOT(on_close())); - if (!qApp->property("Style").isNull()) { - QString iconPath = ":/icons/" + qApp->property("Style").toString() + "/"; + AppConfig &app = AppConfig::Instance(); + int lan = app._frameOptions.language; + + if (true) { + QString iconPath = GetIconPath() + "/"; for (const GSList *l = dev_inst->get_dev_mode_list(); l; l = l->next) { const sr_dev_mode *mode = (const sr_dev_mode *)l->data; @@ -114,7 +117,7 @@ void DevMode::set_device() QAction *action = new QAction(this); action->setIcon(QIcon(iconPath+"square-"+icon_name)); - if (qApp->property("Language") == QLocale::Chinese) + if (lan == QLocale::Chinese) action->setText(mode->name_cn); else action->setText(mode->name); @@ -123,7 +126,7 @@ void DevMode::set_device() _mode_list[action] = mode; if (dev_inst->dev_inst()->mode == _mode_list[action]->mode) { _mode_btn->setIcon(QIcon(iconPath+icon_name)); - if (qApp->property("Language") == QLocale::Chinese) + if (lan== QLocale::Chinese) _mode_btn->setText(mode->name_cn); else _mode_btn->setText(mode->name); @@ -159,7 +162,10 @@ void DevMode::on_mode_change() if (dev_inst->dev_inst()->mode == _mode_list[action]->mode) return; - QString iconPath = ":/icons/" + qApp->property("Style").toString(); + QString iconPath = GetIconPath(); + AppConfig &app = AppConfig::Instance(); + int lan = app._frameOptions.language; + for(std::map::const_iterator i = _mode_list.begin(); i != _mode_list.end(); i++) { if ((*i).first == action) { @@ -175,7 +181,7 @@ void DevMode::on_mode_change() QString icon_name = "/" + QString::fromLocal8Bit((*i).second->icon); _mode_btn->setIcon(QIcon(iconPath+icon_name)); - if (qApp->property("Language") == QLocale::Chinese) + if (lan == QLocale::Chinese) _mode_btn->setText((*i).second->name_cn); else _mode_btn->setText((*i).second->name); diff --git a/DSView/pv/view/header.cpp b/DSView/pv/view/header.cpp index 9d794020..ec5db76c 100755 --- a/DSView/pv/view/header.cpp +++ b/DSView/pv/view/header.cpp @@ -36,8 +36,7 @@ #include #include - -#include + #include #include #include @@ -45,6 +44,7 @@ #include #include #include +#include using namespace boost; using namespace std; diff --git a/DSView/pv/view/selectableitem.cpp b/DSView/pv/view/selectableitem.cpp index 1c4d987e..cc2b42cd 100755 --- a/DSView/pv/view/selectableitem.cpp +++ b/DSView/pv/view/selectableitem.cpp @@ -21,10 +21,10 @@ */ #include "selectableitem.h" - -#include + #include #include +#include namespace pv { namespace view { diff --git a/DSView/pv/view/signal.cpp b/DSView/pv/view/signal.cpp index d694c033..0646cb06 100755 --- a/DSView/pv/view/signal.cpp +++ b/DSView/pv/view/signal.cpp @@ -23,8 +23,7 @@ #include #include - -#include + #include "signal.h" #include "view.h" diff --git a/DSView/pv/view/trace.cpp b/DSView/pv/view/trace.cpp index def3fdb0..fca6addf 100755 --- a/DSView/pv/view/trace.cpp +++ b/DSView/pv/view/trace.cpp @@ -22,17 +22,17 @@ #include #include -#include - -#include +#include #include #include +#include #include "trace.h" #include "view.h" #include "../device/devinst.h" #include "../sigsession.h" + namespace pv { namespace view { diff --git a/DSView/pv/view/view.cpp b/DSView/pv/view/view.cpp index 4d959f0d..349f0b6b 100755 --- a/DSView/pv/view/view.cpp +++ b/DSView/pv/view/view.cpp @@ -25,8 +25,7 @@ #include #include - -#include + #include #include #include @@ -378,10 +377,10 @@ vector< boost::shared_ptr > View::get_traces(int type) { const vector< boost::shared_ptr > sigs(_session.get_signals()); const vector< boost::shared_ptr > groups(_session.get_group_signals()); -#ifdef ENABLE_DECODE + const vector< boost::shared_ptr > decode_sigs( _session.get_decode_signals()); -#endif + const vector< boost::shared_ptr > spectrums(_session.get_spectrum_traces()); vector< boost::shared_ptr > traces; @@ -389,12 +388,12 @@ vector< boost::shared_ptr > View::get_traces(int type) if (type == ALL_VIEW || _trace_view_map[t->get_type()] == type) traces.push_back(t); } -#ifdef ENABLE_DECODE + BOOST_FOREACH(boost::shared_ptr t, decode_sigs) { if (type == ALL_VIEW || _trace_view_map[t->get_type()] == type) traces.push_back(t); } -#endif + BOOST_FOREACH(boost::shared_ptr t, groups) { if (type == ALL_VIEW || _trace_view_map[t->get_type()] == type) traces.push_back(t); diff --git a/DSView/pv/widgets/border.cpp b/DSView/pv/widgets/border.cpp index 9ff70e20..79737213 100755 --- a/DSView/pv/widgets/border.cpp +++ b/DSView/pv/widgets/border.cpp @@ -21,11 +21,11 @@ #include "border.h" #include "../mainframe.h" - -#include + #include #include #include +#include "../config/appconfig.h" namespace pv { namespace widgets { @@ -56,7 +56,10 @@ void Border::paintEvent(QPaintEvent *) painter.setPen(Qt::NoPen); painter.setRenderHint(QPainter::Antialiasing, true); QLinearGradient linearGrad(QPointF(width(), height()), QPointF(0, 0)); - if (qApp->property("Style").toString() == "dark") { + AppConfig &app = AppConfig::Instance(); + QString style = app._frameOptions.style; + + if (style == "dark") { linearGrad.setColorAt(0, dark_border0); linearGrad.setColorAt(0.25, dark_border1); linearGrad.setColorAt(0.5, dark_border2); @@ -71,7 +74,7 @@ void Border::paintEvent(QPaintEvent *) } QRadialGradient radialGrad(QPointF(0, 0), width()); - if (qApp->property("Style").toString() == "dark") { + if (style == "dark") { radialGrad.setColorAt(0, dark_border0); radialGrad.setColorAt(0.25, dark_border1); radialGrad.setColorAt(0.5, dark_border2); diff --git a/DSView/pv/widgets/decodergroupbox.cpp b/DSView/pv/widgets/decodergroupbox.cpp index 80c4c446..a529c4df 100755 --- a/DSView/pv/widgets/decodergroupbox.cpp +++ b/DSView/pv/widgets/decodergroupbox.cpp @@ -32,8 +32,10 @@ #include #include #include +#include #include +#include "../config/appconfig.h" #include @@ -55,7 +57,7 @@ DecoderGroupBox::DecoderGroupBox(boost::shared_ptr &decoder_ setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setWidgetResizable(true); - QString iconPath = ":/icons/" + qApp->property("Style").toString(); + QString iconPath = GetIconPath(); _layout->addWidget(new QLabel(QString("

%1

").arg(_dec->decoder()->name), _widget), 0, 0); _layout->setColumnStretch(0, 1); @@ -129,7 +131,7 @@ bool DecoderGroupBox::eventFilter(QObject *o, QEvent *e) void DecoderGroupBox::tog_icon() { - QString iconPath = ":/icons/" + qApp->property("Style").toString(); + QString iconPath = GetIconPath(); QPushButton *sc = dynamic_cast(sender()); QVariant id = sc->property("index"); int index = id.toInt(); diff --git a/DSView/pv/widgets/decodergroupbox.h b/DSView/pv/widgets/decodergroupbox.h index 814e42a6..61f5599b 100755 --- a/DSView/pv/widgets/decodergroupbox.h +++ b/DSView/pv/widgets/decodergroupbox.h @@ -22,7 +22,7 @@ #ifndef DSVIEW_PV_WIDGETS_DECODERGROUPBOX_H #define DSVIEW_PV_WIDGETS_DECODERGROUPBOX_H -#include + #include #include #include From 26fe2941df9f19bf58141f01d54f62172a3bd8b2 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Thu, 28 Oct 2021 18:49:52 +0800 Subject: [PATCH 14/60] able to export original data --- DSView/pv/config/appconfig.cpp | 7 +- DSView/pv/config/appconfig.h | 18 +- DSView/pv/dialogs/storeprogress.cpp | 162 ++++++++++--- DSView/pv/dialogs/storeprogress.h | 35 ++- DSView/pv/mainframe.cpp | 4 +- DSView/pv/mainwindow.cpp | 5 +- DSView/pv/storesession.cpp | 342 ++++++++++++++++++---------- DSView/pv/storesession.h | 40 ++-- libsigrok4DSL/libsigrok.h | 1 + libsigrok4DSL/output/csv.c | 12 +- libsigrok4DSL/proto.h | 8 + libsigrok4DSL/session.c | 12 + 12 files changed, 432 insertions(+), 214 deletions(-) diff --git a/DSView/pv/config/appconfig.cpp b/DSView/pv/config/appconfig.cpp index ae418bfc..ae3fcd24 100644 --- a/DSView/pv/config/appconfig.cpp +++ b/DSView/pv/config/appconfig.cpp @@ -90,7 +90,7 @@ void _loadApp(AppOptions &o, QSettings &st){ st.beginGroup("Application"); getFiled("quickScroll", st, o.quickScroll, true); getFiled("warnofMultiTrig", st, o.warnofMultiTrig, true); - + getFiled("originalData", st, o.originalData, false); QString fmt; getFiled("protocalFormats", st, fmt, ""); @@ -105,6 +105,7 @@ void _saveApp(AppOptions &o, QSettings &st){ st.beginGroup("Application"); setFiled("quickScroll", st, o.quickScroll); setFiled("warnofMultiTrig", st, o.warnofMultiTrig); + setFiled("originalData", st, o.originalData); QString fmt = FormatArrayToString(o.m_protocolFormats); @@ -149,6 +150,7 @@ void _loadHistory(UserHistory &o, QSettings &st){ getFiled("sessionDir", st, o.sessionDir, ""); getFiled("openDir", st, o.openDir, ""); getFiled("protocolExportPath", st, o.protocolExportPath, ""); + getFiled("exportFormat", st, o.exportFormat, ""); st.endGroup(); } @@ -160,7 +162,8 @@ void _saveHistory(UserHistory &o, QSettings &st){ setFiled("screenShotPath", st, o.screenShotPath); setFiled("sessionDir", st, o.sessionDir); setFiled("openDir", st, o.openDir); - setFiled("protocolExportPath", st, o.protocolExportPath); + setFiled("protocolExportPath", st, o.protocolExportPath); + setFiled("exportFormat", st, o.exportFormat); st.endGroup(); } diff --git a/DSView/pv/config/appconfig.h b/DSView/pv/config/appconfig.h index 14b1d5d6..ffea3327 100644 --- a/DSView/pv/config/appconfig.h +++ b/DSView/pv/config/appconfig.h @@ -45,19 +45,17 @@ public: string m_value; }; -class AppOptions -{ - public: +struct AppOptions +{ bool quickScroll; bool warnofMultiTrig; - + bool originalData; vector m_protocolFormats; }; -class FrameOptions -{ -public: +struct FrameOptions +{ QString style; int language; QByteArray geometry; @@ -65,9 +63,8 @@ public: QByteArray windowState; }; -class UserHistory -{ -public: +struct UserHistory +{ QString exportDir; QString saveDir; bool showDocuments; @@ -75,6 +72,7 @@ public: QString sessionDir; QString openDir; QString protocolExportPath; + QString exportFormat; }; class AppConfig diff --git a/DSView/pv/dialogs/storeprogress.cpp b/DSView/pv/dialogs/storeprogress.cpp index b74daaa4..19d0329e 100755 --- a/DSView/pv/dialogs/storeprogress.cpp +++ b/DSView/pv/dialogs/storeprogress.cpp @@ -19,36 +19,70 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "storeprogress.h" -#include "dsmessagebox.h" +#include "storeprogress.h" #include "pv/sigsession.h" +#include +#include +#include +#include +#include +#include -#include "QVBoxLayout" +#include "../ui/msgbox.h" +#include "../config/appconfig.h" namespace pv { namespace dialogs { StoreProgress::StoreProgress(SigSession &session, QWidget *parent) : DSDialog(parent), - _store_session(session), - _button_box(QDialogButtonBox::Cancel, Qt::Horizontal, this), - _done(false) + _store_session(session) { - this->setModal(true); + _fileLab = NULL; + _ckOrigin = NULL; - _info.setText("..."); + this->setMinimumSize(550, 220); + this->setModal(true); + _progress.setValue(0); _progress.setMaximum(100); - QVBoxLayout* add_layout = new QVBoxLayout(); - add_layout->addWidget(&_info, 0, Qt::AlignCenter); - add_layout->addWidget(&_progress); - add_layout->addWidget(&_button_box); - layout()->addLayout(add_layout); + _isExport = false; + _done = false; + + QGridLayout *grid = new QGridLayout(); + _grid = grid; + grid->setContentsMargins(10, 20, 10, 10); + grid->setVerticalSpacing(25); + + grid->setColumnStretch(0, 2); + grid->setColumnStretch(1, 2); + grid->setColumnStretch(2, 1); + grid->setColumnStretch(3, 1); + + _fileLab = new QLineEdit(); + _fileLab->setEnabled(false); + + QPushButton *openButton = new QPushButton(this); + openButton->setText(tr("change")); + + grid->addWidget(&_progress, 0, 0, 1, 4); + grid->addWidget(_fileLab, 1, 0, 1, 3); + grid->addWidget(openButton, 1, 3, 1, 1); + + QDialogButtonBox *_button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, + Qt::Horizontal, this); + grid->addWidget(_button_box, 2, 2, 1, 2, Qt::AlignRight | Qt::AlignBottom); + + layout()->addLayout(grid); + + connect(_button_box, SIGNAL(rejected()), this, SLOT(reject())); + connect(_button_box, SIGNAL(accepted()), this, SLOT(accept())); - connect(&_button_box, SIGNAL(rejected()), this, SLOT(reject())); connect(&_store_session, SIGNAL(progress_updated()), this, SLOT(on_progress_updated()), Qt::QueuedConnection); + + connect(openButton, SIGNAL(clicked()),this, SLOT(on_change_file())); } StoreProgress::~StoreProgress() @@ -56,12 +90,66 @@ StoreProgress::~StoreProgress() _store_session.wait(); } + void StoreProgress::on_change_file() + { + if (_isExport){ + QString file = _store_session.MakeExportFile(true); + if (file != "") + _fileLab->setText(file); + } + else{ + QString file = _store_session.MakeSaveFile(true); + if (file != "") + _fileLab->setText(file); + } + } + void StoreProgress::reject() { using namespace Qt; _store_session.cancel(); save_done(); - QDialog::reject(); + DSDialog::reject(); +} + +void StoreProgress::accept() +{ + if (_store_session.GetFileName() == ""){ + MsgBox::Show(NULL, "you need to select a file name."); + return; + } + + if (_isExport && _store_session.IsLogicDataType()){ + bool ck = _ckOrigin->isChecked(); + AppConfig &app = AppConfig::Instance(); + if (app._appOptions.originalData != ck){ + app._appOptions.originalData = ck; + app.SaveApp(); + } + } + + //start done + if (_isExport){ + if (_store_session.export_start()){ + QTimer::singleShot(100, this, SLOT(timeout())); + } + else{ + save_done(); + close(); + show_error(); + } + } + else{ + if (_store_session.save_start()){ + QTimer::singleShot(100, this, SLOT(timeout())); + } + else{ + save_done(); + close(); + show_error(); + } + } + //do not to call base class method, otherwise the window will be closed; } void StoreProgress::timeout() @@ -77,36 +165,40 @@ void StoreProgress::timeout() void StoreProgress::save_run(QString session_file) { - _info.setText(tr("Saving...")); - if (_store_session.save_start(session_file)) - show(); - else - show_error(); - - QTimer::singleShot(100, this, SLOT(timeout())); + _isExport = false; + setTitle(tr("Saving...")); + QString file = _store_session.MakeSaveFile(false); + _fileLab->setText(file); + _store_session._sessionFile = session_file; + show(); } void StoreProgress::export_run() { - _info.setText(tr("Exporting...")); - if (_store_session.export_start()) - show(); - else - show_error(); + if (_store_session.IsLogicDataType()) + { + QGridLayout *lay = new QGridLayout(); + lay->setContentsMargins(15, 0, 0, 0); + AppConfig &app = AppConfig::Instance(); + _ckOrigin = new QCheckBox(); + _ckOrigin->setChecked(app._appOptions.originalData); + _ckOrigin->setText(tr("all original data")); + lay->addWidget(_ckOrigin); + _grid->addLayout(lay, 2, 0, 1, 2); + } - QTimer::singleShot(100, this, SLOT(timeout())); + _isExport = true; + setTitle(tr("Exporting...")); + QString file = _store_session.MakeExportFile(false); + _fileLab->setText(file); + show(); } void StoreProgress::show_error() { _done = true; - if (!_store_session.error().isEmpty()) { - dialogs::DSMessageBox msg(parentWidget()); - msg.mBox()->setText(tr("Failed to save data.")); - msg.mBox()->setInformativeText(_store_session.error()); - msg.mBox()->setStandardButtons(QMessageBox::Ok); - msg.mBox()->setIcon(QMessageBox::Warning); - msg.exec(); + if (!_store_session.error().isEmpty()) { + MsgBox::Show(NULL, _store_session.error().toStdString().c_str(), NULL); } } diff --git a/DSView/pv/dialogs/storeprogress.h b/DSView/pv/dialogs/storeprogress.h index 93c61ef4..63d7c013 100755 --- a/DSView/pv/dialogs/storeprogress.h +++ b/DSView/pv/dialogs/storeprogress.h @@ -22,18 +22,16 @@ #ifndef DSVIEW_PV_DIALOGS_SAVEPROGRESS_H #define DSVIEW_PV_DIALOGS_SAVEPROGRESS_H -#include +//#include #include - -#include #include -#include -#include - #include "../storesession.h" -#include "../dialogs/dsdialog.h" -#include "../toolbars/titlebar.h" +#include "../dialogs/dsdialog.h" + +class QLineEdit; +class QCheckBox; +class QGridLayout; namespace pv { @@ -51,10 +49,10 @@ public: virtual ~StoreProgress(); - - + protected: void reject(); + void accept(); private: void show_error(); @@ -70,17 +68,16 @@ public slots: private slots: void on_progress_updated(); void timeout(); + void on_change_file(); private: - pv::StoreSession _store_session; - - QLabel _info; - QProgressBar _progress; - QDialogButtonBox _button_box; - - toolbars::TitleBar *_titlebar; - - bool _done; + pv::StoreSession _store_session; + QProgressBar _progress; + bool _done; + bool _isExport; + QLineEdit *_fileLab; + QCheckBox *_ckOrigin; + QGridLayout *_grid; }; } // dialogs diff --git a/DSView/pv/mainframe.cpp b/DSView/pv/mainframe.cpp index 9beb1187..7c83b53b 100755 --- a/DSView/pv/mainframe.cpp +++ b/DSView/pv/mainframe.cpp @@ -379,7 +379,9 @@ void MainFrame::readSettings() { AppConfig &app = AppConfig::Instance(); - _mainWindow->switchLanguage(app._frameOptions.language); + if (app._frameOptions.language > 0){ + _mainWindow->switchLanguage(app._frameOptions.language); + } if (app._frameOptions.geometry.isEmpty()) { QScreen *screen=QGuiApplication::primaryScreen (); diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index 0e6294fe..ffe8662c 100755 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -887,9 +887,6 @@ void MainWindow::on_export() { using pv::dialogs::StoreProgress; -// dialogs::RegionOptions *regionDlg = new dialogs::RegionOptions(_view, _session, this); -// regionDlg->exec(); - StoreProgress *dlg = new StoreProgress(_session, this); dlg->export_run(); } @@ -1356,7 +1353,7 @@ void MainWindow::switchLanguage(int language) dev->set_config(NULL, NULL, SR_CONF_LANGUAGE, g_variant_new_int16(language)); AppConfig &app = AppConfig::Instance(); - if (app._frameOptions.language != language) + if (app._frameOptions.language != language && language > 0) { app._frameOptions.language = language; app.SaveFrame(); diff --git a/DSView/pv/storesession.cpp b/DSView/pv/storesession.cpp index 5c9c7eef..88fe59bc 100755 --- a/DSView/pv/storesession.cpp +++ b/DSView/pv/storesession.cpp @@ -43,6 +43,7 @@ #include #include +#include #include "config/appconfig.h" @@ -137,8 +138,14 @@ QList StoreSession::getSuportedExportFormats(){ return list; } -bool StoreSession::save_start(QString session_file) +bool StoreSession::save_start() { + if (_sessionFile == "") + { + _error = tr("No set session file name."); + return false; + } + std::set type_set; BOOST_FOREACH(const boost::shared_ptr sig, _session.get_signals()) { assert(sig); @@ -149,11 +156,17 @@ bool StoreSession::save_start(QString session_file) _error = tr("DSView does not currently support" "file saving for multiple data types."); return false; + } else if (type_set.size() == 0) { _error = tr("No data to save."); return false; } + if (_file_name == ""){ + _error = tr("No set file name."); + return false; + } + const boost::shared_ptr snapshot(_session.get_snapshot(*type_set.begin())); assert(snapshot); // Check we have data @@ -161,56 +174,12 @@ bool StoreSession::save_start(QString session_file) _error = tr("No data to save."); return false; } - - //root dir - QString default_name; + QString meta_file = meta_gen(snapshot); - AppConfig &app = AppConfig::Instance(); - if (app._userHistory.saveDir != "") - { - default_name = app._userHistory.saveDir + "/" + _session.get_device()->name() + "-"; - } - else{ - default_name = _session.get_device()->name() + "-"; - } + QString decoders_file = decoders_gen(); - for (const GSList *l = _session.get_device()->get_dev_mode_list(); - l; l = l->next) { - const sr_dev_mode *mode = (const sr_dev_mode *)l->data; - if (_session.get_device()->dev_inst()->mode == mode->mode) { - default_name += mode->acronym; - break; - } - } - - default_name += _session.get_session_time().toString("-yyMMdd-hhmmss"); - - // Show the dialog - QString svFilePath = QFileDialog::getSaveFileName( - NULL, - tr("Save File"), - default_name, - tr("DSView Data (*.dsl)")); - - if (!svFilePath.isEmpty()) { - QFileInfo f(svFilePath); - if(f.suffix().compare("dsl")) - svFilePath.append(tr(".dsl")); - - _file_name = svFilePath; - svFilePath = GetDirectoryName(svFilePath); - - if (svFilePath != app._userHistory.saveDir){ - app._userHistory.saveDir = svFilePath; - app.SaveHistory(); - } - - QString meta_file = meta_gen(snapshot); - - QString decoders_file = decoders_gen(); - - /* + /* if (meta_file == NULL) { _error = tr("Generate temp file failed."); } else { @@ -227,20 +196,20 @@ bool StoreSession::save_start(QString session_file) } */ - //make zip file - if (meta_file != NULL && m_zipDoc.CreateNew(_file_name.toUtf8().data(), false)) + //make zip file + if (meta_file != NULL && m_zipDoc.CreateNew(_file_name.toUtf8().data(), false)) + { + if (!m_zipDoc.AddFromFile(meta_file.toUtf8().data(), "header") + || !m_zipDoc.AddFromFile(decoders_file.toUtf8().data(), "decoders") + || !m_zipDoc.AddFromFile(_sessionFile.toUtf8().data(), "session")) { - if ( !m_zipDoc.AddFromFile(meta_file.toUtf8().data(), "header") - || !m_zipDoc.AddFromFile(decoders_file.toUtf8().data(), "decoders") - || !m_zipDoc.AddFromFile(session_file.toUtf8().data(), "session")) - { - _has_error = true; - _error = m_zipDoc.GetError(); - } - else{ - _thread = boost::thread(&StoreSession::save_proc, this, snapshot); - return !_has_error; - } + _has_error = true; + _error = m_zipDoc.GetError(); + } + else + { + _thread = boost::thread(&StoreSession::save_proc, this, snapshot); + return !_has_error; } } @@ -611,75 +580,37 @@ bool StoreSession::export_start() return false; } - AppConfig &app = AppConfig::Instance(); - - QString default_name; - if (app._userHistory.exportDir != "") - { - default_name = app._userHistory.exportDir + "/" + _session.get_device()->name() + "-"; - } - else{ - default_name = _session.get_device()->name() + "-"; - } + if (_file_name == ""){ + _error = tr("No set file name."); + return false; + } - for (const GSList *l = _session.get_device()->get_dev_mode_list(); - l; l = l->next) { - const sr_dev_mode *mode = (const sr_dev_mode *)l->data; - if (_session.get_device()->dev_inst()->mode == mode->mode) { - default_name += mode->acronym; + //set export all data flag + AppConfig &app = AppConfig::Instance(); + int flag = app._appOptions.originalData ? 1 : 0; + sr_set_export_original_data(flag); + + const struct sr_output_module **supportedModules = sr_output_list(); + while (*supportedModules) + { + if (*supportedModules == NULL) + break; + if (!strcmp((*supportedModules)->id, _suffix.toUtf8().data())) + { + _outModule = *supportedModules; break; } - } - default_name += _session.get_session_time().toString("-yyMMdd-hhmmss"); - - // Show the dialog - QList supportedFormats = getSuportedExportFormats(); - QString filter; - for(int i = 0; i < supportedFormats.count();i++){ - filter.append(supportedFormats[i]); - if(i < supportedFormats.count() - 1) - filter.append(";;"); + supportedModules++; } - QString svFilePath = QFileDialog::getSaveFileName( - NULL, - tr("Export Data"), - default_name, - filter, - &filter); - - if (!svFilePath.isEmpty()) { - QFileInfo f(_file_name); - QStringList list = filter.split('.').last().split(')'); - _suffix = list.first(); - if(f.suffix().compare(_suffix)) - svFilePath += tr(".") + _suffix; - - _file_name = svFilePath; - svFilePath = GetDirectoryName(svFilePath); - - if (svFilePath != app._userHistory.exportDir ){ - app._userHistory.exportDir = svFilePath; - app.SaveHistory(); - } - - const struct sr_output_module** supportedModules = sr_output_list(); - while(*supportedModules){ - if(*supportedModules == NULL) - break; - if(!strcmp((*supportedModules)->id, _suffix.toUtf8().data())){ - _outModule = *supportedModules; - break; - } - supportedModules++; - } - - if(_outModule == NULL) { - _error = tr("Invalid export format."); - } else { - _thread = boost::thread(&StoreSession::export_proc, this, snapshot); - return !_has_error; - } + if (_outModule == NULL) + { + _error = tr("Invalid export format."); + } + else + { + _thread = boost::thread(&StoreSession::export_proc, this, snapshot); + return !_has_error; } _error.clear(); @@ -1192,5 +1123,166 @@ double StoreSession::get_integer(GVariant *var) return val; } +QString StoreSession::MakeSaveFile(bool bDlg) +{ + QString default_name; + + AppConfig &app = AppConfig::Instance(); + if (app._userHistory.saveDir != "") + { + default_name = app._userHistory.saveDir + "/" + _session.get_device()->name() + "-"; + } + else{ + QDir _dir; + QString _root = _dir.home().path(); + default_name = _root + "/" + _session.get_device()->name() + "-"; + } + + for (const GSList *l = _session.get_device()->get_dev_mode_list(); + l; l = l->next) { + const sr_dev_mode *mode = (const sr_dev_mode *)l->data; + if (_session.get_device()->dev_inst()->mode == mode->mode) { + default_name += mode->acronym; + break; + } + } + + default_name += _session.get_session_time().toString("-yyMMdd-hhmmss"); + + // Show the dialog + if (bDlg) + { + default_name = QFileDialog::getSaveFileName( + NULL, + tr("Save File"), + default_name, + tr("DSView Data (*.dsl)")); + + if (default_name.isEmpty()) + { + return ""; //no select file + } + + QString _dir_path = GetDirectoryName(default_name); + + if (_dir_path != app._userHistory.saveDir) + { + app._userHistory.saveDir = _dir_path; + app.SaveHistory(); + } + } + + QFileInfo f(default_name); + if (f.suffix().compare("dsl")) + { + default_name.append(tr(".dsl")); + } + _file_name = default_name; + return default_name; +} + +QString StoreSession::MakeExportFile(bool bDlg) +{ + QString default_name; + AppConfig &app = AppConfig::Instance(); + + if (app._userHistory.exportDir != "") + { + default_name = app._userHistory.exportDir + "/" + _session.get_device()->name() + "-"; + } + else{ + QDir _dir; + QString _root = _dir.home().path(); + default_name = _root + "/" + _session.get_device()->name() + "-"; + } + + for (const GSList *l = _session.get_device()->get_dev_mode_list(); + l; l = l->next) { + const sr_dev_mode *mode = (const sr_dev_mode *)l->data; + if (_session.get_device()->dev_inst()->mode == mode->mode) { + default_name += mode->acronym; + break; + } + } + default_name += _session.get_session_time().toString("-yyMMdd-hhmmss"); + + //ext name + QList supportedFormats = getSuportedExportFormats(); + QString filter; + for(int i = 0; i < supportedFormats.count();i++){ + filter.append(supportedFormats[i]); + if(i < supportedFormats.count() - 1) + filter.append(";;"); + } + + QString selfilter; + if (app._userHistory.exportFormat != ""){ + selfilter.append(app._userHistory.exportFormat); + } + + if (bDlg) + { + default_name = QFileDialog::getSaveFileName( + NULL, + tr("Export Data"), + default_name, + filter, + &selfilter); + + if (default_name == "") + { + return ""; + } + + bool bChange = false; + QString _dir_path = GetDirectoryName(default_name); + if (_dir_path != app._userHistory.exportDir) + { + app._userHistory.exportDir = _dir_path; + bChange = true; + } + if (selfilter != app._userHistory.exportFormat){ + app._userHistory.exportFormat = selfilter; + bChange = true; + } + + if (bChange){ + app.SaveHistory(); + } + } + + QString extName = selfilter; + if (extName == ""){ + extName = filter; + } + + QStringList list = extName.split('.').last().split(')'); + _suffix = list.first(); + + QFileInfo f(default_name); + if(f.suffix().compare(_suffix)){ + default_name += tr(".") + _suffix; + } + + _file_name = default_name; + return default_name; +} + +bool StoreSession::IsLogicDataType() +{ + std::set type_set; + BOOST_FOREACH(const boost::shared_ptr sig, _session.get_signals()) { + assert(sig); + type_set.insert(sig->get_type()); + } + + if (type_set.size()){ + int type = *(type_set.begin()); + return type == SR_CHANNEL_LOGIC; + } + + return false; +} + } // pv diff --git a/DSView/pv/storesession.h b/DSView/pv/storesession.h index 75dcbb2a..d7c201ca 100755 --- a/DSView/pv/storesession.h +++ b/DSView/pv/storesession.h @@ -63,7 +63,7 @@ public: const QString& error() const; - bool save_start(QString session_file); + bool save_start(); bool export_start(); @@ -79,10 +79,16 @@ private: QString decoders_gen(); -public: - +public: QJsonArray json_decoders(); void load_decoders(dock::ProtocolDock *widget, QJsonArray dec_array); + QString MakeSaveFile(bool bDlg); + QString MakeExportFile(bool bDlg); + + inline QString GetFileName() + { return _file_name;} + + bool IsLogicDataType(); private: @@ -92,22 +98,24 @@ private: signals: void progress_updated(); -private: - QString _file_name; - QString _suffix; - SigSession &_session; +public: + QString _sessionFile; - boost::thread _thread; +private: + QString _file_name; + QString _suffix; + SigSession &_session; + + boost::thread _thread; const struct sr_output_module* _outModule; - - //mutable boost::mutex _mutex; - uint64_t _units_stored; - uint64_t _unit_count; - bool _has_error; - QString _error; - bool _canceled; - ZipMaker m_zipDoc; + + uint64_t _units_stored; + uint64_t _unit_count; + bool _has_error; + QString _error; + bool _canceled; + ZipMaker m_zipDoc; }; } // pv diff --git a/libsigrok4DSL/libsigrok.h b/libsigrok4DSL/libsigrok.h index 1409514d..d36dffcf 100755 --- a/libsigrok4DSL/libsigrok.h +++ b/libsigrok4DSL/libsigrok.h @@ -176,6 +176,7 @@ enum { #define SR_PRIV #endif + /** Data types used by sr_config_info(). */ enum { SR_T_UINT64 = 10000, diff --git a/libsigrok4DSL/output/csv.c b/libsigrok4DSL/output/csv.c index 47a85dd6..ad95756b 100755 --- a/libsigrok4DSL/output/csv.c +++ b/libsigrok4DSL/output/csv.c @@ -26,6 +26,7 @@ #include "config.h" /* Needed for PACKAGE_STRING and others. */ #define LOG_PREFIX "output/csv" + struct context { unsigned int num_enabled_channels; @@ -234,10 +235,16 @@ static int receive(const struct sr_output *o, const struct sr_datafeed_packet *p *out = g_string_sized_new(512); } + int bflag = sr_get_export_original_flag(); + for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) { ctx->index++; - if (ctx->index > 1 && (*(uint64_t *)(logic->data + i) & ctx->mask) == ctx->pre_data) - continue; + + if (bflag == 0){ + if (ctx->index > 1 && (*(uint64_t *)(logic->data + i) & ctx->mask) == ctx->pre_data) + continue; + } + g_string_append_printf(*out, "%0.10g", (ctx->index-1)*1.0/ctx->samplerate); for (j = 0; j < ctx->num_enabled_channels; j++) { //idx = ctx->channel_index[j]; @@ -331,3 +338,4 @@ SR_PRIV struct sr_output_module output_csv = { .receive = receive, .cleanup = cleanup, }; + diff --git a/libsigrok4DSL/proto.h b/libsigrok4DSL/proto.h index aeac6b81..81452c3a 100755 --- a/libsigrok4DSL/proto.h +++ b/libsigrok4DSL/proto.h @@ -179,4 +179,12 @@ SR_PRIV uint16_t ds_trigger_get_edge0(uint16_t stage, uint16_t msc, uint16_t lsc SR_PRIV uint16_t ds_trigger_get_mask1(uint16_t stage, uint16_t msc, uint16_t lsc, gboolean qutr_mode, gboolean half_mode); SR_PRIV uint16_t ds_trigger_get_value1(uint16_t stage, uint16_t msc, uint16_t lsc, gboolean qutr_mode, gboolean half_mode); SR_PRIV uint16_t ds_trigger_get_edge1(uint16_t stage, uint16_t msc, uint16_t lsc, gboolean qutr_mode, gboolean half_mode); + +/*--------------------session.c----------------*/ + +SR_API void sr_set_export_original_data(int flag); + +SR_API int sr_get_export_original_flag(); + + #endif diff --git a/libsigrok4DSL/session.c b/libsigrok4DSL/session.c index f3f822f1..34923f4c 100755 --- a/libsigrok4DSL/session.c +++ b/libsigrok4DSL/session.c @@ -34,6 +34,8 @@ #define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args) #define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args) +int bExportOriginalData = 0; //able export all data + /** * @file * @@ -813,4 +815,14 @@ SR_API int sr_session_source_remove_channel(GIOChannel *channel) return _sr_session_source_remove((gintptr)channel); } +SR_API void sr_set_export_original_data(int flag) +{ + bExportOriginalData = flag; +} + +SR_API int sr_get_export_original_flag() +{ + return bExportOriginalData; +} + /** @} */ From 73a5b5fc783b8dba0e9e35d2049de725b65c2d93 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Thu, 28 Oct 2021 18:51:16 +0800 Subject: [PATCH 15/60] none --- DSView/pv/config/appconfig.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DSView/pv/config/appconfig.h b/DSView/pv/config/appconfig.h index ffea3327..d2dbab50 100644 --- a/DSView/pv/config/appconfig.h +++ b/DSView/pv/config/appconfig.h @@ -29,7 +29,7 @@ using namespace std; -//--------------------api +//--------------------api -- QString GetDirectoryName(QString path); From 7e8eb387771ac2fb6122c4ce6ee778b5fd06fd9e Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Fri, 29 Oct 2021 08:55:48 +0800 Subject: [PATCH 16/60] none --- DSView/pv/config/appconfig.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DSView/pv/config/appconfig.h b/DSView/pv/config/appconfig.h index d2dbab50..eb4f884b 100644 --- a/DSView/pv/config/appconfig.h +++ b/DSView/pv/config/appconfig.h @@ -29,7 +29,7 @@ using namespace std; -//--------------------api -- +//--------------------api--- QString GetDirectoryName(QString path); From aa3722b24296f269642d723129f37828b6267d8c Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Fri, 29 Oct 2021 11:07:14 +0800 Subject: [PATCH 17/60] rename toolbar signals name --- DSView/pv/config/appconfig.h | 1 + DSView/pv/data/logicsnapshot.cpp | 5 +- DSView/pv/mainwindow.cpp | 98 ++++++++++++++++++------------ DSView/pv/mainwindow.h | 42 ++++++++----- DSView/pv/toolbars/filebar.cpp | 14 ++--- DSView/pv/toolbars/filebar.h | 12 ++-- DSView/pv/toolbars/logobar.cpp | 6 +- DSView/pv/toolbars/logobar.h | 4 +- DSView/pv/toolbars/samplingbar.cpp | 53 ++++++++-------- DSView/pv/toolbars/samplingbar.h | 14 ++--- DSView/pv/toolbars/titlebar.cpp | 2 +- DSView/pv/toolbars/trigbar.cpp | 20 +++--- DSView/pv/toolbars/trigbar.h | 12 ++-- 13 files changed, 157 insertions(+), 126 deletions(-) diff --git a/DSView/pv/config/appconfig.h b/DSView/pv/config/appconfig.h index eb4f884b..7bae2732 100644 --- a/DSView/pv/config/appconfig.h +++ b/DSView/pv/config/appconfig.h @@ -45,6 +45,7 @@ public: string m_value; }; + struct AppOptions { bool quickScroll; diff --git a/DSView/pv/data/logicsnapshot.cpp b/DSView/pv/data/logicsnapshot.cpp index 05426722..2dd3027e 100755 --- a/DSView/pv/data/logicsnapshot.cpp +++ b/DSView/pv/data/logicsnapshot.cpp @@ -473,8 +473,9 @@ const uint8_t *LogicSnapshot::get_samples(uint64_t start_sample, uint64_t &end_s int sig_index) { //assert(data); - assert(start_sample < get_sample_count()); - assert(end_sample <= get_sample_count()); + uint64_t sample_count = get_sample_count(); + assert(start_sample < sample_count); + assert(end_sample <= sample_count); assert(start_sample <= end_sample); int order = get_ch_order(sig_index); diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index ffe8662c..029d1e0c 100755 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -259,47 +259,55 @@ void MainWindow::setup_ui() connect(&_session, SIGNAL(capture_state_changed(int)), this, SLOT(capture_state_changed(int))); connect(&_session, SIGNAL(device_attach()), this, SLOT(device_attach()), Qt::QueuedConnection); connect(&_session, SIGNAL(device_detach()), this, SLOT(device_detach()), Qt::QueuedConnection); - connect(&_session, SIGNAL(session_error()), this, SLOT(show_error()), Qt::QueuedConnection); + connect(&_session, SIGNAL(session_error()), this, SLOT(on_show_error()), Qt::QueuedConnection); connect(&_session, SIGNAL(session_save()), this, SLOT(session_save())); connect(&_session, SIGNAL(data_updated()), _measure_widget, SLOT(reCalc())); connect(&_session, SIGNAL(repeat_resume()), this, SLOT(repeat_resume())); connect(&_session, SIGNAL(update_capture()), _view, SLOT(update_hori_res()), Qt::DirectConnection); connect(&_session, SIGNAL(cur_snap_samplerate_changed()), _measure_widget, SLOT(cursor_update())); + + //view connect(_view, SIGNAL(cursor_update()), _measure_widget, SLOT(cursor_update())); connect(_view, SIGNAL(cursor_moving()), _measure_widget, SLOT(cursor_moving())); connect(_view, SIGNAL(cursor_moved()), _measure_widget, SLOT(reCalc())); connect(_view, SIGNAL(prgRate(int)), this, SIGNAL(prgRate(int))); connect(_view, SIGNAL(device_changed(bool)), this, SLOT(device_changed(bool)), Qt::DirectConnection); + connect(_view, SIGNAL(auto_trig(int)), _dso_trigger_widget, SLOT(auto_trig(int))); - //tool bar event - connect(_trig_bar, SIGNAL(on_protocol(bool)), this, SLOT(on_protocol(bool))); - connect(_trig_bar, SIGNAL(on_trigger(bool)), this, SLOT(on_trigger(bool))); - connect(_trig_bar, SIGNAL(on_measure(bool)), this, SLOT(on_measure(bool))); - connect(_trig_bar, SIGNAL(on_search(bool)), this, SLOT(on_search(bool))); - connect(_trig_bar, SIGNAL(setTheme(QString)), this, SLOT(switchTheme(QString))); - connect(_file_bar, SIGNAL(load_file(QString)), this, SLOT(load_file(QString))); - connect(_file_bar, SIGNAL(on_save()), this, SLOT(on_save())); - connect(_file_bar, SIGNAL(on_export()), this, SLOT(on_export())); - connect(_file_bar, SIGNAL(on_screenShot()), this, SLOT(on_screenShot()), Qt::QueuedConnection); - connect(_file_bar, SIGNAL(load_session(QString)), this, SLOT(load_session(QString))); - connect(_file_bar, SIGNAL(store_session(QString)), this, SLOT(store_session(QString))); - connect(_logo_bar, SIGNAL(setLanguage(int)), this, SLOT(switchLanguage(int))); - connect(_logo_bar, SIGNAL(openDoc()), this, SLOT(openDoc())); + //trig_bar + connect(_trig_bar, SIGNAL(sig_protocol(bool)), this, SLOT(on_protocol(bool))); + connect(_trig_bar, SIGNAL(sig_trigger(bool)), this, SLOT(on_trigger(bool))); + connect(_trig_bar, SIGNAL(sig_measure(bool)), this, SLOT(on_measure(bool))); + connect(_trig_bar, SIGNAL(sig_search(bool)), this, SLOT(on_search(bool))); + connect(_trig_bar, SIGNAL(sig_setTheme(QString)), this, SLOT(switchTheme(QString))); + connect(_trig_bar, SIGNAL(sig_show_lissajous(bool)), _view, SLOT(show_lissajous(bool))); + + //file toolbar + connect(_file_bar, SIGNAL(sig_load_file(QString)), this, SLOT(on_load_file(QString))); + connect(_file_bar, SIGNAL(sig_save()), this, SLOT(on_save())); + connect(_file_bar, SIGNAL(sig_export()), this, SLOT(on_export())); + connect(_file_bar, SIGNAL(sig_screenShot()), this, SLOT(on_screenShot()), Qt::QueuedConnection); + connect(_file_bar, SIGNAL(sig_load_session(QString)), this, SLOT(on_load_session(QString))); + connect(_file_bar, SIGNAL(sig_store_session(QString)), this, SLOT(on_store_session(QString))); + + //logobar + connect(_logo_bar, SIGNAL(sig_setLanguage(int)), this, SLOT(on_setLanguage(int))); + connect(_logo_bar, SIGNAL(sig_open_doc()), this, SLOT(on_open_doc())); connect(_protocol_widget, SIGNAL(protocol_updated()), _view, SLOT(signals_changed())); + //SamplingBar + connect(_sampling_bar, SIGNAL(sig_device_selected()), this, SLOT(on_device_selected())); + connect(_sampling_bar, SIGNAL(sig_device_updated()), this, SLOT(on_device_updated_reload())); + connect(_sampling_bar, SIGNAL(sig_run_stop()), this, SLOT(on_run_stop())); + connect(_sampling_bar, SIGNAL(sig_instant_stop()), this, SLOT(on_instant_stop())); + connect(_sampling_bar, SIGNAL(sig_duration_changed()), _trigger_widget, SLOT(device_updated())); + connect(_sampling_bar, SIGNAL(sig_duration_changed()), _view, SLOT(timebase_changed())); + connect(_sampling_bar, SIGNAL(sig_show_calibration()), _view, SLOT(show_calibration())); - connect(_sampling_bar, SIGNAL(device_selected()), this, SLOT(update_device_list())); - connect(_sampling_bar, SIGNAL(device_updated()), this, SLOT(reload())); - connect(_sampling_bar, SIGNAL(run_stop()), this, SLOT(run_stop())); - connect(_sampling_bar, SIGNAL(instant_stop()), this, SLOT(instant_stop())); - connect(_sampling_bar, SIGNAL(duration_changed()), _trigger_widget, SLOT(device_updated())); - connect(_sampling_bar, SIGNAL(duration_changed()), _view, SLOT(timebase_changed())); - connect(_sampling_bar, SIGNAL(show_calibration()), _view, SLOT(show_calibration())); - connect(_trig_bar, SIGNAL(show_lissajous(bool)), _view, SLOT(show_lissajous(bool))); connect(_dso_trigger_widget, SIGNAL(set_trig_pos(int)), _view, SLOT(set_trig_pos(int))); - connect(_view, SIGNAL(auto_trig(int)), _dso_trigger_widget, SLOT(auto_trig(int))); + } @@ -320,6 +328,11 @@ void MainWindow::session_error( Q_ARG(QString, info_text)); } +void MainWindow::on_device_selected() +{ + update_device_list(); +} + void MainWindow::update_device_list() { assert(_sampling_bar); @@ -391,7 +404,7 @@ void MainWindow::update_device_list() selected_device->name() + QString::number(selected_device->dev_inst()->mode) + lang_name + ".dsc"; - load_session(ses_name); + on_load_session(ses_name); } } else { _file_bar->set_settings_en(false); @@ -409,7 +422,7 @@ void MainWindow::update_device_list() QString::number(selected_device->dev_inst()->mode) + ".dsc"; if (QFileInfo(ses_name).exists()) - load_session(ses_name); + on_load_session(ses_name); } } _sampling_bar->reload(); @@ -442,14 +455,14 @@ void MainWindow::update_device_list() } -void MainWindow::reload() +void MainWindow::on_device_updated_reload() { _trigger_widget->device_updated(); _session.reload(); _measure_widget->reload(); } -void MainWindow::load_file(QString file_name) +void MainWindow::on_load_file(QString file_name) { try { if (strncmp(_session.get_device()->name().toUtf8(), "virtual", 7)) @@ -568,7 +581,7 @@ void MainWindow::device_changed(bool close) update_device_list(); } -void MainWindow::run_stop() +void MainWindow::on_run_stop() { switch(_session.get_capture_state()) { case SigSession::Init: @@ -586,7 +599,7 @@ void MainWindow::run_stop() } } -void MainWindow::instant_stop() +void MainWindow::on_instant_stop() { switch(_session.get_capture_state()) { case SigSession::Init: @@ -608,10 +621,10 @@ void MainWindow::repeat_resume() { while(_view->session().get_capture_state() == SigSession::Running) QCoreApplication::processEvents(); - run_stop(); + on_run_stop(); } -void MainWindow::show_error() +void MainWindow::on_show_error() { QString title; QString details; @@ -725,7 +738,7 @@ void MainWindow::session_save() lang_name + ".dsc"; if (strncmp(driver_name.toUtf8(), "virtual", 7) && !file_name.isEmpty()) { - store_session(file_name); + on_store_session(file_name); } } @@ -875,7 +888,7 @@ void MainWindow::on_save() dir.cd(path); session_file = dir.absolutePath() + "/DSView-session-XXXXXX"; - store_session(session_file); + on_store_session(session_file); } StoreProgress *dlg = new StoreProgress(_session, this); @@ -891,7 +904,7 @@ void MainWindow::on_export() dlg->export_run(); } -bool MainWindow::load_session(QString name) +bool MainWindow::on_load_session(QString name) { QFile sessionFile(name); if (!sessionFile.open(QIODevice::ReadOnly)) { @@ -1101,7 +1114,7 @@ bool MainWindow::load_session_json(QJsonDocument json, bool file_dev) } -bool MainWindow::store_session(QString name) +bool MainWindow::on_store_session(QString name) { QFile sessionFile(name); if (!sessionFile.open(QIODevice::WriteOnly | QIODevice::Text)) { @@ -1249,10 +1262,10 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) QKeyEvent *ke = (QKeyEvent *) event; switch(ke->key()) { case Qt::Key_S: - run_stop(); + on_run_stop(); break; case Qt::Key_I: - instant_stop(); + on_instant_stop(); break; case Qt::Key_T: if (_session.get_device()->dev_inst()->mode == DSO) @@ -1346,6 +1359,11 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) } return false; } + + void MainWindow::on_setLanguage(int language) + { + switchLanguage(language); + } void MainWindow::switchLanguage(int language) { @@ -1393,6 +1411,10 @@ void MainWindow::switchTheme(QString style) _session.data_updated(); } +void MainWindow::on_open_doc(){ + openDoc(); +} + void MainWindow::openDoc() { #ifndef Q_OS_LINUX diff --git a/DSView/pv/mainwindow.h b/DSView/pv/mainwindow.h index 59fd8d3b..0571aeba 100755 --- a/DSView/pv/mainwindow.h +++ b/DSView/pv/mainwindow.h @@ -80,24 +80,32 @@ public: protected: void closeEvent(QCloseEvent *event); +public: + void openDoc(); + + void switchLanguage(int language); + private: void setup_ui(); void retranslateUi(); void session_error(const QString text, const QString info_text); bool eventFilter(QObject *object, QEvent *event); -public slots: - void session_save(); - - void openDoc(); + bool load_session_json(QJsonDocument json, bool file_dev); - void switchLanguage(int language); + void update_device_list(); + +public slots: + void session_save(); + void switchTheme(QString style); void restore_dock(); private slots: - void load_file(QString file_name); + void on_load_file(QString file_name); + + void on_open_doc(); /** * Updates the device list in the sampling bar, and updates the @@ -105,16 +113,15 @@ private slots: * @param selected_device The device to select, or NULL if the * first device in the device list should be selected. */ - void update_device_list(); + - void reload(); + void on_device_updated_reload(); - void show_session_error( - const QString text, const QString info_text); + void show_session_error(const QString text, const QString info_text); - void run_stop(); + void on_run_stop(); - void instant_stop(); + void on_instant_stop(); void capture_state_changed(int state); @@ -134,9 +141,9 @@ private slots: void on_export(); - bool load_session(QString name); - bool load_session_json(QJsonDocument json, bool file_dev); - bool store_session(QString name); + bool on_load_session(QString name); + + bool on_store_session(QString name); /* * repeat @@ -150,12 +157,15 @@ private slots: void device_detach(); void device_detach_post(); void device_changed(bool close); + void on_device_selected(); /* * errors */ - void show_error(); + void on_show_error(); + void on_setLanguage(int language); + signals: void prgRate(int progress); diff --git a/DSView/pv/toolbars/filebar.cpp b/DSView/pv/toolbars/filebar.cpp index 14a337f7..4a3b8663 100755 --- a/DSView/pv/toolbars/filebar.cpp +++ b/DSView/pv/toolbars/filebar.cpp @@ -91,8 +91,8 @@ FileBar::FileBar(SigSession &session, QWidget *parent) : connect(_action_store, SIGNAL(triggered()), this, SLOT(on_actionStore_triggered())); connect(_action_default, SIGNAL(triggered()), this, SLOT(on_actionDefault_triggered())); connect(_action_open, SIGNAL(triggered()), this, SLOT(on_actionOpen_triggered())); - connect(_action_save, SIGNAL(triggered()), this, SIGNAL(on_save())); - connect(_action_export, SIGNAL(triggered()), this, SIGNAL(on_export())); + connect(_action_save, SIGNAL(triggered()), this, SIGNAL(sig_save())); + connect(_action_export, SIGNAL(triggered()), this, SIGNAL(sig_export())); connect(_action_capture, SIGNAL(triggered()), this, SLOT(on_actionCapture_triggered())); } @@ -152,7 +152,7 @@ void FileBar::on_actionOpen_triggered() app.SaveHistory(); } - load_file(file_name); + sig_load_file(file_name); } } @@ -188,7 +188,7 @@ void FileBar::on_actionLoad_triggered() app.SaveHistory(); } - load_session(file_name); + sig_load_session(file_name); } } @@ -216,7 +216,7 @@ void FileBar::on_actionDefault_triggered() QString file_name = dir.absolutePath() + "/" + driver_name + mode_name + ".def"+QString::number(language)+".dsc"; if (!file_name.isEmpty()) - load_session(file_name); + sig_load_session(file_name); } void FileBar::on_actionStore_triggered() @@ -242,7 +242,7 @@ void FileBar::on_actionStore_triggered() app.SaveHistory(); } - store_session(file_name); + sig_store_session(file_name); } } @@ -250,7 +250,7 @@ void FileBar::on_actionCapture_triggered() { _file_button.close(); QCoreApplication::sendPostedEvents(); - QTimer::singleShot(100, this, SIGNAL(on_screenShot())); + QTimer::singleShot(100, this, SIGNAL(sig_screenShot())); } void FileBar::enable_toggle(bool enable) diff --git a/DSView/pv/toolbars/filebar.h b/DSView/pv/toolbars/filebar.h index 0f55c3db..261d5c31 100755 --- a/DSView/pv/toolbars/filebar.h +++ b/DSView/pv/toolbars/filebar.h @@ -57,12 +57,12 @@ private: const QString text, const QString info_text); signals: - void load_file(QString); - void on_save(); - void on_export(); - void on_screenShot(); //post screen capture event message - void load_session(QString); //post load session event message - void store_session(QString); //post store session event message + void sig_load_file(QString); + void sig_save(); + void sig_export(); + void sig_screenShot(); //post screen capture event message + void sig_load_session(QString); //post load session event message + void sig_store_session(QString); //post store session event message private slots: void on_actionLoad_triggered(); diff --git a/DSView/pv/toolbars/logobar.cpp b/DSView/pv/toolbars/logobar.cpp index 8b0f8a05..85296798 100755 --- a/DSView/pv/toolbars/logobar.cpp +++ b/DSView/pv/toolbars/logobar.cpp @@ -69,7 +69,7 @@ LogoBar::LogoBar(SigSession &session, QWidget *parent) : _manual = new QAction(this); _manual->setObjectName(QString::fromUtf8("actionManual")); _logo_button.addAction(_manual); - connect(_manual, SIGNAL(triggered()), this, SIGNAL(openDoc())); + connect(_manual, SIGNAL(triggered()), this, SIGNAL(sig_open_doc())); _issue = new QAction(this); _issue->setObjectName(QString::fromUtf8("actionManual")); @@ -169,14 +169,14 @@ void LogoBar::on_actionEn_triggered() { _language->setIcon(QIcon::fromTheme("file", QIcon(":/icons/English.svg"))); - setLanguage(QLocale::English); + sig_setLanguage(QLocale::English); } void LogoBar::on_actionCn_triggered() { _language->setIcon(QIcon::fromTheme("file", QIcon(":/icons/Chinese.svg"))); - setLanguage(QLocale::Chinese); + sig_setLanguage(QLocale::Chinese); } void LogoBar::on_actionAbout_triggered() diff --git a/DSView/pv/toolbars/logobar.h b/DSView/pv/toolbars/logobar.h index 691793a7..278def32 100755 --- a/DSView/pv/toolbars/logobar.h +++ b/DSView/pv/toolbars/logobar.h @@ -61,10 +61,10 @@ private: signals: //post event message to set language, MainWindow class receive it - void setLanguage(int language); + void sig_setLanguage(int language); //post event message to open user help document, MainWindow class receive it - void openDoc(); + void sig_open_doc(); private slots: void on_actionEn_triggered(); diff --git a/DSView/pv/toolbars/samplingbar.cpp b/DSView/pv/toolbars/samplingbar.cpp index 2f3bd4fb..46302c9c 100755 --- a/DSView/pv/toolbars/samplingbar.cpp +++ b/DSView/pv/toolbars/samplingbar.cpp @@ -74,32 +74,17 @@ SamplingBar::SamplingBar(SigSession &session, QWidget *parent) : setContentsMargins(0,0,0,0); layout()->setMargin(0); layout()->setSpacing(0); - - connect(&_device_selector, SIGNAL(currentIndexChanged (int)), - this, SLOT(on_device_selected())); - connect(&_configure_button, SIGNAL(clicked()), - this, SLOT(on_configure())); - connect(&_run_stop_button, SIGNAL(clicked()), - this, SLOT(on_run_stop()), Qt::DirectConnection); - connect(&_instant_button, SIGNAL(clicked()), - this, SLOT(on_instant_stop())); - + _mode_button.setPopupMode(QToolButton::InstantPopup); _device_selector.setSizeAdjustPolicy(QComboBox::AdjustToContents); _sample_rate.setSizeAdjustPolicy(QComboBox::AdjustToContents); _sample_count.setSizeAdjustPolicy(QComboBox::AdjustToContents); _device_selector.setMaximumWidth(ComboBoxMaxWidth); - - connect(&_sample_count, SIGNAL(currentIndexChanged(int)), - this, SLOT(on_samplecount_sel(int))); - + //_run_stop_button.setToolButtonStyle(Qt::ToolButtonTextBesideIcon); _run_stop_button.setObjectName(tr("run_stop_button")); - - connect(&_sample_rate, SIGNAL(currentIndexChanged(int)), - this, SLOT(on_samplerate_sel(int))); - + QWidget *leftMargin = new QWidget(this); leftMargin->setFixedWidth(4); addWidget(leftMargin); @@ -115,10 +100,8 @@ SamplingBar::SamplingBar(SigSession &session, QWidget *parent) : addWidget(&_sample_rate); _action_single = new QAction(this); - connect(_action_single, SIGNAL(triggered()), this, SLOT(on_mode())); _action_repeat = new QAction(this); - connect(_action_repeat, SIGNAL(triggered()), this, SLOT(on_mode())); _mode_menu = new QMenu(this); _mode_menu->addAction(_action_single); @@ -135,6 +118,15 @@ SamplingBar::SamplingBar(SigSession &session, QWidget *parent) : set_sampling(false); //retranslateUi(); + + connect(&_device_selector, SIGNAL(currentIndexChanged (int)), this, SLOT(on_device_selected())); + connect(&_configure_button, SIGNAL(clicked()),this, SLOT(on_configure())); + connect(&_run_stop_button, SIGNAL(clicked()),this, SLOT(on_run_stop()), Qt::DirectConnection); + connect(&_instant_button, SIGNAL(clicked()), this, SLOT(on_instant_stop())); + connect(&_sample_count, SIGNAL(currentIndexChanged(int)), this, SLOT(on_samplecount_sel(int))); + connect(_action_single, SIGNAL(triggered()), this, SLOT(on_mode())); + connect(_action_repeat, SIGNAL(triggered()), this, SLOT(on_mode())); + connect(&_sample_rate, SIGNAL(currentIndexChanged(int)), this, SLOT(on_samplerate_sel(int))); } void SamplingBar::changeEvent(QEvent *event) @@ -286,7 +278,7 @@ boost::shared_ptr SamplingBar::get_selected_device() const void SamplingBar::on_configure() { - hide_calibration(); + sig_hide_calibration(); int ret; boost::shared_ptr dev_inst = get_selected_device(); @@ -295,7 +287,7 @@ void SamplingBar::on_configure() pv::dialogs::DeviceOptions dlg(this, dev_inst); ret = dlg.exec(); if (ret == QDialog::Accepted) { - device_updated(); + sig_device_updated(); update_sample_rate_selector(); GVariant* gvar; @@ -315,7 +307,7 @@ void SamplingBar::on_configure() bool cali = g_variant_get_boolean(gvar); g_variant_unref(gvar); if (cali) { - show_calibration(); + sig_show_calibration(); return; } } @@ -353,7 +345,7 @@ void SamplingBar::zero_adj() _sample_count.setCurrentIndex(i); commit_hori_res(); - run_stop(); + sig_run_stop(); pv::dialogs::WaitingDialog wait(this, _session, SR_CONF_ZERO); if (wait.start() == QDialog::Rejected) { @@ -717,7 +709,7 @@ void SamplingBar::on_samplecount_sel(int index) const boost::shared_ptr dev_inst = get_selected_device(); if (dev_inst->dev_inst()->mode == DSO) commit_hori_res(); - duration_changed(); + sig_duration_changed(); } double SamplingBar::get_hori_res() @@ -857,7 +849,8 @@ void SamplingBar::on_run_stop() } } } - run_stop(); + + sig_run_stop(); } } @@ -882,9 +875,12 @@ void SamplingBar::on_instant_stop() enable_instant(false); commit_settings(); _instant = true; + const boost::shared_ptr dev_inst = get_selected_device(); + if (!dev_inst) return; + if (dev_inst->dev_inst()->mode == DSO) { GVariant* gvar = dev_inst->get_config(NULL, NULL, SR_CONF_ZERO); if (gvar != NULL) { @@ -909,7 +905,8 @@ void SamplingBar::on_instant_stop() } } } - instant_stop(); + + sig_instant_stop(); } } @@ -930,7 +927,7 @@ void SamplingBar::on_device_selected() } catch(QString e) { show_session_error(tr("Failed to select ") + dev_inst->dev_inst()->model, e); } - device_selected(); + sig_device_selected(); } void SamplingBar::enable_toggle(bool enable) diff --git a/DSView/pv/toolbars/samplingbar.h b/DSView/pv/toolbars/samplingbar.h index a19298b9..ee3ce6d8 100755 --- a/DSView/pv/toolbars/samplingbar.h +++ b/DSView/pv/toolbars/samplingbar.h @@ -99,13 +99,13 @@ namespace pv void set_sample_rate(uint64_t sample_rate); signals: - void run_stop(); - void instant_stop(); - void device_selected(); - void device_updated(); - void duration_changed(); - void show_calibration(); - void hide_calibration(); + void sig_run_stop(); + void sig_instant_stop(); + void sig_device_selected(); + void sig_device_updated(); + void sig_duration_changed(); + void sig_show_calibration(); + void sig_hide_calibration(); private: void changeEvent(QEvent *event); diff --git a/DSView/pv/toolbars/titlebar.cpp b/DSView/pv/toolbars/titlebar.cpp index 42c2fc64..6d7b58bb 100755 --- a/DSView/pv/toolbars/titlebar.cpp +++ b/DSView/pv/toolbars/titlebar.cpp @@ -69,7 +69,7 @@ TitleBar::TitleBar(bool top, QWidget *parent, bool hasClose) : _lay->addWidget(_minimizeButton); _lay->addWidget(_maximizeButton); - connect(this, SIGNAL( normalShow() ), parent, SLOT(showNormal() ) ); + connect(this, SIGNAL(normalShow() ), parent, SLOT(showNormal() ) ); connect(this, SIGNAL( maximizedShow() ), parent, SLOT(showMaximized() ) ); connect(_minimizeButton, SIGNAL( clicked() ), parent, SLOT(showMinimized() ) ); connect(_maximizeButton, SIGNAL( clicked() ), this, SLOT(showMaxRestore() ) ); diff --git a/DSView/pv/toolbars/trigbar.cpp b/DSView/pv/toolbars/trigbar.cpp index dcccb3ea..7fa25e17 100755 --- a/DSView/pv/toolbars/trigbar.cpp +++ b/DSView/pv/toolbars/trigbar.cpp @@ -185,12 +185,12 @@ void TrigBar::reStyle() void TrigBar::protocol_clicked() { - on_protocol(_protocol_button.isChecked()); + sig_protocol(_protocol_button.isChecked()); } void TrigBar::trigger_clicked() { - on_trigger(_trig_button.isChecked()); + sig_trigger(_trig_button.isChecked()); } void TrigBar::update_trig_btn(bool checked) @@ -215,12 +215,12 @@ void TrigBar::update_search_btn(bool checked) void TrigBar::measure_clicked() { - on_measure(_measure_button.isChecked()); + sig_measure(_measure_button.isChecked()); } void TrigBar::search_clicked() { - on_search(_search_button.isChecked()); + sig_search(_search_button.isChecked()); } void TrigBar::enable_toggle(bool enable) @@ -242,19 +242,19 @@ void TrigBar::close_all() { if (_trig_button.isChecked()) { _trig_button.setChecked(false); - on_trigger(false); + sig_trigger(false); } if (_protocol_button.isChecked()) { _protocol_button.setChecked(false); - on_protocol(false); + sig_protocol(false); } if (_measure_button.isChecked()) { _measure_button.setChecked(false); - on_measure(false); + sig_measure(false); } if(_search_button.isChecked()) { _search_button.setChecked(false); - on_search(false); + sig_search(false); } } @@ -301,13 +301,13 @@ void TrigBar::on_actionMath_triggered() void TrigBar::on_actionDark_triggered() { - setTheme(DARK_STYLE); + sig_setTheme(DARK_STYLE); _themes->setIcon(QIcon(":/icons/"+DARK_STYLE+"/"+DARK_STYLE+".svg")); } void TrigBar::on_actionLight_triggered() { - setTheme(LIGHT_STYLE); + sig_setTheme(LIGHT_STYLE); _themes->setIcon(QIcon(":/icons/"+LIGHT_STYLE+"/"+LIGHT_STYLE+".svg")); } diff --git a/DSView/pv/toolbars/trigbar.h b/DSView/pv/toolbars/trigbar.h index 65764299..58f07f05 100755 --- a/DSView/pv/toolbars/trigbar.h +++ b/DSView/pv/toolbars/trigbar.h @@ -58,12 +58,12 @@ private: void reStyle(); signals: - void setTheme(QString style); - void on_protocol(bool visible); //post decode button click event,to show or hide protocol property panel - void on_trigger(bool visible); //post decode button click event,to show or hide trigger property panel - void on_measure(bool visible);//post decode button click event,to show or hide measure property panel - void on_search(bool visible); - void show_lissajous(bool visible); + void sig_setTheme(QString style); + void sig_protocol(bool visible); //post decode button click event,to show or hide protocol property panel + void sig_trigger(bool visible); //post decode button click event,to show or hide trigger property panel + void sig_measure(bool visible);//post decode button click event,to show or hide measure property panel + void sig_search(bool visible); + void sig_show_lissajous(bool visible); private slots: void on_actionDark_triggered(); From 9361684c63669a65d07bf7820c4adb1ae424973d Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Mon, 1 Nov 2021 16:50:27 +0800 Subject: [PATCH 18/60] remove DevInst shared_ptr --- DSView/main.cpp | 95 ++++---- DSView/pv/appcontrol.cpp | 123 ++++++++++ DSView/pv/appcontrol.h | 68 ++++++ DSView/pv/config/appconfig.cpp | 5 + DSView/pv/config/appconfig.h | 1 + DSView/pv/data/decoderstack.cpp | 10 +- DSView/pv/data/decoderstack.h | 4 +- DSView/pv/data/mathstack.cpp | 2 +- DSView/pv/data/mathstack.h | 4 +- DSView/pv/data/spectrumstack.cpp | 4 +- DSView/pv/data/spectrumstack.h | 4 +- DSView/pv/device/device.cpp | 7 + DSView/pv/device/device.h | 4 +- DSView/pv/device/devinst.cpp | 6 +- DSView/pv/device/devinst.h | 30 +-- DSView/pv/device/file.cpp | 4 + DSView/pv/device/file.h | 3 + DSView/pv/devicemanager.cpp | 93 ++++---- DSView/pv/devicemanager.h | 33 +-- DSView/pv/dialogs/calibration.cpp | 2 +- DSView/pv/dialogs/calibration.h | 6 +- DSView/pv/dialogs/deviceoptions.cpp | 4 +- DSView/pv/dialogs/deviceoptions.h | 6 +- DSView/pv/dialogs/dsomeasure.cpp | 8 +- DSView/pv/dialogs/dsomeasure.h | 4 +- DSView/pv/dialogs/fftoptions.cpp | 18 +- DSView/pv/dialogs/fftoptions.h | 4 +- DSView/pv/dialogs/interval.cpp | 6 +- DSView/pv/dialogs/interval.h | 4 +- DSView/pv/dialogs/lissajousoptions.cpp | 16 +- DSView/pv/dialogs/lissajousoptions.h | 4 +- DSView/pv/dialogs/mathoptions.cpp | 10 +- DSView/pv/dialogs/mathoptions.h | 4 +- DSView/pv/dialogs/protocolexp.cpp | 10 +- DSView/pv/dialogs/protocolexp.h | 4 +- DSView/pv/dialogs/protocollist.cpp | 22 +- DSView/pv/dialogs/protocollist.h | 4 +- DSView/pv/dialogs/regionoptions.cpp | 14 +- DSView/pv/dialogs/regionoptions.h | 4 +- DSView/pv/dialogs/search.cpp | 8 +- DSView/pv/dialogs/search.h | 4 +- DSView/pv/dialogs/storeprogress.cpp | 4 +- DSView/pv/dialogs/storeprogress.h | 2 +- DSView/pv/dialogs/waitingdialog.cpp | 8 +- DSView/pv/dialogs/waitingdialog.h | 8 +- DSView/pv/dock/dsotriggerdock.cpp | 32 +-- DSView/pv/dock/dsotriggerdock.h | 4 +- DSView/pv/dock/measuredock.cpp | 8 +- DSView/pv/dock/measuredock.h | 4 +- DSView/pv/dock/protocoldock.cpp | 48 ++-- DSView/pv/dock/protocoldock.h | 4 +- DSView/pv/dock/searchdock.cpp | 6 +- DSView/pv/dock/searchdock.h | 4 +- DSView/pv/dock/triggerdock.cpp | 22 +- DSView/pv/dock/triggerdock.h | 4 +- DSView/pv/mainframe.cpp | 5 +- DSView/pv/mainframe.h | 6 +- DSView/pv/mainwindow.cpp | 262 ++++++++++++---------- DSView/pv/mainwindow.h | 25 ++- DSView/pv/sigsession.cpp | 298 +++++++++++++++---------- DSView/pv/sigsession.h | 180 ++++++++------- DSView/pv/storesession.cpp | 86 +++---- DSView/pv/storesession.h | 6 +- DSView/pv/toolbars/filebar.cpp | 8 +- DSView/pv/toolbars/filebar.h | 4 +- DSView/pv/toolbars/logobar.cpp | 2 +- DSView/pv/toolbars/logobar.h | 4 +- DSView/pv/toolbars/samplingbar.cpp | 112 +++++----- DSView/pv/toolbars/samplingbar.h | 14 +- DSView/pv/toolbars/trigbar.cpp | 8 +- DSView/pv/toolbars/trigbar.h | 6 +- DSView/pv/view/analogsignal.cpp | 2 +- DSView/pv/view/analogsignal.h | 2 +- DSView/pv/view/decodetrace.cpp | 18 +- DSView/pv/view/decodetrace.h | 4 +- DSView/pv/view/devmode.cpp | 24 +- DSView/pv/view/devmode.h | 4 +- DSView/pv/view/dsosignal.cpp | 2 +- DSView/pv/view/dsosignal.h | 2 +- DSView/pv/view/logicsignal.cpp | 2 +- DSView/pv/view/logicsignal.h | 4 +- DSView/pv/view/signal.cpp | 5 +- DSView/pv/view/signal.h | 9 +- DSView/pv/view/spectrumtrace.cpp | 10 +- DSView/pv/view/spectrumtrace.h | 4 +- DSView/pv/view/view.cpp | 169 +++++++------- DSView/pv/view/view.h | 6 +- DSView/pv/view/viewstatus.cpp | 16 +- DSView/pv/view/viewstatus.h | 4 +- 89 files changed, 1228 insertions(+), 909 deletions(-) create mode 100644 DSView/pv/appcontrol.cpp create mode 100644 DSView/pv/appcontrol.h diff --git a/DSView/main.cpp b/DSView/main.cpp index e1714572..862befdf 100755 --- a/DSView/main.cpp +++ b/DSView/main.cpp @@ -19,10 +19,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include -#include - + #include #include @@ -35,11 +32,11 @@ #include #include "dsapplication.h" -#include "mystyle.h" -#include "pv/devicemanager.h" +#include "mystyle.h" #include "pv/mainframe.h" #include "pv/config/appconfig.h" #include "config.h" +#include "pv/appcontrol.h" char DS_RES_PATH[256]; @@ -58,10 +55,9 @@ void usage() int main(int argc, char *argv[]) { - int ret = 0; - struct sr_context *sr_ctx = NULL; + int ret = 0; const char *open_file = NULL; - + #if QT_VERSION >= QT_VERSION_CHECK(5,6,0) QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); @@ -107,6 +103,8 @@ int main(int argc, char *argv[]) QApplication::setOrganizationName("DreamSourceLab"); QApplication::setOrganizationDomain("www.DreamSourceLab.com"); + AppControl *control = AppControl::Instance(); + // Parse arguments while (1) { static const struct option long_options[] = { @@ -125,12 +123,7 @@ int main(int argc, char *argv[]) case 'l': { const int loglevel = atoi(optarg); - sr_log_loglevel_set(loglevel); - - - srd_log_loglevel_set(loglevel); - - + control->SetLogLevel(loglevel); break; } @@ -166,53 +159,41 @@ int main(int argc, char *argv[]) return 1; } - // Initialise libsigrok - if (sr_init(&sr_ctx) != SR_OK) { - qDebug() << "DSView run ERROR: libsigrok init failed."; + //load app config + AppConfig::Instance().LoadAll(); + + //init core + if (!control->Init()){ + fprintf(stderr, "init error!"); + qDebug() << control->GetLastError(); return 1; } - do { + try + { + control->Start(); + + // Initialise the main frame + pv::MainFrame w; + w.show(); + w.readSettings(); + + //to show the dailog for open help document + w.show_doc(); - // Initialise libsigrokdecode - if (srd_init(NULL) != SRD_OK) { - qDebug() << "ERROR: libsigrokdecode init failed."; - break; - } + //Run the application + ret = a.exec(); + } + catch (const std::exception &e) + { + fprintf(stderr, "main() catch a except!"); + const char *exstr = e.what(); + qDebug() << exstr; + } - // Load the protocol decoders - srd_decoder_load_all(); - - //load app config - AppConfig::Instance().LoadAll(); - - try { - // Create the device manager, initialise the drivers - pv::DeviceManager device_manager(sr_ctx); - - // Initialise the main frame - pv::MainFrame w(device_manager, open_file); - w.show(); - w.readSettings(); - w.show_doc(); // to show the dailog for open help document - - // Run the application - ret = a.exec(); - - } catch(const std::exception &e) { - qDebug() << e.what(); - } - - - // Destroy libsigrokdecode - srd_exit(); - - - } while (0); - - // Destroy libsigrok - if (sr_ctx) - sr_exit(sr_ctx); + //uninit + control->UnInit(); + control->Destroy(); return ret; } diff --git a/DSView/pv/appcontrol.cpp b/DSView/pv/appcontrol.cpp new file mode 100644 index 00000000..9cf40035 --- /dev/null +++ b/DSView/pv/appcontrol.cpp @@ -0,0 +1,123 @@ + +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2012 Joel Holdsworth + * Copyright (C) 2013 DreamSourceLab + * + * 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 "appcontrol.h" + +#include +#include + +#include "devicemanager.h" +#include "sigsession.h" +#include "dsvdef.h" + +AppControl::AppControl() +{ + sr_ctx = NULL; + + _device_manager = new pv::DeviceManager(); + _session = new pv::SigSession(_device_manager); + _session->_appCntrol = this; +} + +AppControl::AppControl(AppControl &o) +{ + (void)o; +} + +AppControl::~AppControl() +{ + DESTROY_OBJECT(_device_manager); + DESTROY_OBJECT(_session); +} + +AppControl* AppControl::Instance() +{ + static AppControl *ins = NULL; + if (ins == NULL){ + ins = new AppControl(); + } + return ins; +} + +void AppControl::Destroy(){ + delete this; +} + +bool AppControl::Init() +{ + // Initialise libsigrok + if (sr_init(&sr_ctx) != SR_OK) + { + m_error = "DSView run ERROR: libsigrok init failed."; + return false; + } + + // Initialise libsigrokdecode + if (srd_init(NULL) != SRD_OK) + { + m_error = "ERROR: libsigrokdecode init failed."; + return false; + } + + // Load the protocol decoders + if (srd_decoder_load_all() != SRD_OK) + { + m_error = "ERROR: load the protocol decoders failed."; + return false; + } + + return true; +} + +bool AppControl::Start() +{ + _session->Open(); + _device_manager->initAll(sr_ctx); + return true; +} + +void AppControl::UnInit() +{ + _session->Close(); + _device_manager->UnInitAll(); + + // Destroy libsigrokdecode + srd_exit(); + + if (sr_ctx) + { + sr_exit(sr_ctx); + sr_ctx = NULL; + } +} + +const char *AppControl::GetLastError() +{ + return m_error.c_str(); +} + + void AppControl::SetLogLevel(int level) + { + sr_log_loglevel_set(level); + srd_log_loglevel_set(level); + } diff --git a/DSView/pv/appcontrol.h b/DSView/pv/appcontrol.h new file mode 100644 index 00000000..ff2742b5 --- /dev/null +++ b/DSView/pv/appcontrol.h @@ -0,0 +1,68 @@ + +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2012 Joel Holdsworth + * Copyright (C) 2013 DreamSourceLab + * + * 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 + */ + +#pragma once + +#include + +struct sr_context; + +namespace pv{ + class DeviceManager; + class SigSession; +} + +class AppControl +{ +private: + explicit AppControl(); + ~AppControl(); + AppControl(AppControl &o); + +public: + static AppControl* Instance(); + + void Destroy(); + + bool Init(); + + bool Start(); + + void UnInit(); + + const char* GetLastError(); + + void SetLogLevel(int level); + + inline pv::SigSession* GetSession() + { return _session;} + + inline pv::DeviceManager& GetDeviceManager() + { return *_device_manager;} + +private: + std::string m_error; + struct sr_context *sr_ctx; + pv::DeviceManager *_device_manager; + pv::SigSession *_session; +}; diff --git a/DSView/pv/config/appconfig.cpp b/DSView/pv/config/appconfig.cpp index ae3fcd24..269b261f 100644 --- a/DSView/pv/config/appconfig.cpp +++ b/DSView/pv/config/appconfig.cpp @@ -173,6 +173,11 @@ AppConfig::AppConfig() { } +AppConfig::AppConfig(AppConfig &o) +{ + (void)o; +} + AppConfig::~AppConfig() { } diff --git a/DSView/pv/config/appconfig.h b/DSView/pv/config/appconfig.h index 7bae2732..224baf8d 100644 --- a/DSView/pv/config/appconfig.h +++ b/DSView/pv/config/appconfig.h @@ -81,6 +81,7 @@ class AppConfig private: AppConfig(); ~AppConfig(); + AppConfig(AppConfig &o); public: static AppConfig &Instance(); diff --git a/DSView/pv/data/decoderstack.cpp b/DSView/pv/data/decoderstack.cpp index 7f946dd1..c9bbd504 100755 --- a/DSView/pv/data/decoderstack.cpp +++ b/DSView/pv/data/decoderstack.cpp @@ -52,7 +52,7 @@ const unsigned int DecoderStack::DecodeNotifyPeriod = 1024; boost::mutex DecoderStack::_global_decode_mutex; -DecoderStack::DecoderStack(pv::SigSession &session, +DecoderStack::DecoderStack(pv::SigSession *session, const srd_decoder *const dec, DecoderStatus *decoder_status) : _session(session), _sample_count(0), @@ -63,11 +63,11 @@ DecoderStack::DecoderStack(pv::SigSession &session, _no_memory(false), _mark_index(-1) { - connect(&_session, SIGNAL(frame_began()), + connect(_session, SIGNAL(frame_began()), this, SLOT(on_new_frame())); - connect(&_session, SIGNAL(data_received()), + connect(_session, SIGNAL(data_received()), this, SLOT(on_data_received())); - connect(&_session, SIGNAL(frame_ended()), + connect(_session, SIGNAL(frame_ended()), this, SLOT(on_frame_ended())); _stack.push_back(boost::shared_ptr( @@ -419,7 +419,7 @@ void DecoderStack::begin_decode() // LogicSignals have the same data/snapshot BOOST_FOREACH (const boost::shared_ptr &dec, _stack) { if (dec && !dec->channels().empty()) { - BOOST_FOREACH(boost::shared_ptr sig, _session.get_signals()) { + BOOST_FOREACH(boost::shared_ptr sig, _session->get_signals()) { if((sig->get_index() == (*dec->channels().begin()).second) && (logic_signal = dynamic_pointer_cast(sig)) && (data = logic_signal->logic_data())) diff --git a/DSView/pv/data/decoderstack.h b/DSView/pv/data/decoderstack.h index 311a819f..bc05fa6b 100755 --- a/DSView/pv/data/decoderstack.h +++ b/DSView/pv/data/decoderstack.h @@ -79,7 +79,7 @@ public: }; public: - DecoderStack(pv::SigSession &_session, + DecoderStack(pv::SigSession *_session, const srd_decoder *const decoder, DecoderStatus *decoder_status); public: @@ -168,7 +168,7 @@ signals: void decode_done(); private: - pv::SigSession &_session; + pv::SigSession *_session; /** * This mutex prevents more than one decode operation occuring diff --git a/DSView/pv/data/mathstack.cpp b/DSView/pv/data/mathstack.cpp index 759b53b3..072d0dfe 100755 --- a/DSView/pv/data/mathstack.cpp +++ b/DSView/pv/data/mathstack.cpp @@ -75,7 +75,7 @@ const QString MathStack::vDialDivUnit[MathStack::vDialUnitCount] = { "V/V", }; -MathStack::MathStack(pv::SigSession &session, +MathStack::MathStack(pv::SigSession *session, boost::shared_ptr dsoSig1, boost::shared_ptr dsoSig2, MathType type) : diff --git a/DSView/pv/data/mathstack.h b/DSView/pv/data/mathstack.h index ffb80db4..7f6f9844 100755 --- a/DSView/pv/data/mathstack.h +++ b/DSView/pv/data/mathstack.h @@ -102,7 +102,7 @@ private: static const QString vDialDivUnit[vDialUnitCount]; public: - MathStack(pv::SigSession &_session, + MathStack(pv::SigSession *_session, boost::shared_ptr dsoSig1, boost::shared_ptr dsoSig2, MathType type); virtual ~MathStack(); @@ -132,7 +132,7 @@ public: signals: private: - pv::SigSession &_session; + pv::SigSession *_session; boost::shared_ptr _dsoSig1; boost::shared_ptr _dsoSig2; diff --git a/DSView/pv/data/spectrumstack.cpp b/DSView/pv/data/spectrumstack.cpp index d040eb9b..b54bddff 100755 --- a/DSView/pv/data/spectrumstack.cpp +++ b/DSView/pv/data/spectrumstack.cpp @@ -52,7 +52,7 @@ const uint64_t SpectrumStack::length_support[5] = { 16384, }; -SpectrumStack::SpectrumStack(pv::SigSession &session, int index) : +SpectrumStack::SpectrumStack(pv::SigSession *session, int index) : _session(session), _index(index), _dc_ignore(true), @@ -173,7 +173,7 @@ void SpectrumStack::calc_fft() // Get the dso data boost::shared_ptr data; boost::shared_ptr dsoSig; - BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { if ((dsoSig = dynamic_pointer_cast(s))) { if (dsoSig->get_index() == _index && dsoSig->enabled()) { data = dsoSig->dso_data(); diff --git a/DSView/pv/data/spectrumstack.h b/DSView/pv/data/spectrumstack.h index caa4d268..82440595 100755 --- a/DSView/pv/data/spectrumstack.h +++ b/DSView/pv/data/spectrumstack.h @@ -63,7 +63,7 @@ public: }; public: - SpectrumStack(pv::SigSession &_session, int index); + SpectrumStack(pv::SigSession *_session, int index); virtual ~SpectrumStack(); void clear(); void init(); @@ -95,7 +95,7 @@ public: signals: private: - pv::SigSession &_session; + pv::SigSession *_session; int _index; uint64_t _sample_num; diff --git a/DSView/pv/device/device.cpp b/DSView/pv/device/device.cpp index 4eb77b33..ab60d5a8 100755 --- a/DSView/pv/device/device.cpp +++ b/DSView/pv/device/device.cpp @@ -33,6 +33,13 @@ Device::Device(sr_dev_inst *sdi) : _sdi(sdi) { assert(_sdi); + void *p = this; + (void)p; +} + +Device::~Device() +{ + } sr_dev_inst* Device::dev_inst() const diff --git a/DSView/pv/device/device.h b/DSView/pv/device/device.h index f1ec24f1..77ed9abe 100755 --- a/DSView/pv/device/device.h +++ b/DSView/pv/device/device.h @@ -28,10 +28,12 @@ namespace pv { namespace device { class Device : public DevInst -{ +{ public: Device(sr_dev_inst *dev_inst); + ~Device(); + sr_dev_inst* dev_inst() const; void use(SigSession *owner); diff --git a/DSView/pv/device/devinst.cpp b/DSView/pv/device/devinst.cpp index 6aeeeb87..d06858cb 100755 --- a/DSView/pv/device/devinst.cpp +++ b/DSView/pv/device/devinst.cpp @@ -61,7 +61,6 @@ void DevInst::release() { if (_owner) { _owner->release_device(this); - _owner = NULL; } } @@ -210,5 +209,10 @@ bool DevInst::is_usable() const return _usable; } +void DevInst::destroy(){ + release(); + delete this; +} + } // device } // pv diff --git a/DSView/pv/device/devinst.h b/DSView/pv/device/devinst.h index b7c7f8c3..8039fddd 100755 --- a/DSView/pv/device/devinst.h +++ b/DSView/pv/device/devinst.h @@ -22,8 +22,6 @@ #ifndef DSVIEW_PV_DEVICE_DEVINST_H #define DSVIEW_PV_DEVICE_DEVINST_H -#include - #include #include @@ -48,19 +46,12 @@ class DevInst : public QObject protected: DevInst(); - ~DevInst(); -public: - virtual sr_dev_inst* dev_inst() const = 0; - - virtual void use(SigSession *owner); - - virtual void release(); + virtual ~DevInst(); +public: SigSession* owner() const; - - virtual QString format_device_title() const = 0; - + GVariant* get_config(const sr_channel *ch, const sr_channel_group *group, int key); bool set_config(sr_channel *ch, sr_channel_group *group, int key, GVariant *data); @@ -115,11 +106,12 @@ public: * @return device name */ QString name(); - - virtual bool is_trigger_enabled() const; + bool is_usable() const; + void destroy(); + public: virtual void start(); @@ -127,6 +119,16 @@ public: virtual void* get_id() const; + virtual sr_dev_inst* dev_inst() const = 0; + + virtual void use(SigSession *owner); + + virtual void release(); + + virtual bool is_trigger_enabled() const; + + virtual QString format_device_title() const = 0; + signals: void device_updated(); void config_changed(); diff --git a/DSView/pv/device/file.cpp b/DSView/pv/device/file.cpp index 7efee676..eb494b04 100755 --- a/DSView/pv/device/file.cpp +++ b/DSView/pv/device/file.cpp @@ -39,6 +39,10 @@ File::File(QString path) : { } +File::~File(){ + +} + QString File::format_device_title() const { QFileInfo fi(_path); diff --git a/DSView/pv/device/file.h b/DSView/pv/device/file.h index d4299e7b..a4984170 100755 --- a/DSView/pv/device/file.h +++ b/DSView/pv/device/file.h @@ -35,10 +35,13 @@ namespace device { class File : public DevInst { + protected: File(QString path); public: + ~File(); + static File* create(QString name); QJsonArray get_decoders(); diff --git a/DSView/pv/devicemanager.cpp b/DSView/pv/devicemanager.cpp index 08bf0946..488d3e61 100755 --- a/DSView/pv/devicemanager.cpp +++ b/DSView/pv/devicemanager.cpp @@ -34,9 +34,6 @@ #include #include -#include - -using boost::shared_ptr; using std::list; using std::map; using std::ostringstream; @@ -45,57 +42,64 @@ using std::string; namespace pv { -DeviceManager::DeviceManager(struct sr_context *sr_ctx) : - _sr_ctx(sr_ctx) +DeviceManager::DeviceManager() { - init_drivers(); - scan_all_drivers(); + _sr_ctx = NULL; +} + +DeviceManager::DeviceManager(DeviceManager &o) +{ + (void)o; } DeviceManager::~DeviceManager() { - release_devices(); + } -const std::list > &DeviceManager::devices() const +void DeviceManager::initAll(struct sr_context *sr_ctx) +{ + _sr_ctx = sr_ctx; + init_drivers(); + scan_all_drivers(); +} + + void DeviceManager::UnInitAll() + { + release_devices(); + } + +void DeviceManager::add_device(DevInst *device) { - return _devices; + assert(device); + + auto it = std::find(_devices.begin(), _devices.end(), device); + if (it ==_devices.end()){ + _devices.push_front(device); + } } -void DeviceManager::add_device(boost::shared_ptr device) +void DeviceManager::del_device(DevInst *device) { assert(device); - if (std::find(_devices.begin(), _devices.end(), device) == - _devices.end()) - _devices.push_front(device); -} - -void DeviceManager::del_device(boost::shared_ptr device) -{ - assert(device); - BOOST_FOREACH(shared_ptr dev, _devices) { - assert(dev); - if(dev == device) { - dev->release(); - break; - } + auto it = std::find(_devices.begin(), _devices.end(), device); + if (it !=_devices.end()){ + _devices.erase(it); //remove from list + device->destroy(); } - if (std::find(_devices.begin(), _devices.end(), device) != - _devices.end()) - _devices.remove(device); } -std::list > DeviceManager::driver_scan( +std::list& DeviceManager::driver_scan( struct sr_dev_driver *const driver, GSList *const drvopts) { - list< shared_ptr > driver_devices; + list driver_devices; assert(driver); // Remove any device instances from this driver from the device // list. They will not be valid after the scan. - list< shared_ptr >::iterator i = _devices.begin(); + auto i = _devices.begin(); while (i != _devices.end()) { if ((*i)->dev_inst() && (*i)->dev_inst()->driver == driver) { @@ -119,16 +123,16 @@ std::list > DeviceManager::driver_scan( // Do the scan GSList *const devices = sr_driver_scan(driver, drvopts); - for (GSList *l = devices; l; l = l->next) - driver_devices.push_front(shared_ptr( - new device::Device((sr_dev_inst*)l->data))); - g_slist_free(devices); - //driver_devices.sort(compare_devices); - // Add the scanned devices to the main list - _devices.insert(_devices.end(), driver_devices.begin(), - driver_devices.end()); - //_devices.sort(compare_devices); + for (GSList *l = devices; l; l = l->next){ + Device *dev = new device::Device((sr_dev_inst*)l->data); //create new device + driver_devices.push_front(dev); + } + + g_slist_free(devices); + + // append the scanned devices to the main list + _devices.insert(_devices.end(), driver_devices.begin(), driver_devices.end()); return driver_devices; } @@ -149,8 +153,7 @@ void DeviceManager::init_drivers() void DeviceManager::release_devices() { // Release all the used devices - BOOST_FOREACH(shared_ptr dev, _devices) { - assert(dev); + for (DevInst *dev : _devices) { dev->release(); } @@ -170,8 +173,7 @@ void DeviceManager::scan_all_drivers() void DeviceManager::release_driver(struct sr_dev_driver *const driver) { - BOOST_FOREACH(shared_ptr dev, _devices) { - assert(dev); + for (DevInst *dev : _devices) { if(dev->dev_inst()->driver == driver) dev->release(); } @@ -180,8 +182,7 @@ void DeviceManager::release_driver(struct sr_dev_driver *const driver) sr_dev_clear(driver); } -bool DeviceManager::compare_devices(boost::shared_ptr a, - boost::shared_ptr b) +bool DeviceManager::compare_devices(DevInst *a, DevInst *b) { assert(a); assert(b); diff --git a/DSView/pv/devicemanager.h b/DSView/pv/devicemanager.h index 426b9aa8..b275b69b 100755 --- a/DSView/pv/devicemanager.h +++ b/DSView/pv/devicemanager.h @@ -30,8 +30,7 @@ #include #include -#include -#include +#include #include #include @@ -51,21 +50,30 @@ namespace device { class DevInst; } +using namespace pv::device; + class DeviceManager { +private: + DeviceManager(DeviceManager &o); + public: - DeviceManager(struct sr_context *sr_ctx); + DeviceManager(); ~DeviceManager(); - const std::list< boost::shared_ptr >& devices() const; + inline const std::list& devices(){ + return _devices; + } - void add_device(boost::shared_ptr device); - void del_device(boost::shared_ptr device); + void add_device(DevInst *device); + void del_device(DevInst *device); - std::list< boost::shared_ptr > driver_scan( - struct sr_dev_driver *const driver, - GSList *const drvopts = NULL); + std::list& driver_scan(struct sr_dev_driver *const driver, GSList *const drvopts = NULL); + + void initAll(struct sr_context *sr_ctx); + + void UnInitAll(); private: void init_drivers(); @@ -76,12 +84,11 @@ private: void release_driver(struct sr_dev_driver *const driver); - static bool compare_devices(boost::shared_ptr a, - boost::shared_ptr b); + static bool compare_devices(DevInst *a, DevInst *b); private: - struct sr_context *const _sr_ctx; - std::list< boost::shared_ptr > _devices; + struct sr_context* _sr_ctx; + std::list _devices; }; } // namespace pv diff --git a/DSView/pv/dialogs/calibration.cpp b/DSView/pv/dialogs/calibration.cpp index e91d1722..2a5b0a8a 100755 --- a/DSView/pv/dialogs/calibration.cpp +++ b/DSView/pv/dialogs/calibration.cpp @@ -121,7 +121,7 @@ void Calibration::retranslateUi() setTitle(tr("Manual Calibration")); } -void Calibration::set_device(boost::shared_ptr dev_inst) +void Calibration::set_device(DevInst *dev_inst) { assert(dev_inst); _dev_inst = dev_inst; diff --git a/DSView/pv/dialogs/calibration.h b/DSView/pv/dialogs/calibration.h index 8418606e..5764ce14 100755 --- a/DSView/pv/dialogs/calibration.h +++ b/DSView/pv/dialogs/calibration.h @@ -36,6 +36,8 @@ #include "../toolbars/titlebar.h" #include "dsdialog.h" +using namespace pv::device; + namespace pv { namespace dialogs { @@ -52,7 +54,7 @@ public: Calibration(QWidget *parent); ~Calibration(); - void set_device(boost::shared_ptr dev_inst); + void set_device(DevInst *dev_inst); protected: void accept(); void reject(); @@ -69,7 +71,7 @@ private slots: void reload_value(); private: - boost::shared_ptr _dev_inst; + DevInst *_dev_inst; QPushButton *_save_btn; QPushButton *_abort_btn; diff --git a/DSView/pv/dialogs/deviceoptions.cpp b/DSView/pv/dialogs/deviceoptions.cpp index fe8513ed..bfa6fe25 100755 --- a/DSView/pv/dialogs/deviceoptions.cpp +++ b/DSView/pv/dialogs/deviceoptions.cpp @@ -38,7 +38,7 @@ using namespace std; namespace pv { namespace dialogs { -DeviceOptions::DeviceOptions(QWidget *parent, boost::shared_ptr dev_inst) : +DeviceOptions::DeviceOptions(QWidget *parent, DevInst *dev_inst) : DSDialog(parent), _dev_inst(dev_inst), _button_box(QDialogButtonBox::Ok, Qt::Horizontal, this), @@ -67,7 +67,7 @@ DeviceOptions::DeviceOptions(QWidget *parent, boost::shared_ptrget_config(NULL, NULL, SR_CONF_OPERATION_MODE); if (gvar != NULL) { diff --git a/DSView/pv/dialogs/deviceoptions.h b/DSView/pv/dialogs/deviceoptions.h index ae803c8a..38ee0798 100755 --- a/DSView/pv/dialogs/deviceoptions.h +++ b/DSView/pv/dialogs/deviceoptions.h @@ -47,6 +47,8 @@ #include "../toolbars/titlebar.h" #include "../dialogs/dsdialog.h" +using namespace pv::device; + namespace pv { namespace dialogs { @@ -55,7 +57,7 @@ class DeviceOptions : public DSDialog Q_OBJECT public: - DeviceOptions(QWidget *parent, boost::shared_ptr dev_inst); + DeviceOptions(QWidget *parent, DevInst *dev_inst); ~DeviceOptions(); @@ -85,7 +87,7 @@ private slots: void channel_enable(); private: - boost::shared_ptr _dev_inst; + DevInst *_dev_inst; QVBoxLayout _layout; QGroupBox *_dynamic_box; diff --git a/DSView/pv/dialogs/dsomeasure.cpp b/DSView/pv/dialogs/dsomeasure.cpp index a454d86c..c5f97510 100755 --- a/DSView/pv/dialogs/dsomeasure.cpp +++ b/DSView/pv/dialogs/dsomeasure.cpp @@ -40,7 +40,7 @@ using namespace pv::view; namespace pv { namespace dialogs { -DsoMeasure::DsoMeasure(SigSession &session, View &parent, +DsoMeasure::DsoMeasure(SigSession *session, View &parent, unsigned int position, int last_sig_index) : DSDialog((QWidget *)&parent), _session(session), @@ -57,7 +57,7 @@ DsoMeasure::DsoMeasure(SigSession &session, View &parent, _measure_tab->setTabPosition(QTabWidget::West); _measure_tab->setUsesScrollButtons(false); - BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s)) && dsoSig->enabled()) { QWidget *measure_widget = new QWidget(this); @@ -79,7 +79,7 @@ DsoMeasure::DsoMeasure(SigSession &session, View &parent, connect(_button_box.button(QDialogButtonBox::Cancel), SIGNAL(clicked()), this, SLOT(reject())); connect(_button_box.button(QDialogButtonBox::Reset), SIGNAL(clicked()), this, SLOT(reset())); - connect(_session.get_device().get(), SIGNAL(device_updated()), this, SLOT(reject())); + connect(_session->get_device(), SIGNAL(device_updated()), this, SLOT(reject())); } DsoMeasure::~DsoMeasure(){ @@ -158,7 +158,7 @@ void DsoMeasure::accept() if(sc != NULL) { QVariant id = sc->property("id"); enum DSO_MEASURE_TYPE ms_type = DSO_MEASURE_TYPE(id.toInt()); - BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s))) { if (_measure_tab->currentWidget()->property("index").toInt() == dsoSig->get_index()) { diff --git a/DSView/pv/dialogs/dsomeasure.h b/DSView/pv/dialogs/dsomeasure.h index 5016fda7..11efed12 100755 --- a/DSView/pv/dialogs/dsomeasure.h +++ b/DSView/pv/dialogs/dsomeasure.h @@ -49,7 +49,7 @@ class DsoMeasure : public DSDialog Q_OBJECT public: - DsoMeasure(SigSession &session, view::View &parent, unsigned int position, int last_sig_index); + DsoMeasure(SigSession *session, view::View &parent, unsigned int position, int last_sig_index); ~DsoMeasure(); @@ -68,7 +68,7 @@ protected: void reject(); private: - SigSession &_session; + SigSession *_session; view::View &_view; unsigned int _position; diff --git a/DSView/pv/dialogs/fftoptions.cpp b/DSView/pv/dialogs/fftoptions.cpp index 9202500d..5af442e7 100755 --- a/DSView/pv/dialogs/fftoptions.cpp +++ b/DSView/pv/dialogs/fftoptions.cpp @@ -38,7 +38,7 @@ using namespace std; namespace pv { namespace dialogs { -FftOptions::FftOptions(QWidget *parent, SigSession &session) : +FftOptions::FftOptions(QWidget *parent, SigSession *session) : DSDialog(parent), _session(session), _button_box(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, @@ -67,7 +67,7 @@ FftOptions::FftOptions(QWidget *parent, SigSession &session) : _dbv_combobox = new QComboBox(this); // setup _ch_combobox - BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s))) { _ch_combobox->addItem(dsoSig->get_name(), QVariant::fromValue(dsoSig->get_index())); @@ -76,7 +76,7 @@ FftOptions::FftOptions(QWidget *parent, SigSession &session) : // setup _window_combobox _len_combobox _sample_limit = 0; - GVariant* gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_MAX_DSO_SAMPLELIMITS); + GVariant* gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_MAX_DSO_SAMPLELIMITS); if (gvar != NULL) { _sample_limit = g_variant_get_uint64(gvar) * 0.5; g_variant_unref(gvar); @@ -87,7 +87,7 @@ FftOptions::FftOptions(QWidget *parent, SigSession &session) : std::vector length; std::vector view_modes; std::vector dbv_ranges; - BOOST_FOREACH(const boost::shared_ptr t, _session.get_spectrum_traces()) { + BOOST_FOREACH(const boost::shared_ptr t, _session->get_spectrum_traces()) { boost::shared_ptr spectrumTraces; if ((spectrumTraces = dynamic_pointer_cast(t))) { windows = spectrumTraces->get_spectrum_stack()->get_windows_support(); @@ -137,7 +137,7 @@ FftOptions::FftOptions(QWidget *parent, SigSession &session) : } // load current settings - BOOST_FOREACH(const boost::shared_ptr t, _session.get_spectrum_traces()) { + BOOST_FOREACH(const boost::shared_ptr t, _session->get_spectrum_traces()) { boost::shared_ptr spectrumTraces; if ((spectrumTraces = dynamic_pointer_cast(t))) { if (spectrumTraces->enabled()) { @@ -217,7 +217,7 @@ FftOptions::FftOptions(QWidget *parent, SigSession &session) : connect(&_button_box, SIGNAL(rejected()), this, SLOT(reject())); connect(_window_combobox, SIGNAL(currentIndexChanged(QString)), this, SLOT(window_changed(QString))); connect(_len_combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(len_changed(int))); - connect(_session.get_device().get(), SIGNAL(device_updated()), this, SLOT(reject())); + connect(_session->get_device(), SIGNAL(device_updated()), this, SLOT(reject())); } FftOptions::~FftOptions(){ @@ -230,7 +230,7 @@ void FftOptions::accept() QDialog::accept(); - BOOST_FOREACH(const boost::shared_ptr t, _session.get_spectrum_traces()) { + BOOST_FOREACH(const boost::shared_ptr t, _session->get_spectrum_traces()) { boost::shared_ptr spectrumTraces; if ((spectrumTraces = dynamic_pointer_cast(t))) { spectrumTraces->set_enable(false); @@ -243,13 +243,13 @@ void FftOptions::accept() //spectrumTraces->init_zoom(); spectrumTraces->set_dbv_range(_dbv_combobox->currentData().toInt()); spectrumTraces->set_enable(_en_checkbox->isChecked()); - if (_session.get_capture_state() == SigSession::Stopped && + if (_session->get_capture_state() == SigSession::Stopped && spectrumTraces->enabled()) spectrumTraces->get_spectrum_stack()->calc_fft(); } } } - _session.spectrum_rebuild(); + _session->spectrum_rebuild(); } void FftOptions::reject() diff --git a/DSView/pv/dialogs/fftoptions.h b/DSView/pv/dialogs/fftoptions.h index 2486c871..dcca5e11 100755 --- a/DSView/pv/dialogs/fftoptions.h +++ b/DSView/pv/dialogs/fftoptions.h @@ -50,7 +50,7 @@ private: public: - FftOptions(QWidget *parent, SigSession &session); + FftOptions(QWidget *parent, SigSession *session); ~FftOptions(); @@ -63,7 +63,7 @@ private slots: void len_changed(int index); private: - SigSession &_session; + SigSession *_session; uint64_t _sample_limit; QComboBox *_len_combobox; diff --git a/DSView/pv/dialogs/interval.cpp b/DSView/pv/dialogs/interval.cpp index 7ab456b7..dcb13ca5 100755 --- a/DSView/pv/dialogs/interval.cpp +++ b/DSView/pv/dialogs/interval.cpp @@ -26,7 +26,7 @@ namespace pv { namespace dialogs { -Interval::Interval(SigSession &session, QWidget *parent) : +Interval::Interval(SigSession *session, QWidget *parent) : DSDialog(parent), _session(session), _button_box(QDialogButtonBox::Ok, @@ -47,7 +47,7 @@ Interval::Interval(SigSession &session, QWidget *parent) : connect(_interval_slider, SIGNAL(valueChanged(int)), _interval_spinBox, SLOT(setValue(int))); connect(_interval_spinBox, SIGNAL(valueChanged(int)), _interval_slider, SLOT(setValue(int))); - _interval_slider->setValue(_session.get_repeat_intvl()); + _interval_slider->setValue(_session->get_repeat_intvl()); QGridLayout *glayout = new QGridLayout(this); glayout->addWidget(_interval_label, 0, 0); @@ -64,7 +64,7 @@ Interval::Interval(SigSession &session, QWidget *parent) : void Interval::accept() { using namespace Qt; - _session.set_repeat_intvl(_interval_slider->value()); + _session->set_repeat_intvl(_interval_slider->value()); QDialog::accept(); } diff --git a/DSView/pv/dialogs/interval.h b/DSView/pv/dialogs/interval.h index 86e42ade..9e3c0c40 100755 --- a/DSView/pv/dialogs/interval.h +++ b/DSView/pv/dialogs/interval.h @@ -40,14 +40,14 @@ class Interval : public DSDialog Q_OBJECT public: - Interval(SigSession &session, QWidget *parent); + Interval(SigSession *session, QWidget *parent); protected: void accept(); void reject(); private: - SigSession &_session; + SigSession *_session; QLabel *_interval_label; QSpinBox *_interval_spinBox; diff --git a/DSView/pv/dialogs/lissajousoptions.cpp b/DSView/pv/dialogs/lissajousoptions.cpp index 02c98167..aa5d53f1 100755 --- a/DSView/pv/dialogs/lissajousoptions.cpp +++ b/DSView/pv/dialogs/lissajousoptions.cpp @@ -41,7 +41,7 @@ using namespace pv::view; namespace pv { namespace dialogs { -LissajousOptions::LissajousOptions(SigSession &session, QWidget *parent) : +LissajousOptions::LissajousOptions(SigSession *session, QWidget *parent) : DSDialog(parent), _session(session), _button_box(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, @@ -63,8 +63,8 @@ LissajousOptions::LissajousOptions(SigSession &session, QWidget *parent) : _percent = new QSlider(Qt::Horizontal, this); _percent->setRange(100, 100); _percent->setEnabled(false); - if (_session.cur_samplelimits() > WellLen) { - int min = ceil(WellLen*100.0/_session.cur_samplelimits()); + if (_session->cur_samplelimits() > WellLen) { + int min = ceil(WellLen*100.0/_session->cur_samplelimits()); _percent->setEnabled(true); _percent->setRange(min, 100); _percent->setValue(min); @@ -74,7 +74,7 @@ LissajousOptions::LissajousOptions(SigSession &session, QWidget *parent) : _y_group = new QGroupBox(this); QHBoxLayout *xlayout = new QHBoxLayout(); QHBoxLayout *ylayout = new QHBoxLayout(); - BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s))) { QString index_str = QString::number(dsoSig->get_index()); @@ -92,7 +92,7 @@ LissajousOptions::LissajousOptions(SigSession &session, QWidget *parent) : _y_group->setLayout(ylayout); - boost::shared_ptr lissajous = _session.get_lissajous_trace(); + boost::shared_ptr lissajous = _session->get_lissajous_trace(); if (lissajous) { _enable->setChecked(lissajous->enabled()); _percent->setValue(lissajous->percent()); @@ -180,15 +180,15 @@ void LissajousOptions::accept() } } bool enable = (xindex != -1 && yindex != -1 && _enable->isChecked()); - _session.lissajous_rebuild(enable, xindex, yindex, _percent->value()); + _session->lissajous_rebuild(enable, xindex, yindex, _percent->value()); - BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s))) { dsoSig->set_show(!enable); } } - boost::shared_ptr mathTrace = _session.get_math_trace(); + boost::shared_ptr mathTrace = _session->get_math_trace(); if (mathTrace && mathTrace->enabled()) { mathTrace->set_show(!enable); } diff --git a/DSView/pv/dialogs/lissajousoptions.h b/DSView/pv/dialogs/lissajousoptions.h index b0653548..9a7e7168 100755 --- a/DSView/pv/dialogs/lissajousoptions.h +++ b/DSView/pv/dialogs/lissajousoptions.h @@ -56,7 +56,7 @@ private: static const int WellLen = SR_Kn(16); public: - LissajousOptions(SigSession &session, QWidget *parent); + LissajousOptions(SigSession *session, QWidget *parent); private: void changeEvent(QEvent *event); @@ -67,7 +67,7 @@ protected: void reject(); private: - SigSession &_session; + SigSession *_session; QCheckBox *_enable; QGroupBox *_x_group; diff --git a/DSView/pv/dialogs/mathoptions.cpp b/DSView/pv/dialogs/mathoptions.cpp index 99169c7a..95111fa5 100755 --- a/DSView/pv/dialogs/mathoptions.cpp +++ b/DSView/pv/dialogs/mathoptions.cpp @@ -41,7 +41,7 @@ using namespace pv::view; namespace pv { namespace dialogs { -MathOptions::MathOptions(SigSession &session, QWidget *parent) : +MathOptions::MathOptions(SigSession *session, QWidget *parent) : DSDialog(parent), _session(session), _button_box(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, @@ -78,7 +78,7 @@ MathOptions::MathOptions(SigSession &session, QWidget *parent) : _src2_group = new QGroupBox(this); QHBoxLayout *src1_layout = new QHBoxLayout(); QHBoxLayout *src2_layout = new QHBoxLayout(); - BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s))) { QString index_str = QString::number(dsoSig->get_index()); @@ -96,7 +96,7 @@ MathOptions::MathOptions(SigSession &session, QWidget *parent) : _src2_group->setLayout(src2_layout); - boost::shared_ptr math = _session.get_math_trace(); + boost::shared_ptr math = _session->get_math_trace(); if (math) { _enable->setChecked(math->enabled()); for (QVector::const_iterator i = _src1_radio.begin(); @@ -206,7 +206,7 @@ void MathOptions::accept() bool enable = (src1 != -1 && src2 != -1 && _enable->isChecked()); boost::shared_ptr dsoSig1; boost::shared_ptr dsoSig2; - BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s))) { if (dsoSig->get_index() == src1) @@ -215,7 +215,7 @@ void MathOptions::accept() dsoSig2 = dsoSig; } } - _session.math_rebuild(enable, dsoSig1, dsoSig2, type); + _session->math_rebuild(enable, dsoSig1, dsoSig2, type); } void MathOptions::reject() diff --git a/DSView/pv/dialogs/mathoptions.h b/DSView/pv/dialogs/mathoptions.h index d11afa36..ae50e7b4 100755 --- a/DSView/pv/dialogs/mathoptions.h +++ b/DSView/pv/dialogs/mathoptions.h @@ -56,7 +56,7 @@ private: static const int WellLen = SR_Kn(16); public: - MathOptions(SigSession &session, QWidget *parent); + MathOptions(SigSession *session, QWidget *parent); private: void changeEvent(QEvent *event); @@ -67,7 +67,7 @@ protected: void reject(); private: - SigSession &_session; + SigSession *_session; QCheckBox *_enable; QGroupBox *_src1_group; diff --git a/DSView/pv/dialogs/protocolexp.cpp b/DSView/pv/dialogs/protocolexp.cpp index 8956e4ad..d526a998 100755 --- a/DSView/pv/dialogs/protocolexp.cpp +++ b/DSView/pv/dialogs/protocolexp.cpp @@ -46,7 +46,7 @@ using namespace std; namespace pv { namespace dialogs { -ProtocolExp::ProtocolExp(QWidget *parent, SigSession &session) : +ProtocolExp::ProtocolExp(QWidget *parent, SigSession *session) : DSDialog(parent), _session(session), _button_box(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, @@ -64,7 +64,7 @@ ProtocolExp::ProtocolExp(QWidget *parent, SigSession &session) : _flayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); _flayout->addRow(new QLabel(tr("Export Format: "), this), _format_combobox); - pv::data::DecoderModel* decoder_model = _session.get_decoder_model(); + pv::data::DecoderModel* decoder_model = _session->get_decoder_model(); const boost::shared_ptr& decoder_stack = decoder_model->getDecoderStack(); if (decoder_stack) { int row_index = 0; @@ -96,7 +96,7 @@ ProtocolExp::ProtocolExp(QWidget *parent, SigSession &session) : connect(&_button_box, SIGNAL(accepted()), this, SLOT(accept())); connect(&_button_box, SIGNAL(rejected()), this, SLOT(reject())); - connect(_session.get_device().get(), SIGNAL(device_updated()), this, SLOT(reject())); + connect(_session->get_device(), SIGNAL(device_updated()), this, SLOT(reject())); } @@ -124,7 +124,7 @@ void ProtocolExp::accept() QString default_filter = _format_combobox->currentText(); QString default_name = app._userHistory.protocolExportPath + "/" + "decoder-"; - default_name += _session.get_session_time().toString("-yyMMdd-hhmmss"); + default_name += _session->get_session_time().toString("-yyMMdd-hhmmss"); QString file_name = QFileDialog::getSaveFileName( this, @@ -170,7 +170,7 @@ void ProtocolExp::accept() .arg("Time[ns]") .arg(title); - pv::data::DecoderModel* decoder_model = _session.get_decoder_model(); + pv::data::DecoderModel* decoder_model = _session->get_decoder_model(); const boost::shared_ptr& decoder_stack = decoder_model->getDecoderStack(); int row_index = 0; Row row; diff --git a/DSView/pv/dialogs/protocolexp.h b/DSView/pv/dialogs/protocolexp.h index b978c604..e888eedf 100755 --- a/DSView/pv/dialogs/protocolexp.h +++ b/DSView/pv/dialogs/protocolexp.h @@ -54,7 +54,7 @@ class ProtocolExp : public DSDialog Q_OBJECT public: - ProtocolExp(QWidget *parent, SigSession &session); + ProtocolExp(QWidget *parent, SigSession *session); protected: void accept(); @@ -67,7 +67,7 @@ private slots: void cancel_export(); private: - SigSession &_session; + SigSession *_session; toolbars::TitleBar *_titlebar; QComboBox *_format_combobox; diff --git a/DSView/pv/dialogs/protocollist.cpp b/DSView/pv/dialogs/protocollist.cpp index 170f8eda..3b2599af 100755 --- a/DSView/pv/dialogs/protocollist.cpp +++ b/DSView/pv/dialogs/protocollist.cpp @@ -38,27 +38,27 @@ using namespace std; namespace pv { namespace dialogs { -ProtocolList::ProtocolList(QWidget *parent, SigSession &session) : +ProtocolList::ProtocolList(QWidget *parent, SigSession *session) : DSDialog(parent), _session(session), _button_box(QDialogButtonBox::Ok, Qt::Horizontal, this) { - pv::data::DecoderModel* decoder_model = _session.get_decoder_model(); + pv::data::DecoderModel* decoder_model = _session->get_decoder_model(); _map_zoom_combobox = new QComboBox(this); _map_zoom_combobox->addItem(tr("Fit to Window")); _map_zoom_combobox->addItem(tr("Fixed")); - int cur_map_zoom = _session.get_map_zoom(); + int cur_map_zoom = _session->get_map_zoom(); if (cur_map_zoom >= _map_zoom_combobox->count()) _map_zoom_combobox->setCurrentIndex(0); else _map_zoom_combobox->setCurrentIndex(cur_map_zoom); - connect(_map_zoom_combobox, SIGNAL(currentIndexChanged(int)), &_session, SLOT(set_map_zoom(int))); + connect(_map_zoom_combobox, SIGNAL(currentIndexChanged(int)), _session, SLOT(set_map_zoom(int))); _protocol_combobox = new QComboBox(this); const std::vector< boost::shared_ptr > decode_sigs( - _session.get_decode_signals()); + _session->get_decode_signals()); int index = 0; BOOST_FOREACH(boost::shared_ptr d, decode_sigs) { _protocol_combobox->addItem(d->get_name()); @@ -89,7 +89,7 @@ ProtocolList::ProtocolList(QWidget *parent, SigSession &session) : connect(&_button_box, SIGNAL(accepted()), this, SLOT(accept())); connect(_protocol_combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(set_protocol(int))); set_protocol(_protocol_combobox->currentIndex()); - connect(_session.get_device().get(), SIGNAL(device_updated()), this, SLOT(reject())); + connect(_session->get_device(), SIGNAL(device_updated()), this, SLOT(reject())); } @@ -128,7 +128,7 @@ void ProtocolList::set_protocol(int index) boost::shared_ptr decoder_stack; const std::vector< boost::shared_ptr > decode_sigs( - _session.get_decode_signals()); + _session->get_decode_signals()); int cur_index = 0; BOOST_FOREACH(boost::shared_ptr d, decode_sigs) { if (index == cur_index) { @@ -139,11 +139,11 @@ void ProtocolList::set_protocol(int index) } if (!decoder_stack){ - _session.get_decoder_model()->setDecoderStack(NULL); + _session->get_decoder_model()->setDecoderStack(NULL); return; } - _session.get_decoder_model()->setDecoderStack(decoder_stack); + _session->get_decoder_model()->setDecoderStack(decoder_stack); int row_index = 0; const std::map rows = decoder_stack->get_rows_lshow(); for (std::map::const_iterator i = rows.begin(); @@ -170,7 +170,7 @@ void ProtocolList::on_row_check(bool show) boost::shared_ptr decoder_stack; const std::vector< boost::shared_ptr > decode_sigs( - _session.get_decode_signals()); + _session->get_decode_signals()); int cur_index = 0; BOOST_FOREACH(boost::shared_ptr d, decode_sigs) { if (cur_index == _protocol_combobox->currentIndex()) { @@ -192,7 +192,7 @@ void ProtocolList::on_row_check(bool show) } } - _session.get_decoder_model()->setDecoderStack(decoder_stack); + _session->get_decoder_model()->setDecoderStack(decoder_stack); } } // namespace dialogs } // namespace pv diff --git a/DSView/pv/dialogs/protocollist.h b/DSView/pv/dialogs/protocollist.h index bc6a9891..1d4c68f2 100755 --- a/DSView/pv/dialogs/protocollist.h +++ b/DSView/pv/dialogs/protocollist.h @@ -48,7 +48,7 @@ class ProtocolList : public DSDialog Q_OBJECT public: - ProtocolList(QWidget *parent, SigSession &session); + ProtocolList(QWidget *parent, SigSession *session); protected: void accept(); @@ -59,7 +59,7 @@ private slots: void on_row_check(bool show); private: - SigSession &_session; + SigSession *_session; toolbars::TitleBar *_titlebar; QComboBox *_map_zoom_combobox; diff --git a/DSView/pv/dialogs/regionoptions.cpp b/DSView/pv/dialogs/regionoptions.cpp index 0a113133..12853c1d 100755 --- a/DSView/pv/dialogs/regionoptions.cpp +++ b/DSView/pv/dialogs/regionoptions.cpp @@ -37,7 +37,7 @@ namespace dialogs { const QString RegionOptions::RegionStart = QT_TR_NOOP("Start"); const QString RegionOptions::RegionEnd = QT_TR_NOOP("End"); -RegionOptions::RegionOptions(view::View *view, SigSession &session, QWidget *parent) : +RegionOptions::RegionOptions(view::View *view, SigSession *session, QWidget *parent) : DSDialog(parent), _session(session), _view(view), @@ -75,19 +75,19 @@ RegionOptions::RegionOptions(view::View *view, SigSession &session, QWidget *par setTitle(tr("Region")); connect(&_button_box, SIGNAL(accepted()), this, SLOT(set_region())); - connect(_session.get_device().get(), SIGNAL(device_updated()), this, SLOT(reject())); + connect(_session->get_device(), SIGNAL(device_updated()), this, SLOT(reject())); } void RegionOptions::set_region() { - const uint64_t last_samples = _session.cur_samplelimits() - 1; + const uint64_t last_samples = _session->cur_samplelimits() - 1; const int index1 = _start_comboBox->currentIndex(); const int index2 = _end_comboBox->currentIndex(); uint64_t start, end; - _session.set_save_start(0); - _session.set_save_end(last_samples); + _session->set_save_start(0); + _session->set_save_end(last_samples); if (index1 == 0) { start = 0; @@ -105,8 +105,8 @@ void RegionOptions::set_region() if (end > last_samples) end = last_samples; - _session.set_save_start(min(start, end)); - _session.set_save_end(max(start, end)); + _session->set_save_start(min(start, end)); + _session->set_save_end(max(start, end)); QDialog::accept(); } diff --git a/DSView/pv/dialogs/regionoptions.h b/DSView/pv/dialogs/regionoptions.h index 097baff7..a0ec9554 100755 --- a/DSView/pv/dialogs/regionoptions.h +++ b/DSView/pv/dialogs/regionoptions.h @@ -52,13 +52,13 @@ private: static const QString RegionEnd; public: - RegionOptions(view::View *view, SigSession &session, QWidget *parent = 0); + RegionOptions(view::View *view, SigSession *session, QWidget *parent = 0); private slots: void set_region(); private: - SigSession &_session; + SigSession *_session; view::View *_view; QComboBox *_start_comboBox; diff --git a/DSView/pv/dialogs/search.cpp b/DSView/pv/dialogs/search.cpp index 86e69dda..74568d7f 100755 --- a/DSView/pv/dialogs/search.cpp +++ b/DSView/pv/dialogs/search.cpp @@ -30,7 +30,7 @@ namespace pv { namespace dialogs { -Search::Search(QWidget *parent, SigSession &session, std::map pattern) : +Search::Search(QWidget *parent, SigSession *session, std::map pattern) : DSDialog(parent), _session(session) { @@ -51,7 +51,7 @@ Search::Search(QWidget *parent, SigSession &session, std::map int index = 0; BOOST_FOREACH(const boost::shared_ptr sig, - _session.get_signals()) { + _session->get_signals()) { assert(sig); boost::shared_ptr logic_sig; if ((logic_sig = boost::dynamic_pointer_cast(sig))) { @@ -86,7 +86,7 @@ Search::Search(QWidget *parent, SigSession &session, std::map connect(&search_buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(&search_buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - connect(_session.get_device().get(), SIGNAL(device_updated()), this, SLOT(reject())); + connect(_session->get_device(), SIGNAL(device_updated()), this, SLOT(reject())); } Search::~Search() @@ -112,7 +112,7 @@ std::map Search::get_pattern() int index = 0; BOOST_FOREACH(const boost::shared_ptr sig, - _session.get_signals()) { + _session->get_signals()) { assert(sig); boost::shared_ptr logic_sig; if ((logic_sig = boost::dynamic_pointer_cast(sig))) { diff --git a/DSView/pv/dialogs/search.h b/DSView/pv/dialogs/search.h index d1f7950a..29c3d5a4 100755 --- a/DSView/pv/dialogs/search.h +++ b/DSView/pv/dialogs/search.h @@ -45,7 +45,7 @@ class Search : public DSDialog public: - Search(QWidget *parent, SigSession &session, std::map pattern); + Search(QWidget *parent, SigSession *session, std::map pattern); ~Search(); std::map get_pattern(); @@ -59,7 +59,7 @@ private slots: void format(); private: - SigSession &_session; + SigSession *_session; toolbars::TitleBar *_titlebar; QVector _search_lineEdit_vec; diff --git a/DSView/pv/dialogs/storeprogress.cpp b/DSView/pv/dialogs/storeprogress.cpp index 19d0329e..7c0b31de 100755 --- a/DSView/pv/dialogs/storeprogress.cpp +++ b/DSView/pv/dialogs/storeprogress.cpp @@ -34,7 +34,7 @@ namespace pv { namespace dialogs { -StoreProgress::StoreProgress(SigSession &session, QWidget *parent) : +StoreProgress::StoreProgress(SigSession *session, QWidget *parent) : DSDialog(parent), _store_session(session) { @@ -155,7 +155,7 @@ void StoreProgress::accept() void StoreProgress::timeout() { if (_done) { - _store_session.session().set_saving(false); + _store_session.session()->set_saving(false); save_done(); close(); } else { diff --git a/DSView/pv/dialogs/storeprogress.h b/DSView/pv/dialogs/storeprogress.h index 63d7c013..a7077142 100755 --- a/DSView/pv/dialogs/storeprogress.h +++ b/DSView/pv/dialogs/storeprogress.h @@ -44,7 +44,7 @@ class StoreProgress : public DSDialog Q_OBJECT public: - StoreProgress(SigSession &session, + StoreProgress(SigSession *session, QWidget *parent = 0); virtual ~StoreProgress(); diff --git a/DSView/pv/dialogs/waitingdialog.cpp b/DSView/pv/dialogs/waitingdialog.cpp index c901cbdf..6272227c 100755 --- a/DSView/pv/dialogs/waitingdialog.cpp +++ b/DSView/pv/dialogs/waitingdialog.cpp @@ -43,14 +43,14 @@ namespace dialogs { const QString WaitingDialog::TIPS_WAIT = "Waiting"; const QString WaitingDialog::TIPS_FINISHED = "Finished!"; -WaitingDialog::WaitingDialog(QWidget *parent, SigSession &session, int key) : +WaitingDialog::WaitingDialog(QWidget *parent, SigSession *session, int key) : DSDialog(parent), _key(key), _session(session), _button_box(QDialogButtonBox::Abort, Qt::Horizontal, this) { - _dev_inst = _session.get_device(); + _dev_inst = _session->get_device(); this->setFixedSize((GIF_WIDTH+2*TIP_WIDTH)*1.2, (GIF_HEIGHT+2*TIP_HEIGHT)*4); this->setWindowOpacity(0.7); @@ -79,7 +79,7 @@ WaitingDialog::WaitingDialog(QWidget *parent, SigSession &session, int key) : connect(timer, SIGNAL(timeout()), this, SLOT(changeText())); connect(&_button_box, SIGNAL(accepted()), this, SLOT(accept())); connect(&_button_box, SIGNAL(rejected()), this, SLOT(reject())); - connect(_dev_inst.get(), SIGNAL(device_updated()), this, SLOT(stop())); + connect(_dev_inst, SIGNAL(device_updated()), this, SLOT(stop())); QVBoxLayout *mlayout = new QVBoxLayout(); @@ -186,7 +186,7 @@ void WaitingDialog::changeText() g_variant_unref(gvar); if (zero_fgain) { boost::shared_ptr dsoSig; - BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) + BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { if ((dsoSig = dynamic_pointer_cast(s))) dsoSig->set_enable(dsoSig->get_index() == 0); diff --git a/DSView/pv/dialogs/waitingdialog.h b/DSView/pv/dialogs/waitingdialog.h index fd14615a..e8fb2474 100755 --- a/DSView/pv/dialogs/waitingdialog.h +++ b/DSView/pv/dialogs/waitingdialog.h @@ -35,6 +35,8 @@ #include "../toolbars/titlebar.h" #include "dsdialog.h" +using namespace pv::device; + namespace pv { namespace dialogs { @@ -53,7 +55,7 @@ private: static const QString TIPS_FINISHED; public: - WaitingDialog(QWidget *parent, SigSession &session, int key); + WaitingDialog(QWidget *parent, SigSession *session, int key); int start(); protected: @@ -66,8 +68,8 @@ private slots: private: int _key; - SigSession &_session; - boost::shared_ptr _dev_inst; + SigSession *_session; + DevInst* _dev_inst; toolbars::TitleBar *_titlebar; QDialogButtonBox _button_box; diff --git a/DSView/pv/dock/dsotriggerdock.cpp b/DSView/pv/dock/dsotriggerdock.cpp index 08bc64b6..d11e961c 100755 --- a/DSView/pv/dock/dsotriggerdock.cpp +++ b/DSView/pv/dock/dsotriggerdock.cpp @@ -44,7 +44,7 @@ using namespace std; namespace pv { namespace dock { -DsoTriggerDock::DsoTriggerDock(QWidget *parent, SigSession &session) : +DsoTriggerDock::DsoTriggerDock(QWidget *parent, SigSession *session) : QScrollArea(parent), _session(session) { @@ -222,7 +222,7 @@ void DsoTriggerDock::auto_trig(int index) void DsoTriggerDock::pos_changed(int pos) { int ret; - ret = _session.get_device()->set_config(NULL, NULL, + ret = _session->get_device()->set_config(NULL, NULL, SR_CONF_HORIZ_TRIGGERPOS, g_variant_new_byte((uint8_t)pos)); if (!ret) { @@ -247,7 +247,7 @@ void DsoTriggerDock::hold_changed(int hold) _holdoff_slider->setRange(0, 999); } holdoff = _holdoff_slider->value() * _holdoff_comboBox->currentData().toDouble() / 10; - ret = _session.get_device()->set_config(NULL, NULL, + ret = _session->get_device()->set_config(NULL, NULL, SR_CONF_TRIGGER_HOLDOFF, g_variant_new_uint64(holdoff)); @@ -264,7 +264,7 @@ void DsoTriggerDock::hold_changed(int hold) void DsoTriggerDock::margin_changed(int margin) { int ret; - ret = _session.get_device()->set_config(NULL, NULL, + ret = _session->get_device()->set_config(NULL, NULL, SR_CONF_TRIGGER_MARGIN, g_variant_new_byte(margin)); if (!ret) { @@ -282,7 +282,7 @@ void DsoTriggerDock::source_changed() int id = _source_group->checkedId(); int ret; - ret = _session.get_device()->set_config(NULL, NULL, + ret = _session->get_device()->set_config(NULL, NULL, SR_CONF_TRIGGER_SOURCE, g_variant_new_byte(id)); if (!ret) { @@ -300,7 +300,7 @@ void DsoTriggerDock::channel_changed(int ch) (void)ch; int ret; - ret = _session.get_device()->set_config(NULL, NULL, + ret = _session->get_device()->set_config(NULL, NULL, SR_CONF_TRIGGER_CHANNEL, g_variant_new_byte(_channel_comboBox->currentData().toInt())); if (!ret) { @@ -318,7 +318,7 @@ void DsoTriggerDock::type_changed() int id = _type_group->checkedId(); int ret; - ret = _session.get_device()->set_config(NULL, NULL, + ret = _session->get_device()->set_config(NULL, NULL, SR_CONF_TRIGGER_SLOPE, g_variant_new_byte(id)); if (!ret) { @@ -333,7 +333,7 @@ void DsoTriggerDock::type_changed() void DsoTriggerDock::device_change() { - if (_session.get_device()->name() != "DSLogic") { + if (_session->get_device()->name() != "DSLogic") { _position_spinBox->setDisabled(true); _position_slider->setDisabled(true); } else { @@ -344,7 +344,7 @@ void DsoTriggerDock::device_change() void DsoTriggerDock::init() { - if (_session.get_device()->name().contains("virtual")) { + if (_session->get_device()->name().contains("virtual")) { foreach(QAbstractButton * btn, _source_group->buttons()) btn->setDisabled(true); foreach(QAbstractButton * btn, _type_group->buttons()) @@ -368,7 +368,7 @@ void DsoTriggerDock::init() } // TRIGGERPOS - GVariant* gvar = _session.get_device()->get_config(NULL, NULL, + GVariant* gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_HORIZ_TRIGGERPOS); if (gvar != NULL) { uint16_t pos = g_variant_get_byte(gvar); @@ -376,7 +376,7 @@ void DsoTriggerDock::init() _position_slider->setValue(pos); } - gvar = _session.get_device()->get_config(NULL, NULL, + gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_TRIGGER_SOURCE); if (gvar != NULL) { uint8_t src = g_variant_get_byte(gvar); @@ -387,13 +387,13 @@ void DsoTriggerDock::init() // setup _channel_comboBox disconnect(_channel_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(channel_changed(int))); _channel_comboBox->clear(); - BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s))) { _channel_comboBox->addItem(dsoSig->get_name(), QVariant::fromValue(dsoSig->get_index())); } } - gvar = _session.get_device()->get_config(NULL, NULL, + gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_TRIGGER_CHANNEL); if (gvar != NULL) { uint8_t src = g_variant_get_byte(gvar); @@ -407,7 +407,7 @@ void DsoTriggerDock::init() } connect(_channel_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(channel_changed(int))); - gvar = _session.get_device()->get_config(NULL, NULL, + gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_TRIGGER_SLOPE); if (gvar != NULL) { uint8_t slope = g_variant_get_byte(gvar); @@ -417,7 +417,7 @@ void DsoTriggerDock::init() disconnect(_holdoff_slider, SIGNAL(valueChanged(int)), this, SLOT(hold_changed(int))); disconnect(_holdoff_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(hold_changed(int))); - gvar = _session.get_device()->get_config(NULL, NULL, + gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_TRIGGER_HOLDOFF); if (gvar != NULL) { uint64_t holdoff = g_variant_get_uint64(gvar); @@ -439,7 +439,7 @@ void DsoTriggerDock::init() connect(_holdoff_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(hold_changed(int))); disconnect(_margin_slider, SIGNAL(valueChanged(int)), this, SLOT(margin_changed(int))); - gvar = _session.get_device()->get_config(NULL, NULL, + gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_TRIGGER_MARGIN); if (gvar != NULL) { uint8_t margin = g_variant_get_byte(gvar); diff --git a/DSView/pv/dock/dsotriggerdock.h b/DSView/pv/dock/dsotriggerdock.h index b0971b72..4688577e 100755 --- a/DSView/pv/dock/dsotriggerdock.h +++ b/DSView/pv/dock/dsotriggerdock.h @@ -44,7 +44,7 @@ class DsoTriggerDock : public QScrollArea Q_OBJECT public: - DsoTriggerDock(QWidget *parent, SigSession &session); + DsoTriggerDock(QWidget *parent, SigSession *session); ~DsoTriggerDock(); void paintEvent(QPaintEvent *); @@ -75,7 +75,7 @@ private slots: private: private: - SigSession &_session; + SigSession *_session; QWidget *_widget; diff --git a/DSView/pv/dock/measuredock.cpp b/DSView/pv/dock/measuredock.cpp index fc7644f6..77166789 100755 --- a/DSView/pv/dock/measuredock.cpp +++ b/DSView/pv/dock/measuredock.cpp @@ -50,7 +50,7 @@ namespace dock { using namespace pv::view; -MeasureDock::MeasureDock(QWidget *parent, View &view, SigSession &session) : +MeasureDock::MeasureDock(QWidget *parent, View &view, SigSession *session) : QScrollArea(parent), _session(session), _view(view) @@ -212,7 +212,7 @@ void MeasureDock::refresh() void MeasureDock::reload() { - if (_session.get_device()->dev_inst()->mode == LOGIC) + if (_session->get_device()->dev_inst()->mode == LOGIC) _edge_groupBox->setDisabled(false); else _edge_groupBox->setDisabled(true); @@ -598,7 +598,7 @@ void MeasureDock::update_edge() if (start_ret && end_ret) { uint64_t rising_edges; uint64_t falling_edges; - const std::vector< boost::shared_ptr > sigs(_session.get_signals()); + const std::vector< boost::shared_ptr > sigs(_session->get_signals()); for(size_t i = 0; i < sigs.size(); i++) { const boost::shared_ptr s(sigs[i]); boost::shared_ptr logicSig; @@ -650,7 +650,7 @@ QComboBox* MeasureDock::create_probe_selector(QWidget *parent) void MeasureDock::update_probe_selector(QComboBox *selector) { selector->clear(); - const std::vector< boost::shared_ptr > sigs(_session.get_signals()); + const std::vector< boost::shared_ptr > sigs(_session->get_signals()); for(size_t i = 0; i < sigs.size(); i++) { const boost::shared_ptr s(sigs[i]); assert(s); diff --git a/DSView/pv/dock/measuredock.h b/DSView/pv/dock/measuredock.h index c9f9beeb..379b1d38 100755 --- a/DSView/pv/dock/measuredock.h +++ b/DSView/pv/dock/measuredock.h @@ -61,7 +61,7 @@ private: static const int Max_Measure_Limits = 16; public: - MeasureDock(QWidget *parent, pv::view::View &view, SigSession &session); + MeasureDock(QWidget *parent, pv::view::View &view, SigSession *session); ~MeasureDock(); void paintEvent(QPaintEvent *); @@ -101,7 +101,7 @@ public slots: void refresh(); private: - SigSession &_session; + SigSession *_session; view::View &_view; QWidget *_widget; diff --git a/DSView/pv/dock/protocoldock.cpp b/DSView/pv/dock/protocoldock.cpp index c4709222..48e04900 100755 --- a/DSView/pv/dock/protocoldock.cpp +++ b/DSView/pv/dock/protocoldock.cpp @@ -56,7 +56,7 @@ namespace pv { namespace dock { -ProtocolDock::ProtocolDock(QWidget *parent, view::View &view, SigSession &session) : +ProtocolDock::ProtocolDock(QWidget *parent, view::View &view, SigSession *session) : QScrollArea(parent), _session(session), _view(view), @@ -126,7 +126,7 @@ ProtocolDock::ProtocolDock(QWidget *parent, view::View &view, SigSession &sessio //dn_title_layout->addStretch(1); _table_view = new QTableView(_dn_widget); - _table_view->setModel(_session.get_decoder_model()); + _table_view->setModel(_session->get_decoder_model()); _table_view->setAlternatingRowColors(true); _table_view->setShowGrid(false); _table_view->horizontalHeader()->setStretchLastSection(true); @@ -197,7 +197,7 @@ ProtocolDock::ProtocolDock(QWidget *parent, view::View &view, SigSession &sessio connect(_del_all_button, SIGNAL(clicked()),this, SLOT(on_del_all_protocol())); - connect(&_session, SIGNAL(decode_done()), this, SLOT(update_model())); + connect(_session, SIGNAL(decode_done()), this, SLOT(update_model())); connect(this, SIGNAL(protocol_updated()), this, SLOT(update_model())); connect(_table_view, SIGNAL(clicked(QModelIndex)), this, SLOT(item_clicked(QModelIndex))); connect(_table_view->horizontalHeader(), SIGNAL(sectionResized(int,int,int)), this, SLOT(column_resize(int, int, int))); @@ -305,7 +305,7 @@ void ProtocolDock::on_add_protocol() void ProtocolDock::add_protocol(bool silent) { - if (_session.get_device()->dev_inst()->mode != LOGIC) { + if (_session->get_device()->dev_inst()->mode != LOGIC) { MsgBox::Show(NULL, "Protocol Analyzer\nProtocol Analyzer is only valid in Digital Mode!", this); return; } @@ -316,7 +316,7 @@ void ProtocolDock::add_protocol(bool silent) DecoderStatus *dstatus = new DecoderStatus(); dstatus->m_format = (int)DecoderDataFormat::hex; - if (_session.add_decoder(decoder, silent, dstatus)) + if (_session->add_decoder(decoder, silent, dstatus)) { //crate item layer QString protocolName = _protocol_combobox->currentText(); @@ -333,7 +333,7 @@ void ProtocolDock::add_protocol(bool silent) } //progress connection - const std::vector> decode_sigs(_session.get_decode_signals()); + const std::vector> decode_sigs(_session->get_decode_signals()); connect(decode_sigs.back().get(), SIGNAL(decoded_progress(int)), this, SLOT(decoded_progress(int))); @@ -360,7 +360,7 @@ void ProtocolDock::del_all_protocol() for (auto it = _protocol_items.begin(); it != _protocol_items.end(); it++) { DESTROY_QT_LATER((*it)); //destory control - _session.remove_decode_signal(0); + _session->remove_decode_signal(0); } _protocol_items.clear(); protocol_updated(); @@ -374,7 +374,7 @@ void ProtocolDock::decoded_progress(int progress) int pg = 0; QString err=""; const std::vector< boost::shared_ptr > decode_sigs( - _session.get_decode_signals()); + _session->get_decode_signals()); int index = 0; BOOST_FOREACH(boost::shared_ptr d, decode_sigs) { @@ -409,13 +409,13 @@ void ProtocolDock::set_model() { pv::dialogs::ProtocolList *protocollist_dlg = new pv::dialogs::ProtocolList(this, _session); protocollist_dlg->exec(); - resize_table_view(_session.get_decoder_model()); - _model_proxy.setSourceModel(_session.get_decoder_model()); + resize_table_view(_session->get_decoder_model()); + _model_proxy.setSourceModel(_session->get_decoder_model()); search_done(); // clear mark_index of all DecoderStacks const std::vector< boost::shared_ptr > decode_sigs( - _session.get_decode_signals()); + _session->get_decode_signals()); BOOST_FOREACH(boost::shared_ptr d, decode_sigs) { d->decoder()->set_mark_index(-1); } @@ -423,9 +423,9 @@ void ProtocolDock::set_model() void ProtocolDock::update_model() { - pv::data::DecoderModel *decoder_model = _session.get_decoder_model(); + pv::data::DecoderModel *decoder_model = _session->get_decoder_model(); const std::vector< boost::shared_ptr > decode_sigs( - _session.get_decode_signals()); + _session->get_decode_signals()); if (decode_sigs.size() == 0) decoder_model->setDecoderStack(NULL); else if (!decoder_model->getDecoderStack()) @@ -466,18 +466,18 @@ void ProtocolDock::resize_table_view(data::DecoderModel* decoder_model) void ProtocolDock::item_clicked(const QModelIndex &index) { - pv::data::DecoderModel *decoder_model = _session.get_decoder_model(); + pv::data::DecoderModel *decoder_model = _session->get_decoder_model(); boost::shared_ptr decoder_stack = decoder_model->getDecoderStack(); if (decoder_stack) { pv::data::decode::Annotation ann; if (decoder_stack->list_annotation(ann, index.column(), index.row())) { const std::vector< boost::shared_ptr > decode_sigs( - _session.get_decode_signals()); + _session->get_decode_signals()); BOOST_FOREACH(boost::shared_ptr d, decode_sigs) { d->decoder()->set_mark_index(-1); } decoder_stack->set_mark_index((ann.start_sample()+ann.end_sample())/2); - _session.show_region(ann.start_sample(), ann.end_sample(), false); + _session->show_region(ann.start_sample(), ann.end_sample(), false); } } _table_view->resizeRowToContents(index.row()); @@ -524,7 +524,7 @@ void ProtocolDock::column_resize(int index, int old_size, int new_size) (void)index; (void)old_size; (void)new_size; - pv::data::DecoderModel *decoder_model = _session.get_decoder_model(); + pv::data::DecoderModel *decoder_model = _session->get_decoder_model(); if (decoder_model->getDecoderStack()) { int top_row = _table_view->rowAt(0); int bom_row = _table_view->rowAt(_table_view->height()); @@ -544,7 +544,7 @@ void ProtocolDock::export_table_view() void ProtocolDock::nav_table_view() { uint64_t row_index = 0; - pv::data::DecoderModel *decoder_model = _session.get_decoder_model(); + pv::data::DecoderModel *decoder_model = _session->get_decoder_model(); boost::shared_ptr decoder_stack = decoder_model->getDecoderStack(); if (decoder_stack) { uint64_t offset = _view.offset() * (decoder_stack->samplerate() * _view.scale()); @@ -565,7 +565,7 @@ void ProtocolDock::nav_table_view() pv::data::decode::Annotation ann; decoder_stack->list_annotation(ann, index.column(), index.row()); const std::vector< boost::shared_ptr > decode_sigs( - _session.get_decode_signals()); + _session->get_decode_signals()); BOOST_FOREACH(boost::shared_ptr d, decode_sigs) { d->decoder()->set_mark_index(-1); } @@ -591,7 +591,7 @@ void ProtocolDock::search_pre() int i = 0; uint64_t rowCount = _model_proxy.rowCount(); QModelIndex matchingIndex; - pv::data::DecoderModel *decoder_model = _session.get_decoder_model(); + pv::data::DecoderModel *decoder_model = _session->get_decoder_model(); boost::shared_ptr decoder_stack = decoder_model->getDecoderStack(); do { _cur_search_index--; @@ -647,7 +647,7 @@ void ProtocolDock::search_nxt() int i = 0; uint64_t rowCount = _model_proxy.rowCount(); QModelIndex matchingIndex; - pv::data::DecoderModel *decoder_model = _session.get_decoder_model(); + pv::data::DecoderModel *decoder_model = _session->get_decoder_model(); boost::shared_ptr decoder_stack = decoder_model->getDecoderStack(); do { _cur_search_index++; @@ -711,7 +711,7 @@ void ProtocolDock::search_update() if (!_search_edited) return; - pv::data::DecoderModel *decoder_model = _session.get_decoder_model(); + pv::data::DecoderModel *decoder_model = _session->get_decoder_model(); boost::shared_ptr decoder_stack = decoder_model->getDecoderStack(); if (!decoder_stack) return; @@ -746,7 +746,7 @@ void ProtocolDock::OnProtocolSetting(void *handle){ int dex = 0; for (auto it = _protocol_items.begin(); it != _protocol_items.end(); it++){ if ((*it) == handle){ - _session.rst_decoder(dex); + _session->rst_decoder(dex); protocol_updated(); break; } @@ -764,7 +764,7 @@ void ProtocolDock::OnProtocolDelete(void *handle){ if ((*it) == handle){ DESTROY_QT_LATER(*it); _protocol_items.remove(dex); - _session.remove_decode_signal(dex); + _session->remove_decode_signal(dex); protocol_updated(); break; } diff --git a/DSView/pv/dock/protocoldock.h b/DSView/pv/dock/protocoldock.h index 8b7a1a39..1e7e9ded 100755 --- a/DSView/pv/dock/protocoldock.h +++ b/DSView/pv/dock/protocoldock.h @@ -64,7 +64,7 @@ public: static const uint64_t ProgressRows = 100000; public: - ProtocolDock(QWidget *parent, view::View &view, SigSession &session); + ProtocolDock(QWidget *parent, view::View &view, SigSession *session); ~ProtocolDock(); void del_all_protocol(); @@ -109,7 +109,7 @@ private: void resize_table_view(data::DecoderModel *decoder_model); private: - SigSession &_session; + SigSession *_session; view::View &_view; QSortFilterProxyModel _model_proxy; double _cur_search_index; diff --git a/DSView/pv/dock/searchdock.cpp b/DSView/pv/dock/searchdock.cpp index 1372ca78..87b2cee3 100755 --- a/DSView/pv/dock/searchdock.cpp +++ b/DSView/pv/dock/searchdock.cpp @@ -50,7 +50,7 @@ namespace dock { using namespace pv::view; using namespace pv::widgets; -SearchDock::SearchDock(QWidget *parent, View &view, SigSession &session) : +SearchDock::SearchDock(QWidget *parent, View &view, SigSession *session) : QWidget(parent), _session(session), _view(view) @@ -130,7 +130,7 @@ void SearchDock::on_previous() bool ret; int64_t last_pos; bool last_hit; - const boost::shared_ptr snapshot(_session.get_snapshot(SR_CHANNEL_LOGIC)); + const boost::shared_ptr snapshot(_session->get_snapshot(SR_CHANNEL_LOGIC)); assert(snapshot); const boost::shared_ptr logic_snapshot = boost::dynamic_pointer_cast(snapshot); @@ -192,7 +192,7 @@ void SearchDock::on_next() { bool ret; int64_t last_pos; - const boost::shared_ptr snapshot(_session.get_snapshot(SR_CHANNEL_LOGIC)); + const boost::shared_ptr snapshot(_session->get_snapshot(SR_CHANNEL_LOGIC)); assert(snapshot); const boost::shared_ptr logic_snapshot = boost::dynamic_pointer_cast(snapshot); diff --git a/DSView/pv/dock/searchdock.h b/DSView/pv/dock/searchdock.h index 0f68daad..6e940bb3 100755 --- a/DSView/pv/dock/searchdock.h +++ b/DSView/pv/dock/searchdock.h @@ -63,7 +63,7 @@ class SearchDock : public QWidget Q_OBJECT public: - SearchDock(QWidget *parent, pv::view::View &view, SigSession &session); + SearchDock(QWidget *parent, pv::view::View &view, SigSession *session); ~SearchDock(); void paintEvent(QPaintEvent *); @@ -78,7 +78,7 @@ public slots: void on_set(); private: - SigSession &_session; + SigSession *_session; view::View &_view; std::map _pattern; diff --git a/DSView/pv/dock/triggerdock.cpp b/DSView/pv/dock/triggerdock.cpp index e38ea7dc..d69b7828 100755 --- a/DSView/pv/dock/triggerdock.cpp +++ b/DSView/pv/dock/triggerdock.cpp @@ -40,13 +40,13 @@ namespace dock { const int TriggerDock::MinTrigPosition = 1; -TriggerDock::TriggerDock(QWidget *parent, SigSession &session) : +TriggerDock::TriggerDock(QWidget *parent, SigSession *session) : QScrollArea(parent), _session(session) { _cur_ch_num = 16; - if (_session.get_device()) { - GVariant *gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_TOTAL_CH_NUM); + if (_session->get_device()) { + GVariant *gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_TOTAL_CH_NUM); if (gvar != NULL) { _cur_ch_num = g_variant_get_int16(gvar); g_variant_unref(gvar); @@ -180,9 +180,9 @@ void TriggerDock::simple_trigger() void TriggerDock::adv_trigger() { - if (_session.get_device()->name() == "DSLogic") { + if (_session->get_device()->name() == "DSLogic") { bool stream = false; - GVariant *gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_STREAM); + GVariant *gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_STREAM); if (gvar != NULL) { stream = g_variant_get_boolean(gvar); g_variant_unref(gvar); @@ -248,20 +248,20 @@ void TriggerDock::device_updated() bool stream = false; uint8_t maxRange; uint64_t sample_limits; - GVariant *gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_HW_DEPTH); + GVariant *gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_HW_DEPTH); if (gvar != NULL) { hw_depth = g_variant_get_uint64(gvar); g_variant_unref(gvar); - if (_session.get_device()->dev_inst()->mode == LOGIC) { + if (_session->get_device()->dev_inst()->mode == LOGIC) { - gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_STREAM); + gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_STREAM); if (gvar != NULL) { stream = g_variant_get_boolean(gvar); g_variant_unref(gvar); } - sample_limits = _session.get_device()->get_sample_limit(); + sample_limits = _session->get_device()->get_sample_limit(); if (stream) maxRange = 1; else if (hw_depth >= sample_limits) @@ -271,7 +271,7 @@ void TriggerDock::device_updated() _position_spinBox->setRange(MinTrigPosition, maxRange); _position_slider->setRange(MinTrigPosition, maxRange); - if (_session.get_device()->name().contains("virtual") || + if (_session->get_device()->name().contains("virtual") || stream) { _simple_radioButton->setChecked(true); simple_trigger(); @@ -279,7 +279,7 @@ void TriggerDock::device_updated() } } - gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_TOTAL_CH_NUM); + gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_TOTAL_CH_NUM); if (gvar != NULL) { int ch_num = g_variant_get_int16(gvar); g_variant_unref(gvar); diff --git a/DSView/pv/dock/triggerdock.h b/DSView/pv/dock/triggerdock.h index 3dd19e68..336f5dc7 100755 --- a/DSView/pv/dock/triggerdock.h +++ b/DSView/pv/dock/triggerdock.h @@ -57,7 +57,7 @@ private: static const int MinTrigPosition; public: - TriggerDock(QWidget *parent, SigSession &session); + TriggerDock(QWidget *parent, SigSession *session); ~TriggerDock(); void paintEvent(QPaintEvent *); @@ -95,7 +95,7 @@ public slots: private: private: - SigSession &_session; + SigSession *_session; int _cur_ch_num; QWidget *_widget; diff --git a/DSView/pv/mainframe.cpp b/DSView/pv/mainframe.cpp index 7c83b53b..fca633f7 100755 --- a/DSView/pv/mainframe.cpp +++ b/DSView/pv/mainframe.cpp @@ -51,8 +51,7 @@ namespace pv { -MainFrame::MainFrame(DeviceManager &device_manager, - const char *open_file_name) +MainFrame::MainFrame() { setAttribute(Qt::WA_TranslucentBackground); // Make this a borderless window which can't @@ -83,7 +82,7 @@ MainFrame::MainFrame(DeviceManager &device_manager, _titleBar = new toolbars::TitleBar(true, this); // MainWindow - _mainWindow = new MainWindow(device_manager, open_file_name, this); + _mainWindow = new MainWindow(this); _mainWindow->setWindowFlags(Qt::Widget); _titleBar->setTitle(_mainWindow->windowTitle()); diff --git a/DSView/pv/mainframe.h b/DSView/pv/mainframe.h index 7e6711ce..e04ac0ee 100755 --- a/DSView/pv/mainframe.h +++ b/DSView/pv/mainframe.h @@ -30,8 +30,7 @@ #include namespace pv { - -class DeviceManager; + class MainWindow; namespace toolbars { @@ -66,8 +65,7 @@ public: }borderTypes; public: - MainFrame(DeviceManager &device_manager, - const char *open_file_name = NULL); + MainFrame(); void readSettings(); diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index 029d1e0c..7cadf548 100755 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -92,6 +92,7 @@ #include #include "../ui/msgbox.h" #include "config/appconfig.h" +#include "appcontrol.h" using boost::shared_ptr; using boost::dynamic_pointer_cast; @@ -100,30 +101,32 @@ using std::vector; namespace pv { -MainWindow::MainWindow(DeviceManager &device_manager, - const char *open_file_name, - QWidget *parent) : +MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), - _device_manager(device_manager), - _session(device_manager), _hot_detach(false), _msg(NULL) { + _control = AppControl::Instance(); + setup_ui(); setContextMenuPolicy(Qt::NoContextMenu); + /* if (open_file_name) { qDebug("Open file: %s", open_file_name); const QString s(QString::fromUtf8(open_file_name)); - QMetaObject::invokeMethod(this, "load_file", + QMetaObject::invokeMethod(this, "on_load_file", Qt::QueuedConnection, Q_ARG(QString, s)); } + */ } void MainWindow::setup_ui() { + SigSession *_session = _control->GetSession(); + setObjectName(QString::fromUtf8("MainWindow")); setContentsMargins(0,0,0,0); layout()->setMargin(0); @@ -236,7 +239,7 @@ void MainWindow::setup_ui() _search_dock->installEventFilter(this); // Populate the device list and select the initially selected device - _session.set_default_device(boost::bind(&MainWindow::session_error, this, + _session->set_default_device(boost::bind(&MainWindow::session_error, this, QString(tr("Set Default Device failed")), _1)); // defaut language @@ -249,22 +252,22 @@ void MainWindow::setup_ui() // update device update_device_list(); - _session.start_hotplug_proc(boost::bind(&MainWindow::session_error, this, + _session->start_hotplug_proc(boost::bind(&MainWindow::session_error, this, QString(tr("Hotplug failed")), _1)); retranslateUi(); // Setup _session events - connect(&_session, SIGNAL(capture_state_changed(int)), this, SLOT(capture_state_changed(int))); - connect(&_session, SIGNAL(device_attach()), this, SLOT(device_attach()), Qt::QueuedConnection); - connect(&_session, SIGNAL(device_detach()), this, SLOT(device_detach()), Qt::QueuedConnection); - connect(&_session, SIGNAL(session_error()), this, SLOT(on_show_error()), Qt::QueuedConnection); - connect(&_session, SIGNAL(session_save()), this, SLOT(session_save())); - connect(&_session, SIGNAL(data_updated()), _measure_widget, SLOT(reCalc())); - connect(&_session, SIGNAL(repeat_resume()), this, SLOT(repeat_resume())); - connect(&_session, SIGNAL(update_capture()), _view, SLOT(update_hori_res()), Qt::DirectConnection); - connect(&_session, SIGNAL(cur_snap_samplerate_changed()), _measure_widget, SLOT(cursor_update())); + connect(_session, SIGNAL(capture_state_changed(int)), this, SLOT(capture_state_changed(int))); + connect(_session, SIGNAL(device_attach()), this, SLOT(device_attach()), Qt::QueuedConnection); + connect(_session, SIGNAL(device_detach()), this, SLOT(device_detach()), Qt::QueuedConnection); + connect(_session, SIGNAL(session_error()), this, SLOT(on_show_error()), Qt::QueuedConnection); + connect(_session, SIGNAL(session_save()), this, SLOT(session_save())); + connect(_session, SIGNAL(data_updated()), _measure_widget, SLOT(reCalc())); + connect(_session, SIGNAL(repeat_resume()), this, SLOT(repeat_resume())); + connect(_session, SIGNAL(update_capture()), _view, SLOT(update_hori_res()), Qt::DirectConnection); + connect(_session, SIGNAL(cur_snap_samplerate_changed()), _measure_widget, SLOT(cursor_update())); //view connect(_view, SIGNAL(cursor_update()), _measure_widget, SLOT(cursor_update())); @@ -342,8 +345,10 @@ void MainWindow::update_device_list() AppConfig &app = AppConfig::Instance(); + SigSession *_session = _control->GetSession(); + switchLanguage(app._frameOptions.language); - _session.stop_capture(); + _session->stop_capture(); _view->reload(); _trigger_widget->device_updated(); @@ -351,13 +356,15 @@ void MainWindow::update_device_list() _trig_bar->reload(); - boost::shared_ptr selected_device = _session.get_device(); + DeviceManager &_device_manager = _control->GetDeviceManager(); + + DevInst *selected_device = _session->get_device(); _device_manager.add_device(selected_device); - _session.init_signals(); + _session->init_signals(); _sampling_bar->set_device_list(_device_manager.devices(), selected_device); - boost::shared_ptr file_dev; - if((file_dev = dynamic_pointer_cast(selected_device))) { + File *file_dev = NULL; + if((file_dev = dynamic_cast(selected_device))) { // check version if (selected_device->dev_inst()->mode == LOGIC) { GVariant* gvar = selected_device->get_config(NULL, NULL, SR_CONF_FILE_VERSION); @@ -385,7 +392,7 @@ void MainWindow::update_device_list() // load data const QString errorMessage( QString(tr("Failed to capture file data!"))); - _session.start_capture(true, boost::bind(&MainWindow::session_error, this, + _session->start_capture(true, boost::bind(&MainWindow::session_error, this, errorMessage, _1)); } @@ -457,20 +464,23 @@ void MainWindow::update_device_list() void MainWindow::on_device_updated_reload() { + SigSession *_session = _control->GetSession(); _trigger_widget->device_updated(); - _session.reload(); + _session->reload(); _measure_widget->reload(); } void MainWindow::on_load_file(QString file_name) { + SigSession *_session = _control->GetSession(); + try { - if (strncmp(_session.get_device()->name().toUtf8(), "virtual", 7)) + if (strncmp(_session->get_device()->name().toUtf8(), "virtual", 7)) session_save(); - _session.set_file(file_name); + _session->set_file(file_name); } catch(QString e) { show_session_error(tr("Failed to load ") + file_name, e); - _session.set_default_device(boost::bind(&MainWindow::session_error, this, + _session->set_default_device(boost::bind(&MainWindow::session_error, this, QString(tr("Set Default Device failed")), _1)); update_device_list(); return; @@ -494,23 +504,27 @@ void MainWindow::show_session_error( void MainWindow::device_attach() { - _session.get_device()->device_updated(); - //_session.stop_hot_plug_proc(); + SigSession *_session = _control->GetSession(); - _session.set_repeating(false); - _session.stop_capture(); + _session->get_device()->device_updated(); + //_session->stop_hot_plug_proc(); + + _session->set_repeating(false); + _session->stop_capture(); _sampling_bar->set_sampling(false); - _session.capture_state_changed(SigSession::Stopped); + _session->capture_state_changed(SigSession::Stopped); struct sr_dev_driver **const drivers = sr_driver_list(); struct sr_dev_driver **driver; + DeviceManager &_device_manager = _control->GetDeviceManager(); + for (driver = drivers; *driver; driver++) if (*driver) _device_manager.driver_scan(*driver); - _session.set_default_device(boost::bind(&MainWindow::session_error, this, + _session->set_default_device(boost::bind(&MainWindow::session_error, this, QString(tr("Set Default Device failed")), _1)); update_device_list(); @@ -518,21 +532,23 @@ void MainWindow::device_attach() void MainWindow::device_detach() { - _session.get_device()->device_updated(); - //_session.stop_hot_plug_proc(); + SigSession *_session = _control->GetSession(); - _session.set_repeating(false); - _session.stop_capture(); + _session->get_device()->device_updated(); + //_session->stop_hot_plug_proc(); + + _session->set_repeating(false); + _session->stop_capture(); _sampling_bar->set_sampling(false); - _session.capture_state_changed(SigSession::Stopped); + _session->capture_state_changed(SigSession::Stopped); session_save(); _view->hide_calibration(); - if (_session.get_device()->dev_inst()->mode != DSO && - strncmp(_session.get_device()->name().toUtf8(), "virtual", 7)) { - const boost::shared_ptr logic_snapshot(_session.get_snapshot(SR_CHANNEL_LOGIC)); + if (_session->get_device()->dev_inst()->mode != DSO && + strncmp(_session->get_device()->name().toUtf8(), "virtual", 7)) { + const boost::shared_ptr logic_snapshot(_session->get_snapshot(SR_CHANNEL_LOGIC)); assert(logic_snapshot); - const boost::shared_ptr analog_snapshot(_session.get_snapshot(SR_CHANNEL_ANALOG)); + const boost::shared_ptr analog_snapshot(_session->get_snapshot(SR_CHANNEL_ANALOG)); assert(analog_snapshot); if (!logic_snapshot->empty() || !analog_snapshot->empty()) { @@ -550,15 +566,18 @@ void MainWindow::device_detach() } _hot_detach = true; - if (!_session.get_saving()) + if (!_session->get_saving()) device_detach_post(); } void MainWindow::device_detach_post() { + SigSession *_session = _control->GetSession(); + if (!_hot_detach) return; + DeviceManager &_device_manager = _control->GetDeviceManager(); _hot_detach = false; struct sr_dev_driver **const drivers = sr_driver_list(); struct sr_dev_driver **driver; @@ -566,16 +585,18 @@ void MainWindow::device_detach_post() if (*driver) _device_manager.driver_scan(*driver); - _session.set_default_device(boost::bind(&MainWindow::session_error, this, + _session->set_default_device(boost::bind(&MainWindow::session_error, this, QString(tr("Set Default Device failed")), _1)); update_device_list(); } void MainWindow::device_changed(bool close) { + SigSession *_session = _control->GetSession(); + if (close) { _sampling_bar->set_sampling(false); - _session.set_default_device(boost::bind(&MainWindow::session_error, this, + _session->set_default_device(boost::bind(&MainWindow::session_error, this, QString(tr("Set Default Device failed")), _1)); } update_device_list(); @@ -583,36 +604,40 @@ void MainWindow::device_changed(bool close) void MainWindow::on_run_stop() { - switch(_session.get_capture_state()) { + SigSession *_session = _control->GetSession(); + + switch(_session->get_capture_state()) { case SigSession::Init: case SigSession::Stopped: commit_trigger(false); - _session.start_capture(false, + _session->start_capture(false, boost::bind(&MainWindow::session_error, this, QString(tr("Capture failed")), _1)); _view->capture_init(); break; case SigSession::Running: - _session.stop_capture(); + _session->stop_capture(); break; } } void MainWindow::on_instant_stop() { - switch(_session.get_capture_state()) { + SigSession *_session = _control->GetSession(); + + switch(_session->get_capture_state()) { case SigSession::Init: case SigSession::Stopped: commit_trigger(true); - _session.start_capture(true, + _session->start_capture(true, boost::bind(&MainWindow::session_error, this, QString(tr("Capture failed")), _1)); _view->capture_init(); break; case SigSession::Running: - _session.stop_capture(); + _session->stop_capture(); break; } } @@ -631,26 +656,28 @@ void MainWindow::on_show_error() QString ch_status = ""; uint64_t error_pattern; - switch(_session.get_error()) { + SigSession *_session = _control->GetSession(); + + switch(_session->get_error()) { case SigSession::Hw_err: - _session.set_repeating(false); - _session.stop_capture(); + _session->set_repeating(false); + _session->stop_capture(); title = tr("Hardware Operation Failed"); details = tr("Please replug device to refresh hardware configuration!"); break; case SigSession::Malloc_err: - _session.set_repeating(false); - _session.stop_capture(); + _session->set_repeating(false); + _session->stop_capture(); title = tr("Malloc Error"); details = tr("Memory is not enough for this sample!\nPlease reduce the sample depth!"); break; case SigSession::Test_data_err: - _session.set_repeating(false); - _session.stop_capture(); + _session->set_repeating(false); + _session->stop_capture(); _sampling_bar->set_sampling(false); - _session.capture_state_changed(SigSession::Stopped); + _session->capture_state_changed(SigSession::Stopped); title = tr("Data Error"); - error_pattern = _session.get_error_pattern(); + error_pattern = _session->get_error_pattern(); for(int i = 0; i < 16; i++) { if (error_pattern & 0x01) ch_status += "X "; @@ -665,11 +692,11 @@ void MainWindow::on_show_error() case SigSession::Pkt_data_err: title = tr("Packet Error"); details = tr("the content of received packet are not expected!"); - _session.refresh(0); + _session->refresh(0); break; case SigSession::Data_overflow: - _session.set_repeating(false); - _session.stop_capture(); + _session->set_repeating(false); + _session->stop_capture(); title = tr("Data Overflow"); details = tr("USB bandwidth can not support current sample rate! \nPlease reduce the sample rate!"); break; @@ -680,7 +707,7 @@ void MainWindow::on_show_error() } dialogs::DSMessageBox msg(this); - connect(_session.get_device().get(), SIGNAL(device_updated()), &msg, SLOT(accept())); + connect(_session->get_device(), SIGNAL(device_updated()), &msg, SLOT(accept())); QFont font("Monaco"); font.setStyleHint(QFont::Monospace); font.setFixedPitch(true); @@ -692,18 +719,20 @@ void MainWindow::on_show_error() msg.mBox()->setIcon(QMessageBox::Warning); msg.exec(); - _session.clear_error(); + _session->clear_error(); } void MainWindow::capture_state_changed(int state) { - if (!_session.repeat_check()) { + SigSession *_session = _control->GetSession(); + + if (!_session->repeat_check()) { _file_bar->enable_toggle(state != SigSession::Running); _sampling_bar->set_sampling(state == SigSession::Running); _view->on_state_changed(state != SigSession::Running); - if (_session.get_device()->dev_inst()->mode != DSO || - _session.get_instant()) { + if (_session->get_device()->dev_inst()->mode != DSO || + _session->get_instant()) { _sampling_bar->enable_toggle(state != SigSession::Running); _trig_bar->enable_toggle(state != SigSession::Running); //_measure_dock->widget()->setEnabled(state != SigSession::Running); @@ -727,11 +756,12 @@ void MainWindow::session_save() #endif AppConfig &app = AppConfig::Instance(); + SigSession *_session = _control->GetSession(); if(dir.mkpath(path)) { dir.cd(path); - QString driver_name = _session.get_device()->name(); - QString mode_name = QString::number(_session.get_device()->dev_inst()->mode); + QString driver_name = _session->get_device()->name(); + QString mode_name = QString::number(_session->get_device()->dev_inst()->mode); QString lang_name = ".ses" + QString::number(app._frameOptions.language); QString file_name = dir.absolutePath() + "/" + driver_name + mode_name + @@ -762,7 +792,9 @@ void MainWindow::on_protocol(bool visible) void MainWindow::on_trigger(bool visible) { - if (_session.get_device()->dev_inst()->mode != DSO) { + SigSession *_session = _control->GetSession(); + + if (_session->get_device()->dev_inst()->mode != DSO) { _trigger_widget->init(); _trigger_dock->setVisible(visible); _dso_trigger_dock->setVisible(false); @@ -779,16 +811,17 @@ void MainWindow::commit_trigger(bool instant) int i = 0; AppConfig &app = AppConfig::Instance(); + SigSession *_session = _control->GetSession(); ds_trigger_init(); - if (_session.get_device()->dev_inst()->mode != LOGIC || + if (_session->get_device()->dev_inst()->mode != LOGIC || instant) return; if (!_trigger_widget->commit_trigger()) { /* simple trigger check trigger_enable */ - BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) + BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { assert(s); boost::shared_ptr logicSig; @@ -810,7 +843,7 @@ void MainWindow::commit_trigger(bool instant) msg.exec(); if (msg.mBox()->clickedButton() == cancelButton) { - BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) + BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { assert(s); boost::shared_ptr logicSig; @@ -876,7 +909,9 @@ void MainWindow::on_save() // dialogs::RegionOptions *regionDlg = new dialogs::RegionOptions(_view, _session, this); // regionDlg->exec(); - _session.set_saving(true); + SigSession *_session = _control->GetSession(); + + _session->set_saving(true); QString session_file; QDir dir; #if QT_VERSION >= 0x050400 @@ -899,6 +934,7 @@ void MainWindow::on_save() void MainWindow::on_export() { using pv::dialogs::StoreProgress; + SigSession *_session = _control->GetSession(); StoreProgress *dlg = new StoreProgress(_session, this); dlg->export_run(); @@ -927,36 +963,21 @@ bool MainWindow::load_session_json(QJsonDocument json, bool file_dev) sessionObj["Version"].toInt() != Session_Version) return false; + SigSession *_session = _control->GetSession(); + // check device and mode - const sr_dev_inst *const sdi = _session.get_device()->dev_inst(); + const sr_dev_inst *const sdi = _session->get_device()->dev_inst(); if ((!file_dev && strcmp(sdi->driver->name, sessionObj["Device"].toString().toUtf8()) != 0) || sdi->mode != sessionObj["DeviceMode"].toDouble()) { MsgBox::Show(NULL, "Session File is not compatible with current device or mode!", this); return false; } - - AppConfig &app = AppConfig::Instance(); - - // check language - if (sessionObj.contains("Language")) { - switchLanguage(sessionObj["Language"].toInt()); - } else if (sessionObj.contains("Operation Mode")) { - bool language_matched = _session.get_device()->set_config(NULL, NULL, SR_CONF_OPERATION_MODE, - g_variant_new_string(sessionObj["Operation Mode"].toString().toUtf8())); - if (!language_matched) { - if (app._frameOptions.language != QLocale::Chinese) - switchLanguage(QLocale::Chinese); - else - switchLanguage(QLocale::English); - } - } - + // clear decoders if (sdi->mode == LOGIC) { _protocol_widget->del_all_protocol(); - } - + } // load device settings GVariant *gvar_opts; @@ -970,21 +991,21 @@ bool MainWindow::load_session_json(QJsonDocument json, bool file_dev) if (!sessionObj.contains(info->name)) continue; if (info->datatype == SR_T_BOOL) - _session.get_device()->set_config(NULL, NULL, info->key, g_variant_new_boolean(sessionObj[info->name].toDouble())); + _session->get_device()->set_config(NULL, NULL, info->key, g_variant_new_boolean(sessionObj[info->name].toDouble())); else if (info->datatype == SR_T_UINT64) - _session.get_device()->set_config(NULL, NULL, info->key, g_variant_new_uint64(sessionObj[info->name].toString().toULongLong())); + _session->get_device()->set_config(NULL, NULL, info->key, g_variant_new_uint64(sessionObj[info->name].toString().toULongLong())); else if (info->datatype == SR_T_UINT8) - _session.get_device()->set_config(NULL, NULL, info->key, g_variant_new_byte(sessionObj[info->name].toString().toUInt())); + _session->get_device()->set_config(NULL, NULL, info->key, g_variant_new_byte(sessionObj[info->name].toString().toUInt())); else if (info->datatype == SR_T_FLOAT) - _session.get_device()->set_config(NULL, NULL, info->key, g_variant_new_double(sessionObj[info->name].toDouble())); + _session->get_device()->set_config(NULL, NULL, info->key, g_variant_new_double(sessionObj[info->name].toDouble())); else if (info->datatype == SR_T_CHAR) - _session.get_device()->set_config(NULL, NULL, info->key, g_variant_new_string(sessionObj[info->name].toString().toUtf8())); + _session->get_device()->set_config(NULL, NULL, info->key, g_variant_new_string(sessionObj[info->name].toString().toUtf8())); } } // load channel settings if (file_dev && (sdi->mode == DSO)) { - for (const GSList *l = _session.get_device()->dev_inst()->channels; l; l = l->next) { + for (const GSList *l = _session->get_device()->dev_inst()->channels; l; l = l->next) { sr_channel *const probe = (sr_channel*)l->data; assert(probe); foreach (const QJsonValue &value, sessionObj["channel"].toArray()) { @@ -1003,7 +1024,7 @@ bool MainWindow::load_session_json(QJsonDocument json, bool file_dev) } } } else { - for (const GSList *l = _session.get_device()->dev_inst()->channels; l; l = l->next) { + for (const GSList *l = _session->get_device()->dev_inst()->channels; l; l = l->next) { sr_channel *const probe = (sr_channel*)l->data; assert(probe); bool isEnabled = false; @@ -1029,12 +1050,12 @@ bool MainWindow::load_session_json(QJsonDocument json, bool file_dev) } } - //_session.init_signals(); - _session.reload(); + //_session->init_signals(); + _session->reload(); // load signal setting if (file_dev && (sdi->mode == DSO)) { - BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { foreach (const QJsonValue &value, sessionObj["channel"].toArray()) { QJsonObject obj = value.toObject(); if ((strcmp(s->get_name().toStdString().c_str(), g_strdup(obj["name"].toString().toStdString().c_str())) == 0) && @@ -1053,7 +1074,7 @@ bool MainWindow::load_session_json(QJsonDocument json, bool file_dev) } } } else { - BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { foreach (const QJsonValue &value, sessionObj["channel"].toArray()) { QJsonObject obj = value.toObject(); if ((s->get_index() == obj["index"].toDouble()) && @@ -1126,11 +1147,12 @@ bool MainWindow::on_store_session(QString name) //outStream.setGenerateByteOrderMark(true); // UTF-8 without BOM AppConfig &app = AppConfig::Instance(); + SigSession *_session = _control->GetSession(); GVariant *gvar_opts; GVariant *gvar; gsize num_opts; - const sr_dev_inst *const sdi = _session.get_device()->dev_inst(); + const sr_dev_inst *const sdi = _session->get_device()->dev_inst(); QJsonObject sessionVar; QJsonArray channelVar; sessionVar["Version"]= QJsonValue::fromVariant(Session_Version); @@ -1145,7 +1167,7 @@ bool MainWindow::on_store_session(QString name) for (unsigned int i = 0; i < num_opts; i++) { const struct sr_config_info *const info = sr_config_info_get(options[i]); - gvar = _session.get_device()->get_config(NULL, NULL, info->key); + gvar = _session->get_device()->get_config(NULL, NULL, info->key); if (gvar != NULL) { if (info->datatype == SR_T_BOOL) sessionVar[info->name] = QJsonValue::fromVariant(g_variant_get_boolean(gvar)); @@ -1161,7 +1183,7 @@ bool MainWindow::on_store_session(QString name) } } - BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { QJsonObject s_obj; s_obj["index"] = s->get_index(); s_obj["type"] = s->get_type(); @@ -1200,7 +1222,7 @@ bool MainWindow::on_store_session(QString name) } sessionVar["channel"] = channelVar; - if (_session.get_device()->dev_inst()->mode == LOGIC) { + if (_session->get_device()->dev_inst()->mode == LOGIC) { sessionVar["trigger"] = _trigger_widget->get_session(); } @@ -1209,7 +1231,7 @@ bool MainWindow::on_store_session(QString name) sessionVar["decoder"] = ss.json_decoders(); - if (_session.get_device()->dev_inst()->mode == DSO) { + if (_session->get_device()->dev_inst()->mode == DSO) { sessionVar["measure"] = _view->get_viewstatus()->get_session(); } @@ -1236,14 +1258,16 @@ void MainWindow::restore_dock() } } - if (_session.get_device()->dev_inst()->mode != DSO) { + SigSession *_session = _control->GetSession(); + + if (_session->get_device()->dev_inst()->mode != DSO) { _dso_trigger_dock->setVisible(false); _trig_bar->update_trig_btn(_trigger_dock->isVisible()); } else { _trigger_dock->setVisible(false); _trig_bar->update_trig_btn(_dso_trigger_dock->isVisible()); } - if (_session.get_device()->dev_inst()->mode != LOGIC) { + if (_session->get_device()->dev_inst()->mode != LOGIC) { on_protocol(false); @@ -1258,7 +1282,8 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) (void) object; if ( event->type() == QEvent::KeyPress ) { - const vector< boost::shared_ptr > sigs(_session.get_signals()); + SigSession *_session = _control->GetSession(); + const vector< boost::shared_ptr > sigs(_session->get_signals()); QKeyEvent *ke = (QKeyEvent *) event; switch(ke->key()) { case Qt::Key_S: @@ -1268,7 +1293,7 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) on_instant_stop(); break; case Qt::Key_T: - if (_session.get_device()->dev_inst()->mode == DSO) + if (_session->get_device()->dev_inst()->mode == DSO) on_trigger(!_dso_trigger_dock->isVisible()); else on_trigger(!_trigger_dock->isVisible()); @@ -1367,7 +1392,8 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) void MainWindow::switchLanguage(int language) { - boost::shared_ptr dev = _session.get_device(); + SigSession *_session = _control->GetSession(); + DevInst *dev = _session->get_device(); dev->set_config(NULL, NULL, SR_CONF_LANGUAGE, g_variant_new_int16(language)); AppConfig &app = AppConfig::Instance(); @@ -1408,7 +1434,9 @@ void MainWindow::switchTheme(QString style) qss.open(QFile::ReadOnly | QFile::Text); qApp->setStyleSheet(qss.readAll()); qss.close(); - _session.data_updated(); + + SigSession *_session = _control->GetSession(); + _session->data_updated(); } void MainWindow::on_open_doc(){ diff --git a/DSView/pv/mainwindow.h b/DSView/pv/mainwindow.h index 0571aeba..7dee5f3a 100755 --- a/DSView/pv/mainwindow.h +++ b/DSView/pv/mainwindow.h @@ -27,8 +27,8 @@ #include #include - -#include "sigsession.h" +#include + #include "dialogs/dsmessagebox.h" class QAction; @@ -40,9 +40,10 @@ class QToolBar; class QWidget; class QDockWidget; -namespace pv { +class AppControl; -class DeviceManager; +namespace pv { + namespace toolbars { class SamplingBar; @@ -63,6 +64,12 @@ namespace view { class View; } +namespace device{ + class DevInst; +} + +using namespace pv::device; + //The mainwindow,referenced by MainFrame //TODO: create graph view,toolbar,and show device list class MainWindow : public QMainWindow @@ -73,9 +80,7 @@ private: static constexpr int Session_Version = 2; public: - explicit MainWindow(DeviceManager &device_manager, - const char *open_file_name = NULL, - QWidget *parent = 0); + explicit MainWindow(QWidget *parent = 0); protected: void closeEvent(QCloseEvent *event); @@ -170,10 +175,8 @@ signals: void prgRate(int progress); private: - DeviceManager &_device_manager; - - SigSession _session; - bool _hot_detach; + AppControl *_control; + bool _hot_detach; pv::view::View *_view; dialogs::DSMessageBox *_msg; diff --git a/DSView/pv/sigsession.cpp b/DSView/pv/sigsession.cpp index 7ceed522..0774aca0 100755 --- a/DSView/pv/sigsession.cpp +++ b/DSView/pv/sigsession.cpp @@ -89,8 +89,7 @@ namespace pv { // TODO: This should not be necessary SigSession* SigSession::_session = NULL; -SigSession::SigSession(DeviceManager &device_manager) : - _device_manager(device_manager), +SigSession::SigSession(DeviceManager *device_manager) : _capture_state(Init), _instant(false), _error(No_err), @@ -100,12 +99,19 @@ SigSession::SigSession(DeviceManager &device_manager) : _repeat_hold_prg(0), _map_zoom(0) { - // TODO: This should not be necessary - _session = this; + void *p = this; + _appCntrol = NULL; + + _hotplug_handle = 0; + _dev_inst = NULL; + _device_manager = device_manager; + // TODO: This should not be necessary + _session = this; _hot_attach = false; _hot_detach = false; _group_cnt = 0; - register_hotplug_callback(); + + _feed_timer.stop(); _noData_cnt = 0; _data_lock = false; @@ -135,38 +141,39 @@ SigSession::SigSession(DeviceManager &device_manager) : connect(&_feed_timer, SIGNAL(timeout()), this, SLOT(feed_timeout())); } +//SigSession::SigSession(SigSession &o){(void)o;} + SigSession::~SigSession() { - stop_capture(); - - ds_trigger_destroy(); - - _dev_inst->release(); - - // TODO: This should not be necessary - _session = NULL; - - if (_hotplug_handle) { - stop_hotplug_proc(); - deregister_hotplug_callback(); - } + Close(); } -boost::shared_ptr SigSession::get_device() const +DevInst* SigSession::get_device() const { return _dev_inst; } +void SigSession::deselect_device() +{ + _decode_traces.clear(); + _group_traces.clear(); + _dev_inst = NULL; +} + /* when be called, it will call 4DSL lib sr_session_new, and create a session struct in the lib */ -void SigSession::set_device(boost::shared_ptr dev_inst) +void SigSession::set_device(DevInst *dev_inst) { - using pv::device::Device; - // Ensure we are not capturing before setting the device //stop_capture(); + assert(dev_inst); + + if (_dev_inst){ + _dev_inst->dev_inst(); + } + if (_dev_inst) { sr_session_datafeed_callback_remove_all(); _dev_inst->release(); @@ -202,29 +209,27 @@ void SigSession::set_file(QString name) { // Deslect the old device, because file type detection in File::create // destorys the old session inside libsigrok. + deselect_device(); + try { - set_device(boost::shared_ptr()); - } catch(const QString e) { - throw(e); - return; - } - try { - set_device(boost::shared_ptr(device::File::create(name))); + set_device(device::File::create(name)); } catch(const QString e) { throw(e); return; } } -void SigSession::close_file(boost::shared_ptr dev_inst) +void SigSession::close_file(DevInst *dev_inst) { assert(dev_inst); + assert(_device_manager); + try { dev_inst->device_updated(); set_repeating(false); stop_capture(); capture_state_changed(SigSession::Stopped); - _device_manager.del_device(dev_inst); + _device_manager->del_device(dev_inst); } catch(const QString e) { throw(e); return; @@ -233,22 +238,25 @@ void SigSession::close_file(boost::shared_ptr dev_inst) void SigSession::set_default_device(boost::function error_handler) { - boost::shared_ptr default_device; - const list > &devices = - _device_manager.devices(); + assert(_device_manager); + DevInst *default_device = NULL; + + const list &devices = _device_manager->devices(); if (!devices.empty()) { // Fall back to the first device in the list. default_device = devices.front(); // Try and find the DreamSourceLab device and select that by default - BOOST_FOREACH (boost::shared_ptr dev, devices) - if (dev->dev_inst() && - !dev->name().contains("virtual")) { + for (DevInst *dev : devices) + if (dev->dev_inst() && !dev->name().contains("virtual")) { default_device = dev; break; } - try { + } + + if (default_device != NULL){ + try { set_device(default_device); } catch(const QString e) { error_handler(e); @@ -257,20 +265,22 @@ void SigSession::set_default_device(boost::function error_ } } -void SigSession::release_device(device::DevInst *dev_inst) +void SigSession::release_device(DevInst *dev_inst) { - (void)dev_inst; - assert(_dev_inst.get() == dev_inst); + if (_dev_inst == NULL) + return; + assert(dev_inst); + assert(_dev_inst == dev_inst); assert(get_capture_state() != Running); - _dev_inst = boost::shared_ptr(); - //_dev_inst.reset(); + + _dev_inst = NULL; } SigSession::capture_state SigSession::get_capture_state() const { boost::lock_guard lock(_sampling_mutex); - return _capture_state; + return _capture_state; } uint64_t SigSession::cur_samplelimits() const @@ -447,7 +457,7 @@ void SigSession::start_capture(bool instant, } // stop previous capture - stop_capture(); + stop_capture(); // reset measure of dso signal BOOST_FOREACH(const boost::shared_ptr s, _signals) { @@ -464,24 +474,24 @@ void SigSession::start_capture(bool instant, _instant = true; capture_init(); - // Check that at least one probe is enabled - const GSList *l; + // Check that at least one probe is enabled + const GSList *l; for (l = _dev_inst->dev_inst()->channels; l; l = l->next) { sr_channel *const probe = (sr_channel*)l->data; - assert(probe); - if (probe->enabled) - break; - } - if (!l) { - error_handler(tr("No probes enabled.")); + assert(probe); + if (probe->enabled) + break; + } + if (!l) { + error_handler(tr("No probes enabled.")); data_updated(); set_repeating(false); capture_state_changed(SigSession::Stopped); - return; - } + return; + } - // Begin the session - _sampling_thread.reset(new boost::thread( + // Begin the session + _sampling_thread.reset(new boost::thread( &SigSession::sample_thread_proc, this, _dev_inst, error_handler)); } @@ -497,11 +507,11 @@ void SigSession::stop_capture() (*i)->decoder()->stop_decode(); if (get_capture_state() != Running) - return; + return; - sr_session_stop(); + sr_session_stop(); - // Check that sampling stopped + // Check that sampling stopped if (_sampling_thread.get()) _sampling_thread->join(); _sampling_thread.reset(); @@ -530,10 +540,10 @@ bool SigSession::get_capture_status(bool &triggered, int &progress) return false; } -vector< boost::shared_ptr > SigSession::get_signals() +vector< boost::shared_ptr >& SigSession::get_signals() { //boost::lock_guard lock(_signals_mutex); - return _signals; + return _signals; } vector< boost::shared_ptr > SigSession::get_group_signals() @@ -562,12 +572,12 @@ bool SigSession::get_instant() void SigSession::set_capture_state(capture_state state) { boost::lock_guard lock(_sampling_mutex); - _capture_state = state; + _capture_state = state; data_updated(); - capture_state_changed(state); + capture_state_changed(state); } -void SigSession::sample_thread_proc(boost::shared_ptr dev_inst, +void SigSession::sample_thread_proc(DevInst *dev_inst, boost::function error_handler) { assert(dev_inst); @@ -934,20 +944,20 @@ void SigSession::feed_in_header(const sr_dev_inst *sdi) void SigSession::feed_in_meta(const sr_dev_inst *sdi, const sr_datafeed_meta &meta) { - (void)sdi; + (void)sdi; - for (const GSList *l = meta.config; l; l = l->next) { + for (const GSList *l = meta.config; l; l = l->next) { const sr_config *const src = (const sr_config*)l->data; - switch (src->key) { - case SR_CONF_SAMPLERATE: - /// @todo handle samplerate changes - /// samplerate = (uint64_t *)src->value; - break; - default: - // Unknown metadata is not an error. - break; - } - } + switch (src->key) { + case SR_CONF_SAMPLERATE: + /// @todo handle samplerate changes + /// samplerate = (uint64_t *)src->value; + break; + default: + // Unknown metadata is not an error. + break; + } + } } void SigSession::feed_in_trigger(const ds_trigger_pos &trigger_pos) @@ -980,9 +990,9 @@ void SigSession::feed_in_logic(const sr_datafeed_logic &logic) { //boost::lock_guard lock(_data_mutex); if (!_logic_data || _cur_logic_snapshot->memory_failed()) { - qDebug() << "Unexpected logic packet"; - return; - } + qDebug() << "Unexpected logic packet"; + return; + } if (logic.data_error == 1) { _error = Test_data_err; @@ -998,7 +1008,7 @@ void SigSession::feed_in_logic(const sr_datafeed_logic &logic) // this after both analog and logic sweeps have begun. frame_began(); } else { - // Append to the existing data snapshot + // Append to the existing data snapshot _cur_logic_snapshot->append_payload(logic); } @@ -1098,13 +1108,13 @@ void SigSession::feed_in_analog(const sr_datafeed_analog &analog) //boost::lock_guard lock(_data_mutex); if(!_analog_data || _cur_analog_snapshot->memory_failed()) - { - qDebug() << "Unexpected analog packet"; - return; // This analog packet was not expected. - } + { + qDebug() << "Unexpected analog packet"; + return; // This analog packet was not expected. + } if (_cur_analog_snapshot->last_ended()) - { + { // reset scale of analog signal BOOST_FOREACH(const boost::shared_ptr s, _signals) { @@ -1118,8 +1128,8 @@ void SigSession::feed_in_analog(const sr_datafeed_analog &analog) // first payload _cur_analog_snapshot->first_payload(analog, _dev_inst->get_sample_limit(), _dev_inst->dev_inst()->channels); } else { - // Append to the existing data snapshot - _cur_analog_snapshot->append_payload(analog); + // Append to the existing data snapshot + _cur_analog_snapshot->append_payload(analog); } if (_cur_analog_snapshot->memory_failed()) { @@ -1136,14 +1146,14 @@ void SigSession::feed_in_analog(const sr_datafeed_analog &analog) void SigSession::data_feed_in(const struct sr_dev_inst *sdi, const struct sr_datafeed_packet *packet) { - assert(sdi); - assert(packet); + assert(sdi); + assert(packet); boost::lock_guard lock(_data_mutex); if (_data_lock && packet->type != SR_DF_END) return; - + if (packet->type != SR_DF_END && packet->status != SR_PKT_OK) { _error = Pkt_data_err; @@ -1151,36 +1161,36 @@ void SigSession::data_feed_in(const struct sr_dev_inst *sdi, return; } - switch (packet->type) { - case SR_DF_HEADER: - feed_in_header(sdi); - break; + switch (packet->type) { + case SR_DF_HEADER: + feed_in_header(sdi); + break; - case SR_DF_META: - assert(packet->payload); - feed_in_meta(sdi, + case SR_DF_META: + assert(packet->payload); + feed_in_meta(sdi, *(const sr_datafeed_meta*)packet->payload); - break; + break; case SR_DF_TRIGGER: assert(packet->payload); feed_in_trigger(*(const ds_trigger_pos*)packet->payload); break; - case SR_DF_LOGIC: - assert(packet->payload); + case SR_DF_LOGIC: + assert(packet->payload); feed_in_logic(*(const sr_datafeed_logic*)packet->payload); - break; + break; case SR_DF_DSO: assert(packet->payload); feed_in_dso(*(const sr_datafeed_dso*)packet->payload); break; - case SR_DF_ANALOG: - assert(packet->payload); + case SR_DF_ANALOG: + assert(packet->payload); feed_in_analog(*(const sr_datafeed_analog*)packet->payload); - break; + break; case SR_DF_OVERFLOW: { @@ -1190,9 +1200,9 @@ void SigSession::data_feed_in(const struct sr_dev_inst *sdi, } break; } - case SR_DF_END: - { - { + case SR_DF_END: + { + { //boost::lock_guard lock(_data_mutex); if (!_cur_logic_snapshot->empty()) { BOOST_FOREACH(const boost::shared_ptr g, _group_traces) @@ -1212,7 +1222,7 @@ void SigSession::data_feed_in(const struct sr_dev_inst *sdi, BOOST_FOREACH(const boost::shared_ptr d, _decode_traces) d->frame_ended(); - } + } if (packet->status != SR_PKT_OK) { _error = Pkt_data_err; @@ -1221,23 +1231,23 @@ void SigSession::data_feed_in(const struct sr_dev_inst *sdi, frame_ended(); if (get_device()->dev_inst()->mode != LOGIC) set_session_time(QDateTime::currentDateTime()); - break; - } - } + break; + } + } } void SigSession::data_feed_in_proc(const struct sr_dev_inst *sdi, const struct sr_datafeed_packet *packet, void *cb_data) { - (void) cb_data; - assert(_session); - _session->data_feed_in(sdi, packet); + (void) cb_data; + assert(_session); + _session->data_feed_in(sdi, packet); } /* * hotplug function */ -int SigSession::hotplug_callback(struct libusb_context *ctx, struct libusb_device *dev, +int SigSession::hotplug_callback(struct libusb_context *ctx, struct libusb_device *dev, libusb_hotplug_event event, void *user_data) { (void)ctx; @@ -1293,12 +1303,12 @@ void SigSession::register_hotplug_callback() int ret; ret = libusb_hotplug_register_callback(NULL, (libusb_hotplug_event)(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | - LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT), + LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT), (libusb_hotplug_flag)LIBUSB_HOTPLUG_ENUMERATE, 0x2A0E, LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY, hotplug_callback, NULL, &_hotplug_handle); if (LIBUSB_SUCCESS != ret){ - qDebug() << "Error creating a hotplug callback\n"; + qDebug() << "Error creating a hotplug callback\n"; } } @@ -1369,7 +1379,7 @@ uint16_t SigSession::get_ch_num(int type) bool SigSession::add_decoder(srd_decoder *const dec, bool silent, DecoderStatus *dstatus) -{ +{ bool ret = false; map probes; boost::shared_ptr decoder_stack; @@ -1379,7 +1389,7 @@ bool SigSession::add_decoder(srd_decoder *const dec, bool silent, DecoderStatus // Create the decoder decoder_stack = boost::shared_ptr( - new data::DecoderStack(*this, dec, dstatus)); + new data::DecoderStack(this, dec, dstatus)); // Make a list of all the probes std::vector all_probes; @@ -1395,7 +1405,7 @@ bool SigSession::add_decoder(srd_decoder *const dec, bool silent, DecoderStatus // Create the decode signal boost::shared_ptr d( - new view::DecodeTrace(*this, decoder_stack, + new view::DecodeTrace(this, decoder_stack, _decode_traces.size())); // set view early for decode start/end region setting BOOST_FOREACH(const boost::shared_ptr s, _signals) { @@ -1524,9 +1534,9 @@ void SigSession::spectrum_rebuild() // if not, rebuild if (iter == _spectrum_traces.end()) { boost::shared_ptr spectrum_stack( - new data::SpectrumStack(*this, dsoSig->get_index())); + new data::SpectrumStack(this, dsoSig->get_index())); boost::shared_ptr spectrum_trace( - new view::SpectrumTrace(*this, spectrum_stack, dsoSig->get_index())); + new view::SpectrumTrace(this, spectrum_stack, dsoSig->get_index())); _spectrum_traces.push_back(spectrum_trace); } } @@ -1569,7 +1579,7 @@ void SigSession::math_rebuild(bool enable, { boost::lock_guard lock(_data_mutex); boost::shared_ptr math_stack( - new data::MathStack(*this, dsoSig1, dsoSig2, type)); + new data::MathStack(this, dsoSig1, dsoSig2, type)); _math_trace.reset(new view::MathTrace(enable, math_stack, dsoSig1, dsoSig2)); if (_math_trace && _math_trace->enabled()) { _math_trace->get_math_stack()->set_samplerate(_dev_inst->get_sample_rate()); @@ -1815,4 +1825,44 @@ void SigSession::set_stop_scale(float scale) _stop_scale = scale; } + sr_dev_inst* SigSession::get_dev_inst_c() + { + void *p = this; + void *p2 = this->_appCntrol; + if (_dev_inst != NULL){ + return _dev_inst->dev_inst(); + } + return NULL; + } + + void SigSession::Open() + { + register_hotplug_callback(); + } + + void SigSession::Close() + { + if (_session == NULL) + return; + + stop_capture(); + + ds_trigger_destroy(); + + if (_dev_inst) + { + _dev_inst->release(); + } + + // TODO: This should not be necessary + _session = NULL; + + if (_hotplug_handle) + { + stop_hotplug_proc(); + deregister_hotplug_callback(); + _hotplug_handle = NULL; + } + } + } // namespace pv diff --git a/DSView/pv/sigsession.h b/DSView/pv/sigsession.h index 6d66c0b5..3e2b8fb3 100755 --- a/DSView/pv/sigsession.h +++ b/DSView/pv/sigsession.h @@ -94,6 +94,8 @@ class Decoder; class DecoderFactory; } +using namespace pv::device; + //created by MainWindow class SigSession : public QObject { @@ -130,25 +132,30 @@ public: Data_overflow }; +private: + // SigSession(SigSession &o); + public: - SigSession(DeviceManager &device_manager); + explicit SigSession(DeviceManager *device_manager); - ~SigSession(); + ~SigSession(); - boost::shared_ptr get_device() const; + DevInst* get_device() const; /** * Sets device instance that will be used in the next capture session. */ - void set_device(boost::shared_ptr dev_inst); + void set_device(DevInst *dev_inst); + + void deselect_device(); void set_file(QString name); - void close_file(boost::shared_ptr dev_inst); + void close_file(DevInst *dev_inst); void set_default_device(boost::function error_handler); - void release_device(device::DevInst *dev_inst); + void release_device(DevInst *dev_inst); capture_state get_capture_state() const; @@ -173,7 +180,7 @@ public: std::set< boost::shared_ptr > get_data() const; - std::vector< boost::shared_ptr > + std::vector< boost::shared_ptr >& get_signals(); std::vector< boost::shared_ptr > @@ -213,8 +220,7 @@ public: void start_hotplug_proc(boost::function error_handler); void stop_hotplug_proc(); - void register_hotplug_callback(); - void deregister_hotplug_callback(); + uint16_t get_ch_num(int type); @@ -264,9 +270,18 @@ public: void exit_capture(); + sr_dev_inst* get_dev_inst_c(); + + void Open(); + + void Close(); + private: void set_capture_state(capture_state state); + void register_hotplug_callback(); + void deregister_hotplug_callback(); + private: /** * Attempts to autodetect the format. Failing that @@ -283,7 +298,7 @@ private: boost::function error_handler, sr_input_format *format = NULL); - void sample_thread_proc(boost::shared_ptr dev_inst, + void sample_thread_proc(DevInst *dev_inst, boost::function error_handler); // data feed @@ -306,77 +321,7 @@ private: static int hotplug_callback(struct libusb_context *ctx, struct libusb_device *dev, libusb_hotplug_event event, void *user_data); -private: - DeviceManager &_device_manager; - /** - * The device instance that will be used in the next capture session. - */ - boost::shared_ptr _dev_inst; - - mutable boost::mutex _sampling_mutex; - capture_state _capture_state; - bool _instant; - uint64_t _cur_snap_samplerate; - uint64_t _cur_samplelimits; - - //mutable boost::mutex _signals_mutex; - std::vector< boost::shared_ptr > _signals; - std::vector< boost::shared_ptr > _group_traces; - - std::vector< boost::shared_ptr > _decode_traces; - pv::data::DecoderModel *_decoder_model; - - std::vector< boost::shared_ptr > _spectrum_traces; - boost::shared_ptr _lissajous_trace; - boost::shared_ptr _math_trace; - - mutable boost::mutex _data_mutex; - boost::shared_ptr _logic_data; - boost::shared_ptr _cur_logic_snapshot; - boost::shared_ptr _dso_data; - boost::shared_ptr _cur_dso_snapshot; - boost::shared_ptr _analog_data; - boost::shared_ptr _cur_analog_snapshot; - boost::shared_ptr _group_data; - boost::shared_ptr _cur_group_snapshot; - int _group_cnt; - - std::unique_ptr _sampling_thread; - - libusb_hotplug_callback_handle _hotplug_handle; - std::unique_ptr _hotplug; - bool _hot_attach; - bool _hot_detach; - - QTimer _feed_timer; - int _noData_cnt; - bool _data_lock; - bool _data_updated; - int _data_auto_lock; - - QDateTime _session_time; - uint64_t _trigger_pos; - bool _trigger_flag; - uint8_t _trigger_ch; - bool _hw_replied; - - error_state _error; - uint64_t _error_pattern; - - run_mode _run_mode; - int _repeat_intvl; - bool _repeating; - int _repeat_hold_prg; - - int _map_zoom; - - uint64_t _save_start; - uint64_t _save_end; - bool _saving; - - bool _dso_feed; - float _stop_scale; signals: void capture_state_changed(int state); @@ -442,6 +387,81 @@ private slots: void feed_timeout(); void repeat_update(); +public: + void *_appCntrol; + +private: + DeviceManager *_device_manager; + + /** + * The device instance that will be used in the next capture session. + */ + DevInst *_dev_inst; + + mutable boost::mutex _sampling_mutex; + capture_state _capture_state; + bool _instant; + uint64_t _cur_snap_samplerate; + uint64_t _cur_samplelimits; + + //mutable boost::mutex _signals_mutex; + std::vector< boost::shared_ptr > _signals; + std::vector< boost::shared_ptr > _group_traces; + + std::vector< boost::shared_ptr > _decode_traces; + pv::data::DecoderModel *_decoder_model; + + std::vector< boost::shared_ptr > _spectrum_traces; + boost::shared_ptr _lissajous_trace; + boost::shared_ptr _math_trace; + + mutable boost::mutex _data_mutex; + boost::shared_ptr _logic_data; + boost::shared_ptr _cur_logic_snapshot; + boost::shared_ptr _dso_data; + boost::shared_ptr _cur_dso_snapshot; + boost::shared_ptr _analog_data; + boost::shared_ptr _cur_analog_snapshot; + boost::shared_ptr _group_data; + boost::shared_ptr _cur_group_snapshot; + int _group_cnt; + + std::unique_ptr _sampling_thread; + + libusb_hotplug_callback_handle _hotplug_handle; + std::unique_ptr _hotplug; + bool _hot_attach; + bool _hot_detach; + + QTimer _feed_timer; + int _noData_cnt; + bool _data_lock; + bool _data_updated; + int _data_auto_lock; + + QDateTime _session_time; + uint64_t _trigger_pos; + bool _trigger_flag; + uint8_t _trigger_ch; + bool _hw_replied; + + error_state _error; + uint64_t _error_pattern; + + run_mode _run_mode; + int _repeat_intvl; + bool _repeating; + int _repeat_hold_prg; + + int _map_zoom; + + uint64_t _save_start; + uint64_t _save_end; + bool _saving; + + bool _dso_feed; + float _stop_scale; + private: // TODO: This should not be necessary. Multiple concurrent // sessions should should be supported and it should be diff --git a/DSView/pv/storesession.cpp b/DSView/pv/storesession.cpp index 88fe59bc..aed18575 100755 --- a/DSView/pv/storesession.cpp +++ b/DSView/pv/storesession.cpp @@ -75,7 +75,7 @@ namespace pv { } } -StoreSession::StoreSession(SigSession &session) : +StoreSession::StoreSession(SigSession *session) : _session(session), _outModule(NULL), _units_stored(0), @@ -90,7 +90,7 @@ StoreSession::~StoreSession() wait(); } -SigSession& StoreSession::session() +SigSession* StoreSession::session() { return _session; } @@ -125,7 +125,7 @@ QList StoreSession::getSuportedExportFormats(){ while(*supportedModules){ if(*supportedModules == NULL) break; - if (_session.get_device()->dev_inst()->mode != LOGIC && + if (_session->get_device()->dev_inst()->mode != LOGIC && strcmp((*supportedModules)->id, "csv")) break; QString format((*supportedModules)->desc); @@ -147,7 +147,7 @@ bool StoreSession::save_start() } std::set type_set; - BOOST_FOREACH(const boost::shared_ptr sig, _session.get_signals()) { + BOOST_FOREACH(const boost::shared_ptr sig, _session->get_signals()) { assert(sig); type_set.insert(sig->get_type()); } @@ -167,7 +167,7 @@ bool StoreSession::save_start() return false; } - const boost::shared_ptr snapshot(_session.get_snapshot(*type_set.begin())); + const boost::shared_ptr snapshot(_session->get_snapshot(*type_set.begin())); assert(snapshot); // Check we have data if (snapshot->empty()) { @@ -230,7 +230,7 @@ void StoreSession::save_proc(boost::shared_ptr snapshot) if ((logic_snapshot = boost::dynamic_pointer_cast(snapshot))) { uint16_t to_save_probes = 0; - BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { if (s->enabled() && logic_snapshot->has_data(s->get_index())) to_save_probes++; } @@ -238,7 +238,7 @@ void StoreSession::save_proc(boost::shared_ptr snapshot) num = logic_snapshot->get_block_num(); bool sample; - BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { int ch_type = s->get_type(); if (ch_type == SR_CHANNEL_LOGIC) { int ch_index = s->get_index(); @@ -283,7 +283,7 @@ void StoreSession::save_proc(boost::shared_ptr snapshot) } } else { int ch_type = -1; - BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { ch_type = s->get_type(); break; } @@ -383,7 +383,7 @@ QString StoreSession::meta_gen(boost::shared_ptr snapshot) return NULL; } - const sr_dev_inst *sdi = _session.get_device()->dev_inst(); + const sr_dev_inst *sdi = _session->get_device()->dev_inst(); meta = fopen(metafile.toUtf8().data(), "wb"); if (meta == NULL) { qDebug() << "Failed to create temp meta file."; @@ -421,68 +421,68 @@ QString StoreSession::meta_gen(boost::shared_ptr snapshot) fprintf(meta, "total blocks = %d\n", logic_snapshot->get_block_num()); } - s = sr_samplerate_string(_session.cur_snap_samplerate()); + s = sr_samplerate_string(_session->cur_snap_samplerate()); fprintf(meta, "samplerate = %s\n", s); if (sdi->mode == DSO) { - gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_TIMEBASE); + gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_TIMEBASE); if (gvar != NULL) { uint64_t tmp_u64 = g_variant_get_uint64(gvar); fprintf(meta, "hDiv = %" PRIu64 "\n", tmp_u64); g_variant_unref(gvar); } - gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_MAX_TIMEBASE); + gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_MAX_TIMEBASE); if (gvar != NULL) { uint64_t tmp_u64 = g_variant_get_uint64(gvar); fprintf(meta, "hDiv max = %" PRIu64 "\n", tmp_u64); g_variant_unref(gvar); } - gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_MIN_TIMEBASE); + gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_MIN_TIMEBASE); if (gvar != NULL) { uint64_t tmp_u64 = g_variant_get_uint64(gvar); fprintf(meta, "hDiv min = %" PRIu64 "\n", tmp_u64); g_variant_unref(gvar); } - gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_UNIT_BITS); + gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_UNIT_BITS); if (gvar != NULL) { uint8_t tmp_u8 = g_variant_get_byte(gvar); fprintf(meta, "bits = %d\n", tmp_u8); g_variant_unref(gvar); } - gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_REF_MIN); + gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_REF_MIN); if (gvar != NULL) { uint32_t tmp_u32 = g_variant_get_uint32(gvar); fprintf(meta, "ref min = %d\n", tmp_u32); g_variant_unref(gvar); } - gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_REF_MAX); + gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_REF_MAX); if (gvar != NULL) { uint32_t tmp_u32 = g_variant_get_uint32(gvar); fprintf(meta, "ref max = %d\n", tmp_u32); g_variant_unref(gvar); } } else if (sdi->mode == LOGIC) { - fprintf(meta, "trigger time = %lld\n", _session.get_session_time().toMSecsSinceEpoch()); + fprintf(meta, "trigger time = %lld\n", _session->get_session_time().toMSecsSinceEpoch()); } else if (sdi->mode == ANALOG) { boost::shared_ptr analog_snapshot; if ((analog_snapshot = dynamic_pointer_cast(snapshot))) { uint8_t tmp_u8 = analog_snapshot->get_unit_bytes(); fprintf(meta, "bits = %d\n", tmp_u8*8); } - gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_REF_MIN); + gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_REF_MIN); if (gvar != NULL) { uint32_t tmp_u32 = g_variant_get_uint32(gvar); fprintf(meta, "ref min = %d\n", tmp_u32); g_variant_unref(gvar); } - gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_REF_MAX); + gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_REF_MAX); if (gvar != NULL) { uint32_t tmp_u32 = g_variant_get_uint32(gvar); fprintf(meta, "ref max = %d\n", tmp_u32); g_variant_unref(gvar); } } - fprintf(meta, "trigger pos = %" PRIu64 "\n", _session.get_trigger_pos()); + fprintf(meta, "trigger pos = %" PRIu64 "\n", _session->get_trigger_pos()); probecnt = 0; for (l = sdi->channels; l; l = l->next) { @@ -557,7 +557,7 @@ QString StoreSession::meta_gen(boost::shared_ptr snapshot) bool StoreSession::export_start() { std::set type_set; - BOOST_FOREACH(const boost::shared_ptr sig, _session.get_signals()) { + BOOST_FOREACH(const boost::shared_ptr sig, _session->get_signals()) { assert(sig); int _tp = sig->get_type(); type_set.insert(_tp); @@ -572,7 +572,7 @@ bool StoreSession::export_start() return false; } - const boost::shared_ptr snapshot(_session.get_snapshot(*type_set.begin())); + const boost::shared_ptr snapshot(_session->get_snapshot(*type_set.begin())); assert(snapshot); // Check we have data if (snapshot->empty()) { @@ -646,7 +646,7 @@ void StoreSession::export_proc(boost::shared_ptr snapshot) struct sr_output output; output.module = (sr_output_module*) _outModule; - output.sdi = _session.get_device()->dev_inst(); + output.sdi = _session->get_device()->dev_inst(); output.param = NULL; if(_outModule->init) _outModule->init(&output, params); @@ -664,7 +664,7 @@ void StoreSession::export_proc(boost::shared_ptr snapshot) struct sr_config *src; src = sr_config_new(SR_CONF_SAMPLERATE, - g_variant_new_uint64(_session.cur_snap_samplerate())); + g_variant_new_uint64(_session->cur_snap_samplerate())); meta.config = g_slist_append(NULL, src); src = sr_config_new(SR_CONF_LIMIT_SAMPLES, @@ -673,12 +673,12 @@ void StoreSession::export_proc(boost::shared_ptr snapshot) GVariant *gvar; uint8_t bits; - gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_UNIT_BITS); + gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_UNIT_BITS); if (gvar != NULL) { bits = g_variant_get_byte(gvar); g_variant_unref(gvar); } - gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_REF_MIN); + gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_REF_MIN); if (gvar != NULL) { src = sr_config_new(SR_CONF_REF_MIN, gvar); g_variant_unref(gvar); @@ -686,7 +686,7 @@ void StoreSession::export_proc(boost::shared_ptr snapshot) src = sr_config_new(SR_CONF_REF_MIN, g_variant_new_uint32(1)); } meta.config = g_slist_append(meta.config, src); - gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_REF_MAX); + gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_REF_MAX); if (gvar != NULL) { src = sr_config_new(SR_CONF_REF_MAX, gvar); g_variant_unref(gvar); @@ -721,7 +721,7 @@ void StoreSession::export_proc(boost::shared_ptr snapshot) uint64_t buf_sample_num = logic_snapshot->get_block_size(blk) * 8; buf_vec.clear(); buf_sample.clear(); - BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { int ch_type = s->get_type(); if (ch_type == SR_CHANNEL_LOGIC) { int ch_index = s->get_index(); @@ -879,7 +879,7 @@ QString StoreSession::decoders_gen() QJsonArray StoreSession::json_decoders() { QJsonArray dec_array; - BOOST_FOREACH(boost::shared_ptr t, _session.get_decode_signals()) { + BOOST_FOREACH(boost::shared_ptr t, _session->get_decode_signals()) { QJsonObject dec_obj; QJsonArray stack_array; QJsonObject show_obj; @@ -959,18 +959,18 @@ QJsonArray StoreSession::json_decoders() void StoreSession::load_decoders(dock::ProtocolDock *widget, QJsonArray dec_array) { - if (_session.get_device()->dev_inst()->mode != LOGIC || + if (_session->get_device()->dev_inst()->mode != LOGIC || dec_array.empty()) return; foreach (const QJsonValue &dec_value, dec_array) { QJsonObject dec_obj = dec_value.toObject(); const vector< boost::shared_ptr > pre_dsigs( - _session.get_decode_signals()); + _session->get_decode_signals()); if (widget->sel_protocol(dec_obj["id"].toString())) widget->add_protocol(true); const vector< boost::shared_ptr > aft_dsigs( - _session.get_decode_signals()); + _session->get_decode_signals()); if (aft_dsigs.size() > pre_dsigs.size()) { const GSList *l; @@ -1130,24 +1130,24 @@ QString StoreSession::MakeSaveFile(bool bDlg) AppConfig &app = AppConfig::Instance(); if (app._userHistory.saveDir != "") { - default_name = app._userHistory.saveDir + "/" + _session.get_device()->name() + "-"; + default_name = app._userHistory.saveDir + "/" + _session->get_device()->name() + "-"; } else{ QDir _dir; QString _root = _dir.home().path(); - default_name = _root + "/" + _session.get_device()->name() + "-"; + default_name = _root + "/" + _session->get_device()->name() + "-"; } - for (const GSList *l = _session.get_device()->get_dev_mode_list(); + for (const GSList *l = _session->get_device()->get_dev_mode_list(); l; l = l->next) { const sr_dev_mode *mode = (const sr_dev_mode *)l->data; - if (_session.get_device()->dev_inst()->mode == mode->mode) { + if (_session->get_device()->dev_inst()->mode == mode->mode) { default_name += mode->acronym; break; } } - default_name += _session.get_session_time().toString("-yyMMdd-hhmmss"); + default_name += _session->get_session_time().toString("-yyMMdd-hhmmss"); // Show the dialog if (bDlg) @@ -1188,23 +1188,23 @@ QString StoreSession::MakeExportFile(bool bDlg) if (app._userHistory.exportDir != "") { - default_name = app._userHistory.exportDir + "/" + _session.get_device()->name() + "-"; + default_name = app._userHistory.exportDir + "/" + _session->get_device()->name() + "-"; } else{ QDir _dir; QString _root = _dir.home().path(); - default_name = _root + "/" + _session.get_device()->name() + "-"; + default_name = _root + "/" + _session->get_device()->name() + "-"; } - for (const GSList *l = _session.get_device()->get_dev_mode_list(); + for (const GSList *l = _session->get_device()->get_dev_mode_list(); l; l = l->next) { const sr_dev_mode *mode = (const sr_dev_mode *)l->data; - if (_session.get_device()->dev_inst()->mode == mode->mode) { + if (_session->get_device()->dev_inst()->mode == mode->mode) { default_name += mode->acronym; break; } } - default_name += _session.get_session_time().toString("-yyMMdd-hhmmss"); + default_name += _session->get_session_time().toString("-yyMMdd-hhmmss"); //ext name QList supportedFormats = getSuportedExportFormats(); @@ -1271,7 +1271,7 @@ QString StoreSession::MakeExportFile(bool bDlg) bool StoreSession::IsLogicDataType() { std::set type_set; - BOOST_FOREACH(const boost::shared_ptr sig, _session.get_signals()) { + BOOST_FOREACH(const boost::shared_ptr sig, _session->get_signals()) { assert(sig); type_set.insert(sig->get_type()); } diff --git a/DSView/pv/storesession.h b/DSView/pv/storesession.h index d7c201ca..45bd1e9a 100755 --- a/DSView/pv/storesession.h +++ b/DSView/pv/storesession.h @@ -53,11 +53,11 @@ private: const static int File_Version = 2; public: - StoreSession(SigSession &session); + StoreSession(SigSession *session); ~StoreSession(); - SigSession& session(); + SigSession* session(); std::pair progress() const; @@ -104,7 +104,7 @@ public: private: QString _file_name; QString _suffix; - SigSession &_session; + SigSession *_session; boost::thread _thread; diff --git a/DSView/pv/toolbars/filebar.cpp b/DSView/pv/toolbars/filebar.cpp index 4a3b8663..8db6d486 100755 --- a/DSView/pv/toolbars/filebar.cpp +++ b/DSView/pv/toolbars/filebar.cpp @@ -36,7 +36,7 @@ namespace pv { namespace toolbars { -FileBar::FileBar(SigSession &session, QWidget *parent) : +FileBar::FileBar(SigSession *session, QWidget *parent) : QToolBar("File Bar", parent), _enable(true), _session(session), @@ -205,10 +205,10 @@ void FileBar::on_actionDefault_triggered() return; } - QString driver_name = _session.get_device()->name(); - QString mode_name = QString::number(_session.get_device()->dev_inst()->mode); + QString driver_name = _session->get_device()->name(); + QString mode_name = QString::number(_session->get_device()->dev_inst()->mode); int language = QLocale::English; - GVariant *gvar_tmp = _session.get_device()->get_config(NULL, NULL, SR_CONF_LANGUAGE); + GVariant *gvar_tmp = _session->get_device()->get_config(NULL, NULL, SR_CONF_LANGUAGE); if (gvar_tmp != NULL) { language = g_variant_get_int16(gvar_tmp); g_variant_unref(gvar_tmp); diff --git a/DSView/pv/toolbars/filebar.h b/DSView/pv/toolbars/filebar.h index 261d5c31..32cbbe81 100755 --- a/DSView/pv/toolbars/filebar.h +++ b/DSView/pv/toolbars/filebar.h @@ -40,7 +40,7 @@ class FileBar : public QToolBar Q_OBJECT public: - explicit FileBar(SigSession &session, QWidget *parent = 0); + explicit FileBar(SigSession *session, QWidget *parent = 0); void enable_toggle(bool enable); @@ -73,7 +73,7 @@ private slots: private: bool _enable; - SigSession& _session; + SigSession* _session; QToolButton _file_button; diff --git a/DSView/pv/toolbars/logobar.cpp b/DSView/pv/toolbars/logobar.cpp index 85296798..6791226a 100755 --- a/DSView/pv/toolbars/logobar.cpp +++ b/DSView/pv/toolbars/logobar.cpp @@ -35,7 +35,7 @@ namespace pv { namespace toolbars { -LogoBar::LogoBar(SigSession &session, QWidget *parent) : +LogoBar::LogoBar(SigSession *session, QWidget *parent) : QToolBar("File Bar", parent), _enable(true), _connected(false), diff --git a/DSView/pv/toolbars/logobar.h b/DSView/pv/toolbars/logobar.h index 278def32..19cf5d3c 100755 --- a/DSView/pv/toolbars/logobar.h +++ b/DSView/pv/toolbars/logobar.h @@ -42,7 +42,7 @@ class LogoBar : public QToolBar Q_OBJECT public: - explicit LogoBar(SigSession &session, QWidget *parent = 0); + explicit LogoBar(SigSession *session, QWidget *parent = 0); void enable_toggle(bool enable); @@ -76,7 +76,7 @@ private slots: private: bool _enable; bool _connected; - SigSession& _session; + SigSession* _session; QToolButton _logo_button; diff --git a/DSView/pv/toolbars/samplingbar.cpp b/DSView/pv/toolbars/samplingbar.cpp index 46302c9c..2ecd10b0 100755 --- a/DSView/pv/toolbars/samplingbar.cpp +++ b/DSView/pv/toolbars/samplingbar.cpp @@ -46,13 +46,15 @@ using std::max; using std::min; using std::string; +using namespace pv::device; + namespace pv { namespace toolbars { const QString SamplingBar::RLEString = tr("(RLE)"); const QString SamplingBar::DIVString = tr(" / div"); -SamplingBar::SamplingBar(SigSession &session, QWidget *parent) : +SamplingBar::SamplingBar(SigSession *session, QWidget *parent) : QToolBar("Sampling Bar", parent), _session(session), _enable(true), @@ -140,7 +142,7 @@ void SamplingBar::changeEvent(QEvent *event) void SamplingBar::retranslateUi() { - boost::shared_ptr dev_inst = get_selected_device(); + DevInst *dev_inst = get_selected_device(); if (dev_inst && dev_inst->dev_inst()) { if (dev_inst->name().contains("virtual-demo")) _device_type.setText(tr("Demo")); @@ -163,17 +165,18 @@ void SamplingBar::retranslateUi() } _configure_button.setText(tr("Options")); _mode_button.setText(tr("Mode")); + + sr_dev_inst *dev_c = _session->get_dev_inst_c(); + if (_instant) { - if (_session.get_device() && - _session.get_device()->dev_inst()->mode == DSO) + if (dev_c && dev_c->mode == DSO) _instant_button.setText(_sampling ? tr("Stop") : tr("Single")); else _instant_button.setText(_sampling ? tr("Stop") : tr("Instant")); _run_stop_button.setText(tr("Start")); } else { _run_stop_button.setText(_sampling ? tr("Stop") : tr("Start")); - if (_session.get_device() && - _session.get_device()->dev_inst()->mode == DSO) + if (dev_c && dev_c->mode == DSO) _instant_button.setText(tr("Single")); else _instant_button.setText(tr("Instant")); @@ -185,7 +188,7 @@ void SamplingBar::retranslateUi() void SamplingBar::reStyle() { - boost::shared_ptr dev_inst = get_selected_device(); + DevInst *dev_inst = get_selected_device(); if (dev_inst && dev_inst->dev_inst()) { if (dev_inst->name().contains("virtual-demo")) _device_type.setIcon(QIcon(":/icons/demo.svg")); @@ -209,7 +212,7 @@ void SamplingBar::reStyle() if (true) { QString iconPath = GetIconPath(); _configure_button.setIcon(QIcon(iconPath+"/params.svg")); - _mode_button.setIcon(_session.get_run_mode() == pv::SigSession::Single ? QIcon(iconPath+"/modes.svg") : + _mode_button.setIcon(_session->get_run_mode() == pv::SigSession::Single ? QIcon(iconPath+"/modes.svg") : QIcon(iconPath+"/moder.svg")); _run_stop_button.setIcon(_sampling ? QIcon(iconPath+"/stop.svg") : QIcon(iconPath+"/start.svg")); @@ -219,9 +222,7 @@ void SamplingBar::reStyle() } } -void SamplingBar::set_device_list( - const std::list > &devices, - boost::shared_ptr selected) +void SamplingBar::set_device_list(const std::list &devices, DevInst *selected) { int selected_index = -1; @@ -232,7 +233,7 @@ void SamplingBar::set_device_list( _device_selector.clear(); _device_selector_map.clear(); - BOOST_FOREACH (boost::shared_ptr dev_inst, devices) { + for (DevInst *dev_inst : devices) { assert(dev_inst); const QString title = dev_inst->format_device_title(); const void *id = dev_inst->get_id(); @@ -258,22 +259,21 @@ void SamplingBar::set_device_list( _updating_device_selector = false; } -boost::shared_ptr SamplingBar::get_selected_device() const +DevInst* SamplingBar::get_selected_device() const { const int index = _device_selector.currentIndex(); if (index < 0) - return boost::shared_ptr(); + return NULL; const void *const id = _device_selector.itemData(index).value(); assert(id); - map >:: - const_iterator iter = _device_selector_map.find(id); - if (iter == _device_selector_map.end()) - return boost::shared_ptr(); + auto it = _device_selector_map.find(id); + if (it == _device_selector_map.end()) + return NULL; - return boost::shared_ptr((*iter).second); + return (*it).second; } void SamplingBar::on_configure() @@ -281,7 +281,7 @@ void SamplingBar::on_configure() sig_hide_calibration(); int ret; - boost::shared_ptr dev_inst = get_selected_device(); + DevInst *dev_inst = get_selected_device(); assert(dev_inst); pv::dialogs::DeviceOptions dlg(this, dev_inst); @@ -332,7 +332,7 @@ void SamplingBar::on_configure() void SamplingBar::zero_adj() { boost::shared_ptr dsoSig; - BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) + BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { if ((dsoSig = dynamic_pointer_cast(s))) dsoSig->set_enable(true); @@ -349,14 +349,14 @@ void SamplingBar::zero_adj() pv::dialogs::WaitingDialog wait(this, _session, SR_CONF_ZERO); if (wait.start() == QDialog::Rejected) { - BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) + BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { if ((dsoSig = dynamic_pointer_cast(s))) dsoSig->commit_settings(); } } - if (_session.get_capture_state() == pv::SigSession::Running) + if (_session->get_capture_state() == pv::SigSession::Running) on_run_stop(); _sample_count.setCurrentIndex(index_back); @@ -399,7 +399,7 @@ void SamplingBar::set_sampling(bool sampling) } else { _run_stop_button.setIcon(sampling ? QIcon(iconPath+"/stop.svg") : QIcon(iconPath+"/start.svg")); } - _mode_button.setIcon(_session.get_run_mode() == pv::SigSession::Single ? QIcon(iconPath+"/modes.svg") : + _mode_button.setIcon(_session->get_run_mode() == pv::SigSession::Single ? QIcon(iconPath+"/modes.svg") : QIcon(iconPath+"/moder.svg")); } @@ -430,7 +430,7 @@ void SamplingBar::update_sample_rate_selector() disconnect(&_sample_rate, SIGNAL(currentIndexChanged(int)), this, SLOT(on_samplerate_sel(int))); - const boost::shared_ptr dev_inst = get_selected_device(); + DevInst *dev_inst = get_selected_device(); if (!dev_inst) return; @@ -504,7 +504,7 @@ void SamplingBar::update_sample_rate_selector_value() void SamplingBar::on_samplerate_sel(int index) { (void)index; - const boost::shared_ptr dev_inst = get_selected_device(); + const DevInst *dev_inst = get_selected_device(); if (dev_inst->dev_inst()->mode != DSO) update_sample_count_selector(); } @@ -530,7 +530,7 @@ void SamplingBar::update_sample_count_selector() assert(!_updating_sample_count); _updating_sample_count = true; - const boost::shared_ptr dev_inst = get_selected_device(); + DevInst *dev_inst = get_selected_device(); GVariant* gvar = dev_inst->get_config(NULL, NULL, SR_CONF_STREAM); if (gvar != NULL) { stream_mode = g_variant_get_boolean(gvar); @@ -546,7 +546,7 @@ void SamplingBar::update_sample_count_selector() #if defined(__x86_64__) || defined(_M_X64) sw_depth = LogicMaxSWDepth64; #elif defined(__i386) || defined(_M_IX86) - int ch_num = _session.get_ch_num(SR_CHANNEL_LOGIC); + int ch_num = _session->get_ch_num(SR_CHANNEL_LOGIC); if (ch_num <= 0) sw_depth = LogicMaxSWDepth32; else @@ -663,7 +663,7 @@ void SamplingBar::update_sample_count_selector_value() GVariant* gvar; double duration; - const boost::shared_ptr dev_inst = get_selected_device(); + DevInst *dev_inst = get_selected_device(); if (dev_inst->dev_inst()->mode == DSO) { gvar = dev_inst->get_config(NULL, NULL, SR_CONF_TIMEBASE); if (gvar != NULL) { @@ -706,7 +706,7 @@ void SamplingBar::on_samplecount_sel(int index) { (void)index; - const boost::shared_ptr dev_inst = get_selected_device(); + const DevInst *dev_inst = get_selected_device(); if (dev_inst->dev_inst()->mode == DSO) commit_hori_res(); sig_duration_changed(); @@ -744,7 +744,7 @@ double SamplingBar::commit_hori_res() const double hori_res = _sample_count.itemData( _sample_count.currentIndex()).value(); - const boost::shared_ptr dev_inst = get_selected_device(); + DevInst *dev_inst = get_selected_device(); const uint64_t sample_limit = dev_inst->get_sample_limit(); GVariant* gvar; uint64_t max_sample_rate; @@ -760,7 +760,7 @@ double SamplingBar::commit_hori_res() const uint64_t sample_rate = min((uint64_t)(sample_limit * SR_SEC(1) / (hori_res * DS_CONF_DSO_HDIVS)), (uint64_t)(max_sample_rate / - (_session.get_ch_num(SR_CHANNEL_DSO) ? _session.get_ch_num(SR_CHANNEL_DSO) : 1))); + (_session->get_ch_num(SR_CHANNEL_DSO) ? _session->get_ch_num(SR_CHANNEL_DSO) : 1))); set_sample_rate(sample_rate); dev_inst->set_config(NULL, NULL, SR_CONF_TIMEBASE, @@ -772,7 +772,7 @@ double SamplingBar::commit_hori_res() void SamplingBar::commit_settings() { bool test = false; - const boost::shared_ptr dev_inst = get_selected_device(); + DevInst *dev_inst = get_selected_device(); if (dev_inst && dev_inst->owner()) { GVariant *gvar = dev_inst->get_config(NULL, NULL, SR_CONF_TEST); if (gvar != NULL) { @@ -790,7 +790,7 @@ void SamplingBar::commit_settings() const uint64_t sample_rate = _sample_rate.itemData( _sample_rate.currentIndex()).value(); - const boost::shared_ptr dev_inst = get_selected_device(); + DevInst *dev_inst = get_selected_device(); if (dev_inst) { if (sample_rate != dev_inst->get_sample_rate()) dev_inst->set_config(NULL, NULL, @@ -815,16 +815,18 @@ void SamplingBar::commit_settings() void SamplingBar::on_run_stop() { - if (get_sampling() || _session.isRepeating()) { - _session.exit_capture(); + if (get_sampling() || _session->isRepeating()) { + _session->exit_capture(); } else { enable_run_stop(false); enable_instant(false); commit_settings(); _instant = false; - const boost::shared_ptr dev_inst = get_selected_device(); + + DevInst *dev_inst = get_selected_device(); if (!dev_inst) return; + if (dev_inst->dev_inst()->mode == DSO) { GVariant* gvar = dev_inst->get_config(NULL, NULL, SR_CONF_ZERO); if (gvar != NULL) { @@ -857,9 +859,9 @@ void SamplingBar::on_run_stop() void SamplingBar::on_instant_stop() { if (get_sampling()) { - _session.set_repeating(false); + _session->set_repeating(false); bool wait_upload = false; - if (_session.get_run_mode() != SigSession::Repetitive) { + if (_session->get_run_mode() != SigSession::Repetitive) { GVariant *gvar = get_selected_device()->get_config(NULL, NULL, SR_CONF_WAIT_UPLOAD); if (gvar != NULL) { wait_upload = g_variant_get_boolean(gvar); @@ -867,8 +869,8 @@ void SamplingBar::on_instant_stop() } } if (!wait_upload) { - _session.stop_capture(); - _session.capture_state_changed(SigSession::Stopped); + _session->stop_capture(); + _session->capture_state_changed(SigSession::Stopped); } } else { enable_run_stop(false); @@ -876,7 +878,7 @@ void SamplingBar::on_instant_stop() commit_settings(); _instant = true; - const boost::shared_ptr dev_inst = get_selected_device(); + DevInst *dev_inst = get_selected_device(); if (!dev_inst) return; @@ -915,15 +917,15 @@ void SamplingBar::on_device_selected() if (_updating_device_selector) return; - _session.stop_capture(); - _session.session_save(); + _session->stop_capture(); + _session->session_save(); - const boost::shared_ptr dev_inst = get_selected_device(); + DevInst* dev_inst = get_selected_device(); if (!dev_inst) return; try { - _session.set_device(dev_inst); + _session->set_device(dev_inst); } catch(QString e) { show_session_error(tr("Failed to select ") + dev_inst->dev_inst()->model, e); } @@ -933,7 +935,7 @@ void SamplingBar::on_device_selected() void SamplingBar::enable_toggle(bool enable) { bool test = false; - const boost::shared_ptr dev_inst = get_selected_device(); + DevInst *dev_inst = get_selected_device(); if (dev_inst && dev_inst->owner()) { GVariant *gvar = dev_inst->get_config(NULL, NULL, SR_CONF_TEST); if (gvar != NULL) { @@ -952,7 +954,7 @@ void SamplingBar::enable_toggle(bool enable) _sample_rate.setDisabled(true); } - if (_session.get_device()->name() == "virtual-session") { + if (_session->get_device()->name() == "virtual-session") { _sample_count.setDisabled(true); _sample_rate.setDisabled(true); } @@ -982,23 +984,23 @@ void SamplingBar::show_session_error( void SamplingBar::reload() { QString iconPath = GetIconPath(); - if (_session.get_device()->dev_inst()->mode == LOGIC) { - if (_session.get_device()->name() == "virtual-session") { + if (_session->get_device()->dev_inst()->mode == LOGIC) { + if (_session->get_device()->name() == "virtual-session") { _mode_action->setVisible(false); } else { - _mode_button.setIcon(_session.get_run_mode() == pv::SigSession::Single ? QIcon(iconPath+"/modes.svg") : + _mode_button.setIcon(_session->get_run_mode() == pv::SigSession::Single ? QIcon(iconPath+"/modes.svg") : QIcon(iconPath+"/moder.svg")); _mode_action->setVisible(true); } _run_stop_action->setVisible(true); _instant_action->setVisible(true); enable_toggle(true); - } else if (_session.get_device()->dev_inst()->mode == ANALOG) { + } else if (_session->get_device()->dev_inst()->mode == ANALOG) { _mode_action->setVisible(false); _run_stop_action->setVisible(true); _instant_action->setVisible(false); enable_toggle(true); - } else if (_session.get_device()->dev_inst()->mode == DSO) { + } else if (_session->get_device()->dev_inst()->mode == DSO) { _mode_action->setVisible(false); _run_stop_action->setVisible(true); _instant_action->setVisible(true); @@ -1016,12 +1018,12 @@ void SamplingBar::on_mode() QAction *act = qobject_cast(sender()); if (act == _action_single) { _mode_button.setIcon(QIcon(iconPath+"/modes.svg")); - _session.set_run_mode(pv::SigSession::Single); + _session->set_run_mode(pv::SigSession::Single); } else if (act == _action_repeat) { _mode_button.setIcon(QIcon(iconPath+"/moder.svg")); pv::dialogs::Interval interval_dlg(_session, this); interval_dlg.exec(); - _session.set_run_mode(pv::SigSession::Repetitive); + _session->set_run_mode(pv::SigSession::Repetitive); } } diff --git a/DSView/pv/toolbars/samplingbar.h b/DSView/pv/toolbars/samplingbar.h index ee3ce6d8..f4addaef 100755 --- a/DSView/pv/toolbars/samplingbar.h +++ b/DSView/pv/toolbars/samplingbar.h @@ -45,7 +45,7 @@ namespace pv namespace device { - // class DevInst; + class DevInst; } namespace dialogs @@ -72,12 +72,11 @@ namespace pv static const uint64_t ZeroTimeBase = SR_US(2); public: - SamplingBar(SigSession &session, QWidget *parent); + SamplingBar(SigSession *session, QWidget *parent); - void set_device_list(const std::list> &devices, - boost::shared_ptr selected); + void set_device_list(const std::list &devices, DevInst* selected); - boost::shared_ptr get_selected_device() const; + DevInst *get_selected_device() const; void update_sample_rate_selector(); @@ -135,7 +134,7 @@ namespace pv void reload(); private: - SigSession &_session; + SigSession *_session; mutable boost::recursive_mutex _sampling_mutex; bool _enable; @@ -144,8 +143,7 @@ namespace pv QToolButton _device_type; QComboBox _device_selector; - std::map> - _device_selector_map; + std::map _device_selector_map; bool _updating_device_selector; QToolButton _configure_button; diff --git a/DSView/pv/toolbars/trigbar.cpp b/DSView/pv/toolbars/trigbar.cpp index 7fa25e17..ea5f7c8e 100755 --- a/DSView/pv/toolbars/trigbar.cpp +++ b/DSView/pv/toolbars/trigbar.cpp @@ -38,7 +38,7 @@ namespace toolbars { const QString TrigBar::DARK_STYLE = "dark"; const QString TrigBar::LIGHT_STYLE = "light"; -TrigBar::TrigBar(SigSession &session, QWidget *parent) : +TrigBar::TrigBar(SigSession *session, QWidget *parent) : QToolBar("Trig Bar", parent), _session(session), _enable(true), @@ -261,21 +261,21 @@ void TrigBar::close_all() void TrigBar::reload() { close_all(); - if (_session.get_device()->dev_inst()->mode == LOGIC) { + if (_session->get_device()->dev_inst()->mode == LOGIC) { _trig_action->setVisible(true); _protocol_action->setVisible(true); _measure_action->setVisible(true); _search_action->setVisible(true); _function_action->setVisible(false); _action_lissajous->setVisible(false); - } else if (_session.get_device()->dev_inst()->mode == ANALOG) { + } else if (_session->get_device()->dev_inst()->mode == ANALOG) { _trig_action->setVisible(false); _protocol_action->setVisible(false); _measure_action->setVisible(true); _search_action->setVisible(false); _function_action->setVisible(false); _action_lissajous->setVisible(false); - } else if (_session.get_device()->dev_inst()->mode == DSO) { + } else if (_session->get_device()->dev_inst()->mode == DSO) { _trig_action->setVisible(true); _protocol_action->setVisible(false); _measure_action->setVisible(true); diff --git a/DSView/pv/toolbars/trigbar.h b/DSView/pv/toolbars/trigbar.h index 58f07f05..f22ce207 100755 --- a/DSView/pv/toolbars/trigbar.h +++ b/DSView/pv/toolbars/trigbar.h @@ -45,7 +45,7 @@ protected: static const QString LIGHT_STYLE; public: - explicit TrigBar(SigSession &session, QWidget *parent = 0); + explicit TrigBar(SigSession *session, QWidget *parent = 0); void enable_toggle(bool enable); void enable_protocol(bool enable); @@ -86,8 +86,8 @@ public slots: void on_application_param(); private: - SigSession& _session; - bool _enable; + SigSession *_session; + bool _enable; QToolButton _trig_button; QToolButton _protocol_button; QToolButton _measure_button; diff --git a/DSView/pv/view/analogsignal.cpp b/DSView/pv/view/analogsignal.cpp index 2460fe5e..605566ac 100755 --- a/DSView/pv/view/analogsignal.cpp +++ b/DSView/pv/view/analogsignal.cpp @@ -47,7 +47,7 @@ const QColor AnalogSignal::SignalColours[4] = { const float AnalogSignal::EnvelopeThreshold = 16.0f; -AnalogSignal::AnalogSignal(boost::shared_ptr dev_inst, +AnalogSignal::AnalogSignal(DevInst *dev_inst, boost::shared_ptr data, sr_channel *probe) : Signal(dev_inst, probe), diff --git a/DSView/pv/view/analogsignal.h b/DSView/pv/view/analogsignal.h index 94e29290..401351eb 100755 --- a/DSView/pv/view/analogsignal.h +++ b/DSView/pv/view/analogsignal.h @@ -53,7 +53,7 @@ private: static const uint8_t DefaultBits = 8; public: - AnalogSignal(boost::shared_ptr dev_inst, + AnalogSignal(DevInst* dev_inst, boost::shared_ptr data, sr_channel *probe); AnalogSignal(boost::shared_ptr s, diff --git a/DSView/pv/view/decodetrace.cpp b/DSView/pv/view/decodetrace.cpp index 0fa24f1a..b81be63e 100755 --- a/DSView/pv/view/decodetrace.cpp +++ b/DSView/pv/view/decodetrace.cpp @@ -115,7 +115,7 @@ const QColor DecodeTrace::OutlineColours[16] = { const QString DecodeTrace::RegionStart = QT_TR_NOOP("Start"); const QString DecodeTrace::RegionEnd = QT_TR_NOOP("End "); -DecodeTrace::DecodeTrace(pv::SigSession &session, +DecodeTrace::DecodeTrace(pv::SigSession *session, boost::shared_ptr decoder_stack, int index) : Trace(QString::fromUtf8( decoder_stack->stack().front()->decoder()->name), index, SR_CHANNEL_DECODER), @@ -181,7 +181,7 @@ void DecodeTrace::paint_back(QPainter &p, int left, int right, QColor fore, QCol p.drawLine(left, sigY, right, sigY); // --draw decode region control - const double samples_per_pixel = _session.cur_snap_samplerate() * _view->scale(); + const double samples_per_pixel = _session->cur_snap_samplerate() * _view->scale(); const double startX = _decode_start/samples_per_pixel - _view->offset(); const double endX = _decode_end/samples_per_pixel - _view->offset(); const double regionY = get_y() - _totalHeight*0.5 - ControlRectWidth; @@ -534,7 +534,7 @@ void DecodeTrace::draw_annotation(const pv::data::decode::Annotation &a, ((type%100 != a.type()%100) && (type%100 != 0))) continue; boost::shared_ptr logic_sig; - BOOST_FOREACH(boost::shared_ptr sig, _session.get_signals()) { + BOOST_FOREACH(boost::shared_ptr sig, _session->get_signals()) { if((sig->get_index() == iter.second) && (logic_sig = dynamic_pointer_cast(sig))) { logic_sig->paint_mark(p, start, end, type/100); @@ -773,7 +773,7 @@ QComboBox* DecodeTrace::create_probe_selector( { assert(dec); - const vector< boost::shared_ptr > sigs(_session.get_signals()); + const vector< boost::shared_ptr > sigs(_session->get_signals()); assert(_decoder_stack); const map::const_iterator probe_iter = @@ -809,7 +809,7 @@ void DecodeTrace::commit_decoder_probes(boost::shared_ptr assert(dec); map probe_map; - const vector< boost::shared_ptr > sigs(_session.get_signals()); + const vector< boost::shared_ptr > sigs(_session->get_signals()); _index_list.clear(); BOOST_FOREACH(const ProbeSelector &s, _probe_selectors) @@ -873,12 +873,12 @@ void DecodeTrace::on_decode_done() // _view->signals_changed(); // } on_new_decode_data(); - _session.decode_done(); + _session->decode_done(); } void DecodeTrace::on_delete() { - _session.remove_decode_signal(this); + _session->remove_decode_signal(this); } void DecodeTrace::on_probe_selected(int) @@ -971,7 +971,7 @@ QRectF DecodeTrace::get_rect(DecodeSetRegions type, int y, int right) void DecodeTrace::on_region_set(int index) { (void)index; - const uint64_t last_samples = _session.cur_samplelimits() - 1; + const uint64_t last_samples = _session->cur_samplelimits() - 1; const int index1 = _start_comboBox->currentIndex(); const int index2 = _end_comboBox->currentIndex(); uint64_t decode_start, decode_end; @@ -1008,7 +1008,7 @@ void DecodeTrace::on_region_set(int index) void DecodeTrace::frame_ended() { - const uint64_t last_samples = _session.cur_samplelimits() - 1; + const uint64_t last_samples = _session->cur_samplelimits() - 1; if (_decode_start > last_samples) { _decode_start = 0; _start_index = 0; diff --git a/DSView/pv/view/decodetrace.h b/DSView/pv/view/decodetrace.h index 924cf333..ee2ae804 100755 --- a/DSView/pv/view/decodetrace.h +++ b/DSView/pv/view/decodetrace.h @@ -97,7 +97,7 @@ private: static const QString RegionEnd; public: - DecodeTrace(pv::SigSession &session, + DecodeTrace(pv::SigSession *session, boost::shared_ptr decoder_stack, int index); ~DecodeTrace(); @@ -206,7 +206,7 @@ private slots: void on_region_set(int index); private: - pv::SigSession &_session; + pv::SigSession *_session; boost::shared_ptr _decoder_stack; uint64_t _decode_start, _decode_end; diff --git a/DSView/pv/view/devmode.cpp b/DSView/pv/view/devmode.cpp index 2c99e95b..05659b20 100755 --- a/DSView/pv/view/devmode.cpp +++ b/DSView/pv/view/devmode.cpp @@ -43,7 +43,7 @@ using namespace std; namespace pv { namespace view { -DevMode::DevMode(QWidget *parent, SigSession &session) : +DevMode::DevMode(QWidget *parent, SigSession *session) : QWidget(parent), _session(session) @@ -91,7 +91,7 @@ void DevMode::changeEvent(QEvent *event) void DevMode::set_device() { - const boost::shared_ptr dev_inst = _session.get_device(); + DevInst* dev_inst = _session->get_device(); assert(dev_inst); for(std::map::const_iterator i = _mode_list.begin(); @@ -134,8 +134,8 @@ void DevMode::set_device() _pop_menu->addAction(action); } - boost::shared_ptr file_dev; - if((file_dev = dynamic_pointer_cast(dev_inst))) { + File *file_dev; + if((file_dev = dynamic_cast(dev_inst))) { _close_button->setDisabled(false); _close_button->setIcon(QIcon(iconPath+"/close.svg")); connect(_close_button, SIGNAL(clicked()), this, SLOT(on_close())); @@ -156,7 +156,7 @@ void DevMode::paintEvent(QPaintEvent*) void DevMode::on_mode_change() { - const boost::shared_ptr dev_inst = _session.get_device(); + DevInst* dev_inst = _session->get_device(); assert(dev_inst); QAction *action = qobject_cast(sender()); if (dev_inst->dev_inst()->mode == _mode_list[action]->mode) @@ -170,11 +170,11 @@ void DevMode::on_mode_change() i != _mode_list.end(); i++) { if ((*i).first == action) { if (dev_inst->dev_inst()->mode != (*i).second->mode) { - _session.set_run_mode(SigSession::Single); - _session.set_repeating(false); - _session.stop_capture(); - _session.capture_state_changed(SigSession::Stopped); - _session.session_save(); + _session->set_run_mode(SigSession::Single); + _session->set_repeating(false); + _session->stop_capture(); + _session->capture_state_changed(SigSession::Stopped); + _session->session_save(); dev_inst->set_config(NULL, NULL, SR_CONF_DEVICE_MODE, g_variant_new_int16((*i).second->mode)); @@ -193,10 +193,10 @@ void DevMode::on_mode_change() void DevMode::on_close() { - const boost::shared_ptr dev_inst = _session.get_device(); + DevInst *dev_inst = _session->get_device(); assert(dev_inst); - _session.close_file(dev_inst); + _session->close_file(dev_inst); dev_changed(true); } diff --git a/DSView/pv/view/devmode.h b/DSView/pv/view/devmode.h index 6dc2f5d9..ae26e53c 100755 --- a/DSView/pv/view/devmode.h +++ b/DSView/pv/view/devmode.h @@ -59,7 +59,7 @@ private: static const int GRID_COLS = 3; public: - DevMode(QWidget *parent, SigSession &session); + DevMode(QWidget *parent, SigSession *ession); private: void paintEvent(QPaintEvent *event); @@ -83,7 +83,7 @@ signals: void dev_changed(bool close); private: - SigSession &_session; + SigSession *_session; QHBoxLayout * _layout; std::map _mode_list; diff --git a/DSView/pv/view/dsosignal.cpp b/DSView/pv/view/dsosignal.cpp index a359acad..615f2d31 100755 --- a/DSView/pv/view/dsosignal.cpp +++ b/DSView/pv/view/dsosignal.cpp @@ -56,7 +56,7 @@ const QColor DsoSignal::SignalColours[4] = { const float DsoSignal::EnvelopeThreshold = 256.0f; -DsoSignal::DsoSignal(boost::shared_ptr dev_inst, +DsoSignal::DsoSignal(DevInst *dev_inst, boost::shared_ptr data, sr_channel *probe): Signal(dev_inst, probe), diff --git a/DSView/pv/view/dsosignal.h b/DSView/pv/view/dsosignal.h index a6f28ec2..50d079a9 100755 --- a/DSView/pv/view/dsosignal.h +++ b/DSView/pv/view/dsosignal.h @@ -87,7 +87,7 @@ private: static const uint16_t MS_RectHeight = 25; public: - DsoSignal(boost::shared_ptr dev_inst, + DsoSignal(DevInst* dev_inst, boost::shared_ptr data, sr_channel *probe); diff --git a/DSView/pv/view/logicsignal.cpp b/DSView/pv/view/logicsignal.cpp index 95d57b67..e336dc4a 100755 --- a/DSView/pv/view/logicsignal.cpp +++ b/DSView/pv/view/logicsignal.cpp @@ -45,7 +45,7 @@ const float LogicSignal::Oversampling = 1.0f; const int LogicSignal::StateHeight = 12; const int LogicSignal::StateRound = 5; -LogicSignal::LogicSignal(boost::shared_ptr dev_inst, +LogicSignal::LogicSignal(DevInst *dev_inst, boost::shared_ptr data, sr_channel *probe) : Signal(dev_inst, probe), diff --git a/DSView/pv/view/logicsignal.h b/DSView/pv/view/logicsignal.h index c9377c8a..d2159eb5 100755 --- a/DSView/pv/view/logicsignal.h +++ b/DSView/pv/view/logicsignal.h @@ -37,6 +37,8 @@ class Logic; class Analog; } +using namespace pv::device; + namespace view { //when device is logic analyzer mode, to draw logic signal trace @@ -64,7 +66,7 @@ public: }; public: - LogicSignal(boost::shared_ptr dev_inst, + LogicSignal(DevInst *dev_inst, boost::shared_ptr data, sr_channel *probe); diff --git a/DSView/pv/view/signal.cpp b/DSView/pv/view/signal.cpp index 0646cb06..3be6142d 100755 --- a/DSView/pv/view/signal.cpp +++ b/DSView/pv/view/signal.cpp @@ -32,8 +32,7 @@ namespace pv { namespace view { -Signal::Signal(boost::shared_ptr dev_inst, - sr_channel *probe) : +Signal::Signal(DevInst *dev_inst,sr_channel *probe) : Trace(probe->name, probe->index, probe->type), _dev_inst(dev_inst), _probe(probe) @@ -59,7 +58,7 @@ void Signal::set_name(QString name) _probe->name = g_strdup(name.toUtf8().data()); } -boost::shared_ptr Signal::get_device() const +DevInst* Signal::get_device() const { return _dev_inst; } diff --git a/DSView/pv/view/signal.h b/DSView/pv/view/signal.h index ff7eb5b0..1d3ed5ad 100755 --- a/DSView/pv/view/signal.h +++ b/DSView/pv/view/signal.h @@ -48,6 +48,8 @@ namespace device { class DevInst; } +using namespace pv::device; + namespace view { //draw signal trace base class @@ -59,8 +61,7 @@ private: protected: - Signal(boost::shared_ptr dev_inst, - sr_channel * const probe); + Signal(DevInst* dev_inst,sr_channel * const probe); /** * Copy constructor @@ -90,10 +91,10 @@ public: */ //virtual void paint_label(QPainter &p, int right, bool hover, int action); - boost::shared_ptr get_device() const; + DevInst* get_device() const; protected: - boost::shared_ptr _dev_inst; + DevInst* _dev_inst; sr_channel *const _probe; }; diff --git a/DSView/pv/view/spectrumtrace.cpp b/DSView/pv/view/spectrumtrace.cpp index 4be12280..64500c52 100755 --- a/DSView/pv/view/spectrumtrace.cpp +++ b/DSView/pv/view/spectrumtrace.cpp @@ -67,7 +67,7 @@ const int SpectrumTrace::DbvRanges[4] = { const int SpectrumTrace::HoverPointSize = 3; const double SpectrumTrace::VerticalRate = 1.0 / 2000.0; -SpectrumTrace::SpectrumTrace(pv::SigSession &session, +SpectrumTrace::SpectrumTrace(pv::SigSession *session, boost::shared_ptr spectrum_stack, int index) : Trace("FFT("+QString::number(index)+")", index, SR_CHANNEL_FFT), _session(session), @@ -79,7 +79,7 @@ SpectrumTrace::SpectrumTrace(pv::SigSession &session, _offset(0) { _typeWidth = 0; - const vector< boost::shared_ptr > sigs(_session.get_signals()); + const vector< boost::shared_ptr > sigs(_session->get_signals()); for(size_t i = 0; i < sigs.size(); i++) { const boost::shared_ptr s(sigs[i]); assert(s); @@ -294,7 +294,7 @@ void SpectrumTrace::paint_mid(QPainter &p, int left, int right, QColor fore, QCo double vdiv = 0; double vfactor = 0; - BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s))) { if(dsoSig->get_index() == _spectrum_stack->get_index()) { @@ -364,8 +364,8 @@ void SpectrumTrace::paint_fore(QPainter &p, int left, int right, QColor fore, QC double blank_right = width; // horizontal ruler - const double NyFreq = _session.cur_snap_samplerate() / (2.0 * _spectrum_stack->get_sample_interval()); - const double deltaFreq = _session.cur_snap_samplerate() * 1.0 / + const double NyFreq = _session->cur_snap_samplerate() / (2.0 * _spectrum_stack->get_sample_interval()); + const double deltaFreq = _session->cur_snap_samplerate() * 1.0 / (_spectrum_stack->get_sample_num() * _spectrum_stack->get_sample_interval()); const double FreqRange = NyFreq * _scale; const double FreqOffset = NyFreq * _offset; diff --git a/DSView/pv/view/spectrumtrace.h b/DSView/pv/view/spectrumtrace.h index 7173188b..293269ef 100755 --- a/DSView/pv/view/spectrumtrace.h +++ b/DSView/pv/view/spectrumtrace.h @@ -67,7 +67,7 @@ private: static const double VerticalRate; public: - SpectrumTrace(pv::SigSession &session, + SpectrumTrace(pv::SigSession *session, boost::shared_ptr spectrum_stack, int index); ~SpectrumTrace(); @@ -133,7 +133,7 @@ private: private slots: private: - pv::SigSession &_session; + pv::SigSession *_session; boost::shared_ptr _spectrum_stack; bool _enable; diff --git a/DSView/pv/view/view.cpp b/DSView/pv/view/view.cpp index 349f0b6b..d9bb13d1 100755 --- a/DSView/pv/view/view.cpp +++ b/DSView/pv/view/view.cpp @@ -79,7 +79,7 @@ const QColor View::LightBlue = QColor(17, 133, 209, 200); const QColor View::LightRed = QColor(213, 15, 37, 200); -View::View(SigSession &session, pv::toolbars::SamplingBar *sampling_bar, QWidget *parent) : +View::View(SigSession *session, pv::toolbars::SamplingBar *sampling_bar, QWidget *parent) : QScrollArea(parent), _session(session), _sampling_bar(sampling_bar), @@ -98,7 +98,9 @@ View::View(SigSession &session, pv::toolbars::SamplingBar *sampling_bar, QWidget _dso_auto(true), _show_lissajous(false), _back_ready(false) -{ +{ + assert(session); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), @@ -165,23 +167,23 @@ View::View(SigSession &session, pv::toolbars::SamplingBar *sampling_bar, QWidget connect(_vsplitter, SIGNAL(splitterMoved(int,int)), this, SLOT(splitterMoved(int, int))); - connect(&_session, SIGNAL(device_setted()), + connect(_session, SIGNAL(device_setted()), _devmode, SLOT(set_device())); - connect(&_session, SIGNAL(signals_changed()), + connect(_session, SIGNAL(signals_changed()), this, SLOT(signals_changed()), Qt::DirectConnection); - connect(&_session, SIGNAL(data_updated()), + connect(_session, SIGNAL(data_updated()), this, SLOT(data_updated())); - connect(&_session, SIGNAL(receive_trigger(quint64)), + connect(_session, SIGNAL(receive_trigger(quint64)), this, SLOT(receive_trigger(quint64))); - connect(&_session, SIGNAL(frame_ended()), + connect(_session, SIGNAL(frame_ended()), this, SLOT(receive_end())); - connect(&_session, SIGNAL(frame_began()), + connect(_session, SIGNAL(frame_began()), this, SLOT(frame_began())); - connect(&_session, SIGNAL(show_region(uint64_t, uint64_t, bool)), + connect(_session, SIGNAL(show_region(uint64_t, uint64_t, bool)), this, SLOT(show_region(uint64_t, uint64_t, bool))); - connect(&_session, SIGNAL(show_wait_trigger()), + connect(_session, SIGNAL(show_wait_trigger()), _time_viewport, SLOT(show_wait_trigger())); - connect(&_session, SIGNAL(repeat_hold(int)), + connect(_session, SIGNAL(repeat_hold(int)), this, SLOT(repeat_show())); connect(_devmode, SIGNAL(dev_changed(bool)), @@ -217,7 +219,7 @@ View::View(SigSession &session, pv::toolbars::SamplingBar *sampling_bar, QWidget SigSession& View::session() { - return _session; + return *_session; } double View::scale() const @@ -252,13 +254,13 @@ double View::get_maxscale() const void View::capture_init() { - if (_session.get_device()->dev_inst()->mode == DSO) + if (_session->get_device()->dev_inst()->mode == DSO) show_trig_cursor(true); - else if (!_session.isRepeating()) + else if (!_session->isRepeating()) show_trig_cursor(false); - _maxscale = _session.cur_sampletime() / (get_view_width() * MaxViewRate); - if (_session.get_device()->dev_inst()->mode == ANALOG) + _maxscale = _session->cur_sampletime() / (get_view_width() * MaxViewRate); + if (_session->get_device()->dev_inst()->mode == ANALOG) set_scale_offset(_maxscale, 0); status_clear(); _trig_time_setted = false; @@ -288,7 +290,7 @@ double View::get_hori_res() void View::update_hori_res() { - if (_session.get_device()->dev_inst()->mode == DSO) { + if (_session->get_device()->dev_inst()->mode == DSO) { _sampling_bar->hori_knob(0); } } @@ -299,12 +301,12 @@ bool View::zoom(double steps, int offset) _preScale = _scale; _preOffset = _offset; - if (_session.get_device()->dev_inst()->mode != DSO) { + if (_session->get_device()->dev_inst()->mode != DSO) { _scale *= std::pow(3.0/2.0, -steps); _scale = max(min(_scale, _maxscale), _minscale); } else { - if (_session.get_capture_state() == SigSession::Running && - _session.get_instant()) + if (_session->get_capture_state() == SigSession::Running && + _session->get_instant()) return ret; double hori_res = -1; @@ -314,7 +316,7 @@ bool View::zoom(double steps, int offset) hori_res = _sampling_bar->hori_knob(1); if (hori_res > 0) { - const double scale = _session.cur_view_time() / get_view_width(); + const double scale = _session->cur_view_time() / get_view_width(); _scale = max(min(scale, _maxscale), _minscale); } else { ret = false; @@ -336,19 +338,19 @@ bool View::zoom(double steps, int offset) void View::timebase_changed() { - if (_session.get_device()->dev_inst()->mode != DSO) + if (_session->get_device()->dev_inst()->mode != DSO) return; double scale = this->scale(); double hori_res = _sampling_bar->get_hori_res(); if (hori_res > 0) - scale = _session.cur_view_time() / get_view_width(); + scale = _session->cur_view_time() / get_view_width(); set_scale_offset(scale, this->offset()); } void View::set_scale_offset(double scale, int64_t offset) { - //if (_session.get_capture_state() == SigSession::Stopped) { + //if (_session->get_capture_state() == SigSession::Stopped) { _preScale = _scale; _preOffset = _offset; @@ -375,13 +377,16 @@ void View::set_preScale_preOffset() vector< boost::shared_ptr > View::get_traces(int type) { - const vector< boost::shared_ptr > sigs(_session.get_signals()); - const vector< boost::shared_ptr > groups(_session.get_group_signals()); + assert(_session); + + auto array = _session->get_signals(); + const vector< boost::shared_ptr > sigs(array); + const vector< boost::shared_ptr > groups(_session->get_group_signals()); const vector< boost::shared_ptr > decode_sigs( - _session.get_decode_signals()); + _session->get_decode_signals()); - const vector< boost::shared_ptr > spectrums(_session.get_spectrum_traces()); + const vector< boost::shared_ptr > spectrums(_session->get_spectrum_traces()); vector< boost::shared_ptr > traces; BOOST_FOREACH(boost::shared_ptr t, sigs) { @@ -404,12 +409,12 @@ vector< boost::shared_ptr > View::get_traces(int type) traces.push_back(t); } - boost::shared_ptr lissajous = _session.get_lissajous_trace(); + boost::shared_ptr lissajous = _session->get_lissajous_trace(); if (lissajous && lissajous->enabled() && (type == ALL_VIEW || _trace_view_map[lissajous->get_type()] == type)) traces.push_back(lissajous); - boost::shared_ptr math = _session.get_math_trace(); + boost::shared_ptr math = _session->get_math_trace(); if (math && math->enabled() && (type == ALL_VIEW || _trace_view_map[math->get_type()] == type)) traces.push_back(math); @@ -481,8 +486,8 @@ void View::repeat_unshow() void View::frame_began() { -// if (_session.get_device()->dev_inst()->mode == LOGIC) -// _viewbottom->set_trig_time(_session.get_session_time()); +// if (_session->get_device()->dev_inst()->mode == LOGIC) +// _viewbottom->set_trig_time(_session->get_session_time()); _search_hit = false; _search_pos = 0; set_search_pos(_search_pos, _search_hit); @@ -490,9 +495,9 @@ void View::frame_began() void View::set_trig_time() { - if (!_trig_time_setted && _session.get_device()->dev_inst()->mode == LOGIC) { - _session.set_session_time(QDateTime::currentDateTime()); - _viewbottom->set_trig_time(_session.get_session_time()); + if (!_trig_time_setted && _session->get_device()->dev_inst()->mode == LOGIC) { + _session->set_session_time(QDateTime::currentDateTime()); + _viewbottom->set_trig_time(_session->get_session_time()); } _trig_time_setted = true; } @@ -504,17 +509,17 @@ bool View::trig_time_setted() void View::receive_end() { - if (_session.get_device()->dev_inst()->mode == LOGIC) { - GVariant *gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_RLE); + if (_session->get_device()->dev_inst()->mode == LOGIC) { + GVariant *gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_RLE); if (gvar != NULL) { bool rle = g_variant_get_boolean(gvar); g_variant_unref(gvar); if (rle) { - gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_ACTUAL_SAMPLES); + gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_ACTUAL_SAMPLES); if (gvar != NULL) { uint64_t actual_samples = g_variant_get_uint64(gvar); g_variant_unref(gvar); - if (actual_samples != _session.cur_samplelimits()) { + if (actual_samples != _session->cur_samplelimits()) { _viewbottom->set_rle_depth(actual_samples); } } @@ -526,11 +531,11 @@ void View::receive_end() void View::receive_trigger(quint64 trig_pos) { - const double time = trig_pos * 1.0 / _session.cur_snap_samplerate(); + const double time = trig_pos * 1.0 / _session->cur_snap_samplerate(); _trig_cursor->set_index(trig_pos); if (ds_trigger_get_en() || - _session.get_device()->name() == "virtual-session" || - _session.get_device()->dev_inst()->mode == DSO) { + _session->get_device()->name() == "virtual-session" || + _session->get_device()->dev_inst()->mode == DSO) { _show_trig_cursor = true; set_scale_offset(_scale, (time / _scale) - (get_view_width() / 2)); } @@ -541,7 +546,7 @@ void View::receive_trigger(quint64 trig_pos) void View::set_trig_pos(int percent) { - uint64_t index = _session.cur_samplelimits() * percent / 100; + uint64_t index = _session->cur_samplelimits() * percent / 100; receive_trigger(index); } @@ -551,7 +556,7 @@ void View::set_search_pos(uint64_t search_pos, bool hit) QColor fore(QWidget::palette().color(QWidget::foregroundRole())); fore.setAlpha(View::BackAlpha); - const double time = search_pos * 1.0 / _session.cur_snap_samplerate(); + const double time = search_pos * 1.0 / _session->cur_snap_samplerate(); _search_pos = search_pos; _search_hit = hit; _search_cursor->set_index(search_pos); @@ -608,11 +613,11 @@ int View::get_signalHeight() void View::get_scroll_layout(int64_t &length, int64_t &offset) const { - const set< boost::shared_ptr > data_set = _session.get_data(); + const set< boost::shared_ptr > data_set = _session->get_data(); if (data_set.empty()) return; - length = ceil(_session.cur_snap_sampletime() / _scale); + length = ceil(_session->cur_snap_sampletime() / _scale); offset = _offset; } @@ -650,11 +655,11 @@ void View::update_scroll() void View::update_scale_offset() { - if (_session.get_device()->dev_inst()->mode != DSO) { - _maxscale = _session.cur_sampletime() / (get_view_width() * MaxViewRate); - _minscale = (1.0 / _session.cur_snap_samplerate()) / MaxPixelsPerSample; + if (_session->get_device()->dev_inst()->mode != DSO) { + _maxscale = _session->cur_sampletime() / (get_view_width() * MaxViewRate); + _minscale = (1.0 / _session->cur_snap_samplerate()) / MaxPixelsPerSample; } else { - _scale = _session.cur_view_time() / get_view_width(); + _scale = _session->cur_view_time() / get_view_width(); _maxscale = 1e9; _minscale = 1e-15; } @@ -665,7 +670,7 @@ void View::update_scale_offset() _preScale = _scale; _preOffset = _offset; - //_trig_cursor->set_index(_session.get_trigger_pos()); + //_trig_cursor->set_index(_session->get_trigger_pos()); _ruler->update(); viewport_update(); @@ -674,8 +679,8 @@ void View::update_scale_offset() void View::dev_changed(bool close) { if (!close) { - if (_session.get_device()->name().contains("virtual")) - _scale = WellSamplesPerPixel * 1.0 / _session.cur_snap_samplerate(); + if (_session->get_device()->name().contains("virtual")) + _scale = WellSamplesPerPixel * 1.0 / _session->cur_snap_samplerate(); _scale = max(min(_scale, _maxscale), _minscale); } @@ -739,8 +744,8 @@ void View::signals_changed() const double height = (_time_viewport->height() - 2 * actualMargin * label_size) * 1.0 / total_rows; - if (_session.get_device()->dev_inst()->mode == LOGIC) { - GVariant* gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_MAX_HEIGHT_VALUE); + if (_session->get_device()->dev_inst()->mode == LOGIC) { + GVariant* gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_MAX_HEIGHT_VALUE); if (gvar != NULL) { max_height = (g_variant_get_byte(gvar) + 1) * MaxHeightUnit; g_variant_unref(gvar); @@ -752,7 +757,7 @@ void View::signals_changed() } else { _signalHeight = (height >= max_height) ? max_height : height; } - } else if (_session.get_device()->dev_inst()->mode == DSO) { + } else if (_session->get_device()->dev_inst()->mode == DSO) { _signalHeight = (_header->height() - horizontalScrollBar()->height() - 2 * actualMargin * label_size) * 1.0 / total_rows; @@ -800,7 +805,7 @@ bool View::eventFilter(QObject *object, QEvent *event) double cur_periods = (mouse_event->pos().x() + _offset) * _scale / _ruler->get_min_period(); int integer_x = round(cur_periods) * _ruler->get_min_period() / _scale - _offset; double cur_deviate_x = qAbs(mouse_event->pos().x() - integer_x); - if (_session.get_device()->dev_inst()->mode == LOGIC && + if (_session->get_device()->dev_inst()->mode == LOGIC && cur_deviate_x < 10) _hover_point = QPoint(integer_x, mouse_event->pos().y()); else @@ -859,11 +864,11 @@ void View::resizeEvent(QResizeEvent*) update_margins(); update_scroll(); signals_changed(); - if (_session.get_device()->dev_inst()->mode == DSO) - _scale = _session.cur_view_time() / get_view_width(); + if (_session->get_device()->dev_inst()->mode == DSO) + _scale = _session->cur_view_time() / get_view_width(); - if (_session.get_device()->dev_inst()->mode != DSO) - _maxscale = _session.cur_sampletime() / (get_view_width() * MaxViewRate); + if (_session->get_device()->dev_inst()->mode != DSO) + _maxscale = _session->cur_sampletime() / (get_view_width() * MaxViewRate); else _maxscale = 1e9; @@ -1008,7 +1013,7 @@ void View::set_cursor_middle(int index) list::iterator i = _cursorList.begin(); while (index-- != 0) i++; - set_scale_offset(_scale, (*i)->index() / (_session.cur_snap_samplerate() * _scale) - (get_view_width() / 2)); + set_scale_offset(_scale, (*i)->index() / (_session->cur_snap_samplerate() * _scale) - (get_view_width() / 2)); } void View::on_measure_updated() @@ -1027,7 +1032,7 @@ QString View::get_measure(QString option) QString View::get_cm_time(int index) { - return _ruler->format_real_time(get_cursor_samples(index), _session.cur_snap_samplerate()); + return _ruler->format_real_time(get_cursor_samples(index), _session->cur_snap_samplerate()); } QString View::get_cm_delta(int index1, int index2) @@ -1038,7 +1043,7 @@ QString View::get_cm_delta(int index1, int index2) uint64_t samples1 = get_cursor_samples(index1); uint64_t samples2 = get_cursor_samples(index2); uint64_t delta_sample = (samples1 > samples2) ? samples1 - samples2 : samples2 - samples1; - return _ruler->format_real_time(delta_sample, _session.cur_snap_samplerate()); + return _ruler->format_real_time(delta_sample, _session->cur_snap_samplerate()); } QString View::get_index_delta(uint64_t start, uint64_t end) @@ -1047,7 +1052,7 @@ QString View::get_index_delta(uint64_t start, uint64_t end) return "0"; uint64_t delta_sample = (start > end) ? start - end : end - start; - return _ruler->format_real_time(delta_sample, _session.cur_snap_samplerate()); + return _ruler->format_real_time(delta_sample, _session->cur_snap_samplerate()); } uint64_t View::get_cursor_samples(int index) @@ -1083,8 +1088,8 @@ void View::on_state_changed(bool stop) QRect View::get_view_rect() { - if (_session.get_device()->dev_inst()->mode == DSO) { - const vector< boost::shared_ptr > sigs(_session.get_signals()); + if (_session->get_device()->dev_inst()->mode == DSO) { + const vector< boost::shared_ptr > sigs(_session->get_signals()); BOOST_FOREACH(const boost::shared_ptr s, sigs) { return s->get_view_rect(); } @@ -1096,8 +1101,8 @@ QRect View::get_view_rect() int View::get_view_width() { int view_width = 0; - if (_session.get_device()->dev_inst()->mode == DSO) { - const vector< boost::shared_ptr > sigs(_session.get_signals()); + if (_session->get_device()->dev_inst()->mode == DSO) { + const vector< boost::shared_ptr > sigs(_session->get_signals()); BOOST_FOREACH(const boost::shared_ptr s, sigs) { view_width = max(view_width, s->get_view_rect().width()); } @@ -1111,8 +1116,8 @@ int View::get_view_width() int View::get_view_height() { int view_height = 0; - if (_session.get_device()->dev_inst()->mode == DSO) { - const vector< boost::shared_ptr > sigs(_session.get_signals()); + if (_session->get_device()->dev_inst()->mode == DSO) { + const vector< boost::shared_ptr > sigs(_session->get_signals()); BOOST_FOREACH(const boost::shared_ptr s, sigs) { view_height = max(view_height, s->get_view_rect().height()); } @@ -1133,14 +1138,14 @@ int64_t View::get_min_offset() int64_t View::get_max_offset() { - return ceil((_session.cur_snap_sampletime() / _scale) - + return ceil((_session->cur_snap_sampletime() / _scale) - (get_view_width() * MaxViewRate)); } // -- calibration dialog void View::show_calibration() { - _cali->set_device(_session.get_device()); + _cali->set_device(_session->get_device()); _cali->show(); } @@ -1152,9 +1157,9 @@ void View::hide_calibration() void View::vDial_updated() { if (_cali->isVisible()) { - _cali->set_device(_session.get_device()); + _cali->set_device(_session->get_device()); } - boost::shared_ptr math_trace = _session.get_math_trace(); + boost::shared_ptr math_trace = _session->get_math_trace(); if (math_trace && math_trace->enabled()) { math_trace->update_vDial(); } @@ -1173,14 +1178,14 @@ void View::show_region(uint64_t start, uint64_t end, bool keep) if (keep) { set_all_update(true); update(); - } else if (_session.get_map_zoom() == 0) { - const double ideal_scale = (end-start) * 2.0 / _session.cur_snap_samplerate() / get_view_width(); + } else if (_session->get_map_zoom() == 0) { + const double ideal_scale = (end-start) * 2.0 / _session->cur_snap_samplerate() / get_view_width(); const double new_scale = max(min(ideal_scale, _maxscale), _minscale); - const double new_off = (start + end) * 0.5 / (_session.cur_snap_samplerate() * new_scale) - (get_view_width() / 2); + const double new_off = (start + end) * 0.5 / (_session->cur_snap_samplerate() * new_scale) - (get_view_width() / 2); set_scale_offset(new_scale, new_off); } else { const double new_scale = scale(); - const double new_off = (start + end) * 0.5 / (_session.cur_snap_samplerate() * new_scale) - (get_view_width() / 2); + const double new_off = (start + end) * 0.5 / (_session->cur_snap_samplerate() * new_scale) - (get_view_width() / 2); set_scale_offset(new_scale, new_off); } } @@ -1214,7 +1219,7 @@ void View::clear() { show_trig_cursor(false); - if (_session.get_device()->dev_inst()->mode != DSO) { + if (_session->get_device()->dev_inst()->mode != DSO) { show_xcursors(false); } else { if (!get_xcursorList().empty()) @@ -1224,7 +1229,7 @@ void View::clear() void View::reconstruct() { - if (_session.get_device()->dev_inst()->mode == DSO) + if (_session->get_device()->dev_inst()->mode == DSO) _viewbottom->setFixedHeight(DsoStatusHeight); else _viewbottom->setFixedHeight(StatusHeight); @@ -1240,7 +1245,7 @@ void View::set_capture_status() { bool triggered; int progress; - if (_session.get_capture_status(triggered, progress)) { + if (_session->get_capture_status(triggered, progress)) { _viewbottom->set_capture_status(triggered, progress); _viewbottom->update(); } diff --git a/DSView/pv/view/view.h b/DSView/pv/view/view.h index e059d461..306653d2 100755 --- a/DSView/pv/view/view.h +++ b/DSView/pv/view/view.h @@ -105,7 +105,7 @@ public: static const QColor LightRed; public: - explicit View(SigSession &session, pv::toolbars::SamplingBar *sampling_bar, QWidget *parent = 0); + explicit View(SigSession *session, pv::toolbars::SamplingBar *sampling_bar, QWidget *parent = 0); SigSession& session(); @@ -260,7 +260,7 @@ signals: void auto_trig(int index); -private: +private: void get_scroll_layout(int64_t &length, int64_t &offset) const; void update_scroll(); @@ -337,7 +337,7 @@ private slots: private: - SigSession &_session; + SigSession *_session; pv::toolbars::SamplingBar *_sampling_bar; QWidget *_viewcenter; diff --git a/DSView/pv/view/viewstatus.cpp b/DSView/pv/view/viewstatus.cpp index 83db6d83..739df933 100755 --- a/DSView/pv/view/viewstatus.cpp +++ b/DSView/pv/view/viewstatus.cpp @@ -40,7 +40,7 @@ using namespace std; namespace pv { namespace view { -ViewStatus::ViewStatus(SigSession &session, View &parent) : +ViewStatus::ViewStatus(SigSession *session, View &parent) : QWidget(&parent), _session(session), _view(parent), @@ -57,7 +57,7 @@ void ViewStatus::paintEvent(QPaintEvent *) style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); QColor fore(QWidget::palette().color(QWidget::foregroundRole())); - if (_session.get_device()->dev_inst()->mode == LOGIC) { + if (_session->get_device()->dev_inst()->mode == LOGIC) { fore.setAlpha(View::ForeAlpha); p.setPen(fore); p.drawText(this->rect(), Qt::AlignLeft | Qt::AlignVCenter, _rle_depth); @@ -66,16 +66,16 @@ void ViewStatus::paintEvent(QPaintEvent *) p.setPen(Qt::NoPen); p.setBrush(View::Blue); p.drawRect(this->rect().left(), this->rect().bottom() - 3, - _session.get_repeat_hold() * this->rect().width() / 100, 3); + _session->get_repeat_hold() * this->rect().width() / 100, 3); p.setPen(View::Blue); p.drawText(this->rect(), Qt::AlignCenter | Qt::AlignVCenter, _capture_status); - } else if (_session.get_device()->dev_inst()->mode == DSO) { + } else if (_session->get_device()->dev_inst()->mode == DSO) { fore.setAlpha(View::BackAlpha); for(size_t i = 0; i < _mrects.size(); i++) { int sig_index = std::get<1>(_mrects[i]); boost::shared_ptr dsoSig = NULL; - const vector< boost::shared_ptr > sigs(_session.get_signals()); + const vector< boost::shared_ptr > sigs(_session->get_signals()); BOOST_FOREACH(const boost::shared_ptr s, sigs) { assert(s); if (!s->enabled()) @@ -133,7 +133,7 @@ void ViewStatus::reload() const int COLUMN = 5; const int ROW = 2; const int MARGIN = 3; - if (_session.get_device()->dev_inst()->mode == DSO) + if (_session->get_device()->dev_inst()->mode == DSO) { const double width = _view.get_view_width() * 1.0 / COLUMN; const int height = (this->height() - 2*MARGIN) / ROW; @@ -184,7 +184,7 @@ void ViewStatus::mousePressEvent(QMouseEvent *event) { assert(event); - if (_session.get_device()->dev_inst()->mode != DSO) + if (_session->get_device()->dev_inst()->mode != DSO) return; if (event->button() == Qt::LeftButton) { @@ -233,7 +233,7 @@ QJsonArray ViewStatus::get_session() void ViewStatus::load_session(QJsonArray measure_array) { - if (_session.get_device()->dev_inst()->mode != DSO || + if (_session->get_device()->dev_inst()->mode != DSO || measure_array.empty()) return; diff --git a/DSView/pv/view/viewstatus.h b/DSView/pv/view/viewstatus.h index c4a006eb..56cfaa43 100755 --- a/DSView/pv/view/viewstatus.h +++ b/DSView/pv/view/viewstatus.h @@ -47,7 +47,7 @@ class ViewStatus : public QWidget Q_OBJECT public: - ViewStatus(SigSession &session, View &parent); + ViewStatus(SigSession *session, View &parent); public: @@ -71,7 +71,7 @@ public slots: void set_capture_status(bool triggered, int progess); private: - SigSession &_session; + SigSession *_session; View &_view; int _hit_rect; From c392bf72c1daeb8d7aa707e102604421b7afef50 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Tue, 2 Nov 2021 18:40:01 +0800 Subject: [PATCH 19/60] change boost thread as std lib, and boost mutex --- DSView/pv/appcontrol.cpp | 1 - DSView/pv/data/analog.cpp | 7 +- DSView/pv/data/analogsnapshot.cpp | 20 +- DSView/pv/data/analogsnapshot.h | 3 + DSView/pv/data/decode/annotation.h | 2 + DSView/pv/data/decode/row.cpp | 17 +- DSView/pv/data/decode/row.h | 14 +- DSView/pv/data/decode/rowdata.cpp | 78 +++--- DSView/pv/data/decode/rowdata.h | 35 +-- DSView/pv/data/decodermodel.cpp | 10 +- DSView/pv/data/decoderstack.cpp | 274 ++++++++++------------ DSView/pv/data/decoderstack.h | 78 +++--- DSView/pv/data/dso.cpp | 7 +- DSView/pv/data/dsosnapshot.cpp | 32 +-- DSView/pv/data/dsosnapshot.h | 6 +- DSView/pv/data/group.cpp | 7 +- DSView/pv/data/groupsnapshot.cpp | 27 +-- DSView/pv/data/groupsnapshot.h | 4 +- DSView/pv/data/logic.cpp | 8 +- DSView/pv/data/logicsnapshot.cpp | 20 +- DSView/pv/data/logicsnapshot.h | 9 +- DSView/pv/data/mathstack.cpp | 13 +- DSView/pv/data/mathstack.h | 2 +- DSView/pv/data/signaldata.h | 4 +- DSView/pv/data/snapshot.cpp | 10 +- DSView/pv/data/snapshot.h | 7 +- DSView/pv/data/spectrumstack.cpp | 8 +- DSView/pv/data/spectrumstack.h | 3 +- DSView/pv/device/sessionfile.cpp | 3 +- DSView/pv/devicemanager.cpp | 20 +- DSView/pv/devicemanager.h | 8 +- DSView/pv/dialogs/calibration.cpp | 4 +- DSView/pv/dialogs/deviceoptions.cpp | 13 +- DSView/pv/dialogs/dsomeasure.cpp | 8 +- DSView/pv/dialogs/fftoptions.cpp | 12 +- DSView/pv/dialogs/lissajousoptions.cpp | 9 +- DSView/pv/dialogs/mathoptions.cpp | 9 +- DSView/pv/dialogs/protocolexp.cpp | 6 +- DSView/pv/dialogs/protocollist.cpp | 12 +- DSView/pv/dialogs/regionoptions.cpp | 4 +- DSView/pv/dialogs/search.cpp | 10 +- DSView/pv/dialogs/waitingdialog.cpp | 8 +- DSView/pv/dock/dsotriggerdock.cpp | 5 +- DSView/pv/dock/protocoldock.cpp | 16 +- DSView/pv/dock/protocoldock.h | 6 +- DSView/pv/mainwindow.cpp | 36 +-- DSView/pv/prop/binding/binding.cpp | 10 +- DSView/pv/prop/binding/decoderoptions.cpp | 2 +- DSView/pv/sigsession.cpp | 135 +++++------ DSView/pv/sigsession.h | 22 +- DSView/pv/storesession.cpp | 70 +++--- DSView/pv/storesession.h | 10 +- DSView/pv/toolbars/filebar.cpp | 3 +- DSView/pv/toolbars/logobar.cpp | 2 +- DSView/pv/toolbars/samplingbar.cpp | 9 +- DSView/pv/toolbars/samplingbar.h | 2 +- DSView/pv/view/decodetrace.cpp | 75 +++--- DSView/pv/view/decodetrace.h | 3 +- DSView/pv/view/devmode.cpp | 3 +- DSView/pv/view/dsosignal.cpp | 2 +- DSView/pv/view/header.cpp | 21 +- DSView/pv/view/lissajoustrace.cpp | 2 +- DSView/pv/view/mathtrace.cpp | 3 +- DSView/pv/view/spectrumtrace.cpp | 5 +- DSView/pv/view/view.cpp | 41 ++-- DSView/pv/view/viewport.cpp | 50 ++-- DSView/pv/view/viewstatus.cpp | 6 +- DSView/pv/view/viewstatus.h | 2 +- DSView/pv/view/xcursor.cpp | 6 +- DSView/pv/widgets/decodergroupbox.cpp | 13 +- 70 files changed, 689 insertions(+), 703 deletions(-) diff --git a/DSView/pv/appcontrol.cpp b/DSView/pv/appcontrol.cpp index 9cf40035..6fa5f704 100644 --- a/DSView/pv/appcontrol.cpp +++ b/DSView/pv/appcontrol.cpp @@ -36,7 +36,6 @@ AppControl::AppControl() _device_manager = new pv::DeviceManager(); _session = new pv::SigSession(_device_manager); - _session->_appCntrol = this; } AppControl::AppControl(AppControl &o) diff --git a/DSView/pv/data/analog.cpp b/DSView/pv/data/analog.cpp index 6685e453..85046322 100755 --- a/DSView/pv/data/analog.cpp +++ b/DSView/pv/data/analog.cpp @@ -22,8 +22,7 @@ #include "analog.h" #include "analogsnapshot.h" - -#include + using namespace boost; using namespace std; @@ -49,13 +48,13 @@ deque< boost::shared_ptr >& Analog::get_snapshots() void Analog::clear() { //_snapshots.clear(); - BOOST_FOREACH(const boost::shared_ptr s, _snapshots) + for(auto &s : _snapshots) s->clear(); } void Analog::init() { //_snapshots.clear(); - BOOST_FOREACH(const boost::shared_ptr s, _snapshots) + for(auto &s : _snapshots) s->init(); } diff --git a/DSView/pv/data/analogsnapshot.cpp b/DSView/pv/data/analogsnapshot.cpp index 77b2e4bf..7da95a1a 100755 --- a/DSView/pv/data/analogsnapshot.cpp +++ b/DSView/pv/data/analogsnapshot.cpp @@ -28,12 +28,9 @@ #include #include - -#include - + #include "analogsnapshot.h" -using namespace boost; using namespace std; namespace pv { @@ -60,7 +57,7 @@ AnalogSnapshot::~AnalogSnapshot() void AnalogSnapshot::free_envelop() { for (unsigned int i = 0; i < _channel_num; i++) { - BOOST_FOREACH(Envelope &e, _envelope_levels[i]) { + for(auto &e : _envelope_levels[i]) { if (e.samples) free(e.samples); } @@ -70,7 +67,12 @@ void AnalogSnapshot::free_envelop() void AnalogSnapshot::init() { - boost::lock_guard lock(_mutex); + std::lock_guard lock(_mutex); + init_all(); +} + +void AnalogSnapshot::init_all() +{ _sample_count = 0; _ring_sample_count = 0; _memory_failed = false; @@ -88,10 +90,10 @@ void AnalogSnapshot::init() void AnalogSnapshot::clear() { - boost::lock_guard lock(_mutex); + std::lock_guard lock(_mutex); free_data(); free_envelop(); - init(); + init_all(); } void AnalogSnapshot::first_payload(const sr_datafeed_analog &analog, uint64_t total_sample_count, GSList *channels) @@ -167,7 +169,7 @@ void AnalogSnapshot::first_payload(const sr_datafeed_analog &analog, uint64_t to void AnalogSnapshot::append_payload( const sr_datafeed_analog &analog) { - boost::lock_guard lock(_mutex); + std::lock_guard lock(_mutex); append_data(analog.data, analog.num_samples, analog.unit_pitch); // Generate the first mip-map from the data diff --git a/DSView/pv/data/analogsnapshot.h b/DSView/pv/data/analogsnapshot.h index 644dbfaa..0d6c1473 100755 --- a/DSView/pv/data/analogsnapshot.h +++ b/DSView/pv/data/analogsnapshot.h @@ -79,6 +79,9 @@ private: static const uint64_t LeafBlockSamples = 1 << LeafBlockPower; static const uint64_t LeafMask = ~(~0ULL << LeafBlockPower); +private: + void init_all(); + public: AnalogSnapshot(); diff --git a/DSView/pv/data/decode/annotation.h b/DSView/pv/data/decode/annotation.h index d45d0e5b..46d3e2eb 100755 --- a/DSView/pv/data/decode/annotation.h +++ b/DSView/pv/data/decode/annotation.h @@ -25,6 +25,7 @@ #include #include +#include class AnnotationResTable; class DecoderStatus; @@ -35,6 +36,7 @@ namespace pv { namespace data { namespace decode { +//create at DecoderStack.annotation_callback class Annotation { public: diff --git a/DSView/pv/data/decode/row.cpp b/DSView/pv/data/decode/row.cpp index 99958900..63fef7c3 100755 --- a/DSView/pv/data/decode/row.cpp +++ b/DSView/pv/data/decode/row.cpp @@ -38,22 +38,7 @@ Row::Row(const srd_decoder *decoder, const srd_decoder_annotation_row *row, cons _row(row), _order(order) { -} - -Row::~Row() -{ - -} - -const srd_decoder* Row::decoder() const -{ - return _decoder; -} - -const srd_decoder_annotation_row* Row::row() const -{ - return _row; -} +} const QString Row::title() const { diff --git a/DSView/pv/data/decode/row.h b/DSView/pv/data/decode/row.h index d6fa4ac6..b21f8093 100755 --- a/DSView/pv/data/decode/row.h +++ b/DSView/pv/data/decode/row.h @@ -32,6 +32,7 @@ namespace pv { namespace data { namespace decode { +//map find key data class Row { public: @@ -41,12 +42,15 @@ public: const srd_decoder_annotation_row *row = NULL, const int order = -1); -public: - - ~Row(); +public: - const srd_decoder* decoder() const; - const srd_decoder_annotation_row* row() const; + inline const srd_decoder* decoder() const{ + return _decoder; + } + + inline const srd_decoder_annotation_row* row() const{ + return _row; + } const QString title() const; diff --git a/DSView/pv/data/decode/rowdata.cpp b/DSView/pv/data/decode/rowdata.cpp index c80cbfbd..9ac049e9 100755 --- a/DSView/pv/data/decode/rowdata.cpp +++ b/DSView/pv/data/decode/rowdata.cpp @@ -31,10 +31,13 @@ namespace pv { namespace data { namespace decode { +std::mutex RowData::_global_visitor_mutex; + RowData::RowData() : _max_annotation(0), _min_annotation(UINT64_MAX) { + _item_count = 0; } RowData::~RowData() @@ -44,14 +47,23 @@ RowData::~RowData() void RowData::clear() { + std::lock_guard lock(_global_visitor_mutex); + + //destroy objercts + for (Annotation *p : _annotations){ + delete p; + } _annotations.clear(); + _item_count = 0; } uint64_t RowData::get_max_sample() const { + std::lock_guard lock(_global_visitor_mutex); + if (_annotations.empty()) return 0; - return _annotations.back().end_sample(); + return _annotations.back()->end_sample(); } uint64_t RowData::get_max_annotation() const @@ -67,52 +79,64 @@ uint64_t RowData::get_min_annotation() const return _min_annotation; } -void RowData::get_annotation_subset( - vector &dest, - uint64_t start_sample, uint64_t end_sample) const -{ - for (vector::const_iterator i = _annotations.begin(); - i != _annotations.end(); i++) - if ((*i).end_sample() > start_sample && - (*i).start_sample() <= end_sample) - dest.push_back(*i); +void RowData::get_annotation_subset(std::vector &dest, + uint64_t start_sample, uint64_t end_sample) const +{ + std::lock_guard lock(_global_visitor_mutex); + + for (Annotation *p : _annotations){ + if (p->end_sample() > start_sample && + p->start_sample() <= end_sample){ + Annotation a = *p; + dest.push_back(a); + } + } } uint64_t RowData::get_annotation_index(uint64_t start_sample) const { + std::lock_guard lock(_global_visitor_mutex); uint64_t index = 0; - for (vector::const_iterator i = _annotations.begin(); - i != _annotations.end(); i++) { - if ((*i).start_sample() > start_sample) - break; - index++; - } + + for (Annotation *p : _annotations){ + if (p->start_sample() > start_sample) + break; + index++; + } + return index; } -bool RowData::push_annotation(const Annotation &a) +bool RowData::push_annotation(Annotation *a) { + if (a == NULL){ + return false; + } + + std::lock_guard lock(_global_visitor_mutex); + try { _annotations.push_back(a); - _max_annotation = max(_max_annotation, a.end_sample() - a.start_sample()); - if (a.end_sample() != a.start_sample()) - _min_annotation = min(_min_annotation, a.end_sample() - a.start_sample()); + _item_count = _annotations.size(); + _max_annotation = max(_max_annotation, a->end_sample() - a->start_sample()); + + if (a->end_sample() != a->start_sample()) + _min_annotation = min(_min_annotation, a->end_sample() - a->start_sample()); + return true; + } catch (const std::bad_alloc&) { return false; } } + -uint64_t RowData::get_annotation_size() const +bool RowData::get_annotation(Annotation &ann, uint64_t index) const { - return _annotations.size(); -} + std::lock_guard lock(_global_visitor_mutex); -bool RowData::get_annotation(Annotation &ann, - uint64_t index) const -{ if (index < _annotations.size()) { - ann = _annotations[index]; + ann = *_annotations[index]; return true; } else { return false; diff --git a/DSView/pv/data/decode/rowdata.h b/DSView/pv/data/decode/rowdata.h index 72d33456..0059567f 100755 --- a/DSView/pv/data/decode/rowdata.h +++ b/DSView/pv/data/decode/rowdata.h @@ -22,7 +22,8 @@ #ifndef DSVIEW_PV_DATA_DECODE_ROWDATA_H #define DSVIEW_PV_DATA_DECODE_ROWDATA_H -#include +#include +#include #include "annotation.h" @@ -35,33 +36,37 @@ class RowData public: RowData(); ~RowData(); + public: uint64_t get_max_sample() const; uint64_t get_max_annotation() const; - uint64_t get_min_annotation() const; - /** - * Extracts sorted annotations between two period into a vector. - */ - void get_annotation_subset( - std::vector &dest, - uint64_t start_sample, uint64_t end_sample) const; + uint64_t get_min_annotation() const; uint64_t get_annotation_index(uint64_t start_sample) const; - bool push_annotation(const Annotation &a); + bool push_annotation(Annotation *a); - uint64_t get_annotation_size() const; + inline uint64_t get_annotation_size() const{ + return _item_count; + } - bool get_annotation(pv::data::decode::Annotation &ann, - uint64_t index) const; + bool get_annotation(pv::data::decode::Annotation &ann, uint64_t index) const; + + /** + * Extracts sorted annotations between two period into a vector. + */ + void get_annotation_subset(std::vector &dest, + uint64_t start_sample, uint64_t end_sample) const; void clear(); private: - uint64_t _max_annotation; - uint64_t _min_annotation; - std::vector _annotations; + uint64_t _max_annotation; + uint64_t _min_annotation; + uint64_t _item_count; + std::vector _annotations; + static std::mutex _global_visitor_mutex; }; } diff --git a/DSView/pv/data/decodermodel.cpp b/DSView/pv/data/decodermodel.cpp index 614f67ff..c42bab6a 100755 --- a/DSView/pv/data/decodermodel.cpp +++ b/DSView/pv/data/decodermodel.cpp @@ -19,13 +19,9 @@ */ #include - -#include -#include - -#include -#include - + +#include "decode/annotation.h" +#include "decode/rowdata.h" #include "decoderstack.h" #include "decodermodel.h" diff --git a/DSView/pv/data/decoderstack.cpp b/DSView/pv/data/decoderstack.cpp index c9bbd504..72d094ce 100755 --- a/DSView/pv/data/decoderstack.cpp +++ b/DSView/pv/data/decoderstack.cpp @@ -18,9 +18,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include -#include + #include #include @@ -29,12 +27,15 @@ #include "decoderstack.h" -#include -#include -#include -#include -#include -#include +#include "logic.h" +#include "logicsnapshot.h" +#include "decode/decoder.h" +#include "decode/annotation.h" +#include "decode/rowdata.h" +#include "../sigsession.h" +#include "../view/logicsignal.h" +#include "../dsvdef.h" + using namespace boost; using namespace std; @@ -50,19 +51,23 @@ const int64_t DecoderStack::DecodeChunkLength = 4 * 1024; //const int64_t DecoderStack::DecodeChunkLength = 1024 * 1024; const unsigned int DecoderStack::DecodeNotifyPeriod = 1024; -boost::mutex DecoderStack::_global_decode_mutex; +std::mutex DecoderStack::_global_decode_mutex; DecoderStack::DecoderStack(pv::SigSession *session, const srd_decoder *const dec, DecoderStatus *decoder_status) : - _session(session), - _sample_count(0), - _frame_complete(false), - _samples_decoded(0), - _decode_state(Stopped), - _options_changed(false), - _no_memory(false), - _mark_index(-1) + _session(session) { + _samples_decoded = 0; + _sample_count = 0; + _frame_complete = false; + _decode_state = Stopped; + _options_changed = false; + _no_memory = false; + _mark_index = -1; + _decoder_status = decoder_status; + _bThreadStop = false; + _decode_thread = NULL; + connect(_session, SIGNAL(frame_began()), this, SLOT(on_new_frame())); connect(_session, SIGNAL(data_received()), @@ -72,32 +77,26 @@ DecoderStack::DecoderStack(pv::SigSession *session, _stack.push_back(boost::shared_ptr( new decode::Decoder(dec))); - - _decoder_status = decoder_status; - + build_row(); } DecoderStack::~DecoderStack() -{ -// if (_decode_thread.joinable()) { -// _decode_thread.interrupt(); -// _decode_thread.join(); -// } +{ stop_decode(); - _stack.clear(); + + for (auto &kv : _rows) + { + delete kv.second; + } _rows.clear(); + + _stack.clear(); _rows_gshow.clear(); _rows_lshow.clear(); _class_rows.clear(); } - -const std::list< boost::shared_ptr >& -DecoderStack::stack() const -{ - return _stack; -} - + void DecoderStack::push(boost::shared_ptr decoder) { assert(decoder); @@ -124,9 +123,15 @@ void DecoderStack::remove(boost::shared_ptr &decoder) void DecoderStack::build_row() { + //destory data + for (auto &kv : _rows) + { + delete kv.second; + } _rows.clear(); + // Add classes - BOOST_FOREACH (const boost::shared_ptr &dec, _stack) + for (auto &dec : _stack) { assert(dec); const srd_decoder *const decc = dec->decoder(); @@ -135,7 +140,7 @@ void DecoderStack::build_row() // Add a row for the decoder if it doesn't have a row list if (!decc->annotation_rows) { const Row row(decc); - _rows[row] = decode::RowData(); + _rows[row] = new decode::RowData(); std::map::const_iterator iter = _rows_gshow.find(row); if (iter == _rows_gshow.end()) { _rows_gshow[row] = true; @@ -159,7 +164,7 @@ void DecoderStack::build_row() const Row row(decc, ann_row, order); // Add a new empty row data object - _rows[row] = decode::RowData(); + _rows[row] = new decode::RowData(); std::map::const_iterator iter = _rows_gshow.find(row); if (iter == _rows_gshow.end()) { _rows_gshow[row] = true; @@ -184,7 +189,7 @@ void DecoderStack::build_row() int64_t DecoderStack::samples_decoded() const { - boost::lock_guard decode_lock(_output_mutex); + std::lock_guard decode_lock(_output_mutex); return _samples_decoded; } @@ -192,51 +197,39 @@ void DecoderStack::get_annotation_subset( std::vector &dest, const Row &row, uint64_t start_sample, uint64_t end_sample) const -{ - //lock_guard lock(_output_mutex); - - std::map::const_iterator iter = - _rows.find(row); +{ + auto iter = _rows.find(row); if (iter != _rows.end()) - (*iter).second.get_annotation_subset(dest, + (*iter).second->get_annotation_subset(dest, start_sample, end_sample); } uint64_t DecoderStack::get_annotation_index( const Row &row, uint64_t start_sample) const -{ - //lock_guard lock(_output_mutex); - +{ uint64_t index = 0; - std::map::const_iterator iter = - _rows.find(row); + auto iter = _rows.find(row); if (iter != _rows.end()) - index = (*iter).second.get_annotation_index(start_sample); + index = (*iter).second->get_annotation_index(start_sample); return index; } uint64_t DecoderStack::get_max_annotation(const Row &row) -{ - //lock_guard lock(_output_mutex); - - std::map::const_iterator iter = - _rows.find(row); +{ + auto iter = _rows.find(row); if (iter != _rows.end()) - return (*iter).second.get_max_annotation(); + return (*iter).second->get_max_annotation(); return 0; } uint64_t DecoderStack::get_min_annotation(const Row &row) -{ - //lock_guard lock(_output_mutex); - - std::map::const_iterator iter = - _rows.find(row); +{ + auto iter = _rows.find(row); if (iter != _rows.end()) - return (*iter).second.get_min_annotation(); + return (*iter).second->get_min_annotation(); return 0; } @@ -278,13 +271,11 @@ void DecoderStack::set_rows_lshow(const decode::Row row, bool show) } bool DecoderStack::has_annotations(const Row &row) const -{ - //lock_guard lock(_output_mutex); - - std::map::const_iterator iter = +{ + auto iter = _rows.find(row); if (iter != _rows.end()) - if(0 == (*iter).second.get_max_sample()) + if(0 == (*iter).second->get_max_sample()) return false; else return true; @@ -294,29 +285,27 @@ bool DecoderStack::has_annotations(const Row &row) const uint64_t DecoderStack::list_annotation_size() const { - boost::lock_guard lock(_output_mutex); + std::lock_guard lock(_output_mutex); uint64_t max_annotation_size = 0; - for (map::const_iterator i = _rows.begin(); + for (auto i = _rows.begin(); i != _rows.end(); i++) { map::const_iterator iter = _rows_lshow.find((*i).first); if (iter != _rows_lshow.end() && (*iter).second) max_annotation_size = max(max_annotation_size, - (*i).second.get_annotation_size()); + (*i).second->get_annotation_size()); } return max_annotation_size; } uint64_t DecoderStack::list_annotation_size(uint16_t row_index) const -{ - //lock_guard lock(_output_mutex); - //int row = 0; - for (map::const_iterator i = _rows.begin(); +{ + for (auto i = _rows.begin(); i != _rows.end(); i++) { map::const_iterator iter = _rows_lshow.find((*i).first); if (iter != _rows_lshow.end() && (*iter).second) if (row_index-- == 0) { - return (*i).second.get_annotation_size(); + return (*i).second->get_annotation_size(); } } return 0; @@ -324,14 +313,13 @@ uint64_t DecoderStack::list_annotation_size(uint16_t row_index) const bool DecoderStack::list_annotation(pv::data::decode::Annotation &ann, uint16_t row_index, uint64_t col_index) const -{ - //lock_guard lock(_output_mutex); - for (map::const_iterator i = _rows.begin(); +{ + for (auto i = _rows.begin(); i != _rows.end(); i++) { map::const_iterator iter = _rows_lshow.find((*i).first); if (iter != _rows_lshow.end() && (*iter).second) { if (row_index-- == 0) { - return (*i).second.get_annotation(ann, col_index); + return (*i).second->get_annotation(ann, col_index); } } } @@ -341,9 +329,8 @@ bool DecoderStack::list_annotation(pv::data::decode::Annotation &ann, bool DecoderStack::list_row_title(int row, QString &title) const -{ - //lock_guard lock(_output_mutex); - for (map::const_iterator i = _rows.begin(); +{ + for (auto i = _rows.begin(); i != _rows.end(); i++) { map::const_iterator iter = _rows_lshow.find((*i).first); if (iter != _rows_lshow.end() && (*iter).second) { @@ -357,8 +344,7 @@ bool DecoderStack::list_row_title(int row, QString &title) const } QString DecoderStack::error_message() -{ - //lock_guard lock(_output_mutex); +{ return _error_message; } @@ -374,24 +360,26 @@ void DecoderStack::init() _samples_decoded = 0; _error_message = QString(); _no_memory = false; - for (map::iterator i = _rows.begin(); - i != _rows.end(); i++) { - //_rows[(*i).first] = decode::RowData(); - (*i).second.clear(); + + for (auto i = _rows.begin(); + i != _rows.end(); i++) { + (*i).second->clear(); } + set_mark_index(-1); } void DecoderStack::stop_decode() -{ - //_snapshot.reset(); - if(_decode_state != Stopped) { - if (_decode_thread.get()) { - _decode_thread->interrupt(); - _decode_thread->join(); - _decode_state = Stopped; - } - _decode_thread.reset(); +{ + _bThreadStop = true; + + if (_decode_thread && _decode_thread->joinable()) { + _decode_thread->join(); + } + DESTROY_OBJECT(_decode_thread); + + if(_decode_state != Stopped) { + _decode_state = Stopped; } } @@ -407,7 +395,7 @@ void DecoderStack::begin_decode() init(); // Check that all decoders have the required channels - BOOST_FOREACH(const boost::shared_ptr &dec, _stack) + for(auto &dec : _stack) if (!dec->have_required_probes()) { _error_message = tr("One or more required channels " "have not been specified"); @@ -417,9 +405,9 @@ void DecoderStack::begin_decode() // We get the logic data of the first channel in the list. // This works because we are currently assuming all // LogicSignals have the same data/snapshot - BOOST_FOREACH (const boost::shared_ptr &dec, _stack) { + for (auto &dec : _stack) { if (dec && !dec->channels().empty()) { - BOOST_FOREACH(boost::shared_ptr sig, _session->get_signals()) { + for(auto &sig : _session->get_signals()) { if((sig->get_index() == (*dec->channels().begin()).second) && (logic_signal = dynamic_pointer_cast(sig)) && (data = logic_signal->logic_data())) @@ -447,18 +435,23 @@ void DecoderStack::begin_decode() if (_samplerate == 0.0) return; - //_decode_thread = boost::thread(&DecoderStack::decode_proc, this); - _decode_thread.reset(new boost::thread(&DecoderStack::decode_proc, this)); + if (_decode_thread && _decode_thread->joinable()) { + _bThreadStop = true; + _decode_thread->join(); + } + DESTROY_OBJECT(_decode_thread); + + _bThreadStop = false; //reset stop flag + _decode_thread = new std::thread(&DecoderStack::decode_proc, this); } uint64_t DecoderStack::get_max_sample_count() const { uint64_t max_sample_count = 0; - for (map::const_iterator i = _rows.begin(); - i != _rows.end(); i++) - max_sample_count = max(max_sample_count, - (*i).second.get_max_sample()); + for (auto i = _rows.begin(); i != _rows.end(); i++){ + max_sample_count = max(max_sample_count, (*i).second->get_max_sample()); + } return max_sample_count; } @@ -485,13 +478,13 @@ void DecoderStack::decode_data( uint64_t entry_cnt = 0; uint64_t i = decode_start; char *error = NULL; - while(!boost::this_thread::interruption_requested() && - i < decode_end && !_no_memory) - { - //lock_guard decode_lock(_global_decode_mutex); + + while(!_bThreadStop && i < decode_end && !_no_memory) + { std::vector chunk; std::vector chunk_const; uint64_t chunk_end = decode_end; + for (int j =0 ; j < logic_di->dec_num_channels; j++) { int sig_index = logic_di->dec_channelmap[j]; if (sig_index == -1) { @@ -520,7 +513,7 @@ void DecoderStack::decode_data( i = chunk_end; { - boost::lock_guard lock(_output_mutex); + std::lock_guard lock(_output_mutex); _samples_decoded = i - decode_start + 1; } @@ -536,8 +529,12 @@ void DecoderStack::decode_data( } void DecoderStack::decode_proc() -{ - boost::lock_guard decode_lock(_global_decode_mutex); +{ + std::lock_guard decode_lock(_global_decode_mutex); + + if (_bThreadStop){ + return; + } optional sample_count; srd_session *session; @@ -554,13 +551,10 @@ void DecoderStack::decode_proc() _decode_state = Running; // Get the intial sample count - { - //unique_lock input_lock(_input_mutex); - sample_count = _sample_count = _snapshot->get_sample_count(); - } + sample_count = _sample_count = _snapshot->get_sample_count(); // Create the decoders - BOOST_FOREACH(const boost::shared_ptr &dec, _stack) + for(auto &dec : _stack) { srd_decoder_inst *const di = dec->create_decoder_inst(session); @@ -588,6 +582,7 @@ void DecoderStack::decode_proc() char *error = NULL; if (srd_session_start(session, &error) == SRD_OK) + //need a lot time decode_data(decode_start, decode_end, session); else _error_message = QString::fromLocal8Bit(error); @@ -622,14 +617,16 @@ void DecoderStack::annotation_callback(srd_proto_data *pdata, void *decoder) DecoderStack *const d = (DecoderStack*)decoder; assert(d); - - //lock_guard lock(d->_output_mutex); - + if (d->_no_memory) { return; } - const Annotation a(pdata, d->_decoder_status); + Annotation *a = new Annotation(pdata, d->_decoder_status); + if (a == NULL){ + d->_no_memory = true; + return; + } // Find the row assert(pdata->pdo); @@ -637,11 +634,11 @@ void DecoderStack::annotation_callback(srd_proto_data *pdata, void *decoder) const srd_decoder *const decc = pdata->pdo->di->decoder; assert(decc); - map::iterator row_iter = d->_rows.end(); + auto row_iter = d->_rows.end(); // Try looking up the sub-row of this class const map, Row>::const_iterator r = - d->_class_rows.find(make_pair(decc, a.format())); + d->_class_rows.find(make_pair(decc, a->format())); if (r != d->_class_rows.end()) row_iter = d->_rows.find((*r).second); else @@ -653,14 +650,13 @@ void DecoderStack::annotation_callback(srd_proto_data *pdata, void *decoder) assert(row_iter != d->_rows.end()); if (row_iter == d->_rows.end()) { qDebug() << "Unexpected annotation: decoder = " << decc << - ", format = " << a.format(); + ", format = " << a->format(); assert(0); return; } - // Add the annotation - boost::lock_guard lock(d->_output_mutex); - if (!(*row_iter).second.push_annotation(a)) + // Add the annotation + if (!(*row_iter).second->push_annotation(a)) d->_no_memory = true; } @@ -670,33 +666,19 @@ void DecoderStack::on_new_frame() } void DecoderStack::on_data_received() -{ -// { -// unique_lock lock(_input_mutex); -// if (_snapshot) -// _sample_count = _snapshot->get_sample_count(); -// } -// _input_cond.notify_one(); +{ } void DecoderStack::on_frame_ended() -{ -// { -// unique_lock lock(_input_mutex); -// if (_snapshot) -// _frame_complete = true; -// } -// _input_cond.notify_one(); +{ _options_changed = true; begin_decode(); } int DecoderStack::list_rows_size() -{ - //lock_guard lock(_output_mutex); +{ int rows_size = 0; - for (map::const_iterator i = _rows.begin(); - i != _rows.end(); i++) { + for (auto i = _rows.begin(); i != _rows.end(); i++) { map::const_iterator iter = _rows_lshow.find((*i).first); if (iter != _rows_lshow.end() && (*iter).second) rows_size++; diff --git a/DSView/pv/data/decoderstack.h b/DSView/pv/data/decoderstack.h index bc05fa6b..d7f89bf1 100755 --- a/DSView/pv/data/decoderstack.h +++ b/DSView/pv/data/decoderstack.h @@ -27,13 +27,14 @@ #include #include -#include + #include #include +#include +#include -#include "../data/decode/row.h" -#include "../data/decode/rowdata.h" +#include "decode/row.h" #include "../data/signaldata.h" class DecoderStatus; @@ -57,6 +58,7 @@ class LogicSnapshot; namespace decode { class Annotation; class Decoder; +class RowData; } class Logic; @@ -86,9 +88,14 @@ public: virtual ~DecoderStack(); - const std::list< boost::shared_ptr >& stack() const; + inline std::list< boost::shared_ptr >& stack(){ + return _stack; + } + void push(boost::shared_ptr decoder); + void remove(boost::shared_ptr& decoder); + void build_row(); int64_t samples_decoded() const; @@ -153,8 +160,7 @@ private: void decode_proc(); - static void annotation_callback(srd_proto_data *pdata, - void *decoder); + static void annotation_callback(srd_proto_data *pdata, void *decoder); private slots: void on_new_frame(); @@ -167,45 +173,39 @@ signals: void new_decode_data(); void decode_done(); -private: - pv::SigSession *_session; +private: + std::list< boost::shared_ptr > _stack; + + boost::shared_ptr _snapshot; + + std::map _rows; + std::map _rows_gshow; + std::map _rows_lshow; + std::map, decode::Row> _class_rows; + + SigSession *_session; + decode_state _decode_state; + bool _options_changed; + bool _no_memory; + int64_t _mark_index; + DecoderStatus *_decoder_status; + QString _error_message; + int64_t _samples_decoded; + uint64_t _sample_count; + bool _frame_complete; + volatile bool _bThreadStop; + + + std::thread *_decode_thread; + mutable std::mutex _output_mutex; /** * This mutex prevents more than one decode operation occuring * concurrently. * @todo A proper solution should be implemented to allow multiple * decode operations. - */ - static boost::mutex _global_decode_mutex; - - std::list< boost::shared_ptr > _stack; - - boost::shared_ptr _snapshot; - - //mutable boost::mutex _input_mutex; - //mutable boost::condition_variable _input_cond; - uint64_t _sample_count; - bool _frame_complete; - - mutable boost::recursive_mutex _output_mutex; - //mutable boost::mutex _output_mutex; - int64_t _samples_decoded; - - std::map _rows; - std::map _rows_gshow; - std::map _rows_lshow; - std::map, decode::Row> _class_rows; - - QString _error_message; - - std::unique_ptr _decode_thread; - decode_state _decode_state; - - bool _options_changed; - bool _no_memory; - - int64_t _mark_index; - DecoderStatus *_decoder_status; + */ + static std::mutex _global_decode_mutex; friend class DecoderStackTest::TwoDecoderStack; }; diff --git a/DSView/pv/data/dso.cpp b/DSView/pv/data/dso.cpp index 7362010f..b88e77d7 100755 --- a/DSView/pv/data/dso.cpp +++ b/DSView/pv/data/dso.cpp @@ -21,8 +21,7 @@ #include "dso.h" #include "dsosnapshot.h" - -#include + using namespace boost; using namespace std; @@ -48,14 +47,14 @@ deque< boost::shared_ptr >& Dso::get_snapshots() void Dso::clear() { //_snapshots.clear(); - BOOST_FOREACH(const boost::shared_ptr s, _snapshots) + for(auto &s : _snapshots) s->clear(); } void Dso::init() { //_snapshots.clear(); - BOOST_FOREACH(const boost::shared_ptr s, _snapshots) + for(auto &s : _snapshots) s->init(); } diff --git a/DSView/pv/data/dsosnapshot.cpp b/DSView/pv/data/dsosnapshot.cpp index 89da7800..60a98a8c 100755 --- a/DSView/pv/data/dsosnapshot.cpp +++ b/DSView/pv/data/dsosnapshot.cpp @@ -27,12 +27,9 @@ #include #include - -#include - + #include "dsosnapshot.h" -using namespace boost; using namespace std; namespace pv { @@ -63,7 +60,7 @@ DsoSnapshot::~DsoSnapshot() void DsoSnapshot::free_envelop() { for (unsigned int i = 0; i < _channel_num; i++) { - BOOST_FOREACH(Envelope &e, _envelope_levels[i]) { + for(auto &e : _envelope_levels[i]) { if (e.samples) free(e.samples); } @@ -73,13 +70,19 @@ void DsoSnapshot::free_envelop() void DsoSnapshot::init() { - boost::lock_guard lock(_mutex); + std::lock_guard lock(_mutex); + init_all(); +} + +void DsoSnapshot::init_all() +{ _sample_count = 0; _ring_sample_count = 0; _memory_failed = false; _last_ended = true; _envelope_done = false; _ch_enable.clear(); + for (unsigned int i = 0; i < _channel_num; i++) { for (unsigned int level = 0; level < ScaleStepCount; level++) { _envelope_levels[i][level].length = 0; @@ -90,10 +93,10 @@ void DsoSnapshot::init() void DsoSnapshot::clear() { - boost::lock_guard lock(_mutex); + std::lock_guard lock(_mutex); free_data(); free_envelop(); - init(); + init_all(); } void DsoSnapshot::first_payload(const sr_datafeed_dso &dso, uint64_t total_sample_count, @@ -157,7 +160,7 @@ void DsoSnapshot::first_payload(const sr_datafeed_dso &dso, uint64_t total_sampl void DsoSnapshot::append_payload(const sr_datafeed_dso &dso) { - boost::lock_guard lock(_mutex); + std::lock_guard lock(_mutex); if (_channel_num > 0 && dso.num_samples != 0) { append_data(dso.data, dso.num_samples, _instant); @@ -184,16 +187,16 @@ void DsoSnapshot::append_data(void *data, uint64_t samples, bool instant) void DsoSnapshot::enable_envelope(bool enable) { - boost::lock_guard lock(_mutex); + std::lock_guard lock(_mutex); if (!_envelope_done && enable) append_payload_to_envelope_levels(true); _envelope_en = enable; } const uint8_t *DsoSnapshot::get_samples( - int64_t start_sample, int64_t end_sample, uint16_t index) const + int64_t start_sample, int64_t end_sample, uint16_t index) { - boost::lock_guard lock(_mutex); + std::lock_guard lock(_mutex); (void)end_sample; assert(start_sample >= 0); @@ -202,10 +205,7 @@ const uint8_t *DsoSnapshot::get_samples( assert(end_sample < (int64_t)get_sample_count()); assert(start_sample <= end_sample); -// uint16_t *const data = new uint16_t[end_sample - start_sample]; -// memcpy(data, (uint16_t*)_data + start_sample, sizeof(uint16_t) * -// (end_sample - start_sample)); -// return data; + return (uint8_t*)_data + start_sample * _channel_num + index * (_channel_num != 1); } diff --git a/DSView/pv/data/dsosnapshot.h b/DSView/pv/data/dsosnapshot.h index aa19cca5..f9586efe 100755 --- a/DSView/pv/data/dsosnapshot.h +++ b/DSView/pv/data/dsosnapshot.h @@ -25,6 +25,7 @@ #include #include +#include #include #include "snapshot.h" @@ -74,6 +75,9 @@ private: static const int VrmsScaleFactor; +private: + void init_all(); + public: DsoSnapshot(); @@ -88,7 +92,7 @@ public: void append_payload(const sr_datafeed_dso &dso); const uint8_t* get_samples(int64_t start_sample, - int64_t end_sample, uint16_t index) const; + int64_t end_sample, uint16_t index); void get_envelope_section(EnvelopeSection &s, uint64_t start, uint64_t end, float min_length, int probe_index) const; diff --git a/DSView/pv/data/group.cpp b/DSView/pv/data/group.cpp index a9ee2cbe..41329f82 100755 --- a/DSView/pv/data/group.cpp +++ b/DSView/pv/data/group.cpp @@ -21,8 +21,7 @@ #include "group.h" #include "groupsnapshot.h" - -#include + using namespace boost; using namespace std; @@ -47,13 +46,13 @@ deque< boost::shared_ptr >& Group::get_snapshots() void Group::clear() { - BOOST_FOREACH(const boost::shared_ptr s, _snapshots) + for(auto &s : _snapshots) s->clear(); } void Group::init() { - BOOST_FOREACH(const boost::shared_ptr s, _snapshots) + for(auto &s : _snapshots) s->init(); } diff --git a/DSView/pv/data/groupsnapshot.cpp b/DSView/pv/data/groupsnapshot.cpp index ae6b6cb3..3c5f25ee 100755 --- a/DSView/pv/data/groupsnapshot.cpp +++ b/DSView/pv/data/groupsnapshot.cpp @@ -27,8 +27,7 @@ #include #include - -#include + #include "logicsnapshot.h" #include "groupsnapshot.h" @@ -53,7 +52,7 @@ GroupSnapshot::GroupSnapshot(const boost::shared_ptr &_logic_snap { assert(_logic_snapshot); - //boost::lock_guard lock(_mutex); + memset(_envelope_levels, 0, sizeof(_envelope_levels)); _data = _logic_snapshot->get_data(); _sample_count = _logic_snapshot->get_sample_count(); @@ -94,9 +93,8 @@ GroupSnapshot::GroupSnapshot(const boost::shared_ptr &_logic_snap } GroupSnapshot::~GroupSnapshot() -{ - //boost::lock_guard lock(_mutex); - BOOST_FOREACH(Envelope &e, _envelope_levels) +{ + for(auto &e : _envelope_levels) free(e.samples); } @@ -111,16 +109,13 @@ void GroupSnapshot::clear() } uint64_t GroupSnapshot::get_sample_count() const -{ - //boost::lock_guard lock(_mutex); +{ return _sample_count; } void GroupSnapshot::append_payload() { - //boost::lock_guard lock(_mutex); - - // Generate the first mip-map from the data + append_payload_to_envelope_levels(); } @@ -134,13 +129,10 @@ const uint16_t* GroupSnapshot::get_samples( assert(start_sample <= end_sample); int64_t i; - uint16_t tmpl, tmpr; - //boost::lock_guard lock(_mutex); + uint16_t tmpl, tmpr; uint16_t *const data = new uint16_t[end_sample - start_sample]; -// memcpy(data, (uint16_t*)_data + start_sample, sizeof(uint16_t) * -// (end_sample - start_sample)); -// memset(data, 0, sizeof(uint16_t) * (end_sample - start_sample)); + for(i = start_sample; i < end_sample; i++) { if (_unit_size == 2) tmpl = *((uint16_t*)_data + i) & _mask; @@ -163,8 +155,7 @@ void GroupSnapshot::get_envelope_section(EnvelopeSection &s, assert(end <= _sample_count); assert(start <= end); assert(min_length > 0); - - //boost::lock_guard lock(_mutex); + const unsigned int min_level = max((int)floorf(logf(min_length) / LogEnvelopeScaleFactor) - 1, 0); diff --git a/DSView/pv/data/groupsnapshot.h b/DSView/pv/data/groupsnapshot.h index 4d87b001..fbd7095e 100755 --- a/DSView/pv/data/groupsnapshot.h +++ b/DSView/pv/data/groupsnapshot.h @@ -23,7 +23,7 @@ #ifndef DSVIEW_PV_DATA_GROUPSNAPSHOT_H #define DSVIEW_PV_DATA_GROUPSNAPSHOT_H -#include + #include #include "../view/signal.h" @@ -99,7 +99,7 @@ private: private: struct Envelope _envelope_levels[ScaleStepCount]; - //mutable boost::recursive_mutex _mutex; + const void *_data; uint64_t _sample_count; int _unit_size; diff --git a/DSView/pv/data/logic.cpp b/DSView/pv/data/logic.cpp index 9797b214..d2597125 100755 --- a/DSView/pv/data/logic.cpp +++ b/DSView/pv/data/logic.cpp @@ -22,9 +22,7 @@ #include "logic.h" #include "logicsnapshot.h" - -#include - + using namespace boost; using namespace std; @@ -50,14 +48,14 @@ deque< boost::shared_ptr >& Logic::get_snapshots() void Logic::clear() { //_snapshots.clear(); - BOOST_FOREACH(const boost::shared_ptr s, _snapshots) + for(auto &s : _snapshots) s->clear(); } void Logic::init() { //_snapshots.clear(); - BOOST_FOREACH(const boost::shared_ptr s, _snapshots) + for(auto &s : _snapshots) s->init(); } diff --git a/DSView/pv/data/logicsnapshot.cpp b/DSView/pv/data/logicsnapshot.cpp index 2dd3027e..025422ba 100755 --- a/DSView/pv/data/logicsnapshot.cpp +++ b/DSView/pv/data/logicsnapshot.cpp @@ -28,12 +28,9 @@ #include #include #include - -#include - + #include "logicsnapshot.h" -using namespace boost; using namespace std; namespace pv { @@ -80,8 +77,13 @@ void LogicSnapshot::free_data() void LogicSnapshot::init() { - boost::lock_guard lock(_mutex); - _sample_count = 0; + std::lock_guard lock(_mutex); + init_all(); +} + +void LogicSnapshot::init_all() +{ + _sample_count = 0; _ring_sample_count = 0; _block_num = 0; _byte_fraction = 0; @@ -95,9 +97,9 @@ void LogicSnapshot::init() void LogicSnapshot::clear() { - boost::lock_guard lock(_mutex); + std::lock_guard lock(_mutex); free_data(); - init(); + init_all(); } void LogicSnapshot::capture_ended() @@ -203,7 +205,7 @@ void LogicSnapshot::first_payload(const sr_datafeed_logic &logic, uint64_t total void LogicSnapshot::append_payload( const sr_datafeed_logic &logic) { - boost::lock_guard lock(_mutex); + std::lock_guard lock(_mutex); if (logic.format == LA_CROSS_DATA) append_cross_payload(logic); diff --git a/DSView/pv/data/logicsnapshot.h b/DSView/pv/data/logicsnapshot.h index bfbf0b78..34bcc13c 100755 --- a/DSView/pv/data/logicsnapshot.h +++ b/DSView/pv/data/logicsnapshot.h @@ -32,6 +32,7 @@ #include #include +#include namespace LogicSnapshotTest { class Pow2; @@ -76,13 +77,19 @@ private: public: typedef std::pair EdgePair; +private: + void init_all(); + public: LogicSnapshot(); virtual ~LogicSnapshot(); + void free_data(); + void clear(); - void init(); + + void init(); void first_payload(const sr_datafeed_logic &logic, uint64_t total_sample_count, GSList *channels); diff --git a/DSView/pv/data/mathstack.cpp b/DSView/pv/data/mathstack.cpp index 072d0dfe..e584d392 100755 --- a/DSView/pv/data/mathstack.cpp +++ b/DSView/pv/data/mathstack.cpp @@ -19,10 +19,7 @@ */ #include "mathstack.h" - -#include -#include - + #include #include #include @@ -100,7 +97,7 @@ MathStack::~MathStack() void MathStack::free_envelop() { - BOOST_FOREACH(Envelope &e, _envelope_level) { + for(auto &e : _envelope_level) { if (e.samples) free(e.samples); } @@ -109,12 +106,12 @@ void MathStack::free_envelop() void MathStack::clear() { - boost::lock_guard lock(_mutex); + std::lock_guard lock(_mutex); } void MathStack::init() { - boost::lock_guard lock(_mutex); + std::lock_guard lock(_mutex); _sample_num = 0; _envelope_done = false; @@ -315,7 +312,7 @@ void MathStack::get_math_envelope_section(EnvelopeSection &s, void MathStack::calc_math() { - boost::lock_guard lock(_mutex); + std::lock_guard lock(_mutex); _math_state = Running; diff --git a/DSView/pv/data/mathstack.h b/DSView/pv/data/mathstack.h index 7f6f9844..e0c1a97c 100755 --- a/DSView/pv/data/mathstack.h +++ b/DSView/pv/data/mathstack.h @@ -27,7 +27,7 @@ #include #include -#include + #include #include diff --git a/DSView/pv/data/signaldata.h b/DSView/pv/data/signaldata.h index 76f9588a..f3269421 100755 --- a/DSView/pv/data/signaldata.h +++ b/DSView/pv/data/signaldata.h @@ -25,7 +25,7 @@ #define DSVIEW_PV_DATA_SIGNALDATA_H #include -#include +#include namespace pv { namespace data { @@ -45,7 +45,7 @@ public: virtual void init() = 0; protected: - mutable boost::recursive_mutex _mutex; + mutable std::mutex _mutex; double _samplerate; }; diff --git a/DSView/pv/data/snapshot.cpp b/DSView/pv/data/snapshot.cpp index 50a094d0..2e50fc2c 100755 --- a/DSView/pv/data/snapshot.cpp +++ b/DSView/pv/data/snapshot.cpp @@ -28,9 +28,7 @@ #include #include #include - -using namespace boost; - + namespace pv { namespace data { @@ -91,13 +89,13 @@ void Snapshot::set_last_ended(bool ended) uint64_t Snapshot::get_sample_count() const { - boost::lock_guard lock(_mutex); + std::lock_guard lock(_mutex); return _sample_count; } uint64_t Snapshot::get_ring_start() const { - boost::lock_guard lock(_mutex); + std::lock_guard lock(_mutex); if (_sample_count < _total_sample_count) return 0; else @@ -106,7 +104,7 @@ uint64_t Snapshot::get_ring_start() const uint64_t Snapshot::get_ring_end() const { - boost::lock_guard lock(_mutex); + std::lock_guard lock(_mutex); if (_sample_count == 0) return 0; else if (_ring_sample_count == 0) diff --git a/DSView/pv/data/snapshot.h b/DSView/pv/data/snapshot.h index 5ea70a9a..e8a43588 100755 --- a/DSView/pv/data/snapshot.h +++ b/DSView/pv/data/snapshot.h @@ -23,7 +23,8 @@ #ifndef DSVIEW_PV_DATA_SNAPSHOT_H #define DSVIEW_PV_DATA_SNAPSHOT_H -#include +#include +#include namespace pv { namespace data { @@ -64,11 +65,11 @@ protected: virtual void free_data(); protected: - mutable boost::recursive_mutex _mutex; + mutable std::mutex _mutex; //std::vector _data; void* _data; - std::vector _ch_index; + mutable std::vector _ch_index; uint64_t _capacity; unsigned int _channel_num; diff --git a/DSView/pv/data/spectrumstack.cpp b/DSView/pv/data/spectrumstack.cpp index b54bddff..7a96f308 100755 --- a/DSView/pv/data/spectrumstack.cpp +++ b/DSView/pv/data/spectrumstack.cpp @@ -19,10 +19,7 @@ */ #include "spectrumstack.h" - -#include -#include - + #include #include #include @@ -173,7 +170,8 @@ void SpectrumStack::calc_fft() // Get the dso data boost::shared_ptr data; boost::shared_ptr dsoSig; - BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { + + for(auto &s : _session->get_signals()) { if ((dsoSig = dynamic_pointer_cast(s))) { if (dsoSig->get_index() == _index && dsoSig->enabled()) { data = dsoSig->dso_data(); diff --git a/DSView/pv/data/spectrumstack.h b/DSView/pv/data/spectrumstack.h index 82440595..aff91060 100755 --- a/DSView/pv/data/spectrumstack.h +++ b/DSView/pv/data/spectrumstack.h @@ -27,8 +27,7 @@ #include #include -#include - + #include #include diff --git a/DSView/pv/device/sessionfile.cpp b/DSView/pv/device/sessionfile.cpp index 2ce80e7e..7f879565 100755 --- a/DSView/pv/device/sessionfile.cpp +++ b/DSView/pv/device/sessionfile.cpp @@ -59,10 +59,9 @@ void SessionFile::use(SigSession *owner) void SessionFile::release() { - if (!_owner) + if (!_owner || !_sdi) return; - assert(_sdi); File::release(); sr_dev_close(_sdi); sr_dev_clear(_sdi->driver); diff --git a/DSView/pv/devicemanager.cpp b/DSView/pv/devicemanager.cpp index 488d3e61..51a4a128 100755 --- a/DSView/pv/devicemanager.cpp +++ b/DSView/pv/devicemanager.cpp @@ -90,11 +90,11 @@ void DeviceManager::del_device(DevInst *device) } } -std::list& DeviceManager::driver_scan( - struct sr_dev_driver *const driver, GSList *const drvopts) -{ - list driver_devices; - +void DeviceManager::driver_scan( + std::list &driver_devices, + struct sr_dev_driver *const driver, + GSList *const drvopts) +{ assert(driver); // Remove any device instances from this driver from the device @@ -118,7 +118,7 @@ std::list& DeviceManager::driver_scan( if (strncmp(driver->name, "virtual", 7)) { QDir dir(DS_RES_PATH); if (!dir.exists()) - return driver_devices; + return; } // Do the scan @@ -133,8 +133,6 @@ std::list& DeviceManager::driver_scan( // append the scanned devices to the main list _devices.insert(_devices.end(), driver_devices.begin(), driver_devices.end()); - - return driver_devices; } void DeviceManager::init_drivers() @@ -167,8 +165,10 @@ void DeviceManager::scan_all_drivers() { // Scan all drivers for all devices. struct sr_dev_driver **const drivers = sr_driver_list(); - for (struct sr_dev_driver **driver = drivers; *driver; driver++) - driver_scan(*driver); + for (struct sr_dev_driver **driver = drivers; *driver; driver++){ + std::list driver_devices; + driver_scan(driver_devices, *driver); + } } void DeviceManager::release_driver(struct sr_dev_driver *const driver) diff --git a/DSView/pv/devicemanager.h b/DSView/pv/devicemanager.h index b275b69b..4862a455 100755 --- a/DSView/pv/devicemanager.h +++ b/DSView/pv/devicemanager.h @@ -30,8 +30,7 @@ #include #include -#include -#include +#include #include #include @@ -69,7 +68,10 @@ public: void add_device(DevInst *device); void del_device(DevInst *device); - std::list& driver_scan(struct sr_dev_driver *const driver, GSList *const drvopts = NULL); + void driver_scan( + std::list &driver_devices, + struct sr_dev_driver *const driver=NULL, + GSList *const drvopts=NULL); void initAll(struct sr_context *sr_ctx); diff --git a/DSView/pv/dialogs/calibration.cpp b/DSView/pv/dialogs/calibration.cpp index 2a5b0a8a..7bc0771a 100755 --- a/DSView/pv/dialogs/calibration.cpp +++ b/DSView/pv/dialogs/calibration.cpp @@ -20,9 +20,7 @@ */ #include "calibration.h" - -#include - + #include #include #include diff --git a/DSView/pv/dialogs/deviceoptions.cpp b/DSView/pv/dialogs/deviceoptions.cpp index bfa6fe25..d8a4b392 100755 --- a/DSView/pv/dialogs/deviceoptions.cpp +++ b/DSView/pv/dialogs/deviceoptions.cpp @@ -21,9 +21,7 @@ */ #include "deviceoptions.h" - -#include - + #include #include #include @@ -94,7 +92,7 @@ void DeviceOptions::accept() // Commit the properties const vector< boost::shared_ptr > &dev_props = _device_options_binding.properties(); - BOOST_FOREACH(boost::shared_ptr p, dev_props) { + for(auto &p : dev_props) { assert(p); p->commit(); } @@ -120,7 +118,7 @@ void DeviceOptions::accept() while(i != _probe_options_binding_list.end()) { const vector< boost::shared_ptr > &probe_props = (*i)->properties(); - BOOST_FOREACH(boost::shared_ptr p, probe_props) { + for(auto &p :probe_props) { assert(p); p->commit(); } @@ -153,7 +151,7 @@ QGridLayout * DeviceOptions::get_property_form(QWidget * parent) const vector< boost::shared_ptr > &properties = _device_options_binding.properties(); int i = 0; - BOOST_FOREACH(boost::shared_ptr p, properties) + for(auto &p : properties) { assert(p); const QString label = p->labeled_widget() ? QString() : p->label(); @@ -527,7 +525,8 @@ void DeviceOptions::analog_probes(QGridLayout &layout) const vector< boost::shared_ptr > &properties = probe_options_binding->properties(); int i = 1; - BOOST_FOREACH(boost::shared_ptr p, properties) + + for(auto &p : properties) { assert(p); const QString label = p->labeled_widget() ? QString() : p->label(); diff --git a/DSView/pv/dialogs/dsomeasure.cpp b/DSView/pv/dialogs/dsomeasure.cpp index c5f97510..46ef2896 100755 --- a/DSView/pv/dialogs/dsomeasure.cpp +++ b/DSView/pv/dialogs/dsomeasure.cpp @@ -29,8 +29,7 @@ #include #include #include - -#include + #include "../dsvdef.h" using namespace boost; @@ -57,7 +56,7 @@ DsoMeasure::DsoMeasure(SigSession *session, View &parent, _measure_tab->setTabPosition(QTabWidget::West); _measure_tab->setUsesScrollButtons(false); - BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { + for(auto &s : _session->get_signals()) { boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s)) && dsoSig->enabled()) { QWidget *measure_widget = new QWidget(this); @@ -158,7 +157,8 @@ void DsoMeasure::accept() if(sc != NULL) { QVariant id = sc->property("id"); enum DSO_MEASURE_TYPE ms_type = DSO_MEASURE_TYPE(id.toInt()); - BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { + + for(auto &s : _session->get_signals()) { boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s))) { if (_measure_tab->currentWidget()->property("index").toInt() == dsoSig->get_index()) { diff --git a/DSView/pv/dialogs/fftoptions.cpp b/DSView/pv/dialogs/fftoptions.cpp index 5af442e7..fe53c54f 100755 --- a/DSView/pv/dialogs/fftoptions.cpp +++ b/DSView/pv/dialogs/fftoptions.cpp @@ -21,8 +21,7 @@ #include "fftoptions.h" -#include - + #include #include @@ -67,7 +66,7 @@ FftOptions::FftOptions(QWidget *parent, SigSession *session) : _dbv_combobox = new QComboBox(this); // setup _ch_combobox - BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { + for(auto &s : _session->get_signals()) { boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s))) { _ch_combobox->addItem(dsoSig->get_name(), QVariant::fromValue(dsoSig->get_index())); @@ -87,7 +86,8 @@ FftOptions::FftOptions(QWidget *parent, SigSession *session) : std::vector length; std::vector view_modes; std::vector dbv_ranges; - BOOST_FOREACH(const boost::shared_ptr t, _session->get_spectrum_traces()) { + + for(auto &t : _session->get_spectrum_traces()) { boost::shared_ptr spectrumTraces; if ((spectrumTraces = dynamic_pointer_cast(t))) { windows = spectrumTraces->get_spectrum_stack()->get_windows_support(); @@ -137,7 +137,7 @@ FftOptions::FftOptions(QWidget *parent, SigSession *session) : } // load current settings - BOOST_FOREACH(const boost::shared_ptr t, _session->get_spectrum_traces()) { + for(auto &t : _session->get_spectrum_traces()) { boost::shared_ptr spectrumTraces; if ((spectrumTraces = dynamic_pointer_cast(t))) { if (spectrumTraces->enabled()) { @@ -230,7 +230,7 @@ void FftOptions::accept() QDialog::accept(); - BOOST_FOREACH(const boost::shared_ptr t, _session->get_spectrum_traces()) { + for(auto &t : _session->get_spectrum_traces()) { boost::shared_ptr spectrumTraces; if ((spectrumTraces = dynamic_pointer_cast(t))) { spectrumTraces->set_enable(false); diff --git a/DSView/pv/dialogs/lissajousoptions.cpp b/DSView/pv/dialogs/lissajousoptions.cpp index aa5d53f1..589ec4d4 100755 --- a/DSView/pv/dialogs/lissajousoptions.cpp +++ b/DSView/pv/dialogs/lissajousoptions.cpp @@ -31,9 +31,7 @@ #include #include -#include - - + using namespace boost; using namespace std; using namespace pv::view; @@ -74,7 +72,8 @@ LissajousOptions::LissajousOptions(SigSession *session, QWidget *parent) : _y_group = new QGroupBox(this); QHBoxLayout *xlayout = new QHBoxLayout(); QHBoxLayout *ylayout = new QHBoxLayout(); - BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { + + for(auto &s : _session->get_signals()) { boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s))) { QString index_str = QString::number(dsoSig->get_index()); @@ -182,7 +181,7 @@ void LissajousOptions::accept() bool enable = (xindex != -1 && yindex != -1 && _enable->isChecked()); _session->lissajous_rebuild(enable, xindex, yindex, _percent->value()); - BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { + for(auto &s : _session->get_signals()) { boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s))) { dsoSig->set_show(!enable); diff --git a/DSView/pv/dialogs/mathoptions.cpp b/DSView/pv/dialogs/mathoptions.cpp index 95111fa5..d7c9e4bb 100755 --- a/DSView/pv/dialogs/mathoptions.cpp +++ b/DSView/pv/dialogs/mathoptions.cpp @@ -31,8 +31,7 @@ #include #include #include - -#include + using namespace boost; using namespace std; @@ -78,7 +77,8 @@ MathOptions::MathOptions(SigSession *session, QWidget *parent) : _src2_group = new QGroupBox(this); QHBoxLayout *src1_layout = new QHBoxLayout(); QHBoxLayout *src2_layout = new QHBoxLayout(); - BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { + + for(auto &s : _session->get_signals()) { boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s))) { QString index_str = QString::number(dsoSig->get_index()); @@ -206,7 +206,8 @@ void MathOptions::accept() bool enable = (src1 != -1 && src2 != -1 && _enable->isChecked()); boost::shared_ptr dsoSig1; boost::shared_ptr dsoSig2; - BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { + + for(auto &s : _session->get_signals()) { boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s))) { if (dsoSig->get_index() == src1) diff --git a/DSView/pv/dialogs/protocolexp.cpp b/DSView/pv/dialogs/protocolexp.cpp index d526a998..f594c6a9 100755 --- a/DSView/pv/dialogs/protocolexp.cpp +++ b/DSView/pv/dialogs/protocolexp.cpp @@ -20,9 +20,7 @@ */ #include "protocolexp.h" - -#include - + #include #include #include @@ -192,7 +190,7 @@ void ProtocolExp::accept() decoder_stack->get_annotation_subset(annotations, row, 0, decoder_stack->sample_count()-1); if (!annotations.empty()) { - BOOST_FOREACH(const Annotation &a, annotations) { + for(auto &a : annotations) { out << QString("%1,%2,%3\n") .arg(QString::number(exported)) .arg(QString::number(a.start_sample()*ns_per_sample, 'f', 20)) diff --git a/DSView/pv/dialogs/protocollist.cpp b/DSView/pv/dialogs/protocollist.cpp index 3b2599af..53b46b30 100755 --- a/DSView/pv/dialogs/protocollist.cpp +++ b/DSView/pv/dialogs/protocollist.cpp @@ -20,8 +20,7 @@ */ #include "protocollist.h" - -#include + #include #include @@ -60,7 +59,8 @@ ProtocolList::ProtocolList(QWidget *parent, SigSession *session) : const std::vector< boost::shared_ptr > decode_sigs( _session->get_decode_signals()); int index = 0; - BOOST_FOREACH(boost::shared_ptr d, decode_sigs) { + + for(auto &d : decode_sigs) { _protocol_combobox->addItem(d->get_name()); if (decoder_model->getDecoderStack() == d->decoder()) _protocol_combobox->setCurrentIndex(index); @@ -130,7 +130,8 @@ void ProtocolList::set_protocol(int index) const std::vector< boost::shared_ptr > decode_sigs( _session->get_decode_signals()); int cur_index = 0; - BOOST_FOREACH(boost::shared_ptr d, decode_sigs) { + + for(auto &d : decode_sigs) { if (index == cur_index) { decoder_stack = d->decoder(); break; @@ -172,7 +173,8 @@ void ProtocolList::on_row_check(bool show) const std::vector< boost::shared_ptr > decode_sigs( _session->get_decode_signals()); int cur_index = 0; - BOOST_FOREACH(boost::shared_ptr d, decode_sigs) { + + for(auto &d : decode_sigs) { if (cur_index == _protocol_combobox->currentIndex()) { decoder_stack = d->decoder(); break; diff --git a/DSView/pv/dialogs/regionoptions.cpp b/DSView/pv/dialogs/regionoptions.cpp index 12853c1d..62ff127a 100755 --- a/DSView/pv/dialogs/regionoptions.cpp +++ b/DSView/pv/dialogs/regionoptions.cpp @@ -20,9 +20,7 @@ */ #include "regionoptions.h" - -#include - + #include "../sigsession.h" #include "../view/cursor.h" #include "../view/view.h" diff --git a/DSView/pv/dialogs/search.cpp b/DSView/pv/dialogs/search.cpp index 74568d7f..26744536 100755 --- a/DSView/pv/dialogs/search.cpp +++ b/DSView/pv/dialogs/search.cpp @@ -24,8 +24,7 @@ #include #include - -#include + namespace pv { namespace dialogs { @@ -50,8 +49,8 @@ Search::Search(QWidget *parent, SigSession *session, std::map search_layout->setVerticalSpacing(0); int index = 0; - BOOST_FOREACH(const boost::shared_ptr sig, - _session->get_signals()) { + + for(auto &sig : _session->get_signals()) { assert(sig); boost::shared_ptr logic_sig; if ((logic_sig = boost::dynamic_pointer_cast(sig))) { @@ -111,8 +110,7 @@ std::map Search::get_pattern() std::map pattern; int index = 0; - BOOST_FOREACH(const boost::shared_ptr sig, - _session->get_signals()) { + for(auto &sig :_session->get_signals()) { assert(sig); boost::shared_ptr logic_sig; if ((logic_sig = boost::dynamic_pointer_cast(sig))) { diff --git a/DSView/pv/dialogs/waitingdialog.cpp b/DSView/pv/dialogs/waitingdialog.cpp index 6272227c..b206912b 100755 --- a/DSView/pv/dialogs/waitingdialog.cpp +++ b/DSView/pv/dialogs/waitingdialog.cpp @@ -20,8 +20,7 @@ */ #include "waitingdialog.h" - -#include + #include #include @@ -186,12 +185,13 @@ void WaitingDialog::changeText() g_variant_unref(gvar); if (zero_fgain) { boost::shared_ptr dsoSig; - BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) + + for(auto &s : _session->get_signals()) { if ((dsoSig = dynamic_pointer_cast(s))) dsoSig->set_enable(dsoSig->get_index() == 0); } - boost::this_thread::sleep(boost::posix_time::millisec(100)); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); _dev_inst->set_config(NULL, NULL, SR_CONF_ZERO_COMB, g_variant_new_boolean(true)); } } diff --git a/DSView/pv/dock/dsotriggerdock.cpp b/DSView/pv/dock/dsotriggerdock.cpp index d11e961c..c859f824 100755 --- a/DSView/pv/dock/dsotriggerdock.cpp +++ b/DSView/pv/dock/dsotriggerdock.cpp @@ -26,7 +26,7 @@ #include "../view/dsosignal.h" #include -#include + #include #include @@ -387,7 +387,8 @@ void DsoTriggerDock::init() // setup _channel_comboBox disconnect(_channel_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(channel_changed(int))); _channel_comboBox->clear(); - BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { + + for(auto &s : _session->get_signals()) { boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s))) { _channel_comboBox->addItem(dsoSig->get_name(), QVariant::fromValue(dsoSig->get_index())); diff --git a/DSView/pv/dock/protocoldock.cpp b/DSView/pv/dock/protocoldock.cpp index 48e04900..a35374ab 100755 --- a/DSView/pv/dock/protocoldock.cpp +++ b/DSView/pv/dock/protocoldock.cpp @@ -45,7 +45,7 @@ #include #include -#include + #include #include #include "../ui/msgbox.h" @@ -377,7 +377,7 @@ void ProtocolDock::decoded_progress(int progress) _session->get_decode_signals()); int index = 0; - BOOST_FOREACH(boost::shared_ptr d, decode_sigs) { + for(auto &d : decode_sigs) { pg = d->get_progress(); if (d->decoder()->out_of_memory()) err = tr("(Out of Memory)"); @@ -416,7 +416,8 @@ void ProtocolDock::set_model() // clear mark_index of all DecoderStacks const std::vector< boost::shared_ptr > decode_sigs( _session->get_decode_signals()); - BOOST_FOREACH(boost::shared_ptr d, decode_sigs) { + + for(auto &d : decode_sigs) { d->decoder()->set_mark_index(-1); } } @@ -432,7 +433,7 @@ void ProtocolDock::update_model() decoder_model->setDecoderStack(decode_sigs.at(0)->decoder()); else { unsigned int index = 0; - BOOST_FOREACH(const boost::shared_ptr d, decode_sigs) { + for(auto &d : decode_sigs) { if (d->decoder() == decoder_model->getDecoderStack()) { decoder_model->setDecoderStack(d->decoder()); break; @@ -473,9 +474,11 @@ void ProtocolDock::item_clicked(const QModelIndex &index) if (decoder_stack->list_annotation(ann, index.column(), index.row())) { const std::vector< boost::shared_ptr > decode_sigs( _session->get_decode_signals()); - BOOST_FOREACH(boost::shared_ptr d, decode_sigs) { + + for(auto &d : decode_sigs) { d->decoder()->set_mark_index(-1); } + decoder_stack->set_mark_index((ann.start_sample()+ann.end_sample())/2); _session->show_region(ann.start_sample(), ann.end_sample(), false); } @@ -566,7 +569,8 @@ void ProtocolDock::nav_table_view() decoder_stack->list_annotation(ann, index.column(), index.row()); const std::vector< boost::shared_ptr > decode_sigs( _session->get_decode_signals()); - BOOST_FOREACH(boost::shared_ptr d, decode_sigs) { + + for(auto &d : decode_sigs) { d->decoder()->set_mark_index(-1); } decoder_stack->set_mark_index((ann.start_sample()+ann.end_sample())/2); diff --git a/DSView/pv/dock/protocoldock.h b/DSView/pv/dock/protocoldock.h index 1e7e9ded..b300846a 100755 --- a/DSView/pv/dock/protocoldock.h +++ b/DSView/pv/dock/protocoldock.h @@ -38,10 +38,12 @@ #include #include -#include +#include #include "../data/decodermodel.h" #include "protocolitemlayer.h" + + namespace pv { class SigSession; @@ -140,7 +142,7 @@ private: QPushButton *_dn_nav_button; QPushButton *_search_button; - mutable boost::mutex _search_mutex; + mutable std::mutex _search_mutex; bool _search_edited; bool _searching; diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index 7cadf548..dd0372af 100755 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -27,7 +27,6 @@ #include -#include #include #include @@ -520,8 +519,12 @@ void MainWindow::device_attach() DeviceManager &_device_manager = _control->GetDeviceManager(); for (driver = drivers; *driver; driver++) - if (*driver) - _device_manager.driver_scan(*driver); + { + if (*driver){ + std::list driver_devices; + _device_manager.driver_scan(driver_devices, *driver); + } + } _session->set_default_device(boost::bind(&MainWindow::session_error, this, @@ -581,9 +584,12 @@ void MainWindow::device_detach_post() _hot_detach = false; struct sr_dev_driver **const drivers = sr_driver_list(); struct sr_dev_driver **driver; - for (driver = drivers; *driver; driver++) - if (*driver) - _device_manager.driver_scan(*driver); + for (driver = drivers; *driver; driver++){ + if (*driver){ + std::list driver_devices; + _device_manager.driver_scan(driver_devices, *driver); + } + } _session->set_default_device(boost::bind(&MainWindow::session_error, this, QString(tr("Set Default Device failed")), _1)); @@ -821,7 +827,7 @@ void MainWindow::commit_trigger(bool instant) if (!_trigger_widget->commit_trigger()) { /* simple trigger check trigger_enable */ - BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) + for(auto &s : _session->get_signals()) { assert(s); boost::shared_ptr logicSig; @@ -843,7 +849,7 @@ void MainWindow::commit_trigger(bool instant) msg.exec(); if (msg.mBox()->clickedButton() == cancelButton) { - BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) + for(auto &s : _session->get_signals()) { assert(s); boost::shared_ptr logicSig; @@ -1055,7 +1061,7 @@ bool MainWindow::load_session_json(QJsonDocument json, bool file_dev) // load signal setting if (file_dev && (sdi->mode == DSO)) { - BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { + for(auto &s : _session->get_signals()) { foreach (const QJsonValue &value, sessionObj["channel"].toArray()) { QJsonObject obj = value.toObject(); if ((strcmp(s->get_name().toStdString().c_str(), g_strdup(obj["name"].toString().toStdString().c_str())) == 0) && @@ -1074,7 +1080,7 @@ bool MainWindow::load_session_json(QJsonDocument json, bool file_dev) } } } else { - BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { + for(auto &s : _session->get_signals()) { foreach (const QJsonValue &value, sessionObj["channel"].toArray()) { QJsonObject obj = value.toObject(); if ((s->get_index() == obj["index"].toDouble()) && @@ -1183,7 +1189,7 @@ bool MainWindow::on_store_session(QString name) } } - BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { + for(auto &s : _session->get_signals()) { QJsonObject s_obj; s_obj["index"] = s->get_index(); s_obj["type"] = s->get_type(); @@ -1328,7 +1334,7 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) _view->zoom(-1); break; case Qt::Key_0: - BOOST_FOREACH(const boost::shared_ptr s, sigs) { + for(auto & s : sigs) { boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s))) { if (dsoSig->get_index() == 0) @@ -1341,7 +1347,7 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) update(); break; case Qt::Key_1: - BOOST_FOREACH(const boost::shared_ptr s, sigs) { + for(auto & s : sigs) { boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s))) { if (dsoSig->get_index() == 1) @@ -1354,7 +1360,7 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) update(); break; case Qt::Key_Up: - BOOST_FOREACH(const boost::shared_ptr s, sigs) { + for(auto &s : sigs) { boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s))) { if (dsoSig->get_vDialActive()) { @@ -1366,7 +1372,7 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) } break; case Qt::Key_Down: - BOOST_FOREACH(const boost::shared_ptr s, sigs) { + for(auto &s : sigs) { boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s))) { if (dsoSig->get_vDialActive()) { diff --git a/DSView/pv/prop/binding/binding.cpp b/DSView/pv/prop/binding/binding.cpp index db9a0453..78e231ba 100755 --- a/DSView/pv/prop/binding/binding.cpp +++ b/DSView/pv/prop/binding/binding.cpp @@ -19,8 +19,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include + #include @@ -41,7 +40,7 @@ const std::vector< boost::shared_ptr >& Binding::properties() void Binding::commit() { - BOOST_FOREACH(shared_ptr p, _properties) { + for(auto &p : _properties) { assert(p); p->commit(); } @@ -52,7 +51,7 @@ void Binding::add_properties_to_form(QFormLayout *layout, { assert(layout); - BOOST_FOREACH(shared_ptr p, _properties) + for(auto &p : _properties) { assert(p); @@ -90,7 +89,8 @@ std::map< boost::shared_ptr, { std::map < boost::shared_ptr, GVariant* > pvalue; - BOOST_FOREACH(shared_ptr p, _properties) + + for(auto &p : _properties) { assert(p); pvalue[p] = p->get_value(); diff --git a/DSView/pv/prop/binding/decoderoptions.cpp b/DSView/pv/prop/binding/decoderoptions.cpp index 644db938..df017534 100755 --- a/DSView/pv/prop/binding/decoderoptions.cpp +++ b/DSView/pv/prop/binding/decoderoptions.cpp @@ -23,7 +23,7 @@ #include "decoderoptions.h" #include -#include + #include #include diff --git a/DSView/pv/sigsession.cpp b/DSView/pv/sigsession.cpp index 0774aca0..c5552d6f 100755 --- a/DSView/pv/sigsession.cpp +++ b/DSView/pv/sigsession.cpp @@ -65,21 +65,10 @@ #include #include -#include + #include "data/decode/decoderstatus.h" +#include "dsvdef.h" -//using boost::dynamic_pointer_cast; -//using boost::function; -//using boost::lock_guard; -//using boost::mutex; -//using boost::shared_ptr; -//using std::list; -//using std::map; -//using std::set; -//using std::string; -//using std::vector; -//using std::deque; -//using std::min; using namespace boost; using namespace std; @@ -99,9 +88,6 @@ SigSession::SigSession(DeviceManager *device_manager) : _repeat_hold_prg(0), _map_zoom(0) { - void *p = this; - _appCntrol = NULL; - _hotplug_handle = 0; _dev_inst = NULL; _device_manager = device_manager; @@ -110,6 +96,9 @@ SigSession::SigSession(DeviceManager *device_manager) : _hot_attach = false; _hot_detach = false; _group_cnt = 0; + _bHotplugStop = false; + _hotplug = NULL; + _sampling_thread = NULL; _feed_timer.stop(); @@ -145,7 +134,6 @@ SigSession::SigSession(DeviceManager *device_manager) : SigSession::~SigSession() { - Close(); } DevInst* SigSession::get_device() const @@ -279,7 +267,7 @@ void SigSession::release_device(DevInst *dev_inst) SigSession::capture_state SigSession::get_capture_state() const { - boost::lock_guard lock(_sampling_mutex); + std::lock_guard lock(_sampling_mutex); return _capture_state; } @@ -336,14 +324,14 @@ void SigSession::set_cur_snap_samplerate(uint64_t samplerate) // DecoderStack - BOOST_FOREACH(const boost::shared_ptr d, _decode_traces) + for(auto &d : _decode_traces) d->decoder()->set_samplerate(_cur_snap_samplerate); // Math if (_math_trace && _math_trace->enabled()) _math_trace->get_math_stack()->set_samplerate(_dev_inst->get_sample_rate()); // SpectrumStack - BOOST_FOREACH(const boost::shared_ptr m, _spectrum_traces) + for(auto & m : _spectrum_traces) m->get_spectrum_stack()->set_samplerate(_cur_snap_samplerate); cur_snap_samplerate_changed(); @@ -383,7 +371,7 @@ void SigSession::capture_init() container_init(); // update current hw offset - BOOST_FOREACH(const boost::shared_ptr s, _signals) + for(auto &s : _signals) { assert(s); boost::shared_ptr dsoSig; @@ -416,7 +404,7 @@ void SigSession::container_init() _dso_data->init(); // SpectrumStack - BOOST_FOREACH(const boost::shared_ptr m, _spectrum_traces) + for(auto &m : _spectrum_traces) { assert(m); m->get_spectrum_stack()->init(); @@ -430,7 +418,7 @@ void SigSession::container_init() //pv::data::DecoderModel *decoder_model = get_decoder_model(); //decoder_model->setDecoderStack(NULL); // DecoderStack - BOOST_FOREACH(const boost::shared_ptr d, _decode_traces) + for(auto &d : _decode_traces) { assert(d); d->decoder()->init(); @@ -459,7 +447,7 @@ void SigSession::start_capture(bool instant, // stop previous capture stop_capture(); // reset measure of dso signal - BOOST_FOREACH(const boost::shared_ptr s, _signals) + for(auto &s : _signals) { assert(s); boost::shared_ptr dsoSig; @@ -490,10 +478,11 @@ void SigSession::start_capture(bool instant, return; } - // Begin the session - _sampling_thread.reset(new boost::thread( - &SigSession::sample_thread_proc, this, _dev_inst, - error_handler)); + if (_sampling_thread && _sampling_thread->joinable()){ + _sampling_thread->join(); + } + DESTROY_OBJECT(_sampling_thread); + _sampling_thread = new std::thread(&SigSession::sample_thread_proc, this, _dev_inst, error_handler); } void SigSession::stop_capture() @@ -512,9 +501,10 @@ void SigSession::stop_capture() sr_session_stop(); // Check that sampling stopped - if (_sampling_thread.get()) + if (_sampling_thread && _sampling_thread->joinable()){ _sampling_thread->join(); - _sampling_thread.reset(); + } + DESTROY_OBJECT(_sampling_thread); } bool SigSession::get_capture_status(bool &triggered, int &progress) @@ -542,13 +532,13 @@ bool SigSession::get_capture_status(bool &triggered, int &progress) vector< boost::shared_ptr >& SigSession::get_signals() { - //boost::lock_guard lock(_signals_mutex); + //boost::lock_guard lock(_signals_mutex); return _signals; } vector< boost::shared_ptr > SigSession::get_group_signals() { - //boost::lock_guard lock(_signals_mutex); + //boost::lock_guard lock(_signals_mutex); return _group_traces; } @@ -556,7 +546,8 @@ set< boost::shared_ptr > SigSession::get_data() const { //lock_guard lock(_signals_mutex); set< boost::shared_ptr > data; - BOOST_FOREACH(const boost::shared_ptr sig, _signals) { + + for(auto &sig : _signals) { assert(sig); data.insert(sig->data()); } @@ -571,7 +562,7 @@ bool SigSession::get_instant() void SigSession::set_capture_state(capture_state state) { - boost::lock_guard lock(_sampling_mutex); + std::lock_guard lock(_sampling_mutex); _capture_state = state; data_updated(); capture_state_changed(state); @@ -606,7 +597,7 @@ void SigSession::sample_thread_proc(DevInst *dev_inst, void SigSession::check_update() { - boost::lock_guard lock(_data_mutex); + std::lock_guard lock(_data_mutex); if (_capture_state != Running) return; @@ -868,7 +859,7 @@ void SigSession::reload() void SigSession::refresh(int holdtime) { - boost::lock_guard lock(_data_mutex); + std::lock_guard lock(_data_mutex); data_lock(); @@ -876,7 +867,7 @@ void SigSession::refresh(int holdtime) _logic_data->init(); //_cur_logic_snapshot.reset(); - BOOST_FOREACH(const boost::shared_ptr d, _decode_traces) + for(auto &d : _decode_traces) { assert(d); d->decoder()->init(); @@ -886,7 +877,7 @@ void SigSession::refresh(int holdtime) if (_dso_data) { _dso_data->init(); // SpectrumStack - BOOST_FOREACH(const boost::shared_ptr m, _spectrum_traces) + for(auto &m : _spectrum_traces) { assert(m); m->get_spectrum_stack()->init(); @@ -988,7 +979,7 @@ void SigSession::feed_in_trigger(const ds_trigger_pos &trigger_pos) void SigSession::feed_in_logic(const sr_datafeed_logic &logic) { - //boost::lock_guard lock(_data_mutex); + //boost::lock_guard lock(_data_mutex); if (!_logic_data || _cur_logic_snapshot->memory_failed()) { qDebug() << "Unexpected logic packet"; return; @@ -1026,7 +1017,7 @@ void SigSession::feed_in_logic(const sr_datafeed_logic &logic) void SigSession::feed_in_dso(const sr_datafeed_dso &dso) { - //boost::lock_guard lock(_data_mutex); + //boost::lock_guard lock(_data_mutex); if(!_dso_data || _cur_dso_snapshot->memory_failed()) { @@ -1038,7 +1029,7 @@ void SigSession::feed_in_dso(const sr_datafeed_dso &dso) { std::map sig_enable; // reset scale of dso signal - BOOST_FOREACH(const boost::shared_ptr s, _signals) + for(auto &s : _signals) { assert(s); boost::shared_ptr dsoSig; @@ -1055,7 +1046,7 @@ void SigSession::feed_in_dso(const sr_datafeed_dso &dso) _cur_dso_snapshot->append_payload(dso); } - BOOST_FOREACH(const boost::shared_ptr s, _signals) { + for(auto &s : _signals) { boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s)) && (dsoSig->enabled())) dsoSig->paint_prepare(); @@ -1064,14 +1055,7 @@ void SigSession::feed_in_dso(const sr_datafeed_dso &dso) if (dso.num_samples != 0) { // update current sample rate set_cur_snap_samplerate(_dev_inst->get_sample_rate()); -// // reset measure of dso signal -// BOOST_FOREACH(const boost::shared_ptr s, _signals) -// { -// assert(s); -// boost::shared_ptr dsoSig; -// if ((dsoSig = dynamic_pointer_cast(s))) -// dsoSig->set_mValid(false); -// } + } if (_cur_dso_snapshot->memory_failed()) { @@ -1081,7 +1065,7 @@ void SigSession::feed_in_dso(const sr_datafeed_dso &dso) } // calculate related spectrum results - BOOST_FOREACH(const boost::shared_ptr m, _spectrum_traces) + for(auto &m : _spectrum_traces) { assert(m); if (m->enabled()) @@ -1105,7 +1089,7 @@ void SigSession::feed_in_dso(const sr_datafeed_dso &dso) void SigSession::feed_in_analog(const sr_datafeed_analog &analog) { - //boost::lock_guard lock(_data_mutex); + //boost::lock_guard lock(_data_mutex); if(!_analog_data || _cur_analog_snapshot->memory_failed()) { @@ -1116,7 +1100,7 @@ void SigSession::feed_in_analog(const sr_datafeed_analog &analog) if (_cur_analog_snapshot->last_ended()) { // reset scale of analog signal - BOOST_FOREACH(const boost::shared_ptr s, _signals) + for(auto &s : _signals) { assert(s); boost::shared_ptr analogSig; @@ -1149,7 +1133,7 @@ void SigSession::data_feed_in(const struct sr_dev_inst *sdi, assert(sdi); assert(packet); - boost::lock_guard lock(_data_mutex); + std::lock_guard lock(_data_mutex); if (_data_lock && packet->type != SR_DF_END) return; @@ -1203,9 +1187,9 @@ void SigSession::data_feed_in(const struct sr_dev_inst *sdi, case SR_DF_END: { { - //boost::lock_guard lock(_data_mutex); + //boost::lock_guard lock(_data_mutex); if (!_cur_logic_snapshot->empty()) { - BOOST_FOREACH(const boost::shared_ptr g, _group_traces) + for(auto &g : _group_traces) { assert(g); @@ -1219,7 +1203,7 @@ void SigSession::data_feed_in(const struct sr_dev_inst *sdi, _cur_dso_snapshot->capture_ended(); _cur_analog_snapshot->capture_ended(); - BOOST_FOREACH(const boost::shared_ptr d, _decode_traces) + for(auto &d : _decode_traces) d->frame_ended(); } @@ -1278,7 +1262,7 @@ void SigSession::hotplug_proc(boost::function error_handle tv.tv_sec = tv.tv_usec = 0; try { - while(_session) { + while(_session && !_bHotplugStop) { libusb_handle_events_timeout(NULL, &tv); if (_hot_attach) { qDebug("DreamSourceLab hardware attached!"); @@ -1290,7 +1274,7 @@ void SigSession::hotplug_proc(boost::function error_handle device_detach(); _hot_detach = false; } - boost::this_thread::sleep(boost::posix_time::millisec(100)); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); } } catch(...) { qDebug("Interrupt exception for hotplug thread was thrown."); @@ -1324,18 +1308,21 @@ void SigSession::start_hotplug_proc(boost::function error_ qDebug() << "Starting a hotplug thread...\n"; _hot_attach = false; _hot_detach = false; - _hotplug.reset(new boost::thread( - &SigSession::hotplug_proc, this, error_handler)); + if (_hotplug && _hotplug->joinable()){ + _hotplug->join(); + } + DESTROY_OBJECT(_hotplug); + _hotplug = new std::thread(&SigSession::hotplug_proc, this, error_handler); } void SigSession::stop_hotplug_proc() -{ - if (_hotplug.get()) { - _hotplug->interrupt(); +{ + _bHotplugStop = true; + if (_hotplug && _hotplug->joinable()){ _hotplug->join(); } - _hotplug.reset(); + DESTROY_OBJECT(_hotplug); } uint16_t SigSession::get_ch_num(int type) @@ -1345,7 +1332,7 @@ uint16_t SigSession::get_ch_num(int type) uint16_t dso_ch_num = 0; uint16_t analog_ch_num = 0; if (_dev_inst->dev_inst()) { - BOOST_FOREACH(const boost::shared_ptr s, _signals) + for(auto &s : _signals) { assert(s); if (dynamic_pointer_cast(s) && s->enabled()) { @@ -1408,7 +1395,7 @@ bool SigSession::add_decoder(srd_decoder *const dec, bool silent, DecoderStatus new view::DecodeTrace(this, decoder_stack, _decode_traces.size())); // set view early for decode start/end region setting - BOOST_FOREACH(const boost::shared_ptr s, _signals) { + for(auto &s : _signals) { if (s->get_view()) { d->set_view(s->get_view()); break; @@ -1465,6 +1452,8 @@ void SigSession::remove_decode_signal(int index) { if (cur_index == index) { + auto d = (*i)->decoder().get(); + d->stop_decode(); //stop decoder thread _decode_traces.erase(i); signals_changed(); return; @@ -1522,7 +1511,7 @@ pv::data::DecoderModel* SigSession::get_decoder_model() const void SigSession::spectrum_rebuild() { bool has_dso_signal = false; - BOOST_FOREACH(const boost::shared_ptr s, _signals) { + for(auto &s : _signals) { boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s))) { has_dso_signal = true; @@ -1577,7 +1566,7 @@ void SigSession::math_rebuild(bool enable, boost::shared_ptr dsoSig2, data::MathStack::MathType type) { - boost::lock_guard lock(_data_mutex); + std::lock_guard lock(_data_mutex); boost::shared_ptr math_stack( new data::MathStack(this, dsoSig1, dsoSig2, type)); _math_trace.reset(new view::MathTrace(enable, math_stack, dsoSig1, dsoSig2)); @@ -1760,7 +1749,7 @@ int SigSession::get_map_zoom() const void SigSession::auto_end() { - BOOST_FOREACH(const boost::shared_ptr s, _signals) { + for(auto &s : _signals) { boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s))) { dsoSig->auto_end(); @@ -1827,8 +1816,6 @@ void SigSession::set_stop_scale(float scale) sr_dev_inst* SigSession::get_dev_inst_c() { - void *p = this; - void *p2 = this->_appCntrol; if (_dev_inst != NULL){ return _dev_inst->dev_inst(); } @@ -1844,7 +1831,7 @@ void SigSession::set_stop_scale(float scale) { if (_session == NULL) return; - + stop_capture(); ds_trigger_destroy(); @@ -1861,7 +1848,7 @@ void SigSession::set_stop_scale(float scale) { stop_hotplug_proc(); deregister_hotplug_callback(); - _hotplug_handle = NULL; + _hotplug_handle = 0; } } diff --git a/DSView/pv/sigsession.h b/DSView/pv/sigsession.h index 3e2b8fb3..9cd6324e 100755 --- a/DSView/pv/sigsession.h +++ b/DSView/pv/sigsession.h @@ -26,8 +26,7 @@ #include #include #include -#include -#include +#include #include #include @@ -386,10 +385,8 @@ private slots: void nodata_timeout(); void feed_timeout(); void repeat_update(); - -public: - void *_appCntrol; - + + private: DeviceManager *_device_manager; @@ -398,13 +395,13 @@ private: */ DevInst *_dev_inst; - mutable boost::mutex _sampling_mutex; + mutable std::mutex _sampling_mutex; capture_state _capture_state; bool _instant; uint64_t _cur_snap_samplerate; uint64_t _cur_samplelimits; - //mutable boost::mutex _signals_mutex; + //mutable std::mutex _signals_mutex; std::vector< boost::shared_ptr > _signals; std::vector< boost::shared_ptr > _group_traces; @@ -415,7 +412,7 @@ private: boost::shared_ptr _lissajous_trace; boost::shared_ptr _math_trace; - mutable boost::mutex _data_mutex; + mutable std::mutex _data_mutex; boost::shared_ptr _logic_data; boost::shared_ptr _cur_logic_snapshot; boost::shared_ptr _dso_data; @@ -426,10 +423,12 @@ private: boost::shared_ptr _cur_group_snapshot; int _group_cnt; - std::unique_ptr _sampling_thread; + std::thread *_sampling_thread; + std::thread *_hotplug; + volatile bool _bHotplugStop; libusb_hotplug_callback_handle _hotplug_handle; - std::unique_ptr _hotplug; + bool _hot_attach; bool _hot_detach; @@ -461,6 +460,7 @@ private: bool _dso_feed; float _stop_scale; + private: // TODO: This should not be necessary. Multiple concurrent diff --git a/DSView/pv/storesession.cpp b/DSView/pv/storesession.cpp index aed18575..230fd51a 100755 --- a/DSView/pv/storesession.cpp +++ b/DSView/pv/storesession.cpp @@ -39,26 +39,13 @@ #include #include #include - -#include + #include #include #include "config/appconfig.h" - -using boost::dynamic_pointer_cast; -using boost::mutex; -using boost::thread; -using boost::lock_guard; -using std::deque; -using std::make_pair; -using std::min; -using std::pair; -using std::set; -using std::string; -using std::vector; - + namespace pv { char chunk_name[30] = {0}; @@ -82,7 +69,7 @@ StoreSession::StoreSession(SigSession *session) : _unit_count(0), _has_error(false), _canceled(false) -{ +{ } StoreSession::~StoreSession() @@ -114,9 +101,8 @@ void StoreSession::wait() } void StoreSession::cancel() -{ - _canceled = true; - _thread.interrupt(); +{ + _canceled = true; } QList StoreSession::getSuportedExportFormats(){ @@ -147,7 +133,7 @@ bool StoreSession::save_start() } std::set type_set; - BOOST_FOREACH(const boost::shared_ptr sig, _session->get_signals()) { + for(auto &sig : _session->get_signals()) { assert(sig); type_set.insert(sig->get_type()); } @@ -190,7 +176,7 @@ bool StoreSession::save_start() if (ret != SR_OK) { _error = tr("Failed to create zip file. Initialization error."); } else { - _thread = boost::thread(&StoreSession::save_proc, this, snapshot); + _thread = std::thread(&StoreSession::save_proc, this, snapshot); return !_has_error; } } @@ -208,7 +194,8 @@ bool StoreSession::save_start() } else { - _thread = boost::thread(&StoreSession::save_proc, this, snapshot); + if (_thread.joinable()) _thread.join(); + _thread = std::thread(&StoreSession::save_proc, this, snapshot); return !_has_error; } } @@ -230,7 +217,7 @@ void StoreSession::save_proc(boost::shared_ptr snapshot) if ((logic_snapshot = boost::dynamic_pointer_cast(snapshot))) { uint16_t to_save_probes = 0; - BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { + for(auto &s : _session->get_signals()) { if (s->enabled() && logic_snapshot->has_data(s->get_index())) to_save_probes++; } @@ -238,13 +225,13 @@ void StoreSession::save_proc(boost::shared_ptr snapshot) num = logic_snapshot->get_block_num(); bool sample; - BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { + for(auto &s : _session->get_signals()) { int ch_type = s->get_type(); if (ch_type == SR_CHANNEL_LOGIC) { int ch_index = s->get_index(); if (!s->enabled() || !logic_snapshot->has_data(ch_index)) continue; - for (int i = 0; !boost::this_thread::interruption_requested() && i < num; i++) { + for (int i = 0; !_canceled && i < num; i++) { uint8_t *buf = logic_snapshot->get_block_buf(i, ch_index, sample); uint64_t size = logic_snapshot->get_block_size(i); bool need_malloc = (buf == NULL); @@ -283,7 +270,7 @@ void StoreSession::save_proc(boost::shared_ptr snapshot) } } else { int ch_type = -1; - BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { + for(auto &s : _session->get_signals()) { ch_type = s->get_type(); break; } @@ -297,7 +284,7 @@ void StoreSession::save_proc(boost::shared_ptr snapshot) const uint8_t *buf_start = (uint8_t *)snapshot->get_data(); const uint8_t *buf_end = buf_start + _unit_count; - for (int i = 0; !boost::this_thread::interruption_requested() && i < num; i++) { + for (int i = 0; !_canceled && i < num; i++) { const uint64_t size = snapshot->get_block_size(i); if ((buf + size) > buf_end) { uint8_t *tmp = (uint8_t *)malloc(size); @@ -557,7 +544,7 @@ QString StoreSession::meta_gen(boost::shared_ptr snapshot) bool StoreSession::export_start() { std::set type_set; - BOOST_FOREACH(const boost::shared_ptr sig, _session->get_signals()) { + for(auto &sig : _session->get_signals()) { assert(sig); int _tp = sig->get_type(); type_set.insert(_tp); @@ -609,7 +596,8 @@ bool StoreSession::export_start() } else { - _thread = boost::thread(&StoreSession::export_proc, this, snapshot); + if (_thread.joinable()) _thread.join(); + _thread = std::thread(&StoreSession::export_proc, this, snapshot); return !_has_error; } @@ -716,12 +704,12 @@ void StoreSession::export_proc(boost::shared_ptr snapshot) std::vector buf_vec; std::vector buf_sample; - for (int blk = 0; !boost::this_thread::interruption_requested() && - blk < blk_num; blk++) { + for (int blk = 0; !_canceled && blk < blk_num; blk++) { uint64_t buf_sample_num = logic_snapshot->get_block_size(blk) * 8; buf_vec.clear(); buf_sample.clear(); - BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { + + for(auto &s : _session->get_signals()) { int ch_type = s->get_type(); if (ch_type == SR_CHANNEL_LOGIC) { int ch_index = s->get_index(); @@ -738,8 +726,7 @@ void StoreSession::export_proc(boost::shared_ptr snapshot) unsigned int size = usize; struct sr_datafeed_logic lp; - for(uint64_t i = 0; !boost::this_thread::interruption_requested() && - i < buf_sample_num; i+=usize){ + for(uint64_t i = 0; !_canceled && i < buf_sample_num; i+=usize){ if(buf_sample_num - i < usize) size = buf_sample_num - i; uint8_t *xbuf = (uint8_t *)malloc(size * unitsize); @@ -786,7 +773,7 @@ void StoreSession::export_proc(boost::shared_ptr snapshot) unsigned int size = usize; struct sr_datafeed_dso dp; - for(uint64_t i = 0; !boost::this_thread::interruption_requested() && i < _unit_count; i+=usize){ + for(uint64_t i = 0; !_canceled && i < _unit_count; i+=usize){ if(_unit_count - i < usize) size = _unit_count - i; @@ -813,7 +800,7 @@ void StoreSession::export_proc(boost::shared_ptr snapshot) unsigned int size = usize; struct sr_datafeed_analog ap; - for(uint64_t i = 0; !boost::this_thread::interruption_requested() && i < _unit_count; i+=usize){ + for(uint64_t i = 0; !_canceled && i < _unit_count; i+=usize){ if(_unit_count - i < usize) size = _unit_count - i; ap.data = &datat[i*snapshot->get_channel_num()]; @@ -879,13 +866,15 @@ QString StoreSession::decoders_gen() QJsonArray StoreSession::json_decoders() { QJsonArray dec_array; - BOOST_FOREACH(boost::shared_ptr t, _session->get_decode_signals()) { + + for(auto &t : _session->get_decode_signals()) { QJsonObject dec_obj; QJsonArray stack_array; QJsonObject show_obj; const boost::shared_ptr& stack = t->decoder(); const std::list< boost::shared_ptr >& decoder = stack->stack(); - BOOST_FOREACH(boost::shared_ptr dec, decoder) { + + for(auto &dec : decoder) { QJsonArray ch_array; const srd_decoder *const d = dec->decoder();; const bool have_probes = (d->channels || d->opt_channels) != 0; @@ -997,7 +986,8 @@ void StoreSession::load_decoders(dock::ProtocolDock *widget, QJsonArray dec_arra } const std::list< boost::shared_ptr >& decoder = stack->stack(); - BOOST_FOREACH(boost::shared_ptr dec, decoder) { + + for(auto &dec : decoder) { const srd_decoder *const d = dec->decoder(); QJsonObject options_obj; @@ -1271,7 +1261,7 @@ QString StoreSession::MakeExportFile(bool bDlg) bool StoreSession::IsLogicDataType() { std::set type_set; - BOOST_FOREACH(const boost::shared_ptr sig, _session->get_signals()) { + for(auto &sig : _session->get_signals()) { assert(sig); type_set.insert(sig->get_type()); } diff --git a/DSView/pv/storesession.h b/DSView/pv/storesession.h index 45bd1e9a..2a671365 100755 --- a/DSView/pv/storesession.h +++ b/DSView/pv/storesession.h @@ -24,8 +24,8 @@ #include #include - -#include +#include + #include #include @@ -106,7 +106,7 @@ private: QString _suffix; SigSession *_session; - boost::thread _thread; + std::thread _thread; const struct sr_output_module* _outModule; @@ -114,8 +114,8 @@ private: uint64_t _unit_count; bool _has_error; QString _error; - bool _canceled; - ZipMaker m_zipDoc; + volatile bool _canceled; + ZipMaker m_zipDoc; }; } // pv diff --git a/DSView/pv/toolbars/filebar.cpp b/DSView/pv/toolbars/filebar.cpp index 8db6d486..7c6e7880 100755 --- a/DSView/pv/toolbars/filebar.cpp +++ b/DSView/pv/toolbars/filebar.cpp @@ -20,7 +20,7 @@ */ #include -#include + #include #include @@ -167,6 +167,7 @@ void FileBar::session_error( void FileBar::show_session_error( const QString text, const QString info_text) { + (void)text; MsgBox::Show(NULL, info_text.toStdString().c_str(), this); } diff --git a/DSView/pv/toolbars/logobar.cpp b/DSView/pv/toolbars/logobar.cpp index 6791226a..4c65cf41 100755 --- a/DSView/pv/toolbars/logobar.cpp +++ b/DSView/pv/toolbars/logobar.cpp @@ -20,7 +20,7 @@ */ #include -#include + #include #include diff --git a/DSView/pv/toolbars/samplingbar.cpp b/DSView/pv/toolbars/samplingbar.cpp index 2ecd10b0..5efe3265 100755 --- a/DSView/pv/toolbars/samplingbar.cpp +++ b/DSView/pv/toolbars/samplingbar.cpp @@ -23,7 +23,7 @@ #include #include -#include + #include #include @@ -332,7 +332,8 @@ void SamplingBar::on_configure() void SamplingBar::zero_adj() { boost::shared_ptr dsoSig; - BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) + + for(auto &s : _session->get_signals()) { if ((dsoSig = dynamic_pointer_cast(s))) dsoSig->set_enable(true); @@ -349,7 +350,7 @@ void SamplingBar::zero_adj() pv::dialogs::WaitingDialog wait(this, _session, SR_CONF_ZERO); if (wait.start() == QDialog::Rejected) { - BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) + for(auto &s : _session->get_signals()) { if ((dsoSig = dynamic_pointer_cast(s))) dsoSig->commit_settings(); @@ -375,7 +376,7 @@ bool SamplingBar::get_instant() const void SamplingBar::set_sampling(bool sampling) { - lock_guard lock(_sampling_mutex); + lock_guard lock(_sampling_mutex); _sampling = sampling; if (!sampling) { diff --git a/DSView/pv/toolbars/samplingbar.h b/DSView/pv/toolbars/samplingbar.h index f4addaef..833795d0 100755 --- a/DSView/pv/toolbars/samplingbar.h +++ b/DSView/pv/toolbars/samplingbar.h @@ -136,7 +136,7 @@ namespace pv private: SigSession *_session; - mutable boost::recursive_mutex _sampling_mutex; + mutable std::mutex _sampling_mutex; bool _enable; bool _sampling; diff --git a/DSView/pv/view/decodetrace.cpp b/DSView/pv/view/decodetrace.cpp index b81be63e..07816c28 100755 --- a/DSView/pv/view/decodetrace.cpp +++ b/DSView/pv/view/decodetrace.cpp @@ -23,7 +23,7 @@ #include -#include + #include #include @@ -127,9 +127,8 @@ DecodeTrace::DecodeTrace(pv::SigSession *session, _end_index(0), _start_count(0), _end_count(0), - _progress(0), - _popup_form(NULL), - _popup() + _progress(0), + _popup(NULL) { assert(_decoder_stack); @@ -150,6 +149,11 @@ DecodeTrace::~DecodeTrace() _decoder_forms.clear(); _probe_selectors.clear(); _bindings.clear(); + + if (_popup){ + delete _popup; + _popup = NULL; + } } bool DecodeTrace::enabled() const @@ -268,11 +272,13 @@ void DecodeTrace::paint_mid(QPainter &p, int left, int right, QColor fore, QColo samples_per_pixel, 0.0); uint64_t end_sample = (uint64_t)max((right + pixels_offset) * samples_per_pixel, 0.0); - BOOST_FOREACH(const boost::shared_ptr &dec, _decoder_stack->stack()) { + + for(auto &dec : _decoder_stack->stack()) { start_sample = max(dec->decode_start(), start_sample); end_sample = min(dec->decode_end(), end_sample); break; } + if (end_sample < start_sample) return; @@ -284,8 +290,7 @@ void DecodeTrace::paint_mid(QPainter &p, int left, int right, QColor fore, QColo assert(_decoder_stack); - BOOST_FOREACH(boost::shared_ptr dec, - _decoder_stack->stack()) { + for(auto &dec :_decoder_stack->stack()) { if (dec->shown()) { const std::map rows = _decoder_stack->get_rows_gshow(); for (std::map::const_iterator i = rows.begin(); @@ -302,14 +307,16 @@ void DecodeTrace::paint_mid(QPainter &p, int left, int right, QColor fore, QColo const uint64_t max_annotation = _decoder_stack->get_max_annotation(row); const double max_annWidth = max_annotation / samples_per_pixel; + if ((max_annWidth > 100) || (max_annWidth > 10 && min_annWidth > 1) || (max_annWidth == 0 && samples_per_pixel < 10)) { vector annotations; _decoder_stack->get_annotation_subset(annotations, row, start_sample, end_sample); + if (!annotations.empty()) { - BOOST_FOREACH(const Annotation &a, annotations) + for(Annotation &a : annotations) draw_annotation(a, p, get_text_colour(), annotation_height, left, right, samples_per_pixel, pixels_offset, y, @@ -345,6 +352,11 @@ void DecodeTrace::paint_fore(QPainter &p, int left, int right, QColor fore, QCol //to show decoder's property setting dialog bool DecodeTrace::create_popup() { + if (_popup != NULL){ + _popup->reload(); + return true; + } + int ret = false; _popup = new dialogs::DSDialog(); @@ -352,8 +364,7 @@ bool DecodeTrace::create_popup() if (QDialog::Accepted == _popup->exec()) { - BOOST_FOREACH(boost::shared_ptr dec, - _decoder_stack->stack()) + for(auto &dec : _decoder_stack->stack()) { if (dec->commit() || _decoder_stack->options_changed()) { _decoder_stack->set_options_changed(true); @@ -374,11 +385,8 @@ void DecodeTrace::create_popup_form() // Transfer the layout and the child widgets to a temporary widget // which then goes out of scope destroying the layout and all the child - // widgets. - if (_popup_form) - _popup->reload(); - - _popup_form = new QFormLayout(); + // widgets. + QFormLayout *_popup_form = new QFormLayout(); _popup_form->setVerticalSpacing(5); _popup_form->setFormAlignment(Qt::AlignLeft); _popup_form->setLabelAlignment(Qt::AlignLeft); @@ -402,7 +410,7 @@ void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form) _probe_selectors.clear(); _decoder_forms.clear(); - const list< boost::shared_ptr >& stack = _decoder_stack->stack(); + list< boost::shared_ptr >& stack = _decoder_stack->stack(); if (stack.empty()) { QLabel *const l = new QLabel( @@ -410,8 +418,7 @@ void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form) l->setAlignment(Qt::AlignCenter); form->addRow(l); } else { - BOOST_FOREACH(boost::shared_ptr dec,stack) { - //boost::shared_ptr dec(*iter); + for(auto &dec : stack) { create_decoder_form(_decoder_stack, dec, parent, form); } @@ -419,9 +426,7 @@ void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form) tr("* Required channels"), parent)); } - //public input layer - // QFormLayout *publay = new QFormLayout(); - // form->addRow(publay); + //Add region combobox _start_comboBox = new QComboBox(parent); @@ -526,15 +531,15 @@ void DecodeTrace::draw_annotation(const pv::data::decode::Annotation &a, draw_range(a, p, fill, outline, text_color, h, start, end, y, fore, back); if ((a.type()/100 == 2) && (end - start > 20)) { - BOOST_FOREACH(boost::shared_ptr dec, - _decoder_stack->stack()) { + for(auto &dec : _decoder_stack->stack()) { for (auto& iter: dec->channels()) { int type = dec->get_channel_type(iter.first); if ((type == SRD_CHANNEL_COMMON) || ((type%100 != a.type()%100) && (type%100 != 0))) continue; boost::shared_ptr logic_sig; - BOOST_FOREACH(boost::shared_ptr sig, _session->get_signals()) { + + for(auto &sig : _session->get_signals()) { if((sig->get_index() == iter.second) && (logic_sig = dynamic_pointer_cast(sig))) { logic_sig->paint_mark(p, start, end, type/100); @@ -644,7 +649,7 @@ void DecodeTrace::draw_range(const pv::data::decode::Annotation &a, QPainter &p, QString best_annotation; int best_width = 0; - BOOST_FOREACH(const QString &a, annotations) { + for(auto &&a : annotations) { const int w = p.boundingRect(QRectF(), 0, a).width(); if (w <= rect.width() && w > best_width) best_annotation = a, best_width = w; @@ -812,7 +817,7 @@ void DecodeTrace::commit_decoder_probes(boost::shared_ptr const vector< boost::shared_ptr > sigs(_session->get_signals()); _index_list.clear(); - BOOST_FOREACH(const ProbeSelector &s, _probe_selectors) + for(auto &s : _probe_selectors) { if(s._decoder != dec) break; @@ -820,7 +825,7 @@ void DecodeTrace::commit_decoder_probes(boost::shared_ptr const int selection = s._combo->itemData( s._combo->currentIndex()).value(); - BOOST_FOREACH(boost::shared_ptr sig, sigs) + for(auto &sig : sigs) if(sig->get_index() == selection) { probe_map[s._pdch] = selection; _index_list.push_back(selection); @@ -834,11 +839,8 @@ void DecodeTrace::commit_decoder_probes(boost::shared_ptr void DecodeTrace::commit_probes() { assert(_decoder_stack); - BOOST_FOREACH(boost::shared_ptr dec, - _decoder_stack->stack()) - commit_decoder_probes(dec); - - //_decoder_stack->begin_decode(); + for(auto &dec : _decoder_stack->stack()) + commit_decoder_probes(dec); } void DecodeTrace::on_new_decode_data() @@ -911,8 +913,7 @@ int DecodeTrace::rows_size() using pv::data::decode::Decoder; int size = 0; - BOOST_FOREACH(boost::shared_ptr dec, - _decoder_stack->stack()) { + for(auto &dec : _decoder_stack->stack()) { if (dec->shown()) { const std::map rows = _decoder_stack->get_rows_gshow(); for (std::map::const_iterator i = rows.begin(); @@ -1000,8 +1001,7 @@ void DecodeTrace::on_region_set(int index) _start_index = index1; _end_index = index2; - BOOST_FOREACH(boost::shared_ptr dec, - _decoder_stack->stack()) { + for(auto &dec : _decoder_stack->stack()) { dec->set_decode_region(decode_start, decode_end); } } @@ -1018,8 +1018,7 @@ void DecodeTrace::frame_ended() _decode_end = last_samples; _end_index = 0; } - BOOST_FOREACH(boost::shared_ptr dec, - _decoder_stack->stack()) { + for(auto &dec : _decoder_stack->stack()) { dec->set_decode_region(_decode_start, _decode_end); dec->commit(); } diff --git a/DSView/pv/view/decodetrace.h b/DSView/pv/view/decodetrace.h index ee2ae804..19e8015f 100755 --- a/DSView/pv/view/decodetrace.h +++ b/DSView/pv/view/decodetrace.h @@ -223,8 +223,7 @@ private: std::vector _decoder_forms; std::vector _cur_row_headings; - - QFormLayout *_popup_form; + dialogs::DSDialog *_popup; }; diff --git a/DSView/pv/view/devmode.cpp b/DSView/pv/view/devmode.cpp index 05659b20..e34408b6 100755 --- a/DSView/pv/view/devmode.cpp +++ b/DSView/pv/view/devmode.cpp @@ -27,8 +27,7 @@ #include "../device/file.h" #include - -#include + #include #include diff --git a/DSView/pv/view/dsosignal.cpp b/DSView/pv/view/dsosignal.cpp index 615f2d31..7a295c5c 100755 --- a/DSView/pv/view/dsosignal.cpp +++ b/DSView/pv/view/dsosignal.cpp @@ -30,7 +30,7 @@ #include "../sigsession.h" #include "../device/devinst.h" -#include + #include #include diff --git a/DSView/pv/view/header.cpp b/DSView/pv/view/header.cpp index ec5db76c..c5c44314 100755 --- a/DSView/pv/view/header.cpp +++ b/DSView/pv/view/header.cpp @@ -35,7 +35,7 @@ #include -#include + #include #include @@ -107,7 +107,7 @@ boost::shared_ptr Header::get_mTrace( const vector< boost::shared_ptr > traces( _view.get_traces(ALL_VIEW)); - BOOST_FOREACH(const boost::shared_ptr t, traces) + for(auto &t : traces) { assert(t); @@ -136,7 +136,8 @@ void Header::paintEvent(QPaintEvent*) const bool dragging = !_drag_traces.empty(); QColor fore(QWidget::palette().color(QWidget::foregroundRole())); fore.setAlpha(View::ForeAlpha); - BOOST_FOREACH(const boost::shared_ptr t, traces) + + for(auto &t : traces) { assert(t); // auto ptr = t.get(); @@ -157,13 +158,13 @@ void Header::mouseDoubleClickEvent(QMouseEvent *event) _mouse_down_point = event->pos(); // Save the offsets of any Traces which will be dragged - BOOST_FOREACH(const boost::shared_ptr t, traces) + for(auto &t : traces) if (t->selected()) _drag_traces.push_back( make_pair(t, t->get_v_offset())); // Select the Trace if it has been clicked - BOOST_FOREACH(const boost::shared_ptr t, traces) + for(auto &t : traces) if (t->mouse_double_click(width(), event->pos())) break; } @@ -186,7 +187,7 @@ void Header::mousePressEvent(QMouseEvent *event) _mouse_down_point = event->pos(); // Save the offsets of any Traces which will be dragged - BOOST_FOREACH(const boost::shared_ptr t, traces) + for(auto &t : traces) if (t->selected()) _drag_traces.push_back( make_pair(t, t->get_v_offset())); @@ -207,14 +208,14 @@ void Header::mousePressEvent(QMouseEvent *event) mTrace->set_old_v_offset(mTrace->get_v_offset()); } - BOOST_FOREACH(const boost::shared_ptr t, traces) + for(auto &t : traces) if (t->mouse_press(width(), event->pos())) break; if (~QApplication::keyboardModifiers() & Qt::ControlModifier) { // Unselect all other Traces because the Ctrl is not // pressed - BOOST_FOREACH(const boost::shared_ptr t, traces) + for(auto &t : traces) if (t != mTrace) t->select(false); } @@ -248,7 +249,7 @@ void Header::mouseReleaseEvent(QMouseEvent *event) const vector< boost::shared_ptr > traces( _view.get_traces(ALL_VIEW)); - BOOST_FOREACH(const boost::shared_ptr t, traces) + for(auto &t : traces) t->select(false); } @@ -288,7 +289,7 @@ void Header::wheelEvent(QWheelEvent *event) #else shift = event->delta() / 80.0; #endif - BOOST_FOREACH(const boost::shared_ptr t, traces) + for(auto &t : traces) if (t->mouse_wheel(width(), event->pos(), shift)) break; update(); diff --git a/DSView/pv/view/lissajoustrace.cpp b/DSView/pv/view/lissajoustrace.cpp index f2c5959c..f1d307cc 100755 --- a/DSView/pv/view/lissajoustrace.cpp +++ b/DSView/pv/view/lissajoustrace.cpp @@ -30,7 +30,7 @@ #include "../sigsession.h" #include "../device/devinst.h" -#include + #include #include diff --git a/DSView/pv/view/mathtrace.cpp b/DSView/pv/view/mathtrace.cpp index fe838d9b..a61db919 100755 --- a/DSView/pv/view/mathtrace.cpp +++ b/DSView/pv/view/mathtrace.cpp @@ -31,8 +31,7 @@ #include "../sigsession.h" #include "../device/devinst.h" #include "../view/dsosignal.h" - -#include + #include #include diff --git a/DSView/pv/view/spectrumtrace.cpp b/DSView/pv/view/spectrumtrace.cpp index 64500c52..bb0ffcb9 100755 --- a/DSView/pv/view/spectrumtrace.cpp +++ b/DSView/pv/view/spectrumtrace.cpp @@ -22,7 +22,7 @@ #include #include -#include + #include #include "spectrumtrace.h" @@ -294,7 +294,8 @@ void SpectrumTrace::paint_mid(QPainter &p, int left, int right, QColor fore, QCo double vdiv = 0; double vfactor = 0; - BOOST_FOREACH(const boost::shared_ptr s, _session->get_signals()) { + + for(auto &s : _session->get_signals()) { boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s))) { if(dsoSig->get_index() == _spectrum_stack->get_index()) { diff --git a/DSView/pv/view/view.cpp b/DSView/pv/view/view.cpp index d9bb13d1..64220412 100755 --- a/DSView/pv/view/view.cpp +++ b/DSView/pv/view/view.cpp @@ -23,8 +23,7 @@ #include #include #include - -#include + #include #include @@ -389,22 +388,22 @@ vector< boost::shared_ptr > View::get_traces(int type) const vector< boost::shared_ptr > spectrums(_session->get_spectrum_traces()); vector< boost::shared_ptr > traces; - BOOST_FOREACH(boost::shared_ptr t, sigs) { + for(auto &t : sigs) { if (type == ALL_VIEW || _trace_view_map[t->get_type()] == type) traces.push_back(t); } - BOOST_FOREACH(boost::shared_ptr t, decode_sigs) { + for(auto &t : decode_sigs) { if (type == ALL_VIEW || _trace_view_map[t->get_type()] == type) traces.push_back(t); } - BOOST_FOREACH(boost::shared_ptr t, groups) { + for(auto &t : groups) { if (type == ALL_VIEW || _trace_view_map[t->get_type()] == type) traces.push_back(t); } - BOOST_FOREACH(boost::shared_ptr t, spectrums) { + for(auto &t : spectrums) { if (type == ALL_VIEW || _trace_view_map[t->get_type()] == type) traces.push_back(t); } @@ -586,15 +585,18 @@ const QPoint& View::hover_point() const void View::normalize_layout() { - const vector< boost::shared_ptr > traces(get_traces(ALL_VIEW)); + vector< boost::shared_ptr > traces(get_traces(ALL_VIEW)); int v_min = INT_MAX; - BOOST_FOREACH(const boost::shared_ptr t, traces) - v_min = min(t->get_v_offset(), v_min); + for(auto &t : traces){ + v_min = min(t->get_v_offset(), v_min); + } const int delta = -min(v_min, 0); - BOOST_FOREACH(boost::shared_ptr t, traces) + + for(auto &t : traces){ t->set_v_offset(t->get_v_offset() + delta); + } verticalScrollBar()->setSliderPosition(delta); v_scroll_value_changed(verticalScrollBar()->sliderPosition()); @@ -696,7 +698,7 @@ void View::signals_changed() vector< boost::shared_ptr > time_traces; vector< boost::shared_ptr > fft_traces; - BOOST_FOREACH(const boost::shared_ptr t, get_traces(ALL_VIEW)) { + for(auto &t : get_traces(ALL_VIEW)) { if (_trace_view_map[t->get_type()] == TIME_VIEW) time_traces.push_back(t); else if (_trace_view_map[t->get_type()] == FFT_VIEW) @@ -711,7 +713,7 @@ void View::signals_changed() _viewport_list.push_back(_fft_viewport); _vsplitter->refresh(); } - BOOST_FOREACH(boost::shared_ptr t, fft_traces) { + for(auto &t : fft_traces) { t->set_view(this); t->set_viewport(_fft_viewport); t->set_totalHeight(_fft_viewport->height()); @@ -732,7 +734,7 @@ void View::signals_changed() } if (!time_traces.empty() && _time_viewport) { - BOOST_FOREACH(const boost::shared_ptr t, time_traces) { + for(auto &t : time_traces) { assert(t); if (dynamic_pointer_cast(t) || t->enabled()) @@ -766,7 +768,8 @@ void View::signals_changed() } _spanY = _signalHeight + 2 * actualMargin; int next_v_offset = actualMargin; - BOOST_FOREACH(boost::shared_ptr t, time_traces) { + + for(auto &t : time_traces) { t->set_view(this); t->set_viewport(_time_viewport); if (t->rows_size() == 0) @@ -847,7 +850,7 @@ int View::headerWidth() const vector< boost::shared_ptr > traces(get_traces(ALL_VIEW)); if (!traces.empty()) { - BOOST_FOREACH(const boost::shared_ptr t, traces) + for(auto &t : traces) headerWidth = max(t->get_name_width() + t->get_leftWidth() + t->get_rightWidth(), headerWidth); } @@ -1090,7 +1093,7 @@ QRect View::get_view_rect() { if (_session->get_device()->dev_inst()->mode == DSO) { const vector< boost::shared_ptr > sigs(_session->get_signals()); - BOOST_FOREACH(const boost::shared_ptr s, sigs) { + for(auto &s : sigs) { return s->get_view_rect(); } } @@ -1103,7 +1106,7 @@ int View::get_view_width() int view_width = 0; if (_session->get_device()->dev_inst()->mode == DSO) { const vector< boost::shared_ptr > sigs(_session->get_signals()); - BOOST_FOREACH(const boost::shared_ptr s, sigs) { + for(auto &s : sigs) { view_width = max(view_width, s->get_view_rect().width()); } } else { @@ -1118,7 +1121,7 @@ int View::get_view_height() int view_height = 0; if (_session->get_device()->dev_inst()->mode == DSO) { const vector< boost::shared_ptr > sigs(_session->get_signals()); - BOOST_FOREACH(const boost::shared_ptr s, sigs) { + for(auto &s : sigs) { view_height = max(view_height, s->get_view_rect().height()); } } else { @@ -1193,7 +1196,7 @@ void View::show_region(uint64_t start, uint64_t end, bool keep) void View::viewport_update() { _viewcenter->update(); - BOOST_FOREACH(QWidget *viewport, _viewport_list) + for(QWidget *viewport : _viewport_list) viewport->update(); } diff --git a/DSView/pv/view/viewport.cpp b/DSView/pv/view/viewport.cpp index f4c475f6..5c548e63 100755 --- a/DSView/pv/view/viewport.cpp +++ b/DSView/pv/view/viewport.cpp @@ -39,7 +39,7 @@ #include #include #include -#include + #include "../config/appconfig.h" @@ -112,7 +112,7 @@ int Viewport::get_total_height() const int h = 0; const vector< boost::shared_ptr > traces(_view.get_traces(_type)); - BOOST_FOREACH(const boost::shared_ptr t, traces) { + for(auto &t : traces) { assert(t); h += (int)(t->get_totalHeight()); } @@ -150,7 +150,8 @@ void Viewport::paintEvent(QPaintEvent *event) fore.setAlpha(View::ForeAlpha); _view.set_back(false); const vector< boost::shared_ptr > traces(_view.get_traces(_type)); - BOOST_FOREACH(const boost::shared_ptr t, traces) + + for(auto &t : traces) { assert(t); @@ -186,7 +187,7 @@ void Viewport::paintEvent(QPaintEvent *event) paintSignals(p, fore, back); } - BOOST_FOREACH(const boost::shared_ptr t, traces) + for(auto &t : traces) { assert(t); if (t->enabled()) @@ -203,7 +204,8 @@ void Viewport::paintSignals(QPainter &p, QColor fore, QColor back) { const vector< boost::shared_ptr > traces(_view.get_traces(_type)); if (_view.session().get_device()->dev_inst()->mode == LOGIC) { - BOOST_FOREACH(const boost::shared_ptr t, traces) + + for(auto &t : traces) { assert(t); // auto ptr = t.get(); @@ -227,7 +229,7 @@ void Viewport::paintSignals(QPainter &p, QColor fore, QColor back) QPainter dbp(&pixmap); //dbp.begin(this); - BOOST_FOREACH(const boost::shared_ptr t, traces) + for(auto &t : traces) { assert(t); @@ -520,7 +522,8 @@ void Viewport::mousePressEvent(QMouseEvent *event) event->button() == Qt::LeftButton && _view.session().get_device()->dev_inst()->mode == DSO) { const vector< boost::shared_ptr > sigs(_view.session().get_signals()); - BOOST_FOREACH(const boost::shared_ptr s, sigs) { + + for(auto &s : sigs) { assert(s); if (!s->enabled()) continue; @@ -637,7 +640,7 @@ void Viewport::mouseMoveEvent(QMouseEvent *event) } _drag_strength = (_mouse_down_point - event->pos()).x(); } else if (_type == FFT_VIEW) { - BOOST_FOREACH(const boost::shared_ptr t, _view.session().get_spectrum_traces()) { + for(auto &t: _view.session().get_spectrum_traces()) { assert(t); if(t->enabled()) { double delta = (_mouse_point - event->pos()).x(); @@ -667,7 +670,8 @@ void Viewport::mouseMoveEvent(QMouseEvent *event) uint64_t index0 = 0, index1 = 0, index2 = 0; bool logic = false; const vector< boost::shared_ptr > sigs(_view.session().get_signals()); - BOOST_FOREACH(const boost::shared_ptr s, sigs) { + + for(auto &s: sigs) { assert(s); boost::shared_ptr logicSig; boost::shared_ptr dsoSig; @@ -730,7 +734,7 @@ void Viewport::mouseMoveEvent(QMouseEvent *event) } if (!(event->buttons() | Qt::NoButton)) { if (_action_type == DSO_XM_STEP1 || _action_type == DSO_XM_STEP2) { - BOOST_FOREACH(const boost::shared_ptr s, _view.session().get_signals()) { + for(auto &s : _view.session().get_signals()) { assert(s); if (!s->get_view_rect().contains(event->pos())) { clear_dso_xm(); @@ -784,7 +788,8 @@ void Viewport::mouseReleaseEvent(QMouseEvent *event) if (_action_type == NO_ACTION) { if (_mouse_down_point.x() == event->pos().x()) { const vector< boost::shared_ptr > sigs(_view.session().get_signals()); - BOOST_FOREACH(const boost::shared_ptr s, sigs) { + + for(auto &s : sigs) { assert(s); boost::shared_ptr logicSig; if ((logicSig = dynamic_pointer_cast(s))) { @@ -807,7 +812,8 @@ void Viewport::mouseReleaseEvent(QMouseEvent *event) if (_action_type == NO_ACTION) { if (_mouse_down_point.x() == event->pos().x()) { const vector< boost::shared_ptr > sigs(_view.session().get_signals()); - BOOST_FOREACH(const boost::shared_ptr s, sigs) { + + for(auto &s : sigs) { assert(s); if (abs(event->pos().y() - s->get_y()) < _view.get_signalHeight()) { _action_type = LOGIC_EDGE; @@ -844,7 +850,7 @@ void Viewport::mouseReleaseEvent(QMouseEvent *event) const vector< boost::shared_ptr > traces( _view.get_traces(ALL_VIEW)); - BOOST_FOREACH(const boost::shared_ptr t, traces) + for(auto &t : traces) t->select(false); } } else if (_action_type == DSO_XM_STEP0) { @@ -961,7 +967,7 @@ void Viewport::mouseDoubleClickEvent(QMouseEvent *event) uint64_t index0 = 0, index1 = 0, index2 = 0; if (_view.session().get_device()->dev_inst()->mode == LOGIC) { const vector< boost::shared_ptr > sigs(_view.session().get_signals()); - BOOST_FOREACH(const boost::shared_ptr s, sigs) { + for(auto &s : sigs) { assert(s); boost::shared_ptr logicSig; if ((logicSig = dynamic_pointer_cast(s))) { @@ -994,7 +1000,7 @@ void Viewport::mouseDoubleClickEvent(QMouseEvent *event) clear_dso_xm(); measure_updated(); } else if (_action_type == NO_ACTION) { - BOOST_FOREACH(const boost::shared_ptr s, _view.session().get_signals()) { + for(auto &s : _view.session().get_signals()) { assert(s); if (s->get_view_rect().contains(event->pos())) { _dso_xm_index[0] = _view.pixel2index(event->pos().x()); @@ -1020,7 +1026,7 @@ void Viewport::wheelEvent(QWheelEvent *event) assert(event); if (_type == FFT_VIEW) { - BOOST_FOREACH(const boost::shared_ptr t, _view.session().get_spectrum_traces()) { + for(auto &t : _view.session().get_spectrum_traces()) { assert(t); if(t->enabled()) { t->zoom(event->delta() / 80, event->x()); @@ -1061,7 +1067,7 @@ void Viewport::wheelEvent(QWheelEvent *event) } const vector< boost::shared_ptr > sigs(_view.session().get_signals()); - BOOST_FOREACH(const boost::shared_ptr s, sigs) { + for(auto &s : sigs) { assert(s); boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s))) { @@ -1169,7 +1175,8 @@ void Viewport::measure() if (_type == TIME_VIEW) { const uint64_t sample_rate = _view.session().cur_snap_samplerate(); const vector< boost::shared_ptr > sigs(_view.session().get_signals()); - BOOST_FOREACH(const boost::shared_ptr s, sigs) { + + for(auto &s : sigs) { assert(s); boost::shared_ptr logicSig; boost::shared_ptr dsoSig; @@ -1251,7 +1258,7 @@ void Viewport::measure() } } } else if (_type == FFT_VIEW) { - BOOST_FOREACH(const boost::shared_ptr t, _view.session().get_spectrum_traces()) { + for(auto &t : _view.session().get_spectrum_traces()) { assert(t); if(t->enabled()) { t->measure(_mouse_point); @@ -1325,7 +1332,8 @@ void Viewport::paintMeasure(QPainter &p, QColor fore, QColor back) const vector< boost::shared_ptr > sigs(_view.session().get_signals()); if (_action_type == NO_ACTION && _measure_type == DSO_VALUE) { - BOOST_FOREACH(const boost::shared_ptr s, sigs) { + + for(auto &s : sigs) { boost::shared_ptr dsoSig; boost::shared_ptr analogSig; if ((dsoSig = dynamic_pointer_cast(s))) { @@ -1353,7 +1361,7 @@ void Viewport::paintMeasure(QPainter &p, QColor fore, QColor back) } if (_dso_ym_valid) { - BOOST_FOREACH(const boost::shared_ptr s, sigs) { + for(auto &s : sigs) { boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s))) { if (dsoSig->get_index() == _dso_ym_sig_index) { diff --git a/DSView/pv/view/viewstatus.cpp b/DSView/pv/view/viewstatus.cpp index 739df933..27345f84 100755 --- a/DSView/pv/view/viewstatus.cpp +++ b/DSView/pv/view/viewstatus.cpp @@ -76,7 +76,8 @@ void ViewStatus::paintEvent(QPaintEvent *) int sig_index = std::get<1>(_mrects[i]); boost::shared_ptr dsoSig = NULL; const vector< boost::shared_ptr > sigs(_session->get_signals()); - BOOST_FOREACH(const boost::shared_ptr s, sigs) { + + for(auto &s : sigs) { assert(s); if (!s->enabled()) continue; @@ -187,8 +188,7 @@ void ViewStatus::mousePressEvent(QMouseEvent *event) if (_session->get_device()->dev_inst()->mode != DSO) return; - if (event->button() == Qt::LeftButton) { - //BOOST_FOREACH(QRect rect, std::get<0>(_mrects)) { + if (event->button() == Qt::LeftButton) { for(size_t i = 0; i < _mrects.size(); i++) { const QRect rect = std::get<0>(_mrects[i]); if (rect.contains(event->pos())) { diff --git a/DSView/pv/view/viewstatus.h b/DSView/pv/view/viewstatus.h index 56cfaa43..29bd473e 100755 --- a/DSView/pv/view/viewstatus.h +++ b/DSView/pv/view/viewstatus.h @@ -28,7 +28,7 @@ #include #include -#include + #include #include diff --git a/DSView/pv/view/xcursor.cpp b/DSView/pv/view/xcursor.cpp index a96daf20..eeecf6aa 100755 --- a/DSView/pv/view/xcursor.cpp +++ b/DSView/pv/view/xcursor.cpp @@ -28,8 +28,7 @@ #include "dsosignal.h" #include - -#include + using namespace boost; using namespace std; @@ -48,7 +47,8 @@ XCursor::XCursor(View &view, QColor &colour, { _dsoSig = NULL; const std::vector< boost::shared_ptr > sigs(_view.session().get_signals()); - BOOST_FOREACH(const boost::shared_ptr s, sigs) { + + for(auto &s : sigs) { boost::shared_ptr dsoSig; if ((dsoSig = dynamic_pointer_cast(s))) if (dsoSig->enabled()) { diff --git a/DSView/pv/widgets/decodergroupbox.cpp b/DSView/pv/widgets/decodergroupbox.cpp index a529c4df..2da50f7b 100755 --- a/DSView/pv/widgets/decodergroupbox.cpp +++ b/DSView/pv/widgets/decodergroupbox.cpp @@ -33,8 +33,7 @@ #include #include #include - -#include + #include "../config/appconfig.h" #include @@ -72,8 +71,7 @@ DecoderGroupBox::DecoderGroupBox(boost::shared_ptr &decoder_ } _index = 0; - BOOST_FOREACH(boost::shared_ptr dec, - _decoder_stack->stack()) { + for(auto &dec : _decoder_stack->stack()) { if (dec == _dec) break; _index++; @@ -137,8 +135,8 @@ void DecoderGroupBox::tog_icon() int index = id.toInt(); if (index == -1) { int i = _index; - BOOST_FOREACH(boost::shared_ptr dec, - _decoder_stack->stack()) { + + for(auto &dec : _decoder_stack->stack()) { if (i-- == 0) { dec->show(!dec->shown()); sc->setIcon(QIcon(dec->shown() ? iconPath+"/shown.svg" : @@ -164,8 +162,7 @@ void DecoderGroupBox::tog_icon() void DecoderGroupBox::on_del_stack() { int i = _index; - BOOST_FOREACH(boost::shared_ptr dec, - _decoder_stack->stack()) { + for(auto &dec : _decoder_stack->stack()) { if (i-- == 0) { del_stack(dec); break; From 1d3b8accfd1a95d8b6c982d8f03818a05b42334b Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Thu, 4 Nov 2021 15:38:42 +0800 Subject: [PATCH 20/60] remove all shared_ptr, remove all boost foreach --- DSView/mystyle.h | 2 +- DSView/pv/ZipMaker.cpp | 2 +- DSView/pv/config/appconfig.cpp | 10 +- DSView/pv/config/appconfig.h | 15 +- DSView/pv/data/analog.cpp | 5 +- DSView/pv/data/analog.h | 12 +- DSView/pv/data/analogsnapshot.cpp | 6 +- DSView/pv/data/analogsnapshot.h | 6 +- DSView/pv/data/decode/annotation.cpp | 22 +- DSView/pv/data/decode/annotation.h | 19 +- DSView/pv/data/decode/decoder.cpp | 67 +--- DSView/pv/data/decode/decoder.h | 44 ++- DSView/pv/data/decode/row.cpp | 9 +- DSView/pv/data/decode/row.h | 6 +- DSView/pv/data/decode/rowdata.cpp | 12 +- DSView/pv/data/decode/rowdata.h | 14 +- DSView/pv/data/decodermodel.cpp | 9 +- DSView/pv/data/decodermodel.h | 16 +- DSView/pv/data/decoderstack.cpp | 67 ++-- DSView/pv/data/decoderstack.h | 41 +- DSView/pv/data/dso.cpp | 5 +- DSView/pv/data/dso.h | 11 +- DSView/pv/data/dsosnapshot.cpp | 6 +- DSView/pv/data/dsosnapshot.h | 6 +- DSView/pv/data/group.cpp | 5 +- DSView/pv/data/group.h | 11 +- DSView/pv/data/groupsnapshot.cpp | 16 +- DSView/pv/data/groupsnapshot.h | 11 +- DSView/pv/data/logic.cpp | 8 +- DSView/pv/data/logic.h | 11 +- DSView/pv/data/mathstack.cpp | 20 +- DSView/pv/data/mathstack.h | 23 +- DSView/pv/data/snapshot.cpp | 20 +- DSView/pv/data/snapshot.h | 22 +- DSView/pv/data/spectrumstack.cpp | 26 +- DSView/pv/data/spectrumstack.h | 21 +- DSView/pv/device/device.cpp | 6 +- DSView/pv/device/device.h | 6 +- DSView/pv/device/devinst.cpp | 8 +- DSView/pv/device/devinst.h | 12 +- DSView/pv/device/file.cpp | 2 +- DSView/pv/device/file.h | 2 +- DSView/pv/device/inputfile.cpp | 2 +- DSView/pv/device/inputfile.h | 2 +- DSView/pv/device/sessionfile.cpp | 2 +- DSView/pv/device/sessionfile.h | 2 +- DSView/pv/dialogs/calibration.cpp | 2 +- DSView/pv/dialogs/calibration.h | 3 +- DSView/pv/dialogs/deviceoptions.cpp | 14 +- DSView/pv/dialogs/deviceoptions.h | 4 +- DSView/pv/dialogs/dsomeasure.cpp | 14 +- DSView/pv/dialogs/dsomeasure.h | 5 +- DSView/pv/dialogs/fftoptions.cpp | 16 +- DSView/pv/dialogs/fftoptions.h | 3 +- DSView/pv/dialogs/lissajousoptions.cpp | 12 +- DSView/pv/dialogs/lissajousoptions.h | 3 +- DSView/pv/dialogs/mathoptions.cpp | 14 +- DSView/pv/dialogs/mathoptions.h | 3 +- DSView/pv/dialogs/protocolexp.cpp | 13 +- DSView/pv/dialogs/protocolexp.h | 4 +- DSView/pv/dialogs/protocollist.cpp | 19 +- DSView/pv/dialogs/protocollist.h | 3 +- DSView/pv/dialogs/regionoptions.h | 4 +- DSView/pv/dialogs/search.cpp | 8 +- DSView/pv/dialogs/search.h | 4 +- DSView/pv/dialogs/shadow.cpp | 2 +- DSView/pv/dialogs/shadow.h | 8 +- DSView/pv/dialogs/storeprogress.h | 5 +- DSView/pv/dialogs/waitingdialog.cpp | 4 +- DSView/pv/dialogs/waitingdialog.h | 4 +- DSView/pv/dock/dsotriggerdock.cpp | 6 +- DSView/pv/dock/measuredock.cpp | 18 +- DSView/pv/dock/protocoldock.cpp | 40 +- DSView/pv/dock/searchdock.cpp | 11 +- DSView/pv/dsvdef.cpp | 7 + DSView/pv/dsvdef.h | 12 + DSView/pv/mainwindow.cpp | 69 ++-- DSView/pv/minizip/mztools.c | 4 +- DSView/pv/prop/binding/binding.cpp | 15 +- DSView/pv/prop/binding/binding.h | 14 +- DSView/pv/prop/binding/decoderoptions.cpp | 35 +- DSView/pv/prop/binding/decoderoptions.h | 12 +- DSView/pv/prop/binding/deviceoptions.cpp | 28 +- DSView/pv/prop/binding/probeoptions.cpp | 18 +- DSView/pv/prop/bool.cpp | 4 +- DSView/pv/prop/bool.h | 4 +- DSView/pv/prop/enum.cpp | 4 +- DSView/pv/prop/property.cpp | 12 +- DSView/pv/prop/property.h | 10 +- DSView/pv/sigsession.cpp | 439 ++++++++++------------ DSView/pv/sigsession.h | 110 +++--- DSView/pv/storesession.cpp | 91 ++--- DSView/pv/storesession.h | 13 +- DSView/pv/toolbars/filebar.cpp | 4 +- DSView/pv/toolbars/samplingbar.cpp | 18 +- DSView/pv/toolbars/samplingbar.h | 10 +- DSView/pv/toolbars/titlebar.cpp | 12 +- DSView/pv/toolbars/titlebar.h | 2 +- DSView/pv/view/analogsignal.cpp | 91 +++-- DSView/pv/view/analogsignal.h | 57 ++- DSView/pv/view/cursor.cpp | 4 +- DSView/pv/view/cursor.h | 4 +- DSView/pv/view/decodetrace.cpp | 87 +++-- DSView/pv/view/decodetrace.h | 60 +-- DSView/pv/view/devmode.cpp | 4 +- DSView/pv/view/devmode.h | 5 +- DSView/pv/view/dsldial.cpp | 14 +- DSView/pv/view/dsldial.h | 14 +- DSView/pv/view/dsosignal.cpp | 90 +++-- DSView/pv/view/dsosignal.h | 56 ++- DSView/pv/view/groupsignal.cpp | 24 +- DSView/pv/view/groupsignal.h | 15 +- DSView/pv/view/header.cpp | 61 ++- DSView/pv/view/header.h | 12 +- DSView/pv/view/lissajoustrace.cpp | 21 +- DSView/pv/view/lissajoustrace.h | 21 +- DSView/pv/view/logicsignal.cpp | 54 ++- DSView/pv/view/logicsignal.h | 30 +- DSView/pv/view/mathtrace.cpp | 28 +- DSView/pv/view/mathtrace.h | 34 +- DSView/pv/view/ruler.cpp | 17 +- DSView/pv/view/ruler.h | 2 +- DSView/pv/view/selectableitem.cpp | 2 +- DSView/pv/view/selectableitem.h | 4 +- DSView/pv/view/signal.cpp | 4 +- DSView/pv/view/signal.h | 9 +- DSView/pv/view/spectrumtrace.cpp | 26 +- DSView/pv/view/spectrumtrace.h | 24 +- DSView/pv/view/timemarker.cpp | 6 +- DSView/pv/view/timemarker.h | 10 +- DSView/pv/view/trace.cpp | 38 +- DSView/pv/view/trace.h | 41 +- DSView/pv/view/view.cpp | 99 ++--- DSView/pv/view/view.h | 37 +- DSView/pv/view/viewport.cpp | 126 ++++--- DSView/pv/view/viewport.h | 13 +- DSView/pv/view/viewstatus.cpp | 6 +- DSView/pv/view/viewstatus.h | 2 - DSView/pv/view/xcursor.cpp | 20 +- DSView/pv/view/xcursor.h | 23 +- DSView/pv/widgets/decodergroupbox.cpp | 4 +- DSView/pv/widgets/decodergroupbox.h | 13 +- 142 files changed, 1484 insertions(+), 1671 deletions(-) diff --git a/DSView/mystyle.h b/DSView/mystyle.h index c53bda52..e2cc768f 100644 --- a/DSView/mystyle.h +++ b/DSView/mystyle.h @@ -7,7 +7,7 @@ class MyStyle : public QProxyStyle { Q_OBJECT public: - int pixelMetric(PixelMetric metric, const QStyleOption * option = 0, const QWidget * widget = 0 ) const { + int pixelMetric(PixelMetric metric, const QStyleOption * option = 0, const QWidget * widget = 0 ) { int s = QProxyStyle::pixelMetric(metric, option, widget); if (metric == QStyle::PM_SmallIconSize) { s = 24; diff --git a/DSView/pv/ZipMaker.cpp b/DSView/pv/ZipMaker.cpp index add6a080..bf57dd14 100644 --- a/DSView/pv/ZipMaker.cpp +++ b/DSView/pv/ZipMaker.cpp @@ -262,7 +262,7 @@ const char *ZipMaker::GetError() break; } rdlen += dlen; - buf = buf + dlen; //move pointer + buf += dlen; //move pointer buflen = inf.dataLen - rdlen; } diff --git a/DSView/pv/config/appconfig.cpp b/DSView/pv/config/appconfig.cpp index 269b261f..3901c7bf 100644 --- a/DSView/pv/config/appconfig.cpp +++ b/DSView/pv/config/appconfig.cpp @@ -27,14 +27,14 @@ #define MAX_PROTOCOL_FORMAT_LIST 15 -StringPair::StringPair(const string &key, const string &value) +StringPair::StringPair(const std::string &key, const std::string &value) { m_key = key; m_value = value; } //------------function -QString FormatArrayToString(vector &protocolFormats){ +QString FormatArrayToString(std::vector &protocolFormats){ QString str; for (StringPair &o : protocolFormats){ @@ -49,7 +49,7 @@ QString FormatArrayToString(vector &protocolFormats){ return str; } -void StringToFormatArray(const QString &str, vector &protocolFormats){ +void StringToFormatArray(const QString &str, std::vector &protocolFormats){ QStringList arr = str.split(";"); for (int i=0; i #include -using namespace std; - + //--------------------api--- QString GetDirectoryName(QString path); @@ -40,9 +39,9 @@ QString GetIconPath(); class StringPair { public: - StringPair(const string &key, const string &value); - string m_key; - string m_value; + StringPair(const std::string &key, const std::string &value); + std::string m_key; + std::string m_value; }; @@ -52,7 +51,7 @@ struct AppOptions bool warnofMultiTrig; bool originalData; - vector m_protocolFormats; + std::vector m_protocolFormats; }; struct FrameOptions @@ -91,8 +90,8 @@ public: void SaveHistory(); void SaveFrame(); - void SetProtocolFormat(const string &protocolName, const string &value); - string GetProtocolFormat(const string &protocolName); + void SetProtocolFormat(const std::string &protocolName, const std::string &value); + std::string GetProtocolFormat(const std::string &protocolName); public: AppOptions _appOptions; diff --git a/DSView/pv/data/analog.cpp b/DSView/pv/data/analog.cpp index 85046322..4dfcc8c4 100755 --- a/DSView/pv/data/analog.cpp +++ b/DSView/pv/data/analog.cpp @@ -24,7 +24,6 @@ #include "analogsnapshot.h" -using namespace boost; using namespace std; namespace pv { @@ -35,12 +34,12 @@ Analog::Analog() : { } -void Analog::push_snapshot(boost::shared_ptr &snapshot) +void Analog::push_snapshot(AnalogSnapshot *snapshot) { _snapshots.push_front(snapshot); } -deque< boost::shared_ptr >& Analog::get_snapshots() +std::deque& Analog::get_snapshots() { return _snapshots; } diff --git a/DSView/pv/data/analog.h b/DSView/pv/data/analog.h index c28b649f..dbba04df 100755 --- a/DSView/pv/data/analog.h +++ b/DSView/pv/data/analog.h @@ -26,7 +26,7 @@ #include "signaldata.h" -#include + #include namespace pv { @@ -39,17 +39,13 @@ class Analog : public SignalData public: Analog(); - void push_snapshot( - boost::shared_ptr &snapshot); - - std::deque< boost::shared_ptr >& - get_snapshots(); - + void push_snapshot(AnalogSnapshot *snapshot); + std::deque& get_snapshots(); void clear(); void init(); private: - std::deque< boost::shared_ptr > _snapshots; + std::deque _snapshots; }; } // namespace data diff --git a/DSView/pv/data/analogsnapshot.cpp b/DSView/pv/data/analogsnapshot.cpp index 7da95a1a..0fb067f3 100755 --- a/DSView/pv/data/analogsnapshot.cpp +++ b/DSView/pv/data/analogsnapshot.cpp @@ -214,7 +214,7 @@ void AnalogSnapshot::append_data(void *data, uint64_t samples, uint16_t pitch) } } -const uint8_t* AnalogSnapshot::get_samples(int64_t start_sample) const +const uint8_t* AnalogSnapshot::get_samples(int64_t start_sample) { assert(start_sample >= 0); assert(start_sample < (int64_t)get_sample_count()); @@ -227,7 +227,7 @@ const uint8_t* AnalogSnapshot::get_samples(int64_t start_sample) const } void AnalogSnapshot::get_envelope_section(EnvelopeSection &s, - uint64_t start, int64_t count, float min_length, int probe_index) const + uint64_t start, int64_t count, float min_length, int probe_index) { assert(count >= 0); assert(min_length > 0); @@ -371,7 +371,7 @@ int AnalogSnapshot::get_ch_order(int sig_index) return order; } -int AnalogSnapshot::get_scale_factor() const +int AnalogSnapshot::get_scale_factor() { return EnvelopeScaleFactor; } diff --git a/DSView/pv/data/analogsnapshot.h b/DSView/pv/data/analogsnapshot.h index 0d6c1473..e9716a45 100755 --- a/DSView/pv/data/analogsnapshot.h +++ b/DSView/pv/data/analogsnapshot.h @@ -95,14 +95,14 @@ public: void append_payload(const sr_datafeed_analog &analog); - const uint8_t *get_samples(int64_t start_sample) const; + const uint8_t *get_samples(int64_t start_sample); void get_envelope_section(EnvelopeSection &s, - uint64_t start, int64_t count, float min_length, int probe_index) const; + uint64_t start, int64_t count, float min_length, int probe_index); int get_ch_order(int sig_index); - int get_scale_factor() const; + int get_scale_factor(); bool has_data(int index); int get_block_num(); diff --git a/DSView/pv/data/decode/annotation.cpp b/DSView/pv/data/decode/annotation.cpp index c0838d04..1949e0ec 100755 --- a/DSView/pv/data/decode/annotation.cpp +++ b/DSView/pv/data/decode/annotation.cpp @@ -172,26 +172,8 @@ Annotation::~Annotation() { } - -uint64_t Annotation::start_sample() const -{ - return _start_sample; -} - -uint64_t Annotation::end_sample() const -{ - return _end_sample; -} - -int Annotation::format() const -{ - return _format; -} - -int Annotation::type() const -{ - return _type; -} + + const std::vector& Annotation::annotations() const { diff --git a/DSView/pv/data/decode/annotation.h b/DSView/pv/data/decode/annotation.h index 46d3e2eb..2e8d359e 100755 --- a/DSView/pv/data/decode/annotation.h +++ b/DSView/pv/data/decode/annotation.h @@ -46,10 +46,21 @@ public: ~Annotation(); - uint64_t start_sample() const; - uint64_t end_sample() const; - int format() const; - int type() const; + inline uint64_t start_sample() const{ + return _start_sample; + } + + inline uint64_t end_sample() const{ + return _end_sample; + } + + inline int format() const{ + return _format; + } + + inline int type() const{ + return _type; + } public: const std::vector& annotations() const; diff --git a/DSView/pv/data/decode/decoder.cpp b/DSView/pv/data/decode/decoder.cpp index 94d1efe3..a9e4c66e 100755 --- a/DSView/pv/data/decode/decoder.cpp +++ b/DSView/pv/data/decode/decoder.cpp @@ -22,12 +22,9 @@ #include #include "decoder.h" +#include -using boost::shared_ptr; -using std::set; -using std::map; -using std::string; - + namespace pv { namespace data { namespace decode { @@ -41,44 +38,18 @@ Decoder::Decoder(const srd_decoder *const dec) : Decoder::~Decoder() { - for (map::const_iterator i = _options_back.begin(); + for (auto i = _options_back.begin(); i != _options_back.end(); i++) if ((*i).second) g_variant_unref((*i).second); } - -const srd_decoder* Decoder::decoder() const -{ - return _decoder; -} - -bool Decoder::shown() const -{ - return _shown; -} - -void Decoder::show(bool show) -{ - _shown = show; -} - -const map& -Decoder::channels() const -{ - return _probes; -} - -void Decoder::set_probes(std::map probes) + +void Decoder::set_probes(std::map probes) { _probes_back = probes; _setted = true; } - -const std::map& Decoder::options() const -{ - return _options; -} - + void Decoder::set_option(const char *id, GVariant *value) { assert(value); @@ -98,17 +69,7 @@ void Decoder::set_decode_region(uint64_t start, uint64_t end) _decode_end != end) _setted = true; } - -uint64_t Decoder::decode_start() const -{ - return _decode_start; -} - -uint64_t Decoder::decode_end() const -{ - return _decode_end; -} - + //apply setting bool Decoder::commit() { @@ -124,7 +85,7 @@ bool Decoder::commit() } } -bool Decoder::have_required_probes() const +bool Decoder::have_required_probes() { for (GSList *l = _decoder->channels; l; l = l->next) { const srd_channel *const pdch = (const srd_channel*)l->data; @@ -136,12 +97,12 @@ bool Decoder::have_required_probes() const return true; } -srd_decoder_inst* Decoder::create_decoder_inst(srd_session *session) const +srd_decoder_inst* Decoder::create_decoder_inst(srd_session *session) { GHashTable *const opt_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_variant_unref); - for (map::const_iterator i = _options.begin(); + for (auto i = _options.begin(); i != _options.end(); i++) { GVariant *const value = (*i).second; @@ -161,7 +122,7 @@ srd_decoder_inst* Decoder::create_decoder_inst(srd_session *session) const GHashTable *const probes = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_variant_unref); - for(map:: + for(std::map:: const_iterator i = _probes.begin(); i != _probes.end(); i++) { @@ -174,11 +135,7 @@ srd_decoder_inst* Decoder::create_decoder_inst(srd_session *session) const return decoder_inst; } - -int Decoder::get_channel_type(const srd_channel *ch) -{ - return ch->type; -} + } // decode } // data diff --git a/DSView/pv/data/decode/decoder.h b/DSView/pv/data/decode/decoder.h index 0309ae47..3d723bdb 100755 --- a/DSView/pv/data/decode/decoder.h +++ b/DSView/pv/data/decode/decoder.h @@ -27,9 +27,7 @@ #include #include #include - -#include - + #include struct srd_decoder; @@ -48,29 +46,49 @@ public: virtual ~Decoder(); - const srd_decoder* decoder() const; + inline const srd_decoder* decoder(){ + return _decoder; + } - bool shown() const; - void show(bool show = true); + inline bool shown(){ + return _shown; + } + + inline void show(bool show = true){ + _shown = show; + } + + inline std::map& channels(){ + return _probes; + } - const std::map& channels() const; void set_probes(std::map probes); - const std::map& options() const; + inline std::map& options(){ + return _options; + } void set_option(const char *id, GVariant *value); - bool have_required_probes() const; + bool have_required_probes(); - srd_decoder_inst* create_decoder_inst(srd_session *session) const; + srd_decoder_inst* create_decoder_inst(srd_session *session); void set_decode_region(uint64_t start, uint64_t end); - uint64_t decode_start() const; - uint64_t decode_end() const; + + inline uint64_t decode_start(){ + return _decode_start; + } + + inline uint64_t decode_end(){ + return _decode_end; + } bool commit(); - int get_channel_type(const srd_channel* ch); + inline int get_channel_type(const srd_channel* ch){ + return ch->type; + } private: const srd_decoder *const _decoder; diff --git a/DSView/pv/data/decode/row.cpp b/DSView/pv/data/decode/row.cpp index 63fef7c3..abe1633b 100755 --- a/DSView/pv/data/decode/row.cpp +++ b/DSView/pv/data/decode/row.cpp @@ -40,7 +40,14 @@ Row::Row(const srd_decoder *decoder, const srd_decoder_annotation_row *row, cons { } -const QString Row::title() const +Row::Row(const Row &o) +{ + _decoder = o._decoder; + _row = o._row; + _order = o._order; +} + +QString Row::title() const { if (_decoder && _decoder->name && _row && _row->desc) return QString("%1: %2") diff --git a/DSView/pv/data/decode/row.h b/DSView/pv/data/decode/row.h index b21f8093..b5c6cdd9 100755 --- a/DSView/pv/data/decode/row.h +++ b/DSView/pv/data/decode/row.h @@ -42,6 +42,8 @@ public: const srd_decoder_annotation_row *row = NULL, const int order = -1); + Row(const Row &o); + public: inline const srd_decoder* decoder() const{ @@ -52,9 +54,9 @@ public: return _row; } - const QString title() const; + QString title() const; - bool operator<(const Row &other) const; + bool operator<(const Row &other)const; private: const srd_decoder *_decoder; diff --git a/DSView/pv/data/decode/rowdata.cpp b/DSView/pv/data/decode/rowdata.cpp index 9ac049e9..e8ac9278 100755 --- a/DSView/pv/data/decode/rowdata.cpp +++ b/DSView/pv/data/decode/rowdata.cpp @@ -57,7 +57,7 @@ void RowData::clear() _item_count = 0; } -uint64_t RowData::get_max_sample() const +uint64_t RowData::get_max_sample() { std::lock_guard lock(_global_visitor_mutex); @@ -66,12 +66,12 @@ uint64_t RowData::get_max_sample() const return _annotations.back()->end_sample(); } -uint64_t RowData::get_max_annotation() const +uint64_t RowData::get_max_annotation() { return _max_annotation; } -uint64_t RowData::get_min_annotation() const +uint64_t RowData::get_min_annotation() { if (_min_annotation == UINT64_MAX) return 10; @@ -80,7 +80,7 @@ uint64_t RowData::get_min_annotation() const } void RowData::get_annotation_subset(std::vector &dest, - uint64_t start_sample, uint64_t end_sample) const + uint64_t start_sample, uint64_t end_sample) { std::lock_guard lock(_global_visitor_mutex); @@ -93,7 +93,7 @@ void RowData::get_annotation_subset(std::vector &d } } -uint64_t RowData::get_annotation_index(uint64_t start_sample) const +uint64_t RowData::get_annotation_index(uint64_t start_sample) { std::lock_guard lock(_global_visitor_mutex); uint64_t index = 0; @@ -131,7 +131,7 @@ bool RowData::push_annotation(Annotation *a) } -bool RowData::get_annotation(Annotation &ann, uint64_t index) const +bool RowData::get_annotation(Annotation &ann, uint64_t index) { std::lock_guard lock(_global_visitor_mutex); diff --git a/DSView/pv/data/decode/rowdata.h b/DSView/pv/data/decode/rowdata.h index 0059567f..e04af7a6 100755 --- a/DSView/pv/data/decode/rowdata.h +++ b/DSView/pv/data/decode/rowdata.h @@ -38,26 +38,26 @@ public: ~RowData(); public: - uint64_t get_max_sample() const; + uint64_t get_max_sample(); - uint64_t get_max_annotation() const; - uint64_t get_min_annotation() const; + uint64_t get_max_annotation(); + uint64_t get_min_annotation(); - uint64_t get_annotation_index(uint64_t start_sample) const; + uint64_t get_annotation_index(uint64_t start_sample); bool push_annotation(Annotation *a); - inline uint64_t get_annotation_size() const{ + inline uint64_t get_annotation_size(){ return _item_count; } - bool get_annotation(pv::data::decode::Annotation &ann, uint64_t index) const; + bool get_annotation(pv::data::decode::Annotation &ann, uint64_t index); /** * Extracts sorted annotations between two period into a vector. */ void get_annotation_subset(std::vector &dest, - uint64_t start_sample, uint64_t end_sample) const; + uint64_t start_sample, uint64_t end_sample); void clear(); diff --git a/DSView/pv/data/decodermodel.cpp b/DSView/pv/data/decodermodel.cpp index c42bab6a..dbf7f121 100755 --- a/DSView/pv/data/decodermodel.cpp +++ b/DSView/pv/data/decodermodel.cpp @@ -37,18 +37,13 @@ DecoderModel::DecoderModel(QObject *parent) { } -void DecoderModel::setDecoderStack(boost::shared_ptr decoder_stack) +void DecoderModel::setDecoderStack(DecoderStack *decoder_stack) { beginResetModel(); _decoder_stack = decoder_stack; endResetModel(); } - -const boost::shared_ptr& DecoderModel::getDecoderStack() const -{ - return _decoder_stack; -} - + int DecoderModel::rowCount(const QModelIndex & /* parent */) const { if (_decoder_stack) diff --git a/DSView/pv/data/decodermodel.h b/DSView/pv/data/decodermodel.h index 09032729..3a9d1760 100755 --- a/DSView/pv/data/decodermodel.h +++ b/DSView/pv/data/decodermodel.h @@ -22,9 +22,7 @@ #define DSVIEW_PV_DATA_DECODERMODEL_H #include - -#include - + #include namespace pv { @@ -46,14 +44,16 @@ public: int rowCount(const QModelIndex & /*parent*/) const; int columnCount(const QModelIndex & /*parent*/) const; QVariant data(const QModelIndex &index, int role) const; - QVariant headerData(int section, Qt::Orientation orientation, - int role) const; + QVariant headerData(int section, Qt::Orientation orientation,int role) const; - void setDecoderStack(boost::shared_ptr decoder_stack); - const boost::shared_ptr& getDecoderStack() const; + void setDecoderStack(DecoderStack *decoder_stack); + + inline DecoderStack* getDecoderStack(){ + return _decoder_stack; + } private: - boost::shared_ptr _decoder_stack; + DecoderStack *_decoder_stack; }; } // namespace data diff --git a/DSView/pv/data/decoderstack.cpp b/DSView/pv/data/decoderstack.cpp index 72d094ce..09d3dcf4 100755 --- a/DSView/pv/data/decoderstack.cpp +++ b/DSView/pv/data/decoderstack.cpp @@ -35,12 +35,11 @@ #include "../sigsession.h" #include "../view/logicsignal.h" #include "../dsvdef.h" - - -using namespace boost; -using namespace std; +#include using namespace pv::data::decode; +using namespace std; +using namespace boost; namespace pv { namespace data { @@ -57,6 +56,10 @@ DecoderStack::DecoderStack(pv::SigSession *session, const srd_decoder *const dec, DecoderStatus *decoder_status) : _session(session) { + assert(session); + assert(dec); + assert(decoder_status); + _samples_decoded = 0; _sample_count = 0; _frame_complete = false; @@ -75,8 +78,7 @@ DecoderStack::DecoderStack(pv::SigSession *session, connect(_session, SIGNAL(frame_ended()), this, SLOT(on_frame_ended())); - _stack.push_back(boost::shared_ptr( - new decode::Decoder(dec))); + _stack.push_back(new decode::Decoder(dec)); build_row(); } @@ -97,7 +99,7 @@ DecoderStack::~DecoderStack() _class_rows.clear(); } -void DecoderStack::push(boost::shared_ptr decoder) +void DecoderStack::push(decode::Decoder *decoder) { assert(decoder); _stack.push_back(decoder); @@ -105,10 +107,10 @@ void DecoderStack::push(boost::shared_ptr decoder) _options_changed = true; } -void DecoderStack::remove(boost::shared_ptr &decoder) +void DecoderStack::remove(Decoder *decoder) { // Find the decoder in the stack - list< boost::shared_ptr >::iterator iter = _stack.begin(); + auto iter = _stack.begin(); for(unsigned int i = 0; i < _stack.size(); i++, iter++) if ((*iter) == decoder) break; @@ -187,7 +189,7 @@ void DecoderStack::build_row() } } -int64_t DecoderStack::samples_decoded() const +int64_t DecoderStack::samples_decoded() { std::lock_guard decode_lock(_output_mutex); return _samples_decoded; @@ -196,7 +198,7 @@ int64_t DecoderStack::samples_decoded() const void DecoderStack::get_annotation_subset( std::vector &dest, const Row &row, uint64_t start_sample, - uint64_t end_sample) const + uint64_t end_sample) { auto iter = _rows.find(row); if (iter != _rows.end()) @@ -206,7 +208,7 @@ void DecoderStack::get_annotation_subset( uint64_t DecoderStack::get_annotation_index( - const Row &row, uint64_t start_sample) const + const Row &row, uint64_t start_sample) { uint64_t index = 0; auto iter = _rows.find(row); @@ -270,7 +272,7 @@ void DecoderStack::set_rows_lshow(const decode::Row row, bool show) } } -bool DecoderStack::has_annotations(const Row &row) const +bool DecoderStack::has_annotations(const Row &row) { auto iter = _rows.find(row); @@ -283,13 +285,13 @@ bool DecoderStack::has_annotations(const Row &row) const return false; } -uint64_t DecoderStack::list_annotation_size() const +uint64_t DecoderStack::list_annotation_size() { std::lock_guard lock(_output_mutex); uint64_t max_annotation_size = 0; for (auto i = _rows.begin(); i != _rows.end(); i++) { - map::const_iterator iter = _rows_lshow.find((*i).first); + auto iter = _rows_lshow.find((*i).first); if (iter != _rows_lshow.end() && (*iter).second) max_annotation_size = max(max_annotation_size, (*i).second->get_annotation_size()); @@ -298,11 +300,11 @@ uint64_t DecoderStack::list_annotation_size() const return max_annotation_size; } -uint64_t DecoderStack::list_annotation_size(uint16_t row_index) const +uint64_t DecoderStack::list_annotation_size(uint16_t row_index) { for (auto i = _rows.begin(); i != _rows.end(); i++) { - map::const_iterator iter = _rows_lshow.find((*i).first); + auto iter = _rows_lshow.find((*i).first); if (iter != _rows_lshow.end() && (*iter).second) if (row_index-- == 0) { return (*i).second->get_annotation_size(); @@ -312,11 +314,11 @@ uint64_t DecoderStack::list_annotation_size(uint16_t row_index) const } bool DecoderStack::list_annotation(pv::data::decode::Annotation &ann, - uint16_t row_index, uint64_t col_index) const + uint16_t row_index, uint64_t col_index) { for (auto i = _rows.begin(); i != _rows.end(); i++) { - map::const_iterator iter = _rows_lshow.find((*i).first); + auto iter = _rows_lshow.find((*i).first); if (iter != _rows_lshow.end() && (*iter).second) { if (row_index-- == 0) { return (*i).second->get_annotation(ann, col_index); @@ -328,11 +330,11 @@ bool DecoderStack::list_annotation(pv::data::decode::Annotation &ann, } -bool DecoderStack::list_row_title(int row, QString &title) const +bool DecoderStack::list_row_title(int row, QString &title) { for (auto i = _rows.begin(); i != _rows.end(); i++) { - map::const_iterator iter = _rows_lshow.find((*i).first); + auto iter = _rows_lshow.find((*i).first); if (iter != _rows_lshow.end() && (*iter).second) { if (row-- == 0) { title = (*i).first.title(); @@ -385,8 +387,8 @@ void DecoderStack::stop_decode() void DecoderStack::begin_decode() { - boost::shared_ptr logic_signal; - boost::shared_ptr data; + pv::view::LogicSignal *logic_signal = NULL; + pv::data::Logic *data = NULL; if (!_options_changed) return; @@ -409,7 +411,7 @@ void DecoderStack::begin_decode() if (dec && !dec->channels().empty()) { for(auto &sig : _session->get_signals()) { if((sig->get_index() == (*dec->channels().begin()).second) && - (logic_signal = dynamic_pointer_cast(sig)) && + (logic_signal = dynamic_cast(sig)) && (data = logic_signal->logic_data())) break; } @@ -422,8 +424,7 @@ void DecoderStack::begin_decode() return; // Check we have a snapshot of data - const deque< boost::shared_ptr > &snapshots = - data->get_snapshots(); + const auto &snapshots = data->get_snapshots(); if (snapshots.empty()) return; _snapshot = snapshots.front(); @@ -445,7 +446,7 @@ void DecoderStack::begin_decode() _decode_thread = new std::thread(&DecoderStack::decode_proc, this); } -uint64_t DecoderStack::get_max_sample_count() const +uint64_t DecoderStack::get_max_sample_count() { uint64_t max_sample_count = 0; @@ -596,7 +597,7 @@ void DecoderStack::decode_proc() _decode_state = Stopped; } -uint64_t DecoderStack::sample_count() const +uint64_t DecoderStack::sample_count() { if (_snapshot) return _snapshot->get_sample_count(); @@ -604,7 +605,7 @@ uint64_t DecoderStack::sample_count() const return 0; } -uint64_t DecoderStack::sample_rate() const +uint64_t DecoderStack::sample_rate() { return _samplerate; } @@ -679,14 +680,14 @@ int DecoderStack::list_rows_size() { int rows_size = 0; for (auto i = _rows.begin(); i != _rows.end(); i++) { - map::const_iterator iter = _rows_lshow.find((*i).first); + auto iter = _rows_lshow.find((*i).first); if (iter != _rows_lshow.end() && (*iter).second) rows_size++; } return rows_size; } -bool DecoderStack::options_changed() const +bool DecoderStack::options_changed() { return _options_changed; } @@ -696,7 +697,7 @@ void DecoderStack::set_options_changed(bool changed) _options_changed = changed; } -bool DecoderStack::out_of_memory() const +bool DecoderStack::out_of_memory() { return _no_memory; } @@ -706,7 +707,7 @@ void DecoderStack::set_mark_index(int64_t index) _mark_index = index; } -int64_t DecoderStack::get_mark_index() const +int64_t DecoderStack::get_mark_index() { return _mark_index; } diff --git a/DSView/pv/data/decoderstack.h b/DSView/pv/data/decoderstack.h index d7f89bf1..c30455b7 100755 --- a/DSView/pv/data/decoderstack.h +++ b/DSView/pv/data/decoderstack.h @@ -25,8 +25,7 @@ #include -#include -#include +#include #include @@ -88,17 +87,17 @@ public: virtual ~DecoderStack(); - inline std::list< boost::shared_ptr >& stack(){ + inline std::list& stack(){ return _stack; } - void push(boost::shared_ptr decoder); + void push(decode::Decoder *decoder); - void remove(boost::shared_ptr& decoder); + void remove(decode::Decoder *decoder); void build_row(); - int64_t samples_decoded() const; + int64_t samples_decoded(); /** * Extracts sorted annotations between two period into a vector. @@ -106,10 +105,10 @@ public: void get_annotation_subset( std::vector &dest, const decode::Row &row, uint64_t start_sample, - uint64_t end_sample) const; + uint64_t end_sample); uint64_t get_annotation_index( - const decode::Row &row, uint64_t start_sample) const; + const decode::Row &row, uint64_t start_sample); uint64_t get_max_annotation(const decode::Row &row); uint64_t get_min_annotation(const decode::Row &row); // except instant(end=start) annotation @@ -119,24 +118,24 @@ public: void set_rows_gshow(const decode::Row row, bool show); void set_rows_lshow(const decode::Row row, bool show); - bool has_annotations(const decode::Row &row) const; + bool has_annotations(const decode::Row &row); - uint64_t list_annotation_size() const; - uint64_t list_annotation_size(uint16_t row_index) const; + uint64_t list_annotation_size(); + uint64_t list_annotation_size(uint16_t row_index); bool list_annotation(decode::Annotation &ann, - uint16_t row_index, uint64_t col_index) const; + uint16_t row_index, uint64_t col_index); - bool list_row_title(int row, QString &title) const; + bool list_row_title(int row, QString &title); QString error_message(); void clear(); void init(); - uint64_t get_max_sample_count() const; + uint64_t get_max_sample_count(); void begin_decode(); @@ -144,16 +143,16 @@ public: int list_rows_size(); - bool options_changed() const; + bool options_changed(); void set_options_changed(bool changed); - uint64_t sample_count() const; - uint64_t sample_rate() const; + uint64_t sample_count(); + uint64_t sample_rate(); - bool out_of_memory() const; + bool out_of_memory(); void set_mark_index(int64_t index); - int64_t get_mark_index() const; + int64_t get_mark_index(); private: void decode_data(const uint64_t decode_start, const uint64_t decode_end, srd_session *const session); @@ -174,9 +173,9 @@ signals: void decode_done(); private: - std::list< boost::shared_ptr > _stack; + std::list _stack; - boost::shared_ptr _snapshot; + pv::data::LogicSnapshot *_snapshot; std::map _rows; std::map _rows_gshow; diff --git a/DSView/pv/data/dso.cpp b/DSView/pv/data/dso.cpp index b88e77d7..acbd6c62 100755 --- a/DSView/pv/data/dso.cpp +++ b/DSView/pv/data/dso.cpp @@ -23,7 +23,6 @@ #include "dsosnapshot.h" -using namespace boost; using namespace std; namespace pv { @@ -34,12 +33,12 @@ Dso::Dso() : { } -void Dso::push_snapshot(boost::shared_ptr &snapshot) +void Dso::push_snapshot(DsoSnapshot *snapshot) { _snapshots.push_front(snapshot); } -deque< boost::shared_ptr >& Dso::get_snapshots() +std::deque& Dso::get_snapshots() { return _snapshots; } diff --git a/DSView/pv/data/dso.h b/DSView/pv/data/dso.h index 0902972a..1ef87645 100755 --- a/DSView/pv/data/dso.h +++ b/DSView/pv/data/dso.h @@ -24,8 +24,7 @@ #define DSVIEW_PV_DATA_DSO_H #include "signaldata.h" - -#include + #include namespace pv { @@ -38,17 +37,15 @@ class Dso : public SignalData public: Dso(); - void push_snapshot( - boost::shared_ptr &snapshot); + void push_snapshot(DsoSnapshot *snapshot); - std::deque< boost::shared_ptr >& - get_snapshots(); + std::deque& get_snapshots(); void clear(); void init(); private: - std::deque< boost::shared_ptr > _snapshots; + std::deque _snapshots; }; } // namespace data diff --git a/DSView/pv/data/dsosnapshot.cpp b/DSView/pv/data/dsosnapshot.cpp index 60a98a8c..db56da10 100755 --- a/DSView/pv/data/dsosnapshot.cpp +++ b/DSView/pv/data/dsosnapshot.cpp @@ -210,7 +210,7 @@ const uint8_t *DsoSnapshot::get_samples( } void DsoSnapshot::get_envelope_section(EnvelopeSection &s, - uint64_t start, uint64_t end, float min_length, int probe_index) const + uint64_t start, uint64_t end, float min_length, int probe_index) { assert(end <= get_sample_count()); assert(start <= end); @@ -348,7 +348,7 @@ void DsoSnapshot::append_payload_to_envelope_levels(bool header) _envelope_done = true; } -double DsoSnapshot::cal_vrms(double zero_off, int index) const +double DsoSnapshot::cal_vrms(double zero_off, int index) { assert(index >= 0); //assert(index < _channel_num); @@ -383,7 +383,7 @@ double DsoSnapshot::cal_vrms(double zero_off, int index) const return vrms; } -double DsoSnapshot::cal_vmean(int index) const +double DsoSnapshot::cal_vmean(int index) { assert(index >= 0); //assert(index < _channel_num); diff --git a/DSView/pv/data/dsosnapshot.h b/DSView/pv/data/dsosnapshot.h index f9586efe..b32eb78f 100755 --- a/DSView/pv/data/dsosnapshot.h +++ b/DSView/pv/data/dsosnapshot.h @@ -95,12 +95,12 @@ public: int64_t end_sample, uint16_t index); void get_envelope_section(EnvelopeSection &s, - uint64_t start, uint64_t end, float min_length, int probe_index) const; + uint64_t start, uint64_t end, float min_length, int probe_index); void enable_envelope(bool enable); - double cal_vrms(double zero_off, int index) const; - double cal_vmean(int index) const; + double cal_vrms(double zero_off, int index); + double cal_vmean(int index); bool has_data(int index); int get_block_num(); diff --git a/DSView/pv/data/group.cpp b/DSView/pv/data/group.cpp index 41329f82..04f699a1 100755 --- a/DSView/pv/data/group.cpp +++ b/DSView/pv/data/group.cpp @@ -23,7 +23,6 @@ #include "groupsnapshot.h" -using namespace boost; using namespace std; namespace pv { @@ -34,12 +33,12 @@ Group::Group() : { } -void Group::push_snapshot(boost::shared_ptr &snapshot) +void Group::push_snapshot(GroupSnapshot *snapshot) { _snapshots.push_back(snapshot); } -deque< boost::shared_ptr >& Group::get_snapshots() +std::deque& Group::get_snapshots() { return _snapshots; } diff --git a/DSView/pv/data/group.h b/DSView/pv/data/group.h index 1312c6ee..bc6e4e53 100755 --- a/DSView/pv/data/group.h +++ b/DSView/pv/data/group.h @@ -24,8 +24,7 @@ #define DSVIEW_PV_DATA_GROUP_H #include "signaldata.h" - -#include + #include namespace pv { @@ -38,17 +37,15 @@ class Group : public SignalData public: Group(); - void push_snapshot( - boost::shared_ptr &snapshot); + void push_snapshot(GroupSnapshot *snapshot); - std::deque< boost::shared_ptr >& - get_snapshots(); + std::deque& get_snapshots(); void clear(); void init(); private: - std::deque< boost::shared_ptr > _snapshots; + std::deque _snapshots; }; } // namespace data diff --git a/DSView/pv/data/groupsnapshot.cpp b/DSView/pv/data/groupsnapshot.cpp index 3c5f25ee..3eae0efb 100755 --- a/DSView/pv/data/groupsnapshot.cpp +++ b/DSView/pv/data/groupsnapshot.cpp @@ -27,12 +27,10 @@ #include #include - #include "logicsnapshot.h" #include "groupsnapshot.h" -using namespace boost; using namespace std; namespace pv { @@ -48,15 +46,17 @@ const uint16_t GroupSnapshot::value_mask[16] = {0x1, 0x2, 0x4, 0x8, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000}; -GroupSnapshot::GroupSnapshot(const boost::shared_ptr &_logic_snapshot, std::list index_list) +GroupSnapshot::GroupSnapshot(const LogicSnapshot *_logic_snapshot, std::list index_list) { assert(_logic_snapshot); + LogicSnapshot *logic_snapshot = const_cast(_logic_snapshot); + memset(_envelope_levels, 0, sizeof(_envelope_levels)); - _data = _logic_snapshot->get_data(); - _sample_count = _logic_snapshot->get_sample_count(); - _unit_size = _logic_snapshot->unit_size(); + _data = logic_snapshot->get_data(); + _sample_count = logic_snapshot->get_sample_count(); + _unit_size = logic_snapshot->unit_size(); _index_list = index_list; _mask = 0; @@ -108,7 +108,7 @@ void GroupSnapshot::clear() } -uint64_t GroupSnapshot::get_sample_count() const +uint64_t GroupSnapshot::get_sample_count() { return _sample_count; } @@ -150,7 +150,7 @@ const uint16_t* GroupSnapshot::get_samples( } void GroupSnapshot::get_envelope_section(EnvelopeSection &s, - uint64_t start, uint64_t end, float min_length) const + uint64_t start, uint64_t end, float min_length) { assert(end <= _sample_count); assert(start <= end); diff --git a/DSView/pv/data/groupsnapshot.h b/DSView/pv/data/groupsnapshot.h index fbd7095e..683e4f96 100755 --- a/DSView/pv/data/groupsnapshot.h +++ b/DSView/pv/data/groupsnapshot.h @@ -22,10 +22,7 @@ #ifndef DSVIEW_PV_DATA_GROUPSNAPSHOT_H #define DSVIEW_PV_DATA_GROUPSNAPSHOT_H - -#include - #include "../view/signal.h" #include @@ -75,7 +72,7 @@ private: static const uint16_t value_mask[16]; public: - GroupSnapshot(const boost::shared_ptr &_logic_snapshot, std::list index_list); + GroupSnapshot(const LogicSnapshot *_logic_snapshot, std::list index_list); virtual ~GroupSnapshot(); @@ -84,13 +81,13 @@ public: void append_payload(); - uint64_t get_sample_count() const; + uint64_t get_sample_count(); const uint16_t* get_samples(int64_t start_sample, int64_t end_sample); void get_envelope_section(EnvelopeSection &s, - uint64_t start, uint64_t end, float min_length) const; + uint64_t start, uint64_t end, float min_length); private: void reallocate_envelope(Envelope &l); @@ -103,7 +100,7 @@ private: const void *_data; uint64_t _sample_count; int _unit_size; - boost::shared_ptr _signal; + view::Signal *_signal; std::list _index_list; uint16_t _mask; int _bubble_start[32]; diff --git a/DSView/pv/data/logic.cpp b/DSView/pv/data/logic.cpp index d2597125..71055656 100755 --- a/DSView/pv/data/logic.cpp +++ b/DSView/pv/data/logic.cpp @@ -22,8 +22,7 @@ #include "logic.h" #include "logicsnapshot.h" - -using namespace boost; + using namespace std; namespace pv { @@ -34,13 +33,12 @@ Logic::Logic() : { } -void Logic::push_snapshot( - boost::shared_ptr &snapshot) +void Logic::push_snapshot(LogicSnapshot *snapshot) { _snapshots.push_front(snapshot); } -deque< boost::shared_ptr >& Logic::get_snapshots() +std::deque& Logic::get_snapshots() { return _snapshots; } diff --git a/DSView/pv/data/logic.h b/DSView/pv/data/logic.h index f163b35c..2eb76aed 100755 --- a/DSView/pv/data/logic.h +++ b/DSView/pv/data/logic.h @@ -25,8 +25,7 @@ #define DSVIEW_PV_DATA_LOGIC_H #include "signaldata.h" - -#include + #include namespace pv { @@ -39,18 +38,16 @@ class Logic : public SignalData public: Logic(); - void push_snapshot( - boost::shared_ptr &snapshot); + void push_snapshot(LogicSnapshot *snapshot); - std::deque< boost::shared_ptr >& - get_snapshots(); + std::deque& get_snapshots(); void clear(); void init(); private: - std::deque< boost::shared_ptr > _snapshots; + std::deque _snapshots; }; } // namespace data diff --git a/DSView/pv/data/mathstack.cpp b/DSView/pv/data/mathstack.cpp index e584d392..87dd08cd 100755 --- a/DSView/pv/data/mathstack.cpp +++ b/DSView/pv/data/mathstack.cpp @@ -73,8 +73,8 @@ const QString MathStack::vDialDivUnit[MathStack::vDialUnitCount] = { }; MathStack::MathStack(pv::SigSession *session, - boost::shared_ptr dsoSig1, - boost::shared_ptr dsoSig2, + view::DsoSignal* dsoSig1, + view::DsoSignal* dsoSig2, MathType type) : _session(session), _dsoSig1(dsoSig1), @@ -117,12 +117,12 @@ void MathStack::init() _envelope_done = false; } -MathStack::MathType MathStack::get_type() const +MathStack::MathType MathStack::get_type() { return _type; } -uint64_t MathStack::get_sample_num() const +uint64_t MathStack::get_sample_num() { return _sample_num; } @@ -276,13 +276,13 @@ double MathStack::get_math_scale() return scale; } -const double* MathStack::get_math(uint64_t start) const +const double* MathStack::get_math(uint64_t start) { return _math.data() + start; } void MathStack::get_math_envelope_section(EnvelopeSection &s, - uint64_t start, uint64_t end, float min_length) const + uint64_t start, uint64_t end, float min_length) { assert(end <= get_sample_num()); assert(start <= end); @@ -316,14 +316,12 @@ void MathStack::calc_math() _math_state = Running; - const boost::shared_ptr data = _dsoSig1->dso_data(); - const deque< boost::shared_ptr > &snapshots = - data->get_snapshots(); + const auto data = _dsoSig1->dso_data(); + const auto &snapshots = data->get_snapshots(); if (snapshots.empty()) return; - const boost::shared_ptr &snapshot = - snapshots.front(); + const auto snapshot = snapshots.front(); if (snapshot->empty()) return; diff --git a/DSView/pv/data/mathstack.h b/DSView/pv/data/mathstack.h index e0c1a97c..2fb72fbc 100755 --- a/DSView/pv/data/mathstack.h +++ b/DSView/pv/data/mathstack.h @@ -25,9 +25,8 @@ #include -#include -#include - +#include + #include #include @@ -103,16 +102,16 @@ private: public: MathStack(pv::SigSession *_session, - boost::shared_ptr dsoSig1, - boost::shared_ptr dsoSig2, MathType type); + view::DsoSignal *dsoSig1, + view::DsoSignal *dsoSig2, MathType type); virtual ~MathStack(); void clear(); void init(); void free_envelop(); void realloc(uint64_t num); - MathType get_type() const; - uint64_t get_sample_num() const; + MathType get_type(); + uint64_t get_sample_num(); void enable_envelope(bool enable); @@ -121,9 +120,9 @@ public: QString get_unit(int level); double get_math_scale(); - const double *get_math(uint64_t start) const; + const double *get_math(uint64_t start); void get_math_envelope_section(EnvelopeSection &s, - uint64_t start, uint64_t end, float min_length) const; + uint64_t start, uint64_t end, float min_length); void calc_math(); void reallocate_envelope(Envelope &e); @@ -132,9 +131,9 @@ public: signals: private: - pv::SigSession *_session; - boost::shared_ptr _dsoSig1; - boost::shared_ptr _dsoSig2; + pv::SigSession *_session; + view::DsoSignal *_dsoSig1; + view::DsoSignal *_dsoSig2; MathType _type; uint64_t _sample_num; diff --git a/DSView/pv/data/snapshot.cpp b/DSView/pv/data/snapshot.cpp index 2e50fc2c..773ea130 100755 --- a/DSView/pv/data/snapshot.cpp +++ b/DSView/pv/data/snapshot.cpp @@ -64,12 +64,12 @@ void Snapshot::free_data() _ch_index.clear(); } -bool Snapshot::memory_failed() const +bool Snapshot::memory_failed() { return _memory_failed; } -bool Snapshot::empty() const +bool Snapshot::empty() { if (get_sample_count() == 0) return true; @@ -77,7 +77,7 @@ bool Snapshot::empty() const return false; } -bool Snapshot::last_ended() const +bool Snapshot::last_ended() { return _last_ended; } @@ -87,13 +87,13 @@ void Snapshot::set_last_ended(bool ended) _last_ended = ended; } -uint64_t Snapshot::get_sample_count() const +uint64_t Snapshot::get_sample_count() { std::lock_guard lock(_mutex); return _sample_count; } -uint64_t Snapshot::get_ring_start() const +uint64_t Snapshot::get_ring_start() { std::lock_guard lock(_mutex); if (_sample_count < _total_sample_count) @@ -102,7 +102,7 @@ uint64_t Snapshot::get_ring_start() const return _ring_sample_count; } -uint64_t Snapshot::get_ring_end() const +uint64_t Snapshot::get_ring_end() { std::lock_guard lock(_mutex); if (_sample_count == 0) @@ -113,22 +113,22 @@ uint64_t Snapshot::get_ring_end() const return _ring_sample_count - 1; } -const void* Snapshot::get_data() const +const void* Snapshot::get_data() { return _data; } -int Snapshot::unit_size() const +int Snapshot::unit_size() { return _unit_size; } -uint8_t Snapshot::get_unit_bytes() const +uint8_t Snapshot::get_unit_bytes() { return _unit_bytes; } -unsigned int Snapshot::get_channel_num() const +unsigned int Snapshot::get_channel_num() { return _channel_num; } diff --git a/DSView/pv/data/snapshot.h b/DSView/pv/data/snapshot.h index e8a43588..79de9589 100755 --- a/DSView/pv/data/snapshot.h +++ b/DSView/pv/data/snapshot.h @@ -39,22 +39,22 @@ public: virtual void clear() = 0; virtual void init() = 0; - uint64_t get_sample_count() const; - uint64_t get_ring_start() const; - uint64_t get_ring_end() const; + uint64_t get_sample_count(); + uint64_t get_ring_start(); + uint64_t get_ring_end(); - const void * get_data() const; + const void * get_data(); - int unit_size() const; - uint8_t get_unit_bytes() const; + int unit_size(); + uint8_t get_unit_bytes(); - bool memory_failed() const; - bool empty() const; + bool memory_failed(); + bool empty(); - bool last_ended() const; + bool last_ended(); void set_last_ended(bool ended); - unsigned int get_channel_num() const; + unsigned int get_channel_num(); virtual void capture_ended(); virtual bool has_data(int index) = 0; @@ -67,7 +67,7 @@ protected: protected: mutable std::mutex _mutex; - //std::vector _data; + void* _data; mutable std::vector _ch_index; diff --git a/DSView/pv/data/spectrumstack.cpp b/DSView/pv/data/spectrumstack.cpp index 7a96f308..c5c48301 100755 --- a/DSView/pv/data/spectrumstack.cpp +++ b/DSView/pv/data/spectrumstack.cpp @@ -76,12 +76,12 @@ void SpectrumStack::init() { } -int SpectrumStack::get_index() const +int SpectrumStack::get_index() { return _index; } -uint64_t SpectrumStack::get_sample_num() const +uint64_t SpectrumStack::get_sample_num() { return _sample_num; } @@ -96,7 +96,7 @@ void SpectrumStack::set_sample_num(uint64_t num) FFTW_R2HC, FFTW_ESTIMATE); } -int SpectrumStack::get_windows_index() const +int SpectrumStack::get_windows_index() { return _windows_index; } @@ -106,7 +106,7 @@ void SpectrumStack::set_windows_index(int index) _windows_index = index; } -bool SpectrumStack::dc_ignored() const +bool SpectrumStack::dc_ignored() { return _dc_ignore; } @@ -116,7 +116,7 @@ void SpectrumStack::set_dc_ignore(bool ignore) _dc_ignore = ignore; } -int SpectrumStack::get_sample_interval() const +int SpectrumStack::get_sample_interval() { return _sample_interval; } @@ -126,7 +126,7 @@ void SpectrumStack::set_sample_interval(int interval) _sample_interval = interval; } -const std::vector SpectrumStack::get_windows_support() const +const std::vector SpectrumStack::get_windows_support() { std::vector windows; for (size_t i = 0; i < sizeof(windows_support)/sizeof(windows_support[0]); i++) @@ -136,7 +136,7 @@ const std::vector SpectrumStack::get_windows_support() const return windows; } -const std::vector SpectrumStack::get_length_support() const +const std::vector SpectrumStack::get_length_support() { std::vector length; for (size_t i = 0; i < sizeof(length_support)/sizeof(length_support[0]); i++) @@ -146,7 +146,7 @@ const std::vector SpectrumStack::get_length_support() const return length; } -const std::vector SpectrumStack::get_fft_spectrum() const +const std::vector SpectrumStack::get_fft_spectrum() { std::vector empty; if (_spectrum_state == Stopped) @@ -168,11 +168,11 @@ void SpectrumStack::calc_fft() { _spectrum_state = Running; // Get the dso data - boost::shared_ptr data; - boost::shared_ptr dsoSig; + pv::data::Dso *data = NULL; + pv::view::DsoSignal *dsoSig = NULL; for(auto &s : _session->get_signals()) { - if ((dsoSig = dynamic_pointer_cast(s))) { + if ((dsoSig = dynamic_cast(s))) { if (dsoSig->get_index() == _index && dsoSig->enabled()) { data = dsoSig->dso_data(); break; @@ -184,10 +184,10 @@ void SpectrumStack::calc_fft() return; // Check we have a snapshot of data - const deque< boost::shared_ptr > &snapshots = - data->get_snapshots(); + const auto &snapshots = data->get_snapshots(); if (snapshots.empty()) return; + _snapshot = snapshots.front(); if (_snapshot->get_sample_count() < _sample_num*_sample_interval) diff --git a/DSView/pv/data/spectrumstack.h b/DSView/pv/data/spectrumstack.h index aff91060..146742ed 100755 --- a/DSView/pv/data/spectrumstack.h +++ b/DSView/pv/data/spectrumstack.h @@ -25,8 +25,7 @@ #include -#include -#include +#include #include @@ -67,24 +66,24 @@ public: void clear(); void init(); - int get_index() const; + int get_index(); - uint64_t get_sample_num() const; + uint64_t get_sample_num(); void set_sample_num(uint64_t num); - int get_windows_index() const; + int get_windows_index(); void set_windows_index(int index); - const std::vector get_windows_support() const; - const std::vector get_length_support() const; + const std::vector get_windows_support(); + const std::vector get_length_support(); - bool dc_ignored() const; + bool dc_ignored(); void set_dc_ignore(bool ignore); - int get_sample_interval() const; + int get_sample_interval(); void set_sample_interval(int interval); - const std::vector get_fft_spectrum() const; + const std::vector get_fft_spectrum(); double get_fft_spectrum(uint64_t index); void calc_fft(); @@ -102,7 +101,7 @@ private: bool _dc_ignore; int _sample_interval; - boost::shared_ptr _snapshot; + pv::data::DsoSnapshot *_snapshot; spectrum_state _spectrum_state; fftw_plan _fft_plan; diff --git a/DSView/pv/device/device.cpp b/DSView/pv/device/device.cpp index ab60d5a8..1f6c0bdb 100755 --- a/DSView/pv/device/device.cpp +++ b/DSView/pv/device/device.cpp @@ -42,7 +42,7 @@ Device::~Device() } -sr_dev_inst* Device::dev_inst() const +sr_dev_inst* Device::dev_inst() { return _sdi; } @@ -70,7 +70,7 @@ void Device::release() sr_dev_close(_sdi); } -QString Device::format_device_title() const +QString Device::format_device_title() { ostringstream s; @@ -95,7 +95,7 @@ QString Device::format_device_title() const return QString::fromStdString(s.str()); } -bool Device::is_trigger_enabled() const +bool Device::is_trigger_enabled() { assert(_sdi); for (const GSList *l = _sdi->channels; l; l = l->next) { diff --git a/DSView/pv/device/device.h b/DSView/pv/device/device.h index 77ed9abe..0290f5a2 100755 --- a/DSView/pv/device/device.h +++ b/DSView/pv/device/device.h @@ -34,15 +34,15 @@ public: ~Device(); - sr_dev_inst* dev_inst() const; + sr_dev_inst* dev_inst(); void use(SigSession *owner); void release(); - QString format_device_title() const; + QString format_device_title(); - bool is_trigger_enabled() const; + bool is_trigger_enabled(); private: sr_dev_inst *const _sdi; diff --git a/DSView/pv/device/devinst.cpp b/DSView/pv/device/devinst.cpp index d06858cb..124ab2ef 100755 --- a/DSView/pv/device/devinst.cpp +++ b/DSView/pv/device/devinst.cpp @@ -43,7 +43,7 @@ DevInst::~DevInst() free(_id); } -void* DevInst::get_id() const +void* DevInst::get_id() { assert(_id); @@ -64,7 +64,7 @@ void DevInst::release() } } -SigSession* DevInst::owner() const +SigSession* DevInst::owner() { return _owner; } @@ -188,7 +188,7 @@ QString DevInst::name() return QString::fromLocal8Bit(sdi->driver->name); } -bool DevInst::is_trigger_enabled() const +bool DevInst::is_trigger_enabled() { return false; } @@ -204,7 +204,7 @@ void DevInst::run() sr_session_run(); } -bool DevInst::is_usable() const +bool DevInst::is_usable() { return _usable; } diff --git a/DSView/pv/device/devinst.h b/DSView/pv/device/devinst.h index 8039fddd..5ad51bf0 100755 --- a/DSView/pv/device/devinst.h +++ b/DSView/pv/device/devinst.h @@ -50,7 +50,7 @@ protected: virtual ~DevInst(); public: - SigSession* owner() const; + SigSession* owner(); GVariant* get_config(const sr_channel *ch, const sr_channel_group *group, int key); @@ -108,7 +108,7 @@ public: QString name(); - bool is_usable() const; + bool is_usable(); void destroy(); @@ -117,17 +117,17 @@ public: virtual void run(); - virtual void* get_id() const; + virtual void* get_id(); - virtual sr_dev_inst* dev_inst() const = 0; + virtual sr_dev_inst* dev_inst() = 0; virtual void use(SigSession *owner); virtual void release(); - virtual bool is_trigger_enabled() const; + virtual bool is_trigger_enabled(); - virtual QString format_device_title() const = 0; + virtual QString format_device_title() = 0; signals: void device_updated(); diff --git a/DSView/pv/device/file.cpp b/DSView/pv/device/file.cpp index eb494b04..88dd0cb5 100755 --- a/DSView/pv/device/file.cpp +++ b/DSView/pv/device/file.cpp @@ -43,7 +43,7 @@ File::~File(){ } -QString File::format_device_title() const +QString File::format_device_title() { QFileInfo fi(_path); return fi.fileName(); diff --git a/DSView/pv/device/file.h b/DSView/pv/device/file.h index a4984170..569d2ef9 100755 --- a/DSView/pv/device/file.h +++ b/DSView/pv/device/file.h @@ -49,7 +49,7 @@ public: QJsonDocument get_session(); public: - QString format_device_title() const; + QString format_device_title(); protected: const QString _path; diff --git a/DSView/pv/device/inputfile.cpp b/DSView/pv/device/inputfile.cpp index bd2feef7..33b346bf 100755 --- a/DSView/pv/device/inputfile.cpp +++ b/DSView/pv/device/inputfile.cpp @@ -37,7 +37,7 @@ InputFile::InputFile(QString path) : { } -sr_dev_inst* InputFile::dev_inst() const +sr_dev_inst* InputFile::dev_inst() { assert(_input); return _input->sdi; diff --git a/DSView/pv/device/inputfile.h b/DSView/pv/device/inputfile.h index e1c1e179..c7e6a50d 100755 --- a/DSView/pv/device/inputfile.h +++ b/DSView/pv/device/inputfile.h @@ -37,7 +37,7 @@ class InputFile : public File public: InputFile(QString path); - sr_dev_inst* dev_inst() const; + sr_dev_inst* dev_inst(); virtual void use(SigSession *owner); diff --git a/DSView/pv/device/sessionfile.cpp b/DSView/pv/device/sessionfile.cpp index 7f879565..6d3f53d2 100755 --- a/DSView/pv/device/sessionfile.cpp +++ b/DSView/pv/device/sessionfile.cpp @@ -30,7 +30,7 @@ SessionFile::SessionFile(QString path) : { } -sr_dev_inst* SessionFile::dev_inst() const +sr_dev_inst* SessionFile::dev_inst() { return _sdi; } diff --git a/DSView/pv/device/sessionfile.h b/DSView/pv/device/sessionfile.h index 08783bdd..cf50ddaa 100755 --- a/DSView/pv/device/sessionfile.h +++ b/DSView/pv/device/sessionfile.h @@ -32,7 +32,7 @@ class SessionFile : public File public: SessionFile(QString path); - sr_dev_inst* dev_inst() const; + sr_dev_inst* dev_inst(); virtual void use(SigSession *owner); diff --git a/DSView/pv/dialogs/calibration.cpp b/DSView/pv/dialogs/calibration.cpp index 7bc0771a..76648789 100755 --- a/DSView/pv/dialogs/calibration.cpp +++ b/DSView/pv/dialogs/calibration.cpp @@ -31,7 +31,7 @@ #include "../dialogs/dsmessagebox.h" #include "../dsvdef.h" -using namespace boost; + using namespace std; namespace pv { diff --git a/DSView/pv/dialogs/calibration.h b/DSView/pv/dialogs/calibration.h index 5764ce14..b5c71e27 100755 --- a/DSView/pv/dialogs/calibration.h +++ b/DSView/pv/dialogs/calibration.h @@ -29,8 +29,7 @@ #include #include -#include -#include +#include #include #include "../toolbars/titlebar.h" diff --git a/DSView/pv/dialogs/deviceoptions.cpp b/DSView/pv/dialogs/deviceoptions.cpp index d8a4b392..96436f78 100755 --- a/DSView/pv/dialogs/deviceoptions.cpp +++ b/DSView/pv/dialogs/deviceoptions.cpp @@ -90,8 +90,7 @@ void DeviceOptions::accept() bool hasEnabled = false; // Commit the properties - const vector< boost::shared_ptr > &dev_props = - _device_options_binding.properties(); + const auto &dev_props = _device_options_binding.properties(); for(auto &p : dev_props) { assert(p); p->commit(); @@ -116,8 +115,8 @@ void DeviceOptions::accept() if (hasEnabled) { QVector::iterator i = _probe_options_binding_list.begin(); while(i != _probe_options_binding_list.end()) { - const vector< boost::shared_ptr > &probe_props = - (*i)->properties(); + const auto &probe_props = (*i)->properties(); + for(auto &p :probe_props) { assert(p); p->commit(); @@ -148,8 +147,8 @@ QGridLayout * DeviceOptions::get_property_form(QWidget * parent) QGridLayout *const layout = new QGridLayout(parent); layout->setVerticalSpacing(5); - const vector< boost::shared_ptr > &properties = - _device_options_binding.properties(); + const auto &properties =_device_options_binding.properties(); + int i = 0; for(auto &p : properties) { @@ -522,8 +521,7 @@ void DeviceOptions::analog_probes(QGridLayout &layout) pv::prop::binding::ProbeOptions *probe_options_binding = new pv::prop::binding::ProbeOptions(_dev_inst->dev_inst(), probe); - const vector< boost::shared_ptr > &properties = - probe_options_binding->properties(); + const auto &properties = probe_options_binding->properties(); int i = 1; for(auto &p : properties) diff --git a/DSView/pv/dialogs/deviceoptions.h b/DSView/pv/dialogs/deviceoptions.h index 38ee0798..c09f83aa 100755 --- a/DSView/pv/dialogs/deviceoptions.h +++ b/DSView/pv/dialogs/deviceoptions.h @@ -36,9 +36,7 @@ #include #include #include -#include - -#include +#include #include #include "../device/devinst.h" diff --git a/DSView/pv/dialogs/dsomeasure.cpp b/DSView/pv/dialogs/dsomeasure.cpp index 46ef2896..a25e7307 100755 --- a/DSView/pv/dialogs/dsomeasure.cpp +++ b/DSView/pv/dialogs/dsomeasure.cpp @@ -57,8 +57,8 @@ DsoMeasure::DsoMeasure(SigSession *session, View &parent, _measure_tab->setUsesScrollButtons(false); for(auto &s : _session->get_signals()) { - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(s)) && dsoSig->enabled()) { + view::DsoSignal *dsoSig; + if ((dsoSig = dynamic_cast(s)) && dsoSig->enabled()) { QWidget *measure_widget = new QWidget(this); this->add_measure(measure_widget, dsoSig); _measure_tab->addTab(measure_widget, QString::number(dsoSig->get_index())); @@ -85,13 +85,15 @@ DsoMeasure::~DsoMeasure(){ DESTROY_QT_OBJECT(_measure_tab); } -void DsoMeasure::add_measure(QWidget *widget, const boost::shared_ptr dsoSig) +void DsoMeasure::add_measure(QWidget *widget, const view::DsoSignal *dsoSig) { const int Column = 5; const int IconSizeForText = 5; QGridLayout *layout = new QGridLayout(widget); layout->setMargin(0); layout->setSpacing(0); + + pv::view::DsoSignal *psig = const_cast(dsoSig); for (int i=DSO_MS_BEGIN+1; isetIconSize(QSize(48, 48)); QPixmap msPix(get_ms_icon(i)); QBitmap msMask = msPix.createMaskFromColor(QColor("black"), Qt::MaskOutColor); - msPix.fill(dsoSig->get_colour()); + msPix.fill(psig->get_colour()); msPix.setMask(msMask); button->setIcon(QIcon(msPix)); layout->addWidget(button, @@ -159,8 +161,8 @@ void DsoMeasure::accept() enum DSO_MEASURE_TYPE ms_type = DSO_MEASURE_TYPE(id.toInt()); for(auto &s : _session->get_signals()) { - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(s))) { + view::DsoSignal *dsoSig = NULL; + if ((dsoSig = dynamic_cast(s))) { if (_measure_tab->currentWidget()->property("index").toInt() == dsoSig->get_index()) { _view.get_viewstatus()->set_measure(_position, false, dsoSig->get_index(), ms_type); break; diff --git a/DSView/pv/dialogs/dsomeasure.h b/DSView/pv/dialogs/dsomeasure.h index 11efed12..ca541ef1 100755 --- a/DSView/pv/dialogs/dsomeasure.h +++ b/DSView/pv/dialogs/dsomeasure.h @@ -27,8 +27,7 @@ #include #include #include - -#include + #include "../view/dsosignal.h" #include "../toolbars/titlebar.h" @@ -57,7 +56,7 @@ public: static QString get_ms_text(int ms_type); private: - void add_measure(QWidget *widget, const boost::shared_ptr dsoSig); + void add_measure(QWidget *widget, const view::DsoSignal *dsoSig); private slots: void set_measure(bool en); diff --git a/DSView/pv/dialogs/fftoptions.cpp b/DSView/pv/dialogs/fftoptions.cpp index fe53c54f..425854c0 100755 --- a/DSView/pv/dialogs/fftoptions.cpp +++ b/DSView/pv/dialogs/fftoptions.cpp @@ -67,8 +67,8 @@ FftOptions::FftOptions(QWidget *parent, SigSession *session) : // setup _ch_combobox for(auto &s : _session->get_signals()) { - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(s))) { + view::DsoSignal *dsoSig = NULL; + if ((dsoSig = dynamic_cast(s))) { _ch_combobox->addItem(dsoSig->get_name(), QVariant::fromValue(dsoSig->get_index())); } } @@ -88,8 +88,8 @@ FftOptions::FftOptions(QWidget *parent, SigSession *session) : std::vector dbv_ranges; for(auto &t : _session->get_spectrum_traces()) { - boost::shared_ptr spectrumTraces; - if ((spectrumTraces = dynamic_pointer_cast(t))) { + view::SpectrumTrace *spectrumTraces = NULL; + if ((spectrumTraces = dynamic_cast(t))) { windows = spectrumTraces->get_spectrum_stack()->get_windows_support(); length = spectrumTraces->get_spectrum_stack()->get_length_support(); view_modes = spectrumTraces->get_view_modes_support(); @@ -138,8 +138,8 @@ FftOptions::FftOptions(QWidget *parent, SigSession *session) : // load current settings for(auto &t : _session->get_spectrum_traces()) { - boost::shared_ptr spectrumTraces; - if ((spectrumTraces = dynamic_pointer_cast(t))) { + view::SpectrumTrace *spectrumTraces = NULL; + if ((spectrumTraces = dynamic_cast(t))) { if (spectrumTraces->enabled()) { _en_checkbox->setChecked(true); for (int i = 0; i < _ch_combobox->count(); i++) { @@ -231,8 +231,8 @@ void FftOptions::accept() QDialog::accept(); for(auto &t : _session->get_spectrum_traces()) { - boost::shared_ptr spectrumTraces; - if ((spectrumTraces = dynamic_pointer_cast(t))) { + view::SpectrumTrace *spectrumTraces = NULL; + if ((spectrumTraces = dynamic_cast(t))) { spectrumTraces->set_enable(false); if (spectrumTraces->get_index() == _ch_combobox->currentData().toInt()) { spectrumTraces->get_spectrum_stack()->set_dc_ignore(_dc_checkbox->isChecked()); diff --git a/DSView/pv/dialogs/fftoptions.h b/DSView/pv/dialogs/fftoptions.h index dcca5e11..b863d6d5 100755 --- a/DSView/pv/dialogs/fftoptions.h +++ b/DSView/pv/dialogs/fftoptions.h @@ -29,8 +29,7 @@ #include #include #include - -#include + #include "../device/devinst.h" #include "../toolbars/titlebar.h" diff --git a/DSView/pv/dialogs/lissajousoptions.cpp b/DSView/pv/dialogs/lissajousoptions.cpp index 589ec4d4..4ab1d3c2 100755 --- a/DSView/pv/dialogs/lissajousoptions.cpp +++ b/DSView/pv/dialogs/lissajousoptions.cpp @@ -74,8 +74,8 @@ LissajousOptions::LissajousOptions(SigSession *session, QWidget *parent) : QHBoxLayout *ylayout = new QHBoxLayout(); for(auto &s : _session->get_signals()) { - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(s))) { + view::DsoSignal *dsoSig = NULL; + if ((dsoSig = dynamic_cast(s))) { QString index_str = QString::number(dsoSig->get_index()); QRadioButton *xradio = new QRadioButton(index_str, _x_group); xradio->setProperty("index", dsoSig->get_index()); @@ -91,7 +91,7 @@ LissajousOptions::LissajousOptions(SigSession *session, QWidget *parent) : _y_group->setLayout(ylayout); - boost::shared_ptr lissajous = _session->get_lissajous_trace(); + auto lissajous = _session->get_lissajous_trace(); if (lissajous) { _enable->setChecked(lissajous->enabled()); _percent->setValue(lissajous->percent()); @@ -182,12 +182,12 @@ void LissajousOptions::accept() _session->lissajous_rebuild(enable, xindex, yindex, _percent->value()); for(auto &s : _session->get_signals()) { - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(s))) { + view::DsoSignal *dsoSig = NULL; + if ((dsoSig = dynamic_cast(s))) { dsoSig->set_show(!enable); } } - boost::shared_ptr mathTrace = _session->get_math_trace(); + auto mathTrace = _session->get_math_trace(); if (mathTrace && mathTrace->enabled()) { mathTrace->set_show(!enable); } diff --git a/DSView/pv/dialogs/lissajousoptions.h b/DSView/pv/dialogs/lissajousoptions.h index 9a7e7168..edb6ce68 100755 --- a/DSView/pv/dialogs/lissajousoptions.h +++ b/DSView/pv/dialogs/lissajousoptions.h @@ -31,8 +31,7 @@ #include #include #include - -#include + #include "../view/dsosignal.h" #include "../toolbars/titlebar.h" diff --git a/DSView/pv/dialogs/mathoptions.cpp b/DSView/pv/dialogs/mathoptions.cpp index d7c9e4bb..21e2d6ab 100755 --- a/DSView/pv/dialogs/mathoptions.cpp +++ b/DSView/pv/dialogs/mathoptions.cpp @@ -79,8 +79,8 @@ MathOptions::MathOptions(SigSession *session, QWidget *parent) : QHBoxLayout *src2_layout = new QHBoxLayout(); for(auto &s : _session->get_signals()) { - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(s))) { + view::DsoSignal *dsoSig = NULL;; + if ((dsoSig = dynamic_cast(s))) { QString index_str = QString::number(dsoSig->get_index()); QRadioButton *xradio = new QRadioButton(index_str, _src1_group); xradio->setProperty("index", dsoSig->get_index()); @@ -96,7 +96,7 @@ MathOptions::MathOptions(SigSession *session, QWidget *parent) : _src2_group->setLayout(src2_layout); - boost::shared_ptr math = _session->get_math_trace(); + auto math = _session->get_math_trace(); if (math) { _enable->setChecked(math->enabled()); for (QVector::const_iterator i = _src1_radio.begin(); @@ -204,12 +204,12 @@ void MathOptions::accept() } } bool enable = (src1 != -1 && src2 != -1 && _enable->isChecked()); - boost::shared_ptr dsoSig1; - boost::shared_ptr dsoSig2; + view::DsoSignal *dsoSig1 = NULL; + view::DsoSignal *dsoSig2 = NULL; for(auto &s : _session->get_signals()) { - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(s))) { + view::DsoSignal *dsoSig = NULL;; + if ((dsoSig = dynamic_cast(s))) { if (dsoSig->get_index() == src1) dsoSig1 = dsoSig; if (dsoSig->get_index() == src2) diff --git a/DSView/pv/dialogs/mathoptions.h b/DSView/pv/dialogs/mathoptions.h index ae50e7b4..ed6aa2fb 100755 --- a/DSView/pv/dialogs/mathoptions.h +++ b/DSView/pv/dialogs/mathoptions.h @@ -31,8 +31,7 @@ #include #include #include - -#include + #include "../view/dsosignal.h" #include "../toolbars/titlebar.h" diff --git a/DSView/pv/dialogs/protocolexp.cpp b/DSView/pv/dialogs/protocolexp.cpp index f594c6a9..b9445c60 100755 --- a/DSView/pv/dialogs/protocolexp.cpp +++ b/DSView/pv/dialogs/protocolexp.cpp @@ -63,12 +63,13 @@ ProtocolExp::ProtocolExp(QWidget *parent, SigSession *session) : _flayout->addRow(new QLabel(tr("Export Format: "), this), _format_combobox); pv::data::DecoderModel* decoder_model = _session->get_decoder_model(); - const boost::shared_ptr& decoder_stack = decoder_model->getDecoderStack(); + + const auto decoder_stack = decoder_model->getDecoderStack(); if (decoder_stack) { int row_index = 0; - const std::map rows = decoder_stack->get_rows_lshow(); - for (std::map::const_iterator i = rows.begin(); - i != rows.end(); i++) { + auto rows = decoder_stack->get_rows_lshow(); + + for (auto i = rows.begin();i != rows.end(); i++) { if ((*i).second) { QLabel *row_label = new QLabel((*i).first.title(), this); QRadioButton *row_sel = new QRadioButton(this); @@ -169,7 +170,7 @@ void ProtocolExp::accept() .arg(title); pv::data::DecoderModel* decoder_model = _session->get_decoder_model(); - const boost::shared_ptr& decoder_stack = decoder_model->getDecoderStack(); + const auto decoder_stack = decoder_model->getDecoderStack(); int row_index = 0; Row row; const std::map rows_lshow = decoder_stack->get_rows_lshow(); @@ -186,7 +187,7 @@ void ProtocolExp::accept() uint64_t exported = 0; double ns_per_sample = SR_SEC(1) * 1.0 / decoder_stack->samplerate(); - vector annotations; + std::vector annotations; decoder_stack->get_annotation_subset(annotations, row, 0, decoder_stack->sample_count()-1); if (!annotations.empty()) { diff --git a/DSView/pv/dialogs/protocolexp.h b/DSView/pv/dialogs/protocolexp.h index e888eedf..8688fd96 100755 --- a/DSView/pv/dialogs/protocolexp.h +++ b/DSView/pv/dialogs/protocolexp.h @@ -29,9 +29,7 @@ #include #include #include - -#include - + #include "../device/devinst.h" #include "../prop/binding/deviceoptions.h" #include "../toolbars/titlebar.h" diff --git a/DSView/pv/dialogs/protocollist.cpp b/DSView/pv/dialogs/protocollist.cpp index 53b46b30..9f474fa8 100755 --- a/DSView/pv/dialogs/protocollist.cpp +++ b/DSView/pv/dialogs/protocollist.cpp @@ -56,8 +56,7 @@ ProtocolList::ProtocolList(QWidget *parent, SigSession *session) : connect(_map_zoom_combobox, SIGNAL(currentIndexChanged(int)), _session, SLOT(set_map_zoom(int))); _protocol_combobox = new QComboBox(this); - const std::vector< boost::shared_ptr > decode_sigs( - _session->get_decode_signals()); + auto &decode_sigs = _session->get_decode_signals(); int index = 0; for(auto &d : decode_sigs) { @@ -126,9 +125,8 @@ void ProtocolList::set_protocol(int index) } _show_label_list.clear(); - boost::shared_ptr decoder_stack; - const std::vector< boost::shared_ptr > decode_sigs( - _session->get_decode_signals()); + pv::data::DecoderStack *decoder_stack = NULL; + const auto &decode_sigs = _session->get_decode_signals(); int cur_index = 0; for(auto &d : decode_sigs) { @@ -146,9 +144,9 @@ void ProtocolList::set_protocol(int index) _session->get_decoder_model()->setDecoderStack(decoder_stack); int row_index = 0; - const std::map rows = decoder_stack->get_rows_lshow(); - for (std::map::const_iterator i = rows.begin(); - i != rows.end(); i++) { + const auto rows = decoder_stack->get_rows_lshow(); + + for (auto i = rows.begin();i != rows.end(); i++) { QLabel *row_label = new QLabel((*i).first.title(), this); QCheckBox *row_checkbox = new QCheckBox(this); //row_checkbox->setChecked(false); @@ -169,9 +167,8 @@ void ProtocolList::on_row_check(bool show) QVariant id = sc->property("index"); int index = id.toInt(); - boost::shared_ptr decoder_stack; - const std::vector< boost::shared_ptr > decode_sigs( - _session->get_decode_signals()); + pv::data::DecoderStack *decoder_stack = NULL; + const auto &decode_sigs = _session->get_decode_signals(); int cur_index = 0; for(auto &d : decode_sigs) { diff --git a/DSView/pv/dialogs/protocollist.h b/DSView/pv/dialogs/protocollist.h index 1d4c68f2..0d4024d9 100755 --- a/DSView/pv/dialogs/protocollist.h +++ b/DSView/pv/dialogs/protocollist.h @@ -29,8 +29,7 @@ #include #include #include - -#include + #include "../device/devinst.h" #include "../prop/binding/deviceoptions.h" diff --git a/DSView/pv/dialogs/regionoptions.h b/DSView/pv/dialogs/regionoptions.h index a0ec9554..b3e06b78 100755 --- a/DSView/pv/dialogs/regionoptions.h +++ b/DSView/pv/dialogs/regionoptions.h @@ -28,9 +28,7 @@ #include #include #include - -#include - + #include "../toolbars/titlebar.h" #include "dsdialog.h" diff --git a/DSView/pv/dialogs/search.cpp b/DSView/pv/dialogs/search.cpp index 26744536..7f562068 100755 --- a/DSView/pv/dialogs/search.cpp +++ b/DSView/pv/dialogs/search.cpp @@ -52,8 +52,8 @@ Search::Search(QWidget *parent, SigSession *session, std::map for(auto &sig : _session->get_signals()) { assert(sig); - boost::shared_ptr logic_sig; - if ((logic_sig = boost::dynamic_pointer_cast(sig))) { + view::LogicSignal *logic_sig = NULL; + if ((logic_sig = dynamic_cast(sig))) { QLineEdit *search_lineEdit = new QLineEdit(this); if (pattern.find(logic_sig->get_index()) != pattern.end()) search_lineEdit->setText(pattern[logic_sig->get_index()]); @@ -112,8 +112,8 @@ std::map Search::get_pattern() int index = 0; for(auto &sig :_session->get_signals()) { assert(sig); - boost::shared_ptr logic_sig; - if ((logic_sig = boost::dynamic_pointer_cast(sig))) { + view::LogicSignal *logic_sig = NULL; + if ((logic_sig = dynamic_cast(sig))) { pattern[logic_sig->get_index()] = _search_lineEdit_vec[index]->text(); index++; } diff --git a/DSView/pv/dialogs/search.h b/DSView/pv/dialogs/search.h index 29c3d5a4..013c4723 100755 --- a/DSView/pv/dialogs/search.h +++ b/DSView/pv/dialogs/search.h @@ -33,9 +33,7 @@ #include "../toolbars/titlebar.h" #include "dsdialog.h" #include "../device/devinst.h" - -#include - + namespace pv { namespace dialogs { diff --git a/DSView/pv/dialogs/shadow.cpp b/DSView/pv/dialogs/shadow.cpp index 0fc91ee4..c6fd3426 100755 --- a/DSView/pv/dialogs/shadow.cpp +++ b/DSView/pv/dialogs/shadow.cpp @@ -94,7 +94,7 @@ void Shadow::draw(QPainter* painter) painter->setWorldTransform(restoreTransform); } -QRectF Shadow::boundingRectFor(const QRectF& rect) const +QRectF Shadow::boundingRectFor(const QRectF& rect) { qreal delta = blurRadius() + distance(); return rect.united(rect.adjusted(-delta, -delta, delta, delta)); diff --git a/DSView/pv/dialogs/shadow.h b/DSView/pv/dialogs/shadow.h index e37bbbad..952aad24 100755 --- a/DSView/pv/dialogs/shadow.h +++ b/DSView/pv/dialogs/shadow.h @@ -36,16 +36,16 @@ public: explicit Shadow(QObject *parent = 0); void draw(QPainter* painter); - QRectF boundingRectFor(const QRectF& rect) const; + QRectF boundingRectFor(const QRectF& rect); inline void setDistance(qreal distance) { _distance = distance; updateBoundingRect(); } - inline qreal distance() const { return _distance; } + inline qreal distance() { return _distance; } inline void setBlurRadius(qreal blurRadius) { _blurRadius = blurRadius; updateBoundingRect(); } - inline qreal blurRadius() const { return _blurRadius; } + inline qreal blurRadius() { return _blurRadius; } inline void setColor(const QColor& color) { _color = color; } - inline QColor color() const { return _color; } + inline QColor color() { return _color; } private: qreal _distance; diff --git a/DSView/pv/dialogs/storeprogress.h b/DSView/pv/dialogs/storeprogress.h index a7077142..f0475b5d 100755 --- a/DSView/pv/dialogs/storeprogress.h +++ b/DSView/pv/dialogs/storeprogress.h @@ -21,10 +21,7 @@ #ifndef DSVIEW_PV_DIALOGS_SAVEPROGRESS_H #define DSVIEW_PV_DIALOGS_SAVEPROGRESS_H - -//#include - -#include + #include #include "../storesession.h" #include "../dialogs/dsdialog.h" diff --git a/DSView/pv/dialogs/waitingdialog.cpp b/DSView/pv/dialogs/waitingdialog.cpp index b206912b..1817c34b 100755 --- a/DSView/pv/dialogs/waitingdialog.cpp +++ b/DSView/pv/dialogs/waitingdialog.cpp @@ -184,11 +184,11 @@ void WaitingDialog::changeText() zero_fgain = g_variant_get_boolean(gvar); g_variant_unref(gvar); if (zero_fgain) { - boost::shared_ptr dsoSig; + view::DsoSignal *dsoSig = NULL; for(auto &s : _session->get_signals()) { - if ((dsoSig = dynamic_pointer_cast(s))) + if ((dsoSig = dynamic_cast(s))) dsoSig->set_enable(dsoSig->get_index() == 0); } std::this_thread::sleep_for(std::chrono::milliseconds(100)); diff --git a/DSView/pv/dialogs/waitingdialog.h b/DSView/pv/dialogs/waitingdialog.h index e8fb2474..dd1071d0 100755 --- a/DSView/pv/dialogs/waitingdialog.h +++ b/DSView/pv/dialogs/waitingdialog.h @@ -27,9 +27,7 @@ #include #include #include - -#include - + #include "../sigsession.h" #include "../device/devinst.h" #include "../toolbars/titlebar.h" diff --git a/DSView/pv/dock/dsotriggerdock.cpp b/DSView/pv/dock/dsotriggerdock.cpp index c859f824..29698f19 100755 --- a/DSView/pv/dock/dsotriggerdock.cpp +++ b/DSView/pv/dock/dsotriggerdock.cpp @@ -24,8 +24,6 @@ #include "../device/devinst.h" #include "../dialogs/dsmessagebox.h" #include "../view/dsosignal.h" - -#include #include @@ -389,8 +387,8 @@ void DsoTriggerDock::init() _channel_comboBox->clear(); for(auto &s : _session->get_signals()) { - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(s))) { + view::DsoSignal *dsoSig = NULL; + if ((dsoSig = dynamic_cast(s))) { _channel_comboBox->addItem(dsoSig->get_name(), QVariant::fromValue(dsoSig->get_index())); } } diff --git a/DSView/pv/dock/measuredock.cpp b/DSView/pv/dock/measuredock.cpp index 77166789..5b6c77dd 100755 --- a/DSView/pv/dock/measuredock.cpp +++ b/DSView/pv/dock/measuredock.cpp @@ -598,12 +598,15 @@ void MeasureDock::update_edge() if (start_ret && end_ret) { uint64_t rising_edges; uint64_t falling_edges; - const std::vector< boost::shared_ptr > sigs(_session->get_signals()); + + const auto &sigs = _session->get_signals(); + for(size_t i = 0; i < sigs.size(); i++) { - const boost::shared_ptr s(sigs[i]); - boost::shared_ptr logicSig; + view::Signal *s = sigs[i]; + view::LogicSignal *logicSig = NULL; assert(s); - if ((logicSig = dynamic_pointer_cast(s)) && + + if ((logicSig = dynamic_cast(s)) && (logicSig->enabled()) && (logicSig->get_index() == _edge_ch_cmb_vec[edge_index]->currentText().toInt())){ if (logicSig->edges(_view.get_cursor_samples(end), _view.get_cursor_samples(start), rising_edges, falling_edges)) { @@ -650,12 +653,13 @@ QComboBox* MeasureDock::create_probe_selector(QWidget *parent) void MeasureDock::update_probe_selector(QComboBox *selector) { selector->clear(); - const std::vector< boost::shared_ptr > sigs(_session->get_signals()); + const auto &sigs = _session->get_signals(); + for(size_t i = 0; i < sigs.size(); i++) { - const boost::shared_ptr s(sigs[i]); + const auto s = sigs[i]; assert(s); - if (dynamic_pointer_cast(s) && s->enabled()) + if (dynamic_cast(s) && s->enabled()) { selector->addItem(QString::number(s->get_index())); } diff --git a/DSView/pv/dock/protocoldock.cpp b/DSView/pv/dock/protocoldock.cpp index a35374ab..85150806 100755 --- a/DSView/pv/dock/protocoldock.cpp +++ b/DSView/pv/dock/protocoldock.cpp @@ -46,13 +46,14 @@ #include -#include #include #include "../ui/msgbox.h" #include "../dsvdef.h" #include "../config/appconfig.h" #include "../data/decode/decoderstatus.h" +using namespace std; + namespace pv { namespace dock { @@ -205,6 +206,8 @@ ProtocolDock::ProtocolDock(QWidget *parent, view::View &view, SigSession *sessio connect(_search_edit, SIGNAL(editingFinished()), this, SLOT(search_changed())); retranslateUi(); + + ds_debug("protocol panel\n"); } ProtocolDock::~ProtocolDock() @@ -333,9 +336,9 @@ void ProtocolDock::add_protocol(bool silent) } //progress connection - const std::vector> decode_sigs(_session->get_decode_signals()); + const auto &decode_sigs = _session->get_decode_signals(); - connect(decode_sigs.back().get(), SIGNAL(decoded_progress(int)), this, SLOT(decoded_progress(int))); + connect(decode_sigs.back(), SIGNAL(decoded_progress(int)), this, SLOT(decoded_progress(int))); protocol_updated(); } @@ -373,8 +376,7 @@ void ProtocolDock::decoded_progress(int progress) int pg = 0; QString err=""; - const std::vector< boost::shared_ptr > decode_sigs( - _session->get_decode_signals()); + const auto &decode_sigs = _session->get_decode_signals(); int index = 0; for(auto &d : decode_sigs) { @@ -414,8 +416,7 @@ void ProtocolDock::set_model() search_done(); // clear mark_index of all DecoderStacks - const std::vector< boost::shared_ptr > decode_sigs( - _session->get_decode_signals()); + const auto &decode_sigs = _session->get_decode_signals(); for(auto &d : decode_sigs) { d->decoder()->set_mark_index(-1); @@ -425,8 +426,8 @@ void ProtocolDock::set_model() void ProtocolDock::update_model() { pv::data::DecoderModel *decoder_model = _session->get_decoder_model(); - const std::vector< boost::shared_ptr > decode_sigs( - _session->get_decode_signals()); + const auto &decode_sigs = _session->get_decode_signals(); + if (decode_sigs.size() == 0) decoder_model->setDecoderStack(NULL); else if (!decoder_model->getDecoderStack()) @@ -468,12 +469,12 @@ void ProtocolDock::resize_table_view(data::DecoderModel* decoder_model) void ProtocolDock::item_clicked(const QModelIndex &index) { pv::data::DecoderModel *decoder_model = _session->get_decoder_model(); - boost::shared_ptr decoder_stack = decoder_model->getDecoderStack(); + + auto decoder_stack = decoder_model->getDecoderStack(); if (decoder_stack) { pv::data::decode::Annotation ann; if (decoder_stack->list_annotation(ann, index.column(), index.row())) { - const std::vector< boost::shared_ptr > decode_sigs( - _session->get_decode_signals()); + const auto &decode_sigs = _session->get_decode_signals(); for(auto &d : decode_sigs) { d->decoder()->set_mark_index(-1); @@ -548,7 +549,8 @@ void ProtocolDock::nav_table_view() { uint64_t row_index = 0; pv::data::DecoderModel *decoder_model = _session->get_decoder_model(); - boost::shared_ptr decoder_stack = decoder_model->getDecoderStack(); + + auto decoder_stack = decoder_model->getDecoderStack(); if (decoder_stack) { uint64_t offset = _view.offset() * (decoder_stack->samplerate() * _view.scale()); std::map rows = decoder_stack->get_rows_lshow(); @@ -567,8 +569,7 @@ void ProtocolDock::nav_table_view() pv::data::decode::Annotation ann; decoder_stack->list_annotation(ann, index.column(), index.row()); - const std::vector< boost::shared_ptr > decode_sigs( - _session->get_decode_signals()); + const auto &decode_sigs = _session->get_decode_signals(); for(auto &d : decode_sigs) { d->decoder()->set_mark_index(-1); @@ -596,7 +597,8 @@ void ProtocolDock::search_pre() uint64_t rowCount = _model_proxy.rowCount(); QModelIndex matchingIndex; pv::data::DecoderModel *decoder_model = _session->get_decoder_model(); - boost::shared_ptr decoder_stack = decoder_model->getDecoderStack(); + + auto decoder_stack = decoder_model->getDecoderStack(); do { _cur_search_index--; if (_cur_search_index <= -1 || _cur_search_index >= _model_proxy.rowCount()) @@ -652,7 +654,8 @@ void ProtocolDock::search_nxt() uint64_t rowCount = _model_proxy.rowCount(); QModelIndex matchingIndex; pv::data::DecoderModel *decoder_model = _session->get_decoder_model(); - boost::shared_ptr decoder_stack = decoder_model->getDecoderStack(); + + auto decoder_stack = decoder_model->getDecoderStack(); do { _cur_search_index++; if (_cur_search_index < 0 || _cur_search_index >= _model_proxy.rowCount()) @@ -716,7 +719,8 @@ void ProtocolDock::search_update() return; pv::data::DecoderModel *decoder_model = _session->get_decoder_model(); - boost::shared_ptr decoder_stack = decoder_model->getDecoderStack(); + + auto decoder_stack = decoder_model->getDecoderStack(); if (!decoder_stack) return; diff --git a/DSView/pv/dock/searchdock.cpp b/DSView/pv/dock/searchdock.cpp index 87b2cee3..33c56f66 100755 --- a/DSView/pv/dock/searchdock.cpp +++ b/DSView/pv/dock/searchdock.cpp @@ -40,8 +40,7 @@ #include #include -#include -#include +#include #include "../config/appconfig.h" namespace pv { @@ -130,9 +129,9 @@ void SearchDock::on_previous() bool ret; int64_t last_pos; bool last_hit; - const boost::shared_ptr snapshot(_session->get_snapshot(SR_CHANNEL_LOGIC)); + const auto snapshot = _session->get_snapshot(SR_CHANNEL_LOGIC); assert(snapshot); - const boost::shared_ptr logic_snapshot = boost::dynamic_pointer_cast(snapshot); + const auto logic_snapshot = dynamic_cast(snapshot); if (!logic_snapshot || logic_snapshot->empty()) { dialogs::DSMessageBox msg(this); @@ -192,9 +191,9 @@ void SearchDock::on_next() { bool ret; int64_t last_pos; - const boost::shared_ptr snapshot(_session->get_snapshot(SR_CHANNEL_LOGIC)); + const auto snapshot = _session->get_snapshot(SR_CHANNEL_LOGIC); assert(snapshot); - const boost::shared_ptr logic_snapshot = boost::dynamic_pointer_cast(snapshot); + const auto logic_snapshot = dynamic_cast(snapshot); if (!logic_snapshot || logic_snapshot->empty()) { dialogs::DSMessageBox msg(this); diff --git a/DSView/pv/dsvdef.cpp b/DSView/pv/dsvdef.cpp index e5203dbe..49d0e5df 100644 --- a/DSView/pv/dsvdef.cpp +++ b/DSView/pv/dsvdef.cpp @@ -23,6 +23,13 @@ #include "dsvdef.h" #include +#ifdef DS_DEBUG_TRACE +#include + void ds_print(const char *s){ + printf(s); + } +#endif + namespace DecoderDataFormat { int Parse(const char *name){ diff --git a/DSView/pv/dsvdef.h b/DSView/pv/dsvdef.h index c35a7de0..cc5283c8 100644 --- a/DSView/pv/dsvdef.h +++ b/DSView/pv/dsvdef.h @@ -22,6 +22,17 @@ #pragma once +#include "../config.h" + + +#ifdef DS_DEBUG_TRACE + void ds_print(const char *s); + + #define ds_debug(x) ds_print((x)) +#else + #define ds_debug(x) +#endif + class QWidget; #define DESTROY_OBJECT(p) if((p)){delete (p); p = NULL;} @@ -48,3 +59,4 @@ namespace app bool is_app_top_window(QWidget* w); } + diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index dd0372af..fe69e51d 100755 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -26,8 +26,7 @@ #include "dock/protocoldock.h" -#include -#include +#include #include #include @@ -92,11 +91,7 @@ #include "../ui/msgbox.h" #include "config/appconfig.h" #include "appcontrol.h" - -using boost::shared_ptr; -using boost::dynamic_pointer_cast; -using std::list; -using std::vector; + namespace pv { @@ -549,9 +544,9 @@ void MainWindow::device_detach() _view->hide_calibration(); if (_session->get_device()->dev_inst()->mode != DSO && strncmp(_session->get_device()->name().toUtf8(), "virtual", 7)) { - const boost::shared_ptr logic_snapshot(_session->get_snapshot(SR_CHANNEL_LOGIC)); + const auto logic_snapshot = _session->get_snapshot(SR_CHANNEL_LOGIC); assert(logic_snapshot); - const boost::shared_ptr analog_snapshot(_session->get_snapshot(SR_CHANNEL_ANALOG)); + const auto analog_snapshot = _session->get_snapshot(SR_CHANNEL_ANALOG); assert(analog_snapshot); if (!logic_snapshot->empty() || !analog_snapshot->empty()) { @@ -830,8 +825,8 @@ void MainWindow::commit_trigger(bool instant) for(auto &s : _session->get_signals()) { assert(s); - boost::shared_ptr logicSig; - if ((logicSig = dynamic_pointer_cast(s))) { + view::LogicSignal *logicSig = NULL; + if ((logicSig = dynamic_cast(s))) { if (logicSig->commit_trig()) i++; } @@ -848,17 +843,19 @@ void MainWindow::commit_trigger(bool instant) msg.mBox()->addButton(tr("Continue"), QMessageBox::ActionRole); msg.exec(); + if (msg.mBox()->clickedButton() == cancelButton) { for(auto &s : _session->get_signals()) { assert(s); - boost::shared_ptr logicSig; - if ((logicSig = dynamic_pointer_cast(s))) { + view::LogicSignal *logicSig = NULL; + if ((logicSig = dynamic_cast(s))) { logicSig->set_trig(view::LogicSignal::NONTRIG); logicSig->commit_trig(); } } } + if (msg.mBox()->clickedButton() == noMoreButton) { app._appOptions.warnofMultiTrig = false; @@ -1068,8 +1065,8 @@ bool MainWindow::load_session_json(QJsonDocument json, bool file_dev) (s->get_type() == obj["type"].toDouble())) { s->set_colour(QColor(obj["colour"].toString())); - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(s))) { + view::DsoSignal *dsoSig = NULL; + if ((dsoSig = dynamic_cast(s))) { dsoSig->load_settings(); dsoSig->set_zero_ratio(obj["zeroPos"].toDouble()); dsoSig->set_trig_ratio(obj["trigValue"].toDouble()); @@ -1088,21 +1085,21 @@ bool MainWindow::load_session_json(QJsonDocument json, bool file_dev) s->set_colour(QColor(obj["colour"].toString())); s->set_name(g_strdup(obj["name"].toString().toUtf8().data())); - boost::shared_ptr logicSig; - if ((logicSig = dynamic_pointer_cast(s))) { + view::LogicSignal *logicSig = NULL; + if ((logicSig = dynamic_cast(s))) { logicSig->set_trig(obj["strigger"].toDouble()); } - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(s))) { + view::DsoSignal *dsoSig = NULL; + if ((dsoSig = dynamic_cast(s))) { dsoSig->load_settings(); dsoSig->set_zero_ratio(obj["zeroPos"].toDouble()); dsoSig->set_trig_ratio(obj["trigValue"].toDouble()); dsoSig->commit_settings(); } - boost::shared_ptr analogSig; - if ((analogSig = dynamic_pointer_cast(s))) { + view::AnalogSignal *analogSig = NULL; + if ((analogSig = dynamic_cast(s))) { analogSig->set_zero_ratio(obj["zeroPos"].toDouble()); analogSig->commit_settings(); } @@ -1200,13 +1197,13 @@ bool MainWindow::on_store_session(QString name) else s_obj["colour"] = QJsonValue::fromVariant("default"); - boost::shared_ptr logicSig; - if ((logicSig = dynamic_pointer_cast(s))) { + view::LogicSignal *logicSig = NULL; + if ((logicSig = dynamic_cast(s))) { s_obj["strigger"] = logicSig->get_trig(); } - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(s))) { + view::DsoSignal *dsoSig = NULL; + if ((dsoSig = dynamic_cast(s))) { s_obj["vdiv"] = QJsonValue::fromVariant(static_cast(dsoSig->get_vDialValue())); s_obj["vfactor"] = QJsonValue::fromVariant(static_cast(dsoSig->get_factor())); s_obj["coupling"] = dsoSig->get_acCoupling(); @@ -1214,8 +1211,8 @@ bool MainWindow::on_store_session(QString name) s_obj["zeroPos"] = dsoSig->get_zero_ratio(); } - boost::shared_ptr analogSig; - if ((analogSig = dynamic_pointer_cast(s))) { + view::AnalogSignal *analogSig = NULL; + if ((analogSig = dynamic_cast(s))) { s_obj["vdiv"] = QJsonValue::fromVariant(static_cast(analogSig->get_vdiv())); s_obj["vfactor"] = QJsonValue::fromVariant(static_cast(analogSig->get_factor())); s_obj["coupling"] = analogSig->get_acCoupling(); @@ -1289,7 +1286,7 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) if ( event->type() == QEvent::KeyPress ) { SigSession *_session = _control->GetSession(); - const vector< boost::shared_ptr > sigs(_session->get_signals()); + const auto &sigs = _session->get_signals(); QKeyEvent *ke = (QKeyEvent *) event; switch(ke->key()) { case Qt::Key_S: @@ -1335,8 +1332,8 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) break; case Qt::Key_0: for(auto & s : sigs) { - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(s))) { + view::DsoSignal *dsoSig = NULL; + if ((dsoSig = dynamic_cast(s))) { if (dsoSig->get_index() == 0) dsoSig->set_vDialActive(!dsoSig->get_vDialActive()); else @@ -1348,8 +1345,8 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) break; case Qt::Key_1: for(auto & s : sigs) { - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(s))) { + view::DsoSignal *dsoSig = NULL; + if ((dsoSig = dynamic_cast(s))) { if (dsoSig->get_index() == 1) dsoSig->set_vDialActive(!dsoSig->get_vDialActive()); else @@ -1361,8 +1358,8 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) break; case Qt::Key_Up: for(auto &s : sigs) { - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(s))) { + view::DsoSignal *dsoSig = NULL; + if ((dsoSig = dynamic_cast(s))) { if (dsoSig->get_vDialActive()) { dsoSig->go_vDialNext(true); update(); @@ -1373,8 +1370,8 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) break; case Qt::Key_Down: for(auto &s : sigs) { - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(s))) { + view::DsoSignal *dsoSig = NULL; + if ((dsoSig = dynamic_cast(s))) { if (dsoSig->get_vDialActive()) { dsoSig->go_vDialPre(true); update(); diff --git a/DSView/pv/minizip/mztools.c b/DSView/pv/minizip/mztools.c index 96891c2e..6047d70c 100644 --- a/DSView/pv/minizip/mztools.c +++ b/DSView/pv/minizip/mztools.c @@ -12,8 +12,8 @@ #include "unzip.h" #define READ_8(adr) ((unsigned char)*(adr)) -#define READ_16(adr) ( READ_8(adr) | (READ_8(adr+1) << 8) ) -#define READ_32(adr) ( READ_16(adr) | (READ_16((adr)+2) << 16) ) +#define READ_16(adr) ( READ_8(adr) | (READ_8(adr+1) << 8) +#define READ_32(adr) ( READ_16(adr) | (READ_16((adr)+2) << 16) #define WRITE_8(buff, n) do { \ *((unsigned char*)(buff)) = (unsigned char) ((n) & 0xff); \ diff --git a/DSView/pv/prop/binding/binding.cpp b/DSView/pv/prop/binding/binding.cpp index 78e231ba..345cae1e 100755 --- a/DSView/pv/prop/binding/binding.cpp +++ b/DSView/pv/prop/binding/binding.cpp @@ -26,14 +26,13 @@ #include #include "binding.h" - -using boost::shared_ptr; + namespace pv { namespace prop { namespace binding { -const std::vector< boost::shared_ptr >& Binding::properties() +const std::vector& Binding::properties() { return _properties; } @@ -47,7 +46,7 @@ void Binding::commit() } void Binding::add_properties_to_form(QFormLayout *layout, - bool auto_commit) const + bool auto_commit) { assert(layout); @@ -71,7 +70,7 @@ void Binding::add_properties_to_form(QFormLayout *layout, } QWidget* Binding::get_property_form(QWidget *parent, - bool auto_commit) const + bool auto_commit) { QWidget *const form = new QWidget(parent); QFormLayout *const layout = new QFormLayout(form); @@ -84,11 +83,9 @@ QWidget* Binding::get_property_form(QWidget *parent, return form; } -std::map< boost::shared_ptr, - GVariant* > Binding::get_property_value() const +std::map Binding::get_property_value() { - std::map < boost::shared_ptr, - GVariant* > pvalue; + std::map pvalue; for(auto &p : _properties) { diff --git a/DSView/pv/prop/binding/binding.h b/DSView/pv/prop/binding/binding.h index 8b413e05..68bae0d7 100755 --- a/DSView/pv/prop/binding/binding.h +++ b/DSView/pv/prop/binding/binding.h @@ -27,8 +27,7 @@ #include #include -#include -#include +#include #include @@ -45,23 +44,22 @@ namespace binding { class Binding { public: - const std::vector< boost::shared_ptr >& properties(); + const std::vector& properties(); void commit(); void add_properties_to_form(QFormLayout *layout, - bool auto_commit = false) const; + bool auto_commit = false); QWidget* get_property_form(QWidget *parent, - bool auto_commit = false) const; + bool auto_commit = false); - std::map< boost::shared_ptr, - GVariant* > get_property_value() const; + std::map get_property_value(); static QString print_gvariant(GVariant *const gvar); protected: - std::vector< boost::shared_ptr > _properties; + std::vector _properties; QWidget *_form; }; diff --git a/DSView/pv/prop/binding/decoderoptions.cpp b/DSView/pv/prop/binding/decoderoptions.cpp index df017534..cdaca0df 100755 --- a/DSView/pv/prop/binding/decoderoptions.cpp +++ b/DSView/pv/prop/binding/decoderoptions.cpp @@ -33,22 +33,16 @@ #include #include -using boost::bind; -using boost::none; -using boost::shared_ptr; -using std::make_pair; -using std::map; -using std::pair; -using std::string; -using std::vector; - +using namespace boost; +using namespace std; + namespace pv { namespace prop { namespace binding { DecoderOptions::DecoderOptions( - shared_ptr decoder_stack, - shared_ptr decoder) : + pv::data::DecoderStack* decoder_stack, + data::decode::Decoder *decoder) : _decoder_stack(decoder_stack), _decoder(decoder) { @@ -69,19 +63,16 @@ DecoderOptions::DecoderOptions( const Property::Setter setter = bind( &DecoderOptions::setter, this, opt->id, _1); - shared_ptr prop; + Property *prop = NULL; if (opt->values) prop = bind_enum(name, opt, getter, setter); else if (g_variant_is_of_type(opt->def, G_VARIANT_TYPE("d"))) - prop = shared_ptr(new Double(name, name, 2, "", - none, none, getter, setter)); + prop = new Double(name, name, 2, "",none, none, getter, setter); else if (g_variant_is_of_type(opt->def, G_VARIANT_TYPE("x"))) - prop = shared_ptr( - new Int(name, name, "", none, getter, setter)); + prop = new Int(name, name, "", none, getter, setter); else if (g_variant_is_of_type(opt->def, G_VARIANT_TYPE("s"))) - prop = shared_ptr( - new String(name, name, getter, setter)); + prop = new String(name, name, getter, setter); else continue; @@ -89,18 +80,18 @@ DecoderOptions::DecoderOptions( } } -shared_ptr DecoderOptions::bind_enum( +Property* DecoderOptions::bind_enum( const QString &name, const srd_decoder_option *option, Property::Getter getter, Property::Setter setter) { - vector< pair > values; + std::vector > values; for (GSList *l = option->values; l; l = l->next) { GVariant *const var = (GVariant*)l->data; assert(var); values.push_back(make_pair(var, print_gvariant(var))); } - return shared_ptr(new Enum(name, name, values, getter, setter)); + return new Enum(name, name, values, getter, setter); } GVariant* DecoderOptions::getter(const char *id) @@ -111,7 +102,7 @@ GVariant* DecoderOptions::getter(const char *id) // Get the value from the hash table if it is already present const map& options = _decoder->options(); - map::const_iterator iter = options.find(id); + auto iter = options.find(id); if (iter != options.end()) val = (*iter).second; diff --git a/DSView/pv/prop/binding/decoderoptions.h b/DSView/pv/prop/binding/decoderoptions.h index 62d91ec3..258c3a62 100755 --- a/DSView/pv/prop/binding/decoderoptions.h +++ b/DSView/pv/prop/binding/decoderoptions.h @@ -23,7 +23,7 @@ #include "binding.h" -#include +#include "../property.h" struct srd_decoder_option; @@ -42,23 +42,23 @@ namespace binding { class DecoderOptions : public Binding { public: - DecoderOptions(boost::shared_ptr decoder_stack, - boost::shared_ptr decoder); + DecoderOptions(pv::data::DecoderStack *decoder_stack, + pv::data::decode::Decoder* decoder); GVariant* getter(const char *id); void setter(const char *id, GVariant *value); private: - static boost::shared_ptr bind_enum(const QString &name, + static Property* bind_enum(const QString &name, const srd_decoder_option *option, Property::Getter getter, Property::Setter setter); private: - boost::shared_ptr _decoder_stack; - boost::shared_ptr _decoder; + pv::data::DecoderStack *_decoder_stack; + pv::data::decode::Decoder *_decoder; }; } // binding diff --git a/DSView/pv/prop/binding/deviceoptions.cpp b/DSView/pv/prop/binding/deviceoptions.cpp index deef3fac..1b4f1b15 100755 --- a/DSView/pv/prop/binding/deviceoptions.cpp +++ b/DSView/pv/prop/binding/deviceoptions.cpp @@ -166,9 +166,9 @@ void DeviceOptions::config_setter( void DeviceOptions::bind_bool(const QString &name, const QString label, int key) { - _properties.push_back(boost::shared_ptr( + _properties.push_back( new Bool(name, label, bind(config_getter, _sdi, key), - bind(config_setter, _sdi, key, _1)))); + bind(config_setter, _sdi, key, _1))); } void DeviceOptions::bind_enum(const QString &name, const QString label, int key, @@ -176,7 +176,7 @@ void DeviceOptions::bind_enum(const QString &name, const QString label, int key, { GVariant *gvar; GVariantIter iter; - vector< pair > values; + std::vector< pair > values; assert(gvar_list); @@ -184,29 +184,29 @@ void DeviceOptions::bind_enum(const QString &name, const QString label, int key, while ((gvar = g_variant_iter_next_value (&iter))) values.push_back(make_pair(gvar, printer(gvar))); - _properties.push_back(boost::shared_ptr( + _properties.push_back( new Enum(name, label, values, bind(config_getter, _sdi, key), - bind(config_setter, _sdi, key, _1)))); + bind(config_setter, _sdi, key, _1))); } void DeviceOptions::bind_int(const QString &name, const QString label, int key, QString suffix, optional< std::pair > range) { - _properties.push_back(boost::shared_ptr( + _properties.push_back( new Int(name, label, suffix, range, bind(config_getter, _sdi, key), - bind(config_setter, _sdi, key, _1)))); + bind(config_setter, _sdi, key, _1))); } void DeviceOptions::bind_double(const QString &name, const QString label, int key, QString suffix, optional< std::pair > range, int decimals, boost::optional step) { - _properties.push_back(boost::shared_ptr( + _properties.push_back( new Double(name, label, decimals, suffix, range, step, bind(config_getter, _sdi, key), - bind(config_setter, _sdi, key, _1)))); + bind(config_setter, _sdi, key, _1))); } QString DeviceOptions::print_gvariant(GVariant *const gvar) @@ -242,12 +242,12 @@ void DeviceOptions::bind_samplerate(const QString &name, const QString label, assert(num_elements == 3); - _properties.push_back(boost::shared_ptr( + _properties.push_back( new Double(name, label, 0, QObject::tr("Hz"), make_pair((double)elements[0], (double)elements[1]), (double)elements[2], bind(samplerate_double_getter, _sdi), - bind(samplerate_double_setter, _sdi, _1)))); + bind(samplerate_double_setter, _sdi, _1))); g_variant_unref(gvar_list_samplerates); } @@ -312,7 +312,7 @@ void DeviceOptions::bind_bandwidths(const QString &name, const QString label, in { GVariant *gvar; GVariantIter iter; - vector< pair > values; + std::vector< pair > values; bool bw_limit = FALSE; assert(gvar_list); @@ -332,10 +332,10 @@ void DeviceOptions::bind_bandwidths(const QString &name, const QString label, in while ((gvar = g_variant_iter_next_value (&iter))) values.push_back(make_pair(gvar, printer(gvar))); - _properties.push_back(boost::shared_ptr( + _properties.push_back( new Enum(name, label, values, bind(config_getter, _sdi, key), - bind(config_setter, _sdi, key, _1)))); + bind(config_setter, _sdi, key, _1))); } } // binding diff --git a/DSView/pv/prop/binding/probeoptions.cpp b/DSView/pv/prop/binding/probeoptions.cpp index 3b6a101f..be3806c9 100755 --- a/DSView/pv/prop/binding/probeoptions.cpp +++ b/DSView/pv/prop/binding/probeoptions.cpp @@ -138,9 +138,9 @@ void ProbeOptions::config_setter( void ProbeOptions::bind_bool(const QString &name, const QString label, int key) { - _properties.push_back(boost::shared_ptr( + _properties.push_back( new Bool(name, label, bind(config_getter, _sdi, _probe, key), - bind(config_setter, _sdi, _probe, key, _1)))); + bind(config_setter, _sdi, _probe, key, _1))); } void ProbeOptions::bind_enum(const QString &name, const QString label, int key, @@ -148,7 +148,7 @@ void ProbeOptions::bind_enum(const QString &name, const QString label, int key, { GVariant *gvar; GVariantIter iter; - vector< pair > values; + std::vector< pair > values; assert(gvar_list); @@ -156,29 +156,29 @@ void ProbeOptions::bind_enum(const QString &name, const QString label, int key, while ((gvar = g_variant_iter_next_value (&iter))) values.push_back(make_pair(gvar, printer(gvar))); - _properties.push_back(boost::shared_ptr( + _properties.push_back( new Enum(name, label, values, bind(config_getter, _sdi, _probe, key), - bind(config_setter, _sdi, _probe, key, _1)))); + bind(config_setter, _sdi, _probe, key, _1))); } void ProbeOptions::bind_int(const QString &name, const QString label, int key, QString suffix, optional< std::pair > range) { - _properties.push_back(boost::shared_ptr( + _properties.push_back( new Int(name, label, suffix, range, bind(config_getter, _sdi, _probe, key), - bind(config_setter, _sdi, _probe, key, _1)))); + bind(config_setter, _sdi, _probe, key, _1))); } void ProbeOptions::bind_double(const QString &name, const QString label, int key, QString suffix, optional< std::pair > range, int decimals, boost::optional step) { - _properties.push_back(boost::shared_ptr( + _properties.push_back( new Double(name, label, decimals, suffix, range, step, bind(config_getter, _sdi, _probe, key), - bind(config_setter, _sdi, _probe, key, _1)))); + bind(config_setter, _sdi, _probe, key, _1))); } void ProbeOptions::bind_vdiv(const QString &name, const QString label, diff --git a/DSView/pv/prop/bool.cpp b/DSView/pv/prop/bool.cpp index 75169b86..b31369c2 100755 --- a/DSView/pv/prop/bool.cpp +++ b/DSView/pv/prop/bool.cpp @@ -65,12 +65,12 @@ QWidget* Bool::get_widget(QWidget *parent, bool auto_commit) return _check_box; } -bool Bool::labeled_widget() const +bool Bool::labeled_widget() { return true; } -GVariant* Bool::get_value() const +GVariant* Bool::get_value() { GVariant *const value = _getter ? _getter() : NULL; diff --git a/DSView/pv/prop/bool.h b/DSView/pv/prop/bool.h index c9f9e409..5603914c 100755 --- a/DSView/pv/prop/bool.h +++ b/DSView/pv/prop/bool.h @@ -40,9 +40,9 @@ public: virtual ~Bool(); QWidget* get_widget(QWidget *parent, bool auto_commit); - bool labeled_widget() const; + bool labeled_widget(); - GVariant* get_value() const; + GVariant* get_value(); void commit(); diff --git a/DSView/pv/prop/enum.cpp b/DSView/pv/prop/enum.cpp index 9f5aadca..d5bd8665 100755 --- a/DSView/pv/prop/enum.cpp +++ b/DSView/pv/prop/enum.cpp @@ -34,13 +34,13 @@ namespace pv { namespace prop { Enum::Enum(QString name, QString label, - vector > values, + std::vector > values, Getter getter, Setter setter) : Property(name, label, getter, setter), _values(values), _selector(NULL) { - for (vector< pair >::const_iterator i = + for (std::vector< pair >::const_iterator i = _values.begin(); i != _values.end(); i++) g_variant_ref((*i).first); } diff --git a/DSView/pv/prop/property.cpp b/DSView/pv/prop/property.cpp index de7150b5..7933398f 100755 --- a/DSView/pv/prop/property.cpp +++ b/DSView/pv/prop/property.cpp @@ -33,22 +33,26 @@ Property::Property(QString name, QString label, Getter getter, Setter setter) : { } -const QString& Property::name() const +Property::~Property(){ + +} + +const QString& Property::name() { return _name; } -const QString& Property::label() const +const QString& Property::label() { return _label; } -bool Property::labeled_widget() const +bool Property::labeled_widget() { return false; } -GVariant* Property::get_value() const +GVariant* Property::get_value() { return NULL; } diff --git a/DSView/pv/prop/property.h b/DSView/pv/prop/property.h index 2868eedb..5ba344be 100755 --- a/DSView/pv/prop/property.h +++ b/DSView/pv/prop/property.h @@ -47,14 +47,16 @@ protected: Property(QString name, QString label, Getter getter, Setter setter); public: - const QString& name() const; - const QString& label() const; + const QString& name(); + const QString& label(); + + virtual ~Property(); virtual QWidget* get_widget(QWidget *parent, bool auto_commit = false) = 0; - virtual bool labeled_widget() const; + virtual bool labeled_widget(); - virtual GVariant* get_value() const; + virtual GVariant* get_value(); virtual void commit() = 0; diff --git a/DSView/pv/sigsession.cpp b/DSView/pv/sigsession.cpp index c5552d6f..b75f55c9 100755 --- a/DSView/pv/sigsession.cpp +++ b/DSView/pv/sigsession.cpp @@ -71,8 +71,7 @@ using namespace boost; -using namespace std; - + namespace pv { // TODO: This should not be necessary @@ -115,16 +114,16 @@ SigSession::SigSession(DeviceManager *device_manager) : _stop_scale = 1; // Create snapshots & data containers - _cur_logic_snapshot.reset(new data::LogicSnapshot()); - _logic_data.reset(new data::Logic()); + _cur_logic_snapshot = new data::LogicSnapshot(); + _logic_data = new data::Logic(); _logic_data->push_snapshot(_cur_logic_snapshot); - _cur_dso_snapshot.reset(new data::DsoSnapshot()); - _dso_data.reset(new data::Dso()); + _cur_dso_snapshot = new data::DsoSnapshot(); + _dso_data = new data::Dso(); _dso_data->push_snapshot(_cur_dso_snapshot); - _cur_analog_snapshot.reset(new data::AnalogSnapshot()); - _analog_data.reset(new data::Analog()); + _cur_analog_snapshot = new data::AnalogSnapshot(); + _analog_data = new data::Analog(); _analog_data->push_snapshot(_cur_analog_snapshot); - _group_data.reset(new data::Group()); + _group_data = new data::Group(); _group_cnt = 0; connect(&_feed_timer, SIGNAL(timeout()), this, SLOT(feed_timeout())); @@ -136,7 +135,7 @@ SigSession::~SigSession() { } -DevInst* SigSession::get_device() const +DevInst* SigSession::get_device() { return _dev_inst; } @@ -230,7 +229,7 @@ void SigSession::set_default_device(boost::function error_ DevInst *default_device = NULL; - const list &devices = _device_manager->devices(); + const std::list &devices = _device_manager->devices(); if (!devices.empty()) { // Fall back to the first device in the list. default_device = devices.front(); @@ -265,18 +264,18 @@ void SigSession::release_device(DevInst *dev_inst) _dev_inst = NULL; } -SigSession::capture_state SigSession::get_capture_state() const +SigSession::capture_state SigSession::get_capture_state() { std::lock_guard lock(_sampling_mutex); return _capture_state; } -uint64_t SigSession::cur_samplelimits() const +uint64_t SigSession::cur_samplelimits() { return _cur_samplelimits; } -uint64_t SigSession::cur_samplerate() const +uint64_t SigSession::cur_samplerate() { // samplerate for current viewport if (_dev_inst->dev_inst()->mode == DSO) @@ -285,23 +284,23 @@ uint64_t SigSession::cur_samplerate() const return cur_snap_samplerate(); } -uint64_t SigSession::cur_snap_samplerate() const +uint64_t SigSession::cur_snap_samplerate() { // samplerate for current snapshot return _cur_snap_samplerate; } -double SigSession::cur_sampletime() const +double SigSession::cur_sampletime() { return cur_samplelimits() * 1.0 / cur_samplerate(); } -double SigSession::cur_snap_sampletime() const +double SigSession::cur_snap_sampletime() { return cur_samplelimits() * 1.0 / cur_snap_samplerate(); } -double SigSession::cur_view_time() const +double SigSession::cur_view_time() { return _dev_inst->get_time_base() * DS_CONF_DSO_HDIVS * 1.0 / SR_SEC(1); } @@ -374,12 +373,12 @@ void SigSession::capture_init() for(auto &s : _signals) { assert(s); - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(s))) { + view::DsoSignal *dsoSig = NULL; + if ((dsoSig = dynamic_cast(s))) { dsoSig->set_zero_ratio(dsoSig->get_zero_ratio()); } - boost::shared_ptr analogSig; - if ((analogSig = dynamic_pointer_cast(s))) { + view::AnalogSignal *analogSig = NULL; + if ((analogSig = dynamic_cast(s))) { analogSig->set_zero_ratio(analogSig->get_zero_ratio()); } } @@ -450,8 +449,8 @@ void SigSession::start_capture(bool instant, for(auto &s : _signals) { assert(s); - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(s))) + view::DsoSignal *dsoSig = NULL; + if ((dsoSig = dynamic_cast(s))) dsoSig->set_mValid(false); } @@ -489,10 +488,7 @@ void SigSession::stop_capture() { data_unlock(); - for (vector< boost::shared_ptr >::iterator i = - _decode_traces.begin(); - i != _decode_traces.end(); - i++) + for (auto i = _decode_traces.begin(); i != _decode_traces.end(); i++) (*i)->decoder()->stop_decode(); if (get_capture_state() != Running) @@ -530,22 +526,20 @@ bool SigSession::get_capture_status(bool &triggered, int &progress) return false; } -vector< boost::shared_ptr >& SigSession::get_signals() -{ - //boost::lock_guard lock(_signals_mutex); +std::vector& SigSession::get_signals() +{ return _signals; } -vector< boost::shared_ptr > SigSession::get_group_signals() -{ - //boost::lock_guard lock(_signals_mutex); +std::vector& SigSession::get_group_signals() +{ return _group_traces; } -set< boost::shared_ptr > SigSession::get_data() const +std::set SigSession::get_data() { //lock_guard lock(_signals_mutex); - set< boost::shared_ptr > data; + std::set data; for(auto &sig : _signals) { assert(sig); @@ -617,37 +611,25 @@ void SigSession::add_group() { std::list probe_index_list; - std::vector< boost::shared_ptr >::iterator i = _signals.begin(); + auto i = _signals.begin(); while (i != _signals.end()) { if ((*i)->get_type() == SR_CHANNEL_LOGIC && (*i)->selected()) probe_index_list.push_back((*i)->get_index()); i++; } - if (probe_index_list.size() > 1) { - //_group_data.reset(new data::Group(_last_sample_rate)); -// if (_group_data->get_snapshots().empty()) -// _group_data->set_samplerate(_dev_inst->get_sample_rate()); + if (probe_index_list.size() > 1) { _group_data->init(); _group_data->set_samplerate(_cur_snap_samplerate); - const boost::shared_ptr signal( - new view::GroupSignal("New Group", - _group_data, probe_index_list, _group_cnt)); + auto signal = new view::GroupSignal("New Group", _group_data, probe_index_list, _group_cnt); _group_traces.push_back(signal); _group_cnt++; - const deque< boost::shared_ptr > &snapshots = - _logic_data->get_snapshots(); - if (!snapshots.empty()) { - //if (!_cur_group_snapshot) - //{ - // Create a new data snapshot - _cur_group_snapshot = boost::shared_ptr( - new data::GroupSnapshot(snapshots.front(), signal->get_index_list())); - //_cur_group_snapshot->append_payload(); - _group_data->push_snapshot(_cur_group_snapshot); - _cur_group_snapshot.reset(); - //} + const auto &snapshots = _logic_data->get_snapshots(); + if (!snapshots.empty()) + { + auto p = new data::GroupSnapshot(snapshots.front(), signal->get_index_list()); + _group_data->push_snapshot(p); } signals_changed(); @@ -657,25 +639,32 @@ void SigSession::add_group() void SigSession::del_group() { - std::vector< boost::shared_ptr >::iterator i = _group_traces.begin(); + auto i = _group_traces.begin(); + while (i != _group_traces.end()) { - if ((*i)->selected()) { - std::vector< boost::shared_ptr >::iterator j = _group_traces.begin(); + pv::view::GroupSignal *psig = *(i); + + if (psig->selected()) { + auto j = _group_traces.begin(); while(j != _group_traces.end()) { - if ((*j)->get_sec_index() > (*i)->get_sec_index()) + if ((*j)->get_sec_index() > psig->get_sec_index()) (*j)->set_sec_index((*j)->get_sec_index() - 1); j++; } - std::deque< boost::shared_ptr > &snapshots = _group_data->get_snapshots(); + auto &snapshots = _group_data->get_snapshots(); if (!snapshots.empty()) { - _group_data->get_snapshots().at((*i)->get_sec_index()).reset(); - std::deque< boost::shared_ptr >::iterator k = snapshots.begin(); + int dex = psig->get_sec_index(); + pv::data::GroupSnapshot *pshot = _group_data->get_snapshots().at(dex); + delete pshot; + + auto k = snapshots.begin(); k += (*i)->get_sec_index(); _group_data->get_snapshots().erase(k); } + + delete psig; - (*i).reset(); i = _group_traces.erase(i); _group_cnt--; @@ -693,8 +682,8 @@ void SigSession::init_signals() assert(_dev_inst); stop_capture(); - vector< boost::shared_ptr > sigs; - boost::shared_ptr signal; + std::vector sigs; + view::Signal *signal = NULL; unsigned int logic_probe_count = 0; unsigned int dso_probe_count = 0; unsigned int analog_probe_count = 0; @@ -741,37 +730,35 @@ void SigSession::init_signals() // Make the logic probe list { _group_traces.clear(); - vector< boost::shared_ptr >().swap(_group_traces); + std::vector().swap(_group_traces); for (GSList *l = _dev_inst->dev_inst()->channels; l; l = l->next) { sr_channel *probe = ( sr_channel *)l->data; assert(probe); - signal.reset(); + signal = NULL; + switch(probe->type) { case SR_CHANNEL_LOGIC: if (probe->enabled) - signal = boost::shared_ptr( - new view::LogicSignal(_dev_inst, _logic_data, probe)); + signal = new view::LogicSignal(_dev_inst, _logic_data, probe); break; case SR_CHANNEL_DSO: - signal = boost::shared_ptr( - new view::DsoSignal(_dev_inst, _dso_data, probe)); + signal = new view::DsoSignal(_dev_inst, _dso_data, probe); break; case SR_CHANNEL_ANALOG: if (probe->enabled) - signal = boost::shared_ptr( - new view::AnalogSignal(_dev_inst, _analog_data, probe)); + signal = new view::AnalogSignal(_dev_inst, _analog_data, probe); break; } - if(signal.get()) + if(signal != NULL) sigs.push_back(signal); } _signals.clear(); - vector< boost::shared_ptr >().swap(_signals); + std::vector().swap(_signals); _signals = sigs; } @@ -789,8 +776,8 @@ void SigSession::reload() stop_capture(); //refresh(0); - vector< boost::shared_ptr > sigs; - boost::shared_ptr signal; + std::vector sigs; + view::Signal *signal = NULL; // Make the logic probe list { @@ -798,58 +785,54 @@ void SigSession::reload() sr_channel *probe = (sr_channel *)l->data; assert(probe); - signal.reset(); + signal = NULL; + switch(probe->type) { case SR_CHANNEL_LOGIC: if (probe->enabled) { - std::vector< boost::shared_ptr >::iterator i = _signals.begin(); + auto i = _signals.begin(); while (i != _signals.end()) { if ((*i)->get_index() == probe->index) { - boost::shared_ptr logicSig; - if ((logicSig = dynamic_pointer_cast(*i))) - signal = boost::shared_ptr( - new view::LogicSignal(logicSig, _logic_data, probe)); + view::LogicSignal *logicSig = NULL; + if ((logicSig = dynamic_cast(*i))) + signal = new view::LogicSignal(logicSig, _logic_data, probe); break; } i++; } - if (!signal.get()) - signal = boost::shared_ptr( - new view::LogicSignal(_dev_inst, _logic_data, probe)); + if (signal == NULL){ + signal = new view::LogicSignal(_dev_inst, _logic_data, probe); + } } break; -// case SR_CHANNEL_DSO: -// signal = boost::shared_ptr( -// new view::DsoSignal(_dev_inst,_dso_data, probe)); -// break; - + case SR_CHANNEL_ANALOG: if (probe->enabled) { - std::vector< boost::shared_ptr >::iterator i = _signals.begin(); + auto i = _signals.begin(); while (i != _signals.end()) { if ((*i)->get_index() == probe->index) { - boost::shared_ptr analogSig; - if ((analogSig = dynamic_pointer_cast(*i))) - signal = boost::shared_ptr( - new view::AnalogSignal(analogSig, _analog_data, probe)); + view::AnalogSignal *analogSig = NULL; + if ((analogSig = dynamic_cast(*i))) + signal = new view::AnalogSignal(analogSig, _analog_data, probe); break; } i++; } - if (!signal.get()) - signal = boost::shared_ptr( - new view::AnalogSignal(_dev_inst, _analog_data, probe)); + if (signal == NULL){ + signal = new view::AnalogSignal(_dev_inst, _analog_data, probe); + } + } break; } - if (signal.get()) + if (signal != NULL) sigs.push_back(signal); } if (!sigs.empty()) { _signals.clear(); - vector< boost::shared_ptr >().swap(_signals); + std::vector().swap(_signals); _signals = sigs; } } @@ -864,8 +847,7 @@ void SigSession::refresh(int holdtime) data_lock(); if (_logic_data) { - _logic_data->init(); - //_cur_logic_snapshot.reset(); + _logic_data->init(); for(auto &d : _decode_traces) { @@ -886,8 +868,7 @@ void SigSession::refresh(int holdtime) _math_trace->get_math_stack()->init(); } if (_analog_data) { - _analog_data->init(); - //_cur_analog_snapshot.reset(); + _analog_data->init(); } QTimer::singleShot(holdtime, this, SLOT(feed_timeout())); @@ -978,8 +959,7 @@ void SigSession::feed_in_trigger(const ds_trigger_pos &trigger_pos) } void SigSession::feed_in_logic(const sr_datafeed_logic &logic) -{ - //boost::lock_guard lock(_data_mutex); +{ if (!_logic_data || _cur_logic_snapshot->memory_failed()) { qDebug() << "Unexpected logic packet"; return; @@ -1016,9 +996,7 @@ void SigSession::feed_in_logic(const sr_datafeed_logic &logic) } void SigSession::feed_in_dso(const sr_datafeed_dso &dso) -{ - //boost::lock_guard lock(_data_mutex); - +{ if(!_dso_data || _cur_dso_snapshot->memory_failed()) { qDebug() << "Unexpected dso packet"; @@ -1032,8 +1010,8 @@ void SigSession::feed_in_dso(const sr_datafeed_dso &dso) for(auto &s : _signals) { assert(s); - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(s))) { + view::DsoSignal *dsoSig = NULL; + if ((dsoSig = dynamic_cast(s))) { dsoSig->set_scale(dsoSig->get_view_rect().height()); sig_enable[dsoSig->get_index()] = dsoSig->enabled(); } @@ -1047,8 +1025,8 @@ void SigSession::feed_in_dso(const sr_datafeed_dso &dso) } for(auto &s : _signals) { - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(s)) && (dsoSig->enabled())) + view::DsoSignal *dsoSig = NULL; + if ((dsoSig = dynamic_cast(s)) && (dsoSig->enabled())) dsoSig->paint_prepare(); } @@ -1088,8 +1066,7 @@ void SigSession::feed_in_dso(const sr_datafeed_dso &dso) } void SigSession::feed_in_analog(const sr_datafeed_analog &analog) -{ - //boost::lock_guard lock(_data_mutex); +{ if(!_analog_data || _cur_analog_snapshot->memory_failed()) { @@ -1103,8 +1080,8 @@ void SigSession::feed_in_analog(const sr_datafeed_analog &analog) for(auto &s : _signals) { assert(s); - boost::shared_ptr analogSig; - if ((analogSig = dynamic_pointer_cast(s))) { + view::AnalogSignal *analogSig = NULL; + if ((analogSig = dynamic_cast(s))) { analogSig->set_scale(analogSig->get_totalHeight()); } } @@ -1187,16 +1164,14 @@ void SigSession::data_feed_in(const struct sr_dev_inst *sdi, case SR_DF_END: { { - //boost::lock_guard lock(_data_mutex); + if (!_cur_logic_snapshot->empty()) { for(auto &g : _group_traces) { assert(g); - _cur_group_snapshot = boost::shared_ptr( - new data::GroupSnapshot(_logic_data->get_snapshots().front(), g->get_index_list())); - _group_data->push_snapshot(_cur_group_snapshot); - _cur_group_snapshot.reset(); + auto p = new data::GroupSnapshot(_logic_data->get_snapshots().front(), g->get_index_list()); + _group_data->push_snapshot(p); } } _cur_logic_snapshot->capture_ended(); @@ -1331,20 +1306,18 @@ uint16_t SigSession::get_ch_num(int type) uint16_t logic_ch_num = 0; uint16_t dso_ch_num = 0; uint16_t analog_ch_num = 0; + if (_dev_inst->dev_inst()) { for(auto &s : _signals) { assert(s); - if (dynamic_pointer_cast(s) && s->enabled()) { - //if (dynamic_pointer_cast(s)) { + if (dynamic_cast(s) && s->enabled()) { logic_ch_num++; } - if (dynamic_pointer_cast(s) && s->enabled()) { - //if (dynamic_pointer_cast(s)) { + if (dynamic_cast(s) && s->enabled()) { dso_ch_num++; } - if (dynamic_pointer_cast(s) && s->enabled()) { - //if (dynamic_pointer_cast(s)) { + if (dynamic_cast(s) && s->enabled()) { analog_ch_num++; } } @@ -1366,75 +1339,74 @@ uint16_t SigSession::get_ch_num(int type) bool SigSession::add_decoder(srd_decoder *const dec, bool silent, DecoderStatus *dstatus) -{ - bool ret = false; - map probes; - boost::shared_ptr decoder_stack; +{ + try { - try { - //lock_guard lock(_signals_mutex); + bool ret = false; // Create the decoder - decoder_stack = boost::shared_ptr( - new data::DecoderStack(this, dec, dstatus)); + std::map probes; + data::DecoderStack *decoder_stack = new data::DecoderStack(this, dec, dstatus); + assert(decoder_stack); // Make a list of all the probes std::vector all_probes; for(const GSList *i = dec->channels; i; i = i->next) all_probes.push_back((const srd_channel*)i->data); + for(const GSList *i = dec->opt_channels; i; i = i->next) all_probes.push_back((const srd_channel*)i->data); - - assert(decoder_stack); - assert(!decoder_stack->stack().empty()); - assert(decoder_stack->stack().front()); + decoder_stack->stack().front()->set_probes(probes); // Create the decode signal - boost::shared_ptr d( - new view::DecodeTrace(this, decoder_stack, - _decode_traces.size())); + view::DecodeTrace *trace = new view::DecodeTrace(this, decoder_stack, _decode_traces.size()); + assert(trace); + // set view early for decode start/end region setting for(auto &s : _signals) { if (s->get_view()) { - d->set_view(s->get_view()); + trace->set_view(s->get_view()); break; } } if (silent) { - _decode_traces.push_back(d); + _decode_traces.push_back(trace); ret = true; - } else if (d->create_popup()) { - _decode_traces.push_back(d); + } else if (trace->create_popup()) { + _decode_traces.push_back(trace); ret = true; } - } catch(const std::runtime_error &e) { - return false; - } - if (ret) { - signals_changed(); - // Do an initial decode - decoder_stack->begin_decode(); - data_updated(); - } + if (ret) + { + signals_changed(); + // Do an initial decode + decoder_stack->begin_decode(); + data_updated(); + } + else{ + delete trace; + } - return ret; + return ret; + + } catch(...) { + ds_debug("Starting a hotplug thread...\n"); + } + + return false; } -vector< boost::shared_ptr > SigSession::get_decode_signals() const -{ - //lock_guard lock(_signals_mutex); +std::vector& SigSession::get_decode_signals() +{ return _decode_traces; } void SigSession::remove_decode_signal(view::DecodeTrace *signal) { - for (vector< boost::shared_ptr >::iterator i = - _decode_traces.begin(); - i != _decode_traces.end(); - i++) - if ((*i).get() == signal) + for (auto i = _decode_traces.begin(); i != _decode_traces.end(); i++) + if ((*i) == signal) { _decode_traces.erase(i); signals_changed(); @@ -1445,14 +1417,12 @@ void SigSession::remove_decode_signal(view::DecodeTrace *signal) void SigSession::remove_decode_signal(int index) { int cur_index = 0; - for (vector< boost::shared_ptr >::iterator i = - _decode_traces.begin(); - i != _decode_traces.end(); - i++) + + for (auto i = _decode_traces.begin(); i != _decode_traces.end(); i++) { if (cur_index == index) { - auto d = (*i)->decoder().get(); + auto d = (*i)->decoder(); d->stop_decode(); //stop decoder thread _decode_traces.erase(i); signals_changed(); @@ -1464,45 +1434,35 @@ void SigSession::remove_decode_signal(int index) void SigSession::rst_decoder(int index) { - int cur_index = 0; - for (vector< boost::shared_ptr >::iterator i = - _decode_traces.begin(); - i != _decode_traces.end(); - i++) - { - if (cur_index == index) - { - if ((*i)->create_popup()) + if (index >= 0 && index < (int)_decode_traces.size()){ + auto p = _decode_traces[index]; + if (p->create_popup()) { - (*i)->decoder()->stop_decode(); - (*i)->decoder()->begin_decode(); + p->decoder()->stop_decode(); + p->decoder()->begin_decode(); data_updated(); } - return; - } - cur_index++; } } void SigSession::rst_decoder(view::DecodeTrace *signal) -{ - for (vector< boost::shared_ptr >::iterator i = - _decode_traces.begin(); - i != _decode_traces.end(); - i++) - if ((*i).get() == signal) - { - if ((*i)->create_popup()) - { - (*i)->decoder()->stop_decode(); - (*i)->decoder()->begin_decode(); - data_updated(); - } - return; - } +{ + for (auto p : _decode_traces) + { + if (p == signal) + { + if (p->create_popup()) + { + p->decoder()->stop_decode(); + p->decoder()->begin_decode(); + data_updated(); + } + break; + } + } } -pv::data::DecoderModel* SigSession::get_decoder_model() const +pv::data::DecoderModel* SigSession::get_decoder_model() { return _decoder_model; } @@ -1512,20 +1472,18 @@ void SigSession::spectrum_rebuild() { bool has_dso_signal = false; for(auto &s : _signals) { - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(s))) { + view::DsoSignal *dsoSig = NULL; + if ((dsoSig = dynamic_cast(s))) { has_dso_signal = true; // check already have - std::vector< boost::shared_ptr >::iterator iter = _spectrum_traces.begin(); + auto iter = _spectrum_traces.begin(); for(unsigned int i = 0; i < _spectrum_traces.size(); i++, iter++) if ((*iter)->get_index() == dsoSig->get_index()) break; // if not, rebuild if (iter == _spectrum_traces.end()) { - boost::shared_ptr spectrum_stack( - new data::SpectrumStack(this, dsoSig->get_index())); - boost::shared_ptr spectrum_trace( - new view::SpectrumTrace(this, spectrum_stack, dsoSig->get_index())); + auto spectrum_stack = new data::SpectrumStack(this, dsoSig->get_index()); + auto spectrum_trace = new view::SpectrumTrace(this, spectrum_stack, dsoSig->get_index()); _spectrum_traces.push_back(spectrum_trace); } } @@ -1537,15 +1495,14 @@ void SigSession::spectrum_rebuild() signals_changed(); } -vector< boost::shared_ptr > SigSession::get_spectrum_traces() -{ - //lock_guard lock(_signals_mutex); +std::vector& SigSession::get_spectrum_traces() +{ return _spectrum_traces; } void SigSession::lissajous_rebuild(bool enable, int xindex, int yindex, double percent) { - _lissajous_trace.reset(new view::LissajousTrace(enable, _dso_data, xindex, yindex, percent)); + _lissajous_trace = new view::LissajousTrace(enable, _dso_data, xindex, yindex, percent); signals_changed(); } @@ -1555,21 +1512,20 @@ void SigSession::lissajous_disable() _lissajous_trace->set_enable(false); } -boost::shared_ptr SigSession::get_lissajous_trace() -{ - //lock_guard lock(_signals_mutex); +view::LissajousTrace* SigSession::get_lissajous_trace() +{ return _lissajous_trace; } -void SigSession::math_rebuild(bool enable, - boost::shared_ptr dsoSig1, - boost::shared_ptr dsoSig2, +void SigSession::math_rebuild(bool enable,view::DsoSignal *dsoSig1, + view::DsoSignal *dsoSig2, data::MathStack::MathType type) { std::lock_guard lock(_data_mutex); - boost::shared_ptr math_stack( - new data::MathStack(this, dsoSig1, dsoSig2, type)); - _math_trace.reset(new view::MathTrace(enable, math_stack, dsoSig1, dsoSig2)); + auto math_stack = new data::MathStack(this, dsoSig1, dsoSig2, type); + DESTROY_OBJECT(_math_trace); + _math_trace = new view::MathTrace(enable, math_stack, dsoSig1, dsoSig2); + if (_math_trace && _math_trace->enabled()) { _math_trace->get_math_stack()->set_samplerate(_dev_inst->get_sample_rate()); _math_trace->get_math_stack()->realloc(_dev_inst->get_sample_limit()); @@ -1584,9 +1540,8 @@ void SigSession::math_disable() _math_trace->set_enable(false); } -boost::shared_ptr SigSession::get_math_trace() +view::MathTrace* SigSession::get_math_trace() { - //lock_guard lock(_signals_mutex); return _math_trace; } @@ -1595,22 +1550,22 @@ void SigSession::set_session_time(QDateTime time) _session_time = time; } -QDateTime SigSession::get_session_time() const +QDateTime SigSession::get_session_time() { return _session_time; } -uint64_t SigSession::get_trigger_pos() const +uint64_t SigSession::get_trigger_pos() { return _trigger_pos; } -bool SigSession::trigd() const +bool SigSession::trigd() { return _trigger_flag; } -uint8_t SigSession::trigd_ch() const +uint8_t SigSession::trigd_ch() { return _trigger_ch; } @@ -1634,7 +1589,7 @@ void SigSession::feed_timeout() } } -boost::shared_ptr SigSession::get_snapshot(int type) +data::Snapshot* SigSession::get_snapshot(int type) { if (type == SR_CHANNEL_LOGIC) return _cur_logic_snapshot; @@ -1646,7 +1601,7 @@ boost::shared_ptr SigSession::get_snapshot(int type) return NULL; } -SigSession::error_state SigSession::get_error() const +SigSession::error_state SigSession::get_error() { return _error; } @@ -1662,12 +1617,12 @@ void SigSession::clear_error() _error = No_err; } -uint64_t SigSession::get_error_pattern() const +uint64_t SigSession::get_error_pattern() { return _error_pattern; } -SigSession::run_mode SigSession::get_run_mode() const +SigSession::run_mode SigSession::get_run_mode() { return _run_mode; } @@ -1677,7 +1632,7 @@ void SigSession::set_run_mode(run_mode mode) _run_mode = mode; } -int SigSession::get_repeat_intvl() const +int SigSession::get_repeat_intvl() { return _repeat_intvl; } @@ -1694,7 +1649,7 @@ void SigSession::set_repeating(bool repeat) _repeat_hold_prg = 0; } -bool SigSession::isRepeating() const +bool SigSession::isRepeating() { return _repeating; } @@ -1729,7 +1684,7 @@ void SigSession::repeat_update() } } -int SigSession::get_repeat_hold() const +int SigSession::get_repeat_hold() { if (isRepeating()) return _repeat_hold_prg; @@ -1742,7 +1697,7 @@ void SigSession::set_map_zoom(int index) _map_zoom = index; } -int SigSession::get_map_zoom() const +int SigSession::get_map_zoom() { return _map_zoom; } @@ -1750,8 +1705,8 @@ int SigSession::get_map_zoom() const void SigSession::auto_end() { for(auto &s : _signals) { - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(s))) { + view::DsoSignal *dsoSig = NULL; + if ((dsoSig = dynamic_cast(s))) { dsoSig->auto_end(); } } @@ -1767,17 +1722,17 @@ void SigSession::set_save_end(uint64_t end) _save_end = end; } -uint64_t SigSession::get_save_start() const +uint64_t SigSession::get_save_start() { return _save_start; } -uint64_t SigSession::get_save_end() const +uint64_t SigSession::get_save_end() { return _save_end; } -bool SigSession::get_saving() const +bool SigSession::get_saving() { return _saving; } @@ -1804,7 +1759,7 @@ void SigSession::exit_capture() } } -float SigSession::stop_scale() const +float SigSession::stop_scale() { return _stop_scale; } diff --git a/DSView/pv/sigsession.h b/DSView/pv/sigsession.h index 9cd6324e..2ae6c63c 100755 --- a/DSView/pv/sigsession.h +++ b/DSView/pv/sigsession.h @@ -24,9 +24,7 @@ #define DSVIEW_PV_SIGSESSION_H #include -#include -#include -#include +#include #include #include @@ -139,7 +137,7 @@ public: ~SigSession(); - DevInst* get_device() const; + DevInst* get_device(); /** * Sets device instance that will be used in the next capture session. @@ -156,20 +154,20 @@ public: void release_device(DevInst *dev_inst); - capture_state get_capture_state() const; + capture_state get_capture_state(); - uint64_t cur_samplerate() const; - uint64_t cur_snap_samplerate() const; - uint64_t cur_samplelimits() const; - double cur_sampletime() const; - double cur_snap_sampletime() const; - double cur_view_time() const; + uint64_t cur_samplerate(); + uint64_t cur_snap_samplerate(); + uint64_t cur_samplelimits(); + double cur_sampletime(); + double cur_snap_sampletime(); + double cur_view_time(); void set_cur_snap_samplerate(uint64_t samplerate); void set_cur_samplelimits(uint64_t samplelimits); void set_session_time(QDateTime time); - QDateTime get_session_time() const; - uint64_t get_trigger_pos() const; + QDateTime get_session_time(); + uint64_t get_trigger_pos(); void start_capture(bool instant, boost::function error_handler); @@ -177,19 +175,15 @@ public: bool get_capture_status(bool &triggered, int &progress); void container_init(); - std::set< boost::shared_ptr > get_data() const; + std::set get_data(); - std::vector< boost::shared_ptr >& - get_signals(); - - std::vector< boost::shared_ptr > - get_group_signals(); + std::vector& get_signals(); + std::vector& get_group_signals(); bool add_decoder(srd_decoder *const dec, bool silent, DecoderStatus *dstatus); - std::vector< boost::shared_ptr > - get_decode_signals() const; + std::vector& get_decode_signals(); void remove_decode_signal(view::DecodeTrace *signal); @@ -199,17 +193,13 @@ public: void rst_decoder(view::DecodeTrace *signal); - pv::data::DecoderModel* get_decoder_model() const; + pv::data::DecoderModel* get_decoder_model(); + std::vector& get_spectrum_traces(); - std::vector< boost::shared_ptr > - get_spectrum_traces(); + view::LissajousTrace* get_lissajous_trace(); - boost::shared_ptr - get_lissajous_trace(); - - boost::shared_ptr - get_math_trace(); + view::MathTrace* get_math_trace(); void init_signals(); @@ -232,40 +222,39 @@ public: void spectrum_rebuild(); void lissajous_rebuild(bool enable, int xindex, int yindex, double percent); void lissajous_disable(); - void math_rebuild(bool enable, - boost::shared_ptr dsoSig1, - boost::shared_ptr dsoSig2, + void math_rebuild(bool enable,pv::view::DsoSignal *dsoSig1, + pv::view::DsoSignal *dsoSig2, data::MathStack::MathType type); void math_disable(); - bool trigd() const; - uint8_t trigd_ch() const; + bool trigd(); + uint8_t trigd_ch(); - boost::shared_ptr get_snapshot(int type); + data::Snapshot* get_snapshot(int type); - error_state get_error() const; + error_state get_error(); void set_error(error_state state); void clear_error(); - uint64_t get_error_pattern() const; + uint64_t get_error_pattern(); - run_mode get_run_mode() const; + run_mode get_run_mode(); void set_run_mode(run_mode mode); - int get_repeat_intvl() const; + int get_repeat_intvl(); void set_repeat_intvl(int interval); - bool isRepeating() const; + bool isRepeating(); bool repeat_check(); - int get_repeat_hold() const; + int get_repeat_hold(); - int get_map_zoom() const; + int get_map_zoom(); void set_save_start(uint64_t start); void set_save_end(uint64_t end); - uint64_t get_save_start() const; - uint64_t get_save_end() const; - bool get_saving() const; + uint64_t get_save_start(); + uint64_t get_save_end(); + bool get_saving(); void set_saving(bool saving); void set_stop_scale(float scale); - float stop_scale() const; + float stop_scale(); void exit_capture(); @@ -402,25 +391,24 @@ private: uint64_t _cur_samplelimits; //mutable std::mutex _signals_mutex; - std::vector< boost::shared_ptr > _signals; - std::vector< boost::shared_ptr > _group_traces; + std::vector _signals; + std::vector _group_traces; - std::vector< boost::shared_ptr > _decode_traces; - pv::data::DecoderModel *_decoder_model; + std::vector _decode_traces; + pv::data::DecoderModel *_decoder_model; - std::vector< boost::shared_ptr > _spectrum_traces; - boost::shared_ptr _lissajous_trace; - boost::shared_ptr _math_trace; + std::vector _spectrum_traces; + view::LissajousTrace *_lissajous_trace; + view::MathTrace *_math_trace; mutable std::mutex _data_mutex; - boost::shared_ptr _logic_data; - boost::shared_ptr _cur_logic_snapshot; - boost::shared_ptr _dso_data; - boost::shared_ptr _cur_dso_snapshot; - boost::shared_ptr _analog_data; - boost::shared_ptr _cur_analog_snapshot; - boost::shared_ptr _group_data; - boost::shared_ptr _cur_group_snapshot; + data::Logic *_logic_data; + data::LogicSnapshot *_cur_logic_snapshot; + data::Dso *_dso_data; + data::DsoSnapshot *_cur_dso_snapshot; + data::Analog *_analog_data; + data::AnalogSnapshot *_cur_analog_snapshot; + data::Group *_group_data; int _group_cnt; std::thread *_sampling_thread; diff --git a/DSView/pv/storesession.cpp b/DSView/pv/storesession.cpp index 230fd51a..c99d2efe 100755 --- a/DSView/pv/storesession.cpp +++ b/DSView/pv/storesession.cpp @@ -82,13 +82,13 @@ SigSession* StoreSession::session() return _session; } -pair StoreSession::progress() const +std::pair StoreSession::progress() { //lock_guard lock(_mutex); - return make_pair(_units_stored, _unit_count); + return std::make_pair(_units_stored, _unit_count); } -const QString& StoreSession::error() const +const QString& StoreSession::error() { //lock_guard lock(_mutex); return _error; @@ -153,7 +153,7 @@ bool StoreSession::save_start() return false; } - const boost::shared_ptr snapshot(_session->get_snapshot(*type_set.begin())); + const auto snapshot = _session->get_snapshot(*type_set.begin()); assert(snapshot); // Check we have data if (snapshot->empty()) { @@ -205,17 +205,17 @@ bool StoreSession::save_start() return false; } -void StoreSession::save_proc(boost::shared_ptr snapshot) +void StoreSession::save_proc(data::Snapshot *snapshot) { assert(snapshot); int ret = SR_ERR; int num = 0; - boost::shared_ptr logic_snapshot; - boost::shared_ptr analog_snapshot; - boost::shared_ptr dso_snapshot; + data::LogicSnapshot *logic_snapshot = NULL; + //data::AnalogSnapshot *analog_snapshot = NULL; + //data::DsoSnapshot *dso_snapshot = NULL; - if ((logic_snapshot = boost::dynamic_pointer_cast(snapshot))) { + if ((logic_snapshot = dynamic_cast(snapshot))) { uint16_t to_save_probes = 0; for(auto &s : _session->get_signals()) { if (s->enabled() && logic_snapshot->has_data(s->get_index())) @@ -345,7 +345,7 @@ void StoreSession::save_proc(boost::shared_ptr snapshot) } } -QString StoreSession::meta_gen(boost::shared_ptr snapshot) +QString StoreSession::meta_gen(data::Snapshot *snapshot) { GSList *l; GVariant *gvar; @@ -396,8 +396,8 @@ QString StoreSession::meta_gen(boost::shared_ptr snapshot) fprintf(meta, "total blocks = %d\n", snapshot->get_block_num()); } - boost::shared_ptr logic_snapshot; - if ((logic_snapshot = dynamic_pointer_cast(snapshot))) { + data::LogicSnapshot *logic_snapshot = NULL; + if ((logic_snapshot = dynamic_cast(snapshot))) { uint16_t to_save_probes = 0; for (l = sdi->channels; l; l = l->next) { probe = (struct sr_channel *)l->data; @@ -451,8 +451,8 @@ QString StoreSession::meta_gen(boost::shared_ptr snapshot) } else if (sdi->mode == LOGIC) { fprintf(meta, "trigger time = %lld\n", _session->get_session_time().toMSecsSinceEpoch()); } else if (sdi->mode == ANALOG) { - boost::shared_ptr analog_snapshot; - if ((analog_snapshot = dynamic_pointer_cast(snapshot))) { + data::AnalogSnapshot *analog_snapshot = NULL; + if ((analog_snapshot = dynamic_cast(snapshot))) { uint8_t tmp_u8 = analog_snapshot->get_unit_bytes(); fprintf(meta, "bits = %d\n", tmp_u8*8); } @@ -559,7 +559,7 @@ bool StoreSession::export_start() return false; } - const boost::shared_ptr snapshot(_session->get_snapshot(*type_set.begin())); + const auto snapshot = _session->get_snapshot(*type_set.begin()); assert(snapshot); // Check we have data if (snapshot->empty()) { @@ -605,20 +605,20 @@ bool StoreSession::export_start() return false; } -void StoreSession::export_proc(boost::shared_ptr snapshot) +void StoreSession::export_proc(data::Snapshot *snapshot) { assert(snapshot); - boost::shared_ptr logic_snapshot; - boost::shared_ptr analog_snapshot; - boost::shared_ptr dso_snapshot; + data::LogicSnapshot *logic_snapshot = NULL; + data::AnalogSnapshot *analog_snapshot = NULL; + data::DsoSnapshot *dso_snapshot = NULL; int channel_type; - if ((logic_snapshot = boost::dynamic_pointer_cast(snapshot))) { + if ((logic_snapshot = dynamic_cast(snapshot))) { channel_type = SR_CHANNEL_LOGIC; - } else if ((dso_snapshot = boost::dynamic_pointer_cast(snapshot))) { + } else if ((dso_snapshot = dynamic_cast(snapshot))) { channel_type = SR_CHANNEL_DSO; - } else if ((analog_snapshot = boost::dynamic_pointer_cast(snapshot))) { + } else if ((analog_snapshot = dynamic_cast(snapshot))) { channel_type = SR_CHANNEL_ANALOG; } else { _has_error = true; @@ -871,15 +871,15 @@ QJsonArray StoreSession::json_decoders() QJsonObject dec_obj; QJsonArray stack_array; QJsonObject show_obj; - const boost::shared_ptr& stack = t->decoder(); - const std::list< boost::shared_ptr >& decoder = stack->stack(); + const auto &stack = t->decoder(); + const auto &decoder = stack->stack(); for(auto &dec : decoder) { QJsonArray ch_array; const srd_decoder *const d = dec->decoder();; const bool have_probes = (d->channels || d->opt_channels) != 0; if (have_probes) { - for(std::map::const_iterator i = dec->channels().begin(); + for(auto i = dec->channels().begin(); i != dec->channels().end(); i++) { QJsonObject ch_obj; ch_obj[(*i).first->id] = QJsonValue::fromVariant((*i).second); @@ -888,8 +888,8 @@ QJsonArray StoreSession::json_decoders() } QJsonObject options_obj; - boost::shared_ptr dec_binding( - new prop::binding::DecoderOptions(stack, dec)); + auto dec_binding = new prop::binding::DecoderOptions(stack, dec); + for (GSList *l = d->options; l; l = l->next) { const srd_decoder_option *const opt = @@ -934,10 +934,10 @@ QJsonArray StoreSession::json_decoders() dec_obj["stacked decoders"] = stack_array; - std::map rows = stack->get_rows_gshow(); - for (std::map::const_iterator i = rows.begin(); - i != rows.end(); i++) { - show_obj[(*i).first.title()] = QJsonValue::fromVariant((*i).second); + auto rows = stack->get_rows_gshow(); + for (auto i = rows.begin(); i != rows.end(); i++) { + pv::data::decode::Row _row = (*i).first; + show_obj[_row.title()] = QJsonValue::fromVariant((*i).second); } dec_obj["show"] = show_obj; @@ -954,17 +954,18 @@ void StoreSession::load_decoders(dock::ProtocolDock *widget, QJsonArray dec_arra foreach (const QJsonValue &dec_value, dec_array) { QJsonObject dec_obj = dec_value.toObject(); - const vector< boost::shared_ptr > pre_dsigs( - _session->get_decode_signals()); + + auto &pre_dsigs = _session->get_decode_signals(); if (widget->sel_protocol(dec_obj["id"].toString())) widget->add_protocol(true); - const vector< boost::shared_ptr > aft_dsigs( - _session->get_decode_signals()); + + auto &aft_dsigs = _session->get_decode_signals(); if (aft_dsigs.size() > pre_dsigs.size()) { const GSList *l; - boost::shared_ptr new_dsig = aft_dsigs.back(); - const boost::shared_ptr& stack = new_dsig->decoder(); + + auto new_dsig = aft_dsigs.back(); + auto stack = new_dsig->decoder(); if (dec_obj.contains("stacked decoders")) { foreach(const QJsonValue &value, dec_obj["stacked decoders"].toArray()) { @@ -976,8 +977,7 @@ void StoreSession::load_decoders(dock::ProtocolDock *widget, QJsonArray dec_arra assert(d); if (QString::fromUtf8(d->id) == stacked_obj["id"].toString()) { - stack->push(boost::shared_ptr( - new data::decode::Decoder(d))); + stack->push(new data::decode::Decoder(d)); break; } } @@ -985,7 +985,7 @@ void StoreSession::load_decoders(dock::ProtocolDock *widget, QJsonArray dec_arra } } - const std::list< boost::shared_ptr >& decoder = stack->stack(); + auto &decoder = stack->stack(); for(auto &dec : decoder) { const srd_decoder *const d = dec->decoder(); @@ -1074,10 +1074,13 @@ void StoreSession::load_decoders(dock::ProtocolDock *widget, QJsonArray dec_arra if (dec_obj.contains("show")) { QJsonObject show_obj = dec_obj["show"].toObject(); std::map rows = stack->get_rows_gshow(); - for (std::map::const_iterator i = rows.begin(); - i != rows.end(); i++) { - if (show_obj.contains((*i).first.title())) { - stack->set_rows_gshow((*i).first, show_obj[(*i).first.title()].toBool()); + + for (auto i = rows.begin();i != rows.end(); i++) { + QString key = (*i).first.title(); + if (show_obj.contains(key)) { + bool bShow = show_obj[key].toBool(); + const pv::data::decode::Row r = (*i).first; + stack->set_rows_gshow(r, bShow); } } } diff --git a/DSView/pv/storesession.h b/DSView/pv/storesession.h index 2a671365..c4a49448 100755 --- a/DSView/pv/storesession.h +++ b/DSView/pv/storesession.h @@ -25,8 +25,7 @@ #include #include #include - -#include + #include #include @@ -59,9 +58,9 @@ public: SigSession* session(); - std::pair progress() const; + std::pair progress(); - const QString& error() const; + const QString& error(); bool save_start(); @@ -72,9 +71,9 @@ public: void cancel(); private: - void save_proc(boost::shared_ptr snapshot); - QString meta_gen(boost::shared_ptr snapshot); - void export_proc(boost::shared_ptr snapshot); + void save_proc(pv::data::Snapshot *snapshot); + QString meta_gen(data::Snapshot *snapshot); + void export_proc(pv::data::Snapshot *snapshot); QString decoders_gen(); diff --git a/DSView/pv/toolbars/filebar.cpp b/DSView/pv/toolbars/filebar.cpp index 7c6e7880..0262e0ac 100755 --- a/DSView/pv/toolbars/filebar.cpp +++ b/DSView/pv/toolbars/filebar.cpp @@ -20,9 +20,7 @@ */ #include - -#include - + #include #include diff --git a/DSView/pv/toolbars/samplingbar.cpp b/DSView/pv/toolbars/samplingbar.cpp index 5efe3265..59fbcb42 100755 --- a/DSView/pv/toolbars/samplingbar.cpp +++ b/DSView/pv/toolbars/samplingbar.cpp @@ -259,7 +259,7 @@ void SamplingBar::set_device_list(const std::list &devices, DevInst *s _updating_device_selector = false; } -DevInst* SamplingBar::get_selected_device() const +DevInst* SamplingBar::get_selected_device() { const int index = _device_selector.currentIndex(); if (index < 0) @@ -331,11 +331,11 @@ void SamplingBar::on_configure() void SamplingBar::zero_adj() { - boost::shared_ptr dsoSig; + view::DsoSignal *dsoSig = NULL; for(auto &s : _session->get_signals()) { - if ((dsoSig = dynamic_pointer_cast(s))) + if ((dsoSig = dynamic_cast(s))) dsoSig->set_enable(true); } const int index_back = _sample_count.currentIndex(); @@ -352,7 +352,7 @@ void SamplingBar::zero_adj() if (wait.start() == QDialog::Rejected) { for(auto &s : _session->get_signals()) { - if ((dsoSig = dynamic_pointer_cast(s))) + if ((dsoSig = dynamic_cast(s))) dsoSig->commit_settings(); } } @@ -364,19 +364,19 @@ void SamplingBar::zero_adj() commit_hori_res(); } -bool SamplingBar::get_sampling() const +bool SamplingBar::get_sampling() { return _sampling; } -bool SamplingBar::get_instant() const +bool SamplingBar::get_instant() { return _instant; } void SamplingBar::set_sampling(bool sampling) { - lock_guard lock(_sampling_mutex); + std::lock_guard lock(_sampling_mutex); _sampling = sampling; if (!sampling) { @@ -505,7 +505,7 @@ void SamplingBar::update_sample_rate_selector_value() void SamplingBar::on_samplerate_sel(int index) { (void)index; - const DevInst *dev_inst = get_selected_device(); + DevInst *dev_inst = get_selected_device(); if (dev_inst->dev_inst()->mode != DSO) update_sample_count_selector(); } @@ -707,7 +707,7 @@ void SamplingBar::on_samplecount_sel(int index) { (void)index; - const DevInst *dev_inst = get_selected_device(); + DevInst *dev_inst = get_selected_device(); if (dev_inst->dev_inst()->mode == DSO) commit_hori_res(); sig_duration_changed(); diff --git a/DSView/pv/toolbars/samplingbar.h b/DSView/pv/toolbars/samplingbar.h index 833795d0..14779f96 100755 --- a/DSView/pv/toolbars/samplingbar.h +++ b/DSView/pv/toolbars/samplingbar.h @@ -27,9 +27,7 @@ #include #include #include - -#include - + #include #include #include @@ -76,13 +74,13 @@ namespace pv void set_device_list(const std::list &devices, DevInst* selected); - DevInst *get_selected_device() const; + DevInst *get_selected_device(); void update_sample_rate_selector(); void set_sampling(bool sampling); - bool get_sampling() const; - bool get_instant() const; + bool get_sampling(); + bool get_instant(); void enable_toggle(bool enable); diff --git a/DSView/pv/toolbars/titlebar.cpp b/DSView/pv/toolbars/titlebar.cpp index 6d7b58bb..306a417a 100755 --- a/DSView/pv/toolbars/titlebar.cpp +++ b/DSView/pv/toolbars/titlebar.cpp @@ -69,17 +69,17 @@ TitleBar::TitleBar(bool top, QWidget *parent, bool hasClose) : _lay->addWidget(_minimizeButton); _lay->addWidget(_maximizeButton); - connect(this, SIGNAL(normalShow() ), parent, SLOT(showNormal() ) ); - connect(this, SIGNAL( maximizedShow() ), parent, SLOT(showMaximized() ) ); - connect(_minimizeButton, SIGNAL( clicked() ), parent, SLOT(showMinimized() ) ); - connect(_maximizeButton, SIGNAL( clicked() ), this, SLOT(showMaxRestore() ) ); + connect(this, SIGNAL(normalShow()), parent, SLOT(showNormal())); + connect(this, SIGNAL( maximizedShow()), parent, SLOT(showMaximized())); + connect(_minimizeButton, SIGNAL( clicked()), parent, SLOT(showMinimized())); + connect(_maximizeButton, SIGNAL( clicked()), this, SLOT(showMaxRestore())); } if (_isTop || _hasClose) { _closeButton= new QToolButton(this); _closeButton->setObjectName("CloseButton"); _lay->addWidget(_closeButton); - connect(_closeButton, SIGNAL( clicked() ), parent, SLOT(close() ) ); + connect(_closeButton, SIGNAL( clicked()), parent, SLOT(close())); } _lay->insertStretch(0, 500); @@ -160,7 +160,7 @@ void TitleBar::setTitle(QString title) _title->setText(title); } -QString TitleBar::title() const +QString TitleBar::title() { return _title->text(); } diff --git a/DSView/pv/toolbars/titlebar.h b/DSView/pv/toolbars/titlebar.h index a216485b..97245223 100755 --- a/DSView/pv/toolbars/titlebar.h +++ b/DSView/pv/toolbars/titlebar.h @@ -39,7 +39,7 @@ public: ~TitleBar(); void setTitle(QString title); - QString title() const; + QString title(); private: void changeEvent(QEvent *event); diff --git a/DSView/pv/view/analogsignal.cpp b/DSView/pv/view/analogsignal.cpp index 605566ac..0368932f 100755 --- a/DSView/pv/view/analogsignal.cpp +++ b/DSView/pv/view/analogsignal.cpp @@ -47,8 +47,7 @@ const QColor AnalogSignal::SignalColours[4] = { const float AnalogSignal::EnvelopeThreshold = 16.0f; -AnalogSignal::AnalogSignal(DevInst *dev_inst, - boost::shared_ptr data, +AnalogSignal::AnalogSignal(DevInst *dev_inst,data::Analog *data, sr_channel *probe) : Signal(dev_inst, probe), _data(data), @@ -96,10 +95,8 @@ AnalogSignal::AnalogSignal(DevInst *dev_inst, } } -AnalogSignal::AnalogSignal(boost::shared_ptr s, - boost::shared_ptr data, - sr_channel *probe) : - Signal(*s.get(), probe), +AnalogSignal::AnalogSignal(view::AnalogSignal *s, pv::data::Analog *data, sr_channel *probe) : + Signal(*s, probe), _data(data), _rects(NULL), _hover_en(false), @@ -124,7 +121,7 @@ AnalogSignal::~AnalogSignal() } } -boost::shared_ptr AnalogSignal::data() const +pv::data::SignalData* AnalogSignal::data() { return _data; } @@ -134,27 +131,27 @@ void AnalogSignal::set_scale(int height) _scale = height / (_ref_max - _ref_min); } -float AnalogSignal::get_scale() const +float AnalogSignal::get_scale() { return _scale; } -int AnalogSignal::get_bits() const +int AnalogSignal::get_bits() { return _bits; } -double AnalogSignal::get_ref_min() const +double AnalogSignal::get_ref_min() { return _ref_min; } -double AnalogSignal::get_ref_max() const +double AnalogSignal::get_ref_max() { return _ref_max; } -int AnalogSignal::get_hw_offset() const +int AnalogSignal::get_hw_offset() { int hw_offset = 0; GVariant *gvar = _dev_inst->get_config(_probe, NULL, SR_CONF_PROBE_HW_OFFSET); @@ -205,13 +202,11 @@ bool AnalogSignal::measure(const QPointF &p) if (!window.contains(p)) return false; - const deque< boost::shared_ptr > &snapshots = - _data->get_snapshots(); + const auto &snapshots = _data->get_snapshots(); if (snapshots.empty()) return false; - const boost::shared_ptr &snapshot = - snapshots.front(); + const auto snapshot = snapshots.front(); if (snapshot->empty()) return false; @@ -248,13 +243,11 @@ QPointF AnalogSignal::get_point(uint64_t index, float &value) if (!enabled()) return pt; - const deque< boost::shared_ptr > &snapshots = - _data->get_snapshots(); + const auto &snapshots = _data->get_snapshots(); if (snapshots.empty()) return pt; - const boost::shared_ptr &snapshot = - snapshots.front(); + const auto snapshot = snapshots.front(); if (snapshot->empty()) return pt; @@ -288,7 +281,7 @@ QPointF AnalogSignal::get_point(uint64_t index, float &value) /** * Probe options **/ -uint64_t AnalogSignal::get_vdiv() const +uint64_t AnalogSignal::get_vdiv() { uint64_t vdiv = 0; GVariant* gvar = _dev_inst->get_config(_probe, NULL, SR_CONF_PROBE_VDIV); @@ -299,7 +292,7 @@ uint64_t AnalogSignal::get_vdiv() const return vdiv; } -uint8_t AnalogSignal::get_acCoupling() const +uint8_t AnalogSignal::get_acCoupling() { uint64_t coupling = 0; GVariant* gvar = _dev_inst->get_config(_probe, NULL, SR_CONF_PROBE_COUPLING); @@ -310,7 +303,7 @@ uint8_t AnalogSignal::get_acCoupling() const return coupling; } -bool AnalogSignal::get_mapDefault() const +bool AnalogSignal::get_mapDefault() { bool isDefault = true; GVariant* gvar = _dev_inst->get_config(_probe, NULL, SR_CONF_PROBE_MAP_DEFAULT); @@ -321,7 +314,7 @@ bool AnalogSignal::get_mapDefault() const return isDefault; } -QString AnalogSignal::get_mapUnit() const +QString AnalogSignal::get_mapUnit() { QString unit; GVariant* gvar = _dev_inst->get_config(_probe, NULL, SR_CONF_PROBE_MAP_UNIT); @@ -332,7 +325,7 @@ QString AnalogSignal::get_mapUnit() const return unit; } -double AnalogSignal::get_mapMin() const +double AnalogSignal::get_mapMin() { double min = -1; GVariant* gvar = _dev_inst->get_config(_probe, NULL, SR_CONF_PROBE_MAP_MIN); @@ -343,7 +336,7 @@ double AnalogSignal::get_mapMin() const return min; } -double AnalogSignal::get_mapMax() const +double AnalogSignal::get_mapMax() { double max = 1; GVariant* gvar = _dev_inst->get_config(_probe, NULL, SR_CONF_PROBE_MAP_MAX); @@ -354,7 +347,7 @@ double AnalogSignal::get_mapMax() const return max; } -uint64_t AnalogSignal::get_factor() const +uint64_t AnalogSignal::get_factor() { GVariant* gvar; uint64_t factor; @@ -369,24 +362,24 @@ uint64_t AnalogSignal::get_factor() const } } -int AnalogSignal::ratio2value(double ratio) const +int AnalogSignal::ratio2value(double ratio) { return ratio * (_ref_max - _ref_min) + _ref_min; } -int AnalogSignal::ratio2pos(double ratio) const +int AnalogSignal::ratio2pos(double ratio) { const int height = get_totalHeight(); const int top = get_y() - height * 0.5; return ratio * height + top; } -double AnalogSignal::value2ratio(int value) const +double AnalogSignal::value2ratio(int value) { return max(0.0, (value - _ref_min) / (_ref_max - _ref_min)); } -double AnalogSignal::pos2ratio(int pos) const +double AnalogSignal::pos2ratio(int pos) { const int height = get_totalHeight(); const int top = get_y() - height / 2; @@ -403,7 +396,7 @@ void AnalogSignal::set_zero_vpos(int pos) } } -int AnalogSignal::get_zero_vpos() const +int AnalogSignal::get_zero_vpos() { return ratio2pos(get_zero_ratio()); } @@ -418,12 +411,12 @@ void AnalogSignal::set_zero_ratio(double ratio) g_variant_new_uint16(_zero_offset)); } -double AnalogSignal::get_zero_ratio() const +double AnalogSignal::get_zero_ratio() { return value2ratio(_zero_offset); } -int AnalogSignal::get_zero_offset() const +int AnalogSignal::get_zero_offset() { return _zero_offset; } @@ -510,13 +503,11 @@ void AnalogSignal::paint_mid(QPainter &p, int left, int right, QColor fore, QCol assert(scale > 0); const int64_t offset = _view->offset(); - const deque< boost::shared_ptr > &snapshots = - _data->get_snapshots(); + const auto &snapshots = _data->get_snapshots(); if (snapshots.empty()) return; - const boost::shared_ptr &snapshot = - snapshots.front(); + const auto snapshot = snapshots.front(); if (snapshot->empty()) return; @@ -571,7 +562,7 @@ void AnalogSignal::paint_fore(QPainter &p, int left, int right, QColor fore, QCo } void AnalogSignal::paint_trace(QPainter &p, - const boost::shared_ptr &snapshot, + const pv::data::AnalogSnapshot *snapshot, int zeroY, const int start_pixel, const uint64_t start_index, const int64_t sample_count, const double samples_per_pixel, const int order, @@ -579,10 +570,12 @@ void AnalogSignal::paint_trace(QPainter &p, { (void)width; - const int64_t channel_num = snapshot->get_channel_num(); + pv::data::AnalogSnapshot *pshot = const_cast(snapshot); + + int64_t channel_num = (int64_t)pshot->get_channel_num(); if (sample_count > 0) { - const uint8_t unit_bytes = snapshot->get_unit_bytes(); - const uint8_t *const samples = snapshot->get_samples(0); + const uint8_t unit_bytes = pshot->get_unit_bytes(); + const uint8_t *const samples = pshot->get_samples(0); assert(samples); p.setPen(_colour); @@ -603,10 +596,10 @@ void AnalogSignal::paint_trace(QPainter &p, yvalue = zeroY + (yvalue - hw_offset) * _scale; yvalue = min(max(yvalue, top), bottom); *point++ = QPointF(x, yvalue); - if (yindex == snapshot->get_ring_end()) + if (yindex == pshot->get_ring_end()) break; yindex++; - yindex %= snapshot->get_sample_count(); + yindex %= pshot->get_sample_count(); x += pixels_per_sample; } p.drawPolyline(points, point - points); @@ -615,7 +608,7 @@ void AnalogSignal::paint_trace(QPainter &p, } void AnalogSignal::paint_envelope(QPainter &p, - const boost::shared_ptr &snapshot, + const pv::data::AnalogSnapshot *snapshot, int zeroY, const int start_pixel, const uint64_t start_index, const int64_t sample_count, const double samples_per_pixel, const int order, @@ -623,9 +616,10 @@ void AnalogSignal::paint_envelope(QPainter &p, { using namespace Qt; using pv::data::AnalogSnapshot; + pv::data::AnalogSnapshot *pshot = const_cast(snapshot); AnalogSnapshot::EnvelopeSection e; - snapshot->get_envelope_section(e, start_index, sample_count, + pshot->get_envelope_section(e, start_index, sample_count, samples_per_pixel, order); if (e.samples_num == 0) return; @@ -640,7 +634,8 @@ void AnalogSignal::paint_envelope(QPainter &p, float y_min = zeroY, y_max = zeroY, pre_y_min = zeroY, pre_y_max = zeroY; int pcnt = 0; const double scale_pixels_per_samples = e.scale / samples_per_pixel; - const uint64_t ring_end = max((int64_t)0, (int64_t)snapshot->get_ring_end() / e.scale - 1); + int64_t end_v = pshot->get_ring_end(); + const uint64_t ring_end = max((int64_t)0, end_v / e.scale - 1); const int hw_offset = get_hw_offset(); float x = start_pixel; @@ -717,7 +712,7 @@ void AnalogSignal::paint_hover_measure(QPainter &p, QColor fore, QColor back) p.drawText(hover_rect, Qt::AlignCenter | Qt::AlignTop | Qt::TextDontClip, hover_str); } - list::iterator i = _view->get_cursorList().begin(); + auto i = _view->get_cursorList().begin(); while (i != _view->get_cursorList().end()) { float pt_value; const QPointF pt = get_point((*i)->index(), pt_value); diff --git a/DSView/pv/view/analogsignal.h b/DSView/pv/view/analogsignal.h index 401351eb..48f3d7f6 100755 --- a/DSView/pv/view/analogsignal.h +++ b/DSView/pv/view/analogsignal.h @@ -24,8 +24,7 @@ #define DSVIEW_PV_ANALOGSIGNAL_H #include "signal.h" - -#include + namespace pv { @@ -53,23 +52,21 @@ private: static const uint8_t DefaultBits = 8; public: - AnalogSignal(DevInst* dev_inst, - boost::shared_ptr data, - sr_channel *probe); - AnalogSignal(boost::shared_ptr s, - boost::shared_ptr data, + AnalogSignal(DevInst* dev_inst, pv::data::Analog *data, sr_channel *probe); + AnalogSignal(view::AnalogSignal* s, pv::data::Analog *data, sr_channel *probe); + virtual ~AnalogSignal(); - boost::shared_ptr data() const; + pv::data::SignalData* data(); void set_scale(int height); - float get_scale() const; - int get_bits() const; - double get_ref_min() const; - double get_ref_max() const; - int get_hw_offset() const; + float get_scale(); + int get_bits(); + double get_ref_min(); + double get_ref_max(); + int get_hw_offset(); int commit_settings(); /** @@ -83,30 +80,30 @@ public: /** * Probe options **/ - uint64_t get_vdiv() const; - uint8_t get_acCoupling() const; - bool get_mapDefault() const; - QString get_mapUnit() const; - double get_mapMin() const; - double get_mapMax() const; - uint64_t get_factor() const; + uint64_t get_vdiv(); + uint8_t get_acCoupling(); + bool get_mapDefault(); + QString get_mapUnit(); + double get_mapMin(); + double get_mapMax(); + uint64_t get_factor(); /** * **/ void set_zero_vpos(int pos); - int get_zero_vpos() const; + int get_zero_vpos(); void set_zero_ratio(double ratio); - double get_zero_ratio() const; - int get_zero_offset() const; + double get_zero_ratio(); + int get_zero_offset(); /** * */ - int ratio2value(double ratio) const; - int ratio2pos(double ratio) const; - double value2ratio(int value) const; - double pos2ratio(int pos) const; + int ratio2value(double ratio); + int ratio2pos(double ratio); + double value2ratio(int value); + double pos2ratio(int pos); /** * Event @@ -139,14 +136,14 @@ public: private: void paint_trace(QPainter &p, - const boost::shared_ptr &snapshot, + const pv::data::AnalogSnapshot *snapshot, int zeroY, const int start_pixel, const uint64_t start_index, const int64_t sample_count, const double samples_per_pixel, const int order, const float top, const float bottom, const int width); void paint_envelope(QPainter &p, - const boost::shared_ptr &snapshot, + const pv::data::AnalogSnapshot *snapshot, int zeroY, const int start_pixel, const uint64_t start_index, const int64_t sample_count, const double samples_per_pixel, const int order, @@ -155,7 +152,7 @@ private: void paint_hover_measure(QPainter &p, QColor fore, QColor back); private: - boost::shared_ptr _data; + pv::data::Analog *_data; QRectF *_rects; diff --git a/DSView/pv/view/cursor.cpp b/DSView/pv/view/cursor.cpp index 7c136567..eca057ca 100755 --- a/DSView/pv/view/cursor.cpp +++ b/DSView/pv/view/cursor.cpp @@ -57,7 +57,7 @@ Cursor::Cursor(View &view, QColor color, uint64_t index) : { } -QRect Cursor::get_label_rect(const QRect &rect, bool &visible, bool has_hoff) const +QRect Cursor::get_label_rect(const QRect &rect, bool &visible, bool has_hoff) { const double samples_per_pixel = _view.session().cur_snap_samplerate() * _view.scale(); const double cur_offset = _index / samples_per_pixel; @@ -79,7 +79,7 @@ QRect Cursor::get_label_rect(const QRect &rect, bool &visible, bool has_hoff) co return QRect(x - label_size.width() / 2, top, label_size.width(), height); } -QRect Cursor::get_close_rect(const QRect &rect) const +QRect Cursor::get_close_rect(const QRect &rect) { return QRect(rect.right() - CloseSize, rect.top(), CloseSize, CloseSize); } diff --git a/DSView/pv/view/cursor.h b/DSView/pv/view/cursor.h index 2a33a8f2..6e8292fc 100755 --- a/DSView/pv/view/cursor.h +++ b/DSView/pv/view/cursor.h @@ -65,9 +65,9 @@ public: * @param rect The rectangle of the ruler client area. * @return Returns the label rectangle. */ - QRect get_label_rect(const QRect &rect, bool &visible, bool has_hoff = true) const; + QRect get_label_rect(const QRect &rect, bool &visible, bool has_hoff = true); - QRect get_close_rect(const QRect &rect) const; + QRect get_close_rect(const QRect &rect); /** * Paints the cursor's label to the ruler. diff --git a/DSView/pv/view/decodetrace.cpp b/DSView/pv/view/decodetrace.cpp index 07816c28..babe8024 100755 --- a/DSView/pv/view/decodetrace.cpp +++ b/DSView/pv/view/decodetrace.cpp @@ -116,7 +116,7 @@ const QString DecodeTrace::RegionStart = QT_TR_NOOP("Start"); const QString DecodeTrace::RegionEnd = QT_TR_NOOP("End "); DecodeTrace::DecodeTrace(pv::SigSession *session, - boost::shared_ptr decoder_stack, int index) : + pv::data::DecoderStack *decoder_stack, int index) : Trace(QString::fromUtf8( decoder_stack->stack().front()->decoder()->name), index, SR_CHANNEL_DECODER), _session(session), @@ -134,9 +134,9 @@ DecodeTrace::DecodeTrace(pv::SigSession *session, _colour = DecodeColours[index % countof(DecodeColours)]; - connect(_decoder_stack.get(), SIGNAL(new_decode_data()), + connect(_decoder_stack, SIGNAL(new_decode_data()), this, SLOT(on_new_decode_data())); - connect(_decoder_stack.get(), SIGNAL(decode_done()), + connect(_decoder_stack, SIGNAL(decode_done()), this, SLOT(on_decode_done())); _start_comboBox = NULL; @@ -156,12 +156,12 @@ DecodeTrace::~DecodeTrace() } } -bool DecodeTrace::enabled() const +bool DecodeTrace::enabled() { return true; } -const boost::shared_ptr& DecodeTrace::decoder() const +pv::data::DecoderStack* DecodeTrace::decoder() { return _decoder_stack; } @@ -311,7 +311,7 @@ void DecodeTrace::paint_mid(QPainter &p, int left, int right, QColor fore, QColo if ((max_annWidth > 100) || (max_annWidth > 10 && min_annWidth > 1) || (max_annWidth == 0 && samples_per_pixel < 10)) { - vector annotations; + std::vector annotations; _decoder_stack->get_annotation_subset(annotations, row, start_sample, end_sample); @@ -410,7 +410,7 @@ void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form) _probe_selectors.clear(); _decoder_forms.clear(); - list< boost::shared_ptr >& stack = _decoder_stack->stack(); + auto &stack = _decoder_stack->stack(); if (stack.empty()) { QLabel *const l = new QLabel( @@ -492,7 +492,7 @@ void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form) void DecodeTrace::draw_annotation(const pv::data::decode::Annotation &a, QPainter &p, QColor text_color, int h, int left, int right, double samples_per_pixel, double pixels_offset, int y, - size_t base_colour, double min_annWidth, QColor fore, QColor back) const + size_t base_colour, double min_annWidth, QColor fore, QColor back) { const double start = max(a.start_sample() / samples_per_pixel - pixels_offset, (double)left); @@ -537,11 +537,12 @@ void DecodeTrace::draw_annotation(const pv::data::decode::Annotation &a, if ((type == SRD_CHANNEL_COMMON) || ((type%100 != a.type()%100) && (type%100 != 0))) continue; - boost::shared_ptr logic_sig; + + LogicSignal *logic_sig = NULL; for(auto &sig : _session->get_signals()) { if((sig->get_index() == iter.second) && - (logic_sig = dynamic_pointer_cast(sig))) { + (logic_sig = dynamic_cast(sig))) { logic_sig->paint_mark(p, start, end, type/100); break; } @@ -554,7 +555,7 @@ void DecodeTrace::draw_annotation(const pv::data::decode::Annotation &a, void DecodeTrace::draw_nodetail(QPainter &p, int h, int left, int right, int y, - size_t base_colour, QColor fore, QColor back) const + size_t base_colour, QColor fore, QColor back) { (void)base_colour; (void)back; @@ -578,7 +579,7 @@ void DecodeTrace::draw_nodetail(QPainter &p, } void DecodeTrace::draw_instant(const pv::data::decode::Annotation &a, QPainter &p, - QColor fill, QColor outline, QColor text_color, int h, double x, int y, double min_annWidth) const + QColor fill, QColor outline, QColor text_color, int h, double x, int y, double min_annWidth) { (void)outline; @@ -603,13 +604,13 @@ void DecodeTrace::draw_instant(const pv::data::decode::Annotation &a, QPainter & void DecodeTrace::draw_range(const pv::data::decode::Annotation &a, QPainter &p, QColor fill, QColor outline, QColor text_color, int h, double start, - double end, int y, QColor fore, QColor back) const + double end, int y, QColor fore, QColor back) { (void)fore; const double top = y + .5 - h / 2; const double bottom = y + .5 + h / 2; - const vector annotations = a.annotations(); + const std::vector annotations = a.annotations(); p.setPen(outline); p.setBrush(fill); @@ -708,13 +709,15 @@ void DecodeTrace::draw_unshown_row(QPainter &p, int y, int h, int left, } void DecodeTrace::create_decoder_form( - boost::shared_ptr &decoder_stack, - boost::shared_ptr &dec, QWidget *parent, + pv::data::DecoderStack *decoder_stack, + data::decode::Decoder *dec, QWidget *parent, QFormLayout *form) { const GSList *l; assert(dec); + assert(decoder_stack); + const srd_decoder *const decoder = dec->decoder(); assert(decoder); @@ -756,8 +759,7 @@ void DecodeTrace::create_decoder_form( } // Add the options - boost::shared_ptr binding( - new prop::binding::DecoderOptions(decoder_stack, dec)); + auto binding = new prop::binding::DecoderOptions(decoder_stack, dec); binding->add_properties_to_form(decoder_form, true); _bindings.push_back(binding); @@ -765,41 +767,43 @@ void DecodeTrace::create_decoder_form( // pv::widgets::DecoderGroupBox *const group = new pv::widgets::DecoderGroupBox(decoder_stack, dec, decoder_form, parent); - connect(group, SIGNAL(del_stack(boost::shared_ptr&)), - this, SLOT(on_del_stack(boost::shared_ptr&))); + + connect(group, SIGNAL(del_stack(data::decode::Decoder*)), + this, SLOT(on_del_stack(data::decode::Decoder*))); form->addRow(group); _decoder_forms.push_back(group); } QComboBox* DecodeTrace::create_probe_selector( - QWidget *parent, const boost::shared_ptr &dec, + QWidget *parent, const data::decode::Decoder *dec, const srd_channel *const pdch) { assert(dec); - const vector< boost::shared_ptr > sigs(_session->get_signals()); + const auto &sigs = _session->get_signals(); assert(_decoder_stack); - const map::const_iterator probe_iter = - dec->channels().find(pdch); + data::decode::Decoder *_dec = const_cast(dec); + + auto probe_iter = _dec->channels().find(pdch); QComboBox *selector = new QComboBox(parent); selector->addItem("-", QVariant::fromValue(-1)); - if (probe_iter == dec->channels().end()) + if (probe_iter == _dec->channels().end()) selector->setCurrentIndex(0); for(size_t i = 0; i < sigs.size(); i++) { - const boost::shared_ptr s(sigs[i]); + const auto s = sigs[i]; assert(s); - if (dynamic_pointer_cast(s) && s->enabled()) + if (dynamic_cast(s) && s->enabled()) { selector->addItem(s->get_name(), QVariant::fromValue(s->get_index())); - if (probe_iter != dec->channels().end()) { + if (probe_iter != _dec->channels().end()) { if ((*probe_iter).second == s->get_index()) selector->setCurrentIndex(i + 1); } @@ -809,12 +813,12 @@ QComboBox* DecodeTrace::create_probe_selector( return selector; } -void DecodeTrace::commit_decoder_probes(boost::shared_ptr &dec) +void DecodeTrace::commit_decoder_probes(data::decode::Decoder *dec) { assert(dec); - map probe_map; - const vector< boost::shared_ptr > sigs(_session->get_signals()); + std::map probe_map; + const auto &sigs = _session->get_signals(); _index_list.clear(); for(auto &s : _probe_selectors) @@ -863,7 +867,7 @@ void DecodeTrace::on_new_decode_data() _view->signals_changed(); } -int DecodeTrace::get_progress() const +int DecodeTrace::get_progress() { return _progress; } @@ -892,19 +896,18 @@ void DecodeTrace::on_stack_decoder(srd_decoder *decoder) { assert(decoder); assert(_decoder_stack); - _decoder_stack->push(boost::shared_ptr( - new data::decode::Decoder(decoder))); - //_decoder_stack->begin_decode(); + _decoder_stack->push(new data::decode::Decoder(decoder)); + create_popup_form(); } -void DecodeTrace::on_del_stack(boost::shared_ptr &dec) +void DecodeTrace::on_del_stack(data::decode::Decoder *dec) { assert(dec); assert(_decoder_stack); - _decoder_stack->remove(dec); + _decoder_stack->remove(dec); create_popup_form(); } @@ -915,10 +918,12 @@ int DecodeTrace::rows_size() int size = 0; for(auto &dec : _decoder_stack->stack()) { if (dec->shown()) { - const std::map rows = _decoder_stack->get_rows_gshow(); - for (std::map::const_iterator i = rows.begin(); - i != rows.end(); i++) { - if ((*i).first.decoder() == dec->decoder() && + + auto rows = _decoder_stack->get_rows_gshow(); + + for (auto i = rows.begin(); i != rows.end(); i++) { + pv::data::decode::Row _row = (*i).first; + if (_row.decoder() == dec->decoder() && _decoder_stack->has_annotations((*i).first) && (*i).second) size++; diff --git a/DSView/pv/view/decodetrace.h b/DSView/pv/view/decodetrace.h index 19e8015f..d2d59f37 100755 --- a/DSView/pv/view/decodetrace.h +++ b/DSView/pv/view/decodetrace.h @@ -30,8 +30,6 @@ #include #include -#include - #include #include "../dialogs/dsdialog.h" @@ -68,7 +66,7 @@ private: struct ProbeSelector { const QComboBox *_combo; - const boost::shared_ptr _decoder; + const pv::data::decode::Decoder *_decoder; const srd_channel *_pdch; }; @@ -98,13 +96,13 @@ private: public: DecodeTrace(pv::SigSession *session, - boost::shared_ptr decoder_stack, + pv::data::DecoderStack *decoder_stack, int index); ~DecodeTrace(); - bool enabled() const; + bool enabled(); - const boost::shared_ptr& decoder() const; + pv::data::DecoderStack* decoder(); void set_view(pv::view::View *view); @@ -143,7 +141,7 @@ public: **/ void frame_ended(); - int get_progress() const; + int get_progress(); protected: void paint_type_options(QPainter &p, int right, const QPoint pt, QColor fore); @@ -156,18 +154,18 @@ private: void draw_annotation(const pv::data::decode::Annotation &a, QPainter &p, QColor text_colour, int text_height, int left, int right, double samples_per_pixel, double pixels_offset, int y, - size_t base_colour, double min_annWidth, QColor fore, QColor back) const; + size_t base_colour, double min_annWidth, QColor fore, QColor back); void draw_nodetail(QPainter &p, int text_height, int left, int right, int y, - size_t base_colour, QColor fore, QColor back) const; + size_t base_colour, QColor fore, QColor back); void draw_instant(const pv::data::decode::Annotation &a, QPainter &p, QColor fill, QColor outline, QColor text_color, int h, double x, - int y, double min_annWidth) const; + int y, double min_annWidth); void draw_range(const pv::data::decode::Annotation &a, QPainter &p, QColor fill, QColor outline, QColor text_color, int h, double start, - double end, int y, QColor fore, QColor back) const; + double end, int y, QColor fore, QColor back); void draw_error(QPainter &p, const QString &message, int left, int right); @@ -175,16 +173,16 @@ private: void draw_unshown_row(QPainter &p, int y, int h, int left, int right, QString info, QColor fore, QColor back); - void create_decoder_form(boost::shared_ptr &decoder_stack, - boost::shared_ptr &dec, + void create_decoder_form(data::DecoderStack *decoder_stack, + pv::data::decode::Decoder *dec, QWidget *parent, QFormLayout *form); QComboBox* create_probe_selector(QWidget *parent, - const boost::shared_ptr &dec, + const pv::data::decode::Decoder *dec, const srd_channel *const pdch); void commit_decoder_probes( - boost::shared_ptr &dec); + data::decode::Decoder *dec); void commit_probes(); @@ -199,32 +197,34 @@ private slots: void on_probe_selected(int); void on_stack_decoder(srd_decoder *decoder); - void on_del_stack(boost::shared_ptr &dec); + + void on_del_stack(data::decode::Decoder *dec); void on_decode_done(); void on_region_set(int index); private: - pv::SigSession *_session; - boost::shared_ptr _decoder_stack; + pv::SigSession *_session; + pv::data::DecoderStack *_decoder_stack; - uint64_t _decode_start, _decode_end; - int _start_index, _end_index; - int _start_count, _end_count; - QComboBox *_start_comboBox, *_end_comboBox; - QFormLayout *_pub_input_layer; - int _progress; - - std::list< boost::shared_ptr > - _bindings; + uint64_t _decode_start; + uint64_t _decode_end; + int _start_index; + int _end_index; + int _start_count; + int _end_count; + QComboBox *_start_comboBox; + QComboBox *_end_comboBox; + QFormLayout *_pub_input_layer; + int _progress; + std::list _bindings; std::list _probe_selectors; std::vector _decoder_forms; - std::vector _cur_row_headings; - - dialogs::DSDialog *_popup; + std::vector _cur_row_headings; + dialogs::DSDialog *_popup; }; } // namespace view diff --git a/DSView/pv/view/devmode.cpp b/DSView/pv/view/devmode.cpp index e34408b6..48e36f81 100755 --- a/DSView/pv/view/devmode.cpp +++ b/DSView/pv/view/devmode.cpp @@ -35,9 +35,7 @@ #include #include #include "../config/appconfig.h" - -using boost::shared_ptr; -using namespace std; + namespace pv { namespace view { diff --git a/DSView/pv/view/devmode.h b/DSView/pv/view/devmode.h index ae26e53c..d5c9fc1e 100755 --- a/DSView/pv/view/devmode.h +++ b/DSView/pv/view/devmode.h @@ -22,10 +22,7 @@ #ifndef DSVIEW_PV_VIEW_DEVMODE_H #define DSVIEW_PV_VIEW_DEVMODE_H - -#include -#include - + #include #include #include diff --git a/DSView/pv/view/dsldial.cpp b/DSView/pv/view/dsldial.cpp index 618817b1..86fa462e 100755 --- a/DSView/pv/view/dsldial.cpp +++ b/DSView/pv/view/dsldial.cpp @@ -119,12 +119,12 @@ void dslDial::set_sel(uint64_t sel) _sel = sel; } -uint64_t dslDial::get_sel() const +uint64_t dslDial::get_sel() { return _sel; } -uint64_t dslDial::get_count() const +uint64_t dslDial::get_count() { return _div; } @@ -145,22 +145,22 @@ bool dslDial::isMax() return false; } -uint64_t dslDial::get_min() const +uint64_t dslDial::get_min() { return _value[0]; } -uint64_t dslDial::get_max() const +uint64_t dslDial::get_max() { return _value[_div-1]; } -uint64_t dslDial::get_value() const +uint64_t dslDial::get_value() { return _value[_sel]; } -uint64_t dslDial::get_value(uint64_t i) const +uint64_t dslDial::get_value(uint64_t i) { assert(i < _div); return _value[i]; @@ -179,7 +179,7 @@ void dslDial::set_factor(uint64_t factor) } } -uint64_t dslDial::get_factor() const +uint64_t dslDial::get_factor() { return _factor; } diff --git a/DSView/pv/view/dsldial.h b/DSView/pv/view/dsldial.h index 120b491c..9c0895c9 100755 --- a/DSView/pv/view/dsldial.h +++ b/DSView/pv/view/dsldial.h @@ -50,23 +50,23 @@ public: // set/get current select void set_sel(uint64_t sel); - uint64_t get_sel() const; - uint64_t get_count() const; + uint64_t get_sel(); + uint64_t get_count(); // boundary detection bool isMin(); bool isMax(); - uint64_t get_min() const; - uint64_t get_max() const; + uint64_t get_min(); + uint64_t get_max(); // get current value - uint64_t get_value() const; - uint64_t get_value(uint64_t i) const; + uint64_t get_value(); + uint64_t get_value(uint64_t i); void set_value(uint64_t value); // set/get factor void set_factor(uint64_t factor); - uint64_t get_factor() const; + uint64_t get_factor(); private: uint64_t _div; diff --git a/DSView/pv/view/dsosignal.cpp b/DSView/pv/view/dsosignal.cpp index 7a295c5c..3a33628e 100755 --- a/DSView/pv/view/dsosignal.cpp +++ b/DSView/pv/view/dsosignal.cpp @@ -57,7 +57,7 @@ const QColor DsoSignal::SignalColours[4] = { const float DsoSignal::EnvelopeThreshold = 256.0f; DsoSignal::DsoSignal(DevInst *dev_inst, - boost::shared_ptr data, + data::Dso *data, sr_channel *probe): Signal(dev_inst, probe), _data(data), @@ -108,12 +108,12 @@ DsoSignal::~DsoSignal() { } -boost::shared_ptr DsoSignal::data() const +pv::data::SignalData* DsoSignal::data() { return _data; } -boost::shared_ptr DsoSignal::dso_data() const +pv::data::Dso* DsoSignal::dso_data() { return _data; } @@ -133,17 +133,17 @@ uint8_t DsoSignal::get_bits() return _bits; } -double DsoSignal::get_ref_min() const +double DsoSignal::get_ref_min() { return _ref_min; } -double DsoSignal::get_ref_max() const +double DsoSignal::get_ref_max() { return _ref_max; } -int DsoSignal::get_name_width() const +int DsoSignal::get_name_width() { return 0; } @@ -193,7 +193,7 @@ void DsoSignal::set_enable(bool enable) _en_lock = false; } -bool DsoSignal::get_vDialActive() const +bool DsoSignal::get_vDialActive() { return _vDialActive; } @@ -400,22 +400,22 @@ int DsoSignal::commit_settings() return ret; } -dslDial * DsoSignal::get_vDial() const +dslDial * DsoSignal::get_vDial() { return _vDial; } -uint64_t DsoSignal::get_vDialValue() const +uint64_t DsoSignal::get_vDialValue() { return _vDial->get_value(); } -uint16_t DsoSignal::get_vDialSel() const +uint16_t DsoSignal::get_vDialSel() { return _vDial->get_sel(); } -uint8_t DsoSignal::get_acCoupling() const +uint8_t DsoSignal::get_acCoupling() { return _acCoupling; } @@ -429,27 +429,27 @@ void DsoSignal::set_acCoupling(uint8_t coupling) } } -int DsoSignal::ratio2value(double ratio) const +int DsoSignal::ratio2value(double ratio) { return ratio * (_ref_max - _ref_min) + _ref_min; } -int DsoSignal::ratio2pos(double ratio) const +int DsoSignal::ratio2pos(double ratio) { return ratio * get_view_rect().height() + get_view_rect().top(); } -double DsoSignal::value2ratio(int value) const +double DsoSignal::value2ratio(int value) { return max(0.0, (value - _ref_min) / (_ref_max - _ref_min)); } -double DsoSignal::pos2ratio(int pos) const +double DsoSignal::pos2ratio(int pos) { return min(max(pos - get_view_rect().top(), 0), get_view_rect().height()) * 1.0 / get_view_rect().height(); } -double DsoSignal::get_trig_vrate() const +double DsoSignal::get_trig_vrate() { if (_dev_inst->name() == "DSLogic") return value2ratio(_trig_value - ratio2value(0.5)) + get_zero_ratio(); @@ -485,17 +485,17 @@ void DsoSignal::set_trig_ratio(double ratio, bool delta_change) g_variant_new_byte(_trig_value)); } -int DsoSignal::get_zero_vpos() const +int DsoSignal::get_zero_vpos() { return ratio2pos(get_zero_ratio()); } -double DsoSignal::get_zero_ratio() const +double DsoSignal::get_zero_ratio() { return value2ratio(_zero_offset); } -int DsoSignal::get_hw_offset() const +int DsoSignal::get_hw_offset() { int hw_offset = 0; GVariant *gvar = _dev_inst->get_config(_probe, NULL, SR_CONF_PROBE_HW_OFFSET); @@ -564,7 +564,7 @@ void DsoSignal::set_show(bool show) _show = show; } -bool DsoSignal::show() const +bool DsoSignal::show() { return _show; } @@ -692,7 +692,7 @@ QString DsoSignal::get_measure(enum DSO_MEASURE_TYPE type) return mString; } -QRect DsoSignal::get_view_rect() const +QRect DsoSignal::get_view_rect() { assert(_viewport); return QRect(0, UpMargin, @@ -704,12 +704,11 @@ void DsoSignal::paint_prepare() { assert(_view); - const deque< boost::shared_ptr > &snapshots = - _data->get_snapshots(); + const auto &snapshots = _data->get_snapshots(); if (snapshots.empty()) return; - const boost::shared_ptr &snapshot = - snapshots.front(); + + const auto snapshot = snapshots.front(); if (snapshot->empty()) return; @@ -847,12 +846,11 @@ void DsoSignal::paint_mid(QPainter &p, int left, int right, QColor fore, QColor assert(scale > 0); const int64_t offset = _view->offset(); - const deque< boost::shared_ptr > &snapshots = - _data->get_snapshots(); + const auto &snapshots = _data->get_snapshots(); if (snapshots.empty()) return; - const boost::shared_ptr &snapshot = - snapshots.front(); + + const auto snapshot = snapshots.front(); if (snapshot->empty()) return; @@ -1018,7 +1016,7 @@ void DsoSignal::paint_fore(QPainter &p, int left, int right, QColor fore, QColor } } -QRectF DsoSignal::get_trig_rect(int left, int right) const +QRectF DsoSignal::get_trig_rect(int left, int right) { (void)left; @@ -1028,14 +1026,16 @@ QRectF DsoSignal::get_trig_rect(int left, int right) const } void DsoSignal::paint_trace(QPainter &p, - const boost::shared_ptr &snapshot, + const pv::data::DsoSnapshot *snapshot, int zeroY, int left, const int64_t start, const int64_t end, int hw_offset, const double pixels_offset, const double samples_per_pixel, uint64_t num_channels) { const int64_t sample_count = end - start + 1; if (sample_count > 0) { - const uint8_t *const samples = snapshot->get_samples(start, end, get_index()); + pv::data::DsoSnapshot *pshot = const_cast(snapshot); + auto pdata = pshot->get_samples(start, end, get_index()); + const uint8_t *const samples = pdata; assert(samples); QColor trace_colour = _colour; @@ -1073,16 +1073,18 @@ void DsoSignal::paint_trace(QPainter &p, } void DsoSignal::paint_envelope(QPainter &p, - const boost::shared_ptr &snapshot, + const pv::data::DsoSnapshot *snapshot, int zeroY, int left, const int64_t start, const int64_t end, int hw_offset, const double pixels_offset, const double samples_per_pixel, uint64_t num_channels) { using namespace Qt; using pv::data::DsoSnapshot; + data::DsoSnapshot *pshot = const_cast(snapshot); + DsoSnapshot::EnvelopeSection e; const uint16_t index = get_index() % num_channels; - snapshot->get_envelope_section(e, start, end, samples_per_pixel, index); + pshot->get_envelope_section(e, start, end, samples_per_pixel, index); if (e.length < 2) return; @@ -1332,7 +1334,7 @@ void DsoSignal::paint_hover_measure(QPainter &p, QColor fore, QColor back) p.drawText(hover_rect, Qt::AlignCenter | Qt::AlignTop | Qt::TextDontClip, hover_str); } - list::iterator i = _view->get_cursorList().begin(); + auto i = _view->get_cursorList().begin(); while (i != _view->get_cursorList().end()) { float pt_value; const QPointF pt = get_point((*i)->index(), pt_value); @@ -1477,13 +1479,11 @@ bool DsoSignal::measure(const QPointF &p) if (!window.contains(p)) return false; - const deque< boost::shared_ptr > &snapshots = - _data->get_snapshots(); + const auto &snapshots = _data->get_snapshots(); if (snapshots.empty()) return false; - const boost::shared_ptr &snapshot = - snapshots.front(); + auto snapshot = const_cast(snapshots.front()); if (snapshot->empty()) return false; @@ -1514,13 +1514,11 @@ QPointF DsoSignal::get_point(uint64_t index, float &value) if (!enabled()) return pt; - const deque< boost::shared_ptr > &snapshots = - _data->get_snapshots(); + const auto &snapshots = _data->get_snapshots(); if (snapshots.empty()) return pt; - const boost::shared_ptr &snapshot = - snapshots.front(); + const auto snapshot = snapshots.front(); if (snapshot->empty()) return pt; @@ -1543,13 +1541,11 @@ double DsoSignal::get_voltage(uint64_t index) if (!enabled()) return 1; - const deque< boost::shared_ptr > &snapshots = - _data->get_snapshots(); + auto &snapshots = _data->get_snapshots(); if (snapshots.empty()) return 1; - const boost::shared_ptr &snapshot = - snapshots.front(); + auto snapshot = const_cast(snapshots.front()); if (snapshot->empty()) return 1; diff --git a/DSView/pv/view/dsosignal.h b/DSView/pv/view/dsosignal.h index 50d079a9..2cdd8bde 100755 --- a/DSView/pv/view/dsosignal.h +++ b/DSView/pv/view/dsosignal.h @@ -24,11 +24,8 @@ #define DSVIEW_PV_DSOSIGNAL_H #include "signal.h" - -#include - + namespace pv { - namespace data { class Logic; class Dso; @@ -87,46 +84,45 @@ private: static const uint16_t MS_RectHeight = 25; public: - DsoSignal(DevInst* dev_inst, - boost::shared_ptr data, + DsoSignal(DevInst* dev_inst, pv::data::Dso *data, sr_channel *probe); virtual ~DsoSignal(); - boost::shared_ptr data() const; - boost::shared_ptr dso_data() const; + pv::data::SignalData* data(); + pv::data::Dso* dso_data(); void set_scale(int height); float get_scale(); uint8_t get_bits(); - double get_ref_min() const; - double get_ref_max() const; + double get_ref_min(); + double get_ref_max(); - int get_name_width() const; + int get_name_width(); /** * */ void set_enable(bool enable); - bool get_vDialActive() const; + bool get_vDialActive(); void set_vDialActive(bool active); bool go_vDialPre(bool manul); bool go_vDialNext(bool manul); bool update_capture(bool instant); - dslDial *get_vDial() const; - uint64_t get_vDialValue() const; - uint16_t get_vDialSel() const; - uint8_t get_acCoupling() const; + dslDial *get_vDial(); + uint64_t get_vDialValue(); + uint16_t get_vDialSel(); + uint8_t get_acCoupling(); void set_acCoupling(uint8_t coupling); void set_trig_vpos(int pos, bool delta_change = true); void set_trig_ratio(double ratio, bool delta_change = true); - double get_trig_vrate() const; + double get_trig_vrate(); void set_factor(uint64_t factor); uint64_t get_factor(); void set_show(bool show); - bool show() const; + bool show(); void set_mValid(bool valid); bool load_settings(); @@ -150,9 +146,9 @@ public: /** * Gets the mid-Y position of this signal. */ - int get_zero_vpos() const; - double get_zero_ratio() const; - int get_hw_offset() const; + int get_zero_vpos(); + double get_zero_ratio(); + int get_hw_offset(); /** * Sets the mid-Y position of this signal. */ @@ -165,10 +161,10 @@ public: /** * */ - int ratio2value(double ratio) const; - int ratio2pos(double ratio) const; - double value2ratio(int value) const; - double pos2ratio(int pos) const; + int ratio2value(double ratio); + int ratio2pos(double ratio); + double value2ratio(int value); + double pos2ratio(int pos); /** * paint prepare @@ -199,9 +195,9 @@ public: **/ void paint_fore(QPainter &p, int left, int right, QColor fore, QColor back); - QRect get_view_rect() const; + QRect get_view_rect(); - QRectF get_trig_rect(int left, int right) const; + QRectF get_trig_rect(int left, int right); QString get_measure(enum DSO_MEASURE_TYPE type); @@ -217,13 +213,13 @@ protected: private: void paint_trace(QPainter &p, - const boost::shared_ptr &snapshot, + const pv::data::DsoSnapshot* snapshot, int zeroY, int left, const int64_t start, const int64_t end, int hw_offset, const double pixels_offset, const double samples_per_pixel, uint64_t num_channels); void paint_envelope(QPainter &p, - const boost::shared_ptr &snapshot, + const pv::data::DsoSnapshot *snapshot, int zeroY, int left, const int64_t start, const int64_t end, int hw_offset, const double pixels_offset, const double samples_per_pixel, uint64_t num_channels); @@ -232,7 +228,7 @@ private: void auto_set(); private: - boost::shared_ptr _data; + pv::data::Dso *_data; float _scale; bool _en_lock; bool _show; diff --git a/DSView/pv/view/groupsignal.cpp b/DSView/pv/view/groupsignal.cpp index 1e67f654..0c5870aa 100755 --- a/DSView/pv/view/groupsignal.cpp +++ b/DSView/pv/view/groupsignal.cpp @@ -42,7 +42,7 @@ const QColor GroupSignal::SignalColours[4] = { const float GroupSignal::EnvelopeThreshold = 256.0f; -GroupSignal::GroupSignal(QString name, boost::shared_ptr data, +GroupSignal::GroupSignal(QString name, data::Group *data, std::list probe_index_list, int group_index) : Trace(name, probe_index_list, SR_CHANNEL_GROUP, group_index), _data(data) @@ -55,12 +55,12 @@ GroupSignal::~GroupSignal() { } -bool GroupSignal::enabled() const +bool GroupSignal::enabled() { return true; } -boost::shared_ptr GroupSignal::data() const +pv::data::SignalData* GroupSignal::data() { return _data; } @@ -85,13 +85,11 @@ void GroupSignal::paint_mid(QPainter &p, int left, int right, QColor fore, QColo _scale = _totalHeight * 1.0f / std::pow(2.0, static_cast(_index_list.size())); - const deque< boost::shared_ptr > &snapshots = - _data->get_snapshots(); + const auto &snapshots = _data->get_snapshots(); if (snapshots.empty()) return; - const boost::shared_ptr &snapshot = - snapshots.at(_sec_index); + const auto snapshot = snapshots.at(_sec_index); const double pixels_offset = offset; const double samplerate = _data->samplerate(); @@ -116,13 +114,15 @@ void GroupSignal::paint_mid(QPainter &p, int left, int right, QColor fore, QColo } void GroupSignal::paint_trace(QPainter &p, - const boost::shared_ptr &snapshot, + const pv::data::GroupSnapshot *snapshot, int y, int left, const int64_t start, const int64_t end, const double pixels_offset, const double samples_per_pixel) { const int64_t sample_count = end - start; - const uint16_t *samples = snapshot->get_samples(start, end); + pv::data::GroupSnapshot *pshot = const_cast(snapshot); + + const uint16_t *samples = pshot->get_samples(start, end); assert(samples); p.setPen(_colour); @@ -144,7 +144,7 @@ void GroupSignal::paint_trace(QPainter &p, } void GroupSignal::paint_envelope(QPainter &p, - const boost::shared_ptr &snapshot, + const pv::data::GroupSnapshot *snapshot, int y, int left, const int64_t start, const int64_t end, const double pixels_offset, const double samples_per_pixel) { @@ -152,7 +152,9 @@ void GroupSignal::paint_envelope(QPainter &p, using pv::data::GroupSnapshot; GroupSnapshot::EnvelopeSection e; - snapshot->get_envelope_section(e, start, end, samples_per_pixel); + + pv::data::GroupSnapshot *pshot = const_cast(snapshot); + pshot->get_envelope_section(e, start, end, samples_per_pixel); if (e.length < 2) return; diff --git a/DSView/pv/view/groupsignal.h b/DSView/pv/view/groupsignal.h index 76f1a20f..a86c388e 100755 --- a/DSView/pv/view/groupsignal.h +++ b/DSView/pv/view/groupsignal.h @@ -26,8 +26,7 @@ #include "signal.h" #include "../data/groupsnapshot.h" -#include -#include +#include namespace pv { @@ -55,7 +54,7 @@ private: public: GroupSignal(QString name, - boost::shared_ptr data, + pv::data::Group *data, std::list probe_index_list, int group_index); virtual ~GroupSignal(); @@ -63,9 +62,9 @@ public: /** * Returns true if the trace is visible and enabled. */ - bool enabled() const; + bool enabled(); - boost::shared_ptr data() const; + pv::data::SignalData* data(); void set_scale(float scale); @@ -84,17 +83,17 @@ protected: private: void paint_trace(QPainter &p, - const boost::shared_ptr &snapshot, + const pv::data::GroupSnapshot *snapshot, int y, int left, const int64_t start, const int64_t end, const double pixels_offset, const double samples_per_pixel); void paint_envelope(QPainter &p, - const boost::shared_ptr &snapshot, + const pv::data::GroupSnapshot *snapshot, int y, int left, const int64_t start, const int64_t end, const double pixels_offset, const double samples_per_pixel); private: - boost::shared_ptr _data; + pv::data::Group *_data; float _scale; }; diff --git a/DSView/pv/view/header.cpp b/DSView/pv/view/header.cpp index c5c44314..e5244e67 100755 --- a/DSView/pv/view/header.cpp +++ b/DSView/pv/view/header.cpp @@ -99,13 +99,10 @@ int Header::get_nameEditWidth() return 0; } -boost::shared_ptr Header::get_mTrace( - int &action, - const QPoint &pt) +pv::view::Trace* Header::get_mTrace(int &action, const QPoint &pt) { const int w = width(); - const vector< boost::shared_ptr > traces( - _view.get_traces(ALL_VIEW)); + const auto &traces = _view.get_traces(ALL_VIEW); for(auto &t : traces) { @@ -115,7 +112,7 @@ boost::shared_ptr Header::get_mTrace( return t; } - return boost::shared_ptr(); + return NULL; } void Header::paintEvent(QPaintEvent*) @@ -128,10 +125,7 @@ void Header::paintEvent(QPaintEvent*) style()->drawPrimitive(QStyle::PE_Widget, &o, &painter, this); const int w = width(); - const vector< boost::shared_ptr > traces( - _view.get_traces(ALL_VIEW)); - - // auto num = traces.size(); + const auto &traces = _view.get_traces(ALL_VIEW); const bool dragging = !_drag_traces.empty(); QColor fore(QWidget::palette().color(QWidget::foregroundRole())); @@ -140,7 +134,6 @@ void Header::paintEvent(QPaintEvent*) for(auto &t : traces) { assert(t); - // auto ptr = t.get(); t->paint_label(painter, w, dragging ? QPoint(-1, -1) : _mouse_point, fore); } @@ -151,8 +144,7 @@ void Header::mouseDoubleClickEvent(QMouseEvent *event) { assert(event); - const vector< boost::shared_ptr > traces( - _view.get_traces(ALL_VIEW)); + const auto &traces = _view.get_traces(ALL_VIEW); if (event->button() & Qt::LeftButton) { _mouse_down_point = event->pos(); @@ -175,8 +167,7 @@ void Header::mousePressEvent(QMouseEvent *event) { assert(event); - const vector< boost::shared_ptr > traces( - _view.get_traces(ALL_VIEW)); + const auto &traces = _view.get_traces(ALL_VIEW); int action; const bool instant = _view.session().get_instant(); if (instant && _view.session().get_capture_state() == SigSession::Running) { @@ -193,8 +184,7 @@ void Header::mousePressEvent(QMouseEvent *event) make_pair(t, t->get_v_offset())); // Select the Trace if it has been clicked - const boost::shared_ptr mTrace = - get_mTrace(action, event->pos()); + const auto mTrace = get_mTrace(action, event->pos()); if (action == Trace::COLOR && mTrace) { _colorFlag = true; } else if (action == Trace::NAME && mTrace) { @@ -229,8 +219,7 @@ void Header::mouseReleaseEvent(QMouseEvent *event) // judge for color / name / trigger / move int action; - const boost::shared_ptr mTrace = - get_mTrace(action, event->pos()); + const auto mTrace = get_mTrace(action, event->pos()); if (mTrace){ if (action == Trace::COLOR && _colorFlag) { _context_trace = mTrace; @@ -247,10 +236,11 @@ void Header::mouseReleaseEvent(QMouseEvent *event) _view.signals_changed(); _view.set_all_update(true); - const vector< boost::shared_ptr > traces( - _view.get_traces(ALL_VIEW)); - for(auto &t : traces) + const auto &traces = _view.get_traces(ALL_VIEW); + + for(auto &t : traces){ t->select(false); + } } _colorFlag = false; @@ -265,8 +255,7 @@ void Header::wheelEvent(QWheelEvent *event) assert(event); if (event->orientation() == Qt::Vertical) { - const vector< boost::shared_ptr > traces( - _view.get_traces(ALL_VIEW)); + const auto &traces = _view.get_traces(ALL_VIEW); // Vertical scrolling double shift = 0; #ifdef Q_OS_DARWIN @@ -327,29 +316,27 @@ void Header::mouseMoveEvent(QMouseEvent *event) if (!_drag_traces.empty()) { const int delta = event->pos().y() - _mouse_down_point.y(); - for (std::list, - int> >::iterator i = _drag_traces.begin(); - i != _drag_traces.end(); i++) { - const boost::shared_ptr sig((*i).first); + for (auto i = _drag_traces.begin(); i != _drag_traces.end(); i++) { + const auto sig = (*i).first; if (sig) { int y = (*i).second + delta; if (sig->get_type() == SR_CHANNEL_DSO) { - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(sig))) { + DsoSignal *dsoSig = NULL; + if ((dsoSig = dynamic_cast(sig))) { dsoSig->set_zero_vpos(y); _moveFlag = true; traces_moved(); } } else if (sig->get_type() == SR_CHANNEL_MATH) { - boost::shared_ptr mathTrace; - if ((mathTrace = dynamic_pointer_cast(sig))) { + MathTrace *mathTrace = NULL; + if ((mathTrace = dynamic_cast(sig))) { mathTrace->set_zero_vpos(y); _moveFlag = true; traces_moved(); } } else if (sig->get_type() == SR_CHANNEL_ANALOG) { - boost::shared_ptr analogSig; - if ((analogSig = dynamic_pointer_cast(sig))) { + AnalogSignal *analogSig = NULL; + if ((analogSig = dynamic_cast(sig))) { analogSig->set_zero_vpos(y); _moveFlag = true; traces_moved(); @@ -384,7 +371,7 @@ void Header::contextMenuEvent(QContextMenuEvent *event) int action; - const boost::shared_ptr t = get_mTrace(action, _mouse_point); + const auto t = get_mTrace(action, _mouse_point); if (!t || !t->selected() || action != Trace::LABEL) return; @@ -400,12 +387,12 @@ void Header::contextMenuEvent(QContextMenuEvent *event) // _context_trace = t; // menu.exec(event->globalPos()); -// _context_trace.reset(); +// _context_trace.r-eset(); } void Header::on_action_set_name_triggered() { - boost::shared_ptr context_Trace = _context_trace; + auto context_Trace = _context_trace; if (!context_Trace) return; diff --git a/DSView/pv/view/header.h b/DSView/pv/view/header.h index 1dc83c01..cf7741e4 100755 --- a/DSView/pv/view/header.h +++ b/DSView/pv/view/header.h @@ -24,9 +24,6 @@ #ifndef DSVIEW_PV_VIEW_HEADER_H #define DSVIEW_PV_VIEW_HEADER_H -#include -#include - #include #include @@ -49,9 +46,7 @@ public: Header(View &parent); private: - boost::shared_ptr get_mTrace( - int &action, - const QPoint &pt); + pv::view::Trace* get_mTrace(int &action, const QPoint &pt); private: void changeEvent(QEvent *event); @@ -100,10 +95,9 @@ private: QLineEdit *nameEdit; - std::list, int> > - _drag_traces; + std::list > _drag_traces; - boost::shared_ptr _context_trace; + Trace *_context_trace; QAction *_action_add_group; QAction *_action_del_group; diff --git a/DSView/pv/view/lissajoustrace.cpp b/DSView/pv/view/lissajoustrace.cpp index f1d307cc..5e091820 100755 --- a/DSView/pv/view/lissajoustrace.cpp +++ b/DSView/pv/view/lissajoustrace.cpp @@ -42,7 +42,7 @@ namespace pv { namespace view { LissajousTrace::LissajousTrace(bool enable, - boost::shared_ptr data, + data::Dso *data, int xIndex, int yIndex, int percent): Trace("Lissajous", xIndex, SR_CHANNEL_LISSAJOUS), _data(data), @@ -58,7 +58,7 @@ LissajousTrace::~LissajousTrace() { } -bool LissajousTrace::enabled() const +bool LissajousTrace::enabled() { return _enable; } @@ -68,27 +68,27 @@ void LissajousTrace::set_enable(bool enable) _enable = enable; } -int LissajousTrace::xIndex() const +int LissajousTrace::xIndex() { return _xIndex; } -int LissajousTrace::yIndex() const +int LissajousTrace::yIndex() { return _yIndex; } -int LissajousTrace::percent() const +int LissajousTrace::percent() { return _percent; } -boost::shared_ptr LissajousTrace::get_data() const +pv::data::Dso* LissajousTrace::get_data() { return _data; } -void LissajousTrace::set_data(boost::shared_ptr data) +void LissajousTrace::set_data(data::Dso *data) { _data = data; } @@ -151,12 +151,11 @@ void LissajousTrace::paint_mid(QPainter &p, int left, int right, QColor fore, QC assert(right >= left); if (enabled()) { - const deque< boost::shared_ptr > &snapshots = - _data->get_snapshots(); + const auto &snapshots = _data->get_snapshots(); if (snapshots.empty()) return; - const boost::shared_ptr &snapshot = - snapshots.front(); + + auto snapshot = snapshots.front(); if (snapshot->empty()) return; diff --git a/DSView/pv/view/lissajoustrace.h b/DSView/pv/view/lissajoustrace.h index f5245d30..5a038a33 100755 --- a/DSView/pv/view/lissajoustrace.h +++ b/DSView/pv/view/lissajoustrace.h @@ -24,9 +24,7 @@ #define DSVIEW_PV_LISSAJOUSTRACE_H #include "trace.h" - -#include - + namespace pv { namespace data { @@ -48,20 +46,19 @@ private: static const int DIV_NUM = 10; public: - LissajousTrace(bool enable, - boost::shared_ptr data, + LissajousTrace(bool enable, pv::data::Dso *data, int xIndex, int yIndex, int percent); virtual ~LissajousTrace(); - bool enabled() const; + bool enabled(); void set_enable(bool enable); - int xIndex() const; - int yIndex() const; - int percent() const; + int xIndex(); + int yIndex(); + int percent(); - boost::shared_ptr get_data() const; - void set_data(boost::shared_ptr data); + pv::data::Dso* get_data(); + void set_data(pv::data::Dso* data); int rows_size(); @@ -92,7 +89,7 @@ public: void paint_label(QPainter &p, int right, const QPoint pt, QColor fore); private: - boost::shared_ptr _data; + pv::data::Dso *_data; bool _enable; int _xIndex; diff --git a/DSView/pv/view/logicsignal.cpp b/DSView/pv/view/logicsignal.cpp index e336dc4a..87f9fb93 100755 --- a/DSView/pv/view/logicsignal.cpp +++ b/DSView/pv/view/logicsignal.cpp @@ -46,7 +46,7 @@ const int LogicSignal::StateHeight = 12; const int LogicSignal::StateRound = 5; LogicSignal::LogicSignal(DevInst *dev_inst, - boost::shared_ptr data, + data::Logic *data, sr_channel *probe) : Signal(dev_inst, probe), _data(data), @@ -54,10 +54,10 @@ LogicSignal::LogicSignal(DevInst *dev_inst, { } -LogicSignal::LogicSignal(boost::shared_ptr s, - boost::shared_ptr data, +LogicSignal::LogicSignal(view::LogicSignal *s, + data::Logic *data, sr_channel *probe) : - Signal(*s.get(), probe), + Signal(*s, probe), _data(data), _trig(s->get_trig()) { @@ -69,22 +69,22 @@ LogicSignal::~LogicSignal() _cur_pulses.clear(); } -const sr_channel* LogicSignal::probe() const +const sr_channel* LogicSignal::probe() { return _probe; } -boost::shared_ptr LogicSignal::data() const +pv::data::SignalData* LogicSignal::data() { return _data; } -boost::shared_ptr LogicSignal::logic_data() const +pv::data::Logic* LogicSignal::logic_data() { return _data; } -LogicSignal::LogicSetRegions LogicSignal::get_trig() const +LogicSignal::LogicSetRegions LogicSignal::get_trig() { return _trig; } @@ -137,14 +137,12 @@ void LogicSignal::paint_mid(QPainter &p, int left, int right, QColor fore, QColo const int high_offset = y - _totalHeight + 0.5f; const int low_offset = y + 0.5f; - const deque< boost::shared_ptr > &snapshots = - _data->get_snapshots(); + const auto &snapshots =_data->get_snapshots(); double samplerate = _data->samplerate(); if (snapshots.empty() || samplerate == 0) return; - - const boost::shared_ptr &snapshot = - snapshots.front(); + + auto snapshot = const_cast(snapshots.front()); if (snapshot->empty() || !snapshot->has_data(_probe->index)) return; @@ -202,7 +200,7 @@ void LogicSignal::paint_mid(QPainter &p, int left, int right, QColor fore, QColo } void LogicSignal::paint_caps(QPainter &p, QLineF *const lines, - vector< pair > &edges, bool level, + std::vector< pair > &edges, bool level, double samples_per_pixel, double pixels_offset, float x_offset, float y_offset) { @@ -210,7 +208,7 @@ void LogicSignal::paint_caps(QPainter &p, QLineF *const lines, uint64_t curX = 0; uint64_t nxtX = 0; - for (vector::const_iterator i = + for (std::vector::const_iterator i = edges.begin(); i != (edges.end() - 1); i++) if ((*i).second == level) { curX = ((*i).first / samples_per_pixel - @@ -289,17 +287,15 @@ void LogicSignal::paint_type_options(QPainter &p, int right, const QPoint pt, QC edgeTrig_rect.right() - 5, edgeTrig_rect.bottom() - 5); } -bool LogicSignal::measure(const QPointF &p, uint64_t &index0, uint64_t &index1, uint64_t &index2) const +bool LogicSignal::measure(const QPointF &p, uint64_t &index0, uint64_t &index1, uint64_t &index2) { const float gap = abs(p.y() - get_y()); if (gap < get_totalHeight() * 0.5) { - const deque< boost::shared_ptr > &snapshots = - _data->get_snapshots(); + const auto &snapshots =_data->get_snapshots(); if (snapshots.empty()) return false; - const boost::shared_ptr &snapshot = - snapshots.front(); + const auto snapshot = snapshots.front(); if (snapshot->empty() || !snapshot->has_data(_probe->index)) return false; @@ -343,18 +339,16 @@ bool LogicSignal::measure(const QPointF &p, uint64_t &index0, uint64_t &index1, return false; } -bool LogicSignal::edge(const QPointF &p, uint64_t &index, int radius) const +bool LogicSignal::edge(const QPointF &p, uint64_t &index, int radius) { uint64_t pre_index, nxt_index; const float gap = abs(p.y() - get_y()); if (gap < get_totalHeight() * 0.5) { - const deque< boost::shared_ptr > &snapshots = - _data->get_snapshots(); + const auto &snapshots = _data->get_snapshots(); if (snapshots.empty()) return false; - const boost::shared_ptr &snapshot = - snapshots.front(); + const auto snapshot = snapshots.front(); if (snapshot->empty() || !snapshot->has_data(_probe->index)) return false; @@ -397,7 +391,7 @@ bool LogicSignal::edge(const QPointF &p, uint64_t &index, int radius) const return false; } -bool LogicSignal::edges(const QPointF &p, uint64_t start, uint64_t &rising, uint64_t &falling) const +bool LogicSignal::edges(const QPointF &p, uint64_t start, uint64_t &rising, uint64_t &falling) { uint64_t end; const float gap = abs(p.y() - get_y()); @@ -408,15 +402,13 @@ bool LogicSignal::edges(const QPointF &p, uint64_t start, uint64_t &rising, uint return false; } -bool LogicSignal::edges(uint64_t end, uint64_t start, uint64_t &rising, uint64_t &falling) const +bool LogicSignal::edges(uint64_t end, uint64_t start, uint64_t &rising, uint64_t &falling) { - const deque< boost::shared_ptr > &snapshots = - _data->get_snapshots(); + const auto &snapshots = _data->get_snapshots(); if (snapshots.empty()) return false; - const boost::shared_ptr &snapshot = - snapshots.front(); + const auto snapshot = snapshots.front(); if (snapshot->empty() || !snapshot->has_data(_probe->index)) return false; diff --git a/DSView/pv/view/logicsignal.h b/DSView/pv/view/logicsignal.h index d2159eb5..931c0df6 100755 --- a/DSView/pv/view/logicsignal.h +++ b/DSView/pv/view/logicsignal.h @@ -26,9 +26,7 @@ #include "signal.h" -#include - -#include +#include namespace pv { @@ -66,26 +64,22 @@ public: }; public: - LogicSignal(DevInst *dev_inst, - boost::shared_ptr data, - sr_channel *probe); + LogicSignal(DevInst *dev_inst, data::Logic* data, sr_channel *probe); - LogicSignal(boost::shared_ptr s, - boost::shared_ptr data, - sr_channel *probe); + LogicSignal(view::LogicSignal*s, pv::data::Logic *data, sr_channel *probe); virtual ~LogicSignal(); - const sr_channel* probe() const; + const sr_channel* probe(); - boost::shared_ptr data() const; + pv::data::SignalData* data(); - boost::shared_ptr logic_data() const; + pv::data::Logic* logic_data(); /** * */ - LogicSetRegions get_trig() const; + LogicSetRegions get_trig(); void set_trig(int trig); bool commit_trig(); @@ -97,13 +91,13 @@ public: **/ void paint_mid(QPainter &p, int left, int right, QColor fore, QColor back); - bool measure(const QPointF &p, uint64_t &index0, uint64_t &index1, uint64_t &index2) const; + bool measure(const QPointF &p, uint64_t &index0, uint64_t &index1, uint64_t &index2); - bool edge(const QPointF &p, uint64_t &index, int radius) const; + bool edge(const QPointF &p, uint64_t &index, int radius); - bool edges(const QPointF &p, uint64_t start, uint64_t &rising, uint64_t &falling) const; + bool edges(const QPointF &p, uint64_t start, uint64_t &rising, uint64_t &falling); - bool edges(uint64_t end, uint64_t start, uint64_t &rising, uint64_t &falling) const; + bool edges(uint64_t end, uint64_t start, uint64_t &rising, uint64_t &falling); bool mouse_press(int right, const QPoint pt); @@ -122,7 +116,7 @@ private: float x_offset, float y_offset); private: - boost::shared_ptr _data; + pv::data::Logic* _data; std::vector< std::pair > _cur_edges; std::vector> _cur_pulses; LogicSetRegions _trig; diff --git a/DSView/pv/view/mathtrace.cpp b/DSView/pv/view/mathtrace.cpp index a61db919..c8f6753c 100755 --- a/DSView/pv/view/mathtrace.cpp +++ b/DSView/pv/view/mathtrace.cpp @@ -36,16 +36,14 @@ #include #include -using namespace boost; using namespace std; namespace pv { namespace view { -MathTrace::MathTrace(bool enable, - boost::shared_ptr math_stack, - boost::shared_ptr dsoSig1, - boost::shared_ptr dsoSig2): +MathTrace::MathTrace(bool enable,data::MathStack *math_stack, + view::DsoSignal *dsoSig1, + view::DsoSignal *dsoSig2): Trace("M", dsoSig1->get_index(), SR_CHANNEL_MATH), _math_stack(math_stack), _dsoSig1(dsoSig1), @@ -71,7 +69,7 @@ MathTrace::~MathTrace() { } -bool MathTrace::enabled() const +bool MathTrace::enabled() { return _enable; } @@ -81,12 +79,12 @@ void MathTrace::set_enable(bool enable) _enable = enable; } -int MathTrace::src1() const +int MathTrace::src1() { return _dsoSig1->get_index(); } -int MathTrace::src2() const +int MathTrace::src2() { return _dsoSig2->get_index(); } @@ -96,7 +94,7 @@ float MathTrace::get_scale() return _scale; } -int MathTrace::get_name_width() const +int MathTrace::get_name_width() { return 0; } @@ -138,12 +136,12 @@ void MathTrace::go_vDialNext() } } -uint64_t MathTrace::get_vDialValue() const +uint64_t MathTrace::get_vDialValue() { return _vDial->get_value(); } -uint16_t MathTrace::get_vDialSel() const +uint16_t MathTrace::get_vDialSel() { return _vDial->get_sel(); } @@ -159,7 +157,7 @@ void MathTrace::set_zero_vrate(double rate) _hw_offset = _zero_vrate * (_ref_max - _ref_min) + _ref_min; } -int MathTrace::get_zero_vpos() const +int MathTrace::get_zero_vpos() { return _zero_vrate * get_view_rect().height() + DsoSignal::UpMargin; } @@ -177,7 +175,7 @@ void MathTrace::set_show(bool show) _show = show; } -QRect MathTrace::get_view_rect() const +QRect MathTrace::get_view_rect() { assert(_viewport); return QRect(0, DsoSignal::UpMargin, @@ -426,7 +424,7 @@ void MathTrace::paint_hover_measure(QPainter &p, QColor fore, QColor back) p.drawText(hover_rect, Qt::AlignCenter | Qt::AlignTop | Qt::TextDontClip, hover_str); } - list::iterator i = _view->get_cursorList().begin(); + auto i = _view->get_cursorList().begin(); while (i != _view->get_cursorList().end()) { float pt_value; const QPointF pt = get_point((*i)->index(), pt_value); @@ -500,7 +498,7 @@ QString MathTrace::get_time(double t) return str; } -const boost::shared_ptr& MathTrace::get_math_stack() const +pv::data::MathStack* MathTrace::get_math_stack() { return _math_stack; } diff --git a/DSView/pv/view/mathtrace.h b/DSView/pv/view/mathtrace.h index 3bcd9428..8eb6413b 100755 --- a/DSView/pv/view/mathtrace.h +++ b/DSView/pv/view/mathtrace.h @@ -23,9 +23,7 @@ #ifndef DSVIEW_PV_MATHTRACE_H #define DSVIEW_PV_MATHTRACE_H -#include "trace.h" - -#include +#include "trace.h" namespace pv { @@ -52,15 +50,15 @@ public: }; public: - MathTrace(bool enable, boost::shared_ptr math_stack, - boost::shared_ptr dsoSig1, - boost::shared_ptr dsoSig2); + MathTrace(bool enable, pv::data::MathStack *math_stack, + view::DsoSignal *dsoSig1, + view::DsoSignal *dsoSig2); virtual ~MathTrace(); float get_scale(); - int get_name_width() const; + int get_name_width(); /** * @@ -68,18 +66,18 @@ public: void update_vDial(); void go_vDialPre(); void go_vDialNext(); - uint64_t get_vDialValue() const; - uint16_t get_vDialSel() const; + uint64_t get_vDialValue(); + uint16_t get_vDialSel(); - bool enabled() const; + bool enabled(); void set_enable(bool enable); void set_show(bool show); - int get_zero_vpos() const; + int get_zero_vpos(); void set_zero_vpos(int pos); - int src1() const; - int src2() const; + int src1(); + int src2(); /** * @@ -125,13 +123,13 @@ public: **/ void paint_fore(QPainter &p, int left, int right, QColor fore, QColor back); - QRect get_view_rect() const; + QRect get_view_rect(); QRectF get_rect(MathSetRegions type, int y, int right); bool mouse_wheel(int right, const QPoint pt, const int shift); - const boost::shared_ptr& get_math_stack() const; + pv::data::MathStack* get_math_stack(); protected: void paint_type_options(QPainter &p, int right, const QPoint pt, QColor fore); @@ -148,9 +146,9 @@ private: void paint_hover_measure(QPainter &p, QColor fore, QColor back); private: - boost::shared_ptr _math_stack; - boost::shared_ptr _dsoSig1; - boost::shared_ptr _dsoSig2; + pv::data::MathStack *_math_stack; + view::DsoSignal *_dsoSig1; + view::DsoSignal *_dsoSig2; bool _enable; bool _show; diff --git a/DSView/pv/view/ruler.cpp b/DSView/pv/view/ruler.cpp index 1108087b..41b9a98c 100755 --- a/DSView/pv/view/ruler.cpp +++ b/DSView/pv/view/ruler.cpp @@ -39,8 +39,7 @@ #include #include #include - -#include + using namespace boost; using namespace std; @@ -219,7 +218,7 @@ void Ruler::mousePressEvent(QMouseEvent *event) bool visible; if (!_cursor_sel_visible & !_view.get_cursorList().empty()) { _view.show_cursors(true); - list::iterator i = _view.get_cursorList().begin(); + auto i = _view.get_cursorList().begin(); while (i != _view.get_cursorList().end()) { const QRect cursor_rect((*i)->get_label_rect(rect(), visible)); if ((*i)->get_close_rect(cursor_rect).contains(event->pos())) { @@ -262,7 +261,7 @@ void Ruler::mouseReleaseEvent(QMouseEvent *event) _view.show_cursors(true); updatedCursor = true; } else if (overCursor > 0) { - list::iterator i = _view.get_cursorList().begin(); + auto i = _view.get_cursorList().begin(); while (--overCursor != 0) i++; (*i)->set_index(index); @@ -304,7 +303,7 @@ void Ruler::mouseReleaseEvent(QMouseEvent *event) int overCursor; overCursor = in_cursor_sel_rect(event->pos()); if (overCursor > 0) { - list::iterator i = _view.get_cursorList().begin(); + auto i = _view.get_cursorList().begin(); while (--overCursor != 0) i++; _view.del_cursor(*i); @@ -430,7 +429,7 @@ void Ruler::draw_logic_tick_mark(QPainter &p) // Draw the cursors if (!_view.get_cursorList().empty()) { - list::iterator i = _view.get_cursorList().begin(); + auto i = _view.get_cursorList().begin(); int index = 1; while (i != _view.get_cursorList().end()) { (*i)->paint_label(p, rect(), prefix, index, _view.session().get_capture_state() == SigSession::Stopped); @@ -548,7 +547,7 @@ void Ruler::draw_osc_tick_mark(QPainter &p) // Draw the cursors if (!_view.get_cursorList().empty()) { - list::iterator i = _view.get_cursorList().begin(); + auto i = _view.get_cursorList().begin(); int index = 1; while (i != _view.get_cursorList().end()) { (*i)->paint_label(p, rect(), prefix, index, _view.session().get_capture_state() == SigSession::Stopped); @@ -613,7 +612,7 @@ void Ruler::draw_cursor_sel(QPainter &p) if (!_view.get_cursorList().empty()) { int index = 1; - list::iterator i = _view.get_cursorList().begin(); + auto i = _view.get_cursorList().begin(); while (i != _view.get_cursorList().end()) { const QRectF cursorRect = get_cursor_sel_rect(index); p.setPen(QPen(Qt::black, 1, Qt::DotLine)); @@ -662,7 +661,7 @@ void Ruler::hover_point_changed() update(); } -double Ruler::get_min_period() const +double Ruler::get_min_period() { return _min_period / MinPeriodScale; } diff --git a/DSView/pv/view/ruler.h b/DSView/pv/view/ruler.h index 18b310c9..822c7d5f 100755 --- a/DSView/pv/view/ruler.h +++ b/DSView/pv/view/ruler.h @@ -69,7 +69,7 @@ public: void set_grabbed_cursor(TimeMarker* grabbed_marker); void rel_grabbed_cursor(); - double get_min_period() const; + double get_min_period(); private: void paintEvent(QPaintEvent *event); diff --git a/DSView/pv/view/selectableitem.cpp b/DSView/pv/view/selectableitem.cpp index cc2b42cd..ed23e2ff 100755 --- a/DSView/pv/view/selectableitem.cpp +++ b/DSView/pv/view/selectableitem.cpp @@ -36,7 +36,7 @@ SelectableItem::SelectableItem() : { } -bool SelectableItem::selected() const +bool SelectableItem::selected() { return _selected; } diff --git a/DSView/pv/view/selectableitem.h b/DSView/pv/view/selectableitem.h index 7859ee4e..4a23cc97 100755 --- a/DSView/pv/view/selectableitem.h +++ b/DSView/pv/view/selectableitem.h @@ -43,14 +43,14 @@ class SelectableItem : public QObject private: static const int HighlightRadius; -public: +protected: SelectableItem(); public: /** * Returns true if the signal has been selected by the user. */ - bool selected() const; + bool selected(); /** * Selects or deselects the signal. diff --git a/DSView/pv/view/signal.cpp b/DSView/pv/view/signal.cpp index 3be6142d..23011a23 100755 --- a/DSView/pv/view/signal.cpp +++ b/DSView/pv/view/signal.cpp @@ -46,7 +46,7 @@ Signal::Signal(const Signal &s, sr_channel *probe) : { } -bool Signal::enabled() const +bool Signal::enabled() { return _probe->enabled; } @@ -58,7 +58,7 @@ void Signal::set_name(QString name) _probe->name = g_strdup(name.toUtf8().data()); } -DevInst* Signal::get_device() const +DevInst* Signal::get_device() { return _dev_inst; } diff --git a/DSView/pv/view/signal.h b/DSView/pv/view/signal.h index 1d3ed5ad..931d54b6 100755 --- a/DSView/pv/view/signal.h +++ b/DSView/pv/view/signal.h @@ -23,8 +23,7 @@ #ifndef DSVIEW_PV_SIGNAL_H #define DSVIEW_PV_SIGNAL_H - -#include + #include #include @@ -69,12 +68,12 @@ protected: Signal(const Signal &s, sr_channel * const probe); public: - virtual boost::shared_ptr data() const = 0; + virtual pv::data::SignalData* data() = 0; /** * Returns true if the trace is visible and enabled. */ - bool enabled() const; + bool enabled(); /** * Sets the name of the signal. @@ -91,7 +90,7 @@ public: */ //virtual void paint_label(QPainter &p, int right, bool hover, int action); - DevInst* get_device() const; + DevInst* get_device(); protected: DevInst* _dev_inst; diff --git a/DSView/pv/view/spectrumtrace.cpp b/DSView/pv/view/spectrumtrace.cpp index bb0ffcb9..6f7ceba3 100755 --- a/DSView/pv/view/spectrumtrace.cpp +++ b/DSView/pv/view/spectrumtrace.cpp @@ -68,7 +68,7 @@ const int SpectrumTrace::HoverPointSize = 3; const double SpectrumTrace::VerticalRate = 1.0 / 2000.0; SpectrumTrace::SpectrumTrace(pv::SigSession *session, - boost::shared_ptr spectrum_stack, int index) : + pv::data::SpectrumStack *spectrum_stack, int index) : Trace("FFT("+QString::number(index)+")", index, SR_CHANNEL_FFT), _session(session), _spectrum_stack(spectrum_stack), @@ -79,11 +79,11 @@ SpectrumTrace::SpectrumTrace(pv::SigSession *session, _offset(0) { _typeWidth = 0; - const vector< boost::shared_ptr > sigs(_session->get_signals()); + const auto &sigs = _session->get_signals(); for(size_t i = 0; i < sigs.size(); i++) { - const boost::shared_ptr s(sigs[i]); + const auto s = sigs[i]; assert(s); - if (dynamic_pointer_cast(s) && index == s->get_index()) + if (dynamic_cast(s) && index == s->get_index()) _colour = s->get_colour(); } } @@ -93,7 +93,7 @@ SpectrumTrace::~SpectrumTrace() } -bool SpectrumTrace::enabled() const +bool SpectrumTrace::enabled() { return _enable; } @@ -103,7 +103,7 @@ void SpectrumTrace::set_enable(bool enable) _enable = enable; } -int SpectrumTrace::view_mode() const +int SpectrumTrace::view_mode() { return _view_mode; } @@ -123,7 +123,7 @@ std::vector SpectrumTrace::get_view_modes_support() return modes; } -const boost::shared_ptr& SpectrumTrace::get_spectrum_stack() const +pv::data::SpectrumStack* SpectrumTrace::get_spectrum_stack() { return _spectrum_stack; } @@ -160,7 +160,7 @@ void SpectrumTrace::set_offset(double delta) _view->update(); } -double SpectrumTrace::get_offset() const +double SpectrumTrace::get_offset() { return _offset; } @@ -173,7 +173,7 @@ void SpectrumTrace::set_scale(double scale) _view->update(); } -double SpectrumTrace::get_scale() const +double SpectrumTrace::get_scale() { return _scale; } @@ -183,7 +183,7 @@ void SpectrumTrace::set_dbv_range(int range) _dbv_range = range; } -int SpectrumTrace::dbv_range() const +int SpectrumTrace::dbv_range() { return _dbv_range; } @@ -296,8 +296,8 @@ void SpectrumTrace::paint_mid(QPainter &p, int left, int right, QColor fore, QCo double vfactor = 0; for(auto &s : _session->get_signals()) { - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(s))) { + DsoSignal *dsoSig = NULL; + if ((dsoSig = dynamic_cast(s))) { if(dsoSig->get_index() == _spectrum_stack->get_index()) { vdiv = dsoSig->get_vDialValue(); vfactor = dsoSig->get_factor(); @@ -483,7 +483,7 @@ void SpectrumTrace::paint_type_options(QPainter &p, int right, const QPoint pt, (void)fore; } -QRect SpectrumTrace::get_view_rect() const +QRect SpectrumTrace::get_view_rect() { assert(_viewport); return QRect(0, UpMargin, diff --git a/DSView/pv/view/spectrumtrace.h b/DSView/pv/view/spectrumtrace.h index 293269ef..9c3f368b 100755 --- a/DSView/pv/view/spectrumtrace.h +++ b/DSView/pv/view/spectrumtrace.h @@ -25,8 +25,7 @@ #include #include - -#include + struct srd_channel; @@ -67,33 +66,32 @@ private: static const double VerticalRate; public: - SpectrumTrace(pv::SigSession *session, - boost::shared_ptr spectrum_stack, int index); + SpectrumTrace(pv::SigSession *session, pv::data::SpectrumStack *spectrum_stack, int index); ~SpectrumTrace(); - bool enabled() const; + bool enabled(); void set_enable(bool enable); void init_zoom(); void zoom(double steps, int offset); - bool zoom_hit() const; + bool zoom_hit(); void set_zoom_hit(bool hit); void set_offset(double delta); - double get_offset() const; + double get_offset(); void set_scale(double scale); - double get_scale() const; + double get_scale(); void set_dbv_range(int range); - int dbv_range() const; + int dbv_range(); std::vector get_dbv_ranges(); - int view_mode() const; + int view_mode(); void set_view_mode(unsigned int mode); std::vector get_view_modes_support(); - const boost::shared_ptr& get_spectrum_stack() const; + pv::data::SpectrumStack* get_spectrum_stack(); static QString format_freq(double freq, unsigned precision = Pricision); @@ -123,7 +121,7 @@ public: **/ void paint_fore(QPainter &p, int left, int right, QColor fore, QColor back); - QRect get_view_rect() const; + QRect get_view_rect(); protected: void paint_type_options(QPainter &p, int right, const QPoint pt, QColor fore); @@ -134,7 +132,7 @@ private slots: private: pv::SigSession *_session; - boost::shared_ptr _spectrum_stack; + pv::data::SpectrumStack *_spectrum_stack; bool _enable; int _view_mode; diff --git a/DSView/pv/view/timemarker.cpp b/DSView/pv/view/timemarker.cpp index f103eb7f..79a43707 100755 --- a/DSView/pv/view/timemarker.cpp +++ b/DSView/pv/view/timemarker.cpp @@ -48,7 +48,7 @@ TimeMarker::TimeMarker(const TimeMarker &s) : { } -QColor TimeMarker::colour() const +QColor TimeMarker::colour() { return _colour; } @@ -58,7 +58,7 @@ void TimeMarker::set_colour(QColor color) _colour = color; } -bool TimeMarker::grabbed() const +bool TimeMarker::grabbed() { return _grabbed; } @@ -67,7 +67,7 @@ void TimeMarker::set_grabbed(bool grabbed) _grabbed = grabbed; } -uint64_t TimeMarker::index() const +uint64_t TimeMarker::index() { return _index; } diff --git a/DSView/pv/view/timemarker.h b/DSView/pv/view/timemarker.h index abcb63d6..84cc0bcb 100755 --- a/DSView/pv/view/timemarker.h +++ b/DSView/pv/view/timemarker.h @@ -60,8 +60,8 @@ public: /** * Gets the time of the marker. */ - double time() const; - uint64_t index() const; + double time(); + uint64_t index(); /** * Sets the time of the marker. @@ -71,13 +71,13 @@ public: /** * Gets/Sets colour of the marker */ - QColor colour() const; + QColor colour(); void set_colour(QColor color); /* * */ - bool grabbed() const; + bool grabbed(); void set_grabbed(bool grabbed); /** @@ -93,7 +93,7 @@ public: * @param visible is this marker in visible area * @return Returns the label rectangle. */ - virtual QRect get_label_rect(const QRect &rect, bool &visible, bool has_hoff = true) const = 0; + virtual QRect get_label_rect(const QRect &rect, bool &visible, bool has_hoff = true) = 0; /** * Paints the marker's label to the ruler. diff --git a/DSView/pv/view/trace.cpp b/DSView/pv/view/trace.cpp index fca6addf..782dfa85 100755 --- a/DSView/pv/view/trace.cpp +++ b/DSView/pv/view/trace.cpp @@ -87,12 +87,12 @@ Trace::Trace(const Trace &t) : { } -QString Trace::get_name() const +QString Trace::get_name() { return _name; } -int Trace::get_name_width() const +int Trace::get_name_width() { QFont font = QApplication::font(); QFontMetrics fm(font); @@ -105,7 +105,7 @@ void Trace::set_name(QString name) _name = name; } -QColor Trace::get_colour() const +QColor Trace::get_colour() { return _colour; } @@ -115,7 +115,7 @@ void Trace::set_colour(QColor colour) _colour = colour; } -int Trace::get_v_offset() const +int Trace::get_v_offset() { return _v_offset; } @@ -126,12 +126,12 @@ void Trace::set_v_offset(int v_offset) } -int Trace::get_type() const +int Trace::get_type() { return _type; } -int Trace::get_index() const +int Trace::get_index() { return _index_list.front(); } @@ -148,7 +148,7 @@ void Trace::set_index_list(std::list index_list) _index_list = index_list; } -int Trace::get_sec_index() const +int Trace::get_sec_index() { return _sec_index; } @@ -158,7 +158,7 @@ void Trace::set_sec_index(int sec_index) _sec_index = sec_index; } -int Trace::get_old_v_offset() const +int Trace::get_old_v_offset() { return _old_v_offset; } @@ -168,12 +168,12 @@ void Trace::set_old_v_offset(int v_offset) _old_v_offset = v_offset; } -int Trace::get_zero_vpos() const +int Trace::get_zero_vpos() { return _v_offset; } -int Trace::get_totalHeight() const +int Trace::get_totalHeight() { return _totalHeight; } @@ -195,7 +195,7 @@ void Trace::set_view(pv::view::View *view) connect(_view, SIGNAL(resize()), this, SLOT(resize())); } -pv::view::View* Trace::get_view() const +pv::view::View* Trace::get_view() { return _view; } @@ -206,7 +206,7 @@ void Trace::set_viewport(pv::view::Viewport *viewport) _viewport = viewport; } -pv::view::Viewport* Trace::get_viewport() const +pv::view::Viewport* Trace::get_viewport() { return _viewport; } @@ -399,18 +399,18 @@ void Trace::compute_text_size(QPainter &p) p.boundingRect(QRectF(), 0, "99").height()); } -QRect Trace::get_view_rect() const +QRect Trace::get_view_rect() { assert(_view); return QRect(0, 0, _view->viewport()->width(), _view->viewport()->height()); } -int Trace::get_y() const +int Trace::get_y() { return _v_offset; } -QColor Trace::get_text_colour() const +QColor Trace::get_text_colour() { return (_colour.lightness() > 64) ? Qt::black : Qt::white; } @@ -432,22 +432,22 @@ int Trace::rows_size() return 1; } -int Trace::get_leftWidth() const +int Trace::get_leftWidth() { return SquareWidth/2 + Margin; } -int Trace::get_rightWidth() const +int Trace::get_rightWidth() { return 2 * Margin + _typeWidth * SquareWidth + 1.5 * SquareWidth; } -int Trace::get_headerHeight() const +int Trace::get_headerHeight() { return SquareWidth; } -QRectF Trace::get_rect(const char *s, int y, int right) const +QRectF Trace::get_rect(const char *s, int y, int right) { const QSizeF color_size(get_leftWidth() - Margin, SquareWidth); const QSizeF name_size(right - get_leftWidth() - get_rightWidth(), SquareWidth); diff --git a/DSView/pv/view/trace.h b/DSView/pv/view/trace.h index 6c0ad638..e1b3ecfb 100755 --- a/DSView/pv/view/trace.h +++ b/DSView/pv/view/trace.h @@ -42,6 +42,7 @@ namespace view { class View; class Viewport; +//base class class Trace : public SelectableItem { Q_OBJECT @@ -72,8 +73,8 @@ public: /** * Gets the name of this signal. */ - QString get_name() const; - virtual int get_name_width() const; + QString get_name(); + virtual int get_name_width(); /** * Sets the name of the signal. @@ -83,7 +84,7 @@ public: /** * Get the colour of the signal. */ - QColor get_colour() const; + QColor get_colour(); /** * Set the colour of the signal. @@ -93,7 +94,7 @@ public: /** * Gets the vertical layout offset of this signal. */ - int get_v_offset() const; + int get_v_offset(); /** * Sets the vertical layout offset of this signal. @@ -103,21 +104,21 @@ public: /** * Gets trace type */ - int get_type() const; + int get_type(); /** * Index process */ - int get_index() const; + int get_index(); std::list &get_index_list(); void set_index_list(std::list index_list); - int get_sec_index() const; + int get_sec_index(); void set_sec_index(int sec_index); /** * Gets the height of this signal. */ - int get_totalHeight() const; + int get_totalHeight(); /** * Sets the height of this signal. @@ -127,31 +128,31 @@ public: /** * Geom */ - int get_leftWidth() const; - int get_rightWidth() const; - int get_headerHeight() const; + int get_leftWidth(); + int get_rightWidth(); + int get_headerHeight(); /** * Gets the old vertical layout offset of this signal. */ - int get_old_v_offset() const; + int get_old_v_offset(); /** * Sets the old vertical layout offset of this signal. */ void set_old_v_offset(int v_offset); - virtual int get_zero_vpos() const; + virtual int get_zero_vpos(); /** * Returns true if the trace is visible and enabled. */ - virtual bool enabled() const = 0; + virtual bool enabled() = 0; virtual void set_view(pv::view::View *view); - pv::view::View* get_view() const; + pv::view::View* get_view(); virtual void set_viewport(pv::view::Viewport *viewport); - pv::view::Viewport* get_viewport() const; + pv::view::Viewport* get_viewport(); /** * Paints prepare @@ -194,7 +195,7 @@ public: /** * Gets the y-offset of the axis. */ - int get_y() const; + int get_y(); /** * Determines if a point is in the header rect. @@ -222,11 +223,11 @@ public: * area. * @return Returns the rectangle of the signal label. */ - QRectF get_rect(const char *s, int y, int right) const; + QRectF get_rect(const char *s, int y, int right); virtual int rows_size(); - virtual QRect get_view_rect() const; + virtual QRect get_view_rect(); virtual bool mouse_double_click(int right, const QPoint pt); @@ -242,7 +243,7 @@ protected: * of the trace colour against a threshold to determine whether * white or black would be more visible. */ - QColor get_text_colour() const; + QColor get_text_colour(); /** * Paints optoins for different trace type. diff --git a/DSView/pv/view/view.cpp b/DSView/pv/view/view.cpp index 64220412..5ee7244f 100755 --- a/DSView/pv/view/view.cpp +++ b/DSView/pv/view/view.cpp @@ -23,8 +23,7 @@ #include #include #include - - + #include #include #include @@ -49,7 +48,7 @@ #include "pv/dialogs/calibration.h" #include "pv/dialogs/lissajousoptions.h" -using namespace boost; + using namespace std; namespace pv { @@ -221,17 +220,17 @@ SigSession& View::session() return *_session; } -double View::scale() const +double View::scale() { return _scale; } -int64_t View::offset() const +int64_t View::offset() { return _offset; } -double View::trig_hoff() const +double View::trig_hoff() { return _trig_hoff; } @@ -241,12 +240,12 @@ void View::set_trig_hoff(double hoff) _trig_hoff = hoff; } -double View::get_minscale() const +double View::get_minscale() { return _minscale; } -double View::get_maxscale() const +double View::get_maxscale() { return _maxscale; } @@ -323,7 +322,7 @@ bool View::zoom(double steps, int offset) } _offset = floor((_offset + offset) * (_preScale / _scale) - offset); - _offset = max(min(_offset, get_max_offset()), get_min_offset()); + _offset = max (min(_offset, get_max_offset()), get_min_offset()); if (_scale != _preScale || _offset != _preOffset) { _header->update(); @@ -374,20 +373,18 @@ void View::set_preScale_preOffset() set_scale_offset(_preScale, _preOffset); } -vector< boost::shared_ptr > View::get_traces(int type) +std::vector View::get_traces(int type) { assert(_session); - auto array = _session->get_signals(); - const vector< boost::shared_ptr > sigs(array); - const vector< boost::shared_ptr > groups(_session->get_group_signals()); + auto &sigs = _session->get_signals(); + const auto &groups = _session->get_group_signals(); - const vector< boost::shared_ptr > decode_sigs( - _session->get_decode_signals()); + const auto &decode_sigs = _session->get_decode_signals(); - const vector< boost::shared_ptr > spectrums(_session->get_spectrum_traces()); + const auto &spectrums = _session->get_spectrum_traces(); - vector< boost::shared_ptr > traces; + std::vector traces; for(auto &t : sigs) { if (type == ALL_VIEW || _trace_view_map[t->get_type()] == type) traces.push_back(t); @@ -408,12 +405,12 @@ vector< boost::shared_ptr > View::get_traces(int type) traces.push_back(t); } - boost::shared_ptr lissajous = _session->get_lissajous_trace(); + auto lissajous = _session->get_lissajous_trace(); if (lissajous && lissajous->enabled() && (type == ALL_VIEW || _trace_view_map[lissajous->get_type()] == type)) traces.push_back(lissajous); - boost::shared_ptr math = _session->get_math_trace(); + auto math = _session->get_math_trace(); if (math && math->enabled() && (type == ALL_VIEW || _trace_view_map[math->get_type()] == type)) traces.push_back(math); @@ -422,30 +419,34 @@ vector< boost::shared_ptr > View::get_traces(int type) return traces; } -bool View::compare_trace_v_offsets(const boost::shared_ptr &a, - const boost::shared_ptr &b) +bool View::compare_trace_v_offsets(const Trace *a, + const Trace *b) { assert(a); assert(b); - if (a->get_type() != b->get_type()) - return a->get_type() < b->get_type(); - else if (a->get_type() == SR_CHANNEL_DSO || a->get_type() == SR_CHANNEL_ANALOG) - return a->get_index() < b->get_index(); + + Trace *a1 = const_cast(a); + Trace *b1 = const_cast(b); + + if (a1->get_type() != b1->get_type()) + return a1->get_type() < b1->get_type(); + else if (a1->get_type() == SR_CHANNEL_DSO || a1->get_type() == SR_CHANNEL_ANALOG) + return a1->get_index() < b1->get_index(); else - return a->get_v_offset() < b->get_v_offset(); + return a1->get_v_offset() < b1->get_v_offset(); } -bool View::cursors_shown() const +bool View::cursors_shown() { return _show_cursors; } -bool View::trig_cursor_shown() const +bool View::trig_cursor_shown() { return _show_trig_cursor; } -bool View::search_cursor_shown() const +bool View::search_cursor_shown() { return _show_search_cursor; } @@ -578,14 +579,14 @@ bool View::get_search_hit() return _search_hit; } -const QPoint& View::hover_point() const +const QPoint& View::hover_point() { return _hover_point; } void View::normalize_layout() { - vector< boost::shared_ptr > traces(get_traces(ALL_VIEW)); + auto traces = get_traces(ALL_VIEW); int v_min = INT_MAX; for(auto &t : traces){ @@ -613,9 +614,9 @@ int View::get_signalHeight() return _signalHeight; } -void View::get_scroll_layout(int64_t &length, int64_t &offset) const +void View::get_scroll_layout(int64_t &length, int64_t &offset) { - const set< boost::shared_ptr > data_set = _session->get_data(); + const auto data_set = _session->get_data(); if (data_set.empty()) return; @@ -695,8 +696,8 @@ void View::signals_changed() int total_rows = 0; int label_size = 0; uint8_t max_height = MaxHeightUnit; - vector< boost::shared_ptr > time_traces; - vector< boost::shared_ptr > fft_traces; + std::vector time_traces; + std::vector fft_traces; for(auto &t : get_traces(ALL_VIEW)) { if (_trace_view_map[t->get_type()] == TIME_VIEW) @@ -736,7 +737,7 @@ void View::signals_changed() if (!time_traces.empty() && _time_viewport) { for(auto &t : time_traces) { assert(t); - if (dynamic_pointer_cast(t) || + if (dynamic_cast(t) || t->enabled()) total_rows += t->rows_size(); if (t->rows_size() != 0) @@ -779,13 +780,13 @@ void View::signals_changed() t->set_v_offset(next_v_offset + 0.5 * traceHeight + actualMargin); next_v_offset += traceHeight + 2 * actualMargin; - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(t))) { + view::DsoSignal *dsoSig = NULL; + if ((dsoSig = dynamic_cast(t))) { dsoSig->set_scale(dsoSig->get_view_rect().height()); } - boost::shared_ptr analogSig; - if ((analogSig = dynamic_pointer_cast(t))) { + view::AnalogSignal *analogSig = NULL; + if ((analogSig = dynamic_cast(t))) { analogSig->set_scale(analogSig->get_totalHeight()); } } @@ -848,7 +849,7 @@ int View::headerWidth() { int headerWidth = _header->get_nameEditWidth(); - const vector< boost::shared_ptr > traces(get_traces(ALL_VIEW)); + const auto &traces = get_traces(ALL_VIEW); if (!traces.empty()) { for(auto &t : traces) headerWidth = max(t->get_name_width() + t->get_leftWidth() + t->get_rightWidth(), @@ -1013,7 +1014,7 @@ void View::set_cursor_middle(int index) { assert(index < (int)_cursorList.size()); - list::iterator i = _cursorList.begin(); + auto i = _cursorList.begin(); while (index-- != 0) i++; set_scale_offset(_scale, (*i)->index() / (_session->cur_snap_samplerate() * _scale) - (get_view_width() / 2)); @@ -1092,7 +1093,7 @@ void View::on_state_changed(bool stop) QRect View::get_view_rect() { if (_session->get_device()->dev_inst()->mode == DSO) { - const vector< boost::shared_ptr > sigs(_session->get_signals()); + const auto &sigs = _session->get_signals(); for(auto &s : sigs) { return s->get_view_rect(); } @@ -1105,7 +1106,7 @@ int View::get_view_width() { int view_width = 0; if (_session->get_device()->dev_inst()->mode == DSO) { - const vector< boost::shared_ptr > sigs(_session->get_signals()); + const auto &sigs = _session->get_signals(); for(auto &s : sigs) { view_width = max(view_width, s->get_view_rect().width()); } @@ -1120,7 +1121,7 @@ int View::get_view_height() { int view_height = 0; if (_session->get_device()->dev_inst()->mode == DSO) { - const vector< boost::shared_ptr > sigs(_session->get_signals()); + const auto &sigs = _session->get_signals(); for(auto &s : sigs) { view_height = max(view_height, s->get_view_rect().height()); } @@ -1162,7 +1163,7 @@ void View::vDial_updated() if (_cali->isVisible()) { _cali->set_device(_session->get_device()); } - boost::shared_ptr math_trace = _session->get_math_trace(); + auto math_trace = _session->get_math_trace(); if (math_trace && math_trace->enabled()) { math_trace->update_vDial(); } @@ -1183,7 +1184,7 @@ void View::show_region(uint64_t start, uint64_t end, bool keep) update(); } else if (_session->get_map_zoom() == 0) { const double ideal_scale = (end-start) * 2.0 / _session->cur_snap_samplerate() / get_view_width(); - const double new_scale = max(min(ideal_scale, _maxscale), _minscale); + const double new_scale = max (min(ideal_scale, _maxscale), _minscale); const double new_off = (start + end) * 0.5 / (_session->cur_snap_samplerate() * new_scale) - (get_view_width() / 2); set_scale_offset(new_scale, new_off); } else { @@ -1254,7 +1255,7 @@ void View::set_capture_status() } } -bool View::get_dso_trig_moved() const +bool View::get_dso_trig_moved() { return _time_viewport->get_dso_trig_moved(); } @@ -1298,7 +1299,7 @@ ViewStatus* View::get_viewstatus() return _viewbottom; } -bool View::back_ready() const +bool View::back_ready() { return _back_ready; } diff --git a/DSView/pv/view/view.h b/DSView/pv/view/view.h index 306653d2..f5e8ea10 100755 --- a/DSView/pv/view/view.h +++ b/DSView/pv/view/view.h @@ -27,10 +27,7 @@ #include #include #include - -#include -#include - + #include #include #include @@ -112,18 +109,18 @@ public: /** * Returns the view time scale in seconds per pixel. */ - double scale() const; + double scale(); /** * Returns the pixels offset of the left edge of the view */ - int64_t offset() const; - int v_offset() const; + int64_t offset(); + int v_offset(); /** * trigger position fix */ - double trig_hoff() const; + double trig_hoff(); void set_trig_hoff(double hoff); int64_t get_min_offset(); @@ -142,14 +139,14 @@ public: void set_scale_offset(double scale, int64_t offset); void set_preScale_preOffset(); - std::vector< boost::shared_ptr > get_traces(int type); + std::vector get_traces(int type); /** * Returns true if cursors are displayed. false otherwise. */ - bool cursors_shown() const; - bool trig_cursor_shown() const; - bool search_cursor_shown() const; + bool cursors_shown(); + bool trig_cursor_shown(); + bool search_cursor_shown(); int get_spanY(); @@ -164,7 +161,7 @@ public: */ void show_cursors(bool show = true); - const QPoint& hover_point() const; + const QPoint& hover_point(); void normalize_layout(); @@ -200,8 +197,8 @@ public: /* * */ - double get_minscale() const; - double get_maxscale() const; + double get_minscale(); + double get_maxscale(); void set_update(Viewport *viewport, bool need_update); void set_all_update(bool need_update); @@ -225,14 +222,14 @@ public: void set_capture_status(); - bool get_dso_trig_moved() const; + bool get_dso_trig_moved(); ViewStatus* get_viewstatus(); /* * back paint status */ - bool back_ready() const; + bool back_ready(); void set_back(bool ready); /* @@ -261,15 +258,15 @@ signals: void auto_trig(int index); private: - void get_scroll_layout(int64_t &length, int64_t &offset) const; + void get_scroll_layout(int64_t &length, int64_t &offset); void update_scroll(); void update_margins(); static bool compare_trace_v_offsets( - const boost::shared_ptr &a, - const boost::shared_ptr &b); + const pv::view::Trace *a, + const pv::view::Trace *b); void clear(); void reconstruct(); diff --git a/DSView/pv/view/viewport.cpp b/DSView/pv/view/viewport.cpp index 5c548e63..95a2ff46 100755 --- a/DSView/pv/view/viewport.cpp +++ b/DSView/pv/view/viewport.cpp @@ -40,8 +40,8 @@ #include #include - #include "../config/appconfig.h" +#include "../dsvdef.h" using namespace boost; using namespace std; @@ -107,11 +107,11 @@ Viewport::Viewport(View &parent, View_type type) : connect(this, SIGNAL(customContextMenuRequested(const QPoint&)),this, SLOT(show_contextmenu(const QPoint&))); } -int Viewport::get_total_height() const +int Viewport::get_total_height() { int h = 0; - const vector< boost::shared_ptr > traces(_view.get_traces(_type)); + const auto &traces = _view.get_traces(_type); for(auto &t : traces) { assert(t); h += (int)(t->get_totalHeight()); @@ -121,7 +121,7 @@ int Viewport::get_total_height() const return h; } -QPoint Viewport::get_mouse_point() const +QPoint Viewport::get_mouse_point() { return _mouse_point; } @@ -149,7 +149,8 @@ void Viewport::paintEvent(QPaintEvent *event) QColor back(QWidget::palette().color(QWidget::backgroundRole())); fore.setAlpha(View::ForeAlpha); _view.set_back(false); - const vector< boost::shared_ptr > traces(_view.get_traces(_type)); + + const auto &traces = _view.get_traces(_type); for(auto &t : traces) { @@ -202,15 +203,13 @@ void Viewport::paintEvent(QPaintEvent *event) void Viewport::paintSignals(QPainter &p, QColor fore, QColor back) { - const vector< boost::shared_ptr > traces(_view.get_traces(_type)); + const auto &traces = _view.get_traces(_type); + if (_view.session().get_device()->dev_inst()->mode == LOGIC) { for(auto &t : traces) { - assert(t); - // auto ptr = t.get(); - // ptr->paint_mid(p, 0, t->get_view_rect().right(), fore, back); - // continue; + assert(t); if (t->enabled()) t->paint_mid(p, 0, t->get_view_rect().right(), fore, back); @@ -253,7 +252,7 @@ void Viewport::paintSignals(QPainter &p, QColor fore, QColor back) //const QRect xrect = QRect(rect().left(), rect().top(), _view.get_view_width(), rect().height()); const QRect xrect = _view.get_view_rect(); if (_view.cursors_shown() && _type == TIME_VIEW) { - list::iterator i = _view.get_cursorList().begin(); + auto i = _view.get_cursorList().begin(); int index = 0; while (i != _view.get_cursorList().end()) { const int64_t cursorX = _view.index2pixel((*i)->index()); @@ -268,7 +267,7 @@ void Viewport::paintSignals(QPainter &p, QColor fore, QColor back) } if (_view.xcursors_shown() && _type == TIME_VIEW) { - list::iterator i = _view.get_xcursorList().begin(); + auto i = _view.get_xcursorList().begin(); int index = 0; bool hovered = false; while (i != _view.get_xcursorList().end()) { @@ -521,14 +520,15 @@ void Viewport::mousePressEvent(QMouseEvent *event) if (_action_type == NO_ACTION && event->button() == Qt::LeftButton && _view.session().get_device()->dev_inst()->mode == DSO) { - const vector< boost::shared_ptr > sigs(_view.session().get_signals()); + + const auto &sigs = _view.session().get_signals(); for(auto &s : sigs) { assert(s); if (!s->enabled()) continue; - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(s))) { + DsoSignal *dsoSig = NULL; + if ((dsoSig = dynamic_cast(s))) { if (dsoSig->get_trig_rect(0, _view.get_view_width()).contains(_mouse_point)) { _drag_sig = s; _action_type = DSO_TRIG_MOVE; @@ -551,7 +551,7 @@ void Viewport::mousePressEvent(QMouseEvent *event) } } if (_action_type == NO_ACTION && _view.cursors_shown()) { - list::iterator i = _view.get_cursorList().begin(); + auto i = _view.get_cursorList().begin(); while (i != _view.get_cursorList().end()) { const int64_t cursorX = _view.index2pixel((*i)->index()); if ((*i)->grabbed()) { @@ -565,7 +565,7 @@ void Viewport::mousePressEvent(QMouseEvent *event) } } if (_action_type == NO_ACTION && _view.xcursors_shown()) { - list::iterator i = _view.get_xcursorList().begin(); + auto i = _view.get_xcursorList().begin(); const QRect xrect = _view.get_view_rect(); while (i != _view.get_xcursorList().end()) { const double cursorX = xrect.left() + (*i)->value(XCursor::XCur_Y)*xrect.width(); @@ -577,13 +577,13 @@ void Viewport::mousePressEvent(QMouseEvent *event) _view.show_xcursors(false); break; } else if ((*i)->get_map_rect(xrect).contains(_view.hover_point())) { - vector< boost::shared_ptr > sigs(_view.session().get_signals()); - vector< boost::shared_ptr >::iterator s = sigs.begin(); + auto &sigs = _view.session().get_signals(); + auto s = sigs.begin(); bool sig_looped = ((*i)->channel() == NULL); bool no_dsoSig = true; while (1) { - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(*s)) && + view::DsoSignal *dsoSig = NULL; + if ((dsoSig = dynamic_cast(*s)) && dsoSig->enabled()) { no_dsoSig = false; if (sig_looped) { @@ -656,8 +656,8 @@ void Viewport::mouseMoveEvent(QMouseEvent *event) !(event->buttons() | Qt::NoButton)) { if (_action_type == DSO_TRIG_MOVE) { if (_drag_sig) { - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(_drag_sig))) { + view::DsoSignal *dsoSig = NULL; + if ((dsoSig = dynamic_cast(_drag_sig))) { dsoSig->set_trig_vpos(event->pos().y()); _dso_trig_moved = true; } @@ -669,21 +669,21 @@ void Viewport::mouseMoveEvent(QMouseEvent *event) int curX = _view.hover_point().x(); uint64_t index0 = 0, index1 = 0, index2 = 0; bool logic = false; - const vector< boost::shared_ptr > sigs(_view.session().get_signals()); + const auto &sigs = _view.session().get_signals(); for(auto &s: sigs) { assert(s); - boost::shared_ptr logicSig; - boost::shared_ptr dsoSig; + view::LogicSignal *logicSig = NULL; + view::DsoSignal *dsoSig = NULL; if ((_view.session().get_device()->dev_inst()->mode == LOGIC) && - (logicSig = dynamic_pointer_cast(s))) { + (logicSig = dynamic_cast(s))) { if (logicSig->measure(event->pos(), index0, index1, index2)) { logic = true; break; } } if ((_view.session().get_device()->dev_inst()->mode == DSO) && - (dsoSig = dynamic_pointer_cast(s))) { + (dsoSig = dynamic_cast(s))) { curX = min(dsoSig->get_view_rect().right(), curX); break; } @@ -712,7 +712,7 @@ void Viewport::mouseMoveEvent(QMouseEvent *event) _curs_moved = true; } else { if (_view.xcursors_shown()) { - list::iterator i = _view.get_xcursorList().begin(); + auto i = _view.get_xcursorList().begin(); const QRect xrect = _view.get_view_rect(); while (i != _view.get_xcursorList().end()) { if ((*i)->grabbed() != XCursor::XCur_None) { @@ -787,12 +787,12 @@ void Viewport::mouseReleaseEvent(QMouseEvent *event) // priority 2 if (_action_type == NO_ACTION) { if (_mouse_down_point.x() == event->pos().x()) { - const vector< boost::shared_ptr > sigs(_view.session().get_signals()); + const auto &sigs = _view.session().get_signals(); for(auto &s : sigs) { assert(s); - boost::shared_ptr logicSig; - if ((logicSig = dynamic_pointer_cast(s))) { + view::LogicSignal *logicSig = NULL; + if ((logicSig = dynamic_cast(s))) { if (logicSig->edge(event->pos(), _edge_start, 10)) { _action_type = LOGIC_JUMP; _cur_preX = _view.index2pixel(_edge_start); @@ -811,7 +811,7 @@ void Viewport::mouseReleaseEvent(QMouseEvent *event) // priority 3 if (_action_type == NO_ACTION) { if (_mouse_down_point.x() == event->pos().x()) { - const vector< boost::shared_ptr > sigs(_view.session().get_signals()); + const auto &sigs = _view.session().get_signals(); for(auto &s : sigs) { assert(s); @@ -844,15 +844,17 @@ void Viewport::mouseReleaseEvent(QMouseEvent *event) } } else if (_action_type == DSO_TRIG_MOVE) { if (_dso_trig_moved && event->button() == Qt::LeftButton) { - _drag_sig.reset(); + _drag_sig = NULL; _action_type = NO_ACTION; _dso_trig_moved = false; - const vector< boost::shared_ptr > traces( - _view.get_traces(ALL_VIEW)); - for(auto &t : traces) - t->select(false); + const auto &traces = _view.get_traces(ALL_VIEW); + + for(auto &t : traces){ + t->select(false); + } } + } else if (_action_type == DSO_XM_STEP0) { if (event->button() == Qt::LeftButton) { _action_type = DSO_XM_STEP1; @@ -895,7 +897,7 @@ void Viewport::mouseReleaseEvent(QMouseEvent *event) } if (_xcurs_moved && event->button() == Qt::LeftButton) { _action_type = NO_ACTION; - list::iterator i = _view.get_xcursorList().begin(); + auto i = _view.get_xcursorList().begin(); while (i != _view.get_xcursorList().end()) { (*i)->rel_grabbed(); i++; @@ -966,11 +968,11 @@ void Viewport::mouseDoubleClickEvent(QMouseEvent *event) uint64_t index; uint64_t index0 = 0, index1 = 0, index2 = 0; if (_view.session().get_device()->dev_inst()->mode == LOGIC) { - const vector< boost::shared_ptr > sigs(_view.session().get_signals()); + const auto &sigs = _view.session().get_signals(); for(auto &s : sigs) { assert(s); - boost::shared_ptr logicSig; - if ((logicSig = dynamic_pointer_cast(s))) { + view::LogicSignal *logicSig = NULL; + if ((logicSig = dynamic_cast(s))) { if (logicSig->measure(event->pos(), index0, index1, index2)) { logic = true; break; @@ -1066,11 +1068,11 @@ void Viewport::wheelEvent(QWheelEvent *event) } } - const vector< boost::shared_ptr > sigs(_view.session().get_signals()); + const auto &sigs = _view.session().get_signals(); for(auto &s : sigs) { assert(s); - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(s))) { + view::DsoSignal *dsoSig = NULL; + if ((dsoSig = dynamic_cast(s))) { dsoSig->auto_end(); } } @@ -1174,14 +1176,15 @@ void Viewport::measure() _measure_type = NO_MEASURE; if (_type == TIME_VIEW) { const uint64_t sample_rate = _view.session().cur_snap_samplerate(); - const vector< boost::shared_ptr > sigs(_view.session().get_signals()); + const auto &sigs = _view.session().get_signals(); for(auto &s : sigs) { assert(s); - boost::shared_ptr logicSig; - boost::shared_ptr dsoSig; - boost::shared_ptr analogSig; - if ((logicSig = dynamic_pointer_cast(s))) { + view::LogicSignal *logicSig = NULL; + view::DsoSignal *dsoSig = NULL; + view::AnalogSignal *analogSig = NULL; + + if ((logicSig = dynamic_cast(s))) { if (_action_type == NO_ACTION) { if (logicSig->measure(_mouse_point, _cur_sample, _nxt_sample, _thd_sample)) { _measure_type = LOGIC_FREQ; @@ -1231,7 +1234,7 @@ void Viewport::measure() _edge_hit = false; } } - } else if ((dsoSig = dynamic_pointer_cast(s))) { + } else if ((dsoSig = dynamic_cast(s))) { if (dsoSig->enabled()) { if (_measure_en && dsoSig->measure(_view.hover_point())) { _measure_type = DSO_VALUE; @@ -1239,7 +1242,7 @@ void Viewport::measure() _measure_type = NO_MEASURE; } } - } else if ((analogSig = dynamic_pointer_cast(s))) { + } else if ((analogSig = dynamic_cast(s))) { if (analogSig->enabled()) { if (_measure_en && analogSig->measure(_view.hover_point())) { _measure_type = DSO_VALUE; @@ -1249,7 +1252,7 @@ void Viewport::measure() } } } - const boost::shared_ptr mathTrace(_view.session().get_math_trace()); + const auto mathTrace = _view.session().get_math_trace(); if (mathTrace && mathTrace->enabled()) { if (_measure_en && mathTrace->measure(_view.hover_point())) { _measure_type = DSO_VALUE; @@ -1329,14 +1332,15 @@ void Viewport::paintMeasure(QPainter &p, QColor fore, QColor back) } } - const vector< boost::shared_ptr > sigs(_view.session().get_signals()); + const auto &sigs = _view.session().get_signals(); if (_action_type == NO_ACTION && _measure_type == DSO_VALUE) { for(auto &s : sigs) { - boost::shared_ptr dsoSig; - boost::shared_ptr analogSig; - if ((dsoSig = dynamic_pointer_cast(s))) { + view::DsoSignal *dsoSig = NULL; + view::AnalogSignal* analogSig = NULL; + + if ((dsoSig = dynamic_cast(s))) { uint64_t index; double value; QPointF hpoint; @@ -1346,7 +1350,7 @@ void Viewport::paintMeasure(QPainter &p, QColor fore, QColor back) p.drawLine(hpoint.x(), dsoSig->get_view_rect().top(), hpoint.x(), dsoSig->get_view_rect().bottom()); } - } else if ((analogSig = dynamic_pointer_cast(s))) { + } else if ((analogSig = dynamic_cast(s))) { uint64_t index; double value; QPointF hpoint; @@ -1362,8 +1366,8 @@ void Viewport::paintMeasure(QPainter &p, QColor fore, QColor back) if (_dso_ym_valid) { for(auto &s : sigs) { - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(s))) { + view::DsoSignal *dsoSig = NULL; + if ((dsoSig = dynamic_cast(s))) { if (dsoSig->get_index() == _dso_ym_sig_index) { p.setPen(QPen(dsoSig->get_colour(), 1, Qt::DotLine)); const int text_height = p.boundingRect(0, 0, INT_MAX, INT_MAX, @@ -1670,7 +1674,7 @@ void Viewport::unshow_wait_trigger() update(); } -bool Viewport::get_dso_trig_moved() const +bool Viewport::get_dso_trig_moved() { return _dso_trig_moved; } diff --git a/DSView/pv/view/viewport.h b/DSView/pv/view/viewport.h index c1d298f1..18b4dc4d 100755 --- a/DSView/pv/view/viewport.h +++ b/DSView/pv/view/viewport.h @@ -25,10 +25,7 @@ #define DSVIEW_PV_VIEW_VIEWPORT_H #include - -#include -#include - + #include #include #include @@ -92,9 +89,9 @@ public: public: explicit Viewport(View &parent, View_type type); - int get_total_height() const; + int get_total_height(); - QPoint get_mouse_point() const; + QPoint get_mouse_point(); QString get_measure(QString option); @@ -109,7 +106,7 @@ public: void set_need_update(bool update); - bool get_dso_trig_moved() const; + bool get_dso_trig_moved(); protected: bool event(QEvent *event) override; @@ -198,7 +195,7 @@ private: bool transfer_started; int timer_cnt; - boost::shared_ptr _drag_sig; + Signal *_drag_sig; uint64_t _hover_index; bool _hover_hit; diff --git a/DSView/pv/view/viewstatus.cpp b/DSView/pv/view/viewstatus.cpp index 27345f84..3a1cf19f 100755 --- a/DSView/pv/view/viewstatus.cpp +++ b/DSView/pv/view/viewstatus.cpp @@ -74,14 +74,14 @@ void ViewStatus::paintEvent(QPaintEvent *) fore.setAlpha(View::BackAlpha); for(size_t i = 0; i < _mrects.size(); i++) { int sig_index = std::get<1>(_mrects[i]); - boost::shared_ptr dsoSig = NULL; - const vector< boost::shared_ptr > sigs(_session->get_signals()); + view::DsoSignal *dsoSig = NULL; + const auto &sigs = _session->get_signals(); for(auto &s : sigs) { assert(s); if (!s->enabled()) continue; - if ((dsoSig = dynamic_pointer_cast(s))) { + if ((dsoSig = dynamic_cast(s))) { if (sig_index == dsoSig->get_index()) break; else diff --git a/DSView/pv/view/viewstatus.h b/DSView/pv/view/viewstatus.h index 29bd473e..c8edf813 100755 --- a/DSView/pv/view/viewstatus.h +++ b/DSView/pv/view/viewstatus.h @@ -27,9 +27,7 @@ #include #include #include - -#include #include diff --git a/DSView/pv/view/xcursor.cpp b/DSView/pv/view/xcursor.cpp index eeecf6aa..decdc14c 100755 --- a/DSView/pv/view/xcursor.cpp +++ b/DSView/pv/view/xcursor.cpp @@ -46,11 +46,11 @@ XCursor::XCursor(View &view, QColor &colour, _colour(colour) { _dsoSig = NULL; - const std::vector< boost::shared_ptr > sigs(_view.session().get_signals()); + const auto &sigs = _view.session().get_signals(); for(auto &s : sigs) { - boost::shared_ptr dsoSig; - if ((dsoSig = dynamic_pointer_cast(s))) + DsoSignal *dsoSig = NULL; + if ((dsoSig = dynamic_cast(s))) if (dsoSig->enabled()) { _dsoSig = dsoSig; break; @@ -70,7 +70,7 @@ XCursor::XCursor(const XCursor &x) : { } -QColor XCursor::colour() const +QColor XCursor::colour() { return _colour; } @@ -83,16 +83,16 @@ void XCursor::set_colour(QColor color) /** * Gets/Sets the mapping channel of the marker */ -boost::shared_ptr XCursor::channel() const +DsoSignal* XCursor::channel() { return _dsoSig; } -void XCursor::set_channel(boost::shared_ptr sig) +void XCursor::set_channel(DsoSignal *sig) { _dsoSig = sig; } -enum XCursor::XCur_type XCursor::grabbed() const +enum XCursor::XCur_type XCursor::grabbed() { return _grabbed; } @@ -108,7 +108,7 @@ void XCursor::rel_grabbed() _grabbed = XCur_None; } -double XCursor::value(XCur_type type) const +double XCursor::value(XCur_type type) { if (type == XCur_Y) return _yvalue; @@ -182,7 +182,7 @@ void XCursor::paint(QPainter &p, const QRect &rect, XCur_type highlight, int or * @param rect The rectangle of the xcursor area. * @return Returns the map label rectangle. */ -QRect XCursor::get_map_rect(const QRect &rect) const +QRect XCursor::get_map_rect(const QRect &rect) { const int width = 10; const int64_t y = rect.top() + _value0 * rect.height() - width/2; @@ -194,7 +194,7 @@ QRect XCursor::get_map_rect(const QRect &rect) const * @param rect The rectangle of the xcursor area. * @return Returns the close label rectangle. */ -QRect XCursor::get_close_rect(const QRect &rect) const +QRect XCursor::get_close_rect(const QRect &rect) { const int width = 10; const int64_t y = rect.top() + _value1 * rect.height() - width/2; diff --git a/DSView/pv/view/xcursor.h b/DSView/pv/view/xcursor.h index e64d80b8..7a95bf1c 100755 --- a/DSView/pv/view/xcursor.h +++ b/DSView/pv/view/xcursor.h @@ -26,10 +26,7 @@ #include #include #include - -#include -#include - + #include class QPainter; @@ -74,25 +71,25 @@ public: /** * Gets/Set the value of the marker. */ - double value(enum XCur_type type) const; + double value(enum XCur_type type); void set_value(enum XCur_type type, double value); /** * Gets/Sets colour of the marker */ - QColor colour() const; + QColor colour(); void set_colour(QColor color); /** * Gets/Sets the mapping channel of the marker */ - boost::shared_ptr channel() const; - void set_channel(boost::shared_ptr sig); + DsoSignal* channel(); + void set_channel(DsoSignal *sig); /** * grab & move */ - enum XCur_type grabbed() const; + enum XCur_type grabbed(); void set_grabbed(enum XCur_type type, bool grabbed); void rel_grabbed(); @@ -108,14 +105,14 @@ public: * @param rect The rectangle of the xcursor area. * @return Returns the map label rectangle. */ - QRect get_map_rect(const QRect &rect) const; + QRect get_map_rect(const QRect &rect); /** * Gets the close label rectangle. * @param rect The rectangle of the xcursor area. * @return Returns the close label rectangle. */ - QRect get_close_rect(const QRect &rect) const; + QRect get_close_rect(const QRect &rect); /** * Paints the labels to the xcursor. @@ -128,8 +125,8 @@ signals: void value_changed(); protected: - View &_view; - boost::shared_ptr _dsoSig; + View &_view; + DsoSignal *_dsoSig; double _yvalue; double _value0; diff --git a/DSView/pv/widgets/decodergroupbox.cpp b/DSView/pv/widgets/decodergroupbox.cpp index 2da50f7b..82a809b5 100755 --- a/DSView/pv/widgets/decodergroupbox.cpp +++ b/DSView/pv/widgets/decodergroupbox.cpp @@ -41,8 +41,8 @@ namespace pv { namespace widgets { -DecoderGroupBox::DecoderGroupBox(boost::shared_ptr &decoder_stack, - boost::shared_ptr &dec, +DecoderGroupBox::DecoderGroupBox(data::DecoderStack *decoder_stack, + data::decode::Decoder *dec, QLayout *dec_layout, QWidget *parent) : QScrollArea(parent), diff --git a/DSView/pv/widgets/decodergroupbox.h b/DSView/pv/widgets/decodergroupbox.h index 61f5599b..96812532 100755 --- a/DSView/pv/widgets/decodergroupbox.h +++ b/DSView/pv/widgets/decodergroupbox.h @@ -26,8 +26,7 @@ #include #include #include -#include -#include +#include namespace pv { @@ -45,8 +44,8 @@ class DecoderGroupBox : public QScrollArea Q_OBJECT public: - DecoderGroupBox(boost::shared_ptr &decoder_stack, - boost::shared_ptr &dec, QLayout *dec_layout, + DecoderGroupBox(pv::data::DecoderStack *decoder_stack, + data::decode::Decoder *dec, QLayout *dec_layout, QWidget *parent = NULL); ~DecoderGroupBox(); bool eventFilter(QObject *o, QEvent *e); @@ -54,7 +53,7 @@ public: signals: void show_hide_decoder(); void show_hide_row(); - void del_stack(boost::shared_ptr &_dec); + void del_stack(data::decode::Decoder *_dec); private slots: void tog_icon(); @@ -63,8 +62,8 @@ private slots: private: QWidget *_widget; - boost::shared_ptr &_decoder_stack; - boost::shared_ptr &_dec; + pv::data::DecoderStack *_decoder_stack; + data::decode::Decoder *_dec; int _index; QGridLayout *_layout; From 0e4f0ae52e847bc7e6d6305556ab8d00dd1d4ef8 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Mon, 8 Nov 2021 19:56:35 +0800 Subject: [PATCH 21/60] decode task save stop anddestory --- DSView/main.cpp | 2 + DSView/pv/appcontrol.cpp | 9 +- DSView/pv/appcontrol.h | 2 + DSView/pv/data/decode/decoder.cpp | 19 +- DSView/pv/data/decode/decoder.h | 24 +- DSView/pv/data/decode/rowdata.cpp | 8 +- DSView/pv/data/decoderstack.cpp | 152 +++++----- DSView/pv/data/decoderstack.h | 57 ++-- DSView/pv/data/dsosnapshot.cpp | 4 +- DSView/pv/data/snapshot.cpp | 25 +- DSView/pv/data/snapshot.h | 6 + DSView/pv/device/devinst.cpp | 5 + DSView/pv/device/devinst.h | 2 + DSView/pv/device/file.cpp | 2 +- DSView/pv/dock/dsotriggerdock.cpp | 12 +- DSView/pv/dock/protocoldock.cpp | 9 +- DSView/pv/mainwindow.cpp | 32 +- DSView/pv/mainwindow.h | 2 +- DSView/pv/sigsession.cpp | 466 +++++++++++++++++++---------- DSView/pv/sigsession.h | 209 +++++++++---- DSView/pv/storesession.cpp | 53 ++-- DSView/pv/storesession.h | 2 +- DSView/pv/view/decodetrace.cpp | 144 ++++----- DSView/pv/view/decodetrace.h | 14 +- DSView/pv/view/view.cpp | 66 ++-- DSView/pv/view/viewstatus.cpp | 2 +- libsigrok4DSL/hardware/demo/demo.h | 2 +- libsigrok4DSL/session.c | 15 +- 28 files changed, 810 insertions(+), 535 deletions(-) diff --git a/DSView/main.cpp b/DSView/main.cpp index 862befdf..c0a15a47 100755 --- a/DSView/main.cpp +++ b/DSView/main.cpp @@ -183,6 +183,8 @@ int main(int argc, char *argv[]) //Run the application ret = a.exec(); + + control->Stop(); } catch (const std::exception &e) { diff --git a/DSView/pv/appcontrol.cpp b/DSView/pv/appcontrol.cpp index 6fa5f704..dff58bc7 100644 --- a/DSView/pv/appcontrol.cpp +++ b/DSView/pv/appcontrol.cpp @@ -95,11 +95,14 @@ bool AppControl::Start() return true; } -void AppControl::UnInit() -{ + void AppControl::Stop() + { _session->Close(); _device_manager->UnInitAll(); - + } + +void AppControl::UnInit() +{ // Destroy libsigrokdecode srd_exit(); diff --git a/DSView/pv/appcontrol.h b/DSView/pv/appcontrol.h index ff2742b5..8e0e1ac0 100644 --- a/DSView/pv/appcontrol.h +++ b/DSView/pv/appcontrol.h @@ -48,6 +48,8 @@ public: bool Start(); + void Stop(); + void UnInit(); const char* GetLastError(); diff --git a/DSView/pv/data/decode/decoder.cpp b/DSView/pv/data/decode/decoder.cpp index a9e4c66e..4c2e80f0 100755 --- a/DSView/pv/data/decode/decoder.cpp +++ b/DSView/pv/data/decode/decoder.cpp @@ -29,11 +29,15 @@ namespace pv { namespace data { namespace decode { -Decoder::Decoder(const srd_decoder *const dec) : - _decoder(dec), - _shown(true), - _setted(true) +Decoder::Decoder(const srd_decoder *const dec): + _decoder(dec) { + _shown = true; + _setted = true; + _decode_start = 0; + _decode_end = 0; + _decode_start_back = 0; + _decode_end_back = 0; } Decoder::~Decoder() @@ -65,9 +69,10 @@ void Decoder::set_decode_region(uint64_t start, uint64_t end) { _decode_start_back = start; _decode_end_back = end; - if (_decode_start != start || - _decode_end != end) - _setted = true; + + if (_decode_start != start || _decode_end != end){ + _setted = true; + } } //apply setting diff --git a/DSView/pv/data/decode/decoder.h b/DSView/pv/data/decode/decoder.h index 3d723bdb..1f737f90 100755 --- a/DSView/pv/data/decode/decoder.h +++ b/DSView/pv/data/decode/decoder.h @@ -44,6 +44,8 @@ class Decoder public: Decoder(const srd_decoder *const decoder); +public: + virtual ~Decoder(); inline const srd_decoder* decoder(){ @@ -92,19 +94,19 @@ public: private: const srd_decoder *const _decoder; + + std::map _probes; + std::map _options; + std::map _probes_back; + std::map _options_back; - bool _shown; + uint64_t _decode_start; + uint64_t _decode_end; + uint64_t _decode_start_back; + uint64_t _decode_end_back; - std::map _probes; - std::map _options; - - std::map _probes_back; - std::map _options_back; - - uint64_t _decode_start, _decode_end; - uint64_t _decode_start_back, _decode_end_back; - - bool _setted; + bool _setted; + bool _shown; }; } // namespace decode diff --git a/DSView/pv/data/decode/rowdata.cpp b/DSView/pv/data/decode/rowdata.cpp index e8ac9278..7dbe30a3 100755 --- a/DSView/pv/data/decode/rowdata.cpp +++ b/DSView/pv/data/decode/rowdata.cpp @@ -42,7 +42,7 @@ RowData::RowData() : RowData::~RowData() { - clear(); + //stack object can not destory the sources } void RowData::clear() @@ -108,10 +108,8 @@ uint64_t RowData::get_annotation_index(uint64_t start_sample) } bool RowData::push_annotation(Annotation *a) -{ - if (a == NULL){ - return false; - } +{ + assert(a); std::lock_guard lock(_global_visitor_mutex); diff --git a/DSView/pv/data/decoderstack.cpp b/DSView/pv/data/decoderstack.cpp index 09d3dcf4..4aa6a86e 100755 --- a/DSView/pv/data/decoderstack.cpp +++ b/DSView/pv/data/decoderstack.cpp @@ -46,12 +46,9 @@ namespace data { const double DecoderStack::DecodeMargin = 1.0; const double DecoderStack::DecodeThreshold = 0.2; -const int64_t DecoderStack::DecodeChunkLength = 4 * 1024; -//const int64_t DecoderStack::DecodeChunkLength = 1024 * 1024; +const int64_t DecoderStack::DecodeChunkLength = 4 * 1024; const unsigned int DecoderStack::DecodeNotifyPeriod = 1024; - -std::mutex DecoderStack::_global_decode_mutex; - + DecoderStack::DecoderStack(pv::SigSession *session, const srd_decoder *const dec, DecoderStatus *decoder_status) : _session(session) @@ -61,22 +58,17 @@ DecoderStack::DecoderStack(pv::SigSession *session, assert(decoder_status); _samples_decoded = 0; - _sample_count = 0; - _frame_complete = false; + _sample_count = 0; _decode_state = Stopped; _options_changed = false; _no_memory = false; _mark_index = -1; _decoder_status = decoder_status; - _bThreadStop = false; - _decode_thread = NULL; + _stask_stauts = NULL; - connect(_session, SIGNAL(frame_began()), - this, SLOT(on_new_frame())); - connect(_session, SIGNAL(data_received()), - this, SLOT(on_data_received())); - connect(_session, SIGNAL(frame_ended()), - this, SLOT(on_frame_ended())); + connect(_session, SIGNAL(frame_began()), this, SLOT(on_new_frame())); + + connect(_session, SIGNAL(data_received()), this, SLOT(on_data_received())); _stack.push_back(new decode::Decoder(dec)); @@ -84,16 +76,21 @@ DecoderStack::DecoderStack(pv::SigSession *session, } DecoderStack::~DecoderStack() -{ - stop_decode(); - +{ + //release source for (auto &kv : _rows) { + kv.second->clear(); delete kv.second; } _rows.clear(); + //Decoder + for (auto *p : _stack){ + delete p; + } _stack.clear(); + _rows_gshow.clear(); _rows_lshow.clear(); _class_rows.clear(); @@ -117,7 +114,10 @@ void DecoderStack::remove(Decoder *decoder) // Delete the element if (iter != _stack.end()) + { _stack.erase(iter); + delete decoder; + } build_row(); _options_changed = true; @@ -125,7 +125,7 @@ void DecoderStack::remove(Decoder *decoder) void DecoderStack::build_row() { - //destory data + //release source for (auto &kv : _rows) { delete kv.second; @@ -357,8 +357,7 @@ void DecoderStack::clear() void DecoderStack::init() { - _sample_count = 0; - _frame_complete = false; + _sample_count = 0; _samples_decoded = 0; _error_message = QString(); _no_memory = false; @@ -370,30 +369,44 @@ void DecoderStack::init() set_mark_index(-1); } - -void DecoderStack::stop_decode() -{ - _bThreadStop = true; - - if (_decode_thread && _decode_thread->joinable()) { - _decode_thread->join(); + +void DecoderStack::stop_decode_work() +{ + //set the flag to exit from task thread + if (_stask_stauts){ + _stask_stauts->m_bStop = true; } - DESTROY_OBJECT(_decode_thread); - - if(_decode_state != Stopped) { - _decode_state = Stopped; - } + _decode_state = Stopped; } -void DecoderStack::begin_decode() +void DecoderStack::begin_decode_work() { + assert(_decode_state == Stopped); + + _decode_state = Running; + do_decode_work(); + _decode_state = Stopped; +} + +void DecoderStack::do_decode_work() +{ + //set the flag to exit from task thread + if (_stask_stauts){ + _stask_stauts->m_bStop = true; + } + _stask_stauts = new decode_task_status(); + _stask_stauts->m_bStop = false; + pv::view::LogicSignal *logic_signal = NULL; pv::data::Logic *data = NULL; if (!_options_changed) + { + qDebug()<<"data not be ready"; return; + } _options_changed = false; - stop_decode(); + init(); // Check that all decoders have the required channels @@ -427,6 +440,7 @@ void DecoderStack::begin_decode() const auto &snapshots = data->get_snapshots(); if (snapshots.empty()) return; + _snapshot = snapshots.front(); if (_snapshot->empty()) return; @@ -435,15 +449,8 @@ void DecoderStack::begin_decode() _samplerate = data->samplerate(); if (_samplerate == 0.0) return; - - if (_decode_thread && _decode_thread->joinable()) { - _bThreadStop = true; - _decode_thread->join(); - } - DESTROY_OBJECT(_decode_thread); - - _bThreadStop = false; //reset stop flag - _decode_thread = new std::thread(&DecoderStack::decode_proc, this); + + decode_proc(); } uint64_t DecoderStack::get_max_sample_count() @@ -457,10 +464,10 @@ uint64_t DecoderStack::get_max_sample_count() return max_sample_count; } -void DecoderStack::decode_data( - const uint64_t decode_start, const uint64_t decode_end, - srd_session *const session) +void DecoderStack::decode_data(const uint64_t decode_start, const uint64_t decode_end, srd_session *const session) { + decode_task_status *status = _stask_stauts; + //uint8_t *chunk = NULL; uint64_t last_cnt = 0; uint64_t notify_cnt = (decode_end - decode_start + 1)/100; @@ -480,8 +487,16 @@ void DecoderStack::decode_data( uint64_t i = decode_start; char *error = NULL; - while(!_bThreadStop && i < decode_end && !_no_memory) - { + if( i >= decode_end){ + qDebug()<<"decode data index have been end:"<m_bStop){ + break; + } + std::vector chunk; std::vector chunk_const; uint64_t chunk_end = decode_end; @@ -523,21 +538,19 @@ void DecoderStack::decode_data( new_decode_data(); } entry_cnt++; - } + } + if (error) g_free(error); - decode_done(); + + qDebug()<<"decode tack proc end"; + + if (!_session->is_closed()) + decode_done(); } void DecoderStack::decode_proc() -{ - std::lock_guard decode_lock(_global_decode_mutex); - - if (_bThreadStop){ - return; - } - - optional sample_count; +{ srd_session *session; srd_decoder_inst *prev_di = NULL; uint64_t decode_start = 0; @@ -547,12 +560,13 @@ void DecoderStack::decode_proc() // Create the session srd_session_new(&session); + assert(session); - - _decode_state = Running; - + // Get the intial sample count - sample_count = _sample_count = _snapshot->get_sample_count(); + _sample_count = _snapshot->get_sample_count(); + + qDebug()<<"sample count:"<<_sample_count; // Create the decoders for(auto &dec : _stack) @@ -592,9 +606,7 @@ void DecoderStack::decode_proc() if (error) { g_free(error); } - srd_session_destroy(session); - - _decode_state = Stopped; + srd_session_destroy(session); } uint64_t DecoderStack::sample_count() @@ -662,18 +674,16 @@ void DecoderStack::annotation_callback(srd_proto_data *pdata, void *decoder) } void DecoderStack::on_new_frame() -{ - //begin_decode(); +{ } void DecoderStack::on_data_received() { } -void DecoderStack::on_frame_ended() +void DecoderStack::frame_ended() { - _options_changed = true; - begin_decode(); + _options_changed = true; } int DecoderStack::list_rows_size() diff --git a/DSView/pv/data/decoderstack.h b/DSView/pv/data/decoderstack.h index c30455b7..c8a2b929 100755 --- a/DSView/pv/data/decoderstack.h +++ b/DSView/pv/data/decoderstack.h @@ -21,23 +21,24 @@ #ifndef DSVIEW_PV_DATA_DECODERSTACK_H #define DSVIEW_PV_DATA_DECODERSTACK_H + #include - #include - -#include - - +#include #include #include -#include -#include +#include #include "decode/row.h" #include "../data/signaldata.h" class DecoderStatus; +struct decode_task_status +{ + volatile bool m_bStop; +}; + namespace DecoderStackTest { class TwoDecoderStack; } @@ -62,6 +63,7 @@ class RowData; class Logic; + //a torotocol have a DecoderStack, destroy by DecodeTrace class DecoderStack : public QObject, public SignalData { Q_OBJECT @@ -133,14 +135,21 @@ public: QString error_message(); void clear(); + void init(); uint64_t get_max_sample_count(); - void begin_decode(); + inline bool IsRunning(){ + return _decode_state == Running; + } + + void begin_decode_work(); - void stop_decode(); + void do_decode_work(); + void stop_decode_work(); + int list_rows_size(); bool options_changed(); @@ -154,6 +163,8 @@ public: void set_mark_index(int64_t index); int64_t get_mark_index(); + void frame_ended(); + private: void decode_data(const uint64_t decode_start, const uint64_t decode_end, srd_session *const session); @@ -164,14 +175,12 @@ private: private slots: void on_new_frame(); - void on_data_received(); - - void on_frame_ended(); + void on_data_received(); signals: void new_decode_data(); void decode_done(); - + private: std::list _stack; @@ -184,28 +193,18 @@ private: SigSession *_session; decode_state _decode_state; - bool _options_changed; - bool _no_memory; + volatile bool _options_changed; + volatile bool _no_memory; int64_t _mark_index; DecoderStatus *_decoder_status; QString _error_message; int64_t _samples_decoded; - uint64_t _sample_count; - bool _frame_complete; - volatile bool _bThreadStop; + uint64_t _sample_count; + + decode_task_status *_stask_stauts; - - std::thread *_decode_thread; mutable std::mutex _output_mutex; - - /** - * This mutex prevents more than one decode operation occuring - * concurrently. - * @todo A proper solution should be implemented to allow multiple - * decode operations. - */ - static std::mutex _global_decode_mutex; - + friend class DecoderStackTest::TwoDecoderStack; }; diff --git a/DSView/pv/data/dsosnapshot.cpp b/DSView/pv/data/dsosnapshot.cpp index db56da10..a3649f8f 100755 --- a/DSView/pv/data/dsosnapshot.cpp +++ b/DSView/pv/data/dsosnapshot.cpp @@ -200,9 +200,9 @@ const uint8_t *DsoSnapshot::get_samples( (void)end_sample; assert(start_sample >= 0); - assert(start_sample < (int64_t)get_sample_count()); + assert(start_sample < (int64_t)sample_count()); assert(end_sample >= 0); - assert(end_sample < (int64_t)get_sample_count()); + assert(end_sample < (int64_t)sample_count()); assert(start_sample <= end_sample); diff --git a/DSView/pv/data/snapshot.cpp b/DSView/pv/data/snapshot.cpp index 773ea130..bac3cc16 100755 --- a/DSView/pv/data/snapshot.cpp +++ b/DSView/pv/data/snapshot.cpp @@ -92,19 +92,34 @@ uint64_t Snapshot::get_sample_count() std::lock_guard lock(_mutex); return _sample_count; } - + uint64_t Snapshot::get_ring_start() { std::lock_guard lock(_mutex); - if (_sample_count < _total_sample_count) - return 0; - else - return _ring_sample_count; + return ring_start(); } uint64_t Snapshot::get_ring_end() { std::lock_guard lock(_mutex); + return ring_end(); +} + +uint64_t Snapshot::sample_count() +{ + return _sample_count; +} + +uint64_t Snapshot::ring_start() +{ + if (_sample_count < _total_sample_count) + return 0; + else + return _ring_sample_count; +} + +uint64_t Snapshot::ring_end() +{ if (_sample_count == 0) return 0; else if (_ring_sample_count == 0) diff --git a/DSView/pv/data/snapshot.h b/DSView/pv/data/snapshot.h index 79de9589..b3447b89 100755 --- a/DSView/pv/data/snapshot.h +++ b/DSView/pv/data/snapshot.h @@ -64,6 +64,12 @@ public: protected: virtual void free_data(); + uint64_t sample_count(); + + uint64_t ring_start(); + + uint64_t ring_end(); + protected: mutable std::mutex _mutex; diff --git a/DSView/pv/device/devinst.cpp b/DSView/pv/device/devinst.cpp index 124ab2ef..a17b6098 100755 --- a/DSView/pv/device/devinst.cpp +++ b/DSView/pv/device/devinst.cpp @@ -204,6 +204,11 @@ void DevInst::run() sr_session_run(); } +void DevInst::stop() +{ + sr_session_stop(); +} + bool DevInst::is_usable() { return _usable; diff --git a/DSView/pv/device/devinst.h b/DSView/pv/device/devinst.h index 5ad51bf0..83b1a884 100755 --- a/DSView/pv/device/devinst.h +++ b/DSView/pv/device/devinst.h @@ -117,6 +117,8 @@ public: virtual void run(); + virtual void stop(); + virtual void* get_id(); virtual sr_dev_inst* dev_inst() = 0; diff --git a/DSView/pv/device/file.cpp b/DSView/pv/device/file.cpp index 88dd0cb5..c24233e2 100755 --- a/DSView/pv/device/file.cpp +++ b/DSView/pv/device/file.cpp @@ -96,7 +96,7 @@ QJsonArray File::get_decoders() } } - zip_close(archive); + zip_close(archive); } return dec_array; diff --git a/DSView/pv/dock/dsotriggerdock.cpp b/DSView/pv/dock/dsotriggerdock.cpp index 29698f19..03e1a8ee 100755 --- a/DSView/pv/dock/dsotriggerdock.cpp +++ b/DSView/pv/dock/dsotriggerdock.cpp @@ -343,10 +343,12 @@ void DsoTriggerDock::device_change() void DsoTriggerDock::init() { if (_session->get_device()->name().contains("virtual")) { - foreach(QAbstractButton * btn, _source_group->buttons()) + for(QAbstractButton * btn : _source_group->buttons()) btn->setDisabled(true); - foreach(QAbstractButton * btn, _type_group->buttons()) + + for(QAbstractButton * btn : _type_group->buttons()) btn->setDisabled(true); + _holdoff_slider->setDisabled(true); _holdoff_spinBox->setDisabled(true); _holdoff_comboBox->setDisabled(true); @@ -354,10 +356,12 @@ void DsoTriggerDock::init() _channel_comboBox->setDisabled(true); return; } else { - foreach(QAbstractButton * btn, _source_group->buttons()) + for(QAbstractButton * btn : _source_group->buttons()) btn->setDisabled(false); - foreach(QAbstractButton * btn, _type_group->buttons()) + + for(QAbstractButton * btn : _type_group->buttons()) btn->setDisabled(false); + _holdoff_slider->setDisabled(false); _holdoff_spinBox->setDisabled(false); _holdoff_comboBox->setDisabled(false); diff --git a/DSView/pv/dock/protocoldock.cpp b/DSView/pv/dock/protocoldock.cpp index 85150806..04888b4a 100755 --- a/DSView/pv/dock/protocoldock.cpp +++ b/DSView/pv/dock/protocoldock.cpp @@ -319,6 +319,9 @@ void ProtocolDock::add_protocol(bool silent) DecoderStatus *dstatus = new DecoderStatus(); dstatus->m_format = (int)DecoderDataFormat::hex; + int numm= _protocol_items.size(); + numm += 0; + if (_session->add_decoder(decoder, silent, dstatus)) { //crate item layer @@ -360,11 +363,13 @@ void ProtocolDock::del_all_protocol() { if (_protocol_items.size() > 0) { + _session->clear_all_decoder(); + for (auto it = _protocol_items.begin(); it != _protocol_items.end(); it++) { DESTROY_QT_LATER((*it)); //destory control - _session->remove_decode_signal(0); } + _protocol_items.clear(); protocol_updated(); } @@ -772,7 +777,7 @@ void ProtocolDock::OnProtocolDelete(void *handle){ if ((*it) == handle){ DESTROY_QT_LATER(*it); _protocol_items.remove(dex); - _session->remove_decode_signal(dex); + _session->remove_decoder(dex); protocol_updated(); break; } diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index fe69e51d..79b986a4 100755 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -246,7 +246,8 @@ void MainWindow::setup_ui() // update device update_device_list(); - _session->start_hotplug_proc(boost::bind(&MainWindow::session_error, this, + + _session->start_hotplug_work(boost::bind(&MainWindow::session_error, this, QString(tr("Hotplug failed")), _1)); retranslateUi(); @@ -375,13 +376,12 @@ void MainWindow::update_device_list() } - // load decoders + // load decoders StoreSession ss(_session); - ss.load_decoders(_protocol_widget, file_dev->get_decoders()); - + bool bFlag = ss.load_decoders(_protocol_widget, file_dev->get_decoders()); // load session - load_session_json(file_dev->get_session(), true); + load_session_json(file_dev->get_session(), true, !bFlag); // load data const QString errorMessage( @@ -957,7 +957,7 @@ bool MainWindow::on_load_session(QString name) return load_session_json(sessionDoc, false); } -bool MainWindow::load_session_json(QJsonDocument json, bool file_dev) +bool MainWindow::load_session_json(QJsonDocument json, bool file_dev, bool bDecoder) { QJsonObject sessionObj = json.object(); @@ -976,9 +976,9 @@ bool MainWindow::load_session_json(QJsonDocument json, bool file_dev) return false; } - // clear decoders - - if (sdi->mode == LOGIC) { + // clear decoders + if (sdi->mode == LOGIC && !file_dev) + { _protocol_widget->del_all_protocol(); } @@ -1011,7 +1011,8 @@ bool MainWindow::load_session_json(QJsonDocument json, bool file_dev) for (const GSList *l = _session->get_device()->dev_inst()->channels; l; l = l->next) { sr_channel *const probe = (sr_channel*)l->data; assert(probe); - foreach (const QJsonValue &value, sessionObj["channel"].toArray()) { + + for (const QJsonValue &value : sessionObj["channel"].toArray()) { QJsonObject obj = value.toObject(); if ((strcmp(probe->name, g_strdup(obj["name"].toString().toStdString().c_str())) == 0) && (probe->type == obj["type"].toDouble())) { @@ -1031,7 +1032,8 @@ bool MainWindow::load_session_json(QJsonDocument json, bool file_dev) sr_channel *const probe = (sr_channel*)l->data; assert(probe); bool isEnabled = false; - foreach (const QJsonValue &value, sessionObj["channel"].toArray()) { + + for (const QJsonValue &value : sessionObj["channel"].toArray()) { QJsonObject obj = value.toObject(); if ((probe->index == obj["index"].toDouble()) && (probe->type == obj["type"].toDouble())) { @@ -1058,8 +1060,9 @@ bool MainWindow::load_session_json(QJsonDocument json, bool file_dev) // load signal setting if (file_dev && (sdi->mode == DSO)) { + for(auto &s : _session->get_signals()) { - foreach (const QJsonValue &value, sessionObj["channel"].toArray()) { + for (const QJsonValue &value : sessionObj["channel"].toArray()) { QJsonObject obj = value.toObject(); if ((strcmp(s->get_name().toStdString().c_str(), g_strdup(obj["name"].toString().toStdString().c_str())) == 0) && (s->get_type() == obj["type"].toDouble())) { @@ -1078,7 +1081,7 @@ bool MainWindow::load_session_json(QJsonDocument json, bool file_dev) } } else { for(auto &s : _session->get_signals()) { - foreach (const QJsonValue &value, sessionObj["channel"].toArray()) { + for (const QJsonValue &value : sessionObj["channel"].toArray()) { QJsonObject obj = value.toObject(); if ((s->get_index() == obj["index"].toDouble()) && (s->get_type() == obj["type"].toDouble())) { @@ -1123,12 +1126,11 @@ bool MainWindow::load_session_json(QJsonDocument json, bool file_dev) // load decoders - if (sessionObj.contains("decoder")) { + if (bDecoder && sessionObj.contains("decoder")) { StoreSession ss(_session); ss.load_decoders(_protocol_widget, sessionObj["decoder"].toArray()); } - // load measure if (sessionObj.contains("measure")) { _view->get_viewstatus()->load_session(sessionObj["measure"].toArray()); diff --git a/DSView/pv/mainwindow.h b/DSView/pv/mainwindow.h index 7dee5f3a..68f2dd6d 100755 --- a/DSView/pv/mainwindow.h +++ b/DSView/pv/mainwindow.h @@ -96,7 +96,7 @@ private: void session_error(const QString text, const QString info_text); bool eventFilter(QObject *object, QEvent *event); - bool load_session_json(QJsonDocument json, bool file_dev); + bool load_session_json(QJsonDocument json, bool file_dev,bool bDecoder=true); void update_device_list(); diff --git a/DSView/pv/sigsession.cpp b/DSView/pv/sigsession.cpp index b75f55c9..b63d1aa9 100755 --- a/DSView/pv/sigsession.cpp +++ b/DSView/pv/sigsession.cpp @@ -64,6 +64,7 @@ #include #include #include +#include #include "data/decode/decoderstatus.h" @@ -95,12 +96,8 @@ SigSession::SigSession(DeviceManager *device_manager) : _hot_attach = false; _hot_detach = false; _group_cnt = 0; - _bHotplugStop = false; - _hotplug = NULL; - _sampling_thread = NULL; - - - _feed_timer.stop(); + _bHotplugStop = false; + _noData_cnt = 0; _data_lock = false; _data_updated = false; @@ -111,7 +108,9 @@ SigSession::SigSession(DeviceManager *device_manager) : _math_trace = NULL; _saving = false; _dso_feed = false; - _stop_scale = 1; + _stop_scale = 1; + _bDecodeRunning = false; + _bClose = false; // Create snapshots & data containers _cur_logic_snapshot = new data::LogicSnapshot(); @@ -126,13 +125,15 @@ SigSession::SigSession(DeviceManager *device_manager) : _group_data = new data::Group(); _group_cnt = 0; + _feed_timer.stop(); + connect(&_feed_timer, SIGNAL(timeout()), this, SLOT(feed_timeout())); } //SigSession::SigSession(SigSession &o){(void)o;} SigSession::~SigSession() -{ +{ } DevInst* SigSession::get_device() @@ -142,7 +143,11 @@ DevInst* SigSession::get_device() void SigSession::deselect_device() { + for (auto p : _decode_traces){ + delete p; + } _decode_traces.clear(); + _group_traces.clear(); _dev_inst = NULL; } @@ -153,8 +158,7 @@ void SigSession::deselect_device() void SigSession::set_device(DevInst *dev_inst) { // Ensure we are not capturing before setting the device - //stop_capture(); - + assert(dev_inst); if (_dev_inst){ @@ -168,6 +172,9 @@ void SigSession::set_device(DevInst *dev_inst) _dev_inst = dev_inst; + for (auto p : _decode_traces){ + delete p; + } _decode_traces.clear(); _group_traces.clear(); @@ -358,6 +365,7 @@ void SigSession::capture_init() _trigger_flag = false; _trigger_ch = 0; _hw_replied = false; + if (_dev_inst->dev_inst()->mode != LOGIC) _feed_timer.start(FeedInterval); else @@ -418,8 +426,7 @@ void SigSession::container_init() //decoder_model->setDecoderStack(NULL); // DecoderStack for(auto &d : _decode_traces) - { - assert(d); + { d->decoder()->init(); } @@ -427,7 +434,7 @@ void SigSession::container_init() void SigSession::start_capture(bool instant, boost::function error_handler) -{ +{ // Check that a device instance has been selected. if (!_dev_inst) { qDebug() << "No device selected"; @@ -445,6 +452,7 @@ void SigSession::start_capture(bool instant, // stop previous capture stop_capture(); + // reset measure of dso signal for(auto &s : _signals) { @@ -455,10 +463,13 @@ void SigSession::start_capture(bool instant, } // update setting + qDebug()<<"device name:"<<_dev_inst->name(); + if (_dev_inst->name() != "virtual-session") _instant = instant; else _instant = true; + capture_init(); // Check that at least one probe is enabled @@ -477,30 +488,59 @@ void SigSession::start_capture(bool instant, return; } - if (_sampling_thread && _sampling_thread->joinable()){ - _sampling_thread->join(); + if (_sampling_thread.joinable()){ + _sampling_thread.join(); + } + _sampling_thread = std::thread(&SigSession::sample_thread_proc, this, _dev_inst, error_handler); +} + + +void SigSession::sample_thread_proc(DevInst *dev_inst, + boost::function error_handler) +{ + assert(dev_inst); + assert(dev_inst->dev_inst()); + assert(error_handler); + + try { + dev_inst->start(); + } catch(const QString e) { + error_handler(e); + return; } - DESTROY_OBJECT(_sampling_thread); - _sampling_thread = new std::thread(&SigSession::sample_thread_proc, this, _dev_inst, error_handler); + + receive_data(0); + set_capture_state(Running); + + dev_inst->run(); + + set_capture_state(Stopped); + + // Confirm that SR_DF_END was received + assert(_cur_logic_snapshot->last_ended()); + assert(_cur_dso_snapshot->last_ended()); + assert(_cur_analog_snapshot->last_ended()); } void SigSession::stop_capture() { - data_unlock(); + do_stop_capture(); + int dex = 0; + clear_all_decode_task(dex); +} - for (auto i = _decode_traces.begin(); i != _decode_traces.end(); i++) - (*i)->decoder()->stop_decode(); +void SigSession::do_stop_capture() +{ + data_unlock(); - if (get_capture_state() != Running) - return; - - sr_session_stop(); + if (_dev_inst){ + _dev_inst->stop(); + } // Check that sampling stopped - if (_sampling_thread && _sampling_thread->joinable()){ - _sampling_thread->join(); + if (_sampling_thread.joinable()){ + _sampling_thread.join(); } - DESTROY_OBJECT(_sampling_thread); } bool SigSession::get_capture_status(bool &triggered, int &progress) @@ -561,37 +601,10 @@ void SigSession::set_capture_state(capture_state state) data_updated(); capture_state_changed(state); } - -void SigSession::sample_thread_proc(DevInst *dev_inst, - boost::function error_handler) -{ - assert(dev_inst); - assert(dev_inst->dev_inst()); - assert(error_handler); - - try { - dev_inst->start(); - } catch(const QString e) { - error_handler(e); - return; - } - - receive_data(0); - set_capture_state(Running); - - dev_inst->run(); - - set_capture_state(Stopped); - - // Confirm that SR_DF_END was received - assert(_cur_logic_snapshot->last_ended()); - assert(_cur_dso_snapshot->last_ended()); - assert(_cur_analog_snapshot->last_ended()); -} - + void SigSession::check_update() { - std::lock_guard lock(_data_mutex); + ds_lock_guard lock(_data_mutex); if (_capture_state != Running) return; @@ -699,6 +712,9 @@ void SigSession::init_signals() // Clear the decode traces + for (auto p : _decode_traces){ + delete p; + } _decode_traces.clear(); @@ -842,7 +858,7 @@ void SigSession::reload() void SigSession::refresh(int holdtime) { - std::lock_guard lock(_data_mutex); + ds_lock_guard lock(_data_mutex); data_lock(); @@ -850,8 +866,7 @@ void SigSession::refresh(int holdtime) _logic_data->init(); for(auto &d : _decode_traces) - { - assert(d); + { d->decoder()->init(); } @@ -1062,6 +1077,7 @@ void SigSession::feed_in_dso(const sr_datafeed_dso &dso) if (!_instant) data_lock(); + _data_updated = true; } @@ -1103,18 +1119,18 @@ void SigSession::feed_in_analog(const sr_datafeed_analog &analog) //data_updated(); _data_updated = true; } - + void SigSession::data_feed_in(const struct sr_dev_inst *sdi, const struct sr_datafeed_packet *packet) { assert(sdi); assert(packet); - - std::lock_guard lock(_data_mutex); - + + ds_lock_guard lock(_data_mutex); + if (_data_lock && packet->type != SR_DF_END) return; - + if (packet->type != SR_DF_END && packet->status != SR_PKT_OK) { _error = Pkt_data_err; @@ -1162,34 +1178,40 @@ void SigSession::data_feed_in(const struct sr_dev_inst *sdi, break; } case SR_DF_END: - { + { + if (!_cur_logic_snapshot->empty()) { - - if (!_cur_logic_snapshot->empty()) { - for(auto &g : _group_traces) - { - assert(g); + for (auto &g : _group_traces) + { + assert(g); - auto p = new data::GroupSnapshot(_logic_data->get_snapshots().front(), g->get_index_list()); - _group_data->push_snapshot(p); - } + auto p = new data::GroupSnapshot(_logic_data->get_snapshots().front(), g->get_index_list()); + _group_data->push_snapshot(p); } - _cur_logic_snapshot->capture_ended(); - _cur_dso_snapshot->capture_ended(); - _cur_analog_snapshot->capture_ended(); - - for(auto &d : _decode_traces) - d->frame_ended(); - } + _cur_logic_snapshot->capture_ended(); + _cur_dso_snapshot->capture_ended(); + _cur_analog_snapshot->capture_ended(); + + qDebug()<<"data frame end"; + + for (auto trace : _decode_traces){ + trace->decoder()->frame_ended(); + trace->frame_ended(); + add_decode_task(trace); + } if (packet->status != SR_PKT_OK) { _error = Pkt_data_err; session_error(); } + frame_ended(); - if (get_device()->dev_inst()->mode != LOGIC) - set_session_time(QDateTime::currentDateTime()); + + if (get_device()->dev_inst()->mode != LOGIC){ + set_session_time(QDateTime::currentDateTime()); + } + break; } } @@ -1276,7 +1298,7 @@ void SigSession::deregister_hotplug_callback() libusb_hotplug_deregister_callback(NULL, _hotplug_handle); } -void SigSession::start_hotplug_proc(boost::function error_handler) +void SigSession::start_hotplug_work(boost::function error_handler) { // Begin the session @@ -1284,20 +1306,18 @@ void SigSession::start_hotplug_proc(boost::function error_ _hot_attach = false; _hot_detach = false; - if (_hotplug && _hotplug->joinable()){ - _hotplug->join(); - } - DESTROY_OBJECT(_hotplug); - _hotplug = new std::thread(&SigSession::hotplug_proc, this, error_handler); + if (_hotplug_thread.joinable()){ + return; + } + _hotplug_thread = std::thread(&SigSession::hotplug_proc, this, error_handler); } -void SigSession::stop_hotplug_proc() +void SigSession::stop_hotplug_work() { _bHotplugStop = true; - if (_hotplug && _hotplug->joinable()){ - _hotplug->join(); - } - DESTROY_OBJECT(_hotplug); + if (_hotplug_thread.joinable()){ + _hotplug_thread.join(); + } } uint16_t SigSession::get_ch_num(int type) @@ -1337,8 +1357,11 @@ uint16_t SigSession::get_ch_num(int type) return num_channels; } +bool SigSession::add_decoder(srd_decoder *const dec, bool silent, DecoderStatus *dstatus){ + return do_add_decoder(dec, silent, dstatus); +} -bool SigSession::add_decoder(srd_decoder *const dec, bool silent, DecoderStatus *dstatus) +bool SigSession::do_add_decoder(srd_decoder *const dec, bool silent, DecoderStatus *dstatus) { try { @@ -1370,22 +1393,21 @@ bool SigSession::add_decoder(srd_decoder *const dec, bool silent, DecoderStatus break; } } - if (silent) { - _decode_traces.push_back(trace); + if (silent) { ret = true; - } else if (trace->create_popup()) { - _decode_traces.push_back(trace); + } else if (trace->create_popup()) { ret = true; } if (ret) { + _decode_traces.push_back(trace); + add_decode_task(trace); signals_changed(); - // Do an initial decode - decoder_stack->begin_decode(); data_updated(); } - else{ + else + { delete trace; } @@ -1397,71 +1419,46 @@ bool SigSession::add_decoder(srd_decoder *const dec, bool silent, DecoderStatus return false; } - + std::vector& SigSession::get_decode_signals() { return _decode_traces; } -void SigSession::remove_decode_signal(view::DecodeTrace *signal) +void SigSession::remove_decoder(int index) { - for (auto i = _decode_traces.begin(); i != _decode_traces.end(); i++) - if ((*i) == signal) - { - _decode_traces.erase(i); - signals_changed(); - return; - } -} + int size = (int)_decode_traces.size(); + assert(index < size); -void SigSession::remove_decode_signal(int index) -{ - int cur_index = 0; + auto it = _decode_traces.begin() + index; + auto trace = (*it); + _decode_traces.erase(it); - for (auto i = _decode_traces.begin(); i != _decode_traces.end(); i++) - { - if (cur_index == index) - { - auto d = (*i)->decoder(); - d->stop_decode(); //stop decoder thread - _decode_traces.erase(i); - signals_changed(); - return; - } - cur_index++; + bool isRunning = trace->decoder()->IsRunning(); + + remove_decode_task(trace); + + if (isRunning){ + //destroy it in thread + trace->_delete_flag = true; } + else{ + delete trace; + signals_changed(); + } } void SigSession::rst_decoder(int index) { - if (index >= 0 && index < (int)_decode_traces.size()){ - auto p = _decode_traces[index]; - if (p->create_popup()) - { - p->decoder()->stop_decode(); - p->decoder()->begin_decode(); - data_updated(); - } + auto trace = get_decoder_trace(index); + + if (trace && trace->create_popup() ){ + remove_decode_task(trace); //remove old task + add_decode_task(trace); + data_updated(); } } - -void SigSession::rst_decoder(view::DecodeTrace *signal) -{ - for (auto p : _decode_traces) - { - if (p == signal) - { - if (p->create_popup()) - { - p->decoder()->stop_decode(); - p->decoder()->begin_decode(); - data_updated(); - } - break; - } - } -} - + pv::data::DecoderModel* SigSession::get_decoder_model() { return _decoder_model; @@ -1521,7 +1518,8 @@ void SigSession::math_rebuild(bool enable,view::DsoSignal *dsoSig1, view::DsoSignal *dsoSig2, data::MathStack::MathType type) { - std::lock_guard lock(_data_mutex); + ds_lock_guard lock(_data_mutex); + auto math_stack = new data::MathStack(this, dsoSig1, dsoSig2, type); DESTROY_OBJECT(_math_trace); _math_trace = new view::MathTrace(enable, math_stack, dsoSig1, dsoSig2); @@ -1581,7 +1579,7 @@ void SigSession::nodata_timeout() } void SigSession::feed_timeout() -{ +{ data_unlock(); if (!_data_updated) { if (++_noData_cnt >= (WaitShowTime/FeedInterval)) @@ -1783,11 +1781,15 @@ void SigSession::set_stop_scale(float scale) } void SigSession::Close() - { - if (_session == NULL) - return; + { + if (_bClose) + return; + + _bClose = true; - stop_capture(); + do_stop_capture(); //stop capture + + clear_all_decoder(); //clear all decode task, and stop decode thread ds_trigger_destroy(); @@ -1799,12 +1801,158 @@ void SigSession::set_stop_scale(float scale) // TODO: This should not be necessary _session = NULL; + stop_hotplug_work(); + if (_hotplug_handle) - { - stop_hotplug_proc(); + { deregister_hotplug_callback(); _hotplug_handle = 0; } } +//append a decode task, and try create a thread + void SigSession::add_decode_task(view::DecodeTrace *trace) + { + qDebug()<<"add a decode task"; + + std::lock_guard lock(_decode_task_mutex); + _decode_tasks.push_back(trace); + + if (!_bDecodeRunning) + { + if (_decode_thread.joinable()) + _decode_thread.join(); + + _decode_thread = std::thread(&SigSession::decode_task_proc, this); + _bDecodeRunning = true; + } + } + + void SigSession::remove_decode_task(view::DecodeTrace *trace) + { + std::lock_guard lock(_decode_task_mutex); + + for (auto it = _decode_tasks.begin(); it != _decode_tasks.end(); it++){ + if ((*it) == trace){ + (*it)->decoder()->stop_decode_work(); + _decode_tasks.erase(it); + qDebug()<<"remove a wait decode task"; + return; + } + } + + //the task maybe is running + qDebug()<<"remove a running decode task"; + trace->decoder()->stop_decode_work(); + } + + void SigSession::clear_all_decoder() + { + //create the wait task deque + int dex = -1; + clear_all_decode_task(dex); + + view::DecodeTrace *runningTrace = NULL; + if (dex != -1){ + runningTrace = _decode_traces[dex]; + runningTrace->_delete_flag = true; //destroy it in thread + } + + for (auto trace : _decode_traces) + { + if (trace != runningTrace){ + delete trace; + } + } + _decode_traces.clear(); + + //wait thread end + if (_decode_thread.joinable()) + { + qDebug() << "wait the decode thread end"; + _decode_thread.join(); + } + + if (!is_closed()) + signals_changed(); + } + + void SigSession::clear_all_decode_task(int &runningDex) + { + std::lock_guard lock(_decode_task_mutex); + + //remove wait task + for (auto trace : _decode_tasks){ + trace->decoder()->stop_decode_work(); //set decode proc stop flag + } + _decode_tasks.clear(); + + //make sure the running task can stop + runningDex = -1; + int dex = 0; + for (auto trace : _decode_traces) + { + if (trace->IsRunning()) + { + trace->decoder()->stop_decode_work(); + runningDex = dex; + } + dex++; + } + } + + view::DecodeTrace* SigSession::get_decoder_trace(int index) + { + int size = (int)_decode_traces.size(); + assert(index < size); + return _decode_traces[index]; + } + + view::DecodeTrace* SigSession::get_top_decode_task() + { + std::lock_guard lock(_decode_task_mutex); + + auto it = _decode_tasks.begin(); + if (it != _decode_tasks.end()){ + auto p = (*it); + _decode_tasks.erase(it); + return p; + } + + return NULL; + } + + //the decode task thread proc + void SigSession::decode_task_proc(){ + + qDebug()<<"decode thread start"; + auto task = get_top_decode_task(); + + while (task != NULL) + { + qDebug()<<"one decode task be actived"; + + if (!task->_delete_flag){ + task->decoder()->begin_decode_work(); + } + + if (task->_delete_flag){ + qDebug()<<"desroy a decoder in task thread"; + + DESTROY_QT_LATER(task); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + if (!_bClose){ + signals_changed(); + } + } + + task = get_top_decode_task(); + } + + qDebug()<<"decode thread end"; + _bDecodeRunning = false; + } + + + } // namespace pv diff --git a/DSView/pv/sigsession.h b/DSView/pv/sigsession.h index 2ae6c63c..9e1d124e 100755 --- a/DSView/pv/sigsession.h +++ b/DSView/pv/sigsession.h @@ -54,6 +54,8 @@ struct srd_channel; class DecoderStatus; +typedef std::lock_guard ds_lock_guard; + namespace pv { class DeviceManager; @@ -157,22 +159,31 @@ public: capture_state get_capture_state(); uint64_t cur_samplerate(); + uint64_t cur_snap_samplerate(); + uint64_t cur_samplelimits(); + double cur_sampletime(); + double cur_snap_sampletime(); + double cur_view_time(); void set_cur_snap_samplerate(uint64_t samplerate); + void set_cur_samplelimits(uint64_t samplelimits); + void set_session_time(QDateTime time); + QDateTime get_session_time(); + uint64_t get_trigger_pos(); - void start_capture(bool instant, - boost::function error_handler); - void capture_init(); + void start_capture(bool instant, boost::function error_handler); + bool get_capture_status(bool &triggered, int &progress); + void container_init(); std::set get_data(); @@ -183,16 +194,12 @@ public: bool add_decoder(srd_decoder *const dec, bool silent, DecoderStatus *dstatus); + void remove_decoder(int index); + std::vector& get_decode_signals(); - - void remove_decode_signal(view::DecodeTrace *signal); - - void remove_decode_signal(int index); - + void rst_decoder(int index); - - void rst_decoder(view::DecodeTrace *signal); - + pv::data::DecoderModel* get_decoder_model(); std::vector& get_spectrum_traces(); @@ -207,53 +214,78 @@ public: void del_group(); - void start_hotplug_proc(boost::function error_handler); - void stop_hotplug_proc(); - + void start_hotplug_work(boost::function error_handler); + + void stop_hotplug_work(); uint16_t get_ch_num(int type); bool get_instant(); bool get_data_lock(); + void data_auto_lock(int lock); + void data_auto_unlock(); + bool get_data_auto_lock(); + void spectrum_rebuild(); + void lissajous_rebuild(bool enable, int xindex, int yindex, double percent); + void lissajous_disable(); + void math_rebuild(bool enable,pv::view::DsoSignal *dsoSig1, pv::view::DsoSignal *dsoSig2, data::MathStack::MathType type); + void math_disable(); bool trigd(); + uint8_t trigd_ch(); data::Snapshot* get_snapshot(int type); error_state get_error(); + void set_error(error_state state); + void clear_error(); + uint64_t get_error_pattern(); run_mode get_run_mode(); + void set_run_mode(run_mode mode); + int get_repeat_intvl(); + void set_repeat_intvl(int interval); + bool isRepeating(); + bool repeat_check(); + int get_repeat_hold(); int get_map_zoom(); void set_save_start(uint64_t start); + void set_save_end(uint64_t end); + uint64_t get_save_start(); + uint64_t get_save_end(); + bool get_saving(); + void set_saving(bool saving); + void set_stop_scale(float scale); + float stop_scale(); void exit_capture(); @@ -264,12 +296,37 @@ public: void Close(); + void clear_all_decoder(); + + inline bool is_closed(){ + return _bClose; + } + private: void set_capture_state(capture_state state); void register_hotplug_callback(); + void deregister_hotplug_callback(); + bool do_add_decoder(srd_decoder *const dec, bool silent, DecoderStatus *dstatus); + + void add_decode_task(view::DecodeTrace *trace); + + void remove_decode_task(view::DecodeTrace *trace); + + void clear_all_decode_task(int &runningDex); + + view::DecodeTrace* get_decoder_trace(int index); + + void decode_task_proc(); + + view::DecodeTrace* get_top_decode_task(); + + void capture_init(); + + void do_stop_capture(); + private: /** * Attempts to autodetect the format. Failing that @@ -291,11 +348,16 @@ private: // data feed void feed_in_header(const sr_dev_inst *sdi); + void feed_in_meta(const sr_dev_inst *sdi, const sr_datafeed_meta &meta); + void feed_in_trigger(const ds_trigger_pos &trigger_pos); + void feed_in_logic(const sr_datafeed_logic &logic); + void feed_in_dso(const sr_datafeed_dso &dso); + void feed_in_analog(const sr_datafeed_analog &analog); void data_feed_in(const struct sr_dev_inst *sdi, @@ -306,6 +368,7 @@ private: // thread for hotplug void hotplug_proc(boost::function error_handler); + static int hotplug_callback(struct libusb_context *ctx, struct libusb_device *dev, libusb_hotplug_event event, void *user_data); @@ -321,6 +384,7 @@ signals: void receive_data(quint64 length); void device_attach(); + void device_detach(); void receive_trigger(quint64 trigger_pos); @@ -338,6 +402,7 @@ signals: void device_setted(); void zero_adj(); + void progressSaveFileValueChanged(int percent); void decode_done(); @@ -351,6 +416,7 @@ signals: void session_error(); void repeat_hold(int percent); + void repeat_resume(); void cur_snap_samplerate_changed(); @@ -359,22 +425,29 @@ signals: public slots: void reload(); + void refresh(int holdtime); + void stop_capture(); + void check_update(); // repeat void set_repeating(bool repeat); + void set_map_zoom(int index); // OSC auto void auto_end(); private slots: void data_lock(); + void data_unlock(); + void nodata_timeout(); + void feed_timeout(); - void repeat_update(); - + + void repeat_update(); private: DeviceManager *_device_manager; @@ -382,73 +455,77 @@ private: /** * The device instance that will be used in the next capture session. */ - DevInst *_dev_inst; + DevInst *_dev_inst; + mutable std::mutex _sampling_mutex; + mutable std::mutex _data_mutex; + mutable std::mutex _decode_task_mutex; + + std::thread _hotplug_thread; + std::thread _sampling_thread; + std::thread _decode_thread; - mutable std::mutex _sampling_mutex; - capture_state _capture_state; - bool _instant; - uint64_t _cur_snap_samplerate; - uint64_t _cur_samplelimits; + volatile bool _bHotplugStop; + volatile bool _bDecodeRunning; - //mutable std::mutex _signals_mutex; - std::vector _signals; + capture_state _capture_state; + bool _instant; + uint64_t _cur_snap_samplerate; + uint64_t _cur_samplelimits; + + std::vector _signals; std::vector _group_traces; std::vector _decode_traces; - pv::data::DecoderModel *_decoder_model; + std::vector _decode_tasks; + pv::data::DecoderModel *_decoder_model; std::vector _spectrum_traces; - view::LissajousTrace *_lissajous_trace; - view::MathTrace *_math_trace; - - mutable std::mutex _data_mutex; - data::Logic *_logic_data; - data::LogicSnapshot *_cur_logic_snapshot; - data::Dso *_dso_data; - data::DsoSnapshot *_cur_dso_snapshot; - data::Analog *_analog_data; - data::AnalogSnapshot *_cur_analog_snapshot; - data::Group *_group_data; - int _group_cnt; - - std::thread *_sampling_thread; - std::thread *_hotplug; - volatile bool _bHotplugStop; - + view::LissajousTrace *_lissajous_trace; + view::MathTrace *_math_trace; + + data::Logic *_logic_data; + data::LogicSnapshot *_cur_logic_snapshot; + data::Dso *_dso_data; + data::DsoSnapshot *_cur_dso_snapshot; + data::Analog *_analog_data; + data::AnalogSnapshot *_cur_analog_snapshot; + data::Group *_group_data; + int _group_cnt; + libusb_hotplug_callback_handle _hotplug_handle; - bool _hot_attach; - bool _hot_detach; + bool _hot_attach; + bool _hot_detach; - QTimer _feed_timer; - int _noData_cnt; - bool _data_lock; - bool _data_updated; - int _data_auto_lock; + QTimer _feed_timer; + int _noData_cnt; + bool _data_lock; + bool _data_updated; + int _data_auto_lock; - QDateTime _session_time; - uint64_t _trigger_pos; - bool _trigger_flag; - uint8_t _trigger_ch; - bool _hw_replied; + QDateTime _session_time; + uint64_t _trigger_pos; + bool _trigger_flag; + uint8_t _trigger_ch; + bool _hw_replied; error_state _error; - uint64_t _error_pattern; + uint64_t _error_pattern; - run_mode _run_mode; - int _repeat_intvl; - bool _repeating; - int _repeat_hold_prg; + run_mode _run_mode; + int _repeat_intvl; + bool _repeating; + int _repeat_hold_prg; - int _map_zoom; + int _map_zoom; - uint64_t _save_start; - uint64_t _save_end; - bool _saving; + uint64_t _save_start; + uint64_t _save_end; + bool _saving; - bool _dso_feed; - float _stop_scale; - + bool _dso_feed; + float _stop_scale; + bool _bClose; private: // TODO: This should not be necessary. Multiple concurrent diff --git a/DSView/pv/storesession.cpp b/DSView/pv/storesession.cpp index c99d2efe..1540affb 100755 --- a/DSView/pv/storesession.cpp +++ b/DSView/pv/storesession.cpp @@ -83,14 +83,12 @@ SigSession* StoreSession::session() } std::pair StoreSession::progress() -{ - //lock_guard lock(_mutex); +{ return std::make_pair(_units_stored, _unit_count); } const QString& StoreSession::error() -{ - //lock_guard lock(_mutex); +{ return _error; } @@ -878,6 +876,7 @@ QJsonArray StoreSession::json_decoders() QJsonArray ch_array; const srd_decoder *const d = dec->decoder();; const bool have_probes = (d->channels || d->opt_channels) != 0; + if (have_probes) { for(auto i = dec->channels().begin(); i != dec->channels().end(); i++) { @@ -946,29 +945,38 @@ QJsonArray StoreSession::json_decoders() return dec_array; } -void StoreSession::load_decoders(dock::ProtocolDock *widget, QJsonArray dec_array) +bool StoreSession::load_decoders(dock::ProtocolDock *widget, QJsonArray dec_array) { - if (_session->get_device()->dev_inst()->mode != LOGIC || - dec_array.empty()) - return; + if (_session->get_device()->dev_inst()->mode != LOGIC || dec_array.empty()) + { + return false; + } + - foreach (const QJsonValue &dec_value, dec_array) { - QJsonObject dec_obj = dec_value.toObject(); + for (const QJsonValue &dec_value : dec_array) { - auto &pre_dsigs = _session->get_decode_signals(); + QJsonObject dec_obj = dec_value.toObject(); + std::vector &pre_dsigs = _session->get_decode_signals(); + + //set current protocol if (widget->sel_protocol(dec_obj["id"].toString())) - widget->add_protocol(true); + { + widget->add_protocol(true); + } + else{ + continue; //protocol is not exists; + } - auto &aft_dsigs = _session->get_decode_signals(); + std::vector &aft_dsigs = _session->get_decode_signals(); - if (aft_dsigs.size() > pre_dsigs.size()) { + if (aft_dsigs.size() >= pre_dsigs.size()) { const GSList *l; auto new_dsig = aft_dsigs.back(); auto stack = new_dsig->decoder(); if (dec_obj.contains("stacked decoders")) { - foreach(const QJsonValue &value, dec_obj["stacked decoders"].toArray()) { + for(const QJsonValue &value : dec_obj["stacked decoders"].toArray()) { QJsonObject stacked_obj = value.toObject(); GSList *dl = g_slist_copy((GSList*)srd_decoder_list()); @@ -995,9 +1003,9 @@ void StoreSession::load_decoders(dock::ProtocolDock *widget, QJsonArray dec_arra std::map probe_map; // Load the mandatory channels for(l = d->channels; l; l = l->next) { - const struct srd_channel *const pdch = - (struct srd_channel *)l->data; - foreach (const QJsonValue &value, dec_obj["channel"].toArray()) { + const struct srd_channel *const pdch = (struct srd_channel *)l->data; + + for (const QJsonValue &value : dec_obj["channel"].toArray()) { QJsonObject ch_obj = value.toObject(); if (ch_obj.contains(pdch->id)) { probe_map[pdch] = ch_obj[pdch->id].toInt(); @@ -1008,9 +1016,9 @@ void StoreSession::load_decoders(dock::ProtocolDock *widget, QJsonArray dec_arra // Load the optional channels for(l = d->opt_channels; l; l = l->next) { - const struct srd_channel *const pdch = - (struct srd_channel *)l->data; - foreach (const QJsonValue &value, dec_obj["channel"].toArray()) { + const struct srd_channel *const pdch = (struct srd_channel *)l->data; + + for (const QJsonValue &value : dec_obj["channel"].toArray()) { QJsonObject ch_obj = value.toObject(); if (ch_obj.contains(pdch->id)) { probe_map[pdch] = ch_obj[pdch->id].toInt(); @@ -1021,7 +1029,7 @@ void StoreSession::load_decoders(dock::ProtocolDock *widget, QJsonArray dec_arra dec->set_probes(probe_map); options_obj = dec_obj["options"].toObject(); } else { - foreach(const QJsonValue &value, dec_obj["stacked decoders"].toArray()) { + for(const QJsonValue &value : dec_obj["stacked decoders"].toArray()) { QJsonObject stacked_obj = value.toObject(); if (QString::fromUtf8(d->id) == stacked_obj["id"].toString()) { options_obj = stacked_obj["options"].toObject(); @@ -1087,6 +1095,7 @@ void StoreSession::load_decoders(dock::ProtocolDock *widget, QJsonArray dec_arra } } + return true; } diff --git a/DSView/pv/storesession.h b/DSView/pv/storesession.h index c4a49448..c7ef0e1d 100755 --- a/DSView/pv/storesession.h +++ b/DSView/pv/storesession.h @@ -80,7 +80,7 @@ private: public: QJsonArray json_decoders(); - void load_decoders(dock::ProtocolDock *widget, QJsonArray dec_array); + bool load_decoders(dock::ProtocolDock *widget, QJsonArray dec_array); QString MakeSaveFile(bool bDlg); QString MakeExportFile(bool bDlg); diff --git a/DSView/pv/view/decodetrace.cpp b/DSView/pv/view/decodetrace.cpp index babe8024..8cc1b1a8 100755 --- a/DSView/pv/view/decodetrace.cpp +++ b/DSView/pv/view/decodetrace.cpp @@ -117,31 +117,30 @@ const QString DecodeTrace::RegionEnd = QT_TR_NOOP("End "); DecodeTrace::DecodeTrace(pv::SigSession *session, pv::data::DecoderStack *decoder_stack, int index) : - Trace(QString::fromUtf8( - decoder_stack->stack().front()->decoder()->name), index, SR_CHANNEL_DECODER), - _session(session), - _decoder_stack(decoder_stack), - _decode_start(0), - _decode_end(INT64_MAX), - _start_index(0), - _end_index(0), - _start_count(0), - _end_count(0), - _progress(0), - _popup(NULL) + Trace(QString::fromUtf8(decoder_stack->stack().front()->decoder()->name), index, SR_CHANNEL_DECODER) { - assert(_decoder_stack); + assert(decoder_stack); - _colour = DecodeColours[index % countof(DecodeColours)]; + _colour = DecodeColours[index % countof(DecodeColours)]; + _start_comboBox = NULL; + _end_comboBox = NULL; + _pub_input_layer = NULL; + _progress = 0; - connect(_decoder_stack, SIGNAL(new_decode_data()), - this, SLOT(on_new_decode_data())); - connect(_decoder_stack, SIGNAL(decode_done()), - this, SLOT(on_decode_done())); + _decode_start = 0; + _decode_end = INT64_MAX; + _end_count = 0; + _start_count = 0; + _end_index = 0; + _start_index = 0; - _start_comboBox = NULL; - _end_comboBox = NULL; - _pub_input_layer = NULL; + _decoder_stack = decoder_stack; + _session = session; + _delete_flag = false; + + connect(_decoder_stack, SIGNAL(new_decode_data()), this, SLOT(on_new_decode_data())); + + connect(_decoder_stack, SIGNAL(decode_done()), this, SLOT(on_decode_done())); } DecodeTrace::~DecodeTrace() @@ -150,10 +149,7 @@ DecodeTrace::~DecodeTrace() _probe_selectors.clear(); _bindings.clear(); - if (_popup){ - delete _popup; - _popup = NULL; - } + DESTROY_OBJECT(_decoder_stack); } bool DecodeTrace::enabled() @@ -351,18 +347,13 @@ void DecodeTrace::paint_fore(QPainter &p, int left, int right, QColor fore, QCol //to show decoder's property setting dialog bool DecodeTrace::create_popup() -{ - if (_popup != NULL){ - _popup->reload(); - return true; - } +{ + int ret = false; //setting have changed flag + + dialogs::DSDialog dlg; + create_popup_form(&dlg); - int ret = false; - _popup = new dialogs::DSDialog(); - - create_popup_form(); - - if (QDialog::Accepted == _popup->exec()) + if (QDialog::Accepted == dlg.exec()) { for(auto &dec : _decoder_stack->stack()) { @@ -375,26 +366,25 @@ bool DecodeTrace::create_popup() } } - //destroy object return ret; } -void DecodeTrace::create_popup_form() +void DecodeTrace::create_popup_form(dialogs::DSDialog *dlg) { // Clear the layout // Transfer the layout and the child widgets to a temporary widget // which then goes out of scope destroying the layout and all the child // widgets. - QFormLayout *_popup_form = new QFormLayout(); - _popup_form->setVerticalSpacing(5); - _popup_form->setFormAlignment(Qt::AlignLeft); - _popup_form->setLabelAlignment(Qt::AlignLeft); - _popup_form->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); - _popup->layout()->addLayout(_popup_form); - _popup->setTitle(tr("Decoder Options")); + QFormLayout *form = new QFormLayout(); + form->setVerticalSpacing(5); + form->setFormAlignment(Qt::AlignLeft); + form->setLabelAlignment(Qt::AlignLeft); + form->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); + dlg->layout()->addLayout(form); + dlg->setTitle(tr("Decoder Options")); - populate_popup_form(_popup, _popup_form); + populate_popup_form(dlg, form); } void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form) @@ -424,15 +414,14 @@ void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form) form->addRow(new QLabel( tr("* Required channels"), parent)); - } - - + } //Add region combobox _start_comboBox = new QComboBox(parent); _end_comboBox = new QComboBox(parent); _start_comboBox->addItem(RegionStart); _end_comboBox->addItem(RegionEnd); + if (_view) { int index = 1; for(std::list::iterator i = _view->get_cursorList().begin(); @@ -443,6 +432,7 @@ void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form) index++; } } + if (_start_count > _start_comboBox->count()) _start_index = 0; if (_end_count > _end_comboBox->count()) @@ -452,10 +442,7 @@ void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form) _start_comboBox->setCurrentIndex(_start_index); _end_comboBox->setCurrentIndex(_end_index); - connect(_start_comboBox, SIGNAL(currentIndexChanged(int)), - this, SLOT(on_region_set(int))); - connect(_end_comboBox, SIGNAL(currentIndexChanged(int)), - this, SLOT(on_region_set(int))); + on_region_set(_start_index); form->addRow(_start_comboBox, new QLabel( tr("Decode Start From"))); @@ -465,11 +452,8 @@ void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form) // Add stacking button pv::widgets::DecoderMenu *const decoder_menu = new pv::widgets::DecoderMenu(parent); - connect(decoder_menu, SIGNAL(decoder_selected(srd_decoder*)), - this, SLOT(on_stack_decoder(srd_decoder*))); - //connect(decoder_menu, SIGNAL(selected()), - // parent, SLOT(accept())); + QPushButton *const stack_button = new QPushButton(tr("Stack Decoder"), parent); stack_button->setMenu(decoder_menu); @@ -481,12 +465,21 @@ void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form) // Add ButtonBox (OK/Cancel) QDialogButtonBox *button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, parent); - connect(button_box, SIGNAL(accepted()), parent, SLOT(accept())); - connect(button_box, SIGNAL(rejected()), parent, SLOT(reject())); + QHBoxLayout *confirm_button_box = new QHBoxLayout; confirm_button_box->addWidget(button_box, 0, Qt::AlignRight); form->addRow(confirm_button_box); + + connect(_start_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(on_region_set(int))); + + connect(_end_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(on_region_set(int))); + + connect(decoder_menu, SIGNAL(decoder_selected(srd_decoder *)), this, SLOT(on_stack_decoder(srd_decoder *))); + + connect(button_box, SIGNAL(accepted()), parent, SLOT(accept())); + + connect(button_box, SIGNAL(rejected()), parent, SLOT(reject())); } void DecodeTrace::draw_annotation(const pv::data::decode::Annotation &a, @@ -733,14 +726,15 @@ void DecodeTrace::create_decoder_form( const struct srd_channel *const pdch = (struct srd_channel *)l->data; QComboBox *const combo = create_probe_selector(parent, dec, pdch); - connect(combo, SIGNAL(currentIndexChanged(int)), - this, SLOT(on_probe_selected(int))); + decoder_form->addRow(tr("%1 (%2) *") .arg(QString::fromUtf8(pdch->name)) .arg(QString::fromUtf8(pdch->desc)), combo); const ProbeSelector s = {combo, dec, pdch}; _probe_selectors.push_back(s); + + connect(combo, SIGNAL(currentIndexChanged(int)), this, SLOT(on_probe_selected(int))); } // Add the optional channels @@ -748,14 +742,15 @@ void DecodeTrace::create_decoder_form( const struct srd_channel *const pdch = (struct srd_channel *)l->data; QComboBox *const combo = create_probe_selector(parent, dec, pdch); - connect(combo, SIGNAL(currentIndexChanged(int)), - this, SLOT(on_probe_selected(int))); + decoder_form->addRow(tr("%1 (%2)") .arg(QString::fromUtf8(pdch->name)) .arg(QString::fromUtf8(pdch->desc)), combo); const ProbeSelector s = {combo, dec, pdch}; _probe_selectors.push_back(s); + + connect(combo, SIGNAL(currentIndexChanged(int)), this, SLOT(on_probe_selected(int))); } // Add the options @@ -767,12 +762,11 @@ void DecodeTrace::create_decoder_form( // pv::widgets::DecoderGroupBox *const group = new pv::widgets::DecoderGroupBox(decoder_stack, dec, decoder_form, parent); - - connect(group, SIGNAL(del_stack(data::decode::Decoder*)), - this, SLOT(on_del_stack(data::decode::Decoder*))); - + form->addRow(group); _decoder_forms.push_back(group); + + connect(group, SIGNAL(del_stack(data::decode::Decoder*)), this, SLOT(on_del_stack(data::decode::Decoder*))); } QComboBox* DecodeTrace::create_probe_selector( @@ -873,19 +867,11 @@ int DecodeTrace::get_progress() } void DecodeTrace::on_decode_done() -{ -// if (_view) { -// _view->set_update(_viewport, true); -// _view->signals_changed(); -// } +{ on_new_decode_data(); _session->decode_done(); } - -void DecodeTrace::on_delete() -{ - _session->remove_decode_signal(this); -} + void DecodeTrace::on_probe_selected(int) { @@ -899,7 +885,7 @@ void DecodeTrace::on_stack_decoder(srd_decoder *decoder) _decoder_stack->push(new data::decode::Decoder(decoder)); - create_popup_form(); + // create_popup_form(); } void DecodeTrace::on_del_stack(data::decode::Decoder *dec) @@ -908,7 +894,7 @@ void DecodeTrace::on_del_stack(data::decode::Decoder *dec) assert(_decoder_stack); _decoder_stack->remove(dec); - create_popup_form(); + // create_popup_form(); } int DecodeTrace::rows_size() diff --git a/DSView/pv/view/decodetrace.h b/DSView/pv/view/decodetrace.h index d2d59f37..5b361e5c 100755 --- a/DSView/pv/view/decodetrace.h +++ b/DSView/pv/view/decodetrace.h @@ -58,6 +58,7 @@ class DecoderGroupBox; namespace view { +//create by SigSession class DecodeTrace : public Trace { Q_OBJECT @@ -98,6 +99,8 @@ public: DecodeTrace(pv::SigSession *session, pv::data::DecoderStack *decoder_stack, int index); + +public: ~DecodeTrace(); bool enabled(); @@ -147,7 +150,7 @@ protected: void paint_type_options(QPainter &p, int right, const QPoint pt, QColor fore); private: - void create_popup_form(); + void create_popup_form(dialogs::DSDialog *dlg); void populate_popup_form(QWidget *parent, QFormLayout *form); @@ -191,9 +194,7 @@ signals: private slots: void on_new_decode_data(); - - void on_delete(); - + void on_probe_selected(int); void on_stack_decoder(srd_decoder *decoder); @@ -204,6 +205,9 @@ private slots: void on_region_set(int index); +public: + volatile bool _delete_flag; //detroy it when deocde task end + private: pv::SigSession *_session; pv::data::DecoderStack *_decoder_stack; @@ -214,6 +218,7 @@ private: int _end_index; int _start_count; int _end_count; + QComboBox *_start_comboBox; QComboBox *_end_comboBox; QFormLayout *_pub_input_layer; @@ -224,7 +229,6 @@ private: std::vector _decoder_forms; std::vector _cur_row_headings; - dialogs::DSDialog *_popup; }; } // namespace view diff --git a/DSView/pv/view/view.cpp b/DSView/pv/view/view.cpp index 5ee7244f..91b53b5b 100755 --- a/DSView/pv/view/view.cpp +++ b/DSView/pv/view/view.cpp @@ -100,12 +100,7 @@ View::View(SigSession *session, pv::toolbars::SamplingBar *sampling_bar, QWidget assert(session); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); - - connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), - this, SLOT(h_scroll_value_changed(int))); - connect(verticalScrollBar(), SIGNAL(valueChanged(int)), - this, SLOT(v_scroll_value_changed(int))); - + // trace viewport map _trace_view_map[SR_CHANNEL_LOGIC] = TIME_VIEW; _trace_view_map[SR_CHANNEL_GROUP] = TIME_VIEW; @@ -128,16 +123,12 @@ View::View(SigSession *session, pv::toolbars::SamplingBar *sampling_bar, QWidget _time_viewport = new Viewport(*this, TIME_VIEW); _time_viewport->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); _time_viewport->setMinimumHeight(100); - connect(_time_viewport, SIGNAL(measure_updated()), - this, SLOT(on_measure_updated())); - connect(_time_viewport, SIGNAL(prgRate(int)), this, SIGNAL(prgRate(int))); + _fft_viewport = new Viewport(*this, FFT_VIEW); _fft_viewport->setVisible(false); _fft_viewport->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); _fft_viewport->setMinimumHeight(100); - connect(_fft_viewport, SIGNAL(measure_updated()), - this, SLOT(on_measure_updated())); - + _vsplitter = new QSplitter(this); _vsplitter->setOrientation(Qt::Vertical); _vsplitter->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); @@ -162,35 +153,6 @@ View::View(SigSession *session, pv::toolbars::SamplingBar *sampling_bar, QWidget _viewbottom->setFixedHeight(StatusHeight); layout->addWidget(_viewbottom, 1, 0); setViewport(_viewcenter); - connect(_vsplitter, SIGNAL(splitterMoved(int,int)), - this, SLOT(splitterMoved(int, int))); - - connect(_session, SIGNAL(device_setted()), - _devmode, SLOT(set_device())); - connect(_session, SIGNAL(signals_changed()), - this, SLOT(signals_changed()), Qt::DirectConnection); - connect(_session, SIGNAL(data_updated()), - this, SLOT(data_updated())); - connect(_session, SIGNAL(receive_trigger(quint64)), - this, SLOT(receive_trigger(quint64))); - connect(_session, SIGNAL(frame_ended()), - this, SLOT(receive_end())); - connect(_session, SIGNAL(frame_began()), - this, SLOT(frame_began())); - connect(_session, SIGNAL(show_region(uint64_t, uint64_t, bool)), - this, SLOT(show_region(uint64_t, uint64_t, bool))); - connect(_session, SIGNAL(show_wait_trigger()), - _time_viewport, SLOT(show_wait_trigger())); - connect(_session, SIGNAL(repeat_hold(int)), - this, SLOT(repeat_show())); - - connect(_devmode, SIGNAL(dev_changed(bool)), - this, SLOT(dev_changed(bool)), Qt::DirectConnection); - - connect(_header, SIGNAL(traces_moved()), - this, SLOT(on_traces_moved())); - connect(_header, SIGNAL(header_updated()), - this, SLOT(header_updated())); _time_viewport->installEventFilter(this); _fft_viewport->installEventFilter(this); @@ -213,6 +175,28 @@ View::View(SigSession *session, pv::toolbars::SamplingBar *sampling_bar, QWidget _cali = new pv::dialogs::Calibration(this); _cali->hide(); + + connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(h_scroll_value_changed(int))); + connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(v_scroll_value_changed(int))); + + connect(_time_viewport, SIGNAL(measure_updated()),this, SLOT(on_measure_updated())); + connect(_time_viewport, SIGNAL(prgRate(int)), this, SIGNAL(prgRate(int))); + connect(_fft_viewport, SIGNAL(measure_updated()), this, SLOT(on_measure_updated())); + + connect(_vsplitter, SIGNAL(splitterMoved(int,int)), this, SLOT(splitterMoved(int, int))); + connect(_session, SIGNAL(device_setted()), _devmode, SLOT(set_device())); + connect(_session, SIGNAL(signals_changed()), this, SLOT(signals_changed()), Qt::DirectConnection); + connect(_session, SIGNAL(data_updated()), this, SLOT(data_updated())); + connect(_session, SIGNAL(receive_trigger(quint64)), this, SLOT(receive_trigger(quint64))); + connect(_session, SIGNAL(frame_ended()), this, SLOT(receive_end())); + connect(_session, SIGNAL(frame_began()), this, SLOT(frame_began())); + connect(_session, SIGNAL(show_region(uint64_t, uint64_t, bool)), this, SLOT(show_region(uint64_t, uint64_t, bool))); + + connect(_session, SIGNAL(show_wait_trigger()), _time_viewport, SLOT(show_wait_trigger())); + connect(_session, SIGNAL(repeat_hold(int)), this, SLOT(repeat_show())); + connect(_devmode, SIGNAL(dev_changed(bool)),this, SLOT(dev_changed(bool)), Qt::DirectConnection); + connect(_header, SIGNAL(traces_moved()),this, SLOT(on_traces_moved())); + connect(_header, SIGNAL(header_updated()),this, SLOT(header_updated())); } SigSession& View::session() diff --git a/DSView/pv/view/viewstatus.cpp b/DSView/pv/view/viewstatus.cpp index 3a1cf19f..cfad21d2 100755 --- a/DSView/pv/view/viewstatus.cpp +++ b/DSView/pv/view/viewstatus.cpp @@ -237,7 +237,7 @@ void ViewStatus::load_session(QJsonArray measure_array) measure_array.empty()) return; - foreach (const QJsonValue &measure_value, measure_array) { + for (const QJsonValue &measure_value : measure_array) { QJsonObject m_obj = measure_value.toObject(); int index = m_obj["site"].toInt(); int sig_index = m_obj["index"].toInt(); diff --git a/libsigrok4DSL/hardware/demo/demo.h b/libsigrok4DSL/hardware/demo/demo.h index 7fbb87e5..0a9cb52e 100755 --- a/libsigrok4DSL/hardware/demo/demo.h +++ b/libsigrok4DSL/hardware/demo/demo.h @@ -168,7 +168,7 @@ static const struct DEMO_profile supported_Demo[] = { (1 << DEMO_LOGIC100x16) | (1 << DEMO_ANALOG10x2) | (1 << DEMO_DSO200x2), - //SR_Mn(100), + //SR_Mn(100), SR_Gn(16), SR_Kn(20), 0, diff --git a/libsigrok4DSL/session.c b/libsigrok4DSL/session.c index 34923f4c..ce46fcb9 100755 --- a/libsigrok4DSL/session.c +++ b/libsigrok4DSL/session.c @@ -36,6 +36,8 @@ int bExportOriginalData = 0; //able export all data +int session_loop_stop_flag = 0; + /** * @file * @@ -403,12 +405,14 @@ SR_API int sr_session_run(void) session->running = TRUE; + session_loop_stop_flag = 0; + sr_info("Running..."); /* Do we have real sources? */ if (session->num_sources == 1 && session->pollfds[0].fd == -1) { /* Dummy source, freewheel over it. */ - while (session->num_sources) { + while (session->num_sources && !session_loop_stop_flag) { if (session->abort_session) { session->sources[0].cb(-1, -1, session->sources[0].cb_data); break; @@ -418,8 +422,9 @@ SR_API int sr_session_run(void) } } else { /* Real sources, use g_poll() main loop. */ - while (session->num_sources) - sr_session_iteration(TRUE); + while (session->num_sources && !session_loop_stop_flag){ + sr_session_iteration(TRUE); + } } g_mutex_lock(&session->stop_mutex); @@ -484,9 +489,11 @@ SR_API int sr_session_stop(void) return SR_ERR_BUG; } + session_loop_stop_flag = 1; //set flag, the run loop will exit + g_mutex_lock(&session->stop_mutex); if (session->running) - session->abort_session = TRUE; + session->abort_session = TRUE; g_mutex_unlock(&session->stop_mutex); return SR_OK; From 140b5bf9f5aac019e54a261bf82f2796c24cdd4e Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Tue, 9 Nov 2021 13:51:59 +0800 Subject: [PATCH 22/60] mem manager update 1 --- DSView/pv/config/appconfig.cpp | 2 +- DSView/pv/data/analog.cpp | 10 +- DSView/pv/data/analog.h | 4 +- DSView/pv/data/decoderstack.cpp | 10 +- DSView/pv/data/dso.cpp | 10 +- DSView/pv/data/dso.h | 4 +- DSView/pv/data/logic.cpp | 10 +- DSView/pv/data/logic.h | 4 +- DSView/pv/device/devinst.cpp | 1 - DSView/pv/dialogs/dsmessagebox.cpp | 1 + DSView/pv/dsvdef.h | 2 + DSView/pv/mainwindow.cpp | 2 +- DSView/pv/sigsession.cpp | 185 ++++++++++++++--------------- DSView/pv/sigsession.h | 7 +- DSView/pv/toolbars/titlebar.cpp | 10 +- DSView/pv/toolbars/trigbar.cpp | 9 +- DSView/pv/view/devmode.cpp | 11 +- DSView/pv/view/mathtrace.cpp | 5 +- DSView/pv/view/spectrumtrace.cpp | 3 +- 19 files changed, 156 insertions(+), 134 deletions(-) diff --git a/DSView/pv/config/appconfig.cpp b/DSView/pv/config/appconfig.cpp index 3901c7bf..b921a631 100644 --- a/DSView/pv/config/appconfig.cpp +++ b/DSView/pv/config/appconfig.cpp @@ -269,7 +269,7 @@ QString GetDirectoryName(QString path) } QString GetIconPath() -{ +{ QString style = AppConfig::Instance()._frameOptions.style; if (style == ""){ style = "dark"; diff --git a/DSView/pv/data/analog.cpp b/DSView/pv/data/analog.cpp index 4dfcc8c4..16339621 100755 --- a/DSView/pv/data/analog.cpp +++ b/DSView/pv/data/analog.cpp @@ -22,6 +22,7 @@ #include "analog.h" #include "analogsnapshot.h" +#include using namespace std; @@ -29,9 +30,11 @@ using namespace std; namespace pv { namespace data { -Analog::Analog() : +Analog::Analog(AnalogSnapshot *snapshot) : SignalData() { + assert(snapshot); + _snapshots.push_front(snapshot); } void Analog::push_snapshot(AnalogSnapshot *snapshot) @@ -57,5 +60,10 @@ void Analog::init() s->init(); } +AnalogSnapshot* Analog::snapshot() +{ + return _snapshots[0]; +} + } // namespace data } // namespace pv diff --git a/DSView/pv/data/analog.h b/DSView/pv/data/analog.h index dbba04df..d3541f8e 100755 --- a/DSView/pv/data/analog.h +++ b/DSView/pv/data/analog.h @@ -37,13 +37,15 @@ class AnalogSnapshot; class Analog : public SignalData { public: - Analog(); + Analog(AnalogSnapshot *snapshot); void push_snapshot(AnalogSnapshot *snapshot); std::deque& get_snapshots(); void clear(); void init(); + AnalogSnapshot* snapshot(); + private: std::deque _snapshots; }; diff --git a/DSView/pv/data/decoderstack.cpp b/DSView/pv/data/decoderstack.cpp index 4aa6a86e..4c76ac7e 100755 --- a/DSView/pv/data/decoderstack.cpp +++ b/DSView/pv/data/decoderstack.cpp @@ -401,8 +401,7 @@ void DecoderStack::do_decode_work() pv::data::Logic *data = NULL; if (!_options_changed) - { - qDebug()<<"data not be ready"; + { return; } _options_changed = false; @@ -542,9 +541,7 @@ void DecoderStack::decode_data(const uint64_t decode_start, const uint64_t decod if (error) g_free(error); - - qDebug()<<"decode tack proc end"; - + if (!_session->is_closed()) decode_done(); } @@ -565,8 +562,7 @@ void DecoderStack::decode_proc() // Get the intial sample count _sample_count = _snapshot->get_sample_count(); - - qDebug()<<"sample count:"<<_sample_count; + // Create the decoders for(auto &dec : _stack) diff --git a/DSView/pv/data/dso.cpp b/DSView/pv/data/dso.cpp index acbd6c62..ea05f5b7 100755 --- a/DSView/pv/data/dso.cpp +++ b/DSView/pv/data/dso.cpp @@ -21,6 +21,7 @@ #include "dso.h" #include "dsosnapshot.h" +#include using namespace std; @@ -28,9 +29,11 @@ using namespace std; namespace pv { namespace data { -Dso::Dso() : +Dso::Dso(DsoSnapshot *snapshot) : SignalData() { + assert(snapshot); + _snapshots.push_front(snapshot); } void Dso::push_snapshot(DsoSnapshot *snapshot) @@ -57,5 +60,10 @@ void Dso::init() s->init(); } + DsoSnapshot* Dso::snapshot() + { + return _snapshots[0]; + } + } // namespace data } // namespace pv diff --git a/DSView/pv/data/dso.h b/DSView/pv/data/dso.h index 1ef87645..cd03988d 100755 --- a/DSView/pv/data/dso.h +++ b/DSView/pv/data/dso.h @@ -35,7 +35,7 @@ class DsoSnapshot; class Dso : public SignalData { public: - Dso(); + Dso(DsoSnapshot *snapshot); void push_snapshot(DsoSnapshot *snapshot); @@ -44,6 +44,8 @@ public: void clear(); void init(); + DsoSnapshot* snapshot(); + private: std::deque _snapshots; }; diff --git a/DSView/pv/data/logic.cpp b/DSView/pv/data/logic.cpp index 71055656..ccc7ec54 100755 --- a/DSView/pv/data/logic.cpp +++ b/DSView/pv/data/logic.cpp @@ -22,15 +22,18 @@ #include "logic.h" #include "logicsnapshot.h" +#include using namespace std; namespace pv { namespace data { -Logic::Logic() : +Logic::Logic(LogicSnapshot *snapshot) : SignalData() { + assert(snapshot); + _snapshots.push_front(snapshot); } void Logic::push_snapshot(LogicSnapshot *snapshot) @@ -57,5 +60,10 @@ void Logic::init() s->init(); } + LogicSnapshot* Logic::snapshot() + { + return _snapshots[0]; + } + } // namespace data } // namespace pv diff --git a/DSView/pv/data/logic.h b/DSView/pv/data/logic.h index 2eb76aed..5f925a1c 100755 --- a/DSView/pv/data/logic.h +++ b/DSView/pv/data/logic.h @@ -36,7 +36,7 @@ class LogicSnapshot; class Logic : public SignalData { public: - Logic(); + Logic(LogicSnapshot *snapshot); void push_snapshot(LogicSnapshot *snapshot); @@ -46,6 +46,8 @@ public: void init(); + LogicSnapshot* snapshot(); + private: std::deque _snapshots; }; diff --git a/DSView/pv/device/devinst.cpp b/DSView/pv/device/devinst.cpp index a17b6098..b0bf7d5a 100755 --- a/DSView/pv/device/devinst.cpp +++ b/DSView/pv/device/devinst.cpp @@ -53,7 +53,6 @@ void* DevInst::get_id() void DevInst::use(SigSession *owner) { assert(owner); - assert(!_owner); _owner = owner; } diff --git a/DSView/pv/dialogs/dsmessagebox.cpp b/DSView/pv/dialogs/dsmessagebox.cpp index eb8f8bbd..2df07b6e 100755 --- a/DSView/pv/dialogs/dsmessagebox.cpp +++ b/DSView/pv/dialogs/dsmessagebox.cpp @@ -36,6 +36,7 @@ namespace dialogs { DSMessageBox::DSMessageBox(QWidget *parent,const char *title) : QDialog(NULL) //must be null, otherwise window can not able to move { + (void)parent; _layout = NULL; _main_widget = NULL; _msg = NULL; diff --git a/DSView/pv/dsvdef.h b/DSView/pv/dsvdef.h index cc5283c8..9069c153 100644 --- a/DSView/pv/dsvdef.h +++ b/DSView/pv/dsvdef.h @@ -39,6 +39,8 @@ class QWidget; #define DESTROY_QT_OBJECT(p) if((p)){((p))->deleteLater(); p = NULL;} #define DESTROY_QT_LATER(p) ((p))->deleteLater(); +#define RELEASE_ARRAY(a) for (auto ptr : (a)){delete ptr;} (a).clear(); + namespace DecoderDataFormat { enum _data_format diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index 79b986a4..5186f719 100755 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -1432,7 +1432,7 @@ void MainWindow::switchTheme(QString style) { app._frameOptions.style = style; app.SaveFrame(); - } + } QString qssRes = ":/" + style + ".qss"; QFile qss(qssRes); diff --git a/DSView/pv/sigsession.cpp b/DSView/pv/sigsession.cpp index b63d1aa9..a42432db 100755 --- a/DSView/pv/sigsession.cpp +++ b/DSView/pv/sigsession.cpp @@ -78,15 +78,7 @@ namespace pv { // TODO: This should not be necessary SigSession* SigSession::_session = NULL; -SigSession::SigSession(DeviceManager *device_manager) : - _capture_state(Init), - _instant(false), - _error(No_err), - _run_mode(Single), - _repeat_intvl(1), - _repeating(false), - _repeat_hold_prg(0), - _map_zoom(0) +SigSession::SigSession(DeviceManager *device_manager) { _hotplug_handle = 0; _dev_inst = NULL; @@ -97,6 +89,15 @@ SigSession::SigSession(DeviceManager *device_manager) : _hot_detach = false; _group_cnt = 0; _bHotplugStop = false; + + _map_zoom = 0; + _repeat_hold_prg = 0; + _repeating = false; + _repeat_intvl = 1; + _run_mode = Single; + _error = No_err; + _instant = false; + _capture_state = Init; _noData_cnt = 0; _data_lock = false; @@ -112,16 +113,10 @@ SigSession::SigSession(DeviceManager *device_manager) : _bDecodeRunning = false; _bClose = false; - // Create snapshots & data containers - _cur_logic_snapshot = new data::LogicSnapshot(); - _logic_data = new data::Logic(); - _logic_data->push_snapshot(_cur_logic_snapshot); - _cur_dso_snapshot = new data::DsoSnapshot(); - _dso_data = new data::Dso(); - _dso_data->push_snapshot(_cur_dso_snapshot); - _cur_analog_snapshot = new data::AnalogSnapshot(); - _analog_data = new data::Analog(); - _analog_data->push_snapshot(_cur_analog_snapshot); + // Create snapshots & data containers + _logic_data = new data::Logic(new data::LogicSnapshot()); + _dso_data = new data::Dso(new data::DsoSnapshot()); + _analog_data = new data::Analog(new data::AnalogSnapshot()); _group_data = new data::Group(); _group_cnt = 0; @@ -142,13 +137,9 @@ DevInst* SigSession::get_device() } void SigSession::deselect_device() -{ - for (auto p : _decode_traces){ - delete p; - } - _decode_traces.clear(); - - _group_traces.clear(); +{ + RELEASE_ARRAY(_decode_traces); + RELEASE_ARRAY(_group_traces); _dev_inst = NULL; } @@ -172,12 +163,8 @@ void SigSession::set_device(DevInst *dev_inst) _dev_inst = dev_inst; - for (auto p : _decode_traces){ - delete p; - } - _decode_traces.clear(); - - _group_traces.clear(); + RELEASE_ARRAY(_decode_traces); + RELEASE_ARRAY(_group_traces); if (_dev_inst) { try { @@ -517,9 +504,9 @@ void SigSession::sample_thread_proc(DevInst *dev_inst, set_capture_state(Stopped); // Confirm that SR_DF_END was received - assert(_cur_logic_snapshot->last_ended()); - assert(_cur_dso_snapshot->last_ended()); - assert(_cur_analog_snapshot->last_ended()); + assert(_logic_data->snapshot()->last_ended()); + assert(_dso_data->snapshot()->last_ended()); + assert(_analog_data->snapshot()->last_ended()); } void SigSession::stop_capture() @@ -654,7 +641,8 @@ void SigSession::del_group() { auto i = _group_traces.begin(); - while (i != _group_traces.end()) { + while (i != _group_traces.end()) { + pv::view::GroupSignal *psig = *(i); if (psig->selected()) { @@ -711,12 +699,8 @@ void SigSession::init_signals() _group_data->clear(); - // Clear the decode traces - for (auto p : _decode_traces){ - delete p; - } - _decode_traces.clear(); - + // Clear the decode traces + RELEASE_ARRAY(_decode_traces); // Detect what data types we will receive if(_dev_inst) { @@ -743,41 +727,42 @@ void SigSession::init_signals() } } - // Make the logic probe list + // Make the logic probe list + RELEASE_ARRAY(_group_traces); + + std::vector().swap(_group_traces); + + for (GSList *l = _dev_inst->dev_inst()->channels; l; l = l->next) { - _group_traces.clear(); - std::vector().swap(_group_traces); + sr_channel *probe = + (sr_channel *)l->data; + assert(probe); + signal = NULL; - for (GSList *l = _dev_inst->dev_inst()->channels; l; l = l->next) { - sr_channel *probe = - ( sr_channel *)l->data; - assert(probe); - signal = NULL; + switch (probe->type) + { + case SR_CHANNEL_LOGIC: + if (probe->enabled) + signal = new view::LogicSignal(_dev_inst, _logic_data, probe); + break; - switch(probe->type) { - case SR_CHANNEL_LOGIC: - if (probe->enabled) - signal = new view::LogicSignal(_dev_inst, _logic_data, probe); - break; + case SR_CHANNEL_DSO: + signal = new view::DsoSignal(_dev_inst, _dso_data, probe); + break; - case SR_CHANNEL_DSO: - signal = new view::DsoSignal(_dev_inst, _dso_data, probe); - break; - - case SR_CHANNEL_ANALOG: - if (probe->enabled) - signal = new view::AnalogSignal(_dev_inst, _analog_data, probe); - break; - } - if(signal != NULL) - sigs.push_back(signal); + case SR_CHANNEL_ANALOG: + if (probe->enabled) + signal = new view::AnalogSignal(_dev_inst, _analog_data, probe); + break; } - - _signals.clear(); - std::vector().swap(_signals); - _signals = sigs; + if (signal != NULL) + sigs.push_back(signal); } + RELEASE_ARRAY(_signals); + std::vector().swap(_signals); + _signals = sigs; + spectrum_rebuild(); lissajous_disable(); math_disable(); @@ -846,8 +831,8 @@ void SigSession::reload() sigs.push_back(signal); } - if (!sigs.empty()) { - _signals.clear(); + if (!sigs.empty()) { + RELEASE_ARRAY(_signals); std::vector().swap(_signals); _signals = sigs; } @@ -869,8 +854,8 @@ void SigSession::refresh(int holdtime) { d->decoder()->init(); } - } + if (_dso_data) { _dso_data->init(); // SpectrumStack @@ -879,9 +864,11 @@ void SigSession::refresh(int holdtime) assert(m); m->get_spectrum_stack()->init(); } + if (_math_trace) _math_trace->get_math_stack()->init(); } + if (_analog_data) { _analog_data->init(); } @@ -975,7 +962,7 @@ void SigSession::feed_in_trigger(const ds_trigger_pos &trigger_pos) void SigSession::feed_in_logic(const sr_datafeed_logic &logic) { - if (!_logic_data || _cur_logic_snapshot->memory_failed()) { + if (!_logic_data || _logic_data->snapshot()->memory_failed()) { qDebug() << "Unexpected logic packet"; return; } @@ -986,8 +973,8 @@ void SigSession::feed_in_logic(const sr_datafeed_logic &logic) session_error(); } - if (_cur_logic_snapshot->last_ended()) { - _cur_logic_snapshot->first_payload(logic, _dev_inst->get_sample_limit(), _dev_inst->dev_inst()->channels); + if (_logic_data->snapshot()->last_ended()) { + _logic_data->snapshot()->first_payload(logic, _dev_inst->get_sample_limit(), _dev_inst->dev_inst()->channels); // @todo Putting this here means that only listeners querying // for logic will be notified. Currently the only user of // frame_began is DecoderStack, but in future we need to signal @@ -995,10 +982,10 @@ void SigSession::feed_in_logic(const sr_datafeed_logic &logic) frame_began(); } else { // Append to the existing data snapshot - _cur_logic_snapshot->append_payload(logic); + _logic_data->snapshot()->append_payload(logic); } - if (_cur_logic_snapshot->memory_failed()) { + if (_logic_data->snapshot()->memory_failed()) { _error = Malloc_err; session_error(); return; @@ -1012,13 +999,13 @@ void SigSession::feed_in_logic(const sr_datafeed_logic &logic) void SigSession::feed_in_dso(const sr_datafeed_dso &dso) { - if(!_dso_data || _cur_dso_snapshot->memory_failed()) + if(!_dso_data || _dso_data->snapshot()->memory_failed()) { qDebug() << "Unexpected dso packet"; return; // This dso packet was not expected. } - if (_cur_dso_snapshot->last_ended()) + if (_dso_data->snapshot()->last_ended()) { std::map sig_enable; // reset scale of dso signal @@ -1033,10 +1020,10 @@ void SigSession::feed_in_dso(const sr_datafeed_dso &dso) } // first payload - _cur_dso_snapshot->first_payload(dso, _dev_inst->get_sample_limit(), sig_enable, _instant); + _dso_data->snapshot()->first_payload(dso, _dev_inst->get_sample_limit(), sig_enable, _instant); } else { // Append to the existing data snapshot - _cur_dso_snapshot->append_payload(dso); + _dso_data->snapshot()->append_payload(dso); } for(auto &s : _signals) { @@ -1051,7 +1038,7 @@ void SigSession::feed_in_dso(const sr_datafeed_dso &dso) } - if (_cur_dso_snapshot->memory_failed()) { + if (_dso_data->snapshot()->memory_failed()) { _error = Malloc_err; session_error(); return; @@ -1084,13 +1071,13 @@ void SigSession::feed_in_dso(const sr_datafeed_dso &dso) void SigSession::feed_in_analog(const sr_datafeed_analog &analog) { - if(!_analog_data || _cur_analog_snapshot->memory_failed()) + if(!_analog_data || _analog_data->snapshot()->memory_failed()) { qDebug() << "Unexpected analog packet"; return; // This analog packet was not expected. } - if (_cur_analog_snapshot->last_ended()) + if (_analog_data->snapshot()->last_ended()) { // reset scale of analog signal for(auto &s : _signals) @@ -1103,13 +1090,13 @@ void SigSession::feed_in_analog(const sr_datafeed_analog &analog) } // first payload - _cur_analog_snapshot->first_payload(analog, _dev_inst->get_sample_limit(), _dev_inst->dev_inst()->channels); + _analog_data->snapshot()->first_payload(analog, _dev_inst->get_sample_limit(), _dev_inst->dev_inst()->channels); } else { // Append to the existing data snapshot - _cur_analog_snapshot->append_payload(analog); + _analog_data->snapshot()->append_payload(analog); } - if (_cur_analog_snapshot->memory_failed()) { + if (_analog_data->snapshot()->memory_failed()) { _error = Malloc_err; session_error(); return; @@ -1179,7 +1166,7 @@ void SigSession::data_feed_in(const struct sr_dev_inst *sdi, } case SR_DF_END: { - if (!_cur_logic_snapshot->empty()) + if (!_logic_data->snapshot()->empty()) { for (auto &g : _group_traces) { @@ -1189,9 +1176,9 @@ void SigSession::data_feed_in(const struct sr_dev_inst *sdi, _group_data->push_snapshot(p); } } - _cur_logic_snapshot->capture_ended(); - _cur_dso_snapshot->capture_ended(); - _cur_analog_snapshot->capture_ended(); + _logic_data->snapshot()->capture_ended(); + _dso_data->snapshot()->capture_ended(); + _analog_data->snapshot()->capture_ended(); qDebug()<<"data frame end"; @@ -1486,8 +1473,9 @@ void SigSession::spectrum_rebuild() } } - if (!has_dso_signal) - _spectrum_traces.clear(); + if (!has_dso_signal){ + RELEASE_ARRAY(_spectrum_traces); + } signals_changed(); } @@ -1499,6 +1487,7 @@ std::vector& SigSession::get_spectrum_traces() void SigSession::lissajous_rebuild(bool enable, int xindex, int yindex, double percent) { + DESTROY_OBJECT(_lissajous_trace); _lissajous_trace = new view::LissajousTrace(enable, _dso_data, xindex, yindex, percent); signals_changed(); } @@ -1590,11 +1579,11 @@ void SigSession::feed_timeout() data::Snapshot* SigSession::get_snapshot(int type) { if (type == SR_CHANNEL_LOGIC) - return _cur_logic_snapshot; + return _logic_data->snapshot(); else if (type == SR_CHANNEL_ANALOG) - return _cur_analog_snapshot; + return _analog_data->snapshot(); else if (type == SR_CHANNEL_DSO) - return _cur_dso_snapshot; + return _dso_data->snapshot(); else return NULL; } @@ -1892,7 +1881,7 @@ void SigSession::set_stop_scale(float scale) int dex = 0; for (auto trace : _decode_traces) { - if (trace->IsRunning()) + if (trace->decoder()->IsRunning()) { trace->decoder()->stop_decode_work(); runningDex = dex; diff --git a/DSView/pv/sigsession.h b/DSView/pv/sigsession.h index 9e1d124e..c5f97439 100755 --- a/DSView/pv/sigsession.h +++ b/DSView/pv/sigsession.h @@ -483,12 +483,9 @@ private: view::LissajousTrace *_lissajous_trace; view::MathTrace *_math_trace; - data::Logic *_logic_data; - data::LogicSnapshot *_cur_logic_snapshot; - data::Dso *_dso_data; - data::DsoSnapshot *_cur_dso_snapshot; + data::Logic *_logic_data; + data::Dso *_dso_data; data::Analog *_analog_data; - data::AnalogSnapshot *_cur_analog_snapshot; data::Group *_group_data; int _group_cnt; diff --git a/DSView/pv/toolbars/titlebar.cpp b/DSView/pv/toolbars/titlebar.cpp index 306a417a..d52b18fc 100755 --- a/DSView/pv/toolbars/titlebar.cpp +++ b/DSView/pv/toolbars/titlebar.cpp @@ -38,17 +38,17 @@ namespace pv { namespace toolbars { TitleBar::TitleBar(bool top, QWidget *parent, bool hasClose) : - QWidget(parent), - _parent(parent), - _moving(false), - _isTop(top), - _hasClose(hasClose) + QWidget(parent) { _title = NULL; _minimizeButton = NULL; _maximizeButton = NULL; _closeButton = NULL; _lay = NULL; + _moving = false; + _parent = parent; + _isTop = top; + _hasClose = hasClose; assert(parent); diff --git a/DSView/pv/toolbars/trigbar.cpp b/DSView/pv/toolbars/trigbar.cpp index ea5f7c8e..2d6cdf29 100755 --- a/DSView/pv/toolbars/trigbar.cpp +++ b/DSView/pv/toolbars/trigbar.cpp @@ -180,7 +180,8 @@ void TrigBar::reStyle() AppConfig &app = AppConfig::Instance(); - _themes->setIcon(QIcon(iconPath+"/"+ app._frameOptions.language +".svg")); + QString icon_fname = iconPath +"/"+ app._frameOptions.style +".svg"; + _themes->setIcon(QIcon(icon_fname)); } void TrigBar::protocol_clicked() @@ -302,13 +303,15 @@ void TrigBar::on_actionMath_triggered() void TrigBar::on_actionDark_triggered() { sig_setTheme(DARK_STYLE); - _themes->setIcon(QIcon(":/icons/"+DARK_STYLE+"/"+DARK_STYLE+".svg")); + QString icon = GetIconPath() + "/" + DARK_STYLE + ".svg"; + _themes->setIcon(QIcon(icon)); } void TrigBar::on_actionLight_triggered() { sig_setTheme(LIGHT_STYLE); - _themes->setIcon(QIcon(":/icons/"+LIGHT_STYLE+"/"+LIGHT_STYLE+".svg")); + QString icon = GetIconPath() + "/" + LIGHT_STYLE +".svg"; + _themes->setIcon(QIcon(icon)); } void TrigBar::on_actionLissajous_triggered() diff --git a/DSView/pv/view/devmode.cpp b/DSView/pv/view/devmode.cpp index 48e36f81..9ca629b1 100755 --- a/DSView/pv/view/devmode.cpp +++ b/DSView/pv/view/devmode.cpp @@ -111,18 +111,20 @@ void DevMode::set_device() l; l = l->next) { const sr_dev_mode *mode = (const sr_dev_mode *)l->data; QString icon_name = QString::fromLocal8Bit(mode->icon); - + QAction *action = new QAction(this); action->setIcon(QIcon(iconPath+"square-"+icon_name)); if (lan == QLocale::Chinese) action->setText(mode->name_cn); else action->setText(mode->name); + connect(action, SIGNAL(triggered()), this, SLOT(on_mode_change())); _mode_list[action] = mode; if (dev_inst->dev_inst()->mode == _mode_list[action]->mode) { - _mode_btn->setIcon(QIcon(iconPath+icon_name)); + QString icon_fname = iconPath + icon_name; + _mode_btn->setIcon(QIcon(icon_fname)); if (lan== QLocale::Chinese) _mode_btn->setText(mode->name_cn); else @@ -176,8 +178,9 @@ void DevMode::on_mode_change() SR_CONF_DEVICE_MODE, g_variant_new_int16((*i).second->mode)); - QString icon_name = "/" + QString::fromLocal8Bit((*i).second->icon); - _mode_btn->setIcon(QIcon(iconPath+icon_name)); + QString icon_fname = iconPath + "/" + QString::fromLocal8Bit((*i).second->icon); + + _mode_btn->setIcon(QIcon(icon_fname)); if (lan == QLocale::Chinese) _mode_btn->setText((*i).second->name_cn); else diff --git a/DSView/pv/view/mathtrace.cpp b/DSView/pv/view/mathtrace.cpp index c8f6753c..78a34280 100755 --- a/DSView/pv/view/mathtrace.cpp +++ b/DSView/pv/view/mathtrace.cpp @@ -31,8 +31,8 @@ #include "../sigsession.h" #include "../device/devinst.h" #include "../view/dsosignal.h" - - +#include "../dsvdef.h" + #include #include @@ -67,6 +67,7 @@ MathTrace::MathTrace(bool enable,data::MathStack *math_stack, MathTrace::~MathTrace() { + DESTROY_OBJECT(_math_stack); } bool MathTrace::enabled() diff --git a/DSView/pv/view/spectrumtrace.cpp b/DSView/pv/view/spectrumtrace.cpp index 6f7ceba3..3115bf33 100755 --- a/DSView/pv/view/spectrumtrace.cpp +++ b/DSView/pv/view/spectrumtrace.cpp @@ -33,6 +33,7 @@ #include "../view/viewport.h" #include "../device/devinst.h" #include "../data/spectrumstack.h" +#include "../dsvdef.h" using namespace boost; using namespace std; @@ -90,7 +91,7 @@ SpectrumTrace::SpectrumTrace(pv::SigSession *session, SpectrumTrace::~SpectrumTrace() { - + DESTROY_OBJECT(_spectrum_stack); } bool SpectrumTrace::enabled() From 01b9aee7788540c1d1a6b6520825de2b59eae1ab Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Tue, 9 Nov 2021 15:36:47 +0800 Subject: [PATCH 23/60] none --- DSView/pv/device/devinst.cpp | 4 ++-- DSView/pv/devicemanager.h | 3 --- DSView/pv/mainwindow.cpp | 5 +++-- DSView/pv/view/analogsignal.cpp | 1 - DSView/pv/view/devmode.cpp | 7 +++++-- DSView/pv/view/dsosignal.cpp | 8 ++------ DSView/pv/view/groupsignal.cpp | 3 +-- DSView/pv/view/header.cpp | 7 ++----- DSView/pv/view/lissajoustrace.cpp | 2 +- DSView/pv/view/ruler.cpp | 3 +-- DSView/pv/view/viewport.cpp | 3 +-- DSView/pv/view/viewstatus.cpp | 2 +- DSView/pv/view/xcursor.cpp | 4 +--- libsigrokdecode4DSL/srd.c | 2 +- 14 files changed, 21 insertions(+), 33 deletions(-) diff --git a/DSView/pv/device/devinst.cpp b/DSView/pv/device/devinst.cpp index b0bf7d5a..1fe1b2f4 100755 --- a/DSView/pv/device/devinst.cpp +++ b/DSView/pv/device/devinst.cpp @@ -214,8 +214,8 @@ bool DevInst::is_usable() } void DevInst::destroy(){ - release(); - delete this; + release(); + //delete this; //do not to destroy } } // device diff --git a/DSView/pv/devicemanager.h b/DSView/pv/devicemanager.h index 4862a455..79f3502d 100755 --- a/DSView/pv/devicemanager.h +++ b/DSView/pv/devicemanager.h @@ -29,9 +29,6 @@ #include #include #include - -#include - #include #include diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index 5186f719..0ca0bc70 100755 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -599,8 +599,9 @@ void MainWindow::device_changed(bool close) _sampling_bar->set_sampling(false); _session->set_default_device(boost::bind(&MainWindow::session_error, this, QString(tr("Set Default Device failed")), _1)); - } - update_device_list(); + } + + update_device_list(); } void MainWindow::on_run_stop() diff --git a/DSView/pv/view/analogsignal.cpp b/DSView/pv/view/analogsignal.cpp index 0368932f..745834ad 100755 --- a/DSView/pv/view/analogsignal.cpp +++ b/DSView/pv/view/analogsignal.cpp @@ -30,7 +30,6 @@ #include "../view/view.h" #include "../device/devinst.h" -using namespace boost; using namespace std; #define byte(x) uint##x##_t diff --git a/DSView/pv/view/devmode.cpp b/DSView/pv/view/devmode.cpp index 9ca629b1..58b31fe5 100755 --- a/DSView/pv/view/devmode.cpp +++ b/DSView/pv/view/devmode.cpp @@ -35,6 +35,7 @@ #include #include #include "../config/appconfig.h" +#include "../ui/msgbox.h" namespace pv { @@ -196,8 +197,10 @@ void DevMode::on_close() DevInst *dev_inst = _session->get_device(); assert(dev_inst); - _session->close_file(dev_inst); - dev_changed(true); + if (MsgBox::Confirm("are you sure to close the device?")){ + _session->close_file(dev_inst); + dev_changed(true); + } } void DevMode::mousePressEvent(QMouseEvent *event) diff --git a/DSView/pv/view/dsosignal.cpp b/DSView/pv/view/dsosignal.cpp index 3a33628e..f4d748ba 100755 --- a/DSView/pv/view/dsosignal.cpp +++ b/DSView/pv/view/dsosignal.cpp @@ -28,14 +28,10 @@ #include "pv/data/dsosnapshot.h" #include "view.h" #include "../sigsession.h" -#include "../device/devinst.h" - - - +#include "../device/devinst.h" #include #include - -using namespace boost; + using namespace std; namespace pv { diff --git a/DSView/pv/view/groupsignal.cpp b/DSView/pv/view/groupsignal.cpp index 0c5870aa..898d455c 100755 --- a/DSView/pv/view/groupsignal.cpp +++ b/DSView/pv/view/groupsignal.cpp @@ -26,8 +26,7 @@ #include "pv/data/group.h" #include "pv/data/groupsnapshot.h" #include "view.h" - -using namespace boost; + using namespace std; namespace pv { diff --git a/DSView/pv/view/header.cpp b/DSView/pv/view/header.cpp index e5244e67..3eecd685 100755 --- a/DSView/pv/view/header.cpp +++ b/DSView/pv/view/header.cpp @@ -34,9 +34,7 @@ #include "../device/devinst.h" #include - - - + #include #include #include @@ -45,8 +43,7 @@ #include #include #include - -using namespace boost; + using namespace std; namespace pv { diff --git a/DSView/pv/view/lissajoustrace.cpp b/DSView/pv/view/lissajoustrace.cpp index 5e091820..81d8d33f 100755 --- a/DSView/pv/view/lissajoustrace.cpp +++ b/DSView/pv/view/lissajoustrace.cpp @@ -35,7 +35,7 @@ #include #include -using namespace boost; + using namespace std; namespace pv { diff --git a/DSView/pv/view/ruler.cpp b/DSView/pv/view/ruler.cpp index 41b9a98c..100292c4 100755 --- a/DSView/pv/view/ruler.cpp +++ b/DSView/pv/view/ruler.cpp @@ -40,8 +40,7 @@ #include #include - -using namespace boost; + using namespace std; namespace pv { diff --git a/DSView/pv/view/viewport.cpp b/DSView/pv/view/viewport.cpp index 95a2ff46..fcd8baad 100755 --- a/DSView/pv/view/viewport.cpp +++ b/DSView/pv/view/viewport.cpp @@ -42,8 +42,7 @@ #include "../config/appconfig.h" #include "../dsvdef.h" - -using namespace boost; + using namespace std; namespace pv { diff --git a/DSView/pv/view/viewstatus.cpp b/DSView/pv/view/viewstatus.cpp index cfad21d2..6ca30b86 100755 --- a/DSView/pv/view/viewstatus.cpp +++ b/DSView/pv/view/viewstatus.cpp @@ -34,7 +34,7 @@ #include "../view/trace.h" #include "../dialogs/dsomeasure.h" -using namespace boost; + using namespace std; namespace pv { diff --git a/DSView/pv/view/xcursor.cpp b/DSView/pv/view/xcursor.cpp index decdc14c..1148dfb5 100755 --- a/DSView/pv/view/xcursor.cpp +++ b/DSView/pv/view/xcursor.cpp @@ -28,9 +28,7 @@ #include "dsosignal.h" #include - - -using namespace boost; + using namespace std; namespace pv { diff --git a/libsigrokdecode4DSL/srd.c b/libsigrokdecode4DSL/srd.c index 6b2569d2..38bb803e 100755 --- a/libsigrokdecode4DSL/srd.c +++ b/libsigrokdecode4DSL/srd.c @@ -202,7 +202,7 @@ SRD_API int srd_init(const char *path) PyImport_AppendInittab("sigrokdecode", PyInit_sigrokdecode); /* Initialize the Python interpreter. */ - Py_InitializeEx(0); + Py_InitializeEx(0); /* Locations relative to the XDG system data directories. */ sys_datadirs = g_get_system_data_dirs(); From 21be857649f318d9721dcaa3be197db71a885b65 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Thu, 11 Nov 2021 18:41:12 +0800 Subject: [PATCH 24/60] remove SigSession qt signal mode, change to interface callback --- DSView/pv/data/decoderstack.cpp | 18 +- DSView/pv/data/decoderstack.h | 6 +- DSView/pv/data/mathstack.cpp | 9 +- DSView/pv/data/spectrumstack.cpp | 1 + DSView/pv/device/inputfile.cpp | 10 +- DSView/pv/dialogs/fftoptions.cpp | 2 + DSView/pv/dialogs/lissajousoptions.cpp | 1 + DSView/pv/dialogs/protocollist.cpp | 10 +- DSView/pv/dialogs/protocollist.h | 1 + DSView/pv/dock/dsotriggerdock.cpp | 1 + DSView/pv/dock/measuredock.cpp | 1 + DSView/pv/dock/protocoldock.cpp | 14 +- DSView/pv/dock/protocoldock.h | 7 +- DSView/pv/dock/triggerdock.cpp | 2 + DSView/pv/dstimer.cpp | 49 +++++ DSView/pv/dstimer.h | 37 ++++ DSView/pv/eventobject.cpp | 6 + DSView/pv/eventobject.h | 55 ++++++ DSView/pv/interface/icallbacks.h | 37 ++++ DSView/pv/interface/uicallback.h | 21 +++ DSView/pv/mainwindow.cpp | 239 +++++++++++++++++------- DSView/pv/mainwindow.h | 195 ++++++++++---------- DSView/pv/sigsession.cpp | 232 +++++++++++------------ DSView/pv/sigsession.h | 246 +++++++------------------ DSView/pv/storesession.cpp | 8 + DSView/pv/toolbars/filebar.cpp | 7 +- DSView/pv/toolbars/logobar.cpp | 1 + DSView/pv/toolbars/samplingbar.cpp | 6 +- DSView/pv/toolbars/trigbar.cpp | 8 +- DSView/pv/view/analogsignal.cpp | 3 +- DSView/pv/view/dsosignal.cpp | 10 +- DSView/pv/view/dsosignal.h | 7 +- DSView/pv/view/spectrumtrace.cpp | 3 +- DSView/pv/view/view.cpp | 31 ++-- DSView/pv/view/view.h | 94 +++++----- DSView/pv/view/viewport.cpp | 3 +- DSView/pv/view/viewport.h | 4 +- DSView/pv/view/viewstatus.cpp | 2 + 38 files changed, 797 insertions(+), 590 deletions(-) create mode 100644 DSView/pv/dstimer.cpp create mode 100644 DSView/pv/dstimer.h create mode 100644 DSView/pv/eventobject.cpp create mode 100644 DSView/pv/eventobject.h create mode 100644 DSView/pv/interface/icallbacks.h diff --git a/DSView/pv/data/decoderstack.cpp b/DSView/pv/data/decoderstack.cpp index 4c76ac7e..c53affa1 100755 --- a/DSView/pv/data/decoderstack.cpp +++ b/DSView/pv/data/decoderstack.cpp @@ -64,12 +64,8 @@ DecoderStack::DecoderStack(pv::SigSession *session, _no_memory = false; _mark_index = -1; _decoder_status = decoder_status; - _stask_stauts = NULL; - - connect(_session, SIGNAL(frame_began()), this, SLOT(on_new_frame())); - - connect(_session, SIGNAL(data_received()), this, SLOT(on_data_received())); - + _stask_stauts = NULL; + _stack.push_back(new decode::Decoder(dec)); build_row(); @@ -668,15 +664,7 @@ void DecoderStack::annotation_callback(srd_proto_data *pdata, void *decoder) if (!(*row_iter).second->push_annotation(a)) d->_no_memory = true; } - -void DecoderStack::on_new_frame() -{ -} - -void DecoderStack::on_data_received() -{ -} - + void DecoderStack::frame_ended() { _options_changed = true; diff --git a/DSView/pv/data/decoderstack.h b/DSView/pv/data/decoderstack.h index c8a2b929..cef31dab 100755 --- a/DSView/pv/data/decoderstack.h +++ b/DSView/pv/data/decoderstack.h @@ -172,11 +172,7 @@ private: static void annotation_callback(srd_proto_data *pdata, void *decoder); -private slots: - void on_new_frame(); - - void on_data_received(); - + signals: void new_decode_data(); void decode_done(); diff --git a/DSView/pv/data/mathstack.cpp b/DSView/pv/data/mathstack.cpp index 87dd08cd..9b2d9686 100755 --- a/DSView/pv/data/mathstack.cpp +++ b/DSView/pv/data/mathstack.cpp @@ -20,10 +20,11 @@ #include "mathstack.h" -#include -#include -#include -#include +#include "dso.h" +#include "dsosnapshot.h" +#include "../sigsession.h" +#include "../view/dsosignal.h" +#include #define PI 3.1415 diff --git a/DSView/pv/data/spectrumstack.cpp b/DSView/pv/data/spectrumstack.cpp index c5c48301..72759c7e 100755 --- a/DSView/pv/data/spectrumstack.cpp +++ b/DSView/pv/data/spectrumstack.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #define PI 3.1415 diff --git a/DSView/pv/device/inputfile.cpp b/DSView/pv/device/inputfile.cpp index 33b346bf..83ed6995 100755 --- a/DSView/pv/device/inputfile.cpp +++ b/DSView/pv/device/inputfile.cpp @@ -51,15 +51,7 @@ void InputFile::use(SigSession *owner) // only *.dsl file is valid // don't allow other types of file input throw tr("Not a valid DSView data file."); - return; - -// _input = load_input_file_format(_path, NULL); -// File::use(owner); - -// sr_session_new(); - -// if (sr_session_dev_add(_input->sdi) != SR_OK) -// throw tr("Failed to add session device."); + return; } void InputFile::release() diff --git a/DSView/pv/dialogs/fftoptions.cpp b/DSView/pv/dialogs/fftoptions.cpp index 425854c0..5b8f44d7 100755 --- a/DSView/pv/dialogs/fftoptions.cpp +++ b/DSView/pv/dialogs/fftoptions.cpp @@ -24,6 +24,7 @@ #include #include +#include #include "../sigsession.h" #include "../data/spectrumstack.h" @@ -31,6 +32,7 @@ #include "../view/dsosignal.h" #include "../view/spectrumtrace.h" + using namespace boost; using namespace std; diff --git a/DSView/pv/dialogs/lissajousoptions.cpp b/DSView/pv/dialogs/lissajousoptions.cpp index 4ab1d3c2..8f8456be 100755 --- a/DSView/pv/dialogs/lissajousoptions.cpp +++ b/DSView/pv/dialogs/lissajousoptions.cpp @@ -30,6 +30,7 @@ #include #include #include +#include using namespace boost; diff --git a/DSView/pv/dialogs/protocollist.cpp b/DSView/pv/dialogs/protocollist.cpp index 9f474fa8..4b094d90 100755 --- a/DSView/pv/dialogs/protocollist.cpp +++ b/DSView/pv/dialogs/protocollist.cpp @@ -49,11 +49,13 @@ ProtocolList::ProtocolList(QWidget *parent, SigSession *session) : _map_zoom_combobox->addItem(tr("Fit to Window")); _map_zoom_combobox->addItem(tr("Fixed")); int cur_map_zoom = _session->get_map_zoom(); + if (cur_map_zoom >= _map_zoom_combobox->count()) _map_zoom_combobox->setCurrentIndex(0); else _map_zoom_combobox->setCurrentIndex(cur_map_zoom); - connect(_map_zoom_combobox, SIGNAL(currentIndexChanged(int)), _session, SLOT(set_map_zoom(int))); + + connect(_map_zoom_combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(on_set_map_zoom(int))); _protocol_combobox = new QComboBox(this); auto &decode_sigs = _session->get_decode_signals(); @@ -193,5 +195,11 @@ void ProtocolList::on_row_check(bool show) _session->get_decoder_model()->setDecoderStack(decoder_stack); } + + void ProtocolList::on_set_map_zoom(int index) + { + _session->set_map_zoom(index); + } + } // namespace dialogs } // namespace pv diff --git a/DSView/pv/dialogs/protocollist.h b/DSView/pv/dialogs/protocollist.h index 0d4024d9..f53dfcfa 100755 --- a/DSView/pv/dialogs/protocollist.h +++ b/DSView/pv/dialogs/protocollist.h @@ -56,6 +56,7 @@ protected: private slots: void set_protocol(int index); void on_row_check(bool show); + void on_set_map_zoom(int index); private: SigSession *_session; diff --git a/DSView/pv/dock/dsotriggerdock.cpp b/DSView/pv/dock/dsotriggerdock.cpp index 03e1a8ee..6d401770 100755 --- a/DSView/pv/dock/dsotriggerdock.cpp +++ b/DSView/pv/dock/dsotriggerdock.cpp @@ -35,6 +35,7 @@ #include #include #include +#include using namespace boost; using namespace std; diff --git a/DSView/pv/dock/measuredock.cpp b/DSView/pv/dock/measuredock.cpp index 5b6c77dd..f3b3f62a 100755 --- a/DSView/pv/dock/measuredock.cpp +++ b/DSView/pv/dock/measuredock.cpp @@ -308,6 +308,7 @@ void MeasureDock::reCalc() update_dist(); update_edge(); } + void MeasureDock::goto_cursor() { diff --git a/DSView/pv/dock/protocoldock.cpp b/DSView/pv/dock/protocoldock.cpp index 04888b4a..26afcc8b 100755 --- a/DSView/pv/dock/protocoldock.cpp +++ b/DSView/pv/dock/protocoldock.cpp @@ -176,33 +176,23 @@ ProtocolDock::ProtocolDock(QWidget *parent, view::View &view, SigSession *sessio _split_widget->setOrientation(Qt::Vertical); _split_widget->setCollapsible(0, false); _split_widget->setCollapsible(1, false); - //_split_widget->setStretchFactor(1, 1); - //_split_widget this->setWidgetResizable(true); this->setWidget(_split_widget); - //_split_widget->setGeometry(0, 0, sizeHint().width(), 500); + _split_widget->setObjectName("protocolWidget"); connect(_dn_nav_button, SIGNAL(clicked()),this, SLOT(nav_table_view())); - connect(_dn_save_button, SIGNAL(clicked()),this, SLOT(export_table_view())); - connect(_dn_set_button, SIGNAL(clicked()),this, SLOT(set_model())); - connect(_pre_button, SIGNAL(clicked()),this, SLOT(search_pre())); - connect(_nxt_button, SIGNAL(clicked()),this, SLOT(search_nxt())); - connect(_add_button, SIGNAL(clicked()),this, SLOT(on_add_protocol())); + connect(_del_all_button, SIGNAL(clicked()),this, SLOT(on_del_all_protocol())); - connect(_del_all_button, SIGNAL(clicked()),this, SLOT(on_del_all_protocol())); - - connect(_session, SIGNAL(decode_done()), this, SLOT(update_model())); connect(this, SIGNAL(protocol_updated()), this, SLOT(update_model())); connect(_table_view, SIGNAL(clicked(QModelIndex)), this, SLOT(item_clicked(QModelIndex))); connect(_table_view->horizontalHeader(), SIGNAL(sectionResized(int,int,int)), this, SLOT(column_resize(int, int, int))); - //connect(_table_view->verticalScrollBar(), SIGNAL(sliderMoved()), this, SLOT(sliderMoved())); connect(_search_edit, SIGNAL(editingFinished()), this, SLOT(search_changed())); retranslateUi(); diff --git a/DSView/pv/dock/protocoldock.h b/DSView/pv/dock/protocoldock.h index b300846a..a83df95b 100755 --- a/DSView/pv/dock/protocoldock.h +++ b/DSView/pv/dock/protocoldock.h @@ -72,6 +72,7 @@ public: void del_all_protocol(); bool sel_protocol(QString name); void add_protocol(bool silent); + private: void changeEvent(QEvent *event); void retranslateUi(); @@ -90,12 +91,14 @@ private: signals: void protocol_updated(); +public slots: + void update_model(); + private slots: void on_add_protocol(); void on_del_all_protocol(); void decoded_progress(int progress); - void set_model(); - void update_model(); + void set_model(); void export_table_view(); void nav_table_view(); void item_clicked(const QModelIndex &index); diff --git a/DSView/pv/dock/triggerdock.cpp b/DSView/pv/dock/triggerdock.cpp index d69b7828..87fa9e94 100755 --- a/DSView/pv/dock/triggerdock.cpp +++ b/DSView/pv/dock/triggerdock.cpp @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include "libsigrok4DSL/libsigrok.h" diff --git a/DSView/pv/dstimer.cpp b/DSView/pv/dstimer.cpp new file mode 100644 index 00000000..e3bbaad2 --- /dev/null +++ b/DSView/pv/dstimer.cpp @@ -0,0 +1,49 @@ + +#include "dstimer.h" +#include + +DsTimer::DsTimer(){ + _binded = false; +} + + void DsTimer::on_timeout() + { + _call(); //call back + } + +void DsTimer::TimeOut(int millsec, CALLBACL_FUNC f) +{ + _call = f; + QTimer::singleShot(millsec, this, SLOT(on_timeout())); +} + +void DsTimer::SetCallback(CALLBACL_FUNC f) + { + assert(!_binded); + _binded = true; + + _call = f; + connect(&_timer, SIGNAL(timeout()), this, SLOT(on_timeout())); + } + + void DsTimer::Start(int millsec, CALLBACL_FUNC f) + { + assert(!_binded); + _binded = true; + + _call = f; + connect(&_timer, SIGNAL(timeout()), this, SLOT(on_timeout())); + _timer.start(millsec); + } + + void DsTimer::Start(int millsec) + { + //check if connectb + assert(_binded); + _timer.start(millsec); + } + + void DsTimer::Stop() + { + _timer.stop(); + } diff --git a/DSView/pv/dstimer.h b/DSView/pv/dstimer.h new file mode 100644 index 00000000..87c35f41 --- /dev/null +++ b/DSView/pv/dstimer.h @@ -0,0 +1,37 @@ + +#ifndef _DS_TIMER_H +#define _DS_TIMER_H + +#include +#include +#include + +typedef std::function CALLBACL_FUNC; + +class DsTimer : public QObject +{ + Q_OBJECT + +public: + DsTimer(); + + void TimeOut(int millsec, CALLBACL_FUNC f); + + void SetCallback(CALLBACL_FUNC f); + + void Start(int millsec, CALLBACL_FUNC f); + + void Start(int millsec); + + void Stop(); + +private slots: + void on_timeout(); + +private: + CALLBACL_FUNC _call; + QTimer _timer; + bool _binded; +}; + +#endif diff --git a/DSView/pv/eventobject.cpp b/DSView/pv/eventobject.cpp new file mode 100644 index 00000000..d8671fa3 --- /dev/null +++ b/DSView/pv/eventobject.cpp @@ -0,0 +1,6 @@ + +#include "eventobject.h" + +EventObject::EventObject(){ + +} \ No newline at end of file diff --git a/DSView/pv/eventobject.h b/DSView/pv/eventobject.h new file mode 100644 index 00000000..770b884d --- /dev/null +++ b/DSView/pv/eventobject.h @@ -0,0 +1,55 @@ + +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2012 Joel Holdsworth + * Copyright (C) 2013 DreamSourceLab + * + * 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 + */ + +#ifndef _EVENT_OBJECT_H +#define _EVENT_OBJECT_H + +#include + +class EventObject : public QObject +{ + Q_OBJECT + +public: + EventObject(); + + +signals: + void show_error(QString error); + void capture_state_changed(int state); + void data_updated(); + void device_attach(); + void device_detach(); + + void session_error(); + void signals_changed(); + void receive_trigger(quint64 trigger_pos); + void frame_ended(); + void frame_began(); + + void decode_done(); + void receive_data_len(quint64 len); + void cur_snap_samplerate_changed(); +}; + +#endif \ No newline at end of file diff --git a/DSView/pv/interface/icallbacks.h b/DSView/pv/interface/icallbacks.h new file mode 100644 index 00000000..1d1627c3 --- /dev/null +++ b/DSView/pv/interface/icallbacks.h @@ -0,0 +1,37 @@ + +#ifndef _I_CALLBACKS_ +#define _I_CALLBACKS_ + +class ISessionCallback +{ +public: + virtual void show_error(QString error)=0; + virtual void session_error()=0; + virtual void capture_state_changed(int state)=0; + virtual void device_attach()=0; + virtual void device_detach()=0; + + virtual void session_save()=0; + virtual void data_updated()=0; + virtual void repeat_resume()=0; + virtual void update_capture()=0; + virtual void cur_snap_samplerate_changed()=0; + + virtual void device_setted()=0; + virtual void signals_changed()=0; + virtual void receive_trigger(quint64 trigger_pos)=0; + virtual void frame_ended()=0; + virtual void frame_began()=0; + + virtual void show_region(uint64_t start, uint64_t end, bool keep)=0; + virtual void show_wait_trigger()=0; + virtual void repeat_hold(int percent)=0; + virtual void decode_done()=0; + virtual void receive_data_len(quint64 len)=0; + + virtual void receive_header()=0; + virtual void data_received()=0; + +}; + +#endif diff --git a/DSView/pv/interface/uicallback.h b/DSView/pv/interface/uicallback.h index 8af7964b..b7ae0054 100644 --- a/DSView/pv/interface/uicallback.h +++ b/DSView/pv/interface/uicallback.h @@ -1,4 +1,25 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2014 Joel Holdsworth + * + * 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 + */ + #pragma once class IDlgCallback diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index 0ca0bc70..2c711e74 100755 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -24,10 +24,7 @@ #include #include "dock/protocoldock.h" - - -#include - + #include #include #include @@ -91,7 +88,7 @@ #include "../ui/msgbox.h" #include "config/appconfig.h" #include "appcontrol.h" - + namespace pv { @@ -101,6 +98,7 @@ MainWindow::MainWindow(QWidget *parent) : _msg(NULL) { _control = AppControl::Instance(); + _control->GetSession()->set_callback(this); setup_ui(); @@ -233,8 +231,7 @@ void MainWindow::setup_ui() _search_dock->installEventFilter(this); // Populate the device list and select the initially selected device - _session->set_default_device(boost::bind(&MainWindow::session_error, this, - QString(tr("Set Default Device failed")), _1)); + _session->set_default_device(); // defaut language AppConfig &app = AppConfig::Instance(); @@ -247,22 +244,25 @@ void MainWindow::setup_ui() // update device update_device_list(); - _session->start_hotplug_work(boost::bind(&MainWindow::session_error, this, - QString(tr("Hotplug failed")), _1)); + _session->start_hotplug_work(); retranslateUi(); + //event + connect(&_event, SIGNAL(capture_state_changed(int)), this, SLOT(on_capture_state_changed(int))); + connect(&_event, SIGNAL(device_attach()), this, SLOT(on_device_attach())); + connect(&_event, SIGNAL(device_detach()), this, SLOT(on_device_detach())); + connect(&_event, SIGNAL(session_error()), this, SLOT(on_session_error())); + connect(&_event, SIGNAL(show_error(QString)), this, SLOT(on_show_error(QString))); + connect(&_event, SIGNAL(signals_changed()), this, SLOT(on_signals_changed())); + connect(&_event, SIGNAL(receive_trigger(quint64)), this, SLOT(on_receive_trigger(quint64))); + connect(&_event, SIGNAL(frame_ended()), this, SLOT(on_frame_ended())); + connect(&_event, SIGNAL(frame_began()), this, SLOT(on_frame_began())); + connect(&_event, SIGNAL(decode_done()), this, SLOT(on_decode_done())); + connect(&_event, SIGNAL(data_updated()), this, SLOT(on_data_updated())); + connect(&_event, SIGNAL(cur_snap_samplerate_changed()), this, SLOT(on_cur_snap_samplerate_changed())); + connect(&_event, SIGNAL(receive_data_len(quint64)), this, SLOT(on_receive_data_len(quint64))); - // Setup _session events - connect(_session, SIGNAL(capture_state_changed(int)), this, SLOT(capture_state_changed(int))); - connect(_session, SIGNAL(device_attach()), this, SLOT(device_attach()), Qt::QueuedConnection); - connect(_session, SIGNAL(device_detach()), this, SLOT(device_detach()), Qt::QueuedConnection); - connect(_session, SIGNAL(session_error()), this, SLOT(on_show_error()), Qt::QueuedConnection); - connect(_session, SIGNAL(session_save()), this, SLOT(session_save())); - connect(_session, SIGNAL(data_updated()), _measure_widget, SLOT(reCalc())); - connect(_session, SIGNAL(repeat_resume()), this, SLOT(repeat_resume())); - connect(_session, SIGNAL(update_capture()), _view, SLOT(update_hori_res()), Qt::DirectConnection); - connect(_session, SIGNAL(cur_snap_samplerate_changed()), _measure_widget, SLOT(cursor_update())); //view connect(_view, SIGNAL(cursor_update()), _measure_widget, SLOT(cursor_update())); @@ -293,7 +293,7 @@ void MainWindow::setup_ui() connect(_logo_bar, SIGNAL(sig_open_doc()), this, SLOT(on_open_doc())); - connect(_protocol_widget, SIGNAL(protocol_updated()), _view, SLOT(signals_changed())); + connect(_protocol_widget, SIGNAL(protocol_updated()), this, SLOT(on_signals_changed())); //SamplingBar connect(_sampling_bar, SIGNAL(sig_device_selected()), this, SLOT(on_device_selected())); @@ -304,8 +304,7 @@ void MainWindow::setup_ui() connect(_sampling_bar, SIGNAL(sig_duration_changed()), _view, SLOT(timebase_changed())); connect(_sampling_bar, SIGNAL(sig_show_calibration()), _view, SLOT(show_calibration())); - connect(_dso_trigger_widget, SIGNAL(set_trig_pos(int)), _view, SLOT(set_trig_pos(int))); - + connect(_dso_trigger_widget, SIGNAL(set_trig_pos(int)), _view, SLOT(set_trig_pos(int))); } @@ -318,14 +317,7 @@ void MainWindow::retranslateUi() _search_dock->setWindowTitle(tr("Search...")); } -void MainWindow::session_error( - const QString text, const QString info_text) -{ - QMetaObject::invokeMethod(this, "show_session_error", - Qt::QueuedConnection, Q_ARG(QString, text), - Q_ARG(QString, info_text)); -} - + void MainWindow::on_device_selected() { update_device_list(); @@ -367,8 +359,7 @@ void MainWindow::update_device_list() int16_t version = g_variant_get_int16(gvar); g_variant_unref(gvar); if (version == 1) { - show_session_error(tr("Attension"), - tr("Current loading file has an old format. " + show_error(tr("Current loading file has an old format. " "This will lead to a slow loading speed. " "Please resave it after loaded.")); } @@ -386,8 +377,7 @@ void MainWindow::update_device_list() // load data const QString errorMessage( QString(tr("Failed to capture file data!"))); - _session->start_capture(true, boost::bind(&MainWindow::session_error, this, - errorMessage, _1)); + _session->start_capture(true); } if (!selected_device->name().contains("virtual")) { @@ -448,9 +438,8 @@ void MainWindow::update_device_list() g_variant_unref(gvar); if (usb30_support && usb_speed == LIBUSB_SPEED_HIGH) - show_session_error(tr("Speed limited"), tr("This is a super-speed usb device(USB 3.0). " - "Plug it into a USB 2.0 port will seriously affect its performance." - "Please replug it into a USB 3.0 port.")); + show_error("Plug it into a USB 2.0 port will seriously affect its performance." + "Please replug it into a USB 3.0 port."); } } } @@ -473,9 +462,8 @@ void MainWindow::on_load_file(QString file_name) session_save(); _session->set_file(file_name); } catch(QString e) { - show_session_error(tr("Failed to load ") + file_name, e); - _session->set_default_device(boost::bind(&MainWindow::session_error, this, - QString(tr("Set Default Device failed")), _1)); + show_error(tr("Failed to load ") + file_name); + _session->set_default_device(); update_device_list(); return; } @@ -483,26 +471,27 @@ void MainWindow::on_load_file(QString file_name) update_device_list(); } -void MainWindow::show_session_error( - const QString text, const QString info_text) +void MainWindow::show_error(QString error) { - dialogs::DSMessageBox msg(this); - _msg = &msg; - msg.mBox()->setText(text); - msg.mBox()->setInformativeText(info_text); - msg.mBox()->setStandardButtons(QMessageBox::Ok); - msg.mBox()->setIcon(QMessageBox::Warning); - msg.exec(); - _msg = NULL; + _event.show_error(error); //safe call +} + +void MainWindow::on_show_error(QString error) +{ + MsgBox::Show(NULL, error.toStdString().c_str(), this); } void MainWindow::device_attach() +{ + _event.device_attach(); //safe call +} + +void MainWindow::on_device_attach() { SigSession *_session = _control->GetSession(); _session->get_device()->device_updated(); - //_session->stop_hot_plug_proc(); - + _session->set_repeating(false); _session->stop_capture(); _sampling_bar->set_sampling(false); @@ -521,14 +510,15 @@ void MainWindow::device_attach() } } - - _session->set_default_device(boost::bind(&MainWindow::session_error, this, - QString(tr("Set Default Device failed")), _1)); + _session->set_default_device(); update_device_list(); - } -void MainWindow::device_detach() +void MainWindow::device_detach(){ + _event.device_detach(); //safe call +} + +void MainWindow::on_device_detach() { SigSession *_session = _control->GetSession(); @@ -586,8 +576,7 @@ void MainWindow::device_detach_post() } } - _session->set_default_device(boost::bind(&MainWindow::session_error, this, - QString(tr("Set Default Device failed")), _1)); + _session->set_default_device(); update_device_list(); } @@ -597,24 +586,21 @@ void MainWindow::device_changed(bool close) if (close) { _sampling_bar->set_sampling(false); - _session->set_default_device(boost::bind(&MainWindow::session_error, this, - QString(tr("Set Default Device failed")), _1)); + _session->set_default_device(); } update_device_list(); } void MainWindow::on_run_stop() -{ +{ SigSession *_session = _control->GetSession(); switch(_session->get_capture_state()) { case SigSession::Init: case SigSession::Stopped: commit_trigger(false); - _session->start_capture(false, - boost::bind(&MainWindow::session_error, this, - QString(tr("Capture failed")), _1)); + _session->start_capture(false); _view->capture_init(); break; @@ -632,9 +618,7 @@ void MainWindow::on_instant_stop() case SigSession::Init: case SigSession::Stopped: commit_trigger(true); - _session->start_capture(true, - boost::bind(&MainWindow::session_error, this, - QString(tr("Capture failed")), _1)); + _session->start_capture(true); _view->capture_init(); break; @@ -651,7 +635,12 @@ void MainWindow::repeat_resume() on_run_stop(); } -void MainWindow::on_show_error() +void MainWindow::session_error() +{ + _event.session_error(); +} + +void MainWindow::on_session_error() { QString title; QString details; @@ -725,6 +714,11 @@ void MainWindow::on_show_error() } void MainWindow::capture_state_changed(int state) +{ + _event.capture_state_changed(state);//safe call +} + +void MainWindow::on_capture_state_changed(int state) { SigSession *_session = _control->GetSession(); @@ -1441,8 +1435,17 @@ void MainWindow::switchTheme(QString style) qApp->setStyleSheet(qss.readAll()); qss.close(); - SigSession *_session = _control->GetSession(); - _session->data_updated(); + data_updated(); +} + +void MainWindow::data_updated() +{ + _event.data_updated(); //safe call +} + +void MainWindow::on_data_updated(){ + _measure_widget->reCalc(); + _view->data_updated(); } void MainWindow::on_open_doc(){ @@ -1463,4 +1466,98 @@ void MainWindow::openDoc() QUrl("file:///"+dir.absolutePath() + "/ug"+QString::number(lan)+".pdf")); } +void MainWindow::update_capture(){ + _view->update_hori_res(); +} + +void MainWindow::cur_snap_samplerate_changed(){ + _event.cur_snap_samplerate_changed(); //safe call +} + +void MainWindow::on_cur_snap_samplerate_changed() +{ + _measure_widget->cursor_update(); +} + +void MainWindow::device_setted(){ + _view->set_device(); +} + + void MainWindow::signals_changed() + { + _event.signals_changed(); //safe call + } + + void MainWindow::on_signals_changed() + { + _view->signals_changed(); + } + + void MainWindow::receive_trigger(quint64 trigger_pos) + { + _event.receive_trigger(trigger_pos); //save call + } + + void MainWindow::on_receive_trigger(quint64 trigger_pos) + { + _view->receive_trigger(trigger_pos); + } + + void MainWindow::frame_ended() + { + _event.frame_ended(); //save call + } + + void MainWindow::on_frame_ended() + { + _view->receive_end(); + } + + void MainWindow::frame_began() + { + _event.frame_began(); //save call + } + + void MainWindow::on_frame_began() + { + _view->frame_began(); + } + + void MainWindow::show_region(uint64_t start, uint64_t end, bool keep){ + _view->show_region(start, end, keep); + } + + void MainWindow::show_wait_trigger(){ + _view->show_wait_trigger(); + } + + void MainWindow::repeat_hold(int percent){ + (void)percent; + _view->repeat_show(); + } + + void MainWindow::decode_done(){ + _event.decode_done(); //safe call + } + + void MainWindow::on_decode_done(){ + _protocol_widget->update_model(); + } + + void MainWindow::receive_data_len(quint64 len){ + _event.receive_data_len(len);//safe call + } + +void MainWindow::on_receive_data_len(quint64 len){ + _view->set_receive_len(len); +} + +void MainWindow::receive_header(){ + +} + +void MainWindow::data_received(){ + +} + } // namespace pv diff --git a/DSView/pv/mainwindow.h b/DSView/pv/mainwindow.h index 68f2dd6d..446844b7 100755 --- a/DSView/pv/mainwindow.h +++ b/DSView/pv/mainwindow.h @@ -25,11 +25,11 @@ #define DSVIEW_PV_MAINWINDOW_H #include - #include -#include - +#include #include "dialogs/dsmessagebox.h" +#include "interface/icallbacks.h" +#include "eventobject.h" class QAction; class QMenuBar; @@ -72,153 +72,148 @@ using namespace pv::device; //The mainwindow,referenced by MainFrame //TODO: create graph view,toolbar,and show device list -class MainWindow : public QMainWindow +class MainWindow : public QMainWindow, public ISessionCallback { Q_OBJECT private: static constexpr int Session_Version = 2; - + public: - explicit MainWindow(QWidget *parent = 0); + explicit MainWindow(QWidget *parent = 0); -protected: - void closeEvent(QCloseEvent *event); - -public: void openDoc(); - void switchLanguage(int language); private: + void closeEvent(QCloseEvent *event); + void setup_ui(); - void retranslateUi(); - void session_error(const QString text, const QString info_text); + void retranslateUi(); bool eventFilter(QObject *object, QEvent *event); - bool load_session_json(QJsonDocument json, bool file_dev,bool bDecoder=true); - void update_device_list(); -public slots: - void session_save(); - +public slots: void switchTheme(QString style); - void restore_dock(); private slots: void on_load_file(QString file_name); - - void on_open_doc(); - - /** - * Updates the device list in the sampling bar, and updates the - * selection. - * @param selected_device The device to select, or NULL if the - * first device in the device list should be selected. - */ - - + void on_open_doc(); void on_device_updated_reload(); - - void show_session_error(const QString text, const QString info_text); - + void on_run_stop(); - - void on_instant_stop(); - - void capture_state_changed(int state); - + void on_instant_stop(); void on_protocol(bool visible); - void on_trigger(bool visible); - void commit_trigger(bool instant); void on_measure(bool visible); - void on_search(bool visible); - void on_screenShot(); - void on_save(); void on_export(); - - bool on_load_session(QString name); - - bool on_store_session(QString name); - - /* - * repeat - */ - void repeat_resume(); - - /* - * hotplug slot function - */ - void device_attach(); - void device_detach(); + bool on_load_session(QString name); + bool on_store_session(QString name); void device_detach_post(); void device_changed(bool close); - void on_device_selected(); - - /* - * errors - */ - void on_show_error(); - + void on_device_selected(); void on_setLanguage(int language); + + void on_capture_state_changed(int state); + void on_data_updated(); + void on_device_attach(); + void on_device_detach(); + void on_show_error(QString str); + void on_session_error(); + void on_signals_changed(); + void on_receive_trigger(quint64 trigger_pos); + void on_frame_ended(); + void on_frame_began(); + void on_decode_done(); + void on_receive_data_len(quint64 len); + void on_cur_snap_samplerate_changed(); signals: void prgRate(int progress); +//ISessionCallback +public: + void session_save(); + +//ISessionCallback private: - AppControl *_control; - bool _hot_detach; + void show_error(QString error); + void session_error(); + void capture_state_changed(int state); + void device_attach(); + void device_detach(); - pv::view::View *_view; - dialogs::DSMessageBox *_msg; + void data_updated(); + void repeat_resume(); + void update_capture(); + void cur_snap_samplerate_changed(); + void device_setted(); - QMenuBar *_menu_bar; - QMenu *_menu_file; - QAction *_action_open; - QAction *_action_connect; - QAction *_action_quit; + void signals_changed(); + void receive_trigger(quint64 trigger_pos); + void frame_ended(); + void frame_began(); + void show_region(uint64_t start, uint64_t end, bool keep); - QMenu *_menu_view; - QAction *_action_view_zoom_in; - QAction *_action_view_zoom_out; - QAction *_action_view_show_cursors; + void show_wait_trigger(); + void repeat_hold(int percent); + void decode_done(); + void receive_data_len(quint64 len); + void receive_header(); + void data_received(); - QMenu *_menu_help; - QAction *_action_about; +private: + AppControl *_control; + bool _hot_detach; - QWidget *_central_widget; - QVBoxLayout *_vertical_layout; + pv::view::View *_view; + dialogs::DSMessageBox *_msg; - toolbars::SamplingBar *_sampling_bar; - toolbars::TrigBar *_trig_bar; - toolbars::FileBar *_file_bar; - toolbars::LogoBar *_logo_bar; //help button, on top right + QMenuBar *_menu_bar; + QMenu *_menu_file; + QAction *_action_open; + QAction *_action_connect; + QAction *_action_quit; + + QMenu *_menu_view; + QAction *_action_view_zoom_in; + QAction *_action_view_zoom_out; + QAction *_action_view_show_cursors; + + QMenu *_menu_help; + QAction *_action_about; + + QWidget *_central_widget; + QVBoxLayout *_vertical_layout; + + toolbars::SamplingBar *_sampling_bar; + toolbars::TrigBar *_trig_bar; + toolbars::FileBar *_file_bar; + toolbars::LogoBar *_logo_bar; //help button, on top right - QDockWidget *_protocol_dock; - dock::ProtocolDock *_protocol_widget; + QDockWidget *_protocol_dock; + dock::ProtocolDock *_protocol_widget; + QDockWidget *_trigger_dock; + QDockWidget *_dso_trigger_dock; + dock::TriggerDock *_trigger_widget; + dock::DsoTriggerDock *_dso_trigger_widget; + QDockWidget *_measure_dock; + dock::MeasureDock *_measure_widget; + QDockWidget *_search_dock; + dock::SearchDock *_search_widget; - - QDockWidget *_trigger_dock; - QDockWidget *_dso_trigger_dock; - dock::TriggerDock *_trigger_widget; - dock::DsoTriggerDock *_dso_trigger_widget; - QDockWidget *_measure_dock; - dock::MeasureDock *_measure_widget; - QDockWidget *_search_dock; - dock::SearchDock * _search_widget; - - QTranslator _qtTrans; - QTranslator _myTrans; + QTranslator _qtTrans; + QTranslator _myTrans; + EventObject _event; }; } // namespace pv diff --git a/DSView/pv/sigsession.cpp b/DSView/pv/sigsession.cpp index a42432db..99a41300 100755 --- a/DSView/pv/sigsession.cpp +++ b/DSView/pv/sigsession.cpp @@ -23,7 +23,6 @@ #include - #include "sigsession.h" #include "mainwindow.h" #include "devicemanager.h" @@ -55,23 +54,13 @@ #include #include -#include - +#include #include -#include -#include -#include -#include -#include -#include -#include - +#include #include "data/decode/decoderstatus.h" #include "dsvdef.h" - -using namespace boost; namespace pv { @@ -103,7 +92,7 @@ SigSession::SigSession(DeviceManager *device_manager) _data_lock = false; _data_updated = false; - _decoder_model = new pv::data::DecoderModel(this); + _decoder_model = new pv::data::DecoderModel(NULL); _lissajous_trace = NULL; _math_trace = NULL; @@ -112,6 +101,7 @@ SigSession::SigSession(DeviceManager *device_manager) _stop_scale = 1; _bDecodeRunning = false; _bClose = false; + _callback = NULL; // Create snapshots & data containers _logic_data = new data::Logic(new data::LogicSnapshot()); @@ -120,12 +110,11 @@ SigSession::SigSession(DeviceManager *device_manager) _group_data = new data::Group(); _group_cnt = 0; - _feed_timer.stop(); - - connect(&_feed_timer, SIGNAL(timeout()), this, SLOT(feed_timeout())); + _feed_timer.Stop(); + _feed_timer.SetCallback(std::bind(&SigSession::feed_timeout, this)); } -//SigSession::SigSession(SigSession &o){(void)o;} +SigSession::SigSession(SigSession &o){(void)o;} SigSession::~SigSession() { @@ -181,7 +170,7 @@ void SigSession::set_device(DevInst *dev_inst) return; } sr_session_datafeed_callback_add(data_feed_in_proc, NULL); - device_setted(); + _callback->device_setted(); } } @@ -217,7 +206,7 @@ void SigSession::close_file(DevInst *dev_inst) } } -void SigSession::set_default_device(boost::function error_handler) +void SigSession::set_default_device() { assert(_device_manager); @@ -240,7 +229,7 @@ void SigSession::set_default_device(boost::function error_ try { set_device(default_device); } catch(const QString e) { - error_handler(e); + _callback->show_error(e); return; } } @@ -252,14 +241,14 @@ void SigSession::release_device(DevInst *dev_inst) return; assert(dev_inst); - assert(_dev_inst == dev_inst); + // assert(_dev_inst == dev_inst); assert(get_capture_state() != Running); _dev_inst = NULL; } SigSession::capture_state SigSession::get_capture_state() -{ +{ std::lock_guard lock(_sampling_mutex); return _capture_state; } @@ -327,7 +316,7 @@ void SigSession::set_cur_snap_samplerate(uint64_t samplerate) for(auto & m : _spectrum_traces) m->get_spectrum_stack()->set_samplerate(_cur_snap_samplerate); - cur_snap_samplerate_changed(); + _callback->cur_snap_samplerate_changed(); } void SigSession::set_cur_samplelimits(uint64_t samplelimits) @@ -343,7 +332,7 @@ void SigSession::capture_init() set_repeating(get_run_mode() == Repetitive); // update instant setting _dev_inst->set_config(NULL, NULL, SR_CONF_INSTANT, g_variant_new_boolean(_instant)); - update_capture(); + _callback->update_capture(); set_cur_snap_samplerate(_dev_inst->get_sample_rate()); set_cur_samplelimits(_dev_inst->get_sample_limit()); @@ -354,9 +343,9 @@ void SigSession::capture_init() _hw_replied = false; if (_dev_inst->dev_inst()->mode != LOGIC) - _feed_timer.start(FeedInterval); + _feed_timer.Start(FeedInterval); else - _feed_timer.stop(); + _feed_timer.Stop(); _noData_cnt = 0; data_unlock(); @@ -419,8 +408,7 @@ void SigSession::container_init() } -void SigSession::start_capture(bool instant, - boost::function error_handler) +void SigSession::start_capture(bool instant) { // Check that a device instance has been selected. if (!_dev_inst) { @@ -432,7 +420,7 @@ void SigSession::start_capture(bool instant, if (!_dev_inst->is_usable()) { _error = Hw_err; - session_error(); + _callback->session_error(); capture_state_changed(SigSession::Stopped); return; } @@ -468,7 +456,7 @@ void SigSession::start_capture(bool instant, break; } if (!l) { - error_handler(tr("No probes enabled.")); + _callback->show_error("No probes enabled."); data_updated(); set_repeating(false); capture_state_changed(SigSession::Stopped); @@ -478,29 +466,25 @@ void SigSession::start_capture(bool instant, if (_sampling_thread.joinable()){ _sampling_thread.join(); } - _sampling_thread = std::thread(&SigSession::sample_thread_proc, this, _dev_inst, error_handler); + _sampling_thread = std::thread(&SigSession::sample_thread_proc, this, _dev_inst); } -void SigSession::sample_thread_proc(DevInst *dev_inst, - boost::function error_handler) +void SigSession::sample_thread_proc(DevInst *dev_inst) { assert(dev_inst); assert(dev_inst->dev_inst()); - assert(error_handler); try { dev_inst->start(); } catch(const QString e) { - error_handler(e); + _callback->show_error(e); return; } receive_data(0); set_capture_state(Running); - dev_inst->run(); - set_capture_state(Stopped); // Confirm that SR_DF_END was received @@ -564,8 +548,7 @@ std::vector& SigSession::get_group_signals() } std::set SigSession::get_data() -{ - //lock_guard lock(_signals_mutex); +{ std::set data; for(auto &sig : _signals) { @@ -582,7 +565,7 @@ bool SigSession::get_instant() } void SigSession::set_capture_state(capture_state state) -{ +{ std::lock_guard lock(_sampling_mutex); _capture_state = state; data_updated(); @@ -766,7 +749,6 @@ void SigSession::init_signals() spectrum_rebuild(); lissajous_disable(); math_disable(); - //data_updated(); } void SigSession::reload() @@ -776,66 +758,72 @@ void SigSession::reload() if (_capture_state == Running) stop_capture(); - //refresh(0); std::vector sigs; view::Signal *signal = NULL; // Make the logic probe list + for (GSList *l = _dev_inst->dev_inst()->channels; l; l = l->next) { - for (GSList *l = _dev_inst->dev_inst()->channels; l; l = l->next) { - sr_channel *probe = - (sr_channel *)l->data; - assert(probe); - signal = NULL; + sr_channel *probe = + (sr_channel *)l->data; + assert(probe); + signal = NULL; - switch(probe->type) { - case SR_CHANNEL_LOGIC: - if (probe->enabled) { - auto i = _signals.begin(); - while (i != _signals.end()) { - if ((*i)->get_index() == probe->index) { - view::LogicSignal *logicSig = NULL; - if ((logicSig = dynamic_cast(*i))) - signal = new view::LogicSignal(logicSig, _logic_data, probe); - break; - } - i++; + switch (probe->type) + { + case SR_CHANNEL_LOGIC: + if (probe->enabled) + { + auto i = _signals.begin(); + while (i != _signals.end()) + { + if ((*i)->get_index() == probe->index) + { + view::LogicSignal *logicSig = NULL; + if ((logicSig = dynamic_cast(*i))) + signal = new view::LogicSignal(logicSig, _logic_data, probe); + break; } - if (signal == NULL){ - signal = new view::LogicSignal(_dev_inst, _logic_data, probe); - } + i++; } - break; - - - case SR_CHANNEL_ANALOG: - if (probe->enabled) { - auto i = _signals.begin(); - while (i != _signals.end()) { - if ((*i)->get_index() == probe->index) { - view::AnalogSignal *analogSig = NULL; - if ((analogSig = dynamic_cast(*i))) - signal = new view::AnalogSignal(analogSig, _analog_data, probe); - break; - } - i++; - } - if (signal == NULL){ - signal = new view::AnalogSignal(_dev_inst, _analog_data, probe); - } - + if (signal == NULL) + { + signal = new view::LogicSignal(_dev_inst, _logic_data, probe); } - break; } - if (signal != NULL) - sigs.push_back(signal); - } + break; - if (!sigs.empty()) { - RELEASE_ARRAY(_signals); - std::vector().swap(_signals); - _signals = sigs; + case SR_CHANNEL_ANALOG: + if (probe->enabled) + { + auto i = _signals.begin(); + while (i != _signals.end()) + { + if ((*i)->get_index() == probe->index) + { + view::AnalogSignal *analogSig = NULL; + if ((analogSig = dynamic_cast(*i))) + signal = new view::AnalogSignal(analogSig, _analog_data, probe); + break; + } + i++; + } + if (signal == NULL) + { + signal = new view::AnalogSignal(_dev_inst, _analog_data, probe); + } + } + break; } + if (signal != NULL) + sigs.push_back(signal); + } + + if (!sigs.empty()) + { + RELEASE_ARRAY(_signals); + std::vector().swap(_signals); + _signals = sigs; } spectrum_rebuild(); @@ -872,9 +860,8 @@ void SigSession::refresh(int holdtime) if (_analog_data) { _analog_data->init(); } - - QTimer::singleShot(holdtime, this, SLOT(feed_timeout())); - //data_updated(); + + _out_timer.TimeOut(holdtime, std::bind(&SigSession::feed_timeout, this)); _data_updated = true; } @@ -912,7 +899,7 @@ void SigSession::feed_in_header(const sr_dev_inst *sdi) { (void)sdi; _trigger_pos = 0; - receive_header(); + _callback->receive_header(); } void SigSession::feed_in_meta(const sr_dev_inst *sdi, @@ -941,7 +928,7 @@ void SigSession::feed_in_trigger(const ds_trigger_pos &trigger_pos) _trigger_flag = (trigger_pos.status & 0x01); if (_trigger_flag) { _trigger_pos = trigger_pos.real_pos; - receive_trigger(_trigger_pos); + _callback->receive_trigger(_trigger_pos); } } else { int probe_count = 0; @@ -956,7 +943,7 @@ void SigSession::feed_in_trigger(const ds_trigger_pos &trigger_pos) } } _trigger_pos = trigger_pos.real_pos * probe_count / probe_en_count; - receive_trigger(_trigger_pos); + _callback->receive_trigger(_trigger_pos); } } @@ -970,7 +957,7 @@ void SigSession::feed_in_logic(const sr_datafeed_logic &logic) if (logic.data_error == 1) { _error = Test_data_err; _error_pattern = logic.error_pattern; - session_error(); + _callback->session_error(); } if (_logic_data->snapshot()->last_ended()) { @@ -979,7 +966,7 @@ void SigSession::feed_in_logic(const sr_datafeed_logic &logic) // for logic will be notified. Currently the only user of // frame_began is DecoderStack, but in future we need to signal // this after both analog and logic sweeps have begun. - frame_began(); + _callback->frame_began(); } else { // Append to the existing data snapshot _logic_data->snapshot()->append_payload(logic); @@ -987,13 +974,14 @@ void SigSession::feed_in_logic(const sr_datafeed_logic &logic) if (_logic_data->snapshot()->memory_failed()) { _error = Malloc_err; - session_error(); + _callback->session_error(); return; } - emit receive_data(logic.length * 8 / get_ch_num(SR_CHANNEL_LOGIC)); - data_received(); - //data_updated(); + receive_data(logic.length * 8 / get_ch_num(SR_CHANNEL_LOGIC)); + + _callback->data_received(); + _data_updated = true; } @@ -1040,7 +1028,7 @@ void SigSession::feed_in_dso(const sr_datafeed_dso &dso) if (_dso_data->snapshot()->memory_failed()) { _error = Malloc_err; - session_error(); + _callback->session_error(); return; } @@ -1098,12 +1086,11 @@ void SigSession::feed_in_analog(const sr_datafeed_analog &analog) if (_analog_data->snapshot()->memory_failed()) { _error = Malloc_err; - session_error(); + _callback->session_error(); return; } receive_data(analog.num_samples); - //data_updated(); _data_updated = true; } @@ -1121,7 +1108,7 @@ void SigSession::data_feed_in(const struct sr_dev_inst *sdi, if (packet->type != SR_DF_END && packet->status != SR_PKT_OK) { _error = Pkt_data_err; - session_error(); + _callback->session_error(); return; } @@ -1160,7 +1147,7 @@ void SigSession::data_feed_in(const struct sr_dev_inst *sdi, { if (_error == No_err) { _error = Data_overflow; - session_error(); + _callback->session_error(); } break; } @@ -1190,10 +1177,10 @@ void SigSession::data_feed_in(const struct sr_dev_inst *sdi, if (packet->status != SR_PKT_OK) { _error = Pkt_data_err; - session_error(); + _callback->session_error(); } - frame_ended(); + _callback->frame_ended(); if (get_device()->dev_inst()->mode != LOGIC){ set_session_time(QDateTime::currentDateTime()); @@ -1235,11 +1222,9 @@ int SigSession::hotplug_callback(struct libusb_context *ctx, struct libusb_devic return 0; } -void SigSession::hotplug_proc(boost::function error_handler) +void SigSession::hotplug_proc() { - struct timeval tv; - - (void)error_handler; + struct timeval tv; if (!_dev_inst) return; @@ -1250,12 +1235,12 @@ void SigSession::hotplug_proc(boost::function error_handle libusb_handle_events_timeout(NULL, &tv); if (_hot_attach) { qDebug("DreamSourceLab hardware attached!"); - device_attach(); + _callback->device_attach(); _hot_attach = false; } if (_hot_detach) { qDebug("DreamSourceLab hardware detached!"); - device_detach(); + _callback->device_detach(); _hot_detach = false; } std::this_thread::sleep_for(std::chrono::milliseconds(100)); @@ -1285,7 +1270,7 @@ void SigSession::deregister_hotplug_callback() libusb_hotplug_deregister_callback(NULL, _hotplug_handle); } -void SigSession::start_hotplug_work(boost::function error_handler) +void SigSession::start_hotplug_work() { // Begin the session @@ -1296,7 +1281,7 @@ void SigSession::start_hotplug_work(boost::function error_ if (_hotplug_thread.joinable()){ return; } - _hotplug_thread = std::thread(&SigSession::hotplug_proc, this, error_handler); + _hotplug_thread = std::thread(&SigSession::hotplug_proc, this); } void SigSession::stop_hotplug_work() @@ -1563,7 +1548,7 @@ void SigSession::nodata_timeout() if (gvar == NULL) return; if (g_variant_get_byte(gvar) != DSO_TRIGGER_AUTO) { - show_wait_trigger(); + _callback->show_wait_trigger(); } } @@ -1651,8 +1636,8 @@ bool SigSession::repeat_check() if (_dev_inst->dev_inst()->mode == LOGIC) { _repeat_hold_prg = 100; - repeat_hold(_repeat_hold_prg); - QTimer::singleShot(_repeat_intvl*1000/RepeatHoldDiv, this, SLOT(repeat_update())); + _callback->repeat_hold(_repeat_hold_prg); + _out_timer.TimeOut(_repeat_intvl*1000/RepeatHoldDiv, std::bind(&SigSession::repeat_update, this)); return true; } else { return false; @@ -1663,9 +1648,10 @@ void SigSession::repeat_update() { if (isRepeating()) { _repeat_hold_prg -= 100/RepeatHoldDiv; - if (_repeat_hold_prg != 0) - QTimer::singleShot(_repeat_intvl*1000/RepeatHoldDiv, this, SLOT(repeat_update())); - repeat_hold(_repeat_hold_prg); + if (_repeat_hold_prg != 0){ + _out_timer.TimeOut(_repeat_intvl*1000/RepeatHoldDiv, std::bind(&SigSession::repeat_update, this)); + } + _callback->repeat_hold(_repeat_hold_prg); if (_repeat_hold_prg == 0) repeat_resume(); } diff --git a/DSView/pv/sigsession.h b/DSView/pv/sigsession.h index c5f97439..16864adb 100755 --- a/DSView/pv/sigsession.h +++ b/DSView/pv/sigsession.h @@ -24,30 +24,20 @@ #define DSVIEW_PV_SIGSESSION_H #include -#include - -#include -#include -#include + #include #include #include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - +#include +#include #include +#include +#include #include "view/mathtrace.h" #include "data/mathstack.h" +#include "interface/icallbacks.h" +#include "dstimer.h" struct srd_decoder; struct srd_channel; @@ -96,10 +86,8 @@ class DecoderFactory; using namespace pv::device; //created by MainWindow -class SigSession : public QObject +class SigSession { - Q_OBJECT - private: static constexpr float Oversampling = 2.0f; static const int RefreshTime = 500; @@ -132,7 +120,7 @@ public: }; private: - // SigSession(SigSession &o); + SigSession(SigSession &o); public: explicit SigSession(DeviceManager *device_manager); @@ -145,95 +133,60 @@ public: * Sets device instance that will be used in the next capture session. */ void set_device(DevInst *dev_inst); - void deselect_device(); - void set_file(QString name); - void close_file(DevInst *dev_inst); - - void set_default_device(boost::function error_handler); + void set_default_device(); void release_device(DevInst *dev_inst); - capture_state get_capture_state(); - uint64_t cur_samplerate(); - uint64_t cur_snap_samplerate(); - uint64_t cur_samplelimits(); double cur_sampletime(); - double cur_snap_sampletime(); - double cur_view_time(); void set_cur_snap_samplerate(uint64_t samplerate); - void set_cur_samplelimits(uint64_t samplelimits); - void set_session_time(QDateTime time); QDateTime get_session_time(); - uint64_t get_trigger_pos(); - - void start_capture(bool instant, boost::function error_handler); - + bool get_capture_status(bool &triggered, int &progress); - void container_init(); - + void container_init(); std::set get_data(); - std::vector& get_signals(); - std::vector& get_group_signals(); bool add_decoder(srd_decoder *const dec, bool silent, DecoderStatus *dstatus); - - void remove_decoder(int index); - + void remove_decoder(int index); std::vector& get_decode_signals(); - void rst_decoder(int index); - + void rst_decoder(int index); pv::data::DecoderModel* get_decoder_model(); - std::vector& get_spectrum_traces(); - view::LissajousTrace* get_lissajous_trace(); - view::MathTrace* get_math_trace(); void init_signals(); - void add_group(); - void del_group(); - - void start_hotplug_work(boost::function error_handler); - - void stop_hotplug_work(); - + void start_hotplug_work(); + void stop_hotplug_work(); uint16_t get_ch_num(int type); bool get_instant(); - bool get_data_lock(); - void data_auto_lock(int lock); - void data_auto_unlock(); - bool get_data_auto_lock(); void spectrum_rebuild(); - void lissajous_rebuild(bool enable, int xindex, int yindex, double percent); - void lissajous_disable(); void math_rebuild(bool enable,pv::view::DsoSignal *dsoSig1, @@ -241,91 +194,104 @@ public: data::MathStack::MathType type); void math_disable(); - bool trigd(); - uint8_t trigd_ch(); - data::Snapshot* get_snapshot(int type); - error_state get_error(); - void set_error(error_state state); - void clear_error(); uint64_t get_error_pattern(); - run_mode get_run_mode(); - void set_run_mode(run_mode mode); - int get_repeat_intvl(); - void set_repeat_intvl(int interval); bool isRepeating(); - bool repeat_check(); - int get_repeat_hold(); - int get_map_zoom(); - void set_save_start(uint64_t start); void set_save_end(uint64_t end); - uint64_t get_save_start(); - uint64_t get_save_end(); - bool get_saving(); void set_saving(bool saving); - void set_stop_scale(float scale); - float stop_scale(); void exit_capture(); - sr_dev_inst* get_dev_inst_c(); - void Open(); - void Close(); - void clear_all_decoder(); inline bool is_closed(){ return _bClose; } + + inline void set_callback(ISessionCallback *callback){ + _callback = callback; + } + +public: + inline void capture_state_changed(int state){ + _callback->capture_state_changed(state); + } + + inline void session_save(){ + _callback->session_save(); + } + + inline void repeat_resume(){ + _callback->repeat_resume(); + } + + inline void show_region(uint64_t start, uint64_t end, bool keep){ + _callback->show_region(start, end, keep); + } + + inline void decode_done(){ + _callback->decode_done(); + } + +private: + inline void data_updated(){ + _callback->data_updated(); + } + + inline void signals_changed(){ + _callback->signals_changed(); + } + + inline void receive_data(quint64 len){ + _callback->receive_data_len(len); + } private: void set_capture_state(capture_state state); - void register_hotplug_callback(); - void deregister_hotplug_callback(); bool do_add_decoder(srd_decoder *const dec, bool silent, DecoderStatus *dstatus); void add_decode_task(view::DecodeTrace *trace); - void remove_decode_task(view::DecodeTrace *trace); + void clear_all_decode_task(int &runningDex); - void clear_all_decode_task(int &runningDex); - view::DecodeTrace* get_decoder_trace(int index); - void decode_task_proc(); + view::DecodeTrace* get_top_decode_task(); - view::DecodeTrace* get_top_decode_task(); - void capture_init(); - void do_stop_capture(); + void data_lock(); + void data_unlock(); + void nodata_timeout(); + void feed_timeout(); + void repeat_update(); private: /** @@ -337,14 +303,8 @@ private: */ static sr_input_format* determine_input_file_format( const std::string &filename); - - static sr_input* load_input_file_format( - const std::string &filename, - boost::function error_handler, - sr_input_format *format = NULL); - - void sample_thread_proc(DevInst *dev_inst, - boost::function error_handler); + + void sample_thread_proc(DevInst *dev_inst); // data feed void feed_in_header(const sr_dev_inst *sdi); @@ -367,87 +327,20 @@ private: const struct sr_datafeed_packet *packet, void *cb_data); // thread for hotplug - void hotplug_proc(boost::function error_handler); + void hotplug_proc(); static int hotplug_callback(struct libusb_context *ctx, struct libusb_device *dev, libusb_hotplug_event event, void *user_data); - - -signals: - void capture_state_changed(int state); - - void signals_changed(); - - void data_updated(); - - void receive_data(quint64 length); - - void device_attach(); - - void device_detach(); - - void receive_trigger(quint64 trigger_pos); - - void receive_header(); - - void dso_ch_changed(uint16_t num); - - void frame_began(); - - void data_received(); - - void frame_ended(); - - void device_setted(); - - void zero_adj(); - - void progressSaveFileValueChanged(int percent); - - void decode_done(); - - void show_region(uint64_t start, uint64_t end, bool keep); - - void show_wait_trigger(); - - void session_save(); - - void session_error(); - - void repeat_hold(int percent); - - void repeat_resume(); - - void cur_snap_samplerate_changed(); - - void update_capture(); - -public slots: +public: void reload(); - void refresh(int holdtime); - + void start_capture(bool instant); void stop_capture(); - void check_update(); - // repeat void set_repeating(bool repeat); - void set_map_zoom(int index); - // OSC auto - void auto_end(); - -private slots: - void data_lock(); - - void data_unlock(); - - void nodata_timeout(); - - void feed_timeout(); - - void repeat_update(); + void auto_end(); private: DeviceManager *_device_manager; @@ -494,7 +387,8 @@ private: bool _hot_attach; bool _hot_detach; - QTimer _feed_timer; + DsTimer _feed_timer; + DsTimer _out_timer; int _noData_cnt; bool _data_lock; bool _data_updated; @@ -524,6 +418,8 @@ private: float _stop_scale; bool _bClose; + ISessionCallback *_callback; + private: // TODO: This should not be necessary. Multiple concurrent // sessions should should be supported and it should be diff --git a/DSView/pv/storesession.cpp b/DSView/pv/storesession.cpp index 1540affb..eee40b78 100755 --- a/DSView/pv/storesession.cpp +++ b/DSView/pv/storesession.cpp @@ -43,6 +43,14 @@ #include #include +#include +#include +#include +#include +#include +#include +#include + #include "config/appconfig.h" diff --git a/DSView/pv/toolbars/filebar.cpp b/DSView/pv/toolbars/filebar.cpp index 0262e0ac..fb708f96 100755 --- a/DSView/pv/toolbars/filebar.cpp +++ b/DSView/pv/toolbars/filebar.cpp @@ -19,18 +19,17 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include - +#include #include #include +#include +#include #include "filebar.h" #include "../device/devinst.h" #include "../ui/msgbox.h" #include "../config/appconfig.h" -#include - namespace pv { namespace toolbars { diff --git a/DSView/pv/toolbars/logobar.cpp b/DSView/pv/toolbars/logobar.cpp index 4c65cf41..01da8850 100755 --- a/DSView/pv/toolbars/logobar.cpp +++ b/DSView/pv/toolbars/logobar.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include "logobar.h" #include "../dialogs/about.h" diff --git a/DSView/pv/toolbars/samplingbar.cpp b/DSView/pv/toolbars/samplingbar.cpp index 59fbcb42..ff193b4c 100755 --- a/DSView/pv/toolbars/samplingbar.cpp +++ b/DSView/pv/toolbars/samplingbar.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include "../devicemanager.h" #include "../device/devinst.h" @@ -814,6 +815,7 @@ void SamplingBar::commit_settings() } } +//start or stop capture void SamplingBar::on_run_stop() { if (get_sampling() || _session->isRepeating()) { @@ -886,14 +888,16 @@ void SamplingBar::on_instant_stop() if (dev_inst->dev_inst()->mode == DSO) { GVariant* gvar = dev_inst->get_config(NULL, NULL, SR_CONF_ZERO); + if (gvar != NULL) { bool zero = g_variant_get_boolean(gvar); g_variant_unref(gvar); + if (zero) { dialogs::DSMessageBox msg(this); msg.mBox()->setText(tr("Auto Calibration")); msg.mBox()->setInformativeText(tr("Auto Calibration program will be started. Don't connect any probes. It can take a while!")); - //msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->addButton(tr("Ok"), QMessageBox::AcceptRole); msg.mBox()->addButton(tr("Skip"), QMessageBox::RejectRole); msg.mBox()->setIcon(QMessageBox::Warning); diff --git a/DSView/pv/toolbars/trigbar.cpp b/DSView/pv/toolbars/trigbar.cpp index 2d6cdf29..4666c88b 100755 --- a/DSView/pv/toolbars/trigbar.cpp +++ b/DSView/pv/toolbars/trigbar.cpp @@ -20,15 +20,17 @@ */ #include "trigbar.h" + +#include +#include +#include + #include "../sigsession.h" #include "../device/devinst.h" #include "../dialogs/fftoptions.h" #include "../dialogs/lissajousoptions.h" #include "../dialogs/mathoptions.h" #include "../view/trace.h" - -#include -#include #include "../dialogs/applicationpardlg.h" #include "../config/appconfig.h" diff --git a/DSView/pv/view/analogsignal.cpp b/DSView/pv/view/analogsignal.cpp index 745834ad..1419046a 100755 --- a/DSView/pv/view/analogsignal.cpp +++ b/DSView/pv/view/analogsignal.cpp @@ -21,7 +21,7 @@ */ #include - +#include #include #include "../view/analogsignal.h" @@ -30,6 +30,7 @@ #include "../view/view.h" #include "../device/devinst.h" + using namespace std; #define byte(x) uint##x##_t diff --git a/DSView/pv/view/dsosignal.cpp b/DSView/pv/view/dsosignal.cpp index f4d748ba..24b69243 100755 --- a/DSView/pv/view/dsosignal.cpp +++ b/DSView/pv/view/dsosignal.cpp @@ -31,6 +31,8 @@ #include "../device/devinst.h" #include #include +#include +#include using namespace std; @@ -1457,8 +1459,8 @@ void DsoSignal::auto_start() _view->session().data_auto_lock(AutoLock); _autoV = true; _autoH = true; - _view->auto_trig(get_index()); - QTimer::singleShot(AutoTime, &_view->session(), SLOT(auto_end())); + _view->auto_trig(get_index()); + _end_timer.TimeOut(AutoTime, std::bind(&DsoSignal::call_auto_end, this)); //start a timeout } } @@ -1572,5 +1574,9 @@ QString DsoSignal::get_time(double t) return str; } +void DsoSignal::call_auto_end(){ + _view->session().auto_end(); +} + } // namespace view } // namespace pv diff --git a/DSView/pv/view/dsosignal.h b/DSView/pv/view/dsosignal.h index 2cdd8bde..606cd5ba 100755 --- a/DSView/pv/view/dsosignal.h +++ b/DSView/pv/view/dsosignal.h @@ -24,6 +24,7 @@ #define DSVIEW_PV_DSOSIGNAL_H #include "signal.h" +#include "../dstimer.h" namespace pv { namespace data { @@ -107,8 +108,7 @@ public: bool get_vDialActive(); void set_vDialActive(bool active); bool go_vDialPre(bool manul); - bool go_vDialNext(bool manul); - bool update_capture(bool instant); + bool go_vDialNext(bool manul); dslDial *get_vDial(); uint64_t get_vDialValue(); uint16_t get_vDialSel(); @@ -227,6 +227,8 @@ private: void paint_hover_measure(QPainter &p, QColor fore, QColor back); void auto_set(); + void call_auto_end(); + private: pv::data::Dso *_data; float _scale; @@ -268,6 +270,7 @@ private: uint64_t _hover_index; QPointF _hover_point; float _hover_value; + DsTimer _end_timer; }; } // namespace view diff --git a/DSView/pv/view/spectrumtrace.cpp b/DSView/pv/view/spectrumtrace.cpp index 3115bf33..8e6bb11e 100755 --- a/DSView/pv/view/spectrumtrace.cpp +++ b/DSView/pv/view/spectrumtrace.cpp @@ -21,8 +21,7 @@ #include #include #include - - +#include #include #include "spectrumtrace.h" diff --git a/DSView/pv/view/view.cpp b/DSView/pv/view/view.cpp index 91b53b5b..1728e03e 100755 --- a/DSView/pv/view/view.cpp +++ b/DSView/pv/view/view.cpp @@ -117,7 +117,6 @@ View::View(SigSession *session, pv::toolbars::SamplingBar *sampling_bar, QWidget _devmode = new DevMode(this, session); setViewportMargins(headerWidth(), RulerHeight, 0, 0); - //setViewport(_viewport); // windows splitter _time_viewport = new Viewport(*this, TIME_VIEW); @@ -184,21 +183,22 @@ View::View(SigSession *session, pv::toolbars::SamplingBar *sampling_bar, QWidget connect(_fft_viewport, SIGNAL(measure_updated()), this, SLOT(on_measure_updated())); connect(_vsplitter, SIGNAL(splitterMoved(int,int)), this, SLOT(splitterMoved(int, int))); - connect(_session, SIGNAL(device_setted()), _devmode, SLOT(set_device())); - connect(_session, SIGNAL(signals_changed()), this, SLOT(signals_changed()), Qt::DirectConnection); - connect(_session, SIGNAL(data_updated()), this, SLOT(data_updated())); - connect(_session, SIGNAL(receive_trigger(quint64)), this, SLOT(receive_trigger(quint64))); - connect(_session, SIGNAL(frame_ended()), this, SLOT(receive_end())); - connect(_session, SIGNAL(frame_began()), this, SLOT(frame_began())); - connect(_session, SIGNAL(show_region(uint64_t, uint64_t, bool)), this, SLOT(show_region(uint64_t, uint64_t, bool))); - - connect(_session, SIGNAL(show_wait_trigger()), _time_viewport, SLOT(show_wait_trigger())); - connect(_session, SIGNAL(repeat_hold(int)), this, SLOT(repeat_show())); + connect(_devmode, SIGNAL(dev_changed(bool)),this, SLOT(dev_changed(bool)), Qt::DirectConnection); connect(_header, SIGNAL(traces_moved()),this, SLOT(on_traces_moved())); connect(_header, SIGNAL(header_updated()),this, SLOT(header_updated())); } +void View::show_wait_trigger() +{ + _time_viewport->show_wait_trigger(); +} + +void View::set_device() +{ + _devmode->set_device(); +} + SigSession& View::session() { return *_session; @@ -1313,5 +1313,14 @@ uint64_t View::pixel2index(double pixel) return index; } +void View::set_receive_len(uint64_t len) +{ + if (_time_viewport) + _time_viewport->set_receive_len(len); + + if (_fft_viewport) + _fft_viewport->set_receive_len(len); +} + } // namespace view } // namespace pv diff --git a/DSView/pv/view/view.h b/DSView/pv/view/view.h index f5e8ea10..a807dd85 100755 --- a/DSView/pv/view/view.h +++ b/DSView/pv/view/view.h @@ -306,6 +306,12 @@ public slots: // void header_updated(); + void receive_trigger(quint64 trig_pos); + + void receive_end(); + + void frame_began(); + private slots: void h_scroll_value_changed(int value); @@ -315,13 +321,9 @@ private slots: void on_traces_moved(); - void receive_trigger(quint64 trig_pos); + void set_trig_pos(int percent); - - void receive_end(); - - void frame_began(); - + // calibration for oscilloscope void show_calibration(); // lissajous figure @@ -332,59 +334,65 @@ private slots: void dev_changed(bool close); +public: + void show_wait_trigger(); + void set_device(); + void set_receive_len(uint64_t len); + private: - SigSession *_session; - pv::toolbars::SamplingBar *_sampling_bar; + SigSession *_session; + pv::toolbars::SamplingBar *_sampling_bar; - QWidget *_viewcenter; - ViewStatus *_viewbottom; - QSplitter *_vsplitter; - Viewport * _time_viewport; - Viewport * _fft_viewport; - LissajousFigure *_lissajous; - Viewport *_active_viewport; - std::list _viewport_list; - std::map _trace_view_map; - Ruler *_ruler; - Header *_header; - DevMode *_devmode; + QWidget *_viewcenter; + ViewStatus *_viewbottom; + QSplitter *_vsplitter; + Viewport *_time_viewport; + Viewport *_fft_viewport; + Viewport *_active_viewport; + LissajousFigure *_lissajous; + std::list _viewport_list; + std::map _trace_view_map; + Ruler *_ruler; + Header *_header; + DevMode *_devmode; + /// The view time scale in seconds per pixel. - double _scale; - double _preScale; - double _maxscale; - double _minscale; + double _scale; + double _preScale; + double _maxscale; + double _minscale; /// The pixels offset of the left edge of the view - int64_t _offset; - int64_t _preOffset; - int _spanY; - int _signalHeight; - bool _updating_scroll; + int64_t _offset; + int64_t _preOffset; + int _spanY; + int _signalHeight; + bool _updating_scroll; // trigger position fix - double _trig_hoff; + double _trig_hoff; - bool _show_cursors; + bool _show_cursors; std::list _cursorList; - Cursor *_trig_cursor; - bool _show_trig_cursor; - Cursor *_search_cursor; - bool _show_search_cursor; - uint64_t _search_pos; - bool _search_hit; + Cursor *_trig_cursor; + bool _show_trig_cursor; + Cursor *_search_cursor; + bool _show_search_cursor; + uint64_t _search_pos; + bool _search_hit; - bool _show_xcursors; + bool _show_xcursors; std::list _xcursorList; - QPoint _hover_point; + QPoint _hover_point; dialogs::Calibration *_cali; - bool _dso_auto; - bool _show_lissajous; - bool _back_ready; - bool _trig_time_setted; + bool _dso_auto; + bool _show_lissajous; + bool _back_ready; + bool _trig_time_setted; }; } // namespace view diff --git a/DSView/pv/view/viewport.cpp b/DSView/pv/view/viewport.cpp index fcd8baad..3ca32160 100755 --- a/DSView/pv/view/viewport.cpp +++ b/DSView/pv/view/viewport.cpp @@ -98,8 +98,7 @@ Viewport::Viewport(View &parent, View_type type) : setContextMenuPolicy(Qt::CustomContextMenu); connect(&trigger_timer, SIGNAL(timeout()),this, SLOT(on_trigger_timer())); - connect(&_drag_timer, SIGNAL(timeout()),this, SLOT(on_drag_timer())); - connect(&_view.session(), &SigSession::receive_data, this, &Viewport::set_receive_len); + connect(&_drag_timer, SIGNAL(timeout()),this, SLOT(on_drag_timer())); connect(yAction, SIGNAL(triggered(bool)), this, SLOT(add_cursor_y())); connect(xAction, SIGNAL(triggered(bool)), this, SLOT(add_cursor_x())); diff --git a/DSView/pv/view/viewport.h b/DSView/pv/view/viewport.h index 18b4dc4d..0ba08201 100755 --- a/DSView/pv/view/viewport.h +++ b/DSView/pv/view/viewport.h @@ -131,8 +131,7 @@ private: private slots: void on_trigger_timer(); void on_drag_timer(); - void set_receive_len(quint64 length); - + void show_contextmenu(const QPoint& pos); void add_cursor_x(); void add_cursor_y(); @@ -140,6 +139,7 @@ private slots: public slots: void show_wait_trigger(); void unshow_wait_trigger(); + void set_receive_len(quint64 length); signals: void measure_updated(); diff --git a/DSView/pv/view/viewstatus.cpp b/DSView/pv/view/viewstatus.cpp index 6ca30b86..635c02d4 100755 --- a/DSView/pv/view/viewstatus.cpp +++ b/DSView/pv/view/viewstatus.cpp @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include "../view/trace.h" #include "../sigsession.h" From 801af9e1253ac4639f096552597bdf3ac60777af Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Mon, 15 Nov 2021 13:12:20 +0800 Subject: [PATCH 25/60] none --- DSView/pv/appcontrol.cpp | 4 ++- DSView/pv/data/decoderstack.cpp | 11 ++++-- DSView/pv/data/decoderstack.h | 27 +++------------ DSView/pv/dock/protocoldock.cpp | 15 +++++---- DSView/pv/mainwindow.cpp | 17 +++------- DSView/pv/sigsession.cpp | 22 +++++------- DSView/pv/sigsession.h | 15 ++------- DSView/pv/storesession.cpp | 33 +++++++++--------- DSView/pv/storesession.h | 2 +- DSView/pv/toolbars/samplingbar.cpp | 8 +++-- DSView/pv/toolbars/samplingbar.h | 54 +++++++++++++----------------- DSView/pv/view/header.cpp | 2 ++ libsigrokdecode4DSL/srd.c | 50 +++++++++++++++------------ libsigrokdecode4DSL/util.c | 6 ++-- 14 files changed, 122 insertions(+), 144 deletions(-) diff --git a/DSView/pv/appcontrol.cpp b/DSView/pv/appcontrol.cpp index dff58bc7..eae70d5d 100644 --- a/DSView/pv/appcontrol.cpp +++ b/DSView/pv/appcontrol.cpp @@ -71,8 +71,10 @@ bool AppControl::Init() return false; } + const char *decoderScriptDir = "/home/lala/tmpdir/any"; + // Initialise libsigrokdecode - if (srd_init(NULL) != SRD_OK) + if (srd_init(decoderScriptDir) != SRD_OK) { m_error = "ERROR: libsigrokdecode init failed."; return false; diff --git a/DSView/pv/data/decoderstack.cpp b/DSView/pv/data/decoderstack.cpp index c53affa1..b8c15a24 100755 --- a/DSView/pv/data/decoderstack.cpp +++ b/DSView/pv/data/decoderstack.cpp @@ -516,11 +516,18 @@ void DecoderStack::decode_data(const uint64_t decode_start, const uint64_t decod if (chunk_end - i > MaxChunkSize) chunk_end = i + MaxChunkSize; - if (srd_session_send(session, i, chunk_end, - chunk.data(), chunk_const.data(), chunk_end - i, &error) != SRD_OK) { + if (srd_session_send( + session, + i, + chunk_end, + chunk.data(), + chunk_const.data(), + chunk_end - i, + &error) != SRD_OK){ _error_message = QString::fromLocal8Bit(error); break; } + i = chunk_end; { diff --git a/DSView/pv/data/decoderstack.h b/DSView/pv/data/decoderstack.h index cef31dab..7685e272 100755 --- a/DSView/pv/data/decoderstack.h +++ b/DSView/pv/data/decoderstack.h @@ -94,9 +94,7 @@ public: } void push(decode::Decoder *decoder); - void remove(decode::Decoder *decoder); - void build_row(); int64_t samples_decoded(); @@ -111,7 +109,6 @@ public: uint64_t get_annotation_index( const decode::Row &row, uint64_t start_sample); - uint64_t get_max_annotation(const decode::Row &row); uint64_t get_min_annotation(const decode::Row &row); // except instant(end=start) annotation @@ -119,9 +116,7 @@ public: std::map get_rows_lshow(); void set_rows_gshow(const decode::Row row, bool show); void set_rows_lshow(const decode::Row row, bool show); - bool has_annotations(const decode::Row &row); - uint64_t list_annotation_size(); uint64_t list_annotation_size(uint16_t row_index); @@ -131,13 +126,9 @@ public: bool list_row_title(int row, QString &title); - QString error_message(); - void clear(); - void init(); - uint64_t get_max_sample_count(); inline bool IsRunning(){ @@ -145,31 +136,22 @@ public: } void begin_decode_work(); - void do_decode_work(); - - void stop_decode_work(); - + void stop_decode_work(); int list_rows_size(); - bool options_changed(); void set_options_changed(bool changed); uint64_t sample_count(); uint64_t sample_rate(); - bool out_of_memory(); - void set_mark_index(int64_t index); int64_t get_mark_index(); - void frame_ended(); private: void decode_data(const uint64_t decode_start, const uint64_t decode_end, srd_session *const session); - void decode_proc(); - static void annotation_callback(srd_proto_data *pdata, void *decoder); @@ -179,7 +161,6 @@ signals: private: std::list _stack; - pv::data::LogicSnapshot *_snapshot; std::map _rows; @@ -192,15 +173,15 @@ private: volatile bool _options_changed; volatile bool _no_memory; int64_t _mark_index; + DecoderStatus *_decoder_status; QString _error_message; int64_t _samples_decoded; uint64_t _sample_count; - decode_task_status *_stask_stauts; - + decode_task_status *_stask_stauts; mutable std::mutex _output_mutex; - + friend class DecoderStackTest::TwoDecoderStack; }; diff --git a/DSView/pv/dock/protocoldock.cpp b/DSView/pv/dock/protocoldock.cpp index 26afcc8b..a9affcdc 100755 --- a/DSView/pv/dock/protocoldock.cpp +++ b/DSView/pv/dock/protocoldock.cpp @@ -195,9 +195,7 @@ ProtocolDock::ProtocolDock(QWidget *parent, view::View &view, SigSession *sessio connect(_table_view->horizontalHeader(), SIGNAL(sectionResized(int,int,int)), this, SLOT(column_resize(int, int, int))); connect(_search_edit, SIGNAL(editingFinished()), this, SLOT(search_changed())); - retranslateUi(); - - ds_debug("protocol panel\n"); + retranslateUi(); } ProtocolDock::~ProtocolDock() @@ -303,14 +301,19 @@ void ProtocolDock::add_protocol(bool silent) return; } + //have no protocol + if (_protocol_combobox->count() == 0){ + if (!silent){ + MsgBox::Show(NULL, "Protocol list is empty!"); + } + return; + } + srd_decoder *const decoder = (srd_decoder *)(_protocol_combobox->itemData(_protocol_combobox->currentIndex())).value(); DecoderStatus *dstatus = new DecoderStatus(); dstatus->m_format = (int)DecoderDataFormat::hex; - - int numm= _protocol_items.size(); - numm += 0; if (_session->add_decoder(decoder, silent, dstatus)) { diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index 2c711e74..a8f3dc45 100755 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -21,9 +21,6 @@ */ - -#include -#include "dock/protocoldock.h" #include #include @@ -70,6 +67,7 @@ #include "dock/dsotriggerdock.h" #include "dock/measuredock.h" #include "dock/searchdock.h" +#include "dock/protocoldock.h" #include "view/view.h" #include "view/trace.h" @@ -168,19 +166,16 @@ void MainWindow::setup_ui() addToolBar(_trig_bar); addToolBar(_file_bar); addToolBar(_logo_bar); - - // Setup the dockWidget - - // protocol dock + + //Setup the dockWidget _protocol_dock=new QDockWidget(tr("Protocol"),this); _protocol_dock->setObjectName("protocol_dock"); _protocol_dock->setFeatures(QDockWidget::DockWidgetMovable); _protocol_dock->setAllowedAreas(Qt::RightDockWidgetArea); - _protocol_dock->setVisible(false); - //dock::ProtocolDock *_protocol_widget = new dock::ProtocolDock(_protocol_dock, _session); + _protocol_dock->setVisible(false); _protocol_widget = new dock::ProtocolDock(_protocol_dock, *_view, _session); _protocol_dock->setWidget(_protocol_widget); - qDebug() << "Protocol decoder enabled!\n"; + //qDebug() << "Protocol decoder enabled!\n"; // measure dock @@ -224,9 +219,7 @@ void MainWindow::setup_ui() _logo_bar->installEventFilter(this); _dso_trigger_dock->installEventFilter(this); _trigger_dock->installEventFilter(this); - _protocol_dock->installEventFilter(this); - _measure_dock->installEventFilter(this); _search_dock->installEventFilter(this); diff --git a/DSView/pv/sigsession.cpp b/DSView/pv/sigsession.cpp index 99a41300..4e9e144c 100755 --- a/DSView/pv/sigsession.cpp +++ b/DSView/pv/sigsession.cpp @@ -437,8 +437,7 @@ void SigSession::start_capture(bool instant) dsoSig->set_mValid(false); } - // update setting - qDebug()<<"device name:"<<_dev_inst->name(); + // update setting if (_dev_inst->name() != "virtual-session") _instant = instant; @@ -1167,8 +1166,6 @@ void SigSession::data_feed_in(const struct sr_dev_inst *sdi, _dso_data->snapshot()->capture_ended(); _analog_data->snapshot()->capture_ended(); - qDebug()<<"data frame end"; - for (auto trace : _decode_traces){ trace->decoder()->frame_ended(); trace->frame_ended(); @@ -1248,7 +1245,7 @@ void SigSession::hotplug_proc() } catch(...) { qDebug("Interrupt exception for hotplug thread was thrown."); } - qDebug("Hotplug thread exit!"); + // qDebug("Hotplug thread exit!"); } void SigSession::register_hotplug_callback() @@ -1271,10 +1268,9 @@ void SigSession::deregister_hotplug_callback() } void SigSession::start_hotplug_work() -{ - +{ // Begin the session - qDebug() << "Starting a hotplug thread...\n"; + // qDebug() << "Starting a hotplug thread...\n"; _hot_attach = false; _hot_detach = false; @@ -1788,7 +1784,7 @@ void SigSession::set_stop_scale(float scale) //append a decode task, and try create a thread void SigSession::add_decode_task(view::DecodeTrace *trace) { - qDebug()<<"add a decode task"; + //qDebug()<<"add a decode task"; std::lock_guard lock(_decode_task_mutex); _decode_tasks.push_back(trace); @@ -1844,7 +1840,7 @@ void SigSession::set_stop_scale(float scale) //wait thread end if (_decode_thread.joinable()) { - qDebug() << "wait the decode thread end"; + // qDebug() << "wait the decode thread end"; _decode_thread.join(); } @@ -1900,12 +1896,12 @@ void SigSession::set_stop_scale(float scale) //the decode task thread proc void SigSession::decode_task_proc(){ - qDebug()<<"decode thread start"; + //qDebug()<<"decode thread start"; auto task = get_top_decode_task(); while (task != NULL) { - qDebug()<<"one decode task be actived"; + // qDebug()<<"one decode task be actived"; if (!task->_delete_flag){ task->decoder()->begin_decode_work(); @@ -1924,7 +1920,7 @@ void SigSession::set_stop_scale(float scale) task = get_top_decode_task(); } - qDebug()<<"decode thread end"; + // qDebug()<<"decode thread end"; _bDecodeRunning = false; } diff --git a/DSView/pv/sigsession.h b/DSView/pv/sigsession.h index 16864adb..7f478af0 100755 --- a/DSView/pv/sigsession.h +++ b/DSView/pv/sigsession.h @@ -274,7 +274,6 @@ private: void set_capture_state(capture_state state); void register_hotplug_callback(); void deregister_hotplug_callback(); - bool do_add_decoder(srd_decoder *const dec, bool silent, DecoderStatus *dstatus); void add_decode_task(view::DecodeTrace *trace); @@ -301,25 +300,17 @@ private: * used, or NULL if no input format was selected or * auto-detected. */ - static sr_input_format* determine_input_file_format( - const std::string &filename); - + static sr_input_format* determine_input_file_format(const std::string &filename); void sample_thread_proc(DevInst *dev_inst); // data feed void feed_in_header(const sr_dev_inst *sdi); - - void feed_in_meta(const sr_dev_inst *sdi, - const sr_datafeed_meta &meta); - + void feed_in_meta(const sr_dev_inst *sdi, const sr_datafeed_meta &meta); void feed_in_trigger(const ds_trigger_pos &trigger_pos); - void feed_in_logic(const sr_datafeed_logic &logic); void feed_in_dso(const sr_datafeed_dso &dso); - - void feed_in_analog(const sr_datafeed_analog &analog); - + void feed_in_analog(const sr_datafeed_analog &analog); void data_feed_in(const struct sr_dev_inst *sdi, const struct sr_datafeed_packet *packet); diff --git a/DSView/pv/storesession.cpp b/DSView/pv/storesession.cpp index eee40b78..a621dc8e 100755 --- a/DSView/pv/storesession.cpp +++ b/DSView/pv/storesession.cpp @@ -23,23 +23,22 @@ #define __STDC_FORMAT_MACROS #include "storesession.h" +#include "sigsession.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - +#include "data/logic.h" +#include "data/logicsnapshot.h" +#include "data/dsosnapshot.h" +#include "data/analogsnapshot.h" +#include "data/decoderstack.h" +#include "data/decode/decoder.h" +#include "data/decode/row.h" +#include "view/trace.h" +#include "view/signal.h" +#include "view/logicsignal.h" +#include "view/dsosignal.h" +#include "view/decodetrace.h" +#include "device/devinst.h" +#include "dock/protocoldock.h" #include #include @@ -51,7 +50,7 @@ #include #include - +#include #include "config/appconfig.h" namespace pv { diff --git a/DSView/pv/storesession.h b/DSView/pv/storesession.h index c7ef0e1d..daadef74 100755 --- a/DSView/pv/storesession.h +++ b/DSView/pv/storesession.h @@ -29,7 +29,7 @@ #include #include -#include + #include "ZipMaker.h" namespace pv { diff --git a/DSView/pv/toolbars/samplingbar.cpp b/DSView/pv/toolbars/samplingbar.cpp index ff193b4c..33f52c72 100755 --- a/DSView/pv/toolbars/samplingbar.cpp +++ b/DSView/pv/toolbars/samplingbar.cpp @@ -339,11 +339,14 @@ void SamplingBar::zero_adj() if ((dsoSig = dynamic_cast(s))) dsoSig->set_enable(true); } + const int index_back = _sample_count.currentIndex(); int i = 0; + for (i = 0; i < _sample_count.count(); i++) if (_sample_count.itemData(i).value() == ZeroTimeBase) break; + _sample_count.setCurrentIndex(i); commit_hori_res(); @@ -722,8 +725,6 @@ double SamplingBar::get_hori_res() double SamplingBar::hori_knob(int dir) { double hori_res = -1; - disconnect(&_sample_count, SIGNAL(currentIndexChanged(int)), - this, SLOT(on_samplecount_sel(int))); if (0 == dir) { hori_res = commit_hori_res(); @@ -735,6 +736,9 @@ double SamplingBar::hori_knob(int dir) hori_res = commit_hori_res(); } + disconnect(&_sample_count, SIGNAL(currentIndexChanged(int)), + this, SLOT(on_samplecount_sel(int))); + connect(&_sample_count, SIGNAL(currentIndexChanged(int)), this, SLOT(on_samplecount_sel(int))); diff --git a/DSView/pv/toolbars/samplingbar.h b/DSView/pv/toolbars/samplingbar.h index 14779f96..3459bb93 100755 --- a/DSView/pv/toolbars/samplingbar.h +++ b/DSView/pv/toolbars/samplingbar.h @@ -64,6 +64,7 @@ namespace pv static const int RefreshShort = 500; static const uint64_t LogicMaxSWDepth64 = SR_GB(16); static const uint64_t LogicMaxSWDepth32 = SR_GB(8); + static const uint64_t AnalogMaxSWDepth = SR_Mn(100); static const QString RLEString; static const QString DIVString; @@ -71,11 +72,8 @@ namespace pv public: SamplingBar(SigSession *session, QWidget *parent); - void set_device_list(const std::list &devices, DevInst* selected); - DevInst *get_selected_device(); - void update_sample_rate_selector(); void set_sampling(bool sampling); @@ -83,9 +81,7 @@ namespace pv bool get_instant(); void enable_toggle(bool enable); - void enable_run_stop(bool enable); - void enable_instant(bool enable); double hori_knob(int dir); @@ -132,37 +128,33 @@ namespace pv void reload(); private: - SigSession *_session; + SigSession *_session; + mutable std::mutex _sampling_mutex; + bool _enable; + bool _sampling; - mutable std::mutex _sampling_mutex; - bool _enable; - bool _sampling; - - QToolButton _device_type; - - QComboBox _device_selector; + QToolButton _device_type; + QComboBox _device_selector; std::map _device_selector_map; - bool _updating_device_selector; + bool _updating_device_selector; - QToolButton _configure_button; + QToolButton _configure_button; + QComboBox _sample_count; + QComboBox _sample_rate; + bool _updating_sample_rate; + bool _updating_sample_count; - QComboBox _sample_count; - QComboBox _sample_rate; - bool _updating_sample_rate; - bool _updating_sample_count; + QToolButton _run_stop_button; + QToolButton _instant_button; + QAction *_run_stop_action; + QAction *_instant_action; + QAction *_mode_action; + QToolButton _mode_button; - QToolButton _run_stop_button; - QToolButton _instant_button; - QAction *_run_stop_action; - QAction *_instant_action; - - QAction *_mode_action; - QToolButton _mode_button; - QMenu *_mode_menu; - QAction *_action_repeat; - QAction *_action_single; - - bool _instant; + QMenu *_mode_menu; + QAction *_action_repeat; + QAction *_action_single; + bool _instant; }; } // namespace toolbars diff --git a/DSView/pv/view/header.cpp b/DSView/pv/view/header.cpp index 3eecd685..90b734f4 100755 --- a/DSView/pv/view/header.cpp +++ b/DSView/pv/view/header.cpp @@ -58,6 +58,8 @@ Header::Header(View &parent) : _moveFlag = false; _colorFlag = false; _nameFlag = false; + _context_trace = NULL; + nameEdit = new QLineEdit(this); nameEdit->setFixedWidth(100); nameEdit->hide(); diff --git a/libsigrokdecode4DSL/srd.c b/libsigrokdecode4DSL/srd.c index 38bb803e..92be591f 100755 --- a/libsigrokdecode4DSL/srd.c +++ b/libsigrokdecode4DSL/srd.c @@ -190,7 +190,7 @@ SRD_API int srd_init(const char *path) size_t i; int ret; const char *env_path; - + if (max_session_id != -1) { srd_err("libsigrokdecode is already initialized."); return SRD_ERR; @@ -202,30 +202,15 @@ SRD_API int srd_init(const char *path) PyImport_AppendInittab("sigrokdecode", PyInit_sigrokdecode); /* Initialize the Python interpreter. */ - Py_InitializeEx(0); + Py_InitializeEx(0); - /* Locations relative to the XDG system data directories. */ - sys_datadirs = g_get_system_data_dirs(); - for (i = g_strv_length((char **)sys_datadirs); i > 0; i--) { - ret = searchpath_add_xdg_dir(sys_datadirs[i-1]); - if (ret != SRD_OK) { - Py_Finalize(); - return ret; - } - } #ifdef DECODERS_DIR /* Hardcoded decoders install location, if defined. */ if ((ret = srd_decoder_searchpath_add(DECODERS_DIR)) != SRD_OK) { Py_Finalize(); return ret; } -#endif - /* Location relative to the XDG user data directory. */ - ret = searchpath_add_xdg_dir(g_get_user_data_dir()); - if (ret != SRD_OK) { - Py_Finalize(); - return ret; - } +#endif /* Path specified by the user. */ if (path) { @@ -234,13 +219,36 @@ SRD_API int srd_init(const char *path) return ret; } } + else{ + /* Locations relative to the XDG system data directories. */ + sys_datadirs = g_get_system_data_dirs(); + for (i = g_strv_length((char **)sys_datadirs); i > 0; i--) + { + ret = searchpath_add_xdg_dir(sys_datadirs[i - 1]); + if (ret != SRD_OK) + { + Py_Finalize(); + return ret; + } + } - /* Environment variable overrides everything, for debugging. */ - if ((env_path = g_getenv("SIGROKDECODE_DIR"))) { - if ((ret = srd_decoder_searchpath_add(env_path)) != SRD_OK) { + /* Location relative to the XDG user data directory. */ + ret = searchpath_add_xdg_dir(g_get_user_data_dir()); + if (ret != SRD_OK) + { Py_Finalize(); return ret; } + + /* Environment variable overrides everything, for debugging. */ + if ((env_path = g_getenv("SIGROKDECODE_DIR"))) + { + if ((ret = srd_decoder_searchpath_add(env_path)) != SRD_OK) + { + Py_Finalize(); + return ret; + } + } } /* Initialize the Python GIL (this also happens to acquire it). */ diff --git a/libsigrokdecode4DSL/util.c b/libsigrokdecode4DSL/util.c index 45fb2d1c..3211fae5 100755 --- a/libsigrokdecode4DSL/util.c +++ b/libsigrokdecode4DSL/util.c @@ -39,13 +39,13 @@ SRD_PRIV PyObject *py_import_by_name(const char *name) PyGILState_STATE gstate; gstate = PyGILState_Ensure(); - + py_modname = PyUnicode_FromString(name); if (!py_modname) { PyGILState_Release(gstate); return NULL; - } - + } + py_mod = PyImport_Import(py_modname); Py_DECREF(py_modname); From 4185466401cfccfb75fe9ffae0875007c41e1b7f Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Mon, 15 Nov 2021 16:08:16 +0800 Subject: [PATCH 26/60] qt pro file --- qtpro/DSView.icns | Bin 0 -> 115411 bytes qtpro/DSView.pro | 379 ++++++ qtpro/DSView.pro.user | 317 +++++ qtpro/language.qrc | 6 + qtpro/my_25.qm | Bin 0 -> 30023 bytes qtpro/my_CN.ts | 2579 +++++++++++++++++++++++++++++++++++++++++ qtpro/qt_25.qm | Bin 0 -> 118333 bytes 7 files changed, 3281 insertions(+) create mode 100644 qtpro/DSView.icns create mode 100644 qtpro/DSView.pro create mode 100644 qtpro/DSView.pro.user create mode 100644 qtpro/language.qrc create mode 100644 qtpro/my_25.qm create mode 100644 qtpro/my_CN.ts create mode 100644 qtpro/qt_25.qm diff --git a/qtpro/DSView.icns b/qtpro/DSView.icns new file mode 100644 index 0000000000000000000000000000000000000000..d98f535111e5d7d8c01e74010f32d91ec0f0e169 GIT binary patch literal 115411 zcmeFacU%)&6F2l6_|vz0bYRbD!sJzkBaL=JS#4`Och~IkU6p%$z;Q;k_r$B80-q^{W>d zAP92k@ZPh=@VyMaXCeqe`S95(lM#e??d;6sN3r(uMbcqES6Ui|q64CygmsO9D?m#JgxLWZ z+F@uI4wQ~T@s6cq#^CKRbm033L#Z8l=0``=8oL1Yf%X#=u7HfAKq$C`cG=mXT|dYL zQ5|+*=5Nh#8B!5uedZ@MyaERJI_l|wtb!;Q@6Y=~Mv%F)bsQNgRL!x*D1wd|PIqJ| zQ^sFlFVRQl>N+u0C`)QlwEOHJb0DZt$9(HLzV>skn~oDhS^X+{a`4av?NTSkAgWo* zb2^=&b`{lfWT>j2L65037+Q0?7Ew72GUZYGcq*GgqL!4x7nwG$Et|q&s8Sbn&DCNs z)DNNO)g2jww9#v73_7i}Z6XzfOWPL=9efnMso~5}4(R=4bFlsUI4W2`pEc;51VwpP zn!u#D1l3>SbY&t1Bj}l-2x4fW4!ub;EKmf77I4+Ykwap$z1`Rd(aXijk)y)&evlLD zj9hbZ#2UfPC@Ot$@ft>9c{cSX-)fZSIXiKb?TgWr%U5nlP$$kHws&_Oo5Q(Mj4~ZL zs`ja9l0ApRyxMz{#o>^dpL)F6Yz~Q4Q_Es=$ZRjkXC{ZE%DT~e6~65g&~$r8&L9?A za)rZT*Gha@ARLw4xNWV){QX;Wepfz4E-?%w4KZ55qo3;XPz<&Bp`HfL4mLx?GuS*(t0NzsX@SP zWuru?2zsap1dRx{xvND04Pt|c2Zq-R8k~4!p-6xrKPL+WnUeeS8PAPE6 zatbl){Z|u3dnY{meG^6ht@%gd-_a`jqmnlh`hE{crw~r}{0rzgOF)omPk#axGYH7f z$x;nMK_5kX=A&po3;kac-_PFv|GqID^FfzB=)`pY)B1ld7BG7ui0tQljnAz3kFaPN zPQs}_ChUJvOG`_ihX3Gr{bTp%;@Bbi|hFfD3f0uPw6zGT^nEn6N zyEJSJP_d6mSTrma|DxbmrC}x*4U+&2um7{VH4w(wh2c`h{Kvpxq6ad}-lgG~8tZ?P z{v;d(56tzYVVI78qnDlm?B_y)iTXEsI2dR0(_~D;AL+PuY}vv;SnJ>DV0_n)^$#du z%pd8PNk7*qp!~KN{^0tfczkjEVe0?`@S|Nnt;3-3u77L(K|Bbs`)!p3?td4LLH}mX zZ|fu`9sB%VALiSEMR|aR)A3atZ~uvS=#P&1X)xx_KbSkv|EB=F`|q4HpaX8v?{4Ss zd^%}6QlC5tlOfRq3?Rki zXTtFty&xKUKEf~?!14b{hFk+d;=>EV?5yn|NBOPaz(qlLJpPEvqQjrU1NraN-#x*< zpxzCRk&38q>WQB&`wGn%JmPOV}tqTLhix!yre{0#VV0HEOX26IsWT6PCJj0@1zImxkFa_Q-&w0hVT|gB;ks<3I!(jy30y@2rbHX@ z1x1B3G}#OV$|NqJ-V8umoD3LunKkX;u7Mr0&naD-ay3tf{7X2=u`34$vO@jisI-`zxRe#4LxGq{^xVR9$v$30~ zPTM|X`X^}he(!~!)f2VBIdp^VsLAXP&M5K2TupC=GJPV7>={1hb{nKN?YGBLyctBg zi7gvZS#O{@;|TlMEDES3(dj1Ej)>xxi8^X(>e_JcY5Eg)LAaonEA&AVnLd2$MwEj< zK(V6k`Lewrar23}%>s^Se^)1HE3zD}u$=r79T8%vhl@8yh3()Q_wc?y$Ne_MQ;fTl zH;2S@FX?2X%H7YrT<#+IKEOp}`tzJo1;Gus{M&Bc9Cenb00ts!>xZABfS?3N40{I+ zZlrryEqs5D^Z{k+_K9%)-QAw;;QAG=UIC`Wc56b>jsOQXM}g_v3aB?n(LNKt)2~1Z zXrF|I6L7geWYjyc0b+CNAbL284za+LYVXV;LH3CQZ(%L>U<1H*Z9+XcifpeA6fLuN z1&$(==>c8hK-w(_S4d~WWEo6%&{PhA;mUU9D6pNI#4d25$aZN&(O35Fz?3EnX9B{E zkjc?_dk=60S_I-0?Mq-L^I>^%NNAHQC{$#-iBa?e(~AS)lmI3v;v>E901gKyID*+q zY{xnj;nd>8WOI}-7oaVkY;TU*8vwt!IItaDzQ9!)u&KMn zR>S4D5SQR@@co&CvBh2wY=nli8GD!;eOVyQEf#gVA%sv8UUl&1C_DSSLth`lr%Os`S6HM;#L=gBoqpSK0F0(ov>ci2vd?!DCT=Z+AR>bh#Q)OLWrQ|2B9}3 z(EN^mh#*-*Rc=;j$bW^Lx9tOD-D}1FQk+{K!H?#|`dqwr4 z9vo`|Cdj6uB+H)dIOU88Usj+?%HW zOlU9P1(J9O6<}xrhGwoa*Z~5)pev}7*1PhE{64H%-!F#@-xbJEFn9nzaLF41Aah0X z7Op#V=tSjxe0Ls+--msH0y)|V1kflK0iz-?%Av~e02xp|xI&M1%uX*J5&A)s4Y? z{NB8wA~6;aJwm<^^IkVF37Q&37&hSJJ^}cyL7dNT?SmUZLi-w^mvWQf9nvTeb;=-C zWS#W@5gQts*od-7*w`R$ZN`{L{3eme5m9Io)eGvlK0J~@AQVHW9B686gqBd;%;F$F zH$1R)jXdoxzN-G=NAy&v?C{UT4Cx;zKN`}^X*hWqJdS_ohxF!N6yvT}1pjQn%M6T7~OD59)~*Ebr` zpFqMhd|gl?3%!RZ)g^6PJ!|;zVI>TuVZ-%itlV_>V!7m;Q{Qs7;x4@^e5;BZs;9(NUnhPXD*@8IIt5r<2LGo5Wla3{t8-#t}Q5f4ag|(l#VusLDXLP5$0{w zS)cwCGVG~IGBj9DMtj0dA+sgX^)Jbt5MrK%Hb%67-KJ0=q7Nqlk*GZ_0Tz7uIUTq= zB+80+Xaq(pokIbd&VEQai7ysuW2B{@(A#ol^x1US0i{k$gv~wloDsbkGIPrhXq0>i zT0BXMLD#(idz#f&+893l4SH8T7|k-(W@xP_hMH?4tq4XkA`A7CJHbCyG;|n^KEee- z59!eh!3R2_xKEUNzCJ7e+Ji!45ZcS8(sj3?Jv%7SmvTmmdV?yo+JECTJ;SLRZhl7r zP(fR_X;Rk}XHKDl7|P;$)Jv|8qFkp*+M3#Qnzkl&cAyyel+ns*TBgBy`Vh7x>Zl@M zQ$*36MGy^65N%r2HLp;>l+bwHVPT$n^aAjmwg(_&wEvbV#T~*=b80$@dP29plhl37 zhk+c*szw0FXs@3xr2k~Ckx_EI{dJD1K9Ff9xp=eBTSwamg3=%wpE0FAem+XClT#rLpSZ2U!Xxk(~YSC(3(~OEdtt$Sws)TDetCe1u;mPEBVkuP#{oj zT2K$@(y~GG8hHO~FA(y9UndbX5}mc^fYOHD9zZp>cH+$WCbS#CJoz28@_;`4F%An? zP=Z1D!5-8dgEhBz!v(~Jk2W1}nrfMWzJk}2|QFcx<4s>4!FcWi763$yUSvw9C zu5Lxy7_2q(I}S(F=m67<@&{ne!~Nh_$oF<@#xn>SPM8QHEf#0}IF=d@RsCYfj^!C( z#FS5%HuSo70z-jjm_LA0cJ$%`dbVjMGRPW^I7-wG{wX05lK}ZL?Ez>teU8JosdRv8 z2C#`>0x)G|+kg%GG?N*MTF$6EXgEC$a2AT=U#C(5r>t&68_l&+VT8jT<6_cu=z!Bq zDp2_;O~AEgf5-Xd=O`&KiPIxc^d6m_0)9L&Fv!NmlvEIOM2c3A1(75=^)@c3$dCp& zbxJMTy%|g((MG)moQV2rrGXq>dpYW(MNa}bYddfS-5V(n7z%oF^tmxD2|VwHOL=Fe z4JaMb@|BcC5Mo${3yGy>;9CYx82EFj(xa3Nh61GN1%|W)2rGA7Lj63g0aUz9D;|^Z z42K`-(=!-su*Zc0C>DCy9h0*(GXW)`#m2PzAi@LZZCa=`fVNs|VfT6DYaD*8Ps?O* zK*TjHC^UcEGdWW;3s4gJaS|2ciq06g?@bn31F-azCcxS=`M8X1eOeX+s|`R{3_N3( zv3Wx7pz#O?TWly0$g~lqIIm!i_9KQ9(BW1`gTmd|96&AE*lVK|kzcHmfW;jE)kCU|Fk)+ci;c+ISZkpK)S2@9v0+^Pi0B3ESua(Vk z0oG5GwBcE&)57p4KaNhvc!{VZ%nBsR59Y4*lpH`wXw7tOm_z9FTR3x$9zBPFdDdTx z4l|DC+Li(14r=D&u+UNq<|mrLBb@uCDJ_?Qjp@D)Jp^PQ@5Q-gmneBS+-0i?lbrUn zDxCZ6IBFgP^Vi$SS};}qv`>10lFz_q=tv#fbr7<*3+FC1r4GP7$MIQsRy9m3M9C3K z0Rw?65?Z^60@F6t_yOL^GN2VO2tD}q(+OGu@Bq^Tu_d8p4F%Q*b~jE*Gtu_LGM)1h zycvS89eN4SfGIi30M->UowBC|Css|94AsoFr(nwkgun?U34)xr`d>eK`vlH`|%)3Kgras7~hf$J*QP#_~C4m$u_ zzr^<|v^Wd}ZGAQry4Qg!OPYaGsf){C4+agL46mLQXxbY}2U0(j?_i)+3bMzA${{rb z*^me-(kY`{_$W94G8ak0LM_M#Np!u#D3)FB)x~ycsoL}WYd8?nY?R!UxkFd03^*8j z`5ur9SJ~1b)ltyanszzA#RFCB`w+QSmx5)jblUoIEX^%mOQ$3A!RPG)up+>{->6fw%+(zOP0@@VG2n#mHr%_GWxm{e}wdT zufDb$yyT`)wIT7=rqN%*NQNJH7Ko6$E=|^^W2w9L_+#~WDsQQ$T@8loEDXn!{b#3V z(y1RI4W>`tpNC>4LE4E)!?fvdV9C%PHtk?66c38%jROlzbhO#@QqTfP9@TWgjuiAZ zR2BE_td<)O*DYlz=?)*ce4lR#8UySP1N=7`(u=@@2J5ap%|e6lDkkT{^SkcsC$RD7 z998x<1FK@1-rtQ3bar+u;V3yeI|YPCz50F!Q7Pj-j0o`HusQ5f*jt5f55KU~>UUts z*RKzQJvr<*AcNy^J@tJV7`&l1KiGxEeh<5mESI3{)*A@<gcep947`vqqxo9Vz}J9`EAc)DSi zuoud9O{s@_(VF1Ge$Jt=92~FRds0 z{Zc=+TQ%$Zb`zeR);P+0BS1gC&YoOlEF zUh(SXqc0GNEdRIgOn!dg^c1#q!yC{@c=*3x1(ign`>@SP{2t6I0ZM2iUb}n`fD;bv z03Z<3Juo~(h*vH(eqe>m!>%g1qr(7r`Lhs$kGq~tNhr7m^JNysiCboek{1vZ1{1tqzfQrRN&9_c=pv9;*`Yls2P}* ztAia_F5pboEk5ulp>G`>pFeQ|79uMjILN5H+{3{gZia*Zhk=r%KZTVT?g%m*B0BNK zp})upcDl(-_m=}Di};$S3y|6FSnWYZWluOP*fD0hyuxSm7i>(pLxv2S+DkbsKOlL0 z0!|{@`xvt<5ccYU^udi40Hgpu^g{Zf3;P+4H~2GyFx_p?f`SDuBPIBn*&XF@4cjybj*m;rRS+l#Y)bz|QE*?tYs$^*L7Cmik!cL)Zi1S!mV06WC= z0Zc@nFhek&N=g}zvaNDhIS0fh>fU5K-Oa$-jUtCs*PRN%s==_l)L4#6SA6+nVRI_92g zSN3g;L5P(jV3qSgNzOPsei(jgY^WReUD7m(oBjH6$j*s;*^ z6=4+$NJy5!$O!2UaiI4pjuF|IDOS`b+ORB*Ocn zY#b#rvDBP|3cXl~KP0dpfL4z>+=Oyg67~WJB)9|W5GKJ;*?os(cx9A>%1fNtX)v0B z8l=gOg~1Sno!6NFI}X%H@7XEXYal)3vCpia}Xo1NRyFXK@_i4y4*+p%v8jvpa_3 za$>-fnb;JPW&eod1ex+JCWJBDZJ^?X0pKY50t;^YIPCc*p>H^B3?-qhK}>i$u;&_s z`(y1NbDTj`4m?SCbYf_|2Ma^NE??FixIr(#RwA0`kj-&{?`$SKi_GAG9f8j4EDXh2 zZvpEwY*^^)Tn<)-WWzI0V%{9!?7hv*0hEL`2Qp!Xz`_EHhH58v4#y3ci&%g<+{U60 z>`HLR1(bw#gfL;^VLK1ZSv+@kE(afuBRd25t8R4$}Zp_P`;ZgUu)}9N92eI^4%5Jy`zS*#odN8KzZ;Uu;$;N|PK4I0F?( z^GyeshgohP0Eb|3VFLl*hN|^p!oFTRE{VUdG1%)Ph|XKA?(Rw=WcUsd`t1BI~gDWL7S z-b^Nk4KKi*?|vI7JYeXBkfnLlN}`z#F+IQrYi~n#uq%h-=$BB{ix(9yII!xfuy1{P z7wgJq<;i?uSw}m0pWoMtf0P}yUaTU{Ajh<3q|}Sec6#|^^(Uc?*I`v3%=Rio5MCsU z!}O@e%Z`pa4#k`ytl;kmQl1IAm;tqrUy#u5c!v@W(fR&ss5;&UK|aI`;zB|K1yTw| zU5%NlMuKu@A`0#0{tKqj$$o|Qo|*OloEsUIYJx$xovuQ#M`Z!#gjgQ+O71FJXgy8;6wjMs{q zv4j!ojlQaTPRwW6Slgl8V2SQIv7KO=W(H(_kwCf8FMM&!i3xcq$?;AdmX+4tc7nI= zT5#(^(q4RPXzrG@iFqHN-1T8GA*UrehP{IX_scz3whKp%&1ABie1by4t_6Bv*Dt^j zr#tVU)@X`%VYx$8uvkn7CS*=8vG7i;!%B^eKoAonu$S}A-BPF^6y(xwaXlAa#S6tY?r~jrPwFn*SGcn1F>EL6B`Uu<6@+563?0JK-LYQE5Ycec=y5gf_k(*o*D(5YWzI9?}ZT z9sB?wW3w|s)(V^r*sc)~1|P&D2tZ{akI;c5y$#oR1W~`Yya0}IH$sU(lr?g%^N<#A z`4b)i+r}cGtv5kFR(a&Z(3^k-&VK}hoIVV}TnM83MO=WmVo!PA022Xi59blOU?qiK z-7w1#(LO;KC=vBTR{uj8(j18y0;xO3it$MJfC%~^!v`0@%8E4I0(mWvvO|}4oTZz8 z8^+cP340F4it*e5VhfhRnwS2(tEp0TQGQF~B2|LDG&54D(0(JzS(C#)G|$!CZEahcsg>#0D(a!Nw7X34rV! zd3UkD&L5=`&rr@{f9UhG&*Dlj%kF^9Ks(|9B} z?bVrvg#nh(^b3Kkz!hVMWdIy7qz7b^;gpc93A(~f#4Krl0G71M(e@OO)+ifrD2BoD zB7QPpSo#T%xgY~Oj3X0qlfV+J&H|5t_aIMh0|bnO`m{L{Kd{roPsICSjuvL}*zg#L z5_trE4`!-_pULCMk+uO(LZ{X&XcKzCweSD}2Uw1A5M+&TkLr5|`rtfh$9<67gxLs3 zfwFjx*o}+>bMWYeepx&x>}KD?qIaO*BVfXG#zMzd?0IVCJ_05zXdtq{1z=-;!($AB z6Hj-423c1&4{~CukP9Ko$0J78gh2$f4R~-bp}qAu6Dk!%|A<7ijhoGLg%M#-gs301 z^$T+VAoL0D46qQ;u3VlQWOm+;$z@)`wr=fK+r1JcLa`*wpm|c(7Uh>VO=~Y?z{2u{jHMeND@Rn`JzT1uML(Jw7*x<)dMHdpl?roF>jEd`5V$Mf-aq~ z>Tuv67%wd0sfybXq(_J?UJ^70ZbT!u7!);15#)Z02-d%b9yA&}FXqCkCKBI)lYgB; z{s4}xk+SAeh?;I#I`f-^u#7hJ;!CQm1(w$au@IKp&IUf>;d#L|SgZP5`COog z+B1N{ZLWtSfAwurSaC_HtV{SDD2)w}XrN7vE|7(^gDdd2`?BsPJ{Pi!hNeCbNHuz! zg^dxXFz-1ka!ZB9X8`06El4tb3b345p>Q8={!|7VK&1foJ|%1yLf$565jE6TfwiJ$Neb*5*K{@uMD_f)kSD^q$ z&Y1guep=}N8+vyP<4=_QH)z)!A@mGC16Rd{*iPGO7lJVWYP&+oNj-+LT-_-s4#gLt!|EiJyORn&W z-oNYp(PqR!YVkLG(x`uG043#b(2c7|oBN*zkY*(PUFzXY2X>_QkDuxPqGyW)uU)4i?Trzwlok_~n6L9{A;fUmp17fnOf@<$+%w_~n6L9{A;fUmp17 zfnOf@<$+%w_~n6L9{A;fUmp17fnOf@<$+%w_~n6L9{A;fUmp17fnOf@<$+%w_~n6L z9{A;f|632huLS<1pSAz!`8#Qn$v<@Xcfjf0rvL2u%Xj+7#XtRTkN>8a@InyN|M5RJ z|J7D>TOx?sKX?E(K@|=_Tfu+z_s@J}=dlCmgH!(*?I>D>{gFWgS@{n|fZTrIHz0=o z?Z137;P50GK70gOF8C+zKJj3le?tH5fBh<+Zv5ZB3MKsXKIR2R<=^drra$}+ z8gV21WtG44)3oNd-~Jhhf^~nZ0gcu_WAC@`wSS`lP5-GLLDs$gyKX?!n%_qK`wN}F zX(CQD|Gn1VT@Skie}3q%{3bjTld{;@^3fA?3eMj!07|ETXj zTf-LL|BHSVv@`CE{(tKGPej$^Tv8kSR|NkjKYg7af)*_5ksEl0yfA%+15=RaH zb5%e8G_i+`_0l1ObOr&}kmbuP;TLqV-_s@_%Glrc*nZ~T0R$lpKfGv>&GJQy3~bJv zJaG8fegv^2xU8=^T4|#t|GYmu<-6DHgBmL4hXPLQTX$|zSjN#!k6&&TP0uu378-MW zd&pB0F*8N!lh?`FB^TS2%zKpve{wo`C2+`7t=&Bd?nW!SjnX4Rr>-(xM|vd5uIX)_ zWh&t9yw!VpYo*o%HLVTnR+kj^7xT1g+6g;#7me*dw93nsYBh4Hg<56WrIz%Lp~IgZ zJJ)=&CSJbxeaN-J8m+npc~_?u8-3q$>+tq>=P0!wJX*phO)Gr4^6chVvWot}nJ4#h zzI*!^Uq3K)nnj38p;F1h*((p+Wa__1zG*O`Lb3BA${l?z&oBk|^Q{MH+`zP~l>A4HC!cT3U&W)PJT=>!?Nn>QL zp!wY4o8tW;H@1w{9HDEHvuAzMlw*hMRY@Kp^_AjIo4}OFsrgfNZLX0UCzW({ zuUOLgIQL_9K#&r5ntAN#4=f9LuB7XXC;w7lYvY6AKJPoX1tfxdcF$~wX6>YQZA;7Q zu9Zf79r4jON86<&GpcHh_#sF5IE@lAjCFqZ-KZ1aXFTGE4m%#Ns=P+-$xmIjbN}RY153-;-8=J65h zUOsIa@pk3g#(i1&o?Q!{(tG_UE!rBMXR<2Hb5{Fj8&y-qi;j);b=xO=REo$h-|@Zg zk#eHh8Drll+;kK`k22s`lH7XLo7;{N-u0v=1%E~;NK&Uny=!rQi!5ySvl zZn5odrk*9JG)u><)uOGrb8pAh@ryGwGnpP?f|wJPkC%Ub ze12VZbd!lsO|nB<;}wV0pcvoAEZ_ZeGRAprUGAY-vg3=PrU_vW-_r*8E4UCo434#*U|YZJBvaK6}KT$T}5y?=-*upuSg!+InBz zdeHThH*RNWw$a-bFP?B*S4z49hd%ql=W&x`Kbxt>>rH-CY_#HN*yQY$Nt?7j%WE1( zJk7lBIYNuF^RR~3;@oE+PA&bKyztJNn&Wjoi!|idE~nPanAO@Mn&8q>^HC>7_r#Db ziLU2&b9Tpdxa@suVKByg+^YFZd(KVEJKIgZP9?8(Lj1Q53fnmP!sg=RnaffuM_L~p z_l4#@&1J-e6SBbv&mB*kmv+u`Z*uHsdH6J=@5R>Xo5y)%#+^UX{(jbKWY46@y*J0| zUORpzWS(lxT*^?rW2#l2;UAQYsZsZK zI$G+M-BX!c5)B5Kg|65B6kUG2MA2t^b6aV5VyMu4?zD=D8&{u=Fq<$jW6@+~{^NZU z$vY+%=^j=&!P>EJtxTaMUv_VNPRheM{bl=;A0|Z2G5M%iI9a{ekv;p~{wL$Ka`{Jn z%NMBawO?qkfc$Q3tb5Qsg{3aUWy&VX>#W3U`Mwuk-b=~7ShHRlETwAo_wLh}FyZCm zID^>M5gErr-=pu7KXkeHpdI2V^3Qq#V)L$<-3`-LC#2mSJ5KJ*Ryej=dGn%K=A493 zS9Y+v&D@41Zqz}lbyF=x&&6w-uUi-SXHNe(t8n#%)0r#JyP)@P-KyPVrr{W7fTUJU zUnZ)iO_#W`I((+c`LSk7)2E$Z{5&MPDAhclzGj4DTzbKHBl(c5#u+-qSww;+*-FV@ z_0)Rz1t)i@tR9`Z<-jKTjul6nvS(DBjo7-rzTY-!{*93@UQo{$mes#bw?YgGw=FV! z)UxtmtuV7fY2%FTLz3rzWSHf@)}B<*J0dB&(mnF!kUP@hdSp#!gVUqVS6Lpo`l;~j z7@wrx4Nu+FUS80>vMWZqX=uRZW#lc!uZpPZlaWlmdH zz%g}Vr3&&$UJ~*8>Ad6L=g<5?t$L6@VrJZU!fk?!n6Drv>dheB`l1FFH@3 zw$qC$>D`@Ismsa{pPv_b#lm2La+$a`+vsfkG0v*9+rO&4``n!zzFX!sS&}(FZS&6Q z{LQ-t5pI>S@;c(x9Nua6J-;GY6z`j%@O)10q=Tb0DZ?y{#*1q9W;P^09S=?`VB0R3 zwbI=y{y1sa!Pyt)r&sm9c*OTrTxqWsO%Q2K`7qfEDeIcluB4W!bTDsgOK<;D8d1%* zA$4Z1zeG68<5FXc;l%HT7W-$6-!b%5(c?2mYdu_&UYQCWtxk$K(!2UXwybESCSmiq zDV6MgYUJwa&5f-N-1n6n1^uv&O|}g8Sw^*e8^c(Wtu9TTGD5a~2*=xkJ$pi(rE)~V zsvVOA6B-v)CJnWWPrkh4`uR#;Xu$}P!ek?rea?u*gVd=PU4~ax5AXTB?Vw|*+QX&C zzLMzk^HO%-d3;#;kn$H5LY<=jj@g%qX+=k?ChYVx|2(@wW7~{54~FRL7p|Elwlolv z5#tA8Ia)a_U5YIqYv$;GIn!rVOjTa`U`xxZt`CtQgg_7#)ovL#oV9sq##8TjQb6ge z^K%yZZpcGTsb|mExl)8z72jGR?)^#=1}F3gH7YXZ(HvJ#y|}ctgtoymZ_a`H^Ixl% zX(;(;3!i$0c~ z7<|F|%tD;T0Gs&la?{{b$7H9I>l|-ZV zb0**N&R9gaVKH}3N@UF&t7}mfJ?BAl!LEpGQ^V-Y`>$h6-mkr}c#LXd-4M;TJ(}dgv6iJf zo7*kP&u6JPTM|!g5Uf^CiZ|rvUJf#dUT3wdX65X+Z^S{H8pTU&Eh5^Kj8o+nO^u6( z@|Tpy`8@UsMs5i{yT(6BmN(pNd88I%oH1NKx3_M%L)7qVd21H!8mzv|V4lVsm6~m) z>feUAh2Gy2U!FK|-_C1>s%=vk85c?P1MGE=TIVIl#wSr)ifZMZ)^|P3d|#j5Q%l%w zpmAv7xg*94E32;*zCAr}%#JDv)5Z}AeEmAwZE2jX&_L0idUo46HD_Mplu6kW=+!!w z^!7z(x7R?bx^CQ)o5~jBx;@3q(v$0x=Xa0)T&a`3Be(gZKsM>vc8A6WLyPIlicQld zwmuzdZM$LLwfB{JY1H}YFODl$Op7iX?f!bvLN!x$+tluNQtw;FtHT#5`X7J(qI_MM zg@VHk-D9eQ>~}^dn%;?aGVmSTll=7R(1iuYPmrrl*`dY0gBNdGu^^GUY35G(H_4tZ z+rB`BGs{J*H15AUX`Hh6!y>)hvGVq)vKiewl;^$Y`aMnvp0vUDfL&jN3XwyuqujXU zn~c0oCKR3w;a^?MYp?C&D{Q=$V(jZl9^B$d8Qe9p#CAqN@5nwI+t+-bL36h&JUhy> zxneQ&fg-=@p?l9M-&@w4O*J_)O03H;d(Jtsd5E%e%uJi0<}J4O3@0ioo2W-FTO8o9+sCkC+_@K@ zx4NwyyXdi*L2hWf{T|yoS36?Gq;s?F#*Xl@%WhkuAn~tSX_momtui=Y#h>!R_)OED zW#48s-f*Bf`qS?mnL6XylDb)Oxo@2^XmPFIX3;XFPBO3jtPeXBT?gmx66wz5r=~=8 z=e_={uiMTPzh5Ue-IlymOdZw#cEP8$B&WQ~cNQ9O`iF*n-SpuzztZcgXJf^fhs#H+ z&wq2m=tv#q>`v{qL-tUEDlcsJD|_`46G#twihCXSVXIN4bfcXm~A@6OjBE5%iC@Co#v2rdDr&8x+5%q60mY@K(sPq za_!}n5Jy%@?5wQ2FNTe_xjH5|KzMX2c?p3~n=!j_(+zri|KuC?M{cjU{yky!!Qppb z2ox@TTc&L1n(X|xJ@t`U&uDtt;C*Eitb2IncWt)M@F!~D^0PR|TJ~+;u%!Fr(#$v2 z%l&AtOF04V1@23cGpL_gPo|uAvt`EWogN#Uzkj;5!@k2_!f$Oo%+25wjSD$;qh{MC zlL=;L<3HPtwE|x^;;Y8en{!Gx;R4#){rF)1W}&=pi>#RX11~ z{c*d7ecOx$k0f>N#ICJ_{Bqk0yIK@KI8U`vm{(e?ocwU6&TCffnUj`H?%S5d zw2dm5eN!-J?+E>ejNhf$ebK5-=Z_nv(m1n$;iFwsv z^3A%WCS^54+Sh2ha+k8@9co;B$}_>nM|_w43X}Erq;T%f=6O>RPrsU89-gX-9@@{T zojZYbW#Y)vISU7&?zNI5a|cZn?>xJyIJYB=^)+m5wd>2&DrT65tIJ56%RSV~@{)%w zQx!iHxTM~EGSt2`Wi?%XK^Es);I3YKKoHE@`Oq+5VsYD^x#4#C+WK4%kA4-lhFO1{ zV*7m6gRv9lZywipaQ24H?YCZ7)V&>V5@5`eNX8TCS zx4vb06Nq2R_Koz4rCT-C%q<<^vOFZ~>1%OT*0q!<;;C7>cjQ9S;&y|Tca1d&R)oQt z=2xbz?cTlj)b5)6=FqcqCY~@v9!PC-hWEd1^Lnz%CtPDJ#ojyme2$FMcX9~ly8&Ak z|Ek{${+|7aW3?~ScbuM5bBfkj;p)ORBK8~@(K!+wRLb#5*RwJ$sA&0ct0L&AZ1hxuiGd0^z_YdPK{sd*m*!ycxA5igoCJJ8o8N`oNa#PRw2!= z+MH0#eA(NAtXZqCuK(=QM+3D&eYSGKqRkJ6bYEIbKCwXD!!0Y&c(nI$)8K0@CkB<5 z#y(s$=dla2ok73HOn<`7d#&vm{K2WZsbuJK6K()6wh6mQf!{ z`*O;K$(LBfWqs#6)o+DI?mTYm9FBVQni=HRkBM@te>uk^;wpLiyIH%JkG4#?>J;4L zwjm~PbISBhM^8S`^{|gA>%MW)Kr)2L<_#aAKi#c<2P5U`_txZ5C*zX+v`0q7DI?mXJd37bdbz2q62C4m$loX*fkfLbRU(|Qewt%^HZdoqIMMU? zA)db8xR&#qh_ANQnsn9;qTNwBeoA3@{m|`IV(qbSZ=USF+9OwIjajo&1F2W9t`>z} z{IqwpszFbr7VpBC$>qjfOLd4v3)xrPN~RBI+x01&iV+6cj2cs#8d-IUt8~)tLSCCB zCA~acO=as6P4oO{iwvU$M?9)8xcMOhipv2t&O+_d32vg+%!O^vKcxlPX3pDrh}fed6g}QQ4t24ciz{fGYnTS+tMda^qyk# z(NA+EBY()=@S)8WcAllQncokqyeROu)?VPWkG0=G=hIiZcld1Wb@w+r)y;2~eYTjG zA+*wet1;x&ORt--|y8X|EZH}G&sk&o4fj!< zS6U##7(;(eGJA0O_fqE@D4lUdKZ0x7_VUX@X7f=ak}A`v^zQRY^cmlOVV|`YQ7l;+ z;A48niWxwl8qM-hHOn%a^W1YmagybSh{f-xU!ret+h|mB(c{Ja&i#)pl@Bp?-9P8L z(N^g7JkFP0b=zxs?bL?w_xcZ4%c7^`T;90YySQ9an(a3);AokZ)tgl_hH&0ku)`vI z`}89OS1SzSl%lH6EcWDO#JqYz3YL!=)0N{z)H5|xxT~TY`N?j}hogtMU0T7p39{Hc z_P*CID#o3O{%Ul^hJSF9iR1XQ;mU7Mvl~8X8J4;9o*6vuT;Hzn6(Khk+c=we+ab|y z!}c}3BW+*!IMreNo3eCO)m<%qOTulL;>Y(l2Hxzk+0`J?AsR1Whx(T9C7kI-n?n{} zi=R*P=Ws_FNl&NDKRwG}j*U0hK-3k!G&j%ul+@Y2&>>mp+ZQ`OHO-cjfo?aqFBRtp znVTCYJZI)!{AT7?_(-^B+1wNE74H(i<}h0yjm%f?=9_VZ??=#P7qzEzM+v6P9HS`N z(d>2W#P0PM5Q&dXaeH_Yr|fNf*{J85#ZaY36A336V_wD7eOb+mJyc$i=0mpJc}BM4 z^-)P{cjw(dAFwfkk)E(4a5Xf9M(u^Fq){E7D#)j!RwL1G%Uv#dL zuD<6SqyEi)kL?v%Gg<3-0qbZ^ZwV#egO3{a4i?cSrpD@Bb*woUwfoThHIWzfmD^7) z&_Bi4UlwBUa5IOyQrC0c!X0Nf^^Ay0wEZ$}P4QEL=^_p8rp6kI9`Q@fmj=oEr|CV{ z7ZGkIu8Q2O+H4#B^!g4TLhqY3ez5!Lu5|DcGih#}CN1XswTksyFCce@J$9DZRB?^8 zPKLiOVClr=j2Tq6Cf!n@YRco7Db%8*ii=Bl`7L_>h<_ycwSGpG&XqkUxZ4lfteIr5 z*d&;MO%<+4<{(-B(KS8onH#e-8!1Kqnf4Z>&$!Q zPYBU(V>S=-I-0*qM@L27!|1e!?nNZ9bp1@hYx|qyzZ6a$Ei^q5r+#&`TKwr*3&^@N zjjLkJJFbb(*|*-&Q8B$0>RPZ&{gyn8uy@!lH8fYMx~8u$=@WnH<##vp1=sJUB`aL% z(GHWadQvy(B)e+W9Sm%&IbK_AC@=WF#O$2QT{XMKOYejjsdL8JaL862_m(({UEC@iHO^3?C0QGLb!fs3dE{Yu@yVp51-iaG;BJwzF{Nc&04wCBeru}++*PdwbL z@}fpxQsy_myTEIL(ez^%KIf*tpJ}%Bo&7|=sTa93*$eg7tx>qS`%SsqO`oSby~3uO zXlXAf)VG_rXSy`!EkQw7BhvHHu^B@-y;GHJ);Vopp(6HD>%vBV^QE8sA3R#(-M+&{$Tlw+ z^1^4;qXpY?PdP;2v4nXFs<8_ybDwQAqP&dNIKL#bCgHnI%Do}enMSA|r~h4EWz)44 z-rgybEXWOOvMAQeYTWj;>*}6emX)@UoWdSq9e<4QooN+3hL9XU-N8yWyk)?CS>!z> zp++)uvUHqFk?J(gr(JrM5!Q!3U#dsjH0Fmn)RjdJiMBd$(Zqx^<2DDCa(5nf8G9ll zL}7nv{rbULcXFtiQi|XZ|reU(IJ*%%v|C4Jy~1 zk*A#5^TW20--R0$ECjNRR%EKxUq*3gry1lujOLiFR7 zNt?~X?tZ^;bhd&Hb@phcviDKW-8v<=oObj6j_;h4v&YTaBeDwfx0*^=c3L*_Gha&< z{G}sLIP{Y4_v8m74!Usn6lD-j=c&G8MH}B+yE9 zDos2@^xv!^yF8X$a5#R&;H>_~{``+mx9h}AH<~T3ZwXU-eud{db4uuFhnv&3yb9V~ zthCLs-RtuI#ok*!MD<2(qcg+MH8e;K-HkL14bmwR(jlQBNJ-4lNP{#8h#)N`(hMmm zB^}bBfOOX|bND^ac|V;`=llBy?7i1s_r2G;*IL(g?Lw=__mF$65w~1GHukREzZe%d zJp^5$COBQtn0I)jUk?LiZN62lxo6A|`631{43x6_r}f$bU%$tHT@b|?N}KJH>EFc( z_$=rj`bHf`oROs~@Aah%ZPh}H#sm`k;a90iwuLVUhZzY(rZRS?D9 zxU*S4mr9Odhw+MvTA}|~*mVzYimRmE!+N*=lb&tfK+nHR4!aXlsfz`U7UnD!@+bGm zd*)vbySAVjJjGgUzwk%o@~w@tv&yc~dr=>b<&3eG;46Nq4kby5U~)6IJ%ST`hW)J< zYx?Nv)(4BmLvc#LR`uDp^t*H2A#{;_d$9o}gSMP`oPeCjS4{GjQFr!NBIBzayeb@X z!tU4eXAob3$!V%Iv%UMedr}!x_G1LYznHo;!y>}<-lKI|uNFq>F|h#1Bp4b)4XaWC ze&X@9+#-8{Hg{j~XfCwgDqRXxfCiA=7B!*(ne44UZGrE1~Lu@-1P*~Fgt zag0HNI3Q$blmNNQfaC=1MmiTL#9NhtmkI;XoPCF$oLAf5o&EB!3}0VS@?ME*Ifs!4o;0NGQCGN767mH2lfW?8?Ywd|c){(-iWsoDAcP;R#I%Y4f2Ai|U zo_nlGFKME~+UCt)2jwLI#1;WTP}jm*24{dqL+N`(_gK=XYjE&*<6olbTFc}F7&b}O zPfJf~+MTmdJZEGl1mkclJ*3`1*7#RuF*LSl3sq+DZ{Msg<@%$rUAJu;JBKbny$Z1^v`8%PhHwnaU5_B?~C6+yHa}&_K;Wb7zh^^IMR%Sk8qW< zBg72>x`6M)f^-9NEit@n$7e*m1L-Z*Yu&DkrfiAWu}O|n4Wy;*q%1_4%jyj&ZXP9e zef52Hsh z3|65FwdNstB1oO{9xL>6gpuO!3p`N{CA(alw>9{RoKN}Y3g0F6@xu7&?so?Sd7{XL z1=@Mu1yW4p+`8FlD`t~P#xa(s!tlF^t(AG!62;1S0L)=;G=aGQcGA1oJ{)v0jF*=; zkE4H{4^K|G+HyYWiP;Ec)^b74(W=rN#a0^D;wu^z84LDK=XJ!}e>zA3wKzM-H@SjR z81@H8O)2SHT{%C>@aw|k?()QC2kt-Ktp485+FV2HASxbXDu9LVgN{7y5YdsJeGa3O z)%c2T$K!WZ?;=qZ(X*KK1wqpjmuf3^^CHN)`J5+=!P0{4REvk5V&&zJBrfJL{jiAt zg9WH{z;@IE9N%-&JiV=vH=8(4FdFFP**=_cKv;)NR#d*8U%qh6;vCQMm@>XJi6bzM6JTzk+Stxm ziL#8TTQ!<{cCGIAiL2~N`E)*Tg^Q-GsHND@vROn4p}M98E9U-4xWlQ$$e}g^w$&L< zfk_&BlpGXpht5X%PoBHr+%bd6sLWy(L6cGWa4oVNSkds0RBw4#Y}>F2b|Ue zb-nlA%@a%1p?0~i>+@$q>o%NUV0fGiwpOt`o3ul?Pomg{UOb*@#s0PQhexxD|YZ{9VZ8j#FQHE8(AYP;1zW-B1zF!g~hJS;?r9uoPP4(Q@7_1 z_=WV?x<7vVRU|4LNKwlPxM`Z@Nz5E#2GSHfwa>tHo*x)kqYuv9RaY%LtzG9`3ayRe z=-!ZMb0PwzA9K$(y@}ouUpt6c!M3A$@{kGAK*pigs#awiFP)=UhSzSj_3S`szNbfF z_WuM*ZVy%dGGDrX-byX3dVFix*g}B0=wlB6Jb7yQk;p`q<(-BbC(jX!f;{haP3Bkl(?;9IIJt)M^5x+$ME83S9?cbU9t>$;X`l!kmY-;yz>Butm$ zE4G=jXcTCG5Cm}1_9f2vs)K)>=CSjHiRZEpDHB|jGbuarl~HM2@t^fG`+NTUhyZGO z*U^j9>~C^^{Z#+in7VaetqMkw#Jk!{JvX#Wtv&27O@UzEuPgsmc1B%(?}zfUdgIi= zu$*im$1c>LgB~1pi2XtCK4}R?gd@zj1ivxy8Gz@a6;!&Z5qRmET+o}4uCfQZqa9>bJ!clMpUVWv(#US=*V3aex@w25H_v09Gv1mz_ z+qH)Q>o0GC*p4tedEoua6IBJJE8>kTnbAGX>&BjGC!mecspJ1m!)oVtsG; zEnue+-ex9ov;A72BNp=l;qXiC8MepO8i4a<@)mAwEdxE65(vP}HpAa8jYkMu`sAXfP2@rUei~|AO;vzUne~SZYsrhei?37W3B!@`APnc;y zUqXfLpojxZiFD(&`m`Np2 z_xQ+*4+Yu#D&apo3K{P(upISQ~5t#fv;Lv+oM@9dZtU?(FV;oUCIgy} z@E=0p#3aq99hc{=ECa$=EA^9fxh~B4a6OiTX3{a3^F_|biiGh&&}OYeVy?ar@~l&p_bp+pe+KppBMa3dZ($Ds29WzBD+S>7 z+#<+}2*HH7voEK#tx@|Rl@&(7#!0H}bH@A9$n-@Y$c5>Cp${NFB6nxA zN1B)BCYK1w6HeBG{9(Fw{n~5tJ9)GFm-BsM>8lF$2|QlHH^cgPUa3{uFGaC_!f?N0 z-l>i6d+-lkF{iRIQesABydC}2H&1p?Hd)fcvaR?~;@RAe+(C5;&Hbg714jI718sk3 zz|*-s>kjy*=<#qYNMr9(LoZz}$z5qYPt&l7$-QvQj^hi_O;r67IdwHzGO&3MSpA0n zc|z{%kw;Z0FpM9FM|LjJ7vq)+%&yAb^-b6~9*<;x=r4Ua7rrTZ%JJuPjODen6DOx@ z4Q|gRn{@CL6#y<^CcnGqndc zB0~|L?5bMGJk^v>7eqoA#hlv1KQ%iUB&PbzJf7N&-pJH3QI^2*?UkcP9K}(O6>ss~ z(j(b?cy;W3b9o`ycO0yGz0bWg{OtTpY9FKgL4{Lha$JWG%#Ho5Mx+(T266WMbtkc` zL4ze@x<*qu<59yVmQ^{8cun2-d|!G$b^Sw0dY>On)NR$CFy(pP)1CHhPeeKyN^wXP zf*zkIFFWW_eS?1Uw)dxZUuRzvmM-Lv?;H4Fh_K{8BoBf_ZNLta*=&drn*%!UG_@I$oMOtb zA6e9T+w1|pIfo`Nm;fY}!i!@ER8U=bHN&;l!68UjC7UiPK|onQI0ZNu)R;yygx3Li&3 zb3Jm|$C#TG{vk^XQg22@0Nf?McEdN>O1#X#in_q*kQ`Qk0a&>)VNG<|n-)|u?t6S+ zNWh2)Gi6sAa@^eH0g7*;R=ud`ap_{tZ(#2s<0FlMj-L*9Sbs)$diTmk0*a8XUYsAL zf8hH-g(eB}bJS?}jCnqY+z(c|l5C+>j!Bn0M0Ef=wyHdv%Koak5R1x@0lGtpHb*+@o}q5#UbJRt8Tdpoyo5`8&4;Un;+*?zgF8tzd@$3GM(6_NE+z z#kPHe#iVt^A4@;C`Ho<*7#;qPuVHlMe+C~v4E0#$1c1JH0#3Tpg2A69%|a18{_5`> zTH@|)fXec8NtU0p*X!_yM8=9|88$IBpQ9MINtOmTH3RyQQ2?*BfnWUNE*^lfOpn|} zKH;qqA#wouA7WpU3e{86*~sxX4m8sYHi&DulP2`Z=ewElaXIkAq;lz534!+OZzTag zij-<_hfu5~lUQt?e2V#5%4WvkvqHK=_Rmu^na3dc z%#D6y`2JDEo1`@oPrZ>!gOCZq;tC;al2s9YAauqh_(pCzn=h>Vhw9WVZOXDK`^toPd;QqEZh>OX z36VbHWrI8TKT%4A6z2CD+C6STq;G068HxXJPyx{7eCZ}4$&IjmPdgc1hm-$mAxe?w zjaU^6ko#n{*jivJ8m`2@UIr_zeE}m1Y^p_7#=Gsg(sWNp zDtHv1KDBv=IUZgF9Kc$UbQ>^Vg&|Z_e<1`z25{WjK~`6Xe3tEefIzrpJAH;SU_tSJ z0o9nXL^~P$;R+Prh?iXC9bfU1JL z(i-nJiY;IVQ4;%#k%HI(Z*D>y^_1@lZ@MzBNw*6fXjFLN45hHn!D7vN;aF+S*Yi6ujSUEDrMYGRu8J5X($lHfd_=}BP3b)f(BVF@0?yy+(S1}Z8Xnsu1 z0A{4tS0YH0-~&&bV6~_tU0m#`W>GSblb;T8h}e;*P%_tE%X~Q)^b2hKs0o9+sO(L4 zgE5z%C93F4f48f5h)^^FBmN@k%9&emtY4UDPB1Gst0D*lG!w_y4V(7NHW z-^>%!22Eoz+fek?-3Y6+^QhjHk1RNi6|fZgDxg>de;_y;`v=($cZsDlRMDNV$I|>o z#;Dkbjc6uBY|id?Ut%Rx*%8Lc3oh}c^VKE|=m!~~i7 zzL@zWWq((5#QyV2)FS4doA!0-1C-3k>z&Wvi6>-;{ujf9#9PH092Qhbxz{Gh&lI4o zb34_w3>wit zso~dboX>sUnRLsaHfeUT{ZWgq)>wl3zSbHRJMBAqjs5yV6l?_vNpYvdn0qSn0S1DqRY$z-q{VwkmOcsA~|ZOAv%Zj3B=UdLQ;NBRxh5fBI1@%7D9gwRp}p}{SI zl_@f)iB>%m@`m2W0U#xTL}L!nX&FJ>%w1XE4+7!GRb&fT$Ee@G$rUdP%Pow*RK23W z1%2WK5JBw2R>b)Y zOc5*XCXS+RNY2R*D0h98Cl9QNsPWpKi{3QZtsW ztXr9BDzs8Qbylpo(SLdHy>I5>$@y|@AVL;wIq-P*%@9p@w(oLU3_uM7MWM4mH_SQl zP`>UoXH&5j;nYs%9}27T+k<;WyFxb~_xJ|!!QWK@+}Kb9Q#Y?y%Wd;DW3?7EDX1~% zl}iD}_qgJj(IzEf8X%iRHTAgexzZBmE>Y>E8-sWUdy^Lcp*?Gec^&H8M`KGkVph$e zd1c$EIv;E;IB;+0V`Jf-6$6mfGO8Z1#kt~Y2(r7C{T27s#tTzQUuXR_ct!UU^IbMR zf|oXI**K~sV_cEOAj0f`M))+`09-~f6HP~A9+__A{2FsT#6Kww$*?In4ZG9O9hDRo zbv&nXR<<1hBO*$ve@8iniQ|t&2qKDWGC_x330vsuwswYvP)Q|t@1%Qr{>Z~Ylnsv{ zWW&f{%nIN2>|i;|RXO-QH3%}!p#2~nUv9O^#K6zQQv^ME@jBP4ABD`5MQtJtdGLVmtMevIR(HzlW%)e|@w;6KKf`?5 zBplwhB^xR~+yOcPleC~ao%ejcm9`uEs;|(3MG6nA_jB7cufCwy&wK(|$S*mv{3Yag za#5kuRH1cxf6|BfT30Rrn2T`Gln;A~k7QsFKSc(ZiG#s)@AInNf+WKtKU;GJ4TuVeLti?$T?Z|&?aRL z8%Mt5&mKBdD*9d@uOv-~gxBPchV+ZON7AtX;_BDuaxJ)6ml(KTKCW-XA-nm|tt_Ke zqpamSYbH*HQ3@6)KcmU?AHx}_^^wYrvJ9NiSH}am=&^RM73nL{)G_o3{+wfA)>D0g z@cBG^R5{0WKPXE_ zT^=Y}_>MEwyUPjhD&%z_Fh3N+2TTxukCz5%zKGtcX$&nvDNmA$$&R0l*2d6~?vB$k zw9IiID!gO3BJJHDV9la<2QWC_Mm5`_le=}>DD_|?l^##oP$6D2GD}Qp_g*NLKNFu} zjYWmb_l_nYC|=8ISqAN?TyIp?I=3PWSlk`pqKYqG7=`zPCablSng=!9=`iGj-9!ni~t;7+MO%KEB;#fMh15*$)y@Ss%G+FJAyN()i z8)K?O>>j&&$Yu`iJA>nhNCE$Z$FC7rix#({k^2=t;eE_J!FP5Ad;9SDNlMs4&{p z_A$tgmcM`eyHj7sU&V9GVCb|2bH0-X?Q|yj8%Uwo~%W0Af zN+MqnHuv%0%OIO)GH=-?r|B|jHGc)1YOxtQc&D#g8c(b%W=G0&3KCUPgETwYM5}`P8@c8v;{gu`Yf7Sgo*l#X5(K1qZds;ic%CToULAz2-7t(@Bn2I z(@H=rEjt-ov&(bjs=0Ad+NbP9)O3^ZPK;^jireu!8WP3Ls21;|oy<_YY(2mQl9UdbdaDq%ekAc#+U*-+}pZ29(Asgny=+T7uE@ zrNTlU$-!N)Zus#MgCL)K;zP(<;|l#$E6weAh9r~J<|q2<{nA*FL2wp=&oZgFJ;B*& zcr2aBeYf*r+{B^Fh_If67goDwr?@qzE+tQ4I;Wf#<*yW@>1VN317E$^(pvE z#@=9+*Z`CXqkiDI3zcsD!f)*j3;C~G8}Qy9)w%6?#At|sp04n(z9x{p1FN&ywRZf#S(|Se;D5; zI??O$hMYY+=jTdcO{asQYnOiku_jj~D#@K@*dr_;|I%F^CsCwxK#;V*s?XV>zySD@ zKmQ{<$TUn2TjQfW<%n%fn3V_qR@t}vP{+%gdt$Yd=@k?!VInx4e967+-n$yh9`O|A zWJh({tj$ODtTtpLOTLaCw=wd~Qor~|5v$91_xP=PHDS^X{txecaYSah9Xpk9@pXt-Om;Uo|L* zWD63@jH_7Puo#Q#zqm6TJ{r!8+v4fJYHTB|cp>qqz4I{nhtOW9cMAtUl4dh==jcjIVb(Sv^5VT@kZ~%WRFTzh#97mf5!l}% zdEW!iwsA22S?;CNOtME zBNq4p5TuNlDc|Guuphw%N+Hf*<8`CY?QW!bzmHW4JJQ+DSL6??vym0i{Jy0-X;=`a z>LQUJXhOFXPx4dHjJkgW@l5@B(r6b_4f@eY)zKf8aQX zi7|moo=w5A*5C#ANaRVSL{2)+bRe@qP6D}$es9mV58wK?1kn{7%FqSXP*z!rkmDu& zJR}Tn8GoGf0TsxO6{e)uGkNaA$8SHKsfDzQZ>_H&etL7EQZq9882K~Wky6dD$}?tY-}M6 zz09fk-bJ>`hHKl#admX5YEqn0O~Py0{p&vI5ol>UYUpWG(ISs}qU`0|yyCblEuUF|B#w5Okme)cjyvOs;}5{Ui;U>`2oZ*ChZ0gf@R9k0>0xO>NU@`4ZS^!wV!?c zVo3P>w_G&fO8QE-zK`7enJXb}l;9woo3BowoHuhJ3t@mtlekGv(JB5mU1nr4E+{$q z(^Uftwo%BqABsikb!K4aVwm{cujlCgMUa7vykUlSJYI3E$;Jf}BN?Rs?M3C6MosgN zrqs&#ZPd3t4|%~Pi}n)P}&!T6Po>MS95oSR+PiMX}(pvFq=YVKLrp^y|mricd58%o)9 z_8lt56>oieC@0c;VyEPSq@${9?O7LcyZkzeJWte&Q7A4tKV5cIg_s{T<<}#U`|IerD>ic9x{Fu9+EzrY^5wX z`SpEP#3_t4=#S`Rg`wGd?M-bbtbgu}xIlZX8h7J0R5KIDzrU6>z%|+Q=cel+B=|KF z9+_@UjfxyYzWH@j1znWsg-lnh%}CwX>Tw@Xg1-~ruRpUJO=*RK8b8w0K4Z$bbyvD+ zk>_`*joOk?b@tX1693at&_yh`q*w)#MxXxhGnXH&NRpO-P>#i$Rl1zr)EA6;0s!Rs z|LFoq|I)0tOwqf)i|Ozt7?7t6D<8j?t`okI0(*FD9GO56O-*|AIk1f7dgC&W)$gsC zu3YlpXJ*}YDNxXM%u?38o2yf^1rYY_qli>((^6&A;QFm*ZuKntE@sjbj~s* zVM`nDBZg#Sdr~&Smffy55ar{G!T#b_RVfN{b)jBGk?pu?!z9n-LIZ}de#4h2PLl$6 zNX5Zv2!xENy|F3vg0kAHy*&xbdw9dMOi><5$iw09yUg9LmVZfJY^@;EsX^%MfAvuQ zIh!@$(q(b&oul+3dF*K5(rE#lE7beVJ_GgOh>q@&A?s}pq|9bDXr>dk{#S9 zBGD?Z+=}$Ah=#AaKalisWLfO4f6?~yx^0sJ$8K$*i0kYjH#uv4wWa)>@{<7Iz=*@d zvzHZ3XCKYKoGGHi`W-wU8ob~aH<(&Fr&-c}YbXk(*}QcEKga@`$n*zylArzx`?zGW z+8}8=dYuv8aqD*|IsXqw_&=`f_TX4?Fw$V!uis(g)S?Xwba;OXz0sxvsiFzJoF9-9 zq^wN4yZ%!I?@#;Ai64Pfpb-Cr(%NLZ5Vx>pGh;ThnBb5zylzq+?CIGdf0w883fUIU zsykR-dAw`iJJZ2Cf+#X?{9u0!A|LSz5FVyLvV?fhrUCd!-A4ZLBqbf<8w}<>!A~}i ztbHIpIfMb4A^Nuim(M&F#Dk6^8kd)wVMl)WidqA{c6~(tebri@2E%>&yao~dD&<^w z-5P81C7;m4Ay{5!j3ySlqj`Xd=QcANYczap_uxPh^m?St+x1q>dK)&(^PbO0O(3ZM zIbq9>4IcFuFKbTF>{%Cgj;AWjuW^BE*u#7^aLM+Owz7tKyi}FtsuOpihKa8DX%h@_ zS~pn@Z3j)uw0|U>z8THV#$CNeXmCGnGBQ>jO~z6tq)83JuNL^KO@!^08^x`x%bMm&p(bykr*JYk}~-gXA!IvMk}eUxz-SH%R}h;ex+_{HTro z^|30hzg()JZ?745@f1Bb3_o_7)i%Z*^+(1O_&P%oFFzkQfm_Ar#_FzWKdeiI>Hmw_ z(;Wa2U8%WN-0x8MBskEt2uPsxtI`Tq2=e^i0nejKak+Rz~~9n2lNkAxT`@qaMzkXM+) zrcte0+|d$m^il<*=sDc}#(O&ILu*su=xoC+ghzLyPw#44ZH@{%7d z%4{A`84IlTyiZ;_*!AZCbO4{czGUNCu{J3*hxuUcG($h}o5}a)aui z(=HJB^3P%Qd_$(|BEixj(j zAbTer3K+1(?M<+;I(&*RmF-gavO^2Y&F}h;N@>&P@g9asln(QcvQiL8BBxF!_#X#^ z9%LA0@H9-a_G)4w3F}I~nK>f}3cF*TB@ljNyGrTG7wF-j(QHz{uU^s|2J{BiS+D(ZW!fY9oPJ0Bu8azvK@QPO=DOmb1%$};XP zYQ2duB-2P}YtgX;(a+wx`y}6@oz4537%Nr_60i`++3K+oNhHdY67I7`+Jtg}UZ6nc z!DwfsSrXJ;q>6zr)#g78@6MdKGU9jK^&cF)m-#P`FiRna%Y2;eev09qbQO6)Oh9tU zDSq0-SF)I;$zC?ITY0KG3s!8FeYetMZ7cC!zSO?x6^nKnPHD%ej>JXf>v=?O92aE*9{5Gt?rF)OgT}d$r z?Ugq2xwo?Ee=V%wyN`R8V_|<1{5EH=$t9}|?Nc!vI)6IE_T*%;1RszLg4<^#O>#** z-#PtWY1#Hk%x+H4f?1eyR@IyD?Ir8h1=uPE78VLc%=;UON)|jrc=X3XwzxUg<|#KK z`Xp`lJ=d!-@=}-kih;h)tj>$Cyzdzp(Z5Q69i1_NOn&MYY^8D0Naw+te_kBqaE!@A z?%yki>dCu;y5paKyEebs4+;)>kj;j>3fJ z2>^fIqUN_y$f3EVO2u!B-v^0fu1E3a5e5V+s@eS+KRS6275%2~ zAm8atHK-r^p(k}!y4mqk)}_`B8orD%y>-=Hua(sEe;M)kU~5>2OX!v>TIOF(JFzJk zDGKGgv_AJ#`B7P;__U8%+2nV5VK%K1%Jg-hT>Lj5tPM5ORJB7D=}$2RHU6O)Dq5-Q z=^RPgP`bLw@nf!6Y46t;y&@8LYCC~jt1dEMn1sfz3{04!ypJ4qcyil%HwJTHM7*lX zC9(Zp$+Ly7c#aTIKOvUFR+U@gFPf+A@Fw5Tp1BWt!#O6>aQoOkJLQdbG8>0_GmnC` zcy0d=XC0^rHna;#Q`9~X680vyQ_2o)P_I6Aq&ky)svOVze2l;B0pKIb?9}y>(4%sn zh66k+yp|JT%HP$)%shShA0-k`)iW9iazF7^Tym*5%$4H_ z}07TcG*D;+<(7>o@7Kg}pp(dUaw2BuQOSQL*>6;*GG`Zs-se&n@%IyNA}PZAw^rAoo^1uGQ~uzPZeg9!Lf z_i7;=a8-&GCSFxW_fcP<9(g+rnwxXeeopMbsBiJ@v2h$JI70ifIkM}5v`pF3zkrl` z!1jUUN71jS%LHdv^}b#B-FZscXTQQ>+neX;y% zRn@r=aoD~xV(7?kaVw1O^4IoL%8oWa?;ZCh(^3cZ&@o;f{qEGyFz)bt07Vg&@Eq40^*AzV-8d zG;t}G{43b)kE+FL-`bDi35!kPWhy!*sdXa%=-Nj%cdfJ>&L&^jJOY`=C|a>b#n`k` z9G-qVj@N!J`*f!5TWis=_V(I?b`ZkAv2D;y&o{X5Rnt>S+6ma=9C_%!rN{9~f1vLW z>TPcX3qxlEA_1Rn_kVfL=r!OJJllB@WLL3wp2kz3^?`c0;?1~Z&BF|bUXFwTm!q!Z z>!g@4lGm+c0ur#V88g~)h`%26{G4?;zPwOU0jhYIBXuN{<3T7VI(~84NXWQqY2t)T zpko^D=bzF8kVo{J)3^16t4#52SsH73;N4#cF3fq zVVT`*0?S5g_=;maBZC{ta+6!<56sk75}-vLt=6G3WNE~^>S!YH%h=$ybh1aePYAuk zYT=VDE)UTM;|L+Yzl|;)-(j5l2D1b(Z;zsWEk=xn#c78a(tHB!iWT82fsAf_Srrjl z3am&*J>CrLr>m!~m+qwF4RF*}c(09qp`$D@Ed$_mvvNdY3J*{gCKmRXlAxycD6TsA z%Hy~`LZBxG)=JK^7e=8+3t3N9ym#~)yWM?Q#t1-a0W0j@G;aN;LfPbERL6b0#Q0Za z^K0jx!Asb3D6MOUXwo%4AX^JS{^9i5ukGbfjK<3XxNnQV*FUzF<@-xbu@pBr97F<| zz5YRdG#>u0TUu_- z?`Ga7@|M&dQe{ZtIef^8!5Wh3Sf4J{JlW+_qW1>1ti98Ir^HCgP4yqE)e{2krML;4 zjCLoI>Ka<&4YGZbIMEakcON0(!@#UBRF6y~)N{VAu8kHMsjdD*T^eS4oSYTSpX9RY zdT!R```t36Ub3yURMu)?_ub;|H*H1obcSk9oWAN}G`9=1yQcDzZ{-={JRwPduMYgz zbiwHdWzbdHqrF1`AA%$^n#EAypX*i+ultYPKV^WLMCwn#znd-JqVF#kuju8GXX{aG z_TU{4*LJ3g{T<@LTPzW_M}O84x)c%MrE~X77O(eH@8_^ek5`GYf}TeS$dnHG%^ajO zD|F5ugxH5F;To;nL)cyoQx75;Eu>Wd(Ig(n0S2$pl^C0@W!lQ$3p>rxY?)6V#{E$@4>!shD#OZ(p7i75=PMLcjD-0197ox^U)+P&QtTnBpQ3|diG}M zN;CZ>N8S|Vm~EkJot!2IWxcUaHb0qtQ|O}2e;7k6R`=U2 zlP8&1y;eWW>r@i;BSfnF5~QNH=RH4$G~z)o|2s`5kb%yB@gYF9v@ETvx2zpPzUF8A* z)&zr~inPV5h9#Ok66StS{&=Se{C2YV)9}-~LTBR56Tb@fjOV<#=GEk;ncP@lMF0rT z7GJP#9)VpamYu)Sk$>xZNRJBHUOD?aYP*p)c3+rtIJbV;xgET{bheFYPXGEvsmK7Y zOt~2i6Ib55b{0W-&6q8SSr+ilsWe%in~oCBSQu6ipsg1ws-dvqQHZAD{ne=8I>(y&GOA zV;(NAPcTX@og$Enc)J@_luD$6Nfi3i9C|RvpKoX(3xNdIGjb2kNgjPHZwj`XRcEQ)SruIo}A+k{f9Zj(1}7~BOGcLoNaap!$csy{ouOfKyhO?#uhl$^3JxqRUFS{< z^R&xT(@XXAIA*+ly2(i&SP!!wI1N{!M=5+%_6`{Opf=j#0Nwl$h#TIK8xE-RtcKb2 zt0QL7Pi-A31MezE7kYY*g>Ee`ICRxgf74nqsbG>RZ8Q24UHWLNr1RHeCGQ|9Xn3}H zhFD#S2y5Ax9R6*G(Hd`kE@0^WgEzl21BF&n>dJPVEhnNKXL`t%=JWaSc+G`z*EKmu zZod&|C&t=wcaQDfWHuXpeL08!K?qa+c0UB^FK{ukN%xq9xJNsn_%q_@0iDU&=ti6{ zkeFD1uX0$$7l%{yWD0+yu)E^#$rZEdzaCVfbxnmp`O#{}KNUvm@+o@a@`D~o%q*L2 z9EC5;i>G7mqYh@(r@>+(69;ed^uFU}Z@%)03}(l}1BEMUlS$1Nl2|VV zOE%pV)br(n|%Gq zg~*WQ%MZxhaZ5f)8?_ZiD&PcwflM0m_Rd%H_Mf+F!*qEo95YjSwpAjAnJ&4|95wdI zgQD3{0~UDr%#lp_-c4kS18o`KwPlOknCD3Bt!D{GYRG+umV`C-3s5=`$ip|2#OAf9 zfCB>@d^HJs@_saWt?$ElWfglh?yE(7nwP^QT8WC%*S2N$70~mUe_eZA``!0Hp1$1m z3~`tWBo)V6P~9mj9C;Z`=}qw!)NCDBmgPqZe)U=AO6plx5(IiOSe2@Mx4ysVcjF(I z==FE}%eB`$p%KluPX9hjSgR$DETNW7_=&dmb$wQ7QPHwXeAZr1kyzb|b;m4#X5}$FPQ3gE1!9Am+J5jBwZe`@H7;S2~QI4n#Lxp={r< ze)`L4bb0jjQO`d89K9_-dHW#a7Tj@upfzfwP!ha2RK8dng!}aFH;jdWgALrKJm$@)VJ+i3c!@ig^y9&>EXH}f0 zS#_LMFjQIp^^~yH>xw-XyPLAVEn3#ih2=6y9qQWj(r z^tde1KJr9jOg9=b9g$Mj<|y7al!7bxV2Vj|{5e*U|ARb9@=oGrsOUO??X{ zlL}8OaVgqo6j?Y|c_o!;zJ>UgZI!Kc9GR?->YE}@;y7j`H0%a$@*sM&3sCK zM?PZ&rA{~`vr|cvf`T|!H^No%;+=~(-pGCb>g)Bi56ln@6?$-&;=_U-5(4}1vLlFl zSoOPcULrI;^5PyTfho%?I*5(KOl76l3m%OxW+ZyoW7<4n4=(5A|CsUu1ZqAklN1L{{2-IiWL8qOP+}{pxd+~3SLfu* z$B)y~mll~^nsgbQ(1;~%9|r99G8Yn7A&;fVDb#jN+-&iPU=xu{SF=1gxxj9d)N6R% zv#T->zU%&1YKiE)#?qT*t?bU0sepWPjN3#r*=*V6`kKG(Z?4}Eir_B{U7bJb#;^X@ z5(qdq31LTYz7jv01$Xz=bO<23BWP*=bISn2pSI+?fM(RWB`3ADrY1Z`|N69ktEqMH zDwDz{d!&v2dY3*xv6_BF!hlGT|HMUP=5it9{=9U?ZOn(_%wSi)mbzmz$^zhve6(5- zSut8%7$%7{jy%KnITX86pnq@1zI@*}iNFSgoE>47k;yYQ&;W$3HMAcRl@J+a#*_ z2&g+Od>r<|7La0Nb1!FdLowXGatHY)iOM)D^;g;$|6qNV^y#0qci?#A-tj*^Q-LhP zxC(*R9TIAbgz5DtDahInDE5CFX2%HpYMT#|L-;HQFf(KHF-!GPZw?ukqLkhJ#JhfT z6G8rv^ON(^lj_F1|A(flaA^Ab+S?f2CEY1VcaD28F^*;GAbDN%i zPXj!^*1t>m#}0j1Fx0P#OjGe9fBDJHGxhu7k)zOv=OhfGl4+l@yAnN<9RK-gD}Jc? zm7~`EPc>)ooK4@;y$js~BVD~|qfyoQ{L|n-ry{ajdpGP#!_*VOcvuUMau+Ct%f(>4f4(N7{8} z+0o4RUUcuavFjG$e;)^j9xALF#{&Y(AhBYnsiXmqQ!Qj<53dy;S0Os=W2)>Q8{O~3 zEM*tHY~xRE)aFPT6%Dx*;Rlo)Qd^z{Or}%A=4SF26@DxmnDA^{6h!KqBf72FOy|nW zu~S#*!r~z&pSat=M|$P=9;)|V1sz29TRegifAc>U=s;<8=3$W^j7c4;+hR!YXSy3) z-yTzKCw_QmoYi4tG{#%buctY6@9i)^g&|`*d#6u2o{k4#k8MO)hs!$FTk-I@r**F# zSyTu6byCOO`^i|yHFWe|c6dzICbIcc;zc_f<~)Be>rCSK-+%3pgW-jSC_Msxiy8iw zE{2wC>shUv|AXz*@zNXdD8ruk^hfPiTPZU$8nFpqCuT0Xwf9^AACH8A!QTP8r^u7m zAC|xLSqdjjpG@~)ZysC2ICl7PE;O0V4GB&P)VB6iy66w)w&8s`6CUDy(fB*DB79+} z%>38A#KU3p+xQGNf=zFYcTWEtV{5=U80R=8=zBW(jsi5yYup@#KAgl#NyRWhSu-*| z@6hP(VXnYBKKgPWpVqp4fV5lTJnDqXT=S%El&^UKOe>}SBFB@r*l)~RmSltp5D35r&vt?y`GUw4L-$c8qDgkL=MrDFTT|05*FS!XC+iV)()m+R8u@n^nIffD6je&SswCb&C0ne8Rk~tW!r&8u~f5tVObbGHubBE1MxFxP=aMRE; z>zmAUUII98tfP!eBjZAb$`8S6P;A=yO?MI6h~CFj*ZMyZ%N`Yq!MiI~KE;CrsnIW;S|4AWv!|PYUlDlr?OVu$I$t0(87)8`gYL z$!9%(k>24oc;}Hc;d^WDSXIQiWS{QLcptu?NoK9_4{rU%4_R?A0c@vE!5pdGIj$7l zE?kY6UqK6I$SM2z&a+KTyR(zWCHe`9ui;n6I}3YnEvtbAo6z0&>Xy}q+hZRri_eWT zq+UQuRSGS;%)_YC<$wQir5RPr~o8L zg;&Uu3x&_;7iZHe%T?$?wU(9f%-?ht@93V$R$pSa2GA{k#R_!yQH%O7*8xD7=G$Gd zG`ZuO`$UCeO1cbQ*&8=42z5oA~3`-Ve{-y_P~wO4d{ptU)xX(Y|0zZB)j zf;01mE9VPLd#Y_N^qErZKI!sEV`*?&|dqWd48ay-ZU$>HVmNn-8WO426 zxLqQl)?;y$6diiTo>g3Vnby0_>^IWDSp@GSPZo zy;}P%W08K$)Fm;I4RL8`Sno6JWhcIW{NTnqWmo9@d)dlulaJ#5 zvETJr8jbVYlLuCW12ATF1l zp9NNa%@v==?^zl?vedRp- z`%p*07rB?L(yB;0{>)GQp0E2EiHm?x_0-vicV^<9mJe?1S2ruxJXH-Jk1Q5X`l#G( ze~4aozumb+=YBvPwNQkd9I2OIW-pzyk%dY{@+wx-btY_=$;70G#WorXBJ+z!M8c(bFWjP^mXbFf`?t?_)*$Ep$t~vH@jP%P%&X&kBeMoiZ(FBJK!w!uQ=Ba?x z7Qdt1@lm^2lT2ovF+;8@;$ZMout@gji#2^l?sqdAtReNx6L|iEd1s>G@h=k8-=kN76HyA`X|c43ouWzWbvqU*>45UI zmBTr+-$hRlEwjABr{7Cf8k?2o#l?Vyhj4kgbbqfqHhiXwmFI#J2c(LYocQ#6XRei1AE(X9AFMnf?pd>`P#P!u?%S%msjR71;Ns32cIKh zM^NV_@eZ2oLOn9mXHgDqO7XbDKsKl#mYYZxZd$88A%OHr@NFXCl8~*x&E=0WBFCBn`ClsA%~XwxPOd?*p;kD8A=0KOa6S z!ql#^PEoDnE4aJmv)Xe=NL+D#nP1DIP#(Jr!^R@N^f$sd>8zjC{h(ZKe5I?4Ioze* zH9PuiF*?KXD_ymE|Dek%zh8UU$=TZ|-kECeuJd$H$(>Dc%BnAM7|5@iAu7A|M>@KN^|?fVraSBi8GD?iRz;>9FoMCkINOV%+^WasTG zk}kgq-+cQobJkMG)gXru5{5Fn0MlEHE5M<8>MkF89^o#l`R;|LR*d&W$b0ECk4_St^{DY(9@pEs z&i1_uOT&5p{Q%2@FskNn_<}UtKOq)spIyAUY-Pa%Jjz91&+pLHZ_#K&4FCRR z6X3SuJAkcRnLn`DnJYKY@Xs%IM8T@{Hw9DL-T4|l%7lYn%!(gmSp!wCId!TYMbe3+ zzIBEUgi6R&&}M{Y^sNXMXRP)^-EY3W@Q}a|d z6Rp>O>L`^dMGHQ>T>P^n*Qu3c3%k77=W5TKgC0q7FHdv^EF!b-E3)pp_@ix<5O$787dEHE-cFTBc zm`_s%p{rdu57*r~Tp>x(T303nXwOOUl^d|p^`qiD^g$EU%8YIQ`?yF-y1(KhixGgri9PBxo zivTET*^t8@oCP|+I`Y({|0=Po7BH`=!Y1sad!?H5**&}djaH;W*V!^u07l%47roAh~{OEOGit}52FcYa_u64#jW0>~06xzB(!Ox?09<9ZC zQ!jC0Vm+&$QpScB{+_D}zde(YBbQ#VA$5c%h;+{Mh71cjq$<5yi-u6sib6uZwQ!ZntBB5u0 z<);`ZFjU1{a&n>Y$NWEB*~|iBRlW^nDPM<3MC6<>p6B}uzQ5Mfuo6OJVf0SD&K%%a zroWJAi;er`mBEAT9>-y4W_GLXmWHdoHQJ1KoPzuEiLI(qmV4w?tp$^rX@6Ygp?2sQ z*!>ijaGGza>CUJ&xsVS{yz^a=akHl3#c#jdDXOle8rR2%rQO?hRHRLf_qqEJUnbbM ziF`**if8bbC8&jsuzbC13K|?h|1UbAWSnEQdi}X0&JhQ>Uzz2O^d$RAqk8?yda{q+ zBk@Sii&wuV=E$^CDa>YC`67)fBpmFC=>{9jrX-365JAgNtu55ycZtT>CZb1=dW#K6I@h@(ph6KMhzMPsKFMi$Z0l9$< zQ<|>(OGM4ox1#f<^_cyztYZs>o6c*^H{@}vw~l$9$mI>v(S{$|x6}6hPnyLWOBus$Ivc_vpY<;|J%q!Srvw-S&R+}BVkFN# z_FHR*;6H{ElR$cIIZq}F`LMTO{og@u5c!`oUv%5LF<-ML)jtpAKEoLogR!T#FzL9M zI@{pw#2@wNq-EB=5k$-JNSRL>jaT)xp-5tYE1SZtMl3B>2z$K0iqlR`rai}T#YTg9 z{XV|deC+h3!-wZu%kU!my2zkGja7bpFhpD)Y~cjaeb0^}*1=(bD`7=V)q9Q%H2TVi z&SP(7E%{TZEmL979J}6&CBveRA~4J2>rRsU z1wW1Xx6uA~@out;?=|M#ip#1pz_hi;%F~rrhw-hiLD9@)!YsV5GjFy3HH$smH15 z{0u=*Aa$njFnS6lyWHgb>0_{)sBuayh1 z3*MGb4Qqz-*aAii(`QPYPk*>4-OiR(Wh$@@{P}>UvG^dM`|SF_!t50fD&{z`ftH$2 zti{HuM8cJ1@&kO$s%|0YPN^+Nlv2ybg&T$$DNb0s|0w6h z=o3J(GRZS7c92p=(}VunOg)UdhF?eUs4Yk@sF}~AzlqOKgjftRNwSK3FzIY~b}70d zlrs84=u$8m$$(a^Uq|G^g(heIohzd{)?}J!3emIw!N#eLQk?V9252Ay_xmMQg?vT- zFEB17z^lQL1R<%yDmJr@%=ze>JNfhqv=CNJhngWKC^%vgzs8PIOPum#`Fsgi(#IXI zpE1N(#jN6zT2F(_my0~=@ajUwE~>uv3+Wj$l8)@?707snChT^)sr2^@1HpC`zxaW8 z2Z4`TZg+nnGdU)mX+@Ew8+y`6N`-soZia_}`%<)a`W=nscT%xz^27iGEs~g>RPE+^ z!hSeJDh=iVt3_n|1P$;v$L@u*4)Ep*o2#|0i+ooD9fhi*Pl-F3UYcmno_aoVD|VA= z61Q`lQ1g7R<*H>1u;crF|L%R%$N#?`cE0*_K>69okzqADo(%|_QhD{4Q%dYte>U&- zigpiXqE}r1%y<|9V`5$EudmJz2a_OZT_4U5%Qkh6LLx8pe&@ixu?H@<>$)MYa!6&J z(h7}X5|k64TP97y2*M}*b;c~oYi|1Z;Nv^Sf}pJ>y)?y=H$RH=JKDZ5D5R4S=xjGe z85A(8tqgfShW7 z`Qfr6Ae$lvQX;PK>?8glkQMq8K<|r3BQ3kNvjDP|ww#7S{n#$?VLBmFJCvF40m0G@dtZq3FXx;N zNRP4SuK$p>&^Zn~mAAa$*tu0yK^Kky7WmrztW!RrRPiarPIaNJ^0NiCBo_cVI&nJ+}4`CoG$U+q=B8wi$yq7$FyhWu1mBmU)xlNQ9s#@hRZ62pjX*t=@;s|x%GLte0&bqLpHM;A$OWD;3)`(M1Wryeb_ zPt=)#G<%h5Y#<+;FH1F6UeG+AN1f*#VsHtRps7q!vFgiED4_1u->Q8@YdZM2uu# zXDUN+W0c+8PZ7>R^bUsv-)CjdfXIwr=uAm{sn!7~^%h+nJn8_`6$`?Quty#whU6+B-9j znb?JeuvvgSANHxfA(^C#~`Jhe9?Z{$`y^fRTE ztbdpNNBd}jb-SkuOLIa=$16>#Q()xe(GRDnFOFLlx#RuC$G_S8+qKO+SZspO#E?qKTu=Ct33hG9X1!~|NuRZa`~ zMb1}M^?)jN08fEP-4My$o3mPLk9!R9kAns-2+%q^X_||aS_=&z@vjiDLk^BBo`ySU z@3Iq4^9kJs-z%v{T?Jn&=|^4CF{n9rA9c59#=WgaD8YxTnf4`=f}a-#Am{A$FuEj^ zLR?cp7r%w{QsL$%&hLI7q>MlEdJwKkKCa`F=3CtT5J|26Y|y0a4~OIF`+{J1)D1546Ye1!V{xsy=MnQpJuRyx{|ObX)Ij&I zL34A>JHN-0I`sH~XGzyPzaiL*M?|8wGZ|(5%}hj=GMu{>lSGVR1ARG!1drgtALS^C z1!M8v5_|+-x0L!@sEF5Oo*%7#6Bn2y>!E-vSHoy=)TVKaJSvm)F9NbKVlh2X1{)=> zPPN9dw&1DQsI@$E6pIac^cZ>|sZRa%ltgNHs`EdIVaEX+x2cop(Lo>OoW2_bxqFVY z7ormUN6D-TszS^#dh~b=>*Q#Q%FTVnt~F625sUgIO$w%rNVbxX{3nX%(51KRFzvAY zyN-YZeY%!=#cH`wv zKmr}K@DHZ$nZ%!N>TPm_#z6^$DD*77_?>J434#o#G=Gyn3utK;MWV;}JHNP+Z9v2} zE2;R=?8m{M-{-_?<@d@(Luok5H2A*z6u3a-wj5FcFX@BPIKvcWYN?*`S#dhFOFv=p zJPx$LEl$(JD)%5Oep6*jPlXrtc0oJD-@io=0%c*8$lDDfPd~O|%t41vSCrdu4~teuLI% z!j!w62RzJJ&B^$>xn0nXH+k6r#qdHJ z-qm5Bpd{bzY+{>g%o^euXaRCS`c!dTQ}})8Al41&M?-n#Dt_PE)(T`tO3_+oZmuFw z&QOm1Wz@|(M;&r!`63HB-bzd-l(}-uxgALHuTrY+5GMvz)1>Al{Fb~?yd@zUCD(x2 zG{t{Z%t;Eg6n7&&@CQ@suvR){mJ3P9Tm~iJf=b>cUuMU*9pt9sz7YY5&7flo1OsV_ zf=fakZsJC12TsSh$H77SL6#i&3VuNbefA$gPdw?w?bp{Eeeu3uvFmtDL0Sxaco($~ zT$*)HLiqYRR_cCUCaNq{w$A@@=Kp4m8>uexL8;YxL@tS2ATcmcli;5QTA+xP5ib>r zFN}{3CD}tzu?A++IiQQ<<{`>SbyT(pE_8Sov$6OE!~L0*b?IKwPC%*@co}`cENYb6 z>I|e4sx^>03P*?!cQ&a#M zReO}^mLB%!q8-jPd6}5~yQ4We@XgczEhYl1Hz26;o*~y$cf8-Y^U@+`5-MAP-5Kj$ zyO7xu@hi#TiUGvf9H9FNS03Y(uh1AA{^CHcRsVR}WNgLnTr$NxL-*QwUs>b9Z(CnQvEOGZuZ}#bG96lg34LnE5i>6xXn_K^N|A_w!572^W#9(#X1`d#dH{ONSHS&?06z zGgUW$5az<8Q&l(zz{95=P30rQRkR^@#?q9l`S{9m#5GL; zlG_2XMqNb=_#yG3mh9~c=WO@JP+&aA>hBCL6P88j55GbB7i9m=JW5lD1H6^^(dbEtn7>ri3o?dQ??Ayl5^bT{^OZEDyue%kpoJ*Q1!qYgWJUQhq`05 zf`djiSu-AnM2iAnB1TI`D*$d5OoBg`sr-WfBRc5YF_-6h5j!LOD6t>lL8BTQp16OE zUM_0bY)z>A-bh3+$6KiQSEE~7~(iZ}f83s`m^ zpCvy~ncSsp&Xs@;6*(Sv@^^#{CDNoj@Lh5E7uus z@yV`1^tk*L3)Ud=c8r^Z--6q?(O~(_Mmi(RgfoBMv}7rNM5D-wA}9rp(w2b58>D=z+k18pCL0K2rUa@!W?4u1e#(}s#V@~_9F^SzK48&!Am zc1@f6%}BhB=U(!x6aOgoTe(>#_;?kSxUCi=+5T(3&GW6hC0F&pmy=sMYx_=YhOO@9 z6NS7gjIf`wxXyP~$1?L3u;Vb?=7b%XiLMkZ(|cbsn;t{neGQm(f_^L?y^H(V*oig@ zig>~dLT-?6q94y{Kzer%GpLSh@Zj2P_HD+&pVq4c3>now4uoz*B_F))%_kfQk(P`4 zt^1F|n8gEPAp4C%qxs8-y3aQ{T^spKX6Kh;vZmFCQ90H`{8%<>dpm%%R6B1#%r^fi z#<&DL%pte;zFce4E{8!cGDeaa|D6x?i6t&B%Nt&FAvur(tnXkn*aTzs%(1bjUj0$B zO##*})Q&+f0=svR`IkToz8-RgK=0;n52j=!V7e-GkHhxJF$d|6c2Qr1w zesc3#D2*Mf9v7%p;3cqyJ0Ks3*dJGQQzV6PhE!u;vkPJf))LTOd8e<6Q8u8k0Evz3 z{2SfG0*u5N59{&>d#a(EUeXz6_3OFjLnD5mjgY&$?{h%MNxVn%3eWtg)y`8}+&mnr z*X1-dY*%9=azCX0!ZKPA>%FTOD^%+Jz3uDVx92(@(BylTxXqS2EJ`gv3f34(B6kKV zj)TL;!HfykcUYbhD}3=XpJK}Ry)lpqG736Izk;mSZk7<=jD_;1;fSg<;n1 zU}F2OiMEl!@2pq2Mk^nio=}kztjbcQj570>phWu6P7c59=#>lb^q)u?v&%pt3qfG&n2R{!F!o`K7St<* z(!XY6@5m5@d{y-4o_)0?gj=a;8jvFsIMYy?Fjis-rN2Q;vTfc+rG%2h5l8TlzF4Y+ zyBX3Sf&Y9$G89k(Eti=l%Rx9WJ);^#xrW`@QE%LU$WbJ023%YL)Ex(lXTgNbVD%jY z>@cYOt0Qw#xJxo`kvAa;ends7v~MEg|;Qy%7~c-Q^jr z8o971r<7*&@)gOu@Ow{%hV!yuVl^|iLs7{v%;oKc-?qG?{a<^9*%&=^uFEK#$(Ja| zJ45ebO)nwe0dfx>!3PT8(TAkb4{a-n!yjLh?c8n4-g#vY4XFGJRl-z2*OyDv%@Xm< zH31;DXO6_%V^5&o*F_`N!XLEyEVO40!Kwz24HG9Y0hKT+@lS%>Y?&rFOJdXb&57KL zWaIWKCQ9J)>aP?59pv3SF!JCv%xFHshHOdzJ?!Y!KATivK*`?0YnoQ#RVI5l?Z#*PxZ-`Vz1IV zShRX37TA5Q(9n8RWiaFuei?xZ^!akH?lt*TnDG5eR?+-Q*B zR09hP3oA34`7Q?Di)?5c(?CB?n0RG{Il;0iVS+XLW?c|*fi>FB`VBhsc~qZbfQ
    o4wZ;|%&hd8vvB{bnyX{uO>* zjpo1@Ln}LJ1SvNRqRA5wThPLTbI(?B0h@Ywo^vYb0gaST<*ZV@^J%}g^9F3xpQ`_> zMQpLawc;O#=xDZ>{YG++Ijo*L?x%K2)s{;O2yuzL)(RuQeC| zkUrC&gR3rSMh5;(X zq(u4rw@P{cVQoH;=DAS(REH4f;n}P#k@YI86JaNeR7VhK^`8R$>{jG3KH=yC zzSaH2BE}~&<`$#Cn8E{05!B;qA}42Y&#Wc3TR3%`{Q2p_fdNEgce$lVg5adY{}zS1 z%M8j$wrh%fsfrxFR4Icv+_3zd&706_TUgDF&LmOer+nogJuqnS1%V5>df-%~qvDaF zDA2wiLOouYgCx9jTG#a|Kx>P^1^h!Z{!(A%Q8K@A8J;%drml6p$@#dl6> z0%~Jcl(WJBY|)?2`}49g9<1Nl9;<4*$+aKR;KRuX?xGk%p1i)#Z*K^sJ&CFau;~IO zk-ke=jXMV>{jJr%l`|(=<&EsyNn|T30lz zHmA}iFSP?xysT-$QK&5|6IY>07n{NhS1Z`F>n18;w)xe|c0~UAd6hESs=}{M0Iw(T zDe`>-W4-@Ia^R|TX3Es2Hs%&alhfJvc0s@huhsL=V>p}(d&Sp47J7zO+Xd-d&c#NfzYA2UsUEd z%BZuO6$@wjI9lz9)r;hlNuPd?G?>JGKwZY8&hb^`7u_vQpl_~kSd;$$T z`T}9sDQf1lUTeiKD+r&kO;HYuj*S#bvUJ#YL^>UQ9F!eC{uQhgc5+a?pOwtVqUv|? zvtPf}0YFtxu7vr`zoIm=nU$Zt$g@p3T>jdUKX~-U%_FGI?#Mj!>939nJUMc{?#d&w zs!&o~MDorU%m1V{cGP(8YC^od=2&kgzwz`!qm`m3toH2<6RSZ z;LcS0JK?%Oqsn9!pVMhe9U(v)Bd9ekC`g(aUVk~uAqMM%M5?|HD92}f4Fp-J*2R+%b$>c-i)nYl;I_Sn z{lBR%WAM6GT%j%>y~dsKg1zvz%q)|pkV)C?z=Y7^kMfdeiEqiM`;3q2RlbFd zpKrmahf*WLNA*7SPy_3x)KJH+`%QsBv>38Scy(2ZKAKM)6H90oU*7rFBTUWV#GfeT zTwz`X+h4mW}ftQEboEp|TF$c_-LOT(gzwr~5o#xfEXL zT`ub{h-xK0@^>cH{Dtuq;}wqou+~}ll~VnWAb_8b!(#0=sr)bdd3oUxz#rJ%kj;-v zA}cxV&?{?Ud`Ph11GoQw#o|FM+U4^KW$n;8ou0eQ_Yk_Fa!K}+^f!)R)${mXotQu$ zhJ>Im8*{wT2th1#w_ERXmacO7g~{grX6Le@MVosArSC-1&D>i&W8@?D=W68Meaca9 zekAuMhBq=^i@p*sVAz3k1reGK0o@(VSduiJo^Ow`(Ejn*xl$Oxd9bCHWwwPY>AkLd z7T(6lfe?MIVmI2N{KDD@+_Sx*)lSa_p1^}wkc&Ht`>;~Ma4>JddE>&`Th%EZ9Vwmv z0WxynA2HNJZ@ONi%s zZm4s0q59{W6ykzZ>luN~Vp1_d_EXxW6OjXcFe}1kc^PM7ZU3|l?VT4*fPCRsGRK0) zOhF?JXvK~A^~$T$Lq65Setg29spFtiC3P1tiDWg)_TB1m(;HjHl_K%{v{N0%1v_?z zN}bLjli4@H4R61;2WD6c4&>0Bf=W+b(D{Qw{Na%KQ-yG+NXCoS7J%PYevpU9UN!|< zb_LW&0e>_g2wqJ}_n`T|Tu2XcK)u4((+&mo!j=)Kp31~WI%S=Ti~480OB;^sq9d3w z(sWld@4R=yW@W$KG%=k_wpnZ3U+29EN_m=Ky4Rk|H(o9olJO{?eT&&WM{SH-(&_zV z5_Ta}zVO|rH|L}et~pc-PsF&%a^Po3$k{x-EQ2%#LrT z=6Va7D*XAg7ips~p!5{7x&6EKs|~_e_7$_(1@tINr0FLXVw;fn#j8%_%<`~PkMA>dBrj!b3VXEUJy~3&v z6ai%{wZB7;d|Kf$j+MICXvV`@|2WH@1ucVO1(u&BO5&I60-Wd^B?LT~Jg#*bPez;T z<6k+KvT>K+*GUTiE@Wik_IF-&ovk?g$$yO`gXfSniuc%`EC0{21VOBOsrU0vD~_Tq zIx@)=c$^LG?9I81&eao7=|0=~kjHa|+!Hv1IVEy^h~u89)!!FQVJJwg4O)F=D)k%8?G!1mR;gp&_OCgBGOzU8te2< zSJ37ZDIP;7hXsZ|!N`HGj7EnPx zPiJv7HRwiw zmgC#I9tIO~Y-Hv|WaGuGym-t@=Co^f=FgS{#fL7Mf!A47SSG$iiwWPq7&t5g%%w#2 zM;_*V9fiNp#Jk|(Ij6!}q{KtAd>!=2UsK)yLx`^}!ua6+pJLtkBUTHA?Mp-yEHM3a z%*H&&nLE4(MFbh@x9Ufp`LC|c2J!vJ-iMs*TTzS80vU=GZ-MIHo8R1G@Sn#M zxSu=DfhT)%fK*SYv&7e zDqlm}26K;jNuIzZ9t+3AU zC}BfL>W55zX=i`?FRP|r|>4^jM zuN()VcgkHHoOSR<8_0#D4ap>734KJmk{PtU3X6FVKVr^~B3_K)2E^?Lgmf+$V;lJ}=&B4RTL3Z+7vZF}jdy zD4Wi|)GiGM1>CJUB)ryTQ`3P4@CY4vJbI5)LLmvmf3s#t zg}BZe4PkxvpuHomETo0M4kRoI|Uf*q;QFkskZgJ-(wp7fHUU%O1sd4}s4 zonH^gdOcM@q_N)bguA|Lh2|(n3g}Gzk3ew~+u#L~yzk#Iz$Od#nkv(N?k#DsaWRJP zOhm&5B|-jrR~v(zfkw!T}DJZ(4lVSi(yMFiCEBt`b@!|Z1WZIswghMg5H z`y@|o?%0#LLxDDXJKNhSW?$LzT*FA%Jm+4f)%F+KX@pfEewPXDNz!s6o9y&d(65Ou zspwGyRyH6Q222(piL=VTaBB9C`Li?2*?q?pqYL0pWa@_;Ac~G}%j#eGp}DNT2;4Gc zMbx`dFy3Sjhos*7uAVm%4(3nrW;2D$2z_Sv6)xSEQ~?mrD`81dvDkg@JkKn!4FAB2 znVLSe(YQvm(>*MTzZG2xHJ<#W!19^UHXn~HSL0d9Ps^}(F_=k06l`)SCRI7wM3kOj z_lsMG{z#>6R8!~UgA0h*9)WiavgbV{25B;CC@gSSZQr* zu}WE|Oa>@pGQT%JKD(jx1=>4CtvmGGBvm^ zWT%3yVYA2~4K=#{k<=10IgAmo4J%THRjIjslhBB#@wuQ%)-`FbQ|uP^OF39GKi>Oc zma~<*`x6MX=+hav_;W!yw%@yH@R!TsTWVTmAv+lDl8qu(-NUv0;{)B>B67k^*5HPr zaP?*}OMCP84QyAbe}fDu@bIxikJit9hR2qf6|N+NDf=sbAS2)0`ErI-5$Bg>Su3dX zp^6wj>_3_pKEW(Zc@qeZgI8A3+kJ79FNpA>**!pe5w<5ZS&dHzm+uH)%rEtT{GMPU z9qcwEe~z%P!Jon7Ox^XyVSu&T{(O;qalo7uiVZqYhLKRjK*_TSauM2^&73Fu@_p>FS=lDC|MN|)T);zjqJ1`m77;xZy2*EUDpU4O6Luo< zZ1Ji8rd>JWX7R;lzl!l-_{2{j2giG_Loh5>Iqt3{^W+3!*8snd6-UM`j%jdxsI1SguqvN{aB7#6lUyQByFUbr)PC_xLC6v*d zF`7fso?<*fl~k(b0b~iKP#ki_feQ%8vGa-{))m>`PwI@7O^Dmh&mj?vhEbRq+(=-} zO@f5J?f_*!5xjr+T&e{KG_t{1QaXi3Ps=G_#^e*YQxMaAZgi=D3>$iP#5}pzVgF1( z!H7-xh?M9CL_|R`3S*GWo7ze?(KUbjySR(=fAy`J|6BdQE9)*RhqyoGU{|h zDJ77PLrX3adg9(_wOh>Q#nIHh)NHf#1vHHic5Rke0s;FG+>#sl$)KC#0KkB4Juf zocxSOz{^8lAt3OA>839DC`e1AW5Y(Z0{a?QM`D3$Ivn%W!Pg6JQinbjhiLQ^`Y=9% zY$t#)-s#^9Pe$bAJcQ?-?(XU&A_d6Us3LyoRW*BshB6~4`C>l_Ebawh-|VfOj8(cy zy>PgWrDP(Z)$+!`&v1CscqfjDO+U*T%tsq;RTFyh>ckfKJB_X!J43L^ItKA;)z*nI zn;$?-aQfF#2}5Bn^I6Se3f3lffeeBVJPDF}4+HYr$}pNQm;&icp<&~yhMd#2EF07* z6ZZ@&d@rXVB~WG1=S+Ky1a9XI&^Y#6PniICo%Z89w%u&CN)S_qpN4fgBOf6$C(g0p=gQIi*l39 zlcT|#@X_llp>e=Y9F!4J>=nj(Luw`Y;1+s}v|gz#cPZ}=v0XHHK}3^g_hM2Lh6>DX zii{48C{Yd7aiO{QBb7i9V_~o4d#Y7um_soMMuA(E4lgU#xfm$5K$+O?I~SBi_l^+X zsSh%7%{j?%faov_qbkr|CoBa_JNvvX29k-kIh+Wc+EM6HJ`x0f<<|yP0=5RXZ$%nU zYIa>?rI_*LVu5LsxS)qPKu!@s3Xfz% zv&;1Y>)Xa45r6h7qp&Ri!#3?j+*`R=A{#Zm!>VDP(M|69JE5OAJ&Pm-Z}?jXG+731 zzA|Jf*7R(RsZar?7#|2RBz6%MqH)v>!sq>Sp_%N!pZQzV4&@fzj$x@>rj)Ql>$(X= z`2ud@Rd%zedJUCM!W`B8>%H{EGGS7tGi>^_Zs6=Q%Ff9w z*?V!k&)e4IY{;^rheApmkauBwH8)_xkS^$Yp%!KpOZC|{MbokL9QWCb ze;mz+RDCvyN(Z^q6@`%>uMQ>M`A#x87Tk`8xO_gJeiH$WiU#8Enr-ymkUBq8z&iBd z!}U76SYieE8eLi8lVQ$DZkWd$^rbFfx&D&B*NDo^6zG%{(CXpe1ggICtvYOAz&=Me zo87wE#atu*>(43BS5{lsNr0mCERe5tK15u1x&C~G?H9J*ks z?GEMKlKO)FT<)CT^m5?Nv43isI3age!GSJU`z=nd);1w&jMkHNMac-~0)#j{yQ)VO z(R&_8VrdrgJgqrtU%K5?JOn$mW1PVe|%zHnp$+EIQ1FBktX zM^fkta`NwGtOUO+ZGC>zehgUIQClz8W^z4g-D+^Y2ON7|aa8~3KM2j!N|c{UkTG`g zZ$@%XxKG=NAqL81W)@F$mpez26jP4}MOrA$?Pc3fHdlU9iudBSU6q%@BsyK&6Zs6JNxX%8R8-jeO}?D+u_NC;JGP+us@zMjq-cF5Ja*6Q`d5V=`RhsZMFR`aHD@cQo~u?KQK&Y0BNfFbT5# zIhS83>J$CV_EbFfC_q=Dq;$Re+$XXC>8bY~+r5?Ivay+}FHcw683<5KwB=jvA^XY) z_APw^dIXx}GQZ#7!~aqtsS8`aU#k*9>`@pGk62&?Lu}dxmNNi+^kjT6bB|`0I8}b` zQ~NO40<)f=zf)34(O_(83KOuF5EL&VDr%w(A1815X06bS#ca@wvGgF;vM@Z$?H=&a z4|28P-?$$4CC>*GIz;bsdVt%B;Y33%QP9Wq#dpoUBiJe8}%<d>v=YrES{`V3 zrQs21UH4~MVfrZ}$D0GY68i<~h%eG6w{Dj_v3$HyFafxd5^xk1U}MclnWxDHj`r}^ z>-Tp-{Bb_-4O=Uk3k9AbodLVd^c!lb zgKh4d)mW#KNh*k4KB%D|(R1*s3}iYmlAN}LcO7Pj7PgfGI#5$s28GVbfXcHC&BGmp zfL6`W#q~%6Ac*;8GKpRwqrWs_^~s_gC5>Qf11V~C{Q}tmHmyFn7JMbJkJ`hc;`kfA z1>ucdkf*W1FGpi(3%UR=EjB`_rX|~OyA0$ru-AU^nG6Cdfx!*-iLH}w2J5w8W!{rg z9PXW@2%j6g{6naAZX!>$tZ126ZTHxA>R`nG=P9`8VeTBWs|mj?bY=32>WD#;*Ceu# zHZJM4=rwzNRJ5^iAt3^w=;(k48T9@J7$K+&3>eY_dq7?;Pq*= z?-5BDDl!n`vtE~$KwUWIWOyu&sO5yPVnbS;=hpX5@81a3kV^bG0mo3|-i`_7m5&j_ zor(lm!Hwcq^_WAvZ~e=vts^)3V6bUGbmh!UbrfDn9TpmWKt)(lu#bE7kSAY~bMMbm zcD7zX50U5+gP~*x0S4a*R1wXBb9Q4qx)rt-r~klGSfwH?0d)|%eLAbv11fStZo*?~ zZCAkQF(W+o8gXG(brD>XH z33B*WpLrei9F1h6poy@-}_FH91EsWP3=Ol|(Rr4E-4|U%5Gu3JvBF!-6E-c)F zBpYS{L2lf+>`SW^|IzeLn<8XBt!i`y_a;yq@x6Uc(H3#m|pl zE8>0}x}o`TVVP8Qw6fspIo{usZ5M+%hIwGDbl6zds7>YUaviNkBSi8jS(ymr!YdYd z2p{CbYsdLja{SZlzwv()OOD46`YgkRcKo9cH?$w0{C0CVK{xa=;0#Z?b@bDSfz^H0 zdw3PZ%8Ag~4H9yV`VaVkB3ok`0Ql9P4|74Y)U@Rwe|>&5`R?|ezYP57G^0>O_Jp8j z4+akk$~MqZ2ta*Gvxa2vd|+Oc)= zI*T#ezDm@pjkda4Mm8W!zcr}h zr5v36`@~uSN@Lls9`E_SiBa_6p)5W&OD4=pdNdWWdAEFcsfvXd)D$bg}9keesD|Y-3#6h z6K8!X933Vb@1JfO*CGP)t_jdg( zsCOl`pWk2~Nwb*Zui>XMDr@#XOw1ZTKA1!X1DX3$_k%xremJ+MFp;#dtZ{#nt?HF* zChmM@w}cSwL`TSd2ZP$|kMD?LzQcLb>31oLM@%!auwe)O>AC9()~jP=rbi`CBJsp| z)k<+=V5*9#Zd;Wi9DgVn53VM~SVnAsC%4=`E>uKufg9iJ*FV z_16clPp>E+m*+2{aR#0pgG-AJ{>&Z_@ghYp3*6bZ4iMPPVSH;VgoW`6OD9VdR-CP; zJg%tje?|qY_6nIeC@@l+a1yV_MrEG1@WZ?0-wR0KjQL24ZU%48K>dB1BNj2qAsMZJ z9ik^}Ori&ONXg4Y`XUJgl%1l0hMlQ4O*6|7$#_B26R_HQV|y^o*7?8#3{5?~KvF7X zvg_jSoR-LWI153eVCSR09kZM{g!WfEG$e#UbYRk`gc~szD7&Wg=NQ;hBfGKiaq{KU z+m@4;^z3Oc3kW?lF5G1*W4wGC^%tDCwCN<_sj4>^GyLiRx)0>|4fJP&e10V41A%E; zO8CtODNv|_r3L`GW5%3r)H}&Gm%WUU2AGxmd>c{yQi#;Xp_#s*rF)0KVj8s37D1l= z9p?nRJaQbZCu!GXe``{RKl1btw~Q6~)KV$nqTwJ1DyeSFh+E_ykgYIDQFa#6Af+Se zz9K_J(D+5SZv{nI2Y4baVN;GHsAOPU#w*6PrEbvlR^TIlmL~9;*ijA~R+h~vJRnHHO$Wx8qUY$`nwbc*FMC@WznOvD!@o~N*|eZve6J1^y{wa;R0 zP&;2`0v()Dl$L;8<9Bnah-3jmk|^YULFCWsO0vLS3a$5X%k_kE+lH0Dw|Ine)*$M%<_V4&TwAXv1RITR&a*T!jB*T6>%s*q?jr~F* zlC1+55M9=zZNcH78;p3T@bXDUtd3?fx7KqMk9+#4Xua{$B!>8pa)ZGOVm|lMP=!sL z=*{hQ(v-1^h^;PnXgq&x>5?!Vwb-Wz%hhx^*^;bY56_R)tooE^9P4{T8b>#94!~F(1 zFr2uyI|;Ib5Xxv&YwjPu(f(43V03|IfvRO89?NFlY)(_)rT|4t$#;{7!ZLMHf!=oZ zBP^*-#YkbO%^H%qA$yDjJ-+>ag~`$fDGmw)G!}^GRpQG2oV6iI|N2ETR!ZWfDJew+ z7f09eawpmA$`76R*J0!7ocv0YLu>gT>z6B+@-WM%&PVo^mlGK+_%E46V(5``d>tqK z?e|Z}bss;*&_&?)YGb`IhtR@clRHa=QvSAj$Bj9QN09g3}g|Exp9FXQM-PX^Y0~{Mu(` zAiJsY3L&B$Lx1eue3K65t!B0;r&-91l66q-u0zUqg>{8ZV#e!}GW?H3d3b7i#l_nP69?&9x5*;4TqWM+;=Y5`9qZ za}PGG3b2C~s^(TDQWrj9KFoj1mOctdC~^JaLrSkDuhu8{XwdzBX%}SI(=apt;_b<8 zdEjlkMeikqA8!Qw6ZryTACr}v&+v_uWZ_|XEg*}boS$cq*X7xtD+B+skb>Emw`aI< zH&lihFi(0+&`j1H!)%CD+QNld%eGtoKcV4`zuI-mkm+mXyoOMR!SRW*JT_|7XRCaw zh*pX=7&Ya+vaJXgEfFZ^VryK;I@?fi2JmYvj;`YmwI162I9)N)YH28&`BD%ghv7>H zC3|ihWtXWl7kzA$YBHV-en1E7-+TRxjSiZpi~BO`A#~}mJpiSvN?>P4j+*NxF72@ybx*1|>0gVQc6RhObrafRPz%_Lu}wt20oy;RQO z#OG4wp}_deCL^~}gWjAIXIu?$YDM)!;qno&Vr`$%2J2$>UB^lkh6u^)L^NXqjJI>yK%UZmA_zr@i82z`kykAmX_8kNp3+08>)XO9nR7^VnTW z?YDw*bIq@;h1RsnFb;^}o{)q*|7b|#Y*zXLWr-Pvu+Gu5_kzGAn^@CuPY7~9h&L}m zOql3i;%d*MIO1tWszedd<`wlpr2REN;@8Hm+@1XC2x=6Jk*^L?=Wy}}LdlvE9EB*` zP>YkIX}!f%5()DuOX0ScpX-dE^~&y17rFtq`{r^C%t|*XFSzK&C^(TPFNK82DI75! zXKt-l9`Tm8dH;Bc*$cke%J^fXyQ<`J$oaC1cGjZr{pOMeso9>2$rc{1#4%%bWuD2= zLHQ_Lb{Pg{NAh=NH};FVZ;jV)S6gE5oxSt={z56=vja0(tt*plNfs3QOG0e7F78|s zyhU}>oMZlzRpdc;`!9vHhG(R+j2Q8OXAkM2o?5tX;rgdA4?)}X?@w-S9ayx`i(De-4t?ApHZy)PWfaL3~ zUdex~`m48n@@hll+#{+yg8#_Vm3B-_10;j1(4iKj( zPsK=pmdiSHgAF5hwhsE%;T{F8N6iIDtnf_^$U4iVOIq=P&;anl&r@5>CN=~lzGYN@ zzDaLx>xp_gVWL=Efj#jqE{37RQNH$`v4SHc&$}2%o7oAoJHZqWlBfjF|ZP<^XvK& z^OtZ|ZXB0Bd5b%6L|z`k#5%txs3~OMejYumN3CE%n!F@OdJz5CAZQr>#-#b|3+q=l zh|C&u?sfe=lj;*YXhw+Z>j;Jy_1W!Vp6A1|$3+JKc{U@J7pQ&#csbemFMkN>!^hin z*gI4;DQAF*(P}xc=#MR5GA=PsWMFGqCeS7Lo8u%7celB;D~K{84Gl80qbb+=?%(yc z?6n39Bj)CO24&yOhAt{GFy@jO`6%P9v7ySu2|5LiQT=`!{RG7QEC+29SBhGHG*-9(*%8IL z+Q=0ETDsAp*u`3$aU9zQXPDPiP^P_ySFA9|qO_0)q3dN6#@tZ?+_><(eKP-xJIxu# z7f2j`#jeA=SMEL#p`$>ZNVcz}X5kNne2u0uio765r-&`fk0PQenm^1NDNiu^#XaoU z!R`INTeliubx;0a&7)0xo*J%X(|G2?n{rY8LU2w-g7j#ZOKoG}Ye@OR)-`><$JKt% z`8xJPBbYT7RVoN%am>iZkU5F}Z#H`|WE(@Gd$TGWG z4t1GK(=l8oguBqR6B639z$bR_M;^(^>kcI8A24(bHK(QQfh6ZK;7*bcgVc1);?0K? zG$?;NSk}@ma&*w;DYt#i7+5if>$7ulFKQ|2_kmp}{1Z6k*ZS4TYhI+^t$LAosxue( z&z%BHTaSyW8hJu?Y^qU&lWg~_0pLz%-ECp%l!)h zIT<>fP0vmH*uHoJq{%oXKB|j41s#?3xQq}-xS&1{BfZ5pkr*D9xezCL!2MB1D)q|L z%ar{TONcJBVfEW9X~Zb9h7*au&iymMdq#yKKBjnGEj5mvh1u!kT00pXosJJyPh9LT zs;b+2f4Sq@KKcWAopmrBYqQfoyEF3Tcl&CFZq7J>|8A9G85};bkL93;m(=v=;%pd_S{m zY7X1XKGtjp?PP-Cl>rV!YF1yV=>n{nyyR(eg8%ekb5)&x;f@~G>rq(p$Ac5coRtLH z7n%qtQ41G|=4pxM%LG=A3fcr|E%M0#X`%~|KADv)#a=$VJE_{ZJMS}0!MwleKKqxU z4nX0RLuFz%TbClTXp$+Gt;FO^U!93`RpFTlMU9^T~q*6aqK0aJ{n zO&Uvfqd#0Doj-CvBihk!)L%{>OK4SXUVXjR4-EemP`b>nw(kC+6YQJG`KtdsFECv6 zATF^>f?48SO zs5=mu$Jc3KNk3h4Tmj>RLedO!MF48ff{6pyU9`r*^i8g>pzV4PNZgj`J+;VGcJc5< zlDB5w1W%%wOy!?it1}$1K7@BM=*#0+VIg3CU45{397$7rmo5zkj>3c7wqKJ%Qut{RW1v9YRJIP!%wsI z=nJFz&OFAaGSI)wycqF__JQ}{zb|{<87~J9Ny42CWy>ijC+P-*ws}I7?glBP1UUl^ zQ^n~e>~PiU{;j-vy8DzOs{m7|32K-;r?CVY%xHpu77F%MN^-6@oh6&>ArYr3f3TWaeQ_sPtG|83`bE<0Ux?k!S|R#vWQRMGS}pt|yE$GemHr2aa7@4=^MkV$~$`=^RSKrXw=NuEHz zAe=({XnovVaPcCD{njKZD%%asOf;Ip;#k#0-&Qa^xUjgYx4YkUVw;oa9GNUS7yW&r zSpZ27?;?*6Ual$3*N#Yo~OvF~$i>KsVz^Q{)zP`uFzrfdIz2Ep6 z$N^_~Gv%u(Asozk0EzL>FAeVxrnkIt!TGy(SDEBr;wEt7TDdGkk=kUeG5Zo|mjBeji@jR%d+impb>2lS%<;X~bb&a)=>4d=h(S0GRBis}=N| zGnfVvA)J}>4K#dL;Gb+vqVdLmY)K30vOw=MX;|qa*}^XAbNmin+suFQB~!~mpp-}b zRQEynq3xp(H;T<0#{i$UJDjFR#A%5!#gL1G$s2kwoiTMcBjhebd7SfSHA6%`3Mb#g z@(COOyyN)e9C_8D#y9yyhQ?nCVQ&;E)-6OtC}`XLWI=G_k&MVkfPPj|$+i#0x04ex z^By4f5Rkb1(@^zy_`*yutGEI*a-1rY`2~jVAvHcS_9pfpK4H!E(BA;VK7nI7tt$p8 z=i0pN5ey7a9q4eK)AKUE64tqmq!?cZp)*_=o9m2v3z_!yNen%Q<5ApDJuTD@S?^Ea zdy<;%QMDK&CKaCSm!_#=5PDY2&?dL<*m%-2;~7J_;Bn`Be3Y!@K`!Yrrl0KEf@H)z zHmq>G!86yGEjtA4jrC6qaY928L5#Sw{#U<%6G0s|X+%&?ZV;ZR^B3$)I+||wE(pgs z32baxj5P80-kLrYnE{V)@Z>9K6Ofc~w#uSv9prf_1Z91&^f<;!s#0|>XySyL?-`3U zHNokbKz}EqCY4Q<&T=~l)H?#pAS(;bmsd;LfVmzW)U%D`XwxnMKPr2Ac$N!QOetoEOvgv*m$ibv4hI5`$v}?Ps~6?MWEB zC)dFeD#QTr=y!7o#h-c4Tu|%#2j%|nh~-D3*Ibo^b3n)OgWua^4mrXvbVX8iY|5iz ztBqh#e2xDeR!VA&V(1N|f|Vx+g4%XLNJOyQ*???G3EQHhA2FP`(wu=-&2sNAmi)=F zt^iYK2l+lCmmYezshZ;wNk!sMqI8E!5kQnKS zvREW!l+N*eJT;1SPPq-adejBwE%t4;l2nK!m{l(LAmmtB<t0SZ!X&OD22hFS*{)r<>;q6J1^M`kpxdrCxmztIbz|JYN2n zx@j;K+nug-NsyJz%%39+5jO>a;0NE6U-Vz^5;5PGy1p{gIPx=%1QClGMqP z#ba551jX*=rN;&L`Jsmh;YFnNEgPU1qR7r@s(M8pmjxU@Fx-fb;e>nwhvG}6usNxS zN9I$f{sth2o?Hc)|~Iqfb6%*?-&ETZ{Yo zkdYhe0^B~2pwHQX+_q386wJ6czTn`=n*grgo-5IUB|$iAuQx37al>y<36S|m&;lAh zCGjq5sl@L)r_1F}nv3?T|CxA@Iy9fQ|0RxyHL}FnIKme(B>@?Z4kEZtdk<$$sD>_1 z*T!^uYd}kD1Y9K9Uj4>^Q6NM&B%Q=^c^l&{54v4F)dT1uM>}cv+FwGH*)2|@1o}hak(TO$(9AP! z%zwcMy9083?`HDd<1u>k9z{oD=K(0@zcj89Z!?bMd<6fg)}L?A&Vt;5s(WcTziA>Nw(ZC#z2>Do9E1g$LZZ*z%ulB*tMZPk6}-$XzVm7c?Jo*vbr6U3x#E##G63pMfwSUH{=9 zUd~m5u9_t~QfVjnrx5AqLM$I6Gz9%d_UkFEFP76vuI;5ky7kHYS>D6V1i*+6AtBcp&nu%en0re zJ9n<=`n6(9hCg3BXTBLrQ+7DZ>7vf>(7FQs(DL!59JIPqbmfb9; z&vCJBcNroC1(Bl+h6?gnz4!<*CZPbr^04x{*6M0{Me-_*`wsV`+>diL2|tPdZtE)i z(~Q-a%gt>XM$Di_(IFV0mZ3yt*KQw1Z471vsx=f;(zjkec;Q`^!y^%R(+8}aWNaui z#049Om&?87g2oUASnO==Jf9grg(~okBdK%!0Xdd8sc4ZItj-C+HNu^~2Kcr)3})f{ zy|iPg^{*5&3W>zsT8ckp*<}{!`9_waA`sX}G;Q|Sh%A8#=00#EnTX{zA$ubB zxFMq~1AzH!=qD$mt=PA37ncjZHT6w(9m|)HHSgr{jxs>B3tu4!UsJ??W3M)W%THVb zHM79TF*KIPZ4SM@)s`45mal%)dp{-plGv7Rd#UoLln}!z68zs>Z8|6g7)afgzHw|LDwl^45 z4zMfd>E)alY0DN!_zPCTj<~1;K_`v6O^ToC;ViRt*shzpYa7?=u&0T2Jsf9NH`=+C z-_vB<_}t(AaqX`MH%}&w7>Ic^$6la3{1^%ub<*YyEq>;0@}qR>A;%d|iXS(Ao!9T= z7mEoAxi_$-`H}Sx)(jMHmLMMcPPf!q66bN!5D~vzZntIvQZQ9BQxAqpqd0zj!AxaS zfy8iaYkw6<{klo=(lcMPRcM-`@3GJA2sHK&vc%0s3Es;IQ4Wyz7B(mIJhL^{yr|M0 zeA(eg{@nd)VMDgD`jfx z%@at?;H^&KqgR%j9T^p=-`uy2zAhY_e(sI$K&ay~NkhmL5vZkI_`9o@VzjY0*0!@h zfy-C9lwO7a-Sc&#DuKK8Ev*)?ceWBGmv@5AE5IcizMOQk4B8qq{g6pV4W=@tP{yih zO4LHll|X8T-3G;O2ydGkfNCQd$@Sun6O%~>i1^Vm+XUx_l@FUQJ_6)hFEJ9TevxyIp{t8X$kJ5)ke3I7;XKp@ zqI}y~naX0x)@q=!4+3(_y&)=_(91eWvQWA_MG(68>#vFH5j2Zm7&wNTCyHXN? zX>C+VVPMv>wZ!tSe03kn++$#(EabSAq&< zFAd$Sw03T>$o+>~ba2$^8#xK_Y6yzK``X$@i~p%d`sVA`JzMPoV@H}$hpQwXCPHFKmXZq(QrvQs^JS<_n^I=(*xWVr;`;#x8qf`>t zN9S?_%MsHic@M#x3=HCJV=UdJXM|Nqx=rB1D#^szo%KkZ^;&??y>-ide7k5Y=_^v1 z3c5YadpI`dtX=lQ)N^;vv4t8Xs5sZ*a3#lN(CF&%&#HL$R1Se&)l8aVdcM=FFh$B; zd7(^)EU#VLJs7U_04q+F#3cyP>c8#;`nZ=1-sZQZbk@ zmTh?xDLUM)d-CzL^7pd8kd@=_Ksq1HErfFB2$yZk(%k%y@5xsb@; zFP;S@L- z^5;{rn8LAW^1$z<2ilXS0fbLGB+SBq>`cSnVdSD9?_D|-RE!JB@}GT43IY*&RF}`I z@zV6F`IvzVq&}zUWpwO@s7=0pfQt4U60W}cw(izQ#4KY`L`3dvCuKAkw0Xay1uH4| z%)!zS(_Ii`>ge62vF=VuPn4;l$l%QN>jtN6Wwp(eP@C|zi}uBL0w=@AJrlIIm{$Xv zm+LEm3#FTPZ9SSA98-pGNlHA_OEps-%cdOMj~|k`@x%|zk%fGE)16aYu7z5PbR}j1 z=PBXKbLsr+XzYiedDMN^jP=W-0lM0A`iMi}vVBTR@H}wv2~62rYg3JXD>5w7$(EJr zaKPr9{GStj(8cZR-9>9bmA=5)E6r#UH=8;EZ!OF9LmEkkDV^5UE7Gv?eD9mNQ4PA? zn&1ANB=;O74*xty>R@-zW6*}XWXHBUDdo%f34WsmoV65Y#s!>LFyt4x9VAAHdCGF| z!u@97-`6rGHF8;UOG;{7x@%6QR1w}yR$XvMnDzV0R@Zxc#~fenHrulo399!hA9 zXF*)6C}qesTX1O6L{gUY6KBBUqeW1vQp~`-_p2;4=vTEw=YOXWfZm`M6j^>GQMB!*ptjt`9^e#FrnF9WV`qut%%Ke|`CmQMCL4V^U`bqC@|qO_)YhJ0>12nOG4 zHq%J z1@`Zayq2E5yjgHz$lxav$2Rv>D|`!&a`VkgEQP}lET%Ab#Z#lan;Ip=JvlBP6r`5$ z8JrV3YY)@hz4zl^ZW9OWSv8a>VzkeJmG`^ZzQsxd%Igj~e+vq}HTsONUVU6Kd7Wv# zg9-h7`MoY|&wF^?!bcm|ll_I*XCyQ|H8p=*($>aE zwpA)WFpQRn>CD8reA*a6u24bSMrTKhzpxOkwniUy48*ztsk&FYsid>V?vGq`e7Lj! z?KWqd*Vhe8L~TgfTqDwoK3Y-dmY zrEmnnV=K)otfRZJDuZx__JDFXHR!useOI|%n+y!Z)UNX4#BqHy!WNPA=@Uc$Zj=`W zkx;L7c~eca?Qu;in=-p@shBkxNkqH5r&^hLUb^TOO$1vu>YH1}eU+Y(9+>~_+L4AE|&MNM2 zi{{01el$mZow*SdnKhbN&pn}*?RCvqZ|TXgWKwY!(CZd6PT85-DF|%YtYsWAwnCUm zXY#*Mj6zsqOUUCz#M7T2E~xLlI4Gmska`?oD7Qw#9Y0Z!o~sW=8SnA0i}Eo1!QLka z3cI2_?T+U{|4RkP2n=53TpM6l>E4{u<2X(K;=R|6;O>Np+PU@XOLzXk@`3;WGrf3W z8O*EzFM#Ol0Hq6X#B5KHSz#=KuyyWuX&-5iu)09)xl1g#$r#164i-EEX*a1bqh`Eg$i;Ix zSl!+$lQ$HetDS4V3uEnMDp>mR&YcJ9j04=$0>ofAI_7=C$;-iuw7=|fr8~=d*q{aUFx~$mx@&C;IjXxmO<}p zlM{yC7sI1leSnXSDK3aFOc8pL28w05iW0@Z4p-ROW=a;QI;FkdU&F-p@81ui8Sk4c z;op4@-^Z^={SDEr(iztJKNmo3dj?EDHPEoUehyFvek%U@vhu}!_>EF~9HEFCAlS7f zcWt62i@*-ED@73o<9pn`>+!rHpF0#233mz@BNk8?g{sKRRSv0F)8^)2P6oA|juVjR zitN!`ejO!({85+!z9539SBBnt$WO)iCObPGV1f|Kd^BomV-!5-rH;^Z0~&>S*pfAb z9VHe}?svpoC^hIf!xI~Ya0Ke;*ScO(k`Ld^Uz6E)t-pqUvK`0+6s^xGv$kERZtj)w zV^$70lOteyi~7XDA|!HI>g6=e@}O6US^c%Il27}irTMLX`ef0KrhL!>e%WSBV6|8P zlfKfan?o1)p>ZZS;>(RpMDHJROQV;aL;bUzz?MP3T`SMPTY9?2I7VHjHulWD*@U#3 zP)?|x-dvgp&YSB&bH=djbJ2%f^XltX(R*L)mg(|pDRz;F#6b%8q*~>vUXy~E;k$`m z!ICc=)ym_$Zy7*!*fFBknPjVf#!1$md&hveS;Rv*#1S94eH!haG};7LihgPF(sEr946?ecMZa^5O$n?3 zzm29{v6dE@<8>~YopP)YK8YZLyEejebpD-c72kett}>mHQU{0FlcGO&I~;&3t#iOE?~W6ygVzNrAqM zW20Ix9z0n7R?1rQufazYz&SCj9+te2n>oRkezD9P(0_R*R>TwkAf55k+3nvU?bFYR zpoBSSB}ExEl36$GPPBPDCXbO)aOi%xM|G-Y4TA-E6B5`qT5o9^gB$}#;WTQ9#% zH}KxYAHuw|CH8O`Ej-YHkS_PfX~ri}9F!L0IY%&x7A2n?6Kt1id{}>F=O~e&l8>Ge%eMW&!P)`hOQgN+8%P0P_O^JHyB1xvz;i7hX)oKM?Qf0n|sU*V^eRX_Xv!&Sywx<)qWbnB0p_+JxqUQN3PzsmovjPkx)ToF%sxenJE#7g zn=aYM=Z+u}{D>guB~jph#_w7;q{iIyo2D}B*?!jl5_q!C9B>DH3_CwQ*RONEP%B1# zxtwgyL#PGyXa;%{C7{x6Z72L9Tt;`S5#*?-7)RtTY8+Jl(+!#wOCR%$T}H=6kS39w zX8#U};1i1CS~Yylq-^8SB%bbddnLi$h@UaFCs0vs;S}a@a9M})3U7bvwCMP4lB6~Cc6ZoK#nvh-ryeuW9TH8@5 zZd_uaOxklSh+N8#yZ=ZYr<2F>3?_L|!P~OH{Aft&DfB$=y1z0~S$Xy-u@h{(2>NWR zR57v<0^V-qk;@^b=F}KN-j~NIYjIZiUorm<{8LF=5WbzYnvt8Ed(xIs3~`{Jk_;?{ zq(VQ(A9x`cXrYIl?7~p&9_66uVpV_wMkPSpP&VNN+%Nms0QOZks0(6j>m&|&1+--s zM~$@Y>{yiFQRB{qTD^K7mbjF$qGO1QggVfe%L6$!&h0$69oE|zBLvSQ<5aW5IUOF| zzj`0KO?FQD^6p)S&q4bxR&NA!>n7_-0ND*eU)~Lkic%!q2wp2#%`8}7?M|+($W6My zJ$LM2X%JyXYxs^34HXtX`r@}W8B4g#1w|2bI5tWwfA42?9bm6>$-TOAUk>jXpS#`U3bcWGci z=vD1Gc?A3foqqYxmQOJGp&gyForKyCiQ~ygZ(7f@%4NQxaB3bqt^pGW7@~dklH`M-@KB+;57aWC;dQHJJaQ}KjT1cjnkdE ztRO*n{jQFFPYQZ>XN=x8d^ej&wbU-weP|okL_{}%4UWr`=|t@GC-5XNa^fi$G(~gn z3pdW&#+C>328@+_Ic0rezEvY9O$C$RCT?CJQj3wt&0c7iTA%*c!`CXlHcV#!a@@5f zwuv`06;YP~+QcP|AM(e9TN!Jtoe2i36{h%fPuI;Rt^&gWDzw0F68dm=B1GC6;in4& z!u0-dY0?+MJON8c$w|9HR!ms~MeT=Ks|lpg(!8{TfeFh~eHNcVzn=_B@EEFyDi;8t7XkcT z46-19sS2;!o%PX|NaiWt%4}hffQB1i6E=n$TCibnIM#^zMZd@Uz(s<<2j5O?&2fCa zID_vb{?4NM%ZwC-@BjdR(-nPC>jtBAMtoHl&Nk$1+APtDI=Wc);0$OX7ee`O!_ViB zR+0qBLtmqFc!oX|{OG2+LW}c$oZ=cahp$BjgR?ge(4W9NL)%C7_4cYOqi=5u_M21V zjBr|FCBCQP7cX?j$wtpJoY5+}pH%AaC5A*yTsj0?Naep(xT|wBBNCZfQ|wD-gTO7b zCB$t3BK`&#kp774Z^}ZPRY43SqDltXHx@|cVdGNDcW+vj8n!l=8K|Bby;789ujBf8 zo3)CDxOxvWcFZXS*MYktkKTMHp~wZFDjGo_^Dm`;3X~%Ws6#gU9j%72P3+O$r-r+M z4U`*~hTM@k^>GZjFZ*beQG3o5{_!`A!1ohj8gc)G-`v{Iz-Qn>ZuDW)1}nzF6UVZ> zhi``qDZI{Fra)Zb`U@Ky0}>UhA>%pl3_k=Tgee_K5d1J?+cilU13M>R#^izguC+Vw z60{BrESxavrIh#KFW(Akn(&)Y>ahr_UvRyJ7KD3yKb}iFe%@rf4wl|0qeCUuB*l06 z6{My8zZ&tK`vlJ3bq(19&m8T0{31yuU-k;qD0yxFLIHk!Hlpgg1mf7bR_K}7#T&A) z_jih+b})t4kV|hEFG7(m`p36AuKid`?+YIv@MUy+b#8ZxVgudt542~%UkhP~(x*hM z7X37PXbPl{OksVsfl3uKK4RCL2$!k9ocnG)B!vKRcs353xiAuLJBOr}P z2?7#Ix1iF@fHcx6sid@$(nvQ5(kb2D!_0lJ&;R#+oiF#^J?EUg_u6Z%6V!*!3Q$}G zj!(XAGFd?Mrp0Mw60DvMZE2YG9s=?X!v;269`*K zv<2@wrgv?u{xA7QHh&g?pk(Em-%l#JXp+n%X@nm?So_8V+Qfl%8F=LT$TPbEx;mFP zPXM`JHKYX|7k|TguEYxZ(8<$p*@J&!fnuE%{JdSw%AHimSA2`_ds|f$Qr*B)^dFRH zr6N_=(N3y-U2t(HN25bnRHc{9?L*RZd|epiT?9cUvC#9V-)K4gVruJ(!$X%4A=$-56+Ud+cxa+m71uF#=`s@%^tno}6I#`-~geU~v=vlYg03=p3 z_7F{cP{Khw=8_T^5@D#@D^#9l=1NgWG*aBD_1r)Hh5edE0zb$_nP;f>gzG0Og@X4gZ`;mneim0#uTTE4e9;&xr(nHMT!$cwVB40F});%^@|?)<&P{Z&8r z;)m1~EZ1l`*1VEHzKFyB?tHne7tWMIJA)N4<3ZD z{>87}$hk4fxggAP00W^D7R8*@gx@*d)i`BbzNSl}m#4;g8xIyI`L$$4Rq zW6k*qm?fx{MedP9PPMlSDwyrbx0v;su#`|F*EEUw_fO6*-TLFVfp1+)Q$t=RZF+SOaXhdoa5k?OfdY)%=CziOf(eu=KEWEqpyrUs-@WFt4 z)h~GVHm;tUnbt`DH9lUT9oKsb_=epQ%PK(Un@xLmw+?j_Ke=)&9-pZnTj>Xh5_vu7 z6`McCUMxl6z!_CfCGJABz-+h=`vYf|Vz$7Pr9!OdG=|V+bg~Ox)TpTyltDlP6X@=A z#|+m>hpAy056nXf09%p;p%7-%#5m@EV;$yP#Bmh#`Aq@)0QrFnhCmVh@>f}Jr zPt|mAS~EbEGLT9A<@m>cWFsyZV&$=Il-un>K{Fz4;pQZYKSfDI;5Xnf5Hb|wbd%l^ zb$)~QD6)U#=TY8w5%RYv+k0od8gyC|ve%P8ufb@*(!Y(^H{BZ2Vj&~W9P{U>fI_@v z8I_oqO+DdI`@o&C^JN1=1`q9gx*IEZ3-OO8);i$E$`$a_Mz62uG~=v@SFR*$<)#}~ zIYZ@`eJlxL66?+k5%8ZdEntYx+f2&T>3a3cFuXh_^u2CELq;EZ<=JXeZZLA*Q+41C z|91L6UcoBjSe1av!>{5Or<9Izewp5|_o~O(8Us*%5~?ogm)$-Ok_Q^(nE5kuUiYNr zrq@Jik0P%D+1G0eNb+fu>fTzLh8!5hjxFu&J(U1-bMW)jv{d^jUb=yBmHA>O@DWrj zLoP&^X_*BMZFjz{TN3&@l1jRESwF1Z?;=p!;z@}~-?}uO#Pz_d(AEU!(o}6nZjI%Q zd4pGZMQC10hGBSxr1t#S(n~hSac~k&=bJ7B5vThds`+D)EI9Eb)tSI+V>B)nh<_C6 z9xqmft^^m?HnoZT*f$lHCE&d|zK*>V7%s-y*ecJx=nci`Xa zo+98ROdWBm@qO)?s}`yDz;WuLw1_$0KzA2SAp<}^dEe%B7re3chLiwOQ z$sM;gUh6;8eQ;(wxLnWIY+SFIpoHRtrQOJmYhaonmi^L;h}tLi8;>cU4@Lm7u}V5P zl}j=V?Q7-ViXogHJE%lQ?}v$D$Bz02myiSF8SC=`wB!A%nOU_P0LzuSddIvyF0Gep zQjOd<{a?@*Oa>=RCNMwh1{7!Yqj3T~Bve)TA1$XXWxrq%pzW)6A-fnM1Ef#O>Kk*+ zTl-^gt-okSN$!5Nm8PLru~$oyo8U2F!sP4n2I9vDY4=sExqNv6o9UoiFdt=0RHi|) z>$^qb&B1RxqryOTd!X@V+UkQjvxMdV+r5>{Bn^5PgAeqr&97|V0~hmvWLuVd)Cd={d}PnFe2H&0 z^a%64jBjGD+4Jm|FDIkVnj&%=#lIaQ&uhfg&0GaQG}DO9$$vDH_c^b9Diz@3?V}ziT-Gm(6y{RY07l1!vwq@&+#2v;N*< zhdcq5ur;^v^Aeqv>F+FgO^yw^M_cv^HGntdnO@=@a>MHVDiEv+L;);L4rI+wxS98@ z3|*$u5DhIits5c4)MbMp_e2r@?Y#R~tmG$p8*nd1sA}qb{<=7|E`=AZ>$$3afJJ^1 zjfYtC&-^>%Oh636l?auqFu&jYY|Gl`LVm214ZX2apsrGI4f>meGn%aP)Akd-ukX($ z@$vD8vAQnNJ51CsA2?K@`|O0XuR@bj#uJi#(jGYSoTATAcPI=jsh@)!0x~G<$zRvq zSLV~^d+qqp2MP6%r`}cdkTq%HAD$4a+o}+klI)tmV_(C^B(+Ja_i=ARLSF+tCsH+r_U5G=#r_pM( z_jrGtx6*0u7T5vm{brA8FPPp4xqnlv%*;gLWf?MorVlGE_7lJ5Y(HhjD?V-VCx z8=m$q-MD;H^m(E3>BlvofF2qPqP0{1659ddn4Ex0bT0K#8AnvjAo9iq%TgNG49HEJlzg>>9rx_!G!`DE}77sHbViX`RxMYx^bAiymUT*9K<|ZQVeXe6L#d z&)MUz7=i7Q_n@a7JOYE7KZp2Rnq$o=@5bUXoQh&n2^89{?>}bz35FpX!S9_U+sARJ z_IxLDhIaYOdR>6i@Uy#zQkTz)fZ85h$;P+PEY4er5AtOp<)!4lET}Jz!jSF(icdK- zQV-rwOctPT8AEhb^0ev^~!4+Zm{yV6c){9e9T&*9z$x;MH`=VNv< zGR3Wk7yr;~^2#-8+J@{`&&)qRactP=8TLQ#FsQG+ebQ_6k6ZKOUr3zxl_nz*1})UR zYlKnRF$u;fnH$P5@MkY@O8bZcigc9Q7Q8c!97Ynq1t#!Mfj86ZbuD;vtgFMV=_Yz; z#<9XZSe}*yTB8Qb5ICMM{3$ zek9AB{_lnN`P~}$Fm@GEB1*QeiF(5Q|5T7T_L3z-VomM_rh1<-!}{n}uiXV=C-5Q} zft{zNEy$kpYMqcW{8xO?->S-^h5J9yjIh=K6d(Y(qXTiAu;(j~M?IYUVC;sT^W+0I z)O&q|7)wmc=F+c2X|TbkQU%zkBM@gQ)0hFY$E1=qA&GWz{~{cdxqDo9ZyHDl2F`Zn zs?fuD8jaSeP~FHSVUIC7*)L*WT=aP>4$wX9!*Hfvmb22Jf8g}Xg`obDIxk<&gcmI)8SEPD zy_mTQbUCtpkTE#p=rFY(P7*wF{OF}IGe#u8u6qv<7>)bM+6^p$(pBM$& z=F~sd{5=XR!{6^Y*xPbUtb7)CWQ^`bP_m;9*zVr*6o3cb_4SPjnE1(0NY(n7!x3^gzzaq)iyn+GGLbXYJ%5HH$E*~!CSz$#L zJ*xp-YYk`7cwloY6+Jf*h5~L3$(Hnjem~f~*H>6_hu^_wHi$gQ+f^L)sR{3@q(&qB zbZG)7qTaDWfXZZAeKteFyor{HsCukYl|i3#r! z;>B8|JI7jyI@P@4+v@UxhBA~$byYQ*$eR1AZEh(N(v~KnSz^NJysNA8lx7+@Dz`R1 z=Ar_A4ur=^B3#N}Ik8ga56)9IaaPDten*6_gN}RC3#A4 z?cSRwetT;SEi|C`D={zT9!r{Ylhfn1hxt?UZHmfdm{s3rLp(ps;p@m1pLreazB}$X z0JoE@4A?yQf*+S;_RRg)nSe}gR{kgk%#d#!_thW87B!VAHmwE4K=Q`&kss48dW;P4 zsCPdugqS+oZwqp z3Z@2+(3@f>3KZi;A^jQ!HE)}2MfCHUaPl*KMFvh#pey!1D$Hcx1`DMu~$^?k97ZY-Iv<9)H2mKP(l zh7p2r&BIasN7R`8C+op`=mY(+R|(@lUWujm6>=0mL{%xl(^33j$w%!H5W8^}xdS5e zFU+xyJl6$Z2QJNG=_!legFp@xM$ikn-9}_#V#w&DbMY+y@g$?oA{h?d`3n&N|%`yVJxmjqbID_9O#I(#@QGKoD-M@!zoh zue`~^Er_T%dqd6d3hie5vn};C5N;~8hVZw;-ESKt^)l8aZzZqI*WGHzIbIeemEn3x1an_SE`g&h zGGCV`;G-}YhSRxJ57|JJV1@>09HQFAD0we}W}y7+mqPQAlZR61HNgQZ?_A+s+5+k) z9ZjauUZy_Y186(oHEc{~0G)O95!qc#9EhT%3MMB&X+sX?nl2mt_|TVChp?FhwPOR2 zWmSUDrLs;O3bgioLuoO3Yu-=5pM-h)h;%Qq0QdJK@)lxR4E>QL*u}QW#9?|@=c3*O z3+#I8WI&@{(_5kb!33a4MjZaS6*8nz)j;j;H?FTF#v2mF|E)fhcy#)KZepTvxIcH* zV-IekLyn1x?p@vImz`mU=NYYA#u|`w7+LRx==BXvTHUbEq#J16l}O%Ucr#=JE%csz zdAlk|6z&m*vZKd%=ap9RdUW&e-Hf}npOBs98G6la$7nW%NKpFe!ah~#+_Sv7nFnl( zXm8G)huy2dMcy^(V@JQ?p-jAXYgW4&g5ncpKm;>hW%_;feNUizF2APk(EaN&UnPH8 z^8DLzpJR)J$ya2)=WJArL<D8H0gnKH&wf*M!XTNU()^ney7sl&U$X#^K+18zgNpQyCDMWQafK z#kd{#8N@8V^DJNC$Ybj9Om@z{r4)^buJXNWIhBg5@$CCdM7#+6<_$dq6)=w6BWz&0 zfFg{=_qH?Ey>>C2Ve%7fM<w8x8$5)8VOR*z^6oO!qK}Ft!Oi zX^kR*Nfm(qTz<+P*!+c=%998}LcP(*u6q!-NPs??{ARN-{9%OpmXpCP0>&xB5oS{x z%uza4S-j2@xvECqPA~g__eK|f*zma=-gi=W2|)|-W=7}jU8J1wYs1BG$P>f z(sJY*8Qc`1IMu=_CJEqHr>U)6v0cw@lhG3bDh}KeUK4-xgoWS9IMwo#fO9*YpHFOd0&4gHGmso0HsXuIb#VS&|Qb3JF{0wiPSdy?RuDCLkoU8fP4j zYZ}tPc`myCA*Eb*f6^KqH#b+K`dt8PnvDHVpa1yBv89?Gl6M zyUzBSF3EomIeRffEuY7_sIIhi@@h@=UEIpgMJ+tVXQsA`Png+Js$emgY&(QMPE8~E z6Ac_U94nC_6R&KeO@7sz*n2NG^YZY5JDq{}iEYCZ$YP`tBhiDr?eOIj@OBwPr^Fk3 zz+!wVWBd}+8&OsABjRW1`NU+SxIX=TqWK;$npfta zoQ!!~hYnH_pXQPP3O^FQnvG7&U`2uucaMp?WzF9YJZHQKX)Z0bj{&YKaD9>aK6%Ql z7EG;{Ga6L#i!6%i3rBRuaM`!7`S&}CW)ct<$(T7+lHiv{qB}7^A;N+#lJY0F7MbX) z<{l}bX9&SOPzBh#<4a?XjQhY=K>5xZJb@a(({p)VlLf6L6#=^+yE;YcJk^o~FWBGc zgGQN|B8>s~8&9puu2G)vP_BCCHqX||5UkLm;zekPR(M3D{QESBbA>!f3(�ls>07 zaCaMv0_fwv)MC8EYS-}VTN4AV#J=RxTqdAbWSy9;^qUn*hw<40K|RUh{%w9|SxT5W z@K4)N!V<;#_+kEwj8xPv`SK6j@jWc*k35>Y;?aqe7-r@TvS=NX;cY7gSh-1zu4~{C zbGkJ-WEgn*m*RBU8pSJAR5757wG}VL8^34-?pQ-j5LcUj3@arj(j=^OK^P4ByAh3B zDvPZ4aggLtQVn?_soMNYO>zMBTOEEy+Fl_uI0Ztgvwro(VufnvhPE|gyQAI=WA|&; zmdNBHFNsWplEC8WO_MZ73*S-i9y;^OyC$W*t00Ncw+C{i3WM+Gs#%n7B+X3Po!g-2 z8(zA)uEds=jUJOhR12tqqq`h+O)Ma(Za7RiMCD3Krz7;`ovGl!w^=MZcJk~#$~4^4 zP&&D|3Z}ZVglrNF&3gomAw~ekWeoTI!9K)sP~Ymy^) z+R-Fper2$yjs3_2Ast)hFX{co_|)^YtceqqV$+Ax)dX`FT-~&Y>r>H*$XDHNCt@rw zTSw!VP^!(eOE1NwhCcx3vICvQi7Wn3aVG`^w@^P#UYJ^UKyRZhP!lX>H}b1Bu*PZH zeoQycF9^&pQyA51w_;x=9zDr-ZuDQc1KcFIAQfa99xgk`+5|eLZ)7Aca#!@;UXo%SwdSYR zurKnYjG4+d(gt7Vf+CQI4af^pxjRG{xLBW1fuPa#zfH`QAQD6IO&s@j?z>1W*};4? z*FulObn$k@tCyKge1t_It7}tKi-LAX&6l>I0MA!=!-+@mkc%(Af$kJ*DKvLe!YtXOb- zj!#7hV69ZH9qScKM9*#;9n$5V>tQ&Cfg{-)IsjdvTg_64+DbmtvJ@|A+E3gg-%5&<^jFuHnoS zioME;yy>0W6#1(EJX_^+wqn}A$9{%fqPLcKJ6?j7&|qMEzC?0Ub4K6#+k(2>Rl}*= z7yow90zuFCALh1At+;mm<7`w)-6^XQ>jPKyPY^k@?rS9@spmGqt@F&v5=!4pWKU3s z1bvEZn8@a5I-~H)kHmq$vMaG%ylvzy?S`x~lo_EfnO5m^&KRR7GFs6_SU1{glwi+Fg`OZfW4&c|d%ADy5Tep|!gd zO7yd+$$MXBIZZ9;w!NO{HfkbvD&U6(dRcRJOCEoG~r2St}39blV2QIlz>ieOGwX2U`MX@KSe(MUxqwt>BBJ8>ktTeivzJDA) zex+aKL}DvDJrU9UqH|8IO7i-cP?_;j<0}C*3}(VsRhS~%XO*%o!>LInD;i0dpU8s$ zBGwnqaN9g5jdPl5Qv9W>IKi-9(*H_XQn;dZ;^^H^PAQzEj4A5Mw;`I2Y90=^p}_Xa zs|>n@?vOawspPm9kd2a2Qx3mtfA8P@o>6j382YV@M+Zx)Zf0KHj`%W!GQV~eHvXYu z`E>5kCmmxt+x(e9yux=hmM(rqp$$ZipC418Giqtvu|fyUB|_ns*55o2@0-Ye+nFvD z$#{F1;yCIR*PZO8jKH?uZ@D5#_Dg>hH`@l*nSn59T$q3Dn~0~1Dp?T$UB7Nv8Jsek zG;u7GlTcu@Bd^g5bi@7miH8)8K90fXAw_JYJ(+s3tp+CafdM3LQBgvc`zff+wWQeP z$Z7!bG_jrmyzTOC8;iH~HQ^+?v58t5wZFteuYczYI9|;NBn7_v@Nb3evN}2O{uRQK zdJ1cxH*9IGsoie_Hu#b#u~gW+zUJM-oht0+w0SAXIdP32V>~=H`iB&&FEQWrEb(q< z;STNTH@E)0jIN8A;wGSb!#Y_y$s&NSsYtv+pUFNI zfGC}{IWeiNx+ReZa5)b3|GXFnO^7AB`9eog`L?qOj&-%Ed>P_8(bE6K@Pv!Kb<%* z>y!xT$PHJ<@|No0a`7_(-1in_%XTQrX~!EmQF7|cK2{I6Mt(-*N0EyV$Y*o>#pOte zC?uPI%QC{L7$!kDugBaY=h8#~3MJX*y2>^4IMkdiBt5*N_yfaw z9kf19EXbDc%6Kr46sCR-r64ODeOewGV=pr6(Ya;Z80};JVa)3MGsw*c+f=ZAu5iuE zwoi?17UhvlPuP5`8&hDVDOE~`yTEsJw8=lK)hzgF-{mQhXj5mMPsI!$V}(EeyGY8< z!MaYn@QJJ4T%vThKR3?ez@iyAkF%AHszh)&FbBa$dX2*1d?vu zW341^GH5RQDxph9vgJ=5#ZXmr8MZh7gN{E_IKw%l*jToOw~x5B@4r^GTn+-gzL9}w zJ`V81uAY|ga$_gBw6_|+G$>6@W_5&634F-YUESIpuo>}wFS$~}E!M2}FkjXN-moQX zZ}q!0Fq{XW=S$r(6UPpa1gPQ__#)1|po6OB_3F)H^Tmprwl&p>jB__{BeI?O-NPYz zXF4M;PvY9j&*c$J5kBgwIStu>t@?_WPq4AO@m&0M5{*BPOtz!1E@r>?e+1Fbbw*wMi_Uj;4nav9$2&3DWSW*#j)32w_v5 zlew|Zim~5~W1Z%oi8)UKr=@fHO`>AyxZ^fOsWa!w7&aPaE2odNi9QPms`KPb*tg9O zPiF`!VZlKP@%-CWbNtP|5E)^X^Nfb*qsaqlXNjz3z6WP(rP}rK3o8N1iEz4jwWxa1 zJA|R648BKHr0%E82WwtkT=`yEQJr~~!`HS{YSF+)LL^?dQ%L#;B?D_xJk=d)C;C&@ z?{b$wpfFMqkNl|<7K*#=bS2c`K4BShGEcQm4zn_oxSliCwH7maV0gJQ`TL#7;{?U~ zxFBHsN|7hlQR(>!g`wMhVhYF_O4Lo1H(Td*l2)cB=`{HYT+!Y7rlVv1HHpC~Y1o4A zyHr{MjN5Bu-Z{;O!%^oc`|dfJ9as92YsqwJk=N30(vtv`Mv@EZH<#8oXH52b@UlN2 z;z>!!KWKkfczM;f9-qBZ!`jW%*%5Yls8Hv-)?|6)NtC(@Ge^J z5zM<%{SA%7;6e+2756^bZWs+5sG(lbA7V=l*_C+qDt)UZzQM%{m&mnmYGdCvIp=M`m8LFk_5~ZU!s94 zyVWX72&WPP^Ho1CojkOkq-D@^2y)v?@Gv2^_Yue5>2o1Wfv;lZ9j*OeBRl0(DE-wg zMQ3>fncPRt0>(Px@;oDlN*|->ryp#$)pIozCmE78-l3<%lY8ctM*O*QyDRSE_~|_q zar5(6dGlVbc)px3B2VgbVJ+$tYd`U#I*J!&BEO4-F_gQ`l%dEO7nZ#5?B zRL|IIBA{2j-M=5^^j-HKPG|t1aCXA8@rAQiPSGqT&-)bC9%GsK9=Z`NJhg^gFNiak zR9lY1$7rg&A+?AMvI^)}CG@q7O-XF4ZA^1QpLmQ)`F|y8mavnbg7~ybR1hE|8|jC~ zapcDC1n@;6p_h@riTNz*mx0{+)&pvAl&wP@Ughahv#Qf!AhOt%l`W9|^PMn3b8i#D z6A7{xyIY+ozSIv6FOnn+|b%&^| zk=UT)TJC*o<5^a$EBZFz+;giDY4b)iX#fAtFUU5kdc&9_V zR0yK1au`m#WVKiCe0I9w`kIo;m8rMGxuoKL3+O1K| zOuHGaQGp4*kWHtM(TvkiI(@SuidLYj7l^-3tyIHzQ{GF49ueV~mNqEbOmR1@`eP#v zP1)>8_b0AxD+%rS0m5r zfvqsL!9QOce*9w$2R6I2G~aEXQ{PRu+6ZBKv`m zg!856pLb9ZHas{a~lrCFN??pi~pGJEqacoJ=D zKh^h-vc7K;zNmCQY&uUFXB_9e7J~j-)}-rNP#hE7^HunEr3fRFlCMp%KXxibhlx|P zSh97Q`21;m6Rq-1_Suh(aQwijGZPF87h`20OeK8pCCGSjElM5Z!cTlIbPW4DUn1Xa zely!ye(IQ@n40fWus&{0&C>v>3Z?y(cYlodii+Ma3D!ut^ln~u5=rqC^2quVaU0;- z6X$MlfH(GT*j9tE4;-qky?+*tw=V_DBT$4-1wFlIZfpN3WZyVhxzy;cTItw5Yrc6; zBGf}Dchnwku1UY!Dbq@3x-jCsG8coBdZpKXO%1;s$>NV3@wIF(NEc;P41@3ahu`!{ z302U$ZQI{6SQu`Ln-9z1m631uF;F66mNB91H$|Dk9ua(TT|8$R@OqEuE_vn$JLqwC@6ZG`xLl zk8L7comk;X58c_6=4>Yxn4h0Ni9l!L39&)N@eVWdCI3hrfz2A!UBOel?dYXV?aM0F z#%i=U=&@JwiEix#%TYqD3c-75WdddRus2aT5{saTp}V}we;+=t$Nl}oPt5u%ej$MZ{L zJwF^RkYL&Y5s6@g|6?TLqt#JodH1E2sK&*wox_HCJZi(}=O1sf=C$;g)H!7_x+?vC zB+gofG1bMOF1q-Z4&Joi(QOgJPj_FLy!LDVKA%y30oAjfpoIQ=0oy_&U^6FbaAeAz zzKwkx@@}uSyW~xihcN6{MkJN;m9azdczyXia9KU=03|~GP3CX@Uw`fh|0c>vGFNcS zWq%dKXGwdASFfOn&J}+&559_9$wDS4`+FJ6c@HBwwTl0+2}3e;{ZQ0< zb*05RTFMO1bp(?v^gm^SdLE{Yn|w7WzCb?Xp~}|5QI`)Mv+NN=l5{aiINuf2YF-s>}Lq3MUxf zY)M^pIe9=1&+N8b4-Vg{)mWPE2TW-x~)OL*GsX* z`KBdHbS^Lr|DOvGrPI4fwvC7*Jf`q6#39Ic2?D=zs$0{;Zs!cai@LRvxqW%!lUG1P z1{9JFa?rWk^z}AyUiszF_|KCB`5p@_kKNJFjG&=(P{MKzUZLZj93}_rAL#LPtWB~} zTc$b5adv0P7`(q8r(g>~ZI0+FX!DnRZmJvYQ3uS#G-4&uk3r#ei{c}@&`2A*RDMWy z=2PX%zr}%`Dm8?h&eO^YDb7u2ue<5eterEH1qdQ#M(|^{@HVXc=bOBtHq;}RTs;Ts znHi2vuimG;Ceou7HVVgk{xh2aSH&&gEcizMmEa>3T6s3yKfZ`c{T_$lk-^4$kz*;eo>VQ4v%go)RDgEAa(P}EUDKCp;p6g8`T&*vf~I=j?f&^tsN3vu zqVoN4vsjg4IfHngJudvCJ=t3rnYxCUE_Pt6J?&CQ=N!8iI=MV^_`z1nM+Z+VgU-<#C!s02 z5kM(-CjeS7Y6HPnLpc8GAZjiU$N&=zC2UCTw79}+PkXhY1SEFojN#HXV}Zz6t^SLX zoEGmYV1Jp?98y6-bKlLiFkSW8O+&R|G;fw%i^!i7x5r1er@!7PBjZXr93@MxiEI9j zDq&T_T)^E>+bf3DCLc0q=f@tk@A3&HA*+r*ANE-hC7pGqVb`X3>T1Bpw=qCZIT%<@ zGu_-YEHjsEe^zNtE7nn^3f3iL}UqLZomM-{ z-rZDWlRyQO)@z*3;n7#LYCZutjX63togtGQwA*&h&Oc5OxLK}4Wwu!GI-@%*)dS|E z^EG

    `0f#y4oUhuPZeV1ba;>4-|%S(L& z`mCNSMi)bVGXnw!<__u|sxIvv+iS$B=xl5HT%#Dg76Soq%Pau;BbFnNn;NIz8C(Ol zR9(uku29Q5e{i9^qk{$`iNB()+i|>qjT+)qbZ*pCv)DGvzx7yd{0R{6;T4Hc!y2#T zE_YO?b)>O!jg71!>nj2Bo@yNEL{WxlKFIrz>WcX+I1wcy#&Cb^=GN#pJ>SMU;pBJ5 zUXAM_&_>tG2p3RtF)PDtm8tj0TnRt#5lM!Aa0c+qW%wfvMsY>@sf+`AW4Im3|7x>T zBIxNu|F@^P2hrKFBgVKl<0E_hH?_j@L{Yk5niiKL478NxsVD&8k`U z5QsI@eYsFjMmF}f>ru0k!Gv}Vyc^?G-$IF5$J7;k@33r?YJc$T((1I11%+`Bc(>Pp z6B)cIytivFD!eC5*RaggU(c@|1fki=1j9l`58E~!`kN}e`j3;)J$0;Dma6(^Z)IdR zz1GE<9M$|Sx}-|=?`^ibI^ zk2I{G(3{nM`1hTVNXZb)KI%OOl#0>5y5@;=XAj2h|NfhIcffOn;*=-)wQd*Z zCR-Vfw|rM#AaUYb_0fu%AdBp3)^s#Iqz|I?CZMTwruZR#IJ_;_E}M3*Sa{m*i|y2- z$>-e{Ou-jfj_&8ilWwlI_bM_!`J#E$Ah!ry{}5&p_?*eINx%65@`^eK@y_BfH>{9) zwMY{)-q@!+6Q=Xv%+V-f@k;mj)}lIVIG9O;fxm83#{WveD=I{#oBTB;-RlQv4@ul^ zfToQ^q6&^z0CF@u?8vmTad(TL`DulFRgUtvvCZ%@Wm1POCKDk(kehz(Q6(SBO)-g> zLUcCagH84i5s5cnNq(}e-OnUY>{sS|J)J~gbLyiF*W=H`Y3Ly1Pt)dyW;8>Mk)^`p z49PD12-CZFPijA;gDVGYw&fs~c|he$>dVCEyQy-XtQp@T)@B{+{UIgRO^Y<$=HGvkMrvojPS3r^i$W2S^vO<#zu& zZtUo;25~2N2wGh2ajRnl@6^10xbczlnXRArPWjXxmJtdXZet(Xi`Dl4y^c>~0A1to zg3DsNtY5?MF`3tR!Lv`lw)X@o^Mv4mH+)U7^U*`FgQmAUIWbM$V_c%^ z0DG4j=Y#PKWiJg8m>`JGrW_J>-7isSguD!3eP_GvhB>@nBfG5!9+3t;gi*$%HZ`sLgC zvKAG3pug+m7%g!A#PqQs$aA1)f!LG21>Ue(TX(!V(h@5R1LKNz~6*UA2dA zYrXChL5v}<>aY4QP6xDITnp!%rgOZ??wvepbiefn@P%X~kRY1YJPciRP5lgSqcOR0 zfU;5%`raFphbw}$64q4UK?(IO$o7%Jy|^*nR0MnB8voPAI_P-BKI1$nMD?hR$wJ8M zZxg5q`2gc36*Jn4TuxM`? ze|l=Mw3?T0)vs8VtUu{s_+b21tu1z)fG%_7Mvg5mSCA-y{X(~m%JBKz(!5vh3TMvQ zPl5P@PpG!6Z6VgbpLZV5A>e`0@L_Rm!w*9jvy!Xw#KJN_Z1&9Y#catcJ)Cpst8g8*A0@M~F)4C6DN z%AK1qUQoQftoXWcPB|2+RMC)E+4f$&ZqjnnRDIIV|E4hXhJ&Ws`MEtS>?X(PUtXst z_g)1^bF*ny{Kz=0Iz58QVk9~>Xnpxq4vjSpf#DAZBAg7vH=my3@6qOrT-9F#zW*EM zgE6Crt}_K4?xEJEoc-sc*ML>GvDq{p&fSFZnHR5x-`+n#&OYWLXbx{oP_(cB<)2G$ z!lri)4OIFWdnlvaFP^E5p6UYdogSlM@wV1^eaoa3ghJo};KY*)eyZXM+ z@2yL*WVV*8tK;9@@>f_}vK{MxC)-~Hs*~CDhEg352Y1b*l2qVAZilXPZ9a)nZDvM| zuJPqVju$2I5nLBRb!oxS^>f&Ey@zEvzeLRRaI1YUOR0t%5Fnv+uEqPcRT&FTr{+u30DN-T(2Q5 zkr@rz1v&;H<64vQ7bEJc$jm;QSjXbAJRPM6O7TcUW#UXLW$iwN+8IqM+$$S9zT16( ziu3Vl_{$l8!&*smK0tHWd($R@OsRlBX_p`7K`)ZtJ+;949hs4Nj&I+o<-*T5yrLE2 zP65;lrM-n!AriQ>s~0#g0ShN5;@R|>f6ht_#laCY03RjLkym22rW0v-((2MJR`Q8+ zFOGESWCZ1Mj|i2FNwA?PRbEMF>Scey`!bQ+EH+2KJl;C^VL6aaNQ(-Z{8J;kN+b;7 zl>&XR^+7=bXLC(Fk1&DKXA-kDDz^d?s|WIkg>||`?D&llWYgXDv!xAnk*0f%tTxu+ zb(RdD4#Iw~8|Z?pX;kxw`g@&=4~8shR%#JHi@W`%>AQ1uLj(TkYdG&)M~UAc_`

  1. Di zB@EIzDZqWXeFu@Frx&pFBr*-y?;|~;Ux;cSbhx~V`s8QSCq{puc$B*lDAg8%2@O@x z7hj&^%V-pyY_0Gvp%>APZB6q*lj(!tR-s`165dPtQ_xg%XOAGUY}kUUfX}eo2VD|Z z|I&J_kv*-sz^BY}-?9_ub&u%F66tsEv)$R#zKOo8DjI?=p|=gc6?1el&i(XaAJlCaJPJI|lWr^h(0)zs9?dY;XUf8agIADrznqB-zhoUJ?t z6?JBFFB9$=*?1HX$~#Q_)wSH8`?^WxSK4HB@EfwnEz6<-1NJXcQ(nY1j|geRHUGbs zuEQVd|Bv5sI9X?9Rj#vD_Fi{JB72mw_ZCUEvxRIbWG6((j&R5(d&|t;d*1k6eSe=n z;4@yY*ZcW=yNSIC%FSvsC=&`=!v09MCgso8g)T~sbVpjS-lQxwlwEtm_XDAPv|%20lQ(!7Z<Y~*BAv)0g9NlRw5D(EubQ|WwS`gwRdce;A;E9v*I z8Mt=O?_TVJ^E5WzUNuVrgh)(U#K$KoE&TAb<7Oa(+LyRwbLj2iP@;&{{;Xj>e|$Tb z+_)X~w4MH|HoI%&wmyTmWP7- zc0$;gCa>D6I%>$0&~Sl|*bfY9o3qpYTjeK(4{jG$Vn`4Ty#V!lye&3!wgnTW*?jCz znSX)Cqm@@aXO~T!i307Kp8L_{F+@t_n$tlHXH|LCjQi9Qo^Zs}-}{BAPxN?5PXi5w z4ubA3ee*T<{#L44fbEr?X7+4w4g;N{GHfCGp&rneE|u)_iueyea?XO70hJ9T&%id&V09LO3znu<}P)zr@P|4 zpB;r0yFJGCnqc38?N?H6Cqzi4!366j(kpA&e|Ked^M;!DVg^WF9W|&o)aUh*_vw6t z(gIN}76;~Jp`HiQ*ZvX&RB=^xuQxr4rF0w4Wo_K8Ww5EYu3SA}^T4+2+gJ&C??nbDO;7lB> z%|YL;KT*!AZCJIi5`PJB#RmmpOwhuNQikr#j{ZylTRPH6G%GCA~F%l_wT)^^V>d*kAp@wdQ-* zzkibMSd6KTNB^?$VF(MroN|Mc=t3-2yk1YWiNiemR4M7 zvqt%cXaS`0=Hc%?_btc1J(k|nEC+tpmxl;*Zb9`D6{BEYTVo{@jPzte*-+Er$hlvX zjZ6NL6p8T&_p^`-&3@GS9yi*NZm^5%aH7{bSTKzSW6PY;Drj@f?T?K!pY?`j)>U3H^?*6aiUmo)T8iDf@I+A@PyQG9U zl-2l-S6zaJiw1rAz0#*blF~^TG=MJ}fIYVLrSONi{HRG+dh+@_d%Hgg~)Pr~=JJ#rE>&?>7AFMsu&d8~Y=b+}@ z0I=D=+4PJAhe|Ca*oWfW7I2P_sQ&)G-pne2M6bGn8+&oSv6Hwon!tqJo?0~|VEhK7 zD(9TNZQdmd44{Q}Zay^Q+pjIa*17I`N4Y(Uut03q-MquYwnZ7tuX-9EWp1mV*~2l% zRc_-y)>2q*8^CB$B*iF^esGQ4HmJ+8b0vrhRYN=GccY2}ciJ2`q zI%Ck&o=`PiUbn7kTJYKq-ubW3b;3h11hFTaWo^g7FFSO^O&;?F?kKDULI~aTUY|4% z8+%DlmeoJ*3PTpiZblJ9w^aPj2QqP}Ca1TFD^h*yV>LfYT!lwRrRz-gIj2*nEL<}B z2y+&LZgIdAAnYJ8DG!y*N-H>DrNSFg5$3%_boVa1HY`6!T#mbBeKpe&AGe@@Wgk9Iec zmY9`Id$)_s?RyU7i&5}fij)XiZue*Tl?z(Q1BfE}H*qw_Hf-bMDKL5Yuv@|*RnSzB zJxH5ljc|ky4KHlfyFD@LnsK%>>PFPUad!i{H?+ofZJALS<`opA#NTZ4P1#u8@Z&qAM<*KxLk~3lSeKWS+*@^6;~q7S}X1-j|vzBW17s zz|$(Zngt(vohkw>NAcbGoW$)byliKL+2}1{!5ZKtm6vNMuhCL7Yng&0geg2=4CC*3 zC%o1fBEH^A($Wqbr)#$;vy6mUQphyhE7lNFw9<YfrebJb2NGUi_GHBu#rN=09qn+nl{0ZWt`E2@_}*X@ zB!~g9xtT(shKXQxNJh6adR5D>`iJv+vf5tNX`Zp5#&&&2WzI=6HZ%b(T1KTrn8W(s zf#8ZCb$<-q_-t2^Hb}oo<5|d)a1r2C%H&oO?`5RRGn{w-mPl6+WG=?t3u2n!PZZ%c z!!F!ma8=>*Gd8`8WUGL+$wG8Mcjs)?r5 zBC?q+5(h71El=u}hP4E*c=T9(j+2`LF#>a_a>Qx!f*m>o$;F9fCM{zEDlg_i5l-Bt zyVhcSKVW!Qbi{qP?TKL#oiuqscSq)sYiBTQK7kW3$mi^-^pa5tUPY80^uYjA-m2=n z_L1K+d8k~fY5Th)0a%8Y3Bw9Zb0kh;S0Po@R_`YW*^z<0ArB{u6ia zZWw$9U=DTC^IS%3IBG&&u(EPdjq_Udb-8hf?>#>8`j;z>UbKhIMf3KBwV1lv2ykCX zJEuO{nwSw`r8pA6P(VF1!em_=5c`&RZ9WSL-~V|o^w%8%Yhd%GPc;d2vviJFwRriF z2i?0`4UE}anN|7tTo|(ok@&^>DWHQnbE3TYt zp|>t67yYb*ABzx5od~2cs5o*Gwd!n6E6pnDf61hcx+kR+0Mj5Ew=RU6+FK^!e?ZI> zu;ym3WNOjK*{m47Ar9T5P&re&U`aSpEk(VpraLLSfypW0QKh1Hd`rgG0u~^MK{VVM zxypEq6$%+NDoJPfrS@=rZJfvHwVzMDLA~#(IzCk$jH>=4Phng@+8z4dTe@_yXSXbb z6N<)faT~*~)gUd6&V<|CQ!ZqSuycd2l*9NHJyzNhGihlN`-ou>&w(Q4Z*yJgZaMH) zR$m@@(gMJR<11_puq#%yWkO>9-Yp%wgw-8*%oyRrE|^#QC#H?|4?-k0QX*VzekZ5% zCBIt1rW4c}UJ_f;|ByaRt|xfUZ~wygroN-WGn*=*bQ(eK{PjM-faE@)*Uz83dNJX<}DU}@nmKxHex}1n;Azh}1sPrHh z?HxNnIQ^1%9v4~>XNH_kbVB7AZ z*yQNWrTqO1=6`NmX9^x}i2sl;+5}F1F&(~Q26<3~72nFLaIe2_V0SN%>`1vCr>@4C zo#nuapnK;m!Yn!Z)z@Uw=g1sdhCY9KLB32hhTR&MuawT2i>DDi%ZH>6D-Dq_Z|)eQ zNE~j^XbS#7@Bu_#s*ss4rju3y#vvDv`l&=8&XUWYKbj>M{gnG!ica^#%xAaGb{QQd zIp34v7XUBs?LtsC_(yZRt>WW7S6RKfY;V_m@uBr1`MDRqiEunB1W|wY1`nlwq`M!v zvWxqeePWNoot--T*&femkTg2Y8e|Xr+GuAspih`%X68iTR_1H*-BFce`yhe+T3m!+ zG(sc>xHFLN$+?*l&6(5F!-$LlTYBcKhwnM!RgZ~a-hjf5CO7qw2GF6V8SPB4MKRAt zD9_Nox<*pf-SK=5m1rcuL}{2-FmdIjrY5(C+S%(Xb>ksZ>`G%{VDi}a#H>d#VMxB3 zl0MbR6E9=oe-V@j8FJz(eaoKu4uM`8ys724#^>4K(!chz(|_8Sg`vkRo}xiY4iC9~ zeSKy75*?N=ma1If4M%(Pi)l~Ie)<3DxKr8LVaW=#5i<0FSukhU`Rr$HkiI%83q#nk zDJ+aG*#{|;Z1SJ%?=KQ4HOff<09041O7i*=j_>;^^s86OKB|@%#I&gn-WGM+2_nS_ zA}&(!e8(q4;M+7{@zIPPX^c7qIb)~RarScoH*=A$4YjAgb)UbsIA$g5F{7G#W)JYN zQ=tv|(@GUsq!jSdQb2@{E_Lo+^NuN(zo6fe=#~6yXv03OX*f2ox|wau15kC0ZK0!oclVi8I{*` zXmZ^Y_Zr2luh2aL?XidWo-eWBq)$N7rCC`9zctDDUwruYAewx8mjXCVdd?Pu@Euhw zQ8eJktAGjY&k#0)t@o!|Hc9Bu#(A>Rn<5w*{;d7nHZ?U`XG=BF>B1>F{ z#KdGJPW)^MM56zT*%q)r1QhvqFa=Eb3p(n8&Cw|a3csdjc#e?)x%4s3>PdbQd?#-3 z(u;x5$!hh$Yvek>Vf}+g$D8tY`(F_M?wkIN$!y33bX=IXDbG(YD z$WuCzH)()a=p-Ir|FXz=EP$JxIxzZ^LbzqQ&fa@2csf;|Wc|4}zPqnxQ}xLRy%=jXRe?$sorOEE~9({ooU^)br; z_#6jZ5rl!4N>o6IQ}ss>H!w`=zn^j(>%)_A2h#CIg8gPogvzPs+15 zX+cr9-S;H^*$wUvQt{wgW`*5lre_I*+o>HM`j89+=*nIu8j}nl{o)6n2S#}`$L8$& zcQHl(3?~{M1dXhCC7%fXH`r57n9aJ@;0Sl9|lO_=pk9^5jf#y6@*D1F2?# zr-lwQvnhjWyV75&hg97EJGLDN1T9WqKt1$oOpUk^{qUqc=?B^J0`^34;&_zk_~57B zfRs@6UOmyVtL$CMU~ShVjzHNq+EU;Uf37I-3SAQ$yObhbQybbYKl|Cf>-4k2W96tE zji>WByGPmCEBDgcK|_nI5BkY(Jq(Ti_l**8@GX;lhfS`Y#0mdCIz<+#W!?D`wK#A^ zd0^dEZ)iBo8T0TsXF1w-UXaR7S`|BY9MWBnm$oGrBQO?cD;x_mABNkZFg@`(Vh zY&=Ru38I=7swS_3H)?+dZ>B2yObFk+FHBi*!?xqlst}%V(~}~`pU^%m`PZ%IR(LZP z{ol;icir@t3$wOQGhmlGuzE{Pa*OYv^@chR^UeQoDb$IxN4YtLoZ zk@r+c)(#@AB4&Md|AIJdL_t74*gWL<#`;N+2w^+Oz5r3zBl>^X@rEW8T@2Gd_@<)~ z?60nZc3_7yt+`x;S(w2IE-y|)D)cWW~6|5{iE7oE3o~noDMP|#`-0Aj*JB!iSzG(_^6SWPnIfkaFM_R9-v5x z7jxEn1KnJ#N+!24uU++GaR&pmC94?~X6Ii;!w%=@-|4cPSmd=` zV7Z5y65PK|fB*=qPjeBU3ZHDK{n3l0*Eh($=$O}jmt{uTp(!qA_MA0Es@c76=Fmoh z%>Nx2LPp1Ieay66>`29qy%e6_&&eo->I>TcUMWAA~7x(K}jZVaFn44nun z7ra^^+Qmz!OKyx2Z4J|>e@0>$ET5`W?J$l;M3Px>J0aPB2lKNZkwrpB!74{|Iny5m zK{E!3^H@>B|4QE=YVSZWqylbe-}AZViOmFZR^Orx@LhK`=Ln@Q0&2VtfZ%>@hU|>L zwI!RrK8ubs9DF`etGiZU!H69e<6jnB@?KIapmqa-yj65|%wGhoQ-G-67wEliA8%&; zRdaQ8FB6(|S@%x9nHKDKEMTY^{PbXy5f@COdr5HGfA@e}`LvUx57 z!;#6_0Geu*j(v%UZz{`Pxm)7x-`3LZMJ_VPRcwH2LiDri-@o~Q8fI1+&Q?|sTUYm+ zuI$T+oUg@D}%81!OWj{GVo$kH;dFSw9e9PoU-ow`x;=IsJbGfsx zX#!7Q{BG@R1N#E{g)9Nx>WIPNFr37C@pTSra{d4Lv<~(6Q7KjLjhZA!Le_Rb&=i%6 zUL@0?wmFD6>z=sG?1mP7JHQhu`X-^-oboKpeFAY&H>6Ix?eDE~*fi=#_?T}$9KXq{ zudmJjG)FHYK8Vl(^|bqKJdVt@iALhyN@%KodOdD=Ou^KR=al;Gn^F7zswjQt2MD$-(mj zsRQzD_h6s>PNF!B%&)V&E#=NEFg5w3!o#EmjnZX4j^_CN8Gqqo0!k2;1X&r_|fUFcr#5+d3#2C7cbVLMC0v z8g-geqVrhFeJEkyVGdNz*OqrlH>^bXwdkLs4%~uwt{RoHKnJp>R>X^Uf*WRCM5u9w zUrI-2m+x7y|LRt11i01ch|p!DvOZq#{0xW3!72{+o@(!bdM_5^1 z0v{uYaL1L#E%JMawXNN#bY4n0ca-GPi_E3{|56D;5I5fqdfFsedW{YGGAG-hvQ}&6 zw)d=o-o0l_Ul{`JBl6CemVJNS1W(bLmCd{@@H?d>pCQHq3lwkUK(>0I2O~ zhX-E}1_%%y1TX%;bfJq0 zhUk}PNhB8Jj9`BtPfpS1#+@uR?EtV1LQ@o3`?nrGI+XlJfOZi8$t~*OLUWm@uI4XE z>G{4%Cp=`V%f&^FR+sN{+w$&B9;@`~5gqc&I~g8#4-ZDZ=T+{ii8(FN3-2snI1t0F z^v`ej!&8}pNCcY8jcKIg?>|DZ5jqgBOxzd`qCbBK+h%JR8Z>!ji*oyP;Wq@iFM8J2 z1<`Gp+vQyfof4<^aRV^4cVYzuS*jBXEWx6PMJq4hl_t*F7+-=0QA?14s-a1~+iK2z zY+bTE?+fl19fudKLEf_Vx7-Iyv-=%(e~sPdE%H4x`i3o+!;j8~dvDq{%68Wi{3uC? zr3i_SA{r7>SyfGvOR9I5d;m%XN<6TRum0#joc@S!&hsMHR=V3rxtxl5;gDigagM%4 zZHRb@KP>-oC_iw@u2)wjktA(xftWS>Zym`9MQqcIo%MLiTK`sK1m^$NNIKNdS-!vQ zee?QQ)~M*Ra& + + + + + EnvironmentId + {e94b86d6-950b-4ba2-9fb4-d7b4ccc4fe74} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + true + 0 + 8 + true + 1 + true + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + true + + + + ProjectExplorer.Project.Target.0 + + 桌面 + 桌面 + {ce867f0c-ef0e-4256-b807-c2554ad78bbf} + 0 + 0 + 0 + + /home/lala/workdir/DSView/build-DSView-unknown-Debug + + + true + QtProjectManager.QMakeBuildStep + true + + false + false + false + + + true + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Debug + Qt4ProjectManager.Qt4BuildConfiguration + 2 + + + /home/lala/workdir/DSView/build-DSView-unknown-Release + + + true + QtProjectManager.QMakeBuildStep + false + + false + false + false + + + true + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Release + Qt4ProjectManager.Qt4BuildConfiguration + 0 + + + /home/lala/workdir/DSView/build-DSView-unknown-Profile + + + true + QtProjectManager.QMakeBuildStep + true + + false + true + false + + + true + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Profile + Qt4ProjectManager.Qt4BuildConfiguration + 0 + + 3 + + + 0 + Deploy + Deploy + ProjectExplorer.BuildSteps.Deploy + + 1 + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + dwarf + + cpu-cycles + + + 250 + + -e + cpu-cycles + --call-graph + dwarf,4096 + -F + 250 + + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + Qt4ProjectManager.Qt4RunConfiguration:/home/lala/workdir/DSView/qtpro/DSView.pro + /home/lala/workdir/DSView/qtpro/DSView.pro + + false + + false + true + true + false + false + true + + /home/lala/workdir/DSView/build-DSView-unknown-Debug + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 22 + + + Version + 22 + + diff --git a/qtpro/language.qrc b/qtpro/language.qrc new file mode 100644 index 00000000..e0eacdf8 --- /dev/null +++ b/qtpro/language.qrc @@ -0,0 +1,6 @@ + + + my_25.qm + qt_25.qm + + diff --git a/qtpro/my_25.qm b/qtpro/my_25.qm new file mode 100644 index 0000000000000000000000000000000000000000..2430370fea5fdfd37b1dc4487c6df93ed087dea3 GIT binary patch literal 30023 zcmdsgd3;pW_4rNlW}hqsr5Y7pSV90H3CI>9B`XAyNiq`>LNH;Lmzgn>ndvNn1j=Sy z0|HfnqP0lHr7p$#ZNIgyRjXBtTeYROv{t^_er-jI6#CUF-*fJL^XAQD=DqRv>F-_IuF2OUP87 zkj^?nmfuZC`BZ41A*80BkQMOTs^3C;66pP!kVg2u7VxYDUf2DBkS2K7IS*QRZ~lJ~ z(h58``+;fpAwt9~>JAHv+ONy@hZ)p>LH333uNp(61%jFD?iC(EZmq==VIry*`bQ_L+n` z{xkS}0pb2)A!Pj1g!@}LAsz1!?&IU|`_)9V2xNEFFws<+fuBc+=E^P58i}U<2q7hF zSljhF(eynfB4do9r%_&E&iVWK%q2G>RrHB%VT8uzFPtA4QQVyq-ZT^ zJh&g8zerX+^c;-CFllPw30Z$PY0d+=U-4&R{o)Mpznrwcw+i?^N!GjsaJ-MKy%%I{ zX(4Ox19^1qhZgWIu(7s#HEZp+kaai0dsSDG;EA_DCoU!5m{I^^s3nmH=fd|+vbpaR zA>$5^Eyec}GWTL~-K#gl_iA#e1;)&C6M5*z@V&Q=ywwD9xO^G;&F|(AQgDX6|LQ03 zeT1BPt_{XEOwOI&19(qmO&AvhJuA+-#4-{1{7qJ=5&Cc0k+pU+;NuQv^&N+CGaSs? z_~{||{byO%)%6gP|GTVje>XzN>h)QN1o+;#JnM%$3JGbrKI@}@f;?t@nRT|~OOXGw zS)cu28}RvVw!X3+#_MplVHEK81z79(BD9YTF-6Mo7c`5t!ompTL zOR~>=@(s}2x!M0XxC8Wm9c!02WdF~8cz=?IwI%u4pZVHh{0%v|pM%~_e>A5k+YkNi z%$fc%!0RUD%&I(0i1tLzY!UC~JkMavt9aMltVH&a(wpu;0R*m-k;wNU=5Nmn-iA zIsSt)o?J{w&kk+~%!f?7mD@aHHR#DptZm)KZ9QZmWZ~bqTMpbz$OYxBov@fY(D(!) z6Q5`8luuY&@g8dzy};V~qpV$F;O;T@fIUaK`+oT@=y?|Rz>y}3tu;q%-(H4j5SO1LjOt_4Par7_%NCuGrijk)I(A&Y;k zxv*_J$n86tvXei9etk>h+XHf*Riqhx7w9f1(%gQ-0T`!ati9@e%^?fWTl;6tk(z%H zQg&E#WF59AHTUL%y>wixd2ktwKRKd#_&KnJ&oiZrA?yHRPM<$UWKMe_zq@4M0~|r0YKc@3)=S z-O~3CAs2q2yY<&w2>Du>?m!9heTR<9XZc&KUAb2Gquao4=3JtCWfl+qVT9@6JNVIjnIp}t}%JgChe+m&f&%J3!tYJ^J=@uLGV%(7plfd40!+(7)nQePsW`;QwyY4?O{TFKlOR z-+$_FGJ-sGAL;M^{j1QQd-X3Io=C{#eXL!ym9=XY=wJ8+&|k4b|IXZn;3p61|9T0~ zZ7$b;whrE(a76$458A-LJ#R4I^ghh9uNf{|^9)rzX>@CA}i$j2Kis8n04gsHShMkdL!Fx{{c3$%ojQcZ&2Toi-NX2Hu zGo|C;y>7$L=73zL{Lt{1_J4u>ea_nIgT@)Jft_dBjaR&bbMT|a`6~fF?`>np0~O$> z3`XDD9q{`WRf5;14jb|JD?I804|UYuY*k_*uT!baPHI=)nor zuGwtbed1f-S7)%cRm0kzX4CEUK<9!3rb8AD%mY6)J@mph(CY_G&z$-c;)^WPFV4?} zdBo1;lnVmZ7_2Ofv@&;W&^(r=D*9#{HP85uH8KUfgsq) zFU<2%-wQ4`U&#%D9P7<1AG{g-@i?=!3w~cc(cHOjHORZh+;tXyx4&$T>^}nUKV{xy zh4J^SHh)_He%AlaeESmky)$Zla6Q1a?>9f56$bb_&2L?O4an#3=HHH-0sZ}!`MvxC z(A#G7C&kcTQ%x@S4&Yt1G`I0+6!fzv*Y>A!7}wLe+m3z>>~U`HEsNg;`<=&H&vUs4 zS^)3NWx0nc-vW6L%0o;oG!*{<9^j!J(UIg;DeVG6Lr8mO!tG&Sd zksNr#=$^UZ{lSsjE*||@4_^sH1LV?bKOglA8-s!~BDi=V6bgj+fYTWbg#;ILgXGrP zs)IqF*J+P<1O6<;WA3>%S~_g%*`0uCoa{Be9`U3CKM((th-a@D#&>jWEsm>!K1I$6 z*L$4O8~VC{GddvnBNSI~u(Gn*?)5i>>;nROyZ4KzAib?^bo&D#A0 z>HR!QAi~=`fen1M8_=eK;~chLBEfJiK_TUv2|b%Qt%7gx`h+lFI&;pnxihZ3vfAg9 zewl%k@?yQ|^!ie+56EU%)Tq7x9bv3iz>tub9hM%;PJr;49{*ix zC)h)Ld&uifM~&O^=Pe&e0Q%a1KjQUAsRE>;v9jOUS-Sh1ZNj#!&j~iktc~Bt#;kM7D-sDoC zmO&xZ2dt$dRw%sddmAN&vO~h>vm^|cHqc?l{yAdJg#!(C%+aX!7G| zP(FM*Nb^RY<*e&i%en-eyLg2?-C2vI_67)r3 zNEJ2L+;(mEn&`aIa|z-%H`{%_fKzz@xPeuBUz7T5YKD;qONsfrR7181C56PS<+~p3 znlw0q#JhJo3i@6B#d}}$EIgkzdamuYb>r~wfxq|Mg9<$Qwrqgvn}vZuXov@G^n?2o z{DG+3gIdZ*P(#D^fuK()HcD#fiaG^&B#2LVmk^A2(vM^&PBvA?=;VYFl(9M<{d3~n zl$Nj&_0XnC9D`Q7vtNiPkHN&zb7H(V^_j%n>rgv!>=4>sa4@+aOZw&<^0cXIMPC>P{56}xq06H7Ghw5;; z_l>Sgzd4!A!G98r!3GZ1>6tSpy&J(!C&)0@CWO)9D+_Td!l5^4-`Q)kHV=-BKGmgj zOxUKmy0|wVRAO`YW29K(7B<%??%cAW_+;?RG?1ivqyc{(qU7!Xf9zM(%}r`7HBw=N^|q@?a`;U`jezx zD8lhTAEqU@g4ox!n}xH8!g5_#k!9wdqCK|3kxkods}c42EZc`}LuYBb*+MKc(XNA! zIhMH%H#~q4>|K1%Z3poK9{-lNnaByF;;w$<q5POc^4g9I2sHFLJ>)im}BF?DurS`y?dk2(=lG)p4olS(#T@y&6_$$B_{G$`&~kx z*AGIHV&7ECQsg`$EU=bauG`<^ds_@ZsN<5ky>j%n;6xzQ0%`VvgK-MpLBJej?hNNO z>bk|KJ*`blMPd-O0D<vAoJCIvmMH2p4KZO}MD@mrTe4z0Xpy0y5LOV<|5dIaXr)2$SLRCJ{javq zP%kA}o9bB)QPyaXsb$R5(D9O<&upVxXRuga9*@c7S{e^2ogo3-06**v(r|qaF9vIL z`KuthIb(^9p4;djy}RFqq<4MXI|32ex7!4F?Y>qS=>`STVp!qy2+n?fL&yt!LCiYf zWwS1rKMl)ZYV;^DRv4Y+D6m{1oJBTp_LC7WS}yo82!>!q7+@V1BU%N71;V?+iop>a zl%xgEghv0M-RFf|fuw-AzDYkqh3ElrWcQOBx1;9EjJW`O08`ok#FvAD0vbJnV)rBk zG0+eQV~F&`3y?6H88beaST2%`g?9z~)1?VRfrU%SM&ck*(g*(p5<)$*YWFrL$$P>^ zN3^dGmTUuT1;Anr1++yN3ASvFmRe>rC+VJf!vp9tW!%oKh7~3(57_hyS`ij}EM+6j z!7*noccv52O=3qYE9(R`kx1SS#cROu?tik1W9Z#?PV)8UasTRcW#T@0M}`oj^s z-$_NTgna^zx>MJE5V7OPv#v=L=C?qYK!ZA%%|gOAqFzWiNnr>C(-7UF^K%Fga=_Bq z>Fx8f?12*1Y{E+vvgo35d|U#}U_9J6BAP%kV2_G1gLpJ#Ak={rks17->p)XGcsas(m7yzHC4(My_-Yx^=RzS$64z=OG zdmS<;gB7}B_q&fc++X`nTqEuNgY$^YoG*&24QL6> zPGPoqpvuoig2vydjf0J#NpVF){YQ1d@Lh)S!Z^k#WJTCwfTAm;!xKjbtFbsX#I*aC zHsR{x&Q2LNF$qAEFSt5Kr|9(uqY+$NM19QtTqsA}h)>bQP~6}ZS)Ky%C-|cAaXx9j z0;gyk8zp2I0TEQ@S*?s>l-Xt^wkQIE;r-&P#^D*Di%5=K@mIcSblWyx;p9c&AKy z3n3gN1aFs-D#?_mE$M>@nh$%2g{2h>s%l|<;}(1YcX&w|KB!va2=QfA*mb5zUOPUl ztgLnfqEs!j`jj{c4OwT|C+(b^o)dV2aij-06M)yHWHOY$RKWjZuOeiK_-MZ-6DRc6 z2cHnBBvS~KNl2f`q{=bQ^0$_+Z5lc-G(7}vS|US~h`NJ3~ynOz+G zIGVXiXai9pa3 zi9S_9RYfFL5LYUbm7cbLbPhbWet{7y3sz^egArt!CE2>0i1G^Wc zuxpX2sSvI$Y`Iy&si8KcWLmA=2e!6>y7R!{zrjdouhAtW8^m%@IFHU5IX!Dzi9oy`w7^r8YR?DQeb@? zqe(vqRK;B^2P_B%*vd%;EZ8z0(tMSGVPaGYdto z(AjdDF8KHMa^Qyb0f}E-Gpu&(Zp!k-30|VkCO)bOY@}{N&yxHyYcon~Uur)^iSRU7 zZV94|geiiOt4_CtZ~F+%m?p=waEZPB({x%Pc)R36Cx;V?t>mM8*Mvo^Gk}sJs25oLAHevhr4%pYgRjq87zF!c6G}05L1(6>t zCNVt&juH%>E-q8rP)4K7C3q22lKW5-375`Sssbi>OTFkV=~kl}Xd!Ox;HICObWOK? zh>I1;J|@LVC2%7TqH-~zP1D!|_Kh@MqlRCP`GGx#149zlJaJ1;v<~zaYDmm-(~%IF z>X=zzz>pCZTx7>IO2T5Sr+XQhBGKZu<@q8BT+hHOGZF^pd|g(}WNP%YS`%?1Rg*%- z)07$_4#!*S0oM$pn~D6mRP&n}E&cA-Z)i%OmlrSb$dt04%-U{f`=Jn&nAXm!4MbU$ z8Ou(@;=8(VK&;AOew)m)tsfrle@lYY%&Lnml!0N9O(tO54c$*l zVA@%oxXGysrzf+M`JA00pR*JBoSh+`vlIE8of)58PkqllQt!BGs6A2d+wgYV8wu1j zHKA~%Qx#BaG3{&iJsl_4U}u)DIC30rM$2FzSFKLz;PL4Eo^Tv$1uT)&p;{~nP&rMk z1WS=UEjrrPB@(HeX8T5UN&mCUkgB|0@I!UCJ?@?{irnpwT2 zB2c#QuGBBivbw2By<_V>S@(&IjHY$f?ABGPU|hS$JxL;^Z52Y^0IgJ1WKRppxD_&D zIo4*IDk-hSXj?8z1gYtKE&IGO~%JL1WJ z4@k}f_a5uYMKqEfjkgLxA>xfd?TXYLv=0R&94eQDK+Dt$VJ=Hp4>iH=xc%xt zG%Qzez1uQUdd=dFFD3YK(tC2%$N&{b*6fZ*XtZmnEHh+-!_kPtvT?`|*0||%3&Cnu zS!iOcfVDYOOT?16?8YrkxeO4&&SV60{jQ7=WLpnOyysNAs1sBsnZ3^?L1^o|gI*T> zDFdY)XJs(65bW;T{raZ;3APWVwovyaGk#?x5JGO+pHRGIpa|NbZbn_g*_L>MLf_2F z=V|Q-BP> zKRX=Bw!yws5dI3mCjx)FAWh!^fBT^FL4duhSZ$OO{vMRoMop{@3=G(3+k~JUt4&;d z2Tcd!2?%F+kd{d)v!PxBqzrG2RjbJSV7^#H)Ih87nG;jSG8NNFhzSc9tXlV;!I9*o zl59tHo`^p-5r$@*r7Oe(V*V5geK4b$lkvn`#=o8(H0m z3YZqk$EswLpRw5<ay8Ii;C5D8EN^)YM*LXDsv ztJ4#lcpj@wm%DLRFcJ$k*mJ5VYsebh&V#!0aPM=(2s`HRjV+$wTLpe&3o!U*rEk)h z8@@HrZ*&<5-)dveNLkX-uxCvrUq`FLoKRL}EU)BYEe6TaLBVINsN``uCw{Y5@({se z&7Um+>p0t`QbcT zEeEx4NyTXw#OqYB-i{XErAYCPMQCJ|d&rkG-dKQ_IZOXXiQY~-#E*V=9n}KmIWAEo zV*#~zOh$GJ!O-CKd&3^Vl_C{87Mkud;MNKzIOEm+Y)eHZlgpcMLnU^20qf+MgwpP# zsIe_>Z*;FowY?!DTsCHVLwy!fqs`%dku=;oQ7U5{Lz1`>}{P{LK?7)ldGO5#z8*j`TNBrcVAX79_6y~5es&Ws^5HHnM| z4;TjephnmWTd{rgm|6z?nII?Thxt26ZkHvI5i3|S#-AWBR^y&T;gTc@ShJov|3z~C zgHfTS=bkZrC{3b3_oiVB8xAtSg47!s%AA~*CJM?W{WKtI*godV)s@uDU`Yx5tB^3{ zNf`K&623wmjZs7cm*+@Ga^pxgXM%%uBMvWhBNO^;end-?=$m6RT0KmB>Rq76q+*&a z3l{TNpc1!$61RgA%Omu3=4eJX*s#m+z+pkiq`_e;X@oPuWn}5NgpQfS2|crZWe>e6 zi6o2W|CD{5G3Kshyh}<1DTK3F`%j2<>Xma%=f*rw$yD*tk&iud$P7d}BDwPDLxT zrbmqaJu=3|NtkFojTpx(W1$^HtC!))kKw^Zc1BpZ{=doun>~<$WVzmlgT|#ss{pfs-{n2JU4PuS zJE5nSh`X$CN*&IOLhwD1cywBU7cK7R$k~UGU8T>;`>YDI^vHYy zDv;FTR))NLt*YHC#oBvZaU!SIW-Oa%ThUqSdk+r|*iJg%Y!mRQtWcstJhTLdK?HWh z64$2=0rsB-K1x?Z5CP+F;<(Tyh62|YF*h7rhmkVeS4X9h6y^fvlw-@NvW)ZxgD6tQ zj?7|&C}A_>Tmum^o^@B#LT&ex37Zu;ovIQwlTth!WXaw2s4PL2U)sWoL)Zy?nqXmv zS*W{-FiYoC^&J&(q1on-9t$?pWb5 zGb+9GSm6A$V~e#MPo|)Ek(Iv{w%XxLdWap}?t@wkwkl7LDyid)UF>*zkOC@h6IRD1 zi9D8kvOp44Ot7e-fdb1hXbKq@U>#7e2Yy}^)kVk=`qryXV@Vq3?$Axi?CZ$d>;LA7fT>xy0U?jiB!hjbKy^U@d=bVlef z>6wfs*ivyr-rb4kFV=Wwefy+)n+f@dU8@)@m ztEr>)RxBB=z%0F?sHIs}0cEJegK#z8h#Eb5Aq-tM$NQN_fyH&RYELQg)+Ms3)J);& zzLqL9%-*(Rl4s6=Q`1TUN*KlL7FrpmBp1uv8=6pYB?92WLXafQP-V@r%S93tKhNgH zfG9&8+@{7Y_e%6J_s`M*N^Ex(F?*B1aw%Ab6pgssfY+SJhXfEn2%3@V8e7-(JCfi{ zkm?R*20j(GMkDk%pPdZQV1r)hAh&**jnA@0@E{5eD#X16(VY2Y>sPdIFj@2ZD{-t* z-m;!gXb)h}5?fhQL5fRjg&|0Pw~YeOSIAi?VEO-I+eV>(g^ro)THx$m32ZFQNQy8_ zCE~q0VoX5ML;?Yy!ybZDr+C!1#vY;@920Pt0ng)5RCOs(iI*9vqbkHbWQwMK3>sqz z+f&L6i$Jk7jlrTX!TpX5aA2`C#nF-i2bA#oGr&Q&pisWH6gY7ELj^~Ilf|21oRUjU zJrq19nlWN!n?7B-!4Vvo*kxBTYp;NlNO)ZVTmj^Qg%G=JN<95ex7Fh}tg$ofahp#; zI)Tyg;-O4B_sH&?NvA>yz!OAZ@klooV?ej*(lZ@AI2^cyQ+Ce=huWzkDLsyF0+ay< zm0o$N0%}Ikm`J6G!A!wLwpB31)x3R-Vi;^CcuSCqW}uTr?HbDl-Brts4Lw4m@y0t5 z6FVA-N+&pkmLT;uwsRPda#E-Xa9xNeZ>e2XkL`L1J&2pS>kw%MVjic!aio1EW{@eO z8d=K1R8j-?A3`0Uc(O1_XXHrCqaWSGEF8Rq)DJ^R6Kugn<)J~mBMIP+Rc$*d{bm`s zu7sVOOCdWsFxNB3dcQ=ITOs)9Jsb+$a{aG);ziS1z6=gU(EyEBX2e;fYg<@~Q&A;Y zRt~?6<_(nqP_3{mlJ?6g>zAn{UK@#hQ$u1~-CsxM-j5^$ z)|6VC>Zu=41C1T2lIW&9pQVE3|HyFT6h zq6Ej;`n}YNs8LH(0i_0pOA#3{@#Y{Us08nmABy^W!vNI_H%>&@$!R5E@G%9k`e^D% z(gs>** z*0CjJUV0-C?Li7o03XeR;|@U5g=r;Af>nSNud`zprG;^00duwB&7J*-c}ZDN4SUKR z+4$~cYL?7sVX@S)q+q$s(%@tc-Zic!B}5TR4NEA-i73PjODHg)g2sqwIy?!JMLt6k zk{5O=$QSO9_bg1PVbx#{)MTK=JBwwx5gomRRhFYmExJ4g1|{u@7bP1-aCzvQ8iT&8 zXk88JgCsS~XhAMj?6!);Xm?TY5_r6ZRzXVIt4{CRb8Y-Yfo`=w4F4GedW25_%q&!O zO?SV)!L;Rt9Xlk7Rxk}y9cTz1liTK*iBl{D!v~Mz*R}G zHOMM9ldAhxx3?(2kEhh)*y~iV4{eW@N^j@XHQJPs4sTK;PlZzdKj9wr9}|3J&;(!I9_g-9)TWCc)&a_+o&~(;7~SA zopO3uF6~F$~<$VOqOcm%EUy|IIOi`It#am;{k`P{{`Q}9(@1+ literal 0 HcmV?d00001 diff --git a/qtpro/my_CN.ts b/qtpro/my_CN.ts new file mode 100644 index 00000000..849c5c17 --- /dev/null +++ b/qtpro/my_CN.ts @@ -0,0 +1,2579 @@ + + + + + About + + About + 关于 + + + + DSApplication + + + + Application Error + 应用程序错误 + + + + An unexpected error occurred + 未知的错误 + + + + File + + &Load Session... + 导入配置(&L)... + + + S&tore Session... + 存储配置(&T)... + + + &Load... + 导入(&L)... + + + S&tore... + 导出(&T)... + + + &Default... + 载入默认(&D)... + + + &Open... + 打开(&O)... + + + &Save... + 保存(&S)... + + + &Export... + 导出(&E)... + + + &Capture... + 截屏(&C)... + + + &About... + 关于(&A)... + + + &Manual + 手册(&M) + + + &Bug Report + 报告问题(&B) + + + &Wiki + &Wiki页面 + + + + Math + + &FFT + &FFT + + + + QObject + + + Hz + + + + + Sampling + + &Single + 单次 + + + &Repetitive + 重复 + + + + pv::MainFrame + + + Document + 文档 + + + + Not Show Again + 不再显示 + + + + Ignore + 忽略 + + + + Open + 打开 + + + + pv::MainWindow + + + + Protocol + 协议 + + + + + + + Trigger Setting... + 触发设置... + + + + + Measurement + 测量 + + + + + Search... + 搜索... + + + + + + + + Set Default Device failed + 启用默认设备失败 + + + + Hotplug failed + 热插拔失败 + + + + Attension + 注意 + + + + Current loading file has an old format. This will lead to a slow loading speed. Please resave it after loaded. + 正在载入老版本格式的文件,载入速度可能较慢,请打开后重新存为新的文件格式。 + + + + Failed to capture file data! + 无法载入文件数据! + + + + Failed to load + 无法加载 + + + + + Capture failed + 采集失败 + + + + Hardware Operation Failed + 硬件操作失败 + + + + Please replug device to refresh hardware configuration! + 请重新插拔硬件来刷新硬件配置! + + + + Data Error + 数据错误 + + + + the received data are not consist with pre-defined test data! + 接收的数据和预定义的测试数据不一致! + + + + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + + + + Trigger + 触发 + + + + Trigger setted on multiple channels! Capture will Only triggered when all setted channels fullfill at one sample + 同时设置了多个通道的简单触发!只有在同一个采样点所有被设置通道的触发条件同时满足时才会触发。 + + + + Not Show Again + 不再显示 + + + Not Show again + 不再显示 + + + + Clear Trig + 清除触发 + + + + Continue + 继续 + + + the received data are not consist with pre-defined test data! + + 接收的数据和预定义的测试数据不一致! + + + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + + + + Packet Error + 数据包错误 + + + + the content of received packet are not expected! + 接收到了非法格式的数据包! + + + + Data Overflow + 数据溢出 + + + + USB bandwidth can not support current sample rate! +Please reduce the sample rate! + 当前的USB带宽受限,请降低采样频率或者减少采样通道,重新开始采样! + + + + Undefined Error + 未定义的错误类型 + + + + Not expected error! + 未知错误! + + + the receive data are not consist with pre-defined test data + 接收的数据和预定义的数据不一致 + + + + Malloc Error + 内存申请错误 + + + + Memory is not enough for this sample! +Please reduce the sample depth! + 无法申请到足够的内存完成此次采样!请减少采样深度后重试! + + + Hardware Connect Failed + 硬件连接问题 + + + Please check hardware connection! + 请检查硬件连接! + + + RLE Mode Warning + RLE压缩模式警告 + + + Hardware buffer is full! +Actually received samples is less than setted sample depth! + 硬件缓存已满!实际收到的采样个数少于设置的采样深度! + + + + Save As + 另存为 + + + + %1 Files (*.%2);;All Files (*) + + + + Save File + 保存文件 + + + File Error + 文件错误 + + + Couldn't open session file! + 无法打开配置文件! + + + + Session Error + 配置错误 + + + + Session File is not compatible with current device or mode! + 配置文件和当前的设备或者模式不兼容! + + + Couldn't open session file to write! + 无法写入配置文件! + + + + pv::SigSession + + Exporting data... It can take a while. + 正在导出数据...请稍等。 + + + Cancel + 取消 + + + Save Capture to File... It can take a while. + 正在保存文件...请稍等. + + + + No probes enabled. + 没有使能的通道. + + + + pv::StoreSession + + + DSView does not currently supportfile saving for multiple data types. + DSView暂不支持同时保存多种类型的数据。 + + + + + + + No data to save. + 没有数据需要保存. + + + + Save File + 保存文件 + + + + DSView Data (*.dsl) + DSView Data (*.dsl) + + + + .dsl + .dsl + + + + Generate temp file failed. + 生成临时文件失败。 + + + + + + Failed to create zip file. Please check write permission of this path. + 无法创建压缩文件,请确认此文件路径的写入权限。 + + + + + Failed to create zip file. Malloc error. + 无法创建压缩文件,内存申请错误。 + + + Malloc failed. + 内存分配失败。 + + + zip_open error. + zip_open错误 + + + sr_session_append error + sr_session_append错误 + + + zip_close error + zip_close错误 + + + + DSView does not currently supportfile export for multiple data types. + DSView暂不支持同时保存多种类型的数据。 + + + + Export Data + 导出数据 + + + + . + . + + + + Invalid export format. + 无效的导出格式。 + + + + data type don't support. + 数据类型不支持。 + + + + xbuffer malloc failed. + xbuffer内存分配失败。 + + + DSView currently only has support for storing a single data stream. + DSView目前只支持保存单个数据流. + + + DSView currently only has support for storing a logic data. + DSView目前只支持保存LA模式下面的数据. + + + No snapshots to save. + 没有截图需要保存. + + + Error while saving. + 保存文件错误. + + + + pv::data::DecoderStack + + + One or more required channels have not been specified + 没有指定协议需要的通道 + + + + At least one of selected channels are not enabled. + 协议使用中的通道未被使能。 + + + Decoder reported an error + 协议分析仪遇到问题 + + + + Failed to create decoder instance + 无法创建协议解析器 + + + + pv::data::MathStack + + Rectangle + 矩形窗 + + + Hann + 汉宁窗 + + + Hamming + 海明窗 + + + Blackman + 布莱克曼窗 + + + Flat_top + 平顶窗 + + + + + + + + + pv::data::SpectrumStack + + + Rectangle + 矩形窗 + + + + Hann + 汉宁窗 + + + + Hamming + 海明窗 + + + + Blackman + 布莱克曼窗 + + + + Flat_top + 平顶窗 + + + + pv::device::DevInst + + + Failed to start session. + 无法开始采样,请检查驱动程序和硬件连接. + + + + pv::device::Device + + + Failed to use device. + 无法使用指定设备. + + + + pv::device::InputFile + + Failed to add session device. + 无法添加指定设备. + + + + Not a valid DSView data file. + 非法的数据文件。 + + + No supported input formats available. + 没有可用的输入格式。 + + + Error: no matching input module found. + 错误:没有找到相应的输入模块。 + + + + + + Failed to load file + 无法加载指定文件 + + + + Failed to allocate input module. + 无法指定输入模块. + + + + pv::device::SessionFile + + + Failed to open file. + + 无法打开指定文件. + + + + Failed to start session. + 无法开始采样,请检查驱动程序和硬件连接. + + + + pv::dialogs::About + + + <font size=24>DSView %1 (%2)</font><br /> + <font size=24>DSView %1 (%2)</font><br /> + + + Website: <a href="%1" style="color:#C0C0C0">%1</a><br />Gitbub: <a href="%2" style="color:#C0C0C0">%2</a><br /><br /><br /> + 网站: <a href="%1" style="color:#C0C0C0">%1</a><br />Gitbub: <a href="%2" style="color:#C0C0C0">%2</a><br /><br /><br /> + + + + <font size=16>Special Thanks</font><br /><a href="%1" style="color:#C0C0C0">All backers on kickstarter</a><br /><a href="%2" style="color:#C0C0C0">All members of Sigrok project</a><br />All contributors of all open-source projects</a><br /><br /><br /> + <font size=16>特别感谢</font><br /><a href="%1" style="color:#C0C0C0">我们众筹项目的所有支持者</a><br /><a href="%2" style="color:#C0C0C0"> Sigrok项目的所有成员</a><br />所有开源项目的贡献者</a><br /><br /><br /> + + + <font size=16>Special Thanks</font><br /><a href="%1" style="color:#C0C0C0">All backers on kickstarter</a><br /><a href="%1" style="color:#C0C0C0">All members of Sigrok project</a><br />All contributors of open-source projects</a><br /><br /><br /> + <font size=16>特别感谢</font><br /><a href="%1" style="color:#C0C0C0">我们众筹项目的所有支持者</a><br /><a href="%1" style="color:#C0C0C0"> Sigrok项目的所有成员</a><br />所有开源项目的贡献者</a><br /><br /><br /> + + + + Website: <a href="%1" style="color:#C0C0C0">%1</a><br />Gitbub: <a href="%2" style="color:#C0C0C0">%2</a><br />Copyright:<a href="%3" style="color:#C0C0C0">%3</a><br /><br /><br /> + 官网: <a href="%1" style="color:#C0C0C0">%1</a><br />Gitbub: <a href="%2" style="color:#C0C0C0">%2</a><br />版权:<a href="%3" style="color:#C0C0C0">%3</a><br /><br /><br /> + + + + © DreamSourceLab. All rights reserved. + ©深圳市梦源科技有限公司 版权所有 + + + + <font size=16>Changelogs</font><br /> + <font size=16>更新日志</font><br /> + + + + About + 关于 + + + + pv::dialogs::Calibration + + + VGAIN + 增益 + + + + VOFF + 偏置 + + + + VCOMB + 单通道增益 + + + + Save + 保存 + + + + Abort + 放弃 + + + + Reset + 重置 + + + + Exit + 退出 + + + + Manual Calibration + 手动校准 + + + + + + Channel + 通道 + + + + Save calibration results... It can take a while. + 正在保持校准结果...请稍等。 + + + + Reload last calibration results... It can take a while. + 重新载入上一次的校准结果...请稍等。 + + + + Attention + 注意 + + + + All calibration settings will become the defualt values! + 恢复所有的校准参数到默认状态! + + + + Ok + 确定 + + + Save Calibration Result... It can take a while. + 正在保存校准结果...请稍等. + + + + + + Cancel + 取消 + + + Reset Calibration Result... It can take a while. + 正在重置校准设置...请稍等. + + + + pv::dialogs::DSMessageBox + + + Message + 消息 + + + + pv::dialogs::DeviceOptions + + Configure Device + 配置设备 + + + + Mode + 模式 + + + + + Channels + 通道 + + + Zero Adjustment + 自动校准 + + + + Auto Calibration + 自动校准 + + + + Manual Calibration + 手动校准 + + + + Device Options + 设备选项 + + + + Attention + 注意 + + + + All channel disabled! Please enable at least one channel. + 已关闭所有通道!需要至少使能一个通道。 + + + + Operation Mode + 运行模式 + + + + Enable All + 打开所有通道 + + + + Disable All + 关闭所有通道 + + + + + Information + 提示 + + + + Current mode only suppport max + 当前模式最大只支持 + + + + channels! + 个通道! + + + + Calibration + 校准 + + + Undefined + 未定义 + + + + Enable: + 启用: + + + Zero adjustment program will be started. Please keep all channels out of singal input. It can take a while! + 将启动调零程序,请勿连接探头,保持输入处于悬空状态,调零期间请耐心等待! + + + Zero adjustment program will be started. This may take a few minutes! + 即将启动零点校准程序.这个过程可能需要花几分钟完成! + + + + + + Ok + 确定 + + + + Auto Calibration program will be started. Please keep all channels out of singal input. It can take a while! + 将开启自动校准程序,请拔下探头,保持所有通道处于悬空状态。 + + + + Cancel + 取消 + + + + pv::dialogs::DsoMeasure + + DSO Measure Options + 示波器测量选项 + + + + Measurements + 测量 + + + + NULL + + + + + Freq + 频率 + + + + Period + 周期 + + + + +Duty + +占空比 + + + + -Duty + -占空比 + + + + +Count + +脉冲数 + + + + Rise + 上升沿 + + + + Fall + 下降沿 + + + + +Width + +脉宽 + + + + -Width + -脉宽 + + + + BrstW + 突发脉宽 + + + + Ampl + 幅度 + + + + High + 高电平 + + + + Low + 低电平 + + + + RMS + 有效值 + + + + Mean + 平均值 + + + + PK-PK + 峰峰值 + + + + Max + 最大值 + + + + Min + 最小值 + + + + +Over + +过冲 + + + + -Over + -过冲 + + + + pv::dialogs::FftOptions + + + FFT Enable: + FFT使能: + + + + FFT Length: + FFT长度: + + + + Sample Interval: + 抽样间隔: + + + + FFT Source: + FFT通道: + + + + FFT Window: + FFT加窗: + + + + DC Ignored: + 忽略直流: + + + + Y-axis Mode: + Y轴模式: + + + + DBV Range: + DBV范围: + + + + FFT Options + FFT选项 + + + + pv::dialogs::Interval + + + Interval(s): + 间隔(s): + + + + Repetitive Interval + 重复间隔 + + + + pv::dialogs::LissajousOptions + + + Enable + 使能 + + + + X-axis + X轴 + + + + Y-axis + Y轴 + + + + Lissajous Options + 李萨茹图 + + + + pv::dialogs::MathOptions + + + Add + + + + + Substract + + + + + Multiply + + + + + Divide + + + + + Enable + 使能 + + + + Math Type + 运算类型 + + + + 1st Source + 第一操作数 + + + + 2nd Source + 第二操作数 + + + + Math Options + 数学运算选项 + + + + pv::dialogs::ProtocolExp + + + Comma-Separated Values (*.csv) + Comma-Separated Values (*.csv) + + + + Text files (*.txt) + Text files (*.txt) + + + + Export Format: + 导出格式: + + + + Protocol Export + 协议导出 + + + + Export Data + 导出数据 + + + + . + + + + + Export Protocol List Result... It can take a while. + 正在导出协议分析的结果...请稍等. + + + + Cancel + 取消 + + + + pv::dialogs::ProtocolList + + + Fit to Window + 适应窗口大小 + + + + Fixed + 固定 + + + + Map Zoom: + 缩放: + + + + Decoded Protocols: + 已解析的协议: + + + + Protocol List Viewer + 协议列表显示 + + + + pv::dialogs::RegionOptions + + + Start + 开始 + + + + End + 结束 + + + + Cursor + 光标 + + + + Region + 区域 + + + + pv::dialogs::Search + + Search Value: + 搜索值: + + + + X: Don't care +0: Low level +1: High level +R: Rising edge +F: Falling edge +C: Rising/Falling edge + X: 不关心 +0: 低电平 +1: 高电平 +R: 上升沿 +F: 下降沿 +C: 上升/下降沿 + + + + Search Options + 搜索选项 + + + + pv::dialogs::StoreProgress + + + Saving... + 保存... + + + + Exporting... + 导出... + + + Cancel + 取消 + + + Failed to save session. + 无法保存当前内容. + + + + Failed to save data. + 保存数据失败。 + + + + pv::dialogs::StreamOptions + + Stream Mode Options + Stream模式选项 + + + Stream Mode Active! + Stream模式已激活! + + + Buffer Mode Active! + Buffer模式已激活! + + + 16 Channels, Max 10MHz sample rate + 16通道,最大10MHz采样率 + + + 8 Channels, Max 25MHz sample rate + 8通道,最大25MHz采样率 + + + + pv::dialogs::WaitingDialog + + + Waiting + 稍等 + + + + Finished! + 完成! + + + + Save calibration Result... It can take a while. + 正在保存校准结果...请稍等. + + + + Load current setting... It can take a while. + 正在载入当前设置...请稍等. + + + Zero Adjustment + 零点校准 + + + + Auto Calibration + 自动校准 + + + Save Auto Zero Result... It can take a while. + 正在保存校准结果...请稍等. + + + + + Cancel + 取消 + + + Load Current Setting... It can take a while. + 正在载入当前设置...请稍等. + + + + pv::dock::DsoTriggerDock + + + Trigger Position: + 触发位置: + + + Trigger Hold Off Time: + 触发释抑时间: + + + + Hold Off Time: + 触发释抑时间: + + + + uS + 微秒 + + + + mS + 毫秒 + + + + S + + + + + Noise Sensitivity: + 触发灵敏度: + + + + Trigger Sources: + 触发源: + + + + Auto + 自动 + + + + Channel 0 + 通道0 + + + + Channel 1 + 通道1 + + + + Channel 0 && 1 + 通道0&&1 + + + + Channel 0 | 1 + 通道0|1 + + + Channel 0 && Channel 1 + 通道0&&通道1 + + + Channel 0 | Channel 1 + 通道0|通道1 + + + + Trigger Types: + 触发类型: + + + + Rising Edge + 上升沿触发 + + + + Falling Edge + 下降沿触发 + + + + % + + + + + + + + + + Trigger Setting Issue + 触发设置遇到问题 + + + + Change horiz trigger position failed! + 无法改变触发位置的设置! + + + + Change trigger hold off time failed! + 无法改变触发释抑时间的设置! + + + + Change trigger value sensitivity failed! + 无法改变触发灵敏度的设置! + + + + Change trigger source failed! + 无法改变触发源的设置! + + + + Change trigger channel failed! + 无法改变触发通道的设置! + + + + Change trigger type failed! + 无法改变触发类型的设置! + + + + pv::dock::MeasureDock + + + Mouse measurement + 鼠标测量 + + + + Enable floating measurement + 使能鼠标跟随测量 + + + Width: + 宽度: + + + Period: + 周期: + + + Frequency: + 频率: + + + Duty Cycle: + 占空比: + + + Cursor measurement + 光标测量 + + + Delta Samples: + 采样间隔: + + + + Cursors + 光标 + + + + + Time/Samples + 时间/采样点位置 + + + + W: + 宽度: + + + + P: + 周期: + + + + F: + 频率: + + + + D: + 占空比: + + + + Cursor Distance + 距离测量 + + + + Edges + 边沿统计 + + + + Channel + 通道 + + + + Rising/Falling/Edges + 上升沿/下降沿/所有边沿 + + + + + + + + + + + + + - + - + + + + @ + @ + + + + Information + 提示 + + + + Please insert cursor before using cursor measure. + 使用光标测量前,请先在波形窗口插入光标。 + + + + Ok + 确定 + + + Cursor + 光标 + + + + pv::dock::ProtocolDock + + + Protocol List Viewer + 协议列表显示 + + + + search + 搜索 + + + + Matching Items: + 匹配项: + + + + + Protocol Analyzer + 协议分析 + + + + Protocol Analyzer is only valid in Digital Mode! + 协议分析功能只在LA模式下有效! + + + + No Protocol Analyzer to delete! + 没有协议分析需要删除! + + + + (Out of Memory) + (内存不足) + + + + Searching... + 搜索中... + + + + Cancel + 取消 + + + + pv::dock::SearchDock + + + search + 搜索 + + + + + + + + + Search + 搜索 + + + + Search cursor at the start position! + 搜索光标已处于起始位置! + + + + + Pattern not found! + 未找到指定波形! + + + + + No Sample data! + 没有采样数据! + + + + Search Previous... + 搜索上一个... + + + + + Cancel + 取消 + + + Pattern + 模式 + + + not found! + 没有找到! + + + + Search cursor at the end position! + 搜索光标已处于结束位置! + + + + Search Next... + 搜索下一个... + + + + pv::dock::TriggerDock + + + Simple Trigger + 简单触发模式 + + + + Advanced Trigger + 高级触发模式 + + + + Trigger Position: + 触发位置: + + + + Total Trigger Stages: + 总触发等级: + + + + Or + + + + + And + + + + + + == + + + + + + != + + + + + Inv + 取反 + + + + Counter + 计数 + + + + Contiguous + 连续 + + + + + X: Don't care +0: Low level +1: High level +R: Rising edge +F: Falling edge +C: Rising/Falling edge + X: 不关心 +0: 低电平 +1: 高电平 +R: 上升沿 +F: 下降沿 +C: 上升/下降沿 + + + + Stage + 等级 + + + + Start Flag: + 开始条件: + + + + Stop Flag: + 停止条件: + + + + Clock Flag: + 时钟设置: + + + + Data Channel: + 数据通道: + + + + Data Value: + 数据值: + + + + Data Bits + 数据位宽 + + + counter + 计数 + + + + + + Serial Trigger + 串行触发 + + + + + Stage Trigger + 多级触发 + + + + % + % + + + + + Trigger + 触发 + + + + Stream Mode Don't Support Advanced Trigger! + Stream模式不支持高级触发功能! + + + Stram Mode Don't Support Advanced Trigger! + Stream模式不支持高级触发! + + + + Advanced Trigger need DSLogic Hardware Support! + 高级触发功能需要DSLogic硬件支持! + + + + pv::toolbars::FileBar + + Session + 配置 + + + + Open File + 打开文件 + + + Data Export + 数据导出 + + + No Data to Save! + 没有需要保存的数据! + + + Export Data + 导出数据 + + + File Save + 文件保存 + + + DSView currently only support saving logic data to file! + DSView目前只支持保存逻辑分析仪的数据到文件,其它模式可选择导出数据! + + + + Settings + 配置 + + + Save File + 保存文件 + + + + File + 文件 + + + + &Load... + 导入(&L)... + + + + S&tore... + 导出(&T)... + + + + &Default... + 载入默认(&D)... + + + + &Open... + 打开(&O)... + + + + &Save... + 保存(&S)... + + + + &Export... + 导出(&E)... + + + + &Capture... + 截屏(&C)... + + + + DSView Data (*.dsl) + + + + + Open Session + 打开配置文件 + + + + + DSView Session (*.dsc) + + + + + Session Load + 配置载入 + + + + Cannot find default session file for this device! + 无法找到当前设备的默认配置文件! + + + + Save Session + 保存配置文件 + + + + .dsc + + + + + pv::toolbars::LogoBar + + + Help + 帮助 + + + + &Language + 语言(&L) + + + + &About... + 关于(&A)... + + + + &Manual + 手册(&M) + + + + &Bug Report + 报告问题(&B) + + + + pv::toolbars::SamplingBar + + + run_stop_button + + + + + @ + + + + Zero Adjustment + 零点校准 + + + + (RLE) + (压缩) + + + + / div + 每格 + + + + Options + 选项 + + + + Mode + 模式 + + + + + + Stop + 停止 + + + + + Single + 单次 + + + + + Instant + 立即 + + + + + Start + 开始 + + + + &Single + 单次(&S) + + + + &Repetitive + 重复(&R) + + + + + Auto Calibration + 自动校准 + + + + Please adjust zero skew and save the result! + 请调整零点偏移并保存结果! + + + + + Ok + 确定 + + + + + Skip + 跳过 + + + + Auto Calibration program will be started. Please keep all channels out of singal input. It can take a while! + 将开启自动校准程序,请拔下探头,保持所有通道处于悬空状态。 + + + + Failed to select + 无法选择 + + + Zero adjustment program will be started. Please keep all channels out of singal input. It can take a while! + 将启动调零程序,请勿连接探头,保持输入处于悬空状态,调零过程请耐心等待! + + + Please adjust zero skew and save the result! +Please left both of channels unconnect for zero adjustment! + 请调整零点偏移并保存结果!在此过程中请保持通道输入处于悬空状态! + + + Failed to Select + 无法选择 + + + + pv::toolbars::TrigBar + + + Trigger + 触发 + + + + Decode + 解码 + + + + Measure + 测量 + + + + Search + 搜索 + + + + Function + 函数 + + + + Display + 显示 + + + + Themes + 主题 + + + + Dark + 暗黑 + + + + Light + 清新 + + + + &Lissajous + 李萨茹图(&L) + + + + FFT + FFT + + + + Math + 数学运算 + + + + pv::view::DecodeTrace + + + Start + 采样起始 + + + + End + 采样结束 + + + + Unshown + 已隐藏 + + + + Decoder Options + 解码器选项 + + + + <p><i>No decoders in the stack</i></p> + 没有协议解析器 + + + + <i>* Required channels</i> + *必要的通道 + + + + Cursor + 光标 + + + + Decode Start From + 解码起始位置 + + + + Decode End to + 解码结束位置 + + + + Stack Decoder + 多层协议 + + + + Zoom in for details + 放大查看细节 + + + Zoom in For Detials + 放大查看细节 + + + + Error: + 错误: + + + + Error: ... + 错误: ... + + + + <b>%1</b> (%2) * + + + + + <b>%1</b> (%2) + + + + + pv::view::DsoSignal + + + EN + 启用 + + + + DIS + 禁用 + + + + GND + 接地 + + + + DC + 直流 + + + + AC + 交流 + + + + AUTO + 自动 + + + Vmax: + 最大值: + + + Vmin: + 最小值: + + + Perd: + 周期: + + + Freq: + 频率: + + + Vp-p: + 峰-峰值: + + + Vrms: + 有效值: + + + Vmean: + 平均值: + + + Vmax: ##### + 最大值:##### + + + Vmin: ##### + 最小值:##### + + + Perd: ##### + 周期:##### + + + Freq: ##### + 频率:##### + + + Vp-p: ##### + 峰-峰值:##### + + + Vrms: ##### + 有效值:##### + + + Vmean: ##### + 平均值:##### + + + Max: + 最大值: + + + Min: + 最小值: + + + Period: + 周期: + + + Frequency: + 频率: + + + + pv::view::Header + + + Add Group + 增加组信号 + + + + Del Group + 删除组信号 + + + + Set Channel Colour + 设置通道颜色 + + + + pv::view::LissajousTrace + + + Lissajous Figure + 李萨茹图 + + + + Data source error. + 数据源错误 + + + + pv::view::View + + + ViewArea_center + + + + + ViewArea_ruler + + + + + ViewArea_header + + + + + pv::view::ViewStatus + + + Measure + 测量 + + + + Trigger Time: + 触发时间: + + + + Samples Captured! + 个数据被采集! + + + + Triggered! + 已触发! + + + + + % Captured + % 已采集 + + + + Waiting for Trigger! + 等待触发! + + + + pv::view::Viewport + + + Add Y-cursor + 添加Y轴光标 + + + + Add X-cursor + 添加X轴光标 + + + + Triggered! + 已触发! + + + + + % Captured + % 已采集 + + + + Waiting for Trigger! + 等待触发! + + + + Rising: + 上升沿: + + + + Falling: + 下降沿: + + + + Edges: + 跳变沿: + + + + Width: + 宽度: + + + + Period: + 周期: + + + + Frequency: + 频率: + + + + Duty Cycle: + 占空比: + + + + pv::view::dslDial + + / div + 每格 + + + + /div + /格 + + + + pv::widgets::ViewStatus + + Trigger Time: + 触发时间: + + + Triggered! + 已触发! + + + % Captured + % 已采集 + + + Waiting for Trigger! + 等待触发! + + + RLE FULL: + RLE缓存已满: + + + Samples Captured! + 个数据被采集! + + + diff --git a/qtpro/qt_25.qm b/qtpro/qt_25.qm new file mode 100644 index 0000000000000000000000000000000000000000..3e5c146b14e0e5bd643a55a9f4fa625c547ad2b0 GIT binary patch literal 118333 zcmcG12Yi&p)Biq~>n#C7FP=z35231*U`Qwdaw(S(VjysrT#}RIE?zEyP(lj|gsxN( zMFCM1(Vy4_6)Yg2sMt^}fL&}9L52T!ckiBit_AS@{NLZlcapF(J3Bi&J3Bi&&*0~a zTOIs$-^DAErBc#V|gph7TXc+_8osdtn36bM(+jW4+fQtap?ol~l3gB$O zRKQDs!wGrp5x^0I?C1zM67YV&QG`6+954-VF<>SkPxJ@O0(=$_ee8S^&_c+Q-2ig{ zw*ux8vdaWG4)8Ew9wASGmV7+mtAP20JWc6LB&6T%geV3P(xDHBJ&tjBE9lX`&soFa z7Vu4fe_jok4!n7Q8HAjQ<&7{ z5)KF4!{K1?)*bYWw{SSX%Hc!33F&PlcC*CuheFPg(QyA%1(iO?4Ug7XWHc^-`4+DSWaC8z;bjSFGAjFeIns3S?!l0I_c$vciZ*iEMMY>b@X8+6K z%u@^st&frJR4yHU;Lz>i@UN#y_qQ$)(yIr#c{$eq$DPT*TaOT7`5ZE+=}sba|CQW! zv>739Zy+fHHxY98ZZaa#LCCZBkrB>*ge-fO!{u5sat-G1=0px3T17@p#ky z96q#%jQZvr5%e#Tw9Z(MV}2xQKLPek;qYJv8QmT7y`eQ3JzzE9W)2faaCq}e91dE@ z;jA$n&R);q!!0>{c>#k$n_I}}A{+Gc0vVIl9R2=4#;kzcQrnTSx4({c|1lXmAN}Zm z;V`j+j9riRP4|%W{`JtSPf5D%3L(4mNxJ=iL{Ml+`h3_i`4nPqc!`koM3OOcG356J z$s949kQ;M3tSe_wXmf~U{fU0e^GNpM%YB)8 zlJQOIh_G}%8Gm3uA-B%saLafGg=iHS|IT{+{TB|m>?PyrIKKUiWlbZ6*^g?S*_!6RW2K5juAurA5&5R~C@+kuMP8!5L(x9CBRP znanLZL4>=#4Hy0m1-|9P^t;C~qJE)KWUlSh7PAVRZ=WcxKv$${NY?9oqiXz$En*$ED(?&5I8HV*IE!r|fW9KPFyywetP>+&>*x8FeC(+z_> zO34S^ju4_lF;RiWw3u6g>I)XPxqb`dKP&IIrp5<=T)?O{3)S- zO=}{kJ{1P{f;^L&3PWS@?-TA4QdC%Xt=0%B^#|auO%PI!*ztP{A+_TkRIVq5th)JxeDauJd1DU|RzEL{KX;i3=48Q|J(Q5-d4m1?CPH3)O(@Cy8hRfk zl-~_s<-NBBS2kdGjo^CSO@x@IgvzaEA`J5gQ=f%?%z0Uu_5%8UcaJc02IlLrBf{L* zi{Qt+D=ZlKJJxBIu=;0=<3+u&`Ca&l|0W9C`@|43yBmW-+kD~C*|9_*_X|(W=u8CJ zAz}A33D|cR3D0Ij?>f7L=aL;n5S9qfeG1?3;ETfE%nn2-zE#+#FD62Vox=VY^t-cA zc*}E)2#zO(pFaV;@{fcwPh-6mO%{Hwy@?2g2ZcXgg#9U33x8I-32{6n(>#BQkd=?h zG@sWIVS1uWmk)aKbu!)gZwOgFN!GD^ClPM4%euDf0M~o7tmms+py$uYdJQqd4~>=e z{-hHj^AE`S$J7y$dt5fyv>)_m$%d}&L&(w@vY{_QPHpd%rEfk7yRl7XoSXrw)N?*gxs-D_88qa26W?a=12yG z*2%JG3gIV>uaiA9A9m)AL$YUKA4!LW9J-rx_*c5@xoqgw<~L-|QTzCaTlV6R_RyOP zvKKGl?{D;xy<7*q?);Z*&%9>{xnPy;+4wi?no73!hCPIQ5X+zt{i?Vo{lbm?i?TSJ~AWbr}S!CPQ&n!GDJ-WD(~TXuY3YeIhdLiS|= ze@_S5sVxHh>X&3c&vU|lUy=Rs*GeL|=gIz@hxzUs#bNCi9IpC=!!mG)g`d_PgDe93DLuCI99! z5%SkXDGSdKVPdl=&EYgcUYH%FUxs-|TN~Bnv#((fx<Yjc>wG4P)`Ph8#Ph8=3%{bXcG0zSEsNa-52$$9Q5B#k9w^;{E%CokJ{JeLCEQR z)WNx+^Pnv1;91y-r6;0}7z>GTqdV&881SY0n?Ygoj;N0o!!Jl|5_M7wz1cV+>g2ft zgw&3XI@RMtLQ3+Yer$n#M5l`S=@|T-ZQ7{c2SMK3cST*y*hGXCxlxyTo*_c6TTU(} zLq64V)h6sWZ`RA3t%BUr@0Q2H#}k}3dHW$9h%kS*Jbo1Btwb(QP%k4wr)lzDTlW)U ze@Q;H=?NkX9W76rW`WuV95E6g8ysD~*khzQHRhxGbp;ssQRK*EGj&7CDc?ojPohV;8?N9iZx$;H5 z3W-o{kvH_|fPN3lm)zYPcJvqdvg6cm+b&;jg}v&vM!x15GxotA@-;6_1RXPjf~<#p z?V&etPO6cwOM|}^bB@FI6TI*l4sTw<;X^-ic;F(3zx85JXw^ynKor)=R|5d^0q+2G z0B!<=oWFV>a1kM2mH@5?+yM9};1R$V@b5CfAE1Ai0Wae3edG_&ILJ3zK;V5n5D<7@ zI{|_B^+SNb`}!k5wEtQu-&~yvyK;oXLYaJ9s+oFUUXn9`m!@Apg1*)^pM0@~+g5oXt725x8I~9tJuycl34o@86@OQmJI}du3{wITia-u@_ z@hL(~g^K8JSHsVGT@iBwlVL|Au|qQ$9Y@XO9C+Pn<=cE_!XwwJJ;ip`2n zElv_5JEe$AIRL#)Q^Ysa!M}J)5&y^uBJ{sO(e>>Y=kGMg#7 zKY?|+`x`}%7XhEUQ8BdR!-PzGQ!zBD8td~}#poSph>+4zF~$geJ^z^^{fr!OksgZd zy?XM>`2^By9kE>%pSagWo_D{9XcVtgkR zbErS`zj=x!{jna5pDUKo^XiC)6iZ&l_`ZEiv3%fM?AxC!RvrPr<1Z-gQDeR{{!pwN z8ApiakYe3NClQ8hRIL95c5=lpiVbhU&urU8ao@sq*dOO9Hg?|v_?Y710sG;XwpMI= z%7b`NqT&(S@6#VDw)eVBh`Ny@LJXcg0ihVtn`gqS$=`eD%CT@%)S<@DJ(~ucY)O z+XAkDRY@On8d&s-=oZ|ia z;m5@GRD9UlLCD!6#j!`=hyM1y;;II6C!Itv^;Ax(M7vkdD(%rL zF+Xo99h)$3oHJih)~oknUB)TzdcOnWB2$%%;m-&i%9Klwp}#3FDOb36 z;T$nlc~8e>L|C~+xi)4P)_;<6{VykoFsDp;Uk%proBNgb&G+D(Hl4%0(aHyRB%t3H zIsEZY<>sB3x1_9yA|+9EXr4ULSC!>RlYh&5B>jDxvx9sHFmo4z=)@y zXK~7dDUj2o*~)_tVLW{sI9z*1dGJm2v-UCN!S9L@e~9I9dI^X36mqz(hQs^sSH6>o z`7+E`9_oK9_W$pdN0)wwbNxK!C*5JEtw)ugnJtKWCMr+eeFOa1vC5xc!uS@QRh}uH zi@$%Vy!_-aoI`I^UjDia{U)k}sXMV>cT>sNV12u?Rfay7iBOQJYN`Dg=P!$@-B6r2 z7adWV7GVBMyQ(^mGZJC;d#dh_Z9xork*dd%RK$ITsd`;GLxcfCRDFJKgY(*PRlh!% z7kekwfK|}H@uyWcKZkbr9#IW!wFu{mRMpTyC$NtHQKjTgMBL|$Dz*J5@T>k%rF~^4 z!r*^ZqZ6@SH!oL>X?qO&+D_G&Co%5m+f}(U+rl27P>s78^t1M=COjTP$e#ODR`(lN zj~11u{UWrVqndiW1J1L*sAhI41l}Um%(*ys>1U~Cvi8SRv!>n-dvL#M)`m{dk4YT< zxQRi*7^PbB?po;6KdKeCuY!ELs5XuRU)Jwb4=C@&K2e~0;Hgx|TdjII@Sw+pQu-T^#I0|=u(~hdpGv4W2#fH z50qs7J9*E0Wb3dmRxh9(A+>_9}Y4x>;-N2hSSREib_y%Qfn@x5g2n=}~ptqo)wx zXs&K|Wh(Szy}G>(=%~;OD#4=mOoZAu)HWsN<@>E_+sNk-r&+8nnU8iOiq$3e z6eF(ik-GE&?00P|)MaU_;V;~zcKnF>Uv-yyT5s6r<1N+GyY&HI7u7SfvWd{-IrY5l z#W-JVSI-|^4|$fU@7lSE2(C@)#kq5!hYjk6E(!2cE~uAXfLsr4P_GuSj}1vzuP%b! znRH0~*!@_Sy-PX#_zm^$6K>dr0qSRWK_55Wp?-e+hln#|t6z-4c`?VTe(`i6e*a4S z($jYIU!{KeXD7~w+tjagf?PAw)vqjh8~(yv^{Y0lt0=4b^}G6m-mmKYpJ1NGyr6z7 z1%C9vQ5VwZ7L;P@~`p^Nam;IO39~5e^PpH(NeTeb3yQn^X z?@h4xz0_Y&JJ@cE`peFcYvpeBH=jd(H$1EUZ3O7u*oDJcpQ`_ODIf8R0`;Gj2MDp< ztUlL0i3oS?Q~z@j^Ve)ChpDI3|0Y+#zrSB2KLx(~9?~dgLGCk#Y1DVxap!frM)TPg zoI?`;w_@M8O`|yrxu1DY)9jbwI7jI?T$QG28IAc|wL;S_xd`_evp5{tNz?ALvp7dC z*7V%~{uXV~3?6eC@>rl5GH^K7TdXGKk*DBSyrvm*Bm9bC^EH-zm$A=jG&!Z1zdlKt zaa!}JycG!Ol6 zKlUXzhw~R`w$;}|UR^Yg&~;ejG%tT`#<}i<=D<7qAiq@2!Tj!s7aBC5kHLOp z5;R{B=+Qq`%`ZzZZ!0=z&Xm^?;kNrVzsGfk+}3N(>#?sGmT4}$1bzG_N%MEFGeqe3 zs8$%V4036sm4AOH&h_7FmH(jK##pUt)-%|*f6!`NfJt(#>2b6h__4O@ZtMfk=WDz5 zI*oPtsx~1B{ngCU_WuI(Y{RrSSO1B9W2kn}(oeB}{j43*>J;qYdF`;bet>=JqaF5# zlL(`BYez5YNJzt19Bzowj_D(Z9owSKKE4xiy=S#KwHoXP@!Firg;>`Uw7GZmgFSju zJ8>oYU+mUSeo6s<{~HdEtk>G)7=LxN*0vY;4M(*_UBKUK`?N*R4TnFIt}TA=F#OjB zt$ic>p=N(`IDEL)zI_JdXw#M~>y3CtA8pA$@Vj1Lt1a!Hi+!xSw)716H9e!9@<0#7 zZ9mewQ^9w8oz^or2kYch4y{YH)s(-F)^d10MLTt}nFt$ewbM52CuG4=ZEb(Z>4nd= zb${LqKU=L`@B{QM?hftUM{dQv-Y?o!ozOmMk9J+!M%<&_!eNgR4*UP1-Ed$K;*U>i zH$EN<|79nKM^)MfN}xZtjnZx(4ZZn3Ui;YWPKbMa&f&3W?c;Hkh>w2LRr~sz7=LD#_JBtL zKY6hBoqHj7OM>>j%;&*p8G}O0UfK`8!Z^ph$>D?)?TG=mz@Pg|dm;(zN^<7Nxz=Zz=qy2ep44gniCV)c*B1__}?I_TRg!a4$8H!<1Ka@?`82 z`Mq?CwUF0?Njl9s^mj`S4j)d@X)fUJGd|Yo+BJv0oU7AUV7^+<*WJ|9gL{(2y2QK8 zh?84&{o5bG{_vnK`M!&|7d7cp{=__IZ_o|@5cn;VbZK8=|J15Krb}r{iC`ioapkI=-r#`WEa>i!XH3zQ%sn=V4v# zW;fz~R^9xwXqS6XS3fTn`%qV1!?#8vOr5V=G79|}-{vs6oo?yp@OQg)(XB8zvCf9+ zR(85fNQzvyD&aQ7&xY&nxx5PdS99H3y#x0FH|iexxGnAtPU#+|csEpX=)TC|#f7@Z z|B1sn`BUAKpTbTyUCLp~&$?&YEQ6nYP`B5Ed0V|m_xh9%aXwn1+xNlUpmRX?b~@(g zwJy51-)e^Sazb~|oP_=VjPB5juzQvg-MjH8aL;jr?!%s`*k`-yKKcZ7?zHKSKX)4U z(J8twiZI@>@9VyDW1Lwx>b{}$KX{x$Atqb*eJk%i~z~RKhdi9bt z#6u?P4f8PW?1}p5@6AN;6zZFvho5_Dm%jO<&)~jezrMw^QSdi2^)2RO|Ec*>-}1qo zxKG=wH|;zDKft6Bp4Emc#puK6fKIvVw%lCNUj~w3q0Ed%5=5Weg9Nzgfhl~4i zxb>)hsAneP$TRe*b8-;38l+GA3FGRyN}qWf`qRqw+2fYszWxpdg%)LiJE33kdP~9s zuzT5h%Sh<^(iVElt5|RQGxYhV;lH<0=<~ljhx?u~eZlJcaQ}0^zG(6u+|!KFm%$E` zvH$4rxY(Bt~b&HFH(G5VUhXR)7_>hIdHi3m3n{gT%b2svD%UvhL9_N~tPW#7Y2 zbR4f=@e26teUZbdUU<*X{P&I9^ecZi;=W<4e${;s0q>mtp6{VAebYExTdKeJ4GrdD zrGCx4^@Kd5({KF80=eF&zrSlS*7HyL2Oa_a>d*C$E>dCNJFI_v5cFl%6#e6rpFX`g zv{!OCZ3c%cCv&)ZD2MO5^-sj$Tp|3S-*p%C>(^fT-A6m%eAQL|yj2eWK(2pDTMNCK zr+?`w=zCR_evdr?@uX4u17*;Qs+0O7P0{ZJoBsWIXK+vQtp2Mu&~N#3`fuYf@7kyJ z-~Un#Xx0DpIP`k<%lhA+IDzw2n*Pt3XQ8J}^k-M$_sX{VOBb>3+m-469q%E+ywmzC z|2T0kO$=o3tHdm|B&pEoE5+OQ7J8Wg!W-%LMgP<%B9 z_oW>Ss*D8e|AP$LgV;}cTr_mh;vQ=9Zo^HTz~_3m;ie%N_gmi?;?|=d&q+gZ0J5^6a2@PhQ#-W!{6*-7|^UA_&#A6bYKr5f1NUnC~bms z#$>~ok6}L>S{pJwyW!9FWl(6d#*p(8$#bsc-S{YxMPK(@;<+E7jK@277tRR8lD;`N6OH75Ms{hFaBek=Bi9fq12zY(GuX_!jey&uKlkE0kA z3_A={XKlgXdvo|>6@!A|W5djXokU1@*)V4(=4btQ!~C}~Z@G_fSa7%DuB~x6#|$+r z8~rH!?Tv=D`wHQI78o9y^*$k$j~O02n@z~&J%*!o4(x(FUi`su_}39cnDd0;_(jOQdxGKf@i;(^|K6r zwa2{G9biysbJ6fuSBzUDZ{?gwBD$kioYMoH|lS*V!m1%WA4u(r0Ys! z?A^y9_e2g`y=-jZf}Drf%XBhZg{<2{e{Ltf8N=rN~n!o7WM^w>@bh{u_u^Dclt`^o5{{ut-` zrx_HYdq$V`Z4SS=INCway;1K)SCnl+e6US)v*{cWOa=VN_$Y8E}C4tDGtSM=-w zors`zM93iZ(Q z+oE69z^*kV(XV%`Bly4Q{hyB|LRm@l0r!W{=iVG%cs2Sxnji3J_vo+2qW^iZ(ciah z20!KJ=pTk%z^9kLET5PMT7IqWQdnb-&6--ODLK30lbZUBR#~I!9!Zoj zJh2a`6C5b~H*Ij4r=mQ`GS%TJDswnXO&*uYQ)V|=tBV~jQ)Rie)@Ci5Vk)-RIEw71 z!M3Eh-h+GDk_Ow{y^^MuIf}|mcT`t-Og4LwwE|c*R!6zjR*s*X#ilZAm8r~8T4r~f zD&6)HyW8$8vL_7g#d^dBPISq%myBvpWwl43awrFvB9B*-05O$sF4astoiTxp&PJFl z#+`6}mYpb(SRbFnBFdnU%OL0K!!{MW>{TYG%VV1Aa!*NMQW#+^FQ_j@drgn5*P3^@wX_IZQvAZEuDtS=!3cqt)@6KVRrp>Ba{Y#l@M%}t< zk%lIv+*M^asAG5;P&ao~<9%u~GxBFO?3wK} z#f#X+Oi`z*5)u-wLSO~Sx)d~CRaUj*>cf?n8nQQwovJN%H(d!=;a8niw&MGeq}qWJ z#4^`ZQ*wFvRrs`jwPxeArBzRkpD&^sl8ew`mBZ#JcX(9@C30jl*f0$&i`J_g$h7QwIRb5%>!jh&Y(PpDV5l*o@zHN zER%bHoY?xlnxK+q51h~h!|Aq`ESg(Wzv$#NVO&|FZ1Q&cJJq55d1f8|YpK2X347A= zPtD!378Ja2r40;PqNo#-lTB{>oz)Jvz1URbDz+Dy995+wXSNnNz`ATT$l}FzCeX_iXE%K zZKo|wS~kJu4x6YfqN1>s=3iIWDybMMDLS>cugb7ES4cSTkm9N?FJ{XcGl|(WRZuCL zs=zVak?ZQ9U_(ZFV;z*cV0Qmw2k~?SHp?VJ%@*|w5@l39=}%LN^13YCkukfvi)35_ z{o`^~!lH1Gjr$4-ChE+1{RXI>wH$`4xE9l5s;;`uF;kX8#@sHb^Zz7Lqx~!UsG54` zikUO=8YCl&O>@>*%N@nuDKdF#E3cjB#D)u0P*ilzqj`BtqUOz8`{&Ac6J@1j;%r`R8!j*ZSNt)qcO2EQSl?nF$Ea9X2h6zZDR<2NNO{rmcCZy!!;hh^ z7!Ct*q)%zLf(_<0aXd}qdiOBJ_3>(ciNncv8&y_c>QI!k-dmUrCB|t^7!y#TJMF?9 z`Erj^q|qw5!saNgc2(1nFiK_E)V%vv03~_0X-%<+r%bh%+dXzVbX`{8RIA4dPqf_5 z`jlmk6x%7_Jy(TqCNFwF%Puxlra7zN6Ne{=n`(5#&NK2HcXb4MC1>rs#CFQu%3>_l zu=Kjw?>3*O0wLPcZnnDYL~41t-Cg?Yr23pC^xty~^sgel?s2`fBOEyRP$OC5s&>L9 z;Fht{>M3I;umu0?g!{lujy|g|ZJz3|mb*&1B2WR6E+n3$lCC0MRlHx4p*Y%{c!pt? zU_`~6nOhawT0hNMuz|JD2xy-%hKeCfd%E;P+AHESU~a-=7*`(7nU!N;IN6duRPott z=;5*S8DA8PXE+uKjw0Ry?<+h;Olh~GRoN|}wp3oZ5-d%8uCofB7T5LAF=voW=x*^Cz~d==GeilkE#8Y8`u$(wG$_<_uxA{Ny*;* zPTcsWI;zU3T`6YEgRZHLaeX=t9o!3zBMg=LvP>aOV7!}zZ3A^QsS;J0x^(Lr9y>M& zJ0XBVw3I?ZBpUJwg_Apraffa?3{*3&n;?I2f=> z;hVDr-$Hw<+BPciqZl5}uAeyKUhm`!0%|f2)Y! zBn7)8wr#V0s%eC)9Hu`!w%mTYRAOmh)gq{;+NUF87aG2bG2!7!s~f(pdvnp7<1ULB zx>UOd!4%Uthka^z9C^)|Nx5SCs8mNJwgcMf&<^gU%k79XflAu`N*j@~)`w9$Fajg1 zTQ~eFHdhRHyIql3379uIRo?Irg&;fBQV6UsZ+tQbHZU$ zpCSUby7aWIEL@|VCS!*^}er?#h`b)9O9EM;fU*yXC^NfSK2f zb-=TTJnu~@fAgcpon@m-3mBbdtjjgU6z_0G7@M5RRAf(Xh72Q&#=Z+HC2*Z+ueLyp zek8hmiv1Y;h!IzSUV`h#)JrfUEuEYuX04gjJtB4&li`H(>s9kwQ*~wdAS{akFd1l)O8UhA-BL=2~V+Uk%sO#v^ir->K7U)n#opcijTYv0iP~+5nt*h`tc*% z0N~RxiTG0Q%#Yv5K;5-d7K;N_St{*CaCgIx)kx>Arhew%bzk0lxoE416>F)jKzNmKbla)T``ecEjJOGtiEFrTPYt=#m-7bU#ujEP!m5P8WRbR%s8PoDGVoV{RF^B zv0rN8NwuMT)c(Dum`acOr(sCONl8{v50wg*x~o?iWIHy<#e9fF%a2xwT2R^b5vQuP zlsxr`z^T^b(#G|n^AJvMRG)(6*3?gg8S?O>)zAHr1{e@u#{WbH^eMOibXCCId2eB` zVWe9f&OG=`uBmLg0xh0uEJ6|fT{)<&vG{PtgoQh*yV!2doG`^EcGDi)uA9db(OqRF z;;*oNRP7MaV(w;>tiEQuhhEHOx?LVuk&A~oA|5khvihQ7DdNpll4H2M@ZRb!Vy}wi z%1XWsB8-6$hO}X%<4b7EO`kMu5lO03?IqUgau3@^LfaN5WIrmlm5;KQGw&s|9X*bU z?PUB2AJR%s&rNLaNRe!5igp$2-4%e0>}Mg=AwkOFWyqIkhPZ{+7&pohi@-;DyB~thp9*@w_Djy#KzzQm#e;Z4o|s#nAOcRT}|6f zUu!ujwr#@NRxwS*F102mSBZo= zi(}Dy3@F^wv00zAS*=S@mP zSxWLdO9-gbt5h2Kw}C4EYdr2pHQsg zDw1;9!M2!sqnuYtl`azVz!K+*HtuI93*zwOGpjv_&0`|@Ad0+KUG56*Fa--j z?1GN4kuGlVb>SU4jHWlKATn(=4pchIvdE}D+YXzHSQfOGMgD@>p(xq_6r2h;3O{`X zBgm--A<|b`YGGe0!cC&KrGgRX@Q>Qd3(oj8K}e2&N+ zw+Zcd{&SX(0{p|oYv{Jr?qR*MG1I9HGsrM~Ww*>?E}}TZ0oTx1IU*)>g#T%DW^IP) zx<`kMrK^svW2hv9eMNDUw_U?1-S+EOqfVhba7Qw%R$m(z*cYx-nPUUFSh$0(F>&l2 zL&uJrGj`j|(9Mi3Co=KrESYnG|?MFxqgeo5K zJp|^dk_NS>-WY2y4GAdXeQsG`>!xO%nM~oa7o4?mF9k%!Dz7YF>7w>c;lA zEG{IKa8FN7@s}>J`_Fu_5^RqH7rG|wbW|i^@wMhbr33lxnApE@6ulA^FTf(=>St%w zeNGQIG+HWRH}g90rfMe)R#6$fFN{c{6>@-Fq=-yG{*Q}9|7_1^3TcaGeYteFKbz$rne0e2g=CQQf{RP6Z0>PwEV+l#r(~p?;(4|byKV@=mecEIkxlOrHKt7Cx<}T4Nv2g6BAL(D4OPlCRL1dy2g&*xfsC#(wmz06ERB7Mm$^ zT&1Pl%xJO#+NtTz5nx(FPGN|)s`xwm!R$mH9$B|>o|{Q4Sz^eW$0rxFgfSj0 z!8poYJn2=R#eS9q7Gm-)mG%&+NVfw6HUlJL;uIJeyJ-*?(v8s=@9n-Z0>-*4-T{mZ zm~K`4NO~;uUMvMOZLE99i-kadL`hgEAOcRz`a5%$6mIj`qW~<6)e`~BXx{0?85h*k zIBR(XoK{e=a^ypn5$lRJD=fb0k@Ogy9A92pW;J2ofkBT%$5{V`ca#WUNU)W|%Hykj z_lY5*nde>-#k$0Wj08zBsyaRr4hv9F9S~Jj?_CLuI$z(x9YqRKK($>JHkWS+gwMYT zY7}_qC0>pNwUUL)ya{R(OGCYgUzcEsyRc!K@_R4!CtXFy^&V&{@!-<31h?IM8;t?K zZhNrZGjcks6H0nbpDwv$jiD5#*pb{;WwKXP@(k(lBzUeA3)*H6SYcZ24`Q~UM5>+4 z%Cpc4vK2v-$~inKJ@sFT-ZO78H%QXM+vSQRXru<|0CWg-}lbx)r<1a#lQj|(GN&X4+yGr;mDX=eT0AG5d9@rVl7%1^Ay zj%&1P8d9ZWipWo4Lcs>hCoA6-NwoBnu+baz8mrskbL-fM5F|h(l)ENW5_Fet_{DNs zq|nw+!Or$!+%kCJJyal(R^&rMg}V#iAtoW$K#jZ>h`yo5q* zFa;<4`EV>SiBc9CcHyE!dd<-~m;@3rT<&7;EofMQWWAZMiX;%csj0LgDATAw6B$d7QHmgfs-#re&r-n+AcG4J0#uv=~-FOCM>;5X}iiu?X>WTQnB@0Q3e*A zu^c`{7Tpagqx>hPAJpTg3CzVT<9`$oocOt%*hMrw&#D~75)^~5TL8Nfn0DZ}NIIa0 z(h+fWxY|R=IvqKSEWRx1SWeH3VncbV%gK%>2Sod~TX-RneX9^qynd}|~LQ5gl`#Im`=@x@a{ zW6MZ&Ky-yFOn4G<+kKL;s}Qj-LU=877H_^qc1$%;=63t(kVC6>p~iXsaQDKe2@Q4Pl^CCSOhm}<9GmzumCvol*b%(-WCX3=no1XDi(PYKF-cq9^@l0TOd zIad3guSMW6#{O0LF?zSc;z7NMNyKdHee~o_NtU zgUkx{s8&Lxm6r(Od``G}jD*7(N7S=w?1~J+2u8GAxBzOrd)dlV? z(b6cXI3n}J1bQv( zFm+&$@Gv>_$q0QzuxM_{l_Fcg`~ZisCzQkYP>WAh0`_Y5UT&(@iKC#FqmmGW zYk5-=f^@YfB_Rl1yusmiCB3rNXMADXQd7?-YxyT7z4)V#py|4mMS~G^;A@251+$BQ zkV*5t^*}Jd>a3k=tqnhQF+ndi{P)+P?>s`dzy4<)AtYJ_zHsr0LvoM zq<3^w7~uyN;XOzQ1MKKdm64hZiNTPhf4Za*PS<c`bwvoWmUcqDDap2s2NLud z5>1Qoy{ibpyQXIqAz1S4^ySCJA*n{V+*7@$osgzidr1+3pe#K-RVNvRnmwNIzMTkZ zt+h3&sc+akV{Pd`ksn=pEkgMf*vxs@AQZ`ODn+EAXA~hg5kjva?Ue2T0l6SCnTQ5q zpAdJ~usWhGCCiW2)aNDI{SOoj+4drenMpSnZ(bsuQOT|ph zyC2$^`kE4FNx_`Uu#EqwH2u&Hd3umI65Q&r+@P>svMgmdbR)?y5kY}ndgL(LJcfB5 zJax%`v|%`wl!Cl@^8#?jTnz{PqzCnrehoM|K{z>$;Harv6u_Apqp{U`-|~eY&}8H% zpxzKYi}^MM8mjfZM`uqTX>Fpx2(Tsb$Jdr`^IOp1Da|va=bD1N8Sykb+HA<_UaBcm zRlYDI-f{tHj-V;A^e&Xnp{XFut?C%pyQ8Vd>SQjWjb-^3qoNK<4^<}R;D!_xNs#bk z#dSWdFGNv#un>x=#6A^&z&#GlctB+tnr`Jp9foRWk*At@!}Pw`J*A569^uEV3|i-E z=^_u0a&70}NVs?i&mB@xXJUMh;HjrchZkApBAlip^mPqpEIej}w__0+hd-4^XdM1< z9-*=MZ>#^EO;oaz1y2lFBaoJgxPz4zkYGnL^_ro!0~x*ScZ)JrCcCXRUdSd)d#!oH z>}3-Mn>R=>)X8pKH8`x^(`{%U1(UKLv>lLOsD{~{rKny&rz=b+@=ZrGEFwdSVX(OD zWEHOI%(arH@?m(H8iA;K(d?CnCd5j(P^Z+o9jHrH6ahnS87-xqYOjdIu+lO*fDgQ6 zt#FtcVMboITf&Go)m~$DB0%7d)Pc5a@W#10nn1CSw7cA;k;Seo)XyC)=|w@WrX$Hw zYdMvpu^n*NN)Xf|tM7n;@I+!tZGUZrv&0#Q;jXBjQWg=TP@mDO)GonLj z*;QMk^E+pEmCS-N4WW(5GiE<6p{*Wmt+YB3q>M1X>b!k*|C{uj1Vc3j7u(iiYb1mv zH$(ZQDx?@whEhinn#p-V=+aM z)}DO%42kpS7q4B9e47=6=51Hr*y7vCE-JnQCb#}X?4DR<)Jli z1T=R$Y9mg(<&>r6l+M!T*|dCEgfXgT%*n8rdrF!&wKyt}#6=^$rWBMAY(yzDzsndh zJ5PeEvN)V&n1BeK$*G&*7bsrh*?8_x7#XQ8pJsOrFe1n*$8~eWft3F?vno*GbCB1{ zt{uaXFaOPA8;2Lses*%~r~+0UfpzVM@(Ho#llk2PFv_g3g%L26<-d*lSJGOZQ)Z21 zY~=K@s>q2d$6-UUfJo~^U6&j*WzBNjRy_GZP6A@7jnA2K>0*m?#Ceq}GS%%LNyQ z$Dh>tS&U&+AXiE=AV>KI2^BFrIU=2=sJjX(HT9HEkeFIZDY@u9NH}4|`W^^Jm@3~( z7BK=CajIg?y5+Ozkt!^uwyAgyM9U#irDdUfo_!XouSTD2c#5z%X$F?-j$yD`Pl0nI z%F}l-B4Rc1VFe_~`)7h>)d%&YWjJBFiS<2|2|L7gw2H{Jt;v|084*@?%vcxJbwnYn z=>P+CnbrXH>1^;yh@~N<$VP;Pl&+0oMk(Utwh}2dI(xfJ0%hHB)a%uCF>E#Q!ibT$_E zLWR3xH?DD6;FhX!I3m}^bT~{k&9!gX((szN1X?CnBVyz9c(eX}>GaHMDzZj-{=+^Y zLGx}DY?BDwVj^x766|ZY@4-md_7X>e<+b0`W|J;7Hb(8PWLv&bVlTaKc}!gp$r7z_ zS2|e|g8$X{N=T^bHWjcQj5MHv_3U<6S9;&LNZPl{X+o=0ntLukzHn^T`f(@n4fgYv zqt!PA(BPN#?3RqKZYW!&3$^^{F2V~`1`Q;JjKced9Fo~^p?nx!Yoh8j8>(dEZW{b@@BDRGO>cJaL! zCo;TC#hY20mSq_$R`I3Q8@aHRh|JNVwn02x`<5Y*<@N3v64YzhG$gI{bVH+3*|0>i zD%-J5##{6jZ;}JnXwdj#dD%{%r04FNvsdE6w)Vv>*<=-!;q5JzpsSdL=_HHO@Sd4U$Sk%jF{xAYdgXlAH`)5IpFai#{t2FV*alhb~5%_Cx)P z!g~U|gBDzSXmT9${k<1BbabIa{^O&Y2!#I2^O*>wvXv{-1DSJ3`6`oZE4|u2H zC4{VD-vb!-Zlvhl<-gG^!T@3&{neR@?I@0dXdk=|Bpn1k{Rkz=XW4S6n|DjAH^U$jo0#sz!2351<2g&;`Z?f*Nu^B8AB9sbahrTqUQ!na|DWPii?k=eI zT^Lf@(v&rsK|6JmOuL(XfrIftH`y?V#{6#iZRo7j)Kf0R-kYIB5G|L5BGEJnn}&s0 z*gt3p*XFJUA+Wog~(VAG2hbM0IVVjFgB~?MBVtGkD`q>$3{2QgDB;!e%60}^jeklkn3`lutH%9xW8^xBIbIMV z{j3r_#nO!y)va$`>3>PuHIsb;iKpxPVtMSw0;?1rIhHzPN!bpSB&)V0_G7>~PeZ>0 zLaSr&4>^fb)tRP)u_&%D*_!&SOsjBuLcI+Bd7*^RK5nCwynVE%9|SSqC9T3ycn`9> zyHI68Z80bZ`~Uq|&7K1M-k(eqc^E=@;Qg@i(0Y?}3DN)%vJTs6GJ&0E#a(PB+jUMR9whW(|<3#r>34hqH&KZ?UA#@an<)E8c&Z}q*4u-z3s z^|o-b_uy|->HC`6i89W(KK_S$0}cqxIq+#8`uLxIMxlqP6xz`-u5ZUssW;8K)4Zeb z9v=Lo9;hVm@J8A@Vk7i(Pd-CKADM{fqcHk)ZF@za?5_ViIA zyWb68i!-?SRZ4LNH*dVcW>9N6y{8tZSMoKOpmtX+#2M7yTTFspXZSygB=&WPQccijvD(2rg2lEARtSRN=9Ffj2AoHYl!Tc+GZL?WBA{Ps6UI$xPSL}< zDxp-oW1&GV$^yH_^>2T%l#(yt#dz^O|Xy=v7%Uhfm~@r zNd!4wtTKj#h$KMb<0OO(-7jog;f!?_r-qTCw+Xaj6XLEeQ@Pb$8ZbS6GTs5vICH=g zP*&>07Z~>C#75*|`RCJh6aNSZBQ>EyrPqUap6b7U4yE9o8eX}JRw)aRYfDPSTfK{a z-XT<3{DTRg6;cJPgM=2G({Po*uEO5ZROgBS_F79wQXhwY=BzOWTfrE^`SO=33#p~n zl~QCzk`0S`(OyQw6;uo5*E^p+O&67dO-F!^OP6bi2z~h1yHfmwBAko;M>dBSB_t+cX@xG6QpFmOHbA3cfmk(@*{NH^+>z*)#5PWaOfwsnAeytIZ!C#Y29lo>ToDw9ZfZgzB3_5!n#VDXSj|;G4z&*K}luM zJCY0{6+sI_ULL;4Ntl*KUdx+_X}m;C$RLmR7a$LVsBElYd6@R{`JY?-)t%+(cBePN zIApHD60QBsSdu=#)}%Y){bkO>bODwkmqicLULH`_Th;g^H&Q#CrrbqP4fzV^f+6CD zfj5A-|by3;7hv*560)X*f$fxjD=Tqly-*qe>nL?>@Jcv zDYEF)utg`Q+k?owikAyz><2Uo`>iQS3w${MUt~uJL?q??9($HIYuZ~a!&e9@g7WIX z7%R%*Yp17QHmZAb-aJ#h86~hIYUna$cnaEiG3N z6nE5kQ=oacvT0U2Oui!|W@*fC!|`Z2Pf4mr2i6=3*Es(9W2B}kTz8{*CwsWjDwHIT zWwF`pMk6lvyGwh}!m}&BH=jpkW}W?Rx-4tzBXpYHc&GS&g4M&LMjiwjig>&i;ag|5 z??VDK0E{bnT3&{2C5`iFvV2PeuH0d#r6uT5xaMe1j~u<3O#f9?1lMOD*S4=5}$o&lr1%_FM|k{4&WQZ5Lf|1s;3OB3H(Oi)#!0r(sb-Ei=SpFSOO^ za`xn+YLq7}J)X~LIbn$8RxKt2w>PMj0N;@v&e@WW$j-IjhD9V1L({2f`ftd|zAX|$ z*r$?M{x6GodcR)5FW4fIG|~c5Gz>?-dMWu}Qac(Z@Z}VHqXX6&6cqB+{ftO4#zzq^ z%Ta$tBCl3KG%J0jRvMLji$!yDdR2F!r4I6LqgIl?SQn@BCQ8*tztk+{*JmF6(Zh%g zcPO}MUPhT__2-dnLnU0&i?1v?|VA<{S-?6kPoL&4xkOhzP zAB6D51P|VD;f$#gT{MTnm8>u9Qms7O1hw{ja8wd zNkZ4K?ATeZXsdky-6(1GF_FIHXz9zm!xwnC&(tX6j3hPfAtWUc4r<2f7k#dQ9t-`@ zt9y~PX#ddJm3^b^T-yaiWAn^Em;kSaed>TJvB(J`C88M+cW9sWYm}`RmK1?AY)Bq> zOkk!Le}vQ~%WLfEC+VxIQt;ged`k;osc`ZSc66Zkx{M^NqjjYX{Qx^ktzuRKYMj6z4Y1 zmqyGg%6aqd==!2*YUTX4l~2x9x@^JnP9hJgeIEU?rFT?Rq3NjL>Rj`f+R(}OOYTaW zFcaS)c;Z9nyj9Sgdn%<<-ikgH^NGrSKHTK+NuOE(3>|M zmsa6J0+MfK8hrYdjlb8jQ)IyRjzaR-Y1T1!x_Hh>6>{jsB1B=RX{l{qxFeu0aZ|rD zT4Z$=;p(0pADRU4l2%d4zk$i3qoG;6{{1HGy@xg{BPH$se(MoThDG?f2OuhpB#Q0d z^{K%QMrOMveXl5@N_Ne1SE-A|n1Zp``2Wi#M_583*}js{H_P@7Oo(JO5H|BA`m)>~ zdc$F>&6j(WG<;N3FZm*LXUVkCbl4(Sd36P{*5E7JSYnO$@@ruR7)g&xbS^DUqycC ztwbn{i|fAk2$l|`a{XU?&}C($4oi`&qHDeK3qdqd&zbuBrdV1MkbWVFhhb>t$m|E^ z{3|Yr6u$;}-F_G^&I0>NA+7)I`$!=a7J{=EBlo3*mdL`}3V8MWD;gmzFdw*f?i5?d z*CHf$YsHQ#=D`PkF(N!I>am2-lIjOP3|xiOe_q}pOwlB?41ADa7z(In;|l>*q#EBC z@E}!WAaS$b>6ZhLI6~*bwiwAx7GR7elh8gF7#3h><2MT)Fec-_G?HR!PoJil2ht@l zp>T5NL|MayvR6w_XH3Sekhd@2eA1SZlVdH@9j?g(2fFF48qEpuosZ}xTW4HMPfE$n zwq#^avg9P^q@{E=A+{v0CzI8K$`E+KXiq?SKUQIveZ`2Dm35n_YMP4K=Sb)QvBXhY z%`f)pV&=jLUPssUk&o~suG=7lkYQ_xUWJM(FWCjyHE7rYh|d_V`RgDdJ+l=+doCq8 zMtTepIgo5&{35m-C*sE02(o7(6nq9PgbQ&X^t*u)9waAG&I4|AYaFg>7GVmZ^55)Y z2pL(yv!W2>qg=dFohple7>v6^-WQ`LwnoyJx7Az3iS}jm1@KH#h?`LH-m`17B85#$TQjETn5 z_$h(C@Vkp%YvQZyCXz^xS{8-KU{}%2V+Xr|CM441^NTd{S4G1ni3ruOr+>_I3m9<= z|EVYJIrJLNivjey(Of7hKl-rF_r6mq8`SIw4kq>W=1D~kBuO9N(Tle*(xREyID(qB zzA!_W^HmFe$>2RGGCDrjI$#k0_w!}|xrpTqGc!{&D(OC0<*(`~lVqbP@SQQ9eiD-v zt}R1rW_+b8Tz0z^b1qr>4f^eemapp6%|71+C7(`p)kaTht~Ml zhQxKNsW#3Ud-?BH$hy4}YR zGDgd~nN=_oUGP|>LXtxelR~Ru;4ufSRobPff+dAOv+!XBi``RQ`TvT0^WZwK>rU{A z1hEkWDT<%A_(D zr6}F$bWdlgVr9lPQ<;kX=*3-bCzEb3Nw>P}$)w{<+8LMAp7dBMIkDsB{C?*y-~GP# z-3L&bsVSB%68P@D=bn4+xo1Ca*NLl6(x{ zqWbgyci-O%gv>z+qsv#KOXUb+-fKry3+?35C7<1y4Lev=v@_p)AU7qRaLl%~U{+rH{R;uP zyo1b29*?l`BKR!fK>Hl5=mIjtnU=gvIlrE`?JTlNM!^2c2+ktwR874rr#1!A)H$`T z$|gEk;t;e$PQjc^CY@(>c}S%>!oUo7o2=NBv+=9+d&$&mCL*$jdo8vLqVk zsL^yi7hk%x@1I8~x)fJqcBBYmN@4eLNo-aBQTZGl;$V2(sO?m8Mjih-xeK} zc|S6$YMS?L@x{`WkztjylT(WhD%Q`dx*K)8#g7hm(74LZE81f#X+TN3{$hVfySBqt z;6 z#Autu52-ZUqp__y6F>EIwMzPSi9M~7hWa{MC4QUS&noHDayAN!d>-j$l{93jy{wYP zu3>7EN)WpBVt3xr!#9ctS0%ie#2^}m^MjHZv@?m*$;I7`T}Nb3wb9 zFV6qRSoe`#FyI?swWnDO0yw8t>aT7WQ`OxyjVHm$z^vhFL%ZloW4DtVKV?7`HA+-! zuTn|0ksdkwuxix7V*BX4UW#z^;ls(J(S{~7C2My%Z)RzYU?_PA0sI`E*u&Dn#~z6k zz?Yxf<+mOB-0b04>z>GI9NL8sl2>8F&PF@avew4r&$jY2dG+_FS|nolGXB+sKl@V$ zQh`WHp)9brwK1sO-_jIZ4w{$9lhyZNwHEx1t7}MN zYd_f96x8lH(1NuILD8kd^rvO5&B+_*(#^7T3;s(KaA^%j!P3n^ZA)__mL>p2mk#rT zm$mNpFTGoqZpN7_Lo1xxP^YMT%2!_owx=+a@;t7WY%$xAU-p8}Qq`8Z44R1A!EwJ|u;0tt|koi8vv6;C}k7$no+XSHZYk)N11$f#M)Hb#3CpZAAD4zB@OYikBO$^iumI#Ep76L}W z(tELV;~s7u02Ez%pR@G7+M+G2a3$JP27u4?Kh2ZK%*WK@|yFYo| z%~+Q>uEk2c7~HTx5LwetBW~_>(i!K^Aa$MGWz`rQi3>Mujo93dje8Hjzg4*4@ z1z6d;Xl2h6S>=NbdC$t$u~C!|nlTo^Bx-DPIc1xNQ`W$kuQ(-7gMUJzAbrM9=b<+6 z%BIFf-jJr2rlPoNbD3qEhgog~0E$`e!{UZ*SYTopTiXV9xv!BZ6Ck`uE0t-(r($_q zlLrHV`cfYkLE&+=BOJooHEP;|{BC^RntTp-56@hR1FPO6NayCg zyDq_A99G@tW!3mhZ+MUVO;Mv_3k~pNu&Uv=+X|WZu79}Er8IlYVKQMdpB?Z zfC`o-Gu}f|BLGF0b{KD)hw(mzr48fVXJ3M5LBA}GS7I+-g##8N2kPvmX zdo9T|W9tbLD(1lv?w=~OWcJN_ig0_W=tM=4 zq2ArUx+F#Mml#>eATwx-^r}%0rQ7=BsEg$cYK*kFT`8-CZEX_>pzrT4q^|wG#r}%p zlVhV&^tJHY+SGBBT^a+igug}A3LR{e8WE;)`vG*?Ah|uJU_B>iv zCDY?m0?jaLT#X4V)G|V5tzQn%A+cq24?cGIdkkCKWEHSeMT6!Qse|CpcV_pVVvN1> zFPu{Z`jAQFK_3gDF-T+9qAvPyc1vuYNyPok;(r6Uf1_w?=(<%l#%D#I1^t)W%Tjn)0nSTQp{V+W8k}AFyY>{#1s|RL2nk@F~2k$0p|UV~FQZ zKKjPOi3C%8xea@2#$$-v9>dhOU$jtb>1q>R#7J?t_kY&hX-3BA~6S6RNTX&d2sNLhiq7#Wnm zlMOjkD9ObEd;p%g9wL zI%_GTyPU_i^7!a9a+9Xuu`N0dVeIF>^7hA)Qy%7Wd+> zn8(~Zs9Xh}Is1dFeJR_6GcgV@eqc=U`=(5I92L7T==pIrXk3@73E2ul=FL308w=CD50uC|W9+FMlD^ z)8PR7pk&Jr2=Dr9I0d7A-=3Ra82!8h$3~fmz6M@yhMF$o^fhrwwVf6FUcFYQlQQ6l15#=25*~c%0h^v%Q0YlYDcK)Fy{Xc#EQM*{_ zk;y3_srZmmGJa^yWHxd$ZE=8#s$GO0Tzm{Tap~- z*eCgYB`Kk1`?5e`CXC$Mr_`t=)eg8HW7yJEVOBfVn zfklNG2?#0o7 z<6NH78kUumyQ76QheMS@tHvLTgym6<%=yxDHxj1o?09LySs(O`HUvPC2ZXgGI?A*H zI}|Br>?%!uH56_=*!qoc_PyiKW?dLHi%m`7iDQu&)QufQ zC^vB{Sz0=Sm)k7|@1JC5v+(=KB2*=0k)OpDsgEs!M=@y?ol#r3%KG%TZv833z3aJ+ zgnlp^Rd!<}&lowHgtBn5b=e0w8G%ihYJ<*O4U>Dl6IF7Wb3Zw^W8zhNe9-b`*>}M&SoK22lQQK_MEj~l z=h$p2Y=XFlpp;LiE)p7E5UN;qH;*G`*eSLd)FNZ=qJTIzo!?>nn9;dQScKQk;Dp1i zCgDK8o|$nqwB*Pygc{GyjI_-mwsAtq6}KzW^>)@3M@I6h$$V9J4|2;VoiEog9)EtJ zulMP!t(OByvFY%oPO6UM7K*b@$|lp_R!}y3^9z3**m3hOguB zvB}AcIkxOtWb_-~JhLh?`eBYnnr$9+@_4H}i?31Tv(GfKd^q~MpRjv=SSO(&sSPFy z;GYGDbe@F+{Th{+(tYvPpZ4sfF~m;rkSWnIIe@P0%JNaL`KsGb_cV5Y;r0*jboGQD zueFFo24?_UVtZu-CaZATDBAk3rC0Sdp8Knw(mP*qs_?9p9tV&^B;s^1kI{vzGDeN( z#u5t_;0IAIN%BmB$$^2nY4D_ift6@EzkYt<+8;WRoz-Fcu0WR{iUEpXLzXd0?%M+; zUl<{aPO{1<*R1YFA_Fr2o1LUbPfkRb%a)iE;hpLJ(=feL6=p_+K-tWQER2^kIctgZ zPIlj!ZFZ)3z5!FrA~h(T{v;~33%mgt#lo_aW~pZEtpDIx83uB=bjUFWw@M$Jb8a7@ zZBxQ5AMNyg6W#ye`(|3w*~f|jC(I>na3kp@<;YF52_ z=J4j7J)F;&B%+LI4$!d9BfziNPa|7bWi+mJ-=gTU#U*d zi3&iv`-kXOXfq`o`t-9 zF%?9l|J5vuGc-G?WNRhoBut{wLkW*tv*?i~0!F&yo;=8r@l5r9vw^~v9lwgpv*n0L zTg3+7+sFneSFbv*9$B1&fk&3Yl;3?_dIok6Zc5xX`?;FzkSu0C~yoB-6-~!dM z3X2a)QwXS(1qBHGv-tX4KzS-`$(1mT)U-x}0h|I~$;e?!!wjJ;c`u#jvup(O&k_abc3oGv?rNI;w-&4pC9i>0|%?8?xVpkoJKLio& zg-Gi(8rixdOS$;P8a-&Ar`B~;ZL|bZS(bXjqW^&>i0KOOKbZRlwC%kVVbiGWVLw{l zs!GepJ}b#q-*%F%SXC-vvb6}jWD~fH2pX7@zvb=36&xc?^b!VE+kvxm`rAQe90Zjr zVMuvr`mOh${q+l>6|54yR%e2?Nw`OozQ4Kr>}rm&lLI1rZ|ZT!He7yl`I+sJ&jAZQ zKP4`^*vBQ=7czfs=Pfy+qe5a|twkhY4tQbqb2}J1@MOnS9LY`11Tak|p>>TN7#~*7 zVV+Ut5MNNT*|E%&A5k@zB|tj{ocTJ8XEt9;RI}&nFa+6ry*ml@8j>(-*nBOq!|}PX z+gVtb#w>D5j?7L=m`&_UhBfA$@0K4`Ih3)_s?=u^4HeR3q#0A>N|fV!_8ko6xe^bN zl%|fcOQ8jH`7u?!I0itad?tZd_R|&88887^oD(58_QU1JW(E>It5Tl{K{=bk$2!+M z216-gf?O-z^5d#ZMeMWk;nb;rINjtt)fLBc^OLM#C@)6r^OBc-e#<$h<71j3)PfJnHXd*RZ0bPDlrR&E&t5Tmy{9VXkOYt#0vq?uv zBdmF+pyqZ$cn8zpKhzJ?vslr*NP_?YITG0nxt>`of9yZ9J%6tu{)`)MgY zW>360cSQo_bZ(l zOP*C`2%K5DgfZn3Rtt^HjwqqEB;m^{Rn{ste`NKrsW6 zlw+H&qLBhk5Td)NR;!rUAOA`>zUq{atWu+T@&l8J>{&zCb=EPQYv?kl){wADIl2Pp z!7Ia%Z`;cywh#3sq`wfa9eLHYJoe?XY*?*-Sz3bFV_&R+%Xtn=zfjC7PtT3}q^xQ^ zDlTJ{VT?z_TCa!n3y&{cZY75H!-(k_UP(We)B+0|r<8Znp?a#PJpr3*5n`B=c=(_| zL{XM6kDOBN3_Rt$n#!V;DAHESkU5AV;nRuIExMIt4B=Jyc(?$h(yn0-JmvDe3rR`W zuonylA5SW^{uDvB~s`m;1urQ*|Ib;{=_5-?oSvoHTu`!zx^hM+Q! zBz#yUWf5mVX4B5}r9Fu0n@*az65o#kM?lMd?HX2Rjm?c-Qj)bnq z6&ZG1Pnfgh`I8sEU|}pnzoUu4{v_U565&)O9v)Q%5U+sFS?BU|cG}X+l^IkBPgtI{ zF8Mv>dGZ(;2SQ+#%-&iK1fm{<=%>Zq2hnef_zof; z7I7RzzC*!H)n15gJlJ8w;$Wlc^ebI8BDEWd?1#EpS8!&JsxEkJ0tH%BEu?_q_bdhp zdhUeI{S5v)pW36Ufp@pw2(!g%VK*?%bH(U7Ha2+)HpTucr~-N9nauniT@t+LdTUr3 zoollAVx*!`jWa(y=~L1pMEC5NLLU!_To{uZ?%holXYc=$Yk$TSEN&i2n%QaHTYNfB z6$zMmG-IC3oos|^~Svr zNo!TbHC6r@8rkg3FY~H}1CfGwUxBrNhn-#00#cV>51c5jl#(jG@i=}Y#15%$Y`V5EAPTPH*b8cdn{q+yP$)by^1?f zIKG3>U}~;^Y;>R)E~G_;1S2CPF&2O86hBvG?--QmLx*!O}A2OG7!q9;6_xE z6lEo%Z@ev&LMJKv1Uw!gSI{M;%ov_K1NrW2BJrVKLiBOa9QE(}zIbCIU z_GrcpLL^y9Usj1jwfxR0;>>oUZVYOC3Pj*|!hDPov#c9xs0j@7$M{&&MdbSpP=Up- z31xVe)#XjCc?;`Sn74GOIpdk3nJ`FL700k8=Se1jd|)br{5`FwRh?PYvscn8Tx0bL zs18%27*usDDh84)XOh%`}o+7gB&cJy9>j^2a1SVqAj3|yB* zPC2&i6*Z?Od?VIzBVYM%1HZ|LF&WwJjC_du32G1^cac^@Taq~e)}GJyl*xFv`*X>W zxf-#<6b>lyNh^h)mNTm;QtqHqw$BO^NfF1o;t*b#HqPic1WHJDQl^|4$J2kT^n|+fr~0{q1f8tXB#OY z>Ijqp+`GY4e&Dxz_A-gVVkuDGMs!OV73rLE5H5&hG$4>$r3`Jt-sRW&`W!(}ko?j% z_uc>-WDh*ffzIs$U5aDG&zmavJ%r&jyu4EMnx#@A58)FSLt?LD2o zeK4PRS|>&>zScTeqgja~xNraoWvI74a>&V7-Hf6DK^IC~+ng!b0FWsIV~0r$U3`fR zI26=%GTX_#Pxc-?mL61Svd1FFLA>#N?*CZ0m>i2*D0(bC?Hz%<3U>bcITlWBk3~%% zJ(iw!=UAfqxZh)WF4dd*bSk*>A&V98J$4$WKm1(pr-SG6)03)hLGW1=k6-#F;mql9 z?zhgzX5aW+Z#ptP`%T`@66;c2A_L0O;72Ux06x>@LT|&Z7AGa70FAxJ>~|>r?BEo7 zq*iOKZDwThQs|iK&G#Q?IK40|=}@T$cYsrOfF`r4GXV3Ly;$qqX~x;609lA+2o>Ft zxhfOl=pK^FHI~I&Su!?s)YoYM5DERBl6}ChT~%Nkb~ff8O&OJ&k?6-Iwiv2VrVvv81CahBP-VqE~dO z^;FQ%(knpZ4b4*^)kxpfHEqEBiEOqDiEY+35}l&tg-Cyow#hLuWW_%6Wj91Wt7eZe zCe>wc_WynNuiC9VBH4feQsiNEn+|$M(I+=El}7^&^-M))Dd#Ma@zrX)f5@8NT4v7X zKP(ukmo`I#Ug@Zcq}=4CDT_sF?5sSZYK-$z@B&3at)5tMXK*-m>yOdj$@S$ud<1RJ zrh)VUm~mmRr(;h!Pom>XD4$w1l^FRt`cXMQI{n|KpSB;O{sIKoljAyKD&cd=y!P`7 z`J7^I;SNeD+1f9cADI(@HacU;uYcDy&mGMV<&XtdI9C;gUI;6vZhZ4>7*g@5vA#_* zfS(C}6k7P#OFHr)x|%b~uimkcJrC4OZs}9pcItrLkp9H zuOd;oWlv8ACNMV&e@P?&uM*!mF?i8WtMA?!4b}SYB!J~> z6%k#k#C#T<9G-wJ!Axk4b>sPoxd4%eD=@z`3U~YI7-F=a5AW+5XQ2p9*fiE?OCXr zaYj=-Yb?6?s@_^YBMK9*`JL{QBV|2}y}iyg-rfPx zPp&O8eP>{(gYz(UpXF69gnex|BU$V46V9wV7oT--asbZni3EP*fO@^%nY3o{N%8U| zu=8~xq$-{)qTX%uOv{dmQ5`RO9&4hrI%$fipp%GGnQ@6AlH1xtE;?Z{yLI<0(QT1E z@9;nfPqFlPTeSY2E?1b}7>)qqT}&B)WEIHjO`HNoftziJwL^4csnxz~)q}eUz}PIgnTS`rSxn z91fNI8&yhE$>|A069gwV*j!Xvh-fp4{1#gm1 zsCbA?bk5>gy0LGI2ie3vE)r!E{j!9{V7n~@GHM%e^s7=RzHq49@0RyuB@Q$CRb>K^ zKn+|(t}cJ$oB6NO9cE`ov>?^cLh3*tDJPkD1rp}-2~Q2OnTzESM`13fH#kag;tTc= zTs1!@!Nuw^RmmWdoi5B2TLlTeDqAUM8!8%C|>yHN#2+xJm-myZ7K5LdjtuG^qh%472Q%~q9qWYGt*;5 zW=cj-wUhx(P+5`HcWJ3AYs9!yZuH#3>+6Xrj8p;Hb-KlM}liKn5AiUv5BYYgTwsrYJ@`kZ#fFsBra?#6l2JWI`b6S$pkYTC7*V zWtX2$rkH{X(mJZGaOHJm?ldrDpS5~=m?FCt9G)IF8XSOmXw#A`8wIRVQ1`FWC!FxF zs@{>@?DiSF5~C{cY)v5~ehyrP z*0wSk5{O4MItV=j(G%US zNlG4_P(96~vk}quJ7fbZO+EU}t^aWPKiO|wTU_+B$?{8BrEiI7U_h0| zrp@q(LsXTy^!g>)g_|K-ni;9_AZX2Jp6sn1PW5!iAU9y7Dl?nA5+D|*#+KKK9$#~B zEd%dT&%&$M{_KApsz$qn54%2juj-}smmlE2`w>hx{a>#BTmJp}-QmZa+?+G{2}B(* z5^*q(@`)z!2RxrSJGn93qsVU%wG2)QcU&ZtPi%V6cC@>nk~T}apB-1BK0$A-Btfpf z{lmUr@651c>u??6dE?)y5`p#JRG8p!%3pnq!!^HXRmB+Wm#TcR%8!cuJK$ zGMp4xA*A_#Ffzb|5w?r+OunZm#72G#B*A1bKLkQHQbM?z#!L5+7X!~K#qpwrp6J2q zNi+ZY<>j79Yl?!7R1fyxRcT})tZV0*#;?DA;N=zFKg+;R7CF5~)P$&$GmO?m$~BCr znHd;-r=!5_?5#zBM>cgdU7udXgc-)>odFFJ>+=h@H_p|P8VS6mjVCQ_ksdJnuulI_ zqy|Hi23TU5P)9@(Z9uL^vquY7XQg2@E?N5OPk+?a5tK4L+K=?DumWg^%|tw~9B2_d zwAjL+9~l8_RngKjsA@Y z$5_}}gy~aCWuYp~oucQk{>;Yom&tuVpw3ORpwytu7@ZX0E5h!y>!A2$68k5~atXCf zL-@VPl1SCp_0CZ31g4QVdcXlq%8HbEA}aA9U60uD z_~qU?H=%EJ!EMG3zBJ9k`d}q|b)rjb@ty*5l41nej36}0L^9-fzmMfw?gDj!^^-ln z;FSBVQ9z0cDc2_XxTDb5(I2X`LvRh`F&c3pU@r*VE^XjibwUeuL!0oZFWjO>{0 zNxQBluV;N|zTyr{>sl>m##_awIX{?)wzWhR56XmOJCkfYX2dkL!#TWmQ*2(O+$3>q zt!KIC^s0*kmnWE4b@>5`EzWecoDNl6<@H3PxJguD9+*X6Cpiebd2$CPW)tDuz*`kO zN=SoEym{B}Qjl|||Ku@|%7X3NnzqX;sRTIBzRM|)G91aG8l5M#l$nI+HR^kE7*-8- z*4<#oSuP{7_KDkA$G3oPWi+SxM`zZ@F!cDb%P6O7@PHzQCIrQZTFG<1b$;x<`GxF@ z*;QAszWG56Et^k{jj?^9P@iaouDqN$p?*P?XwMxxyIpVcUnqFn4KF@T>^45=PUF27 z8`N!9fG`h}z@(cUa2|2zF&vP^3@3&YVcH1U%xWy@dNn`qkTd5tGiNB>fKA5~jl|h? zy>vo(;o-SjXUvhIdmJeAX~KT3I6G zfw>0r3x-?tbi9-bIflLOThf?WT?m-$hfs{MfO8}>=!<`<~I2oIJ=k)04@B)+G|>L~D6S&c%Uo8T4)8r~^C^=%y9Nx8~d zZBxN&TOzB)1uU+XxTVeHxJEM?t_U`z&f(ADVAJ_qJ)dweRg+;5Dip+E`?+(6)qCP- zT}59iN>I1HbG<$DBPxGGyJ!f>x;%6XY%9jhksBDuPtDFi2f#yk1py4OLQG61!oG%- zr=B5FodfMdn2;?6As-v*FL8z~2DHwdJlG5W=I!UZe>U^g-deua>1VR;bNb8lR61hb z)J%SEaMC%yaWs|=a#K@`9?cC=7g8}+%CeKVK11!$VZo7as!qZ8r=Q(K0SAf*#YT#W zG~SS9s7c6V%?)=@vCEk-gPd`e%=B`m-4T0Yl&X)IToXWAl<9A!Xp{=FH(?;AX*kFn zc%vizMS4ted0VnK&mMNxs)IyF=CloMP;;{=BgnH;3u&Gu&GCSyiM(uURrf69?Jitj z^zBgXdhpDQy~k?yvSQfi1?7C5CaBYSyvAr*CGiXivxt_ES&@Ar{Y7Xy2&LBoX|uVd z^9$@h(%BJt%8qdjs7yI1?da$+o5vM`aS$8HL91qWlh8!Mt?8I@2$>>mk|A$v_HFDr zg-WHmoLM#8Ml)F>8k>#1*Z*tXKkI1>e|Gx&7YFZEsh@Vm==KyAuNDVayhCk{3Mk`uFa0C%3@?1mH@QmR>yEx<9u1+R!H8r&j2i%7&xT6zb+_*rdv~U4gG#cz( z9O(Jv^^sfu;=*cb#WaObs!*&8!C3OQ^g+id_{#;042^-M(aAZTAD)AunCy+2f$&An zGz6yw5Pkzc;5q!w3mD%2Axo+>%vRL@Bt5^Ia^nmq|6A3Jms z?kd=A;U*#f$c00iws;T|b|+EC=~ZfXSu`)7U-<0f!!L2cn9Pmx-=rc(vqlIt6D9M( zI4g8mF+5=vs|oWMRiEAbyCWym#jqk3N^k2GOd0AKBomD1gdlyG+o;$F)$EY(k_kBE zhdTRq;*j;4tL&RuSPMLf8abpnNk9>vj#Zlw#e}Z)F%3tfNeUX#tO;5tV{U3_jOjZG zXo?($k)ENN;aFma(V}+bu0s3^vFBI`Lt7>59jl~opPLo!MfV9YyZ6SABSwKO32V}P z4UXYHhY9<7DqJDlmEiOL8Yxpd>wA^r#L%uT_-^raGfWzWAMSQe^0`77@VpHp+gr9z z3DMcTYm;pVPNLxpg$}gV&XKE$1X&m48-^Q#ZM%Kg*%HD|az#UCfiDGj1a}a5RnZ)pKZezJHb3QTJVI8NMkW#NFrlhIBE@7J?qyU`_RX!C z3lG>lDUHiAKYIBW>fs50W^dvV2h9|^?XwWRFkl5Dbeb21@k`E!USRfz_+%gZ?k`Z3 zR7QufALdq*Eue38e)`I1w!1glLB((g9L}51^XNqV%)lh@8>$D6q6b!=o&=YIu^d7! z1r^0r*uwx~uW4b14e{VCfAC@Reh8u_1XZyDyr(%ucuSxO?XXvp*g*gFb|(Xyyi!Cj z=BMW`QP2wci|)cu@U|XSxaUnneKt+U)Gy@k$N_x)&+pv2Cq*TCYlrR)^ecl2C>6iww*L6^qd<*@kKf+AuU=fO9IDeQINisdhL~0 z-aq@Gz$cl8GypU%qugZRH|A9bzFz`-6xk4X1bojTZyYjCfV4!g3dyiQY9j7@Gam(j z2=$%L6fK(g&V8=}3BLY~6vtqDAOe>T)BylBi-I`<(KxyZd|ZH}xJfFwe)r~bwAK8g zv;S%=bqS<405Mh@FcWaRmd<7t|DgCRn+b*RM_MUA%0VHKl=ni5%Q^`uVY&@wy7Uj! zWU1iVzmJg3V+E6vHZCzo5)8S?hxj@%3_}$`n3(9qVub6K+L+U+E9rVFp`g))+ku0F zLtIR|-DAI(&{@qVuh=mq>)jS`X^LXCF%#OuH_rbij%RwsJb*;82C-P(21kdBUB_WTtD+-Z{vmj{xyxu6k%tp-|Bz;&o4ct?v(@gF~BV$ zd?rRPL@Z+-6x+On9M^ilJPvxpS@Op?TqsO(y#9A@E5SQoGhFffwd^WGH_+LDPE$R| z0j04uFet&Pu_hDD|CdoZNrx>8cOM;|P)#ZQB-J9T{&$~!ytkJZ;QHNpAn3-|I~yC9 zDM2LtEq;-HQog9?gXBPQx)lOX|1|QHDf!OfDb{xcl0}{mK4juSjkB>U5y3;fIr!}m zGUY(^=pFV z8p%U8v>TVTM_8?nVj``!IErG5%Ni;}ydUR&qC7@cM8XPI|3Sr45kEoqBYfdCW%i>Q zwDy+xx$w)5R0#tN{if=WiQ>j(vOA4zymUY@zvr9H-zc5r{PMHwAUD^dJi-wE+cl4Sypsx6<1(Y}D9K-$eH^&D65tXVHm@=82rJHnqYDg< z4x{X3gJg=xMWUQDsLL4npk2#{%O!IM1`xV=d{~aA5jqczxp^h9fLmBBERLqlxa zWh7LsB%sMGT0Y`UXrSOXF)%jA02Zo#e5_2*Hh$#8Qg!x;7yjtAulIbC61lVP!>!}} zqr-EPb2Gs-UjvcLeUls|QR__x#*EGfFuc$5TbN)`=1oDUOvlwfNuRkMCRNdheRHJ zOM&;z7x&XH;9ej;e_UJfVXl4g+jw~JQ+`R}IfYaL2REkxkrDWpM!CT;SVU2jSZfK2 z)(sh<;Tn88K9tET7zf#)OL<9Hd5l6BEYq&A{!0YYhFf@Um~xchu|i1gEGv}hxJDm1 zB3Ajpxqg>rNgYfzEd>O5%~Z2W6$_FeAM}ujx$Dn=e(GI5V~S7HXThH!xT%Z(RSMj_ zDq@6Ro9od3RBtW48dUtV<+qnbZuejW$O)PpLpcUf4=8sc^)_I}bX59Kv_UQ(Py@Fg3H*hNgXv$%|E7bGCt59M0yS%w zAAMxwbF*{Mo2h=8m((N0HMloiiMHuxxVP8et72iTzE>3nhEs3PpKWuNJ{DOTR~>zA zp`xJ6*(lz%t2l`M`~W-0pq7hvB#UWyD>6@+of9AhfFYK2C5@vn?`%u$ zZe(m5oS!3Q-QVDdpBCE#fz&qqRc%i`!Z6hhM=>B%AF z(;oq54{G`1X0)-6P&vZX@|S+hs78{*rGA2QzS9~vNqpN z(49>VL6=t!!JM?h_;!KHYYcLl`5*0*w(iL2^Z=d2NX@ZvO&*q}RFok9gTB9$j^4m; zDi|(LutYz0GzS6{bC~gb(;q#K*n^QGPvcG;8MMay52))1nwzag1T`R0`}tJ36hs<% zdwHH(?P-SE@h0+HH50j+=&K6P{y_4gTlkSjDKK(2+_ zRf{vO&($l>)ed7j)K}AYR&9$y7tkIeXxg2sy*TjtV|PCEz}UVxjN-uvYNwzd(wjlw z+Dvd2wL6yz@76nmWA8!DIi?EtX!C z^-zw+3BOJdxtpN{i6Arl5_KVXi=hqO{sl#gp(Kl{Eb=brGc<*|0=y!;=(N%DE;5B&2kU98iUiPHnv~P0V@SI-g)@4emc(kbDyGk3hkb`jjmw$m6@~h`>#oQ(h zQ9#I(wY}8E5?C=ZohH44<@)G4N>_4-KJcs}dJ!_~mIOa4VM2e5MZrDc%#4RagfT60 z<>>vz&)8~$?i1f47I@yF;Z(Ld_MUHamXPZKQ9K`v!NusCvCg2wsF1@ITB2wc&IL)c zdmd&1khz1TUy84z4#L$ib$Q905z-}EOBk3B6su0k<`7TFMador5P?aciDQX?SZnXL zX2l`ZLS=?5-Q;Rs5qNCj*cB{5IC?HgTl9Q~o@a3e3FX%u836}Tp@6uhx; zVQgzgsFU;xPvDeeXFfmt57S^FU59Ri_!l!r-mB_+HT_?RrhYhk=l?ca1s9B%Fs;YT z21}aXh~Wa?Ij7ivawzDZ#A~nEhq_IUnQ}&~67VEZtF=ee(hXVer za4>4|bp13gD+1mHO4ER&LdXV`ne-jesBaC|H6T>(; z6{B{;#in zBVDh8LYRq6vF6t7y(-2J>3=uhn$@JU`_`;OJVyy1QeQId^;r{&2#DaXB{1QG3>|(D zHD;)*sbA_a5`N;Nody?1VvI1-DM2M-U)4hN2~`Q{ z8PdY3FxSmYbb@2lrd=z zg`F-AvLPflEDeI6iU5;LdHP2c5fN&&9j~3BmSLFprO!2f!IKdJ1qYxIQA)YK)J#*7k>F5NZXcNsdS_A_XIU<;AGTM>6 z5G61b$pT`*f_~HY2C`)8pY$9i?qz545==j4jTdJpKAyJrY$;a>Q%W36ZO81FM#qrG ziZcf_yXZ10CP0#J>MfiYFZ9nlPj%1ty-HIF{aD#*b~E4$?JU)Lk|nsfj=M+>Ee`Bk z41<=~>2njPk%Lp34leS@AkB-%$|EAwsiSi2G_X3+%4Y;0=kUTSzAq6RIXTjYHup6- z;iz(wJ|TJ?->#uuEWXtJtLQ`8nR{%0!3yY`I+zW_5Jwys)(~S{9*!VJe)zUUNrw?u z#IZKT;~ifln69HkMP8|Zsu?BPL_A&QdHEQzbG2h_pMCuPZohy9gVD#l{n`LXn<5@C zVd0A!08zDDtcqf7bgctRF#$?gfZ?if1Y5|KD7tqCi_(HlfODytDOLo+w#Vb+@|uf^j^GJm5K9S5sh0lIH$R~Y1tL9z{A6^Vs_=E93M30%_wlOQmW-MnN6Ha)P zLb{KLYU4!8yG8Z&{5&^GlBMY69PN`>M@d62<%l-TLp2v8)Ja2Fd_W}M761|3;-j*( zR&~Q^HC=g#_qyUYlu2J&f8&n_%B~z#>9TM)O{Jz0<~y7k$NvY2uDmQi$s^Ko27$qh zzC@(BN3Zk1 z_ey90;l=Cjyq`+v9YCE6-W(o0d_#x{L`vn@q}QCXp5g{qBOJ!$>a6ydvziUgqRmEy z?fB^DYUW3LK!EyFII>Y3gS6vBu<&1Aeqid|k;mV;iNlWl4rQ^_S5x@!D8|iVJbyNZ zKRJmE7XmOIO0i}`lc4R|)Gcs8KPjLS5vJMa5k%EZp@HFSa0Izu;z}X2wI@qIChXM+ zvYiQ>noqt>*6{p<1Hz8MQ&UQ>vRY)mnSKUl>eR?SOJ#d3KvuUkkG3nBkvq+gq5=o2 zE988OA0)?nz6KZ)BMM~%WkhjAVc?P(zd_qPRwp5%Tt7`GK z`$%EEo*lEQkd;_C;?{8HqnruXSGj5J3jT1DY8IqnfxK8#_0?T0*BMA{Pxmq%3*q6*tCMGp=49A#aR$7z z|4Zf$XP&Ayxyi zhl1*(kh~dx1UzhOdQ$54xj*)cQnd;M-eSAF6a{3rBNhcL&O_$XW z)m-nUU9&poW_VH~bNf$^r0ZF|NFHRVkTAcX99qsL-P40CGYZbuJH+w`j`vEW`CQP9 zpXyo${#b(zEbL?A%@bn+>ZA<;O=}=87^Z|N-DgmM7-0>G-I^7n%(E$*go-D*-t&NN zg`9)atQXf7(Cj>kq-~XP>bdw`O2#uu@p!V?IdB9Los#TM;=g?6rK6$zWL~7EZoRDH*b86pcZUKWu}dy z;dm&e1n6|l%rz!CPUCM@Y)xOd@%wzO#RaKfZzZ}qn>_7o@-&lSl(2FRq{&Oo1P2FNklCYaofC7!08ru9$xM;_q3JWi#PG^%wG6PNaQ{Lllt_ z!R|TyEyne0gv;JqR9c5K$E1-sJ3YV^tbLhBMCo!;T&j^+WaR`SPDEz%;=!J>wqGazv7^9*E&QUA`zno#EmDGGf4koK7>~u+H3%FjASYS z1Erpv<)0|Pgt&yl#ceo4F>#1wr7KBck80<{0tyj{=#8Ji%ZwWjd0$1k!T*a&_OW6x z-2?^|&9uBstyr!JOCRv^;~bEMMhk*1l?rDr=u(twXrsD%j4egxJFYEZT@{K&JTwN( z=>Q73AC?+h2^6kEPMKvjgH;fzXdRktHL03J!&!{czDuu|vXklY`Mr0(fvZhbg$jpB zMirGK41l!2d`f`PY4HQlCzvIQ<%Ln|&_~bx0OE)1dK;a;TZr*CWNbQ7QmNj;pBcU2L;DbEB>(P()rQ-KA;2n+Jo6(SL;wGpet<`D zuZqMAu^B(RdUgKA=W8-QRUBKi@S9=DE13_Xcr4TKH38q!iW^rPrkR@~YX`T(Ihxwl zkY>OR>XcT^`)IyHF$5HknL=R>#p&g~NC1K8zX@ffipU{632I4U1OaJrXqT&BMB<|w zxTRQJ4qb_^Dn*k*@$xypveb1=ogt>*5++2)R>3?nlRB8XA}`G}t}%&q7SHTad3BuE zs2?#9I2!dm->EAoJvxdeXeHeT@~W(toaF96Df&Ogm2M!?m$wp zttqSL(KG)xv%d2my?#3VWfjz6Stpuc(M18@D)XU~XahXjm>H4Nrci~0H(v*Acvxx8 z+gA(+LqmJ$GxH1f+`)xZC4Fa4yJTrtWrb(rks_L0mZ5c;MQ-g@OAVvd-a(~^fWjkY5aHkY z(S@Li(jcRkXBq2ij3%>K0{%ANhSn+x+c?uHVOvVsN$^xeV4xi4-l|s~0@)(3tfopD z&!hb7eY6AkkEU55Y9FHrVVnGHM$3TMoix353p z0-1&$8xXU|;)5MF+1iIYbdr z)WsoD)B;n}Qu&y8+ttpL2*6k$7FglWkpx|3%=GvQ17hfAs7rg^Fg_HMLAmgzg-#0Yy?&gT2`$ zBL*pkO%Ltr{Ij_;%)G6qKKQwB{Pf0qH{N@DLH*WRHKPKopPFxDtDgD(rfXUXlGaNRp2R@2BNQe@68lIrSU8pCgfP)<^gc9UV z@Rr2Zu$3b46+%I-q}1H=`{_JQuQSwj_JKElOrs|&^g38PSqPup2zk@+5=w5SSd{c* zM*@NR%T|IYuj~})^*lw#4Y8Bdd3F1G*|&mVr4L@cdawM(dm!qACdB9EDyo3<3+f68 zIY6wqS79H=D^Y;eyO2oK=4rrI6e-ls`iUCvgcOu^Xj-Tl0nQgmPNOqBJRAHhH>gC`J9pl;L!-tHUl+Vs78{wp_(AHOLQ2pm=uz7s`)JRQk6 z5Z)Rqe`XGtrfe83_=Mm_kS4Xz5%Oa6HPs=H2pt+^)D&bUM5Lg0hma;@Cx}ov35N8> zEi5Qm=iG0+MA2)yh1NtVpFrumPz(nViD)cV49C7mEZcuFv|wCWq-hXy%K>cLqg3$; zIH-Z522?R2HX{s3(ox)1y)kArObn$keeNfn!R@syD8y%N{%_BJMcKAuMiO~z!xT`( z`loU;lBU6aLU_fb{mu+3P)Gm_?TJ!`&&T;{=$|lP5P+dwB1L|u^VjHm=o(UN*fXUdi2&0iX>;1WG(yqH7_q67Ge}g_9TC^4YO0v? z@ty+Gue#v6-lOijW#ktJ`uZ63N)ng1IYJ5YEch1NtHY7tB{3cp2EM5) z2gKQ|Pb(R~u;&0F@|=o`6Vb@cC#3del0(r6gc+>b#=*B-XMgJKAg?t~ngjt581M~P za#e7qQu+=c#@Lcjp8|==h6<6BP@vNara4+y5 zhg^(s`AD~xb+WX=dk_FL!$=Qmkh+j9iT8aIP2kw`K_r5s+{v~Ug0skNJgrx0PPNGV zP4fQ?Xy951i&M?a8ke12o&Qk8MtrG67*^_UeBjETWN%*l>nnePk|-k*c+!Z18)0L> z3j$Mf%RvDPRajh@(1wMPhBHAkjNX)LbSeKj&0QfN6M5rET^d#VHWI=RG(H)4-lvwg z=db;?io75PQ1`vJ_O0_*uNp0nY*rJrI5VA7O`~nMs-WeDW$4SUvu$w4MHzsQii$4G ztumG}OUfj^BBWd=HZ7;|ATJ*2EB!^4Z_fung-kiH9m>M$WY=m6HBG%=M1p& zky-=u5O~QYNULi2vEfH-)C{Df{9aEKO?{SrDb?E<$YAOMI!c(9RD1&wK9ooD6Fc7c z7DvOfOK9&C@*u;golQS-YU1L=d)+3nRhmaz2M)rm{*Oj;WEqd$)qm$zfl zwGS%gkbFF@_~GA?m>qs2H(COf9Bj9q){I-RPYN+sZIkyt{HG4!kuX#3xJEFO@2K}) z$QVtC)+ln++Z%8FfjMwWgr)$;0CXejC6OTY>0V|()45<88v-|>UIf`yTNl-16!KZ4 z7D11ko}3$275D2yGNL;oEP)_)n&Ks1>Mmpq)NXi)*%fcG*@=VLPb>J{CmS1pior^b zbW>3iP6ou0&x$=7jTbV$iXwz<;)H3N#} za)hY$*VUT1ka2P{nO=+Y?R#~8Vf^siV=p|f;NdM*+&Np7PVryp2qxc!YLT*4@^_8P z`2RxKBJwh3yPy)+t%RN6fa#4xW+DnGk{`*|M!~KMwq|4$UVd&Hyi-?Q!z8fRnBU`^ zlr7Y>{|ST}I;xZkvh!VrgBLQQ8A7yBLDzh)81X>F&{&`lKzWBn2Lvhc4zBaERaeCW zJ&`^lWf1UCNkKI6$}z!7mx48ge#0GE!Abm83)xpEMe)r1HQ9kX9 z_p0s;zIFaWhB;p9n(((TJfE(&@>*xFjlXb%H7GZsZ|5YAiZ2S=JSv+rjs$fwR8SY6 z924IWAkz>g8ei|1>F{}>Jixa<{0VO|k)22BkE>VlB1|Cif#EwlLRrD+2X2Io`&&wg z3~{A2IkK;>%enQVN*cD@MjX=WXGtOji7qZskOgD6{FNFQ3IN&)L0Q8`X*!+uJit@Z zoQh(jVKihG?5XGgU4MqHDb)jDYWF!+3H$TIAgaaMTa=I>>`|`}P0d3)<(DUV%6d^p z+J3$=e;EZ25uFVypl48JI>l?jf@t9|$--fg!D;WXJ0BJds}da@H@wKWay8C{(TwuL zSbFX!Z=HGTeGA`;4tiX_5K^*RuW%on;o%IeMbRqTj99> E2ZWfXlmGw# literal 0 HcmV?d00001 From 264f57fe95394b5e8531d54d8612633c553a075c Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Tue, 16 Nov 2021 15:49:26 +0800 Subject: [PATCH 27/60] config.h --- DSView/config.h | 36 +++++++++++++++++++++++++++++++++ DSView/pv/appcontrol.cpp | 3 ++- DSView/pv/data/decoderstack.cpp | 4 +++- DSView/pv/sigsession.cpp | 2 +- qtpro/DSView.pro.user | 19 ++++++++++++++++- 5 files changed, 60 insertions(+), 4 deletions(-) create mode 100755 DSView/config.h diff --git a/DSView/config.h b/DSView/config.h new file mode 100755 index 00000000..25d9638f --- /dev/null +++ b/DSView/config.h @@ -0,0 +1,36 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Alexandru Gagniuc + * + * 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, see . + */ + +#ifndef _DSVIEW_CONFIG_H +#define _DSVIEW_CONFIG_H + +/* Application details */ +#define DS_TITLE "DSView" +#define DS_DESCRIPTION "A GUI for instruments of DreamSourceLab" +#define DS_BIN_NAME "DSView" + +/* DSView version information */ +#define DS_VERSION_MAJOR 1 +#define DS_VERSION_MINOR 5 +#define DS_VERSION_MICRO 0 +#define DS_VERSION_STRING "1.5.0" + +#define DS_DEBUG_TRACE + +#endif diff --git a/DSView/pv/appcontrol.cpp b/DSView/pv/appcontrol.cpp index eae70d5d..39461b2c 100644 --- a/DSView/pv/appcontrol.cpp +++ b/DSView/pv/appcontrol.cpp @@ -71,7 +71,8 @@ bool AppControl::Init() return false; } - const char *decoderScriptDir = "/home/lala/tmpdir/any"; + // const char *decoderScriptDir = "/home/lala/tmpdir/any"; + const char * decoderScriptDir = NULL; // Initialise libsigrokdecode if (srd_init(decoderScriptDir) != SRD_OK) diff --git a/DSView/pv/data/decoderstack.cpp b/DSView/pv/data/decoderstack.cpp index b8c15a24..9a32a7ab 100755 --- a/DSView/pv/data/decoderstack.cpp +++ b/DSView/pv/data/decoderstack.cpp @@ -480,7 +480,7 @@ void DecoderStack::decode_data(const uint64_t decode_start, const uint64_t decod uint64_t entry_cnt = 0; uint64_t i = decode_start; - char *error = NULL; + char *error = NULL; if( i >= decode_end){ qDebug()<<"decode data index have been end:"<decoder()->stop_decode_work(); } diff --git a/qtpro/DSView.pro.user b/qtpro/DSView.pro.user index cb6bad0c..562886c3 100644 --- a/qtpro/DSView.pro.user +++ b/qtpro/DSView.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -55,8 +55,25 @@ ProjectExplorer.Project.PluginSettings + + true + true + true + true + + 0 + true true + + true + Builtin.TidyAndClazy + 4 + + + + true + From 8aa8fdf0eb0f56482ddfbd6245790f152775b9aa Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Tue, 16 Nov 2021 18:24:12 +0800 Subject: [PATCH 28/60] update capture screen method --- DSView/pv/mainwindow.cpp | 42 ++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index a8f3dc45..e1fa249c 100755 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -30,10 +30,8 @@ #include #include #include -#include -#include -#include -#include +#include +#include #include #include #include @@ -868,20 +866,29 @@ void MainWindow::on_screenShot() { AppConfig &app = AppConfig::Instance(); QString default_name = app._userHistory.screenShotPath + "/DSView" + QDateTime::currentDateTime().toString("-yyMMdd-hhmmss"); - QPixmap pixmap; - QScreen *screen = QGuiApplication::primaryScreen(); - QDesktopWidget *desktop = QApplication::desktop(); - pixmap = screen->grabWindow(desktop->winId(), parentWidget()->pos().x(), parentWidget()->pos().y(), - parentWidget()->frameGeometry().width(), parentWidget()->frameGeometry().height()); + QPixmap pixmap = QPixmap::grabWindow(winId()); QString format = "png"; - QString fileName = QFileDialog::getSaveFileName(this, - tr("Save As"), default_name, - tr("%1 Files (*.%2);;All Files (*)") - .arg(format.toUpper()).arg(format)); + QString fileName = QFileDialog::getSaveFileName( + this, + tr("Save As"), + default_name, + // tr("%1 Files (*.%2);;All Files (*)") + "png file(*.png);;jpeg file(*.jpeg)", + &format); - if (!fileName.isEmpty()) { - pixmap.save(fileName, format.toLatin1()); + if (!fileName.isEmpty()) { + + QStringList list = format.split('.').last().split(')'); + QString suffix = list.first(); + + QFileInfo f(fileName); + if (f.suffix().compare(suffix)) + { + fileName += tr(".") + suffix; + } + + pixmap.save(fileName, suffix.toLatin1()); fileName = GetDirectoryName(fileName); @@ -895,10 +902,7 @@ void MainWindow::on_screenShot() //save file void MainWindow::on_save() { - using pv::dialogs::StoreProgress; - -// dialogs::RegionOptions *regionDlg = new dialogs::RegionOptions(_view, _session, this); -// regionDlg->exec(); + using pv::dialogs::StoreProgress; SigSession *_session = _control->GetSession(); From b0bb9b5da3fc7fe5e304d9930c6356c173cceb75 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Wed, 17 Nov 2021 09:54:52 +0800 Subject: [PATCH 29/60] none --- libsigrokdecode4DSL/version.h | 71 +++++++++++++++++++++++++++++++++++ qtpro/DSView.pro.user | 2 +- 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 libsigrokdecode4DSL/version.h diff --git a/libsigrokdecode4DSL/version.h b/libsigrokdecode4DSL/version.h new file mode 100644 index 00000000..d131411e --- /dev/null +++ b/libsigrokdecode4DSL/version.h @@ -0,0 +1,71 @@ +/* version.h. Generated from version.h.in by configure. */ +/* + * This file is part of the libsigrokdecode project. + * + * Copyright (C) 2010 Uwe Hermann + * Copyright (C) 2012 Bert Vermeulen + * + * 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 . + */ + +#ifndef LIBSIGROKDECODE_VERSION_H +#define LIBSIGROKDECODE_VERSION_H + +/** + * @file + * + * Version number definitions and macros. + */ + +/** + * @ingroup grp_versions + * + * @{ + */ + +/* + * Package version macros (can be used for conditional compilation). + */ + +/** The libsigrokdecode package 'major' version number. */ +#define SRD_PACKAGE_VERSION_MAJOR 0 + +/** The libsigrokdecode package 'minor' version number. */ +#define SRD_PACKAGE_VERSION_MINOR 6 + +/** The libsigrokdecode package 'micro' version number. */ +#define SRD_PACKAGE_VERSION_MICRO 0 + +/** The libsigrokdecode package version ("major.minor.micro") as string. */ +#define SRD_PACKAGE_VERSION_STRING "0.6.0-git-c708a00" + +/* + * Library/libtool version macros (can be used for conditional compilation). + */ + +/** The libsigrokdecode libtool 'current' version number. */ +#define SRD_LIB_VERSION_CURRENT 4 + +/** The libsigrokdecode libtool 'revision' version number. */ +#define SRD_LIB_VERSION_REVISION 0 + +/** The libsigrokdecode libtool 'age' version number. */ +#define SRD_LIB_VERSION_AGE 0 + +/** The libsigrokdecode libtool version ("current:revision:age") as string. */ +#define SRD_LIB_VERSION_STRING "4:0:0" + +/** @} */ + +#endif diff --git a/qtpro/DSView.pro.user b/qtpro/DSView.pro.user index 562886c3..cf656ba4 100644 --- a/qtpro/DSView.pro.user +++ b/qtpro/DSView.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId From 6995e5d55ee06d4a21c09487bcd8bc587ce3dd7c Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Wed, 17 Nov 2021 10:02:59 +0800 Subject: [PATCH 30/60] none --- libsigrok4DSL/version.h | 69 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 libsigrok4DSL/version.h diff --git a/libsigrok4DSL/version.h b/libsigrok4DSL/version.h new file mode 100644 index 00000000..8597d4f8 --- /dev/null +++ b/libsigrok4DSL/version.h @@ -0,0 +1,69 @@ +/* + * This file is part of the libsigrok project. + * + * Copyright (C) 2010-2012 Bert Vermeulen + * + * 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 . + */ + +#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 From c7a6ce2ef56eba4028f9ca7da84995f2b45afa5a Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Fri, 19 Nov 2021 14:24:26 +0800 Subject: [PATCH 31/60] switch qt class to 6.0 version --- DSView/pv/config/appconfig.cpp | 10 +- DSView/pv/config/appconfig.h | 7 +- DSView/pv/data/dsosnapshot.cpp | 2 +- DSView/pv/dialogs/about.cpp | 12 +- DSView/pv/dialogs/deviceoptions.cpp | 6 +- DSView/pv/dialogs/dsdialog.cpp | 31 ++--- DSView/pv/dialogs/dsmessagebox.cpp | 7 +- DSView/pv/dialogs/dsomeasure.cpp | 1 - DSView/pv/dialogs/lissajousoptions.cpp | 1 - DSView/pv/dialogs/mathoptions.cpp | 3 +- DSView/pv/dialogs/protocolexp.cpp | 3 +- DSView/pv/dialogs/regionoptions.cpp | 2 +- DSView/pv/dialogs/search.cpp | 6 +- DSView/pv/dialogs/shadow.cpp | 2 +- DSView/pv/dialogs/shadow.h | 8 +- DSView/pv/dock/measuredock.cpp | 3 +- DSView/pv/dock/protocoldock.cpp | 4 +- DSView/pv/dock/searchdock.cpp | 3 +- DSView/pv/dock/triggerdock.cpp | 6 +- DSView/pv/dsvdef.cpp | 17 +++ DSView/pv/dsvdef.h | 5 + DSView/pv/mainframe.cpp | 154 +++++++++++++---------- DSView/pv/mainframe.h | 8 +- DSView/pv/mainwindow.cpp | 6 +- DSView/pv/prop/binding/deviceoptions.cpp | 5 +- DSView/pv/prop/binding/probeoptions.cpp | 4 +- DSView/pv/prop/double.cpp | 4 +- DSView/pv/prop/int.cpp | 2 +- DSView/pv/storesession.cpp | 50 ++++---- DSView/pv/storesession.h | 1 + DSView/pv/toolbars/samplingbar.cpp | 1 - DSView/pv/toolbars/titlebar.cpp | 31 +++-- DSView/pv/toolbars/titlebar.h | 9 +- DSView/pv/ui/msgbox.cpp | 12 +- DSView/pv/view/decodetrace.cpp | 1 + DSView/pv/view/devmode.cpp | 4 +- DSView/pv/view/header.cpp | 96 ++++++++++---- DSView/pv/view/ruler.cpp | 6 +- DSView/pv/view/viewport.cpp | 88 +++++++++---- qtpro/DSView.pro | 2 + qtpro/DSView.pro.user | 2 +- 41 files changed, 385 insertions(+), 240 deletions(-) diff --git a/DSView/pv/config/appconfig.cpp b/DSView/pv/config/appconfig.cpp index b921a631..42bc78d3 100644 --- a/DSView/pv/config/appconfig.cpp +++ b/DSView/pv/config/appconfig.cpp @@ -119,7 +119,10 @@ void _loadFrame(FrameOptions &o, QSettings &st){ getFiled("style", st, o.style, "dark"); getFiled("language", st, o.language, -1); getFiled("isMax", st, o.isMax, false); - o.geometry = st.value("geometry", QByteArray()).toByteArray(); + getFiled("left", st, o.left, 0); + getFiled("top", st, o.top, 0); + getFiled("right", st, o.right, 0); + getFiled("bottom", st, o.bottom, 0); o.windowState = st.value("windowState", QByteArray()).toByteArray(); st.endGroup(); @@ -135,7 +138,10 @@ void _saveFrame(FrameOptions &o, QSettings &st){ setFiled("style", st, o.style); setFiled("language", st, o.language); setFiled("isMax", st, o.isMax); - st.setValue("geometry", o.geometry); + setFiled("left", st, o.left); + setFiled("top", st, o.top); + setFiled("right", st, o.right); + setFiled("bottom", st, o.bottom); st.setValue("windowState", o.windowState); st.endGroup(); } diff --git a/DSView/pv/config/appconfig.h b/DSView/pv/config/appconfig.h index 7cddff2a..f01678ad 100644 --- a/DSView/pv/config/appconfig.h +++ b/DSView/pv/config/appconfig.h @@ -57,8 +57,11 @@ struct AppOptions struct FrameOptions { QString style; - int language; - QByteArray geometry; + int language; + int left; //frame region + int top; + int right; + int bottom; bool isMax; QByteArray windowState; }; diff --git a/DSView/pv/data/dsosnapshot.cpp b/DSView/pv/data/dsosnapshot.cpp index a3649f8f..bf389c11 100755 --- a/DSView/pv/data/dsosnapshot.cpp +++ b/DSView/pv/data/dsosnapshot.cpp @@ -378,7 +378,7 @@ double DsoSnapshot::cal_vrms(double zero_off, int index) vrms = vrms_pre + vrms / get_sample_count(); vrms_pre = vrms; } - vrms = std::pow(vrms, 0.5); + vrms = pow(vrms, 0.5); return vrms; } diff --git a/DSView/pv/dialogs/about.cpp b/DSView/pv/dialogs/about.cpp index a0a40099..3392d2a0 100755 --- a/DSView/pv/dialogs/about.cpp +++ b/DSView/pv/dialogs/about.cpp @@ -21,6 +21,8 @@ */ +#include "about.h" + #include #include #include @@ -28,10 +30,9 @@ #include #include #include -#include - -#include "about.h" + #include "../config/appconfig.h" +#include "../dsvdef.h" namespace pv { namespace dialogs { @@ -88,9 +89,10 @@ About::About(QWidget *parent) : QString filename = dir.absolutePath() + "/NEWS" + QString::number(lan); QFile news(filename); if (news.open(QIODevice::ReadOnly)) { - QTextCodec *code=QTextCodec::codecForName("UTF-8"); + QTextStream stream(&news); - stream.setCodec(code); + app::set_utf8(stream); + QString line; while (!stream.atEnd()){ line = stream.readLine(); diff --git a/DSView/pv/dialogs/deviceoptions.cpp b/DSView/pv/dialogs/deviceoptions.cpp index 96436f78..ee506833 100755 --- a/DSView/pv/dialogs/deviceoptions.cpp +++ b/DSView/pv/dialogs/deviceoptions.cpp @@ -55,7 +55,7 @@ DeviceOptions::DeviceOptions(QWidget *parent, DevInst *dev_inst) : this); _dynamic_box->setLayout(&_dynamic_layout); _layout.addWidget(_dynamic_box); - _dynamic_box->setVisible(_dynamic_box->title() != NULL); + _dynamic_box->setVisible(_dynamic_box->title() != ""); _layout.addStretch(1); _layout.addWidget(&_button_box); @@ -346,7 +346,7 @@ void DeviceOptions::mode_check() if (mode != _mode) { dynamic_widget(_dynamic_layout); - _dynamic_box->setVisible(_dynamic_box->title() != NULL); + _dynamic_box->setVisible(_dynamic_box->title() != ""); _mode = mode; } } @@ -375,7 +375,7 @@ void DeviceOptions::channel_check() if(sc != NULL) _dev_inst->set_config(NULL, NULL, SR_CONF_CHANNEL_MODE, g_variant_new_string(text.toUtf8().data())); dynamic_widget(_dynamic_layout); - _dynamic_box->setVisible(_dynamic_box->title() != NULL); + _dynamic_box->setVisible(_dynamic_box->title() != ""); } void DeviceOptions::analog_channel_check() diff --git a/DSView/pv/dialogs/dsdialog.cpp b/DSView/pv/dialogs/dsdialog.cpp index 1d8f15ff..37a0e7cd 100755 --- a/DSView/pv/dialogs/dsdialog.cpp +++ b/DSView/pv/dialogs/dsdialog.cpp @@ -78,9 +78,7 @@ DSDialog::~DSDialog() } void DSDialog::accept() -{ - using namespace Qt; - +{ _clickYes = true; if (m_callback){ m_callback->OnDlgResult(true); @@ -91,8 +89,7 @@ void DSDialog::accept() } void DSDialog::reject() -{ - using namespace Qt; +{ _clickYes = false; if (m_callback){ @@ -133,24 +130,28 @@ void DSDialog::build_base(bool hasClose) { _main_widget = new QWidget(this); _main_layout = new QVBoxLayout(_main_widget); - _titlebar = new toolbars::TitleBar(false, this, hasClose); - _base_layout = new QVBoxLayout(this); - _main_widget->setLayout(_main_layout); - _main_widget->setAutoFillBackground(true); - _shadow = new Shadow(_main_widget); + _shadow = new Shadow(this); _shadow->setBlurRadius(10.0); _shadow->setDistance(3.0); _shadow->setColor(QColor(0, 0, 0, 80)); - _main_widget->setGraphicsEffect(_shadow); - - _main_layout->addWidget(_titlebar); + _main_widget->setAutoFillBackground(true); + this->setGraphicsEffect(_shadow); + + _titlebar = new toolbars::TitleBar(false, this, hasClose); + _main_layout->addWidget(_titlebar); + + QWidget *space = new QWidget(this); + space->setFixedHeight(15); + _main_layout->addWidget(space); + + _base_layout = new QVBoxLayout(this); _base_layout->addWidget(_main_widget); - setLayout(_base_layout); + setLayout(_base_layout); _main_layout->setAlignment(Qt::AlignCenter | Qt::AlignTop); - + _main_layout->setContentsMargins(10,5,10,10); } } // namespace dialogs diff --git a/DSView/pv/dialogs/dsmessagebox.cpp b/DSView/pv/dialogs/dsmessagebox.cpp index 2df07b6e..1d6fb9ef 100755 --- a/DSView/pv/dialogs/dsmessagebox.cpp +++ b/DSView/pv/dialogs/dsmessagebox.cpp @@ -53,7 +53,7 @@ DSMessageBox::DSMessageBox(QWidget *parent,const char *title) : _main_layout = new QVBoxLayout(_main_widget); _main_widget->setLayout(_main_layout); - _shadow = new Shadow(); + _shadow = new Shadow(this); _msg = new QMessageBox(this); _titlebar = new toolbars::TitleBar(false, this); _layout = new QVBoxLayout(this); @@ -63,7 +63,8 @@ DSMessageBox::DSMessageBox(QWidget *parent,const char *title) : _shadow->setColor(QColor(0, 0, 0, 80)); _main_widget->setAutoFillBackground(true); - _main_widget->setGraphicsEffect(_shadow); + this->setGraphicsEffect(_shadow); + _msg->setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint); if (title){ @@ -77,7 +78,7 @@ DSMessageBox::DSMessageBox(QWidget *parent,const char *title) : _main_layout->addWidget(_msg); _layout->addWidget(_main_widget); - setLayout(_layout); + setLayout(_layout); connect(_msg, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(on_button(QAbstractButton*))); } diff --git a/DSView/pv/dialogs/dsomeasure.cpp b/DSView/pv/dialogs/dsomeasure.cpp index a25e7307..7e9825ef 100755 --- a/DSView/pv/dialogs/dsomeasure.cpp +++ b/DSView/pv/dialogs/dsomeasure.cpp @@ -90,7 +90,6 @@ void DsoMeasure::add_measure(QWidget *widget, const view::DsoSignal *dsoSig) const int Column = 5; const int IconSizeForText = 5; QGridLayout *layout = new QGridLayout(widget); - layout->setMargin(0); layout->setSpacing(0); pv::view::DsoSignal *psig = const_cast(dsoSig); diff --git a/DSView/pv/dialogs/lissajousoptions.cpp b/DSView/pv/dialogs/lissajousoptions.cpp index 8f8456be..2ae27886 100755 --- a/DSView/pv/dialogs/lissajousoptions.cpp +++ b/DSView/pv/dialogs/lissajousoptions.cpp @@ -125,7 +125,6 @@ LissajousOptions::LissajousOptions(SigSession *session, QWidget *parent) : } _layout = new QGridLayout(); - _layout->setMargin(0); _layout->setSpacing(0); _layout->addWidget(lisa_label, 0, 0, 1, 2, Qt::AlignCenter); _layout->addWidget(_enable, 1, 0, 1, 1); diff --git a/DSView/pv/dialogs/mathoptions.cpp b/DSView/pv/dialogs/mathoptions.cpp index 21e2d6ab..afc2e9f9 100755 --- a/DSView/pv/dialogs/mathoptions.cpp +++ b/DSView/pv/dialogs/mathoptions.cpp @@ -139,8 +139,7 @@ MathOptions::MathOptions(SigSession *session, QWidget *parent) : } } - _layout = new QGridLayout(); - _layout->setMargin(0); + _layout = new QGridLayout(); _layout->setSpacing(0); _layout->addWidget(lisa_label, 0, 0, 1, 2, Qt::AlignCenter); _layout->addWidget(_enable, 1, 0, 1, 1); diff --git a/DSView/pv/dialogs/protocolexp.cpp b/DSView/pv/dialogs/protocolexp.cpp index b9445c60..7a9e6104 100755 --- a/DSView/pv/dialogs/protocolexp.cpp +++ b/DSView/pv/dialogs/protocolexp.cpp @@ -37,6 +37,7 @@ #include "../view/decodetrace.h" #include "../data/decodermodel.h" #include "../config/appconfig.h" +#include "../dsvdef.h" using namespace boost; using namespace std; @@ -148,7 +149,7 @@ void ProtocolExp::accept() QFile file(file_name); file.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream out(&file); - out.setCodec("UTF-8"); + app::set_utf8(out); //out.setGenerateByteOrderMark(true); // UTF-8 without BOM QFuture future; diff --git a/DSView/pv/dialogs/regionoptions.cpp b/DSView/pv/dialogs/regionoptions.cpp index 62ff127a..ce71775d 100755 --- a/DSView/pv/dialogs/regionoptions.cpp +++ b/DSView/pv/dialogs/regionoptions.cpp @@ -43,7 +43,7 @@ RegionOptions::RegionOptions(view::View *view, SigSession *session, QWidget *par Qt::Horizontal, this) { QHBoxLayout *hlayout = new QHBoxLayout(); - hlayout->setMargin(0); + hlayout->setContentsMargins(0,0,0,0); hlayout->setSpacing(0); _start_comboBox = new QComboBox(this); _end_comboBox = new QComboBox(this); diff --git a/DSView/pv/dialogs/search.cpp b/DSView/pv/dialogs/search.cpp index 7f562068..406f1be8 100755 --- a/DSView/pv/dialogs/search.cpp +++ b/DSView/pv/dialogs/search.cpp @@ -23,7 +23,7 @@ #include "../view/logicsignal.h" #include -#include +#include namespace pv { @@ -39,8 +39,8 @@ Search::Search(QWidget *parent, SigSession *session, std::map font.setFixedPitch(true); //this->setMinimumWidth(350); - QRegExp value_rx("[10XRFCxrfc]+"); - QValidator *value_validator = new QRegExpValidator(value_rx, this); + QRegularExpression value_rx("[10XRFCxrfc]+"); + QValidator *value_validator = new QRegularExpressionValidator(value_rx, this); search_buttonBox.addButton(QDialogButtonBox::Ok); search_buttonBox.addButton(QDialogButtonBox::Cancel); diff --git a/DSView/pv/dialogs/shadow.cpp b/DSView/pv/dialogs/shadow.cpp index c6fd3426..0fc91ee4 100755 --- a/DSView/pv/dialogs/shadow.cpp +++ b/DSView/pv/dialogs/shadow.cpp @@ -94,7 +94,7 @@ void Shadow::draw(QPainter* painter) painter->setWorldTransform(restoreTransform); } -QRectF Shadow::boundingRectFor(const QRectF& rect) +QRectF Shadow::boundingRectFor(const QRectF& rect) const { qreal delta = blurRadius() + distance(); return rect.united(rect.adjusted(-delta, -delta, delta, delta)); diff --git a/DSView/pv/dialogs/shadow.h b/DSView/pv/dialogs/shadow.h index 952aad24..e37bbbad 100755 --- a/DSView/pv/dialogs/shadow.h +++ b/DSView/pv/dialogs/shadow.h @@ -36,16 +36,16 @@ public: explicit Shadow(QObject *parent = 0); void draw(QPainter* painter); - QRectF boundingRectFor(const QRectF& rect); + QRectF boundingRectFor(const QRectF& rect) const; inline void setDistance(qreal distance) { _distance = distance; updateBoundingRect(); } - inline qreal distance() { return _distance; } + inline qreal distance() const { return _distance; } inline void setBlurRadius(qreal blurRadius) { _blurRadius = blurRadius; updateBoundingRect(); } - inline qreal blurRadius() { return _blurRadius; } + inline qreal blurRadius() const { return _blurRadius; } inline void setColor(const QColor& color) { _color = color; } - inline QColor color() { return _color; } + inline QColor color() const { return _color; } private: qreal _distance; diff --git a/DSView/pv/dock/measuredock.cpp b/DSView/pv/dock/measuredock.cpp index f3b3f62a..68b983bd 100755 --- a/DSView/pv/dock/measuredock.cpp +++ b/DSView/pv/dock/measuredock.cpp @@ -38,8 +38,7 @@ #include "../dialogs/dsmessagebox.h" #include -#include -#include +#include #include #include "../config/appconfig.h" diff --git a/DSView/pv/dock/protocoldock.cpp b/DSView/pv/dock/protocoldock.cpp index a9affcdc..ba3f0282 100755 --- a/DSView/pv/dock/protocoldock.cpp +++ b/DSView/pv/dock/protocoldock.cpp @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include #include @@ -696,7 +696,7 @@ void ProtocolDock::search_nxt() void ProtocolDock::search_done() { QString str = _search_edit->text().trimmed(); - QRegExp rx("(-)"); + QRegularExpression rx("(-)"); _str_list = str.split(rx); _model_proxy.setFilterFixedString(_str_list.first()); if (_str_list.size() > 1) diff --git a/DSView/pv/dock/searchdock.cpp b/DSView/pv/dock/searchdock.cpp index 33c56f66..bc3de15f 100755 --- a/DSView/pv/dock/searchdock.cpp +++ b/DSView/pv/dock/searchdock.cpp @@ -32,8 +32,7 @@ #include "../dialogs/dsmessagebox.h" #include -#include -#include +#include #include #include #include diff --git a/DSView/pv/dock/triggerdock.cpp b/DSView/pv/dock/triggerdock.cpp index 87fa9e94..d90da9fd 100755 --- a/DSView/pv/dock/triggerdock.cpp +++ b/DSView/pv/dock/triggerdock.cpp @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include #include @@ -566,8 +566,8 @@ void TriggerDock::setup_adv_tab() _stage_tabWidget->setUsesScrollButtons(false); const QString mask = "N N N N N N N N N N N N N N N N"; - QRegExp value_rx("[10XRFCxrfc ]+"); - QValidator *value_validator = new QRegExpValidator(value_rx, _stage_tabWidget); + QRegularExpression value_rx("[10XRFCxrfc ]+"); + QValidator *value_validator = new QRegularExpressionValidator(value_rx, _stage_tabWidget); for (int i = 0; i < TriggerStages; i++) { QComboBox *_logic_comboBox = new QComboBox(_stage_tabWidget); _logic_comboBox->addItem(tr("Or")); diff --git a/DSView/pv/dsvdef.cpp b/DSView/pv/dsvdef.cpp index 49d0e5df..0ad7c4ef 100644 --- a/DSView/pv/dsvdef.cpp +++ b/DSView/pv/dsvdef.cpp @@ -30,6 +30,14 @@ } #endif +#include + +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +#include +#else +#include +#endif + namespace DecoderDataFormat { int Parse(const char *name){ @@ -71,4 +79,13 @@ namespace app } return false; } + + void set_utf8(QTextStream &stream){ + #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + stream.setEncoding(QStringConverter::Utf8); + #else + QTextCodec *code=QTextCodec::codecForName("UTF-8"); + stream.setCodec(code); + #endif + } } diff --git a/DSView/pv/dsvdef.h b/DSView/pv/dsvdef.h index 9069c153..9a5ef516 100644 --- a/DSView/pv/dsvdef.h +++ b/DSView/pv/dsvdef.h @@ -34,6 +34,7 @@ #endif class QWidget; +class QTextStream; #define DESTROY_OBJECT(p) if((p)){delete (p); p = NULL;} #define DESTROY_QT_OBJECT(p) if((p)){((p))->deleteLater(); p = NULL;} @@ -41,6 +42,8 @@ class QWidget; #define RELEASE_ARRAY(a) for (auto ptr : (a)){delete ptr;} (a).clear(); +#define ABS_VAL(x) (x>0?x:-x) + namespace DecoderDataFormat { enum _data_format @@ -60,5 +63,7 @@ namespace app QWidget* get_app_window_instance(QWidget *ins, bool bSet); bool is_app_top_window(QWidget* w); + + void set_utf8(QTextStream &stream); } diff --git a/DSView/pv/mainframe.cpp b/DSView/pv/mainframe.cpp index fca633f7..173c1427 100755 --- a/DSView/pv/mainframe.cpp +++ b/DSView/pv/mainframe.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include "dsvdef.h" #include "config/appconfig.h" @@ -53,6 +54,13 @@ namespace pv { MainFrame::MainFrame() { + _layout = NULL; + _bDraging = false; + _hit_border = None; + _freezing = false; + _titleBar = NULL; + _mainWindow = NULL; + setAttribute(Qt::WA_TranslucentBackground); // Make this a borderless window which can't // be resized or moved via the window system @@ -61,23 +69,17 @@ MainFrame::MainFrame() #else setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint); #endif + setMinimumHeight(minHeight); setMinimumWidth(minWidth); - //resize(1024, 768); - + // Set the window icon QIcon icon; - icon.addFile(QString::fromUtf8(":/icons/logo.svg"), - QSize(), QIcon::Normal, QIcon::Off); + icon.addFile(QString::fromUtf8(":/icons/logo.svg"), QSize(), QIcon::Normal, QIcon::Off); setWindowIcon(icon); app::get_app_window_instance(this, true); - - _bDraging = false; - _hit_border = None; - _freezing = false; - _minimized = false; - + // Title _titleBar = new toolbars::TitleBar(true, this); @@ -87,7 +89,7 @@ MainFrame::MainFrame() _titleBar->setTitle(_mainWindow->windowTitle()); QVBoxLayout *vbox = new QVBoxLayout(); - vbox->setMargin(0); + vbox->setContentsMargins(0,0,0,0); vbox->setSpacing(0); vbox->addWidget(_titleBar); vbox->addWidget(_mainWindow); @@ -120,8 +122,8 @@ MainFrame::MainFrame() _bottom_right->installEventFilter(this); _layout = new QGridLayout(this); - _layout->setMargin(0); _layout->setSpacing(0); + _layout->setContentsMargins(0,0,0,0); _layout->addWidget(_top_left, 0, 0); _layout->addWidget(_top, 0, 1); _layout->addWidget(_top_right, 0, 2); @@ -132,28 +134,17 @@ MainFrame::MainFrame() _layout->addWidget(_bottom, 2, 1); _layout->addWidget(_bottom_right, 2, 2); - connect(&_timer, SIGNAL(timeout()), this, SLOT(unfreezing())); - //readSettings(); - + connect(&_timer, SIGNAL(timeout()), this, SLOT(unfreezing())); } - -void MainFrame::changeEvent(QEvent* event) -{ - QFrame::changeEvent(event); - QWindowStateChangeEvent* win_event = static_cast< QWindowStateChangeEvent* >(event); - if(win_event->type() == QEvent::WindowStateChange) { - if (win_event->oldState() & Qt::WindowMinimized) { - if (_minimized) { - readSettings(); - _minimized = false; - } - } - } -} - + void MainFrame::resizeEvent(QResizeEvent *event) { QFrame::resizeEvent(event); + + if (_layout == NULL){ + return; + } + if (isMaximized()) { hide_border(); } else { @@ -201,19 +192,18 @@ void MainFrame::show_border() void MainFrame::showNormal() { - show_border(); + show_border(); QFrame::showNormal(); } void MainFrame::showMaximized() -{ +{ hide_border(); QFrame::showMaximized(); } void MainFrame::showMinimized() -{ - _minimized = true; +{ writeSettings(); QFrame::showMinimized(); } @@ -285,57 +275,69 @@ bool MainFrame::eventFilter(QObject *object, QEvent *event) newLeft = mouse_event->globalX(); if (newHeight > minimumHeight()) newTop = mouse_event->globalY(); - setGeometry(newLeft, newTop, - newWidth, newHeight); + setGeometry(newLeft, newTop, newWidth, newHeight); + saveWindowRegion(); break; + case BottomLeft: newWidth = std::max(_dragStartGeometry.right() - mouse_event->globalX(), minimumWidth()); newHeight = std::max(mouse_event->globalY() - _dragStartGeometry.top(), minimumHeight()); newLeft = geometry().left(); if (newWidth > minimumWidth()) newLeft = mouse_event->globalX(); - setGeometry(newLeft, _dragStartGeometry.top(), - newWidth, newHeight); + setGeometry(newLeft, _dragStartGeometry.top(), newWidth, newHeight); + saveWindowRegion(); break; + case TopRight: newWidth = std::max(mouse_event->globalX() - _dragStartGeometry.left(), minimumWidth()); newHeight = std::max(_dragStartGeometry.bottom() - mouse_event->globalY(), minimumHeight()); newTop = geometry().top(); if (newHeight > minimumHeight()) newTop = mouse_event->globalY(); - setGeometry(_dragStartGeometry.left(), newTop, - newWidth, newHeight); + setGeometry(_dragStartGeometry.left(), newTop, newWidth, newHeight); + saveWindowRegion(); break; + case BottomRight: newWidth = std::max(mouse_event->globalX() - _dragStartGeometry.left(), minimumWidth()); newHeight = std::max(mouse_event->globalY() - _dragStartGeometry.top(), minimumHeight()); - setGeometry(_dragStartGeometry.left(), _dragStartGeometry.top(), - newWidth, newHeight); + setGeometry(_dragStartGeometry.left(), _dragStartGeometry.top(), newWidth, newHeight); + saveWindowRegion(); break; + case Left: newWidth = _dragStartGeometry.right() - mouse_event->globalX(); - if (newWidth > minimumWidth()) - setGeometry(mouse_event->globalX(), _dragStartGeometry.top(), - newWidth, height()); + if (newWidth > minimumWidth()){ + setGeometry(mouse_event->globalX(), _dragStartGeometry.top(), newWidth, height()); + saveWindowRegion(); + } break; + case Right: newWidth = mouse_event->globalX() - _dragStartGeometry.left(); - if (newWidth > minimumWidth()) - setGeometry(_dragStartGeometry.left(), _dragStartGeometry.top(), - newWidth, height()); + if (newWidth > minimumWidth()){ + setGeometry(_dragStartGeometry.left(), _dragStartGeometry.top(), newWidth, height()); + saveWindowRegion(); + } break; + case Top: newHeight = _dragStartGeometry.bottom() - mouse_event->globalY(); - if (newHeight > minimumHeight()) - setGeometry(_dragStartGeometry.left(), mouse_event->globalY(), - width(), newHeight); + if (newHeight > minimumHeight()){ + setGeometry(_dragStartGeometry.left(), mouse_event->globalY(),width(), newHeight); + saveWindowRegion(); + } break; + case Bottom: newHeight = mouse_event->globalY() - _dragStartGeometry.top(); - if (newHeight > minimumHeight()) - setGeometry(_dragStartGeometry.left(), _dragStartGeometry.top(), - width(), newHeight); + if (newHeight > minimumHeight()){ + setGeometry(_dragStartGeometry.left(), _dragStartGeometry.top(), width(), newHeight); + saveWindowRegion(); + } break; + default: break; } @@ -366,39 +368,59 @@ bool MainFrame::eventFilter(QObject *object, QEvent *event) return QFrame::eventFilter(object, event); } + void MainFrame::saveWindowRegion() + { + AppConfig &app = AppConfig::Instance(); + QRect rc = geometry(); + app._frameOptions.left = rc.left(); + app._frameOptions.top = rc.top(); + app._frameOptions.right = rc.right(); + app._frameOptions.bottom = rc.bottom(); + } + void MainFrame::writeSettings() { AppConfig &app = AppConfig::Instance(); - app._frameOptions.isMax = isMaximized(); - app._frameOptions.geometry = saveGeometry(); + app._frameOptions.isMax = isMaximized(); + + if (!isMaximized()){ + saveWindowRegion(); + } + app.SaveFrame(); } void MainFrame::readSettings() { + if (_layout == NULL) + return; + AppConfig &app = AppConfig::Instance(); if (app._frameOptions.language > 0){ _mainWindow->switchLanguage(app._frameOptions.language); } - if (app._frameOptions.geometry.isEmpty()) { + if (app._frameOptions.right == 0) { QScreen *screen=QGuiApplication::primaryScreen (); const QRect availableGeometry = screen->availableGeometry(); resize(availableGeometry.width() / 2, availableGeometry.height() / 1.5); const int origX = std::max(0, (availableGeometry.width() - width()) / 2); const int origY = std::max(0, (availableGeometry.height() - height()) / 2); move(origX, origY); + } else { - try - { - QByteArray ge = app._frameOptions.geometry; - restoreGeometry(ge); - } - catch(...) - { - MsgBox::Show(NULL, "restore frame status error!"); - } + if (app._frameOptions.isMax){ + showMaximized(); //show max by system api + } + else{ + int left = app._frameOptions.left; + int top = app._frameOptions.top; + int right = app._frameOptions.right; + int bottom = app._frameOptions.bottom; + resize(right-left, bottom-top); + move(left, top); + } } // restore dockwidgets diff --git a/DSView/pv/mainframe.h b/DSView/pv/mainframe.h index e04ac0ee..25b8df4b 100755 --- a/DSView/pv/mainframe.h +++ b/DSView/pv/mainframe.h @@ -69,8 +69,7 @@ public: void readSettings(); -protected: - void changeEvent(QEvent* event); +protected: void resizeEvent(QResizeEvent *event); void closeEvent(QCloseEvent *event); bool eventFilter(QObject *object, QEvent *event); @@ -86,8 +85,8 @@ public slots: private: void hide_border(); void show_border(); - void writeSettings(); + void saveWindowRegion(); private: toolbars::TitleBar *_titleBar; @@ -107,8 +106,7 @@ private: QRect _dragStartGeometry; int _hit_border; QTimer _timer; - bool _freezing; - bool _minimized; + bool _freezing; }; } // namespace pv diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index e1fa249c..0869e39b 100755 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include "mainwindow.h" @@ -84,6 +85,7 @@ #include "../ui/msgbox.h" #include "config/appconfig.h" #include "appcontrol.h" +#include "../dsvdef.h" namespace pv { @@ -117,7 +119,6 @@ void MainWindow::setup_ui() setObjectName(QString::fromUtf8("MainWindow")); setContentsMargins(0,0,0,0); - layout()->setMargin(0); layout()->setSpacing(0); // Setup the central widget @@ -1140,7 +1141,8 @@ bool MainWindow::on_store_session(QString name) return false; } QTextStream outStream(&sessionFile); - outStream.setCodec("UTF-8"); + app::set_utf8(outStream); + //outStream.setGenerateByteOrderMark(true); // UTF-8 without BOM AppConfig &app = AppConfig::Instance(); diff --git a/DSView/pv/prop/binding/deviceoptions.cpp b/DSView/pv/prop/binding/deviceoptions.cpp index 1b4f1b15..a0e051c2 100755 --- a/DSView/pv/prop/binding/deviceoptions.cpp +++ b/DSView/pv/prop/binding/deviceoptions.cpp @@ -24,6 +24,7 @@ #include #include +#include #include @@ -191,7 +192,7 @@ void DeviceOptions::bind_enum(const QString &name, const QString label, int key, } void DeviceOptions::bind_int(const QString &name, const QString label, int key, QString suffix, - optional< std::pair > range) + boost::optional< std::pair > range) { _properties.push_back( new Int(name, label, suffix, range, @@ -200,7 +201,7 @@ void DeviceOptions::bind_int(const QString &name, const QString label, int key, } void DeviceOptions::bind_double(const QString &name, const QString label, int key, QString suffix, - optional< std::pair > range, + boost::optional< std::pair > range, int decimals, boost::optional step) { _properties.push_back( diff --git a/DSView/pv/prop/binding/probeoptions.cpp b/DSView/pv/prop/binding/probeoptions.cpp index be3806c9..cf916b04 100755 --- a/DSView/pv/prop/binding/probeoptions.cpp +++ b/DSView/pv/prop/binding/probeoptions.cpp @@ -163,7 +163,7 @@ void ProbeOptions::bind_enum(const QString &name, const QString label, int key, } void ProbeOptions::bind_int(const QString &name, const QString label, int key, QString suffix, - optional< std::pair > range) + boost::optional< std::pair > range) { _properties.push_back( new Int(name, label, suffix, range, @@ -172,7 +172,7 @@ void ProbeOptions::bind_int(const QString &name, const QString label, int key, Q } void ProbeOptions::bind_double(const QString &name, const QString label, int key, QString suffix, - optional< std::pair > range, + boost::optional< std::pair > range, int decimals, boost::optional step) { _properties.push_back( diff --git a/DSView/pv/prop/double.cpp b/DSView/pv/prop/double.cpp index 2c832d9a..b5c7c3d7 100755 --- a/DSView/pv/prop/double.cpp +++ b/DSView/pv/prop/double.cpp @@ -35,8 +35,8 @@ namespace prop { Double::Double(QString name, QString label, int decimals, QString suffix, - optional< pair > range, - optional step, + boost::optional< pair > range, + boost::optional step, Getter getter, Setter setter) : Property(name, label, getter, setter), diff --git a/DSView/pv/prop/int.cpp b/DSView/pv/prop/int.cpp index ac7961ee..3648193d 100755 --- a/DSView/pv/prop/int.cpp +++ b/DSView/pv/prop/int.cpp @@ -51,7 +51,7 @@ namespace prop { Int::Int(QString name, QString label, QString suffix, - optional< pair > range, + boost::optional< pair > range, Getter getter, Setter setter) : Property(name, label, getter, setter), diff --git a/DSView/pv/storesession.cpp b/DSView/pv/storesession.cpp index a621dc8e..322ebd5f 100755 --- a/DSView/pv/storesession.cpp +++ b/DSView/pv/storesession.cpp @@ -52,22 +52,9 @@ #include #include "config/appconfig.h" +#include "dsvdef.h" -namespace pv { - - char chunk_name[30] = {0}; - - void MakeChunkName(int chunk_num, int index, int type, int version){ - if (version == 2) { - const char *type_name = NULL; - type_name = (type == SR_CHANNEL_LOGIC) ? "L" : - (type == SR_CHANNEL_DSO) ? "O" : - (type == SR_CHANNEL_ANALOG) ? "A" : "U"; - snprintf(chunk_name, 15, "%s-%d/%d", type_name, index, chunk_num); - } else { - snprintf(chunk_name, 15, "data"); - } - } +namespace pv { StoreSession::StoreSession(SigSession *session) : _session(session), @@ -188,7 +175,7 @@ bool StoreSession::save_start() */ //make zip file - if (meta_file != NULL && m_zipDoc.CreateNew(_file_name.toUtf8().data(), false)) + if (meta_file != "" && m_zipDoc.CreateNew(_file_name.toUtf8().data(), false)) { if (!m_zipDoc.AddFromFile(meta_file.toUtf8().data(), "header") || !m_zipDoc.AddFromFile(decoders_file.toUtf8().data(), "decoders") @@ -214,6 +201,8 @@ void StoreSession::save_proc(data::Snapshot *snapshot) { assert(snapshot); + char chunk_name[20] = {0}; + int ret = SR_ERR; int num = 0; data::LogicSnapshot *logic_snapshot = NULL; @@ -253,7 +242,7 @@ void StoreSession::save_proc(data::Snapshot *snapshot) // ret = sr_session_append(_file_name.toUtf8().data(), buf, size, // i, ch_index, ch_type, File_Version); - MakeChunkName(i, ch_index, ch_type, File_Version); + MakeChunkName(chunk_name, i, ch_index, ch_type, File_Version); ret = m_zipDoc.AddFromBuffer(chunk_name, (const char*)buf, size) ? SR_OK : -1; if (ret != SR_OK) { @@ -304,7 +293,7 @@ void StoreSession::save_proc(data::Snapshot *snapshot) // ret = sr_session_append(_file_name.toUtf8().data(), tmp, size, // i, 0, ch_type, File_Version); - MakeChunkName(i, 0, ch_type, File_Version); + MakeChunkName(chunk_name, i, 0, ch_type, File_Version); ret = m_zipDoc.AddFromBuffer(chunk_name, (const char*)tmp, size) ? SR_OK : -1; buf += (size - _unit_count); @@ -315,7 +304,7 @@ void StoreSession::save_proc(data::Snapshot *snapshot) // ret = sr_session_append(_file_name.toUtf8().data(), buf, size, // i, 0, ch_type, File_Version); - MakeChunkName(i, 0, ch_type, File_Version); + MakeChunkName(chunk_name, i, 0, ch_type, File_Version); ret = m_zipDoc.AddFromBuffer(chunk_name, (const char*)buf, size) ? SR_OK : -1; buf += size; @@ -646,8 +635,8 @@ void StoreSession::export_proc(data::Snapshot *snapshot) QFile file(_file_name); file.open(QIODevice::WriteOnly | QIODevice::Text); - QTextStream out(&file); - out.setCodec("UTF-8"); + QTextStream out(&file); + app::set_utf8(out); //out.setGenerateByteOrderMark(true); // UTF-8 without BOM // Meta @@ -853,7 +842,7 @@ QString StoreSession::decoders_gen() return NULL; } QTextStream outStream(&sessionFile); - outStream.setCodec("UTF-8"); + app::set_utf8(outStream); //outStream.setGenerateByteOrderMark(true); // UTF-8 without BOM QJsonArray dec_array = json_decoders(); @@ -1293,5 +1282,22 @@ bool StoreSession::IsLogicDataType() return false; } +void StoreSession::MakeChunkName(char *chunk_name, int chunk_num, int index, int type, int version) +{ + chunk_name[0] = 0; + + if (version == 2) + { + const char *type_name = NULL; + type_name = (type == SR_CHANNEL_LOGIC) ? "L" : (type == SR_CHANNEL_DSO) ? "O" + : (type == SR_CHANNEL_ANALOG) ? "A" + : "U"; + snprintf(chunk_name, 15, "%s-%d/%d", type_name, index, chunk_num); + } + else + { + snprintf(chunk_name, 15, "data"); + } +} } // pv diff --git a/DSView/pv/storesession.h b/DSView/pv/storesession.h index daadef74..99db9f12 100755 --- a/DSView/pv/storesession.h +++ b/DSView/pv/storesession.h @@ -93,6 +93,7 @@ public: private: QList getSuportedExportFormats(); double get_integer(GVariant * var); + void MakeChunkName(char *chunk_name, int chunk_num, int index, int type, int version); signals: void progress_updated(); diff --git a/DSView/pv/toolbars/samplingbar.cpp b/DSView/pv/toolbars/samplingbar.cpp index 33f52c72..50ceebe8 100755 --- a/DSView/pv/toolbars/samplingbar.cpp +++ b/DSView/pv/toolbars/samplingbar.cpp @@ -75,7 +75,6 @@ SamplingBar::SamplingBar(SigSession *session, QWidget *parent) : { setMovable(false); setContentsMargins(0,0,0,0); - layout()->setMargin(0); layout()->setSpacing(0); _mode_button.setPopupMode(QToolButton::InstantPopup); diff --git a/DSView/pv/toolbars/titlebar.cpp b/DSView/pv/toolbars/titlebar.cpp index d52b18fc..982fab1d 100755 --- a/DSView/pv/toolbars/titlebar.cpp +++ b/DSView/pv/toolbars/titlebar.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -39,26 +40,26 @@ namespace toolbars { TitleBar::TitleBar(bool top, QWidget *parent, bool hasClose) : QWidget(parent) -{ - _title = NULL; +{ _minimizeButton = NULL; _maximizeButton = NULL; _closeButton = NULL; - _lay = NULL; _moving = false; _parent = parent; _isTop = top; _hasClose = hasClose; + _title = NULL; assert(parent); setObjectName("TitleBar"); setContentsMargins(0,0,0,0); - setFixedHeight(32); + setFixedHeight(32); + + QHBoxLayout *lay1 = new QHBoxLayout(this); _title = new QLabel(this); - _lay = new QHBoxLayout(this); - _lay->addWidget(_title); + lay1->addWidget(_title); if (_isTop) { _minimizeButton = new QToolButton(this); @@ -66,8 +67,8 @@ TitleBar::TitleBar(bool top, QWidget *parent, bool hasClose) : _maximizeButton = new QToolButton(this); _maximizeButton->setObjectName("MaximizeButton"); - _lay->addWidget(_minimizeButton); - _lay->addWidget(_maximizeButton); + lay1->addWidget(_minimizeButton); + lay1->addWidget(_maximizeButton); connect(this, SIGNAL(normalShow()), parent, SLOT(showNormal())); connect(this, SIGNAL( maximizedShow()), parent, SLOT(showMaximized())); @@ -78,24 +79,22 @@ TitleBar::TitleBar(bool top, QWidget *parent, bool hasClose) : if (_isTop || _hasClose) { _closeButton= new QToolButton(this); _closeButton->setObjectName("CloseButton"); - _lay->addWidget(_closeButton); + lay1->addWidget(_closeButton); connect(_closeButton, SIGNAL( clicked()), parent, SLOT(close())); } - _lay->insertStretch(0, 500); - _lay->insertStretch(2, 500); - _lay->setMargin(0); - _lay->setSpacing(0); + lay1->insertStretch(0, 500); + lay1->insertStretch(2, 500); + lay1->setContentsMargins(0,0,0,0); + lay1->setSpacing(0); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); } -TitleBar::~TitleBar(){ - DESTROY_QT_OBJECT(_title); +TitleBar::~TitleBar(){ DESTROY_QT_OBJECT(_minimizeButton); DESTROY_QT_OBJECT(_maximizeButton); DESTROY_QT_OBJECT(_closeButton); - DESTROY_QT_OBJECT(_lay); } void TitleBar::changeEvent(QEvent *event) diff --git a/DSView/pv/toolbars/titlebar.h b/DSView/pv/toolbars/titlebar.h index 97245223..47d937fa 100755 --- a/DSView/pv/toolbars/titlebar.h +++ b/DSView/pv/toolbars/titlebar.h @@ -23,9 +23,10 @@ #define DSVIEW_PV_TOOLBARS_TITLEBAR_H #include -class QLabel; + class QToolButton; class QHBoxLayout; +class QLabel; namespace pv { namespace toolbars { @@ -61,12 +62,12 @@ protected: void mouseReleaseEvent(QMouseEvent *event); void mouseDoubleClickEvent(QMouseEvent *event); - QLabel *_title; + QToolButton *_minimizeButton; QToolButton *_maximizeButton; QToolButton *_closeButton; - QHBoxLayout *_lay; - + QLabel *_title; + bool _moving; bool _isTop; bool _hasClose; diff --git a/DSView/pv/ui/msgbox.cpp b/DSView/pv/ui/msgbox.cpp index 88b415db..3b10c38e 100644 --- a/DSView/pv/ui/msgbox.cpp +++ b/DSView/pv/ui/msgbox.cpp @@ -34,8 +34,12 @@ void MsgBox::Show(const char *title, const char *text, QWidget *parent) { assert(text); + QString str; + str.append("\n"); + str.append(text); + pv::dialogs::DSMessageBox msg(parent, title); - msg.mBox()->setText(QString(text)); + msg.mBox()->setText(str); // msg.mBox()->setInformativeText(QString(text)); msg.mBox()->setStandardButtons(QMessageBox::Ok); msg.mBox()->setIcon(QMessageBox::Warning); @@ -46,8 +50,12 @@ bool MsgBox::Confirm(const char *text, QWidget *parent) { assert(text); + QString str; + str.append("\n"); + str.append(text); + pv::dialogs::DSMessageBox msg(parent, "Question"); - msg.mBox()->setText(QString(text)); + msg.mBox()->setText(str); msg.mBox()->setStandardButtons(QMessageBox::Yes | QMessageBox::No); msg.mBox()->setIcon(QMessageBox::Question); msg.exec(); diff --git a/DSView/pv/view/decodetrace.cpp b/DSView/pv/view/decodetrace.cpp index 8cc1b1a8..1de94a9b 100755 --- a/DSView/pv/view/decodetrace.cpp +++ b/DSView/pv/view/decodetrace.cpp @@ -351,6 +351,7 @@ bool DecodeTrace::create_popup() int ret = false; //setting have changed flag dialogs::DSDialog dlg; + //dlg.setMinimumSize(500,600); create_popup_form(&dlg); if (QDialog::Accepted == dlg.exec()) diff --git a/DSView/pv/view/devmode.cpp b/DSView/pv/view/devmode.cpp index 58b31fe5..a69f082d 100755 --- a/DSView/pv/view/devmode.cpp +++ b/DSView/pv/view/devmode.cpp @@ -47,7 +47,6 @@ DevMode::DevMode(QWidget *parent, SigSession *session) : { _layout = new QHBoxLayout(this); - _layout->setMargin(0); _layout->setSpacing(0); _layout->setContentsMargins(2, 0, 0, 0); @@ -71,8 +70,7 @@ DevMode::DevMode(QWidget *parent, SigSession *session) : _mode_btn->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum); _layout->addWidget(_close_button); - _layout->addWidget(_mode_btn); - //_layout->addWidget(new QWidget(this)); + _layout->addWidget(_mode_btn); _layout->setStretch(1, 100); setLayout(_layout); } diff --git a/DSView/pv/view/header.cpp b/DSView/pv/view/header.cpp index 90b734f4..b3aed97f 100755 --- a/DSView/pv/view/header.cpp +++ b/DSView/pv/view/header.cpp @@ -20,20 +20,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "header.h" -#include "view.h" - -#include "../../extdef.h" -#include "trace.h" -#include "dsosignal.h" -#include "logicsignal.h" -#include "analogsignal.h" -#include "groupsignal.h" -#include "decodetrace.h" -#include "../sigsession.h" -#include "../device/devinst.h" - -#include +#include "header.h" #include #include @@ -43,6 +30,20 @@ #include #include #include +#include + +#include "view.h" +#include "trace.h" +#include "dsosignal.h" +#include "logicsignal.h" +#include "analogsignal.h" +#include "groupsignal.h" +#include "decodetrace.h" +#include "../sigsession.h" +#include "../device/devinst.h" +#include "../../extdef.h" +#include "../dsvdef.h" + using namespace std; @@ -253,33 +254,74 @@ void Header::wheelEvent(QWheelEvent *event) { assert(event); - if (event->orientation() == Qt::Vertical) { + int x = 0; + int y = 0; + int delta = 0; + bool isVertical = true; + QPoint pos; + (void)x; + (void)y; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + x = (int)event->position().x(); + y = (int)event->position().y(); + int anglex = event->angleDelta().x(); + int angley = event->angleDelta().y(); + + pos.setX(x); + pos.setY(y); + + if (anglex == 0 || ABS_VAL(angley) >= ABS_VAL(anglex)){ + delta = angley; + isVertical = true; + } + else{ + delta = anglex; + isVertical = false; //hori direction + } +#else + x = event->x(); + delta = event->delta(); + isVertical = event->orientation() == Qt::Vertical; + pos = event->pos(); +#endif + + if (isVertical) + { const auto &traces = _view.get_traces(ALL_VIEW); // Vertical scrolling double shift = 0; - #ifdef Q_OS_DARWIN + +#ifdef Q_OS_DARWIN static bool active = true; static int64_t last_time; - if (event->source() == Qt::MouseEventSynthesizedBySystem) { - if (active) { + if (event->source() == Qt::MouseEventSynthesizedBySystem) + { + if (active) + { last_time = QDateTime::currentMSecsSinceEpoch(); - shift = event->delta() > 1.5 ? -1 : - event->delta() < -1.5 ? 1 : 0; + shift = delta > 1.5 ? -1 : delta < -1.5 ? 1 : 0; } int64_t cur_time = QDateTime::currentMSecsSinceEpoch(); if (cur_time - last_time > 100) active = true; else active = false; - } else { - shift = -event->delta() / 80.0; } - #else - shift = event->delta() / 80.0; - #endif - for(auto &t : traces) - if (t->mouse_wheel(width(), event->pos(), shift)) + else + { + shift = -delta / 80.0; + } +#else + shift = delta / 80.0; +#endif + + for (auto &t : traces) + { + if (t->mouse_wheel(width(), pos, shift)) break; + } + update(); } } diff --git a/DSView/pv/view/ruler.cpp b/DSView/pv/view/ruler.cpp index 100292c4..25c54a95 100755 --- a/DSView/pv/view/ruler.cpp +++ b/DSView/pv/view/ruler.cpp @@ -28,8 +28,7 @@ #include "../sigsession.h" #include "../device/devinst.h" #include "dsosignal.h" - -#include +#include "../../extdef.h" #include #include @@ -38,10 +37,11 @@ #include #include #include -#include +#include using namespace std; +using namespace Qt; namespace pv { namespace view { diff --git a/DSView/pv/view/viewport.cpp b/DSView/pv/view/viewport.cpp index 3ca32160..ff65b2fd 100755 --- a/DSView/pv/view/viewport.cpp +++ b/DSView/pv/view/viewport.cpp @@ -38,7 +38,9 @@ #include #include #include -#include +#include +#include +#include #include "../config/appconfig.h" #include "../dsvdef.h" @@ -1023,54 +1025,86 @@ void Viewport::mouseDoubleClickEvent(QMouseEvent *event) void Viewport::wheelEvent(QWheelEvent *event) { - assert(event); + assert(event); - if (_type == FFT_VIEW) { - for(auto &t : _view.session().get_spectrum_traces()) { - assert(t); - if(t->enabled()) { - t->zoom(event->delta() / 80, event->x()); + int x = 0; //mouse x pos + int delta = 0; + bool isVertical = true; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + x = (int)event->position().x(); + int anglex = event->angleDelta().x(); + int angley = event->angleDelta().y(); + + if (anglex == 0 || ABS_VAL(angley) >= ABS_VAL(anglex)){ + delta = angley; + isVertical = true; + } + else{ + delta = anglex; + isVertical = false; //hori direction + } +#else + x = event->x(); + delta = event->delta(); + isVertical = event->orientation() == Qt::Vertical; +#endif + + if (_type == FFT_VIEW) + { + for (auto &t : _view.session().get_spectrum_traces()) + { + if (t->enabled()) + { + t->zoom(delta / 80, x); break; } } - } else if (_type == TIME_VIEW){ - if (event->orientation() == Qt::Vertical) { + } + else if (_type == TIME_VIEW) + { + if (isVertical) + { // Vertical scrolling is interpreted as zooming in/out - const int offset = event->x(); - #ifdef Q_OS_DARWIN +#ifdef Q_OS_DARWIN static bool active = true; static int64_t last_time; - if (event->source() == Qt::MouseEventSynthesizedBySystem) { - if (active && (event->modifiers() & Qt::ShiftModifier)) { + if (event->source() == Qt::MouseEventSynthesizedBySystem) + { + if (active && (event->modifiers() & Qt::ShiftModifier)) + { last_time = QDateTime::currentMSecsSinceEpoch(); - const double scale = event->delta() > 1.5 ? 1 : - event->delta() < -1.5 ? -1 : 0; - _view.zoom(scale, offset); + const double scale = delta > 1.5 ? 1 : (delta < -1.5 ? -1 : 0); + _view.zoom(scale, x); } int64_t cur_time = QDateTime::currentMSecsSinceEpoch(); if (cur_time - last_time > 50) active = true; else active = false; - } else { - _view.zoom(-event->delta() / 80, offset); } - #else - _view.zoom(event->delta() / 80, offset); - #endif - } else if (event->orientation() == Qt::Horizontal) { + else + { + _view.zoom(-delta / 80, x); + } +#else + _view.zoom(delta / 80, x); +#endif + } + else + { // Horizontal scrolling is interpreted as moving left/right if (!(event->modifiers() & Qt::ShiftModifier)) - _view.set_scale_offset(_view.scale(), - _view.offset() - event->delta()); + _view.set_scale_offset(_view.scale(), _view.offset() - delta); } } const auto &sigs = _view.session().get_signals(); - for(auto &s : sigs) { - assert(s); + for (auto &s : sigs) + { view::DsoSignal *dsoSig = NULL; - if ((dsoSig = dynamic_cast(s))) { + if ((dsoSig = dynamic_cast(s))) + { dsoSig->auto_end(); } } diff --git a/qtpro/DSView.pro b/qtpro/DSView.pro index f8e7fde1..5fd987c2 100644 --- a/qtpro/DSView.pro +++ b/qtpro/DSView.pro @@ -12,8 +12,10 @@ QT += svg } CONFIG += exceptions CONFIG += object_parallel_to_source + greaterThan(QT_MAJOR_VERSION, 4): CONFIG += c++11 greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + #QMAKE_CFLAGS_ISYSTEM = -I TARGET = DSView diff --git a/qtpro/DSView.pro.user b/qtpro/DSView.pro.user index cf656ba4..8871a8fc 100644 --- a/qtpro/DSView.pro.user +++ b/qtpro/DSView.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId From 0368988a8cf3da9a4b3d5413b3c1d3ce8bd5361c Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Tue, 23 Nov 2021 13:35:08 +0800 Subject: [PATCH 32/60] fix combobox's bug at macos --- DSView/DSView.desktop | 10 -- DSView/main.cpp | 11 +- DSView/pv/ZipMaker.cpp | 4 +- DSView/pv/appcontrol.cpp | 14 +- DSView/pv/dialogs/deviceoptions.cpp | 2 +- DSView/pv/dialogs/deviceoptions.h | 2 +- DSView/pv/dialogs/fftoptions.cpp | 22 +-- DSView/pv/dialogs/fftoptions.h | 18 +-- DSView/pv/dialogs/protocolexp.cpp | 2 +- DSView/pv/dialogs/protocolexp.h | 4 +- DSView/pv/dialogs/protocollist.cpp | 4 +- DSView/pv/dialogs/protocollist.h | 9 +- DSView/pv/dialogs/regionoptions.cpp | 4 +- DSView/pv/dialogs/regionoptions.h | 6 +- DSView/pv/dock/dsotriggerdock.cpp | 4 +- DSView/pv/dock/dsotriggerdock.h | 7 +- DSView/pv/dock/measuredock.cpp | 10 +- DSView/pv/dock/measuredock.h | 9 +- DSView/pv/dock/protocoldock.cpp | 10 +- DSView/pv/dock/protocoldock.h | 4 +- DSView/pv/dock/protocolitemlayer.cpp | 3 +- DSView/pv/dock/protocolitemlayer.h | 5 +- DSView/pv/dock/searchdock.cpp | 4 +- DSView/pv/dock/searchdock.h | 2 +- DSView/pv/dock/triggerdock.cpp | 12 +- DSView/pv/dock/triggerdock.h | 15 +- DSView/pv/dsvdef.h | 1 + DSView/pv/mainframe.cpp | 47 +++--- DSView/pv/mainwindow.cpp | 14 +- DSView/pv/prop/binding/probeoptions.cpp | 1 + DSView/pv/prop/enum.cpp | 4 +- DSView/pv/prop/enum.h | 4 +- DSView/pv/toolbars/samplingbar.cpp | 6 +- DSView/pv/toolbars/samplingbar.h | 8 +- DSView/pv/ui/dscombobox.cpp | 72 +++++++++ DSView/pv/ui/dscombobox.h | 46 ++++++ DSView/pv/view/decodetrace.cpp | 14 +- DSView/pv/view/decodetrace.h | 10 +- DSView/pv/view/spectrumtrace.cpp | 18 ++- DSView/pv/view/viewport.cpp | 4 +- DSView/pv/view/viewstatus.cpp | 7 +- libsigrok4DSL/config.h | 192 ++++++++++++++++++++++++ libsigrok4DSL/output/gnuplot.c | 2 +- qtpro/DSView.pro | 2 + qtpro/DSView.pro.user | 2 +- 45 files changed, 506 insertions(+), 145 deletions(-) delete mode 100755 DSView/DSView.desktop mode change 100755 => 100644 DSView/pv/mainframe.cpp mode change 100755 => 100644 DSView/pv/mainwindow.cpp create mode 100644 DSView/pv/ui/dscombobox.cpp create mode 100644 DSView/pv/ui/dscombobox.h create mode 100644 libsigrok4DSL/config.h diff --git a/DSView/DSView.desktop b/DSView/DSView.desktop deleted file mode 100755 index e1143240..00000000 --- a/DSView/DSView.desktop +++ /dev/null @@ -1,10 +0,0 @@ -[Desktop Entry] -Type=Application -Encoding=UTF-8 -Name=DSView -Comment=GUI Program for DreamSourceLab USB-based Instruments -TryExec=DSView -Exec=DSView -Icon=dsview -Terminal=false -Categories=Development;Electronics;Qt; diff --git a/DSView/main.cpp b/DSView/main.cpp index c0a15a47..210f9241 100755 --- a/DSView/main.cpp +++ b/DSView/main.cpp @@ -144,12 +144,13 @@ int main(int argc, char *argv[]) return 1; } else if (argcFinal - optind == 1) open_file = argvFinal[argcFinal - 1]; - - // Initialise DS_RES_PATH + QDir dir(QCoreApplication::applicationDirPath()); + +#ifdef Q_OS_LINUX if (dir.cd("..") && dir.cd("share") && - dir.cd(QApplication::applicationName()) && + dir.cd("DSView") && dir.cd("res")) { // the path command like: cd ../share/DSView/res QString res_dir = dir.absolutePath() + "/"; @@ -158,6 +159,10 @@ int main(int argc, char *argv[]) qDebug() << "DSView run ERROR: config files don't exist."; return 1; } +#endif + +//#ifdef Q_OS_DARWIN +//#endif //load app config AppConfig::Instance().LoadAll(); diff --git a/DSView/pv/ZipMaker.cpp b/DSView/pv/ZipMaker.cpp index bf57dd14..18e48fc6 100644 --- a/DSView/pv/ZipMaker.cpp +++ b/DSView/pv/ZipMaker.cpp @@ -23,7 +23,7 @@ #include "ZipMaker.h" #include -#include +#include #include #include #include @@ -251,7 +251,7 @@ const char *ZipMaker::GetError() unzOpenCurrentFile((unzFile)m_uzDoc); //read file data to buffer - void *buf = inf.pData; + char *buf = (char*)inf.pData; long long buflen = inf.dataLen; long long rdlen = 0; diff --git a/DSView/pv/appcontrol.cpp b/DSView/pv/appcontrol.cpp index 39461b2c..fb477aea 100644 --- a/DSView/pv/appcontrol.cpp +++ b/DSView/pv/appcontrol.cpp @@ -25,6 +25,8 @@ #include #include +#include +#include #include "devicemanager.h" #include "sigsession.h" @@ -72,7 +74,17 @@ bool AppControl::Init() } // const char *decoderScriptDir = "/home/lala/tmpdir/any"; - const char * decoderScriptDir = NULL; + //const char * decoderScriptDir = NULL; + + char decoderScriptDir[256] = {0}; + QDir dir(QCoreApplication::applicationDirPath()); +#ifdef Q_OS_LINUX + dir.cd("../share/DSView/decoders"); +#else + dir.cd("decoders"); +#endif + + strcpy(decoderScriptDir, dir.absolutePath().toUtf8().data()); // Initialise libsigrokdecode if (srd_init(decoderScriptDir) != SRD_OK) diff --git a/DSView/pv/dialogs/deviceoptions.cpp b/DSView/pv/dialogs/deviceoptions.cpp index ee506833..3fa3be2c 100755 --- a/DSView/pv/dialogs/deviceoptions.cpp +++ b/DSView/pv/dialogs/deviceoptions.cpp @@ -391,7 +391,7 @@ void DeviceOptions::analog_channel_check() } } dynamic_widget(_dynamic_layout); - _dynamic_box->setVisible(_dynamic_box->title() != NULL); + _dynamic_box->setVisible(_dynamic_box->title() != ""); } void DeviceOptions::channel_enable() diff --git a/DSView/pv/dialogs/deviceoptions.h b/DSView/pv/dialogs/deviceoptions.h index c09f83aa..7c4d1cdd 100755 --- a/DSView/pv/dialogs/deviceoptions.h +++ b/DSView/pv/dialogs/deviceoptions.h @@ -34,7 +34,6 @@ #include #include #include -#include #include #include @@ -44,6 +43,7 @@ #include "../prop/binding/probeoptions.h" #include "../toolbars/titlebar.h" #include "../dialogs/dsdialog.h" +#include "../ui/dscombobox.h" using namespace pv::device; diff --git a/DSView/pv/dialogs/fftoptions.cpp b/DSView/pv/dialogs/fftoptions.cpp index 5b8f44d7..10855971 100755 --- a/DSView/pv/dialogs/fftoptions.cpp +++ b/DSView/pv/dialogs/fftoptions.cpp @@ -31,6 +31,7 @@ #include "../view/trace.h" #include "../view/dsosignal.h" #include "../view/spectrumtrace.h" +#include "../dsvdef.h" using namespace boost; @@ -58,15 +59,15 @@ FftOptions::FftOptions(QWidget *parent, SigSession *session) : _layout = NULL; _en_checkbox = new QCheckBox(this); - _len_combobox = new QComboBox(this); - _interval_combobox = new QComboBox(this); - _ch_combobox = new QComboBox(this); - _window_combobox = new QComboBox(this); + _len_combobox = new DsComboBox(this); + _interval_combobox = new DsComboBox(this); + _ch_combobox = new DsComboBox(this); + _window_combobox = new DsComboBox(this); _dc_checkbox = new QCheckBox(this); _dc_checkbox->setChecked(true); - _view_combobox = new QComboBox(this); - _dbv_combobox = new QComboBox(this); - + _view_combobox = new DsComboBox(this); + _dbv_combobox = new DsComboBox(this); + // setup _ch_combobox for(auto &s : _session->get_signals()) { view::DsoSignal *dsoSig = NULL; @@ -217,9 +218,9 @@ FftOptions::FftOptions(QWidget *parent, SigSession *session) : connect(&_button_box, SIGNAL(accepted()), this, SLOT(accept())); connect(&_button_box, SIGNAL(rejected()), this, SLOT(reject())); - connect(_window_combobox, SIGNAL(currentIndexChanged(QString)), this, SLOT(window_changed(QString))); + connect(_window_combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(window_changed(int))); connect(_len_combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(len_changed(int))); - connect(_session->get_device(), SIGNAL(device_updated()), this, SLOT(reject())); + connect(_session->get_device(), SIGNAL(device_updated()), this, SLOT(reject())); } FftOptions::~FftOptions(){ @@ -261,8 +262,9 @@ void FftOptions::reject() QDialog::reject(); } -void FftOptions::window_changed(QString str) +void FftOptions::window_changed(int index) { + QString str = _window_combobox->itemText(index); QString hint_pic= ":/icons/" + str +".png"; QPixmap pixmap(hint_pic); _hint_label->setPixmap(pixmap); diff --git a/DSView/pv/dialogs/fftoptions.h b/DSView/pv/dialogs/fftoptions.h index b863d6d5..631713bf 100755 --- a/DSView/pv/dialogs/fftoptions.h +++ b/DSView/pv/dialogs/fftoptions.h @@ -27,13 +27,13 @@ #include #include #include -#include -#include +#include #include "../device/devinst.h" #include "../toolbars/titlebar.h" #include "dsdialog.h" +#include "../ui/dscombobox.h" namespace pv { @@ -58,21 +58,21 @@ protected: void reject(); private slots: - void window_changed(QString str); + void window_changed(int index); void len_changed(int index); private: SigSession *_session; uint64_t _sample_limit; - QComboBox *_len_combobox; - QComboBox *_interval_combobox; + DsComboBox *_len_combobox; + DsComboBox *_interval_combobox; QCheckBox *_en_checkbox; - QComboBox *_ch_combobox; - QComboBox *_window_combobox; + DsComboBox *_ch_combobox; + DsComboBox *_window_combobox; QCheckBox *_dc_checkbox; - QComboBox *_view_combobox; - QComboBox *_dbv_combobox; + DsComboBox *_view_combobox; + DsComboBox *_dbv_combobox; QLabel *_hint_label; QGridLayout *_glayout; diff --git a/DSView/pv/dialogs/protocolexp.cpp b/DSView/pv/dialogs/protocolexp.cpp index 7a9e6104..728410e5 100755 --- a/DSView/pv/dialogs/protocolexp.cpp +++ b/DSView/pv/dialogs/protocolexp.cpp @@ -52,7 +52,7 @@ ProtocolExp::ProtocolExp(QWidget *parent, SigSession *session) : Qt::Horizontal, this), _export_cancel(false) { - _format_combobox = new QComboBox(this); + _format_combobox = new DsComboBox(this); _format_combobox->addItem(tr("Comma-Separated Values (*.csv)")); _format_combobox->addItem(tr("Text files (*.txt)")); diff --git a/DSView/pv/dialogs/protocolexp.h b/DSView/pv/dialogs/protocolexp.h index 8688fd96..a4894459 100755 --- a/DSView/pv/dialogs/protocolexp.h +++ b/DSView/pv/dialogs/protocolexp.h @@ -28,12 +28,12 @@ #include #include #include -#include #include "../device/devinst.h" #include "../prop/binding/deviceoptions.h" #include "../toolbars/titlebar.h" #include "dsdialog.h" +#include "../ui/dscombobox.h" namespace pv { @@ -68,7 +68,7 @@ private: SigSession *_session; toolbars::TitleBar *_titlebar; - QComboBox *_format_combobox; + DsComboBox *_format_combobox; std::list _row_sel_list; std::list _row_label_list; QFormLayout *_flayout; diff --git a/DSView/pv/dialogs/protocollist.cpp b/DSView/pv/dialogs/protocollist.cpp index 4b094d90..4144cc58 100755 --- a/DSView/pv/dialogs/protocollist.cpp +++ b/DSView/pv/dialogs/protocollist.cpp @@ -45,7 +45,7 @@ ProtocolList::ProtocolList(QWidget *parent, SigSession *session) : { pv::data::DecoderModel* decoder_model = _session->get_decoder_model(); - _map_zoom_combobox = new QComboBox(this); + _map_zoom_combobox = new DsComboBox(this); _map_zoom_combobox->addItem(tr("Fit to Window")); _map_zoom_combobox->addItem(tr("Fixed")); int cur_map_zoom = _session->get_map_zoom(); @@ -57,7 +57,7 @@ ProtocolList::ProtocolList(QWidget *parent, SigSession *session) : connect(_map_zoom_combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(on_set_map_zoom(int))); - _protocol_combobox = new QComboBox(this); + _protocol_combobox = new DsComboBox(this); auto &decode_sigs = _session->get_decode_signals(); int index = 0; diff --git a/DSView/pv/dialogs/protocollist.h b/DSView/pv/dialogs/protocollist.h index f53dfcfa..879787c0 100755 --- a/DSView/pv/dialogs/protocollist.h +++ b/DSView/pv/dialogs/protocollist.h @@ -27,14 +27,13 @@ #include #include #include -#include -#include - +#include #include "../device/devinst.h" #include "../prop/binding/deviceoptions.h" #include "../toolbars/titlebar.h" #include "dsdialog.h" +#include "../ui/dscombobox.h" namespace pv { @@ -62,8 +61,8 @@ private: SigSession *_session; toolbars::TitleBar *_titlebar; - QComboBox *_map_zoom_combobox; - QComboBox *_protocol_combobox; + DsComboBox *_map_zoom_combobox; + DsComboBox *_protocol_combobox; std::list _show_checkbox_list; std::list _show_label_list; QFormLayout *_flayout; diff --git a/DSView/pv/dialogs/regionoptions.cpp b/DSView/pv/dialogs/regionoptions.cpp index ce71775d..8c455d26 100755 --- a/DSView/pv/dialogs/regionoptions.cpp +++ b/DSView/pv/dialogs/regionoptions.cpp @@ -45,8 +45,8 @@ RegionOptions::RegionOptions(view::View *view, SigSession *session, QWidget *par QHBoxLayout *hlayout = new QHBoxLayout(); hlayout->setContentsMargins(0,0,0,0); hlayout->setSpacing(0); - _start_comboBox = new QComboBox(this); - _end_comboBox = new QComboBox(this); + _start_comboBox = new DsComboBox(this); + _end_comboBox = new DsComboBox(this); _start_comboBox->addItem(RegionStart); _end_comboBox->addItem(RegionEnd); if (_view) { diff --git a/DSView/pv/dialogs/regionoptions.h b/DSView/pv/dialogs/regionoptions.h index b3e06b78..a66b2811 100755 --- a/DSView/pv/dialogs/regionoptions.h +++ b/DSView/pv/dialogs/regionoptions.h @@ -27,10 +27,10 @@ #include #include #include -#include #include "../toolbars/titlebar.h" #include "dsdialog.h" +#include "../ui/dscombobox.h" namespace pv { @@ -59,8 +59,8 @@ private: SigSession *_session; view::View *_view; - QComboBox *_start_comboBox; - QComboBox *_end_comboBox; + DsComboBox *_start_comboBox; + DsComboBox *_end_comboBox; QDialogButtonBox _button_box; diff --git a/DSView/pv/dock/dsotriggerdock.cpp b/DSView/pv/dock/dsotriggerdock.cpp index 6d401770..7fce3f47 100755 --- a/DSView/pv/dock/dsotriggerdock.cpp +++ b/DSView/pv/dock/dsotriggerdock.cpp @@ -61,7 +61,7 @@ DsoTriggerDock::DsoTriggerDock(QWidget *parent, SigSession *session) : connect(_position_slider, SIGNAL(valueChanged(int)), this, SLOT(pos_changed(int))); _holdoff_label = new QLabel(_widget); - _holdoff_comboBox = new QComboBox(_widget); + _holdoff_comboBox = new DsComboBox(_widget); _holdoff_comboBox->addItem(tr("uS"), QVariant::fromValue(1000)); _holdoff_comboBox->addItem(tr("mS"), QVariant::fromValue(1000000)); _holdoff_comboBox->addItem(tr("S"), QVariant::fromValue(1000000000)); @@ -103,7 +103,7 @@ DsoTriggerDock::DsoTriggerDock(QWidget *parent, SigSession *session) : connect(_falling_radioButton, SIGNAL(clicked()), this, SLOT(type_changed())); _source_group=new QButtonGroup(_widget); - _channel_comboBox = new QComboBox(_widget); + _channel_comboBox = new DsComboBox(_widget); _type_group=new QButtonGroup(_widget); _source_group->addButton(_auto_radioButton); diff --git a/DSView/pv/dock/dsotriggerdock.h b/DSView/pv/dock/dsotriggerdock.h index 4688577e..847194e5 100755 --- a/DSView/pv/dock/dsotriggerdock.h +++ b/DSView/pv/dock/dsotriggerdock.h @@ -27,12 +27,13 @@ #include #include #include -#include #include #include #include +#include "../ui/dscombobox.h" + namespace pv { class SigSession; @@ -79,7 +80,7 @@ private: QWidget *_widget; - QComboBox *_holdoff_comboBox; + DsComboBox *_holdoff_comboBox; QSpinBox *_holdoff_spinBox; QSlider *_holdoff_slider; @@ -89,7 +90,7 @@ private: QSlider *_position_slider; QButtonGroup *_source_group; - QComboBox *_channel_comboBox; + DsComboBox *_channel_comboBox; QButtonGroup *_type_group; QLabel *_position_label; diff --git a/DSView/pv/dock/measuredock.cpp b/DSView/pv/dock/measuredock.cpp index 68b983bd..cd98281f 100755 --- a/DSView/pv/dock/measuredock.cpp +++ b/DSView/pv/dock/measuredock.cpp @@ -216,7 +216,7 @@ void MeasureDock::reload() else _edge_groupBox->setDisabled(true); - for (QVector ::const_iterator i = _edge_ch_cmb_vec.begin(); + for (QVector ::const_iterator i = _edge_ch_cmb_vec.begin(); i != _edge_ch_cmb_vec.end(); i++) { update_probe_selector(*i); } @@ -416,7 +416,7 @@ void MeasureDock::add_edge_measure() g_label->setContentsMargins(0,0,0,0); QLabel *a_label = new QLabel(tr("@"), row_widget); a_label->setContentsMargins(0,0,0,0); - QComboBox *ch_cmb = create_probe_selector(row_widget); + DsComboBox *ch_cmb = create_probe_selector(row_widget); _edge_del_btn_vec.push_back(del_btn); _edge_s_btn_vec.push_back(s_btn); _edge_e_btn_vec.push_back(e_btn); @@ -643,14 +643,14 @@ void MeasureDock::set_cursor_btn_color(QPushButton *btn) btn->setStyleSheet(style); } -QComboBox* MeasureDock::create_probe_selector(QWidget *parent) +DsComboBox* MeasureDock::create_probe_selector(QWidget *parent) { - QComboBox *selector = new QComboBox(parent); + DsComboBox *selector = new DsComboBox(parent); update_probe_selector(selector); return selector; } -void MeasureDock::update_probe_selector(QComboBox *selector) +void MeasureDock::update_probe_selector(DsComboBox *selector) { selector->clear(); const auto &sigs = _session->get_signals(); diff --git a/DSView/pv/dock/measuredock.h b/DSView/pv/dock/measuredock.h index 379b1d38..63b77b52 100755 --- a/DSView/pv/dock/measuredock.h +++ b/DSView/pv/dock/measuredock.h @@ -24,7 +24,6 @@ #include #include -#include #include #include #include @@ -42,6 +41,8 @@ #include +#include "../ui/dscombobox.h" + namespace pv { class SigSession; @@ -73,8 +74,8 @@ private: void reStyle(); private: - QComboBox* create_probe_selector(QWidget *parent); - void update_probe_selector(QComboBox *selector); + DsComboBox* create_probe_selector(QWidget *parent); + void update_probe_selector(DsComboBox *selector); signals: @@ -129,7 +130,7 @@ private: QVector _edge_del_btn_vec; QVector _edge_s_btn_vec; QVector _edge_e_btn_vec; - QVector _edge_ch_cmb_vec; + QVector _edge_ch_cmb_vec; QVector _edge_r_label_vec; QPushButton *_sel_btn; diff --git a/DSView/pv/dock/protocoldock.cpp b/DSView/pv/dock/protocoldock.cpp index ba3f0282..28cf86b0 100755 --- a/DSView/pv/dock/protocoldock.cpp +++ b/DSView/pv/dock/protocoldock.cpp @@ -75,7 +75,7 @@ ProtocolDock::ProtocolDock(QWidget *parent, view::View &view, SigSession *sessio _del_all_button = new QPushButton(_up_widget); _del_all_button->setFlat(true); _del_all_button->setCheckable(true); - _protocol_combobox = new QComboBox(_up_widget); + _protocol_combobox = new DsComboBox(_up_widget); GSList *l = g_slist_sort(g_slist_copy( (GSList*)srd_decoder_list()), decoder_name_cmp); @@ -248,8 +248,12 @@ void ProtocolDock::paintEvent(QPaintEvent *) void ProtocolDock::resizeEvent(QResizeEvent *event) { int width = this->visibleRegion().boundingRect().width(); - width = width - _dn_layout->margin() * 2 - - _dn_search_layout->margin() * 2 - + + int mg1 = 10; + int mg2 = 10; + + width = width - mg1 * 2 - + mg2 * 2 - _dn_search_layout->spacing() * 2 - _pre_button->width()-_nxt_button->width(); width = std::max(width, 0); diff --git a/DSView/pv/dock/protocoldock.h b/DSView/pv/dock/protocoldock.h index a83df95b..2fc198e1 100755 --- a/DSView/pv/dock/protocoldock.h +++ b/DSView/pv/dock/protocoldock.h @@ -27,7 +27,6 @@ #include #include -#include #include #include #include @@ -42,6 +41,7 @@ #include "../data/decodermodel.h" #include "protocolitemlayer.h" +#include "../ui/dscombobox.h" namespace pv { @@ -135,7 +135,7 @@ private: QPushButton *_add_button; QPushButton *_del_all_button; - QComboBox *_protocol_combobox; + DsComboBox *_protocol_combobox; QVector _protocol_index_list; QVBoxLayout *_up_layout; QVector _protocol_items; //protocol item layers diff --git a/DSView/pv/dock/protocolitemlayer.cpp b/DSView/pv/dock/protocolitemlayer.cpp index bde54209..4dfe4cfb 100644 --- a/DSView/pv/dock/protocolitemlayer.cpp +++ b/DSView/pv/dock/protocolitemlayer.cpp @@ -21,7 +21,6 @@ #include "protocolitemlayer.h" #include "../dsvdef.h" -#include #include #include "../config/appconfig.h" @@ -40,7 +39,7 @@ ProtocolItemLayer::ProtocolItemLayer(QWidget *parent, QString protocolName, IPro _progress_label = new QLabel(parent); _set_button = new QPushButton(parent); _del_button = new QPushButton(parent); - _format_combox = new QComboBox(parent); + _format_combox = new DsComboBox(parent); QString iconPath = GetIconPath(); _del_button->setFlat(true); diff --git a/DSView/pv/dock/protocolitemlayer.h b/DSView/pv/dock/protocolitemlayer.h index 45901ef4..3591cb9e 100644 --- a/DSView/pv/dock/protocolitemlayer.h +++ b/DSView/pv/dock/protocolitemlayer.h @@ -23,10 +23,9 @@ #include #include -#include #include -#include #include +#include "../ui/dscombobox.h" class DecoderStatus; @@ -68,7 +67,7 @@ private: QLabel *_progress_label; QPushButton *_set_button; QPushButton *_del_button; - QComboBox *_format_combox; + DsComboBox *_format_combox; IProtocolItemLayerCallback *m_callback; QString _protocolName; bool m_bSetting; diff --git a/DSView/pv/dock/searchdock.cpp b/DSView/pv/dock/searchdock.cpp index bc3de15f..1d7cd1c3 100755 --- a/DSView/pv/dock/searchdock.cpp +++ b/DSView/pv/dock/searchdock.cpp @@ -261,7 +261,9 @@ void SearchDock::on_set() _search_value->setText(search_label); QFontMetrics fm = this->fontMetrics(); - _search_value->setFixedWidth(fm.width(search_label)+_search_button->width()+20); + //fm.width(search_label) + int tw = fm.boundingRect(search_label).width(); + _search_value->setFixedWidth(tw + _search_button->width()+20); if (new_pattern != _pattern) { _view.set_search_pos(_view.get_search_pos(), false); diff --git a/DSView/pv/dock/searchdock.h b/DSView/pv/dock/searchdock.h index 6e940bb3..d53c261e 100755 --- a/DSView/pv/dock/searchdock.h +++ b/DSView/pv/dock/searchdock.h @@ -25,7 +25,6 @@ #include #include -#include #include #include #include @@ -43,6 +42,7 @@ #include #include "../widgets/fakelineedit.h" +#include "../ui/dscombobox.h" namespace pv { diff --git a/DSView/pv/dock/triggerdock.cpp b/DSView/pv/dock/triggerdock.cpp index d90da9fd..1b869fe0 100755 --- a/DSView/pv/dock/triggerdock.cpp +++ b/DSView/pv/dock/triggerdock.cpp @@ -71,7 +71,7 @@ TriggerDock::TriggerDock(QWidget *parent, SigSession *session) : _stages_label = new QLabel(_widget); _stages_label->setDisabled(true); - stages_comboBox = new QComboBox(_widget); + stages_comboBox = new DsComboBox(_widget); for (int i = 1; i <= TriggerStages; i++) stages_comboBox->addItem(QString::number(i)); //stages_comboBox->setCurrentIndex(stages_comboBox->count() - 1); @@ -569,7 +569,7 @@ void TriggerDock::setup_adv_tab() QRegularExpression value_rx("[10XRFCxrfc ]+"); QValidator *value_validator = new QRegularExpressionValidator(value_rx, _stage_tabWidget); for (int i = 0; i < TriggerStages; i++) { - QComboBox *_logic_comboBox = new QComboBox(_stage_tabWidget); + DsComboBox *_logic_comboBox = new DsComboBox(_stage_tabWidget); _logic_comboBox->addItem(tr("Or")); _logic_comboBox->addItem(tr("And")); _logic_comboBox->setCurrentIndex(1); @@ -586,7 +586,7 @@ void TriggerDock::setup_adv_tab() _count_spinBox->setRange(1, INT32_MAX); _count_spinBox->setButtonSymbols(QAbstractSpinBox::NoButtons); _count_spinBox_list.push_back(_count_spinBox); - QComboBox *_inv0_comboBox = new QComboBox(_stage_tabWidget); + DsComboBox *_inv0_comboBox = new DsComboBox(_stage_tabWidget); _inv0_comboBox->addItem(tr("==")); _inv0_comboBox->addItem(tr("!=")); _inv0_comboBox_list.push_back(_inv0_comboBox); @@ -598,7 +598,7 @@ void TriggerDock::setup_adv_tab() _value1_lineEdit->setInputMask(mask); _value1_lineEdit->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); _value1_lineEdit_list.push_back(_value1_lineEdit); - QComboBox *_inv1_comboBox = new QComboBox(_stage_tabWidget); + DsComboBox *_inv1_comboBox = new DsComboBox(_stage_tabWidget); _inv1_comboBox->addItem(tr("==")); _inv1_comboBox->addItem(tr("!=")); _inv1_comboBox_list.push_back(_inv1_comboBox); @@ -734,7 +734,7 @@ void TriggerDock::setup_adv_tab() _serial_edge_lineEdit->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); _serial_data_label = new QLabel(_serial_groupBox); - _serial_data_comboBox = new QComboBox(_serial_groupBox); + _serial_data_comboBox = new DsComboBox(_serial_groupBox); for(int i = 0; i < _cur_ch_num; i++) _serial_data_comboBox->addItem(QString::number(i)); @@ -746,7 +746,7 @@ void TriggerDock::setup_adv_tab() _serial_value_lineEdit->setInputMask(mask); _serial_value_lineEdit->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); - _serial_bits_comboBox = new QComboBox(_serial_groupBox); + _serial_bits_comboBox = new DsComboBox(_serial_groupBox); for(int i = 1; i <= 16; i++) _serial_bits_comboBox->addItem(QString::number(i)); diff --git a/DSView/pv/dock/triggerdock.h b/DSView/pv/dock/triggerdock.h index 336f5dc7..eef9cab3 100755 --- a/DSView/pv/dock/triggerdock.h +++ b/DSView/pv/dock/triggerdock.h @@ -25,7 +25,6 @@ #include #include -#include #include #include #include @@ -43,6 +42,8 @@ #include +#include "../ui/dscombobox.h" + namespace pv { class SigSession; @@ -108,20 +109,20 @@ private: QSlider *_position_slider; QLabel *_stages_label; - QComboBox *stages_comboBox; + DsComboBox *stages_comboBox; QTabWidget *_stage_tabWidget; QVector _stage_groupBox_list; QVector _mu_label_list; - QVector _logic_comboBox_list; + QVector _logic_comboBox_list; QVector _value0_lineEdit_list; QVector _value0_ext32_lineEdit_list; QVector _count_spinBox_list; - QVector _inv0_comboBox_list; + QVector _inv0_comboBox_list; QVector _value1_lineEdit_list; QVector _value1_ext32_lineEdit_list; - QVector _inv1_comboBox_list; + QVector _inv1_comboBox_list; QVector _contiguous_checkbox_list; QTabWidget *_adv_tabWidget; @@ -136,10 +137,10 @@ private: QLineEdit *_serial_edge_lineEdit; QLineEdit *_serial_edge_ext32_lineEdit; QLabel *_serial_data_label; - QComboBox *_serial_data_comboBox; + DsComboBox *_serial_data_comboBox; QLabel *_serial_value_label; QLineEdit *_serial_value_lineEdit; - QComboBox *_serial_bits_comboBox; + DsComboBox *_serial_bits_comboBox; QLabel *_serial_note_label; QLabel *_data_bits_label; diff --git a/DSView/pv/dsvdef.h b/DSView/pv/dsvdef.h index 9a5ef516..b2b26002 100644 --- a/DSView/pv/dsvdef.h +++ b/DSView/pv/dsvdef.h @@ -23,6 +23,7 @@ #pragma once #include "../config.h" +#include #ifdef DS_DEBUG_TRACE diff --git a/DSView/pv/mainframe.cpp b/DSView/pv/mainframe.cpp old mode 100755 new mode 100644 index 173c1427..a48232f6 --- a/DSView/pv/mainframe.cpp +++ b/DSView/pv/mainframe.cpp @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -229,7 +228,15 @@ bool MainFrame::eventFilter(QObject *object, QEvent *event) return QFrame::eventFilter(object, event); } - if (!_bDraging && type == QEvent::MouseMove && (!(mouse_event->buttons() || Qt::NoButton))){ +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + int x0 = (int)mouse_event->globalPosition().x(); + int y0 = (int)mouse_event->globalPosition().y(); +#else + int x0 = mouse_event->globalX(); + int y0 = mouse_event->globalY(); +#endif + + if (!_bDraging && type == QEvent::MouseMove && (!(mouse_event->buttons() | Qt::NoButton))){ if (object == _top_left) { _hit_border = TopLeft; setCursor(Qt::SizeFDiagCursor); @@ -267,55 +274,55 @@ bool MainFrame::eventFilter(QObject *object, QEvent *event) if (!_freezing) { switch (_hit_border) { case TopLeft: - newWidth = std::max(_dragStartGeometry.right() - mouse_event->globalX(), minimumWidth()); - newHeight = std::max(_dragStartGeometry.bottom() - mouse_event->globalY(), minimumHeight()); + newWidth = std::max(_dragStartGeometry.right() - x0, minimumWidth()); + newHeight = std::max(_dragStartGeometry.bottom() - y0, minimumHeight()); newLeft = geometry().left(); newTop = geometry().top(); if (newWidth > minimumWidth()) - newLeft = mouse_event->globalX(); + newLeft = x0; if (newHeight > minimumHeight()) - newTop = mouse_event->globalY(); + newTop = y0; setGeometry(newLeft, newTop, newWidth, newHeight); saveWindowRegion(); break; case BottomLeft: - newWidth = std::max(_dragStartGeometry.right() - mouse_event->globalX(), minimumWidth()); - newHeight = std::max(mouse_event->globalY() - _dragStartGeometry.top(), minimumHeight()); + newWidth = std::max(_dragStartGeometry.right() - x0, minimumWidth()); + newHeight = std::max(y0 - _dragStartGeometry.top(), minimumHeight()); newLeft = geometry().left(); if (newWidth > minimumWidth()) - newLeft = mouse_event->globalX(); + newLeft = x0; setGeometry(newLeft, _dragStartGeometry.top(), newWidth, newHeight); saveWindowRegion(); break; case TopRight: - newWidth = std::max(mouse_event->globalX() - _dragStartGeometry.left(), minimumWidth()); - newHeight = std::max(_dragStartGeometry.bottom() - mouse_event->globalY(), minimumHeight()); + newWidth = std::max(x0 - _dragStartGeometry.left(), minimumWidth()); + newHeight = std::max(_dragStartGeometry.bottom() - y0, minimumHeight()); newTop = geometry().top(); if (newHeight > minimumHeight()) - newTop = mouse_event->globalY(); + newTop = y0; setGeometry(_dragStartGeometry.left(), newTop, newWidth, newHeight); saveWindowRegion(); break; case BottomRight: - newWidth = std::max(mouse_event->globalX() - _dragStartGeometry.left(), minimumWidth()); - newHeight = std::max(mouse_event->globalY() - _dragStartGeometry.top(), minimumHeight()); + newWidth = std::max(x0 - _dragStartGeometry.left(), minimumWidth()); + newHeight = std::max(y0 - _dragStartGeometry.top(), minimumHeight()); setGeometry(_dragStartGeometry.left(), _dragStartGeometry.top(), newWidth, newHeight); saveWindowRegion(); break; case Left: - newWidth = _dragStartGeometry.right() - mouse_event->globalX(); + newWidth = _dragStartGeometry.right() - x0; if (newWidth > minimumWidth()){ - setGeometry(mouse_event->globalX(), _dragStartGeometry.top(), newWidth, height()); + setGeometry(x0, _dragStartGeometry.top(), newWidth, height()); saveWindowRegion(); } break; case Right: - newWidth = mouse_event->globalX() - _dragStartGeometry.left(); + newWidth = x0 - _dragStartGeometry.left(); if (newWidth > minimumWidth()){ setGeometry(_dragStartGeometry.left(), _dragStartGeometry.top(), newWidth, height()); saveWindowRegion(); @@ -323,15 +330,15 @@ bool MainFrame::eventFilter(QObject *object, QEvent *event) break; case Top: - newHeight = _dragStartGeometry.bottom() - mouse_event->globalY(); + newHeight = _dragStartGeometry.bottom() - y0; if (newHeight > minimumHeight()){ - setGeometry(_dragStartGeometry.left(), mouse_event->globalY(),width(), newHeight); + setGeometry(_dragStartGeometry.left(), y0,width(), newHeight); saveWindowRegion(); } break; case Bottom: - newHeight = mouse_event->globalY() - _dragStartGeometry.top(); + newHeight = y0 - _dragStartGeometry.top(); if (newHeight > minimumHeight()){ setGeometry(_dragStartGeometry.left(), _dragStartGeometry.top(), width(), newHeight); saveWindowRegion(); diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp old mode 100755 new mode 100644 index 0869e39b..9f171525 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -39,6 +39,11 @@ #include #include #include +#include + +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +#include +#endif #include "mainwindow.h" @@ -867,7 +872,14 @@ void MainWindow::on_screenShot() { AppConfig &app = AppConfig::Instance(); QString default_name = app._userHistory.screenShotPath + "/DSView" + QDateTime::currentDateTime().toString("-yyMMdd-hhmmss"); - QPixmap pixmap = QPixmap::grabWindow(winId()); + +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + QScreen *scr = QGuiApplication::primaryScreen(); + QPixmap pixmap = scr->grabWindow(winId()); +#else + QPixmap pixmap = QPixmap::grabWindow(winId()); +#endif + QString format = "png"; QString fileName = QFileDialog::getSaveFileName( diff --git a/DSView/pv/prop/binding/probeoptions.cpp b/DSView/pv/prop/binding/probeoptions.cpp index cf916b04..87647d9c 100755 --- a/DSView/pv/prop/binding/probeoptions.cpp +++ b/DSView/pv/prop/binding/probeoptions.cpp @@ -23,6 +23,7 @@ #include #include +#include #include diff --git a/DSView/pv/prop/enum.cpp b/DSView/pv/prop/enum.cpp index d5bd8665..e70f1925 100755 --- a/DSView/pv/prop/enum.cpp +++ b/DSView/pv/prop/enum.cpp @@ -22,10 +22,10 @@ #include -#include #include #include "enum.h" +#include "../ui/dscombobox.h" using namespace boost; using namespace std; @@ -62,7 +62,7 @@ QWidget* Enum::get_widget(QWidget *parent, bool auto_commit) return NULL; } - _selector = new QComboBox(parent); + _selector = new DsComboBox(parent); for (unsigned int i = 0; i < _values.size(); i++) { const pair &v = _values[i]; _selector->addItem(v.second, QVariant::fromValue((void*)v.first)); diff --git a/DSView/pv/prop/enum.h b/DSView/pv/prop/enum.h index 6b1214cd..41606271 100755 --- a/DSView/pv/prop/enum.h +++ b/DSView/pv/prop/enum.h @@ -28,7 +28,7 @@ #include "property.h" -class QComboBox; +class DsComboBox; namespace pv { namespace prop { @@ -53,7 +53,7 @@ private slots: private: const std::vector< std::pair > _values; - QComboBox *_selector; + DsComboBox *_selector; }; } // prop diff --git a/DSView/pv/toolbars/samplingbar.cpp b/DSView/pv/toolbars/samplingbar.cpp index 50ceebe8..49b84f8b 100755 --- a/DSView/pv/toolbars/samplingbar.cpp +++ b/DSView/pv/toolbars/samplingbar.cpp @@ -79,9 +79,9 @@ SamplingBar::SamplingBar(SigSession *session, QWidget *parent) : _mode_button.setPopupMode(QToolButton::InstantPopup); - _device_selector.setSizeAdjustPolicy(QComboBox::AdjustToContents); - _sample_rate.setSizeAdjustPolicy(QComboBox::AdjustToContents); - _sample_count.setSizeAdjustPolicy(QComboBox::AdjustToContents); + _device_selector.setSizeAdjustPolicy(DsComboBox::AdjustToContents); + _sample_rate.setSizeAdjustPolicy(DsComboBox::AdjustToContents); + _sample_count.setSizeAdjustPolicy(DsComboBox::AdjustToContents); _device_selector.setMaximumWidth(ComboBoxMaxWidth); //_run_stop_button.setToolButtonStyle(Qt::ToolButtonTextBesideIcon); diff --git a/DSView/pv/toolbars/samplingbar.h b/DSView/pv/toolbars/samplingbar.h index 3459bb93..81ca3c8c 100755 --- a/DSView/pv/toolbars/samplingbar.h +++ b/DSView/pv/toolbars/samplingbar.h @@ -28,11 +28,11 @@ #include #include -#include #include #include #include #include +#include "../ui/dscombobox.h" struct st_dev_inst; class QAction; @@ -134,13 +134,13 @@ namespace pv bool _sampling; QToolButton _device_type; - QComboBox _device_selector; + DsComboBox _device_selector; std::map _device_selector_map; bool _updating_device_selector; QToolButton _configure_button; - QComboBox _sample_count; - QComboBox _sample_rate; + DsComboBox _sample_count; + DsComboBox _sample_rate; bool _updating_sample_rate; bool _updating_sample_count; diff --git a/DSView/pv/ui/dscombobox.cpp b/DSView/pv/ui/dscombobox.cpp new file mode 100644 index 00000000..f405b6b9 --- /dev/null +++ b/DSView/pv/ui/dscombobox.cpp @@ -0,0 +1,72 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2012 Joel Holdsworth + * Copyright (C) 2013 DreamSourceLab + * + * 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 "dscombobox.h" +#include +#include +#include "../config/appconfig.h" + +DsComboBox::DsComboBox(QWidget *parent) : QComboBox(parent) +{ + _contentWidth = 0; + QComboBox::setSizeAdjustPolicy(QComboBox::AdjustToContents); +} + + void DsComboBox::addItem(const QString &atext, const QVariant &auserData) + { + QComboBox::addItem(atext, auserData); + +#ifdef Q_OS_DARWIN + if (!atext.isEmpty()){ + QFontMetrics fm = this->fontMetrics(); + int w = fm.boundingRect(atext).width(); + if (w > _contentWidth){ + _contentWidth = w; + this->setStyleSheet("QAbstractItemView{min-width:" + QString::number(w + 30) + "px;}"); + } + } +#endif + } + + void DsComboBox::showPopup() + { + QComboBox::showPopup(); + +#ifdef Q_OS_DARWIN + + QWidget *popup = this->findChild(); + auto rc = popup->geometry(); + int x = rc.left() + 6; + int y = rc.top(); + int w = rc.right() - rc.left(); + int h = rc.bottom() - rc.top() + 15; + popup->setGeometry(x, y, w, h); + + if (AppConfig::Instance()._frameOptions.style == "dark"){ + popup->setStyleSheet("background-color:#262626;"); + } + else{ + popup->setStyleSheet("background-color:#white;"); + } +#endif + } diff --git a/DSView/pv/ui/dscombobox.h b/DSView/pv/ui/dscombobox.h new file mode 100644 index 00000000..c8d1230e --- /dev/null +++ b/DSView/pv/ui/dscombobox.h @@ -0,0 +1,46 @@ + +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2012 Joel Holdsworth + * Copyright (C) 2013 DreamSourceLab + * + * 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 + */ + + +#ifndef DSCOMBOBOX_H +#define DSCOMBOBOX_H + +#include + +class DsComboBox : public QComboBox +{ + Q_OBJECT + +public: + explicit DsComboBox(QWidget *parent = nullptr); + + void addItem(const QString &atext, const QVariant &userData = QVariant()); + +protected: + void showPopup(); + +private: + int _contentWidth; +}; + +#endif // DSCOMBOBOX_H diff --git a/DSView/pv/view/decodetrace.cpp b/DSView/pv/view/decodetrace.cpp index 1de94a9b..aea46fe0 100755 --- a/DSView/pv/view/decodetrace.cpp +++ b/DSView/pv/view/decodetrace.cpp @@ -27,7 +27,6 @@ #include #include -#include #include #include #include @@ -53,6 +52,7 @@ #include "../view/cursor.h" #include "../toolbars/titlebar.h" #include "../dsvdef.h" +#include "../ui/dscombobox.h" using namespace boost; using namespace std; @@ -418,8 +418,8 @@ void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form) } //Add region combobox - _start_comboBox = new QComboBox(parent); - _end_comboBox = new QComboBox(parent); + _start_comboBox = new DsComboBox(parent); + _end_comboBox = new DsComboBox(parent); _start_comboBox->addItem(RegionStart); _end_comboBox->addItem(RegionEnd); @@ -726,7 +726,7 @@ void DecodeTrace::create_decoder_form( for(l = decoder->channels; l; l = l->next) { const struct srd_channel *const pdch = (struct srd_channel *)l->data; - QComboBox *const combo = create_probe_selector(parent, dec, pdch); + DsComboBox *const combo = create_probe_selector(parent, dec, pdch); decoder_form->addRow(tr("%1 (%2) *") .arg(QString::fromUtf8(pdch->name)) @@ -742,7 +742,7 @@ void DecodeTrace::create_decoder_form( for(l = decoder->opt_channels; l; l = l->next) { const struct srd_channel *const pdch = (struct srd_channel *)l->data; - QComboBox *const combo = create_probe_selector(parent, dec, pdch); + DsComboBox *const combo = create_probe_selector(parent, dec, pdch); decoder_form->addRow(tr("%1 (%2)") .arg(QString::fromUtf8(pdch->name)) @@ -770,7 +770,7 @@ void DecodeTrace::create_decoder_form( connect(group, SIGNAL(del_stack(data::decode::Decoder*)), this, SLOT(on_del_stack(data::decode::Decoder*))); } -QComboBox* DecodeTrace::create_probe_selector( +DsComboBox* DecodeTrace::create_probe_selector( QWidget *parent, const data::decode::Decoder *dec, const srd_channel *const pdch) { @@ -783,7 +783,7 @@ QComboBox* DecodeTrace::create_probe_selector( data::decode::Decoder *_dec = const_cast(dec); auto probe_iter = _dec->channels().find(pdch); - QComboBox *selector = new QComboBox(parent); + DsComboBox *selector = new DsComboBox(parent); selector->addItem("-", QVariant::fromValue(-1)); diff --git a/DSView/pv/view/decodetrace.h b/DSView/pv/view/decodetrace.h index 5b361e5c..4f70df85 100755 --- a/DSView/pv/view/decodetrace.h +++ b/DSView/pv/view/decodetrace.h @@ -36,7 +36,7 @@ struct srd_channel; struct srd_decoder; -class QComboBox; +class DsComboBox; namespace pv { @@ -66,7 +66,7 @@ class DecodeTrace : public Trace private: struct ProbeSelector { - const QComboBox *_combo; + const DsComboBox *_combo; const pv::data::decode::Decoder *_decoder; const srd_channel *_pdch; }; @@ -180,7 +180,7 @@ private: pv::data::decode::Decoder *dec, QWidget *parent, QFormLayout *form); - QComboBox* create_probe_selector(QWidget *parent, + DsComboBox* create_probe_selector(QWidget *parent, const pv::data::decode::Decoder *dec, const srd_channel *const pdch); @@ -219,8 +219,8 @@ private: int _start_count; int _end_count; - QComboBox *_start_comboBox; - QComboBox *_end_comboBox; + DsComboBox *_start_comboBox; + DsComboBox *_end_comboBox; QFormLayout *_pub_input_layer; int _progress; diff --git a/DSView/pv/view/spectrumtrace.cpp b/DSView/pv/view/spectrumtrace.cpp index 8e6bb11e..3527a013 100755 --- a/DSView/pv/view/spectrumtrace.cpp +++ b/DSView/pv/view/spectrumtrace.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "spectrumtrace.h" #include "../sigsession.h" @@ -208,12 +209,17 @@ QString SpectrumTrace::format_freq(double freq, unsigned precision) const int prefix = floor((order - FirstSIPrefixPower)/ 3.0f); const double divider = pow(10.0, max(prefix * 3.0 + FirstSIPrefixPower, 0.0)); - QString s; - QTextStream ts(&s); - ts.setRealNumberPrecision(precision); - ts << fixed << freq / divider << - FreqPrefixes[prefix] << "Hz"; - return s; + //QString s; + //QTextStream ts(&s); + //ts.setRealNumberPrecision(precision); + //ts << fixed << freq / divider << FreqPrefixes[prefix] << "Hz"; + //return s; + char buf[20] = {0}; + char format[10] = {0}; + sprintf(format, "%%.%df%%s", precision); + QString prev = FreqPrefixes[prefix] + "Hz"; + sprintf(buf, format, freq / divider, prev.toLatin1().data()); + return QString(buf); } } diff --git a/DSView/pv/view/viewport.cpp b/DSView/pv/view/viewport.cpp index ff65b2fd..6bbaa6da 100755 --- a/DSView/pv/view/viewport.cpp +++ b/DSView/pv/view/viewport.cpp @@ -1597,7 +1597,9 @@ void Viewport::paintMeasure(QPainter &p, QColor fore, QColor back) QString delta_text = _view.get_index_delta(_edge_start, _edge_end) + "/" + QString::number(delta); QFontMetrics fm = this->fontMetrics(); - const int rectW = fm.width(delta_text) + 60; + // const int rectW = fm.width(delta_text) + 60; + const int rectW = fm.boundingRect(delta_text).width() + 60; + const int rectH = fm.height() + 10; //const int rectY = (_cur_aftY >= _cur_preY) ? _cur_preY_top : _cur_preY_bottom; //const int rectX = (_cur_aftX >= _cur_preX) ? _cur_preX : _cur_preX - rectW; diff --git a/DSView/pv/view/viewstatus.cpp b/DSView/pv/view/viewstatus.cpp index 635c02d4..ccd3872a 100755 --- a/DSView/pv/view/viewstatus.cpp +++ b/DSView/pv/view/viewstatus.cpp @@ -54,7 +54,12 @@ ViewStatus::ViewStatus(SigSession *session, View &parent) : void ViewStatus::paintEvent(QPaintEvent *) { QStyleOption opt; - opt.init(this); + #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + opt.initFrom(this); + #else + opt.init(this); + #endif + QPainter p(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); diff --git a/libsigrok4DSL/config.h b/libsigrok4DSL/config.h new file mode 100644 index 00000000..1c40c8d3 --- /dev/null +++ b/libsigrok4DSL/config.h @@ -0,0 +1,192 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +#ifndef SR_CONFIG_H +#define SR_CONFIG_H /* To stop multiple inclusions. */ + +/* Define if building universal (internal helper macro) */ +/* #undef AC_APPLE_UNIVERSAL_BUILD */ + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* DreamSourceLab hardware driver support */ +#define HAVE_DSL_DEVICE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Demo driver support */ +#define HAVE_LA_DEMO 1 + +/* Specifies whether we have libserialport. */ +/* #undef HAVE_LIBSERIALPORT */ + +/* Specifies whether we have a libusb.h header. */ +#define HAVE_LIBUSB_1_0 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strchr' function. */ +#define HAVE_STRCHR 1 + +/* Define to 1 if you have the `strcspn' function. */ +#define HAVE_STRCSPN 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strncasecmp' function. */ +#define HAVE_STRNCASECMP 1 + +/* Define to 1 if you have the `strstr' function. */ +#define HAVE_STRSTR 1 + +/* Define to 1 if you have the `strtol' function. */ +#define HAVE_STRTOL 1 + +/* Define to 1 if you have the `strtoul' function. */ +#define HAVE_STRTOUL 1 + +/* Define to 1 if you have the `strtoull' function. */ +#define HAVE_STRTOULL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_TERMIOS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#define LT_OBJDIR ".libs/" + +/* Name of package */ +#define PACKAGE "libsigrok4DSL" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "support@dreamsourcelab.com" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "libsigrok4DSL" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "libsigrok4DSL 0.2.0" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "libsigrok4DSL" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "http://www.dreamsourcelab.com" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "0.2.0" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "0.2.0" + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +/* # undef WORDS_BIGENDIAN */ +# endif +#endif + +/* Define for Solaris 2.5.1 so the uint32_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT32_T */ + +/* Define for Solaris 2.5.1 so the uint64_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT64_T */ + +/* Define for Solaris 2.5.1 so the uint8_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT8_T */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* Define to the type of a signed integer type of width exactly 16 bits if + such a type exists and the standard includes do not define it. */ +/* #undef int16_t */ + +/* Define to the type of a signed integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +/* #undef int32_t */ + +/* Define to the type of a signed integer type of width exactly 64 bits if + such a type exists and the standard includes do not define it. */ +/* #undef int64_t */ + +/* Define to the type of a signed integer type of width exactly 8 bits if such + a type exists and the standard includes do not define it. */ +/* #undef int8_t */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* Define to the type of an unsigned integer type of width exactly 16 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint16_t */ + +/* Define to the type of an unsigned integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint32_t */ + +/* Define to the type of an unsigned integer type of width exactly 64 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint64_t */ + +/* Define to the type of an unsigned integer type of width exactly 8 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint8_t */ + +#endif /* SR_CONFIG_H */ diff --git a/libsigrok4DSL/output/gnuplot.c b/libsigrok4DSL/output/gnuplot.c index 92b01324..1644fceb 100755 --- a/libsigrok4DSL/output/gnuplot.c +++ b/libsigrok4DSL/output/gnuplot.c @@ -25,7 +25,7 @@ #include #include #include -#include "config.h" /* Needed for PACKAGE_STRING and others. */ +#include "../config.h" /* Needed for PACKAGE_STRING and others. */ #define LOG_PREFIX "output/gnuplot" diff --git a/qtpro/DSView.pro b/qtpro/DSView.pro index 5fd987c2..5d30bed6 100644 --- a/qtpro/DSView.pro +++ b/qtpro/DSView.pro @@ -163,6 +163,7 @@ SOURCES += \ ../DSView/pv/ZipMaker.cpp \ ../DSView/pv/data/decode/AnnotationResTable.cpp \ ../DSView/pv/ui/msgbox.cpp \ + ../DSView/pv/ui/dscombobox.cpp \ ../DSView/pv/dock/protocolitemlayer.cpp \ ../DSView/pv/config/appconfig.cpp \ ../DSView/pv/dsvdef.cpp \ @@ -262,6 +263,7 @@ HEADERS += \ ../DSView/pv/ZipMaker.h \ ../DSView/pv/data/decode/AnnotationResTable.h \ ../DSView/pv/ui/msgbox.h \ + ../DSView/pv/ui/dscombobox.h \ ../DSView/pv/dock/protocolitemlayer.h \ ../DSView/pv/config/appconfig.h \ ../DSView/pv/dsvdef.h \ diff --git a/qtpro/DSView.pro.user b/qtpro/DSView.pro.user index 8871a8fc..c4f4a0b2 100644 --- a/qtpro/DSView.pro.user +++ b/qtpro/DSView.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId From f85170e93f1dc4697439323b773a7b0cdf86cc54 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Tue, 23 Nov 2021 17:24:15 +0800 Subject: [PATCH 33/60] update the app data directory get mode,fix switch language bug at macos --- DSView/main.cpp | 26 ++++++-------------- DSView/pv/appcontrol.cpp | 22 ++++++----------- DSView/pv/config/appconfig.cpp | 31 ++++++++++++++++++++++-- DSView/pv/config/appconfig.h | 6 +++++ DSView/pv/devicemanager.cpp | 3 ++- DSView/pv/dialogs/about.cpp | 7 +----- DSView/pv/interface/uicallback.h | 5 ++++ DSView/pv/mainframe.cpp | 13 ++++++++-- DSView/pv/mainwindow.cpp | 28 ++++++--------------- DSView/pv/mainwindow.h | 13 ++++++---- DSView/pv/prop/binding/deviceoptions.cpp | 24 +++++++++--------- DSView/pv/prop/binding/probeoptions.cpp | 11 ++++----- DSView/pv/toolbars/filebar.cpp | 11 +++------ DSView/pv/toolbars/logobar.cpp | 29 +++++++++++----------- DSView/pv/toolbars/logobar.h | 13 ++++++---- DSView/pv/ui/dscombobox.h | 3 ++- DSView/pv/view/devmode.cpp | 6 ++--- 17 files changed, 130 insertions(+), 121 deletions(-) diff --git a/DSView/main.cpp b/DSView/main.cpp index 210f9241..978f37b2 100755 --- a/DSView/main.cpp +++ b/DSView/main.cpp @@ -38,8 +38,6 @@ #include "config.h" #include "pv/appcontrol.h" -char DS_RES_PATH[256]; - void usage() { fprintf(stdout, @@ -53,6 +51,8 @@ void usage() "\n", DS_BIN_NAME, DS_DESCRIPTION); } +char DS_RES_PATH[256] = {0}; + int main(int argc, char *argv[]) { int ret = 0; @@ -142,24 +142,12 @@ int main(int argc, char *argv[]) if (argcFinal - optind > 1) { fprintf(stderr, "Only one file can be openened.\n"); return 1; - } else if (argcFinal - optind == 1) + } else if (argcFinal - optind == 1){ open_file = argvFinal[argcFinal - 1]; - - QDir dir(QCoreApplication::applicationDirPath()); - -#ifdef Q_OS_LINUX - if (dir.cd("..") && - dir.cd("share") && - dir.cd("DSView") && - dir.cd("res")) { - // the path command like: cd ../share/DSView/res - QString res_dir = dir.absolutePath() + "/"; - strcpy(DS_RES_PATH, res_dir.toUtf8().data()); - } else { - qDebug() << "DSView run ERROR: config files don't exist."; - return 1; - } -#endif + } + + QString path = GetAppDataDir(); + strcpy(DS_RES_PATH, path.toUtf8().data()); //#ifdef Q_OS_DARWIN //#endif diff --git a/DSView/pv/appcontrol.cpp b/DSView/pv/appcontrol.cpp index fb477aea..34fb8f99 100644 --- a/DSView/pv/appcontrol.cpp +++ b/DSView/pv/appcontrol.cpp @@ -31,6 +31,7 @@ #include "devicemanager.h" #include "sigsession.h" #include "dsvdef.h" +#include "config/appconfig.h" AppControl::AppControl() { @@ -71,23 +72,14 @@ bool AppControl::Init() { m_error = "DSView run ERROR: libsigrok init failed."; return false; - } - - // const char *decoderScriptDir = "/home/lala/tmpdir/any"; - //const char * decoderScriptDir = NULL; - - char decoderScriptDir[256] = {0}; - QDir dir(QCoreApplication::applicationDirPath()); -#ifdef Q_OS_LINUX - dir.cd("../share/DSView/decoders"); -#else - dir.cd("decoders"); -#endif - - strcpy(decoderScriptDir, dir.absolutePath().toUtf8().data()); + } + + QString dir = GetAppDataDir() + "/decoders"; + char path[256] = {0}; + strcpy(path, dir.toUtf8().data()); // Initialise libsigrokdecode - if (srd_init(decoderScriptDir) != SRD_OK) + if (srd_init(path) != SRD_OK) { m_error = "ERROR: libsigrokdecode init failed."; return false; diff --git a/DSView/pv/config/appconfig.cpp b/DSView/pv/config/appconfig.cpp index 42bc78d3..50aeb5cb 100644 --- a/DSView/pv/config/appconfig.cpp +++ b/DSView/pv/config/appconfig.cpp @@ -24,6 +24,9 @@ #include #include #include +#include +#include +#include #define MAX_PROTOCOL_FORMAT_LIST 15 @@ -126,10 +129,14 @@ void _loadFrame(FrameOptions &o, QSettings &st){ o.windowState = st.value("windowState", QByteArray()).toByteArray(); st.endGroup(); - if (o.language == -1){ + if (o.language == -1 || (o.language != LAN_CN && o.language != LAN_EN)){ //get local language QLocale locale; - o.language = locale.language(); + + if (QLocale::languageToString(locale.language()) == "Chinese") + o.language = LAN_CN; + else + o.language = LAN_EN; } } @@ -282,3 +289,23 @@ QString GetIconPath() } return ":/icons/" + style; } + +QString GetAppDataDir() +{ +//applicationDirPath not end with '/' +#ifdef Q_OS_LINUX + QDir dir(QCoreApplication::applicationDirPath()); + if (dir.cd("..") && dir.cd("share") &&dir.cd("DSView")) + { + return dir.absolutePath(); + } + qDebug() << "dir is not exists:" << QCoreApplication::applicationDirPath() + "/../share/DSView"; + assert(false); +#else + return QCoreApplication::applicationDirPath(); +#endif +} + +QString GetResourceDir(){ + return GetAppDataDir() + "/res"; +} diff --git a/DSView/pv/config/appconfig.h b/DSView/pv/config/appconfig.h index f01678ad..f9cdb6a8 100644 --- a/DSView/pv/config/appconfig.h +++ b/DSView/pv/config/appconfig.h @@ -27,6 +27,8 @@ #include #include +#define LAN_CN 25 +#define LAN_EN 31 //--------------------api--- @@ -34,6 +36,10 @@ QString GetDirectoryName(QString path); QString GetIconPath(); +QString GetAppDataDir(); + +QString GetResourceDir(); + //------------------class class StringPair diff --git a/DSView/pv/devicemanager.cpp b/DSView/pv/devicemanager.cpp index 51a4a128..448272ef 100755 --- a/DSView/pv/devicemanager.cpp +++ b/DSView/pv/devicemanager.cpp @@ -33,6 +33,7 @@ #include #include #include +#include "config/appconfig.h" using std::list; using std::map; @@ -116,7 +117,7 @@ void DeviceManager::driver_scan( // Check If DSL hardware driver if (strncmp(driver->name, "virtual", 7)) { - QDir dir(DS_RES_PATH); + QDir dir(GetResourceDir()); if (!dir.exists()) return; } diff --git a/DSView/pv/dialogs/about.cpp b/DSView/pv/dialogs/about.cpp index 3392d2a0..920dfeaa 100755 --- a/DSView/pv/dialogs/about.cpp +++ b/DSView/pv/dialogs/about.cpp @@ -76,13 +76,8 @@ About::About(QWidget *parent) : .arg("http://sigrok.org/"); QString changlogs = tr("Changelogs
    "); - #ifndef Q_OS_LINUX - QDir dir(QCoreApplication::applicationDirPath()); - #else - QDir dir(DS_RES_PATH); - dir.cdUp(); - #endif + QDir dir(GetAppDataDir()); AppConfig &app = AppConfig::Instance(); int lan = app._frameOptions.language; diff --git a/DSView/pv/interface/uicallback.h b/DSView/pv/interface/uicallback.h index b7ae0054..58c2394c 100644 --- a/DSView/pv/interface/uicallback.h +++ b/DSView/pv/interface/uicallback.h @@ -27,3 +27,8 @@ class IDlgCallback public: virtual void OnDlgResult(bool bYes)=0; }; + +class IMainForm{ +public: + virtual void switchLanguage(int language)=0; +}; diff --git a/DSView/pv/mainframe.cpp b/DSView/pv/mainframe.cpp index a48232f6..cd9b1e71 100644 --- a/DSView/pv/mainframe.cpp +++ b/DSView/pv/mainframe.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include "dsvdef.h" #include "config/appconfig.h" @@ -449,12 +450,18 @@ void MainFrame::show_doc() dialogs::DSDialog dlg(this, true); dlg.setTitle(tr("Document")); + QString path = GetAppDataDir() + "/showDoc" + QString::number(lan)+ ".png"; + if (!QFile::exists(path)){ + path = ":/icons/showDoc"+QString::number(lan)+".png"; + } + QLabel tipsLabel; - tipsLabel.setPixmap(QPixmap(":/icons/showDoc"+QString::number(lan)+".png")); + tipsLabel.setPixmap(path); + QMessageBox msg; msg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint); msg.setContentsMargins(0, 0, 0, 0); - connect(&msg, SIGNAL(buttonClicked(QAbstractButton*)), &dlg, SLOT(accept())); + QPushButton *noMoreButton = msg.addButton(tr("Not Show Again"), QMessageBox::ActionRole); msg.addButton(tr("Ignore"), QMessageBox::ActionRole); QPushButton *openButton = msg.addButton(tr("Open"), QMessageBox::ActionRole); @@ -465,6 +472,8 @@ void MainFrame::show_doc() layout.setContentsMargins(0, 0, 0, 0); dlg.layout()->addLayout(&layout); + connect(&msg, SIGNAL(buttonClicked(QAbstractButton*)), &dlg, SLOT(accept())); + dlg.exec(); if (msg.clickedButton() == openButton) { diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index 9f171525..44d528b6 100644 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -286,7 +286,6 @@ void MainWindow::setup_ui() connect(_file_bar, SIGNAL(sig_store_session(QString)), this, SLOT(on_store_session(QString))); //logobar - connect(_logo_bar, SIGNAL(sig_setLanguage(int)), this, SLOT(on_setLanguage(int))); connect(_logo_bar, SIGNAL(sig_open_doc()), this, SLOT(on_open_doc())); @@ -302,6 +301,8 @@ void MainWindow::setup_ui() connect(_sampling_bar, SIGNAL(sig_show_calibration()), _view, SLOT(show_calibration())); connect(_dso_trigger_widget, SIGNAL(set_trig_pos(int)), _view, SLOT(set_trig_pos(int))); + + _logo_bar->set_mainform_callback(this); } @@ -397,12 +398,8 @@ void MainWindow::update_device_list() } else { _file_bar->set_settings_en(false); _logo_bar->dsl_connected(false); - #ifdef Q_OS_LINUX - QDir dir(DS_RES_PATH); - #else - QDir dir(QCoreApplication::applicationDirPath()); - assert(dir.cd("res")); - #endif + + QDir dir(GetResourceDir()); if (dir.exists()) { QString str = dir.absolutePath() + "/"; QString ses_name = str + @@ -1395,11 +1392,7 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) } return false; } - - void MainWindow::on_setLanguage(int language) - { - switchLanguage(language); - } + void MainWindow::switchLanguage(int language) { @@ -1414,7 +1407,7 @@ void MainWindow::switchLanguage(int language) app.SaveFrame(); } - if (language != QLocale::English) + if (language == LAN_CN) { _qtTrans.load(":/qt_" + QString::number(language)); qApp->installTranslator(&_qtTrans); @@ -1464,13 +1457,8 @@ void MainWindow::on_open_doc(){ } void MainWindow::openDoc() -{ - #ifndef Q_OS_LINUX - QDir dir(QCoreApplication::applicationDirPath()); - #else - QDir dir(DS_RES_PATH); - dir.cdUp(); - #endif +{ + QDir dir(GetAppDataDir()); AppConfig &app = AppConfig::Instance(); int lan = app._frameOptions.language; QDesktopServices::openUrl( diff --git a/DSView/pv/mainwindow.h b/DSView/pv/mainwindow.h index 446844b7..8cbf35a9 100755 --- a/DSView/pv/mainwindow.h +++ b/DSView/pv/mainwindow.h @@ -30,6 +30,7 @@ #include "dialogs/dsmessagebox.h" #include "interface/icallbacks.h" #include "eventobject.h" +#include "interface/uicallback.h" class QAction; class QMenuBar; @@ -72,7 +73,7 @@ using namespace pv::device; //The mainwindow,referenced by MainFrame //TODO: create graph view,toolbar,and show device list -class MainWindow : public QMainWindow, public ISessionCallback +class MainWindow : public QMainWindow, public ISessionCallback, public IMainForm { Q_OBJECT @@ -83,8 +84,7 @@ public: explicit MainWindow(QWidget *parent = 0); void openDoc(); - void switchLanguage(int language); - + private: void closeEvent(QCloseEvent *event); @@ -119,8 +119,7 @@ private slots: bool on_store_session(QString name); void device_detach_post(); void device_changed(bool close); - void on_device_selected(); - void on_setLanguage(int language); + void on_device_selected(); void on_capture_state_changed(int state); void on_data_updated(); @@ -139,6 +138,10 @@ private slots: signals: void prgRate(int progress); +//IMainForm +public: + void switchLanguage(int language); + //ISessionCallback public: void session_save(); diff --git a/DSView/pv/prop/binding/deviceoptions.cpp b/DSView/pv/prop/binding/deviceoptions.cpp index a0e051c2..0b25ba33 100755 --- a/DSView/pv/prop/binding/deviceoptions.cpp +++ b/DSView/pv/prop/binding/deviceoptions.cpp @@ -20,20 +20,18 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include - -#include -#include -#include - -#include - #include "deviceoptions.h" -#include -#include -#include -#include +#include +#include +#include +#include + +#include "../bool.h" +#include "../double.h" +#include "../enum.h" +#include "../int.h" +#include "../config/appconfig.h" using namespace boost; using namespace std; @@ -73,7 +71,7 @@ DeviceOptions::DeviceOptions(struct sr_dev_inst *sdi) : if (sr_config_get(_sdi->driver, _sdi, NULL, NULL, SR_CONF_LANGUAGE, &gvar_tmp) == SR_OK) { if (gvar_tmp != NULL) { int language = g_variant_get_int16(gvar_tmp); - if (language == QLocale::Chinese) + if (language == LAN_CN) label_char = info->label_cn; g_variant_unref(gvar_tmp); } diff --git a/DSView/pv/prop/binding/probeoptions.cpp b/DSView/pv/prop/binding/probeoptions.cpp index 87647d9c..ec876265 100755 --- a/DSView/pv/prop/binding/probeoptions.cpp +++ b/DSView/pv/prop/binding/probeoptions.cpp @@ -19,21 +19,20 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "probeoptions.h" + #include #include #include -#include - #include - -#include "probeoptions.h" - #include #include #include #include +#include "../../config/appconfig.h" + using namespace boost; using namespace std; @@ -74,7 +73,7 @@ ProbeOptions::ProbeOptions(struct sr_dev_inst *sdi, if (sr_config_get(_sdi->driver, _sdi, NULL, NULL, SR_CONF_LANGUAGE, &gvar_tmp) == SR_OK) { if (gvar_tmp != NULL) { int language = g_variant_get_int16(gvar_tmp); - if (language == QLocale::Chinese) + if (language == LAN_CN) label_char = info->label_cn; g_variant_unref(gvar_tmp); } diff --git a/DSView/pv/toolbars/filebar.cpp b/DSView/pv/toolbars/filebar.cpp index fb708f96..81996711 100755 --- a/DSView/pv/toolbars/filebar.cpp +++ b/DSView/pv/toolbars/filebar.cpp @@ -191,13 +191,8 @@ void FileBar::on_actionLoad_triggered() } void FileBar::on_actionDefault_triggered() -{ -#ifdef Q_OS_LINUX - QDir dir(DS_RES_PATH); -#else - QDir dir(QCoreApplication::applicationDirPath()); - assert(dir.cd("res")); -#endif +{ + QDir dir(GetResourceDir()); if (!dir.exists()) { MsgBox::Show(NULL, "Cannot find default session file for this device!", this); return; @@ -205,7 +200,7 @@ void FileBar::on_actionDefault_triggered() QString driver_name = _session->get_device()->name(); QString mode_name = QString::number(_session->get_device()->dev_inst()->mode); - int language = QLocale::English; + int language = LAN_EN; GVariant *gvar_tmp = _session->get_device()->get_config(NULL, NULL, SR_CONF_LANGUAGE); if (gvar_tmp != NULL) { language = g_variant_get_int16(gvar_tmp); diff --git a/DSView/pv/toolbars/logobar.cpp b/DSView/pv/toolbars/logobar.cpp index 01da8850..c08d2bc1 100755 --- a/DSView/pv/toolbars/logobar.cpp +++ b/DSView/pv/toolbars/logobar.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include "logobar.h" #include "../dialogs/about.h" @@ -43,6 +44,8 @@ LogoBar::LogoBar(SigSession *session, QWidget *parent) : _session(session), _logo_button(this) { + _mainForm = NULL; + setMovable(false); setContentsMargins(0,0,0,0); @@ -118,7 +121,7 @@ void LogoBar::retranslateUi() _issue->setText(tr("&Bug Report")); AppConfig &app = AppConfig::Instance(); - if (app._frameOptions.language == QLocale::Chinese) + if (app._frameOptions.language == LAN_CN) _language->setIcon(QIcon(":/icons/Chinese.svg")); else _language->setIcon(QIcon(":/icons/English.svg")); @@ -170,14 +173,17 @@ void LogoBar::on_actionEn_triggered() { _language->setIcon(QIcon::fromTheme("file", QIcon(":/icons/English.svg"))); - sig_setLanguage(QLocale::English); + + assert(_mainForm); + _mainForm->switchLanguage(LAN_EN); } void LogoBar::on_actionCn_triggered() { _language->setIcon(QIcon::fromTheme("file", QIcon(":/icons/Chinese.svg"))); - sig_setLanguage(QLocale::Chinese); + assert(_mainForm); + _mainForm->switchLanguage(LAN_CN); } void LogoBar::on_actionAbout_triggered() @@ -187,22 +193,15 @@ void LogoBar::on_actionAbout_triggered() } void LogoBar::on_actionManual_triggered() -{ - #ifndef Q_OS_LINUX - QDir dir(QCoreApplication::applicationDirPath()); - #else - QDir dir(DS_RES_PATH); - dir.cdUp(); - #endif - QDesktopServices::openUrl( - QUrl("file:///"+dir.absolutePath() + "/ug.pdf")); +{ + QDir dir(GetAppDataDir()); + QDesktopServices::openUrl( QUrl("file:///"+dir.absolutePath() + "/ug.pdf")); } void LogoBar::on_actionIssue_triggered() { - QDir dir(QCoreApplication::applicationDirPath()); - QDesktopServices::openUrl( - QUrl(QLatin1String("https://github.com/DreamSourceLab/DSView/issues"))); + QDir dir(GetAppDataDir()); + QDesktopServices::openUrl(QUrl(QLatin1String("https://github.com/DreamSourceLab/DSView/issues"))); } void LogoBar::enable_toggle(bool enable) diff --git a/DSView/pv/toolbars/logobar.h b/DSView/pv/toolbars/logobar.h index 19cf5d3c..a3f8982b 100755 --- a/DSView/pv/toolbars/logobar.h +++ b/DSView/pv/toolbars/logobar.h @@ -27,10 +27,11 @@ #include #include #include +#include #include "../sigsession.h" +#include "../interface/uicallback.h" -#include namespace pv { namespace toolbars { @@ -49,6 +50,10 @@ public: //show the hardware device conneted status with logo picture void dsl_connected(bool conn); + inline void set_mainform_callback(IMainForm *callback){ + _mainForm = callback; + } + private: void changeEvent(QEvent *event); void retranslateUi(); @@ -59,10 +64,7 @@ private: void show_session_error( const QString text, const QString info_text); -signals: - //post event message to set language, MainWindow class receive it - void sig_setLanguage(int language); - +signals: //post event message to open user help document, MainWindow class receive it void sig_open_doc(); @@ -89,6 +91,7 @@ private: QAction *_about; QAction *_manual; QAction *_issue; + IMainForm *_mainForm; }; } // namespace toolbars diff --git a/DSView/pv/ui/dscombobox.h b/DSView/pv/ui/dscombobox.h index c8d1230e..00820d50 100644 --- a/DSView/pv/ui/dscombobox.h +++ b/DSView/pv/ui/dscombobox.h @@ -21,7 +21,6 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - #ifndef DSCOMBOBOX_H #define DSCOMBOBOX_H @@ -43,4 +42,6 @@ private: int _contentWidth; }; + + #endif // DSCOMBOBOX_H diff --git a/DSView/pv/view/devmode.cpp b/DSView/pv/view/devmode.cpp index a69f082d..cfc6c0db 100755 --- a/DSView/pv/view/devmode.cpp +++ b/DSView/pv/view/devmode.cpp @@ -113,7 +113,7 @@ void DevMode::set_device() QAction *action = new QAction(this); action->setIcon(QIcon(iconPath+"square-"+icon_name)); - if (lan == QLocale::Chinese) + if (lan == LAN_CN) action->setText(mode->name_cn); else action->setText(mode->name); @@ -124,7 +124,7 @@ void DevMode::set_device() if (dev_inst->dev_inst()->mode == _mode_list[action]->mode) { QString icon_fname = iconPath + icon_name; _mode_btn->setIcon(QIcon(icon_fname)); - if (lan== QLocale::Chinese) + if (lan== LAN_CN) _mode_btn->setText(mode->name_cn); else _mode_btn->setText(mode->name); @@ -180,7 +180,7 @@ void DevMode::on_mode_change() QString icon_fname = iconPath + "/" + QString::fromLocal8Bit((*i).second->icon); _mode_btn->setIcon(QIcon(icon_fname)); - if (lan == QLocale::Chinese) + if (lan == LAN_CN) _mode_btn->setText((*i).second->name_cn); else _mode_btn->setText((*i).second->name); From 55ef4298cf18e4c5892b7386d1597cf531cf399a Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Wed, 24 Nov 2021 14:41:25 +0800 Subject: [PATCH 34/60] adjust interface style at macos --- DSView/pv/view/devmode.cpp | 131 ++++++++++++++++++++----------------- DSView/pv/view/devmode.h | 14 ++-- DSView/pv/view/view.cpp | 11 ++-- DSView/themes/dark.qss | 22 +++++-- DSView/themes/light.qss | 21 ++++-- qtpro/DSView.pro.user | 2 +- 6 files changed, 115 insertions(+), 86 deletions(-) diff --git a/DSView/pv/view/devmode.cpp b/DSView/pv/view/devmode.cpp index cfc6c0db..1c3b5a8d 100755 --- a/DSView/pv/view/devmode.cpp +++ b/DSView/pv/view/devmode.cpp @@ -26,53 +26,60 @@ #include "../device/devinst.h" #include "../device/file.h" -#include - - +#include #include #include #include #include #include +#include + #include "../config/appconfig.h" #include "../ui/msgbox.h" - - + namespace pv { namespace view { DevMode::DevMode(QWidget *parent, SigSession *session) : QWidget(parent), - _session(session) - + _session(session) { - _layout = new QHBoxLayout(this); - _layout->setSpacing(0); - _layout->setContentsMargins(2, 0, 0, 0); + _bFile = false; - _close_button = new QToolButton(this); + QHBoxLayout *layout = new QHBoxLayout(this); + layout->setSpacing(0); + layout->setContentsMargins(2, 0, 0, 0); + + _close_button = new QToolButton(); _close_button->setObjectName("FileCloseButton"); _close_button->setContentsMargins(0, 0, 0, 0); _close_button->setFixedWidth(10); _close_button->setFixedHeight(height()); _close_button->setIconSize(QSize(10, 10)); - _close_button->setToolButtonStyle(Qt::ToolButtonIconOnly); + _close_button->setToolButtonStyle(Qt::ToolButtonIconOnly); + _close_button->setMinimumWidth(10); - _pop_menu = new QMenu(this); - - _mode_btn = new QToolButton(this); + _mode_btn = new QToolButton(); _mode_btn->setObjectName("ModeButton"); - _mode_btn->setIconSize(QSize(height()*2, height())); + _mode_btn->setIconSize(QSize(height() * 1.5, height())); _mode_btn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); - _mode_btn->setContentsMargins(0, 0, 1000, 0); - _mode_btn->setMenu(_pop_menu); + _mode_btn->setContentsMargins(0, 0, 0, 0); _mode_btn->setPopupMode(QToolButton::InstantPopup); _mode_btn->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum); - _layout->addWidget(_close_button); - _layout->addWidget(_mode_btn); - _layout->setStretch(1, 100); - setLayout(_layout); + // _mode_btn->setArrowType(Qt::NoArrow); + + _pop_menu = new QMenu(this); + _pop_menu->setContentsMargins(15,0,0,0); + _mode_btn->setMenu(_pop_menu); + + layout->addWidget(_close_button); + layout->addWidget(_mode_btn); + + layout->setStretch(1, 100); + setLayout(layout); + + connect(_close_button, SIGNAL(clicked()), this, SLOT(on_close())); } @@ -89,7 +96,10 @@ void DevMode::set_device() { DevInst* dev_inst = _session->get_device(); assert(dev_inst); + + _bFile = false; + //remove all action object for(std::map::const_iterator i = _mode_list.begin(); i != _mode_list.end(); i++) { (*i).first->setParent(NULL); @@ -97,53 +107,54 @@ void DevMode::set_device() delete (*i).first; } _mode_list.clear(); + _close_button->setIcon(QIcon()); - _close_button->setDisabled(true); - disconnect(_close_button, SIGNAL(clicked()), this, SLOT(on_close())); + _close_button->setDisabled(true); AppConfig &app = AppConfig::Instance(); int lan = app._frameOptions.language; - if (true) { - QString iconPath = GetIconPath() + "/"; - for (const GSList *l = dev_inst->get_dev_mode_list(); - l; l = l->next) { - const sr_dev_mode *mode = (const sr_dev_mode *)l->data; - QString icon_name = QString::fromLocal8Bit(mode->icon); - - QAction *action = new QAction(this); - action->setIcon(QIcon(iconPath+"square-"+icon_name)); + QString iconPath = GetIconPath() + "/"; + + for (const GSList *l = dev_inst->get_dev_mode_list(); l; l = l->next) + { + const sr_dev_mode *mode = (const sr_dev_mode *)l->data; + QString icon_name = QString::fromLocal8Bit(mode->icon); + + QAction *action = new QAction(this); + action->setIcon(QIcon(iconPath + "square-" + icon_name)); + if (lan == LAN_CN) + action->setText(mode->name_cn); + else + action->setText(mode->name); + + connect(action, SIGNAL(triggered()), this, SLOT(on_mode_change())); + + _mode_list[action] = mode; + if (dev_inst->dev_inst()->mode == _mode_list[action]->mode) + { + QString icon_fname = iconPath + icon_name; + _mode_btn->setIcon(QIcon(icon_fname)); if (lan == LAN_CN) - action->setText(mode->name_cn); + _mode_btn->setText(mode->name_cn); else - action->setText(mode->name); - - connect(action, SIGNAL(triggered()), this, SLOT(on_mode_change())); - - _mode_list[action] = mode; - if (dev_inst->dev_inst()->mode == _mode_list[action]->mode) { - QString icon_fname = iconPath + icon_name; - _mode_btn->setIcon(QIcon(icon_fname)); - if (lan== LAN_CN) - _mode_btn->setText(mode->name_cn); - else - _mode_btn->setText(mode->name); - } - _pop_menu->addAction(action); - } - - File *file_dev; - if((file_dev = dynamic_cast(dev_inst))) { - _close_button->setDisabled(false); - _close_button->setIcon(QIcon(iconPath+"/close.svg")); - connect(_close_button, SIGNAL(clicked()), this, SLOT(on_close())); + _mode_btn->setText(mode->name); } + _pop_menu->addAction(action); } + + if ((dynamic_cast(dev_inst))) + { + _close_button->setDisabled(false); + _close_button->setIcon(QIcon(iconPath + "/close.svg")); + _bFile = true; + } + update(); } void DevMode::paintEvent(QPaintEvent*) -{ +{ using pv::view::Trace; QStyleOption o; @@ -164,8 +175,8 @@ void DevMode::on_mode_change() AppConfig &app = AppConfig::Instance(); int lan = app._frameOptions.language; - for(std::map::const_iterator i = _mode_list.begin(); - i != _mode_list.end(); i++) { + for(auto i = _mode_list.begin();i != _mode_list.end(); i++) + { if ((*i).first == action) { if (dev_inst->dev_inst()->mode != (*i).second->mode) { _session->set_run_mode(SigSession::Single); @@ -186,6 +197,8 @@ void DevMode::on_mode_change() _mode_btn->setText((*i).second->name); dev_changed(false); } + + break; } } } @@ -195,7 +208,7 @@ void DevMode::on_close() DevInst *dev_inst = _session->get_device(); assert(dev_inst); - if (MsgBox::Confirm("are you sure to close the device?")){ + if (_bFile && MsgBox::Confirm("are you sure to close the device?")){ _session->close_file(dev_inst); dev_changed(true); } diff --git a/DSView/pv/view/devmode.h b/DSView/pv/view/devmode.h index d5c9fc1e..0d148da6 100755 --- a/DSView/pv/view/devmode.h +++ b/DSView/pv/view/devmode.h @@ -30,13 +30,12 @@ #include #include -#include #include #include #include #include - + namespace pv { namespace device{ @@ -81,13 +80,12 @@ signals: private: SigSession *_session; - - QHBoxLayout * _layout; std::map _mode_list; - QToolButton *_mode_btn; - QMenu *_pop_menu; - QPoint _mouse_point; - QToolButton *_close_button; + QToolButton *_mode_btn; + QMenu *_pop_menu; + QPoint _mouse_point; + QToolButton *_close_button; + bool _bFile; }; } // namespace view diff --git a/DSView/pv/view/view.cpp b/DSView/pv/view/view.cpp index 1728e03e..f0a196f0 100755 --- a/DSView/pv/view/view.cpp +++ b/DSView/pv/view/view.cpp @@ -922,12 +922,11 @@ void View::data_updated() void View::update_margins() { - _ruler->setGeometry(_viewcenter->x(), 0, - get_view_width(), _viewcenter->y()); - _header->setGeometry(0, _viewcenter->y(), - _viewcenter->x(), _viewcenter->height()); - _devmode->setGeometry(0, 0, - _viewcenter->x(), _viewcenter->y()); + _ruler->setGeometry(_viewcenter->x(), 0, get_view_width(), _viewcenter->y()); + + _header->setGeometry(0, _viewcenter->y(), _viewcenter->x(), _viewcenter->height()); + + _devmode->setGeometry(0, 0, _viewcenter->x(), _viewcenter->y()); } void View::header_updated() diff --git a/DSView/themes/dark.qss b/DSView/themes/dark.qss index 4ff510ba..194d7c97 100755 --- a/DSView/themes/dark.qss +++ b/DSView/themes/dark.qss @@ -1279,25 +1279,35 @@ QToolButton::menu-arrow:open QToolButton#ModeButton::menu-arrow { - image: url(:/dark/mode_down_arrow.svg); + /* image: url(:/dark/mode_down_arrow.svg);*/ + image:none; } /* the subcontrol below is used only in the InstantPopup or DelayedPopup mode */ QToolButton::menu-indicator { image: url(:/dark/down_arrow.svg); - top: -7px; - left: -2px; + top: -20px; + left: 0px; + width:8px; + height:10px; } + +QToolButton{ + font-size:14px; +} + QToolButton#ModeButton::menu-indicator { image: url(:/dark/mode_down_arrow.svg); - top: -7px; - left: -3px; + top: 0px; + left: 0px; + width:12px; + height:12px; } QToolButton#ModeButton::menu-indicator:hover { - top: -5px; + top: 0px; } QPushButton::menu-indicator diff --git a/DSView/themes/light.qss b/DSView/themes/light.qss index 06f704e6..54463857 100755 --- a/DSView/themes/light.qss +++ b/DSView/themes/light.qss @@ -1319,26 +1319,35 @@ QToolButton::menu-arrow:open QToolButton#ModeButton::menu-arrow { - image: url(:/light/mode_down_arrow.svg); + /*image: url(:/light/mode_down_arrow.svg);*/ + image:none; } /* the subcontrol below is used only in the InstantPopup or DelayedPopup mode */ QToolButton::menu-indicator { image: url(:/light/down_arrow.svg); - top: -7px; - left: -2px; + top: -20px; + left: 0px; + width:8px; + height:10px; +} + +QToolButton{ + font-size:14px; } QToolButton#ModeButton::menu-indicator { image: url(:/light/mode_down_arrow.svg); - top: -7px; - left: -3px; + top: 0px; + left: 0px; + width:12px; + height:12px; } QToolButton#ModeButton::menu-indicator:hover { - top: -5px; + top: 0px; } QPushButton::menu-indicator diff --git a/qtpro/DSView.pro.user b/qtpro/DSView.pro.user index c4f4a0b2..cc096235 100644 --- a/qtpro/DSView.pro.user +++ b/qtpro/DSView.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId From 0c2b4cf4302a7ae1dbb4cca80efd66f36845b62a Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Wed, 24 Nov 2021 14:42:16 +0800 Subject: [PATCH 35/60] none --- DSView/themes/dark.qss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DSView/themes/dark.qss b/DSView/themes/dark.qss index 194d7c97..63e3fd7b 100755 --- a/DSView/themes/dark.qss +++ b/DSView/themes/dark.qss @@ -1279,7 +1279,7 @@ QToolButton::menu-arrow:open QToolButton#ModeButton::menu-arrow { - /* image: url(:/dark/mode_down_arrow.svg);*/ + /*image: url(:/dark/mode_down_arrow.svg);*/ image:none; } From 050b6023d52ef53a5787b89b97bf5e6a1f51deb8 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Wed, 24 Nov 2021 17:04:12 +0800 Subject: [PATCH 36/60] any head file path ref mode changed --- DSView/pv/data/analogsnapshot.cpp | 4 +--- DSView/pv/data/decodermodel.h | 2 +- DSView/pv/data/dsosnapshot.cpp | 4 +--- DSView/pv/data/groupsnapshot.cpp | 5 ++--- DSView/pv/data/logicsnapshot.cpp | 5 ++--- DSView/pv/data/spectrumstack.cpp | 8 ++++---- DSView/pv/device/devinst.cpp | 2 +- DSView/pv/dialogs/about.h | 3 +-- DSView/pv/dialogs/calibration.h | 2 +- DSView/pv/dialogs/deviceoptions.cpp | 2 +- DSView/pv/dialogs/storeprogress.cpp | 2 +- DSView/pv/dock/triggerdock.cpp | 2 +- DSView/{ => pv}/extdef.h | 0 DSView/pv/mainframe.cpp | 2 +- DSView/pv/mainwindow.cpp | 4 ++-- DSView/pv/prop/binding/binding.cpp | 3 +-- DSView/pv/prop/binding/decoderoptions.cpp | 12 ++++++------ DSView/pv/prop/binding/deviceoptions.cpp | 2 +- DSView/pv/prop/binding/probeoptions.cpp | 8 ++++---- DSView/pv/storesession.cpp | 2 +- DSView/pv/toolbars/samplingbar.cpp | 6 ++---- DSView/pv/view/analogsignal.cpp | 3 ++- DSView/pv/view/cursor.cpp | 2 +- DSView/pv/view/decodetrace.cpp | 2 +- DSView/pv/view/decodetrace.h | 2 +- DSView/pv/view/dsosignal.cpp | 10 ++++------ DSView/pv/view/groupsignal.cpp | 10 +++++----- DSView/pv/view/header.cpp | 2 +- DSView/pv/view/lissajoustrace.cpp | 10 +++++----- DSView/pv/view/logicsignal.cpp | 11 ++++------- DSView/pv/view/mathtrace.cpp | 4 ++-- DSView/pv/view/ruler.cpp | 2 +- DSView/pv/view/signal.cpp | 8 +++----- DSView/pv/view/spectrumtrace.cpp | 3 ++- DSView/pv/view/trace.cpp | 3 ++- DSView/pv/view/view.cpp | 10 +++++----- DSView/pv/view/view.h | 3 ++- DSView/pv/view/viewport.h | 2 +- DSView/pv/view/viewstatus.h | 1 - DSView/test/data/analogsnapshot.cpp | 6 ++---- DSView/test/data/logicsnapshot.cpp | 2 +- libsigrok4DSL/hardware/DSL/command.c | 4 ++-- libsigrok4DSL/hardware/DSL/command.h | 4 ++-- libsigrok4DSL/hardware/DSL/dscope.c | 4 ++-- libsigrok4DSL/hardware/DSL/dsl.c | 4 ++-- libsigrok4DSL/hardware/DSL/dsl.h | 4 ++-- libsigrok4DSL/hardware/DSL/dslogic.c | 4 ++-- libsigrok4DSL/hardware/common/ezusb.c | 4 ++-- libsigrok4DSL/hardware/common/usb.c | 4 ++-- libsigrok4DSL/hardware/demo/demo.h | 4 ++-- libsigrok4DSL/input/in_binary.c | 4 ++-- libsigrok4DSL/input/in_vcd.c | 4 ++-- libsigrok4DSL/input/in_wav.c | 4 ++-- libsigrok4DSL/input/input.c | 4 ++-- libsigrok4DSL/output/csv.c | 6 +++--- libsigrok4DSL/output/gnuplot.c | 4 ++-- libsigrok4DSL/output/output.c | 4 ++-- libsigrok4DSL/output/srzip.c | 4 ++-- libsigrok4DSL/output/vcd.c | 6 +++--- qtpro/DSView.pro | 13 +++++-------- qtpro/DSView.pro.user | 2 +- 61 files changed, 124 insertions(+), 143 deletions(-) rename DSView/{ => pv}/extdef.h (100%) diff --git a/DSView/pv/data/analogsnapshot.cpp b/DSView/pv/data/analogsnapshot.cpp index 0fb067f3..329bafdf 100755 --- a/DSView/pv/data/analogsnapshot.cpp +++ b/DSView/pv/data/analogsnapshot.cpp @@ -20,16 +20,14 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include - #include #include #include #include - #include #include "analogsnapshot.h" +#include "../extdef.h" using namespace std; diff --git a/DSView/pv/data/decodermodel.h b/DSView/pv/data/decodermodel.h index 3a9d1760..a08fe1bf 100755 --- a/DSView/pv/data/decodermodel.h +++ b/DSView/pv/data/decodermodel.h @@ -23,7 +23,7 @@ #include -#include +#include "decode/rowdata.h" namespace pv { namespace data { diff --git a/DSView/pv/data/dsosnapshot.cpp b/DSView/pv/data/dsosnapshot.cpp index bf389c11..62642a94 100755 --- a/DSView/pv/data/dsosnapshot.cpp +++ b/DSView/pv/data/dsosnapshot.cpp @@ -19,16 +19,14 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include - #include #include #include #include - #include #include "dsosnapshot.h" +#include "../extdef.h" using namespace std; diff --git a/DSView/pv/data/groupsnapshot.cpp b/DSView/pv/data/groupsnapshot.cpp index 3eae0efb..1e8430a4 100755 --- a/DSView/pv/data/groupsnapshot.cpp +++ b/DSView/pv/data/groupsnapshot.cpp @@ -18,9 +18,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include - + #include #include #include @@ -30,6 +28,7 @@ #include "logicsnapshot.h" #include "groupsnapshot.h" +#include "../extdef.h" using namespace std; diff --git a/DSView/pv/data/logicsnapshot.cpp b/DSView/pv/data/logicsnapshot.cpp index 025422ba..f4e42584 100755 --- a/DSView/pv/data/logicsnapshot.cpp +++ b/DSView/pv/data/logicsnapshot.cpp @@ -19,9 +19,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include - + #include #include @@ -30,6 +28,7 @@ #include #include "logicsnapshot.h" +#include "../extdef.h" using namespace std; diff --git a/DSView/pv/data/spectrumstack.cpp b/DSView/pv/data/spectrumstack.cpp index 72759c7e..99c34e9b 100755 --- a/DSView/pv/data/spectrumstack.cpp +++ b/DSView/pv/data/spectrumstack.cpp @@ -20,10 +20,10 @@ #include "spectrumstack.h" -#include -#include -#include -#include +#include "dso.h" +#include "dsosnapshot.h" +#include "../sigsession.h" +#include "../view/dsosignal.h" #include #define PI 3.1415 diff --git a/DSView/pv/device/devinst.cpp b/DSView/pv/device/devinst.cpp index 1fe1b2f4..29777872 100755 --- a/DSView/pv/device/devinst.cpp +++ b/DSView/pv/device/devinst.cpp @@ -25,7 +25,7 @@ #include "devinst.h" -#include +#include "../sigsession.h" namespace pv { namespace device { diff --git a/DSView/pv/dialogs/about.h b/DSView/pv/dialogs/about.h index a82377e7..a86ca127 100755 --- a/DSView/pv/dialogs/about.h +++ b/DSView/pv/dialogs/about.h @@ -27,8 +27,7 @@ #include #include "dsdialog.h" -#include - + namespace pv { namespace dialogs { diff --git a/DSView/pv/dialogs/calibration.h b/DSView/pv/dialogs/calibration.h index b5c71e27..6253de04 100755 --- a/DSView/pv/dialogs/calibration.h +++ b/DSView/pv/dialogs/calibration.h @@ -31,7 +31,7 @@ #include -#include +#include "../device/devinst.h" #include "../toolbars/titlebar.h" #include "dsdialog.h" diff --git a/DSView/pv/dialogs/deviceoptions.cpp b/DSView/pv/dialogs/deviceoptions.cpp index 3fa3be2c..b0b6119e 100755 --- a/DSView/pv/dialogs/deviceoptions.cpp +++ b/DSView/pv/dialogs/deviceoptions.cpp @@ -27,7 +27,7 @@ #include #include "dsmessagebox.h" -#include +#include "../prop/property.h" #include "../dsvdef.h" using namespace boost; diff --git a/DSView/pv/dialogs/storeprogress.cpp b/DSView/pv/dialogs/storeprogress.cpp index 7c0b31de..168a4c75 100755 --- a/DSView/pv/dialogs/storeprogress.cpp +++ b/DSView/pv/dialogs/storeprogress.cpp @@ -20,7 +20,7 @@ */ #include "storeprogress.h" -#include "pv/sigsession.h" +#include "../sigsession.h" #include #include #include diff --git a/DSView/pv/dock/triggerdock.cpp b/DSView/pv/dock/triggerdock.cpp index 1b869fe0..962f6a9f 100755 --- a/DSView/pv/dock/triggerdock.cpp +++ b/DSView/pv/dock/triggerdock.cpp @@ -35,7 +35,7 @@ #include #include -#include "libsigrok4DSL/libsigrok.h" +#include namespace pv { namespace dock { diff --git a/DSView/extdef.h b/DSView/pv/extdef.h similarity index 100% rename from DSView/extdef.h rename to DSView/pv/extdef.h diff --git a/DSView/pv/mainframe.cpp b/DSView/pv/mainframe.cpp index cd9b1e71..5f7c3be0 100644 --- a/DSView/pv/mainframe.cpp +++ b/DSView/pv/mainframe.cpp @@ -46,7 +46,7 @@ #include "dsvdef.h" #include "config/appconfig.h" -#include "../ui/msgbox.h" +#include "ui/msgbox.h" #include diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index 44d528b6..cfd76a37 100644 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -87,10 +87,10 @@ #include #include #include -#include "../ui/msgbox.h" +#include "ui/msgbox.h" #include "config/appconfig.h" #include "appcontrol.h" -#include "../dsvdef.h" +#include "dsvdef.h" namespace pv { diff --git a/DSView/pv/prop/binding/binding.cpp b/DSView/pv/prop/binding/binding.cpp index 345cae1e..4d861370 100755 --- a/DSView/pv/prop/binding/binding.cpp +++ b/DSView/pv/prop/binding/binding.cpp @@ -23,8 +23,7 @@ #include -#include - +#include "../property.h" #include "binding.h" diff --git a/DSView/pv/prop/binding/decoderoptions.cpp b/DSView/pv/prop/binding/decoderoptions.cpp index cdaca0df..b1ecae3b 100755 --- a/DSView/pv/prop/binding/decoderoptions.cpp +++ b/DSView/pv/prop/binding/decoderoptions.cpp @@ -26,12 +26,12 @@ #include -#include -#include -#include -#include -#include -#include +#include "../../data/decoderstack.h" +#include "../../data/decode/decoder.h" +#include "../double.h" +#include "../enum.h" +#include "../int.h" +#include "../string.h" using namespace boost; using namespace std; diff --git a/DSView/pv/prop/binding/deviceoptions.cpp b/DSView/pv/prop/binding/deviceoptions.cpp index 0b25ba33..66a9900f 100755 --- a/DSView/pv/prop/binding/deviceoptions.cpp +++ b/DSView/pv/prop/binding/deviceoptions.cpp @@ -31,7 +31,7 @@ #include "../double.h" #include "../enum.h" #include "../int.h" -#include "../config/appconfig.h" +#include "../../config/appconfig.h" using namespace boost; using namespace std; diff --git a/DSView/pv/prop/binding/probeoptions.cpp b/DSView/pv/prop/binding/probeoptions.cpp index ec876265..74b18088 100755 --- a/DSView/pv/prop/binding/probeoptions.cpp +++ b/DSView/pv/prop/binding/probeoptions.cpp @@ -26,10 +26,10 @@ #include #include #include -#include -#include -#include -#include +#include "../bool.h" +#include "../double.h" +#include "../enum.h" +#include "../int.h" #include "../../config/appconfig.h" diff --git a/DSView/pv/storesession.cpp b/DSView/pv/storesession.cpp index 322ebd5f..b65b36ed 100755 --- a/DSView/pv/storesession.cpp +++ b/DSView/pv/storesession.cpp @@ -50,7 +50,7 @@ #include #include -#include +#include #include "config/appconfig.h" #include "dsvdef.h" diff --git a/DSView/pv/toolbars/samplingbar.cpp b/DSView/pv/toolbars/samplingbar.cpp index 49b84f8b..7281bde6 100755 --- a/DSView/pv/toolbars/samplingbar.cpp +++ b/DSView/pv/toolbars/samplingbar.cpp @@ -20,12 +20,10 @@ */ #include "samplingbar.h" +#include "../extdef.h" -#include -#include - +#include #include - #include #include #include diff --git a/DSView/pv/view/analogsignal.cpp b/DSView/pv/view/analogsignal.cpp index 1419046a..498d46f9 100755 --- a/DSView/pv/view/analogsignal.cpp +++ b/DSView/pv/view/analogsignal.cpp @@ -20,7 +20,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include + #include #include @@ -29,6 +29,7 @@ #include "../data/analogsnapshot.h" #include "../view/view.h" #include "../device/devinst.h" +#include "../extdef.h" using namespace std; diff --git a/DSView/pv/view/cursor.cpp b/DSView/pv/view/cursor.cpp index eca057ca..a4b667a3 100755 --- a/DSView/pv/view/cursor.cpp +++ b/DSView/pv/view/cursor.cpp @@ -35,7 +35,7 @@ #include #include -#include +#include "../extdef.h" namespace pv { namespace view { diff --git a/DSView/pv/view/decodetrace.cpp b/DSView/pv/view/decodetrace.cpp index aea46fe0..250ca49c 100755 --- a/DSView/pv/view/decodetrace.cpp +++ b/DSView/pv/view/decodetrace.cpp @@ -21,7 +21,7 @@ #include -#include +#include "../extdef.h" #include diff --git a/DSView/pv/view/decodetrace.h b/DSView/pv/view/decodetrace.h index 4f70df85..fde1ff23 100755 --- a/DSView/pv/view/decodetrace.h +++ b/DSView/pv/view/decodetrace.h @@ -30,7 +30,7 @@ #include #include -#include +#include "../prop/binding/decoderoptions.h" #include "../dialogs/dsdialog.h" struct srd_channel; diff --git a/DSView/pv/view/dsosignal.cpp b/DSView/pv/view/dsosignal.cpp index 24b69243..65e5fb59 100755 --- a/DSView/pv/view/dsosignal.cpp +++ b/DSView/pv/view/dsosignal.cpp @@ -19,13 +19,10 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include -#include - -#include "../../extdef.h" +#include "../extdef.h" #include "dsosignal.h" -#include "pv/data/dso.h" -#include "pv/data/dsosnapshot.h" +#include "../data/dso.h" +#include "../data/dsosnapshot.h" #include "view.h" #include "../sigsession.h" #include "../device/devinst.h" @@ -33,6 +30,7 @@ #include #include #include +#include using namespace std; diff --git a/DSView/pv/view/groupsignal.cpp b/DSView/pv/view/groupsignal.cpp index 898d455c..b33ae478 100755 --- a/DSView/pv/view/groupsignal.cpp +++ b/DSView/pv/view/groupsignal.cpp @@ -19,13 +19,13 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include -#include - +#include "../extdef.h" #include "groupsignal.h" -#include "pv/data/group.h" -#include "pv/data/groupsnapshot.h" +#include "../data/group.h" +#include "../data/groupsnapshot.h" #include "view.h" + +#include using namespace std; diff --git a/DSView/pv/view/header.cpp b/DSView/pv/view/header.cpp index b3aed97f..58563dd3 100755 --- a/DSView/pv/view/header.cpp +++ b/DSView/pv/view/header.cpp @@ -41,7 +41,7 @@ #include "decodetrace.h" #include "../sigsession.h" #include "../device/devinst.h" -#include "../../extdef.h" +#include "../extdef.h" #include "../dsvdef.h" diff --git a/DSView/pv/view/lissajoustrace.cpp b/DSView/pv/view/lissajoustrace.cpp index 81d8d33f..a39a66e7 100755 --- a/DSView/pv/view/lissajoustrace.cpp +++ b/DSView/pv/view/lissajoustrace.cpp @@ -19,14 +19,14 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include + #include -#include "../../extdef.h" -#include "lissajoustrace.h" -#include "pv/data/dso.h" -#include "pv/data/dsosnapshot.h" #include "view.h" +#include "../extdef.h" +#include "lissajoustrace.h" +#include "../data/dso.h" +#include "../data/dsosnapshot.h" #include "../sigsession.h" #include "../device/devinst.h" diff --git a/DSView/pv/view/logicsignal.cpp b/DSView/pv/view/logicsignal.cpp index 87f9fb93..dae072a8 100755 --- a/DSView/pv/view/logicsignal.cpp +++ b/DSView/pv/view/logicsignal.cpp @@ -21,18 +21,15 @@ */ #include - -#include - + #include - #include - #include "logicsignal.h" #include "view.h" -#include "pv/data/logic.h" -#include "pv/data/logicsnapshot.h" +#include "../data/logic.h" +#include "../data/logicsnapshot.h" #include "view.h" +#include "../extdef.h" using namespace boost; using namespace std; diff --git a/DSView/pv/view/mathtrace.cpp b/DSView/pv/view/mathtrace.cpp index 78a34280..8ea5d8ff 100755 --- a/DSView/pv/view/mathtrace.cpp +++ b/DSView/pv/view/mathtrace.cpp @@ -19,10 +19,9 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include + #include -#include "../../extdef.h" #include "mathtrace.h" #include "../data/dso.h" #include "../data/dsosnapshot.h" @@ -32,6 +31,7 @@ #include "../device/devinst.h" #include "../view/dsosignal.h" #include "../dsvdef.h" +#include "../extdef.h" #include #include diff --git a/DSView/pv/view/ruler.cpp b/DSView/pv/view/ruler.cpp index 25c54a95..905d9de7 100755 --- a/DSView/pv/view/ruler.cpp +++ b/DSView/pv/view/ruler.cpp @@ -28,7 +28,7 @@ #include "../sigsession.h" #include "../device/devinst.h" #include "dsosignal.h" -#include "../../extdef.h" +#include "../extdef.h" #include #include diff --git a/DSView/pv/view/signal.cpp b/DSView/pv/view/signal.cpp index 23011a23..f8146bef 100755 --- a/DSView/pv/view/signal.cpp +++ b/DSView/pv/view/signal.cpp @@ -20,14 +20,12 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include - -#include - - + +#include #include "signal.h" #include "view.h" #include "../device/devinst.h" +#include "../extdef.h" namespace pv { namespace view { diff --git a/DSView/pv/view/spectrumtrace.cpp b/DSView/pv/view/spectrumtrace.cpp index 3527a013..b55a1325 100755 --- a/DSView/pv/view/spectrumtrace.cpp +++ b/DSView/pv/view/spectrumtrace.cpp @@ -18,7 +18,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include + #include #include #include @@ -34,6 +34,7 @@ #include "../device/devinst.h" #include "../data/spectrumstack.h" #include "../dsvdef.h" +#include "../extdef.h" using namespace boost; using namespace std; diff --git a/DSView/pv/view/trace.cpp b/DSView/pv/view/trace.cpp index 782dfa85..cf6f17e3 100755 --- a/DSView/pv/view/trace.cpp +++ b/DSView/pv/view/trace.cpp @@ -20,7 +20,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include + #include #include #include @@ -31,6 +31,7 @@ #include "view.h" #include "../device/devinst.h" #include "../sigsession.h" +#include "../extdef.h" namespace pv { diff --git a/DSView/pv/view/view.cpp b/DSView/pv/view/view.cpp index f0a196f0..3328fb5d 100755 --- a/DSView/pv/view/view.cpp +++ b/DSView/pv/view/view.cpp @@ -42,11 +42,11 @@ #include "analogsignal.h" #include "../device/devinst.h" -#include "pv/sigsession.h" -#include "pv/data/logic.h" -#include "pv/data/logicsnapshot.h" -#include "pv/dialogs/calibration.h" -#include "pv/dialogs/lissajousoptions.h" +#include "../sigsession.h" +#include "../data/logic.h" +#include "../data/logicsnapshot.h" +#include "../dialogs/calibration.h" +#include "../dialogs/lissajousoptions.h" using namespace std; diff --git a/DSView/pv/view/view.h b/DSView/pv/view/view.h index a807dd85..6475cd7d 100755 --- a/DSView/pv/view/view.h +++ b/DSView/pv/view/view.h @@ -33,7 +33,7 @@ #include #include -#include "../../extdef.h" + #include "../toolbars/samplingbar.h" #include "../data/signaldata.h" #include "../view/viewport.h" @@ -41,6 +41,7 @@ #include "xcursor.h" #include "signal.h" #include "viewstatus.h" +#include "../extdef.h" namespace pv { diff --git a/DSView/pv/view/viewport.h b/DSView/pv/view/viewport.h index 0ba08201..0442645d 100755 --- a/DSView/pv/view/viewport.h +++ b/DSView/pv/view/viewport.h @@ -33,7 +33,7 @@ #include #include "../view/view.h" -#include "../../extdef.h" +#include "../extdef.h" class QPainter; class QPaintEvent; diff --git a/DSView/pv/view/viewstatus.h b/DSView/pv/view/viewstatus.h index c8edf813..c4125ca3 100755 --- a/DSView/pv/view/viewstatus.h +++ b/DSView/pv/view/viewstatus.h @@ -28,7 +28,6 @@ #include #include - #include namespace pv { diff --git a/DSView/test/data/analogsnapshot.cpp b/DSView/test/data/analogsnapshot.cpp index cd1fd773..7cf4f289 100755 --- a/DSView/test/data/analogsnapshot.cpp +++ b/DSView/test/data/analogsnapshot.cpp @@ -17,15 +17,13 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include - + #define __STDC_LIMIT_MACROS #include #include - #include "../../pv/data/analogsnapshot.h" +#include "../extdef.h" using namespace std; diff --git a/DSView/test/data/logicsnapshot.cpp b/DSView/test/data/logicsnapshot.cpp index bbc74383..2473580e 100755 --- a/DSView/test/data/logicsnapshot.cpp +++ b/DSView/test/data/logicsnapshot.cpp @@ -18,7 +18,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include +#include "../extdef.h" #define __STDC_LIMIT_MACROS #include diff --git a/libsigrok4DSL/hardware/DSL/command.c b/libsigrok4DSL/hardware/DSL/command.c index 82170f08..b391237d 100755 --- a/libsigrok4DSL/hardware/DSL/command.c +++ b/libsigrok4DSL/hardware/DSL/command.c @@ -17,8 +17,8 @@ * along with this program. If not, see . */ -#include "libsigrok.h" -#include "libsigrok-internal.h" +#include "../../libsigrok.h" +#include "../../libsigrok-internal.h" #include "command.h" #include "dsl.h" diff --git a/libsigrok4DSL/hardware/DSL/command.h b/libsigrok4DSL/hardware/DSL/command.h index 0a541c47..a5647638 100755 --- a/libsigrok4DSL/hardware/DSL/command.h +++ b/libsigrok4DSL/hardware/DSL/command.h @@ -21,8 +21,8 @@ #define LIBDSL_HARDWARE_COMMAND_H #include -#include "libsigrok.h" -#include "libsigrok-internal.h" +#include "../../libsigrok.h" +#include "../../libsigrok-internal.h" /* Protocol commands */ #define CMD_CTL_WR 0xb0 diff --git a/libsigrok4DSL/hardware/DSL/dscope.c b/libsigrok4DSL/hardware/DSL/dscope.c index 12652a55..b9bdb446 100755 --- a/libsigrok4DSL/hardware/DSL/dscope.c +++ b/libsigrok4DSL/hardware/DSL/dscope.c @@ -18,8 +18,8 @@ * along with this program. If not, see . */ -#include "libsigrok.h" -#include "libsigrok-internal.h" +#include "../../libsigrok.h" +#include "../../libsigrok-internal.h" #include "dsl.h" #include "command.h" diff --git a/libsigrok4DSL/hardware/DSL/dsl.c b/libsigrok4DSL/hardware/DSL/dsl.c index a08452b1..01e2e01c 100755 --- a/libsigrok4DSL/hardware/DSL/dsl.c +++ b/libsigrok4DSL/hardware/DSL/dsl.c @@ -17,8 +17,8 @@ * along with this program. If not, see . */ -#include "libsigrok.h" -#include "libsigrok-internal.h" +#include "../../libsigrok.h" +#include "../../libsigrok-internal.h" #include "command.h" #include "dsl.h" diff --git a/libsigrok4DSL/hardware/DSL/dsl.h b/libsigrok4DSL/hardware/DSL/dsl.h index 4d695380..9f9fe95f 100755 --- a/libsigrok4DSL/hardware/DSL/dsl.h +++ b/libsigrok4DSL/hardware/DSL/dsl.h @@ -22,8 +22,8 @@ #define LIBDSL_HARDWARE_DSL_H #include -#include "libsigrok.h" -#include "libsigrok-internal.h" +#include "../../libsigrok.h" +#include "../../libsigrok-internal.h" #include "command.h" #include diff --git a/libsigrok4DSL/hardware/DSL/dslogic.c b/libsigrok4DSL/hardware/DSL/dslogic.c index 443c8052..76419965 100755 --- a/libsigrok4DSL/hardware/DSL/dslogic.c +++ b/libsigrok4DSL/hardware/DSL/dslogic.c @@ -18,8 +18,8 @@ * along with this program. If not, see . */ -#include "libsigrok.h" -#include "libsigrok-internal.h" +#include "../../libsigrok.h" +#include "../../libsigrok-internal.h" #include "dsl.h" #include "command.h" diff --git a/libsigrok4DSL/hardware/common/ezusb.c b/libsigrok4DSL/hardware/common/ezusb.c index d05d2a79..dce61729 100755 --- a/libsigrok4DSL/hardware/common/ezusb.c +++ b/libsigrok4DSL/hardware/common/ezusb.c @@ -20,8 +20,8 @@ /* * Helper functions for the Cypress EZ-USB / FX2 series chips. */ -#include "libsigrok.h" -#include "libsigrok-internal.h" +#include "../../libsigrok.h" +#include "../../libsigrok-internal.h" //#include #include #include diff --git a/libsigrok4DSL/hardware/common/usb.c b/libsigrok4DSL/hardware/common/usb.c index 09c287ea..5e11c710 100755 --- a/libsigrok4DSL/hardware/common/usb.c +++ b/libsigrok4DSL/hardware/common/usb.c @@ -17,8 +17,8 @@ * along with this program. If not, see . */ -#include "libsigrok.h" -#include "libsigrok-internal.h" +#include "../../libsigrok.h" +#include "../../libsigrok-internal.h" #include #include //#include diff --git a/libsigrok4DSL/hardware/demo/demo.h b/libsigrok4DSL/hardware/demo/demo.h index 0a9cb52e..e347401f 100755 --- a/libsigrok4DSL/hardware/demo/demo.h +++ b/libsigrok4DSL/hardware/demo/demo.h @@ -22,8 +22,8 @@ #define LIBDSL_HARDWARE_DEMO_H #include -#include "libsigrok.h" -#include "libsigrok-internal.h" +#include "../../libsigrok.h" +#include "../../libsigrok-internal.h" #include #include diff --git a/libsigrok4DSL/input/in_binary.c b/libsigrok4DSL/input/in_binary.c index f75e1a1a..e9e3d7e8 100755 --- a/libsigrok4DSL/input/in_binary.c +++ b/libsigrok4DSL/input/in_binary.c @@ -17,8 +17,8 @@ * along with this program. If not, see . */ -#include "libsigrok.h" -#include "libsigrok-internal.h" +#include "../libsigrok.h" +#include "../libsigrok-internal.h" #include #include #include diff --git a/libsigrok4DSL/input/in_vcd.c b/libsigrok4DSL/input/in_vcd.c index 41ff6c0b..a19146a5 100755 --- a/libsigrok4DSL/input/in_vcd.c +++ b/libsigrok4DSL/input/in_vcd.c @@ -57,8 +57,8 @@ /* */ -#include "libsigrok.h" -#include "libsigrok-internal.h" +#include "../libsigrok.h" +#include "../libsigrok-internal.h" #include #include #include diff --git a/libsigrok4DSL/input/in_wav.c b/libsigrok4DSL/input/in_wav.c index 33db01d9..a576aa8a 100755 --- a/libsigrok4DSL/input/in_wav.c +++ b/libsigrok4DSL/input/in_wav.c @@ -17,8 +17,8 @@ * along with this program. If not, see . */ -#include "libsigrok.h" -#include "libsigrok-internal.h" +#include "../libsigrok.h" +#include "../libsigrok-internal.h" #include #include #include diff --git a/libsigrok4DSL/input/input.c b/libsigrok4DSL/input/input.c index 68ae49e4..bcfb6576 100755 --- a/libsigrok4DSL/input/input.c +++ b/libsigrok4DSL/input/input.c @@ -17,8 +17,8 @@ * along with this program. If not, see . */ -#include "libsigrok.h" -#include "libsigrok-internal.h" +#include "../libsigrok.h" +#include "../libsigrok-internal.h" /** * @file diff --git a/libsigrok4DSL/output/csv.c b/libsigrok4DSL/output/csv.c index ad95756b..4aa398a5 100755 --- a/libsigrok4DSL/output/csv.c +++ b/libsigrok4DSL/output/csv.c @@ -18,12 +18,12 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libsigrok.h" -#include "libsigrok-internal.h" +#include "../libsigrok.h" +#include "../libsigrok-internal.h" #include #include #include -#include "config.h" /* Needed for PACKAGE_STRING and others. */ +#include "../config.h" /* Needed for PACKAGE_STRING and others. */ #define LOG_PREFIX "output/csv" diff --git a/libsigrok4DSL/output/gnuplot.c b/libsigrok4DSL/output/gnuplot.c index 1644fceb..e39c1d4c 100755 --- a/libsigrok4DSL/output/gnuplot.c +++ b/libsigrok4DSL/output/gnuplot.c @@ -18,8 +18,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libsigrok.h" -#include "libsigrok-internal.h" +#include "../libsigrok.h" +#include "../libsigrok-internal.h" #include #include #include diff --git a/libsigrok4DSL/output/output.c b/libsigrok4DSL/output/output.c index 639bd24b..68292a86 100755 --- a/libsigrok4DSL/output/output.c +++ b/libsigrok4DSL/output/output.c @@ -17,8 +17,8 @@ * along with this program. If not, see . */ -#include "libsigrok.h" -#include "libsigrok-internal.h" +#include "../libsigrok.h" +#include "../libsigrok-internal.h" #include /** @cond PRIVATE */ diff --git a/libsigrok4DSL/output/srzip.c b/libsigrok4DSL/output/srzip.c index 5f19f5ab..f723ce69 100755 --- a/libsigrok4DSL/output/srzip.c +++ b/libsigrok4DSL/output/srzip.c @@ -17,8 +17,8 @@ * along with this program. If not, see . */ -#include "libsigrok.h" -#include "libsigrok-internal.h" +#include "../libsigrok.h" +#include "../libsigrok-internal.h" #include #include #include diff --git a/libsigrok4DSL/output/vcd.c b/libsigrok4DSL/output/vcd.c index ce923350..37a5a9af 100755 --- a/libsigrok4DSL/output/vcd.c +++ b/libsigrok4DSL/output/vcd.c @@ -19,12 +19,12 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libsigrok.h" -#include "libsigrok-internal.h" +#include "../libsigrok.h" +#include "../libsigrok-internal.h" #include #include #include -#include "config.h" /* Needed for PACKAGE and others. */ +#include "../config.h" /* Needed for PACKAGE and others. */ #define LOG_PREFIX "output/vcd" diff --git a/qtpro/DSView.pro b/qtpro/DSView.pro index 5d30bed6..419d9b4a 100644 --- a/qtpro/DSView.pro +++ b/qtpro/DSView.pro @@ -27,16 +27,14 @@ CONFIG += decoders DEFINES += decoders unix:!macx { -INCLUDEPATH += /usr/local/include/ INCLUDEPATH += /usr/include/glib-2.0 INCLUDEPATH += /usr/lib/x86_64-linux-gnu/glib-2.0/include INCLUDEPATH += /usr/include/libusb-1.0 INCLUDEPATH += /usr/include/boost INCLUDEPATH += /usr/include/python3.8 INCLUDEPATH += .. -INCLUDEPATH += ../libsigrok4DSL -INCLUDEPATH += ../DSView -INCLUDEPATH += ../DSView/pv/dialogs +#INCLUDEPATH += ../libsigrok4DSL +#INCLUDEPATH += ../DSView LIBS += /usr/lib/x86_64-linux-gnu/libglib-2.0.so LIBS += /usr/lib/x86_64-linux-gnu/libusb-1.0.so @@ -57,9 +55,8 @@ INCLUDEPATH += /usr/local/include/libusb-1.0 INCLUDEPATH += /usr/local/include/boost INCLUDEPATH += /Library/Frameworks/Python.framework/Versions/3.4/include/python3.4m INCLUDEPATH += .. -INCLUDEPATH += ../libsigrok4DSL -INCLUDEPATH += ../DSView -INCLUDEPATH += ../DSView/pv/dialogs +#INCLUDEPATH += ../libsigrok4DSL +#INCLUDEPATH += ../DSView #LIBS += -framework CoreFoundation #LIBS += -framework CoreServices @@ -176,7 +173,7 @@ SOURCES += \ ../DSView/pv/dstimer.cpp HEADERS += \ - ../DSView/extdef.h \ + ../DSView/pv/extdef.h \ ../DSView/config.h \ ../DSView/pv/sigsession.h \ ../DSView/pv/mainwindow.h \ diff --git a/qtpro/DSView.pro.user b/qtpro/DSView.pro.user index cc096235..2e3a9259 100644 --- a/qtpro/DSView.pro.user +++ b/qtpro/DSView.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId From 5740946c7c833b7bc2bc1b5bc487a4446cd0c553 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Thu, 25 Nov 2021 10:50:39 +0800 Subject: [PATCH 37/60] fix resource dir not find bug --- DSView/main.cpp | 5 +---- DSView/pv/appcontrol.cpp | 3 +++ DSView/pv/config/appconfig.cpp | 7 ++++++- DSView/pv/devicemanager.h | 4 +--- DSView/pv/mainwindow.cpp | 1 - DSView/pv/toolbars/logobar.cpp | 1 - DSView/pv/toolbars/samplingbar.cpp | 1 - libsigrok4DSL/libsigrok-internal.h | 6 ++++++ libsigrok4DSL/libsigrok.h | 2 -- libsigrok4DSL/proto.h | 2 ++ libsigrok4DSL/session.c | 15 +++++++++++++++ qtpro/DSView.pro | 4 ---- qtpro/DSView.pro.user | 2 +- 13 files changed, 35 insertions(+), 18 deletions(-) diff --git a/DSView/main.cpp b/DSView/main.cpp index 978f37b2..8485be26 100755 --- a/DSView/main.cpp +++ b/DSView/main.cpp @@ -51,7 +51,6 @@ void usage() "\n", DS_BIN_NAME, DS_DESCRIPTION); } -char DS_RES_PATH[256] = {0}; int main(int argc, char *argv[]) { @@ -146,9 +145,7 @@ int main(int argc, char *argv[]) open_file = argvFinal[argcFinal - 1]; } - QString path = GetAppDataDir(); - strcpy(DS_RES_PATH, path.toUtf8().data()); - + //#ifdef Q_OS_DARWIN //#endif diff --git a/DSView/pv/appcontrol.cpp b/DSView/pv/appcontrol.cpp index 34fb8f99..52275e88 100644 --- a/DSView/pv/appcontrol.cpp +++ b/DSView/pv/appcontrol.cpp @@ -73,6 +73,9 @@ bool AppControl::Init() m_error = "DSView run ERROR: libsigrok init failed."; return false; } + + QString resdir = GetResourceDir(); + sr_set_firmware_resource_dir(resdir.toUtf8()); QString dir = GetAppDataDir() + "/decoders"; char path[256] = {0}; diff --git a/DSView/pv/config/appconfig.cpp b/DSView/pv/config/appconfig.cpp index 50aeb5cb..920300fe 100644 --- a/DSView/pv/config/appconfig.cpp +++ b/DSView/pv/config/appconfig.cpp @@ -307,5 +307,10 @@ QString GetAppDataDir() } QString GetResourceDir(){ - return GetAppDataDir() + "/res"; + QDir dir = GetAppDataDir() + "/res"; + if (dir.exists()){ + return dir.absolutePath(); + } + qDebug() << "dir is not exists:" << dir.absolutePath(); + assert(false); } diff --git a/DSView/pv/devicemanager.h b/DSView/pv/devicemanager.h index 79f3502d..c8b85b63 100755 --- a/DSView/pv/devicemanager.h +++ b/DSView/pv/devicemanager.h @@ -35,9 +35,7 @@ struct sr_context; struct sr_dev_driver; struct sr_dev_inst; -struct libusbhp_t; -struct libusbhp_device_t; - + namespace pv { class SigSession; diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index cfd76a37..61979413 100644 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -86,7 +86,6 @@ #include #include #include -#include #include "ui/msgbox.h" #include "config/appconfig.h" #include "appcontrol.h" diff --git a/DSView/pv/toolbars/logobar.cpp b/DSView/pv/toolbars/logobar.cpp index c08d2bc1..3914d9f0 100755 --- a/DSView/pv/toolbars/logobar.cpp +++ b/DSView/pv/toolbars/logobar.cpp @@ -200,7 +200,6 @@ void LogoBar::on_actionManual_triggered() void LogoBar::on_actionIssue_triggered() { - QDir dir(GetAppDataDir()); QDesktopServices::openUrl(QUrl(QLatin1String("https://github.com/DreamSourceLab/DSView/issues"))); } diff --git a/DSView/pv/toolbars/samplingbar.cpp b/DSView/pv/toolbars/samplingbar.cpp index 7281bde6..753eeb92 100755 --- a/DSView/pv/toolbars/samplingbar.cpp +++ b/DSView/pv/toolbars/samplingbar.cpp @@ -23,7 +23,6 @@ #include "../extdef.h" #include -#include #include #include #include diff --git a/libsigrok4DSL/libsigrok-internal.h b/libsigrok4DSL/libsigrok-internal.h index de86db20..9eb3f5fc 100755 --- a/libsigrok4DSL/libsigrok-internal.h +++ b/libsigrok4DSL/libsigrok-internal.h @@ -27,6 +27,9 @@ #include #endif +// firmware binary file directory, endswith letter '/' +extern char DS_RES_PATH[256]; + /** * @file * @@ -119,6 +122,9 @@ SR_PRIV int sr_session_send(const struct sr_dev_inst *sdi, const struct sr_datafeed_packet *packet); SR_PRIV int sr_session_stop_sync(void); +SR_PRIV int usb_hotplug_callback(struct libusb_context *ctx, struct libusb_device *dev, + libusb_hotplug_event event, void *user_data); + /*--- std.c -----------------------------------------------------------------*/ typedef int (*dev_close_t)(struct sr_dev_inst *sdi); diff --git a/libsigrok4DSL/libsigrok.h b/libsigrok4DSL/libsigrok.h index d36dffcf..9ca4936b 100755 --- a/libsigrok4DSL/libsigrok.h +++ b/libsigrok4DSL/libsigrok.h @@ -134,8 +134,6 @@ enum { #define MAX_TIMEBASE SR_SEC(10) #define MIN_TIMEBASE SR_NS(10) -extern char DS_RES_PATH[256]; - /** libsigrok loglevels. */ enum { SR_LOG_NONE = 0, /**< Output no messages at all. */ diff --git a/libsigrok4DSL/proto.h b/libsigrok4DSL/proto.h index 81452c3a..0ebd0d26 100755 --- a/libsigrok4DSL/proto.h +++ b/libsigrok4DSL/proto.h @@ -186,5 +186,7 @@ SR_API void sr_set_export_original_data(int flag); SR_API int sr_get_export_original_flag(); +SR_API void sr_set_firmware_resource_dir(const char *dir); + #endif diff --git a/libsigrok4DSL/session.c b/libsigrok4DSL/session.c index ce46fcb9..ba857999 100755 --- a/libsigrok4DSL/session.c +++ b/libsigrok4DSL/session.c @@ -34,6 +34,8 @@ #define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args) #define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args) +char DS_RES_PATH[256] = {0}; + int bExportOriginalData = 0; //able export all data int session_loop_stop_flag = 0; @@ -832,4 +834,17 @@ SR_API int sr_get_export_original_flag() return bExportOriginalData; } +void sr_set_firmware_resource_dir(const char *dir) +{ + if (dir){ + strcpy(DS_RES_PATH, dir); + + int len = strlen(DS_RES_PATH); + if (DS_RES_PATH[len-1] != '/'){ + DS_RES_PATH[len] = '/'; + DS_RES_PATH[len+1] = 0; + } + } +} + /** @} */ diff --git a/qtpro/DSView.pro b/qtpro/DSView.pro index 419d9b4a..57b0ae30 100644 --- a/qtpro/DSView.pro +++ b/qtpro/DSView.pro @@ -33,8 +33,6 @@ INCLUDEPATH += /usr/include/libusb-1.0 INCLUDEPATH += /usr/include/boost INCLUDEPATH += /usr/include/python3.8 INCLUDEPATH += .. -#INCLUDEPATH += ../libsigrok4DSL -#INCLUDEPATH += ../DSView LIBS += /usr/lib/x86_64-linux-gnu/libglib-2.0.so LIBS += /usr/lib/x86_64-linux-gnu/libusb-1.0.so @@ -55,8 +53,6 @@ INCLUDEPATH += /usr/local/include/libusb-1.0 INCLUDEPATH += /usr/local/include/boost INCLUDEPATH += /Library/Frameworks/Python.framework/Versions/3.4/include/python3.4m INCLUDEPATH += .. -#INCLUDEPATH += ../libsigrok4DSL -#INCLUDEPATH += ../DSView #LIBS += -framework CoreFoundation #LIBS += -framework CoreServices diff --git a/qtpro/DSView.pro.user b/qtpro/DSView.pro.user index 2e3a9259..1c801f1b 100644 --- a/qtpro/DSView.pro.user +++ b/qtpro/DSView.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId From f6ca1f6ed8e8e1b3e6edb7dcb335444020c51227 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Thu, 25 Nov 2021 15:41:00 +0800 Subject: [PATCH 38/60] fix capture thread stop bug --- DSView/pv/data/snapshot.cpp | 42 +---------- DSView/pv/data/snapshot.h | 36 ++++++--- DSView/pv/device/devinst.cpp | 7 +- DSView/pv/mainwindow.cpp | 11 ++- DSView/pv/mainwindow.h | 4 +- libsigrok4DSL/libsigrok-internal.h | 2 +- libsigrok4DSL/session.c | 16 ++-- libsigrokdecode4DSL/config.h | 114 +++++++++++++++++++++++++++++ 8 files changed, 161 insertions(+), 71 deletions(-) create mode 100644 libsigrokdecode4DSL/config.h diff --git a/DSView/pv/data/snapshot.cpp b/DSView/pv/data/snapshot.cpp index bac3cc16..c359addb 100755 --- a/DSView/pv/data/snapshot.cpp +++ b/DSView/pv/data/snapshot.cpp @@ -64,11 +64,6 @@ void Snapshot::free_data() _ch_index.clear(); } -bool Snapshot::memory_failed() -{ - return _memory_failed; -} - bool Snapshot::empty() { if (get_sample_count() == 0) @@ -77,16 +72,6 @@ bool Snapshot::empty() return false; } -bool Snapshot::last_ended() -{ - return _last_ended; -} - -void Snapshot::set_last_ended(bool ended) -{ - _last_ended = ended; -} - uint64_t Snapshot::get_sample_count() { std::lock_guard lock(_mutex); @@ -104,12 +89,7 @@ uint64_t Snapshot::get_ring_end() std::lock_guard lock(_mutex); return ring_end(); } - -uint64_t Snapshot::sample_count() -{ - return _sample_count; -} - + uint64_t Snapshot::ring_start() { if (_sample_count < _total_sample_count) @@ -128,26 +108,6 @@ uint64_t Snapshot::ring_end() return _ring_sample_count - 1; } -const void* Snapshot::get_data() -{ - return _data; -} - -int Snapshot::unit_size() -{ - return _unit_size; -} - -uint8_t Snapshot::get_unit_bytes() -{ - return _unit_bytes; -} - -unsigned int Snapshot::get_channel_num() -{ - return _channel_num; -} - void Snapshot::capture_ended() { set_last_ended(true); diff --git a/DSView/pv/data/snapshot.h b/DSView/pv/data/snapshot.h index b3447b89..5113aef0 100755 --- a/DSView/pv/data/snapshot.h +++ b/DSView/pv/data/snapshot.h @@ -43,18 +43,35 @@ public: uint64_t get_ring_start(); uint64_t get_ring_end(); - const void * get_data(); + inline const void* get_data(){ + return _data; + } - int unit_size(); - uint8_t get_unit_bytes(); + inline int unit_size(){ + return _unit_size; + } + + inline uint8_t get_unit_bytes(){ + return _unit_bytes; + } + + inline bool memory_failed(){ + return _memory_failed; + } - bool memory_failed(); bool empty(); - bool last_ended(); - void set_last_ended(bool ended); + inline bool last_ended(){ + return _last_ended; + } - unsigned int get_channel_num(); + inline void set_last_ended(bool ended){ + _last_ended = ended; + } + + inline unsigned int get_channel_num(){ + return _channel_num; + } virtual void capture_ended(); virtual bool has_data(int index) = 0; @@ -64,10 +81,11 @@ public: protected: virtual void free_data(); - uint64_t sample_count(); + inline uint64_t sample_count(){ + return _sample_count; + } uint64_t ring_start(); - uint64_t ring_end(); protected: diff --git a/DSView/pv/device/devinst.cpp b/DSView/pv/device/devinst.cpp index 29777872..f4b03485 100755 --- a/DSView/pv/device/devinst.cpp +++ b/DSView/pv/device/devinst.cpp @@ -200,7 +200,12 @@ void DevInst::start() void DevInst::run() { - sr_session_run(); + qDebug()<<"session run loop start"; + int ret = sr_session_run(); + if (ret != SR_OK){ + qDebug()<<"start session error!"; + } + qDebug()<<"session run loop end"; } void DevInst::stop() diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index 61979413..cbd65ecd 100644 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #include @@ -236,10 +237,7 @@ void MainWindow::setup_ui() // UI initial _measure_widget->add_dist_measure(); - - // update device - update_device_list(); - + _session->start_hotplug_work(); retranslateUi(); @@ -302,6 +300,9 @@ void MainWindow::setup_ui() connect(_dso_trigger_widget, SIGNAL(set_trig_pos(int)), _view, SLOT(set_trig_pos(int))); _logo_bar->set_mainform_callback(this); + + //delay to update device list + QTimer::singleShot(200, this, SLOT(update_device_list())); } @@ -457,8 +458,6 @@ void MainWindow::on_load_file(QString file_name) } catch(QString e) { show_error(tr("Failed to load ") + file_name); _session->set_default_device(); - update_device_list(); - return; } update_device_list(); diff --git a/DSView/pv/mainwindow.h b/DSView/pv/mainwindow.h index 8cbf35a9..6e284bb8 100755 --- a/DSView/pv/mainwindow.h +++ b/DSView/pv/mainwindow.h @@ -91,8 +91,7 @@ private: void setup_ui(); void retranslateUi(); bool eventFilter(QObject *object, QEvent *event); - bool load_session_json(QJsonDocument json, bool file_dev,bool bDecoder=true); - void update_device_list(); + bool load_session_json(QJsonDocument json, bool file_dev,bool bDecoder=true); public slots: void switchTheme(QString style); @@ -102,6 +101,7 @@ private slots: void on_load_file(QString file_name); void on_open_doc(); void on_device_updated_reload(); + void update_device_list(); void on_run_stop(); void on_instant_stop(); diff --git a/libsigrok4DSL/libsigrok-internal.h b/libsigrok4DSL/libsigrok-internal.h index 9eb3f5fc..c310a370 100755 --- a/libsigrok4DSL/libsigrok-internal.h +++ b/libsigrok4DSL/libsigrok-internal.h @@ -28,7 +28,7 @@ #endif // firmware binary file directory, endswith letter '/' -extern char DS_RES_PATH[256]; +extern char DS_RES_PATH[500]; /** * @file diff --git a/libsigrok4DSL/session.c b/libsigrok4DSL/session.c index ba857999..74ca9996 100755 --- a/libsigrok4DSL/session.c +++ b/libsigrok4DSL/session.c @@ -34,12 +34,10 @@ #define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args) #define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args) -char DS_RES_PATH[256] = {0}; +char DS_RES_PATH[500] = {0}; int bExportOriginalData = 0; //able export all data -int session_loop_stop_flag = 0; - /** * @file * @@ -407,14 +405,12 @@ SR_API int sr_session_run(void) session->running = TRUE; - session_loop_stop_flag = 0; - sr_info("Running..."); /* Do we have real sources? */ if (session->num_sources == 1 && session->pollfds[0].fd == -1) { /* Dummy source, freewheel over it. */ - while (session->num_sources && !session_loop_stop_flag) { + while (session->num_sources) { if (session->abort_session) { session->sources[0].cb(-1, -1, session->sources[0].cb_data); break; @@ -424,7 +420,7 @@ SR_API int sr_session_run(void) } } else { /* Real sources, use g_poll() main loop. */ - while (session->num_sources && !session_loop_stop_flag){ + while (session->num_sources){ sr_session_iteration(TRUE); } } @@ -491,8 +487,6 @@ SR_API int sr_session_stop(void) return SR_ERR_BUG; } - session_loop_stop_flag = 1; //set flag, the run loop will exit - g_mutex_lock(&session->stop_mutex); if (session->running) session->abort_session = TRUE; @@ -841,8 +835,8 @@ void sr_set_firmware_resource_dir(const char *dir) int len = strlen(DS_RES_PATH); if (DS_RES_PATH[len-1] != '/'){ - DS_RES_PATH[len] = '/'; - DS_RES_PATH[len+1] = 0; + DS_RES_PATH[len] = '/'; + DS_RES_PATH[len + 1] = 0; } } } diff --git a/libsigrokdecode4DSL/config.h b/libsigrokdecode4DSL/config.h new file mode 100644 index 00000000..1d480390 --- /dev/null +++ b/libsigrokdecode4DSL/config.h @@ -0,0 +1,114 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define if building universal (internal helper macro) */ +/* #undef AC_APPLE_UNIVERSAL_BUILD */ + +/* The canonical host libsigrokdecode will run on. */ +#define CONF_HOST "x86_64-pc-linux-gnu" + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#define LT_OBJDIR ".libs/" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "support@dreamsourcelab.com" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "libsigrokdecode4DSL" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "libsigrokdecode4DSL 0.6.0" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "libsigrokdecode4DSL" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "http://www.dreamsourcelab.com" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "0.6.0" + +/* Binary age of libsigrokdecode4DSL. */ +#define SRD_LIB_VERSION_AGE 0 + +/* Binary version of libsigrokdecode4DSL. */ +#define SRD_LIB_VERSION_CURRENT 4 + +/* Binary revision of libsigrokdecode4DSL. */ +#define SRD_LIB_VERSION_REVISION 0 + +/* Binary version triple of libsigrokdecode4DSL. */ +#define SRD_LIB_VERSION_STRING "4:0:0" + +/* Major version number of libsigrokdecode4DSL. */ +#define SRD_PACKAGE_VERSION_MAJOR 0 + +/* Micro version number of libsigrokdecode4DSL. */ +#define SRD_PACKAGE_VERSION_MICRO 0 + +/* Minor version number of libsigrokdecode4DSL. */ +#define SRD_PACKAGE_VERSION_MINOR 6 + +/* Version of libsigrokdecode4DSL. */ +#define SRD_PACKAGE_VERSION_STRING "0.6.0-git-c708a00" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +/* # undef WORDS_BIGENDIAN */ +# endif +#endif + +/* Enable large inode numbers on Mac OS X 10.5. */ +#ifndef _DARWIN_USE_64_BIT_INODE +# define _DARWIN_USE_64_BIT_INODE 1 +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* The targeted POSIX standard. */ +#ifndef _POSIX_C_SOURCE +# define _POSIX_C_SOURCE 200112L +#endif From 82da3a6acd1aba361fe863cbbe72396a972f8da1 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Tue, 30 Nov 2021 14:17:47 +0800 Subject: [PATCH 39/60] make zip file in memory, function update --- DSView/pv/config/appconfig.cpp | 10 + DSView/pv/config/appconfig.h | 4 +- DSView/pv/device/device.cpp | 15 +- DSView/pv/device/devinst.cpp | 3 +- DSView/pv/device/sessionfile.cpp | 25 +- DSView/pv/devicemanager.cpp | 3 +- DSView/pv/dialogs/storeprogress.cpp | 6 +- DSView/pv/dialogs/storeprogress.h | 3 +- DSView/pv/interface/icallbacks.h | 6 + DSView/pv/mainwindow.cpp | 72 +++--- DSView/pv/mainwindow.h | 9 +- DSView/pv/sigsession.cpp | 8 +- DSView/pv/storesession.cpp | 382 ++++++++++++++++------------ DSView/pv/storesession.h | 18 +- libsigrok4DSL/dsdevice.c | 2 +- libsigrok4DSL/proto.h | 3 + libsigrok4DSL/session.c | 11 + qtpro/DSView.pro | 1 + qtpro/DSView.pro.user | 2 +- 19 files changed, 333 insertions(+), 250 deletions(-) diff --git a/DSView/pv/config/appconfig.cpp b/DSView/pv/config/appconfig.cpp index 920300fe..75fae622 100644 --- a/DSView/pv/config/appconfig.cpp +++ b/DSView/pv/config/appconfig.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #define MAX_PROTOCOL_FORMAT_LIST 15 @@ -314,3 +315,12 @@ QString GetResourceDir(){ qDebug() << "dir is not exists:" << dir.absolutePath(); assert(false); } + +QString GetUserDataDir() +{ + #if QT_VERSION >= 0x050400 + return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); + #else + return QStandardPaths::writableLocation(QStandardPaths::DataLocation); + #endif +} diff --git a/DSView/pv/config/appconfig.h b/DSView/pv/config/appconfig.h index f9cdb6a8..250e1868 100644 --- a/DSView/pv/config/appconfig.h +++ b/DSView/pv/config/appconfig.h @@ -33,12 +33,10 @@ //--------------------api--- QString GetDirectoryName(QString path); - QString GetIconPath(); - QString GetAppDataDir(); - QString GetResourceDir(); +QString GetUserDataDir(); //------------------class diff --git a/DSView/pv/device/device.cpp b/DSView/pv/device/device.cpp index 1f6c0bdb..4e056b45 100755 --- a/DSView/pv/device/device.cpp +++ b/DSView/pv/device/device.cpp @@ -33,8 +33,6 @@ Device::Device(sr_dev_inst *sdi) : _sdi(sdi) { assert(_sdi); - void *p = this; - (void)p; } Device::~Device() @@ -52,9 +50,8 @@ void Device::use(SigSession *owner) DevInst::use(owner); sr_session_new(); - - assert(_sdi); sr_dev_open(_sdi); + _usable = (_sdi->status == SR_ST_ACTIVE); if (sr_session_dev_add(_sdi) != SR_OK) throw QString(tr("Failed to use device.")); @@ -74,15 +71,6 @@ QString Device::format_device_title() { ostringstream s; - assert(_sdi); - -// if (_sdi->vendor && _sdi->vendor[0]) { -// s << _sdi->vendor; -// if ((_sdi->model && _sdi->model[0]) || -// (_sdi->version && _sdi->version[0])) -// s << ' '; -// } - if (_sdi->model && _sdi->model[0]) { s << _sdi->model; if (_sdi->version && _sdi->version[0]) @@ -97,7 +85,6 @@ QString Device::format_device_title() bool Device::is_trigger_enabled() { - assert(_sdi); for (const GSList *l = _sdi->channels; l; l = l->next) { const sr_channel *const p = (const sr_channel *)l->data; assert(p); diff --git a/DSView/pv/device/devinst.cpp b/DSView/pv/device/devinst.cpp index f4b03485..92c4894f 100755 --- a/DSView/pv/device/devinst.cpp +++ b/DSView/pv/device/devinst.cpp @@ -195,7 +195,8 @@ bool DevInst::is_trigger_enabled() void DevInst::start() { if (sr_session_start() != SR_OK) - throw tr("Failed to start session."); + throw tr("Failed to start session."); + //assert(false); } void DevInst::run() diff --git a/DSView/pv/device/sessionfile.cpp b/DSView/pv/device/sessionfile.cpp index 6d3f53d2..3873fa22 100755 --- a/DSView/pv/device/sessionfile.cpp +++ b/DSView/pv/device/sessionfile.cpp @@ -25,9 +25,9 @@ namespace pv { namespace device { SessionFile::SessionFile(QString path) : - File(path), - _sdi(NULL) + File(path) { + _sdi = NULL; } sr_dev_inst* SessionFile::dev_inst() @@ -38,6 +38,9 @@ sr_dev_inst* SessionFile::dev_inst() void SessionFile::use(SigSession *owner) { assert(!_sdi); + if (_sdi){ + //return; + } if (sr_session_load(_path.toUtf8().data()) != SR_OK) throw tr("Failed to open file.\n"); @@ -58,15 +61,15 @@ void SessionFile::use(SigSession *owner) } void SessionFile::release() -{ - if (!_owner || !_sdi) - return; - - File::release(); - sr_dev_close(_sdi); - sr_dev_clear(_sdi->driver); - sr_session_destroy(); - _sdi = NULL; +{ + if (_owner != NULL && _sdi != NULL) + { + File::release(); + sr_dev_close(_sdi); + sr_dev_clear(_sdi->driver); + sr_session_destroy(); + _sdi = NULL; + } } } // device diff --git a/DSView/pv/devicemanager.cpp b/DSView/pv/devicemanager.cpp index 448272ef..f148ee11 100755 --- a/DSView/pv/devicemanager.cpp +++ b/DSView/pv/devicemanager.cpp @@ -102,8 +102,7 @@ void DeviceManager::driver_scan( // list. They will not be valid after the scan. auto i = _devices.begin(); while (i != _devices.end()) { - if ((*i)->dev_inst() && - (*i)->dev_inst()->driver == driver) { + if ((*i)->dev_inst() && (*i)->dev_inst()->driver == driver) { (*i)->release(); i = _devices.erase(i); } else { diff --git a/DSView/pv/dialogs/storeprogress.cpp b/DSView/pv/dialogs/storeprogress.cpp index 168a4c75..28fa1571 100755 --- a/DSView/pv/dialogs/storeprogress.cpp +++ b/DSView/pv/dialogs/storeprogress.cpp @@ -158,18 +158,20 @@ void StoreProgress::timeout() _store_session.session()->set_saving(false); save_done(); close(); + delete this; + } else { QTimer::singleShot(100, this, SLOT(timeout())); } } -void StoreProgress::save_run(QString session_file) +void StoreProgress::save_run(ISessionDataGetter *getter) { _isExport = false; setTitle(tr("Saving...")); QString file = _store_session.MakeSaveFile(false); _fileLab->setText(file); - _store_session._sessionFile = session_file; + _store_session._sessionDataGetter = getter; show(); } diff --git a/DSView/pv/dialogs/storeprogress.h b/DSView/pv/dialogs/storeprogress.h index f0475b5d..54a5b548 100755 --- a/DSView/pv/dialogs/storeprogress.h +++ b/DSView/pv/dialogs/storeprogress.h @@ -25,6 +25,7 @@ #include #include "../storesession.h" #include "../dialogs/dsdialog.h" +#include "../interface/icallbacks.h" class QLineEdit; class QCheckBox; @@ -59,7 +60,7 @@ signals: void save_done(); public slots: - void save_run(QString session_file); + void save_run(ISessionDataGetter *getter); void export_run(); private slots: diff --git a/DSView/pv/interface/icallbacks.h b/DSView/pv/interface/icallbacks.h index 1d1627c3..0fca6f66 100644 --- a/DSView/pv/interface/icallbacks.h +++ b/DSView/pv/interface/icallbacks.h @@ -34,4 +34,10 @@ public: }; +class ISessionDataGetter +{ +public: + virtual bool genSessionData(std::string &str) = 0; +}; + #endif diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index cbd65ecd..70caa8f4 100644 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -913,25 +913,11 @@ void MainWindow::on_save() using pv::dialogs::StoreProgress; SigSession *_session = _control->GetSession(); - _session->set_saving(true); - QString session_file; - QDir dir; - #if QT_VERSION >= 0x050400 - QString path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); - #else - QString path = QStandardPaths::writableLocation(QStandardPaths::DataLocation); - #endif - if(dir.mkpath(path)) { - dir.cd(path); - - session_file = dir.absolutePath() + "/DSView-session-XXXXXX"; - on_store_session(session_file); - } StoreProgress *dlg = new StoreProgress(_session, this); connect(dlg, SIGNAL(save_done()), this, SLOT(device_detach_post())); - dlg->save_run(session_file); + dlg->save_run(this); } void MainWindow::on_export() @@ -1139,21 +1125,9 @@ bool MainWindow::load_session_json(QJsonDocument json, bool file_dev, bool bDeco return true; } - -bool MainWindow::on_store_session(QString name) -{ - QFile sessionFile(name); - if (!sessionFile.open(QIODevice::WriteOnly | QIODevice::Text)) { - qDebug("Warning: Couldn't open session file to write!"); - return false; - } - QTextStream outStream(&sessionFile); - app::set_utf8(outStream); - - //outStream.setGenerateByteOrderMark(true); // UTF-8 without BOM - - AppConfig &app = AppConfig::Instance(); +bool MainWindow::gen_session_json(QJsonArray &array){ SigSession *_session = _control->GetSession(); + AppConfig &app = AppConfig::Instance(); GVariant *gvar_opts; GVariant *gvar; @@ -1168,6 +1142,7 @@ bool MainWindow::on_store_session(QString name) if ((sr_config_list(sdi->driver, sdi, NULL, SR_CONF_DEVICE_SESSIONS, &gvar_opts) != SR_OK)) return false; /* Driver supports no device instance sessions. */ + const int *const options = (const int32_t *)g_variant_get_fixed_array( gvar_opts, &num_opts, sizeof(int32_t)); for (unsigned int i = 0; i < num_opts; i++) { @@ -1231,23 +1206,52 @@ bool MainWindow::on_store_session(QString name) if (_session->get_device()->dev_inst()->mode == LOGIC) { sessionVar["trigger"] = _trigger_widget->get_session(); } - - + StoreSession ss(_session); - sessionVar["decoder"] = ss.json_decoders(); - + QJsonArray decodeJson; + ss.json_decoders(decodeJson); + sessionVar["decoder"] = decodeJson; if (_session->get_device()->dev_inst()->mode == DSO) { sessionVar["measure"] = _view->get_viewstatus()->get_session(); + } + + array.push_back(sessionVar); + return true; +} + +bool MainWindow::on_store_session(QString name) +{ + QFile sessionFile(name); + if (!sessionFile.open(QIODevice::WriteOnly | QIODevice::Text)) { + qDebug("Warning: Couldn't open session file to write!"); + return false; } - QJsonDocument sessionDoc(sessionVar); + QTextStream outStream(&sessionFile); + app::set_utf8(outStream); + + QJsonArray jsonArray; + if (!gen_session_json(jsonArray)) + return false; + QJsonDocument sessionDoc(jsonArray); //sessionFile.write(QString::fromUtf8(sessionDoc.toJson())); outStream << QString::fromUtf8(sessionDoc.toJson()); sessionFile.close(); return true; } +bool MainWindow::genSessionData(std::string &str) +{ + QJsonArray jsonArray; + if (!gen_session_json(jsonArray)) + return false; + QJsonDocument sessionDoc(jsonArray); + QString data = QString::fromUtf8(sessionDoc.toJson()); + str.append(data.toLatin1().data()); + return true; +} + void MainWindow::restore_dock() { // default dockwidget size diff --git a/DSView/pv/mainwindow.h b/DSView/pv/mainwindow.h index 6e284bb8..047024ad 100755 --- a/DSView/pv/mainwindow.h +++ b/DSView/pv/mainwindow.h @@ -73,7 +73,7 @@ using namespace pv::device; //The mainwindow,referenced by MainFrame //TODO: create graph view,toolbar,and show device list -class MainWindow : public QMainWindow, public ISessionCallback, public IMainForm +class MainWindow : public QMainWindow, public ISessionCallback, public IMainForm, ISessionDataGetter { Q_OBJECT @@ -146,6 +146,10 @@ public: public: void session_save(); + //ISessionDataGetter +private: + bool genSessionData(std::string &str); + //ISessionCallback private: void show_error(QString error); @@ -173,6 +177,9 @@ private: void receive_header(); void data_received(); + //------private + bool gen_session_json(QJsonArray &array); + private: AppControl *_control; bool _hot_detach; diff --git a/DSView/pv/sigsession.cpp b/DSView/pv/sigsession.cpp index 2816eddb..0806c8ba 100755 --- a/DSView/pv/sigsession.cpp +++ b/DSView/pv/sigsession.cpp @@ -418,6 +418,8 @@ void SigSession::start_capture(bool instant) } assert(_dev_inst->dev_inst()); + qDebug()<<"start capture, device title:"<<_dev_inst->format_device_title(); + if (!_dev_inst->is_usable()) { _error = Hw_err; _callback->session_error(); @@ -431,7 +433,6 @@ void SigSession::start_capture(bool instant) // reset measure of dso signal for(auto &s : _signals) { - assert(s); view::DsoSignal *dsoSig = NULL; if ((dsoSig = dynamic_cast(s))) dsoSig->set_mValid(false); @@ -465,6 +466,10 @@ void SigSession::start_capture(bool instant) if (_sampling_thread.joinable()){ _sampling_thread.join(); } + + if (sr_check_session_start_before() != 0){ + assert(false); + } _sampling_thread = std::thread(&SigSession::sample_thread_proc, this, _dev_inst); } @@ -483,6 +488,7 @@ void SigSession::sample_thread_proc(DevInst *dev_inst) receive_data(0); set_capture_state(Running); + //session loop dev_inst->run(); set_capture_state(Stopped); diff --git a/DSView/pv/storesession.cpp b/DSView/pv/storesession.cpp index b65b36ed..33a4b829 100755 --- a/DSView/pv/storesession.cpp +++ b/DSView/pv/storesession.cpp @@ -49,10 +49,11 @@ #include #include #include - + #include #include "config/appconfig.h" #include "dsvdef.h" + namespace pv { @@ -64,6 +65,7 @@ StoreSession::StoreSession(SigSession *session) : _has_error(false), _canceled(false) { + _sessionDataGetter = NULL; } StoreSession::~StoreSession() @@ -117,12 +119,8 @@ QList StoreSession::getSuportedExportFormats(){ } bool StoreSession::save_start() -{ - if (_sessionFile == "") - { - _error = tr("No set session file name."); - return false; - } +{ + assert(_sessionDataGetter); std::set type_set; for(auto &sig : _session->get_signals()) { @@ -151,11 +149,7 @@ bool StoreSession::save_start() if (snapshot->empty()) { _error = tr("No data to save."); return false; - } - - QString meta_file = meta_gen(snapshot); - - QString decoders_file = decoders_gen(); + } /* if (meta_file == NULL) { @@ -174,13 +168,37 @@ bool StoreSession::save_start() } */ - //make zip file - if (meta_file != "" && m_zipDoc.CreateNew(_file_name.toUtf8().data(), false)) - { - if (!m_zipDoc.AddFromFile(meta_file.toUtf8().data(), "header") - || !m_zipDoc.AddFromFile(decoders_file.toUtf8().data(), "decoders") - || !m_zipDoc.AddFromFile(_sessionFile.toUtf8().data(), "session")) - { + std::string meta_data; + std::string decoder_data; + std::string session_data; + + meta_gen(snapshot, meta_data); + decoders_gen(decoder_data); + _sessionDataGetter->genSessionData(session_data); + + if (meta_data.empty()) { + _error = tr("Generate temp file data failed."); + QFile::remove(_file_name); + return false; + } + if (decoder_data.empty()){ + _error = tr("Generate decoder file data failed."); + QFile::remove(_file_name); + return false; + } + if (session_data.empty()){ + _error = tr("Generate session file data failed."); + QFile::remove(_file_name); + return false; + } + + std::string _filename = getFileName(_file_name); + if (m_zipDoc.CreateNew(_filename.c_str(), false)) + { + if ( !m_zipDoc.AddFromBuffer("header", meta_data.c_str(), meta_data.size()) + || !m_zipDoc.AddFromBuffer("decoders", decoder_data.c_str(), decoder_data.size()) + || !m_zipDoc.AddFromBuffer("session", session_data.c_str(), session_data.size()) + ){ _has_error = true; _error = m_zipDoc.GetError(); } @@ -191,9 +209,11 @@ bool StoreSession::save_start() return !_has_error; } } + else{ + _error = tr("Generate zip file failed."); + } QFile::remove(_file_name); - //_error.clear(); return false; } @@ -339,55 +359,35 @@ void StoreSession::save_proc(data::Snapshot *snapshot) } } -QString StoreSession::meta_gen(data::Snapshot *snapshot) +bool StoreSession::meta_gen(data::Snapshot *snapshot, std::string &str) { GSList *l; - GVariant *gvar; - FILE *meta = NULL; + GVariant *gvar; struct sr_channel *probe; int probecnt; char *s; struct sr_status status; - QString metafile; + const sr_dev_inst *sdi = NULL; + char meta[300] = {0}; + + sdi = _session->get_device()->dev_inst(); + + sprintf(meta, "%s", "[version]\n"); str += meta; + sprintf(meta, "version = %d\n", File_Version); str += meta; + sprintf(meta, "%s", "[header]\n"); str += meta; - /* init "metadata" */ - QDir dir; - #if QT_VERSION >= 0x050400 - QString path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); - #else - QString path = QStandardPaths::writableLocation(QStandardPaths::DataLocation); - #endif - if(dir.mkpath(path)) { - dir.cd(path); - metafile = dir.absolutePath() + "/DSView-meta-XXXXXX"; - } else { - return NULL; - } - - const sr_dev_inst *sdi = _session->get_device()->dev_inst(); - meta = fopen(metafile.toUtf8().data(), "wb"); - if (meta == NULL) { - qDebug() << "Failed to create temp meta file."; - return NULL; - } - - fprintf(meta, "[version]\n"); - fprintf(meta, "version = %d\n", File_Version); - - /* metadata */ - fprintf(meta, "[header]\n"); if (sdi->driver) { - fprintf(meta, "driver = %s\n", sdi->driver->name); - fprintf(meta, "device mode = %d\n", sdi->mode); + sprintf(meta, "driver = %s\n", sdi->driver->name); str += meta; + sprintf(meta, "device mode = %d\n", sdi->mode); str += meta; } /* metadata */ - fprintf(meta, "capturefile = data\n"); - fprintf(meta, "total samples = %" PRIu64 "\n", snapshot->get_sample_count()); + sprintf(meta, "capturefile = data\n"); str += meta; + sprintf(meta, "total samples = %" PRIu64 "\n", snapshot->get_sample_count()); str += meta; if (sdi->mode != LOGIC) { - fprintf(meta, "total probes = %d\n", snapshot->get_channel_num()); - fprintf(meta, "total blocks = %d\n", snapshot->get_block_num()); + sprintf(meta, "total probes = %d\n", snapshot->get_channel_num()); str += meta; + sprintf(meta, "total blocks = %d\n", snapshot->get_block_num()); str += meta; } data::LogicSnapshot *logic_snapshot = NULL; @@ -398,140 +398,198 @@ QString StoreSession::meta_gen(data::Snapshot *snapshot) if (probe->enabled && logic_snapshot->has_data(probe->index)) to_save_probes++; } - fprintf(meta, "total probes = %d\n", to_save_probes); - fprintf(meta, "total blocks = %d\n", logic_snapshot->get_block_num()); + sprintf(meta, "total probes = %d\n", to_save_probes); str += meta; + sprintf(meta, "total blocks = %d\n", logic_snapshot->get_block_num()); str += meta; } s = sr_samplerate_string(_session->cur_snap_samplerate()); - fprintf(meta, "samplerate = %s\n", s); + + sprintf(meta, "samplerate = %s\n", s); str += meta; if (sdi->mode == DSO) { gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_TIMEBASE); if (gvar != NULL) { uint64_t tmp_u64 = g_variant_get_uint64(gvar); - fprintf(meta, "hDiv = %" PRIu64 "\n", tmp_u64); + sprintf(meta, "hDiv = %" PRIu64 "\n", tmp_u64); str += meta; g_variant_unref(gvar); } gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_MAX_TIMEBASE); if (gvar != NULL) { uint64_t tmp_u64 = g_variant_get_uint64(gvar); - fprintf(meta, "hDiv max = %" PRIu64 "\n", tmp_u64); + sprintf(meta, "hDiv max = %" PRIu64 "\n", tmp_u64); str += meta; g_variant_unref(gvar); } gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_MIN_TIMEBASE); if (gvar != NULL) { uint64_t tmp_u64 = g_variant_get_uint64(gvar); - fprintf(meta, "hDiv min = %" PRIu64 "\n", tmp_u64); + sprintf(meta, "hDiv min = %" PRIu64 "\n", tmp_u64); str += meta; g_variant_unref(gvar); } gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_UNIT_BITS); if (gvar != NULL) { uint8_t tmp_u8 = g_variant_get_byte(gvar); - fprintf(meta, "bits = %d\n", tmp_u8); + sprintf(meta, "bits = %d\n", tmp_u8); str += meta; g_variant_unref(gvar); } gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_REF_MIN); if (gvar != NULL) { uint32_t tmp_u32 = g_variant_get_uint32(gvar); - fprintf(meta, "ref min = %d\n", tmp_u32); + sprintf(meta, "ref min = %d\n", tmp_u32); str += meta; g_variant_unref(gvar); } gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_REF_MAX); if (gvar != NULL) { uint32_t tmp_u32 = g_variant_get_uint32(gvar); - fprintf(meta, "ref max = %d\n", tmp_u32); + sprintf(meta, "ref max = %d\n", tmp_u32); str += meta; g_variant_unref(gvar); } } else if (sdi->mode == LOGIC) { - fprintf(meta, "trigger time = %lld\n", _session->get_session_time().toMSecsSinceEpoch()); + sprintf(meta, "trigger time = %lld\n", _session->get_session_time().toMSecsSinceEpoch()); str += meta; } else if (sdi->mode == ANALOG) { data::AnalogSnapshot *analog_snapshot = NULL; if ((analog_snapshot = dynamic_cast(snapshot))) { uint8_t tmp_u8 = analog_snapshot->get_unit_bytes(); - fprintf(meta, "bits = %d\n", tmp_u8*8); + sprintf(meta, "bits = %d\n", tmp_u8*8); str += meta; } gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_REF_MIN); if (gvar != NULL) { uint32_t tmp_u32 = g_variant_get_uint32(gvar); - fprintf(meta, "ref min = %d\n", tmp_u32); + sprintf(meta, "ref min = %d\n", tmp_u32); str += meta; g_variant_unref(gvar); } gvar = _session->get_device()->get_config(NULL, NULL, SR_CONF_REF_MAX); if (gvar != NULL) { uint32_t tmp_u32 = g_variant_get_uint32(gvar); - fprintf(meta, "ref max = %d\n", tmp_u32); + sprintf(meta, "ref max = %d\n", tmp_u32); str += meta; g_variant_unref(gvar); } } - fprintf(meta, "trigger pos = %" PRIu64 "\n", _session->get_trigger_pos()); + sprintf(meta, "trigger pos = %" PRIu64 "\n", _session->get_trigger_pos()); str += meta; + + probecnt = 0; - probecnt = 0; for (l = sdi->channels; l; l = l->next) { + probe = (struct sr_channel *)l->data; - if (snapshot->has_data(probe->index)) { - if (sdi->mode == LOGIC && !probe->enabled) - continue; + if (!snapshot->has_data(probe->index)) + continue; + if (sdi->mode == LOGIC && !probe->enabled) + continue; - if (probe->name) - fprintf(meta, "probe%d = %s\n", (sdi->mode == LOGIC) ? probe->index : probecnt, probe->name); - if (probe->trigger) - fprintf(meta, " trigger%d = %s\n", probecnt, probe->trigger); - if (sdi->mode == DSO) { - fprintf(meta, " enable%d = %d\n", probecnt, probe->enabled); - fprintf(meta, " coupling%d = %d\n", probecnt, probe->coupling); - fprintf(meta, " vDiv%d = %" PRIu64 "\n", probecnt, probe->vdiv); - fprintf(meta, " vFactor%d = %" PRIu64 "\n", probecnt, probe->vfactor); - fprintf(meta, " vOffset%d = %d\n", probecnt, probe->hw_offset); - fprintf(meta, " vTrig%d = %d\n", probecnt, probe->trig_value); - if (sr_status_get(sdi, &status, false) == SR_OK) { - if (probe->index == 0) { - fprintf(meta, " period%d = %" PRIu32 "\n", probecnt, status.ch0_cyc_tlen); - fprintf(meta, " pcnt%d = %" PRIu32 "\n", probecnt, status.ch0_cyc_cnt); - fprintf(meta, " max%d = %d\n", probecnt, status.ch0_max); - fprintf(meta, " min%d = %d\n", probecnt, status.ch0_min); - fprintf(meta, " plen%d = %" PRIu32 "\n", probecnt, status.ch0_cyc_plen); - fprintf(meta, " llen%d = %" PRIu32 "\n", probecnt, status.ch0_cyc_llen); - fprintf(meta, " level%d = %d\n", probecnt, status.ch0_level_valid); - fprintf(meta, " plevel%d = %d\n", probecnt, status.ch0_plevel); - fprintf(meta, " low%d = %" PRIu32 "\n", probecnt, status.ch0_low_level); - fprintf(meta, " high%d = %" PRIu32 "\n", probecnt, status.ch0_high_level); - fprintf(meta, " rlen%d = %" PRIu32 "\n", probecnt, status.ch0_cyc_rlen); - fprintf(meta, " flen%d = %" PRIu32 "\n", probecnt, status.ch0_cyc_flen); - fprintf(meta, " rms%d = %" PRIu64 "\n", probecnt, status.ch0_acc_square); - fprintf(meta, " mean%d = %" PRIu32 "\n", probecnt, status.ch0_acc_mean); - } else { - fprintf(meta, " period%d = %" PRIu32 "\n", probecnt, status.ch1_cyc_tlen); - fprintf(meta, " pcnt%d = %" PRIu32 "\n", probecnt, status.ch1_cyc_cnt); - fprintf(meta, " max%d = %d\n", probecnt, status.ch1_max); - fprintf(meta, " min%d = %d\n", probecnt, status.ch1_min); - fprintf(meta, " plen%d = %" PRIu32 "\n", probecnt, status.ch1_cyc_plen); - fprintf(meta, " llen%d = %" PRIu32 "\n", probecnt, status.ch1_cyc_llen); - fprintf(meta, " level%d = %d\n", probecnt, status.ch1_level_valid); - fprintf(meta, " plevel%d = %d\n", probecnt, status.ch1_plevel); - fprintf(meta, " low%d = %" PRIu32 "\n", probecnt, status.ch1_low_level); - fprintf(meta, " high%d = %" PRIu32 "\n", probecnt, status.ch1_high_level); - fprintf(meta, " rlen%d = %" PRIu32 "\n", probecnt, status.ch1_cyc_rlen); - fprintf(meta, " flen%d = %" PRIu32 "\n", probecnt, status.ch1_cyc_flen); - fprintf(meta, " rms%d = %" PRIu64 "\n", probecnt, status.ch1_acc_square); - fprintf(meta, " mean%d = %" PRIu32 "\n", probecnt, status.ch1_acc_mean); - } - } - } else if (sdi->mode == ANALOG) { - fprintf(meta, " enable%d = %d\n", probecnt, probe->enabled); - fprintf(meta, " coupling%d = %d\n", probecnt, probe->coupling); - fprintf(meta, " vDiv%d = %" PRIu64 "\n", probecnt, probe->vdiv); - fprintf(meta, " vOffset%d = %d\n", probecnt, probe->hw_offset); - fprintf(meta, " mapUnit%d = %s\n", probecnt, probe->map_unit); - fprintf(meta, " mapMax%d = %lf\n", probecnt, probe->map_max); - fprintf(meta, " mapMin%d = %lf\n", probecnt, probe->map_min); - } - probecnt++; + if (probe->name) + { + int sigdex = (sdi->mode == LOGIC) ? probe->index : probecnt; + sprintf(meta, "probe%d = %s\n", sigdex, probe->name); + str += meta; } - } - fclose(meta); + if (probe->trigger){ + sprintf(meta, " trigger%d = %s\n", probecnt, probe->trigger); + str += meta; + } - return metafile; + if (sdi->mode == DSO) + { + sprintf(meta, " enable%d = %d\n", probecnt, probe->enabled); + str += meta; + sprintf(meta, " coupling%d = %d\n", probecnt, probe->coupling); + str += meta; + sprintf(meta, " vDiv%d = %" PRIu64 "\n", probecnt, probe->vdiv); + str += meta; + sprintf(meta, " vFactor%d = %" PRIu64 "\n", probecnt, probe->vfactor); + str += meta; + sprintf(meta, " vOffset%d = %d\n", probecnt, probe->hw_offset); + str += meta; + sprintf(meta, " vTrig%d = %d\n", probecnt, probe->trig_value); + str += meta; + + if (sr_status_get(sdi, &status, false) == SR_OK) + { + if (probe->index == 0) + { + sprintf(meta, " period%d = %" PRIu32 "\n", probecnt, status.ch0_cyc_tlen); + str += meta; + sprintf(meta, " pcnt%d = %" PRIu32 "\n", probecnt, status.ch0_cyc_cnt); + str += meta; + sprintf(meta, " max%d = %d\n", probecnt, status.ch0_max); + str += meta; + sprintf(meta, " min%d = %d\n", probecnt, status.ch0_min); + str += meta; + sprintf(meta, " plen%d = %" PRIu32 "\n", probecnt, status.ch0_cyc_plen); + str += meta; + sprintf(meta, " llen%d = %" PRIu32 "\n", probecnt, status.ch0_cyc_llen); + str += meta; + sprintf(meta, " level%d = %d\n", probecnt, status.ch0_level_valid); + str += meta; + sprintf(meta, " plevel%d = %d\n", probecnt, status.ch0_plevel); + str += meta; + sprintf(meta, " low%d = %" PRIu32 "\n", probecnt, status.ch0_low_level); + str += meta; + sprintf(meta, " high%d = %" PRIu32 "\n", probecnt, status.ch0_high_level); + str += meta; + sprintf(meta, " rlen%d = %" PRIu32 "\n", probecnt, status.ch0_cyc_rlen); + str += meta; + sprintf(meta, " flen%d = %" PRIu32 "\n", probecnt, status.ch0_cyc_flen); + str += meta; + sprintf(meta, " rms%d = %" PRIu64 "\n", probecnt, status.ch0_acc_square); + str += meta; + sprintf(meta, " mean%d = %" PRIu32 "\n", probecnt, status.ch0_acc_mean); + str += meta; + } + else + { + sprintf(meta, " period%d = %" PRIu32 "\n", probecnt, status.ch1_cyc_tlen); + str += meta; + sprintf(meta, " pcnt%d = %" PRIu32 "\n", probecnt, status.ch1_cyc_cnt); + str += meta; + sprintf(meta, " max%d = %d\n", probecnt, status.ch1_max); + str += meta; + sprintf(meta, " min%d = %d\n", probecnt, status.ch1_min); + str += meta; + sprintf(meta, " plen%d = %" PRIu32 "\n", probecnt, status.ch1_cyc_plen); + str += meta; + sprintf(meta, " llen%d = %" PRIu32 "\n", probecnt, status.ch1_cyc_llen); + str += meta; + sprintf(meta, " level%d = %d\n", probecnt, status.ch1_level_valid); + str += meta; + sprintf(meta, " plevel%d = %d\n", probecnt, status.ch1_plevel); + str += meta; + sprintf(meta, " low%d = %" PRIu32 "\n", probecnt, status.ch1_low_level); + str += meta; + sprintf(meta, " high%d = %" PRIu32 "\n", probecnt, status.ch1_high_level); + str += meta; + sprintf(meta, " rlen%d = %" PRIu32 "\n", probecnt, status.ch1_cyc_rlen); + str += meta; + sprintf(meta, " flen%d = %" PRIu32 "\n", probecnt, status.ch1_cyc_flen); + str += meta; + sprintf(meta, " rms%d = %" PRIu64 "\n", probecnt, status.ch1_acc_square); + str += meta; + sprintf(meta, " mean%d = %" PRIu32 "\n", probecnt, status.ch1_acc_mean); + str += meta; + } + } + } + else if (sdi->mode == ANALOG) + { + sprintf(meta, " enable%d = %d\n", probecnt, probe->enabled); + str += meta; + sprintf(meta, " coupling%d = %d\n", probecnt, probe->coupling); + str += meta; + sprintf(meta, " vDiv%d = %" PRIu64 "\n", probecnt, probe->vdiv); + str += meta; + sprintf(meta, " vOffset%d = %d\n", probecnt, probe->hw_offset); + str += meta; + sprintf(meta, " mapUnit%d = %s\n", probecnt, probe->map_unit); + str += meta; + sprintf(meta, " mapMax%d = %lf\n", probecnt, probe->map_max); + str += meta; + sprintf(meta, " mapMin%d = %lf\n", probecnt, probe->map_min); + str += meta; + } + probecnt++; + } + + return true; } //export as csv file @@ -824,43 +882,19 @@ void StoreSession::export_proc(data::Snapshot *snapshot) } -QString StoreSession::decoders_gen() -{ - QDir dir; - #if QT_VERSION >= 0x050400 - QString path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); - #else - QString path = QStandardPaths::writableLocation(QStandardPaths::DataLocation); - #endif - if(dir.mkpath(path)) { - dir.cd(path); - - QString file_name = dir.absolutePath() + "/DSView-decoders-XXXXXX"; - QFile sessionFile(file_name); - if (!sessionFile.open(QIODevice::WriteOnly | QIODevice::Text)) { - qDebug("Warning: Couldn't open session file to write!"); - return NULL; - } - QTextStream outStream(&sessionFile); - app::set_utf8(outStream); - //outStream.setGenerateByteOrderMark(true); // UTF-8 without BOM - - QJsonArray dec_array = json_decoders(); - QJsonDocument sessionDoc(dec_array); - outStream << QString::fromUtf8(sessionDoc.toJson()); - sessionFile.close(); - - return file_name; - } else { - return NULL; - } - +bool StoreSession::decoders_gen(std::string &str) +{ + QJsonArray dec_array; + if (!json_decoders(dec_array)) + return false; + QJsonDocument sessionDoc(dec_array); + QString data = QString::fromUtf8(sessionDoc.toJson()); + str.append(data.toLatin1().data()); + return true; } -QJsonArray StoreSession::json_decoders() -{ - QJsonArray dec_array; - +bool StoreSession::json_decoders(QJsonArray &array) +{ for(auto &t : _session->get_decode_signals()) { QJsonObject dec_obj; QJsonArray stack_array; @@ -913,7 +947,6 @@ QJsonArray StoreSession::json_decoders() } } - if (have_probes) { dec_obj["id"] = QJsonValue::fromVariant(d->id); dec_obj["channel"] = ch_array; @@ -936,9 +969,10 @@ QJsonArray StoreSession::json_decoders() } dec_obj["show"] = show_obj; - dec_array.push_back(dec_obj); + array.push_back(dec_obj); } - return dec_array; + + return true; } bool StoreSession::load_decoders(dock::ProtocolDock *widget, QJsonArray dec_array) @@ -1300,4 +1334,14 @@ void StoreSession::MakeChunkName(char *chunk_name, int chunk_num, int index, int } } +std::string StoreSession::getFileName(QString fileName) +{ +#if defined(_WIN32) + QTextCodec *code = QTextCodec::codecForName("GB2312"); + return code->fromUnicode(fileName).data(); +#else + return _file_name.toUtf8().toStdString(); +#endif +} + } // pv diff --git a/DSView/pv/storesession.h b/DSView/pv/storesession.h index 99db9f12..882653e9 100755 --- a/DSView/pv/storesession.h +++ b/DSView/pv/storesession.h @@ -24,12 +24,12 @@ #include #include -#include - +#include #include - #include +#include "interface/icallbacks.h" + #include "ZipMaker.h" namespace pv { @@ -72,14 +72,13 @@ public: private: void save_proc(pv::data::Snapshot *snapshot); - QString meta_gen(data::Snapshot *snapshot); - void export_proc(pv::data::Snapshot *snapshot); - - QString decoders_gen(); + bool meta_gen(data::Snapshot *snapshot, std::string &str); + void export_proc(pv::data::Snapshot *snapshot); + bool decoders_gen(std::string &str); public: - QJsonArray json_decoders(); + bool json_decoders(QJsonArray &array); bool load_decoders(dock::ProtocolDock *widget, QJsonArray dec_array); QString MakeSaveFile(bool bDlg); QString MakeExportFile(bool bDlg); @@ -94,12 +93,13 @@ private: QList getSuportedExportFormats(); double get_integer(GVariant * var); void MakeChunkName(char *chunk_name, int chunk_num, int index, int type, int version); + std:: string getFileName(QString fileName); signals: void progress_updated(); public: - QString _sessionFile; + ISessionDataGetter *_sessionDataGetter; private: QString _file_name; diff --git a/libsigrok4DSL/dsdevice.c b/libsigrok4DSL/dsdevice.c index bf0c6ce9..213a91db 100755 --- a/libsigrok4DSL/dsdevice.c +++ b/libsigrok4DSL/dsdevice.c @@ -360,7 +360,7 @@ SR_API int sr_dev_open(struct sr_dev_inst *sdi) SR_API int sr_dev_close(struct sr_dev_inst *sdi) { int ret; - + if (!sdi || !sdi->driver || !sdi->driver->dev_close) return SR_ERR; diff --git a/libsigrok4DSL/proto.h b/libsigrok4DSL/proto.h index 0ebd0d26..88aaec0e 100755 --- a/libsigrok4DSL/proto.h +++ b/libsigrok4DSL/proto.h @@ -117,6 +117,9 @@ SR_API int sr_session_source_remove(int fd); SR_API int sr_session_source_remove_pollfd(GPollFD *pollfd); SR_API int sr_session_source_remove_channel(GIOChannel *channel); +//0:ok, 1:error +SR_API int sr_check_session_start_before(); + /*--- input/input.c ---------------------------------------------------------*/ SR_API struct sr_input_format **sr_input_list(void); diff --git a/libsigrok4DSL/session.c b/libsigrok4DSL/session.c index 74ca9996..24786c07 100755 --- a/libsigrok4DSL/session.c +++ b/libsigrok4DSL/session.c @@ -383,6 +383,17 @@ SR_API int sr_session_start(void) return ret; } +/* +* check session if be created +*/ +int sr_check_session_start_before(){ + + if (!session || !session->devs) { + return 1; + } + return 0; +} + /** * Run the session. * diff --git a/qtpro/DSView.pro b/qtpro/DSView.pro index 57b0ae30..c3540636 100644 --- a/qtpro/DSView.pro +++ b/qtpro/DSView.pro @@ -18,6 +18,7 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets #QMAKE_CFLAGS_ISYSTEM = -I + TARGET = DSView TEMPLATE = app diff --git a/qtpro/DSView.pro.user b/qtpro/DSView.pro.user index 1c801f1b..936f882c 100644 --- a/qtpro/DSView.pro.user +++ b/qtpro/DSView.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId From 092827434ec4aba970ed885287ac12edbe8939de Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Fri, 3 Dec 2021 18:50:31 +0800 Subject: [PATCH 40/60] fix usb2.0 device alaim interface error bug --- DSView/main.cpp | 4 ++ libsigrok4DSL/hardware/DSL/dsl.c | 21 ++++++-- libsigrok4DSL/hardware/DSL/dslogic.c | 6 ++- libsigrok4DSL/hwdriver.c | 78 ++++++++++++++++++++++++++++ libsigrok4DSL/proto.h | 18 +++---- qtpro/DSView.pro.user | 2 +- 6 files changed, 114 insertions(+), 15 deletions(-) diff --git a/DSView/main.cpp b/DSView/main.cpp index 8485be26..dac39c93 100755 --- a/DSView/main.cpp +++ b/DSView/main.cpp @@ -38,6 +38,8 @@ #include "config.h" #include "pv/appcontrol.h" +//#include + void usage() { fprintf(stdout, @@ -54,6 +56,8 @@ void usage() int main(int argc, char *argv[]) { + // sr_test_usb_api();return 0; + int ret = 0; const char *open_file = NULL; diff --git a/libsigrok4DSL/hardware/DSL/dsl.c b/libsigrok4DSL/hardware/DSL/dsl.c index 01e2e01c..70c5da81 100755 --- a/libsigrok4DSL/hardware/DSL/dsl.c +++ b/libsigrok4DSL/hardware/DSL/dsl.c @@ -1779,6 +1779,7 @@ SR_PRIV int dsl_dev_open(struct sr_dev_driver *di, struct sr_dev_inst *sdi, gboo int ret; uint8_t hw_info; struct ctl_rd_cmd rd_cmd; + int fdError = 0; devc = sdi->priv; usb = sdi->conn; @@ -1799,7 +1800,7 @@ SR_PRIV int dsl_dev_open(struct sr_dev_driver *di, struct sr_dev_inst *sdi, gboo sr_err("%s: Unable to open device.", __func__); return SR_ERR; } - + ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE); if (ret != 0) { switch(ret) { @@ -1810,13 +1811,27 @@ SR_PRIV int dsl_dev_open(struct sr_dev_driver *di, struct sr_dev_inst *sdi, gboo case LIBUSB_ERROR_NO_DEVICE: sr_err("%s: Device has been disconnected.", __func__); break; + case LIBUSB_ERROR_NOT_FOUND: + { + sr_err("%s: Unable to claim interface, try again: LIBUSB_ERROR_NOT_FOUND.", __func__); + ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE); + fdError = 1; + } + break; default: - sr_err("%s: Unable to claim interface: %s.", + sr_err("%s: Unable to claim interface, try again: %s.", __func__, libusb_error_name(ret)); break; } - return SR_ERR; + if (ret != 0 && fdError == 1){ + sr_err("%s: Unable to claim interface, the second time: %s.", + __func__, libusb_error_name(ret)); + } + + if (ret != 0){ + return SR_ERR; + } } rd_cmd.header.dest = DSL_CTL_HW_STATUS; diff --git a/libsigrok4DSL/hardware/DSL/dslogic.c b/libsigrok4DSL/hardware/DSL/dslogic.c index 76419965..345f9db9 100755 --- a/libsigrok4DSL/hardware/DSL/dslogic.c +++ b/libsigrok4DSL/hardware/DSL/dslogic.c @@ -287,7 +287,9 @@ static GSList *scan(GSList *options) /* Find all DSLogic compatible devices and upload firmware to them. */ devices = NULL; - libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist); + int usbnum = libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist); + int stdnum = 0; + for (i = 0; devlist[i]; i++) { if (conn) { usb = NULL; @@ -314,6 +316,8 @@ static GSList *scan(GSList *options) (usb_speed != LIBUSB_SPEED_SUPER)) continue; + stdnum++; + prof = NULL; for (j = 0; supported_DSLogic[j].vid; j++) { if (des.idVendor == supported_DSLogic[j].vid && diff --git a/libsigrok4DSL/hwdriver.c b/libsigrok4DSL/hwdriver.c index 6af67d91..5be41d3d 100755 --- a/libsigrok4DSL/hwdriver.c +++ b/libsigrok4DSL/hwdriver.c @@ -27,6 +27,8 @@ #include #include "config.h" /* Needed for HAVE_LIBUSB_1_0 and others. */ +#include "hardware/DSL/dsl.h" + /* Message logging helpers with subsystem-specific prefix string. */ #define LOG_PREFIX "hwdriver: " #define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args) @@ -475,3 +477,79 @@ SR_PRIV int sr_source_add(int fd, int events, int timeout, } /** @} */ + +/* +test usb device api +*/ +SR_API void sr_test_usb_api() +{ + libusb_context *ctx; + struct libusb_device_descriptor des; + int usb_speed; + int ret; + int i; + int num_devs; + libusb_device **devlist; + int stdnum = 0; + int j; + int bfind = 0; + int dlsnum = 0; + struct libusb_device_handle *devhandle; + + printf("\n"); + + ret = libusb_init(&ctx); + if (ret) { + printf("unable to initialize libusb: %i\n", ret); + return; + } + + num_devs = libusb_get_device_list(ctx, &devlist); + printf("usb dev num:%d\n", num_devs); + + for (i=0; i - + EnvironmentId From 65f5946fe3b58eee5f94fa5a16589955e2b1b3aa Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Mon, 6 Dec 2021 15:57:04 +0800 Subject: [PATCH 41/60] fix dock panel can not restore bug --- DSView/pv/config/appconfig.cpp | 32 +++++++++++++++-- DSView/pv/config/appconfig.h | 13 ++++++- DSView/pv/mainwindow.cpp | 5 ++- DSView/pv/toolbars/trigbar.cpp | 66 ++++++++++++++++++++++++++++++++-- DSView/pv/toolbars/trigbar.h | 40 ++++++++++++--------- qtpro/DSView.pro.user | 2 +- 6 files changed, 134 insertions(+), 24 deletions(-) diff --git a/DSView/pv/config/appconfig.cpp b/DSView/pv/config/appconfig.cpp index 75fae622..f94c7304 100644 --- a/DSView/pv/config/appconfig.cpp +++ b/DSView/pv/config/appconfig.cpp @@ -111,13 +111,31 @@ void _saveApp(AppOptions &o, QSettings &st){ setFiled("warnofMultiTrig", st, o.warnofMultiTrig); setFiled("originalData", st, o.originalData); - QString fmt = FormatArrayToString(o.m_protocolFormats); setFiled("protocalFormats", st, fmt); st.endGroup(); } //-----frame + +void _loadDockOptions(DockOptions &o, QSettings &st, const char *group){ + st.beginGroup(group); + getFiled("decodeDoc", st, o.decodeDoc, false); + getFiled("triggerDoc", st, o.triggerDoc, false); + getFiled("measureDoc", st, o.measureDoc, false); + getFiled("searchDoc", st, o.searchDoc, false); + st.endGroup(); +} + +void _saveDockOptions(DockOptions &o, QSettings &st, const char *group){ + st.beginGroup(group); + setFiled("decodeDoc", st, o.decodeDoc); + setFiled("triggerDoc", st, o.triggerDoc); + setFiled("measureDoc", st, o.measureDoc); + setFiled("searchDoc", st, o.searchDoc); + st.endGroup(); +} + void _loadFrame(FrameOptions &o, QSettings &st){ st.beginGroup("MainFrame"); getFiled("style", st, o.style, "dark"); @@ -127,6 +145,11 @@ void _loadFrame(FrameOptions &o, QSettings &st){ getFiled("top", st, o.top, 0); getFiled("right", st, o.right, 0); getFiled("bottom", st, o.bottom, 0); + + _loadDockOptions(o._logicDock, st, "LOGIC_DOCK"); + _loadDockOptions(o._analogDock, st, "ANALOG_DOCK"); + _loadDockOptions(o._dsoDock, st, "DSO_DOCK"); + o.windowState = st.value("windowState", QByteArray()).toByteArray(); st.endGroup(); @@ -149,8 +172,13 @@ void _saveFrame(FrameOptions &o, QSettings &st){ setFiled("left", st, o.left); setFiled("top", st, o.top); setFiled("right", st, o.right); - setFiled("bottom", st, o.bottom); + setFiled("bottom", st, o.bottom); st.setValue("windowState", o.windowState); + + _saveDockOptions(o._logicDock, st, "LOGIC_DOCK"); + _saveDockOptions(o._analogDock, st, "ANALOG_DOCK"); + _saveDockOptions(o._dsoDock, st, "DSO_DOCK"); + st.endGroup(); } diff --git a/DSView/pv/config/appconfig.h b/DSView/pv/config/appconfig.h index 250e1868..176180fd 100644 --- a/DSView/pv/config/appconfig.h +++ b/DSView/pv/config/appconfig.h @@ -58,6 +58,13 @@ struct AppOptions std::vector m_protocolFormats; }; + struct DockOptions{ + bool decodeDoc; + bool triggerDoc; + bool measureDoc; + bool searchDoc; +}; + struct FrameOptions { QString style; @@ -68,6 +75,10 @@ struct FrameOptions int bottom; bool isMax; QByteArray windowState; + + DockOptions _logicDock; + DockOptions _analogDock; + DockOptions _dsoDock; }; struct UserHistory @@ -103,5 +114,5 @@ public: public: AppOptions _appOptions; UserHistory _userHistory; - FrameOptions _frameOptions; + FrameOptions _frameOptions; }; diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index 70caa8f4..8437868f 100644 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -303,6 +303,7 @@ void MainWindow::setup_ui() //delay to update device list QTimer::singleShot(200, this, SLOT(update_device_list())); + } @@ -436,6 +437,8 @@ void MainWindow::update_device_list() "Please replug it into a USB 3.0 port."); } } + + _trig_bar->restore_status(); } @@ -1260,7 +1263,7 @@ void MainWindow::restore_dock() if (!st.isEmpty()){ try { - restoreState(st); + restoreState(st); } catch(...) { diff --git a/DSView/pv/toolbars/trigbar.cpp b/DSView/pv/toolbars/trigbar.cpp index 4666c88b..202eb572 100755 --- a/DSView/pv/toolbars/trigbar.cpp +++ b/DSView/pv/toolbars/trigbar.cpp @@ -43,7 +43,7 @@ const QString TrigBar::LIGHT_STYLE = "light"; TrigBar::TrigBar(SigSession *session, QWidget *parent) : QToolBar("Trig Bar", parent), _session(session), - _enable(true), + _trig_button(this), _protocol_button(this), _measure_button(this), @@ -51,6 +51,8 @@ TrigBar::TrigBar(SigSession *session, QWidget *parent) : _function_button(this), _setting_button(this) { + _enable = true; + setMovable(false); setContentsMargins(0,0,0,0); @@ -187,13 +189,21 @@ void TrigBar::reStyle() } void TrigBar::protocol_clicked() -{ +{ sig_protocol(_protocol_button.isChecked()); + + DockOptions *opt = getDockOptions(); + opt->decodeDoc = _protocol_button.isChecked(); + AppConfig::Instance().SaveFrame(); } void TrigBar::trigger_clicked() { sig_trigger(_trig_button.isChecked()); + + DockOptions *opt = getDockOptions(); + opt->triggerDoc = _trig_button.isChecked(); + AppConfig::Instance().SaveFrame(); } void TrigBar::update_trig_btn(bool checked) @@ -219,11 +229,19 @@ void TrigBar::update_search_btn(bool checked) void TrigBar::measure_clicked() { sig_measure(_measure_button.isChecked()); + + DockOptions *opt = getDockOptions(); + opt->measureDoc = _measure_button.isChecked(); + AppConfig::Instance().SaveFrame(); } void TrigBar::search_clicked() { sig_search(_search_button.isChecked()); + + DockOptions *opt = getDockOptions(); + opt->searchDoc = _search_button.isChecked(); + AppConfig::Instance().SaveFrame(); } void TrigBar::enable_toggle(bool enable) @@ -264,6 +282,7 @@ void TrigBar::close_all() void TrigBar::reload() { close_all(); + if (_session->get_device()->dev_inst()->mode == LOGIC) { _trig_action->setVisible(true); _protocol_action->setVisible(true); @@ -271,6 +290,7 @@ void TrigBar::reload() _search_action->setVisible(true); _function_action->setVisible(false); _action_lissajous->setVisible(false); + } else if (_session->get_device()->dev_inst()->mode == ANALOG) { _trig_action->setVisible(false); _protocol_action->setVisible(false); @@ -278,6 +298,7 @@ void TrigBar::reload() _search_action->setVisible(false); _function_action->setVisible(false); _action_lissajous->setVisible(false); + } else if (_session->get_device()->dev_inst()->mode == DSO) { _trig_action->setVisible(true); _protocol_action->setVisible(false); @@ -286,6 +307,7 @@ void TrigBar::reload() _function_action->setVisible(true); _action_lissajous->setVisible(true); } + enable_toggle(true); update(); } @@ -329,5 +351,45 @@ void TrigBar::on_actionLissajous_triggered() dlg.ShowDlg(this); } + +void TrigBar::restore_status() +{ + DockOptions *opt = getDockOptions(); + int mode = _session->get_device()->dev_inst()->mode; + + if (opt->decodeDoc){ + _protocol_button.setChecked(true); + sig_protocol(true); + } + + if (opt->triggerDoc){ + _trig_button.setChecked(true); + sig_trigger(true); + } + + if (opt->measureDoc){ + _measure_button.setChecked(true); + sig_measure(true); + } + + if (opt->searchDoc){ + _search_button.setChecked(true); + sig_search(true); + } +} + + DockOptions* TrigBar::getDockOptions() + { + AppConfig &app = AppConfig::Instance(); + int mode = _session->get_device()->dev_inst()->mode; + + if (mode == LOGIC) + return &app._frameOptions._logicDock; + else if (mode == DSO) + return &app._frameOptions._dsoDock; + else + return &app._frameOptions._analogDock; + } + } // namespace toolbars } // namespace pv diff --git a/DSView/pv/toolbars/trigbar.h b/DSView/pv/toolbars/trigbar.h index f22ce207..68f6c219 100755 --- a/DSView/pv/toolbars/trigbar.h +++ b/DSView/pv/toolbars/trigbar.h @@ -28,6 +28,8 @@ #include #include +class DockOptions; + namespace pv { class SigSession; @@ -56,6 +58,7 @@ private: void changeEvent(QEvent *event); void retranslateUi(); void reStyle(); + DockOptions* getDockOptions(); signals: void sig_setTheme(QString style); @@ -85,32 +88,35 @@ public slots: void on_actionMath_triggered(); void on_application_param(); +public: + void restore_status(); + private: - SigSession *_session; - bool _enable; + SigSession *_session; + bool _enable; QToolButton _trig_button; QToolButton _protocol_button; QToolButton _measure_button; QToolButton _search_button; QToolButton _function_button; QToolButton _setting_button; - QAction* _trig_action; - QAction* _protocol_action; - QAction* _measure_action; - QAction* _search_action; - QAction* _function_action; - QAction* _display_action; + QAction *_trig_action; + QAction *_protocol_action; + QAction *_measure_action; + QAction *_search_action; + QAction *_function_action; + QAction *_display_action; - QMenu* _function_menu; - QAction* _action_fft; - QAction* _action_math; + QMenu *_function_menu; + QAction *_action_fft; + QAction *_action_math; - QMenu* _display_menu; - QMenu *_themes; - QAction *_appParam_action; - QAction *_dark_style; - QAction *_light_style; - QAction* _action_lissajous; + QMenu *_display_menu; + QMenu *_themes; + QAction *_appParam_action; + QAction *_dark_style; + QAction *_light_style; + QAction *_action_lissajous; }; } // namespace toolbars diff --git a/qtpro/DSView.pro.user b/qtpro/DSView.pro.user index de29711f..994a2dc4 100644 --- a/qtpro/DSView.pro.user +++ b/qtpro/DSView.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId From 26f4e65b7b6592173aa1b23fcd23861b4d3d1c3d Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Mon, 6 Dec 2021 16:38:13 +0800 Subject: [PATCH 42/60] auto load file data from application startup param --- DSView/main.cpp | 1 + DSView/pv/appcontrol.h | 3 +++ DSView/pv/mainwindow.cpp | 25 ++++++++++++++----------- DSView/pv/mainwindow.h | 1 + 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/DSView/main.cpp b/DSView/main.cpp index dac39c93..0fce15d8 100755 --- a/DSView/main.cpp +++ b/DSView/main.cpp @@ -147,6 +147,7 @@ int main(int argc, char *argv[]) return 1; } else if (argcFinal - optind == 1){ open_file = argvFinal[argcFinal - 1]; + control->_open_file_name = open_file; } diff --git a/DSView/pv/appcontrol.h b/DSView/pv/appcontrol.h index 8e0e1ac0..2766cbae 100644 --- a/DSView/pv/appcontrol.h +++ b/DSView/pv/appcontrol.h @@ -62,6 +62,9 @@ public: inline pv::DeviceManager& GetDeviceManager() { return *_device_manager;} +public: + std::string _open_file_name; + private: std::string m_error; struct sr_context *sr_ctx; diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index 8437868f..9efe422f 100644 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -91,6 +91,7 @@ #include "config/appconfig.h" #include "appcontrol.h" #include "dsvdef.h" +#include "appcontrol.h" namespace pv { @@ -102,20 +103,11 @@ MainWindow::MainWindow(QWidget *parent) : { _control = AppControl::Instance(); _control->GetSession()->set_callback(this); + _bFirstLoad = true; setup_ui(); - setContextMenuPolicy(Qt::NoContextMenu); - - /* - if (open_file_name) { - qDebug("Open file: %s", open_file_name); - const QString s(QString::fromUtf8(open_file_name)); - QMetaObject::invokeMethod(this, "on_load_file", - Qt::QueuedConnection, - Q_ARG(QString, s)); - } - */ + setContextMenuPolicy(Qt::NoContextMenu); } void MainWindow::setup_ui() @@ -439,6 +431,17 @@ void MainWindow::update_device_list() } _trig_bar->restore_status(); + + //load specified file name from application startup param + if (_bFirstLoad){ + _bFirstLoad = false; + + if (AppControl::Instance()->_open_file_name != ""){ + QString f(QString::fromUtf8(AppControl::Instance()->_open_file_name.c_str())); + qDebug()<<"auto load file:"< Date: Mon, 13 Dec 2021 09:18:03 +0800 Subject: [PATCH 43/60] Set python home at windows os --- DSView/main.cpp | 10 +++++----- DSView/pv/appcontrol.cpp | 13 ++++++++++++- DSView/pv/sigsession.cpp | 1 + DSView/pv/sigsession.h | 7 ++++--- DSView/pv/toolbars/titlebar.cpp | 3 ++- INSTALL | 1 + libsigrokdecode4DSL/libsigrokdecode.h | 1 + libsigrokdecode4DSL/srd.c | 6 ++++++ qtpro/DSView.pro | 5 +++-- qtpro/DSView.pro.user | 2 +- 10 files changed, 36 insertions(+), 13 deletions(-) diff --git a/DSView/main.cpp b/DSView/main.cpp index 0fce15d8..d0cb7161 100755 --- a/DSView/main.cpp +++ b/DSView/main.cpp @@ -42,7 +42,7 @@ void usage() { - fprintf(stdout, + printf( "Usage:\n" " %s [OPTION…] [FILE] — %s\n" "\n" @@ -132,7 +132,7 @@ int main(int argc, char *argv[]) case 'V': // Print version info - fprintf(stdout, "%s %s\n", DS_TITLE, DS_VERSION_STRING); + printf("%s %s\n", DS_TITLE, DS_VERSION_STRING); return 0; case 'h': @@ -143,7 +143,7 @@ int main(int argc, char *argv[]) } if (argcFinal - optind > 1) { - fprintf(stderr, "Only one file can be openened.\n"); + printf("Only one file can be openened.\n"); return 1; } else if (argcFinal - optind == 1){ open_file = argvFinal[argcFinal - 1]; @@ -159,7 +159,7 @@ int main(int argc, char *argv[]) //init core if (!control->Init()){ - fprintf(stderr, "init error!"); + printf("init error!"); qDebug() << control->GetLastError(); return 1; } @@ -183,7 +183,7 @@ int main(int argc, char *argv[]) } catch (const std::exception &e) { - fprintf(stderr, "main() catch a except!"); + printf("main() catch a except!"); const char *exstr = e.what(); qDebug() << exstr; } diff --git a/DSView/pv/appcontrol.cpp b/DSView/pv/appcontrol.cpp index 52275e88..15c0e52d 100644 --- a/DSView/pv/appcontrol.cpp +++ b/DSView/pv/appcontrol.cpp @@ -75,7 +75,18 @@ bool AppControl::Init() } QString resdir = GetResourceDir(); - sr_set_firmware_resource_dir(resdir.toUtf8()); + sr_set_firmware_resource_dir(resdir.toUtf8().data()); + +#ifdef _WIN32 + QString pythonHome = GetAppDataDir() + "/Python"; + QDir pydir; + if (pydir.exists(pythonHome)){ + srd_set_python_home(pythonHome.toUtf8().data()); + }else{ + qDebug()<<"python home directory not exists,"< + #include "sigsession.h" #include "mainwindow.h" #include "devicemanager.h" diff --git a/DSView/pv/sigsession.h b/DSView/pv/sigsession.h index 7f478af0..ca38e3bd 100755 --- a/DSView/pv/sigsession.h +++ b/DSView/pv/sigsession.h @@ -22,9 +22,7 @@ #ifndef DSVIEW_PV_SIGSESSION_H #define DSVIEW_PV_SIGSESSION_H - -#include - + #include #include #include @@ -39,8 +37,11 @@ #include "interface/icallbacks.h" #include "dstimer.h" +#include + struct srd_decoder; struct srd_channel; + class DecoderStatus; diff --git a/DSView/pv/toolbars/titlebar.cpp b/DSView/pv/toolbars/titlebar.cpp index 982fab1d..aae90e15 100755 --- a/DSView/pv/toolbars/titlebar.cpp +++ b/DSView/pv/toolbars/titlebar.cpp @@ -188,7 +188,8 @@ void TitleBar::setRestoreButton(bool max) void TitleBar::mousePressEvent(QMouseEvent* event) { - if(event->button() == Qt::LeftButton && !parentWidget()->isMaximized()) { + if(event->button() == Qt::LeftButton && !parentWidget()->isMaximized()) + { int x = event->pos().x(); int y = event->pos().y(); bool bTopWidow = app::is_app_top_window(_parent); diff --git a/INSTALL b/INSTALL index 94bdb080..abe9eafe 100755 --- a/INSTALL +++ b/INSTALL @@ -26,6 +26,7 @@ Requirements This is part of the standard OpenBSD install (not an extra package), apparently. - check >= 0.9.4 (optional, only needed to run unit tests) - libfftw3 >= 3.3 + - zlib Building and installing ----------------------- diff --git a/libsigrokdecode4DSL/libsigrokdecode.h b/libsigrokdecode4DSL/libsigrokdecode.h index 491c3371..d66cc74e 100755 --- a/libsigrokdecode4DSL/libsigrokdecode.h +++ b/libsigrokdecode4DSL/libsigrokdecode.h @@ -361,6 +361,7 @@ struct srd_pd_callback { SRD_API int srd_init(const char *path); SRD_API int srd_exit(void); SRD_API GSList *srd_searchpaths_get(void); +SRD_API void srd_set_python_home(const char *path); /* session.c */ SRD_API int srd_session_new(struct srd_session **sess); diff --git a/libsigrokdecode4DSL/srd.c b/libsigrokdecode4DSL/srd.c index 92be591f..caec1fd0 100755 --- a/libsigrokdecode4DSL/srd.c +++ b/libsigrokdecode4DSL/srd.c @@ -386,4 +386,10 @@ SRD_API GSList *srd_searchpaths_get(void) return paths; } +//set python home directory +SRD_API void srd_set_python_home(const char *path) +{ + Py_SetPythonHome((wchar_t*)path); +} + /** @} */ diff --git a/qtpro/DSView.pro b/qtpro/DSView.pro index c3540636..575d247e 100644 --- a/qtpro/DSView.pro +++ b/qtpro/DSView.pro @@ -13,8 +13,9 @@ QT += svg CONFIG += exceptions CONFIG += object_parallel_to_source -greaterThan(QT_MAJOR_VERSION, 4): CONFIG += c++11 -greaterThan(QT_MAJOR_VERSION, 4): QT += widgets +//QT += core5compat +CONFIG += c++11 +QT += widgets #QMAKE_CFLAGS_ISYSTEM = -I diff --git a/qtpro/DSView.pro.user b/qtpro/DSView.pro.user index 994a2dc4..536a527e 100644 --- a/qtpro/DSView.pro.user +++ b/qtpro/DSView.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId From dd11e1096cc666e2abac30aab9209478b41d99d3 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Mon, 13 Dec 2021 11:56:25 +0800 Subject: [PATCH 44/60] python home set at windows os,fix path string encoding --- DSView/pv/appcontrol.cpp | 7 +++++-- libsigrokdecode4DSL/libsigrokdecode.h | 2 +- libsigrokdecode4DSL/srd.c | 2 +- qtpro/DSView.pro.user | 4 ++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/DSView/pv/appcontrol.cpp b/DSView/pv/appcontrol.cpp index 15c0e52d..23fd92d0 100644 --- a/DSView/pv/appcontrol.cpp +++ b/DSView/pv/appcontrol.cpp @@ -77,19 +77,22 @@ bool AppControl::Init() QString resdir = GetResourceDir(); sr_set_firmware_resource_dir(resdir.toUtf8().data()); + + #ifdef _WIN32 QString pythonHome = GetAppDataDir() + "/Python"; QDir pydir; if (pydir.exists(pythonHome)){ - srd_set_python_home(pythonHome.toUtf8().data()); + const wchar_t *pyhome = reinterpret_cast(pythonHome.utf16()); + srd_set_python_home(pyhome); }else{ qDebug()<<"python home directory not exists,"< - + EnvironmentId @@ -93,7 +93,7 @@ QtProjectManager.QMakeBuildStep true - false + true false false From 0e5fed0855633025612533944c89591a6a7a68d6 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Mon, 13 Dec 2021 17:19:23 +0800 Subject: [PATCH 45/60] fix form resize exception under windows --- DSView/main.cpp | 7 ++++--- DSView/pv/mainframe.cpp | 22 +++++++++++----------- DSView/pv/sigsession.cpp | 17 ++++++++++------- DSView/pv/sigsession.h | 2 +- qtpro/DSView.pro.user | 4 ++-- 5 files changed, 28 insertions(+), 24 deletions(-) diff --git a/DSView/main.cpp b/DSView/main.cpp index d0cb7161..6b45764b 100755 --- a/DSView/main.cpp +++ b/DSView/main.cpp @@ -165,12 +165,13 @@ int main(int argc, char *argv[]) } try - { - control->Start(); - + { + control->Start(); + // Initialise the main frame pv::MainFrame w; w.show(); + w.readSettings(); //to show the dailog for open help document diff --git a/DSView/pv/mainframe.cpp b/DSView/pv/mainframe.cpp index 5f7c3be0..adab48f6 100644 --- a/DSView/pv/mainframe.cpp +++ b/DSView/pv/mainframe.cpp @@ -228,15 +228,7 @@ bool MainFrame::eventFilter(QObject *object, QEvent *event) if (isMaximized() || _titleBar->IsMoving()){ return QFrame::eventFilter(object, event); } - -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - int x0 = (int)mouse_event->globalPosition().x(); - int y0 = (int)mouse_event->globalPosition().y(); -#else - int x0 = mouse_event->globalX(); - int y0 = mouse_event->globalY(); -#endif - + if (!_bDraging && type == QEvent::MouseMove && (!(mouse_event->buttons() | Qt::NoButton))){ if (object == _top_left) { _hit_border = TopLeft; @@ -271,6 +263,15 @@ bool MainFrame::eventFilter(QObject *object, QEvent *event) } if (type == QEvent::MouseMove) { + +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + int x0 = (int)mouse_event->globalPosition().x(); + int y0 = (int)mouse_event->globalPosition().y(); +#else + int x0 = mouse_event->globalX(); + int y0 = mouse_event->globalY(); +#endif + if(mouse_event->buttons().testFlag(Qt::LeftButton)) { if (!_freezing) { switch (_hit_border) { @@ -362,8 +363,7 @@ bool MainFrame::eventFilter(QObject *object, QEvent *event) _dragStartGeometry = geometry(); } else if (type == QEvent::MouseButtonRelease) { - if (mouse_event->button() == Qt::LeftButton) { - + if (mouse_event->button() == Qt::LeftButton) { _bDraging = false; _timer.stop(); } diff --git a/DSView/pv/sigsession.cpp b/DSView/pv/sigsession.cpp index d3d9a848..1eff15f9 100755 --- a/DSView/pv/sigsession.cpp +++ b/DSView/pv/sigsession.cpp @@ -61,8 +61,7 @@ #include "data/decode/decoderstatus.h" #include "dsvdef.h" - - + namespace pv { // TODO: This should not be necessary @@ -1259,13 +1258,17 @@ void SigSession::register_hotplug_callback() { int ret; - ret = libusb_hotplug_register_callback(NULL, (libusb_hotplug_event)(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | - LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT), - (libusb_hotplug_flag)LIBUSB_HOTPLUG_ENUMERATE, 0x2A0E, LIBUSB_HOTPLUG_MATCH_ANY, - LIBUSB_HOTPLUG_MATCH_ANY, hotplug_callback, NULL, + ret = libusb_hotplug_register_callback(NULL, + (libusb_hotplug_event)(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT), + (libusb_hotplug_flag)LIBUSB_HOTPLUG_ENUMERATE, + 0x2A0E, + LIBUSB_HOTPLUG_MATCH_ANY, + LIBUSB_HOTPLUG_MATCH_ANY, + hotplug_callback, + NULL, &_hotplug_handle); if (LIBUSB_SUCCESS != ret){ - qDebug() << "Error creating a hotplug callback\n"; + qDebug() << "Error creating a hotplug callback,code:"< - + EnvironmentId @@ -93,7 +93,7 @@ QtProjectManager.QMakeBuildStep true - true + false false false From d6c126c33eaa705e74a7968b892327b71d21f9a1 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Tue, 14 Dec 2021 17:18:11 +0800 Subject: [PATCH 46/60] libuse callback function set stdcall mode, add app logo --- DSView.icns | Bin 0 -> 115411 bytes DSView/main.cpp | 1 + DSView/pv/appcontrol.cpp | 1 + DSView/pv/sigsession.h | 2 +- applogo.rc | 1 + qtpro/DSView.pro | 5 +++++ qtpro/DSView.pro.user | 2 +- 7 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 DSView.icns create mode 100644 applogo.rc diff --git a/DSView.icns b/DSView.icns new file mode 100644 index 0000000000000000000000000000000000000000..d98f535111e5d7d8c01e74010f32d91ec0f0e169 GIT binary patch literal 115411 zcmeFacU%)&6F2l6_|vz0bYRbD!sJzkBaL=JS#4`Och~IkU6p%$z;Q;k_r$B80-q^{W>d zAP92k@ZPh=@VyMaXCeqe`S95(lM#e??d;6sN3r(uMbcqES6Ui|q64CygmsO9D?m#JgxLWZ z+F@uI4wQ~T@s6cq#^CKRbm033L#Z8l=0``=8oL1Yf%X#=u7HfAKq$C`cG=mXT|dYL zQ5|+*=5Nh#8B!5uedZ@MyaERJI_l|wtb!;Q@6Y=~Mv%F)bsQNgRL!x*D1wd|PIqJ| zQ^sFlFVRQl>N+u0C`)QlwEOHJb0DZt$9(HLzV>skn~oDhS^X+{a`4av?NTSkAgWo* zb2^=&b`{lfWT>j2L65037+Q0?7Ew72GUZYGcq*GgqL!4x7nwG$Et|q&s8Sbn&DCNs z)DNNO)g2jww9#v73_7i}Z6XzfOWPL=9efnMso~5}4(R=4bFlsUI4W2`pEc;51VwpP zn!u#D1l3>SbY&t1Bj}l-2x4fW4!ub;EKmf77I4+Ykwap$z1`Rd(aXijk)y)&evlLD zj9hbZ#2UfPC@Ot$@ft>9c{cSX-)fZSIXiKb?TgWr%U5nlP$$kHws&_Oo5Q(Mj4~ZL zs`ja9l0ApRyxMz{#o>^dpL)F6Yz~Q4Q_Es=$ZRjkXC{ZE%DT~e6~65g&~$r8&L9?A za)rZT*Gha@ARLw4xNWV){QX;Wepfz4E-?%w4KZ55qo3;XPz<&Bp`HfL4mLx?GuS*(t0NzsX@SP zWuru?2zsap1dRx{xvND04Pt|c2Zq-R8k~4!p-6xrKPL+WnUeeS8PAPE6 zatbl){Z|u3dnY{meG^6ht@%gd-_a`jqmnlh`hE{crw~r}{0rzgOF)omPk#axGYH7f z$x;nMK_5kX=A&po3;kac-_PFv|GqID^FfzB=)`pY)B1ld7BG7ui0tQljnAz3kFaPN zPQs}_ChUJvOG`_ihX3Gr{bTp%;@Bbi|hFfD3f0uPw6zGT^nEn6N zyEJSJP_d6mSTrma|DxbmrC}x*4U+&2um7{VH4w(wh2c`h{Kvpxq6ad}-lgG~8tZ?P z{v;d(56tzYVVI78qnDlm?B_y)iTXEsI2dR0(_~D;AL+PuY}vv;SnJ>DV0_n)^$#du z%pd8PNk7*qp!~KN{^0tfczkjEVe0?`@S|Nnt;3-3u77L(K|Bbs`)!p3?td4LLH}mX zZ|fu`9sB%VALiSEMR|aR)A3atZ~uvS=#P&1X)xx_KbSkv|EB=F`|q4HpaX8v?{4Ss zd^%}6QlC5tlOfRq3?Rki zXTtFty&xKUKEf~?!14b{hFk+d;=>EV?5yn|NBOPaz(qlLJpPEvqQjrU1NraN-#x*< zpxzCRk&38q>WQB&`wGn%JmPOV}tqTLhix!yre{0#VV0HEOX26IsWT6PCJj0@1zImxkFa_Q-&w0hVT|gB;ks<3I!(jy30y@2rbHX@ z1x1B3G}#OV$|NqJ-V8umoD3LunKkX;u7Mr0&naD-ay3tf{7X2=u`34$vO@jisI-`zxRe#4LxGq{^xVR9$v$30~ zPTM|X`X^}he(!~!)f2VBIdp^VsLAXP&M5K2TupC=GJPV7>={1hb{nKN?YGBLyctBg zi7gvZS#O{@;|TlMEDES3(dj1Ej)>xxi8^X(>e_JcY5Eg)LAaonEA&AVnLd2$MwEj< zK(V6k`Lewrar23}%>s^Se^)1HE3zD}u$=r79T8%vhl@8yh3()Q_wc?y$Ne_MQ;fTl zH;2S@FX?2X%H7YrT<#+IKEOp}`tzJo1;Gus{M&Bc9Cenb00ts!>xZABfS?3N40{I+ zZlrryEqs5D^Z{k+_K9%)-QAw;;QAG=UIC`Wc56b>jsOQXM}g_v3aB?n(LNKt)2~1Z zXrF|I6L7geWYjyc0b+CNAbL284za+LYVXV;LH3CQZ(%L>U<1H*Z9+XcifpeA6fLuN z1&$(==>c8hK-w(_S4d~WWEo6%&{PhA;mUU9D6pNI#4d25$aZN&(O35Fz?3EnX9B{E zkjc?_dk=60S_I-0?Mq-L^I>^%NNAHQC{$#-iBa?e(~AS)lmI3v;v>E901gKyID*+q zY{xnj;nd>8WOI}-7oaVkY;TU*8vwt!IItaDzQ9!)u&KMn zR>S4D5SQR@@co&CvBh2wY=nli8GD!;eOVyQEf#gVA%sv8UUl&1C_DSSLth`lr%Os`S6HM;#L=gBoqpSK0F0(ov>ci2vd?!DCT=Z+AR>bh#Q)OLWrQ|2B9}3 z(EN^mh#*-*Rc=;j$bW^Lx9tOD-D}1FQk+{K!H?#|`dqwr4 z9vo`|Cdj6uB+H)dIOU88Usj+?%HW zOlU9P1(J9O6<}xrhGwoa*Z~5)pev}7*1PhE{64H%-!F#@-xbJEFn9nzaLF41Aah0X z7Op#V=tSjxe0Ls+--msH0y)|V1kflK0iz-?%Av~e02xp|xI&M1%uX*J5&A)s4Y? z{NB8wA~6;aJwm<^^IkVF37Q&37&hSJJ^}cyL7dNT?SmUZLi-w^mvWQf9nvTeb;=-C zWS#W@5gQts*od-7*w`R$ZN`{L{3eme5m9Io)eGvlK0J~@AQVHW9B686gqBd;%;F$F zH$1R)jXdoxzN-G=NAy&v?C{UT4Cx;zKN`}^X*hWqJdS_ohxF!N6yvT}1pjQn%M6T7~OD59)~*Ebr` zpFqMhd|gl?3%!RZ)g^6PJ!|;zVI>TuVZ-%itlV_>V!7m;Q{Qs7;x4@^e5;BZs;9(NUnhPXD*@8IIt5r<2LGo5Wla3{t8-#t}Q5f4ag|(l#VusLDXLP5$0{w zS)cwCGVG~IGBj9DMtj0dA+sgX^)Jbt5MrK%Hb%67-KJ0=q7Nqlk*GZ_0Tz7uIUTq= zB+80+Xaq(pokIbd&VEQai7ysuW2B{@(A#ol^x1US0i{k$gv~wloDsbkGIPrhXq0>i zT0BXMLD#(idz#f&+893l4SH8T7|k-(W@xP_hMH?4tq4XkA`A7CJHbCyG;|n^KEee- z59!eh!3R2_xKEUNzCJ7e+Ji!45ZcS8(sj3?Jv%7SmvTmmdV?yo+JECTJ;SLRZhl7r zP(fR_X;Rk}XHKDl7|P;$)Jv|8qFkp*+M3#Qnzkl&cAyyel+ns*TBgBy`Vh7x>Zl@M zQ$*36MGy^65N%r2HLp;>l+bwHVPT$n^aAjmwg(_&wEvbV#T~*=b80$@dP29plhl37 zhk+c*szw0FXs@3xr2k~Ckx_EI{dJD1K9Ff9xp=eBTSwamg3=%wpE0FAem+XClT#rLpSZ2U!Xxk(~YSC(3(~OEdtt$Sws)TDetCe1u;mPEBVkuP#{oj zT2K$@(y~GG8hHO~FA(y9UndbX5}mc^fYOHD9zZp>cH+$WCbS#CJoz28@_;`4F%An? zP=Z1D!5-8dgEhBz!v(~Jk2W1}nrfMWzJk}2|QFcx<4s>4!FcWi763$yUSvw9C zu5Lxy7_2q(I}S(F=m67<@&{ne!~Nh_$oF<@#xn>SPM8QHEf#0}IF=d@RsCYfj^!C( z#FS5%HuSo70z-jjm_LA0cJ$%`dbVjMGRPW^I7-wG{wX05lK}ZL?Ez>teU8JosdRv8 z2C#`>0x)G|+kg%GG?N*MTF$6EXgEC$a2AT=U#C(5r>t&68_l&+VT8jT<6_cu=z!Bq zDp2_;O~AEgf5-Xd=O`&KiPIxc^d6m_0)9L&Fv!NmlvEIOM2c3A1(75=^)@c3$dCp& zbxJMTy%|g((MG)moQV2rrGXq>dpYW(MNa}bYddfS-5V(n7z%oF^tmxD2|VwHOL=Fe z4JaMb@|BcC5Mo${3yGy>;9CYx82EFj(xa3Nh61GN1%|W)2rGA7Lj63g0aUz9D;|^Z z42K`-(=!-su*Zc0C>DCy9h0*(GXW)`#m2PzAi@LZZCa=`fVNs|VfT6DYaD*8Ps?O* zK*TjHC^UcEGdWW;3s4gJaS|2ciq06g?@bn31F-azCcxS=`M8X1eOeX+s|`R{3_N3( zv3Wx7pz#O?TWly0$g~lqIIm!i_9KQ9(BW1`gTmd|96&AE*lVK|kzcHmfW;jE)kCU|Fk)+ci;c+ISZkpK)S2@9v0+^Pi0B3ESua(Vk z0oG5GwBcE&)57p4KaNhvc!{VZ%nBsR59Y4*lpH`wXw7tOm_z9FTR3x$9zBPFdDdTx z4l|DC+Li(14r=D&u+UNq<|mrLBb@uCDJ_?Qjp@D)Jp^PQ@5Q-gmneBS+-0i?lbrUn zDxCZ6IBFgP^Vi$SS};}qv`>10lFz_q=tv#fbr7<*3+FC1r4GP7$MIQsRy9m3M9C3K z0Rw?65?Z^60@F6t_yOL^GN2VO2tD}q(+OGu@Bq^Tu_d8p4F%Q*b~jE*Gtu_LGM)1h zycvS89eN4SfGIi30M->UowBC|Css|94AsoFr(nwkgun?U34)xr`d>eK`vlH`|%)3Kgras7~hf$J*QP#_~C4m$u_ zzr^<|v^Wd}ZGAQry4Qg!OPYaGsf){C4+agL46mLQXxbY}2U0(j?_i)+3bMzA${{rb z*^me-(kY`{_$W94G8ak0LM_M#Np!u#D3)FB)x~ycsoL}WYd8?nY?R!UxkFd03^*8j z`5ur9SJ~1b)ltyanszzA#RFCB`w+QSmx5)jblUoIEX^%mOQ$3A!RPG)up+>{->6fw%+(zOP0@@VG2n#mHr%_GWxm{e}wdT zufDb$yyT`)wIT7=rqN%*NQNJH7Ko6$E=|^^W2w9L_+#~WDsQQ$T@8loEDXn!{b#3V z(y1RI4W>`tpNC>4LE4E)!?fvdV9C%PHtk?66c38%jROlzbhO#@QqTfP9@TWgjuiAZ zR2BE_td<)O*DYlz=?)*ce4lR#8UySP1N=7`(u=@@2J5ap%|e6lDkkT{^SkcsC$RD7 z998x<1FK@1-rtQ3bar+u;V3yeI|YPCz50F!Q7Pj-j0o`HusQ5f*jt5f55KU~>UUts z*RKzQJvr<*AcNy^J@tJV7`&l1KiGxEeh<5mESI3{)*A@<gcep947`vqqxo9Vz}J9`EAc)DSi zuoud9O{s@_(VF1Ge$Jt=92~FRds0 z{Zc=+TQ%$Zb`zeR);P+0BS1gC&YoOlEF zUh(SXqc0GNEdRIgOn!dg^c1#q!yC{@c=*3x1(ign`>@SP{2t6I0ZM2iUb}n`fD;bv z03Z<3Juo~(h*vH(eqe>m!>%g1qr(7r`Lhs$kGq~tNhr7m^JNysiCboek{1vZ1{1tqzfQrRN&9_c=pv9;*`Yls2P}* ztAia_F5pboEk5ulp>G`>pFeQ|79uMjILN5H+{3{gZia*Zhk=r%KZTVT?g%m*B0BNK zp})upcDl(-_m=}Di};$S3y|6FSnWYZWluOP*fD0hyuxSm7i>(pLxv2S+DkbsKOlL0 z0!|{@`xvt<5ccYU^udi40Hgpu^g{Zf3;P+4H~2GyFx_p?f`SDuBPIBn*&XF@4cjybj*m;rRS+l#Y)bz|QE*?tYs$^*L7Cmik!cL)Zi1S!mV06WC= z0Zc@nFhek&N=g}zvaNDhIS0fh>fU5K-Oa$-jUtCs*PRN%s==_l)L4#6SA6+nVRI_92g zSN3g;L5P(jV3qSgNzOPsei(jgY^WReUD7m(oBjH6$j*s;*^ z6=4+$NJy5!$O!2UaiI4pjuF|IDOS`b+ORB*Ocn zY#b#rvDBP|3cXl~KP0dpfL4z>+=Oyg67~WJB)9|W5GKJ;*?os(cx9A>%1fNtX)v0B z8l=gOg~1Sno!6NFI}X%H@7XEXYal)3vCpia}Xo1NRyFXK@_i4y4*+p%v8jvpa_3 za$>-fnb;JPW&eod1ex+JCWJBDZJ^?X0pKY50t;^YIPCc*p>H^B3?-qhK}>i$u;&_s z`(y1NbDTj`4m?SCbYf_|2Ma^NE??FixIr(#RwA0`kj-&{?`$SKi_GAG9f8j4EDXh2 zZvpEwY*^^)Tn<)-WWzI0V%{9!?7hv*0hEL`2Qp!Xz`_EHhH58v4#y3ci&%g<+{U60 z>`HLR1(bw#gfL;^VLK1ZSv+@kE(afuBRd25t8R4$}Zp_P`;ZgUu)}9N92eI^4%5Jy`zS*#odN8KzZ;Uu;$;N|PK4I0F?( z^GyeshgohP0Eb|3VFLl*hN|^p!oFTRE{VUdG1%)Ph|XKA?(Rw=WcUsd`t1BI~gDWL7S z-b^Nk4KKi*?|vI7JYeXBkfnLlN}`z#F+IQrYi~n#uq%h-=$BB{ix(9yII!xfuy1{P z7wgJq<;i?uSw}m0pWoMtf0P}yUaTU{Ajh<3q|}Sec6#|^^(Uc?*I`v3%=Rio5MCsU z!}O@e%Z`pa4#k`ytl;kmQl1IAm;tqrUy#u5c!v@W(fR&ss5;&UK|aI`;zB|K1yTw| zU5%NlMuKu@A`0#0{tKqj$$o|Qo|*OloEsUIYJx$xovuQ#M`Z!#gjgQ+O71FJXgy8;6wjMs{q zv4j!ojlQaTPRwW6Slgl8V2SQIv7KO=W(H(_kwCf8FMM&!i3xcq$?;AdmX+4tc7nI= zT5#(^(q4RPXzrG@iFqHN-1T8GA*UrehP{IX_scz3whKp%&1ABie1by4t_6Bv*Dt^j zr#tVU)@X`%VYx$8uvkn7CS*=8vG7i;!%B^eKoAonu$S}A-BPF^6y(xwaXlAa#S6tY?r~jrPwFn*SGcn1F>EL6B`Uu<6@+563?0JK-LYQE5Ycec=y5gf_k(*o*D(5YWzI9?}ZT z9sB?wW3w|s)(V^r*sc)~1|P&D2tZ{akI;c5y$#oR1W~`Yya0}IH$sU(lr?g%^N<#A z`4b)i+r}cGtv5kFR(a&Z(3^k-&VK}hoIVV}TnM83MO=WmVo!PA022Xi59blOU?qiK z-7w1#(LO;KC=vBTR{uj8(j18y0;xO3it$MJfC%~^!v`0@%8E4I0(mWvvO|}4oTZz8 z8^+cP340F4it*e5VhfhRnwS2(tEp0TQGQF~B2|LDG&54D(0(JzS(C#)G|$!CZEahcsg>#0D(a!Nw7X34rV! zd3UkD&L5=`&rr@{f9UhG&*Dlj%kF^9Ks(|9B} z?bVrvg#nh(^b3Kkz!hVMWdIy7qz7b^;gpc93A(~f#4Krl0G71M(e@OO)+ifrD2BoD zB7QPpSo#T%xgY~Oj3X0qlfV+J&H|5t_aIMh0|bnO`m{L{Kd{roPsICSjuvL}*zg#L z5_trE4`!-_pULCMk+uO(LZ{X&XcKzCweSD}2Uw1A5M+&TkLr5|`rtfh$9<67gxLs3 zfwFjx*o}+>bMWYeepx&x>}KD?qIaO*BVfXG#zMzd?0IVCJ_05zXdtq{1z=-;!($AB z6Hj-423c1&4{~CukP9Ko$0J78gh2$f4R~-bp}qAu6Dk!%|A<7ijhoGLg%M#-gs301 z^$T+VAoL0D46qQ;u3VlQWOm+;$z@)`wr=fK+r1JcLa`*wpm|c(7Uh>VO=~Y?z{2u{jHMeND@Rn`JzT1uML(Jw7*x<)dMHdpl?roF>jEd`5V$Mf-aq~ z>Tuv67%wd0sfybXq(_J?UJ^70ZbT!u7!);15#)Z02-d%b9yA&}FXqCkCKBI)lYgB; z{s4}xk+SAeh?;I#I`f-^u#7hJ;!CQm1(w$au@IKp&IUf>;d#L|SgZP5`COog z+B1N{ZLWtSfAwurSaC_HtV{SDD2)w}XrN7vE|7(^gDdd2`?BsPJ{Pi!hNeCbNHuz! zg^dxXFz-1ka!ZB9X8`06El4tb3b345p>Q8={!|7VK&1foJ|%1yLf$565jE6TfwiJ$Neb*5*K{@uMD_f)kSD^q$ z&Y1guep=}N8+vyP<4=_QH)z)!A@mGC16Rd{*iPGO7lJVWYP&+oNj-+LT-_-s4#gLt!|EiJyORn&W z-oNYp(PqR!YVkLG(x`uG043#b(2c7|oBN*zkY*(PUFzXY2X>_QkDuxPqGyW)uU)4i?Trzwlok_~n6L9{A;fUmp17fnOf@<$+%w_~n6L9{A;fUmp17 zfnOf@<$+%w_~n6L9{A;fUmp17fnOf@<$+%w_~n6L9{A;fUmp17fnOf@<$+%w_~n6L z9{A;f|632huLS<1pSAz!`8#Qn$v<@Xcfjf0rvL2u%Xj+7#XtRTkN>8a@InyN|M5RJ z|J7D>TOx?sKX?E(K@|=_Tfu+z_s@J}=dlCmgH!(*?I>D>{gFWgS@{n|fZTrIHz0=o z?Z137;P50GK70gOF8C+zKJj3le?tH5fBh<+Zv5ZB3MKsXKIR2R<=^drra$}+ z8gV21WtG44)3oNd-~Jhhf^~nZ0gcu_WAC@`wSS`lP5-GLLDs$gyKX?!n%_qK`wN}F zX(CQD|Gn1VT@Skie}3q%{3bjTld{;@^3fA?3eMj!07|ETXj zTf-LL|BHSVv@`CE{(tKGPej$^Tv8kSR|NkjKYg7af)*_5ksEl0yfA%+15=RaH zb5%e8G_i+`_0l1ObOr&}kmbuP;TLqV-_s@_%Glrc*nZ~T0R$lpKfGv>&GJQy3~bJv zJaG8fegv^2xU8=^T4|#t|GYmu<-6DHgBmL4hXPLQTX$|zSjN#!k6&&TP0uu378-MW zd&pB0F*8N!lh?`FB^TS2%zKpve{wo`C2+`7t=&Bd?nW!SjnX4Rr>-(xM|vd5uIX)_ zWh&t9yw!VpYo*o%HLVTnR+kj^7xT1g+6g;#7me*dw93nsYBh4Hg<56WrIz%Lp~IgZ zJJ)=&CSJbxeaN-J8m+npc~_?u8-3q$>+tq>=P0!wJX*phO)Gr4^6chVvWot}nJ4#h zzI*!^Uq3K)nnj38p;F1h*((p+Wa__1zG*O`Lb3BA${l?z&oBk|^Q{MH+`zP~l>A4HC!cT3U&W)PJT=>!?Nn>QL zp!wY4o8tW;H@1w{9HDEHvuAzMlw*hMRY@Kp^_AjIo4}OFsrgfNZLX0UCzW({ zuUOLgIQL_9K#&r5ntAN#4=f9LuB7XXC;w7lYvY6AKJPoX1tfxdcF$~wX6>YQZA;7Q zu9Zf79r4jON86<&GpcHh_#sF5IE@lAjCFqZ-KZ1aXFTGE4m%#Ns=P+-$xmIjbN}RY153-;-8=J65h zUOsIa@pk3g#(i1&o?Q!{(tG_UE!rBMXR<2Hb5{Fj8&y-qi;j);b=xO=REo$h-|@Zg zk#eHh8Drll+;kK`k22s`lH7XLo7;{N-u0v=1%E~;NK&Uny=!rQi!5ySvl zZn5odrk*9JG)u><)uOGrb8pAh@ryGwGnpP?f|wJPkC%Ub ze12VZbd!lsO|nB<;}wV0pcvoAEZ_ZeGRAprUGAY-vg3=PrU_vW-_r*8E4UCo434#*U|YZJBvaK6}KT$T}5y?=-*upuSg!+InBz zdeHThH*RNWw$a-bFP?B*S4z49hd%ql=W&x`Kbxt>>rH-CY_#HN*yQY$Nt?7j%WE1( zJk7lBIYNuF^RR~3;@oE+PA&bKyztJNn&Wjoi!|idE~nPanAO@Mn&8q>^HC>7_r#Db ziLU2&b9Tpdxa@suVKByg+^YFZd(KVEJKIgZP9?8(Lj1Q53fnmP!sg=RnaffuM_L~p z_l4#@&1J-e6SBbv&mB*kmv+u`Z*uHsdH6J=@5R>Xo5y)%#+^UX{(jbKWY46@y*J0| zUORpzWS(lxT*^?rW2#l2;UAQYsZsZK zI$G+M-BX!c5)B5Kg|65B6kUG2MA2t^b6aV5VyMu4?zD=D8&{u=Fq<$jW6@+~{^NZU z$vY+%=^j=&!P>EJtxTaMUv_VNPRheM{bl=;A0|Z2G5M%iI9a{ekv;p~{wL$Ka`{Jn z%NMBawO?qkfc$Q3tb5Qsg{3aUWy&VX>#W3U`Mwuk-b=~7ShHRlETwAo_wLh}FyZCm zID^>M5gErr-=pu7KXkeHpdI2V^3Qq#V)L$<-3`-LC#2mSJ5KJ*Ryej=dGn%K=A493 zS9Y+v&D@41Zqz}lbyF=x&&6w-uUi-SXHNe(t8n#%)0r#JyP)@P-KyPVrr{W7fTUJU zUnZ)iO_#W`I((+c`LSk7)2E$Z{5&MPDAhclzGj4DTzbKHBl(c5#u+-qSww;+*-FV@ z_0)Rz1t)i@tR9`Z<-jKTjul6nvS(DBjo7-rzTY-!{*93@UQo{$mes#bw?YgGw=FV! z)UxtmtuV7fY2%FTLz3rzWSHf@)}B<*J0dB&(mnF!kUP@hdSp#!gVUqVS6Lpo`l;~j z7@wrx4Nu+FUS80>vMWZqX=uRZW#lc!uZpPZlaWlmdH zz%g}Vr3&&$UJ~*8>Ad6L=g<5?t$L6@VrJZU!fk?!n6Drv>dheB`l1FFH@3 zw$qC$>D`@Ismsa{pPv_b#lm2La+$a`+vsfkG0v*9+rO&4``n!zzFX!sS&}(FZS&6Q z{LQ-t5pI>S@;c(x9Nua6J-;GY6z`j%@O)10q=Tb0DZ?y{#*1q9W;P^09S=?`VB0R3 zwbI=y{y1sa!Pyt)r&sm9c*OTrTxqWsO%Q2K`7qfEDeIcluB4W!bTDsgOK<;D8d1%* zA$4Z1zeG68<5FXc;l%HT7W-$6-!b%5(c?2mYdu_&UYQCWtxk$K(!2UXwybESCSmiq zDV6MgYUJwa&5f-N-1n6n1^uv&O|}g8Sw^*e8^c(Wtu9TTGD5a~2*=xkJ$pi(rE)~V zsvVOA6B-v)CJnWWPrkh4`uR#;Xu$}P!ek?rea?u*gVd=PU4~ax5AXTB?Vw|*+QX&C zzLMzk^HO%-d3;#;kn$H5LY<=jj@g%qX+=k?ChYVx|2(@wW7~{54~FRL7p|Elwlolv z5#tA8Ia)a_U5YIqYv$;GIn!rVOjTa`U`xxZt`CtQgg_7#)ovL#oV9sq##8TjQb6ge z^K%yZZpcGTsb|mExl)8z72jGR?)^#=1}F3gH7YXZ(HvJ#y|}ctgtoymZ_a`H^Ixl% zX(;(;3!i$0c~ z7<|F|%tD;T0Gs&la?{{b$7H9I>l|-ZV zb0**N&R9gaVKH}3N@UF&t7}mfJ?BAl!LEpGQ^V-Y`>$h6-mkr}c#LXd-4M;TJ(}dgv6iJf zo7*kP&u6JPTM|!g5Uf^CiZ|rvUJf#dUT3wdX65X+Z^S{H8pTU&Eh5^Kj8o+nO^u6( z@|Tpy`8@UsMs5i{yT(6BmN(pNd88I%oH1NKx3_M%L)7qVd21H!8mzv|V4lVsm6~m) z>feUAh2Gy2U!FK|-_C1>s%=vk85c?P1MGE=TIVIl#wSr)ifZMZ)^|P3d|#j5Q%l%w zpmAv7xg*94E32;*zCAr}%#JDv)5Z}AeEmAwZE2jX&_L0idUo46HD_Mplu6kW=+!!w z^!7z(x7R?bx^CQ)o5~jBx;@3q(v$0x=Xa0)T&a`3Be(gZKsM>vc8A6WLyPIlicQld zwmuzdZM$LLwfB{JY1H}YFODl$Op7iX?f!bvLN!x$+tluNQtw;FtHT#5`X7J(qI_MM zg@VHk-D9eQ>~}^dn%;?aGVmSTll=7R(1iuYPmrrl*`dY0gBNdGu^^GUY35G(H_4tZ z+rB`BGs{J*H15AUX`Hh6!y>)hvGVq)vKiewl;^$Y`aMnvp0vUDfL&jN3XwyuqujXU zn~c0oCKR3w;a^?MYp?C&D{Q=$V(jZl9^B$d8Qe9p#CAqN@5nwI+t+-bL36h&JUhy> zxneQ&fg-=@p?l9M-&@w4O*J_)O03H;d(Jtsd5E%e%uJi0<}J4O3@0ioo2W-FTO8o9+sCkC+_@K@ zx4NwyyXdi*L2hWf{T|yoS36?Gq;s?F#*Xl@%WhkuAn~tSX_momtui=Y#h>!R_)OED zW#48s-f*Bf`qS?mnL6XylDb)Oxo@2^XmPFIX3;XFPBO3jtPeXBT?gmx66wz5r=~=8 z=e_={uiMTPzh5Ue-IlymOdZw#cEP8$B&WQ~cNQ9O`iF*n-SpuzztZcgXJf^fhs#H+ z&wq2m=tv#q>`v{qL-tUEDlcsJD|_`46G#twihCXSVXIN4bfcXm~A@6OjBE5%iC@Co#v2rdDr&8x+5%q60mY@K(sPq za_!}n5Jy%@?5wQ2FNTe_xjH5|KzMX2c?p3~n=!j_(+zri|KuC?M{cjU{yky!!Qppb z2ox@TTc&L1n(X|xJ@t`U&uDtt;C*Eitb2IncWt)M@F!~D^0PR|TJ~+;u%!Fr(#$v2 z%l&AtOF04V1@23cGpL_gPo|uAvt`EWogN#Uzkj;5!@k2_!f$Oo%+25wjSD$;qh{MC zlL=;L<3HPtwE|x^;;Y8en{!Gx;R4#){rF)1W}&=pi>#RX11~ z{c*d7ecOx$k0f>N#ICJ_{Bqk0yIK@KI8U`vm{(e?ocwU6&TCffnUj`H?%S5d zw2dm5eN!-J?+E>ejNhf$ebK5-=Z_nv(m1n$;iFwsv z^3A%WCS^54+Sh2ha+k8@9co;B$}_>nM|_w43X}Erq;T%f=6O>RPrsU89-gX-9@@{T zojZYbW#Y)vISU7&?zNI5a|cZn?>xJyIJYB=^)+m5wd>2&DrT65tIJ56%RSV~@{)%w zQx!iHxTM~EGSt2`Wi?%XK^Es);I3YKKoHE@`Oq+5VsYD^x#4#C+WK4%kA4-lhFO1{ zV*7m6gRv9lZywipaQ24H?YCZ7)V&>V5@5`eNX8TCS zx4vb06Nq2R_Koz4rCT-C%q<<^vOFZ~>1%OT*0q!<;;C7>cjQ9S;&y|Tca1d&R)oQt z=2xbz?cTlj)b5)6=FqcqCY~@v9!PC-hWEd1^Lnz%CtPDJ#ojyme2$FMcX9~ly8&Ak z|Ek{${+|7aW3?~ScbuM5bBfkj;p)ORBK8~@(K!+wRLb#5*RwJ$sA&0ct0L&AZ1hxuiGd0^z_YdPK{sd*m*!ycxA5igoCJJ8o8N`oNa#PRw2!= z+MH0#eA(NAtXZqCuK(=QM+3D&eYSGKqRkJ6bYEIbKCwXD!!0Y&c(nI$)8K0@CkB<5 z#y(s$=dla2ok73HOn<`7d#&vm{K2WZsbuJK6K()6wh6mQf!{ z`*O;K$(LBfWqs#6)o+DI?mTYm9FBVQni=HRkBM@te>uk^;wpLiyIH%JkG4#?>J;4L zwjm~PbISBhM^8S`^{|gA>%MW)Kr)2L<_#aAKi#c<2P5U`_txZ5C*zX+v`0q7DI?mXJd37bdbz2q62C4m$loX*fkfLbRU(|Qewt%^HZdoqIMMU? zA)db8xR&#qh_ANQnsn9;qTNwBeoA3@{m|`IV(qbSZ=USF+9OwIjajo&1F2W9t`>z} z{IqwpszFbr7VpBC$>qjfOLd4v3)xrPN~RBI+x01&iV+6cj2cs#8d-IUt8~)tLSCCB zCA~acO=as6P4oO{iwvU$M?9)8xcMOhipv2t&O+_d32vg+%!O^vKcxlPX3pDrh}fed6g}QQ4t24ciz{fGYnTS+tMda^qyk# z(NA+EBY()=@S)8WcAllQncokqyeROu)?VPWkG0=G=hIiZcld1Wb@w+r)y;2~eYTjG zA+*wet1;x&ORt--|y8X|EZH}G&sk&o4fj!< zS6U##7(;(eGJA0O_fqE@D4lUdKZ0x7_VUX@X7f=ak}A`v^zQRY^cmlOVV|`YQ7l;+ z;A48niWxwl8qM-hHOn%a^W1YmagybSh{f-xU!ret+h|mB(c{Ja&i#)pl@Bp?-9P8L z(N^g7JkFP0b=zxs?bL?w_xcZ4%c7^`T;90YySQ9an(a3);AokZ)tgl_hH&0ku)`vI z`}89OS1SzSl%lH6EcWDO#JqYz3YL!=)0N{z)H5|xxT~TY`N?j}hogtMU0T7p39{Hc z_P*CID#o3O{%Ul^hJSF9iR1XQ;mU7Mvl~8X8J4;9o*6vuT;Hzn6(Khk+c=we+ab|y z!}c}3BW+*!IMreNo3eCO)m<%qOTulL;>Y(l2Hxzk+0`J?AsR1Whx(T9C7kI-n?n{} zi=R*P=Ws_FNl&NDKRwG}j*U0hK-3k!G&j%ul+@Y2&>>mp+ZQ`OHO-cjfo?aqFBRtp znVTCYJZI)!{AT7?_(-^B+1wNE74H(i<}h0yjm%f?=9_VZ??=#P7qzEzM+v6P9HS`N z(d>2W#P0PM5Q&dXaeH_Yr|fNf*{J85#ZaY36A336V_wD7eOb+mJyc$i=0mpJc}BM4 z^-)P{cjw(dAFwfkk)E(4a5Xf9M(u^Fq){E7D#)j!RwL1G%Uv#dL zuD<6SqyEi)kL?v%Gg<3-0qbZ^ZwV#egO3{a4i?cSrpD@Bb*woUwfoThHIWzfmD^7) z&_Bi4UlwBUa5IOyQrC0c!X0Nf^^Ay0wEZ$}P4QEL=^_p8rp6kI9`Q@fmj=oEr|CV{ z7ZGkIu8Q2O+H4#B^!g4TLhqY3ez5!Lu5|DcGih#}CN1XswTksyFCce@J$9DZRB?^8 zPKLiOVClr=j2Tq6Cf!n@YRco7Db%8*ii=Bl`7L_>h<_ycwSGpG&XqkUxZ4lfteIr5 z*d&;MO%<+4<{(-B(KS8onH#e-8!1Kqnf4Z>&$!Q zPYBU(V>S=-I-0*qM@L27!|1e!?nNZ9bp1@hYx|qyzZ6a$Ei^q5r+#&`TKwr*3&^@N zjjLkJJFbb(*|*-&Q8B$0>RPZ&{gyn8uy@!lH8fYMx~8u$=@WnH<##vp1=sJUB`aL% z(GHWadQvy(B)e+W9Sm%&IbK_AC@=WF#O$2QT{XMKOYejjsdL8JaL862_m(({UEC@iHO^3?C0QGLb!fs3dE{Yu@yVp51-iaG;BJwzF{Nc&04wCBeru}++*PdwbL z@}fpxQsy_myTEIL(ez^%KIf*tpJ}%Bo&7|=sTa93*$eg7tx>qS`%SsqO`oSby~3uO zXlXAf)VG_rXSy`!EkQw7BhvHHu^B@-y;GHJ);Vopp(6HD>%vBV^QE8sA3R#(-M+&{$Tlw+ z^1^4;qXpY?PdP;2v4nXFs<8_ybDwQAqP&dNIKL#bCgHnI%Do}enMSA|r~h4EWz)44 z-rgybEXWOOvMAQeYTWj;>*}6emX)@UoWdSq9e<4QooN+3hL9XU-N8yWyk)?CS>!z> zp++)uvUHqFk?J(gr(JrM5!Q!3U#dsjH0Fmn)RjdJiMBd$(Zqx^<2DDCa(5nf8G9ll zL}7nv{rbULcXFtiQi|XZ|reU(IJ*%%v|C4Jy~1 zk*A#5^TW20--R0$ECjNRR%EKxUq*3gry1lujOLiFR7 zNt?~X?tZ^;bhd&Hb@phcviDKW-8v<=oObj6j_;h4v&YTaBeDwfx0*^=c3L*_Gha&< z{G}sLIP{Y4_v8m74!Usn6lD-j=c&G8MH}B+yE9 zDos2@^xv!^yF8X$a5#R&;H>_~{``+mx9h}AH<~T3ZwXU-eud{db4uuFhnv&3yb9V~ zthCLs-RtuI#ok*!MD<2(qcg+MH8e;K-HkL14bmwR(jlQBNJ-4lNP{#8h#)N`(hMmm zB^}bBfOOX|bND^ac|V;`=llBy?7i1s_r2G;*IL(g?Lw=__mF$65w~1GHukREzZe%d zJp^5$COBQtn0I)jUk?LiZN62lxo6A|`631{43x6_r}f$bU%$tHT@b|?N}KJH>EFc( z_$=rj`bHf`oROs~@Aah%ZPh}H#sm`k;a90iwuLVUhZzY(rZRS?D9 zxU*S4mr9Odhw+MvTA}|~*mVzYimRmE!+N*=lb&tfK+nHR4!aXlsfz`U7UnD!@+bGm zd*)vbySAVjJjGgUzwk%o@~w@tv&yc~dr=>b<&3eG;46Nq4kby5U~)6IJ%ST`hW)J< zYx?Nv)(4BmLvc#LR`uDp^t*H2A#{;_d$9o}gSMP`oPeCjS4{GjQFr!NBIBzayeb@X z!tU4eXAob3$!V%Iv%UMedr}!x_G1LYznHo;!y>}<-lKI|uNFq>F|h#1Bp4b)4XaWC ze&X@9+#-8{Hg{j~XfCwgDqRXxfCiA=7B!*(ne44UZGrE1~Lu@-1P*~Fgt zag0HNI3Q$blmNNQfaC=1MmiTL#9NhtmkI;XoPCF$oLAf5o&EB!3}0VS@?ME*Ifs!4o;0NGQCGN767mH2lfW?8?Ywd|c){(-iWsoDAcP;R#I%Y4f2Ai|U zo_nlGFKME~+UCt)2jwLI#1;WTP}jm*24{dqL+N`(_gK=XYjE&*<6olbTFc}F7&b}O zPfJf~+MTmdJZEGl1mkclJ*3`1*7#RuF*LSl3sq+DZ{Msg<@%$rUAJu;JBKbny$Z1^v`8%PhHwnaU5_B?~C6+yHa}&_K;Wb7zh^^IMR%Sk8qW< zBg72>x`6M)f^-9NEit@n$7e*m1L-Z*Yu&DkrfiAWu}O|n4Wy;*q%1_4%jyj&ZXP9e zef52Hsh z3|65FwdNstB1oO{9xL>6gpuO!3p`N{CA(alw>9{RoKN}Y3g0F6@xu7&?so?Sd7{XL z1=@Mu1yW4p+`8FlD`t~P#xa(s!tlF^t(AG!62;1S0L)=;G=aGQcGA1oJ{)v0jF*=; zkE4H{4^K|G+HyYWiP;Ec)^b74(W=rN#a0^D;wu^z84LDK=XJ!}e>zA3wKzM-H@SjR z81@H8O)2SHT{%C>@aw|k?()QC2kt-Ktp485+FV2HASxbXDu9LVgN{7y5YdsJeGa3O z)%c2T$K!WZ?;=qZ(X*KK1wqpjmuf3^^CHN)`J5+=!P0{4REvk5V&&zJBrfJL{jiAt zg9WH{z;@IE9N%-&JiV=vH=8(4FdFFP**=_cKv;)NR#d*8U%qh6;vCQMm@>XJi6bzM6JTzk+Stxm ziL#8TTQ!<{cCGIAiL2~N`E)*Tg^Q-GsHND@vROn4p}M98E9U-4xWlQ$$e}g^w$&L< zfk_&BlpGXpht5X%PoBHr+%bd6sLWy(L6cGWa4oVNSkds0RBw4#Y}>F2b|Ue zb-nlA%@a%1p?0~i>+@$q>o%NUV0fGiwpOt`o3ul?Pomg{UOb*@#s0PQhexxD|YZ{9VZ8j#FQHE8(AYP;1zW-B1zF!g~hJS;?r9uoPP4(Q@7_1 z_=WV?x<7vVRU|4LNKwlPxM`Z@Nz5E#2GSHfwa>tHo*x)kqYuv9RaY%LtzG9`3ayRe z=-!ZMb0PwzA9K$(y@}ouUpt6c!M3A$@{kGAK*pigs#awiFP)=UhSzSj_3S`szNbfF z_WuM*ZVy%dGGDrX-byX3dVFix*g}B0=wlB6Jb7yQk;p`q<(-BbC(jX!f;{haP3Bkl(?;9IIJt)M^5x+$ME83S9?cbU9t>$;X`l!kmY-;yz>Butm$ zE4G=jXcTCG5Cm}1_9f2vs)K)>=CSjHiRZEpDHB|jGbuarl~HM2@t^fG`+NTUhyZGO z*U^j9>~C^^{Z#+in7VaetqMkw#Jk!{JvX#Wtv&27O@UzEuPgsmc1B%(?}zfUdgIi= zu$*im$1c>LgB~1pi2XtCK4}R?gd@zj1ivxy8Gz@a6;!&Z5qRmET+o}4uCfQZqa9>bJ!clMpUVWv(#US=*V3aex@w25H_v09Gv1mz_ z+qH)Q>o0GC*p4tedEoua6IBJJE8>kTnbAGX>&BjGC!mecspJ1m!)oVtsG; zEnue+-ex9ov;A72BNp=l;qXiC8MepO8i4a<@)mAwEdxE65(vP}HpAa8jYkMu`sAXfP2@rUei~|AO;vzUne~SZYsrhei?37W3B!@`APnc;y zUqXfLpojxZiFD(&`m`Np2 z_xQ+*4+Yu#D&apo3K{P(upISQ~5t#fv;Lv+oM@9dZtU?(FV;oUCIgy} z@E=0p#3aq99hc{=ECa$=EA^9fxh~B4a6OiTX3{a3^F_|biiGh&&}OYeVy?ar@~l&p_bp+pe+KppBMa3dZ($Ds29WzBD+S>7 z+#<+}2*HH7voEK#tx@|Rl@&(7#!0H}bH@A9$n-@Y$c5>Cp${NFB6nxA zN1B)BCYK1w6HeBG{9(Fw{n~5tJ9)GFm-BsM>8lF$2|QlHH^cgPUa3{uFGaC_!f?N0 z-l>i6d+-lkF{iRIQesABydC}2H&1p?Hd)fcvaR?~;@RAe+(C5;&Hbg714jI718sk3 zz|*-s>kjy*=<#qYNMr9(LoZz}$z5qYPt&l7$-QvQj^hi_O;r67IdwHzGO&3MSpA0n zc|z{%kw;Z0FpM9FM|LjJ7vq)+%&yAb^-b6~9*<;x=r4Ua7rrTZ%JJuPjODen6DOx@ z4Q|gRn{@CL6#y<^CcnGqndc zB0~|L?5bMGJk^v>7eqoA#hlv1KQ%iUB&PbzJf7N&-pJH3QI^2*?UkcP9K}(O6>ss~ z(j(b?cy;W3b9o`ycO0yGz0bWg{OtTpY9FKgL4{Lha$JWG%#Ho5Mx+(T266WMbtkc` zL4ze@x<*qu<59yVmQ^{8cun2-d|!G$b^Sw0dY>On)NR$CFy(pP)1CHhPeeKyN^wXP zf*zkIFFWW_eS?1Uw)dxZUuRzvmM-Lv?;H4Fh_K{8BoBf_ZNLta*=&drn*%!UG_@I$oMOtb zA6e9T+w1|pIfo`Nm;fY}!i!@ER8U=bHN&;l!68UjC7UiPK|onQI0ZNu)R;yygx3Li&3 zb3Jm|$C#TG{vk^XQg22@0Nf?McEdN>O1#X#in_q*kQ`Qk0a&>)VNG<|n-)|u?t6S+ zNWh2)Gi6sAa@^eH0g7*;R=ud`ap_{tZ(#2s<0FlMj-L*9Sbs)$diTmk0*a8XUYsAL zf8hH-g(eB}bJS?}jCnqY+z(c|l5C+>j!Bn0M0Ef=wyHdv%Koak5R1x@0lGtpHb*+@o}q5#UbJRt8Tdpoyo5`8&4;Un;+*?zgF8tzd@$3GM(6_NE+z z#kPHe#iVt^A4@;C`Ho<*7#;qPuVHlMe+C~v4E0#$1c1JH0#3Tpg2A69%|a18{_5`> zTH@|)fXec8NtU0p*X!_yM8=9|88$IBpQ9MINtOmTH3RyQQ2?*BfnWUNE*^lfOpn|} zKH;qqA#wouA7WpU3e{86*~sxX4m8sYHi&DulP2`Z=ewElaXIkAq;lz534!+OZzTag zij-<_hfu5~lUQt?e2V#5%4WvkvqHK=_Rmu^na3dc z%#D6y`2JDEo1`@oPrZ>!gOCZq;tC;al2s9YAauqh_(pCzn=h>Vhw9WVZOXDK`^toPd;QqEZh>OX z36VbHWrI8TKT%4A6z2CD+C6STq;G068HxXJPyx{7eCZ}4$&IjmPdgc1hm-$mAxe?w zjaU^6ko#n{*jivJ8m`2@UIr_zeE}m1Y^p_7#=Gsg(sWNp zDtHv1KDBv=IUZgF9Kc$UbQ>^Vg&|Z_e<1`z25{WjK~`6Xe3tEefIzrpJAH;SU_tSJ z0o9nXL^~P$;R+Prh?iXC9bfU1JL z(i-nJiY;IVQ4;%#k%HI(Z*D>y^_1@lZ@MzBNw*6fXjFLN45hHn!D7vN;aF+S*Yi6ujSUEDrMYGRu8J5X($lHfd_=}BP3b)f(BVF@0?yy+(S1}Z8Xnsu1 z0A{4tS0YH0-~&&bV6~_tU0m#`W>GSblb;T8h}e;*P%_tE%X~Q)^b2hKs0o9+sO(L4 zgE5z%C93F4f48f5h)^^FBmN@k%9&emtY4UDPB1Gst0D*lG!w_y4V(7NHW z-^>%!22Eoz+fek?-3Y6+^QhjHk1RNi6|fZgDxg>de;_y;`v=($cZsDlRMDNV$I|>o z#;Dkbjc6uBY|id?Ut%Rx*%8Lc3oh}c^VKE|=m!~~i7 zzL@zWWq((5#QyV2)FS4doA!0-1C-3k>z&Wvi6>-;{ujf9#9PH092Qhbxz{Gh&lI4o zb34_w3>wit zso~dboX>sUnRLsaHfeUT{ZWgq)>wl3zSbHRJMBAqjs5yV6l?_vNpYvdn0qSn0S1DqRY$z-q{VwkmOcsA~|ZOAv%Zj3B=UdLQ;NBRxh5fBI1@%7D9gwRp}p}{SI zl_@f)iB>%m@`m2W0U#xTL}L!nX&FJ>%w1XE4+7!GRb&fT$Ee@G$rUdP%Pow*RK23W z1%2WK5JBw2R>b)Y zOc5*XCXS+RNY2R*D0h98Cl9QNsPWpKi{3QZtsW ztXr9BDzs8Qbylpo(SLdHy>I5>$@y|@AVL;wIq-P*%@9p@w(oLU3_uM7MWM4mH_SQl zP`>UoXH&5j;nYs%9}27T+k<;WyFxb~_xJ|!!QWK@+}Kb9Q#Y?y%Wd;DW3?7EDX1~% zl}iD}_qgJj(IzEf8X%iRHTAgexzZBmE>Y>E8-sWUdy^Lcp*?Gec^&H8M`KGkVph$e zd1c$EIv;E;IB;+0V`Jf-6$6mfGO8Z1#kt~Y2(r7C{T27s#tTzQUuXR_ct!UU^IbMR zf|oXI**K~sV_cEOAj0f`M))+`09-~f6HP~A9+__A{2FsT#6Kww$*?In4ZG9O9hDRo zbv&nXR<<1hBO*$ve@8iniQ|t&2qKDWGC_x330vsuwswYvP)Q|t@1%Qr{>Z~Ylnsv{ zWW&f{%nIN2>|i;|RXO-QH3%}!p#2~nUv9O^#K6zQQv^ME@jBP4ABD`5MQtJtdGLVmtMevIR(HzlW%)e|@w;6KKf`?5 zBplwhB^xR~+yOcPleC~ao%ejcm9`uEs;|(3MG6nA_jB7cufCwy&wK(|$S*mv{3Yag za#5kuRH1cxf6|BfT30Rrn2T`Gln;A~k7QsFKSc(ZiG#s)@AInNf+WKtKU;GJ4TuVeLti?$T?Z|&?aRL z8%Mt5&mKBdD*9d@uOv-~gxBPchV+ZON7AtX;_BDuaxJ)6ml(KTKCW-XA-nm|tt_Ke zqpamSYbH*HQ3@6)KcmU?AHx}_^^wYrvJ9NiSH}am=&^RM73nL{)G_o3{+wfA)>D0g z@cBG^R5{0WKPXE_ zT^=Y}_>MEwyUPjhD&%z_Fh3N+2TTxukCz5%zKGtcX$&nvDNmA$$&R0l*2d6~?vB$k zw9IiID!gO3BJJHDV9la<2QWC_Mm5`_le=}>DD_|?l^##oP$6D2GD}Qp_g*NLKNFu} zjYWmb_l_nYC|=8ISqAN?TyIp?I=3PWSlk`pqKYqG7=`zPCablSng=!9=`iGj-9!ni~t;7+MO%KEB;#fMh15*$)y@Ss%G+FJAyN()i z8)K?O>>j&&$Yu`iJA>nhNCE$Z$FC7rix#({k^2=t;eE_J!FP5Ad;9SDNlMs4&{p z_A$tgmcM`eyHj7sU&V9GVCb|2bH0-X?Q|yj8%Uwo~%W0Af zN+MqnHuv%0%OIO)GH=-?r|B|jHGc)1YOxtQc&D#g8c(b%W=G0&3KCUPgETwYM5}`P8@c8v;{gu`Yf7Sgo*l#X5(K1qZds;ic%CToULAz2-7t(@Bn2I z(@H=rEjt-ov&(bjs=0Ad+NbP9)O3^ZPK;^jireu!8WP3Ls21;|oy<_YY(2mQl9UdbdaDq%ekAc#+U*-+}pZ29(Asgny=+T7uE@ zrNTlU$-!N)Zus#MgCL)K;zP(<;|l#$E6weAh9r~J<|q2<{nA*FL2wp=&oZgFJ;B*& zcr2aBeYf*r+{B^Fh_If67goDwr?@qzE+tQ4I;Wf#<*yW@>1VN317E$^(pvE z#@=9+*Z`CXqkiDI3zcsD!f)*j3;C~G8}Qy9)w%6?#At|sp04n(z9x{p1FN&ywRZf#S(|Se;D5; zI??O$hMYY+=jTdcO{asQYnOiku_jj~D#@K@*dr_;|I%F^CsCwxK#;V*s?XV>zySD@ zKmQ{<$TUn2TjQfW<%n%fn3V_qR@t}vP{+%gdt$Yd=@k?!VInx4e967+-n$yh9`O|A zWJh({tj$ODtTtpLOTLaCw=wd~Qor~|5v$91_xP=PHDS^X{txecaYSah9Xpk9@pXt-Om;Uo|L* zWD63@jH_7Puo#Q#zqm6TJ{r!8+v4fJYHTB|cp>qqz4I{nhtOW9cMAtUl4dh==jcjIVb(Sv^5VT@kZ~%WRFTzh#97mf5!l}% zdEW!iwsA22S?;CNOtME zBNq4p5TuNlDc|Guuphw%N+Hf*<8`CY?QW!bzmHW4JJQ+DSL6??vym0i{Jy0-X;=`a z>LQUJXhOFXPx4dHjJkgW@l5@B(r6b_4f@eY)zKf8aQX zi7|moo=w5A*5C#ANaRVSL{2)+bRe@qP6D}$es9mV58wK?1kn{7%FqSXP*z!rkmDu& zJR}Tn8GoGf0TsxO6{e)uGkNaA$8SHKsfDzQZ>_H&etL7EQZq9882K~Wky6dD$}?tY-}M6 zz09fk-bJ>`hHKl#admX5YEqn0O~Py0{p&vI5ol>UYUpWG(ISs}qU`0|yyCblEuUF|B#w5Okme)cjyvOs;}5{Ui;U>`2oZ*ChZ0gf@R9k0>0xO>NU@`4ZS^!wV!?c zVo3P>w_G&fO8QE-zK`7enJXb}l;9woo3BowoHuhJ3t@mtlekGv(JB5mU1nr4E+{$q z(^Uftwo%BqABsikb!K4aVwm{cujlCgMUa7vykUlSJYI3E$;Jf}BN?Rs?M3C6MosgN zrqs&#ZPd3t4|%~Pi}n)P}&!T6Po>MS95oSR+PiMX}(pvFq=YVKLrp^y|mricd58%o)9 z_8lt56>oieC@0c;VyEPSq@${9?O7LcyZkzeJWte&Q7A4tKV5cIg_s{T<<}#U`|IerD>ic9x{Fu9+EzrY^5wX z`SpEP#3_t4=#S`Rg`wGd?M-bbtbgu}xIlZX8h7J0R5KIDzrU6>z%|+Q=cel+B=|KF z9+_@UjfxyYzWH@j1znWsg-lnh%}CwX>Tw@Xg1-~ruRpUJO=*RK8b8w0K4Z$bbyvD+ zk>_`*joOk?b@tX1693at&_yh`q*w)#MxXxhGnXH&NRpO-P>#i$Rl1zr)EA6;0s!Rs z|LFoq|I)0tOwqf)i|Ozt7?7t6D<8j?t`okI0(*FD9GO56O-*|AIk1f7dgC&W)$gsC zu3YlpXJ*}YDNxXM%u?38o2yf^1rYY_qli>((^6&A;QFm*ZuKntE@sjbj~s* zVM`nDBZg#Sdr~&Smffy55ar{G!T#b_RVfN{b)jBGk?pu?!z9n-LIZ}de#4h2PLl$6 zNX5Zv2!xENy|F3vg0kAHy*&xbdw9dMOi><5$iw09yUg9LmVZfJY^@;EsX^%MfAvuQ zIh!@$(q(b&oul+3dF*K5(rE#lE7beVJ_GgOh>q@&A?s}pq|9bDXr>dk{#S9 zBGD?Z+=}$Ah=#AaKalisWLfO4f6?~yx^0sJ$8K$*i0kYjH#uv4wWa)>@{<7Iz=*@d zvzHZ3XCKYKoGGHi`W-wU8ob~aH<(&Fr&-c}YbXk(*}QcEKga@`$n*zylArzx`?zGW z+8}8=dYuv8aqD*|IsXqw_&=`f_TX4?Fw$V!uis(g)S?Xwba;OXz0sxvsiFzJoF9-9 zq^wN4yZ%!I?@#;Ai64Pfpb-Cr(%NLZ5Vx>pGh;ThnBb5zylzq+?CIGdf0w883fUIU zsykR-dAw`iJJZ2Cf+#X?{9u0!A|LSz5FVyLvV?fhrUCd!-A4ZLBqbf<8w}<>!A~}i ztbHIpIfMb4A^Nuim(M&F#Dk6^8kd)wVMl)WidqA{c6~(tebri@2E%>&yao~dD&<^w z-5P81C7;m4Ay{5!j3ySlqj`Xd=QcANYczap_uxPh^m?St+x1q>dK)&(^PbO0O(3ZM zIbq9>4IcFuFKbTF>{%Cgj;AWjuW^BE*u#7^aLM+Owz7tKyi}FtsuOpihKa8DX%h@_ zS~pn@Z3j)uw0|U>z8THV#$CNeXmCGnGBQ>jO~z6tq)83JuNL^KO@!^08^x`x%bMm&p(bykr*JYk}~-gXA!IvMk}eUxz-SH%R}h;ex+_{HTro z^|30hzg()JZ?745@f1Bb3_o_7)i%Z*^+(1O_&P%oFFzkQfm_Ar#_FzWKdeiI>Hmw_ z(;Wa2U8%WN-0x8MBskEt2uPsxtI`Tq2=e^i0nejKak+Rz~~9n2lNkAxT`@qaMzkXM+) zrcte0+|d$m^il<*=sDc}#(O&ILu*su=xoC+ghzLyPw#44ZH@{%7d z%4{A`84IlTyiZ;_*!AZCbO4{czGUNCu{J3*hxuUcG($h}o5}a)aui z(=HJB^3P%Qd_$(|BEixj(j zAbTer3K+1(?M<+;I(&*RmF-gavO^2Y&F}h;N@>&P@g9asln(QcvQiL8BBxF!_#X#^ z9%LA0@H9-a_G)4w3F}I~nK>f}3cF*TB@ljNyGrTG7wF-j(QHz{uU^s|2J{BiS+D(ZW!fY9oPJ0Bu8azvK@QPO=DOmb1%$};XP zYQ2duB-2P}YtgX;(a+wx`y}6@oz4537%Nr_60i`++3K+oNhHdY67I7`+Jtg}UZ6nc z!DwfsSrXJ;q>6zr)#g78@6MdKGU9jK^&cF)m-#P`FiRna%Y2;eev09qbQO6)Oh9tU zDSq0-SF)I;$zC?ITY0KG3s!8FeYetMZ7cC!zSO?x6^nKnPHD%ej>JXf>v=?O92aE*9{5Gt?rF)OgT}d$r z?Ugq2xwo?Ee=V%wyN`R8V_|<1{5EH=$t9}|?Nc!vI)6IE_T*%;1RszLg4<^#O>#** z-#PtWY1#Hk%x+H4f?1eyR@IyD?Ir8h1=uPE78VLc%=;UON)|jrc=X3XwzxUg<|#KK z`Xp`lJ=d!-@=}-kih;h)tj>$Cyzdzp(Z5Q69i1_NOn&MYY^8D0Naw+te_kBqaE!@A z?%yki>dCu;y5paKyEebs4+;)>kj;j>3fJ z2>^fIqUN_y$f3EVO2u!B-v^0fu1E3a5e5V+s@eS+KRS6275%2~ zAm8atHK-r^p(k}!y4mqk)}_`B8orD%y>-=Hua(sEe;M)kU~5>2OX!v>TIOF(JFzJk zDGKGgv_AJ#`B7P;__U8%+2nV5VK%K1%Jg-hT>Lj5tPM5ORJB7D=}$2RHU6O)Dq5-Q z=^RPgP`bLw@nf!6Y46t;y&@8LYCC~jt1dEMn1sfz3{04!ypJ4qcyil%HwJTHM7*lX zC9(Zp$+Ly7c#aTIKOvUFR+U@gFPf+A@Fw5Tp1BWt!#O6>aQoOkJLQdbG8>0_GmnC` zcy0d=XC0^rHna;#Q`9~X680vyQ_2o)P_I6Aq&ky)svOVze2l;B0pKIb?9}y>(4%sn zh66k+yp|JT%HP$)%shShA0-k`)iW9iazF7^Tym*5%$4H_ z}07TcG*D;+<(7>o@7Kg}pp(dUaw2BuQOSQL*>6;*GG`Zs-se&n@%IyNA}PZAw^rAoo^1uGQ~uzPZeg9!Lf z_i7;=a8-&GCSFxW_fcP<9(g+rnwxXeeopMbsBiJ@v2h$JI70ifIkM}5v`pF3zkrl` z!1jUUN71jS%LHdv^}b#B-FZscXTQQ>+neX;y% zRn@r=aoD~xV(7?kaVw1O^4IoL%8oWa?;ZCh(^3cZ&@o;f{qEGyFz)bt07Vg&@Eq40^*AzV-8d zG;t}G{43b)kE+FL-`bDi35!kPWhy!*sdXa%=-Nj%cdfJ>&L&^jJOY`=C|a>b#n`k` z9G-qVj@N!J`*f!5TWis=_V(I?b`ZkAv2D;y&o{X5Rnt>S+6ma=9C_%!rN{9~f1vLW z>TPcX3qxlEA_1Rn_kVfL=r!OJJllB@WLL3wp2kz3^?`c0;?1~Z&BF|bUXFwTm!q!Z z>!g@4lGm+c0ur#V88g~)h`%26{G4?;zPwOU0jhYIBXuN{<3T7VI(~84NXWQqY2t)T zpko^D=bzF8kVo{J)3^16t4#52SsH73;N4#cF3fq zVVT`*0?S5g_=;maBZC{ta+6!<56sk75}-vLt=6G3WNE~^>S!YH%h=$ybh1aePYAuk zYT=VDE)UTM;|L+Yzl|;)-(j5l2D1b(Z;zsWEk=xn#c78a(tHB!iWT82fsAf_Srrjl z3am&*J>CrLr>m!~m+qwF4RF*}c(09qp`$D@Ed$_mvvNdY3J*{gCKmRXlAxycD6TsA z%Hy~`LZBxG)=JK^7e=8+3t3N9ym#~)yWM?Q#t1-a0W0j@G;aN;LfPbERL6b0#Q0Za z^K0jx!Asb3D6MOUXwo%4AX^JS{^9i5ukGbfjK<3XxNnQV*FUzF<@-xbu@pBr97F<| zz5YRdG#>u0TUu_- z?`Ga7@|M&dQe{ZtIef^8!5Wh3Sf4J{JlW+_qW1>1ti98Ir^HCgP4yqE)e{2krML;4 zjCLoI>Ka<&4YGZbIMEakcON0(!@#UBRF6y~)N{VAu8kHMsjdD*T^eS4oSYTSpX9RY zdT!R```t36Ub3yURMu)?_ub;|H*H1obcSk9oWAN}G`9=1yQcDzZ{-={JRwPduMYgz zbiwHdWzbdHqrF1`AA%$^n#EAypX*i+ultYPKV^WLMCwn#znd-JqVF#kuju8GXX{aG z_TU{4*LJ3g{T<@LTPzW_M}O84x)c%MrE~X77O(eH@8_^ek5`GYf}TeS$dnHG%^ajO zD|F5ugxH5F;To;nL)cyoQx75;Eu>Wd(Ig(n0S2$pl^C0@W!lQ$3p>rxY?)6V#{E$@4>!shD#OZ(p7i75=PMLcjD-0197ox^U)+P&QtTnBpQ3|diG}M zN;CZ>N8S|Vm~EkJot!2IWxcUaHb0qtQ|O}2e;7k6R`=U2 zlP8&1y;eWW>r@i;BSfnF5~QNH=RH4$G~z)o|2s`5kb%yB@gYF9v@ETvx2zpPzUF8A* z)&zr~inPV5h9#Ok66StS{&=Se{C2YV)9}-~LTBR56Tb@fjOV<#=GEk;ncP@lMF0rT z7GJP#9)VpamYu)Sk$>xZNRJBHUOD?aYP*p)c3+rtIJbV;xgET{bheFYPXGEvsmK7Y zOt~2i6Ib55b{0W-&6q8SSr+ilsWe%in~oCBSQu6ipsg1ws-dvqQHZAD{ne=8I>(y&GOA zV;(NAPcTX@og$Enc)J@_luD$6Nfi3i9C|RvpKoX(3xNdIGjb2kNgjPHZwj`XRcEQ)SruIo}A+k{f9Zj(1}7~BOGcLoNaap!$csy{ouOfKyhO?#uhl$^3JxqRUFS{< z^R&xT(@XXAIA*+ly2(i&SP!!wI1N{!M=5+%_6`{Opf=j#0Nwl$h#TIK8xE-RtcKb2 zt0QL7Pi-A31MezE7kYY*g>Ee`ICRxgf74nqsbG>RZ8Q24UHWLNr1RHeCGQ|9Xn3}H zhFD#S2y5Ax9R6*G(Hd`kE@0^WgEzl21BF&n>dJPVEhnNKXL`t%=JWaSc+G`z*EKmu zZod&|C&t=wcaQDfWHuXpeL08!K?qa+c0UB^FK{ukN%xq9xJNsn_%q_@0iDU&=ti6{ zkeFD1uX0$$7l%{yWD0+yu)E^#$rZEdzaCVfbxnmp`O#{}KNUvm@+o@a@`D~o%q*L2 z9EC5;i>G7mqYh@(r@>+(69;ed^uFU}Z@%)03}(l}1BEMUlS$1Nl2|VV zOE%pV)br(n|%Gq zg~*WQ%MZxhaZ5f)8?_ZiD&PcwflM0m_Rd%H_Mf+F!*qEo95YjSwpAjAnJ&4|95wdI zgQD3{0~UDr%#lp_-c4kS18o`KwPlOknCD3Bt!D{GYRG+umV`C-3s5=`$ip|2#OAf9 zfCB>@d^HJs@_saWt?$ElWfglh?yE(7nwP^QT8WC%*S2N$70~mUe_eZA``!0Hp1$1m z3~`tWBo)V6P~9mj9C;Z`=}qw!)NCDBmgPqZe)U=AO6plx5(IiOSe2@Mx4ysVcjF(I z==FE}%eB`$p%KluPX9hjSgR$DETNW7_=&dmb$wQ7QPHwXeAZr1kyzb|b;m4#X5}$FPQ3gE1!9Am+J5jBwZe`@H7;S2~QI4n#Lxp={r< ze)`L4bb0jjQO`d89K9_-dHW#a7Tj@upfzfwP!ha2RK8dng!}aFH;jdWgALrKJm$@)VJ+i3c!@ig^y9&>EXH}f0 zS#_LMFjQIp^^~yH>xw-XyPLAVEn3#ih2=6y9qQWj(r z^tde1KJr9jOg9=b9g$Mj<|y7al!7bxV2Vj|{5e*U|ARb9@=oGrsOUO??X{ zlL}8OaVgqo6j?Y|c_o!;zJ>UgZI!Kc9GR?->YE}@;y7j`H0%a$@*sM&3sCK zM?PZ&rA{~`vr|cvf`T|!H^No%;+=~(-pGCb>g)Bi56ln@6?$-&;=_U-5(4}1vLlFl zSoOPcULrI;^5PyTfho%?I*5(KOl76l3m%OxW+ZyoW7<4n4=(5A|CsUu1ZqAklN1L{{2-IiWL8qOP+}{pxd+~3SLfu* z$B)y~mll~^nsgbQ(1;~%9|r99G8Yn7A&;fVDb#jN+-&iPU=xu{SF=1gxxj9d)N6R% zv#T->zU%&1YKiE)#?qT*t?bU0sepWPjN3#r*=*V6`kKG(Z?4}Eir_B{U7bJb#;^X@ z5(qdq31LTYz7jv01$Xz=bO<23BWP*=bISn2pSI+?fM(RWB`3ADrY1Z`|N69ktEqMH zDwDz{d!&v2dY3*xv6_BF!hlGT|HMUP=5it9{=9U?ZOn(_%wSi)mbzmz$^zhve6(5- zSut8%7$%7{jy%KnITX86pnq@1zI@*}iNFSgoE>47k;yYQ&;W$3HMAcRl@J+a#*_ z2&g+Od>r<|7La0Nb1!FdLowXGatHY)iOM)D^;g;$|6qNV^y#0qci?#A-tj*^Q-LhP zxC(*R9TIAbgz5DtDahInDE5CFX2%HpYMT#|L-;HQFf(KHF-!GPZw?ukqLkhJ#JhfT z6G8rv^ON(^lj_F1|A(flaA^Ab+S?f2CEY1VcaD28F^*;GAbDN%i zPXj!^*1t>m#}0j1Fx0P#OjGe9fBDJHGxhu7k)zOv=OhfGl4+l@yAnN<9RK-gD}Jc? zm7~`EPc>)ooK4@;y$js~BVD~|qfyoQ{L|n-ry{ajdpGP#!_*VOcvuUMau+Ct%f(>4f4(N7{8} z+0o4RUUcuavFjG$e;)^j9xALF#{&Y(AhBYnsiXmqQ!Qj<53dy;S0Os=W2)>Q8{O~3 zEM*tHY~xRE)aFPT6%Dx*;Rlo)Qd^z{Or}%A=4SF26@DxmnDA^{6h!KqBf72FOy|nW zu~S#*!r~z&pSat=M|$P=9;)|V1sz29TRegifAc>U=s;<8=3$W^j7c4;+hR!YXSy3) z-yTzKCw_QmoYi4tG{#%buctY6@9i)^g&|`*d#6u2o{k4#k8MO)hs!$FTk-I@r**F# zSyTu6byCOO`^i|yHFWe|c6dzICbIcc;zc_f<~)Be>rCSK-+%3pgW-jSC_Msxiy8iw zE{2wC>shUv|AXz*@zNXdD8ruk^hfPiTPZU$8nFpqCuT0Xwf9^AACH8A!QTP8r^u7m zAC|xLSqdjjpG@~)ZysC2ICl7PE;O0V4GB&P)VB6iy66w)w&8s`6CUDy(fB*DB79+} z%>38A#KU3p+xQGNf=zFYcTWEtV{5=U80R=8=zBW(jsi5yYup@#KAgl#NyRWhSu-*| z@6hP(VXnYBKKgPWpVqp4fV5lTJnDqXT=S%El&^UKOe>}SBFB@r*l)~RmSltp5D35r&vt?y`GUw4L-$c8qDgkL=MrDFTT|05*FS!XC+iV)()m+R8u@n^nIffD6je&SswCb&C0ne8Rk~tW!r&8u~f5tVObbGHubBE1MxFxP=aMRE; z>zmAUUII98tfP!eBjZAb$`8S6P;A=yO?MI6h~CFj*ZMyZ%N`Yq!MiI~KE;CrsnIW;S|4AWv!|PYUlDlr?OVu$I$t0(87)8`gYL z$!9%(k>24oc;}Hc;d^WDSXIQiWS{QLcptu?NoK9_4{rU%4_R?A0c@vE!5pdGIj$7l zE?kY6UqK6I$SM2z&a+KTyR(zWCHe`9ui;n6I}3YnEvtbAo6z0&>Xy}q+hZRri_eWT zq+UQuRSGS;%)_YC<$wQir5RPr~o8L zg;&Uu3x&_;7iZHe%T?$?wU(9f%-?ht@93V$R$pSa2GA{k#R_!yQH%O7*8xD7=G$Gd zG`ZuO`$UCeO1cbQ*&8=42z5oA~3`-Ve{-y_P~wO4d{ptU)xX(Y|0zZB)j zf;01mE9VPLd#Y_N^qErZKI!sEV`*?&|dqWd48ay-ZU$>HVmNn-8WO426 zxLqQl)?;y$6diiTo>g3Vnby0_>^IWDSp@GSPZo zy;}P%W08K$)Fm;I4RL8`Sno6JWhcIW{NTnqWmo9@d)dlulaJ#5 zvETJr8jbVYlLuCW12ATF1l zp9NNa%@v==?^zl?vedRp- z`%p*07rB?L(yB;0{>)GQp0E2EiHm?x_0-vicV^<9mJe?1S2ruxJXH-Jk1Q5X`l#G( ze~4aozumb+=YBvPwNQkd9I2OIW-pzyk%dY{@+wx-btY_=$;70G#WorXBJ+z!M8c(bFWjP^mXbFf`?t?_)*$Ep$t~vH@jP%P%&X&kBeMoiZ(FBJK!w!uQ=Ba?x z7Qdt1@lm^2lT2ovF+;8@;$ZMout@gji#2^l?sqdAtReNx6L|iEd1s>G@h=k8-=kN76HyA`X|c43ouWzWbvqU*>45UI zmBTr+-$hRlEwjABr{7Cf8k?2o#l?Vyhj4kgbbqfqHhiXwmFI#J2c(LYocQ#6XRei1AE(X9AFMnf?pd>`P#P!u?%S%msjR71;Ns32cIKh zM^NV_@eZ2oLOn9mXHgDqO7XbDKsKl#mYYZxZd$88A%OHr@NFXCl8~*x&E=0WBFCBn`ClsA%~XwxPOd?*p;kD8A=0KOa6S z!ql#^PEoDnE4aJmv)Xe=NL+D#nP1DIP#(Jr!^R@N^f$sd>8zjC{h(ZKe5I?4Ioze* zH9PuiF*?KXD_ymE|Dek%zh8UU$=TZ|-kECeuJd$H$(>Dc%BnAM7|5@iAu7A|M>@KN^|?fVraSBi8GD?iRz;>9FoMCkINOV%+^WasTG zk}kgq-+cQobJkMG)gXru5{5Fn0MlEHE5M<8>MkF89^o#l`R;|LR*d&W$b0ECk4_St^{DY(9@pEs z&i1_uOT&5p{Q%2@FskNn_<}UtKOq)spIyAUY-Pa%Jjz91&+pLHZ_#K&4FCRR z6X3SuJAkcRnLn`DnJYKY@Xs%IM8T@{Hw9DL-T4|l%7lYn%!(gmSp!wCId!TYMbe3+ zzIBEUgi6R&&}M{Y^sNXMXRP)^-EY3W@Q}a|d z6Rp>O>L`^dMGHQ>T>P^n*Qu3c3%k77=W5TKgC0q7FHdv^EF!b-E3)pp_@ix<5O$787dEHE-cFTBc zm`_s%p{rdu57*r~Tp>x(T303nXwOOUl^d|p^`qiD^g$EU%8YIQ`?yF-y1(KhixGgri9PBxo zivTET*^t8@oCP|+I`Y({|0=Po7BH`=!Y1sad!?H5**&}djaH;W*V!^u07l%47roAh~{OEOGit}52FcYa_u64#jW0>~06xzB(!Ox?09<9ZC zQ!jC0Vm+&$QpScB{+_D}zde(YBbQ#VA$5c%h;+{Mh71cjq$<5yi-u6sib6uZwQ!ZntBB5u0 z<);`ZFjU1{a&n>Y$NWEB*~|iBRlW^nDPM<3MC6<>p6B}uzQ5Mfuo6OJVf0SD&K%%a zroWJAi;er`mBEAT9>-y4W_GLXmWHdoHQJ1KoPzuEiLI(qmV4w?tp$^rX@6Ygp?2sQ z*!>ijaGGza>CUJ&xsVS{yz^a=akHl3#c#jdDXOle8rR2%rQO?hRHRLf_qqEJUnbbM ziF`**if8bbC8&jsuzbC13K|?h|1UbAWSnEQdi}X0&JhQ>Uzz2O^d$RAqk8?yda{q+ zBk@Sii&wuV=E$^CDa>YC`67)fBpmFC=>{9jrX-365JAgNtu55ycZtT>CZb1=dW#K6I@h@(ph6KMhzMPsKFMi$Z0l9$< zQ<|>(OGM4ox1#f<^_cyztYZs>o6c*^H{@}vw~l$9$mI>v(S{$|x6}6hPnyLWOBus$Ivc_vpY<;|J%q!Srvw-S&R+}BVkFN# z_FHR*;6H{ElR$cIIZq}F`LMTO{og@u5c!`oUv%5LF<-ML)jtpAKEoLogR!T#FzL9M zI@{pw#2@wNq-EB=5k$-JNSRL>jaT)xp-5tYE1SZtMl3B>2z$K0iqlR`rai}T#YTg9 z{XV|deC+h3!-wZu%kU!my2zkGja7bpFhpD)Y~cjaeb0^}*1=(bD`7=V)q9Q%H2TVi z&SP(7E%{TZEmL979J}6&CBveRA~4J2>rRsU z1wW1Xx6uA~@out;?=|M#ip#1pz_hi;%F~rrhw-hiLD9@)!YsV5GjFy3HH$smH15 z{0u=*Aa$njFnS6lyWHgb>0_{)sBuayh1 z3*MGb4Qqz-*aAii(`QPYPk*>4-OiR(Wh$@@{P}>UvG^dM`|SF_!t50fD&{z`ftH$2 zti{HuM8cJ1@&kO$s%|0YPN^+Nlv2ybg&T$$DNb0s|0w6h z=o3J(GRZS7c92p=(}VunOg)UdhF?eUs4Yk@sF}~AzlqOKgjftRNwSK3FzIY~b}70d zlrs84=u$8m$$(a^Uq|G^g(heIohzd{)?}J!3emIw!N#eLQk?V9252Ay_xmMQg?vT- zFEB17z^lQL1R<%yDmJr@%=ze>JNfhqv=CNJhngWKC^%vgzs8PIOPum#`Fsgi(#IXI zpE1N(#jN6zT2F(_my0~=@ajUwE~>uv3+Wj$l8)@?707snChT^)sr2^@1HpC`zxaW8 z2Z4`TZg+nnGdU)mX+@Ew8+y`6N`-soZia_}`%<)a`W=nscT%xz^27iGEs~g>RPE+^ z!hSeJDh=iVt3_n|1P$;v$L@u*4)Ep*o2#|0i+ooD9fhi*Pl-F3UYcmno_aoVD|VA= z61Q`lQ1g7R<*H>1u;crF|L%R%$N#?`cE0*_K>69okzqADo(%|_QhD{4Q%dYte>U&- zigpiXqE}r1%y<|9V`5$EudmJz2a_OZT_4U5%Qkh6LLx8pe&@ixu?H@<>$)MYa!6&J z(h7}X5|k64TP97y2*M}*b;c~oYi|1Z;Nv^Sf}pJ>y)?y=H$RH=JKDZ5D5R4S=xjGe z85A(8tqgfShW7 z`Qfr6Ae$lvQX;PK>?8glkQMq8K<|r3BQ3kNvjDP|ww#7S{n#$?VLBmFJCvF40m0G@dtZq3FXx;N zNRP4SuK$p>&^Zn~mAAa$*tu0yK^Kky7WmrztW!RrRPiarPIaNJ^0NiCBo_cVI&nJ+}4`CoG$U+q=B8wi$yq7$FyhWu1mBmU)xlNQ9s#@hRZ62pjX*t=@;s|x%GLte0&bqLpHM;A$OWD;3)`(M1Wryeb_ zPt=)#G<%h5Y#<+;FH1F6UeG+AN1f*#VsHtRps7q!vFgiED4_1u->Q8@YdZM2uu# zXDUN+W0c+8PZ7>R^bUsv-)CjdfXIwr=uAm{sn!7~^%h+nJn8_`6$`?Quty#whU6+B-9j znb?JeuvvgSANHxfA(^C#~`Jhe9?Z{$`y^fRTE ztbdpNNBd}jb-SkuOLIa=$16>#Q()xe(GRDnFOFLlx#RuC$G_S8+qKO+SZspO#E?qKTu=Ct33hG9X1!~|NuRZa`~ zMb1}M^?)jN08fEP-4My$o3mPLk9!R9kAns-2+%q^X_||aS_=&z@vjiDLk^BBo`ySU z@3Iq4^9kJs-z%v{T?Jn&=|^4CF{n9rA9c59#=WgaD8YxTnf4`=f}a-#Am{A$FuEj^ zLR?cp7r%w{QsL$%&hLI7q>MlEdJwKkKCa`F=3CtT5J|26Y|y0a4~OIF`+{J1)D1546Ye1!V{xsy=MnQpJuRyx{|ObX)Ij&I zL34A>JHN-0I`sH~XGzyPzaiL*M?|8wGZ|(5%}hj=GMu{>lSGVR1ARG!1drgtALS^C z1!M8v5_|+-x0L!@sEF5Oo*%7#6Bn2y>!E-vSHoy=)TVKaJSvm)F9NbKVlh2X1{)=> zPPN9dw&1DQsI@$E6pIac^cZ>|sZRa%ltgNHs`EdIVaEX+x2cop(Lo>OoW2_bxqFVY z7ormUN6D-TszS^#dh~b=>*Q#Q%FTVnt~F625sUgIO$w%rNVbxX{3nX%(51KRFzvAY zyN-YZeY%!=#cH`wv zKmr}K@DHZ$nZ%!N>TPm_#z6^$DD*77_?>J434#o#G=Gyn3utK;MWV;}JHNP+Z9v2} zE2;R=?8m{M-{-_?<@d@(Luok5H2A*z6u3a-wj5FcFX@BPIKvcWYN?*`S#dhFOFv=p zJPx$LEl$(JD)%5Oep6*jPlXrtc0oJD-@io=0%c*8$lDDfPd~O|%t41vSCrdu4~teuLI% z!j!w62RzJJ&B^$>xn0nXH+k6r#qdHJ z-qm5Bpd{bzY+{>g%o^euXaRCS`c!dTQ}})8Al41&M?-n#Dt_PE)(T`tO3_+oZmuFw z&QOm1Wz@|(M;&r!`63HB-bzd-l(}-uxgALHuTrY+5GMvz)1>Al{Fb~?yd@zUCD(x2 zG{t{Z%t;Eg6n7&&@CQ@suvR){mJ3P9Tm~iJf=b>cUuMU*9pt9sz7YY5&7flo1OsV_ zf=fakZsJC12TsSh$H77SL6#i&3VuNbefA$gPdw?w?bp{Eeeu3uvFmtDL0Sxaco($~ zT$*)HLiqYRR_cCUCaNq{w$A@@=Kp4m8>uexL8;YxL@tS2ATcmcli;5QTA+xP5ib>r zFN}{3CD}tzu?A++IiQQ<<{`>SbyT(pE_8Sov$6OE!~L0*b?IKwPC%*@co}`cENYb6 z>I|e4sx^>03P*?!cQ&a#M zReO}^mLB%!q8-jPd6}5~yQ4We@XgczEhYl1Hz26;o*~y$cf8-Y^U@+`5-MAP-5Kj$ zyO7xu@hi#TiUGvf9H9FNS03Y(uh1AA{^CHcRsVR}WNgLnTr$NxL-*QwUs>b9Z(CnQvEOGZuZ}#bG96lg34LnE5i>6xXn_K^N|A_w!572^W#9(#X1`d#dH{ONSHS&?06z zGgUW$5az<8Q&l(zz{95=P30rQRkR^@#?q9l`S{9m#5GL; zlG_2XMqNb=_#yG3mh9~c=WO@JP+&aA>hBCL6P88j55GbB7i9m=JW5lD1H6^^(dbEtn7>ri3o?dQ??Ayl5^bT{^OZEDyue%kpoJ*Q1!qYgWJUQhq`05 zf`djiSu-AnM2iAnB1TI`D*$d5OoBg`sr-WfBRc5YF_-6h5j!LOD6t>lL8BTQp16OE zUM_0bY)z>A-bh3+$6KiQSEE~7~(iZ}f83s`m^ zpCvy~ncSsp&Xs@;6*(Sv@^^#{CDNoj@Lh5E7uus z@yV`1^tk*L3)Ud=c8r^Z--6q?(O~(_Mmi(RgfoBMv}7rNM5D-wA}9rp(w2b58>D=z+k18pCL0K2rUa@!W?4u1e#(}s#V@~_9F^SzK48&!Am zc1@f6%}BhB=U(!x6aOgoTe(>#_;?kSxUCi=+5T(3&GW6hC0F&pmy=sMYx_=YhOO@9 z6NS7gjIf`wxXyP~$1?L3u;Vb?=7b%XiLMkZ(|cbsn;t{neGQm(f_^L?y^H(V*oig@ zig>~dLT-?6q94y{Kzer%GpLSh@Zj2P_HD+&pVq4c3>now4uoz*B_F))%_kfQk(P`4 zt^1F|n8gEPAp4C%qxs8-y3aQ{T^spKX6Kh;vZmFCQ90H`{8%<>dpm%%R6B1#%r^fi z#<&DL%pte;zFce4E{8!cGDeaa|D6x?i6t&B%Nt&FAvur(tnXkn*aTzs%(1bjUj0$B zO##*})Q&+f0=svR`IkToz8-RgK=0;n52j=!V7e-GkHhxJF$d|6c2Qr1w zesc3#D2*Mf9v7%p;3cqyJ0Ks3*dJGQQzV6PhE!u;vkPJf))LTOd8e<6Q8u8k0Evz3 z{2SfG0*u5N59{&>d#a(EUeXz6_3OFjLnD5mjgY&$?{h%MNxVn%3eWtg)y`8}+&mnr z*X1-dY*%9=azCX0!ZKPA>%FTOD^%+Jz3uDVx92(@(BylTxXqS2EJ`gv3f34(B6kKV zj)TL;!HfykcUYbhD}3=XpJK}Ry)lpqG736Izk;mSZk7<=jD_;1;fSg<;n1 zU}F2OiMEl!@2pq2Mk^nio=}kztjbcQj570>phWu6P7c59=#>lb^q)u?v&%pt3qfG&n2R{!F!o`K7St<* z(!XY6@5m5@d{y-4o_)0?gj=a;8jvFsIMYy?Fjis-rN2Q;vTfc+rG%2h5l8TlzF4Y+ zyBX3Sf&Y9$G89k(Eti=l%Rx9WJ);^#xrW`@QE%LU$WbJ023%YL)Ex(lXTgNbVD%jY z>@cYOt0Qw#xJxo`kvAa;ends7v~MEg|;Qy%7~c-Q^jr z8o971r<7*&@)gOu@Ow{%hV!yuVl^|iLs7{v%;oKc-?qG?{a<^9*%&=^uFEK#$(Ja| zJ45ebO)nwe0dfx>!3PT8(TAkb4{a-n!yjLh?c8n4-g#vY4XFGJRl-z2*OyDv%@Xm< zH31;DXO6_%V^5&o*F_`N!XLEyEVO40!Kwz24HG9Y0hKT+@lS%>Y?&rFOJdXb&57KL zWaIWKCQ9J)>aP?59pv3SF!JCv%xFHshHOdzJ?!Y!KATivK*`?0YnoQ#RVI5l?Z#*PxZ-`Vz1IV zShRX37TA5Q(9n8RWiaFuei?xZ^!akH?lt*TnDG5eR?+-Q*B zR09hP3oA34`7Q?Di)?5c(?CB?n0RG{Il;0iVS+XLW?c|*fi>FB`VBhsc~qZbfQ
      o4wZ;|%&hd8vvB{bnyX{uO>* zjpo1@Ln}LJ1SvNRqRA5wThPLTbI(?B0h@Ywo^vYb0gaST<*ZV@^J%}g^9F3xpQ`_> zMQpLawc;O#=xDZ>{YG++Ijo*L?x%K2)s{;O2yuzL)(RuQeC| zkUrC&gR3rSMh5;(X zq(u4rw@P{cVQoH;=DAS(REH4f;n}P#k@YI86JaNeR7VhK^`8R$>{jG3KH=yC zzSaH2BE}~&<`$#Cn8E{05!B;qA}42Y&#Wc3TR3%`{Q2p_fdNEgce$lVg5adY{}zS1 z%M8j$wrh%fsfrxFR4Icv+_3zd&706_TUgDF&LmOer+nogJuqnS1%V5>df-%~qvDaF zDA2wiLOouYgCx9jTG#a|Kx>P^1^h!Z{!(A%Q8K@A8J;%drml6p$@#dl6> z0%~Jcl(WJBY|)?2`}49g9<1Nl9;<4*$+aKR;KRuX?xGk%p1i)#Z*K^sJ&CFau;~IO zk-ke=jXMV>{jJr%l`|(=<&EsyNn|T30lz zHmA}iFSP?xysT-$QK&5|6IY>07n{NhS1Z`F>n18;w)xe|c0~UAd6hESs=}{M0Iw(T zDe`>-W4-@Ia^R|TX3Es2Hs%&alhfJvc0s@huhsL=V>p}(d&Sp47J7zO+Xd-d&c#NfzYA2UsUEd z%BZuO6$@wjI9lz9)r;hlNuPd?G?>JGKwZY8&hb^`7u_vQpl_~kSd;$$T z`T}9sDQf1lUTeiKD+r&kO;HYuj*S#bvUJ#YL^>UQ9F!eC{uQhgc5+a?pOwtVqUv|? zvtPf}0YFtxu7vr`zoIm=nU$Zt$g@p3T>jdUKX~-U%_FGI?#Mj!>939nJUMc{?#d&w zs!&o~MDorU%m1V{cGP(8YC^od=2&kgzwz`!qm`m3toH2<6RSZ z;LcS0JK?%Oqsn9!pVMhe9U(v)Bd9ekC`g(aUVk~uAqMM%M5?|HD92}f4Fp-J*2R+%b$>c-i)nYl;I_Sn z{lBR%WAM6GT%j%>y~dsKg1zvz%q)|pkV)C?z=Y7^kMfdeiEqiM`;3q2RlbFd zpKrmahf*WLNA*7SPy_3x)KJH+`%QsBv>38Scy(2ZKAKM)6H90oU*7rFBTUWV#GfeT zTwz`X+h4mW}ftQEboEp|TF$c_-LOT(gzwr~5o#xfEXL zT`ub{h-xK0@^>cH{Dtuq;}wqou+~}ll~VnWAb_8b!(#0=sr)bdd3oUxz#rJ%kj;-v zA}cxV&?{?Ud`Ph11GoQw#o|FM+U4^KW$n;8ou0eQ_Yk_Fa!K}+^f!)R)${mXotQu$ zhJ>Im8*{wT2th1#w_ERXmacO7g~{grX6Le@MVosArSC-1&D>i&W8@?D=W68Meaca9 zekAuMhBq=^i@p*sVAz3k1reGK0o@(VSduiJo^Ow`(Ejn*xl$Oxd9bCHWwwPY>AkLd z7T(6lfe?MIVmI2N{KDD@+_Sx*)lSa_p1^}wkc&Ht`>;~Ma4>JddE>&`Th%EZ9Vwmv z0WxynA2HNJZ@ONi%s zZm4s0q59{W6ykzZ>luN~Vp1_d_EXxW6OjXcFe}1kc^PM7ZU3|l?VT4*fPCRsGRK0) zOhF?JXvK~A^~$T$Lq65Setg29spFtiC3P1tiDWg)_TB1m(;HjHl_K%{v{N0%1v_?z zN}bLjli4@H4R61;2WD6c4&>0Bf=W+b(D{Qw{Na%KQ-yG+NXCoS7J%PYevpU9UN!|< zb_LW&0e>_g2wqJ}_n`T|Tu2XcK)u4((+&mo!j=)Kp31~WI%S=Ti~480OB;^sq9d3w z(sWld@4R=yW@W$KG%=k_wpnZ3U+29EN_m=Ky4Rk|H(o9olJO{?eT&&WM{SH-(&_zV z5_Ta}zVO|rH|L}et~pc-PsF&%a^Po3$k{x-EQ2%#LrT z=6Va7D*XAg7ips~p!5{7x&6EKs|~_e_7$_(1@tINr0FLXVw;fn#j8%_%<`~PkMA>dBrj!b3VXEUJy~3&v z6ai%{wZB7;d|Kf$j+MICXvV`@|2WH@1ucVO1(u&BO5&I60-Wd^B?LT~Jg#*bPez;T z<6k+KvT>K+*GUTiE@Wik_IF-&ovk?g$$yO`gXfSniuc%`EC0{21VOBOsrU0vD~_Tq zIx@)=c$^LG?9I81&eao7=|0=~kjHa|+!Hv1IVEy^h~u89)!!FQVJJwg4O)F=D)k%8?G!1mR;gp&_OCgBGOzU8te2< zSJ37ZDIP;7hXsZ|!N`HGj7EnPx zPiJv7HRwiw zmgC#I9tIO~Y-Hv|WaGuGym-t@=Co^f=FgS{#fL7Mf!A47SSG$iiwWPq7&t5g%%w#2 zM;_*V9fiNp#Jk|(Ij6!}q{KtAd>!=2UsK)yLx`^}!ua6+pJLtkBUTHA?Mp-yEHM3a z%*H&&nLE4(MFbh@x9Ufp`LC|c2J!vJ-iMs*TTzS80vU=GZ-MIHo8R1G@Sn#M zxSu=DfhT)%fK*SYv&7e zDqlm}26K;jNuIzZ9t+3AU zC}BfL>W55zX=i`?FRP|r|>4^jM zuN()VcgkHHoOSR<8_0#D4ap>734KJmk{PtU3X6FVKVr^~B3_K)2E^?Lgmf+$V;lJ}=&B4RTL3Z+7vZF}jdy zD4Wi|)GiGM1>CJUB)ryTQ`3P4@CY4vJbI5)LLmvmf3s#t zg}BZe4PkxvpuHomETo0M4kRoI|Uf*q;QFkskZgJ-(wp7fHUU%O1sd4}s4 zonH^gdOcM@q_N)bguA|Lh2|(n3g}Gzk3ew~+u#L~yzk#Iz$Od#nkv(N?k#DsaWRJP zOhm&5B|-jrR~v(zfkw!T}DJZ(4lVSi(yMFiCEBt`b@!|Z1WZIswghMg5H z`y@|o?%0#LLxDDXJKNhSW?$LzT*FA%Jm+4f)%F+KX@pfEewPXDNz!s6o9y&d(65Ou zspwGyRyH6Q222(piL=VTaBB9C`Li?2*?q?pqYL0pWa@_;Ac~G}%j#eGp}DNT2;4Gc zMbx`dFy3Sjhos*7uAVm%4(3nrW;2D$2z_Sv6)xSEQ~?mrD`81dvDkg@JkKn!4FAB2 znVLSe(YQvm(>*MTzZG2xHJ<#W!19^UHXn~HSL0d9Ps^}(F_=k06l`)SCRI7wM3kOj z_lsMG{z#>6R8!~UgA0h*9)WiavgbV{25B;CC@gSSZQr* zu}WE|Oa>@pGQT%JKD(jx1=>4CtvmGGBvm^ zWT%3yVYA2~4K=#{k<=10IgAmo4J%THRjIjslhBB#@wuQ%)-`FbQ|uP^OF39GKi>Oc zma~<*`x6MX=+hav_;W!yw%@yH@R!TsTWVTmAv+lDl8qu(-NUv0;{)B>B67k^*5HPr zaP?*}OMCP84QyAbe}fDu@bIxikJit9hR2qf6|N+NDf=sbAS2)0`ErI-5$Bg>Su3dX zp^6wj>_3_pKEW(Zc@qeZgI8A3+kJ79FNpA>**!pe5w<5ZS&dHzm+uH)%rEtT{GMPU z9qcwEe~z%P!Jon7Ox^XyVSu&T{(O;qalo7uiVZqYhLKRjK*_TSauM2^&73Fu@_p>FS=lDC|MN|)T);zjqJ1`m77;xZy2*EUDpU4O6Luo< zZ1Ji8rd>JWX7R;lzl!l-_{2{j2giG_Loh5>Iqt3{^W+3!*8snd6-UM`j%jdxsI1SguqvN{aB7#6lUyQByFUbr)PC_xLC6v*d zF`7fso?<*fl~k(b0b~iKP#ki_feQ%8vGa-{))m>`PwI@7O^Dmh&mj?vhEbRq+(=-} zO@f5J?f_*!5xjr+T&e{KG_t{1QaXi3Ps=G_#^e*YQxMaAZgi=D3>$iP#5}pzVgF1( z!H7-xh?M9CL_|R`3S*GWo7ze?(KUbjySR(=fAy`J|6BdQE9)*RhqyoGU{|h zDJ77PLrX3adg9(_wOh>Q#nIHh)NHf#1vHHic5Rke0s;FG+>#sl$)KC#0KkB4Juf zocxSOz{^8lAt3OA>839DC`e1AW5Y(Z0{a?QM`D3$Ivn%W!Pg6JQinbjhiLQ^`Y=9% zY$t#)-s#^9Pe$bAJcQ?-?(XU&A_d6Us3LyoRW*BshB6~4`C>l_Ebawh-|VfOj8(cy zy>PgWrDP(Z)$+!`&v1CscqfjDO+U*T%tsq;RTFyh>ckfKJB_X!J43L^ItKA;)z*nI zn;$?-aQfF#2}5Bn^I6Se3f3lffeeBVJPDF}4+HYr$}pNQm;&icp<&~yhMd#2EF07* z6ZZ@&d@rXVB~WG1=S+Ky1a9XI&^Y#6PniICo%Z89w%u&CN)S_qpN4fgBOf6$C(g0p=gQIi*l39 zlcT|#@X_llp>e=Y9F!4J>=nj(Luw`Y;1+s}v|gz#cPZ}=v0XHHK}3^g_hM2Lh6>DX zii{48C{Yd7aiO{QBb7i9V_~o4d#Y7um_soMMuA(E4lgU#xfm$5K$+O?I~SBi_l^+X zsSh%7%{j?%faov_qbkr|CoBa_JNvvX29k-kIh+Wc+EM6HJ`x0f<<|yP0=5RXZ$%nU zYIa>?rI_*LVu5LsxS)qPKu!@s3Xfz% zv&;1Y>)Xa45r6h7qp&Ri!#3?j+*`R=A{#Zm!>VDP(M|69JE5OAJ&Pm-Z}?jXG+731 zzA|Jf*7R(RsZar?7#|2RBz6%MqH)v>!sq>Sp_%N!pZQzV4&@fzj$x@>rj)Ql>$(X= z`2ud@Rd%zedJUCM!W`B8>%H{EGGS7tGi>^_Zs6=Q%Ff9w z*?V!k&)e4IY{;^rheApmkauBwH8)_xkS^$Yp%!KpOZC|{MbokL9QWCb ze;mz+RDCvyN(Z^q6@`%>uMQ>M`A#x87Tk`8xO_gJeiH$WiU#8Enr-ymkUBq8z&iBd z!}U76SYieE8eLi8lVQ$DZkWd$^rbFfx&D&B*NDo^6zG%{(CXpe1ggICtvYOAz&=Me zo87wE#atu*>(43BS5{lsNr0mCERe5tK15u1x&C~G?H9J*ks z?GEMKlKO)FT<)CT^m5?Nv43isI3age!GSJU`z=nd);1w&jMkHNMac-~0)#j{yQ)VO z(R&_8VrdrgJgqrtU%K5?JOn$mW1PVe|%zHnp$+EIQ1FBktX zM^fkta`NwGtOUO+ZGC>zehgUIQClz8W^z4g-D+^Y2ON7|aa8~3KM2j!N|c{UkTG`g zZ$@%XxKG=NAqL81W)@F$mpez26jP4}MOrA$?Pc3fHdlU9iudBSU6q%@BsyK&6Zs6JNxX%8R8-jeO}?D+u_NC;JGP+us@zMjq-cF5Ja*6Q`d5V=`RhsZMFR`aHD@cQo~u?KQK&Y0BNfFbT5# zIhS83>J$CV_EbFfC_q=Dq;$Re+$XXC>8bY~+r5?Ivay+}FHcw683<5KwB=jvA^XY) z_APw^dIXx}GQZ#7!~aqtsS8`aU#k*9>`@pGk62&?Lu}dxmNNi+^kjT6bB|`0I8}b` zQ~NO40<)f=zf)34(O_(83KOuF5EL&VDr%w(A1815X06bS#ca@wvGgF;vM@Z$?H=&a z4|28P-?$$4CC>*GIz;bsdVt%B;Y33%QP9Wq#dpoUBiJe8}%<d>v=YrES{`V3 zrQs21UH4~MVfrZ}$D0GY68i<~h%eG6w{Dj_v3$HyFafxd5^xk1U}MclnWxDHj`r}^ z>-Tp-{Bb_-4O=Uk3k9AbodLVd^c!lb zgKh4d)mW#KNh*k4KB%D|(R1*s3}iYmlAN}LcO7Pj7PgfGI#5$s28GVbfXcHC&BGmp zfL6`W#q~%6Ac*;8GKpRwqrWs_^~s_gC5>Qf11V~C{Q}tmHmyFn7JMbJkJ`hc;`kfA z1>ucdkf*W1FGpi(3%UR=EjB`_rX|~OyA0$ru-AU^nG6Cdfx!*-iLH}w2J5w8W!{rg z9PXW@2%j6g{6naAZX!>$tZ126ZTHxA>R`nG=P9`8VeTBWs|mj?bY=32>WD#;*Ceu# zHZJM4=rwzNRJ5^iAt3^w=;(k48T9@J7$K+&3>eY_dq7?;Pq*= z?-5BDDl!n`vtE~$KwUWIWOyu&sO5yPVnbS;=hpX5@81a3kV^bG0mo3|-i`_7m5&j_ zor(lm!Hwcq^_WAvZ~e=vts^)3V6bUGbmh!UbrfDn9TpmWKt)(lu#bE7kSAY~bMMbm zcD7zX50U5+gP~*x0S4a*R1wXBb9Q4qx)rt-r~klGSfwH?0d)|%eLAbv11fStZo*?~ zZCAkQF(W+o8gXG(brD>XH z33B*WpLrei9F1h6poy@-}_FH91EsWP3=Ol|(Rr4E-4|U%5Gu3JvBF!-6E-c)F zBpYS{L2lf+>`SW^|IzeLn<8XBt!i`y_a;yq@x6Uc(H3#m|pl zE8>0}x}o`TVVP8Qw6fspIo{usZ5M+%hIwGDbl6zds7>YUaviNkBSi8jS(ymr!YdYd z2p{CbYsdLja{SZlzwv()OOD46`YgkRcKo9cH?$w0{C0CVK{xa=;0#Z?b@bDSfz^H0 zdw3PZ%8Ag~4H9yV`VaVkB3ok`0Ql9P4|74Y)U@Rwe|>&5`R?|ezYP57G^0>O_Jp8j z4+akk$~MqZ2ta*Gvxa2vd|+Oc)= zI*T#ezDm@pjkda4Mm8W!zcr}h zr5v36`@~uSN@Lls9`E_SiBa_6p)5W&OD4=pdNdWWdAEFcsfvXd)D$bg}9keesD|Y-3#6h z6K8!X933Vb@1JfO*CGP)t_jdg( zsCOl`pWk2~Nwb*Zui>XMDr@#XOw1ZTKA1!X1DX3$_k%xremJ+MFp;#dtZ{#nt?HF* zChmM@w}cSwL`TSd2ZP$|kMD?LzQcLb>31oLM@%!auwe)O>AC9()~jP=rbi`CBJsp| z)k<+=V5*9#Zd;Wi9DgVn53VM~SVnAsC%4=`E>uKufg9iJ*FV z_16clPp>E+m*+2{aR#0pgG-AJ{>&Z_@ghYp3*6bZ4iMPPVSH;VgoW`6OD9VdR-CP; zJg%tje?|qY_6nIeC@@l+a1yV_MrEG1@WZ?0-wR0KjQL24ZU%48K>dB1BNj2qAsMZJ z9ik^}Ori&ONXg4Y`XUJgl%1l0hMlQ4O*6|7$#_B26R_HQV|y^o*7?8#3{5?~KvF7X zvg_jSoR-LWI153eVCSR09kZM{g!WfEG$e#UbYRk`gc~szD7&Wg=NQ;hBfGKiaq{KU z+m@4;^z3Oc3kW?lF5G1*W4wGC^%tDCwCN<_sj4>^GyLiRx)0>|4fJP&e10V41A%E; zO8CtODNv|_r3L`GW5%3r)H}&Gm%WUU2AGxmd>c{yQi#;Xp_#s*rF)0KVj8s37D1l= z9p?nRJaQbZCu!GXe``{RKl1btw~Q6~)KV$nqTwJ1DyeSFh+E_ykgYIDQFa#6Af+Se zz9K_J(D+5SZv{nI2Y4baVN;GHsAOPU#w*6PrEbvlR^TIlmL~9;*ijA~R+h~vJRnHHO$Wx8qUY$`nwbc*FMC@WznOvD!@o~N*|eZve6J1^y{wa;R0 zP&;2`0v()Dl$L;8<9Bnah-3jmk|^YULFCWsO0vLS3a$5X%k_kE+lH0Dw|Ine)*$M%<_V4&TwAXv1RITR&a*T!jB*T6>%s*q?jr~F* zlC1+55M9=zZNcH78;p3T@bXDUtd3?fx7KqMk9+#4Xua{$B!>8pa)ZGOVm|lMP=!sL z=*{hQ(v-1^h^;PnXgq&x>5?!Vwb-Wz%hhx^*^;bY56_R)tooE^9P4{T8b>#94!~F(1 zFr2uyI|;Ib5Xxv&YwjPu(f(43V03|IfvRO89?NFlY)(_)rT|4t$#;{7!ZLMHf!=oZ zBP^*-#YkbO%^H%qA$yDjJ-+>ag~`$fDGmw)G!}^GRpQG2oV6iI|N2ETR!ZWfDJew+ z7f09eawpmA$`76R*J0!7ocv0YLu>gT>z6B+@-WM%&PVo^mlGK+_%E46V(5``d>tqK z?e|Z}bss;*&_&?)YGb`IhtR@clRHa=QvSAj$Bj9QN09g3}g|Exp9FXQM-PX^Y0~{Mu(` zAiJsY3L&B$Lx1eue3K65t!B0;r&-91l66q-u0zUqg>{8ZV#e!}GW?H3d3b7i#l_nP69?&9x5*;4TqWM+;=Y5`9qZ za}PGG3b2C~s^(TDQWrj9KFoj1mOctdC~^JaLrSkDuhu8{XwdzBX%}SI(=apt;_b<8 zdEjlkMeikqA8!Qw6ZryTACr}v&+v_uWZ_|XEg*}boS$cq*X7xtD+B+skb>Emw`aI< zH&lihFi(0+&`j1H!)%CD+QNld%eGtoKcV4`zuI-mkm+mXyoOMR!SRW*JT_|7XRCaw zh*pX=7&Ya+vaJXgEfFZ^VryK;I@?fi2JmYvj;`YmwI162I9)N)YH28&`BD%ghv7>H zC3|ihWtXWl7kzA$YBHV-en1E7-+TRxjSiZpi~BO`A#~}mJpiSvN?>P4j+*NxF72@ybx*1|>0gVQc6RhObrafRPz%_Lu}wt20oy;RQO z#OG4wp}_deCL^~}gWjAIXIu?$YDM)!;qno&Vr`$%2J2$>UB^lkh6u^)L^NXqjJI>yK%UZmA_zr@i82z`kykAmX_8kNp3+08>)XO9nR7^VnTW z?YDw*bIq@;h1RsnFb;^}o{)q*|7b|#Y*zXLWr-Pvu+Gu5_kzGAn^@CuPY7~9h&L}m zOql3i;%d*MIO1tWszedd<`wlpr2REN;@8Hm+@1XC2x=6Jk*^L?=Wy}}LdlvE9EB*` zP>YkIX}!f%5()DuOX0ScpX-dE^~&y17rFtq`{r^C%t|*XFSzK&C^(TPFNK82DI75! zXKt-l9`Tm8dH;Bc*$cke%J^fXyQ<`J$oaC1cGjZr{pOMeso9>2$rc{1#4%%bWuD2= zLHQ_Lb{Pg{NAh=NH};FVZ;jV)S6gE5oxSt={z56=vja0(tt*plNfs3QOG0e7F78|s zyhU}>oMZlzRpdc;`!9vHhG(R+j2Q8OXAkM2o?5tX;rgdA4?)}X?@w-S9ayx`i(De-4t?ApHZy)PWfaL3~ zUdex~`m48n@@hll+#{+yg8#_Vm3B-_10;j1(4iKj( zPsK=pmdiSHgAF5hwhsE%;T{F8N6iIDtnf_^$U4iVOIq=P&;anl&r@5>CN=~lzGYN@ zzDaLx>xp_gVWL=Efj#jqE{37RQNH$`v4SHc&$}2%o7oAoJHZqWlBfjF|ZP<^XvK& z^OtZ|ZXB0Bd5b%6L|z`k#5%txs3~OMejYumN3CE%n!F@OdJz5CAZQr>#-#b|3+q=l zh|C&u?sfe=lj;*YXhw+Z>j;Jy_1W!Vp6A1|$3+JKc{U@J7pQ&#csbemFMkN>!^hin z*gI4;DQAF*(P}xc=#MR5GA=PsWMFGqCeS7Lo8u%7celB;D~K{84Gl80qbb+=?%(yc z?6n39Bj)CO24&yOhAt{GFy@jO`6%P9v7ySu2|5LiQT=`!{RG7QEC+29SBhGHG*-9(*%8IL z+Q=0ETDsAp*u`3$aU9zQXPDPiP^P_ySFA9|qO_0)q3dN6#@tZ?+_><(eKP-xJIxu# z7f2j`#jeA=SMEL#p`$>ZNVcz}X5kNne2u0uio765r-&`fk0PQenm^1NDNiu^#XaoU z!R`INTeliubx;0a&7)0xo*J%X(|G2?n{rY8LU2w-g7j#ZOKoG}Ye@OR)-`><$JKt% z`8xJPBbYT7RVoN%am>iZkU5F}Z#H`|WE(@Gd$TGWG z4t1GK(=l8oguBqR6B639z$bR_M;^(^>kcI8A24(bHK(QQfh6ZK;7*bcgVc1);?0K? zG$?;NSk}@ma&*w;DYt#i7+5if>$7ulFKQ|2_kmp}{1Z6k*ZS4TYhI+^t$LAosxue( z&z%BHTaSyW8hJu?Y^qU&lWg~_0pLz%-ECp%l!)h zIT<>fP0vmH*uHoJq{%oXKB|j41s#?3xQq}-xS&1{BfZ5pkr*D9xezCL!2MB1D)q|L z%ar{TONcJBVfEW9X~Zb9h7*au&iymMdq#yKKBjnGEj5mvh1u!kT00pXosJJyPh9LT zs;b+2f4Sq@KKcWAopmrBYqQfoyEF3Tcl&CFZq7J>|8A9G85};bkL93;m(=v=;%pd_S{m zY7X1XKGtjp?PP-Cl>rV!YF1yV=>n{nyyR(eg8%ekb5)&x;f@~G>rq(p$Ac5coRtLH z7n%qtQ41G|=4pxM%LG=A3fcr|E%M0#X`%~|KADv)#a=$VJE_{ZJMS}0!MwleKKqxU z4nX0RLuFz%TbClTXp$+Gt;FO^U!93`RpFTlMU9^T~q*6aqK0aJ{n zO&Uvfqd#0Doj-CvBihk!)L%{>OK4SXUVXjR4-EemP`b>nw(kC+6YQJG`KtdsFECv6 zATF^>f?48SO zs5=mu$Jc3KNk3h4Tmj>RLedO!MF48ff{6pyU9`r*^i8g>pzV4PNZgj`J+;VGcJc5< zlDB5w1W%%wOy!?it1}$1K7@BM=*#0+VIg3CU45{397$7rmo5zkj>3c7wqKJ%Qut{RW1v9YRJIP!%wsI z=nJFz&OFAaGSI)wycqF__JQ}{zb|{<87~J9Ny42CWy>ijC+P-*ws}I7?glBP1UUl^ zQ^n~e>~PiU{;j-vy8DzOs{m7|32K-;r?CVY%xHpu77F%MN^-6@oh6&>ArYr3f3TWaeQ_sPtG|83`bE<0Ux?k!S|R#vWQRMGS}pt|yE$GemHr2aa7@4=^MkV$~$`=^RSKrXw=NuEHz zAe=({XnovVaPcCD{njKZD%%asOf;Ip;#k#0-&Qa^xUjgYx4YkUVw;oa9GNUS7yW&r zSpZ27?;?*6Ual$3*N#Yo~OvF~$i>KsVz^Q{)zP`uFzrfdIz2Ep6 z$N^_~Gv%u(Asozk0EzL>FAeVxrnkIt!TGy(SDEBr;wEt7TDdGkk=kUeG5Zo|mjBeji@jR%d+impb>2lS%<;X~bb&a)=>4d=h(S0GRBis}=N| zGnfVvA)J}>4K#dL;Gb+vqVdLmY)K30vOw=MX;|qa*}^XAbNmin+suFQB~!~mpp-}b zRQEynq3xp(H;T<0#{i$UJDjFR#A%5!#gL1G$s2kwoiTMcBjhebd7SfSHA6%`3Mb#g z@(COOyyN)e9C_8D#y9yyhQ?nCVQ&;E)-6OtC}`XLWI=G_k&MVkfPPj|$+i#0x04ex z^By4f5Rkb1(@^zy_`*yutGEI*a-1rY`2~jVAvHcS_9pfpK4H!E(BA;VK7nI7tt$p8 z=i0pN5ey7a9q4eK)AKUE64tqmq!?cZp)*_=o9m2v3z_!yNen%Q<5ApDJuTD@S?^Ea zdy<;%QMDK&CKaCSm!_#=5PDY2&?dL<*m%-2;~7J_;Bn`Be3Y!@K`!Yrrl0KEf@H)z zHmq>G!86yGEjtA4jrC6qaY928L5#Sw{#U<%6G0s|X+%&?ZV;ZR^B3$)I+||wE(pgs z32baxj5P80-kLrYnE{V)@Z>9K6Ofc~w#uSv9prf_1Z91&^f<;!s#0|>XySyL?-`3U zHNokbKz}EqCY4Q<&T=~l)H?#pAS(;bmsd;LfVmzW)U%D`XwxnMKPr2Ac$N!QOetoEOvgv*m$ibv4hI5`$v}?Ps~6?MWEB zC)dFeD#QTr=y!7o#h-c4Tu|%#2j%|nh~-D3*Ibo^b3n)OgWua^4mrXvbVX8iY|5iz ztBqh#e2xDeR!VA&V(1N|f|Vx+g4%XLNJOyQ*???G3EQHhA2FP`(wu=-&2sNAmi)=F zt^iYK2l+lCmmYezshZ;wNk!sMqI8E!5kQnKS zvREW!l+N*eJT;1SPPq-adejBwE%t4;l2nK!m{l(LAmmtB<t0SZ!X&OD22hFS*{)r<>;q6J1^M`kpxdrCxmztIbz|JYN2n zx@j;K+nug-NsyJz%%39+5jO>a;0NE6U-Vz^5;5PGy1p{gIPx=%1QClGMqP z#ba551jX*=rN;&L`Jsmh;YFnNEgPU1qR7r@s(M8pmjxU@Fx-fb;e>nwhvG}6usNxS zN9I$f{sth2o?Hc)|~Iqfb6%*?-&ETZ{Yo zkdYhe0^B~2pwHQX+_q386wJ6czTn`=n*grgo-5IUB|$iAuQx37al>y<36S|m&;lAh zCGjq5sl@L)r_1F}nv3?T|CxA@Iy9fQ|0RxyHL}FnIKme(B>@?Z4kEZtdk<$$sD>_1 z*T!^uYd}kD1Y9K9Uj4>^Q6NM&B%Q=^c^l&{54v4F)dT1uM>}cv+FwGH*)2|@1o}hak(TO$(9AP! z%zwcMy9083?`HDd<1u>k9z{oD=K(0@zcj89Z!?bMd<6fg)}L?A&Vt;5s(WcTziA>Nw(ZC#z2>Do9E1g$LZZ*z%ulB*tMZPk6}-$XzVm7c?Jo*vbr6U3x#E##G63pMfwSUH{=9 zUd~m5u9_t~QfVjnrx5AqLM$I6Gz9%d_UkFEFP76vuI;5ky7kHYS>D6V1i*+6AtBcp&nu%en0re zJ9n<=`n6(9hCg3BXTBLrQ+7DZ>7vf>(7FQs(DL!59JIPqbmfb9; z&vCJBcNroC1(Bl+h6?gnz4!<*CZPbr^04x{*6M0{Me-_*`wsV`+>diL2|tPdZtE)i z(~Q-a%gt>XM$Di_(IFV0mZ3yt*KQw1Z471vsx=f;(zjkec;Q`^!y^%R(+8}aWNaui z#049Om&?87g2oUASnO==Jf9grg(~okBdK%!0Xdd8sc4ZItj-C+HNu^~2Kcr)3})f{ zy|iPg^{*5&3W>zsT8ckp*<}{!`9_waA`sX}G;Q|Sh%A8#=00#EnTX{zA$ubB zxFMq~1AzH!=qD$mt=PA37ncjZHT6w(9m|)HHSgr{jxs>B3tu4!UsJ??W3M)W%THVb zHM79TF*KIPZ4SM@)s`45mal%)dp{-plGv7Rd#UoLln}!z68zs>Z8|6g7)afgzHw|LDwl^45 z4zMfd>E)alY0DN!_zPCTj<~1;K_`v6O^ToC;ViRt*shzpYa7?=u&0T2Jsf9NH`=+C z-_vB<_}t(AaqX`MH%}&w7>Ic^$6la3{1^%ub<*YyEq>;0@}qR>A;%d|iXS(Ao!9T= z7mEoAxi_$-`H}Sx)(jMHmLMMcPPf!q66bN!5D~vzZntIvQZQ9BQxAqpqd0zj!AxaS zfy8iaYkw6<{klo=(lcMPRcM-`@3GJA2sHK&vc%0s3Es;IQ4Wyz7B(mIJhL^{yr|M0 zeA(eg{@nd)VMDgD`jfx z%@at?;H^&KqgR%j9T^p=-`uy2zAhY_e(sI$K&ay~NkhmL5vZkI_`9o@VzjY0*0!@h zfy-C9lwO7a-Sc&#DuKK8Ev*)?ceWBGmv@5AE5IcizMOQk4B8qq{g6pV4W=@tP{yih zO4LHll|X8T-3G;O2ydGkfNCQd$@Sun6O%~>i1^Vm+XUx_l@FUQJ_6)hFEJ9TevxyIp{t8X$kJ5)ke3I7;XKp@ zqI}y~naX0x)@q=!4+3(_y&)=_(91eWvQWA_MG(68>#vFH5j2Zm7&wNTCyHXN? zX>C+VVPMv>wZ!tSe03kn++$#(EabSAq&< zFAd$Sw03T>$o+>~ba2$^8#xK_Y6yzK``X$@i~p%d`sVA`JzMPoV@H}$hpQwXCPHFKmXZq(QrvQs^JS<_n^I=(*xWVr;`;#x8qf`>t zN9S?_%MsHic@M#x3=HCJV=UdJXM|Nqx=rB1D#^szo%KkZ^;&??y>-ide7k5Y=_^v1 z3c5YadpI`dtX=lQ)N^;vv4t8Xs5sZ*a3#lN(CF&%&#HL$R1Se&)l8aVdcM=FFh$B; zd7(^)EU#VLJs7U_04q+F#3cyP>c8#;`nZ=1-sZQZbk@ zmTh?xDLUM)d-CzL^7pd8kd@=_Ksq1HErfFB2$yZk(%k%y@5xsb@; zFP;S@L- z^5;{rn8LAW^1$z<2ilXS0fbLGB+SBq>`cSnVdSD9?_D|-RE!JB@}GT43IY*&RF}`I z@zV6F`IvzVq&}zUWpwO@s7=0pfQt4U60W}cw(izQ#4KY`L`3dvCuKAkw0Xay1uH4| z%)!zS(_Ii`>ge62vF=VuPn4;l$l%QN>jtN6Wwp(eP@C|zi}uBL0w=@AJrlIIm{$Xv zm+LEm3#FTPZ9SSA98-pGNlHA_OEps-%cdOMj~|k`@x%|zk%fGE)16aYu7z5PbR}j1 z=PBXKbLsr+XzYiedDMN^jP=W-0lM0A`iMi}vVBTR@H}wv2~62rYg3JXD>5w7$(EJr zaKPr9{GStj(8cZR-9>9bmA=5)E6r#UH=8;EZ!OF9LmEkkDV^5UE7Gv?eD9mNQ4PA? zn&1ANB=;O74*xty>R@-zW6*}XWXHBUDdo%f34WsmoV65Y#s!>LFyt4x9VAAHdCGF| z!u@97-`6rGHF8;UOG;{7x@%6QR1w}yR$XvMnDzV0R@Zxc#~fenHrulo399!hA9 zXF*)6C}qesTX1O6L{gUY6KBBUqeW1vQp~`-_p2;4=vTEw=YOXWfZm`M6j^>GQMB!*ptjt`9^e#FrnF9WV`qut%%Ke|`CmQMCL4V^U`bqC@|qO_)YhJ0>12nOG4 zHq%J z1@`Zayq2E5yjgHz$lxav$2Rv>D|`!&a`VkgEQP}lET%Ab#Z#lan;Ip=JvlBP6r`5$ z8JrV3YY)@hz4zl^ZW9OWSv8a>VzkeJmG`^ZzQsxd%Igj~e+vq}HTsONUVU6Kd7Wv# zg9-h7`MoY|&wF^?!bcm|ll_I*XCyQ|H8p=*($>aE zwpA)WFpQRn>CD8reA*a6u24bSMrTKhzpxOkwniUy48*ztsk&FYsid>V?vGq`e7Lj! z?KWqd*Vhe8L~TgfTqDwoK3Y-dmY zrEmnnV=K)otfRZJDuZx__JDFXHR!useOI|%n+y!Z)UNX4#BqHy!WNPA=@Uc$Zj=`W zkx;L7c~eca?Qu;in=-p@shBkxNkqH5r&^hLUb^TOO$1vu>YH1}eU+Y(9+>~_+L4AE|&MNM2 zi{{01el$mZow*SdnKhbN&pn}*?RCvqZ|TXgWKwY!(CZd6PT85-DF|%YtYsWAwnCUm zXY#*Mj6zsqOUUCz#M7T2E~xLlI4Gmska`?oD7Qw#9Y0Z!o~sW=8SnA0i}Eo1!QLka z3cI2_?T+U{|4RkP2n=53TpM6l>E4{u<2X(K;=R|6;O>Np+PU@XOLzXk@`3;WGrf3W z8O*EzFM#Ol0Hq6X#B5KHSz#=KuyyWuX&-5iu)09)xl1g#$r#164i-EEX*a1bqh`Eg$i;Ix zSl!+$lQ$HetDS4V3uEnMDp>mR&YcJ9j04=$0>ofAI_7=C$;-iuw7=|fr8~=d*q{aUFx~$mx@&C;IjXxmO<}p zlM{yC7sI1leSnXSDK3aFOc8pL28w05iW0@Z4p-ROW=a;QI;FkdU&F-p@81ui8Sk4c z;op4@-^Z^={SDEr(iztJKNmo3dj?EDHPEoUehyFvek%U@vhu}!_>EF~9HEFCAlS7f zcWt62i@*-ED@73o<9pn`>+!rHpF0#233mz@BNk8?g{sKRRSv0F)8^)2P6oA|juVjR zitN!`ejO!({85+!z9539SBBnt$WO)iCObPGV1f|Kd^BomV-!5-rH;^Z0~&>S*pfAb z9VHe}?svpoC^hIf!xI~Ya0Ke;*ScO(k`Ld^Uz6E)t-pqUvK`0+6s^xGv$kERZtj)w zV^$70lOteyi~7XDA|!HI>g6=e@}O6US^c%Il27}irTMLX`ef0KrhL!>e%WSBV6|8P zlfKfan?o1)p>ZZS;>(RpMDHJROQV;aL;bUzz?MP3T`SMPTY9?2I7VHjHulWD*@U#3 zP)?|x-dvgp&YSB&bH=djbJ2%f^XltX(R*L)mg(|pDRz;F#6b%8q*~>vUXy~E;k$`m z!ICc=)ym_$Zy7*!*fFBknPjVf#!1$md&hveS;Rv*#1S94eH!haG};7LihgPF(sEr946?ecMZa^5O$n?3 zzm29{v6dE@<8>~YopP)YK8YZLyEejebpD-c72kett}>mHQU{0FlcGO&I~;&3t#iOE?~W6ygVzNrAqM zW20Ix9z0n7R?1rQufazYz&SCj9+te2n>oRkezD9P(0_R*R>TwkAf55k+3nvU?bFYR zpoBSSB}ExEl36$GPPBPDCXbO)aOi%xM|G-Y4TA-E6B5`qT5o9^gB$}#;WTQ9#% zH}KxYAHuw|CH8O`Ej-YHkS_PfX~ri}9F!L0IY%&x7A2n?6Kt1id{}>F=O~e&l8>Ge%eMW&!P)`hOQgN+8%P0P_O^JHyB1xvz;i7hX)oKM?Qf0n|sU*V^eRX_Xv!&Sywx<)qWbnB0p_+JxqUQN3PzsmovjPkx)ToF%sxenJE#7g zn=aYM=Z+u}{D>guB~jph#_w7;q{iIyo2D}B*?!jl5_q!C9B>DH3_CwQ*RONEP%B1# zxtwgyL#PGyXa;%{C7{x6Z72L9Tt;`S5#*?-7)RtTY8+Jl(+!#wOCR%$T}H=6kS39w zX8#U};1i1CS~Yylq-^8SB%bbddnLi$h@UaFCs0vs;S}a@a9M})3U7bvwCMP4lB6~Cc6ZoK#nvh-ryeuW9TH8@5 zZd_uaOxklSh+N8#yZ=ZYr<2F>3?_L|!P~OH{Aft&DfB$=y1z0~S$Xy-u@h{(2>NWR zR57v<0^V-qk;@^b=F}KN-j~NIYjIZiUorm<{8LF=5WbzYnvt8Ed(xIs3~`{Jk_;?{ zq(VQ(A9x`cXrYIl?7~p&9_66uVpV_wMkPSpP&VNN+%Nms0QOZks0(6j>m&|&1+--s zM~$@Y>{yiFQRB{qTD^K7mbjF$qGO1QggVfe%L6$!&h0$69oE|zBLvSQ<5aW5IUOF| zzj`0KO?FQD^6p)S&q4bxR&NA!>n7_-0ND*eU)~Lkic%!q2wp2#%`8}7?M|+($W6My zJ$LM2X%JyXYxs^34HXtX`r@}W8B4g#1w|2bI5tWwfA42?9bm6>$-TOAUk>jXpS#`U3bcWGci z=vD1Gc?A3foqqYxmQOJGp&gyForKyCiQ~ygZ(7f@%4NQxaB3bqt^pGW7@~dklH`M-@KB+;57aWC;dQHJJaQ}KjT1cjnkdE ztRO*n{jQFFPYQZ>XN=x8d^ej&wbU-weP|okL_{}%4UWr`=|t@GC-5XNa^fi$G(~gn z3pdW&#+C>328@+_Ic0rezEvY9O$C$RCT?CJQj3wt&0c7iTA%*c!`CXlHcV#!a@@5f zwuv`06;YP~+QcP|AM(e9TN!Jtoe2i36{h%fPuI;Rt^&gWDzw0F68dm=B1GC6;in4& z!u0-dY0?+MJON8c$w|9HR!ms~MeT=Ks|lpg(!8{TfeFh~eHNcVzn=_B@EEFyDi;8t7XkcT z46-19sS2;!o%PX|NaiWt%4}hffQB1i6E=n$TCibnIM#^zMZd@Uz(s<<2j5O?&2fCa zID_vb{?4NM%ZwC-@BjdR(-nPC>jtBAMtoHl&Nk$1+APtDI=Wc);0$OX7ee`O!_ViB zR+0qBLtmqFc!oX|{OG2+LW}c$oZ=cahp$BjgR?ge(4W9NL)%C7_4cYOqi=5u_M21V zjBr|FCBCQP7cX?j$wtpJoY5+}pH%AaC5A*yTsj0?Naep(xT|wBBNCZfQ|wD-gTO7b zCB$t3BK`&#kp774Z^}ZPRY43SqDltXHx@|cVdGNDcW+vj8n!l=8K|Bby;789ujBf8 zo3)CDxOxvWcFZXS*MYktkKTMHp~wZFDjGo_^Dm`;3X~%Ws6#gU9j%72P3+O$r-r+M z4U`*~hTM@k^>GZjFZ*beQG3o5{_!`A!1ohj8gc)G-`v{Iz-Qn>ZuDW)1}nzF6UVZ> zhi``qDZI{Fra)Zb`U@Ky0}>UhA>%pl3_k=Tgee_K5d1J?+cilU13M>R#^izguC+Vw z60{BrESxavrIh#KFW(Akn(&)Y>ahr_UvRyJ7KD3yKb}iFe%@rf4wl|0qeCUuB*l06 z6{My8zZ&tK`vlJ3bq(19&m8T0{31yuU-k;qD0yxFLIHk!Hlpgg1mf7bR_K}7#T&A) z_jih+b})t4kV|hEFG7(m`p36AuKid`?+YIv@MUy+b#8ZxVgudt542~%UkhP~(x*hM z7X37PXbPl{OksVsfl3uKK4RCL2$!k9ocnG)B!vKRcs353xiAuLJBOr}P z2?7#Ix1iF@fHcx6sid@$(nvQ5(kb2D!_0lJ&;R#+oiF#^J?EUg_u6Z%6V!*!3Q$}G zj!(XAGFd?Mrp0Mw60DvMZE2YG9s=?X!v;269`*K zv<2@wrgv?u{xA7QHh&g?pk(Em-%l#JXp+n%X@nm?So_8V+Qfl%8F=LT$TPbEx;mFP zPXM`JHKYX|7k|TguEYxZ(8<$p*@J&!fnuE%{JdSw%AHimSA2`_ds|f$Qr*B)^dFRH zr6N_=(N3y-U2t(HN25bnRHc{9?L*RZd|epiT?9cUvC#9V-)K4gVruJ(!$X%4A=$-56+Ud+cxa+m71uF#=`s@%^tno}6I#`-~geU~v=vlYg03=p3 z_7F{cP{Khw=8_T^5@D#@D^#9l=1NgWG*aBD_1r)Hh5edE0zb$_nP;f>gzG0Og@X4gZ`;mneim0#uTTE4e9;&xr(nHMT!$cwVB40F});%^@|?)<&P{Z&8r z;)m1~EZ1l`*1VEHzKFyB?tHne7tWMIJA)N4<3ZD z{>87}$hk4fxggAP00W^D7R8*@gx@*d)i`BbzNSl}m#4;g8xIyI`L$$4Rq zW6k*qm?fx{MedP9PPMlSDwyrbx0v;su#`|F*EEUw_fO6*-TLFVfp1+)Q$t=RZF+SOaXhdoa5k?OfdY)%=CziOf(eu=KEWEqpyrUs-@WFt4 z)h~GVHm;tUnbt`DH9lUT9oKsb_=epQ%PK(Un@xLmw+?j_Ke=)&9-pZnTj>Xh5_vu7 z6`McCUMxl6z!_CfCGJABz-+h=`vYf|Vz$7Pr9!OdG=|V+bg~Ox)TpTyltDlP6X@=A z#|+m>hpAy056nXf09%p;p%7-%#5m@EV;$yP#Bmh#`Aq@)0QrFnhCmVh@>f}Jr zPt|mAS~EbEGLT9A<@m>cWFsyZV&$=Il-un>K{Fz4;pQZYKSfDI;5Xnf5Hb|wbd%l^ zb$)~QD6)U#=TY8w5%RYv+k0od8gyC|ve%P8ufb@*(!Y(^H{BZ2Vj&~W9P{U>fI_@v z8I_oqO+DdI`@o&C^JN1=1`q9gx*IEZ3-OO8);i$E$`$a_Mz62uG~=v@SFR*$<)#}~ zIYZ@`eJlxL66?+k5%8ZdEntYx+f2&T>3a3cFuXh_^u2CELq;EZ<=JXeZZLA*Q+41C z|91L6UcoBjSe1av!>{5Or<9Izewp5|_o~O(8Us*%5~?ogm)$-Ok_Q^(nE5kuUiYNr zrq@Jik0P%D+1G0eNb+fu>fTzLh8!5hjxFu&J(U1-bMW)jv{d^jUb=yBmHA>O@DWrj zLoP&^X_*BMZFjz{TN3&@l1jRESwF1Z?;=p!;z@}~-?}uO#Pz_d(AEU!(o}6nZjI%Q zd4pGZMQC10hGBSxr1t#S(n~hSac~k&=bJ7B5vThds`+D)EI9Eb)tSI+V>B)nh<_C6 z9xqmft^^m?HnoZT*f$lHCE&d|zK*>V7%s-y*ecJx=nci`Xa zo+98ROdWBm@qO)?s}`yDz;WuLw1_$0KzA2SAp<}^dEe%B7re3chLiwOQ z$sM;gUh6;8eQ;(wxLnWIY+SFIpoHRtrQOJmYhaonmi^L;h}tLi8;>cU4@Lm7u}V5P zl}j=V?Q7-ViXogHJE%lQ?}v$D$Bz02myiSF8SC=`wB!A%nOU_P0LzuSddIvyF0Gep zQjOd<{a?@*Oa>=RCNMwh1{7!Yqj3T~Bve)TA1$XXWxrq%pzW)6A-fnM1Ef#O>Kk*+ zTl-^gt-okSN$!5Nm8PLru~$oyo8U2F!sP4n2I9vDY4=sExqNv6o9UoiFdt=0RHi|) z>$^qb&B1RxqryOTd!X@V+UkQjvxMdV+r5>{Bn^5PgAeqr&97|V0~hmvWLuVd)Cd={d}PnFe2H&0 z^a%64jBjGD+4Jm|FDIkVnj&%=#lIaQ&uhfg&0GaQG}DO9$$vDH_c^b9Diz@3?V}ziT-Gm(6y{RY07l1!vwq@&+#2v;N*< zhdcq5ur;^v^Aeqv>F+FgO^yw^M_cv^HGntdnO@=@a>MHVDiEv+L;);L4rI+wxS98@ z3|*$u5DhIits5c4)MbMp_e2r@?Y#R~tmG$p8*nd1sA}qb{<=7|E`=AZ>$$3afJJ^1 zjfYtC&-^>%Oh636l?auqFu&jYY|Gl`LVm214ZX2apsrGI4f>meGn%aP)Akd-ukX($ z@$vD8vAQnNJ51CsA2?K@`|O0XuR@bj#uJi#(jGYSoTATAcPI=jsh@)!0x~G<$zRvq zSLV~^d+qqp2MP6%r`}cdkTq%HAD$4a+o}+klI)tmV_(C^B(+Ja_i=ARLSF+tCsH+r_U5G=#r_pM( z_jrGtx6*0u7T5vm{brA8FPPp4xqnlv%*;gLWf?MorVlGE_7lJ5Y(HhjD?V-VCx z8=m$q-MD;H^m(E3>BlvofF2qPqP0{1659ddn4Ex0bT0K#8AnvjAo9iq%TgNG49HEJlzg>>9rx_!G!`DE}77sHbViX`RxMYx^bAiymUT*9K<|ZQVeXe6L#d z&)MUz7=i7Q_n@a7JOYE7KZp2Rnq$o=@5bUXoQh&n2^89{?>}bz35FpX!S9_U+sARJ z_IxLDhIaYOdR>6i@Uy#zQkTz)fZ85h$;P+PEY4er5AtOp<)!4lET}Jz!jSF(icdK- zQV-rwOctPT8AEhb^0ev^~!4+Zm{yV6c){9e9T&*9z$x;MH`=VNv< zGR3Wk7yr;~^2#-8+J@{`&&)qRactP=8TLQ#FsQG+ebQ_6k6ZKOUr3zxl_nz*1})UR zYlKnRF$u;fnH$P5@MkY@O8bZcigc9Q7Q8c!97Ynq1t#!Mfj86ZbuD;vtgFMV=_Yz; z#<9XZSe}*yTB8Qb5ICMM{3$ zek9AB{_lnN`P~}$Fm@GEB1*QeiF(5Q|5T7T_L3z-VomM_rh1<-!}{n}uiXV=C-5Q} zft{zNEy$kpYMqcW{8xO?->S-^h5J9yjIh=K6d(Y(qXTiAu;(j~M?IYUVC;sT^W+0I z)O&q|7)wmc=F+c2X|TbkQU%zkBM@gQ)0hFY$E1=qA&GWz{~{cdxqDo9ZyHDl2F`Zn zs?fuD8jaSeP~FHSVUIC7*)L*WT=aP>4$wX9!*Hfvmb22Jf8g}Xg`obDIxk<&gcmI)8SEPD zy_mTQbUCtpkTE#p=rFY(P7*wF{OF}IGe#u8u6qv<7>)bM+6^p$(pBM$& z=F~sd{5=XR!{6^Y*xPbUtb7)CWQ^`bP_m;9*zVr*6o3cb_4SPjnE1(0NY(n7!x3^gzzaq)iyn+GGLbXYJ%5HH$E*~!CSz$#L zJ*xp-YYk`7cwloY6+Jf*h5~L3$(Hnjem~f~*H>6_hu^_wHi$gQ+f^L)sR{3@q(&qB zbZG)7qTaDWfXZZAeKteFyor{HsCukYl|i3#r! z;>B8|JI7jyI@P@4+v@UxhBA~$byYQ*$eR1AZEh(N(v~KnSz^NJysNA8lx7+@Dz`R1 z=Ar_A4ur=^B3#N}Ik8ga56)9IaaPDten*6_gN}RC3#A4 z?cSRwetT;SEi|C`D={zT9!r{Ylhfn1hxt?UZHmfdm{s3rLp(ps;p@m1pLreazB}$X z0JoE@4A?yQf*+S;_RRg)nSe}gR{kgk%#d#!_thW87B!VAHmwE4K=Q`&kss48dW;P4 zsCPdugqS+oZwqp z3Z@2+(3@f>3KZi;A^jQ!HE)}2MfCHUaPl*KMFvh#pey!1D$Hcx1`DMu~$^?k97ZY-Iv<9)H2mKP(l zh7p2r&BIasN7R`8C+op`=mY(+R|(@lUWujm6>=0mL{%xl(^33j$w%!H5W8^}xdS5e zFU+xyJl6$Z2QJNG=_!legFp@xM$ikn-9}_#V#w&DbMY+y@g$?oA{h?d`3n&N|%`yVJxmjqbID_9O#I(#@QGKoD-M@!zoh zue`~^Er_T%dqd6d3hie5vn};C5N;~8hVZw;-ESKt^)l8aZzZqI*WGHzIbIeemEn3x1an_SE`g&h zGGCV`;G-}YhSRxJ57|JJV1@>09HQFAD0we}W}y7+mqPQAlZR61HNgQZ?_A+s+5+k) z9ZjauUZy_Y186(oHEc{~0G)O95!qc#9EhT%3MMB&X+sX?nl2mt_|TVChp?FhwPOR2 zWmSUDrLs;O3bgioLuoO3Yu-=5pM-h)h;%Qq0QdJK@)lxR4E>QL*u}QW#9?|@=c3*O z3+#I8WI&@{(_5kb!33a4MjZaS6*8nz)j;j;H?FTF#v2mF|E)fhcy#)KZepTvxIcH* zV-IekLyn1x?p@vImz`mU=NYYA#u|`w7+LRx==BXvTHUbEq#J16l}O%Ucr#=JE%csz zdAlk|6z&m*vZKd%=ap9RdUW&e-Hf}npOBs98G6la$7nW%NKpFe!ah~#+_Sv7nFnl( zXm8G)huy2dMcy^(V@JQ?p-jAXYgW4&g5ncpKm;>hW%_;feNUizF2APk(EaN&UnPH8 z^8DLzpJR)J$ya2)=WJArL<D8H0gnKH&wf*M!XTNU()^ney7sl&U$X#^K+18zgNpQyCDMWQafK z#kd{#8N@8V^DJNC$Ybj9Om@z{r4)^buJXNWIhBg5@$CCdM7#+6<_$dq6)=w6BWz&0 zfFg{=_qH?Ey>>C2Ve%7fM<w8x8$5)8VOR*z^6oO!qK}Ft!Oi zX^kR*Nfm(qTz<+P*!+c=%998}LcP(*u6q!-NPs??{ARN-{9%OpmXpCP0>&xB5oS{x z%uza4S-j2@xvECqPA~g__eK|f*zma=-gi=W2|)|-W=7}jU8J1wYs1BG$P>f z(sJY*8Qc`1IMu=_CJEqHr>U)6v0cw@lhG3bDh}KeUK4-xgoWS9IMwo#fO9*YpHFOd0&4gHGmso0HsXuIb#VS&|Qb3JF{0wiPSdy?RuDCLkoU8fP4j zYZ}tPc`myCA*Eb*f6^KqH#b+K`dt8PnvDHVpa1yBv89?Gl6M zyUzBSF3EomIeRffEuY7_sIIhi@@h@=UEIpgMJ+tVXQsA`Png+Js$emgY&(QMPE8~E z6Ac_U94nC_6R&KeO@7sz*n2NG^YZY5JDq{}iEYCZ$YP`tBhiDr?eOIj@OBwPr^Fk3 zz+!wVWBd}+8&OsABjRW1`NU+SxIX=TqWK;$npfta zoQ!!~hYnH_pXQPP3O^FQnvG7&U`2uucaMp?WzF9YJZHQKX)Z0bj{&YKaD9>aK6%Ql z7EG;{Ga6L#i!6%i3rBRuaM`!7`S&}CW)ct<$(T7+lHiv{qB}7^A;N+#lJY0F7MbX) z<{l}bX9&SOPzBh#<4a?XjQhY=K>5xZJb@a(({p)VlLf6L6#=^+yE;YcJk^o~FWBGc zgGQN|B8>s~8&9puu2G)vP_BCCHqX||5UkLm;zekPR(M3D{QESBbA>!f3(�ls>07 zaCaMv0_fwv)MC8EYS-}VTN4AV#J=RxTqdAbWSy9;^qUn*hw<40K|RUh{%w9|SxT5W z@K4)N!V<;#_+kEwj8xPv`SK6j@jWc*k35>Y;?aqe7-r@TvS=NX;cY7gSh-1zu4~{C zbGkJ-WEgn*m*RBU8pSJAR5757wG}VL8^34-?pQ-j5LcUj3@arj(j=^OK^P4ByAh3B zDvPZ4aggLtQVn?_soMNYO>zMBTOEEy+Fl_uI0Ztgvwro(VufnvhPE|gyQAI=WA|&; zmdNBHFNsWplEC8WO_MZ73*S-i9y;^OyC$W*t00Ncw+C{i3WM+Gs#%n7B+X3Po!g-2 z8(zA)uEds=jUJOhR12tqqq`h+O)Ma(Za7RiMCD3Krz7;`ovGl!w^=MZcJk~#$~4^4 zP&&D|3Z}ZVglrNF&3gomAw~ekWeoTI!9K)sP~Ymy^) z+R-Fper2$yjs3_2Ast)hFX{co_|)^YtceqqV$+Ax)dX`FT-~&Y>r>H*$XDHNCt@rw zTSw!VP^!(eOE1NwhCcx3vICvQi7Wn3aVG`^w@^P#UYJ^UKyRZhP!lX>H}b1Bu*PZH zeoQycF9^&pQyA51w_;x=9zDr-ZuDQc1KcFIAQfa99xgk`+5|eLZ)7Aca#!@;UXo%SwdSYR zurKnYjG4+d(gt7Vf+CQI4af^pxjRG{xLBW1fuPa#zfH`QAQD6IO&s@j?z>1W*};4? z*FulObn$k@tCyKge1t_It7}tKi-LAX&6l>I0MA!=!-+@mkc%(Af$kJ*DKvLe!YtXOb- zj!#7hV69ZH9qScKM9*#;9n$5V>tQ&Cfg{-)IsjdvTg_64+DbmtvJ@|A+E3gg-%5&<^jFuHnoS zioME;yy>0W6#1(EJX_^+wqn}A$9{%fqPLcKJ6?j7&|qMEzC?0Ub4K6#+k(2>Rl}*= z7yow90zuFCALh1At+;mm<7`w)-6^XQ>jPKyPY^k@?rS9@spmGqt@F&v5=!4pWKU3s z1bvEZn8@a5I-~H)kHmq$vMaG%ylvzy?S`x~lo_EfnO5m^&KRR7GFs6_SU1{glwi+Fg`OZfW4&c|d%ADy5Tep|!gd zO7yd+$$MXBIZZ9;w!NO{HfkbvD&U6(dRcRJOCEoG~r2St}39blV2QIlz>ieOGwX2U`MX@KSe(MUxqwt>BBJ8>ktTeivzJDA) zex+aKL}DvDJrU9UqH|8IO7i-cP?_;j<0}C*3}(VsRhS~%XO*%o!>LInD;i0dpU8s$ zBGwnqaN9g5jdPl5Qv9W>IKi-9(*H_XQn;dZ;^^H^PAQzEj4A5Mw;`I2Y90=^p}_Xa zs|>n@?vOawspPm9kd2a2Qx3mtfA8P@o>6j382YV@M+Zx)Zf0KHj`%W!GQV~eHvXYu z`E>5kCmmxt+x(e9yux=hmM(rqp$$ZipC418Giqtvu|fyUB|_ns*55o2@0-Ye+nFvD z$#{F1;yCIR*PZO8jKH?uZ@D5#_Dg>hH`@l*nSn59T$q3Dn~0~1Dp?T$UB7Nv8Jsek zG;u7GlTcu@Bd^g5bi@7miH8)8K90fXAw_JYJ(+s3tp+CafdM3LQBgvc`zff+wWQeP z$Z7!bG_jrmyzTOC8;iH~HQ^+?v58t5wZFteuYczYI9|;NBn7_v@Nb3evN}2O{uRQK zdJ1cxH*9IGsoie_Hu#b#u~gW+zUJM-oht0+w0SAXIdP32V>~=H`iB&&FEQWrEb(q< z;STNTH@E)0jIN8A;wGSb!#Y_y$s&NSsYtv+pUFNI zfGC}{IWeiNx+ReZa5)b3|GXFnO^7AB`9eog`L?qOj&-%Ed>P_8(bE6K@Pv!Kb<%* z>y!xT$PHJ<@|No0a`7_(-1in_%XTQrX~!EmQF7|cK2{I6Mt(-*N0EyV$Y*o>#pOte zC?uPI%QC{L7$!kDugBaY=h8#~3MJX*y2>^4IMkdiBt5*N_yfaw z9kf19EXbDc%6Kr46sCR-r64ODeOewGV=pr6(Ya;Z80};JVa)3MGsw*c+f=ZAu5iuE zwoi?17UhvlPuP5`8&hDVDOE~`yTEsJw8=lK)hzgF-{mQhXj5mMPsI!$V}(EeyGY8< z!MaYn@QJJ4T%vThKR3?ez@iyAkF%AHszh)&FbBa$dX2*1d?vu zW341^GH5RQDxph9vgJ=5#ZXmr8MZh7gN{E_IKw%l*jToOw~x5B@4r^GTn+-gzL9}w zJ`V81uAY|ga$_gBw6_|+G$>6@W_5&634F-YUESIpuo>}wFS$~}E!M2}FkjXN-moQX zZ}q!0Fq{XW=S$r(6UPpa1gPQ__#)1|po6OB_3F)H^Tmprwl&p>jB__{BeI?O-NPYz zXF4M;PvY9j&*c$J5kBgwIStu>t@?_WPq4AO@m&0M5{*BPOtz!1E@r>?e+1Fbbw*wMi_Uj;4nav9$2&3DWSW*#j)32w_v5 zlew|Zim~5~W1Z%oi8)UKr=@fHO`>AyxZ^fOsWa!w7&aPaE2odNi9QPms`KPb*tg9O zPiF`!VZlKP@%-CWbNtP|5E)^X^Nfb*qsaqlXNjz3z6WP(rP}rK3o8N1iEz4jwWxa1 zJA|R648BKHr0%E82WwtkT=`yEQJr~~!`HS{YSF+)LL^?dQ%L#;B?D_xJk=d)C;C&@ z?{b$wpfFMqkNl|<7K*#=bS2c`K4BShGEcQm4zn_oxSliCwH7maV0gJQ`TL#7;{?U~ zxFBHsN|7hlQR(>!g`wMhVhYF_O4Lo1H(Td*l2)cB=`{HYT+!Y7rlVv1HHpC~Y1o4A zyHr{MjN5Bu-Z{;O!%^oc`|dfJ9as92YsqwJk=N30(vtv`Mv@EZH<#8oXH52b@UlN2 z;z>!!KWKkfczM;f9-qBZ!`jW%*%5Yls8Hv-)?|6)NtC(@Ge^J z5zM<%{SA%7;6e+2756^bZWs+5sG(lbA7V=l*_C+qDt)UZzQM%{m&mnmYGdCvIp=M`m8LFk_5~ZU!s94 zyVWX72&WPP^Ho1CojkOkq-D@^2y)v?@Gv2^_Yue5>2o1Wfv;lZ9j*OeBRl0(DE-wg zMQ3>fncPRt0>(Px@;oDlN*|->ryp#$)pIozCmE78-l3<%lY8ctM*O*QyDRSE_~|_q zar5(6dGlVbc)px3B2VgbVJ+$tYd`U#I*J!&BEO4-F_gQ`l%dEO7nZ#5?B zRL|IIBA{2j-M=5^^j-HKPG|t1aCXA8@rAQiPSGqT&-)bC9%GsK9=Z`NJhg^gFNiak zR9lY1$7rg&A+?AMvI^)}CG@q7O-XF4ZA^1QpLmQ)`F|y8mavnbg7~ybR1hE|8|jC~ zapcDC1n@;6p_h@riTNz*mx0{+)&pvAl&wP@Ughahv#Qf!AhOt%l`W9|^PMn3b8i#D z6A7{xyIY+ozSIv6FOnn+|b%&^| zk=UT)TJC*o<5^a$EBZFz+;giDY4b)iX#fAtFUU5kdc&9_V zR0yK1au`m#WVKiCe0I9w`kIo;m8rMGxuoKL3+O1K| zOuHGaQGp4*kWHtM(TvkiI(@SuidLYj7l^-3tyIHzQ{GF49ueV~mNqEbOmR1@`eP#v zP1)>8_b0AxD+%rS0m5r zfvqsL!9QOce*9w$2R6I2G~aEXQ{PRu+6ZBKv`m zg!856pLb9ZHas{a~lrCFN??pi~pGJEqacoJ=D zKh^h-vc7K;zNmCQY&uUFXB_9e7J~j-)}-rNP#hE7^HunEr3fRFlCMp%KXxibhlx|P zSh97Q`21;m6Rq-1_Suh(aQwijGZPF87h`20OeK8pCCGSjElM5Z!cTlIbPW4DUn1Xa zely!ye(IQ@n40fWus&{0&C>v>3Z?y(cYlodii+Ma3D!ut^ln~u5=rqC^2quVaU0;- z6X$MlfH(GT*j9tE4;-qky?+*tw=V_DBT$4-1wFlIZfpN3WZyVhxzy;cTItw5Yrc6; zBGf}Dchnwku1UY!Dbq@3x-jCsG8coBdZpKXO%1;s$>NV3@wIF(NEc;P41@3ahu`!{ z302U$ZQI{6SQu`Ln-9z1m631uF;F66mNB91H$|Dk9ua(TT|8$R@OqEuE_vn$JLqwC@6ZG`xLl zk8L7comk;X58c_6=4>Yxn4h0Ni9l!L39&)N@eVWdCI3hrfz2A!UBOel?dYXV?aM0F z#%i=U=&@JwiEix#%TYqD3c-75WdddRus2aT5{saTp}V}we;+=t$Nl}oPt5u%ej$MZ{L zJwF^RkYL&Y5s6@g|6?TLqt#JodH1E2sK&*wox_HCJZi(}=O1sf=C$;g)H!7_x+?vC zB+gofG1bMOF1q-Z4&Joi(QOgJPj_FLy!LDVKA%y30oAjfpoIQ=0oy_&U^6FbaAeAz zzKwkx@@}uSyW~xihcN6{MkJN;m9azdczyXia9KU=03|~GP3CX@Uw`fh|0c>vGFNcS zWq%dKXGwdASFfOn&J}+&559_9$wDS4`+FJ6c@HBwwTl0+2}3e;{ZQ0< zb*05RTFMO1bp(?v^gm^SdLE{Yn|w7WzCb?Xp~}|5QI`)Mv+NN=l5{aiINuf2YF-s>}Lq3MUxf zY)M^pIe9=1&+N8b4-Vg{)mWPE2TW-x~)OL*GsX* z`KBdHbS^Lr|DOvGrPI4fwvC7*Jf`q6#39Ic2?D=zs$0{;Zs!cai@LRvxqW%!lUG1P z1{9JFa?rWk^z}AyUiszF_|KCB`5p@_kKNJFjG&=(P{MKzUZLZj93}_rAL#LPtWB~} zTc$b5adv0P7`(q8r(g>~ZI0+FX!DnRZmJvYQ3uS#G-4&uk3r#ei{c}@&`2A*RDMWy z=2PX%zr}%`Dm8?h&eO^YDb7u2ue<5eterEH1qdQ#M(|^{@HVXc=bOBtHq;}RTs;Ts znHi2vuimG;Ceou7HVVgk{xh2aSH&&gEcizMmEa>3T6s3yKfZ`c{T_$lk-^4$kz*;eo>VQ4v%go)RDgEAa(P}EUDKCp;p6g8`T&*vf~I=j?f&^tsN3vu zqVoN4vsjg4IfHngJudvCJ=t3rnYxCUE_Pt6J?&CQ=N!8iI=MV^_`z1nM+Z+VgU-<#C!s02 z5kM(-CjeS7Y6HPnLpc8GAZjiU$N&=zC2UCTw79}+PkXhY1SEFojN#HXV}Zz6t^SLX zoEGmYV1Jp?98y6-bKlLiFkSW8O+&R|G;fw%i^!i7x5r1er@!7PBjZXr93@MxiEI9j zDq&T_T)^E>+bf3DCLc0q=f@tk@A3&HA*+r*ANE-hC7pGqVb`X3>T1Bpw=qCZIT%<@ zGu_-YEHjsEe^zNtE7nn^3f3iL}UqLZomM-{ z-rZDWlRyQO)@z*3;n7#LYCZutjX63togtGQwA*&h&Oc5OxLK}4Wwu!GI-@%*)dS|E z^EG

      `0f#y4oUhuPZeV1ba;>4-|%S(L& z`mCNSMi)bVGXnw!<__u|sxIvv+iS$B=xl5HT%#Dg76Soq%Pau;BbFnNn;NIz8C(Ol zR9(uku29Q5e{i9^qk{$`iNB()+i|>qjT+)qbZ*pCv)DGvzx7yd{0R{6;T4Hc!y2#T zE_YO?b)>O!jg71!>nj2Bo@yNEL{WxlKFIrz>WcX+I1wcy#&Cb^=GN#pJ>SMU;pBJ5 zUXAM_&_>tG2p3RtF)PDtm8tj0TnRt#5lM!Aa0c+qW%wfvMsY>@sf+`AW4Im3|7x>T zBIxNu|F@^P2hrKFBgVKl<0E_hH?_j@L{Yk5niiKL478NxsVD&8k`U z5QsI@eYsFjMmF}f>ru0k!Gv}Vyc^?G-$IF5$J7;k@33r?YJc$T((1I11%+`Bc(>Pp z6B)cIytivFD!eC5*RaggU(c@|1fki=1j9l`58E~!`kN}e`j3;)J$0;Dma6(^Z)IdR zz1GE<9M$|Sx}-|=?`^ibI^ zk2I{G(3{nM`1hTVNXZb)KI%OOl#0>5y5@;=XAj2h|NfhIcffOn;*=-)wQd*Z zCR-Vfw|rM#AaUYb_0fu%AdBp3)^s#Iqz|I?CZMTwruZR#IJ_;_E}M3*Sa{m*i|y2- z$>-e{Ou-jfj_&8ilWwlI_bM_!`J#E$Ah!ry{}5&p_?*eINx%65@`^eK@y_BfH>{9) zwMY{)-q@!+6Q=Xv%+V-f@k;mj)}lIVIG9O;fxm83#{WveD=I{#oBTB;-RlQv4@ul^ zfToQ^q6&^z0CF@u?8vmTad(TL`DulFRgUtvvCZ%@Wm1POCKDk(kehz(Q6(SBO)-g> zLUcCagH84i5s5cnNq(}e-OnUY>{sS|J)J~gbLyiF*W=H`Y3Ly1Pt)dyW;8>Mk)^`p z49PD12-CZFPijA;gDVGYw&fs~c|he$>dVCEyQy-XtQp@T)@B{+{UIgRO^Y<$=HGvkMrvojPS3r^i$W2S^vO<#zu& zZtUo;25~2N2wGh2ajRnl@6^10xbczlnXRArPWjXxmJtdXZet(Xi`Dl4y^c>~0A1to zg3DsNtY5?MF`3tR!Lv`lw)X@o^Mv4mH+)U7^U*`FgQmAUIWbM$V_c%^ z0DG4j=Y#PKWiJg8m>`JGrW_J>-7isSguD!3eP_GvhB>@nBfG5!9+3t;gi*$%HZ`sLgC zvKAG3pug+m7%g!A#PqQs$aA1)f!LG21>Ue(TX(!V(h@5R1LKNz~6*UA2dA zYrXChL5v}<>aY4QP6xDITnp!%rgOZ??wvepbiefn@P%X~kRY1YJPciRP5lgSqcOR0 zfU;5%`raFphbw}$64q4UK?(IO$o7%Jy|^*nR0MnB8voPAI_P-BKI1$nMD?hR$wJ8M zZxg5q`2gc36*Jn4TuxM`? ze|l=Mw3?T0)vs8VtUu{s_+b21tu1z)fG%_7Mvg5mSCA-y{X(~m%JBKz(!5vh3TMvQ zPl5P@PpG!6Z6VgbpLZV5A>e`0@L_Rm!w*9jvy!Xw#KJN_Z1&9Y#catcJ)Cpst8g8*A0@M~F)4C6DN z%AK1qUQoQftoXWcPB|2+RMC)E+4f$&ZqjnnRDIIV|E4hXhJ&Ws`MEtS>?X(PUtXst z_g)1^bF*ny{Kz=0Iz58QVk9~>Xnpxq4vjSpf#DAZBAg7vH=my3@6qOrT-9F#zW*EM zgE6Crt}_K4?xEJEoc-sc*ML>GvDq{p&fSFZnHR5x-`+n#&OYWLXbx{oP_(cB<)2G$ z!lri)4OIFWdnlvaFP^E5p6UYdogSlM@wV1^eaoa3ghJo};KY*)eyZXM+ z@2yL*WVV*8tK;9@@>f_}vK{MxC)-~Hs*~CDhEg352Y1b*l2qVAZilXPZ9a)nZDvM| zuJPqVju$2I5nLBRb!oxS^>f&Ey@zEvzeLRRaI1YUOR0t%5Fnv+uEqPcRT&FTr{+u30DN-T(2Q5 zkr@rz1v&;H<64vQ7bEJc$jm;QSjXbAJRPM6O7TcUW#UXLW$iwN+8IqM+$$S9zT16( ziu3Vl_{$l8!&*smK0tHWd($R@OsRlBX_p`7K`)ZtJ+;949hs4Nj&I+o<-*T5yrLE2 zP65;lrM-n!AriQ>s~0#g0ShN5;@R|>f6ht_#laCY03RjLkym22rW0v-((2MJR`Q8+ zFOGESWCZ1Mj|i2FNwA?PRbEMF>Scey`!bQ+EH+2KJl;C^VL6aaNQ(-Z{8J;kN+b;7 zl>&XR^+7=bXLC(Fk1&DKXA-kDDz^d?s|WIkg>||`?D&llWYgXDv!xAnk*0f%tTxu+ zb(RdD4#Iw~8|Z?pX;kxw`g@&=4~8shR%#JHi@W`%>AQ1uLj(TkYdG&)M~UAc_`

    1. Di zB@EIzDZqWXeFu@Frx&pFBr*-y?;|~;Ux;cSbhx~V`s8QSCq{puc$B*lDAg8%2@O@x z7hj&^%V-pyY_0Gvp%>APZB6q*lj(!tR-s`165dPtQ_xg%XOAGUY}kUUfX}eo2VD|Z z|I&J_kv*-sz^BY}-?9_ub&u%F66tsEv)$R#zKOo8DjI?=p|=gc6?1el&i(XaAJlCaJPJI|lWr^h(0)zs9?dY;XUf8agIADrznqB-zhoUJ?t z6?JBFFB9$=*?1HX$~#Q_)wSH8`?^WxSK4HB@EfwnEz6<-1NJXcQ(nY1j|geRHUGbs zuEQVd|Bv5sI9X?9Rj#vD_Fi{JB72mw_ZCUEvxRIbWG6((j&R5(d&|t;d*1k6eSe=n z;4@yY*ZcW=yNSIC%FSvsC=&`=!v09MCgso8g)T~sbVpjS-lQxwlwEtm_XDAPv|%20lQ(!7Z<Y~*BAv)0g9NlRw5D(EubQ|WwS`gwRdce;A;E9v*I z8Mt=O?_TVJ^E5WzUNuVrgh)(U#K$KoE&TAb<7Oa(+LyRwbLj2iP@;&{{;Xj>e|$Tb z+_)X~w4MH|HoI%&wmyTmWP7- zc0$;gCa>D6I%>$0&~Sl|*bfY9o3qpYTjeK(4{jG$Vn`4Ty#V!lye&3!wgnTW*?jCz znSX)Cqm@@aXO~T!i307Kp8L_{F+@t_n$tlHXH|LCjQi9Qo^Zs}-}{BAPxN?5PXi5w z4ubA3ee*T<{#L44fbEr?X7+4w4g;N{GHfCGp&rneE|u)_iueyea?XO70hJ9T&%id&V09LO3znu<}P)zr@P|4 zpB;r0yFJGCnqc38?N?H6Cqzi4!366j(kpA&e|Ked^M;!DVg^WF9W|&o)aUh*_vw6t z(gIN}76;~Jp`HiQ*ZvX&RB=^xuQxr4rF0w4Wo_K8Ww5EYu3SA}^T4+2+gJ&C??nbDO;7lB> z%|YL;KT*!AZCJIi5`PJB#RmmpOwhuNQikr#j{ZylTRPH6G%GCA~F%l_wT)^^V>d*kAp@wdQ-* zzkibMSd6KTNB^?$VF(MroN|Mc=t3-2yk1YWiNiemR4M7 zvqt%cXaS`0=Hc%?_btc1J(k|nEC+tpmxl;*Zb9`D6{BEYTVo{@jPzte*-+Er$hlvX zjZ6NL6p8T&_p^`-&3@GS9yi*NZm^5%aH7{bSTKzSW6PY;Drj@f?T?K!pY?`j)>U3H^?*6aiUmo)T8iDf@I+A@PyQG9U zl-2l-S6zaJiw1rAz0#*blF~^TG=MJ}fIYVLrSONi{HRG+dh+@_d%Hgg~)Pr~=JJ#rE>&?>7AFMsu&d8~Y=b+}@ z0I=D=+4PJAhe|Ca*oWfW7I2P_sQ&)G-pne2M6bGn8+&oSv6Hwon!tqJo?0~|VEhK7 zD(9TNZQdmd44{Q}Zay^Q+pjIa*17I`N4Y(Uut03q-MquYwnZ7tuX-9EWp1mV*~2l% zRc_-y)>2q*8^CB$B*iF^esGQ4HmJ+8b0vrhRYN=GccY2}ciJ2`q zI%Ck&o=`PiUbn7kTJYKq-ubW3b;3h11hFTaWo^g7FFSO^O&;?F?kKDULI~aTUY|4% z8+%DlmeoJ*3PTpiZblJ9w^aPj2QqP}Ca1TFD^h*yV>LfYT!lwRrRz-gIj2*nEL<}B z2y+&LZgIdAAnYJ8DG!y*N-H>DrNSFg5$3%_boVa1HY`6!T#mbBeKpe&AGe@@Wgk9Iec zmY9`Id$)_s?RyU7i&5}fij)XiZue*Tl?z(Q1BfE}H*qw_Hf-bMDKL5Yuv@|*RnSzB zJxH5ljc|ky4KHlfyFD@LnsK%>>PFPUad!i{H?+ofZJALS<`opA#NTZ4P1#u8@Z&qAM<*KxLk~3lSeKWS+*@^6;~q7S}X1-j|vzBW17s zz|$(Zngt(vohkw>NAcbGoW$)byliKL+2}1{!5ZKtm6vNMuhCL7Yng&0geg2=4CC*3 zC%o1fBEH^A($Wqbr)#$;vy6mUQphyhE7lNFw9<YfrebJb2NGUi_GHBu#rN=09qn+nl{0ZWt`E2@_}*X@ zB!~g9xtT(shKXQxNJh6adR5D>`iJv+vf5tNX`Zp5#&&&2WzI=6HZ%b(T1KTrn8W(s zf#8ZCb$<-q_-t2^Hb}oo<5|d)a1r2C%H&oO?`5RRGn{w-mPl6+WG=?t3u2n!PZZ%c z!!F!ma8=>*Gd8`8WUGL+$wG8Mcjs)?r5 zBC?q+5(h71El=u}hP4E*c=T9(j+2`LF#>a_a>Qx!f*m>o$;F9fCM{zEDlg_i5l-Bt zyVhcSKVW!Qbi{qP?TKL#oiuqscSq)sYiBTQK7kW3$mi^-^pa5tUPY80^uYjA-m2=n z_L1K+d8k~fY5Th)0a%8Y3Bw9Zb0kh;S0Po@R_`YW*^z<0ArB{u6ia zZWw$9U=DTC^IS%3IBG&&u(EPdjq_Udb-8hf?>#>8`j;z>UbKhIMf3KBwV1lv2ykCX zJEuO{nwSw`r8pA6P(VF1!em_=5c`&RZ9WSL-~V|o^w%8%Yhd%GPc;d2vviJFwRriF z2i?0`4UE}anN|7tTo|(ok@&^>DWHQnbE3TYt zp|>t67yYb*ABzx5od~2cs5o*Gwd!n6E6pnDf61hcx+kR+0Mj5Ew=RU6+FK^!e?ZI> zu;ym3WNOjK*{m47Ar9T5P&re&U`aSpEk(VpraLLSfypW0QKh1Hd`rgG0u~^MK{VVM zxypEq6$%+NDoJPfrS@=rZJfvHwVzMDLA~#(IzCk$jH>=4Phng@+8z4dTe@_yXSXbb z6N<)faT~*~)gUd6&V<|CQ!ZqSuycd2l*9NHJyzNhGihlN`-ou>&w(Q4Z*yJgZaMH) zR$m@@(gMJR<11_puq#%yWkO>9-Yp%wgw-8*%oyRrE|^#QC#H?|4?-k0QX*VzekZ5% zCBIt1rW4c}UJ_f;|ByaRt|xfUZ~wygroN-WGn*=*bQ(eK{PjM-faE@)*Uz83dNJX<}DU}@nmKxHex}1n;Azh}1sPrHh z?HxNnIQ^1%9v4~>XNH_kbVB7AZ z*yQNWrTqO1=6`NmX9^x}i2sl;+5}F1F&(~Q26<3~72nFLaIe2_V0SN%>`1vCr>@4C zo#nuapnK;m!Yn!Z)z@Uw=g1sdhCY9KLB32hhTR&MuawT2i>DDi%ZH>6D-Dq_Z|)eQ zNE~j^XbS#7@Bu_#s*ss4rju3y#vvDv`l&=8&XUWYKbj>M{gnG!ica^#%xAaGb{QQd zIp34v7XUBs?LtsC_(yZRt>WW7S6RKfY;V_m@uBr1`MDRqiEunB1W|wY1`nlwq`M!v zvWxqeePWNoot--T*&femkTg2Y8e|Xr+GuAspih`%X68iTR_1H*-BFce`yhe+T3m!+ zG(sc>xHFLN$+?*l&6(5F!-$LlTYBcKhwnM!RgZ~a-hjf5CO7qw2GF6V8SPB4MKRAt zD9_Nox<*pf-SK=5m1rcuL}{2-FmdIjrY5(C+S%(Xb>ksZ>`G%{VDi}a#H>d#VMxB3 zl0MbR6E9=oe-V@j8FJz(eaoKu4uM`8ys724#^>4K(!chz(|_8Sg`vkRo}xiY4iC9~ zeSKy75*?N=ma1If4M%(Pi)l~Ie)<3DxKr8LVaW=#5i<0FSukhU`Rr$HkiI%83q#nk zDJ+aG*#{|;Z1SJ%?=KQ4HOff<09041O7i*=j_>;^^s86OKB|@%#I&gn-WGM+2_nS_ zA}&(!e8(q4;M+7{@zIPPX^c7qIb)~RarScoH*=A$4YjAgb)UbsIA$g5F{7G#W)JYN zQ=tv|(@GUsq!jSdQb2@{E_Lo+^NuN(zo6fe=#~6yXv03OX*f2ox|wau15kC0ZK0!oclVi8I{*` zXmZ^Y_Zr2luh2aL?XidWo-eWBq)$N7rCC`9zctDDUwruYAewx8mjXCVdd?Pu@Euhw zQ8eJktAGjY&k#0)t@o!|Hc9Bu#(A>Rn<5w*{;d7nHZ?U`XG=BF>B1>F{ z#KdGJPW)^MM56zT*%q)r1QhvqFa=Eb3p(n8&Cw|a3csdjc#e?)x%4s3>PdbQd?#-3 z(u;x5$!hh$Yvek>Vf}+g$D8tY`(F_M?wkIN$!y33bX=IXDbG(YD z$WuCzH)()a=p-Ir|FXz=EP$JxIxzZ^LbzqQ&fa@2csf;|Wc|4}zPqnxQ}xLRy%=jXRe?$sorOEE~9({ooU^)br; z_#6jZ5rl!4N>o6IQ}ss>H!w`=zn^j(>%)_A2h#CIg8gPogvzPs+15 zX+cr9-S;H^*$wUvQt{wgW`*5lre_I*+o>HM`j89+=*nIu8j}nl{o)6n2S#}`$L8$& zcQHl(3?~{M1dXhCC7%fXH`r57n9aJ@;0Sl9|lO_=pk9^5jf#y6@*D1F2?# zr-lwQvnhjWyV75&hg97EJGLDN1T9WqKt1$oOpUk^{qUqc=?B^J0`^34;&_zk_~57B zfRs@6UOmyVtL$CMU~ShVjzHNq+EU;Uf37I-3SAQ$yObhbQybbYKl|Cf>-4k2W96tE zji>WByGPmCEBDgcK|_nI5BkY(Jq(Ti_l**8@GX;lhfS`Y#0mdCIz<+#W!?D`wK#A^ zd0^dEZ)iBo8T0TsXF1w-UXaR7S`|BY9MWBnm$oGrBQO?cD;x_mABNkZFg@`(Vh zY&=Ru38I=7swS_3H)?+dZ>B2yObFk+FHBi*!?xqlst}%V(~}~`pU^%m`PZ%IR(LZP z{ol;icir@t3$wOQGhmlGuzE{Pa*OYv^@chR^UeQoDb$IxN4YtLoZ zk@r+c)(#@AB4&Md|AIJdL_t74*gWL<#`;N+2w^+Oz5r3zBl>^X@rEW8T@2Gd_@<)~ z?60nZc3_7yt+`x;S(w2IE-y|)D)cWW~6|5{iE7oE3o~noDMP|#`-0Aj*JB!iSzG(_^6SWPnIfkaFM_R9-v5x z7jxEn1KnJ#N+!24uU++GaR&pmC94?~X6Ii;!w%=@-|4cPSmd=` zV7Z5y65PK|fB*=qPjeBU3ZHDK{n3l0*Eh($=$O}jmt{uTp(!qA_MA0Es@c76=Fmoh z%>Nx2LPp1Ieay66>`29qy%e6_&&eo->I>TcUMWAA~7x(K}jZVaFn44nun z7ra^^+Qmz!OKyx2Z4J|>e@0>$ET5`W?J$l;M3Px>J0aPB2lKNZkwrpB!74{|Iny5m zK{E!3^H@>B|4QE=YVSZWqylbe-}AZViOmFZR^Orx@LhK`=Ln@Q0&2VtfZ%>@hU|>L zwI!RrK8ubs9DF`etGiZU!H69e<6jnB@?KIapmqa-yj65|%wGhoQ-G-67wEliA8%&; zRdaQ8FB6(|S@%x9nHKDKEMTY^{PbXy5f@COdr5HGfA@e}`LvUx57 z!;#6_0Geu*j(v%UZz{`Pxm)7x-`3LZMJ_VPRcwH2LiDri-@o~Q8fI1+&Q?|sTUYm+ zuI$T+oUg@D}%81!OWj{GVo$kH;dFSw9e9PoU-ow`x;=IsJbGfsx zX#!7Q{BG@R1N#E{g)9Nx>WIPNFr37C@pTSra{d4Lv<~(6Q7KjLjhZA!Le_Rb&=i%6 zUL@0?wmFD6>z=sG?1mP7JHQhu`X-^-oboKpeFAY&H>6Ix?eDE~*fi=#_?T}$9KXq{ zudmJjG)FHYK8Vl(^|bqKJdVt@iALhyN@%KodOdD=Ou^KR=al;Gn^F7zswjQt2MD$-(mj zsRQzD_h6s>PNF!B%&)V&E#=NEFg5w3!o#EmjnZX4j^_CN8Gqqo0!k2;1X&r_|fUFcr#5+d3#2C7cbVLMC0v z8g-geqVrhFeJEkyVGdNz*OqrlH>^bXwdkLs4%~uwt{RoHKnJp>R>X^Uf*WRCM5u9w zUrI-2m+x7y|LRt11i01ch|p!DvOZq#{0xW3!72{+o@(!bdM_5^1 z0v{uYaL1L#E%JMawXNN#bY4n0ca-GPi_E3{|56D;5I5fqdfFsedW{YGGAG-hvQ}&6 zw)d=o-o0l_Ul{`JBl6CemVJNS1W(bLmCd{@@H?d>pCQHq3lwkUK(>0I2O~ zhX-E}1_%%y1TX%;bfJq0 zhUk}PNhB8Jj9`BtPfpS1#+@uR?EtV1LQ@o3`?nrGI+XlJfOZi8$t~*OLUWm@uI4XE z>G{4%Cp=`V%f&^FR+sN{+w$&B9;@`~5gqc&I~g8#4-ZDZ=T+{ii8(FN3-2snI1t0F z^v`ej!&8}pNCcY8jcKIg?>|DZ5jqgBOxzd`qCbBK+h%JR8Z>!ji*oyP;Wq@iFM8J2 z1<`Gp+vQyfof4<^aRV^4cVYzuS*jBXEWx6PMJq4hl_t*F7+-=0QA?14s-a1~+iK2z zY+bTE?+fl19fudKLEf_Vx7-Iyv-=%(e~sPdE%H4x`i3o+!;j8~dvDq{%68Wi{3uC? zr3i_SA{r7>SyfGvOR9I5d;m%XN<6TRum0#joc@S!&hsMHR=V3rxtxl5;gDigagM%4 zZHRb@KP>-oC_iw@u2)wjktA(xftWS>Zym`9MQqcIo%MLiTK`sK1m^$NNIKNdS-!vQ zee?QQ)~M*Ra&= QT_VERSION_CHECK(5,6,0) + //On Windows, need to compile with the QT5 version of the library, which makes the interface slightly larger. QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); #endif // QT_VERSION diff --git a/DSView/pv/appcontrol.cpp b/DSView/pv/appcontrol.cpp index 23fd92d0..0f3d01e4 100644 --- a/DSView/pv/appcontrol.cpp +++ b/DSView/pv/appcontrol.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include "devicemanager.h" #include "sigsession.h" diff --git a/DSView/pv/sigsession.h b/DSView/pv/sigsession.h index b4b7f9db..4de67805 100755 --- a/DSView/pv/sigsession.h +++ b/DSView/pv/sigsession.h @@ -321,7 +321,7 @@ private: // thread for hotplug void hotplug_proc(); - static int hotplug_callback(struct libusb_context *ctx, struct libusb_device *dev, + static LIBUSB_CALL int hotplug_callback(struct libusb_context *ctx, struct libusb_device *dev, libusb_hotplug_event event, void *user_data); public: diff --git a/applogo.rc b/applogo.rc new file mode 100644 index 00000000..5e20a8c3 --- /dev/null +++ b/applogo.rc @@ -0,0 +1 @@ +IDI_ICON1 ICON DISCARDABLE "DSView.icns" diff --git a/qtpro/DSView.pro b/qtpro/DSView.pro index 575d247e..2637a9b8 100644 --- a/qtpro/DSView.pro +++ b/qtpro/DSView.pro @@ -375,4 +375,9 @@ RESOURCES += \ ICON = DSView.icns +RC_FILE += ../applogo.rc + MOC_DIR = ../../DSView_tmp/DSView_moc + +DISTFILES += \ + ../applogo.rc diff --git a/qtpro/DSView.pro.user b/qtpro/DSView.pro.user index d7a2e816..1dc0ec18 100644 --- a/qtpro/DSView.pro.user +++ b/qtpro/DSView.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId From ada05d91edc9c93c358df9209ed714cd0571be84 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Wed, 15 Dec 2021 10:45:03 +0800 Subject: [PATCH 47/60] windows app logo --- applogo.rc | 2 +- logo-win.ico | Bin 0 -> 68588 bytes qtpro/DSView.pro | 4 ++-- qtpro/DSView.pro.user | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 logo-win.ico diff --git a/applogo.rc b/applogo.rc index 5e20a8c3..3f4ac618 100644 --- a/applogo.rc +++ b/applogo.rc @@ -1 +1 @@ -IDI_ICON1 ICON DISCARDABLE "DSView.icns" +IDI_ICON1 ICON DISCARDABLE "logo-win.ico" diff --git a/logo-win.ico b/logo-win.ico new file mode 100644 index 0000000000000000000000000000000000000000..881489ad5c6c2ff5329ef2ea6b1627bec75f14c0 GIT binary patch literal 68588 zcmeFZby!v3_BXod?o=d2DJ2CIX+cnsl*T|nM39p15(%Y5QaS`tLKKh&DUk*N>5}fw zz23Pu@Kw(_zxR*(-22@3dEPVGd(AcG9G}k^Gxn^t6oSwoB8Z8J6vUX&3_1k$KoCSq zdL*->K~Mz-1o84hARiaXB!-|VObF;7%eW8}Oo7xtk{@9~kkA=G00J7s1l3DJPy#aq zNlG5c>_9d$I^ko2GS5NKiwp>2XFtk+bQ*##HJ|W@z`+fN#DyXb_+S)`4B{MV1R0Jke1R>H=v02%aDlh@PHD5x9a|@b!eM zs;WQ+jQT(@jJyM1@P|x7ULeASg@q~b1z{A3#I49s|4%||8;odeeRw2KL4?Zyb#Nph z5yU`*;S+*|QA?DJFh9{)2Iw{zMv)?UQMWK0e3Ag~08OOQQK&!ShIjtSM-c%FM`7xS zsSUOO9$K`TFCgJaf@7DawopKn&&WITV`6w4sWvrrT+juS8|KI~RG2z3U}1h#8O!k0 z5z(>2k%6hHWeZgDQKguhFN7S4t>(Z0k{w3kk!eSS7BEP&K*}NT0&sa5nU4%pZNTHH z1(14Fbry|C0C2+`m5sXHLe`4~s_Fp=s6-I9utC200Utx;eT zX&c$kk$ss7d{6p$6}UeM|F89PWFxe;LfD|IS=6^yEhBq?g+)Ew+J@>Ppm|_qRc~)PA6yK)YDf zFTXDTVRe>?c^Z!B3A~8rTvYvRs_dfU{$1!B^#79L(mp`~Cy$GO5Zz5>Yml%9W zp#Xe!_|H2s1BntsUyO$W0=)1jQu^lKhy<`ow-69MAa{LpOFC1@sE2%3ty z49&)hKyz=zpt*QyXg*N}noqd_Eu<+y3+bxRLZ$|^@J%rStLa*d$n0yAjovn90r z*$P@IdJ3(SIzuaEuFz`LGibf>HMH?P23l`^18sI>KwI7Kpv~_0(01QvXlJkt+8L{b zcBea`-I*?EZ~iB=zc2vpFO5L^D`U{X`ZRR7IS(CdEkTFdE70N28g#g~4IS?9K!*o= z5CVaK^5I`l2fT7To`LG%0fW2>7;vpvASm<#1my`qP@5zKt=xpjU_FQrwuV&U=a4lV z4~4-W0sb4nkNks2=Yb$h74S>3f*{;b2*S^UAc8h9G_F7p6HE??!F-S&tO_{+o@h7> z`V8ko-EhZ0cuIh0Q335`1wmq=5Tuv~K{^0$vI0SlFc}mG@NWP<2jHs!z7yal|G=LI zcu5rq(zSvh+fXn+#$@#kU2; z4+h200>%Fd#{5n)2=3#9;2~8Ap0tMGxiAP`$%o*rj(_~;0dtcIs5&cNfENe&TL2HZ zR!jlji41}R`5-u66@qiEA-FmWaOOksua4h%&|g(B0Upe4p)vzjSq%4RAFe#8iuyRU}!fVhW0yF!t!H_l|3|Xtf& zpjG}17?@a?NOcflo#>nZk7LlLCxI5J1{9Hqzxkt2z({M<$NK0@?uMBq|E@L10B0Ibr>6?Z`690wxx|1kgT4h#r;ui2Jzc(Z_ybfVCZjfl2*a z8)*UqRr0?8NP8#@@CcI>Fdrk1oB}03F7=5TN=BtY1Q3C?)C-8|9HG&awF0kE0@kCPF$dD)EoU)K^g+ zAq^Z692N989#xN|NExMo#gEdbJ7zwiJr+S-Bl(4oR57rS*;i36ft!DHPI6I3ko>=` zfvi&~0~99?odA!~n1GG%#FrzS2nz6LCpy+eISnfRg#I|02B|L!D)djaBOTDwL`8*> zRR83G8{naYgy26ZC|cA7Bw-?%j=&%~`mm!M`h(*rA0(joPt=c;k$I>ZB0b?bsiXEG=N*KhCt#G#ttU-^;c{ikt( z5o8$v2z)S6{A|b4v3;P8i6;7+|Id2nLzMt1{EIv1B#?xECn8e_jthXYcES(riUR(> z)RD@_{G%HBI}cnPD8s$Sd#-6H7<}=>PT+nSL^sp$stnoeMfA%KzUi zzwb~5Kn)v!1VxX9#SMOpe>42nCqgv=3#tzvmk>!W@t6O<)sLG1G|v$s@+yoRsQxE@ z3`&$omyf*x5d|vY@6!G@00tIRKK+qLfEFnNexv~u$)CEYdsG!kP#!ZLNgRLuT>ge| zpbSW`q8N|vMbSxsf&Wa8g@LLfpvcL5qz&d0atNu7bm>2Vj(j*#mXII@izIYl?#RXe zfH*4i34j_Cc>sWP5AYvF|9U+d9FYJ~2^=gy4?zr=$Nc}Qi;_{pFVZg_KuL$xhwzc! z|Ih7!%PAotObtjek<%$MFrtM2!6T#<6d&gCsR|N-1pjaTkbEfLk-A5L3QW`gbHD&A z)}w%0fq}~bQj`E|PGn31L8HhR2kfPgF<8r-#GXhQO!Fr(QvAO;cp?k`M}1Tw`%`@(_x%o zZ+a1$i3I!7XklnJ2JA_8?CVwh-?{# z_*P*^bsem=H(@Aj8;0_CVW?yOk99T=GuY?|gN=?N*ytF7jgAx8=!AgE$pHJzPhg)} z0rr`VV4v9q_L+nK-KYL{pZec@>Yw{mjQOiid}X=s#(J zY%~m7kP8Cyf8YTO7{|H)SpmX0gM{)hGBbnd-%ViRgG^>Lkih^Hc>Y}h2|F^3WT5;v z1&~c~oQQPf-|_+IBn=1LQ=bSY@t;nC{C|{B@|pi|8W*^VeUfn;^N{?JfGo=&BJ%bx z`Sc&&9P9m+j{ykq{w5&)O9cE(eyx9a$t0R7+Vn+gyRo_O$|y38LQkpJz>5sK^|1;GCA_CXPV0;*WZ zY&^^pTfbvahev^#nGO^A^Z1v5j$}XuW-y`uRh`G0NDCm)U?3;ye?g-}EL1KAfTMn4 z|49X;{WHb?2PZKwjur#|XFYc~TBk_<<2bT(s4}81zkGj~ufGoKb%Cs>1ZLJ(Ldq=R)rC0Hl)|FKRu%>zLf!8$_%tTR->I>QjGGwi`S!yl|O zqQN>N1K82F0#ZiN{YD&fkzk?H|GE5DI7-6(!zMBX>jZa#I0hWigTx~l=Qj+Q zfKKvHK2n1Oh<^<8B*0f>0sja`&mKMh7z=-oivRmNBnJ81GC)O1jtKuW@<}Dp4S5;0 zqk$DX!32F7(znTc2tm>>Z^%g9cI;n_$MTHO=xu{z$~i99EGA z6m}`ey{+a&s`y~$s1oVLx%)f>8eZ-{xQS2uY(YKefI zKru;hAw-O#XP@t>At^z0)$)4%S`8oG82kQ%aE73|kz3e$$0&^ur1Ns&8yr~AFu5BcrSQO{mPlAPap7UbX;i6|3Fdh?N4 zrGd=9nkJIezt+LAWT*IH>xwW-qewA-=*>#fdmhd&(Va606?L(&FZC{q=7tfMD|ZN+ zMEVF1^}1Z(SF(t1Ph8q)xbC)FMDt1*)2{is#LsV-BXx(4SiNP^qgXNWFI+J=mb`Us zZ${hUceiO+&Z#NWRaBIdZGMqdF<-KCFk0$p5DL=PQvujMf=>hh^2$e zfgX4-%&eVB>zVy$K{|^^mb$%J30qe)a4QrV1k+{FE~AIVRoo$ST#NdQ5b; z4c5ea-M57G0}7-HWoa*H$uTA(^1IY)SzZ!vefQR@$HeNGjNhCtehfS_u(=#t$kF$p znR6sGhR)|R!cNYhoxON8Xu?^_&ZnnLm^Ha76Z0t!Z`w11w$X=vY@52f5uWDw_e%wA z_qVyw+u%IT`#J?YwfD5Msr4!(NjYAUT{5z$&Wo%+)cP#oKKx#?JYEN5IeqW5I=7d3 zZ{<@&aOkh~^x+0~{Y7ENujDqDq*t)KzcQP74tiJI+AL0X3$Bzi94c4DbB%85Rm@_& z&N`bBV0Oq@@ukW~_Ug5R%gP^a{^G*N)Sw~1j!)_LfIRm~adrWRv((dxm()Jv>$fW& z-t3zX(BJ*a32RxlZr>MP-?URK2ynZ{beS(=X3DU~Qzy4}k^ZTb&iotji+ZPSb2F4Y zW>Ejksja04+tDQO#;V7BcM7{46FW~bdmRp|etV5)Ln|NA6OC&M0kRV3)&;|Jpq|AL zLgyui-W^8G-JKks;4RD;;>BC}oi`JAM$$1}d*IA@tLmO&Uw6)!Pw_6w+5GI7uf?sD zn|i7_XEDl1%tLKBnDxens7cNsMT?73hGFOX7Bq%t(vLiitd0T2lr$^avm-YOIp!mR zQ%%d&$Ya9}<6W&iWX8W72BZ{_?hA`uXaB;laz+I|OMiYNkj$R>!(-D`8y5;#@K6jg81sq)aPDqU$cjcA&02HM-TKGa{zz~%g<&vp&X)~Kd(rr+9r!AeFp;$EmdxrP&K z@%2TIn!63}rQ>uTZ>38;FA=%)P2F0((pA21`gLC56I-q=%=~2bz|A_c1>3r4J5nDu zR%->RFcxD;O~NO6iFfZ`OU&4FR~(ebtL5BteO)4Y{($r0)^^G2^!T^zAeMIjGwxEc z@;j@alI*%OePT90>1{oF|JC!M2=@kc{9OA;C}*VCUSjKxva7ww+2}$(Uke+Mg!Oz?7zP%E7-!P2v7)FJ;Elg>9e#t`KBz zc9+tXzcj^!c9ue7BvUe1eWN(-GuhkTo)wDBT9S-4rn&p+_qQ8(4Gkd*7;k+0qLgDy zHt9=x#M9S45%g4)Zq*mO?Cm~@#h^#)B+utG@~F03mI{b$bewACGt}DuqI{0D@m2~2 z$!EW-slnI|Z%m~}&O2Ldz1{D-(h+WcUSg@fl~1@>Yfodvtv)YUheBD z)gan@5m<}CX)Cxd7WO?caRRZn_>AGT&Rfb3cdvy|Pn_sf52b7L459o8hzTX;L=f~d8Su2|e=u*COBEd5@Ege?W55`NUd{A?m5W}!{ zXJt*FM2Jexpi@JMqJ4i8)37)<`zPG~Gb4NL_uE%hJgQ89J%+59D zCPyrOsreU}nL1wB%C^E2Z(e=w4%n{3S1S5;kD5HtlibDra;l?cKFz(u#pj9N!VAgY znnZ+1?&2+PwAtNpC|R|i!gp1lGUIF`xY$SSI)gB6rHMME^SgV|_g<*;Bd_o*W$O%_ zR{n|b9_%+pn)EYdI#igj|MqQ8yPPE7UoJI{&vY=bqHG^-aNYFlLVZBGi1Z`*@JC$6`9=?CWiEP7sB>cvioDBzVErP z`Nkm5-rf6pI7;wzP*6s}Lh4r6{>aiZWP?+S#oz22CuhbS4&KmM^+d#ok|Md zEuwbhwYUX2VatBGxFD0AKX7%*+~rf;ZWj8hy&(Q_L_qX`^5`K>#uba?`uOW)I}~Z8 zx_Xp9GXxGAO7z;xlZ7hIb`}@e-qXhqFk!vfcbmM9M#0U|CHZ*~Rc~ZLY;fnZTMO>x zg99b=fkO2(Ki4Z<27ARiD3rdI3;``CSyrJ@Q zY5?cR&i2PAy%JMm?6(-KFjID7bkNSyxJa!EJ-woYFMqEOgOAYMB5AIgB$g)AQf$eL zVL7gOqtbBlL0f9u;Zn{m3j0?vwM?X}NwNxP`TY;i(YWGo2sUc0<6Zqhp#J>N7 zizH0|AM=~{7A0qrsgb&&j1~pASWDHQqVZ=+gwG9a472U$POVj$zr>f^qtbnZ4&Sjc zB|F^`yt`~dKa?6a7Cv#fplZNaB}k(9RD7)?aX4eck}p;v)ZB4Wgz{^aprGTYIIL^B zGrJ<$Qy)D%eaVwdb#f2Juv@;T_0V+}jLH=GQ*!-a)$igq`89C(geTfoj#1P`5i8HC z)T84f#T$C91-x}%g4Gz@aH7{Og@*3p0_q*50SrHF%A(BKC1)PEAAWy2v}2SNvQ2Q| z`^JU6FY0SQ9FvRe>XRP&-Ia4&N)>CghpUT}^C~wsZSDzZnD$b5F~zX<>x;SPJiDno z@uaxZP4yJvH>NM65nL<7EIcF|@$z_~RHMW*O^UEQ*wk-#n1 zgM|^6ireCi=Nw%#2oeu|{d%U_pq{{55y5=Nut3TG8CFPw_6~ zsmLgPeS1j;HX~8thh=T8-hDqWMe$oKXW7e!r2Uwp5VQKd(Yjq zInV{XZ-&!8;n?zp2 zgOP?=ac8OSRl$&JV8>X1bcE|`GnMfK?u^&l4xiuDd$6sxn7MOu#}sql50XzAd!Dp* zsa1U<>ie2X+-`gf!^TzquFX-Lv}=giZ;xN}dv~mk?gxoE&S?p2mEhdtIlPk|+Mb?Z zU+2qZ_UX!s(m9U8)E}iT^X3I|ulG8u{n4eIZlq8sqD;E;WYf!3Eao~(c5vTA zl8KN-1MwxZxU+$R`(N2t8yr)}HL80qakj_k2*l6Nt9*}`8IEzXBfx39;kYMEayM>% zsvMKpZu;D%RxMfgiuYD7cY;dzDlxLRFb&-*xiu+wAGrF(N~(}G)}{@H3Ge+HZxX_e zu%ByXC-<%#A{&dbT`zi`H$ZQUuojh#8OC_Io+66XPqmR%fKG+Z**t>4LWm~De5Yi{64F$#l=3dnztUi`9@l#`#=4r@otuFYCh-|KD=FXC+y}e zM6DHx8ousUMW#rhm&UW|i-g4`AJCkxQ}N#-Yu`V7q5y3x+wljTw`r_bx*{I+NvQbl zqFKS3T<+mFhUmQ3w*)4|x#t@dAAM`j`5CboOu^kYG2IfwLWl>u|6C#!Kj?bCtB7_m zAH3@1cG}oAN!}?^w48@Of7U^Mg>K+BZ7pT>BK^x|>Bcv&g4r1Za;mfx%8OkB39b_n zvu=fbw9vV>sPFi+MPHVcI<8}H$ZeWWKt4;&|EaFjZql8^;Hb4nx{FvsZ+f*8`J^RF zlXxhv6SvC3T9U_ZIi9YLeCfDy_1eU8XCkl|( z2~d(mPhWp|=3MR~vliP((u?Nu{Cdm4p&bA2hm#dMw&DD?r^#@M{irF3J{4DHpW03| zzPVq+M((zm8Pk$&KGx+sJd{8y?51uo=9jX%GLR+s&&Zsp@MkmrnyU?kNw#A}b!BI>S75APUd!I**;imA`U=|E2G@y={lfsJk=jkP zGX7qocaLA@-&vNiTYvq`ULT(+T+gZ_%URU6@RXq9sc^Vz>DwnFDgAXrylAOfWi0tq z;{8MDV2&5-JnYif=kgzykkUzJr7%&EzBYy7A#|DM4qe*F2HV(MZOoYcT>i0pTC5(o z2=HiLZqRntc)G-BbQea(N+b;HrH)$k)2-iebd8Kt)=KGck1G1+H9j^=JUel2*pbU1 z8NxJX)fdTK4purZ>K^=T@uQlqUPD;rGH&fk9Y5pn-O+~#_ZNDsHd>#~-%R|LA|9f1 zJ;XscRRM#(^AwGIEk`eatEd?y11k-w&HHTl37=-4oJ$B5R6T`J<_|U-TpR!`K&KIB+KBs@;0jUoY9tv z_xvpt<%%9bjh)K%_xc8EuZC6^2CW#vw zSJqt(iO3ZvjKDz?hZ_&3X(F)5ZRI>;5Vvd{Q!TlR&^zs{6l;`s_a>Ls~kCO1GiqtmmYawo!*U{>tA&d-kipsS>+++hS9<%lSrL_SL$FtWSFsDNINo65ROk z?qEGKO6C*%d6%I~y!Y$Xaifnb>t+w{rRDi0JiZ_K3abUb+w`gW&Y@xAkgP=CGj!4j z`dFo>Ur(KX*reMzWx^J?Q*rNCgFlB7H~=|iy2VJ;RFJ&qGe1DL+U!K#&7a-HPkK)E z^NlOy(rCC!xEE;y_k>MKdlbqq%sAcLL-(+~xL$;_YuzJm={lWz^VdA3%sJV;m7fnq zyIatGL=w)15(~efk-)=Zx=eP7did0f@zo{jgXJ>{{eDjE-a~W#4`zza^=Xr5eH6o< zunVYKZ>B2FaU+HubRHh2PwM)jlfJ>_j9KiGc|Pr;YxVfn6Wz36-^4j$KM%_W#sTlu zhE6v_PN~cI-TCahj-Qw>zL3}B)nJFJSCedhvg^IK+$GhjV6Vl4 z7^{gRDARZRXz+&i9DaOnqi5943z=KGgPfq3H`FZ!jctKWZkKQh>w5Y^oJ7`Xn^ljI z(?+EpH+pa-q@=3DJ$Pr_GXa}#%u z<=nvh28xzOA;Z^R7cPh>rO!#dYbB7Kr2oc7={XwRemQHP)uO8O?>!1 zW$%GeL-WOC&c$^`lBU}9G|r~n;-qv{O<67g$qXI2Re^YW&AcpBc4;W_ZepO;^<2Wy zt$?lf4C=}bk>N4ULOl~L6`GeWhVn2lArXD$e4;{EP=)${k&5xbtd(wnzx~ zPGIS-5&EhTSCW@TfJtl7eQho$eKb&Ma*|>2+n-AkDcJ|5u*V%Y*J3yCYdxOYCCpMA z*fCsIfeBnA=!SC>+@K2)dr|w`%B|X_`L+H|@QQ=S+>PW1=#@72Xtjblsx!jnKdV8Q zo7!nPbwv(osagan9oJ~(!@oCTpVxQ&CCma{o0k6dVPeaobGoTD;bh} zNz!H`nlX*dt$B{|gu|g4^qe!^&+vwdzpr)V6l(U|{47H-A47Lo{NO#k`^}xKyKyjc zd-?J}t*52mPh!OjH?fe;NyZym&V~Azv%I4>L zntYA^V*TCNwh8_$Np=YB`INK@kIUSeS;u$biC|~^cN#Y@4A9qppm?L5FMQ$r?I`KQ z0IAg4iRox-EjEhY#&3w*pggq({KANj=(Zmk>^;(559e6Y3+BMcTWu(ChrL;qL8z@_ zPx^7_dr#~yj}^;U7&o83lCTB81vKHJ(!}>)GYy2IKdmhy0=%dSgmA2Q1P+V(Qrpv# z8}6TfMSI8niQd_}^Jc%$s*T)5K}{4hxm!zd?+FV_D$U0|Ans1y%KFJ&w)GrG@Z!5p zsW@-UG8*&(|M$B0$6sSz{t$USOF+~YJ+q!wS6y{)_6;4rK~GlkH;#r?y2S@K3-^_E zm%sXS-RWEM4;X@JS)H-fuG(|9cAAY#bsD)UN~7I2BoEt?D~+*oFroO=9j#P2darEf zS4WIe*%hq?M1zlSqP<(m)q>oMlBNBp5kJqRN~*DYJ|@ItHs1eGoQh3SA!{5<5+lDC zlh@jY;SsTxO%Vo9gp+nkwb(jZdJ>(#WAi`|SWzFB#wE1OYPgDF6SI5q-U<(S(7-2$ zTQ;K@h5G~VYqof}j06we@1QL+(<*q^P~#`XO1B6-qKUCF7Vq!wY~1S)>>Pque{vtF zpYf^?nLdc5SPS?2+&%VL{7a+YZE-zy;FRL?5?w`Oe5Rjr3JpFi{g2PD6d}f|A{3E>-*mR!T`hAC|)iGY@0Evy5vTX60f7hj2et zjhp%#?Yy(K3L$ml*|Zh@zOY@vXpYjA)uwOw?xDa*fih-1yNjGJN-vRoFeXH(Zp4-l zhTJcO8$5P*h&6|}5S$o8rPrM}UzA@?Jj}|;qXYX8LGNZ)^4gqD!DvTWuL~v!oPr-@ zU+pGt?nE%gNg+6{{q&1+i(V#a{`%|fsU&r+W?WMIq|;K>5|8;;t8^X?ep8gYf)(oR z!P9I#G4zaK7(*g%|KK~8Tfz{X+JjIkq9;^w=a5#soSREA$iZD25=P{sN6Xb+bBo<`PI@+?#jC{*409Fl4-t>HVe8K% zAr2?ET1s&#o=Lx&4I>3al(xvY%Aqm>mJ8F@V=)+@%UB*6rp19q_%)L@aTfXy_ zxYD_SCIxum7*1*%n~N)=8;{=eI6MdiZ3NA6EpIefX=2d3e@TJP>j-#IX_s8}&35Ok zt`BFwp!-Y(y5akPLw1;*L42Uu@T#T{`7i4{@GHV@$5AYp$u%{p{a*gmm}~FG0>VKt z&v4_hM2)J`JECklTUPDwX|*QT%x5~2T%TehA;mF?eJLtF4*Pl?i$=TW4?DBLu4HE2 zn5<_Zq$-VS$Xy)`%P~lluk0!>jj$cB)CW?0NfmtAy?8Xd!`PXXLs=)@Mq1C*(UIp0 zWsY0IG&iGJNCn}nukQE*oZi{#C}H@bH-ZAZoq<<+uwR@`pdo4c#`HX} z6CM=)>7~krUbbAx3#o-jTo`*%qFYuo=&7{XL`_JE&lHsG8K?8M)<5U`VAoI9pxrjT zm&^=~3p*X|3pVvh8bLLTSCZ%x*TnA5KB;?R65A9(34RpR6ZrC%v%RP-x4z59^`F-1 zN3g~Qz0g?%Q{S5vzXyY&RE<7EbYC?VUpC|CrTER(VrfaE8SyD8Q})_l8hgcDcvJ8t zJ4t{PHBB&Q{UAN_&)Ao^tYvZ2iL&z9w0a(o|ydLSg{fou$X6mwaZgi zKy2D5x4*r;M%JsFzyCcjcxYLSl2EkQ`)ykh6Xna*hG5W5bntgaBlh-fECUf{#;VY# zef7eTID&FV)8L?O2GTViiB?HMaDp&lJcX^&6*b|ug|uYvK-uf?Uw zK*Ig}rccGiu@9A)vtH;q)bZrX35NBXCX={WD)h-!18|A@1j(sXIB@5uN0D++xKPPW z6}~g(7{wp5@s^2`c9a*Q1GE7(b46b5bb~6>%;5F4NkrEYqkrv6k1NUDov&Yq(3s&_ zpFz)rw=<6O+th-=i`ckWq0jonR0rGn*u>X@Ox<yQ^EIGEAvkkvqj_(QF+OcZS z5Ak}2-pJ3sSZG>tnumYA(m~zFe5#U-wyvPEl+Pw#InouQIv{`FuuP%drJ3Bkrl+=J zP7?Gg{xcP{IpRZ&A)fd)lVRW?@_zJyHMan~op(p>(|#-A3~eE{9!7|*z=WS+F|yIf z<~p}jZc`wtbf_COcIB|)1A3`9uxx(xW|V;=I(d${N$p#jK2n38v9X3~r2eIcZS~LH zb$Qd$RfX0Q*A7R(B;8f%5{)jueTVeSi+CO1A-dU>bL!Bh&5z5jv~i$?F^yrO#}-ut zVizCjCPmg!vSH;7P*txiE94cjhcD?dT_%ieP#JhXdFxuPL?Ci-jg*{%-5n^E6D-HX z8L`II=wB#bIy^AbA~kVStBrHVg(cQkp0nzA_xpnfBEd7rP97>@YUNye0~xe43Xa6@dkx;Re|aD02NRaJXZfFW~QsUj9el=US;pd zdEIF~sI>FOsI%BwX%& zA?kylC64Aljc9o8zOi2t%@*q)&nloAscA}Vn$-|RGe!Rn(k(BL>;FZb6{m5Ee|8~( zR=kXfMmWKM^Ql~4lO!84-&Ue!76;0lM;&F*ulQC3yuj!v@6CF<6ChV;>YSk%v@8ZJ^Zefql0q@SN_{@ zMhQj;mk{N%w5Q@+Q|i}c@lAfz(uG?w3oIwhn@XkPw+8T#1kAwv4-q8vPo8%%QcZdI zQ5g5=22&%S7v*jrT8h4r4u3$tYZYYg=SWo4KA}O-f2a_>3p;yoEnV(n4I*drxR+9+Y4THs3@uG;5OoX+t9wd?DU-zK%xrg(rM`g*FfkYCSrsQjH z=cU(q^gGiE1ns#o4At@%e!1<)&t5*@D--Pvib7abzoQAt;FQEqs?d0;`qljMMB0x3 zqZ~+c0ne~K^TEP)T@p=&{%h~Kih*u5LnB!KQ_jVa)sc7Q%!5MJUdHB&{%a%e(CDdX zXgRpref6%!?&^-=dtPz|BhgsmIQs^t|L&p&u9iy8P`r)f_DIc{*Wkf%zaPZClM}6c zaPAyyqibVbZ>z_LK0w0T2Gy1cBQ z-N)s;NZsna*FJl)nY_DA(tU(YFlAMn8Ah?mM~eM2)iLbbWb&%7D&h6?-5GYnt&yp4 zUWT~Y8fEjA$;QhT`k{oZ-TWM@<|JI)j|}{|AYI|5P+tLw!H`?$$fE7WuYJG|RTfUl zBF^1tl|9t|Y>q!#^Z{+~(y-TI^ByTz`kX;KbS-A3@`r?Q4m2aRcmKKDy%#!hJ^;va z8J(}JqcVT&!mv5t~P*gJ{(u}p;VUCVQ_Ya(ifAQ=wY`GZi(@+uM{#mS)CrZelJifEoVXv=SAYU{&!6?MlZj5)#k z9+h|XJRkDM!f}CL9c?oRByxzWQfT6?30e80CsnFeSi!kLPH`r4yj&mA1xVg)FZVWk z7VYa8w;XkJ2Z!G@kt7kri22 zTLPZ5(UAyX-511Pm(aT`gSLVbodKJ^B!LYxhN)d%uo2<%6MWG1`qE1?8sX~H49leS zUF(Y9u}a1fvPL8do=Jw-^GZWv9HU-vS2GSsHwp)Kc`ADQ<~MMNxQh1q>6fbst$QpL zLJTouHHoD)yn!1d@5gYlBtKMVmaUgqpF^H4;-H_c8U9XtV1UO+*jktVf#_qzm>QwK zZm>sQpHIWX%gHL?yF5MD3axz6M@jf!!n5Sa>F}i(1D>wIsxjf@I#0{1+){AoE2sC!f@Rc$n5)jomJ=m*EH5|cb5>-+{; z*>GIWFZfxwXHQ zk*=JKlm_qLtR@_+u|DPm=ge$(6XwUhNw6@zxpPJxjZ`mQb$I*9oCKQAS_@Xg^m}ZP z7hn3Y<8>L<6WQ0UThGhjxa*%H9rE}XYRCz3o=SUWKh27BoqKKNMM0=Mfg-`Gyr?5h z6rHm0+Q)len&EpreCr;Obn`)HdHt1CbsDTMLb}ih_xAYg$Y9@W1_Rn`#o!#C#`v#C zRNAfzMBPR2jN(R;Mms#%hVRad$Sv{bH5nUdl&8+B=_<8^nb^?&v> zwjKWBhuQeo!9LI8{Xko@N7!N1>oZztD~$IE44OF^6O0H9o^!DTdl~uay5g`%f^%fe z5gi`~v#F^{LPj*VCD1~nspszAbs?pg^3b%A#**wiv=$zXGj=D#izM4KdgM1C`}Xw8 zaFzb>>uWi@7X;6ggCmJoy-^8J`u;;)HR%{i$ufgX9OYJ<)kmND2q(Rq1;DO`&$*b$ zq^C;*f%hHPZCD+#IuUkC>HWpPz+qTNF@~zDhMqZrq~g9DbY=W9)34AN#z1uNLc{$Y zK`hZ7wh=Qf-Uopgi9GA8UD)~iCOpP!P{e6PlMdw;`?2(qJD?W^z44^HCg*X<&Ot^? zU}-V@tQmPE7wuQD0^xnC9-4UIuPoxi@d{nu*7sCV|8ue~{R2n&T6A@s#jS)S-|M@N zn~UFhhS-E>OK>eB1cdftutsZ2#&H=D9F2FI(jf8$JGs>rMVboTxobI>X_V*>GL@w( z&pU&KecSxRxyUMcn$zsTZF=tct@ja;<8Wco}UBX{&Q_^60XL)&hfX!!F|3Dz~ z#m$eg@NlTFS85=igB~e$c_!Rw-}C`O44$ePdPT2Y!A2P0NTe)cgt&S@-ugbfdNLav zMl@~rZ|t`APd3m~#P^wp_}{k_OaiCty8S{2i&zYzt@>W*Q*nU@E0g5LdKSUg1LE2m zt6xp)7-jD%)H+$j-*1T4a5oszplC{m$h!lb{7dX>;mb&GV>MFh9LQuv+8!f}$sVwcVYZ|d@ zGJ&sk&Ts>MRaxe^r$v(pT^KB#llnph-Ve{dy~@EC1*;H#)@AoJ8Y8Z4e;0|pyj7H< z;3hVCDYvnl?$SG24|9S*=a9!T00F0WUa{U*vU@O9&y=XnmMJ=%s9KqmWhw#a+HjMG$JLnrG50N5=7d(gY@W(2@qr( zPU2M&yI{T`^KY8A$L&;pMhU^Pg^x9ti41pU$QM@q&!fHenrvALF__81cIB_d&c2%v zT&Xr|wl7WIdf+Hg*q_>-&8!5yBcsxUK0Ub{)3&$eI(KHlJ0|AkgQ44mF3$H*O}=B?+-n!?(e_&Z4Y&>TPqSG3?jn#)WCh$^m+KEQ8`tFB7+qiQ6A3&M=ZtR4oy0 zI>xxdBDy+p?(GB@`x#`wIkgj7c+y@tC05nhCef=ZH4_3uJ5~WvuwIUkrUp^}VUR1| z@XADM>v{RICbf#8#E7=?S7&w%Zb@Py-d(w&3SoZ9#V^bgj*_ujGLf|si1HLgBO|^{ z&R<#D(>t~)uKCHh)FZ+T)5g3uV3hIJ-t1b3yY&o@d?;fSbE~~ePUp;xeYY%r`ZrMxW-E-Hd&ACS26T`HN?o^RCTRop>ZR;AH1BayU&E)45{$U=iht($!@~e4vmoRR;kA(;sPcd zMvi6G-eowmEgM~a<@N_dw2k3Kcf7U@-iaKg^R$9Dby_?`_68<`N0+{FD{3!K8`fi? zv!sI|b9nFxn!a$WS9}h8h=^80JX`ayZGkJ1<>rr%DrfaZdC-2IRu{&!TAg`tH=DVs z5DQQ39YkI}wH#wUy_msH{^7k}gSRc?Fk^I3@~MlRr2tGsMYn2p~%OTN6i{qP=F;uhE26}BAjW&~G#U(6cW zuYT`qH@={c^3;5)0*@&jryPX0oYNk6IRp>0yzE8%>JbyM&O;F{W z5IfEAW~rvu%hhp8n5OWGVf*)9SWQU2o@3Qd5uVkWPQ6hP zyIf|&SxQ<8eZCo>9OY;=AcM2k_gO|}=AIR$kp>j7B&FPJGY;O^OJI(E(ms@Se;`Qg zskNOR29IBO*IEdTF-P7*4_cCfA&(|74HE>ve2?#0nZz=Ty}yM={NnD|^B>V-Ig*1L z*xZkD8svPQn9df+l~zWY#)k!o6zu@n7UMF@r){t-xMj?0vLs z)J%cH$6IxZFghiFU1YHMe!yh5TwnQ}nx!XpBKA}fiJ#a#JEQ8s#>Ua6FwP+}t0}9- zcCj1#1Cv~U>a{1LJ5j_trUa#t&mUf1ofGB3k0wvSm-HIdPP>KHUc$P*gO>qi3cDq% zR=*|EkVPj8!0Ep`V_HY`gwV8w;E8vsb{w*Ne@tlCp=Jjno-5ylo}>@oeL}+C(fXY?t{0 zv95ZnHHgH1BJxXmR{C;LGo;maY`|E2^4INn)d@Azm?xDP&Set3VRKxt9qZI3_p;ic zw;oTc>nOb*)tzT22&_&GOv|SkNXp>M*LD`!4WBJ>RmLT`_0*uh9uj^la0f4RbDRj{ z&fMdbO)I*&Xbmtx!q3rRN;$AlqEHvcx=-~g7Ry*hb*F}Vwu@Pa@KMIK{>WUGghCNZ z7f&v)y3(4wIerJSuBAD=o0sEtlo*LWCTrY!S>|>~;;qCW?<8?)C?G7Te2`o|NSQ4& zoLy0QIU<(oG2d*U=#&pv*JCV|_=ANOsRPSM3XkOgCN_+aJaP&*-5<9NCn2tq?x>>D zwy}1%xV4bPw+9yYH9cb%5iBb_>|B8vmI$szt9q-3nDe3|UCk~H>1H^|b&3x+CO6$h zd0PUWv_86SmwV&WhWNRAFHM}a`O>~{e|SndaYKXLg5h4xfZHkA`oyF&p_`esE1T}7 z)xo5>J^K$ciKYcRza>;S^QK{DT0I;*Ezw2>7D`4kurrnAJk_=RSDzgBTnU`hcE!(~ zcB>HSeW^9=|`J=5ol&KE;O= zCrWguWV>ulG_a19UPU|z+1P1zgx%-vuGe09I5<#OtGK*DyrmX_&GPWc+QjGGy9{(p z4xU0+zT^bvcn0^)Y&u`+91pXgwl%uRPvLDIG2$^)Ony+t-DpB&WN7f3NicL%{&n%S zM?!TkUb@e&@!4}9uPVXS(y|2NsEG&WKQkYx$(0&Q_^I(4esW< zt;5Xw<$UMxD6tC9xZ{QJX^py1;j7U6Y}VdcmB{jS?8axDS|+Tf3ojN7eQ$QQ%m4bD zF4fam`;Q!_+asMTCLVhKRNk(lN6$IT!US)ye6d&Do@U8(#{4P$w!`Xa4$lkAyswo! z_`HmIG-8j6*b>)TDyYF3W8h)F&Zyq3K3uu}ickYpm+)%)JQEZW6qeM2H0^AARNweWN9zwihNzI4NY zUO{vwKJ=$zBoT+$+PYcn?HM)Y=h@1_qc22s)2=poOuA@}hCGqd7cKEEH9eiqdx%Bl zQ({B%*uvKRa$n?kW225>Punqvb7ktvEUV}Fn%C9}uiu^0ZF{HaB06eC-tg>uH2RKB z3}cW3wrcG#2G!TlP#J{*D@NCrfLN!;Hy?L$6mxXH%_9D)ce=eqvn*KRRm7bGH}ri` zKK&gxJk4b)A2F=gQsZtc4D%M&cb=AfYl>34d|Gd0ZBgv)f>nJ4jzehjoq96=v8<;T z!3)+gI75_y&1&c}H7qN<1oyY5poiwf2D=Ho%7e^08A3XP{3^9BWwqf$- ztAk_d^sl@hv~A^$uL)g8V8+ZjBZ>qN4qn6_lynL#`cA*{hbk&=J#B1ZKlHdRz07t7 ztK!b=^kTPZjg8;1vlNwA@K)R98x%42b}tv3y)9htiE|x5xRyn0rG# z#p89uU!Kh5W2CI+a(#r~v~AIt7s~CD& z?HGL5Pay$K2VJXBaC`{uOBo!`^rih<{at%F>&)J?pnDD>rgxLH6St5LzOV!DlH>c* z^mBS941nba)r;DjCGKS-g%2#t&bEzVoSS(*(eMc0nT3I((f2~NxtDKcE!{8m2#MYA z--jTuNC-!(+X7FYA8gb)?Z;6+dd$ioVdTUooHXX9ex~612k_6Zo{l~8Zg~yucjjB( zb?_r=+s?Bp&|vp!lB!W=>@-^!bu>fMYE8+1%fu0CzIV3DGh^?yA{yZXvnOWbE^_{h z{cdCNG%vZuO@CDI+Jx{aga1$Q)u1n3Kiw`_avmlpF`mRGouf%I4tNf`?vh28QOR^e zMU$s)Awi_~<4$1V6%&So^0S(!3efvU4uaO>7&V>Z7&mc<_hdP_KJjXe<+Pp`b&TYA za)_DD&w9|^GF>iv7rf}!LgghDza(ugRhXn%KP{{BY`N&`x{&rpQwEL)oH;IHnCdY! z^eVnZi1N8p)52=fWvK)yud7#McvG^kOaz+npHhnqPpiUF5Cywt;aubPY~K}vaGWn| zpPO%j7u1aF1Q%^AjOkhrd@4O|V~ye|h~>grlP#-ehZjw)rUL?%8p+vt*{$W?o*Df5 z{(rT19dJ<`-yfq`zzUWGMG1mI6A@zUQNS+tUQn@%9Yu{Al_GXjjGzz;0%8G`s8|6( zMU)bV0V@bdxdRS3;HX#F|IFc>>)!6(UWI)Azx{mfX3NZb-}k1^yqR&`S`{DC$Fua* znyNCr9vLe}Se=jf_H{sDsL@W7q4V0Uu}KMbI+NS=wP9P#cez1P&KrIgtDirAIB(lCG=9b|+Y+rxgK%I2)xCJtDjl2N zKR0i;&)xax@TcyX`$DlQr!m$a=f^D4GdWdL(qj}b8I4HE9GbJ@?B%zw_Le-b6C}2A zEvTNftzuzRzi;l;#XRoqd-tS+&^?RQc1XlShef(8bq~*aQ)4kpdronivgMC^ylwVC z*ZTFD*P@J;f3&NuOU=nH;Pth;>9G9LM=U&0l)kx>R$64J^Ok$-V(fUo_Fbmq^{|C~ zM6)grB91k=zx@~gMH_;nLmt~2O}{yb*9Dl$#(GR{GWvbgw)o&#b4;)H`DcsMev?1v zMP}z+V6EN)R*Jk3ywAD4*Ev62aQTtB@1rNlXIFc@o*LAH=RNS-$Xk&oeT|1+w)R?M z80g(r@5SyrgAUfTKM_^ehBrdjc=bq6ovU3tS3bYE(|c3JoxMA@Hx>1LA*j_iAGJz5 zy|#8n<}>VU-t|#0X8pP4=EA~6r`xmlhYw{hd3UXOs>QYGhSyzVZbrTC9y@PUNt9*g z(Pj2tEoR*jMe6>m`)GP z9vqYv_FZ<$!P{fnnQRyBxnNfJu6s<%osVT1B7;|P<2)C51?@Dgys;LT*gpy%w_J2* zeYG<-I%+O!Tio`raOVX%SSGOK(BAIs#SWf(>BqifekfR9K6F*9g&&g+%`Bf)^f36I z@%WZ|jk-PK2ecev$9i$ad8hTVsirBjD>k$WZXXu=vT%2#-v;isVvn9ar6>9%aJ|

      uG7MZeW7zIxcV=f-LUGHwtMW>0o*+`Kc$?1IJVN~cHPE@Z}T^<&OL$&{;o_~ z?OeO1_r=+-vi(NS-)!`gzx~YN-Ah)DP1)Tkboh9$C#!;u$49Il+M(>gGGIXAcEx$y z(z@gA`{j1fp8m~{??d>)*j*9n!>Vt0-e1U#=Y@A#5S*~RMZYMgKX_f&MxOVm-F&i~@Op0vL%&IdtbZpZJ8Fsl(QYYIiZq*yC2HZ00?25jp zbo}fcc)tZ-iFEa?%RJ4l{xNI?uw=^%IPaglsqXpB4{J~K+VCmm?DruTXSZonQm|~S z-^{Sx<;72C?#-RktVNXhB6|y+#1BO;IJ^kqB>UN)!p+*xYP;WfL>@aqx7>L6lvnLm zKE)p`^eQ^GY{$Bu2JGjj4!5m+Z{m2BdowyS@wx9^OP7Mg z82d;okM{iqJ#Xy@*l$s-T`)54%IJwT+23?M;J4~mzX{JmJ9XF_FeAaIcazz_92v3v zEx*^|>Qm=WytCb&b=>{fg_+kp?i&S$^5=B=GcUw(!3M(*Z|3B9d@!i`Fiv-DH_o!- zyVIt#-eEKKo@XXr$F7*U`P#X?i%mak_WNclzy9-vcJAABTwtrM!736@92j@abk zY}N5_vR>}9F%y5=WjZ>fzYYKU?=BAD>*&|5OS1TF(7KLJeFWzw%zx8Szvb9}evj>i zc?m8LzV%jr;+k=3qpi(18pddQ@7^*)XI6-H@B0<8`Ia;ED(;v>SMZ+9=)ZV6|JTK< zY_;F%kG5@bXhxj*o)aD2J$HhIoE(c8kG?zB&GV@40)z0be;5f5v!@tzm{2&#d7b0G zH}nnPtv%7ra=C@KiPy+%6IZKVhTomZdJ|`p_R!X+(yjG@H!BbEHx_o<5omATe87Nn zp|8wV{lKd|rKA7I=ID0!SkU`)9W(4%`sglA`nz5f{*y7L^N-q*nfdF+oQUO*NX+y* zo%nYAVTYeh9Y2*jkE+R<$~|HK6K}Kj#hJQ&joN#8TX3(N`cKs#-hFU_M^a_jC{Pwm zt>Rpo)#v`Oo@b8R6=PN2J2w_p$9e{K=o_l-mSa<5_B_b!@4C}%FPD06*s^i`;;TA_ zAwhG4?EAgmWM(|!?Qy$2tfo?XJFmxCY2M{JB=YX0PJr+fQ#9xr4?V(hzh3+GOAd)WF$thQUB*8JzG1CQ%`;-3q6 z0c!bfk!SNuR)*Jgxwd!1{2<4JJ-0qf=Il#8VP|M2beikguA}9lcP}Dkx ztX=r->0i9;IR`d%Wrqwpch!6DZO=t~p8<|3*@jQH2hP>zPkEoU>91=h23ApB9#*=o zZD#5}Jth6ooK6FhK3Y`FdUpN7v28rxEa$%LZI>n&8h0o-Vi~e0Sr`_Z=^0$O{ZT-K zoq6wX{B@eWZ|TeTavXbl6PO{I5)$;}BI|&&`LM~@q4`(pdKw_SKCW@I>AO>Tc*su9k%z{ z*q|Z$LSEMbpDcD!!XUE?%iQ2T1C}|tM|$r|*}Is7ZB6VGwPw%sOSOwPbxd;Edax6Z~H&7KUu<=0;Rdru?!NlLF_x88l{rw`V)Ll>8B4C4dlxnDS(dT8!YX6t zgRraPI###*V{*W|)-|D79&hGFm>5Qs9@}C!bkIM=-TqyeJTBX^aPH+f_HBbNoxA?N z>w+l9aaWg=l~}Mg>OL(w;rssCpY8*XpKiYJXMU1yaL28-lbxy^oF<%`m)1Jo@yes2 zza4yJuyvLFjdg2|`a}P@(y;a%iFJqfgKPV-|s+23}CDh z6@T2Uh>T=mDw6#l<{j+R_+*u({{#A1Wr9x_nM_RHVP%5?(yf0Rhn}7)`3bER} zB#f7E7Ax=_f`OgJ8oj>2X&+zDWSG+vAQxf-}-as-a?F#vgQ+^N!70DMLA{~6G-}Qj(BGt(c%M6ha1G_Oc zK0O@J6Q=<|IqO$(+yji@gd)|-{<+K)@hcmj{2&eR3*N8ghVQ9_@`IhX8OdG?&Os|U z(;v$_{4JJ$<`)c{0L3gE``<>V1MYpNS{7)}bMLGNGRR2xAZ@UY8j{MuI?@fR6V}Sq zLvio|((sb9N7H2^$OEu1BdeSf@(N_?qzq z8&Fmm!Uy@K!Qva?#JO~`!#tr#*-cNg4g;sxH5whzVa@lpPzYy%?_l~gRZ}j`ca0$( zP|08Q`i4TXBbjP*UefA-<3C<0`iPIRE|vVs_UCf2OPgK zl=4Fixvn}5q5~ve_3U7YvaT5Eb8RkG^4DsO^5ovzLMgwnx>TcBz`QWvr{VcJFh)i<)~dEP7$HC9 zf;O^*d7wx`W5jGvvxbo$#6#7)FiQF1yd$mt2=S<>-x^ToH%R;g z{A|zOl=9bOQg5C_X}_W5mo+w4^4AKrrh$BKONss!O+U(ps|L0bRAqoj2KMT)K6S9)>0Jaf$9K`#YjA*sU58GIHUZmL6 znD+4e%43dyg$0ibob-&Teq2bp?SaRm`Fr}gSKf<1RGJ2guFRCux8`O3x(ICI=>VpC88nr_tm?2;Z*S4Y6&yEU+$Mnbe8BFGEY8t8L1~VB`c!kf zNLIf{j2qaQ$t(|n?6PgKz}N>^FTy(98LVgdx=wD$XIc3b#a)5VKoED*{bcs>o>(1* z(Z)MWMA8|yepIaW#F%`%b*Pjw6S0TTg;-Xb1^|#9;0yl!uq*B z?xP(%fk0qQhM}R~3CnUB$%4`YQ&+^VlGvs5^Ir{yHqcOi4J|Jje_8D!rZVIGN%(*@ zUC92s^51K_CGQ(iSpaRYM3u#=Ne5!P9%%1cU)F*3K--Y~;xur~s0w{+R4$k^s>zB` zN(Zo>!`GY8UKuYtyszYB8#FfCTzoumf~F~?1MUMSNt`2k{IYy;z9;H{mmIJT`Dv_f z>0=j0dZy<;Fi(B>AN_R@o)EK%RhWGr9M-V$e>tHZKvYPJ4ir0o}m< zG*vq0#dy5J%Sv_6``dp#6%7f7##Bzq!UFWgd*&gv=8H;x_`a$rrz`uoN$r19UYtJI z$G*n|<%PrPWTpF7m3n;#?3*cT53Er=f_jq$#?QeTudQ^l$@2{~sediGvGf+}Xjft5 zT>q{I%LE}9C%B0Ts)jO^4U2|8n_{0UL`+y8(5j~1?NM6qw#%w_TSV8pO_A$T|J($* z^^gDiSC%6k$AURQMX$e^WjLY4pA=@WhnM@@!#8Q*_bQ}}ab1sf4qoUK$ z?+bm0l+no`J*UwgD-NCyidZmiA^yj}*i|)HXZed%+f`GtL5yTF0KFGTFt~TXggmy) z_GsCYgAF1_fzJRgUWVGDw5bR?`-F*1-1vU8cpWonN1^bVa%*zp$0Hd~ACBWUT0ZPJ zn?poHQ}|Ijs^Pr)0rD(3-CtqsC_XgZ7UR8n_!Han2LT*+MHt9jFxZY2U7CUwg)ERc z2B|6iLq2Tpesy`Y>(MaMb)KAn36$~*N>94fai;$*OjM>H5CKwg0M`go=}+1B5Wgz-qbiNqErlQE3uSRqg%{&jQQAQ~@M#C# z=eg^vMFzea_Wyz9KEjRMn(XJQ#}C?&EH&(bN!6xB@uMoY`rTdC>jb35-2GrJ3rRkP z_I9em4(UK1s-%afMTVc3cur;f(E5KoPgULviqfRw0K8Bce%?!Owd$Yk*+&Y$D&rf) zuPSv;q=k6k-P%tvDu{zG_TfaHs(hyEo6+^Fned1En;@Mq@vn>@#0T$k?>Z_G2VZm# zX)1$_Nmz25HO1Q#wV=Mm>w*aeW&FTBz3}|deQEeExphZoudNI=reP6gqAPD-TLjke zO3_ep+l@@7!gIr=_(B{a@qS~>`b}^wfQTJFlkro>yE>BoJ>(D9FUaHv+8t!r#rRdw zZ(5P1A>4=>hf%c_cumt9najVT?naTYu_S@-!~{lsxqlacTP zoI}#|+z%`_6_tT=VU!pa0F&?`QQ{Ab|A1F6u?deI32mD^zg5q?^{2i2`kPALi^AN$2)hkN*4Q?ib{DVL4|q!pGF*v6DI#o*7u$ zF!nQTvBJ}qrRDFVI?~~-gCCu>w8ZvAJ+!pM_C@Wqw6fs)7Ft@-&}~|O-V87#5}!K* z-Tz%*Yrq9Q;`9>@pMl=8pbPYf^osP1^bYN`;BOlEAv-N=1MtA`Dhe1MK(<~;<#_{Hv5yt_bgIu_u z9-^M5I8=T97;ug7Z{6?A=voU=X zj(f{NX&Q)@)Lu#|I5$BRX%FEme{o7mhv=K4E{qFB!%BrCnJ0jIa!UDQ*hb*qUMrSY z(ePy9P};-0Wd4}EL*+gbzfApb?`@Wf<6H&GYBWMs;lkw22QE8PE>QCM8O*MYS_ zYQYD1knJ%+)mI?JO=!1~`oYN}|97(f7V|oaIR79&f7xX$+1YO_24m!$OOqw>s;>AI z%S%$9Kz?*%4!IQlT)HsI=$7}=OG+1Fj39kU(Iuogq`T6{y;Ac4Qel-yi--@=6}LBG ze-!+{*bk{3^|qmUSm^^Nk~4N?r!l5-5V0|RhV+YqrUk<>7^b`w@<$PObU0CY1hK)Z zJjy*xA>K^m9>gQO=rD=DiO22ge}d;(htkgZDLpkwm_-sD0w;2qGr3=kiB8#N(ElzzWKct7I79 zJGjo>3j82&Fg+!nR{_&1;`u2s%_5$cg40qi;P?MwdJ4&j+-M*-)I%2dLA@Y7A-%yl zCL{2(20t{<E1z4h!yy z`8gdz7uxs93M1<~qQ|t%BiiH1qA%;an7PXJE5eT$ zrs&FSi9Qh)q96DyK1UkJjQq&LN=Ad~9iC?Wz4X{B(GUBNAH_BgR5ay%Poz)x49^LG z_7>o3CodmL|G0Eb#~XfwG{Dss_5l44-q400@I{J^+DyDTt-5DkVCTr@D00(n4Q zS%4?x4aX_I1wRY$L*o=nT7d_e3(R{Lp?Fl(Ej&M>ij0MX9>_~@e`#g&2A)SfZRt62 zaegG5AE2psBshT|$fGE5Vrk)d>#xdIl;@DE=(?H0^TWk^iX%GEt+x>bXCQ)oi}COA zxa7J2iUwh9RjRGWP%n7?h(0g=PtrOUW)9>h*QEuiA3QzcJqk;FkAFsfpo@RcZFvC;DogGRb@sjoz4I`XYmL{Yoc?c;7)9{wVAh`ts?BsSRLhaSNQR1d zX8X*@n=cW4=rY01RQHG$JX-?sK=0^Wra1645dAuMjs;D+-~>(-W1;gy_Dw=xhK`Uw zG8(k+aPxnl&^+-nh6KjCSkd$0$tWZeWA zRwnO?f~I~o51R#Md7{CLj|*resp^8XAWcXcw!`4UG3cUpm}hfpPNLfK9ZcjP^CPO_ zIN>QHKd3EHn;lD9fp6V3QP5# zDlFA|Dmv&r3WuKYF8an}SP#LlFbtQ%?ij3nm&lIiLw679$@&icFs%dOzKOK-L_+y6 zis$p`%LAlGI==FJV@wZ>4=|yN=+)ciP|L!&9dO{w_%>uKW|@xx<~b&tXjaZtUNMGt<*hpho)ANXhZ9b7*$p@aO8jiHJ0g7yejTMmnF zh3uYqai_)D;CLqD1! - + EnvironmentId From de9818f159cc7084ca9fd98db2e0da7d222e2cd7 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Wed, 15 Dec 2021 15:23:51 +0800 Subject: [PATCH 48/60] Save Dailog path text style --- DSView/pv/dialogs/storeprogress.cpp | 1 + DSView/themes/dark.qss | 4 ++++ DSView/themes/light.qss | 4 ++++ qtpro/DSView.pro | 10 +++++++++- 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/DSView/pv/dialogs/storeprogress.cpp b/DSView/pv/dialogs/storeprogress.cpp index 28fa1571..ad6d4596 100755 --- a/DSView/pv/dialogs/storeprogress.cpp +++ b/DSView/pv/dialogs/storeprogress.cpp @@ -62,6 +62,7 @@ StoreProgress::StoreProgress(SigSession *session, QWidget *parent) : _fileLab = new QLineEdit(); _fileLab->setEnabled(false); + _fileLab->setObjectName("PathLine"); QPushButton *openButton = new QPushButton(this); openButton->setText(tr("change")); diff --git a/DSView/themes/dark.qss b/DSView/themes/dark.qss index 63e3fd7b..d9d62acd 100755 --- a/DSView/themes/dark.qss +++ b/DSView/themes/dark.qss @@ -1622,3 +1622,7 @@ QTextBrowser:hover { border: 1px transparent; } + +QLineEdit#PathLine{ + color:#eff0f1; +} \ No newline at end of file diff --git a/DSView/themes/light.qss b/DSView/themes/light.qss index 54463857..06b47f2e 100755 --- a/DSView/themes/light.qss +++ b/DSView/themes/light.qss @@ -1660,3 +1660,7 @@ QTextBrowser:hover { border: 1px transparent; } + +QLineEdit#PathLine{ + color:#2A2A2A; +} diff --git a/qtpro/DSView.pro b/qtpro/DSView.pro index c0b4a15e..228a0d42 100644 --- a/qtpro/DSView.pro +++ b/qtpro/DSView.pro @@ -13,7 +13,10 @@ QT += svg CONFIG += exceptions CONFIG += object_parallel_to_source -//QT += core5compat +#QT += core5compat +#able to show console log on widnows +#CONFIG += console thread + CONFIG += c++11 QT += widgets @@ -378,6 +381,11 @@ ICON = DSView.icns #RC_FILE += ../applogo.rc MOC_DIR = ../../DSView_tmp/DSView_moc +RCC_DIR = ../../DSView_tmp/RCC_DIR +UI_HEADERS_DIR = ../../DSView_tmp/UI_HEADERS_DIR +UI_SOURCES_DIR = ../../DSView_tmp/UI_SOURCES_DIR +UI_DIR = ../../DSView_tmp/UI_DIR +OBJECTS_DIR = ../../DSView_tmp/OBJECTS_DIR DISTFILES += \ ../applogo.rc From c407ab22f7ab647da1f67365c52d5ce4ed4a4a11 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Wed, 15 Dec 2021 16:07:52 +0800 Subject: [PATCH 49/60] Get the right startup param name for auto open data file --- DSView/main.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/DSView/main.cpp b/DSView/main.cpp index 3ec0a875..39df2e69 100755 --- a/DSView/main.cpp +++ b/DSView/main.cpp @@ -38,6 +38,10 @@ #include "config.h" #include "pv/appcontrol.h" +#if _WIN32 +#include +#endif + //#include void usage() From a04eb6ff5d79556d4756d664ef6ca04ead4720a0 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Wed, 15 Dec 2021 16:13:47 +0800 Subject: [PATCH 50/60] fix include --- DSView/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DSView/main.cpp b/DSView/main.cpp index 39df2e69..7a4845d2 100755 --- a/DSView/main.cpp +++ b/DSView/main.cpp @@ -38,7 +38,7 @@ #include "config.h" #include "pv/appcontrol.h" -#if _WIN32 +#ifdef _WIN32 #include #endif From cabc8bf61dacf18048ff2b67c94ed5d96e44f8e1 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Wed, 15 Dec 2021 16:45:09 +0800 Subject: [PATCH 51/60] check the auto load file if be exists --- DSView/pv/mainwindow.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index 9efe422f..c6522eab 100644 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -435,11 +435,19 @@ void MainWindow::update_device_list() //load specified file name from application startup param if (_bFirstLoad){ _bFirstLoad = false; - + if (AppControl::Instance()->_open_file_name != ""){ - QString f(QString::fromUtf8(AppControl::Instance()->_open_file_name.c_str())); - qDebug()<<"auto load file:"<_open_file_name.c_str())); + QFile fpath; + + if (fpath.exists(opf)){ + qDebug()<<"auto load file:"< Date: Fri, 17 Dec 2021 13:18:10 +0800 Subject: [PATCH 52/60] ruler tooltip text froma --- DSView/pv/view/ruler.cpp | 18 ++++++++++++++++++ qtpro/DSView.pro | 4 ++++ qtpro/DSView.pro.user | 2 +- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/DSView/pv/view/ruler.cpp b/DSView/pv/view/ruler.cpp index 905d9de7..7abc58e7 100755 --- a/DSView/pv/view/ruler.cpp +++ b/DSView/pv/view/ruler.cpp @@ -96,12 +96,21 @@ QString Ruler::format_freq(double period, unsigned precision) const int prefix = ceil((order - FirstSIPrefixPower) / 3.0f); const double multiplier = pow(10.0, max(-prefix * 3.0 - FirstSIPrefixPower, 0.0)); + /* QString s; QTextStream ts(&s); ts.setRealNumberPrecision(precision); ts << fixed << 1 / (period * multiplier) << FreqPrefixes[prefix] << "Hz"; return s; + */ + + char buf[20] = {0}; + char format[10] = {0}; + sprintf(format, "%%.%df%%s", precision); + QString prev = FreqPrefixes[prefix] + "Hz"; + sprintf(buf, format, 1 / (period * multiplier), prev.toLatin1().data()); + return QString(buf); } } @@ -110,12 +119,21 @@ QString Ruler::format_time(double t, int prefix, { const double multiplier = pow(10.0, -prefix * 3 - FirstSIPrefixPower + 6.0); + /* QString s; QTextStream ts(&s); ts.setRealNumberPrecision(precision); ts << fixed << forcesign << (t * multiplier) / 1000000.0 << SIPrefixes[prefix] << "s"; return s; + */ + + char buf[20] = {0}; + char format[10] = {0}; + sprintf(format, "%%.%df%%s", precision); + QString prev = FreqPrefixes[prefix] + "s"; + sprintf(buf, format, (t * multiplier) / 1000000.0, prev.toLatin1().data()); + return QString(buf); } QString Ruler::format_time(double t) diff --git a/qtpro/DSView.pro b/qtpro/DSView.pro index 228a0d42..a122b7a1 100644 --- a/qtpro/DSView.pro +++ b/qtpro/DSView.pro @@ -22,6 +22,10 @@ QT += widgets #QMAKE_CFLAGS_ISYSTEM = -I +win32:{ + #QMAKE_LFLAGS += -shared +} + TARGET = DSView TEMPLATE = app diff --git a/qtpro/DSView.pro.user b/qtpro/DSView.pro.user index 79cd0fe4..152e14ab 100644 --- a/qtpro/DSView.pro.user +++ b/qtpro/DSView.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId From d2bab86a8fcf32e24404b4c7c99f9186b211c013 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Tue, 28 Dec 2021 10:11:15 +0800 Subject: [PATCH 53/60] Set custom python home, for able to debug with qtcreator on windows --- .gitignore | 1 + DSView/pv/appcontrol.cpp | 5 ++- DSView/pv/storesession.cpp | 4 +++ qtpro/DSView.pro | 63 ++++++++++++++++++++++++++------------ qtpro/DSView.pro.user | 2 +- 5 files changed, 52 insertions(+), 23 deletions(-) diff --git a/.gitignore b/.gitignore index e48ca087..c855d007 100755 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,4 @@ moc_*.cpp_parameters DSView-prj build* share +.vscode diff --git a/DSView/pv/appcontrol.cpp b/DSView/pv/appcontrol.cpp index 0f3d01e4..286e8019 100644 --- a/DSView/pv/appcontrol.cpp +++ b/DSView/pv/appcontrol.cpp @@ -81,13 +81,12 @@ bool AppControl::Init() #ifdef _WIN32 - QString pythonHome = GetAppDataDir() + "/Python"; + //able run debug with qtcreator + QString pythonHome = "c:/python"; QDir pydir; if (pydir.exists(pythonHome)){ const wchar_t *pyhome = reinterpret_cast(pythonHome.utf16()); srd_set_python_home(pyhome); - }else{ - qDebug()<<"python home directory not exists,"< #include #include + +#ifdef _WIN32 +#include +#endif #include #include "config/appconfig.h" diff --git a/qtpro/DSView.pro b/qtpro/DSView.pro index a122b7a1..53e0acad 100644 --- a/qtpro/DSView.pro +++ b/qtpro/DSView.pro @@ -5,26 +5,32 @@ #------------------------------------------------- QT += core gui + +win32{ +QT += winextras +QT += svg +QMAKE_LFLAGS += -static +}else{ CONFIG -= lib_bundle CONFIG += app_bundle +} + macx { QT += svg +#QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.12 +QMAKE_CXXFLAGS += -fvisibility=hidden +QMAKE_CXXFLAGS += -fvisibility-inlines-hidden } + CONFIG += exceptions CONFIG += object_parallel_to_source #QT += core5compat -#able to show console log on widnows #CONFIG += console thread CONFIG += c++11 QT += widgets - -#QMAKE_CFLAGS_ISYSTEM = -I - -win32:{ - #QMAKE_LFLAGS += -shared -} +QMAKE_CFLAGS_ISYSTEM = -I TARGET = DSView @@ -35,6 +41,24 @@ TRANSLATIONS = my_CN.ts CONFIG += decoders DEFINES += decoders +win32:{ +#INCLUDEPATH += C:\Qt\Tools\mingw730_32\i686-w64-mingw32\include +INCLUDEPATH += D:\msys64\mingw32\lib\glib-2.0\include +INCLUDEPATH += D:\msys64\mingw32\include\glib-2.0 +INCLUDEPATH += D:\msys64\mingw32\include +INCLUDEPATH += D:\msys64\mingw32\include\libusb-1.0 +INCLUDEPATH += C:\Python\Python310-32\include +INCLUDEPATH += D:\msys64\mingw32\include\boost +INCLUDEPATH += .. + +LIBS += D:\msys64\mingw32\lib\libglib-2.0.a +LIBS += D:\msys64\mingw32\lib\libzip.a +LIBS += D:\msys64\mingw32\lib\libusb-1.0.a +LIBS += D:\msys64\mingw32\lib\libz.a +LIBS += D:\msys64\mingw32\lib\libfftw3.a +LIBS += C:\Python\Python310-32\libs\python310.lib +} + unix:!macx { INCLUDEPATH += /usr/include/glib-2.0 INCLUDEPATH += /usr/lib/x86_64-linux-gnu/glib-2.0/include @@ -78,7 +102,6 @@ LIBS += /usr/local/lib/libboost_thread-mt.a LIBS += /usr/local/lib/libboost_system-mt.a LIBS += /usr/local/lib/libboost_filesystem-mt.a LIBS += /Library/Frameworks/Python.framework/Versions/3.4/lib/libpython3.4.dylib -#LIBS += /opt/local/lib/libsetupapi.a LIBS += /usr/local/lib/libfftw3.a } @@ -379,17 +402,19 @@ RESOURCES += \ ../DSView/themes/breeze.qrc \ language.qrc -ICON = DSView.icns - # make app logo on windows -#RC_FILE += ../applogo.rc -MOC_DIR = ../../DSView_tmp/DSView_moc -RCC_DIR = ../../DSView_tmp/RCC_DIR -UI_HEADERS_DIR = ../../DSView_tmp/UI_HEADERS_DIR -UI_SOURCES_DIR = ../../DSView_tmp/UI_SOURCES_DIR -UI_DIR = ../../DSView_tmp/UI_DIR -OBJECTS_DIR = ../../DSView_tmp/OBJECTS_DIR +win32 { +RC_FILE += ../applogo.rc +}else{ +ICON = DSView.icns +} + +MOC_DIR = ../../DSView-build/MOC_DIR +RCC_DIR = ../../DSView-build/RCC_DIR +UI_HEADERS_DIR = ../../DSView-build/UI_HEADERS_DIR +UI_SOURCES_DIR = ../../DSView-build/UI_SOURCES_DIR +UI_DIR = ../../DSView-build/UI_DIR +OBJECTS_DIR = ../../DSView-build/OBJECTS_DIR +DESTDIR = ../../DSView-build/bin -DISTFILES += \ - ../applogo.rc diff --git a/qtpro/DSView.pro.user b/qtpro/DSView.pro.user index 152e14ab..7ba4c464 100644 --- a/qtpro/DSView.pro.user +++ b/qtpro/DSView.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId From be2514f00947c02f011457094031927bd70d8ecd Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Mon, 10 Jan 2022 17:47:27 +0800 Subject: [PATCH 54/60] More flexible conversion of numeric formats --- DSView/pv/data/decode/AnnotationResTable.cpp | 163 +++++++++- DSView/pv/data/decode/AnnotationResTable.h | 30 +- DSView/pv/data/decode/annotation.cpp | 285 ++++++------------ DSView/pv/data/decode/annotation.h | 14 +- DSView/pv/data/decode/decoder.cpp | 4 +- DSView/pv/data/decoderstack.cpp | 3 + DSView/pv/dock/protocoldock.cpp | 20 +- DSView/pv/dock/protocoldock.h | 2 +- DSView/pv/dock/protocolitemlayer.cpp | 18 +- DSView/pv/dsvdef.cpp | 5 +- DSView/pv/dsvdef.h | 3 +- .../decoders => decoders}/0-i2c/__init__.py | 0 .../decoders => decoders}/0-i2c/pd.py | 0 .../decoders => decoders}/0-spi/__init__.py | 0 .../decoders => decoders}/0-spi/pd.py | 0 .../decoders => decoders}/0-uart/__init__.py | 0 .../decoders => decoders}/0-uart/pd.py | 0 .../decoders => decoders}/1-i2c/__init__.py | 0 .../decoders => decoders}/1-i2c/pd.py | 0 .../decoders => decoders}/1-spi/__init__.py | 0 .../decoders => decoders}/1-spi/pd.py | 0 .../decoders => decoders}/1-uart/__init__.py | 0 .../decoders => decoders}/1-uart/pd.py | 0 .../decoders => decoders}/a7105/__init__.py | 0 .../decoders => decoders}/a7105/pd.py | 0 .../decoders => decoders}/ac97/__init__.py | 0 .../decoders => decoders}/ac97/pd.py | 0 .../decoders => decoders}/ad5626/__init__.py | 0 .../decoders => decoders}/ad5626/pd.py | 0 .../decoders => decoders}/ad79x0/__init__.py | 0 .../decoders => decoders}/ad79x0/pd.py | 0 .../decoders => decoders}/ade77xx/__init__.py | 0 .../decoders => decoders}/ade77xx/lists.py | 0 .../decoders => decoders}/ade77xx/pd.py | 0 .../decoders => decoders}/adf435x/__init__.py | 0 .../decoders => decoders}/adf435x/pd.py | 0 .../adns5020/__init__.py | 0 .../decoders => decoders}/adns5020/pd.py | 0 .../decoders => decoders}/adxl345/__init__.py | 0 .../decoders => decoders}/adxl345/lists.py | 0 .../decoders => decoders}/adxl345/pd.py | 0 .../decoders => decoders}/am230x/__init__.py | 0 .../decoders => decoders}/am230x/pd.py | 0 .../amulet_ascii/__init__.py | 0 .../amulet_ascii/lists.py | 0 .../decoders => decoders}/amulet_ascii/pd.py | 0 .../arm_etmv3/__init__.py | 0 .../decoders => decoders}/arm_etmv3/pd.py | 0 .../decoders => decoders}/arm_itm/__init__.py | 0 .../decoders => decoders}/arm_itm/pd.py | 0 .../arm_tpiu/__init__.py | 0 .../decoders => decoders}/arm_tpiu/pd.py | 0 .../atsha204a/__init__.py | 0 .../decoders => decoders}/atsha204a/pd.py | 0 .../decoders => decoders}/aud/__init__.py | 0 .../decoders => decoders}/aud/pd.py | 0 .../decoders => decoders}/avr_isp/__init__.py | 0 .../decoders => decoders}/avr_isp/parts.py | 0 .../decoders => decoders}/avr_isp/pd.py | 0 .../decoders => decoders}/avr_pdi/__init__.py | 0 .../decoders => decoders}/avr_pdi/pd.py | 0 .../decoders => decoders}/caliper/__init__.py | 0 .../decoders => decoders}/caliper/pd.py | 0 .../decoders => decoders}/can/__init__.py | 0 .../decoders => decoders}/can/pd.py | 0 .../decoders => decoders}/cc1101/__init__.py | 0 .../decoders => decoders}/cc1101/lists.py | 0 .../decoders => decoders}/cc1101/pd.py | 0 .../decoders => decoders}/cec/__init__.py | 0 .../decoders => decoders}/cec/pd.py | 0 .../decoders => decoders}/cec/protocoldata.py | 0 .../decoders => decoders}/cfp/__init__.py | 0 .../decoders => decoders}/cfp/pd.py | 0 .../cjtag-oscan0/__init__.py | 0 .../decoders => decoders}/cjtag-oscan0/pd.py | 0 .../decoders => decoders}/common/__init__.py | 0 .../common/plugtrx/__init__.py | 0 .../common/plugtrx/mod.py | 0 .../common/sdcard/__init__.py | 0 .../common/sdcard/mod.py | 0 .../common/srdhelper/__init__.py | 0 .../common/srdhelper/mod.py | 0 .../decoders => decoders}/counter/__init__.py | 0 .../decoders => decoders}/counter/pd.py | 0 .../decoders => decoders}/dali/__init__.py | 0 .../decoders => decoders}/dali/lists.py | 0 .../decoders => decoders}/dali/pd.py | 0 .../decoders => decoders}/dcf77/__init__.py | 0 .../decoders => decoders}/dcf77/pd.py | 0 .../decoders => decoders}/dmx512/__init__.py | 0 .../decoders => decoders}/dmx512/pd.py | 0 .../decoders => decoders}/ds1307/__init__.py | 0 .../decoders => decoders}/ds1307/pd.py | 0 .../decoders => decoders}/ds2408/__init__.py | 0 .../decoders => decoders}/ds2408/pd.py | 0 .../decoders => decoders}/ds243x/__init__.py | 0 .../decoders => decoders}/ds243x/pd.py | 0 .../ds28ea00/__init__.py | 0 .../decoders => decoders}/ds28ea00/pd.py | 0 .../decoders => decoders}/dsi/__init__.py | 0 .../decoders => decoders}/dsi/pd.py | 0 .../decoders => decoders}/edid/__init__.py | 0 .../decoders => decoders}/edid/config | 0 .../decoders => decoders}/edid/pd.py | 0 .../decoders => decoders}/edid/pnpids.txt | 0 .../eeprom24xx/__init__.py | 0 .../decoders => decoders}/eeprom24xx/lists.py | 0 .../decoders => decoders}/eeprom24xx/pd.py | 0 .../eeprom93xx/__init__.py | 0 .../decoders => decoders}/eeprom93xx/pd.py | 0 .../decoders => decoders}/em4100/__init__.py | 0 .../decoders => decoders}/em4100/pd.py | 0 .../decoders => decoders}/em4305/__init__.py | 0 .../decoders => decoders}/em4305/pd.py | 0 .../enc28j60/__init__.py | 0 .../decoders => decoders}/enc28j60/lists.py | 0 .../decoders => decoders}/enc28j60/pd.py | 0 .../decoders => decoders}/flexray/__init__.py | 0 .../decoders => decoders}/flexray/pd.py | 0 .../decoders => decoders}/fsi/__init__.py | 0 .../decoders => decoders}/fsi/pd.py | 0 .../decoders => decoders}/gpib/__init__.py | 0 .../decoders => decoders}/gpib/pd.py | 0 .../graycode/__init__.py | 0 .../decoders => decoders}/graycode/pd.py | 0 .../guess_bitrate/__init__.py | 0 .../decoders => decoders}/guess_bitrate/pd.py | 0 .../decoders => decoders}/hdcp/__init__.py | 0 .../decoders => decoders}/hdcp/pd.py | 0 .../i2cdemux/__init__.py | 0 .../decoders => decoders}/i2cdemux/pd.py | 0 .../i2cfilter/__init__.py | 0 .../decoders => decoders}/i2cfilter/pd.py | 0 .../decoders => decoders}/i2s/__init__.py | 0 .../decoders => decoders}/i2s/pd.py | 0 .../decoders => decoders}/iec/__init__.py | 0 .../decoders => decoders}/iec/pd.py | 0 .../decoders => decoders}/ieee488/__init__.py | 0 .../decoders => decoders}/ieee488/pd.py | 0 .../decoders => decoders}/ir_irmp/__init__.py | 0 .../ir_irmp/irmp_library.py | 0 .../decoders => decoders}/ir_irmp/pd.py | 0 .../decoders => decoders}/ir_nec/__init__.py | 0 .../decoders => decoders}/ir_nec/lists.py | 0 .../decoders => decoders}/ir_nec/pd.py | 0 .../decoders => decoders}/ir_rc5/__init__.py | 0 .../decoders => decoders}/ir_rc5/lists.py | 0 .../decoders => decoders}/ir_rc5/pd.py | 0 .../decoders => decoders}/ir_rc6/__init__.py | 0 .../decoders => decoders}/ir_rc6/pd.py | 0 .../decoders => decoders}/ir_sirc/__init__.py | 0 .../decoders => decoders}/ir_sirc/lists.py | 0 .../decoders => decoders}/ir_sirc/pd.py | 0 .../decoders => decoders}/jitter/__init__.py | 0 .../decoders => decoders}/jitter/pd.py | 0 .../decoders => decoders}/jtag/__init__.py | 0 .../decoders => decoders}/jtag/pd.py | 0 .../jtag_ejtag/__init__.py | 0 .../decoders => decoders}/jtag_ejtag/pd.py | 0 .../jtag_stm32/__init__.py | 0 .../decoders => decoders}/jtag_stm32/pd.py | 0 .../decoders => decoders}/lfast/__init__.py | 0 .../decoders => decoders}/lfast/pd.py | 0 .../decoders => decoders}/lin/__init__.py | 0 .../decoders => decoders}/lin/pd.py | 0 .../decoders => decoders}/lm75/__init__.py | 0 .../decoders => decoders}/lm75/pd.py | 0 .../decoders => decoders}/lpc/__init__.py | 0 .../decoders => decoders}/lpc/pd.py | 0 .../decoders => decoders}/ltc242x/__init__.py | 0 .../decoders => decoders}/ltc242x/pd.py | 0 .../decoders => decoders}/ltc26x7/__init__.py | 0 .../decoders => decoders}/ltc26x7/pd.py | 0 .../maple_bus/__init__.py | 0 .../decoders => decoders}/maple_bus/pd.py | 0 .../decoders => decoders}/max7219/__init__.py | 0 .../decoders => decoders}/max7219/pd.py | 0 .../decoders => decoders}/mcs48/__init__.py | 0 .../decoders => decoders}/mcs48/pd.py | 0 .../decoders => decoders}/mdio/__init__.py | 0 .../decoders => decoders}/mdio/pd.py | 0 .../microwire/__init__.py | 0 .../decoders => decoders}/microwire/pd.py | 0 .../decoders => decoders}/midi/__init__.py | 0 .../decoders => decoders}/midi/lists.py | 0 .../decoders => decoders}/midi/pd.py | 0 .../decoders => decoders}/miller/__init__.py | 0 .../decoders => decoders}/miller/pd.py | 0 .../mipi_dsi/__init__.py | 0 .../decoders => decoders}/mipi_dsi/pd.py | 0 .../mipi_rffe/__init__.py | 0 .../decoders => decoders}/mipi_rffe/pd.py | 0 .../mlx90614/__init__.py | 0 .../decoders => decoders}/mlx90614/pd.py | 0 .../decoders => decoders}/modbus/__init__.py | 0 .../decoders => decoders}/modbus/pd.py | 0 .../decoders => decoders}/morse/__init__.py | 0 .../decoders => decoders}/morse/pd.py | 0 .../mrf24j40/__init__.py | 0 .../decoders => decoders}/mrf24j40/lists.py | 0 .../decoders => decoders}/mrf24j40/pd.py | 0 .../mxc6225xu/__init__.py | 0 .../decoders => decoders}/mxc6225xu/pd.py | 0 .../nes_gamepad/__init__.py | 0 .../decoders => decoders}/nes_gamepad/pd.py | 0 .../nrf24l01/__init__.py | 0 .../decoders => decoders}/nrf24l01/pd.py | 0 .../decoders => decoders}/nrf905/__init__.py | 0 .../decoders => decoders}/nrf905/pd.py | 0 .../numbers_and_state/__init__.py | 0 .../numbers_and_state/pd.py | 0 .../decoders => decoders}/nunchuk/__init__.py | 0 .../decoders => decoders}/nunchuk/pd.py | 0 .../onewire_link/__init__.py | 0 .../decoders => decoders}/onewire_link/pd.py | 0 .../onewire_network/__init__.py | 0 .../onewire_network/pd.py | 0 .../decoders => decoders}/ook/__init__.py | 0 .../decoders => decoders}/ook/pd.py | 0 .../ook_oregon/__init__.py | 0 .../decoders => decoders}/ook_oregon/lists.py | 0 .../decoders => decoders}/ook_oregon/pd.py | 0 .../decoders => decoders}/ook_vis/__init__.py | 0 .../decoders => decoders}/ook_vis/pd.py | 0 .../decoders => decoders}/pan1321/__init__.py | 0 .../decoders => decoders}/pan1321/pd.py | 0 .../parallel/__init__.py | 0 .../decoders => decoders}/parallel/pd.py | 0 .../decoders => decoders}/pca9571/__init__.py | 0 .../decoders => decoders}/pca9571/pd.py | 0 .../decoders => decoders}/pjdl/__init__.py | 0 .../decoders => decoders}/pjdl/pd.py | 0 .../decoders => decoders}/pjon/__init__.py | 0 .../decoders => decoders}/pjon/pd.py | 0 .../decoders => decoders}/ps2/__init__.py | 0 .../decoders => decoders}/ps2/pd.py | 0 .../decoders => decoders}/pwm/__init__.py | 0 .../decoders => decoders}/pwm/pd.py | 0 .../decoders => decoders}/qi/__init__.py | 0 .../decoders => decoders}/qi/pd.py | 0 .../decoders => decoders}/qspi/__init__.py | 0 .../decoders => decoders}/qspi/pd.py | 0 .../rc_encode/__init__.py | 0 .../decoders => decoders}/rc_encode/pd.py | 0 .../decoders => decoders}/rfm12/__init__.py | 0 .../decoders => decoders}/rfm12/pd.py | 0 .../rgb_led_spi/__init__.py | 0 .../decoders => decoders}/rgb_led_spi/pd.py | 0 .../rgb_led_ws281x/__init__.py | 0 .../rgb_led_ws281x/pd.py | 0 .../decoders => decoders}/rtc8564/__init__.py | 0 .../decoders => decoders}/rtc8564/pd.py | 0 .../sae_j1850_vpw/__init__.py | 0 .../decoders => decoders}/sae_j1850_vpw/pd.py | 0 .../decoders => decoders}/sda2506/__init__.py | 0 .../decoders => decoders}/sda2506/pd.py | 0 .../sdcard_sd/__init__.py | 0 .../decoders => decoders}/sdcard_sd/pd.py | 0 .../sdcard_spi/__init__.py | 0 .../decoders => decoders}/sdcard_spi/pd.py | 0 .../decoders => decoders}/sdq/__init__.py | 0 .../decoders => decoders}/sdq/pd.py | 0 .../seven_segment/__init__.py | 0 .../decoders => decoders}/seven_segment/pd.py | 0 .../signature/__init__.py | 0 .../decoders => decoders}/signature/pd.py | 0 .../decoders => decoders}/sipi/__init__.py | 0 .../decoders => decoders}/sipi/pd.py | 0 .../decoders => decoders}/sle44xx/__init__.py | 0 .../decoders => decoders}/sle44xx/pd.py | 0 .../decoders => decoders}/spdif/__init__.py | 0 .../decoders => decoders}/spdif/pd.py | 0 .../spiflash/__init__.py | 0 .../decoders => decoders}/spiflash/lists.py | 0 .../decoders => decoders}/spiflash/pd.py | 0 .../decoders => decoders}/ssi32/__init__.py | 0 .../decoders => decoders}/ssi32/pd.py | 0 .../st25r39xx_spi/__init__.py | 0 .../st25r39xx_spi/lists.py | 0 .../decoders => decoders}/st25r39xx_spi/pd.py | 0 .../decoders => decoders}/st7735/__init__.py | 0 .../decoders => decoders}/st7735/pd.py | 0 .../decoders => decoders}/st7789/__init__.py | 0 .../decoders => decoders}/st7789/pd.py | 0 .../stepper_motor/__init__.py | 0 .../decoders => decoders}/stepper_motor/pd.py | 0 .../decoders => decoders}/swd/__init__.py | 0 .../decoders => decoders}/swd/pd.py | 0 .../decoders => decoders}/swim/__init__.py | 0 .../decoders => decoders}/swim/pd.py | 0 .../decoders => decoders}/t55xx/__init__.py | 0 .../decoders => decoders}/t55xx/pd.py | 0 .../tca6408a/__init__.py | 0 .../decoders => decoders}/tca6408a/pd.py | 0 .../tdm_audio/__init__.py | 0 .../decoders => decoders}/tdm_audio/pd.py | 0 .../decoders => decoders}/timing/__init__.py | 0 .../decoders => decoders}/timing/pd.py | 0 .../decoders => decoders}/tlc5620/__init__.py | 0 .../decoders => decoders}/tlc5620/pd.py | 0 .../usb_packet/__init__.py | 0 .../decoders => decoders}/usb_packet/pd.py | 0 .../usb_power_delivery/__init__.py | 0 .../usb_power_delivery/pd.py | 0 .../usb_request/__init__.py | 0 .../decoders => decoders}/usb_request/pd.py | 0 .../usb_signalling/__init__.py | 0 .../usb_signalling/pd.py | 0 .../decoders => decoders}/wiegand/__init__.py | 0 .../decoders => decoders}/wiegand/pd.py | 0 .../decoders => decoders}/x2444m/__init__.py | 0 .../decoders => decoders}/x2444m/pd.py | 0 .../decoders => decoders}/xfp/__init__.py | 0 .../decoders => decoders}/xfp/pd.py | 0 .../decoders => decoders}/xy2-100/__init__.py | 0 .../decoders => decoders}/xy2-100/pd.py | 0 .../decoders => decoders}/z80/__init__.py | 0 .../decoders => decoders}/z80/pd.py | 0 .../decoders => decoders}/z80/tables.py | 0 doc/decoder.txt | 28 ++ libsigrokdecode4DSL/decoder.c | 14 +- libsigrokdecode4DSL/instance.c | 15 +- libsigrokdecode4DSL/libsigrokdecode.h | 22 +- libsigrokdecode4DSL/session.c | 1 + libsigrokdecode4DSL/srd.c | 3 +- libsigrokdecode4DSL/type_decoder.c | 129 +++++++- qtpro/DSView.pro.user | 4 +- .../tests => test/decode_test}/core.c | 0 .../tests => test/decode_test}/decoder.c | 0 .../tests => test/decode_test}/inst.c | 0 .../tests => test/decode_test}/lib.h | 0 .../tests => test/decode_test}/main.c | 0 .../tests => test/decode_test}/session.c | 0 333 files changed, 489 insertions(+), 274 deletions(-) rename {libsigrokdecode4DSL/decoders => decoders}/0-i2c/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/0-i2c/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/0-spi/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/0-spi/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/0-uart/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/0-uart/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/1-i2c/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/1-i2c/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/1-spi/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/1-spi/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/1-uart/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/1-uart/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/a7105/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/a7105/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ac97/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ac97/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ad5626/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ad5626/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ad79x0/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ad79x0/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ade77xx/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ade77xx/lists.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ade77xx/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/adf435x/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/adf435x/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/adns5020/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/adns5020/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/adxl345/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/adxl345/lists.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/adxl345/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/am230x/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/am230x/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/amulet_ascii/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/amulet_ascii/lists.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/amulet_ascii/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/arm_etmv3/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/arm_etmv3/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/arm_itm/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/arm_itm/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/arm_tpiu/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/arm_tpiu/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/atsha204a/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/atsha204a/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/aud/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/aud/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/avr_isp/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/avr_isp/parts.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/avr_isp/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/avr_pdi/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/avr_pdi/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/caliper/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/caliper/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/can/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/can/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/cc1101/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/cc1101/lists.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/cc1101/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/cec/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/cec/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/cec/protocoldata.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/cfp/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/cfp/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/cjtag-oscan0/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/cjtag-oscan0/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/common/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/common/plugtrx/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/common/plugtrx/mod.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/common/sdcard/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/common/sdcard/mod.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/common/srdhelper/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/common/srdhelper/mod.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/counter/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/counter/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/dali/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/dali/lists.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/dali/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/dcf77/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/dcf77/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/dmx512/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/dmx512/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ds1307/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ds1307/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ds2408/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ds2408/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ds243x/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ds243x/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ds28ea00/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ds28ea00/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/dsi/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/dsi/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/edid/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/edid/config (100%) rename {libsigrokdecode4DSL/decoders => decoders}/edid/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/edid/pnpids.txt (100%) rename {libsigrokdecode4DSL/decoders => decoders}/eeprom24xx/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/eeprom24xx/lists.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/eeprom24xx/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/eeprom93xx/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/eeprom93xx/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/em4100/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/em4100/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/em4305/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/em4305/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/enc28j60/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/enc28j60/lists.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/enc28j60/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/flexray/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/flexray/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/fsi/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/fsi/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/gpib/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/gpib/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/graycode/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/graycode/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/guess_bitrate/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/guess_bitrate/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/hdcp/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/hdcp/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/i2cdemux/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/i2cdemux/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/i2cfilter/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/i2cfilter/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/i2s/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/i2s/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/iec/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/iec/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ieee488/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ieee488/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ir_irmp/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ir_irmp/irmp_library.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ir_irmp/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ir_nec/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ir_nec/lists.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ir_nec/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ir_rc5/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ir_rc5/lists.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ir_rc5/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ir_rc6/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ir_rc6/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ir_sirc/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ir_sirc/lists.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ir_sirc/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/jitter/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/jitter/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/jtag/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/jtag/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/jtag_ejtag/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/jtag_ejtag/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/jtag_stm32/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/jtag_stm32/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/lfast/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/lfast/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/lin/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/lin/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/lm75/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/lm75/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/lpc/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/lpc/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ltc242x/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ltc242x/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ltc26x7/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ltc26x7/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/maple_bus/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/maple_bus/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/max7219/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/max7219/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/mcs48/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/mcs48/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/mdio/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/mdio/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/microwire/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/microwire/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/midi/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/midi/lists.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/midi/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/miller/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/miller/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/mipi_dsi/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/mipi_dsi/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/mipi_rffe/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/mipi_rffe/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/mlx90614/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/mlx90614/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/modbus/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/modbus/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/morse/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/morse/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/mrf24j40/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/mrf24j40/lists.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/mrf24j40/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/mxc6225xu/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/mxc6225xu/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/nes_gamepad/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/nes_gamepad/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/nrf24l01/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/nrf24l01/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/nrf905/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/nrf905/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/numbers_and_state/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/numbers_and_state/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/nunchuk/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/nunchuk/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/onewire_link/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/onewire_link/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/onewire_network/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/onewire_network/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ook/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ook/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ook_oregon/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ook_oregon/lists.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ook_oregon/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ook_vis/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ook_vis/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/pan1321/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/pan1321/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/parallel/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/parallel/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/pca9571/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/pca9571/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/pjdl/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/pjdl/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/pjon/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/pjon/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ps2/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ps2/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/pwm/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/pwm/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/qi/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/qi/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/qspi/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/qspi/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/rc_encode/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/rc_encode/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/rfm12/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/rfm12/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/rgb_led_spi/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/rgb_led_spi/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/rgb_led_ws281x/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/rgb_led_ws281x/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/rtc8564/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/rtc8564/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/sae_j1850_vpw/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/sae_j1850_vpw/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/sda2506/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/sda2506/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/sdcard_sd/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/sdcard_sd/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/sdcard_spi/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/sdcard_spi/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/sdq/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/sdq/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/seven_segment/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/seven_segment/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/signature/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/signature/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/sipi/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/sipi/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/sle44xx/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/sle44xx/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/spdif/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/spdif/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/spiflash/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/spiflash/lists.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/spiflash/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ssi32/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/ssi32/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/st25r39xx_spi/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/st25r39xx_spi/lists.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/st25r39xx_spi/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/st7735/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/st7735/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/st7789/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/st7789/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/stepper_motor/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/stepper_motor/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/swd/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/swd/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/swim/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/swim/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/t55xx/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/t55xx/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/tca6408a/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/tca6408a/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/tdm_audio/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/tdm_audio/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/timing/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/timing/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/tlc5620/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/tlc5620/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/usb_packet/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/usb_packet/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/usb_power_delivery/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/usb_power_delivery/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/usb_request/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/usb_request/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/usb_signalling/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/usb_signalling/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/wiegand/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/wiegand/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/x2444m/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/x2444m/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/xfp/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/xfp/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/xy2-100/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/xy2-100/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/z80/__init__.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/z80/pd.py (100%) rename {libsigrokdecode4DSL/decoders => decoders}/z80/tables.py (100%) create mode 100644 doc/decoder.txt rename {libsigrokdecode4DSL/tests => test/decode_test}/core.c (100%) rename {libsigrokdecode4DSL/tests => test/decode_test}/decoder.c (100%) rename {libsigrokdecode4DSL/tests => test/decode_test}/inst.c (100%) rename {libsigrokdecode4DSL/tests => test/decode_test}/lib.h (100%) rename {libsigrokdecode4DSL/tests => test/decode_test}/main.c (100%) rename {libsigrokdecode4DSL/tests => test/decode_test}/session.c (100%) diff --git a/DSView/pv/data/decode/AnnotationResTable.cpp b/DSView/pv/data/decode/AnnotationResTable.cpp index 805129f3..f9be9e16 100644 --- a/DSView/pv/data/decode/AnnotationResTable.cpp +++ b/DSView/pv/data/decode/AnnotationResTable.cpp @@ -21,36 +21,169 @@ #include "AnnotationResTable.h" #include +#include "../../dsvdef.h" + +#define DECODER_MAX_DATA_BLOCK_LEN 25 +#define FORMAT_TMP_BUFFER_SIZE 100 + +const char g_bin_cvt_table[] = "0000000100100011010001010110011110001001101010111100110111101111"; +char g_bin_format_tmp_buffer[FORMAT_TMP_BUFFER_SIZE + 3]; +char g_oct_format_tmp_buffer[FORMAT_TMP_BUFFER_SIZE + 6]; +char g_number_tmp_64[30]; + char* bin2oct_string(char *buf, int size, const char *bin, int len){ + char *wr = buf + size - 1; + *wr = 0; //end flag -AnnotationResTable::AnnotationResTable(){ - + char *rd = (char*)bin + len - 1; //move to last byte + char tmp[3]; + + while (rd >= bin && wr > buf) + { + wr--; + int num = 0; + + while (rd >= bin && num < 3) + { + tmp[2-num] = *rd; + rd--; + num++; + } + + //fill + while (num < 3) + { + tmp[2-num] = '0'; + ++num; + } + + if (strncmp(tmp, "000", 3) == 0) + *wr = '0'; + else if (strncmp(tmp, "001", 3) == 0) + *wr = '1'; + else if (strncmp(tmp, "010", 3) == 0) + *wr = '2'; + else if (strncmp(tmp, "011", 3) == 0) + *wr = '3'; + else if (strncmp(tmp, "100", 3) == 0) + *wr = '4'; + else if (strncmp(tmp, "101", 3) == 0) + *wr = '5'; + else if (strncmp(tmp, "110", 3) == 0) + *wr = '6'; + else if (strncmp(tmp, "111", 3) == 0) + *wr = '7'; + } + + return wr; } -AnnotationResTable::~AnnotationResTable(){ - +long long bin2long_string(const char *bin, int len) +{ + char *rd = (char *)bin + len - 1; //move to last byte + int dex = 0; + long long value = 0; + long long bv = 0; + + while (rd >= bin) + { + if (*rd == '1') + { + bv = 1 << dex; + value += bv; + } + rd--; + ++dex; + } + + return value; } -int AnnotationResTable::MakeIndex(const std::string &key, AnnotationStringList *&ls) + +int AnnotationResTable::MakeIndex(const std::string &key, AnnotationSourceItem* &newItem) { - auto fd =m_indexs.find(key); + auto fd = m_indexs.find(key); if (fd != m_indexs.end()){ return (*fd).second; } - + + AnnotationSourceItem *item = new AnnotationSourceItem(); + m_resourceTable.push_back(item); + + item->cur_display_format = -1; + item->is_numerical = false; + newItem = item; + int dex = m_indexs.size(); m_indexs[key] = dex; - - //make a new string vector - m_resourceTable.push_back(AnnotationStringList()); - ls = &m_resourceTable[dex]; - return dex; } -const AnnotationStringList& AnnotationResTable::GetString(int index){ - int num = m_resourceTable.size(); - assert(index >= 0 && index < num); +AnnotationSourceItem* AnnotationResTable::GetItem(int index){ + assert(index >= 0 && index < m_resourceTable.size()); return m_resourceTable[index]; } + +const char* AnnotationResTable::format_numberic(const char *hex_str, int fmt) +{ + assert(hex_str); + + //flow, convert to oct\dec\bin format + const char *data = hex_str; + if (data[0] == 0 || fmt == DecoderDataFormat::hex){ + return data; + } + + //convert to bin format + char *buf = g_bin_format_tmp_buffer + FORMAT_TMP_BUFFER_SIZE; + *(buf + 1) = 0; //set the end flag + *buf = 0; + + int len = strlen(data); + //buffer is not enough + if (len > DECODER_MAX_DATA_BLOCK_LEN){ + return data; + } + + char *rd = (char*)data + len - 1; //move to last byte + char c = 0; + int dex = 0; + + while (rd >= data) + { + c = *rd; + dex = (int)(c <= '9' ? (c - '0') : (c - 'A' + 10)); + char *ptable = (char*)g_bin_cvt_table + dex * 4; + + buf -= 4; //move to left for 4 bytes + buf[0] = ptable[0]; + buf[1] = ptable[1]; + buf[2] = ptable[2]; + buf[3] = ptable[3]; + + rd--; + } + + //get bin format + if (fmt == DecoderDataFormat::bin){ + return buf; + } + + //get oct format + if (fmt == DecoderDataFormat::oct){ + char *oct_buf = bin2oct_string(g_oct_format_tmp_buffer, + sizeof(g_oct_format_tmp_buffer), buf, len * 4); + return oct_buf; + } + + //64 bit integer + if (fmt == DecoderDataFormat::dec && len * 4 <= 64){ + long long lv = bin2long_string(buf, len *4); + g_number_tmp_64[0] = 0; + sprintf(g_number_tmp_64, "%lld", lv); + return g_number_tmp_64; + } + + return data; +} diff --git a/DSView/pv/data/decode/AnnotationResTable.h b/DSView/pv/data/decode/AnnotationResTable.h index 21639ae5..3d6ea3ed 100644 --- a/DSView/pv/data/decode/AnnotationResTable.h +++ b/DSView/pv/data/decode/AnnotationResTable.h @@ -26,23 +26,27 @@ #include #include -typedef std::vector AnnotationStringList; +struct AnnotationSourceItem +{ + bool is_numerical; + char str_number_hex[18]; //numerical value hex format string + std::vector src_lines; //the origin source string lines + std::vector cvt_lines; //the converted to bin/hex/oct format string lines + int cur_display_format; //current format as bin/ex/oct..., init with -1 +}; -class AnnotationResTable{ - +class AnnotationResTable +{ public: - AnnotationResTable(); + int MakeIndex(const std::string &key, AnnotationSourceItem* &newItem); + AnnotationSourceItem* GetItem(int index); - ~AnnotationResTable(); + inline int GetCount(){ + return m_resourceTable.size();} - int MakeIndex(const std::string &key, AnnotationStringList *&ls); - - const AnnotationStringList& GetString(int index); - - inline int GetCount(){return m_resourceTable.size();} - + static const char* format_numberic(const char *hex_str, int fmt); private: - std::map m_indexs; - std::vector m_resourceTable; + std::map m_indexs; + std::vector m_resourceTable; }; \ No newline at end of file diff --git a/DSView/pv/data/decode/annotation.cpp b/DSView/pv/data/decode/annotation.cpp index 1949e0ec..87c97c65 100755 --- a/DSView/pv/data/decode/annotation.cpp +++ b/DSView/pv/data/decode/annotation.cpp @@ -32,134 +32,84 @@ #include "../../config/appconfig.h" #include "decoderstatus.h" #include "../../dsvdef.h" + + //a find talbe instance +AnnotationResTable annTable; +char sz_format_tmp_buf[50]; -#define DECODER_MAX_DATA_BLOCK_LEN 300 -#define FORMAT_TMP_BUFFER_SIZE 1200 +bool is_hex_number_str(const char *str) +{ + char c = *str; -const char g_bin_cvt_table[] = "0000000100100011010001010110011110001001101010111100110111101111"; -char g_bin_format_tmp_buffer[FORMAT_TMP_BUFFER_SIZE + 3]; -char g_oct_format_tmp_buffer[FORMAT_TMP_BUFFER_SIZE + 6]; -std::vector g_format_ret_vector; - -char* bin2oct_string(char *buf, int size, const char *bin, int len){ - char *wr = buf + size - 1; - *wr = 0; //end flag - - char *rd = (char*)bin + len - 1; //move to last byte - - char tmp[3]; - - while (rd >= bin && wr > buf) - { - wr--; - - int num = 0; - - while (rd >= bin && num < 3) - { - tmp[2-num] = *rd; - rd--; - num++; - } - - //fill - while (num < 3) - { - tmp[2-num] = '0'; - ++num; - } - - - if (strncmp(tmp, "000", 3) == 0) - *wr = '0'; - else if (strncmp(tmp, "001", 3) == 0) - *wr = '1'; - else if (strncmp(tmp, "010", 3) == 0) - *wr = '2'; - else if (strncmp(tmp, "011", 3) == 0) - *wr = '3'; - else if (strncmp(tmp, "100", 3) == 0) - *wr = '4'; - else if (strncmp(tmp, "101", 3) == 0) - *wr = '5'; - else if (strncmp(tmp, "110", 3) == 0) - *wr = '6'; - else if (strncmp(tmp, "111", 3) == 0) - *wr = '7'; - } - - return wr; -} - -long long bin2long_string(const char *bin, int len) -{ - char *rd = (char *)bin + len - 1; //move to last byte - int dex = 0; - long long value = 0; - long long bv = 0; - - while (rd >= bin) + while (c) { - if (*rd == '1') - { - bv = 1 << dex; - value += bv; + if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')){ + c = *str; + str++; + continue; } - rd--; - ++dex; + return false; } - - return value; + + return true; } namespace pv { namespace data { namespace decode { - -//a find talbe instance -AnnotationResTable *Annotation::m_resTable = new AnnotationResTable(); - -Annotation::Annotation(const srd_proto_data *const pdata, DecoderStatus *status) : - _start_sample(pdata->start_sample), - _end_sample(pdata->end_sample) + +Annotation::Annotation(const srd_proto_data *const pdata, DecoderStatus *status) { assert(pdata); const srd_proto_data_annotation *const pda = (const srd_proto_data_annotation*)pdata->data; assert(pda); - _format = pda->ann_class; - _type = pda->ann_type; - _status = status; - - //have numerical - if (_type >= 100 && _type < 200){ - status->m_bNumerical = true; - } - - _strIndex = 0; - - std::string key; + _start_sample = pdata->start_sample; + _end_sample = pdata->end_sample; + _format = pda->ann_class; + _type = pda->ann_type; + _resIndex = 0; + _status = status; + //make resource find key - const char *const *annotations = (char**)pda->ann_text; - while(*annotations) { - const char *ptr = *annotations; - key.append(ptr, strlen(ptr)); + std::string key; + + char **annotations = pda->ann_text; + while(annotations && *annotations) { + key.append(*annotations, strlen(*annotations)); annotations++; } - - AnnotationStringList *annotationArray = NULL; - _strIndex = Annotation::m_resTable->MakeIndex(key, annotationArray); + + if (pda->str_number_hex[0]){ + //append numeric string + key.append(pda->str_number_hex, strlen(pda->str_number_hex)); + } + + AnnotationSourceItem *resItem = NULL; + _resIndex = annTable.MakeIndex(key, resItem); - //save new string lines - if (annotationArray){ - annotations = (char **)pda->ann_text; - while (*annotations) - { - annotationArray->push_back(QString::fromUtf8(*annotations)); - annotations++; + //is a new item + if (resItem != NULL){ + char **annotations = pda->ann_text; + while(annotations && *annotations) { + resItem->src_lines.push_back(QString::fromUtf8(*annotations)); + annotations++; } - } + + //get numerical data + if (pda->str_number_hex[0]){ + strcpy(resItem->str_number_hex, pda->str_number_hex); + resItem->is_numerical = true; + } + else if (resItem->src_lines.size() == 1 && _type >= 100 && _type < 200){ + if (is_hex_number_str(resItem->src_lines[0].toLatin1().data())){ + resItem->is_numerical = true; + } + } + + _status->m_bNumerical |= resItem->is_numerical; + } } Annotation::Annotation() @@ -172,93 +122,52 @@ Annotation::~Annotation() { } - - - + const std::vector& Annotation::annotations() const { assert(_status); - - int fmt = _status->m_format; - const std::vector& vct = Annotation::m_resTable->GetString(_strIndex); - - if (!(_type >= 100 && _type < 200) || fmt == DecoderDataFormat::ascii || fmt == DecoderDataFormat::hex){ - return vct; + + AnnotationSourceItem &resItem = *annTable.GetItem(_resIndex); + + //get origin data, is not a numberical value + if (!resItem.is_numerical){ + return resItem.src_lines; } - if (vct.size() != 1){ - return vct; + + if (resItem.cur_display_format != _status->m_format){ + resItem.cur_display_format = _status->m_format; + resItem.cvt_lines.clear(); + + if (resItem.src_lines.size() > 0) + { + for (QString &rd_src : resItem.src_lines) + { + if (resItem.str_number_hex[0] != 0) + { + QString src = rd_src.replace("{$}", "%s"); + const char *num_str = AnnotationResTable::format_numberic(resItem.str_number_hex, resItem.cur_display_format); + sprintf(sz_format_tmp_buf, src.toLatin1().data(), num_str); + resItem.cvt_lines.push_back(QString(sz_format_tmp_buf)); + } + else + { + const char *src_str = rd_src.toLatin1().data(); + const char *num_str = AnnotationResTable::format_numberic(src_str, resItem.cur_display_format); + if (src_str != num_str) + resItem.cvt_lines.push_back(QString(num_str)); + else + resItem.cvt_lines.push_back(QString(rd_src)); + } + } + } + else{ + const char *num_str = AnnotationResTable::format_numberic(resItem.str_number_hex, resItem.cur_display_format); + resItem.cvt_lines.push_back(QString(num_str)); + } } - //flow, convert to oct\dec\bin format - const char *data = vct[0].toStdString().c_str(); - if (*data == 0 || *data == '['){ - return vct; - } - - //convert to bin format - char *buf = g_bin_format_tmp_buffer + FORMAT_TMP_BUFFER_SIZE; - *(buf + 1) = 0; //set the end flag - *buf = 0; - - int len = strlen(data); - //buffer is not enough - if (len > DECODER_MAX_DATA_BLOCK_LEN){ - return vct; - } - - char *rd = (char*)data + len - 1; //move to last byte - char c = 0; - int dex = 0; - - while (rd >= data) - { - c = *rd; - dex = (int)(c <= '9' ? (c - '0') : (c - 'A' + 10)); - char *ptable = (char*)g_bin_cvt_table + dex * 4; - - buf -= 4; //move to left for 4 bytes - buf[0] = ptable[0]; - buf[1] = ptable[1]; - buf[2] = ptable[2]; - buf[3] = ptable[3]; - - rd--; - } - - std::vector &vct2 = g_format_ret_vector; - if (vct2.size() == 0){ - vct2.push_back(QString()); - } - - //get bin format - if (fmt == DecoderDataFormat::bin){ - vct2[0].clear(); - vct2[0].append(buf); - return vct2; - } - - //get oct format - if (fmt == DecoderDataFormat::oct){ - char *oct_buf = bin2oct_string(g_oct_format_tmp_buffer, - sizeof(g_oct_format_tmp_buffer), buf, len * 4); - vct2[0].clear(); - vct2[0].append(oct_buf); - return vct2; - } - - //64 bit integer - if (fmt == DecoderDataFormat::dec && len * 4 <= 64){ - long long lv = bin2long_string(buf, len *4); - char vbuf[30] = {0}; - sprintf(vbuf, "%lld", lv); - - vct2[0].clear(); - vct2[0].append(vbuf); - return vct2; - } - - return vct2; -} + return resItem.cvt_lines; +} } // namespace decode diff --git a/DSView/pv/data/decode/annotation.h b/DSView/pv/data/decode/annotation.h index 2e8d359e..f2025776 100755 --- a/DSView/pv/data/decode/annotation.h +++ b/DSView/pv/data/decode/annotation.h @@ -66,14 +66,12 @@ public: const std::vector& annotations() const; private: - uint64_t _start_sample; - uint64_t _end_sample; - short _format; - short _type; //100-199: is a numerical value type,can show hex/oct format - short _strIndex; - DecoderStatus *_status; - - static AnnotationResTable * m_resTable; + uint64_t _start_sample; + uint64_t _end_sample; + short _format; + short _type; + short _resIndex; + DecoderStatus *_status; /*a global variable*/ }; } // namespace decode diff --git a/DSView/pv/data/decode/decoder.cpp b/DSView/pv/data/decode/decoder.cpp index 4c2e80f0..81e4f1c7 100755 --- a/DSView/pv/data/decode/decoder.cpp +++ b/DSView/pv/data/decode/decoder.cpp @@ -127,9 +127,7 @@ srd_decoder_inst* Decoder::create_decoder_inst(srd_session *session) GHashTable *const probes = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_variant_unref); - for(std::map:: - const_iterator i = _probes.begin(); - i != _probes.end(); i++) + for(auto i = _probes.begin(); i != _probes.end(); i++) { GVariant *const gvar = g_variant_new_int32((*i).second); g_variant_ref_sink(gvar); diff --git a/DSView/pv/data/decoderstack.cpp b/DSView/pv/data/decoderstack.cpp index 9a32a7ab..7b7f3930 100755 --- a/DSView/pv/data/decoderstack.cpp +++ b/DSView/pv/data/decoderstack.cpp @@ -463,6 +463,8 @@ void DecoderStack::decode_data(const uint64_t decode_start, const uint64_t decod { decode_task_status *status = _stask_stauts; + // qDebug()<<"decode start:"< lock(_output_mutex); _samples_decoded = i - decode_start + 1; diff --git a/DSView/pv/dock/protocoldock.cpp b/DSView/pv/dock/protocoldock.cpp index 28cf86b0..9a49da9c 100755 --- a/DSView/pv/dock/protocoldock.cpp +++ b/DSView/pv/dock/protocoldock.cpp @@ -484,6 +484,8 @@ void ProtocolDock::item_clicked(const QModelIndex &index) decoder_stack->set_mark_index((ann.start_sample()+ann.end_sample())/2); _session->show_region(ann.start_sample(), ann.end_sample(), false); + + // qDebug()<resizeRowToContents(index.row()); @@ -652,31 +654,44 @@ void ProtocolDock::search_nxt() _cur_search_index = -1; return; } + int i = 0; uint64_t rowCount = _model_proxy.rowCount(); QModelIndex matchingIndex; pv::data::DecoderModel *decoder_model = _session->get_decoder_model(); + auto decoder_stack = decoder_model->getDecoderStack(); + + if (decoder_stack == NULL){ + qDebug()<<"decoder_stack is null"; + return; + } - auto decoder_stack = decoder_model->getDecoderStack(); do { _cur_search_index++; if (_cur_search_index < 0 || _cur_search_index >= _model_proxy.rowCount()) _cur_search_index = 0; matchingIndex = _model_proxy.mapToSource(_model_proxy.index(floor(_cur_search_index),_model_proxy.filterKeyColumn())); - if (!decoder_stack || !matchingIndex.isValid()) + + if (!matchingIndex.isValid()) break; + + // qDebug()<<"row:"<list_annotation(ann, col, row); row++; }while(ann_valid && (ann.type() < 100 || ann.type() > 999)); + + auto strlist = ann.annotations(); QString source = ann.annotations().at(0); if (ann_valid && source.contains(nxt)) i++; @@ -748,7 +763,6 @@ void ProtocolDock::search_update() search_done(); } _search_edited = false; - //search_done(); } //-------------------IProtocolItemLayerCallback diff --git a/DSView/pv/dock/protocoldock.h b/DSView/pv/dock/protocoldock.h index 2fc198e1..c01245f0 100755 --- a/DSView/pv/dock/protocoldock.h +++ b/DSView/pv/dock/protocoldock.h @@ -117,7 +117,7 @@ private: SigSession *_session; view::View &_view; QSortFilterProxyModel _model_proxy; - double _cur_search_index; + int _cur_search_index; QStringList _str_list; QSplitter *_split_widget; diff --git a/DSView/pv/dock/protocolitemlayer.cpp b/DSView/pv/dock/protocolitemlayer.cpp index 4dfe4cfb..784c2a19 100644 --- a/DSView/pv/dock/protocolitemlayer.cpp +++ b/DSView/pv/dock/protocolitemlayer.cpp @@ -120,20 +120,14 @@ void ProtocolItemLayer::LoadFormatSelect(bool bSingle) m_singleFlag = bSingle; m_bSetting = true; - _format_combox->clear(); - _format_combox->addItem("ascii"); - int dex = 0; + _format_combox->clear(); - if (!bSingle) - { - _format_combox->addItem("dec"); - _format_combox->addItem("hex"); - _format_combox->addItem("oct"); - _format_combox->addItem("bin"); - dex = 2; - } + _format_combox->addItem("hex"); + _format_combox->addItem("dec"); + _format_combox->addItem("oct"); + _format_combox->addItem("bin"); - _format_combox->setCurrentIndex(dex); + _format_combox->setCurrentIndex(0); m_bSetting = false; } diff --git a/DSView/pv/dsvdef.cpp b/DSView/pv/dsvdef.cpp index 0ad7c4ef..35c57072 100644 --- a/DSView/pv/dsvdef.cpp +++ b/DSView/pv/dsvdef.cpp @@ -41,9 +41,6 @@ namespace DecoderDataFormat { int Parse(const char *name){ - if (strcmp(name, "ascii") == 0){ - return (int)ascii; - } if (strcmp(name, "dec") == 0){ return (int)dec; } @@ -56,7 +53,7 @@ namespace DecoderDataFormat if (strcmp(name, "bin") == 0){ return (int)bin; } - return (int)ascii; + return (int)hex; } } diff --git a/DSView/pv/dsvdef.h b/DSView/pv/dsvdef.h index b2b26002..fc209a79 100644 --- a/DSView/pv/dsvdef.h +++ b/DSView/pv/dsvdef.h @@ -49,9 +49,8 @@ namespace DecoderDataFormat { enum _data_format { - ascii = 0, - dec, hex, + dec, oct, bin }; diff --git a/libsigrokdecode4DSL/decoders/0-i2c/__init__.py b/decoders/0-i2c/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/0-i2c/__init__.py rename to decoders/0-i2c/__init__.py diff --git a/libsigrokdecode4DSL/decoders/0-i2c/pd.py b/decoders/0-i2c/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/0-i2c/pd.py rename to decoders/0-i2c/pd.py diff --git a/libsigrokdecode4DSL/decoders/0-spi/__init__.py b/decoders/0-spi/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/0-spi/__init__.py rename to decoders/0-spi/__init__.py diff --git a/libsigrokdecode4DSL/decoders/0-spi/pd.py b/decoders/0-spi/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/0-spi/pd.py rename to decoders/0-spi/pd.py diff --git a/libsigrokdecode4DSL/decoders/0-uart/__init__.py b/decoders/0-uart/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/0-uart/__init__.py rename to decoders/0-uart/__init__.py diff --git a/libsigrokdecode4DSL/decoders/0-uart/pd.py b/decoders/0-uart/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/0-uart/pd.py rename to decoders/0-uart/pd.py diff --git a/libsigrokdecode4DSL/decoders/1-i2c/__init__.py b/decoders/1-i2c/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/1-i2c/__init__.py rename to decoders/1-i2c/__init__.py diff --git a/libsigrokdecode4DSL/decoders/1-i2c/pd.py b/decoders/1-i2c/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/1-i2c/pd.py rename to decoders/1-i2c/pd.py diff --git a/libsigrokdecode4DSL/decoders/1-spi/__init__.py b/decoders/1-spi/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/1-spi/__init__.py rename to decoders/1-spi/__init__.py diff --git a/libsigrokdecode4DSL/decoders/1-spi/pd.py b/decoders/1-spi/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/1-spi/pd.py rename to decoders/1-spi/pd.py diff --git a/libsigrokdecode4DSL/decoders/1-uart/__init__.py b/decoders/1-uart/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/1-uart/__init__.py rename to decoders/1-uart/__init__.py diff --git a/libsigrokdecode4DSL/decoders/1-uart/pd.py b/decoders/1-uart/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/1-uart/pd.py rename to decoders/1-uart/pd.py diff --git a/libsigrokdecode4DSL/decoders/a7105/__init__.py b/decoders/a7105/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/a7105/__init__.py rename to decoders/a7105/__init__.py diff --git a/libsigrokdecode4DSL/decoders/a7105/pd.py b/decoders/a7105/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/a7105/pd.py rename to decoders/a7105/pd.py diff --git a/libsigrokdecode4DSL/decoders/ac97/__init__.py b/decoders/ac97/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ac97/__init__.py rename to decoders/ac97/__init__.py diff --git a/libsigrokdecode4DSL/decoders/ac97/pd.py b/decoders/ac97/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ac97/pd.py rename to decoders/ac97/pd.py diff --git a/libsigrokdecode4DSL/decoders/ad5626/__init__.py b/decoders/ad5626/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ad5626/__init__.py rename to decoders/ad5626/__init__.py diff --git a/libsigrokdecode4DSL/decoders/ad5626/pd.py b/decoders/ad5626/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ad5626/pd.py rename to decoders/ad5626/pd.py diff --git a/libsigrokdecode4DSL/decoders/ad79x0/__init__.py b/decoders/ad79x0/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ad79x0/__init__.py rename to decoders/ad79x0/__init__.py diff --git a/libsigrokdecode4DSL/decoders/ad79x0/pd.py b/decoders/ad79x0/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ad79x0/pd.py rename to decoders/ad79x0/pd.py diff --git a/libsigrokdecode4DSL/decoders/ade77xx/__init__.py b/decoders/ade77xx/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ade77xx/__init__.py rename to decoders/ade77xx/__init__.py diff --git a/libsigrokdecode4DSL/decoders/ade77xx/lists.py b/decoders/ade77xx/lists.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ade77xx/lists.py rename to decoders/ade77xx/lists.py diff --git a/libsigrokdecode4DSL/decoders/ade77xx/pd.py b/decoders/ade77xx/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ade77xx/pd.py rename to decoders/ade77xx/pd.py diff --git a/libsigrokdecode4DSL/decoders/adf435x/__init__.py b/decoders/adf435x/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/adf435x/__init__.py rename to decoders/adf435x/__init__.py diff --git a/libsigrokdecode4DSL/decoders/adf435x/pd.py b/decoders/adf435x/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/adf435x/pd.py rename to decoders/adf435x/pd.py diff --git a/libsigrokdecode4DSL/decoders/adns5020/__init__.py b/decoders/adns5020/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/adns5020/__init__.py rename to decoders/adns5020/__init__.py diff --git a/libsigrokdecode4DSL/decoders/adns5020/pd.py b/decoders/adns5020/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/adns5020/pd.py rename to decoders/adns5020/pd.py diff --git a/libsigrokdecode4DSL/decoders/adxl345/__init__.py b/decoders/adxl345/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/adxl345/__init__.py rename to decoders/adxl345/__init__.py diff --git a/libsigrokdecode4DSL/decoders/adxl345/lists.py b/decoders/adxl345/lists.py similarity index 100% rename from libsigrokdecode4DSL/decoders/adxl345/lists.py rename to decoders/adxl345/lists.py diff --git a/libsigrokdecode4DSL/decoders/adxl345/pd.py b/decoders/adxl345/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/adxl345/pd.py rename to decoders/adxl345/pd.py diff --git a/libsigrokdecode4DSL/decoders/am230x/__init__.py b/decoders/am230x/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/am230x/__init__.py rename to decoders/am230x/__init__.py diff --git a/libsigrokdecode4DSL/decoders/am230x/pd.py b/decoders/am230x/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/am230x/pd.py rename to decoders/am230x/pd.py diff --git a/libsigrokdecode4DSL/decoders/amulet_ascii/__init__.py b/decoders/amulet_ascii/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/amulet_ascii/__init__.py rename to decoders/amulet_ascii/__init__.py diff --git a/libsigrokdecode4DSL/decoders/amulet_ascii/lists.py b/decoders/amulet_ascii/lists.py similarity index 100% rename from libsigrokdecode4DSL/decoders/amulet_ascii/lists.py rename to decoders/amulet_ascii/lists.py diff --git a/libsigrokdecode4DSL/decoders/amulet_ascii/pd.py b/decoders/amulet_ascii/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/amulet_ascii/pd.py rename to decoders/amulet_ascii/pd.py diff --git a/libsigrokdecode4DSL/decoders/arm_etmv3/__init__.py b/decoders/arm_etmv3/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/arm_etmv3/__init__.py rename to decoders/arm_etmv3/__init__.py diff --git a/libsigrokdecode4DSL/decoders/arm_etmv3/pd.py b/decoders/arm_etmv3/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/arm_etmv3/pd.py rename to decoders/arm_etmv3/pd.py diff --git a/libsigrokdecode4DSL/decoders/arm_itm/__init__.py b/decoders/arm_itm/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/arm_itm/__init__.py rename to decoders/arm_itm/__init__.py diff --git a/libsigrokdecode4DSL/decoders/arm_itm/pd.py b/decoders/arm_itm/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/arm_itm/pd.py rename to decoders/arm_itm/pd.py diff --git a/libsigrokdecode4DSL/decoders/arm_tpiu/__init__.py b/decoders/arm_tpiu/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/arm_tpiu/__init__.py rename to decoders/arm_tpiu/__init__.py diff --git a/libsigrokdecode4DSL/decoders/arm_tpiu/pd.py b/decoders/arm_tpiu/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/arm_tpiu/pd.py rename to decoders/arm_tpiu/pd.py diff --git a/libsigrokdecode4DSL/decoders/atsha204a/__init__.py b/decoders/atsha204a/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/atsha204a/__init__.py rename to decoders/atsha204a/__init__.py diff --git a/libsigrokdecode4DSL/decoders/atsha204a/pd.py b/decoders/atsha204a/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/atsha204a/pd.py rename to decoders/atsha204a/pd.py diff --git a/libsigrokdecode4DSL/decoders/aud/__init__.py b/decoders/aud/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/aud/__init__.py rename to decoders/aud/__init__.py diff --git a/libsigrokdecode4DSL/decoders/aud/pd.py b/decoders/aud/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/aud/pd.py rename to decoders/aud/pd.py diff --git a/libsigrokdecode4DSL/decoders/avr_isp/__init__.py b/decoders/avr_isp/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/avr_isp/__init__.py rename to decoders/avr_isp/__init__.py diff --git a/libsigrokdecode4DSL/decoders/avr_isp/parts.py b/decoders/avr_isp/parts.py similarity index 100% rename from libsigrokdecode4DSL/decoders/avr_isp/parts.py rename to decoders/avr_isp/parts.py diff --git a/libsigrokdecode4DSL/decoders/avr_isp/pd.py b/decoders/avr_isp/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/avr_isp/pd.py rename to decoders/avr_isp/pd.py diff --git a/libsigrokdecode4DSL/decoders/avr_pdi/__init__.py b/decoders/avr_pdi/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/avr_pdi/__init__.py rename to decoders/avr_pdi/__init__.py diff --git a/libsigrokdecode4DSL/decoders/avr_pdi/pd.py b/decoders/avr_pdi/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/avr_pdi/pd.py rename to decoders/avr_pdi/pd.py diff --git a/libsigrokdecode4DSL/decoders/caliper/__init__.py b/decoders/caliper/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/caliper/__init__.py rename to decoders/caliper/__init__.py diff --git a/libsigrokdecode4DSL/decoders/caliper/pd.py b/decoders/caliper/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/caliper/pd.py rename to decoders/caliper/pd.py diff --git a/libsigrokdecode4DSL/decoders/can/__init__.py b/decoders/can/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/can/__init__.py rename to decoders/can/__init__.py diff --git a/libsigrokdecode4DSL/decoders/can/pd.py b/decoders/can/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/can/pd.py rename to decoders/can/pd.py diff --git a/libsigrokdecode4DSL/decoders/cc1101/__init__.py b/decoders/cc1101/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/cc1101/__init__.py rename to decoders/cc1101/__init__.py diff --git a/libsigrokdecode4DSL/decoders/cc1101/lists.py b/decoders/cc1101/lists.py similarity index 100% rename from libsigrokdecode4DSL/decoders/cc1101/lists.py rename to decoders/cc1101/lists.py diff --git a/libsigrokdecode4DSL/decoders/cc1101/pd.py b/decoders/cc1101/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/cc1101/pd.py rename to decoders/cc1101/pd.py diff --git a/libsigrokdecode4DSL/decoders/cec/__init__.py b/decoders/cec/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/cec/__init__.py rename to decoders/cec/__init__.py diff --git a/libsigrokdecode4DSL/decoders/cec/pd.py b/decoders/cec/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/cec/pd.py rename to decoders/cec/pd.py diff --git a/libsigrokdecode4DSL/decoders/cec/protocoldata.py b/decoders/cec/protocoldata.py similarity index 100% rename from libsigrokdecode4DSL/decoders/cec/protocoldata.py rename to decoders/cec/protocoldata.py diff --git a/libsigrokdecode4DSL/decoders/cfp/__init__.py b/decoders/cfp/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/cfp/__init__.py rename to decoders/cfp/__init__.py diff --git a/libsigrokdecode4DSL/decoders/cfp/pd.py b/decoders/cfp/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/cfp/pd.py rename to decoders/cfp/pd.py diff --git a/libsigrokdecode4DSL/decoders/cjtag-oscan0/__init__.py b/decoders/cjtag-oscan0/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/cjtag-oscan0/__init__.py rename to decoders/cjtag-oscan0/__init__.py diff --git a/libsigrokdecode4DSL/decoders/cjtag-oscan0/pd.py b/decoders/cjtag-oscan0/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/cjtag-oscan0/pd.py rename to decoders/cjtag-oscan0/pd.py diff --git a/libsigrokdecode4DSL/decoders/common/__init__.py b/decoders/common/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/common/__init__.py rename to decoders/common/__init__.py diff --git a/libsigrokdecode4DSL/decoders/common/plugtrx/__init__.py b/decoders/common/plugtrx/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/common/plugtrx/__init__.py rename to decoders/common/plugtrx/__init__.py diff --git a/libsigrokdecode4DSL/decoders/common/plugtrx/mod.py b/decoders/common/plugtrx/mod.py similarity index 100% rename from libsigrokdecode4DSL/decoders/common/plugtrx/mod.py rename to decoders/common/plugtrx/mod.py diff --git a/libsigrokdecode4DSL/decoders/common/sdcard/__init__.py b/decoders/common/sdcard/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/common/sdcard/__init__.py rename to decoders/common/sdcard/__init__.py diff --git a/libsigrokdecode4DSL/decoders/common/sdcard/mod.py b/decoders/common/sdcard/mod.py similarity index 100% rename from libsigrokdecode4DSL/decoders/common/sdcard/mod.py rename to decoders/common/sdcard/mod.py diff --git a/libsigrokdecode4DSL/decoders/common/srdhelper/__init__.py b/decoders/common/srdhelper/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/common/srdhelper/__init__.py rename to decoders/common/srdhelper/__init__.py diff --git a/libsigrokdecode4DSL/decoders/common/srdhelper/mod.py b/decoders/common/srdhelper/mod.py similarity index 100% rename from libsigrokdecode4DSL/decoders/common/srdhelper/mod.py rename to decoders/common/srdhelper/mod.py diff --git a/libsigrokdecode4DSL/decoders/counter/__init__.py b/decoders/counter/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/counter/__init__.py rename to decoders/counter/__init__.py diff --git a/libsigrokdecode4DSL/decoders/counter/pd.py b/decoders/counter/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/counter/pd.py rename to decoders/counter/pd.py diff --git a/libsigrokdecode4DSL/decoders/dali/__init__.py b/decoders/dali/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/dali/__init__.py rename to decoders/dali/__init__.py diff --git a/libsigrokdecode4DSL/decoders/dali/lists.py b/decoders/dali/lists.py similarity index 100% rename from libsigrokdecode4DSL/decoders/dali/lists.py rename to decoders/dali/lists.py diff --git a/libsigrokdecode4DSL/decoders/dali/pd.py b/decoders/dali/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/dali/pd.py rename to decoders/dali/pd.py diff --git a/libsigrokdecode4DSL/decoders/dcf77/__init__.py b/decoders/dcf77/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/dcf77/__init__.py rename to decoders/dcf77/__init__.py diff --git a/libsigrokdecode4DSL/decoders/dcf77/pd.py b/decoders/dcf77/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/dcf77/pd.py rename to decoders/dcf77/pd.py diff --git a/libsigrokdecode4DSL/decoders/dmx512/__init__.py b/decoders/dmx512/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/dmx512/__init__.py rename to decoders/dmx512/__init__.py diff --git a/libsigrokdecode4DSL/decoders/dmx512/pd.py b/decoders/dmx512/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/dmx512/pd.py rename to decoders/dmx512/pd.py diff --git a/libsigrokdecode4DSL/decoders/ds1307/__init__.py b/decoders/ds1307/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ds1307/__init__.py rename to decoders/ds1307/__init__.py diff --git a/libsigrokdecode4DSL/decoders/ds1307/pd.py b/decoders/ds1307/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ds1307/pd.py rename to decoders/ds1307/pd.py diff --git a/libsigrokdecode4DSL/decoders/ds2408/__init__.py b/decoders/ds2408/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ds2408/__init__.py rename to decoders/ds2408/__init__.py diff --git a/libsigrokdecode4DSL/decoders/ds2408/pd.py b/decoders/ds2408/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ds2408/pd.py rename to decoders/ds2408/pd.py diff --git a/libsigrokdecode4DSL/decoders/ds243x/__init__.py b/decoders/ds243x/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ds243x/__init__.py rename to decoders/ds243x/__init__.py diff --git a/libsigrokdecode4DSL/decoders/ds243x/pd.py b/decoders/ds243x/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ds243x/pd.py rename to decoders/ds243x/pd.py diff --git a/libsigrokdecode4DSL/decoders/ds28ea00/__init__.py b/decoders/ds28ea00/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ds28ea00/__init__.py rename to decoders/ds28ea00/__init__.py diff --git a/libsigrokdecode4DSL/decoders/ds28ea00/pd.py b/decoders/ds28ea00/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ds28ea00/pd.py rename to decoders/ds28ea00/pd.py diff --git a/libsigrokdecode4DSL/decoders/dsi/__init__.py b/decoders/dsi/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/dsi/__init__.py rename to decoders/dsi/__init__.py diff --git a/libsigrokdecode4DSL/decoders/dsi/pd.py b/decoders/dsi/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/dsi/pd.py rename to decoders/dsi/pd.py diff --git a/libsigrokdecode4DSL/decoders/edid/__init__.py b/decoders/edid/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/edid/__init__.py rename to decoders/edid/__init__.py diff --git a/libsigrokdecode4DSL/decoders/edid/config b/decoders/edid/config similarity index 100% rename from libsigrokdecode4DSL/decoders/edid/config rename to decoders/edid/config diff --git a/libsigrokdecode4DSL/decoders/edid/pd.py b/decoders/edid/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/edid/pd.py rename to decoders/edid/pd.py diff --git a/libsigrokdecode4DSL/decoders/edid/pnpids.txt b/decoders/edid/pnpids.txt similarity index 100% rename from libsigrokdecode4DSL/decoders/edid/pnpids.txt rename to decoders/edid/pnpids.txt diff --git a/libsigrokdecode4DSL/decoders/eeprom24xx/__init__.py b/decoders/eeprom24xx/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/eeprom24xx/__init__.py rename to decoders/eeprom24xx/__init__.py diff --git a/libsigrokdecode4DSL/decoders/eeprom24xx/lists.py b/decoders/eeprom24xx/lists.py similarity index 100% rename from libsigrokdecode4DSL/decoders/eeprom24xx/lists.py rename to decoders/eeprom24xx/lists.py diff --git a/libsigrokdecode4DSL/decoders/eeprom24xx/pd.py b/decoders/eeprom24xx/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/eeprom24xx/pd.py rename to decoders/eeprom24xx/pd.py diff --git a/libsigrokdecode4DSL/decoders/eeprom93xx/__init__.py b/decoders/eeprom93xx/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/eeprom93xx/__init__.py rename to decoders/eeprom93xx/__init__.py diff --git a/libsigrokdecode4DSL/decoders/eeprom93xx/pd.py b/decoders/eeprom93xx/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/eeprom93xx/pd.py rename to decoders/eeprom93xx/pd.py diff --git a/libsigrokdecode4DSL/decoders/em4100/__init__.py b/decoders/em4100/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/em4100/__init__.py rename to decoders/em4100/__init__.py diff --git a/libsigrokdecode4DSL/decoders/em4100/pd.py b/decoders/em4100/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/em4100/pd.py rename to decoders/em4100/pd.py diff --git a/libsigrokdecode4DSL/decoders/em4305/__init__.py b/decoders/em4305/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/em4305/__init__.py rename to decoders/em4305/__init__.py diff --git a/libsigrokdecode4DSL/decoders/em4305/pd.py b/decoders/em4305/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/em4305/pd.py rename to decoders/em4305/pd.py diff --git a/libsigrokdecode4DSL/decoders/enc28j60/__init__.py b/decoders/enc28j60/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/enc28j60/__init__.py rename to decoders/enc28j60/__init__.py diff --git a/libsigrokdecode4DSL/decoders/enc28j60/lists.py b/decoders/enc28j60/lists.py similarity index 100% rename from libsigrokdecode4DSL/decoders/enc28j60/lists.py rename to decoders/enc28j60/lists.py diff --git a/libsigrokdecode4DSL/decoders/enc28j60/pd.py b/decoders/enc28j60/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/enc28j60/pd.py rename to decoders/enc28j60/pd.py diff --git a/libsigrokdecode4DSL/decoders/flexray/__init__.py b/decoders/flexray/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/flexray/__init__.py rename to decoders/flexray/__init__.py diff --git a/libsigrokdecode4DSL/decoders/flexray/pd.py b/decoders/flexray/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/flexray/pd.py rename to decoders/flexray/pd.py diff --git a/libsigrokdecode4DSL/decoders/fsi/__init__.py b/decoders/fsi/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/fsi/__init__.py rename to decoders/fsi/__init__.py diff --git a/libsigrokdecode4DSL/decoders/fsi/pd.py b/decoders/fsi/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/fsi/pd.py rename to decoders/fsi/pd.py diff --git a/libsigrokdecode4DSL/decoders/gpib/__init__.py b/decoders/gpib/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/gpib/__init__.py rename to decoders/gpib/__init__.py diff --git a/libsigrokdecode4DSL/decoders/gpib/pd.py b/decoders/gpib/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/gpib/pd.py rename to decoders/gpib/pd.py diff --git a/libsigrokdecode4DSL/decoders/graycode/__init__.py b/decoders/graycode/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/graycode/__init__.py rename to decoders/graycode/__init__.py diff --git a/libsigrokdecode4DSL/decoders/graycode/pd.py b/decoders/graycode/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/graycode/pd.py rename to decoders/graycode/pd.py diff --git a/libsigrokdecode4DSL/decoders/guess_bitrate/__init__.py b/decoders/guess_bitrate/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/guess_bitrate/__init__.py rename to decoders/guess_bitrate/__init__.py diff --git a/libsigrokdecode4DSL/decoders/guess_bitrate/pd.py b/decoders/guess_bitrate/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/guess_bitrate/pd.py rename to decoders/guess_bitrate/pd.py diff --git a/libsigrokdecode4DSL/decoders/hdcp/__init__.py b/decoders/hdcp/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/hdcp/__init__.py rename to decoders/hdcp/__init__.py diff --git a/libsigrokdecode4DSL/decoders/hdcp/pd.py b/decoders/hdcp/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/hdcp/pd.py rename to decoders/hdcp/pd.py diff --git a/libsigrokdecode4DSL/decoders/i2cdemux/__init__.py b/decoders/i2cdemux/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/i2cdemux/__init__.py rename to decoders/i2cdemux/__init__.py diff --git a/libsigrokdecode4DSL/decoders/i2cdemux/pd.py b/decoders/i2cdemux/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/i2cdemux/pd.py rename to decoders/i2cdemux/pd.py diff --git a/libsigrokdecode4DSL/decoders/i2cfilter/__init__.py b/decoders/i2cfilter/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/i2cfilter/__init__.py rename to decoders/i2cfilter/__init__.py diff --git a/libsigrokdecode4DSL/decoders/i2cfilter/pd.py b/decoders/i2cfilter/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/i2cfilter/pd.py rename to decoders/i2cfilter/pd.py diff --git a/libsigrokdecode4DSL/decoders/i2s/__init__.py b/decoders/i2s/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/i2s/__init__.py rename to decoders/i2s/__init__.py diff --git a/libsigrokdecode4DSL/decoders/i2s/pd.py b/decoders/i2s/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/i2s/pd.py rename to decoders/i2s/pd.py diff --git a/libsigrokdecode4DSL/decoders/iec/__init__.py b/decoders/iec/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/iec/__init__.py rename to decoders/iec/__init__.py diff --git a/libsigrokdecode4DSL/decoders/iec/pd.py b/decoders/iec/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/iec/pd.py rename to decoders/iec/pd.py diff --git a/libsigrokdecode4DSL/decoders/ieee488/__init__.py b/decoders/ieee488/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ieee488/__init__.py rename to decoders/ieee488/__init__.py diff --git a/libsigrokdecode4DSL/decoders/ieee488/pd.py b/decoders/ieee488/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ieee488/pd.py rename to decoders/ieee488/pd.py diff --git a/libsigrokdecode4DSL/decoders/ir_irmp/__init__.py b/decoders/ir_irmp/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ir_irmp/__init__.py rename to decoders/ir_irmp/__init__.py diff --git a/libsigrokdecode4DSL/decoders/ir_irmp/irmp_library.py b/decoders/ir_irmp/irmp_library.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ir_irmp/irmp_library.py rename to decoders/ir_irmp/irmp_library.py diff --git a/libsigrokdecode4DSL/decoders/ir_irmp/pd.py b/decoders/ir_irmp/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ir_irmp/pd.py rename to decoders/ir_irmp/pd.py diff --git a/libsigrokdecode4DSL/decoders/ir_nec/__init__.py b/decoders/ir_nec/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ir_nec/__init__.py rename to decoders/ir_nec/__init__.py diff --git a/libsigrokdecode4DSL/decoders/ir_nec/lists.py b/decoders/ir_nec/lists.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ir_nec/lists.py rename to decoders/ir_nec/lists.py diff --git a/libsigrokdecode4DSL/decoders/ir_nec/pd.py b/decoders/ir_nec/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ir_nec/pd.py rename to decoders/ir_nec/pd.py diff --git a/libsigrokdecode4DSL/decoders/ir_rc5/__init__.py b/decoders/ir_rc5/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ir_rc5/__init__.py rename to decoders/ir_rc5/__init__.py diff --git a/libsigrokdecode4DSL/decoders/ir_rc5/lists.py b/decoders/ir_rc5/lists.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ir_rc5/lists.py rename to decoders/ir_rc5/lists.py diff --git a/libsigrokdecode4DSL/decoders/ir_rc5/pd.py b/decoders/ir_rc5/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ir_rc5/pd.py rename to decoders/ir_rc5/pd.py diff --git a/libsigrokdecode4DSL/decoders/ir_rc6/__init__.py b/decoders/ir_rc6/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ir_rc6/__init__.py rename to decoders/ir_rc6/__init__.py diff --git a/libsigrokdecode4DSL/decoders/ir_rc6/pd.py b/decoders/ir_rc6/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ir_rc6/pd.py rename to decoders/ir_rc6/pd.py diff --git a/libsigrokdecode4DSL/decoders/ir_sirc/__init__.py b/decoders/ir_sirc/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ir_sirc/__init__.py rename to decoders/ir_sirc/__init__.py diff --git a/libsigrokdecode4DSL/decoders/ir_sirc/lists.py b/decoders/ir_sirc/lists.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ir_sirc/lists.py rename to decoders/ir_sirc/lists.py diff --git a/libsigrokdecode4DSL/decoders/ir_sirc/pd.py b/decoders/ir_sirc/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ir_sirc/pd.py rename to decoders/ir_sirc/pd.py diff --git a/libsigrokdecode4DSL/decoders/jitter/__init__.py b/decoders/jitter/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/jitter/__init__.py rename to decoders/jitter/__init__.py diff --git a/libsigrokdecode4DSL/decoders/jitter/pd.py b/decoders/jitter/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/jitter/pd.py rename to decoders/jitter/pd.py diff --git a/libsigrokdecode4DSL/decoders/jtag/__init__.py b/decoders/jtag/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/jtag/__init__.py rename to decoders/jtag/__init__.py diff --git a/libsigrokdecode4DSL/decoders/jtag/pd.py b/decoders/jtag/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/jtag/pd.py rename to decoders/jtag/pd.py diff --git a/libsigrokdecode4DSL/decoders/jtag_ejtag/__init__.py b/decoders/jtag_ejtag/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/jtag_ejtag/__init__.py rename to decoders/jtag_ejtag/__init__.py diff --git a/libsigrokdecode4DSL/decoders/jtag_ejtag/pd.py b/decoders/jtag_ejtag/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/jtag_ejtag/pd.py rename to decoders/jtag_ejtag/pd.py diff --git a/libsigrokdecode4DSL/decoders/jtag_stm32/__init__.py b/decoders/jtag_stm32/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/jtag_stm32/__init__.py rename to decoders/jtag_stm32/__init__.py diff --git a/libsigrokdecode4DSL/decoders/jtag_stm32/pd.py b/decoders/jtag_stm32/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/jtag_stm32/pd.py rename to decoders/jtag_stm32/pd.py diff --git a/libsigrokdecode4DSL/decoders/lfast/__init__.py b/decoders/lfast/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/lfast/__init__.py rename to decoders/lfast/__init__.py diff --git a/libsigrokdecode4DSL/decoders/lfast/pd.py b/decoders/lfast/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/lfast/pd.py rename to decoders/lfast/pd.py diff --git a/libsigrokdecode4DSL/decoders/lin/__init__.py b/decoders/lin/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/lin/__init__.py rename to decoders/lin/__init__.py diff --git a/libsigrokdecode4DSL/decoders/lin/pd.py b/decoders/lin/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/lin/pd.py rename to decoders/lin/pd.py diff --git a/libsigrokdecode4DSL/decoders/lm75/__init__.py b/decoders/lm75/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/lm75/__init__.py rename to decoders/lm75/__init__.py diff --git a/libsigrokdecode4DSL/decoders/lm75/pd.py b/decoders/lm75/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/lm75/pd.py rename to decoders/lm75/pd.py diff --git a/libsigrokdecode4DSL/decoders/lpc/__init__.py b/decoders/lpc/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/lpc/__init__.py rename to decoders/lpc/__init__.py diff --git a/libsigrokdecode4DSL/decoders/lpc/pd.py b/decoders/lpc/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/lpc/pd.py rename to decoders/lpc/pd.py diff --git a/libsigrokdecode4DSL/decoders/ltc242x/__init__.py b/decoders/ltc242x/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ltc242x/__init__.py rename to decoders/ltc242x/__init__.py diff --git a/libsigrokdecode4DSL/decoders/ltc242x/pd.py b/decoders/ltc242x/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ltc242x/pd.py rename to decoders/ltc242x/pd.py diff --git a/libsigrokdecode4DSL/decoders/ltc26x7/__init__.py b/decoders/ltc26x7/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ltc26x7/__init__.py rename to decoders/ltc26x7/__init__.py diff --git a/libsigrokdecode4DSL/decoders/ltc26x7/pd.py b/decoders/ltc26x7/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ltc26x7/pd.py rename to decoders/ltc26x7/pd.py diff --git a/libsigrokdecode4DSL/decoders/maple_bus/__init__.py b/decoders/maple_bus/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/maple_bus/__init__.py rename to decoders/maple_bus/__init__.py diff --git a/libsigrokdecode4DSL/decoders/maple_bus/pd.py b/decoders/maple_bus/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/maple_bus/pd.py rename to decoders/maple_bus/pd.py diff --git a/libsigrokdecode4DSL/decoders/max7219/__init__.py b/decoders/max7219/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/max7219/__init__.py rename to decoders/max7219/__init__.py diff --git a/libsigrokdecode4DSL/decoders/max7219/pd.py b/decoders/max7219/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/max7219/pd.py rename to decoders/max7219/pd.py diff --git a/libsigrokdecode4DSL/decoders/mcs48/__init__.py b/decoders/mcs48/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/mcs48/__init__.py rename to decoders/mcs48/__init__.py diff --git a/libsigrokdecode4DSL/decoders/mcs48/pd.py b/decoders/mcs48/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/mcs48/pd.py rename to decoders/mcs48/pd.py diff --git a/libsigrokdecode4DSL/decoders/mdio/__init__.py b/decoders/mdio/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/mdio/__init__.py rename to decoders/mdio/__init__.py diff --git a/libsigrokdecode4DSL/decoders/mdio/pd.py b/decoders/mdio/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/mdio/pd.py rename to decoders/mdio/pd.py diff --git a/libsigrokdecode4DSL/decoders/microwire/__init__.py b/decoders/microwire/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/microwire/__init__.py rename to decoders/microwire/__init__.py diff --git a/libsigrokdecode4DSL/decoders/microwire/pd.py b/decoders/microwire/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/microwire/pd.py rename to decoders/microwire/pd.py diff --git a/libsigrokdecode4DSL/decoders/midi/__init__.py b/decoders/midi/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/midi/__init__.py rename to decoders/midi/__init__.py diff --git a/libsigrokdecode4DSL/decoders/midi/lists.py b/decoders/midi/lists.py similarity index 100% rename from libsigrokdecode4DSL/decoders/midi/lists.py rename to decoders/midi/lists.py diff --git a/libsigrokdecode4DSL/decoders/midi/pd.py b/decoders/midi/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/midi/pd.py rename to decoders/midi/pd.py diff --git a/libsigrokdecode4DSL/decoders/miller/__init__.py b/decoders/miller/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/miller/__init__.py rename to decoders/miller/__init__.py diff --git a/libsigrokdecode4DSL/decoders/miller/pd.py b/decoders/miller/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/miller/pd.py rename to decoders/miller/pd.py diff --git a/libsigrokdecode4DSL/decoders/mipi_dsi/__init__.py b/decoders/mipi_dsi/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/mipi_dsi/__init__.py rename to decoders/mipi_dsi/__init__.py diff --git a/libsigrokdecode4DSL/decoders/mipi_dsi/pd.py b/decoders/mipi_dsi/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/mipi_dsi/pd.py rename to decoders/mipi_dsi/pd.py diff --git a/libsigrokdecode4DSL/decoders/mipi_rffe/__init__.py b/decoders/mipi_rffe/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/mipi_rffe/__init__.py rename to decoders/mipi_rffe/__init__.py diff --git a/libsigrokdecode4DSL/decoders/mipi_rffe/pd.py b/decoders/mipi_rffe/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/mipi_rffe/pd.py rename to decoders/mipi_rffe/pd.py diff --git a/libsigrokdecode4DSL/decoders/mlx90614/__init__.py b/decoders/mlx90614/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/mlx90614/__init__.py rename to decoders/mlx90614/__init__.py diff --git a/libsigrokdecode4DSL/decoders/mlx90614/pd.py b/decoders/mlx90614/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/mlx90614/pd.py rename to decoders/mlx90614/pd.py diff --git a/libsigrokdecode4DSL/decoders/modbus/__init__.py b/decoders/modbus/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/modbus/__init__.py rename to decoders/modbus/__init__.py diff --git a/libsigrokdecode4DSL/decoders/modbus/pd.py b/decoders/modbus/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/modbus/pd.py rename to decoders/modbus/pd.py diff --git a/libsigrokdecode4DSL/decoders/morse/__init__.py b/decoders/morse/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/morse/__init__.py rename to decoders/morse/__init__.py diff --git a/libsigrokdecode4DSL/decoders/morse/pd.py b/decoders/morse/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/morse/pd.py rename to decoders/morse/pd.py diff --git a/libsigrokdecode4DSL/decoders/mrf24j40/__init__.py b/decoders/mrf24j40/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/mrf24j40/__init__.py rename to decoders/mrf24j40/__init__.py diff --git a/libsigrokdecode4DSL/decoders/mrf24j40/lists.py b/decoders/mrf24j40/lists.py similarity index 100% rename from libsigrokdecode4DSL/decoders/mrf24j40/lists.py rename to decoders/mrf24j40/lists.py diff --git a/libsigrokdecode4DSL/decoders/mrf24j40/pd.py b/decoders/mrf24j40/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/mrf24j40/pd.py rename to decoders/mrf24j40/pd.py diff --git a/libsigrokdecode4DSL/decoders/mxc6225xu/__init__.py b/decoders/mxc6225xu/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/mxc6225xu/__init__.py rename to decoders/mxc6225xu/__init__.py diff --git a/libsigrokdecode4DSL/decoders/mxc6225xu/pd.py b/decoders/mxc6225xu/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/mxc6225xu/pd.py rename to decoders/mxc6225xu/pd.py diff --git a/libsigrokdecode4DSL/decoders/nes_gamepad/__init__.py b/decoders/nes_gamepad/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/nes_gamepad/__init__.py rename to decoders/nes_gamepad/__init__.py diff --git a/libsigrokdecode4DSL/decoders/nes_gamepad/pd.py b/decoders/nes_gamepad/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/nes_gamepad/pd.py rename to decoders/nes_gamepad/pd.py diff --git a/libsigrokdecode4DSL/decoders/nrf24l01/__init__.py b/decoders/nrf24l01/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/nrf24l01/__init__.py rename to decoders/nrf24l01/__init__.py diff --git a/libsigrokdecode4DSL/decoders/nrf24l01/pd.py b/decoders/nrf24l01/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/nrf24l01/pd.py rename to decoders/nrf24l01/pd.py diff --git a/libsigrokdecode4DSL/decoders/nrf905/__init__.py b/decoders/nrf905/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/nrf905/__init__.py rename to decoders/nrf905/__init__.py diff --git a/libsigrokdecode4DSL/decoders/nrf905/pd.py b/decoders/nrf905/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/nrf905/pd.py rename to decoders/nrf905/pd.py diff --git a/libsigrokdecode4DSL/decoders/numbers_and_state/__init__.py b/decoders/numbers_and_state/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/numbers_and_state/__init__.py rename to decoders/numbers_and_state/__init__.py diff --git a/libsigrokdecode4DSL/decoders/numbers_and_state/pd.py b/decoders/numbers_and_state/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/numbers_and_state/pd.py rename to decoders/numbers_and_state/pd.py diff --git a/libsigrokdecode4DSL/decoders/nunchuk/__init__.py b/decoders/nunchuk/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/nunchuk/__init__.py rename to decoders/nunchuk/__init__.py diff --git a/libsigrokdecode4DSL/decoders/nunchuk/pd.py b/decoders/nunchuk/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/nunchuk/pd.py rename to decoders/nunchuk/pd.py diff --git a/libsigrokdecode4DSL/decoders/onewire_link/__init__.py b/decoders/onewire_link/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/onewire_link/__init__.py rename to decoders/onewire_link/__init__.py diff --git a/libsigrokdecode4DSL/decoders/onewire_link/pd.py b/decoders/onewire_link/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/onewire_link/pd.py rename to decoders/onewire_link/pd.py diff --git a/libsigrokdecode4DSL/decoders/onewire_network/__init__.py b/decoders/onewire_network/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/onewire_network/__init__.py rename to decoders/onewire_network/__init__.py diff --git a/libsigrokdecode4DSL/decoders/onewire_network/pd.py b/decoders/onewire_network/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/onewire_network/pd.py rename to decoders/onewire_network/pd.py diff --git a/libsigrokdecode4DSL/decoders/ook/__init__.py b/decoders/ook/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ook/__init__.py rename to decoders/ook/__init__.py diff --git a/libsigrokdecode4DSL/decoders/ook/pd.py b/decoders/ook/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ook/pd.py rename to decoders/ook/pd.py diff --git a/libsigrokdecode4DSL/decoders/ook_oregon/__init__.py b/decoders/ook_oregon/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ook_oregon/__init__.py rename to decoders/ook_oregon/__init__.py diff --git a/libsigrokdecode4DSL/decoders/ook_oregon/lists.py b/decoders/ook_oregon/lists.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ook_oregon/lists.py rename to decoders/ook_oregon/lists.py diff --git a/libsigrokdecode4DSL/decoders/ook_oregon/pd.py b/decoders/ook_oregon/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ook_oregon/pd.py rename to decoders/ook_oregon/pd.py diff --git a/libsigrokdecode4DSL/decoders/ook_vis/__init__.py b/decoders/ook_vis/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ook_vis/__init__.py rename to decoders/ook_vis/__init__.py diff --git a/libsigrokdecode4DSL/decoders/ook_vis/pd.py b/decoders/ook_vis/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ook_vis/pd.py rename to decoders/ook_vis/pd.py diff --git a/libsigrokdecode4DSL/decoders/pan1321/__init__.py b/decoders/pan1321/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/pan1321/__init__.py rename to decoders/pan1321/__init__.py diff --git a/libsigrokdecode4DSL/decoders/pan1321/pd.py b/decoders/pan1321/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/pan1321/pd.py rename to decoders/pan1321/pd.py diff --git a/libsigrokdecode4DSL/decoders/parallel/__init__.py b/decoders/parallel/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/parallel/__init__.py rename to decoders/parallel/__init__.py diff --git a/libsigrokdecode4DSL/decoders/parallel/pd.py b/decoders/parallel/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/parallel/pd.py rename to decoders/parallel/pd.py diff --git a/libsigrokdecode4DSL/decoders/pca9571/__init__.py b/decoders/pca9571/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/pca9571/__init__.py rename to decoders/pca9571/__init__.py diff --git a/libsigrokdecode4DSL/decoders/pca9571/pd.py b/decoders/pca9571/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/pca9571/pd.py rename to decoders/pca9571/pd.py diff --git a/libsigrokdecode4DSL/decoders/pjdl/__init__.py b/decoders/pjdl/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/pjdl/__init__.py rename to decoders/pjdl/__init__.py diff --git a/libsigrokdecode4DSL/decoders/pjdl/pd.py b/decoders/pjdl/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/pjdl/pd.py rename to decoders/pjdl/pd.py diff --git a/libsigrokdecode4DSL/decoders/pjon/__init__.py b/decoders/pjon/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/pjon/__init__.py rename to decoders/pjon/__init__.py diff --git a/libsigrokdecode4DSL/decoders/pjon/pd.py b/decoders/pjon/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/pjon/pd.py rename to decoders/pjon/pd.py diff --git a/libsigrokdecode4DSL/decoders/ps2/__init__.py b/decoders/ps2/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ps2/__init__.py rename to decoders/ps2/__init__.py diff --git a/libsigrokdecode4DSL/decoders/ps2/pd.py b/decoders/ps2/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ps2/pd.py rename to decoders/ps2/pd.py diff --git a/libsigrokdecode4DSL/decoders/pwm/__init__.py b/decoders/pwm/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/pwm/__init__.py rename to decoders/pwm/__init__.py diff --git a/libsigrokdecode4DSL/decoders/pwm/pd.py b/decoders/pwm/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/pwm/pd.py rename to decoders/pwm/pd.py diff --git a/libsigrokdecode4DSL/decoders/qi/__init__.py b/decoders/qi/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/qi/__init__.py rename to decoders/qi/__init__.py diff --git a/libsigrokdecode4DSL/decoders/qi/pd.py b/decoders/qi/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/qi/pd.py rename to decoders/qi/pd.py diff --git a/libsigrokdecode4DSL/decoders/qspi/__init__.py b/decoders/qspi/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/qspi/__init__.py rename to decoders/qspi/__init__.py diff --git a/libsigrokdecode4DSL/decoders/qspi/pd.py b/decoders/qspi/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/qspi/pd.py rename to decoders/qspi/pd.py diff --git a/libsigrokdecode4DSL/decoders/rc_encode/__init__.py b/decoders/rc_encode/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/rc_encode/__init__.py rename to decoders/rc_encode/__init__.py diff --git a/libsigrokdecode4DSL/decoders/rc_encode/pd.py b/decoders/rc_encode/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/rc_encode/pd.py rename to decoders/rc_encode/pd.py diff --git a/libsigrokdecode4DSL/decoders/rfm12/__init__.py b/decoders/rfm12/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/rfm12/__init__.py rename to decoders/rfm12/__init__.py diff --git a/libsigrokdecode4DSL/decoders/rfm12/pd.py b/decoders/rfm12/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/rfm12/pd.py rename to decoders/rfm12/pd.py diff --git a/libsigrokdecode4DSL/decoders/rgb_led_spi/__init__.py b/decoders/rgb_led_spi/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/rgb_led_spi/__init__.py rename to decoders/rgb_led_spi/__init__.py diff --git a/libsigrokdecode4DSL/decoders/rgb_led_spi/pd.py b/decoders/rgb_led_spi/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/rgb_led_spi/pd.py rename to decoders/rgb_led_spi/pd.py diff --git a/libsigrokdecode4DSL/decoders/rgb_led_ws281x/__init__.py b/decoders/rgb_led_ws281x/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/rgb_led_ws281x/__init__.py rename to decoders/rgb_led_ws281x/__init__.py diff --git a/libsigrokdecode4DSL/decoders/rgb_led_ws281x/pd.py b/decoders/rgb_led_ws281x/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/rgb_led_ws281x/pd.py rename to decoders/rgb_led_ws281x/pd.py diff --git a/libsigrokdecode4DSL/decoders/rtc8564/__init__.py b/decoders/rtc8564/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/rtc8564/__init__.py rename to decoders/rtc8564/__init__.py diff --git a/libsigrokdecode4DSL/decoders/rtc8564/pd.py b/decoders/rtc8564/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/rtc8564/pd.py rename to decoders/rtc8564/pd.py diff --git a/libsigrokdecode4DSL/decoders/sae_j1850_vpw/__init__.py b/decoders/sae_j1850_vpw/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/sae_j1850_vpw/__init__.py rename to decoders/sae_j1850_vpw/__init__.py diff --git a/libsigrokdecode4DSL/decoders/sae_j1850_vpw/pd.py b/decoders/sae_j1850_vpw/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/sae_j1850_vpw/pd.py rename to decoders/sae_j1850_vpw/pd.py diff --git a/libsigrokdecode4DSL/decoders/sda2506/__init__.py b/decoders/sda2506/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/sda2506/__init__.py rename to decoders/sda2506/__init__.py diff --git a/libsigrokdecode4DSL/decoders/sda2506/pd.py b/decoders/sda2506/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/sda2506/pd.py rename to decoders/sda2506/pd.py diff --git a/libsigrokdecode4DSL/decoders/sdcard_sd/__init__.py b/decoders/sdcard_sd/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/sdcard_sd/__init__.py rename to decoders/sdcard_sd/__init__.py diff --git a/libsigrokdecode4DSL/decoders/sdcard_sd/pd.py b/decoders/sdcard_sd/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/sdcard_sd/pd.py rename to decoders/sdcard_sd/pd.py diff --git a/libsigrokdecode4DSL/decoders/sdcard_spi/__init__.py b/decoders/sdcard_spi/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/sdcard_spi/__init__.py rename to decoders/sdcard_spi/__init__.py diff --git a/libsigrokdecode4DSL/decoders/sdcard_spi/pd.py b/decoders/sdcard_spi/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/sdcard_spi/pd.py rename to decoders/sdcard_spi/pd.py diff --git a/libsigrokdecode4DSL/decoders/sdq/__init__.py b/decoders/sdq/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/sdq/__init__.py rename to decoders/sdq/__init__.py diff --git a/libsigrokdecode4DSL/decoders/sdq/pd.py b/decoders/sdq/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/sdq/pd.py rename to decoders/sdq/pd.py diff --git a/libsigrokdecode4DSL/decoders/seven_segment/__init__.py b/decoders/seven_segment/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/seven_segment/__init__.py rename to decoders/seven_segment/__init__.py diff --git a/libsigrokdecode4DSL/decoders/seven_segment/pd.py b/decoders/seven_segment/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/seven_segment/pd.py rename to decoders/seven_segment/pd.py diff --git a/libsigrokdecode4DSL/decoders/signature/__init__.py b/decoders/signature/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/signature/__init__.py rename to decoders/signature/__init__.py diff --git a/libsigrokdecode4DSL/decoders/signature/pd.py b/decoders/signature/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/signature/pd.py rename to decoders/signature/pd.py diff --git a/libsigrokdecode4DSL/decoders/sipi/__init__.py b/decoders/sipi/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/sipi/__init__.py rename to decoders/sipi/__init__.py diff --git a/libsigrokdecode4DSL/decoders/sipi/pd.py b/decoders/sipi/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/sipi/pd.py rename to decoders/sipi/pd.py diff --git a/libsigrokdecode4DSL/decoders/sle44xx/__init__.py b/decoders/sle44xx/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/sle44xx/__init__.py rename to decoders/sle44xx/__init__.py diff --git a/libsigrokdecode4DSL/decoders/sle44xx/pd.py b/decoders/sle44xx/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/sle44xx/pd.py rename to decoders/sle44xx/pd.py diff --git a/libsigrokdecode4DSL/decoders/spdif/__init__.py b/decoders/spdif/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/spdif/__init__.py rename to decoders/spdif/__init__.py diff --git a/libsigrokdecode4DSL/decoders/spdif/pd.py b/decoders/spdif/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/spdif/pd.py rename to decoders/spdif/pd.py diff --git a/libsigrokdecode4DSL/decoders/spiflash/__init__.py b/decoders/spiflash/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/spiflash/__init__.py rename to decoders/spiflash/__init__.py diff --git a/libsigrokdecode4DSL/decoders/spiflash/lists.py b/decoders/spiflash/lists.py similarity index 100% rename from libsigrokdecode4DSL/decoders/spiflash/lists.py rename to decoders/spiflash/lists.py diff --git a/libsigrokdecode4DSL/decoders/spiflash/pd.py b/decoders/spiflash/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/spiflash/pd.py rename to decoders/spiflash/pd.py diff --git a/libsigrokdecode4DSL/decoders/ssi32/__init__.py b/decoders/ssi32/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ssi32/__init__.py rename to decoders/ssi32/__init__.py diff --git a/libsigrokdecode4DSL/decoders/ssi32/pd.py b/decoders/ssi32/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/ssi32/pd.py rename to decoders/ssi32/pd.py diff --git a/libsigrokdecode4DSL/decoders/st25r39xx_spi/__init__.py b/decoders/st25r39xx_spi/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/st25r39xx_spi/__init__.py rename to decoders/st25r39xx_spi/__init__.py diff --git a/libsigrokdecode4DSL/decoders/st25r39xx_spi/lists.py b/decoders/st25r39xx_spi/lists.py similarity index 100% rename from libsigrokdecode4DSL/decoders/st25r39xx_spi/lists.py rename to decoders/st25r39xx_spi/lists.py diff --git a/libsigrokdecode4DSL/decoders/st25r39xx_spi/pd.py b/decoders/st25r39xx_spi/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/st25r39xx_spi/pd.py rename to decoders/st25r39xx_spi/pd.py diff --git a/libsigrokdecode4DSL/decoders/st7735/__init__.py b/decoders/st7735/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/st7735/__init__.py rename to decoders/st7735/__init__.py diff --git a/libsigrokdecode4DSL/decoders/st7735/pd.py b/decoders/st7735/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/st7735/pd.py rename to decoders/st7735/pd.py diff --git a/libsigrokdecode4DSL/decoders/st7789/__init__.py b/decoders/st7789/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/st7789/__init__.py rename to decoders/st7789/__init__.py diff --git a/libsigrokdecode4DSL/decoders/st7789/pd.py b/decoders/st7789/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/st7789/pd.py rename to decoders/st7789/pd.py diff --git a/libsigrokdecode4DSL/decoders/stepper_motor/__init__.py b/decoders/stepper_motor/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/stepper_motor/__init__.py rename to decoders/stepper_motor/__init__.py diff --git a/libsigrokdecode4DSL/decoders/stepper_motor/pd.py b/decoders/stepper_motor/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/stepper_motor/pd.py rename to decoders/stepper_motor/pd.py diff --git a/libsigrokdecode4DSL/decoders/swd/__init__.py b/decoders/swd/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/swd/__init__.py rename to decoders/swd/__init__.py diff --git a/libsigrokdecode4DSL/decoders/swd/pd.py b/decoders/swd/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/swd/pd.py rename to decoders/swd/pd.py diff --git a/libsigrokdecode4DSL/decoders/swim/__init__.py b/decoders/swim/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/swim/__init__.py rename to decoders/swim/__init__.py diff --git a/libsigrokdecode4DSL/decoders/swim/pd.py b/decoders/swim/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/swim/pd.py rename to decoders/swim/pd.py diff --git a/libsigrokdecode4DSL/decoders/t55xx/__init__.py b/decoders/t55xx/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/t55xx/__init__.py rename to decoders/t55xx/__init__.py diff --git a/libsigrokdecode4DSL/decoders/t55xx/pd.py b/decoders/t55xx/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/t55xx/pd.py rename to decoders/t55xx/pd.py diff --git a/libsigrokdecode4DSL/decoders/tca6408a/__init__.py b/decoders/tca6408a/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/tca6408a/__init__.py rename to decoders/tca6408a/__init__.py diff --git a/libsigrokdecode4DSL/decoders/tca6408a/pd.py b/decoders/tca6408a/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/tca6408a/pd.py rename to decoders/tca6408a/pd.py diff --git a/libsigrokdecode4DSL/decoders/tdm_audio/__init__.py b/decoders/tdm_audio/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/tdm_audio/__init__.py rename to decoders/tdm_audio/__init__.py diff --git a/libsigrokdecode4DSL/decoders/tdm_audio/pd.py b/decoders/tdm_audio/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/tdm_audio/pd.py rename to decoders/tdm_audio/pd.py diff --git a/libsigrokdecode4DSL/decoders/timing/__init__.py b/decoders/timing/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/timing/__init__.py rename to decoders/timing/__init__.py diff --git a/libsigrokdecode4DSL/decoders/timing/pd.py b/decoders/timing/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/timing/pd.py rename to decoders/timing/pd.py diff --git a/libsigrokdecode4DSL/decoders/tlc5620/__init__.py b/decoders/tlc5620/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/tlc5620/__init__.py rename to decoders/tlc5620/__init__.py diff --git a/libsigrokdecode4DSL/decoders/tlc5620/pd.py b/decoders/tlc5620/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/tlc5620/pd.py rename to decoders/tlc5620/pd.py diff --git a/libsigrokdecode4DSL/decoders/usb_packet/__init__.py b/decoders/usb_packet/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/usb_packet/__init__.py rename to decoders/usb_packet/__init__.py diff --git a/libsigrokdecode4DSL/decoders/usb_packet/pd.py b/decoders/usb_packet/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/usb_packet/pd.py rename to decoders/usb_packet/pd.py diff --git a/libsigrokdecode4DSL/decoders/usb_power_delivery/__init__.py b/decoders/usb_power_delivery/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/usb_power_delivery/__init__.py rename to decoders/usb_power_delivery/__init__.py diff --git a/libsigrokdecode4DSL/decoders/usb_power_delivery/pd.py b/decoders/usb_power_delivery/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/usb_power_delivery/pd.py rename to decoders/usb_power_delivery/pd.py diff --git a/libsigrokdecode4DSL/decoders/usb_request/__init__.py b/decoders/usb_request/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/usb_request/__init__.py rename to decoders/usb_request/__init__.py diff --git a/libsigrokdecode4DSL/decoders/usb_request/pd.py b/decoders/usb_request/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/usb_request/pd.py rename to decoders/usb_request/pd.py diff --git a/libsigrokdecode4DSL/decoders/usb_signalling/__init__.py b/decoders/usb_signalling/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/usb_signalling/__init__.py rename to decoders/usb_signalling/__init__.py diff --git a/libsigrokdecode4DSL/decoders/usb_signalling/pd.py b/decoders/usb_signalling/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/usb_signalling/pd.py rename to decoders/usb_signalling/pd.py diff --git a/libsigrokdecode4DSL/decoders/wiegand/__init__.py b/decoders/wiegand/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/wiegand/__init__.py rename to decoders/wiegand/__init__.py diff --git a/libsigrokdecode4DSL/decoders/wiegand/pd.py b/decoders/wiegand/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/wiegand/pd.py rename to decoders/wiegand/pd.py diff --git a/libsigrokdecode4DSL/decoders/x2444m/__init__.py b/decoders/x2444m/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/x2444m/__init__.py rename to decoders/x2444m/__init__.py diff --git a/libsigrokdecode4DSL/decoders/x2444m/pd.py b/decoders/x2444m/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/x2444m/pd.py rename to decoders/x2444m/pd.py diff --git a/libsigrokdecode4DSL/decoders/xfp/__init__.py b/decoders/xfp/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/xfp/__init__.py rename to decoders/xfp/__init__.py diff --git a/libsigrokdecode4DSL/decoders/xfp/pd.py b/decoders/xfp/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/xfp/pd.py rename to decoders/xfp/pd.py diff --git a/libsigrokdecode4DSL/decoders/xy2-100/__init__.py b/decoders/xy2-100/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/xy2-100/__init__.py rename to decoders/xy2-100/__init__.py diff --git a/libsigrokdecode4DSL/decoders/xy2-100/pd.py b/decoders/xy2-100/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/xy2-100/pd.py rename to decoders/xy2-100/pd.py diff --git a/libsigrokdecode4DSL/decoders/z80/__init__.py b/decoders/z80/__init__.py similarity index 100% rename from libsigrokdecode4DSL/decoders/z80/__init__.py rename to decoders/z80/__init__.py diff --git a/libsigrokdecode4DSL/decoders/z80/pd.py b/decoders/z80/pd.py similarity index 100% rename from libsigrokdecode4DSL/decoders/z80/pd.py rename to decoders/z80/pd.py diff --git a/libsigrokdecode4DSL/decoders/z80/tables.py b/decoders/z80/tables.py similarity index 100% rename from libsigrokdecode4DSL/decoders/z80/tables.py rename to decoders/z80/tables.py diff --git a/doc/decoder.txt b/doc/decoder.txt new file mode 100644 index 00000000..542a084f --- /dev/null +++ b/doc/decoder.txt @@ -0,0 +1,28 @@ +sigrokdecode module's types + +output types: + 1.OUTPUT_ANN + 2.OUTPUT_PYTHON + 3.OUTPUT_BINARY + 4.OUTPUT_META + +default sample rate name: SRD_CONF_SAMPLERATE,value is 10000 + +sigrokdecode.Decoder methods: + +class Decoder{ + PyObject* put(PyObject *self, PyObject *args); + PyObject* register(PyObject *self, PyObject *args,PyObject *kwargs); + PyObject* wait(PyObject *self, PyObject *args); + PyObject* has_channel(PyObject *self, PyObject *args); +} + + +c can call's method of python: + 1.reset + 2.start + 3.decode + 4.metadata + + + diff --git a/libsigrokdecode4DSL/decoder.c b/libsigrokdecode4DSL/decoder.c index 4906b5d9..809cb25b 100755 --- a/libsigrokdecode4DSL/decoder.c +++ b/libsigrokdecode4DSL/decoder.c @@ -40,7 +40,10 @@ /** @cond PRIVATE */ -/* The list of loaded protocol decoders. */ +/* + The list of loaded protocol decoders. + Is srd_decoder* type +*/ static GSList *pd_list = NULL; /* srd.c */ @@ -719,6 +722,7 @@ SRD_API int srd_decoder_load(const char *module_name) d = g_malloc0(sizeof(struct srd_decoder)); fail_txt = NULL; + //Load module from python script file,module_name is a sub directory d->py_mod = py_import_by_name(module_name); if (!d->py_mod) { fail_txt = "import by name failed"; @@ -731,13 +735,19 @@ SRD_API int srd_decoder_load(const char *module_name) goto err_out; } - /* Get the 'Decoder' class as Python object. */ + /* + Get the 'Decoder' class as Python object. + Here, Decoder is python class type + */ d->py_dec = PyObject_GetAttrString(d->py_mod, "Decoder"); if (!d->py_dec) { fail_txt = "no 'Decoder' attribute in imported module"; goto except_out; } + /* + Here, Decoder is c class type + */ py_basedec = PyObject_GetAttrString(mod_sigrokdecode, "Decoder"); if (!py_basedec) { fail_txt = "no 'Decoder' attribute in sigrokdecode(3)"; diff --git a/libsigrokdecode4DSL/instance.c b/libsigrokdecode4DSL/instance.c index 5d96701f..1b3d5df7 100755 --- a/libsigrokdecode4DSL/instance.c +++ b/libsigrokdecode4DSL/instance.c @@ -379,9 +379,10 @@ SRD_API struct srd_decoder_inst *srd_inst_new(struct srd_session *sess, di->py_pinvalues = NULL; di->dec_num_channels = g_slist_length(di->decoder->channels) + g_slist_length(di->decoder->opt_channels); + if (di->dec_num_channels) { - di->dec_channelmap = - g_malloc(sizeof(int) * di->dec_num_channels); + di->dec_channelmap = g_malloc(sizeof(int) * di->dec_num_channels); + for (i = 0; i < di->dec_num_channels; i++) di->dec_channelmap[i] = i; @@ -913,7 +914,8 @@ static gboolean all_terms_match(struct srd_decoder_inst *di, return TRUE; } -static gboolean find_match(struct srd_decoder_inst *di) +static gboolean +find_match(struct srd_decoder_inst *di) { uint64_t j; GSList *l, *cond; @@ -1059,9 +1061,11 @@ static gpointer di_thread(gpointer data) * "Regular" termination of the decode() method is not expected. */ //Py_IncRef(di->py_inst); + //srd_err("start call decode()"); srd_dbg("%s: Calling decode().", di->inst_id); py_res = PyObject_CallMethod(di->py_inst, "decode", NULL); srd_dbg("%s: decode() terminated.", di->inst_id); + //srd_err("end call decode()"); if (!py_res) di->decoder_state = SRD_ERR; @@ -1210,7 +1214,10 @@ SRD_PRIV int srd_inst_decode(struct srd_decoder_inst *di, abs_start_samplenum, abs_end_samplenum, abs_end_samplenum - abs_start_samplenum, inbuflen, di->inst_id); - /* If this is the first call, start the worker thread. */ + /* + If this is the first call, start the worker thread. + One session may be have more decoder,so more thread will be created + */ if (!di->thread_handle) { srd_dbg("No worker thread for this decoder stack " "exists yet, creating one: %s.", di->inst_id); diff --git a/libsigrokdecode4DSL/libsigrokdecode.h b/libsigrokdecode4DSL/libsigrokdecode.h index 77d8a216..9bc23973 100755 --- a/libsigrokdecode4DSL/libsigrokdecode.h +++ b/libsigrokdecode4DSL/libsigrokdecode.h @@ -32,7 +32,10 @@ extern "C" { struct srd_session { int session_id; - /* List of decoder instances. */ + /* + List of decoder instances. + srd_decoder_inst* type + */ GSList *di_list; /* List of frontend callbacks to receive decoder output. */ @@ -257,14 +260,16 @@ struct srd_decoder_inst { struct srd_decoder *decoder; struct srd_session *sess; void *py_inst; - void *py_pinvalues; + void *py_pinvalues; /* is a python duple type, like (1,0,255,255)*/ char *inst_id; - GSList *pd_output; + GSList *pd_output; /* srd_pd_output* type */ int dec_num_channels; int *dec_channelmap; GSList *next_di; - /** List of conditions a PD wants to wait for. */ + /** List of conditions a PD wants to wait for. + * Type is srd_term* of GSList* + */ GSList *condition_list; /** Array of booleans denoting which conditions matched. */ @@ -291,7 +296,9 @@ struct srd_decoder_inst { /** Absolute current sample matched conditions. */ gboolean abs_cur_matched; - /** Array of "old" (previous sample) pin values. */ + /** Array of "old" (previous sample) pin values. + * Type of uint8_t + */ GArray *old_pins_array; /** Handle for this PD stack's worker thread. */ @@ -339,8 +346,9 @@ struct srd_proto_data { }; struct srd_proto_data_annotation { int ann_class; - int ann_type; - char **ann_text; + int ann_type; + char str_number_hex[18]; //numerical value hex format string + char **ann_text; //text string lines }; struct srd_proto_data_binary { int bin_class; diff --git a/libsigrokdecode4DSL/session.c b/libsigrokdecode4DSL/session.c index e60a9da1..32597486 100755 --- a/libsigrokdecode4DSL/session.c +++ b/libsigrokdecode4DSL/session.c @@ -269,6 +269,7 @@ SRD_API int srd_session_send(struct srd_session *sess, if (!sess) return SRD_ERR_ARG; + //foreach srd_decoder_inst* stack for (d = sess->di_list; d; d = d->next) { if ((ret = srd_inst_decode(d->data, abs_start_samplenum, abs_end_samplenum, inbuf, inbuf_const, inbuflen, error)) != SRD_OK) diff --git a/libsigrokdecode4DSL/srd.c b/libsigrokdecode4DSL/srd.c index b070ab24..5a43b98e 100755 --- a/libsigrokdecode4DSL/srd.c +++ b/libsigrokdecode4DSL/srd.c @@ -255,7 +255,7 @@ SRD_API int srd_init(const char *path) PyEval_InitThreads(); /* Release the GIL (ignore return value, we don't need it here). */ - (void)PyEval_SaveThread(); + PyEval_SaveThread(); max_session_id = 0; @@ -359,6 +359,7 @@ SRD_PRIV int srd_decoder_searchpath_add(const char *path) PyGILState_Release(gstate); + //append the directory to search list searchpaths = g_slist_prepend(searchpaths, g_strdup(path)); return SRD_OK; diff --git a/libsigrokdecode4DSL/type_decoder.c b/libsigrokdecode4DSL/type_decoder.c index d4b9782b..86599c6b 100755 --- a/libsigrokdecode4DSL/type_decoder.c +++ b/libsigrokdecode4DSL/type_decoder.c @@ -53,6 +53,91 @@ static void release_annotation(struct srd_proto_data_annotation *pda) g_strfreev(pda->ann_text); } +static int py_parse_ann_data(PyObject *list_obj, char ***out_strv, int list_size, char *hex_str_buf) +{ + PyObject *py_item, *py_bytes; + char **strv, *str; + PyGILState_STATE gstate; + int ret = SRD_ERR_PYTHON; + int ijmp = 0; + int text_num = 0; + PyObject* text_items[10]; + PyObject *py_tmp; + PyObject *py_numobj = NULL; + int i; + long long lv; + + gstate = PyGILState_Ensure(); + + str = NULL; + strv = NULL; + + //get annotation text count + for (i = 0; i < list_size; i++){ + py_tmp = PyList_GetItem(list_obj, i); + + //is a string + if (PyUnicode_Check(py_tmp)){ + text_items[text_num] = py_tmp; + text_num++; + } + else if (PyLong_Check(py_tmp)){ + py_numobj = py_tmp; + } + } + + if (py_numobj == NULL && text_num == 0){ + srd_err("list element type must be string or numberical"); + goto err; + } + + if (py_numobj != NULL){ + lv = PyLong_AsLongLong(py_numobj); + sprintf(hex_str_buf, "%02llX", lv); + } + + //have no text, only one numberical + if (text_num == 0){ + PyGILState_Release(gstate); + return SRD_OK; + } + + //more annotation text + strv = g_try_new0(char *, text_num + 1); + if (!strv) { + srd_err("Failed to allocate result string vector."); + ret = SRD_ERR_MALLOC; + goto err; + } + + for (i = 0; i < text_num; i++) { + py_bytes = PyUnicode_AsUTF8String(text_items[i]); + if (!py_bytes) + goto err; + + str = g_strdup(PyBytes_AsString(py_bytes)); + Py_DECREF(py_bytes); + if (!str) + goto err; + + strv[i] = str; + } + + *out_strv = strv; + PyGILState_Release(gstate); + return SRD_OK; + +err: + if (strv) + g_strfreev(strv); + srd_exception_catch(NULL, "Failed to obtain string item"); + PyGILState_Release(gstate); + return ret; +} + +/* + @obj is the fourth param from python calls put() +*/ static int convert_annotation(struct srd_decoder_inst *di, PyObject *obj, struct srd_proto_data *pdata) { @@ -62,6 +147,9 @@ static int convert_annotation(struct srd_decoder_inst *di, PyObject *obj, char **ann_text; gpointer ann_type_ptr; PyGILState_STATE gstate; + int ann_size; + + pda = pdata->data; gstate = PyGILState_Ensure(); @@ -96,27 +184,37 @@ static int convert_annotation(struct srd_decoder_inst *di, PyObject *obj, // "annotation class %d.", di->decoder->name, ann_class); // return SRD_ERR_PYTHON; // } - if (ann_class >= g_slist_length(di->decoder->ann_types)) { + if (ann_class >= g_slist_length(di->decoder->ann_types) || ann_class < 0) { srd_err("Protocol decoder %s submitted data to unregistered " "annotation class %d.", di->decoder->name, ann_class); goto err; } ann_type_ptr = g_slist_nth_data(di->decoder->ann_types, ann_class); - /* Second element must be a list. */ + /* + Second element must be a list. + */ py_tmp = PyList_GetItem(obj, 1); if (!PyList_Check(py_tmp)) { srd_err("Protocol decoder %s submitted annotation list, but " "second element was not a list.", di->decoder->name); goto err; } - if (py_strseq_to_char(py_tmp, &ann_text) != SRD_OK) { + + ann_size = PyList_Size(py_tmp); + if (ann_size == 0){ + srd_err("Protocol decoder %s, put() param, the annotation list is empty.", di->decoder->name); + goto err; + } + + pda->str_number_hex[0] = 0; + ann_text = NULL; + if (py_parse_ann_data(py_tmp, &ann_text, ann_size, pda->str_number_hex) != SRD_OK) { srd_err("Protocol decoder %s submitted annotation list, but " "second element was malformed.", di->decoder->name); goto err; } - - pda = pdata->data; + pda->ann_class = ann_class; pda->ann_type = GPOINTER_TO_INT(ann_type_ptr); pda->ann_text = ann_text; @@ -334,7 +432,7 @@ static PyObject *Decoder_put(PyObject *self, PyObject *args) struct srd_pd_callback *cb; PyGILState_STATE gstate; - py_data = NULL; + py_data = NULL; //the fourth param from python gstate = PyGILState_Ensure(); @@ -394,17 +492,20 @@ static PyObject *Decoder_put(PyObject *self, PyObject *args) case SRD_OUTPUT_PYTHON: for (l = di->next_di; l; l = l->next) { next_di = l->data; + srd_spew("Instance %s put %" PRIu64 "-%" PRIu64 " %s " "on oid %d (%s) to instance %s.", di->inst_id, start_sample, end_sample, output_type_name(pdo->output_type), output_id, pdo->proto_id, next_di->inst_id); + if (!(py_res = PyObject_CallMethod( next_di->py_inst, "decode", "KKO", start_sample, end_sample, py_data))) { srd_exception_catch(NULL, "Calling %s decode() failed", next_di->inst_id); } + Py_XDECREF(py_res); } if ((cb = srd_pd_output_callback_find(di->sess, pdo->output_type))) { @@ -459,6 +560,9 @@ err: return NULL; } +/* + return output info index +*/ static PyObject *Decoder_register(PyObject *self, PyObject *args, PyObject *kwargs) { @@ -612,7 +716,9 @@ static int get_current_pinvalues(const struct srd_decoder_inst *di) for (i = 0; i < di->dec_num_channels; i++) { /* A channelmap value of -1 means "unused optional channel". */ if (di->dec_channelmap[i] == -1) { - /* Value of unused channel is 0xff, instead of 0 or 1. */ + /* Value of unused channel is 0xff, instead of 0 or 1. + Done set -1 by srd_inst_channel_set_all() + */ PyTuple_SetItem(di->py_pinvalues, i, PyLong_FromLong(0xff)); } else { if (*(di->inbuf + i) == NULL) { @@ -905,6 +1011,7 @@ static PyObject *Decoder_wait(PyObject *self, PyObject *args) while (!di->got_new_samples && !di->want_wait_terminate) g_cond_wait(&di->got_new_samples_cond, &di->data_mutex); + /* * Check whether any of the current condition(s) match. * Arrange for termination requests to take a code path which @@ -915,7 +1022,7 @@ static PyObject *Decoder_wait(PyObject *self, PyObject *args) found_match = FALSE; /* Ignore return value for now, should never be negative. */ - (void)process_samples_until_condition_match(di, &found_match); + process_samples_until_condition_match(di, &found_match); Py_END_ALLOW_THREADS @@ -940,7 +1047,7 @@ static PyObject *Decoder_wait(PyObject *self, PyObject *args) Py_INCREF(di->py_pinvalues); return (PyObject *)di->py_pinvalues; } - + /* No match, reset state for the next chunk. */ di->got_new_samples = FALSE; di->handled_all_samples = TRUE; @@ -1032,12 +1139,16 @@ err: static PyMethodDef Decoder_methods[] = { { "put", Decoder_put, METH_VARARGS, "Accepts a dictionary with the following keys: startsample, endsample, data" }, + { "register", (PyCFunction)Decoder_register, METH_VARARGS|METH_KEYWORDS, "Register a new output stream" }, + { "wait", Decoder_wait, METH_VARARGS, "Wait for one or more conditions to occur" }, + { "has_channel", Decoder_has_channel, METH_VARARGS, "Report whether a channel was supplied" }, + {NULL, NULL, 0, NULL} }; diff --git a/qtpro/DSView.pro.user b/qtpro/DSView.pro.user index 7ba4c464..6fe947fc 100644 --- a/qtpro/DSView.pro.user +++ b/qtpro/DSView.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -314,7 +314,7 @@ false true - /home/lala/workdir/DSView/build-DSView-unknown-Debug + /home/lala/workdir/DSView-build/bin 1 diff --git a/libsigrokdecode4DSL/tests/core.c b/test/decode_test/core.c similarity index 100% rename from libsigrokdecode4DSL/tests/core.c rename to test/decode_test/core.c diff --git a/libsigrokdecode4DSL/tests/decoder.c b/test/decode_test/decoder.c similarity index 100% rename from libsigrokdecode4DSL/tests/decoder.c rename to test/decode_test/decoder.c diff --git a/libsigrokdecode4DSL/tests/inst.c b/test/decode_test/inst.c similarity index 100% rename from libsigrokdecode4DSL/tests/inst.c rename to test/decode_test/inst.c diff --git a/libsigrokdecode4DSL/tests/lib.h b/test/decode_test/lib.h similarity index 100% rename from libsigrokdecode4DSL/tests/lib.h rename to test/decode_test/lib.h diff --git a/libsigrokdecode4DSL/tests/main.c b/test/decode_test/main.c similarity index 100% rename from libsigrokdecode4DSL/tests/main.c rename to test/decode_test/main.c diff --git a/libsigrokdecode4DSL/tests/session.c b/test/decode_test/session.c similarity index 100% rename from libsigrokdecode4DSL/tests/session.c rename to test/decode_test/session.c From 1cd25f29a66e90a24c29f132b4a4614c643240b4 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Tue, 11 Jan 2022 15:19:28 +0800 Subject: [PATCH 55/60] Add ascii display format for numberic value from the decode result --- DSView/pv/data/decode/AnnotationResTable.cpp | 33 +++++++++++++++----- DSView/pv/data/decode/AnnotationResTable.h | 3 +- DSView/pv/data/decode/annotation.cpp | 32 +++++++++++-------- DSView/pv/data/decode/annotation.h | 2 ++ DSView/pv/data/decode/decoderstatus.h | 6 ++-- DSView/pv/dock/protocoldock.cpp | 7 +++-- DSView/pv/dock/protocolitemlayer.cpp | 11 ++++--- DSView/pv/dsvdef.cpp | 9 ++++-- DSView/pv/dsvdef.h | 9 +++--- decoders/0-i2c/pd.py | 3 +- decoders/0-spi/pd.py | 4 +-- decoders/0-uart/pd.py | 10 +++--- decoders/1-i2c/pd.py | 5 ++- decoders/1-uart/pd.py | 8 +++-- libsigrokdecode4DSL/libsigrokdecode.h | 1 + libsigrokdecode4DSL/type_decoder.c | 9 ++++-- qtpro/DSView.pro.user | 2 +- 17 files changed, 97 insertions(+), 57 deletions(-) diff --git a/DSView/pv/data/decode/AnnotationResTable.cpp b/DSView/pv/data/decode/AnnotationResTable.cpp index f9be9e16..223a3409 100644 --- a/DSView/pv/data/decode/AnnotationResTable.cpp +++ b/DSView/pv/data/decode/AnnotationResTable.cpp @@ -24,11 +24,10 @@ #include "../../dsvdef.h" #define DECODER_MAX_DATA_BLOCK_LEN 25 -#define FORMAT_TMP_BUFFER_SIZE 100 const char g_bin_cvt_table[] = "0000000100100011010001010110011110001001101010111100110111101111"; -char g_bin_format_tmp_buffer[FORMAT_TMP_BUFFER_SIZE + 3]; -char g_oct_format_tmp_buffer[FORMAT_TMP_BUFFER_SIZE + 6]; +char g_bin_format_tmp_buffer[DECODER_MAX_DATA_BLOCK_LEN * 4 + 2]; +char g_oct_format_tmp_buffer[DECODER_MAX_DATA_BLOCK_LEN * 3 + 2]; char g_number_tmp_64[30]; char* bin2oct_string(char *buf, int size, const char *bin, int len){ @@ -111,7 +110,7 @@ int AnnotationResTable::MakeIndex(const std::string &key, AnnotationSourceItem* m_resourceTable.push_back(item); item->cur_display_format = -1; - item->is_numerical = false; + item->is_numeric = false; newItem = item; int dex = m_indexs.size(); @@ -135,9 +134,9 @@ const char* AnnotationResTable::format_numberic(const char *hex_str, int fmt) } //convert to bin format - char *buf = g_bin_format_tmp_buffer + FORMAT_TMP_BUFFER_SIZE; - *(buf + 1) = 0; //set the end flag - *buf = 0; + char *buf = g_bin_format_tmp_buffer + sizeof(g_bin_format_tmp_buffer) - 2; + buf[1] = 0; //set the end flag + buf[0] = 0; int len = strlen(data); //buffer is not enough @@ -178,11 +177,29 @@ const char* AnnotationResTable::format_numberic(const char *hex_str, int fmt) //64 bit integer if (fmt == DecoderDataFormat::dec && len * 4 <= 64){ - long long lv = bin2long_string(buf, len *4); + long long lv = bin2long_string(buf, len * 4); g_number_tmp_64[0] = 0; sprintf(g_number_tmp_64, "%lld", lv); return g_number_tmp_64; } + + //ascii + if (fmt == DecoderDataFormat::ascii && len < 30 - 3){ + if (len == 2){ + int lv = (int)bin2long_string(buf, len * 4); + //can display chars + if (lv >= 33 && lv <= 126){ + sprintf(g_number_tmp_64, "%c", (char)lv); + return g_number_tmp_64; + } + } + char * const wr_buf = g_number_tmp_64; + g_number_tmp_64[0] = '['; + strcpy(g_number_tmp_64 + 1, data); + g_number_tmp_64[len+1] = ']'; + g_number_tmp_64[len+2] = 0; + return g_number_tmp_64; + } return data; } diff --git a/DSView/pv/data/decode/AnnotationResTable.h b/DSView/pv/data/decode/AnnotationResTable.h index 3d6ea3ed..1cf98f73 100644 --- a/DSView/pv/data/decode/AnnotationResTable.h +++ b/DSView/pv/data/decode/AnnotationResTable.h @@ -28,8 +28,9 @@ struct AnnotationSourceItem { - bool is_numerical; + bool is_numeric; char str_number_hex[18]; //numerical value hex format string + long long numberic_value; std::vector src_lines; //the origin source string lines std::vector cvt_lines; //the converted to bin/hex/oct format string lines int cur_display_format; //current format as bin/ex/oct..., init with -1 diff --git a/DSView/pv/data/decode/annotation.cpp b/DSView/pv/data/decode/annotation.cpp index 87c97c65..6bd60bee 100755 --- a/DSView/pv/data/decode/annotation.cpp +++ b/DSView/pv/data/decode/annotation.cpp @@ -40,9 +40,11 @@ char sz_format_tmp_buf[50]; bool is_hex_number_str(const char *str) { char c = *str; + int len = 0; while (c) { + ++len; if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')){ c = *str; str++; @@ -50,8 +52,7 @@ bool is_hex_number_str(const char *str) } return false; } - - return true; + return len % 2 == 0 && len > 0; } namespace pv { @@ -96,19 +97,19 @@ Annotation::Annotation(const srd_proto_data *const pdata, DecoderStatus *status) resItem->src_lines.push_back(QString::fromUtf8(*annotations)); annotations++; } - - //get numerical data + + //get numeric data if (pda->str_number_hex[0]){ strcpy(resItem->str_number_hex, pda->str_number_hex); - resItem->is_numerical = true; + resItem->is_numeric = true; } else if (resItem->src_lines.size() == 1 && _type >= 100 && _type < 200){ if (is_hex_number_str(resItem->src_lines[0].toLatin1().data())){ - resItem->is_numerical = true; + resItem->is_numeric = true; } } - _status->m_bNumerical |= resItem->is_numerical; + _status->m_bNumeric |= resItem->is_numeric; } } @@ -126,11 +127,11 @@ Annotation::~Annotation() const std::vector& Annotation::annotations() const { assert(_status); - + AnnotationSourceItem &resItem = *annTable.GetItem(_resIndex); - - //get origin data, is not a numberical value - if (!resItem.is_numerical){ + + //get origin data, is not a numberic value + if (!resItem.is_numeric){ return resItem.src_lines; } @@ -167,8 +168,13 @@ const std::vector& Annotation::annotations() const } return resItem.cvt_lines; -} - +} + +bool Annotation::is_numberic() +{ + AnnotationSourceItem *resItem = annTable.GetItem(_resIndex); + return resItem->is_numeric; +} } // namespace decode } // namespace data diff --git a/DSView/pv/data/decode/annotation.h b/DSView/pv/data/decode/annotation.h index f2025776..629ea6fa 100755 --- a/DSView/pv/data/decode/annotation.h +++ b/DSView/pv/data/decode/annotation.h @@ -62,6 +62,8 @@ public: return _type; } + bool is_numberic(); + public: const std::vector& annotations() const; diff --git a/DSView/pv/data/decode/decoderstatus.h b/DSView/pv/data/decode/decoderstatus.h index d80780b3..8761bcc2 100644 --- a/DSView/pv/data/decode/decoderstatus.h +++ b/DSView/pv/data/decode/decoderstatus.h @@ -26,13 +26,13 @@ class DecoderStatus public: DecoderStatus() { - m_bNumerical = false; + m_bNumeric = false; m_format = 0; sdr_decoder_handle = NULL; } public: - bool m_bNumerical; //when decoder get any numerical data,it will be set + bool m_bNumeric; //when decoder get any numerical data,it will be set int m_format; //protocol format code void *sdr_decoder_handle; -}; \ No newline at end of file +}; diff --git a/DSView/pv/dock/protocoldock.cpp b/DSView/pv/dock/protocoldock.cpp index 9a49da9c..6081c64f 100755 --- a/DSView/pv/dock/protocoldock.cpp +++ b/DSView/pv/dock/protocoldock.cpp @@ -618,10 +618,12 @@ void ProtocolDock::search_pre() bool ann_valid; while(i < _str_list.size()) { QString nxt = _str_list.at(i); + do { ann_valid = decoder_stack->list_annotation(ann, col, row); row++; - }while(ann_valid && (ann.type() < 100 || ann.type() > 999)); + }while(ann_valid && !ann.is_numberic()); + QString source = ann.annotations().at(0); if (ann_valid && source.contains(nxt)) i++; @@ -686,10 +688,11 @@ void ProtocolDock::search_nxt() while(i < _str_list.size()) { QString nxt = _str_list.at(i); + do { ann_valid = decoder_stack->list_annotation(ann, col, row); row++; - }while(ann_valid && (ann.type() < 100 || ann.type() > 999)); + }while(ann_valid && !ann.is_numberic()); auto strlist = ann.annotations(); QString source = ann.annotations().at(0); diff --git a/DSView/pv/dock/protocolitemlayer.cpp b/DSView/pv/dock/protocolitemlayer.cpp index 784c2a19..863bbaa9 100644 --- a/DSView/pv/dock/protocolitemlayer.cpp +++ b/DSView/pv/dock/protocolitemlayer.cpp @@ -122,10 +122,13 @@ void ProtocolItemLayer::LoadFormatSelect(bool bSingle) m_bSetting = true; _format_combox->clear(); - _format_combox->addItem("hex"); - _format_combox->addItem("dec"); - _format_combox->addItem("oct"); - _format_combox->addItem("bin"); + if (!bSingle){ + _format_combox->addItem("hex"); + _format_combox->addItem("dec"); + _format_combox->addItem("oct"); + _format_combox->addItem("bin"); + } + _format_combox->addItem("ascii"); _format_combox->setCurrentIndex(0); m_bSetting = false; diff --git a/DSView/pv/dsvdef.cpp b/DSView/pv/dsvdef.cpp index 35c57072..113cac13 100644 --- a/DSView/pv/dsvdef.cpp +++ b/DSView/pv/dsvdef.cpp @@ -44,15 +44,18 @@ namespace DecoderDataFormat if (strcmp(name, "dec") == 0){ return (int)dec; } - if (strcmp(name, "hex") == 0){ + if (strcmp(name, "hex") == 0){ return (int)hex; } - if (strcmp(name, "oct") == 0){ + if (strcmp(name, "oct") == 0){ return (int)oct; } - if (strcmp(name, "bin") == 0){ + if (strcmp(name, "bin") == 0){ return (int)bin; } + if (strcmp(name, "ascii") == 0){ + return (int)ascii; + } return (int)hex; } } diff --git a/DSView/pv/dsvdef.h b/DSView/pv/dsvdef.h index fc209a79..13c61d51 100644 --- a/DSView/pv/dsvdef.h +++ b/DSView/pv/dsvdef.h @@ -49,10 +49,11 @@ namespace DecoderDataFormat { enum _data_format { - hex, - dec, - oct, - bin + hex=0, + dec=1, + oct=2, + bin=3, + ascii=4 }; int Parse(const char *name); diff --git a/decoders/0-i2c/pd.py b/decoders/0-i2c/pd.py index 8cb47ee0..dad9922d 100755 --- a/decoders/0-i2c/pd.py +++ b/decoders/0-i2c/pd.py @@ -188,8 +188,7 @@ class Decoder(srd.Decoder): self.putx([proto[cmd][0], w]) self.ss, self.es = self.ss_byte, self.samplenum - self.putx([proto[cmd][0], ['%s: %02X' % (proto[cmd][1], d), - '%s: %02X' % (proto[cmd][2], d), '%02X' % d]]) + self.putx([proto[cmd][0], ['%s: {$}' % proto[cmd][1], '%s: {$}' % proto[cmd][2], '{$}', d]]) # Done with this packet. self.bitcount = self.databyte = 0 diff --git a/decoders/0-spi/pd.py b/decoders/0-spi/pd.py index 4708a98d..2d397f02 100755 --- a/decoders/0-spi/pd.py +++ b/decoders/0-spi/pd.py @@ -151,9 +151,9 @@ class Decoder(srd.Decoder): # Dataword annotations. if self.have_miso: - self.put(ss, es, self.out_ann, [0, ['%02X' % self.misodata]]) + self.put(ss, es, self.out_ann, [0, [self.misodata]]) if self.have_mosi: - self.put(ss, es, self.out_ann, [1, ['%02X' % self.mosidata]]) + self.put(ss, es, self.out_ann, [1, [self.mosidata]]) def reset_decoder_state(self): self.misodata = 0 if self.have_miso else None diff --git a/decoders/0-uart/pd.py b/decoders/0-uart/pd.py index fdb7c28b..9edf2254 100755 --- a/decoders/0-uart/pd.py +++ b/decoders/0-uart/pd.py @@ -218,11 +218,11 @@ class Decoder(srd.Decoder): if self.options['bit_order'] == 'msb-first': bits.reverse() self.datavalue = bitpack(bits) - - b = self.datavalue - formatted = self.format_value(b) - if formatted is not None: - self.putx([0, [formatted]]) + self.putx([0, [self.datavalue]]) + #b = self.datavalue + #formatted = self.format_value(b) + #if formatted is not None: + # self.putx([0, [formatted]]) self.databits = [] diff --git a/decoders/1-i2c/pd.py b/decoders/1-i2c/pd.py index fb6af6bb..a163eba4 100755 --- a/decoders/1-i2c/pd.py +++ b/decoders/1-i2c/pd.py @@ -213,11 +213,10 @@ class Decoder(srd.Decoder): if cmd.startswith('ADDRESS'): self.ss, self.es = self.samplenum, self.samplenum + self.bitwidth w = ['Write', 'Wr', 'W'] if self.wr else ['Read', 'Rd', 'R'] - self.putx([proto[cmd][0], w]) + self.putx([0, w]) self.ss, self.es = self.ss_byte, self.samplenum - self.putx([proto[cmd][0], ['%s: %02X' % (proto[cmd][1], d), - '%s: %02X' % (proto[cmd][2], d), '%02X' % d]]) + self.putx([proto[cmd][0], ['%s: {$}' % proto[cmd][1], '%s: {$}' % proto[cmd][2], '{$}', d]]) # Done with this packet. self.bitcount = self.databyte = 0 diff --git a/decoders/1-uart/pd.py b/decoders/1-uart/pd.py index 1984f4e1..f3d6181c 100755 --- a/decoders/1-uart/pd.py +++ b/decoders/1-uart/pd.py @@ -253,10 +253,12 @@ class Decoder(srd.Decoder): self.datavalue = bitpack(bits) self.putpx(['DATA', 0, (self.datavalue, self.databits)]) + self.putx([0, [self.datavalue]]) + b = self.datavalue - formatted = self.format_value(b) - if formatted is not None: - self.putx([0, [formatted]]) + #formatted = self.format_value(b) + #if formatted is not None: + # self.putx([0, [formatted]]) bdata = b.to_bytes(self.bw, byteorder='big') self.putbin([0, bdata]) diff --git a/libsigrokdecode4DSL/libsigrokdecode.h b/libsigrokdecode4DSL/libsigrokdecode.h index 9bc23973..a399de18 100755 --- a/libsigrokdecode4DSL/libsigrokdecode.h +++ b/libsigrokdecode4DSL/libsigrokdecode.h @@ -348,6 +348,7 @@ struct srd_proto_data_annotation { int ann_class; int ann_type; char str_number_hex[18]; //numerical value hex format string + long long numberic_value; char **ann_text; //text string lines }; struct srd_proto_data_binary { diff --git a/libsigrokdecode4DSL/type_decoder.c b/libsigrokdecode4DSL/type_decoder.c index 86599c6b..6199652b 100755 --- a/libsigrokdecode4DSL/type_decoder.c +++ b/libsigrokdecode4DSL/type_decoder.c @@ -53,7 +53,7 @@ static void release_annotation(struct srd_proto_data_annotation *pda) g_strfreev(pda->ann_text); } -static int py_parse_ann_data(PyObject *list_obj, char ***out_strv, int list_size, char *hex_str_buf) +static int py_parse_ann_data(PyObject *list_obj, char ***out_strv, int list_size, char *hex_str_buf, long long *numberic_value) { PyObject *py_item, *py_bytes; char **strv, *str; @@ -93,7 +93,8 @@ static int py_parse_ann_data(PyObject *list_obj, char ***out_strv, int list_size if (py_numobj != NULL){ lv = PyLong_AsLongLong(py_numobj); - sprintf(hex_str_buf, "%02llX", lv); + sprintf(hex_str_buf, "%02llX", lv); + *numberic_value = lv; } //have no text, only one numberical @@ -209,7 +210,9 @@ static int convert_annotation(struct srd_decoder_inst *di, PyObject *obj, pda->str_number_hex[0] = 0; ann_text = NULL; - if (py_parse_ann_data(py_tmp, &ann_text, ann_size, pda->str_number_hex) != SRD_OK) { + pda->numberic_value = 0; + + if (py_parse_ann_data(py_tmp, &ann_text, ann_size, pda->str_number_hex, &pda->numberic_value) != SRD_OK) { srd_err("Protocol decoder %s submitted annotation list, but " "second element was malformed.", di->decoder->name); goto err; diff --git a/qtpro/DSView.pro.user b/qtpro/DSView.pro.user index 6fe947fc..e06307fe 100644 --- a/qtpro/DSView.pro.user +++ b/qtpro/DSView.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId From e080c8b4189302117d788600ea62cb74a07256c6 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Thu, 13 Jan 2022 11:00:53 +0800 Subject: [PATCH 56/60] fix bug for stack decoder can not add and remove --- DSView/pv/view/decodetrace.cpp | 160 ++++++++++++++++++++++++++------- DSView/pv/view/decodetrace.h | 21 +++-- qtpro/DSView.pro.user | 4 +- 3 files changed, 145 insertions(+), 40 deletions(-) diff --git a/DSView/pv/view/decodetrace.cpp b/DSView/pv/view/decodetrace.cpp index 250ca49c..9c05d62e 100755 --- a/DSView/pv/view/decodetrace.cpp +++ b/DSView/pv/view/decodetrace.cpp @@ -53,6 +53,7 @@ #include "../toolbars/titlebar.h" #include "../dsvdef.h" #include "../ui/dscombobox.h" +#include using namespace boost; using namespace std; @@ -133,6 +134,8 @@ DecodeTrace::DecodeTrace(pv::SigSession *session, _start_count = 0; _end_index = 0; _start_index = 0; + _decoder_container = NULL; + _form_base_height = 0; _decoder_stack = decoder_stack; _session = session; @@ -349,6 +352,8 @@ void DecodeTrace::paint_fore(QPainter &p, int left, int right, QColor fore, QCol bool DecodeTrace::create_popup() { int ret = false; //setting have changed flag + _form_base_height = 0; + _decoder_container = NULL; dialogs::DSDialog dlg; //dlg.setMinimumSize(500,600); @@ -367,27 +372,59 @@ bool DecodeTrace::create_popup() } } + _decoder_container = NULL; return ret; } void DecodeTrace::create_popup_form(dialogs::DSDialog *dlg) { - // Clear the layout - // Transfer the layout and the child widgets to a temporary widget // which then goes out of scope destroying the layout and all the child // widgets. - QFormLayout *form = new QFormLayout(); + QFormLayout *form = new QFormLayout(); form->setVerticalSpacing(5); form->setFormAlignment(Qt::AlignLeft); form->setLabelAlignment(Qt::AlignLeft); form->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); + + _decoder_container = new QWidget(dlg); + dlg->layout()->addWidget(_decoder_container); + + QVBoxLayout *decoder_lay = new QVBoxLayout(); + decoder_lay->setContentsMargins(0, 0, 0, 0); + decoder_lay->setDirection(QBoxLayout::TopToBottom); + _decoder_container->setLayout(decoder_lay); + dlg->layout()->addLayout(form); dlg->setTitle(tr("Decoder Options")); populate_popup_form(dlg, form); } +void DecodeTrace::load_all_decoder_property(std::list &ls) +{ + assert(_decoder_container); + QVBoxLayout *lay = dynamic_cast(_decoder_container->layout()); + assert(lay); + + for(auto &dec : ls) + { + QWidget *panel = new QWidget(_decoder_container); + QFormLayout *form = new QFormLayout(); + form->setContentsMargins(0,0,0,0); + panel->setLayout(form); + lay->addWidget(panel); + + create_decoder_form(_decoder_stack, dec, panel, form); + + decoder_panel_item inf; + inf.decoder_handle = dec; + inf.panel = panel; + inf.panel_height = 0; + _decoder_panels.push_back(inf); + } +} + void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form) { using pv::data::decode::Decoder; @@ -401,21 +438,11 @@ void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form) _probe_selectors.clear(); _decoder_forms.clear(); - auto &stack = _decoder_stack->stack(); + load_all_decoder_property(_decoder_stack->stack()); - if (stack.empty()) { - QLabel *const l = new QLabel( - tr("

      No decoders in the stack

      ")); - l->setAlignment(Qt::AlignCenter); - form->addRow(l); - } else { - for(auto &dec : stack) { - create_decoder_form(_decoder_stack, dec, parent, form); - } - - form->addRow(new QLabel( - tr("* Required channels"), parent)); - } + if (_decoder_stack->stack().size() > 0){ + form->addRow(new QLabel(tr("* Required channels"), parent)); + } //Add region combobox _start_comboBox = new DsComboBox(parent); @@ -473,13 +500,9 @@ void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form) form->addRow(confirm_button_box); connect(_start_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(on_region_set(int))); - connect(_end_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(on_region_set(int))); - connect(decoder_menu, SIGNAL(decoder_selected(srd_decoder *)), this, SLOT(on_stack_decoder(srd_decoder *))); - connect(button_box, SIGNAL(accepted()), parent, SLOT(accept())); - connect(button_box, SIGNAL(rejected()), parent, SLOT(reject())); } @@ -775,16 +798,12 @@ DsComboBox* DecodeTrace::create_probe_selector( const srd_channel *const pdch) { assert(dec); - const auto &sigs = _session->get_signals(); - assert(_decoder_stack); data::decode::Decoder *_dec = const_cast(dec); - auto probe_iter = _dec->channels().find(pdch); DsComboBox *selector = new DsComboBox(parent); - selector->addItem("-", QVariant::fromValue(-1)); if (probe_iter == _dec->channels().end()) @@ -877,25 +896,104 @@ void DecodeTrace::on_decode_done() void DecodeTrace::on_probe_selected(int) { commit_probes(); -} +} void DecodeTrace::on_stack_decoder(srd_decoder *decoder) { assert(decoder); assert(_decoder_stack); - _decoder_stack->push(new data::decode::Decoder(decoder)); - - // create_popup_form(); -} + auto dec = new data::decode::Decoder(decoder); + _decoder_stack->push(dec); + std::list items; + items.push_back(dec); + + if (_decoder_panels.size()){ + auto it = _decoder_panels.end(); + --it; + if ((*it).panel_height == 0){ + (*it).panel_height = (*it).panel->geometry().height(); + } + } + + if (_decoder_panels.size() == 1 && _decoder_container && _form_base_height == 0){ + QWidget *dlg = dynamic_cast(_decoder_container->parent()); + assert(dlg); + _form_base_height = dlg->geometry().height(); + } + + load_all_decoder_property(items); +} + void DecodeTrace::on_del_stack(data::decode::Decoder *dec) { assert(dec); assert(_decoder_stack); _decoder_stack->remove(dec); - // create_popup_form(); + + std::list dels; + std::list adds; + + for (auto it = _decoder_panels.begin(); it != _decoder_panels.end(); it++){ + if ((*it).decoder_handle == dec){ + dels.push_back((*it)); + auto del_it = it; + + it++; + while (it != _decoder_panels.end()) + { + dels.push_back((*it)); + adds.push_back((pv::data::decode::Decoder*)(*it).decoder_handle); + it++; + } + _decoder_panels.erase(del_it); + break; + } + } + + while (true) + { + if (dels.empty()) + break; + + auto it = dels.end(); + it--; + auto inf = (*it); + assert(inf.panel); + + inf.panel->deleteLater(); + dels.erase(it); + + for (auto fd = _decoder_panels.begin(); fd != _decoder_panels.end(); ++fd){ + if ((*fd).decoder_handle == inf.decoder_handle){ + _decoder_panels.erase(fd); + break; + } + } + } + + if (adds.size() > 0){ + load_all_decoder_property(adds); + } + +// QTimer::singleShot(200, this, SLOT(on_resize_decoder_panel())); +} + +void DecodeTrace::on_resize_decoder_panel() +{ + /* + int dex = 0; + + for (auto &panel : _decoder_panels){ + assert(panel.panel); + dex++; + if (dex > 1){ + panel.panel->setMaximumHeight(panel.panel_height); + } + } + */ } int DecodeTrace::rows_size() diff --git a/DSView/pv/view/decodetrace.h b/DSView/pv/view/decodetrace.h index fde1ff23..b76c6360 100755 --- a/DSView/pv/view/decodetrace.h +++ b/DSView/pv/view/decodetrace.h @@ -22,20 +22,26 @@ #ifndef DSVIEW_PV_VIEW_DECODETRACE_H #define DSVIEW_PV_VIEW_DECODETRACE_H -#include "trace.h" #include #include - #include #include +#include +#include "trace.h" #include "../prop/binding/decoderoptions.h" #include "../dialogs/dsdialog.h" struct srd_channel; struct srd_decoder; +struct decoder_panel_item{ + QWidget *panel; + void *decoder_handle; + int panel_height; +}; + class DsComboBox; namespace pv { @@ -188,22 +194,20 @@ private: data::decode::Decoder *dec); void commit_probes(); + void load_all_decoder_property(std::list &ls); signals: void decoded_progress(int progress); private slots: - void on_new_decode_data(); - + void on_new_decode_data(); void on_probe_selected(int); - void on_stack_decoder(srd_decoder *decoder); - void on_del_stack(data::decode::Decoder *dec); void on_decode_done(); - void on_region_set(int index); + void on_resize_decoder_panel(); public: volatile bool _delete_flag; //detroy it when deocde task end @@ -223,6 +227,9 @@ private: DsComboBox *_end_comboBox; QFormLayout *_pub_input_layer; int _progress; + QWidget *_decoder_container; + std::list _decoder_panels; + int _form_base_height; std::list _bindings; std::list _probe_selectors; diff --git a/qtpro/DSView.pro.user b/qtpro/DSView.pro.user index e06307fe..37a2b3e0 100644 --- a/qtpro/DSView.pro.user +++ b/qtpro/DSView.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -141,7 +141,7 @@ QtProjectManager.QMakeBuildStep false - false + true false false From 2e0b7d0eace21920b37438ab9476999292f2bdd0 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Wed, 26 Jan 2022 17:20:35 +0800 Subject: [PATCH 57/60] qt pro file --- DSView/config.h | 4 ++-- DSView/main.cpp | 5 +++++ DSView/pv/widgets/decodermenu.cpp | 7 +++++-- qtpro/DSView.pro | 20 +++++--------------- qtpro/DSView.pro.user | 6 +++--- 5 files changed, 20 insertions(+), 22 deletions(-) diff --git a/DSView/config.h b/DSView/config.h index 25d9638f..067e528a 100755 --- a/DSView/config.h +++ b/DSView/config.h @@ -27,9 +27,9 @@ /* DSView version information */ #define DS_VERSION_MAJOR 1 -#define DS_VERSION_MINOR 5 +#define DS_VERSION_MINOR 2 #define DS_VERSION_MICRO 0 -#define DS_VERSION_STRING "1.5.0" +#define DS_VERSION_STRING "1.2.0" #define DS_DEBUG_TRACE diff --git a/DSView/main.cpp b/DSView/main.cpp index 7a4845d2..e038ae68 100755 --- a/DSView/main.cpp +++ b/DSView/main.cpp @@ -111,6 +111,11 @@ int main(int argc, char *argv[]) QApplication::setOrganizationName("DreamSourceLab"); QApplication::setOrganizationDomain("www.DreamSourceLab.com"); +#ifdef Q_OS_LINUX + QCoreApplication::addLibraryPath("/usr/lib/x86_64-linux-gnu/qt5/plugins"); + printf("qt plugins root:/usr/lib/x86_64-linux-gnu/qt5/plugins\n"); +#endif + AppControl *control = AppControl::Instance(); // Parse arguments diff --git a/DSView/pv/widgets/decodermenu.cpp b/DSView/pv/widgets/decodermenu.cpp index 39b1c156..f0a7a201 100755 --- a/DSView/pv/widgets/decodermenu.cpp +++ b/DSView/pv/widgets/decodermenu.cpp @@ -50,8 +50,11 @@ DecoderMenu::DecoderMenu(QWidget *parent, bool first_level_decoder) : } g_slist_free(l); - connect(&_mapper, SIGNAL(mapped(QObject*)), - this, SLOT(on_action(QObject*))); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + connect(&_mapper, SIGNAL(mappedObject(QObject*)), this, SLOT(on_action(QObject*))); +#else + connect(&_mapper, SIGNAL(mapped(QObject*)), this, SLOT(on_action(QObject*))); +#endif } int DecoderMenu::decoder_name_cmp(const void *a, const void *b) diff --git a/qtpro/DSView.pro b/qtpro/DSView.pro index 53e0acad..3ee34059 100644 --- a/qtpro/DSView.pro +++ b/qtpro/DSView.pro @@ -32,6 +32,7 @@ CONFIG += c++11 QT += widgets QMAKE_CFLAGS_ISYSTEM = -I +CONFIG += release TARGET = DSView TEMPLATE = app @@ -69,9 +70,6 @@ INCLUDEPATH += .. LIBS += /usr/lib/x86_64-linux-gnu/libglib-2.0.so LIBS += /usr/lib/x86_64-linux-gnu/libusb-1.0.so -LIBS += /usr/lib/x86_64-linux-gnu/libboost_thread.so -LIBS += /usr/lib/x86_64-linux-gnu/libboost_system.so -LIBS += /usr/lib/x86_64-linux-gnu/libboost_filesystem.so LIBS += /usr/lib/x86_64-linux-gnu/libpython3.8.so LIBS += /usr/lib/x86_64-linux-gnu/libfftw3.so LIBS += /usr/local/lib/libz.so.1.2.11 @@ -87,20 +85,12 @@ INCLUDEPATH += /usr/local/include/boost INCLUDEPATH += /Library/Frameworks/Python.framework/Versions/3.4/include/python3.4m INCLUDEPATH += .. -#LIBS += -framework CoreFoundation -#LIBS += -framework CoreServices -#LIBS += /usr/lib/libiconv.2.dylib -#LIBS += /usr/local/lib/libpcre.a -#LIBS += /usr/local/opt/gettext/lib/libintl.a -#LIBS += /usr/lib/libz.1.dylib -#LIBS += /usr/lib/libobjc.dylib - LIBS += /usr/local/lib/libglib-2.0.dylib LIBS += /usr/local/lib/libusb-1.0.dylib -LIBS += /usr/local/lib/libboost_atomic-mt.a -LIBS += /usr/local/lib/libboost_thread-mt.a -LIBS += /usr/local/lib/libboost_system-mt.a -LIBS += /usr/local/lib/libboost_filesystem-mt.a +#LIBS += /usr/local/lib/libboost_atomic-mt.a +#LIBS += /usr/local/lib/libboost_thread-mt.a +#LIBS += /usr/local/lib/libboost_system-mt.a +#LIBS += /usr/local/lib/libboost_filesystem-mt.a LIBS += /Library/Frameworks/Python.framework/Versions/3.4/lib/libpython3.4.dylib LIBS += /usr/local/lib/libfftw3.a } diff --git a/qtpro/DSView.pro.user b/qtpro/DSView.pro.user index 37a2b3e0..99eacae7 100644 --- a/qtpro/DSView.pro.user +++ b/qtpro/DSView.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -82,7 +82,7 @@ 桌面 桌面 {ce867f0c-ef0e-4256-b807-c2554ad78bbf} - 0 + 1 0 0 @@ -141,7 +141,7 @@ QtProjectManager.QMakeBuildStep false - true + false false false From 8770b9f7339f518c5df5c39ec4eedf869b9a73b8 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Wed, 26 Jan 2022 17:21:21 +0800 Subject: [PATCH 58/60] pro file --- qtpro/DSView-mac.pro | 361 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 361 insertions(+) create mode 100644 qtpro/DSView-mac.pro diff --git a/qtpro/DSView-mac.pro b/qtpro/DSView-mac.pro new file mode 100644 index 00000000..b5d06417 --- /dev/null +++ b/qtpro/DSView-mac.pro @@ -0,0 +1,361 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2013-07-24T17:32:25 +# +#------------------------------------------------- + +QT += core gui +CONFIG -= lib_bundle +CONFIG += app_bundle +macx { +QT += svg +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 +#CONFIG += sdk_no_version_check +} +CONFIG += exceptions +CONFIG += object_parallel_to_source +CONFIG += c++11 +QT += widgets +#QT+= core5compat + +#QMAKE_CFLAGS_ISYSTEM = -I + +TARGET = DSView +TEMPLATE = app + +TRANSLATIONS = my_CN.ts + +CONFIG += decoders +DEFINES += decoders + +macx: { +INCLUDEPATH += /usr/local/include/ +INCLUDEPATH += /usr/local/Cellar/glib/2.70.1/include/glib-2.0 +INCLUDEPATH += /usr/local/Cellar/glib/2.70.1/lib/glib-2.0/include +INCLUDEPATH += /usr/local/Cellar/libusb/1.0.24/include/libusb-1.0 +INCLUDEPATH += /usr/local/Cellar/boost/1.76.0/include +INCLUDEPATH += /usr/local/Cellar/python@3.9/3.9.9/frameworks/Python.framework/versions/3.9/include/python3.9 +INCLUDEPATH += /usr/local/Cellar/libzip/1.8.0_1/include +INCLUDEPATH += /usr/local/Cellar/fftw/3.3.10/include +INCLUDEPATH += /usr/local/Cellar/zlib/1.2.11/include + +INCLUDEPATH += .. +INCLUDEPATH += ../libsigrok4DSL +INCLUDEPATH += ../DSView +INCLUDEPATH += ../DSView/pv/dialogs + +LIBS += /usr/local/Cellar/glib/2.70.1/lib/libglib-2.0.dylib +LIBS += /usr/local/Cellar/libusb/1.0.24/lib/libusb-1.0.dylib +LIBS += /usr/local/Cellar/python@3.9/3.9.9/frameworks/Python.framework/versions/3.9/lib/libpython3.9.dylib +LIBS += /usr/local/Cellar/fftw/3.3.10/lib/libfftw3.a +LIBS += /usr/local/Cellar/zlib/1.2.11/lib/libz.1.2.11.dylib +LIBS += /usr/local/Cellar/libzip/1.8.0_1/lib/libzip.5.4.dylib +} + +SOURCES += \ + ../DSView/main.cpp \ + ../DSView/pv/sigsession.cpp \ + ../DSView/pv/mainwindow.cpp \ + ../DSView/pv/devicemanager.cpp \ + ../DSView/pv/data/snapshot.cpp \ + ../DSView/pv/data/signaldata.cpp \ + ../DSView/pv/data/logicsnapshot.cpp \ + ../DSView/pv/data/logic.cpp \ + ../DSView/pv/data/analogsnapshot.cpp \ + ../DSView/pv/data/analog.cpp \ + ../DSView/pv/dialogs/deviceoptions.cpp \ + ../DSView/pv/prop/property.cpp \ + ../DSView/pv/prop/int.cpp \ + ../DSView/pv/prop/enum.cpp \ + ../DSView/pv/prop/double.cpp \ + ../DSView/pv/prop/bool.cpp \ + ../DSView/pv/prop/binding/binding.cpp \ + ../DSView/pv/toolbars/samplingbar.cpp \ + ../DSView/pv/ui/dscombobox.cpp \ + ../DSView/pv/view/viewport.cpp \ + ../DSView/pv/view/view.cpp \ + ../DSView/pv/view/timemarker.cpp \ + ../DSView/pv/view/signal.cpp \ + ../DSView/pv/view/ruler.cpp \ + ../DSView/pv/view/logicsignal.cpp \ + ../DSView/pv/view/header.cpp \ + ../DSView/pv/view/cursor.cpp \ + ../DSView/pv/view/analogsignal.cpp \ + ../DSView/pv/prop/binding/deviceoptions.cpp \ + ../DSView/pv/toolbars/trigbar.cpp \ + ../DSView/pv/toolbars/filebar.cpp \ + ../DSView/pv/dock/triggerdock.cpp \ + ../DSView/pv/dock/measuredock.cpp \ + ../DSView/pv/dock/searchdock.cpp \ + ../DSView/pv/toolbars/logobar.cpp \ + ../DSView/pv/data/groupsnapshot.cpp \ + ../DSView/pv/view/groupsignal.cpp \ + ../DSView/pv/data/group.cpp \ + ../DSView/pv/dialogs/about.cpp \ + ../DSView/pv/dialogs/search.cpp \ + ../DSView/pv/data/dsosnapshot.cpp \ + ../DSView/pv/data/dso.cpp \ + ../DSView/pv/view/dsosignal.cpp \ + ../DSView/pv/view/dsldial.cpp \ + ../DSView/pv/dock/dsotriggerdock.cpp \ + ../DSView/pv/view/trace.cpp \ + ../DSView/pv/view/selectableitem.cpp \ + ../DSView/pv/widgets/fakelineedit.cpp \ + ../DSView/pv/prop/string.cpp \ + ../DSView/pv/device/sessionfile.cpp \ + ../DSView/pv/device/inputfile.cpp \ + ../DSView/pv/device/file.cpp \ + ../DSView/pv/device/devinst.cpp \ + ../DSView/pv/dialogs/storeprogress.cpp \ + ../DSView/pv/storesession.cpp \ + ../DSView/pv/view/devmode.cpp \ + ../DSView/pv/device/device.cpp \ + ../DSView/pv/dialogs/waitingdialog.cpp \ + ../DSView/pv/dialogs/dsomeasure.cpp \ + ../DSView/pv/dialogs/calibration.cpp \ + ../DSView/pv/dialogs/fftoptions.cpp \ + ../DSView/dsapplication.cpp \ + ../DSView/pv/toolbars/titlebar.cpp \ + ../DSView/pv/mainframe.cpp \ + ../DSView/pv/widgets/border.cpp \ + ../DSView/pv/dialogs/dsmessagebox.cpp \ + ../DSView/pv/dialogs/shadow.cpp \ + ../DSView/pv/dialogs/dsdialog.cpp \ + ../DSView/pv/dialogs/interval.cpp \ + ../DSView/pv/prop/binding/probeoptions.cpp \ + ../DSView/pv/view/xcursor.cpp \ + ../DSView/pv/view/viewstatus.cpp \ + ../DSView/pv/dialogs/lissajousoptions.cpp \ + ../DSView/pv/view/lissajoustrace.cpp \ + ../DSView/pv/view/spectrumtrace.cpp \ + ../DSView/pv/data/spectrumstack.cpp \ + ../DSView/pv/view/mathtrace.cpp \ + ../DSView/pv/dialogs/mathoptions.cpp \ + ../DSView/pv/data/mathstack.cpp \ + ../DSView/pv/dialogs/regionoptions.cpp \ + ../DSView/pv/ZipMaker.cpp \ + ../DSView/pv/data/decode/AnnotationResTable.cpp \ + ../DSView/pv/ui/msgbox.cpp \ + ../DSView/pv/dock/protocolitemlayer.cpp \ + ../DSView/pv/config/appconfig.cpp \ + ../DSView/pv/dsvdef.cpp \ + ../DSView/pv/minizip/zip.c \ + ../DSView/pv/minizip/unzip.c \ + ../DSView/pv/minizip/ioapi.c \ + ../DSView/pv/dialogs/applicationpardlg.cpp \ + ../DSView/pv/appcontrol.cpp \ + ../DSView/pv/eventobject.cpp \ + ../DSView/pv/dstimer.cpp + +HEADERS += \ + ../DSView/extdef.h \ + ../DSView/config.h \ + ../DSView/pv/sigsession.h \ + ../DSView/pv/mainwindow.h \ + ../DSView/pv/devicemanager.h \ + ../DSView/pv/data/snapshot.h \ + ../DSView/pv/data/signaldata.h \ + ../DSView/pv/data/logicsnapshot.h \ + ../DSView/pv/data/logic.h \ + ../DSView/pv/data/analogsnapshot.h \ + ../DSView/pv/data/analog.h \ + ../DSView/pv/dialogs/deviceoptions.h \ + ../DSView/pv/prop/property.h \ + ../DSView/pv/prop/int.h \ + ../DSView/pv/prop/enum.h \ + ../DSView/pv/prop/double.h \ + ../DSView/pv/prop/bool.h \ + ../DSView/pv/prop/binding/deviceoptions.h \ + ../DSView/pv/prop/binding/binding.h \ + ../DSView/pv/toolbars/samplingbar.h \ + ../DSView/pv/ui/dscombobox.h \ + ../DSView/pv/view/viewport.h \ + ../DSView/pv/view/view.h \ + ../DSView/pv/view/timemarker.h \ + ../DSView/pv/view/signal.h \ + ../DSView/pv/view/ruler.h \ + ../DSView/pv/view/logicsignal.h \ + ../DSView/pv/view/header.h \ + ../DSView/pv/view/cursor.h \ + ../DSView/pv/view/analogsignal.h \ + ../DSView/pv/toolbars/trigbar.h \ + ../DSView/pv/toolbars/filebar.h \ + ../DSView/pv/dock/triggerdock.h \ + ../DSView/pv/dock/measuredock.h \ + ../DSView/pv/dock/searchdock.h \ + ../DSView/pv/toolbars/logobar.h \ + ../DSView/pv/data/groupsnapshot.h \ + ../DSView/pv/view/groupsignal.h \ + ../DSView/pv/data/group.h \ + ../DSView/pv/dialogs/about.h \ + ../DSView/pv/dialogs/search.h \ + ../DSView/pv/data/dso.h \ + ../DSView/pv/data/dsosnapshot.h \ + ../DSView/pv/view/dsosignal.h \ + ../DSView/pv/view/dsldial.h \ + ../DSView/pv/dock/dsotriggerdock.h \ + ../DSView/pv/view/trace.h \ + ../DSView/pv/view/selectableitem.h \ + ../DSView/pv/widgets/fakelineedit.h \ + ../DSView/pv/prop/string.h \ + ../DSView/pv/device/sessionfile.h \ + ../DSView/pv/device/inputfile.h \ + ../DSView/pv/device/file.h \ + ../DSView/pv/device/devinst.h \ + ../DSView/pv/dialogs/storeprogress.h \ + ../DSView/pv/storesession.h \ + ../DSView/pv/view/devmode.h \ + ../DSView/pv/device/device.h \ + ../DSView/pv/dialogs/waitingdialog.h \ + ../DSView/pv/dialogs/dsomeasure.h \ + ../DSView/pv/dialogs/calibration.h \ + ../DSView/pv/dialogs/fftoptions.h \ + ../DSView/dsapplication.h \ + ../DSView/pv/toolbars/titlebar.h \ + ../DSView/pv/mainframe.h \ + ../DSView/pv/widgets/border.h \ + ../DSView/pv/dialogs/dsmessagebox.h \ + ../DSView/pv/dialogs/shadow.h \ + ../DSView/pv/dialogs/dsdialog.h \ + ../DSView/pv/dialogs/interval.h \ + ../DSView/config.h \ + ../libsigrok4DSL/config.h \ + ../DSView/pv/prop/binding/probeoptions.h \ + ../libsigrok4DSL/hardware/demo/demo.h \ + ../DSView/pv/view/xcursor.h \ + ../DSView/pv/view/viewstatus.h \ + ../DSView/pv/dialogs/lissajousoptions.h \ + ../DSView/pv/view/lissajoustrace.h \ + ../DSView/pv/view/spectrumtrace.h \ + ../DSView/pv/data/spectrumstack.h \ + ../DSView/pv/view/mathtrace.h \ + ../DSView/pv/dialogs/mathoptions.h \ + ../DSView/pv/data/mathstack.h \ + ../DSView/pv/dialogs/regionoptions.h \ + ../DSView/mystyle.h \ + ../DSView/pv/ZipMaker.h \ + ../DSView/pv/data/decode/AnnotationResTable.h \ + ../DSView/pv/ui/msgbox.h \ + ../DSView/pv/dock/protocolitemlayer.h \ + ../DSView/pv/config/appconfig.h \ + ../DSView/pv/dsvdef.h \ + ../DSView/pv/minizip/zip.h \ + ../DSView/pv/minizip/unzip.h \ + ../DSView/pv/minizip/ioapi.h \ + ../DSView/pv/dialogs/applicationpardlg.h \ + ../DSView/pv/appcontrol.h \ + ../DSView/pv/eventobject.h \ + ../DSView/pv/dstimer.h + +SOURCES += \ + ../libsigrok4DSL/version.c \ + ../libsigrok4DSL/strutil.c \ + ../libsigrok4DSL/std.c \ + ../libsigrok4DSL/session_file.c \ + ../libsigrok4DSL/session_driver.c \ + ../libsigrok4DSL/session.c \ + ../libsigrok4DSL/log.c \ + ../libsigrok4DSL/hwdriver.c \ + ../libsigrok4DSL/error.c \ + ../libsigrok4DSL/backend.c \ + ../libsigrok4DSL/output/output.c \ + ../libsigrok4DSL/input/input.c \ + ../libsigrok4DSL/hardware/demo/demo.c \ + ../libsigrok4DSL/input/in_binary.c \ + ../libsigrok4DSL/input/in_vcd.c \ + ../libsigrok4DSL/input/in_wav.c \ + ../libsigrok4DSL/output/csv.c \ + ../libsigrok4DSL/output/gnuplot.c \ + ../libsigrok4DSL/output/srzip.c \ + ../libsigrok4DSL/output/vcd.c \ + ../libsigrok4DSL/hardware/DSL/dslogic.c \ + ../libsigrok4DSL/hardware/common/usb.c \ + ../libsigrok4DSL/hardware/common/ezusb.c \ + ../libsigrok4DSL/trigger.c \ + ../libsigrok4DSL/dsdevice.c \ + ../libsigrok4DSL/hardware/DSL/dscope.c \ + ../libsigrok4DSL/hardware/DSL/command.c \ + ../libsigrok4DSL/hardware/DSL/dsl.c + +HEADERS += \ + ../libsigrok4DSL/version.h \ + ../libsigrok4DSL/proto.h \ + ../libsigrok4DSL/libsigrok-internal.h \ + ../libsigrok4DSL/libsigrok.h \ + ../libsigrok4DSL/config.h \ + ../libsigrok4DSL/hardware/DSL/command.h \ + ../libsigrok4DSL/hardware/DSL/dsl.h + +decoders { +DEFINES += ENABLE_DECODE +SOURCES += \ + ../DSView/pv/data/decoderstack.cpp \ + ../DSView/pv/data/decode/rowdata.cpp \ + ../DSView/pv/data/decode/row.cpp \ + ../DSView/pv/data/decode/decoder.cpp \ + ../DSView/pv/data/decode/annotation.cpp \ + ../DSView/pv/view/decodetrace.cpp \ + ../DSView/pv/prop/binding/decoderoptions.cpp \ + ../DSView/pv/dock/protocoldock.cpp \ + ../DSView/pv/dialogs/protocollist.cpp \ + ../DSView/pv/dialogs/protocolexp.cpp \ + ../DSView/pv/widgets/decodermenu.cpp \ + ../DSView/pv/widgets/decodergroupbox.cpp \ + ../DSView/pv/data/decodermodel.cpp + +HEADERS += \ + ../DSView/pv/data/decoderstack.h \ + ../DSView/pv/data/decode/rowdata.h \ + ../DSView/pv/data/decode/row.h \ + ../DSView/pv/data/decode/decoder.h \ + ../DSView/pv/data/decode/annotation.h \ + ../DSView/pv/view/decodetrace.h \ + ../DSView/pv/prop/binding/decoderoptions.h \ + ../DSView/pv/dock/protocoldock.h \ + ../DSView/pv/dialogs/protocollist.h \ + ../DSView/pv/dialogs/protocolexp.h \ + ../DSView/pv/widgets/decodermenu.h \ + ../DSView/pv/widgets/decodergroupbox.h \ + ../DSView/pv/data/decodermodel.h + + +#unix:!macx { +#}else{ +SOURCES += \ + #../libsigrokdecode4DSL/type_logic.c \ + ../libsigrokdecode4DSL/type_decoder.c \ + ../libsigrokdecode4DSL/srd.c \ + ../libsigrokdecode4DSL/module_sigrokdecode.c \ + ../libsigrokdecode4DSL/decoder.c \ + ../libsigrokdecode4DSL/error.c \ + ../libsigrokdecode4DSL/exception.c \ + ../libsigrokdecode4DSL/instance.c \ + ../libsigrokdecode4DSL/log.c \ + ../libsigrokdecode4DSL/session.c \ + ../libsigrokdecode4DSL/util.c \ + ../libsigrokdecode4DSL/version.c + +HEADERS += \ + ../libsigrokdecode4DSL/libsigrokdecode-internal.h \ + ../libsigrokdecode4DSL/libsigrokdecode.h \ + ../libsigrokdecode4DSL/config.h \ + ../libsigrokdecode4DSL/version.h +#} +} + +FORMS += + +RESOURCES += \ + ../DSView/DSView.qrc \ + ../DSView/themes/breeze.qrc \ + language.qrc + +ICON = DSView.icns + +MOC_DIR = ../../DSView-build/MOC_DIR +RCC_DIR = ../../DSView-build/RCC_DIR +UI_HEADERS_DIR = ../../DSView-build/UI_HEADERS_DIR +UI_SOURCES_DIR = ../../DSView-build/UI_SOURCES_DIR +UI_DIR = ../../DSView-build/UI_DIR +OBJECTS_DIR = ../../DSView-build/OBJECTS_DIR +DESTDIR = ../../DSView-build/bin From ac1d16041158535a7e616f44e9223be5c12ec0f9 Mon Sep 17 00:00:00 2001 From: DreamSourceLab Date: Thu, 27 Jan 2022 19:19:50 -0800 Subject: [PATCH 59/60] move decoders --- .gitignore | 2 + decoders/0-i2c/__init__.py | 25 - decoders/0-i2c/pd.py | 259 --- decoders/0-spi/__init__.py | 32 - decoders/0-spi/pd.py | 275 --- decoders/0-uart/__init__.py | 40 - decoders/0-uart/pd.py | 353 ---- decoders/1-i2c/__init__.py | 25 - decoders/1-i2c/pd.py | 295 ---- decoders/1-spi/__init__.py | 32 - decoders/1-spi/pd.py | 352 ---- decoders/1-uart/__init__.py | 40 - decoders/1-uart/pd.py | 441 ----- decoders/a7105/__init__.py | 25 - decoders/a7105/pd.py | 356 ---- decoders/ac97/__init__.py | 36 - decoders/ac97/pd.py | 505 ------ decoders/ad5626/__init__.py | 25 - decoders/ad5626/pd.py | 62 - decoders/ad79x0/__init__.py | 25 - decoders/ad79x0/pd.py | 137 -- decoders/ade77xx/__init__.py | 32 - decoders/ade77xx/lists.py | 102 -- decoders/ade77xx/pd.py | 131 -- decoders/adf435x/__init__.py | 29 - decoders/adf435x/pd.py | 144 -- decoders/adns5020/__init__.py | 27 - decoders/adns5020/pd.py | 116 -- decoders/adxl345/__init__.py | 26 - decoders/adxl345/lists.py | 96 - decoders/adxl345/pd.py | 453 ----- decoders/am230x/__init__.py | 36 - decoders/am230x/pd.py | 229 --- decoders/amulet_ascii/__init__.py | 28 - decoders/amulet_ascii/lists.py | 73 - decoders/amulet_ascii/pd.py | 699 -------- decoders/arm_etmv3/__init__.py | 25 - decoders/arm_etmv3/pd.py | 567 ------ decoders/arm_itm/__init__.py | 25 - decoders/arm_itm/pd.py | 373 ---- decoders/arm_tpiu/__init__.py | 28 - decoders/arm_tpiu/pd.py | 131 -- decoders/atsha204a/__init__.py | 30 - decoders/atsha204a/pd.py | 323 ---- decoders/aud/__init__.py | 31 - decoders/aud/pd.py | 107 -- decoders/avr_isp/__init__.py | 25 - decoders/avr_isp/parts.py | 41 - decoders/avr_isp/pd.py | 213 --- decoders/avr_pdi/__init__.py | 42 - decoders/avr_pdi/pd.py | 576 ------ decoders/caliper/__init__.py | 36 - decoders/caliper/pd.py | 146 -- decoders/can/__init__.py | 29 - decoders/can/pd.py | 415 ----- decoders/cc1101/__init__.py | 28 - decoders/cc1101/lists.py | 115 -- decoders/cc1101/pd.py | 296 ---- decoders/cec/__init__.py | 25 - decoders/cec/pd.py | 312 ---- decoders/cec/protocoldata.py | 117 -- decoders/cfp/__init__.py | 34 - decoders/cfp/pd.py | 110 -- decoders/cjtag-oscan0/__init__.py | 37 - decoders/cjtag-oscan0/pd.py | 390 ----- decoders/common/__init__.py | 19 - decoders/common/plugtrx/__init__.py | 20 - decoders/common/plugtrx/mod.py | 192 -- decoders/common/sdcard/__init__.py | 20 - decoders/common/sdcard/mod.py | 151 -- decoders/common/srdhelper/__init__.py | 20 - decoders/common/srdhelper/mod.py | 84 - decoders/counter/__init__.py | 28 - decoders/counter/pd.py | 145 -- decoders/dali/__init__.py | 24 - decoders/dali/lists.py | 98 -- decoders/dali/pd.py | 245 --- decoders/dcf77/__init__.py | 28 - decoders/dcf77/pd.py | 311 ---- decoders/dmx512/__init__.py | 25 - decoders/dmx512/pd.py | 179 -- decoders/ds1307/__init__.py | 25 - decoders/ds1307/pd.py | 264 --- decoders/ds2408/__init__.py | 25 - decoders/ds2408/pd.py | 129 -- decoders/ds243x/__init__.py | 25 - decoders/ds243x/pd.py | 270 --- decoders/ds28ea00/__init__.py | 25 - decoders/ds28ea00/pd.py | 93 - decoders/dsi/__init__.py | 24 - decoders/dsi/pd.py | 157 -- decoders/edid/__init__.py | 35 - decoders/edid/config | 1 - decoders/edid/pd.py | 668 ------- decoders/edid/pnpids.txt | 2135 ----------------------- decoders/eeprom24xx/__init__.py | 25 - decoders/eeprom24xx/lists.py | 204 --- decoders/eeprom24xx/pd.py | 433 ----- decoders/eeprom93xx/__init__.py | 32 - decoders/eeprom93xx/pd.py | 141 -- decoders/em4100/__init__.py | 24 - decoders/em4100/pd.py | 238 --- decoders/em4305/__init__.py | 24 - decoders/em4305/pd.py | 394 ----- decoders/enc28j60/__init__.py | 32 - decoders/enc28j60/lists.py | 161 -- decoders/enc28j60/pd.py | 294 ---- decoders/flexray/__init__.py | 32 - decoders/flexray/pd.py | 413 ----- decoders/fsi/__init__.py | 25 - decoders/fsi/pd.py | 574 ------ decoders/gpib/__init__.py | 24 - decoders/gpib/pd.py | 182 -- decoders/graycode/__init__.py | 24 - decoders/graycode/pd.py | 200 --- decoders/guess_bitrate/__init__.py | 40 - decoders/guess_bitrate/pd.py | 79 - decoders/hdcp/__init__.py | 27 - decoders/hdcp/pd.py | 191 -- decoders/i2cdemux/__init__.py | 27 - decoders/i2cdemux/pd.py | 80 - decoders/i2cfilter/__init__.py | 37 - decoders/i2cfilter/pd.py | 93 - decoders/i2s/__init__.py | 29 - decoders/i2s/pd.py | 214 --- decoders/iec/__init__.py | 24 - decoders/iec/pd.py | 168 -- decoders/ieee488/__init__.py | 26 - decoders/ieee488/pd.py | 748 -------- decoders/ir_irmp/__init__.py | 25 - decoders/ir_irmp/irmp_library.py | 137 -- decoders/ir_irmp/pd.py | 137 -- decoders/ir_nec/__init__.py | 24 - decoders/ir_nec/lists.py | 50 - decoders/ir_nec/pd.py | 237 --- decoders/ir_rc5/__init__.py | 24 - decoders/ir_rc5/lists.py | 93 - decoders/ir_rc5/pd.py | 187 -- decoders/ir_rc6/__init__.py | 24 - decoders/ir_rc6/pd.py | 205 --- decoders/ir_sirc/__init__.py | 26 - decoders/ir_sirc/lists.py | 201 --- decoders/ir_sirc/pd.py | 215 --- decoders/jitter/__init__.py | 29 - decoders/jitter/pd.py | 198 --- decoders/jtag/__init__.py | 30 - decoders/jtag/pd.py | 289 --- decoders/jtag_ejtag/__init__.py | 25 - decoders/jtag_ejtag/pd.py | 408 ----- decoders/jtag_stm32/__init__.py | 29 - decoders/jtag_stm32/pd.py | 269 --- decoders/lfast/__init__.py | 35 - decoders/lfast/pd.py | 335 ---- decoders/lin/__init__.py | 28 - decoders/lin/pd.py | 235 --- decoders/lm75/__init__.py | 25 - decoders/lm75/pd.py | 186 -- decoders/lpc/__init__.py | 25 - decoders/lpc/pd.py | 547 ------ decoders/ltc242x/__init__.py | 25 - decoders/ltc242x/pd.py | 86 - decoders/ltc26x7/__init__.py | 25 - decoders/ltc26x7/pd.py | 187 -- decoders/maple_bus/__init__.py | 25 - decoders/maple_bus/pd.py | 219 --- decoders/max7219/__init__.py | 25 - decoders/max7219/pd.py | 115 -- decoders/mcs48/__init__.py | 31 - decoders/mcs48/pd.py | 119 -- decoders/mdio/__init__.py | 39 - decoders/mdio/pd.py | 327 ---- decoders/microwire/__init__.py | 40 - decoders/microwire/pd.py | 195 --- decoders/midi/__init__.py | 28 - decoders/midi/lists.py | 840 --------- decoders/midi/pd.py | 627 ------- decoders/miller/__init__.py | 26 - decoders/miller/pd.py | 190 -- decoders/mipi_dsi/__init__.py | 24 - decoders/mipi_dsi/pd.py | 218 --- decoders/mipi_rffe/__init__.py | 25 - decoders/mipi_rffe/pd.py | 510 ------ decoders/mlx90614/__init__.py | 25 - decoders/mlx90614/pd.py | 78 - decoders/modbus/__init__.py | 28 - decoders/modbus/pd.py | 934 ---------- decoders/morse/__init__.py | 28 - decoders/morse/pd.py | 250 --- decoders/mrf24j40/__init__.py | 25 - decoders/mrf24j40/lists.py | 165 -- decoders/mrf24j40/pd.py | 137 -- decoders/mxc6225xu/__init__.py | 28 - decoders/mxc6225xu/pd.py | 217 --- decoders/nes_gamepad/__init__.py | 54 - decoders/nes_gamepad/pd.py | 105 -- decoders/nrf24l01/__init__.py | 29 - decoders/nrf24l01/pd.py | 370 ---- decoders/nrf905/__init__.py | 26 - decoders/nrf905/pd.py | 301 ---- decoders/numbers_and_state/__init__.py | 41 - decoders/numbers_and_state/pd.py | 377 ---- decoders/nunchuk/__init__.py | 30 - decoders/nunchuk/pd.py | 207 --- decoders/onewire_link/__init__.py | 56 - decoders/onewire_link/pd.py | 347 ---- decoders/onewire_network/__init__.py | 56 - decoders/onewire_network/pd.py | 185 -- decoders/ook/__init__.py | 36 - decoders/ook/pd.py | 484 ----- decoders/ook_oregon/__init__.py | 25 - decoders/ook_oregon/lists.py | 75 - decoders/ook_oregon/pd.py | 389 ----- decoders/ook_vis/__init__.py | 25 - decoders/ook_vis/pd.py | 194 -- decoders/pan1321/__init__.py | 25 - decoders/pan1321/pd.py | 164 -- decoders/parallel/__init__.py | 34 - decoders/parallel/pd.py | 213 --- decoders/pca9571/__init__.py | 25 - decoders/pca9571/pd.py | 102 -- decoders/pjdl/__init__.py | 27 - decoders/pjdl/pd.py | 723 -------- decoders/pjon/__init__.py | 25 - decoders/pjon/pd.py | 603 ------- decoders/ps2/__init__.py | 26 - decoders/ps2/pd.py | 193 -- decoders/pwm/__init__.py | 24 - decoders/pwm/pd.py | 141 -- decoders/qi/__init__.py | 25 - decoders/qi/pd.py | 244 --- decoders/qspi/__init__.py | 31 - decoders/qspi/pd.py | 226 --- decoders/rc_encode/__init__.py | 36 - decoders/rc_encode/pd.py | 167 -- decoders/rfm12/__init__.py | 25 - decoders/rfm12/pd.py | 497 ------ decoders/rgb_led_spi/__init__.py | 25 - decoders/rgb_led_spi/pd.py | 70 - decoders/rgb_led_ws281x/__init__.py | 27 - decoders/rgb_led_ws281x/pd.py | 195 --- decoders/rtc8564/__init__.py | 25 - decoders/rtc8564/pd.py | 254 --- decoders/sae_j1850_vpw/__init__.py | 24 - decoders/sae_j1850_vpw/pd.py | 165 -- decoders/sda2506/__init__.py | 24 - decoders/sda2506/pd.py | 144 -- decoders/sdcard_sd/__init__.py | 24 - decoders/sdcard_sd/pd.py | 583 ------- decoders/sdcard_spi/__init__.py | 68 - decoders/sdcard_spi/pd.py | 465 ----- decoders/sdq/__init__.py | 28 - decoders/sdq/pd.py | 131 -- decoders/seven_segment/__init__.py | 24 - decoders/seven_segment/pd.py | 136 -- decoders/signature/__init__.py | 25 - decoders/signature/pd.py | 142 -- decoders/sipi/__init__.py | 30 - decoders/sipi/pd.py | 181 -- decoders/sle44xx/__init__.py | 26 - decoders/sle44xx/pd.py | 541 ------ decoders/spdif/__init__.py | 25 - decoders/spdif/pd.py | 246 --- decoders/spiflash/__init__.py | 30 - decoders/spiflash/lists.py | 144 -- decoders/spiflash/pd.py | 539 ------ decoders/ssi32/__init__.py | 28 - decoders/ssi32/pd.py | 127 -- decoders/st25r39xx_spi/__init__.py | 31 - decoders/st25r39xx_spi/lists.py | 231 --- decoders/st25r39xx_spi/pd.py | 350 ---- decoders/st7735/__init__.py | 27 - decoders/st7735/pd.py | 173 -- decoders/st7789/__init__.py | 7 - decoders/st7789/pd.py | 296 ---- decoders/stepper_motor/__init__.py | 25 - decoders/stepper_motor/pd.py | 95 - decoders/swd/__init__.py | 34 - decoders/swd/pd.py | 350 ---- decoders/swim/__init__.py | 29 - decoders/swim/pd.py | 304 ---- decoders/t55xx/__init__.py | 25 - decoders/t55xx/pd.py | 326 ---- decoders/tca6408a/__init__.py | 25 - decoders/tca6408a/pd.py | 132 -- decoders/tdm_audio/__init__.py | 25 - decoders/tdm_audio/pd.py | 116 -- decoders/timing/__init__.py | 24 - decoders/timing/pd.py | 128 -- decoders/tlc5620/__init__.py | 24 - decoders/tlc5620/pd.py | 210 --- decoders/usb_packet/__init__.py | 43 - decoders/usb_packet/pd.py | 397 ----- decoders/usb_power_delivery/__init__.py | 24 - decoders/usb_power_delivery/pd.py | 639 ------- decoders/usb_request/__init__.py | 49 - decoders/usb_request/pd.py | 371 ---- decoders/usb_signalling/__init__.py | 50 - decoders/usb_signalling/pd.py | 352 ---- decoders/wiegand/__init__.py | 28 - decoders/wiegand/pd.py | 148 -- decoders/x2444m/__init__.py | 25 - decoders/x2444m/pd.py | 111 -- decoders/xfp/__init__.py | 38 - decoders/xfp/pd.py | 482 ----- decoders/xy2-100/__init__.py | 28 - decoders/xy2-100/pd.py | 242 --- decoders/z80/__init__.py | 36 - decoders/z80/pd.py | 359 ---- decoders/z80/tables.py | 1083 ------------ test/decode_test/core.c | 104 -- test/decode_test/decoder.c | 467 ----- test/decode_test/inst.c | 163 -- test/decode_test/lib.h | 31 - test/decode_test/main.c | 56 - test/decode_test/session.c | 290 --- 315 files changed, 2 insertions(+), 51138 deletions(-) delete mode 100755 decoders/0-i2c/__init__.py delete mode 100755 decoders/0-i2c/pd.py delete mode 100755 decoders/0-spi/__init__.py delete mode 100755 decoders/0-spi/pd.py delete mode 100755 decoders/0-uart/__init__.py delete mode 100755 decoders/0-uart/pd.py delete mode 100755 decoders/1-i2c/__init__.py delete mode 100755 decoders/1-i2c/pd.py delete mode 100755 decoders/1-spi/__init__.py delete mode 100755 decoders/1-spi/pd.py delete mode 100755 decoders/1-uart/__init__.py delete mode 100755 decoders/1-uart/pd.py delete mode 100644 decoders/a7105/__init__.py delete mode 100644 decoders/a7105/pd.py delete mode 100755 decoders/ac97/__init__.py delete mode 100755 decoders/ac97/pd.py delete mode 100644 decoders/ad5626/__init__.py delete mode 100644 decoders/ad5626/pd.py delete mode 100644 decoders/ad79x0/__init__.py delete mode 100644 decoders/ad79x0/pd.py delete mode 100755 decoders/ade77xx/__init__.py delete mode 100755 decoders/ade77xx/lists.py delete mode 100755 decoders/ade77xx/pd.py delete mode 100755 decoders/adf435x/__init__.py delete mode 100755 decoders/adf435x/pd.py delete mode 100755 decoders/adns5020/__init__.py delete mode 100755 decoders/adns5020/pd.py delete mode 100644 decoders/adxl345/__init__.py delete mode 100644 decoders/adxl345/lists.py delete mode 100644 decoders/adxl345/pd.py delete mode 100755 decoders/am230x/__init__.py delete mode 100755 decoders/am230x/pd.py delete mode 100644 decoders/amulet_ascii/__init__.py delete mode 100644 decoders/amulet_ascii/lists.py delete mode 100644 decoders/amulet_ascii/pd.py delete mode 100755 decoders/arm_etmv3/__init__.py delete mode 100755 decoders/arm_etmv3/pd.py delete mode 100755 decoders/arm_itm/__init__.py delete mode 100755 decoders/arm_itm/pd.py delete mode 100755 decoders/arm_tpiu/__init__.py delete mode 100755 decoders/arm_tpiu/pd.py delete mode 100755 decoders/atsha204a/__init__.py delete mode 100755 decoders/atsha204a/pd.py delete mode 100755 decoders/aud/__init__.py delete mode 100755 decoders/aud/pd.py delete mode 100755 decoders/avr_isp/__init__.py delete mode 100755 decoders/avr_isp/parts.py delete mode 100755 decoders/avr_isp/pd.py delete mode 100755 decoders/avr_pdi/__init__.py delete mode 100755 decoders/avr_pdi/pd.py delete mode 100644 decoders/caliper/__init__.py delete mode 100644 decoders/caliper/pd.py delete mode 100755 decoders/can/__init__.py delete mode 100755 decoders/can/pd.py delete mode 100644 decoders/cc1101/__init__.py delete mode 100644 decoders/cc1101/lists.py delete mode 100644 decoders/cc1101/pd.py delete mode 100755 decoders/cec/__init__.py delete mode 100755 decoders/cec/pd.py delete mode 100755 decoders/cec/protocoldata.py delete mode 100755 decoders/cfp/__init__.py delete mode 100755 decoders/cfp/pd.py delete mode 100644 decoders/cjtag-oscan0/__init__.py delete mode 100644 decoders/cjtag-oscan0/pd.py delete mode 100755 decoders/common/__init__.py delete mode 100755 decoders/common/plugtrx/__init__.py delete mode 100755 decoders/common/plugtrx/mod.py delete mode 100755 decoders/common/sdcard/__init__.py delete mode 100755 decoders/common/sdcard/mod.py delete mode 100755 decoders/common/srdhelper/__init__.py delete mode 100755 decoders/common/srdhelper/mod.py delete mode 100755 decoders/counter/__init__.py delete mode 100755 decoders/counter/pd.py delete mode 100755 decoders/dali/__init__.py delete mode 100755 decoders/dali/lists.py delete mode 100755 decoders/dali/pd.py delete mode 100755 decoders/dcf77/__init__.py delete mode 100755 decoders/dcf77/pd.py delete mode 100755 decoders/dmx512/__init__.py delete mode 100755 decoders/dmx512/pd.py delete mode 100755 decoders/ds1307/__init__.py delete mode 100755 decoders/ds1307/pd.py delete mode 100644 decoders/ds2408/__init__.py delete mode 100644 decoders/ds2408/pd.py delete mode 100755 decoders/ds243x/__init__.py delete mode 100755 decoders/ds243x/pd.py delete mode 100755 decoders/ds28ea00/__init__.py delete mode 100755 decoders/ds28ea00/pd.py delete mode 100755 decoders/dsi/__init__.py delete mode 100755 decoders/dsi/pd.py delete mode 100755 decoders/edid/__init__.py delete mode 100755 decoders/edid/config delete mode 100755 decoders/edid/pd.py delete mode 100755 decoders/edid/pnpids.txt delete mode 100755 decoders/eeprom24xx/__init__.py delete mode 100755 decoders/eeprom24xx/lists.py delete mode 100755 decoders/eeprom24xx/pd.py delete mode 100755 decoders/eeprom93xx/__init__.py delete mode 100755 decoders/eeprom93xx/pd.py delete mode 100755 decoders/em4100/__init__.py delete mode 100755 decoders/em4100/pd.py delete mode 100755 decoders/em4305/__init__.py delete mode 100755 decoders/em4305/pd.py delete mode 100644 decoders/enc28j60/__init__.py delete mode 100644 decoders/enc28j60/lists.py delete mode 100644 decoders/enc28j60/pd.py delete mode 100644 decoders/flexray/__init__.py delete mode 100644 decoders/flexray/pd.py delete mode 100755 decoders/fsi/__init__.py delete mode 100755 decoders/fsi/pd.py delete mode 100755 decoders/gpib/__init__.py delete mode 100755 decoders/gpib/pd.py delete mode 100755 decoders/graycode/__init__.py delete mode 100755 decoders/graycode/pd.py delete mode 100755 decoders/guess_bitrate/__init__.py delete mode 100755 decoders/guess_bitrate/pd.py delete mode 100644 decoders/hdcp/__init__.py delete mode 100644 decoders/hdcp/pd.py delete mode 100755 decoders/i2cdemux/__init__.py delete mode 100755 decoders/i2cdemux/pd.py delete mode 100755 decoders/i2cfilter/__init__.py delete mode 100755 decoders/i2cfilter/pd.py delete mode 100755 decoders/i2s/__init__.py delete mode 100755 decoders/i2s/pd.py delete mode 100755 decoders/iec/__init__.py delete mode 100755 decoders/iec/pd.py delete mode 100644 decoders/ieee488/__init__.py delete mode 100644 decoders/ieee488/pd.py delete mode 100644 decoders/ir_irmp/__init__.py delete mode 100644 decoders/ir_irmp/irmp_library.py delete mode 100644 decoders/ir_irmp/pd.py delete mode 100755 decoders/ir_nec/__init__.py delete mode 100755 decoders/ir_nec/lists.py delete mode 100755 decoders/ir_nec/pd.py delete mode 100755 decoders/ir_rc5/__init__.py delete mode 100755 decoders/ir_rc5/lists.py delete mode 100755 decoders/ir_rc5/pd.py delete mode 100644 decoders/ir_rc6/__init__.py delete mode 100644 decoders/ir_rc6/pd.py delete mode 100644 decoders/ir_sirc/__init__.py delete mode 100644 decoders/ir_sirc/lists.py delete mode 100644 decoders/ir_sirc/pd.py delete mode 100755 decoders/jitter/__init__.py delete mode 100755 decoders/jitter/pd.py delete mode 100755 decoders/jtag/__init__.py delete mode 100755 decoders/jtag/pd.py delete mode 100755 decoders/jtag_ejtag/__init__.py delete mode 100755 decoders/jtag_ejtag/pd.py delete mode 100755 decoders/jtag_stm32/__init__.py delete mode 100755 decoders/jtag_stm32/pd.py delete mode 100644 decoders/lfast/__init__.py delete mode 100644 decoders/lfast/pd.py delete mode 100755 decoders/lin/__init__.py delete mode 100755 decoders/lin/pd.py delete mode 100755 decoders/lm75/__init__.py delete mode 100755 decoders/lm75/pd.py delete mode 100755 decoders/lpc/__init__.py delete mode 100755 decoders/lpc/pd.py delete mode 100644 decoders/ltc242x/__init__.py delete mode 100644 decoders/ltc242x/pd.py delete mode 100644 decoders/ltc26x7/__init__.py delete mode 100644 decoders/ltc26x7/pd.py delete mode 100755 decoders/maple_bus/__init__.py delete mode 100755 decoders/maple_bus/pd.py delete mode 100755 decoders/max7219/__init__.py delete mode 100755 decoders/max7219/pd.py delete mode 100755 decoders/mcs48/__init__.py delete mode 100755 decoders/mcs48/pd.py delete mode 100755 decoders/mdio/__init__.py delete mode 100755 decoders/mdio/pd.py delete mode 100755 decoders/microwire/__init__.py delete mode 100755 decoders/microwire/pd.py delete mode 100755 decoders/midi/__init__.py delete mode 100755 decoders/midi/lists.py delete mode 100755 decoders/midi/pd.py delete mode 100755 decoders/miller/__init__.py delete mode 100755 decoders/miller/pd.py delete mode 100644 decoders/mipi_dsi/__init__.py delete mode 100644 decoders/mipi_dsi/pd.py delete mode 100644 decoders/mipi_rffe/__init__.py delete mode 100644 decoders/mipi_rffe/pd.py delete mode 100755 decoders/mlx90614/__init__.py delete mode 100755 decoders/mlx90614/pd.py delete mode 100755 decoders/modbus/__init__.py delete mode 100755 decoders/modbus/pd.py delete mode 100755 decoders/morse/__init__.py delete mode 100755 decoders/morse/pd.py delete mode 100755 decoders/mrf24j40/__init__.py delete mode 100755 decoders/mrf24j40/lists.py delete mode 100755 decoders/mrf24j40/pd.py delete mode 100755 decoders/mxc6225xu/__init__.py delete mode 100755 decoders/mxc6225xu/pd.py delete mode 100644 decoders/nes_gamepad/__init__.py delete mode 100644 decoders/nes_gamepad/pd.py delete mode 100755 decoders/nrf24l01/__init__.py delete mode 100755 decoders/nrf24l01/pd.py delete mode 100644 decoders/nrf905/__init__.py delete mode 100644 decoders/nrf905/pd.py delete mode 100644 decoders/numbers_and_state/__init__.py delete mode 100644 decoders/numbers_and_state/pd.py delete mode 100755 decoders/nunchuk/__init__.py delete mode 100755 decoders/nunchuk/pd.py delete mode 100755 decoders/onewire_link/__init__.py delete mode 100755 decoders/onewire_link/pd.py delete mode 100755 decoders/onewire_network/__init__.py delete mode 100755 decoders/onewire_network/pd.py delete mode 100755 decoders/ook/__init__.py delete mode 100755 decoders/ook/pd.py delete mode 100755 decoders/ook_oregon/__init__.py delete mode 100755 decoders/ook_oregon/lists.py delete mode 100755 decoders/ook_oregon/pd.py delete mode 100755 decoders/ook_vis/__init__.py delete mode 100755 decoders/ook_vis/pd.py delete mode 100755 decoders/pan1321/__init__.py delete mode 100755 decoders/pan1321/pd.py delete mode 100755 decoders/parallel/__init__.py delete mode 100755 decoders/parallel/pd.py delete mode 100644 decoders/pca9571/__init__.py delete mode 100644 decoders/pca9571/pd.py delete mode 100644 decoders/pjdl/__init__.py delete mode 100644 decoders/pjdl/pd.py delete mode 100644 decoders/pjon/__init__.py delete mode 100644 decoders/pjon/pd.py delete mode 100755 decoders/ps2/__init__.py delete mode 100755 decoders/ps2/pd.py delete mode 100755 decoders/pwm/__init__.py delete mode 100755 decoders/pwm/pd.py delete mode 100755 decoders/qi/__init__.py delete mode 100755 decoders/qi/pd.py delete mode 100644 decoders/qspi/__init__.py delete mode 100644 decoders/qspi/pd.py delete mode 100755 decoders/rc_encode/__init__.py delete mode 100755 decoders/rc_encode/pd.py delete mode 100755 decoders/rfm12/__init__.py delete mode 100755 decoders/rfm12/pd.py delete mode 100755 decoders/rgb_led_spi/__init__.py delete mode 100755 decoders/rgb_led_spi/pd.py delete mode 100755 decoders/rgb_led_ws281x/__init__.py delete mode 100755 decoders/rgb_led_ws281x/pd.py delete mode 100755 decoders/rtc8564/__init__.py delete mode 100755 decoders/rtc8564/pd.py delete mode 100644 decoders/sae_j1850_vpw/__init__.py delete mode 100644 decoders/sae_j1850_vpw/pd.py delete mode 100755 decoders/sda2506/__init__.py delete mode 100755 decoders/sda2506/pd.py delete mode 100755 decoders/sdcard_sd/__init__.py delete mode 100755 decoders/sdcard_sd/pd.py delete mode 100755 decoders/sdcard_spi/__init__.py delete mode 100755 decoders/sdcard_spi/pd.py delete mode 100644 decoders/sdq/__init__.py delete mode 100644 decoders/sdq/pd.py delete mode 100644 decoders/seven_segment/__init__.py delete mode 100644 decoders/seven_segment/pd.py delete mode 100644 decoders/signature/__init__.py delete mode 100644 decoders/signature/pd.py delete mode 100644 decoders/sipi/__init__.py delete mode 100644 decoders/sipi/pd.py delete mode 100644 decoders/sle44xx/__init__.py delete mode 100644 decoders/sle44xx/pd.py delete mode 100755 decoders/spdif/__init__.py delete mode 100755 decoders/spdif/pd.py delete mode 100755 decoders/spiflash/__init__.py delete mode 100755 decoders/spiflash/lists.py delete mode 100755 decoders/spiflash/pd.py delete mode 100755 decoders/ssi32/__init__.py delete mode 100755 decoders/ssi32/pd.py delete mode 100644 decoders/st25r39xx_spi/__init__.py delete mode 100644 decoders/st25r39xx_spi/lists.py delete mode 100644 decoders/st25r39xx_spi/pd.py delete mode 100755 decoders/st7735/__init__.py delete mode 100755 decoders/st7735/pd.py delete mode 100644 decoders/st7789/__init__.py delete mode 100644 decoders/st7789/pd.py delete mode 100755 decoders/stepper_motor/__init__.py delete mode 100755 decoders/stepper_motor/pd.py delete mode 100755 decoders/swd/__init__.py delete mode 100755 decoders/swd/pd.py delete mode 100755 decoders/swim/__init__.py delete mode 100755 decoders/swim/pd.py delete mode 100755 decoders/t55xx/__init__.py delete mode 100755 decoders/t55xx/pd.py delete mode 100755 decoders/tca6408a/__init__.py delete mode 100755 decoders/tca6408a/pd.py delete mode 100644 decoders/tdm_audio/__init__.py delete mode 100644 decoders/tdm_audio/pd.py delete mode 100755 decoders/timing/__init__.py delete mode 100755 decoders/timing/pd.py delete mode 100755 decoders/tlc5620/__init__.py delete mode 100755 decoders/tlc5620/pd.py delete mode 100755 decoders/usb_packet/__init__.py delete mode 100755 decoders/usb_packet/pd.py delete mode 100755 decoders/usb_power_delivery/__init__.py delete mode 100755 decoders/usb_power_delivery/pd.py delete mode 100755 decoders/usb_request/__init__.py delete mode 100755 decoders/usb_request/pd.py delete mode 100755 decoders/usb_signalling/__init__.py delete mode 100755 decoders/usb_signalling/pd.py delete mode 100755 decoders/wiegand/__init__.py delete mode 100755 decoders/wiegand/pd.py delete mode 100644 decoders/x2444m/__init__.py delete mode 100644 decoders/x2444m/pd.py delete mode 100755 decoders/xfp/__init__.py delete mode 100755 decoders/xfp/pd.py delete mode 100644 decoders/xy2-100/__init__.py delete mode 100644 decoders/xy2-100/pd.py delete mode 100755 decoders/z80/__init__.py delete mode 100755 decoders/z80/pd.py delete mode 100755 decoders/z80/tables.py delete mode 100755 test/decode_test/core.c delete mode 100755 test/decode_test/decoder.c delete mode 100755 test/decode_test/inst.c delete mode 100755 test/decode_test/lib.h delete mode 100755 test/decode_test/main.c delete mode 100755 test/decode_test/session.c diff --git a/.gitignore b/.gitignore index c855d007..da76bd66 100755 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,5 @@ DSView-prj build* share .vscode +qtpro +test diff --git a/decoders/0-i2c/__init__.py b/decoders/0-i2c/__init__.py deleted file mode 100755 index 2a36b060..00000000 --- a/decoders/0-i2c/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -''' -I²C (Inter-Integrated Circuit) is a bidirectional, multi-master -bus using two signals (SCL = serial clock line, SDA = serial data line). -''' - -from .pd import Decoder diff --git a/decoders/0-i2c/pd.py b/decoders/0-i2c/pd.py deleted file mode 100755 index dad9922d..00000000 --- a/decoders/0-i2c/pd.py +++ /dev/null @@ -1,259 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2010-2016 Uwe Hermann -## Copyright (C) 2019 DreamSourceLab -## -## 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, see . -## - -# TODO: Look into arbitration, collision detection, clock synchronisation, etc. -# TODO: Implement support for inverting SDA/SCL levels (0->1 and 1->0). -# TODO: Implement support for detecting various bus errors. - -import sigrokdecode as srd - -''' -OUTPUT_PYTHON format: - -Packet: -[, ] - -: - - 'START' (START condition) - - 'START REPEAT' (Repeated START condition) - - 'ADDRESS READ' (Slave address, read) - - 'ADDRESS WRITE' (Slave address, write) - - 'DATA READ' (Data, read) - - 'DATA WRITE' (Data, write) - - 'STOP' (STOP condition) - - 'ACK' (ACK bit) - - 'NACK' (NACK bit) - - 'BITS' (: list of data/address bits and their ss/es numbers) - - is the data or address byte associated with the 'ADDRESS*' and 'DATA*' -command. Slave addresses do not include bit 0 (the READ/WRITE indication bit). -For example, a slave address field could be 0x51 (instead of 0xa2). -For 'START', 'START REPEAT', 'STOP', 'ACK', and 'NACK' is None. -''' - -# CMD: [annotation-type-index, long annotation, short annotation] -proto = { - 'START': [0, 'Start', 'S'], - 'START REPEAT': [1, 'Start repeat', 'Sr'], - 'STOP': [2, 'Stop', 'P'], - 'ACK': [3, 'ACK', 'A'], - 'NACK': [4, 'NACK', 'N'], - 'ADDRESS READ': [5, 'Address read', 'AR'], - 'ADDRESS WRITE': [6, 'Address write', 'AW'], - 'DATA READ': [7, 'Data read', 'DR'], - 'DATA WRITE': [8, 'Data write', 'DW'], -} - -class Decoder(srd.Decoder): - api_version = 3 - id = '0:i2c' - name = '0:I²C' - longname = 'Inter-Integrated Circuit' - desc = 'Two-wire, multi-master, serial bus.' - license = 'gplv2+' - inputs = ['logic'] - outputs = ['i2c'] - tags = ['Embedded/industrial'] - channels = ( - {'id': 'scl', 'type': 8, 'name': 'SCL', 'desc': 'Serial clock line'}, - {'id': 'sda', 'type': 108, 'name': 'SDA', 'desc': 'Serial data line'}, - ) - options = ( - {'id': 'address_format', 'desc': 'Displayed slave address format', - 'default': 'shifted', 'values': ('shifted', 'unshifted')}, - ) - annotations = ( - ('7', 'start', 'Start condition'), - ('6', 'repeat-start', 'Repeat start condition'), - ('1', 'stop', 'Stop condition'), - ('5', 'ack', 'ACK'), - ('0', 'nack', 'NACK'), - ('112', 'address-read', 'Address read'), - ('111', 'address-write', 'Address write'), - ('110', 'data-read', 'Data read'), - ('109', 'data-write', 'Data write'), - ('1000', 'warnings', 'Human-readable warnings'), - ) - annotation_rows = ( - ('addr-data', 'Address/Data', (0, 1, 2, 3, 4, 5, 6, 7, 8)), - ('warnings', 'Warnings', (9,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.ss = self.es = self.ss_byte = -1 - self.bitcount = 0 - self.databyte = 0 - self.wr = -1 - self.is_repeat_start = 0 - self.state = 'FIND START' - self.pdu_start = None - self.pdu_bits = 0 - self.bits = [] - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putx(self, data): - self.put(self.ss, self.es, self.out_ann, data) - - def handle_start(self): - self.ss, self.es = self.samplenum, self.samplenum - self.pdu_start = self.samplenum - self.pdu_bits = 0 - cmd = 'START REPEAT' if (self.is_repeat_start == 1) else 'START' - self.putx([proto[cmd][0], proto[cmd][1:]]) - self.state = 'FIND ADDRESS' - self.bitcount = self.databyte = 0 - self.is_repeat_start = 1 - self.wr = -1 - self.bits = [] - - # Gather 8 bits of data plus the ACK/NACK bit. - def handle_address_or_data(self, scl, sda): - self.pdu_bits += 1 - - # Address and data are transmitted MSB-first. - self.databyte <<= 1 - self.databyte |= sda - - # Remember the start of the first data/address bit. - if self.bitcount == 0: - self.ss_byte = self.samplenum - - # Store individual bits and their start/end samplenumbers. - # In the list, index 0 represents the LSB (I²C transmits MSB-first). - self.bits.insert(0, [sda, self.samplenum, self.samplenum]) - if self.bitcount > 0: - self.bits[1][2] = self.samplenum - if self.bitcount == 7: - self.bitwidth = self.bits[1][2] - self.bits[2][2] - self.bits[0][2] += self.bitwidth - - # Return if we haven't collected all 8 + 1 bits, yet. - if self.bitcount < 7: - self.bitcount += 1 - return - - d = self.databyte - if self.state == 'FIND ADDRESS': - # The READ/WRITE bit is only in address bytes, not data bytes. - self.wr = 0 if (self.databyte & 1) else 1 - if self.options['address_format'] == 'shifted': - d = d >> 1 - - bin_class = -1 - if self.state == 'FIND ADDRESS' and self.wr == 1: - cmd = 'ADDRESS WRITE' - bin_class = 1 - elif self.state == 'FIND ADDRESS' and self.wr == 0: - cmd = 'ADDRESS READ' - bin_class = 0 - elif self.state == 'FIND DATA' and self.wr == 1: - cmd = 'DATA WRITE' - bin_class = 3 - elif self.state == 'FIND DATA' and self.wr == 0: - cmd = 'DATA READ' - bin_class = 2 - - self.ss, self.es = self.ss_byte, self.samplenum + self.bitwidth - - if cmd.startswith('ADDRESS'): - self.ss, self.es = self.samplenum, self.samplenum + self.bitwidth - w = ['Write', 'Wr', 'W'] if self.wr else ['Read', 'Rd', 'R'] - self.putx([proto[cmd][0], w]) - self.ss, self.es = self.ss_byte, self.samplenum - - self.putx([proto[cmd][0], ['%s: {$}' % proto[cmd][1], '%s: {$}' % proto[cmd][2], '{$}', d]]) - - # Done with this packet. - self.bitcount = self.databyte = 0 - self.bits = [] - self.state = 'FIND ACK' - - def get_ack(self, scl, sda): - self.ss, self.es = self.samplenum, self.samplenum + self.bitwidth - cmd = 'NACK' if (sda == 1) else 'ACK' - self.putx([proto[cmd][0], proto[cmd][1:]]) - # There could be multiple data bytes in a row, so either find - # another data byte or a STOP condition next. - self.state = 'FIND DATA' - - def handle_stop(self): - cmd = 'STOP' - self.ss, self.es = self.samplenum, self.samplenum - self.putx([proto[cmd][0], proto[cmd][1:]]) - self.state = 'FIND START' - self.is_repeat_start = 0 - self.wr = -1 - self.bits = [] - - def decode(self): - while True: - # State machine. - if self.state == 'FIND START': - # Wait for a START condition (S): SCL = high, SDA = falling. - self.wait({0: 'h', 1: 'f'}) - self.handle_start() - elif self.state == 'FIND ADDRESS': - # Wait for any of the following conditions (or combinations): - # a) Data sampling of receiver: SCL = rising, and/or - # b) START condition (S): SCL = high, SDA = falling, and/or - # c) STOP condition (P): SCL = high, SDA = rising - (scl, sda) = self.wait([{0: 'r'}, {0: 'h', 1: 'f'}, {0: 'h', 1: 'r'}]) - - # Check which of the condition(s) matched and handle them. - if (self.matched & (0b1 << 0)): - self.handle_address_or_data(scl, sda) - elif (self.matched & (0b1 << 1)): - self.handle_start() - elif (self.matched & (0b1 << 2)): - self.handle_stop() - elif self.state == 'FIND DATA': - # Wait for any of the following conditions (or combinations): - # a) Data sampling of receiver: SCL = rising, and/or - # b) START condition (S): SCL = high, SDA = falling, and/or - # c) STOP condition (P): SCL = high, SDA = rising - (scl, sda) = self.wait([{0: 'r'}, {0: 'h', 1: 'f'}, {0: 'h', 1: 'r'}]) - - # Check which of the condition(s) matched and handle them. - if (self.matched & (0b1 << 0)): - self.handle_address_or_data(scl, sda) - elif (self.matched & (0b1 << 1)): - self.handle_start() - elif (self.matched & (0b1 << 2)): - self.handle_stop() - elif self.state == 'FIND ACK': - # Wait for any of the following conditions (or combinations): - # a) a data/ack bit: SCL = rising. - # b) STOP condition (P): SCL = high, SDA = rising - (scl, sda) = self.wait([{0: 'r'}, {0: 'h', 1: 'r'}]) - if (self.matched & (0b1 << 0)): - self.get_ack(scl, sda) - elif (self.matched & (0b1 << 1)): - self.handle_stop() - diff --git a/decoders/0-spi/__init__.py b/decoders/0-spi/__init__.py deleted file mode 100755 index dc5cbc05..00000000 --- a/decoders/0-spi/__init__.py +++ /dev/null @@ -1,32 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -''' -The SPI (Serial Peripheral Interface) protocol decoder supports synchronous -SPI(-like) protocols with a clock line, a MISO and MOSI line for data -transfer in two directions, and an optional CS# pin. - -Either MISO or MOSI (but not both) can be optional. - -If CS# is supplied, data is only decoded when CS# is asserted (clock -transitions where CS# is not asserted are ignored). If CS# is not supplied, -data is decoded on every clock transition (depending on SPI mode). -''' - -from .pd import Decoder diff --git a/decoders/0-spi/pd.py b/decoders/0-spi/pd.py deleted file mode 100755 index 2d397f02..00000000 --- a/decoders/0-spi/pd.py +++ /dev/null @@ -1,275 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2011 Gareth McMullin -## Copyright (C) 2012-2014 Uwe Hermann -## Copyright (C) 2019 DreamSourceLab -## -## 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, see . -## - -import sigrokdecode as srd -from collections import namedtuple - -Data = namedtuple('Data', ['ss', 'es', 'val']) - -''' -OUTPUT_PYTHON format: - -Packet: -[, , ] - -: - - 'DATA': contains the MOSI data, contains the MISO data. - The data is _usually_ 8 bits (but can also be fewer or more bits). - Both data items are Python numbers (not strings), or None if the respective - channel was not supplied. - - 'BITS': / contain a list of bit values in this MOSI/MISO data - item, and for each of those also their respective start-/endsample numbers. - - 'CS-CHANGE': is the old CS# pin value, is the new value. - Both data items are Python numbers (0/1), not strings. At the beginning of - the decoding a packet is generated with = None and being the - initial state of the CS# pin or None if the chip select pin is not supplied. - - 'TRANSFER': / contain a list of Data() namedtuples for each - byte transferred during this block of CS# asserted time. Each Data() has - fields ss, es, and val. - -Examples: - ['CS-CHANGE', None, 1] - ['CS-CHANGE', 1, 0] - ['DATA', 0xff, 0x3a] - ['BITS', [[1, 80, 82], [1, 83, 84], [1, 85, 86], [1, 87, 88], - [1, 89, 90], [1, 91, 92], [1, 93, 94], [1, 95, 96]], - [[0, 80, 82], [1, 83, 84], [0, 85, 86], [1, 87, 88], - [1, 89, 90], [1, 91, 92], [0, 93, 94], [0, 95, 96]]] - ['DATA', 0x65, 0x00] - ['DATA', 0xa8, None] - ['DATA', None, 0x55] - ['CS-CHANGE', 0, 1] - ['TRANSFER', [Data(ss=80, es=96, val=0xff), ...], - [Data(ss=80, es=96, val=0x3a), ...]] -''' - -# Key: (CPOL, CPHA). Value: SPI mode. -# Clock polarity (CPOL) = 0/1: Clock is low/high when inactive. -# Clock phase (CPHA) = 0/1: Data is valid on the leading/trailing clock edge. -spi_mode = { - (0, 0): 0, # Mode 0 - (0, 1): 1, # Mode 1 - (1, 0): 2, # Mode 2 - (1, 1): 3, # Mode 3 -} - -class ChannelError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = '0:spi' - name = '0:SPI' - longname = 'Serial Peripheral Interface' - desc = 'Full-duplex, synchronous, serial bus.' - license = 'gplv2+' - inputs = ['logic'] - outputs = ['spi'] - tags = ['Embedded/industrial'] - channels = ( - {'id': 'clk', 'type': 0, 'name': 'CLK', 'desc': 'Clock'}, - ) - optional_channels = ( - {'id': 'miso', 'type': 107, 'name': 'MISO', 'desc': 'Master in, slave out'}, - {'id': 'mosi', 'type': 109, 'name': 'MOSI', 'desc': 'Master out, slave in'}, - {'id': 'cs', 'type': -1, 'name': 'CS#', 'desc': 'Chip-select'}, - ) - options = ( - {'id': 'cs_polarity', 'desc': 'CS# polarity', 'default': 'active-low', - 'values': ('active-low', 'active-high')}, - {'id': 'cpol', 'desc': 'Clock polarity (CPOL)', 'default': 0, - 'values': (0, 1)}, - {'id': 'cpha', 'desc': 'Clock phase (CPHA)', 'default': 0, - 'values': (0, 1)}, - {'id': 'bitorder', 'desc': 'Bit order', - 'default': 'msb-first', 'values': ('msb-first', 'lsb-first')}, - {'id': 'wordsize', 'desc': 'Word size', 'default': 8, - 'values': tuple(range(4,129,1))}, - ) - annotations = ( - ('106', 'miso-data', 'MISO data'), - ('108', 'mosi-data', 'MOSI data'), - ) - annotation_rows = ( - ('miso-data', 'MISO data', (0,)), - ('mosi-data', 'MOSI data', (1,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.bitcount = 0 - self.misodata = self.mosidata = 0 - self.misobits = [] - self.mosibits = [] - self.ss_block = -1 - self.samplenum = -1 - self.ss_transfer = -1 - self.cs_was_deasserted = False - self.have_cs = self.have_miso = self.have_mosi = None - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.bw = (self.options['wordsize'] + 7) // 8 - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def putw(self, data): - self.put(self.ss_block, self.samplenum, self.out_ann, data) - - def putdata(self): - # Pass MISO and MOSI bits and then data to the next PD up the stack. - so = self.misodata if self.have_miso else None - si = self.mosidata if self.have_mosi else None - - if self.have_miso: - ss, es = self.misobits[-1][1], self.misobits[0][2] - if self.have_mosi: - ss, es = self.mosibits[-1][1], self.mosibits[0][2] - - # Dataword annotations. - if self.have_miso: - self.put(ss, es, self.out_ann, [0, [self.misodata]]) - if self.have_mosi: - self.put(ss, es, self.out_ann, [1, [self.mosidata]]) - - def reset_decoder_state(self): - self.misodata = 0 if self.have_miso else None - self.mosidata = 0 if self.have_mosi else None - self.misobits = [] if self.have_miso else None - self.mosibits = [] if self.have_mosi else None - self.bitcount = 0 - - def cs_asserted(self, cs): - active_low = (self.options['cs_polarity'] == 'active-low') - return (cs == 0) if active_low else (cs == 1) - - def handle_bit(self, miso, mosi, clk, cs): - # If this is the first bit of a dataword, save its sample number. - if self.bitcount == 0: - self.ss_block = self.samplenum - self.cs_was_deasserted = \ - not self.cs_asserted(cs) if self.have_cs else False - - ws = self.options['wordsize'] - bo = self.options['bitorder'] - - # Receive MISO bit into our shift register. - if self.have_miso: - if bo == 'msb-first': - self.misodata |= miso << (ws - 1 - self.bitcount) - else: - self.misodata |= miso << self.bitcount - - # Receive MOSI bit into our shift register. - if self.have_mosi: - if bo == 'msb-first': - self.mosidata |= mosi << (ws - 1 - self.bitcount) - else: - self.mosidata |= mosi << self.bitcount - - # Guesstimate the endsample for this bit (can be overridden below). - es = self.samplenum - if self.bitcount > 0: - if self.have_miso: - es += self.samplenum - self.misobits[0][1] - elif self.have_mosi: - es += self.samplenum - self.mosibits[0][1] - - if self.have_miso: - self.misobits.insert(0, [miso, self.samplenum, es]) - if self.have_mosi: - self.mosibits.insert(0, [mosi, self.samplenum, es]) - - if self.bitcount > 0 and self.have_miso: - self.misobits[1][2] = self.samplenum - if self.bitcount > 0 and self.have_mosi: - self.mosibits[1][2] = self.samplenum - - self.bitcount += 1 - - # Continue to receive if not enough bits were received, yet. - if self.bitcount != ws: - return - - self.putdata() - - self.reset_decoder_state() - - def find_clk_edge(self, miso, mosi, clk, cs, first): - if self.have_cs and (first or (self.matched & (0b1 << self.have_cs))): - # Send all CS# pin value changes. - oldcs = None if first else 1 - cs - - # Reset decoder state when CS# changes (and the CS# pin is used). - self.reset_decoder_state() - - # We only care about samples if CS# is asserted. - if self.have_cs and not self.cs_asserted(cs): - return - - # Ignore sample if the clock pin hasn't changed. - if first or not (self.matched & (0b1 << 0)): - return - - # Found the correct clock edge, now get the SPI bit(s). - self.handle_bit(miso, mosi, clk, cs) - - def decode(self): - # The CLK input is mandatory. Other signals are (individually) - # optional. Yet either MISO or MOSI (or both) must be provided. - # Tell stacked decoders when we don't have a CS# signal. - if not self.has_channel(0): - raise ChannelError('CLK pin required.') - self.have_miso = self.has_channel(1) - self.have_mosi = self.has_channel(2) - if not self.have_miso and not self.have_mosi: - raise ChannelError('Either MISO or MOSI (or both) pins required.') - self.have_cs = self.has_channel(3) - - # We want all CLK changes. We want all CS changes if CS is used. - # Map 'have_cs' from boolean to an integer index. This simplifies - # evaluation in other locations. - # Sample data on rising/falling clock edge (depends on mode). - mode = spi_mode[self.options['cpol'], self.options['cpha']] - if mode == 0 or mode == 3: # Sample on rising clock edge - wait_cond = [{0: 'r'}] - else: # Sample on falling clock edge - wait_cond = [{0: 'f'}] - - if self.have_cs: - self.have_cs = len(wait_cond) - wait_cond.append({3: 'e'}) - - # "Pixel compatibility" with the v2 implementation. Grab and - # process the very first sample before checking for edges. The - # previous implementation did this by seeding old values with - # None, which led to an immediate "change" in comparison. - (clk, miso, mosi, cs) = self.wait({}) - self.find_clk_edge(miso, mosi, clk, cs, True) - - while True: - (clk, miso, mosi, cs) = self.wait(wait_cond) - self.find_clk_edge(miso, mosi, clk, cs, False) diff --git a/decoders/0-uart/__init__.py b/decoders/0-uart/__init__.py deleted file mode 100755 index ce6136f1..00000000 --- a/decoders/0-uart/__init__.py +++ /dev/null @@ -1,40 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -''' -UART (Universal Asynchronous Receiver Transmitter) is a simple serial -communication protocol which allows two devices to talk to each other. - -This decoder should work on all "UART-like" async protocols with one -start bit (0), 5-9 databits, an (optional) parity bit, and one or more -stop bits (1), in this order. - -It can be run on one signal line (RX or TX) only, or on two lines (RX + TX). - -There are various standards for the physical layer specification of the -signals, including RS232, (TTL) UART, RS485, and others. However, the logic -level of the respective pins is only relevant when acquiring the data via -a logic analyzer (you have to select the correct logic analyzer and/or -the correct place where to probe). Once the data is in digital form and -matches the "UART" description above, this protocol decoder can work with -it though, no matter whether the source was on TTL UART levels, or RS232, -or others. -''' - -from .pd import Decoder diff --git a/decoders/0-uart/pd.py b/decoders/0-uart/pd.py deleted file mode 100755 index 9edf2254..00000000 --- a/decoders/0-uart/pd.py +++ /dev/null @@ -1,353 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2011-2014 Uwe Hermann -## Copyright (C) 2019 DreamSourceLab -## -## 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, see . -## - -import sigrokdecode as srd -from common.srdhelper import bitpack -from math import floor, ceil - -''' -OUTPUT_PYTHON format: - -Packet: -[, , ] - -This is the list of s and their respective values: - - 'STARTBIT': The data is the (integer) value of the start bit (0/1). - - 'DATA': This is always a tuple containing two items: - - 1st item: the (integer) value of the UART data. Valid values - range from 0 to 511 (as the data can be up to 9 bits in size). - - 2nd item: the list of individual data bits and their ss/es numbers. - - 'PARITYBIT': The data is the (integer) value of the parity bit (0/1). - - 'STOPBIT': The data is the (integer) value of the stop bit (0 or 1). - - 'INVALID STARTBIT': The data is the (integer) value of the start bit (0/1). - - 'INVALID STOPBIT': The data is the (integer) value of the stop bit (0/1). - - 'PARITY ERROR': The data is a tuple with two entries. The first one is - the expected parity value, the second is the actual parity value. - - 'FRAME': The data is always a tuple containing two items: The (integer) - value of the UART data, and a boolean which reflects the validity of the - UART frame. - -''' - -# Given a parity type to check (odd, even, zero, one), the value of the -# parity bit, the value of the data, and the length of the data (5-9 bits, -# usually 8 bits) return True if the parity is correct, False otherwise. -# 'none' is _not_ allowed as value for 'parity_type'. -def parity_ok(parity_type, parity_bit, data, num_data_bits): - - # Handle easy cases first (parity bit is always 1 or 0). - if parity_type == 'zero': - return parity_bit == 0 - elif parity_type == 'one': - return parity_bit == 1 - - # Count number of 1 (high) bits in the data (and the parity bit itself!). - ones = bin(data).count('1') + parity_bit - - # Check for odd/even parity. - if parity_type == 'odd': - return (ones % 2) == 1 - elif parity_type == 'even': - return (ones % 2) == 0 - -class SamplerateError(Exception): - pass - -class ChannelError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = '0:uart' - name = '0:UART' - longname = 'Universal Asynchronous Receiver/Transmitter' - desc = 'Asynchronous, serial bus.' - license = 'gplv2+' - inputs = ['logic'] - outputs = ['uart'] - tags = ['Embedded/industrial'] - channels = ( - {'id': 'rxtx', 'type': 209, 'name': 'RX/TX', 'desc': 'UART transceive line'}, - ) - options = ( - {'id': 'baudrate', 'desc': 'Baud rate', 'default': 115200}, - {'id': 'num_data_bits', 'desc': 'Data bits', 'default': 8, - 'values': tuple(range(4,129,1))}, - {'id': 'parity_type', 'desc': 'Parity type', 'default': 'none', - 'values': ('none', 'odd', 'even', 'zero', 'one')}, - {'id': 'parity_check', 'desc': 'Check parity?', 'default': 'yes', - 'values': ('yes', 'no')}, - {'id': 'num_stop_bits', 'desc': 'Stop bits', 'default': 1.0, - 'values': (0.0, 0.5, 1.0, 1.5, 2.0, 2.5)}, - {'id': 'bit_order', 'desc': 'Bit order', 'default': 'lsb-first', - 'values': ('lsb-first', 'msb-first')}, - {'id': 'format', 'desc': 'Data format', 'default': 'hex', - 'values': ('ascii', 'dec', 'hex', 'oct', 'bin')}, - {'id': 'invert', 'desc': 'Invert Signal?', 'default': 'no', - 'values': ('yes', 'no')}, - {'id': 'anno_startstop', 'desc': 'Display Start/Stop?', 'default': 'no', - 'values': ('yes', 'no')}, - ) - annotations = ( - ('108', 'data', 'data'), - ('7', 'start', 'start bits'), - ('6', 'parity-ok', 'parity OK bits'), - ('0', 'parity-err', 'parity error bits'), - ('1', 'stop', 'stop bits'), - ('1000', 'warnings', 'warnings'), - ) - annotation_rows = ( - ('data', 'RX/TX', (0, 1, 2, 3, 4)), - ('warnings', 'Warnings', (5,)), - ) - idle_state = 'WAIT FOR START BIT' - - def putx(self, data): - s, halfbit = self.startsample, self.bit_width / 2.0 - if self.options['anno_startstop'] == 'yes' : - self.put(s - floor(halfbit), self.samplenum + ceil(halfbit), self.out_ann, data) - else : - self.put(self.frame_start, self.samplenum + ceil(halfbit * (1+self.options['num_stop_bits'])), self.out_ann, data) - - def putg(self, data): - s, halfbit = self.samplenum, self.bit_width / 2.0 - self.put(s - floor(halfbit), s + ceil(halfbit), self.out_ann, data) - - def putgse(self, ss, es, data): - self.put(ss, es, self.out_ann, data) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.samplenum = 0 - self.frame_start = -1 - self.frame_valid = None - self.startbit = -1 - self.cur_data_bit = 0 - self.datavalue = 0 - self.paritybit = -1 - self.stopbit1 = -1 - self.startsample = -1 - self.state = 'WAIT FOR START BIT' - self.databits = [] - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.bw = (self.options['num_data_bits'] + 7) // 8 - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - # The width of one UART bit in number of samples. - self.bit_width = float(self.samplerate) / float(self.options['baudrate']) - - def get_sample_point(self, bitnum): - # Determine absolute sample number of a bit slot's sample point. - # bitpos is the samplenumber which is in the middle of the - # specified UART bit (0 = start bit, 1..x = data, x+1 = parity bit - # (if used) or the first stop bit, and so on). - # The samples within bit are 0, 1, ..., (bit_width - 1), therefore - # index of the middle sample within bit window is (bit_width - 1) / 2. - bitpos = self.frame_start + (self.bit_width - 1) / 2.0 - bitpos += bitnum * self.bit_width - return bitpos - - def wait_for_start_bit(self, signal): - # Save the sample number where the start bit begins. - self.frame_start = self.samplenum - self.frame_valid = True - - self.state = 'GET START BIT' - - def get_start_bit(self, signal): - self.startbit = signal - - # The startbit must be 0. If not, we report an error and wait - # for the next start bit (assuming this one was spurious). - if self.startbit != 0: - self.putg([5, ['Frame error', 'Frame err', 'FE']]) - self.frame_valid = False - es = self.samplenum + ceil(self.bit_width / 2.0) - self.state = 'WAIT FOR START BIT' - return - - self.cur_data_bit = 0 - self.datavalue = 0 - self.startsample = -1 - - if self.options['anno_startstop'] == 'yes': - self.putg([1, ['Start bit', 'Start', 'S']]) - - self.state = 'GET DATA BITS' - - def get_data_bits(self, signal): - # Save the sample number of the middle of the first data bit. - if self.startsample == -1: - self.startsample = self.samplenum - - # Store individual data bits and their start/end samplenumbers. - s, halfbit = self.samplenum, int(self.bit_width / 2) - self.databits.append([signal, s - halfbit, s + halfbit]) - - # Return here, unless we already received all data bits. - self.cur_data_bit += 1 - if self.cur_data_bit < self.options['num_data_bits']: - return - - # Convert accumulated data bits to a data value. - bits = [b[0] for b in self.databits] - if self.options['bit_order'] == 'msb-first': - bits.reverse() - self.datavalue = bitpack(bits) - self.putx([0, [self.datavalue]]) - #b = self.datavalue - #formatted = self.format_value(b) - #if formatted is not None: - # self.putx([0, [formatted]]) - - self.databits = [] - - # Advance to either reception of the parity bit, or reception of - # the STOP bits if parity is not applicable. - self.state = 'GET PARITY BIT' - if self.options['parity_type'] == 'none': - self.state = 'GET STOP BITS' - - def format_value(self, v): - # Format value 'v' according to configured options. - # Reflects the user selected kind of representation, as well as - # the number of data bits in the UART frames. - - fmt, bits = self.options['format'], self.options['num_data_bits'] - - # Assume "is printable" for values from 32 to including 126, - # below 32 is "control" and thus not printable, above 127 is - # "not ASCII" in its strict sense, 127 (DEL) is not printable, - # fall back to hex representation for non-printables. - if fmt == 'ascii': - if v in range(32, 126 + 1): - return chr(v) - hexfmt = "[{:02X}]" if bits <= 8 else "[{:03X}]" - return hexfmt.format(v) - - # Mere number to text conversion without prefix and padding - # for the "decimal" output format. - if fmt == 'dec': - return "{:d}".format(v) - - # Padding with leading zeroes for hex/oct/bin formats, but - # without a prefix for density -- since the format is user - # specified, there is no ambiguity. - if fmt == 'hex': - digits = (bits + 4 - 1) // 4 - fmtchar = "X" - elif fmt == 'oct': - digits = (bits + 3 - 1) // 3 - fmtchar = "o" - elif fmt == 'bin': - digits = bits - fmtchar = "b" - else: - fmtchar = None - if fmtchar is not None: - fmt = "{{:0{:d}{:s}}}".format(digits, fmtchar) - return fmt.format(v) - - return None - - def get_parity_bit(self, signal): - self.paritybit = signal - - if parity_ok(self.options['parity_type'], self.paritybit, - self.datavalue, self.options['num_data_bits']): - self.putg([2, ['Parity bit', 'Parity', 'P']]) - else: - # TODO: Return expected/actual parity values. - self.putg([3, ['Parity error', 'Parity err', 'PE']]) - self.frame_valid = False - - self.state = 'GET STOP BITS' - - # TODO: Currently only supports 1 stop bit. - def get_stop_bits(self, signal): - self.stopbit1 = signal - - # Stop bits must be 1. If not, we report an error. - if self.stopbit1 != 1: - self.putg([5, ['Frame error', 'Frame err', 'FE']]) - self.frame_valid = False - - if self.options['anno_startstop'] == 'yes': - self.putg([2, ['Stop bit', 'Stop', 'T']]) - - # Pass the complete UART frame to upper layers. - es = self.samplenum + ceil(self.bit_width / 2.0) - - self.state = 'WAIT FOR START BIT' - - def get_wait_cond(self, inv): - # Return condititions that are suitable for Decoder.wait(). Those - # conditions either match the falling edge of the START bit, or - # the sample point of the next bit time. - state = self.state - if state == 'WAIT FOR START BIT': - return {0: 'r' if inv else 'f'} - if state == 'GET START BIT': - bitnum = 0 - elif state == 'GET DATA BITS': - bitnum = 1 + self.cur_data_bit - elif state == 'GET PARITY BIT': - bitnum = 1 + self.options['num_data_bits'] - elif state == 'GET STOP BITS': - bitnum = 1 + self.options['num_data_bits'] - bitnum += 0 if self.options['parity_type'] == 'none' else 1 - want_num = ceil(self.get_sample_point(bitnum)) - return {'skip': want_num - self.samplenum} - - def inspect_sample(self, signal, inv): - # Inspect a sample returned by .wait() for the specified UART line. - if inv: - signal = not signal - - state = self.state - if state == 'WAIT FOR START BIT': - self.wait_for_start_bit(signal) - elif state == 'GET START BIT': - self.get_start_bit(signal) - elif state == 'GET DATA BITS': - self.get_data_bits(signal) - elif state == 'GET PARITY BIT': - self.get_parity_bit(signal) - elif state == 'GET STOP BITS': - self.get_stop_bits(signal) - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - - inv = self.options['invert'] == 'yes' - - while True: - conds = self.get_wait_cond(inv) - (rxtx, ) = self.wait(conds) - if (self.matched & (0b1 << 0)): - self.inspect_sample(rxtx, inv) diff --git a/decoders/1-i2c/__init__.py b/decoders/1-i2c/__init__.py deleted file mode 100755 index 2a36b060..00000000 --- a/decoders/1-i2c/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -''' -I²C (Inter-Integrated Circuit) is a bidirectional, multi-master -bus using two signals (SCL = serial clock line, SDA = serial data line). -''' - -from .pd import Decoder diff --git a/decoders/1-i2c/pd.py b/decoders/1-i2c/pd.py deleted file mode 100755 index a163eba4..00000000 --- a/decoders/1-i2c/pd.py +++ /dev/null @@ -1,295 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2010-2016 Uwe Hermann -## Copyright (C) 2019 DreamSourceLab -## -## 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, see . -## - -# TODO: Look into arbitration, collision detection, clock synchronisation, etc. -# TODO: Implement support for inverting SDA/SCL levels (0->1 and 1->0). -# TODO: Implement support for detecting various bus errors. - -import sigrokdecode as srd - -''' -OUTPUT_PYTHON format: - -Packet: -[, ] - -: - - 'START' (START condition) - - 'START REPEAT' (Repeated START condition) - - 'ADDRESS READ' (Slave address, read) - - 'ADDRESS WRITE' (Slave address, write) - - 'DATA READ' (Data, read) - - 'DATA WRITE' (Data, write) - - 'STOP' (STOP condition) - - 'ACK' (ACK bit) - - 'NACK' (NACK bit) - - 'BITS' (: list of data/address bits and their ss/es numbers) - - is the data or address byte associated with the 'ADDRESS*' and 'DATA*' -command. Slave addresses do not include bit 0 (the READ/WRITE indication bit). -For example, a slave address field could be 0x51 (instead of 0xa2). -For 'START', 'START REPEAT', 'STOP', 'ACK', and 'NACK' is None. -''' - -# CMD: [annotation-type-index, long annotation, short annotation] -proto = { - 'START': [0, 'Start', 'S'], - 'START REPEAT': [1, 'Start repeat', 'Sr'], - 'STOP': [2, 'Stop', 'P'], - 'ACK': [3, 'ACK', 'A'], - 'NACK': [4, 'NACK', 'N'], - 'BIT': [5, 'Bit', 'B'], - 'ADDRESS READ': [6, 'Address read', 'AR'], - 'ADDRESS WRITE': [7, 'Address write', 'AW'], - 'DATA READ': [8, 'Data read', 'DR'], - 'DATA WRITE': [9, 'Data write', 'DW'], -} - -class Decoder(srd.Decoder): - api_version = 3 - id = '1:i2c' - name = '1:I²C' - longname = 'Inter-Integrated Circuit' - desc = 'Two-wire, multi-master, serial bus.' - license = 'gplv2+' - inputs = ['logic'] - outputs = ['i2c'] - tags = ['Embedded/industrial'] - channels = ( - {'id': 'scl', 'type': 8, 'name': 'SCL', 'desc': 'Serial clock line'}, - {'id': 'sda', 'type': 108, 'name': 'SDA', 'desc': 'Serial data line'}, - ) - options = ( - {'id': 'address_format', 'desc': 'Displayed slave address format', - 'default': 'shifted', 'values': ('shifted', 'unshifted')}, - ) - annotations = ( - ('7', 'start', 'Start condition'), - ('6', 'repeat-start', 'Repeat start condition'), - ('1', 'stop', 'Stop condition'), - ('5', 'ack', 'ACK'), - ('0', 'nack', 'NACK'), - ('208', 'bit', 'Data/address bit'), - ('112', 'address-read', 'Address read'), - ('111', 'address-write', 'Address write'), - ('110', 'data-read', 'Data read'), - ('109', 'data-write', 'Data write'), - ('1000', 'warnings', 'Human-readable warnings'), - ) - annotation_rows = ( - ('bits', 'Bits', (5,)), - ('addr-data', 'Address/Data', (0, 1, 2, 3, 4, 6, 7, 8, 9)), - ('warnings', 'Warnings', (10,)), - ) - binary = ( - ('address-read', 'Address read'), - ('address-write', 'Address write'), - ('data-read', 'Data read'), - ('data-write', 'Data write'), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.ss = self.es = self.ss_byte = -1 - self.bitcount = 0 - self.databyte = 0 - self.wr = -1 - self.is_repeat_start = 0 - self.state = 'FIND START' - self.pdu_start = None - self.pdu_bits = 0 - self.bits = [] - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def start(self): - self.out_python = self.register(srd.OUTPUT_PYTHON) - self.out_ann = self.register(srd.OUTPUT_ANN) - self.out_binary = self.register(srd.OUTPUT_BINARY) - self.out_bitrate = self.register(srd.OUTPUT_META, - meta=(int, 'Bitrate', 'Bitrate from Start bit to Stop bit')) - - def putx(self, data): - self.put(self.ss, self.es, self.out_ann, data) - - def putp(self, data): - self.put(self.ss, self.es, self.out_python, data) - - def putb(self, data): - self.put(self.ss, self.es, self.out_binary, data) - - def handle_start(self): - self.ss, self.es = self.samplenum, self.samplenum - self.pdu_start = self.samplenum - self.pdu_bits = 0 - cmd = 'START REPEAT' if (self.is_repeat_start == 1) else 'START' - self.putp([cmd, None]) - self.putx([proto[cmd][0], proto[cmd][1:]]) - self.state = 'FIND ADDRESS' - self.bitcount = self.databyte = 0 - self.is_repeat_start = 1 - self.wr = -1 - self.bits = [] - - # Gather 8 bits of data plus the ACK/NACK bit. - def handle_address_or_data(self, scl, sda): - self.pdu_bits += 1 - - # Address and data are transmitted MSB-first. - self.databyte <<= 1 - self.databyte |= sda - - # Remember the start of the first data/address bit. - if self.bitcount == 0: - self.ss_byte = self.samplenum - - # Store individual bits and their start/end samplenumbers. - # In the list, index 0 represents the LSB (I²C transmits MSB-first). - self.bits.insert(0, [sda, self.samplenum, self.samplenum]) - if self.bitcount > 0: - self.bits[1][2] = self.samplenum - if self.bitcount == 7: - self.bitwidth = self.bits[1][2] - self.bits[2][2] - self.bits[0][2] += self.bitwidth - - # Return if we haven't collected all 8 + 1 bits, yet. - if self.bitcount < 7: - self.bitcount += 1 - return - - d = self.databyte - if self.state == 'FIND ADDRESS': - # The READ/WRITE bit is only in address bytes, not data bytes. - self.wr = 0 if (self.databyte & 1) else 1 - if self.options['address_format'] == 'shifted': - d = d >> 1 - - bin_class = -1 - if self.state == 'FIND ADDRESS' and self.wr == 1: - cmd = 'ADDRESS WRITE' - bin_class = 1 - elif self.state == 'FIND ADDRESS' and self.wr == 0: - cmd = 'ADDRESS READ' - bin_class = 0 - elif self.state == 'FIND DATA' and self.wr == 1: - cmd = 'DATA WRITE' - bin_class = 3 - elif self.state == 'FIND DATA' and self.wr == 0: - cmd = 'DATA READ' - bin_class = 2 - - self.ss, self.es = self.ss_byte, self.samplenum + self.bitwidth - - self.putp(['BITS', self.bits]) - self.putp([cmd, d]) - - self.putb([bin_class, bytes([d])]) - - for bit in self.bits: - self.put(bit[1], bit[2], self.out_ann, [5, ['%d' % bit[0]]]) - - if cmd.startswith('ADDRESS'): - self.ss, self.es = self.samplenum, self.samplenum + self.bitwidth - w = ['Write', 'Wr', 'W'] if self.wr else ['Read', 'Rd', 'R'] - self.putx([0, w]) - self.ss, self.es = self.ss_byte, self.samplenum - - self.putx([proto[cmd][0], ['%s: {$}' % proto[cmd][1], '%s: {$}' % proto[cmd][2], '{$}', d]]) - - # Done with this packet. - self.bitcount = self.databyte = 0 - self.bits = [] - self.state = 'FIND ACK' - - def get_ack(self, scl, sda): - self.ss, self.es = self.samplenum, self.samplenum + self.bitwidth - cmd = 'NACK' if (sda == 1) else 'ACK' - self.putp([cmd, None]) - self.putx([proto[cmd][0], proto[cmd][1:]]) - # There could be multiple data bytes in a row, so either find - # another data byte or a STOP condition next. - self.state = 'FIND DATA' - - def handle_stop(self): - # Meta bitrate - if self.samplerate: - elapsed = 1 / float(self.samplerate) * (self.samplenum - self.pdu_start + 1) - bitrate = int(1 / elapsed * self.pdu_bits) - self.put(self.ss_byte, self.samplenum, self.out_bitrate, bitrate) - - cmd = 'STOP' - self.ss, self.es = self.samplenum, self.samplenum - self.putp([cmd, None]) - self.putx([proto[cmd][0], proto[cmd][1:]]) - self.state = 'FIND START' - self.is_repeat_start = 0 - self.wr = -1 - self.bits = [] - - def decode(self): - while True: - # State machine. - if self.state == 'FIND START': - # Wait for a START condition (S): SCL = high, SDA = falling. - self.wait({0: 'h', 1: 'f'}) - self.handle_start() - elif self.state == 'FIND ADDRESS': - # Wait for any of the following conditions (or combinations): - # a) Data sampling of receiver: SCL = rising, and/or - # b) START condition (S): SCL = high, SDA = falling, and/or - # c) STOP condition (P): SCL = high, SDA = rising - (scl, sda) = self.wait([{0: 'r'}, {0: 'h', 1: 'f'}, {0: 'h', 1: 'r'}]) - - # Check which of the condition(s) matched and handle them. - if (self.matched & (0b1 << 0)): - self.handle_address_or_data(scl, sda) - elif (self.matched & (0b1 << 1)): - self.handle_start() - elif (self.matched & (0b1 << 2)): - self.handle_stop() - elif self.state == 'FIND DATA': - # Wait for any of the following conditions (or combinations): - # a) Data sampling of receiver: SCL = rising, and/or - # b) START condition (S): SCL = high, SDA = falling, and/or - # c) STOP condition (P): SCL = high, SDA = rising - (scl, sda) = self.wait([{0: 'r'}, {0: 'h', 1: 'f'}, {0: 'h', 1: 'r'}]) - - # Check which of the condition(s) matched and handle them. - if (self.matched & (0b1 << 0)): - self.handle_address_or_data(scl, sda) - elif (self.matched & (0b1 << 1)): - self.handle_start() - elif (self.matched & (0b1 << 2)): - self.handle_stop() - elif self.state == 'FIND ACK': - # Wait for any of the following conditions (or combinations): - # a) a data/ack bit: SCL = rising. - # b) STOP condition (P): SCL = high, SDA = rising - (scl, sda) = self.wait([{0: 'r'}, {0: 'h', 1: 'r'}]) - if (self.matched & (0b1 << 0)): - self.get_ack(scl, sda) - elif (self.matched & (0b1 << 1)): - self.handle_stop() - diff --git a/decoders/1-spi/__init__.py b/decoders/1-spi/__init__.py deleted file mode 100755 index dc5cbc05..00000000 --- a/decoders/1-spi/__init__.py +++ /dev/null @@ -1,32 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -''' -The SPI (Serial Peripheral Interface) protocol decoder supports synchronous -SPI(-like) protocols with a clock line, a MISO and MOSI line for data -transfer in two directions, and an optional CS# pin. - -Either MISO or MOSI (but not both) can be optional. - -If CS# is supplied, data is only decoded when CS# is asserted (clock -transitions where CS# is not asserted are ignored). If CS# is not supplied, -data is decoded on every clock transition (depending on SPI mode). -''' - -from .pd import Decoder diff --git a/decoders/1-spi/pd.py b/decoders/1-spi/pd.py deleted file mode 100755 index e17e6adb..00000000 --- a/decoders/1-spi/pd.py +++ /dev/null @@ -1,352 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2011 Gareth McMullin -## Copyright (C) 2012-2014 Uwe Hermann -## Copyright (C) 2019 DreamSourceLab -## -## 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, see . -## - -import sigrokdecode as srd -from collections import namedtuple - -Data = namedtuple('Data', ['ss', 'es', 'val']) - -''' -OUTPUT_PYTHON format: - -Packet: -[, , ] - -: - - 'DATA': contains the MOSI data, contains the MISO data. - The data is _usually_ 8 bits (but can also be fewer or more bits). - Both data items are Python numbers (not strings), or None if the respective - channel was not supplied. - - 'BITS': / contain a list of bit values in this MOSI/MISO data - item, and for each of those also their respective start-/endsample numbers. - - 'CS-CHANGE': is the old CS# pin value, is the new value. - Both data items are Python numbers (0/1), not strings. At the beginning of - the decoding a packet is generated with = None and being the - initial state of the CS# pin or None if the chip select pin is not supplied. - - 'TRANSFER': / contain a list of Data() namedtuples for each - byte transferred during this block of CS# asserted time. Each Data() has - fields ss, es, and val. - -Examples: - ['CS-CHANGE', None, 1] - ['CS-CHANGE', 1, 0] - ['DATA', 0xff, 0x3a] - ['BITS', [[1, 80, 82], [1, 83, 84], [1, 85, 86], [1, 87, 88], - [1, 89, 90], [1, 91, 92], [1, 93, 94], [1, 95, 96]], - [[0, 80, 82], [1, 83, 84], [0, 85, 86], [1, 87, 88], - [1, 89, 90], [1, 91, 92], [0, 93, 94], [0, 95, 96]]] - ['DATA', 0x65, 0x00] - ['DATA', 0xa8, None] - ['DATA', None, 0x55] - ['CS-CHANGE', 0, 1] - ['TRANSFER', [Data(ss=80, es=96, val=0xff), ...], - [Data(ss=80, es=96, val=0x3a), ...]] -''' - -# Key: (CPOL, CPHA). Value: SPI mode. -# Clock polarity (CPOL) = 0/1: Clock is low/high when inactive. -# Clock phase (CPHA) = 0/1: Data is valid on the leading/trailing clock edge. -spi_mode = { - (0, 0): 0, # Mode 0 - (0, 1): 1, # Mode 1 - (1, 0): 2, # Mode 2 - (1, 1): 3, # Mode 3 -} - -class ChannelError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = '1:spi' - name = '1:SPI' - longname = 'Serial Peripheral Interface' - desc = 'Full-duplex, synchronous, serial bus.' - license = 'gplv2+' - inputs = ['logic'] - outputs = ['spi'] - tags = ['Embedded/industrial'] - channels = ( - {'id': 'clk', 'type': 0, 'name': 'CLK', 'desc': 'Clock'}, - ) - optional_channels = ( - {'id': 'miso', 'type': 107, 'name': 'MISO', 'desc': 'Master in, slave out'}, - {'id': 'mosi', 'type': 109, 'name': 'MOSI', 'desc': 'Master out, slave in'}, - {'id': 'cs', 'type': -1, 'name': 'CS#', 'desc': 'Chip-select'}, - ) - options = ( - {'id': 'cs_polarity', 'desc': 'CS# polarity', 'default': 'active-low', - 'values': ('active-low', 'active-high')}, - {'id': 'cpol', 'desc': 'Clock polarity (CPOL)', 'default': 0, - 'values': (0, 1)}, - {'id': 'cpha', 'desc': 'Clock phase (CPHA)', 'default': 0, - 'values': (0, 1)}, - {'id': 'bitorder', 'desc': 'Bit order', - 'default': 'msb-first', 'values': ('msb-first', 'lsb-first')}, - {'id': 'wordsize', 'desc': 'Word size', 'default': 8, - 'values': tuple(range(5,129,1))}, - {'id': 'frame', 'desc': 'Frame Decoder', 'default': 'no', - 'values': ('yes', 'no')}, - ) - annotations = ( - ('106', 'miso-data', 'MISO data'), - ('108', 'mosi-data', 'MOSI data'), - ('207', 'miso-bits', 'MISO bits'), - ('209', 'mosi-bits', 'MOSI bits'), - ('1000', 'warnings', 'Human-readable warnings'), - - ('6', 'miso-transfer', 'MISO transfer'), - ('8', 'mosi-transfer', 'MOSI transfer'), - ) - annotation_rows = ( - ('miso-bits', 'MISO bits', (2,)), - ('miso-data', 'MISO data', (0,)), - ('miso-transfer', 'MISO transfer', (5,)), - ('mosi-bits', 'MOSI bits', (3,)), - ('mosi-data', 'MOSI data', (1,)), - ('mosi-transfer', 'MOSI transfer', (6,)), - ('other', 'Other', (4,)), - ) - binary = ( - ('miso', 'MISO'), - ('mosi', 'MOSI'), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.bitcount = 0 - self.misodata = self.mosidata = 0 - self.misobits = [] - self.mosibits = [] - self.misobytes = [] - self.mosibytes = [] - self.ss_block = -1 - self.samplenum = -1 - self.ss_transfer = -1 - self.cs_was_deasserted = False - self.have_cs = self.have_miso = self.have_mosi = None - - def start(self): - self.out_python = self.register(srd.OUTPUT_PYTHON) - self.out_ann = self.register(srd.OUTPUT_ANN) - self.out_binary = self.register(srd.OUTPUT_BINARY) - self.out_bitrate = self.register(srd.OUTPUT_META, - meta=(int, 'Bitrate', 'Bitrate during transfers')) - self.bw = (self.options['wordsize'] + 7) // 8 - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def putw(self, data): - self.put(self.ss_block, self.samplenum, self.out_ann, data) - - def putdata(self, frame): - # Pass MISO and MOSI bits and then data to the next PD up the stack. - so = self.misodata if self.have_miso else None - si = self.mosidata if self.have_mosi else None - so_bits = self.misobits if self.have_miso else None - si_bits = self.mosibits if self.have_mosi else None - - if self.have_miso: - ss, es = self.misobits[-1][1], self.misobits[0][2] - bdata = so.to_bytes(self.bw, byteorder='big') - self.put(ss, es, self.out_binary, [0, bdata]) - if self.have_mosi: - ss, es = self.mosibits[-1][1], self.mosibits[0][2] - bdata = si.to_bytes(self.bw, byteorder='big') - self.put(ss, es, self.out_binary, [1, bdata]) - - self.put(ss, es, self.out_python, ['BITS', si_bits, so_bits]) - self.put(ss, es, self.out_python, ['DATA', si, so]) - - if frame: - if self.have_miso: - self.misobytes.append(Data(ss=ss, es=es, val=so)) - if self.have_mosi: - self.mosibytes.append(Data(ss=ss, es=es, val=si)) - - # Bit annotations. - if self.have_miso: - for bit in self.misobits: - self.put(bit[1], bit[2], self.out_ann, [2, ['%d' % bit[0]]]) - if self.have_mosi: - for bit in self.mosibits: - self.put(bit[1], bit[2], self.out_ann, [3, ['%d' % bit[0]]]) - - # Dataword annotations. - if self.have_miso: - self.put(ss, es, self.out_ann, [0, ['%02X' % self.misodata]]) - if self.have_mosi: - self.put(ss, es, self.out_ann, [1, ['%02X' % self.mosidata]]) - - def reset_decoder_state(self): - self.misodata = 0 if self.have_miso else None - self.mosidata = 0 if self.have_mosi else None - self.misobits = [] if self.have_miso else None - self.mosibits = [] if self.have_mosi else None - self.bitcount = 0 - - def cs_asserted(self, cs): - active_low = (self.options['cs_polarity'] == 'active-low') - return (cs == 0) if active_low else (cs == 1) - - def handle_bit(self, miso, mosi, clk, cs, frame): - # If this is the first bit of a dataword, save its sample number. - if self.bitcount == 0: - self.ss_block = self.samplenum - self.cs_was_deasserted = \ - not self.cs_asserted(cs) if self.have_cs else False - - ws = self.options['wordsize'] - bo = self.options['bitorder'] - - # Receive MISO bit into our shift register. - if self.have_miso: - if bo == 'msb-first': - self.misodata |= miso << (ws - 1 - self.bitcount) - else: - self.misodata |= miso << self.bitcount - - # Receive MOSI bit into our shift register. - if self.have_mosi: - if bo == 'msb-first': - self.mosidata |= mosi << (ws - 1 - self.bitcount) - else: - self.mosidata |= mosi << self.bitcount - - # Guesstimate the endsample for this bit (can be overridden below). - es = self.samplenum - if self.bitcount > 0: - if self.have_miso: - es += self.samplenum - self.misobits[0][1] - elif self.have_mosi: - es += self.samplenum - self.mosibits[0][1] - - if self.have_miso: - self.misobits.insert(0, [miso, self.samplenum, es]) - if self.have_mosi: - self.mosibits.insert(0, [mosi, self.samplenum, es]) - - if self.bitcount > 0 and self.have_miso: - self.misobits[1][2] = self.samplenum - if self.bitcount > 0 and self.have_mosi: - self.mosibits[1][2] = self.samplenum - - self.bitcount += 1 - - # Continue to receive if not enough bits were received, yet. - if self.bitcount != ws: - return - - self.putdata(frame) - - # Meta bitrate. - if self.samplerate: - elapsed = 1 / float(self.samplerate) - elapsed *= (self.samplenum - self.ss_block + 1) - bitrate = int(1 / elapsed * ws) - self.put(self.ss_block, self.samplenum, self.out_bitrate, bitrate) - - if self.have_cs and self.cs_was_deasserted: - self.putw([4, ['CS# was deasserted during this data word!']]) - - self.reset_decoder_state() - - def find_clk_edge(self, miso, mosi, clk, cs, first, frame): - if self.have_cs and (first or (self.matched & (0b1 << self.have_cs))): - # Send all CS# pin value changes. - oldcs = None if first else 1 - cs - self.put(self.samplenum, self.samplenum, self.out_python, - ['CS-CHANGE', oldcs, cs]) - - if frame: - if self.cs_asserted(cs): - self.ss_transfer = self.samplenum - self.misobytes = [] - self.mosibytes = [] - elif self.ss_transfer != -1: - if self.have_miso: - self.put(self.ss_transfer, self.samplenum, self.out_ann, - [5, [' '.join(format(x.val, '02X') for x in self.misobytes)]]) - if self.have_mosi: - self.put(self.ss_transfer, self.samplenum, self.out_ann, - [6, [' '.join(format(x.val, '02X') for x in self.mosibytes)]]) - self.put(self.ss_transfer, self.samplenum, self.out_python, - ['TRANSFER', self.mosibytes, self.misobytes]) - - # Reset decoder state when CS# changes (and the CS# pin is used). - self.reset_decoder_state() - - # We only care about samples if CS# is asserted. - if self.have_cs and not self.cs_asserted(cs): - return - - # Ignore sample if the clock pin hasn't changed. - if first or not (self.matched & (0b1 << 0)): - return - - # Found the correct clock edge, now get the SPI bit(s). - self.handle_bit(miso, mosi, clk, cs, frame) - - def decode(self): - # The CLK input is mandatory. Other signals are (individually) - # optional. Yet either MISO or MOSI (or both) must be provided. - # Tell stacked decoders when we don't have a CS# signal. - if not self.has_channel(0): - raise ChannelError('CLK pin required.') - self.have_miso = self.has_channel(1) - self.have_mosi = self.has_channel(2) - if not self.have_miso and not self.have_mosi: - raise ChannelError('Either MISO or MOSI (or both) pins required.') - self.have_cs = self.has_channel(3) - if not self.have_cs: - self.put(0, 0, self.out_python, ['CS-CHANGE', None, None]) - - frame = self.options['frame'] == 'yes' - - # We want all CLK changes. We want all CS changes if CS is used. - # Map 'have_cs' from boolean to an integer index. This simplifies - # evaluation in other locations. - # Sample data on rising/falling clock edge (depends on mode). - mode = spi_mode[self.options['cpol'], self.options['cpha']] - if mode == 0 or mode == 3: # Sample on rising clock edge - wait_cond = [{0: 'r'}] - else: # Sample on falling clock edge - wait_cond = [{0: 'f'}] - - if self.have_cs: - self.have_cs = len(wait_cond) - wait_cond.append({3: 'e'}) - - # "Pixel compatibility" with the v2 implementation. Grab and - # process the very first sample before checking for edges. The - # previous implementation did this by seeding old values with - # None, which led to an immediate "change" in comparison. - (clk, miso, mosi, cs) = self.wait({}) - self.find_clk_edge(miso, mosi, clk, cs, True, frame) - - while True: - (clk, miso, mosi, cs) = self.wait(wait_cond) - self.find_clk_edge(miso, mosi, clk, cs, False, frame) diff --git a/decoders/1-uart/__init__.py b/decoders/1-uart/__init__.py deleted file mode 100755 index ce6136f1..00000000 --- a/decoders/1-uart/__init__.py +++ /dev/null @@ -1,40 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -''' -UART (Universal Asynchronous Receiver Transmitter) is a simple serial -communication protocol which allows two devices to talk to each other. - -This decoder should work on all "UART-like" async protocols with one -start bit (0), 5-9 databits, an (optional) parity bit, and one or more -stop bits (1), in this order. - -It can be run on one signal line (RX or TX) only, or on two lines (RX + TX). - -There are various standards for the physical layer specification of the -signals, including RS232, (TTL) UART, RS485, and others. However, the logic -level of the respective pins is only relevant when acquiring the data via -a logic analyzer (you have to select the correct logic analyzer and/or -the correct place where to probe). Once the data is in digital form and -matches the "UART" description above, this protocol decoder can work with -it though, no matter whether the source was on TTL UART levels, or RS232, -or others. -''' - -from .pd import Decoder diff --git a/decoders/1-uart/pd.py b/decoders/1-uart/pd.py deleted file mode 100755 index f3d6181c..00000000 --- a/decoders/1-uart/pd.py +++ /dev/null @@ -1,441 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2011-2014 Uwe Hermann -## Copyright (C) 2019 DreamSourceLab -## -## 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, see . -## - -import sigrokdecode as srd -from common.srdhelper import bitpack -from math import floor, ceil - -''' -OUTPUT_PYTHON format: - -Packet: -[, , ] - -This is the list of s and their respective values: - - 'STARTBIT': The data is the (integer) value of the start bit (0/1). - - 'DATA': This is always a tuple containing two items: - - 1st item: the (integer) value of the UART data. Valid values - range from 0 to 511 (as the data can be up to 9 bits in size). - - 2nd item: the list of individual data bits and their ss/es numbers. - - 'PARITYBIT': The data is the (integer) value of the parity bit (0/1). - - 'STOPBIT': The data is the (integer) value of the stop bit (0 or 1). - - 'INVALID STARTBIT': The data is the (integer) value of the start bit (0/1). - - 'INVALID STOPBIT': The data is the (integer) value of the stop bit (0/1). - - 'PARITY ERROR': The data is a tuple with two entries. The first one is - the expected parity value, the second is the actual parity value. - - 'BREAK': The data is always 0. - - 'FRAME': The data is always a tuple containing two items: The (integer) - value of the UART data, and a boolean which reflects the validity of the - UART frame. - -''' - -# Given a parity type to check (odd, even, zero, one), the value of the -# parity bit, the value of the data, and the length of the data (5-9 bits, -# usually 8 bits) return True if the parity is correct, False otherwise. -# 'none' is _not_ allowed as value for 'parity_type'. -def parity_ok(parity_type, parity_bit, data, num_data_bits): - - # Handle easy cases first (parity bit is always 1 or 0). - if parity_type == 'zero': - return parity_bit == 0 - elif parity_type == 'one': - return parity_bit == 1 - - # Count number of 1 (high) bits in the data (and the parity bit itself!). - ones = bin(data).count('1') + parity_bit - - # Check for odd/even parity. - if parity_type == 'odd': - return (ones % 2) == 1 - elif parity_type == 'even': - return (ones % 2) == 0 - -class SamplerateError(Exception): - pass - -class ChannelError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = '1:uart' - name = '1:UART' - longname = 'Universal Asynchronous Receiver/Transmitter' - desc = 'Asynchronous, serial bus.' - license = 'gplv2+' - inputs = ['logic'] - outputs = ['uart'] - tags = ['Embedded/industrial'] - channels = ( - {'id': 'rxtx', 'type': 209, 'name': 'RX/TX', 'desc': 'UART transceive line'}, - ) - options = ( - {'id': 'baudrate', 'desc': 'Baud rate', 'default': 115200}, - {'id': 'num_data_bits', 'desc': 'Data bits', 'default': 8, - 'values': tuple(range(4,129,1))}, - {'id': 'parity_type', 'desc': 'Parity type', 'default': 'none', - 'values': ('none', 'odd', 'even', 'zero', 'one')}, - {'id': 'parity_check', 'desc': 'Check parity?', 'default': 'yes', - 'values': ('yes', 'no')}, - {'id': 'num_stop_bits', 'desc': 'Stop bits', 'default': 1.0, - 'values': (0.0, 0.5, 1.0, 1.5, 2.0, 2.5)}, - {'id': 'bit_order', 'desc': 'Bit order', 'default': 'lsb-first', - 'values': ('lsb-first', 'msb-first')}, - {'id': 'format', 'desc': 'Data format', 'default': 'hex', - 'values': ('ascii', 'dec', 'hex', 'oct', 'bin')}, - {'id': 'invert', 'desc': 'Invert Signal?', 'default': 'no', - 'values': ('yes', 'no')}, - {'id': 'anno_startstop', 'desc': 'Display Start/Stop?', 'default': 'yes', - 'values': ('yes', 'no')}, - ) - annotations = ( - ('108', 'data', 'data'), - ('7', 'start', 'start bits'), - ('6', 'parity-ok', 'parity OK bits'), - ('0', 'parity-err', 'parity error bits'), - ('1', 'stop', 'stop bits'), - ('1000', 'warnings', 'warnings'), - ('209', 'data-bits', 'data bits'), - ('10', 'break', 'break'), - ) - annotation_rows = ( - ('data', 'RX/TX', (0, 1, 2, 3, 4)), - ('data-bits', 'Bits', (6,)), - ('warnings', 'Warnings', (5,)), - ('break', 'break', (7,)), - ) - binary = ( - ('rxtx', 'RX/TX dump'), - ) - idle_state = 'WAIT FOR START BIT' - - def putx(self, data): - s, halfbit = self.startsample, self.bit_width / 2.0 - if self.options['anno_startstop'] == 'yes' : - self.put(s - floor(halfbit), self.samplenum + ceil(halfbit), self.out_ann, data) - else : - self.put(self.frame_start, self.samplenum + ceil(halfbit * (1+self.options['num_stop_bits'])), self.out_ann, data) - - def putpx(self, data): - s, halfbit = self.startsample, self.bit_width / 2.0 - self.put(s - floor(halfbit), self.samplenum + ceil(halfbit), self.out_python, data) - - def putg(self, data): - s, halfbit = self.samplenum, self.bit_width / 2.0 - self.put(s - floor(halfbit), s + ceil(halfbit), self.out_ann, data) - - def putp(self, data): - s, halfbit = self.samplenum, self.bit_width / 2.0 - self.put(s - floor(halfbit), s + ceil(halfbit), self.out_python, data) - - def putgse(self, ss, es, data): - self.put(ss, es, self.out_ann, data) - - def putpse(self, ss, es, data): - self.put(ss, es, self.out_python, data) - - def putbin(self, data): - s, halfbit = self.startsample, self.bit_width / 2.0 - self.put(s - floor(halfbit), self.samplenum + ceil(halfbit), self.out_binary, data) - - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.samplenum = 0 - self.frame_start = -1 - self.frame_valid = None - self.startbit = -1 - self.cur_data_bit = 0 - self.datavalue = 0 - self.paritybit = -1 - self.stopbit1 = -1 - self.startsample = -1 - self.state = 'WAIT FOR START BIT' - self.databits = [] - self.break_start = None - - def start(self): - self.out_python = self.register(srd.OUTPUT_PYTHON) - self.out_binary = self.register(srd.OUTPUT_BINARY) - self.out_ann = self.register(srd.OUTPUT_ANN) - self.bw = (self.options['num_data_bits'] + 7) // 8 - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - # The width of one UART bit in number of samples. - self.bit_width = float(self.samplerate) / float(self.options['baudrate']) - - def get_sample_point(self, bitnum): - # Determine absolute sample number of a bit slot's sample point. - # bitpos is the samplenumber which is in the middle of the - # specified UART bit (0 = start bit, 1..x = data, x+1 = parity bit - # (if used) or the first stop bit, and so on). - # The samples within bit are 0, 1, ..., (bit_width - 1), therefore - # index of the middle sample within bit window is (bit_width - 1) / 2. - bitpos = self.frame_start + (self.bit_width - 1) / 2.0 - bitpos += bitnum * self.bit_width - return bitpos - - def wait_for_start_bit(self, signal): - # Save the sample number where the start bit begins. - self.frame_start = self.samplenum - self.frame_valid = True - - self.state = 'GET START BIT' - - def get_start_bit(self, signal): - self.startbit = signal - - # The startbit must be 0. If not, we report an error and wait - # for the next start bit (assuming this one was spurious). - if self.startbit != 0: - self.putp(['INVALID STARTBIT', 0, self.startbit]) - self.putg([5, ['Frame error', 'Frame err', 'FE']]) - self.frame_valid = False - es = self.samplenum + ceil(self.bit_width / 2.0) - self.putpse(self.frame_start, es, ['FRAME', 0, - (self.datavalue, self.frame_valid)]) - self.state = 'WAIT FOR START BIT' - return - - self.cur_data_bit = 0 - self.datavalue = 0 - self.startsample = -1 - - self.putp(['STARTBIT', 0, self.startbit]) - if self.options['anno_startstop'] == 'yes': - self.putg([1, ['Start bit', 'Start', 'S']]) - - self.state = 'GET DATA BITS' - - def get_data_bits(self, signal): - # Save the sample number of the middle of the first data bit. - if self.startsample == -1: - self.startsample = self.samplenum - - self.putg([6, ['%d' % signal]]) - - # Store individual data bits and their start/end samplenumbers. - s, halfbit = self.samplenum, int(self.bit_width / 2) - self.databits.append([signal, s - halfbit, s + halfbit]) - - # Return here, unless we already received all data bits. - self.cur_data_bit += 1 - if self.cur_data_bit < self.options['num_data_bits']: - return - - # Convert accumulated data bits to a data value. - bits = [b[0] for b in self.databits] - if self.options['bit_order'] == 'msb-first': - bits.reverse() - self.datavalue = bitpack(bits) - self.putpx(['DATA', 0, (self.datavalue, self.databits)]) - - self.putx([0, [self.datavalue]]) - - b = self.datavalue - #formatted = self.format_value(b) - #if formatted is not None: - # self.putx([0, [formatted]]) - - bdata = b.to_bytes(self.bw, byteorder='big') - self.putbin([0, bdata]) - self.putbin([1, bdata]) - - self.databits = [] - - # Advance to either reception of the parity bit, or reception of - # the STOP bits if parity is not applicable. - self.state = 'GET PARITY BIT' - if self.options['parity_type'] == 'none': - self.state = 'GET STOP BITS' - - def format_value(self, v): - # Format value 'v' according to configured options. - # Reflects the user selected kind of representation, as well as - # the number of data bits in the UART frames. - - fmt, bits = self.options['format'], self.options['num_data_bits'] - - # Assume "is printable" for values from 32 to including 126, - # below 32 is "control" and thus not printable, above 127 is - # "not ASCII" in its strict sense, 127 (DEL) is not printable, - # fall back to hex representation for non-printables. - if fmt == 'ascii': - if v in range(32, 126 + 1): - return chr(v) - hexfmt = "[{:02X}]" if bits <= 8 else "[{:03X}]" - return hexfmt.format(v) - - # Mere number to text conversion without prefix and padding - # for the "decimal" output format. - if fmt == 'dec': - return "{:d}".format(v) - - # Padding with leading zeroes for hex/oct/bin formats, but - # without a prefix for density -- since the format is user - # specified, there is no ambiguity. - if fmt == 'hex': - digits = (bits + 4 - 1) // 4 - fmtchar = "X" - elif fmt == 'oct': - digits = (bits + 3 - 1) // 3 - fmtchar = "o" - elif fmt == 'bin': - digits = bits - fmtchar = "b" - else: - fmtchar = None - if fmtchar is not None: - fmt = "{{:0{:d}{:s}}}".format(digits, fmtchar) - return fmt.format(v) - - return None - - def get_parity_bit(self, signal): - self.paritybit = signal - - if parity_ok(self.options['parity_type'], self.paritybit, - self.datavalue, self.options['num_data_bits']): - self.putp(['PARITYBIT', 0, self.paritybit]) - self.putg([2, ['Parity bit', 'Parity', 'P']]) - else: - # TODO: Return expected/actual parity values. - self.putp(['PARITY ERROR', 0, (0, 1)]) # FIXME: Dummy tuple... - self.putg([3, ['Parity error', 'Parity err', 'PE']]) - self.frame_valid = False - - self.state = 'GET STOP BITS' - - # TODO: Currently only supports 1 stop bit. - def get_stop_bits(self, signal): - self.stopbit1 = signal - - # Stop bits must be 1. If not, we report an error. - if self.stopbit1 != 1: - self.putp(['INVALID STOPBIT', 0, self.stopbit1]) - self.putg([5, ['Frame error', 'Frame err', 'FE']]) - self.frame_valid = False - - self.putp(['STOPBIT', 0, self.stopbit1]) - if self.options['anno_startstop'] == 'yes': - self.putg([2, ['Stop bit', 'Stop', 'T']]) - - # Pass the complete UART frame to upper layers. - es = self.samplenum + ceil(self.bit_width / 2.0) - self.putpse(self.frame_start, es, ['FRAME', 0, - (self.datavalue, self.frame_valid)]) - - self.state = 'WAIT FOR START BIT' - - def handle_break(self): - self.putpse(self.frame_start, self.samplenum, - ['BREAK', 0, 0]) - self.putgse(self.frame_start, self.samplenum, - [7, ['Break condition', 'Break', 'Brk', 'B']]) - self.state = 'WAIT FOR START BIT' - - def get_wait_cond(self, inv): - # Return condititions that are suitable for Decoder.wait(). Those - # conditions either match the falling edge of the START bit, or - # the sample point of the next bit time. - state = self.state - if state == 'WAIT FOR START BIT': - return {0: 'r' if inv else 'f'} - if state == 'GET START BIT': - bitnum = 0 - elif state == 'GET DATA BITS': - bitnum = 1 + self.cur_data_bit - elif state == 'GET PARITY BIT': - bitnum = 1 + self.options['num_data_bits'] - elif state == 'GET STOP BITS': - bitnum = 1 + self.options['num_data_bits'] - bitnum += 0 if self.options['parity_type'] == 'none' else 1 - want_num = ceil(self.get_sample_point(bitnum)) - return {'skip': want_num - self.samplenum} - - def inspect_sample(self, signal, inv): - # Inspect a sample returned by .wait() for the specified UART line. - if inv: - signal = not signal - - state = self.state - if state == 'WAIT FOR START BIT': - self.wait_for_start_bit(signal) - elif state == 'GET START BIT': - self.get_start_bit(signal) - elif state == 'GET DATA BITS': - self.get_data_bits(signal) - elif state == 'GET PARITY BIT': - self.get_parity_bit(signal) - elif state == 'GET STOP BITS': - self.get_stop_bits(signal) - - def inspect_edge(self, signal, inv): - # Inspect edges, independently from traffic, to detect break conditions. - if inv: - signal = not signal - if not signal: - # Signal went low. Start another interval. - self.break_start = self.samplenum - return - # Signal went high. Was there an extended period with low signal? - if self.break_start is None: - return - diff = self.samplenum - self.break_start - if diff >= self.break_min_sample_count: - self.handle_break() - self.break_start = None - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - - inv = self.options['invert'] == 'yes' - cond_data_idx = None - - # Determine the number of samples for a complete frame's time span. - # A period of low signal (at least) that long is a break condition. - frame_samples = 1 # START - frame_samples += self.options['num_data_bits'] - frame_samples += 0 if self.options['parity_type'] == 'none' else 1 - frame_samples += self.options['num_stop_bits'] - frame_samples *= self.bit_width - self.break_min_sample_count = ceil(frame_samples) - cond_edge_idx = None - - while True: - conds = [] - - cond_data_idx = len(conds) - conds.append(self.get_wait_cond(inv)) - cond_edge_idx = len(conds) - conds.append({0: 'e'}) - - (rxtx, ) = self.wait(conds) - if cond_data_idx is not None and (self.matched & (0b1 << cond_data_idx)): - self.inspect_sample(rxtx, inv) - if cond_edge_idx is not None and (self.matched & (0b1 << cond_edge_idx)): - self.inspect_edge(rxtx, inv) diff --git a/decoders/a7105/__init__.py b/decoders/a7105/__init__.py deleted file mode 100644 index a011c987..00000000 --- a/decoders/a7105/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Jens Steinhauser -## -## 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, see . -## - -''' -This decoder stacks on top of the 'spi' PD and decodes the protocol spoken -by the AMICCOM A7105 2.4GHz transceiver chips. -''' - -from .pd import Decoder diff --git a/decoders/a7105/pd.py b/decoders/a7105/pd.py deleted file mode 100644 index d441c666..00000000 --- a/decoders/a7105/pd.py +++ /dev/null @@ -1,356 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 Richard Li -## -## 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, see . -## - -import sigrokdecode as srd - -class ChannelError(Exception): - pass - -regs = { -# addr: ('name', size) - 0x00: ('MODE', 1), - 0x01: ('MODE_CTRL', 1), - 0x02: ('CALC', 1), - 0x03: ('FIFO_I', 1), - 0x04: ('FIFO_II', 1), - 0x05: ('FIFO_DATA', 1), - 0x06: ('ID_DATA', 1), - 0x07: ('RC_OSC_I', 1), - 0x08: ('RC_OSC_II', 1), - 0x09: ('RC_OSC_III', 1), - 0x0a: ('CKO_PIN', 1), - 0x0b: ('GPIO1_PIN_I', 1), - 0x0c: ('GPIO2_PIN_II', 1), - 0x0d: ('CLOCK', 1), - 0x0e: ('DATA_RATE', 1), - 0x0f: ('PLL_I', 1), - 0x10: ('PLL_II', 1), - 0x11: ('PLL_III', 1), - 0x12: ('PLL_IV', 1), - 0x13: ('PLL_V', 1), - 0x14: ('TX_I', 1), - 0x15: ('TX_II', 1), - 0x16: ('DELAY_I', 1), - 0x17: ('DELAY_II', 1), - 0x18: ('RX', 1), - 0x19: ('RX_GAIN_I', 1), - 0x1a: ('RX_GAIN_II', 1), - 0x1b: ('RX_GAIN_III', 1), - 0x1c: ('RX_GAIN_IV', 1), - 0x1d: ('RSSI_THRES', 1), - 0x1e: ('ADC', 1), - 0x1f: ('CODE_I', 1), - 0x20: ('CODE_II', 1), - 0x21: ('CODE_III', 1), - 0x22: ('IF_CAL_I', 1), - 0x23: ('IF_CAL_II', 1), - 0x24: ('VCO_CURR_CAL', 1), - 0x25: ('VCO_SB_CALC_I', 1), - 0x26: ('VCO_SB_CALC_II', 1), - 0x27: ('BATT_DETECT', 1), - 0x28: ('TX_TEST', 1), - 0x29: ('RX_DEM_TEST_I', 1), - 0x2a: ('RX_DEM_TEST_II', 1), - 0x2b: ('CPC', 1), - 0x2c: ('CRYSTAL_TEST', 1), - 0x2d: ('PLL_TEST', 1), - 0x2e: ('VCO_TEST_I', 1), - 0x2f: ('VCO_TEST_II', 1), - 0x30: ('IFAT', 1), - 0x31: ('RSCALE', 1), - 0x32: ('FILTER_TEST', 1), - 0x33: ('UNKNOWN', 1), -} - -class Decoder(srd.Decoder): - api_version = 3 - id = 'a7105' - name = 'A7105' - longname = 'AMICCOM A7105' - desc = '2.4GHz FSK/GFSK Transceiver with 2K ~ 500Kbps data rate.' - license = 'gplv2+' - inputs = ['spi'] - outputs = [] - tags = ['IC', 'Wireless/RF'] - options = ( - {'id': 'hex_display', 'desc': 'Display payload in Hex', 'default': 'yes', - 'values': ('yes', 'no')}, - ) - annotations = ( - # Sent from the host to the chip. - ('cmd', 'Commands sent to the device'), - ('tx-data', 'Payload sent to the device'), - - # Returned by the chip. - ('rx-data', 'Payload read from the device'), - - ('warning', 'Warnings'), - ) - ann_cmd = 0 - ann_tx = 1 - ann_rx = 2 - ann_warn = 3 - annotation_rows = ( - ('commands', 'Commands', (ann_cmd, ann_tx, ann_rx)), - ('warnings', 'Warnings', (ann_warn,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.next() - self.requirements_met = True - self.cs_was_released = False - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def warn(self, pos, msg): - '''Put a warning message 'msg' at 'pos'.''' - self.put(pos[0], pos[1], self.out_ann, [self.ann_warn, [msg]]) - - def putp(self, pos, ann, msg): - '''Put an annotation message 'msg' at 'pos'.''' - self.put(pos[0], pos[1], self.out_ann, [ann, [msg]]) - - def next(self): - '''Resets the decoder after a complete command was decoded.''' - # 'True' for the first byte after CS went low. - self.first = True - - # The current command, and the minimum and maximum number - # of data bytes to follow. - self.cmd = None - self.min = 0 - self.max = 0 - - # Used to collect the bytes after the command byte - # (and the start/end sample number). - self.mb = [] - self.mb_s = -1 - self.mb_e = -1 - - def mosi_bytes(self): - '''Returns the collected MOSI bytes of a multi byte command.''' - return [b[0] for b in self.mb] - - def miso_bytes(self): - '''Returns the collected MISO bytes of a multi byte command.''' - return [b[1] for b in self.mb] - - def decode_command(self, pos, b): - '''Decodes the command byte 'b' at position 'pos' and prepares - the decoding of the following data bytes.''' - c = self.parse_command(b) - if c is None: - self.warn(pos, 'unknown command') - return - - self.cmd, self.dat, self.min, self.max = c - - if self.cmd in ('W_REGISTER', 'R_REGISTER'): - # Don't output anything now, the command is merged with - # the data bytes following it. - self.mb_s = pos[0] - else: - self.putp(pos, self.ann_cmd, self.format_command()) - - def format_command(self): - '''Returns the label for the current command.''' - return 'Cmd {}'.format(self.cmd) - - def parse_command(self, b): - '''Parses the command byte. - - Returns a tuple consisting of: - - the name of the command - - additional data needed to dissect the following bytes - - minimum number of following bytes - - maximum number of following bytes - ''' - - if b == 0x05: - return ('W_TX_FIFO', None, 1, 32) - elif b == 0x45: - return ('R_RX_FIFO', None, 1, 32) - if b == 0x06: - return ('W_ID', None, 1, 4) - elif b == 0x46: - return ('R_ID', None, 1, 4) - elif (b & 0b10000000) == 0: - if (b & 0b01000000) == 0: - c = 'W_REGISTER' - else: - c = 'R_REGISTER' - d = b & 0b00111111 - return (c, d, 1, 1) - - else: - cmd = b & 0b11110000 - if cmd == 0b10000000: - return ('SLEEP_MODE', None, 0, 0) - if cmd == 0b10010000: - return ('IDLE_MODE', None, 0, 0) - if cmd == 0b10100000: - return ('STANDBY_MODE', None, 0, 0) - if cmd == 0b10110000: - return ('PLL_MODE', None, 0, 0) - if cmd == 0b11000000: - return ('RX_MODE', None, 0, 0) - if cmd == 0b11010000: - return ('TX_MODE', None, 0, 0) - if cmd == 0b11100000: - return ('FIFO_WRITE_PTR_RESET', None, 0, 0) - if cmd == 0b11110000: - return ('FIFO_READ_PTR_RESET', None, 0, 0) - - def decode_register(self, pos, ann, regid, data): - '''Decodes a register. - - pos -- start and end sample numbers of the register - ann -- is the annotation number that is used to output the register. - regid -- may be either an integer used as a key for the 'regs' - dictionary, or a string directly containing a register name.' - data -- is the register content. - ''' - - if type(regid) == int: - # Get the name of the register. - if regid not in regs: - self.warn(pos, 'unknown register') - return - name = regs[regid][0] - else: - name = regid - - # Multi byte register come LSByte first. - data = reversed(data) - - label = '{}: {}'.format(self.format_command(), name) - - self.decode_mb_data(pos, ann, data, label, True) - - def decode_mb_data(self, pos, ann, data, label, always_hex): - '''Decodes the data bytes 'data' of a multibyte command at position - 'pos'. The decoded data is prefixed with 'label'. If 'always_hex' is - True, all bytes are decoded as hex codes, otherwise only non - printable characters are escaped.''' - - if always_hex: - def escape(b): - return '{:02X}'.format(b) - else: - def escape(b): - c = chr(b) - if not str.isprintable(c): - return '\\x{:02X}'.format(b) - return c - - data = ''.join([escape(b) for b in data]) - text = '{} = "{}"'.format(label, data.strip()) - self.putp(pos, ann, text) - - def finish_command(self, pos): - '''Decodes the remaining data bytes at position 'pos'.''' - - always_hex = self.options['hex_display'] == 'yes' - if self.cmd == 'R_REGISTER': - self.decode_register(pos, self.ann_cmd, - self.dat, self.miso_bytes()) - elif self.cmd == 'W_REGISTER': - self.decode_register(pos, self.ann_cmd, - self.dat, self.mosi_bytes()) - elif self.cmd == 'R_RX_FIFO': - self.decode_mb_data(pos, self.ann_rx, - self.miso_bytes(), 'RX FIFO', always_hex) - elif self.cmd == 'W_TX_FIFO': - self.decode_mb_data(pos, self.ann_tx, - self.mosi_bytes(), 'TX FIFO', always_hex) - elif self.cmd == 'R_ID': - self.decode_mb_data(pos, self.ann_rx, - self.miso_bytes(), 'R ID', always_hex) - elif self.cmd == 'W_ID': - self.decode_mb_data(pos, self.ann_tx, - self.mosi_bytes(), 'W ID', always_hex) - - def decode(self, ss, es, data): - if not self.requirements_met: - return - - ptype, data1, data2 = data - - if ptype == 'TRANSFER': - if self.cmd: - # Check if we got the minimum number of data bytes - # after the command byte. - if len(self.mb) < self.min: - self.warn((ss, ss), 'missing data bytes') - elif self.mb: - self.finish_command((self.mb_s, self.mb_e)) - - self.next() - self.cs_was_released = True - elif ptype == 'CS-CHANGE': - if data1 is None: - if data2 is None: - self.requirements_met = False - raise ChannelError('CS# pin required.') - elif data2 == 1: - self.cs_was_released = True - - if data1 == 0 and data2 == 1: - # Rising edge, the complete command is transmitted, process - # the bytes that were send after the command byte. - if self.cmd: - # Check if we got the minimum number of data bytes - # after the command byte. - if len(self.mb) < self.min: - self.warn((ss, ss), 'missing data bytes') - elif self.mb: - self.finish_command((self.mb_s, self.mb_e)) - - self.next() - self.cs_was_released = True - elif ptype == 'DATA' and self.cs_was_released: - mosi, miso = data1, data2 - pos = (ss, es) - - if miso is None and mosi is None: - self.requirements_met = False - raise ChannelError('Either MISO or MOSI pins required (3 wires SPI).') - - if miso is None: - miso = mosi - if mosi is None: - mosi = miso - - if self.first: - self.first = False - # First byte is always the command. - self.decode_command(pos, mosi) - else: - if not self.cmd or len(self.mb) >= self.max: - self.warn(pos, 'excess byte') - else: - # Collect the bytes after the command byte. - if self.mb_s == -1: - self.mb_s = ss - self.mb_e = es - self.mb.append((mosi, miso)) diff --git a/decoders/ac97/__init__.py b/decoders/ac97/__init__.py deleted file mode 100755 index 8b96e8aa..00000000 --- a/decoders/ac97/__init__.py +++ /dev/null @@ -1,36 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2017 Gerhard Sittig -## -## 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, see . -## - -''' -AC'97 (Audio Codec '97) was specifically designed by Intel for audio and -modem I/O functionality in mainstream PC systems. See the specification in -http://download.intel.com/support/motherboards/desktop/sb/ac97_r23.pdf - -AC'97 communicates full duplex data (SDATA_IN, SDATA_OUT), where bits -are clocked by the BIT_CLK and frames are signalled by the SYNC signals. -A low active RESET# line completes the set of signals. - -Frames repeat at a nominal frequency of 48kHz, and consist of 256 bits -each. One 16bit slot contains management information, twelve 20bit slots -follow which carry data for three management and nine audio/modem channels. -Optionally two slots of one frame can get combined for higher resolution -on fewer channels, or double data rate. -''' - -from .pd import Decoder diff --git a/decoders/ac97/pd.py b/decoders/ac97/pd.py deleted file mode 100755 index 3f79eefa..00000000 --- a/decoders/ac97/pd.py +++ /dev/null @@ -1,505 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2017 Gerhard Sittig -## Copyright (C) 2019 DreamSourceLab -## -## 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, see . -## - -# This implementation is incomplete. TODO items: -# - Support the optional RESET# pin, detect cold and warm reset. -# - Split slot values into audio samples of their respective width and -# frequency (either on user provided parameters, or from inspection of -# decoded register access). - -import sigrokdecode as srd - -class ChannelError(Exception): - pass - -class Pins: - (SYNC, BIT_CLK, SDATA_OUT, SDATA_IN, RESET) = range(5) - -class Ann: - ( - BITS_OUT, BITS_IN, - SLOT_OUT_RAW, SLOT_OUT_TAG, SLOT_OUT_ADDR, SLOT_OUT_DATA, - SLOT_OUT_03, SLOT_OUT_04, SLOT_OUT_05, SLOT_OUT_06, - SLOT_OUT_07, SLOT_OUT_08, SLOT_OUT_09, SLOT_OUT_10, - SLOT_OUT_11, SLOT_OUT_IO, - SLOT_IN_RAW, SLOT_IN_TAG, SLOT_IN_ADDR, SLOT_IN_DATA, - SLOT_IN_03, SLOT_IN_04, SLOT_IN_05, SLOT_IN_06, - SLOT_IN_07, SLOT_IN_08, SLOT_IN_09, SLOT_IN_10, - SLOT_IN_11, SLOT_IN_IO, - WARN, ERROR, - ) = range(32) - ( - BIN_FRAME_OUT, - BIN_FRAME_IN, - BIN_SLOT_RAW_OUT, - BIN_SLOT_RAW_IN, - ) = range(4) - -class Decoder(srd.Decoder): - api_version = 3 - id = 'ac97' - name = "AC '97" - longname = "Audio Codec '97" - desc = 'Audio and modem control for PC systems.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Audio', 'PC'] - channels = ( - {'id': 'sync', 'name': 'SYNC', 'desc': 'Frame synchronization'}, - {'id': 'clk', 'name': 'BIT_CLK', 'desc': 'Data bits clock'}, - ) - optional_channels = ( - {'id': 'out', 'name': 'SDATA_OUT', 'desc': 'Data output'}, - {'id': 'in', 'name': 'SDATA_IN', 'desc': 'Data input'}, - {'id': 'rst', 'name': 'RESET#', 'desc': 'Reset line'}, - ) - annotations = ( - ('bit-out', 'Output bits'), - ('bit-in', 'Input bits'), - ('slot-out-raw', 'Output raw value'), - ('slot-out-tag', 'Output TAG'), - ('slot-out-cmd-addr', 'Output command address'), - ('slot-out-cmd-data', 'Output command data'), - ('slot-out-03', 'Output slot 3'), - ('slot-out-04', 'Output slot 4'), - ('slot-out-05', 'Output slot 5'), - ('slot-out-06', 'Output slot 6'), - ('slot-out-07', 'Output slot 7'), - ('slot-out-08', 'Output slot 8'), - ('slot-out-09', 'Output slot 9'), - ('slot-out-10', 'Output slot 10'), - ('slot-out-11', 'Output slot 11'), - ('slot-out-io-ctrl', 'Output I/O control'), - ('slot-in-raw', 'Input raw value'), - ('slot-in-tag', 'Input TAG'), - ('slot-in-sts-addr', 'Input status address'), - ('slot-in-sts-data', 'Input status data'), - ('slot-in-03', 'Input slot 3'), - ('slot-in-04', 'Input slot 4'), - ('slot-in-05', 'Input slot 5'), - ('slot-in-06', 'Input slot 6'), - ('slot-in-07', 'Input slot 7'), - ('slot-in-08', 'Input slot 8'), - ('slot-in-09', 'Input slot 9'), - ('slot-in-10', 'Input slot 10'), - ('slot-in-11', 'Input slot 11'), - ('slot-in-io-sts', 'Input I/O status'), - # TODO: Add more annotation classes: - # TAG: 'ready', 'valid', 'id', 'rsv' - # CMD ADDR: 'r/w', 'addr', 'unused' - # CMD DATA: 'data', 'unused' - # 3-11: 'data', 'unused', 'double data' - ('warning', 'Warning'), - ('error', 'Error'), - ) - annotation_rows = ( - ('bits-out', 'Output bits', (Ann.BITS_OUT,)), - ('slots-out-raw', 'Output numbers', (Ann.SLOT_OUT_RAW,)), - ('slots-out', 'Output slots', ( - Ann.SLOT_OUT_TAG, Ann.SLOT_OUT_ADDR, Ann.SLOT_OUT_DATA, - Ann.SLOT_OUT_03, Ann.SLOT_OUT_04, Ann.SLOT_OUT_05, Ann.SLOT_OUT_06, - Ann.SLOT_OUT_07, Ann.SLOT_OUT_08, Ann.SLOT_OUT_09, Ann.SLOT_OUT_10, - Ann.SLOT_OUT_11, Ann.SLOT_OUT_IO,)), - ('bits-in', 'Input bits', (Ann.BITS_IN,)), - ('slots-in-raw', 'Input numbers', (Ann.SLOT_IN_RAW,)), - ('slots-in', 'Input slots', ( - Ann.SLOT_IN_TAG, Ann.SLOT_IN_ADDR, Ann.SLOT_IN_DATA, - Ann.SLOT_IN_03, Ann.SLOT_IN_04, Ann.SLOT_IN_05, Ann.SLOT_IN_06, - Ann.SLOT_IN_07, Ann.SLOT_IN_08, Ann.SLOT_IN_09, Ann.SLOT_IN_10, - Ann.SLOT_IN_11, Ann.SLOT_IN_IO,)), - ('warnings', 'Warnings', (Ann.WARN,)), - ('errors', 'Errors', (Ann.ERROR,)), - ) - binary = ( - ('frame-out', 'Frame bits, output data'), - ('frame-in', 'Frame bits, input data'), - ('slot-raw-out', 'Raw slot bits, output data'), - ('slot-raw-in', 'Raw slot bits, input data'), - # TODO: Which (other) binary classes to implement? - # - Are binary annotations per audio slot useful? - # - Assume 20bit per slot, in 24bit units? Or assume 16bit - # audio samples? Observe register access and derive width - # of the audio data? Dump channels 3-11 or 1-12? - ) - - def putx(self, ss, es, cls, data): - self.put(ss, es, self.out_ann, [cls, data]) - - def putf(self, frombit, bitcount, cls, data): - ss = self.frame_ss_list[frombit] - es = self.frame_ss_list[frombit + bitcount] - self.putx(ss, es, cls, data) - - def putb(self, frombit, bitcount, cls, data): - ss = self.frame_ss_list[frombit] - es = self.frame_ss_list[frombit + bitcount] - self.put(ss, es, self.out_binary, [cls, data]) - - def __init__(self): - self.out_binary = None - self.out_ann = None - self.reset() - - def reset(self): - self.frame_ss_list = None - self.frame_slot_lens = [0, 16] + [16 + 20 * i for i in range(1, 13)] - self.frame_total_bits = self.frame_slot_lens[-1] - self.handle_slots = { - 0: self.handle_slot_00, - 1: self.handle_slot_01, - 2: self.handle_slot_02, - } - - def start(self): - if not self.out_binary: - self.out_binary = self.register(srd.OUTPUT_BINARY) - if not self.out_ann: - self.out_ann = self.register(srd.OUTPUT_ANN) - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def bits_to_int(self, bits): - # Convert MSB-first bit sequence to integer value. - if not bits: - return 0 - count = len(bits) - value = sum([2 ** (count - 1 - i) for i in range(count) if bits[i]]) - return value - - def bits_to_bin_ann(self, bits): - # Convert MSB-first bit sequence to binary annotation data. - # It's assumed that the number of bits does not (in useful ways) - # fit into an integer, and we need to create an array of bytes - # from the data afterwards, anyway. Hence the separate routine - # and the conversion of eight bits each. - out = [] - count = len(bits) - while count > 0: - count -= 8 - by, bits = bits[:8], bits[8:] - by = self.bits_to_int(by) - out.append(by) - out = bytes(out) - return out - - def int_to_nibble_text(self, value, bitcount): - # Convert number to hex digits for given bit count. - digits = (bitcount + 3) // 4 - text = '{{:0{:d}x}}'.format(digits).format(value) - return text - - def get_bit_field(self, data, size, off, count): - shift = size - off - count - data >>= shift - mask = (1 << count) - 1 - data &= mask - return data - - def flush_frame_bits(self): - # Flush raw frame bits to binary annotation. - anncls = Ann.BIN_FRAME_OUT - data = self.frame_bits_out[:] - count = len(data) - data = self.bits_to_bin_ann(data) - self.putb(0, count, anncls, data) - - anncls = Ann.BIN_FRAME_IN - data = self.frame_bits_in[:] - count = len(data) - data = self.bits_to_bin_ann(data) - self.putb(0, count, anncls, data) - - def start_frame(self, ss): - # Mark the start of a frame. - if self.frame_ss_list: - # Flush bits if we had a frame before the frame which is - # starting here. - self.flush_frame_bits() - self.frame_ss_list = [ss] - self.frame_bits_out = [] - self.frame_bits_in = [] - self.frame_slot_data_out = [] - self.frame_slot_data_in = [] - self.have_slots = {True: None, False: None} - - def handle_slot_dummy(self, slotidx, bitidx, bitcount, is_out, data): - # Handle slot x, default/fallback handler. - # Only process data of slots 1-12 when slot 0 says "valid". - if not self.have_slots[is_out]: - return - if not self.have_slots[is_out][slotidx]: - return - - # Emit a naive annotation with just the data bits that we saw - # for the slot (hex nibbles for density). For audio data this - # can be good enough. Slots with special meaning should not end - # up calling the dummy handler. - text = self.int_to_nibble_text(data, bitcount) - anncls = Ann.SLOT_OUT_TAG if is_out else Ann.SLOT_IN_TAG - self.putf(bitidx, bitcount, anncls + slotidx, [text]) - - # Emit binary output for the data that is contained in slots - # which end up calling the default handler. This transparently - # should translate to "the slots with audio data", as other - # slots which contain management data should have their specific - # handler routines. In the present form, this approach might be - # good enough to get a (header-less) audio stream for typical - # setups where only line-in or line-out are in use. - # - # TODO: Improve this early prototype implementation. For now the - # decoder just exports the upper 16 bits of each audio channel - # that happens to be valid. For an improved implementation, it - # either takes user provided specs or more smarts like observing - # register access (if the capture includes it). - anncls = Ann.BIN_SLOT_RAW_OUT if is_out else Ann.BIN_SLOT_RAW_IN - data_bin = data >> 4 - data_bin &= 0xffff - data_bin = data_bin.to_bytes(2, byteorder = 'big') - self.putb(bitidx, bitcount, anncls, data_bin) - - def handle_slot_00(self, slotidx, bitidx, bitcount, is_out, data): - # Handle slot 0, TAG. - slotpos = self.frame_slot_lens[slotidx] - fieldoff = 0 - anncls = Ann.SLOT_OUT_TAG if is_out else Ann.SLOT_IN_TAG - - fieldlen = 1 - ready = self.get_bit_field(data, bitcount, fieldoff, fieldlen) - text = ['READY: 1', 'READY', 'RDY', 'R'] if ready else ['ready: 0', 'rdy', '-'] - self.putf(slotpos + fieldoff, fieldlen, anncls, text) - fieldoff += fieldlen - - fieldlen = 12 - valid = self.get_bit_field(data, bitcount, fieldoff, fieldlen) - text = ['VALID: {:3x}'.format(valid), '{:3x}'.format(valid)] - self.putf(slotpos + fieldoff, fieldlen, anncls, text) - have_slots = [True] + [False] * 12 - for idx in range(12): - have_slots[idx + 1] = bool(valid & (1 << (11 - idx))) - self.have_slots[is_out] = have_slots - fieldoff += fieldlen - - fieldlen = 1 - rsv = self.get_bit_field(data, bitcount, fieldoff, fieldlen) - if rsv != 0: - text = ['reserved bit error', 'rsv error', 'rsv'] - self.putf(slotpos + fieldoff, fieldlen, Ann.ERROR, text) - fieldoff += fieldlen - - # TODO: Will input slot 0 have a Codec ID, or 3 reserved bits? - fieldlen = 2 - codec = self.get_bit_field(data, bitcount, fieldoff, fieldlen) - text = ['CODEC: {:1x}'.format(codec), '{:1x}'.format(codec)] - self.putf(slotpos + fieldoff, fieldlen, anncls, text) - fieldoff += fieldlen - - def handle_slot_01(self, slotidx, bitidx, bitcount, is_out, data): - # Handle slot 1, command/status address. - slotpos = self.frame_slot_lens[slotidx] - if not self.have_slots[is_out]: - return - if not self.have_slots[is_out][slotidx]: - return - fieldoff = 0 - anncls = Ann.SLOT_OUT_TAG if is_out else Ann.SLOT_IN_TAG - anncls += slotidx - - fieldlen = 1 - if is_out: - is_read = self.get_bit_field(data, bitcount, fieldoff, fieldlen) - text = ['READ', 'RD', 'R'] if is_read else ['WRITE', 'WR', 'W'] - self.putf(slotpos + fieldoff, fieldlen, anncls, text) - # TODO: Check for the "atomic" constraint? Some operations - # involve address _and_ data, which cannot be spread across - # several frames. Slot 0 and 1 _must_ be provided within the - # same frame (the test should occur in the handler for slot - # 2 of course, in slot 1 we don't know what will follow). - else: - rsv = self.get_bit_field(data, bitcount, fieldoff, fieldlen) - if rsv != 0: - text = ['reserved bit error', 'rsv error', 'rsv'] - self.putf(slotpos + fieldoff, fieldlen, Ann.ERROR, text) - fieldoff += fieldlen - - fieldlen = 7 - regaddr = self.get_bit_field(data, bitcount, fieldoff, fieldlen) - # TODO: Present 0-63 or 0-126 as the address of the 16bit register? - text = ['ADDR: {:2x}'.format(regaddr), '{:2x}'.format(regaddr)] - self.putf(slotpos + fieldoff, fieldlen, anncls, text) - if regaddr & 0x01: - text = ['odd register address', 'odd reg addr', 'odd addr', 'odd'] - self.putf(slotpos + fieldoff, fieldlen, Ann.ERROR, text) - fieldoff += fieldlen - - # Strictly speaking there are 10 data request bits and 2 reserved - # bits for input slots, and 12 reserved bits for output slots. We - # test for 10 and 2 bits, to simplify the logic. Only in case of - # non-zero reserved bits for outputs this will result in "a little - # strange" an annotation. This is a cosmetic issue, we don't mind. - fieldlen = 10 - reqdata = self.get_bit_field(data, bitcount, fieldoff, fieldlen) - if is_out and reqdata != 0: - text = ['reserved bit error', 'rsv error', 'rsv'] - self.putf(slotpos + fieldoff, fieldlen, Ann.ERROR, text) - if not is_out: - text = ['REQ: {:3x}'.format(reqdata), '{:3x}'.format(reqdata)] - self.putf(slotpos + fieldoff, fieldlen, anncls, text) - fieldoff += fieldlen - - fieldlen = 2 - rsv = self.get_bit_field(data, bitcount, fieldoff, fieldlen) - if rsv != 0: - text = ['reserved bit error', 'rsv error', 'rsv'] - self.putf(slotpos + fieldoff, fieldlen, Ann.ERROR, text) - fieldoff += fieldlen - - def handle_slot_02(self, slotidx, bitidx, bitcount, is_out, data): - # Handle slot 2, command/status data. - slotpos = self.frame_slot_lens[slotidx] - if not self.have_slots[is_out]: - return - if not self.have_slots[is_out][slotidx]: - return - fieldoff = 0 - anncls = Ann.SLOT_OUT_TAG if is_out else Ann.SLOT_IN_TAG - anncls += slotidx - - fieldlen = 16 - rwdata = self.get_bit_field(data, bitcount, fieldoff, fieldlen) - # TODO: Check for zero output data when the operation is a read. - # TODO: Check for the "atomic" constraint. - text = ['DATA: {:4x}'.format(rwdata), '{:4x}'.format(rwdata)] - self.putf(slotpos + fieldoff, fieldlen, anncls, text) - fieldoff += fieldlen - - fieldlen = 4 - rsv = self.get_bit_field(data, bitcount, fieldoff, fieldlen) - if rsv != 0: - text = ['reserved bits error', 'rsv error', 'rsv'] - self.putf(slotpos + fieldoff, fieldlen, Ann.ERROR, text) - fieldoff += fieldlen - - # TODO: Implement other slots. - # - 1: cmd/status addr (check status vs command) - # - 2: cmd/status data (check status vs command) - # - 3-11: audio out/in - # - 12: io control/status (modem GPIO(?)) - - def handle_slot(self, slotidx, data_out, data_in): - # Process a received slot of a frame. - func = self.handle_slots.get(slotidx, self.handle_slot_dummy) - bitidx = self.frame_slot_lens[slotidx] - bitcount = self.frame_slot_lens[slotidx + 1] - bitidx - if data_out is not None: - func(slotidx, bitidx, bitcount, True, data_out) - if data_in is not None: - func(slotidx, bitidx, bitcount, False, data_in) - - def handle_bits(self, ss, es, bit_out, bit_in): - # Process a received pair of bits. - # Emit the bits' annotations. Only interpret the data when we - # are in a frame (have seen the start of the frame, and don't - # exceed the expected number of bits in a frame). - if bit_out is not None: - self.putx(ss, es, Ann.BITS_OUT, ['{:d}'.format(bit_out)]) - if bit_in is not None: - self.putx(ss, es, Ann.BITS_IN, ['{:d}'.format(bit_in)]) - if self.frame_ss_list is None: - return - self.frame_ss_list.append(es) - have_len = len(self.frame_ss_list) - 1 - if have_len > self.frame_total_bits: - return - - # Accumulate the bits within the frame, until one slot of the - # frame has become available. - slot_idx = 0 - if bit_out is not None: - self.frame_bits_out.append(bit_out) - slot_idx = len(self.frame_slot_data_out) - if bit_in is not None: - self.frame_bits_in.append(bit_in) - slot_idx = len(self.frame_slot_data_in) - want_len = self.frame_slot_lens[slot_idx + 1] - if have_len != want_len: - return - prev_len = self.frame_slot_lens[slot_idx] - - # Convert bits to integer values. This shall simplify extraction - # of bit fields in multiple other locations. - slot_data_out = None - if bit_out is not None: - slot_bits = self.frame_bits_out[prev_len:] - slot_data = self.bits_to_int(slot_bits) - self.frame_slot_data_out.append(slot_data) - slot_data_out = slot_data - slot_data_in = None - if bit_in is not None: - slot_bits = self.frame_bits_in[prev_len:] - slot_data = self.bits_to_int(slot_bits) - self.frame_slot_data_in.append(slot_data) - slot_data_in = slot_data - - # Emit simple annotations for the integer values, until upper - # layer decode stages will be implemented. - slot_len = have_len - prev_len - slot_ss = self.frame_ss_list[prev_len] - slot_es = self.frame_ss_list[have_len] - if slot_data_out is not None: - slot_text = self.int_to_nibble_text(slot_data_out, slot_len) - self.putx(slot_ss, slot_es, Ann.SLOT_OUT_RAW, [slot_text]) - if slot_data_in is not None: - slot_text = self.int_to_nibble_text(slot_data_in, slot_len) - self.putx(slot_ss, slot_es, Ann.SLOT_IN_RAW, [slot_text]) - - self.handle_slot(slot_idx, slot_data_out, slot_data_in) - - def decode(self): - have_sdo = self.has_channel(Pins.SDATA_OUT) - have_sdi = self.has_channel(Pins.SDATA_IN) - if not have_sdo and not have_sdi: - raise ChannelError('Either SDATA_OUT or SDATA_IN (or both) are required.') - have_reset = self.has_channel(Pins.RESET) - - # Data is sampled at falling CLK edges. Annotations need to span - # the period between rising edges. SYNC rises one cycle _before_ - # the start of a frame. Grab the earliest SYNC sample we can get - # and advance to the start of a bit time. Then keep getting the - # samples and the end of all subsequent bit times. - prev_sync = [None, None, None] - (sync, bit_clk, sdata_out, sdata_in, reset) = self.wait({Pins.BIT_CLK: 'e'}) - if bit_clk == 0: - prev_sync[-1] = sync - (sync, bit_clk, sdata_out, sdata_in, reset) = self.wait({Pins.BIT_CLK: 'r'}) - bit_ss = self.samplenum - while True: - (sync, bit_clk, sdata_out, sdata_in, reset) = self.wait({Pins.BIT_CLK: 'f'}) - prev_sync.pop(0) - prev_sync.append(sync) - self.wait({Pins.BIT_CLK: 'r'}) - if prev_sync[0] == 0 and prev_sync[1] == 1: - self.start_frame(bit_ss) - self.handle_bits(bit_ss, self.samplenum, - sdata_out if have_sdo else None, - sdata_in if have_sdi else None) - bit_ss = self.samplenum diff --git a/decoders/ad5626/__init__.py b/decoders/ad5626/__init__.py deleted file mode 100644 index 5f67799b..00000000 --- a/decoders/ad5626/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 Analog Devices Inc. -## -## 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 . -## - -''' -This decoder stacks on top of the 'spi' PD and decodes the -Analog Devices AD5626 protocol. -''' - -from .pd import Decoder diff --git a/decoders/ad5626/pd.py b/decoders/ad5626/pd.py deleted file mode 100644 index cffee83d..00000000 --- a/decoders/ad5626/pd.py +++ /dev/null @@ -1,62 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 Analog Devices Inc. -## -## 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 . -## - -import sigrokdecode as srd - -class Decoder(srd.Decoder): - api_version = 3 - id = 'ad5626' - name = 'AD5626' - longname = 'Analog Devices AD5626' - desc = 'Analog Devices AD5626 12-bit nanoDAC.' - license = 'gplv2+' - inputs = ['spi'] - outputs = [] - tags = ['IC', 'Analog/digital'] - annotations = ( - ('voltage', 'Voltage'), - ) - - def __init__(self,): - self.reset() - - def reset(self): - self.data = 0 - self.ss = 0 - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def decode(self, ss, es, data): - ptype = data[0] - - if ptype == 'CS-CHANGE': - cs_old, cs_new = data[1:] - if cs_old is not None and cs_old == 0 and cs_new == 1: - self.data >>= 1 - self.data /= 1000 - self.put(self.ss, es, self.out_ann, [0, ['%.3fV' % self.data]]) - self.data = 0 - elif cs_old is not None and cs_old == 1 and cs_new == 0: - self.ss = ss - elif ptype == 'BITS': - mosi = data[1] - for bit in reversed(mosi): - self.data = self.data | bit[0] - self.data <<= 1 diff --git a/decoders/ad79x0/__init__.py b/decoders/ad79x0/__init__.py deleted file mode 100644 index 0e81f17b..00000000 --- a/decoders/ad79x0/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 Analog Devices Inc. -## -## 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 . -## - -''' -This decoder stacks on top of the 'spi' PD and decodes the -Analog Devices AD7910/AD7920 protocol. -''' - -from .pd import Decoder diff --git a/decoders/ad79x0/pd.py b/decoders/ad79x0/pd.py deleted file mode 100644 index 3d7ab731..00000000 --- a/decoders/ad79x0/pd.py +++ /dev/null @@ -1,137 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 Analog Devices Inc. -## -## 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 . -## - -import sigrokdecode as srd - -modes = { - 0: ['Normal Mode', 'Normal', 'Norm', 'N'], - 1: ['Power Down Mode', 'Power Down', 'PD'], - 2: ['Power Up Mode', 'Power Up', 'PU'], -} - -input_voltage_format = ['%.6fV', '%.2fV'] - -validation = { - 'invalid': ['Invalid data', 'Invalid', 'N/A'], - 'incomplete': ['Incomplete conversion', 'Incomplete', 'I'], - 'complete': ['Complete conversion', 'Complete', 'C'], -} - -class Decoder(srd.Decoder): - api_version = 3 - id = 'ad79x0' - name = 'AD79x0' - longname = 'Analog Devices AD79x0' - desc = 'Analog Devices AD7910/AD7920 12-bit ADC.' - license = 'gplv2+' - inputs = ['spi'] - outputs = [] - tags = ['IC', 'Analog/digital'] - annotations = ( - ('mode', 'Mode'), - ('voltage', 'Voltage'), - ('validation', 'Validation'), - ) - annotation_rows = ( - ('modes', 'Modes', (0,)), - ('voltages', 'Voltages', (1,)), - ('data_validation', 'Data validation', (2,)), - ) - options = ( - {'id': 'vref', 'desc': 'Reference voltage (V)', 'default': 1.5}, - ) - - def __init__(self,): - self.reset() - - def reset(self): - self.samplerate = 0 - self.samples_bit = -1 - self.ss = -1 - self.start_sample = 0 - self.previous_state = 0 - self.data = 0 - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def put_validation(self, pos, msg): - self.put(pos[0], pos[1], self.out_ann, [2, validation[msg]]) - - def put_data(self, pos, input_voltage): - ann = [] - for format in input_voltage_format: - ann.append(format % input_voltage) - self.put(pos[0], pos[1], self.out_ann, [1, ann]) - - def put_mode(self, pos, msg): - self.put(pos[0], pos[1], self.out_ann, [0, modes[msg]]) - - def decode(self, ss, es, data): - ptype = data[0] - - if ptype == 'CS-CHANGE': - cs_old, cs_new = data[1:] - if cs_old is not None and cs_old == 0 and cs_new == 1: - if self.samples_bit == -1: - return - self.data >>= 1 - nb_bits = (ss - self.ss) // self.samples_bit - if nb_bits >= 10: - if self.data == 0xFFF: - self.put_mode([self.start_sample, es], 2) - self.previous_state = 0 - self.put_validation([self.start_sample, es], 'invalid') - else: - self.put_mode([self.start_sample, es], 0) - if nb_bits == 16: - self.put_validation([self.start_sample, es], 'complete') - elif nb_bits < 16: - self.put_validation([self.start_sample, es], 'incomplete') - vin = (self.data / ((2**12) - 1)) * self.options['vref'] - self.put_data([self.start_sample, es], vin) - elif nb_bits < 10: - self.put_mode([self.start_sample, es], 1) - self.previous_state = 1 - self.put_validation([self.start_sample, es], 'invalid') - - self.ss = -1 - self.samples_bit = -1 - self.data = 0 - elif cs_old is not None and cs_old == 1 and cs_new == 0: - self.start_sample = ss - self.samples_bit = -1 - - elif ptype == 'BITS': - if data[2] is None: - return - miso = data[2] - if self.samples_bit == -1: - self.samples_bit = miso[0][2] - miso[0][1] - - if self.ss == -1: - self.ss = ss - - for bit in reversed(miso): - self.data = self.data | bit[0] - self.data <<= 1 diff --git a/decoders/ade77xx/__init__.py b/decoders/ade77xx/__init__.py deleted file mode 100755 index cbe8689d..00000000 --- a/decoders/ade77xx/__init__.py +++ /dev/null @@ -1,32 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2017 Karl Palsson -## -## 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 -## - -''' -This decoder stacks on top of the 'spi' PD and decodes Analog Devices -ADE77xx command/responses. - -The ADE77xx is a "Poly Phase Multifunction Energy Metering IC with Per Phase -Information". - -This PD has been tested with an ADE7758 so far, support for other devices -from the ADE77xx series can be added in the future. -''' - -from .pd import Decoder diff --git a/decoders/ade77xx/lists.py b/decoders/ade77xx/lists.py deleted file mode 100755 index f556389d..00000000 --- a/decoders/ade77xx/lists.py +++ /dev/null @@ -1,102 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2017 Karl Palsson -## -## Permission is hereby granted, free of charge, to any person obtaining a copy -## of this software and associated documentation files (the "Software"), to deal -## in the Software without restriction, including without limitation the rights -## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -## copies of the Software, and to permit persons to whom the Software is -## furnished to do so, subject to the following conditions: -## -## The above copyright notice and this permission notice shall be included in all -## copies or substantial portions of the Software. -## -## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -## SOFTWARE. - -from collections import OrderedDict - -# Generated from datasheet rev E, using tabula. -regs = OrderedDict([ - (0x1, ('AWATTHR', 'Watt-Hour Accumulation Register for Phase A. Active power is accumulated over time in this read-only register. The AWATTHR register can hold a maximum of 0.52 seconds of active energy information with full-scale analog inputs before it overflows (see the Active Energy Calculation section). Bit 0 and Bit 1 of the COMPMODE register determine how the active energy is processed from the six analog inputs.', 'R', 16, 'S', 0x0)), - (0x2, ('BWATTHR', 'Watt-Hour Accumulation Register for Phase B.', 'R', 16, 'S', 0x0)), - (0x3, ('CWATTHR', 'Watt-Hour Accumulation Register for Phase C.', 'R', 16, 'S', 0x0)), - (0x4, ('AVARHR', 'VAR-Hour Accumulation Register for Phase A. Reactive power is accumulated over time in this read-only register. The AVARHR register can hold a maximum of 0.52 seconds of reactive energy information with full-scale analog inputs before it overflows (see the Reactive Energy Calculation section). Bit 0 and Bit 1 of the COMPMODE register determine how the reactive energy is processed from the six analog inputs.', 'R', 16, 'S', 0x0)), - (0x5, ('BVARHR', 'VAR-Hour Accumulation Register for Phase B.', 'R', 16, 'S', 0x0)), - (0x6, ('CVARHR', 'VAR-Hour Accumulation Register for Phase C.', 'R', 16, 'S', 0x0)), - (0x7, ('AVAHR', 'VA-Hour Accumulation Register for Phase A. Apparent power is accumulated over time in this read-only register. The AVAHR register can hold a maximum of 1.15 seconds of apparent energy information with full-scale analog inputs before it overflows (see the Apparent Energy Calculation section). Bit 0 and Bit 1 of the COMPMODE register determine how the apparent energy is processed from the six analog inputs.', 'R', 16, 'S', 0x0)), - (0x8, ('BVAHR', 'VA-Hour Accumulation Register for Phase B.', 'R', 16, 'S', 0x0)), - (0x9, ('CVAHR', 'VA-Hour Accumulation Register for Phase C.', 'R', 16, 'S', 0x0)), - (0xa, ('AIRMS', 'Phase A Current Channel RMS Register. The register contains the rms component of the Phase A input of the current channel. The source is selected by data bits in the mode register.', 'R', 24, 'S', 0x0)), - (0xb, ('BIRMS', 'Phase B Current Channel RMS Register.', 'R', 24, 'S', 0x0)), - (0xc, ('CIRMS', 'Phase C Current Channel RMS Register.', 'R', 24, 'S', 0x0)), - (0xd, ('AVRMS', 'Phase A Voltage Channel RMS Register.', 'R', 24, 'S', 0x0)), - (0xe, ('BVRMS', 'Phase B Voltage Channel RMS Register.', 'R', 24, 'S', 0x0)), - (0xf, ('CVRMS', 'Phase C Voltage Channel RMS Register.', 'R', 24, 'S', 0x0)), - (0x10, ('FREQ', 'Frequency of the Line Input Estimated by the Zero-Crossing Processing. It can also display the period of the line input. Bit 7 of the LCYCMODE register determines if the reading is frequency or period. Default is frequency. Data Bit 0 and Bit 1 of the MMODE register determine the voltage channel used for the frequency or period calculation.', 'R', 12, 'U', 0x0)), - (0x11, ('TEMP', 'Temperature Register. This register contains the result of the latest temperature conversion. Refer to the Temperature Measurement section for details on how to interpret the content of this register.', 'R', 8, 'S', 0x0)), - (0x12, ('WFORM', 'Waveform Register. This register contains the digitized waveform of one of the six analog inputs or the digitized power waveform. The source is selected by Data Bit 0 to Bit 4 in the WAVMODE register.', 'R', 24, 'S', 0x0)), - (0x13, ('OPMODE', 'Operational Mode Register. This register defines the general configuration of the ADE7758 (see Table 18).', 'R/W', 8, 'U', 0x4)), - (0x14, ('MMODE', 'Measurement Mode Register. This register defines the channel used for period and peak detection measurements (see Table 19).', 'R/W', 8, 'U', 0xfc)), - (0x15, ('WAVMODE', 'Waveform Mode Register. This register defines the channel and sampling frequency used in the waveform sampling mode (see Table 20).', 'R/W', 8, 'U', 0x0)), - (0x16, ('COMPMODE', 'Computation Mode Register. This register configures the formula applied for the energy and line active energy measurements (see Table 22).', 'R/W', 8, 'U', 0x1c)), - (0x17, ('LCYCMODE', 'Line Cycle Mode Register. This register configures the line cycle accumulation mode for WATT-HR', 'R/W', 8, 'U', 0x78)), - (0x18, ('Mask', 'IRQ Mask Register. It determines if an interrupt event generates an active-low output at the IRQ pin (see the Interrupts section).', 'R/W', 24, 'U', 0x0)), - (0x19, ('Status', 'IRQ Status Register. This register contains information regarding the source of the ADE7758 interrupts (see the Interrupts section).', 'R', 24, 'U', 0x0)), - (0x1a, ('RSTATUS', 'IRQ Reset Status Register. Same as the STATUS register, except that its contents are reset to 0 (all flags cleared) after a read operation.', 'R', 24, 'U', 0x0)), - (0x1b, ('ZXTOUT', 'Zero-Cross Timeout Register. If no zero crossing is detected within the time period specified by this register', 'R/W', 16, 'U', 0xffff)), - (0x1c, ('LINECYC', 'Line Cycle Register. The content of this register sets the number of half-line cycles that the active', 'R/W', 16, 'U', 0xffff)), - (0x1d, ('SAGCYC', 'SAG Line Cycle Register. This register specifies the number of consecutive half-line cycles where voltage channel input may fall below a threshold level. This register is common to the three line voltage SAG detection. The detection threshold is specified by the SAGLVL register (see the Line Voltage SAG Detection section).', 'R/W', 8, 'U', 0xff)), - (0x1e, ('SAGLVL', 'SAG Voltage Level. This register specifies the detection threshold for the SAG event. This register is common to all three phases’ line voltage SAG detections. See the description of the SAGCYC register for details.', 'R/W', 8, 'U', 0x0)), - (0x1f, ('VPINTLVL', 'Voltage Peak Level Interrupt Threshold Register. This register sets the level of the voltage peak detection. Bit 5 to Bit 7 of the MMODE register determine which phases are to be monitored. If the selected voltage phase exceeds this level', 'R/W', 8, 'U', 0xff)), - (0x20, ('IPINTLVL', 'Current Peak Level Interrupt Threshold Register. This register sets the level of the current peak detection. Bit 5 to Bit 7 of the MMODE register determine which phases are to be monitored. If the selected current phase exceeds this level', 'R/W', 8, 'U', 0xff)), - (0x21, ('VPEAK', 'Voltage Peak Register. This register contains the value of the peak voltage waveform that has occurred within a fixed number of half-line cycles. The number of half-line cycles is set by the LINECYC register.', 'R', 8, 'U', 0x0)), - (0x22, ('IPEAK', 'Current Peak Register. This register holds the value of the peak current waveform that has occurred within a fixed number of half-line cycles. The number of half-line cycles is set by the LINECYC register.', 'R', 8, 'U', 0x0)), - (0x23, ('Gain', 'PGA Gain Register. This register is used to adjust the gain selection for the PGA in the current and voltage channels (see the Analog Inputs section).', 'R/W', 8, 'U', 0x0)), - (0x24, ('AVRMSGAIN', 'Phase A VRMS Gain Register. The range of the voltage rms calculation can be adjusted by writing to this register. It has an adjustment range of ±50% with a resolution of 0.0244%/LSB.', 'R/W', 12, 'S', 0x0)), - (0x25, ('BVRMSGAIN', 'Phase B VRMS Gain Register.', 'R/W', 12, 'S', 0x0)), - (0x26, ('CVRMSGAIN', 'Phase C VRMS Gain Register.', 'R/W', 12, 'S', 0x0)), - (0x27, ('AIGAIN', 'Phase A Current Gain Register. This register is not recommended to be used and it should be kept at 0', 'R/W', 12, 'S', 0x0)), - (0x28, ('BIGAIN', 'Phase B Current Gain Register. This register is not recommended to be used and it should be kept at 0', 'R/W', 12, 'S', 0x0)), - (0x29, ('CIGAIN', 'Phase C Current Gain Register. This register is not recommended to be used and it should be kept at 0', 'R/W', 12, 'S', 0x0)), - (0x2a, ('AWG', 'Phase A Watt Gain Register. The range of the watt calculation can be adjusted by writing to this register. It has an adjustment range of ±50% with a resolution of 0.0244%/LSB.', 'R/W', 12, 'S', 0x0)), - (0x2b, ('BWG', 'Phase B Watt Gain Register.', 'R/W', 12, 'S', 0x0)), - (0x2c, ('CWG', 'Phase C Watt Gain Register.', 'R/W', 12, 'S', 0x0)), - (0x2d, ('AVARG', 'Phase A VAR Gain Register. The range of the VAR calculation can be adjusted by writing to this register. It has an adjustment range of ±50% with a resolution of 0.0244%/LSB.', 'R/W', 12, 'S', 0x0)), - (0x2e, ('BVARG', 'Phase B VAR Gain Register.', 'R/W', 12, 'S', 0x0)), - (0x2f, ('CVARG', 'Phase C VAR Gain Register.', 'R/W', 12, 'S', 0x0)), - (0x30, ('AVAG', 'Phase A VA Gain Register. The range of the VA calculation can be adjusted by writing to this register. It has an adjustment range of ±50% with a resolution of 0.0244%/LSB.', 'R/W', 12, 'S', 0x0)), - (0x31, ('BVAG', 'Phase B VA Gain Register.', 'R/W', 12, 'S', 0x0)), - (0x32, ('CVAG', 'Phase C VA Gain Register.', 'R/W', 12, 'S', 0x0)), - (0x33, ('AVRMSOS', 'Phase A Voltage RMS Offset Correction Register.', 'R/W', 12, 'S', 0x0)), - (0x34, ('BVRMSOS', 'Phase B Voltage RMS Offset Correction Register.', 'R/W', 12, 'S', 0x0)), - (0x35, ('CVRMSOS', 'Phase C Voltage RMS Offset Correction Register.', 'R/W', 12, 'S', 0x0)), - (0x36, ('AIRMSOS', 'Phase A Current RMS Offset Correction Register.', 'R/W', 12, 'S', 0x0)), - (0x37, ('BIRMSOS', 'Phase B Current RMS Offset Correction Register.', 'R/W', 12, 'S', 0x0)), - (0x38, ('CIRMSOS', 'Phase C Current RMS Offset Correction Register.', 'R/W', 12, 'S', 0x0)), - (0x39, ('AWATTOS', 'Phase A Watt Offset Calibration Register.', 'R/W', 12, 'S', 0x0)), - (0x3a, ('BWATTOS', 'Phase B Watt Offset Calibration Register.', 'R/W', 12, 'S', 0x0)), - (0x3b, ('CWATTOS', 'Phase C Watt Offset Calibration Register.', 'R/W', 12, 'S', 0x0)), - (0x3c, ('AVAROS', 'Phase A VAR Offset Calibration Register.', 'R/W', 12, 'S', 0x0)), - (0x3d, ('BVAROS', 'Phase B VAR Offset Calibration Register.', 'R/W', 12, 'S', 0x0)), - (0x3e, ('CVAROS', 'Phase C VAR Offset Calibration Register.', 'R/W', 12, 'S', 0x0)), - (0x3f, ('APHCAL', 'Phase A Phase Calibration Register. The phase relationship between the current and voltage channel can be adjusted by writing to this signed 7-bit register (see the Phase Compensation section).', 'R/W', 7, 'S', 0x0)), - (0x40, ('BPHCAL', 'Phase B Phase Calibration Register.', 'R/W', 7, 'S', 0x0)), - (0x41, ('CPHCAL', 'Phase C Phase Calibration Register.', 'R/W', 7, 'S', 0x0)), - (0x42, ('WDIV', 'Active Energy Register Divider.', 'R/W', 8, 'U', 0x0)), - (0x43, ('VARDIV', 'Reactive Energy Register Divider.', 'R/W', 8, 'U', 0x0)), - (0x44, ('VADIV', 'Apparent Energy Register Divider.', 'R/W', 8, 'U', 0x0)), - (0x45, ('APCFNUM', 'Active Power CF Scaling Numerator Register. The content of this register is used in the numerator of the APCF output scaling calculation. Bits [15:13] indicate reverse polarity active power measurement for Phase A', 'R/W', 16, 'U', 0x0)), - (0x46, ('APCFDEN', 'Active Power CF Scaling Denominator Register. The content of this register is used in the denominator of the APCF output scaling.', 'R/W', 12, 'U', 0x3f)), - (0x47, ('VARCFNUM', 'Reactive Power CF Scaling Numerator Register. The content of this register is used in the numerator of the VARCF output scaling. Bits [15:13] indicate reverse polarity reactive power measurement for Phase A', 'R/W', 16, 'U', 0x0)), - (0x48, ('VARCFDEN', 'Reactive Power CF Scaling Denominator Register. The content of this register is used in the denominator of the VARCF output scaling.', 'R/W', 12, 'U', 0x3f)), - (0x7e, ('CHKSUM', 'Checksum Register. The content of this register represents the sum of all the ones in the last register read from the SPI port.', 'R', 8, 'U', None)), - (0x7f, ('Version', 'Version of the Die.', 'R', 8, 'U', None)), -]) diff --git a/decoders/ade77xx/pd.py b/decoders/ade77xx/pd.py deleted file mode 100755 index 5a24a25e..00000000 --- a/decoders/ade77xx/pd.py +++ /dev/null @@ -1,131 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2017 Karl Palsson -## -## Permission is hereby granted, free of charge, to any person obtaining a copy -## of this software and associated documentation files (the "Software"), to deal -## in the Software without restriction, including without limitation the rights -## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -## copies of the Software, and to permit persons to whom the Software is -## furnished to do so, subject to the following conditions: -## -## The above copyright notice and this permission notice shall be included in all -## copies or substantial portions of the Software. -## -## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -## SOFTWARE. - -import math -import sigrokdecode as srd -from .lists import * - -class Decoder(srd.Decoder): - api_version = 3 - id = 'ade77xx' - name = 'ADE77xx' - longname = 'Analog Devices ADE77xx' - desc = 'Poly phase multifunction energy metering IC protocol.' - license = 'mit' - inputs = ['spi'] - outputs = [] - tags = ['Analog/digital', 'IC', 'Sensor'] - annotations = ( - ('read', 'Register read commands'), - ('write', 'Register write commands'), - ('warning', 'Warnings'), - ) - annotation_rows = ( - ('read', 'Read', (0,)), - ('write', 'Write', (1,)), - ('warnings', 'Warnings', (2,)), - ) - - def reset_data(self): - self.expected = 0 - self.mosi_bytes, self.miso_bytes = [], [] - - def __init__(self): - self.reset() - - def reset(self): - self.ss_cmd, self.es_cmd = 0, 0 - self.reset_data() - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putx(self, data): - self.put(self.ss_cmd, self.es_cmd, self.out_ann, data) - - def put_warn(self, pos, msg): - self.put(pos[0], pos[1], self.out_ann, [2, [msg]]) - - def decode(self, ss, es, data): - ptype = data[0] - if ptype == 'CS-CHANGE': - # Bear in mind, that CS is optional according to the datasheet. - # If we transition high mid-stream, toss out our data and restart. - cs_old, cs_new = data[1:] - if cs_old is not None and cs_old == 0 and cs_new == 1: - if len(self.mosi_bytes) > 0 and len(self.mosi_bytes[1:]) < self.expected: - # Mark short read/write for reg at least! - self.es_cmd = es - write, reg = self.cmd & 0x80, self.cmd & 0x7f - rblob = regs.get(reg) - idx = 1 if write else 0 - self.putx([idx, ['%s: %s' % (rblob[0], "SHORT")]]) - self.put_warn([self.ss_cmd, es], "Short transfer!") - self.reset_data() - return - - # Don't care about anything else. - if ptype != 'DATA': - return - mosi, miso = data[1:] - - if len(self.mosi_bytes) == 0: - self.ss_cmd = ss - self.mosi_bytes.append(mosi) - self.miso_bytes.append(miso) - - # A transfer is 2-4 bytes, (command + 1..3 byte reg). - if len(self.mosi_bytes) < 2: - return - - self.cmd = self.mosi_bytes[0] - write, reg = self.cmd & 0x80, self.cmd & 0x7f - rblob = regs.get(reg) - if not rblob: - # If you don't have CS, this will _destroy_ comms! - self.put_warn([self.ss_cmd, es], 'Unknown register!') - return - - self.expected = math.ceil(rblob[3] / 8) - if len(self.mosi_bytes[1:]) != self.expected: - return - valo, vali = None, None - self.es_cmd = es - if self.expected == 3: - valo = self.mosi_bytes[1] << 16 | self.mosi_bytes[2] << 8 | \ - self.mosi_bytes[3] - vali = self.miso_bytes[1] << 16 | self.miso_bytes[2] << 8 | \ - self.miso_bytes[3] - elif self.expected == 2: - valo = self.mosi_bytes[1] << 8 | self.mosi_bytes[2] - vali = self.miso_bytes[1] << 8 | self.miso_bytes[2] - elif self.expected == 1: - valo = self.mosi_bytes[1] - vali = self.miso_bytes[1] - - if write: - self.putx([1, ['%s: %#x' % (rblob[0], valo)]]) - else: - self.putx([0, ['%s: %#x' % (rblob[0], vali)]]) - - self.reset_data() diff --git a/decoders/adf435x/__init__.py b/decoders/adf435x/__init__.py deleted file mode 100755 index 1c89e2dc..00000000 --- a/decoders/adf435x/__init__.py +++ /dev/null @@ -1,29 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2017 Joel Holdsworth -## -## 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, see . -## - -''' -This decoder stacks on top of the 'spi' PD and decodes the protocol spoken -by the Analog Devices ADF4350 and ADF4351 RF synthesizer chips. - -Details: -http://www.analog.com/media/en/technical-documentation/data-sheets/ADF4350.pdf -http://www.analog.com/media/en/technical-documentation/data-sheets/ADF4351.pdf -''' - -from .pd import Decoder diff --git a/decoders/adf435x/pd.py b/decoders/adf435x/pd.py deleted file mode 100755 index f6c6e6e0..00000000 --- a/decoders/adf435x/pd.py +++ /dev/null @@ -1,144 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2017 Joel Holdsworth -## -## 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 . -## - -import sigrokdecode as srd - -def disabled_enabled(v): - return ['Disabled', 'Enabled'][v] - -def output_power(v): - return '%+ddBm' % [-4, -1, 2, 5][v] - -regs = { -# reg: name offset width parser - 0: [ - ('FRAC', 3, 12, None), - ('INT', 15, 16, lambda v: 'Not Allowed' if v < 32 else v) - ], - 1: [ - ('MOD', 3, 12, None), - ('Phase', 15, 12, None), - ('Prescalar', 27, 1, lambda v: ['4/5', '8/9'][v]), - ('Phase Adjust', 28, 1, lambda v: ['Off', 'On'][v]), - ], - 2: [ - ('Counter Reset', 3, 1, disabled_enabled), - ('Charge Pump Three-State', 4, 1, disabled_enabled), - ('Power-Down', 5, 1, disabled_enabled), - ('PD Polarity', 6, 1, lambda v: ['Negative', 'Positive'][v]), - ('LDP', 7, 1, lambda v: ['10ns', '6ns'][v]), - ('LDF', 8, 1, lambda v: ['FRAC-N', 'INT-N'][v]), - ('Charge Pump Current Setting', 9, 4, lambda v: '%0.2fmA @ 5.1kΩ' % - [0.31, 0.63, 0.94, 1.25, 1.56, 1.88, 2.19, 2.50, - 2.81, 3.13, 3.44, 3.75, 4.06, 4.38, 4.69, 5.00][v]), - ('Double Buffer', 13, 1, disabled_enabled), - ('R Counter', 14, 10, None), - ('RDIV2', 24, 1, disabled_enabled), - ('Reference Doubler', 25, 1, disabled_enabled), - ('MUXOUT', 26, 3, lambda v: - ['Three-State Output', 'DVdd', 'DGND', 'R Counter Output', 'N Divider Output', - 'Analog Lock Detect', 'Digital Lock Detect', 'Reserved'][v]), - ('Low Noise and Low Spur Modes', 29, 2, lambda v: - ['Low Noise Mode', 'Reserved', 'Reserved', 'Low Spur Mode'][v]) - ], - 3: [ - ('Clock Divider', 3, 12, None), - ('Clock Divider Mode', 15, 2, lambda v: - ['Clock Divider Off', 'Fast Lock Enable', 'Resync Enable', 'Reserved'][v]), - ('CSR Enable', 18, 1, disabled_enabled), - ('Charge Cancellation', 21, 1, disabled_enabled), - ('ABP', 22, 1, lambda v: ['6ns (FRAC-N)', '3ns (INT-N)'][v]), - ('Band Select Clock Mode', 23, 1, lambda v: ['Low', 'High'][v]) - ], - 4: [ - ('Output Power', 3, 2, output_power), - ('Output Enable', 5, 1, disabled_enabled), - ('AUX Output Power', 6, 2, output_power), - ('AUX Output Select', 8, 1, lambda v: ['Divided Output', 'Fundamental'][v]), - ('AUX Output Enable', 9, 1, disabled_enabled), - ('MTLD', 10, 1, disabled_enabled), - ('VCO Power-Down', 11, 1, lambda v: - 'VCO Powered ' + ('Down' if v == 1 else 'Up')), - ('Band Select Clock Divider', 12, 8, None), - ('RF Divider Select', 20, 3, lambda v: '÷' + str(2**v)), - ('Feedback Select', 23, 1, lambda v: ['Divided', 'Fundamental'][v]), - ], - 5: [ - ('LD Pin Mode', 22, 2, lambda v: - ['Low', 'Digital Lock Detect', 'Low', 'High'][v]) - ] -} - -ANN_REG = 0 - -class Decoder(srd.Decoder): - api_version = 3 - id = 'adf435x' - name = 'ADF435x' - longname = 'Analog Devices ADF4350/1' - desc = 'Wideband synthesizer with integrated VCO.' - license = 'gplv3+' - inputs = ['spi'] - outputs = [] - tags = ['Clock/timing', 'IC', 'Wireless/RF'] - annotations = ( - # Sent from the host to the chip. - ('register', 'Register written to the device'), - ) - annotation_rows = ( - ('registers', 'Register writes', (ANN_REG,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.bits = [] - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def decode_bits(self, offset, width): - return (sum([(1 << i) if self.bits[offset + i][0] else 0 for i in range(width)]), - (self.bits[offset + width - 1][1], self.bits[offset][2])) - - def decode_field(self, name, offset, width, parser): - val, pos = self.decode_bits(offset, width) - self.put(pos[0], pos[1], self.out_ann, [ANN_REG, - ['%s: %s' % (name, parser(val) if parser else str(val))]]) - return val - - def decode(self, ss, es, data): - - ptype, data1, data2 = data - - if ptype == 'CS-CHANGE': - if data1 == 1: - if len(self.bits) == 32: - reg_value, reg_pos = self.decode_bits(0, 3) - self.put(reg_pos[0], reg_pos[1], self.out_ann, [ANN_REG, - ['Register: %d' % reg_value, 'Reg: %d' % reg_value, - '[%d]' % reg_value]]) - if reg_value < len(regs): - field_descs = regs[reg_value] - for field_desc in field_descs: - field = self.decode_field(*field_desc) - self.bits = [] - if ptype == 'BITS': - self.bits = data1 + self.bits diff --git a/decoders/adns5020/__init__.py b/decoders/adns5020/__init__.py deleted file mode 100755 index e519da44..00000000 --- a/decoders/adns5020/__init__.py +++ /dev/null @@ -1,27 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Karl Palsson -## -## 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, see . -## - -''' -This decoder stacks on top of the 'spi' PD and decodes ADNS-5020 optical mouse -sensor commands and data. - -Use MOSI for the SDIO shared line. -''' - -from .pd import Decoder diff --git a/decoders/adns5020/pd.py b/decoders/adns5020/pd.py deleted file mode 100755 index 9ac778e0..00000000 --- a/decoders/adns5020/pd.py +++ /dev/null @@ -1,116 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Karl Palsson -## -## 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, see . -## - -import sigrokdecode as srd - -regs = { - 0: 'Product_ID', - 1: 'Revision_ID', - 2: 'Motion', - 3: 'Delta_X', - 4: 'Delta_Y', - 5: 'SQUAL', - 6: 'Shutter_Upper', - 7: 'Shutter_Lower', - 8: 'Maximum_Pixel', - 9: 'Pixel_Sum', - 0xa: 'Minimum_Pixel', - 0xb: 'Pixel_Grab', - 0xd: 'Mouse_Control', - 0x3a: 'Chip_Reset', - 0x3f: 'Inv_Rev_ID', - 0x63: 'Motion_Burst', -} - -class Decoder(srd.Decoder): - api_version = 3 - id = 'adns5020' - name = 'ADNS-5020' - longname = 'Avago ADNS-5020' - desc = 'Bidirectional optical mouse sensor protocol.' - license = 'gplv2+' - inputs = ['spi'] - outputs = [] - tags = ['IC', 'PC', 'Sensor'] - annotations = ( - ('read', 'Register read commands'), - ('write', 'Register write commands'), - ('warning', 'Warnings'), - ) - annotation_rows = ( - ('read', 'Read', (0,)), - ('write', 'Write', (1,)), - ('warnings', 'Warnings', (2,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.ss_cmd, self.es_cmd = 0, 0 - self.mosi_bytes = [] - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putx(self, data): - self.put(self.ss_cmd, self.es_cmd, self.out_ann, data) - - def put_warn(self, pos, msg): - self.put(pos[0], pos[1], self.out_ann, [2, [msg]]) - - def decode(self, ss, es, data): - ptype = data[0] - if ptype == 'CS-CHANGE': - # If we transition high mid-stream, toss out our data and restart. - cs_old, cs_new = data[1:] - if cs_old is not None and cs_old == 0 and cs_new == 1: - if len(self.mosi_bytes) not in [0, 2]: - self.put_warn([self.ss_cmd, es], 'Misplaced CS#!') - self.mosi_bytes = [] - return - - # Don't care about anything else. - if ptype != 'DATA': - return - mosi, miso = data[1:] - - self.ss, self.es = ss, es - - if len(self.mosi_bytes) == 0: - self.ss_cmd = ss - self.mosi_bytes.append(mosi) - - # Writes/reads are mostly two transfers (burst mode is different). - if len(self.mosi_bytes) != 2: - return - - self.es_cmd = es - cmd, arg = self.mosi_bytes - write = cmd & 0x80 - reg = cmd & 0x7f - reg_desc = regs.get(reg, 'Reserved %#x' % reg) - if reg > 0x63: - reg_desc = 'Unknown' - if write: - self.putx([1, ['%s: %#x' % (reg_desc, arg)]]) - else: - self.putx([0, ['%s: %d' % (reg_desc, arg)]]) - - self.mosi_bytes = [] diff --git a/decoders/adxl345/__init__.py b/decoders/adxl345/__init__.py deleted file mode 100644 index e46bce9f..00000000 --- a/decoders/adxl345/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 Analog Devices Inc. -## -## 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 -## - -''' -This decoder stacks on top of the 'spi' PD and decodes the -Analog Devices ADXL345 protocol. -''' - -from .pd import Decoder diff --git a/decoders/adxl345/lists.py b/decoders/adxl345/lists.py deleted file mode 100644 index c22ef3e0..00000000 --- a/decoders/adxl345/lists.py +++ /dev/null @@ -1,96 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 Analog Devices Inc. -## -## 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 -## - -error_messages = { - 'interrupt': ['Interrupt'], - 'undesirable': ['Undesirable behavior'], - 'dis_single': ['Disable single tap'], - 'dis_double': ['Disable double tap'], - 'dis_single_double': ['Disable single/double tap'], -} - -rate_code = { - 0x00: 0.1, - 0x01: 0.2, - 0x02: 0.39, - 0x03: 0.78, - 0x04: 1.56, - 0x05: 3.13, - 0x06: 6.25, - 0x07: 12.5, - 0x08: 25, - 0x09: 50, - 0x0A: 100, - 0x0B: 200, - 0x0C: 400, - 0x0D: 800, - 0x0E: 1600, - 0x0F: 3200, -} - -fifo_modes = { - 0x00: 'Bypass', - 0x01: 'FIFO', - 0x02: 'Stream', - 0x03: 'Trigger', -} - -operations = { - 0x00: ['WRITE REG', 'WRITE', 'W'], - 0x01: ['READ REG', 'READ', 'R'], -} - -number_bytes = { - 0x00: ['SINGLE BYTE', 'SING BYTE', '1 BYTE', '1B'], - 0x01: ['MULTIPLE BYTES', 'MULTI BYTES', 'n*BYTES', 'n*B'], -} - -registers = { - 0x00: ['DEVID', 'DID', 'ID'], - 0x1D: ['THRESH_TAP', 'TH_TAP', 'TH_T'], - 0x1E: ['OFSX', 'OFX'], - 0x1F: ['OFSY', 'OFY'], - 0x20: ['OFSZ', 'OFZ'], - 0x21: ['DUR'], - 0x22: ['Latent', 'Lat'], - 0x23: ['Window', 'Win'], - 0x24: ['THRESH_ACT', 'TH_ACT', 'TH_A'], - 0x25: ['THRESH_INACT', 'TH_INACT', 'TH_I'], - 0x26: ['TIME_INACT', 'TI_INACT', 'TI_I'], - 0x27: ['ACT_INACT_CTL', 'ACT_I_CTL', 'A_I_C'], - 0x28: ['THRESH_FF', 'TH_FF'], - 0x29: ['TIME_FF', 'TI_FF'], - 0x2A: ['TAP_AXES', 'TAP_AX', 'TP_AX'], - 0x2B: ['ACT_TAP_STATUS', 'ACT_TAP_STAT', 'ACT_TP_ST', 'A_T_S'], - 0x2C: ['BW_RATE', 'BW_R'], - 0x2D: ['POWER_CTL', 'PW_CTL', 'PW_C'], - 0x2E: ['INT_ENABLE', 'INT_EN', 'I_EN'], - 0x2F: ['INT_MAP', 'I_M'], - 0x30: ['INT_SOURCE', 'INT_SRC', 'I_SRC', 'I_S'], - 0x31: ['DATA_FORMAT', 'DATA_FRM', 'D_FRM', 'D_F'], - 0x32: ['DATAX0', 'DX0', 'X0'], - 0x33: ['DATAX1', 'DX1', 'X1'], - 0x34: ['DATAY0', 'DY0', 'Y0'], - 0x35: ['DATAY1', 'DY1', 'Y1'], - 0x36: ['DATAZ0', 'DZ0', 'Z0'], - 0x37: ['DATAZ1', 'DZ1', 'Z1'], - 0x38: ['FIFO_CTL', 'FIF_CT', 'F_C'], - 0x39: ['FIFO_STATUS', 'FIFO_STAT', 'FIF_ST', 'F_S'], -} diff --git a/decoders/adxl345/pd.py b/decoders/adxl345/pd.py deleted file mode 100644 index 2d53e4c0..00000000 --- a/decoders/adxl345/pd.py +++ /dev/null @@ -1,453 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 Analog Devices Inc. -## -## 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 . -## - -import sigrokdecode as srd -from common.srdhelper import SrdIntEnum -from .lists import * - -WORD_SIZE = 8 - -class Channel(): - MISO, MOSI = range(2) - -class Operation(): - READ, WRITE = range(2) - -class BitType(): - ENABLE = {1: ['Enable %s', 'En %s', '%s '], 0: ['Disable %s', 'Dis %s', '!%s '],} - SOURCE = {1: ['Involve %s', 'Inv %s', '%s'], 0: ['Not involve %s', 'Not inv %s', '!%s'],} - INTERRUPT = {1: ['INT2 %s', 'I2: %s '], 0: ['INT1 %s', 'I1:%s '],} - AC_DC = {1: ['%s ac', 'ac'], 0: ['%s dc', 'dc'],} - UNUSED = {1: ['N/A'], 0: ['N/A'],} - OTHER = 0 - -class Bit(): - def __init__(self, name, type, values=None): - self.value = 0 - self.name = name - self.type = type - self.values = values - - def set_value(self, value): - self.value = value - - def get_bit_annotation(self): - if self.type == BitType.OTHER: - annotation = self.values[self.value].copy() - else: - annotation = self.type[self.value].copy() - - for index in range(len(annotation)): - if '%s' in annotation[index]: - annotation[index] = str(annotation[index] % self.name) - return annotation - -Ann = SrdIntEnum.from_str('Ann', 'READ WRITE MB REG_ADDRESS REG_DATA WARNING') - -St = SrdIntEnum.from_str('St', 'IDLE ADDRESS_BYTE DATA') - -class Decoder(srd.Decoder): - api_version = 3 - id = 'adxl345' - name = 'ADXL345' - longname = 'Analog Devices ADXL345' - desc = 'Analog Devices ADXL345 3-axis accelerometer.' - license = 'gplv2+' - inputs = ['spi'] - outputs = [] - tags = ['IC', 'Sensor'] - annotations = ( - ('read', 'Read'), - ('write', 'Write'), - ('mb', 'Multiple bytes'), - ('reg-address', 'Register address'), - ('reg-data', 'Register data'), - ('warning', 'Warning'), - ) - annotation_rows = ( - ('reg', 'Registers', (Ann.READ, Ann.WRITE, Ann.MB, Ann.REG_ADDRESS)), - ('data', 'Data', (Ann.REG_DATA, Ann.WARNING)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.mosi, self.miso = [], [] - self.reg = [] - self.operation = None - self.address = 0 - self.data = -1 - self.state = St.IDLE - self.ss, self.es = -1, -1 - self.samples_per_bit = 0 - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putx(self, data): - self.put(self.ss, self.es, self.out_ann, data) - - def putb(self, data, index): - start = self.ss + (self.samples_per_bit * index) - self.put(start, start + self.samples_per_bit, self.out_ann, data) - - def putbs(self, data, start_index, stop_index): - start_index = self.reverse_bit_index(start_index, WORD_SIZE) - stop_index = self.reverse_bit_index(stop_index, WORD_SIZE) - start = self.ss + (self.samples_per_bit * start_index) - stop = start + (self.samples_per_bit * (stop_index - start_index + 1)) - self.put(start, stop, self.out_ann, data) - - def handle_reg_with_scaling_factor(self, data, factor, name, unit, error_msg): - if data == 0 and error_msg is not None: - self.putx([Ann.WARNING, error_msg]) - else: - result = (data * factor) / 1000 - self.putx([Ann.REG_DATA, ['%s: %f %s' % (name, result, unit), '%f %s' % (result, unit)]]) - - def handle_reg_bit_msg(self, bit, index, en_msg, dis_msg): - self.putb([Ann.REG_DATA, [en_msg if bit else dis_msg]], index) - - def interpret_bits(self, data, bits): - bits_values = [] - for offset in range(8): - bits_values.insert(0, (data & (1 << offset)) >> offset) - - for index in range(len(bits)): - if bits[index] is None: - continue - bit = bits[index] - bit.set_value(bits_values[index]) - self.putb([Ann.REG_DATA, bit.get_bit_annotation()], index) - - return list(reversed(bits_values)) - - def reverse_bit_index(self, index, word_size): - return word_size - index - 1 - - def get_decimal_number(self, bits, start_index, stop_index): - number = 0 - interval = range(start_index, stop_index + 1, 1) - for index, offset in zip(interval, range(len(interval))): - bit = bits[index] - number = number | (bit << offset) - return number - - def get_axis_value(self, data, axis): - if self.data != - 1: - data <<= 8 - self.data |= data - self.put(self.start_index, self.es, self.out_ann, - [Ann.REG_DATA, ['%s: 0x%04X' % (axis, self.data), str(data)]]) - self.data = -1 - else: - self.putx([Ann.REG_DATA, [str(data)]]) - - def handle_reg_0x1d(self, data): - self.handle_reg_with_scaling_factor(data, 62.5, 'Threshold', 'g', - error_messages['undesirable']) - - def handle_reg_0x1e(self, data): - self.handle_reg_with_scaling_factor(data, 15.6, 'OFSX', 'g', None) - - def handle_reg_0x1f(self, data): - self.handle_reg_with_scaling_factor(data, 15.6, 'OFSY', 'g', None) - - def handle_reg_0x20(self, data): - self.handle_reg_with_scaling_factor(data, 15.6, 'OFSZ', 'g', None) - - def handle_reg_0x21(self, data): - self.handle_reg_with_scaling_factor(data, 0.625, 'Duration', 's', - error_messages['dis_single_double']) - - def handle_reg_0x22(self, data): - self.handle_reg_with_scaling_factor(data, 1.25, 'Latency', 's', - error_messages['dis_double']) - - def handle_reg_0x23(self, data): - self.handle_reg_with_scaling_factor(data, 1.25, 'Window', 's', - error_messages['dis_double']) - - def handle_reg_0x24(self, data): - self.handle_reg_0x1d(data) - - def handle_reg_0x25(self, data): - self.handle_reg_0x1d(data) - - def handle_reg_0x26(self, data): - self.handle_reg_with_scaling_factor(data, 1000, 'Time', 's', - error_messages['interrupt']) - - def handle_reg_0x27(self, data): - bits = [Bit('ACT', BitType.AC_DC), - Bit('ACT_X', BitType.ENABLE), - Bit('ACT_Y', BitType.ENABLE), - Bit('ACT_Z', BitType.ENABLE), - Bit('INACT', BitType.AC_DC), - Bit('INACT_X', BitType.ENABLE), - Bit('INACT_Y', BitType.ENABLE), - Bit('INACT_Z', BitType.ENABLE)] - self.interpret_bits(data, bits) - - def handle_reg_0x28(self, data): - self.handle_reg_0x1d(data) - - def handle_reg_0x29(self, data): - self.handle_reg_with_scaling_factor(data, 5, 'Time', 's', - error_messages['undesirable']) - - def handle_reg_0x2a(self, data): - bits = [Bit('', BitType.UNUSED), - Bit('', BitType.UNUSED), - Bit('', BitType.UNUSED), - Bit('', BitType.UNUSED), - Bit('', BitType.OTHER, {1: ['Suppressed', 'Suppr', 'S'], - 0: ['Unsuppressed', 'Unsuppr', 'Uns'],}), - Bit('TAP_X', BitType.ENABLE), - Bit('TAP_Y', BitType.ENABLE), - Bit('TAP_Z', BitType.ENABLE)] - self.interpret_bits(data, bits) - - def handle_reg_0x2b(self, data): - bits = [Bit('', BitType.UNUSED), - Bit('ACT_X', BitType.SOURCE), - Bit('ACT_Y', BitType.SOURCE), - Bit('ACT_Z', BitType.SOURCE), - Bit('', BitType.OTHER, {1: ['Asleep', 'Asl'], - 0: ['Not asleep', 'Not asl', '!Asl'],}), - Bit('TAP_X', BitType.SOURCE), - Bit('TAP_Y', BitType.SOURCE), - Bit('TAP_Z', BitType.SOURCE)] - self.interpret_bits(data, bits) - - def handle_reg_0x2c(self, data): - bits = [Bit('', BitType.UNUSED), - Bit('', BitType.UNUSED), - Bit('', BitType.UNUSED), - Bit('', BitType.OTHER, {1: ['Reduce power', 'Reduce pw', 'Red pw'], 0: ['Normal operation', 'Normal op', 'Norm op'],})] - bits_values = self.interpret_bits(data, bits) - - start_index, stop_index = 0, 3 - rate = self.get_decimal_number(bits_values, start_index, stop_index) - self.putbs([Ann.REG_DATA, ['%f' % rate_code[rate]]], stop_index, start_index) - - def handle_reg_0x2d(self, data): - bits = [Bit('', BitType.UNUSED), - Bit('', BitType.UNUSED), - Bit('', BitType.OTHER, {1: ['Link'], 0: ['Unlink'], }), - Bit('AUTO_SLEEP', BitType.ENABLE), - Bit('', BitType.OTHER, {1: ['Measurement mode', 'Measurement', 'Meas'], 0: ['Standby mode', 'Standby'], }), - Bit('', BitType.OTHER, {1: ['Sleep mode', 'Sleep', 'Slp'], 0: ['Normal mode', 'Normal', 'Nrm'],})] - bits_values = self.interpret_bits(data, bits) - - start_index, stop_index = 0, 1 - wakeup = self.get_decimal_number(bits_values, start_index, stop_index) - frequency = 2 ** (~wakeup & 0x03) - self.putbs([Ann.REG_DATA, ['%d Hz' % frequency]], stop_index, start_index) - - def handle_reg_0x2e(self, data): - bits = [Bit('DATA_READY', BitType.ENABLE), - Bit('SINGLE_TAP', BitType.ENABLE), - Bit('DOUBLE_TAP', BitType.ENABLE), - Bit('Activity', BitType.ENABLE), - Bit('Inactivity', BitType.ENABLE), - Bit('FREE_FALL', BitType.ENABLE), - Bit('Watermark', BitType.ENABLE), - Bit('Overrun', BitType.ENABLE)] - self.interpret_bits(data, bits) - - def handle_reg_0x2f(self, data): - bits = [Bit('DATA_READY', BitType.INTERRUPT), - Bit('SINGLE_TAP', BitType.INTERRUPT), - Bit('DOUBLE_TAP', BitType.INTERRUPT), - Bit('Activity', BitType.INTERRUPT), - Bit('Inactivity', BitType.INTERRUPT), - Bit('FREE_FALL', BitType.INTERRUPT), - Bit('Watermark', BitType.INTERRUPT), - Bit('Overrun', BitType.INTERRUPT)] - self.interpret_bits(data, bits) - - def handle_reg_0x30(self, data): - bits = [Bit('DATA_READY', BitType.SOURCE), - Bit('SINGLE_TAP', BitType.SOURCE), - Bit('DOUBLE_TAP', BitType.SOURCE), - Bit('Activity', BitType.SOURCE), - Bit('Inactivity', BitType.SOURCE), - Bit('FREE_FALL', BitType.SOURCE), - Bit('Watermark', BitType.SOURCE), - Bit('Overrun', BitType.SOURCE)] - self.interpret_bits(data, bits) - - def handle_reg_0x31(self, data): - bits = [Bit('SELF_TEST', BitType.ENABLE), - Bit('', BitType.OTHER, {1: ['3-wire SPI', '3-SPI'], 0: ['4-wire SPI', '4-SPI'],}), - Bit('', BitType.OTHER, {1: ['INT ACT LOW', 'INT LOW'], 0: ['INT ACT HIGH', 'INT HIGH'],}), - Bit('', BitType.UNUSED), - Bit('', BitType.OTHER, {1: ['Full resolution', 'Full res'], 0: ['10-bit mode', '10-bit'],}), - Bit('', BitType.OTHER, {1: ['MSB mode', 'MSB'], 0: ['LSB mode', 'LSB'],})] - bits_values = self.interpret_bits(data, bits) - - start_index, stop_index = 0, 1 - range_g = self.get_decimal_number(bits_values, start_index, stop_index) - result = 2 ** (range_g + 1) - self.putbs([Ann.REG_DATA, ['+/-%d g' % result]], stop_index, start_index) - - def handle_reg_0x32(self, data): - self.data = data - self.putx([Ann.REG_DATA, [str(data)]]) - - def handle_reg_0x33(self, data): - self.get_axis_value(data, 'X') - - def handle_reg_0x34(self, data): - self.handle_reg_0x32(data) - - def handle_reg_0x35(self, data): - self.get_axis_value(data, 'Y') - - def handle_reg_0x36(self, data): - self.handle_reg_0x32(data) - - def handle_reg_0x37(self, data): - self.get_axis_value(data, 'Z') - - def handle_reg_0x38(self, data): - bits = [None, - None, - Bit('', BitType.OTHER, {1: ['Trig-INT2', 'INT2'], 0: ['Trig-INT1', 'INT1'], })] - bits_values = self.interpret_bits(data, bits) - - start_index, stop_index = 6, 7 - fifo = self.get_decimal_number(bits_values, start_index, stop_index) - self.putbs([Ann.REG_DATA, [fifo_modes[fifo]]], stop_index, start_index) - - start_index, stop_index = 0, 4 - samples = self.get_decimal_number(bits_values, start_index, stop_index) - self.putbs([Ann.REG_DATA, ['Samples: %d' % samples, '%d' % samples]], stop_index, start_index) - - def handle_reg_0x39(self, data): - bits = [Bit('', BitType.OTHER, {1: ['Triggered', 'Trigg'], 0: ['Not triggered', 'Not trigg'],}), - Bit('', BitType.UNUSED)] - bits_values = self.interpret_bits(data, bits) - - start_index, stop_index = 0, 5 - entries = self.get_decimal_number(bits_values, start_index, stop_index) - self.putbs([Ann.REG_DATA, ['Entries: %d' % entries, '%d' % entries]], stop_index, start_index) - - def get_bit(self, channel): - if (channel == Channel.MOSI and self.mosi is None) or \ - (channel == Channel.MISO and self.miso is None): - raise Exception('No available data') - - mosi_bit, miso_bit = 0, 0 - if self.miso is not None: - if len(self.mosi) < 0: - raise Exception('No available data') - miso_bit = self.miso.pop(0) - if self.miso is not None: - if len(self.miso) < 0: - raise Exception('No available data') - mosi_bit = self.mosi.pop(0) - - if channel == Channel.MOSI: - return mosi_bit - return miso_bit - - def decode(self, ss, es, data): - ptype = data[0] - - if ptype == 'CS-CHANGE': - cs_old, cs_new = data[1:] - if cs_old is not None and cs_old == 1 and cs_new == 0: - self.ss, self.es = ss, es - self.state = St.ADDRESS_BYTE - else: - self.state = St.IDLE - - elif ptype == 'BITS': - if data[1] is not None: - self.mosi = list(reversed(data[1])) - if data[2] is not None: - self.miso = list(reversed(data[2])) - - if self.mosi is None and self.miso is None: - return - - if self.state == St.ADDRESS_BYTE: - # OPERATION BIT - op_bit = self.get_bit(Channel.MOSI) - self.put(op_bit[1], op_bit[2], self.out_ann, - [Ann.READ if op_bit[0] else Ann.WRITE, operations[op_bit[0]]]) - self.operation = Operation.READ if op_bit[0] else Operation.WRITE - # MULTIPLE-BYTE BIT - mb_bit = self.get_bit(Channel.MOSI) - self.put(mb_bit[1], mb_bit[2], self.out_ann, [Ann.MB, number_bytes[mb_bit[0]]]) - - # REGISTER 6-BIT ADDRESS - self.address = 0 - start_sample = self.mosi[0][1] - addr_bit = [] - for i in range(6): - addr_bit = self.get_bit(Channel.MOSI) - self.address |= addr_bit[0] - self.address <<= 1 - self.address >>= 1 - self.put(start_sample, addr_bit[2], self.out_ann, - [Ann.REG_ADDRESS, ['ADDRESS: 0x%02X' % self.address, 'ADDR: 0x%02X' - % self.address, '0x%02X' % self.address]]) - self.ss = -1 - self.state = St.DATA - - elif self.state == St.DATA: - self.reg.extend(self.mosi if self.operation == Operation.WRITE else self.miso) - - self.mosi, self.miso = [], [] - if self.ss == -1: - self.ss, self.es = self.reg[0][1], es - self.samples_per_bit = self.reg[0][2] - self.ss - - if len(self.reg) < 8: - return - else: - reg_value = 0 - reg_bit = [] - for offset in range(7, -1, -1): - reg_bit = self.reg.pop(0) - - mask = reg_bit[0] << offset - reg_value |= mask - - if self.address < 0x00 or self.address > 0x39: - return - - if self.address in [0x32, 0x34, 0x36]: - self.start_index = self.ss - - if 0x1D > self.address >= 0x00: - self.put(self.ss, reg_bit[2], self.out_ann, [Ann.REG_ADDRESS, [str(self.address)]]) - self.put(self.ss, reg_bit[2], self.out_ann, [Ann.REG_DATA, [str(reg_value)]]) - else: - self.put(self.ss, reg_bit[2], self.out_ann, [Ann.REG_ADDRESS, registers[self.address]]) - handle_reg = getattr(self, 'handle_reg_0x%02x' % self.address) - handle_reg(reg_value) - - self.reg = [] - self.address += 1 - self.ss = -1 diff --git a/decoders/am230x/__init__.py b/decoders/am230x/__init__.py deleted file mode 100755 index 280c8856..00000000 --- a/decoders/am230x/__init__.py +++ /dev/null @@ -1,36 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Johannes Roemer -## -## 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, see . -## - -''' -This decoder handles the proprietary single wire communication protocol used -by the Aosong AM230x/DHTxx/RHTxx series of digital humidity and temperature -sensors. - -Sample rate: -A sample rate of at least 200kHz is recommended to properly detect all the -elements of the protocol. - -Options: -The AM230x and DHTxx/RHTxx digital humidity and temperature sensors use the -same single-wire protocol with different encoding of the measured values. -Therefore the option 'device' must be used to properly decode the -communication of the respective sensor. -''' - -from .pd import Decoder diff --git a/decoders/am230x/pd.py b/decoders/am230x/pd.py deleted file mode 100755 index fbc68d39..00000000 --- a/decoders/am230x/pd.py +++ /dev/null @@ -1,229 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Johannes Roemer -## -## 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, see . -## - -import sigrokdecode as srd - -# Define valid timing values (in microseconds). -timing = { - 'START LOW' : {'min': 750, 'max': 25000}, - 'START HIGH' : {'min': 10, 'max': 10000}, - 'RESPONSE LOW' : {'min': 50, 'max': 90}, - 'RESPONSE HIGH' : {'min': 50, 'max': 90}, - 'BIT LOW' : {'min': 45, 'max': 90}, - 'BIT 0 HIGH' : {'min': 20, 'max': 35}, - 'BIT 1 HIGH' : {'min': 65, 'max': 80}, -} - -class SamplerateError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = 'am230x' - name = 'AM230x' - longname = 'Aosong AM230x/DHTxx/RHTxx' - desc = 'Aosong AM230x/DHTxx/RHTxx humidity/temperature sensor.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['IC', 'Sensor'] - channels = ( - {'id': 'sda', 'name': 'SDA', 'desc': 'Single wire serial data line'}, - ) - options = ( - {'id': 'device', 'desc': 'Device type', - 'default': 'am230x', 'values': ('am230x/rht', 'dht11')}, - ) - annotations = ( - ('start', 'Start'), - ('response', 'Response'), - ('bit', 'Bit'), - ('end', 'End'), - ('byte', 'Byte'), - ('humidity', 'Relative humidity in percent'), - ('temperature', 'Temperature in degrees Celsius'), - ('checksum', 'Checksum'), - ) - annotation_rows = ( - ('bits', 'Bits', (0, 1, 2, 3)), - ('bytes', 'Bytes', (4,)), - ('results', 'Results', (5, 6, 7)), - ) - - def putfs(self, data): - self.put(self.fall, self.samplenum, self.out_ann, data) - - def putb(self, data): - self.put(self.bytepos[-1], self.samplenum, self.out_ann, data) - - def putv(self, data): - self.put(self.bytepos[-2], self.samplenum, self.out_ann, data) - - def reset_variables(self): - self.state = 'WAIT FOR START LOW' - self.fall = 0 - self.rise = 0 - self.bits = [] - self.bytepos = [] - - def is_valid(self, name): - dt = 0 - if name.endswith('LOW'): - dt = self.samplenum - self.fall - elif name.endswith('HIGH'): - dt = self.samplenum - self.rise - if dt >= self.cnt[name]['min'] and dt <= self.cnt[name]['max']: - return True - return False - - def bits2num(self, bitlist): - number = 0 - for i in range(len(bitlist)): - number += bitlist[-1 - i] * 2**i - return number - - def calculate_humidity(self, bitlist): - h = 0 - if self.options['device'] == 'dht11': - h = self.bits2num(bitlist[0:8]) - else: - h = self.bits2num(bitlist) / 10 - return h - - def calculate_temperature(self, bitlist): - t = 0 - if self.options['device'] == 'dht11': - t = self.bits2num(bitlist[0:8]) - else: - t = self.bits2num(bitlist[1:]) / 10 - if bitlist[0] == 1: - t = -t - return t - - def calculate_checksum(self, bitlist): - checksum = 0 - for i in range(8, len(bitlist) + 1, 8): - checksum += self.bits2num(bitlist[i-8:i]) - return checksum % 256 - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.reset_variables() - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def metadata(self, key, value): - if key != srd.SRD_CONF_SAMPLERATE: - return - self.samplerate = value - # Convert microseconds to sample counts. - self.cnt = {} - for e in timing: - self.cnt[e] = {} - for t in timing[e]: - self.cnt[e][t] = timing[e][t] * self.samplerate / 1000000 - - def handle_byte(self, bit): - self.bits.append(bit) - self.putfs([2, ['Bit: %d' % bit, '%d' % bit]]) - self.fall = self.samplenum - self.state = 'WAIT FOR BIT HIGH' - if len(self.bits) % 8 == 0: - byte = self.bits2num(self.bits[-8:]) - self.putb([4, ['Byte: %#04x' % byte, '%#04x' % byte]]) - if len(self.bits) == 16: - h = self.calculate_humidity(self.bits[-16:]) - self.putv([5, ['Humidity: %.1f %%' % h, 'RH = %.1f %%' % h]]) - elif len(self.bits) == 32: - t = self.calculate_temperature(self.bits[-16:]) - self.putv([6, ['Temperature: %.1f °C' % t, 'T = %.1f °C' % t]]) - elif len(self.bits) == 40: - parity = self.bits2num(self.bits[-8:]) - if parity == self.calculate_checksum(self.bits[0:32]): - self.putb([7, ['Checksum: OK', 'OK']]) - else: - self.putb([7, ['Checksum: not OK', 'NOK']]) - self.state = 'WAIT FOR END' - self.bytepos.append(self.samplenum) - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - while True: - # State machine. - if self.state == 'WAIT FOR START LOW': - self.wait({0: 'f'}) - self.fall = self.samplenum - self.state = 'WAIT FOR START HIGH' - elif self.state == 'WAIT FOR START HIGH': - self.wait({0: 'r'}) - if self.is_valid('START LOW'): - self.rise = self.samplenum - self.state = 'WAIT FOR RESPONSE LOW' - else: - self.reset_variables() - elif self.state == 'WAIT FOR RESPONSE LOW': - self.wait({0: 'f'}) - if self.is_valid('START HIGH'): - self.putfs([0, ['Start', 'S']]) - self.fall = self.samplenum - self.state = 'WAIT FOR RESPONSE HIGH' - else: - self.reset_variables() - elif self.state == 'WAIT FOR RESPONSE HIGH': - self.wait({0: 'r'}) - if self.is_valid('RESPONSE LOW'): - self.rise = self.samplenum - self.state = 'WAIT FOR FIRST BIT' - else: - self.reset_variables() - elif self.state == 'WAIT FOR FIRST BIT': - self.wait({0: 'f'}) - if self.is_valid('RESPONSE HIGH'): - self.putfs([1, ['Response', 'R']]) - self.fall = self.samplenum - self.bytepos.append(self.samplenum) - self.state = 'WAIT FOR BIT HIGH' - else: - self.reset_variables() - elif self.state == 'WAIT FOR BIT HIGH': - self.wait({0: 'r'}) - if self.is_valid('BIT LOW'): - self.rise = self.samplenum - self.state = 'WAIT FOR BIT LOW' - else: - self.reset_variables() - elif self.state == 'WAIT FOR BIT LOW': - self.wait({0: 'f'}) - if self.is_valid('BIT 0 HIGH'): - bit = 0 - elif self.is_valid('BIT 1 HIGH'): - bit = 1 - else: - self.reset_variables() - continue - self.handle_byte(bit) - elif self.state == 'WAIT FOR END': - self.wait({0: 'r'}) - self.putfs([3, ['End', 'E']]) - self.reset_variables() diff --git a/decoders/amulet_ascii/__init__.py b/decoders/amulet_ascii/__init__.py deleted file mode 100644 index 7d2c8c35..00000000 --- a/decoders/amulet_ascii/__init__.py +++ /dev/null @@ -1,28 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Vesa-Pekka Palmu -## -## 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, see . -## - -''' -This decoder stacks on top of the 'uart' PD and decodes the ASCII protocol -for Amulet LCD display controllers. - -Currently the decoder treats both RX and TX the same way, decoding all -message types. -''' - -from .pd import Decoder diff --git a/decoders/amulet_ascii/lists.py b/decoders/amulet_ascii/lists.py deleted file mode 100644 index 92e27a95..00000000 --- a/decoders/amulet_ascii/lists.py +++ /dev/null @@ -1,73 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Vesa-Pekka Palmu -## -## 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, see . -## - -from collections import OrderedDict - -# OrderedDict which maps command IDs to their names and descriptions. -cmds = OrderedDict([ - (0xA0, ('PAGE', 'Jump to page')), - (0xD0, ('GBV', 'Get byte variable')), - (0xD1, ('GWV', 'Get word variable')), - (0xD2, ('GSV', 'Get string variable')), - (0xD3, ('GLV', 'Get label variable')), - (0xD4, ('GRPC', 'Get RPC buffer')), - (0xD5, ('SBV', 'Set byte variable')), - (0xD6, ('SWV', 'Set word variable')), - (0xD7, ('SSV', 'Set string variable')), - (0xD8, ('RPC', 'Invoke RPC')), - (0xD9, ('LINE', 'Draw line')), - (0xDA, ('RECT', 'Draw rectangle')), - (0xDB, ('FRECT', 'Draw filled rectangle')), - (0xDC, ('PIXEL', 'Draw pixel')), - (0xDD, ('GBVA', 'Get byte variable array')), - (0xDE, ('GWVA', 'Get word variable array')), - (0xDF, ('SBVA', 'Set byte variable array')), - (0xE0, ('GBVR', 'Get byte variable reply')), - (0xE1, ('GWVR', 'Get word variable reply')), - (0xE2, ('GSVR', 'Get string variable reply')), - (0xE3, ('GLVR', 'Get label variable reply')), - (0xE4, ('GRPCR', 'Get RPC buffer reply')), - (0xE5, ('SBVR', 'Set byte variable reply')), - (0xE6, ('SWVR', 'Set word variable reply')), - (0xE7, ('SSVR', 'Set string variable reply')), - (0xE8, ('RPCR', 'Invoke RPC reply')), - (0xE9, ('LINER', 'Draw line reply')), - (0xEA, ('RECTR', 'Draw rectangle')), - (0xEB, ('FRECTR', 'Draw filled rectangle reply')), - (0xEC, ('PIXELR', 'Draw pixel reply')), - (0xED, ('GBVAR', 'Get byte variable array reply')), - (0xEE, ('GWVAR', 'Get word variable array reply')), - (0xEF, ('SBVAR', 'Set byte variable array reply')), - (0xF0, ('ACK', 'Acknowledgment')), - (0xF1, ('NACK', 'Negative acknowledgment')), - (0xF2, ('SWVA', 'Set word variable array')), - (0xF3, ('SWVAR', 'Set word variable array reply')), - (0xF4, ('GCV', 'Get color variable')), - (0xF5, ('GCVR', 'Get color variable reply')), - (0xF6, ('SCV', 'Set color variable')), - (0xF7, ('SCVR', 'Set color variable reply')), -]) - -cmds_with_high_bytes = [ - 0xA0, # PAGE - Page change - 0xD7, # SVV - Set string variable - 0xE7, # SVVR - Set string variable reply - 0xE2, # GSVR - Get string variable reply - 0xE3, # GLVR - Get label variable reply -] diff --git a/decoders/amulet_ascii/pd.py b/decoders/amulet_ascii/pd.py deleted file mode 100644 index 71953234..00000000 --- a/decoders/amulet_ascii/pd.py +++ /dev/null @@ -1,699 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Vesa-Pekka Palmu -## -## 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 . -## - -import sigrokdecode as srd -from math import ceil -from common.srdhelper import SrdIntEnum -from .lists import * - -L = len(cmds) -RX = 0 -TX = 1 - -Ann = SrdIntEnum.from_list('Ann', - [c[0] for c in cmds.values()] + ['BIT', 'FIELD', 'WARN']) - -def cmd_annotation_classes(): - return tuple([tuple([cmd[0].lower(), cmd[1]]) for cmd in cmds.values()]) - -class Decoder(srd.Decoder): - api_version = 3 - id = 'amulet_ascii' - name = 'Amulet ASCII' - longname = 'Amulet LCD ASCII' - desc = 'Amulet Technologies LCD controller ASCII protocol.' - license = 'gplv3+' - inputs = ['uart'] - outputs = [] - tags = ['Display'] - annotations = cmd_annotation_classes() + ( - ('bit', 'Bit'), - ('field', 'Field'), - ('warning', 'Warning'), - ) - annotation_rows = ( - ('bits', 'Bits', (L + 0,)), - ('fields', 'Fields', (L + 1,)), - ('commands', 'Commands', tuple(range(L))), - ('warnings', 'Warnings', (L + 2,)), - ) - options = ( - {'id': 'ms_chan', 'desc': 'Master -> slave channel', - 'default': 'RX', 'values': ('RX', 'TX')}, - {'id': 'sm_chan', 'desc': 'Slave -> master channel', - 'default': 'TX', 'values': ('RX', 'TX')}, - ) - - def __init__(self): - self.reset() - - def reset(self): - self.state = None - self.cmdstate = None - - # Build dict mapping command keys to handler functions. Each - # command in 'cmds' (defined in lists.py) has a matching - # handler self.handle_. - def get_handler(cmd): - s = 'handle_%s' % cmds[cmd][0].lower().replace('/', '_') - return getattr(self, s) - self.cmd_handlers = dict((cmd, get_handler(cmd)) for cmd in cmds.keys()) - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putx(self, data): - # Simplification, most annotations span exactly one SPI byte/packet. - self.put(self.ss, self.es, self.out_ann, data) - - def putf(self, data): - self.put(self.ss_field, self.es_field, self.out_ann, data) - - def putc(self, data): - self.put(self.ss_cmd, self.es_cmd, self.out_ann, data) - - def cmd_ann_list(self): - x, s = cmds[self.state][0], cmds[self.state][1] - return ['Command: %s (%s)' % (s, x), 'Command: %s' % s, - 'Cmd: %s' % s, 'Cmd: %s' % x, x] - - def emit_cmd_byte(self): - self.ss_cmd = self.ss - self.putx([Ann.FIELD, self.cmd_ann_list()]) - - def emit_addr_bytes(self, pdata): - if self.cmdstate == 2: - self.ss_field = self.ss - self.addr = chr(pdata) - self.putx([Ann.BIT, ['Address high nibble: %c' % pdata, - 'Addr high 0x%c' % pdata, 'Addr h 0x%c' % pdata]]) - elif self.cmdstate == 3: - self.es_field = self.es - self.addr += chr(pdata) - self.addr = int(self.addr, 16) - self.putx([Ann.BIT, ['Address low nibble: %c' % pdata, - 'Addr low 0x%c' % pdata, 'Addr l 0x%c' % pdata]]) - self.putf([Ann.FIELD, ['Address: 0x%02X' % self.addr, - 'Addr: 0x%02X' % self.addr, '0x%02X' % self.addr]]) - - def emit_cmd_end(self, data): - self.es_cmd = self.es - self.putc(data) - self.state = None - - def handle_read(self, data): - if self.cmdstate == 1: - self.emit_cmd_byte() - self.addr = 0 - elif self.cmdstate == 2: - self.emit_addr_bytes(pdata) - elif self.cmdstate == 3: - self.emit_addr_bytes(pdata) - self.cmdstate += 1 - - def handle_set_common(self, pdata): - if self.cmdstate == 1: - self.addr = 0 - self.emit_addr_bytes(pdata) - - def emit_not_implemented(self, data): - self.es_cmd = self.es - self.putc([Ann.WARN, ['Command not decoded', 'Not decoded']]) - self.emit_cmd_end(data) - - def handle_string(self, pdata, ann_class): - # TODO: unicode / string modifiers... - self.handle_set_common(pdata) - if self.cmdstate == 4: - self.ss_field = self.ss - self.value = '' - if pdata == 0x00: - # Null terminated string ends. - self.es_field = self.es - self.putx([Ann.BIT, ['NULL']]) - self.putf([Ann.FIELD, ['Value: %s' % self.value, - 'Val: %s' % self.value, '%s' % self.value]]) - self.emit_cmd_end([ann_class, self.cmd_ann_list()]) - return - if self.cmdstate > 3: - self.value += chr(pdata) - self.putx([Ann.BIT, ['%c' % pdata]]) - self.cmdstate += 1 - - # Command handlers - - # Page change 0xA0, 0x02, index_high, index_low, checksum - def handle_page(self, pdata): - if self.cmdstate == 2: - if pdata == 0x02: - self.ss_field = self.ss_cmd - self.es_field = self.es - self.putf([Ann.FIELD, self.cmd_ann_list()]) - self.checksum = 0xA0 + 0x02 - else: - self.putx([Ann.WARN, ['Illegal second byte for page change', - 'Illegal byte']]) - self.state = None - elif self.cmdstate == 3: - self.ss_field = self.ss - self.checksum += pdata - self.page[0] = pdata - elif self.cmdstate == 4: - self.checksum += pdata - self.page[1] = pdata - self.es_field = self.es - if self.page[0] == self.page [1] == 0xFF: - # Soft reset trigger - self.putf(Ann.WARN, ['Soft reset', 'Reset']) - else: - page = chr(self.page[0]) + chr(self.page[1]) - self.putf(Ann.FIELD, ['Page index: 0x%s' % page, - 'Page: 0x%s' % page, '0x%s' % page]) - elif self.cmdstate == 5: - self.checksum += pdata - if (self.checksum & 0xFF) != 0: - self.putx([Ann.WARN, ['Checksum error', 'Error', 'ERR']]) - else: - self.putx([Ann.FIELD, ['Checksum OK', 'OK']]) - self.emit_cmd_end(Ann.PAGE) - self.cmdstate += 1 - - # Value reads: command byte, address high nibble, address low nibble - - # Get byte value - def handle_gbv(self, pdata): - self.handle_read(pdata) - self.emit_cmd_end([Ann.GBV, self.cmd_ann_list()]) - - # Get word value - def handle_gwv(self, pdata): - self.handle_read(pdata) - self.emit_cmd_end([Ann.GWV, self.cmd_ann_list()]) - - # Get string value - def handle_gsv(self, pdata): - self.handle_read(pdata) - self.emit_cmd_end([Ann.GSV, self.cmd_ann_list()]) - - # Get label value - def handle_glv(self, pdata): - self.handle_read(pdata) - self.emit_cmd_end([Ann.GLV, self.cmd_ann_list()]) - - # Get RPC buffer - def handle_grpc(self, pdata): - if self.cmdstate == 2: - self.ss_field = self.ss - self.flags = int(chr(pdata), 16) << 4 - elif self.cmdstate == 3: - self.flags += int(chr(pdata), 16) - self.es_field = self.es - self.putf([Ann.FIELD, ['RPC flag: 0x%02X' % self.flags]]) - self.emit_cmd_end([Ann.GRPC, self.cmd_ann_list()]) - - # Get byte value array - def handle_gbva(self, pdata): - self.handle_read(pdata) - self.emit_cmd_end([Ann.GBVA, self.cmd_ann_list()]) - - # Get word value array - def handle_gwva(self, pdata): - self.handle_read(pdata) - self.emit_cmd_end([Ann.GWVA, self.cmd_ann_list()]) - - # Get color variable - def handle_gcv(self, pdata): - self.handle_read(pdata) - self.emit_cmd_end([Ann.GCV, self.cmd_ann_list()]) - - # Value setters: command byte, address high nibble, address low nibble, data bytes - - # Set byte value data = high nibble, low nibble - def handle_sbv(self, pdata): - self.handle_set_common(pdata) - if self.cmdstate == 4: - self.ss_field = self.ss - self.value = chr(pdata) - elif self.cmdstate == 5: - self.value += chr(pdata) - self.es_field = self.es - self.putf([Ann.FIELD, ['Value: 0x%s' % self.value, - 'Val: 0x%s' % self.value, '0x%s' % self.value]]) - self.emit_cmd_end([Ann.SBV, self.cmd_ann_list()]) - self.cmdstate += 1 - - # Set word value, msb high, msb low, lsb high, lsb low - def handle_swv(self, pdata): - self.handle_set_common(pdata) - if self.cmdstate > 3: - nibble = self.cmdstate - 4 - if nibble == 0: - self.ss_field = self.ss - self.value = 0 - self.value += int(chr(pdata), 16) << 12 - (4 * nibble) - if nibble == 3: - self.es_field = self.es - self.putf([Ann.FIELD, ['Value: 0x%04x' % self.value, - 'Val: 0x%04x' % self.value, '0x%04x' % self.value]]) - self.emit_cmd_end([Ann.SWV, self.cmd_ann_list()]) - return - self.cmdstate += 1 - - # Set string value, null terminated utf8 strings - def handle_ssv(self, pdata): - self.handle_string(pdata, Ann.SSV) - - # Set byte value array - def handle_sbva(self, pdata): - nibble = (self.cmdstate - 3) % 2 - if self.cmdstate == 2: - self.addr = int(chr(pdata), 16) << 4 - self.ss_field = self.ss - self.putx([Ann.BIT, ['Address high nibble: %c' % pdata, - 'Addr high 0x%c' % pdata, '0x%c' % pdata]]) - elif self.cmdstate == 3: - self.addr += int(chr(pdata), 16) - self.es_field = self.ss - self.putx([Ann.BIT, ['Address low nibble: %c' % pdata, - 'Addr low 0x%c' % pdata, '0x%c' % pdata]]) - self.putf([Ann.FIELD, ['Address: 0x%02X' % self.addr, - 'Addr: 0x%02X' % self.addr, '0x%02X' % self.addr]]) - elif stage == 2: - if pdata == 0x00: - # Null terminated list - self.emit_cmd_end([Ann.SBVA, self.cmd_ann_list()]) - return - self.value = int(chr(pdata), 16) << 4 - else: - self.value += int(chr(pdata), 16) - self.es_field = self.es - self.putf([Ann.FIELD, ['Value 0x%02X' % self.value, - '0x%02X' % self.value]]) - self.cmdstate += 1 - - # Set word value array - def handle_swva(self, pdata): - nibble = (self.cmdstate - 3) % 4 - if self.cmdstate == 2: - self.addr = int(chr(pdata), 16) << 4 - self.ss_field = self.ss - self.putx([Ann.BIT, ['Address high nibble: %c' % pdata, - 'Addr high 0x%c' % pdata, '0x%c' % pdata]]) - elif self.cmdstate == 3: - self.addr += int(chr(pdata), 16) - self.es_field = self.ss - self.putx([Ann.BIT, ['Address low nibble: %c' % pdata, - 'Addr low 0x%c' % pdata, '0x%c' % pdata]]) - self.putf([Ann.FIELD, ['Address: 0x%02X' % self.addr, - 'Addr: 0x%02X' % self.addr, '0x%02X' % self.addr]]) - self.value = 0 - else: - self.value += int(chr(pdata), 16) << 12 - (4 * nibble) - if nibble == 0: - if pdata == 0x00: - # Null terminated list - self.emit_cmd_end([Ann.SWVA, self.cmd_ann_list()]) - return - self.ss_field = self.ss - if nibble == 3: - self.es_field = self.es - self.putf([Ann.FIELD, ['Value 0x%04X' % self.value, - '0x%04X' % self.value]]) - self.cmdstate += 1 - - # Set color variable - def handle_scv(self, pdata): - if self.cmdstate == 8: - self.emit_not_implemented([Ann.SCV, self.cmd_ann_list()]) - self.cmdstate += 1 - - # RPC trigger - def handle_rpc(self, pdata): - self.handle_read(pdata) - self.emit_cmd_end([Ann.RPC, self.cmd_ann_list()]) - - # Drawing - - # Decode pair of (x,y) 16bit coordinates - def decode_coords(self, pdata): - if self.cmdstate == 1: - self.coords[0] = 0 - self.coords[1] = 0 - self.coords[2] = 0 - self.coords[3] = 0 - if self.cmdstate < 18: - # Coordinates - nibble = (self.cmdstate - 1) % 4 - i = (self.cmdstate - 1) / 4 - self.coords[i] += int(chr(pdata), 16) << 12 - (4 * nibble) - if nibble == 0: - self.ss_field = self.ss - elif nibble == 3: - self.es_field = self.es - self.putf([Ann.FIELD, ['Coordinate 0x%04X' % self.coords[i]], - ['0x%04X' % self.coords[i]]]) - - # TODO: There are actually two protocol revisions for drawing. - # Both use 4 bytes for 16bit x and y pairs for start and end. - # The older follows this by a pattern selector and then line weight. - # Newer version has 6 bytes for 8bit RGB color... - - # Draw line - def handle_line(self, pdata): - decode_coords(pdata) - if self.cmdstate == 18: - self.es_cmd = self.es - self.putc([Ann.LINE, self.cmd_ann_list()]) - self.putc([Ann.WARN, ['Line pattern / Color not implemented']]) - self.state = None - self.cmdstate += 1 - - # Draw rectange - def handle_rect(self, pdata): - decode_coords(pdata) - if self.cmdstate == 18: - self.es_cmd = self.es - self.putc([Ann.RECT, self.cmd_ann_list()]) - self.putc([Ann.WARN, ['Line pattern / Color not implemented']]) - self.state = None - self.cmdstate += 1 - - # Draw filled rectangle - def handle_frect(self, pdata): - decode_coords(pdata) - if self.cmdstate == 18: - self.es_cmd = self.es - self.putc([Ann.FRECT, self.cmd_ann_list()]) - self.putc([Ann.WARN, ['Fill pattern / Color not implemented']]) - self.state = None - self.cmdstate += 1 - - # Draw pixel - def handle_pixel(self, pdata): - self.es_cmd = self.es - self.putc([Ann.WARN, ['Draw pixel documentation is missing.', 'Undocumented']]) - self.state = None - - # Replies - def handle_gbvr(self, pdata): - self.emit_add_bytes(pdata) - if self.cmdstate == 4: - self.ss_field = self.ss - self.value = int(chr(pdata), 16) << 4 - self.putx([Ann.BIT, ['High nibble 0x%s' % pdata, '0x%s' % pdata]]) - elif self.cmdstate == 5: - self.value += int(chr(pdata), 16) - self.putx([Ann.BIT, ['Low nibble 0x%s' % pdata, '0x%s' % pdata]]) - self.es_field = self.es - self.putf([Ann.FIELD, ['Value: 0x%02X' % self.value, - '0x%02X' % self.value]]) - self.emit_cmd_end([Ann.GBVR, self.cmd_ann_list()]) - self.cmdstate += 1 - - def handle_gwvr(self, pdata): - self.emit_add_bytes(pdata) - if self.cmdstate > 3: - nibble = self.cmdstate - 3 - if nibble == 0: - self.value = 0 - self.ss_field = self.ss - self.value += int(chr(pdata), 16) << 12 - (4 * nibble) - self.putx([Ann.BIT, ['0x%s' % pdata]]) - if nibble == 3: - self.putf([Ann.FIELD, ['Value: 0x%04x' % self.value, - '0x%04X' % self.value]]) - self.es_cmd = self.ss - self.emit_cmd_end([Ann.GWVR, self.cmd_ann_list()]) - self.cmdstate += 1 - - def handle_gsvr(self, pdata): - self.handle_string(pdata, Ann.GSVR) - - def handle_glvr(self, pdata): - self.handle_string(pdata, Ann.GLVR) - - def handle_grpcr(self, pdata): - self.handle_addr(pdata) - if self.cmdstate > 3: - nibble = (self.cmdstate - 3) % 2 - if nibble == 0: - if pdata == 0x00: - self.emit_cmd_end([Ann.GRPCR, self.cmd_ann_list()]) - return - self.value = int(chr(pdata), 16) << 4 - self.ss_field = self.ss - self.putx([Ann.BIT, ['0x%s' % pdata]]) - if nibble == 2: - self.value += int(chr(pdata), 16) - self.es_field = self.es - self.putx([Ann.BIT, ['0x%s' % pdata]]) - self.putf([Ann.FIELD, ['0x%02X' % self.value]]) - self.cmdstate += 1 - - def handle_sbvr(self, pdata): - self.handle_set_common(pdata) - if self.cmdstate == 4: - self.ss_field = self.ss - self.value = chr(pdata) - elif self.cmdstate == 5: - self.value += chr(pdata) - self.es_field = self.es - self.putf([Ann.FIELD, ['Value: 0x%s' % self.value, - 'Val: 0x%s' % self.value, '0x%s' % self.value]]) - self.emit_cmd_end([Ann.SBVR, self.cmd_ann_list()]) - self.cmdstate += 1 - - def handle_swvr(self, pdata): - self.handle_set_common(pdata) - if self.cmdstate == 4: - self.ss_field = self.ss - self.value = (pdata - 0x30) << 4 - elif self.cmdstate == 5: - self.value += (pdata - 0x30) - self.value = self.value << 8 - elif self.cmdstate == 6: - self.value += (pdata - 0x30) << 4 - elif self.cmdstate == 7: - self.value += (pdata - 0x30) - self.es_field = self.es - self.putf([Ann.FIELD, ['Value: 0x%04x' % self.value, - 'Val: 0x%04x' % self.value, '0x%04x' % self.value]]) - self.emit_cmd_end([Ann.SWVR, self.cmd_ann_list()]) - self.state = None - self.cmdstate += 1 - - def handle_ssvr(self, pdata): - self.handle_string(pdata, Ann.SSVR) - - def handle_rpcr(self, pdata): - self.handle_read(pdata) - self.emit_cmd_end([Ann.RPCR, self.cmd_ann_list()]) - - def handle_liner(self, pdata): - decode_coords(pdata) - if self.cmdstate == 18: - self.es_cmd = self.es - self.putc([Ann.LINER, self.cmd_ann_list()]) - self.putc([Ann.WARN, ['Line pattern / Color not implemented']]) - self.state = None - self.cmdstate += 1 - - def handle_rectr(self, pdata): - decode_coords(pdata) - if self.cmdstate == 18: - self.es_cmd = self.es - self.putc([Ann.RECTR, self.cmd_ann_list()]) - self.putc([Ann.WARN, ['Line pattern / Color not implemented']]) - self.state = None - self.cmdstate += 1 - - def handle_frectr(self, pdata): - decode_coords(pdata) - if self.cmdstate == 18: - self.es_cmd = self.es - self.putc([Ann.FRECTR, self.cmd_ann_list()]) - self.putc([Ann.WARN, ['Line pattern / Color not implemented']]) - self.state = None - self.cmdstate += 1 - - def handle_pixelr(self, pdata): - self.es_cmd = self.es - self.putc([Ann.WARN,['Draw pixel documentation is missing.', 'Undocumented']]) - self.state = None - - def handle_gbvar(self, pdata): - nibble = (self.cmdstate - 3) % 2 - if self.cmdstate == 2: - self.addr = int(chr(pdata), 16) << 4 - self.ss_field = self.ss - self.putx([Ann.BIT, ['Address high nibble: %c' % pdata, - 'Addr high 0x%c' % pdata, '0x%c' % pdata]]) - elif self.cmdstate == 3: - self.addr += int(chr(pdata), 16) - self.es_field = self.ss - self.putx([Ann.BIT, ['Address low nibble: %c' % pdata, - 'Addr low 0x%c' % pdata, '0x%c' % pdata]]) - self.putf([Ann.FIELD, ['Address: 0x%02X' % self.addr, - 'Addr: 0x%02X' % self.addr, '0x%02X' % self.addr]]) - elif stage == 2: - if pdata == 0x00: - # Null terminated list - self.emit_cmd_end([Ann.GBVAR, self.cmd_ann_list()]) - return - self.value = int(chr(pdata), 16) << 4 - else: - self.value += int(chr(pdata), 16) - self.es_field = self.es - self.putf([Ann.FIELD, ['Value 0x%02X' % self.value, - '0x%02X' % self.value]]) - self.cmdstate += 1 - - def handle_gwvar(self, pdata): - nibble = (self.cmdstate - 3) % 4 - if self.cmdstate == 2: - self.addr = int(chr(pdata), 16) << 4 - self.ss_field = self.ss - self.putx([Ann.BIT, ['Address high nibble: %c' % pdata, - 'Addr high 0x%c' % pdata, '0x%c' % pdata]]) - elif self.cmdstate == 3: - self.addr += int(chr(pdata), 16) - self.es_field = self.ss - self.putx([Ann.BIT, ['Address low nibble: %c' % pdata, - 'Addr low 0x%c' % pdata, '0x%c' % pdata]]) - self.putf([Ann.FIELD, ['Address: 0x%02X' % self.addr, - 'Addr: 0x%02X' % self.addr, '0x%02X' % self.addr]]) - self.value = 0 - else: - self.value += int(chr(pdata), 16) << 12 - (4 * nibble) - if nibble == 0: - if pdata == 0x00: - # Null terminated list - self.emit_cmd_end([Ann.GWVAR, self.cmd_ann_list()]) - return - self.ss_field = self.ss - if nibble == 3: - self.es_field = self.es - self.putf([Ann.FIELD, ['Value 0x%04X' % self.value, - '0x%04X' % self.value]]) - self.cmdstate += 1 - - # Get byte variable array reply - def handle_sbvar(self, pdata): - nibble = (self.cmdstate - 3) % 2 - if self.cmdstate == 2: - self.addr = int(chr(pdata), 16) << 4 - self.ss_field = self.ss - self.putx([Ann.BIT, ['Address high nibble: %c' % pdata, - 'Addr high 0x%c' % pdata, '0x%c' % pdata]]) - elif self.cmdstate == 3: - self.addr += int(chr(pdata), 16) - self.es_field = self.ss - self.putx([Ann.BIT, ['Address low nibble: %c' % pdata, - 'Addr low 0x%c' % pdata, '0x%c' % pdata]]) - self.putf([Ann.FIELD, ['Address: 0x%02X' % self.addr, - 'Addr: 0x%02X' % self.addr, '0x%02X' % self.addr]]) - elif stage == 2: - if pdata == 0x00: - # Null terminated list - self.emit_cmd_end([Ann.SBVAR, self.cmd_ann_list()]) - return - self.value = int(chr(pdata), 16) << 4 - else: - self.value += int(chr(pdata), 16) - self.es_field = self.es - self.putf([Ann.FIELD, ['Value 0x%02X' % self.value, - '0x%02X' % self.value]]) - self.cmdstate += 1 - - # Set word variable array reply - def handle_swvar(self, pdata): - nibble = (self.cmdstate - 3) % 4 - if self.cmdstate == 2: - self.addr = int(chr(pdata), 16) << 4 - self.ss_field = self.ss - self.putx([Ann.BIT, ['Address high nibble: %c' % pdata, - 'Addr high 0x%c' % pdata, '0x%c' % pdata]]) - elif self.cmdstate == 3: - self.addr += int(chr(pdata), 16) - self.es_field = self.ss - self.putx([Ann.BIT, ['Address low nibble: %c' % pdata, - 'Addr low 0x%c' % pdata, '0x%c' % pdata]]) - self.putf([Ann.FIELD, ['Address: 0x%02X' % self.addr, - 'Addr: 0x%02X' % self.addr, '0x%02X' % self.addr]]) - self.value = 0 - else: - self.value += int(chr(pdata), 16) << 12 - (4 * nibble) - if nibble == 0: - if pdata == 0x00: - # Null terminated list - self.emit_cmd_end([Ann.SWVAR, self.cmd_ann_list()]) - return - self.ss_field = self.ss - if nibble == 3: - self.es_field = self.es - self.putf([Ann.FIELD, ['Value 0x%04X' % self.value, - '0x%04X' % self.value]]) - self.cmdstate += 1 - - def handle_gcvr(self, pdata): - if self.cmdstate == 8: - self.emit_not_implemented([Ann.SCV, self.cmd_ann_list()]) - self.cmdstate += 1 - - def handle_scvr(self, pdata): - if self.cmdstate == 8: - self.emit_not_implemented([Ann.SCV, self.cmd_ann_list()]) - self.cmdstate += 1 - - # ACK & NACK - - def handle_ack(self, pdata): - self.putx([Ann.ACK, self.cmd_ann_list()]) - self.state = None - - def handle_nack(self, pdata): - self.putx([Ann.NACK, self.cmd_ann_list()]) - self.state = None - - def decode(self, ss, es, data): - ptype, rxtx, pdata = data - - self.ss, self.es = ss, es - - if ptype != 'DATA': - return - - # Handle commands. - try: - abort_current = (0xD0 <= pdata[0] <= 0xF7) and \ - (not (self.state in cmds_with_high_bytes)) and \ - self.state != None - if abort_current: - self.putx([Ann.WARN, ['Command aborted by invalid byte', 'Abort']]) - self.state = pdata[0] - self.emit_cmd_byte() - self.cmdstate = 1 - if self.state is None: - self.state = pdata[0] - self.emit_cmd_byte() - self.cmdstate = 1 - self.cmd_handlers[self.state](pdata[0]) - except KeyError: - self.putx([Ann.WARN, ['Unknown command: 0x%02x' % pdata[0]]]) - self.state = None diff --git a/decoders/arm_etmv3/__init__.py b/decoders/arm_etmv3/__init__.py deleted file mode 100755 index 617063ca..00000000 --- a/decoders/arm_etmv3/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Petteri Aimonen -## -## 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, see . -## - -''' -This decoder stacks on top of the 'uart' PD and decodes packets of -the ARMv7m Embedded Trace Macroblock v3.x. -''' - -from .pd import Decoder diff --git a/decoders/arm_etmv3/pd.py b/decoders/arm_etmv3/pd.py deleted file mode 100755 index 6649b46e..00000000 --- a/decoders/arm_etmv3/pd.py +++ /dev/null @@ -1,567 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Petteri Aimonen -## -## 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, see . -## - -import sigrokdecode as srd -import subprocess -import re - -# See ETMv3 Signal Protocol table 7-11: 'Encoding of Exception[8:0]'. -exc_names = [ - 'No exception', 'IRQ1', 'IRQ2', 'IRQ3', 'IRQ4', 'IRQ5', 'IRQ6', 'IRQ7', - 'IRQ0', 'UsageFault', 'NMI', 'SVC', 'DebugMon', 'MemManage', 'PendSV', - 'SysTick', 'Reserved', 'Reset', 'BusFault', 'Reserved', 'Reserved' -] - -for i in range(8, 496): - exc_names.append('IRQ%d' % i) - -def parse_varint(bytes_): - '''Parse an integer where the top bit is the continuation bit. - Returns value and number of parsed bytes.''' - v = 0 - for i, b in enumerate(bytes_): - v |= (b & 0x7F) << (i * 7) - if b & 0x80 == 0: - return v, i+1 - return v, len(bytes_) - -def parse_uint(bytes_): - '''Parse little-endian integer.''' - v = 0 - for i, b in enumerate(bytes_): - v |= b << (i * 8) - return v - -def parse_exc_info(bytes_): - '''Parse exception information bytes from a branch packet.''' - if len(bytes_) < 1: - return None - - excv, exclen = parse_varint(bytes_) - if bytes_[exclen - 1] & 0x80 != 0x00: - return None # Exception info not complete. - - if exclen == 2 and excv & (1 << 13): - # Exception byte 1 was skipped, fix up the decoding. - excv = (excv & 0x7F) | ((excv & 0x3F80) << 7) - - ns = excv & 1 - exc = ((excv >> 1) & 0x0F) | ((excv >> 7) & 0x1F0) - cancel = (excv >> 5) & 1 - altisa = (excv >> 6) & 1 - hyp = (excv >> 12) & 1 - resume = (excv >> 14) & 0x0F - return (ns, exc, cancel, altisa, hyp, resume) - -def parse_branch_addr(bytes_, ref_addr, cpu_state, branch_enc): - '''Parse encoded branch address. - Returns addr, addrlen, cpu_state, exc_info. - Returns None if packet is not yet complete''' - - addr, addrlen = parse_varint(bytes_) - - if bytes_[addrlen - 1] & 0x80 != 0x00: - return None # Branch address not complete. - - addr_bits = 7 * addrlen - - have_exc_info = False - if branch_enc == 'original': - if addrlen == 5 and bytes_[4] & 0x40: - have_exc_info = True - elif branch_enc == 'alternative': - addr_bits -= 1 # Top bit of address indicates exc_info. - if addrlen >= 2 and addr & (1 << addr_bits): - have_exc_info = True - addr &= ~(1 << addr_bits) - - exc_info = None - if have_exc_info: - exc_info = parse_exc_info(bytes_[addrlen:]) - if exc_info is None: - return None # Exception info not complete. - - if addrlen == 5: - # Possible change in CPU state. - if bytes_[4] & 0xB8 == 0x08: - cpu_state = 'arm' - elif bytes_[4] & 0xB0 == 0x10: - cpu_state = 'thumb' - elif bytes_[4] & 0xA0 == 0x20: - cpu_state = 'jazelle' - else: - raise NotImplementedError('Unhandled branch byte 4: 0x%02x' % bytes_[4]) - - # Shift the address according to current CPU state. - if cpu_state == 'arm': - addr = (addr & 0xFFFFFFFE) << 1 - addr_bits += 1 - elif cpu_state == 'thumb': - addr = addr & 0xFFFFFFFE - elif cpu_state == 'jazelle': - addr = (addr & 0xFFFFFFFFE) >> 1 - addr_bits -= 1 - else: - raise NotImplementedError('Unhandled state: ' + cpu_state) - - # If the address wasn't full, fill in with the previous address. - if addrlen < 5: - addr |= ref_addr & (0xFFFFFFFF << addr_bits) - - return addr, addrlen, cpu_state, exc_info - -class Decoder(srd.Decoder): - api_version = 3 - id = 'arm_etmv3' - name = 'ARM ETMv3' - longname = 'ARM Embedded Trace Macroblock v3' - desc = 'ARM ETM v3 instruction trace protocol.' - license = 'gplv2+' - inputs = ['uart'] - outputs = [] - tags = ['Debug/trace'] - annotations = ( - ('trace', 'Trace info'), - ('branch', 'Branches'), - ('exception', 'Exceptions'), - ('execution', 'Instruction execution'), - ('data', 'Data access'), - ('pc', 'Program counter'), - ('instr_e', 'Executed instructions'), - ('instr_n', 'Not executed instructions'), - ('source', 'Source code'), - ('location', 'Current location'), - ('function', 'Current function'), - ) - annotation_rows = ( - ('trace', 'Trace info', (0,)), - ('flow', 'Code flow', (1, 2, 3,)), - ('data', 'Data access', (4,)), - ('pc', 'Program counter', (5,)), - ('instruction', 'Instructions', (6, 7,)), - ('source', 'Source code', (8,)), - ('location', 'Current location', (9,)), - ('function', 'Current function', (10,)), - ) - options = ( - {'id': 'objdump', 'desc': 'objdump path', - 'default': 'arm-none-eabi-objdump'}, - {'id': 'objdump_opts', 'desc': 'objdump options', - 'default': '-lSC'}, - {'id': 'elffile', 'desc': '.elf path', - 'default': ''}, - {'id': 'branch_enc', 'desc': 'Branch encoding', - 'default': 'alternative', 'values': ('alternative', 'original')}, - ) - - def __init__(self): - self.reset() - - def reset(self): - self.buf = [] - self.syncbuf = [] - self.prevsample = 0 - self.last_branch = 0 - self.cpu_state = 'arm' - self.current_pc = 0 - self.current_loc = None - self.current_func = None - self.next_instr_lookup = {} - self.file_lookup = {} - self.func_lookup = {} - self.disasm_lookup = {} - self.source_lookup = {} - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.load_objdump() - - def load_objdump(self): - '''Parse disassembly obtained from objdump into two tables: - next_instr_lookup: Find the next PC addr from current PC. - disasm_lookup: Find the instruction text from current PC. - source_lookup: Find the source code line from current PC. - ''' - if not (self.options['objdump'] and self.options['elffile']): - return - - opts = [self.options['objdump']] - opts += self.options['objdump_opts'].split() - opts += [self.options['elffile']] - - try: - disasm = subprocess.check_output(opts) - except subprocess.CalledProcessError: - return - - disasm = disasm.decode('utf-8', 'replace') - - instpat = re.compile('\s*([0-9a-fA-F]+):\t+([0-9a-fA-F ]+)\t+([a-zA-Z][^;]+)\s*;?.*') - branchpat = re.compile('(b|bl|b..|bl..|cbnz|cbz)(?:\.[wn])?\s+(?:r[0-9]+,\s*)?([0-9a-fA-F]+)') - filepat = re.compile('[^\s]+[/\\\\]([a-zA-Z0-9._-]+:[0-9]+)(?:\s.*)?') - funcpat = re.compile('[0-9a-fA-F]+\s*<([^>]+)>:.*') - - prev_src = '' - prev_file = '' - prev_func = '' - - for line in disasm.split('\n'): - m = instpat.match(line) - if m: - addr = int(m.group(1), 16) - raw = m.group(2) - disas = m.group(3).strip().replace('\t', ' ') - self.disasm_lookup[addr] = disas - self.source_lookup[addr] = prev_src - self.file_lookup[addr] = prev_file - self.func_lookup[addr] = prev_func - - # Next address in direct sequence. - ilen = len(raw.replace(' ', '')) // 2 - next_n = addr + ilen - - # Next address if branch is taken. - bm = branchpat.match(disas) - if bm: - next_e = int(bm.group(2), 16) - else: - next_e = next_n - - self.next_instr_lookup[addr] = (next_n, next_e) - else: - m = funcpat.match(line) - if m: - prev_func = m.group(1) - prev_src = None - else: - m = filepat.match(line) - if m: - prev_file = m.group(1) - prev_src = None - else: - prev_src = line.strip() - - def flush_current_loc(self): - if self.current_loc is not None: - ss, es, loc, src = self.current_loc - if loc: - self.put(ss, es, self.out_ann, [9, [loc]]) - if src: - self.put(ss, es, self.out_ann, [8, [src]]) - self.current_loc = None - - def flush_current_func(self): - if self.current_func is not None: - ss, es, func = self.current_func - if func: - self.put(ss, es, self.out_ann, [10, [func]]) - self.current_func = None - - def instructions_executed(self, exec_status): - '''Advance program counter based on executed instructions. - Argument is a list of False for not executed and True for executed - instructions. - ''' - - if len(exec_status) == 0: - return - - tdelta = max(1, (self.prevsample - self.startsample) / len(exec_status)) - - for i, exec_status in enumerate(exec_status): - pc = self.current_pc - default_next = pc + 2 if self.cpu_state == 'thumb' else pc + 4 - target_n, target_e = self.next_instr_lookup.get(pc, (default_next, default_next)) - ss = self.startsample + round(tdelta * i) - es = self.startsample + round(tdelta * (i+1)) - - self.put(ss, es, self.out_ann, - [5, ['PC 0x%08x' % pc, '0x%08x' % pc, '%08x' % pc]]) - - new_loc = self.file_lookup.get(pc) - new_src = self.source_lookup.get(pc) - new_dis = self.disasm_lookup.get(pc) - new_func = self.func_lookup.get(pc) - - # Report source line only when it changes. - if self.current_loc is not None: - if new_loc != self.current_loc[2] or new_src != self.current_loc[3]: - self.flush_current_loc() - - if self.current_loc is None: - self.current_loc = [ss, es, new_loc, new_src] - else: - self.current_loc[1] = es - - # Report function name only when it changes. - if self.current_func is not None: - if new_func != self.current_func[2]: - self.flush_current_func() - - if self.current_func is None: - self.current_func = [ss, es, new_func] - else: - self.current_func[1] = es - - # Report instruction every time. - if new_dis: - if exec_status: - a = [6, ['Executed: ' + new_dis, new_dis, new_dis.split()[0]]] - else: - a = [7, ['Not executed: ' + new_dis, new_dis, new_dis.split()[0]]] - self.put(ss, es, self.out_ann, a) - - if exec_status: - self.current_pc = target_e - else: - self.current_pc = target_n - - def get_packet_type(self, byte): - '''Identify packet type based on its first byte. - See ARM IHI0014Q section "ETMv3 Signal Protocol" "Packet Types" - ''' - if byte & 0x01 == 0x01: - return 'branch' - elif byte == 0x00: - return 'a_sync' - elif byte == 0x04: - return 'cyclecount' - elif byte == 0x08: - return 'i_sync' - elif byte == 0x0C: - return 'trigger' - elif byte & 0xF3 in (0x20, 0x40, 0x60): - return 'ooo_data' - elif byte == 0x50: - return 'store_failed' - elif byte == 0x70: - return 'i_sync' - elif byte & 0xDF in (0x54, 0x58, 0x5C): - return 'ooo_place' - elif byte == 0x3C: - return 'vmid' - elif byte & 0xD3 == 0x02: - return 'data' - elif byte & 0xFB == 0x42: - return 'timestamp' - elif byte == 0x62: - return 'data_suppressed' - elif byte == 0x66: - return 'ignore' - elif byte & 0xEF == 0x6A: - return 'value_not_traced' - elif byte == 0x6E: - return 'context_id' - elif byte == 0x76: - return 'exception_exit' - elif byte == 0x7E: - return 'exception_entry' - elif byte & 0x81 == 0x80: - return 'p_header' - else: - return 'unknown' - - def fallback(self, buf): - ptype = self.get_packet_type(buf[0]) - return [0, ['Unhandled ' + ptype + ': ' + ' '.join(['%02x' % b for b in buf])]] - - def handle_a_sync(self, buf): - if buf[-1] == 0x80: - return [0, ['Synchronization']] - - def handle_exception_exit(self, buf): - return [2, ['Exception exit']] - - def handle_exception_entry(self, buf): - return [2, ['Exception entry']] - - def handle_i_sync(self, buf): - contextid_bytes = 0 # This is the default ETM config. - - if len(buf) < 6: - return None # Packet definitely not full yet. - - if buf[0] == 0x08: # No cycle count. - cyclecount = None - idx = 1 + contextid_bytes # Index to info byte. - elif buf[0] == 0x70: # With cycle count. - cyclecount, cyclen = parse_varint(buf[1:6]) - idx = 1 + cyclen + contextid_bytes - - if len(buf) <= idx + 4: - return None - infobyte = buf[idx] - addr = parse_uint(buf[idx+1:idx+5]) - - reasoncode = (infobyte >> 5) & 3 - reason = ('Periodic', 'Tracing enabled', 'After overflow', 'Exit from debug')[reasoncode] - jazelle = (infobyte >> 4) & 1 - nonsec = (infobyte >> 3) & 1 - altisa = (infobyte >> 2) & 1 - hypervisor = (infobyte >> 1) & 1 - thumb = addr & 1 - addr &= 0xFFFFFFFE - - if reasoncode == 0 and self.current_pc != addr: - self.put(self.startsample, self.prevsample, self.out_ann, - [0, ['WARN: Unexpected PC change 0x%08x -> 0x%08x' % \ - (self.current_pc, addr)]]) - elif reasoncode != 0: - # Reset location when the trace has been interrupted. - self.flush_current_loc() - self.flush_current_func() - - self.last_branch = addr - self.current_pc = addr - - if jazelle: - self.cpu_state = 'jazelle' - elif thumb: - self.cpu_state = 'thumb' - else: - self.cpu_state = 'arm' - - cycstr = '' - if cyclecount is not None: - cycstr = ', cyclecount %d' % cyclecount - - if infobyte & 0x80: # LSIP packet - self.put(self.startsample, self.prevsample, self.out_ann, - [0, ['WARN: LSIP I-Sync packet not implemented']]) - - return [0, ['I-Sync: %s, PC 0x%08x, %s state%s' % \ - (reason, addr, self.cpu_state, cycstr), \ - 'I-Sync: %s 0x%08x' % (reason, addr)]] - - def handle_trigger(self, buf): - return [0, ['Trigger event', 'Trigger']] - - def handle_p_header(self, buf): - # Only non cycle-accurate mode supported. - if buf[0] & 0x83 == 0x80: - n = (buf[0] >> 6) & 1 - e = (buf[0] >> 2) & 15 - - self.instructions_executed([1] * e + [0] * n) - - if n: - return [3, ['%d instructions executed, %d skipped due to ' \ - 'condition codes' % (e, n), - '%d ins exec, %d skipped' % (e, n), - '%dE,%dN' % (e, n)]] - else: - return [3, ['%d instructions executed' % e, - '%d ins exec' % e, '%dE' % e]] - elif buf[0] & 0xF3 == 0x82: - i1 = (buf[0] >> 3) & 1 - i2 = (buf[0] >> 2) & 1 - self.instructions_executed([not i1, not i2]) - txt1 = ('executed', 'skipped') - txt2 = ('E', 'S') - return [3, ['Instruction 1 %s, instruction 2 %s' % (txt1[i1], txt1[i2]), - 'I1 %s, I2 %s' % (txt2[i1], txt2[i2]), - '%s,%s' % (txt2[i1], txt2[i2])]] - else: - return self.fallback(buf) - - def handle_branch(self, buf): - if buf[-1] & 0x80 != 0x00: - return None # Not complete yet. - - brinfo = parse_branch_addr(buf, self.last_branch, self.cpu_state, - self.options['branch_enc']) - - if brinfo is None: - return None # Not complete yet. - - addr, addrlen, cpu_state, exc_info = brinfo - self.last_branch = addr - self.current_pc = addr - - txt = '' - - if cpu_state != self.cpu_state: - txt += ', to %s state' % cpu_state - self.cpu_state = cpu_state - - annidx = 1 - - if exc_info: - annidx = 2 - ns, exc, cancel, altisa, hyp, resume = exc_info - if ns: - txt += ', to non-secure state' - if exc: - if exc < len(exc_names): - txt += ', exception %s' % exc_names[exc] - else: - txt += ', exception 0x%02x' % exc - if cancel: - txt += ', instr cancelled' - if altisa: - txt += ', to AltISA' - if hyp: - txt += ', to hypervisor' - if resume: - txt += ', instr resume 0x%02x' % resume - - return [annidx, ['Branch to 0x%08x%s' % (addr, txt), - 'B 0x%08x%s' % (addr, txt)]] - - def decode(self, ss, es, data): - ptype, rxtx, pdata = data - - if ptype != 'DATA': - return - - # Reset packet if there is a long pause between bytes. - # This helps getting the initial synchronization. - self.byte_len = es - ss - if ss - self.prevsample > 16 * self.byte_len: - self.flush_current_loc() - self.flush_current_func() - self.buf = [] - self.prevsample = es - - self.buf.append(pdata[0]) - - # Store the start time of the packet. - if len(self.buf) == 1: - self.startsample = ss - - # Keep separate buffer for detection of sync packets. - # Sync packets override everything else, so that we can regain sync - # even if some packets are corrupted. - self.syncbuf = self.syncbuf[-4:] + [pdata[0]] - if self.syncbuf == [0x00, 0x00, 0x00, 0x00, 0x80]: - self.buf = self.syncbuf - self.syncbuf = [] - - # See if it is ready to be decoded. - ptype = self.get_packet_type(self.buf[0]) - if hasattr(self, 'handle_' + ptype): - func = getattr(self, 'handle_' + ptype) - data = func(self.buf) - else: - data = self.fallback(self.buf) - - if data is not None: - if data: - self.put(self.startsample, es, self.out_ann, data) - self.buf = [] diff --git a/decoders/arm_itm/__init__.py b/decoders/arm_itm/__init__.py deleted file mode 100755 index 1733d36d..00000000 --- a/decoders/arm_itm/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Petteri Aimonen -## -## 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, see . -## - -''' -This decoder stacks on top of the 'uart' or 'arm_tpiu' PD and decodes the -ARM Cortex-M processor trace data from Instrumentation Trace Macroblock. -''' - -from .pd import Decoder diff --git a/decoders/arm_itm/pd.py b/decoders/arm_itm/pd.py deleted file mode 100755 index 64149787..00000000 --- a/decoders/arm_itm/pd.py +++ /dev/null @@ -1,373 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Petteri Aimonen -## -## 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, see . -## - -import sigrokdecode as srd -import string -import subprocess -import re - -ARM_EXCEPTIONS = { - 0: 'Thread', - 1: 'Reset', - 2: 'NMI', - 3: 'HardFault', - 4: 'MemManage', - 5: 'BusFault', - 6: 'UsageFault', - 11: 'SVCall', - 12: 'Debug Monitor', - 14: 'PendSV', - 15: 'SysTick', -} - -class Decoder(srd.Decoder): - api_version = 3 - id = 'arm_itm' - name = 'ARM ITM' - longname = 'ARM Instrumentation Trace Macroblock' - desc = 'ARM Cortex-M / ARMv7m ITM trace protocol.' - license = 'gplv2+' - inputs = ['uart'] - outputs = [] - tags = ['Debug/trace'] - options = ( - {'id': 'objdump', 'desc': 'objdump path', - 'default': 'arm-none-eabi-objdump'}, - {'id': 'objdump_opts', 'desc': 'objdump options', - 'default': '-lSC'}, - {'id': 'elffile', 'desc': '.elf path', - 'default': ''}, - ) - annotations = ( - ('trace', 'Trace information'), - ('timestamp', 'Timestamp'), - ('software', 'Software message'), - ('dwt_event', 'DWT event'), - ('dwt_watchpoint', 'DWT watchpoint'), - ('dwt_exc', 'Exception trace'), - ('dwt_pc', 'Program counter'), - ('mode_thread', 'Current mode: thread'), - ('mode_irq', 'Current mode: IRQ'), - ('mode_exc', 'Current mode: Exception'), - ('location', 'Current location'), - ('function', 'Current function'), - ) - annotation_rows = ( - ('trace', 'Trace information', (0, 1)), - ('software', 'Software trace', (2,)), - ('dwt_event', 'DWT event', (3,)), - ('dwt_watchpoint', 'DWT watchpoint', (4,)), - ('dwt_exc', 'Exception trace', (5,)), - ('dwt_pc', 'Program counter', (6,)), - ('mode', 'Current mode', (7, 8, 9)), - ('location', 'Current location', (10,)), - ('function', 'Current function', (11,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.buf = [] - self.syncbuf = [] - self.swpackets = {} - self.prevsample = 0 - self.dwt_timestamp = 0 - self.current_mode = None - self.file_lookup = {} - self.func_lookup = {} - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.load_objdump() - - def load_objdump(self): - '''Parse disassembly obtained from objdump into a lookup tables''' - if not (self.options['objdump'] and self.options['elffile']): - return - - opts = [self.options['objdump']] - opts += self.options['objdump_opts'].split() - opts += [self.options['elffile']] - - try: - disasm = subprocess.check_output(opts) - except subprocess.CalledProcessError: - return - - disasm = disasm.decode('utf-8', 'replace') - - instpat = re.compile('\s*([0-9a-fA-F]+):\t+([0-9a-fA-F ]+)\t+([a-zA-Z][^;]+)\s*;?.*') - filepat = re.compile('[^\s]+[/\\\\]([a-zA-Z0-9._-]+:[0-9]+)(?:\s.*)?') - funcpat = re.compile('[0-9a-fA-F]+\s*<([^>]+)>:.*') - - prev_file = '' - prev_func = '' - - for line in disasm.split('\n'): - m = instpat.match(line) - if m: - addr = int(m.group(1), 16) - self.file_lookup[addr] = prev_file - self.func_lookup[addr] = prev_func - else: - m = funcpat.match(line) - if m: - prev_func = m.group(1) - else: - m = filepat.match(line) - if m: - prev_file = m.group(1) - - def get_packet_type(self, byte): - '''Identify packet type based on its first byte. - See ARMv7-M_ARM.pdf section "Debug ITM and DWT" "Packet Types" - ''' - if byte & 0x7F == 0: - return 'sync' - elif byte == 0x70: - return 'overflow' - elif byte & 0x0F == 0 and byte & 0xF0 != 0: - return 'timestamp' - elif byte & 0x0F == 0x08: - return 'sw_extension' - elif byte & 0x0F == 0x0C: - return 'hw_extension' - elif byte & 0x0F == 0x04: - return 'reserved' - elif byte & 0x04 == 0x00: - return 'software' - else: - return 'hardware' - - def mode_change(self, new_mode): - if self.current_mode is not None: - start, mode = self.current_mode - if mode.startswith('Thread'): - ann_idx = 7 - elif mode.startswith('IRQ'): - ann_idx = 8 - else: - ann_idx = 9 - self.put(start, self.startsample, self.out_ann, [ann_idx, [mode]]) - - if new_mode is None: - self.current_mode = None - else: - self.current_mode = (self.startsample, new_mode) - - def location_change(self, pc): - new_loc = self.file_lookup.get(pc) - new_func = self.func_lookup.get(pc) - ss = self.startsample - es = self.prevsample - - if new_loc is not None: - self.put(ss, es, self.out_ann, [10, [new_loc]]) - - if new_func is not None: - self.put(ss, es, self.out_ann, [11, [new_func]]) - - def fallback(self, buf): - ptype = self.get_packet_type(buf[0]) - return [0, [('Unhandled %s: ' % ptype) + ' '.join(['%02x' % b for b in buf])]] - - def handle_overflow(self, buf): - return [0, ['Overflow']] - - def handle_hardware(self, buf): - '''Handle packets from hardware source, i.e. DWT block.''' - plen = (0, 1, 2, 4)[buf[0] & 0x03] - pid = buf[0] >> 3 - if len(buf) != plen + 1: - return None # Not complete yet. - - if pid == 0: - text = 'DWT events:' - if buf[1] & 0x20: - text += ' Cyc' - if buf[1] & 0x10: - text += ' Fold' - if buf[1] & 0x08: - text += ' LSU' - if buf[1] & 0x04: - text += ' Sleep' - if buf[1] & 0x02: - text += ' Exc' - if buf[1] & 0x01: - text += ' CPI' - return [3, [text]] - elif pid == 1: - excnum = ((buf[2] & 1) << 8) | buf[1] - event = (buf[2] >> 4) - excstr = ARM_EXCEPTIONS.get(excnum, 'IRQ %d' % (excnum - 16)) - if event == 1: - self.mode_change(excstr) - return [5, ['Enter: ' + excstr, 'E ' + excstr]] - elif event == 2: - self.mode_change(None) - return [5, ['Exit: ' + excstr, 'X ' + excstr]] - elif event == 3: - self.mode_change(excstr) - return [5, ['Resume: ' + excstr, 'R ' + excstr]] - elif pid == 2: - pc = buf[1] | (buf[2] << 8) | (buf[3] << 16) | (buf[4] << 24) - self.location_change(pc) - return [6, ['PC: 0x%08x' % pc]] - elif (buf[0] & 0xC4) == 0x84: - comp = (buf[0] & 0x30) >> 4 - what = 'Read' if (buf[0] & 0x08) == 0 else 'Write' - if plen == 1: - data = '0x%02x' % (buf[1]) - elif plen == 2: - data = '0x%04x' % (buf[1] | (buf[2] << 8)) - else: - data = '0x%08x' % (buf[1] | (buf[2] << 8) | (buf[3] << 16) | (buf[4] << 24)) - return [4, ['Watchpoint %d: %s data %s' % (comp, what, data), - 'WP%d: %s %s' % (comp, what[0], data)]] - elif (buf[0] & 0xCF) == 0x47: - comp = (buf[0] & 0x30) >> 4 - addr = buf[1] | (buf[2] << 8) | (buf[3] << 16) | (buf[4] << 24) - self.location_change(addr) - return [4, ['Watchpoint %d: PC 0x%08x' % (comp, addr), - 'WP%d: PC 0x%08x' % (comp, addr)]] - elif (buf[0] & 0xCF) == 0x4E: - comp = (buf[0] & 0x30) >> 4 - offset = buf[1] | (buf[2] << 8) - return [4, ['Watchpoint %d: address 0x????%04x' % (comp, offset), - 'WP%d: A 0x%04x' % (comp, offset)]] - - return self.fallback(buf) - - def handle_software(self, buf): - '''Handle packets generated by software running on the CPU.''' - plen = (0, 1, 2, 4)[buf[0] & 0x03] - pid = buf[0] >> 3 - if len(buf) != plen + 1: - return None # Not complete yet. - - if plen == 1 and chr(buf[1]) in string.printable: - self.add_delayed_sw(pid, chr(buf[1])) - return [] # Handled but no data to output. - - self.push_delayed_sw() - - if plen == 1: - return [2, ['%d: 0x%02x' % (pid, buf[1])]] - elif plen == 2: - return [2, ['%d: 0x%02x%02x' % (pid, buf[2], buf[1])]] - elif plen == 4: - return [2, ['%d: 0x%02x%02x%02x%02x' % (pid, buf[4], buf[3], buf[2], buf[1])]] - - def handle_timestamp(self, buf): - '''Handle timestamp packets, which indicate the time of some DWT event packet.''' - if buf[-1] & 0x80 != 0: - return None # Not complete yet. - - if buf[0] & 0x80 == 0: - tc = 0 - ts = buf[0] >> 4 - else: - tc = (buf[0] & 0x30) >> 4 - ts = buf[1] & 0x7F - if len(buf) > 2: - ts |= (buf[2] & 0x7F) << 7 - if len(buf) > 3: - ts |= (buf[3] & 0x7F) << 14 - if len(buf) > 4: - ts |= (buf[4] & 0x7F) << 21 - - self.dwt_timestamp += ts - - if tc == 0: - msg = '(exact)' - elif tc == 1: - msg = '(timestamp delayed)' - elif tc == 2: - msg = '(event delayed)' - elif tc == 3: - msg = '(event and timestamp delayed)' - - return [1, ['Timestamp: %d %s' % (self.dwt_timestamp, msg)]] - - def add_delayed_sw(self, pid, c): - '''We join printable characters from software source so that printed - strings are easy to read. Joining is done by PID so that different - sources do not get confused with each other.''' - if self.swpackets.get(pid) is not None: - self.swpackets[pid][1] = self.prevsample - self.swpackets[pid][2] += c - else: - self.swpackets[pid] = [self.startsample, self.prevsample, c] - - def push_delayed_sw(self): - for pid, packet in self.swpackets.items(): - if packet is None: - continue - ss, prevtime, text = packet - # Heuristic criterion: Text has ended if at least 16 byte - # durations after previous received byte. Actual delay depends - # on printf implementation on target. - if self.prevsample - prevtime > 16 * self.byte_len: - self.put(ss, prevtime, self.out_ann, [2, ['%d: "%s"' % (pid, text)]]) - self.swpackets[pid] = None - - def decode(self, ss, es, data): - ptype, rxtx, pdata = data - - # For now, ignore all UART packets except the actual data packets. - if ptype != 'DATA': - return - - self.byte_len = es - ss - - # Reset packet if there is a long pause between bytes. - # TPIU framing can introduce small pauses, but more than 1 frame - # should reset packet. - if ss - self.prevsample > 16 * self.byte_len: - self.push_delayed_sw() - self.buf = [] - self.prevsample = es - - # Build up the current packet byte by byte. - self.buf.append(pdata[0]) - - # Store the start time of the packet. - if len(self.buf) == 1: - self.startsample = ss - - # Keep separate buffer for detection of sync packets. - # Sync packets override everything else, so that we can regain sync - # even if some packets are corrupted. - self.syncbuf = self.syncbuf[-5:] + [pdata[0]] - if self.syncbuf == [0, 0, 0, 0, 0, 0x80]: - self.buf = self.syncbuf - - # See if it is ready to be decoded. - ptype = self.get_packet_type(self.buf[0]) - if hasattr(self, 'handle_' + ptype): - func = getattr(self, 'handle_' + ptype) - data = func(self.buf) - else: - data = self.fallback(self.buf) - - if data is not None: - if data: - self.put(self.startsample, es, self.out_ann, data) - self.buf = [] diff --git a/decoders/arm_tpiu/__init__.py b/decoders/arm_tpiu/__init__.py deleted file mode 100755 index ce9c3744..00000000 --- a/decoders/arm_tpiu/__init__.py +++ /dev/null @@ -1,28 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Petteri Aimonen -## -## 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, see . -## - -''' -This decoder stacks on top of the 'uart' PD and decodes the frame format -of ARMv7m Trace Port Interface Unit. - -It filters the data coming from various trace sources (such as ARMv7m ITM -and ETM blocks) into separate streams that can be further decoded by other PDs. -''' - -from .pd import Decoder diff --git a/decoders/arm_tpiu/pd.py b/decoders/arm_tpiu/pd.py deleted file mode 100755 index 29b4605f..00000000 --- a/decoders/arm_tpiu/pd.py +++ /dev/null @@ -1,131 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Petteri Aimonen -## -## 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, see . -## - -import sigrokdecode as srd - -class Decoder(srd.Decoder): - api_version = 3 - id = 'arm_tpiu' - name = 'ARM TPIU' - longname = 'ARM Trace Port Interface Unit' - desc = 'Filter TPIU formatted trace data into separate streams.' - license = 'gplv2+' - inputs = ['uart'] - outputs = ['uart'] # Emulate uart output so that arm_itm/arm_etm can stack. - tags = ['Debug/trace'] - options = ( - {'id': 'stream', 'desc': 'Stream index', 'default': 1}, - {'id': 'sync_offset', 'desc': 'Initial sync offset', 'default': 0}, - ) - annotations = ( - ('stream', 'Current stream'), - ('data', 'Stream data'), - ) - annotation_rows = ( - ('stream', 'Current stream', (0,)), - ('data', 'Stream data', (1,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.buf = [] - self.syncbuf = [] - self.prevsample = 0 - self.stream = 0 - self.ss_stream = None - self.bytenum = 0 - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.out_python = self.register(srd.OUTPUT_PYTHON) - - def stream_changed(self, ss, stream): - if self.stream != stream: - if self.stream != 0: - self.put(self.ss_stream, ss, self.out_ann, - [0, ['Stream %d' % self.stream, 'S%d' % self.stream]]) - self.stream = stream - self.ss_stream = ss - - def emit_byte(self, ss, es, byte): - if self.stream == self.options['stream']: - self.put(ss, es, self.out_ann, [1, ['0x%02x' % byte]]) - self.put(ss, es, self.out_python, ['DATA', 0, (byte, [])]) - - def process_frame(self, buf): - # Byte 15 contains the lowest bits of bytes 0, 2, ... 14. - lowbits = buf[15][2] - - for i in range(0, 15, 2): - # Odd bytes can be stream ID or data. - delayed_stream_change = None - lowbit = (lowbits >> (i // 2)) & 0x01 - if buf[i][2] & 0x01 != 0: - if lowbit: - delayed_stream_change = buf[i][2] >> 1 - else: - self.stream_changed(buf[i][0], buf[i][2] >> 1) - else: - byte = buf[i][2] | lowbit - self.emit_byte(buf[i][0], buf[i][1], byte) - - # Even bytes are always data. - if i < 14: - self.emit_byte(buf[i+1][0], buf[i+1][1], buf[i+1][2]) - - # The stream change can be delayed to occur after the data byte. - if delayed_stream_change is not None: - self.stream_changed(buf[i+1][1], delayed_stream_change) - - def decode(self, ss, es, data): - ptype, rxtx, pdata = data - - if ptype != 'DATA': - return - - # Reset packet if there is a long pause between bytes. - self.byte_len = es - ss - if ss - self.prevsample > self.byte_len: - self.buf = [] - self.prevsample = es - - self.buf.append((ss, es, pdata[0])) - self.bytenum += 1 - - # Allow skipping N first bytes of the data. By adjusting the sync - # value, one can get initial synchronization as soon as the trace - # starts. - if self.bytenum < self.options['sync_offset']: - self.buf = [] - return - - # Keep separate buffer for detection of sync packets. - # Sync packets override everything else, so that we can regain sync - # even if some packets are corrupted. - self.syncbuf = self.syncbuf[-3:] + [pdata[0]] - if self.syncbuf == [0xFF, 0xFF, 0xFF, 0x7F]: - self.buf = [] - self.syncbuf = [] - return - - if len(self.buf) == 16: - self.process_frame(self.buf) - self.buf = [] diff --git a/decoders/atsha204a/__init__.py b/decoders/atsha204a/__init__.py deleted file mode 100755 index fd0f4288..00000000 --- a/decoders/atsha204a/__init__.py +++ /dev/null @@ -1,30 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Michalis Pappas -## -## 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, see . -## - -''' -This decoder stacks on top of the 'i2c' PD and decodes the -Microchip ATSHA204A and ATECC508A crypto authentication protocol. - -The decoder might also support the following devices (untested): - * ATSHA204 - * ATECC108 - * ATECC108A -''' - -from .pd import Decoder diff --git a/decoders/atsha204a/pd.py b/decoders/atsha204a/pd.py deleted file mode 100755 index c666332a..00000000 --- a/decoders/atsha204a/pd.py +++ /dev/null @@ -1,323 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Michalis Pappas -## -## 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, see . -## - -import sigrokdecode as srd - -WORD_ADDR_RESET = 0x00 -WORD_ADDR_SLEEP = 0x01 -WORD_ADDR_IDLE = 0x02 -WORD_ADDR_COMMAND = 0x03 - -WORD_ADDR = {0x00: 'RESET', 0x01: 'SLEEP', 0x02: 'IDLE', 0x03: 'COMMAND'} - -OPCODE_COUNTER = 0x24 -OPCODE_DERIVE_KEY = 0x1c -OPCODE_DEV_REV = 0x30 -OPCODE_ECDH = 0x43 -OPCODE_GEN_DIG = 0x15 -OPCODE_GEN_KEY = 0x40 -OPCODE_HMAC = 0x11 -OPCODE_CHECK_MAC = 0x28 -OPCODE_LOCK = 0x17 -OPCODE_MAC = 0x08 -OPCODE_NONCE = 0x16 -OPCODE_PAUSE = 0x01 -OPCODE_PRIVWRITE = 0x46 -OPCODE_RANDOM = 0x1b -OPCODE_READ = 0x02 -OPCODE_SHA = 0x47 -OPCODE_SIGN = 0x41 -OPCODE_UPDATE_EXTRA = 0x20 -OPCODE_VERIFY = 0x45 -OPCODE_WRITE = 0x12 - -OPCODES = { - 0x01: 'Pause', - 0x02: 'Read', - 0x08: 'MAC', - 0x11: 'HMAC', - 0x12: 'Write', - 0x15: 'GenDig', - 0x16: 'Nonce', - 0x17: 'Lock', - 0x1b: 'Random', - 0x1c: 'DeriveKey', - 0x20: 'UpdateExtra', - 0x24: 'Counter', - 0x28: 'CheckMac', - 0x30: 'DevRev', - 0x40: 'GenKey', - 0x41: 'Sign', - 0x43: 'ECDH', - 0x45: 'Verify', - 0x46: 'PrivWrite', - 0x47: 'SHA', -} - -ZONE_CONFIG = 0x00 -ZONE_OTP = 0x01 -ZONE_DATA = 0x02 - -ZONES = {0x00: 'CONFIG', 0x01: 'OTP', 0x02: 'DATA'} - -STATUS_SUCCESS = 0x00 -STATUS_CHECKMAC_FAIL = 0x01 -STATUS_PARSE_ERROR = 0x03 -STATUS_EXECUTION_ERROR = 0x0f -STATUS_READY = 0x11 -STATUS_CRC_COMM_ERROR = 0xff - -STATUS = { - 0x00: 'Command success', - 0x01: 'Checkmac failure', - 0x03: 'Parse error', - 0x0f: 'Execution error', - 0x11: 'Ready', - 0xff: 'CRC / communications error', -} - -class Decoder(srd.Decoder): - api_version = 3 - id = 'atsha204a' - name = 'ATSHA204A' - longname = 'Microchip ATSHA204A' - desc = 'Microchip ATSHA204A family crypto authentication protocol.' - license = 'gplv2+' - inputs = ['i2c'] - outputs = [] - tags = ['Security/crypto', 'IC', 'Memory'] - annotations = ( - ('waddr', 'Word address'), - ('count', 'Count'), - ('opcode', 'Opcode'), - ('param1', 'Param1'), - ('param2', 'Param2'), - ('data', 'Data'), - ('crc', 'CRC'), - ('status', 'Status'), - ('warning', 'Warning'), - ) - annotation_rows = ( - ('frame', 'Frame', (0, 1, 2, 3, 4, 5, 6)), - ('status', 'Status', (7,)), - ('warnings', 'Warnings', (8,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.state = 'IDLE' - self.waddr = self.opcode = -1 - self.ss_block = self.es_block = 0 - self.bytes = [] - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def output_tx_bytes(self): - b = self.bytes - if len(b) < 1: # Ignore wakeup. - return - self.waddr = b[0][2] - self.put_waddr(b[0]) - if self.waddr == WORD_ADDR_COMMAND: - count = b[1][2] - self.put_count(b[1]) - if len(b) - 1 != count: - self.put_warning(b[0][0], b[-1][1], - 'Invalid frame length: Got {}, expecting {} '.format( - len(b) - 1, count)) - return - self.opcode = b[2][2] - self.put_opcode(b[2]) - self.put_param1(b[3]) - self.put_param2([b[4], b[5]]) - self.put_data(b[6:-2]) - self.put_crc([b[-2], b[-1]]) - - def output_rx_bytes(self): - b = self.bytes - count = b[0][2] - self.put_count(b[0]) - if self.waddr == WORD_ADDR_RESET: - self.put_data([b[1]]) - self.put_crc([b[2], b[3]]) - self.put_status(b[0][0], b[-1][1], b[1][2]) - elif self.waddr == WORD_ADDR_COMMAND: - if count == 4: # Status / Error. - self.put_data([b[1]]) - self.put_crc([b[2], b[3]]) - self.put_status(b[0][0], b[-1][1], b[1][2]) - else: - self.put_data(b[1:-2]) - self.put_crc([b[-2], b[-1]]) - - def putx(self, s, data): - self.put(s[0], s[1], self.out_ann, data) - - def puty(self, s, data): - self.put(s[0][0], s[1][1], self.out_ann, data) - - def putz(self, ss, es, data): - self.put(ss, es, self.out_ann, data) - - def put_waddr(self, s): - self.putx(s, [0, ['Word addr: %s' % WORD_ADDR[s[2]]]]) - - def put_count(self, s): - self.putx(s, [1, ['Count: %s' % s[2]]]) - - def put_opcode(self, s): - self.putx(s, [2, ['Opcode: %s' % OPCODES[s[2]]]]) - - def put_param1(self, s): - op = self.opcode - if op in (OPCODE_CHECK_MAC, OPCODE_COUNTER, OPCODE_DEV_REV, \ - OPCODE_ECDH, OPCODE_GEN_KEY, OPCODE_HMAC, OPCODE_MAC, \ - OPCODE_NONCE, OPCODE_RANDOM, OPCODE_SHA, OPCODE_SIGN, \ - OPCODE_VERIFY): - self.putx(s, [3, ['Mode: %02X' % s[2]]]) - elif op == OPCODE_DERIVE_KEY: - self.putx(s, [3, ['Random: %s' % s[2]]]) - elif op == OPCODE_PRIVWRITE: - self.putx(s, [3, ['Encrypted: {}'.format('Yes' if s[2] & 0x40 else 'No')]]) - elif op == OPCODE_GEN_DIG: - self.putx(s, [3, ['Zone: %s' % ZONES[s[2]]]]) - elif op == OPCODE_LOCK: - self.putx(s, [3, ['Zone: {}, Summary: {}'.format( - 'DATA/OTP' if s[2] else 'CONFIG', - 'Ignored' if s[2] & 0x80 else 'Used')]]) - elif op == OPCODE_PAUSE: - self.putx(s, [3, ['Selector: %02X' % s[2]]]) - elif op == OPCODE_READ: - self.putx(s, [3, ['Zone: {}, Length: {}'.format(ZONES[s[2] & 0x03], - '32 bytes' if s[2] & 0x90 else '4 bytes')]]) - elif op == OPCODE_WRITE: - self.putx(s, [3, ['Zone: {}, Encrypted: {}, Length: {}'.format(ZONES[s[2] & 0x03], - 'Yes' if s[2] & 0x40 else 'No', '32 bytes' if s[2] & 0x90 else '4 bytes')]]) - else: - self.putx(s, [3, ['Param1: %02X' % s[2]]]) - - def put_param2(self, s): - op = self.opcode - if op == OPCODE_DERIVE_KEY: - self.puty(s, [4, ['TargetKey: {:02x} {:02x}'.format(s[1][2], s[0][2])]]) - elif op in (OPCODE_COUNTER, OPCODE_ECDH, OPCODE_GEN_KEY, OPCODE_PRIVWRITE, \ - OPCODE_SIGN, OPCODE_VERIFY): - self.puty(s, [4, ['KeyID: {:02x} {:02x}'.format(s[1][2], s[0][2])]]) - elif op in (OPCODE_NONCE, OPCODE_PAUSE, OPCODE_RANDOM): - self.puty(s, [4, ['Zero: {:02x} {:02x}'.format(s[1][2], s[0][2])]]) - elif op in (OPCODE_HMAC, OPCODE_MAC, OPCODE_CHECK_MAC, OPCODE_GEN_DIG): - self.puty(s, [4, ['SlotID: {:02x} {:02x}'.format(s[1][2], s[0][2])]]) - elif op == OPCODE_LOCK: - self.puty(s, [4, ['Summary: {:02x} {:02x}'.format(s[1][2], s[0][2])]]) - elif op in (OPCODE_READ, OPCODE_WRITE): - self.puty(s, [4, ['Address: {:02x} {:02x}'.format(s[1][2], s[0][2])]]) - elif op == OPCODE_UPDATE_EXTRA: - self.puty(s, [4, ['NewValue: {:02x}'.format(s[0][2])]]) - else: - self.puty(s, [4, ['-']]) - - def put_data(self, s): - if len(s) == 0: - return - op = self.opcode - if op == OPCODE_CHECK_MAC: - self.putz(s[0][0], s[31][1], [5, ['ClientChal: %s' % ' '.join(format(i[2], '02x') for i in s[0:32])]]) - self.putz(s[32][0], s[63][1], [5, ['ClientResp: %s' % ' '.join(format(i[2], '02x') for i in s[32:64])]]) - self.putz(s[64][0], s[76][1], [5, ['OtherData: %s' % ' '.join(format(i[2], '02x') for i in s[64:77])]]) - elif op == OPCODE_DERIVE_KEY: - self.putz(s[0][0], s[31][1], [5, ['MAC: %s' % ' '.join(format(i[2], '02x') for i in s)]]) - elif op == OPCODE_ECDH: - self.putz(s[0][0], s[31][1], [5, ['Pub X: %s' % ' '.join(format(i[2], '02x') for i in s[0:32])]]) - self.putz(s[32][0], s[63][1], [5, ['Pub Y: %s' % ' '.join(format(i[2], '02x') for i in s[32:64])]]) - elif op in (OPCODE_GEN_DIG, OPCODE_GEN_KEY): - self.putz(s[0][0], s[3][1], [5, ['OtherData: %s' % ' '.join(format(i[2], '02x') for i in s)]]) - elif op == OPCODE_MAC: - self.putz(s[0][0], s[31][1], [5, ['Challenge: %s' % ' '.join(format(i[2], '02x') for i in s)]]) - elif op == OPCODE_PRIVWRITE: - if len(s) > 36: # Key + MAC. - self.putz(s[0][0], s[-35][1], [5, ['Value: %s' % ' '.join(format(i[2], '02x') for i in s)]]) - self.putz(s[-32][0], s[-1][1], [5, ['MAC: %s' % ' '.join(format(i[2], '02x') for i in s)]]) - else: # Just value. - self.putz(s[0][0], s[-1][1], [5, ['Value: %s' % ' '.join(format(i[2], '02x') for i in s)]]) - elif op == OPCODE_VERIFY: - if len(s) >= 64: # ECDSA components (always present) - self.putz(s[0][0], s[31][1], [5, ['ECDSA R: %s' % ' '.join(format(i[2], '02x') for i in s[0:32])]]) - self.putz(s[32][0], s[63][1], [5, ['ECDSA S: %s' % ' '.join(format(i[2], '02x') for i in s[32:64])]]) - if len(s) == 83: # OtherData (follow ECDSA components in validate / invalidate mode) - self.putz(s[64][0], s[82][1], [5, ['OtherData: %s' % ' '.join(format(i[2], '02x') for i in s[64:83])]]) - if len(s) == 128: # Public key components (follow ECDSA components in external mode) - self.putz(s[64][0], s[95][1], [5, ['Pub X: %s' % ' '.join(format(i[2], '02x') for i in s[64:96])]]) - self.putz(s[96][0], s[127][1], [5, ['Pub Y: %s' % ' '.join(format(i[2], '02x') for i in s[96:128])]]) - elif op == OPCODE_WRITE: - if len(s) > 32: # Value + MAC. - self.putz(s[0][0], s[-31][1], [5, ['Value: %s' % ' '.join(format(i[2], '02x') for i in s)]]) - self.putz(s[-32][0], s[-1][1], [5, ['MAC: %s' % ' '.join(format(i[2], '02x') for i in s)]]) - else: # Just value. - self.putz(s[0][0], s[-1][1], [5, ['Value: %s' % ' '.join(format(i[2], '02x') for i in s)]]) - else: - self.putz(s[0][0], s[-1][1], [5, ['Data: %s' % ' '.join(format(i[2], '02x') for i in s)]]) - - def put_crc(self, s): - self.puty(s, [6, ['CRC: {:02X} {:02X}'.format(s[0][2], s[1][2])]]) - - def put_status(self, ss, es, status): - self.putz(ss, es, [7, ['Status: %s' % STATUS[status]]]) - - def put_warning(self, ss, es, msg): - self.putz(ss, es, [8, ['Warning: %s' % msg]]) - - def decode(self, ss, es, data): - cmd, databyte = data - # State machine. - if self.state == 'IDLE': - # Wait for an I²C START condition. - if cmd != 'START': - return - self.state = 'GET SLAVE ADDR' - self.ss_block = ss - elif self.state == 'GET SLAVE ADDR': - # Wait for an address read/write operation. - if cmd == 'ADDRESS READ': - self.state = 'READ REGS' - elif cmd == 'ADDRESS WRITE': - self.state = 'WRITE REGS' - elif self.state == 'READ REGS': - if cmd == 'DATA READ': - self.bytes.append([ss, es, databyte]) - elif cmd == 'STOP': - self.es_block = es - # Reset the opcode before received data, as this causes - # responses to be displayed incorrectly. - self.opcode = -1 - if len(self.bytes) > 0: - self.output_rx_bytes() - self.waddr = -1 - self.bytes = [] - self.state = 'IDLE' - elif self.state == 'WRITE REGS': - if cmd == 'DATA WRITE': - self.bytes.append([ss, es, databyte]) - elif cmd == 'STOP': - self.es_block = es - self.output_tx_bytes() - self.bytes = [] - self.state = 'IDLE' diff --git a/decoders/aud/__init__.py b/decoders/aud/__init__.py deleted file mode 100755 index 10b74234..00000000 --- a/decoders/aud/__init__.py +++ /dev/null @@ -1,31 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2016 fenugrec -## -## 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, see . -## - -''' -This protocol decoder decodes the AUD (Advanced User Debugger) interface -of certain Renesas / Hitachi microcontrollers, when set in Branch Trace mode. - -AUD has two modes, this PD currently only supports "Branch Trace" mode. - -Details: -http://www.renesas.eu/products/mpumcu/superh/sh7050/sh7058/Documentation.jsp -("rej09b0046 - SH7058 Hardware manual") -''' - -from .pd import Decoder diff --git a/decoders/aud/pd.py b/decoders/aud/pd.py deleted file mode 100755 index ad93634f..00000000 --- a/decoders/aud/pd.py +++ /dev/null @@ -1,107 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2016 fenugrec -## Copyright (C) 2019 DreamSourceLab -## -## 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, see . -## - -# TODO: -# - Annotations are very crude and could be improved. -# - Annotate every nibble? Would give insight on interrupted shifts. -# - Annotate invalid "command" nibbles while SYNC==1? - -import sigrokdecode as srd - -class Decoder(srd.Decoder): - api_version = 3 - id = 'aud' - name = 'AUD' - longname = 'Advanced User Debugger' - desc = 'Renesas/Hitachi Advanced User Debugger (AUD) protocol.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Debug/trace'] - channels = ( - {'id': 'audck', 'name': 'AUDCK', 'desc': 'AUD clock'}, - {'id': 'naudsync', 'name': 'nAUDSYNC', 'desc': 'AUD sync'}, - {'id': 'audata3', 'name': 'AUDATA3', 'desc': 'AUD data line 3'}, - {'id': 'audata2', 'name': 'AUDATA2', 'desc': 'AUD data line 2'}, - {'id': 'audata1', 'name': 'AUDATA1', 'desc': 'AUD data line 1'}, - {'id': 'audata0', 'name': 'AUDATA0', 'desc': 'AUD data line 0'}, - ) - annotations = ( - ('dest', 'Destination address'), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.ncnt = 0 - self.nmax = 0 - self.addr = 0 - self.lastaddr = 0 - self.ss = 0 - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putx(self, data): - self.put(self.ss, self.samplenum, self.out_ann, data) - - def handle_clk_edge(self, clk, sync, datapins): - # Reconstruct nibble. - nib = 0 - for i in range(4): - nib |= datapins[3-i] << i - - # sync == 1: annotate if finished; update cmd. - # TODO: Annotate idle level (nibble = 0x03 && SYNC=1). - if sync == 1: - if (self.ncnt == self.nmax) and (self.nmax != 0): - # Done shifting an address: annotate. - self.putx([0, ['0x%08X' % self.addr]]) - self.lastaddr = self.addr - - self.ncnt = 0 - self.addr = self.lastaddr - self.ss = self.samplenum - if nib == 0x08: - self.nmax = 1 - elif nib == 0x09: - self.nmax = 2 - elif nib == 0x0a: - self.nmax = 4 - elif nib == 0x0b: - self.nmax = 8 - else: - # Undefined or idle. - self.nmax = 0 - else: - # sync == 0, valid cmd: start or continue shifting in nibbles. - if (self.nmax > 0): - # Clear tgt nibble. - self.addr &= ~(0x0F << (self.ncnt * 4)) - # Set nibble. - self.addr |= nib << (self.ncnt * 4) - self.ncnt += 1 - - def decode(self): - while True: - (clk, sync, d3, d2, d1, d0) = self.wait({0: 'r'}) - d = (d3, d2, d1, d0) - self.handle_clk_edge(clk, sync, d) diff --git a/decoders/avr_isp/__init__.py b/decoders/avr_isp/__init__.py deleted file mode 100755 index e3d90525..00000000 --- a/decoders/avr_isp/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -''' -This decoder stacks on top of the 'spi' PD and decodes the In-System -Programming (ISP) protocol of some Atmel AVR 8-bit microcontrollers. -''' - -from .pd import Decoder diff --git a/decoders/avr_isp/parts.py b/decoders/avr_isp/parts.py deleted file mode 100755 index 0767789a..00000000 --- a/decoders/avr_isp/parts.py +++ /dev/null @@ -1,41 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -# Device code addresses: -# 0x00: vendor code, 0x01: part family + flash size, 0x02: part number - -# Vendor code -vendor_code = { - 0x1e: 'Atmel', - 0x00: 'Device locked', -} - -# (Part family + flash size, part number) -part = { - (0x90, 0x01): 'AT90S1200', - (0x91, 0x01): 'AT90S2313', - (0x92, 0x01): 'AT90S4414', - (0x92, 0x05): 'ATmega48', # 4kB flash - (0x93, 0x01): 'AT90S8515', - (0x93, 0x0a): 'ATmega88', # 8kB flash - (0x94, 0x06): 'ATmega168', # 16kB flash - (0xff, 0xff): 'Device code erased, or target missing', - (0x01, 0x02): 'Device locked', - # TODO: Lots more entries. -} diff --git a/decoders/avr_isp/pd.py b/decoders/avr_isp/pd.py deleted file mode 100755 index a0719b73..00000000 --- a/decoders/avr_isp/pd.py +++ /dev/null @@ -1,213 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012-2014 Uwe Hermann -## -## 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, see . -## - -import sigrokdecode as srd -from .parts import * - -VENDOR_CODE_ATMEL = 0x1e - -class Decoder(srd.Decoder): - api_version = 3 - id = 'avr_isp' - name = 'AVR ISP' - longname = 'AVR In-System Programming' - desc = 'Atmel AVR In-System Programming (ISP) protocol.' - license = 'gplv2+' - inputs = ['spi'] - outputs = [] - tags = ['Debug/trace'] - annotations = ( - ('pe', 'Programming enable'), - ('rsb0', 'Read signature byte 0'), - ('rsb1', 'Read signature byte 1'), - ('rsb2', 'Read signature byte 2'), - ('ce', 'Chip erase'), - ('rfb', 'Read fuse bits'), - ('rhfb', 'Read high fuse bits'), - ('refb', 'Read extended fuse bits'), - ('warnings', 'Warnings'), - ('dev', 'Device'), - ) - annotation_rows = ( - ('bits', 'Bits', ()), - ('commands', 'Commands', tuple(range(7 + 1))), - ('warnings', 'Warnings', (8,)), - ('dev', 'Device', (9,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.state = 'IDLE' - self.mosi_bytes, self.miso_bytes = [], [] - self.ss_cmd, self.es_cmd = 0, 0 - self.xx, self.yy, self.zz, self.mm = 0, 0, 0, 0 - self.ss_device = None - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putx(self, data): - self.put(self.ss_cmd, self.es_cmd, self.out_ann, data) - - def handle_cmd_programming_enable(self, cmd, ret): - # Programming enable. - # Note: The chip doesn't send any ACK for 'Programming enable'. - self.putx([0, ['Programming enable']]) - - # Sanity check on reply. - if ret[1:4] != [0xac, 0x53, cmd[2]]: - self.putx([8, ['Warning: Unexpected bytes in reply!']]) - - def handle_cmd_read_signature_byte_0x00(self, cmd, ret): - # Signature byte 0x00: vendor code. - self.vendor_code = ret[3] - v = vendor_code[self.vendor_code] - self.putx([1, ['Vendor code: 0x%02x (%s)' % (ret[3], v)]]) - - # Store for later. - self.xx = cmd[1] # Same as ret[2]. - self.yy = cmd[3] - self.zz = ret[0] - - # Sanity check on reply. - if ret[1] != 0x30 or ret[2] != cmd[1]: - self.putx([8, ['Warning: Unexpected bytes in reply!']]) - - # Sanity check for the vendor code. - if self.vendor_code != VENDOR_CODE_ATMEL: - self.putx([8, ['Warning: Vendor code was not 0x1e (Atmel)!']]) - - def handle_cmd_read_signature_byte_0x01(self, cmd, ret): - # Signature byte 0x01: part family and memory size. - self.part_fam_flash_size = ret[3] - self.putx([2, ['Part family / memory size: 0x%02x' % ret[3]]]) - - # Store for later. - self.mm = cmd[3] - self.ss_device = self.ss_cmd - - # Sanity check on reply. - if ret[1] != 0x30 or ret[2] != cmd[1] or ret[0] != self.yy: - self.putx([8, ['Warning: Unexpected bytes in reply!']]) - - def handle_cmd_read_signature_byte_0x02(self, cmd, ret): - # Signature byte 0x02: part number. - self.part_number = ret[3] - self.putx([3, ['Part number: 0x%02x' % ret[3]]]) - - p = part[(self.part_fam_flash_size, self.part_number)] - data = [9, ['Device: Atmel %s' % p]] - self.put(self.ss_device, self.es_cmd, self.out_ann, data) - - # Sanity check on reply. - if ret[1] != 0x30 or ret[2] != self.xx or ret[0] != self.mm: - self.putx([8, ['Warning: Unexpected bytes in reply!']]) - - self.xx, self.yy, self.zz, self.mm = 0, 0, 0, 0 - - def handle_cmd_chip_erase(self, cmd, ret): - # Chip erase (erases both flash an EEPROM). - # Upon successful chip erase, the lock bits will also be erased. - # The only way to end a Chip Erase cycle is to release RESET#. - self.putx([4, ['Chip erase']]) - - # TODO: Check/handle RESET#. - - # Sanity check on reply. - bit = (ret[2] & (1 << 7)) >> 7 - if ret[1] != 0xac or bit != 1 or ret[3] != cmd[2]: - self.putx([8, ['Warning: Unexpected bytes in reply!']]) - - def handle_cmd_read_fuse_bits(self, cmd, ret): - # Read fuse bits. - self.putx([5, ['Read fuse bits: 0x%02x' % ret[3]]]) - - # TODO: Decode fuse bits. - # TODO: Sanity check on reply. - - def handle_cmd_read_fuse_high_bits(self, cmd, ret): - # Read fuse high bits. - self.putx([6, ['Read fuse high bits: 0x%02x' % ret[3]]]) - - # TODO: Decode fuse bits. - # TODO: Sanity check on reply. - - def handle_cmd_read_extended_fuse_bits(self, cmd, ret): - # Read extended fuse bits. - self.putx([7, ['Read extended fuse bits: 0x%02x' % ret[3]]]) - - # TODO: Decode fuse bits. - # TODO: Sanity check on reply. - - def handle_command(self, cmd, ret): - if cmd[:2] == [0xac, 0x53]: - self.handle_cmd_programming_enable(cmd, ret) - elif cmd[0] == 0xac and (cmd[1] & (1 << 7)) == (1 << 7): - self.handle_cmd_chip_erase(cmd, ret) - elif cmd[:3] == [0x50, 0x00, 0x00]: - self.handle_cmd_read_fuse_bits(cmd, ret) - elif cmd[:3] == [0x58, 0x08, 0x00]: - self.handle_cmd_read_fuse_high_bits(cmd, ret) - elif cmd[:3] == [0x50, 0x08, 0x00]: - self.handle_cmd_read_extended_fuse_bits(cmd, ret) - elif cmd[0] == 0x30 and cmd[2] == 0x00: - self.handle_cmd_read_signature_byte_0x00(cmd, ret) - elif cmd[0] == 0x30 and cmd[2] == 0x01: - self.handle_cmd_read_signature_byte_0x01(cmd, ret) - elif cmd[0] == 0x30 and cmd[2] == 0x02: - self.handle_cmd_read_signature_byte_0x02(cmd, ret) - else: - c = '%02x %02x %02x %02x' % tuple(cmd) - r = '%02x %02x %02x %02x' % tuple(ret) - self.putx([0, ['Unknown command: %s (reply: %s)!' % (c, r)]]) - - def decode(self, ss, es, data): - ptype, mosi, miso = data - - # For now, only use DATA and BITS packets. - if ptype not in ('DATA', 'BITS'): - return - - # Store the individual bit values and ss/es numbers. The next packet - # is guaranteed to be a 'DATA' packet belonging to this 'BITS' one. - if ptype == 'BITS': - self.miso_bits, self.mosi_bits = miso, mosi - return - - self.ss, self.es = ss, es - - if len(self.mosi_bytes) == 0: - self.ss_cmd = ss - - # Append new bytes. - self.mosi_bytes.append(mosi) - self.miso_bytes.append(miso) - - # All commands consist of 4 bytes. - if len(self.mosi_bytes) < 4: - return - - self.es_cmd = es - - self.handle_command(self.mosi_bytes, self.miso_bytes) - - self.mosi_bytes = [] - self.miso_bytes = [] diff --git a/decoders/avr_pdi/__init__.py b/decoders/avr_pdi/__init__.py deleted file mode 100755 index 1c61dea7..00000000 --- a/decoders/avr_pdi/__init__.py +++ /dev/null @@ -1,42 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2016 Gerhard Sittig -## -## 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, see . -## - -''' -PDI (Program and Debug Interface) is an Atmel proprietary interface for -external programming and on-chip debugging of the device. - -See the Atmel Application Note AVR1612 "PDI programming driver" and the -"Program and Debug Interface" section in the Xmega A manual for details. - -The protocol uses two pins: the RESET pin and one dedicated DATA pin. -The RESET pin provides a clock, the DATA pin communicates serial frames -with a start bit, eight data bits, an even parity bit, and two stop bits. -Data communication is bidirectional and half duplex, the device will -provide response data after reception of a respective request. - -Protocol frames communicate opcodes and their arguments, which provides -random and sequential access to the device's address space. By accessing -the registers of internal peripherals, especially the NVM controller, -it's possible to identify the device, read from and write to several -kinds of memory (signature rows, fuses and lock bits, internal flash and -EEPROM, memory mapped peripherals), and to control execution of software -on the device. -''' - -from .pd import Decoder diff --git a/decoders/avr_pdi/pd.py b/decoders/avr_pdi/pd.py deleted file mode 100755 index 45705950..00000000 --- a/decoders/avr_pdi/pd.py +++ /dev/null @@ -1,576 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2011-2014 Uwe Hermann -## Copyright (C) 2016 Gerhard Sittig -## Copyright (C) 2019 DreamSourceLab -## -## 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, see . -## - -# Note the implementation details: -# -# Although the Atmel literature suggests (does not explicitly mandate, -# but shows in diagrams) that two stop bits are used in the protocol, -# the decoder loses synchronization with ATxmega generated responses -# when it expects more than one stop bit. Since the chip's hardware is -# fixed, this is not an implementation error in some programmer software. -# Since this is a protocol decoder which does not participate in the -# communication (does not actively send data), we can read the data -# stream with one stop bit, and transparently keep working when two -# are used. -# -# Annotations in the UART fields level differ from Atmel literature. -# Wrong parity bits are referred to as "parity error". Low stop bits are -# referred to as "frame error". -# -# The PDI component in the device starts disabled. Enabling PDI -# communication is done by raising DATA and clocking RESET with a -# minimum frequency. PDI communication automatically gets disabled when -# RESET "is inactive" for a certain period of time. The specific timing -# conditions are rather fuzzy in the literature (phrased weakly), and -# are device dependent (refer to the minumum RESET pulse width). This -# protocol decoder implementation internally prepares for but currently -# does not support these enable and disable phases. On the one hand it -# avoids excess external dependencies or wrong results for legal input -# data. On the other hand the decoder works when input streams start in -# the middle of an established connection. -# -# Communication peers detect physical collisions. The decoder can't. -# Upon collisions, a peer will cease any subsequent transmission, until -# a BREAK is seen. Synchronization can get enforced by sending two BREAK -# conditions. The first will cause a collision, the second will re-enable -# the peer. The decoder has no concept of physical collisions. It stops -# the interpretation of instructions when BREAK is seen, and assumes -# that a new instruction will start after BREAK. -# -# This protocol decoder only supports PDI communication over UART frames. -# It lacks support for PDI over JTAG. This would require separation into -# multiple protocol decoder layers (UART physical, JTAG physical, PDI -# instructions, optionally device support on top of PDI. There is some -# more potential for future extensions: -# - The JTAG physical has dedicated TX and RX directions. This decoder -# only picks up communicated bytes but does not check which "line" -# they are communicated on (not applicable to half duplex UART). -# - PDI over JTAG uses "special frame error" conditions to communicate -# additional symbols: BREAK (0xBB with parity 1), DELAY (0xDB with -# parity 1), and EMPTY (0xEB with parity 1). -# - Another "device support" layer might interpret device specific -# timings, and might map addresses used in memory access operations -# to component names, or even register names and bit fields(?). It's -# quite deep a rabbithole though... - -import sigrokdecode as srd -from collections import namedtuple - -class Ann: - '''Annotation and binary output classes.''' - ( - BIT, START, DATA, PARITY_OK, PARITY_ERR, - STOP_OK, STOP_ERR, BREAK, - OPCODE, DATA_PROG, DATA_DEV, PDI_BREAK, - ENABLE, DISABLE, COMMAND, - ) = range(15) - ( - BIN_BYTES, - ) = range(1) - -Bit = namedtuple('Bit', 'val ss es') - -class PDI: - '''PDI protocol instruction opcodes, and operand formats.''' - ( - OP_LDS, OP_LD, OP_STS, OP_ST, - OP_LDCS, OP_REPEAT, OP_STCS, OP_KEY, - ) = range(8) - pointer_format_nice = [ - '*(ptr)', - '*(ptr++)', - 'ptr', - 'ptr++ (rsv)', - ] - pointer_format_terse = [ - '*p', - '*p++', - 'p', - '(rsv)', - ] - ctrl_reg_name = { - 0: 'status', - 1: 'reset', - 2: 'ctrl', - } - -class Decoder(srd.Decoder): - api_version = 3 - id = 'avr_pdi' - name = 'AVR PDI' - longname = 'Atmel Program and Debug Interface' - desc = 'Atmel ATxmega Program and Debug Interface (PDI) protocol.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Debug/trace'] - channels = ( - {'id': 'reset', 'name': 'RESET', 'desc': 'RESET / PDI_CLK'}, - {'id': 'data', 'name': 'DATA', 'desc': 'PDI_DATA'}, - ) - annotations = ( - ('uart-bit', 'UART bit'), - ('start-bit', 'Start bit'), - ('data-bit', 'Data bit'), - ('parity-ok', 'Parity OK bit'), - ('parity-err', 'Parity error bit'), - ('stop-ok', 'Stop OK bit'), - ('stop-err', 'Stop error bit'), - ('break', 'BREAK condition'), - ('opcode', 'Instruction opcode'), - ('data-prog', 'Programmer data'), - ('data-dev', 'Device data'), - ('pdi-break', 'BREAK at PDI level'), - ('enable', 'Enable PDI'), - ('disable', 'Disable PDI'), - ('cmd-data', 'PDI command with data'), - ) - annotation_rows = ( - ('uart_bits', 'UART bits', (Ann.BIT,)), - ('uart_fields', 'UART fields', (Ann.START, Ann.DATA, Ann.PARITY_OK, - Ann.PARITY_ERR, Ann.STOP_OK, Ann.STOP_ERR, Ann.BREAK)), - ('pdi_fields', 'PDI fields', (Ann.OPCODE, Ann.DATA_PROG, Ann.DATA_DEV, - Ann.PDI_BREAK)), - ('pdi_cmds', 'PDI Cmds', (Ann.ENABLE, Ann.DISABLE, Ann.COMMAND)), - ) - binary = ( - ('bytes', 'PDI protocol bytes'), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.clear_state() - - def clear_state(self): - # Track bit times and bit values. - self.ss_last_fall = None - self.data_sample = None - self.ss_curr_fall = None - # Collect UART frame bits into byte values. - self.bits = [] - self.zero_count = 0 - self.zero_ss = None - self.break_ss = None - self.break_es = None - self.clear_insn() - - def clear_insn(self): - # Collect instructions and their arguments, - # properties of the current instructions. - self.insn_rep_count = 0 - self.insn_opcode = None - self.insn_wr_counts = [] - self.insn_rd_counts = [] - # Accumulation of data items as bytes pass by. - self.insn_dat_bytes = [] - self.insn_dat_count = 0 - self.insn_ss_data = None - # Next layer "commands", instructions plus operands. - self.cmd_ss = None - self.cmd_insn_parts_nice = [] - self.cmd_insn_parts_terse = [] - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.out_binary = self.register(srd.OUTPUT_BINARY) - - def put_ann_bit(self, bit_nr, ann_idx): - b = self.bits[bit_nr] - self.put(b.ss, b.es, self.out_ann, [ann_idx, [str(b.val)]]) - - def put_ann_data(self, bit_nr, ann_data): - b = self.bits[bit_nr] - self.put(b.ss, b.es, self.out_ann, ann_data) - - def put_ann_row_val(self, ss, es, row, value): - self.put(ss, es, self.out_ann, [row, value]) - - def put_bin_bytes(self, ss, es, row, value): - self.put(ss, es, self.out_binary, [row, value]) - - def handle_byte(self, ss, es, byteval): - '''Handle a byte at the PDI protocol layer.''' - - # Handle BREAK conditions, which will abort any - # potentially currently executing instruction. - is_break = byteval is None - if is_break: - self.cmd_insn_parts_nice.append('BREAK') - self.cmd_insn_parts_terse.append('BRK') - self.insn_rep_count = 0 - # Will FALLTHROUGH to "end of instruction" below. - - # Decode instruction opcodes and argument sizes - # from the first byte of a transaction. - if self.insn_opcode is None and not is_break: - opcode = (byteval & 0xe0) >> 5 - arg30 = byteval & 0x0f - arg32 = (byteval & 0x0c) >> 2 - arg10 = byteval & 0x03 - self.insn_opcode = opcode - self.cmd_ss = ss - mnemonics = None - if opcode == PDI.OP_LDS: - # LDS: load data, direct addressing. - # Writes an address, reads a data item. - width_addr = arg32 + 1 - width_data = arg10 + 1 - self.insn_wr_counts = [width_addr] - self.insn_rd_counts = [width_data] - mnemonics = [ - 'Insn: LDS a{:d}, m{:d}'.format(width_addr, width_data), - 'LDS a{:d}, m{:d}'.format(width_addr, width_data), 'LDS', - ] - self.cmd_insn_parts_nice = ['LDS'] - self.cmd_insn_parts_terse = ['LDS'] - elif opcode == PDI.OP_LD: - # LD: load data, indirect addressing. - # Reads a data item, with optional repeat. - ptr_txt = PDI.pointer_format_nice[arg32] - ptr_txt_terse = PDI.pointer_format_terse[arg32] - width_data = arg10 + 1 - self.insn_wr_counts = [] - self.insn_rd_counts = [width_data] - if self.insn_rep_count: - self.insn_rd_counts.extend(self.insn_rep_count * [width_data]) - self.insn_rep_count = 0 - mnemonics = [ - 'Insn: LD {:s} m{:d}'.format(ptr_txt, width_data), - 'LD {:s} m{:d}'.format(ptr_txt, width_data), 'LD', - ] - self.cmd_insn_parts_nice = ['LD', ptr_txt] - self.cmd_insn_parts_terse = ['LD', ptr_txt_terse] - elif opcode == PDI.OP_STS: - # STS: store data, direct addressing. - # Writes an address, writes a data item. - width_addr = arg32 + 1 - width_data = arg10 + 1 - self.insn_wr_counts = [width_addr, width_data] - self.insn_rd_counts = [] - mnemonics = [ - 'Insn: STS a{:d}, i{:d}'.format(width_addr, width_data), - 'STS a{:d}, i{:d}'.format(width_addr, width_data), 'STS', - ] - self.cmd_insn_parts_nice = ['STS'] - self.cmd_insn_parts_terse = ['STS'] - elif opcode == PDI.OP_ST: - # ST: store data, indirect addressing. - # Writes a data item, with optional repeat. - ptr_txt = PDI.pointer_format_nice[arg32] - ptr_txt_terse = PDI.pointer_format_terse[arg32] - width_data = arg10 + 1 - self.insn_wr_counts = [width_data] - self.insn_rd_counts = [] - if self.insn_rep_count: - self.insn_wr_counts.extend(self.insn_rep_count * [width_data]) - self.insn_rep_count = 0 - mnemonics = [ - 'Insn: ST {:s} i{:d}'.format(ptr_txt, width_data), - 'ST {:s} i{:d}'.format(ptr_txt, width_data), 'ST', - ] - self.cmd_insn_parts_nice = ['ST', ptr_txt] - self.cmd_insn_parts_terse = ['ST', ptr_txt_terse] - elif opcode == PDI.OP_LDCS: - # LDCS: load control/status. - # Loads exactly one byte. - reg_num = arg30 - reg_txt = PDI.ctrl_reg_name.get(reg_num, 'r{:d}'.format(reg_num)) - reg_txt_terse = '{:d}'.format(reg_num) - self.insn_wr_counts = [] - self.insn_rd_counts = [1] - mnemonics = [ - 'Insn: LDCS {:s}, m1'.format(reg_txt), - 'LDCS {:s}, m1'.format(reg_txt), 'LDCS', - ] - self.cmd_insn_parts_nice = ['LDCS', reg_txt] - self.cmd_insn_parts_terse = ['LDCS', reg_txt_terse] - elif opcode == PDI.OP_STCS: - # STCS: store control/status. - # Writes exactly one byte. - reg_num = arg30 - reg_txt = PDI.ctrl_reg_name.get(reg_num, 'r{:d}'.format(reg_num)) - reg_txt_terse = '{:d}'.format(reg_num) - self.insn_wr_counts = [1] - self.insn_rd_counts = [] - mnemonics = [ - 'Insn: STCS {:s}, i1'.format(reg_txt), - 'STCS {:s}, i1'.format(reg_txt), 'STCS', - ] - self.cmd_insn_parts_nice = ['STCS', reg_txt] - self.cmd_insn_parts_terse = ['STCS', reg_txt_terse] - elif opcode == PDI.OP_REPEAT: - # REPEAT: sets repeat count for the next instruction. - # Reads repeat count from following bytes. - width_data = arg10 + 1 - self.insn_wr_counts = [width_data] - self.insn_rd_counts = [] - mnemonics = [ - 'Insn: REPEAT i{:d}'.format(width_data), - 'REPEAT i{:d}'.format(width_data), 'REP', - ] - self.cmd_insn_parts_nice = ['REPEAT'] - self.cmd_insn_parts_terse = ['REP'] - elif opcode == PDI.OP_KEY: - # KEY: set activation key (enables PDIBUS mmap access). - # Writes a sequence of 8 bytes, fixed length. - width_data = 8 - self.insn_wr_counts = [width_data] - self.insn_rd_counts = [] - mnemonics = [ - 'Insn: KEY i{:d}'.format(width_data), - 'KEY i{:d}'.format(width_data), 'KEY', - ] - self.cmd_insn_parts_nice = ['KEY'] - self.cmd_insn_parts_terse = ['KEY'] - - # Emit an annotation for the instruction opcode. - self.put_ann_row_val(ss, es, Ann.OPCODE, mnemonics) - - # Prepare to write/read operands/data bytes. - self.insn_dat_bytes = [] - if self.insn_wr_counts: - self.insn_dat_count = self.insn_wr_counts[0] - return - if self.insn_rd_counts: - self.insn_dat_count = self.insn_rd_counts[0] - return - # FALLTHROUGH. - # When there are no operands or data bytes to read, - # then fall through to the end of the instruction - # handling below (which emits annotations). - - # Read bytes which carry operands (addresses, immediates) - # or data values for memory access. - if self.insn_dat_count and not is_break: - - # Accumulate received bytes until another multi byte - # data item is complete. - if not self.insn_dat_bytes: - self.insn_ss_data = ss - self.insn_dat_bytes.append(byteval) - self.insn_dat_count -= 1 - if self.insn_dat_count: - return - - # Determine the data item's duration and direction, - # "consume" its length spec (to simplify later steps). - data_ss = self.insn_ss_data - data_es = es - if self.insn_wr_counts: - data_ann = Ann.DATA_PROG - data_width = self.insn_wr_counts.pop(0) - elif self.insn_rd_counts: - data_ann = Ann.DATA_DEV - data_width = self.insn_rd_counts.pop(0) - - # PDI communicates multi-byte data items in little endian - # order. Get a nice textual representation of the number, - # wide and narrow for several zoom levels. - self.insn_dat_bytes.reverse() - data_txt_digits = ''.join(['{:02x}'.format(b) for b in self.insn_dat_bytes]) - data_txt_hex = '0x' + data_txt_digits - data_txt_prefix = 'Data: ' + data_txt_hex - data_txts = [data_txt_prefix, data_txt_hex, data_txt_digits] - self.insn_dat_bytes = [] - - # Emit an annotation for the data value. - self.put_ann_row_val(data_ss, data_es, data_ann, data_txts) - - # Collect detailled information which describes the whole - # command when combined (for a next layer annotation, - # spanning the complete command). - self.cmd_insn_parts_nice.append(data_txt_hex) - self.cmd_insn_parts_terse.append(data_txt_digits) - - # Send out write data first until exhausted, - # then drain expected read data. - if self.insn_wr_counts: - self.insn_dat_count = self.insn_wr_counts[0] - return - if self.insn_rd_counts: - self.insn_dat_count = self.insn_rd_counts[0] - return - - # FALLTHROUGH. - # When all operands and data bytes were seen, - # terminate the inspection of the instruction. - - # Postprocess the instruction after its operands were seen. - cmd_es = es - cmd_txt_nice = ' '.join(self.cmd_insn_parts_nice) - cmd_txt_terse = ' '.join(self.cmd_insn_parts_terse) - cmd_txts = [cmd_txt_nice, cmd_txt_terse] - self.put_ann_row_val(self.cmd_ss, cmd_es, Ann.COMMAND, cmd_txts) - if self.insn_opcode == PDI.OP_REPEAT and not is_break: - # The last communicated data item is the repeat - # count for the next instruction (i.e. it will - # execute N+1 times when "REPEAT N" is specified). - count = int(self.cmd_insn_parts_nice[-1], 0) - self.insn_rep_count = count - - # Have the state for instruction decoding cleared, but make sure - # to carry over REPEAT count specs between instructions. They - # start out as zero, will be setup by REPEAT instructions, need - # to get passed to the instruction which follows REPEAT. The - # instruction which sees a non-zero repeat count which will - # consume the counter and drop it to zero, then the counter - # remains at zero until the next REPEAT instruction. - save_rep_count = self.insn_rep_count - self.clear_insn() - self.insn_rep_count = save_rep_count - - def handle_bits(self, ss, es, bitval): - '''Handle a bit at the UART layer.''' - - # Concentrate annotation literals here for easier maintenance. - ann_class_text = { - Ann.START: ['Start bit', 'Start', 'S'], - Ann.PARITY_OK: ['Parity OK', 'Par OK', 'P'], - Ann.PARITY_ERR: ['Parity error', 'Par ERR', 'PE'], - Ann.STOP_OK: ['Stop bit', 'Stop', 'T'], - Ann.STOP_ERR: ['Stop bit error', 'Stop ERR', 'TE'], - Ann.BREAK: ['Break condition', 'BREAK', 'BRK'], - } - def put_uart_field(bitpos, annclass): - self.put_ann_data(bitpos, [annclass, ann_class_text[annclass]]) - - # The number of bits which form one UART frame. Note that - # the decoder operates with only one stop bit. - frame_bitcount = 1 + 8 + 1 + 1 - - # Detect adjacent runs of all-zero bits. This is meant - # to cope when BREAK conditions appear at any arbitrary - # position, it need not be "aligned" to an UART frame. - if bitval == 1: - self.zero_count = 0 - elif bitval == 0: - if not self.zero_count: - self.zero_ss = ss - self.zero_count += 1 - if self.zero_count == frame_bitcount: - self.break_ss = self.zero_ss - - # BREAK conditions are _at_minimum_ the length of a UART frame, but - # can span an arbitrary number of bit times. Track the "end sample" - # value of the last low bit we have seen, and emit the annotation only - # after the line went idle (high) again. Pass BREAK to the upper layer - # as well. When the line is low, BREAK still is pending. When the line - # is high, the current bit cannot be START, thus return from here. - if self.break_ss is not None: - if bitval == '0': - self.break_es = es - return - self.put(self.break_ss, self.break_es, self.out_ann, - [Ann.BREAK, ann_class_text[Ann.BREAK]]) - self.handle_byte(self.break_ss, self.break_es, None) - self.break_ss = None - self.break_es = None - self.bits = [] - return - - # Ignore high bits when waiting for START. - if not self.bits and bitval == 1: - return - - # Store individual bits and their start/end sample numbers, - # until a complete frame was received. - self.bits.append(Bit(bitval, ss, es)) - if len(self.bits) < frame_bitcount: - return - - # Get individual fields of the UART frame. - bits_num = sum([b.val << pos for pos, b in enumerate(self.bits)]) - if False: - # This logic could detect BREAK conditions which are aligned to - # UART frames. Which was obsoleted by the above detection at - # arbitrary positions. The code still can be useful to detect - # "other kinds of frame errors" which carry valid symbols for - # upper layers (the Atmel literature suggests "break", "delay", - # and "empty" symbols when PDI is communicated over different - # physical layers). - if bits_num == 0: # BREAK - self.break_ss = self.bits[0].ss - self.break_es = es - self.bits = [] - return - start_bit = bits_num & 0x01; bits_num >>= 1 - data_val = bits_num & 0xff; bits_num >>= 8 - data_text = '{:02x}'.format(data_val) - parity_bit = bits_num & 0x01; bits_num >>= 1 - stop_bit = bits_num & 0x01; bits_num >>= 1 - - # Check for frame errors. START _must_ have been low - # according to the above accumulation logic. - parity_ok = (bin(data_val).count('1') + parity_bit) % 2 == 0 - stop_ok = stop_bit == 1 - valid_frame = parity_ok and stop_ok - - # Emit annotations. - for idx in range(frame_bitcount): - self.put_ann_bit(idx, Ann.BIT) - put_uart_field(0, Ann.START) - self.put(self.bits[1].ss, self.bits[8].es, self.out_ann, - [Ann.DATA, ['Data: ' + data_text, 'D: ' + data_text, data_text]]) - put_uart_field(9, Ann.PARITY_OK if parity_ok else Ann.PARITY_ERR) - put_uart_field(10, Ann.STOP_OK if stop_ok else Ann.STOP_ERR) - - # Emit binary data stream. Have bytes interpreted at higher layers. - if valid_frame: - byte_ss, byte_es = self.bits[0].ss, self.bits[-1].es - self.put_bin_bytes(byte_ss, byte_es, Ann.BIN_BYTES, bytes([data_val])) - self.handle_byte(byte_ss, byte_es, data_val) - - # Reset internal state for the next frame. - self.bits = [] - - def handle_clk_edge(self, clock_pin, data_pin): - # Sample the data line on rising clock edges. Always, for TX and for - # RX bytes alike. - if clock_pin == 1: - self.data_sample = data_pin - return - - # Falling clock edges are boundaries for bit slots. Inspect previously - # sampled bits on falling clock edges, when the start and end sample - # numbers were determined. Only inspect bit slots of known clock - # periods (avoid interpreting the DATA line when the "enabled" state - # has not yet been determined). - self.ss_last_fall = self.ss_curr_fall - self.ss_curr_fall = self.samplenum - if self.ss_last_fall is None: - return - - # Have the past bit slot processed. - bit_ss, bit_es = self.ss_last_fall, self.ss_curr_fall - bit_val = self.data_sample - self.handle_bits(bit_ss, bit_es, bit_val) - - def decode(self): - while True: - (clock_pin, data_pin) = self.wait({0: 'e'}) - self.handle_clk_edge(clock_pin, data_pin) diff --git a/decoders/caliper/__init__.py b/decoders/caliper/__init__.py deleted file mode 100644 index 44dab08b..00000000 --- a/decoders/caliper/__init__.py +++ /dev/null @@ -1,36 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 Tomas Mudrunka -## -## 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, see . -## - -''' -This decoder interprets the digital output of cheap generic calipers -(usually made in China), and shows the measured value in millimeters -or inches. - -Notice that these devices often communicate on voltage levels below -3.3V and may require additional circuitry to capture the signal. - -This decoder does not work for calipers using the Digimatic protocol -(eg. Mitutoyo and similar brands). - -For more information see: -http://www.shumatech.com/support/chinese_scales.htm -https://www.instructables.com/id/Reading-Digital-Callipers-with-an-Arduino-USB/ -''' - -from .pd import Decoder diff --git a/decoders/caliper/pd.py b/decoders/caliper/pd.py deleted file mode 100644 index 20a2a555..00000000 --- a/decoders/caliper/pd.py +++ /dev/null @@ -1,146 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 Tomas Mudrunka -## -## Permission is hereby granted, free of charge, to any person obtaining a copy -## of this software and associated documentation files (the "Software"), to deal -## in the Software without restriction, including without limitation the rights -## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -## copies of the Software, and to permit persons to whom the Software is -## furnished to do so, subject to the following conditions: -## -## The above copyright notice and this permission notice shall be included in all -## copies or substantial portions of the Software. -## -## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -## SOFTWARE. - -import sigrokdecode as srd -from common.srdhelper import bitpack - -# Millimeters per inch. -mm_per_inch = 25.4 - -class Decoder(srd.Decoder): - api_version = 3 - id = 'caliper' - name = 'Caliper' - longname = 'Digital calipers' - desc = 'Protocol of cheap generic digital calipers.' - license = 'mit' - inputs = ['logic'] - outputs = [] - channels = ( - {'id': 'clk', 'name': 'CLK', 'desc': 'Serial clock line'}, - {'id': 'data', 'name': 'DATA', 'desc': 'Serial data line'}, - ) - options = ( - {'id': 'timeout_ms', 'desc': 'Packet timeout in ms, 0 to disable', - 'default': 10}, - {'id': 'unit', 'desc': 'Convert units', 'default': 'keep', - 'values': ('keep', 'mm', 'inch')}, - {'id': 'changes', 'desc': 'Changes only', 'default': 'no', - 'values': ('no', 'yes')}, - ) - tags = ['Analog/digital', 'Sensor'] - annotations = ( - ('measurement', 'Measurement'), - ('warning', 'Warning'), - ) - annotation_rows = ( - ('measurements', 'Measurements', (0,)), - ('warnings', 'Warnings', (1,)), - ) - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def __init__(self): - self.reset() - - def reset(self): - self.ss, self.es = 0, 0 - self.number_bits = [] - self.flags_bits = [] - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putg(self, ss, es, cls, data): - self.put(ss, es, self.out_ann, [cls, data]) - - def decode(self): - last_sent = None - timeout_ms = self.options['timeout_ms'] - want_unit = self.options['unit'] - show_all = self.options['changes'] == 'no' - wait_cond = [{0: 'r'}] - if timeout_ms: - snum_per_ms = self.samplerate / 1000 - timeout_snum = timeout_ms * snum_per_ms - wait_cond.append({'skip': round(timeout_snum)}) - while True: - # Sample data at the rising clock edge. Optionally timeout - # after inactivity for a user specified period. Present the - # number of unprocessed bits to the user for diagnostics. - clk, data = self.wait(wait_cond) - if timeout_ms and not self.matched[0]: - if self.number_bits or self.flags_bits: - count = len(self.number_bits) + len(self.flags_bits) - self.putg(self.ss, self.samplenum, 1, [ - 'timeout with {} bits in buffer'.format(count), - 'timeout ({} bits)'.format(count), - 'timeout', - ]) - self.reset() - continue - - # Store position of first bit and last activity. - # Shift in measured number and flag bits. - if not self.ss: - self.ss = self.samplenum - self.es = self.samplenum - if len(self.number_bits) < 16: - self.number_bits.append(data) - continue - if len(self.flags_bits) < 8: - self.flags_bits.append(data) - if len(self.flags_bits) < 8: - continue - - # Get raw values from received data bits. Run the number - # conversion, controlled by flags and/or user specs. - negative = bool(self.flags_bits[4]) - is_inch = bool(self.flags_bits[7]) - number = bitpack(self.number_bits) - if negative: - number = -number - if is_inch: - number /= 2000 - if want_unit == 'mm': - number *= mm_per_inch - is_inch = False - else: - number /= 100 - if want_unit == 'inch': - number = round(number / mm_per_inch, 4) - is_inch = True - unit = 'in' if is_inch else 'mm' - - # Construct and emit an annotation. - if show_all or (number, unit) != last_sent: - self.putg(self.ss, self.es, 0, [ - '{number}{unit}'.format(**locals()), - '{number}'.format(**locals()), - ]) - last_sent = (number, unit) - - # Reset internal state for the start of the next packet. - self.reset() diff --git a/decoders/can/__init__.py b/decoders/can/__init__.py deleted file mode 100755 index 47f571d6..00000000 --- a/decoders/can/__init__.py +++ /dev/null @@ -1,29 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -''' -CAN (Controller Area Network) is a field bus protocol for distributed -real-time control. - -This decoder assumes that a single CAN_RX line is sampled (e.g. on -the digital output side of a CAN transceiver IC such as the Microchip -MCP-2515DM-BM). -''' - -from .pd import Decoder diff --git a/decoders/can/pd.py b/decoders/can/pd.py deleted file mode 100755 index 3e630ee1..00000000 --- a/decoders/can/pd.py +++ /dev/null @@ -1,415 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012-2013 Uwe Hermann -## Copyright (C) 2019 DreamSourceLab -## -## 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, see . -## - -import sigrokdecode as srd - -class SamplerateError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = 'can' - name = 'CAN' - longname = 'Controller Area Network' - desc = 'Field bus protocol for distributed realtime control.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Automotive'] - channels = ( - {'id': 'can_rx', 'name': 'CAN RX', 'desc': 'CAN bus line'}, - ) - options = ( - {'id': 'bitrate', 'desc': 'Bitrate (bits/s)', 'default': 1000000}, - {'id': 'sample_point', 'desc': 'Sample point (%)', 'default': 70.0}, - ) - annotations = ( - ('data', 'CAN payload data'), - ('sof', 'Start of frame'), - ('eof', 'End of frame'), - ('id', 'Identifier'), - ('ext-id', 'Extended identifier'), - ('full-id', 'Full identifier'), - ('ide', 'Identifier extension bit'), - ('reserved-bit', 'Reserved bit 0 and 1'), - ('rtr', 'Remote transmission request'), - ('srr', 'Substitute remote request'), - ('dlc', 'Data length count'), - ('crc-sequence', 'CRC sequence'), - ('crc-delimiter', 'CRC delimiter'), - ('ack-slot', 'ACK slot'), - ('ack-delimiter', 'ACK delimiter'), - ('stuff-bit', 'Stuff bit'), - ('warnings', 'Human-readable warnings'), - ('bit', 'Bit'), - ) - annotation_rows = ( - ('bits', 'Bits', (15, 17)), - ('fields', 'Fields', tuple(range(15))), - ('warnings', 'Warnings', (16,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.reset_variables() - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - self.bit_width = float(self.samplerate) / float(self.options['bitrate']) - self.sample_point = (self.bit_width / 100.0) * self.options['sample_point'] - - # Generic helper for CAN bit annotations. - def putg(self, ss, es, data): - left, right = int(self.sample_point), int(self.bit_width - self.sample_point) - self.put(ss - left, es + right, self.out_ann, data) - - # Single-CAN-bit annotation using the current samplenum. - def putx(self, data): - self.putg(self.samplenum, self.samplenum, data) - - # Single-CAN-bit annotation using the samplenum of CAN bit 12. - def put12(self, data): - self.putg(self.ss_bit12, self.ss_bit12, data) - - # Multi-CAN-bit annotation from self.ss_block to current samplenum. - def putb(self, data): - self.putg(self.ss_block, self.samplenum, data) - - def reset_variables(self): - self.state = 'IDLE' - self.sof = self.frame_type = self.dlc = None - self.rawbits = [] # All bits, including stuff bits - self.bits = [] # Only actual CAN frame bits (no stuff bits) - self.curbit = 0 # Current bit of CAN frame (bit 0 == SOF) - self.last_databit = 999 # Positive value that bitnum+x will never match - self.ss_block = None - self.ss_bit12 = None - self.ss_databytebits = [] - - # Poor man's clock synchronization. Use signal edges which change to - # dominant state in rather simple ways. This naive approach is neither - # aware of the SYNC phase's width nor the specific location of the edge, - # but improves the decoder's reliability when the input signal's bitrate - # does not exactly match the nominal rate. - def dom_edge_seen(self, force = False): - self.dom_edge_snum = self.samplenum - self.dom_edge_bcount = self.curbit - - def bit_sampled(self): - # EMPTY - pass - - # Determine the position of the next desired bit's sample point. - def get_sample_point(self, bitnum): - samplenum = self.dom_edge_snum - samplenum += int(self.bit_width * (bitnum - self.dom_edge_bcount)) - samplenum += int(self.sample_point) - return samplenum - - def is_stuff_bit(self): - # CAN uses NRZ encoding and bit stuffing. - # After 5 identical bits, a stuff bit of opposite value is added. - # But not in the CRC delimiter, ACK, and end of frame fields. - if len(self.bits) > self.last_databit + 17: - return False - last_6_bits = self.rawbits[-6:] - if last_6_bits not in ([0, 0, 0, 0, 0, 1], [1, 1, 1, 1, 1, 0]): - return False - - # Stuff bit. Keep it in self.rawbits, but drop it from self.bits. - self.bits.pop() # Drop last bit. - return True - - def is_valid_crc(self, crc_bits): - return True # TODO - - def decode_error_frame(self, bits): - pass # TODO - - def decode_overload_frame(self, bits): - pass # TODO - - # Both standard and extended frames end with CRC, CRC delimiter, ACK, - # ACK delimiter, and EOF fields. Handle them in a common function. - # Returns True if the frame ended (EOF), False otherwise. - def decode_frame_end(self, can_rx, bitnum): - - # Remember start of CRC sequence (see below). - if bitnum == (self.last_databit + 1): - self.ss_block = self.samplenum - - # CRC sequence (15 bits) - elif bitnum == (self.last_databit + 15): - x = self.last_databit + 1 - crc_bits = self.bits[x:x + 15 + 1] - self.crc = int(''.join(str(d) for d in crc_bits), 2) - self.putb([11, ['CRC sequence: 0x%04x' % self.crc, - 'CRC: 0x%04x' % self.crc, 'CRC']]) - if not self.is_valid_crc(crc_bits): - self.putb([16, ['CRC is invalid']]) - - # CRC delimiter bit (recessive) - elif bitnum == (self.last_databit + 16): - self.putx([12, ['CRC delimiter: %d' % can_rx, - 'CRC d: %d' % can_rx, 'CRC d']]) - if can_rx != 1: - self.putx([16, ['CRC delimiter must be a recessive bit']]) - - # ACK slot bit (dominant: ACK, recessive: NACK) - elif bitnum == (self.last_databit + 17): - ack = 'ACK' if can_rx == 0 else 'NACK' - self.putx([13, ['ACK slot: %s' % ack, 'ACK s: %s' % ack, 'ACK s']]) - - # ACK delimiter bit (recessive) - elif bitnum == (self.last_databit + 18): - self.putx([14, ['ACK delimiter: %d' % can_rx, - 'ACK d: %d' % can_rx, 'ACK d']]) - if can_rx != 1: - self.putx([16, ['ACK delimiter must be a recessive bit']]) - - # Remember start of EOF (see below). - elif bitnum == (self.last_databit + 19): - self.ss_block = self.samplenum - - # End of frame (EOF), 7 recessive bits - elif bitnum == (self.last_databit + 25): - self.putb([2, ['End of frame', 'EOF', 'E']]) - if self.rawbits[-7:] != [1, 1, 1, 1, 1, 1, 1]: - self.putb([16, ['End of frame (EOF) must be 7 recessive bits']]) - self.reset_variables() - return True - - return False - - # Returns True if the frame ended (EOF), False otherwise. - def decode_standard_frame(self, can_rx, bitnum): - - # Bit 14: RB0 (reserved bit) - # Has to be sent dominant, but receivers should accept recessive too. - if bitnum == 14: - self.putx([7, ['Reserved bit 0: %d' % can_rx, - 'RB0: %d' % can_rx, 'RB0']]) - - # Bit 12: Remote transmission request (RTR) bit - # Data frame: dominant, remote frame: recessive - # Remote frames do not contain a data field. - rtr = 'remote' if self.bits[12] == 1 else 'data' - self.put12([8, ['Remote transmission request: %s frame' % rtr, - 'RTR: %s frame' % rtr, 'RTR']]) - - # Remember start of DLC (see below). - elif bitnum == 15: - self.ss_block = self.samplenum - - # Bits 15-18: Data length code (DLC), in number of bytes (0-8). - elif bitnum == 18: - self.dlc = int(''.join(str(d) for d in self.bits[15:18 + 1]), 2) - self.putb([10, ['Data length code: %d' % self.dlc, - 'DLC: %d' % self.dlc, 'DLC']]) - self.last_databit = 18 + (self.dlc * 8) - if self.dlc > 8: - self.putb([16, ['Data length code (DLC) > 8 is not allowed']]) - - # Remember all databyte bits, except the very last one. - elif bitnum in range(19, self.last_databit): - self.ss_databytebits.append(self.samplenum) - - # Bits 19-X: Data field (0-8 bytes, depending on DLC) - # The bits within a data byte are transferred MSB-first. - elif bitnum == self.last_databit: - self.ss_databytebits.append(self.samplenum) # Last databyte bit. - for i in range(self.dlc): - x = 18 + (8 * i) + 1 - b = int(''.join(str(d) for d in self.bits[x:x + 8]), 2) - ss = self.ss_databytebits[i * 8] - es = self.ss_databytebits[((i + 1) * 8) - 1] - self.putg(ss, es, [0, ['Data byte %d: 0x%02x' % (i, b), - 'DB %d: 0x%02x' % (i, b), 'DB']]) - self.ss_databytebits = [] - - elif bitnum > self.last_databit: - return self.decode_frame_end(can_rx, bitnum) - - return False - - # Returns True if the frame ended (EOF), False otherwise. - def decode_extended_frame(self, can_rx, bitnum): - - # Remember start of EID (see below). - if bitnum == 14: - self.ss_block = self.samplenum - - # Bits 14-31: Extended identifier (EID[17..0]) - elif bitnum == 31: - self.eid = int(''.join(str(d) for d in self.bits[14:]), 2) - s = '%d (0x%x)' % (self.eid, self.eid) - self.putb([4, ['Extended Identifier: %s' % s, - 'Extended ID: %s' % s, 'Extended ID', 'EID']]) - - self.fullid = self.id << 18 | self.eid - s = '%d (0x%x)' % (self.fullid, self.fullid) - self.putb([5, ['Full Identifier: %s' % s, 'Full ID: %s' % s, - 'Full ID', 'FID']]) - - # Bit 12: Substitute remote request (SRR) bit - self.put12([9, ['Substitute remote request: %d' % self.bits[12], - 'SRR: %d' % self.bits[12], 'SRR']]) - - # Bit 32: Remote transmission request (RTR) bit - # Data frame: dominant, remote frame: recessive - # Remote frames do not contain a data field. - if bitnum == 32: - rtr = 'remote' if can_rx == 1 else 'data' - self.putx([8, ['Remote transmission request: %s frame' % rtr, - 'RTR: %s frame' % rtr, 'RTR']]) - - # Bit 33: RB1 (reserved bit) - elif bitnum == 33: - self.putx([7, ['Reserved bit 1: %d' % can_rx, - 'RB1: %d' % can_rx, 'RB1']]) - - # Bit 34: RB0 (reserved bit) - elif bitnum == 34: - self.putx([7, ['Reserved bit 0: %d' % can_rx, - 'RB0: %d' % can_rx, 'RB0']]) - - # Remember start of DLC (see below). - elif bitnum == 35: - self.ss_block = self.samplenum - - # Bits 35-38: Data length code (DLC), in number of bytes (0-8). - elif bitnum == 38: - self.dlc = int(''.join(str(d) for d in self.bits[35:38 + 1]), 2) - self.putb([10, ['Data length code: %d' % self.dlc, - 'DLC: %d' % self.dlc, 'DLC']]) - self.last_databit = 38 + (self.dlc * 8) - - # Remember all databyte bits, except the very last one. - elif bitnum in range(39, self.last_databit): - self.ss_databytebits.append(self.samplenum) - - # Bits 39-X: Data field (0-8 bytes, depending on DLC) - # The bits within a data byte are transferred MSB-first. - elif bitnum == self.last_databit: - self.ss_databytebits.append(self.samplenum) # Last databyte bit. - for i in range(self.dlc): - x = 38 + (8 * i) + 1 - b = int(''.join(str(d) for d in self.bits[x:x + 8]), 2) - ss = self.ss_databytebits[i * 8] - es = self.ss_databytebits[((i + 1) * 8) - 1] - self.putg(ss, es, [0, ['Data byte %d: 0x%02x' % (i, b), - 'DB %d: 0x%02x' % (i, b), 'DB']]) - self.ss_databytebits = [] - - elif bitnum > self.last_databit: - return self.decode_frame_end(can_rx, bitnum) - - return False - - def handle_bit(self, can_rx): - self.rawbits.append(can_rx) - self.bits.append(can_rx) - - # Get the index of the current CAN frame bit (without stuff bits). - bitnum = len(self.bits) - 1 - - # If this is a stuff bit, remove it from self.bits and ignore it. - if self.is_stuff_bit(): - self.putx([15, [str(can_rx)]]) - self.curbit += 1 # Increase self.curbit (bitnum is not affected). - return - else: - self.putx([17, [str(can_rx)]]) - - # Bit 0: Start of frame (SOF) bit - if bitnum == 0: - self.putx([1, ['Start of frame', 'SOF', 'S']]) - if can_rx != 0: - self.putx([16, ['Start of frame (SOF) must be a dominant bit']]) - - # Remember start of ID (see below). - elif bitnum == 1: - self.ss_block = self.samplenum - - # Bits 1-11: Identifier (ID[10..0]) - # The bits ID[10..4] must NOT be all recessive. - elif bitnum == 11: - self.id = int(''.join(str(d) for d in self.bits[1:]), 2) - s = '%d (0x%x)' % (self.id, self.id), - self.putb([3, ['Identifier: %s' % s, 'ID: %s' % s, 'ID']]) - if (self.id & 0x7f0) == 0x7f0: - self.putb([16, ['Identifier bits 10..4 must not be all recessive']]) - - # RTR or SRR bit, depending on frame type (gets handled later). - elif bitnum == 12: - # self.putx([0, ['RTR/SRR: %d' % can_rx]]) # Debug only. - self.ss_bit12 = self.samplenum - - # Bit 13: Identifier extension (IDE) bit - # Standard frame: dominant, extended frame: recessive - elif bitnum == 13: - ide = self.frame_type = 'standard' if can_rx == 0 else 'extended' - self.putx([6, ['Identifier extension bit: %s frame' % ide, - 'IDE: %s frame' % ide, 'IDE']]) - - # Bits 14-X: Frame-type dependent, passed to the resp. handlers. - elif bitnum >= 14: - if self.frame_type == 'standard': - done = self.decode_standard_frame(can_rx, bitnum) - else: - done = self.decode_extended_frame(can_rx, bitnum) - - # The handlers return True if a frame ended (EOF). - if done: - return - - # After a frame there are 3 intermission bits (recessive). - # After these bits, the bus is considered free. - - self.curbit += 1 - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - - while True: - # State machine. - if self.state == 'IDLE': - # Wait for a dominant state (logic 0) on the bus. - (can_rx,) = self.wait({0: 'l'}) - self.sof = self.samplenum - self.dom_edge_seen(force = True) - self.state = 'GET BITS' - elif self.state == 'GET BITS': - # Wait until we're in the correct bit/sampling position. - pos = self.get_sample_point(self.curbit) - (can_rx,) = self.wait([{'skip': pos - self.samplenum}, {0: 'f'}]) - if (self.matched & (0b1 << 1)): - self.dom_edge_seen() - if (self.matched & (0b1 << 0)): - self.handle_bit(can_rx) - self.bit_sampled() diff --git a/decoders/cc1101/__init__.py b/decoders/cc1101/__init__.py deleted file mode 100644 index 68fc7987..00000000 --- a/decoders/cc1101/__init__.py +++ /dev/null @@ -1,28 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Marco Geisler -## -## 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, see . -## - -''' -This decoder stacks on top of the 'spi' PD and decodes the protocol spoken -by the Texas Instruments low-power sub-1GHz RF transceiver chips. - -Details: -http://www.ti.com/lit/ds/symlink/cc1101.pdf -''' - -from .pd import Decoder diff --git a/decoders/cc1101/lists.py b/decoders/cc1101/lists.py deleted file mode 100644 index dfb9b07f..00000000 --- a/decoders/cc1101/lists.py +++ /dev/null @@ -1,115 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Marco Geisler -## -## 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, see . -## - -regs = { -# addr: 'name' - 0x00: 'IOCFG2', - 0x01: 'IOCFG1', - 0x02: 'IOCFG0', - 0x03: 'FIFOTHR', - 0x04: 'SYNC1', - 0x05: 'SYNC0', - 0x06: 'PKTLEN', - 0x07: 'PKTCTRL1', - 0x08: 'PKTCTRL0', - 0x09: 'ADDR', - 0x0A: 'CHANNR', - 0x0B: 'FSCTRL1', - 0x0C: 'FSCTRL0', - 0x0D: 'FREQ2', - 0x0E: 'FREQ1', - 0x0F: 'FREQ0', - 0x10: 'MDMCFG4', - 0x11: 'MDMCFG3', - 0x12: 'MDMCFG2', - 0x13: 'MDMCFG1', - 0x14: 'MDMCFG0', - 0x15: 'DEVIATN', - 0x16: 'MCSM2', - 0x17: 'MCSM1', - 0x18: 'MCSM0', - 0x19: 'FOCCFG', - 0x1A: 'BSCFG', - 0x1B: 'AGCTRL2', - 0x1C: 'AGCTRL1', - 0x1D: 'AGCTRL0', - 0x1E: 'WOREVT1', - 0x1F: 'WOREVT0', - 0x20: 'WORCTRL', - 0x21: 'FREND1', - 0x22: 'FREND0', - 0x23: 'FSCAL3', - 0x24: 'FSCAL2', - 0x25: 'FSCAL1', - 0x26: 'FSCAL0', - 0x27: 'RCCTRL1', - 0x28: 'RCCTRL0', - 0x29: 'FSTEST', - 0x2A: 'PTEST', - 0x2B: 'AGCTEST', - 0x2C: 'TEST2', - 0x2D: 'TEST1', - 0x2E: 'TEST0', - 0x30: 'PARTNUM', - 0x31: 'VERSION', - 0x32: 'FREQEST', - 0x33: 'LQI', - 0x34: 'RSSI', - 0x35: 'MARCSTATE', - 0x36: 'WORTIME1', - 0x37: 'WORTIME0', - 0x38: 'PKTSTATUS', - 0x39: 'VCO_VC_DAC', - 0x3A: 'TXBYTES', - 0x3B: 'RXBYTES', - 0x3C: 'RCCTRL1_STATUS', - 0x3D: 'RCCTRL0_STATUS', - 0x3E: 'PATABLE', - 0x3F: 'FIFO' -} - -strobes = { -# addr: 'name' - 0x30: 'SRES', - 0x31: 'SFSTXON', - 0x32: 'SXOFF', - 0x33: 'SCAL', - 0x34: 'SRX', - 0x35: 'STX', - 0x36: 'SIDLE', - 0x37: '', - 0x38: 'SWOR', - 0x39: 'SPWD', - 0x3A: 'SFRX', - 0x3B: 'SFTX', - 0x3C: 'SWORRST', - 0x3D: 'SNOP' -} - -status_reg_states = { -# value: 'state name' - 0b000: 'IDLE', - 0b001: 'RX', - 0b010: 'TX', - 0b011: 'FSTXON', - 0b100: 'CALIBRATE', - 0b101: 'SETTLING', - 0b110: 'RXFIFO_OVERFLOW', - 0b111: 'TXFIFO_OVERFLOW' -} diff --git a/decoders/cc1101/pd.py b/decoders/cc1101/pd.py deleted file mode 100644 index 8407b510..00000000 --- a/decoders/cc1101/pd.py +++ /dev/null @@ -1,296 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Marco Geisler -## -## 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, see . -## - -import sigrokdecode as srd -from collections import namedtuple -from .lists import * - -ANN_STROBE, ANN_SINGLE_READ, ANN_SINGLE_WRITE, ANN_BURST_READ, \ - ANN_BURST_WRITE, ANN_STATUS_READ, ANN_STATUS, ANN_WARN = range(8) - -Pos = namedtuple('Pos', ['ss', 'es']) -Data = namedtuple('Data', ['mosi', 'miso']) - -class ChannelError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = 'cc1101' - name = 'CC1101' - longname = 'Texas Instruments CC1101' - desc = 'Low-power sub-1GHz RF transceiver chip.' - license = 'gplv2+' - inputs = ['spi'] - outputs = [] - tags = ['IC', 'Wireless/RF'] - annotations = ( - ('strobe', 'Command strobe'), - ('single_read', 'Single register read'), - ('single_write', 'Single register write'), - ('burst_read', 'Burst register read'), - ('burst_write', 'Burst register write'), - ('status', 'Status register'), - ('warning', 'Warning'), - ) - annotation_rows = ( - ('cmd', 'Commands', (ANN_STROBE,)), - ('data', 'Data', (ANN_SINGLE_READ, ANN_SINGLE_WRITE, ANN_BURST_READ, - ANN_BURST_WRITE, ANN_STATUS_READ)), - ('status', 'Status register', (ANN_STATUS,)), - ('warnings', 'Warnings', (ANN_WARN,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.next() - self.requirements_met = True - self.cs_was_released = False - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def warn(self, pos, msg): - '''Put a warning message 'msg' at 'pos'.''' - self.put(pos.ss, pos.es, self.out_ann, [ANN_WARN, [msg]]) - - def putp(self, pos, ann, msg): - '''Put an annotation message 'msg' at 'pos'.''' - self.put(pos.ss, pos.es, self.out_ann, [ann, [msg]]) - - def putp2(self, pos, ann, msg1, msg2): - '''Put an annotation message 'msg' at 'pos'.''' - self.put(pos.ss, pos.es, self.out_ann, [ann, [msg1, msg2]]) - - def next(self): - '''Resets the decoder after a complete command was decoded.''' - # 'True' for the first byte after CS# went low. - self.first = True - - # The current command, and the minimum and maximum number - # of data bytes to follow. - self.cmd = None - self.min = 0 - self.max = 0 - - # Used to collect the bytes after the command byte - # (and the start/end sample number). - self.mb = [] - self.ss_mb = -1 - self.es_mb = -1 - - def mosi_bytes(self): - '''Returns the collected MOSI bytes of a multi byte command.''' - return [b.mosi for b in self.mb] - - def miso_bytes(self): - '''Returns the collected MISO bytes of a multi byte command.''' - return [b.miso for b in self.mb] - - def decode_command(self, pos, b): - '''Decodes the command byte 'b' at position 'pos' and prepares - the decoding of the following data bytes.''' - c = self.parse_command(b) - if c is None: - self.warn(pos, 'unknown command') - return - - self.cmd, self.dat, self.min, self.max = c - - if self.cmd == 'Strobe': - self.putp(pos, ANN_STROBE, self.format_command()) - else: - # Don't output anything now, the command is merged with - # the data bytes following it. - self.ss_mb = pos.ss - - def format_command(self): - '''Returns the label for the current command.''' - if self.cmd in ('Read', 'Burst read', 'Write', 'Burst write', 'Status read'): - return self.cmd - if self.cmd == 'Strobe': - reg = strobes.get(self.dat, 'unknown strobe') - return '{} {}'.format(self.cmd, reg) - else: - return 'TODO Cmd {}'.format(self.cmd) - - def parse_command(self, b): - '''Parses the command byte. - - Returns a tuple consisting of: - - the name of the command - - additional data needed to dissect the following bytes - - minimum number of following bytes - - maximum number of following bytes (None for infinite) - ''' - - addr = b & 0x3F - if (addr < 0x30) or (addr == 0x3E) or (addr == 0x3F): - if (b & 0xC0) == 0x00: - return ('Write', addr, 1, 1) - if (b & 0xC0) == 0x40: - return ('Burst write', addr, 1, 99999) - if (b & 0xC0) == 0x80: - return ('Read', addr, 1, 1) - if (b & 0xC0) == 0xC0: - return ('Burst read', addr, 1, 99999) - else: - self.warn(pos, 'unknown address/command combination') - else: - if (b & 0x40) == 0x00: - return ('Strobe', addr, 0, 0) - if (b & 0xC0) == 0xC0: - return ('Status read', addr, 1, 99999) - else: - self.warn(pos, 'unknown address/command combination') - - def decode_reg(self, pos, ann, regid, data): - '''Decodes a register. - - pos -- start and end sample numbers of the register - ann -- the annotation number that is used to output the register. - regid -- may be either an integer used as a key for the 'regs' - dictionary, or a string directly containing a register name.' - data -- the register content. - ''' - - if type(regid) == int: - # Get the name of the register. - if regid not in regs: - self.warn(pos, 'unknown register') - return - name = '{} ({:02X})'.format(regs[regid], regid) - else: - name = regid - - if regid == 'STATUS' and ann == ANN_STATUS: - label = 'Status' - self.decode_status_reg(pos, ann, data, label) - else: - if self.cmd in ('Write', 'Read', 'Status read', 'Burst read', 'Burst write'): - label = '{}: {}'.format(self.format_command(), name) - else: - label = 'Reg ({}) {}'.format(self.cmd, name) - self.decode_mb_data(pos, ann, data, label) - - def decode_status_reg(self, pos, ann, data, label): - '''Decodes the data bytes 'data' of a status register at position - 'pos'. The decoded data is prefixed with 'label'.''' - status = data[0] - # bit 7 --> CHIP_RDYn - if status & 0b10000000 == 0b10000000: - longtext_chiprdy = 'CHIP_RDYn is high! ' - else: - longtext_chiprdy = '' - # bits 6:4 --> STATE - state = (status & 0x70) >> 4 - longtext_state = 'STATE is {}, '.format(status_reg_states[state]) - # bits 3:0 --> FIFO_BYTES_AVAILABLE - fifo_bytes = status & 0x0F - if self.cmd in ('Single read', 'Status read', 'Burst read'): - longtext_fifo = '{} bytes available in RX FIFO'.format(fifo_bytes) - else: - longtext_fifo = '{} bytes free in TX FIFO'.format(fifo_bytes) - - text = '{} = {:02X}'.format(label, status) - longtext = ''.join([text, '; ', longtext_chiprdy, longtext_state, longtext_fifo]) - self.putp2(pos, ann, longtext, text) - - def decode_mb_data(self, pos, ann, data, label): - '''Decodes the data bytes 'data' of a multibyte command at position - 'pos'. The decoded data is prefixed with 'label'.''' - - def escape(b): - return '{:02X}'.format(b) - - data = ' '.join([escape(b) for b in data]) - text = '{} = {}'.format(label, data) - self.putp(pos, ann, text) - - def finish_command(self, pos): - '''Decodes the remaining data bytes at position 'pos'.''' - - if self.cmd == 'Write': - self.decode_reg(pos, ANN_SINGLE_WRITE, self.dat, self.mosi_bytes()) - elif self.cmd == 'Burst write': - self.decode_reg(pos, ANN_BURST_WRITE, self.dat, self.mosi_bytes()) - elif self.cmd == 'Read': - self.decode_reg(pos, ANN_SINGLE_READ, self.dat, self.miso_bytes()) - elif self.cmd == 'Burst read': - self.decode_reg(pos, ANN_BURST_READ, self.dat, self.miso_bytes()) - elif self.cmd == 'Strobe': - self.decode_reg(pos, ANN_STROBE, self.dat, self.mosi_bytes()) - elif self.cmd == 'Status read': - self.decode_reg(pos, ANN_STATUS_READ, self.dat, self.miso_bytes()) - else: - self.warn(pos, 'unhandled command') - - def decode(self, ss, es, data): - if not self.requirements_met: - return - - ptype, data1, data2 = data - - if ptype == 'CS-CHANGE': - if data1 is None: - if data2 is None: - self.requirements_met = False - raise ChannelError('CS# pin required.') - elif data2 == 1: - self.cs_was_released = True - - if data1 == 0 and data2 == 1: - # Rising edge, the complete command is transmitted, process - # the bytes that were sent after the command byte. - if self.cmd: - # Check if we got the minimum number of data bytes - # after the command byte. - if len(self.mb) < self.min: - self.warn((ss, ss), 'missing data bytes') - elif self.mb: - self.finish_command(Pos(self.ss_mb, self.es_mb)) - - self.next() - self.cs_was_released = True - - elif ptype == 'DATA' and self.cs_was_released: - mosi, miso = data1, data2 - pos = Pos(ss, es) - - if miso is None or mosi is None: - self.requirements_met = False - raise ChannelError('Both MISO and MOSI pins required.') - - if self.first: - self.first = False - # First MOSI byte is always the command. - self.decode_command(pos, mosi) - # First MISO byte is always the status register. - self.decode_reg(pos, ANN_STATUS, 'STATUS', [miso]) - else: - if not self.cmd or len(self.mb) >= self.max: - self.warn(pos, 'excess byte') - else: - # Collect the bytes after the command byte. - if self.ss_mb == -1: - self.ss_mb = ss - self.es_mb = es - self.mb.append(Data(mosi, miso)) diff --git a/decoders/cec/__init__.py b/decoders/cec/__init__.py deleted file mode 100755 index 4138b62b..00000000 --- a/decoders/cec/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Jorge Solla Rubiales -## -## 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, see . -## - -''' -The Consumer Electronics Control (CEC) protocol allows users to command and -control devices connected through HDMI. -''' - -from .pd import Decoder diff --git a/decoders/cec/pd.py b/decoders/cec/pd.py deleted file mode 100755 index 363a0497..00000000 --- a/decoders/cec/pd.py +++ /dev/null @@ -1,312 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Jorge Solla Rubiales -## Copyright (C) 2019 DreamSourceLab -## -## 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, see . -## - -import sigrokdecode as srd -from .protocoldata import * - -# Pulse types -class Pulse: - INVALID, START, ZERO, ONE = range(4) - -# Protocol stats -class Stat: - WAIT_START, GET_BITS, WAIT_EOM, WAIT_ACK = range(4) - -# Pulse times in milliseconds -timing = { - Pulse.START: { - 'low': { 'min': 3.5, 'max': 3.9 }, - 'total': { 'min': 4.3, 'max': 4.7 } - }, - Pulse.ZERO: { - 'low': { 'min': 1.3, 'max': 1.7 }, - 'total': { 'min': 2.05, 'max': 2.75 } - }, - Pulse.ONE: { - 'low': { 'min': 0.4, 'max': 0.8 }, - 'total': { 'min': 2.05, 'max': 2.75 } - } -} - -class ChannelError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = 'cec' - name = 'CEC' - longname = 'HDMI-CEC' - desc = 'HDMI Consumer Electronics Control (CEC) protocol.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Display', 'PC'] - channels = ( - {'id': 'cec', 'name': 'CEC', 'desc': 'CEC bus data'}, - ) - annotations = ( - ('st', 'Start'), - ('eom-0', 'End of message'), - ('eom-1', 'Message continued'), - ('nack', 'ACK not set'), - ('ack', 'ACK set'), - ('bits', 'Bits'), - ('bytes', 'Bytes'), - ('frames', 'Frames'), - ('sections', 'Sections'), - ('warnings', 'Warnings') - ) - annotation_rows = ( - ('bits', 'Bits', (0, 1, 2, 3, 4, 5)), - ('bytes', 'Bytes', (6,)), - ('frames', 'Frames', (7,)), - ('sections', 'Sections', (8,)), - ('warnings', 'Warnings', (9,)) - ) - - def __init__(self): - self.reset() - - def precalculate(self): - # Restrict max length of ACK/NACK labels to 2 BIT pulses. - bit_time = timing[Pulse.ZERO]['total']['min'] * 2 - self.max_ack_len_samples = round((bit_time / 1000) * self.samplerate) - - def reset(self): - self.stat = Stat.WAIT_START - self.samplerate = None - self.fall_start = None - self.fall_end = None - self.rise = None - self.reset_frame_vars() - - def reset_frame_vars(self): - self.eom = None - self.bit_count = 0 - self.byte_count = 0 - self.byte = 0 - self.byte_start = None - self.frame_start = None - self.frame_end = None - self.is_nack = 0 - self.cmd_bytes = [] - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - self.precalculate() - - def handle_frame(self, is_nack): - if self.fall_start is None or self.fall_end is None: - return - - i = 0 - string = '' - while i < len(self.cmd_bytes): - string += '{:02x}'.format(self.cmd_bytes[i]['val']) - if i != (len(self.cmd_bytes) - 1): - string += ':' - i += 1 - - self.put(self.frame_start, self.frame_end, self.out_ann, [7, [string]]) - - i = 0 - operands = 0 - string = '' - while i < len(self.cmd_bytes): - if i == 0: # Parse header - (src, dst) = decode_header(self.cmd_bytes[i]['val']) - string = 'HDR: ' + src + ', ' + dst - elif i == 1: # Parse opcode - string += ' | OPC: ' + opcodes.get(self.cmd_bytes[i]['val'], 'Invalid') - else: # Parse operands - if operands == 0: - string += ' | OPS: ' - operands += 1 - string += '0x{:02x}'.format(self.cmd_bytes[i]['val']) - if i != len(self.cmd_bytes) - 1: - string += ', ' - i += 1 - - # Header only commands are PINGS - if i == 1: - string += ' | OPC: PING' if self.eom else ' | OPC: NONE. Aborted cmd' - - # Add extra information (ack of the command from the destination) - string += ' | R: NACK' if is_nack else ' | R: ACK' - - self.put(self.frame_start, self.frame_end, self.out_ann, [8, [string]]) - - def process(self): - zero_time = ((self.rise - self.fall_start) / self.samplerate) * 1000.0 - total_time = ((self.fall_end - self.fall_start) / self.samplerate) * 1000.0 - pulse = Pulse.INVALID - - # VALIDATION: Identify pulse based on length of the low period - for key in timing: - if zero_time >= timing[key]['low']['min'] and zero_time <= timing[key]['low']['max']: - pulse = key - break - - # VALIDATION: Invalid pulse - if pulse == Pulse.INVALID: - self.stat = Stat.WAIT_START - self.put(self.fall_start, self.fall_end, self.out_ann, [9, ['Invalid pulse: Wrong timing']]) - return - - # VALIDATION: If waiting for start, discard everything else - if self.stat == Stat.WAIT_START and pulse != Pulse.START: - self.put(self.fall_start, self.fall_end, self.out_ann, [9, ['Expected START: BIT found']]) - return - - # VALIDATION: If waiting for ACK or EOM, only BIT pulses (0/1) are expected - if (self.stat == Stat.WAIT_ACK or self.stat == Stat.WAIT_EOM) and pulse == Pulse.START: - self.put(self.fall_start, self.fall_end, self.out_ann, [9, ['Expected BIT: START received)']]) - self.stat = Stat.WAIT_START - - # VALIDATION: ACK bit pulse remains high till the next frame (if any): Validate only min time of the low period - if self.stat == Stat.WAIT_ACK and pulse != Pulse.START: - if total_time < timing[pulse]['total']['min']: - pulse = Pulse.INVALID - self.put(self.fall_start, self.fall_end, self.out_ann, [9, ['ACK pulse below minimun time']]) - self.stat = Stat.WAIT_START - return - - # VALIDATION / PING FRAME DETECTION: Initiator doesn't sets the EOM = 1 but stops sending when ack doesn't arrive - if self.stat == Stat.GET_BITS and pulse == Pulse.START: - # Make sure we received a complete byte to consider it a valid ping - if self.bit_count == 0: - self.handle_frame(self.is_nack) - else: - self.put(self.frame_start, self.samplenum, self.out_ann, [9, ['ERROR: Incomplete byte received']]) - - # Set wait start so we receive next frame - self.stat = Stat.WAIT_START - - # VALIDATION: Check timing of the BIT (0/1) pulse in any other case (not waiting for ACK) - if self.stat != Stat.WAIT_ACK and pulse != Pulse.START: - if total_time < timing[pulse]['total']['min'] or total_time > timing[pulse]['total']['max']: - self.put(self.fall_start, self.fall_end, self.out_ann, [9, ['Bit pulse exceeds total pulse timespan']]) - pulse = Pulse.INVALID - self.stat = Stat.WAIT_START - return - - if pulse == Pulse.ZERO: - bit = 0 - elif pulse == Pulse.ONE: - bit = 1 - - # STATE: WAIT START - if self.stat == Stat.WAIT_START: - self.stat = Stat.GET_BITS - self.reset_frame_vars() - self.put(self.fall_start, self.fall_end, self.out_ann, [0, ['ST']]) - - # STATE: GET BITS - elif self.stat == Stat.GET_BITS: - # Reset stats on first bit - if self.bit_count == 0: - self.byte_start = self.fall_start - self.byte = 0 - - # If 1st byte of the datagram save its sample num - if len(self.cmd_bytes) == 0: - self.frame_start = self.fall_start - - self.byte += (bit << (7 - self.bit_count)) - self.bit_count += 1 - self.put(self.fall_start, self.fall_end, self.out_ann, [5, [str(bit)]]) - - if self.bit_count == 8: - self.bit_count = 0 - self.byte_count += 1 - self.stat = Stat.WAIT_EOM - self.put(self.byte_start, self.samplenum, self.out_ann, [6, ['0x{:02x}'.format(self.byte)]]) - self.cmd_bytes.append({'st': self.byte_start, 'ed': self.samplenum, 'val': self.byte}) - - # STATE: WAIT EOM - elif self.stat == Stat.WAIT_EOM: - self.eom = bit - self.frame_end = self.fall_end - - a = [2, ['EOM=Y']] if self.eom else [1, ['EOM=N']] - self.put(self.fall_start, self.fall_end, self.out_ann, a) - - self.stat = Stat.WAIT_ACK - - # STATE: WAIT ACK - elif self.stat == Stat.WAIT_ACK: - # If a frame with broadcast destination is being sent, the ACK is - # inverted: a 0 is considered a NACK, therefore we invert the value - # of the bit here, so we match the real meaning of it. - if (self.cmd_bytes[0]['val'] & 0x0F) == 0x0F: - bit = ~bit & 0x01 - - if (self.fall_end - self.fall_start) > self.max_ack_len_samples: - ann_end = self.fall_start + self.max_ack_len_samples - else: - ann_end = self.fall_end - - if bit: - # Any NACK detected in the frame is enough to consider the - # whole frame NACK'd. - self.is_nack = 1 - self.put(self.fall_start, ann_end, self.out_ann, [3, ['NACK']]) - else: - self.put(self.fall_start, ann_end, self.out_ann, [4, ['ACK']]) - - # After ACK bit, wait for new datagram or continue reading current - # one based on EOM value. - if self.eom or self.is_nack: - self.stat = Stat.WAIT_START - self.handle_frame(self.is_nack) - else: - self.stat = Stat.GET_BITS - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - - # Wait for first falling edge. - self.wait({0: 'f'}) - self.fall_end = self.samplenum - - while True: - self.wait({0: 'r'}) - self.rise = self.samplenum - - if self.stat == Stat.WAIT_ACK: - self.wait([{0: 'f'}, {'skip': self.max_ack_len_samples}]) - else: - self.wait([{0: 'f'}]) - - self.fall_start = self.fall_end - self.fall_end = self.samplenum - self.process() - - # If there was a timeout while waiting for ACK: RESYNC. - # Note: This is an expected situation as no new falling edge will - # happen until next frame is transmitted. - if self.matched == 0b10: - self.wait({0: 'f'}) - self.fall_end = self.samplenum diff --git a/decoders/cec/protocoldata.py b/decoders/cec/protocoldata.py deleted file mode 100755 index 78c3b6f5..00000000 --- a/decoders/cec/protocoldata.py +++ /dev/null @@ -1,117 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Jorge Solla Rubiales -## -## 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, see . -## - -logical_adresses = [ - 'TV', - 'Recording_1', - 'Recording_2', - 'Tuner_1', - 'Playback_1', - 'AudioSystem', - 'Tuner2', - 'Tuner3', - 'Playback_2', - 'Recording_3', - 'Tuner_4', - 'Playback_3', - 'Backup_1', - 'Backup_2', - 'FreeUse', -] - -# List taken from LibCEC. -opcodes = { - 0x82: 'ACTIVE_SOURCE', - 0x04: 'IMAGE_VIEW_ON', - 0x0D: 'TEXT_VIEW_ON', - 0x9D: 'INACTIVE_SOURCE', - 0x85: 'REQUEST_ACTIVE_SOURCE', - 0x80: 'ROUTING_CHANGE', - 0x81: 'ROUTING_INFORMATION', - 0x86: 'SET_STREAM_PATH', - 0x36: 'STANDBY', - 0x0B: 'RECORD_OFF', - 0x09: 'RECORD_ON', - 0x0A: 'RECORD_STATUS', - 0x0F: 'RECORD_TV_SCREEN', - 0x33: 'CLEAR_ANALOGUE_TIMER', - 0x99: 'CLEAR_DIGITAL_TIMER', - 0xA1: 'CLEAR_EXTERNAL_TIMER', - 0x34: 'SET_ANALOGUE_TIMER', - 0x97: 'SET_DIGITAL_TIMER', - 0xA2: 'SET_EXTERNAL_TIMER', - 0x67: 'SET_TIMER_PROGRAM_TITLE', - 0x43: 'TIMER_CLEARED_STATUS', - 0x35: 'TIMER_STATUS', - 0x9E: 'CEC_VERSION', - 0x9F: 'GET_CEC_VERSION', - 0x83: 'GIVE_PHYSICAL_ADDRESS', - 0x91: 'GET_MENU_LANGUAGE', - 0x84: 'REPORT_PHYSICAL_ADDRESS', - 0x32: 'SET_MENU_LANGUAGE', - 0x42: 'DECK_CONTROL', - 0x1B: 'DECK_STATUS', - 0x1A: 'GIVE_DECK_STATUS', - 0x41: 'PLAY', - 0x08: 'GIVE_TUNER_DEVICE_STATUS', - 0x92: 'SELECT_ANALOGUE_SERVICE', - 0x93: 'SELECT_DIGITAL_SERVICE', - 0x07: 'TUNER_DEVICE_STATUS', - 0x06: 'TUNER_STEP_DECREMENT', - 0x05: 'TUNER_STEP_INCREMENT', - 0x87: 'DEVICE_VENDOR_ID', - 0x8C: 'GIVE_DEVICE_VENDOR_ID', - 0x89: 'VENDOR_COMMAND', - 0xA0: 'VENDOR_COMMAND_WITH_ID', - 0x8A: 'VENDOR_REMOTE_BUTTON_DOWN', - 0x8B: 'VENDOR_REMOTE_BUTTON_UP', - 0x64: 'SET_OSD_STRING', - 0x46: 'GIVE_OSD_NAME', - 0x47: 'SET_OSD_NAME', - 0x8D: 'MENU_REQUEST', - 0x8E: 'MENU_STATUS', - 0x44: 'USER_CONTROL_PRESSED', - 0x45: 'USER_CONTROL_RELEASE', - 0x8F: 'GIVE_DEVICE_POWER_STATUS', - 0x90: 'REPORT_POWER_STATUS', - 0x00: 'FEATURE_ABORT', - 0xFF: 'ABORT', - 0x71: 'GIVE_AUDIO_STATUS', - 0x7D: 'GIVE_SYSTEM_AUDIO_MODE_STATUS', - 0x7A: 'REPORT_AUDIO_STATUS', - 0x72: 'SET_SYSTEM_AUDIO_MODE', - 0x70: 'SYSTEM_AUDIO_MODE_REQUEST', - 0x7E: 'SYSTEM_AUDIO_MODE_STATUS', - 0x9A: 'SET_AUDIO_RATE', -} - -def resolve_logical_address(id_, is_initiator): - if id_ < 0 or id_ > 0x0F: - return 'Invalid' - - # Special handling of 0x0F. - if id_ == 0x0F: - return 'Unregistered' if is_initiator else 'Broadcast' - - return logical_adresses[id_] - -def decode_header(header): - src = (header & 0xF0) >> 4 - dst = (header & 0x0F) - return (resolve_logical_address(src, 1), resolve_logical_address(dst, 0)) diff --git a/decoders/cfp/__init__.py b/decoders/cfp/__init__.py deleted file mode 100755 index 351e893b..00000000 --- a/decoders/cfp/__init__.py +++ /dev/null @@ -1,34 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Elias Oenal -## All rights reserved. -## -## Redistribution and use in source and binary forms, with or without -## modification, are permitted provided that the following conditions are met: -## -## 1. Redistributions of source code must retain the above copyright notice, -## this list of conditions and the following disclaimer. -## 2. Redistributions in binary form must reproduce the above copyright notice, -## this list of conditions and the following disclaimer in the documentation -## and/or other materials provided with the distribution. -## -## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -## ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -## LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -## POSSIBILITY OF SUCH DAMAGE. -## - -''' -This decoder stacks on top of the 'mdio' PD and decodes the CFP 100G -pluggable transceiver protocol. -''' - -from .pd import Decoder diff --git a/decoders/cfp/pd.py b/decoders/cfp/pd.py deleted file mode 100755 index 9638ba19..00000000 --- a/decoders/cfp/pd.py +++ /dev/null @@ -1,110 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Elias Oenal -## All rights reserved. -## -## Redistribution and use in source and binary forms, with or without -## modification, are permitted provided that the following conditions are met: -## -## 1. Redistributions of source code must retain the above copyright notice, -## this list of conditions and the following disclaimer. -## 2. Redistributions in binary form must reproduce the above copyright notice, -## this list of conditions and the following disclaimer in the documentation -## and/or other materials provided with the distribution. -## -## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -## ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -## LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -## POSSIBILITY OF SUCH DAMAGE. -## - -import sigrokdecode as srd - -MODULE_ID = { - 0x00: 'Unknown or unspecified', - 0x01: 'GBIC', - 0x02: 'Module/connector soldered to motherboard', - 0x03: 'SFP', - 0x04: '300 pin XSBI', - 0x05: 'XENPAK', - 0x06: 'XFP', - 0x07: 'XFF', - 0x08: 'XFP-E', - 0x09: 'XPAK', - 0x0a: 'X2', - 0x0B: 'DWDM-SFP', - 0x0C: 'QSFP', - 0x0D: 'QSFP+', - 0x0E: 'CFP', - 0x0F: 'CXP (TBD)', - 0x11: 'CFP2', - 0x12: 'CFP4', -} - -class Decoder(srd.Decoder): - api_version = 3 - id = 'cfp' - name = 'CFP' - longname = '100 Gigabit C form-factor pluggable' - desc = '100 Gigabit C form-factor pluggable (CFP) protocol.' - license = 'BSD' - inputs = ['mdio'] - outputs = [] - tags = ['Networking'] - annotations = ( - ('register', 'Register'), - ('decode', 'Decode'), - ) - annotation_rows = ( - ('registers', 'Registers', (0,)), - ('decodes', 'Decodes', (1,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - pass - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putx(self, data): - self.put(self.ss, self.es, self.out_ann, data) - - def decode(self, ss, es, data): - self.ss, self.es = ss, es - for (clause45, clause45_addr, is_read, portad, devad, reg) in data: - if not is_read: - continue - if clause45_addr in range(0x8000, 0x807F + 1): - self.putx([0, ['CFP NVR 1: Basic ID register', 'NVR1']]) - if clause45_addr == 0x8000: - self.putx([1, ['Module identifier: %s' % \ - MODULE_ID.get(reg, 'Reserved')]]) - elif clause45_addr in range(0x8080, 0x80FF + 1): - self.putx([0, ['CFP NVR 2: Extended ID register', 'NVR2']]) - elif clause45_addr in range(0x8100, 0x817F + 1): - self.putx([0, ['CFP NVR 3: Network lane specific register', 'NVR3']]) - elif clause45_addr in range(0x8180, 0x81FF + 1): - self.putx([0, ['CFP NVR 4', 'NVR4']]) - elif clause45_addr in range(0x8400, 0x847F + 1): - self.putx([0, ['Vendor NVR 1: Vendor data register', 'V-NVR1']]) - elif clause45_addr in range(0x8480, 0x84FF + 1): - self.putx([0, ['Vendor NVR 2: Vendor data register', 'V-NVR2']]) - elif clause45_addr in range(0x8800, 0x887F + 1): - self.putx([0, ['User NVR 1: User data register', 'U-NVR1']]) - elif clause45_addr in range(0x8880, 0x88FF + 1): - self.putx([0, ['User NVR 2: User data register', 'U-NVR2']]) - elif clause45_addr in range(0xA000, 0xA07F + 1): - self.putx([0, ['CFP Module VR 1: CFP Module level control and DDM register', 'Mod-VR1']]) - elif clause45_addr in range(0xA080, 0xA0FF + 1): - self.putx([0, ['MLG VR 1: MLG Management Interface register', 'MLG-VR1']]) diff --git a/decoders/cjtag-oscan0/__init__.py b/decoders/cjtag-oscan0/__init__.py deleted file mode 100644 index 46444052..00000000 --- a/decoders/cjtag-oscan0/__init__.py +++ /dev/null @@ -1,37 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012-2015 Uwe Hermann -## Copyright (C) 2019 Zhiyuan Wan -## Copyright (C) 2019 Kongou Hikari -## -## 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 -## - -''' -JTAG (Joint Test Action Group), a.k.a. "IEEE 1149.1: Standard Test Access Port -and Boundary-Scan Architecture", is a protocol used for testing, debugging, -and flashing various digital ICs. - -Details: -https://en.wikipedia.org/wiki/Joint_Test_Action_Group -http://focus.ti.com/lit/an/ssya002c/ssya002c.pdf - -This decoders handles a tiny part of IEEE 1149.7, the so called CJTAG OSCAN1 -format -http://developers-club.com/posts/237885/ -''' - -from .pd import Decoder \ No newline at end of file diff --git a/decoders/cjtag-oscan0/pd.py b/decoders/cjtag-oscan0/pd.py deleted file mode 100644 index 44cf89f0..00000000 --- a/decoders/cjtag-oscan0/pd.py +++ /dev/null @@ -1,390 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012-2015 Uwe Hermann -## Copyright (C) 2019 DreamSourceLab -## Copyright (C) 2019 Zhiyuan Wan -## Copyright (C) 2019 Kongou Hikari -## -## Version: -## Modified by Shiqiu Nie(369614718@qq.com) -## Date: 2017-01-11 -## Descript: -## 1. 2017-01-10 Fixed TDI/TDO data decode, when JTAG TAP run into -## SHIFT-IR/SHIFT-DR status,the first bit is not a valid bit. -## 2. 2017-01-11 Fixed decode when shift only one bit. -## -## 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, see . -## - -import sigrokdecode as srd - -''' -OUTPUT_PYTHON format: - -Packet: -[, ] - -: - - 'NEW STATE': is the new state of the JTAG state machine. - Valid values: 'TEST-LOGIC-RESET', 'RUN-TEST/IDLE', 'SELECT-DR-SCAN', - 'CAPTURE-DR', 'SHIFT-DR', 'EXIT1-DR', 'PAUSE-DR', 'EXIT2-DR', 'UPDATE-DR', - 'SELECT-IR-SCAN', 'CAPTURE-IR', 'SHIFT-IR', 'EXIT1-IR', 'PAUSE-IR', - 'EXIT2-IR', 'UPDATE-IR'. - - 'IR TDI': Bitstring that was clocked into the IR register. - - 'IR TDO': Bitstring that was clocked out of the IR register. - - 'DR TDI': Bitstring that was clocked into the DR register. - - 'DR TDO': Bitstring that was clocked out of the DR register. - -All bitstrings are a list consisting of two items. The first is a sequence -of '1' and '0' characters (the right-most character is the LSB. Example: -'01110001', where 1 is the LSB). The second item is a list of ss/es values -for each bit that is in the bitstring. -''' - -jtag_states = [ - # Intro "tree" - 'TEST-LOGIC-RESET', 'RUN-TEST/IDLE', - # DR "tree" - 'SELECT-DR-SCAN', 'CAPTURE-DR', 'UPDATE-DR', 'PAUSE-DR', - 'SHIFT-DR', 'EXIT1-DR', 'EXIT2-DR', - # IR "tree" - 'SELECT-IR-SCAN', 'CAPTURE-IR', 'UPDATE-IR', 'PAUSE-IR', - 'SHIFT-IR', 'EXIT1-IR', 'EXIT2-IR', -] - -class Decoder(srd.Decoder): - api_version = 3 - id = 'cjtag_oscan1' - name = 'cJTAG OScan1' - longname = 'Compact Joint Test Action Group (IEEE 1149.7)' - desc = 'Protocol for testing, debugging, and flashing ICs, Now this plugin has no ZBS support, it only supports Oscan1 format.' - license = 'gplv2+' - inputs = ['logic'] - outputs = ['jtag'] - tags = ['Debug/trace'] - channels = ( - {'id': 'tdi', 'name': 'TDI', 'desc': 'Test data input'}, - {'id': 'tdo', 'name': 'TDO', 'desc': 'Test data output'}, - {'id': 'tck', 'name': 'TCK', 'desc': 'Test clock'}, - {'id': 'tms', 'name': 'TMS', 'desc': 'Test mode select'}, - ) - optional_channels = ( - {'id': 'trst', 'name': 'TRST#', 'desc': 'Test reset'}, - {'id': 'srst', 'name': 'SRST#', 'desc': 'System reset'}, - {'id': 'rtck', 'name': 'RTCK', 'desc': 'Return clock signal'}, - ) - annotations = tuple([tuple([s.lower(), s]) for s in jtag_states]) + ( \ - ('bit-tdi', 'Bit (TDI)'), - ('bit-tdo', 'Bit (TDO)'), - ('bitstring-tdi', 'Bitstring (TDI)'), - ('bitstring-tdo', 'Bitstring (TDO)'), - ('bit-tms', 'Bit (TMS)'), - ('state-tapc', 'TAPC State'), - ) - annotation_rows = ( - ('bits-tdi', 'Bits (TDI)', (16,)), - ('bits-tdo', 'Bits (TDO)', (17,)), - ('bitstrings-tdi', 'Bitstring (TDI)', (18,)), - ('bitstrings-tdo', 'Bitstring (TDO)', (19,)), - ('bit-tms', 'Bit (TMS)', (20,)), - ('state-tapc', 'TAPC State', (21,)), - ('states', 'States', tuple(range(15 + 1))), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.state = 'TEST-LOGIC-RESET' - # self.state = 'RUN-TEST/IDLE' - self.cjtagstate = '4-WIRE' - self.oldcjtagstate = None - self.escape_edges = 0 - self.oaclen = 0 - self.oldtms = 0 - self.oacp = 0 - self.oscan1cycle = 0 - self.oldstate = None - self.bits_tdi = [] - self.bits_tdo = [] - self.bits_samplenums_tdi = [] - self.bits_samplenums_tdo = [] - self.ss_item = self.es_item = None - self.ss_bitstring = self.es_bitstring = None - self.saved_item = None - self.first = True - self.first_bit = True - self.bits_cnt = 0 - self.data_ready = False - - def start(self): - self.out_python = self.register(srd.OUTPUT_PYTHON) - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putx(self, data): - self.put(self.ss_item, self.es_item, self.out_ann, data) - - def putp(self, data): - self.put(self.ss_item, self.es_item, self.out_python, data) - - def putx_bs(self, data): - self.put(self.ss_bitstring, self.es_bitstring, self.out_ann, data) - - def putp_bs(self, data): - self.put(self.ss_bitstring, self.es_bitstring, self.out_python, data) - - def advance_state_machine(self, tms): - self.oldstate = self.state - - if self.cjtagstate.startswith("CJTAG-"): - self.oacp = self.oacp + 1 - if (self.oacp > 4 and self.oaclen == 12): - self.cjtagstate = 'CJTAG-EC' - - if (self.oacp == 8 and tms == 0): - self.oaclen = 36 - if (self.oacp > 8 and self.oaclen == 36): - self.cjtagstate = 'CJTAG-SPARE' - if (self.oacp > 13 and self.oaclen == 36): - self.cjtagstate = 'CJTAG-TPDEL' - if (self.oacp > 16 and self.oaclen == 36): - self.cjtagstate = 'CJTAG-TPREV' - if (self.oacp > 18 and self.oaclen == 36): - self.cjtagstate = 'CJTAG-TPST' - if (self.oacp > 23 and self.oaclen == 36): - self.cjtagstate = 'CJTAG-RDYC' - if (self.oacp > 25 and self.oaclen == 36): - self.cjtagstate = 'CJTAG-DLYC' - if (self.oacp > 27 and self.oaclen == 36): - self.cjtagstate = 'CJTAG-SCNFMT' - - if (self.oacp > 8 and self.oaclen == 12): - self.cjtagstate = 'CJTAG-CP' - if (self.oacp > 32 and self.oaclen == 36): - self.cjtagstate = 'CJTAG-CP' - - if (self.oacp > self.oaclen): - self.cjtagstate = 'OSCAN1' - self.oscan1cycle = 1 - self.state = 'TEST-LOGIC-RESET' # Because Nuclei cJTAG device asserts a reset during cJTAG online activating. - - else : - # Intro "tree" - if self.state == 'TEST-LOGIC-RESET': - self.state = 'TEST-LOGIC-RESET' if (tms) else 'RUN-TEST/IDLE' - elif self.state == 'RUN-TEST/IDLE': - self.state = 'SELECT-DR-SCAN' if (tms) else 'RUN-TEST/IDLE' - - # DR "tree" - elif self.state == 'SELECT-DR-SCAN': - self.state = 'SELECT-IR-SCAN' if (tms) else 'CAPTURE-DR' - elif self.state == 'CAPTURE-DR': - self.state = 'EXIT1-DR' if (tms) else 'SHIFT-DR' - elif self.state == 'SHIFT-DR': - self.state = 'EXIT1-DR' if (tms) else 'SHIFT-DR' - elif self.state == 'EXIT1-DR': - self.state = 'UPDATE-DR' if (tms) else 'PAUSE-DR' - elif self.state == 'PAUSE-DR': - self.state = 'EXIT2-DR' if (tms) else 'PAUSE-DR' - elif self.state == 'EXIT2-DR': - self.state = 'UPDATE-DR' if (tms) else 'SHIFT-DR' - elif self.state == 'UPDATE-DR': - self.state = 'SELECT-DR-SCAN' if (tms) else 'RUN-TEST/IDLE' - - # IR "tree" - elif self.state == 'SELECT-IR-SCAN': - self.state = 'TEST-LOGIC-RESET' if (tms) else 'CAPTURE-IR' - elif self.state == 'CAPTURE-IR': - self.state = 'EXIT1-IR' if (tms) else 'SHIFT-IR' - elif self.state == 'SHIFT-IR': - self.state = 'EXIT1-IR' if (tms) else 'SHIFT-IR' - elif self.state == 'EXIT1-IR': - self.state = 'UPDATE-IR' if (tms) else 'PAUSE-IR' - elif self.state == 'PAUSE-IR': - self.state = 'EXIT2-IR' if (tms) else 'PAUSE-IR' - elif self.state == 'EXIT2-IR': - self.state = 'UPDATE-IR' if (tms) else 'SHIFT-IR' - elif self.state == 'UPDATE-IR': - self.state = 'SELECT-DR-SCAN' if (tms) else 'RUN-TEST/IDLE' - - def handle_rising_tck_edge(self, tdi, tdo, tck, tms, trst, srst, rtck): - # Rising TCK edges always advance the state machine. - - self.advance_state_machine(tms) - - if self.first: - # Save the start sample and item for later (no output yet). - self.ss_item = self.samplenum - self.first = False - else: - # Output the saved item (from the last CLK edge to the current). - self.es_item = self.samplenum - # Output the old state (from last rising TCK edge to current one). - self.putx([jtag_states.index(self.oldstate), [self.oldstate]]) - self.putp(['NEW STATE', self.state]) - self.putx([21, [self.oldcjtagstate]]) - if(self.oldcjtagstate.startswith("CJTAG-")): - self.putx([20, [str(self.oldtms)]]) - #self.putx([20, [str(tms)]]) - #self.putx([16, [str(tdi)]]) - #self.putx([17, [str(tdo)]]) - self.oldtms = tms - # Upon SHIFT-IR/SHIFT-DR collect the current TDI/TDO values. - if self.state.startswith('SHIFT-'): - #if self.first_bit: - #self.ss_bitstring = self.samplenum - # self.first_bit = False - - #else: - if self.bits_cnt > 0: - if self.bits_cnt == 1: - self.ss_bitstring = self.samplenum - - if self.bits_cnt > 1: - self.putx([16, [str(self.bits_tdi[0])]]) - self.putx([17, [str(self.bits_tdo[0])]]) - # Use self.samplenum as ES of the previous bit. - self.bits_samplenums_tdi[0][1] = self.samplenum - self.bits_samplenums_tdo[0][1] = self.samplenum - - self.bits_tdi.insert(0, tdi) - self.bits_tdo.insert(0, tdo) - - # Use self.samplenum as SS of the current bit. - self.bits_samplenums_tdi.insert(0, [self.samplenum, -1]) - self.bits_samplenums_tdo.insert(0, [self.samplenum, -1]) - - self.bits_cnt = self.bits_cnt + 1 - - # Output all TDI/TDO bits if we just switched from SHIFT-* to EXIT1-*. - if self.oldstate.startswith('SHIFT-') and \ - self.state.startswith('EXIT1-'): - - #self.es_bitstring = self.samplenum - if self.bits_cnt > 0: - if self.bits_cnt == 1: # Only shift one bit - self.ss_bitstring = self.samplenum - self.bits_tdi.insert(0, tdi) - self.bits_tdo.insert(0, tdo) - ## Use self.samplenum as SS of the current bit. - self.bits_samplenums_tdi.insert(0, [self.samplenum, -1]) - self.bits_samplenums_tdo.insert(0, [self.samplenum, -1]) - else: - ### ---------------------------------------------------------------- - self.putx([16, [str(self.bits_tdi[0])]]) - self.putx([17, [str(self.bits_tdo[0])]]) - ### Use self.samplenum as ES of the previous bit. - self.bits_samplenums_tdi[0][1] = self.samplenum - self.bits_samplenums_tdo[0][1] = self.samplenum - - self.bits_tdi.insert(0, tdi) - self.bits_tdo.insert(0, tdo) - - ## Use self.samplenum as SS of the current bit. - self.bits_samplenums_tdi.insert(0, [self.samplenum, -1]) - self.bits_samplenums_tdo.insert(0, [self.samplenum, -1]) - ## ---------------------------------------------------------------- - - self.data_ready = True - - self.first_bit = True - self.bits_cnt = 0 - if self.oldstate.startswith('EXIT'):# and \ - #self.state.startswith('PAUSE-'): - if self.data_ready: - self.data_ready = False - self.es_bitstring = self.samplenum - t = self.state[-2:] + ' TDI' - b = ''.join(map(str, self.bits_tdi)) - h = ' (0x%X' % int('0b' + b, 2) + ')' - s = t + ': ' + h + ', ' + str(len(self.bits_tdi)) + ' bits' #b + - self.putx_bs([18, [s]]) - self.bits_samplenums_tdi[0][1] = self.samplenum # ES of last bit. - self.putp_bs([t, [b, self.bits_samplenums_tdi]]) - self.putx([16, [str(self.bits_tdi[0])]]) # Last bit. - self.bits_tdi = [] - self.bits_samplenums_tdi = [] - - t = self.state[-2:] + ' TDO' - b = ''.join(map(str, self.bits_tdo)) - h = ' (0x%X' % int('0b' + b, 2) + ')' - s = t + ': ' + h + ', ' + str(len(self.bits_tdo)) + ' bits' #+ b - self.putx_bs([19, [s]]) - self.bits_samplenums_tdo[0][1] = self.samplenum # ES of last bit. - self.putp_bs([t, [b, self.bits_samplenums_tdo]]) - self.putx([17, [str(self.bits_tdo[0])]]) # Last bit. - self.bits_tdo = [] - self.bits_samplenums_tdo = [] - - #self.first_bit = True - #self.bits_cnt = 0 - - #self.ss_bitstring = self.samplenum - - self.ss_item = self.samplenum - - def handle_tms_edge(self, tck, tms): - self.escape_edges = self.escape_edges + 1 - #print ("Detected escape sequence " + str(self.escape_edges)) - #self.es_item = self.samplenum - #self.putx([20, [str(self.escape_edges)]]) - def handle_tapc_state(self, tck, tms): - self.oldcjtagstate = self.cjtagstate - - if self.escape_edges >= 8: - self.cjtagstate = '4-WIRE' - if self.escape_edges == 6 : #| self.escape_edges == 7: - self.cjtagstate = 'CJTAG-OAC' - self.oacp = 0 - self.oaclen = 12 - - self.escape_edges = 0 - - def decode(self): - tdi_real = 0 - tms_real = 0 - tdo_real = 0 - - while True: - # Wait for a rising edge on TCK. - - (tdi, tdo, tck, tms, trst, srst, rtck) = self.wait({2: 'r'}) - self.handle_tapc_state(tck, tms) - - if(self.cjtagstate == 'OSCAN1'): - if(self.oscan1cycle == 0): #nTDI - if(tms == 0): - tdi_real = 1 - else: - tdi_real = 0 - self.oscan1cycle = 1 - elif(self.oscan1cycle == 1): #TMS - tms_real = tms - self.oscan1cycle = 2 - elif(self.oscan1cycle == 2): #TDO - tdo_real = tms - self.handle_rising_tck_edge(tdi_real, tdo_real, tck, tms_real, trst, srst, rtck) - self.oscan1cycle = 0 - else: - self.handle_rising_tck_edge(tdi, tdo, tck, tms, trst, srst, rtck) - - while (tck == 1): - (tdi, tdo, tck, tms_n, trst, srst, rtck) = self.wait([{2: 'f'}, {3: 'e'}]) - if(tms_n != tms): - tms = tms_n - self.handle_tms_edge(tck, tms) - - - diff --git a/decoders/common/__init__.py b/decoders/common/__init__.py deleted file mode 100755 index 2a0beb50..00000000 --- a/decoders/common/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2016 Uwe Hermann -## -## 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, see . -## - diff --git a/decoders/common/plugtrx/__init__.py b/decoders/common/plugtrx/__init__.py deleted file mode 100755 index 8dd0822b..00000000 --- a/decoders/common/plugtrx/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2016 Bert Vermeulen -## -## 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 . -## - -from .mod import * diff --git a/decoders/common/plugtrx/mod.py b/decoders/common/plugtrx/mod.py deleted file mode 100755 index 3d1b66dd..00000000 --- a/decoders/common/plugtrx/mod.py +++ /dev/null @@ -1,192 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2016 Bert Vermeulen -## -## 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 . -## - -# This module contains definitions for use by pluggable network adapters, -# such as SFP, XFP etc. - -MODULE_ID = { - 0x01: 'GBIC', - 0x02: 'Integrated module/connector', - 0x03: 'SFP', - 0x04: '300-pin XBI', - 0x05: 'XENPAK', - 0x06: 'XFP', - 0x07: 'XFF', - 0x08: 'XFP-E', - 0x09: 'XPAK', - 0x0a: 'X2', -} - -ALARM_THRESHOLDS = { - 0: 'Temp high alarm', - 2: 'Temp low alarm', - 4: 'Temp high warning', - 6: 'Temp low warning', - 16: 'Bias high alarm', - 18: 'Bias low alarm', - 20: 'Bias high warning', - 22: 'Bias low warning', - 24: 'TX power high alarm', - 26: 'TX power low alarm', - 28: 'TX power high warning', - 30: 'TX power low warning', - 32: 'RX power high alarm', - 34: 'RX power low alarm', - 36: 'RX power high warning', - 38: 'RX power low warning', - 40: 'AUX 1 high alarm', - 42: 'AUX 1 low alarm', - 44: 'AUX 1 high warning', - 46: 'AUX 1 low warning', - 48: 'AUX 2 high alarm', - 50: 'AUX 2 low alarm', - 52: 'AUX 2 high warning', - 54: 'AUX 2 low warning', -} - -AD_READOUTS = { - 0: 'Module temperature', - 4: 'TX bias current', - 6: 'Measured TX output power', - 8: 'Measured RX input power', - 10: 'AUX 1 measurement', - 12: 'AUX 2 measurement', -} - -GCS_BITS = [ - 'TX disable', - 'Soft TX disable', - 'MOD_NR', - 'P_Down', - 'Soft P_Down', - 'Interrupt', - 'RX_LOS', - 'Data_Not_Ready', - 'TX_NR', - 'TX_Fault', - 'TX_CDR not locked', - 'RX_NR', - 'RX_CDR not locked', -] - -CONNECTOR = { - 0x01: 'SC', - 0x02: 'Fibre Channel style 1 copper', - 0x03: 'Fibre Channel style 2 copper', - 0x04: 'BNC/TNC', - 0x05: 'Fibre Channel coax', - 0x06: 'FiberJack', - 0x07: 'LC', - 0x08: 'MT-RJ', - 0x09: 'MU', - 0x0a: 'SG', - 0x0b: 'Optical pigtail', - 0x20: 'HSSDC II', - 0x21: 'Copper pigtail', -} - -TRANSCEIVER = [ - # 10GB Ethernet - ['10GBASE-SR', '10GBASE-LR', '10GBASE-ER', '10GBASE-LRM', '10GBASE-SW', - '10GBASE-LW', '10GBASE-EW'], - # 10GB Fibre Channel - ['1200-MX-SN-I', '1200-SM-LL-L', 'Extended Reach 1550 nm', - 'Intermediate reach 1300 nm FP'], - # 10GB Copper - [], - # 10GB low speed - ['1000BASE-SX / 1xFC MMF', '1000BASE-LX / 1xFC SMF', '2xFC MMF', - '2xFC SMF', 'OC48-SR', 'OC48-IR', 'OC48-LR'], - # 10GB SONET/SDH interconnect - ['I-64.1r', 'I-64.1', 'I-64.2r', 'I-64.2', 'I-64.3', 'I-64.5'], - # 10GB SONET/SDH short haul - ['S-64.1', 'S-64.2a', 'S-64.2b', 'S-64.3a', 'S-64.3b', 'S-64.5a', 'S-64.5b'], - # 10GB SONET/SDH long haul - ['L-64.1', 'L-64.2a', 'L-64.2b', 'L-64.2c', 'L-64.3', 'G.959.1 P1L1-2D2'], - # 10GB SONET/SDH very long haul - ['V-64.2a', 'V-64.2b', 'V-64.3'], -] - -SERIAL_ENCODING = [ - '64B/66B', - '8B/10B', - 'SONET scrambled', - 'NRZ', - 'RZ', -] - -XMIT_TECH = [ - '850 nm VCSEL', - '1310 nm VCSEL', - '1550 nm VCSEL', - '1310 nm FP', - '1310 nm DFB', - '1550 nm DFB', - '1310 nm EML' - '1550 nm EML' - 'copper', -] - -CDR = [ - '9.95Gb/s', - '10.3Gb/s', - '10.5Gb/s', - '10.7Gb/s', - '11.1Gb/s', - '(unknown)', - 'lineside loopback mode', - 'XFI loopback mode', -] - -DEVICE_TECH = [ - ['no wavelength control', 'sctive wavelength control'], - ['uncooled transmitter device', 'cooled transmitter'], - ['PIN detector', 'APD detector'], - ['transmitter not tunable', 'transmitter tunable'], -] - -ENHANCED_OPTS = [ - 'VPS', - 'soft TX_DISABLE', - 'soft P_Down', - 'VPS LV regulator mode', - 'VPS bypassed regulator mode', - 'active FEC control', - 'wavelength tunability', - 'CMU', -] - -AUX_TYPES = [ - 'not implemented', - 'APD bias voltage', - '(unknown)', - 'TEC current', - 'laser temperature', - 'laser wavelength', - '5V supply voltage', - '3.3V supply voltage', - '1.8V supply voltage', - '-5.2V supply voltage', - '5V supply current', - '(unknown)', - '(unknown)', - '3.3V supply current', - '1.8V supply current', - '-5.2V supply current', -] diff --git a/decoders/common/sdcard/__init__.py b/decoders/common/sdcard/__init__.py deleted file mode 100755 index fb323856..00000000 --- a/decoders/common/sdcard/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012-2014 Uwe Hermann -## -## 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, see . -## - -from .mod import * diff --git a/decoders/common/sdcard/mod.py b/decoders/common/sdcard/mod.py deleted file mode 100755 index 2ef33238..00000000 --- a/decoders/common/sdcard/mod.py +++ /dev/null @@ -1,151 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012-2014 Uwe Hermann -## -## 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, see . -## - -# Normal commands (CMD) -# Unlisted items are 'Reserved' as per SD spec. The 'Unknown' items don't -# seem to be mentioned in the spec, but aren't marked as reserved either. -cmd_names = { - 0: 'GO_IDLE_STATE', - 1: 'SEND_OP_COND', # Reserved in SD mode - 2: 'ALL_SEND_CID', - 3: 'SEND_RELATIVE_ADDR', - 4: 'SET_DSR', - 5: 'IO_SEND_OP_COND', # SDIO-only - 6: 'SWITCH_FUNC', # New since spec 1.10 - 7: 'SELECT/DESELECT_CARD', - 8: 'SEND_IF_COND', - 9: 'SEND_CSD', - 10: 'SEND_CID', - 11: 'VOLTAGE_SWITCH', - 12: 'STOP_TRANSMISSION', - 13: 'SEND_STATUS', - # 14: Reserved - 15: 'GO_INACTIVE_STATE', - 16: 'SET_BLOCKLEN', - 17: 'READ_SINGLE_BLOCK', - 18: 'READ_MULTIPLE_BLOCK', - 19: 'SEND_TUNING_BLOCK', - 20: 'SPEED_CLASS_CONTROL', - # 21-22: Reserved - 23: 'SET_BLOCK_COUNT', - 24: 'WRITE_BLOCK', - 25: 'WRITE_MULTIPLE_BLOCK', - 26: 'Reserved for manufacturer', - 27: 'PROGRAM_CSD', - 28: 'SET_WRITE_PROT', - 29: 'CLR_WRITE_PROT', - 30: 'SEND_WRITE_PROT', - # 31: Reserved - 32: 'ERASE_WR_BLK_START', # SPI mode: ERASE_WR_BLK_START_ADDR - 33: 'ERASE_WR_BLK_END', # SPI mode: ERASE_WR_BLK_END_ADDR - 34: 'Reserved for CMD6', # New since spec 1.10 - 35: 'Reserved for CMD6', # New since spec 1.10 - 36: 'Reserved for CMD6', # New since spec 1.10 - 37: 'Reserved for CMD6', # New since spec 1.10 - 38: 'ERASE', - # 39: Reserved - 40: 'Reserved for security specification', - # 41: Reserved - 42: 'LOCK_UNLOCK', - # 43-49: Reserved - 50: 'Reserved for CMD6', # New since spec 1.10 - # 51: Reserved - 52: 'IO_RW_DIRECT', # SDIO-only - 53: 'IO_RW_EXTENDED', # SDIO-only - 54: 'Unknown', - 55: 'APP_CMD', - 56: 'GEN_CMD', - 57: 'Reserved for CMD6', # New since spec 1.10 - 58: 'READ_OCR', # Reserved in SD mode - 59: 'CRC_ON_OFF', # Reserved in SD mode - 60: 'Reserved for manufacturer', - 61: 'Reserved for manufacturer', - 62: 'Reserved for manufacturer', - 63: 'Reserved for manufacturer', -} - -# Application-specific commands (ACMD) -# Unlisted items are 'Reserved' as per SD spec. The 'Unknown' items don't -# seem to be mentioned in the spec, but aren't marked as reserved either. -acmd_names = { - # 1-5: Reserved - 6: 'SET_BUS_WIDTH', - # 7-12: Reserved - 13: 'SD_STATUS', - 14: 'Reserved for Security Application', - 15: 'Reserved for Security Application', - 16: 'Reserved for Security Application', - # 17: Reserved - 18: 'Reserved for SD security applications', - # 19-21: Reserved - 22: 'SEND_NUM_WR_BLOCKS', - 23: 'SET_WR_BLK_ERASE_COUNT', - # 24: Reserved - 25: 'Reserved for SD security applications', - 26: 'Reserved for SD security applications', - 27: 'Reserved for security specification', - 28: 'Reserved for security specification', - # 29: Reserved - 30: 'Reserved for security specification', - 31: 'Reserved for security specification', - 32: 'Reserved for security specification', - 33: 'Reserved for security specification', - 34: 'Reserved for security specification', - 35: 'Reserved for security specification', - # 36-37: Reserved - 38: 'Reserved for SD security applications', - # 39-40: Reserved - 41: 'SD_SEND_OP_COND', - 42: 'SET_CLR_CARD_DETECT', - 43: 'Reserved for SD security applications', - 44: 'Reserved for SD security applications', - 45: 'Reserved for SD security applications', - 46: 'Reserved for SD security applications', - 47: 'Reserved for SD security applications', - 48: 'Reserved for SD security applications', - 49: 'Reserved for SD security applications', - 50: 'Unknown', - 51: 'SEND_SCR', - 52: 'Reserved for security specification', - 53: 'Reserved for security specification', - 54: 'Reserved for security specification', - 55: 'Non-existant', # Doesn't exist (equivalent to CMD55) - 56: 'Reserved for security specification', - 57: 'Reserved for security specification', - 58: 'Reserved for security specification', - 59: 'Reserved for security specification', - 60: 'Unknown', - 61: 'Unknown', - 62: 'Unknown', - 63: 'Unknown', -} - -accepted_voltages = { - 0b0001: '2.7-3.6V', - 0b0010: 'reserved for low voltage range', - 0b0100: 'reserved', - 0b1000: 'reserved', - # All other values: "not defined". -} - -sd_status = { - # 311:0: Reserved for manufacturer - # 391:312: Reserved -} - diff --git a/decoders/common/srdhelper/__init__.py b/decoders/common/srdhelper/__init__.py deleted file mode 100755 index fb323856..00000000 --- a/decoders/common/srdhelper/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012-2014 Uwe Hermann -## -## 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, see . -## - -from .mod import * diff --git a/decoders/common/srdhelper/mod.py b/decoders/common/srdhelper/mod.py deleted file mode 100755 index 6c45af98..00000000 --- a/decoders/common/srdhelper/mod.py +++ /dev/null @@ -1,84 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012-2020 Uwe Hermann -## -## 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, see . -## - -from enum import Enum, IntEnum, unique -from itertools import chain -import re - -# Return the specified BCD number (max. 8 bits) as integer. -def bcd2int(b): - return (b & 0x0f) + ((b >> 4) * 10) - -def bin2int(s: str): - return int('0b' + s, 2) - -def bitpack(bits): - return sum([b << i for i, b in enumerate(bits)]) - -def bitunpack(num, minbits=0): - res = [] - while num or minbits > 0: - res.append(num & 1) - num >>= 1 - minbits -= 1 - return tuple(res) - -@unique -class SrdStrEnum(Enum): - @classmethod - def from_list(cls, name, l): - # Keys are limited/converted to [A-Z0-9_], values can be any string. - items = [(re.sub('[^A-Z0-9_]', '_', l[i]), l[i]) for i in range(len(l))] - return cls(name, items) - - @classmethod - def from_str(cls, name, s): - return cls.from_list(name, s.split()) - -@unique -class SrdIntEnum(IntEnum): - @classmethod - def _prefix(cls, p): - return tuple([a.value for a in cls if a.name.startswith(p)]) - - @classmethod - def prefixes(cls, prefix_list): - if isinstance(prefix_list, str): - prefix_list = prefix_list.split() - return tuple(chain(*[cls._prefix(p) for p in prefix_list])) - - @classmethod - def _suffix(cls, s): - return tuple([a.value for a in cls if a.name.endswith(s)]) - - @classmethod - def suffixes(cls, suffix_list): - if isinstance(suffix_list, str): - suffix_list = suffix_list.split() - return tuple(chain(*[cls._suffix(s) for s in suffix_list])) - - @classmethod - def from_list(cls, name, l): - # Manually construct (Python 3.4 is missing the 'start' argument). - # Python defaults to start=1, but we want start=0. - return cls(name, [(l[i], i) for i in range(len(l))]) - - @classmethod - def from_str(cls, name, s): - return cls.from_list(name, s.split()) diff --git a/decoders/counter/__init__.py b/decoders/counter/__init__.py deleted file mode 100755 index 505148dd..00000000 --- a/decoders/counter/__init__.py +++ /dev/null @@ -1,28 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Stefan Brüns -## -## 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, see . -## - -''' -This decoder is a simple edge counter. - -It can count rising and/or falling edges, provides an optional reset -signal. It can also divide the count to e.g. count the number of -fixed-length words (where a word corresponds to e.g. 9 clock edges). -''' - -from .pd import Decoder diff --git a/decoders/counter/pd.py b/decoders/counter/pd.py deleted file mode 100755 index b0b1af71..00000000 --- a/decoders/counter/pd.py +++ /dev/null @@ -1,145 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Stefan Brüns -## -## 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, see . -## - -import sigrokdecode as srd - -PIN_DATA, PIN_RESET = range(2) -ROW_EDGE, ROW_WORD, ROW_RESET = range(3) - -class Decoder(srd.Decoder): - api_version = 3 - id = 'counter' - name = 'Counter' - longname = 'Edge counter' - desc = 'Count the number of edges in a signal.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Util'] - channels = ( - {'id': 'data', 'name': 'Data', 'desc': 'Data line'}, - ) - optional_channels = ( - {'id': 'reset', 'name': 'Reset', 'desc': 'Reset line'}, - ) - annotations = ( - ('edge_count', 'Edge count'), - ('word_count', 'Word count'), - ('word_reset', 'Word reset'), - ) - annotation_rows = ( - ('edge_counts', 'Edges', (ROW_EDGE,)), - ('word_counts', 'Words', (ROW_WORD,)), - ('word_resets', 'Word resets', (ROW_RESET,)), - ) - options = ( - {'id': 'data_edge', 'desc': 'Edges to count (data)', 'default': 'any', - 'values': ('any', 'rising', 'falling')}, - {'id': 'divider', 'desc': 'Count divider (word width)', 'default': 0}, - {'id': 'reset_edge', 'desc': 'Edge which clears counters (reset)', - 'default': 'falling', 'values': ('rising', 'falling')}, - {'id': 'edge_off', 'desc': 'Edge counter value after start/reset', 'default': 0}, - {'id': 'word_off', 'desc': 'Word counter value after start/reset', 'default': 0}, - {'id': 'dead_cycles', 'desc': 'Ignore this many edges after reset', 'default': 0}, - {'id': 'start_with_reset', 'desc': 'Assume decode starts with reset', - 'default': 'no', 'values': ('no', 'yes')}, - ) - - def __init__(self): - self.reset() - - def reset(self): - pass - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putc(self, cls, ss, annlist): - self.put(ss, self.samplenum, self.out_ann, [cls, annlist]) - - def decode(self): - opt_edge_map = {'rising': 'r', 'falling': 'f', 'any': 'e'} - - data_edge = self.options['data_edge'] - divider = self.options['divider'] - if divider < 0: - divider = 0 - reset_edge = self.options['reset_edge'] - - condition = [{PIN_DATA: opt_edge_map[data_edge]}] - have_reset = self.has_channel(PIN_RESET) - if have_reset: - cond_reset = len(condition) - condition.append({PIN_RESET: opt_edge_map[reset_edge]}) - - edge_count = int(self.options['edge_off']) - edge_start = None - word_count = int(self.options['word_off']) - word_start = None - - if self.options['start_with_reset'] == 'yes': - dead_count = int(self.options['dead_cycles']) - else: - dead_count = 0 - - while True: - self.wait(condition) - now = self.samplenum - - if have_reset and (self.matched & (0b1 < -## -## 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, see . -## - -''' -DALI is a biphase/manchester based lighting control protocol. -''' - -from .pd import Decoder diff --git a/decoders/dali/lists.py b/decoders/dali/lists.py deleted file mode 100755 index e9d3a4ba..00000000 --- a/decoders/dali/lists.py +++ /dev/null @@ -1,98 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Jeremy Swanson -## -## 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, see . -## - -# DALI extended commands -extended_commands = { - 0xA1: ['Terminate special processes', 'Terminate'], - 0xA3: ['DTR = DATA', 'DTR'], - 0xA5: ['INITIALISE', 'INIT'], - 0xA7: ['RANDOMISE', 'RAND'], - 0xA9: ['COMPARE', 'COMP'], - 0xAB: ['WITHDRAW', 'WDRAW'], - 0xB1: ['SET SEARCH H', 'SAH'], - 0xB3: ['SET SEARCH M', 'SAM'], - 0xB5: ['SET SEARCH L', 'SAL'], - 0xB7: ['Program Short Address', 'ProgSA'], - 0xB9: ['Verify Short Address', 'VfySA'], - 0xBB: ['Query Short Address', 'QryShort'], - 0xBD: ['Physical Selection', 'PysSel'], - 0xC1: ['Enable Device Type X', 'EnTyp'], - 0xC3: ['DTR1 = DATA', 'DTR1'], - 0xC5: ['DTR2 = DATA', 'DTR2'], - 0xC7: ['Write Memory Location', 'WRI'], -} - -# List of commands -dali_commands = { - 0x00: ['Immediate Off', 'IOFF'], - 0x01: ['Up 200ms', 'Up'], - 0x02: ['Down 200ms', 'Down'], - 0x03: ['Step Up', 'Step+'], - 0x04: ['Step Down', 'Step-'], - 0x05: ['Recall Maximum Level', 'Recall Max'], - 0x06: ['Recall Minimum Level', 'Recall Min'], - 0x07: ['Step down and off', 'Down Off'], - 0x08: ['Step ON and UP', 'On Up'], - 0x20: ['Reset', 'Rst'], - 0x21: ['Store Dim Level in DTR', 'Level -> DTR'], - 0x2A: ['Store DTR as Max Level', 'DTR->Max'], - 0x2B: ['Store DTR as Min Level', 'DTR->Min'], - 0x2C: ['Store DTR as Fail Level', 'DTR->Fail'], - 0x2D: ['Store DTR as Power On Level', 'DTR->Poweron'], - 0x2E: ['Store DTR as Fade Time', 'DTR->Fade'], - 0x2F: ['Store DTR as Fade Rate', 'DTR->Rate'], - 0x80: ['Store DTR as Short Address', 'DTR->Add'], - 0x81: ['Enable Memory Write', 'WEn'], - 0x90: ['Query Status', 'Status'], - 0x91: ['Query Ballast', 'Ballast'], - 0x92: ['Query Lamp Failure', 'LmpFail'], - 0x93: ['Query Power On', 'Power On'], - 0x94: ['Query Limit Error', 'Limit Err'], - 0x95: ['Query Reset', 'Reset State'], - 0x96: ['Query Missing Short Address', 'NoSrt'], - 0x97: ['Query Version', 'Ver'], - 0x98: ['Query DTR', 'GetDTR'], - 0x99: ['Query Device Type', 'Type'], - 0x9A: ['Query Physical Minimum', 'PhysMin'], - 0x9B: ['Query Power Fail', 'PowerFailed'], - 0x9C: ['Query DTR1', 'GetDTR1'], - 0x9D: ['Query DTR2', 'GetDTR2'], - 0xA0: ['Query Level', 'GetLevel'], - 0xA1: ['Query Max Level', 'GetMax'], - 0xA2: ['Query Min Level', 'GetMin'], - 0xA3: ['Query Power On', 'GetPwrOn'], - 0xA4: ['Query Fail Level', 'GetFail'], - 0xA5: ['Query Fade Rate', 'GetRate'], - 0xA6: ['Query Power Fail', 'PwrFail'], - 0xC0: ['Query Groups 0-7', 'GetGrpsL'], - 0xC1: ['Query Groups 7-15', 'GetGrpsH'], - 0xC2: ['Query BRNH', 'BRNH'], - 0xC3: ['Query BRNM', 'BRNM'], - 0xC4: ['Query BRNL', 'BRNL'], - 0xC5: ['Query Memory', 'GetMem'], -} - -# DALI device type 8 -dali_device_type8 = { - 0xE0: ['Set Temp X-Y Coordinate', 'Set X-Y'], - 0xE2: ['Activate Colour Set point', 'Activate SetPoint'], - 0xE7: ['Set Colour Temperature Tc', 'DTRs->ColTemp'], - 0xF9: ['Query Features', 'QryFeats'], - 0xFA: ['Query Current Setpoint Colour', 'GetSetPoint'], -} diff --git a/decoders/dali/pd.py b/decoders/dali/pd.py deleted file mode 100755 index 53147463..00000000 --- a/decoders/dali/pd.py +++ /dev/null @@ -1,245 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Jeremy Swanson -## -## 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, see . -## - -import sigrokdecode as srd -from .lists import * - -class SamplerateError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = 'dali' - name = 'DALI' - longname = 'Digital Addressable Lighting Interface' - desc = 'Digital Addressable Lighting Interface (DALI) protocol.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Embedded/industrial', 'Lighting'] - channels = ( - {'id': 'dali', 'name': 'DALI', 'desc': 'DALI data line'}, - ) - options = ( - {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-low', - 'values': ('active-low', 'active-high')}, - ) - annotations = ( - ('bit', 'Bit'), - ('startbit', 'Startbit'), - ('sbit', 'Select bit'), - ('ybit', 'Individual or group'), - ('address', 'Address'), - ('command', 'Command'), - ('reply', 'Reply data'), - ('raw', 'Raw data'), - ) - annotation_rows = ( - ('bits', 'Bits', (0,)), - ('raw', 'Raw data', (7,)), - ('fields', 'Fields', (1, 2, 3, 4, 5, 6)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.samplenum = None - self.edges, self.bits, self.ss_es_bits = [], [], [] - self.state = 'IDLE' - self.dev_type = None - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.old_dali = 1 if self.options['polarity'] == 'active-low' else 0 - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - # One bit: 833.33us (one half low, one half high). - # This is how may samples are in 1TE. - self.halfbit = int((self.samplerate * 0.0008333) / 2.0) - - def putb(self, bit1, bit2, data): - ss, es = self.ss_es_bits[bit1][0], self.ss_es_bits[bit2][1] - self.put(ss, es, self.out_ann, data) - - def handle_bits(self, length): - a, c, f, g, b = 0, 0, 0, 0, self.bits - # Individual raw bits. - for i in range(length): - if i == 0: - ss = max(0, self.bits[0][0]) - else: - ss = self.ss_es_bits[i - 1][1] - es = self.bits[i][0] + (self.halfbit * 2) - self.ss_es_bits.append([ss, es]) - self.putb(i, i, [0, ['%d' % self.bits[i][1]]]) - # Bits[0:0]: Startbit - s = ['Startbit: %d' % b[0][1], 'ST: %d' % b[0][1], 'ST', 'S', 'S'] - self.putb(0, 0, [1, s]) - self.putb(0, 0, [7, s]) - # Bits[1:8] - for i in range(8): - f |= (b[1 + i][1] << (7 - i)) - if length == 9: # BACKWARD Frame - s = ['Reply: %02X' % f, 'Rply: %02X' % f, - 'Rep: %02X' % f, 'R: %02X' % f, 'R'] - self.putb(1, 8, [7, s]) - s = ['Reply: %d' % f, 'Rply: %d' % f, - 'Rep: %d' % f, 'R: %d' % f, 'R'] - self.putb(1, 8, [6, s]) - return - - # FORWARD FRAME - # Bits[9:16]: Command/data (MSB-first) - for i in range(8): - c |= (b[9 + i][1] << (7 - i)) - # Raw output - s = ['Raw data: %02X' % f, 'Raw: %02X' % f, - 'Raw: %02X' % f, 'R: %02X' % f, 'R'] - self.putb(1, 8, [7, s]) - s = ['Raw data: %02X' % c, 'Raw: %02X' % c, - 'Raw: %02X' % c, 'R: %02X' % c, 'R'] - self.putb(9, 16, [7, s]) - - # Bits[8:8]: Select bit - # s = ['Selectbit: %d' % b[8][1], 'SEL: %d' % b[8][1], 'SEL', 'SE', 'S'] - if b[8][1] == 1: - s = ['Command', 'Comd', 'COM', 'CO', 'C'] - else: - s = ['Arc Power Level', 'Arc Pwr', 'ARC', 'AC', 'A'] - self.putb(8, 8, [1, s]) - - # f &= 254 # Clear the select bit. - if f >= 254: # BROADCAST - s = ['BROADCAST', 'Brdcast', 'BC', 'B', 'B'] - self.putb(1, 7, [5, s]) - elif f >= 160: # Extended command 0b10100000 - if f == 0xC1: # DALI_ENABLE_DEVICE_TYPE_X - self.dev_type = -1 - x = extended_commands.get(f, ['Unknown', 'Unk']) - s = ['Extended Command: %02X (%s)' % (f, x[0]), - 'XC: %02X (%s)' % (f, x[1]), - 'XC: %02X' % f, 'X: %02X' % f, 'X'] - self.putb(1, 8, [5, s]) - elif f >= 128: # Group - # Bits[1:1]: Ybit - s = ['YBit: %d' % b[1][1], 'YB: %d' % b[1][1], 'YB', 'Y', 'Y'] - self.putb(1, 1, [3, s]) - g = (f & 127) >> 1 - s = ['Group address: %d' % g, 'Group: %d' % g, - 'GP: %d' % g, 'G: %d' % g, 'G'] - self.putb(2,7, [4, s]) - else: # Short address - # Bits[1:1]: Ybit - s = ['YBit: %d' % b[1][1], 'YB: %d' % b[1][1], 'YB', 'Y', 'Y'] - self.putb(1, 1, [3, s]) - a = f >> 1 - s = ['Short address: %d' % a, 'Addr: %d' % a, - 'Addr: %d' % a, 'A: %d' % a, 'A'] - self.putb(2, 7, [4, s]) - - # Bits[9:16]: Command/data (MSB-first) - if f >= 160 and f < 254: - if self.dev_type == -1: - self.dev_type = c - s = ['Type: %d' % c, 'Typ: %d' % c, - 'Typ: %d' % c, 'T: %d' % c, 'D'] - else: - self.dev_type = None - s = ['Data: %d' % c, 'Dat: %d' % c, - 'Dat: %d' % c, 'D: %d' % c, 'D'] - elif b[8][1] == 1: - un = c & 0xF0 - ln = c & 0x0F - if un == 0x10: # Set scene command - x = ['Recall Scene %d' % ln, 'SC %d' % ln] - elif un == 0x40: - x = ['Store DTR as Scene %d' % ln, 'SC %d = DTR' % ln] - elif un == 0x50: - x = ['Delete Scene %d' % ln, 'DEL SC %d' % ln] - elif un == 0x60: - x = ['Add to Group %d' % ln, 'Grp %d Add' % ln] - elif un == 0x70: - x = ['Remove from Group %d' % ln, 'Grp %d Del' % ln] - elif un == 0xB0: - x = ['Query Scene %d Level' % ln, 'Sc %d Level' % ln] - elif c >= 224: # Application specific commands - if self.dev_type == 8: - x = dali_device_type8.get(c, ['Unknown App', 'Unk']) - else: - x = ['Application Specific Command %d' % c, 'App Cmd %d' % c] - else: - x = dali_commands.get(c, ['Unknown', 'Unk']) - s = ['Command: %d (%s)' % (c, x[0]), 'Com: %d (%s)' % (c, x[1]), - 'Com: %d' % c, 'C: %d' % c, 'C'] - else: - s = ['Arc Power Level: %d' % c, 'Level: %d' % c, - 'Lev: %d' % c, 'L: %d' % c, 'L'] - self.putb(9, 16, [5, s]) - - def reset_decoder_state(self): - self.edges, self.bits, self.ss_es_bits = [], [], [] - self.state = 'IDLE' - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - bit = 0 - while True: - # TODO: Come up with more appropriate self.wait() conditions. - (dali,) = self.wait() - if self.options['polarity'] == 'active-high': - dali ^= 1 # Invert. - - # State machine. - if self.state == 'IDLE': - # Wait for any edge (rising or falling). - if self.old_dali == dali: - continue - self.edges.append(self.samplenum) - self.state = 'PHASE0' - self.old_dali = dali - continue - - if self.old_dali != dali: - self.edges.append(self.samplenum) - elif self.samplenum == (self.edges[-1] + int(self.halfbit * 1.5)): - self.edges.append(self.samplenum - int(self.halfbit * 0.5)) - else: - continue - - bit = self.old_dali - if self.state == 'PHASE0': - self.phase0 = bit - self.state = 'PHASE1' - elif self.state == 'PHASE1': - if (bit == 1) and (self.phase0 == 1): # Stop bit. - if len(self.bits) == 17 or len(self.bits) == 9: - # Forward or Backward. - self.handle_bits(len(self.bits)) - self.reset_decoder_state() # Reset upon errors. - continue - else: - self.bits.append([self.edges[-3], bit]) - self.state = 'PHASE0' - - self.old_dali = dali diff --git a/decoders/dcf77/__init__.py b/decoders/dcf77/__init__.py deleted file mode 100755 index caadcff8..00000000 --- a/decoders/dcf77/__init__.py +++ /dev/null @@ -1,28 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -''' -This PD decodes the DCF77 protocol (a European long-wave time signal that -uses a 77.5kHz carrier frequency). - -Details: -http://en.wikipedia.org/wiki/DCF77 -''' - -from .pd import Decoder diff --git a/decoders/dcf77/pd.py b/decoders/dcf77/pd.py deleted file mode 100755 index 7365134e..00000000 --- a/decoders/dcf77/pd.py +++ /dev/null @@ -1,311 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012-2016 Uwe Hermann -## -## 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, see . -## - -import sigrokdecode as srd -import calendar -from common.srdhelper import bcd2int - -class SamplerateError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = 'dcf77' - name = 'DCF77' - longname = 'DCF77 time protocol' - desc = 'European longwave time signal (77.5kHz carrier signal).' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Clock/timing'] - channels = ( - {'id': 'data', 'name': 'DATA', 'desc': 'DATA line'}, - ) - annotations = ( - ('start-of-minute', 'Start of minute'), - ('special-bits', 'Special bits (civil warnings, weather forecast)'), - ('call-bit', 'Call bit'), - ('summer-time', 'Summer time announcement'), - ('cest', 'CEST bit'), - ('cet', 'CET bit'), - ('leap-second', 'Leap second bit'), - ('start-of-time', 'Start of encoded time'), - ('minute', 'Minute'), - ('minute-parity', 'Minute parity bit'), - ('hour', 'Hour'), - ('hour-parity', 'Hour parity bit'), - ('day', 'Day of month'), - ('day-of-week', 'Day of week'), - ('month', 'Month'), - ('year', 'Year'), - ('date-parity', 'Date parity bit'), - ('raw-bits', 'Raw bits'), - ('unknown-bits', 'Unknown bits'), - ('warnings', 'Human-readable warnings'), - ) - annotation_rows = ( - ('bits', 'Bits', (17, 18)), - ('fields', 'Fields', tuple(range(0, 16 + 1))), - ('warnings', 'Warnings', (19,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.state = 'WAIT FOR RISING EDGE' - self.ss_bit = self.ss_bit_old = self.es_bit = self.ss_block = 0 - self.datebits = [] - self.bitcount = 0 # Counter for the DCF77 bits (0..58) - self.dcf77_bitnumber_is_known = 0 - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def putx(self, data): - # Annotation for a single DCF77 bit. - self.put(self.ss_bit, self.es_bit, self.out_ann, data) - - def putb(self, data): - # Annotation for a multi-bit DCF77 field. - self.put(self.ss_block, self.samplenum, self.out_ann, data) - - # TODO: Which range to use? Only the 100ms/200ms or full second? - def handle_dcf77_bit(self, bit): - c = self.bitcount - - # Create one annotation for each DCF77 bit (containing the 0/1 value). - # Use 'Unknown DCF77 bit x: val' if we're not sure yet which of the - # 0..58 bits it is (because we haven't seen a 'new minute' marker yet). - # Otherwise, use 'DCF77 bit x: val'. - s = 'B' if self.dcf77_bitnumber_is_known else 'Unknown b' - ann = 17 if self.dcf77_bitnumber_is_known else 18 - self.putx([ann, ['%sit %d: %d' % (s, c, bit), '%d' % bit]]) - - # If we're not sure yet which of the 0..58 DCF77 bits we have, return. - # We don't want to decode bogus data. - if not self.dcf77_bitnumber_is_known: - return - - # Collect bits 36-58, we'll need them for a parity check later. - if c in range(36, 58 + 1): - self.datebits.append(bit) - - # Output specific "decoded" annotations for the respective DCF77 bits. - if c == 0: - # Start of minute: DCF bit 0. - if bit == 0: - self.putx([0, ['Start of minute (always 0)', - 'Start of minute', 'SoM']]) - else: - self.putx([19, ['Start of minute != 0', 'SoM != 0']]) - elif c in range(1, 14 + 1): - # Special bits (civil warnings, weather forecast): DCF77 bits 1-14. - if c == 1: - self.tmp = bit - self.ss_block = self.ss_bit - else: - self.tmp |= (bit << (c - 1)) - if c == 14: - s = '{:014b}'.format(self.tmp) - self.putb([1, ['Special bits: %s' % s, 'SB: %s' % s]]) - elif c == 15: - s = '' if (bit == 1) else 'not ' - self.putx([2, ['Call bit: %sset' % s, 'CB: %sset' % s]]) - # TODO: Previously this bit indicated use of the backup antenna. - elif c == 16: - s = '' if (bit == 1) else 'not ' - x = 'yes' if (bit == 1) else 'no' - self.putx([3, ['Summer time announcement: %sactive' % s, - 'Summer time: %sactive' % s, - 'Summer time: %s' % x, 'ST: %s' % x]]) - elif c == 17: - s = '' if (bit == 1) else 'not ' - x = 'yes' if (bit == 1) else 'no' - self.putx([4, ['CEST: %sin effect' % s, 'CEST: %s' % x]]) - elif c == 18: - s = '' if (bit == 1) else 'not ' - x = 'yes' if (bit == 1) else 'no' - self.putx([5, ['CET: %sin effect' % s, 'CET: %s' % x]]) - elif c == 19: - s = '' if (bit == 1) else 'not ' - x = 'yes' if (bit == 1) else 'no' - self.putx([6, ['Leap second announcement: %sactive' % s, - 'Leap second: %sactive' % s, - 'Leap second: %s' % x, 'LS: %s' % x]]) - elif c == 20: - # Start of encoded time: DCF bit 20. - if bit == 1: - self.putx([7, ['Start of encoded time (always 1)', - 'Start of encoded time', 'SoeT']]) - else: - self.putx([19, ['Start of encoded time != 1', 'SoeT != 1']]) - elif c in range(21, 27 + 1): - # Minutes (0-59): DCF77 bits 21-27 (BCD format). - if c == 21: - self.tmp = bit - self.ss_block = self.ss_bit - else: - self.tmp |= (bit << (c - 21)) - if c == 27: - m = bcd2int(self.tmp) - self.putb([8, ['Minutes: %d' % m, 'Min: %d' % m]]) - elif c == 28: - # Even parity over minute bits (21-28): DCF77 bit 28. - self.tmp |= (bit << (c - 21)) - parity = bin(self.tmp).count('1') - s = 'OK' if ((parity % 2) == 0) else 'INVALID!' - self.putx([9, ['Minute parity: %s' % s, 'Min parity: %s' % s]]) - elif c in range(29, 34 + 1): - # Hours (0-23): DCF77 bits 29-34 (BCD format). - if c == 29: - self.tmp = bit - self.ss_block = self.ss_bit - else: - self.tmp |= (bit << (c - 29)) - if c == 34: - self.putb([10, ['Hours: %d' % bcd2int(self.tmp)]]) - elif c == 35: - # Even parity over hour bits (29-35): DCF77 bit 35. - self.tmp |= (bit << (c - 29)) - parity = bin(self.tmp).count('1') - s = 'OK' if ((parity % 2) == 0) else 'INVALID!' - self.putx([11, ['Hour parity: %s' % s]]) - elif c in range(36, 41 + 1): - # Day of month (1-31): DCF77 bits 36-41 (BCD format). - if c == 36: - self.tmp = bit - self.ss_block = self.ss_bit - else: - self.tmp |= (bit << (c - 36)) - if c == 41: - self.putb([12, ['Day: %d' % bcd2int(self.tmp)]]) - elif c in range(42, 44 + 1): - # Day of week (1-7): DCF77 bits 42-44 (BCD format). - # A value of 1 means Monday, 7 means Sunday. - if c == 42: - self.tmp = bit - self.ss_block = self.ss_bit - else: - self.tmp |= (bit << (c - 42)) - if c == 44: - d = bcd2int(self.tmp) - try: - dn = calendar.day_name[d - 1] # day_name[0] == Monday - self.putb([13, ['Day of week: %d (%s)' % (d, dn), - 'DoW: %d (%s)' % (d, dn)]]) - except IndexError: - self.putb([19, ['Day of week: %d (%s)' % (d, 'invalid'), - 'DoW: %d (%s)' % (d, 'inv')]]) - elif c in range(45, 49 + 1): - # Month (1-12): DCF77 bits 45-49 (BCD format). - if c == 45: - self.tmp = bit - self.ss_block = self.ss_bit - else: - self.tmp |= (bit << (c - 45)) - if c == 49: - m = bcd2int(self.tmp) - try: - mn = calendar.month_name[m] # month_name[1] == January - self.putb([14, ['Month: %d (%s)' % (m, mn), - 'Mon: %d (%s)' % (m, mn)]]) - except IndexError: - self.putb([19, ['Month: %d (%s)' % (m, 'invalid'), - 'Mon: %d (%s)' % (m, 'inv')]]) - elif c in range(50, 57 + 1): - # Year (0-99): DCF77 bits 50-57 (BCD format). - if c == 50: - self.tmp = bit - self.ss_block = self.ss_bit - else: - self.tmp |= (bit << (c - 50)) - if c == 57: - self.putb([15, ['Year: %d' % bcd2int(self.tmp)]]) - elif c == 58: - # Even parity over date bits (36-58): DCF77 bit 58. - parity = self.datebits.count(1) - s = 'OK' if ((parity % 2) == 0) else 'INVALID!' - self.putx([16, ['Date parity: %s' % s, 'DP: %s' % s]]) - self.datebits = [] - else: - self.putx([19, ['Invalid DCF77 bit: %d' % c, - 'Invalid bit: %d' % c, 'Inv: %d' % c]]) - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - while True: - if self.state == 'WAIT FOR RISING EDGE': - # Wait until the next rising edge occurs. - self.wait({0: 'r'}) - - # Save the sample number where the DCF77 bit begins. - self.ss_bit = self.samplenum - - # Calculate the length (in ms) between two rising edges. - len_edges = self.ss_bit - self.ss_bit_old - len_edges_ms = int((len_edges / self.samplerate) * 1000) - - # The time between two rising edges is usually around 1000ms. - # For DCF77 bit 59, there is no rising edge at all, i.e. the - # time between DCF77 bit 59 and DCF77 bit 0 (of the next - # minute) is around 2000ms. Thus, if we see an edge with a - # 2000ms distance to the last one, this edge marks the - # beginning of a new minute (and DCF77 bit 0 of that minute). - if len_edges_ms in range(1600, 2400 + 1): - self.bitcount = 0 - self.ss_bit_old = self.ss_bit - self.dcf77_bitnumber_is_known = 1 - - self.ss_bit_old = self.ss_bit - self.state = 'GET BIT' - - elif self.state == 'GET BIT': - # Wait until the next falling edge occurs. - self.wait({0: 'f'}) - - # Save the sample number where the DCF77 bit ends. - self.es_bit = self.samplenum - - # Calculate the length (in ms) of the current high period. - len_high = self.samplenum - self.ss_bit - len_high_ms = int((len_high / self.samplerate) * 1000) - - # If the high signal was 100ms long, that encodes a 0 bit. - # If it was 200ms long, that encodes a 1 bit. - if len_high_ms in range(40, 160 + 1): - bit = 0 - elif len_high_ms in range(161, 260 + 1): - bit = 1 - else: - bit = -1 - - if bit in (0, 1): - self.handle_dcf77_bit(bit) - self.bitcount += 1 - else: - self.putx([19, ['Invalid bit timing', 'Inv timing', 'Inv']]) - - self.state = 'WAIT FOR RISING EDGE' diff --git a/decoders/dmx512/__init__.py b/decoders/dmx512/__init__.py deleted file mode 100755 index b5e57836..00000000 --- a/decoders/dmx512/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2016 Fabian J. Stumpf -## -## 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, see . -## - -''' -DMX512 (Digital MultipleX 512) is a protocol based on RS485, used to control -professional lighting fixtures. -''' - -from .pd import Decoder diff --git a/decoders/dmx512/pd.py b/decoders/dmx512/pd.py deleted file mode 100755 index 355095ee..00000000 --- a/decoders/dmx512/pd.py +++ /dev/null @@ -1,179 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2016 Fabian J. Stumpf -## -## 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, see . -## - -import sigrokdecode as srd - -class Decoder(srd.Decoder): - api_version = 3 - id = 'dmx512' - name = 'DMX512' - longname = 'Digital MultipleX 512' - desc = 'Digital MultipleX 512 (DMX512) lighting protocol.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Embedded/industrial', 'Lighting'] - channels = ( - {'id': 'dmx', 'name': 'DMX data', 'desc': 'Any DMX data line'}, - ) - options = ( - {'id': 'invert', 'desc': 'Invert Signal?', 'default': 'no', - 'values': ('yes', 'no')}, - ) - annotations = ( - ('bit', 'Bit'), - ('break', 'Break'), - ('mab', 'Mark after break'), - ('startbit', 'Start bit'), - ('stopbits', 'Stop bit'), - ('startcode', 'Start code'), - ('channel', 'Channel'), - ('interframe', 'Interframe'), - ('interpacket', 'Interpacket'), - ('data', 'Data'), - ('error', 'Error'), - ) - annotation_rows = ( - ('name', 'Logical', (1, 2, 5, 6, 7, 8)), - ('data', 'Data', (9,)), - ('bits', 'Bits', (0, 3, 4)), - ('errors', 'Errors', (10,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.sample_usec = None - self.run_start = -1 - self.state = 'FIND BREAK' - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - self.sample_usec = 1 / value * 1000000 - self.skip_per_bit = int(4 / self.sample_usec) - - def putr(self, data): - self.put(self.run_start, self.samplenum, self.out_ann, data) - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - - inv = self.options['invert'] == 'yes' - - (dmx,) = self.wait({0: 'h' if inv else 'l'}) - self.run_start = self.samplenum - - while True: - # Seek for an interval with no state change with a length between - # 88 and 1000000 us (BREAK). - if self.state == 'FIND BREAK': - (dmx,) = self.wait({0: 'f' if inv else 'r'}) - runlen = (self.samplenum - self.run_start) * self.sample_usec - if runlen > 88 and runlen < 1000000: - self.putr([1, ['Break']]) - self.state = 'MARK MAB' - self.channel = 0 - elif runlen >= 1000000: - # Error condition. - self.putr([10, ['Invalid break length']]) - else: - (dmx,) = self.wait({0: 'h' if inv else 'l'}) - self.run_start = self.samplenum - # Directly following the BREAK is the MARK AFTER BREAK. - elif self.state == 'MARK MAB': - self.run_start = self.samplenum - (dmx,) = self.wait({0: 'r' if inv else 'f'}) - self.putr([2, ['MAB']]) - self.state = 'READ BYTE' - self.channel = 0 - self.bit = 0 - self.aggreg = dmx - self.run_start = self.samplenum - # Mark and read a single transmitted byte - # (start bit, 8 data bits, 2 stop bits). - elif self.state == 'READ BYTE': - bit_start = self.samplenum - bit_end = self.run_start + (self.bit + 1) * self.skip_per_bit - (dmx,) = self.wait({'skip': round(self.skip_per_bit/2)}) - bit_value = not dmx if inv else dmx - - if self.bit == 0: - self.byte = 0 - self.put(bit_start, bit_end, - self.out_ann, [3, ['Start bit']]) - if bit_value != 0: - # (Possibly) invalid start bit, mark but don't fail. - self.put(bit_start, bit_end, - self.out_ann, [10, ['Invalid start bit']]) - elif self.bit >= 9: - self.put(bit_start, bit_end, - self.out_ann, [4, ['Stop bit']]) - if bit_value != 1: - # Invalid stop bit, mark. - self.put(bit_start, bit_end, - self.out_ann, [10, ['Invalid stop bit']]) - if self.bit == 10: - # On invalid 2nd stop bit, search for new break. - self.state = 'FIND BREAK' - else: - # Label and process one bit. - self.put(bit_start, bit_end, - self.out_ann, [0, [str(bit_value)]]) - self.byte |= bit_value << (self.bit - 1) - - # Label a complete byte. - if self.state == 'READ BYTE' and self.bit == 10: - if self.channel == 0: - d = [5, ['Start code']] - else: - d = [6, ['Channel ' + str(self.channel)]] - self.put(self.run_start, bit_end, self.out_ann, d) - self.put(self.run_start + self.skip_per_bit, - bit_end - 2 * self.skip_per_bit, - self.out_ann, [9, [str(self.byte) + ' / ' + \ - str(hex(self.byte))]]) - # Continue by scanning the IFT. - self.channel += 1 - self.run_start = self.samplenum - self.state = 'MARK IFT' - - self.bit += 1 - (dmx,) = self.wait({'skip': round(bit_end - self.samplenum)}) - # Mark the INTERFRAME-TIME between bytes / INTERPACKET-TIME between packets. - elif self.state == 'MARK IFT': - self.run_start = self.samplenum - if self.channel > 512: - (dmx,) = self.wait({0: 'h' if inv else 'l'}) - self.putr([8, ['Interpacket']]) - self.state = 'FIND BREAK' - self.run_start = self.samplenum - else: - if (not dmx if inv else dmx): - (dmx,) = self.wait({0: 'h' if inv else 'l'}) - self.putr([7, ['Interframe']]) - self.state = 'READ BYTE' - self.bit = 0 - self.run_start = self.samplenum diff --git a/decoders/ds1307/__init__.py b/decoders/ds1307/__init__.py deleted file mode 100755 index faf4ce68..00000000 --- a/decoders/ds1307/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2013 Matt Ranostay -## -## 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, see . -## - -''' -This decoder stacks on top of the 'i2c' PD and decodes the Dallas DS1307 -real-time clock (RTC) specific registers and commands. -''' - -from .pd import Decoder diff --git a/decoders/ds1307/pd.py b/decoders/ds1307/pd.py deleted file mode 100755 index f8ebe195..00000000 --- a/decoders/ds1307/pd.py +++ /dev/null @@ -1,264 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012-2014 Uwe Hermann -## Copyright (C) 2013 Matt Ranostay -## -## 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, see . -## - -import re -import sigrokdecode as srd -from common.srdhelper import bcd2int - -days_of_week = ( - 'Sunday', 'Monday', 'Tuesday', 'Wednesday', - 'Thursday', 'Friday', 'Saturday', -) - -regs = ( - 'Seconds', 'Minutes', 'Hours', 'Day', 'Date', 'Month', 'Year', - 'Control', 'RAM', -) - -bits = ( - 'Clock halt', 'Seconds', 'Reserved', 'Minutes', '12/24 hours', 'AM/PM', - 'Hours', 'Day', 'Date', 'Month', 'Year', 'OUT', 'SQWE', 'RS', 'RAM', -) - -rates = { - 0b00: '1Hz', - 0b01: '4096Hz', - 0b10: '8192Hz', - 0b11: '32768Hz', -} - -DS1307_I2C_ADDRESS = 0x68 - -def regs_and_bits(): - l = [('reg-' + r.lower(), r + ' register') for r in regs] - l += [('bit-' + re.sub('\/| ', '-', b).lower(), b + ' bit') for b in bits] - return tuple(l) - -class Decoder(srd.Decoder): - api_version = 3 - id = 'ds1307' - name = 'DS1307' - longname = 'Dallas DS1307' - desc = 'Dallas DS1307 realtime clock module protocol.' - license = 'gplv2+' - inputs = ['i2c'] - outputs = [] - tags = ['Clock/timing', 'IC'] - annotations = regs_and_bits() + ( - ('read-datetime', 'Read date/time'), - ('write-datetime', 'Write date/time'), - ('reg-read', 'Register read'), - ('reg-write', 'Register write'), - ('warnings', 'Warnings'), - ) - annotation_rows = ( - ('bits', 'Bits', tuple(range(9, 24))), - ('regs', 'Registers', tuple(range(9))), - ('date-time', 'Date/time', (24, 25, 26, 27)), - ('warnings', 'Warnings', (28,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.state = 'IDLE' - self.hours = -1 - self.minutes = -1 - self.seconds = -1 - self.days = -1 - self.date = -1 - self.months = -1 - self.years = -1 - self.bits = [] - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putx(self, data): - self.put(self.ss, self.es, self.out_ann, data) - - def putd(self, bit1, bit2, data): - self.put(self.bits[bit1][1], self.bits[bit2][2], self.out_ann, data) - - def putr(self, bit): - self.put(self.bits[bit][1], self.bits[bit][2], self.out_ann, - [11, ['Reserved bit', 'Reserved', 'Rsvd', 'R']]) - - def handle_reg_0x00(self, b): # Seconds (0-59) / Clock halt bit - self.putd(7, 0, [0, ['Seconds', 'Sec', 'S']]) - ch = 1 if (b & (1 << 7)) else 0 - self.putd(7, 7, [9, ['Clock halt: %d' % ch, 'Clk hlt: %d' % ch, - 'CH: %d' % ch, 'CH']]) - s = self.seconds = bcd2int(b & 0x7f) - self.putd(6, 0, [10, ['Second: %d' % s, 'Sec: %d' % s, 'S: %d' % s, 'S']]) - - def handle_reg_0x01(self, b): # Minutes (0-59) - self.putd(7, 0, [1, ['Minutes', 'Min', 'M']]) - self.putr(7) - m = self.minutes = bcd2int(b & 0x7f) - self.putd(6, 0, [12, ['Minute: %d' % m, 'Min: %d' % m, 'M: %d' % m, 'M']]) - - def handle_reg_0x02(self, b): # Hours (1-12+AM/PM or 0-23) - self.putd(7, 0, [2, ['Hours', 'H']]) - self.putr(7) - ampm_mode = True if (b & (1 << 6)) else False - if ampm_mode: - self.putd(6, 6, [13, ['12-hour mode', '12h mode', '12h']]) - a = 'PM' if (b & (1 << 5)) else 'AM' - self.putd(5, 5, [14, [a, a[0]]]) - h = self.hours = bcd2int(b & 0x1f) - self.putd(4, 0, [15, ['Hour: %d' % h, 'H: %d' % h, 'H']]) - else: - self.putd(6, 6, [13, ['24-hour mode', '24h mode', '24h']]) - h = self.hours = bcd2int(b & 0x3f) - self.putd(5, 0, [15, ['Hour: %d' % h, 'H: %d' % h, 'H']]) - - def handle_reg_0x03(self, b): # Day / day of week (1-7) - self.putd(7, 0, [3, ['Day of week', 'Day', 'D']]) - for i in (7, 6, 5, 4, 3): - self.putr(i) - w = self.days = bcd2int(b & 0x07) - ws = days_of_week[self.days - 1] - self.putd(2, 0, [16, ['Weekday: %s' % ws, 'WD: %s' % ws, 'WD', 'W']]) - - def handle_reg_0x04(self, b): # Date (1-31) - self.putd(7, 0, [4, ['Date', 'D']]) - for i in (7, 6): - self.putr(i) - d = self.date = bcd2int(b & 0x3f) - self.putd(5, 0, [17, ['Date: %d' % d, 'D: %d' % d, 'D']]) - - def handle_reg_0x05(self, b): # Month (1-12) - self.putd(7, 0, [5, ['Month', 'Mon', 'M']]) - for i in (7, 6, 5): - self.putr(i) - m = self.months = bcd2int(b & 0x1f) - self.putd(4, 0, [18, ['Month: %d' % m, 'Mon: %d' % m, 'M: %d' % m, 'M']]) - - def handle_reg_0x06(self, b): # Year (0-99) - self.putd(7, 0, [6, ['Year', 'Y']]) - y = self.years = bcd2int(b & 0xff) - self.years += 2000 - self.putd(7, 0, [19, ['Year: %d' % y, 'Y: %d' % y, 'Y']]) - - def handle_reg_0x07(self, b): # Control Register - self.putd(7, 0, [7, ['Control', 'Ctrl', 'C']]) - for i in (6, 5, 3, 2): - self.putr(i) - o = 1 if (b & (1 << 7)) else 0 - s = 1 if (b & (1 << 4)) else 0 - s2 = 'en' if (b & (1 << 4)) else 'dis' - r = rates[b & 0x03] - self.putd(7, 7, [20, ['Output control: %d' % o, - 'OUT: %d' % o, 'O: %d' % o, 'O']]) - self.putd(4, 4, [21, ['Square wave output: %sabled' % s2, - 'SQWE: %sabled' % s2, 'SQWE: %d' % s, 'S: %d' % s, 'S']]) - self.putd(1, 0, [22, ['Square wave output rate: %s' % r, - 'Square wave rate: %s' % r, 'SQW rate: %s' % r, 'Rate: %s' % r, - 'RS: %s' % s, 'RS', 'R']]) - - def handle_reg_0x3f(self, b): # RAM (bytes 0x08-0x3f) - self.putd(7, 0, [8, ['RAM', 'R']]) - self.putd(7, 0, [23, ['SRAM: 0x%02X' % b, '0x%02X' % b]]) - - def output_datetime(self, cls, rw): - # TODO: Handle read/write of only parts of these items. - d = '%s, %02d.%02d.%4d %02d:%02d:%02d' % ( - days_of_week[self.days - 1], self.date, self.months, - self.years, self.hours, self.minutes, self.seconds) - self.put(self.ss_block, self.es, self.out_ann, - [cls, ['%s date/time: %s' % (rw, d)]]) - - def handle_reg(self, b): - r = self.reg if self.reg < 8 else 0x3f - fn = getattr(self, 'handle_reg_0x%02x' % r) - fn(b) - # Honor address auto-increment feature of the DS1307. When the - # address reaches 0x3f, it will wrap around to address 0. - self.reg += 1 - if self.reg > 0x3f: - self.reg = 0 - - def is_correct_chip(self, addr): - if addr == DS1307_I2C_ADDRESS: - return True - self.put(self.ss_block, self.es, self.out_ann, - [28, ['Ignoring non-DS1307 data (slave 0x%02X)' % addr]]) - return False - - def decode(self, ss, es, data): - cmd, databyte = data - - # Collect the 'BITS' packet, then return. The next packet is - # guaranteed to belong to these bits we just stored. - if cmd == 'BITS': - self.bits = databyte - return - - # Store the start/end samples of this I²C packet. - self.ss, self.es = ss, es - - # State machine. - if self.state == 'IDLE': - # Wait for an I²C START condition. - if cmd != 'START': - return - self.state = 'GET SLAVE ADDR' - self.ss_block = ss - elif self.state == 'GET SLAVE ADDR': - # Wait for an address write operation. - if cmd != 'ADDRESS WRITE': - return - if not self.is_correct_chip(databyte): - self.state = 'IDLE' - return - self.state = 'GET REG ADDR' - elif self.state == 'GET REG ADDR': - # Wait for a data write (master selects the slave register). - if cmd != 'DATA WRITE': - return - self.reg = databyte - self.state = 'WRITE RTC REGS' - elif self.state == 'WRITE RTC REGS': - # If we see a Repeated Start here, it's an RTC read. - if cmd == 'START REPEAT': - self.state = 'READ RTC REGS' - return - # Otherwise: Get data bytes until a STOP condition occurs. - if cmd == 'DATA WRITE': - self.handle_reg(databyte) - elif cmd == 'STOP': - self.output_datetime(25, 'Written') - self.state = 'IDLE' - elif self.state == 'READ RTC REGS': - # Wait for an address read operation. - if cmd != 'ADDRESS READ': - return - if not self.is_correct_chip(databyte): - self.state = 'IDLE' - return - self.state = 'READ RTC REGS2' - elif self.state == 'READ RTC REGS2': - if cmd == 'DATA READ': - self.handle_reg(databyte) - elif cmd == 'STOP': - self.output_datetime(24, 'Read') - self.state = 'IDLE' diff --git a/decoders/ds2408/__init__.py b/decoders/ds2408/__init__.py deleted file mode 100644 index b196ce97..00000000 --- a/decoders/ds2408/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -''' -This decoder stacks on top of the 'onewire_network' PD and decodes the -Maxim DS2408 1-Wire 8-channel addressable switch protocol. -''' - -from .pd import Decoder diff --git a/decoders/ds2408/pd.py b/decoders/ds2408/pd.py deleted file mode 100644 index 33f2873f..00000000 --- a/decoders/ds2408/pd.py +++ /dev/null @@ -1,129 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Mariusz Bialonczyk -## -## 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, see . -## - -import sigrokdecode as srd - -# Dictionary of FUNCTION commands and their names. -command = { - 0xf0: 'Read PIO Registers', - 0xf5: 'Channel Access Read', - 0x5a: 'Channel Access Write', - 0xcc: 'Write Conditional Search Register', - 0xc3: 'Reset Activity Latches', - 0x3c: 'Disable Test Mode', -} - -class Decoder(srd.Decoder): - api_version = 3 - id = 'ds2408' - name = 'DS2408' - longname = 'Maxim DS2408' - desc = '1-Wire 8-channel addressable switch.' - license = 'gplv2+' - inputs = ['onewire_network'] - outputs = [] - tags = ['Embedded/industrial', 'IC'] - annotations = ( - ('text', 'Human-readable text'), - ) - - def __init__(self): - self.reset() - - def reset(self): - # Bytes for function command. - self.bytes = [] - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putx(self, data): - self.put(self.ss, self.es, self.out_ann, data) - - def decode(self, ss, es, data): - code, val = data - - if code == 'RESET/PRESENCE': - self.ss, self.es = ss, es - self.putx([0, ['Reset/presence: %s' - % ('true' if val else 'false')]]) - self.bytes = [] - elif code == 'ROM': - self.ss, self.es = ss, es - family_code = val & 0xff - self.putx([0, ['ROM: 0x%016x (family code 0x%02x)' % (val, family_code)]]) - self.bytes = [] - elif code == 'DATA': - self.bytes.append(val) - if 1 == len(self.bytes): - self.ss, self.es = ss, es - if val not in command: - self.putx([0, ['Unrecognized command: 0x%02x' % val]]) - else: - self.putx([0, ['%s (0x%02x)' % (command[val], val)]]) - elif 0xf0 == self.bytes[0]: # Read PIO Registers - if 2 == len(self.bytes): - self.ss = ss - elif 3 == len(self.bytes): - self.es = es - self.putx([0, ['Target address: 0x%04x' - % ((self.bytes[2] << 8) + self.bytes[1])]]) - elif 3 < len(self.bytes): - self.ss, self.es = ss, es - self.putx([0, ['Data: 0x%02x' % self.bytes[-1]]]) - elif 0xf5 == self.bytes[0]: # Channel Access Read - if 2 == len(self.bytes): - self.ss = ss - elif 2 < len(self.bytes): - self.ss, self.es = ss, es - self.putx([0, ['PIO sample: 0x%02x' % self.bytes[-1]]]) - elif 0x5a == self.bytes[0]: # Channel Access Write - if 2 == len(self.bytes): - self.ss = ss - elif 3 == len(self.bytes): - self.es = es - if (self.bytes[-1] == (self.bytes[-2] ^ 0xff)): - self.putx([0, ['Data: 0x%02x (bit-inversion correct: 0x%02x)' % (self.bytes[-2], self.bytes[-1])]]) - else: - self.putx([0, ['Data error: second byte (0x%02x) is not bit-inverse of first (0x%02x)' % (self.bytes[-1], self.bytes[-2])]]) - elif 3 < len(self.bytes): - self.ss, self.es = ss, es - if 0xaa == self.bytes[-1]: - self.putx([0, ['Success']]) - elif 0xff == self.bytes[-1]: - self.putx([0, ['Fail New State']]) - elif 0xcc == self.bytes[0]: # Write Conditional Search Register - if 2 == len(self.bytes): - self.ss = ss - elif 3 == len(self.bytes): - self.es = es - self.putx([0, ['Target address: 0x%04x' - % ((self.bytes[2] << 8) + self.bytes[1])]]) - elif 3 < len(self.bytes): - self.ss, self.es = ss, es - self.putx([0, ['Data: 0x%02x' % self.bytes[-1]]]) - elif 0xc3 == self.bytes[0]: # Reset Activity Latches - if 2 == len(self.bytes): - self.ss = ss - elif 2 < len(self.bytes): - self.ss, self.es = ss, es - if 0xaa == self.bytes[-1]: - self.putx([0, ['Success']]) - else: - self.putx([0, ['Invalid byte']]) diff --git a/decoders/ds243x/__init__.py b/decoders/ds243x/__init__.py deleted file mode 100755 index c460e045..00000000 --- a/decoders/ds243x/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2017 Kevin Redon -## -## 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, see . -## - -''' -This decoder stacks on top of the 'onewire_network' PD and decodes the -Maxim DS243x (1-Wire EEPROM) protocol. -''' - -from .pd import Decoder diff --git a/decoders/ds243x/pd.py b/decoders/ds243x/pd.py deleted file mode 100755 index 7f9f6660..00000000 --- a/decoders/ds243x/pd.py +++ /dev/null @@ -1,270 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2017 Kevin Redon -## Copyright (C) 2017 Soeren Apel -## -## 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, see . -## - -import sigrokdecode as srd - -# Dictionary of FUNCTION commands and their names. -commands_2432 = { - 0x0f: 'Write scratchpad', - 0xaa: 'Read scratchpad', - 0x55: 'Copy scratchpad', - 0xf0: 'Read memory', - 0x5a: 'Load first secret', - 0x33: 'Compute next secret', - 0xa5: 'Read authenticated page', -} - -commands_2433 = { - 0x0f: 'Write scratchpad', - 0xaa: 'Read scratchpad', - 0x55: 'Copy scratchpad', - 0xf0: 'Read memory', -} - -# Maxim DS243x family code, present at the end of the ROM code. -family_codes = { - 0x33: ('DS2432', commands_2432), - 0x23: ('DS2433', commands_2433), -} - -# Calculate the CRC-16 checksum. -# Initial value: 0x0000, xor-in: 0x0000, polynom 0x8005, xor-out: 0xffff. -def crc16(byte_array): - reverse = 0xa001 # Use the reverse polynom to make algo simpler. - crc = 0x0000 # Initial value. - # Reverse CRC calculation. - for byte in byte_array: - for bit in range(8): - if (byte ^ crc) & 1: - crc = (crc >> 1) ^ reverse - else: - crc >>= 1 - byte >>= 1 - crc ^= 0xffff # Invert CRC. - return crc - -class Decoder(srd.Decoder): - api_version = 3 - id = 'ds243x' - name = 'DS243x' - longname = 'Maxim DS2432/3' - desc = 'Maxim DS243x series 1-Wire EEPROM protocol.' - license = 'gplv2+' - inputs = ['onewire_network'] - outputs = [] - tags = ['IC', 'Memory'] - annotations = ( - ('text', 'Human-readable text'), - ) - binary = ( - ('mem_read', 'Data read from memory'), - ) - - def __init__(self): - self.reset() - - def reset(self): - # Bytes for function command. - self.bytes = [] - self.family_code = None - self.family = '' - self.commands = commands_2432 # Use max command set until we know better. - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.out_binary = self.register(srd.OUTPUT_BINARY) - - def putx(self, data): - self.put(self.ss, self.es, self.out_ann, data) - - def decode(self, ss, es, data): - code, val = data - - if code == 'RESET/PRESENCE': - self.ss, self.es = ss, es - self.putx([0, ['Reset/presence: %s' - % ('true' if val else 'false')]]) - self.bytes = [] - elif code == 'ROM': - self.ss, self.es = ss, es - self.family_code = val & 0xff - - s = None - if self.family_code in family_codes: - self.family, self.commands = family_codes[val & 0xff] - s = 'is 0x%02x, %s detected' % (self.family_code, self.family) - else: - s = '0x%02x unknown' % (self.family_code) - - self.putx([0, ['ROM: 0x%016x (%s)' % (val, 'family code ' + s), - 'ROM: 0x%016x (%s)' % (val, self.family)]]) - self.bytes = [] - elif code == 'DATA': - self.bytes.append(val) - if 1 == len(self.bytes): - self.ss, self.es = ss, es - if val not in self.commands: - self.putx([0, ['Unrecognized command: 0x%02x' % val]]) - else: - self.putx([0, ['Function command: %s (0x%02x)' - % (self.commands[val], val)]]) - elif 0x0f == self.bytes[0]: # Write scratchpad - if 2 == len(self.bytes): - self.ss = ss - elif 3 == len(self.bytes): - self.es = es - self.putx([0, ['Target address: 0x%04x' - % ((self.bytes[2] << 8) + self.bytes[1])]]) - elif 4 == len(self.bytes): - self.ss = ss - elif 11 == len(self.bytes): - self.es = es - self.putx([0, ['Data: ' + (','.join(format(n, '#04x') - for n in self.bytes[3:11]))]]) - elif 12 == len(self.bytes): - self.ss = ss - elif 13 == len(self.bytes): - self.es = es - self.putx([0, ['CRC: ' - + ('ok' if crc16(self.bytes[0:11]) == (self.bytes[11] - + (self.bytes[12] << 8)) else 'error')]]) - elif 0xaa == self.bytes[0]: # Read scratchpad - if 2 == len(self.bytes): - self.ss = ss - elif 3 == len(self.bytes): - self.es = es - self.putx([0, ['Target address: 0x%04x' - % ((self.bytes[2] << 8) + self.bytes[1])]]) - elif 4 == len(self.bytes): - self.ss, self.es = ss, es - self.putx([0, ['Data status (E/S): 0x%02x' - % (self.bytes[3])]]) - elif 5 == len(self.bytes): - self.ss = ss - elif 12 == len(self.bytes): - self.es = es - self.putx([0, ['Data: ' + (','.join(format(n, '#04x') - for n in self.bytes[4:12]))]]) - elif 13 == len(self.bytes): - self.ss = ss - elif 14 == len(self.bytes): - self.es = es - self.putx([0, ['CRC: ' - + ('ok' if crc16(self.bytes[0:12]) == (self.bytes[12] - + (self.bytes[13] << 8)) else 'error')]]) - elif 0x5a == self.bytes[0]: # Load first secret - if 2 == len(self.bytes): - self.ss = ss - elif 4 == len(self.bytes): - self.es = es - self.putx([0, ['Authorization pattern (TA1, TA2, E/S): ' - + (','.join(format(n, '#04x') - for n in self.bytes[1:4]))]]) - elif 4 < len(self.bytes): - self.ss, self.es = ss, es - if (0xaa == self.bytes[-1] or 0x55 == self.bytes[-1]): - self.putx([0, ['End of operation']]) - elif 0x33 == self.bytes[0]: # Compute next secret - if 2 == len(self.bytes): - self.ss = ss - elif 3 == len(self.bytes): - self.es = es - self.putx([0, ['Target address: 0x%04x' - % ((self.bytes[2] << 8) + self.bytes[1])]]) - elif 3 < len(self.bytes): - self.ss, self.es = ss, es - if (0xaa == self.bytes[-1] or 0x55 == self.bytes[-1]): - self.putx([0, ['End of operation']]) - elif 0x55 == self.bytes[0]: # Copy scratchpad - if 2 == len(self.bytes): - self.ss = ss - elif 4 == len(self.bytes): - self.es = es - self.putx([0, ['Authorization pattern (TA1, TA2, E/S): ' - + (','.join(format(n, '#04x') - for n in self.bytes[1:4]))]]) - elif 5 == len(self.bytes): - self.ss = ss - elif 24 == len(self.bytes): - self.es = es - mac = ','.join(format(n, '#04x') for n in self.bytes[4:24]) - self.putx([0, ['Message authentication code: ' + mac, - 'MAC: ' + mac]]) - elif 24 < len(self.bytes): - self.ss, self.es = ss, es - if (0xaa == self.bytes[-1] or 0x55 == self.bytes[-1]): - self.putx([0, ['Operation succeeded']]) - elif (0 == self.bytes[-1]): - self.putx([0, ['Operation failed']]) - elif 0xa5 == self.bytes[0]: # Read authenticated page - if 2 == len(self.bytes): - self.ss = ss - elif 3 == len(self.bytes): - self.es = es - self.putx([0, ['Target address: 0x%04x' - % ((self.bytes[2] << 8) + self.bytes[1])]]) - elif 4 == len(self.bytes): - self.ss = ss - elif 35 == len(self.bytes): - self.es = es - self.putx([0, ['Data: ' + (','.join(format(n, '#04x') - for n in self.bytes[3:35]))]]) - elif 36 == len(self.bytes): - self.ss, self.es = ss, es - self.putx([0, ['Padding: ' - + ('ok' if 0xff == self.bytes[-1] else 'error')]]) - elif 37 == len(self.bytes): - self.ss = ss - elif 38 == len(self.bytes): - self.es = es - self.putx([0, ['CRC: ' - + ('ok' if crc16(self.bytes[0:36]) == (self.bytes[36] - + (self.bytes[37] << 8)) else 'error')]]) - elif 39 == len(self.bytes): - self.ss = ss - elif 58 == len(self.bytes): - self.es = es - mac = ','.join(format(n, '#04x') for n in self.bytes[38:58]) - self.putx([0, ['Message authentication code: ' + mac, - 'MAC: ' + mac]]) - elif 59 == len(self.bytes): - self.ss = ss - elif 60 == len(self.bytes): - self.es = es - self.putx([0, ['MAC CRC: ' - + ('ok' if crc16(self.bytes[38:58]) == (self.bytes[58] - + (self.bytes[59] << 8)) else 'error')]]) - elif 60 < len(self.bytes): - self.ss, self.es = ss, es - if (0xaa == self.bytes[-1] or 0x55 == self.bytes[-1]): - self.putx([0, ['Operation completed']]) - elif 0xf0 == self.bytes[0]: # Read memory - if 2 == len(self.bytes): - self.ss = ss - elif 3 == len(self.bytes): - self.es = es - self.putx([0, ['Target address: 0x%04x' - % ((self.bytes[2] << 8) + self.bytes[1])]]) - elif 3 < len(self.bytes): - self.ss, self.es = ss, es - self.putx([0, ['Data: 0x%02x' % (self.bytes[-1])]]) - - bdata = self.bytes[-1].to_bytes(1, byteorder='big') - self.put(ss, es, self.out_binary, [0, bdata]) diff --git a/decoders/ds28ea00/__init__.py b/decoders/ds28ea00/__init__.py deleted file mode 100755 index 31550707..00000000 --- a/decoders/ds28ea00/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -''' -This decoder stacks on top of the 'onewire_network' PD and decodes the -Maxim DS28EA00 1-Wire digital thermometer protocol. -''' - -from .pd import Decoder diff --git a/decoders/ds28ea00/pd.py b/decoders/ds28ea00/pd.py deleted file mode 100755 index 9a578449..00000000 --- a/decoders/ds28ea00/pd.py +++ /dev/null @@ -1,93 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Iztok Jeras -## -## 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, see . -## - -import sigrokdecode as srd - -# Dictionary of FUNCTION commands and their names. -command = { - # Scratchpad - 0x4e: 'Write scratchpad', - 0xbe: 'Read scratchpad', - 0x48: 'Copy scratchpad', - # Thermometer - 0x44: 'Convert temperature', - 0xb4: 'Read power mode', - 0xb8: 'Recall EEPROM', - 0xf5: 'PIO access read', - 0xA5: 'PIO access write', - 0x99: 'Chain', -} - -class Decoder(srd.Decoder): - api_version = 3 - id = 'ds28ea00' - name = 'DS28EA00' - longname = 'Maxim DS28EA00 1-Wire digital thermometer' - desc = '1-Wire digital thermometer with Sequence Detect and PIO.' - license = 'gplv2+' - inputs = ['onewire_network'] - outputs = [] - tags = ['IC', 'Sensor'] - annotations = ( - ('text', 'Human-readable text'), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.trn_beg = 0 - self.trn_end = 0 - self.state = 'ROM' - self.rom = 0x0000000000000000 - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putx(self, data): - self.put(self.ss, self.es, self.out_ann, data) - - def decode(self, ss, es, data): - code, val = data - - self.ss, self.es = ss, es - - # State machine. - if code == 'RESET/PRESENCE': - self.putx([0, ['Reset/presence: %s' - % ('true' if val else 'false')]]) - self.state = 'ROM' - elif code == 'ROM': - self.rom = val - self.putx([0, ['ROM: 0x%016x' % (val)]]) - self.state = 'COMMAND' - elif code == 'DATA': - if self.state == 'COMMAND': - if val not in command: - self.putx([0, ['Unrecognized command: 0x%02x' % val]]) - return - self.putx([0, ['Function command: 0x%02x \'%s\'' - % (val, command[val])]]) - self.state = command[val].upper() - elif self.state == 'READ SCRATCHPAD': - self.putx([0, ['Scratchpad data: 0x%02x' % val]]) - elif self.state == 'CONVERT TEMPERATURE': - self.putx([0, ['Temperature conversion status: 0x%02x' % val]]) - elif self.state in [s.upper() for s in command.values()]: - self.putx([0, ['TODO \'%s\': 0x%02x' % (self.state, val)]]) diff --git a/decoders/dsi/__init__.py b/decoders/dsi/__init__.py deleted file mode 100755 index bfba8672..00000000 --- a/decoders/dsi/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Jeremy Swanson -## -## 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, see . -## - -''' -DSI is a biphase/manchester based lighting control protocol. -''' - -from .pd import Decoder diff --git a/decoders/dsi/pd.py b/decoders/dsi/pd.py deleted file mode 100755 index 7ce95179..00000000 --- a/decoders/dsi/pd.py +++ /dev/null @@ -1,157 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Jeremy Swanson -## -## 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, see . -## - -import sigrokdecode as srd - -class SamplerateError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = 'dsi' - name = 'DSI' - longname = 'Digital Serial Interface' - desc = 'Digital Serial Interface (DSI) lighting protocol.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Embedded/industrial', 'Lighting'] - channels = ( - {'id': 'dsi', 'name': 'DSI', 'desc': 'DSI data line'}, - ) - options = ( - {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-high', - 'values': ('active-low', 'active-high')}, - ) - annotations = ( - ('bit', 'Bit'), - ('startbit', 'Start bit'), - ('level', 'Dimmer level'), - ('raw', 'Raw data'), - ) - annotation_rows = ( - ('bits', 'Bits', (0,)), - ('raw', 'Raw data', (3,)), - ('fields', 'Fields', (1, 2)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.samplenum = None - self.edges, self.bits, self.ss_es_bits = [], [], [] - self.state = 'IDLE' - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.old_dsi = 1 if self.options['polarity'] == 'active-low' else 0 - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - # One bit: 1666.7us (one half low, one half high). - # This is how many samples are in 1TE. - self.halfbit = int((self.samplerate * 0.0016667) / 2.0) - - def putb(self, bit1, bit2, data): - ss, es = self.ss_es_bits[bit1][0], self.ss_es_bits[bit2][1] - self.put(ss, es, self.out_ann, data) - - def handle_bits(self, length): - a, c, f, g, b = 0, 0, 0, 0, self.bits - # Individual raw bits. - for i in range(length): - if i == 0: - ss = max(0, self.bits[0][0]) - else: - ss = self.ss_es_bits[i - 1][1] - es = self.bits[i][0] + (self.halfbit * 2) - self.ss_es_bits.append([ss, es]) - self.putb(i, i, [0, ['%d' % self.bits[i][1]]]) - # Bits[0:0]: Startbit - s = ['Startbit: %d' % b[0][1], 'ST: %d' % b[0][1], 'ST', 'S', 'S'] - self.putb(0, 0, [1, s]) - self.putb(0, 0, [3, s]) - # Bits[1:8] - for i in range(8): - f |= (b[1 + i][1] << (7 - i)) - g = f / 2.55 - if length == 9: # BACKWARD Frame - s = ['Data: %02X' % f, 'Dat: %02X' % f, - 'Dat: %02X' % f, 'D: %02X' % f, 'D'] - self.putb(1, 8, [3, s]) - s = ['Level: %d%%' % g, 'Lev: %d%%' % g, - 'Lev: %d%%' % g, 'L: %d' % g, 'D'] - self.putb(1, 8, [2, s]) - return - - def reset_decoder_state(self): - self.edges, self.bits, self.ss_es_bits = [], [], [] - self.state = 'IDLE' - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - bit = 0 - while True: - (self.dsi,) = self.wait() - if self.options['polarity'] == 'active-high': - self.dsi ^= 1 # Invert. - - # State machine. - if self.state == 'IDLE': - # Wait for any edge (rising or falling). - if self.old_dsi == self.dsi: - continue - # Add in the first half of the start bit. - self.edges.append(self.samplenum - int(self.halfbit)) - self.edges.append(self.samplenum) - # Start bit is 0->1. - self.phase0 = self.dsi ^ 1 - self.state = 'PHASE1' - self.old_dsi = self.dsi - # Get the next sample point. - self.old_dsi = self.dsi - continue - - if self.old_dsi != self.dsi: - self.edges.append(self.samplenum) - elif self.samplenum == (self.edges[-1] + int(self.halfbit * 1.5)): - self.edges.append(self.samplenum - int(self.halfbit * 0.5)) - else: - continue - - bit = self.old_dsi - if self.state == 'PHASE0': - self.phase0 = bit - self.state = 'PHASE1' - elif self.state == 'PHASE1': - if (bit == 1) and (self.phase0 == 1): # Stop bit. - if len(self.bits) == 17 or len(self.bits) == 9: - # Forward or Backward. - self.handle_bits(len(self.bits)) - self.reset_decoder_state() # Reset upon errors. - continue - else: - self.bits.append([self.edges[-3], bit]) - self.state = 'PHASE0' - - self.old_dsi = self.dsi diff --git a/decoders/edid/__init__.py b/decoders/edid/__init__.py deleted file mode 100755 index 256d839d..00000000 --- a/decoders/edid/__init__.py +++ /dev/null @@ -1,35 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Bert Vermeulen -## -## 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, see . -## - -''' -Extended Display Identification Data (EDID) 1.3 structure decoder. - -The three-character vendor ID as specified in the EDID standard refers to -a Plug and Play ID (PNPID). The list of PNPID assignments is done by Microsoft. - -The 'pnpids.txt' file included with this protocol decoder is derived from -the list of assignments downloadable from that page. It was retrieved in -January 2012. - -Details: -https://en.wikipedia.org/wiki/Extended_display_identification_data -http://msdn.microsoft.com/en-us/windows/hardware/gg463195 -''' - -from .pd import Decoder diff --git a/decoders/edid/config b/decoders/edid/config deleted file mode 100755 index ba74a8f7..00000000 --- a/decoders/edid/config +++ /dev/null @@ -1 +0,0 @@ -extra-install pnpids.txt diff --git a/decoders/edid/pd.py b/decoders/edid/pd.py deleted file mode 100755 index 2d7460ce..00000000 --- a/decoders/edid/pd.py +++ /dev/null @@ -1,668 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Bert Vermeulen -## -## 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 . -## - -# TODO: -# - EDID < 1.3 -# - add short annotations -# - Signal level standard field in basic display parameters block -# - Additional color point descriptors -# - Additional standard timing descriptors -# - Extensions - -import sigrokdecode as srd -import os - -EDID_HEADER = [0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00] -OFF_VENDOR = 8 -OFF_VERSION = 18 -OFF_BASIC = 20 -OFF_CHROM = 25 -OFF_EST_TIMING = 35 -OFF_STD_TIMING = 38 -OFF_DET_TIMING = 54 -OFF_NUM_EXT = 126 -OFF_CHECKSUM = 127 - -# Pre-EDID established timing modes -est_modes = [ - '720x400@70Hz', - '720x400@88Hz', - '640x480@60Hz', - '640x480@67Hz', - '640x480@72Hz', - '640x480@75Hz', - '800x600@56Hz', - '800x600@60Hz', - '800x600@72Hz', - '800x600@75Hz', - '832x624@75Hz', - '1024x768@87Hz(i)', - '1024x768@60Hz', - '1024x768@70Hz', - '1024x768@75Hz', - '1280x1024@75Hz', - '1152x870@75Hz', -] - -# X:Y display aspect ratios, as used in standard timing modes -xy_ratio = [ - (16, 10), - (4, 3), - (5, 4), - (16, 9), -] - -# Annotation classes -ANN_FIELDS = 0 -ANN_SECTIONS = 1 - -class Decoder(srd.Decoder): - api_version = 3 - id = 'edid' - name = 'EDID' - longname = 'Extended Display Identification Data' - desc = 'Data structure describing display device capabilities.' - license = 'gplv3+' - inputs = ['i2c'] - outputs = [] - tags = ['Display', 'Memory', 'PC'] - annotations = ( - ('fields', 'EDID structure fields'), - ('sections', 'EDID structure sections'), - ) - annotation_rows = ( - ('sections', 'Sections', (1,)), - ('fields', 'Fields', (0,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.state = None - # Received data items, used as an index into samplenum/data - self.cnt = 0 - # Start/end sample numbers per data item - self.sn = [] - # Received data - self.cache = [] - # Random read offset - self.offset = 0 - # Extensions - self.extension = 0 - self.ext_sn = [[]] - self.ext_cache = [[]] - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def decode(self, ss, es, data): - cmd, data = data - - if cmd == 'ADDRESS WRITE' and data == 0x50: - self.state = 'offset' - self.ss = ss - return - - if cmd == 'ADDRESS READ' and data == 0x50: - if self.extension > 0: - self.state = 'extensions' - s = str(self.extension) - t = ["Extension: " + s, "X: " + s, s] - else: - self.state = 'header' - t = ["EDID"] - self.put(ss, es, self.out_ann, [ANN_SECTIONS, t]) - return - - if cmd == 'DATA WRITE' and self.state == 'offset': - self.offset = data - self.extension = self.offset // 128 - self.cnt = self.offset % 128 - if self.extension > 0: - ext = self.extension - 1 - l = len(self.ext_sn[ext]) - # Truncate or extend to self.cnt. - self.sn = self.ext_sn[ext][0:self.cnt] + [0] * max(0, self.cnt - l) - self.cache = self.ext_cache[ext][0:self.cnt] + [0] * max(0, self.cnt - l) - else: - l = len(self.sn) - self.sn = self.sn[0:self.cnt] + [0] * max(0, self.cnt - l) - self.cache = self.cache[0:self.cnt] + [0] * max(0, self.cnt - l) - ss = self.ss if self.ss else ss - s = str(data) - t = ["Offset: " + s, "O: " + s, s] - self.put(ss, es, self.out_ann, [ANN_SECTIONS, t]) - return - - # We only care about actual data bytes that are read (for now). - if cmd != 'DATA READ': - return - - self.cnt += 1 - if self.extension > 0: - self.ext_sn[self.extension - 1].append([ss, es]) - self.ext_cache[self.extension - 1].append(data) - else: - self.sn.append([ss, es]) - self.cache.append(data) - - if self.state is None or self.state == 'header': - # Wait for the EDID header - if self.cnt >= OFF_VENDOR: - if self.cache[-8:] == EDID_HEADER: - # Throw away any garbage before the header - self.sn = self.sn[-8:] - self.cache = self.cache[-8:] - self.cnt = 8 - self.state = 'edid' - self.put(self.sn[0][0], es, self.out_ann, - [ANN_SECTIONS, ['Header']]) - self.put(self.sn[0][0], es, self.out_ann, - [ANN_FIELDS, ['Header pattern']]) - elif self.state == 'edid': - if self.cnt == OFF_VERSION: - self.decode_vid(-10) - self.decode_pid(-8) - self.decode_serial(-6) - self.decode_mfrdate(-2) - self.put(self.sn[OFF_VENDOR][0], es, self.out_ann, - [ANN_SECTIONS, ['Vendor/product']]) - elif self.cnt == OFF_BASIC: - self.put(self.sn[OFF_VERSION][0], es, self.out_ann, - [ANN_SECTIONS, ['EDID Version']]) - self.put(self.sn[OFF_VERSION][0], self.sn[OFF_VERSION][1], - self.out_ann, [ANN_FIELDS, - ['Version %d' % self.cache[-2]]]) - self.put(self.sn[OFF_VERSION+1][0], self.sn[OFF_VERSION+1][1], - self.out_ann, [ANN_FIELDS, - ['Revision %d' % self.cache[-1]]]) - elif self.cnt == OFF_CHROM: - self.put(self.sn[OFF_BASIC][0], es, self.out_ann, - [ANN_SECTIONS, ['Basic display']]) - self.decode_basicdisplay(-5) - elif self.cnt == OFF_EST_TIMING: - self.put(self.sn[OFF_CHROM][0], es, self.out_ann, - [ANN_SECTIONS, ['Color characteristics']]) - self.decode_chromaticity(-10) - elif self.cnt == OFF_STD_TIMING: - self.put(self.sn[OFF_EST_TIMING][0], es, self.out_ann, - [ANN_SECTIONS, ['Established timings']]) - self.decode_est_timing(-3) - elif self.cnt == OFF_DET_TIMING: - self.put(self.sn[OFF_STD_TIMING][0], es, self.out_ann, - [ANN_SECTIONS, ['Standard timings']]) - self.decode_std_timing(self.cnt - 16) - elif self.cnt == OFF_NUM_EXT: - self.decode_descriptors(-72) - elif self.cnt == OFF_CHECKSUM: - self.put(ss, es, self.out_ann, - [0, ['Extensions present: %d' % self.cache[self.cnt-1]]]) - elif self.cnt == OFF_CHECKSUM+1: - checksum = 0 - for i in range(128): - checksum += self.cache[i] - if checksum % 256 == 0: - csstr = 'OK' - else: - csstr = 'WRONG!' - self.put(ss, es, self.out_ann, [0, ['Checksum: %d (%s)' % ( - self.cache[self.cnt-1], csstr)]]) - self.state = 'extensions' - - elif self.state == 'extensions': - cache = self.ext_cache[self.extension - 1] - sn = self.ext_sn[self.extension - 1] - v = cache[self.cnt - 1] - if self.cnt == 1: - if v == 2: - self.put(ss, es, self.out_ann, [1, ['Extensions Tag', 'Tag']]) - else: - self.put(ss, es, self.out_ann, [1, ['Bad Tag']]) - elif self.cnt == 2: - self.put(ss, es, self.out_ann, [1, ['Version']]) - self.put(ss, es, self.out_ann, [0, [str(v)]]) - elif self.cnt == 3: - self.put(ss, es, self.out_ann, [1, ['DTD offset']]) - self.put(ss, es, self.out_ann, [0, [str(v)]]) - elif self.cnt == 4: - self.put(ss, es, self.out_ann, [1, ['Format support | DTD count']]) - support = "Underscan: {0}, {1} Audio, YCbCr: {2}".format( - "yes" if v & 0x80 else "no", - "Basic" if v & 0x40 else "No", - ["None", "422", "444", "422+444"][(v & 0x30) >> 4]) - self.put(ss, es, self.out_ann, [0, ['{0}, DTDs: {1}'.format(support, v & 0xf)]]) - elif self.cnt <= cache[2]: - if self.cnt == cache[2]: - self.put(sn[4][0], es, self.out_ann, [1, ['Data block collection']]) - self.decode_data_block_collection(cache[4:], sn[4:]) - elif (self.cnt - cache[2]) % 18 == 0: - n = (self.cnt - cache[2]) / 18 - if n <= cache[3] & 0xf: - self.put(sn[self.cnt - 18][0], es, self.out_ann, [1, ['DTD']]) - self.decode_descriptors(-18) - - elif self.cnt == 127: - dtd_last = cache[2] + (cache[3] & 0xf) * 18 - self.put(sn[dtd_last][0], es, self.out_ann, [1, ['Padding']]) - elif self.cnt == 128: - checksum = sum(cache) % 256 - self.put(ss, es, self.out_ann, [0, ['Checksum: %d (%s)' % ( - cache[self.cnt-1], 'Wrong' if checksum else 'OK')]]) - - def ann_field(self, start, end, annotation): - annotation = annotation if isinstance(annotation, list) else [annotation] - sn = self.ext_sn[self.extension - 1] if self.extension else self.sn - self.put(sn[start][0], sn[end][1], - self.out_ann, [ANN_FIELDS, annotation]) - - def lookup_pnpid(self, pnpid): - pnpid_file = os.path.join(os.path.dirname(__file__), 'pnpids.txt') - if os.path.exists(pnpid_file): - for line in open(pnpid_file).readlines(): - if line.find(pnpid + ';') == 0: - return line[4:].strip() - return '' - - def decode_vid(self, offset): - pnpid = chr(64 + ((self.cache[offset] & 0x7c) >> 2)) - pnpid += chr(64 + (((self.cache[offset] & 0x03) << 3) - | ((self.cache[offset+1] & 0xe0) >> 5))) - pnpid += chr(64 + (self.cache[offset+1] & 0x1f)) - vendor = self.lookup_pnpid(pnpid) - if vendor: - pnpid += ' (%s)' % vendor - self.ann_field(offset, offset+1, pnpid) - - def decode_pid(self, offset): - pidstr = 'Product 0x%.2x%.2x' % (self.cache[offset+1], self.cache[offset]) - self.ann_field(offset, offset+1, pidstr) - - def decode_serial(self, offset): - serialnum = (self.cache[offset+3] << 24) \ - + (self.cache[offset+2] << 16) \ - + (self.cache[offset+1] << 8) \ - + self.cache[offset] - serialstr = '' - is_alnum = True - for i in range(4): - if not chr(self.cache[offset+3-i]).isalnum(): - is_alnum = False - break - serialstr += chr(self.cache[offset+3-i]) - serial = serialstr if is_alnum else str(serialnum) - self.ann_field(offset, offset+3, 'Serial ' + serial) - - def decode_mfrdate(self, offset): - datestr = '' - if self.cache[offset]: - datestr += 'week %d, ' % self.cache[offset] - datestr += str(1990 + self.cache[offset+1]) - if datestr: - self.ann_field(offset, offset+1, ['Manufactured ' + datestr, datestr]) - - def decode_basicdisplay(self, offset): - # Video input definition - vid = self.cache[offset] - if vid & 0x80: - # Digital - self.ann_field(offset, offset, 'Video input: VESA DFP 1.') - else: - # Analog - sls = (vid & 60) >> 5 - self.ann_field(offset, offset, 'Signal level standard: %.2x' % sls) - if vid & 0x10: - self.ann_field(offset, offset, 'Blank-to-black setup expected') - syncs = '' - if vid & 0x08: - syncs += 'separate syncs, ' - if vid & 0x04: - syncs += 'composite syncs, ' - if vid & 0x02: - syncs += 'sync on green, ' - if vid & 0x01: - syncs += 'Vsync serration required, ' - if syncs: - self.ann_field(offset, offset, 'Supported syncs: %s' % syncs[:-2]) - # Max horizontal/vertical image size - if self.cache[offset+1] != 0 and self.cache[offset+2] != 0: - # Projectors have this set to 0 - sizestr = '%dx%dcm' % (self.cache[offset+1], self.cache[offset+2]) - self.ann_field(offset+1, offset+2, 'Physical size: ' + sizestr) - # Display transfer characteristic (gamma) - if self.cache[offset+3] != 0xff: - gamma = (self.cache[offset+3] + 100) / 100 - self.ann_field(offset+3, offset+3, 'Gamma: %1.2f' % gamma) - # Feature support - fs = self.cache[offset+4] - dpms = '' - if fs & 0x80: - dpms += 'standby, ' - if fs & 0x40: - dpms += 'suspend, ' - if fs & 0x20: - dpms += 'active off, ' - if dpms: - self.ann_field(offset+4, offset+4, 'DPMS support: %s' % dpms[:-2]) - dt = (fs & 0x18) >> 3 - dtstr = '' - if dt == 0: - dtstr = 'Monochrome' - elif dt == 1: - dtstr = 'RGB color' - elif dt == 2: - dtstr = 'non-RGB multicolor' - if dtstr: - self.ann_field(offset+4, offset+4, 'Display type: %s' % dtstr) - if fs & 0x04: - self.ann_field(offset+4, offset+4, 'Color space: standard sRGB') - # Save this for when we decode the first detailed timing descriptor - self.have_preferred_timing = (fs & 0x02) == 0x02 - if fs & 0x01: - gft = '' - else: - gft = 'not ' - self.ann_field(offset+4, offset+4, - 'Generalized timing formula: %ssupported' % gft) - - def convert_color(self, value): - # Convert from 10-bit packet format to float - outval = 0.0 - for i in range(10): - if value & 0x01: - outval += 2 ** -(10-i) - value >>= 1 - return outval - - def decode_chromaticity(self, offset): - redx = (self.cache[offset+2] << 2) + ((self.cache[offset] & 0xc0) >> 6) - redy = (self.cache[offset+3] << 2) + ((self.cache[offset] & 0x30) >> 4) - self.ann_field(offset, offset+9, 'Chromacity red: X %1.3f, Y %1.3f' % ( - self.convert_color(redx), self.convert_color(redy))) - - greenx = (self.cache[offset+4] << 2) + ((self.cache[offset] & 0x0c) >> 6) - greeny = (self.cache[offset+5] << 2) + ((self.cache[offset] & 0x03) >> 4) - self.ann_field(offset, offset+9, 'Chromacity green: X %1.3f, Y %1.3f' % ( - self.convert_color(greenx), self.convert_color(greeny))) - - bluex = (self.cache[offset+6] << 2) + ((self.cache[offset+1] & 0xc0) >> 6) - bluey = (self.cache[offset+7] << 2) + ((self.cache[offset+1] & 0x30) >> 4) - self.ann_field(offset, offset+9, 'Chromacity blue: X %1.3f, Y %1.3f' % ( - self.convert_color(bluex), self.convert_color(bluey))) - - whitex = (self.cache[offset+8] << 2) + ((self.cache[offset+1] & 0x0c) >> 6) - whitey = (self.cache[offset+9] << 2) + ((self.cache[offset+1] & 0x03) >> 4) - self.ann_field(offset, offset+9, 'Chromacity white: X %1.3f, Y %1.3f' % ( - self.convert_color(whitex), self.convert_color(whitey))) - - def decode_est_timing(self, offset): - # Pre-EDID modes - bitmap = (self.cache[offset] << 9) \ - + (self.cache[offset+1] << 1) \ - + ((self.cache[offset+2] & 0x80) >> 7) - modestr = '' - for i in range(17): - if bitmap & (1 << (16-i)): - modestr += est_modes[i] + ', ' - if modestr: - self.ann_field(offset, offset+2, - 'Supported established modes: %s' % modestr[:-2]) - - def decode_std_timing(self, offset): - modestr = '' - for i in range(0, 16, 2): - if self.cache[offset+i] == 0x01 and self.cache[offset+i+1] == 0x01: - # Unused field - continue - x = (self.cache[offset+i] + 31) * 8 - ratio = (self.cache[offset+i+1] & 0xc0) >> 6 - ratio_x, ratio_y = xy_ratio[ratio] - y = x / ratio_x * ratio_y - refresh = (self.cache[offset+i+1] & 0x3f) + 60 - modestr += '%dx%d@%dHz, ' % (x, y, refresh) - if modestr: - self.ann_field(offset, offset + 15, - 'Supported standard modes: %s' % modestr[:-2]) - - def decode_detailed_timing(self, cache, sn, offset, is_first): - if is_first and self.have_preferred_timing: - # Only on first detailed timing descriptor - section = 'Preferred' - else: - section = 'Detailed' - section += ' timing descriptor' - - self.put(sn[0][0], sn[17][1], - self.out_ann, [ANN_SECTIONS, [section]]) - - pixclock = float((cache[1] << 8) + cache[0]) / 100 - self.ann_field(offset, offset+1, 'Pixel clock: %.2f MHz' % pixclock) - - horiz_active = ((cache[4] & 0xf0) << 4) + cache[2] - horiz_blank = ((cache[4] & 0x0f) << 8) + cache[3] - self.ann_field(offset+2, offset+4, 'Horizontal active: %d, blanking: %d' % (horiz_active, horiz_blank)) - - vert_active = ((cache[7] & 0xf0) << 4) + cache[5] - vert_blank = ((cache[7] & 0x0f) << 8) + cache[6] - self.ann_field(offset+5, offset+7, 'Vertical active: %d, blanking: %d' % (vert_active, vert_blank)) - - horiz_sync_off = ((cache[11] & 0xc0) << 2) + cache[8] - horiz_sync_pw = ((cache[11] & 0x30) << 4) + cache[9] - vert_sync_off = ((cache[11] & 0x0c) << 2) + ((cache[10] & 0xf0) >> 4) - vert_sync_pw = ((cache[11] & 0x03) << 4) + (cache[10] & 0x0f) - - syncs = (horiz_sync_off, horiz_sync_pw, vert_sync_off, vert_sync_pw) - self.ann_field(offset+8, offset+11, [ - 'Horizontal sync offset: %d, pulse width: %d, Vertical sync offset: %d, pulse width: %d' % syncs, - 'HSync off: %d, pw: %d, VSync off: %d, pw: %d' % syncs]) - - horiz_size = ((cache[14] & 0xf0) << 4) + cache[12] - vert_size = ((cache[14] & 0x0f) << 8) + cache[13] - self.ann_field(offset+12, offset+14, 'Physical size: %dx%dmm' % (horiz_size, vert_size)) - - horiz_border = cache[15] - self.ann_field(offset+15, offset+15, 'Horizontal border: %d pixels' % horiz_border) - vert_border = cache[16] - self.ann_field(offset+16, offset+16, 'Vertical border: %d lines' % vert_border) - - features = 'Flags: ' - if cache[17] & 0x80: - features += 'interlaced, ' - stereo = (cache[17] & 0x60) >> 5 - if stereo: - if cache[17] & 0x01: - features += '2-way interleaved stereo (' - features += ['right image on even lines', - 'left image on even lines', - 'side-by-side'][stereo-1] - features += '), ' - else: - features += 'field sequential stereo (' - features += ['right image on sync=1', 'left image on sync=1', - '4-way interleaved'][stereo-1] - features += '), ' - sync = (cache[17] & 0x18) >> 3 - sync2 = (cache[17] & 0x06) >> 1 - posneg = ['negative', 'positive'] - features += 'sync type ' - if sync == 0x00: - features += 'analog composite (serrate on RGB)' - elif sync == 0x01: - features += 'bipolar analog composite (serrate on RGB)' - elif sync == 0x02: - features += 'digital composite (serrate on composite polarity ' \ - + (posneg[sync2 & 0x01]) + ')' - elif sync == 0x03: - features += 'digital separate (' - features += 'Vsync polarity ' + (posneg[(sync2 & 0x02) >> 1]) - features += ', Hsync polarity ' + (posneg[sync2 & 0x01]) - features += ')' - features += ', ' - self.ann_field(offset+17, offset+17, features[:-2]) - - def decode_descriptor(self, cache, offset): - tag = cache[3] - self.ann_field(offset, offset+1, "Flag") - self.ann_field(offset+2, offset+2, "Flag (reserved)") - self.ann_field(offset+3, offset+3, "Tag: {0:X}".format(tag)) - self.ann_field(offset+4, offset+4, "Flag") - - sn = self.ext_sn[self.extension - 1] if self.extension else self.sn - - if tag == 0xff: - # Monitor serial number - self.put(sn[offset][0], sn[offset+17][1], self.out_ann, - [ANN_SECTIONS, ['Serial number']]) - text = bytes(cache[5:][:13]).decode(encoding='cp437', errors='replace') - self.ann_field(offset+5, offset+17, text.strip()) - elif tag == 0xfe: - # Text - self.put(sn[offset][0], sn[offset+17][1], self.out_ann, - [ANN_SECTIONS, ['Text']]) - text = bytes(cache[5:][:13]).decode(encoding='cp437', errors='replace') - self.ann_field(offset+5, offset+17, text.strip()) - elif tag == 0xfc: - # Monitor name - self.put(sn[offset][0], sn[offset+17][1], self.out_ann, - [ANN_SECTIONS, ['Monitor name']]) - text = bytes(cache[5:][:13]).decode(encoding='cp437', errors='replace') - self.ann_field(offset+5, offset+17, text.strip()) - elif tag == 0xfd: - # Monitor range limits - self.put(sn[offset][0], sn[offset+17][1], self.out_ann, - [ANN_SECTIONS, ['Monitor range limits']]) - self.ann_field(offset+5, offset+5, [ - 'Minimum vertical rate: {0}Hz'.format(cache[5]), - 'VSync >= {0}Hz'.format(cache[5])]) - self.ann_field(offset+6, offset+6, [ - 'Maximum vertical rate: {0}Hz'.format(cache[6]), - 'VSync <= {0}Hz'.format(cache[6])]) - self.ann_field(offset+7, offset+7, [ - 'Minimum horizontal rate: {0}kHz'.format(cache[7]), - 'HSync >= {0}kHz'.format(cache[7])]) - self.ann_field(offset+8, offset+8, [ - 'Maximum horizontal rate: {0}kHz'.format(cache[8]), - 'HSync <= {0}kHz'.format(cache[8])]) - self.ann_field(offset+9, offset+9, [ - 'Maximum pixel clock: {0}MHz'.format(cache[9] * 10), - 'PixClk <= {0}MHz'.format(cache[9] * 10)]) - if cache[10] == 0x02: - self.ann_field(offset+10, offset+10, ['Secondary timing formula supported', '2nd GTF: yes']) - self.ann_field(offset+11, offset+17, ['GTF']) - else: - self.ann_field(offset+10, offset+10, ['Secondary timing formula unsupported', '2nd GTF: no']) - self.ann_field(offset+11, offset+17, ['Padding']) - elif tag == 0xfb: - # Additional color point data - self.put(sn[offset][0], sn[offset+17][1], self.out_ann, - [ANN_SECTIONS, ['Additional color point data']]) - elif tag == 0xfa: - # Additional standard timing definitions - self.put(sn[offset][0], sn[offset+17][1], self.out_ann, - [ANN_SECTIONS, ['Additional standard timing definitions']]) - else: - self.put(sn[offset][0], sn[offset+17][1], self.out_ann, - [ANN_SECTIONS, ['Unknown descriptor']]) - - def decode_descriptors(self, offset): - # 4 consecutive 18-byte descriptor blocks - cache = self.ext_cache[self.extension - 1] if self.extension else self.cache - sn = self.ext_sn[self.extension - 1] if self.extension else self.sn - - for i in range(offset, 0, 18): - if cache[i] != 0 or cache[i+1] != 0: - self.decode_detailed_timing(cache[i:], sn[i:], i, i == offset) - else: - if cache[i+2] == 0 or cache[i+4] == 0: - self.decode_descriptor(cache[i:], i) - - def decode_data_block(self, tag, cache, sn): - codes = { 0: ['0: Reserved'], - 1: ['1: Audio Data Block', 'Audio'], - 2: ['2: Video Data Block', 'Video'], - 3: ['3: Vendor Specific Data Block', 'VSDB'], - 4: ['4: Speacker Allocation Data Block', 'SADB'], - 5: ['5: VESA DTC Data Block', 'DTC'], - 6: ['6: Reserved'], - 7: ['7: Extended', 'Ext'] } - ext_codes = { 0: [ '0: Video Capability Data Block', 'VCDB'], - 1: [ '1: Vendor Specific Video Data Block', 'VSVDB'], - 17: ['17: Vendor Specific Audio Data Block', 'VSADB'], } - if tag < 7: - code = codes[tag] - ext_len = 0 - if tag == 1: - aformats = { 1: '1 (LPCM)' } - rates = [ '192', '176', '96', '88', '48', '44', '32' ] - - aformat = cache[1] >> 3 - sup_rates = [ i for i in range(0, 8) if (1 << i) & cache[2] ] - - data = "Format: {0} Channels: {1}".format( - aformats.get(aformat, aformat), (cache[1] & 0x7) + 1) - data += " Rates: " + " ".join(rates[6 - i] for i in sup_rates) - data += " Extra: [{0:02X}]".format(cache[3]) - - elif tag ==2: - data = "VIC: " - data += ", ".join("{0}{1}".format(v & 0x7f, - ['', ' (Native)'][v >> 7]) - for v in cache[1:]) - - elif tag ==3: - ouis = { b'\x00\x0c\x03': 'HDMI Licensing, LLC' } - oui = bytes(cache[3:0:-1]) - ouis = ouis.get(oui, None) - data = "OUI: " + " ".join('{0:02X}'.format(x) for x in oui) - data += " ({0})".format(ouis) if ouis else "" - data += ", PhyAddr: {0}.{1}.{2}.{3}".format( - cache[4] >> 4, cache[4] & 0xf, cache[5] >> 4, cache[5] & 0xf) - data += ", [" + " ".join('{0:02X}'.format(x) for x in cache[6:]) + "]" - - elif tag ==4: - speakers = [ 'FL/FR', 'LFE', 'FC', 'RL/RR', - 'RC', 'FLC/FRC', 'RLC/RRC', 'FLW/FRW', - 'FLH/FRH', 'TC', 'FCH' ] - sup_speakers = cache[1] + (cache[2] << 8) - sup_speakers = [ i for i in range(0, 8) if (1 << i) & sup_speakers ] - data = "Speakers: " + " ".join(speakers[i] for i in sup_speakers) - - else: - data = " ".join('{0:02X}'.format(x) for x in cache[1:]) - - else: - # Extended tags - ext_len = 1 - ext_code = ext_codes.get(cache[1], ['Unknown', '?']) - code = zip(codes[7], [", ", ": "], ext_code) - code = [ "".join(x) for x in code ] - data = " ".join('{0:02X}'.format(x) for x in cache[2:]) - - self.put(sn[0][0], sn[0 + ext_len][1], self.out_ann, - [ANN_FIELDS, code]) - self.put(sn[1 + ext_len][0], sn[len(cache) - 1][1], self.out_ann, - [ANN_FIELDS, [data]]) - - def decode_data_block_collection(self, cache, sn): - offset = 0 - while offset < len(cache): - length = 1 + cache[offset] & 0x1f - tag = cache[offset] >> 5 - self.decode_data_block(tag, cache[offset:offset + length], sn[offset:]) - offset += length diff --git a/decoders/edid/pnpids.txt b/decoders/edid/pnpids.txt deleted file mode 100755 index 1ced20c5..00000000 --- a/decoders/edid/pnpids.txt +++ /dev/null @@ -1,2135 +0,0 @@ -AAE;Anatek Electronics Inc. -AAT;Ann Arbor Technologies -ABA;ABBAHOME INC. -ABC;AboCom System Inc -ABD;Allen Bradley Company -ABE;Alcatel Bell -ABO;Alcatel Bell -ABT;Anchor Bay Technologies, Inc. -ABV;Advanced Research Technology -ACA;Ariel Corporation -ACB;Aculab Ltd -ACC;Accton Technology Corporation -ACD;AWETA BV -ACE;Actek Engineering Pty Ltd -ACG;A&R Cambridge Ltd -ACH;Archtek Telecom Corporation -ACI;Ancor Communications Inc -ACK;Acksys -ACL;Apricot Computers -ACM;Acroloop Motion Control Systems Inc -ACO;Allion Computer Inc. -ACP;Aspen Tech Inc -ACR;Acer Technologies -ACS;Altos Computer Systems -ACT;Applied Creative Technology -ACU;Acculogic -ACV;ActivCard S.A -ADA;Addi-Data GmbH -ADB;Aldebbaron -ADC;Acnhor Datacomm -ADD;Advanced Peripheral Devices Inc -ADE;Arithmos, Inc. -ADH;Aerodata Holdings Ltd -ADI;ADI Systems Inc -ADK;Adtek System Science Company Ltd -ADL;ASTRA Security Products Ltd -ADM;Ad Lib MultiMedia Inc -ADN;Analog & Digital Devices Tel. Inc -ADP;Adaptec Inc -ADR;Nasa Ames Research Center -ADS;Analog Devices Inc -ADT;Adtek -ADT;Aved Display Technologies -ADV;Advanced Micro Devices Inc -ADX;Adax Inc -AEC;Antex Electronics Corporation -AED;Advanced Electronic Designs, Inc. -AEI;Actiontec Electric Inc -AEJ;Alpha Electronics Company -AEM;ASEM S.p.A. -AEP;Aetas Peripheral International -AET;Aethra Telecomunicazioni S.r.l. -AFA;Alfa Inc -AGC;Beijing Aerospace Golden Card Electronic Engineering Co.,Ltd. -AGI;Artish Graphics Inc -AGL;Argolis -AGM;Advan Int'l Corporation -AGT;Agilent Technologies -AHC;Advantech Co., Ltd. -AIC;Arnos Insturments & Computer Systems -AIE;Altmann Industrieelektronik -AII;Amptron International Inc. -AIL;Altos India Ltd -AIM;AIMS Lab Inc -AIR;Advanced Integ. Research Inc -AIS;Alien Internet Services -AIW;Aiwa Company Ltd -AIX;ALTINEX, INC. -AJA;AJA Video Systems, Inc. -AKB;Akebia Ltd -AKE;AKAMI Electric Co.,Ltd -AKI;AKIA Corporation -AKL;AMiT Ltd -AKM;Asahi Kasei Microsystems Company Ltd -AKP;Atom Komplex Prylad -AKY;Askey Computer Corporation -ALA;Alacron Inc -ALC;Altec Corporation -ALD;In4S Inc -ALG;Realtek Semiconductor Corp. -ALH;AL Systems -ALI;Acer Labs -ALJ;Altec Lansing -ALK;Acrolink Inc -ALL;Alliance Semiconductor Corporation -ALM;Acutec Ltd. -ALN;Alana Technologies -ALO;Algolith Inc. -ALP;Alps Electric Company Ltd -ALR;Advanced Logic -ALS;Avance Logic Inc -ALS;Texas Advanced optoelectronics Solutions, Inc -ALT;Altra -ALV;AlphaView LCD -ALX;ALEXON Co.,Ltd. -AMA;Asia Microelectronic Development Inc -AMB;Ambient Technologies, Inc. -AMC;Attachmate Corporation -AMD;Amdek Corporation -AMI;American Megatrends Inc -AML;Anderson Multimedia Communications (HK) Limited -AMN;Amimon LTD. -AMP;AMP Inc -AMT;AMT International Industry -AMX;AMX LLC -ANA;Anakron -ANC;Ancot -AND;Adtran Inc -ANI;Anigma Inc -ANK;Anko Electronic Company Ltd -ANL;Analogix Semiconductor, Inc -ANO;Anorad Corporation -ANP;Andrew Network Production -ANR;ANR Ltd -ANS;Ansel Communication Company -ANT;Ace CAD Enterprise Company Ltd -ANX;Acer Netxus Inc -AOA;AOpen Inc. -AOE;Advanced Optics Electronics, Inc. -AOL;America OnLine -AOT;Alcatel -APC;American Power Conversion -APD;AppliAdata -APG;Horner Electric Inc -API;A Plus Info Corporation -APL;Aplicom Oy -APM;Applied Memory Tech -APN;Appian Tech Inc -APP;Apple Computer Inc -APR;Aprilia s.p.a. -APS;Autologic Inc -APT;Audio Processing Technology Ltd -APV;A+V Link -APX;AP Designs Ltd -ARC;Alta Research Corporation -ARE;ICET S.p.A. -ARG;Argus Electronics Co., LTD -ARI;Argosy Research Inc -ARK;Ark Logic Inc -ARL;Arlotto Comnet Inc -ARM;Arima -ARO;Poso International B.V. -ARS;Arescom Inc -ART;Corion Industrial Corporation -ASC;Ascom Strategic Technology Unit -ASD;USC Information Sciences Institute -ASE;AseV Display Labs -ASI;Ahead Systems -ASK;Ask A/S -ASL;AccuScene Corporation Ltd -ASM;ASEM S.p.A. -ASN;Asante Tech Inc -ASP;ASP Microelectronics Ltd -AST;AST Research Inc -ASU;Asuscom Network Inc -ASX;AudioScience -ASY;Rockwell Collins / Airshow Systems -ATA;Allied Telesyn International (Asia) Pte Ltd -ATC;Ably-Tech Corporation -ATD;Alpha Telecom Inc -ATE;Innovate Ltd -ATH;Athena Informatica S.R.L. -ATI;Allied Telesis KK -ATK;Allied Telesyn Int'l -ATL;Arcus Technology Ltd -ATM;ATM Ltd -ATN;Athena Smartcard Solutions Ltd. -ATO;ASTRO DESIGN, INC. -ATP;Alpha-Top Corporation -ATT;AT&T -ATV;Office Depot, Inc. -ATX;Athenix Corporation -AUI;Alps Electric Inc -AUO;DO NOT USE - AUO -AUR;Aureal Semiconductor -AUT;Autotime Corporation -AVA;Avaya Communication -AVC;Auravision Corporation -AVD;Avid Electronics Corporation -AVE;Add Value Enterpises (Asia) Pte Ltd -AVI;Nippon Avionics Co.,Ltd -AVM;AVM GmbH -AVN ;Advance Computer Corporation -AVO;Avocent Corporation -AVR;AVerMedia Information, Inc. -AVT;Avtek (Electronics) Pty Ltd -AVV;SBS Technologies (Canada), Inc. (was Avvida Systems, Inc.) -AWC;Access Works Comm Inc -AWL;Aironet Wireless Communications, Inc -AWS;Wave Systems -AXB;Adrienne Electronics Corporation -AXC;AXIOMTEK CO., LTD. -AXE;D-Link Systems Inc (used as 2nd pnpid) -AXI;American Magnetics -AXL;Axel -AXP;American Express -AXT;Axtend Technologies Inc -AXX;Axxon Computer Corporation -AXY;AXYZ Automation Services, Inc -AYD;Aydin Displays -AYR;Airlib, Inc -AZM;AZ Middelheim - Radiotherapy -AZT;Aztech Systems Ltd -BAC;Biometric Access Corporation -BAN;Banyan -BBB;an-najah university -BBH;B&Bh -BBL;Brain Boxes Limited -BCC;Beaver Computer Corporaton -BCD;Dr. Seufert GmbH -BCM;Broadcom -BCQ;Deutsche Telekom Berkom GmbH -BCS;Booria CAD/CAM systems -BDO;Brahler ICS -BDR;Blonder Tongue Labs, Inc. -BDS;Barco Display Systems -BEC;Elektro Beckhoff GmbH -BEI;Beckworth Enterprises Inc -BEK;Beko Elektronik A.S. -BEL;Beltronic Industrieelektronik GmbH -BEO;Baug & Olufsen -BFE;B.F. Engineering Corporation -BGB;Barco Graphics N.V -BGT;Budzetron Inc -BHZ;BitHeadz, Inc. -BIC;Big Island Communications -BII;Boeckeler Instruments Inc -BIL;Billion Electric Company Ltd -BIO;BioLink Technologies International, Inc. -BIT;Bit 3 Computer -BLI;Busicom -BLN;BioLink Technologies -BLP;Bloomberg L.P. -BMI;Benson Medical Instruments Company -BML;BIOMED Lab -BMS;BIOMEDISYS -BNE;Bull AB -BNK;Banksia Tech Pty Ltd -BNO;Bang & Olufsen -BNS;Boulder Nonlinear Systems -BOB;Rainy Orchard -BOE;BOE -BOI;NINGBO BOIGLE DIGITAL TECHNOLOGY CO.,LTD -BOS;BOS -BPD;Micro Solutions, Inc. -BPU;Best Power -BRA;Braemac Pty Ltd -BRC;BARC -BRG;Bridge Information Co., Ltd -BRI;Boca Research Inc -BRM;Braemar Inc -BRO;BROTHER INDUSTRIES,LTD. -BSE;Bose Corporation -BSL;Biomedical Systems Laboratory -BST;BodySound Technologies, Inc. -BTC;Bit 3 Computer -BTE;Brilliant Technology -BTF;Bitfield Oy -BTI;BusTech Inc -BUF;Yasuhiko Shirai Melco Inc -BUJ;ATI Tech Inc -BUL;Bull -BUR;Bernecker & Rainer Ind-Eletronik GmbH -BUS;BusTek -BUT;21ST CENTURY ENTERTAINMENT -BWK;Bitworks Inc. -BXE;Buxco Electronics -BYD;byd:sign corporation -CAA;Castles Automation Co., Ltd -CAC;CA & F Elettronica -CAG;CalComp -CAI;Canon Inc. -CAL;Acon -CAM;Cambridge Audio -CAN;Canopus Company Ltd -CAN;Carrera Computer Inc -CAN;CORNEA -CAR;Cardinal Company Ltd -CAS;CASIO COMPUTER CO.,LTD -CAT;Consultancy in Advanced Technology -CBI;ComputerBoards Inc -CBR;Cebra Tech A/S -CBT;Cabletime Ltd -CBX;Cybex Computer Products Corporation -CCC;C-Cube Microsystems -CCI;Cache -CCJ;CONTEC CO.,LTD. -CCL;CCL/ITRI -CCP;Capetronic USA Inc -CDC;Core Dynamics Corporation -CDD;Convergent Data Devices -CDE;Colin.de -CDG;Christie Digital Systems Inc -CDI;Concept Development Inc -CDK;Cray Communications -CDN;Codenoll Technical Corporation -CDP;CalComp -CDS;Computer Diagnostic Systems -CDT;IBM Corporation -CDV;Convergent Design Inc. -CEA;Consumer Electronics Association -CEC;Chicony Electronics Company Ltd -CED;Cambridge Electronic Design Ltd -CEF;Cefar Digital Vision -CEI;Crestron Electronics, Inc. -CEM;MEC Electronics GmbH -CEN;Centurion Technologies P/L -CEP;C-DAC -CER;Ceronix -CET;TEC CORPORATION -CFG;Atlantis -CGA;Chunghwa Picture Tubes, LTD -CGS;Chyron Corp -CHA;Chase Research PLC -CHC;Chic Technology Corp. -CHD;ChangHong Electric Co.,Ltd -CHE;Acer Inc -CHG;Sichuan Changhong Electric CO, LTD. -CHI;Chrontel Inc -CHL;Chloride-R&D -CHM;CHIC TECHNOLOGY CORP. -CHO;Sichuang Changhong Corporation -CHP;CH Products -CHS;Agentur Chairos -CHT;Chunghwa Picture Tubes,LTD. -CHY;Cherry GmbH -CIC;Comm. Intelligence Corporation -CII;Cromack Industries Inc -CIL;Citicom Infotech Private Limited -CIN;Citron GmbH -CIP;Ciprico Inc -CIR;Cirrus Logic Inc -CIS;Cisco Systems Inc -CIT;Citifax Limited -CKC;The Concept Keyboard Company Ltd -CKJ;Carina System Co., Ltd. -CLA;Clarion Company Ltd -CLD;COMMAT L.t.d. -CLE;Classe Audio -CLG;CoreLogic -CLI;Cirrus Logic Inc -CLM;CrystaLake Multimedia -CLO;Clone Computers -CLT;automated computer control systems -CLV;Clevo Company -CLX;CardLogix -CMC;CMC Ltd -CMD;Colorado MicroDisplay, Inc. -CMG;Chenming Mold Ind. Corp. -CMI;C-Media Electronics -CMM;Comtime GmbH -CMN;Chimei Innolux Corporation -CMO;Chi Mei Optoelectronics corp. -CMR;Cambridge Research Systems Ltd -CMS;CompuMaster Srl -CMX;Comex Electronics AB -CNB;American Power Conversion -CNC;Alvedon Computers Ltd -CNE;Cine-tal -CNI;Connect Int'l A/S -CNN;Canon Inc -CNT;COINT Multimedia Systems -COB;COBY Electronics Co., Ltd -COD;CODAN Pty. Ltd. -COI;Codec Inc. -COL;Rockwell Collins, Inc. -COM;Comtrol Corporation -CON;Contec Company Ltd -COO;coolux GmbH -COR;Corollary Inc -COS;CoStar Corporation -COT;Core Technology Inc -COW;Polycow Productions -CPC;Ciprico Inc -CPD;CompuAdd -CPI;Computer Peripherals Inc -CPL;Compal Electronics Inc -CPQ;Compaq Computer Company -CPT;cPATH -CPX;Powermatic Data Systems -CRC;CONRAC GmbH -CRD;Cardinal Technical Inc -CRE;Creative Labs Inc -CRI;Crio Inc. -CRL;Creative Logic   -CRN;Cornerstone Imaging -CRO;Extraordinary Technologies PTY Limited -CRQ;Cirque Corporation -CRS;Crescendo Communication Inc -CRV;Cerevo Inc. -CRX;Cyrix Corporation -CSB;Transtex SA -CSC;Crystal Semiconductor -CSD;Cresta Systems Inc -CSE;Concept Solutions & Engineering -CSI;Cabletron System Inc -CSO;California Institute of Technology -CSS;CSS Laboratories -CST;CSTI Inc -CTA;CoSystems Inc -CTC;CTC Communication Development Company Ltd -CTE;Chunghwa Telecom Co., Ltd. -CTL;Creative Technology Ltd -CTM;Computerm Corporation -CTN;Computone Products -CTP;Computer Technology Corporation -CTS;Comtec Systems Co., Ltd. -CTX;Creatix Polymedia GmbH -CUB;Cubix Corporation -CUK;Calibre UK Ltd -CVA;Covia Inc. -CVS;Clarity Visual Systems -CWR;Connectware Inc -CXT;Conexant Systems -CYB;CyberVision -CYC;Cylink Corporation -CYD;Cyclades Corporation -CYL;Cyberlabs -CYT;Cytechinfo Inc -CYV;Cyviz AS -CYW;Cyberware -CYX;Cyrix Corporation -CZE;Carl Zeiss AG -DAC;Digital Acoustics Corporation -DAE;Digatron Industrie Elektronik GmbH -DAI;DAIS SET Ltd. -DAK;Daktronics -DAL;Digital Audio Labs Inc -DAN;Danelec Marine A/S -DAS;DAVIS AS -DAT;Datel Inc -DAU;Daou Tech Inc -DAV;Davicom Semiconductor Inc -DAW;DA2 Technologies Inc -DAX;Data Apex Ltd -DBD;Diebold Inc. -DBI;DigiBoard Inc -DBK;Databook Inc -DBL;Doble Engineering Company -DBN;DB Networks Inc -DCA;Digital Communications Association -DCC;Dale Computer Corporation -DCD;Datacast LLC -DCE;dSPACE GmbH -DCI;Concepts Inc -DCL;Dynamic Controls Ltd -DCM;DCM Data Products -DCO;Dialogue Technology Corporation -DCR;Decros Ltd -DCS;Diamond Computer Systems Inc -DCT;Dancall Telecom A/S -DCV;Datatronics Technology Inc -DDA;DA2 Technologies Corporation -DDD;Danka Data Devices -DDI;Data Display AG -DDS;Barco, n.v. -DDT;Datadesk Technologies Inc -DEC;Digital Equipment Corporation -DEI;Deico Electronics -DEL;Dell Inc. -DEN;Densitron Computers Ltd -DEX;idex displays -DFI;DFI -DFK;SharkTec A/S -DGA;Digiital Arts Inc -DGC;Data General Corporation -DGI;DIGI International -DGK;DugoTech Co., LTD -DGP;Digicorp European sales S.A. -DGS;Diagsoft Inc -DGT;The Dearborn Group -DGT;Dearborn Group Technology -DHP;DH Print -DHQ;Quadram -DHT;Projectavision Inc -DIA;Diadem -DIG;Digicom S.p.A. -DII;Dataq Instruments Inc -DIM;dPict Imaging, Inc. -DIN;Daintelecom Co., Ltd -DIS;Diseda S.A. -DIT;Dragon Information Technology -DJE;Capstone Visua lProduct Development -DJP;Maygay Machines, Ltd -DKY;Datakey Inc -DLB;Dolby Laboratories Inc. -DLC;Diamond Lane Comm. Corporation -DLG;Digital-Logic GmbH -DLK;D-Link Systems Inc -DLL;Dell Inc -DLT;Digitelec Informatique Park Cadera -DMB;Digicom Systems Inc -DMC;Dune Microsystems Corporation -DMM;Dimond Multimedia Systems Inc -DMP;D&M Holdings Inc, Professional Business Company -DMS;DOME imaging systems -DMT;Distributed Management Task Force, Inc. (DMTF) -DMV;NDS Ltd -DNA;DNA Enterprises, Inc. -DNG;Apache Micro Peripherals Inc -DNI;Deterministic Networks Inc. -DNT;Dr. Neuhous Telekommunikation GmbH -DNV;DiCon -DOL;Dolman Technologies Group Inc -DOM;Dome Imaging Systems -DON;DENON, Ltd. -DOT;Dotronic Mikroelektronik GmbH -DPA;DigiTalk Pro AV -DPC;Delta Electronics Inc -DPI;DocuPoint -DPL;Digital Projection Limited -DPM;ADPM Synthesis sas -DPS;Digital Processing Systems -DPT;DPT -DPX;DpiX, Inc. -DQB;Datacube Inc -DRB;Dr. Bott KG -DRC;Data Ray Corp. -DRD;DIGITAL REFLECTION INC. -DRI;Data Race Inc -DSD;DS Multimedia Pte Ltd -DSI;Digitan Systems Inc -DSM;DSM Digital Services GmbH -DSP;Domain Technology Inc -DTA;DELTATEC -DTC;DTC Tech Corporation -DTE;Dimension Technologies, Inc. -DTI;Diversified Technology, Inc. -DTK;Dynax Electronics (HK) Ltd -DTL;e-Net Inc -DTN;Datang Telephone Co -DTO;Deutsche Thomson OHG -DTT;Design & Test Technology, Inc. -DTX;Data Translation -DUA;Dosch & Amand GmbH & Company KG -DUN;NCR Corporation -DVD;Dictaphone Corporation -DVL;Devolo AG -DVS;Digital Video System -DVT;Data Video -DWE;Daewoo Electronics Company Ltd -DXC;Digipronix Control Systems -DXL;Dextera Labs Inc -DXP;Data Expert Corporation -DXS;Signet -DYC;Dycam Inc -DYM;Dymo-CoStar Corporation -DYN;Askey Computer Corporation -DYX;Dynax Electronics (HK) Ltd -EAS;Evans and Sutherland Computer -EBH;Data Price Informatica -EBT;HUALONG TECHNOLOGY CO., LTD -ECA;Electro Cam Corp. -ECC;ESSential Comm. Corporation -ECI;Enciris Technologies -ECK;Eugene Chukhlomin Sole Proprietorship, d.b.a. -ECL;Excel Company Ltd -ECM;E-Cmos Tech Corporation -ECO;Echo Speech Corporation -ECP;Elecom Company Ltd -ECS;Elitegroup Computer Systems Company Ltd -ECT;Enciris Technologies -EDC;e.Digital Corporation -EDG;Electronic-Design GmbH -EDI;Edimax Tech. Company Ltd -EDM;EDMI -EDT;Emerging Display Technologies Corp -EEE;ET&T Technology Company Ltd -EEH;EEH Datalink GmbH -EEP;E.E.P.D. GmbH -EES;EE Solutions, Inc. -EGD;EIZO GmbH Display Technologies -EGL;Eagle Technology -EGN;Egenera, Inc. -EGO;Ergo Electronics -EHJ;Epson Research -EHN;Enhansoft -EIC;Eicon Technology Corporation -EKA;MagTek Inc. -EKC;Eastman Kodak Company -EKS;EKSEN YAZILIM -ELA;ELAD srl -ELC;Electro Scientific Ind -ELE;Elecom Company Ltd -ELG;Elmeg GmbH Kommunikationstechnik -ELI;Edsun Laboratories -ELL;Electrosonic Ltd -ELM;Elmic Systems Inc -ELO;Elo TouchSystems Inc -ELO;Tyco Electronics -ELS;ELSA GmbH -ELT;Element Labs, Inc. -ELX;Elonex PLC -EMB;Embedded computing inc ltd -EMC;eMicro Corporation -EME;EMiNE TECHNOLOGY COMPANY, LTD. -EMG;EMG Consultants Inc -EMI;Ex Machina Inc -EMU;Emulex Corporation -ENC;Eizo Nanao Corporation -END;ENIDAN Technologies Ltd -ENE;ENE Technology Inc. -ENI;Efficient Networks -ENS;Ensoniq Corporation -ENT;Enterprise Comm. & Computing Inc -EPC;Empac -EPI;Envision Peripherals, Inc -EPN;EPiCON Inc. -EPS;KEPS -EQP;Equipe Electronics Ltd. -EQX;Equinox Systems Inc -ERG;Ergo System -ERI;Ericsson Mobile Communications AB -ERN;Ericsson, Inc. -ERP;Euraplan GmbH -ERT;Escort Insturments Corporation -ESA;Elbit Systems of America -ESC;Eden Sistemas de Computacao S/A -ESD;Ensemble Designs, Inc -ESG;ELCON Systemtechnik GmbH -ESI;Extended Systems, Inc. -ESK;ES&S -ESS;ESS Technology Inc -EST;Embedded Solution Technology -ESY;E-Systems Inc -ETC;Everton Technology Company Ltd -ETD;ELAN MICROELECTRONICS CORPORATION -ETH;Etherboot Project -ETI;Eclipse Tech Inc -ETK;eTEK Labs Inc. -ETL;Evertz Microsystems Ltd. -ETS;Electronic Trade Solutions Ltd -ETT;E-Tech Inc -EUT;Ericsson Mobile Networks B.V. -EVI;eviateg GmbH -EVX;Everex -EXA;Exabyte -EXC;Excession Audio -EXI;Exide Electronics -EXN;RGB Systems, Inc. dba Extron Electronics -EXP;Data Export Corporation -EXT;Exatech Computadores & Servicos Ltda -EXX;Exxact GmbH -EXY;Exterity Ltd -EZE;EzE Technologies -EZP;Storm Technology -FAR;Farallon Computing -FBI;Interface Corporation -FCB;Furukawa Electric Company Ltd -FCG;First International Computer Ltd -FCS;Focus Enhancements, Inc. -FDC;Future Domain -FDT;Fujitsu Display Technologies Corp. -FEC;FURUNO ELECTRIC CO., LTD. -FEL;Fellowes & Questec -FEN;Fen Systems Ltd. -FER;Ferranti Int'L -FFI;Fairfield Industries -FGD;Lisa Draexlmaier GmbH -FGL;Fujitsu General Limited. -FHL;FHLP -FIC;Formosa Industrial Computing Inc -FIL;Forefront Int'l Ltd -FIN;Finecom Co., Ltd. -FIR;Chaplet Systems Inc -FIS;FLY-IT Simulators -FIT;Feature Integration Technology Inc. -FJC;Fujitsu Takamisawa Component Limited -FJS;Fujitsu Spain -FJT;F.J. Tieman BV -FLE;ADTI Media, Inc -FLI;Faroudja Laboratories -FLY;Butterfly Communications -FMA;Fast Multimedia AG -FMC;Ford Microelectronics Inc -FMI;Fujitsu Microelect Inc -FMI;Fellowes, Inc. -FML;Fujitsu Microelect Ltd -FMZ;Formoza-Altair -FNC;Fanuc LTD -FNI;Funai Electric Co., Ltd. -FOA;FOR-A Company Limited -FOS;Foss Tecator -FOX;HON HAI PRECISON IND.CO.,LTD. -FPE;Fujitsu Peripherals Ltd -FPS;Deltec Corporation -FPX;Cirel Systemes -FRC;Force Computers -FRD;Freedom Scientific BLV -FRE;Forvus Research Inc -FRI;Fibernet Research Inc -FRS;South Mountain Technologies, LTD -FSC;Future Systems Consulting KK -FSI;Fore Systems Inc -FST;Modesto PC Inc -FTC;Futuretouch Corporation -FTE;Frontline Test Equipment Inc. -FTG;FTG Data Systems -FTI;FastPoint Technologies, Inc. -FTN;Fountain Technologies Inc -FTR;Mediasonic -FUJ;Fujitsu Ltd -FUN;sisel muhendislik -FUS;Fujitsu Siemens Computers GmbH -FVC;First Virtual Corporation -FVX;C-C-C Group Plc -FWA;Attero Tech, LLC -FWR;Flat Connections Inc -FXX;Fuji Xerox -FZC;Founder Group Shenzhen Co. -FZI;FZI Forschungszentrum Informatik -GAG;Gage Applied Sciences Inc -GAL;Galil Motion Control -GAU;Gaudi Co., Ltd. -GCC;GCC Technologies Inc -GCI;Gateway Comm. Inc -GCS;Grey Cell Systems Ltd -GDC;General Datacom -GDI;G. Diehl ISDN GmbH -GDS;GDS -GDT;Vortex Computersysteme GmbH -GEF;GE Fanuc Embedded Systems -GEH;GE Intelligent Platforms - Huntsville -GEM;Gem Plus -GEN;Genesys ATE Inc -GEO;GEO Sense -GES;GES Singapore Pte Ltd -GET;Getac Technology Corporation -GFM;GFMesstechnik GmbH -GFN;Gefen Inc. -GGL;Google Inc. -GIC;General Inst. Corporation -GIM;Guillemont International -GIS;AT&T Global Info Solutions -GJN;Grand Junction Networks -GLE;AD electronics -GLM;Genesys Logic -GLS;Gadget Labs LLC -GMK;GMK Electronic Design GmbH -GML;General Information Systems -GMM;GMM Research Inc -GMN;GEMINI 2000 Ltd -GMX;GMX Inc -GND;Gennum Corporation -GNN;GN Nettest Inc -GNZ;Gunze Ltd -GRA;Graphica Computer -GRE;GOLD RAIN ENTERPRISES CORP. -GRH;Granch Ltd -GRV;Advanced Gravis -GRY;Robert Gray Company -GSB;NIPPONDENCHI CO,.LTD -GSC;General Standards Corporation -GSM;Goldstar Company Ltd -GST;Graphic SystemTechnology -GSY;Grossenbacher Systeme AG -GTC;Graphtec Corporation -GTI;Goldtouch -GTK;G-Tech Corporation -GTM;Garnet System Company Ltd -GTS;Geotest Marvin Test Systems Inc -GTT;General Touch Technology Co., Ltd. -GUD;Guntermann & Drunck GmbH -GUZ;Guzik Technical Enterprises -GVC;GVC Corporation -GVL;Global Village Communication -GWI;GW Instruments -GWY;Gateway 2000 -GZE;GUNZE Limited -HAE;Haider electronics -HAI;Haivision Systems Inc. -HAL;Halberthal -HAN;Hanchang System Corporation -HAY;Hayes Microcomputer Products Inc -HCA;DAT -HCE;Hitachi Consumer Electronics Co., Ltd -HCL;HCL America Inc -HCM;HCL Peripherals -HCP;Hitachi Computer Products Inc -HCW;Hauppauge Computer Works Inc -HDC;HardCom Elektronik & Datateknik -HDI;HD-INFO d.o.o. -HDV;Holografika kft. -HEC;Hitachi Engineering Company Ltd -HEC;Hisense Electric Co., Ltd. -HEL;Hitachi Micro Systems Europe Ltd -HER;Ascom Business Systems -HET;HETEC Datensysteme GmbH -HHC;HIRAKAWA HEWTECH CORP. -HIB;Hibino Corporation -HIC;Hitachi Information Technology Co., Ltd. -HIK;Hikom Co., Ltd. -HIL;Hilevel Technology -HIT;Hitachi America Ltd -HJI;Harris & Jeffries Inc -HKA;HONKO MFG. CO., LTD. -HKG;Josef Heim KG -HMC;Hualon Microelectric Corporation -HMK;hmk Daten-System-Technik BmbH -HMX;HUMAX Co., Ltd. -HNS;Hughes Network Systems -HOB;HOB Electronic GmbH -HOE;Hosiden Corporation -HOL;Holoeye Photonics AG -HPA;Zytor Communications -HPC;Hewlett Packard Co. -HPD;Hewlett Packard -HPI;Headplay, Inc. -HPK;HAMAMATSU PHOTONICS K.K. -HPQ;HP -HPR;H.P.R. Electronics GmbH -HRC;Hercules -HRE;Qingdao Haier Electronics Co., Ltd. -HRL;Herolab GmbH -HRS;Harris Semiconductor -HRT;HERCULES -HSC;Hagiwara Sys-Com Company Ltd -HSD;HannStar Display Corp -HSM;AT&T Microelectronics -HSP;HannStar Display Corp -HTC;Hitachi Ltd -HTI;Hampshire Company, Inc. -HTK;Holtek Microelectronics Inc -HTX;Hitex Systementwicklung GmbH -HUB;GAI-Tronics, A Hubbell Company -HUM;IMP Electronics Ltd. -HWA;Harris Canada Inc -HWC;DBA Hans Wedemeyer -HWD;Highwater Designs Ltd -HWP;Hewlett Packard -HXM;Hexium Ltd. -HYC;Hypercope Gmbh Aachen -HYD;Hydis Technologies.Co.,LTD -HYO;HYC CO., LTD. -HYP;Hyphen Ltd -HYR;Hypertec Pty Ltd -HYT;Heng Yu Technology (HK) Limited -HYV;Hynix Semiconductor -IAF;Institut f r angewandte Funksystemtechnik GmbH -IAI;Integration Associates, Inc. -IAT;IAT Germany GmbH -IBC;Integrated Business Systems -IBI;INBINE.CO.LTD -IBM;IBM Brasil -IBM;IBM France -IBP;IBP Instruments GmbH -IBR;IBR GmbH -ICA;ICA Inc -ICC;BICC Data Networks Ltd -ICD;ICD Inc -ICE;IC Ensemble -ICI;Infotek Communication Inc -ICM;Intracom SA -ICN;Sanyo Icon -ICO;Intel Corp -ICS;Integrated Circuit Systems -ICV;Inside Contactless -ICX;ICCC A/S -IDC;International Datacasting Corporation -IDE;IDE Associates -IDK;IDK Corporation -IDO;IDEO Product Development -IDP;Integrated Device Technology, Inc. -IDS;Interdigital Sistemas de Informacao -IDT;International Display Technology -IDX;IDEXX Labs -IEC;Interlace Engineering Corporation -IEE;IEE -IEI;Interlink Electronics -IFS;In Focus Systems Inc -IFT;Informtech -IFX;Infineon Technologies AG -IGC;Intergate Pty Ltd -IGM;IGM Communi -IHE;InHand Electronics -IIC;ISIC Innoscan Industrial Computers A/S -III;Intelligent Instrumentation -IIN;IINFRA Co., Ltd -IKS;Ikos Systems Inc -ILC;Image Logic Corporation -ILS;Innotech Corporation -IMA;Imagraph -IMC;IMC Networks -IMD;ImasDe Canarias S.A. -IME;Imagraph -IMG;IMAGENICS Co., Ltd. -IMI;International Microsystems Inc -IMM;Immersion Corporation -IMN;Impossible Production -IMP;Impression Products Incorporated -IMT;Inmax Technology Corporation -INC;Home Row Inc -IND;ILC -INE;Inventec Electronics (M) Sdn. Bhd. -INF;Inframetrics Inc -ING;Integraph Corporation -INI;Initio Corporation -INK;Indtek Co., Ltd. -INL;InnoLux Display Corporation -INM;InnoMedia Inc -INN;Innovent Systems, Inc. -INO;Innolab Pte Ltd -INP;Interphase Corporation -INS;Ines GmbH -INT;Interphase Corporation -inu;Inovatec S.p.A. -INV;Inviso, Inc. -INZ;Best Buy -IOA;CRE Technology Corporation -IOD;I-O Data Device Inc -IOM;Iomega -ION;Inside Out Networks -IOS;i-O Display System -IOT;I/OTech Inc -IPC;IPC Corporation -IPD;Industrial Products Design, Inc. -IPI;Intelligent Platform Management Interface (IPMI) forum (Intel, HP, NEC, Dell) -IPM;IPM Industria Politecnica Meridionale SpA -IPN;Performance Technologies -IPR;Ithaca Peripherals -IPS;IPS, Inc. (Intellectual Property Solutions, Inc.) -IPT;International Power Technologies -IPW;IPWireless, Inc -IQT;IMAGEQUEST Co., Ltd -IRD;IRdata -ISA;Symbol Technologies -ISC;Id3 Semiconductors -ISG;Insignia Solutions Inc -ISI;Interface Solutions -ISL;Isolation Systems -ISM;Image Stream Medical -ISP;IntreSource Systems Pte Ltd -ISR;INSIS Co., LTD. -ISS;ISS Inc -IST;Intersolve Technologies -ISY;International Integrated Systems,Inc.(IISI) -ITA;Itausa Export North America -ITC;Intercom Inc -ITD;Internet Technology Corporation -ITE;Integrated Tech Express Inc -ITK;ITK Telekommunikation AG -ITL;Inter-Tel -ITM;ITM inc. -ITN;The NTI Group -ITP;IT-PRO Consulting und Systemhaus GmbH -ITR;Infotronic America, Inc. -ITS;IDTECH -ITT;I&T Telecom. -ITX;integrated Technology Express Inc -IUC;ICSL -IVI;Intervoice Inc -IVM;Liyama North America -IWR;Icuiti Corporation -IWX;Intelliworxx, Inc. -IXD;Intertex Data AB -JAC;Astec Inc -JAE;Japan Aviation Electronics Industry, Limited -JAS;Janz Automationssysteme AG -JAT;Jaton Corporation -JAZ;Carrera Computer Inc (used as second pnpid) -JCE;Jace Tech Inc -JDL;Japan Digital Laboratory Co.,Ltd. -JEN;N-Vision -JET;JET POWER TECHNOLOGY CO., LTD. -JFX;Jones Futurex Inc -JGD;University College -JIC;Jaeik Information & Communication Co., Ltd. -JMT;Micro Technical Company Ltd -JPC;JPC Technology Limited -JPW;Wallis Hamilton Industries -JQE;CNet Technical Inc -JSD;JS DigiTech, Inc -JSI;Jupiter Systems, Inc. -JSK;SANKEN ELECTRIC CO., LTD -JTS;JS Motorsports -JTY;jetway security micro,inc -JUK;Janich & Klass Computertechnik GmbH -JUP;Jupiter Systems -JVC;JVC -JWD;Video International Inc. -JWL;Jewell Instruments, LLC -JWS;JWSpencer & Co. -JWY;Jetway Information Co., Ltd -KAR;Karna -KBI;Kidboard Inc -KBL;Kobil Systems GmbH -KCL;Keycorp Ltd -KDE;KDE -KDK;Kodiak Tech -KDM;Korea Data Systems Co., Ltd. -KDS;KDS USA -KEC;Kyushu Electronics Systems Inc -KEM;Kontron Embedded Modules GmbH -KES;Kesa Corporation -KEY;Key Tech Inc -KFC;SCD Tech -KFE ;Komatsu Forest -KFX;Kofax Image Products -KIS;KiSS Technology A/S -KMC;Mitsumi Company Ltd -KML;Kensington Microware Ltd -KNC;Konica corporation -KNX;Nutech Marketing PTL -KOB;Kobil Systems GmbH -KOD;Eastman Kodak Company -KOE;KOLTER ELECTRONIC -KOL;Kollmorgen Motion Technologies Group -KOW;KOWA Company,LTD. -KPC;King Phoenix Company -KRL;Krell Industries Inc. -KRM;Kroma Telecom -KRY;Kroy LLC -KSC;Kinetic Systems Corporation -KSL;Karn Solutions Ltd. -KSX;King Tester Corporation -KTC;Kingston Tech Corporation -KTD;Takahata Electronics Co.,Ltd. -KTE;K-Tech -KTG;Kayser-Threde GmbH -KTI;Konica Technical Inc -KTK;Key Tronic Corporation -KTN;Katron Tech Inc -KUR;Kurta Corporation -KVA;Kvaser AB -KWD;Kenwood Corporation -KYC;Kyocera Corporation -KYE;KYE Syst Corporation -KYK;Samsung Electronics America Inc -KZI;K-Zone International co. Ltd. -KZN;K-Zone International -LAB;ACT Labs Ltd -LAC;LaCie -LAF;Microline -LAG;Laguna Systems -LAN;Sodeman Lancom Inc -LAS;LASAT Comm. A/S -LAV;Lava Computer MFG Inc -LBO;Lubosoft -LCC;LCI -LCD;Toshiba Matsushita Display Technology Co., Ltd -LCE;La Commande Electronique -LCI;Lite-On Communication Inc -LCM;Latitude Comm. -LCN;LEXICON -LCS;Longshine Electronics Company -LCT;Labcal Technologies -LDT;LogiDataTech Electronic GmbH -LEC;Lectron Company Ltd -LED;Long Engineering Design Inc -LEG;Legerity, Inc -LEN;Lenovo Group Limited -LEO;First International Computer Inc -LEX;Lexical Ltd -LGC;Logic Ltd -LGI;Logitech Inc -LGS;LG Semicom Company Ltd -LGX;Lasergraphics, Inc. -LHA;Lars Haagh ApS -LHE;Lung Hwa Electronics Company Ltd -LHT;Lighthouse Technologies Limited -LIP;Linked IP GmbH -LIT;Lithics Silicon Technology -LJX;Datalogic Corporation -LKM;Likom Technology Sdn. Bhd. -LLL;L-3 Communications -LMG;Lucent Technologies -LMI;Lexmark Int'l Inc -LMP;Leda Media Products -LMT;Laser Master -LND;Land Computer Company Ltd -LNK;Link Tech Inc -LNR;Linear Systems Ltd. -LNT;LANETCO International -LNV;Lenovo -LOC;Locamation B.V. -LOE;Loewe Opta GmbH -LOG;Logicode Technology Inc -LPE;El-PUSK Co., Ltd. -LPI;Design Technology -LPL;DO NOT USE - LPL -LSC;LifeSize Communications -LSI;Loughborough Sound Images -LSJ;LSI Japan Company Ltd -LSL;Logical Solutions -LSY;LSI Systems Inc -LTC;Labtec Inc -LTI;Jongshine Tech Inc -LTK;Lucidity Technology Company Ltd -LTN;Litronic Inc -LTS;LTS Scale LLC -LTV;Leitch Technology International Inc. -LTW;Lightware, Inc -LUC;Lucent Technologies -LUM;Lumagen, Inc. -LUX;Luxxell Research Inc -LWC;Labway Corporation -LWR;Lightware Visual Engineering -LWW;Lanier Worldwide -LXN;Luxeon -LXS;ELEA CardWare -LZX;Lightwell Company Ltd -MAC;MAC System Company Ltd -MAD;Xedia Corporation -MAE;Maestro Pty Ltd -MAG;MAG InnoVision -MAI;Mutoh America Inc -MAL;Meridian Audio Ltd -MAN;LGIC -MAS;Mass Inc. -MAT;Matsushita Electric Ind. Company Ltd -MAX;Rogen Tech Distribution Inc -MAY;Maynard Electronics -MAZ;MAZeT GmbH -MBC;MBC -MBD;Microbus PLC -MBM;Marshall Electronics -MBV;Moreton Bay -MCA;American Nuclear Systems Inc -MCC;Micro Industries -MCD;McDATA Corporation -MCE;Metz-Werke GmbH & Co KG -MCG;Motorola Computer Group -MCI;Micronics Computers -MCL;Motorola Communications Israel -MCM;Metricom Inc -MCN;Micron Electronics Inc -MCO;Motion Computing Inc. -MCP;Magni Systems Inc -MCQ;Mat's Computers -MCR;Marina Communicaitons -MCS;Micro Computer Systems -MCT;Microtec -MDA;Media4 Inc -MDC;Midori Electronics -MDD;MODIS -MDG;Madge Networks -MDI;Micro Design Inc -MDK;Mediatek Corporation -MDO;Panasonic -MDR;Medar Inc -MDS;Micro Display Systems Inc -MDT;Magus Data Tech -MDV;MET Development Inc -MDX;MicroDatec GmbH -MDY;Microdyne Inc -MEC;Mega System Technologies Inc -MED;Messeltronik Dresden GmbH -MEE;Mitsubishi Electric Engineering Co., Ltd. -MEG;Abeam Tech Ltd -MEI;Panasonic Industry Company -MEL;Mitsubishi Electric Corporation -MEN;MEN Mikroelectronik Nueruberg GmbH -MEQ;Matelect Ltd. -MET;Metheus Corporation -MFG;MicroField Graphics Inc -MFI;Micro Firmware -MFR;MediaFire Corp. -MGA;Mega System Technologies, Inc. -MGC;Mentor Graphics Corporation -MGE;Schneider Electric S.A. -MGL;M-G Technology Ltd -MGT;Megatech R & D Company -MIC;Micom Communications Inc -MID;miro Displays -MII;Mitec Inc -MIL;Marconi Instruments Ltd -MIN;Minicom Digital Signage -MIP;micronpc.com -MIR;Miro Computer Prod. -MIS;Modular Industrial Solutions Inc -MIT;MCM Industrial Technology GmbH -MJI;MARANTZ JAPAN, INC. -MJS;MJS Designs -MKC;Media Tek Inc. -MKT;MICROTEK Inc. -MKV;Trtheim Technology -MLD;Deep Video Imaging Ltd -MLG;Micrologica AG -MLI;McIntosh Laboratory Inc. -MLM;Millennium Engineering Inc -MLN;Mark Levinson -MLS;Milestone EPE -MLX;Mylex Corporation -MMA;Micromedia AG -MMD;Micromed Biotecnologia Ltd -MMF;Minnesota Mining and Manufacturing -MMI;Multimax -MMM;Electronic Measurements -MMN;MiniMan Inc -MMS;MMS Electronics -MNC;Mini Micro Methods Ltd -MNL;Monorail Inc -MNP;Microcom -MOD;Modular Technology -MOM;Momentum Data Systems -MOS;Moses Corporation -MOT;Motorola UDS -MPC;M-Pact Inc -MPI;Mediatrix Peripherals Inc -MPJ;Microlab -MPL;Maple Research Inst. Company Ltd -MPN;Mainpine Limited -MPS;mps Software GmbH -MPX;Micropix Technologies, Ltd. -MQP;MultiQ Products AB -MRA;Miranda Technologies Inc -MRC;Marconi Simulation & Ty-Coch Way Training -MRD;MicroDisplay Corporation -MRK;Maruko & Company Ltd -MRL;Miratel -MRO;Medikro Oy -MRT;Merging Technologies -MSA;Micro Systemation AB -MSC;Mouse Systems Corporation -MSD;Datenerfassungs- und Informationssysteme -MSF;M-Systems Flash Disk Pioneers -MSG;MSI GmbH -MSH;Microsoft -MSI;Microstep -MSK;Megasoft Inc -MSL;MicroSlate Inc. -MSM;Advanced Digital Systems -MSP;Mistral Solutions [P] Ltd. -MST;MS Telematica -MSU;motorola -MSV;Mosgi Corporation -MSX;Micomsoft Co., Ltd. -MSY;MicroTouch Systems Inc -MTB;Media Technologies Ltd. -MTC;Mars-Tech Corporation -MTD;MindTech Display Co. Ltd -MTE;MediaTec GmbH -MTH;Micro-Tech Hearing Instruments -MTI;MaxCom Technical Inc -MTI;Motorola Inc. -MTK;Microtek International Inc. -MTL;Mitel Corporation -MTN;Mtron Storage Technology Co., Ltd. -MTR;Mitron computer Inc -MTS;Multi-Tech Systems -MTU;Mark of the Unicorn Inc -MTX;Matrox -MUD;Multi-Dimension Institute -MUK;mainpine limited -MVD;Microvitec PLC -MVI;Media Vision Inc -MVM;SOBO VISION -MVS;Microvision -MVX;COM 1 -MWI;Multiwave Innovation Pte Ltd -MWR;mware -MWY;Microway Inc -MXD;MaxData Computer GmbH & Co.KG -MXI;Macronix Inc -MXL;Hitachi Maxell, Ltd. -MXP;Maxpeed Corporation -MXT;Maxtech Corporation -MXV;MaxVision Corporation -MYA;Monydata -MYR;Myriad Solutions Ltd -MYX;Micronyx Inc -NAC;Ncast Corporation -NAD;NAD Electronics -NAK;Nakano Engineering Co.,Ltd. -NAL;Network Alchemy -NAT;NaturalPoint Inc. -NAV;Navigation Corporation -NAX;Naxos Tecnologia -NBL;N*Able Technologies Inc -NBS;National Key Lab. on ISN -NBT;NingBo Bestwinning Technology CO., Ltd -NCA;Nixdorf Company -NCC;NCR Corporation -NCE;Norcent Technology, Inc. -NCI;NewCom Inc -NCL;NetComm Ltd -NCR;NCR Electronics -NCS;Northgate Computer Systems -NCT;NEC CustomTechnica, Ltd. -NDC;National DataComm Corporaiton -NDI;National Display Systems -NDK;Naitoh Densei CO., LTD. -NDL;Network Designers -NDS;Nokia Data -NEC;NEC Corporation -NEO;NEO TELECOM CO.,LTD. -NET;Mettler Toledo -NEU;NEUROTEC - EMPRESA DE PESQUISA E DESENVOLVIMENTO EM BIOMEDICINA -NEX;Nexgen Mediatech Inc., -NFC;BTC Korea Co., Ltd -NFS;Number Five Software -NGC;Network General -NGS;A D S Exports -NHT;Vinci Labs -NIC;National Instruments Corporation -NIS;Nissei Electric Company -NIT;Network Info Technology -NIX;Seanix Technology Inc -NLC;Next Level Communications -NMP;Nokia Mobile Phones -NMS;Natural Micro System -NMV;NEC-Mitsubishi Electric Visual Systems Corporation -NMX;Neomagic -NNC;NNC -NOE;NordicEye AB -NOI;North Invent A/S -NOK;Nokia Display Products -NOR;Norand Corporation -NOT;Not Limited Inc -NPI;Network Peripherals Inc -NRL;U.S. Naval Research Lab -NRT;Beijing Northern Radiantelecom Co. -NRV;Taugagreining hf -NSC;National Semiconductor Corporation -NSI;NISSEI ELECTRIC CO.,LTD -NSP;Nspire System Inc. -NSS;Newport Systems Solutions -NST;Network Security Technology Co -NTC;NeoTech S.R.L -NTI;New Tech Int'l Company -NTL;National Transcomm. Ltd -NTN;Nuvoton Technology Corporation -NTR;N-trig Innovative Technologies, Inc. -NTS;Nits Technology Inc. -NTT;NTT Advanced Technology Corporation -NTW;Networth Inc -NTX;Netaccess Inc -NUG;NU Technology, Inc. -NUI;NU Inc. -NVC;NetVision Corporation -NVD;Nvidia -NVI;NuVision US, Inc. -NVL;Novell Inc -NVT;Navatek Engineering Corporation -NWC;NW Computer Engineering -NWP;NovaWeb Technologies Inc -NWS;Newisys, Inc. -NXC;NextCom K.K. -NXG;Nexgen -NXP;NXP Semiconductors bv. -NXQ;Nexiq Technologies, Inc. -NXS;Technology Nexus Secure Open Systems AB -NYC;nakayo telecommunications,inc. -OAK;Oak Tech Inc -OAS;Oasys Technology Company -OBS;Optibase Technologies -OCD;Macraigor Systems Inc -OCN;Olfan -OCS;Open Connect Solutions -ODM;ODME Inc. -ODR;Odrac -OEC;ORION ELECTRIC CO.,LTD -OEI;Optum Engineering Inc. -OIC;Option Industrial Computers -OIM;Option International -OIN;Option International -OKI;OKI Electric Industrial Company Ltd -OLC;Olicom A/S -OLD;Olidata S.p.A. -OLI;Olivetti -OLT;Olitec S.A. -OLV;Olitec S.A. -OLY;OLYMPUS CORPORATION -OMC;OBJIX Multimedia Corporation -OMN;Omnitel -OMR;Omron Corporation -ONE;Oneac Corporation -ONK;ONKYO Corporation -ONL;OnLive, Inc -ONS;On Systems Inc -ONW;OPEN Networks Ltd -ONX;SOMELEC Z.I. Du Vert Galanta -OOS;OSRAM -OPC;Opcode Inc -OPI;D.N.S. Corporation -OPT;OPTi Inc -OPV;Optivision Inc -OQI;Oksori Company Ltd -ORG;ORGA Kartensysteme GmbH -ORI;OSR Open Systems Resources, Inc. -ORN;ORION ELECTRIC CO., LTD. -OSA;OSAKA Micro Computer, Inc. -OSP;OPTI-UPS Corporation -OSR;Oksori Company Ltd -OTB;outsidetheboxstuff.com -OTI;Orchid Technology -OTM;Optoma Corporation           -OTT;OPTO22, Inc. -OUK;OUK Company Ltd -OWL;Mediacom Technologies Pte Ltd -OXU;Oxus Research S.A. -OYO;Shadow Systems -OZO;Tribe Computer Works Inc -PAC;Pacific Avionics Corporation -PAD;Promotion and Display Technology Ltd. -PAK;Many CNC System Co., Ltd. -PAM;Peter Antesberger Messtechnik -PAN;The Panda Project -PAR;Parallan Comp Inc -PBI;Pitney Bowes -PBL;Packard Bell Electronics -PBN;Packard Bell NEC -PBV;Pitney Bowes -PCA;Philips BU Add On Card -PCB;OCTAL S.A. -PCC;PowerCom Technology Company Ltd -PCG;First Industrial Computer Inc -PCI;Pioneer Computer Inc -PCK;PCBANK21 -PCL;pentel.co.,ltd -PCM;PCM Systems Corporation -PCO;Performance Concepts Inc., -PCP;Procomp USA Inc -PCS;TOSHIBA PERSONAL COMPUTER SYSTEM CORPRATION -PCT;PC-Tel Inc -PCW;Pacific CommWare Inc -PCX;PC Xperten -PDM;Psion Dacom Plc. -PDN;AT&T Paradyne -PDR;Pure Data Inc -PDS;PD Systems International Ltd -PDT;PDTS - Prozessdatentechnik und Systeme -PDV;Prodrive B.V. -PEC;POTRANS Electrical Corp. -PEI;PEI Electronics Inc -PEL;Primax Electric Ltd -PEN;Interactive Computer Products Inc -PEP;Peppercon AG -PER;Perceptive Signal Technologies -PET;Practical Electronic Tools -PFT;Telia ProSoft AB -PGM;Paradigm Advanced Research Centre -PGP;propagamma kommunikation -PGS;Princeton Graphic Systems -PHC;Pijnenburg Beheer N.V. -PHE;Philips Medical Systems Boeblingen GmbH -PHI;DO NOT USE - PHI -PHL;Philips Consumer Electronics Company -PHO;Photonics Systems Inc. -PHS;Philips Communication Systems -PHY;Phylon Communications -PIE;Pacific Image Electronics Company Ltd -PIM;Prism, LLC -PIO;Pioneer Electronic Corporation -PIX;Pixie Tech Inc -PJA;Projecta -PJD;Projectiondesign AS -PJT;Pan Jit International Inc. -PKA;Acco UK ltd. -PLC;Pro-Log Corporation -PLF;Panasonic Avionics Corporation -PLM;PROLINK Microsystems Corp. -PLT;PT Hartono Istana Teknologi -PLV;PLUS Vision Corp. -PLX;Parallax Graphics -PLY;Polycom Inc. -PMC;PMC Consumer Electronics Ltd -PMD;TDK USA Corporation -PMM;Point Multimedia System -PMT;Promate Electronic Co., Ltd. -PMX;Photomatrix -PNG;Microsoft -PNG;P.I. Engineering Inc -PNL;Panelview, Inc. -PNP;Microsoft -PNR;Planar Systems, Inc. -PNS;PanaScope -PNX;Phoenix Technologies, Ltd. -POL;PolyComp (PTY) Ltd. -PON;Perpetual Technologies, LLC -POR;Portalis LC -PPC;Phoenixtec Power Company Ltd -PPD;MEPhI -PPI;Practical Peripherals -PPM;Clinton Electronics Corp. -PPP;Purup Prepress AS -PPR;PicPro -PPX;Perceptive Pixel Inc. -PQI;Pixel Qi -PRA;PRO/AUTOMATION -PRC;PerComm -PRD;Praim S.R.L. -PRF;Digital Electronics Corporation -PRG;The Phoenix Research Group Inc -PRI;Priva Hortimation BV -PRM;Prometheus -PRO;Proteon -PRS;Leutron Vision -PRX;Proxima Corporation -PSA;Advanced Signal Processing Technologies -PSC;Philips Semiconductors -PSD;Peus-Systems GmbH -PSE;Practical Solutions Pte., Ltd. -PSI;PSI-Perceptive Solutions Inc -PSL;Perle Systems Limited -PSM;Prosum -PST;Global Data SA -PTC;PS Technology Corporation -PTG;Cipher Systems Inc -PTH;Pathlight Technology Inc -PTI;Promise Technology Inc -PTL;Pantel Inc -PTS;Plain Tree Systems Inc -PTW;DO NOT USE -PVC;DO NOT USE -PVG;Proview Global Co., Ltd -PVI;Prime view international Co., Ltd -PVM;Penta Studiotechnik GmbH -PVN;Pixel Vision -PVP;Klos Technologies, Inc. -PXC;Phoenix Contact -PXE;PIXELA CORPORATION -PXL;The Moving Pixel Company -PXM;Proxim Inc -QCC;QuakeCom Company Ltd -QCH;Metronics Inc -QCI;Quanta Computer Inc -QCK;Quick Corporation -QCL;Quadrant Components Inc -QCP;Qualcomm Inc -QDI;Quantum Data Incorporated -QDM;Quadram -QDS;Quanta Display Inc. -QFF;Padix Co., Inc. -QFI;Quickflex, Inc -QLC;Q-Logic -QQQ;Chuomusen Co., Ltd. -QSI;Quantum Solutions, Inc. -QTD;Quantum 3D Inc -QTH;Questech Ltd -QTI;Quicknet Technologies Inc -QTM;Quantum -QTR;Qtronix Corporation -QUA;Quatographic AG -QUE;Questra Consulting -QVU;Quartics -RAC;Racore Computer Products Inc -RAD;Radisys Corporation -RAI;Rockwell Automation/Intecolor -RAN;Rancho Tech Inc -RAR;Raritan, Inc. -RAS;RAScom Inc -RAT;Rent-A-Tech -RAY;Raylar Design, Inc. -RCE;Parc d'Activite des Bellevues -RCH;Reach Technology Inc -RCI;RC International -RCN;Radio Consult SRL -RCO;Rockwell Collins -RDI;Rainbow Displays, Inc. -RDM;Tremon Enterprises Company Ltd -RDS;Radius Inc -REA;Real D -REC;ReCom -RED;Research Electronics Development Inc -REF;Reflectivity, Inc. -REL;Reliance Electric Ind Corporation -REM;SCI Systems Inc. -REN;Renesas Technology Corp. -RES;ResMed Pty Ltd -RGL;Robertson Geologging Ltd -RHM;Rohm Company Ltd -RIC;RICOH COMPANY, LTD. -RII;Racal Interlan Inc -RIO;Rios Systems Company Ltd -RIT;Ritech Inc -RIV;Rivulet Communications -RJA;Roland Corporation -RJS;Advanced Engineering -RKC;Reakin Technolohy Corporation -RLD;MEPCO -RLN;RadioLAN Inc -RMC;Raritan Computer, Inc -RMP;Research Machines -RMT;Roper Mobile -RNB;Rainbow Technologies -ROB;Robust Electronics GmbH -ROH;Rohm Co., Ltd. -ROK;Rockwell International -ROP;Roper International Ltd -RPI;RoomPro Technologies -RPT;R.P.T.Intergroups -RRI;Radicom Research Inc -RSC;PhotoTelesis -RSH;ADC-Centre -RSI;Rampage Systems Inc -RSN;Radiospire Networks, Inc. -RSQ;R Squared -RSS;Rockwell Semiconductor Systems -RSX;Rapid Tech Corporation -RTC;Relia Technologies -RTI;Rancho Tech Inc -RTK;DO NOT USE -RTL;Realtek Semiconductor Company Ltd -RTS;Raintree Systems -RUN;RUNCO International -RUP;Ups Manufactoring s.r.l. -RVC;RSI Systems Inc -RVI;Realvision Inc -RVL;Reveal Computer Prod -RWC;Red Wing Corporation -RXT;Tectona SoftSolutions (P) Ltd., -SAA;Sanritz Automation Co.,Ltd. -SAE;Saab Aerotech -SAG;Sedlbauer -SAI;Sage Inc -SAK;Saitek Ltd -SAM;Samsung Electric Company -SAN;Sanyo Electric Co.,Ltd. -SAS;Stores Automated Systems Inc -SAT;Shuttle Tech -SBC;Shanghai Bell Telephone Equip Mfg Co -SBD;Softbed - Consulting & Development Ltd -SBI;SMART Technologies Inc. -SBS;SBS-or Industrial Computers GmbH -SBT;Senseboard Technologies AB -SCC;SORD Computer Corporation -SCD;Sanyo Electric Company Ltd -SCE;Sun Corporation -SCH;Schlumberger Cards -SCI;System Craft -SCL;Sigmacom Co., Ltd. -SCM;SCM Microsystems Inc -SCN;Scanport, Inc. -SCO;SORCUS Computer GmbH -SCP;Scriptel Corporation -SCR;Systran Corporation -SCS;Nanomach Anstalt -SCT;Smart Card Technology -SDA;SAT (Societe Anonyme) -SDD;Intrada-SDD Ltd -SDE;Sherwood Digital Electronics Corporation -SDF;SODIFF E&T CO., Ltd. -SDH;Communications Specialies, Inc. -SDI;Samtron Displays Inc -SDK;SAIT-Devlonics -SDR;SDR Systems -SDS;SunRiver Data System -SDT;Siemens AG -SDX;SDX Business Systems Ltd -SEA;Seanix Technology Inc. -SEB;system elektronik GmbH -SEC;Seiko Epson Corporation -SEE;SeeColor Corporation -SEG;DO NOT USE -SEI;Seitz & Associates Inc -SEL;Way2Call Communications -SEM;Samsung Electronics Company Ltd -SEN;Sencore -SEO;SEOS Ltd -SEP;SEP Eletronica Ltda. -SER;Sony Ericsson Mobile Communications Inc. -SES;Session Control LLC -SET;SendTek Corporation -SFM;TORNADO Company -SFT;Mikroforum Ring 3 -SGC;Spectragraphics Corporation -SGD;Sigma Designs, Inc. -SGE;Kansai Electric Company Ltd -SGI;Scan Group Ltd -SGL;Super Gate Technology Company Ltd -SGM;SAGEM -SGO;Logos Design A/S -SGT;Stargate Technology -SGX;Silicon Graphics Inc -SGZ;Systec Computer GmbH -SHC;ShibaSoku Co., Ltd. -SHG;Soft & Hardware development Goldammer GmbH -SHI;Jiangsu Shinco Electronic Group Co., Ltd -SHP;Sharp Corporation -SHR;Digital Discovery -SHT;Shin Ho Tech -SIA;SIEMENS AG -SIB;Sanyo Electric Company Ltd -SIC;Sysmate Corporation -SID;Seiko Instruments Information Devices Inc -SIE;Siemens -SIG;Sigma Designs Inc -SII;Silicon Image, Inc. -SIL;Silicon Laboratories, Inc -SIM;S3 Inc -SIN;Singular Technology Co., Ltd. -SIR;Sirius Technologies Pty Ltd -SIS;Silicon Integrated Systems Corporation -SIT;Sitintel -SIU;Seiko Instruments USA Inc -SIX;Zuniq Data Corporation -SJE;Sejin Electron Inc -SKD;Schneider & Koch -SKT;Samsung Electro-Mechanics Company Ltd -SKY;SKYDATA S.P.A. -SLA;Systeme Lauer GmbH&Co KG -SLB;Shlumberger Ltd -SLC;Syslogic Datentechnik AG -SLF;StarLeaf -SLH;Silicon Library Inc. -SLI;Symbios Logic Inc -SLK;Silitek Corporation -SLM;Solomon Technology Corporation -SLR;Schlumberger Technology Corporate -SLS;Schnick-Schnack-Systems GmbH -SLT;Salt Internatioinal Corp. -SLX;Specialix -SMA;SMART Modular Technologies -SMB;Schlumberger -SMC;Standard Microsystems Corporation -SME;Sysmate Company -SMI;SpaceLabs Medical Inc -SMK;SMK CORPORATION -SML;Sumitomo Metal Industries, Ltd. -SMM;Shark Multimedia Inc -SMO;STMicroelectronics -SMP;Simple Computing -SMR;B.& V. s.r.l. -SMS;Silicom Multimedia Systems Inc -SMT;Silcom Manufacturing Tech Inc -SNC;Sentronic International Corp. -SNI;Siemens Microdesign GmbH -SNK;S&K Electronics -SNO;SINOSUN TECHNOLOGY CO., LTD -SNP;Siemens Nixdorf Info Systems -SNS;Cirtech (UK) Ltd -SNT;SuperNet Inc -SNW;Snell & Wilcox -SNX;Sonix Comm. Ltd -SNY;Sony -SOI;Silicon Optix Corporation -SOL;Solitron Technologies Inc -SON;Sony -SOR;Sorcus Computer GmbH -SOT;Sotec Company Ltd -SOY;SOYO Group, Inc -SPC;SpinCore Technologies, Inc -SPE;SPEA Software AG -SPH;G&W Instruments GmbH -SPI;SPACE-I Co., Ltd. -SPK;SpeakerCraft -SPL;Smart Silicon Systems Pty Ltd -SPN;Sapience Corporation -SPR;pmns GmbH -SPS;Synopsys Inc -SPT;Sceptre Tech Inc -SPU;SIM2 Multimedia S.P.A. -SPX;Simplex Time Recorder Co. -SQT;Sequent Computer Systems Inc -SRC;Integrated Tech Express Inc -SRD;Setred -SRF;Surf Communication Solutions Ltd -SRG;Intuitive Surgical, Inc. -SRT;SeeReal Technologies GmbH -SSC;Sierra Semiconductor Inc -SSD;FlightSafety International -SSE;Samsung Electronic Co. -SSI;S-S Technology Inc -SSJ;Sankyo Seiki Mfg.co., Ltd -SSP;Spectrum Signal Proecessing Inc -SSS;S3 Inc -SST;SystemSoft Corporation -STA;ST Electronics Systems Assembly Pte Ltd -STB;STB Systems Inc -STC;STAC Electronics -STD;STD Computer Inc -STE;SII Ido-Tsushin Inc -STF;Starflight Electronics -STG;StereoGraphics Corp. -STH;Semtech Corporation -STI;Smart Tech Inc -STK;SANTAK CORP. -STL;SigmaTel Inc -STM;SGS Thomson Microelectronics -STN;Samsung Electronics America -STO;Stollmann E+V GmbH -STP;StreamPlay Ltd -STR;Starlight Networks Inc -STS;SITECSYSTEM CO., LTD. -STT;Star Paging Telecom Tech (Shenzhen) Co. Ltd. -STW;Starwin Inc. -STY;SDS Technologies -SUB;Subspace Comm. Inc -SUM;Summagraphics Corporation -SUN;Sun Electronics Corporation -SUP;Supra Corporation -SUR;Surenam Computer Corporation -SVA;SGEG -SVC;Intellix Corp. -SVD;SVD Computer -SVI;Sun Microsystems -SVS;SVSI -SVT;SEVIT Co., Ltd. -SWC;Software Café -SWI;Sierra Wireless Inc. -SWL;Sharedware Ltd -SWS;Static -SWT;Software Technologies Group,Inc. -SXB;Syntax-Brillian -SXD;Silex technology, Inc. -SXL;SolutionInside -SXT;SHARP TAKAYA ELECTRONIC INDUSTRY CO.,LTD. -SYC;Sysmic -SYE;SY Electronics Ltd -SYK;Stryker Communications -SYL;Sylvania Computer Products -SYM;Symicron Computer Communications Ltd. -SYN;Synaptics Inc -SYP;SYPRO Co Ltd -SYS;Sysgration Ltd -SYT;Seyeon Tech Company Ltd -SYV;SYVAX Inc -SYX;Prime Systems, Inc. -TAA;Tandberg -TAB;Todos Data System AB -TAG;Teles AG -TAI;Toshiba America Info Systems Inc -TAM;Tamura Seisakusyo Ltd -TAS;Taskit Rechnertechnik GmbH -TAT;Teleliaison Inc -TAX;Taxan (Europe) Ltd -TBB;Triple S Engineering Inc -TBC;Turbo Communication, Inc -TBS;Turtle Beach System -TCC;Tandon Corporation -TCD;Taicom Data Systems Co., Ltd. -TCE;Century Corporation -TCH;Interaction Systems, Inc -TCI;Tulip Computers Int'l B.V. -TCJ;TEAC America Inc -TCL;Technical Concepts Ltd -TCM;3Com Corporation -TCN;Tecnetics (PTY) Ltd -TCO;Thomas-Conrad Corporation -TCR;Thomson Consumer Electronics -TCS;Tatung Company of America Inc -TCT;Telecom Technology Centre Co. Ltd. -TCX;FREEMARS Heavy Industries -TDC;Teradici -TDD;Tandberg Data Display AS -TDK;TDK USA Corporation -TDM;Tandem Computer Europe Inc -TDP;3D Perception -TDS;Tri-Data Systems Inc -TDT;TDT -TDV;TDVision Systems, Inc. -TDY;Tandy Electronics -TEA;TEAC System Corporation -TEC;Tecmar Inc -TEK;Tektronix Inc -TEL;Promotion and Display Technology Ltd. -TER;TerraTec Electronic GmbH -TGI;TriGem Computer Inc -TGM;TriGem Computer,Inc. -TGS;Torus Systems Ltd -TGV;Grass Valley Germany GmbH -THN;Thundercom Holdings Sdn. Bhd. -TIC;Trigem KinfoComm -TIP;TIPTEL AG -TIV;OOO Technoinvest -TIX;Tixi.Com GmbH -TKC;Taiko Electric Works.LTD -TKN;Teknor Microsystem Inc -TKO;TouchKo, Inc. -TKS;TimeKeeping Systems, Inc. -TLA;Ferrari Electronic GmbH -TLD;Telindus -TLI;TOSHIBA TELI CORPORATION -TLK;Telelink AG -TLS;Teleste Educational OY -TLT;Dai Telecom S.p.A. -TLV;S3 Inc -TLX;Telxon Corporation -TMC;Techmedia Computer Systems Corporation -TME;AT&T Microelectronics -TMI;Texas Microsystem -TMM;Time Management, Inc. -TMR;Taicom International Inc -TMS;Trident Microsystems Ltd -TMT;T-Metrics Inc. -TMX;Thermotrex Corporation -TNC;TNC Industrial Company Ltd -TNJ;DO NOT USE -TNM;TECNIMAGEN SA -TNY;Tennyson Tech Pty Ltd -TOE;TOEI Electronics Co., Ltd. -TOG;The OPEN Group -TOP;Orion Communications Co., Ltd. -TOS;Toshiba Corporation -TOU;Touchstone Technology -TPC;Touch Panel Systems Corporation -TPE;Technology Power Enterprises Inc -TPJ;(none) -TPK;TOPRE CORPORATION -TPR;Topro Technology Inc -TPS;Teleprocessing Systeme GmbH -TPT;Thruput Ltd -TPV;Top Victory Electronics ( Fujian ) Company Ltd -TPZ;Ypoaz Systems Inc -TRA;TriTech Microelectronics International -TRC;Trioc AB -TRD;Trident Microsystem Inc -TRE;Tremetrics -TRI;Tricord Systems -TRL;Royal Information -TRM;Tekram Technology Company Ltd -TRN;Datacommunicatie Tron B.V. -TRS;Torus Systems Ltd -TRU;Aashima Technology B.V. -TRX;Trex Enterprises -TSB;Toshiba America Info Systems Inc -TSC;Sanyo Electric Company Ltd -TSD;TechniSat Digital GmbH -TSE;Tottori Sanyo Electric -TSF;Racal-Airtech Software Forge Ltd -TSG;The Software Group Ltd -TSI;TeleVideo Systems -TSL;Tottori SANYO Electric Co., Ltd. -TSP;U.S. Navy -TST;Transtream Inc -TSV;TRANSVIDEO -TSY;TouchSystems -TTA;Topson Technology Co., Ltd. -TTB;National Semiconductor Japan Ltd -TTC;Telecommunications Techniques Corporation -TTE;TTE, Inc. -TTI;Trenton Terminals Inc -TTK;Totoku Electric Company Ltd -TTL;2-Tel B.V. -TTS;TechnoTrend Systemtechnik GmbH -TTY;TRIDELITY Display Solutions GmbH -TUT;Tut Systems -TVD;Tecnovision -TVI;Truevision -TVM;Taiwan Video & Monitor Corporation -TVO;TV One Ltd -TVR;TV Interactive Corporation -TVS;TVS Electronics Limited -TWA;Tidewater Association -TWE;Kontron Electronik -TWH;Twinhead International Corporation -TWI;Easytel oy -TWK;TOWITOKO electronics GmbH -TWX;TEKWorx Limited -TXL;Trixel Ltd -TXN;Texas Insturments -TXT;Textron Defense System -TYN;Tyan Computer Corporation -UAS;Ultima Associates Pte Ltd -UBI;Ungermann-Bass Inc -UBL;Ubinetics Ltd. -UDN;Uniden Corporation -UEC;Ultima Electronics Corporation -UEG;Elitegroup Computer Systems Company Ltd -UEI;Universal Electronics Inc -UET;Universal Empowering Technologies -UFG;UNIGRAF-USA -UFO;UFO Systems Inc -UHB;XOCECO -UIC;Uniform Industrial Corporation -UJR;Ueda Japan Radio Co., Ltd. -ULT;Ultra Network Tech -UMC;United Microelectr Corporation -UMG;Umezawa Giken Co.,Ltd -UMM;Universal Multimedia -UNA;Unisys DSD -UNB;Unisys Corporation -UNC;Unisys Corporation -UND;DO NOT USE - UND -UNE;DO NOT USE - UNE -UNF;DO NOT USE - UNF -UNI;Unisys Corporation -UNI;Uniform Industry Corp. -UNM;Unisys Corporation -UNO;Unisys Corporation -UNP;Unitop -UNS;Unisys Corporation -UNT;Unisys Corporation -UNY;Unicate -UPP;UPPI -UPS;Systems Enhancement -URD;Video Computer S.p.A. -USA;Utimaco Safeware AG -USD;U.S. Digital Corporation -USI;Universal Scientific Industrial Co., Ltd. -USR;U.S. Robotics Inc -UTD;Up to Date Tech -UWC;Uniwill Computer Corp. -VAL;Valence Computing Corporation -VAR;Varian Australia Pty Ltd -VBT;Valley Board Ltda -VCC;Virtual Computer Corporation -VCI;VistaCom Inc -VCJ;Victor Company of Japan, Limited -VCM;Vector Magnetics, LLC -VCX;VCONEX -VDA;Victor Data Systems -VDC;VDC Display Systems -VDM;Vadem -VDO;Video & Display Oriented Corporation -VDS;Vidisys GmbH & Company -VDT;Viditec, Inc. -VEC;Vector Informatik GmbH -VEK;Vektrex -VES;Vestel Elektronik Sanayi ve Ticaret A. S. -VFI;VeriFone Inc -VHI;Macrocad Development Inc. -VIA;VIA Tech Inc -VIB;Tatung UK Ltd -VIC;Victron B.V. -VID;Ingram Macrotron Germany -VIK;Viking Connectors -VIN;Vine Micros Ltd -VIR;Visual Interface, Inc -VIS;Visioneer -VIT;Visitech AS -VLB;ValleyBoard Ltda. -VLT;VideoLan Technologies -VMI;Vermont Microsystems -VML;Vine Micros Limited -VNC;Vinca Corporation -VOB;MaxData Computer AG -VPI;Video Products Inc -VPR;Best Buy -VQ@;Vision Quest -VRC;Virtual Resources Corporation -VSC;ViewSonic Corporation -VSD;3M -VSI;VideoServer -VSN;Ingram Macrotron -VSP;Vision Systems GmbH -VSR;V-Star Electronics Inc. -VTC;VTel Corporation -VTG;Voice Technologies Group Inc -VTI;VLSI Tech Inc -VTK;Viewteck Co., Ltd. -VTL;Vivid Technology Pte Ltd -VTM;Miltope Corporation -VTN;VIDEOTRON CORP. -VTS;VTech Computers Ltd -VTV;VATIV Technologies -VUT;Vutrix (UK) Ltd -VWB;Vweb Corp. -WAC;Wacom Tech -WAL;Wave Access -WAN;DO NOT USE -WAV;Wavephore -WBN;MicroSoftWare -WBS;WB Systemtechnik GmbH -WCI;Wisecom Inc -WCS;Woodwind Communications Systems Inc -WDC;Western Digital -WDE;Westinghouse Digital Electronics -WEB;WebGear Inc -WEC;Winbond Electronics Corporation -WEL ; W-DEV -WEY;WEY Design AG -WHI;Whistle Communications -WII;Innoware Inc -WIL;WIPRO Information Technology Ltd -WIN;Wintop Technology Inc -WIP;Wipro Infotech -WKH;Uni-Take Int'l Inc. -WLD;Wildfire Communications Inc -WML;Wolfson Microelectronics Ltd -WMO;Westermo Teleindustri AB -WMT;Winmate Communication Inc -WNI;WillNet Inc. -WNV;Winnov L.P. -WNX;Wincor Nixdorf International GmbH -WPA;Matsushita Communication Industrial Co., Ltd. -WPI;Wearnes Peripherals International (Pte) Ltd -WRC;WiNRADiO Communications -WSC;CIS Technology Inc -WSP;Wireless And Smart Products Inc. -WST;Wistron Corporation -WTC;ACC Microelectronics -WTI;WorkStation Tech -WTK;Wearnes Thakral Pte -WTS;Restek Electric Company Ltd -WVM;Wave Systems Corporation -WWV;World Wide Video, Inc. -WXT;Woxter Technology Co. Ltd -WYS;Myse Technology -WYT;Wooyoung Image & Information Co.,Ltd. -XAC;XAC Automation Corp -XAD;Alpha Data -XDM;XDM Ltd. -XER;DO NOT USE -XFG;Jan Strapko - FOTO -XFO;EXFO Electro Optical Engineering -XIN;Xinex Networks Inc -XIO;Xiotech Corporation -XIR;Xirocm Inc -XIT;Xitel Pty ltd -XLX;Xilinx, Inc. -XMM;C3PO S.L. -XNT;XN Technologies, Inc. -XOC;DO NOT USE -XQU;SHANGHAI SVA-DAV ELECTRONICS CO., LTD -XRC;Xircom Inc -XRO;XORO ELECTRONICS (CHENGDU) LIMITED -XSN;Xscreen AS -XST;XS Technologies Inc -XSY;XSYS -XTD;Icuiti Corporation -XTE;X2E GmbH -XTL;Crystal Computer -XTN;X-10 (USA) Inc -XYC;Xycotec Computer GmbH -YED;Y-E Data Inc -YHQ;Yokogawa Electric Corporation -YHW;Exacom SA -YMH;Yamaha Corporation -YOW;American Biometric Company -ZAN;Zandar Technologies plc -ZAX;Zefiro Acoustics -ZAZ;Zazzle Technologies -ZBR;Zebra Technologies International, LLC -ZCT;ZeitControl cardsystems GmbH -ZDS;Zenith Data Systems -ZGT;Zenith Data Systems -ZIC;ZTEIC DESIGN CO., LTD. -ZMT;Zalman Tech Co., Ltd. -ZMZ;Z Microsystems -ZNI;Zetinet Inc -ZNX;Znyx Adv. Systems -ZOW;Zowie Intertainment, Inc -ZRN;Zoran Corporation -ZSE;Zenith Data Systems -ZTC;ZyDAS Technology Corporation -ZTE;ZTE Corporation -ZTI;Zoom Telephonics Inc -ZTM;ZT Group Int'l Inc. -ZYD;Zydacron Inc -ZYP;Zypcom Inc -ZYT;Zytex Computers -ZYX;Zyxel -ZZZ;Boca Research Inc diff --git a/decoders/eeprom24xx/__init__.py b/decoders/eeprom24xx/__init__.py deleted file mode 100755 index 7d496fce..00000000 --- a/decoders/eeprom24xx/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Uwe Hermann -## -## 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, see . -## - -''' -This decoder stacks on top of the 'i2c' PD and decodes the -industry standard 24xx series serial EEPROM protocol. -''' - -from .pd import Decoder diff --git a/decoders/eeprom24xx/lists.py b/decoders/eeprom24xx/lists.py deleted file mode 100755 index c6ee63d5..00000000 --- a/decoders/eeprom24xx/lists.py +++ /dev/null @@ -1,204 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Uwe Hermann -## -## 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, see . -## - -# -# Chip specific properties: -# -# - vendor: chip manufacturer -# - model: chip model -# - size: total EEPROM size (in number of bytes) -# - page_size: page size (in number of bytes) -# - page_wraparound: Whether writes wrap-around at page boundaries -# - addr_bytes: number of EEPROM address bytes used -# - addr_pins: number of address pins (A0/A1/A2) on this chip -# - max_speed: max. supported I²C speed (in kHz) -# -chips = { - # Generic chip (128 bytes, 8 bytes page size) - 'generic': { - 'vendor': '', - 'model': 'Generic', - 'size': 128, - 'page_size': 8, - 'page_wraparound': True, - 'addr_bytes': 1, - 'addr_pins': 3, - 'max_speed': 400, - }, - - # Microchip - 'microchip_24aa65': { - 'vendor': 'Microchip', - 'model': '24AA65', - 'size': 8 * 1024, - 'page_size': 64, # Actually 8, but there are 8 pages of "input cache" - 'page_wraparound': True, - 'addr_bytes': 2, - 'addr_pins': 3, - 'max_speed': 400, - }, - 'microchip_24lc65': { - 'vendor': 'Microchip', - 'model': '24LC65', - 'size': 8 * 1024, - 'page_size': 64, # Actually 8, but there are 8 pages of "input cache" - 'page_wraparound': True, - 'addr_bytes': 2, - 'addr_pins': 3, - 'max_speed': 400, - }, - 'microchip_24c65': { - 'vendor': 'Microchip', - 'model': '24C65', - 'size': 8 * 1024, - 'page_size': 64, # Actually 8, but there are 8 pages of "input cache" - 'page_wraparound': True, - 'addr_bytes': 2, - 'addr_pins': 3, - 'max_speed': 400, - }, - 'microchip_24aa64': { - 'vendor': 'Microchip', - 'model': '24AA64', - 'size': 8 * 1024, - 'page_size': 32, - 'page_wraparound': True, - 'addr_bytes': 2, - 'addr_pins': 3, - 'max_speed': 400, # 100 for VCC < 2.5V - }, - 'microchip_24lc64': { - 'vendor': 'Microchip', - 'model': '24LC64', - 'size': 8 * 1024, - 'page_size': 32, - 'page_wraparound': True, - 'addr_bytes': 2, - 'addr_pins': 3, - 'max_speed': 400, - }, - 'microchip_24aa02uid': { - 'vendor': 'Microchip', - 'model': '24AA02UID', - 'size': 256, - 'page_size': 8, - 'page_wraparound': True, - 'addr_bytes': 1, - 'addr_pins': 0, # Pins A0, A1, A2 not used - 'max_speed': 400, - }, - 'microchip_24aa025uid': { - 'vendor': 'Microchip', - 'model': '24AA025UID', - 'size': 256, - 'page_size': 16, - 'page_wraparound': True, - 'addr_bytes': 1, - 'addr_pins': 3, - 'max_speed': 400, - }, - 'microchip_24aa025uid_sot23': { - 'vendor': 'Microchip', - 'model': '24AA025UID (SOT-23)', - 'size': 256, - 'page_size': 16, - 'page_wraparound': True, - 'addr_bytes': 1, - 'addr_pins': 2, # SOT-23 package: A2 not available - 'max_speed': 400, - }, - - # ON Semiconductor - 'onsemi_cat24c256': { - 'vendor': 'ON Semiconductor', - 'model': 'CAT24C256', - 'size': 32 * 1024, - 'page_size': 64, - 'page_wraparound': True, - 'addr_bytes': 2, - 'addr_pins': 3, - 'max_speed': 1000, - }, - 'onsemi_cat24m01': { - 'vendor': 'ON Semiconductor', - 'model': 'CAT24M01', - 'size': 128 * 1024, - 'page_size': 256, - 'page_wraparound': True, - 'addr_bytes': 2, - 'addr_pins': 2, # Pin A0 not connected - 'max_speed': 1000, - }, - - # Siemens - 'siemens_slx_24c01': { - 'vendor': 'Siemens', - 'model': 'SLx 24C01', - 'size': 128, - 'page_size': 8, - 'page_wraparound': True, - 'addr_bytes': 1, - 'addr_pins': 0, # Pins A0, A1, A2 are not connected (NC) - 'max_speed': 400, - }, - 'siemens_slx_24c02': { - 'vendor': 'Siemens', - 'model': 'SLx 24C02', - 'size': 256, - 'page_size': 8, - 'page_wraparound': True, - 'addr_bytes': 1, - 'addr_pins': 0, # Pins A0, A1, A2 are not connected (NC) - 'max_speed': 400, - }, - - # ST - 'st_m24c01': { - 'vendor': 'ST', - 'model': 'M24C01', - 'size': 128, - 'page_size': 16, - 'page_wraparound': True, - 'addr_bytes': 1, - 'addr_pins': 3, # Called E0, E1, E2 on this chip. - 'max_speed': 400, - }, - 'st_m24c02': { - 'vendor': 'ST', - 'model': 'M24C02', - 'size': 256, - 'page_size': 16, - 'page_wraparound': True, - 'addr_bytes': 1, - 'addr_pins': 3, # Called E0, E1, E2 on this chip. - 'max_speed': 400, - }, - - # Xicor - 'xicor_x24c02': { - 'vendor': 'Xicor', - 'model': 'X24C02', - 'size': 256, - 'page_size': 4, - 'page_wraparound': True, - 'addr_bytes': 1, - 'addr_pins': 3, - 'max_speed': 100, - }, -} diff --git a/decoders/eeprom24xx/pd.py b/decoders/eeprom24xx/pd.py deleted file mode 100755 index 033a44b2..00000000 --- a/decoders/eeprom24xx/pd.py +++ /dev/null @@ -1,433 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Uwe Hermann -## -## 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, see . -## - -import sigrokdecode as srd -from .lists import * - -class Decoder(srd.Decoder): - api_version = 3 - id = 'eeprom24xx' - name = '24xx EEPROM' - longname = '24xx I²C EEPROM' - desc = '24xx series I²C EEPROM protocol.' - license = 'gplv2+' - inputs = ['i2c'] - outputs = [] - tags = ['IC', 'Memory'] - options = ( - {'id': 'chip', 'desc': 'Chip', 'default': 'generic', - 'values': tuple(chips.keys())}, - {'id': 'addr_counter', 'desc': 'Initial address counter value', - 'default': 0}, - ) - annotations = ( - # Warnings - ('warnings', 'Warnings'), - # Bits/bytes - ('control-code', 'Control code'), - ('address-pin', 'Address pin (A0/A1/A2)'), - ('rw-bit', 'Read/write bit'), - ('word-addr-byte', 'Word address byte'), - ('data-byte', 'Data byte'), - # Fields - ('control-word', 'Control word'), - ('word-addr', 'Word address'), - ('data', 'Data'), - # Operations - ('byte-write', 'Byte write'), - ('page-write', 'Page write'), - ('cur-addr-read', 'Current address read'), - ('random-read', 'Random read'), - ('seq-random-read', 'Sequential random read'), - ('seq-cur-addr-read', 'Sequential current address read'), - ('ack-polling', 'Acknowledge polling'), - ('set-bank-addr', 'Set bank address'), # SBA. Only 34AA04. - ('read-bank-addr', 'Read bank address'), # RBA. Only 34AA04. - ('set-wp', 'Set write protection'), # SWP - ('clear-all-wp', 'Clear all write protection'), # CWP - ('read-wp', 'Read write protection status'), # RPS - ) - annotation_rows = ( - ('bits-bytes', 'Bits/bytes', (1, 2, 3, 4, 5)), - ('fields', 'Fields', (6, 7, 8)), - ('ops', 'Operations', tuple(range(9, 21))), - ('warnings', 'Warnings', (0,)), - ) - binary = ( - ('binary', 'Binary'), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.reset_variables() - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.out_binary = self.register(srd.OUTPUT_BINARY) - self.chip = chips[self.options['chip']] - self.addr_counter = self.options['addr_counter'] - - def putb(self, data): - self.put(self.ss_block, self.es_block, self.out_ann, data) - - def putbin(self, data): - self.put(self.ss_block, self.es_block, self.out_binary, data) - - def putbits(self, bit1, bit2, bits, data): - self.put(bits[bit1][1], bits[bit2][2], self.out_ann, data) - - def reset_variables(self): - self.state = 'WAIT FOR START' - self.packets = [] - self.bytebuf = [] - self.is_cur_addr_read = False - self.is_random_access_read = False - self.is_seq_random_read = False - self.is_byte_write = False - self.is_page_write = False - - def packet_append(self): - self.packets.append([self.ss, self.es, self.cmd, self.databyte, self.bits]) - if self.cmd in ('DATA READ', 'DATA WRITE'): - self.bytebuf.append(self.databyte) - - def hexbytes(self, idx): - return ' '.join(['%02X' % b for b in self.bytebuf[idx:]]) - - def put_control_word(self, bits): - s = ''.join(['%d' % b[0] for b in reversed(bits[4:])]) - self.putbits(7, 4, bits, [1, ['Control code bits: ' + s, - 'Control code: ' + s, 'Ctrl code: ' + s, 'Ctrl code', 'Ctrl', 'C']]) - for i in reversed(range(self.chip['addr_pins'])): - self.putbits(i + 1, i + 1, bits, - [2, ['Address bit %d: %d' % (i, bits[i + 1][0]), - 'Addr bit %d' % i, 'A%d' % i, 'A']]) - s1 = 'read' if bits[0][0] == 1 else 'write' - s2 = 'R' if bits[0][0] == 1 else 'W' - self.putbits(0, 0, bits, [3, ['R/W bit: ' + s1, 'R/W', 'RW', s2]]) - self.putbits(7, 0, bits, [6, ['Control word', 'Control', 'CW', 'C']]) - - def put_word_addr(self, p): - if self.chip['addr_bytes'] == 1: - a = p[1][3] - self.put(p[1][0], p[1][1], self.out_ann, - [4, ['Word address byte: %02X' % a, 'Word addr byte: %02X' % a, - 'Addr: %02X' % a, 'A: %02X' % a, '%02X' % a]]) - self.put(p[1][0], p[1][1], self.out_ann, [7, ['Word address', - 'Word addr', 'Addr', 'A']]) - self.addr_counter = a - else: - a = p[1][3] - self.put(p[1][0], p[1][1], self.out_ann, - [4, ['Word address high byte: %02X' % a, - 'Word addr high byte: %02X' % a, - 'Addr high: %02X' % a, 'AH: %02X' % a, '%02X' % a]]) - a = p[2][3] - self.put(p[2][0], p[2][1], self.out_ann, - [4, ['Word address low byte: %02X' % a, - 'Word addr low byte: %02X' % a, - 'Addr low: %02X' % a, 'AL: %02X' % a, '%02X' % a]]) - self.put(p[1][0], p[2][1], self.out_ann, [7, ['Word address', - 'Word addr', 'Addr', 'A']]) - self.addr_counter = (p[1][3] << 8) | p[2][3] - - def put_data_byte(self, p): - if self.chip['addr_bytes'] == 1: - s = '%02X' % self.addr_counter - else: - s = '%04X' % self.addr_counter - self.put(p[0], p[1], self.out_ann, [5, ['Data byte %s: %02X' % \ - (s, p[3]), 'Data byte: %02X' % p[3], \ - 'Byte: %02X' % p[3], 'DB: %02X' % p[3], '%02X' % p[3]]]) - - def put_data_bytes(self, idx, cls, s): - for p in self.packets[idx:]: - self.put_data_byte(p) - self.addr_counter += 1 - self.put(self.packets[idx][0], self.packets[-1][1], self.out_ann, - [8, ['Data', 'D']]) - a = ''.join(['%s' % c[0] for c in s.split()]).upper() - self.putb([cls, ['%s (%s): %s' % (s, self.addr_and_len(), \ - self.hexbytes(self.chip['addr_bytes'])), - '%s (%s)' % (s, self.addr_and_len()), s, a, s[0]]]) - self.putbin([0, bytes(self.bytebuf[self.chip['addr_bytes']:])]) - - def addr_and_len(self): - if self.chip['addr_bytes'] == 1: - a = '%02X' % self.bytebuf[0] - else: - a = '%02X%02X' % tuple(self.bytebuf[:2]) - num_data_bytes = len(self.bytebuf) - self.chip['addr_bytes'] - d = '%d bytes' % num_data_bytes - if num_data_bytes <= 1: - d = d[:-1] - return 'addr=%s, %s' % (a, d) - - def decide_on_seq_or_rnd_read(self): - if len(self.bytebuf) < 2: - self.reset_variables() - return - if len(self.bytebuf) == 2: - self.is_random_access_read = True - else: - self.is_seq_random_read = True - - def put_operation(self): - idx = 1 + self.chip['addr_bytes'] - if self.is_byte_write: - # Byte write: word address, one data byte. - self.put_word_addr(self.packets) - self.put_data_bytes(idx, 9, 'Byte write') - elif self.is_page_write: - # Page write: word address, two or more data bytes. - self.put_word_addr(self.packets) - intitial_addr = self.addr_counter - self.put_data_bytes(idx, 10, 'Page write') - num_bytes_to_write = len(self.packets[idx:]) - if num_bytes_to_write > self.chip['page_size']: - self.putb([0, ['Warning: Wrote %d bytes but page size is ' - 'only %d bytes!' % (num_bytes_to_write, - self.chip['page_size'])]]) - page1 = int(intitial_addr / self.chip['page_size']) - page2 = int((self.addr_counter - 1) / self.chip['page_size']) - if page1 != page2: - self.putb([0, ['Warning: Page write crossed page boundary ' - 'from page %d to %d!' % (page1, page2)]]) - elif self.is_cur_addr_read: - # Current address read: no word address, one data byte. - self.put_data_byte(self.packets[1]) - self.put(self.packets[1][0], self.packets[-1][1], self.out_ann, - [8, ['Data', 'D']]) - self.putb([11, ['Current address read: %02X' % self.bytebuf[0], - 'Current address read', 'Cur addr read', 'CAR', 'C']]) - self.putbin([0, bytes([self.bytebuf[0]])]) - self.addr_counter += 1 - elif self.is_random_access_read: - # Random access read: word address, one data byte. - self.put_control_word(self.packets[idx][4]) - self.put_word_addr(self.packets) - self.put_data_bytes(idx + 1, 12, 'Random access read') - elif self.is_seq_random_read: - # Sequential random read: word address, two or more data bytes. - self.put_control_word(self.packets[idx][4]) - self.put_word_addr(self.packets) - self.put_data_bytes(idx + 1, 13, 'Sequential random read') - - def handle_wait_for_start(self): - # Wait for an I²C START condition. - if self.cmd not in ('START', 'START REPEAT'): - return - self.ss_block = self.ss - self.state = 'GET CONTROL WORD' - - def handle_get_control_word(self): - # The packet after START must be an ADDRESS READ or ADDRESS WRITE. - if self.cmd not in ('ADDRESS READ', 'ADDRESS WRITE'): - self.reset_variables() - return - self.packet_append() - self.put_control_word(self.bits) - self.state = '%s GET ACK NACK AFTER CONTROL WORD' % self.cmd[8] - - def handle_r_get_ack_nack_after_control_word(self): - if self.cmd == 'ACK': - self.state = 'R GET WORD ADDR OR BYTE' - elif self.cmd == 'NACK': - self.es_block = self.es - self.putb([0, ['Warning: No reply from slave!']]) - self.reset_variables() - else: - self.reset_variables() - - def handle_r_get_word_addr_or_byte(self): - if self.cmd == 'STOP': - self.es_block = self.es - self.putb([0, ['Warning: Slave replied, but master aborted!']]) - self.reset_variables() - return - elif self.cmd != 'DATA READ': - self.reset_variables() - return - self.packet_append() - self.state = 'R GET ACK NACK AFTER WORD ADDR OR BYTE' - - def handle_r_get_ack_nack_after_word_addr_or_byte(self): - if self.cmd == 'ACK': - self.state = 'R GET RESTART' - elif self.cmd == 'NACK': - self.is_cur_addr_read = True - self.state = 'GET STOP AFTER LAST BYTE' - else: - self.reset_variables() - - def handle_r_get_restart(self): - if self.cmd == 'RESTART': - self.state = 'R READ BYTE' - else: - self.reset_variables() - - def handle_r_read_byte(self): - if self.cmd == 'DATA READ': - self.packet_append() - self.state = 'R GET ACK NACK AFTER BYTE WAS READ' - else: - self.reset_variables() - - def handle_r_get_ack_nack_after_byte_was_read(self): - if self.cmd == 'ACK': - self.state = 'R READ BYTE' - elif self.cmd == 'NACK': - # It's either a RANDOM READ or a SEQUENTIAL READ. - self.state = 'GET STOP AFTER LAST BYTE' - else: - self.reset_variables() - - def handle_w_get_ack_nack_after_control_word(self): - if self.cmd == 'ACK': - self.state = 'W GET WORD ADDR' - elif self.cmd == 'NACK': - self.es_block = self.es - self.putb([0, ['Warning: No reply from slave!']]) - self.reset_variables() - else: - self.reset_variables() - - def handle_w_get_word_addr(self): - if self.cmd == 'STOP': - self.es_block = self.es - self.putb([0, ['Warning: Slave replied, but master aborted!']]) - self.reset_variables() - return - elif self.cmd != 'DATA WRITE': - self.reset_variables() - return - self.packet_append() - self.state = 'W GET ACK AFTER WORD ADDR' - - def handle_w_get_ack_after_word_addr(self): - if self.cmd == 'ACK': - self.state = 'W DETERMINE EEPROM READ OR WRITE' - else: - self.reset_variables() - - def handle_w_determine_eeprom_read_or_write(self): - if self.cmd == 'START REPEAT': - # It's either a RANDOM ACCESS READ or SEQUENTIAL RANDOM READ. - self.state = 'R2 GET CONTROL WORD' - elif self.cmd == 'DATA WRITE': - self.packet_append() - self.state = 'W GET ACK NACK AFTER BYTE WAS WRITTEN' - else: - self.reset_variables() - - def handle_w_write_byte(self): - if self.cmd == 'DATA WRITE': - self.packet_append() - self.state = 'W GET ACK NACK AFTER BYTE WAS WRITTEN' - elif self.cmd == 'STOP': - if len(self.bytebuf) < 2: - self.reset_variables() - return - self.es_block = self.es - if len(self.bytebuf) == 2: - self.is_byte_write = True - else: - self.is_page_write = True - self.put_operation() - self.reset_variables() - elif self.cmd == 'START REPEAT': - # It's either a RANDOM ACCESS READ or SEQUENTIAL RANDOM READ. - self.state = 'R2 GET CONTROL WORD' - else: - self.reset_variables() - - def handle_w_get_ack_nack_after_byte_was_written(self): - if self.cmd == 'ACK': - self.state = 'W WRITE BYTE' - else: - self.reset_variables() - - def handle_r2_get_control_word(self): - if self.cmd == 'ADDRESS READ': - self.packet_append() - self.state = 'R2 GET ACK AFTER ADDR READ' - else: - self.reset_variables() - - def handle_r2_get_ack_after_addr_read(self): - if self.cmd == 'ACK': - self.state = 'R2 READ BYTE' - else: - self.reset_variables() - - def handle_r2_read_byte(self): - if self.cmd == 'DATA READ': - self.packet_append() - self.state = 'R2 GET ACK NACK AFTER BYTE WAS READ' - elif self.cmd == 'STOP': - self.decide_on_seq_or_rnd_read() - self.es_block = self.es - self.putb([0, ['Warning: STOP expected after a NACK (not ACK)']]) - self.put_operation() - self.reset_variables() - else: - self.reset_variables() - - def handle_r2_get_ack_nack_after_byte_was_read(self): - if self.cmd == 'ACK': - self.state = 'R2 READ BYTE' - elif self.cmd == 'NACK': - self.decide_on_seq_or_rnd_read() - self.state = 'GET STOP AFTER LAST BYTE' - else: - self.reset_variables() - - def handle_get_stop_after_last_byte(self): - if self.cmd == 'STOP': - self.es_block = self.es - self.put_operation() - self.reset_variables() - elif self.cmd == 'START REPEAT': - self.es_block = self.es - self.putb([0, ['Warning: STOP expected (not RESTART)']]) - self.put_operation() - self.reset_variables() - self.ss_block = self.ss - self.state = 'GET CONTROL WORD' - else: - self.reset_variables() - - def decode(self, ss, es, data): - self.cmd, self.databyte = data - - # Collect the 'BITS' packet, then return. The next packet is - # guaranteed to belong to these bits we just stored. - if self.cmd == 'BITS': - self.bits = self.databyte - return - - # Store the start/end samples of this I²C packet. - self.ss, self.es = ss, es - - # State machine. - s = 'handle_%s' % self.state.lower().replace(' ', '_') - handle_state = getattr(self, s) - handle_state() diff --git a/decoders/eeprom93xx/__init__.py b/decoders/eeprom93xx/__init__.py deleted file mode 100755 index c8eaf7a0..00000000 --- a/decoders/eeprom93xx/__init__.py +++ /dev/null @@ -1,32 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2017 Kevin Redon -## -## 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, see . -## - -''' -This decoder stacks on top of the 'microwire' PD and decodes the 93xx EEPROM -specific instructions. - -The implemented instructions come from the STMicroelectronics M93Cx6 EEPROM -datasheet. They are compatible with the Atmel AT93Cxx EEPROM with slightly -different names. - -Warning: Other EEPROMs using Microwire might have different operation codes -and instructions. -''' - -from .pd import Decoder diff --git a/decoders/eeprom93xx/pd.py b/decoders/eeprom93xx/pd.py deleted file mode 100755 index 7b64e59a..00000000 --- a/decoders/eeprom93xx/pd.py +++ /dev/null @@ -1,141 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2017 Kevin Redon -## -## 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, see . -## - -import sigrokdecode as srd - -class Decoder(srd.Decoder): - api_version = 3 - id = 'eeprom93xx' - name = '93xx EEPROM' - longname = '93xx Microwire EEPROM' - desc = '93xx series Microwire EEPROM protocol.' - license = 'gplv2+' - inputs = ['microwire'] - outputs = [] - tags = ['IC', 'Memory'] - options = ( - {'id': 'addresssize', 'desc': 'Address size', 'default': 8}, - {'id': 'wordsize', 'desc': 'Word size', 'default': 16}, - ) - annotations = ( - ('si-data', 'SI data'), - ('so-data', 'SO data'), - ('warning', 'Warning'), - ) - annotation_rows = ( - ('data', 'Data', (0, 1)), - ('warnings', 'Warnings', (2,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.frame = [] - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.addresssize = self.options['addresssize'] - self.wordsize = self.options['wordsize'] - - def put_address(self, data): - # Get address (MSb first). - a = 0 - for b in range(len(data)): - a += (data[b].si << (len(data) - b - 1)) - self.put(data[0].ss, data[-1].es, self.out_ann, - [0, ['Address: 0x%x' % a, 'Addr: 0x%x' % a, '0x%x' % a]]) - - def put_word(self, si, data): - # Decode word (MSb first). - word = 0 - for b in range(len(data)): - d = data[b].si if si else data[b].so - word += (d << (len(data) - b - 1)) - idx = 0 if si else 1 - self.put(data[0].ss, data[-1].es, - self.out_ann, [idx, ['Data: 0x%x' % word, '0x%x' % word]]) - - def decode(self, ss, es, data): - if len(data) < (2 + self.addresssize): - self.put(ss, es, self.out_ann, [2, ['Not enough packet bits']]) - return - - opcode = (data[0].si << 1) + (data[1].si << 0) - - if opcode == 2: - # READ instruction. - self.put(data[0].ss, data[1].es, - self.out_ann, [0, ['Read word', 'READ']]) - self.put_address(data[2:2 + self.addresssize]) - - # Get all words. - word_start = 2 + self.addresssize - while len(data) - word_start > 0: - # Check if there are enough bits for a word. - if len(data) - word_start < self.wordsize: - self.put(data[word_start].ss, data[len(data) - 1].es, - self.out_ann, [2, ['Not enough word bits']]) - break - self.put_word(False, data[word_start:word_start + self.wordsize]) - # Go to next word. - word_start += self.wordsize - elif opcode == 1: - # WRITE instruction. - self.put(data[0].ss, data[1].es, - self.out_ann, [0, ['Write word', 'WRITE']]) - self.put_address(data[2:2 + self.addresssize]) - # Get word. - if len(data) < 2 + self.addresssize + self.wordsize: - self.put(data[2 + self.addresssize].ss, - data[len(data) - 1].ss, - self.out_ann, [2, ['Not enough word bits']]) - else: - self.put_word(True, data[2 + self.addresssize:2 + self.addresssize + self.wordsize]) - elif opcode == 3: - # ERASE instruction. - self.put(data[0].ss, data[1].es, - self.out_ann, [0, ['Erase word', 'ERASE']]) - self.put_address(data[2:2 + self.addresssize]) - elif opcode == 0: - if data[2].si == 1 and data[3].si == 1: - # WEN instruction. - self.put(data[0].ss, data[2 + self.addresssize - 1].es, - self.out_ann, [0, ['Write enable', 'WEN']]) - elif data[2].si == 0 and data[3].si == 0: - # WDS instruction. - self.put(data[0].ss, data[2 + self.addresssize - 1].es, - self.out_ann, [0, ['Write disable', 'WDS']]) - elif data[2].si == 1 and data[3].si == 0: - # ERAL instruction. - self.put(data[0].ss, data[2 + self.addresssize - 1].es, - self.out_ann, [0, ['Erase all memory', - 'Erase all', 'ERAL']]) - elif data[2].si == 0 and data[3].si == 1: - # WRAL instruction. - self.put(data[0].ss, data[2 + self.addresssize - 1].es, - self.out_ann, [0, ['Write all memory', - 'Write all', 'WRAL']]) - # Get word. - if len(data) < 2 + self.addresssize + self.wordsize: - self.put(data[2 + self.addresssize].ss, - data[len(data) - 1].ss, - self.out_ann, [2, ['Not enough word bits']]) - else: - self.put_word(True, data[2 + self.addresssize:2 + self.addresssize + self.wordsize]) diff --git a/decoders/em4100/__init__.py b/decoders/em4100/__init__.py deleted file mode 100755 index c3c95e28..00000000 --- a/decoders/em4100/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Benjamin Larsson -## -## 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, see . -## - -''' -EM4100 is a biphase/manchester/PSK based 100-150kHz RFID protocol. -''' - -from .pd import Decoder diff --git a/decoders/em4100/pd.py b/decoders/em4100/pd.py deleted file mode 100755 index 7f42ad70..00000000 --- a/decoders/em4100/pd.py +++ /dev/null @@ -1,238 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Benjamin Larsson -## -## 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, see . -## - -import sigrokdecode as srd - -class SamplerateError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = 'em4100' - name = 'EM4100' - longname = 'RFID EM4100' - desc = 'EM4100 100-150kHz RFID protocol.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['IC', 'RFID'] - channels = ( - {'id': 'data', 'name': 'Data', 'desc': 'Data line'}, - ) - options = ( - {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-high', - 'values': ('active-low', 'active-high')}, - {'id': 'datarate' , 'desc': 'Data rate', 'default': 64, - 'values': (64, 32, 16)}, -# {'id': 'coding', 'desc': 'Bit coding', 'default': 'biphase', -# 'values': ('biphase', 'manchester', 'psk')}, - {'id': 'coilfreq', 'desc': 'Coil frequency', 'default': 125000}, - ) - annotations = ( - ('bit', 'Bit'), - ('header', 'Header'), - ('version-customer', 'Version/customer'), - ('data', 'Data'), - ('rowparity-ok', 'Row parity OK'), - ('rowparity-err', 'Row parity error'), - ('colparity-ok', 'Column parity OK'), - ('colparity-err', 'Column parity error'), - ('stopbit', 'Stop bit'), - ('tag', 'Tag'), - ) - annotation_rows = ( - ('bits', 'Bits', (0,)), - ('fields', 'Fields', (1, 2, 3, 4, 5, 6, 7, 8)), - ('tags', 'Tags', (9,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.oldpin = None - self.last_samplenum = None - self.lastlast_samplenum = None - self.last_edge = 0 - self.bit_width = 0 - self.halfbit_limit = 0 - self.oldpp = 0 - self.oldpl = 0 - self.oldsamplenum = 0 - self.last_bit_pos = 0 - self.ss_first = 0 - self.first_one = 0 - self.state = 'HEADER' - self.data = 0 - self.data_bits = 0 - self.ss_data = 0 - self.data_parity = 0 - self.payload_cnt = 0 - self.data_col_parity = [0, 0, 0, 0, 0, 0] - self.col_parity = [0, 0, 0, 0, 0, 0] - self.tag = 0 - self.all_row_parity_ok = True - self.col_parity_pos = [] - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - self.bit_width = (self.samplerate / self.options['coilfreq']) * self.options['datarate'] - self.halfbit_limit = self.bit_width/2 + self.bit_width/4 - self.polarity = 0 if self.options['polarity'] == 'active-low' else 1 - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putbit(self, bit, ss, es): - self.put(ss, es, self.out_ann, [0, [str(bit)]]) - if self.state == 'HEADER': - if bit == 1: - if self.first_one > 0: - self.first_one += 1 - if self.first_one == 9: - self.put(self.ss_first, es, self.out_ann, - [1, ['Header', 'Head', 'He', 'H']]) - self.first_one = 0 - self.state = 'PAYLOAD' - return - if self.first_one == 0: - self.first_one = 1 - self.ss_first = ss - - if bit == 0: - self.first_one = 0 - return - - if self.state == 'PAYLOAD': - self.payload_cnt += 1 - if self.data_bits == 0: - self.ss_data = ss - self.data = 0 - self.data_parity = 0 - self.data_bits += 1 - if self.data_bits == 5: - s = 'Version/customer' if self.payload_cnt <= 10 else 'Data' - c = 2 if self.payload_cnt <= 10 else 3 - self.put(self.ss_data, ss, self.out_ann, - [c, [s + ': %X' % self.data, '%X' % self.data]]) - s = 'OK' if self.data_parity == bit else 'ERROR' - c = 4 if s == 'OK' else 5 - if s == 'ERROR': - self.all_row_parity_ok = False - self.put(ss, es, self.out_ann, - [c, ['Row parity: ' + s, 'RP: ' + s, 'RP', 'R']]) - self.tag = (self.tag << 4) | self.data - self.data_bits = 0 - if self.payload_cnt == 50: - self.state = 'TRAILER' - self.payload_cnt = 0 - - self.data_parity ^= bit - self.data_col_parity[self.data_bits] ^= bit - self.data = (self.data << 1) | bit - return - - if self.state == 'TRAILER': - self.payload_cnt += 1 - if self.data_bits == 0: - self.ss_data = ss - self.data = 0 - self.data_parity = 0 - self.data_bits += 1 - self.col_parity[self.data_bits] = bit - self.col_parity_pos.append([ss, es]) - - if self.data_bits == 5: - self.put(ss, es, self.out_ann, [8, ['Stop bit', 'SB', 'S']]) - - for i in range(1, 5): - s = 'OK' if self.data_col_parity[i] == \ - self.col_parity[i] else 'ERROR' - c = 6 if s == 'OK' else 7 - self.put(self.col_parity_pos[i - 1][0], - self.col_parity_pos[i - 1][1], self.out_ann, - [c, ['Column parity %d: %s' % (i, s), - 'CP%d: %s' % (i, s), 'CP%d' % i, 'C']]) - - # Emit an annotation for valid-looking tags. - all_col_parity_ok = (self.data_col_parity[1:5] == self.col_parity[1:5]) - if all_col_parity_ok and self.all_row_parity_ok: - self.put(self.ss_first, es, self.out_ann, - [9, ['Tag: %010X' % self.tag, 'Tag', 'T']]) - - self.tag = 0 - self.data_bits = 0 - - if self.payload_cnt == 5: - self.state = 'HEADER' - self.payload_cnt = 0 - self.data_col_parity = [0, 0, 0, 0, 0, 0] - self.col_parity = [0, 0, 0, 0, 0, 0] - self.col_parity_pos = [] - self.all_row_parity_ok = True - - def manchester_decode(self, pl, pp, pin): - bit = self.oldpin ^ self.polarity - if pl > self.halfbit_limit: - es = int(self.samplenum - pl/2) - if self.oldpl > self.halfbit_limit: - ss = int(self.oldsamplenum - self.oldpl/2) - else: - ss = int(self.oldsamplenum - self.oldpl) - self.putbit(bit, ss, es) - self.last_bit_pos = int(self.samplenum - pl/2) - else: - es = int(self.samplenum) - if self.oldpl > self.halfbit_limit: - ss = int(self.oldsamplenum - self.oldpl/2) - self.putbit(bit, ss, es) - self.last_bit_pos = int(self.samplenum) - else: - if self.last_bit_pos <= self.oldsamplenum - self.oldpl: - ss = int(self.oldsamplenum - self.oldpl) - self.putbit(bit, ss, es) - self.last_bit_pos = int(self.samplenum) - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - - # Initialize internal state from the very first sample. - (pin,) = self.wait() - self.oldpin = pin - self.last_samplenum = self.samplenum - self.lastlast_samplenum = self.samplenum - self.last_edge = self.samplenum - self.oldpl = 0 - self.oldpp = 0 - self.oldsamplenum = 0 - self.last_bit_pos = 0 - - while True: - # Ignore identical samples, only process edges. - (pin,) = self.wait({0: 'e'}) - pl = self.samplenum - self.oldsamplenum - pp = pin - self.manchester_decode(pl, pp, pin) - self.oldpl = pl - self.oldpp = pp - self.oldsamplenum = self.samplenum - self.oldpin = pin diff --git a/decoders/em4305/__init__.py b/decoders/em4305/__init__.py deleted file mode 100755 index df437787..00000000 --- a/decoders/em4305/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Benjamin Larsson -## -## 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, see . -## - -''' -EM4305 is a 100-150kHz RFID protocol. -''' - -from .pd import Decoder diff --git a/decoders/em4305/pd.py b/decoders/em4305/pd.py deleted file mode 100755 index 6297643c..00000000 --- a/decoders/em4305/pd.py +++ /dev/null @@ -1,394 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2016 Benjamin Larsson -## -## 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, see . -## - -import sigrokdecode as srd - -class SamplerateError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = 'em4305' - name = 'EM4305' - longname = 'RFID EM4205/EM4305' - desc = 'EM4205/EM4305 100-150kHz RFID protocol.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['IC', 'RFID'] - channels = ( - {'id': 'data', 'name': 'Data', 'desc': 'Data line'}, - ) - options = ( - {'id': 'coilfreq', 'desc': 'Coil frequency', 'default': 125000}, - {'id': 'first_field_stop', 'desc': 'First field stop min', 'default': 40}, - {'id': 'w_gap', 'desc': 'Write gap min', 'default': 12}, - {'id': 'w_one_max', 'desc': 'Write one max', 'default': 32}, - {'id': 'w_zero_on_min', 'desc': 'Write zero on min', 'default': 15}, - {'id': 'w_zero_off_max', 'desc': 'Write zero off max', 'default': 27}, - {'id': 'em4100_decode', 'desc': 'EM4100 decode', 'default': 'on', - 'values': ('on', 'off')}, - ) - annotations = ( - ('bit_value', 'Bit value'), - ('first_field_stop', 'First field stop'), - ('write_gap', 'Write gap'), - ('write_mode_exit', 'Write mode exit'), - ('bit', 'Bit'), - ('opcode', 'Opcode'), - ('lock', 'Lock'), - ('data', 'Data'), - ('password', 'Password'), - ('address', 'Address'), - ('bitrate', 'Bitrate'), - ) - annotation_rows = ( - ('bits', 'Bits', (0,)), - ('structure', 'Structure', (1, 2, 3, 4)), - ('fields', 'Fields', (5, 6, 7, 8, 9)), - ('decode', 'Decode', (10,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.last_samplenum = None - self.state = 'FFS_SEARCH' - self.bits_pos = [[0 for col in range(3)] for row in range(70)] - self.br_string = ['RF/8', 'RF/16', 'Unused', 'RF/32', 'RF/40', - 'Unused', 'Unused', 'RF/64',] - self.encoder = ['not used', 'Manchester', 'Bi-phase', 'not used'] - self.delayed_on = ['No delay', 'Delayed on - BP/8', 'Delayed on - BP/4', 'No delay'] - self.em4100_decode1_partial = 0 - self.cmds = ['Invalid', 'Login', 'Write word', 'Invalid', 'Read word', 'Disable', 'Protect', 'Invalid'] - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - self.field_clock = self.samplerate / self.options['coilfreq'] - self.wzmax = self.options['w_zero_off_max'] * self.field_clock - self.wzmin = self.options['w_zero_on_min'] * self.field_clock - self.womax = self.options['w_one_max'] * self.field_clock - self.ffs = self.options['first_field_stop'] * self.field_clock - self.writegap = self.options['w_gap'] * self.field_clock - self.nogap = 300 * self.field_clock - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def decode_config(self, idx): - bitrate = self.get_3_bits(idx+2) - self.put(self.bits_pos[idx][1], self.bits_pos[idx+5][2], - self.out_ann, [10, ['Data rate: ' + \ - self.br_string[bitrate], self.br_string[bitrate]]]) - encoding = self.bits_pos[idx+6][0]<<0 | self.bits_pos[idx+7][0]<<1 - self.put(self.bits_pos[idx+6][1], self.bits_pos[idx+10][2], - self.out_ann, [10, ['Encoder: ' + \ - self.encoder[encoding], self.encoder[encoding]]]) - self.put(self.bits_pos[idx+11][1], self.bits_pos[idx+12][2], self.out_ann, - [10, ['Zero bits', 'ZB']]) - delay_on = self.bits_pos[idx+13][0]<<0 | self.bits_pos[idx+14][0]<<1 - self.put(self.bits_pos[idx+13][1], self.bits_pos[idx+14][2], - self.out_ann, [10, ['Delayed on: ' + \ - self.delayed_on[delay_on], self.delayed_on[delay_on]]]) - lwr = self.bits_pos[idx+15][0]<<3 | self.bits_pos[idx+16][0]<<2 | \ - self.bits_pos[idx+18][0]<<1 | self.bits_pos[idx+19][0]<<0 - self.put(self.bits_pos[idx+15][1], self.bits_pos[idx+19][2], - self.out_ann, [10, ['Last default read word: %d' % lwr, 'LWR: %d' % lwr, '%d' % lwr]]) - self.put(self.bits_pos[idx+20][1], self.bits_pos[idx+20][2], - self.out_ann, [10, ['Read login: %d' % self.bits_pos[idx+20][0], '%d' % self.bits_pos[idx+20][0]]]) - self.put(self.bits_pos[idx+21][1], self.bits_pos[idx+21][2], self.out_ann, - [10, ['Zero bits', 'ZB']]) - self.put(self.bits_pos[idx+22][1], self.bits_pos[idx+22][2], - self.out_ann, [10, ['Write login: %d' % self.bits_pos[idx+22][0], '%d' % self.bits_pos[idx+22][0]]]) - self.put(self.bits_pos[idx+23][1], self.bits_pos[idx+24][2], self.out_ann, - [10, ['Zero bits', 'ZB']]) - self.put(self.bits_pos[idx+25][1], self.bits_pos[idx+25][2], - self.out_ann, [10, ['Disable: %d' % self.bits_pos[idx+25][0], '%d' % self.bits_pos[idx+25][0]]]) - self.put(self.bits_pos[idx+27][1], self.bits_pos[idx+27][2], - self.out_ann, [10, ['Reader talk first: %d' % self.bits_pos[idx+27][0], 'RTF: %d' % self.bits_pos[idx+27][0]]]) - self.put(self.bits_pos[idx+28][1], self.bits_pos[idx+28][2], self.out_ann, - [10, ['Zero bits', 'ZB']]) - self.put(self.bits_pos[idx+29][1], self.bits_pos[idx+29][2], - self.out_ann, [10, ['Pigeon mode: %d' % self.bits_pos[idx+29][0], '%d' % self.bits_pos[idx+29][0]]]) - self.put(self.bits_pos[idx+30][1], self.bits_pos[idx+34][2], - self.out_ann, [10, ['Reserved', 'Res', 'R']]) - - def put4bits(self, idx): - bits = self.bits_pos[idx][0]<<3 | self.bits_pos[idx+1][0]<<2 | \ - self.bits_pos[idx+2][0]<<1 | self.bits_pos[idx+3][0] - self.put(self.bits_pos[idx][1], self.bits_pos[idx+3][2], self.out_ann, - [10, ['%X' % bits]]) - - def em4100_decode1(self, idx): - self.put(self.bits_pos[idx][1], self.bits_pos[idx+9][2], self.out_ann, - [10, ['EM4100 header', 'EM header', 'Header', 'H']]) - self.put4bits(idx+10) - bits = self.bits_pos[idx+15][0]<<3 | self.bits_pos[idx+16][0]<<2 | \ - self.bits_pos[idx+18][0]<<1 | self.bits_pos[idx+19][0]<<0 - self.put(self.bits_pos[idx+15][1], self.bits_pos[idx+19][2], self.out_ann, - [10, ['%X' % bits]]) - self.put4bits(idx+21) - self.put4bits(idx+27) - self.em4100_decode1_partial = self.bits_pos[idx+32][0]<<3 | \ - self.bits_pos[idx+33][0]<<2 | self.bits_pos[idx+34][0]<<1 - self.put(self.bits_pos[idx+32][1], self.bits_pos[idx+34][2], - self.out_ann, [10, ['Partial nibble']]) - - def em4100_decode2(self, idx): - if self.em4100_decode1_partial != 0: - bits = self.em4100_decode1_partial + self.bits_pos[idx][0] - self.put(self.bits_pos[idx][1], self.bits_pos[idx][2], - self.out_ann, [10, ['%X' % bits]]) - self.em4100_decode1_partial = 0 - else: - self.put(self.bits_pos[idx][1], self.bits_pos[idx][2], - self.out_ann, [10, ['Partial nibble']]) - - self.put4bits(idx+2) - bits = self.bits_pos[idx+7][0]<<3 | self.bits_pos[idx+9][0]<<2 | \ - self.bits_pos[idx+10][0]<<1 | self.bits_pos[idx+11][0]<<0 - self.put(self.bits_pos[idx+7][1], self.bits_pos[idx+11][2], self.out_ann, - [10, ['%X' % bits]]) - self.put4bits(idx+13) - self.put4bits(idx+19) - bits = self.bits_pos[idx+24][0]<<3 | self.bits_pos[idx+25][0]<<2 | \ - self.bits_pos[idx+27][0]<<1 | self.bits_pos[idx+28][0]<<0 - self.put(self.bits_pos[idx+24][1], self.bits_pos[idx+28][2], self.out_ann, - [10, ['%X' % bits]]) - self.put(self.bits_pos[idx+30][1], self.bits_pos[idx+34][2], - self.out_ann, [10, ['EM4100 trailer']]) - - def get_32_bits(self, idx): - return self.get_8_bits(idx+27)<<24 | self.get_8_bits(idx+18)<<16 | \ - self.get_8_bits(idx+9)<<8 | self.get_8_bits(idx) - - def get_8_bits(self, idx): - retval = 0 - for i in range(0, 8): - retval <<= 1 - retval |= self.bits_pos[i+idx][0] - return retval - - def get_3_bits(self, idx): - return self.bits_pos[idx][0]<<2 | self.bits_pos[idx+1][0]<<1 | \ - self.bits_pos[idx+2][0] - - def get_4_bits(self, idx): - return self.bits_pos[idx][0]<<0 | self.bits_pos[idx+1][0]<<1 | \ - self.bits_pos[idx+2][0]<<2 | self.bits_pos[idx+3][0]<<3 - - def print_row_parity(self, idx, length): - parity = 0 - for i in range(0, length): - parity += self.bits_pos[i+idx][0] - parity = parity & 0x1 - if parity == self.bits_pos[idx+length][0]: - self.put(self.bits_pos[idx+length][1], self.bits_pos[idx+length][2], self.out_ann, - [5, ['Row parity OK', 'Parity OK', 'OK']]) - else: - self.put(self.bits_pos[idx+length][1], self.bits_pos[idx+length][2], self.out_ann, - [5, ['Row parity failed', 'Parity failed', 'Fail']]) - - def print_col_parity(self, idx): - data_1 = self.get_8_bits(idx) - data_2 = self.get_8_bits(idx+9) - data_3 = self.get_8_bits(idx+9+9) - data_4 = self.get_8_bits(idx+9+9+9) - col_par = self.get_8_bits(idx+9+9+9+9) - col_par_calc = data_1^data_2^data_3^data_4 - - if col_par == col_par_calc: - self.put(self.bits_pos[idx+9+9+9+9][1], self.bits_pos[idx+9+9+9+9+7][2], self.out_ann, - [5, ['Column parity OK', 'Parity OK', 'OK']]) - else: - self.put(self.bits_pos[idx+9+9+9+9][1], self.bits_pos[idx+9+9+9+9+7][2], self.out_ann, - [5, ['Column parity failed', 'Parity failed', 'Fail']]) - - def print_8bit_data(self, idx): - data = self.get_8_bits(idx) - self.put(self.bits_pos[idx][1], self.bits_pos[idx+7][2], self.out_ann, - [9, ['Data' + ': %X' % data, '%X' % data]]) - - def put_fields(self): - if self.bit_nr == 50: - self.put(self.bits_pos[0][1], self.bits_pos[0][2], self.out_ann, - [4, ['Logic zero']]) - self.put(self.bits_pos[1][1], self.bits_pos[4][2], self.out_ann, - [4, ['Command', 'Cmd', 'C']]) - self.put(self.bits_pos[5][1], self.bits_pos[49][2], self.out_ann, - [4, ['Password', 'Passwd', 'Pass', 'P']]) - # Get command. - cmd = self.get_3_bits(1) - self.put(self.bits_pos[1][1], self.bits_pos[3][2], self.out_ann, - [5, [self.cmds[cmd]]]) - self.print_row_parity(1, 3) - - # Print data. - self.print_8bit_data(5) - self.print_row_parity(5, 8) - self.print_8bit_data(14) - self.print_row_parity(14, 8) - self.print_8bit_data(23) - self.print_row_parity(23, 8) - self.print_8bit_data(32) - self.print_row_parity(32, 8) - self.print_col_parity(5) - if self.bits_pos[49][0] == 0: - self.put(self.bits_pos[49][1], self.bits_pos[49][2], self.out_ann, - [5, ['Stop bit', 'Stop', 'SB']]) - else: - self.put(self.bits_pos[49][1], self.bits_pos[49][2], self.out_ann, - [5, ['Stop bit error', 'Error']]) - - if cmd == 1: - password = self.get_32_bits(5) - self.put(self.bits_pos[12][1], self.bits_pos[46][2], self.out_ann, - [10, ['Login password: %X' % password]]) - - if self.bit_nr == 57: - self.put(self.bits_pos[0][1], self.bits_pos[0][2], self.out_ann, - [4, ['Logic zero', 'LZ']]) - self.put(self.bits_pos[1][1], self.bits_pos[4][2], self.out_ann, - [4, ['Command', 'Cmd', 'C']]) - self.put(self.bits_pos[5][1], self.bits_pos[11][2], self.out_ann, - [4, ['Address', 'Addr', 'A']]) - self.put(self.bits_pos[12][1], self.bits_pos[56][2], self.out_ann, - [4, ['Data', 'Da', 'D']]) - - # Get command. - cmd = self.get_3_bits(1) - self.put(self.bits_pos[1][1], self.bits_pos[3][2], self.out_ann, - [5, [self.cmds[cmd]]]) - self.print_row_parity(1, 3) - - # Get address. - addr = self.get_4_bits(5) - self.put(self.bits_pos[5][1], self.bits_pos[8][2], self.out_ann, - [9, ['Addr' + ': %d' % addr, '%d' % addr]]) - self.put(self.bits_pos[9][1], self.bits_pos[10][2], self.out_ann, - [5, ['Zero bits', 'ZB']]) - self.print_row_parity(5, 6) - # Print data. - self.print_8bit_data(12) - self.print_row_parity(12, 8) - self.print_8bit_data(21) - self.print_row_parity(21, 8) - self.print_8bit_data(30) - self.print_row_parity(30, 8) - self.print_8bit_data(39) - self.print_row_parity(39, 8) - self.print_col_parity(12) - if self.bits_pos[56][0] == 0: - self.put(self.bits_pos[56][1], self.bits_pos[56][2], self.out_ann, - [5, ['Stop bit', 'Stop', 'SB']]) - else: - self.put(self.bits_pos[56][1], self.bits_pos[56][2], self.out_ann, - [5, ['Stop bit error', 'Error']]) - - if addr == 4: - self.decode_config(12) - - if addr == 2: - password = self.get_32_bits(12) - self.put(self.bits_pos[12][1], self.bits_pos[46][2], self.out_ann, - [10, ['Write password: %X' % password]]) - - # If we are programming EM4100 data we can decode it halfway. - if addr == 5 and self.options['em4100_decode'] == 'on': - self.em4100_decode1(12) - if addr == 6 and self.options['em4100_decode'] == 'on': - self.em4100_decode2(12) - - self.bit_nr = 0 - - def add_bits_pos(self, bit, ss_bit, es_bit): - if self.bit_nr < 70: - self.bits_pos[self.bit_nr][0] = bit - self.bits_pos[self.bit_nr][1] = ss_bit - self.bits_pos[self.bit_nr][2] = es_bit - self.bit_nr += 1 - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - - # Initialize internal state. - self.last_samplenum = self.samplenum - self.oldsamplenum = 0 - self.old_gap_end = 0 - self.gap_detected = 0 - self.bit_nr = 0 - - while True: - # Ignore identical samples, only process edges. - (pin,) = self.wait({0: 'e'}) - - pl = self.samplenum - self.oldsamplenum - pp = pin - samples = self.samplenum - self.last_samplenum - - if self.state == 'FFS_DETECTED': - if pl > self.writegap: - self.gap_detected = 1 - if (self.last_samplenum - self.old_gap_end) > self.nogap: - self.gap_detected = 0 - self.state = 'FFS_SEARCH' - self.put(self.old_gap_end, self.last_samplenum, - self.out_ann, [3, ['Write mode exit']]) - self.put_fields() - - if self.state == 'FFS_SEARCH': - if pl > self.ffs: - self.gap_detected = 1 - self.put(self.last_samplenum, self.samplenum, - self.out_ann, [1, ['First field stop', 'Field stop', 'FFS']]) - self.state = 'FFS_DETECTED' - - if self.gap_detected == 1: - self.gap_detected = 0 - if (self.last_samplenum - self.old_gap_end) > self.wzmin \ - and (self.last_samplenum - self.old_gap_end) < self.wzmax: - self.put(self.old_gap_end, self.samplenum, - self.out_ann, [0, ['0']]) - self.add_bits_pos(0, self.old_gap_end, self.samplenum) - if (self.last_samplenum - self.old_gap_end) > self.womax \ - and (self.last_samplenum-self.old_gap_end) < self.nogap: - # One or more 1 bits - one_bits = (int)((self.last_samplenum - self.old_gap_end) / self.womax) - for ox in range(0, one_bits): - bs = (int)(self.old_gap_end+ox*self.womax) - be = (int)(self.old_gap_end+ox*self.womax + self.womax) - self.put(bs, be, self.out_ann, [0, ['1']]) - self.add_bits_pos(1, bs, be) - if (self.samplenum - self.last_samplenum) > self.wzmin \ - and (self.samplenum - self.last_samplenum) < self.wzmax: - bs = (int)(self.old_gap_end+one_bits*self.womax) - self.put(bs, self.samplenum, self.out_ann, [0, ['0']]) - self.add_bits_pos(0, bs, self.samplenum) - - self.old_gap_end = self.samplenum - - if self.state == 'SKIP': - self.state = 'FFS_SEARCH' - - self.oldsamplenum = self.samplenum - self.last_samplenum = self.samplenum diff --git a/decoders/enc28j60/__init__.py b/decoders/enc28j60/__init__.py deleted file mode 100644 index 42f4377e..00000000 --- a/decoders/enc28j60/__init__.py +++ /dev/null @@ -1,32 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Jiahao Li -## -## Permission is hereby granted, free of charge, to any person obtaining a copy -## of this software and associated documentation files (the "Software"), to deal -## in the Software without restriction, including without limitation the rights -## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -## copies of the Software, and to permit persons to whom the Software is -## furnished to do so, subject to the following conditions: -## -## The above copyright notice and this permission notice shall be included in all -## copies or substantial portions of the Software. -## -## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -## SOFTWARE. - -''' -This decoder stacks on top of the 'spi' PD and decodes the protocol spoken -by the Microchip ENC28J60 Ethernet chip. - -Details: -http://ww1.microchip.com/downloads/en/DeviceDoc/39662e.pdf -''' - -from .pd import Decoder diff --git a/decoders/enc28j60/lists.py b/decoders/enc28j60/lists.py deleted file mode 100644 index 59fbc1f2..00000000 --- a/decoders/enc28j60/lists.py +++ /dev/null @@ -1,161 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Jiahao Li -## -## Permission is hereby granted, free of charge, to any person obtaining a copy -## of this software and associated documentation files (the "Software"), to deal -## in the Software without restriction, including without limitation the rights -## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -## copies of the Software, and to permit persons to whom the Software is -## furnished to do so, subject to the following conditions: -## -## The above copyright notice and this permission notice shall be included in all -## copies or substantial portions of the Software. -## -## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -## SOFTWARE. - -REGS = [ - [ - 'ERDPTL', - 'ERDPTH', - 'EWRPTL', - 'EWRPTH', - 'ETXSTL', - 'ETXSTH', - 'ETXNDL', - 'ETXNDH', - 'ERXSTL', - 'ERXSTH', - 'ERXNDL', - 'ERXNDH', - 'ERXRDPTL', - 'ERXRDPTH', - 'ERXWRPTL', - 'ERXWRPTH', - 'EDMASTL', - 'EDMASTH', - 'EDMANDL', - 'EDMANDH', - 'EDMADSTL', - 'EDMADSTH', - 'EDMACSL', - 'EDMACSH', - '—', - '—', - 'Reserved', - 'EIE', - 'EIR', - 'ESTAT', - 'ECON2', - 'ECON1', - ], - [ - 'EHT0', - 'EHT1', - 'EHT2', - 'EHT3', - 'EHT4', - 'EHT5', - 'EHT6', - 'EHT7', - 'EPMM0', - 'EPMM1', - 'EPMM2', - 'EPMM3', - 'EPMM4', - 'EPMM5', - 'EPMM6', - 'EPMM7', - 'EPMCSL', - 'EPMCSH', - '—', - '—', - 'EPMOL', - 'EPMOH', - 'Reserved', - 'Reserved', - 'ERXFCON', - 'EPKTCNT', - 'Reserved', - 'EIE', - 'EIR', - 'ESTAT', - 'ECON2', - 'ECON1', - ], - [ - 'MACON1', - 'Reserved', - 'MACON3', - 'MACON4', - 'MABBIPG', - '—', - 'MAIPGL', - 'MAIPGH', - 'MACLCON1', - 'MACLCON2', - 'MAMXFLL', - 'MAMXFLH', - 'Reserved', - 'Reserved', - 'Reserved', - '—', - 'Reserved', - 'Reserved', - 'MICMD', - '—', - 'MIREGADR', - 'Reserved', - 'MIWRL', - 'MIWRH', - 'MIRDL', - 'MIRDH', - 'Reserved', - 'EIE', - 'EIR', - 'ESTAT', - 'ECON2', - 'ECON1', - ], - [ - 'MAADR5', - 'MAADR6', - 'MAADR3', - 'MAADR4', - 'MAADR1', - 'MAADR2', - 'EBSTSD', - 'EBSTCON', - 'EBSTCSL', - 'EBSTCSH', - 'MISTAT', - '—', - '—', - '—', - '—', - '—', - '—', - '—', - 'EREVID', - '—', - '—', - 'ECOCON', - 'Reserved', - 'EFLOCON', - 'EPAUSL', - 'EPAUSH', - 'Reserved', - 'EIE', - 'EIR', - 'ESTAT', - 'ECON2', - 'ECON1', - ], -] diff --git a/decoders/enc28j60/pd.py b/decoders/enc28j60/pd.py deleted file mode 100644 index f7a6625a..00000000 --- a/decoders/enc28j60/pd.py +++ /dev/null @@ -1,294 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Jiahao Li -## -## Permission is hereby granted, free of charge, to any person obtaining a copy -## of this software and associated documentation files (the "Software"), to deal -## in the Software without restriction, including without limitation the rights -## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -## copies of the Software, and to permit persons to whom the Software is -## furnished to do so, subject to the following conditions: -## -## The above copyright notice and this permission notice shall be included in all -## copies or substantial portions of the Software. -## -## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -## SOFTWARE. - -import sigrokdecode as srd -from .lists import * - -OPCODE_MASK = 0b11100000 -REG_ADDR_MASK = 0b00011111 - -OPCODE_HANDLERS = { - 0b00000000: '_process_rcr', - 0b00100000: '_process_rbm', - 0b01000000: '_process_wcr', - 0b01100000: '_process_wbm', - 0b10000000: '_process_bfs', - 0b10100000: '_process_bfc', - 0b11100000: '_process_src', -} - -(ANN_RCR, ANN_RBM, ANN_WCR, ANN_WBM, ANN_BFS, ANN_BFC, ANN_SRC, ANN_DATA, -ANN_REG_ADDR, ANN_WARNING) = range(10) - -REG_ADDR_ECON1 = 0x1F -BIT_ECON1_BSEL0 = 0b00000001 -BIT_ECON1_BSEL1 = 0b00000010 - -class Decoder(srd.Decoder): - api_version = 3 - id = 'enc28j60' - name = 'ENC28J60' - longname = 'Microchip ENC28J60' - desc = 'Microchip ENC28J60 10Base-T Ethernet controller protocol.' - license = 'mit' - inputs = ['spi'] - outputs = [] - tags = ['Embedded/industrial', 'Networking'] - annotations = ( - ('rcr', 'Read Control Register'), - ('rbm', 'Read Buffer Memory'), - ('wcr', 'Write Control Register'), - ('wbm', 'Write Buffer Memory'), - ('bfs', 'Bit Field Set'), - ('bfc', 'Bit Field Clear'), - ('src', 'System Reset Command'), - ('data', 'Data'), - ('reg-addr', 'Register Address'), - ('warning', 'Warning'), - ) - annotation_rows = ( - ('commands', 'Commands', - (ANN_RCR, ANN_RBM, ANN_WCR, ANN_WBM, ANN_BFS, ANN_BFC, ANN_SRC)), - ('fields', 'Fields', (ANN_DATA, ANN_REG_ADDR)), - ('warnings', 'Warnings', (ANN_WARNING,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.mosi = [] - self.miso = [] - self.ranges = [] - self.cmd_ss = None - self.cmd_es = None - self.range_ss = None - self.range_es = None - self.active = False - self.bsel0 = None - self.bsel1 = None - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putc(self, data): - self.put(self.cmd_ss, self.cmd_es, self.out_ann, data) - - def putr(self, data): - self.put(self.range_ss, self.range_es, self.out_ann, data) - - def _process_command(self): - if len(self.mosi) == 0: - self.active = False - return - - header = self.mosi[0] - opcode = header & OPCODE_MASK - - if opcode not in OPCODE_HANDLERS: - self._put_command_warning("Unknown opcode.") - self.active = False - return - - getattr(self, OPCODE_HANDLERS[opcode])() - - self.active = False - - def _get_register_name(self, reg_addr): - if (self.bsel0 is None) or (self.bsel1 is None): - # We don't know the bank we're in yet. - return None - else: - bank = (self.bsel1 << 1) + self.bsel0 - return REGS[bank][reg_addr] - - def _put_register_header(self): - reg_addr = self.mosi[0] & REG_ADDR_MASK - reg_name = self._get_register_name(reg_addr) - - self.range_ss, self.range_es = self.cmd_ss, self.ranges[1][0] - - if reg_name is None: - # We don't know the bank we're in yet. - self.putr([ANN_REG_ADDR, [ - 'Reg Bank ? Addr 0x{0:02X}'.format(reg_addr), - '?:{0:02X}'.format(reg_addr)]]) - self.putr([ANN_WARNING, ['Warning: Register bank not known yet.', - 'Warning']]) - else: - self.putr([ANN_REG_ADDR, ['Reg {0}'.format(reg_name), - '{0}'.format(reg_name)]]) - - if (reg_name == '-') or (reg_name == 'Reserved'): - self.putr([ANN_WARNING, ['Warning: Invalid register accessed.', - 'Warning']]) - - def _put_data_byte(self, data, byte_index, binary=False): - self.range_ss = self.ranges[byte_index][0] - if byte_index == len(self.mosi) - 1: - self.range_es = self.cmd_es - else: - self.range_es = self.ranges[byte_index + 1][0] - - if binary: - self.putr([ANN_DATA, ['Data 0b{0:08b}'.format(data), - '{0:08b}'.format(data)]]) - else: - self.putr([ANN_DATA, ['Data 0x{0:02X}'.format(data), - '{0:02X}'.format(data)]]) - - def _put_command_warning(self, reason): - self.putc([ANN_WARNING, ['Warning: {0}'.format(reason), 'Warning']]) - - def _process_rcr(self): - self.putc([ANN_RCR, ['Read Control Register', 'RCR']]) - - if (len(self.mosi) != 2) and (len(self.mosi) != 3): - self._put_command_warning('Invalid command length.') - return - - self._put_register_header() - - reg_name = self._get_register_name(self.mosi[0] & REG_ADDR_MASK) - if reg_name is None: - # We can't tell if we're accessing MAC/MII registers or not - # Let's trust the user in this case. - pass - else: - if (reg_name[0] == 'M') and (len(self.mosi) != 3): - self._put_command_warning('Attempting to read a MAC/MII ' - + 'register without using the dummy byte.') - return - - if (reg_name[0] != 'M') and (len(self.mosi) != 2): - self._put_command_warning('Attempting to read a non-MAC/MII ' - + 'register using the dummy byte.') - return - - if len(self.mosi) == 2: - self._put_data_byte(self.miso[1], 1) - else: - self.range_ss, self.range_es = self.ranges[1][0], self.ranges[2][0] - self.putr([ANN_DATA, ['Dummy Byte', 'Dummy']]) - self._put_data_byte(self.miso[2], 2) - - def _process_rbm(self): - if self.mosi[0] != 0b00111010: - self._put_command_warning('Invalid header byte.') - return - - self.putc([ANN_RBM, ['Read Buffer Memory: Length {0}'.format( - len(self.mosi) - 1), 'RBM']]) - - for i in range(1, len(self.miso)): - self._put_data_byte(self.miso[i], i) - - def _process_wcr(self): - self.putc([ANN_WCR, ['Write Control Register', 'WCR']]) - - if len(self.mosi) != 2: - self._put_command_warning('Invalid command length.') - return - - self._put_register_header() - self._put_data_byte(self.mosi[1], 1) - - if self.mosi[0] & REG_ADDR_MASK == REG_ADDR_ECON1: - self.bsel0 = (self.mosi[1] & BIT_ECON1_BSEL0) >> 0 - self.bsel1 = (self.mosi[1] & BIT_ECON1_BSEL1) >> 1 - - def _process_wbm(self): - if self.mosi[0] != 0b01111010: - self._put_command_warning('Invalid header byte.') - return - - self.putc([ANN_WBM, ['Write Buffer Memory: Length {0}'.format( - len(self.mosi) - 1), 'WBM']]) - - for i in range(1, len(self.mosi)): - self._put_data_byte(self.mosi[i], i) - - def _process_bfc(self): - self.putc([ANN_BFC, ['Bit Field Clear', 'BFC']]) - - if len(self.mosi) != 2: - self._put_command_warning('Invalid command length.') - return - - self._put_register_header() - self._put_data_byte(self.mosi[1], 1, True) - - if self.mosi[0] & REG_ADDR_MASK == REG_ADDR_ECON1: - if self.mosi[1] & BIT_ECON1_BSEL0: - self.bsel0 = 0 - if self.mosi[1] & BIT_ECON1_BSEL1: - self.bsel1 = 0 - - def _process_bfs(self): - self.putc([ANN_BFS, ['Bit Field Set', 'BFS']]) - - if len(self.mosi) != 2: - self._put_command_warning('Invalid command length.') - return - - self._put_register_header() - self._put_data_byte(self.mosi[1], 1, True) - - if self.mosi[0] & REG_ADDR_MASK == REG_ADDR_ECON1: - if self.mosi[1] & BIT_ECON1_BSEL0: - self.bsel0 = 1 - if self.mosi[1] & BIT_ECON1_BSEL1: - self.bsel1 = 1 - - def _process_src(self): - self.putc([ANN_SRC, ['System Reset Command', 'SRC']]) - - if len(self.mosi) != 1: - self._put_command_warning('Invalid command length.') - return - - self.bsel0 = 0 - self.bsel1 = 0 - - def decode(self, ss, es, data): - ptype, data1, data2 = data - - if ptype == 'CS-CHANGE': - new_cs = data2 - - if new_cs == 0: - self.active = True - self.cmd_ss = ss - self.mosi = [] - self.miso = [] - self.ranges = [] - elif new_cs == 1: - if self.active: - self.cmd_es = es - self._process_command() - elif ptype == 'DATA': - mosi, miso = data1, data2 - - self.mosi.append(mosi) - self.miso.append(miso) - self.ranges.append((ss, es)) diff --git a/decoders/flexray/__init__.py b/decoders/flexray/__init__.py deleted file mode 100644 index 73dc7fa1..00000000 --- a/decoders/flexray/__init__.py +++ /dev/null @@ -1,32 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Stephan Thiele -## -## 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, see . -## - -''' -FlexRay is a fast, deterministic and fault-tolerant fieldbus system -which is used in cars in high security related areas like X-by-Wire. - -It is the result of the FlexRay consortium which consisted of BMW, -Daimler, Motorola (today Freescale) and Philips, with the goal of -working out a common standard automotive bus system. - -This decoder assumes that at least one channel of a logic level RX line -of a transceiver is sampled (e.g. NXP TJA1080). -''' - -from .pd import Decoder diff --git a/decoders/flexray/pd.py b/decoders/flexray/pd.py deleted file mode 100644 index 8ec30439..00000000 --- a/decoders/flexray/pd.py +++ /dev/null @@ -1,413 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Stephan Thiele -## -## 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, see . -## - -import sigrokdecode as srd - -# Selection of constants as defined in FlexRay specification 3.0.1 Chapter A.1: -class Const: - cChannelIdleDelimiter = 11 - cCrcInitA = 0xFEDCBA - cCrcInitB = 0xABCDEF - cCrcPolynomial = 0x5D6DCB - cCrcSize = 24 - cCycleCountMax = 63 - cdBSS = 2 - cdCAS = 30 - cdFES = 2 - cdFSS = 1 - cHCrcInit = 0x01A - cHCrcPolynomial = 0x385 - cHCrcSize = 11 - cSamplesPerBit = 8 - cSlotIDMax = 2047 - cStaticSlotIDMax = 1023 - cVotingSamples = 5 - -class SamplerateError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = 'flexray' - name = 'FlexRay' - longname = 'FlexRay' - desc = 'Automotive network communications protocol.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Automotive'] - channels = ( - {'id': 'channel', 'name': 'Channel', 'desc': 'FlexRay bus channel'}, - ) - options = ( - {'id': 'channel_type', 'desc': 'Channel type', 'default': 'A', - 'values': ('A', 'B')}, - {'id': 'bitrate', 'desc': 'Bitrate (bit/s)', 'default': 10000000, - 'values': (10000000, 5000000, 2500000)}, - ) - annotations = ( - ('data', 'FlexRay payload data'), - ('tss', 'Transmission start sequence'), - ('fss', 'Frame start sequence'), - ('reserved-bit', 'Reserved bit'), - ('ppi', 'Payload preamble indicator'), - ('null-frame', 'Nullframe indicator'), - ('sync-frame', 'Full identifier'), - ('startup-frame', 'Startup frame indicator'), - ('id', 'Frame ID'), - ('length', 'Data length'), - ('header-crc', 'Header CRC'), - ('cycle', 'Cycle code'), - ('data-byte', 'Data byte'), - ('frame-crc', 'Frame CRC'), - ('fes', 'Frame end sequence'), - ('bss', 'Byte start sequence'), - ('warning', 'Warning'), - ('bit', 'Bit'), - ('cid', 'Channel idle delimiter'), - ('dts', 'Dynamic trailing sequence'), - ('cas', 'Collision avoidance symbol'), - ) - annotation_rows = ( - ('bits', 'Bits', (15, 17)), - ('fields', 'Fields', tuple(range(15)) + (18, 19, 20)), - ('warnings', 'Warnings', (16,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.reset_variables() - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - bitrate = float(self.options['bitrate']) - self.samplerate = value - self.bit_width = float(self.samplerate) / bitrate - self.sample_point = (self.bit_width / 100.0) * self.sample_point_percent - - # Generic helper for FlexRay bit annotations. - def putg(self, ss, es, data): - left, right = int(self.sample_point), int(self.bit_width - self.sample_point) - self.put(ss - left, es + right, self.out_ann, data) - - # Single-FlexRay-bit annotation using the current samplenum. - def putx(self, data): - self.putg(self.samplenum, self.samplenum, data) - - # Multi-FlexRay-bit annotation from self.ss_block to current samplenum. - def putb(self, data): - self.putg(self.ss_block, self.samplenum, data) - - # Generic CRC algorithm for any bit size and any data length. Used for - # 11-bit header and 24-bit trailer. Not very efficient but at least it - # works for now. - # - # TODO: - # - use precalculated tables to increase performance. - # - Add support for reverse CRC calculations. - - @staticmethod - def crc(data, data_len_bits, polynom, crc_len_bits, iv=0, xor=0): - reg = iv ^ xor - - for i in range(data_len_bits - 1, -1, -1): - bit = ((reg >> (crc_len_bits - 1)) & 0x1) ^ ((data >> i) & 0x1) - reg <<= 1 - if bit: - reg ^= polynom - - mask = (1 << crc_len_bits) - 1 - crc = reg & mask - - return crc ^ xor - - def reset_variables(self): - self.sample_point_percent = 50 # TODO: use vote based sampling - self.state = 'IDLE' - self.tss_start = self.tss_end = self.frame_type = self.dlc = None - self.rawbits = [] # All bits, including byte start sequence bits - self.bits = [] # Only actual FlexRay frame bits (no byte start sequence bits) - self.curbit = 0 # Current bit of FlexRay frame (bit 0 == FSS) - self.last_databit = 999 # Positive value that bitnum+x will never match - self.last_xmit_bit = 999 # Positive value that bitnum+x will never match - self.ss_block = None - self.ss_databytebits = [] - self.end_of_frame = False - self.dynamic_frame = False - self.ss_bit0 = None - self.ss_bit1 = None - self.ss_bit2 = None - - # Poor man's clock synchronization. Use signal edges which change to - # dominant state in rather simple ways. This naive approach is neither - # aware of the SYNC phase's width nor the specific location of the edge, - # but improves the decoder's reliability when the input signal's bitrate - # does not exactly match the nominal rate. - def dom_edge_seen(self, force=False): - self.dom_edge_snum = self.samplenum - self.dom_edge_bcount = self.curbit - - # Determine the position of the next desired bit's sample point. - def get_sample_point(self, bitnum): - samplenum = self.dom_edge_snum - samplenum += self.bit_width * (bitnum - self.dom_edge_bcount) - samplenum += self.sample_point - return int(samplenum) - - def is_bss_sequence(self): - # FlexRay uses NRZ encoding and adds a binary 10 sequence before each - # byte. After each 8 data bits, a BSS sequence is added but not after - # frame CRC. - - if self.end_of_frame: - return False - - if (len(self.rawbits) - 2) % 10 == 0: - return True - elif (len(self.rawbits) - 3) % 10 == 0: - return True - - return False - - def handle_bit(self, fr_rx): - self.rawbits.append(fr_rx) - self.bits.append(fr_rx) - - # Get the index of the current FlexRay frame bit. - bitnum = len(self.bits) - 1 - - # If this is a byte start sequence remove it from self.bits and ignore it. - if self.is_bss_sequence(): - self.bits.pop() - - if bitnum > 1: - self.putx([15, [str(fr_rx)]]) - else: - if len(self.rawbits) == 2: - self.ss_bit1 = self.samplenum - elif len(self.rawbits) == 3: - self.ss_bit2 = self.samplenum - - self.curbit += 1 # Increase self.curbit (bitnum is not affected). - return - else: - if bitnum > 1: - self.putx([17, [str(fr_rx)]]) - - # Bit 0: Frame start sequence (FSS) bit - if bitnum == 0: - self.ss_bit0 = self.samplenum - - # Bit 1: Start of header - elif bitnum == 1: - if self.rawbits[:3] == [1, 1, 0]: - self.put(self.tss_start, self.tss_end, self.out_ann, - [1, ['Transmission start sequence', 'TSS']]) - - self.putg(self.ss_bit0, self.ss_bit0, [17, [str(self.rawbits[:3][0])]]) - self.putg(self.ss_bit0, self.ss_bit0, [2, ['FSS', 'Frame start sequence']]) - self.putg(self.ss_bit1, self.ss_bit1, [15, [str(self.rawbits[:3][1])]]) - self.putg(self.ss_bit2, self.ss_bit2, [15, [str(self.rawbits[:3][2])]]) - self.putx([17, [str(fr_rx)]]) - self.putx([3, ['Reserved bit: %d' % fr_rx, 'RB: %d' % fr_rx, 'RB']]) - else: - self.put(self.tss_start, self.tss_end, self.out_ann, - [20, ['Collision avoidance symbol', 'CAS']]) - self.reset_variables() - - # TODO: warning, if sequence is neither [1, 1, 0] nor [1, 1, 1] - - # Bit 2: Payload preamble indicator. Must be 0 if null frame indicator is 0. - elif bitnum == 2: - self.putx([4, ['Payload preamble indicator: %d' % fr_rx, - 'PPI: %d' % fr_rx]]) - - # Bit 3: Null frame indicator (inversed) - elif bitnum == 3: - data_type = 'data frame' if fr_rx else 'null frame' - self.putx([5, ['Null frame indicator: %s' % data_type, - 'NF: %d' % fr_rx, 'NF']]) - - # Bit 4: Sync frame indicator - # Must be 1 if startup frame indicator is 1. - elif bitnum == 4: - self.putx([6, ['Sync frame indicator: %d' % fr_rx, - 'Sync: %d' % fr_rx, 'Sync']]) - - # Bit 5: Startup frame indicator - elif bitnum == 5: - self.putx([7, ['Startup frame indicator: %d' % fr_rx, - 'Startup: %d' % fr_rx, 'Startup']]) - - # Remember start of ID (see below). - elif bitnum == 6: - self.ss_block = self.samplenum - - # Bits 6-16: Frame identifier (ID[10..0]) - # ID must NOT be 0. - elif bitnum == 16: - self.id = int(''.join(str(d) for d in self.bits[6:]), 2) - self.putb([8, ['Frame ID: %d' % self.id, 'ID: %d' % self.id, - '%d' % self.id]]) - - # Remember start of payload length (see below). - elif bitnum == 17: - self.ss_block = self.samplenum - - # Bits 17-23: Payload length (Length[7..0]) - # Payload length in header is the half of the real payload size. - elif bitnum == 23: - self.payload_length = int(''.join(str(d) for d in self.bits[17:]), 2) - self.putb([9, ['Payload length: %d' % self.payload_length, - 'Length: %d' % self.payload_length, - '%d' % self.payload_length]]) - - # Remember start of header CRC (see below). - elif bitnum == 24: - self.ss_block = self.samplenum - - # Bits 24-34: Header CRC (11-bit) (HCRC[11..0]) - # Calculation of header CRC is equal on both channels. - elif bitnum == 34: - bits = ''.join([str(b) for b in self.bits[4:24]]) - header_to_check = int(bits, 2) - expected_crc = self.crc(header_to_check, len(bits), - Const.cHCrcPolynomial, Const.cHCrcSize, Const.cHCrcInit) - self.header_crc = int(''.join(str(d) for d in self.bits[24:]), 2) - - crc_ok = self.header_crc == expected_crc - crc_ann = "OK" if crc_ok else "bad" - - self.putb([10, ['Header CRC: 0x%X (%s)' % (self.header_crc, crc_ann), - '0x%X (%s)' % (self.header_crc, crc_ann), - '0x%X' % self.header_crc]]) - - # Remember start of cycle code (see below). - elif bitnum == 35: - self.ss_block = self.samplenum - - # Bits 35-40: Cycle code (Cyc[6..0]) - # Cycle code. Must be between 0 and 63. - elif bitnum == 40: - self.cycle = int(''.join(str(d) for d in self.bits[35:]), 2) - self.putb([11, ['Cycle: %d' % self.cycle, 'Cyc: %d' % self.cycle, - '%d' % self.cycle]]) - self.last_databit = 41 + 2 * self.payload_length * 8 - - # Remember all databyte bits, except the very last one. - elif bitnum in range(41, self.last_databit): - self.ss_databytebits.append(self.samplenum) - - # Bits 41-X: Data field (0-254 bytes, depending on length) - # The bits within a data byte are transferred MSB-first. - elif bitnum == self.last_databit: - self.ss_databytebits.append(self.samplenum) # Last databyte bit. - for i in range(2 * self.payload_length): - x = 40 + (8 * i) + 1 - b = int(''.join(str(d) for d in self.bits[x:x + 8]), 2) - ss = self.ss_databytebits[i * 8] - es = self.ss_databytebits[((i + 1) * 8) - 1] - self.putg(ss, es, [12, ['Data byte %d: 0x%02x' % (i, b), - 'DB%d: 0x%02x' % (i, b), '%02X' % b]]) - self.ss_databytebits = [] - self.ss_block = self.samplenum # Remember start of trailer CRC. - - # Trailer CRC (24-bit) (CRC[11..0]) - # Initialization vector of channel A and B are different, so CRCs are - # different for same data. - elif bitnum == self.last_databit + 23: - bits = ''.join([str(b) for b in self.bits[1:-24]]) - frame_to_check = int(bits, 2) - iv = Const.cCrcInitA if self.options['channel_type'] == 'A' else Const.cCrcInitB - expected_crc = self.crc(frame_to_check, len(bits), - Const.cCrcPolynomial, Const.cCrcSize, iv=iv) - self.frame_crc = int(''.join(str(d) for d in self.bits[self.last_databit:]), 2) - - crc_ok = self.frame_crc == expected_crc - crc_ann = "OK" if crc_ok else "bad" - - self.putb([13, ['Frame CRC: 0x%X (%s)' % (self.frame_crc, crc_ann), - '0x%X (%s)' % (self.frame_crc, crc_ann), - '0x%X' % self.frame_crc]]) - self.end_of_frame = True - - # Remember start of frame end sequence (see below). - elif bitnum == self.last_databit + 24: - self.ss_block = self.samplenum - - # Frame end sequence, must be 1 followed by 0. - elif bitnum == self.last_databit + 25: - self.putb([14, ['Frame end sequence', 'FES']]) - - # Check for DTS - elif bitnum == self.last_databit + 26: - if not fr_rx: - self.dynamic_frame = True - else: - self.last_xmit_bit = bitnum - self.ss_block = self.samplenum - - # Remember start of channel idle delimiter (see below). - elif bitnum == self.last_xmit_bit: - self.ss_block = self.samplenum - - # Channel idle limiter (CID[11..0]) - elif bitnum == self.last_xmit_bit + Const.cChannelIdleDelimiter - 1: - self.putb([18, ['Channel idle delimiter', 'CID']]) - self.reset_variables() - - # DTS if dynamic frame - elif bitnum > self.last_databit + 27: - if self.dynamic_frame: - if fr_rx: - if self.last_xmit_bit == 999: - self.putb([19, ['Dynamic trailing sequence', 'DTS']]) - self.last_xmit_bit = bitnum + 1 - self.ss_block = self.samplenum - - self.curbit += 1 - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - - while True: - # State machine. - if self.state == 'IDLE': - # Wait for a dominant state (logic 0) on the bus. - (fr_rx,) = self.wait({0: 'l'}) - self.tss_start = self.samplenum - (fr_rx,) = self.wait({0: 'h'}) - self.tss_end = self.samplenum - self.dom_edge_seen(force = True) - self.state = 'GET BITS' - elif self.state == 'GET BITS': - # Wait until we're in the correct bit/sampling position. - pos = self.get_sample_point(self.curbit) - (fr_rx,) = self.wait([{'skip': pos - self.samplenum}, {0: 'f'}]) - if self.matched[1]: - self.dom_edge_seen() - if self.matched[0]: - self.handle_bit(fr_rx) diff --git a/decoders/fsi/__init__.py b/decoders/fsi/__init__.py deleted file mode 100755 index 8d589923..00000000 --- a/decoders/fsi/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 Raptor Engineering, LLC -## -## This program is free software: you can redistribute it and/or modify -## it under the terms of the GNU Affero 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 Affero General Public License for more details. -## -## You should have received a copy of the GNU Affero General Public License -## along with this program. If not, see . -## - -''' -FSI is a low level serial protocol used by various devices on OpenPOWER -systems such as the Raptor Talos II and Blackbird. -''' - -from .pd import Decoder diff --git a/decoders/fsi/pd.py b/decoders/fsi/pd.py deleted file mode 100755 index 4b6b69f6..00000000 --- a/decoders/fsi/pd.py +++ /dev/null @@ -1,574 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 Raptor Engineering, LLC -## -## This program is free software: you can redistribute it and/or modify -## it under the terms of the GNU Affero 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 Affero General Public License for more details. -## -## You should have received a copy of the GNU Affero General Public License -## along with this program. If not, see . -## - -import sigrokdecode as srd - -# ... -fields = { - # START field (indicates the start of a transaction) - 'START': { - 0b1: 'Start of FSI cycle', - }, -} - -class Decoder(srd.Decoder): - api_version = 3 - id = 'fsi' - name = 'FSI' - longname = 'Flexible Service Interface' - desc = 'Protocol for FSI devices on Raptor OpenPOWER systems.' - license = 'agplv3' - inputs = ['logic'] - outputs = [] - tags = ['PC'] - channels = ( - {'id': 'data', 'name': 'DATA', 'desc': 'Frame'}, - {'id': 'clock', 'name': 'CLOCK', 'desc': 'Clock'}, - ) - annotations = ( - ('warnings', 'Warnings'), - ('start', 'Start'), - ('cycle-type', 'Cycle type'), - ('direction', 'Direction'), - ('addr', 'Address'), - ('data', 'Data'), - ('commands', 'Commands'), - ('crc', 'CRC'), - ('turn-around', 'TAR'), - ) - annotation_rows = ( - ('data', 'Data', (1, 2, 3, 4, 5, 6, 7, 8,)), - ('warnings', 'Warnings', (0,)), - ) - - def __init__(self): - self.tar_cycles = 3 - self.reset() - - def reset(self): - self.state = 'IDLE' - self.break_start_sample_number = 0 - self.break_counter = 0 - self.samplenum = 0 - self.samplenum_prev = 0 - self.fsi_data_prev = 0 - self.fsi_data_break_prev = 0 - self.crc_internal = 0 - self.response_received = 0 - self.crc_calculating = 0 - self.busy_seq_count = 0 - self.valid_response = 0 - self.prev_address = {} - self.prev_address_valid = {0: False, 1: False, 2: False, 3: False} - self.ss_block = None - self.es_block = None - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putb(self, data): - self.put(self.ss_block, self.es_block, self.out_ann, data) - - def decode(self): - while True: - # FSI is clocked out on the falling edge and latched in on the rising edge of the clock...according to the specification. - # That said, the specification is not clear on what this actually means (and it doesn't follow industry convention). - # Real IBM POWER9 hardware is verified to work in the following mode: - # FSI data being sent to the master is latched by the master logic at the falling edge of the FSI clock - # FSI data being from to the master is strobed by the master logic at the falling edge of the FSI clock - # FSI data being sent to the slave is latched by the slave logic at the rising edge of the FSI clock - # FSI data being from to the slave is strobed by the slave logic at the rising edge of the FSI clock - # - # The above means that we have to be able to make a reasonable guess as to who is transmitting (the master or the slave) - # in order to know which edge to sample on - - # Wait for either clock edge - (data, clk) = self.wait({1: 'e'}) - - # FSI data is electrically inverted - fsi_data = not data - fsi_clk = clk - current_sample_number = self.samplenum - - # Detect BREAK commands - # Note these can only be sent by the master, so sample on the rising clock edge only - if (fsi_clk): - if (self.fsi_data_break_prev == 1): - self.break_counter = self.break_counter + 1 - if (self.break_counter == 256): - self.ss_block = self.break_start_sample_number - self.es_block = current_sample_number - self.putb([6, ['BREAK']]) - self.state = 'BREAK_TAR_QUEUED' - self.busy_seq_count = 0 - self.valid_response = 0 - self.prev_address = {} - self.prev_address_valid = {0: False, 1: False, 2: False, 3: False} - self.ss_block = current_sample_number - else: - if (self.break_counter > 256): - self.es_block = current_sample_number - self.putb([0, ['BREAK asserted in excess of specification cycles']]) - self.break_start_sample_number = current_sample_number - self.break_counter = 0 - self.fsi_data_break_prev = fsi_data - - if ((self.state == 'TAR') or (self.state == 'RX_SLAVE_ID') or (self.state == 'RESPONSE') or (self.state == 'RX_DATA') - or (self.state == 'RX_IPOLL_INTERRUPT_FIELD') or (self.state == 'RX_IPOLL_DMA_CONTROL_FIELD') or (self.state == 'RX_IPOLL_DMA_CONTROL_FIELD') - or ((self.state == 'CRC') and (self.valid_response))): - # Slave is / should be transmitting, sample on falling clock edge only - if (fsi_clk): - continue - else: - # Master is / should be transmitting, sample on rising clock edge only - if (not fsi_clk): - continue - - # Transfer state machine - if (self.state == 'IDLE'): - self.crc_internal = 0 - self.response_received = 0 - if (self.fsi_data_prev == 1): - self.tx_slave_id = 0 - self.data_count = 2 - self.ss_block = self.samplenum_prev - self.es_block = current_sample_number - self.putb([1, ['START']]) - self.ss_block = current_sample_number - self.crc_calculating = 1 - self.state = 'TX_SLAVE_ID' - - elif (self.state == 'TX_SLAVE_ID'): - self.crc_calculating = 1 - if (self.data_count > 0): - self.tx_slave_id = (self.tx_slave_id >> 1) | (self.fsi_data_prev << 1) - self.data_count = self.data_count - 1 - if (self.data_count == 0): - self.es_block = current_sample_number - self.putb([5, ['Slave ID: 0x%01x' % self.tx_slave_id]]) - self.ss_block = current_sample_number - self.command_count = 0 - self.command_code = 0 - self.command = None - self.valid_command = False - self.state = 'COMMAND' - - elif (self.state == 'COMMAND'): - self.crc_calculating = 1 - self.command_code = (self.command_code << 1) | self.fsi_data_prev - self.command_count = self.command_count + 1 - if ((self.command_count == 3) and (self.command_code == 0b100)): - self.command = 'ABS_ADR' - self.valid_command = True - elif ((self.command_count == 3) and (self.command_code == 0b101)): - self.command = 'REL_ADR' - self.valid_command = True - elif ((self.command_count == 2) and (self.command_code == 0b11)): - self.command = 'SAME_ADR' - self.valid_command = True - elif ((self.command_count == 3) and (self.command_code == 0b010)): - self.command = 'D_POLL' - self.valid_command = True - elif ((self.command_count == 3) and (self.command_code == 0b011)): - self.command = 'E_POLL' - self.valid_command = True - elif ((self.command_count == 3) and (self.command_code == 0b001)): - self.command = 'I_POLL' - self.valid_command = True - if ((self.command_count > 7) or (self.valid_command == True)): - if (self.command_count == 8): - self.es_block = current_sample_number - self.putb([6, ['Invalid command code: 0x%02x/%d' % (self.command_code, self.command_count)]]) - self.putb([0, ['%s' % 'Invalid command code']]) - self.ss_block = current_sample_number - self.state = 'IDLE' - else: - self.es_block = current_sample_number - self.putb([6, ['Command: %s (0x%02x/%d)' % (self.command, self.command_code, self.command_count)]]) - self.ss_block = current_sample_number - if (self.command == 'ABS_ADR'): - self.address_length = 21 - self.address_count = 0 - self.address = 0 - self.state = 'DIRECTION' - elif (self.command == 'REL_ADR'): - self.address_length = 8 - self.address_count = 0 - self.address = 0 - self.state = 'DIRECTION' - elif (self.command == 'SAME_ADR'): - self.address_length = 2 - self.address_count = 0 - self.address = 0 - self.state = 'DIRECTION' - elif (self.command == 'D_POLL'): - self.crc = 0 - self.crc_count = 0 - self.state = 'CRC' - elif (self.command == 'E_POLL'): - self.crc = 0 - self.crc_count = 0 - self.state = 'CRC' - elif (self.command == 'I_POLL'): - self.crc = 0 - self.crc_count = 0 - self.state = 'CRC' - else: - self.state = 'IDLE' - - elif (self.state == 'DIRECTION'): - self.crc_calculating = 1 - self.direction = self.fsi_data_prev - self.es_block = current_sample_number - if (self.direction == 1): - self.putb([3, ['Direction: %s' % 'Read']]) - else: - self.putb([3, ['Direction: %s' % 'Write']]) - self.ss_block = current_sample_number - if (self.command == 'REL_ADR'): - self.state = 'REL_ADDRESS_SIGN' - else: - self.state = 'ADDRESS' - - elif (self.state == 'REL_ADDRESS_SIGN'): - self.crc_calculating = 1 - self.relative_address_negative = self.fsi_data_prev - self.es_block = current_sample_number - if (self.relative_address_negative == 1): - self.putb([5, ['Relative address sign: %s' % '(-)']]) - else: - self.putb([5, ['Relative address sign: %s' % '(+)']]) - self.ss_block = current_sample_number - self.state = 'ADDRESS' - - elif (self.state == 'ADDRESS'): - self.crc_calculating = 1 - self.address = (self.address << 1) | self.fsi_data_prev - self.address_count = self.address_count + 1 - if (self.address_count >= self.address_length): - self.address_raw = self.address - if (self.prev_address_valid[self.tx_slave_id]): - if (self.command == 'SAME_ADR'): - self.address = (self.prev_address[self.tx_slave_id] & ~0b11) | (self.address_raw & 0b11) - elif (self.command == 'REL_ADR'): - if (self.relative_address_negative): - self.address = self.prev_address[self.tx_slave_id] - (0x100 - self.address_raw) - else: - self.address = self.prev_address[self.tx_slave_id] + self.address_raw - self.es_block = current_sample_number - if (((self.command == 'SAME_ADR') or (self.command == 'REL_ADR'))): - self.putb([5, ['Address: 0x%06x (0x%03x)' % (self.address, self.address_raw)]]) - if (not self.prev_address_valid[self.tx_slave_id]): - self.putb([0, ['%s' % 'Base address for relative address not captured']]) - else: - self.putb([5, ['Address: 0x%06x' % self.address]]) - self.ss_block = current_sample_number - self.state = 'DATA_SIZE' - - elif (self.state == 'DATA_SIZE'): - self.crc_calculating = 1 - if (self.direction and ((self.address_raw & 3) == 3) and self.fsi_data_prev): - # OpenFSI suffers from an unfortunate conflict between the SAME_ADR command - # and the TERM command. Both start with 2'b11 and since both are variable - # length it is impossible to determine if a TERM command was sent until this - # point in the receiver process! - # - # Set correct command code for further processing - self.command_code = 0b111111 - self.command_count = 6 - self.command = 'TERM' - self.es_block = current_sample_number - self.putb([6, ['Command: %s (0x%02x/%d)' % (self.command, self.command_code, self.command_count)]]) - self.ss_block = current_sample_number - self.direction = 0 - self.busy_seq_count = 0 - self.crc = 0 - self.crc_count = 0 - self.state = 'CRC' - else: - if (self.fsi_data_prev == 0): - self.data_size = 'BYTE' - else: - if ((self.address_raw & 3) == 1): - self.data_size = 'WORD' - # Force lowest address bits to specification-mandated values if required - self.address = (self.address & ~3) | 1 - elif ((self.address_raw & 1) == 0): - self.data_size = 'HALF_WORD' - # Force lowest address bits to specification-mandated values if required - self.address = self.address & ~1 - else: - self.data_size = 'UNKNOWN' - self.es_block = current_sample_number - if (self.data_size == 'UNKNOWN'): - self.putb([0, ['Data Size: %s' % 'UNKNOWN']]) - self.state = 'IDLE' - else: - self.putb([3, ['Data Size: %s' % self.data_size]]) - if (self.direction == 1): - self.crc = 0 - self.crc_count = 0 - self.state = 'CRC' - else: - self.data = 0 - self.data_count = 0 - if (self.data_size == 'BYTE'): - self.data_length = 8 - elif (self.data_size == 'HALF_WORD'): - self.data_length = 16 - elif (self.data_size == 'WORD'): - self.data_length = 32 - else: - self.data_size = None - self.state = 'TX_DATA' - self.ss_block = current_sample_number - - elif (self.state == 'TX_DATA'): - self.crc_calculating = 1 - self.data = (self.data << 1) | self.fsi_data_prev - self.data_count = self.data_count + 1 - if (self.data_count >= self.data_length): - self.es_block = current_sample_number - if (self.data_size == 'BYTE'): - self.putb([5, ['Data: 0x%02x' % self.data]]) - elif (self.data_size == 'HALF_WORD'): - self.putb([5, ['Data: 0x%04x' % self.data]]) - else: - self.putb([5, ['Data: 0x%08x' % self.data]]) - self.ss_block = current_sample_number - self.crc = 0 - self.crc_count = 0 - self.state = 'CRC' - - elif (self.state == 'CRC'): - if (self.crc_count == 0): - self.computed_crc_tx_end = self.crc_internal - self.crc_calculating = 1 - self.crc = (self.crc << 1) | self.fsi_data_prev - self.crc_count = self.crc_count + 1 - if (self.crc_count >= 4): - self.es_block = current_sample_number - if (self.crc == self.computed_crc_tx_end): - self.putb([7, ['CRC: 0x%01x (GOOD)' % self.crc]]) - if (self.response_received): - if (((self.command == 'ABS_ADR') or (self.command == 'REL_ADR') or (self.command == 'SAME_ADR')) - and ((self.response == 'ACK_D') or (self.response == 'ACK'))): - self.prev_address[self.tx_slave_id] = self.address - self.prev_address_valid[self.tx_slave_id] = True - else: - self.putb([7, ['CRC: 0x%01x (BAD)' % self.crc]]) - self.putb([0, ['%s' % 'Bad CRC']]) - self.ss_block = current_sample_number - self.tar_timer = 0 - self.state = 'TAR' - self.timeout_counter = 0 - - elif (self.state == 'BREAK_TAR_QUEUED'): - # Special case, since break operates outside of the main state machine - # This state is a safe entry point into the main state machine - self.tar_timer = 0 - self.state = 'BREAK_TAR' - - elif (self.state == 'BREAK_TAR'): - self.tar_timer = self.tar_timer + 1 - if (self.tar_timer > self.tar_cycles): - self.crc_calculating = 0 - self.crc_internal = 0 - self.es_block = current_sample_number - self.putb([8, ['%s' % 'TAR']]) - self.ss_block = current_sample_number - self.state = 'IDLE' - - elif (self.state == 'TAR'): - self.crc_calculating = 0 - self.crc_internal = 0 - self.tar_timer = self.tar_timer + 1 - if (self.tar_timer > self.tar_cycles): - if (self.response_received == 1): - self.response_received = 0 - if (self.rx_slave_id == self.tx_slave_id): - if (self.response == 'BUSY'): - self.busy_seq_count = self.busy_seq_count + 1 - else: - self.busy_seq_count = 0 - # Sequence complete - self.state = 'IDLE' - if (self.timeout_counter == 0): - self.es_block = self.samplenum_prev - self.putb([8, ['%s' % 'TAR']]) - self.ss_block = current_sample_number - if (self.fsi_data_prev == 1): - self.crc_calculating = 1 - self.rx_slave_id = 0 - self.data_count = 2 - if (self.state == 'IDLE'): - # Already processed response message, was going to IDLE state - self.state = 'TX_SLAVE_ID' - else: - self.state = 'RX_SLAVE_ID' - self.ss_block = self.samplenum_prev - self.es_block = current_sample_number - self.putb([1, ['START']]) - self.ss_block = current_sample_number - else: - self.timeout_counter = self.timeout_counter + 1 - if (self.timeout_counter >= 256): - self.es_block = current_sample_number - self.putb([8, ['%s' % 'Response timeout']]) - self.putb([0, ['%s' % 'Response timeout']]) - self.state = 'IDLE' - - elif (self.state == 'RX_SLAVE_ID'): - self.crc_calculating = 1 - self.response_received = 1 - if (self.data_count > 0): - self.rx_slave_id = (self.rx_slave_id >> 1) | (self.fsi_data_prev << 1) - self.data_count = self.data_count - 1 - if (self.data_count == 0): - self.es_block = current_sample_number - self.putb([5, ['Slave ID: 0x%01x' % self.rx_slave_id]]) - if (self.rx_slave_id != self.tx_slave_id): - self.putb([0, ['%s' % 'Slave ID does not match active transaction']]) - self.ss_block = current_sample_number - self.response_count = 0 - self.response_code = 0 - self.response = None - self.valid_response = False - self.state = 'RESPONSE' - - elif (self.state == 'RESPONSE'): - self.crc_calculating = 1 - self.response_code = (self.response_code << 1) | self.fsi_data_prev - self.response_count = self.response_count + 1 - if ((self.command == 'I_POLL') and (self.rx_slave_id == self.tx_slave_id) and (self.response_count == 1) and (self.response_code == 0b0)): - self.response = 'I_POLL_RSP' - self.valid_response = True - elif ((self.response_count == 2) and (self.response_code == 0b00)): - if (self.direction == 1): - self.response = 'ACK_D' - else: - self.response = 'ACK' - self.valid_response = True - elif ((self.response_count == 2) and (self.response_code == 0b01)): - self.response = 'BUSY' - self.valid_response = True - elif ((self.response_count == 2) and (self.response_code == 0b10)): - self.response = 'ERR_A' - self.valid_response = True - elif ((self.response_count == 2) and (self.response_code == 0b11)): - self.response = 'ERR_C' - self.valid_response = True - if ((self.response_count > 2) or (self.valid_response == True)): - if (self.response_count == 8): - self.es_block = current_sample_number - self.putb([6, ['Invalid response code: 0x%02x/%d' % (self.response_code, self.response_count)]]) - self.putb([0, ['%s' % 'Invalid response code']]) - self.ss_block = current_sample_number - self.state = 'IDLE' - else: - self.es_block = current_sample_number - self.putb([6, ['Response: %s (0x%02x/%d)' % (self.response, self.response_code, self.response_count)]]) - self.ss_block = current_sample_number - if (self.response == 'ACK_D'): - self.data = 0 - self.data_count = 0 - if (self.data_size == 'BYTE'): - self.data_length = 8 - elif (self.data_size == 'HALF_WORD'): - self.data_length = 16 - elif (self.data_size == 'WORD'): - self.data_length = 32 - else: - self.data_size = None - #self.state = 'DIRECTION' - self.state = 'RX_DATA' - elif (self.response == 'ACK'): - self.crc = 0 - self.crc_count = 0 - self.state = 'CRC' - elif (self.response == 'BUSY'): - self.crc = 0 - self.crc_count = 0 - self.state = 'CRC' - elif (self.response == 'ERR_A'): - self.crc = 0 - self.crc_count = 0 - self.state = 'CRC' - elif (self.response == 'ERR_C'): - self.crc = 0 - self.crc_count = 0 - self.state = 'CRC' - elif (self.response == 'I_POLL_RSP'): - self.data = 0 - self.data_count = 0 - self.data_length = 2 - self.state = 'RX_IPOLL_INTERRUPT_FIELD' - else: - self.state = 'IDLE' - - elif (self.state == 'RX_DATA'): - self.crc_calculating = 1 - self.data = (self.data << 1) | self.fsi_data_prev - self.data_count = self.data_count + 1 - if (self.data_count >= self.data_length): - self.es_block = current_sample_number - self.putb([5, ['Data: 0x%08x' % self.data]]) - self.ss_block = current_sample_number - self.crc = 0 - self.crc_count = 0 - self.state = 'CRC' - - elif (self.state == 'RX_IPOLL_INTERRUPT_FIELD'): - self.crc_calculating = 1 - self.data = (self.data << 1) | self.fsi_data_prev - self.data_count = self.data_count + 1 - if (self.data_count >= self.data_length): - self.es_block = current_sample_number - self.putb([5, ['Interrupt Field: 0x%01x' % self.data]]) - self.ss_block = current_sample_number - self.data = 0 - self.data_count = 0 - self.data_length = 3 - self.state = 'RX_IPOLL_DMA_CONTROL_FIELD' - - elif (self.state == 'RX_IPOLL_DMA_CONTROL_FIELD'): - self.crc_calculating = 1 - self.data = (self.data << 1) | self.fsi_data_prev - self.data_count = self.data_count + 1 - if (self.data_count >= self.data_length): - self.es_block = current_sample_number - self.putb([5, ['DMA Control Field: 0x%01x' % self.data]]) - self.ss_block = current_sample_number - self.crc = 0 - self.crc_count = 0 - self.state = 'CRC' - - # CRC calculation - # Implement Galios-type LFSR for polynomial 0x7 (MSB first) - crc_prev = self.crc_internal - if (self.crc_calculating): - crc_feedback = (((crc_prev >> 3) & 1) ^ self.fsi_data_prev) & 1 - if (self.crc_calculating): - self.crc_internal = (self.crc_internal & ~(1 << 0)) | ((crc_feedback & 1) << 0) - self.crc_internal = (self.crc_internal & ~(1 << 1)) | ((((crc_prev & 1) ^ crc_feedback) & 1) << 1) - self.crc_internal = (self.crc_internal & ~(1 << 2)) | (((((crc_prev >> 1) & 1) ^ crc_feedback) & 1) << 2) - self.crc_internal = (self.crc_internal & ~(1 << 3)) | ((((crc_prev >> 2) & 1) & 1) << 3) - - self.fsi_data_prev = fsi_data - self.samplenum_prev = current_sample_number diff --git a/decoders/gpib/__init__.py b/decoders/gpib/__init__.py deleted file mode 100755 index 3b546ef1..00000000 --- a/decoders/gpib/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2016 Rudolf Reuter -## -## 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, see . -## - -''' -This protocol decoder can decode the GPIB (IEEE-488) protocol. -''' - -from .pd import Decoder diff --git a/decoders/gpib/pd.py b/decoders/gpib/pd.py deleted file mode 100755 index f0c963c2..00000000 --- a/decoders/gpib/pd.py +++ /dev/null @@ -1,182 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2016 Rudolf Reuter -## Copyright (C) 2019 DreamSourceLab -## -## 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, see . -## - -import sigrokdecode as srd - -class Decoder(srd.Decoder): - api_version = 3 - id = 'gpib' - name = 'GPIB' - longname = 'General Purpose Interface Bus' - desc = 'IEEE-488 General Purpose Interface Bus (GPIB / HPIB).' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['PC'] - channels = ( - {'id': 'dio1' , 'name': 'DIO1', 'desc': 'Data I/O bit 1'}, - {'id': 'dio2' , 'name': 'DIO2', 'desc': 'Data I/O bit 2'}, - {'id': 'dio3' , 'name': 'DIO3', 'desc': 'Data I/O bit 3'}, - {'id': 'dio4' , 'name': 'DIO4', 'desc': 'Data I/O bit 4'}, - {'id': 'dio5' , 'name': 'DIO5', 'desc': 'Data I/O bit 5'}, - {'id': 'dio6' , 'name': 'DIO6', 'desc': 'Data I/O bit 6'}, - {'id': 'dio7' , 'name': 'DIO7', 'desc': 'Data I/O bit 7'}, - {'id': 'dio8' , 'name': 'DIO8', 'desc': 'Data I/O bit 8'}, - {'id': 'eoi', 'name': 'EOI', 'desc': 'End or identify'}, - {'id': 'dav', 'name': 'DAV', 'desc': 'Data valid'}, - {'id': 'nrfd', 'name': 'NRFD', 'desc': 'Not ready for data'}, - {'id': 'ndac', 'name': 'NDAC', 'desc': 'Not data accepted'}, - {'id': 'ifc', 'name': 'IFC', 'desc': 'Interface clear'}, - {'id': 'srq', 'name': 'SRQ', 'desc': 'Service request'}, - {'id': 'atn', 'name': 'ATN', 'desc': 'Attention'}, - {'id': 'ren', 'name': 'REN', 'desc': 'Remote enable'}, - ) - options = ( - {'id': 'sample_total', 'desc': 'Total number of samples', 'default': 0}, - ) - annotations = ( - ('items', 'Items'), - ('gpib', 'DAT/CMD'), - ('eoi', 'EOI'), - ) - annotation_rows = ( - ('bytes', 'Bytes', (0,)), - ('gpib', 'DAT/CMD', (1,)), - ('eoi', 'EOI', (2,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.items = [] - self.itemcount = 0 - self.saved_item = None - self.saved_ATN = False - self.saved_EOI = False - self.samplenum = 0 - self.ss_item = self.es_item = None - self.first = True - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putb(self, data): - self.put(self.ss_item, self.es_item, self.out_ann, data) - - def handle_bits(self, datapins): - dbyte = 0x20 - dATN = False - item2 = False - dEOI = False - item3 = False - # If this is the first item in a word, save its sample number. - if self.itemcount == 0: - self.ss_word = self.samplenum - - # Get the bits for this item. - item = 0 - for i in range(8): - item |= datapins[i] << i - - item = item ^ 0xff # Invert data byte. - self.items.append(item) - self.itemcount += 1 - - if datapins[14] == 0: - item2 = True - if datapins[8] == 0: - item3 = True - - if self.first: - # Save the start sample and item for later (no output yet). - self.ss_item = self.samplenum - self.first = False - self.saved_item = item - self.saved_ATN = item2 - self.saved_EOI = item3 - else: - # Output the saved item. - dbyte = self.saved_item - dATN = self.saved_ATN - dEOI = self.saved_EOI - self.es_item = self.samplenum - self.putb([0, ['%02X' % self.saved_item]]) - - # Encode item byte to GPIB convention. - self.strgpib = ' ' - if dATN: # ATN, decode commands. - if dbyte == 0x01: self.strgpib = 'GTL' - if dbyte == 0x04: self.strgpib = 'SDC' - if dbyte == 0x05: self.strgpib = 'PPC' - if dbyte == 0x08: self.strgpib = 'GET' - if dbyte == 0x09: self.strgpib = 'TCT' - if dbyte == 0x11: self.strgpib = 'LLO' - if dbyte == 0x14: self.strgpib = 'DCL' - if dbyte == 0x15: self.strgpib = 'PPU' - if dbyte == 0x18: self.strgpib = 'SPE' - if dbyte == 0x19: self.strgpib = 'SPD' - if dbyte == 0x3f: self.strgpib = 'UNL' - if dbyte == 0x5f: self.strgpib = 'UNT' - if dbyte > 0x1f and dbyte < 0x3f: # Address Listener. - self.strgpib = 'L' + chr(dbyte + 0x10) - if dbyte > 0x3f and dbyte < 0x5f: # Address Talker - self.strgpib = 'T' + chr(dbyte - 0x10) - else: - if dbyte > 0x1f and dbyte < 0x7f: - self.strgpib = chr(dbyte) - if dbyte == 0x0a: - self.strgpib = 'LF' - if dbyte == 0x0d: - self.strgpib = 'CR' - - self.putb([1, [self.strgpib]]) - self.strEOI = ' ' - if dEOI: - self.strEOI = 'EOI' - self.putb([2, [self.strEOI]]) - - self.ss_item = self.samplenum - self.saved_item = item - self.saved_ATN = item2 - self.saved_EOI = item3 - - if self.itemcount < 16: - return - - self.itemcount, self.items = 0, [] - - def decode(self): - - # Inspect samples at falling edge of DAV. But make sure to also - # start inspection when the capture happens to start with low - # DAV level. Optionally enforce processing when a user specified - # sample number was reached. - waitcond = [{9: 'l'}] - lsn = self.options['sample_total'] - if lsn: - waitcond.append({'skip': lsn}) - while True: - if lsn: - waitcond[1]['skip'] = lsn - self.samplenum - 1 - (d1, d2, d3, d4, d5, d6, d7, d8, eoi, dav, nrfd, ndac, ifc, srq, atn, ren) = self.wait(waitcond) - pins = (d1, d2, d3, d4, d5, d6, d7, d8, eoi, dav, nrfd, ndac, ifc, srq, atn, ren) - self.handle_bits(pins) - waitcond[0][9] = 'f' diff --git a/decoders/graycode/__init__.py b/decoders/graycode/__init__.py deleted file mode 100755 index 90ef824c..00000000 --- a/decoders/graycode/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2017 Christoph Rackwitz -## -## 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, see . -## - -''' -Gray code and rotary encoder protocol. -''' - -from .pd import Decoder diff --git a/decoders/graycode/pd.py b/decoders/graycode/pd.py deleted file mode 100755 index 9303c33a..00000000 --- a/decoders/graycode/pd.py +++ /dev/null @@ -1,200 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2017 Christoph Rackwitz -## Copyright (C) 2019 DreamSourceLab -## -## 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, see . -## - -import math -import sigrokdecode as srd -from collections import deque -from common.srdhelper import bitpack, bitunpack - -def gray_encode(plain): - return plain & (plain >> 1) - -def gray_decode(gray): - temp = gray - temp ^= (temp >> 8) - temp ^= (temp >> 4) - temp ^= (temp >> 2) - temp ^= (temp >> 1) - return temp - -def prefix_fmt(value, emin=None): - sgn = (value > 0) - (value < 0) - value = abs(value) - p = math.log10(value) if value else 0 - value = sgn * math.floor(value * 10**int(3 - p)) * 10**-int(3 - p) - e = p // 3 * 3 - if emin is not None and e < emin: - e = emin - value *= 10**-e - p -= e - decimals = 2 - int(p) - prefixes = {-9: 'n', -6: 'µ', -3: 'm', 0: '', 3: 'k', 6: 'M', 9: 'G'} - return '{0:.{1}f} {2}'.format(value, decimals, prefixes[e]) - -class ChannelMapError(Exception): - pass - -class Value: - def __init__(self, onchange): - self.onchange = onchange - self.timestamp = None - self.value = None - - def get(self): - return self.value - - def set(self, timestamp, newval): - if newval != self.value: - if self.value is not None: - self.onchange(self.timestamp, self.value, timestamp, newval) - - self.value = newval - self.timestamp = timestamp - elif False: - if self.value is not None: - self.onchange(self.timestamp, self.value, timestamp, newval) - -MAX_CHANNELS = 8 # 10 channels causes some weird problems... - -class Decoder(srd.Decoder): - api_version = 3 - id = 'graycode' - name = 'Gray code' - longname = 'Gray code and rotary encoder' - desc = 'Accumulate rotary encoder increments, provide statistics.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Encoding'] - optional_channels = tuple( - {'id': 'd{}'.format(i), 'name': 'D{}'.format(i), 'desc': 'Data line {}'.format(i)} - for i in range(MAX_CHANNELS) - ) - options = ( - {'id': 'edges', 'desc': 'Edges per rotation', 'default': 0}, - {'id': 'avg_period', 'desc': 'Averaging period', 'default': 10}, - ) - annotations = ( - ('phase', 'Phase'), - ('increment', 'Increment'), - ('count', 'Count'), - ('turns', 'Turns'), - ('interval', 'Interval'), - ('average', 'Average'), - ('rpm', 'Rate'), - ) - annotation_rows = tuple((u, v, (i,)) for i, (u, v) in enumerate(annotations)) - - def __init__(self): - self.reset() - - def reset(self): - self.num_channels = 0 - self.samplerate = None - self.last_n = deque() - - self.phase = Value(self.on_phase) - self.increment = Value(self.on_increment) - self.count = Value(self.on_count) - self.turns = Value(self.on_turns) - - def on_phase(self, told, vold, tnew, vnew): - self.put(told, tnew, self.out_ann, [0, ['{}'.format(vold)]]) - - def on_increment(self, told, vold, tnew, vnew): - if vold == 0: - message = '0' - elif abs(vold) == self.ENCODER_STEPS // 2: - message = '±π' - else: - message = '{:+d}'.format(vold) - self.put(told, tnew, self.out_ann, [1, [message]]) - - def on_count(self, told, vold, tnew, vnew): - self.put(told, tnew, self.out_ann, [2, ['{}'.format(vold)]]) - - def on_turns(self, told, vold, tnew, vnew): - self.put(told, tnew, self.out_ann, [3, ['{:+d}'.format(vold)]]) - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def decode(self): - chmask = [self.has_channel(i) for i in range(MAX_CHANNELS)] - self.num_channels = sum(chmask) - if chmask != [i < self.num_channels for i in range(MAX_CHANNELS)]: - raise ChannelMapError('Assigned channels need to be contiguous') - - self.ENCODER_STEPS = 1 << self.num_channels - - (d0, d1, d2, d3, d4, d5, d6, d7) = self.wait() - startbits = (d0, d1, d2, d3, d4, d5, d6, d7) - curtime = self.samplenum - - self.turns.set(self.samplenum, 0) - self.count.set(self.samplenum, 0) - self.phase.set(self.samplenum, gray_decode(bitpack(startbits[:self.num_channels]))) - - while True: - prevtime = curtime - (d0, d1, d2, d3, d4, d5, d6, d7) = self.wait([{i: 'e'} for i in range(self.num_channels)]) - bits = (d0, d1, d2, d3, d4, d5, d6, d7) - curtime = self.samplenum - - oldcount = self.count.get() - oldphase = self.phase.get() - - newphase = gray_decode(bitpack(bits[:self.num_channels])) - self.phase.set(self.samplenum, newphase) - - phasedelta_raw = (newphase - oldphase + (self.ENCODER_STEPS // 2 - 1)) % self.ENCODER_STEPS - (self.ENCODER_STEPS // 2 - 1) - phasedelta = phasedelta_raw - self.increment.set(self.samplenum, phasedelta) - if abs(phasedelta) == self.ENCODER_STEPS // 2: - phasedelta = 0 - - self.count.set(self.samplenum, self.count.get() + phasedelta) - - if self.options['edges']: - self.turns.set(self.samplenum, self.count.get() // self.options['edges']) - - if self.samplerate: - period = (curtime - prevtime) / self.samplerate - freq = abs(phasedelta_raw) / period - - self.put(prevtime, curtime, self.out_ann, [4, [ - '{}s, {}Hz'.format(prefix_fmt(period), prefix_fmt(freq))]]) - - if self.options['avg_period']: - self.last_n.append((abs(phasedelta_raw), period)) - if len(self.last_n) > self.options['avg_period']: - self.last_n.popleft() - - avg_period = sum(v for u, v in self.last_n) / (sum(u for u, v in self.last_n) or 1) - self.put(prevtime, curtime, self.out_ann, [5, [ - '{}s, {}Hz'.format(prefix_fmt(avg_period), - prefix_fmt(1 / avg_period))]]) - - if self.options['edges']: - self.put(prevtime, curtime, self.out_ann, [6, ['{}rpm'.format(prefix_fmt(60 * freq / self.options['edges'], emin=0))]]) diff --git a/decoders/guess_bitrate/__init__.py b/decoders/guess_bitrate/__init__.py deleted file mode 100755 index a02bf183..00000000 --- a/decoders/guess_bitrate/__init__.py +++ /dev/null @@ -1,40 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2013 Uwe Hermann -## -## 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, see . -## - -''' -This protocol decoder tries to guess the bitrate / baudrate of the -communication on the specified channel. - -Typically this will be used to guess / detect the baudrate used in a UART -communication snippet, but it could also be used to guess bitrates of certain -other protocols or buses. - -It should be noted that this is nothing more than a simple guess / heuristic, -and that there are various cases in practice where the detection of the -bitrate or baudrate will not necessarily have the expected result. - -The precision of the estimated bitrate / baudrate will also depend on the -samplerate used to sample the respective channel. For good results it is -recommended to use a logic analyzer samplerate that is much higher than -the expected bitrate/baudrate that might be used on the channel. - -The last annotation emitted by the decoder will be the best bitrate guess. -''' - -from .pd import Decoder diff --git a/decoders/guess_bitrate/pd.py b/decoders/guess_bitrate/pd.py deleted file mode 100755 index 462fa8aa..00000000 --- a/decoders/guess_bitrate/pd.py +++ /dev/null @@ -1,79 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2013-2016 Uwe Hermann -## -## 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, see . -## - -import sigrokdecode as srd - -class SamplerateError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = 'guess_bitrate' - name = 'Guess bitrate' - longname = 'Guess bitrate/baudrate' - desc = 'Guess the bitrate/baudrate of a UART (or other) protocol.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Clock/timing', 'Util'] - channels = ( - {'id': 'data', 'name': 'Data', 'desc': 'Data line'}, - ) - annotations = ( - ('bitrate', 'Bitrate / baudrate'), - ) - - def putx(self, data): - self.put(self.ss_edge, self.samplenum, self.out_ann, data) - - def __init__(self): - self.reset() - - def reset(self): - self.ss_edge = None - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - - # Get the first edge on the data line. - self.wait({0: 'e'}) - self.ss_edge = self.samplenum - - # Get any subsequent edge on the data line. Get the smallest - # distance between any two transitions, assuming it corresponds - # to one bit time of the respective bitrate of the input stream. - # This heuristics keeps getting better for longer captures. - bitwidth = None - while True: - self.wait({0: 'e'}) - - b = self.samplenum - self.ss_edge - if bitwidth is None or b < bitwidth: - bitwidth = b - bitrate = int(float(self.samplerate) / float(b)) - self.putx([0, ['%d' % bitrate]]) - self.ss_edge = self.samplenum diff --git a/decoders/hdcp/__init__.py b/decoders/hdcp/__init__.py deleted file mode 100644 index f2e10b6a..00000000 --- a/decoders/hdcp/__init__.py +++ /dev/null @@ -1,27 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Dave Craig -## -## 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, see . -## - -''' -This decoder stacks on top of the 'i2c' PD and decodes HDCP messages. - -Details: -https://www.digital-cp.com/sites/default/files/specifications/HDCP%20on%20HDMI%20Specification%20Rev2_2_Final1.pdf -''' - -from .pd import Decoder diff --git a/decoders/hdcp/pd.py b/decoders/hdcp/pd.py deleted file mode 100644 index 157b23a3..00000000 --- a/decoders/hdcp/pd.py +++ /dev/null @@ -1,191 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Dave Craig -## -## 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, see . -## - -import sigrokdecode as srd - -msg_ids = { - 2: 'AKE_Init', - 3: 'AKE_Send_Cert', - 4: 'AKE_No_stored_km', - 5: 'AKE_Stored_km', - - 7: 'AKE_Send_H_prime', - 8: 'AKE_Send_Pairing_Info', - - 9: 'LC_Init', - 10: 'LC_Send_L_prime', - - 11: 'SKE_Send_Eks', - 12: 'RepeaterAuth_Send_ReceiverID_List', - - 15: 'RepeaterAuth_Send_Ack', - 16: 'RepeaterAuth_Stream_Manage', - 17: 'RepeaterAuth_Stream_Ready', -} - -write_items = { - 0x00: '1.4 Bksv - Receiver KSV', - 0x08: '1.4 Ri\' - Link Verification', - 0x0a: '1.4 Pj\' - Enhanced Link Verification', - 0x10: '1.4 Aksv - Transmitter KSV', - 0x15: '1.4 Ainfo - Transmitter KSV', - 0x18: '1.4 An - Session random number', - 0x20: '1.4 V\'H0', - 0x24: '1.4 V\'H1', - 0x28: '1.4 V\'H2', - 0x2c: '1.4 V\'H3', - 0x30: '1.4 V\'H4', - 0x40: '1.4 Bcaps', - 0x41: '1.4 Bstatus', - 0x43: '1.4 KSV FIFO', - 0x50: 'HDCP2Version', - 0x60: 'Write_Message', - 0x70: 'RxStatus', - 0x80: 'Read_Message', -} - -class Decoder(srd.Decoder): - api_version = 3 - id = 'hdcp' - name = 'HDCP' - longname = 'HDCP over HDMI' - desc = 'HDCP protocol over HDMI.' - license = 'gplv2+' - inputs = ['i2c'] - outputs = ['hdcp'] - tags = ['PC', 'Security/crypto'] - annotations = \ - tuple(('message-0x%02X' % i, 'Message 0x%02X' % i) for i in range(18)) + ( - ('summary', 'Summary'), - ('warning', 'Warning'), - ) - annotation_rows = ( - ('messages', 'Messages', tuple(range(18))), - ('summaries', 'Summaries', (18,)), - ('warnings', 'Warnings', (19,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.state = 'IDLE' - self.stack = [] - self.msg = -1 - self.ss = self.es = self.ss_block = self.es_block = 0 - self.init_seq = [] - self.valid = 0 - self.type = '' - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putb(self, data): - self.put(self.ss_block, self.es_block, self.out_ann, data) - - def decode(self, ss, es, data): - cmd, databyte = data - - # Collect the 'BITS' packet, then return. The next packet is - # guaranteed to belong to these bits we just stored. - if cmd == 'BITS': - self.bits = databyte - return - - self.ss, self.es = ss, es - - # State machine. - if self.state == 'IDLE': - # Wait for an I2C START condition. - if cmd == 'START': - self.reset() - self.ss_block = ss - elif cmd != 'START REPEAT': - return - self.state = 'GET SLAVE ADDR' - elif self.state == 'GET SLAVE ADDR': - if cmd == 'ADDRESS READ': - self.state = 'BUFFER DATA' - if databyte != 0x3a: - self.state = 'IDLE' - elif cmd == 'ADDRESS WRITE': - self.state = 'WRITE OFFSET' - if databyte != 0x3a: - self.state = 'IDLE' - elif self.state == 'WRITE OFFSET': - if cmd == 'DATA WRITE': - if databyte in write_items: - self.type = write_items[databyte] - if databyte in (0x10, 0x15, 0x18, 0x60): - self.state = 'BUFFER DATA' - # If we are reading, then jump back to IDLE for a start repeat. - # If we are writing, then just continue onwards. - if self.state == 'BUFFER DATA': - pass - elif self.type != '': - self.state = 'IDLE' - elif self.state == 'BUFFER DATA': - if cmd in ('STOP', 'NACK'): - self.es_block = es - self.state = 'IDLE' - if self.type == '': - return - if not self.stack: - self.putb([18, ['%s' % (self.type)]]) - return - if self.type == 'RxStatus': - rxstatus = (self.stack.pop() << 8) | self.stack.pop() - reauth_req = (rxstatus & 0x800) != 0 - ready = (rxstatus & 0x400) != 0 - length = rxstatus & 0x3ff - text = '%s, reauth %s, ready %s, length %s' % \ - (self.type, reauth_req, ready, length) - self.putb([18, [text]]) - elif self.type == '1.4 Bstatus': - bstatus = (self.stack.pop() << 8) | self.stack.pop() - device_count = bstatus & 0x7f - max_devs_exceeded = (bstatus & 0x80) != 0 - depth = ((bstatus & 0x700) >> 8) - max_cascase_exceeded = bstatus & 0x800 - hdmi_mode = (bstatus & 0x1000) != 0 - text = '%s, %s devices, depth %s, hdmi mode %s' % \ - (self.type, device_count, depth, hdmi_mode) - self.putb([18, [text]]) - elif self.type == 'Read_Message': - msg = self.stack.pop(0) - self.putb([msg, ['%s, %s' % (self.type, - msg_ids.get(msg, 'Invalid'))]]) - elif self.type == 'Write_Message': - msg = self.stack.pop(0) - self.putb([msg, ['%s, %s' % (self.type, - msg_ids.get(msg, 'Invalid'))]]) - elif self.type == 'HDCP2Version': - version = self.stack.pop(0) - if (version & 0x4): - self.putb([18, ['HDCP2']]) - else: - self.putb([18, ['NOT HDCP2']]) - else: - self.putb([18, ['%s' % (self.type)]]) - elif cmd == 'DATA READ': - # Stack up our data bytes. - self.stack.append(databyte) - elif cmd == 'DATA WRITE': - # Stack up our data bytes. - self.stack.append(databyte) diff --git a/decoders/i2cdemux/__init__.py b/decoders/i2cdemux/__init__.py deleted file mode 100755 index e3e9a913..00000000 --- a/decoders/i2cdemux/__init__.py +++ /dev/null @@ -1,27 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -''' -This is a generic I²C demultiplexing protocol decoder. - -It takes an I²C stream as input and outputs multiple I²C streams, each -stream containing only I²C packets for one specific I²C slave. -''' - -from .pd import Decoder diff --git a/decoders/i2cdemux/pd.py b/decoders/i2cdemux/pd.py deleted file mode 100755 index d6841d32..00000000 --- a/decoders/i2cdemux/pd.py +++ /dev/null @@ -1,80 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -import sigrokdecode as srd - -class Decoder(srd.Decoder): - api_version = 3 - id = 'i2cdemux' - name = 'I²C demux' - longname = 'I²C demultiplexer' - desc = 'Demux I²C packets into per-slave-address streams.' - license = 'gplv2+' - inputs = ['i2c'] - outputs = [] # TODO: Only known at run-time. - tags = ['Util'] - - def __init__(self): - self.reset() - - def reset(self): - self.packets = [] # Local cache of I²C packets - self.slaves = [] # List of known slave addresses - self.stream = -1 # Current output stream - self.streamcount = 0 # Number of created output streams - - def start(self): - self.out_python = [] - - # Grab I²C packets into a local cache, until an I²C STOP condition - # packet comes along. At some point before that STOP condition, there - # will have been an ADDRESS READ or ADDRESS WRITE which contains the - # I²C address of the slave that the master wants to talk to. - # We use this slave address to figure out which output stream should - # get the whole chunk of packets (from START to STOP). - def decode(self, ss, es, data): - - cmd, databyte = data - - # Add the I²C packet to our local cache. - self.packets.append([ss, es, data]) - - if cmd in ('ADDRESS READ', 'ADDRESS WRITE'): - if databyte in self.slaves: - self.stream = self.slaves.index(databyte) - return - - # We're never seen this slave, add a new stream. - self.slaves.append(databyte) - self.out_python.append(self.register(srd.OUTPUT_PYTHON, - proto_id='i2c-%s' % hex(databyte))) - self.stream = self.streamcount - self.streamcount += 1 - elif cmd == 'STOP': - if self.stream == -1: - raise Exception('Invalid stream!') # FIXME? - - # Send the whole chunk of I²C packets to the correct stream. - for p in self.packets: - self.put(p[0], p[1], self.out_python[self.stream], p[2]) - - self.packets = [] - self.stream = -1 - else: - pass # Do nothing, only add the I²C packet to our cache. diff --git a/decoders/i2cfilter/__init__.py b/decoders/i2cfilter/__init__.py deleted file mode 100755 index be97bf0a..00000000 --- a/decoders/i2cfilter/__init__.py +++ /dev/null @@ -1,37 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Bert Vermeulen -## -## 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 . -## - -''' -This is a generic I²C filtering protocol decoder. - -It takes input from the I²C protocol decoder and removes all traffic -except that from/to the specified slave address and/or direction. - -It then outputs the filtered data again as OUTPUT_PROTO of type/format 'i2c' -(up the protocol decoder stack). No annotations are output. - -The I²C slave address to filter out should be passed in as an option -'address', as an integer. A specific read or write operation can be selected -with the 'direction' option, which should be 'read', 'write', or 'both'. - -Both of these are optional; if no options are specified the entire payload -of the I²C session will be output. -''' - -from .pd import Decoder diff --git a/decoders/i2cfilter/pd.py b/decoders/i2cfilter/pd.py deleted file mode 100755 index 7798e17a..00000000 --- a/decoders/i2cfilter/pd.py +++ /dev/null @@ -1,93 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Bert Vermeulen -## Copyright (C) 2012 Uwe Hermann -## -## 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 . -## - -# TODO: Support for filtering out multiple slave/direction pairs? - -import sigrokdecode as srd - -class Decoder(srd.Decoder): - api_version = 3 - id = 'i2cfilter' - name = 'I²C filter' - longname = 'I²C filter' - desc = 'Filter out addresses/directions in an I²C stream.' - license = 'gplv3+' - inputs = ['i2c'] - outputs = ['i2c'] - tags = ['Util'] - options = ( - {'id': 'address', 'desc': 'Address to filter out of the I²C stream', - 'default': 0}, - {'id': 'direction', 'desc': 'Direction to filter', 'default': 'both', - 'values': ('read', 'write', 'both')} - ) - - def __init__(self): - self.reset() - - def reset(self): - self.curslave = -1 - self.curdirection = None - self.packets = [] # Local cache of I²C packets - - def start(self): - self.out_python = self.register(srd.OUTPUT_PYTHON, proto_id='i2c') - if self.options['address'] not in range(0, 127 + 1): - raise Exception('Invalid slave (must be 0..127).') - - # Grab I²C packets into a local cache, until an I²C STOP condition - # packet comes along. At some point before that STOP condition, there - # will have been an ADDRESS READ or ADDRESS WRITE which contains the - # I²C address of the slave that the master wants to talk to. - # If that slave shall be filtered, output the cache (all packets from - # START to STOP) as proto 'i2c', otherwise drop it. - def decode(self, ss, es, data): - - cmd, databyte = data - - # Add the I²C packet to our local cache. - self.packets.append([ss, es, data]) - - if cmd in ('ADDRESS READ', 'ADDRESS WRITE'): - self.curslave = databyte - self.curdirection = cmd[8:].lower() - elif cmd in ('STOP', 'START REPEAT'): - # If this chunk was not for the correct slave, drop it. - if self.options['address'] == 0: - pass - elif self.curslave != self.options['address']: - self.packets = [] - return - - # If this chunk was not in the right direction, drop it. - if self.options['direction'] == 'both': - pass - elif self.options['direction'] != self.curdirection: - self.packets = [] - return - - # TODO: START->STOP chunks with both read and write (Repeat START) - # Otherwise, send out the whole chunk of I²C packets. - for p in self.packets: - self.put(p[0], p[1], self.out_python, p[2]) - - self.packets = [] - else: - pass # Do nothing, only add the I²C packet to our cache. diff --git a/decoders/i2s/__init__.py b/decoders/i2s/__init__.py deleted file mode 100755 index a0b7097f..00000000 --- a/decoders/i2s/__init__.py +++ /dev/null @@ -1,29 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Joel Holdsworth -## -## 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, see . -## - -''' -I²S (Integrated Interchip Sound) is a serial bus for connecting digital -audio devices (usually on the same device/board). - -Details: -http://www.nxp.com/acrobat_download/various/I2SBUS.pdf -http://en.wikipedia.org/wiki/I2s -''' - -from .pd import Decoder diff --git a/decoders/i2s/pd.py b/decoders/i2s/pd.py deleted file mode 100755 index 7e4959ec..00000000 --- a/decoders/i2s/pd.py +++ /dev/null @@ -1,214 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Joel Holdsworth -## Copyright (C) 2019 DreamSourceLab -## -## 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, see . -## - -import sigrokdecode as srd -import struct - -''' -OUTPUT_PYTHON format: - -Packet: -[, ] - -, : - - 'DATA', [, ] - -: 'L' or 'R' -: integer -''' - -class Decoder(srd.Decoder): - api_version = 3 - id = 'i2s' - name = 'I²S' - longname = 'Integrated Interchip Sound' - desc = 'Serial bus for connecting digital audio devices.' - license = 'gplv2+' - inputs = ['logic'] - outputs = ['i2s'] - tags = ['Audio', 'PC'] - channels = ( - {'id': 'sck', 'name': 'SCK', 'desc': 'Bit clock line'}, - {'id': 'ws', 'name': 'WS', 'desc': 'Word select line'}, - {'id': 'sd', 'name': 'SD', 'desc': 'Serial data line'}, - ) - options = ( - {'id': 'ws_polarity', 'desc': 'WS polarity', 'default': 'left-high', - 'values': ('left-low', 'left-high')}, - {'id': 'clk_edge', 'desc': 'SCK active edge', 'default': 'rising-edge', - 'values': ('rising-edge', 'falling-edge')}, - {'id': 'bit_shift', 'desc': 'Bit shift', 'default': 'none', - 'values': ('right-shifted by one', 'none')}, - {'id': 'bit_align', 'desc': 'Bit align', 'default': 'left-aligned', - 'values': ('left-aligned', 'right-aligned')}, - {'id': 'bitorder', 'desc': 'Bit order', - 'default': 'msb-first', 'values': ('msb-first', 'lsb-first')}, - {'id': 'wordsize', 'desc': 'Word size', 'default': 16, - 'values': tuple(range(4,129,1))}, - ) - annotations = ( - ('left', 'Left channel'), - ('right', 'Right channel'), - ('warnings', 'Warnings'), - ) - binary = ( - ('wav', 'WAV file'), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.oldws = 1 - self.bitcount = 0 - self.data = 0 - self.samplesreceived = 0 - self.first_sample = None - self.ss_block = None - self.wordlength = -1 - self.wrote_wav_header = False - - def start(self): - self.out_python = self.register(srd.OUTPUT_PYTHON) - self.out_binary = self.register(srd.OUTPUT_BINARY) - self.out_ann = self.register(srd.OUTPUT_ANN) - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def putpb(self, data): - self.put(self.ss_block, self.samplenum, self.out_python, data) - - def putbin(self, data): - self.put(self.ss_block, self.samplenum, self.out_binary, data) - - def putb(self, data): - self.put(self.ss_block, self.samplenum, self.out_ann, data) - - def report(self): - # Calculate the sample rate. - samplerate = '?' - if self.ss_block is not None and \ - self.first_sample is not None and \ - self.ss_block > self.first_sample and \ - self.samplerate: - samplerate = '%d' % (self.samplesreceived * - self.samplerate / (self.ss_block - - self.first_sample)) - - return 'I²S: %d %d-bit samples received at %sHz' % \ - (self.samplesreceived, self.wordlength, samplerate) - - def wav_header(self): - # Chunk descriptor - h = b'RIFF' - h += b'\x24\x80\x00\x00' # Chunk size (2084) - h += b'WAVE' - # Fmt subchunk - h += b'fmt ' - h += b'\x10\x00\x00\x00' # Subchunk size (16 bytes) - h += b'\x01\x00' # Audio format (0x0001 == PCM) - h += b'\x02\x00' # Number of channels (2) - h += b'\x80\x3e\x00\x00' # Samplerate (16000) - h += b'\x00\xfa\x00\x00' # Byterate (64000) - h += b'\x04\x00' # Blockalign (4) - h += b'\x20\x00' # Bits per sample (32) - # Data subchunk - h += b'data' - h += b'\xff\xff\xff\xff' # Subchunk size (4G bytes) TODO - return h - - def wav_sample(self, sample): - return struct.pack(' self.bitcount: - self.putb([2, ['Received %d-bit word, expected %d-bit ' - 'word' % (self.bitcount, self.wordlength)]]) - else: - if (left_algined and msb) or (not left_algined and not msb): - self.data >>= self.bitcount - self.wordlength - else: - self.data &= int("1"*self.wordlength, 2) - self.oldws = self.oldws if left_high else not self.oldws - idx = 0 if self.oldws else 1 - c1 = 'Left channel' if self.oldws else 'Right channel' - c2 = 'Left' if self.oldws else 'Right' - c3 = 'L' if self.oldws else 'R' - v = '%08x' % self.data - self.putpb(['DATA', [c3, self.data]]) - self.putb([idx, ['%s: %s' % (c1, v), '%s: %s' % (c2, v), - '%s: %s' % (c3, v), c3]]) - self.putbin([0, self.wav_sample(self.data)]) - - - # Reset decoder state. - self.data = 0 if right_shifted else self.last - self.bitcount = 0 if right_shifted else 1 - self.ss_block = self.samplenum - - # Save the first sample position. - if self.first_sample is None: - self.first_sample = self.samplenum - - self.oldws = ws diff --git a/decoders/iec/__init__.py b/decoders/iec/__init__.py deleted file mode 100755 index fa0d96f3..00000000 --- a/decoders/iec/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2017 Marcus Comstedt -## -## 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, see . -## - -''' -This protocol decoder can decode the Commodore serial IEEE-488 (IEC) protocol. -''' - -from .pd import Decoder diff --git a/decoders/iec/pd.py b/decoders/iec/pd.py deleted file mode 100755 index 8acd1d1f..00000000 --- a/decoders/iec/pd.py +++ /dev/null @@ -1,168 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2017 Marcus Comstedt -## Copyright (C) 2019 DreamSourceLab -## -## 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, see . -## - -import sigrokdecode as srd - -step_wait_conds = ( - [{2: 'f'}, {0: 'l', 1: 'h'}], - [{2: 'f'}, {0: 'h', 1: 'h'}, {1: 'l'}], - [{2: 'f'}, {0: 'f'}, {1: 'l'}], - [{2: 'f'}, {1: 'e'}], -) - -class Decoder(srd.Decoder): - api_version = 3 - id = 'iec' - name = 'IEC' - longname = 'Commodore IEC bus' - desc = 'Commodore serial IEEE-488 (IEC) bus protocol.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['PC', 'Retro computing'] - channels = ( - {'id': 'data', 'name': 'DATA', 'desc': 'Data I/O'}, - {'id': 'clk', 'name': 'CLK', 'desc': 'Clock'}, - {'id': 'atn', 'name': 'ATN', 'desc': 'Attention'}, - ) - optional_channels = ( - {'id': 'srq', 'name': 'SRQ', 'desc': 'Service request'}, - ) - annotations = ( - ('items', 'Items'), - ('gpib', 'DAT/CMD'), - ('eoi', 'EOI'), - ) - annotation_rows = ( - ('bytes', 'Bytes', (0,)), - ('gpib', 'DAT/CMD', (1,)), - ('eoi', 'EOI', (2,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.saved_ATN = False - self.saved_EOI = False - self.ss_item = self.es_item = None - self.step = 0 - self.bits = 0 - self.numbits = 0 - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putb(self, data): - self.put(self.ss_item, self.es_item, self.out_ann, data) - - def handle_bits(self): - # Output the saved item. - dbyte = self.bits - dATN = self.saved_ATN - dEOI = self.saved_EOI - self.es_item = self.samplenum - self.putb([0, ['%02X' % dbyte]]) - - # Encode item byte to GPIB convention. - self.strgpib = ' ' - if dATN: # ATN, decode commands. - # Note: Commands < 0x20 are not used on IEC bus. - if dbyte == 0x01: self.strgpib = 'GTL' - if dbyte == 0x04: self.strgpib = 'SDC' - if dbyte == 0x05: self.strgpib = 'PPC' - if dbyte == 0x08: self.strgpib = 'GET' - if dbyte == 0x09: self.strgpib = 'TCT' - if dbyte == 0x11: self.strgpib = 'LLO' - if dbyte == 0x14: self.strgpib = 'DCL' - if dbyte == 0x15: self.strgpib = 'PPU' - if dbyte == 0x18: self.strgpib = 'SPE' - if dbyte == 0x19: self.strgpib = 'SPD' - - if dbyte == 0x3f: self.strgpib = 'UNL' - if dbyte == 0x5f: self.strgpib = 'UNT' - if dbyte > 0x1f and dbyte < 0x3f: # Address listener. - self.strgpib = 'L' + chr(dbyte + 0x10) - if dbyte > 0x3f and dbyte < 0x5f: # Address talker. - self.strgpib = 'T' + chr(dbyte - 0x10) - if dbyte > 0x5f and dbyte < 0x70: # Channel reopen. - self.strgpib = 'R' + chr(dbyte - 0x30) - if dbyte > 0xdf and dbyte < 0xf0: # Channel close. - self.strgpib = 'C' + chr(dbyte - 0xb0) - if dbyte > 0xef: # Channel open. - self.strgpib = 'O' + chr(dbyte - 0xc0) - else: - if dbyte > 0x1f and dbyte < 0x7f: - self.strgpib = chr(dbyte) - if dbyte == 0x0a: - self.strgpib = 'LF' - if dbyte == 0x0d: - self.strgpib = 'CR' - - self.putb([1, [self.strgpib]]) - self.strEOI = ' ' - if dEOI: - self.strEOI = 'EOI' - self.putb([2, [self.strEOI]]) - - def decode(self): - while True: - - (data, clk, atn, srq) = self.wait(step_wait_conds[self.step]) - - if (self.matched & (0b1 << 0)): - # Falling edge on ATN, reset step. - self.step = 0 - - if self.step == 0: - # Don't use self.matched[1] here since we might come from - # a step with different conds due to the code above. - if data == 0 and clk == 1: - # Rising edge on CLK while DATA is low: Ready to send. - self.step = 1 - elif self.step == 1: - if data == 1 and clk == 1: - # Rising edge on DATA while CLK is high: Ready for data. - self.ss_item = self.samplenum - self.saved_ATN = not atn - self.saved_EOI = False - self.bits = 0 - self.numbits = 0 - self.step = 2 - elif clk == 0: - # CLK low again, transfer aborted. - self.step = 0 - elif self.step == 2: - if data == 0 and clk == 1: - # DATA goes low while CLK is still high, EOI confirmed. - self.saved_EOI = True - elif clk == 0: - self.step = 3 - elif self.step == 3: - if (self.matched & (0b1 << 1)): - if clk == 1: - # Rising edge on CLK; latch DATA. - self.bits |= data << self.numbits - elif clk == 0: - # Falling edge on CLK; end of bit. - self.numbits += 1 - if self.numbits == 8: - self.handle_bits() - self.step = 0 diff --git a/decoders/ieee488/__init__.py b/decoders/ieee488/__init__.py deleted file mode 100644 index 4240114a..00000000 --- a/decoders/ieee488/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Gerhard Sittig -## -## 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, see . -## - -''' -This protocol decoder can decode the GPIB (IEEE-488) protocol. Both variants -of (up to) 16 parallel lines as well as serial communication (IEC bus) are -supported in this implementation. -''' - -from .pd import Decoder diff --git a/decoders/ieee488/pd.py b/decoders/ieee488/pd.py deleted file mode 100644 index 4531cb30..00000000 --- a/decoders/ieee488/pd.py +++ /dev/null @@ -1,748 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2016 Rudolf Reuter -## Copyright (C) 2017 Marcus Comstedt -## Copyright (C) 2019 Gerhard Sittig -## -## 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, see . -## - -# This file was created from earlier implementations of the 'gpib' and -# the 'iec' protocol decoders. It combines the parallel and the serial -# transmission variants in a single instance with optional inputs for -# maximum code re-use. - -# TODO -# - Extend annotations for improved usability. -# - Keep talkers' data streams on separate annotation rows? Is this useful -# here at the GPIB level, or shall stacked decoders dispatch these? May -# depend on how often captures get inspected which involve multiple peers. -# - Make serial bit annotations optional? Could slow down interactive -# exploration for long captures (see USB). -# - Move the inlined Commodore IEC peripherals support to a stacked decoder -# when more peripherals get added. -# - SCPI over GPIB may "represent somewhat naturally" here already when -# text lines are a single run of data at the GPIB layer (each line between -# the address spec and either EOI or ATN). So a stacked SCPI decoder may -# only become necessary when the text lines' content shall get inspected. - -import sigrokdecode as srd -from common.srdhelper import bitpack - -''' -OUTPUT_PYTHON format for stacked decoders: - -General packet format: -[, , ] - -This is the list of s and their respective values: - -Raw bits and bytes at the physical transport level: - - 'IEC_BIT': is not applicable, is the transport's bit value. - - 'GPIB_RAW': is not applicable, is the transport's - byte value. Data bytes are in the 0x00-0xff range, command/address - bytes are in the 0x100-0x1ff range. - -GPIB level byte fields (commands, addresses, pieces of data): - - 'COMMAND': is not applicable, is the command's byte value. - - 'LISTEN': is the listener address (0-30), is the raw - byte value (including the 0x20 offset). - - 'TALK': is the talker address (0-30), is the raw byte - value (including the 0x40 offset). - - 'SECONDARY': is the secondary address (0-31), is the - raw byte value (including the 0x60 offset). - - 'MSB_SET': as well as are the raw byte value (including - the 0x80 offset). This usually does not happen for GPIB bytes with ATN - active, but was observed with the IEC bus and Commodore floppy drives, - when addressing channels within the device. - - 'DATA_BYTE': is the talker address (when available), - is the raw data byte (transport layer, ATN inactive). - -Extracted payload information (peers and their communicated data): - - 'TALK_LISTEN': is the current talker, is the list of - current listeners. These updates for the current "connected peers" - are sent when the set of peers changes, i.e. after talkers/listeners - got selected or deselected. Of course the data only covers what could - be gathered from the input data. Some controllers may not explicitly - address themselves, or captures may not include an early setup phase. - - 'TALKER_BYTES': is the talker address (when available), - is the accumulated byte sequence between addressing a talker and EOI, - or the next command/address. - - 'TALKER_TEXT': is the talker address (when available), - is the accumulated text sequence between addressing a talker and EOI, - or the next command/address. -''' - -class ChannelError(Exception): - pass - -def _format_ann_texts(fmts, **args): - if not fmts: - return None - return [fmt.format(**args) for fmt in fmts] - -_cmd_table = { - # Command codes in the 0x00-0x1f range. - 0x01: ['Go To Local', 'GTL'], - 0x04: ['Selected Device Clear', 'SDC'], - 0x05: ['Parallel Poll Configure', 'PPC'], - 0x08: ['Global Execute Trigger', 'GET'], - 0x09: ['Take Control', 'TCT'], - 0x11: ['Local Lock Out', 'LLO'], - 0x14: ['Device Clear', 'DCL'], - 0x15: ['Parallel Poll Unconfigure', 'PPU'], - 0x18: ['Serial Poll Enable', 'SPE'], - 0x19: ['Serial Poll Disable', 'SPD'], - # Unknown type of command. - None: ['Unknown command 0x{cmd:02x}', 'command 0x{cmd:02x}', 'cmd {cmd:02x}', 'C{cmd_ord:c}'], - # Special listener/talker "addresses" (deselecting previous peers). - 0x3f: ['Unlisten', 'UNL'], - 0x5f: ['Untalk', 'UNT'], -} - -def _is_command(b): - # Returns a tuple of booleans (or None when not applicable) whether - # the raw GPIB byte is: a command, an un-listen, an un-talk command. - if b in range(0x00, 0x20): - return True, None, None - if b in range(0x20, 0x40) and (b & 0x1f) == 31: - return True, True, False - if b in range(0x40, 0x60) and (b & 0x1f) == 31: - return True, False, True - return False, None, None - -def _is_listen_addr(b): - if b in range(0x20, 0x40): - return b & 0x1f - return None - -def _is_talk_addr(b): - if b in range(0x40, 0x60): - return b & 0x1f - return None - -def _is_secondary_addr(b): - if b in range(0x60, 0x80): - return b & 0x1f - return None - -def _is_msb_set(b): - if b & 0x80: - return b - return None - -def _get_raw_byte(b, atn): - # "Decorate" raw byte values for stacked decoders. - return b | 0x100 if atn else b - -def _get_raw_text(b, atn): - return ['{leader}{data:02x}'.format(leader = '/' if atn else '', data = b)] - -def _get_command_texts(b): - fmts = _cmd_table.get(b, None) - known = fmts is not None - if not fmts: - fmts = _cmd_table.get(None, None) - if not fmts: - return known, None - return known, _format_ann_texts(fmts, cmd = b, cmd_ord = ord('0') + b) - -def _get_address_texts(b): - laddr = _is_listen_addr(b) - taddr = _is_talk_addr(b) - saddr = _is_secondary_addr(b) - msb = _is_msb_set(b) - fmts = None - if laddr is not None: - fmts = ['Listen {addr:d}', 'L {addr:d}', 'L{addr_ord:c}'] - addr = laddr - elif taddr is not None: - fmts = ['Talk {addr:d}', 'T {addr:d}', 'T{addr_ord:c}'] - addr = taddr - elif saddr is not None: - fmts = ['Secondary {addr:d}', 'S {addr:d}', 'S{addr_ord:c}'] - addr = saddr - elif msb is not None: # For IEC bus compat. - fmts = ['Secondary {addr:d}', 'S {addr:d}', 'S{addr_ord:c}'] - addr = msb - return _format_ann_texts(fmts, addr = addr, addr_ord = ord('0') + addr) - -def _get_data_text(b): - # TODO Move the table of ASCII control characters to a common location? - # TODO Move the "printable with escapes" logic to a common helper? - _control_codes = { - 0x00: 'NUL', - 0x01: 'SOH', - 0x02: 'STX', - 0x03: 'ETX', - 0x04: 'EOT', - 0x05: 'ENQ', - 0x06: 'ACK', - 0x07: 'BEL', - 0x08: 'BS', - 0x09: 'TAB', - 0x0a: 'LF', - 0x0b: 'VT', - 0x0c: 'FF', - 0x0d: 'CR', - 0x0e: 'SO', - 0x0f: 'SI', - 0x10: 'DLE', - 0x11: 'DC1', - 0x12: 'DC2', - 0x13: 'DC3', - 0x14: 'DC4', - 0x15: 'NAK', - 0x16: 'SYN', - 0x17: 'ETB', - 0x18: 'CAN', - 0x19: 'EM', - 0x1a: 'SUB', - 0x1b: 'ESC', - 0x1c: 'FS', - 0x1d: 'GS', - 0x1e: 'RS', - 0x1f: 'US', - } - # Yes, exclude 0x7f (DEL) here. It's considered non-printable. - if b in range(0x20, 0x7f) and b not in ('[', ']'): - return '{:s}'.format(chr(b)) - elif b in _control_codes: - return '[{:s}]'.format(_control_codes[b]) - # Use a compact yet readable and unambigous presentation for bytes - # which contain non-printables. The format that is used here is - # compatible with 93xx EEPROM and UART decoders. - return '[{:02x}]'.format(b) - -( - PIN_DIO1, PIN_DIO2, PIN_DIO3, PIN_DIO4, - PIN_DIO5, PIN_DIO6, PIN_DIO7, PIN_DIO8, - PIN_EOI, PIN_DAV, PIN_NRFD, PIN_NDAC, - PIN_IFC, PIN_SRQ, PIN_ATN, PIN_REN, - PIN_CLK, -) = range(17) -PIN_DATA = PIN_DIO1 - -( - ANN_RAW_BIT, ANN_RAW_BYTE, - ANN_CMD, ANN_LADDR, ANN_TADDR, ANN_SADDR, ANN_DATA, - ANN_EOI, - ANN_TEXT, - # TODO Want to provide one annotation class per talker address (0-30)? - ANN_IEC_PERIPH, - ANN_WARN, -) = range(11) - -( - BIN_RAW, - BIN_DATA, - # TODO Want to provide one binary annotation class per talker address (0-30)? -) = range(2) - -class Decoder(srd.Decoder): - api_version = 3 - id = 'ieee488' - name = 'IEEE-488' - longname = 'IEEE-488 GPIB/HPIB/IEC' - desc = 'IEEE-488 General Purpose Interface Bus (GPIB/HPIB or IEC).' - license = 'gplv2+' - inputs = ['logic'] - outputs = ['ieee488'] - tags = ['PC', 'Retro computing'] - channels = ( - {'id': 'dio1' , 'name': 'DIO1/DATA', - 'desc': 'Data I/O bit 1, or serial data'}, - ) - optional_channels = ( - {'id': 'dio2' , 'name': 'DIO2', 'desc': 'Data I/O bit 2'}, - {'id': 'dio3' , 'name': 'DIO3', 'desc': 'Data I/O bit 3'}, - {'id': 'dio4' , 'name': 'DIO4', 'desc': 'Data I/O bit 4'}, - {'id': 'dio5' , 'name': 'DIO5', 'desc': 'Data I/O bit 5'}, - {'id': 'dio6' , 'name': 'DIO6', 'desc': 'Data I/O bit 6'}, - {'id': 'dio7' , 'name': 'DIO7', 'desc': 'Data I/O bit 7'}, - {'id': 'dio8' , 'name': 'DIO8', 'desc': 'Data I/O bit 8'}, - {'id': 'eoi', 'name': 'EOI', 'desc': 'End or identify'}, - {'id': 'dav', 'name': 'DAV', 'desc': 'Data valid'}, - {'id': 'nrfd', 'name': 'NRFD', 'desc': 'Not ready for data'}, - {'id': 'ndac', 'name': 'NDAC', 'desc': 'Not data accepted'}, - {'id': 'ifc', 'name': 'IFC', 'desc': 'Interface clear'}, - {'id': 'srq', 'name': 'SRQ', 'desc': 'Service request'}, - {'id': 'atn', 'name': 'ATN', 'desc': 'Attention'}, - {'id': 'ren', 'name': 'REN', 'desc': 'Remote enable'}, - {'id': 'clk', 'name': 'CLK', 'desc': 'Serial clock'}, - ) - options = ( - {'id': 'iec_periph', 'desc': 'Decode Commodore IEC bus peripherals details', - 'default': 'no', 'values': ('no', 'yes')}, - {'id': 'delim', 'desc': 'Payload data delimiter', - 'default': 'eol', 'values': ('none', 'eol')}, - ) - annotations = ( - ('bit', 'IEC bit'), - ('raw', 'Raw byte'), - ('cmd', 'Command'), - ('laddr', 'Listener address'), - ('taddr', 'Talker address'), - ('saddr', 'Secondary address'), - ('data', 'Data byte'), - ('eoi', 'EOI'), - ('text', 'Talker text'), - ('periph', 'IEC bus peripherals'), - ('warning', 'Warning'), - ) - annotation_rows = ( - ('bits', 'IEC bits', (ANN_RAW_BIT,)), - ('raws', 'Raw bytes', (ANN_RAW_BYTE,)), - ('gpib', 'Commands/data', (ANN_CMD, ANN_LADDR, ANN_TADDR, ANN_SADDR, ANN_DATA,)), - ('eois', 'EOI', (ANN_EOI,)), - ('texts', 'Talker texts', (ANN_TEXT,)), - ('periphs', 'IEC peripherals', (ANN_IEC_PERIPH,)), - ('warnings', 'Warnings', (ANN_WARN,)), - ) - binary = ( - ('raw', 'Raw bytes'), - ('data', 'Talker bytes'), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.curr_raw = None - self.curr_atn = None - self.curr_eoi = None - self.latch_atn = None - self.latch_eoi = None - self.accu_bytes = [] - self.accu_text = [] - self.ss_raw = None - self.es_raw = None - self.ss_eoi = None - self.es_eoi = None - self.ss_text = None - self.es_text = None - self.last_talker = None - self.last_listener = [] - self.last_iec_addr = None - self.last_iec_sec = None - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.out_bin = self.register(srd.OUTPUT_BINARY) - self.out_python = self.register(srd.OUTPUT_PYTHON) - - def putg(self, ss, es, data): - self.put(ss, es, self.out_ann, data) - - def putbin(self, ss, es, data): - self.put(ss, es, self.out_bin, data) - - def putpy(self, ss, es, ptype, addr, pdata): - self.put(ss, es, self.out_python, [ptype, addr, pdata]) - - def emit_eoi_ann(self, ss, es): - self.putg(ss, es, [ANN_EOI, ['EOI']]) - - def emit_bin_ann(self, ss, es, ann_cls, data): - self.putbin(ss, es, [ann_cls, bytes(data)]) - - def emit_data_ann(self, ss, es, ann_cls, data): - self.putg(ss, es, [ann_cls, data]) - - def emit_warn_ann(self, ss, es, data): - self.putg(ss, es, [ANN_WARN, data]) - - def flush_bytes_text_accu(self): - if self.accu_bytes and self.ss_text is not None and self.es_text is not None: - self.emit_bin_ann(self.ss_text, self.es_text, BIN_DATA, bytearray(self.accu_bytes)) - self.putpy(self.ss_text, self.es_text, 'TALKER_BYTES', self.last_talker, bytearray(self.accu_bytes)) - self.accu_bytes = [] - if self.accu_text and self.ss_text is not None and self.es_text is not None: - text = ''.join(self.accu_text) - self.emit_data_ann(self.ss_text, self.es_text, ANN_TEXT, [text]) - self.putpy(self.ss_text, self.es_text, 'TALKER_TEXT', self.last_talker, text) - self.accu_text = [] - self.ss_text = self.es_text = None - - def check_extra_flush(self, b): - # Optionally flush previously accumulated runs of payload data - # according to user specified conditions. - if self.options['delim'] == 'none': - return - if not self.accu_bytes: - return - - # This implementation exlusively handles "text lines", but adding - # support for more variants here is straight forward. - # - # Search for the first data byte _after_ a user specified text - # line termination sequence was seen. The termination sequence's - # alphabet may be variable, and the sequence may span multiple - # data bytes. We accept either CR or LF, and combine the CR+LF - # sequence to strive for maximum length annotations for improved - # readability at different zoom levels. It's acceptable that this - # implementation would also combine multiple line terminations - # like LF+LF. - term_chars = (10, 13) - is_eol = b in term_chars - had_eol = self.accu_bytes[-1] in term_chars - if had_eol and not is_eol: - self.flush_bytes_text_accu() - - def handle_ifc_change(self, ifc): - # Track IFC line for parallel input. - # Assertion of IFC de-selects all talkers and listeners. - if ifc: - self.last_talker = None - self.last_listener = [] - self.flush_bytes_text_accu() - - def handle_eoi_change(self, eoi): - # Track EOI line for parallel and serial input. - if eoi: - self.ss_eoi = self.samplenum - self.curr_eoi = eoi - else: - self.es_eoi = self.samplenum - if self.ss_eoi and self.latch_eoi: - self.emit_eoi_ann(self.ss_eoi, self.es_eoi) - self.es_text = self.es_eoi - self.flush_bytes_text_accu() - self.ss_eoi = self.es_eoi = None - self.curr_eoi = None - - def handle_atn_change(self, atn): - # Track ATN line for parallel and serial input. - self.curr_atn = atn - if atn: - self.flush_bytes_text_accu() - - def handle_iec_periph(self, ss, es, addr, sec, data): - # The annotation is optional. - if self.options['iec_periph'] != 'yes': - return - # Void internal state. - if addr is None and sec is None and data is None: - self.last_iec_addr = None - self.last_iec_sec = None - return - # Grab and evaluate new input. - _iec_addr_names = { - # TODO Add more items here. See the "Device numbering" section - # of the https://en.wikipedia.org/wiki/Commodore_bus page. - 8: 'Disk 0', - 9: 'Disk 1', - } - _iec_disk_range = range(8, 16) - if addr is not None: - self.last_iec_addr = addr - name = _iec_addr_names.get(addr, None) - if name: - self.emit_data_ann(ss, es, ANN_IEC_PERIPH, [name]) - addr = self.last_iec_addr # Simplify subsequent logic. - if sec is not None: - # BEWARE! The secondary address is a full byte and includes - # the 0x60 offset, to also work when the MSB was set. - self.last_iec_sec = sec - subcmd, channel = sec & 0xf0, sec & 0x0f - channel_ord = ord('0') + channel - if addr is not None and addr in _iec_disk_range: - subcmd_fmts = { - 0x60: ['Reopen {ch:d}', 'Re {ch:d}', 'R{ch_ord:c}'], - 0xe0: ['Close {ch:d}', 'Cl {ch:d}', 'C{ch_ord:c}'], - 0xf0: ['Open {ch:d}', 'Op {ch:d}', 'O{ch_ord:c}'], - }.get(subcmd, None) - if subcmd_fmts: - texts = _format_ann_texts(subcmd_fmts, ch = channel, ch_ord = channel_ord) - self.emit_data_ann(ss, es, ANN_IEC_PERIPH, texts) - sec = self.last_iec_sec # Simplify subsequent logic. - if data is not None: - if addr is None or sec is None: - return - # TODO Process data depending on peripheral type and channel? - - def handle_data_byte(self): - if not self.curr_atn: - self.check_extra_flush(self.curr_raw) - b = self.curr_raw - texts = _get_raw_text(b, self.curr_atn) - self.emit_data_ann(self.ss_raw, self.es_raw, ANN_RAW_BYTE, texts) - self.emit_bin_ann(self.ss_raw, self.es_raw, BIN_RAW, b.to_bytes(1, byteorder='big')) - self.putpy(self.ss_raw, self.es_raw, 'GPIB_RAW', None, _get_raw_byte(b, self.curr_atn)) - if self.curr_atn: - ann_cls = None - upd_iec = False, - py_type = None - py_peers = False - is_cmd, is_unl, is_unt = _is_command(b) - laddr = _is_listen_addr(b) - taddr = _is_talk_addr(b) - saddr = _is_secondary_addr(b) - msb = _is_msb_set(b) - if is_cmd: - known, texts = _get_command_texts(b) - if not known: - warn_texts = ['Unknown GPIB command', 'unknown', 'UNK'] - self.emit_warn_ann(self.ss_raw, self.es_raw, warn_texts) - ann_cls = ANN_CMD - py_type, py_addr = 'COMMAND', None - if is_unl: - self.last_listener = [] - py_peers = True - if is_unt: - self.last_talker = None - py_peers = True - if is_unl or is_unt: - upd_iec = True, None, None, None - elif laddr is not None: - addr = laddr - texts = _get_address_texts(b) - ann_cls = ANN_LADDR - py_type, py_addr = 'LISTEN', addr - if addr == self.last_talker: - self.last_talker = None - self.last_listener.append(addr) - upd_iec = True, addr, None, None - py_peers = True - elif taddr is not None: - addr = taddr - texts = _get_address_texts(b) - ann_cls = ANN_TADDR - py_type, py_addr = 'TALK', addr - if addr in self.last_listener: - self.last_listener.remove(addr) - self.last_talker = addr - upd_iec = True, addr, None, None - py_peers = True - elif saddr is not None: - addr = saddr - texts = _get_address_texts(b) - ann_cls = ANN_SADDR - upd_iec = True, None, b, None - py_type, py_addr = 'SECONDARY', addr - elif msb is not None: - # These are not really "secondary addresses", but they - # are used by the Commodore IEC bus (floppy channels). - texts = _get_address_texts(b) - ann_cls = ANN_SADDR - upd_iec = True, None, b, None - py_type, py_addr = 'MSB_SET', b - if ann_cls is not None and texts is not None: - self.emit_data_ann(self.ss_raw, self.es_raw, ann_cls, texts) - if upd_iec[0]: - self.handle_iec_periph(self.ss_raw, self.es_raw, upd_iec[1], upd_iec[2], upd_iec[3]) - if py_type: - self.putpy(self.ss_raw, self.es_raw, py_type, py_addr, b) - if py_peers: - self.last_listener.sort() - self.putpy(self.ss_raw, self.es_raw, 'TALK_LISTEN', self.last_talker, self.last_listener) - else: - self.accu_bytes.append(b) - text = _get_data_text(b) - if not self.accu_text: - self.ss_text = self.ss_raw - self.accu_text.append(text) - self.es_text = self.es_raw - self.emit_data_ann(self.ss_raw, self.es_raw, ANN_DATA, [text]) - self.handle_iec_periph(self.ss_raw, self.es_raw, None, None, b) - self.putpy(self.ss_raw, self.es_raw, 'DATA_BYTE', self.last_talker, b) - - def handle_dav_change(self, dav, data): - if dav: - # Data availability starts when the flag goes active. - self.ss_raw = self.samplenum - self.curr_raw = bitpack(data) - self.latch_atn = self.curr_atn - self.latch_eoi = self.curr_eoi - return - # Data availability ends when the flag goes inactive. Handle the - # previously captured data byte according to associated flags. - self.es_raw = self.samplenum - self.handle_data_byte() - self.ss_raw = self.es_raw = None - self.curr_raw = None - - def inject_dav_phase(self, ss, es, data): - # Inspection of serial input has resulted in one raw byte which - # spans a given period of time. Pretend we had seen a DAV active - # phase, to re-use code for the parallel transmission. - self.ss_raw = ss - self.curr_raw = bitpack(data) - self.latch_atn = self.curr_atn - self.latch_eoi = self.curr_eoi - self.es_raw = es - self.handle_data_byte() - self.ss_raw = self.es_raw = None - self.curr_raw = None - - def invert_pins(self, pins): - # All lines (including data bits!) are low active and thus need - # to get inverted to receive their logical state (high active, - # regular data bit values). Cope with inputs being optional. - return [1 - p if p in (0, 1) else p for p in pins] - - def decode_serial(self, has_clk, has_data_1, has_atn, has_srq): - if not has_clk or not has_data_1 or not has_atn: - raise ChannelError('IEC bus needs at least ATN and serial CLK and DATA.') - - # This is a rephrased version of decoders/iec/pd.py:decode(). - # SRQ was not used there either. Magic numbers were eliminated. - ( - STEP_WAIT_READY_TO_SEND, - STEP_WAIT_READY_FOR_DATA, - STEP_PREP_DATA_TEST_EOI, - STEP_CLOCK_DATA_BITS, - ) = range(4) - step_wait_conds = ( - [{PIN_ATN: 'f'}, {PIN_DATA: 'l', PIN_CLK: 'h'}], - [{PIN_ATN: 'f'}, {PIN_DATA: 'h', PIN_CLK: 'h'}, {PIN_CLK: 'l'}], - [{PIN_ATN: 'f'}, {PIN_DATA: 'f'}, {PIN_CLK: 'l'}], - [{PIN_ATN: 'f'}, {PIN_CLK: 'e'}], - ) - step = STEP_WAIT_READY_TO_SEND - bits = [] - - while True: - - # Sample input pin values. Keep DATA/CLK in verbatim form to - # re-use 'iec' decoder logic. Turn ATN to positive logic for - # easier processing. The data bits get handled during byte - # accumulation. - pins = self.wait(step_wait_conds[step]) - data, clk = pins[PIN_DATA], pins[PIN_CLK] - atn, = self.invert_pins([pins[PIN_ATN]]) - - if self.matched[0]: - # Falling edge on ATN, reset step. - step = STEP_WAIT_READY_TO_SEND - - if step == STEP_WAIT_READY_TO_SEND: - # Don't use self.matched[1] here since we might come from - # a step with different conds due to the code above. - if data == 0 and clk == 1: - # Rising edge on CLK while DATA is low: Ready to send. - step = STEP_WAIT_READY_FOR_DATA - elif step == STEP_WAIT_READY_FOR_DATA: - if data == 1 and clk == 1: - # Rising edge on DATA while CLK is high: Ready for data. - ss_byte = self.samplenum - self.handle_atn_change(atn) - if self.curr_eoi: - self.handle_eoi_change(False) - bits = [] - step = STEP_PREP_DATA_TEST_EOI - elif clk == 0: - # CLK low again, transfer aborted. - step = STEP_WAIT_READY_TO_SEND - elif step == STEP_PREP_DATA_TEST_EOI: - if data == 0 and clk == 1: - # DATA goes low while CLK is still high, EOI confirmed. - self.handle_eoi_change(True) - elif clk == 0: - step = STEP_CLOCK_DATA_BITS - ss_bit = self.samplenum - elif step == STEP_CLOCK_DATA_BITS: - if self.matched[1]: - if clk == 1: - # Rising edge on CLK; latch DATA. - bits.append(data) - elif clk == 0: - # Falling edge on CLK; end of bit. - es_bit = self.samplenum - self.emit_data_ann(ss_bit, es_bit, ANN_RAW_BIT, ['{:d}'.format(bits[-1])]) - self.putpy(ss_bit, es_bit, 'IEC_BIT', None, bits[-1]) - ss_bit = self.samplenum - if len(bits) == 8: - es_byte = self.samplenum - self.inject_dav_phase(ss_byte, es_byte, bits) - if self.curr_eoi: - self.handle_eoi_change(False) - step = STEP_WAIT_READY_TO_SEND - - def decode_parallel(self, has_data_n, has_dav, has_atn, has_eoi, has_srq): - - if False in has_data_n or not has_dav or not has_atn: - raise ChannelError('IEEE-488 needs at least ATN and DAV and eight DIO lines.') - has_ifc = self.has_channel(PIN_IFC) - - # Capture data lines at the falling edge of DAV, process their - # values at rising DAV edge (when data validity ends). Also make - # sure to start inspection when the capture happens to start with - # low signal levels, i.e. won't include the initial falling edge. - # Scan for ATN/EOI edges as well (including the trick which works - # around initial pin state). - # Map low-active physical transport lines to positive logic here, - # to simplify logical inspection/decoding of communicated data, - # and to avoid redundancy and inconsistency in later code paths. - waitcond = [] - idx_dav = len(waitcond) - waitcond.append({PIN_DAV: 'l'}) - idx_atn = len(waitcond) - waitcond.append({PIN_ATN: 'l'}) - idx_eoi = None - if has_eoi: - idx_eoi = len(waitcond) - waitcond.append({PIN_EOI: 'l'}) - idx_ifc = None - if has_ifc: - idx_ifc = len(waitcond) - waitcond.append({PIN_IFC: 'l'}) - while True: - pins = self.wait(waitcond) - pins = self.invert_pins(pins) - - # BEWARE! Order of evaluation does matter. For low samplerate - # captures, many edges fall onto the same sample number. So - # we process active edges of flags early (before processing - # data bits), and inactive edges late (after data got processed). - if idx_ifc is not None and self.matched[idx_ifc] and pins[PIN_IFC] == 1: - self.handle_ifc_change(pins[PIN_IFC]) - if idx_eoi is not None and self.matched[idx_eoi] and pins[PIN_EOI] == 1: - self.handle_eoi_change(pins[PIN_EOI]) - if self.matched[idx_atn] and pins[PIN_ATN] == 1: - self.handle_atn_change(pins[PIN_ATN]) - if self.matched[idx_dav]: - self.handle_dav_change(pins[PIN_DAV], pins[PIN_DIO1:PIN_DIO8 + 1]) - if self.matched[idx_atn] and pins[PIN_ATN] == 0: - self.handle_atn_change(pins[PIN_ATN]) - if idx_eoi is not None and self.matched[idx_eoi] and pins[PIN_EOI] == 0: - self.handle_eoi_change(pins[PIN_EOI]) - if idx_ifc is not None and self.matched[idx_ifc] and pins[PIN_IFC] == 0: - self.handle_ifc_change(pins[PIN_IFC]) - - waitcond[idx_dav][PIN_DAV] = 'e' - waitcond[idx_atn][PIN_ATN] = 'e' - if has_eoi: - waitcond[idx_eoi][PIN_EOI] = 'e' - if has_ifc: - waitcond[idx_ifc][PIN_IFC] = 'e' - - def decode(self): - # The decoder's boilerplate declares some of the input signals as - # optional, but only to support both serial and parallel variants. - # The CLK signal discriminates the two. For either variant some - # of the "optional" signals are not really optional for proper - # operation of the decoder. Check these conditions here. - has_clk = self.has_channel(PIN_CLK) - has_data_1 = self.has_channel(PIN_DIO1) - has_data_n = [bool(self.has_channel(pin) for pin in range(PIN_DIO1, PIN_DIO8 + 1))] - has_dav = self.has_channel(PIN_DAV) - has_atn = self.has_channel(PIN_ATN) - has_eoi = self.has_channel(PIN_EOI) - has_srq = self.has_channel(PIN_SRQ) - if has_clk: - self.decode_serial(has_clk, has_data_1, has_atn, has_srq) - else: - self.decode_parallel(has_data_n, has_dav, has_atn, has_eoi, has_srq) diff --git a/decoders/ir_irmp/__init__.py b/decoders/ir_irmp/__init__.py deleted file mode 100644 index b6bbff60..00000000 --- a/decoders/ir_irmp/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Rene Staffen -## -## 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, see . -## - -''' -IRMP is a multi protocol infrared remote protocol decoder. See -https://www.mikrocontroller.net/articles/IRMP for details. -''' - -from .pd import Decoder diff --git a/decoders/ir_irmp/irmp_library.py b/decoders/ir_irmp/irmp_library.py deleted file mode 100644 index 5ec65222..00000000 --- a/decoders/ir_irmp/irmp_library.py +++ /dev/null @@ -1,137 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Rene Staffen -## -## 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, see . -## - -''' -Python binding for the IRMP library. -''' - -import ctypes -import platform - -class IrmpLibrary: - ''' - Library instance for an infrared protocol detector. - ''' - - __usable_instance = None - - class ResultData(ctypes.Structure): - _fields_ = [ - ( 'protocol', ctypes.c_uint32, ), - ( 'protocol_name', ctypes.c_char_p, ), - ( 'address', ctypes.c_uint32, ), - ( 'command', ctypes.c_uint32, ), - ( 'flags', ctypes.c_uint32, ), - ( 'start_sample', ctypes.c_uint32, ), - ( 'end_sample', ctypes.c_uint32, ), - ] - - FLAG_REPETITION = 1 << 0 - FLAG_RELEASE = 1 << 1 - - def _library_filename(self): - ''' - Determine the library filename depending on the platform. - ''' - - if platform.uname()[0] == 'Linux': - return 'libirmp.so' - if platform.uname()[0] == 'Darwin': - return 'libirmp.dylib' - return 'irmp.dll' - - def _library_setup_api(self): - ''' - Lookup the C library's API routines. Declare their prototypes. - ''' - - if not self._lib: - return False - - self._lib.irmp_get_sample_rate.restype = ctypes.c_uint32 - self._lib.irmp_get_sample_rate.argtypes = [] - - self._lib.irmp_reset_state.restype = None - self._lib.irmp_reset_state.argtypes = [] - - self._lib.irmp_add_one_sample.restype = ctypes.c_int - self._lib.irmp_add_one_sample.argtypes = [ ctypes.c_int, ] - - if False: - self._lib.irmp_detect_buffer.restype = self.ResultData - self._lib.irmp_detect_buffer.argtypes = [ ctypes.POINTER(ctypes.c_uint8), ctypes.c_size_t, ] - - self._lib.irmp_get_result_data.restype = ctypes.c_int - self._lib.irmp_get_result_data.argtypes = [ ctypes.POINTER(self.ResultData), ] - - self._lib.irmp_get_protocol_name.restype = ctypes.c_char_p - self._lib.irmp_get_protocol_name.argtypes = [ ctypes.c_uint32, ] - - # Create a result buffer that's local to the library instance. - self._data = self.ResultData() - - return True - - def __init__(self): - ''' - Create a library instance. - ''' - - # Only create a working instance for the first invocation. - # Degrade all other instances, make them fail "late" during - # execution, so that users will see the errors. - self._lib = None - self._data = None - if IrmpLibrary.__usable_instance is None: - filename = self._library_filename() - self._lib = ctypes.cdll.LoadLibrary(filename) - self._library_setup_api() - IrmpLibrary.__usable_instance = self - - def get_sample_rate(self): - if not self._lib: - return None - return self._lib.irmp_get_sample_rate() - - def reset_state(self): - if not self._lib: - return None - self._lib.irmp_reset_state() - - def add_one_sample(self, level): - if not self._lib: - raise Exception("IRMP library limited to a single instance.") - if not self._lib.irmp_add_one_sample(int(level)): - return False - self._lib.irmp_get_result_data(ctypes.byref(self._data)) - return True - - def get_result_data(self): - if not self._data: - return None - return { - 'proto_nr': self._data.protocol, - 'proto_name': self._data.protocol_name.decode('UTF-8', 'ignore'), - 'address': self._data.address, - 'command': self._data.command, - 'repeat': bool(self._data.flags & self.FLAG_REPETITION), - 'release': bool(self._data.flags & self.FLAG_RELEASE), - 'start': self._data.start_sample, - 'end': self._data.end_sample, - } diff --git a/decoders/ir_irmp/pd.py b/decoders/ir_irmp/pd.py deleted file mode 100644 index 979c1e01..00000000 --- a/decoders/ir_irmp/pd.py +++ /dev/null @@ -1,137 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Gump Yang -## Copyright (C) 2019 Rene Staffen -## -## 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, see . -## - -from . import irmp_library -import sigrokdecode as srd - -class SamplerateError(Exception): - pass - -class LibraryError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = 'ir_irmp' - name = 'IR IRMP' - longname = 'IR IRMP' - desc = 'IRMP infrared remote control multi protocol.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['IR'] - channels = ( - {'id': 'ir', 'name': 'IR', 'desc': 'Data line'}, - ) - options = ( - {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-low', - 'values': ('active-low', 'active-high')}, - ) - annotations = ( - ('packet', 'Packet'), - ) - annotation_rows = ( - ('packets', 'IR Packets', (0,)), - ) - - def putframe(self, data): - '''Emit annotation for an IR frame.''' - - # Cache result data fields in local variables. Get the ss/es - # timestamps, scaled to sample numbers. - nr = data['proto_nr'] - name = data['proto_name'] - addr = data['address'] - cmd = data['command'] - repeat = data['repeat'] - release = data['release'] - ss = data['start'] * self.rate_factor - es = data['end'] * self.rate_factor - - # Prepare display texts for several zoom levels. - # Implementor's note: Keep list lengths for flags aligned during - # maintenance. Make sure there are as many flags text variants - # as are referenced by annotation text variants. Differing list - # lengths or dynamic refs will severely complicate the logic. - rep_txts = ['repeat', 'rep', 'r'] - rel_txts = ['release', 'rel', 'R'] - flag_txts = [None,] * len(rep_txts) - for zoom in range(len(flag_txts)): - flag_txts[zoom] = [] - if repeat: - flag_txts[zoom].append(rep_txts[zoom]) - if release: - flag_txts[zoom].append(rel_txts[zoom]) - flag_txts = [' '.join(t) or '-' for t in flag_txts] - flg = flag_txts # Short name for .format() references. - txts = [ - 'Protocol: {name} ({nr}), Address 0x{addr:04x}, Command: 0x{cmd:04x}, Flags: {flg[0]}'.format(**locals()), - 'P: {name} ({nr}), Addr: 0x{addr:x}, Cmd: 0x{cmd:x}, Flg: {flg[1]}'.format(**locals()), - 'P: {nr} A: 0x{addr:x} C: 0x{cmd:x} F: {flg[1]}'.format(**locals()), - 'C:{cmd:x} A:{addr:x} {flg[2]}'.format(**locals()), - 'C:{cmd:x}'.format(**locals()), - ] - - # Emit the annotation from details which were constructed above. - self.put(ss, es, self.out_ann, [0, txts]) - - def __init__(self): - self.irmp = None - self.reset() - - def reset(self): - self.want_reset = True - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def decode(self): - if not self.irmp: - try: - self.irmp = irmp_library.IrmpLibrary() - except Exception as e: - txt = e.args[0] - raise LibraryError(txt) - if self.irmp: - self.lib_rate = self.irmp.get_sample_rate() - if not self.irmp or not self.lib_rate: - raise LibraryError('Cannot access IRMP library. One instance limit exceeded?') - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - if self.samplerate % self.lib_rate: - raise SamplerateError('Capture samplerate must be multiple of library samplerate ({})'.format(self.lib_rate)) - self.rate_factor = int(self.samplerate / self.lib_rate) - if self.want_reset: - self.irmp.reset_state() - self.want_reset = False - - self.active = 0 if self.options['polarity'] == 'active-low' else 1 - ir, = self.wait() - while True: - if self.active == 1: - ir = 1 - ir - if self.irmp.add_one_sample(ir): - data = self.irmp.get_result_data() - self.putframe(data) - ir, = self.wait([{'skip': self.rate_factor}]) diff --git a/decoders/ir_nec/__init__.py b/decoders/ir_nec/__init__.py deleted file mode 100755 index c361c3dc..00000000 --- a/decoders/ir_nec/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Gump Yang -## -## 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, see . -## - -''' -NEC is a pulse-distance based infrared remote control protocol. -''' - -from .pd import Decoder diff --git a/decoders/ir_nec/lists.py b/decoders/ir_nec/lists.py deleted file mode 100755 index 7d47a46d..00000000 --- a/decoders/ir_nec/lists.py +++ /dev/null @@ -1,50 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Uwe Hermann -## -## 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, see . -## - -# Addresses/devices. Items that are not listed are reserved/unknown. -address = { - 0x40: 'Matsui TV', -} - -digits = { - 0: ['0', '0'], - 1: ['1', '1'], - 2: ['2', '2'], - 3: ['3', '3'], - 4: ['4', '4'], - 5: ['5', '5'], - 6: ['6', '6'], - 7: ['7', '7'], - 8: ['8', '8'], - 9: ['9', '9'], -} - -# Commands. Items that are not listed are reserved/unknown. -command = { - 0x40: dict(list(digits.items()) + list({ - 11: ['-/--', '-/--'], - 16: ['Mute', 'M'], - 18: ['Standby', 'StBy'], - 26: ['Volume up', 'Vol+'], - 27: ['Program up', 'P+'], - 30: ['Volume down', 'Vol-'], - 31: ['Program down', 'P-'], - 68: ['AV', 'AV'], - }.items())), -} diff --git a/decoders/ir_nec/pd.py b/decoders/ir_nec/pd.py deleted file mode 100755 index 830892e8..00000000 --- a/decoders/ir_nec/pd.py +++ /dev/null @@ -1,237 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Gump Yang -## Copyright (C) 2019 DreamSourceLab -## -## 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, see . -## - -import sigrokdecode as srd -from .lists import * - -class SamplerateError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = 'ir_nec' - name = 'IR NEC' - longname = 'IR NEC' - desc = 'NEC infrared remote control protocol.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['IR'] - channels = ( - {'id': 'ir', 'name': 'IR', 'desc': 'Data line'}, - ) - options = ( - {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-low', - 'values': ('active-low', 'active-high')}, - {'id': 'cd_freq', 'desc': 'Carrier Frequency', 'default': 0}, - ) - annotations = ( - ('bit', 'Bit'), - ('agc-pulse', 'AGC pulse'), - ('longpause', 'Long pause'), - ('shortpause', 'Short pause'), - ('stop-bit', 'Stop bit'), - ('leader-code', 'Leader code'), - ('addr', 'Address'), - ('addr-inv', 'Address#'), - ('cmd', 'Command'), - ('cmd-inv', 'Command#'), - ('repeat-code', 'Repeat code'), - ('remote', 'Remote'), - ('warnings', 'Warnings'), - ) - annotation_rows = ( - ('bits', 'Bits', (0, 1, 2, 3, 4)), - ('fields', 'Fields', (5, 6, 7, 8, 9, 10)), - ('remote', 'Remote', (11,)), - ('warnings', 'Warnings', (12,)), - ) - - def putx(self, data): - self.put(self.ss_start, self.samplenum, self.out_ann, data) - - def putb(self, data): - self.put(self.ss_bit, self.samplenum, self.out_ann, data) - - def putd(self, data): - name = self.state.title() - d = {'ADDRESS': 6, 'ADDRESS#': 7, 'COMMAND': 8, 'COMMAND#': 9} - s = {'ADDRESS': ['ADDR', 'A'], 'ADDRESS#': ['ADDR#', 'A#'], - 'COMMAND': ['CMD', 'C'], 'COMMAND#': ['CMD#', 'C#']} - self.putx([d[self.state], ['%s: 0x%02X' % (name, data), - '%s: 0x%02X' % (s[self.state][0], data), - '%s: 0x%02X' % (s[self.state][1], data), s[self.state][1]]]) - - def putstop(self, ss): - self.put(ss, ss + self.stop, self.out_ann, - [4, ['Stop bit', 'Stop', 'St', 'S']]) - - def putpause(self, p): - self.put(self.ss_start, self.ss_other_edge, self.out_ann, - [1, ['AGC pulse', 'AGC', 'A']]) - idx = 2 if p == 'Long' else 3 - self.put(self.ss_other_edge, self.samplenum, self.out_ann, - [idx, [p + ' pause', '%s-pause' % p[0], '%sP' % p[0], 'P']]) - - def putremote(self): - dev = address.get(self.addr, 'Unknown device') - buttons = command.get(self.addr, None) - if buttons is None: - btn = ['Unknown', 'Unk'] - else: - btn = buttons.get(self.cmd, ['Unknown', 'Unk']) - self.put(self.ss_remote, self.ss_bit + self.stop, self.out_ann, - [11, ['%s: %s' % (dev, btn[0]), '%s: %s' % (dev, btn[1]), - '%s' % btn[1]]]) - - def __init__(self): - self.reset() - - def reset(self): - self.state = 'IDLE' - self.ss_bit = self.ss_start = self.ss_other_edge = self.ss_remote = 0 - self.data = self.count = self.active = None - self.addr = self.cmd = None - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.active = 0 if self.options['polarity'] == 'active-low' else 1 - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - self.tolerance = 0.05 # +/-5% - self.lc = int(self.samplerate * 0.0135) - 1 # 13.5ms - self.rc = int(self.samplerate * 0.01125) - 1 # 11.25ms - self.dazero = int(self.samplerate * 0.001125) - 1 # 1.125ms - self.daone = int(self.samplerate * 0.00225) - 1 # 2.25ms - self.stop = int(self.samplerate * 0.000652) - 1 # 0.652ms - - def compare_with_tolerance(self, measured, base): - return (measured >= base * (1 - self.tolerance) - and measured <= base * (1 + self.tolerance)) - - def handle_bit(self, tick): - ret = None - if self.compare_with_tolerance(tick, self.dazero): - ret = 0 - elif self.compare_with_tolerance(tick, self.daone): - ret = 1 - if ret in (0, 1): - self.putb([0, ['%d' % ret]]) - self.data |= (ret << self.count) # LSB-first - self.count = self.count + 1 - self.ss_bit = self.samplenum - - def data_ok(self): - ret, name = (self.data >> 8) & (self.data & 0xff), self.state.title() - if self.count == 8: - if self.state == 'ADDRESS': - self.addr = self.data - if self.state == 'COMMAND': - self.cmd = self.data - self.putd(self.data) - self.ss_start = self.samplenum - return True - if ret == 0: - self.putd(self.data >> 8) - else: - self.putx([12, ['%s error: 0x%04X' % (name, self.data)]]) - self.data = self.count = 0 - self.ss_bit = self.ss_start = self.samplenum - return ret == 0 - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - - cd_count = None - if self.options['cd_freq']: - cd_count = int(self.samplerate / self.options['cd_freq']) + 1 - prev_ir = None - - while True: - # Detect changes in the presence of an active input signal. - # The decoder can either be fed an already filtered RX signal - # or optionally can detect the presence of a carrier. Periods - # of inactivity (signal changes slower than the carrier freq, - # if specified) pass on the most recently sampled level. This - # approach works for filtered and unfiltered input alike, and - # only slightly extends the active phase of input signals with - # carriers included by one period of the carrier frequency. - # IR based communication protocols can cope with this slight - # inaccuracy just fine by design. Enabling carrier detection - # on already filtered signals will keep the length of their - # active period, but will shift their signal changes by one - # carrier period before they get passed to decoding logic. - if cd_count: - (cur_ir,) = self.wait([{0: 'e'}, {'skip': cd_count}]) - if (self.matched & (0b1 << 0)): - cur_ir = self.active - if cur_ir == prev_ir: - continue - prev_ir = cur_ir - self.ir = cur_ir - else: - (self.ir,) = self.wait({0: 'e'}) - - if self.ir != self.active: - # Save the non-active edge, then wait for the next edge. - self.ss_other_edge = self.samplenum - continue - - b = self.samplenum - self.ss_bit - - # State machine. - if self.state == 'IDLE': - if self.compare_with_tolerance(b, self.lc): - self.putpause('Long') - self.putx([5, ['Leader code', 'Leader', 'LC', 'L']]) - self.ss_remote = self.ss_start - self.data = self.count = 0 - self.state = 'ADDRESS' - elif self.compare_with_tolerance(b, self.rc): - self.putpause('Short') - self.putstop(self.samplenum) - self.samplenum += self.stop - self.putx([10, ['Repeat code', 'Repeat', 'RC', 'R']]) - self.data = self.count = 0 - self.ss_bit = self.ss_start = self.samplenum - elif self.state == 'ADDRESS': - self.handle_bit(b) - if self.count == 8: - self.state = 'ADDRESS#' if self.data_ok() else 'IDLE' - elif self.state == 'ADDRESS#': - self.handle_bit(b) - if self.count == 16: - self.state = 'COMMAND' if self.data_ok() else 'IDLE' - elif self.state == 'COMMAND': - self.handle_bit(b) - if self.count == 8: - self.state = 'COMMAND#' if self.data_ok() else 'IDLE' - elif self.state == 'COMMAND#': - self.handle_bit(b) - if self.count == 16: - self.state = 'STOP' if self.data_ok() else 'IDLE' - elif self.state == 'STOP': - self.putstop(self.ss_bit) - self.putremote() - self.ss_bit = self.ss_start = self.samplenum - self.state = 'IDLE' diff --git a/decoders/ir_rc5/__init__.py b/decoders/ir_rc5/__init__.py deleted file mode 100755 index 7a209b19..00000000 --- a/decoders/ir_rc5/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Uwe Hermann -## -## 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, see . -## - -''' -RC-5 is a biphase/manchester based infrared remote control protocol. -''' - -from .pd import Decoder diff --git a/decoders/ir_rc5/lists.py b/decoders/ir_rc5/lists.py deleted file mode 100755 index 4a8c958d..00000000 --- a/decoders/ir_rc5/lists.py +++ /dev/null @@ -1,93 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Uwe Hermann -## -## 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, see . -## - -# Systems/addresses (0..31). Items that are not listed are reserved/unknown. -system = { - 0: ['TV receiver 1', 'TV1'], - 1: ['TV receiver 2', 'TV2'], - 2: ['Teletext', 'Txt'], - 3: ['Extension to TV1 and TV2', 'Ext TV1/TV2'], - 4: ['LaserVision player', 'LV'], - 5: ['Video cassette recorder 1', 'VCR1'], - 6: ['Video cassette recorder 2', 'VCR2'], - 7: ['Experimental', 'Exp'], - 8: ['Satellite TV receiver 1', 'Sat1'], - 9: ['Extension to VCR1 and VCR2', 'Ext VCR1/VCR2'], - 10: ['Satellite TV receiver 2', 'Sat2'], - 12: ['Compact disc video player', 'CD-Video'], - 13: ['Camcorder', 'Cam'], - 14: ['Photo on compact disc player', 'CD-Photo'], - 16: ['Audio preamplifier 1', 'Preamp1'], - 17: ['Radio tuner', 'Tuner'], - 18: ['Analog cassette recoder 1', 'Rec1'], - 19: ['Audio preamplifier 2', 'Preamp2'], - 20: ['Compact disc player', 'CD'], - 21: ['Audio stack or record player', 'Combi'], - 22: ['Audio satellite', 'Sat'], - 23: ['Analog cassette recoder 2', 'Rec2'], - 26: ['Compact disc recorder', 'CD-R'], - 29: ['Lighting 1', 'Light1'], - 30: ['Lighting 2', 'Light2'], - 31: ['Telephone', 'Phone'], -} - -digits = { - 0: ['0', '0'], - 1: ['1', '1'], - 2: ['2', '2'], - 3: ['3', '3'], - 4: ['4', '4'], - 5: ['5', '5'], - 6: ['6', '6'], - 7: ['7', '7'], - 8: ['8', '8'], - 9: ['9', '9'], -} - -# Commands (0..63 for RC-5, and 0..127 for Extended RC-5). -# Items that are not listed are reserved/unknown. -command = { - 'TV': dict(list(digits.items()) + list({ - 10: ['-/--', '-/--'], - 11: ['Channel/program', 'Ch/P'], - 12: ['Standby', 'StBy'], - 13: ['Mute', 'M'], - 14: ['Personal preferences', 'PP'], - 15: ['Display', 'Disp'], - 16: ['Volume up', 'Vol+'], - 17: ['Volume down', 'Vol-'], - 18: ['Brightness up', 'Br+'], - 19: ['Brightness down', 'Br-'], - 20: ['Saturation up', 'S+'], - 21: ['Saturation down', 'S-'], - 32: ['Program up', 'P+'], - 33: ['Program down', 'P-'], - }.items())), - 'VCR': dict(list(digits.items()) + list({ - 10: ['-/--', '-/--'], - 12: ['Standby', 'StBy'], - 32: ['Program up', 'P+'], - 33: ['Program down', 'P-'], - 50: ['Fast rewind', 'FRW'], - 52: ['Fast forward', 'FFW'], - 53: ['Play', 'Pl'], - 54: ['Stop', 'St'], - 55: ['Recording', 'Rec'], - }.items())), -} diff --git a/decoders/ir_rc5/pd.py b/decoders/ir_rc5/pd.py deleted file mode 100755 index e18a90bf..00000000 --- a/decoders/ir_rc5/pd.py +++ /dev/null @@ -1,187 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Uwe Hermann -## -## 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, see . -## - -import sigrokdecode as srd -from .lists import * - -class SamplerateError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = 'ir_rc5' - name = 'IR RC-5' - longname = 'IR RC-5' - desc = 'RC-5 infrared remote control protocol.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['IR'] - channels = ( - {'id': 'ir', 'name': 'IR', 'desc': 'IR data line'}, - ) - options = ( - {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-low', - 'values': ('active-low', 'active-high')}, - {'id': 'protocol', 'desc': 'Protocol type', 'default': 'standard', - 'values': ('standard', 'extended')}, - ) - annotations = ( - ('bit', 'Bit'), - ('startbit1', 'Startbit 1'), - ('startbit2', 'Startbit 2'), - ('togglebit-0', 'Toggle bit 0'), - ('togglebit-1', 'Toggle bit 1'), - ('address', 'Address'), - ('command', 'Command'), - ) - annotation_rows = ( - ('bits', 'Bits', (0,)), - ('fields', 'Fields', (1, 2, 3, 4, 5, 6)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.samplenum = None - self.edges, self.bits, self.ss_es_bits = [], [], [] - self.state = 'IDLE' - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.old_ir = 1 if self.options['polarity'] == 'active-low' else 0 - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - # One bit: 1.78ms (one half low, one half high). - self.halfbit = int((self.samplerate * 0.00178) / 2.0) - - def putb(self, bit1, bit2, data): - ss, es = self.ss_es_bits[bit1][0], self.ss_es_bits[bit2][1] - self.put(ss, es, self.out_ann, data) - - def handle_bits(self): - a, c, b = 0, 0, self.bits - # Individual raw bits. - for i in range(14): - if i == 0: - ss = max(0, self.bits[0][0] - self.halfbit) - else: - ss = self.ss_es_bits[i - 1][1] - es = self.bits[i][0] + self.halfbit - self.ss_es_bits.append([ss, es]) - self.putb(i, i, [0, ['%d' % self.bits[i][1]]]) - # Bits[0:0]: Startbit 1 - s = ['Startbit1: %d' % b[0][1], 'SB1: %d' % b[0][1], 'SB1', 'S1', 'S'] - self.putb(0, 0, [1, s]) - # Bits[1:1]: Startbit 2 - ann_idx = 2 - s = ['Startbit2: %d' % b[1][1], 'SB2: %d' % b[1][1], 'SB2', 'S2', 'S'] - if self.options['protocol'] == 'extended': - s = ['CMD[6]#: %d' % b[1][1], 'C6#: %d' % b[1][1], 'C6#', 'C#', 'C'] - ann_idx = 6 - self.putb(1, 1, [ann_idx, s]) - # Bits[2:2]: Toggle bit - s = ['Togglebit: %d' % b[2][1], 'Toggle: %d' % b[2][1], - 'TB: %d' % b[2][1], 'TB', 'T'] - self.putb(2, 2, [3 if b[2][1] == 0 else 4, s]) - # Bits[3:7]: Address (MSB-first) - for i in range(5): - a |= (b[3 + i][1] << (4 - i)) - x = system.get(a, ['Unknown', 'Unk']) - s = ['Address: %d (%s)' % (a, x[0]), 'Addr: %d (%s)' % (a, x[1]), - 'Addr: %d' % a, 'A: %d' % a, 'A'] - self.putb(3, 7, [5, s]) - # Bits[8:13]: Command (MSB-first) - for i in range(6): - c |= (b[8 + i][1] << (5 - i)) - if self.options['protocol'] == 'extended': - inverted_bit6 = 1 if b[1][1] == 0 else 0 - c |= (inverted_bit6 << 6) - cmd_type = 'VCR' if x[1] in ('VCR1', 'VCR2') else 'TV' - x = command[cmd_type].get(c, ['Unknown', 'Unk']) - s = ['Command: %d (%s)' % (c, x[0]), 'Cmd: %d (%s)' % (c, x[1]), - 'Cmd: %d' % c, 'C: %d' % c, 'C'] - self.putb(8, 13, [6, s]) - - def edge_type(self): - # Categorize according to distance from last edge (short/long). - distance = self.samplenum - self.edges[-1] - s, l, margin = self.halfbit, self.halfbit * 2, int(self.halfbit / 2) - if distance in range(l - margin, l + margin + 1): - return 'l' - elif distance in range(s - margin, s + margin + 1): - return 's' - else: - return 'e' # Error, invalid edge distance. - - def reset_decoder_state(self): - self.edges, self.bits, self.ss_es_bits = [], [], [] - self.state = 'IDLE' - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - while True: - - (self.ir,) = self.wait() - - # Wait for any edge (rising or falling). - if self.old_ir == self.ir: - continue - - # State machine. - if self.state == 'IDLE': - bit = 1 - self.edges.append(self.samplenum) - self.bits.append([self.samplenum, bit]) - self.state = 'MID1' - self.old_ir = self.ir - continue - edge = self.edge_type() - if edge == 'e': - self.reset_decoder_state() # Reset state machine upon errors. - continue - if self.state == 'MID1': - self.state = 'START1' if edge == 's' else 'MID0' - bit = None if edge == 's' else 0 - elif self.state == 'MID0': - self.state = 'START0' if edge == 's' else 'MID1' - bit = None if edge == 's' else 1 - elif self.state == 'START1': - if edge == 's': - self.state = 'MID1' - bit = 1 if edge == 's' else None - elif self.state == 'START0': - if edge == 's': - self.state = 'MID0' - bit = 0 if edge == 's' else None - - self.edges.append(self.samplenum) - if bit is not None: - self.bits.append([self.samplenum, bit]) - - if len(self.bits) == 14: - self.handle_bits() - self.reset_decoder_state() - - self.old_ir = self.ir diff --git a/decoders/ir_rc6/__init__.py b/decoders/ir_rc6/__init__.py deleted file mode 100644 index b2cb9f9a..00000000 --- a/decoders/ir_rc6/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Benedikt Otto -## -## 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, see . -## - -''' -RC-6 is a biphase/manchester based infrared remote control protocol. -''' - -from .pd import Decoder diff --git a/decoders/ir_rc6/pd.py b/decoders/ir_rc6/pd.py deleted file mode 100644 index e195dbd1..00000000 --- a/decoders/ir_rc6/pd.py +++ /dev/null @@ -1,205 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Benedikt Otto -## -## 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, see . -## - -import sigrokdecode as srd - -class SamplerateError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = 'ir_rc6' - name = 'IR RC-6' - longname = 'IR RC-6' - desc = 'RC-6 infrared remote control protocol.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['IR'] - channels = ( - {'id': 'ir', 'name': 'IR', 'desc': 'IR data line'}, - ) - options = ( - {'id': 'polarity', 'desc': 'Polarity', 'default': 'auto', - 'values': ('auto', 'active-low', 'active-high')}, - ) - annotations = ( - ('bit', 'Bit'), - ('sync', 'Sync'), - ('startbit', 'Startbit'), - ('field', 'Field'), - ('togglebit', 'Togglebit'), - ('address', 'Address'), - ('command', 'Command'), - ) - annotation_rows = ( - ('bits', 'Bits', (0,)), - ('fields', 'Fields', (1, 2, 3, 4, 5, 6)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.edges, self.deltas, self.bits = [], [], [] - self.state = 'IDLE' - self.mode = 0 - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - # One bit: 0.889ms (one half low, one half high). - self.halfbit = int((self.samplerate * 0.000889) / 2.0) - - def putb(self, bit, data): - self.put(bit[0], bit[1], self.out_ann, data) - - def putbits(self, bit1, bit2, data): - self.put(bit1[0], bit2[1], self.out_ann, data) - - def putx(self, ss, es, data): - self.put(ss, es, self.out_ann, data) - - def handle_bit(self): - if len(self.bits) != 6: - return - if self.bits[0][2] == 8 and self.bits[0][3] == 1: - self.putb(self.bits[0], [1, ['Synchronisation', 'Sync']]) - else: - return - if self.bits[1][3] == 1: - self.putb(self.bits[1], [2, ['Startbit', 'Start']]) - else: - return - self.mode = sum([self.bits[2 + i][3] << (2 - i) for i in range(3)]) - self.putbits(self.bits[2], self.bits[4], [3, ['Field: %d' % self.mode]]) - self.putb(self.bits[5], [4, ['Toggle: %d' % self.bits[5][3]]]) - - def handle_package(self): - # Sync and start bits have to be 1. - if self.bits[0][3] == 0 or self.bits[1][3] == 0: - return - if len(self.bits) <= 6: - return - - if self.mode == 0 and len(self.bits) == 22: # Mode 0 standard - value = sum([self.bits[6 + i][3] << (7 - i) for i in range(8)]) - self.putbits(self.bits[6], self.bits[13], [5, ['Address: %0.2X' % value]]) - - value = sum([self.bits[14 + i][3] << (7 - i) for i in range(8)]) - self.putbits(self.bits[14], self.bits[21], [6, ['Data: %0.2X' % value]]) - - self.bits = [] - - if self.mode == 6 and len(self.bits) >= 15: # Mode 6 - if self.bits[6][3] == 0: # Short addr, Mode 6A - value = sum([self.bits[6 + i][3] << (7 - i) for i in range(8)]) - self.putbits(self.bits[6], self.bits[13], [5, ['Address: %0.2X' % value]]) - - num_data_bits = len(self.bits) - 14 - value = sum([self.bits[14 + i][3] << (num_data_bits - 1 - i) for i in range(num_data_bits)]) - self.putbits(self.bits[14], self.bits[-1], [6, ['Data: %X' % value]]) - - self.bits = [] - - elif len(self.bits) >= 23: # Long addr, Mode 6B - value = sum([self.bits[6 + i][3] << (15 - i) for i in range(16)]) - self.putbits(self.bits[6], self.bits[21], [5, ['Address: %0.2X' % value]]) - - num_data_bits = len(self.bits) - 22 - value = sum([self.bits[22 + i][3] << (num_data_bits - 1 - i) for i in range(num_data_bits)]) - self.putbits(self.bits[22], self.bits[-1], [6, ['Data: %X' % value]]) - - self.bits = [] - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - value = 0 - num_edges = -1 - self.invert = False - - while True: - conditions = [{0: 'e'}] - if self.state == 'DATA': - conditions.append({'skip': self.halfbit * 6}) - (self.ir,) = self.wait(conditions) - - if len(conditions) == 2: - if self.matched[1]: - self.state = 'IDLE' - - self.edges.append(self.samplenum) - if len(self.edges) < 2: - continue - - delta = (self.edges[-1] - self.edges[-2]) / self.halfbit - delta = int(delta + 0.5) - self.deltas.append(delta) - - if len(self.deltas) < 2: - continue - - if self.deltas[-2:] == [6, 2]: - self.state = 'SYNC' - num_edges = 0 - self.bits = [] - - if self.options['polarity'] == 'auto': - value = 1 - else: - value = self.ir if self.options['polarity'] == 'active-high' else 1 - self.ir - - self.bits.append((self.edges[-3], self.edges[-1], 8, value)) - self.invert = self.ir == 0 - self.putb(self.bits[-1], [0, ['%d' % value]]) # Add bit. - - if (num_edges % 2) == 0: # Only count every second edge. - if self.deltas[-2] in [1, 2, 3] and self.deltas[-1] in [1, 2, 3, 6]: - self.state = 'DATA' - if self.deltas[-2] != self.deltas[-1]: - # Insert border between 2 bits. - self.edges.insert(-1, self.edges[-2] + self.deltas[-2] * self.halfbit) - total = self.deltas[-1] - self.deltas[-1] = self.deltas[-2] - self.deltas.append(total - self.deltas[-1]) - - self.bits.append((self.edges[-4], self.edges[-2], self.deltas[-2] * 2, value)) - - num_edges += 1 - else: - self.bits.append((self.edges[-3], self.edges[-1], self.deltas[-1] * 2, value)) - - self.putb(self.bits[-1], [0, ['%d' % value]]) # Add bit. - - if len(self.bits) > 0: - self.handle_bit() - if self.state == 'IDLE': - self.handle_package() - - if self.options['polarity'] == 'auto': - value = self.ir if self.invert else 1 - self.ir - else: - value = self.ir if self.options['polarity'] == 'active-low' else 1 - self.ir - - num_edges += 1 diff --git a/decoders/ir_sirc/__init__.py b/decoders/ir_sirc/__init__.py deleted file mode 100644 index 4061ed73..00000000 --- a/decoders/ir_sirc/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 Tom Flanagan -## -## 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, see . -## - -''' -Decoder for the Sony IR remote control protocol (SIRC). - -https://www.sbprojects.net/knowledge/ir/sirc.php -''' - -from .pd import Decoder diff --git a/decoders/ir_sirc/lists.py b/decoders/ir_sirc/lists.py deleted file mode 100644 index 5c6d8fa6..00000000 --- a/decoders/ir_sirc/lists.py +++ /dev/null @@ -1,201 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 Tom Flanagan -## -## 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, see . -## - -NUMBERS = { - 0x00: '1', - 0x01: '2', - 0x02: '3', - 0x03: '4', - 0x04: '5', - 0x05: '6', - 0x06: '7', - 0x07: '8', - 0x08: '9', - 0x09: '0/10', -} - -ADDRESSES = { - # TV - (0x01, None): (['TV: ', 'TV:'], { - 0x15: 'Power', - 0x25: 'Input', - - 0x33: 'Right', - 0x34: 'Left', - 0x3A: 'Display', - - 0x60: 'Home', - 0x65: 'Enter', - - 0x74: 'Up', - 0x75: 'Down', - - }), - - # Video - (0x0B, None): (['Video: ', 'V:'], { - 0x18: 'Stop', - 0x19: 'Pause', - 0x1A: 'Play', - 0x1B: 'Rewind', - 0x1C: 'Fast Forward', - - 0x42: 'Up', - 0x43: 'Down', - 0x4D: 'Home', - - 0x51: 'Enter', - 0x5A: 'Display', - - 0x61: 'Right', - 0x62: 'Left', - }), - - # BR Input select - (0x10, 0x28): (['BlueRay: ', 'BR:'], { - 0x16: 'BlueRay', - }), - - # Amp, Game, Sat, Tuner, USB - (0x10, 0x08): (['Playback: ', 'PB:'], { - 0x2A: 'Shuffle', - 0x2C: 'Repeat', - 0x2E: 'Folder Down', - 0x2F: 'Folder Up', - - 0x30: 'Previous', - 0x31: 'Next', - 0x32: 'Play', - 0x33: 'Rewind', - 0x34: 'Fast Forward', - 0x38: 'Stop', - 0x39: 'Pause', - - 0x73: 'Options', - 0x7D: 'Return', - }), - - # CD - (0x11, None): (['CD: ', 'CD:'], { - 0x28: 'Display', - - 0x30: 'Previous', - 0x31: 'Next', - 0x32: 'Play', - 0x33: 'Rewind', - 0x34: 'Fast Forward', - 0x38: 'Stop', - 0x39: 'Pause', - }), - - # BD - (0x1A, 0xE2): (['BlueRay: ', 'BD:'], { - 0x18: 'Stop', - 0x19: 'Pause', - 0x1A: 'Play', - 0x1B: 'Rewind', - 0x1C: 'Fast Forward', - - 0x29: 'Menu', - 0x2C: 'Top Menu', - - 0x39: 'Up', - 0x3A: 'Down', - 0x3B: 'Left', - 0x3C: 'Right', - 0x3D: 'Enter', - 0x3F: 'Options', - - 0x41: 'Display', - 0x42: 'Home', - 0x43: 'Return', - - 0x56: 'Next', - 0x57: 'Previous', - }), - - # DVD - (0x1A, 0x49): (['DVD: ', 'DVD:'], { - 0x0B: 'Enter', - 0x0E: 'Return', - 0x17: 'Options', - - 0x1A: 'Top Menu', - 0x1B: 'Menu', - - 0x30: 'Previous', - 0x31: 'Next', - 0x32: 'Play', - 0x33: 'Rewind', - 0x34: 'Fast Forward', - 0x38: 'Stop', - 0x39: 'Pause', - - 0x54: 'Display', - - 0x7B: 'Left', - 0x7C: 'Right', - 0x79: 'Up', - 0x7A: 'Down', - }), - - # Amp, Game, Sat, Tuner, USB modes - (0x30, None): (['Keypad: ', 'KP:'], { - 0x0C: 'Enter', - - 0x12: 'Volume Up', - 0x13: 'Volume Down', - 0x14: 'Mute', - 0x15: 'Power', - - 0x21: 'Tuner', - 0x22: 'Video', - 0x25: 'CD', - - 0x4D: 'Home', - 0x4B: 'Display', - - 0x60: 'Sleep', - 0x6A: 'TV', - - 0x53: 'Home', - - 0x7C: 'Game', - 0x7D: 'DVD', - }), - - # Amp, Game, Sat, Tuner, USB modes - (0xB0, None): (['Arrows: ', 'Ar:'], { - 0x7A: 'Left', - 0x7B: 'Right', - 0x78: 'Up', - 0x79: 'Down', - 0x77: 'Amp Menu', - }), - - # TV mode - (0x97, None): (['TV Extra', 'TV:'], { - 0x23: 'Return', - 0x36: 'Options', - - }), -} - -for (address, extended), (name, commands) in ADDRESSES.items(): - commands.update(NUMBERS) diff --git a/decoders/ir_sirc/pd.py b/decoders/ir_sirc/pd.py deleted file mode 100644 index 14ba63f0..00000000 --- a/decoders/ir_sirc/pd.py +++ /dev/null @@ -1,215 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 Tom Flanagan -## -## 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, see . -## - -from common.srdhelper import bitpack_lsb -from .lists import ADDRESSES -import sigrokdecode as srd - -class SamplerateError(Exception): - pass - -class SIRCError(Exception): - pass - -class SIRCErrorSilent(SIRCError): - pass - -class Ann: - BIT, AGC, PAUSE, START, CMD, ADDR, EXT, REMOTE, WARN = range(9) - -AGC_USEC = 2400 -ONE_USEC = 1200 -ZERO_USEC = 600 -PAUSE_USEC = 600 - -class Decoder(srd.Decoder): - api_version = 3 - id = 'ir_sirc' - name = 'IR SIRC' - longname = 'Sony IR (SIRC)' - desc = 'Sony infrared remote control protocol (SIRC).' - license = 'gplv2+' - tags = ['IR'] - inputs = ['logic'] - outputs = [] - channels = ( - {'id': 'ir', 'name': 'IR', 'desc': 'IR data line'}, - ) - options = ( - {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-low', - 'values': ('active-low', 'active-high')}, - ) - annotations = ( - ('bit', 'Bit'), - ('agc', 'AGC'), - ('pause', 'Pause'), - ('start', 'Start'), - ('command', 'Command'), - ('address', 'Address'), - ('extended', 'Extended'), - ('remote', 'Remote'), - ('warning', 'Warning'), - ) - annotation_rows = ( - ('bits', 'Bits', (Ann.BIT, Ann.AGC, Ann.PAUSE)), - ('fields', 'Fields', (Ann.START, Ann.CMD, Ann.ADDR, Ann.EXT)), - ('remotes', 'Remotes', (Ann.REMOTE,)), - ('warnings', 'Warnings', (Ann.WARN,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - pass - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.active = self.options['polarity'] == 'active-high' - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - self.snum_per_us = self.samplerate / 1e6 - - def putg(self, ss, es, cls, texts): - self.put(ss, es, self.out_ann, [cls, texts]) - - def tolerance(self, ss, es, expected): - microseconds = (es - ss) / self.snum_per_us - tolerance = expected * 0.30 - return (expected - tolerance) < microseconds < (expected + tolerance) - - def wait_wrap(self, conds, timeout): - if timeout is not None: - to = int(timeout * self.snum_per_us) - conds.append({'skip': to}) - ss = self.samplenum - pins = self.wait(conds) - es = self.samplenum - return pins, ss, es, self.matched - - def read_pulse(self, high, time): - e = 'f' if high else 'r' - max_time = int(time * 1.30) - (ir,), ss, es, (edge, timeout) = self.wait_wrap([{0: e}], max_time) - if timeout or not self.tolerance(ss, es, time): - raise SIRCError('Timeout') - return ir, ss, es, (edge, timeout) - - def read_bit(self): - e = 'f' if self.active else 'r' - _, high_ss, high_es, (edge, timeout) = self.wait_wrap([{0: e}], 2000) - if timeout: - raise SIRCError('Bit High Timeout') - if self.tolerance(high_ss, high_es, ONE_USEC): - bit = 1 - elif self.tolerance(high_ss, high_es, ZERO_USEC): - bit = 0 - else: - raise SIRCError('Bit Low Timeout') - try: - _, low_ss, low_es, _ = self.read_pulse(not self.active, PAUSE_USEC) - good = True - except SIRCError: - low_es = high_es + int(PAUSE_USEC * self.snum_per_us) - good = False - self.putg(high_ss, low_es, Ann.BIT, ['{}'.format(bit)]) - return bit, high_ss, low_es, good - - def read_signal(self): - # Start code - try: - _, agc_ss, agc_es, _ = self.read_pulse(self.active, AGC_USEC) - _, pause_ss, pause_es, _ = self.read_pulse(not self.active, PAUSE_USEC) - except SIRCError: - raise SIRCErrorSilent('not an SIRC message') - self.putg(agc_ss, agc_es, Ann.AGC, ['AGC', 'A']) - self.putg(pause_ss, pause_es, Ann.PAUSE, ['Pause', 'P']) - self.putg(agc_ss, pause_es, Ann.START, ['Start', 'S']) - - # Read bits - bits = [] - while True: - bit, ss, es, good = self.read_bit() - bits.append((bit, ss, es)) - if len(bits) > 20: - raise SIRCError('too many bits') - if not good: - if len(bits) == 12: - command = bits[0:7] - address = bits[7:12] - extended = [] - elif len(bits) == 15: - command = bits[0:7] - address = bits[7:15] - extended = [] - elif len(bits) == 20: - command = bits[0:7] - address = bits[7:12] - extended = bits[12:20] - else: - raise SIRCError('incorrect bits count {}'.format(len(bits))) - break - - command_num = bitpack_lsb(command, 0) - address_num = bitpack_lsb(address, 0) - command_str = '0x{:02X}'.format(command_num) - address_str = '0x{:02X}'.format(address_num) - self.putg(command[0][1], command[-1][2], Ann.CMD, [ - 'Command: {}'.format(command_str), - 'C:{}'.format(command_str), - ]) - self.putg(address[0][1], address[-1][2], Ann.ADDR, [ - 'Address: {}'.format(address_str), - 'A:{}'.format(address_str), - ]) - extended_num = None - if extended: - extended_num = bitpack_lsb(extended, 0) - extended_str = '0x{:02X}'.format(extended_num) - self.putg(extended[0][1], extended[-1][2], Ann.EXT, [ - 'Extended: {}'.format(extended_str), - 'E:{}'.format(extended_str), - ]) - return address_num, command_num, extended_num, bits[0][1], bits[-1][2] - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - - unknown = (['Unknown Device: ', 'UNK: '], {}) - while True: - e = 'h' if self.active else 'l' - _, _, frame_ss, _ = self.wait_wrap([{0: e}], None) - try: - addr, cmd, ext, payload_ss, payload_es = self.read_signal() - names, cmds = ADDRESSES.get((addr, ext), unknown) - text = cmds.get(cmd, 'Unknown') - self.putg(frame_ss, payload_es, Ann.REMOTE, [ - n + text for n in names - ]) - except SIRCErrorSilent as e: - pass - except SIRCError as e: - self.putg(frame_ss, self.samplenum, Ann.WARN, [ - 'Error: {}'.format(e), - 'Error', - 'E', - ]) diff --git a/decoders/jitter/__init__.py b/decoders/jitter/__init__.py deleted file mode 100755 index 3394ad75..00000000 --- a/decoders/jitter/__init__.py +++ /dev/null @@ -1,29 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Sebastien Bourdelin -## -## 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, see . -## - -''' -This protocol decoder retrieves the timing jitter between two digital signals. - -It allows to define a clock source channel and a resulting signal channel. - -Each time a significant edge is detected in the clock source, we calculate the -elapsed time before the resulting signal answers and report the timing jitter. -''' - -from .pd import Decoder diff --git a/decoders/jitter/pd.py b/decoders/jitter/pd.py deleted file mode 100755 index 8ea1aa67..00000000 --- a/decoders/jitter/pd.py +++ /dev/null @@ -1,198 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Sebastien Bourdelin -## -## 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, see . -## - -import sigrokdecode as srd - -# Helper dictionary for edge detection. -edge_detector = { - 'rising': lambda x, y: bool(not x and y), - 'falling': lambda x, y: bool(x and not y), - 'both': lambda x, y: bool(x ^ y), -} - -class SamplerateError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = 'jitter' - name = 'Jitter' - longname = 'Timing jitter calculation' - desc = 'Retrieves the timing jitter between two digital signals.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Clock/timing', 'Util'] - channels = ( - {'id': 'clk', 'name': 'Clock', 'desc': 'Clock reference channel'}, - {'id': 'sig', 'name': 'Resulting signal', 'desc': 'Resulting signal controlled by the clock'}, - ) - options = ( - {'id': 'clk_polarity', 'desc': 'Clock edge polarity', - 'default': 'rising', 'values': ('rising', 'falling', 'both')}, - {'id': 'sig_polarity', 'desc': 'Resulting signal edge polarity', - 'default': 'rising', 'values': ('rising', 'falling', 'both')}, - ) - annotations = ( - ('jitter', 'Jitter value'), - ('clk_missed', 'Clock missed'), - ('sig_missed', 'Signal missed'), - ) - annotation_rows = ( - ('jitter', 'Jitter values', (0,)), - ('clk_missed', 'Clock missed', (1,)), - ('sig_missed', 'Signal missed', (2,)), - ) - binary = ( - ('ascii-float', 'Jitter values as newline-separated ASCII floats'), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.state = 'CLK' - self.samplerate = None - self.oldclk, self.oldsig = 0, 0 - self.clk_start = None - self.sig_start = None - self.clk_missed = 0 - self.sig_missed = 0 - - def start(self): - self.clk_edge = edge_detector[self.options['clk_polarity']] - self.sig_edge = edge_detector[self.options['sig_polarity']] - self.out_ann = self.register(srd.OUTPUT_ANN) - self.out_binary = self.register(srd.OUTPUT_BINARY) - self.out_clk_missed = self.register(srd.OUTPUT_META, - meta=(int, 'Clock missed', 'Clock transition missed')) - self.out_sig_missed = self.register(srd.OUTPUT_META, - meta=(int, 'Signal missed', 'Resulting signal transition missed')) - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - # Helper function for jitter time annotations. - def putx(self, delta): - # Adjust granularity. - if delta == 0 or delta >= 1: - delta_s = '%.1fs' % (delta) - elif delta <= 1e-12: - delta_s = '%.1ffs' % (delta * 1e15) - elif delta <= 1e-9: - delta_s = '%.1fps' % (delta * 1e12) - elif delta <= 1e-6: - delta_s = '%.1fns' % (delta * 1e9) - elif delta <= 1e-3: - delta_s = '%.1fμs' % (delta * 1e6) - else: - delta_s = '%.1fms' % (delta * 1e3) - - self.put(self.clk_start, self.sig_start, self.out_ann, [0, [delta_s]]) - - # Helper function for ASCII float jitter values (one value per line). - def putb(self, delta): - if delta is None: - return - # Format the delta to an ASCII float value terminated by a newline. - x = str(delta) + '\n' - self.put(self.clk_start, self.sig_start, self.out_binary, - [0, x.encode('UTF-8')]) - - # Helper function for missed clock and signal annotations. - def putm(self, data): - self.put(self.samplenum, self.samplenum, self.out_ann, data) - - def handle_clk(self, clk, sig): - if self.clk_start == self.samplenum: - # Clock transition already treated. - # We have done everything we can with this sample. - return True - - if self.clk_edge(self.oldclk, clk): - # Clock edge found. - # We note the sample and move to the next state. - self.clk_start = self.samplenum - self.state = 'SIG' - return False - else: - if self.sig_start is not None \ - and self.sig_start != self.samplenum \ - and self.sig_edge(self.oldsig, sig): - # If any transition in the resulting signal - # occurs while we are waiting for a clock, - # we increase the missed signal counter. - self.sig_missed += 1 - self.put(self.samplenum, self.samplenum, self.out_sig_missed, self.sig_missed) - self.putm([2, ['Missed signal', 'MS']]) - # No clock edge found, we have done everything we - # can with this sample. - return True - - def handle_sig(self, clk, sig): - if self.sig_start == self.samplenum: - # Signal transition already treated. - # We have done everything we can with this sample. - return True - - if self.sig_edge(self.oldsig, sig): - # Signal edge found. - # We note the sample, calculate the jitter - # and move to the next state. - self.sig_start = self.samplenum - self.state = 'CLK' - # Calculate and report the timing jitter. - delta = (self.sig_start - self.clk_start) / self.samplerate - self.putx(delta) - self.putb(delta) - return False - else: - if self.clk_start != self.samplenum \ - and self.clk_edge(self.oldclk, clk): - # If any transition in the clock signal - # occurs while we are waiting for a resulting - # signal, we increase the missed clock counter. - self.clk_missed += 1 - self.put(self.samplenum, self.samplenum, self.out_clk_missed, self.clk_missed) - self.putm([1, ['Missed clock', 'MC']]) - # No resulting signal edge found, we have done - # everything we can with this sample. - return True - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - while True: - # Wait for a transition on CLK and/or SIG. - (clk, sig) = self.wait([{0: 'e'}, {1: 'e'}]) - - # State machine: - # For each sample we can move 2 steps forward in the state machine. - while True: - # Clock state has the lead. - if self.state == 'CLK': - if self.handle_clk(clk, sig): - break - if self.state == 'SIG': - if self.handle_sig(clk, sig): - break - - # Save current CLK/SIG values for the next round. - self.oldclk, self.oldsig = clk, sig diff --git a/decoders/jtag/__init__.py b/decoders/jtag/__init__.py deleted file mode 100755 index 51bb6299..00000000 --- a/decoders/jtag/__init__.py +++ /dev/null @@ -1,30 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -''' -JTAG (Joint Test Action Group), a.k.a. "IEEE 1149.1: Standard Test Access Port -and Boundary-Scan Architecture", is a protocol used for testing, debugging, -and flashing various digital ICs. - -Details: -https://en.wikipedia.org/wiki/Joint_Test_Action_Group -http://focus.ti.com/lit/an/ssya002c/ssya002c.pdf -''' - -from .pd import Decoder diff --git a/decoders/jtag/pd.py b/decoders/jtag/pd.py deleted file mode 100755 index e9c629b6..00000000 --- a/decoders/jtag/pd.py +++ /dev/null @@ -1,289 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012-2015 Uwe Hermann -## Copyright (C) 2019 DreamSourceLab -## -## Version: -## Modified by Shiqiu Nie(369614718@qq.com) -## Date: 2017-01-11 -## Descript: -## 1. 2017-01-10 Fixed TDI/TDO data decode, when JTAG TAP run into -## SHIFT-IR/SHIFT-DR status,the first bit is not a valid bit. -## 2. 2017-01-11 Fixed decode when shift only one bit. -## -## 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, see . -## - -import sigrokdecode as srd - -''' -OUTPUT_PYTHON format: - -Packet: -[, ] - -: - - 'NEW STATE': is the new state of the JTAG state machine. - Valid values: 'TEST-LOGIC-RESET', 'RUN-TEST/IDLE', 'SELECT-DR-SCAN', - 'CAPTURE-DR', 'SHIFT-DR', 'EXIT1-DR', 'PAUSE-DR', 'EXIT2-DR', 'UPDATE-DR', - 'SELECT-IR-SCAN', 'CAPTURE-IR', 'SHIFT-IR', 'EXIT1-IR', 'PAUSE-IR', - 'EXIT2-IR', 'UPDATE-IR'. - - 'IR TDI': Bitstring that was clocked into the IR register. - - 'IR TDO': Bitstring that was clocked out of the IR register. - - 'DR TDI': Bitstring that was clocked into the DR register. - - 'DR TDO': Bitstring that was clocked out of the DR register. - -All bitstrings are a list consisting of two items. The first is a sequence -of '1' and '0' characters (the right-most character is the LSB. Example: -'01110001', where 1 is the LSB). The second item is a list of ss/es values -for each bit that is in the bitstring. -''' - -jtag_states = [ - # Intro "tree" - 'TEST-LOGIC-RESET', 'RUN-TEST/IDLE', - # DR "tree" - 'SELECT-DR-SCAN', 'CAPTURE-DR', 'UPDATE-DR', 'PAUSE-DR', - 'SHIFT-DR', 'EXIT1-DR', 'EXIT2-DR', - # IR "tree" - 'SELECT-IR-SCAN', 'CAPTURE-IR', 'UPDATE-IR', 'PAUSE-IR', - 'SHIFT-IR', 'EXIT1-IR', 'EXIT2-IR', -] - -class Decoder(srd.Decoder): - api_version = 3 - id = 'jtag' - name = 'JTAG' - longname = 'Joint Test Action Group (IEEE 1149.1)' - desc = 'Protocol for testing, debugging, and flashing ICs.' - license = 'gplv2+' - inputs = ['logic'] - outputs = ['jtag'] - tags = ['Debug/trace'] - channels = ( - {'id': 'tdi', 'name': 'TDI', 'desc': 'Test data input'}, - {'id': 'tdo', 'name': 'TDO', 'desc': 'Test data output'}, - {'id': 'tck', 'name': 'TCK', 'desc': 'Test clock'}, - {'id': 'tms', 'name': 'TMS', 'desc': 'Test mode select'}, - ) - optional_channels = ( - {'id': 'trst', 'name': 'TRST#', 'desc': 'Test reset'}, - {'id': 'srst', 'name': 'SRST#', 'desc': 'System reset'}, - {'id': 'rtck', 'name': 'RTCK', 'desc': 'Return clock signal'}, - ) - annotations = tuple([tuple([s.lower(), s]) for s in jtag_states]) + ( \ - ('bit-tdi', 'Bit (TDI)'), - ('bit-tdo', 'Bit (TDO)'), - ('bitstring-tdi', 'Bitstring (TDI)'), - ('bitstring-tdo', 'Bitstring (TDO)'), - ) - annotation_rows = ( - ('bits-tdi', 'Bits (TDI)', (16,)), - ('bits-tdo', 'Bits (TDO)', (17,)), - ('bitstrings-tdi', 'Bitstring (TDI)', (18,)), - ('bitstrings-tdo', 'Bitstring (TDO)', (19,)), - ('states', 'States', tuple(range(15 + 1))), - ) - - def __init__(self): - self.reset() - - def reset(self): - # self.state = 'TEST-LOGIC-RESET' - self.state = 'RUN-TEST/IDLE' - self.oldstate = None - self.bits_tdi = [] - self.bits_tdo = [] - self.bits_samplenums_tdi = [] - self.bits_samplenums_tdo = [] - self.ss_item = self.es_item = None - self.ss_bitstring = self.es_bitstring = None - self.saved_item = None - self.first = True - self.first_bit = True - self.bits_cnt = 0 - self.data_ready = False - - def start(self): - self.out_python = self.register(srd.OUTPUT_PYTHON) - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putx(self, data): - self.put(self.ss_item, self.es_item, self.out_ann, data) - - def putp(self, data): - self.put(self.ss_item, self.es_item, self.out_python, data) - - def putx_bs(self, data): - self.put(self.ss_bitstring, self.es_bitstring, self.out_ann, data) - - def putp_bs(self, data): - self.put(self.ss_bitstring, self.es_bitstring, self.out_python, data) - - def advance_state_machine(self, tms): - self.oldstate = self.state - - # Intro "tree" - if self.state == 'TEST-LOGIC-RESET': - self.state = 'TEST-LOGIC-RESET' if (tms) else 'RUN-TEST/IDLE' - elif self.state == 'RUN-TEST/IDLE': - self.state = 'SELECT-DR-SCAN' if (tms) else 'RUN-TEST/IDLE' - - # DR "tree" - elif self.state == 'SELECT-DR-SCAN': - self.state = 'SELECT-IR-SCAN' if (tms) else 'CAPTURE-DR' - elif self.state == 'CAPTURE-DR': - self.state = 'EXIT1-DR' if (tms) else 'SHIFT-DR' - elif self.state == 'SHIFT-DR': - self.state = 'EXIT1-DR' if (tms) else 'SHIFT-DR' - elif self.state == 'EXIT1-DR': - self.state = 'UPDATE-DR' if (tms) else 'PAUSE-DR' - elif self.state == 'PAUSE-DR': - self.state = 'EXIT2-DR' if (tms) else 'PAUSE-DR' - elif self.state == 'EXIT2-DR': - self.state = 'UPDATE-DR' if (tms) else 'SHIFT-DR' - elif self.state == 'UPDATE-DR': - self.state = 'SELECT-DR-SCAN' if (tms) else 'RUN-TEST/IDLE' - - # IR "tree" - elif self.state == 'SELECT-IR-SCAN': - self.state = 'TEST-LOGIC-RESET' if (tms) else 'CAPTURE-IR' - elif self.state == 'CAPTURE-IR': - self.state = 'EXIT1-IR' if (tms) else 'SHIFT-IR' - elif self.state == 'SHIFT-IR': - self.state = 'EXIT1-IR' if (tms) else 'SHIFT-IR' - elif self.state == 'EXIT1-IR': - self.state = 'UPDATE-IR' if (tms) else 'PAUSE-IR' - elif self.state == 'PAUSE-IR': - self.state = 'EXIT2-IR' if (tms) else 'PAUSE-IR' - elif self.state == 'EXIT2-IR': - self.state = 'UPDATE-IR' if (tms) else 'SHIFT-IR' - elif self.state == 'UPDATE-IR': - self.state = 'SELECT-DR-SCAN' if (tms) else 'RUN-TEST/IDLE' - - def handle_rising_tck_edge(self, tdi, tdo, tck, tms, trst, srst, rtck): - # Rising TCK edges always advance the state machine. - self.advance_state_machine(tms) - - if self.first: - # Save the start sample and item for later (no output yet). - self.ss_item = self.samplenum - self.first = False - else: - # Output the saved item (from the last CLK edge to the current). - self.es_item = self.samplenum - # Output the old state (from last rising TCK edge to current one). - self.putx([jtag_states.index(self.oldstate), [self.oldstate]]) - self.putp(['NEW STATE', self.state]) - - # Upon SHIFT-IR/SHIFT-DR collect the current TDI/TDO values. - if self.state.startswith('SHIFT-'): - #if self.first_bit: - #self.ss_bitstring = self.samplenum - # self.first_bit = False - - #else: - if self.bits_cnt > 0: - if self.bits_cnt == 1: - self.ss_bitstring = self.samplenum - - if self.bits_cnt > 1: - self.putx([16, [str(self.bits_tdi[0])]]) - self.putx([17, [str(self.bits_tdo[0])]]) - # Use self.samplenum as ES of the previous bit. - self.bits_samplenums_tdi[0][1] = self.samplenum - self.bits_samplenums_tdo[0][1] = self.samplenum - - self.bits_tdi.insert(0, tdi) - self.bits_tdo.insert(0, tdo) - - # Use self.samplenum as SS of the current bit. - self.bits_samplenums_tdi.insert(0, [self.samplenum, -1]) - self.bits_samplenums_tdo.insert(0, [self.samplenum, -1]) - - self.bits_cnt = self.bits_cnt + 1 - - # Output all TDI/TDO bits if we just switched from SHIFT-* to EXIT1-*. - if self.oldstate.startswith('SHIFT-') and \ - self.state.startswith('EXIT1-'): - - #self.es_bitstring = self.samplenum - if self.bits_cnt > 0: - if self.bits_cnt == 1: # Only shift one bit - self.ss_bitstring = self.samplenum - self.bits_tdi.insert(0, tdi) - self.bits_tdo.insert(0, tdo) - ## Use self.samplenum as SS of the current bit. - self.bits_samplenums_tdi.insert(0, [self.samplenum, -1]) - self.bits_samplenums_tdo.insert(0, [self.samplenum, -1]) - else: - ### ---------------------------------------------------------------- - self.putx([16, [str(self.bits_tdi[0])]]) - self.putx([17, [str(self.bits_tdo[0])]]) - ### Use self.samplenum as ES of the previous bit. - self.bits_samplenums_tdi[0][1] = self.samplenum - self.bits_samplenums_tdo[0][1] = self.samplenum - - self.bits_tdi.insert(0, tdi) - self.bits_tdo.insert(0, tdo) - - ## Use self.samplenum as SS of the current bit. - self.bits_samplenums_tdi.insert(0, [self.samplenum, -1]) - self.bits_samplenums_tdo.insert(0, [self.samplenum, -1]) - ## ---------------------------------------------------------------- - - self.data_ready = True - - self.first_bit = True - self.bits_cnt = 0 - if self.oldstate.startswith('EXIT'):# and \ - #self.state.startswith('PAUSE-'): - if self.data_ready: - self.data_ready = False - self.es_bitstring = self.samplenum - t = self.state[-2:] + ' TDI' - b = ''.join(map(str, self.bits_tdi)) - h = ' (0x%X' % int('0b' + b, 2) + ')' - s = t + ': ' + h + ', ' + str(len(self.bits_tdi)) + ' bits' #b + - self.putx_bs([18, [s]]) - self.bits_samplenums_tdi[0][1] = self.samplenum # ES of last bit. - self.putp_bs([t, [b, self.bits_samplenums_tdi]]) - self.putx([16, [str(self.bits_tdi[0])]]) # Last bit. - self.bits_tdi = [] - self.bits_samplenums_tdi = [] - - t = self.state[-2:] + ' TDO' - b = ''.join(map(str, self.bits_tdo)) - h = ' (0x%X' % int('0b' + b, 2) + ')' - s = t + ': ' + h + ', ' + str(len(self.bits_tdo)) + ' bits' #+ b - self.putx_bs([19, [s]]) - self.bits_samplenums_tdo[0][1] = self.samplenum # ES of last bit. - self.putp_bs([t, [b, self.bits_samplenums_tdo]]) - self.putx([17, [str(self.bits_tdo[0])]]) # Last bit. - self.bits_tdo = [] - self.bits_samplenums_tdo = [] - - #self.first_bit = True - #self.bits_cnt = 0 - - #self.ss_bitstring = self.samplenum - - self.ss_item = self.samplenum - - def decode(self): - while True: - # Wait for a rising edge on TCK. - (tdi, tdo, tck, tms, trst, srst, rtck) = self.wait({2: 'r'}) - self.handle_rising_tck_edge(tdi, tdo, tck, tms, trst, srst, rtck) diff --git a/decoders/jtag_ejtag/__init__.py b/decoders/jtag_ejtag/__init__.py deleted file mode 100755 index 1c66dcd5..00000000 --- a/decoders/jtag_ejtag/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Vladislav Ivanov -## -## 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, see . -## - -''' -This decoder stacks on top of the 'jtag' PD and decodes JTAG data specific -to the MIPS EJTAG protocol. -''' - -from .pd import Decoder diff --git a/decoders/jtag_ejtag/pd.py b/decoders/jtag_ejtag/pd.py deleted file mode 100755 index f16f0b4e..00000000 --- a/decoders/jtag_ejtag/pd.py +++ /dev/null @@ -1,408 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Vladislav Ivanov -## -## 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, see . -## - -import sigrokdecode as srd -from common.srdhelper import bin2int - -class Instruction(object): - IDCODE = 0x01 - IMPCODE = 0x03 - ADDRESS = 0x08 - DATA = 0x09 - CONTROL = 0x0A - ALL = 0x0B - EJTAGBOOT = 0x0C - NORMALBOOT = 0x0D - FASTDATA = 0x0E - TCBCONTROLA = 0x10 - TCBCONTROLB = 0x11 - TCBDATA = 0x12 - TCBCONTROLC = 0x13 - PCSAMPLE = 0x14 - TCBCONTROLD = 0x15 - TCBCONTROLE = 0x16 - -class State(object): - RESET = 0 - DEVICE_ID = 1 - IMPLEMENTATION = 2 - DATA = 3 - ADDRESS = 4 - CONTROL = 5 - FASTDATA = 6 - PC_SAMPLE = 7 - BYPASS = 8 - -class ControlReg(object): - PRACC = (1 << 18) - PRNW = (1 << 19) - -class Ann(object): - INSTRUCTION = 0 - REGISTER = 1 - CONTROL_FIELD_IN = 10 - CONTROL_FIELD_OUT = 11 - PRACC = 12 - -ejtag_insn = { - 0x00: ['Free', 'Boundary scan'], - 0x01: ['IDCODE', 'Select Device Identification (ID) register'], - 0x02: ['Free', 'Boundary scan'], - 0x03: ['IMPCODE', 'Select Implementation register'], - 0x08: ['ADDRESS', 'Select Address register'], - 0x09: ['DATA', 'Select Data register'], - 0x0A: ['CONTROL', 'Select EJTAG Control register'], - 0x0B: ['ALL', 'Select the Address, Data and EJTAG Control registers'], - 0x0C: ['EJTAGBOOT', 'Fetch code from the debug exception vector after reset'], - 0x0D: ['NORMALBOOT', 'Execute the reset handler after reset'], - 0x0E: ['FASTDATA', 'Select the Data and Fastdata registers'], - 0x0F: ['Reserved', 'Reserved'], - 0x10: ['TCBCONTROLA', 'Select the control register TCBTraceControl'], - 0x11: ['TCBCONTROLB', 'Selects trace control block register B'], - 0x12: ['TCBDATA', 'Access the registers specified by TCBCONTROLB'], - 0x13: ['TCBCONTROLC', 'Select trace control block register C'], - 0x14: ['PCSAMPLE', 'Select the PCsample register'], - 0x15: ['TCBCONTROLD', 'Select trace control block register D'], - 0x16: ['TCBCONTROLE', 'Select trace control block register E'], - 0x17: ['FDC', 'Select Fast Debug Channel'], - 0x1C: ['Free', 'Boundary scan'], -} - -ejtag_reg = { - 0x00: 'RESET', - 0x01: 'DEVICE_ID', - 0x02: 'IMPLEMENTATION', - 0x03: 'DATA', - 0x04: 'ADDRESS', - 0x05: 'CONTROL', - 0x06: 'FASTDATA', - 0x07: 'PC_SAMPLE', - 0x08: 'BYPASS', -} - -ejtag_control_reg = [ - [31, 31, 'Rocc', [ - # Read - ['No reset ocurred', 'Reset ocurred'], - # Write - ['Acknowledge reset', 'No effect'], - ]], - [30, 29, 'Psz', [ - ['Access: byte', 'Access: halfword', 'Access: word', 'Access: triple'], - ]], - [23, 23, 'VPED', [ - ['VPE disabled', 'VPE enabled'], - ]], - [22, 22, 'Doze', [ - ['Processor is not in low-power mode', 'Processor is in low-power mode'], - ]], - [21, 21, 'Halt', [ - ['Internal system bus clock is running', 'Internal system bus clock is stopped'], - ]], - [20, 20, 'Per Rst', [ - ['No peripheral reset applied', 'Peripheral reset applied'], - ['Deassert peripheral reset', 'Assert peripheral reset'], - ]], - [19, 19, 'PRn W', [ - ['Read processor access', 'Write processor access'], - ]], - [18, 18, 'Pr Acc', [ - ['No pending processor access', 'Pending processor access'], - ['Finish processor access', 'Don\'t finish processor access'], - ]], - [16, 16, 'Pr Rst', [ - ['No processor reset applied', 'Processor reset applied'], - ['Deassert processor reset', 'Assert system reset'], - ]], - [15, 15, 'Prob En', [ - ['Probe will not serve processor accesses', 'Probe will service processor accesses'], - ]], - [14, 14, 'Prob Trap', [ - ['Default location', 'DMSEG fetch'], - ['Set to default location', 'Set to DMSEG fetch'], - ]], - [13, 13, 'ISA On Debug', [ - ['MIPS32/MIPS64 ISA', 'microMIPS ISA'], - ['Set to MIPS32/MIPS64 ISA', 'Set to microMIPS ISA'], - ]], - [12, 12, 'EJTAG Brk', [ - ['No pending debug interrupt', 'Pending debug interrupt'], - ['No effect', 'Request debug interrupt'], - ]], - [3, 3, 'DM', [ - ['Not in debug mode', 'In debug mode'], - ]], -] - -ejtag_state_map = { - Instruction.IDCODE: State.DEVICE_ID, - Instruction.IMPCODE: State.IMPLEMENTATION, - Instruction.DATA: State.DATA, - Instruction.ADDRESS: State.ADDRESS, - Instruction.CONTROL: State.CONTROL, - Instruction.FASTDATA: State.FASTDATA, -} - -class RegData(object): - def __init__(self): - self.ss = None - self.es = None - self.data = None - -class LastData(object): - def __init__(self): - self.data_in = RegData() - self.data_out = RegData() - -class PraccState(object): - def reset(self): - self.address_in = None - self.address_out = None - self.data_in = None - self.data_out = None - self.write = False - self.ss = 0 - self.es = 0 - - def __init__(self): - self.reset() - -regs_items = { - 'ann': tuple([tuple([s.lower(), s]) for s in list(ejtag_reg.values())]), - 'rows_range': tuple(range(1, 1 + 9)), -} - -class Decoder(srd.Decoder): - api_version = 3 - id = 'jtag_ejtag' - name = 'JTAG / EJTAG' - longname = 'Joint Test Action Group / EJTAG (MIPS)' - desc = 'MIPS EJTAG protocol.' - license = 'gplv2+' - inputs = ['jtag'] - outputs = [] - tags = ['Debug/trace'] - annotations = ( - ('instruction', 'Instruction'), - ) + regs_items['ann'] + ( - ('control_field_in', 'Control field in'), - ('control_field_out', 'Control field out'), - ('pracc', 'PrAcc'), - ) - annotation_rows = ( - ('instructions', 'Instructions', (0,)), - ('regs', 'Registers', regs_items['rows_range']), - ('control_fields_in', 'Control fields in', (10,)), - ('control_fields_out', 'Control fields out', (11,)), - ('pracc', 'PrAcc', (12,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.state = State.RESET - self.pracc_state = PraccState() - - def put_current(self, data): - self.put(self.ss, self.es, self.out_ann, data) - - def put_at(self, ss: int, es: int, data): - self.put(ss, es, self.out_ann, data) - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def select_reg(self, ir_value: int): - self.state = ejtag_state_map.get(ir_value, State.RESET) - - def parse_pracc(self): - control_in = bin2int(self.last_data['in']['data'][0]) - control_out = bin2int(self.last_data['out']['data'][0]) - - # Check if JTAG master acknowledges a pending PrAcc. - if not ((not (control_in & ControlReg.PRACC)) and \ - (control_out & ControlReg.PRACC)): - return - - ss, es = self.pracc_state.ss, self.pracc_state.es - pracc_write = (control_out & ControlReg.PRNW) != 0 - - s = 'PrAcc: ' - s += 'Store' if pracc_write else 'Load/Fetch' - - if pracc_write: - if self.pracc_state.address_out is not None: - s += ', A:' + ' 0x{:08X}'.format(self.pracc_state.address_out) - if self.pracc_state.data_out is not None: - s += ', D:' + ' 0x{:08X}'.format(self.pracc_state.data_out) - else: - if self.pracc_state.address_out is not None: - s += ', A:' + ' 0x{:08X}'.format(self.pracc_state.address_out) - if self.pracc_state.data_in is not None: - s += ', D:' + ' 0x{:08X}'.format(self.pracc_state.data_in) - - self.pracc_state.reset() - - self.put_at(ss, es, [Ann.PRACC, [s]]) - - def parse_control_reg(self, ann): - reg_write = ann == Ann.CONTROL_FIELD_IN - control_bit_positions = [] - data_select = 'in' if (reg_write) else 'out' - - control_bit_positions = self.last_data[data_select]['data'][1] - control_data = self.last_data[data_select]['data'][0] - - # Annotate control register fields. - for field in ejtag_control_reg: - start_bit = 31 - field[1] - end_bit = 31 - field[0] - comment = field[2] - value_descriptions = [] - - if reg_write: - if len(field[3]) < 2: - continue - value_descriptions = field[3][1] - else: - value_descriptions = field[3][0] - - ss = control_bit_positions[start_bit][0] - es = control_bit_positions[end_bit][1] - - value_str = control_data[end_bit : start_bit + 1] - value_index = bin2int(value_str) - - short_desc = comment + ': ' + value_str - long_desc = value_descriptions[value_index] if len(value_descriptions) > value_index else '?' - - self.put_at(ss, es, [ann, [long_desc, short_desc]]) - - def check_last_data(self): - if not hasattr(self, 'last_data'): - self.last_data = {'in': {}, 'out': {}} - - def handle_fastdata(self, val, ann): - spracc_write_desc = { - 0: ['0', 'SPrAcc: 0', 'Request completion of Fastdata access'], - 1: ['1', 'SPrAcc: 1', 'No effect'], - } - spracc_read_desc = { - 0: ['0', 'SPrAcc: 0', 'Fastdata access failure'], - 1: ['1', 'SPrAcc: 1', 'Successful completion of Fastdata access'], - } - - bitstring = val[0] - bit_sample_pos = val[1] - fastdata_state = bitstring[32] - data = bin2int(bitstring[0:32]) - - fastdata_bit_pos = bit_sample_pos[32] - data_pos = [bit_sample_pos[31][0], bit_sample_pos[0][1]] - - ss_fastdata, es_fastdata = fastdata_bit_pos - ss_data, es_data = data_pos - - display_data = [ann, ['0x{:08X}'.format(data)]] - spracc_display_data = [] - - if ann == Ann.CONTROL_FIELD_IN: - spracc_display_data = [ann, spracc_write_desc[int(fastdata_state)]] - elif ann == Ann.CONTROL_FIELD_OUT: - spracc_display_data = [ann, spracc_read_desc[int(fastdata_state)]] - - self.put_at(ss_fastdata, es_fastdata, spracc_display_data) - self.put_at(ss_data, es_data, display_data) - - def handle_dr_tdi(self, val): - value = bin2int(val[0]) - self.check_last_data() - self.last_data['in'] = {'ss': self.ss, 'es': self.es, 'data': val} - - self.pracc_state.ss, self.pracc_state.es = self.ss, self.es - - if self.state == State.ADDRESS: - self.pracc_state.address_in = value - elif self.state == State.DATA: - self.pracc_state.data_in = value - elif self.state == State.FASTDATA: - self.handle_fastdata(val, Ann.CONTROL_FIELD_IN) - - def handle_dr_tdo(self, val): - value = bin2int(val[0]) - self.check_last_data() - self.last_data['out'] = {'ss': self.ss, 'es': self.es, 'data': val} - if self.state == State.ADDRESS: - self.pracc_state.address_out = value - elif self.state == State.DATA: - self.pracc_state.data_out = value - elif self.state == State.FASTDATA: - self.handle_fastdata(val, Ann.CONTROL_FIELD_OUT) - - def handle_ir_tdi(self, val): - code = bin2int(val[0]) - hexval = '0x{:02X}'.format(code) - if code in ejtag_insn: - # Format instruction name. - insn = ejtag_insn[code] - s_short = insn[0] - s_long = insn[0] + ': ' + insn[1] + ' (' + hexval + ')' - # Display it and select data register. - self.put_current([Ann.INSTRUCTION, [s_long, s_short]]) - else: - self.put_current([Ann.INSTRUCTION, [hexval, 'IR TDI ({})'.format(hexval)]]) - self.select_reg(code) - - def handle_new_state(self, new_state): - if new_state != 'UPDATE-DR' or not hasattr(self, 'last_data'): - return - - if self.state == State.RESET: - return - - reg_name = ejtag_reg[self.state] - ann_index = Ann.REGISTER + self.state - display_data = [ann_index, [reg_name]] - self.put_at(self.last_data['in']['ss'], self.last_data['in']['es'], display_data) - - if self.state == State.CONTROL: - control_bit_positions = self.last_data['in']['data'][1] - bit_count = len(control_bit_positions) - # Check if control register data length is correct. - if bit_count != 32: - error_display = [Ann.REGISTER, ['Error: length != 32']] - self.put_at(self.last_data['in']['ss'], self.last_data['in']['es'], error_display) - return - self.parse_control_reg(Ann.CONTROL_FIELD_IN) - self.parse_control_reg(Ann.CONTROL_FIELD_OUT) - self.parse_pracc() - - def decode(self, ss: int, es: int, data): - cmd, val = data - self.ss, self.es = ss, es - - if cmd == 'IR TDI': - self.handle_ir_tdi(val) - elif cmd == 'DR TDI': - self.handle_dr_tdi(val) - elif cmd == 'DR TDO': - self.handle_dr_tdo(val) - elif cmd == 'NEW STATE': - self.handle_new_state(val) diff --git a/decoders/jtag_stm32/__init__.py b/decoders/jtag_stm32/__init__.py deleted file mode 100755 index bf69e8e0..00000000 --- a/decoders/jtag_stm32/__init__.py +++ /dev/null @@ -1,29 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -''' -This decoder stacks on top of the 'jtag' PD and decodes JTAG data specific to -the STM32 microcontroller series. - -Details: -https://en.wikipedia.org/wiki/STM32 -http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/REFERENCE_MANUAL/CD00171190.pdf (e.g. chapter 31.7: "JTAG debug port") -''' - -from .pd import Decoder diff --git a/decoders/jtag_stm32/pd.py b/decoders/jtag_stm32/pd.py deleted file mode 100755 index 82558b82..00000000 --- a/decoders/jtag_stm32/pd.py +++ /dev/null @@ -1,269 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012-2015 Uwe Hermann -## -## 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, see . -## - -import sigrokdecode as srd - -# JTAG debug port data registers (in IR[3:0]) and their sizes (in bits) -# Note: The ARM DAP-DP is not IEEE 1149.1 (JTAG) compliant (as per ARM docs), -# as it does not implement the EXTEST, SAMPLE, and PRELOAD instructions. -# Instead, BYPASS is decoded for any of these instructions. -ir = { - '1111': ['BYPASS', 1], # Bypass register - '1110': ['IDCODE', 32], # ID code register - '1010': ['DPACC', 35], # Debug port access register - '1011': ['APACC', 35], # Access port access register - '1000': ['ABORT', 35], # Abort register # TODO: 32 bits? Datasheet typo? -} - -# Boundary scan data registers (in IR[8:4]) and their sizes (in bits) -bs_ir = { - '11111': ['BYPASS', 1], # Bypass register -} - -# ARM Cortex-M3 r1p1-01rel0 ID code -cm3_idcode = 0x3ba00477 - -# http://infocenter.arm.com/help/topic/com.arm.doc.ddi0413c/Chdjibcg.html -cm3_idcode_ver = { - 0x3: 'JTAG-DP', - 0x2: 'SW-DP', -} -cm3_idcode_part = { - 0xba00: 'JTAG-DP', - 0xba10: 'SW-DP', -} - -# http://infocenter.arm.com/help/topic/com.arm.doc.faqs/ka14408.html -jedec_id = { - 5: { - 0x3b: 'ARM Ltd.', - }, -} - -# JTAG ID code in the STM32F10xxx BSC (boundary scan) TAP -jtag_idcode = { - 0x06412041: 'Low-density device, rev. A', - 0x06410041: 'Medium-density device, rev. A', - 0x16410041: 'Medium-density device, rev. B/Z/Y', - 0x06414041: 'High-density device, rev. A/Z/Y', - 0x06430041: 'XL-density device, rev. A', - 0x06418041: 'Connectivity-line device, rev. A/Z', -} - -# ACK[2:0] in the DPACC/APACC registers (unlisted values are reserved) -ack_val = { - '001': 'WAIT', - '010': 'OK/FAULT', -} - -# 32bit debug port registers (addressed via A[3:2]) -dp_reg = { - '00': 'Reserved', # Must be kept at reset value - '01': 'DP CTRL/STAT', - '10': 'DP SELECT', - '11': 'DP RDBUFF', -} - -# APB-AP registers (each of them 32 bits wide) -apb_ap_reg = { - 0x00: ['CSW', 'Control/status word'], - 0x04: ['TAR', 'Transfer address'], - # 0x08: Reserved SBZ - 0x0c: ['DRW', 'Data read/write'], - 0x10: ['BD0', 'Banked data 0'], - 0x14: ['BD1', 'Banked data 1'], - 0x18: ['BD2', 'Banked data 2'], - 0x1c: ['BD3', 'Banked data 3'], - # 0x20-0xf4: Reserved SBZ - 0x800000000: ['ROM', 'Debug ROM address'], - 0xfc: ['IDR', 'Identification register'], -} - -# TODO: Split off generic ARM/Cortex-M3 parts into another protocol decoder? - -# Bits[31:28]: Version (here: 0x3) -# JTAG-DP: 0x3, SW-DP: 0x2 -# Bits[27:12]: Part number (here: 0xba00) -# JTAG-DP: 0xba00, SW-DP: 0xba10 -# Bits[11:1]: JEDEC (JEP-106) manufacturer ID (here: 0x23b) -# Bits[11:8]: Continuation code ('ARM Ltd.': 0x04) -# Bits[7:1]: Identity code ('ARM Ltd.': 0x3b) -# Bits[0:0]: Reserved (here: 0x1) -def decode_device_id_code(bits): - id_hex = '0x%x' % int('0b' + bits, 2) - ver = cm3_idcode_ver.get(int('0b' + bits[-32:-28], 2), 'UNKNOWN') - part = cm3_idcode_part.get(int('0b' + bits[-28:-12], 2), 'UNKNOWN') - ids = jedec_id.get(int('0b' + bits[-12:-8], 2) + 1, {}) - manuf = ids.get(int('0b' + bits[-7:-1], 2), 'UNKNOWN') - return (id_hex, manuf, ver, part) - -# DPACC is used to access debug port registers (CTRL/STAT, SELECT, RDBUFF). -# APACC is used to access all Access Port (AHB-AP) registers. - -# APACC/DPACC, when transferring data IN: -# Bits[34:3] = DATA[31:0]: 32bit data to transfer (write request) -# Bits[2:1] = A[3:2]: 2-bit address (debug/access port register) -# Bits[0:0] = RnW: Read request (1) or write request (0) -def data_in(instruction, bits): - data, a, rnw = bits[:-3], bits[-3:-1], bits[-1] - data_hex = '0x%x' % int('0b' + data, 2) - r = 'Read request' if (rnw == '1') else 'Write request' - # reg = dp_reg[a] if (instruction == 'DPACC') else apb_ap_reg[a] - reg = dp_reg[a] if (instruction == 'DPACC') else a # TODO - return 'New transaction: DATA: %s, A: %s, RnW: %s' % (data_hex, reg, r) - -# APACC/DPACC, when transferring data OUT: -# Bits[34:3] = DATA[31:0]: 32bit data which is read (read request) -# Bits[2:0] = ACK[2:0]: 3-bit acknowledge -def data_out(bits): - data, ack = bits[:-3], bits[-3:] - data_hex = '0x%x' % int('0b' + data, 2) - ack_meaning = ack_val.get(ack, 'Reserved') - return 'Previous transaction result: DATA: %s, ACK: %s' \ - % (data_hex, ack_meaning) - -class Decoder(srd.Decoder): - api_version = 3 - id = 'jtag_stm32' - name = 'JTAG / STM32' - longname = 'Joint Test Action Group / ST STM32' - desc = 'ST STM32-specific JTAG protocol.' - license = 'gplv2+' - inputs = ['jtag'] - outputs = [] - tags = ['Debug/trace'] - annotations = ( - ('item', 'Item'), - ('field', 'Field'), - ('command', 'Command'), - ('warning', 'Warning'), - ) - annotation_rows = ( - ('items', 'Items', (0,)), - ('fields', 'Fields', (1,)), - ('commands', 'Commands', (2,)), - ('warnings', 'Warnings', (3,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.state = 'IDLE' - self.samplenums = None - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putx(self, data): - self.put(self.ss, self.es, self.out_ann, data) - - def putf(self, s, e, data): - self.put(self.samplenums[s][0], self.samplenums[e][1], self.out_ann, data) - - def handle_reg_bypass(self, cmd, bits): - self.putx([0, ['BYPASS: ' + bits]]) - - def handle_reg_idcode(self, cmd, bits): - bits = bits[1:] - - id_hex, manuf, ver, part = decode_device_id_code(bits) - cc = '0x%x' % int('0b' + bits[-12:-8], 2) - ic = '0x%x' % int('0b' + bits[-7:-1], 2) - - self.putf(0, 0, [1, ['Reserved', 'Res', 'R']]) - self.putf(8, 11, [0, ['Continuation code: %s' % cc, 'CC', 'C']]) - self.putf(1, 7, [0, ['Identity code: %s' % ic, 'IC', 'I']]) - self.putf(1, 11, [1, ['Manufacturer: %s' % manuf, 'Manuf', 'M']]) - self.putf(12, 27, [1, ['Part: %s' % part, 'Part', 'P']]) - self.putf(28, 31, [1, ['Version: %s' % ver, 'Version', 'V']]) - self.putf(32, 32, [1, ['BYPASS (BS TAP)', 'BS', 'B']]) - - self.putx([2, ['IDCODE: %s (%s: %s/%s)' % \ - decode_device_id_code(bits)]]) - - def handle_reg_dpacc(self, cmd, bits): - bits = bits[1:] - s = data_in('DPACC', bits) if (cmd == 'DR TDI') else data_out(bits) - self.putx([2, [s]]) - - def handle_reg_apacc(self, cmd, bits): - bits = bits[1:] - s = data_in('APACC', bits) if (cmd == 'DR TDI') else data_out(bits) - self.putx([2, [s]]) - - def handle_reg_abort(self, cmd, bits): - bits = bits[1:] - # Bits[31:1]: reserved. Bit[0]: DAPABORT. - a = '' if (bits[0] == '1') else 'No ' - s = 'DAPABORT = %s: %sDAP abort generated' % (bits[0], a) - self.putx([2, [s]]) - - # Warn if DAPABORT[31:1] contains non-zero bits. - if (bits[:-1] != ('0' * 31)): - self.putx([3, ['WARNING: DAPABORT[31:1] reserved!']]) - - def handle_reg_unknown(self, cmd, bits): - bits = bits[1:] - self.putx([2, ['Unknown instruction: %s' % bits]]) - - def decode(self, ss, es, data): - cmd, val = data - - self.ss, self.es = ss, es - - if cmd != 'NEW STATE': - # The right-most char in the 'val' bitstring is the LSB. - val, self.samplenums = val - self.samplenums.reverse() - - if cmd == 'IR TDI': - # Switch to the state named after the instruction, or 'UNKNOWN'. - # The STM32F10xxx has two serially connected JTAG TAPs, the - # boundary scan tap (5 bits) and the Cortex-M3 TAP (4 bits). - # See UM 31.5 "STM32F10xxx JTAG TAP connection" for details. - self.state = ir.get(val[5:9], ['UNKNOWN', 0])[0] - bstap_ir = bs_ir.get(val[:5], ['UNKNOWN', 0])[0] - self.putf(4, 8, [1, ['IR (BS TAP): ' + bstap_ir]]) - self.putf(0, 3, [1, ['IR (M3 TAP): ' + self.state]]) - self.putx([2, ['IR: %s' % self.state]]) - - # State machine - if self.state == 'BYPASS': - # Here we're interested in incoming bits (TDI). - if cmd != 'DR TDI': - return - handle_reg = getattr(self, 'handle_reg_%s' % self.state.lower()) - handle_reg(cmd, val) - self.state = 'IDLE' - elif self.state in ('IDCODE', 'ABORT', 'UNKNOWN'): - # Here we're interested in outgoing bits (TDO). - if cmd != 'DR TDO': - return - handle_reg = getattr(self, 'handle_reg_%s' % self.state.lower()) - handle_reg(cmd, val) - self.state = 'IDLE' - elif self.state in ('DPACC', 'APACC'): - # Here we're interested in incoming and outgoing bits (TDI/TDO). - if cmd not in ('DR TDI', 'DR TDO'): - return - handle_reg = getattr(self, 'handle_reg_%s' % self.state.lower()) - handle_reg(cmd, val) - if cmd == 'DR TDO': # Assumes 'DR TDI' comes before 'DR TDO'. - self.state = 'IDLE' diff --git a/decoders/lfast/__init__.py b/decoders/lfast/__init__.py deleted file mode 100644 index 681f4f9e..00000000 --- a/decoders/lfast/__init__.py +++ /dev/null @@ -1,35 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 Soeren Apel -## -## 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, see . -## - -''' -LFAST is a physical communication interface used mainly by the NXP Zipwire -interface. It's a framed asynchronous serial interface using differential -TX/RX pairs, capable of data rates of up to 320 MBit/s. - -This interface is also provided by Infineon as HSCT. - -As with most differential signals, it's sufficient to measure TXP or RXP, no -need for a differential probe. The REFCLK used by the hardware isn't needed by -this protocol decoder either. - -For details see https://www.nxp.com/docs/en/application-note/AN5134.pdf and -https://hitex.co.uk/fileadmin/uk-files/downloads/ShieldBuddy/tc27xD_um_v2.2.pdf -''' - -from .pd import Decoder diff --git a/decoders/lfast/pd.py b/decoders/lfast/pd.py deleted file mode 100644 index 7476e59a..00000000 --- a/decoders/lfast/pd.py +++ /dev/null @@ -1,335 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 Soeren Apel -## -## 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, see . -## - -import sigrokdecode as srd -from common.srdhelper import bitpack -import decimal - -''' -OUTPUT_PYTHON format: - -[ss, es, data] where data is a data byte of the LFAST payload. All bytes of -the payload are sent at once, each with its start and end sample. -''' - -# See tc27xD_um_v2.2.pdf, Table 20-10 -payload_sizes = { - 0b000: '8 bit', - 0b001: '32 bit / 4 byte', - 0b010: '64 bit / 8 byte', - 0b011: '96 bit / 12 byte', - 0b100: '128 bit / 16 byte', - 0b101: '256 bit / 32 byte', - 0b110: '512 bit / 64 byte', - 0b111: '288 bit / 36 byte' -} - -# See tc27xD_um_v2.2.pdf, Table 20-10 -payload_byte_sizes = { - 0b000: 1, - 0b001: 4, - 0b010: 8, - 0b011: 12, - 0b100: 16, - 0b101: 32, - 0b110: 64, - 0b111: 36 -} - -# See tc27xD_um_v2.2.pdf, Table 20-11 -channel_types = { - 0b0000: 'Interface Control / PING', - 0b0001: 'Unsolicited Status (32 bit)', - 0b0010: 'Slave Interface Control / Read', - 0b0011: 'CTS Transfer', - 0b0100: 'Data Channel A', - 0b0101: 'Data Channel B', - 0b0110: 'Data Channel C', - 0b0111: 'Data Channel D', - 0b1000: 'Data Channel E', - 0b1001: 'Data Channel F', - 0b1010: 'Data Channel G', - 0b1011: 'Data Channel H', - 0b1100: 'Reserved', - 0b1101: 'Reserved', - 0b1110: 'Reserved', - 0b1111: 'Reserved', -} - -# See tc27xD_um_v2.2.pdf, Table 20-12 -control_payloads = { - 0x00: 'PING', - 0x01: 'Reserved', - 0x02: 'Slave interface clock multiplier start', - 0x04: 'Slave interface clock multiplier stop', - 0x08: 'Use 5 MBaud for M->S', - 0x10: 'Use 320 MBaud for M->S', - 0x20: 'Use 5 MBaud for S->M', - 0x40: 'Use 20 MBaud for S->M (needs 20 MHz SysClk)', - 0x80: 'Use 320 MBaud for S->M', - 0x31: 'Enable slave interface transmitter', - 0x32: 'Disable slave interface transmitter', - 0x34: 'Enable clock test mode', - 0x38: 'Disable clock test mode and payload loopback', - 0xFF: 'Enable payload loopback', -} - - -ann_bit, ann_sync, ann_header_pl_size, ann_header_ch_type, ann_header_cts, \ - ann_payload, ann_control_data, ann_sleepbit, ann_warning = range(9) -state_sync, state_header, state_payload, state_sleepbit = range(4) - -class Decoder(srd.Decoder): - api_version = 3 - id = 'lfast' - name = 'LFAST' - longname = 'NXP LFAST interface' - desc = 'Differential high-speed P2P interface' - license = 'gplv2+' - inputs = ['logic'] - outputs = ['lfast'] - tags = ['Embedded/industrial'] - channels = ( - {'id': 'data', 'name': 'Data', 'desc': 'TXP or RXP'}, - ) - annotations = ( - ('bit', 'Bits'), - ('sync', 'Sync Pattern'), - ('header_pl_size', 'Payload Size'), - ('header_ch_type', 'Logical Channel Type'), - ('header_cts', 'Clear To Send'), - ('payload', 'Payload'), - ('ctrl_data', 'Control Data'), - ('sleep', 'Sleep Bit'), - ('warning', 'Warning'), - ) - annotation_rows = ( - ('bits', 'Bits', (ann_bit,)), - ('fields', 'Fields', (ann_sync, ann_header_pl_size, ann_header_ch_type, - ann_header_cts, ann_payload, ann_control_data, ann_sleepbit,)), - ('warnings', 'Warnings', (ann_warning,)), - ) - - def __init__(self): - decimal.getcontext().rounding = decimal.ROUND_HALF_UP - self.bit_len = 0xFFFFFFFF - self.reset() - - def reset(self): - self.prev_bit_len = self.bit_len - self.ss = self.es = 0 - self.ss_payload = self.es_payload = 0 - self.ss_byte = 0 - self.bits = [] - self.payload = [] - self.payload_size = 0 # Expected number of bytes, as read from header - self.bit_len = 0 # Length of one bit time, in samples - self.timeout = 0 # Desired timeout for next edge, in samples - self.ch_type_id = 0 # ID of channel type - self.state = state_sync - - def metadata(self, key, value): - pass - - def start(self): - self.out_python = self.register(srd.OUTPUT_PYTHON) - self.out_ann = self.register(srd.OUTPUT_ANN) - - def put_ann(self, ss, es, ann_class, value): - self.put(ss, es, self.out_ann, [ann_class, value]) - - def put_payload(self): - self.put(self.ss_payload, self.es_payload, self.out_python, self.payload) - - def handle_sync(self): - if len(self.bits) == 1: - self.ss_sync = self.ss_bit - - if len(self.bits) == 16: - value = bitpack(self.bits) - if value == 0xA84B: - self.put_ann(self.ss_sync, self.es_bit, ann_sync, ['Sync OK']) - else: - self.put_ann(self.ss_sync, self.es_bit, ann_warning, ['Wrong Sync Value: {:02X}'.format(value)]) - self.reset() - - # Only continue if we didn't just reset - if self.ss > 0: - self.bits = [] - self.state = state_header - self.timeout = int(9.4 * self.bit_len) - - def handle_header(self): - if len(self.bits) == 1: - self.ss_header = self.ss_bit - - if len(self.bits) == 8: - # See tc27xD_um_v2.2.pdf, Figure 20-47, for the header structure - bit_len = (self.es_bit - self.ss_header) / 8 - value = bitpack(self.bits) - - ss = self.ss_header - es = ss + 3 * bit_len - size_id = (value & 0xE0) >> 5 - size = payload_sizes.get(size_id) - self.payload_size = payload_byte_sizes.get(size_id) - self.put_ann(int(ss), int(es), ann_header_pl_size, [size]) - - ss = es - es = ss + 4 * bit_len - self.ch_type_id = (value & 0x1E) >> 1 - ch_type = channel_types.get(self.ch_type_id) - self.put_ann(int(ss), int(es), ann_header_ch_type, [ch_type]) - - ss = es - es = ss + bit_len - cts = value & 0x01 - self.put_ann(int(ss), int(es), ann_header_cts, ['{}'.format(cts)]) - - self.bits = [] - self.state = state_payload - self.timeout = int(9.4 * self.bit_len) - - def handle_payload(self): - self.timeout = int((self.payload_size - len(self.payload)) * 8 * self.bit_len) - - if len(self.bits) == 1: - self.ss_byte = self.ss_bit - if self.ss_payload == 0: - self.ss_payload = self.ss_bit - - if len(self.bits) == 8: - value = bitpack(self.bits) - value_hex = '{:02X}'.format(value) - - # Control transfers have no SIPI payload, show them as control transfers - # Check the channel_types list for the meaning of the magic values - if (self.ch_type_id >= 0b0100) and (self.ch_type_id <= 0b1011): - self.put_ann(self.ss_byte, self.es_bit, ann_payload, [value_hex]) - else: - # Control transfers are 8-bit transfers, so only evaluate the first byte - if len(self.payload) == 0: - ctrl_data = control_payloads.get(value, value_hex) - self.put_ann(self.ss_byte, self.es_bit, ann_control_data, [ctrl_data]) - else: - self.put_ann(self.ss_byte, self.es_bit, ann_control_data, [value_hex]) - - self.bits = [] - self.es_payload = self.es_bit - self.payload.append((self.ss_byte, self.es_payload, value)) - - if (len(self.payload) == self.payload_size): - self.timeout = int(1.4 * self.bit_len) - self.state = state_sleepbit - - def handle_sleepbit(self): - if len(self.bits) == 0: - self.put_ann(self.ss_bit, self.es_bit, ann_sleepbit, ['No LVDS sleep mode request', 'No sleep', 'N']) - elif len(self.bits) > 1: - self.put_ann(self.ss_bit, self.es_bit, ann_warning, ['Expected only the sleep bit, got {} bits instead'.format(len(self.bits))]) - else: - if self.bits[0] == 1: - self.put_ann(self.ss_bit, self.es_bit, ann_sleepbit, ['LVDS sleep mode request', 'Sleep', 'Y']) - else: - self.put_ann(self.ss_bit, self.es_bit, ann_sleepbit, ['No LVDS sleep mode request', 'No sleep', 'N']) - - # We only send the payload out if this is an actual data transfer; - # check the channel_types list for the meaning of the magic values - if (self.ch_type_id >= 0b0100) and (self.ch_type_id <= 0b1011): - if len(self.payload) > 0: - self.put_payload() - - def decode(self): - while True: - if self.timeout == 0: - rising_edge, = self.wait({0: 'e'}) - else: - rising_edge, = self.wait([{0: 'e'}, {'skip': self.timeout}]) - - # If this is the first edge, we only update ss - if self.ss == 0: - self.ss = self.samplenum - # Let's set the timeout for the sync pattern as well - self.timeout = int(16.2 * self.prev_bit_len) - continue - - self.es = self.samplenum - - # Check for the sleep bit if this is a timeout condition - if (len(self.matched) == 2) and self.matched[1]: - rising_edge = ~rising_edge - if self.state == state_sync: - self.reset() - continue - elif self.state == state_sleepbit: - self.ss_bit += self.bit_len - self.es_bit = self.ss_bit + self.bit_len - self.handle_sleepbit() - self.reset() - continue - - # Shouldn't happen but we check just in case - if int(self.es - self.ss) == 0: - continue - - # We use the first bit to deduce the bit length - if self.bit_len == 0: - self.bit_len = self.es - self.ss - - # Determine number of bits covered by this edge - bit_count = (self.es - self.ss) / self.bit_len - bit_count = int(decimal.Decimal(bit_count).to_integral_value()) - - if bit_count == 0: - self.put_ann(self.ss, self.es, ann_warning, ['Bit time too short']) - self.reset() - continue - - bit_value = '0' if rising_edge else '1' - - divided_len = (self.es - self.ss) / bit_count - for i in range(bit_count): - self.ss_bit = int(self.ss + i * divided_len) - self.es_bit = int(self.ss_bit + divided_len) - self.put_ann(self.ss_bit, self.es_bit, ann_bit, [bit_value]) - - # Place the new bit at the front of the bit list - self.bits.insert(0, (0 if rising_edge else 1)) - - if self.state == state_sync: - self.handle_sync() - elif self.state == state_header: - self.handle_header() - elif self.state == state_payload: - self.handle_payload() - elif self.state == state_sleepbit: - self.handle_sleepbit() - self.reset() - - if self.ss == 0: - break # Because reset() was called, invalidating everything - - # Only update ss if we didn't just perform a reset - if self.ss > 0: - self.ss = self.samplenum - - # If we got here when a timeout occurred, we have processed all null - # bits that we could and should reset now to find the next packet - if (len(self.matched) == 2) and self.matched[1]: - self.reset() diff --git a/decoders/lin/__init__.py b/decoders/lin/__init__.py deleted file mode 100755 index f5b2835f..00000000 --- a/decoders/lin/__init__.py +++ /dev/null @@ -1,28 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Stephan Thiele -## -## 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, see . -## - -''' -This decoder stacks on top of the 'uart' PD and decodes the LIN -(Local Interconnect Network) protocol. - -LIN is layered on top of the UART (async serial) protocol, with 8n1 settings. -Bytes are sent LSB-first. -''' - -from .pd import Decoder diff --git a/decoders/lin/pd.py b/decoders/lin/pd.py deleted file mode 100755 index c6db6787..00000000 --- a/decoders/lin/pd.py +++ /dev/null @@ -1,235 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Stephan Thiele -## -## 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, see . -## - -import sigrokdecode as srd - -class LinFsm: - class State: - WaitForBreak = 'WAIT_FOR_BREAK' - Sync = 'SYNC' - Pid = 'PID' - Data = 'DATA' - Checksum = 'CHECKSUM' - Error = 'ERROR' - - def transit(self, target_state): - if not self._transition_allowed(target_state): - return False - self.state = target_state - return True - - def _transition_allowed(self, target_state): - if target_state == LinFsm.State.Error: - return True - return target_state in self.allowed_state[self.state] - - def reset(self): - self.state = LinFsm.State.WaitForBreak - - def __init__(self): - a = dict() - a[LinFsm.State.WaitForBreak] = (LinFsm.State.Sync,) - a[LinFsm.State.Sync] = (LinFsm.State.Pid,) - a[LinFsm.State.Pid] = (LinFsm.State.Data,) - a[LinFsm.State.Data] = (LinFsm.State.Data, LinFsm.State.Checksum) - a[LinFsm.State.Checksum] = (LinFsm.State.WaitForBreak,) - a[LinFsm.State.Error] = (LinFsm.State.Sync,) - self.allowed_state = a - - self.state = None - self.reset() - -class Decoder(srd.Decoder): - api_version = 3 - id = 'lin' - name = 'LIN' - longname = 'Local Interconnect Network' - desc = 'Local Interconnect Network (LIN) protocol.' - license = 'gplv2+' - inputs = ['uart'] - outputs = [] - tags = ['Automotive'] - options = ( - {'id': 'version', 'desc': 'Protocol version', 'default': 2, 'values': (1, 2)}, - ) - annotations = ( - ('data', 'LIN data'), - ('control', 'Protocol info'), - ('error', 'Error descriptions'), - ('inline_error', 'Protocol violations and errors'), - ) - annotation_rows = ( - ('data', 'Data', (0, 1, 3)), - ('error', 'Error', (2,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.fsm = LinFsm() - self.lin_header = [] - self.lin_rsp = [] - self.lin_version = None - self.out_ann = None - self.ss_block = None - self.es_block = None - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.lin_version = self.options['version'] - - def putx(self, data): - self.put(self.ss_block, self.es_block, self.out_ann, data) - - def wipe_break_null_byte(self, value): - # Upon a break condition a null byte is received which must be ignored. - if self.fsm.state not in (LinFsm.State.WaitForBreak, LinFsm.State.Error): - if len(self.lin_rsp): - value = self.lin_rsp.pop()[2] - else: - self.lin_header.pop() - - if value != 0: - self.fsm.transit(LinFsm.State.Error) - self.handle_error(None) - return False - - return True - - def handle_wait_for_break(self, value): - self.wipe_break_null_byte(value) - - def handle_break(self, value): - if self.fsm.state not in (LinFsm.State.WaitForBreak, LinFsm.State.Error): - if self.wipe_break_null_byte(value): - self.fsm.transit(LinFsm.State.Checksum) - self.handle_checksum() - - self.fsm.reset() - self.fsm.transit(LinFsm.State.Sync) - - self.putx([1, ['Break condition', 'Break', 'Brk', 'B']]) - - def handle_sync(self, value): - self.fsm.transit(LinFsm.State.Pid) - self.lin_header.append((self.ss_block, self.es_block, value)) - - def handle_pid(self, value): - self.fsm.transit(LinFsm.State.Data) - self.lin_header.append((self.ss_block, self.es_block, value)) - - def handle_data(self, value): - self.lin_rsp.append((self.ss_block, self.es_block, value)) - - def handle_checksum(self): - sync = self.lin_header.pop(0) if len(self.lin_header) else None - - self.put(sync[0], sync[1], self.out_ann, [0, ['Sync', 'S']]) - - if sync[2] != 0x55: - self.put(sync[0], sync[1], self.out_ann, - [2, ['Sync is not 0x55', 'Not 0x55', '!= 0x55']]) - - pid = self.lin_header.pop(0) if len(self.lin_header) else None - checksum = self.lin_rsp.pop() if len(self.lin_rsp) else None - - if pid: - id_ = pid[2] & 0x3F - parity = pid[2] >> 6 - - expected_parity = self.calc_parity(pid[2]) - parity_valid = parity == expected_parity - - if not parity_valid: - self.put(pid[0], pid[1], self.out_ann, [2, ['P != %d' % expected_parity]]) - - ann_class = 0 if parity_valid else 3 - self.put(pid[0], pid[1], self.out_ann, [ann_class, [ - 'ID: %02X Parity: %d (%s)' % (id_, parity, 'ok' if parity_valid else 'bad'), - 'ID: 0x%02X' % id_, 'I: %d' % id_ - ]]) - - if len(self.lin_rsp): - checksum_valid = self.checksum_is_valid(pid[2], self.lin_rsp, checksum[2]) - - for b in self.lin_rsp: - self.put(b[0], b[1], self.out_ann, [0, ['Data: 0x%02X' % b[2], 'D: 0x%02X' % b[2]]]) - - ann_class = 0 if checksum_valid else 3 - self.put(checksum[0], checksum[1], self.out_ann, - [ann_class, ['Checksum: 0x%02X' % checksum[2], 'Checksum', 'Chk', 'C']]) - - if not checksum_valid: - self.put(checksum[0], checksum[1], self.out_ann, [2, ['Checksum invalid']]) - else: - pass # No response. - - self.lin_header.clear() - self.lin_rsp.clear() - - def handle_error(self, dummy): - self.putx([3, ['Error', 'Err', 'E']]) - - def checksum_is_valid(self, pid, data, checksum): - if self.lin_version == 2: - id_ = pid & 0x3F - - if id_ != 60 and id_ != 61: - checksum += pid - - for d in data: - checksum += d[2] - - carry_bits = int(checksum / 256) - checksum += carry_bits - - return checksum & 0xFF == 0xFF - - @staticmethod - def calc_parity(pid): - id_ = [((pid & 0x3F) >> i) & 1 for i in range(8)] - - p0 = id_[0] ^ id_[1] ^ id_[2] ^ id_[4] - p1 = not (id_[1] ^ id_[3] ^ id_[4] ^ id_[5]) - - return (p0 << 0) | (p1 << 1) - - def decode(self, ss, es, data): - ptype, rxtx, pdata = data - - self.ss_block, self.es_block = ss, es - - # Ignore all UART packets except the actual data packets or BREAK. - if ptype == 'BREAK': - self.handle_break(pdata) - if ptype != 'DATA': - return - - # We're only interested in the byte value (not individual bits). - pdata = pdata[0] - - # Short LIN overview: - # - Message begins with a BREAK (0x00) for at least 13 bittimes. - # - Break is always followed by a SYNC byte (0x55). - # - Sync byte is followed by a PID byte (Protected Identifier). - # - PID byte is followed by 1 - 8 data bytes and a final checksum byte. - - handler = getattr(self, 'handle_%s' % self.fsm.state.lower()) - handler(pdata) diff --git a/decoders/lm75/__init__.py b/decoders/lm75/__init__.py deleted file mode 100755 index 83ce811b..00000000 --- a/decoders/lm75/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -''' -This decoder stacks on top of the 'i2c' PD and decodes the National LM75 -(and compatibles) temperature sensor protocol. -''' - -from .pd import Decoder diff --git a/decoders/lm75/pd.py b/decoders/lm75/pd.py deleted file mode 100755 index 14df1b52..00000000 --- a/decoders/lm75/pd.py +++ /dev/null @@ -1,186 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -# TODO: Better support for various LM75 compatible devices. - -import sigrokdecode as srd - -# LM75 only supports 9 bit resolution, compatible devices usually 9-12 bits. -resolution = { - # CONFIG[6:5]: - 0x00: 9, - 0x01: 10, - 0x02: 11, - 0x03: 12, -} - -ft = { - # CONFIG[4:3]: - 0x00: 1, - 0x01: 2, - 0x02: 4, - 0x03: 6, -} - -class Decoder(srd.Decoder): - api_version = 3 - id = 'lm75' - name = 'LM75' - longname = 'National LM75' - desc = 'National LM75 (and compatibles) temperature sensor.' - license = 'gplv2+' - inputs = ['i2c'] - outputs = [] - tags = ['Sensor'] - options = ( - {'id': 'sensor', 'desc': 'Sensor type', 'default': 'lm75', - 'values': ('lm75',)}, - {'id': 'resolution', 'desc': 'Resolution (bits)', 'default': 9, - 'values': (9, 10, 11, 12)}, - ) - annotations = ( - ('celsius', 'Temperature in degrees Celsius'), - ('kelvin', 'Temperature in Kelvin'), - ('text-verbose', 'Human-readable text (verbose)'), - ('text', 'Human-readable text'), - ('warnings', 'Human-readable warnings'), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.state = 'IDLE' - self.reg = 0x00 # Currently selected register - self.databytes = [] - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putx(self, data): - # Helper for annotations which span exactly one I²C packet. - self.put(self.ss, self.es, self.out_ann, data) - - def putb(self, data): - # Helper for annotations which span a block of I²C packets. - self.put(self.ss_block, self.es_block, self.out_ann, data) - - def warn_upon_invalid_slave(self, addr): - # LM75 and compatible devices have a 7-bit I²C slave address where - # the 4 MSBs are fixed to 1001, and the 3 LSBs are configurable. - # Thus, valid slave addresses (1001xxx) range from 0x48 to 0x4f. - if addr not in range(0x48, 0x4f + 1): - s = 'Warning: I²C slave 0x%02x not an LM75 compatible sensor.' - self.putx([4, [s % addr]]) - - def output_temperature(self, s, rw): - # TODO: Support for resolutions other than 9 bit. - before, after = self.databytes[0], (self.databytes[1] >> 7) * 5 - celsius = float('%d.%d' % (before, after)) - kelvin = celsius + 273.15 - self.putb([0, ['%s: %.1f °C' % (s, celsius)]]) - self.putb([1, ['%s: %.1f K' % (s, kelvin)]]) - - # Warn about the temperature register (0x00) being read-only. - if s == 'Temperature' and rw == 'WRITE': - s = 'Warning: The temperature register is read-only!' - self.putb([4, [s]]) - - def handle_temperature_reg(self, b, s, rw): - # Common helper for the temperature/T_HYST/T_OS registers. - if len(self.databytes) == 0: - self.ss_block = self.ss - self.databytes.append(b) - return - self.databytes.append(b) - self.es_block = self.es - self.output_temperature(s, rw) - self.databytes = [] - - def handle_reg_0x00(self, b, rw): - # Temperature register (16bits, read-only). - self.handle_temperature_reg(b, 'Temperature', rw) - - def handle_reg_0x01(self, b, rw): - # Configuration register (8 bits, read/write). - # TODO: Bit-exact annotation ranges. - - sd = b & (1 << 0) - tmp = 'normal operation' if (sd == 0) else 'shutdown mode' - s = 'SD = %d: %s\n' % (sd, tmp) - s2 = 'SD = %s, ' % tmp - - cmp_int = b & (1 << 1) - tmp = 'comparator' if (cmp_int == 0) else 'interrupt' - s += 'CMP/INT = %d: %s mode\n' % (cmp_int, tmp) - s2 += 'CMP/INT = %s, ' % tmp - - pol = b & (1 << 2) - tmp = 'low' if (pol == 0) else 'high' - s += 'POL = %d: OS polarity is active-%s\n' % (pol, tmp) - s2 += 'POL = active-%s, ' % tmp - - bits = (b & ((1 << 4) | (1 << 3))) >> 3 - s += 'Fault tolerance setting: %d bit(s)\n' % ft[bits] - s2 += 'FT = %d' % ft[bits] - - # Not supported by LM75, but by various compatible devices. - if self.options['sensor'] != 'lm75': # TODO - bits = (b & ((1 << 6) | (1 << 5))) >> 5 - s += 'Resolution: %d bits\n' % resolution[bits] - s2 += ', resolution = %d' % resolution[bits] - - self.putx([2, [s]]) - self.putx([3, [s2]]) - - def handle_reg_0x02(self, b, rw): - # T_HYST register (16 bits, read/write). - self.handle_temperature_reg(b, 'T_HYST trip temperature', rw) - - def handle_reg_0x03(self, b, rw): - # T_OS register (16 bits, read/write). - self.handle_temperature_reg(b, 'T_OS trip temperature', rw) - - def decode(self, ss, es, data): - cmd, databyte = data - - # Store the start/end samples of this I²C packet. - self.ss, self.es = ss, es - - # State machine. - if self.state == 'IDLE': - # Wait for an I²C START condition. - if cmd != 'START': - return - self.state = 'GET SLAVE ADDR' - elif self.state == 'GET SLAVE ADDR': - # Wait for an address read/write operation. - if cmd in ('ADDRESS READ', 'ADDRESS WRITE'): - self.warn_upon_invalid_slave(databyte) - self.state = cmd[8:] + ' REGS' # READ REGS / WRITE REGS - elif self.state in ('READ REGS', 'WRITE REGS'): - if cmd in ('DATA READ', 'DATA WRITE'): - handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg) - handle_reg(databyte, cmd[5:]) # READ / WRITE - elif cmd == 'STOP': - # TODO: Any output? - self.state = 'IDLE' - else: - # self.putx([0, ['Ignoring: %s (data=%s)' % (cmd, databyte)]]) - pass diff --git a/decoders/lpc/__init__.py b/decoders/lpc/__init__.py deleted file mode 100755 index 52277587..00000000 --- a/decoders/lpc/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -''' -LPC (Low Pin Count) is a protocol for low-bandwidth devices used on -some PC mainboards, such as the "BIOS chip" or the so-called "Super I/O". -''' - -from .pd import Decoder diff --git a/decoders/lpc/pd.py b/decoders/lpc/pd.py deleted file mode 100755 index 6ae13f4a..00000000 --- a/decoders/lpc/pd.py +++ /dev/null @@ -1,547 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012-2013 Uwe Hermann -## Copyright (C) 2019 DreamSourceLab -## Copyright (C) 2020 Raptor Engineering, LLC -## -## 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, see . -## - -import sigrokdecode as srd - -# ... -fields = { - # START field (indicates start or stop of a transaction) - 'START': { - 0b0000: 'Start of cycle for a target', - 0b0001: 'Reserved', - 0b0010: 'Grant for bus master 0', - 0b0011: 'Grant for bus master 1', - 0b0100: 'Reserved', - 0b0101: 'TPM', - 0b0110: 'Reserved', - 0b0111: 'Reserved', - 0b1000: 'Reserved', - 0b1001: 'Reserved', - 0b1010: 'Reserved', - 0b1011: 'Reserved', - 0b1100: 'Reserved', - 0b1101: 'Start of cycle for a Firmware Memory Read cycle', - 0b1110: 'Start of cycle for a Firmware Memory Write cycle', - 0b1111: 'Stop/abort (end of a cycle for a target)', - }, - # Cycle type / direction field - # Bit 0 (LAD[0]) is unused, should always be 0. - # Neither host nor peripheral are allowed to drive 0b11x0. - 'CT_DR': { - 0b0000: 'I/O read', - 0b0001: 'I/O read', - 0b0010: 'I/O write', - 0b0011: 'I/O write', - 0b0100: 'Memory read', - 0b0101: 'Memory read', - 0b0110: 'Memory write', - 0b0111: 'Memory write', - 0b1000: 'DMA read', - 0b1001: 'DMA read', - 0b1010: 'DMA write', - 0b1011: 'DMA write', - 0b1100: 'Reserved / not allowed', - 0b1101: 'Reserved / not allowed', - 0b1110: 'Reserved / not allowed', - 0b1111: 'Reserved / not allowed', - }, - # Cycle type / direction field - # False for read cycle, True for write cycle - 'CT_DR_WR': { - 0b0000: False, - 0b0001: False, - 0b0010: True, - 0b0011: True, - 0b0100: False, - 0b0101: False, - 0b0110: True, - 0b0111: True, - 0b1000: False, - 0b1001: False, - 0b1010: True, - 0b1011: True, - 0b1100: False, - 0b1101: False, - 0b1110: False, - 0b1111: False, - }, - # SIZE field (determines how many bytes are to be transferred) - # Bits[3:2] are reserved, must be driven to 0b00. - # Neither host nor peripheral are allowed to drive 0b0010. - 'SIZE': { - 0b0000: '8 bits (1 byte)', - 0b0001: '16 bits (2 bytes)', - 0b0010: 'Reserved / not allowed', - 0b0011: '32 bits (4 bytes)', - }, - # CHANNEL field (bits[2:0] contain the DMA channel number) - 'CHANNEL': { - 0b0000: '0', - 0b0001: '1', - 0b0010: '2', - 0b0011: '3', - 0b0100: '4', - 0b0101: '5', - 0b0110: '6', - 0b0111: '7', - }, - # SYNC field (used to add wait states) - 'SYNC': { - 0b0000: 'Ready', - 0b0001: 'Reserved', - 0b0010: 'Reserved', - 0b0011: 'Reserved', - 0b0100: 'Reserved', - 0b0101: 'Short wait', - 0b0110: 'Long wait', - 0b0111: 'Reserved', - 0b1000: 'Reserved', - 0b1001: 'Ready more (DMA only)', - 0b1010: 'Error', - 0b1011: 'Reserved', - 0b1100: 'Reserved', - 0b1101: 'Reserved', - 0b1110: 'Reserved', - 0b1111: 'Reserved', - }, -} - -class Decoder(srd.Decoder): - api_version = 3 - id = 'lpc' - name = 'LPC' - longname = 'Low Pin Count' - desc = 'Protocol for low-bandwidth devices on PC mainboards.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['PC'] - channels = ( - {'id': 'lframe', 'name': 'LFRAME#', 'desc': 'Frame'}, - {'id': 'lclk', 'name': 'LCLK', 'desc': 'Clock'}, - {'id': 'lad0', 'name': 'LAD[0]', 'desc': 'Addr/control/data 0'}, - {'id': 'lad1', 'name': 'LAD[1]', 'desc': 'Addr/control/data 1'}, - {'id': 'lad2', 'name': 'LAD[2]', 'desc': 'Addr/control/data 2'}, - {'id': 'lad3', 'name': 'LAD[3]', 'desc': 'Addr/control/data 3'}, - ) - optional_channels = ( - {'id': 'lreset', 'name': 'LRESET#', 'desc': 'Reset'}, - {'id': 'ldrq', 'name': 'LDRQ#', 'desc': 'Encoded DMA / bus master request'}, - {'id': 'serirq', 'name': 'SERIRQ', 'desc': 'Serialized IRQ'}, - {'id': 'clkrun', 'name': 'CLKRUN#', 'desc': 'Clock run'}, - {'id': 'lpme', 'name': 'LPME#', 'desc': 'LPC power management event'}, - {'id': 'lpcpd', 'name': 'LPCPD#', 'desc': 'Power down'}, - {'id': 'lsmi', 'name': 'LSMI#', 'desc': 'System Management Interrupt'}, - ) - annotations = ( - ('warnings', 'Warnings'), - ('start', 'Start'), - ('cycle-type', 'Cycle-type/direction'), - ('addr', 'Address'), - ('tar1', 'Turn-around cycle 1'), - ('sync', 'Sync'), - ('timeout', 'Time Out'), - ('data', 'Data'), - ('tar2', 'Turn-around cycle 2'), - ) - annotation_rows = ( - ('data', 'Data', (1, 2, 3, 4, 5, 6, 7, 8)), - ('warnings', 'Warnings', (0,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.state = 'IDLE' - self.oldlclk = -1 - self.samplenum = 0 - self.lad = -1 - self.addr = 0 - self.direction = 0 - self.cur_nibble = 0 - self.cycle_type = -1 - self.databyte = 0 - self.tarcount = 0 - self.synccount = 0 - self.timeoutcount = 0 - self.oldpins = None - self.ss_block = self.es_block = None - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putb(self, data): - self.put(self.ss_block, self.es_block, self.out_ann, data) - - def handle_get_start(self, lframe): - # LAD[3:0]: START field (1 clock cycle). - - # The last value of LAD[3:0] before LFRAME# gets de-asserted is what - # the peripherals must use. However, the host can keep LFRAME# asserted - # multiple clocks, and we output all START fields that occur, even - # though the peripherals are supposed to ignore all but the last one. - self.es_block = self.samplenum - self.putb([1, [fields['START'][self.oldlad], 'START', 'St', 'S']]) - self.ss_block = self.samplenum - - - # LFRAME# is asserted (low). Wait until it gets de-asserted again - # (the host is allowed to keep it asserted multiple clocks). - if lframe != 1: - return - - if (self.oldlad == 0b0000 or self.oldlad == 0b0101): - self.start_field = self.oldlad - self.state = 'GET CT/DR' - elif (self.oldlad == 0b1101 or self.oldlad == 0b1110): - self.start_field = self.oldlad - if (self.oldlad == 0b1110): - self.direction = True - else: - self.direction = False - self.state = 'GET FW IDSEL' - else: - self.state = 'IDLE' - - def handle_get_ct_dr(self): - # LAD[3:0]: Cycle type / direction field (1 clock cycle). - - self.cycle_type = fields['CT_DR'][self.oldlad] - self.direction = fields['CT_DR_WR'][self.oldlad] - - # TODO: Warning/error on invalid cycle types. - if self.cycle_type == 'Reserved': - self.putb([0, ['Invalid cycle type (%s)' % self.oldlad_bits]]) - - self.es_block = self.samplenum - self.putb([2, ['Cycle type: %s' % self.cycle_type]]) - self.ss_block = self.samplenum - - self.state = 'GET ADDR' - self.addr = 0 - self.cur_nibble = 0 - - def handle_get_fw_idsel(self): - # LAD[3:0]: IDSEL field (1 clock cycle). - self.es_block = self.samplenum - s = 'IDSEL: 0x%%0%dx' % self.oldlad - self.putb([3, [s % self.oldlad]]) - self.ss_block = self.samplenum - - self.state = 'GET FW ADDR' - self.addr = 0 - self.cur_nibble = 0 - - def handle_get_fw_addr(self): - # LAD[3:0]: ADDR field (7 clock cycles). - addr_nibbles = 7 # Address is 28bits. - - # Addresses are driven MSN-first. - offset = ((addr_nibbles - 1) - self.cur_nibble) * 4 - if (offset < 0): - self.putb([0, ['Warning: Invalid address shift: %d' % offset]]) - self.state = 'IDLE' - return - self.addr |= (self.oldlad << offset) - - # Continue if we haven't seen all ADDR cycles, yet. - if (self.cur_nibble < addr_nibbles - 1): - self.cur_nibble += 1 - return - - self.es_block = self.samplenum - s = 'Address: 0x%%0%dx' % addr_nibbles - self.putb([3, [s % self.addr]]) - self.ss_block = self.samplenum - - self.state = 'GET FW MSIZE' - - def handle_get_fw_msize(self): - # LAD[3:0]: MSIZE field (1 clock cycle). - self.es_block = self.samplenum - s = 'MSIZE: 0x%%0%dx' % self.oldlad - self.putb([3, [s % self.oldlad]]) - self.ss_block = self.samplenum - self.msize = self.oldlad - - if self.direction == 1: - self.state = 'GET FW DATA' - self.cycle_count = 0 - self.dataword = 0 - self.cur_nibble = 0 - else: - self.state = 'GET TAR' - self.tar_count = 0 - - def handle_get_addr(self): - # LAD[3:0]: ADDR field (4/8/0 clock cycles). - - # I/O cycles: 4 ADDR clocks. Memory cycles: 8 ADDR clocks. - # DMA cycles: no ADDR clocks at all. - if self.cycle_type in ('I/O read', 'I/O write'): - addr_nibbles = 4 # Address is 16bits. - elif self.cycle_type in ('Memory read', 'Memory write'): - addr_nibbles = 8 # Address is 32bits. - else: - addr_nibbles = 0 # TODO: How to handle later on? - - # Addresses are driven MSN-first. - offset = ((addr_nibbles - 1) - self.cur_nibble) * 4 - if (offset < 0): - self.putb([0, ['Warning: Invalid address shift: %d' % offset]]) - self.state = 'IDLE' - return - self.addr |= (self.oldlad << offset) - - # Continue if we haven't seen all ADDR cycles, yet. - if (self.cur_nibble < addr_nibbles - 1): - self.cur_nibble += 1 - return - - self.es_block = self.samplenum - s = 'Address: 0x%%0%dx' % addr_nibbles - self.putb([3, [s % self.addr]]) - self.ss_block = self.samplenum - - if self.direction == 1: - self.state = 'GET DATA' - self.cycle_count = 0 - else: - self.state = 'GET TAR' - self.tar_count = 0 - - def handle_get_tar(self): - # LAD[3:0]: First TAR (turn-around) field (2 clock cycles). - - self.es_block = self.samplenum - self.putb([4, ['TAR, cycle %d: %s' % (self.tarcount, self.oldlad_bits)]]) - self.ss_block = self.samplenum - - # On the first TAR clock cycle LAD[3:0] is driven to 1111 by - # either the host or peripheral. On the second clock cycle, - # the host or peripheral tri-states LAD[3:0], but its value - # should still be 1111, due to pull-ups on the LAD lines. - if self.oldlad_bits != '1111': - self.putb([0, ['TAR, cycle %d: %s (expected 1111)' % \ - (self.tarcount, self.oldlad_bits)]]) - - if (self.tarcount != 1): - self.tarcount += 1 - return - - self.tarcount = 0 - self.state = 'GET SYNC' - - def handle_get_sync(self, lframe): - # LAD[3:0]: SYNC field (1-n clock cycles). - - self.sync_val = self.oldlad_bits - self.cycle_type = fields['SYNC'][self.oldlad] - - self.es_block = self.samplenum - # TODO: Warnings if reserved value are seen? - if self.cycle_type == 'Reserved': - self.putb([0, ['SYNC, cycle %d: %s (reserved value)' % \ - (self.synccount, self.sync_val)]]) - - self.es_block = self.samplenum - self.putb([5, ['SYNC, cycle %d: %s' % (self.synccount, self.sync_val)]]) - self.ss_block = self.samplenum - - # TODO - if (self.cycle_type != 'Short wait' and self.cycle_type != 'Long wait'): - self.cycle_count = 0 - if (lframe == 0): - self.state = 'GET TIMEOUT' - elif (self.start_field == 0b1101 or self.start_field == 0b1110): - self.state = 'GET FW DATA' - self.cycle_count = 0 - self.dataword = 0 - self.cur_nibble = 0 - else: - self.state = 'GET DATA' - - def handle_get_timeout(self): - # LFRAME#: tie low (4 clock cycles). - - if (self.oldlframe != 0): - self.putb([0, ['TIMEOUT cycle, LFRAME# must be low for 4 LCLk cycles']]) - self.timeoutcount = 0 - self.state = 'IDLE' - return - - self.es_block = self.samplenum - self.putb([6, ['Timeout %d' % self.timeoutcount]]) - self.ss_block = self.samplenum - - if (self.timeoutcount != 3): - self.timeoutcount += 1 - return - - self.timeoutcount = 0 - self.state = 'IDLE' - - def handle_get_fw_data(self): - # LAD[3:0]: DATA field - if (self.msize == 0b0000): - data_nibbles = 2 # Data is 8bits. - elif (self.msize == 0b0001): - data_nibbles = 4 # Data is 16bits. - elif (self.msize == 0b0010): - data_nibbles = 8 # Data is 32bits. - elif (self.msize == 0b0100): - data_nibbles = 32 # Data is 128bits. - elif (self.msize == 0b0111): - data_nibbles = 256 # Data is 1024bits. - else: - self.putb([0, ['Warning: Invalid MSIZE: %d' % self.msize]]) - self.state = 'IDLE' - return - - # Data is driven LSN-first. - nibble_swap = self.cur_nibble % 2 - offset = ((data_nibbles - 1) - self.cur_nibble) * 4 - if (nibble_swap): - offset += 4 - else: - offset -= 4 - if (offset < 0): - self.putb([0, ['Warning: Invalid data shift: %d' % offset]]) - self.state = 'IDLE' - return - self.dataword |= (self.oldlad << offset) - - # Continue if we haven't seen all DATA cycles, yet. - if (self.cur_nibble < data_nibbles - 1): - self.cur_nibble += 1 - return - - self.es_block = self.samplenum - s = 'DATA: 0x%%0%dx' % data_nibbles - self.putb([3, [s % self.dataword]]) - self.ss_block = self.samplenum - - self.cycle_count = 0 - self.state = 'GET TAR2' - - def handle_get_data(self): - # LAD[3:0]: DATA field (2 clock cycles). - - # Data is driven LSN-first. - if (self.cycle_count == 0): - self.databyte = self.oldlad - elif (self.cycle_count == 1): - self.databyte |= (self.oldlad << 4) - else: - self.putb([0, ['Warning: Invalid cycle_count: %d' % self.cycle_count]]) - self.state = 'IDLE' - return - - if (self.cycle_count != 1): - self.cycle_count += 1 - return - - self.es_block = self.samplenum - self.putb([7, ['DATA: 0x%02x' % self.databyte]]) - self.ss_block = self.samplenum - - self.cycle_count = 0 - self.state = 'GET TAR2' - - def handle_get_tar2(self): - # LAD[3:0]: Second TAR field (2 clock cycles). - - self.es_block = self.samplenum - self.putb([8, ['TAR, cycle %d: %s' % (self.tarcount, self.oldlad_bits)]]) - self.ss_block = self.samplenum - - # On the first TAR clock cycle LAD[3:0] is driven to 1111 by - # either the host or peripheral. On the second clock cycle, - # the host or peripheral tri-states LAD[3:0], but its value - # should still be 1111, due to pull-ups on the LAD lines. - if self.oldlad_bits != '1111': - self.putb([0, ['Warning: TAR, cycle %d: %s (expected 1111)' - % (self.tarcount, self.oldlad_bits)]]) - - if (self.tarcount != 1): - self.tarcount += 1 - return - - self.tarcount = 0 - self.state = 'IDLE' - - def decode(self): - while True: - - # Only look at the signals upon rising LCLK edges. The LPC clock - # is the same as the PCI clock (which is sampled at rising edges). - (lframe, lclk, lad0, lad1, lad2, lad3, lreset, ldrq, serirq, clkrun, lpme, lpcpd, lsmi) = self.wait({1: 'r'}) - - # Store LAD[3:0] bit values (one nibble) in local variables. - # Most (but not all) states need this. - lad = (lad3 << 3) | (lad2 << 2) | (lad1 << 1) | lad0 - lad_bits = '{:04b}'.format(lad) - # self.putb([0, ['LAD: %s' % lad_bits]]) - - # TODO: Only memory read/write is currently supported/tested. - - # Detect host cycle abort requests - if (lframe == 0) and (self.oldlframe == 0): - self.state = 'GET TIMEOUT' - - # State machine - if self.state == 'IDLE': - # A valid LPC cycle starts with LFRAME# being asserted (low). - if lframe == 0: - self.ss_block = self.samplenum - self.state = 'GET START' - self.lad = -1 - else: - self.wait({0: 'f'}) - elif self.state == 'GET START': - self.handle_get_start(lframe) - elif self.state == 'GET CT/DR': - self.handle_get_ct_dr() - elif self.state == 'GET ADDR': - self.handle_get_addr() - elif self.state == 'GET FW IDSEL': - self.handle_get_fw_idsel() - elif self.state == 'GET FW ADDR': - self.handle_get_fw_addr() - elif self.state == 'GET FW MSIZE': - self.handle_get_fw_msize() - elif self.state == 'GET TAR': - self.handle_get_tar() - elif self.state == 'GET SYNC': - self.handle_get_sync(lframe) - elif self.state == 'GET TIMEOUT': - self.handle_get_timeout() - elif self.state == 'GET FW DATA': - self.handle_get_fw_data() - elif self.state == 'GET DATA': - self.handle_get_data() - elif self.state == 'GET TAR2': - self.handle_get_tar2() - - self.oldlframe = lframe - self.oldlad = lad - self.oldlad_bits = lad_bits diff --git a/decoders/ltc242x/__init__.py b/decoders/ltc242x/__init__.py deleted file mode 100644 index 43d9d346..00000000 --- a/decoders/ltc242x/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 Analog Devices Inc. -## -## 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 . -## - -''' -This decoder stacks on top of the 'spi' PD and decodes the -Linear Technology LTC2421/LTC2422 protocol. -''' - -from .pd import Decoder diff --git a/decoders/ltc242x/pd.py b/decoders/ltc242x/pd.py deleted file mode 100644 index 27ae5b99..00000000 --- a/decoders/ltc242x/pd.py +++ /dev/null @@ -1,86 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 Analog Devices Inc. -## -## 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 . -## - -import sigrokdecode as srd - -input_voltage_format = ['%.6fV', '%.2fV'] - -class Decoder(srd.Decoder): - api_version = 3 - id = 'ltc242x' - name = 'LTC242x' - longname = 'Linear Technology LTC242x' - desc = 'Linear Technology LTC2421/LTC2422 1-/2-channel 20-bit ADC.' - license = 'gplv2+' - inputs = ['spi'] - outputs = [] - tags = ['IC', 'Analog/digital'] - annotations = ( - ('ch0_voltage', 'CH0 voltage'), - ('ch1_voltage', 'CH1 voltage'), - ) - annotation_rows = ( - ('ch0_voltages', 'CH0 voltages', (0,)), - ('ch1_voltages', 'CH1 voltages', (1,)), - ) - options = ( - {'id': 'vref', 'desc': 'Reference voltage (V)', 'default': 1.5}, - ) - - def __init__(self): - self.reset() - - def reset(self): - self.data = 0 - self.ss, self.es = 0, 0 - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def handle_input_voltage(self, data): - input_voltage = data & 0x3FFFFF - input_voltage = -(2**21 - input_voltage) - input_voltage = (input_voltage / 0xfffff) * self.options['vref'] - ann = [] - for format in input_voltage_format: - ann.append(format % input_voltage) - - channel = (data & (1 << 22)) >> 22 - self.put(self.ss, self.es, self.out_ann, [channel, ann]) - - def decode(self, ss, es, data): - ptype = data[0] - - if ptype == 'CS-CHANGE': - cs_old, cs_new = data[1:] - if cs_old is not None and cs_old == 0 and cs_new == 1: - self.es = es - self.data >>= 1 - self.handle_input_voltage(self.data) - - self.data = 0 - elif cs_old is not None and cs_old == 1 and cs_new == 0: - self.ss = ss - - elif ptype == 'BITS': - miso = data[2] - for bit in reversed(miso): - self.data = self.data | bit[0] - - self.data <<= 1 diff --git a/decoders/ltc26x7/__init__.py b/decoders/ltc26x7/__init__.py deleted file mode 100644 index efedd4d3..00000000 --- a/decoders/ltc26x7/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 Analog Devices Inc. -## -## 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 . -## - -''' -This decoder stacks on top of the 'i2c' PD and decodes the -Linear Technology LTC2607/LTC2617/LTC2627 protocol. -''' - -from .pd import Decoder diff --git a/decoders/ltc26x7/pd.py b/decoders/ltc26x7/pd.py deleted file mode 100644 index 3255d5fd..00000000 --- a/decoders/ltc26x7/pd.py +++ /dev/null @@ -1,187 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 Analog Devices Inc. -## -## 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 . -## - -import sigrokdecode as srd - -slave_address = { - 0x00: ['GND', 'GND', 'GND', 'G'], - 0x01: ['FLOAT', 'FLOAT', 'FLOAT', 'F'], - 0x02: ['VCC', 'VCC', 'VCC', 'V'], -} - -commands = { - 0x00: ['Write Input Register', 'Write In Reg', 'Wr In Reg', 'WIR'], - 0x01: ['Update DAC', 'Update', 'U'], - 0x03: ['Write and Power Up DAC', 'Write & Power Up', 'W&PU'], - 0x04: ['Power Down DAC', 'Power Down', 'PD'], - 0x0F: ['No Operation', 'No Op', 'NO'], -} - -addresses = { - 0x00: ['DAC A', 'A'], - 0x01: ['DAC B', 'B'], - 0x0F: ['All DACs', 'All'], -} - -input_voltage_format = ['%.6fV', '%.2fV'] - -class Decoder(srd.Decoder): - api_version = 3 - id = 'ltc26x7' - name = 'LTC26x7' - longname = 'Linear Technology LTC26x7' - desc = 'Linear Technology LTC26x7 16-/14-/12-bit rail-to-rail DACs.' - license = 'gplv2+' - inputs = ['i2c'] - outputs = [] - tags = ['IC', 'Analog/digital'] - options = ( - {'id': 'chip', 'desc': 'Chip', 'default': 'ltc2607', - 'values': ('ltc2607', 'ltc2617', 'ltc2627')}, - {'id': 'vref', 'desc': 'Reference voltage (V)', 'default': 1.5}, - ) - annotations = ( - ('slave_addr', 'Slave address'), - ('command', 'Command'), - ('address', 'Address'), - ('dac_a_voltage', 'DAC A voltage'), - ('dac_b_voltage', 'DAC B voltage'), - ) - annotation_rows = ( - ('addr_cmd', 'Address/command', (0, 1, 2)), - ('dac_a_voltages', 'DAC A voltages', (3,)), - ('dac_b_voltages', 'DAC B voltages', (4,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.state = 'IDLE' - self.ss = -1 - self.data = 0x00 - self.dac_val = 0 - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def convert_ternary_str(self, n): - if n == 0: - return [0, 0, 0] - nums = [] - while n: - n, r = divmod(n, 3) - nums.append(r) - while len(nums) < 3: - nums.append(0) - return list(reversed(nums)) - - def handle_slave_addr(self, data): - if data == 0x73: - ann = ['Global address', 'Global addr', 'Glob addr', 'GA'] - self.put(self.ss, self.es, self.out_ann, [0, ann]) - return - ann = ['CA2=%s CA1=%s CA0=%s', '2=%s 1=%s 0=%s', '%s %s %s', '%s %s %s'] - addr = 0 - for i in range(7): - if i in [2, 3]: - continue - offset = i - if i > 3: - offset -= 2 - mask = 1 << i - if data & mask: - mask = 1 << offset - addr |= mask - - addr -= 0x04 - ternary_values = self.convert_ternary_str(addr) - for i in range(len(ann)): - ann[i] = ann[i] % (slave_address[ternary_values[0]][i], - slave_address[ternary_values[1]][i], - slave_address[ternary_values[2]][i]) - self.put(self.ss, self.es, self.out_ann, [0, ann]) - - def handle_cmd_addr(self, data): - cmd_val = (data >> 4) & 0x0F - self.dac_val = (data & 0x0F) - sm = (self.ss + self.es) // 2 - - self.put(self.ss, sm, self.out_ann, [1, commands[cmd_val]]) - self.put(sm, self.es, self.out_ann, [2, addresses[self.dac_val]]) - - def handle_data(self, data): - self.data = (self.data << 8) & 0xFF00 - self.data += data - if self.options['chip'] == 'ltc2617': - self.data = (self.data >> 2) - self.data = (self.options['vref'] * self.data) / 0x3FFF - elif self.options['chip'] == 'ltc2627': - self.data = (self.data >> 4) - self.data = (self.options['vref'] * self.data) / 0x0FFF - else: - self.data = (self.options['vref'] * self.data) / 0xFFFF - ann = [] - for format in input_voltage_format: - ann.append(format % self.data) - self.data = 0 - - if self.dac_val == 0x0F: # All DACs (A and B). - self.put(self.ss, self.es, self.out_ann, [3 + 0, ann]) - self.put(self.ss, self.es, self.out_ann, [3 + 1, ann]) - else: - self.put(self.ss, self.es, self.out_ann, [3 + self.dac_val, ann]) - - def decode(self, ss, es, data): - cmd, databyte = data - self.es = es - - # State machine. - if self.state == 'IDLE': - # Wait for an I²C START condition. - if cmd != 'START': - return - self.state = 'GET SLAVE ADDR' - elif self.state == 'GET SLAVE ADDR': - # Wait for an address write operation. - if cmd != 'ADDRESS WRITE': - return - self.ss = ss - self.handle_slave_addr(databyte) - self.ss = -1 - self.state = 'GET CMD ADDR' - elif self.state == 'GET CMD ADDR': - if cmd != 'DATA WRITE': - return - self.ss = ss - self.handle_cmd_addr(databyte) - self.ss = -1 - self.state = 'WRITE DATA' - elif self.state == 'WRITE DATA': - if cmd == 'DATA WRITE': - if self.ss == -1: - self.ss = ss - self.data = databyte - return - self.handle_data(databyte) - self.ss = -1 - elif cmd == 'STOP': - self.state = 'IDLE' - else: - return diff --git a/decoders/maple_bus/__init__.py b/decoders/maple_bus/__init__.py deleted file mode 100755 index 33b90a5b..00000000 --- a/decoders/maple_bus/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2017 Marcus Comstedt -## -## 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, see . -## - -''' -Maple bus is serial communication protocol used by peripherals for the -SEGA Dreamcast game console. -''' - -from .pd import Decoder diff --git a/decoders/maple_bus/pd.py b/decoders/maple_bus/pd.py deleted file mode 100755 index 0e4e6043..00000000 --- a/decoders/maple_bus/pd.py +++ /dev/null @@ -1,219 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2017 Marcus Comstedt -## Copyright (C) 2019 DreamSourceLab -## -## 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, see . -## - -import sigrokdecode as srd - -ann = [ - ['Size', 'L'], - ['SrcAP', 'S'], - ['DstAP', 'D'], - ['Cmd', 'C'], - ['Data'], - ['Cksum', 'K'], -] - -class Decoder(srd.Decoder): - api_version = 3 - id = 'maple_bus' - name = 'Maple bus' - longname = 'SEGA Maple bus' - desc = 'Maple bus peripheral protocol for SEGA Dreamcast.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Retro computing'] - channels = ( - {'id': 'sdcka', 'name': 'SDCKA', 'desc': 'Data/clock line A'}, - {'id': 'sdckb', 'name': 'SDCKB', 'desc': 'Data/clock line B'}, - ) - annotations = ( - ('start', 'Start pattern'), - ('end', 'End pattern'), - ('start-with-crc', 'Start pattern with CRC'), - ('occupancy', 'SDCKB occupancy pattern'), - ('reset', 'RESET pattern'), - ('bit', 'Bit'), - ('size', 'Data size'), - ('source', 'Source AP'), - ('dest', 'Destination AP'), - ('command', 'Command'), - ('data', 'Data'), - ('checksum', 'Checksum'), - ('frame-error', 'Frame error'), - ('checksum-error', 'Checksum error'), - ('size-error', 'Size error'), - ) - annotation_rows = ( - ('bits', 'Bits', (0, 1, 2, 3, 4, 5)), - ('fields', 'Fields', (6, 7, 8, 9, 10, 11)), - ('warnings', 'Warnings', (12, 13, 14)), - ) - binary = ( - ('size', 'Data size'), - ('source', 'Source AP'), - ('dest', 'Destination AP'), - ('command', 'Command code'), - ('data', 'Data'), - ('checksum', 'Checksum'), - ) - - def __init__(self): - self.reset() - - def reset(self): - pass - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.out_binary = self.register(srd.OUTPUT_BINARY) - self.pending_bit_pos = None - - def putx(self, data): - self.put(self.ss, self.es, self.out_ann, data) - - def putb(self, data): - self.put(self.ss, self.es, self.out_binary, data) - - def byte_annotation(self, bintype, d): - return [bintype + 6, - ['%s: %02X' % (name, d) for name in ann[bintype]] + ['%02X' % d]] - - def got_start(self): - self.putx([0, ['Start pattern', 'Start', 'S']]) - - def got_end(self): - self.putx([1, ['End pattern', 'End', 'E']]) - if self.length != self.expected_length + 1: - self.putx([14, ['Size error', 'L error', 'LE']]) - - def got_start_with_crc(self): - self.putx([2, ['Start pattern with CRC', 'Start CRC', 'SC']]) - - def got_occupancy(self): - self.putx([3, ['SDCKB occupancy pattern', 'Occupancy', 'O']]) - - def got_reset(self): - self.putx([4, ['RESET pattern', 'RESET', 'R']]) - - def output_pending_bit(self): - if self.pending_bit_pos: - self.put(self.pending_bit_pos, self.pending_bit_pos, self.out_ann, [5, ['Bit: %d' % self.pending_bit, '%d' % self.pending_bit]]) - - def got_bit(self, n): - self.output_pending_bit() - self.data = self.data * 2 + n - self.pending_bit = n - self.pending_bit_pos = self.samplenum - - def got_byte(self): - self.output_pending_bit() - bintype = 4 - if self.length < 4: - if self.length == 0: - self.expected_length = 4 * (self.data + 1) - bintype = self.length - elif self.length == self.expected_length: - bintype = 5 - if self.data != self.checksum: - self.putx([13, ['Cksum error', 'K error', 'KE']]) - self.length = self.length + 1 - self.checksum = self.checksum ^ self.data - self.putx(self.byte_annotation(bintype, self.data)) - self.putb([bintype, bytes([self.data])]) - self.pending_bit_pos = None - - def frame_error(self): - self.putx([7, ['Frame error', 'F error', 'FE']]) - - def handle_start(self): - self.wait({0: 'l', 1: 'h'}) - self.ss = self.samplenum - count = 0 - while True: - (sdcka, sdckb) = self.wait([{1: 'f'}, {0: 'r'}]) - if (self.matched & (0b1 << 0)): - count = count + 1 - if (self.matched & (0b1 << 1)): - self.es = self.samplenum - if sdckb == 1: - if count == 4: - self.got_start() - return True - elif count == 6: - self.got_start_with_crc() - return True - elif count == 8: - self.got_occupancy() - return False - elif count >= 14: - self.got_reset() - return False - self.frame_error() - return False - - def handle_byte_or_stop(self): - self.ss = self.samplenum - self.pending_bit_pos = None - initial = True - counta = 0 - countb = 0 - self.data = 0 - while countb < 4: - (sdcka, sdckb) = self.wait([{0: 'f'}, {1: 'f'}]) - self.es = self.samplenum - if (self.matched & (0b1 << 0)): - if counta == countb: - self.got_bit(sdckb) - counta = counta + 1 - elif counta == 1 and countb == 0 and self.data == 0 and sdckb == 0: - self.wait([{0: 'h', 1: 'h'}, {0: 'f'}, {1: 'f'}]) - self.es = self.samplenum - if (self.matched & (0b1 << 0)): - self.got_end() - else: - self.frame_error() - return False - else: - self.frame_error() - return False - elif (self.matched & (0b1 << 1)): - if counta == countb + 1: - self.got_bit(sdcka) - countb = countb + 1 - elif counta == 0 and countb == 0 and sdcka == 1 and initial: - self.ss = self.samplenum - initial = False - else: - self.frame_error() - return False - self.wait({0: 'h'}) - self.es = self.samplenum - self.got_byte() - return True - - def decode(self): - while True: - while not self.handle_start(): - pass - self.length = 0 - self.expected_length = 4 - self.checksum = 0 - while self.handle_byte_or_stop(): - pass diff --git a/decoders/max7219/__init__.py b/decoders/max7219/__init__.py deleted file mode 100755 index 673d3040..00000000 --- a/decoders/max7219/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Paul Evans -## -## 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, see . -## - -''' -This decoder stacks on top of the 'spi' PD and decodes the Maxim MAX7219 and -MAX7221 LED matrix driver protocol. -''' - -from .pd import Decoder diff --git a/decoders/max7219/pd.py b/decoders/max7219/pd.py deleted file mode 100755 index 53067a67..00000000 --- a/decoders/max7219/pd.py +++ /dev/null @@ -1,115 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Paul Evans -## -## 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, see . -## - -import re -import sigrokdecode as srd - -def _decode_intensity(val): - intensity = val & 0x0f - if intensity == 0: - return 'min' - elif intensity == 15: - return 'max' - else: - return intensity - -registers = { - 0x00: ['No-op', lambda _: ''], - 0x09: ['Decode', lambda v: '0b{:08b}'.format(v)], - 0x0A: ['Intensity', _decode_intensity], - 0x0B: ['Scan limit', lambda v: 1 + v], - 0x0C: ['Shutdown', lambda v: 'off' if v else 'on'], - 0x0F: ['Display test', lambda v: 'on' if v else 'off'] -} - -ann_reg, ann_digit, ann_warning = range(3) - -class Decoder(srd.Decoder): - api_version = 3 - id = 'max7219' - name = 'MAX7219' - longname = 'Maxim MAX7219/MAX7221' - desc = 'Maxim MAX72xx series 8-digit LED display driver.' - license = 'gplv2+' - inputs = ['spi'] - outputs = [] - tags = ['Display'] - annotations = ( - ('register', 'Registers written to the device'), - ('digit', 'Digits displayed on the device'), - ('warnings', 'Human-readable warnings'), - ) - annotation_rows = ( - ('commands', 'Commands', (ann_reg, ann_digit)), - ('warnings', 'Warnings', (ann_warning,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - pass - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.pos = 0 - self.cs_start = 0 - - def putreg(self, ss, es, reg, value): - self.put(ss, es, self.out_ann, [ann_reg, ['%s: %s' % (reg, value)]]) - - def putdigit(self, ss, es, digit, value): - self.put(ss, es, self.out_ann, [ann_digit, ['Digit %d: %02X' % (digit, value)]]) - - def putwarn(self, ss, es, message): - self.put(ss, es, self.out_ann, [ann_warning, [message]]) - - def decode(self, ss, es, data): - ptype, mosi, _ = data - - if ptype == 'DATA': - if not self.cs_asserted: - return - - if self.pos == 0: - self.addr = mosi - self.addr_start = ss - elif self.pos == 1: - if self.addr >= 1 and self.addr <= 8: - self.putdigit(self.addr_start, es, self.addr, mosi) - elif self.addr in registers: - name, decoder = registers[self.addr] - self.putreg(self.addr_start, es, name, decoder(mosi)) - else: - self.putwarn(self.addr_start, es, - 'Unknown register %02X' % (self.addr)) - - self.pos += 1 - elif ptype == 'CS-CHANGE': - self.cs_asserted = mosi - if self.cs_asserted: - self.pos = 0 - self.cs_start = ss - else: - if self.pos == 1: - # Don't warn if pos=0 so that CS# glitches don't appear - # as spurious warnings. - self.putwarn(self.cs_start, es, 'Short write') - elif self.pos > 2: - self.putwarn(self.cs_start, es, 'Overlong write') diff --git a/decoders/mcs48/__init__.py b/decoders/mcs48/__init__.py deleted file mode 100755 index b989a2a8..00000000 --- a/decoders/mcs48/__init__.py +++ /dev/null @@ -1,31 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 fenugrec -## -## 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, see . -## - -''' -This protocol decoder de-multiplexes Intel MCS-48 (8039, 8048, etc.) external -program memory accesses. - -This requires 14 channels: 8 for D0-D7 (data and lower 8 bits of address), -4 for A8-A11 (output on port P2), ALE and PSEN. - -An optional A12 is supported, which may be an arbitrary I/O pin driven by -software (use case is dumping ROM of an HP 3478A). -''' - -from .pd import Decoder diff --git a/decoders/mcs48/pd.py b/decoders/mcs48/pd.py deleted file mode 100755 index 50216a41..00000000 --- a/decoders/mcs48/pd.py +++ /dev/null @@ -1,119 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 fenugrec -## Copyright (C) 2019 DreamSourceLab -## -## 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, see . -## - -import sigrokdecode as srd - -class ChannelError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = 'mcs48' - name = 'MCS-48' - longname = 'Intel MCS-48' - desc = 'Intel MCS-48 external memory access protocol.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Retro computing'] - channels = ( - {'id': 'ale', 'name': 'ALE', 'desc': 'Address latch enable'}, - {'id': 'psen', 'name': '/PSEN', 'desc': 'Program store enable'}, - ) + tuple({ - 'id': 'd%d' % i, - 'name': 'D%d' % i, - 'desc': 'CPU data line %d' % i - } for i in range(0, 8) - ) + tuple({ - 'id': 'a%d' % i, - 'name': 'A%d' % i, - 'desc': 'CPU address line %d' % i - } for i in range(8, 12) - ) - optional_channels = tuple({ - 'id': 'a%d' % i, - 'name': 'A%d' % i, - 'desc': 'CPU address line %d' % i - } for i in range(12, 13) - ) - annotations = ( - ('romdata', 'Address:Data'), - ) - binary = ( - ('romdata', 'AAAA:DD'), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.addr = 0 - self.addr_s = 0 - self.data = 0 - self.data_s = 0 - - # Flag to make sure we get an ALE pulse first. - self.started = 0 - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.out_bin = self.register(srd.OUTPUT_BINARY) - - def newaddr(self, addr, data): - # Falling edge on ALE: reconstruct address. - self.started = 1 - addr = sum([bit << i for i, bit in enumerate(addr)]) - addr <<= len(data) - addr |= sum([bit << i for i, bit in enumerate(data)]) - self.addr = addr - self.addr_s = self.samplenum - - def newdata(self, data): - # Edge on PSEN: get data. - data = sum([bit << i for i, bit in enumerate(data)]) - self.data = data - self.data_s = self.samplenum - if self.started: - anntext = '{:04X}:{:02X}'.format(self.addr, self.data) - self.put(self.addr_s, self.data_s, self.out_ann, [0, [anntext]]) - bindata = self.addr.to_bytes(2, byteorder='big') - bindata += self.data.to_bytes(1, byteorder='big') - self.put(self.addr_s, self.data_s, self.out_bin, [0, bindata]) - - def decode(self): - # Address bits above A11 are optional, and are considered to be A12+. - # This logic needs more adjustment when more bank address pins are - # to get supported. For now, having just A12 is considered sufficient. - has_bank = self.has_channel(14) - bank_pin_count = 1 if has_bank else 0 - # Sample address on the falling ALE edge. - # Save data on falling edge of PSEN. - while True: - (ale, psen, d0, d1, d2, d3, d4, d5, d6, d7, a8, a9, a10, a11, a12) = self.wait([{0: 'f'}, {1: 'r'}]) - data = (d0, d1, d2, d3, d4, d5, d6, d7) - addr = (a8, a9, a10, a11) - bank = (a12, ) - if has_bank: - addr += bank[:bank_pin_count] - # Handle those conditions (one or more) that matched this time. - if (self.matched & (0b1 << 0)): - self.newaddr(addr, data) - if (self.matched & (0b1 << 1)): - self.newdata(data) diff --git a/decoders/mdio/__init__.py b/decoders/mdio/__init__.py deleted file mode 100755 index 98213b97..00000000 --- a/decoders/mdio/__init__.py +++ /dev/null @@ -1,39 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2016 Elias Oenal -## All rights reserved. -## -## Redistribution and use in source and binary forms, with or without -## modification, are permitted provided that the following conditions are met: -## -## 1. Redistributions of source code must retain the above copyright notice, -## this list of conditions and the following disclaimer. -## 2. Redistributions in binary form must reproduce the above copyright notice, -## this list of conditions and the following disclaimer in the documentation -## and/or other materials provided with the distribution. -## -## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -## ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -## LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -## POSSIBILITY OF SUCH DAMAGE. -## - -''' -The MDIO (Management Data Input/Output) protocol decoder supports the -MII Management serial bus (a bidirectional bus between the PHY and the STA), -with a clock line (MDC) and a bi-directional data line (MDIO). - -MDIO is also known as SMI (Serial Management Interface). - -It's part of the Ethernet standard. -''' - -from .pd import Decoder diff --git a/decoders/mdio/pd.py b/decoders/mdio/pd.py deleted file mode 100755 index 9ea76c9e..00000000 --- a/decoders/mdio/pd.py +++ /dev/null @@ -1,327 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2016 Elias Oenal -## Copyright (C) 2019 DreamSourceLab -## All rights reserved. -## -## Redistribution and use in source and binary forms, with or without -## modification, are permitted provided that the following conditions are met: -## -## 1. Redistributions of source code must retain the above copyright notice, -## this list of conditions and the following disclaimer. -## 2. Redistributions in binary form must reproduce the above copyright notice, -## this list of conditions and the following disclaimer in the documentation -## and/or other materials provided with the distribution. -## -## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -## ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -## LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -## POSSIBILITY OF SUCH DAMAGE. -## - -import sigrokdecode as srd - -class Decoder(srd.Decoder): - api_version = 3 - id = 'mdio' - name = 'MDIO' - longname = 'Management Data Input/Output' - desc = 'MII management bus between MAC and PHY.' - license = 'bsd' - inputs = ['logic'] - outputs = ['mdio'] - tags = ['Networking'] - channels = ( - {'id': 'mdc', 'name': 'MDC', 'desc': 'Clock'}, - {'id': 'mdio', 'name': 'MDIO', 'desc': 'Data'}, - ) - options = ( - {'id': 'show_debug_bits', 'desc': 'Show debug bits', - 'default': 'no', 'values': ('yes', 'no')}, - ) - annotations = ( - ('bit-val', 'Bit value'), - ('bit-num', 'Bit number'), - ('frame', 'Frame'), - ('frame-idle', 'Bus idle state'), - ('frame-error', 'Frame error'), - ('decode', 'Decode'), - ) - annotation_rows = ( - ('bit-val', 'Bit value', (0,)), - ('bit-num', 'Bit number', (1,)), - ('frame', 'Frame', (2, 3)), - ('frame-error', 'Frame error', (4,)), - ('decode', 'Decode', (5,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.illegal_bus = 0 - self.samplenum = -1 - self.clause45_addr = -1 # Clause 45 is context sensitive. - self.reset_decoder_state() - - def start(self): - self.out_python = self.register(srd.OUTPUT_PYTHON) - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putbit(self, mdio, ss, es): - self.put(ss, es, self.out_ann, [0, ['%d' % mdio]]) - if self.options['show_debug_bits'] == 'yes': - self.put(ss, es, self.out_ann, [1, ['%d' % (self.bitcount - 1), '%d' % ((self.bitcount - 1) % 10)]]) - - def putff(self, data): - self.put(self.ss_frame_field, self.samplenum, self.out_ann, data) - - def putdata(self): - self.put(self.ss_frame_field, self.mdiobits[0][2], self.out_ann, - [2, ['DATA: %04X' % self.data, 'DATA', 'D']]) - - if self.clause45 and self.opcode == 0: - self.clause45_addr = self.data - - # Decode data. - if self.opcode > 0 or not self.clause45: - decoded_min = '' - if self.clause45 and self.clause45_addr != -1: - decoded_min += str.format('ADDR: %04X ' % self.clause45_addr) - elif self.clause45: - decoded_min += str.format('ADDR: UKWN ') - - if self.clause45 and self.opcode > 1 \ - or (not self.clause45 and self.opcode): - decoded_min += str.format('READ: %04X' % self.data) - is_read = 1 - else: - decoded_min += str.format('WRITE: %04X' % self.data) - is_read = 0 - decoded_ext = str.format(' %s: %02d' % \ - ('PRTAD' if self.clause45 else 'PHYAD', self.portad)) - decoded_ext += str.format(' %s: %02d' % \ - ('DEVAD' if self.clause45 else 'REGAD', self.devad)) - if self.ta_invalid or self.op_invalid: - decoded_ext += ' ERROR' - self.put(self.ss_frame, self.mdiobits[0][2], self.out_ann, - [5, [decoded_min + decoded_ext, decoded_min]]) - - self.put(self.ss_frame, self.mdiobits[0][2], self.out_python, - [(bool(self.clause45), int(self.clause45_addr), \ - bool(is_read), int(self.portad), int(self.devad), \ - int(self.data))]) - - # Post read increment address. - if self.clause45 and self.opcode == 2 and self.clause45_addr != -1: - self.clause45_addr += 1 - - def reset_decoder_state(self): - self.mdiobits = [] - self.bitcount = -1 - self.opcode = -1 - self.clause45 = 0 - self.ss_frame = -1 - self.ss_frame_field = -1 - self.preamble_len = 0 - self.ta_invalid = -1 - self.op_invalid = '' - self.portad = -1 - self.portad_bits = 5 - self.devad = -1 - self.devad_bits = 5 - self.data = -1 - self.data_bits = 16 - self.state = 'PRE' - - def state_PRE(self, mdio): - if self.illegal_bus: - if mdio == 0: # Stay in illegal bus state. - return - else: # Leave and continue parsing. - self.illegal_bus = 0 - self.put(self.ss_illegal, self.samplenum, self.out_ann, - [4, ['ILLEGAL BUS STATE', 'ILL']]) - self.ss_frame = self.samplenum - - if self.ss_frame == -1: - self.ss_frame = self.samplenum - - if mdio == 1: - self.preamble_len += 1 - - # Valid MDIO can't clock more than 16 succeeding ones without being - # in either IDLE or PRE. - if self.preamble_len > 16: - if self.preamble_len >= 10000 + 32: - self.put(self.ss_frame, self.mdiobits[32][1], self.out_ann, - [3, ['IDLE #%d' % (self.preamble_len - 32), 'IDLE', 'I']]) - self.ss_frame = self.mdiobits[32][1] - self.preamble_len = 32 - # This is getting out of hand, free some memory. - del self.mdiobits[33:-1] - if mdio == 0: - if self.preamble_len < 32: - self.ss_frame = self.mdiobits[self.preamble_len][1] - self.put(self.ss_frame, self.samplenum, self.out_ann, - [4, ['SHORT PREAMBLE', 'SHRT PRE']]) - elif self.preamble_len > 32: - self.ss_frame = self.mdiobits[32][1] - self.put(self.mdiobits[self.preamble_len][1], - self.mdiobits[32][1], self.out_ann, - [3, ['IDLE #%d' % (self.preamble_len - 32), - 'IDLE', 'I']]) - self.preamble_len = 32 - else: - self.ss_frame = self.mdiobits[32][1] - self.put(self.ss_frame, self.samplenum, self.out_ann, - [2, ['PRE #%d' % self.preamble_len, 'PRE', 'P']]) - self.ss_frame_field = self.samplenum - self.state = 'ST' - elif mdio == 0: - self.ss_illegal = self.ss_frame - self.illegal_bus = 1 - - def state_ST(self, mdio): - if mdio == 0: - self.clause45 = 1 - self.state = 'OP' - - def state_OP(self, mdio): - if self.opcode == -1: - if self.clause45: - st = ['ST (Clause 45)', 'ST 45'] - else: - st = ['ST (Clause 22)', 'ST 22'] - self.putff([2, st + ['ST', 'S']]) - self.ss_frame_field = self.samplenum - - if mdio: - self.opcode = 2 - else: - self.opcode = 0 - else: - if self.clause45: - self.state = 'PRTAD' - self.opcode += mdio - else: - if mdio == self.opcode: - self.op_invalid = 'invalid for Clause 22' - self.state = 'PRTAD' - - def state_PRTAD(self, mdio): - if self.portad == -1: - self.portad = 0 - if self.clause45: - if self.opcode == 0: - op = ['OP: ADDR', 'OP: A'] - elif self.opcode == 1: - op = ['OP: WRITE', 'OP: W'] - elif self.opcode == 2: - op = ['OP: READINC', 'OP: RI'] - elif self.opcode == 3: - op = ['OP: READ', 'OP: R'] - else: - op = ['OP: READ', 'OP: R'] if self.opcode else ['OP: WRITE', 'OP: W'] - self.putff([2, op + ['OP', 'O']]) - if self.op_invalid: - self.putff([4, ['OP %s' % self.op_invalid, 'OP', 'O']]) - self.ss_frame_field = self.samplenum - self.portad_bits -= 1 - self.portad |= mdio << self.portad_bits - if not self.portad_bits: - self.state = 'DEVAD' - - def state_DEVAD(self, mdio): - if self.devad == -1: - self.devad = 0 - if self.clause45: - prtad = ['PRTAD: %02d' % self.portad, 'PRT', 'P'] - else: - prtad = ['PHYAD: %02d' % self.portad, 'PHY', 'P'] - self.putff([2, prtad]) - self.ss_frame_field = self.samplenum - self.devad_bits -= 1 - self.devad |= mdio << self.devad_bits - if not self.devad_bits: - self.state = 'TA' - - def state_TA(self, mdio): - if self.ta_invalid == -1: - self.ta_invalid = '' - if self.clause45: - regad = ['DEVAD: %02d' % self.devad, 'DEV', 'D'] - else: - regad = ['REGAD: %02d' % self.devad, 'REG', 'R'] - self.putff([2, regad]) - self.ss_frame_field = self.samplenum - if mdio != 1 and ((self.clause45 and self.opcode < 2) - or (not self.clause45 and self.opcode == 0)): - self.ta_invalid = ' invalid (bit1)' - else: - if mdio != 0: - if self.ta_invalid: - self.ta_invalid = ' invalid (bit1 and bit2)' - else: - self.ta_invalid = ' invalid (bit2)' - self.state = 'DATA' - - def state_DATA(self, mdio): - if self.data == -1: - self.data = 0 - self.putff([2, ['TA', 'T']]) - if self.ta_invalid: - self.putff([4, ['TA%s' % self.ta_invalid, 'TA', 'T']]) - self.ss_frame_field = self.samplenum - self.data_bits -= 1 - self.data |= mdio << self.data_bits - if not self.data_bits: - # Output final bit. - self.mdiobits[0][2] = self.mdiobits[0][1] + self.quartile_cycle_length() - self.bitcount += 1 - self.putbit(self.mdiobits[0][0], self.mdiobits[0][1], self.mdiobits[0][2]) - self.putdata() - self.reset_decoder_state() - - def process_state(self, argument, mdio): - method_name = 'state_' + str(argument) - method = getattr(self, method_name) - return method(mdio) - - # Returns the first quartile point of the frames cycle lengths. This is a - # conservative guess for the end of the last cycle. On average it will be - # more likely to fall short, than being too long, which makes for better - # readability in GUIs. - def quartile_cycle_length(self): - # 48 is the minimum number of samples we have to have at the end of a - # frame. The last sample only has a leading clock edge and is ignored. - bitlen = [] - for i in range(1, 49): - bitlen.append(self.mdiobits[i][2] - self.mdiobits[i][1]) - bitlen = sorted(bitlen) - return bitlen[12] - - def handle_bit(self, mdio): - self.bitcount += 1 - self.mdiobits.insert(0, [mdio, self.samplenum, -1]) - - if self.bitcount > 0: - self.mdiobits[1][2] = self.samplenum # Note end of last cycle. - # Output the last bit we processed. - self.putbit(self.mdiobits[1][0], self.mdiobits[1][1], self.mdiobits[1][2]) - - self.process_state(self.state, mdio) - - def decode(self): - while True: - # Process pin state upon rising MDC edge. - (mdc, mdio) = self.wait({0: 'r'}) - self.handle_bit(mdio) diff --git a/decoders/microwire/__init__.py b/decoders/microwire/__init__.py deleted file mode 100755 index 53f52d09..00000000 --- a/decoders/microwire/__init__.py +++ /dev/null @@ -1,40 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2017 Kevin Redon -## -## 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, see . -## - -''' -Microwire is a 3-wire half-duplex synchronous serial communication protocol. - -Originally from National Semiconductor, it is often used in EEPROM chips with -device specific commands on top of the bit stream. - -Channels: - - - CS: chip select, active high - - SK: clock line, for the synchronous communication (idle low) - - SI: slave data input, output by the master and parsed by the selected slave - on rising edge of clock line (idle low) - - SO: slave data output, output by the selected slave and changed on rising - edge of clock line, or goes from low to high when ready during status - check (idle high impedance) - -The channel names might vary from chip to chip but the underlying function is -the same. -''' - -from .pd import Decoder diff --git a/decoders/microwire/pd.py b/decoders/microwire/pd.py deleted file mode 100755 index 47d87b85..00000000 --- a/decoders/microwire/pd.py +++ /dev/null @@ -1,195 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2017 Kevin Redon -## Copyright (C) 2019 DreamSourceLab -## -## 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, see . -## - -import sigrokdecode as srd -from collections import namedtuple - -''' -OUTPUT_PYTHON format: - -Packet: -[namedtuple('ss': bit start sample number, - 'es': bit end sample number, - 'si': SI bit, - 'so': SO bit, - ), ...] - -Since address and word size are variable, a list of all bits in each packet -need to be output. Since Microwire is a synchronous protocol with separate -input and output lines (SI and SO) they are provided together, but because -Microwire is half-duplex only the SI or SO bits will be considered at once. -To be able to annotate correctly the instructions formed by the bit, the start -and end sample number of each bit (pair of SI/SO bit) are provided. -''' - -PyPacket = namedtuple('PyPacket', 'ss es si so') -Packet = namedtuple('Packet', 'samplenum matched cs sk si so') - -class Decoder(srd.Decoder): - api_version = 3 - id = 'microwire' - name = 'Microwire' - longname = 'Microwire' - desc = '3-wire, half-duplex, synchronous serial bus.' - license = 'gplv2+' - inputs = ['logic'] - outputs = ['microwire'] - tags = ['Embedded/industrial'] - channels = ( - {'id': 'cs', 'name': 'CS', 'desc': 'Chip select'}, - {'id': 'sk', 'name': 'SK', 'desc': 'Clock'}, - {'id': 'si', 'name': 'SI', 'desc': 'Slave in'}, - {'id': 'so', 'name': 'SO', 'desc': 'Slave out'}, - ) - annotations = ( - ('start-bit', 'Start bit'), - ('si-bit', 'SI bit'), - ('so-bit', 'SO bit'), - ('status-check-ready', 'Status check ready'), - ('status-check-busy', 'Status check busy'), - ('warning', 'Warning'), - ) - annotation_rows = ( - ('si-bits', 'SI bits', (0, 1)), - ('so-bits', 'SO bits', (2,)), - ('status', 'Status', (3, 4)), - ('warnings', 'Warnings', (5,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - pass - - def start(self): - self.out_python = self.register(srd.OUTPUT_PYTHON) - self.out_ann = self.register(srd.OUTPUT_ANN) - - def decode(self): - while True: - # Wait for slave to be selected on rising CS. - (cs, sk, si, so) = self.wait({0: 'r'}) - if sk: - self.put(self.samplenum, self.samplenum, self.out_ann, - [5, ['Clock should be low on start', - 'Clock high on start', 'Clock high', 'SK high']]) - sk = 0 # Enforce correct state for correct clock handling. - # Because we don't know if this is bit communication or a - # status check we have to collect the SI and SO values on SK - # edges while the chip is selected and figure out afterwards. - packet = [] - while cs: - # Save change. - packet.append(Packet(self.samplenum, self.matched, cs, sk, si, so)) - edge = 'r' if sk == 0 else 'f' - (cs, sk, si, so) = self.wait([{0: 'l'}, {1: edge}, {3: 'e'}]) - # Save last change. - packet.append(Packet(self.samplenum, self.matched, cs, sk, si, so)) - - # Figure out if this is a status check. - # Either there is no clock or no start bit (on first rising edge). - status_check = True - for change in packet: - # Get first clock rising edge. - if (change.matched & (0b1 << 1)) and change.sk: - if change.si: - status_check = False - break - - # The packet is for a status check. - # SO low = busy, SO high = ready. - # The SO signal might be noisy in the beginning because it starts - # in high impedance. - if status_check: - start_samplenum = packet[0].samplenum - bit_so = packet[0].so - # Check for SO edges. - for change in packet: - if (change.matched & (0b1 << 2)): - if bit_so == 0 and change.so: - # Rising edge Busy -> Ready. - self.put(start_samplenum, change.samplenum, - self.out_ann, [4, ['Busy', 'B']]) - start_samplenum = change.samplenum - bit_so = change.so - # Put last state. - if bit_so == 0: - self.put(start_samplenum, packet[-1].samplenum, - self.out_ann, [4, ['Busy', 'B']]) - else: - self.put(start_samplenum, packet[-1].samplenum, - self.out_ann, [3, ['Ready', 'R']]) - else: - # Bit communication. - # Since the slave samples SI on clock rising edge we do the - # same. Because the slave changes SO on clock rising edge we - # sample on the falling edge. - bit_start = 0 # Rising clock sample of bit start. - bit_si = 0 # SI value at rising clock edge. - bit_so = 0 # SO value at falling clock edge. - start_bit = True # Start bit incoming (first bit). - pydata = [] # Python output data. - for change in packet: - if (change.matched & (0b1 << 1)): - # Clock edge. - if change.sk: # Rising clock edge. - if bit_start > 0: # Bit completed. - if start_bit: - if bit_si == 0: # Start bit missing. - self.put(bit_start, change.samplenum, - self.out_ann, - [5, ['Start bit not high', - 'Start bit low']]) - else: - self.put(bit_start, change.samplenum, - self.out_ann, - [0, ['Start bit', 'S']]) - start_bit = False - else: - self.put(bit_start, change.samplenum, - self.out_ann, - [1, ['SI bit: %d' % bit_si, - 'SI: %d' % bit_si, - '%d' % bit_si]]) - self.put(bit_start, change.samplenum, - self.out_ann, - [2, ['SO bit: %d' % bit_so, - 'SO: %d' % bit_so, - '%d' % bit_so]]) - pydata.append(PyPacket(bit_start, - change.samplenum, bit_si, bit_so)) - bit_start = change.samplenum - bit_si = change.si - else: # Falling clock edge. - bit_so = change.so - elif (change.matched & (0b1 << 0)) and \ - change.cs == 0 and change.sk == 0: - # End of packet. - self.put(bit_start, change.samplenum, self.out_ann, - [1, ['SI bit: %d' % bit_si, - 'SI: %d' % bit_si, '%d' % bit_si]]) - self.put(bit_start, change.samplenum, self.out_ann, - [2, ['SO bit: %d' % bit_so, - 'SO: %d' % bit_so, '%d' % bit_so]]) - pydata.append(PyPacket(bit_start, change.samplenum, - bit_si, bit_so)) - self.put(packet[0].samplenum, packet[len(packet) - 1].samplenum, - self.out_python, pydata) diff --git a/decoders/midi/__init__.py b/decoders/midi/__init__.py deleted file mode 100755 index 378b0167..00000000 --- a/decoders/midi/__init__.py +++ /dev/null @@ -1,28 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2013 Uwe Hermann -## -## 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, see . -## - -''' -This decoder stacks on top of the 'uart' PD and decodes the MIDI -(Musical Instrument Digital Interface) protocol. - -MIDI is layered on top of the UART (async serial) protocol, with a fixed -baud rate of 31250 baud (+/- 1%) and 8n1 settings. Bytes are sent LSB-first. -''' - -from .pd import Decoder diff --git a/decoders/midi/lists.py b/decoders/midi/lists.py deleted file mode 100755 index 1e628615..00000000 --- a/decoders/midi/lists.py +++ /dev/null @@ -1,840 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2013-2016 Uwe Hermann -## Copyright (C) 2016 Chris Dreher -## -## 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, see . -## - -# Each status byte has 3 string names, each shorter than the previous -status_bytes = { - # Channel voice messages - 0x80: ['note off', 'note off', 'N off'], - 0x90: ['note on', 'note on', 'N on'], # However, velocity = 0 means "note off". - 0xa0: ['polyphonic key pressure / aftertouch', 'key pressure', 'KP' ], - 0xb0: ['control change', 'ctrl chg', 'CC'], - 0xc0: ['program change', 'prgm chg', 'PC'], - 0xd0: ['channel pressure / aftertouch', 'channel pressure', 'CP'], - 0xe0: ['pitch bend change', 'pitch bend', 'PB'], - - # Channel mode messages - # 0xb0: 'select channel mode', # Note: Same as 'control change'. - - # System exclusive messages - 0xf0: ['system exclusive', 'SysEx', 'SE'], - - # System common messages - 0xf1: ['MIDI time code quarter frame', 'MIDI time code', 'MIDI time'], - 0xf2: ['song position pointer', 'song position', 'song pos'], - 0xf3: ['song select', 'song select', 'song sel'], - 0xf4: ['undefined 0xf4', 'undef 0xf4', 'undef'], - 0xf5: ['undefined 0xf5', 'undef 0xf5', 'undef'], - 0xf6: ['tune request', 'tune request', 'tune req'], - 0xf7: ['end of system exclusive (EOX)', 'end of SysEx', 'EOX'], - - # System real time messages - 0xf8: ['timing clock', 'timing clock', 'clock'], - 0xf9: ['undefined 0xf9', 'undef 0xf9', 'undef'], - 0xfa: ['start', 'start', 's'], - 0xfb: ['continue', 'continue', 'cont'], - 0xfc: ['stop', 'stop', 'st'], - 0xfd: ['undefined 0xfd', 'undef 0xfd', 'undef'], - 0xfe: ['active sensing', 'active sensing', 'sensing'], - 0xff: ['system reset', 'reset', 'rst'], -} - -# Universal system exclusive (SysEx) messages, non-realtime (0x7e) -universal_sysex_nonrealtime = { - (0x00, None): 'unused', - (0x01, None): 'sample dump header', - (0x02, None): 'sample data packet', - (0x03, None): 'sample dump request', - - (0x04, None): 'MIDI time code', - (0x04, 0x00): 'special', - (0x04, 0x01): 'punch in points', - (0x04, 0x02): 'punch out points', - (0x04, 0x03): 'delete punch in point', - (0x04, 0x04): 'delete punch out point', - (0x04, 0x05): 'event start point', - (0x04, 0x06): 'event stop point', - (0x04, 0x07): 'event start points with additional info', - (0x04, 0x08): 'event stop points with additional info', - (0x04, 0x09): 'delete event start point', - (0x04, 0x0a): 'delete event stop point', - (0x04, 0x0b): 'cue points', - (0x04, 0x0c): 'cue points with additional info', - (0x04, 0x0d): 'delete cue point', - (0x04, 0x0e): 'event name in additional info', - - (0x05, None): 'sample dump extensions', - (0x05, 0x01): 'multiple loop points', - (0x05, 0x02): 'loop points request', - - (0x06, None): 'general information', - (0x06, 0x01): 'identity request', - (0x06, 0x02): 'identity reply', - - (0x07, None): 'file dump', - (0x07, 0x01): 'header', - (0x07, 0x02): 'data packet', - (0x07, 0x03): 'request', - - (0x08, None): 'MIDI tuning standard', - (0x08, 0x00): 'bulk dump request', - (0x08, 0x01): 'bulk dump reply', - - (0x09, None): 'general MIDI', - (0x09, 0x01): 'general MIDI system on', - (0x09, 0x02): 'general MIDI system off', - - (0x7b, None): 'end of file', - (0x7c, None): 'wait', - (0x7d, None): 'cancel', - (0x7e, None): 'nak', - (0x7f, None): 'ack', -} - -# Universal system exclusive (SysEx) messages, realtime (0x7f) -universal_sysex_realtime = { - (0x00, None): 'unused', - - (0x01, None): 'MIDI time code', - (0x01, 0x01): 'full message', - (0x01, 0x02): 'user bits', - - (0x02, None): 'MIDI show control', - (0x02, 0x00): 'MSC extensions', - # (0x02, TODO): 'TODO', # 0x01 - 0x7f: MSC commands. - - (0x03, None): 'notation information', - (0x03, 0x01): 'bar number', - (0x03, 0x02): 'time signature (immediate)', - (0x03, 0x42): 'time signature (delayed)', - - (0x04, None): 'device control', - (0x04, 0x01): 'master volume', - (0x04, 0x02): 'master balance', - - (0x05, None): 'real time MTC cueing', - (0x05, 0x00): 'special', - (0x05, 0x01): 'punch in points', - (0x05, 0x02): 'punch out points', - (0x05, 0x03): 'reserved', - (0x05, 0x04): 'reserved', - (0x05, 0x05): 'event start points', - (0x05, 0x06): 'event stop points', - (0x05, 0x07): 'event start points with additional info', - (0x05, 0x08): 'event stop points with additional info', - (0x05, 0x09): 'reserved', - (0x05, 0x0a): 'reserved', - (0x05, 0x0b): 'cue points', - (0x05, 0x0c): 'cue points with additional info', - (0x05, 0x0d): 'reserved', - (0x05, 0x0e): 'event name in additional info', - - (0x06, None): 'MIDI machine control commands', - # (0x06, TODO): 'TODO', # 0x00 - 0x7f: MMC commands. - - (0x07, None): 'MIDI machine control responses', - # (0x07, TODO): 'TODO', # 0x00 - 0x7f: MMC commands. - - (0x08, None): 'MIDI tuning standard', - (0x85, 0x02): 'note change', -} - -# Note: Not all IDs are used/listed, i.e. there are some "holes". -sysex_manufacturer_ids = { - # American group (range 01-1f, 000001-001f7f) - (0x01,): 'Sequential', - (0x02,): 'IDP', - (0x03,): 'Voyetra/Octave-Plateau', - (0x04,): 'Moog', - (0x05,): 'Passport Designs', - (0x06,): 'Lexicon', - (0x07,): 'Kurzweil', - (0x08,): 'Fender', - (0x09,): 'Gulbransen', - (0x0a,): 'AKG Acoustics', - (0x0b,): 'Voyce Music', - (0x0c,): 'Waveframe Corp', - (0x0d,): 'ADA Signal Processors', - (0x0e,): 'Garfield Electronics', - (0x0f,): 'Ensoniq', - (0x10,): 'Oberheim', - (0x11,): 'Apple Computer', - (0x12,): 'Grey Matter Response', - (0x13,): 'Digidesign', - (0x14,): 'Palm Tree Instruments', - (0x15,): 'JLCooper Electronics', - (0x16,): 'Lowrey', - (0x17,): 'Adams-Smith', - (0x18,): 'Emu Systems', - (0x19,): 'Harmony Systems', - (0x1a,): 'ART', - (0x1b,): 'Baldwin', - (0x1c,): 'Eventide', - (0x1d,): 'Inventronics', - (0x1f,): 'Clarity', - - (0x00, 0x00, 0x01): 'Time Warner Interactive', - (0x00, 0x00, 0x07): 'Digital Music Corp.', - (0x00, 0x00, 0x08): 'IOTA Systems', - (0x00, 0x00, 0x09): 'New England Digital', - (0x00, 0x00, 0x0a): 'Artisyn', - (0x00, 0x00, 0x0b): 'IVL Technologies', - (0x00, 0x00, 0x0c): 'Southern Music Systems', - (0x00, 0x00, 0x0d): 'Lake Butler Sound Company', - (0x00, 0x00, 0x0e): 'Alesis', - (0x00, 0x00, 0x10): 'DOD Electronics', - (0x00, 0x00, 0x11): 'Studer-Editech', - (0x00, 0x00, 0x14): 'Perfect Fretworks', - (0x00, 0x00, 0x15): 'KAT', - (0x00, 0x00, 0x16): 'Opcode', - (0x00, 0x00, 0x17): 'Rane Corp.', - (0x00, 0x00, 0x18): 'Anadi Inc.', - (0x00, 0x00, 0x19): 'KMX', - (0x00, 0x00, 0x1a): 'Allen & Heath Brenell', - (0x00, 0x00, 0x1b): 'Peavy Electronics', - (0x00, 0x00, 0x1c): '360 Systems', - (0x00, 0x00, 0x1d): 'Spectrum Design and Development', - (0x00, 0x00, 0x1e): 'Marquis Music', - (0x00, 0x00, 0x1f): 'Zeta Systems', - - (0x00, 0x00, 0x20): 'Axxes', - (0x00, 0x00, 0x21): 'Orban', - (0x00, 0x00, 0x24): 'KTI', - (0x00, 0x00, 0x25): 'Breakaway Technologies', - (0x00, 0x00, 0x26): 'CAE', - (0x00, 0x00, 0x29): 'Rocktron Corp.', - (0x00, 0x00, 0x2a): 'PianoDisc', - (0x00, 0x00, 0x2b): 'Cannon Research Group', - (0x00, 0x00, 0x2d): 'Rogers Instrument Corp.', - (0x00, 0x00, 0x2e): 'Blue Sky Logic', - (0x00, 0x00, 0x2f): 'Encore Electronics', - - (0x00, 0x00, 0x30): 'Uptown', - (0x00, 0x00, 0x31): 'Voce', - (0x00, 0x00, 0x32): 'CTI Audio, Inc. (Music. Intel Dev.)', - (0x00, 0x00, 0x33): 'S&S Research', - (0x00, 0x00, 0x34): 'Broderbund Software, Inc.', - (0x00, 0x00, 0x35): 'Allen Organ Co.', - (0x00, 0x00, 0x37): 'Music Quest', - (0x00, 0x00, 0x38): 'APHEX', - (0x00, 0x00, 0x39): 'Gallien Krueger', - (0x00, 0x00, 0x3a): 'IBM', - (0x00, 0x00, 0x3c): 'Hotz Instruments Technologies', - (0x00, 0x00, 0x3d): 'ETA Lighting', - (0x00, 0x00, 0x3e): 'NSI Corporation', - (0x00, 0x00, 0x3f): 'Ad Lib, Inc.', - - (0x00, 0x00, 0x40): 'Richmond Sound Design', - (0x00, 0x00, 0x41): 'Microsoft', - (0x00, 0x00, 0x42): 'The Software Toolworks', - (0x00, 0x00, 0x43): 'Niche/RJMG', - (0x00, 0x00, 0x44): 'Intone', - (0x00, 0x00, 0x47): 'GT Electronics / Groove Tubes', - (0x00, 0x00, 0x49): 'Timeline Vista', - (0x00, 0x00, 0x4a): 'Mesa Boogie', - (0x00, 0x00, 0x4c): 'Sequoia Development', - (0x00, 0x00, 0x4d): 'Studio Electronics', - (0x00, 0x00, 0x4e): 'Euphonix', - (0x00, 0x00, 0x4f): 'InterMIDI, Inc.', - - (0x00, 0x00, 0x50): 'MIDI Solutions', - (0x00, 0x00, 0x51): '3DO Company', - (0x00, 0x00, 0x52): 'Lightwave Research', - (0x00, 0x00, 0x53): 'Micro-W', - (0x00, 0x00, 0x54): 'Spectral Synthesis', - (0x00, 0x00, 0x55): 'Lone Wolf', - (0x00, 0x00, 0x56): 'Studio Technologies', - (0x00, 0x00, 0x57): 'Peterson EMP', - (0x00, 0x00, 0x58): 'Atari', - (0x00, 0x00, 0x59): 'Marion Systems', - (0x00, 0x00, 0x5a): 'Design Event', - (0x00, 0x00, 0x5b): 'Winjammer Software', - (0x00, 0x00, 0x5c): 'AT&T Bell Labs', - (0x00, 0x00, 0x5e): 'Symetrix', - (0x00, 0x00, 0x5f): 'MIDI the World', - - (0x00, 0x00, 0x60): 'Desper Products', - (0x00, 0x00, 0x61): 'Micros\'N MIDI', - (0x00, 0x00, 0x62): 'Accordians Intl', - (0x00, 0x00, 0x63): 'EuPhonics', - (0x00, 0x00, 0x64): 'Musonix', - (0x00, 0x00, 0x65): 'Turtle Beach Systems', - (0x00, 0x00, 0x66): 'Mackie Designs', - (0x00, 0x00, 0x67): 'Compuserve', - (0x00, 0x00, 0x68): 'BES Technologies', - (0x00, 0x00, 0x69): 'QRS Music Rolls', - (0x00, 0x00, 0x6a): 'P G Music', - (0x00, 0x00, 0x6b): 'Sierra Semiconductor', - (0x00, 0x00, 0x6c): 'EpiGraf Audio Visual', - (0x00, 0x00, 0x6d): 'Electronics Deiversified', - (0x00, 0x00, 0x6e): 'Tune 1000', - (0x00, 0x00, 0x6f): 'Advanced Micro Devices', - - (0x00, 0x00, 0x70): 'Mediamation', - (0x00, 0x00, 0x71): 'Sabine Music', - (0x00, 0x00, 0x72): 'Woog Labs', - (0x00, 0x00, 0x73): 'Micropolis', - (0x00, 0x00, 0x74): 'Ta Horng Musical Inst.', - (0x00, 0x00, 0x75): 'eTek (formerly Forte)', - (0x00, 0x00, 0x76): 'Electrovoice', - (0x00, 0x00, 0x77): 'Midisoft', - (0x00, 0x00, 0x78): 'Q-Sound Labs', - (0x00, 0x00, 0x79): 'Westrex', - (0x00, 0x00, 0x7a): 'NVidia', - (0x00, 0x00, 0x7b): 'ESS Technology', - (0x00, 0x00, 0x7c): 'MediaTrix Peripherals', - (0x00, 0x00, 0x7d): 'Brooktree', - (0x00, 0x00, 0x7e): 'Otari', - (0x00, 0x00, 0x7f): 'Key Electronics', - - (0x00, 0x01, 0x01): 'Crystalake Multimedia', - (0x00, 0x01, 0x02): 'Crystal Semiconductor', - (0x00, 0x01, 0x03): 'Rockwell Semiconductor', - - # European group (range 20-3f, 002000-003f7f) - (0x20,): 'Passac', - (0x21,): 'SIEL', - (0x22,): 'Synthaxe', - (0x24,): 'Hohner', - (0x25,): 'Twister', - (0x26,): 'Solton', - (0x27,): 'Jellinghaus MS', - (0x28,): 'Southworth Music Systems', - (0x29,): 'PPG', - (0x2a,): 'JEN', - (0x2b,): 'SSL Limited', - (0x2c,): 'Audio Veritrieb', - (0x2f,): 'Elka', - - (0x30,): 'Dynacord', - (0x31,): 'Viscount', - (0x33,): 'Clavia Digital Instruments', - (0x34,): 'Audio Architecture', - (0x35,): 'GeneralMusic Corp.', - (0x39,): 'Soundcraft Electronics', - (0x3b,): 'Wersi', - (0x3c,): 'Avab Elektronik Ab', - (0x3d,): 'Digigram', - (0x3e,): 'Waldorf Electronics', - (0x3f,): 'Quasimidi', - - (0x00, 0x20, 0x00): 'Dream', - (0x00, 0x20, 0x01): 'Strand Lighting', - (0x00, 0x20, 0x02): 'Amek Systems', - (0x00, 0x20, 0x04): 'Böhm Electronic', - (0x00, 0x20, 0x06): 'Trident Audio', - (0x00, 0x20, 0x07): 'Real World Studio', - (0x00, 0x20, 0x09): 'Yes Technology', - (0x00, 0x20, 0x0a): 'Audiomatica', - (0x00, 0x20, 0x0b): 'Bontempi/Farfisa', - (0x00, 0x20, 0x0c): 'F.B.T. Elettronica', - (0x00, 0x20, 0x0d): 'MidiTemp', - (0x00, 0x20, 0x0e): 'LA Audio (Larking Audio)', - (0x00, 0x20, 0x0f): 'Zero 88 Lighting Limited', - - (0x00, 0x20, 0x10): 'Micon Audio Electronics GmbH', - (0x00, 0x20, 0x11): 'Forefront Technology', - (0x00, 0x20, 0x13): 'Kenton Electronics', - (0x00, 0x20, 0x15): 'ADB', - (0x00, 0x20, 0x16): 'Marshall Products', - (0x00, 0x20, 0x17): 'DDA', - (0x00, 0x20, 0x18): 'BSS', - (0x00, 0x20, 0x19): 'MA Lighting Technology', - (0x00, 0x20, 0x1a): 'Fatar', - (0x00, 0x20, 0x1b): 'QSC Audio', - (0x00, 0x20, 0x1c): 'Artisan Classic Organ', - (0x00, 0x20, 0x1d): 'Orla Spa', - (0x00, 0x20, 0x1e): 'Pinnacle Audio', - (0x00, 0x20, 0x1f): 'TC Electronics', - - (0x00, 0x20, 0x20): 'Doepfer Musikelektronik', - (0x00, 0x20, 0x21): 'Creative Technology Pte', - (0x00, 0x20, 0x22): 'Minami/Seiyddo', - (0x00, 0x20, 0x23): 'Goldstar', - (0x00, 0x20, 0x24): 'Midisoft s.a.s di M. Cima', - (0x00, 0x20, 0x25): 'Samick', - (0x00, 0x20, 0x26): 'Penny and Giles', - (0x00, 0x20, 0x27): 'Acorn Computer', - (0x00, 0x20, 0x28): 'LSC Electronics', - (0x00, 0x20, 0x29): 'Novation EMS', - (0x00, 0x20, 0x2a): 'Samkyung Mechatronics', - (0x00, 0x20, 0x2b): 'Medeli Electronics', - (0x00, 0x20, 0x2c): 'Charlie Lab', - (0x00, 0x20, 0x2d): 'Blue Chip Music Tech', - (0x00, 0x20, 0x2e): 'BEE OH Corp', - - # Japanese group (range 40-5f, 004000-005f7f) - (0x40,): 'Kawai', - (0x41,): 'Roland', - (0x42,): 'Korg', - (0x43,): 'Yamaha', - (0x44,): 'Casio', - (0x46,): 'Kamiya Studio', - (0x47,): 'Akai', - (0x48,): 'Japan Victor', - (0x49,): 'Mesosha', - (0x4a,): 'Hoshino Gakki', - (0x4b,): 'Fujitsu Elect', - (0x4c,): 'Sony', - (0x4d,): 'Nisshin Onpa', - (0x4e,): 'TEAC', - (0x50,): 'Matsushita Electric', - (0x51,): 'Fostex', - (0x52,): 'Zoom', - (0x53,): 'Midori Electronics', - (0x54,): 'Matsushita Communication Industrial', - (0x55,): 'Suzuki Musical Inst. Mfg.', - - # Other (range 60-7c, 006000-007f7f) - - # Special (7d-7f) - (0x7d,): 'Non-Commercial', - (0x7e,): 'Universal Non-Realtime', - (0x7f,): 'Universal Realtime', -} - -control_functions = { - 0x00: ['bank select MSB', 'bank MSB', 'bank-M'], - 0x01: ['modulation wheel/lever MSB', 'modulation MSB', 'mod-M'], - 0x02: ['breath controller MSB', 'breath MSB', 'breath-M'], - # 0x03: undefined MSB - 0x04: ['foot controller MSB', 'foot MSB', 'foot-M'], - 0x05: ['portamento time MSB', 'portamento MSB', 'porta-M'], - 0x06: ['data entry MSB', 'data entry MSB', 'data-M'], - 0x07: ['channel volume MSB (formerly main volume)', 'channel volume MSB', 'ch vol-M'], - 0x08: ['balance MSB', 'bal MSB', 'bal-M'], - # 0x09: undefined MSB - 0x0a: ['pan MSB', 'pan MSB', 'pan-M'], - 0x0b: ['expression controller MSB', 'expression MSB', 'expr-M'], - 0x0c: ['effect control 1 MSB', 'effect 1 MSB', 'eff-1-M'], - 0x0d: ['effect control 2 MSB', 'effect 2 MSB', 'eff-2-M'], - # 0x0e-0x0f: undefined MSB - 0x10: ['general purpose controller 1 MSB', 'GP ctrl 1 MSB', 'GPC-1-M'], - 0x11: ['general purpose controller 2 MSB', 'GP ctrl 2 MSB', 'GPC-2-M'], - 0x12: ['general purpose controller 3 MSB', 'GP ctrl 3 MSB', 'GPC-3-M'], - 0x13: ['general purpose controller 4 MSB', 'GP ctrl 4 MSB', 'GPC-4-M'], - # 0x14-0x1f: undefined MSB - 0x20: ['bank select LSB', 'bank LSB', 'bank-L'], - 0x21: ['modulation wheel/lever LSB', 'modulation LSB', 'mod-L'], - 0x22: ['breath controller LSB', 'breath LSB', 'breath-L'], - # 0x23: undefined LSB - 0x24: ['foot controller LSB', 'foot LSB', 'foot-L'], - 0x25: ['portamento time LSB', 'portamento LSB', 'porta-L'], - 0x26: ['data entry LSB', 'data entry LSB', 'data-L'], - 0x27: ['channel volume LSB (formerly main volume)', 'channel volume LSB', 'ch vol-L'], - 0x28: ['balance LSB', 'bal LSB', 'bal-L'], - # 0x29: undefined LSB - 0x2a: ['pan LSB', 'pan LSB', 'pan-L'], - 0x2b: ['expression controller LSB', 'expression LSB', 'expr-L'], - 0x2c: ['effect control 1 LSB', 'effect 1 LSB', 'eff-1-L'], - 0x2d: ['effect control 2 LSB', 'effect 2 LSB', 'eff-2-L'], - # 0x2e-0x2f: undefined LSB - 0x30: ['general purpose controller 1 LSB', 'GP ctrl 1 LSB', 'GPC-1-L'], - 0x31: ['general purpose controller 2 LSB', 'GP ctrl 2 LSB', 'GPC-2-L'], - 0x32: ['general purpose controller 3 LSB', 'GP ctrl 3 LSB', 'GPC-3-L'], - 0x33: ['general purpose controller 4 LSB', 'GP ctrl 4 LSB', 'GPC-4-L'], - # 0x34-0x3f: undefined LSB - 0x40: ['damper pedal (sustain)', 'sustain', 'sust'], - 0x41: ['portamento on/off', 'porta on/off', 'porta on/off'], - 0x42: ['sostenuto', 'sostenuto', 'sostenuto'], - 0x43: ['soft pedal', 'soft pedal', 'soft pedal'], - 0x44: ['legato footswitch', 'legato switch', 'legato'], # vv: 00-3f = normal, 40-7f = legato - 0x45: ['hold 2', 'hold 2', 'hold 2'], - 0x46: ['sound controller 1 (default: sound variation)', 'sound ctrl 1', 'snd ctrl 1'], - 0x47: ['sound controller 2 (default: timbre / harmonic intensity)', 'sound ctrl 2', 'snd ctrl 2'], - 0x48: ['sound controller 3 (default: release time)', 'sound ctrl 3', 'snd ctrl 3'], - 0x49: ['sound controller 4 (default: attack time)', 'sound ctrl 4', 'snd ctrl 4'], - 0x4a: ['sound controller 5 (default: brightness)', 'sound ctrl 5', 'snd ctrl 5'], - 0x4b: ['sound controller 6 (GM2 default: decay time)', 'sound ctrl 6', 'snd ctrl 6'], - 0x4c: ['sound controller 7 (GM2 default: vibrato rate)', 'sound ctrl 7', 'snd ctrl 7'], - 0x4d: ['sound controller 8 (GM2 default: vibrato depth)', 'sound ctrl 8', 'snd ctrl 8'], - 0x4e: ['sound controller 9 (GM2 default: vibrato delay)', 'sound ctrl 9', 'snd ctrl 9'], - 0x4f: ['sound controller 10', 'sound ctrl 10', 'snd ctrl 10'], - 0x50: ['general purpose controller 5', 'GP controller 5', 'GPC-5'], - 0x51: ['general purpose controller 6', 'GP controller 6', 'GPC-6'], - 0x52: ['general purpose controller 7', 'GP controller 7', 'GPC-7'], - 0x53: ['general purpose controller 8', 'GP controller 8', 'GPC-8'], - 0x54: ['portamento control', 'portamento ctrl', 'porta ctrl'], - # 0x55-0x5a: undefined - 0x5b: ['effects 1 depth (formerly external effects depth)', 'effects 1 depth', 'eff 1 depth'], - 0x5c: ['effects 2 depth (formerly tremolo depth)', 'effects 2 depth', 'eff 2 depth'], - 0x5d: ['effects 3 depth (formerly chorus depth)', 'effects 3 depth', 'eff 3 depth'], - 0x5e: ['effects 4 depth (formerly celeste/detune depth)', 'effects 4 depth', 'eff 4 depth'], - 0x5f: ['effects 5 depth (formerly phaser depth)', 'effects 5 depth', 'eff 5 depth'], - 0x60: ['data increment', 'data inc', 'data++'], - 0x61: ['data decrement', 'data dec', 'data--'], - 0x62: ['Non-Registered Parameter Number LSB', 'NRPN LSB', 'NRPN-L'], - 0x63: ['Non-Registered Parameter Number MSB', 'NRPN MSB', 'NRPN-M'], - 0x64: ['Registered Parameter Number LSB', 'RPN LSB', 'RPN-L'], - 0x65: ['Registered Parameter Number MSB', 'RPN MSB', 'RPN-M'], - # 0x66-0x77: undefined - # 0x78-0x7f: reserved for channel mode messages - 0x78: ['all sound off', 'all snd off', 'snd off'], - 0x79: ['reset all controllers', 'reset all ctrls', 'reset ctrls'], - 0x7a: ['local control', 'local ctrl', 'local ctrl'], - 0x7b: ['all notes off', 'notes off', 'notes off'], - 0x7c: ['omni mode off', 'omni off', 'omni off'], # all notes off - 0x7d: ['omni mode on', 'omni on', 'omni on'], # all notes off - 0x7e: ['mono mode on', 'mono on', 'mono'], # mono mode on, all notes off - 0x7f: ['poly mode on', 'poly on', 'poly'], # mono mode off, all notes off -} - -gm_instruments = { - 1: 'Acoustic Grand Piano', - 2: 'Bright Acoustic Piano', - 3: 'Electric Grand Piano', - 4: 'Honky-tonk Piano', - 5: 'Electric Piano 1', - 6: 'Electric Piano 2', - 7: 'Harpsichord', - 8: 'Clavi', - 9: 'Celesta', - 10: 'Glockenspiel', - 11: 'Music Box', - 12: 'Vibraphone', - 13: 'Marimba', - 14: 'Xylophone', - 15: 'Tubular Bells', - 16: 'Dulcimer', - 17: 'Drawbar Organ', - 18: 'Percussive Organ', - 19: 'Rock Organ', - 20: 'Church Organ', - 21: 'Reed Organ', - 22: 'Accordion', - 23: 'Harmonica', - 24: 'Tango Accordion', - 25: 'Acoustic Guitar (nylon)', - 26: 'Acoustic Guitar (steel)', - 27: 'Electric Guitar (jazz)', - 28: 'Electric Guitar (clean)', - 29: 'Electric Guitar (muted)', - 30: 'Overdriven Guitar', - 31: 'Distortion Guitar', - 32: 'Guitar harmonics', - 33: 'Acoustic Bass', - 34: 'Electric Bass (finger)', - 35: 'Electric Bass (pick)', - 36: 'Fretless Bass', - 37: 'Slap Bass 1', - 38: 'Slap Bass 2', - 39: 'Synth Bass 1', - 40: 'Synth Bass 2', - 41: 'Violin', - 42: 'Viola', - 43: 'Cello', - 44: 'Contrabass', - 45: 'Tremolo Strings', - 46: 'Pizzicato Strings', - 47: 'Orchestral Harp', - 48: 'Timpani', - 49: 'String Ensemble 1', - 50: 'String Ensemble 2', - 51: 'SynthStrings 1', - 52: 'SynthStrings 2', - 53: 'Choir Aahs', - 54: 'Voice Oohs', - 55: 'Synth Voice', - 56: 'Orchestra Hit', - 57: 'Trumpet', - 58: 'Trombone', - 59: 'Tuba', - 60: 'Muted Trumpet', - 61: 'French Horn', - 62: 'Brass Section', - 63: 'SynthBrass 1', - 64: 'SynthBrass 2', - 65: 'Soprano Sax', - 66: 'Alto Sax', - 67: 'Tenor Sax', - 68: 'Baritone Sax', - 69: 'Oboe', - 70: 'English Horn', - 71: 'Bassoon', - 72: 'Clarinet', - 73: 'Piccolo', - 74: 'Flute', - 75: 'Recorder', - 76: 'Pan Flute', - 77: 'Blown Bottle', - 78: 'Shakuhachi', - 79: 'Whistle', - 80: 'Ocarina', - 81: 'Lead 1 (square)', - 82: 'Lead 2 (sawtooth)', - 83: 'Lead 3 (calliope)', - 84: 'Lead 4 (chiff)', - 85: 'Lead 5 (charang)', - 86: 'Lead 6 (voice)', - 87: 'Lead 7 (fifths)', - 88: 'Lead 8 (bass + lead)', - 89: 'Pad 1 (new age)', - 90: 'Pad 2 (warm)', - 91: 'Pad 3 (polysynth)', - 92: 'Pad 4 (choir)', - 93: 'Pad 5 (bowed)', - 94: 'Pad 6 (metallic)', - 95: 'Pad 7 (halo)', - 96: 'Pad 8 (sweep)', - 97: 'FX 1 (rain)', - 98: 'FX 2 (soundtrack)', - 99: 'FX 3 (crystal)', - 100: 'FX 4 (atmosphere)', - 101: 'FX 5 (brightness)', - 102: 'FX 6 (goblins)', - 103: 'FX 7 (echoes)', - 104: 'FX 8 (sci-fi)', - 105: 'Sitar', - 106: 'Banjo', - 107: 'Shamisen', - 108: 'Koto', - 109: 'Kalimba', - 110: 'Bag pipe', - 111: 'Fiddle', - 112: 'Shanai', - 113: 'Tinkle Bell', - 114: 'Agogo', - 115: 'Steel Drums', - 116: 'Woodblock', - 117: 'Taiko Drum', - 118: 'Melodic Tom', - 119: 'Synth Drum', - 120: 'Reverse Cymbal', - 121: 'Guitar Fret Noise', - 122: 'Breath Noise', - 123: 'Seashore', - 124: 'Bird Tweet', - 125: 'Telephone Ring', - 126: 'Helicopter', - 127: 'Applause', - 128: 'Gunshot', -} - -drum_kit = { - 1: 'GM Standard Kit', - 9: 'GS Room Kit', - 17: 'GS Power Kit', - 25: 'GS Power Kit', - 26: 'GS TR-808 Kit', - 33: 'GS Jazz Kit', - 41: 'GS Brush Kit', - 49: 'GS Orchestra Kit', - 57: 'GS Sound FX Kit', - 128: 'GS CM-64/CM-32 Kit', -} - -# Each quarter frame type has 2 string names, each shorter than the previous -quarter_frame_type = { - 0: ['frame count LS nibble', 'frame LSN'], - 1: ['frame count MS nibble', 'frame MSN'], - 2: ['seconds LS nibble', 'sec LSN'], - 3: ['seconds MS nibble', 'sec MSN'], - 4: ['minutes LS nibble', 'min LSN'], - 5: ['minutes MS nibble', 'min MSN'], - 6: ['hours LS nibble', 'hrs LSN'], - 7: ['hours MS nibble and SMPTE type', 'hrs MSN'], -} - -smpte_type = { - 0: '24 fps', - 1: '25 fps', - 2: '30 fps (drop-frame)', - 3: '30 fps (non-drop)', -} - -chromatic_notes = { - 0: 'C-1', - 1: 'C#-1', - 2: 'D-1', - 3: 'D#-1', - 4: 'E-1', - 5: 'F-1', - 6: 'F#-1', - 7: 'G-1', - 8: 'G#-1', - 9: 'A-1', - 10: 'A#-1', - 11: 'B-1', - 12: 'C0', - 13: 'C#0', - 14: 'D0', - 15: 'D#0', - 16: 'E0', - 17: 'F0', - 18: 'F#0', - 19: 'G0', - 20: 'G#0', - 21: 'A0', - 22: 'A#0', - 23: 'B0', - 24: 'C1', - 25: 'C#1', - 26: 'D1', - 27: 'D#1', - 28: 'E1', - 29: 'F1', - 30: 'F#1', - 31: 'G1', - 32: 'G#1', - 33: 'A1', - 34: 'A#1', - 35: 'B1', - 36: 'C2', - 37: 'C#2', - 38: 'D2', - 39: 'D#2', - 40: 'E2', - 41: 'F2', - 42: 'F#2', - 43: 'G2', - 44: 'G#2', - 45: 'A2', - 46: 'A#2', - 47: 'B2', - 48: 'C3', - 49: 'C#3', - 50: 'D3', - 51: 'D#3', - 52: 'E3', - 53: 'F3', - 54: 'F#3', - 55: 'G3', - 56: 'G#3', - 57: 'A3', - 58: 'A#3', - 59: 'B3', - 60: 'C4', - 61: 'C#4', - 62: 'D4', - 63: 'D#4', - 64: 'E4', - 65: 'F4', - 66: 'F#4', - 67: 'G4', - 68: 'G#4', - 69: 'A4', - 70: 'A#4', - 71: 'B4', - 72: 'C5', - 73: 'C#5', - 74: 'D5', - 75: 'D#5', - 76: 'E5', - 77: 'F5', - 78: 'F#5', - 79: 'G5', - 80: 'G#5', - 81: 'A5', - 82: 'A#5', - 83: 'B5', - 84: 'C6', - 85: 'C#6', - 86: 'D6', - 87: 'D#6', - 88: 'E6', - 89: 'F6', - 90: 'F#6', - 91: 'G6', - 92: 'G#6', - 93: 'A6', - 94: 'A#6', - 95: 'B6', - 96: 'C7', - 97: 'C#7', - 98: 'D7', - 99: 'D#7', - 100: 'E7', - 101: 'F7', - 102: 'F#7', - 103: 'G7', - 104: 'G#7', - 105: 'A7', - 106: 'A#7', - 107: 'B7', - 108: 'C8', - 109: 'C#8', - 110: 'D8', - 111: 'D#8', - 112: 'E8', - 113: 'F8', - 114: 'F#8', - 115: 'G8', - 116: 'G#8', - 117: 'A8', - 118: 'A#8', - 119: 'B8', - 120: 'C9', - 121: 'C#9', - 122: 'D9', - 123: 'D#9', - 124: 'E9', - 125: 'F9', - 126: 'F#9', - 127: 'G9', -} - -percussion_notes = { - 35: 'Acoustic Bass Drum', - 36: 'Bass Drum 1', - 37: 'Side Stick', - 38: 'Acoustic Snare', - 39: 'Hand Clap', - 40: 'Electric Snare', - 41: 'Low Floor Tom', - 42: 'Closed Hi Hat', - 43: 'High Floor Tom', - 44: 'Pedal Hi-Hat', - 45: 'Low Tom', - 46: 'Open Hi-Hat', - 47: 'Low-Mid Tom', - 48: 'Hi Mid Tom', - 49: 'Crash Cymbal 1', - 50: 'High Tom', - 51: 'Ride Cymbal 1', - 52: 'Chinese Cymbal', - 53: 'Ride Bell', - 54: 'Tambourine', - 55: 'Splash Cymbal', - 56: 'Cowbell', - 57: 'Crash Cymbal 2', - 58: 'Vibraslap', - 59: 'Ride Cymbal 2', - 60: 'Hi Bongo', - 61: 'Low Bongo', - 62: 'Mute Hi Conga', - 63: 'Open Hi Conga', - 64: 'Low Conga', - 65: 'High Timbale', - 66: 'Low Timbale', - 67: 'High Agogo', - 68: 'Low Agogo', - 69: 'Cabasa', - 70: 'Maracas', - 71: 'Short Whistle', - 72: 'Long Whistle', - 73: 'Short Guiro', - 74: 'Long Guiro', - 75: 'Claves', - 76: 'Hi Wood Block', - 77: 'Low Wood Block', - 78: 'Mute Cuica', - 79: 'Open Cuica', - 80: 'Mute Triangle', - 81: 'Open Triangle', -} diff --git a/decoders/midi/pd.py b/decoders/midi/pd.py deleted file mode 100755 index ae35e123..00000000 --- a/decoders/midi/pd.py +++ /dev/null @@ -1,627 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2013-2016 Uwe Hermann -## Copyright (C) 2016 Chris Dreher -## -## 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, see . -## - -import sigrokdecode as srd -from .lists import * - -RX = 0 -TX = 1 - -class Decoder(srd.Decoder): - api_version = 3 - id = 'midi' - name = 'MIDI' - longname = 'Musical Instrument Digital Interface' - desc = 'Musical Instrument Digital Interface (MIDI) protocol.' - license = 'gplv2+' - inputs = ['uart'] - outputs = [] - tags = ['Audio', 'PC'] - annotations = ( - ('text-verbose', 'Human-readable text (verbose)'), - ('text-sysreal-verbose', 'Human-readable SysReal text (verbose)'), - ('text-error', 'Human-readable Error text'), - ) - annotation_rows = ( - ('normal', 'Normal', (0, 2)), - ('sys-real', 'SysReal', (1,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.state = 'IDLE' - self.status_byte = 0 - self.explicit_status_byte = False - self.cmd = [] - self.ss = None - self.es = None - self.ss_block = None - self.es_block = None - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putx(self, data): - self.put(self.ss_block, self.es_block, self.out_ann, data) - - def get_note_name(self, channel, note): - if channel != 10: - return chromatic_notes[note] - else: - return 'assuming ' + percussion_notes.get(note, 'undefined') - - def check_for_garbage_flush(self, is_flushed): - if is_flushed: - if self.explicit_status_byte: - self.cmd.insert(0, self.status_byte) - self.handle_garbage_msg(None) - - def soft_clear_status_byte(self): - self.explicit_status_byte = False - - def hard_clear_status_byte(self): - self.status_byte = 0 - self.explicit_status_byte = False - - def set_status_byte(self, newbyte): - self.status_byte = newbyte - self.explicit_status_byte = True - - def handle_channel_msg_0x80(self, is_flushed): - # Note off: 8n kk vv - # n = channel, kk = note, vv = velocity - c = self.cmd - if len(c) < 2: - self.check_for_garbage_flush(is_flushed) - return - self.es_block = self.es - msg, chan = self.status_byte & 0xf0, (self.status_byte & 0x0f) + 1 - note, velocity = c[0], c[1] - note_name = self.get_note_name(chan, note) - self.putx([0, ['Channel %d: %s (note = %d \'%s\', velocity = %d)' % \ - (chan, status_bytes[msg][0], note, note_name, velocity), - 'ch %d: %s %d, velocity = %d' % \ - (chan, status_bytes[msg][1], note, velocity), - '%d: %s %d, vel %d' % \ - (chan, status_bytes[msg][2], note, velocity)]]) - self.cmd, self.state = [], 'IDLE' - self.soft_clear_status_byte() - - def handle_channel_msg_0x90(self, is_flushed): - # Note on: 9n kk vv - # n = channel, kk = note, vv = velocity - # If velocity == 0 that actually means 'note off', though. - c = self.cmd - if len(c) < 2: - self.check_for_garbage_flush(is_flushed) - return - self.es_block = self.es - msg, chan = self.status_byte & 0xf0, (self.status_byte & 0x0f) + 1 - note, velocity = c[0], c[1] - s = status_bytes[0x80] if (velocity == 0) else status_bytes[msg] - note_name = self.get_note_name(chan, note) - self.putx([0, ['Channel %d: %s (note = %d \'%s\', velocity = %d)' % \ - (chan, s[0], note, note_name, velocity), - 'ch %d: %s %d, velocity = %d' % \ - (chan, s[1], note, velocity), - '%d: %s %d, vel %d' % \ - (chan, s[2], note, velocity)]]) - self.cmd, self.state = [], 'IDLE' - self.soft_clear_status_byte() - - def handle_channel_msg_0xa0(self, is_flushed): - # Polyphonic key pressure / aftertouch: An kk vv - # n = channel, kk = polyphonic key pressure, vv = pressure value - c = self.cmd - if len(c) < 2: - self.check_for_garbage_flush(is_flushed) - return - self.es_block = self.es - msg, chan = self.status_byte & 0xf0, (self.status_byte & 0x0f) + 1 - note, pressure = c[0], c[1] - note_name = self.get_note_name(chan, note) - self.putx([0, ['Channel %d: %s of %d for note = %d \'%s\'' % \ - (chan, status_bytes[msg][0], pressure, note, note_name), - 'ch %d: %s %d for note %d' % \ - (chan, status_bytes[msg][1], pressure, note), - '%d: %s %d, N %d' % \ - (chan, status_bytes[msg][2], pressure, note)]]) - self.cmd, self.state = [], 'IDLE' - self.soft_clear_status_byte() - - def handle_controller_0x44(self): - # Legato footswitch: Bn 44 vv - # n = channel, vv = value (<= 0x3f: normal, > 0x3f: legato) - c = self.cmd - msg, chan = self.status_byte & 0xf0, (self.status_byte & 0x0f) + 1 - vv = c[1] - t = ('normal', 'no') if vv <= 0x3f else ('legato', 'yes') - self.putx([0, ['Channel %d: %s \'%s\' = %s' % \ - (chan, status_bytes[msg][0], - control_functions[0x44][0], t[0]), - 'ch %d: %s \'%s\' = %s' % \ - (chan, status_bytes[msg][1], - control_functions[0x44][1], t[0]), - '%d: %s \'%s\' = %s' % \ - (chan, status_bytes[msg][2], - control_functions[0x44][2], t[1])]]) - - def handle_controller_0x54(self): - # Portamento control (PTC): Bn 54 kk - # n = channel, kk = source note for pitch reference - c = self.cmd - msg, chan = self.status_byte & 0xf0, (self.status_byte & 0x0f) + 1 - kk = c[1] - kk_name = self.get_note_name(chan, kk) - self.putx([0, ['Channel %d: %s \'%s\' (source note = %d / %s)' % \ - (chan, status_bytes[msg][0], - control_functions[0x54][0], kk, kk_name), - 'ch %d: %s \'%s\' (source note = %d)' % \ - (chan, status_bytes[msg][1], - control_functions[0x54][1], kk), - '%d: %s \'%s\' (src N %d)' % \ - (chan, status_bytes[msg][2], - control_functions[0x54][2], kk)]]) - - def handle_controller_generic(self): - c = self.cmd - msg, chan = self.status_byte & 0xf0, (self.status_byte & 0x0f) + 1 - fn, param = c[0], c[1] - default_name = 'undefined' - ctrl_fn = control_functions.get(fn, default_name) - if ctrl_fn == default_name: - ctrl_fn = ('undefined 0x%02x' % fn, 'undef 0x%02x' % fn, '0x%02x' % fn) - self.putx([0, ['Channel %d: %s \'%s\' (param = 0x%02x)' % \ - (chan, status_bytes[msg][0], ctrl_fn[0], param), - 'ch %d: %s \'%s\' (param = 0x%02x)' % \ - (chan, status_bytes[msg][1], ctrl_fn[1], param), - '%d: %s \'%s\' is 0x%02x' % \ - (chan, status_bytes[msg][2], ctrl_fn[2], param)]]) - - def handle_channel_mode(self): - # Channel Mode: Bn mm vv - # n = channel, mm = mode number (120 - 127), vv = value - c = self.cmd - msg, chan = self.status_byte & 0xf0, (self.status_byte & 0x0f) + 1 - mm, vv = c[0], c[1] - mode_fn = control_functions.get(mm, ('undefined', 'undef', 'undef')) - # Decode the value based on the mode number. - vv_string = ('', '') - if mm == 122: # mode = local control? - if vv == 0: - vv_string = ('off', 'off') - elif vv == 127: # mode = poly mode on? - vv_string = ('on', 'on') - else: - vv_string = ('(non-standard param value of 0x%02x)' % vv, - '0x%02x' % vv) - elif mm == 126: # mode = mono mode on? - if vv != 0: - vv_string = ('(%d channels)' % vv, '(%d ch)' % vv) - else: - vv_string = ('(channels \'basic\' through 16)', - '(ch \'basic\' thru 16)') - elif vv != 0: # All other channel mode messages expect vv == 0. - vv_string = ('(non-standard param value of 0x%02x)' % vv, - '0x%02x' % vv) - self.putx([0, ['Channel %d: %s \'%s\' %s' % \ - (chan, status_bytes[msg][0], mode_fn[0], vv_string[0]), - 'ch %d: %s \'%s\' %s' % \ - (chan, status_bytes[msg][1], mode_fn[1], vv_string[1]), - '%d: %s \'%s\' %s' % \ - (chan, status_bytes[msg][2], mode_fn[2], vv_string[1])]]) - self.cmd, self.state = [], 'IDLE' - self.soft_clear_status_byte() - - def handle_channel_msg_0xb0(self, is_flushed): - # Control change (or channel mode messages): Bn cc vv - # n = channel, cc = control number (0 - 119), vv = control value - c = self.cmd - if len(c) < 2: - self.check_for_garbage_flush(is_flushed) - return - self.es_block = self.es - if c[0] in range(0x78, 0x7f + 1): - self.handle_channel_mode() - return - handle_ctrl = getattr(self, 'handle_controller_0x%02x' % c[0], - self.handle_controller_generic) - handle_ctrl() - self.cmd, self.state = [], 'IDLE' - self.soft_clear_status_byte() - - def handle_channel_msg_0xc0(self, is_flushed): - # Program change: Cn pp - # n = channel, pp = program number (0 - 127) - c = self.cmd - if len(c) < 1: - self.check_for_garbage_flush(is_flushed) - return - self.es_block = self.es - msg, chan = self.status_byte & 0xf0, (self.status_byte & 0x0f) + 1 - pp = self.cmd[0] + 1 - change_type = 'instrument' - name = '' - if chan != 10: # channel != percussion - name = gm_instruments.get(pp, 'undefined') - else: - change_type = 'drum kit' - name = drum_kit.get(pp, 'undefined') - self.putx([0, ['Channel %d: %s to %s %d (assuming %s)' % \ - (chan, status_bytes[msg][0], change_type, pp, name), - 'ch %d: %s to %s %d' % \ - (chan, status_bytes[msg][1], change_type, pp), - '%d: %s %d' % \ - (chan, status_bytes[msg][2], pp)]]) - self.cmd, self.state = [], 'IDLE' - self.soft_clear_status_byte() - - def handle_channel_msg_0xd0(self, is_flushed): - # Channel pressure / aftertouch: Dn vv - # n = channel, vv = pressure value - c = self.cmd - if len(c) < 1: - self.check_for_garbage_flush(is_flushed) - return - self.es_block = self.es - msg, chan = self.status_byte & 0xf0, (self.status_byte & 0x0f) + 1 - vv = self.cmd[0] - self.putx([0, ['Channel %d: %s %d' % (chan, status_bytes[msg][0], vv), - 'ch %d: %s %d' % (chan, status_bytes[msg][1], vv), - '%d: %s %d' % (chan, status_bytes[msg][2], vv)]]) - self.cmd, self.state = [], 'IDLE' - self.soft_clear_status_byte() - - def handle_channel_msg_0xe0(self, is_flushed): - # Pitch bend change: En ll mm - # n = channel, ll = pitch bend change LSB, mm = pitch bend change MSB - c = self.cmd - if len(c) < 2: - self.check_for_garbage_flush(is_flushed) - return - self.es_block = self.es - msg, chan = self.status_byte & 0xf0, (self.status_byte & 0x0f) + 1 - ll, mm = self.cmd[0], self.cmd[1] - decimal = (mm << 7) + ll - self.putx([0, ['Channel %d: %s 0x%02x 0x%02x (%d)' % \ - (chan, status_bytes[msg][0], ll, mm, decimal), - 'ch %d: %s 0x%02x 0x%02x (%d)' % \ - (chan, status_bytes[msg][1], ll, mm, decimal), - '%d: %s (%d)' % \ - (chan, status_bytes[msg][2], decimal)]]) - self.cmd, self.state = [], 'IDLE' - self.soft_clear_status_byte() - - def handle_channel_msg_generic(self, is_flushed): - # TODO: It should not be possible to hit this code. - # It currently can not be unit tested. - msg_type = self.status_byte & 0xf0 - self.es_block = self.es - self.putx([2, ['Unknown channel message type: 0x%02x' % msg_type]]) - self.cmd, self.state = [], 'IDLE' - self.soft_clear_status_byte() - - def handle_channel_msg(self, newbyte): - if newbyte is not None: - if newbyte >= 0x80: - self.set_status_byte(newbyte) - else: - self.cmd.append(newbyte) - msg_type = self.status_byte & 0xf0 - handle_msg = getattr(self, 'handle_channel_msg_0x%02x' % msg_type, - self.handle_channel_msg_generic) - handle_msg(newbyte is None) - - def handle_sysex_msg(self, newbyte): - # SysEx message: 1 status byte, 1-3 manuf. bytes, x data bytes, EOX byte - # - # SysEx messages are variable length, can be terminated by EOX or - # by any non-SysReal status byte, and it clears self.status_byte. - # - # Note: All System message codes don't utilize self.status_byte. - self.hard_clear_status_byte() - if newbyte != 0xf7 and newbyte is not None: # EOX - self.cmd.append(newbyte) - return - self.es_block = self.es - # Note: Unlike other methods, this code pops bytes out of self.cmd - # to isolate the data. - msg = self.cmd.pop(0) - if len(self.cmd) < 1: - self.putx([2, ['%s: truncated manufacturer code (<1 bytes)' % \ - status_bytes[msg][0], - '%s: truncated manufacturer (<1 bytes)' % \ - status_bytes[msg][1], - '%s: trunc. manu.' % status_bytes[msg][2]]]) - self.cmd, self.state = [], 'IDLE' - return - # Extract the manufacturer name (or SysEx realtime or non-realtime). - m1 = self.cmd.pop(0) - manu = (m1,) - if m1 == 0x00: # If byte == 0, then 2 more manufacturer bytes follow. - if len(self.cmd) < 2: - self.putx([2, ['%s: truncated manufacturer code (<3 bytes)' % \ - status_bytes[msg][0], - '%s: truncated manufacturer (<3 bytes)' % \ - status_bytes[msg][1], - '%s: trunc. manu.' % status_bytes[msg][2]]]) - self.cmd, self.state = [], 'IDLE' - return - manu = (m1, self.cmd.pop(0), self.cmd.pop(0)) - default_name = 'undefined' - manu_name = sysex_manufacturer_ids.get(manu, default_name) - if manu_name == default_name: - if len(manu) == 3: - manu_name = ('%s (0x%02x 0x%02x 0x%02x)' % \ - (default_name, manu[0], manu[1], manu[2]), - default_name) - else: - manu_name = ('%s (0x%02x)' % (default_name, manu[0]), - default_name) - else: - manu_name = (manu_name, manu_name) - # Extract the payload, display in 1 of 2 formats - # TODO: Write methods to decode SysEx realtime & non-realtime payloads. - payload0 = '' - payload1 = '' - while len(self.cmd) > 0: - byte = self.cmd.pop(0) - payload0 += '0x%02x ' % (byte) - payload1 += '%02x ' % (byte) - if payload0 == '': - payload0 = '' - payload1 = '<>' - payload = (payload0, payload1) - self.putx([0, ['%s: for \'%s\' with payload %s' % \ - (status_bytes[msg][0], manu_name[0], payload[0]), - '%s: \'%s\', payload %s' % \ - (status_bytes[msg][1], manu_name[1], payload[1]), - '%s: \'%s\', payload %s' % \ - (status_bytes[msg][2], manu_name[1], payload[1])]]) - self.cmd, self.state = [], 'IDLE' - - def handle_syscommon_midi_time_code_quarter_frame_msg(self, newbyte): - # MIDI time code quarter frame: F1 nd - # n = message type - # d = values - # - # Note: All System message codes don't utilize self.status_byte, - # and System Exclusive and System Common clear it. - c = self.cmd - if len(c) < 2: - if newbyte is None: - self.handle_garbage_msg(None) - return - msg = c[0] - nn, dd = (c[1] & 0x70) >> 4, c[1] & 0x0f - group = ('System Common', 'SysCom', 'SC') - self.es_block = self.es - if nn != 7: # If message type does not contain SMPTE type. - self.putx([0, ['%s: %s of %s, value 0x%01x' % \ - (group[0], status_bytes[msg][0], - quarter_frame_type[nn][0], dd), - '%s: %s of %s, value 0x%01x' % \ - (group[1], status_bytes[msg][1], - quarter_frame_type[nn][1], dd), - '%s: %s of %s, value 0x%01x' % \ - (group[2], status_bytes[msg][2], - quarter_frame_type[nn][1], dd)]]) - self.cmd, self.state = [], 'IDLE' - return - tt = (dd & 0x6) >> 1 - self.putx([0, ['%s: %s of %s, value 0x%01x for %s' % \ - (group[0], status_bytes[msg][0], \ - quarter_frame_type[nn][0], dd, smpte_type[tt]), - '%s: %s of %s, value 0x%01x for %s' % \ - (group[1], status_bytes[msg][1], \ - quarter_frame_type[nn][1], dd, smpte_type[tt]), - '%s: %s of %s, value 0x%01x for %s' % \ - (group[2], status_bytes[msg][2], \ - quarter_frame_type[nn][1], dd, smpte_type[tt])]]) - self.cmd, self.state = [], 'IDLE' - - def handle_syscommon_msg(self, newbyte): - # System common messages - # - # There are 5 simple formats (which are directly handled here) and - # 1 complex one called MIDI time code quarter frame. - # - # Note: While the MIDI lists 0xf7 as a "system common" message, it - # is actually only used with SysEx messages so it is processed there. - # - # Note: All System message codes don't utilize self.status_byte. - self.hard_clear_status_byte() - if newbyte is not None: - self.cmd.append(newbyte) - c = self.cmd - msg = c[0] - group = ('System Common', 'SysCom', 'SC') - if msg == 0xf1: - # MIDI time code quarter frame - self.handle_syscommon_midi_time_code_quarter_frame_msg(newbyte) - return - elif msg == 0xf2: - # Song position pointer: F2 ll mm - # ll = LSB position, mm = MSB position - if len(c) < 3: - if newbyte is None: - self.handle_garbage_msg(None) - return - ll, mm = c[1], c[2] - decimal = (mm << 7) + ll - self.es_block = self.es - self.putx([0, ['%s: %s 0x%02x 0x%02x (%d)' % \ - (group[0], status_bytes[msg][0], ll, mm, decimal), - '%s: %s 0x%02x 0x%02x (%d)' % \ - (group[1], status_bytes[msg][1], ll, mm, decimal), - '%s: %s (%d)' % \ - (group[2], status_bytes[msg][2], decimal)]]) - elif msg == 0xf3: - # Song select: F3 ss - # ss = song selection number - if len(c) < 2: - if newbyte is None: - self.handle_garbage_msg(None) - return - ss = c[1] - self.es_block = self.es - self.putx([0, ['%s: %s number %d' % \ - (group[0], status_bytes[msg][0], ss), - '%s: %s number %d' % \ - (group[1], status_bytes[msg][1], ss), - '%s: %s # %d' % \ - (group[2], status_bytes[msg][2], ss)]]) - elif msg == 0xf4 or msg == 0xf5 or msg == 0xf6: - # Undefined 0xf4, Undefined 0xf5, and Tune Request (respectively). - # All are only 1 byte long with no data bytes. - self.es_block = self.es - self.putx([0, ['%s: %s' % (group[0], status_bytes[msg][0]), - '%s: %s' % (group[1], status_bytes[msg][1]), - '%s: %s' % (group[2], status_bytes[msg][2])]]) - self.cmd, self.state = [], 'IDLE' - - def handle_sysrealtime_msg(self, newbyte): - # System realtime message: 0b11111ttt (t = message type) - # - # Important: These messages are handled differently from all others - # because they are allowed to temporarily interrupt other messages. - # The interrupted messages resume after the realtime message is done. - # Thus, they mostly leave 'self' the way it was found. - # - # Note: All System message codes don't utilize self.status_byte. - old_ss_block, old_es_block = self.ss_block, self.es_block - self.ss_block, self.es_block = self.ss, self.es - group = ('System Realtime', 'SysReal', 'SR') - self.putx([1, ['%s: %s' % (group[0], status_bytes[newbyte][0]), - '%s: %s' % (group[1], status_bytes[newbyte][1]), - '%s: %s' % (group[2], status_bytes[newbyte][2])]]) - self.ss_block, self.es_block = old_ss_block, old_es_block - # Deliberately not resetting self.cmd or self.state. - - def handle_garbage_msg(self, newbyte): - # Handle messages that are either not handled or are corrupt. - self.es_block = self.es - if newbyte is not None: - self.cmd.append(newbyte) - return - payload = '' - max_bytes = 16 # Put a limit on the length on the hex dump. - for index in range(len(self.cmd)): - if index == max_bytes: - payload += ' ...' - break - if index == 0: - payload = '0x%02x' % self.cmd[index] - else: - payload += ' 0x%02x' % self.cmd[index] - self.putx([2, ['UNHANDLED DATA: %s' % payload, - 'UNHANDLED', '???', '?']]) - self.cmd, self.state = [], 'IDLE' - self.hard_clear_status_byte() - - def handle_state(self, state, newbyte): - # 'newbyte' can either be: - # 1. Value between 0x00-0xff, deal with the byte normally. - # 2. Value of 'None' which means "flush any buffered data". - if state == 'HANDLE CHANNEL MSG': - self.handle_channel_msg(newbyte) - elif state == 'HANDLE SYSEX MSG': - self.handle_sysex_msg(newbyte) - elif state == 'HANDLE SYSCOMMON MSG': - self.handle_syscommon_msg(newbyte) - elif state == 'HANDLE SYSREALTIME MSG': - self.handle_sysrealtime_msg(newbyte) - elif state == 'BUFFER GARBAGE MSG': - self.handle_garbage_msg(newbyte) - - def get_next_state(self, newbyte): - # 'newbyte' must be a valid byte between 0x00 and 0xff. - # - # Try to determine the state based off of the 'newbyte' parameter. - if newbyte in range(0x80, 0xef + 1): - return 'HANDLE CHANNEL MSG' - if newbyte == 0xf0: - return 'HANDLE SYSEX MSG' - if newbyte in range(0xf1, 0xf7): - return'HANDLE SYSCOMMON MSG' - if newbyte in range(0xf8, 0xff + 1): - return 'HANDLE SYSREALTIME MSG' - # Passing 0xf7 is an error; messages don't start with 0xf7. - if newbyte == 0xf7: - return 'BUFFER GARBAGE MSG' - # Next, base the state off of self.status_byte. - if self.status_byte < 0x80: - return 'BUFFER GARBAGE MSG' - return self.get_next_state(self.status_byte) - - def decode(self, ss, es, data): - ptype, rxtx, pdata = data - state = 'IDLE' - - # For now, ignore all UART packets except the actual data packets. - if ptype != 'DATA': - return - - # We're only interested in the byte value (not individual bits). - pdata = pdata[0] - - # Short MIDI overview: - # - Status bytes are 0x80-0xff, data bytes are 0x00-0x7f. - # - Most messages: 1 status byte, 1-2 data bytes. - # - Real-time system messages: always 1 byte. - # - SysEx messages: 1 status byte, n data bytes, EOX byte. - # - # Aspects of the MIDI protocol that complicate decoding: - # - MIDI System Realtime messages can briefly interrupt other - # messages already in progress. - # - "Running Status" allows for omitting the status byte in most - # scenarios if sequential messages have the same status byte. - # - System Exclusive (SysEx) messages can be terminated by ANY - # status byte (not limited to EOX byte). - - # State machine. - if pdata >= 0x80 and pdata != 0xf7: - state = self.get_next_state(pdata) - if state != 'HANDLE SYSREALTIME MSG' and self.state != 'IDLE': - # Flush the previous data since a new message is starting. - self.handle_state(self.state, None) - # Cache ss and es -after- flushing previous data. - self.ss, self.es = ss, es - # This is a status byte, remember the start sample. - if state != 'HANDLE SYSREALTIME MSG': - self.ss_block = ss - elif self.state == 'IDLE' or self.state == 'BUFFER GARBAGE MSG': - # Deal with "running status" or that we're buffering garbage. - self.ss, self.es = ss, es - if self.state == 'IDLE': - self.ss_block = ss - state = self.get_next_state(pdata) - else: - self.ss, self.es = ss, es - state = self.state - - # Yes, this is intentionally _not_ an 'elif' here. - if state != 'HANDLE SYSREALTIME MSG': - self.state = state - if state == 'BUFFER GARBAGE MSG': - self.status_byte = 0 - self.handle_state(state, pdata) diff --git a/decoders/miller/__init__.py b/decoders/miller/__init__.py deleted file mode 100755 index ce0d4941..00000000 --- a/decoders/miller/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2017 Christoph Rackwitz -## -## 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, see . -## - -''' -The Miller protocol decoder supports (modified) Miller encoded data. - -E.g. used in NFC communication at 106 kbaud. -''' - -from .pd import Decoder diff --git a/decoders/miller/pd.py b/decoders/miller/pd.py deleted file mode 100755 index f41711f1..00000000 --- a/decoders/miller/pd.py +++ /dev/null @@ -1,190 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2017 Christoph Rackwitz -## -## 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, see . -## - -# http://www.gorferay.com/type-a-communications-interface/ -# https://resources.infosecinstitute.com/introduction-rfid-security/ -# https://www.radio-electronics.com/info/wireless/nfc/near-field-communications-modulation-rf-signal-interface.php -# https://www.researchgate.net/figure/Modified-Miller-Code_fig16_283498836 - -# Miller: either edge -# modified Miller: falling edge - -import sigrokdecode as srd - -def roundto(x, k=1.0): - return round(x / k) * k - -class Decoder(srd.Decoder): - api_version = 3 - id = 'miller' - name = 'Miller' - longname = 'Miller encoding' - desc = 'Miller encoding protocol.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Encoding'] - channels = ( - {'id': 'data', 'name': 'Data', 'desc': 'Data signal'}, - ) - options = ( - {'id': 'baudrate', 'desc': 'Baud rate', 'default': 106000}, - {'id': 'edge', 'desc': 'Edge', 'default': 'falling', 'values': ('rising', 'falling', 'either')}, - ) - annotations = ( - ('bit', 'Bit'), - ('bitstring', 'Bitstring'), - ) - annotation_rows = tuple((u, v, (i,)) for i, (u, v) in enumerate(annotations)) - binary = ( - ('raw', 'Raw binary'), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.out_binary = self.register(srd.OUTPUT_BINARY) - - def decode_bits(self): - timeunit = self.samplerate / self.options['baudrate'] - edgetype = self.options['edge'][0] - - self.wait({0: edgetype}) # first symbol, beginning of unit - prevedge = self.samplenum - - # start of message: '0' - prevbit = 0 - yield (0, prevedge, prevedge + timeunit) - expectedstart = self.samplenum + timeunit - - # end of message: '0' followed by one idle symbol - - while True: - self.wait([{0: edgetype}, {'skip': int(3 * timeunit)}]) - got_timeout = (self.matched & (0b1 << 1)) - sampledelta = (self.samplenum - prevedge) - prevedge = self.samplenum - timedelta = roundto(sampledelta / timeunit, 0.5) - - # a mark stands for a 1 bit - # a mark has an edge in the middle - - # a space stands for a 0 bit - # a space either has an edge at the beginning or no edge at all - # after a mark, a space is edge-less - # after a space, a space has an edge - - # we get 1.0, 1.5, 2.0 times between edges - - # end of transmission is always a space, either edged or edge-less - - if prevbit == 0: # space -> ??? - if timedelta == 1.0: # 1.0 units -> space - yield (0, self.samplenum, self.samplenum + timeunit) - prevbit = 0 - expectedstart = self.samplenum + timeunit - elif timedelta == 1.5: # 1.5 units -> mark - yield (1, expectedstart, self.samplenum + 0.5*timeunit) - prevbit = 1 - expectedstart = self.samplenum + timeunit*0.5 - elif timedelta >= 2.0: - # idle symbol (end of message) - yield None - else: - # assert timedelta >= 2.0 - yield (False, self.samplenum - sampledelta, self.samplenum) - break - else: # mark -> ??? - if timedelta <= 0.5: - yield (False, self.samplenum - sampledelta, self.samplenum) - break - if timedelta == 1.0: # 1.0 units -> mark again (1.5 from start) - yield (1, expectedstart, self.samplenum + 0.5*timeunit) - prevbit = 1 - expectedstart = self.samplenum + 0.5*timeunit - elif timedelta == 1.5: # 1.5 units -> space (no pulse) and space (pulse) - yield (0, expectedstart, self.samplenum) - yield (0, self.samplenum, self.samplenum + timeunit) - prevbit = 0 - expectedstart = self.samplenum + timeunit - elif timedelta == 2.0: # 2.0 units -> space (no pulse) and mark (pulse) - yield (0, expectedstart, expectedstart + timeunit) - yield (1, self.samplenum - 0.5*timeunit, self.samplenum + 0.5*timeunit) - prevbit = 1 - expectedstart = self.samplenum + timeunit*0.5 - else: # longer -> space and end of message - yield (0, expectedstart, expectedstart + timeunit) - yield None - break - - def decode_run(self): - numbits = 0 - bitvalue = 0 - bitstring = '' - stringstart = None - stringend = None - - for bit in self.decode_bits(): - if bit is None: - break - - (value, ss, es) = bit - - if value is False: - self.put(int(ss), int(es), self.out_ann, [1, ['ERROR']]) - else: - self.put(int(ss), int(es), self.out_ann, [0, ['{}'.format(value)]]) - - if value is False: - numbits = 0 - break - - if stringstart is None: - stringstart = ss - - stringend = es - - bitvalue |= value << numbits - numbits += 1 - - bitstring += '{}'.format(value) - if numbits % 4 == 0: - bitstring += ' ' - - if not numbits: - return - - self.put(int(stringstart), int(stringend), self.out_ann, [1, ['{}'.format(bitstring)]]) - - numbytes = numbits // 8 + (numbits % 8 > 0) - bytestring = bitvalue.to_bytes(numbytes, 'little') - self.put(int(stringstart), int(stringend), self.out_binary, [0, bytestring]) - - def decode(self): - while True: - self.decode_run() diff --git a/decoders/mipi_dsi/__init__.py b/decoders/mipi_dsi/__init__.py deleted file mode 100644 index 5935127a..00000000 --- a/decoders/mipi_dsi/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -''' - -''' - -from .pd import Decoder diff --git a/decoders/mipi_dsi/pd.py b/decoders/mipi_dsi/pd.py deleted file mode 100644 index a7e1f71d..00000000 --- a/decoders/mipi_dsi/pd.py +++ /dev/null @@ -1,218 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## Author: Shiqiu Nie (369614718@qq.com) -## Version: 0.2 -## Date: 2019-07-01 -## History: -## 1. 2019-07-01 Create decoder -## 2. 2017-01-17 V0.1,Decode EscMode,BTA,Data,Stop,Idle -## 3. 2019-07-01 V0.2,Support for V3 decoder -## -## Copyright (C) 2010-2016 Uwe Hermann -## Copyright (C) 2019 DreamSourceLab -## -## 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, see . -## - -# TODO: - -import sigrokdecode as srd - -''' -OUTPUT_PYTHON format: - -Packet: -[, ] - -: - - - is the data or address byte associated with the 'ADDRESS*' and 'DATA*' -command. -''' - -# CMD: [annotation-type-index, long annotation, short annotation] -proto = { - 'ESC Mode': [0, 'Escape mode entry', 'ESC'], - 'BTA': [1, 'Bi-directional Data Lane Turnaround','BTA'], - 'DATA': [2, 'Data', 'Data'], - 'STOP': [3, 'Stop', 'S'], - 'LPDT': [4, 'LPDT Command', 'LPDT'], - 'DI': [5, 'Data Identifier', 'DI'], - 'ECC': [6, 'Error Correction Code', 'ECC'], - 'WC': [7, 'Word count', 'WC'], - 'CRC': [8, 'CheckSUM', 'CRC'], - 'ULPS': [9, 'Ultra-Low Power State', 'ULPS'], - 'IDLE': [10,'Idle', 'Idle'], -} -# LP state -lp_state = ['LP-00','LP-01','LP-10','LP-11'] - -class Decoder(srd.Decoder): - api_version = 3 - id = 'MIPI_DSI' - name = 'MIPI_DSI' - longname = 'MIPI Display Serial Interface' - desc = 'MIPI Display Serial Interface low power communication' - license = 'gplv2+' - inputs = ['logic'] - outputs = ['mipi_dsi'] - tags = ['Embedded/industrial'] - channels = ( - {'id': 'D0N', 'type': 8, 'name': 'D0N', 'desc': 'LP data 0 neg'}, - {'id': 'D0P', 'type': 108, 'name': 'D0P', 'desc': 'LP data 0 pos'}, - ) - options = ( - - ) - annotations = ( - ('111', 'LP-00', 'LP-00'), - ('110', 'LP-01', 'LP-01'), - ('109', 'LP-10', 'LP-10'), - ('108', 'LP-11', 'LP-11'), - ('7', 'EscapeMode', 'Escape mode'), - ('6', 'BTA', 'Bi-directional Data Lane Turnaround'), - ('112', 'LPDT', 'LPDT'), - ('0', 'DI', 'Data identifier'), - ('12', 'ECC', 'ECC'), - ('11', 'WC', 'Word count'), - ('107', 'CRC', 'CheckSUM'), - ('5', 'Stop', 'Stop condition'), - ('1', 'Idle', 'Idle'), - ) - annotation_rows = ( - ('LPData', 'LPData', (0, 1, 2, 3,)), - ('LP', 'LP', (4, 5, 6, 7, 8, 9, 10)), - ) - binary = ( - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.ss = self.es = self.ss_byte = -1 - self.bitcount = 0 - self.databyte = 0 - self.is_esc_bta = 0 # 0=ESC Mode 1=BTA Mode - self.state = 'FIND START' - self.pdu_start = None - self.pdu_bits = 0 - self.bits = [] - self.findmode_state = 'Find Mode state0' - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def start(self): - self.out_python = self.register(srd.OUTPUT_PYTHON) - self.out_ann = self.register(srd.OUTPUT_ANN) - self.out_binary = self.register(srd.OUTPUT_BINARY) - self.out_bitrate = self.register(srd.OUTPUT_META, - meta=(int, 'Bitrate', 'Bitrate from Start bit to Stop bit')) - - def putx(self, data): - self.put(self.ss, self.es, self.out_ann, data) - - def putp(self, data): - self.put(self.ss, self.es, self.out_python, data) - - def putb(self, data): - self.put(self.ss, self.es, self.out_binary, data) - - def handle_start(self): - self.ss, self.es = self.samplenum, self.samplenum - self.pdu_start = self.samplenum - self.pdu_bits = 0 - self.state = 'FIND MODE' - self.bitcount = self.databyte = 0 - self.findmode_state = 'Find Mode state0' - self.bits = [] - - def handle_esc_bta(self, d0n, d0p): - self.es = self.samplenum - cmd = 'ESC Mode' if(d0n == 1) else 'BTA' - self.putp([cmd, None]) - self.putx([proto[cmd][0], proto[cmd][1:]]) - self.bitcount = self.databyte = 0 - self.bits = [] - self.state = 'FIND DATA' - self.ss = self.samplenum - - def handle_stop(self): - cmd = 'STOP' - self.es = self.samplenum - self.putp([cmd, None]) - self.putx([proto[cmd][0], proto[cmd][1:]]) - self.state = 'FIND START' - self.is_esc_bta = 0 - self.bits = [] - - def handle_data(self, d0n, d0p): - self.pdu_bits += 1 - - self.databyte >>= 1 - if d0p: - self.databyte |= 0x80 - - if self.bitcount == 0: - self.ss_byte = self.samplenum - - if self.bitcount < 7: - self.bitcount += 1 - return - - d = self.databyte - - self.es = self.samplenum - h = '0x%02X' % d - cmd = 'DATA' - self.putb([cmd, None]) - self.putx([proto[cmd][0], [h]]) - - self.bitcount = self.databyte = 0 - self.bits = [] - self.state = 'FIND DATA' - self.ss = self.samplenum - - def decode(self): - while True: - # State machine. - if self.state == 'FIND START': - # Wait for a START condition (S): D0P = high, D0N = falling. - self.wait({0: 'f', 1: 'h'}) - self.handle_start() - elif self.state == 'FIND MODE': - if self.findmode_state == 'Find Mode state0': - self.wait({0: 'l', 1: 'l'}) - self.findmode_state = 'Find Mode state1' - elif self.findmode_state == 'Find Mode state1': - (d0n, d0p) = self.wait([{0: 'h', 1: 'l'}, {0: 'l', 1: 'h'}]) - self.findmode_state = 'Find Mode state2' - elif self.findmode_state == 'Find Mode state2': - self.wait({0: 'l', 1: 'l'}) - self.handle_esc_bta(d0n, d0p) - #self.findmode_state = 'Find Mode state0' - elif self.state == 'FIND DATA': - (d0n, d0p) = self.wait([{0: 'h', 1: 'l'}, {0: 'l', 1: 'h'}]) - self.wait([{0: 'l', 1: 'l'}, {0: 'h', 1: 'h'}]) - - if (self.matched & (0b1 << 0)): - self.handle_data(d0n, d0p) - else : - self.handle_stop() - - diff --git a/decoders/mipi_rffe/__init__.py b/decoders/mipi_rffe/__init__.py deleted file mode 100644 index c63ab855..00000000 --- a/decoders/mipi_rffe/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -''' -RFFE(RF Front-End Control Interface)is a bidirectional, single-master -bus using two signals (SCLK = serial clock line, SDATA = serial data line). -''' - -from .pd import Decoder diff --git a/decoders/mipi_rffe/pd.py b/decoders/mipi_rffe/pd.py deleted file mode 100644 index a8673d03..00000000 --- a/decoders/mipi_rffe/pd.py +++ /dev/null @@ -1,510 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2010-2016 Uwe Hermann -## Copyright (C) 2020 DreamSourceLab -## -## 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, see . -## - -# TODO: Look into arbitration, collision detection, clock synchronisation, etc. -# TODO: Implement support for inverting SDATA/SCLK levels (0->1 and 1->0). -# TODO: Implement support for detecting various bus errors. - -import sigrokdecode as srd - -''' -OUTPUT_PYTHON format: - -Packet: -[SSC,, ] - -SSC:Sequence Start Condition - -: - - 'SA' (Slave Address) - - 'COMMAND' (command Key) - - 'BC' (Byte Count) - - 'P' (Parity) - - 'ADDRESS' (Register Address) - - 'DATA WRITE0' (Register 0 Write Data) -: - - 'ADDRESS' (Register Address) - - 'P' (Parity) - - 'BP' (Bus Park) - - 'DATA READ' (Data, read) - - 'DATA WRITE' (Data, write) - - : A Command Frame shall consist of a 4-bit Slave address field, an 8-bit command payload field, and a single parity bit. - - : A Data or Address Frame shall consist of eight data bits or eight address bits, respectively, and a single parity bit. -''' -# cmd: [annotation-type-index, long annotation, short annotation] -proto = { - 'SSC': [0, 'Sequence Start Condition', 'SSC'], - 'SA': [1, 'Slave Address', 'SA'], - 'ERW': [2, 'Extended Register Write', 'ERW'], - 'ERR': [3, 'Extended Register Read', 'ERR'], - 'ERWL': [4, 'Extended Register Write Long', 'ERWL'], - 'ERRL': [5, 'Extended Register Read Long', 'ERRL'], - 'RW': [6, 'Register Write', 'RW'], - 'RR': [7, 'Register Read', 'RR'], - 'R0W': [8, 'Register 0 Write', 'R0W'], - 'BC': [9, 'Byte', 'BC'], - 'P': [10, 'Parity', 'P'], - 'ADDRESS': [11, 'Address', 'A'], - 'BP': [12, 'Bus Pack', 'BP'], - 'DATA': [13, 'Data ', 'DATA'], - 'CMD_WARNINGS': [14, 'Command Warnings', 'CMD_WARN'], - 'BIC': [15, 'Bus Idle Condition ', 'BIC'], - 'BC_WARNINGS': [16, 'BC Warnings', 'BC_WARN'], - 'IJE': [17, 'Illegal Jump Edge', 'IJE_WAEN'], - 'PW': [18, 'Parity warnings', 'P_WAEN'], -} - -class Decoder(srd.Decoder): - api_version = 3 - id = 'mipi_rffe' - name = 'MIPI_RFFE' - longname = 'RF Front-End Control Interface' - desc = 'Two-wire, single-master, serial bus.' - license = 'gplv2+' - inputs = ['logic'] - outputs = ['mipi_rffe'] - tags = ['Embedded/industrial'] - channels = ( - {'id': 'sclk', 'type': 8, 'name': 'SCLK', 'desc': 'Serial clock line'}, - {'id': 'sdata', 'type': 108, 'name': 'SDATA', 'desc': 'Serial data line'}, - ) - options = ( - {'id': 'error_display', 'desc': 'Error display options', - 'default': 'display', 'values': ('display', 'not_display')}, - ) - annotations = ( - ('7', 'ssc', 'Sequence Start Condition'), - ('6', 'sa', 'Slave Address'), - ('1', 'erw', 'Extended register write'), - ('5', 'err', 'Extended register read'), - ('0', 'erwl', 'Extended register write long'), - ('112', 'errl', 'Extended register read long'), - ('111', 'rw', 'Register write'), - ('110', 'rr', 'Register read'), - ('109', 'r0w', 'Register 0 write'), - ('108', 'bc', 'Byte'), - ('7', 'p', 'Parity'), - ('75', 'address', 'Address'), - ('70', 'bp', 'Bus pack'), - ('65', 'data', 'DATA'), - ('1000', 'Command warnings', 'Command warnings'), - ('50', 'Bus Idle Condition ', 'Bus Idle Condition '), - ('1000', 'BC warnings', 'BC warnings'), - ('1000', 'Illegal Jump Edge', 'IJE_WAEN'), - ('1000', 'Parity warnings', 'Parity warnings'), - ) - annotation_rows = ( - ('command-data', 'Command/Data', (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 , 11, 12, 13 ,15)), - ('warnings', 'Warnings', (14,16,17,18,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.ss = self.es = -1 - self.bitcount = 0 - self.databyte = 0 - self.state = 'FIND SSC' - self.extended = -1 - self.cmdkey = 'NULL' - self.BC = 0 - self.bits = 0 - self.Pcount = 0 - self.BPcount = 0 - self.ADDcount = 0 - self.BPss = 0 - self.SSCs = 0 - self.Pes = 0 - self.sdata = -1 - self.Pdata = -1 - self.parity = False - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self._display = 1 if self.options['error_display'] == 'display' else 0 - - def putx(self, data): - self.put(self.ss, self.es, self.out_ann, data) - - def Parity(self): - self.parity = True - if self.Pcount == 1 : - if self.cmdkey == 'ERW' : - self.Pdata = self.Pdata + (0*(2**(self.Pkey+1))) - if self.cmdkey == 'ERR' : - self.Pdata = self.Pdata + (2*(2**(self.Pkey+1))) - if self.cmdkey == 'ERWL' : - self.Pdata = self.Pdata + (6*(2**(self.Pkey+1))) - if self.cmdkey == 'ERRL' : - self.Pdata = self.Pdata + (7*(2**(self.Pkey+1))) - if self.cmdkey == 'RW' : - self.Pdata = self.Pdata + (2*(2**(self.Pkey+1))) - if self.cmdkey == 'RR' : - self.Pdata = self.Pdata + (3*(2**(self.Pkey+1))) - if self.cmdkey == 'R0W' : - self.Pdata = self.Pdata + (1*(2**(self.Pkey+1))) - while self.Pdata : - self.parity = not self.parity - self.Pdata = self.Pdata & (self.Pdata - 1) - self.Pdata = self.Pkey = 0 - - - def handle_BP(self,cmd,state): - - self.ss = self.Pes - self.es = self.samplenum - self.putx([proto[cmd][0], proto[cmd][1:]]) - self.state = state - - def handle(self,cmd,state,key,key0): - key1 = key - if key > 7 : - key = 7 - if self.bitcount == 0: - self.DATAss = self.samplenum - - if self.bitcount < key: - while True : - if self._display : - (sclk, sdata) = self.wait([{0: 'f'},{0: 'l', 1: 'e'}]) - if (self.matched & (0b1 << 0)): - self.databyte <<= 1 - self.databyte |= sdata - break - if (self.matched & (0b1 << 1)): - self.ss = self.samplenum - (sclk, sdata) = self.wait([{0: 'f'},{0: 'l', 1: 'e'}]) - if (self.matched & (0b1 << 0)): - self.es = self.samplenum - self.putx([proto['IJE'][0], proto['IJE'][1:]]) - self.databyte <<= 1 - self.databyte |= sdata - break - if (self.matched & (0b1 << 1)): - self.es = self.samplenum - self.putx([proto['IJE'][0], proto['IJE'][1:]]) - else : - (sclk, sdata) = self.wait({0: 'f'}) - self.databyte <<= 1 - self.databyte |= sdata - break - - self.bitcount += 1 - return - - while True : - if self._display : - (sclk, sdata) = self.wait([{0: 'f'},{0: 'l', 1: 'e'}]) - if (self.matched & (0b1 << 0)): - self.databyte <<= 1 - self.databyte |= sdata - break - if (self.matched & (0b1 << 1)): - self.ss = self.samplenum - (sclk, sdata) = self.wait([{0: 'f'},{0: 'l', 1: 'e'}]) - if (self.matched & (0b1 << 0)): - self.es = self.samplenum - self.putx([proto['IJE'][0], proto['IJE'][1:]]) - self.databyte <<= 1 - self.databyte |= sdata - break - if (self.matched & (0b1 << 1)): - self.es = self.samplenum - self.putx([proto['IJE'][0], proto['IJE'][1:]]) - else : - (sclk, sdata) = self.wait({0: 'f'}) - self.databyte <<= 1 - self.databyte |= sdata - break - self.wait({0 : 'r'}) - d = self.databyte - self.ss = self.DATAss - self.es = self.samplenum - if cmd != 'P': - self.Pdata = d - self.Pkey = key - if cmd == 'BC': - self.BC = d - if self.cmdkey == 'ERW' or self.cmdkey == 'ERR' : - if self.BC < 4 or self.BC > 16 : - self.putx([proto['BC_WARNINGS'][0], proto['BC_WARNINGS'][1:]]) - self.init() - return - else : - if self.BC < 1 or self.BC > 8 : - self.putx([proto['BC_WARNINGS'][0], proto['BC_WARNINGS'][1:]]) - self.init() - return - if cmd == 'P': - self.Pes = self.samplenum - if self._display : - self.Parity() - if self.parity != d : - self.putx([proto['PW'][0], proto['PW'][1:]]) - self.putx([proto[cmd][0], ['%s: %d' % (proto[cmd][1],d), - '%s: %d' % (proto[cmd][2],d), '%d' % d]]) - self.bitcount = self.databyte = 0 - self.state = state - return - self.putx([proto[cmd][0], ['%s[%d:%d]: %02X' % (proto[cmd][1],key1,key0,d), - '%s[%d:%d]: %02X' % (proto[cmd][2],key1,key0,d), '%02X' % d]]) - self.bitcount = self.databyte = 0 - if cmd == 'DATA': - self.bits -= 8 - self.state = state - - - - - def handle_CMD(self): - if self.bitcount == 0: - self.DATAss = self.samplenum - (sclk, sdata) = self.wait({0: 'f'}) - if sdata : - self.wait({0 : 'r'}) - self.cmdset('R0W','FIND DATA') - return - - if self.bitcount == 1: - if self.sdata : - self.extended = 0 - else : - self.extended = 1 - - if self.bitcount == 2: - if not self.extended : - if self.sdata : - self.cmdset('RR','FIND ADDRESS') - return - else : - self.cmdset('RW','FIND ADDRESS') - return - - if self.bitcount == 3: - if not self.sdata : - if self.extended : - self.cmdset('ERR','FIND BTEY_COUNT') - return - else : - self.cmdset('ERW','FIND BTEY_COUNT') - return - elif self.extended : - self.ss = self.DATAss - self.es = self.samplenum - self.putx([proto['CMD_WARNINGS'][0], proto['CMD_WARNINGS'][1:]]) - self.init() - return - - if self.bitcount == 4: - if self.sdata : - self.cmdset('ERRL','FIND BTEY_COUNT') - return - else : - self.cmdset('ERWL','FIND BTEY_COUNT') - return - - if self.bitcount <4: - while True : - if self._display : - (sclk,self.sdata) = self.wait([{0: 'f'},{0: 'l', 1: 'e'}]) - if (self.matched & (0b1 << 0)): - break - if (self.matched & (0b1 << 1)): - self.ss = self.samplenum - (sclk,self.sdata) = self.wait([{0: 'f'},{0: 'l', 1: 'e'}]) - if (self.matched & (0b1 << 0)): - self.es = self.samplenum - self.putx([proto['IJE'][0], proto['IJE'][1:]]) - break - if (self.matched & (0b1 << 1)): - self.es = self.samplenum - self.putx([proto['IJE'][0], proto['IJE'][1:]]) - else : - (sclk,self.sdata) = self.wait({0: 'f'}) - break - self.wait({0 : 'r'}) - self.bitcount += 1 - - def cmdset(self,cmd,state): - self.ss = self.DATAss - self.es = self.samplenum - self.putx([proto[cmd][0], proto[cmd][1:]]) - self.state = state - self.bitcount = 0 - self.extended = -1 - self.cmdkey = cmd - - def initBP(self,sclk,sdata,state,key): - self.handle_BP('BP',state) - self.state = state - if key : - self.init() - - def init(self): - self.cmdkey = 'NULL' - self.ADDcount = 0 - self.Pcount = 0 - self.BPcount = 0 - self.BC = 0 - self.bitcount = 0 - self.Pes = 0 - self.state = 'FIND SSC' - - - - - def decode(self): - while True: - if self.state == 'FIND SSC': - self.wait({0: 'l', 1: 'r'}) - self.BPss = self.samplenum - self.wait([{0: 'h'},{0: 'l', 1: 'f'}]) - if (self.matched & (0b1 << 0)): - continue - if (self.matched & (0b1 << 1)): - self.wait([{0: 'l', 1: 'e'},{0: 'r'}]) - if (self.matched & (0b1 << 0)): - continue - if (self.matched & (0b1 << 1)): - self.ss,self.es = self.BPss,self.samplenum - self.putx([proto['SSC'][0], proto['SSC'][1:]]) - self.state = 'FIND SLAVE ADDRESS' - - elif self.state == 'FIND SLAVE ADDRESS': - self.handle('SA','FIND COMMAND',3,0) - - elif self.state == 'FIND COMMAND': - self.handle_CMD() - - elif self.state == 'FIND BTEY_COUNT': - if self.cmdkey == 'ERW' or self.cmdkey == 'ERR' : - self.handle('BC','FIND PARITY',3,0) - else : - self.handle('BC','FIND PARITY',2,0) - self.bits = self.BC*8 - - elif self.state == 'FIND ADDRESS': - if self.cmdkey == 'RW' or self.cmdkey == 'RR' : - self.handle('ADDRESS','FIND PARITY',4,0) - elif self.cmdkey == 'ERR' or self.cmdkey == 'ERW' : - self.handle('ADDRESS','FIND PARITY',7,0) - else : - if self.Pcount == 1 : - self.handle('ADDRESS','FIND PARITY',15,8) - else : - self.handle('ADDRESS','FIND PARITY',7,0) - - elif self.state == 'FIND DATA': - if self.cmdkey == 'R0W' : - self.handle('DATA','FIND PARITY',6,0) - elif self.cmdkey == 'RW' or self.cmdkey == 'RR' : - self.handle('DATA','FIND PARITY',7,0) - else : - self.handle('DATA','FIND PARITY',self.bits-1,self.bits-8) - - elif self.state == 'FIND PARITY': - self.Pcount += 1 - self.handle('P','NULL',0,0) - if self.cmdkey == 'R0W' : - self.state = 'FIND BUS_PARK' - - elif self.cmdkey == 'ERW' : - if self.Pcount == 1 : - self.ADDcount,self.state = 1,'FIND ADDRESS' - elif self.Pcount == 2 : - self.state = 'FIND DATA' - elif self.Pcount == self.BC + 2 : - self.state = 'FIND BUS_PARK' - continue - elif self.Pcount > 2 : - self.state = 'FIND DATA' - - elif self.cmdkey == 'ERR' : - if self.Pcount == 1 : - self.ADDcount,self.state = 1,'FIND ADDRESS' - elif self.Pcount == 2 : - self.BPcount,self.state = 1,'FIND BUS_PARK' - elif self.Pcount == self.BC + 2 : - self.BPcount =2 - self.state = 'FIND BUS_PARK' - continue - elif self.Pcount > 2 : - self.state = 'FIND DATA' - - elif self.cmdkey == 'ERWL' : - if self.Pcount == 1 : - self.ADDcount,self.state = 2,'FIND ADDRESS' - elif self.Pcount == 2 : - self.ADDcount,self.state = 1,'FIND ADDRESS' - elif self.Pcount == 3 : - self.state = 'FIND DATA' - elif self.Pcount == self.BC + 3 : - self.state = 'FIND BUS_PARK' - continue - elif self.Pcount > 3 : - self.state = 'FIND DATA' - - elif self.cmdkey == 'ERRL' : - if self.Pcount == 1 : - self.ADDcount,self.state = 2,'FIND ADDRESS' - elif self.Pcount == 2 : - self.ADDcount,self.state = 1,'FIND ADDRESS' - elif self.Pcount == 3 : - self.BPcount,self.state = 1,'FIND BUS_PARK' - elif self.Pcount == self.BC + 3 : - self.BPcount =2 - self.state = 'FIND BUS_PARK' - continue - elif self.Pcount > 3 : - self.state = 'FIND DATA' - - elif self.cmdkey == 'RW' : - if self.Pcount == 1 : - self.state = 'FIND DATA' - elif self.Pcount == 2 : - self.BPcount,self.state = 1,'FIND BUS_PARK' - - elif self.cmdkey == 'RR' : - self.state = 'FIND BUS_PARK' - self.BPcount = 1 if (self.Pcount == 1) else 2 - - elif self.state == 'FIND BUS_PARK': - (sclk, sdata) = self.wait({0: 'l', 1: 'l'}) - self.ss = self.samplenum - if self.cmdkey == 'ERR' or self.cmdkey == 'ERRL' or self.cmdkey == 'RR': - key = 0 if (self.BPcount == 1) else 1 - self.initBP(sclk,sdata,'FIND DATA',key) - else : - self.initBP(sclk,sdata,'FIND SSC',1) - - - - - - - \ No newline at end of file diff --git a/decoders/mlx90614/__init__.py b/decoders/mlx90614/__init__.py deleted file mode 100755 index 2e20c4d9..00000000 --- a/decoders/mlx90614/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -''' -This decoder stacks on top of the 'i2c' PD and decodes the Melexis MLX90614 -infrared thermometer protocol. -''' - -from .pd import Decoder diff --git a/decoders/mlx90614/pd.py b/decoders/mlx90614/pd.py deleted file mode 100755 index f0dbe22a..00000000 --- a/decoders/mlx90614/pd.py +++ /dev/null @@ -1,78 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -import sigrokdecode as srd - -class Decoder(srd.Decoder): - api_version = 3 - id = 'mlx90614' - name = 'MLX90614' - longname = 'Melexis MLX90614' - desc = 'Melexis MLX90614 infrared thermometer protocol.' - license = 'gplv2+' - inputs = ['i2c'] - outputs = [] - tags = ['IC', 'Sensor'] - annotations = ( - ('celsius', 'Temperature in degrees Celsius'), - ('kelvin', 'Temperature in Kelvin'), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.state = 'IGNORE START REPEAT' - self.data = [] - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putx(self, data): - self.put(self.ss, self.es, self.out_ann, data) - - # Quick hack implementation! This needs to be improved a lot! - def decode(self, ss, es, data): - cmd, databyte = data - - # State machine. - if self.state == 'IGNORE START REPEAT': - if cmd != 'START REPEAT': - return - self.state = 'IGNORE ADDRESS WRITE' - elif self.state == 'IGNORE ADDRESS WRITE': - if cmd != 'ADDRESS WRITE': - return - self.state = 'GET TEMPERATURE' - elif self.state == 'GET TEMPERATURE': - if cmd != 'DATA WRITE': - return - if len(self.data) == 0: - self.data.append(databyte) - self.ss = ss - elif len(self.data) == 1: - self.data.append(databyte) - self.es = es - else: - kelvin = (self.data[0] | (self.data[1] << 8)) * 0.02 - celsius = kelvin - 273.15 - self.putx([0, ['Temperature: %3.2f °C' % celsius]]) - self.putx([1, ['Temperature: %3.2f K' % kelvin]]) - self.state = 'IGNORE START REPEAT' - self.data = [] diff --git a/decoders/modbus/__init__.py b/decoders/modbus/__init__.py deleted file mode 100755 index b60eea15..00000000 --- a/decoders/modbus/__init__.py +++ /dev/null @@ -1,28 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Bart de Waal -## -## 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, see . -## - -''' -This decoder stacks on top of the 'uart' PD and decodes Modbus RTU, -a protocol with a single a client and one or more servers. - -The RX channel will be checked for both client->server and server->client -communication, the TX channel only for client->server. -''' - -from .pd import Decoder diff --git a/decoders/modbus/pd.py b/decoders/modbus/pd.py deleted file mode 100755 index 487acf1f..00000000 --- a/decoders/modbus/pd.py +++ /dev/null @@ -1,934 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Bart de Waal -## Copyright (C) 2019 DreamSourceLab -## -## 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 . -## - -import sigrokdecode as srd -from math import ceil - -RX = 0 -TX = 1 - -class No_more_data(Exception): - '''This exception is a signal that we should stop parsing an ADU as there - is no more data to parse.''' - pass - -class Data: - '''The Data class is used to hold the bytes from the serial decode.''' - def __init__(self, start, end, data): - self.start = start - self.end = end - self.data = data - -class Modbus_ADU: - '''An Application Data Unit is what Modbus calls one message. - Protocol decoders are supposed to keep track of state and then provide - decoded data to the backend as it reads it. In Modbus' case, the state is - the ADU up to that point. This class represents the state and writes the - messages to the backend. - This class is for the common infrastructure between CS and SC. It should - not be used directly, only inhereted from.''' - - def __init__(self, parent, start, write_channel, annotation_prefix): - self.data = [] # List of all the data received up to now - self.parent = parent # Reference to the decoder object - self.start = start - self.last_read = start # The last moment parsed by this ADU object - self.write_channel = write_channel - self.last_byte_put = -1 - self.annotation_prefix = annotation_prefix - # Any Modbus message needs to be at least 4 bytes long. The Modbus - # function may make this longer. - self.minimum_length = 4 - - # This variable is used by an external function to determine when the - # next frame should be started. - self.startNewFrame = False - - # If there is an error in a frame, we'd like to highlight it. Keep - # track of errors. - self.hasError = False - - def add_data(self, start, end, data): - '''Let the frame handle another piece of data. - start: start of this data - end: end of this data - data: data as received from the UART decoder''' - ptype, rxtx, pdata = data - self.last_read = end - if ptype == 'DATA': - self.data.append(Data(start, end, pdata[0])) - self.parse() # parse() is defined in the specific type of ADU. - - def puti(self, byte_to_put, annotation, message): - '''This class keeps track of how much of the data has already been - annotated. This function tells the parent class to write message, but - only if it hasn't written about this bit before. - byte_to_put: Only write if it hasn't yet written byte_to_put. It will - write from the start of self.last_byte_put+1 to the end - of byte_to_put. - annotation: Annotation to write to, without annotation_prefix. - message: Message to write.''' - if byte_to_put > len(self.data) - 1: - # If the byte_to_put hasn't been read yet. - raise No_more_data - - if annotation == 'error': - self.hasError = True - - if byte_to_put > self.last_byte_put: - self.parent.puta( - self.data[self.last_byte_put + 1].start, - self.data[byte_to_put].end, - self.annotation_prefix + annotation, - message) - self.last_byte_put = byte_to_put - raise No_more_data - - def putl(self, annotation, message, maximum=None): - '''Puts the last byte on the stack with message. The contents of the - last byte will be applied to message using format.''' - last_byte_address = len(self.data) - 1 - if maximum is not None and last_byte_address > maximum: - return - self.puti(last_byte_address, annotation, - message.format(self.data[-1].data)) - - def close(self, message_overflow): - '''Function to be called when next message is started. As there is - always space between one message and the next, we can use that space - for errors at the end.''' - # TODO: Figure out how to make this happen for last message. - data = self.data - if len(data) < self.minimum_length: - if len(data) == 0: - # Sometimes happens with noise, safe to ignore. - return - self.parent.puta( - data[self.last_byte_put].end, message_overflow, - self.annotation_prefix + 'error', - 'Message too short or not finished') - self.hasError = True - if self.hasError and self.parent.options['channel'] == 'RX': - # If we are on RX mode (so client->server and server->client - # messages can be seperated) we like to mark blocks containing - # errors. We don't do this in TX mode, because then we interpret - # each frame as both a client->server and server->client frame, and - # one of those is bound to contain an error, making highlighting - # frames useless. - self.parent.puta(data[0].start, data[-1].end, - 'error-indication', 'Frame contains error') - if len(data) > 256: - try: - self.puti(len(data) - 1, self.annotation_prefix + 'error', - 'Modbus data frames are limited to 256 bytes') - except No_more_data: - pass - - def check_crc(self, byte_to_put): - '''Check the CRC code, data[byte_to_put] is the 2nd byte of the CRC.''' - crc_byte1, crc_byte2 = self.calc_crc(byte_to_put) - data = self.data - if data[-2].data == crc_byte1 and data[-1].data == crc_byte2: - self.puti(byte_to_put, 'crc', 'CRC correct') - else: - self.puti(byte_to_put, 'error', - 'CRC should be {} {}'.format(crc_byte1, crc_byte2)) - - def half_word(self, start): - '''Return the half word (16 bit) value starting at start bytes in. If - it goes out of range it raises the usual errors.''' - if (start + 1) > (len(self.data) - 1): - # If there isn't enough length to access data[start + 1]. - raise No_more_data - return self.data[start].data * 0x100 + self.data[start + 1].data - - def calc_crc(self, last_byte): - '''Calculate the CRC, as described in the spec. - The last byte of the CRC should be data[last_byte].''' - if last_byte < 3: - # Every Modbus ADU should be as least 4 long, so we should never - # have to calculate a CRC on something shorter. - raise Exception('Could not calculate CRC: message too short') - - result = 0xFFFF - magic_number = 0xA001 # As defined in the modbus specification. - for byte in self.data[:last_byte - 1]: - result = result ^ byte.data - for i in range(8): - LSB = result & 1 - result = result >> 1 - if (LSB): # If the LSB is true. - result = result ^ magic_number - byte1 = result & 0xFF - byte2 = (result & 0xFF00) >> 8 - return (byte1, byte2) - - def parse_write_single_coil(self): - '''Parse function 5, write single coil.''' - self.minimum_length = 8 - - self.puti(1, 'function', 'Function 5: Write Single Coil') - - address = self.half_word(2) - self.puti(3, 'address', - 'Address 0x{:X} / {:d}'.format(address, address + 10000)) - - raw_value = self.half_word(4) - value = 'Invalid Coil Value' - if raw_value == 0x0000: - value = 'Coil Value OFF' - elif raw_value == 0xFF00: - value = 'Coil Value ON' - self.puti(5, 'data', value) - - self.check_crc(7) - - def parse_write_single_register(self): - '''Parse function 6, write single register.''' - self.minimum_length = 8 - - self.puti(1, 'function', 'Function 6: Write Single Register') - - address = self.half_word(2) - self.puti(3, 'address', - 'Address 0x{:X} / {:d}'.format(address, address + 30000)) - - value = self.half_word(4) - value_formatted = 'Register Value 0x{0:X} / {0:d}'.format(value) - self.puti(5, 'data', value_formatted) - - self.check_crc(7) - - def parse_diagnostics(self): - '''Parse function 8, diagnostics. This function has many subfunctions, - but they are all more or less the same.''' - self.minimum_length = 8 - - self.puti(1, 'function', 'Function 8: Diagnostics') - - diag_subfunction = { - 0: 'Return Query data', - 1: 'Restart Communications Option', - 2: 'Return Diagnostics Register', - 3: 'Change ASCII Input Delimiter', - 4: 'Force Listen Only Mode', - 10: 'Clear Counters and Diagnostic Register', - 11: 'Return Bus Message Count', - 12: 'Return Bus Communication Error Count', - 13: 'Return Bus Exception Error Count', - 14: 'Return Slave Message Count', - 15: 'Return Slave No Response Count', - 16: 'Return Slave NAK Count', - 17: 'Return Slave Busy Count', - 18: 'Return Bus Character Overrun Count', - 20: 'Return Overrun Counter and Flag', - } - subfunction = self.half_word(2) - subfunction_name = diag_subfunction.get(subfunction, - 'Reserved subfunction') - self.puti(3, 'data', - 'Subfunction {}: {}'.format(subfunction, subfunction_name)) - - diagnostic_data = self.half_word(4) - self.puti(5, 'data', - 'Data Field: {0} / 0x{0:04X}'.format(diagnostic_data)) - - self.check_crc(7) - - def parse_mask_write_register(self): - '''Parse function 22, Mask Write Register.''' - self.minimum_length = 10 - data = self.data - - self.puti(1, 'function', 'Function 22: Mask Write Register') - - address = self.half_word(2) - self.puti(3, 'address', - 'Address 0x{:X} / {:d}'.format(address, address + 30001)) - - self.half_word(4) # To make sure we don't oveflow data. - and_mask_1 = data[4].data - and_mask_2 = data[5].data - self.puti(5, 'data', - 'AND mask: {:08b} {:08b}'.format(and_mask_1, and_mask_2)) - - self.half_word(6) # To make sure we don't oveflow data. - or_mask_1 = data[6].data - or_mask_2 = data[7].data - self.puti(7, 'data', - 'OR mask: {:08b} {:08b}'.format(or_mask_1, or_mask_2)) - - self.check_crc(9) - - def parse_not_implemented(self): - '''Explicitly mark certain functions as legal functions, but not - implemented in this parser. This is due to the author not being able to - find anything (hardware or software) that supports these functions.''' - # TODO: Implement these functions. - - # Mentioning what function it is is no problem. - function = self.data[1].data - functionname = { - 20: 'Read File Record', - 21: 'Write File Record', - 24: 'Read FIFO Queue', - 43: 'Read Device Identification/Encapsulated Interface Transport', - }[function] - self.puti(1, 'function', - 'Function {}: {} (not supported)'.format(function, functionname)) - - # From there on out we can keep marking it unsupported. - self.putl('data', 'This function is not currently supported') - -class Modbus_ADU_SC(Modbus_ADU): - '''SC stands for Server -> Client.''' - def parse(self): - '''Select which specific Modbus function we should parse.''' - data = self.data - - # This try-catch is being used as flow control. - try: - server_id = data[0].data - if 1 <= server_id <= 247: - message = 'Slave ID: {}'.format(server_id) - else: - message = 'Slave ID {} is invalid' - self.puti(0, 'server-id', message) - - function = data[1].data - if function == 1 or function == 2: - self.parse_read_bits() - elif function == 3 or function == 4 or function == 23: - self.parse_read_registers() - elif function == 5: - self.parse_write_single_coil() - elif function == 6: - self.parse_write_single_register() - elif function == 7: - self.parse_read_exception_status() - elif function == 8: - self.parse_diagnostics() - elif function == 11: - self.parse_get_comm_event_counter() - elif function == 12: - self.parse_get_comm_event_log() - elif function == 15 or function == 16: - self.parse_write_multiple() - elif function == 17: - self.parse_report_server_id() - elif function == 22: - self.parse_mask_write_register() - elif function in {21, 21, 24, 43}: - self.parse_not_implemented() - elif function > 0x80: - self.parse_error() - else: - self.puti(1, 'error', - 'Unknown function: {}'.format(data[1].data)) - self.putl('error', 'Unknown function') - - # If the message gets here without raising an exception, the - # message goes on longer than it should. - self.putl('error', 'Message too long') - - except No_more_data: - # Just a message saying we don't need to parse anymore this round. - pass - - def parse_read_bits(self): - self.mimumum_length = 5 - - data = self.data - function = data[1].data - - if function == 1: - self.puti(1, 'function', 'Function 1: Read Coils') - else: - self.puti(1, 'function', 'Function 2: Read Discrete Inputs') - - bytecount = self.data[2].data - self.minimum_length = 5 + bytecount # 3 before data, 2 CRC. - self.puti(2, 'length', 'Byte count: {}'.format(bytecount)) - - # From here on out, we expect registers on 3 and 4, 5 and 6 etc. - # So registers never start when the length is even. - self.putl('data', '{:08b}', bytecount + 2) - self.check_crc(bytecount + 4) - - def parse_read_registers(self): - self.mimumum_length = 5 - - data = self.data - - function = data[1].data - if function == 3: - self.puti(1, 'function', 'Function 3: Read Holding Registers') - elif function == 4: - self.puti(1, 'function', 'Function 4: Read Input Registers') - elif function == 23: - self.puti(1, 'function', 'Function 23: Read/Write Multiple Registers') - - bytecount = self.data[2].data - self.minimum_length = 5 + bytecount # 3 before data, 2 CRC. - if bytecount % 2 == 0: - self.puti(2, 'length', 'Byte count: {}'.format(bytecount)) - else: - self.puti(2, 'error', - 'Error: Odd byte count ({})'.format(bytecount)) - - # From here on out, we expect registers on 3 and 4, 5 and 6 etc. - # So registers never start when the length is even. - if len(data) % 2 == 1: - register_value = self.half_word(-2) - self.putl('data', '0x{0:04X} / {0}'.format(register_value), - bytecount + 2) - else: - raise No_more_data - - self.check_crc(bytecount + 4) - - def parse_read_exception_status(self): - self.mimumum_length = 5 - - self.puti(1, 'function', 'Function 7: Read Exception Status') - exception_status = self.data[2].data - self.puti(2, 'data', - 'Exception status: {:08b}'.format(exception_status)) - self.check_crc(4) - - def parse_get_comm_event_counter(self): - self.mimumum_length = 8 - - self.puti(1, 'function', 'Function 11: Get Comm Event Counter') - - status = self.half_word(2) - if status == 0x0000: - self.puti(3, 'data', 'Status: not busy') - elif status == 0xFFFF: - self.puti(3, 'data', 'Status: busy') - else: - self.puti(3, 'error', 'Bad status: 0x{:04X}'.format(status)) - - count = self.half_word(4) - self.puti(5, 'data', 'Event Count: {}'.format(count)) - self.check_crc(7) - - def parse_get_comm_event_log(self): - self.mimumum_length = 11 - self.puti(1, 'function', 'Function 12: Get Comm Event Log') - - data = self.data - - bytecount = data[2].data - self.puti(2, 'length', 'Bytecount: {}'.format(bytecount)) - # The bytecount is the length of everything except the slaveID, - # function code, bytecount and CRC. - self.mimumum_length = 5 + bytecount - - status = self.half_word(3) - if status == 0x0000: - self.puti(4, 'data', 'Status: not busy') - elif status == 0xFFFF: - self.puti(4, 'data', 'Status: busy') - else: - self.puti(4, 'error', 'Bad status: 0x{:04X}'.format(status)) - - event_count = self.half_word(5) - self.puti(6, 'data', 'Event Count: {}'.format(event_count)) - - message_count = self.half_word(7) - self.puti(8, 'data', 'Message Count: {}'.format(message_count)) - - self.putl('data', 'Event: 0x{:02X}'.format(data[-1].data), - bytecount + 2) - - self.check_crc(bytecount + 4) - - def parse_write_multiple(self): - '''Function 15 and 16 are almost the same, so we can parse them both - using one function.''' - self.mimumum_length = 8 - - function = self.data[1].data - if function == 15: - data_unit = 'Coils' - max_outputs = 0x07B0 - long_address_offset = 10001 - elif function == 16: - data_unit = 'Registers' - max_outputs = 0x007B - long_address_offset = 30001 - - self.puti(1, 'function', - 'Function {}: Write Multiple {}'.format(function, data_unit)) - - starting_address = self.half_word(2) - # Some instruction manuals use a long form name for addresses, this is - # listed here for convienience. - address_name = long_address_offset + starting_address - self.puti(3, 'address', - 'Start at address 0x{:X} / {:d}'.format(starting_address, - address_name)) - - quantity_of_outputs = self.half_word(4) - if quantity_of_outputs <= max_outputs: - self.puti(5, 'data', - 'Write {} {}'.format(quantity_of_outputs, data_unit)) - else: - self.puti(5, 'error', - 'Bad value: {} {}. Max is {}'.format(quantity_of_outputs, - data_unit, max_outputs)) - - self.check_crc(7) - - def parse_report_server_id(self): - # Buildup of this function: - # 1 byte serverID - # 1 byte function (17) - # 1 byte bytecount - # 1 byte serverID (counts for bytecount) - # 1 byte Run Indicator Status (counts for bytecount) - # bytecount - 2 bytes of device specific data (counts for bytecount) - # 2 bytes of CRC - self.mimumum_length = 7 - data = self.data - self.puti(1, 'function', 'Function 17: Report Server ID') - - bytecount = data[2].data - self.puti(2, 'length', 'Data is {} bytes long'.format(bytecount)) - - self.puti(3, 'data', 'serverID: {}'.format(data[3].data)) - - run_indicator_status = data[4].data - if run_indicator_status == 0x00: - self.puti(4, 'data', 'Run Indicator status: Off') - elif run_indicator_status == 0xFF: - self.puti(4, 'data', 'Run Indicator status: On') - else: - self.puti(4, 'error', - 'Bad Run Indicator status: 0x{:X}'.format(run_indicator_status)) - - self.putl('data', 'Device specific data: {}, "{}"'.format(data[-1].data, - chr(data[-1].data)), 2 + bytecount) - - self.check_crc(4 + bytecount) - - def parse_error(self): - '''Parse a Modbus error message.''' - self.mimumum_length = 5 - # The function code of an error is always 0x80 above the function call - # that caused it. - functioncode = self.data[1].data - 0x80 - - functions = { - 1: 'Read Coils', - 2: 'Read Discrete Inputs', - 3: 'Read Holding Registers', - 4: 'Read Input Registers', - 5: 'Write Single Coil', - 6: 'Write Single Register', - 7: 'Read Exception Status', - 8: 'Diagnostic', - 11: 'Get Com Event Counter', - 12: 'Get Com Event Log', - 15: 'Write Multiple Coils', - 16: 'Write Multiple Registers', - 17: 'Report Slave ID', - 20: 'Read File Record', - 21: 'Write File Record', - 22: 'Mask Write Register', - 23: 'Read/Write Multiple Registers', - 24: 'Read FIFO Queue', - 43: 'Read Device Identification/Encapsulated Interface Transport', - } - functionname = '{}: {}'.format(functioncode, - functions.get(functioncode, 'Unknown function')) - self.puti(1, 'function', - 'Error for function {}'.format(functionname)) - - error = self.data[2].data - errorcodes = { - 1: 'Illegal Function', - 2: 'Illegal Data Address', - 3: 'Illegal Data Value', - 4: 'Slave Device Failure', - 5: 'Acknowledge', - 6: 'Slave Device Busy', - 8: 'Memory Parity Error', - 10: 'Gateway Path Unavailable', - 11: 'Gateway Target Device failed to respond', - } - errorname = '{}: {}'.format(error, errorcodes.get(error, 'Unknown')) - self.puti(2, 'data', 'Error {}'.format(errorname)) - self.check_crc(4) - -class Modbus_ADU_CS(Modbus_ADU): - '''CS stands for Client -> Server.''' - def parse(self): - '''Select which specific Modbus function we should parse.''' - data = self.data - - # This try-catch is being used as flow control. - try: - server_id = data[0].data - message = '' - if server_id == 0: - message = 'Broadcast message' - elif 1 <= server_id <= 247: - message = 'Slave ID: {}'.format(server_id) - elif 248 <= server_id <= 255: - message = 'Slave ID: {} (reserved address)'.format(server_id) - self.puti(0, 'server-id', message) - - function = data[1].data - if function >= 1 and function <= 4: - self.parse_read_data_command() - if function == 5: - self.parse_write_single_coil() - if function == 6: - self.parse_write_single_register() - if function in {7, 11, 12, 17}: - self.parse_single_byte_request() - elif function == 8: - self.parse_diagnostics() - if function in {15, 16}: - self.parse_write_multiple() - elif function == 22: - self.parse_mask_write_register() - elif function == 23: - self.parse_read_write_registers() - elif function in {21, 21, 24, 43}: - self.parse_not_implemented() - else: - self.puti(1, 'error', - 'Unknown function: {}'.format(data[1].data)) - self.putl('error', 'Unknown function') - - # If the message gets here without raising an exception, the - # message goes on longer than it should. - self.putl('error', 'Message too long') - - except No_more_data: - # Just a message saying we don't need to parse anymore this round. - pass - - def parse_read_data_command(self): - '''Interpret a command to read x units of data starting at address, ie - functions 1, 2, 3 and 4, and write the result to the annotations.''' - data = self.data - self.minimum_length = 8 - - function = data[1].data - functionname = {1: 'Read Coils', - 2: 'Read Discrete Inputs', - 3: 'Read Holding Registers', - 4: 'Read Input Registers', - }[function] - - self.puti(1, 'function', - 'Function {}: {}'.format(function, functionname)) - - starting_address = self.half_word(2) - # Some instruction manuals use a long form name for addresses, this is - # listed here for convienience. - # Example: holding register 60 becomes 30061. - address_name = 10000 * function + 1 + starting_address - self.puti(3, 'address', - 'Start at address 0x{:X} / {:d}'.format(starting_address, - address_name)) - - self.puti(5, 'length', - 'Read {:d} units of data'.format(self.half_word(4))) - self.check_crc(7) - - def parse_single_byte_request(self): - '''Some Modbus functions have no arguments, this parses those.''' - function = self.data[1].data - function_name = {7: 'Read Exception Status', - 11: 'Get Comm Event Counter', - 12: 'Get Comm Event Log', - 17: 'Report Slave ID', - }[function] - self.puti(1, 'function', - 'Function {}: {}'.format(function, function_name)) - - self.check_crc(3) - - def parse_write_multiple(self): - '''Function 15 and 16 are almost the same, so we can parse them both - using one function.''' - self.mimumum_length = 9 - - function = self.data[1].data - if function == 15: - data_unit = 'Coils' - max_outputs = 0x07B0 - ratio_bytes_data = 1/8 - long_address_offset = 10001 - elif function == 16: - data_unit = 'Registers' - max_outputs = 0x007B - ratio_bytes_data = 2 - long_address_offset = 30001 - - self.puti(1, 'function', - 'Function {}: Write Multiple {}'.format(function, data_unit)) - - starting_address = self.half_word(2) - # Some instruction manuals use a long form name for addresses, this is - # listed here for convienience. - address_name = long_address_offset + starting_address - self.puti(3, 'address', - 'Start at address 0x{:X} / {:d}'.format(starting_address, - address_name)) - - quantity_of_outputs = self.half_word(4) - if quantity_of_outputs <= max_outputs: - self.puti(5, 'length', - 'Write {} {}'.format(quantity_of_outputs, data_unit)) - else: - self.puti(5, 'error', - 'Bad value: {} {}. Max is {}'.format(quantity_of_outputs, - data_unit, max_outputs)) - proper_bytecount = ceil(quantity_of_outputs * ratio_bytes_data) - - bytecount = self.data[6].data - if bytecount == proper_bytecount: - self.puti(6, 'length', 'Byte count: {}'.format(bytecount)) - else: - self.puti(6, 'error', - 'Bad byte count, is {}, should be {}'.format(bytecount, - proper_bytecount)) - self.mimumum_length = bytecount + 9 - - self.putl('data', 'Value 0x{:X}', 6 + bytecount) - - self.check_crc(bytecount + 8) - - def parse_read_file_record(self): - self.puti(1, 'function', 'Function 20: Read file records') - - data = self.data - - bytecount = data[2].data - - self.minimum_length = 5 + bytecount - # 1 for serverID, 1 for function, 1 for bytecount, 2 for CRC. - - if 0x07 <= bytecount <= 0xF5: - self.puti(2, 'length', 'Request is {} bytes long'.format(bytecount)) - else: - self.puti(2, 'error', - 'Request claims to be {} bytes long, legal values are between' - ' 7 and 247'.format(bytecount)) - - current_byte = len(data) - 1 - # Function 20 is a number of sub-requests, the first starting at 3, - # the total length of the sub-requests is bytecount. - if current_byte <= bytecount + 2: - step = (current_byte - 3) % 7 - if step == 0: - if data[current_byte].data == 6: - self.puti(current_byte, 'data', 'Start sub-request') - else: - self.puti(current_byte, 'error', - 'First byte of subrequest should be 0x06') - elif step == 1: - raise No_more_data - elif step == 2: - file_number = self.half_word(current_byte - 1) - self.puti(current_byte, 'data', - 'Read File number {}'.format(file_number)) - elif step == 3: - raise No_more_data - elif step == 4: - record_number = self.half_word(current_byte - 1) - self.puti(current_byte, 'address', - 'Read from record number {}'.format(record_number)) - # TODO: Check if within range. - elif step == 5: - raise No_more_data - elif step == 6: - records_to_read = self.half_word(current_byte - 1) - self.puti(current_byte, 'length', - 'Read {} records'.format(records_to_read)) - self.check_crc(4 + bytecount) - - def parse_read_write_registers(self): - '''Parse function 23: Read/Write multiple registers.''' - self.minimum_length = 13 - - self.puti(1, 'function', 'Function 23: Read/Write Multiple Registers') - - starting_address = self.half_word(2) - # Some instruction manuals use a long form name for addresses, this is - # listed here for convienience. - # Example: holding register 60 becomes 30061. - address_name = 30001 + starting_address - self.puti(3, 'address', - 'Read starting at address 0x{:X} / {:d}'.format(starting_address, - address_name)) - - self.puti(5, 'length', 'Read {:d} units of data'.format(self.half_word(4))) - - starting_address = self.half_word(6) - self.puti(7, 'address', - 'Write starting at address 0x{:X} / {:d}'.format(starting_address, - address_name)) - - quantity_of_outputs = self.half_word(8) - self.puti(9, 'length', - 'Write {} registers'.format(quantity_of_outputs)) - proper_bytecount = quantity_of_outputs * 2 - - bytecount = self.data[10].data - if bytecount == proper_bytecount: - self.puti(10, 'length', 'Byte count: {}'.format(bytecount)) - else: - self.puti(10, 'error', - 'Bad byte count, is {}, should be {}'.format(bytecount, - proper_bytecount)) - self.mimumum_length = bytecount + 13 - - self.putl('data', 'Data, value 0x{:02X}', 10 + bytecount) - - self.check_crc(bytecount + 12) - -class Decoder(srd.Decoder): - api_version = 3 - id = 'modbus' - name = 'Modbus' - longname = 'Modbus RTU over RS232/RS485' - desc = 'Modbus RTU protocol for industrial applications.' - license = 'gplv3+' - inputs = ['uart'] - outputs = ['modbus'] - tags = ['Embedded/industrial'] - annotations = ( - ('sc-server-id', ''), - ('sc-function', ''), - ('sc-crc', ''), - ('sc-address', ''), - ('sc-data', ''), - ('sc-length', ''), - ('sc-error', ''), - ('cs-server-id', ''), - ('cs-function', ''), - ('cs-crc', ''), - ('cs-address', ''), - ('cs-data', ''), - ('cs-length', ''), - ('cs-error', ''), - ('error-indication', ''), - ) - annotation_rows = ( - ('sc', 'Server->client', (7, 8, 9, 10, 11, 12, 13)), - ('cs', 'Client->server', (0, 1, 2, 3, 4, 5, 6)), - ('error-indicator', 'Errors in frame', (14,)), - ) - options = ( - {'id': 'channel', 'desc': 'Direction', 'default': 'TX', - 'values': ('TX', 'RX')}, - ) - - def __init__(self): - self.reset() - - def reset(self): - self.ADUSc = None # Start off with empty slave -> client ADU. - self.ADUCs = None # Start off with empty client -> slave ADU. - - # The reason we have both (despite not supporting full duplex comms) is - # because we want to be able to decode the message as both client -> - # server and server -> client, and let the user see which of the two - # the ADU was. - - self.bitlength = None # We will later test how long a bit is. - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def puta(self, start, end, ann_str, message): - '''Put an annotation from start to end, with ann as a - string. This means you don't have to know the ann's - number to write annotations to it.''' - ann = [s[0] for s in self.annotations].index(ann_str) - self.put(start, end, self.out_ann, [ann, [message]]) - - def decode_adu(self, ss, es, data, direction): - '''Decode the next byte or bit (depending on type) in the ADU. - ss: Start time of the data - es: End time of the data - data: Data as passed from the UART decoder - direction: Is this data for the Cs (client -> server) or Sc (server -> - client) being decoded right now?''' - ptype, rxtx, pdata = data - - # We don't have a nice way to get the baud rate from UART, so we have - # to figure out how long a bit lasts. We do this by looking at the - # length of (probably) the startbit. - if self.bitlength is None: - if ptype == 'STARTBIT' or ptype == 'STOPBIT': - self.bitlength = es - ss - else: - # If we don't know the bitlength yet, we can't start decoding. - return - - # Select the ADU, create the ADU if needed. - # We set ADU.startNewFrame = True when we know the old one is over. - if direction == 'Sc': - if (self.ADUSc is None) or self.ADUSc.startNewFrame: - self.ADUSc = Modbus_ADU_SC(self, ss, TX, 'sc-') - ADU = self.ADUSc - if direction == 'Cs': - if self.ADUCs is None or self.ADUCs.startNewFrame: - self.ADUCs = Modbus_ADU_CS(self, ss, TX, 'cs-') - ADU = self.ADUCs - - # We need to determine if the last ADU is over. - # According to the Modbus spec, there should be 3.5 characters worth of - # space between each message. But if within a message there is a length - # of more than 1.5 character, that's an error. For our purposes - # somewhere between seems fine. - # A character is 11 bits long, so (3.5 + 1.5)/2 * 11 ~= 28 - # TODO: Display error for too short or too long. - if (ss - ADU.last_read) <= self.bitlength * 28: - ADU.add_data(ss, es, data) - else: - # It's been too long since the last part of the ADU! - # If there is any data in the ADU we need to show it to the user - if len(ADU.data) > 0: - # Extend errors for 3 bits after last byte, we can guarantee - # space. - ADU.close(ADU.data[-1].end + self.bitlength * 3) - - ADU.startNewFrame = True - # Restart this function, it will make a new ADU for us. - self.decode_adu(ss, es, data, direction) - - def decode(self, ss, es, data): - ptype, rxtx, pdata = data - - # Decide what ADU(s) we need this packet to go to. - # Note that it's possible to go to both ADUs. - if self.options['channel'] == 'TX': - self.decode_adu(ss, es, data, 'Sc') - if self.options['channel'] == 'RX': - self.decode_adu(ss, es, data, 'Cs') diff --git a/decoders/morse/__init__.py b/decoders/morse/__init__.py deleted file mode 100755 index 5d916247..00000000 --- a/decoders/morse/__init__.py +++ /dev/null @@ -1,28 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2017 Christoph Rackwitz -## -## 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, see . -## - -''' -Morse code is a method of transmitting text information as a series of -on-off tones. - -Details: -https://en.wikipedia.org/wiki/Morse_code -''' - -from .pd import Decoder diff --git a/decoders/morse/pd.py b/decoders/morse/pd.py deleted file mode 100755 index 8b5cb829..00000000 --- a/decoders/morse/pd.py +++ /dev/null @@ -1,250 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2017 Christoph Rackwitz -## -## 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, see . -## - -import sigrokdecode as srd - -def decode_ditdah(s): - return tuple({'-': 3, '.': 1}[c] for c in s) - -def encode_ditdah(tpl): - return ''.join({1: '.', 3: '-'}[c] for c in tpl) - -# https://www.itu.int/dms_pubrec/itu-r/rec/m/R-REC-M.1677-1-200910-I!!PDF-E.pdf -# Recommendation ITU-R M.1677-1 -# (10/2009) -# International Morse code -alphabet = { - # 1.1.1 Letters - '.-': 'a', - '-...': 'b', - '-.-.': 'c', - '-..': 'd', - '.': 'e', - '..-..': 'é', # "accented" - '..-.': 'f', - '--.': 'g', - '....': 'h', - '..': 'i', - '.---': 'j', - '-.-': 'k', - '.-..': 'l', - '--': 'm', - '-.': 'n', - '---': 'o', - '.--.': 'p', - '--.-': 'q', - '.-.': 'r', - '...': 's', - '-': 't', - '..-': 'u', - '...-': 'v', - '.--': 'w', - '-..-': 'x', - '-.--': 'y', - '--..': 'z', - - # 1.1.2 Figures - '.----': '1', - '..---': '2', - '...--': '3', - '....-': '4', - '.....': '5', - '-....': '6', - '--...': '7', - '---..': '8', - '----.': '9', - '-----': '0', - - # 1.1.3 Punctuation marks and miscellaneous signs - '.-.-.-': '.', # Full stop (period) - '--..--': ',', # Comma - '---...': ':', # Colon or division sign - '..--..': '?', # Question mark (note of interrogation or request for repetition of a transmission not understood) - '.----.': '’', # Apostrophe - '-....-': '-', # Hyphen or dash or subtraction sign - '-..-.': '/', # Fraction bar or division sign - '-.--.': '(', # Left-hand bracket (parenthesis) - '-.--.-': ')', # Right-hand bracket (parenthesis) - '.-..-.': '“ ”', # Inverted commas (quotation marks) (before and after the words) - '-...-': '=', # Double hyphen - '...-.': 'UNDERSTOOD', # Understood - '........': 'ERROR', # Error (eight dots) - '.-.-.': '+', # Cross or addition sign - '.-...': 'WAIT', # Wait - '...-.-': 'EOW', # End of work - '-.-.-': 'START', # Starting signal (to precede every transmission) - '.--.-.': '@', # Commercial at - - #'-.-': 'ITT', # K: Invitation to transmit - - # 3.2.1 For the multiplication sign, the signal corresponding to the letter X shall be transmitted. - #'-..-': '×', # Multiplication sign -} - -alphabet = {decode_ditdah(k): v for k, v in alphabet.items()} - -# 2 Spacing and length of the signals (right side is just for printing). -symbols = { # level, time units - # 2.1 A dash is equal to three dots. - (1, 1): '*', - (1, 3): '===', - # 2.2 The space between the signals forming the same letter is equal to one dot. - (0, 1): '_', - # 2.3 The space between two letters is equal to three dots. - (0, 3): '__', - # 2.4 The space between two words is equal to seven dots. - (0, 7): '___', -} - -class Decoder(srd.Decoder): - api_version = 3 - id = 'morse' - name = 'Morse' - longname = 'Morse code' - desc = 'Demodulated morse code protocol.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Encoding'] - channels = ( - {'id': 'data', 'name': 'Data', 'desc': 'Data line'}, - ) - options = ( - {'id': 'timeunit', 'desc': 'Time unit (guess)', 'default': 0.1}, - ) - annotations = ( - ('time', 'Time'), - ('units', 'Units'), - ('symbol', 'Symbol'), - ('letter', 'Letter'), - ('word', 'Word'), - ) - annotation_rows = tuple((u, v, (i,)) for i, (u, v) in enumerate(annotations)) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.out_binary = self.register(srd.OUTPUT_BINARY) - - def decode_symbols(self): - # Annotate symbols, emit symbols, handle timeout via token. - - timeunit = self.options['timeunit'] - - self.wait({0: 'r'}) - prevtime = self.samplenum # Time of an actual edge. - - while True: - (val,) = self.wait([{0: 'e'}, {'skip': int(5 * self.samplerate * timeunit)}]) - - pval = 1 - val - curtime = self.samplenum - dt = (curtime - prevtime) / self.samplerate - units = dt / timeunit - iunits = int(max(1, round(units))) - error = abs(units - iunits) - - symbol = (pval, iunits) - - if (self.matched & (0b1 << 1)): - yield None # Flush word. - continue - - self.put(prevtime, curtime, self.out_ann, [0, ['{:.3g}'.format(dt)]]) - - if symbol in symbols: - self.put(prevtime, curtime, self.out_ann, [1, ['{:.1f}*{:.3g}'.format(units, timeunit)]]) - yield (prevtime, curtime, symbol) - else: - self.put(prevtime, curtime, self.out_ann, [1, ['!! {:.1f}*{:.3g} !!'.format(units, timeunit)]]) - - prevtime = curtime - - thisunit = dt / iunits - timeunit += (thisunit - timeunit) * 0.2 * max(0, 1 - 2*error) # Adapt. - - def decode_morse(self): - # Group symbols into letters. - sequence = () - s0 = s1 = None - - for item in self.decode_symbols(): - do_yield = False - if item is not None: # Level + width. - (t0, t1, symbol) = item - (sval, sunits) = symbol - if sval == 1: - if s0 is None: - s0 = t0 - s1 = t1 - sequence += (sunits,) - else: - # Generate "flush" for end of letter, end of word. - if sunits >= 3: - do_yield = True - else: - do_yield = True - if do_yield: - if sequence: - yield (s0, s1, alphabet.get(sequence, encode_ditdah(sequence))) - sequence = () - s0 = s1 = None - if item is None: - yield None # Pass through flush of 5+ space. - - def decode(self): - - # Strictly speaking there is no point in running this decoder - # when the sample rate is unknown or zero. But the previous - # implementation already fell back to a rate of 1 in that case. - # We stick with this approach, to not introduce new constraints - # for existing use scenarios. - if not self.samplerate: - self.samplerate = 1.0 - - # Annotate letters, group into words. - s0 = s1 = None - word = '' - for item in self.decode_morse(): - do_yield = False - - if item is not None: # Append letter. - (t0, t1, letter) = item - self.put(t0, t1, self.out_ann, [3, [letter]]) - if s0 is None: - s0 = t0 - s1 = t1 - word += letter - else: - do_yield = True - - if do_yield: # Flush of word. - if word: - self.put(s0, s1, self.out_ann, [4, [word]]) - word = '' - s0 = s1 = None diff --git a/decoders/mrf24j40/__init__.py b/decoders/mrf24j40/__init__.py deleted file mode 100755 index 37b8b5c3..00000000 --- a/decoders/mrf24j40/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Karl Palsson -## -## 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, see . -## - -''' -This decoder stacks on top of the 'spi' PD and decodes Microchip MRF24J40 -IEEE 802.15.4 2.4 GHz RF tranceiver commands and data. -''' - -from .pd import Decoder diff --git a/decoders/mrf24j40/lists.py b/decoders/mrf24j40/lists.py deleted file mode 100755 index f5931c24..00000000 --- a/decoders/mrf24j40/lists.py +++ /dev/null @@ -1,165 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Karl Palsson -## -## 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, see . -## - -sregs = { - 0: 'RXMCR', - 1: 'PANIDL', - 2: 'PANIDH', - 3: 'SADRL', - 4: 'SADRH', - 5: 'EADR0', - 6: 'EADR1', - 7: 'EADR2', - 8: 'EADR3', - 9: 'EADR4', - 0xa: 'EADR5', - 0xb: 'EADR6', - 0xc: 'EADR7', - 0xd: 'RXFLUSH', - 0xe: 'Reserved', - 0xf: 'Reserved', - 0x10: 'ORDER', - 0x11: 'TXMCR', - 0x12: 'ACKTMOUT', - 0x13: 'ESLOTG1', - 0x14: 'SYMTICKL', - 0x15: 'SYMTICKH', - 0x16: 'PACON0', - 0x17: 'PACON1', - 0x18: 'PACON2', - 0x19: 'Reserved', - 0x1a: 'TXBCON0', - 0x1b: 'TXNCON', - 0x1c: 'TXG1CON', - 0x1d: 'TXG2CON', - 0x1e: 'ESLOTG23', - 0x1f: 'ESLOTG45', - 0x20: 'ESLOTG67', - 0x21: 'TXPEND', - 0x22: 'WAKECON', - 0x23: 'FRMOFFSET', - 0x24: 'TXSTAT', - 0x25: 'TXBCON1', - 0x26: 'GATECLK', - 0x27: 'TXTIME', - 0x28: 'HSYMTIMRL', - 0x29: 'HSYMTIMRH', - 0x2a: 'SOFTRST', - 0x2b: 'Reserved', - 0x2c: 'SECCON0', - 0x2d: 'SECCON1', - 0x2e: 'TXSTBL', - 0x2f: 'Reserved', - 0x30: 'RXSR', - 0x31: 'INTSTAT', - 0x32: 'INTCON', - 0x33: 'GPIO', - 0x34: 'TRISGPIO', - 0x35: 'SLPACK', - 0x36: 'RFCTL', - 0x37: 'SECCR2', - 0x38: 'BBREG0', - 0x39: 'BBREG1', - 0x3a: 'BBREG2', - 0x3b: 'BBREG3', - 0x3c: 'BBREG4', - 0x3d: 'Reserved', - 0x3e: 'BBREG6', - 0x3f: 'CCAEDTH', -} - -lregs = { - 0x200: 'RFCON0', - 0x201: 'RFCON1', - 0x202: 'RFCON2', - 0x203: 'RFCON3', - 0x204: 'Reserved', - 0x205: 'RFCON5', - 0x206: 'RFCON6', - 0x207: 'RFCON7', - 0x208: 'RFCON8', - 0x209: 'SLPCAL0', - 0x20A: 'SLPCAL1', - 0x20B: 'SLPCAL2', - 0x20C: 'Reserved', - 0x20D: 'Reserved', - 0x20E: 'Reserved', - 0x20F: 'RFSTATE', - 0x210: 'RSSI', - 0x211: 'SLPCON0', - 0x212: 'Reserved', - 0x213: 'Reserved', - 0x214: 'Reserved', - 0x215: 'Reserved', - 0x216: 'Reserved', - 0x217: 'Reserved', - 0x218: 'Reserved', - 0x219: 'Reserved', - 0x21A: 'Reserved', - 0x21B: 'Reserved', - 0x21C: 'Reserved', - 0x21D: 'Reserved', - 0x21E: 'Reserved', - 0x21F: 'Reserved', - 0x220: 'SLPCON1', - 0x221: 'Reserved', - 0x222: 'WAKETIMEL', - 0x223: 'WAKETIMEH', - 0x224: 'REMCNTL', - 0x225: 'REMCNTH', - 0x226: 'MAINCNT0', - 0x227: 'MAINCNT1', - 0x228: 'MAINCNT2', - 0x229: 'MAINCNT3', - 0x22A: 'Reserved', - 0x22B: 'Reserved', - 0x22C: 'Reserved', - 0x22D: 'Reserved', - 0x22E: 'Reserved', - 0x22F: 'TESTMODE', - 0x230: 'ASSOEADR0', - 0x231: 'ASSOEADR1', - 0x232: 'ASSOEADR2', - 0x233: 'ASSOEADR3', - 0x234: 'ASSOEADR4', - 0x235: 'ASSOEADR5', - 0x236: 'ASSOEADR6', - 0x237: 'ASSOEADR7', - 0x238: 'ASSOSADR0', - 0x239: 'ASSOSADR1', - 0x23A: 'Reserved', - 0x23B: 'Reserved', - 0x23C: 'Unimplemented', - 0x23D: 'Unimplemented', - 0x23E: 'Unimplemented', - 0x23F: 'Unimplemented', - 0x240: 'UPNONCE0', - 0x241: 'UPNONCE1', - 0x242: 'UPNONCE2', - 0x243: 'UPNONCE3', - 0x244: 'UPNONCE4', - 0x245: 'UPNONCE5', - 0x246: 'UPNONCE6', - 0x247: 'UPNONCE7', - 0x248: 'UPNONCE8', - 0x249: 'UPNONCE9', - 0x24A: 'UPNONCE10', - 0x24B: 'UPNONCE11', - 0x24C: 'UPNONCE12' -} diff --git a/decoders/mrf24j40/pd.py b/decoders/mrf24j40/pd.py deleted file mode 100755 index b242ee66..00000000 --- a/decoders/mrf24j40/pd.py +++ /dev/null @@ -1,137 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Karl Palsson -## -## 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, see . -## - -import sigrokdecode as srd -from .lists import * - -class Decoder(srd.Decoder): - api_version = 3 - id = 'mrf24j40' - name = 'MRF24J40' - longname = 'Microchip MRF24J40' - desc = 'IEEE 802.15.4 2.4 GHz RF tranceiver chip.' - license = 'gplv2+' - inputs = ['spi'] - outputs = [] - tags = ['IC', 'Wireless/RF'] - annotations = ( - ('sread', 'Short register read commands'), - ('swrite', 'Short register write commands'), - ('lread', 'Long register read commands'), - ('lwrite', 'Long register write commands'), - ('warning', 'Warnings'), - ) - annotation_rows = ( - ('read', 'Read', (0, 2)), - ('write', 'Write', (1, 3)), - ('warnings', 'Warnings', (4,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.ss_cmd, self.es_cmd = 0, 0 - self.mosi_bytes = [] - self.miso_bytes = [] - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putx(self, data): - self.put(self.ss_cmd, self.es_cmd, self.out_ann, data) - - def putw(self, pos, msg): - self.put(pos[0], pos[1], self.out_ann, [4, [msg]]) - - def reset_data(self): - self.mosi_bytes = [] - self.miso_bytes = [] - - def handle_short(self): - write = self.mosi_bytes[0] & 0x1 - reg = (self.mosi_bytes[0] >> 1) & 0x3f - reg_desc = sregs.get(reg, 'illegal') - if write: - self.putx([1, ['%s: %#x' % (reg_desc, self.mosi_bytes[1])]]) - else: - self.putx([0, ['%s: %#x' % (reg_desc, self.miso_bytes[1])]]) - - def handle_long(self): - dword = self.mosi_bytes[0] << 8 | self.mosi_bytes[1] - write = dword & (0x1 << 4) - reg = dword >> 5 & 0x3ff - if reg >= 0x0: - reg_desc = 'TX:%#x' % reg - if reg >= 0x80: - reg_desc = 'TX beacon:%#x' % reg - if reg >= 0x100: - reg_desc = 'TX GTS1:%#x' % reg - if reg >= 0x180: - reg_desc = 'TX GTS2:%#x' % reg - if reg >= 0x200: - reg_desc = lregs.get(reg, 'illegal') - if reg >= 0x280: - reg_desc = 'Security keys:%#x' % reg - if reg >= 0x2c0: - reg_desc = 'Reserved:%#x' % reg - if reg >= 0x300: - reg_desc = 'RX:%#x' % reg - - if write: - self.putx([3, ['%s: %#x' % (reg_desc, self.mosi_bytes[2])]]) - else: - self.putx([2, ['%s: %#x' % (reg_desc, self.miso_bytes[2])]]) - - def decode(self, ss, es, data): - ptype = data[0] - if ptype == 'CS-CHANGE': - # If we transition high mid-stream, toss out our data and restart. - cs_old, cs_new = data[1:] - if cs_old is not None and cs_old == 0 and cs_new == 1: - if len(self.mosi_bytes) not in (0, 2, 3): - self.putw([self.ss_cmd, es], 'Misplaced CS!') - self.reset_data() - return - - # Don't care about anything else. - if ptype != 'DATA': - return - mosi, miso = data[1:] - - self.ss, self.es = ss, es - - if len(self.mosi_bytes) == 0: - self.ss_cmd = ss - self.mosi_bytes.append(mosi) - self.miso_bytes.append(miso) - - # Everything is either 2 bytes or 3 bytes. - if len(self.mosi_bytes) < 2: - return - - if self.mosi_bytes[0] & 0x80: - if len(self.mosi_bytes) == 3: - self.es_cmd = es - self.handle_long() - self.reset_data() - else: - self.es_cmd = es - self.handle_short() - self.reset_data() diff --git a/decoders/mxc6225xu/__init__.py b/decoders/mxc6225xu/__init__.py deleted file mode 100755 index 2aaa726f..00000000 --- a/decoders/mxc6225xu/__init__.py +++ /dev/null @@ -1,28 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -''' -This decoder stacks on top of the 'i2c' PD and decodes the MEMSIC MXC6225XU -digital thermal orientation sensor (DTOS) protocol. - -The chip's I²C interface supports standard mode and fast mode (max. 400kHz). -Its I²C slave address is 0x2a. -''' - -from .pd import Decoder diff --git a/decoders/mxc6225xu/pd.py b/decoders/mxc6225xu/pd.py deleted file mode 100755 index e9617782..00000000 --- a/decoders/mxc6225xu/pd.py +++ /dev/null @@ -1,217 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -import sigrokdecode as srd - -# Definitions of various bits in MXC6225XU registers. -status = { - # SH[1:0] - 'sh': { - 0b00: 'none', - 0b01: 'shake left', - 0b10: 'shake right', - 0b11: 'undefined', - }, - # ORI[1:0] and OR[1:0] (same format) - 'ori': { - 0b00: 'vertical in upright orientation', - 0b01: 'rotated 90 degrees clockwise', - 0b10: 'vertical in inverted orientation', - 0b11: 'rotated 90 degrees counterclockwise', - }, - # SHTH[1:0] - 'shth': { - 0b00: '0.5g', - 0b01: '1.0g', - 0b10: '1.5g', - 0b11: '2.0g', - }, - # SHC[1:0] - 'shc': { - 0b00: '16', - 0b01: '32', - 0b10: '64', - 0b11: '128', - }, - # ORC[1:0] - 'orc': { - 0b00: '16', - 0b01: '32', - 0b10: '64', - 0b11: '128', - }, -} - -class Decoder(srd.Decoder): - api_version = 3 - id = 'mxc6225xu' - name = 'MXC6225XU' - longname = 'MEMSIC MXC6225XU' - desc = 'Digital Thermal Orientation Sensor (DTOS) protocol.' - license = 'gplv2+' - inputs = ['i2c'] - outputs = [] - tags = ['IC', 'Sensor'] - annotations = ( - ('text', 'Human-readable text'), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.state = 'IDLE' - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putx(self, data): - self.put(self.ss, self.es, self.out_ann, data) - - def handle_reg_0x00(self, b): - # XOUT: 8-bit x-axis acceleration output. - # Data is in 2's complement, values range from -128 to 127. - self.putx([0, ['XOUT: %d' % b]]) - - def handle_reg_0x01(self, b): - # YOUT: 8-bit y-axis acceleration output. - # Data is in 2's complement, values range from -128 to 127. - self.putx([0, ['YOUT: %d' % b]]) - - def handle_reg_0x02(self, b): - # STATUS: Orientation and shake status. - - # Bits[7:7]: INT - int_val = (b >> 7) & 1 - s = 'unchanged and no' if (int_val == 0) else 'changed or' - ann = 'INT = %d: Orientation %s shake event occurred\n' % (int_val, s) - - # Bits[6:5]: SH[1:0] - sh = (((b >> 6) & 1) << 1) | ((b >> 5) & 1) - ann += 'SH[1:0] = %s: Shake event: %s\n' % \ - (bin(sh)[2:], status['sh'][sh]) - - # Bits[4:4]: TILT - tilt = (b >> 4) & 1 - s = '' if (tilt == 0) else 'not ' - ann += 'TILT = %d: Orientation measurement is %svalid\n' % (tilt, s) - - # Bits[3:2]: ORI[1:0] - ori = (((b >> 3) & 1) << 1) | ((b >> 2) & 1) - ann += 'ORI[1:0] = %s: %s\n' % (bin(ori)[2:], status['ori'][ori]) - - # Bits[1:0]: OR[1:0] - or_val = (((b >> 1) & 1) << 1) | ((b >> 0) & 1) - ann += 'OR[1:0] = %s: %s\n' % (bin(or_val)[2:], status['ori'][or_val]) - - # ann += 'b = %s\n' % (bin(b)) - - self.putx([0, [ann]]) - - def handle_reg_0x03(self, b): - # DETECTION: Powerdown, orientation and shake detection parameters. - # Note: This is a write-only register. - - # Bits[7:7]: PD - pd = (b >> 7) & 1 - s = 'Do not power down' if (pd == 0) else 'Power down' - ann = 'PD = %d: %s the device (into a low-power state)\n' % (pd, s) - - # Bits[6:6]: SHM - shm = (b >> 6) & 1 - ann = 'SHM = %d: Set shake mode to %d\n' % (shm, shm) - - # Bits[5:4]: SHTH[1:0] - shth = (((b >> 5) & 1) << 1) | ((b >> 4) & 1) - ann += 'SHTH[1:0] = %s: Set shake threshold to %s\n' \ - % (bin(shth)[2:], status['shth'][shth]) - - # Bits[3:2]: SHC[1:0] - shc = (((b >> 3) & 1) << 1) | ((b >> 2) & 1) - ann += 'SHC[1:0] = %s: Set shake count to %s readings\n' \ - % (bin(shc)[2:], status['shc'][shc]) - - # Bits[1:0]: ORC[1:0] - orc = (((b >> 1) & 1) << 1) | ((b >> 0) & 1) - ann += 'ORC[1:0] = %s: Set orientation count to %s readings\n' \ - % (bin(orc)[2:], status['orc'][orc]) - - self.putx([0, [ann]]) - - # TODO: Fixup, this is copy-pasted from another PD. - # TODO: Handle/check the ACKs/NACKs. - def decode(self, ss, es, data): - cmd, databyte = data - - # Store the start/end samples of this I²C packet. - self.ss, self.es = ss, es - - # State machine. - if self.state == 'IDLE': - # Wait for an I²C START condition. - if cmd != 'START': - return - self.state = 'GET SLAVE ADDR' - elif self.state == 'GET SLAVE ADDR': - # Wait for an address write operation. - # TODO: We should only handle packets to the slave(?) - if cmd != 'ADDRESS WRITE': - return - self.state = 'GET REG ADDR' - elif self.state == 'GET REG ADDR': - # Wait for a data write (master selects the slave register). - if cmd != 'DATA WRITE': - return - self.reg = databyte - self.state = 'WRITE REGS' - elif self.state == 'WRITE REGS': - # If we see a Repeated Start here, it's a multi-byte read. - if cmd == 'START REPEAT': - self.state = 'READ REGS' - return - # Otherwise: Get data bytes until a STOP condition occurs. - if cmd == 'DATA WRITE': - handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg) - handle_reg(databyte) - self.reg += 1 - # TODO: Check for NACK! - elif cmd == 'STOP': - # TODO - self.state = 'IDLE' - else: - pass # TODO - elif self.state == 'READ REGS': - # Wait for an address read operation. - # TODO: We should only handle packets to the slave(?) - if cmd == 'ADDRESS READ': - self.state = 'READ REGS2' - return - else: - pass # TODO - elif self.state == 'READ REGS2': - if cmd == 'DATA READ': - handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg) - handle_reg(databyte) - self.reg += 1 - # TODO: Check for NACK! - elif cmd == 'STOP': - # TODO - self.state = 'IDLE' - else: - pass # TODO? diff --git a/decoders/nes_gamepad/__init__.py b/decoders/nes_gamepad/__init__.py deleted file mode 100644 index e7543748..00000000 --- a/decoders/nes_gamepad/__init__.py +++ /dev/null @@ -1,54 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Stephan Thiele -## -## 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, see . -## - -''' -This decoder stacks on top of the 'spi' PD and decodes the button states -of an NES gamepad. - -The SPI decoder needs to be configured as follows: - -Clock polarity = 1 -Clock phase = 0 -Bit order = msb-first -Word size = 8 - -Chip-select is not used and must not be assigned to any channel. - -Hardware setup is as follows: - ___ - GND |o \ - CUP |o o| VCC - OUT 0 |o o| D3 - D1 |o o| D4 - ----- -NES Gamepad Connector - -VCC - Power 5V -GND - Ground -CUP - Shift register clock (CLK) -OUT 0 - Shift register latch (optional) -D1 - Gamepad data (MOSI) -D3 - Data (unused) -D4 - Data (unused) - -Data pins D3 and D4 are not used by the standard gamepad but -by special controllers like the Nintento Zapper light gun. -''' - -from .pd import Decoder diff --git a/decoders/nes_gamepad/pd.py b/decoders/nes_gamepad/pd.py deleted file mode 100644 index b276e5db..00000000 --- a/decoders/nes_gamepad/pd.py +++ /dev/null @@ -1,105 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Stephan Thiele -## -## 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, see . -## - -import sigrokdecode as srd - -class Decoder(srd.Decoder): - api_version = 3 - id = 'nes_gamepad' - name = 'NES gamepad' - longname = 'Nintendo Entertainment System gamepad' - desc = 'NES gamepad button states.' - license = 'gplv2+' - inputs = ['spi'] - outputs = [] - tags = ['Retro computing'] - options = ( - # Currently only the standard controller is supported. This might be - # extended by special controllers like the Nintendo Zapper light gun. - {'id': 'variant', 'desc': 'Gamepad variant', - 'default': 'Standard gamepad', 'values': ('Standard gamepad',)}, - ) - annotations = ( - ('button', 'Button state'), - ('no-press', 'No button press'), - ('not-connected', 'Gamepad unconnected') - ) - annotation_rows = ( - ('buttons', 'Button states', (0,)), - ('no-presses', 'No button presses', (1,)), - ('not-connected-vals', 'Gamepad unconnected', (2,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.variant = None - self.ss_block = None - self.es_block = None - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.variant = self.options['variant'] - - def putx(self, data): - self.put(self.ss_block, self.es_block, self.out_ann, data) - - def handle_data(self, value): - if value == 0xFF: - self.putx([1, ['No button is pressed']]) - return - - if value == 0x00: - self.putx([2, ['Gamepad is not connected']]) - return - - buttons = [ - 'A', - 'B', - 'Select', - 'Start', - 'North', - 'South', - 'West', - 'East' - ] - - bits = format(value, '08b') - button_str = '' - - for b in enumerate(bits): - button_index = b[0] - button_is_pressed = b[1] == '0' - - if button_is_pressed: - if button_str != '': - button_str += ' + ' - button_str += buttons[button_index] - - self.putx([0, ['%s' % button_str]]) - - def decode(self, ss, es, data): - ptype, mosi, miso = data - self.ss_block, self.es_block = ss, es - - if ptype != 'DATA': - return - - self.handle_data(miso) diff --git a/decoders/nrf24l01/__init__.py b/decoders/nrf24l01/__init__.py deleted file mode 100755 index 60124780..00000000 --- a/decoders/nrf24l01/__init__.py +++ /dev/null @@ -1,29 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Jens Steinhauser -## -## 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, see . -## - -''' -This decoder stacks on top of the 'spi' PD and decodes the protocol spoken -by the Nordic Semiconductor nRF24L01 and nRF24L01+ 2.4GHz transceiver chips. - -Details: -http://www.nordicsemi.com/eng/Products/2.4GHz-RF/nRF24L01 -http://www.nordicsemi.com/eng/Products/2.4GHz-RF/nRF24L01P -''' - -from .pd import Decoder diff --git a/decoders/nrf24l01/pd.py b/decoders/nrf24l01/pd.py deleted file mode 100755 index 89a2d3b4..00000000 --- a/decoders/nrf24l01/pd.py +++ /dev/null @@ -1,370 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Jens Steinhauser -## Copyright (C) 2019 DreamSourceLab -## -## 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, see . -## - -import sigrokdecode as srd - -class ChannelError(Exception): - pass - -regs = { -# addr: ('name', size) - 0x00: ('CONFIG', 1), - 0x01: ('EN_AA', 1), - 0x02: ('EN_RXADDR', 1), - 0x03: ('SETUP_AW', 1), - 0x04: ('SETUP_RETR', 1), - 0x05: ('RF_CH', 1), - 0x06: ('RF_SETUP', 1), - 0x07: ('STATUS', 1), - 0x08: ('OBSERVE_TX', 1), - 0x09: ('RPD', 1), - 0x0a: ('RX_ADDR_P0', 5), - 0x0b: ('RX_ADDR_P1', 5), - 0x0c: ('RX_ADDR_P2', 1), - 0x0d: ('RX_ADDR_P3', 1), - 0x0e: ('RX_ADDR_P4', 1), - 0x0f: ('RX_ADDR_P5', 1), - 0x10: ('TX_ADDR', 5), - 0x11: ('RX_PW_P0', 1), - 0x12: ('RX_PW_P1', 1), - 0x13: ('RX_PW_P2', 1), - 0x14: ('RX_PW_P3', 1), - 0x15: ('RX_PW_P4', 1), - 0x16: ('RX_PW_P5', 1), - 0x17: ('FIFO_STATUS', 1), - 0x1c: ('DYNPD', 1), - 0x1d: ('FEATURE', 1), -} - -xn297_regs = { - 0x19: ('DEMOD_CAL', 1), - 0x1a: ('RF_CAL2', 6), - 0x1b: ('DEM_CAL2', 3), - 0x1e: ('RF_CAL', 3), - 0x1f: ('BB_CAL', 5), -} - -class Decoder(srd.Decoder): - api_version = 3 - id = 'nrf24l01' - name = 'nRF24L01(+)' - longname = 'Nordic Semiconductor nRF24L01(+)' - desc = '2.4GHz RF transceiver chip.' - license = 'gplv2+' - inputs = ['spi'] - outputs = [] - tags = ['IC', 'Wireless/RF'] - options = ( - {'id': 'chip', 'desc': 'Chip type', - 'default': 'nrf24l01', 'values': ('nrf24l01', 'xn297')}, - {'id': 'hex_display', 'desc': 'Display payload in Hex', 'default': 'yes', - 'values': ('yes', 'no')}, - ) - annotations = ( - # Sent from the host to the chip. - ('cmd', 'Commands sent to the device'), - ('tx-data', 'Payload sent to the device'), - - # Returned by the chip. - ('register', 'Registers read from the device'), - ('rx-data', 'Payload read from the device'), - - ('warning', 'Warnings'), - ) - ann_cmd = 0 - ann_tx = 1 - ann_reg = 2 - ann_rx = 3 - ann_warn = 4 - annotation_rows = ( - ('commands', 'Commands', (ann_cmd, ann_tx)), - ('responses', 'Responses', (ann_reg, ann_rx)), - ('warnings', 'Warnings', (ann_warn,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.next() - self.requirements_met = True - self.cs_was_released = False - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - if self.options['chip'] == 'xn297': - regs.update(xn297_regs) - - def warn(self, pos, msg): - '''Put a warning message 'msg' at 'pos'.''' - self.put(pos[0], pos[1], self.out_ann, [self.ann_warn, [msg]]) - - def putp(self, pos, ann, msg): - '''Put an annotation message 'msg' at 'pos'.''' - self.put(pos[0], pos[1], self.out_ann, [ann, [msg]]) - - def next(self): - '''Resets the decoder after a complete command was decoded.''' - # 'True' for the first byte after CS went low. - self.first = True - - # The current command, and the minimum and maximum number - # of data bytes to follow. - self.cmd = None - self.min = 0 - self.max = 0 - - # Used to collect the bytes after the command byte - # (and the start/end sample number). - self.mb = [] - self.mb_s = -1 - self.mb_e = -1 - - def mosi_bytes(self): - '''Returns the collected MOSI bytes of a multi byte command.''' - return [b[0] for b in self.mb] - - def miso_bytes(self): - '''Returns the collected MISO bytes of a multi byte command.''' - return [b[1] for b in self.mb] - - def decode_command(self, pos, b): - '''Decodes the command byte 'b' at position 'pos' and prepares - the decoding of the following data bytes.''' - c = self.parse_command(b) - if c is None: - self.warn(pos, 'unknown command') - return - - self.cmd, self.dat, self.min, self.max = c - - if self.cmd in ('W_REGISTER', 'ACTIVATE', 'RST_FSPI'): - # Don't output anything now, the command is merged with - # the data bytes following it. - self.mb_s = pos[0] - else: - self.putp(pos, self.ann_cmd, self.format_command()) - - def format_command(self): - '''Returns the label for the current command.''' - if self.cmd == 'R_REGISTER': - reg = regs[self.dat][0] if self.dat in regs else 'unknown register' - return 'Cmd R_REGISTER "{}"'.format(reg) - else: - return 'Cmd {}'.format(self.cmd) - - def parse_command(self, b): - '''Parses the command byte. - - Returns a tuple consisting of: - - the name of the command - - additional data needed to dissect the following bytes - - minimum number of following bytes - - maximum number of following bytes - ''' - buflen = 32 - if self.options['chip'] == 'xn297': - buglen = 64 - if (b & 0xe0) in (0b00000000, 0b00100000): - c = 'R_REGISTER' if not (b & 0xe0) else 'W_REGISTER' - d = b & 0x1f - m = regs[d][1] if d in regs else 1 - return (c, d, 1, m) - if b == 0b01010000: - # nRF24L01 only - return ('ACTIVATE', None, 1, 1) - if b == 0b01100001: - return ('R_RX_PAYLOAD', None, 1, buflen) - if b == 0b01100000: - return ('R_RX_PL_WID', None, 1, 1) - if b == 0b10100000: - return ('W_TX_PAYLOAD', None, 1, buflen) - if b == 0b10110000: - return ('W_TX_PAYLOAD_NOACK', None, 1, buflen) - if (b & 0xf8) == 0b10101000: - return ('W_ACK_PAYLOAD', b & 0x07, 1, buflen) - if b == 0b11100001: - return ('FLUSH_TX', None, 0, 0) - if b == 0b11100010: - return ('FLUSH_RX', None, 0, 0) - if b == 0b11100011: - return ('REUSE_TX_PL', None, 0, 0) - if b == 0b11111111: - return ('NOP', None, 0, 0) - - if self.options['chip'] == 'xn297': - if b == 0b11111101: - return ('CE_FSPI_ON', None, 1, 1) - if b == 0b11111100: - return ('CE_FSPI_OFF', None, 1, 1) - if b == 0b01010011: - return ('RST_FSPI', None, 1, 1) - - def decode_register(self, pos, ann, regid, data): - '''Decodes a register. - - pos -- start and end sample numbers of the register - ann -- is the annotation number that is used to output the register. - regid -- may be either an integer used as a key for the 'regs' - dictionary, or a string directly containing a register name.' - data -- is the register content. - ''' - - if type(regid) == int: - # Get the name of the register. - if regid not in regs: - self.warn(pos, 'unknown register') - return - name = regs[regid][0] - else: - name = regid - - # Multi byte register come LSByte first. - data = reversed(data) - - if self.cmd == 'W_REGISTER' and ann == self.ann_cmd: - # The 'W_REGISTER' command is merged with the following byte(s). - label = '{}: {}'.format(self.format_command(), name) - else: - label = 'Reg {}'.format(name) - - self.decode_mb_data(pos, ann, data, label, True) - - def decode_mb_data(self, pos, ann, data, label, always_hex): - '''Decodes the data bytes 'data' of a multibyte command at position - 'pos'. The decoded data is prefixed with 'label'. If 'always_hex' is - True, all bytes are decoded as hex codes, otherwise only non - printable characters are escaped.''' - - if always_hex: - def escape(b): - return '{:02X}'.format(b) - else: - def escape(b): - c = chr(b) - if not str.isprintable(c): - return '\\x{:02X}'.format(b) - return c - - data = ''.join([escape(b) for b in data]) - text = '{} = "{}"'.format(label, data.strip()) - self.putp(pos, ann, text) - - def finish_command(self, pos): - '''Decodes the remaining data bytes at position 'pos'.''' - - always_hex = self.options['hex_display'] == 'yes' - if self.cmd == 'R_REGISTER': - self.decode_register(pos, self.ann_reg, - self.dat, self.miso_bytes()) - elif self.cmd == 'W_REGISTER': - self.decode_register(pos, self.ann_cmd, - self.dat, self.mosi_bytes()) - elif self.cmd == 'R_RX_PAYLOAD': - self.decode_mb_data(pos, self.ann_rx, - self.miso_bytes(), 'RX payload', always_hex) - elif (self.cmd == 'W_TX_PAYLOAD' or - self.cmd == 'W_TX_PAYLOAD_NOACK'): - self.decode_mb_data(pos, self.ann_tx, - self.mosi_bytes(), 'TX payload', always_hex) - elif self.cmd == 'W_ACK_PAYLOAD': - lbl = 'ACK payload for pipe {}'.format(self.dat) - self.decode_mb_data(pos, self.ann_tx, - self.mosi_bytes(), lbl, always_hex) - elif self.cmd == 'R_RX_PL_WID': - msg = 'Payload width = {}'.format(self.mb[0][1]) - self.putp(pos, self.ann_reg, msg) - elif self.cmd == 'ACTIVATE': - if self.mosi_bytes()[0] == 0x8c: - self.cmd = 'DEACTIVATE' - elif self.mosi_bytes()[0] != 0x73: - self.warn(pos, 'wrong data for "ACTIVATE" command') - self.putp(pos, self.ann_cmd, self.format_command()) - elif self.cmd == 'RST_FSPI': - if self.mosi_bytes()[0] == 0x5a: - self.cmd = 'RST_FSPI_HOLD' - elif self.mosi_bytes()[0] == 0xa5: - self.cmd = 'RST_FSPI_RELS' - else: - self.warn(pos, 'wrong data for "RST_FSPI" command') - self.putp(pos, self.ann_cmd, self.format_command()) - - - def decode(self, ss, es, data): - if not self.requirements_met: - return - - ptype, data1, data2 = data - - if ptype == 'TRANSFER': - if self.cmd: - # Check if we got the minimum number of data bytes - # after the command byte. - if len(self.mb) < self.min: - self.warn((ss, ss), 'missing data bytes') - elif self.mb: - self.finish_command((self.mb_s, self.mb_e)) - - self.next() - self.cs_was_released = True - elif ptype == 'CS-CHANGE': - if data1 is None: - if data2 is None: - self.requirements_met = False - raise ChannelError('CS# pin required.') - elif data2 == 1: - self.cs_was_released = True - - if data1 == 0 and data2 == 1: - # Rising edge, the complete command is transmitted, process - # the bytes that were send after the command byte. - if self.cmd: - # Check if we got the minimum number of data bytes - # after the command byte. - if len(self.mb) < self.min: - self.warn((ss, ss), 'missing data bytes') - elif self.mb: - self.finish_command((self.mb_s, self.mb_e)) - - self.next() - self.cs_was_released = True - elif ptype == 'DATA' and self.cs_was_released: - mosi, miso = data1, data2 - pos = (ss, es) - - if miso is None or mosi is None: - self.requirements_met = False - raise ChannelError('Both MISO and MOSI pins required.') - - if self.first: - self.first = False - # First MOSI byte is always the command. - self.decode_command(pos, mosi) - # First MISO byte is always the status register. - self.decode_register(pos, self.ann_reg, 'STATUS', [miso]) - else: - if not self.cmd or len(self.mb) >= self.max: - self.warn(pos, 'excess byte') - else: - # Collect the bytes after the command byte. - if self.mb_s == -1: - self.mb_s = ss - self.mb_e = es - self.mb.append((mosi, miso)) diff --git a/decoders/nrf905/__init__.py b/decoders/nrf905/__init__.py deleted file mode 100644 index c6d35abb..00000000 --- a/decoders/nrf905/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 Jorge Solla Rubiales -## -## 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 -## - -''' -This decoder stacks on top of the 'spi' PD and decodes the Nordic Semiconductor -NRF905 (433/868/915MHz transceiver) command/responses. -''' - -from .pd import Decoder diff --git a/decoders/nrf905/pd.py b/decoders/nrf905/pd.py deleted file mode 100644 index 12949fea..00000000 --- a/decoders/nrf905/pd.py +++ /dev/null @@ -1,301 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 Jorge Solla Rubiales -## -## Permission is hereby granted, free of charge, to any person obtaining a copy -## of this software and associated documentation files (the "Software"), to deal -## in the Software without restriction, including without limitation the rights -## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -## copies of the Software, and to permit persons to whom the Software is -## furnished to do so, subject to the following conditions: -## -## The above copyright notice and this permission notice shall be included in all -## copies or substantial portions of the Software. -## -## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -## SOFTWARE. - -import sigrokdecode as srd -from common.srdhelper import SrdIntEnum - -CFG_REGS = { - 0: [{'name': 'CH_NO', 'stbit': 7, 'nbits': 8}], - 1: [ - {'name': 'AUTO_RETRAN', 'stbit': 5, 'nbits': 1, - 'opts': {0: 'No retransmission', 1: 'Retransmission of data packet'}}, - {'name': 'RX_RED_PWR', 'stbit': 4, 'nbits': 1, - 'opts': {0: 'Normal operation', 1: 'Reduced power'}}, - {'name': 'PA_PWR', 'stbit': 3, 'nbits': 2, - 'opts': {0: '-10 dBm', 1: '-2 dBm', 2: '+6 dBm', 3: '+10 dBm'}}, - {'name': 'HFREQ_PLL', 'stbit': 1, 'nbits': 1, - 'opts': {0: '433 MHz', 1: '868 / 915 MHz'}}, - {'name': 'CH_NO_8', 'stbit': 0, 'nbits': 1}, - ], - 2: [ - {'name': 'TX_AFW (TX addr width)', 'stbit': 6, 'nbits': 3}, - {'name': 'RX_AFW (RX addr width)', 'stbit': 2, 'nbits': 3}, - ], - 3: [{'name': 'RW_PW (RX payload width)', 'stbit': 5, 'nbits': 6}], - 4: [{'name': 'TX_PW (TX payload width)', 'stbit': 5, 'nbits': 6}], - 5: [{'name': 'RX_ADDR_0', 'stbit': 7, 'nbits': 8}], - 6: [{'name': 'RX_ADDR_1', 'stbit': 7, 'nbits': 8}], - 7: [{'name': 'RX_ADDR_2', 'stbit': 7, 'nbits': 8}], - 8: [{'name': 'RX_ADDR_3', 'stbit': 7, 'nbits': 8}], - 9: [ - {'name': 'CRC_MODE', 'stbit': 7, 'nbits': 1, - 'opts': {0: '8 CRC check bit', 1: '16 CRC check bit'}}, - {'name': 'CRC_EN', 'stbit': 6, 'nbits': 1, - 'opts': {0: 'Disabled', 1: 'Enabled'}}, - {'name': 'XOR', 'stbit': 5, 'nbits': 3, - 'opts': {0: '4 MHz', 1: '8 MHz', 2: '12 MHz', - 3: '16 MHz', 4: '20 MHz'}}, - {'name': 'UP_CLK_EN', 'stbit': 2, 'nbits': 1, - 'opts': {0: 'No external clock signal avail.', - 1: 'External clock signal enabled'}}, - {'name': 'UP_CLK_FREQ', 'stbit': 1, 'nbits': 2, - 'opts': {0: '4 MHz', 1: '2 MHz', 2: '1 MHz', 3: '500 kHz'}}, - ], -} - -CHN_CFG = [ - {'name': 'PA_PWR', 'stbit': 3, 'nbits': 2, - 'opts': {0: '-10 dBm', 1: '-2 dBm', 2: '+6 dBm', 3: '+10 dBm'}}, - {'name': 'HFREQ_PLL', 'stbit': 1, 'nbits': 1, - 'opts': {0: '433 MHz', 1: '868 / 915 MHz'}}, -] - -STAT_REG = [ - {'name': 'AM', 'stbit': 7, 'nbits': 1}, - {'name': 'DR', 'stbit': 5, 'nbits': 1}, -] - -Ann = SrdIntEnum.from_str('Ann', 'CMD REG_WR REG_RD TX RX RESP WARN') - -class Decoder(srd.Decoder): - api_version = 3 - id = 'nrf905' - name = 'nRF905' - longname = 'Nordic Semiconductor nRF905' - desc = '433/868/933MHz transceiver chip.' - license = 'mit' - inputs = ['spi'] - outputs = [] - tags = ['IC', 'Wireless/RF'] - annotations = ( - ('cmd', 'Command sent to the device'), - ('reg-write', 'Config register written to the device'), - ('reg-read', 'Config register read from the device'), - ('tx-data', 'Payload sent to the device'), - ('rx-data', 'Payload read from the device'), - ('resp', 'Response to commands received from the device'), - ('warning', 'Warning'), - ) - annotation_rows = ( - ('commands', 'Commands', (Ann.CMD,)), - ('responses', 'Responses', (Ann.RESP,)), - ('registers', 'Registers', (Ann.REG_WR, Ann.REG_RD)), - ('tx', 'Transmitted data', (Ann.TX,)), - ('rx', 'Received data', (Ann.RX,)), - ('warnings', 'Warnings', (Ann.WARN,)), - ) - - def __init__(self): - self.ss_cmd, self.es_cmd = 0, 0 - self.cs_asserted = False - self.reset() - - def reset(self): - self.mosi_bytes, self.miso_bytes = [], [] - self.cmd_samples = {'ss': 0, 'es': 0} - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def extract_bits(self, byte, start_bit, num_bits): - begin = 7 - start_bit - end = begin + num_bits - if begin < 0 or end > 8: - return 0 - binary = format(byte, '08b')[begin:end] - return int(binary, 2) - - def extract_vars(self, reg_vars, reg_value): - # Iterate all vars on current register. - data = '' - for var in reg_vars: - var_value = self.extract_bits(reg_value, var['stbit'], var['nbits']) - data += var['name'] + ' = ' + str(var_value) - opt = '' - - # If var has options, just add the option meaning. - if 'opts' in var: - opt = var['opts'].get(var_value, 'unknown') - data += ' (' + opt + ')' - - # Add var separator. - if reg_vars.index(var) != len(reg_vars) - 1: - data += ' | ' - return data - - def parse_config_register(self, addr, value, is_write): - reg_value = value[0] - data = 'CFG_REG[' + hex(addr) + '] -> ' - - # Get register vars for this register. - if addr in CFG_REGS: - reg_vars = CFG_REGS[addr] - else: - # Invalid register address. - self.put(value[1], value[2], - self.out_ann, [Ann.WARN, ['Invalid reg. addr']]) - return - - data += self.extract_vars(reg_vars, reg_value) - - ann = Ann.REG_WR if is_write else Ann.REG_RD - self.put(value[1], value[2], self.out_ann, [ann, [data]]) - - def parse_config_registers(self, addr, registers, is_write): - i = 0 - while i < len(registers): - reg_addr = i + addr - if reg_addr <= 9: - self.parse_config_register(reg_addr, registers[i], is_write) - i += 1 - - def dump_cmd_bytes(self, prefix, cmd_bytes, ann): - ss, es = cmd_bytes[1][1], 0 - data = '' - for byte in cmd_bytes[1:]: - data += format(byte[0], '02X') + ' ' - es = byte[2] - self.put(ss, es, self.out_ann, [ann, [prefix + data]]) - - def handle_WC(self): - start_addr = self.mosi_bytes[0][0] & 0x0F - if start_addr > 9: - return - self.parse_config_registers(start_addr, self.mosi_bytes[1:], True) - - def handle_RC(self): - start_addr = self.mosi_bytes[0][0] & 0x0F - if start_addr > 9: - return - self.parse_config_registers(start_addr, self.miso_bytes[1:], False) - - def handle_WTP(self): - self.dump_cmd_bytes('Write TX payload.: ', self.mosi_bytes, Ann.TX) - - def handle_RTP(self): - self.dump_cmd_bytes('Read TX payload: ', self.miso_bytes, Ann.RESP) - - def handle_WTA(self): - self.dump_cmd_bytes('Write TX addr: ', self.mosi_bytes, Ann.REG_WR) - - def handle_RTA(self): - self.dump_cmd_bytes('Read TX addr: ', self.miso_bytes, Ann.RESP) - - def handle_RRP(self): - self.dump_cmd_bytes('Read RX payload: ', self.miso_bytes, Ann.RX) - - def handle_CC(self): - cmd, dta = self.mosi_bytes[0], self.mosi_bytes[1] - channel = ((cmd[0] & 0x01) << 8) + dta - data = self.extract_vars(CHN_CFG, cmd[0]) - data += '| CHN = ' + str(channel) - self.put(self.mosi_bytes[0][1], self.mosi_bytes[1][2], - self.out_ann, [Ann.REG_WR, [data]]) - - def handle_STAT(self): - status = 'STAT = ' + self.extract_vars(STAT_REG, self.miso_bytes[0][0]) - self.put(self.miso_bytes[0][1], self.miso_bytes[0][2], - self.out_ann, [Ann.REG_RD, [status]]) - - def process_cmd(self): - cmd, cmd_name, cmd_hnd = '', '', None - - for byte in self.mosi_bytes: - cmd += hex(byte[0]) + ' ' - - cmd = self.mosi_bytes[0][0] - - if (cmd & 0xF0) == 0x00: - cmd_name, cmd_hnd = 'CMD: W_CONFIG (WC)', self.handle_WC - elif (cmd & 0xF0) == 0x10: - cmd_name, cmd_hnd = 'CMD: R_CONFIG (RC)', self.handle_RC - elif cmd == 0x20: - cmd_name, cmd_hnd = 'CMD: W_TX_PAYLOAD (WTP)', self.handle_WTP - elif cmd == 0x21: - cmd_name, cmd_hnd = 'CMD: R_TX_PAYLOAD (RTP)', self.handle_RTP - elif cmd == 0x22: - cmd_name, cmd_hnd = 'CMD: W_TX_ADDRESS (WTA)', self.handle_WTA - elif cmd == 0x23: - cmd_name, cmd_hnd = 'CMD: R_TX_ADDRESS (RTA)', self.handle_RTA - elif cmd == 0x24: - cmd_name, cmd_hnd = 'CMD: R_RX_PAYLOAD (RRP)', self.handle_RRP - elif (cmd & 0xF0 == 0x80): - cmd_name, cmd_hnd = 'CMD: CHANNEL_CONFIG (CC)', self.handle_CC - - # Report command name. - self.put(self.cmd_samples['ss'], self.cmd_samples['es'], - self.out_ann, [Ann.CMD, [cmd_name]]) - - # Handle status byte. - self.handle_STAT() - - # Handle command. - if cmd_hnd is not None: - cmd_hnd() - - def set_cs_status(self, sample, asserted): - if self.cs_asserted == asserted: - return - - if asserted: - self.cmd_samples['ss'] = sample - self.cmd_samples['es'] = -1 - else: - self.cmd_samples['es'] = sample - - self.cs_asserted = asserted - - def decode(self, ss, es, data): - ptype, data1, data2 = data - - if ptype == 'CS-CHANGE': - if data1 is None and data2 is None: - self.requirements_met = False - raise ChannelError('CS# pin required.') - - if data1 is None and data2 == 0: - self.set_cs_status(ss, True) - - elif data1 is None and data2 == 1: - self.set_cs_status(ss, False) - - elif data1 == 1 and data2 == 0: - self.set_cs_status(ss, True) - - elif data1 == 0 and data2 == 1: - self.set_cs_status(ss, False) - if len(self.mosi_bytes): - self.process_cmd() - self.reset() - - elif ptype == 'DATA': - # Ignore traffic if CS is not asserted. - if self.cs_asserted is False: - return - - mosi, miso = data1, data2 - if miso is None or mosi is None: - raise ChannelError('Both MISO and MOSI pins required.') - - self.mosi_bytes.append((mosi, ss, es)) - self.miso_bytes.append((miso, ss, es)) diff --git a/decoders/numbers_and_state/__init__.py b/decoders/numbers_and_state/__init__.py deleted file mode 100644 index 4fe42a34..00000000 --- a/decoders/numbers_and_state/__init__.py +++ /dev/null @@ -1,41 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Comlab AG -## Copyright (C) 2020 Gerhard Sittig -## -## 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, see . -## - -''' -This protocol decoder takes a set of logic input signals, and interprets -their bit pattern according to user specifications as different kinds of -numbers, or an enumeration of e.g. machine states. - -Supported formats are: signed and unsigned integers, fixed point numbers, -IEEE754 floating point numbers, and number to text mapping controlled by -external data files. (Support for half precision floats depends on the -Python runtime, and may not universally be available.) - -User provided text mapping files can either use the JSON format: - {"one": 1, "two": 2, "four": 4} -or the Python programming language: - enumtext = { 1: "one", 2: "two", 3: "three", } - -In addition to all enum values on one row (sequential presentation of -the data), a limited number of enum values also are shown in tabular -presentation, which can help visualize state machines or task switches. -''' - -from .pd import Decoder diff --git a/decoders/numbers_and_state/pd.py b/decoders/numbers_and_state/pd.py deleted file mode 100644 index b8ac87e7..00000000 --- a/decoders/numbers_and_state/pd.py +++ /dev/null @@ -1,377 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Comlab AG -## Copyright (C) 2020 Gerhard Sittig -## -## 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, see . -## - -# This implementation started as a "vector slicer", then turned into the -# "numbers and states" decoder, because users always had the freedom to -# connect any logic signal to either of the decoder inputs. That's when -# slicing vectors took second seat, and just was not needed any longer -# in the strict sense. -# -# TODO -# - Find an appropriate number of input channels, and maximum enum slots. -# - Re-check correctness of signed integers. Signed fixed point is based -# on integers and transparently benefits from fixes and improvements. -# - Local formatting in individual decoders becomes obsolete when common -# support for user selected formatting gets introduced. -# - There is overlap with the 'parallel' decoder. Ideally the numbers -# decoder could stack on top of parallel, but parallel currently is -# severely limited in its number of input channels, and dramatically -# widening the parallel decoder may be undesirable. - -from common.srdhelper import bitpack -import json -import sigrokdecode as srd -import struct - -''' -OUTPUT_PYTHON format: - -Packet: -[, ] - -This is a list of s and their respective values: - - 'RAW': The data is a tuple of bit count and bit pattern (a number, - assuming unsigned integer presentation of the input data bit pattern). - - 'NUMBER': The data is the conversion result of the bit pattern. - - 'ENUM': The data is a tuple of the raw number and its mapped text. -''' - -# TODO Better raise the number of channels to 32. This allows access to -# IEEE754 single precision numbers, and shall cover most busses, _and_ -# remains within most logic analyzers' capabilities, and keeps the UI -# dialog somewhat managable. What's a good default for the number of -# enum slots (which translate to annotation rows)? Notice that 2 to the -# power of the channel count is way out of the question. :) -_max_channels = 16 -_max_enum_slots = 32 - -class ChannelError(Exception): - pass - -class Pin: - CLK, BIT_0 = range(2) - BIT_N = BIT_0 + _max_channels - -class Ann: - RAW, NUM = range(2) - ENUM_0 = NUM + 1 - ENUM_OVR = ENUM_0 + _max_enum_slots - ENUMS = range(ENUM_0, ENUM_OVR) - WARN = ENUM_OVR + 1 - - @staticmethod - def enum_indices(): - return [i for i in range(Ann.ENUMS)] - - @staticmethod - def get_enum_idx(code): - if code in range(_max_enum_slots): - return Ann.ENUM_0 + code - return Ann.ENUM_OVR - -def _channel_decl(count): - return tuple([ - {'id': 'bit{}'.format(i), 'name': 'Bit{}'.format(i), 'desc': 'Bit position {}'.format(i)} - for i in range(count) - ]) - -def _enum_cls_decl(count): - return tuple([ - ('enum{}'.format(i), 'Enumeration slot {}'.format(i)) - for i in range(count) - ] + [('enumovr', 'Enumeration overflow')]) - -def _enum_rows_decl(count): - return tuple([ - ('enums{}'.format(i), 'Enumeration slots {}'.format(i), (Ann.ENUM_0 + i,)) - for i in range(count) - ] + [('enumsovr', 'Enumeration overflows', (Ann.ENUM_OVR,))]) - -class Decoder(srd.Decoder): - api_version = 3 - id = 'numbers_and_state' - name = 'Numbers and State' - longname = 'Interpret bit patters as numbers or state enums' - desc = 'Interpret bit patterns as different kinds of numbers (integer, float, enum).' - license = 'gplv2+' - inputs = ['logic'] - outputs = ['numbers_and_state'] - tags = ['Encoding', 'Util'] - optional_channels = ( - {'id': 'clk', 'name': 'Clock', 'desc': 'Clock'}, - ) + _channel_decl(_max_channels) - options = ( - {'id': 'clkedge', 'desc': 'Clock edge', 'default': 'rising', - 'values': ('rising', 'falling', 'either')}, - {'id': 'count', 'desc': 'Total bits count', 'default': 0}, - {'id': 'interp', 'desc': 'Interpretation', 'default': 'unsigned', - 'values': ('unsigned', 'signed', 'fixpoint', 'fixsigned', 'ieee754', 'enum')}, - {'id': 'fracbits', 'desc': 'Fraction bits count', 'default': 0}, - {'id': 'mapping', 'desc': 'Enum to text map file', - 'default': 'enumtext.json'}, - {'id': 'format', 'desc': 'Number format', 'default': '-', - 'values': ('-', 'bin', 'oct', 'dec', 'hex')}, - ) - annotations = ( - ('raw', 'Raw pattern'), - ('number', 'Number'), - ) + _enum_cls_decl(_max_enum_slots) + ( - ('warning', 'Warning'), - ) - annotation_rows = ( - ('raws', 'Raw bits', (Ann.RAW,)), - ('numbers', 'Numbers', (Ann.NUM,)), - ) + _enum_rows_decl(_max_enum_slots) + ( - ('warnings', 'Warnings', (Ann.WARN,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - pass - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.out_python = self.register(srd.OUTPUT_PYTHON) - - def putg(self, ss, es, cls, data): - self.put(ss, es, self.out_ann, [cls, data]) - - def putpy(self, ss, es, ptype, pdata): - self.put(ss, es, self.out_python, (ptype, pdata)) - - def grab_pattern(self, pins): - '''Get a bit pattern from potentially incomplete probes' values.''' - - # Pad and trim the input data, to achieve the user specified - # total number of bits. Map all unassigned signals to 0 (low). - # Return raw number (unsigned integer interpreation). - bits = pins + (None,) * self.bitcount - bits = bits[:self.bitcount] - bits = [b if b in (0, 1) else 0 for b in bits] - pattern = bitpack(bits) - return pattern - - def handle_pattern(self, ss, es, pattern): - fmt = '{{:0{}b}}'.format(self.bitcount) - txt = fmt.format(pattern) - self.putg(ss, es, Ann.RAW, [txt]) - self.putpy(ss, es, 'RAW', (self.bitcount, pattern)) - - try: - value = self.interpreter(ss, es, pattern) - except: - value = None - if value is None: - return - self.putpy(ss, es, 'NUMBER', value) - try: - formatted = self.formatter(ss, es, value) - except: - formatted = None - if formatted: - self.putg(ss, es, Ann.NUM, formatted) - if self.interpreter == self.interp_enum: - cls = Ann.get_enum_idx(pattern) - self.putg(ss, es, cls, formatted) - self.putpy(ss, es, 'ENUM', (value, formatted)) - - def interp_unsigned(self, ss, es, pattern): - value = pattern - return value - - def interp_signed(self, ss, es, pattern): - if not 'signmask' in self.interp_state: - self.interp_state.update({ - 'signmask': 1 << (self.bitcount - 1), - 'signfull': 1 << self.bitcount, - }) - is_neg = pattern & self.interp_state['signmask'] - if is_neg: - value = -(self.interp_state['signfull'] - pattern) - else: - value = pattern - return value - - def interp_fixpoint(self, ss, es, pattern): - if not 'fixdiv' in self.interp_state: - self.interp_state.update({ - 'fixsign': self.options['interp'] == 'fixsigned', - 'fixdiv': 2 ** self.options['fracbits'], - }) - if self.interp_state['fixsign']: - value = self.interp_signed(ss, es, pattern) - else: - value = self.interp_unsigned(ss, es, pattern) - value /= self.interp_state['fixdiv'] - return value - - def interp_ieee754(self, ss, es, pattern): - if not 'ieee_has_16bit' in self.interp_state: - self.interp_state.update({ - 'ieee_fmt_int_16': '=H', - 'ieee_fmt_flt_16': '=e', - 'ieee_fmt_int_32': '=L', - 'ieee_fmt_flt_32': '=f', - 'ieee_fmt_int_64': '=Q', - 'ieee_fmt_flt_64': '=d', - }) - try: - fmt = self.interp_state.update['ieee_fmt_flt_16'] - has_16bit_support = 8 * struct.calcsize(fmt) == 16 - except: - has_16bit_support = False - self.interp_state['ieee_has_16bit'] = has_16bit_support - if self.bitcount == 16: - if not self.interp_state['ieee_has_16bit']: - return None - buff = struct.pack(self.interp_state['ieee_fmt_int_16'], pattern) - value, = struct.unpack(self.interp_state['ieee_fmt_flt_16'], buff) - return value - if self.bitcount == 32: - buff = struct.pack(self.interp_state['ieee_fmt_int_32'], pattern) - value, = struct.unpack(self.interp_state['ieee_fmt_flt_32'], buff) - return value - if self.bitcount == 64: - buff = struct.pack(self.interp_state['ieee_fmt_int_64'], pattern) - value, = struct.unpack(self.interp_state['ieee_fmt_flt_64'], buff) - return value - return None - - def interp_enum(self, ss, es, pattern): - if not 'enum_map' in self.interp_state: - self.interp_state.update({ - 'enum_fn': self.options['mapping'], - 'enum_map': {}, - 'enum_have_map': False, - }) - try: - fn = self.interp_state['enum_fn'] - # TODO Optionally try in several locations? Next to the - # decoder implementation? Where else? Expect users to - # enter absolute paths? - with open(fn, 'r') as f: - maptext = f.read() - maptable = {} - if fn.endswith('.js') or fn.endswith('.json'): - # JSON requires string literals on the LHS, so the - # table is written "in reverse order". - js_table = json.loads(maptext) - for k, v in js_table.items(): - maptable[v] = k - elif fn.endswith('.py'): - # Expect a specific identifier at the Python module - # level, and assume that it's a dictionary. - py_table = {} - exec(maptext, py_table) - maptable.update(py_table['enumtext']) - self.interp_state['enum_map'].update(maptable) - self.interp_state['enum_have_map'] = True - except: - # Silently ignore failure. This happens while the user - # is typing the filename, and is non-fatal. If the file - # exists and is not readable or not valid or of unknown - # format, the worst thing that can happen is that the - # decoder implementation keeps using "anonymous" phrases - # until a mapping has become available. No harm is done. - # This decoder cannot tell intermediate from final file - # read attempts, so we cannot raise severity here. - pass - value = self.interp_state['enum_map'].get(pattern, None) - if value is None: - value = pattern - return value - - def format_native(self, ss, es, value): - return ['{}'.format(value),] - - def format_bin(self, ss, es, value): - if not self.format_string: - self.format_string = '{{:0{}b}}'.format(self.bitcount) - return [self.format_string.format(value)] - - def format_oct(self, ss, es, value): - if not self.format_string: - self.format_string = '{{:0{}o}}'.format((self.bitcount + 3 - 1) // 3) - return [self.format_string.format(value)] - - def format_dec(self, ss, es, value): - if not self.format_string: - self.format_string = '{:d}' - return [self.format_string.format(value)] - - def format_hex(self, ss, es, value): - if not self.format_string: - self.format_string = '{{:0{}x}}'.format((self.bitcount + 4 - 1) // 4) - return [self.format_string.format(value)] - - def decode(self): - channels = [ch for ch in range(_max_channels) if self.has_channel(ch)] - have_clk = Pin.CLK in channels - if have_clk: - channels.remove(Pin.CLK) - if not channels: - raise ChannelError("Need at least one bit channel.") - if have_clk: - clkedge = { - 'rising': 'r', - 'falling': 'f', - 'either': 'e', - }.get(self.options['clkedge']) - wait_cond = {Pin.CLK: clkedge} - else: - wait_cond = [{ch: 'e'} for ch in channels] - - bitcount = self.options['count'] - if not bitcount: - bitcount = channels[-1] - Pin.BIT_0 + 1 - self.bitcount = bitcount - - self.interpreter = { - 'unsigned': self.interp_unsigned, - 'signed': self.interp_signed, - 'fixpoint': self.interp_fixpoint, - 'fixsigned': self.interp_fixpoint, - 'ieee754': self.interp_ieee754, - 'enum': self.interp_enum, - }.get(self.options['interp']) - self.interp_state = {} - self.formatter = { - '-': self.format_native, - 'bin': self.format_bin, - 'oct': self.format_oct, - 'dec': self.format_dec, - 'hex': self.format_hex, - }.get(self.options['format']) - self.format_string = None - - pins = self.wait() - ss = self.samplenum - prev_pattern = self.grab_pattern(pins[Pin.BIT_0:]) - while True: - pins = self.wait(wait_cond) - es = self.samplenum - pattern = self.grab_pattern(pins[Pin.BIT_0:]) - if pattern == prev_pattern: - continue - self.handle_pattern(ss, es, prev_pattern) - ss = es - prev_pattern = pattern diff --git a/decoders/nunchuk/__init__.py b/decoders/nunchuk/__init__.py deleted file mode 100755 index a6092c45..00000000 --- a/decoders/nunchuk/__init__.py +++ /dev/null @@ -1,30 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -''' -This decoder stacks on top of the 'i2c' PD and decodes the Nintendo Wii -Nunchuk controller protocol. - -Details: -http://wiibrew.org/wiki/Wiimote/Extension_Controllers/Nunchuck -http://todbot.com/blog/2008/02/18/wiichuck-wii-nunchuck-adapter-available/ -https://www.sparkfun.com/products/9281 -''' - -from .pd import Decoder diff --git a/decoders/nunchuk/pd.py b/decoders/nunchuk/pd.py deleted file mode 100755 index 59b10289..00000000 --- a/decoders/nunchuk/pd.py +++ /dev/null @@ -1,207 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2010-2014 Uwe Hermann -## -## 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, see . -## - -import sigrokdecode as srd - -class Decoder(srd.Decoder): - api_version = 3 - id = 'nunchuk' - name = 'Nunchuk' - longname = 'Nintendo Wii Nunchuk' - desc = 'Nintendo Wii Nunchuk controller protocol.' - license = 'gplv2+' - inputs = ['i2c'] - outputs = [] - tags = ['Sensor'] - annotations = \ - tuple(('reg-0x%02X' % i, 'Register 0x%02X' % i) for i in range(6)) + ( - ('bit-bz', 'BZ bit'), - ('bit-bc', 'BC bit'), - ('bit-ax', 'AX bits'), - ('bit-ay', 'AY bits'), - ('bit-az', 'AZ bits'), - ('nunchuk-write', 'Nunchuk write'), - ('cmd-init', 'Init command'), - ('summary', 'Summary'), - ('warnings', 'Warnings'), - ) - annotation_rows = ( - ('regs', 'Registers', tuple(range(13))), - ('summary', 'Summary', (13,)), - ('warnings', 'Warnings', (14,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.state = 'IDLE' - self.sx = self.sy = self.ax = self.ay = self.az = self.bz = self.bc = -1 - self.databytecount = 0 - self.reg = 0x00 - self.ss = self.es = self.ss_block = self.es_block = 0 - self.init_seq = [] - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putx(self, data): - self.put(self.ss, self.es, self.out_ann, data) - - def putb(self, data): - self.put(self.ss_block, self.es_block, self.out_ann, data) - - def putd(self, bit1, bit2, data): - self.put(self.bits[bit1][1], self.bits[bit2][2], self.out_ann, data) - - def handle_reg_0x00(self, databyte): - self.ss_block = self.ss - self.sx = databyte - self.putx([0, ['Analog stick X position: 0x%02X' % self.sx, - 'SX: 0x%02X' % self.sx]]) - - def handle_reg_0x01(self, databyte): - self.sy = databyte - self.putx([1, ['Analog stick Y position: 0x%02X' % self.sy, - 'SY: 0x%02X' % self.sy]]) - - def handle_reg_0x02(self, databyte): - self.ax = databyte << 2 - self.putx([2, ['Accelerometer X value bits[9:2]: 0x%03X' % self.ax, - 'AX[9:2]: 0x%03X' % self.ax]]) - - def handle_reg_0x03(self, databyte): - self.ay = databyte << 2 - self.putx([3, ['Accelerometer Y value bits[9:2]: 0x%03X' % self.ay, - 'AY[9:2]: 0x%03X' % self.ay]]) - - def handle_reg_0x04(self, databyte): - self.az = databyte << 2 - self.putx([4, ['Accelerometer Z value bits[9:2]: 0x%03X' % self.az, - 'AZ[9:2]: 0x%03X' % self.az]]) - - def handle_reg_0x05(self, databyte): - self.es_block = self.es - self.bz = (databyte & (1 << 0)) >> 0 # Bits[0:0] - self.bc = (databyte & (1 << 1)) >> 1 # Bits[1:1] - ax_rest = (databyte & (3 << 2)) >> 2 # Bits[3:2] - ay_rest = (databyte & (3 << 4)) >> 4 # Bits[5:4] - az_rest = (databyte & (3 << 6)) >> 6 # Bits[7:6] - self.ax |= ax_rest - self.ay |= ay_rest - self.az |= az_rest - - # self.putx([5, ['Register 5', 'Reg 5', 'R5']]) - - s = '' if (self.bz == 0) else 'not ' - self.putd(0, 0, [6, ['Z: %spressed' % s, 'BZ: %d' % self.bz]]) - - s = '' if (self.bc == 0) else 'not ' - self.putd(1, 1, [7, ['C: %spressed' % s, 'BC: %d' % self.bc]]) - - self.putd(3, 2, [8, ['Accelerometer X value bits[1:0]: 0x%X' % ax_rest, - 'AX[1:0]: 0x%X' % ax_rest]]) - - self.putd(5, 4, [9, ['Accelerometer Y value bits[1:0]: 0x%X' % ay_rest, - 'AY[1:0]: 0x%X' % ay_rest]]) - - self.putd(7, 6, [10, ['Accelerometer Z value bits[1:0]: 0x%X' % az_rest, - 'AZ[1:0]: 0x%X' % az_rest]]) - - self.reg = 0x00 - - def output_full_block_if_possible(self): - # For now, only output summary annotations if all values are available. - t = (self.sx, self.sy, self.ax, self.ay, self.az, self.bz, self.bc) - if -1 in t: - return - bz = 'pressed' if self.bz == 0 else 'not pressed' - bc = 'pressed' if self.bc == 0 else 'not pressed' - s = 'Analog stick: %d/%d, accelerometer: %d/%d/%d, Z: %s, C: %s' % \ - (self.sx, self.sy, self.ax, self.ay, self.az, bz, bc) - self.putb([13, [s]]) - - def handle_reg_write(self, databyte): - self.putx([11, ['Nunchuk write: 0x%02X' % databyte]]) - if len(self.init_seq) < 2: - self.init_seq.append(databyte) - - def output_init_seq(self): - if len(self.init_seq) != 2: - self.putb([14, ['Init sequence was %d bytes long (2 expected)' % \ - len(self.init_seq)]]) - return - - if self.init_seq != [0x40, 0x00]: - self.putb([14, ['Unknown init sequence (expected: 0x40 0x00)']]) - return - - # TODO: Detect Nunchuk clones (they have different init sequences). - - self.putb([12, ['Initialize Nunchuk', 'Init Nunchuk', 'Init', 'I']]) - - def decode(self, ss, es, data): - cmd, databyte = data - - # Collect the 'BITS' packet, then return. The next packet is - # guaranteed to belong to these bits we just stored. - if cmd == 'BITS': - self.bits = databyte - return - - self.ss, self.es = ss, es - - # State machine. - if self.state == 'IDLE': - # Wait for an I²C START condition. - if cmd != 'START': - return - self.state = 'GET SLAVE ADDR' - self.ss_block = ss - elif self.state == 'GET SLAVE ADDR': - # Wait for an address read/write operation. - if cmd == 'ADDRESS READ': - self.state = 'READ REGS' - elif cmd == 'ADDRESS WRITE': - self.state = 'WRITE REGS' - elif self.state == 'READ REGS': - if cmd == 'DATA READ': - handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg) - handle_reg(databyte) - self.reg += 1 - elif cmd == 'STOP': - self.es_block = es - self.output_full_block_if_possible() - self.sx = self.sy = self.ax = self.ay = self.az = -1 - self.bz = self.bc = -1 - self.state = 'IDLE' - else: - # self.putx([14, ['Ignoring: %s (data=%s)' % (cmd, databyte)]]) - pass - elif self.state == 'WRITE REGS': - if cmd == 'DATA WRITE': - self.handle_reg_write(databyte) - elif cmd == 'STOP': - self.es_block = es - self.output_init_seq() - self.init_seq = [] - self.state = 'IDLE' - else: - # self.putx([14, ['Ignoring: %s (data=%s)' % (cmd, databyte)]]) - pass diff --git a/decoders/onewire_link/__init__.py b/decoders/onewire_link/__init__.py deleted file mode 100755 index abd55671..00000000 --- a/decoders/onewire_link/__init__.py +++ /dev/null @@ -1,56 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## Copyright (C) 2017 Kevin Redon -## -## 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, see . -## - -''' -This protocol decoder handles the 1-Wire link layer. - -The 1-Wire protocol enables bidirectional communication over a single wire -(and ground) between a single master and one or multiple slaves. The protocol -is layered: - - - Link layer (reset, presence detection, reading/writing bits) - - Network layer (skip/search/match device ROM addresses) - - Transport layer (transport data between 1-Wire master and device) - -Sample rate: -A sufficiently high samplerate is required to properly detect all the elements -of the protocol. A lower samplerate can be used if the master does not use -overdrive communication speed. The following minimal values should be used: - - - overdrive available: 2MHz minimum, 5MHz suggested - - overdrive not available: 400kHz minimum, 1MHz suggested - -Channels: -1-Wire requires a single signal, but some master implementations might have a -separate signal used to deliver power to the bus during temperature conversion -as an example. - - - owr (1-Wire signal line) - -Options: -1-Wire is an asynchronous protocol with fixed timing values, so the decoder -must know the samplerate. -Two speeds are available: normal and overdrive. The decoder detects when -switching speed, but the user can set which to start decoding with: - - - overdrive (to decode starting with overdrive speed) -''' - -from .pd import Decoder diff --git a/decoders/onewire_link/pd.py b/decoders/onewire_link/pd.py deleted file mode 100755 index 6592279e..00000000 --- a/decoders/onewire_link/pd.py +++ /dev/null @@ -1,347 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2017 Kevin Redon -## -## 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, see . -## - -import sigrokdecode as srd - -class SamplerateError(Exception): - pass - -# Timing values in us for the signal at regular and overdrive speed. -timing = { - 'RSTL': { - 'min': { - False: 480.0, - True: 48.0, - }, - 'max': { - False: 960.0, - True: 80.0, - }, - }, - 'RSTH': { - 'min': { - False: 480.0, - True: 48.0, - }, - }, - 'PDH': { - 'min': { - False: 15.0, - True: 2.0, - }, - 'max': { - False: 60.0, - True: 6.0, - }, - }, - 'PDL': { - 'min': { - False: 60.0, - True: 8.0, - }, - 'max': { - False: 240.0, - True: 24.0, - }, - }, - 'SLOT': { - 'min': { - False: 60.0, - True: 6.0, - }, - 'max': { - False: 120.0, - True: 16.0, - }, - }, - 'REC': { - 'min': { - False: 1.0, - True: 1.0, - }, - }, - 'LOWR': { - 'min': { - False: 1.0, - True: 1.0, - }, - 'max': { - False: 15.0, - True: 2.0, - }, - }, -} - -class Decoder(srd.Decoder): - api_version = 3 - id = 'onewire_link' - name = 'OneWire link layer' - longname = '1-Wire serial communication bus (link layer)' - desc = 'Bidirectional, half-duplex, asynchronous serial bus.' - license = 'gplv2+' - inputs = ['logic'] - outputs = ['onewire_link'] - tags = ['Embedded/industrial'] - channels = ( - {'id': 'owr', 'name': 'OWR', 'desc': '1-Wire signal line'}, - ) - options = ( - {'id': 'overdrive', 'desc': 'Start in overdrive speed', - 'default': 'no', 'values': ('yes', 'no')}, - ) - annotations = ( - ('bit', 'Bit'), - ('warnings', 'Warnings'), - ('reset', 'Reset'), - ('presence', 'Presence'), - ('overdrive', 'Overdrive speed notifications'), - ) - annotation_rows = ( - ('bits', 'Bits', (0, 2, 3)), - ('info', 'Info', (4,)), - ('warnings', 'Warnings', (1,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.state = 'INITIAL' - self.present = 0 - self.bit = 0 - self.bit_count = -1 - self.command = 0 - self.overdrive = False - self.fall = 0 - self.rise = 0 - - def start(self): - self.out_python = self.register(srd.OUTPUT_PYTHON) - self.out_ann = self.register(srd.OUTPUT_ANN) - self.overdrive = (self.options['overdrive'] == 'yes') - self.fall = 0 - self.rise = 0 - self.bit_count = -1 - - def putm(self, data): - self.put(0, 0, self.out_ann, data) - - def putpfs(self, data): - self.put(self.fall, self.samplenum, self.out_python, data) - - def putfs(self, data): - self.put(self.fall, self.samplenum, self.out_ann, data) - - def putfr(self, data): - self.put(self.fall, self.rise, self.out_ann, data) - - def putprs(self, data): - self.put(self.rise, self.samplenum, self.out_python, data) - - def putrs(self, data): - self.put(self.rise, self.samplenum, self.out_ann, data) - - def checks(self): - # Check if samplerate is appropriate. - if self.options['overdrive'] == 'yes': - if self.samplerate < 2000000: - self.putm([1, ['Sampling rate is too low. Must be above ' + - '2MHz for proper overdrive mode decoding.']]) - elif self.samplerate < 5000000: - self.putm([1, ['Sampling rate is suggested to be above 5MHz ' + - 'for proper overdrive mode decoding.']]) - else: - if self.samplerate < 400000: - self.putm([1, ['Sampling rate is too low. Must be above ' + - '400kHz for proper normal mode decoding.']]) - elif self.samplerate < 1000000: - self.putm([1, ['Sampling rate is suggested to be above ' + - '1MHz for proper normal mode decoding.']]) - - def metadata(self, key, value): - if key != srd.SRD_CONF_SAMPLERATE: - return - self.samplerate = value - - def wait_falling_timeout(self, start, t): - # Wait until either a falling edge is seen, and/or the specified - # number of samples have been skipped (i.e. time has passed). - cnt = int((t[self.overdrive] / 1000000.0) * self.samplerate) - samples_to_skip = (start + cnt) - self.samplenum - samples_to_skip = samples_to_skip if (samples_to_skip > 0) else 0 - return self.wait([{0: 'f'}, {'skip': samples_to_skip}]) - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - self.checks() - while True: - # State machine. - if self.state == 'INITIAL': # Unknown initial state. - # Wait until we reach the idle high state. - self.wait({0: 'h'}) - self.rise = self.samplenum - self.state = 'IDLE' - elif self.state == 'IDLE': # Idle high state. - # Wait for falling edge. - self.wait({0: 'f'}) - self.fall = self.samplenum - # Get time since last rising edge. - time = ((self.fall - self.rise) / self.samplerate) * 1000000.0 - if self.rise > 0 and \ - time < timing['REC']['min'][self.overdrive]: - self.putfr([1, ['Recovery time not long enough' - 'Recovery too short', - 'REC < ' + str(timing['REC']['min'][self.overdrive])]]) - # A reset pulse or slot can start on a falling edge. - self.state = 'LOW' - # TODO: Check minimum recovery time. - elif self.state == 'LOW': # Reset pulse or slot. - # Wait for rising edge. - self.wait({0: 'r'}) - self.rise = self.samplenum - # Detect reset or slot base on timing. - time = ((self.rise - self.fall) / self.samplerate) * 1000000.0 - if time >= timing['RSTL']['min'][False]: # Normal reset pulse. - if time > timing['RSTL']['max'][False]: - self.putfr([1, ['Too long reset pulse might mask interrupt ' + - 'signalling by other devices', - 'Reset pulse too long', - 'RST > ' + str(timing['RSTL']['max'][False])]]) - # Regular reset pulse clears overdrive speed. - if self.overdrive: - self.putfr([4, ['Exiting overdrive mode', 'Overdrive off']]) - self.overdrive = False - self.putfr([2, ['Reset', 'Rst', 'R']]) - self.state = 'PRESENCE DETECT HIGH' - elif self.overdrive == True and \ - time >= timing['RSTL']['min'][self.overdrive] and \ - time < timing['RSTL']['max'][self.overdrive]: - # Overdrive reset pulse. - self.putfr([2, ['Reset', 'Rst', 'R']]) - self.state = 'PRESENCE DETECT HIGH' - elif time < timing['SLOT']['max'][self.overdrive]: - # Read/write time slot. - if time < timing['LOWR']['min'][self.overdrive]: - self.putfr([1, ['Low signal not long enough', - 'Low too short', - 'LOW < ' + str(timing['LOWR']['min'][self.overdrive])]]) - if time < timing['LOWR']['max'][self.overdrive]: - self.bit = 1 # Short pulse is a 1 bit. - else: - self.bit = 0 # Long pulse is a 0 bit. - # Wait for end of slot. - self.state = 'SLOT' - else: - # Timing outside of known states. - self.putfr([1, ['Erroneous signal', 'Error', 'Err', 'E']]) - self.state = 'IDLE' - elif self.state == 'PRESENCE DETECT HIGH': # Wait for slave presence signal. - # Wait for a falling edge and/or presence detect signal. - self.wait_falling_timeout(self.rise, timing['PDH']['max']) - - # Calculate time since rising edge. - time = ((self.samplenum - self.rise) / self.samplerate) * 1000000.0 - - if (self.matched & (0b1 << 0)) and not (self.matched & (0b1 << 1)): - # Presence detected. - if time < timing['PDH']['min'][self.overdrive]: - self.putrs([1, ['Presence detect signal is too early', - 'Presence detect too early', - 'PDH < ' + str(timing['PDH']['min'][self.overdrive])]]) - self.fall = self.samplenum - self.state = 'PRESENCE DETECT LOW' - else: # No presence detected. - self.putrs([3, ['Presence: false', 'Presence', 'Pres', 'P']]) - self.putprs(['RESET/PRESENCE', False]) - self.state = 'IDLE' - elif self.state == 'PRESENCE DETECT LOW': # Slave presence signalled. - # Wait for end of presence signal (on rising edge). - self.wait({0: 'r'}) - # Calculate time since start of presence signal. - time = ((self.samplenum - self.fall) / self.samplerate) * 1000000.0 - if time < timing['PDL']['min'][self.overdrive]: - self.putfs([1, ['Presence detect signal is too short', - 'Presence detect too short', - 'PDL < ' + str(timing['PDL']['min'][self.overdrive])]]) - elif time > timing['PDL']['max'][self.overdrive]: - self.putfs([1, ['Presence detect signal is too long', - 'Presence detect too long', - 'PDL > ' + str(timing['PDL']['max'][self.overdrive])]]) - if time > timing['RSTH']['min'][self.overdrive]: - self.rise = self.samplenum - # Wait for end of presence detect. - self.state = 'PRESENCE DETECT' - - # End states (for additional checks). - if self.state == 'SLOT': # Wait for end of time slot. - # Wait for a falling edge and/or end of timeslot. - self.wait_falling_timeout(self.fall, timing['SLOT']['min']) - - if (self.matched & (0b1 << 0)) and not (self.matched & (0b1 << 1)): - # Low detected before end of slot. - self.putfs([1, ['Time slot not long enough', - 'Slot too short', - 'SLOT < ' + str(timing['SLOT']['min'][self.overdrive])]]) - # Don't output invalid bit. - self.fall = self.samplenum - self.state = 'LOW' - else: # End of time slot. - # Output bit. - self.putfs([0, ['Bit: %d' % self.bit, '%d' % self.bit]]) - self.putpfs(['BIT', self.bit]) - # Save command bits. - if self.bit_count >= 0: - self.command += (self.bit << self.bit_count) - self.bit_count += 1 - # Check for overdrive ROM command. - if self.bit_count >= 8: - if self.command == 0x3c or self.command == 0x69: - self.overdrive = True - self.put(self.samplenum, self.samplenum, - self.out_ann, - [4, ['Entering overdrive mode', 'Overdrive on']]) - self.bit_count = -1 - self.state = 'IDLE' - - if self.state == 'PRESENCE DETECT': - # Wait for a falling edge and/or end of presence detect. - self.wait_falling_timeout(self.rise, timing['RSTH']['min']) - - if (self.matched & (0b1 << 0)) and not (self.matched & (0b1 << 1)): - # Low detected before end of presence detect. - self.putfs([1, ['Presence detect not long enough', - 'Presence detect too short', - 'RTSH < ' + str(timing['RSTH']['min'][self.overdrive])]]) - # Inform about presence detected. - self.putrs([3, ['Slave presence detected', 'Slave present', - 'Present', 'P']]) - self.putprs(['RESET/PRESENCE', True]) - self.fall = self.samplenum - self.state = 'LOW' - else: # End of time slot. - # Inform about presence detected. - self.putrs([3, ['Presence: true', 'Presence', 'Pres', 'P']]) - self.putprs(['RESET/PRESENCE', True]) - self.rise = self.samplenum - # Start counting the first 8 bits to get the ROM command. - self.bit_count = 0 - self.command = 0 - self.state = 'IDLE' diff --git a/decoders/onewire_network/__init__.py b/decoders/onewire_network/__init__.py deleted file mode 100755 index 60907efa..00000000 --- a/decoders/onewire_network/__init__.py +++ /dev/null @@ -1,56 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -''' -This decoder stacks on top of the 'onewire_link' PD and decodes the -1-Wire protocol (network layer). - -The 1-Wire protocol enables bidirectional communication over a single wire -(and ground) between a single master and one or multiple slaves. The protocol -is layered: - - - Link layer (reset, presence detection, reading/writing bits) - - Network layer (skip/search/match device ROM addresses) - - Transport layer (transport data between 1-Wire master and device) - -Network layer: - -The following link layer annotations are shown: - - - RESET/PRESENCE True/False - The event is marked from the signal negative edge to the end of the reset - high period. It is also reported if there are any devices attached to the - bus. - -The following network layer annotations are shown: - - - ROM command - The requested ROM command is displayed as an 8bit hex value and by name. - - ROM - The 64bit value of the addressed device is displayed: - Family code (1 byte) + serial number (6 bytes) + CRC (1 byte) - - Data - Data intended for the transport layer is displayed as an 8bit hex value. - -TODO: - - Add CRC checks, to see if there were communication errors on the wire. - - Add reporting original/complement address values from the search algorithm. -''' - -from .pd import Decoder diff --git a/decoders/onewire_network/pd.py b/decoders/onewire_network/pd.py deleted file mode 100755 index ef302aea..00000000 --- a/decoders/onewire_network/pd.py +++ /dev/null @@ -1,185 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Iztok Jeras -## -## 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, see . -## - -import sigrokdecode as srd - -# Dictionary of ROM commands and their names, next state. -command = { - 0x33: ['Read ROM' , 'GET ROM' ], - 0x0f: ['Conditional read ROM' , 'GET ROM' ], - 0xcc: ['Skip ROM' , 'TRANSPORT' ], - 0x55: ['Match ROM' , 'GET ROM' ], - 0xf0: ['Search ROM' , 'SEARCH ROM'], - 0xec: ['Conditional search ROM' , 'SEARCH ROM'], - 0x3c: ['Overdrive skip ROM' , 'TRANSPORT' ], - 0x69: ['Overdrive match ROM' , 'GET ROM' ], - 0xa5: ['Resume' , 'TRANSPORT' ], - 0x96: ['DS2408: Disable Test Mode' , 'GET ROM' ], -} - -class Decoder(srd.Decoder): - api_version = 3 - id = 'onewire_network' - name = '1-Wire network layer' - longname = '1-Wire serial communication bus (network layer)' - desc = 'Bidirectional, half-duplex, asynchronous serial bus.' - license = 'gplv2+' - inputs = ['onewire_link'] - outputs = ['onewire_network'] - tags = ['Embedded/industrial'] - annotations = ( - ('text', 'Human-readable text'), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.ss_block = 0 - self.es_block = 0 - self.state = 'COMMAND' - self.bit_cnt = 0 - self.search = 'P' - self.data_p = 0x0 - self.data_n = 0x0 - self.data = 0x0 - self.rom = 0x0000000000000000 - - def start(self): - self.out_python = self.register(srd.OUTPUT_PYTHON) - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putx(self, data): - # Helper function for most annotations. - self.put(self.ss_block, self.es_block, self.out_ann, data) - - def puty(self, data): - # Helper function for most protocol packets. - self.put(self.ss_block, self.es_block, self.out_python, data) - - def decode(self, ss, es, data): - code, val = data - - # State machine. - if code == 'RESET/PRESENCE': - self.search = 'P' - self.bit_cnt = 0 - self.put(ss, es, self.out_ann, - [0, ['Reset/presence: %s' % ('true' if val else 'false')]]) - self.put(ss, es, self.out_python, ['RESET/PRESENCE', val]) - self.state = 'COMMAND' - return - - # For now we're only interested in 'RESET/PRESENCE' and 'BIT' packets. - if code != 'BIT': - return - - if self.state == 'COMMAND': - # Receiving and decoding a ROM command. - if self.onewire_collect(8, val, ss, es) == 0: - return - if self.data in command: - self.putx([0, ['ROM command: 0x%02x \'%s\'' - % (self.data, command[self.data][0])]]) - self.state = command[self.data][1] - else: - self.putx([0, ['ROM command: 0x%02x \'%s\'' - % (self.data, 'unrecognized')]]) - self.state = 'COMMAND ERROR' - elif self.state == 'GET ROM': - # A 64 bit device address is selected. - # Family code (1 byte) + serial number (6 bytes) + CRC (1 byte) - if self.onewire_collect(64, val, ss, es) == 0: - return - self.rom = self.data & 0xffffffffffffffff - self.putx([0, ['ROM: 0x%016x' % self.rom]]) - self.puty(['ROM', self.rom]) - self.state = 'TRANSPORT' - elif self.state == 'SEARCH ROM': - # A 64 bit device address is searched for. - # Family code (1 byte) + serial number (6 bytes) + CRC (1 byte) - if self.onewire_search(64, val, ss, es) == 0: - return - self.rom = self.data & 0xffffffffffffffff - self.putx([0, ['ROM: 0x%016x' % self.rom]]) - self.puty(['ROM', self.rom]) - self.state = 'TRANSPORT' - elif self.state == 'TRANSPORT': - # The transport layer is handled in byte sized units. - if self.onewire_collect(8, val, ss, es) == 0: - return - self.putx([0, ['Data: 0x%02x' % self.data]]) - self.puty(['DATA', self.data]) - elif self.state == 'COMMAND ERROR': - # Since the command is not recognized, print raw data. - if self.onewire_collect(8, val, ss, es) == 0: - return - self.putx([0, ['ROM error data: 0x%02x' % self.data]]) - - # Data collector. - def onewire_collect(self, length, val, ss, es): - # Storing the sample this sequence begins with. - if self.bit_cnt == 0: - self.ss_block = ss - self.data = self.data & ~(1 << self.bit_cnt) | (val << self.bit_cnt) - self.bit_cnt += 1 - # Storing the sample this sequence ends with. - # In case the full length of the sequence is received, return 1. - if self.bit_cnt == length: - self.es_block = es - self.data = self.data & ((1 << length) - 1) - self.bit_cnt = 0 - return 1 - else: - return 0 - - # Search collector. - def onewire_search(self, length, val, ss, es): - # Storing the sample this sequence begins with. - if (self.bit_cnt == 0) and (self.search == 'P'): - self.ss_block = ss - - if self.search == 'P': - # Master receives an original address bit. - self.data_p = self.data_p & ~(1 << self.bit_cnt) | \ - (val << self.bit_cnt) - self.search = 'N' - elif self.search == 'N': - # Master receives a complemented address bit. - self.data_n = self.data_n & ~(1 << self.bit_cnt) | \ - (val << self.bit_cnt) - self.search = 'D' - elif self.search == 'D': - # Master transmits an address bit. - self.data = self.data & ~(1 << self.bit_cnt) | (val << self.bit_cnt) - self.search = 'P' - self.bit_cnt += 1 - - # Storing the sample this sequence ends with. - # In case the full length of the sequence is received, return 1. - if self.bit_cnt == length: - self.es_block = es - self.data_p = self.data_p & ((1 << length) - 1) - self.data_n = self.data_n & ((1 << length) - 1) - self.data = self.data & ((1 << length) - 1) - self.search = 'P' - self.bit_cnt = 0 - return 1 - else: - return 0 diff --git a/decoders/ook/__init__.py b/decoders/ook/__init__.py deleted file mode 100755 index 24e493bb..00000000 --- a/decoders/ook/__init__.py +++ /dev/null @@ -1,36 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Steve R -## -## 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, see . -## - -''' -OOK decodes On-off keying based remote control protocols. - -It is aimed at 433MHz but should also work with other common RC frequencies. -The input can be captured directly from a transmitter (before the modulation -stage) or demodulated by an RF receiver. - -Over the air captured traces will be a lot noisier and will probably need the -area of interest to be zoomed onto, then selected with the "Cursors" and the -"Save Selected Range As" feature to be used to extract it from the noise. - -There is a limited amount of pre-filtering and garbage removal built into the -decoder which can sometimes extract signals directly from a larger over the air -trace. It depends heavily on your environment. -''' - -from .pd import Decoder diff --git a/decoders/ook/pd.py b/decoders/ook/pd.py deleted file mode 100755 index 559291c4..00000000 --- a/decoders/ook/pd.py +++ /dev/null @@ -1,484 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Steve R -## -## 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, see . -## - -import sigrokdecode as srd - -''' -OUTPUT_PYTHON format: -Samples: The Samples array is sent when a DECODE_TIMEOUT occurs. -[, , ] - is the sample number of the start of the decoded bit. This may not line -up with the pulses that were converted into the decoded bit particularly for -Manchester encoding. - is the sample number of the end of the decoded bit. - is a single character string which is the state of the decoded bit. -This can be -'0' zero or low -'1' one or high -'E' Error or invalid. This can be caused by missing transitions or the wrong -pulse lengths according to the rules for the particular encoding. In some cases -this is intentional (Oregon 1 preamble) and is part of the sync pattern. In -other cases the signal could simply be broken. - -If there are more than self.max_errors (default 5) in decoding then the -OUTPUT_PYTHON is not sent as the data is assumed to be worthless. -There also needs to be a low for five times the preamble period at the end of -each set of pulses to trigger a DECODE_TIMEOUT and get the OUTPUT_PYTHON sent. -''' - -class SamplerateError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = 'ook' - name = 'OOK' - longname = 'On-off keying' - desc = 'On-off keying protocol.' - license = 'gplv2+' - inputs = ['logic'] - outputs = ['ook'] - tags = ['Encoding'] - channels = ( - {'id': 'data', 'name': 'Data', 'desc': 'Data line'}, - ) - annotations = ( - ('frame', 'Frame'), - ('info', 'Info'), - ('1111', '1111'), - ('1010', '1010'), - ('diffman', 'Diff Man'), - ('nrz', 'NRZ'), - ) - annotation_rows = ( - ('frame', 'Framing',(0,)), - ('info', 'Info', (1,)), - ('man1111', 'Man 1111', (2,)), - ('man1010', 'Man 1010', (3,)), - ('diffman', 'Diff Man', (4,)), - ('nrz', 'NRZ', (5,)), - ) - binary = ( - ('pulse-lengths', 'Pulse lengths'), - ) - options = ( - {'id': 'invert', 'desc': 'Invert data', 'default': 'no', - 'values': ('no', 'yes')}, - {'id': 'decodeas', 'desc': 'Decode type', 'default': 'Manchester', - 'values': ('NRZ', 'Manchester', 'Diff Manchester')}, - {'id': 'preamble', 'desc': 'Preamble', 'default': 'auto', - 'values': ('auto', '1010', '1111')}, - {'id': 'preamlen', 'desc': 'Filter length', 'default': '7', - 'values': ('0', '3', '4', '5', '6', '7', '8', '9', '10')}, - {'id': 'diffmanvar', 'desc': 'Transition at start', 'default': '1', - 'values': ('1', '0')}, - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.ss = self.es = -1 - self.ss_1111 = self.ss_1010 = -1 - self.samplenumber_last = None - self.sample_first = None - self.sample_high = 0 - self.sample_low = 0 - self.edge_count = 0 - self.word_first = None - self.word_count = 0 - self.state = 'IDLE' - self.lstate = None - self.lstate_1010 = None - self.insync = 0 # Preamble in sync flag - self.man_errors = 0 - self.man_errors_1010 = 0 - self.preamble = [] # Preamble buffer - self.half_time = -1 # Half time for man 1111 - self.half_time_1010 = 0 # Half time for man 1010 - self.pulse_lengths = [] # Pulse lengths - self.decoded = [] # Decoded stream - self.decoded_1010 = [] # Decoded stream - self.diff_man_trans = '0' # Transition - self.diff_man_len = 1 # Length of pulse in half clock periods - self.max_errors = 5 # Max number of errors to output OOK - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.out_python = self.register(srd.OUTPUT_PYTHON) - self.out_binary = self.register(srd.OUTPUT_BINARY) - self.invert = self.options['invert'] - self.decodeas = self.options['decodeas'] - self.preamble_val = self.options['preamble'] - self.preamble_len = self.options['preamlen'] - self.diffmanvar = self.options['diffmanvar'] - - def putx(self, data): - self.put(self.ss, self.es, self.out_ann, data) - - def putp(self, data): - self.put(self.ss, self.es, self.out_python, data) - - def dump_pulse_lengths(self): - if self.samplerate: - self.pulse_lengths[-1] = self.sample_first # Fix final pulse length. - s = 'Pulses(us)=' - s += ','.join(str(int(int(x) * 1000000 / self.samplerate)) - for x in self.pulse_lengths) - s += '\n' - self.put(self.samplenum - 10, self.samplenum, self.out_binary, - [0, bytes([ord(c) for c in s])]) - - def decode_nrz(self, start, samples, state): - self.pulse_lengths.append(samples) - # Use different high and low widths to compensate skewed waveforms. - dsamples = self.sample_high if state == '1' else self.sample_low - self.ss, self.es = start, start + samples - while samples > dsamples * 0.5: - if samples >= dsamples * 1.5: # More than one bit. - self.es = self.ss + dsamples - self.putx([5, [state]]) - self.decoded.append([self.ss, self.es, state]) - self.edge_count += 1 - elif samples >= dsamples * 0.5 and samples < dsamples * 1.5: # Last bit. - self.putx([5, [state]]) - self.decoded.append([self.ss, self.es, state]) - self.edge_count += 1 - else: - self.edge_count += 1 - samples -= dsamples - self.ss += dsamples - self.es += dsamples - - # Ensure 2nd row doesn't go past end of 1st row. - if self.es > self.samplenum: - self.es = self.samplenum - - if self.state == 'DECODE_TIMEOUT': # Five bits - reset. - self.ss = self.decoded[0][0] - self.es = self.decoded[len(self.decoded) - 1][1] - self.dump_pulse_lengths() - self.putp(self.decoded) - self.decode_timeout() - break - - def lock_onto_preamble(self, samples, state): # Filters and recovers clock. - self.edge_count += 1 - l2s = 5 # Max ratio of long to short pulses. - - # Filter incoming pulses to remove random noise. - if self.state == 'DECODE_TIMEOUT': - self.preamble = [] - self.edge_count = 0 - self.word_first = self.samplenum - self.sample_first = self.samplenum - self.samplenumber_last - self.state = 'WAITING_FOR_PREAMBLE' - self.man_errors = 0 - - pre_detect = int(self.preamble_len) # Number of valid pulses to detect. - pre_samples = self.samplenum - self.samplenumber_last - if len(self.preamble) > 0: - if (pre_samples * l2s < self.preamble[-1][1] or - self.preamble[-1][1] * l2s < pre_samples): # Garbage in. - self.put(self.samplenum, self.samplenum, - self.out_ann, [0, ['R']]) # Display resets. - self.preamble = [] # Clear buffer. - self.preamble.append([self.samplenumber_last, - pre_samples, state]) - self.edge_count = 0 - self.samplenumber_last = self.samplenum - self.word_first = self.samplenum - else: - self.preamble.append([self.samplenumber_last, - pre_samples, state]) - else: - self.preamble.append([self.samplenumber_last, - pre_samples, state]) - - pre = self.preamble - if len(self.preamble) == pre_detect: # Have a valid series of pulses. - if self.preamble[0][2] == '1': - self.sample_high = self.preamble[0][1] # Allows skewed pulses. - self.sample_low = self.preamble[1][1] - else: - self.sample_high = self.preamble[1][1] - self.sample_low = self.preamble[0][1] - - self.edge_count = 0 - - for i in range(len(self.preamble)): - if i > 1: - if (pre[i][1] > pre[i - 2][1] * 1.25 or - pre[i][1] * 1.25 < pre[i - 2][1]): # Adjust ref width. - if pre[i][2] == '1': - self.sample_high = pre[i][1] - else: - self.sample_low = pre[i][1] - - # Display start of preamble. - if self.decodeas == 'NRZ': - self.decode_nrz(pre[i][0], pre[i][1], pre[i][2]) - if self.decodeas == 'Manchester': - self.decode_manchester(pre[i][0], pre[i][1], pre[i][2]) - if self.decodeas == 'Diff Manchester': - self.es = pre[i][0] + pre[i][1] - self.decode_diff_manchester(pre[i][0], pre[i][1], pre[i][2]) - - # Used to timeout signal. - self.sample_first = int((self.sample_high + self.sample_low)/2) - self.insync = 1 - self.state = 'DECODING' - self.lstate = state - self.lstate_1010 = state - - def decode_diff_manchester(self, start, samples, state): - self.pulse_lengths.append(samples) - - # Use different high and low widths to compensate skewed waveforms. - dsamples = self.sample_high if state == '1' else self.sample_low - - self.es = start + samples - p_length = round(samples / dsamples) # Find relative pulse length. - - if self.edge_count == 0: - self.diff_man_trans = '1' # Very first pulse must be a transition. - self.diff_man_len = 1 # Must also be a half pulse. - self.ss = start - elif self.edge_count % 2 == 1: # Time to make a decision. - if self.diffmanvar == '0': # Transition at self.ss is a zero. - self.diff_man_trans = '0' if self.diff_man_trans == '1' else '1' - if self.diff_man_len == 1 and p_length == 1: - self.putx([4, [self.diff_man_trans]]) - self.decoded.append([self.ss, self.es, self.diff_man_trans]) - self.diff_man_trans = '1' - elif self.diff_man_len == 1 and p_length == 2: - self.es -= int(samples / 2) - self.putx([4, [self.diff_man_trans]]) - self.decoded.append([self.ss, self.es, self.diff_man_trans]) - self.diff_man_trans = '0' - self.edge_count += 1 # Add a virt edge to keep in sync with clk. - elif self.diff_man_len == 2 and p_length == 1: - self.putx([4, [self.diff_man_trans]]) - self.decoded.append([self.ss, self.es, self.diff_man_trans]) - self.diff_man_trans = '1' - elif self.diff_man_len == 2 and p_length == 2: # Double illegal E E. - self.es -= samples - self.putx([4, ['E']]) - self.decoded.append([self.ss, self.es, 'E']) - self.ss = self.es - self.es += samples - self.putx([4, ['E']]) - self.decoded.append([self.ss, self.es, 'E']) - self.diff_man_trans = '1' - elif self.diff_man_len == 1 and p_length > 4: - if self.state == 'DECODE_TIMEOUT': - self.es = self.ss + 2 * self.sample_first - self.putx([4, [self.diff_man_trans]]) # Write error. - self.decoded.append([self.ss, self.es, self.diff_man_trans]) - self.ss = self.decoded[0][0] - self.es = self.decoded[len(self.decoded) - 1][1] - self.dump_pulse_lengths() - if self.man_errors < self.max_errors: - self.putp(self.decoded) - else: - error_message = 'Probably not Diff Manchester encoded' - self.ss = self.word_first - self.putx([1, [error_message]]) - self.decode_timeout() - self.diff_man_trans = '1' - self.ss = self.es - self.diff_man_len = p_length # Save the previous length. - self.edge_count += 1 - - def decode_manchester_sim(self, start, samples, state, - dsamples, half_time, lstate, ss, pream): - ook_bit = [] - errors = 0 - if self.edge_count == 0: - half_time += 1 - if samples > 0.75 * dsamples and samples <= 1.5 * dsamples: # Long p. - half_time += 2 - if half_time % 2 == 0: # Transition. - es = start - else: - es = start + int(samples / 2) - if ss == start: - lstate = 'E' - es = start + samples - if not (self.edge_count == 0 and pream == '1010'): # Skip first p. - ook_bit = [ss, es, lstate] - lstate = state - ss = es - elif samples > 0.25 * dsamples and samples <= 0.75 * dsamples: # Short p. - half_time += 1 - if (half_time % 2 == 0): # Transition. - es = start + samples - ook_bit = [ss, es, lstate] - lstate = state - ss = es - else: # 1st half. - ss = start - lstate = state - else: # Too long or too short - error. - errors = 1 - if self.state != 'DECODE_TIMEOUT': # Error condition. - lstate = 'E' - es = ss + samples - else: # Assume final half bit buried in timeout pulse. - es = ss + self.sample_first - ook_bit = [ss, es, lstate] - ss = es - - return (half_time, lstate, ss, ook_bit, errors) - - def decode_manchester(self, start, samples, state): - self.pulse_lengths.append(samples) - - # Use different high and low widths to compensate skewed waveforms. - dsamples = self.sample_high if state == '1' else self.sample_low - - if self.preamble_val != '1010': # 1111 preamble is half clock T. - (self.half_time, self.lstate, self.ss_1111, ook_bit, errors) = ( - self.decode_manchester_sim(start, samples, state, dsamples * 2, - self.half_time, self.lstate, - self.ss_1111, '1111')) - self.man_errors += errors - if ook_bit != []: - self.decoded.append([ook_bit[0], ook_bit[1], ook_bit[2]]) - - if self.preamble_val != '1111': # 1010 preamble is clock T. - (self.half_time_1010, self.lstate_1010, self.ss_1010, - ook_bit, errors) = ( - self.decode_manchester_sim(start, samples, state, dsamples, - self.half_time_1010, self.lstate_1010, - self.ss_1010, '1010')) - self.man_errors_1010 += errors - if ook_bit != []: - self.decoded_1010.append([ook_bit[0], ook_bit[1], ook_bit[2]]) - - self.edge_count += 1 - - # Stream display and save ook_bit. - if ook_bit != []: - self.ss, self.es = ook_bit[0], ook_bit[1] - if self.preamble_val == '1111': - self.putx([2, [ook_bit[2]]]) - if self.preamble_val == '1010': - self.putx([3, [ook_bit[2]]]) - - if self.state == 'DECODE_TIMEOUT': # End of packet. - self.dump_pulse_lengths() - - decoded = [] - # If 1010 preamble has less errors use it. - if (self.preamble_val == '1010' or - (self.man_errors_1010 < self.max_errors and - self.man_errors_1010 < self.man_errors and - len(self.decoded_1010) > 0)): - decoded = self.decoded_1010 - man_errors = self.man_errors_1010 - d_row = 3 - else: - decoded = self.decoded - man_errors = self.man_errors - d_row = 2 - - if self.preamble_val == 'auto': # Display OOK packet. - for i in range(len(decoded)): - self.ss, self.es = decoded[i][0], decoded[i][1] - self.putx([d_row, [decoded[i][2]]]) - - if (man_errors < self.max_errors and len(decoded) > 0): - self.ss, self.es = decoded[0][0], decoded[len(decoded) - 1][1] - self.putp(decoded) - else: - error_message = 'Not Manchester encoded or wrong preamble' - self.ss = self.word_first - self.putx([1, [error_message]]) - - self.put(self.es, self.es, self.out_ann, [0, ['T']]) # Mark timeout. - self.decode_timeout() - - def decode_timeout(self): - self.word_count = 0 - self.samplenumber_last = None - self.edge_count = 0 - self.man_errors = 0 # Clear the bit error counters. - self.man_errors_1010 = 0 - self.state = 'IDLE' - self.wait({0: 'e'}) # Get rid of long pulse. - self.samplenumber_last = self.samplenum - self.word_first = self.samplenum - self.insync = 0 # Preamble in sync flag - self.preamble = [] # Preamble buffer - self.half_time = -1 # Half time for man 1111 - self.half_time_1010 = 0 # Half time for man 1010 - self.decoded = [] # Decoded bits - self.decoded_1010 = [] # Decoded bits for man 1010 - self.pulse_lengths = [] - - def decode(self): - while True: - if self.edge_count == 0: # Waiting for a signal. - (ook,) = self.wait({0: 'e'}) - self.state = 'DECODING' - else: - (ook,) = self.wait([{0: 'e'}, {'skip': 5 * self.sample_first}]) - if (self.matched & (0b1 << 1)) and not (self.matched & (0b1 << 0)): # No edges for 5 p's. - self.state = 'DECODE_TIMEOUT' - - if not self.samplenumber_last: # Set counters to start of signal. - self.samplenumber_last = self.samplenum - self.word_first = self.samplenum - continue - samples = self.samplenum - self.samplenumber_last - if not self.sample_first: # Get number of samples for first pulse. - self.sample_first = samples - - pinstate = ook - if self.state == 'DECODE_TIMEOUT': # No edge so flip the state. - pinstate = int(not pinstate) - if self.invert == 'yes': # Invert signal. - pinstate = int(not pinstate) - state = '0' if pinstate else '1' - - # No preamble filtering or checking and no skew correction. - if self.preamble_len == '0': - self.sample_high = self.sample_first - self.sample_low = self.sample_first - self.insync = 0 - - if self.insync == 0: - self.lock_onto_preamble(samples, state) - else: - if self.decodeas == 'NRZ': - self.decode_nrz(self.samplenumber_last, samples, state) - if self.decodeas == 'Manchester': - self.decode_manchester(self.samplenumber_last, - samples, state) - if self.decodeas == 'Diff Manchester': - self.decode_diff_manchester(self.samplenumber_last, - samples, state) - - self.samplenumber_last = self.samplenum diff --git a/decoders/ook_oregon/__init__.py b/decoders/ook_oregon/__init__.py deleted file mode 100755 index f1a1fdf4..00000000 --- a/decoders/ook_oregon/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Steve R -## -## 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, see . -## - -''' -This decoder stacks on top of the 'ook' PD and decodes the Oregon Scientific -433MHz remote control protocol for weather sensors. -''' - -from .pd import Decoder diff --git a/decoders/ook_oregon/lists.py b/decoders/ook_oregon/lists.py deleted file mode 100755 index c46c4cc7..00000000 --- a/decoders/ook_oregon/lists.py +++ /dev/null @@ -1,75 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Steve R -## -## 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, see . -## - -# Most of the info here comes from "434MHz RF Protocol Descriptions for -# Wireless Weather Sensors - October 2015" Known Sensor ID Codes - p25. - -# Format is 4 hex digit ID code followed by a LIST of models that use that -# ID and the type of sensor. -# SensorID is used as the hash in a Python hash table, so it must be upper case. -# The type of sensor is used to decode and display readings in the L2 decode, -# it's case-sensitive. -# Be very careful with the formatting ' [] and commas. - -sensor = { -# 'SensorID': [['model1', 'model2'], 'type'], - '1984': [['WGR800'], 'Wind'], # The newer anemometer with no temperature/RH sensor. - '1994': [['WGR800'], 'Wind'], # The original anemometer which included a temperature/RH sensor. - '1A2D': [['THGR228N'], 'Temp_Hum1'], - '1A3D': [['THGR918'], ''], - '1D20': [['THGN123N', 'THGR122NX', 'THGN123N', 'THGR228N'], 'Temp_Hum'], - '1D30': [['THGN500', 'THGN132N'], ''], - '2914': [['PCR800'], 'Rain'], - '2A19': [['PCR800'], 'Rain1'], - '2A1D': [['RGR918'], 'Rain'], - '2D10': [['RGR968', 'PGR968 '], 'Rain1'], - '3A0D': [['STR918', 'WGR918'], 'Wind'], - '5A5D': [['BTHR918'], ''], - '5A6D': [['BTHR918N'], 'Temp_Hum_Baro'], - '5D53': [['BTHGN129'], 'Baro'], - '5D60': [['BTHR968'], 'Temp_Hum_Baro'], - 'C844': [['THWR800'], 'Temp'], - 'CC13': [['RTGR328N'], 'Temp_Hum'], - 'CC23': [['THGR328N'], 'Temp_Hum'], - 'CD39': [['RTHR328N'], 'Temp'], - 'D874': [['UVN800'], 'UV1'], - 'EA4C': [['THWR288A'], 'Temp'], - 'EC40': [['THN132N', 'THR238NF'], 'Temp'], - 'EC70': [['UVR128'], 'UV'], - 'F824': [['THGN800', 'THGN801', 'THGR810'], 'Temp_Hum'], - 'F8B4': [['THGR810'], 'Temp_Hum'], -# '': ['PSR01'], '', ''], -# '': ['RTGR328NA'], '', ''], -# '': ['THC268'], '', ''], -# '': ['THWR288A-JD'], '', ''], -# '': ['THGR268'], '', ''], -# '': ['THR268'], '', ''], -} - -# The sensor checksum exceptions are used to calculate the right checksum for -# sensors that don't follow the v1, v2.1 and v3 methods. For instance a v2.1 -# sensor that has a v3 checksum. -sensor_checksum = { -# 'SensorID': ['checksum_method', 'comment'], - '1D20': ['v3', 'THGR228N'], - '5D60': ['v3', 'BTHR918N'], - 'EC40': ['v3', 'THN132N'], -} - -dir_table = ['N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW', 'N'] diff --git a/decoders/ook_oregon/pd.py b/decoders/ook_oregon/pd.py deleted file mode 100755 index 225f5983..00000000 --- a/decoders/ook_oregon/pd.py +++ /dev/null @@ -1,389 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Steve R -## -## 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, see . -## - -import sigrokdecode as srd -import math -from .lists import * - -class Decoder(srd.Decoder): - api_version = 3 - id = 'ook_oregon' - name = 'Oregon' - longname = 'Oregon Scientific' - desc = 'Oregon Scientific weather sensor protocol.' - license = 'gplv2+' - inputs = ['ook'] - outputs = [] - tags = ['Sensor'] - annotations = ( - ('bit', 'Bit'), - ('field', 'Field'), - ('l2', 'Level 2'), - ('pre', 'Preamble'), - ('syn', 'Sync'), - ('id', 'SensorID'), - ('ch', 'Channel'), - ('roll', 'Rolling code'), - ('f1', 'Flags1'), - ) - annotation_rows = ( - ('bits', 'Bits', (0,)), - ('fields', 'Fields', (1, 3, 4)), - ('l2', 'Level 2', (2,)), - ) - binary = ( - ('data-hex', 'Hex data'), - ) - options = ( - {'id': 'unknown', 'desc': 'Unknown type is', 'default': 'Unknown', - 'values': ('Unknown', 'Temp', 'Temp_Hum', 'Temp_Hum1', 'Temp_Hum_Baro', - 'Temp_Hum_Baro1', 'UV', 'UV1', 'Wind', 'Rain', 'Rain1')}, - ) - - def __init__(self): - self.reset() - - def reset(self): - self.decoded = [] # Local cache of decoded OOK. - self.skip = None - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.out_binary = self.register(srd.OUTPUT_BINARY) - self.unknown = self.options['unknown'] - - def putx(self, data): - self.put(self.ss, self.es, self.out_ann, data) - - def dump_oregon_hex(self, start, finish): - nib = self.decoded_nibbles - hexstring = '' - for x in nib: - hexstring += str(x[3]) if x[3] != '' else ' ' - s = 'Oregon ' + self.ver + ' \"' + hexstring.upper() + '\"\n' - self.put(start, finish, self.out_binary, - [0, bytes([ord(c) for c in s])]) - - def oregon_put_pre_and_sync(self, len_pream, len_sync, ver): - ook = self.decoded - self.decode_pos = len_pream - self.ss, self.es = ook[0][0], ook[self.decode_pos][0] - self.putx([1, ['Oregon ' + ver + ' Preamble', ver + ' Preamble', - ver + ' Pre', ver]]) - self.decode_pos += len_sync - self.ss, self.es = ook[len_pream][0], ook[self.decode_pos][0] - self.putx([1, ['Sync', 'Syn', 'S']]) - - # Strip off preamble and sync bits. - self.decoded = self.decoded[self.decode_pos:] - self.ookstring = self.ookstring[self.decode_pos:] - self.ver = ver - - def oregon(self): - self.ookstring = '' - self.decode_pos = 0 - ook = self.decoded - for i in range(len(ook)): - self.ookstring += ook[i][2] - if '10011001' in self.ookstring[:40]: - (preamble, data) = self.ookstring.split('10011001', 1) - if len(data) > 0 and len(preamble) > 16: - self.oregon_put_pre_and_sync(len(preamble), 8, 'v2.1') - self.oregon_v2() - elif 'E1100' in self.ookstring[:17]: - (preamble, data) = self.ookstring.split('E1100', 1) - if len(data) > 0 and len(preamble) <= 12: - self.oregon_put_pre_and_sync(len(preamble), 5, 'v1') - self.oregon_v1() - elif '0101' in self.ookstring[:28]: - (preamble, data) = self.ookstring.split('0101', 1) - if len(data) > 0 and len(preamble) > 12: - self.oregon_put_pre_and_sync(len(preamble), 4, 'v3') - self.oregon_v3() - elif len(self.ookstring) > 16: # Ignore short packets. - error_message = 'Not Oregon or wrong preamble' - self.ss, self.es = ook[0][0], ook[len(ook) - 1][1] - self.putx([1,[error_message]]) - - def oregon_v1(self): - ook = self.decoded - self.decode_pos = 0 - self.decoded_nibbles = [] - if len(self.decoded) >= 32: # Check there are at least 8 nibbles. - self.oregon_put_nib('RollingCode', ook[self.decode_pos][0], - ook[self.decode_pos + 3][1], 4) - self.oregon_put_nib('Ch', ook[self.decode_pos][0], - ook[self.decode_pos + 3][1], 4) - self.oregon_put_nib('Temp', ook[self.decode_pos][0], - ook[self.decode_pos + 15][1], 16) - self.oregon_put_nib('Checksum', ook[self.decode_pos][0], - ook[self.decode_pos + 7][1], 8) - - self.dump_oregon_hex(ook[0][0], ook[len(ook) - 1][1]) - - # L2 decode. - self.oregon_temp(2) - self.oregon_channel(1) - self.oregon_battery(2) - self.oregon_checksum_v1() - - def oregon_v2(self): # Convert to v3 format - discard odd bits. - self.decode_pos = 0 - self.ookstring = self.ookstring[1::2] - for i in range(len(self.decoded)): - if i % 2 == 1: - self.decoded[i][0] = self.decoded[i - 1][0] # Re-align start pos. - self.decoded = self.decoded[1::2] # Discard left hand bits. - self.oregon_v3() # Decode with v3 decoder. - - def oregon_nibbles(self, ookstring): - num_nibbles = int(len(ookstring) / 4) - nibbles = [] - for i in range(num_nibbles): - nibble = ookstring[4 * i : 4 * i + 4] - nibble = nibble[::-1] # Reversed from right. - nibbles.append(nibble) - return nibbles - - def oregon_put_nib(self, label, start, finish, numbits): - param = self.ookstring[self.decode_pos:self.decode_pos + numbits] - param = self.oregon_nibbles(param) - if 'E' in ''.join(param): # Blank out fields with errors. - result = '' - else: - result = hex(int(''.join(param), 2))[2:] - if len(result) < numbits / 4: # Reinstate leading zeros. - result = '0' * (int(numbits / 4) - len(result)) + result - if label != '': - label += ': ' - self.put(start, finish, self.out_ann, [1, [label + result, result]]) - if label == '': # No label - use nibble position. - label = int(self.decode_pos / 4) - for i in range(len(param)): - ss = self.decoded[self.decode_pos + (4 * i)][0] - es = self.decoded[self.decode_pos + (4 * i) + 3][1] - # Blank out nibbles with errors. - result = '' if ('E' in param[i]) else hex(int(param[i], 2))[2:] - # Save nibbles for L2 decoder. - self.decoded_nibbles.append([ss, es, label, result]) - self.decode_pos += numbits - - def oregon_v3(self): - self.decode_pos = 0 - self.decoded_nibbles = [] - ook = self.decoded - - if len(self.decoded) >= 32: # Check there are at least 8 nibbles. - self.oregon_put_nib('SensorID', ook[self.decode_pos][0], - ook[self.decode_pos + 16][0], 16) - self.oregon_put_nib('Ch', ook[self.decode_pos][0], - ook[self.decode_pos + 3][1], 4) - self.oregon_put_nib('RollingCode', ook[self.decode_pos][0], - ook[self.decode_pos + 7][1], 8) - self.oregon_put_nib('Flags1', ook[self.decode_pos][0], - ook[self.decode_pos + 3][1], 4) - - rem_nibbles = len(self.ookstring[self.decode_pos:]) // 4 - for i in range(rem_nibbles): # Display and save rest of nibbles. - self.oregon_put_nib('', ook[self.decode_pos][0], - ook[self.decode_pos + 3][1], 4) - self.dump_oregon_hex(ook[0][0], ook[len(ook) - 1][1]) - self.oregon_level2() # Level 2 decode. - else: - error_message = 'Too short to decode' - self.put(ook[0][0], ook[-1][1], self.out_ann, [1, [error_message]]) - - def oregon_put_l2_param(self, offset, digits, dec_point, pre_label, label): - nib = self.decoded_nibbles - result = 0 - out_string = ''.join(str(x[3]) for x in nib[offset:offset + digits]) - if len(out_string) == digits: - for i in range(dec_point, 0, -1): - result += int(nib[offset + dec_point - i][3], 16) / pow(10, i) - for i in range(dec_point, digits): - result += int(nib[offset + i][3], 16) * pow(10, i - dec_point) - result = '%g' % (result) - else: - result = '' - es = nib[offset + digits - 1][1] - if label == '\u2103': - es = nib[offset + digits][1] # Align temp to include +/- nibble. - self.put(nib[offset][0], es, self.out_ann, - [2, [pre_label + result + label, result]]) - - def oregon_temp(self, offset): - nib = self.decoded_nibbles - if nib[offset + 3][3] != '': - temp_sign = str(int(nib[offset + 3][3], 16)) - temp_sign = '-' if temp_sign != '0' else '+' - else: - temp_sign = '?' - self.oregon_put_l2_param(offset, 3, 1, temp_sign, '\u2103') - - def oregon_baro(self, offset): - nib = self.decoded_nibbles - baro = '' - if not (nib[offset + 2][3] == '' or nib[offset + 1][3] == '' - or nib[offset][3] == ''): - baro = str(int(nib[offset + 1][3] + nib[offset][3], 16) + 856) - self.put(nib[offset][0], nib[offset + 3][1], - self.out_ann, [2, [baro + ' mb', baro]]) - - def oregon_wind_dir(self, offset): - nib = self.decoded_nibbles - if nib[offset][3] != '': - w_dir = int(int(nib[offset][3], 16) * 22.5) - w_compass = dir_table[math.floor((w_dir + 11.25) / 22.5)] - self.put(nib[offset][0], nib[offset][1], self.out_ann, - [2, [w_compass + ' (' + str(w_dir) + '\u00b0)', w_compass]]) - - def oregon_channel(self, offset): - nib = self.decoded_nibbles - channel = '' - if nib[offset][3] != '': - ch = int(nib[offset][3], 16) - if self.ver != 'v3': # May not be true for all v2.1 sensors. - if ch != 0: - bit_pos = 0 - while ((ch & 1) == 0): - bit_pos += 1 - ch = ch >> 1 - if self.ver == 'v2.1': - bit_pos += 1 - channel = str(bit_pos) - elif self.ver == 'v3': # Not sure if this applies to all v3's. - channel = str(ch) - if channel != '': - self.put(nib[offset][0], nib[offset][1], - self.out_ann, [2, ['Ch ' + channel, channel]]) - - def oregon_battery(self, offset): - nib = self.decoded_nibbles - batt = 'OK' - if nib[offset][3] != '': - if (int(nib[offset][3], 16) >> 2) & 0x1 == 1: - batt = 'Low' - self.put(nib[offset][0], nib[offset][1], - self.out_ann, [2, ['Batt ' + batt, batt]]) - - def oregon_level2(self): # v2 and v3 level 2 decoder. - nib = self.decoded_nibbles - self.sensor_id = (nib[0][3] + nib[1][3] + nib[2][3] + nib[3][3]).upper() - nl, sensor_type = sensor.get(self.sensor_id, [['Unknown'], 'Unknown']) - names = ','.join(nl) - # Allow user to try decoding an unknown sensor. - if sensor_type == 'Unknown' and self.unknown != 'Unknown': - sensor_type = self.unknown - self.put(nib[0][0], nib[3][1], self.out_ann, - [2, [names + ' - ' + sensor_type, names, nl[0]]]) - self.oregon_channel(4) - self.oregon_battery(7) - if sensor_type == 'Rain': - self.oregon_put_l2_param(8, 4, 2, '', ' in/hr') # Rain rate - self.oregon_put_l2_param(12, 6, 3, 'Total ', ' in') # Rain total - self.oregon_checksum(18) - if sensor_type == 'Rain1': - self.oregon_put_l2_param(8, 3, 1, '', ' mm/hr') # Rain rate - self.oregon_put_l2_param(11, 5, 1, 'Total ', ' mm') # Rain total - self.oregon_checksum(18) - if sensor_type == 'Temp': - self.oregon_temp(8) - self.oregon_checksum(12) - if sensor_type == 'Temp_Hum_Baro': - self.oregon_temp(8) - self.oregon_put_l2_param(12, 2, 0, 'Hum ', '%') # Hum - self.oregon_baro(15) # Baro - self.oregon_checksum(19) - if sensor_type == 'Temp_Hum_Baro1': - self.oregon_temp(8) - self.oregon_put_l2_param(12, 2, 0, 'Hum ', '%') # Hum - self.oregon_baro(14) # Baro - if sensor_type == 'Temp_Hum': - self.oregon_temp(8) - self.oregon_put_l2_param(12, 2, 0, 'Hum ', '%') # Hum - self.oregon_checksum(15) - if sensor_type == 'Temp_Hum1': - self.oregon_temp(8) - self.oregon_put_l2_param(12, 2, 0, 'Hum ', '%') # Hum - self.oregon_checksum(14) - if sensor_type == 'UV': - self.oregon_put_l2_param(8, 2, 0, '', '') # UV - if sensor_type == 'UV1': - self.oregon_put_l2_param(11, 2, 0,'' ,'') # UV - if sensor_type == 'Wind': - self.oregon_wind_dir(8) - self.oregon_put_l2_param(11, 3, 1, 'Gust ', ' m/s') # Wind gust - self.oregon_put_l2_param(14, 3, 1, 'Speed ', ' m/s') # Wind speed - self.oregon_checksum(17) - - def oregon_put_checksum(self, nibbles, checksum): - nib = self.decoded_nibbles - result = 'BAD' - if (nibbles + 1) < len(nib): - if (nib[nibbles + 1][3] != '' and nib[nibbles][3] != '' - and checksum != -1): - if self.ver != 'v1': - if checksum == (int(nib[nibbles + 1][3], 16) * 16 + - int(nib[nibbles][3], 16)): - result = 'OK' - else: - if checksum == (int(nib[nibbles][3], 16) * 16 + - int(nib[nibbles + 1][3], 16)): - result = 'OK' - rx_check = (nib[nibbles + 1][3] + nib[nibbles][3]).upper() - details = '%s Calc %s Rx %s ' % (result, hex(checksum)[2:].upper(), - rx_check) - self.put(nib[nibbles][0], nib[nibbles + 1][1], - self.out_ann, [2, ['Checksum ' + details, result]]) - - def oregon_checksum(self, nibbles): - checksum = 0 - for i in range(nibbles): # Add reversed nibbles. - nibble = self.ookstring[i * 4 : i * 4 + 4] - nibble = nibble[::-1] # Reversed from right. - if 'E' in nibble: # Abort checksum if there are errors. - checksum = -1 - break - checksum += int(nibble, 2) - if checksum > 255: - checksum -= 255 # Make it roll over at 255. - chk_ver, comment = sensor_checksum.get(self.sensor_id, - ['Unknown', 'Unknown']) - if chk_ver != 'Unknown': - self.ver = chk_ver - if self.ver == 'v2.1': - checksum -= 10 # Subtract 10 from v2 checksums. - self.oregon_put_checksum(nibbles, checksum) - - def oregon_checksum_v1(self): - nib = self.decoded_nibbles - checksum = 0 - for i in range(3): # Add the first three bytes. - if nib[2 * i][3] == '' or nib[2 * i + 1][3] == '': # Abort if blank. - checksum = -1 - break - checksum += ((int(nib[2 * i][3], 16) & 0xF) << 4 | - (int(nib[2 * i + 1][3], 16) & 0xF)) - if checksum > 255: - checksum -= 255 # Make it roll over at 255. - self.oregon_put_checksum(6, checksum) - - def decode(self, ss, es, data): - self.decoded = data - self.oregon() diff --git a/decoders/ook_vis/__init__.py b/decoders/ook_vis/__init__.py deleted file mode 100755 index f50f9ef8..00000000 --- a/decoders/ook_vis/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Steve R -## -## 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, see . -## - -''' -This decoder stacks on top of the 'ook' PD and visualizes protocol details -in various ways. -''' - -from .pd import Decoder diff --git a/decoders/ook_vis/pd.py b/decoders/ook_vis/pd.py deleted file mode 100755 index f985b96f..00000000 --- a/decoders/ook_vis/pd.py +++ /dev/null @@ -1,194 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Steve R -## -## 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, see . -## - -import sigrokdecode as srd -from common.srdhelper import bcd2int - -class Decoder(srd.Decoder): - api_version = 3 - id = 'ook_vis' - name = 'OOK visualisation' - longname = 'On-off keying visualisation' - desc = 'OOK visualisation in various formats.' - license = 'gplv2+' - inputs = ['ook'] - outputs = ['ook'] - tags = ['Encoding'] - annotations = ( - ('bit', 'Bit'), - ('ref', 'Reference'), - ('field', 'Field'), - ('ref_field', 'Ref field'), - ('level2', 'L2'), - ('ref_level2', 'Ref L2'), - ) - annotation_rows = ( - ('bits', 'Bits', (0,)), - ('compare', 'Compare', (1,)), - ('fields', 'Fields', (2,)), - ('ref_fields', 'Ref fields', (3,)), - ('level2', 'L2', (4,)), - ('ref_level2', 'Ref L2', (5,)), - ) - options = ( - {'id': 'displayas', 'desc': 'Display as', 'default': 'Nibble - Hex', - 'values': ('Byte - Hex', 'Byte - Hex rev', 'Byte - BCD', - 'Byte - BCD rev', 'Nibble - Hex', 'Nibble - Hex rev', 'Nibble - BCD', - 'Nibble - BCD rev')}, - {'id': 'synclen', 'desc': 'Sync length', 'default': '4', - 'values': ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10')}, - {'id': 'syncoffset', 'desc': 'Sync offset', 'default': '0', - 'values': ('-4', '-3', '-2', '-1', '0', '1', '2', '3', '4')}, - {'id': 'refsample', 'desc': 'Compare', 'default': 'off', 'values': - ('off', 'show numbers', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', - '21', '22', '23', '24', '25', '26', '27', '28', '29', '30')}, - ) - - def __init__(self): - self.reset() - - def reset(self): - self.decoded = [] # Local cache of decoded OOK. - self.ookstring = '' - self.ookcache = [] - self.trace_num = 0 - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.out_python = self.register(srd.OUTPUT_PYTHON) - self.displayas = self.options['displayas'] - self.sync_length = self.options['synclen'] - self.sync_offset = self.options['syncoffset'] - self.ref = self.options['refsample'] - - def putx(self, data): - self.put(self.ss, self.es, self.out_ann, data) - - def putp(self, data): - self.put(self.ss, self.es, self.out_python, data) - - def display_level2(self, bits, line): - self.decode_pos = 0 - ook = self.decoded - # Find the end of the preamble which could be 1010 or 1111. - if len(ook) > 1: - preamble_end = len(ook) + 1 - char_first = ook[0][2] - char_second = ook[1][2] - if char_first == char_second: # 1111 - preamble = '1111' - char_last = char_first - else: - preamble = '1010' - char_last = char_second - for i in range(len(ook)): - if preamble == '1111': - if ook[i][2] != char_last: - preamble_end = i - break - else: - char_last = ook[i][2] - else: - if ook[i][2] != char_last: - char_last = ook[i][2] - else: - preamble_end = i - break - - if len(ook) >= preamble_end: - preamble_end += int(self.sync_offset) - 1 - self.ss, self.es = ook[0][0], ook[preamble_end][1] - self.putx([line, ['Preamble', 'Pre', 'P']]) - self.decode_pos += preamble_end - - if len(ook) > self.decode_pos + int(self.sync_length): - self.ss = self.es - self.es = ook[self.decode_pos + int(self.sync_length)][1] - self.putx([line, ['Sync', 'Syn', 'S']]) - self.decode_pos += int(self.sync_length) + 1 - - ookstring = self.ookstring[self.decode_pos:] - rem_nibbles = len(ookstring) // bits - for i in range(rem_nibbles): # Display the rest of nibbles. - self.ss = ook[self.decode_pos][0] - self.es = ook[self.decode_pos + bits - 1][1] - self.put_field(bits, line) - - def put_field(self, numbits, line): - param = self.ookstring[self.decode_pos:self.decode_pos + numbits] - if 'rev' in self.displayas: - param = param[::-1] # Reversed from right. - if not 'E' in param: # Format if no errors. - if 'Hex' in self.displayas: - param = hex(int(param, 2))[2:] - elif 'BCD' in self.displayas: - param = bcd2int(int(param, 2)) - self.putx([line, [str(param)]]) - self.decode_pos += numbits - - def display_all(self): - ookstring = '' - self.decode_pos = 0 - ook = self.decoded - for i in range(len(ook)): - self.ookstring += ook[i][2] - bits = 4 if 'Nibble' in self.displayas else 8 - rem_nibbles = len(self.ookstring) // bits - for i in range(rem_nibbles): # Display the rest of the nibbles. - self.ss = ook[self.decode_pos][0] - self.es = ook[self.decode_pos + bits - 1][1] - self.put_field(bits, 2) - - self.display_level2(bits, 4) # Display L2 decode. - - if (self.ref != 'off' and self.ref != 'show numbers' and - len(self.ookcache) >= int(self.ref)): # Compare traces. - ref = int(self.ref) - 1 - self.display_ref(self.trace_num, ref) - if len(self.ookcache) == int(self.ref): # Backfill. - for i in range(0, ref): - self.display_ref(i, ref) - elif self.ref == 'show numbers': # Display ref numbers. - self.ss = self.ookcache[self.trace_num][0][0] - end_sig = len(self.ookcache[self.trace_num]) - 1 - self.es = self.ookcache[self.trace_num][end_sig][1] - self.putx([1, [str(self.trace_num + 1)]]) - - def display_ref(self, t_num, ref): - display_len = len(self.ookcache[ref]) - if len(self.ookcache[t_num]) < len(self.ookcache[ref]): - display_len = len(self.ookcache[t_num]) - for i in range(display_len): - self.ss = self.ookcache[t_num][i][0] - self.es = self.ookcache[t_num][i][1] - self.putx([1, [self.ookcache[ref][i][2]]]) - - def add_to_cache(self): # Cache the OOK so it can be used as a reference. - self.ookcache.append(self.decoded) - - def decode(self, ss, es, data): - self.decoded = data - self.add_to_cache() - self.display_all() - self.ookstring = '' - self.trace_num += 1 - self.ss = ss - self.es = es - self.putp(data) # Send data up the stack. diff --git a/decoders/pan1321/__init__.py b/decoders/pan1321/__init__.py deleted file mode 100755 index 428fc91f..00000000 --- a/decoders/pan1321/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -''' -This decoder stacks on top of the 'uart' PD and decodes the Panasonic PAN1321 -Bluetooth module Serial Port Profile (SPP) protocol. -''' - -from .pd import Decoder diff --git a/decoders/pan1321/pd.py b/decoders/pan1321/pd.py deleted file mode 100755 index 6c931147..00000000 --- a/decoders/pan1321/pd.py +++ /dev/null @@ -1,164 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012-2013 Uwe Hermann -## -## 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, see . -## - -import sigrokdecode as srd - -# ... -RX = 0 -TX = 1 - -class Decoder(srd.Decoder): - api_version = 3 - id = 'pan1321' - name = 'PAN1321' - longname = 'Panasonic PAN1321' - desc = 'Bluetooth RF module with Serial Port Profile (SPP).' - license = 'gplv2+' - inputs = ['uart'] - outputs = [] - tags = ['Wireless/RF'] - annotations = ( - ('text-verbose', 'Human-readable text (verbose)'), - ('text', 'Human-readable text'), - ('warnings', 'Human-readable warnings'), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.cmd = ['', ''] - self.ss_block = None - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putx(self, data): - self.put(self.ss_block, self.es_block, self.out_ann, data) - - def handle_host_command(self, rxtx, s): - if s.startswith('AT+JAAC'): - # AT+JAAC= (0 or 1) - p = s[s.find('=') + 1:] - if p not in ('0', '1'): - self.putx([2, ['Warning: Invalid JAAC parameter "%s"' % p]]) - return - x = 'Auto' if (p == '1') else 'Don\'t auto' - self.putx([0, ['%s-accept new connections' % x]]) - self.putx([1, ['%s-accept connections' % x]]) - elif s.startswith('AT+JPRO'): - # AT+JPRO= (0 or 1) - p = s[s.find('=') + 1:] - if p not in ('0', '1'): - self.putx([2, ['Warning: Invalid JPRO parameter "%s"' % p]]) - return - onoff = 'off' if (p == '0') else 'on' - x = 'Leaving' if (p == '0') else 'Entering' - self.putx([0, ['%s production mode' % x]]) - self.putx([1, ['Production mode = %s' % onoff]]) - elif s.startswith('AT+JRES'): - # AT+JRES - if s != 'AT+JRES': # JRES has no params. - self.putx([2, ['Warning: Invalid JRES usage.']]) - return - self.putx([0, ['Triggering a software reset']]) - self.putx([1, ['Reset']]) - elif s.startswith('AT+JSDA'): - # AT+JSDA=, (l: length in bytes, d: data) - # l is (max?) 3 decimal digits and ranges from 1 to MTU size. - # Data can be ASCII or binary values (l bytes total). - l, d = s[s.find('=') + 1:].split(',') - if not l.isnumeric(): - self.putx([2, ['Warning: Invalid data length "%s".' % l]]) - if int(l) != len(d): - self.putx([2, ['Warning: Data length mismatch (%d != %d).' % \ - (int(l), len(d))]]) - # TODO: Warn if length > MTU size (which is firmware-dependent - # and is negotiated by both Bluetooth devices upon connection). - b = ''.join(['%02x ' % ord(c) for c in d])[:-1] - self.putx([0, ['Sending %d data bytes: %s' % (int(l), b)]]) - self.putx([1, ['Send %d = %s' % (int(l), b)]]) - elif s.startswith('AT+JSEC'): - # AT+JSEC=,,,, - # secmode: Security mode 1 or 3 (default). - # linkkey_info: Must be 1 or 2. Has no function according to docs. - # pintype: 1: variable pin (default), 2: fixed pin. - # pinlen: PIN length (2 decimal digits). Max. PIN length is 16. - # pin: The Bluetooth PIN ('pinlen' chars). Used if pintype=2. - # Note: AT+JSEC (if used) must be the first command after reset. - # TODO: Parse all the other parameters. - pin = s[-4:] - self.putx([0, ['Host set the Bluetooth PIN to "' + pin + '"']]) - self.putx([1, ['PIN = ' + pin]]) - elif s.startswith('AT+JSLN'): - # AT+JSLN=, - # namelen: Friendly name length (2 decimal digits). Max. len is 18. - # name: The Bluetooth "friendly name" ('namelen' ASCII characters). - name = s[s.find(',') + 1:] - self.putx([0, ['Host set the Bluetooth name to "' + name + '"']]) - self.putx([1, ['BT name = ' + name]]) - else: - self.putx([0, ['Host sent unsupported command: %s' % s]]) - self.putx([1, ['Unsupported command: %s' % s]]) - - def handle_device_reply(self, rxtx, s): - if s == 'ROK': - self.putx([0, ['Device initialized correctly']]) - self.putx([1, ['Init']]) - elif s == 'OK': - self.putx([0, ['Device acknowledged last command']]) - self.putx([1, ['ACK']]) - elif s.startswith('ERR'): - error = s[s.find('=') + 1:] - self.putx([0, ['Device sent error code ' + error]]) - self.putx([1, ['ERR = ' + error]]) - else: - self.putx([0, ['Device sent an unknown reply: %s' % s]]) - self.putx([1, ['Unknown reply: %s' % s]]) - - def decode(self, ss, es, data): - ptype, rxtx, pdata = data - - # For now, ignore all UART packets except the actual data packets. - if ptype != 'DATA': - return - - # We're only interested in the byte value (not individual bits). - pdata = pdata[0] - - # If this is the start of a command/reply, remember the start sample. - if self.cmd[rxtx] == '': - self.ss_block = ss - - # Append a new (ASCII) byte to the currently built/parsed command. - self.cmd[rxtx] += chr(pdata) - - # Get packets/bytes until an \r\n sequence is found (end of command). - if self.cmd[rxtx][-2:] != '\r\n': - return - - # Handle host commands and device replies. - # We remove trailing \r\n from the strings before handling them. - self.es_block = es - if rxtx == RX: - self.handle_device_reply(rxtx, self.cmd[rxtx][:-2]) - elif rxtx == TX: - self.handle_host_command(rxtx, self.cmd[rxtx][:-2]) - - self.cmd[rxtx] = '' diff --git a/decoders/parallel/__init__.py b/decoders/parallel/__init__.py deleted file mode 100755 index 100523ec..00000000 --- a/decoders/parallel/__init__.py +++ /dev/null @@ -1,34 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2013 Uwe Hermann -## -## 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, see . -## - -''' -This protocol decoder can decode synchronous parallel buses with various -number of data bits/channels and one (optional) clock line. - -If no clock line is supplied, the decoder works slightly differently in -that it interprets every transition on any of the supplied data channels -like there had been a clock transition. - -It is required to use the lowest data channels, and use consecutive ones. -For example, for a 4-bit sync parallel bus, channels D0/D1/D2/D3 (and CLK) -should be used. Using combinations like D7/D12/D3/D15 is not supported. -For an 8-bit bus you should use D0-D7, for a 16-bit bus use D0-D15 and so on. -''' - -from .pd import Decoder diff --git a/decoders/parallel/pd.py b/decoders/parallel/pd.py deleted file mode 100755 index d7544c16..00000000 --- a/decoders/parallel/pd.py +++ /dev/null @@ -1,213 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2013-2016 Uwe Hermann -## -## 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, see . -## - -import sigrokdecode as srd -from common.srdhelper import bitpack - -''' -OUTPUT_PYTHON format: - -Packet: -[, ] - -, - - 'ITEM', [, ] - - 'WORD', [, , ] - -: - - A single item (a number). It can be of arbitrary size. The max. number - of bits in this item is specified in . - -: - - The size of an item (in bits). For a 4-bit parallel bus this is 4, - for a 16-bit parallel bus this is 16, and so on. - -: - - A single word (a number). It can be of arbitrary size. The max. number - of bits in this word is specified in . The (exact) number - of items in this word is specified in . - -: - - The size of a word (in bits). For a 2-item word with 8-bit items - is 16, for a 3-item word with 4-bit items - is 12, and so on. - -: - - The size of a word (in number of items). For a 4-item word (no matter - how many bits each item consists of) is 4, for a 7-item - word is 7, and so on. -''' - -def channel_list(num_channels): - l = [{'id': 'clk', 'name': 'CLK', 'desc': 'Clock line'}] - for i in range(num_channels): - d = {'id': 'd%d' % i, 'name': 'D%d' % i, 'desc': 'Data line %d' % i} - l.append(d) - return tuple(l) - -class ChannelError(Exception): - pass - -NUM_CHANNELS = 8 - -class Decoder(srd.Decoder): - api_version = 3 - id = 'parallel' - name = 'Parallel' - longname = 'Parallel sync bus' - desc = 'Generic parallel synchronous bus.' - license = 'gplv2+' - inputs = ['logic'] - outputs = ['parallel'] - tags = ['Util'] - optional_channels = channel_list(NUM_CHANNELS) - options = ( - {'id': 'clock_edge', 'desc': 'Clock edge to sample on', - 'default': 'rising', 'values': ('rising', 'falling')}, - {'id': 'wordsize', 'desc': 'Data wordsize (# bus cycles)', - 'default': 0}, - {'id': 'endianness', 'desc': 'Data endianness', - 'default': 'little', 'values': ('little', 'big')}, - ) - annotations = ( - ('items', 'Items'), - ('words', 'Words'), - ) - annotation_rows = ( - ('items', 'Items', (0,)), - ('words', 'Words', (1,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.items = [] - self.saved_item = None - self.ss_item = self.es_item = None - self.saved_word = None - self.ss_word = self.es_word = None - self.first = True - - def start(self): - self.out_python = self.register(srd.OUTPUT_PYTHON) - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putpb(self, data): - self.put(self.ss_item, self.es_item, self.out_python, data) - - def putb(self, data): - self.put(self.ss_item, self.es_item, self.out_ann, data) - - def putpw(self, data): - self.put(self.ss_word, self.es_word, self.out_python, data) - - def putw(self, data): - self.put(self.ss_word, self.es_word, self.out_ann, data) - - def handle_bits(self, item, used_pins): - - # If a word was previously accumulated, then emit its annotation - # now after its end samplenumber became available. - if self.saved_word is not None: - if self.options['wordsize'] > 0: - self.es_word = self.samplenum - self.putw([1, [self.fmt_word.format(self.saved_word)]]) - self.putpw(['WORD', self.saved_word]) - self.saved_word = None - - # Defer annotations for individual items until the next sample - # is taken, and the previous sample's end samplenumber has - # become available. - if self.first: - # Save the start sample and item for later (no output yet). - self.ss_item = self.samplenum - self.first = False - self.saved_item = item - else: - # Output the saved item (from the last CLK edge to the current). - self.es_item = self.samplenum - self.putpb(['ITEM', self.saved_item]) - self.putb([0, [self.fmt_item.format(self.saved_item)]]) - self.ss_item = self.samplenum - self.saved_item = item - - # Get as many items as the configured wordsize specifies. - if not self.items: - self.ss_word = self.samplenum - self.items.append(item) - ws = self.options['wordsize'] - if len(self.items) < ws: - return - - # Collect words and prepare annotation details, but defer emission - # until the end samplenumber becomes available. - endian = self.options['endianness'] - if endian == 'big': - self.items.reverse() - word = sum([self.items[i] << (i * used_pins) for i in range(ws)]) - self.saved_word = word - self.items = [] - - def decode(self): - # Determine which (optional) channels have input data. Insist in - # a non-empty input data set. Cope with sparse connection maps. - # Store enough state to later "compress" sampled input data. - max_possible = len(self.optional_channels) - idx_channels = [ - idx if self.has_channel(idx) else None - for idx in range(max_possible) - ] - has_channels = [idx for idx in idx_channels if idx is not None] - if not has_channels: - raise ChannelError('At least one channel has to be supplied.') - max_connected = max(has_channels) - - # Determine .wait() conditions, depending on the presence of a - # clock signal. Either inspect samples on the configured edge of - # the clock, or inspect samples upon ANY edge of ANY of the pins - # which provide input data. - if self.has_channel(0): - edge = self.options['clock_edge'][0] - conds = {0: edge} - else: - conds = [{idx: 'e'} for idx in has_channels] - - # Pre-determine which input data to strip off, the width of - # individual items and multiplexed words, as well as format - # strings here. This simplifies call sites which run in tight - # loops later. - idx_strip = max_connected + 1 - num_item_bits = idx_strip - 1 - num_word_items = self.options['wordsize'] - num_word_bits = num_item_bits * num_word_items - num_digits = (num_item_bits + 3) // 4 - self.fmt_item = "{{:0{}x}}".format(num_digits) - num_digits = (num_word_bits + 3) // 4 - self.fmt_word = "{{:0{}x}}".format(num_digits) - - # Keep processing the input stream. Assume "always zero" for - # not-connected input lines. Pass data bits (all inputs except - # clock) to the handle_bits() method. - while True: - (clk, d0, d1, d2, d3, d4, d5, d6, d7) = self.wait(conds) - pins = (clk, d0, d1, d2, d3, d4, d5, d6, d7) - bits = [0 if idx is None else pins[idx] for idx in idx_channels] - item = bitpack(bits[1:idx_strip]) - self.handle_bits(item, num_item_bits) diff --git a/decoders/pca9571/__init__.py b/decoders/pca9571/__init__.py deleted file mode 100644 index 28152d93..00000000 --- a/decoders/pca9571/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Mickael Bosch -## -## 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, see . -## - -''' -This decoder stacks on top of the 'i2c' PD and decodes the NXP Semiconductors -PCA9571 8-bit I²C output expander protocol. -''' - -from .pd import Decoder diff --git a/decoders/pca9571/pd.py b/decoders/pca9571/pd.py deleted file mode 100644 index df309e91..00000000 --- a/decoders/pca9571/pd.py +++ /dev/null @@ -1,102 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Mickael Bosch -## -## 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, see . -## - -import sigrokdecode as srd - -NUM_OUTPUT_CHANNELS = 8 - -# TODO: Other I²C functions: general call / reset address, device ID address. - -class Decoder(srd.Decoder): - api_version = 3 - id = 'pca9571' - name = 'PCA9571' - longname = 'NXP PCA9571' - desc = 'NXP PCA9571 8-bit I²C output expander.' - license = 'gplv2+' - inputs = ['i2c'] - outputs = [] - tags = ['Embedded/industrial', 'IC'] - annotations = ( - ('register', 'Register type'), - ('value', 'Register value'), - ('warning', 'Warning messages'), - ) - annotation_rows = ( - ('regs', 'Registers', (0, 1)), - ('warnings', 'Warnings', (2,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.state = 'IDLE' - self.last_write = 0xFF # Chip port default state is high. - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putx(self, data): - self.put(self.ss, self.es, self.out_ann, data) - - def handle_io(self, b): - if self.state == 'READ DATA': - operation = ['Outputs read', 'R'] - if b != self.last_write: - self.putx([2, ['Warning: read value and last write value ' - '(%02X) are different' % self.last_write]]) - else: - operation = ['Outputs set', 'W'] - self.last_write = b - self.putx([1, [operation[0] + ': %02X' % b, - operation[1] + ': %02X' % b]]) - - def check_correct_chip(self, addr): - if addr != 0x25: - self.putx([2, ['Warning: I²C slave 0x%02X not a PCA9571 ' - 'compatible chip.' % addr]]) - return False - return True - - def decode(self, ss, es, data): - cmd, databyte = data - self.ss, self.es = ss, es - - # State machine. - if cmd in ('ACK', 'BITS'): # Discard 'ACK' and 'BITS'. - pass - elif cmd in ('START', 'START REPEAT'): # Start a communication. - self.state = 'GET SLAVE ADDR' - elif cmd in ('NACK', 'STOP'): # Reset the state machine. - self.state = 'IDLE' - elif cmd in ('ADDRESS READ', 'ADDRESS WRITE'): - if ((self.state == 'GET SLAVE ADDR') and - self.check_correct_chip(databyte)): - if cmd == 'ADDRESS READ': - self.state = 'READ DATA' - else: - self.state = 'WRITE DATA' - else: - self.state = 'IDLE' - elif cmd in ('DATA READ', 'DATA WRITE'): - if self.state in ('READ DATA', 'WRITE DATA'): - self.handle_io(databyte) - else: - self.state = 'IDLE' diff --git a/decoders/pjdl/__init__.py b/decoders/pjdl/__init__.py deleted file mode 100644 index c3cc8559..00000000 --- a/decoders/pjdl/__init__.py +++ /dev/null @@ -1,27 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 Gerhard Sittig -## -## 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, see . -## - -''' -This protocol decoder interprets the PJDL data link of the PJON protocol. -Bytes and frames get extracted from single wire serial communication -(which often is referred to as "software bitbang" because that's what -the Arduino reference implementation happens to do). -''' - -from .pd import Decoder diff --git a/decoders/pjdl/pd.py b/decoders/pjdl/pd.py deleted file mode 100644 index d5cc39f2..00000000 --- a/decoders/pjdl/pd.py +++ /dev/null @@ -1,723 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 Gerhard Sittig -## -## 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, see . -## - -# See the https://www.pjon.org/ PJON project page and especially the -# https://www.pjon.org/PJDL-specification-v4.1.php PJDL v4.1 spec for -# the "Padded Jittering Data Link" single wire serial data link layer. - -# TODO -# - Improve (fix, and extend) carrier sense support. Detection of the -# idle/busy connection state is incomplete and fragile. Getting 'IDLE' -# operational in the PJDL decoder would greatly help the PJON decoder -# to flush ACK details before the start of new frames. -# - Check the correctness of timing assumptions. This implementation has -# support for tolerances, which the spec does not discuss. Though real -# world traffic was found to not decode at all with strict spec values -# and without tolerances, while communication peers were able to talk -# to each other. This needs more attention. -# - Check robustness when input data contains glitches. The spec does -# not discuss how to handle these. Data bit sampling happens to work -# because their value is taken at the center of the bit time. But -# pad bits suffer badly from glitches, which breaks frame inspection -# as well. -# - Cleanup the decoder implementation in general terms. Some details -# have become obsolete ("edges", "pads"), and/or are covered by other -# code paths. -# - Implement more data link decoders which can feed their output into -# the PJON protocol decoder. Candidates are: PJDLR, PJDLS, TSDL. -# - Determine whether or not the data link layer should interpret any -# frame content. From my perspective it should not, and needs not in -# the strict sense. Possible gains would be getting the (expected!) -# packet length, or whether a synchronous response is requested. But -# this would duplicate knowledge which should remain internal to the -# PJON decoder. And this link layer decoder neither shall assume that -# the input data would be correct, or complete. Instead the decoder -# shall remain usable on captures which demonstrate faults, and be -# helpful in pointing them out. The design goal is to extract the -# maximum of information possible, and pass it on as transparently -# as possible. - -import sigrokdecode as srd -from common.srdhelper import bitpack -from math import ceil, floor - -''' -OUTPUT_PYTHON format for stacked decoders: - -General packet format: -[, ] - -This is the list of s and their respective values: - -Carrier sense: -- 'IDLE': is the pin level (always 0). -- 'BUSY': is always True. - -Raw bit slots: -- 'PAD_BIT': is the pin level (always 1). -- 'DATA_BIT': is the pin level (0, or 1). -- 'SHORT_BIT': is the pin level (always 1). -- 'SYNC_LOSS': is an arbitrary text (internal use only). - -Date bytes and frames: -- 'SYNC_PAD': is True. Spans the high pad bit as well as the - low data bit. -- 'DATA_BYTE': is the byte value (0..255). -- 'FRAME_INIT': is True. Spans three sync pads. -- 'FRAME_DATA': is the sequence of bytes in the frame. Non-data - phases in the frame get represented by strings instead of numbers - ('INIT', 'SYNC', 'SHORT', 'WAIT'). Frames can be incomplete, depending - on the decoder's input data. -- 'SYNC_RESP_WAIT': is always True. - -Notice that this link layer decoder is not aware of frame content. Will -neither check packet length, nor variable width fields, nor verify the -presence of requested synchronous responses. Cannot tell the sequence of -frame bytes then ACK bytes (without wait phase) from just frame bytes. -An upper layer protocol decoder will interpret content, the link layer -decoder remains as transparent as possible, and will neither assume -correct nor complete input data. -''' - -# Carrier sense, and synchronization loss implementation is currently -# incomplete, and results in too many too short annotations, some of -# them spurious and confusing. TODO Improve the implementation. -_with_ann_carrier = False -_with_ann_sync_loss = False - -PIN_DATA, = range(1) -ANN_CARRIER_BUSY, ANN_CARRIER_IDLE, \ -ANN_PAD_BIT, ANN_LOW_BIT, ANN_DATA_BIT, ANN_SHORT_DATA, ANN_SYNC_LOSS, \ -ANN_DATA_BYTE, \ -ANN_FRAME_INIT, ANN_FRAME_BYTES, ANN_FRAME_WAIT, \ - = range(11) - -class SamplerateError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = 'pjdl' - name = 'PJDL' - longname = 'Padded Jittering Data Link' - desc = 'PJDL, a single wire serial link layer for PJON.' - license = 'gplv2+' - inputs = ['logic'] - outputs = ['pjon_link'] - tags = ['Embedded/industrial'] - channels = ( - {'id': 'data' , 'name': 'DATA', 'desc': 'Single wire data'}, - ) - options = ( - {'id': 'mode', 'desc': 'Communication mode', - 'default': 1, 'values': (1, 2, 3, 4)}, - {'id': 'idle_add_us', 'desc': 'Added idle time (us)', 'default': 4}, - ) - annotations = ( - ('cs_busy', 'Carrier busy'), - ('cs_idle', 'Carrier idle'), - ('bit_pad', 'Pad bit'), - ('bit_low', 'Low bit'), - ('bit_data', 'Data bit'), - ('bit_short', 'Short data'), - ('sync_loss', 'Sync loss'), - ('byte', 'Data byte'), - ('frame_init', 'Frame init'), - ('frame_bytes', 'Frame bytes'), - ('frame_wait', 'Frame wait'), - ) - annotation_rows = ( - ('carriers', 'Carriers', (ANN_CARRIER_BUSY, ANN_CARRIER_IDLE,)), - ('bits', 'Bits', (ANN_PAD_BIT, ANN_LOW_BIT, ANN_DATA_BIT, ANN_SHORT_DATA,)), - ('bytes', 'Bytes', (ANN_FRAME_INIT, ANN_DATA_BYTE, ANN_FRAME_WAIT,)), - ('frames', 'Frames', (ANN_FRAME_BYTES,)), - ('warns', 'Warnings', (ANN_SYNC_LOSS,)), - ) - - # Communication modes' data bit and pad bit duration (in us), and - # tolerances in percent and absolute (us). - mode_times = { - 1: (44, 116), - 2: (40, 92), - 3: (28, 88), - 4: (26, 60), - } - time_tol_perc = 10 - time_tol_abs = 1.5 - - def __init__(self): - self.reset() - - def reset(self): - self.reset_state() - - def reset_state(self): - self.carrier_want_idle = True - self.carrier_is_busy = False - self.carrier_is_idle = False - self.carrier_idle_ss = None - self.carrier_busy_ss = None - self.syncpad_fall_ss = None - - self.edges = None - self.symbols = None - self.sync_pads = None - self.data_bits = None - self.frame_bytes = None - self.short_bits = None - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.out_python = self.register(srd.OUTPUT_PYTHON) - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - self.span_prepare() - - def putg(self, ss, es, data): - cls = data[0] - if not _with_ann_carrier and cls in (ANN_CARRIER_BUSY, ANN_CARRIER_IDLE): - return - if not _with_ann_sync_loss and cls in (ANN_SYNC_LOSS,): - return - self.put(ss, es, self.out_ann, data) - - def putpy(self, ss, es, ptype, pdata): - self.put(ss, es, self.out_python, [ptype, pdata]) - - def symbols_clear(self): - syms = self.symbols or [] - self.symbols = [] - return syms - - def symbols_append(self, ss, es, symbol, data = None): - if self.symbols is None: - self.symbols = [] - item = (ss, es, symbol, data) - self.symbols.append(item) - - def symbols_get_last(self, count = None): - if not self.symbols: - return None - if count is None: - count = 1 - if len(self.symbols) < count: - return None - items = self.symbols[-count:] - if count == 1: - items = items[0] - return items - - def symbols_update_last(self, ss, es, symbol, data = None): - if not self.symbols: - return None - item = list(self.symbols[-1]) - if ss is not None: - item[0] = ss - if es is not None: - item[1] = es - if symbol is not None: - item[2] = symbol - if data is not None: - item[3] = data - self.symbols[-1] = tuple(item) - - def symbols_has_prev(self, want_items): - if not isinstance(want_items, (list, tuple,)): - want_items = [want_items] - if self.symbols is None: - return False - if len(self.symbols) < len(want_items): - return False - sym_off = len(self.symbols) - len(want_items) - for idx, want_item in enumerate(want_items): - if self.symbols[sym_off + idx][2] != want_item: - return False - return True - - def symbols_collapse(self, count, symbol, data = None, squeeze = None): - if self.symbols is None: - return None - if len(self.symbols) < count: - return None - self.symbols, last_data = self.symbols[:-count], self.symbols[-count:] - while squeeze and self.symbols and self.symbols[-1][2] == squeeze: - last_data.insert(0, self.symbols.pop()) - ss, es = last_data[0][0], last_data[-1][1] - if data is None: - data = last_data - item = (ss, es, symbol, data) - self.symbols.append(item) - - def frame_flush(self): - syms = self.symbols_clear() - while syms and syms[0][2] == 'IDLE': - syms.pop(0) - while syms and syms[-1][2] == 'IDLE': - syms.pop(-1) - if not syms: - return - text = [] - data = [] - for sym in syms: - if sym[2] == 'FRAME_INIT': - text.append('INIT') - data.append('INIT') - continue - if sym[2] == 'SYNC_PAD': - if not text or text[-1] != 'SYNC': - text.append('SYNC') - data.append('SYNC') - continue - if sym[2] == 'DATA_BYTE': - b = [bit[3] for bit in sym[3] if bit[2] == 'DATA_BIT'] - b = bitpack(b) - text.append('{:02x}'.format(b)) - data.append(b) - continue - if sym[2] == 'SHORT_BIT': - if not text or text[-1] != 'SHORT': - text.append('SHORT') - data.append('SHORT') - continue - if sym[2] == 'WAIT_ACK': - text.append('WAIT') - data.append('WAIT') - continue - text = ' '.join(text) - ss, es = syms[0][0], syms[-1][1] - self.putg(ss, es, [ANN_FRAME_BYTES, [text]]) - self.putpy(ss, es, 'FRAME_DATA', data) - - def carrier_flush(self): - # Force annotations if BUSY started, or if IDLE tracking started - # and kept running for long enough. This will be called before - # internal state reset, so we won't manipulate internal variables, - # and can afford to emit annotations which haven't met their - # proper end condition yet. - if self.carrier_busy_ss: - ss, es = self.carrier_busy_ss, self.samplenum - self.putg(ss, es, [ANN_CARRIER_BUSY, ['BUSY']]) - if self.carrier_idle_ss: - ss, es = self.carrier_idle_ss, self.samplenum - ss += int(self.idle_width) - if ss < es: - self.putg(ss, es, [ANN_CARRIER_IDLE, ['IDLE']]) - - def carrier_set_idle(self, on, ss, es): - if on: - # IDLE starts here, or continues. - if not self.carrier_idle_ss: - self.carrier_idle_ss = int(ss) - if not self.symbols_has_prev('IDLE'): - self.symbols_append(ss, ss, 'IDLE') - self.symbols_update_last(None, es, None) - # HACK We have seen an IDLE condition. This implementation - # loses details which are used to track IDLE, but it's more - # important to start accumulation of a new frame here. - self.frame_flush() - self.reset_state() - # end of HACK - self.carrier_is_idle = True - self.carrier_want_idle = False - return - # IDLE ends here. - if self.symbols_has_prev('IDLE'): - self.symbols_update_last(None, es, None) - self.carrier_flush() - self.carrier_is_idle = False - self.carrier_idle_ss = None - - def carrier_set_busy(self, on, snum): - self.carrier_is_busy = on - if on: - self.carrier_is_idle = None - if not self.carrier_busy_ss: - self.carrier_busy_ss = snum - return - if self.carrier_busy_ss: - self.putg(self.carrier_busy_ss, snum, [ANN_CARRIER_BUSY, ['BUSY']]) - self.carrier_busy_ss = None - self.carrier_is_busy = False - - def carrier_check(self, level, snum): - - # When HIGH is seen, immediately end IDLE and switch to BUSY. - if level: - self.carrier_set_idle(False, snum, snum) - self.carrier_set_busy(True, snum) - return - - # LOW is seen. Start tracking an IDLE period if not done yet. - if not self.carrier_idle_ss: - self.carrier_idle_ss = int(snum) - - # End BUSY when LOW persisted for an exact data byte's length. - # Start IDLE when LOW persisted for a data byte's length plus - # the user specified additional period. - span = snum - self.carrier_idle_ss - if span >= self.byte_width: - self.carrier_set_busy(False, snum) - if span >= self.idle_width: - self.carrier_set_idle(True, self.carrier_idle_ss + self.idle_width, snum) - - def span_prepare(self): - '''Prepare calculation of durations in terms of samples.''' - - # Determine samples per microsecond, and sample counts for - # several bit types, and sample count for a data byte's - # length, including optional extra time. Determine ranges - # for bit widths (tolerance margin). - - # Get times in microseconds. - mode_times = self.mode_times[self.options['mode']] - mode_times = [t * 1.0 for t in mode_times] - self.data_width, self.pad_width = mode_times - self.byte_width = self.pad_width + 9 * self.data_width - self.add_idle_width = self.options['idle_add_us'] - self.idle_width = self.byte_width + self.add_idle_width - - # Derive ranges (add tolerance) and scale to sample counts. - self.usec_width = self.samplerate / 1e6 - self.hold_high_width = 9 * self.time_tol_abs * self.usec_width - - def _get_range(width): - reladd = self.time_tol_perc / 100 - absadd = self.time_tol_abs - lower = min(width * (1 - reladd), width - absadd) - upper = max(width * (1 + reladd), width + absadd) - lower = floor(lower * self.usec_width) - upper = ceil(upper * self.usec_width) - return (lower, upper + 1) - - self.data_bit_1_range = _get_range(self.data_width * 1) - self.data_bit_2_range = _get_range(self.data_width * 2) - self.data_bit_3_range = _get_range(self.data_width * 3) - self.data_bit_4_range = _get_range(self.data_width * 4) - self.short_data_range = _get_range(self.data_width / 4) - self.pad_bit_range = _get_range(self.pad_width) - - self.data_width *= self.usec_width - self.pad_width *= self.usec_width - self.byte_width *= self.usec_width - self.idle_width *= self.usec_width - - self.lookahead_width = int(4 * self.data_width) - - def span_snum_to_us(self, count): - return count / self.usec_width - - def span_is_pad(self, span): - return span in range(*self.pad_bit_range) - - def span_is_data(self, span): - if span in range(*self.data_bit_1_range): - return 1 - if span in range(*self.data_bit_2_range): - return 2 - if span in range(*self.data_bit_3_range): - return 3 - if span in range(*self.data_bit_4_range): - return 4 - return False - - def span_is_short(self, span): - return span in range(*self.short_data_range) - - def wait_until(self, want): - '''Wait until a given location, but keep sensing carrier.''' - - # Implementor's note: Avoids skip values below 1. This version - # "may overshoot" by one sample. Which should be acceptable for - # this specific use case (can put the sample point of a bit time - # out of the center by some 4% under worst case conditions). - - want = int(want) - while True: - diff = max(want - self.samplenum, 1) - pins = self.wait([{PIN_DATA: 'e'}, {'skip': diff}]) - self.carrier_check(pins[PIN_DATA], self.samplenum) - if self.samplenum >= want: - return pins - # UNREACH - - def decode(self): - if not self.samplerate or self.samplerate < 1e6: - raise SamplerateError('Need a samplerate of at least 1MSa/s') - - # As a special case the first low period in the input capture is - # saught regardless of whether we can see its falling edge. This - # approach is also used to recover after synchronization was lost. - # - # The important condition here in the main loop is: Get the next - # edge's position, but time out after a maximum period of four - # data bits. This allows for the detection of SYNC pulses, also - # responds "soon enough" to DATA bits where edges can be few - # within a data byte. Also avoids excessive waits for unexpected - # communication errors. - # - # DATA bits within a byte are taken at fixed intervals relative - # to the SYNC-PAD's falling edge. It's essential to check the - # carrier at every edge, also during DATA bit sampling. Simple - # skips to the desired sample point could break that feature. - while True: - - # Help kick-start the IDLE condition detection after - # decoder state reset. - if not self.edges: - curr_level, = self.wait({PIN_DATA: 'l'}) - self.carrier_check(curr_level, self.samplenum) - self.edges = [self.samplenum] - continue - - # Advance to the next edge, or over a medium span without an - # edge. Prepare to classify the distance to derive bit types - # from these details. - last_snum = self.samplenum - curr_level, = self.wait([{PIN_DATA: 'e'}, {'skip': self.lookahead_width}]) - self.carrier_check(curr_level, self.samplenum) - bit_level = curr_level - edge_seen = self.matched[0] - if edge_seen: - bit_level = 1 - bit_level - if not self.edges: - self.edges = [self.samplenum] - continue - self.edges.append(self.samplenum) - curr_snum = self.samplenum - - # Check bit width (can also be multiple data bits). - span = self.edges[-1] - self.edges[-2] - is_pad = bit_level and self.span_is_pad(span) - is_data = self.span_is_data(span) - is_short = bit_level and self.span_is_short(span) - - if is_pad: - # BEWARE! Use ss value of last edge (genuinely seen, or - # inserted after a DATA byte) for PAD bit annotations. - ss, es = self.edges[-2], curr_snum - texts = ['PAD', '{:d}'.format(bit_level)] - self.putg(ss, es, [ANN_PAD_BIT, texts]) - self.symbols_append(ss, es, 'PAD_BIT', bit_level) - ss, es = self.symbols_get_last()[:2] - self.putpy(ss, es, 'PAD_BIT', bit_level) - continue - - if is_short: - ss, es = last_snum, curr_snum - texts = ['SHORT', '{:d}'.format(bit_level)] - self.putg(ss, es, [ANN_SHORT_DATA, texts]) - self.symbols_append(ss, es, 'SHORT_BIT', bit_level) - ss, es = self.symbols_get_last()[:2] - self.putpy(ss, es, 'SHORT_BIT', bit_level) - continue - - # Force IDLE period check when the decoder seeks to sync - # to the input data stream. - if not bit_level and not self.symbols and self.carrier_want_idle: - continue - - # Accept arbitrary length LOW phases after DATA bytes(!) or - # SHORT pulses, but not within a DATA byte or SYNC-PAD etc. - # This covers the late start of the next SYNC-PAD (byte of - # a frame, or ACK byte after a frame, or the start of the - # next frame). - if not bit_level: - if self.symbols_has_prev('DATA_BYTE'): - continue - if self.symbols_has_prev('SHORT_BIT'): - continue - if self.symbols_has_prev('WAIT_ACK'): - continue - - # Get (consume!) the LOW DATA bit after a PAD. - took_low = False - if is_data and not bit_level and self.symbols_has_prev('PAD_BIT'): - took_low = True - is_data -= 1 - next_snum = int(last_snum + self.data_width) - ss, es = last_snum, next_snum - texts = ['ZERO', '{:d}'.format(bit_level)] - self.putg(ss, es, [ANN_LOW_BIT, texts]) - self.symbols_append(ss, es, 'ZERO_BIT', bit_level) - ss, es = self.symbols_get_last()[:2] - self.putpy(ss, es, 'DATA_BIT', bit_level) - self.data_fall_time = last_snum - last_snum = next_snum - # Turn the combination of PAD and LOW DATA into SYNC-PAD. - # Start data bit accumulation after a SYNC-PAD was seen. - sync_pad_seq = ['PAD_BIT', 'ZERO_BIT'] - if self.symbols_has_prev(sync_pad_seq): - self.symbols_collapse(len(sync_pad_seq), 'SYNC_PAD') - ss, es = self.symbols_get_last()[:2] - self.putpy(ss, es, 'SYNC_PAD', True) - self.data_bits = [] - # Turn three subsequent SYNC-PAD into FRAME-INIT. Start the - # accumulation of frame bytes when FRAME-INIT was seen. - frame_init_seq = 3 * ['SYNC_PAD'] - if self.symbols_has_prev(frame_init_seq): - self.symbols_collapse(len(frame_init_seq), 'FRAME_INIT') - # Force a flush of the previous frame after we have - # reliably detected the start of another one. This is a - # workaround for this decoder's inability to detect the - # end of a frame after an ACK was seen or byte counts - # have been reached. We cannot assume perfect input, - # thus we leave all interpretation of frame content to - # upper layers. Do keep the recently queued FRAME_INIT - # symbol across the flush operation. - if len(self.symbols) > 1: - keep = self.symbols.pop(-1) - self.frame_flush() - self.symbols.clear() - self.symbols.append(keep) - ss, es = self.symbols_get_last()[:2] - texts = ['FRAME INIT', 'INIT', 'I'] - self.putg(ss, es, [ANN_FRAME_INIT, texts]) - self.putpy(ss, es, 'FRAME_INIT', True) - self.frame_bytes = [] - # Collapse SYNC-PAD after SHORT+ into a WAIT-ACK. Include - # all leading SHORT bits in the WAIT as well. - wait_ack_seq = ['SHORT_BIT', 'SYNC_PAD'] - if self.symbols_has_prev(wait_ack_seq): - self.symbols_collapse(len(wait_ack_seq), 'WAIT_ACK', - squeeze = 'SHORT_BIT') - ss, es = self.symbols_get_last()[:2] - texts = ['WAIT for sync response', 'WAIT response', 'WAIT', 'W'] - self.putg(ss, es, [ANN_FRAME_WAIT, texts]) - self.putpy(ss, es, 'SYNC_RESP_WAIT', True) - if took_low and not is_data: - # Start at the very next edge if we just consumed a LOW - # after a PAD bit, and the DATA bit count is exhausted. - # This improves robustness, deals with inaccurate edge - # positions. (Motivated by real world captures, the spec - # would not discuss bit time tolerances.) - continue - - # When we get here, the only remaining (the only supported) - # activity is the collection of a data byte's DATA bits. - # These are not taken by the main loop's "edge search, with - # a timeout" approach, which is "too tolerant". Instead all - # DATA bits get sampled at a fixed interval and relative to - # the SYNC-PAD's falling edge. We expect to have seen the - # data byte' SYNC-PAD before. If we haven't, the decoder is - # not yet synchronized to the input data. - if not is_data: - fast_cont = edge_seen and curr_level - ss, es = last_snum, curr_snum - texts = ['failed pulse length check', 'pulse length', 'length'] - self.putg(ss, es, [ANN_SYNC_LOSS, texts]) - self.frame_flush() - self.carrier_flush() - self.reset_state() - if fast_cont: - self.edges = [self.samplenum] - continue - if not self.symbols_has_prev('SYNC_PAD'): - # Fast reponse to the specific combination of: no-sync, - # edge seen, and current high level. In this case we - # can reset internal state, but also can continue the - # interpretation right after the most recently seen - # rising edge, which could start the next PAD time. - # Otherwise continue slow interpretation after reset. - fast_cont = edge_seen and curr_level - self.frame_flush() - self.carrier_flush() - self.reset_state() - if fast_cont: - self.edges = [self.samplenum] - continue - - # The main loop's "edge search with period timeout" approach - # can have provided up to three more DATA bits after the LOW - # bit of the SYNC-PAD. Consume them immediately in that case, - # otherwise .wait() for their sample point. Stick with float - # values for bit sample points and bit time boundaries for - # improved accuracy, only round late to integers when needed. - bit_field = [] - bit_ss = self.data_fall_time + self.data_width - for bit_idx in range(8): - bit_es = bit_ss + self.data_width - bit_snum = (bit_es + bit_ss) / 2 - if bit_snum > self.samplenum: - bit_level, = self.wait_until(bit_snum) - ss, es = ceil(bit_ss), floor(bit_es) - texts = ['{:d}'.format(bit_level)] - self.putg(ss, es, [ANN_DATA_BIT, texts]) - self.symbols_append(ss, es, 'DATA_BIT', bit_level) - ss, es = self.symbols_get_last()[:2] - self.putpy(ss, es, 'DATA_BIT', bit_level) - bit_field.append(bit_level) - if self.data_bits is not None: - self.data_bits.append(bit_level) - bit_ss = bit_es - end_snum = bit_es - curr_level, = self.wait_until(end_snum) - curr_snum = self.samplenum - - # We are at the exact _calculated_ boundary of the last DATA - # bit time. Improve robustness for those situations where - # the transmitter's and the sender's timings differ within a - # margin, and the transmitter may hold the last DATA bit's - # HIGH level for a little longer. - # - # When no falling edge is seen within the maximum tolerance - # for the last DATA bit, then this could be the combination - # of a HIGH DATA bit and a PAD bit without a LOW in between. - # Fake an edge in that case, to re-use existing code paths. - # Make sure to keep referencing times to the last SYNC pad's - # falling edge. This is the last reliable condition we have. - if curr_level: - hold = self.hold_high_width - curr_level, = self.wait([{PIN_DATA: 'l'}, {'skip': int(hold)}]) - self.carrier_check(curr_level, self.samplenum) - if self.matched[1]: - self.edges.append(curr_snum) - curr_level = 1 - curr_level - curr_snum = self.samplenum - - # Get the byte value from the bits (when available). - # TODO Has the local 'bit_field' become obsolete, or should - # self.data_bits go away? - data_byte = bitpack(bit_field) - if self.data_bits is not None: - data_byte = bitpack(self.data_bits) - self.data_bits.clear() - if self.frame_bytes is not None: - self.frame_bytes.append(data_byte) - - # Turn a sequence of a SYNC-PAD and eight DATA bits into a - # DATA-BYTE symbol. - byte_seq = ['SYNC_PAD'] + 8 * ['DATA_BIT'] - if self.symbols_has_prev(byte_seq): - self.symbols_collapse(len(byte_seq), 'DATA_BYTE') - ss, es = self.symbols_get_last()[:2] - texts = ['{:02x}'.format(data_byte)] - self.putg(ss, es, [ANN_DATA_BYTE, texts]) - self.putpy(ss, es, 'DATA_BYTE', data_byte) - - # Optionally terminate the accumulation of a frame when a - # WAIT-ACK period was followed by a DATA-BYTE? This could - # flush the current packet before the next FRAME-INIT or - # IDLE are seen, and increases usability for short input - # data (aggressive trimming). It won't help when WAIT is - # not seen, though. - sync_resp_seq = ['WAIT_ACK'] + ['DATA_BYTE'] - if self.symbols_has_prev(sync_resp_seq): - self.frame_flush() diff --git a/decoders/pjon/__init__.py b/decoders/pjon/__init__.py deleted file mode 100644 index 579fb591..00000000 --- a/decoders/pjon/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 Gerhard Sittig -## -## 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, see . -## - -''' -This protocol decoder interprets the PJON protocol on top of the PJDL -link layer (and potentially other link layers). -''' - -from .pd import Decoder diff --git a/decoders/pjon/pd.py b/decoders/pjon/pd.py deleted file mode 100644 index b23cfb84..00000000 --- a/decoders/pjon/pd.py +++ /dev/null @@ -1,603 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 Gerhard Sittig -## -## 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, see . -## - -# See the https://www.pjon.org/ PJON project page and especially the -# https://www.pjon.org/PJON-protocol-specification-v3.2.php protocol -# specification, which can use different link layers. - -# TODO -# - Check for the correct order of optional fields (the spec is not as -# explicit on these details as I'd expect). -# - Check decoder's robustness, completeness, and correctness when more -# captures become available. Currently there are only few, which only -# cover minimal communication, and none of the protocol's flexibility. -# The decoder was essentially written based on the available docs, and -# then took some arbitrary choices and liberties to cope with real life -# data from an example setup. Strictly speaking this decoder violates -# the spec, and errs towards the usability side. - -import sigrokdecode as srd -import struct - -ANN_RX_INFO, ANN_HDR_CFG, ANN_PKT_LEN, ANN_META_CRC, ANN_TX_INFO, \ -ANN_SVC_ID, ANN_PKT_ID, ANN_ANON_DATA, ANN_PAYLOAD, ANN_END_CRC, \ -ANN_SYN_RSP, \ -ANN_RELATION, \ -ANN_WARN, \ - = range(13) - -def calc_crc8(data): - crc = 0 - for b in data: - crc ^= b - for i in range(8): - odd = crc % 2 - crc >>= 1 - if odd: - crc ^= 0x97 - return crc - -def calc_crc32(data): - crc = 0xffffffff - for b in data: - crc ^= b - for i in range(8): - odd = crc % 2 - crc >>= 1 - if odd: - crc ^= 0xedb88320 - crc ^= 0xffffffff - return crc - -class Decoder(srd.Decoder): - api_version = 3 - id = 'pjon' - name = 'PJON' - longname = 'PJON' - desc = 'The PJON protocol.' - license = 'gplv2+' - inputs = ['pjon_link'] - outputs = [] - tags = ['Embedded/industrial'] - annotations = ( - ('rx_info', 'Receiver ID'), - ('hdr_cfg', 'Header config'), - ('pkt_len', 'Packet length'), - ('meta_crc', 'Meta CRC'), - ('tx_info', 'Sender ID'), - ('port', 'Service ID'), - ('pkt_id', 'Packet ID'), - ('anon', 'Anonymous data'), - ('payload', 'Payload'), - ('end_crc', 'End CRC'), - ('syn_rsp', 'Sync response'), - ('relation', 'Relation'), - ('warning', 'Warning'), - ) - annotation_rows = ( - ('fields', 'Fields', ( - ANN_RX_INFO, ANN_HDR_CFG, ANN_PKT_LEN, ANN_META_CRC, ANN_TX_INFO, - ANN_SVC_ID, ANN_ANON_DATA, ANN_PAYLOAD, ANN_END_CRC, ANN_SYN_RSP, - )), - ('relations', 'Relations', (ANN_RELATION,)), - ('warnings', 'Warnings', (ANN_WARN,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.reset_frame() - - def reset_frame(self): - self.frame_ss = None - self.frame_es = None - self.frame_rx_id = None - self.frame_tx_id = None - self.frame_payload_text = None - self.frame_bytes = None - self.frame_has_ack = None - self.ack_bytes = None - self.ann_ss = None - self.ann_es = None - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putg(self, ss, es, ann, data): - self.put(ss, es, self.out_ann, [ann, data]) - - def frame_flush(self): - if not self.frame_bytes: - return - if not self.frame_ss or not self.frame_es: - return - - # Emit "communication relation" details. - # TODO Include the service ID (port number) as well? - text = [] - if self.frame_rx_id is not None: - text.append("RX {}".format(self.frame_rx_id[-1])) - if self.frame_tx_id is not None: - text.append("TX {}".format(self.frame_tx_id[-1])) - if self.frame_payload_text is not None: - text.append("DATA {}".format(self.frame_payload_text)) - if self.frame_has_ack is not None: - text.append("ACK {:02x}".format(self.frame_has_ack)) - if text: - text = " - ".join(text) - self.putg(self.frame_ss, self.frame_es, ANN_RELATION, [text]) - - def handle_field_get_desc(self, idx = None): - '''Lookup description of a PJON frame field.''' - if not self.field_desc: - return None - if idx is None: - idx = self.field_desc_idx - if idx >= 0 and idx >= len(self.field_desc): - return None - if idx < 0 and abs(idx) > len(self.field_desc): - return None - desc = self.field_desc[idx] - return desc - - def handle_field_add_desc(self, fmt, hdl, cls = None): - '''Register description for a PJON frame field.''' - item = { - 'format': fmt, - 'width': struct.calcsize(fmt), - 'handler': hdl, - 'anncls': cls, - } - self.field_desc.append(item) - - def handle_field_seed_desc(self): - '''Seed list of PJON frame fields' descriptions.''' - - # At the start of a PJON frame, the layout of only two fields - # is known. Subsequent fields (their presence, and width) depend - # on the content of the header config field. - - self.field_desc = [] - self.handle_field_add_desc(' 15 and not self.cfg_crc32: - warn_texts.append('length above 15 needs CRC32') - if pl_len < 1: - warn_texts.append('suspicious payload length') - pl_len = 0 - if warn_texts: - warn_texts = ', '.join(warn_texts) - self.putg(self.ann_ss, self.ann_es, ANN_WARN, [warn_texts]) - pl_fmt = '>{:d}B'.format(pl_len) - - desc = self.handle_field_get_desc(-2) - desc['format'] = pl_fmt - desc['width'] = struct.calcsize(pl_fmt) - - # Have the caller emit the annotation for the packet length. - # Provide information of different detail level for zooming. - texts = [ - 'LENGTH {:d} (PAYLOAD {:d})'.format(pkt_len, pl_len), - 'LEN {:d} (PL {:d})'.format(pkt_len, pl_len), - '{:d} ({:d})'.format(pkt_len, pl_len), - '{:d}'.format(pkt_len), - ] - return texts - - def handle_field_common_crc(self, have, is_meta): - '''Process a CRC field of a PJON frame.''' - - # CRC algorithm and width are configurable, and can differ - # across meta and end checksums in a frame's fields. - caption = 'META' if is_meta else 'END' - crc_len = 8 if is_meta else 32 if self.cfg_crc32 else 8 - crc_bytes = crc_len // 8 - crc_fmt = '{:08x}' if crc_len == 32 else '{:02x}' - have_text = crc_fmt.format(have) - - # Check received against expected checksum. Emit warnings. - warn_texts = [] - data = self.frame_bytes[:-crc_bytes] - want = calc_crc32(data) if crc_len == 32 else calc_crc8(data) - if want != have: - want_text = crc_fmt.format(want) - warn_texts.append('CRC mismatch - want {} have {}'.format(want_text, have_text)) - if warn_texts: - warn_texts = ', '.join(warn_texts) - self.putg(self.ann_ss, self.ann_es, ANN_WARN, [warn_texts]) - - # Provide text representation for frame field, caller emits - # the annotation. - texts = [ - '{}_CRC {}'.format(caption, have_text), - 'CRC {}'.format(have_text), - have_text, - ] - return texts - - def handle_field_meta_crc(self, b): - '''Process initial CRC (meta) field of a PJON frame.''' - # Caller provides a list of values. We want a single scalar. - b = b[0] - return self.handle_field_common_crc(b, True) - - def handle_field_end_crc(self, b): - '''Process end CRC (total frame) field of a PJON frame.''' - # Caller provides a list of values. We want a single scalar. - b = b[0] - return self.handle_field_common_crc(b, False) - - def handle_field_common_bus(self, b): - '''Common handling of bus ID details. Used for RX and TX.''' - bus_id = b[:4] - bus_num = struct.unpack('>L', bytearray(bus_id)) - bus_txt = '.'.join(['{:d}'.format(b) for b in bus_id]) - return bus_num, bus_txt - - def handle_field_rx_bus(self, b): - '''Process receiver bus ID field of a PJON frame.''' - - # When we get here, there always should be an RX ID already. - bus_num, bus_txt = self.handle_field_common_bus(b[:4]) - rx_txt = "{} {}".format(bus_txt, self.frame_rx_id[-1]) - self.frame_rx_id = (bus_num, self.frame_rx_id[0], rx_txt) - - # Provide text representation for frame field, caller emits - # the annotation. - texts = [ - 'RX_BUS {}'.format(bus_txt), - bus_txt, - ] - return texts - - def handle_field_tx_bus(self, b): - '''Process transmitter bus ID field of a PJON frame.''' - - # The TX ID field is optional, as is the use of bus ID fields. - # In the TX info case the TX bus ID is seen before the TX ID. - bus_num, bus_txt = self.handle_field_common_bus(b[:4]) - self.frame_tx_id = (bus_num, None, bus_txt) - - # Provide text representation for frame field, caller emits - # the annotation. - texts = [ - 'TX_BUS {}'.format(bus_txt), - bus_txt, - ] - return texts - - def handle_field_tx_id(self, b): - '''Process transmitter ID field of a PJON frame.''' - - b = b[0] - - id_txt = "{:d}".format(b) - if self.frame_tx_id is None: - self.frame_tx_id = (b, id_txt) - else: - tx_txt = "{} {}".format(self.frame_tx_id[-1], id_txt) - self.frame_tx_id = (self.frame_tx_id[0], b, tx_txt) - - # Provide text representation for frame field, caller emits - # the annotation. - texts = [ - 'TX_ID {}'.format(id_txt), - id_txt, - ] - return texts - - def handle_field_payload(self, b): - '''Process payload data field of a PJON frame.''' - - text = ' '.join(['{:02x}'.format(v) for v in b]) - self.frame_payload = b[:] - self.frame_payload_text = text - - texts = [ - 'PAYLOAD {}'.format(text), - text, - ] - return texts - - def handle_field_sync_resp(self, b): - '''Process synchronous response for a PJON frame.''' - - self.frame_has_ack = b - - texts = [ - 'ACK {:02x}'.format(b), - '{:02x}'.format(b), - ] - return texts - - def decode(self, ss, es, data): - ptype, pdata = data - - # Start frame bytes accumulation when FRAME_INIT is seen. Flush - # previously accumulated frame bytes when a new frame starts. - if ptype == 'FRAME_INIT': - self.frame_flush() - self.reset_frame() - self.frame_bytes = [] - self.handle_field_seed_desc() - self.frame_ss = ss - self.frame_es = es - return - - # Use IDLE as another (earlier) trigger to flush frames. Also - # trigger flushes on FRAME-DATA which mean that the link layer - # inspection has seen the end of a protocol frame. - # - # TODO Improve usability? Emit warnings for PJON frames where - # FRAME_DATA was seen but FRAME_INIT wasn't? So that users can - # become aware of broken frames. - if ptype in ('IDLE', 'FRAME_DATA'): - self.frame_flush() - self.reset_frame() - return - - # Switch from data bytes to response bytes when WAIT is seen. - if ptype == 'SYNC_RESP_WAIT': - self.ack_bytes = [] - self.ann_ss, self.ann_es = None, None - return - - # Accumulate data bytes as they arrive. Put them in the bucket - # which corresponds to its most recently seen leader. - if ptype == 'DATA_BYTE': - b = pdata - self.frame_es = es - - # Are we collecting response bytes (ACK)? - if self.ack_bytes is not None: - if not self.ann_ss: - self.ann_ss = ss - self.ack_bytes.append(b) - self.ann_es = es - text = self.handle_field_sync_resp(b) - if text: - self.putg(self.ann_ss, self.ann_es, ANN_SYN_RSP, text) - self.ann_ss, self.ann_es = None, None - return - - # Are we collecting frame content? - if self.frame_bytes is not None: - if not self.ann_ss: - self.ann_ss = ss - self.frame_bytes.append(b) - self.ann_es = es - - # Has the field value become available yet? - desc = self.handle_field_get_desc() - if not desc: - return - width = desc.get('width', None) - if not width: - return - self.field_desc_got += 1 - if self.field_desc_got != width: - return - - # Grab most recent received field as a byte array. Get - # the values that it contains. - fmt = desc.get('format', '>B') - raw = bytearray(self.frame_bytes[-width:]) - values = struct.unpack(fmt, raw) - - # Process the value, and get its presentation. Can be - # mere formatting, or serious execution of logic. - hdl = desc.get('handler', '{!r}') - if isinstance(hdl, str): - text = [hdl.format(*values)] - elif isinstance(hdl, (list, tuple)): - text = [f.format(*values) for f in hdl] - elif hdl: - text = hdl(values) - cls = desc.get('anncls', ANN_ANON_DATA) - - # Emit annotation unless the handler routine already did. - if cls is not None and text: - self.putg(self.ann_ss, self.ann_es, cls, text) - self.ann_ss, self.ann_es = None, None - - # Advance scan position for to-get-received field. - self.field_desc_idx += 1 - self.field_desc_got = 0 - return - - # Unknown phase, not collecting. Not synced yet to the input? - return - - # Unknown or unhandled kind of link layer output. - return diff --git a/decoders/ps2/__init__.py b/decoders/ps2/__init__.py deleted file mode 100755 index 75c47687..00000000 --- a/decoders/ps2/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2016 Daniel Schulte -## -## 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, see . -## - -''' -This protocol decoder can decode PS/2 device -> host communication. - -Host -> device communication is currently not supported. -''' - -from .pd import Decoder diff --git a/decoders/ps2/pd.py b/decoders/ps2/pd.py deleted file mode 100755 index fc6972bb..00000000 --- a/decoders/ps2/pd.py +++ /dev/null @@ -1,193 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2016 Daniel Schulte -## Copyright (C) 2019 DreamSourceLab -## -## 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, see . -## - -import sigrokdecode as srd -from collections import namedtuple - -class Ann: - BIT, HSTART, DSTART, STOP, PARITY_OK, PARITY_ERR, DATA, WORD, ACK = range(9) - -Bit = namedtuple('Bit', 'val ss es') - -class Decoder(srd.Decoder): - api_version = 3 - id = 'ps2' - name = 'PS/2' - longname = 'PS/2' - desc = 'PS/2 keyboard/mouse interface.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['PC'] - channels = ( - {'id': 'clk', 'type': 0, 'name': 'Clock', 'desc': 'Clock line'}, - {'id': 'data', 'type': 107, 'name': 'Data', 'desc': 'Data line'}, - ) - options = ( - {'id': 'HtoD_Clock', 'desc': 'HtoD_Clock', - 'default': 'rise', 'values': ('rise', 'fall')}, - {'id': 'DtoH_Clock', 'desc': 'DtoH_Clock', - 'default': 'fall', 'values': ('fall', 'rise')}, - ) - annotations = ( - ('207', 'bit', 'Bit'), - ('109', 'HSTART', 'HSTART'), - ('50', 'DSTART', 'DSTART'), - ('1000', 'stop-bit', 'Stop bit'), - ('7', 'parity-ok', 'Parity OK bit'), - ('1000', 'parity-err', 'Parity error bit'), - ('40', 'data-bit', 'Data bit'), - ('65', 'word', 'Word'), - ('75', 'ACK', 'ACK'), - ) - annotation_rows = ( - ('bits', 'Bits', (0,)), - ('fields', 'Fields', (1, 2, 3, 4, 5, 6, 7, 8)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.bits = [] - self.samplenum = 0 - self.bitcount = 0 - self.state = 'NULL' - self.ss = self.es = 0 - self.HtoDss = 0 - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.HtoD = 1 if self.options['HtoD_Clock'] == 'rise' else 0 - self.DtoH = 1 if self.options['DtoH_Clock'] == 'fall' else 0 - def putb(self, bit, ann_idx): - b = self.bits[bit] - self.put(b.ss, b.es, self.out_ann, [ann_idx, [str(b.val)]]) - - def putx(self, bit, ann): - self.put(self.bits[bit].ss, self.bits[bit].es, self.out_ann, ann) - - def handle_bits(self, datapin): - # Ignore non start condition bits (useful during keyboard init). - if self.bitcount == 0 and datapin == 1: - self.state = 'HtoD' - (clock_pin, datapin) = self.wait({0: 'r'}) - - - # Store individual bits and their start/end samplenumbers. - self.bits.append(Bit(datapin, self.samplenum, self.samplenum)) - - # Fix up end sample numbers of the bits. - if self.bitcount > 0: - b = self.bits[self.bitcount - 1] - self.bits[self.bitcount - 1] = Bit(b.val, b.ss, self.samplenum) - if self.bitcount == 11: - self.bitwidth = self.bits[1].es - self.bits[2].es - b = self.bits[-1] - self.bits[-1] = Bit(b.val, b.ss, b.es + self.bitwidth) - - # Find all 11 bits. Start + 8 data + odd parity + stop. - if self.bitcount < 11: - self.bitcount += 1 - return - - # Extract data word. - word = 0 - for i in range(8): - word |= (self.bits[i + 1].val << i) - - # Calculate parity. - parity_ok = (bin(word).count('1') + self.bits[9].val) % 2 == 1 - - # Emit annotations. - for i in range(11): - self.putb(i, Ann.BIT) - if self.state == 'HtoD': - self.putx(0, [Ann.HSTART, ['Host Start', 'HStart', 'HS']]) - if self.state == 'DtoH': - self.putx(0, [Ann.DSTART, ['Device Start', 'Device', 'DS']]) - self.put(self.bits[1].ss, self.bits[8].es, self.out_ann, [Ann.WORD, - ['Data: %02x' % word, 'D: %02x' % word, '%02x' % word]]) - if parity_ok: - self.putx(9, [Ann.PARITY_OK, ['Parity OK', 'Par OK', 'P']]) - else: - self.putx(9, [Ann.PARITY_ERR, ['Parity error', 'Par err', 'PE']]) - self.putx(10, [Ann.STOP, ['Stop bit', 'Stop', 'St', 'T']]) - - self.bits, self.bitcount = [], 0 - self.state == 'NULL' - - def decode(self): - while True: - # Sample data bits on falling clock edge. - if self.bitcount == 0: - if self.HtoDss : - self.state = 'HtoD' - (clock_pin, data_pin) = self.wait({0: 'r',1: 'l'}) - self.handle_bits(data_pin) - (clock_pin, data_pin) = self.wait({0: 'f'}) - else: - (clock_pin, data_pin) = self.wait([{0: 'f',1: 'r'},{0: 'f',1: 'f'},{0: 'f',1: 'h'},{0: 'f',1: 'l'}]) - if (self.matched & (0b1 << 0)): - continue - if (self.matched & (0b1 << 1)): - self.state = 'HtoD' - (clock_pin, data_pin) = self.wait({0: 'r',1: 'l'}) - self.handle_bits(data_pin) - (clock_pin, data_pin) = self.wait({0: 'f'}) - if (self.matched & (0b1 << 2)): - self.state = 'HtoD' - (clock_pin, data_pin) = self.wait({0: 'r',1: 'l'}) - self.handle_bits(data_pin) - (clock_pin, data_pin) = self.wait({0: 'f'}) - if (self.matched & (0b1 << 3)): - self.state = 'DtoH' - self.handle_bits(data_pin) - if self.state == 'HtoD': - if self.HtoD : - (clock_pin, data_pin) = self.wait({0: 'r'}) - else: - (clock_pin, data_pin) = self.wait({0: 'f'}) - self.handle_bits(data_pin) - if (self.bitcount == 10): - (clock_pin, data_pin) = self.wait({0: 'r'}) - self.handle_bits(data_pin) - if (self.bitcount == 11): - (clock_pin, data_pin) = self.wait({0: 'f'}) - self.handle_bits(data_pin) - self.ss = self.samplenum - (clock_pin, data_pin) = self.wait({0: 'r'}) - self.es = self.samplenum - self.put(self.ss,self.es,self.out_ann,[Ann.ACK, ['ACK', 'ACK', 'ACK', 'A']]) - self.HtoDss = 0 - if self.state == 'DtoH': - if self.DtoH : - (clock_pin, data_pin) = self.wait({0: 'f'}) - else: - (clock_pin, data_pin) = self.wait({0: 'r'}) - self.handle_bits(data_pin) - if (self.bitcount == 11): - (clock_pin, data_pin) = self.wait([{1: 'f'},{0: 'r'}]) - if (self.matched & (0b1 << 0)): - self.handle_bits(data_pin) - self.HtoDss = 1 - if (self.matched & (0b1 << 1)): - self.handle_bits(data_pin) - self.HtoDss = 0 \ No newline at end of file diff --git a/decoders/pwm/__init__.py b/decoders/pwm/__init__.py deleted file mode 100755 index 8f039766..00000000 --- a/decoders/pwm/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Torsten Duwe -## -## 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, see . -## - -''' -Pulse-width modulation (PWM) a.k.a pulse-duration modulation (PDM) decoder. -''' - -from .pd import Decoder diff --git a/decoders/pwm/pd.py b/decoders/pwm/pd.py deleted file mode 100755 index d8626ee0..00000000 --- a/decoders/pwm/pd.py +++ /dev/null @@ -1,141 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Torsten Duwe -## Copyright (C) 2014 Sebastien Bourdelin -## -## 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, see . -## - -import sigrokdecode as srd - -class SamplerateError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = 'pwm' - name = 'PWM' - longname = 'Pulse-width modulation' - desc = 'Analog level encoded in duty cycle percentage.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Encoding'] - channels = ( - {'id': 'data', 'name': 'Data', 'desc': 'Data line'}, - ) - options = ( - {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-high', - 'values': ('active-low', 'active-high')}, - ) - annotations = ( - ('duty-cycle', 'Duty cycle'), - ('period', 'Period'), - ) - annotation_rows = ( - ('duty-cycle', 'Duty cycle', (0,)), - ('period', 'Period', (1,)), - ) - binary = ( - ('raw', 'RAW file'), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.ss_block = self.es_block = None - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.out_binary = self.register(srd.OUTPUT_BINARY) - self.out_average = \ - self.register(srd.OUTPUT_META, - meta=(float, 'Average', 'PWM base (cycle) frequency')) - - def putx(self, data): - self.put(self.ss_block, self.es_block, self.out_ann, data) - - def putp(self, period_t): - # Adjust granularity. - if period_t == 0 or period_t >= 1: - period_s = '%.1f s' % (period_t) - elif period_t <= 1e-12: - period_s = '%.1f fs' % (period_t * 1e15) - elif period_t <= 1e-9: - period_s = '%.1f ps' % (period_t * 1e12) - elif period_t <= 1e-6: - period_s = '%.1f ns' % (period_t * 1e9) - elif period_t <= 1e-3: - period_s = '%.1f μs' % (period_t * 1e6) - else: - period_s = '%.1f ms' % (period_t * 1e3) - - self.put(self.ss_block, self.es_block, self.out_ann, [1, [period_s]]) - - def putb(self, data): - self.put(self.ss_block, self.es_block, self.out_binary, data) - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - - num_cycles = 0 - average = 0 - - # Wait for an "active" edge (depends on config). This starts - # the first full period of the inspected signal waveform. - self.wait({0: 'f' if self.options['polarity'] == 'active-low' else 'r'}) - self.first_samplenum = self.samplenum - - # Keep getting samples for the period's middle and terminal edges. - # At the same time that last sample starts the next period. - while True: - - # Get the next two edges. Setup some variables that get - # referenced in the calculation and in put() routines. - start_samplenum = self.samplenum - self.wait({0: 'e'}) - end_samplenum = self.samplenum - self.wait({0: 'e'}) - self.ss_block = start_samplenum - self.es_block = self.samplenum - - # Calculate the period, the duty cycle, and its ratio. - period = self.samplenum - start_samplenum - duty = end_samplenum - start_samplenum - ratio = float(duty / period) - - # Report the duty cycle in percent. - percent = float(ratio * 100) - self.putx([0, ['%f%%' % percent]]) - - # Report the duty cycle in the binary output. - self.putb([0, bytes([int(ratio * 256)])]) - - # Report the period in units of time. - period_t = float(period / self.samplerate) - self.putp(period_t) - - # Update and report the new duty cycle average. - num_cycles += 1 - average += percent - self.put(self.first_samplenum, self.es_block, self.out_average, - float(average / num_cycles)) diff --git a/decoders/qi/__init__.py b/decoders/qi/__init__.py deleted file mode 100755 index 0d49d17b..00000000 --- a/decoders/qi/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Josef Gajdusek -## -## 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, see . -## - -''' -This decoder decodes demodulated data streams used by the Qi standard -for communication from the receiver to the charging station. -''' - -from .pd import Decoder diff --git a/decoders/qi/pd.py b/decoders/qi/pd.py deleted file mode 100755 index b750d9ce..00000000 --- a/decoders/qi/pd.py +++ /dev/null @@ -1,244 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Josef Gajdusek -## -## 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, see . -## - -import sigrokdecode as srd -import operator -import collections -from functools import reduce - -end_codes = ( - 'Unknown', - 'Charge Complete', - 'Internal Fault', - 'Over Temperature', - 'Over Voltage', - 'Over Current', - 'Battery Failure', - 'Reconfigure', - 'No Response', -) - -class SamplerateError(Exception): - pass - -def calc_checksum(packet): - return reduce(operator.xor, packet[:-1]) - -def bits_to_uint(bits): - # LSB first - return reduce(lambda i, v: (i >> 1) | (v << (len(bits) - 1)), bits, 0) - -class Decoder(srd.Decoder): - api_version = 3 - id = 'qi' - name = 'Qi' - longname = 'Qi charger protocol' - desc = 'Protocol used by Qi receiver.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Embedded/industrial', 'Wireless/RF'] - channels = ( - {'id': 'qi', 'name': 'Qi', 'desc': 'Demodulated Qi data line'}, - ) - annotations = ( - ('bits', 'Bits'), - ('bytes-errors', 'Bit errors'), - ('bytes-start', 'Start bits'), - ('bytes-info', 'Info bits'), - ('bytes-data', 'Data bytes'), - ('packets-data', 'Packet data'), - ('packets-checksum-ok', 'Packet checksum'), - ('packets-checksum-err', 'Packet checksum'), - ) - annotation_rows = ( - ('bits', 'Bits', (0,)), - ('bytes', 'Bytes', (1, 2, 3, 4)), - ('packets', 'Packets', (5, 6, 7)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.reset_variables() - - def reset_variables(self): - self.counter = 0 - self.prev = None - self.state = 'IDLE' - self.lastbit = 0 - self.bytestart = 0 - self.deq = collections.deque(maxlen = 2) - self.bits = [] - self.bitsi = [0] - self.bytesi = [] - self.packet = [] - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - self.bit_width = float(self.samplerate) / 2e3 - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.reset_variables() - - def packet_len(self, byte): - if 0x00 <= byte <= 0x1f: - return int(1 + (byte - 0) / 32) - if 0x20 <= byte <= 0x7f: - return int(2 + (byte - 32) / 16) - if 0x80 <= byte <= 0xdf: - return int(8 + (byte - 128) / 8) - if 0xe0 <= byte <= 0xff: - return int(20 + (byte - 224) / 4) - - def in_tolerance(self, l): - return (0.75 * self.bit_width) < l < (1.25 * self.bit_width) - - def putp(self, data): - self.put(self.bytesi[0], self.bytesi[-1], self.out_ann, [5, data]) - - def process_packet(self): - if self.packet[0] == 0x01: # Signal Strength - self.putp(['Signal Strength: %d' % self.packet[1], - 'SS: %d' % self.packet[1], 'SS']) - elif self.packet[0] == 0x02: # End Power Transfer - reason = end_codes[self.packet[1]] if self.packet[1] < len(end_codes) else 'Reserved' - self.putp(['End Power Transfer: %s' % reason, - 'EPT: %s' % reason, 'EPT']) - elif self.packet[0] == 0x03: # Control Error - val = self.packet[1] if self.packet[1] < 128 else (self.packet[1] & 0x7f) - 128 - self.putp(['Control Error: %d' % val, 'CE: %d' % val, 'CE']) - elif self.packet[0] == 0x04: # Received Power - self.putp(['Received Power: %d' % self.packet[1], - 'RP: %d' % self.packet[1], 'RP']) - elif self.packet[0] == 0x05: # Charge Status - self.putp(['Charge Status: %d' % self.packet[1], - 'CS: %d' % self.packet[1], 'CS']) - elif self.packet[0] == 0x06: # Power Control Hold-off - self.putp(['Power Control Hold-off: %dms' % self.packet[1], - 'PCH: %d' % self.packet[1]], 'PCH') - elif self.packet[0] == 0x51: # Configuration - powerclass = (self.packet[1] & 0xc0) >> 7 - maxpower = self.packet[1] & 0x3f - prop = (self.packet[3] & 0x80) >> 7 - count = self.packet[3] & 0x07 - winsize = (self.packet[4] & 0xf8) >> 3 - winoff = self.packet[4] & 0x07 - self.putp(['Configuration: Power Class = %d, Maximum Power = %d, Prop = %d,' - 'Count = %d, Window Size = %d, Window Offset = %d' % - (powerclass, maxpower, prop, count, winsize, winoff), - 'C: PC = %d MP = %d P = %d C = %d WS = %d WO = %d' % - (powerclass, maxpower, prop, count, winsize, winoff), - 'Configuration', 'C']) - elif self.packet[0] == 0x71: # Identification - version = '%d.%d' % ((self.packet[1] & 0xf0) >> 4, self.packet[1] & 0x0f) - mancode = '%02x%02x' % (self.packet[2], self.packet[3]) - devid = '%02x%02x%02x%02x' % (self.packet[4] & ~0x80, - self.packet[5], self.packet[6], self.packet[7]) - self.putp(['Identification: Version = %s, Manufacturer = %s, ' \ - 'Device = %s' % (version, mancode, devid), - 'ID: %s %s %s' % (version, mancode, devid), 'ID']) - elif self.packet[0] == 0x81: # Extended Identification - edevid = '%02x%02x%02x%02x%02x%02x%02x%02x' % self.packet[1:-1] - self.putp(['Extended Identification: %s' % edevid, - 'EI: %s' % edevid, 'EI']) - elif self.packet[0] in (0x18, 0x19, 0x28, 0x29, 0x38, 0x48, 0x58, 0x68, - 0x78, 0x85, 0xa4, 0xc4, 0xe2): # Proprietary - self.putp(['Proprietary', 'P']) - else: # Unknown - self.putp(['Unknown', '?']) - self.put(self.bytesi[-1], self.samplenum, self.out_ann, - [6, ['Checksum OK', 'OK']] if \ - calc_checksum(self.packet) == self.packet[-1] - else [6, ['Checksum error', 'ERR']]) - - def process_byte(self): - self.put(self.bytestart, self.bitsi[0], self.out_ann, - ([2, ['Start bit', 'Start', 'S']]) if self.bits[0] == 0 else - ([1, ['Start error', 'Start err', 'SE']])) - databits = self.bits[1:9] - data = bits_to_uint(databits) - parity = reduce(lambda i, v: (i + v) % 2, databits, 1) - self.put(self.bitsi[0], self.bitsi[8], self.out_ann, [4, ['%02x' % data]]) - self.put(self.bitsi[8], self.bitsi[9], self.out_ann, - ([3, ['Parity bit', 'Parity', 'P']]) if self.bits[9] == parity else - ([1, ['Parity error', 'Parity err', 'PE']])) - self.put(self.bitsi[9], self.bitsi[10], self.out_ann, - ([3, ['Stop bit', 'Stop', 'S']]) if self.bits[10] == 1 else - ([1, ['Stop error', 'Stop err', 'SE']])) - - self.bytesi.append(self.bytestart) - self.packet.append(data) - if self.packet_len(self.packet[0]) + 2 == len(self.packet): - self.process_packet() - self.bytesi.clear() - self.packet.clear() - - def add_bit(self, bit): - self.bits.append(bit) - self.bitsi.append(self.samplenum) - - if self.state == 'IDLE' and len(self.bits) >= 5 and \ - self.bits[-5:] == [1, 1, 1, 1, 0]: - self.state = 'DATA' - self.bytestart = self.bitsi[-2] - self.bits = [0] - self.bitsi = [self.samplenum] - self.packet.clear() - elif self.state == 'DATA' and len(self.bits) == 11: - self.process_byte() - self.bytestart = self.samplenum - self.bits.clear() - self.bitsi.clear() - if self.state != 'IDLE': - self.put(self.lastbit, self.samplenum, self.out_ann, [0, ['%d' % bit]]) - self.lastbit = self.samplenum - - def handle_transition(self, l, htl): - self.deq.append(l) - if len(self.deq) >= 2 and \ - (self.in_tolerance(self.deq[-1] + self.deq[-2]) or \ - htl and self.in_tolerance(l * 2) and \ - self.deq[-2] > 1.25 * self.bit_width): - self.add_bit(1) - self.deq.clear() - elif self.in_tolerance(l): - self.add_bit(0) - self.deq.clear() - elif l > (1.25 * self.bit_width): - self.state = 'IDLE' - self.bytesi.clear() - self.packet.clear() - self.bits.clear() - self.bitsi.clear() - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - - (qi,) = self.wait() - self.handle_transition(self.samplenum, qi == 0) - while True: - prev = self.samplenum - (qi,) = self.wait({0: 'e'}) - self.handle_transition(self.samplenum - prev, qi == 0) diff --git a/decoders/qspi/__init__.py b/decoders/qspi/__init__.py deleted file mode 100644 index 10b74234..00000000 --- a/decoders/qspi/__init__.py +++ /dev/null @@ -1,31 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2016 fenugrec -## -## 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, see . -## - -''' -This protocol decoder decodes the AUD (Advanced User Debugger) interface -of certain Renesas / Hitachi microcontrollers, when set in Branch Trace mode. - -AUD has two modes, this PD currently only supports "Branch Trace" mode. - -Details: -http://www.renesas.eu/products/mpumcu/superh/sh7050/sh7058/Documentation.jsp -("rej09b0046 - SH7058 Hardware manual") -''' - -from .pd import Decoder diff --git a/decoders/qspi/pd.py b/decoders/qspi/pd.py deleted file mode 100644 index e0aa4f2a..00000000 --- a/decoders/qspi/pd.py +++ /dev/null @@ -1,226 +0,0 @@ -### -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 DreamSourceLab -## -## 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, see . -## - -import sigrokdecode as srd -from collections import namedtuple - -Data = namedtuple('Data', ['ss', 'es', 'val']) - - -# Key: (CPOL, CPHA). Value: SPI mode. -# Clock polarity (CPOL) = 0/1: Clock is low/high when inactive. -# Clock phase (CPHA) = 0/1: Data is valid on the leading/trailing clock edge. -spi_mode = { - (0, 0): 0, # Mode 0 - (0, 1): 1, # Mode 1 - (1, 0): 2, # Mode 2 - (1, 1): 3, # Mode 3 -} - -class ChannelError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = 'qspi' - name = 'QSPI' - longname = 'Quad Serial Peripheral Interface' - desc = 'Full-duplex, synchronous, serial bus.' - license = 'gplv2+' - inputs = ['logic'] - outputs = ['spi'] - tags = ['Embedded/industrial'] - channels = ( - {'id': 'clk', 'type': 0, 'name': 'CLK', 'desc': 'Clock'}, - {'id': 'io0', 'type': 107, 'name': 'IO0', 'desc': 'Data i/o 0'}, - ) - optional_channels = ( - {'id': 'io1', 'type': 107, 'name': 'IO1', 'desc': 'Data i/o 1'}, - {'id': 'io2', 'type': 107, 'name': 'IO2', 'desc': 'Data i/o 2'}, - {'id': 'io3', 'type': 107, 'name': 'IO3', 'desc': 'Data i/o 3'}, - {'id': 'cs', 'type': -1, 'name': 'CS#', 'desc': 'Chip-select'}, - ) - options = ( - {'id': 'cs_polarity', 'desc': 'CS# polarity', 'default': 'active-low', - 'values': ('active-low', 'active-high')}, - {'id': 'cpol', 'desc': 'Clock polarity (CPOL)', 'default': 0, - 'values': (0, 1)}, - {'id': 'cpha', 'desc': 'Clock phase (CPHA)', 'default': 0, - 'values': (0, 1)}, - {'id': 'bitorder', 'desc': 'Bit order', - 'default': 'msb-first', 'values': ('msb-first', 'lsb-first')}, - {'id': 'wordsize', 'desc': 'Word size', 'default': 8}, - ) - annotations = ( - ('106', 'data', 'data'), - ) - annotation_rows = ( - ('data', 'data', (0,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.bitcount = 0 - self.data = 0 - self.bits = [] - self.ss_block = -1 - self.samplenum = -1 - self.ss_transfer = -1 - self.cs_was_deasserted = False - self.have_cs = self.have_io1 = self.have_io3 = None - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.bw = (self.options['wordsize'] + 7) // 8 - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def putw(self, data): - self.put(self.ss_block, self.samplenum, self.out_ann, data) - - def putdata(self): - # Pass bits and then data to the next PD up the stack. - ss, es = self.bits[-1][1], self.bits[0][2] - - # Dataword annotations. - self.put(ss, es, self.out_ann, [0, ['%02X' % self.data]]) - - def reset_decoder_state(self): - self.data = 0 - self.bits = [] - self.bitcount = 0 - - def cs_asserted(self, cs): - active_low = (self.options['cs_polarity'] == 'active-low') - return (cs == 0) if active_low else (cs == 1) - - def handle_bit(self, datapins, clk, cs): - # If this is the first bit of a dataword, save its sample number. - if self.bitcount == 0: - self.ss_block = self.samplenum - self.cs_was_deasserted = \ - not self.cs_asserted(cs) if self.have_cs else False - - bo = self.options['bitorder'] - ws = self.options['wordsize'] - if self.have_io3: - nibws = ws >> 2 - elif self.have_io1: - nibws = ws >> 1 - else: - nibws = ws - - # Receive bit into our shift register. - if self.have_io3: - for i in range(4): - if bo == 'msb-first': - self.data |= datapins[i] << (ws - 1 - self.bitcount*4 - i) - else: - self.data |= datapins[3-i] << (self.bitcount*4 + i) - elif self.have_io1: - for i in range(2): - if bo == 'msb-first': - self.data |= datapins[i+2] << (ws - 1 - self.bitcount*2 - i) - else: - self.data |= datapins[3-i] << (self.bitcount*2 + i) - else: - if bo == 'msb-first': - self.data |= datapins[3] << (ws - 1 - self.bitcount) - else: - self.data |= datapins[3] << self.bitcount - - # Guesstimate the endsample for this bit (can be overridden below). - es = self.samplenum - if self.bitcount > 0: - es += self.samplenum - self.bits[0][1] - - self.bits.insert(0, [datapins[3], self.samplenum, es]) - - if self.bitcount > 0: - self.bits[1][2] = self.samplenum - - self.bitcount += 1 - - # Continue to receive if not enough bits were received, yet. - if self.bitcount != nibws: - return - - self.putdata() - - self.reset_decoder_state() - - def find_clk_edge(self, datapins, clk, cs, first): - if self.have_cs and (first or (self.matched & (0b1 << self.have_cs))): - # Send all CS# pin value changes. - oldcs = None if first else 1 - cs - - # Reset decoder state when CS# changes (and the CS# pin is used). - self.reset_decoder_state() - - # We only care about samples if CS# is asserted. - if self.have_cs and not self.cs_asserted(cs): - return - - # Ignore sample if the clock pin hasn't changed. - if first or not (self.matched & (0b1 << 0)): - return - - # Found the correct clock edge, now get the SPI bit(s). - self.handle_bit(datapins, clk, cs) - - def decode(self): - # The CLK & IO0 input is mandatory. Other signals are (individually) - # optional. Tell stacked decoders when we don't have a CS# signal. - if not self.has_channel(0): - raise ChannelError('CLK pin required.') - self.have_io1 = self.has_channel(2) - self.have_io3 = self.has_channel(3) & self.has_channel(4) - self.have_cs = self.has_channel(5) - - # We want all CLK changes. We want all CS changes if CS is used. - # Map 'have_cs' from boolean to an integer index. This simplifies - # evaluation in other locations. - # Sample data on rising/falling clock edge (depends on mode). - mode = spi_mode[self.options['cpol'], self.options['cpha']] - if mode == 0 or mode == 3: # Sample on rising clock edge - wait_cond = [{0: 'r'}] - else: # Sample on falling clock edge - wait_cond = [{0: 'f'}] - - if self.have_cs: - self.have_cs = len(wait_cond) - wait_cond.append({5: 'e'}) - - # "Pixel compatibility" with the v2 implementation. Grab and - # process the very first sample before checking for edges. The - # previous implementation did this by seeding old values with - # None, which led to an immediate "change" in comparison. - (clk, d0, d1, d2, d3, cs) = self.wait({}) - d = (d3, d2, d1, d0); - self.find_clk_edge(d, clk, cs, True) - - while True: - (clk, d0, d1, d2, d3, cs) = self.wait(wait_cond) - d = (d3, d2, d1, d0); - self.find_clk_edge(d, clk, cs, False)# diff --git a/decoders/rc_encode/__init__.py b/decoders/rc_encode/__init__.py deleted file mode 100755 index db78dc1e..00000000 --- a/decoders/rc_encode/__init__.py +++ /dev/null @@ -1,36 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Steve R -## -## 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, see . -## - -''' -This PD decodes the remote control protocol which is frequently used -within key fobs and power socket remotes. - -They contain encoding chips like the PT2262 which converts the button -pressed and address settings into a series of pulses which is then -transmitted over whatever frequency and modulation that the designer -chooses. These devices operate at a number of frequencies including 433MHz. - -This PD should also decode the HX2262 and SC5262 which are equivalents. - -The decoder also contains some additional decoding for a Maplin L95AR -remote control and will turn the received signal into which button was -pressed and what the address code DIP switches are set to. -''' - -from .pd import Decoder diff --git a/decoders/rc_encode/pd.py b/decoders/rc_encode/pd.py deleted file mode 100755 index daeca092..00000000 --- a/decoders/rc_encode/pd.py +++ /dev/null @@ -1,167 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Steve R -## -## 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, see . -## - -import sigrokdecode as srd - -bitvals = ('0', '1', 'f', 'U') - -def decode_bit(edges): - # Datasheet says long pulse is 3 times short pulse. - lmin = 2 # long min multiplier - lmax = 5 # long max multiplier - eqmin = 0.5 # equal min multiplier - eqmax = 1.5 # equal max multiplier - if ( # 0 -___-___ - (edges[1] >= edges[0] * lmin and edges[1] <= edges[0] * lmax) and - (edges[2] >= edges[0] * eqmin and edges[2] <= edges[0] * eqmax) and - (edges[3] >= edges[0] * lmin and edges[3] <= edges[0] * lmax)): - return '0' - elif ( # 1 ---_---_ - (edges[0] >= edges[1] * lmin and edges[0] <= edges[1] * lmax) and - (edges[0] >= edges[2] * eqmin and edges[0] <= edges[2] * eqmax) and - (edges[0] >= edges[3] * lmin and edges[0] <= edges[3] * lmax)): - return '1' - elif ( # float ---_-___ - (edges[1] >= edges[0] * lmin and edges[1] <= edges[0] * lmax) and - (edges[2] >= edges[0] * lmin and edges[2] <= edges[0]* lmax) and - (edges[3] >= edges[0] * eqmin and edges[3] <= edges[0] * eqmax)): - return 'f' - else: - return 'U' - -def pinlabels(bit_count): - if bit_count <= 6: - return 'A%i' % (bit_count - 1) - else: - return 'A%i/D%i' % (bit_count - 1, 12 - bit_count) - -def decode_model(model, bits): - if model == 'maplin_l95ar': - address = 'Addr' # Address pins A0 to A5 - for i in range(0, 6): - address += ' %i:' % (i + 1) + ('on' if bits[i][0] == '0' else 'off') - button = 'Button' - # Button pins A6/D5 to A11/D0 - if bits[6][0] == '0' and bits[11][0] == '0': - button += ' A ON/OFF' - elif bits[7][0] == '0' and bits[11][0] == '0': - button += ' B ON/OFF' - elif bits[9][0] == '0' and bits[11][0] == '0': - button += ' C ON/OFF' - elif bits[8][0] == '0' and bits[11][0] == '0': - button += ' D ON/OFF' - else: - button += ' Unknown' - return ['%s' % address, bits[0][1], bits[5][2], \ - '%s' % button, bits[6][1], bits[11][2]] - -class Decoder(srd.Decoder): - api_version = 3 - id = 'rc_encode' - name = 'RC encode' - longname = 'Remote control encoder' - desc = 'PT2262/HX2262/SC5262 remote control encoder protocol.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['IC', 'IR'] - channels = ( - {'id': 'data', 'name': 'Data', 'desc': 'Data line'}, - ) - annotations = ( - ('bit-0', 'Bit 0'), - ('bit-1', 'Bit 1'), - ('bit-f', 'Bit f'), - ('bit-U', 'Bit U'), - ('bit-sync', 'Bit sync'), - ('pin', 'Pin'), - ('code-word-addr', 'Code word address'), - ('code-word-data', 'Code word data'), - ) - annotation_rows = ( - ('bits', 'Bits', (0, 1, 2, 3, 4)), - ('pins', 'Pins', (5,)), - ('code-words', 'Code words', (6, 7)), - ) - options = ( - {'id': 'remote', 'desc': 'Remote', 'default': 'none', - 'values': ('none', 'maplin_l95ar')}, - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplenumber_last = None - self.pulses = [] - self.bits = [] - self.labels = [] - self.bit_count = 0 - self.ss = None - self.es = None - self.state = 'IDLE' - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.model = self.options['remote'] - - def putx(self, data): - self.put(self.ss, self.es, self.out_ann, data) - - def decode(self): - while True: - self.wait({0: 'e'}) - self.state = 'DECODING' - - if not self.samplenumber_last: # Set counters to start of signal. - self.samplenumber_last = self.samplenum - self.ss = self.samplenum - continue - - if self.bit_count < 12: # Decode A0 to A11. - self.bit_count += 1 - for i in range(0, 4): # Get four pulses for each bit. - if i > 0: - self.wait({0: 'e'}) # Get next 3 edges. - samples = self.samplenum - self.samplenumber_last - self.pulses.append(samples) # Save the pulse width. - self.samplenumber_last = self.samplenum - self.es = self.samplenum - self.bits.append([decode_bit(self.pulses), self.ss, - self.es]) # Save states and times. - idx = bitvals.index(decode_bit(self.pulses)) - self.putx([idx, [decode_bit(self.pulses)]]) # Write decoded bit. - self.putx([5, [pinlabels(self.bit_count)]]) # Write pin labels. - self.pulses = [] - self.ss = self.samplenum - else: - if self.model != 'none': - self.labels = decode_model(self.model, self.bits) - self.put(self.labels[1], self.labels[2], self.out_ann, - [6, [self.labels[0]]]) # Write model decode. - self.put(self.labels[4], self.labels[5], self.out_ann, - [7, [self.labels[3]]]) # Write model decode. - samples = self.samplenum - self.samplenumber_last - self.wait({'skip': 8 * samples}) # Wait for end of sync bit. - self.es = self.samplenum - self.putx([4, ['Sync']]) # Write sync label. - self.reset() # Reset and wait for next set of pulses. - self.state = 'DECODE_TIMEOUT' - if not self.state == 'DECODE_TIMEOUT': - self.samplenumber_last = self.samplenum diff --git a/decoders/rfm12/__init__.py b/decoders/rfm12/__init__.py deleted file mode 100755 index 2fc6de7b..00000000 --- a/decoders/rfm12/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Sławek Piotrowski -## -## 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, see . -## - -''' -This decoder stacks on top of the 'spi' PD and decodes the HopeRF RFM12 -wireless transceiver control protocol. -''' - -from .pd import Decoder diff --git a/decoders/rfm12/pd.py b/decoders/rfm12/pd.py deleted file mode 100755 index d3df13a9..00000000 --- a/decoders/rfm12/pd.py +++ /dev/null @@ -1,497 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Sławek Piotrowski -## -## 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, see . -## - -import sigrokdecode as srd - -class Decoder(srd.Decoder): - api_version = 3 - id = 'rfm12' - name = 'RFM12' - longname = 'HopeRF RFM12' - desc = 'HopeRF RFM12 wireless transceiver control protocol.' - license = 'gplv2+' - inputs = ['spi'] - outputs = [] - tags = ['Wireless/RF'] - annotations = ( - ('cmd', 'Command'), - ('params', 'Command parameters'), - ('disabled', 'Disabled bits'), - ('return', 'Returned values'), - ('disabled_return', 'Disabled returned values'), - ('interpretation', 'Interpretation'), - ) - annotation_rows = ( - ('commands', 'Commands', (0, 1, 2)), - ('return', 'Return', (3, 4)), - ('interpretation', 'Interpretation', (5,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.mosi_bytes, self.miso_bytes = [], [] - self.mosi_bits, self.miso_bits = [], [] - self.row_pos = [0, 0, 0] - - self.ann_to_row = [0, 0, 0, 1, 1, 2] - - # Initialize with Power-On-Reset values. - self.last_status = [0x00, 0x00] - self.last_config = 0x08 - self.last_power = 0x08 - self.last_freq = 0x680 - self.last_data_rate = 0x23 - self.last_fifo_and_reset = 0x80 - self.last_afc = 0xF7 - self.last_transceiver = 0x00 - self.last_pll = 0x77 - - def advance_ann(self, ann, length): - row = self.ann_to_row[ann] - self.row_pos[row] += length - - def putx(self, ann, length, description): - if not isinstance(description, list): - description = [description] - row = self.ann_to_row[ann] - bit = self.row_pos[row] - self.put(self.mosi_bits[bit][1], self.mosi_bits[bit + length - 1][2], - self.out_ann, [ann, description]) - bit += length - self.row_pos[row] = bit - - def describe_bits(self, data, names): - i = 0x01 << len(names) - 1 - bit = 0 - while i != 0: - if names[bit] != '': - self.putx(1 if (data & i) else 2, 1, names[bit]) - i >>= 1 - bit += 1 - - def describe_return_bits(self, data, names): - i = 0x01 << len(names) - 1 - bit = 0 - while i != 0: - if names[bit] != '': - self.putx(3 if (data & i) else 4, 1, names[bit]) - else: - self.advance_ann(3, 1) - i >>= 1 - bit += 1 - - def describe_changed_bits(self, data, old_data, names): - changes = data ^ old_data - i = 0x01 << (len(names) - 1) - bit = 0 - while i != 0: - if names[bit] != '' and changes & i: - s = ['+', 'Turning on'] if (data & i) else ['-', 'Turning off'] - self.putx(5, 1, s) - else: - self.advance_ann(5, 1) - i >>= 1 - bit += 1 - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def handle_configuration_cmd(self, cmd, ret): - self.putx(0, 8, ['Configuration command', 'Configuration']) - NAMES = [['Internal data register', 'el'], ['FIFO mode', 'ef']] - - bits = (cmd[1] & 0xC0) >> 6 - old_bits = (self.last_config & 0xC0) >> 6 - self.describe_bits(bits, NAMES) - self.describe_changed_bits(bits, old_bits, NAMES) - - FREQUENCIES = ['315', '433', '868', '915'] - f = FREQUENCIES[(cmd[1] & 0x30) >> 4] + 'MHz' - self.putx(1, 2, ['Frequency: ' + f, f]) - if cmd[1] & 0x30 != self.last_config & 0x30: - self.putx(5, 2, ['Changed', '~']) - - c = '%.1fpF' % (8.5 + (cmd[1] & 0xF) * 0.5) - self.putx(1, 4, ['Capacitance: ' + c, c]) - if cmd[1] & 0xF != self.last_config & 0xF: - self.putx(5, 4, ['Changed', '~']) - - self.last_config = cmd[1] - - def handle_power_management_cmd(self, cmd, ret): - self.putx(0, 8, ['Power management', 'Power']) - NAMES = [['Receiver chain', 'er'], ['Baseband circuit', 'ebb'], - ['Transmission', 'et'], ['Synthesizer', 'es'], - ['Crystal oscillator', 'ex'], ['Low battery detector', 'eb'], - ['Wake-up timer', 'ew'], ['Clock output off switch', 'dc']] - - self.describe_bits(cmd[1], NAMES) - - power = cmd[1] - - # Some bits imply other, even if they are set to 0. - if power & 0x80: - power |= 0x58 - if power & 0x20: - power |= 0x18 - self.describe_changed_bits(power, self.last_power, NAMES) - - self.last_power = power - - def handle_frequency_setting_cmd(self, cmd, ret): - self.putx(0, 4, ['Frequency setting', 'Frequency']) - f = ((cmd[1] & 0xF) << 8) + cmd[2] - self.putx(0, 12, ['F = %3.4f' % f]) - self.row_pos[2] -= 4 - if self.last_freq != f: - self.putx(5, 12, ['Changing', '~']) - self.last_freq = f - - def handle_data_rate_cmd(self, cmd, ret): - self.putx(0, 8, ['Data rate command', 'Data rate']) - r = cmd[1] & 0x7F - cs = (cmd[1] & 0x80) >> 7 - rate = 10000 / 29.0 / (r + 1) / (1 + 7 * cs) - self.putx(0, 8, ['%3.1fkbps' % rate]) - if self.last_data_rate != cmd[1]: - self.putx(5, 8, ['Changing', '~']) - self.last_data_rate = cmd[1] - - def handle_receiver_control_cmd(self, cmd, ret): - self.putx(0, 5, ['Receiver control command']) - s = 'interrupt input' if (cmd[0] & 0x04) else 'VDI output' - self.putx(0, 1, ['pin16 = ' + s]) - VDI_NAMES = ['Fast', 'Medium', 'Slow', 'Always on'] - vdi_speed = VDI_NAMES[cmd[0] & 0x3] - self.putx(0, 2, ['VDI: %s' % vdi_speed]) - BANDWIDTH_NAMES = ['Reserved', '400kHz', '340kHz', '270kHz', '200kHz', - '134kHz', '67kHz', 'Reserved'] - bandwidth = BANDWIDTH_NAMES[(cmd[1] & 0xE0) >> 5] - self.putx(0, 3, ['Bandwidth: %s' % bandwidth]) - LNA_GAIN_NAMES = [0, -6, -14, -20] - lna_gain = LNA_GAIN_NAMES[(cmd[1] & 0x18) >> 3] - self.putx(0, 2, ['LNA gain: %ddB' % lna_gain]) - RSSI_THRESHOLD_NAMES = ['-103', '-97', '-91', '-85', '-79', '-73', - 'Reserved', 'Reserved'] - rssi_threshold = RSSI_THRESHOLD_NAMES[cmd[1] & 0x7] - self.putx(0, 3, ['RSSI threshold: %s' % rssi_threshold]) - - def handle_data_filter_cmd(self, cmd, ret): - self.putx(0, 8, ['Data filter command']) - if cmd[1] & 0x80: - clock_recovery = 'auto' - elif cmd[1] & 0x40: - clock_recovery = 'fast' - else: - clock_recovery = 'slow' - self.putx(0, 2, ['Clock recovery: %s mode' % clock_recovery]) - self.advance_ann(0, 1) # Should always be 1. - s = 'analog' if (cmd[1] & 0x10) else 'digital' - self.putx(0, 1, ['Data filter: ' + s]) - self.advance_ann(0, 1) # Should always be 1. - self.putx(0, 3, ['DQD threshold: %d' % (cmd[1] & 0x7)]) - - def handle_fifo_and_reset_cmd(self, cmd, ret): - self.putx(0, 8, ['FIFO and reset command']) - fifo_level = (cmd[1] & 0xF0) >> 4 - self.putx(0, 4, ['FIFO trigger level: %d' % fifo_level]) - last_fifo_level = (self.last_fifo_and_reset & 0xF0) >> 4 - if fifo_level != last_fifo_level: - self.putx(5, 4, ['Changing', '~']) - else: - self.advance_ann(5, 4) - s = 'one byte' if (cmd[1] & 0x08) else 'two bytes' - self.putx(0, 1, ['Synchron length: ' + s]) - if (cmd[1] & 0x08) != (self.last_fifo_and_reset & 0x08): - self.putx(5, 1, ['Changing', '~']) - else: - self.advance_ann(5, 1) - - if cmd[1] & 0x04: - fifo_fill = 'Always' - elif cmd[1] & 0x02: - fifo_fill = 'After synchron pattern' - else: - fifo_fill = 'Never' - self.putx(0, 2, ['FIFO fill: %s' % fifo_fill]) - if (cmd[1] & 0x06) != (self.last_fifo_and_reset & 0x06): - self.putx(5, 2, ['Changing', '~']) - else: - self.advance_ann(5, 2) - - s = 'non-sensitive' if (cmd[1] & 0x01) else 'sensitive' - self.putx(0, 1, ['Reset mode: ' + s]) - if (cmd[1] & 0x01) != (self.last_fifo_and_reset & 0x01): - self.putx(5, 1, ['Changing', '~']) - else: - self.advance_ann(5, 1) - - self.last_fifo_and_reset = cmd[1] - - def handle_synchron_pattern_cmd(self, cmd, ret): - self.putx(0, 8, ['Synchron pattern command']) - if self.last_fifo_and_reset & 0x08: - self.putx(0, 8, ['Pattern: 0x2D%02X' % pattern]) - else: - self.putx(0, 8, ['Pattern: %02X' % pattern]) - - def handle_fifo_read_cmd(self, cmd, ret): - self.putx(0, 8, ['FIFO read command', 'FIFO read']) - self.putx(3, 8, ['Data: %02X' % ret[1]]) - - def handle_afc_cmd(self, cmd, ret): - self.putx(0, 8, ['AFC command']) - MODES = ['Off', 'Once', 'During receiving', 'Always'] - mode = (cmd[1] & 0xC0) >> 6 - self.putx(0, 2, ['Mode: %s' % MODES[mode]]) - if (cmd[1] & 0xC0) != (self.last_afc & 0xC0): - self.putx(5, 2, ['Changing', '~']) - else: - self.advance_ann(5, 2) - - range_limit = (cmd[1] & 0x30) >> 4 - FREQ_TABLE = [0.0, 2.5, 5.0, 7.5] - freq_delta = FREQ_TABLE[(self.last_config & 0x30) >> 4] - - if range_limit == 0: - self.putx(0, 2, ['Range: No limit']) - elif range_limit == 1: - self.putx(0, 2, ['Range: +/-%dkHz' % (15 * freq_delta)]) - elif range_limit == 2: - self.putx(0, 2, ['Range: +/-%dkHz' % (7 * freq_delta)]) - elif range_limit == 3: - self.putx(0, 2, ['Range: +/-%dkHz' % (3 * freq_delta)]) - - if (cmd[1] & 0x30) != (self.last_afc & 0x30): - self.putx(5, 2, ['Changing', '~']) - else: - self.advance_ann(5, 2) - - NAMES = ['Strobe edge', 'High accuracy mode', 'Enable offset register', - 'Enable offset calculation'] - self.describe_bits(cmd[1] & 0xF, NAMES) - self.describe_changed_bits(cmd[1] & 0xF, self.last_afc & 0xF, NAMES) - - self.last_afc = cmd[1] - - def handle_transceiver_control_cmd(self, cmd, ret): - self.putx(0, 8, ['Transceiver control command']) - self.putx(0, 4, ['FSK frequency delta: %dkHz' % (15 * ((cmd[1] & 0xF0) >> 4))]) - if cmd[1] & 0xF0 != self.last_transceiver & 0xF0: - self.putx(5, 4, ['Changing', '~']) - else: - self.advance_ann(5, 4) - - POWERS = [0, -2.5, -5, -7.5, -10, -12.5, -15, -17.5] - self.advance_ann(0, 1) - self.advance_ann(5, 1) - self.putx(0,3, ['Relative power: %dB' % (cmd[1] & 0x07)]) - if (cmd[1] & 0x07) != (self.last_transceiver & 0x07): - self.putx(5, 3, ['Changing', '~']) - else: - self.advance_ann(5, 3) - self.last_transceiver = cmd[1] - - def handle_pll_setting_cmd(self, cmd, ret): - self.putx(0, 8, ['PLL setting command']) - self.advance_ann(0, 1) - self.putx(0, 2, ['Clock buffer rise and fall time']) - self.advance_ann(0, 1) - self.advance_ann(5, 4) - NAMES = [['Delay in phase detector', 'dly'], ['Disable dithering', 'ddit']] - self.describe_bits((cmd[1] & 0xC) >> 2, NAMES) - self.describe_changed_bits((cmd[1] & 0xC) >> 2, (self.last_pll & 0xC) >> 2, NAMES) - s = '256kbps, high' if (cmd[1] & 0x01) else '86.2kbps, low' - self.putx(0, 1, ['Max bit rate: %s noise' % s]) - - self.advance_ann(5, 1) - if (cmd[1] & 0x01) != (self.last_pll & 0x01): - self.putx(5, 1, ['Changing', '~']) - - self.last_pll = cmd[1] - - def handle_transmitter_register_cmd(self, cmd, ret): - self.putx(0, 8, ['Transmitter register command', 'Transmit']) - self.putx(0, 8, ['Data: %s' % cmd[1], '%s' % cmd[1]]) - - def handle_software_reset_cmd(self, cmd, ret): - self.putx(0, 16, ['Software reset command']) - - def handle_wake_up_timer_cmd(self, cmd, ret): - self.putx(0, 3, ['Wake-up timer command', 'Timer']) - r = cmd[0] & 0x1F - m = cmd[1] - time = 1.03 * m * pow(2, r) + 0.5 - self.putx(0, 13, ['Time: %7.2f' % time]) - - def handle_low_duty_cycle_cmd(self, cmd, ret): - self.putx(0, 16, ['Low duty cycle command']) - - def handle_low_battery_detector_cmd(self, cmd, ret): - self.putx(0, 8, ['Low battery detector command']) - NAMES = ['1', '1.25', '1.66', '2', '2.5', '3.33', '5', '10'] - clock = NAMES[(cmd[1] & 0xE0) >> 5] - self.putx(0, 3, ['Clock output: %sMHz' % clock, '%sMHz' % clock]) - self.advance_ann(0, 1) - v = 2.25 + (cmd[1] & 0x0F) * 0.1 - self.putx(0, 4, ['Low battery voltage: %1.2fV' % v, '%1.2fV' % v]) - - def handle_status_read_cmd(self, cmd, ret): - self.putx(0, 8, ['Status read command', 'Status']) - NAMES = ['RGIT/FFIT', 'POR', 'RGUR/FFOV', 'WKUP', 'EXT', 'LBD', - 'FFEM', 'RSSI/ATS', 'DQD', 'CRL', 'ATGL'] - status = (ret[0] << 3) + (ret[1] >> 5) - self.row_pos[1] -= 8 - self.row_pos[2] -= 8 - self.describe_return_bits(status, NAMES) - receiver_enabled = (self.last_power & 0x80) >> 7 - - if ret[0] & 0x80: - if receiver_enabled: - s = 'Received data in FIFO' - else: - s = 'Transmit register ready' - self.putx(5, 1, s) - else: - self.advance_ann(5, 1) - if ret[0] & 0x40: - self.putx(5, 1, 'Power on Reset') - else: - self.advance_ann(5, 1) - if ret[0] & 0x20: - if receiver_enabled: - s = 'RX FIFO overflow' - else: - s = 'Transmit register under run' - self.putx(5, 1, s) - else: - self.advance_ann(5, 1) - if ret[0] & 0x10: - self.putx(5, 1, 'Wake-up timer') - else: - self.advance_ann(5, 1) - if ret[0] & 0x08: - self.putx(5, 1, 'External interrupt') - else: - self.advance_ann(5, 1) - if ret[0] & 0x04: - self.putx(5, 1, 'Low battery') - else: - self.advance_ann(5, 1) - if ret[0] & 0x02: - self.putx(5, 1, 'FIFO is empty') - else: - self.advance_ann(5, 1) - if ret[0] & 0x01: - if receiver_enabled: - s = 'Incoming signal above limit' - else: - s = 'Antenna detected RF signal' - self.putx(5, 1, s) - else: - self.advance_ann(5, 1) - if ret[1] & 0x80: - self.putx(5, 1, 'Data quality detector') - else: - self.advance_ann(5, 1) - if ret[1] & 0x40: - self.putx(5, 1, 'Clock recovery locked') - else: - self.advance_ann(5, 1) - self.advance_ann(5, 1) - - self.putx(3, 5, ['AFC offset']) - if (self.last_status[1] & 0x1F) != (ret[1] & 0x1F): - self.putx(5, 5, ['Changed', '~']) - self.last_status = ret - - def handle_cmd(self, cmd, ret): - if cmd[0] == 0x80: - self.handle_configuration_cmd(cmd, ret) - elif cmd[0] == 0x82: - self.handle_power_management_cmd(cmd, ret) - elif cmd[0] & 0xF0 == 0xA0: - self.handle_frequency_setting_cmd(cmd, ret) - elif cmd[0] == 0xC6: - self.handle_data_rate_cmd(cmd, ret) - elif cmd[0] & 0xF8 == 0x90: - self.handle_receiver_control_cmd(cmd, ret) - elif cmd[0] == 0xC2: - self.handle_data_filter_cmd(cmd, ret) - elif cmd[0] == 0xCA: - self.handle_fifo_and_reset_cmd(cmd, ret) - elif cmd[0] == 0xCE: - self.handle_synchron_pattern_cmd(cmd, ret) - elif cmd[0] == 0xB0: - self.handle_fifo_read_cmd(cmd, ret) - elif cmd[0] == 0xC4: - self.handle_afc_cmd(cmd, ret) - elif cmd[0] & 0xFE == 0x98: - self.handle_transceiver_control_cmd(cmd, ret) - elif cmd[0] == 0xCC: - self.handle_pll_setting_cmd(cmd, ret) - elif cmd[0] == 0xB8: - self.handle_transmitter_register_cmd(cmd, ret) - elif cmd[0] == 0xFE: - self.handle_software_reset_cmd(cmd, ret) - elif cmd[0] & 0xE0 == 0xE0: - self.handle_wake_up_timer_cmd(cmd, ret) - elif cmd[0] == 0xC8: - self.handle_low_duty_cycle_cmd(cmd, ret) - elif cmd[0] == 0xC0: - self.handle_low_battery_detector_cmd(cmd, ret) - elif cmd[0] == 0x00: - self.handle_status_read_cmd(cmd, ret) - else: - c = '%02x %02x' % tuple(cmd) - r = '%02x %02x' % tuple(ret) - self.putx(0, 16, ['Unknown command: %s (reply: %s)!' % (c, r)]) - - def decode(self, ss, es, data): - ptype, mosi, miso = data - - # For now, only use DATA and BITS packets. - if ptype not in ('DATA', 'BITS'): - return - - # Store the individual bit values and ss/es numbers. The next packet - # is guaranteed to be a 'DATA' packet belonging to this 'BITS' one. - if ptype == 'BITS': - if mosi is not None: - self.mosi_bits.extend(reversed(mosi)) - if miso is not None: - self.miso_bits.extend(reversed(miso)) - return - - # Append new bytes. - self.mosi_bytes.append(mosi) - self.miso_bytes.append(miso) - - # All commands consist of 2 bytes. - if len(self.mosi_bytes) < 2: - return - - self.row_pos = [0, 8, 8] - - self.handle_cmd(self.mosi_bytes, self.miso_bytes) - - self.mosi_bytes, self.miso_bytes = [], [] - self.mosi_bits, self.miso_bits = [], [] diff --git a/decoders/rgb_led_spi/__init__.py b/decoders/rgb_led_spi/__init__.py deleted file mode 100755 index 1cf62eb8..00000000 --- a/decoders/rgb_led_spi/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Matt Ranostay -## -## 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, see . -## - -''' -This decoder stacks on top of the 'spi' PD and decodes generic RGB LED string -values that are clocked over SPI in RGB values. -''' - -from .pd import Decoder diff --git a/decoders/rgb_led_spi/pd.py b/decoders/rgb_led_spi/pd.py deleted file mode 100755 index ee94c6bf..00000000 --- a/decoders/rgb_led_spi/pd.py +++ /dev/null @@ -1,70 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Matt Ranostay -## -## 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, see . -## - -import sigrokdecode as srd - -class Decoder(srd.Decoder): - api_version = 3 - id = 'rgb_led_spi' - name = 'RGB LED (SPI)' - longname = 'RGB LED string decoder (SPI)' - desc = 'RGB LED string protocol (RGB values clocked over SPI).' - license = 'gplv2+' - inputs = ['spi'] - outputs = [] - tags = ['Display'] - annotations = ( - ('rgb', 'RGB values'), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.ss_cmd, self.es_cmd = 0, 0 - self.mosi_bytes = [] - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putx(self, data): - self.put(self.ss_cmd, self.es_cmd, self.out_ann, data) - - def decode(self, ss, es, data): - ptype, mosi, miso = data - - # Only care about data packets. - if ptype != 'DATA': - return - self.ss, self.es = ss, es - - if len(self.mosi_bytes) == 0: - self.ss_cmd = ss - self.mosi_bytes.append(mosi) - - # RGB value == 3 bytes - if len(self.mosi_bytes) != 3: - return - - red, green, blue = self.mosi_bytes - rgb_value = int(red) << 16 | int(green) << 8 | int(blue) - - self.es_cmd = es - self.putx([0, ['#%.6x' % rgb_value]]) - self.mosi_bytes = [] diff --git a/decoders/rgb_led_ws281x/__init__.py b/decoders/rgb_led_ws281x/__init__.py deleted file mode 100755 index 20de109f..00000000 --- a/decoders/rgb_led_ws281x/__init__.py +++ /dev/null @@ -1,27 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2016 Vladimir Ermakov -## -## 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 . -## - -''' -WS281x RGB LED protocol decoder. - -Details: -https://cpldcpu.wordpress.com/2014/01/14/light_ws2812-library-v2-0-part-i-understanding-the-ws2812/ -''' - -from .pd import Decoder diff --git a/decoders/rgb_led_ws281x/pd.py b/decoders/rgb_led_ws281x/pd.py deleted file mode 100755 index 0ea283ea..00000000 --- a/decoders/rgb_led_ws281x/pd.py +++ /dev/null @@ -1,195 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2016 Vladimir Ermakov -## Copyright (C) 2019 DreamSourceLab -## Copyright (C) 2021 Michael Miller -## -## 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 . -## - -import sigrokdecode as srd -from functools import reduce - -class SamplerateError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = 'rgb_led_ws281x' - name = 'RGB LED WS2812+' - longname = 'RGB LED color decoder' - desc = 'Decodes colors from bus pulses for single wire RGB leds like APA106, WS2811, WS2812, WS2813, SK6812, TM1829, TM1814, and TX1812.' - license = 'gplv3+' - inputs = ['logic'] - outputs = [] - tags = ['Display', 'IC'] - channels = ( - {'id': 'din', 'name': 'DIN', 'desc': 'DIN data line'}, - ) - options = ( - {'id': 'colors', 'desc': 'Colors', 'default': 'GRB', - 'values': ( 'GRB', 'RGB', 'BRG', 'RBG', 'BGR', 'GRBW', 'RGBW', 'WRGB', 'LBGR', 'LGRB', 'LRGB', 'LRBG', 'LGBR', 'LBRG')}, - {'id': 'polarity', 'desc': 'Polarity', 'default': 'normal', - 'values': ('normal', 'inverted')}, - ) - annotations = ( - ('bit', 'Bit'), - ('reset', 'RESET'), - ('rgb', 'RGB'), - ) - annotation_rows = ( - ('bit', 'Bits', (0, 1)), - ('rgb', 'RGB', (2,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.state = 'FIND RESET' - self.samplerate = None - self.ss_packet = None - self.ss = None - self.es = None - self.bits = [] - self.bit_ = None - self.colorsize = None - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def handle_bits(self, samplenum): - if len(self.bits) == self.colorsize: - elems = reduce(lambda a, b: (a << 1) | b, self.bits) - if self.colorsize == 24: - if self.options['colors'] == 'GRB': - rgb = (elems & 0xff0000) >> 8 | (elems & 0x00ff00) << 8 | (elems & 0x0000ff) - elif self.options['colors'] == 'RGB': - rgb = elems - elif self.options['colors'] == 'BRG': - rgb = (elems & 0xff0000) >> 16 | (elems & 0x00ffff) << 8 - elif self.options['colors'] == 'RBG': - rgb = (elems & 0xff0000) | (elems & 0x00ff00) >> 8 | (elems & 0x0000ff) << 8 - elif self.options['colors'] == 'BGR': - rgb = (elems & 0xff0000) >> 16 | (elems & 0x00ff00) | (elems & 0x0000ff) << 16 - - self.put(self.ss_packet, samplenum, self.out_ann, - [2, ['RGB#%06x' % rgb]]) - else: - if self.options['colors'] == 'GRBW': - rgb = (elems & 0xff000000) >> 16 | (elems & 0x00ff0000) | (elems & 0x0000ff00) >> 8 - w = (elems & 0x000000ff) - elif self.options['colors'] == 'RGBW': - rgb = (elems & 0xffffff00) >> 8 - w = (elems & 0x000000ff) - elif self.options['colors'] == 'WRGB': - rgb = (elems & 0x00ffffff) - w = (elems & 0xff000000) >> 32 - elif self.options['colors'] == 'LBGR': - rgb = (elems & 0x0000ff00) | (elems & 0x00ff0000) >> 16 | (elems & 0x000000ff) << 16 - w = (elems & 0xff000000) >> 32 - elif self.options['colors'] == 'LGRB': - rgb = (elems & 0x000000ff) | (elems & 0x00ff0000) >> 8 | (elems & 0x0000ff00) << 8 - w = (elems & 0xff000000) >> 32 - elif self.options['colors'] == 'LRGB': - rgb = (elems & 0x00ffffff) - w = (elems & 0xff000000) >> 32 - elif self.options['colors'] == 'LRBG': - rgb = (elems & 0x00ff0000) | (elems & 0x0000ff00) >> 8 | (elems & 0x000000ff) << 8 - w = (elems & 0xff000000) >> 32 - elif self.options['colors'] == 'LGBR': - rgb = (elems & 0x00ffff00) >> 8 | (elems & 0x000000ff) << 16 - w = (elems & 0xff000000) >> 32 - elif self.options['colors'] == 'LBRG': - rgb = (elems & 0x00ff0000) >> 16 | (elems & 0x0000ffff) << 8 - w = (elems & 0xff000000) >> 32 - - self.put(self.ss_packet, samplenum, self.out_ann, - [2, ['RGB#%06x #%02x' % (rgb, w)]]) - - self.bits = [] - self.ss_packet = samplenum - - def check_bit_(self, samplenum): - period = samplenum - self.ss - tH_samples = self.es - self.ss - tH = tH_samples / self.samplerate - if tH >= 625e-9: - self.bit_ = True - else: - # Ideal duty for T0H: 33%, T1H: 66%. - self.bit_ = (tH_samples / period) > 0.5 - - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - - if len(self.options['colors']) == 4: - self.colorsize = 32 - else: - self.colorsize = 24 - - while True: - if self.state == 'FIND RESET': - self.wait({0: 'l' if self.options['polarity'] == 'normal' else 'h'}) - self.ss = self.samplenum - self.wait({0: 'e'}) - self.es = self.samplenum - if ((self.es - self.ss) / self.samplerate > 50e-6): - self.state = 'RESET' - elif ((self.es - self.ss) / self.samplerate > 3e-6): - self.bits = [] - self.ss = self.samplenum - self.ss_packet = self.samplenum - self.wait({0: 'e'}) - self.state = 'BIT FALLING' - elif self.state == 'RESET': - self.put(self.ss, self.es, self.out_ann, [1, ['RESET', 'RST', 'R']]) - self.bits = [] - self.ss = self.samplenum - self.ss_packet = self.samplenum - self.wait({0: 'e'}) - self.state = 'BIT FALLING' - elif self.state == 'BIT FALLING': - self.es = self.samplenum - self.wait({0: 'e'}) - if ((self.samplenum - self.es) / self.samplerate > 50e-6): - self.check_bit_(self.samplenum) - self.put(self.ss, self.es, self.out_ann, - [0, ['%d' % self.bit_]]) - self.bits.append(self.bit_) - self.handle_bits(self.es) - - self.ss = self.es - self.es = self.samplenum - self.state = 'RESET' - else: - self.state = 'BIT RISING' - elif self.state == 'BIT RISING': - self.check_bit_(self.samplenum) - self.put(self.ss, self.samplenum, self.out_ann, - [0, ['%d' % self.bit_]]) - self.bits.append(self.bit_) - self.handle_bits(self.samplenum) - - self.ss = self.samplenum - self.wait({0: 'e'}) - self.state = 'BIT FALLING' diff --git a/decoders/rtc8564/__init__.py b/decoders/rtc8564/__init__.py deleted file mode 100755 index f17e7515..00000000 --- a/decoders/rtc8564/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -''' -This decoder stacks on top of the 'i2c' PD and decodes the Epson -RTC-8564 JE/NB real-time clock (RTC) protocol. -''' - -from .pd import Decoder diff --git a/decoders/rtc8564/pd.py b/decoders/rtc8564/pd.py deleted file mode 100755 index b57fae64..00000000 --- a/decoders/rtc8564/pd.py +++ /dev/null @@ -1,254 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012-2014 Uwe Hermann -## -## 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, see . -## - -import sigrokdecode as srd -from common.srdhelper import bcd2int - -def reg_list(): - l = [] - for i in range(8 + 1): - l.append(('reg-0x%02x' % i, 'Register 0x%02x' % i)) - - return tuple(l) - -class Decoder(srd.Decoder): - api_version = 3 - id = 'rtc8564' - name = 'RTC-8564' - longname = 'Epson RTC-8564 JE/NB' - desc = 'Realtime clock module protocol.' - license = 'gplv2+' - inputs = ['i2c'] - outputs = [] - tags = ['Clock/timing'] - annotations = reg_list() + ( - ('read', 'Read date/time'), - ('write', 'Write date/time'), - ('bit-reserved', 'Reserved bit'), - ('bit-vl', 'VL bit'), - ('bit-century', 'Century bit'), - ('reg-read', 'Register read'), - ('reg-write', 'Register write'), - ) - annotation_rows = ( - ('bits', 'Bits', tuple(range(0, 8 + 1)) + (11, 12, 13)), - ('regs', 'Register access', (14, 15)), - ('date-time', 'Date/time', (9, 10)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.state = 'IDLE' - self.hours = -1 - self.minutes = -1 - self.seconds = -1 - self.days = -1 - self.weekdays = -1 - self.months = -1 - self.years = -1 - self.bits = [] - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putx(self, data): - self.put(self.ss, self.es, self.out_ann, data) - - def putd(self, bit1, bit2, data): - self.put(self.bits[bit1][1], self.bits[bit2][2], self.out_ann, data) - - def putr(self, bit): - self.put(self.bits[bit][1], self.bits[bit][2], self.out_ann, - [11, ['Reserved bit', 'Reserved', 'Rsvd', 'R']]) - - def handle_reg_0x00(self, b): # Control register 1 - pass - - def handle_reg_0x01(self, b): # Control register 2 - ti_tp = 1 if (b & (1 << 4)) else 0 - af = 1 if (b & (1 << 3)) else 0 - tf = 1 if (b & (1 << 2)) else 0 - aie = 1 if (b & (1 << 1)) else 0 - tie = 1 if (b & (1 << 0)) else 0 - - ann = '' - - s = 'repeated' if ti_tp else 'single-shot' - ann += 'TI/TP = %d: %s operation upon fixed-cycle timer interrupt '\ - 'events\n' % (ti_tp, s) - s = '' if af else 'no ' - ann += 'AF = %d: %salarm interrupt detected\n' % (af, s) - s = '' if tf else 'no ' - ann += 'TF = %d: %sfixed-cycle timer interrupt detected\n' % (tf, s) - s = 'enabled' if aie else 'prohibited' - ann += 'AIE = %d: INT# pin output %s when an alarm interrupt '\ - 'occurs\n' % (aie, s) - s = 'enabled' if tie else 'prohibited' - ann += 'TIE = %d: INT# pin output %s when a fixed-cycle interrupt '\ - 'event occurs\n' % (tie, s) - - self.putx([1, [ann]]) - - def handle_reg_0x02(self, b): # Seconds / Voltage-low bit - vl = 1 if (b & (1 << 7)) else 0 - self.putd(7, 7, [12, ['Voltage low: %d' % vl, 'Volt. low: %d' % vl, - 'VL: %d' % vl, 'VL']]) - s = self.seconds = bcd2int(b & 0x7f) - self.putd(6, 0, [2, ['Second: %d' % s, 'Sec: %d' % s, 'S: %d' % s, 'S']]) - - def handle_reg_0x03(self, b): # Minutes - self.putr(7) - m = self.minutes = bcd2int(b & 0x7f) - self.putd(6, 0, [3, ['Minute: %d' % m, 'Min: %d' % m, 'M: %d' % m, 'M']]) - - def handle_reg_0x04(self, b): # Hours - self.putr(7) - self.putr(6) - h = self.hours = bcd2int(b & 0x3f) - self.putd(5, 0, [4, ['Hour: %d' % h, 'H: %d' % h, 'H']]) - - def handle_reg_0x05(self, b): # Days - self.putr(7) - self.putr(6) - d = self.days = bcd2int(b & 0x3f) - self.putd(5, 0, [5, ['Day: %d' % d, 'D: %d' % d, 'D']]) - - def handle_reg_0x06(self, b): # Weekdays - for i in (7, 6, 5, 4, 3): - self.putr(i) - w = self.weekdays = bcd2int(b & 0x07) - self.putd(2, 0, [6, ['Weekday: %d' % w, 'WD: %d' % w, 'WD', 'W']]) - - def handle_reg_0x07(self, b): # Months / century bit - c = 1 if (b & (1 << 7)) else 0 - self.putd(7, 7, [13, ['Century bit: %d' % c, 'Century: %d' % c, - 'Cent: %d' % c, 'C: %d' % c, 'C']]) - self.putr(6) - self.putr(5) - m = self.months = bcd2int(b & 0x1f) - self.putd(4, 0, [7, ['Month: %d' % m, 'Mon: %d' % m, 'M: %d' % m, 'M']]) - - def handle_reg_0x08(self, b): # Years - y = self.years = bcd2int(b & 0xff) - self.putx([8, ['Year: %d' % y, 'Y: %d' % y, 'Y']]) - - def handle_reg_0x09(self, b): # Alarm, minute - pass - - def handle_reg_0x0a(self, b): # Alarm, hour - pass - - def handle_reg_0x0b(self, b): # Alarm, day - pass - - def handle_reg_0x0c(self, b): # Alarm, weekday - pass - - def handle_reg_0x0d(self, b): # CLKOUT output - pass - - def handle_reg_0x0e(self, b): # Timer setting - pass - - def handle_reg_0x0f(self, b): # Down counter for fixed-cycle timer - pass - - def decode(self, ss, es, data): - cmd, databyte = data - - # Collect the 'BITS' packet, then return. The next packet is - # guaranteed to belong to these bits we just stored. - if cmd == 'BITS': - self.bits = databyte - return - - # Store the start/end samples of this I²C packet. - self.ss, self.es = ss, es - - # State machine. - if self.state == 'IDLE': - # Wait for an I²C START condition. - if cmd != 'START': - return - self.state = 'GET SLAVE ADDR' - self.ss_block = ss - elif self.state == 'GET SLAVE ADDR': - # Wait for an address write operation. - # TODO: We should only handle packets to the RTC slave (0xa2/0xa3). - if cmd != 'ADDRESS WRITE': - return - self.state = 'GET REG ADDR' - elif self.state == 'GET REG ADDR': - # Wait for a data write (master selects the slave register). - if cmd != 'DATA WRITE': - return - self.reg = databyte - self.state = 'WRITE RTC REGS' - elif self.state == 'WRITE RTC REGS': - # If we see a Repeated Start here, it's probably an RTC read. - if cmd == 'START REPEAT': - self.state = 'READ RTC REGS' - return - # Otherwise: Get data bytes until a STOP condition occurs. - if cmd == 'DATA WRITE': - r, s = self.reg, '%02X: %02X' % (self.reg, databyte) - self.putx([15, ['Write register %s' % s, 'Write reg %s' % s, - 'WR %s' % s, 'WR', 'W']]) - handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg) - handle_reg(databyte) - self.reg += 1 - # TODO: Check for NACK! - elif cmd == 'STOP': - # TODO: Handle read/write of only parts of these items. - d = '%02d.%02d.%02d %02d:%02d:%02d' % (self.days, self.months, - self.years, self.hours, self.minutes, self.seconds) - self.put(self.ss_block, es, self.out_ann, - [9, ['Write date/time: %s' % d, 'Write: %s' % d, - 'W: %s' % d]]) - self.state = 'IDLE' - else: - pass # TODO - elif self.state == 'READ RTC REGS': - # Wait for an address read operation. - # TODO: We should only handle packets to the RTC slave (0xa2/0xa3). - if cmd == 'ADDRESS READ': - self.state = 'READ RTC REGS2' - return - else: - pass # TODO - elif self.state == 'READ RTC REGS2': - if cmd == 'DATA READ': - r, s = self.reg, '%02X: %02X' % (self.reg, databyte) - self.putx([15, ['Read register %s' % s, 'Read reg %s' % s, - 'RR %s' % s, 'RR', 'R']]) - handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg) - handle_reg(databyte) - self.reg += 1 - # TODO: Check for NACK! - elif cmd == 'STOP': - d = '%02d.%02d.%02d %02d:%02d:%02d' % (self.days, self.months, - self.years, self.hours, self.minutes, self.seconds) - self.put(self.ss_block, es, self.out_ann, - [10, ['Read date/time: %s' % d, 'Read: %s' % d, - 'R: %s' % d]]) - self.state = 'IDLE' - else: - pass # TODO? diff --git a/decoders/sae_j1850_vpw/__init__.py b/decoders/sae_j1850_vpw/__init__.py deleted file mode 100644 index 6894bfde..00000000 --- a/decoders/sae_j1850_vpw/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2016 Anthony Symons -## -## 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, see . -## - -''' -SAE J1850 Variable Pulse Width decoder. Decode GM VPW 1X and 4X Vehicle Bus. -''' - -from .pd import Decoder diff --git a/decoders/sae_j1850_vpw/pd.py b/decoders/sae_j1850_vpw/pd.py deleted file mode 100644 index fd2389ec..00000000 --- a/decoders/sae_j1850_vpw/pd.py +++ /dev/null @@ -1,165 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2016 Anthony Symons -## -## 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, see . -## - -import sigrokdecode as srd - -class SamplerateError(Exception): - pass - -def timeuf(t): - return int (t * 1000.0 * 1000.0) - -class Ann: - ANN_RAW, ANN_SOF, ANN_IFS, ANN_DATA, \ - ANN_PACKET = range(5) - -class Decoder(srd.Decoder): - api_version = 3 - id = 'sae_j1850_vpw' - name = 'SAE J1850 VPW' - longname = 'SAE J1850 VPW.' - desc = 'SAE J1850 Variable Pulse Width 1x and 4x.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Automotive'] - channels = ( - {'id': 'data', 'name': 'Data', 'desc': 'Data line'}, - ) - annotations = ( - ('raw', 'Raw'), - ('sof', 'SOF'), - ('ifs', 'EOF/IFS'), - ('data', 'Data'), - ('packet', 'Packet'), - ) - annotation_rows = ( - ('raws', 'Raws', (Ann.ANN_RAW, Ann.ANN_SOF, Ann.ANN_IFS,)), - ('bytes', 'Bytes', (Ann.ANN_DATA,)), - ('packets', 'Packets', (Ann.ANN_PACKET,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.state = 'IDLE' - self.samplerate = None - self.byte = 0 # the byte offset in the packet - self.mode = 0 # for by packet decode - self.data = 0 # the current byte - self.datastart = 0 # sample number this byte started at - self.csa = 0 # track the last byte seperately to retrospectively add the CS marker - self.csb = 0 - self.count = 0 # which bit number we are up to - self.active = 0 # which logic level is considered active - - # vpw timings. ideal, min and max tollerances. - # From SAE J1850 1995 rev section 23.406 - - self.sof = 200 - self.sofl = 164 - self.sofh = 245 # 240 by the spec, 245 so a 60us 4x sample will pass - self.long = 128 - self.longl = 97 - self.longh = 170 # 164 by the spec but 170 for low sample rate tolerance. - self.short = 64 - self.shortl = 24 # 35 by the spec, 24 to allow down to 6us as measured in practice for 4x @ 1mhz sampling - self.shorth = 97 - self.ifs = 240 - self.spd = 1 # set to 4 when a 4x SOF is detected (VPW high speed frame) - - def handle_bit(self, ss, es, b): - self.data |= (b << 7-self.count) # MSB-first - self.put(ss, es, self.out_ann, [Ann.ANN_RAW, ["%d" % b]]) - if self.count == 0: - self.datastart = ss - if self.count == 7: - self.csa = self.datastart # for CS - self.csb = self.samplenum # for CS - self.put(self.datastart, self.samplenum, self.out_ann, [Ann.ANN_DATA, ["%02X" % self.data]]) - # add protocol parsing here - if self.byte == 0: - self.put(self.datastart, self.samplenum, self.out_ann, [Ann.ANN_PACKET, ['Priority','Prio','P']]) - elif self.byte == 1: - self.put(self.datastart, self.samplenum, self.out_ann, [Ann.ANN_PACKET, ['Destination','Dest','D']]) - elif self.byte == 2: - self.put(self.datastart, self.samplenum, self.out_ann, [Ann.ANN_PACKET, ['Source','Src','S']]) - elif self.byte == 3: - self.put(self.datastart, self.samplenum, self.out_ann, [Ann.ANN_PACKET, ['Mode','M']]) - self.mode = self.data - elif self.mode == 1 and self.byte == 4: # mode 1 payload - self.put(self.datastart, self.samplenum, self.out_ann, [Ann.ANN_PACKET, ['Pid','P']]) - - # prepare for next byte - self.count = -1 - self.data = 0 - self.byte = self.byte + 1 # track packet offset - self.count = self.count + 1 - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - - self.wait({0: 'e'}) - es = self.samplenum - while True: - ss = es - pin, = self.wait({0: 'e'}) - es = self.samplenum - - samples = es - ss - t = timeuf(samples / self.samplerate) - if self.state == 'IDLE': # detect and set speed from the size of sof - if pin == self.active and t in range(self.sofl , self.sofh): - self.put(ss, es, self.out_ann, [Ann.ANN_RAW, ['1X SOF', 'S1', 'S']]) - self.spd = 1 - self.data = 0 - self.count = 0 - self.state = 'DATA' - elif pin == self.active and t in range(int(self.sofl / 4) , int(self.sofh / 4)): - self.put(ss, es, self.out_ann, [Ann.ANN_RAW, ['4X SOF', 'S4', '4']]) - self.spd = 4 - self.data = 0 - self.count = 0 - self.state = 'DATA' - - elif self.state == 'DATA': - if t >= int(self.ifs / self.spd): - self.state = 'IDLE' - self.put(ss, es, self.out_ann, [Ann.ANN_RAW, ["EOF/IFS", "E"]]) # EOF=239-280 IFS=281+ - self.put(self.csa, self.csb, self.out_ann, [Ann.ANN_PACKET, ['Checksum','CS','C']]) # retrospective print of CS - self.byte = 0 # reset packet offset - elif t in range(int(self.shortl / self.spd), int(self.shorth / self.spd)): - if pin == self.active: - self.handle_bit(ss, es, 1) - else: - self.handle_bit(ss, es, 0) - elif t in range(int(self.longl / self.spd), int(self.longh / self.spd)): - if pin == self.active: - self.handle_bit(ss, es, 0) - else: - self.handle_bit(ss, es, 1) diff --git a/decoders/sda2506/__init__.py b/decoders/sda2506/__init__.py deleted file mode 100755 index bf555109..00000000 --- a/decoders/sda2506/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Max Weller -## -## 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, see . -## - -''' -Decoder for Siemens EEPROM SDA 2506-5. -''' - -from .pd import Decoder diff --git a/decoders/sda2506/pd.py b/decoders/sda2506/pd.py deleted file mode 100755 index 813bff6a..00000000 --- a/decoders/sda2506/pd.py +++ /dev/null @@ -1,144 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Max Weller -## Copyright (C) 2019 DreamSourceLab -## -## 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, see . -## - -import re -import sigrokdecode as srd - -ann_cmdbit, ann_databit, ann_cmd, ann_data, ann_warning = range(5) - -class Decoder(srd.Decoder): - api_version = 3 - id = 'sda2506' - name = 'SDA2506' - longname = 'Siemens SDA 2506-5' - desc = 'Serial nonvolatile 1-Kbit EEPROM.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['IC', 'Memory'] - channels = ( - {'id': 'clk', 'name': 'CLK', 'desc': 'Clock'}, - {'id': 'd', 'name': 'DATA', 'desc': 'Data'}, - {'id': 'ce', 'name': 'CE#', 'desc': 'Chip-enable'}, - ) - annotations = ( - ('cmdbit', 'Command bit'), - ('databit', 'Data bit'), - ('cmd', 'Command'), - ('data', 'Data byte'), - ('warnings', 'Human-readable warnings'), - ) - annotation_rows = ( - ('bits', 'Bits', (ann_cmdbit, ann_databit)), - ('commands', 'Commands', (ann_cmd,)), - ('data', 'Data', (ann_data,)), - ('warnings', 'Warnings', (ann_warning,)), - ) - - def __init__(self): - self.samplerate = None - self.reset() - - def reset(self): - self.cmdbits = [] - self.databits = [] - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putbit(self, ss, es, typ, value): - self.put(ss, es, self.out_ann, [typ, ['%s' % (value)]]) - - def putdata(self, ss, es): - value = 0 - for i in range(8): - value = (value << 1) | self.databits[i] - self.put(ss, es, self.out_ann, [ann_data, ['%02X' % (value)]]) - - def decode_bits(self, offset, width): - out = 0 - for i in range(width): - out = (out << 1) | self.cmdbits[offset + i][0] - return (out, self.cmdbits[offset + width - 1][1], self.cmdbits[offset][2]) - - def decode_field(self, name, offset, width): - val, ss, es = self.decode_bits(offset, width) - self.put(ss, es, self.out_ann, [ann_data, ['%s: %02X' % (name, val)]]) - return val - - def decode(self): - while True: - # Wait for CLK edge or CE edge. - (clk, d, ce) = self.wait([{0: 'e'}, {2: 'e'}]) - - if (self.matched & (0b1 << 0)) and ce == 1 and clk == 1: - # Rising clk edge and command mode. - bitstart = self.samplenum - self.wait({0: 'f'}) - self.cmdbits = [(d, bitstart, self.samplenum)] + self.cmdbits - if len(self.cmdbits) > 24: - self.cmdbits = self.cmdbits[0:24] - self.putbit(bitstart, self.samplenum, ann_cmdbit, d) - elif (self.matched & (0b1 << 0)) and ce == 0 and clk == 0: - # Falling clk edge and data mode. - bitstart = self.samplenum - (clk, d, ce) = self.wait([{'skip': int(2.5 * (1e6 / self.samplerate))}, {0: 'r'}, {2: 'e'}]) # Wait 25 us for data ready. - if (self.matched & (0b1 << 2)) and not (self.matched & 0b011): - self.wait([{0: 'r'}, {2: 'e'}]) - if len(self.databits) == 0: - self.datastart = bitstart - self.databits = [d] + self.databits - self.putbit(bitstart, self.samplenum, ann_databit, d) - if len(self.databits) == 8: - self.putdata(self.datastart, self.samplenum) - self.databits = [] - elif (self.matched & (0b1 << 1)) and ce == 0: - # Chip enable edge. - try: - self.decode_field('addr', 1, 7) - self.decode_field('CB', 0, 1) - if self.cmdbits[0][0] == 0: - # Beginning read command. - self.decode_field('read', 1, 7) - self.put(self.cmdbits[7][1], self.samplenum, - self.out_ann, [ann_cmd, ['read' ]]) - elif d == 0: - # Beginning write command. - self.decode_field('data', 8, 8) - addr, ss, es = self.decode_bits(1, 7) - data, ss, es = self.decode_bits(8, 8) - cmdstart = self.samplenum - self.wait({2: 'r'}) - self.put(cmdstart, self.samplenum, self.out_ann, - [ann_cmd, ['Write to %02X: %02X' % (addr, data)]]) - else: - # Beginning erase command. - val, ss, es = self.decode_bits(1, 7) - cmdstart = self.samplenum - self.wait({2: 'r'}) - self.put(cmdstart, self.samplenum, self.out_ann, - [ann_cmd, ['Erase: %02X' % (val)]]) - self.databits = [] - except Exception as ex: - self.reset() diff --git a/decoders/sdcard_sd/__init__.py b/decoders/sdcard_sd/__init__.py deleted file mode 100755 index 7c334222..00000000 --- a/decoders/sdcard_sd/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Uwe Hermann -## -## 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, see . -## - -''' -SD card (SD mode) low-level protocol decoder. -''' - -from .pd import Decoder diff --git a/decoders/sdcard_sd/pd.py b/decoders/sdcard_sd/pd.py deleted file mode 100755 index 292d0a6c..00000000 --- a/decoders/sdcard_sd/pd.py +++ /dev/null @@ -1,583 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015-2020 Uwe Hermann -## -## 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, see . -## - -import sigrokdecode as srd -from common.srdhelper import SrdIntEnum, SrdStrEnum -from common.sdcard import (cmd_names, acmd_names, accepted_voltages, sd_status) - -responses = '1 1b 2 3 6 7'.split() -token_fields = 'START TRANSMISSION CMD ARG CRC END'.split() -reg_card_status = 'OUT_OF_RANGE ADDRESS_ERROR BLOCK_LEN_ERROR ERASE_SEQ_ERROR \ - ERASE_PARAM WP_VIOLATION CARD_IS_LOCKED LOCK_UNLOCK_FAILED COM_CRC_ERROR \ - ILLEGAL_COMMAND CARD_ECC_FAILED CC_ERROR ERROR RSVD_DEFERRED_RESPONSE \ - CSD_OVERWRITE WP_ERASE_SKIP CARD_ECC_DISABLED ERASE_RESET CURRENT_STATE \ - READY_FOR_DATA RSVD FX_EVENT APP_CMD RSVD_SDIO AKE_SEQ_ERROR RSVD_APP_CMD \ - RSVD_TESTMODE'.split() -reg_cid = 'MID OID PNM PRV PSN RSVD MDT CRC ONE'.split() -reg_csd = 'CSD_STRUCTURE RSVD TAAC NSAC TRAN_SPEED CCC READ_BL_LEN \ - READ_BL_PARTIAL WRITE_BLK_MISALIGN READ_BLK_MISALIGN DSR_IMP C_SIZE \ - VDD_R_CURR_MIN VDD_R_CURR_MAX VDD_W_CURR_MIN VDD_W_CURR_MAX C_SIZE_MULT \ - ERASE_BLK_EN SECTOR_SIZE WP_GRP_SIZE WP_GRP_ENABLE R2W_FACTOR \ - WRITE_BL_LEN WRITE_BL_PARTIAL FILE_FORMAT_GRP COPY PERM_WRITE_PROTECT \ - TMP_WRITE_PROTECT FILE_FORMAT CRC ONE'.split() - -Pin = SrdIntEnum.from_str('Pin', 'CMD CLK DAT0 DAT1 DAT2 DAT3') - -a = ['CMD%d' % i for i in range(64)] + ['ACMD%d' % i for i in range(64)] + \ - ['RESPONSE_R' + r.upper() for r in responses] + \ - ['R_STATUS_' + r for r in reg_card_status] + \ - ['R_CID_' + r for r in reg_cid] + \ - ['R_CSD_' + r for r in reg_csd] + \ - ['BIT_' + r for r in ('0', '1')] + \ - ['F_' + f for f in token_fields] + \ - ['DECODED_BIT', 'DECODED_F'] -Ann = SrdIntEnum.from_list('Ann', a) - -s = ['GET_COMMAND_TOKEN', 'HANDLE_CMD999'] + \ - ['HANDLE_CMD%d' % i for i in range(64)] + \ - ['HANDLE_ACMD%d' % i for i in range(64)] + \ - ['GET_RESPONSE_R%s' % r.upper() for r in responses] -St = SrdStrEnum.from_list('St', s) - -class Bit: - def __init__(self, s, e, b): - self.ss, self.es, self.bit = s, e ,b - -class Decoder(srd.Decoder): - api_version = 3 - id = 'sdcard_sd' - name = 'SD card (SD mode)' - longname = 'Secure Digital card (SD mode)' - desc = 'Secure Digital card (SD mode) low-level protocol.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Memory'] - channels = ( - {'id': 'cmd', 'name': 'CMD', 'desc': 'Command'}, - {'id': 'clk', 'name': 'CLK', 'desc': 'Clock'}, - ) - optional_channels = ( - {'id': 'dat0', 'name': 'DAT0', 'desc': 'Data pin 0'}, - {'id': 'dat1', 'name': 'DAT1', 'desc': 'Data pin 1'}, - {'id': 'dat2', 'name': 'DAT2', 'desc': 'Data pin 2'}, - {'id': 'dat3', 'name': 'DAT3', 'desc': 'Data pin 3'}, - ) - annotations = \ - tuple(('cmd%d' % i, 'CMD%d' % i) for i in range(64)) + \ - tuple(('acmd%d' % i, 'ACMD%d' % i) for i in range(64)) + \ - tuple(('response_r%s' % r, 'R%s' % r) for r in responses) + \ - tuple(('reg_status_' + r.lower(), 'Status: ' + r) for r in reg_card_status) + \ - tuple(('reg_cid_' + r.lower(), 'CID: ' + r) for r in reg_cid) + \ - tuple(('reg_csd_' + r.lower(), 'CSD: ' + r) for r in reg_csd) + \ - tuple(('bit_' + r, 'Bit ' + r) for r in ('0', '1')) + \ - tuple(('field-' + r.lower(), r) for r in token_fields) + \ - ( \ - ('decoded-bit', 'Decoded bit'), - ('decoded-field', 'Decoded field'), - ) - annotation_rows = ( - ('raw-bits', 'Raw bits', Ann.prefixes('BIT_')), - ('decoded-bits', 'Decoded bits', (Ann.DECODED_BIT,) + Ann.prefixes('R_')), - ('decoded-fields', 'Decoded fields', (Ann.DECODED_F,)), - ('fields', 'Fields', Ann.prefixes('F_')), - ('commands', 'Commands', Ann.prefixes('CMD ACMD RESPONSE_')), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.state = St.GET_COMMAND_TOKEN - self.token = [] - self.is_acmd = False # Indicates CMD vs. ACMD - self.cmd = None - self.last_cmd = None - self.arg = None - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putt(self, data): - self.put(self.token[0].ss, self.token[47].es, self.out_ann, data) - - def putf(self, s, e, data): - self.put(self.token[s].ss, self.token[e].es, self.out_ann, data) - - def puta(self, s, e, data): - self.put(self.token[47 - 8 - e].ss, self.token[47 - 8 - s].es, - self.out_ann, data) - - def putc(self, desc): - cmd = Ann.ACMD0 + self.cmd if self.is_acmd else self.cmd - self.last_cmd = cmd - self.putt([cmd, ['%s: %s' % (self.cmd_str, desc), self.cmd_str, - self.cmd_str.split(' ')[0]]]) - - def putr(self, r): - self.putt([r, ['Response: %s' % r.name.split('_')[1]]]) - - def cmd_name(self, cmd): - c = acmd_names if self.is_acmd else cmd_names - return c.get(cmd, 'Unknown') - - def get_token_bits(self, cmd_pin, n): - # Get a bit, return True if we already got 'n' bits, False otherwise. - self.token.append(Bit(self.samplenum, self.samplenum, cmd_pin)) - if len(self.token) > 0: - self.token[len(self.token) - 2].es = self.samplenum - if len(self.token) < n: - return False - self.token[n - 1].es += self.token[n - 1].ss - self.token[n - 2].ss - return True - - def is_from_host(self): - # CMD[46:46]: Transmission bit (1 == host), (0 == card) - return self.token[1].bit == 1 - - def is_from_card(self): - # CMD[46:46]: Transmission bit (1 == host), (0 == card) - return self.token[1].bit == 0 - - def handle_common_token_fields(self): - s = self.token - - # Annotations for each individual bit. - for bit in range(len(self.token)): - self.putf(bit, bit, [Ann.BIT_0 + s[bit].bit, ['%d' % s[bit].bit]]) - - # CMD[47:47]: Start bit (always 0) - self.putf(0, 0, [Ann.F_START, ['Start bit', 'Start', 'S']]) - - # CMD[46:46]: Transmission bit (1 == host) - t = 'host' if s[1].bit == 1 else 'card' - self.putf(1, 1, [Ann.F_TRANSMISSION, ['Transmission: ' + t, 'T: ' + t, 'T']]) - - # CMD[45:40]: Command index (BCD; valid: 0-63) - self.cmd = int('0b' + ''.join([str(s[i].bit) for i in range(2, 8)]), 2) - c = '%s (%d)' % (self.cmd_name(self.cmd), self.cmd) - self.putf(2, 7, [Ann.F_CMD, ['Command: ' + c, 'Cmd: ' + c, - 'CMD%d' % self.cmd, 'Cmd', 'C']]) - - # CMD[39:08]: Argument - self.arg = int('0b' + ''.join([str(s[i].bit) for i in range(8, 40)]), 2) - self.putf(8, 39, [Ann.F_ARG, ['Argument: 0x%08x' % self.arg, 'Arg', 'A']]) - - # CMD[07:01]: CRC7 - self.crc = int('0b' + ''.join([str(s[i].bit) for i in range(40, 47)]), 2) - self.putf(40, 46, [Ann.F_CRC, ['CRC: 0x%x' % self.crc, 'CRC', 'C']]) - - # CMD[00:00]: End bit (always 1) - self.putf(47, 47, [Ann.F_END, ['End bit', 'End', 'E']]) - - def get_command_token(self, cmd_pin): - # Command tokens (48 bits) are sent serially (MSB-first) by the host - # (over the CMD line), either to one SD card or to multiple ones. - # - # Format: - # - Bits[47:47]: Start bit (always 0) - # - Bits[46:46]: Transmission bit (1 == host) - # - Bits[45:40]: Command index (BCD; valid: 0-63) - # - Bits[39:08]: Argument - # - Bits[07:01]: CRC7 - # - Bits[00:00]: End bit (always 1) - - if not self.get_token_bits(cmd_pin, 48): - return - if not self.is_from_host(): - # Bad state due to a decoding mistake or a protocol error, - # drop the current token to try to recover from this situation. - self.token, self.state = [], St.GET_COMMAND_TOKEN - return - - self.handle_cmd() - - def handle_cmd(self): - self.handle_common_token_fields() - - # Handle command. - s = 'ACMD' if self.is_acmd else 'CMD' - self.cmd_str = '%s%d (%s)' % (s, self.cmd, self.cmd_name(self.cmd)) - if hasattr(self, 'handle_%s%d' % (s.lower(), self.cmd)): - self.state = St['HANDLE_CMD%d' % self.cmd] - else: - self.state = St.HANDLE_CMD999 - self.putc('%s%d' % (s, self.cmd)) - - def handle_cmd0(self): - # CMD0 (GO_IDLE_STATE) -> no response - self.puta(0, 31, [Ann.DECODED_F, ['Stuff bits', 'Stuff', 'SB', 'S']]) - self.putc('Reset all SD cards') - self.token, self.state = [], St.GET_COMMAND_TOKEN - - def handle_cmd2(self): - # CMD2 (ALL_SEND_CID) -> R2 - self.puta(0, 31, [Ann.DECODED_F, ['Stuff bits', 'Stuff', 'SB', 'S']]) - self.putc('Ask card for CID number') - self.token, self.state = [], St.GET_RESPONSE_R2 - - def handle_cmd3(self): - # CMD3 (SEND_RELATIVE_ADDR) -> R6 - self.puta(0, 31, [Ann.DECODED_F, ['Stuff bits', 'Stuff', 'SB', 'S']]) - self.putc('Ask card for new relative card address (RCA)') - self.token, self.state = [], St.GET_RESPONSE_R6 - - def handle_cmd6(self): - # CMD6 (SWITCH_FUNC) -> R1 - self.putc('Switch/check card function') - self.token, self.state = [], St.GET_RESPONSE_R1 - - def handle_cmd7(self): - # CMD7 (SELECT/DESELECT_CARD) -> R1b - self.putc('Select / deselect card') - self.token, self.state = [], St.GET_RESPONSE_R6 - - def handle_cmd8(self): - # CMD8 (SEND_IF_COND) -> R7 - self.puta(12, 31, [Ann.DECODED_F, ['Reserved', 'Res', 'R']]) - self.puta(8, 11, [Ann.DECODED_F, ['Supply voltage', 'Voltage', 'VHS', 'V']]) - self.puta(0, 7, [Ann.DECODED_F, ['Check pattern', 'Check pat', 'Check', 'C']]) - self.putc('Send interface condition to card') - self.token, self.state = [], St.GET_RESPONSE_R7 - # TODO: Handle case when card doesn't reply with R7 (no reply at all). - - def handle_cmd9(self): - # CMD9 (SEND_CSD) -> R2 - self.puta(16, 31, [Ann.DECODED_F, ['RCA', 'R']]) - self.puta(0, 15, [Ann.DECODED_F, ['Stuff bits', 'Stuff', 'SB', 'S']]) - self.putc('Send card-specific data (CSD)') - self.token, self.state = [], St.GET_RESPONSE_R2 - - def handle_cmd10(self): - # CMD10 (SEND_CID) -> R2 - self.puta(16, 31, [Ann.DECODED_F, ['RCA', 'R']]) - self.puta(0, 15, [Ann.DECODED_F, ['Stuff bits', 'Stuff', 'SB', 'S']]) - self.putc('Send card identification data (CID)') - self.token, self.state = [], St.GET_RESPONSE_R2 - - def handle_cmd13(self): - # CMD13 (SEND_STATUS) -> R1 - self.puta(16, 31, [Ann.DECODED_F, ['RCA', 'R']]) - self.puta(0, 15, [Ann.DECODED_F, ['Stuff bits', 'Stuff', 'SB', 'S']]) - self.putc('Send card status register') - self.token, self.state = [], St.GET_RESPONSE_R1 - - def handle_cmd16(self): - # CMD16 (SET_BLOCKLEN) -> R1 - self.puta(0, 31, [Ann.DECODED_F, ['Block length', 'Blocklen', 'BL', 'B']]) - self.putc('Set the block length to %d bytes' % self.arg) - self.token, self.state = [], St.GET_RESPONSE_R1 - - def handle_cmd55(self): - # CMD55 (APP_CMD) -> R1 - self.puta(16, 31, [Ann.DECODED_F, ['RCA', 'R']]) - self.puta(0, 15, [Ann.DECODED_F, ['Stuff bits', 'Stuff', 'SB', 'S']]) - self.putc('Next command is an application-specific command') - self.is_acmd = True - self.token, self.state = [], St.GET_RESPONSE_R1 - - def handle_acmd6(self): - # ACMD6 (SET_BUS_WIDTH) -> R1 - self.putc('Read SD config register (SCR)') - self.token, self.state = [], St.GET_RESPONSE_R1 - - def handle_acmd13(self): - # ACMD13 (SD_STATUS) -> R1 - self.puta(0, 31, [Ann.DECODED_F, ['Stuff bits', 'Stuff', 'SB', 'S']]) - self.putc('Set SD status') - self.token, self.state = [], St.GET_RESPONSE_R1 - - def handle_acmd41(self): - # ACMD41 (SD_SEND_OP_COND) -> R3 - self.puta(0, 23, [Ann.DECODED_F, - ['VDD voltage window', 'VDD volt', 'VDD', 'V']]) - self.puta(24, 24, [Ann.DECODED_F, ['S18R']]) - self.puta(25, 27, [Ann.DECODED_F, ['Reserved', 'Res', 'R']]) - self.puta(28, 28, [Ann.DECODED_F, ['XPC']]) - self.puta(29, 29, [Ann.DECODED_F, - ['Reserved for eSD', 'Reserved', 'Res', 'R']]) - self.puta(30, 30, [Ann.DECODED_F, - ['Host capacity support info', 'Host capacity', 'HCS', 'H']]) - self.puta(31, 31, [Ann.DECODED_F, ['Reserved', 'Res', 'R']]) - self.putc('Send HCS info and activate the card init process') - self.token, self.state = [], St.GET_RESPONSE_R3 - - def handle_acmd51(self): - # ACMD51 (SEND_SCR) -> R1 - self.putc('Read SD config register (SCR)') - self.token, self.state = [], St.GET_RESPONSE_R1 - - def handle_cmd999(self): - self.token, self.state = [], St.GET_RESPONSE_R1 - - def handle_acmd999(self): - self.token, self.state = [], St.GET_RESPONSE_R1 - - def handle_reg_status(self): - self.putf(8, 8, [Ann.R_STATUS_OUT_OF_RANGE, ['OUT_OF_RANGE']]) - self.putf(9, 9, [Ann.R_STATUS_ADDRESS_ERROR, ['ADDRESS_ERROR']]) - self.putf(10, 10, [Ann.R_STATUS_BLOCK_LEN_ERROR, ['BLOCK_LEN_ERROR']]) - self.putf(11, 11, [Ann.R_STATUS_ERASE_SEQ_ERROR, ['ERASE_SEQ_ERROR']]) - self.putf(12, 12, [Ann.R_STATUS_ERASE_PARAM, ['ERASE_PARAM']]) - self.putf(13, 13, [Ann.R_STATUS_WP_VIOLATION, ['WP_VIOLATION']]) - self.putf(14, 14, [Ann.R_STATUS_CARD_IS_LOCKED, ['CARD_IS_LOCKED']]) - self.putf(15, 15, [Ann.R_STATUS_LOCK_UNLOCK_FAILED, ['LOCK_UNLOCK_FAILED']]) - self.putf(16, 16, [Ann.R_STATUS_COM_CRC_ERROR, ['COM_CRC_ERROR']]) - self.putf(17, 17, [Ann.R_STATUS_ILLEGAL_COMMAND, ['ILLEGAL_COMMAND']]) - self.putf(18, 18, [Ann.R_STATUS_CARD_ECC_FAILED, ['CARD_ECC_FAILED']]) - self.putf(19, 19, [Ann.R_STATUS_CC_ERROR, ['CC_ERROR']]) - self.putf(20, 20, [Ann.R_STATUS_ERROR, ['ERROR']]) - self.putf(21, 21, [Ann.R_STATUS_RSVD, ['Reserved', 'RSVD', 'R']]) - self.putf(22, 22, [Ann.R_STATUS_RSVD_DEFERRED_RESPONSE, ['Reserved for DEFERRED_RESPONSE', 'RSVD_DEFERRED_RESPONSE']]) - self.putf(23, 23, [Ann.R_STATUS_CSD_OVERWRITE, ['CSD_OVERWRITE']]) - self.putf(24, 24, [Ann.R_STATUS_WP_ERASE_SKIP, ['WP_ERASE_SKIP']]) - self.putf(25, 25, [Ann.R_STATUS_CARD_ECC_DISABLED, ['CARD_ECC_DISABLED']]) - self.putf(26, 26, [Ann.R_STATUS_ERASE_RESET, ['ERASE_RESET']]) - self.putf(27, 30, [Ann.R_STATUS_CURRENT_STATE, ['CURRENT_STATE']]) - self.putf(31, 31, [Ann.R_STATUS_READY_FOR_DATA, ['READY_FOR_DATA']]) - self.putf(32, 32, [Ann.R_STATUS_RSVD, ['RSVD']]) - self.putf(33, 33, [Ann.R_STATUS_FX_EVENT, ['FX_EVENT']]) - self.putf(34, 34, [Ann.R_STATUS_APP_CMD, ['APP_CMD']]) - self.putf(35, 35, [Ann.R_STATUS_RSVD_SDIO, ['Reserved for SDIO card', 'RSVD_SDIO']]) - self.putf(36, 36, [Ann.R_STATUS_AKE_SEQ_ERROR, ['AKE_SEQ_ERROR']]) - self.putf(37, 37, [Ann.R_STATUS_RSVD_APP_CMD, ['Reserved for application specific commands', 'RSVD_APP_CMD']]) - self.putf(38, 39, [Ann.R_STATUS_RSVD_TESTMODE, ['Reserved for manufacturer test mode', 'RSVD_TESTMODE']]) - - def handle_reg_cid(self): - self.putf(8, 15, [Ann.R_CID_MID, ['Manufacturer ID', 'MID']]) - self.putf(16, 31, [Ann.R_CID_OID, ['OEM/application ID', 'OID']]) - self.putf(32, 71, [Ann.R_CID_PNM, ['Product name', 'PNM']]) - self.putf(72, 79, [Ann.R_CID_PRV, ['Product revision', 'PRV']]) - self.putf(80, 111, [Ann.R_CID_PSN, ['Product serial number', 'PSN']]) - self.putf(112, 115, [Ann.R_CID_RSVD, ['Reserved', 'RSVD', 'R']]) - self.putf(116, 127, [Ann.R_CID_MDT, ['Manufacturing date', 'MDT']]) - self.putf(128, 134, [Ann.R_CID_CRC, ['CRC7 checksum', 'CRC']]) - self.putf(135, 135, [Ann.R_CID_ONE, ['Always 1', '1']]) - - def handle_reg_csd(self): - self.putf(8, 9, [Ann.R_CSD_CSD_STRUCTURE, ['CSD structure', 'CSD_STRUCTURE']]) - self.putf(10, 15, [Ann.R_CSD_RSVD, ['Reserved', 'RSVD', 'R']]) - self.putf(16, 23, [Ann.R_CSD_TAAC, ['Data read access-time - 1', 'TAAC']]) - self.putf(24, 31, [Ann.R_CSD_NSAC, ['Data read access-time - 2 in CLK cycles (NSAC * 100)', 'NSAC']]) - self.putf(32, 39, [Ann.R_CSD_TRAN_SPEED, ['Max. data transfer rate', 'TRAN_SPEED']]) - self.putf(40, 51, [Ann.R_CSD_CCC, ['Card command classes', 'CCC']]) - self.putf(52, 55, [Ann.R_CSD_READ_BL_LEN, ['Max. read data block length', 'READ_BL_LEN']]) - self.putf(56, 56, [Ann.R_CSD_READ_BL_PARTIAL, ['Partial blocks for read allowed', 'READ_BL_PARTIAL']]) - self.putf(57, 57, [Ann.R_CSD_WRITE_BLK_MISALIGN, ['Write block misalignment', 'WRITE_BLK_MISALIGN']]) - self.putf(58, 58, [Ann.R_CSD_READ_BLK_MISALIGN, ['Read block misalignment', 'READ_BLK_MISALIGN']]) - self.putf(59, 59, [Ann.R_CSD_DSR_IMP, ['DSR implemented', 'DSR_IMP']]) - self.putf(60, 61, [Ann.R_CSD_RSVD, ['Reserved', 'RSVD', 'R']]) - self.putf(62, 73, [Ann.R_CSD_C_SIZE, ['Device size', 'C_SIZE']]) - self.putf(74, 76, [Ann.R_CSD_VDD_R_CURR_MIN, ['Max. read current @VDD min', 'VDD_R_CURR_MIN']]) - self.putf(77, 79, [Ann.R_CSD_VDD_R_CURR_MAX, ['Max. read current @VDD max', 'VDD_R_CURR_MAX']]) - self.putf(80, 82, [Ann.R_CSD_VDD_W_CURR_MIN, ['Max. write current @VDD min', 'VDD_W_CURR_MIN']]) - self.putf(83, 85, [Ann.R_CSD_VDD_W_CURR_MAX, ['Max. write current @VDD max', 'VDD_W_CURR_MAX']]) - self.putf(86, 88, [Ann.R_CSD_C_SIZE_MULT, ['Device size multiplier', 'C_SIZE_MULT']]) - self.putf(89, 89, [Ann.R_CSD_ERASE_BLK_EN, ['Erase single block enable', 'ERASE_BLK_EN']]) - self.putf(90, 96, [Ann.R_CSD_SECTOR_SIZE, ['Erase sector size', 'SECTOR_SIZE']]) - self.putf(97, 103, [Ann.R_CSD_WP_GRP_SIZE, ['Write protect group size', 'WP_GRP_SIZE']]) - self.putf(104, 104, [Ann.R_CSD_WP_GRP_ENABLE, ['Write protect group enable', 'WP_GRP_ENABLE']]) - self.putf(105, 106, [Ann.R_CSD_RSVD, ['Reserved', 'RSVD', 'R']]) - self.putf(107, 109, [Ann.R_CSD_R2W_FACTOR, ['Write speed factor', 'R2W_FACTOR']]) - self.putf(110, 113, [Ann.R_CSD_WRITE_BL_LEN, ['Max. write data block length', 'WRITE_BL_LEN']]) - self.putf(114, 114, [Ann.R_CSD_WRITE_BL_PARTIAL, ['Partial blocks for write allowed', 'WRITE_BL_PARTIAL']]) - self.putf(115, 119, [Ann.R_CSD_RSVD, ['Reserved', 'RSVD']]) - self.putf(120, 120, [Ann.R_CSD_FILE_FORMAT_GRP, ['File format group', 'FILE_FORMAT_GRP']]) - self.putf(121, 121, [Ann.R_CSD_COPY, ['Copy flag', 'COPY']]) - self.putf(122, 122, [Ann.R_CSD_PERM_WRITE_PROTECT, ['Permanent write protection', 'PERM_WRITE_PROTECT']]) - self.putf(123, 123, [Ann.R_CSD_TMP_WRITE_PROTECT, ['Temporary write protection', 'TMP_WRITE_PROTECT']]) - self.putf(124, 125, [Ann.R_CSD_FILE_FORMAT, ['File format', 'FILE_FORMAT']]) - self.putf(126, 127, [Ann.R_CSD_RSVD, ['Reserved', 'RSVD', 'R']]) - self.putf(128, 134, [Ann.R_CSD_CRC, ['CRC', 'CRC', 'C']]) - self.putf(135, 135, [Ann.R_CSD_ONE, ['Always 1', '1']]) - - # Response tokens can have one of four formats (depends on content). - # They can have a total length of 48 or 136 bits. - # They're sent serially (MSB-first) by the card that the host - # addressed previously, or (synchronously) by all connected cards. - - def handle_response_r1(self, cmd_pin): - # R1: Normal response command - # - Bits[47:47]: Start bit (always 0) - # - Bits[46:46]: Transmission bit (0 == card) - # - Bits[45:40]: Command index (BCD; valid: 0-63) - # - Bits[39:08]: Card status - # - Bits[07:01]: CRC7 - # - Bits[00:00]: End bit (always 1) - if not self.get_token_bits(cmd_pin, 48): - return - assert(self.is_from_card()) - self.handle_common_token_fields() - self.putr(Ann.RESPONSE_R1) - self.puta(0, 31, [Ann.DECODED_F, ['Card status', 'Status', 'S']]) - self.handle_reg_status() - - self.token, self.state = [], St.GET_COMMAND_TOKEN - - def handle_response_r1b(self, cmd_pin): - # R1b: Same as R1 with an optional busy signal (on the data line) - if not self.get_token_bits(cmd_pin, 48): - return - assert(self.is_from_card()) - self.handle_common_token_fields() - self.puta(0, 31, [Ann.DECODED_F, ['Card status', 'Status', 'S']]) - self.putr(Ann.RESPONSE_R1B) - self.token, self.state = [], St.GET_COMMAND_TOKEN - - def handle_response_r2(self, cmd_pin): - # R2: CID/CSD register - # - Bits[135:135]: Start bit (always 0) - # - Bits[134:134]: Transmission bit (0 == card) - # - Bits[133:128]: Reserved (always 0b111111) - # - Bits[127:001]: CID or CSD register including internal CRC7 - # - Bits[000:000]: End bit (always 1) - if not self.get_token_bits(cmd_pin, 136): - return - assert(self.is_from_card()) - # Annotations for each individual bit. - for bit in range(len(self.token)): - self.putf(bit, bit, [Ann.BIT_0 + self.token[bit].bit, ['%d' % self.token[bit].bit]]) - self.putf(0, 0, [Ann.F_START, ['Start bit', 'Start', 'S']]) - t = 'host' if self.token[1].bit == 1 else 'card' - self.putf(1, 1, [Ann.F_TRANSMISSION, ['Transmission: ' + t, 'T: ' + t, 'T']]) - self.putf(2, 7, [Ann.F_CMD, ['Reserved', 'Res', 'R']]) - self.putf(8, 134, [Ann.F_ARG, ['Argument', 'Arg', 'A']]) - self.putf(135, 135, [Ann.F_END, ['End bit', 'End', 'E']]) - self.putf(8, 134, [Ann.DECODED_F, ['CID/CSD register', 'CID/CSD', 'C']]) - self.putf(0, 135, [Ann.RESPONSE_R2, ['Response: R2']]) - - if self.last_cmd in (Ann.CMD2, Ann.CMD10): - self.handle_reg_cid() - - if self.last_cmd == Ann.CMD9: - self.handle_reg_csd() - - self.token, self.state = [], St.GET_COMMAND_TOKEN - - def handle_response_r3(self, cmd_pin): - # R3: OCR register - # - Bits[47:47]: Start bit (always 0) - # - Bits[46:46]: Transmission bit (0 == card) - # - Bits[45:40]: Reserved (always 0b111111) - # - Bits[39:08]: OCR register - # - Bits[07:01]: Reserved (always 0b111111) - # - Bits[00:00]: End bit (always 1) - if not self.get_token_bits(cmd_pin, 48): - return - assert(self.is_from_card()) - self.putr(Ann.RESPONSE_R3) - # Annotations for each individual bit. - for bit in range(len(self.token)): - self.putf(bit, bit, [Ann.BIT_0 + self.token[bit].bit, ['%d' % self.token[bit].bit]]) - self.putf(0, 0, [Ann.F_START, ['Start bit', 'Start', 'S']]) - t = 'host' if self.token[1].bit == 1 else 'card' - self.putf(1, 1, [Ann.F_TRANSMISSION, ['Transmission: ' + t, 'T: ' + t, 'T']]) - self.putf(2, 7, [Ann.F_CMD, ['Reserved', 'Res', 'R']]) - self.putf(8, 39, [Ann.F_ARG, ['Argument', 'Arg', 'A']]) - self.putf(40, 46, [Ann.F_CRC, ['Reserved', 'Res', 'R']]) - self.putf(47, 47, [Ann.F_END, ['End bit', 'End', 'E']]) - self.puta(0, 31, [Ann.DECODED_F, ['OCR register', 'OCR reg', 'OCR', 'O']]) - self.token, self.state = [], St.GET_COMMAND_TOKEN - - def handle_response_r6(self, cmd_pin): - # R6: Published RCA response - # - Bits[47:47]: Start bit (always 0) - # - Bits[46:46]: Transmission bit (0 == card) - # - Bits[45:40]: Command index (always 0b000011) - # - Bits[39:24]: Argument[31:16]: New published RCA of the card - # - Bits[23:08]: Argument[15:0]: Card status bits - # - Bits[07:01]: CRC7 - # - Bits[00:00]: End bit (always 1) - if not self.get_token_bits(cmd_pin, 48): - return - assert(self.is_from_card()) - self.handle_common_token_fields() - self.puta(0, 15, [Ann.DECODED_F, ['Card status bits', 'Status', 'S']]) - self.puta(16, 31, [Ann.DECODED_F, ['Relative card address', 'RCA', 'R']]) - self.putr(Ann.RESPONSE_R6) - self.token, self.state = [], St.GET_COMMAND_TOKEN - - def handle_response_r7(self, cmd_pin): - # R7: Card interface condition - # - Bits[47:47]: Start bit (always 0) - # - Bits[46:46]: Transmission bit (0 == card) - # - Bits[45:40]: Command index (always 0b001000) - # - Bits[39:20]: Reserved bits (all-zero) - # - Bits[19:16]: Voltage accepted - # - Bits[15:08]: Echo-back of check pattern - # - Bits[07:01]: CRC7 - # - Bits[00:00]: End bit (always 1) - if not self.get_token_bits(cmd_pin, 48): - return - assert(self.is_from_card()) - self.handle_common_token_fields() - - self.putr(Ann.RESPONSE_R7) - - # Arg[31:12]: Reserved bits (all-zero) - self.puta(12, 31, [Ann.DECODED_F, ['Reserved', 'Res', 'R']]) - - # Arg[11:08]: Voltage accepted - v = ''.join(str(i.bit) for i in self.token[28:32]) - av = accepted_voltages.get(int('0b' + v, 2), 'Unknown') - self.puta(8, 11, [Ann.DECODED_F, - ['Voltage accepted: ' + av, 'Voltage', 'Volt', 'V']]) - - # Arg[07:00]: Echo-back of check pattern - self.puta(0, 7, [Ann.DECODED_F, - ['Echo-back of check pattern', 'Echo', 'E']]) - - self.token, self.state = [], St.GET_COMMAND_TOKEN - - def decode(self): - while True: - conds = {Pin.CLK: 'r'} - - # Wait for start bit (CMD = 0). - if ((self.state == St.GET_COMMAND_TOKEN or - self.state.value.startswith('GET_RESPONSE')) and - (len(self.token) == 0)): - conds.update({Pin.CMD: 'l'}) - - # Wait for a rising CLK edge. - (cmd_pin, clk, dat0, dat1, dat2, dat3) = self.wait(conds) - - # State machine. - if self.state == St.GET_COMMAND_TOKEN: - self.get_command_token(cmd_pin) - elif self.state.value.startswith('HANDLE_CMD'): - # Call the respective handler method for the command. - a, cmdstr = 'a' if self.is_acmd else '', self.state.value[10:].lower() - handle_cmd = getattr(self, 'handle_%scmd%s' % (a, cmdstr)) - handle_cmd() - # Leave ACMD mode again after the first command after CMD55. - if self.is_acmd and cmdstr not in ('55', '63'): - self.is_acmd = False - elif self.state.value.startswith('GET_RESPONSE'): - # Call the respective handler method for the response. - s = 'handle_response_%s' % self.state.value[13:].lower() - handle_response = getattr(self, s) - - # AssertionError can be raised when the token we are trying - # to handle as a response is in fact a command. - # (Transmission bit is 1). Just re-handle the token as command. - try: - handle_response(cmd_pin) - except AssertionError: - self.handle_cmd() diff --git a/decoders/sdcard_spi/__init__.py b/decoders/sdcard_spi/__init__.py deleted file mode 100755 index a0945162..00000000 --- a/decoders/sdcard_spi/__init__.py +++ /dev/null @@ -1,68 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -''' -This decoder stacks on top of the 'spi' PD and decodes the SD card -(SPI mode) low-level protocol. - -Most SD cards can be accessed via two different protocols/modes: SD mode -or SPI mode. - -All SD cards are in SD mode upon powerup. They can be switched to SPI mode -using a special method involving CMD0 (see spec). Once in SPI mode, the mode -can no longer be changed without a power-cycle of the card. - -SPI mode properties (differences to SD mode): - * The 'sdcard_spi' PD stacks on top of the 'spi' PD. This is not possible - for the 'sdcard_sd' PD, as that protocol is not SPI related at all. - Hence 'sdcard_spi' and 'sdcard_sd' are two separate PDs. - * The state machines for SPI mode and SD mode are different. - * In SPI mode, data transfers are byte-oriented (commands/data are multiples - of 8 bits, with the CS# pin asserted respectively), unlike SD mode where - commands/data are bit-oriented with parallel transmission of 1 or 4 bits. - * While the SPI mode command set has some commands in common with the - SD mode command set, they are not the same and also not a subset/superset. - Some commands are only available in SD mode (e.g. CMD2), some only - in SPI mode (e.g. CMD1). - * Response types of commands also differ between SD mode and SPI mode. - E.g. CMD9 has an R2 response in SD mode, but R1 in SPI mode. - * The commands and functions in SD mode defined after version 2.00 of the - spec are NOT supported in SPI mode. - * SPI mode: The selected SD card ALWAYS responds to commands (unlike SD mode). - * Upon data retrieval problems (read operations) the card will respond with - an error response (and no data), as opposed to a timeout in SD mode. - * SPI mode: For every data block sent to the card (write operations) the host - gets a data response token from the card. - * SDSC: A data block can be max. one card write block, min. 1 byte. - * SDHC/SDXC: Block length is fixed to 512. The block length set by CMD16 - is only used for CDM42 (not for memory data transfers). Thus, partial - read/write operations are disabled in SPI mode. - * SPI mode: Write protected commands (CMD28, CMD29, CMD30) are not supported. - * The SD mode state machine is NOT used. All commands that are supported - in SPI mode are always available. - * Per default the card is in CRC OFF mode. Exception: CMD0 (which is used to - switch to SPI mode) needs a valid CRC. - * The APP_CMD status bit is not available in SPI mode. - * TODO: Switch function command differences. - * In SPI mode cards cannot guarantee their speed class (the host should - assume class 0, no matter what the card indicates). - * The RCA register is not accessible in SPI mode. -''' - -from .pd import Decoder diff --git a/decoders/sdcard_spi/pd.py b/decoders/sdcard_spi/pd.py deleted file mode 100755 index 962438f1..00000000 --- a/decoders/sdcard_spi/pd.py +++ /dev/null @@ -1,465 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012-2014 Uwe Hermann -## -## 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, see . -## - -import sigrokdecode as srd -from common.sdcard import (cmd_names, acmd_names) - -class Decoder(srd.Decoder): - api_version = 3 - id = 'sdcard_spi' - name = 'SD card (SPI mode)' - longname = 'Secure Digital card (SPI mode)' - desc = 'Secure Digital card (SPI mode) low-level protocol.' - license = 'gplv2+' - inputs = ['spi'] - outputs = [] - tags = ['Memory'] - annotations = \ - tuple(('cmd%d' % i, 'CMD%d' % i) for i in range(64)) + \ - tuple(('acmd%d' % i, 'ACMD%d' % i) for i in range(64)) + ( \ - ('r1', 'R1 reply'), - ('r1b', 'R1B reply'), - ('r2', 'R2 reply'), - ('r3', 'R3 reply'), - ('r7', 'R7 reply'), - ('bits', 'Bits'), - ('bit-warnings', 'Bit warnings'), - ) - annotation_rows = ( - ('bits', 'Bits', (133, 134)), - ('cmd-reply', 'Commands/replies', tuple(range(133))), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.state = 'IDLE' - self.ss, self.es = 0, 0 - self.ss_bit, self.es_bit = 0, 0 - self.ss_cmd, self.es_cmd = 0, 0 - self.cmd_token = [] - self.cmd_token_bits = [] - self.is_acmd = False # Indicates CMD vs. ACMD - self.blocklen = 0 - self.read_buf = [] - self.cmd_str = '' - self.is_cmd24 = False - self.cmd24_start_token_found = False - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putx(self, data): - self.put(self.ss_cmd, self.es_cmd, self.out_ann, data) - - def putc(self, cmd, desc): - self.putx([cmd, ['%s: %s' % (self.cmd_str, desc)]]) - - def putb(self, data): - self.put(self.ss_bit, self.es_bit, self.out_ann, data) - - def cmd_name(self, cmd): - c = acmd_names if self.is_acmd else cmd_names - s = c.get(cmd, 'Unknown') - # SD mode names for CMD32/33: ERASE_WR_BLK_{START,END}. - # SPI mode names for CMD32/33: ERASE_WR_BLK_{START,END}_ADDR. - if cmd in (32, 33): - s += '_ADDR' - return s - - def handle_command_token(self, mosi, miso): - # Command tokens (6 bytes) are sent (MSB-first) by the host. - # - # Format: - # - CMD[47:47]: Start bit (always 0) - # - CMD[46:46]: Transmitter bit (1 == host) - # - CMD[45:40]: Command index (BCD; valid: 0-63) - # - CMD[39:08]: Argument - # - CMD[07:01]: CRC7 - # - CMD[00:00]: End bit (always 1) - - if len(self.cmd_token) == 0: - self.ss_cmd = self.ss - - self.cmd_token.append(mosi) - self.cmd_token_bits.append(self.mosi_bits) - - # All command tokens are 6 bytes long. - if len(self.cmd_token) < 6: - return - - self.es_cmd = self.es - - t = self.cmd_token - - # CMD or ACMD? - s = 'ACMD' if self.is_acmd else 'CMD' - - def tb(byte, bit): - return self.cmd_token_bits[5 - byte][bit] - - # Bits[47:47]: Start bit (always 0) - bit, self.ss_bit, self.es_bit = tb(5, 7)[0], tb(5, 7)[1], tb(5, 7)[2] - if bit == 0: - self.putb([134, ['Start bit: %d' % bit]]) - else: - self.putb([135, ['Start bit: %s (Warning: Must be 0!)' % bit]]) - - # Bits[46:46]: Transmitter bit (1 == host) - bit, self.ss_bit, self.es_bit = tb(5, 6)[0], tb(5, 6)[1], tb(5, 6)[2] - if bit == 1: - self.putb([134, ['Transmitter bit: %d' % bit]]) - else: - self.putb([135, ['Transmitter bit: %d (Warning: Must be 1!)' % bit]]) - - # Bits[45:40]: Command index (BCD; valid: 0-63) - cmd = self.cmd_index = t[0] & 0x3f - self.ss_bit, self.es_bit = tb(5, 5)[1], tb(5, 0)[2] - self.putb([134, ['Command: %s%d (%s)' % (s, cmd, self.cmd_name(cmd))]]) - - # Bits[39:8]: Argument - self.arg = (t[1] << 24) | (t[2] << 16) | (t[3] << 8) | t[4] - self.ss_bit, self.es_bit = tb(4, 7)[1], tb(1, 0)[2] - self.putb([134, ['Argument: 0x%04x' % self.arg]]) - - # Bits[7:1]: CRC7 - # TODO: Check CRC7. - crc = t[5] >> 1 - self.ss_bit, self.es_bit = tb(0, 7)[1], tb(0, 1)[2] - self.putb([134, ['CRC7: 0x%01x' % crc]]) - - # Bits[0:0]: End bit (always 1) - bit, self.ss_bit, self.es_bit = tb(0, 0)[0], tb(0, 0)[1], tb(0, 0)[2] - if bit == 1: - self.putb([134, ['End bit: %d' % bit]]) - else: - self.putb([135, ['End bit: %d (Warning: Must be 1!)' % bit]]) - - # Handle command. - if cmd in (0, 1, 9, 16, 17, 24, 41, 49, 55, 59): - self.state = 'HANDLE CMD%d' % cmd - self.cmd_str = '%s%d (%s)' % (s, cmd, self.cmd_name(cmd)) - else: - self.state = 'HANDLE CMD999' - a = '%s%d: %02x %02x %02x %02x %02x %02x' % ((s, cmd) + tuple(t)) - self.putx([cmd, [a]]) - - def handle_cmd0(self): - # CMD0: GO_IDLE_STATE - self.putc(0, 'Reset the SD card') - self.state = 'GET RESPONSE R1' - - def handle_cmd1(self): - # CMD1: SEND_OP_COND - self.putc(1, 'Send HCS info and activate the card init process') - hcs = (self.arg & (1 << 30)) >> 30 - self.ss_bit = self.cmd_token_bits[5 - 4][6][1] - self.es_bit = self.cmd_token_bits[5 - 4][6][2] - self.putb([134, ['HCS: %d' % hcs]]) - self.state = 'GET RESPONSE R1' - - def handle_cmd9(self): - # CMD9: SEND_CSD (128 bits / 16 bytes) - self.putc(9, 'Ask card to send its card specific data (CSD)') - if len(self.read_buf) == 0: - self.ss_cmd = self.ss - self.read_buf.append(self.miso) - # FIXME - ### if len(self.read_buf) < 16: - if len(self.read_buf) < 16 + 4: - return - self.es_cmd = self.es - self.read_buf = self.read_buf[4:] # TODO: Document or redo. - self.putx([9, ['CSD: %s' % self.read_buf]]) - # TODO: Decode all bits. - self.read_buf = [] - ### self.state = 'GET RESPONSE R1' - self.state = 'IDLE' - - def handle_cmd10(self): - # CMD10: SEND_CID (128 bits / 16 bytes) - self.putc(10, 'Ask card to send its card identification (CID)') - self.read_buf.append(self.miso) - if len(self.read_buf) < 16: - return - self.putx([10, ['CID: %s' % self.read_buf]]) - # TODO: Decode all bits. - self.read_buf = [] - self.state = 'GET RESPONSE R1' - - def handle_cmd16(self): - # CMD16: SET_BLOCKLEN - self.blocklen = self.arg - # TODO: Sanity check on block length. - self.putc(16, 'Set the block length to %d bytes' % self.blocklen) - self.state = 'GET RESPONSE R1' - - def handle_cmd17(self): - # CMD17: READ_SINGLE_BLOCK - self.putc(17, 'Read a block from address 0x%04x' % self.arg) - if len(self.read_buf) == 0: - self.ss_cmd = self.ss - self.read_buf.append(self.miso) - if len(self.read_buf) < self.blocklen + 2: # FIXME - return - self.es_cmd = self.es - self.read_buf = self.read_buf[2:] # FIXME - self.putx([17, ['Block data: %s' % self.read_buf]]) - self.read_buf = [] - self.state = 'GET RESPONSE R1' - - def handle_cmd24(self): - # CMD24: WRITE_BLOCK - self.putc(24, 'Write a block to address 0x%04x' % self.arg) - self.is_cmd24 = True - self.state = 'GET RESPONSE R1' - - def handle_cmd49(self): - self.state = 'GET RESPONSE R1' - - def handle_cmd55(self): - # CMD55: APP_CMD - self.putc(55, 'Next command is an application-specific command') - self.is_acmd = True - self.state = 'GET RESPONSE R1' - - def handle_cmd59(self): - # CMD59: CRC_ON_OFF - crc_on_off = self.arg & (1 << 0) - s = 'on' if crc_on_off == 1 else 'off' - self.putc(59, 'Turn the SD card CRC option %s' % s) - self.state = 'GET RESPONSE R1' - - def handle_acmd41(self): - # ACMD41: SD_SEND_OP_COND - self.putc(64 + 41, 'Send HCS info and activate the card init process') - self.state = 'GET RESPONSE R1' - - def handle_cmd999(self): - self.state = 'GET RESPONSE R1' - - def handle_cid_register(self): - # Card Identification (CID) register, 128bits - - cid = self.cid - - # Manufacturer ID: CID[127:120] (8 bits) - mid = cid[15] - - # OEM/Application ID: CID[119:104] (16 bits) - oid = (cid[14] << 8) | cid[13] - - # Product name: CID[103:64] (40 bits) - pnm = 0 - for i in range(12, 8 - 1, -1): - pnm <<= 8 - pnm |= cid[i] - - # Product revision: CID[63:56] (8 bits) - prv = cid[7] - - # Product serial number: CID[55:24] (32 bits) - psn = 0 - for i in range(6, 3 - 1, -1): - psn <<= 8 - psn |= cid[i] - - # RESERVED: CID[23:20] (4 bits) - - # Manufacturing date: CID[19:8] (12 bits) - # TODO - - # CRC7 checksum: CID[7:1] (7 bits) - # TODO - - # Not used, always 1: CID[0:0] (1 bit) - # TODO - - def handle_response_r1(self, res): - # The R1 response token format (1 byte). - # Sent by the card after every command except for SEND_STATUS. - - self.ss_cmd, self.es_cmd = self.miso_bits[7][1], self.miso_bits[0][2] - self.putx([65, ['R1: 0x%02x' % res]]) - - def putbit(bit, data): - b = self.miso_bits[bit] - self.ss_bit, self.es_bit = b[1], b[2] - self.putb([134, data]) - - # Bit 0: 'In idle state' bit - s = '' if (res & (1 << 0)) else 'not ' - putbit(0, ['Card is %sin idle state' % s]) - - # Bit 1: 'Erase reset' bit - s = '' if (res & (1 << 1)) else 'not ' - putbit(1, ['Erase sequence %scleared' % s]) - - # Bit 2: 'Illegal command' bit - s = 'I' if (res & (1 << 2)) else 'No i' - putbit(2, ['%sllegal command detected' % s]) - - # Bit 3: 'Communication CRC error' bit - s = 'failed' if (res & (1 << 3)) else 'was successful' - putbit(3, ['CRC check of last command %s' % s]) - - # Bit 4: 'Erase sequence error' bit - s = 'E' if (res & (1 << 4)) else 'No e' - putbit(4, ['%srror in the sequence of erase commands' % s]) - - # Bit 5: 'Address error' bit - s = 'M' if (res & (1 << 4)) else 'No m' - putbit(5, ['%sisaligned address used in command' % s]) - - # Bit 6: 'Parameter error' bit - s = '' if (res & (1 << 4)) else 'not ' - putbit(6, ['Command argument %soutside allowed range' % s]) - - # Bit 7: Always set to 0 - putbit(7, ['Bit 7 (always 0)']) - - if self.is_cmd24: - self.state = 'HANDLE DATA BLOCK CMD24' - - def handle_response_r1b(self, res): - # TODO - pass - - def handle_response_r2(self, res): - # TODO - pass - - def handle_response_r3(self, res): - # TODO - pass - - # Note: Response token formats R4 and R5 are reserved for SDIO. - - # TODO: R6? - - def handle_response_r7(self, res): - # TODO - pass - - def handle_data_cmd24(self, mosi): - if self.cmd24_start_token_found: - if len(self.read_buf) == 0: - self.ss_data = self.ss - if not self.blocklen: - # Assume a fixed block size when inspection of the - # previous traffic did not provide the respective - # parameter value. - # TODO Make the default block size a user adjustable option? - self.blocklen = 512 - self.read_buf.append(mosi) - # Wait until block transfer completed. - if len(self.read_buf) < self.blocklen: - return - self.es_data = self.es - self.put(self.ss_data, self.es_data, self.out_ann, [24, ['Block data: %s' % self.read_buf]]) - self.read_buf = [] - self.state = 'DATA RESPONSE' - elif mosi == 0xfe: - self.put(self.ss, self.es, self.out_ann, [24, ['Start Block']]) - self.cmd24_start_token_found = True - - def handle_data_response(self, miso): - # Data Response token (1 byte). - # - # Format: - # - Bits[7:5]: Don't care. - # - Bits[4:4]: Always 0. - # - Bits[3:1]: Status. - # - 010: Data accepted. - # - 101: Data rejected due to a CRC error. - # - 110: Data rejected due to a write error. - # - Bits[0:0]: Always 1. - miso &= 0x1f - if miso & 0x11 != 0x01: - # This is not the byte we are waiting for. - # Should we return to IDLE here? - return - m = self.miso_bits - self.put(m[7][1], m[5][2], self.out_ann, [134, ['Don\'t care']]) - self.put(m[4][1], m[4][2], self.out_ann, [134, ['Always 0']]) - if miso == 0x05: - self.put(m[3][1], m[1][2], self.out_ann, [134, ['Data accepted']]) - elif miso == 0x0b: - self.put(m[3][1], m[1][2], self.out_ann, [134, ['Data rejected (CRC error)']]) - elif miso == 0x0d: - self.put(m[3][1], m[1][2], self.out_ann, [134, ['Data rejected (write error)']]) - self.put(m[0][1], m[0][2], self.out_ann, [134, ['Always 1']]) - ann_class = None - if self.is_cmd24: - ann_class = 24 - if ann_class is not None: - self.put(self.ss, self.es, self.out_ann, [ann_class, ['Data Response']]) - self.state = 'IDLE' - - def decode(self, ss, es, data): - ptype, mosi, miso = data - - # For now, only use DATA and BITS packets. - if ptype not in ('DATA', 'BITS'): - return - - # Store the individual bit values and ss/es numbers. The next packet - # is guaranteed to be a 'DATA' packet belonging to this 'BITS' one. - if ptype == 'BITS': - self.miso_bits, self.mosi_bits = miso, mosi - return - - self.ss, self.es = ss, es - - # State machine. - if self.state == 'IDLE': - # Ignore stray 0xff bytes, some devices seem to send those!? - if mosi == 0xff: # TODO? - return - self.state = 'GET COMMAND TOKEN' - self.handle_command_token(mosi, miso) - elif self.state == 'GET COMMAND TOKEN': - self.handle_command_token(mosi, miso) - elif self.state.startswith('HANDLE CMD'): - self.miso, self.mosi = miso, mosi - # Call the respective handler method for the command. - a, cmdstr = 'a' if self.is_acmd else '', self.state[10:].lower() - handle_cmd = getattr(self, 'handle_%scmd%s' % (a, cmdstr)) - handle_cmd() - self.cmd_token = [] - self.cmd_token_bits = [] - # Leave ACMD mode again after the first command after CMD55. - if self.is_acmd and cmdstr != '55': - self.is_acmd = False - elif self.state.startswith('GET RESPONSE'): - # Ignore stray 0xff bytes, some devices seem to send those!? - if miso == 0xff: # TODO? - return - # Call the respective handler method for the response. - # Assume return to IDLE state, but allow response handlers - # to advance to some other state when applicable. - s = 'handle_response_%s' % self.state[13:].lower() - handle_response = getattr(self, s) - self.state = 'IDLE' - handle_response(miso) - elif self.state == 'HANDLE DATA BLOCK CMD24': - self.handle_data_cmd24(mosi) - elif self.state == 'DATA RESPONSE': - self.handle_data_response(miso) diff --git a/decoders/sdq/__init__.py b/decoders/sdq/__init__.py deleted file mode 100644 index 3fc10438..00000000 --- a/decoders/sdq/__init__.py +++ /dev/null @@ -1,28 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019-2020 Philip Åkesson -## -## 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, see . -## - -''' -The SDQ protocol was developed by Texas Instruments, and is used in -devices like battery pack authentication. Apple uses SDQ in MagSafe -and Lightning connectors, as well as some batteries. - -See https://www.ti.com/lit/ds/symlink/bq26100.pdf for details. -''' - -from .pd import Decoder diff --git a/decoders/sdq/pd.py b/decoders/sdq/pd.py deleted file mode 100644 index 66df4202..00000000 --- a/decoders/sdq/pd.py +++ /dev/null @@ -1,131 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019-2020 Philip Åkesson -## -## 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, see . -## - -from common.srdhelper import bitpack -import sigrokdecode as srd - -class SamplerateError(Exception): - pass - -class Pin: - SDQ, = range(1) - -class Ann: - BIT, BYTE, BREAK, = range(3) - -class Decoder(srd.Decoder): - api_version = 3 - id = 'sdq' - name = 'SDQ' - longname = 'Texas Instruments SDQ' - desc = 'Texas Instruments SDQ. The SDQ protocol is also used by Apple.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Embedded/industrial'] - channels = ( - {'id': 'sdq', 'name': 'SDQ', 'desc': 'Single wire SDQ data line.'}, - ) - options = ( - {'id': 'bitrate', 'desc': 'Bit rate', 'default': 98425}, - ) - annotations = ( - ('bit', 'Bit'), - ('byte', 'Byte'), - ('break', 'Break'), - ) - annotation_rows = ( - ('bits', 'Bits', (Ann.BIT,)), - ('bytes', 'Bytes', (Ann.BYTE,)), - ('breaks', 'Breaks', (Ann.BREAK,)), - ) - - def puts(self, data): - self.put(self.startsample, self.samplenum, self.out_ann, data) - - def putetu(self, data): - self.put(self.startsample, self.startsample + int(self.bit_width), self.out_ann, data) - - def putbetu(self, data): - self.put(self.bytepos, self.startsample + int(self.bit_width), self.out_ann, data) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.startsample = 0 - self.bits = [] - self.bytepos = 0 - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def handle_bit(self, bit): - self.bits.append(bit) - self.putetu([Ann.BIT, [ - 'Bit: {:d}'.format(bit), - '{:d}'.format(bit), - ]]) - - if len(self.bits) == 8: - byte = bitpack(self.bits) - self.putbetu([Ann.BYTE, [ - 'Byte: 0x{:02x}'.format(byte), - '0x{:02x}'.format(byte), - ]]) - self.bits = [] - self.bytepos = 0 - - def handle_break(self): - self.puts([Ann.BREAK, ['Break', 'BR']]) - self.bits = [] - self.startsample = self.samplenum - self.bytepos = 0 - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - self.bit_width = float(self.samplerate) / float(self.options['bitrate']) - self.half_bit_width = self.bit_width / 2.0 - # BREAK if the line is low for longer than this. - break_threshold = self.bit_width * 1.2 - - # Wait until the line is high before inspecting input data. - sdq, = self.wait({Pin.SDQ: 'h'}) - while True: - # Get the length of a low pulse (falling to rising edge). - sdq, = self.wait({Pin.SDQ: 'f'}) - self.startsample = self.samplenum - if self.bytepos == 0: - self.bytepos = self.samplenum - sdq, = self.wait({Pin.SDQ: 'r'}) - - # Check for 0 or 1 data bits, or the BREAK symbol. - delta = self.samplenum - self.startsample - if delta > break_threshold: - self.handle_break() - elif delta > self.half_bit_width: - self.handle_bit(0) - else: - self.handle_bit(1) diff --git a/decoders/seven_segment/__init__.py b/decoders/seven_segment/__init__.py deleted file mode 100644 index ea03e4f2..00000000 --- a/decoders/seven_segment/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Benedikt Otto -## -## 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, see . -## - -''' -This decoder decodes the output of a 7-segment display. -''' - -from .pd import Decoder diff --git a/decoders/seven_segment/pd.py b/decoders/seven_segment/pd.py deleted file mode 100644 index edabf04a..00000000 --- a/decoders/seven_segment/pd.py +++ /dev/null @@ -1,136 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Benedikt Otto -## -## 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, see . -## - -import sigrokdecode as srd - -class ChannelError(Exception): - pass - -digits = { - (0, 0, 0, 0, 0, 0, 0): ' ', - (1, 1, 1, 1, 1, 1, 0): '0', - (0, 1, 1, 0, 0, 0, 0): '1', - (1, 1, 0, 1, 1, 0, 1): '2', - (1, 1, 1, 1, 0, 0, 1): '3', - (0, 1, 1, 0, 0, 1, 1): '4', - (1, 0, 1, 1, 0, 1, 1): '5', - (1, 0, 1, 1, 1, 1, 1): '6', - (1, 1, 1, 0, 0, 0, 0): '7', - (1, 1, 1, 1, 1, 1, 1): '8', - (1, 1, 1, 1, 0, 1, 1): '9', - (1, 1, 1, 0, 1, 1, 1): 'A', - (0, 0, 1, 1, 1, 1, 1): 'B', - (1, 0, 0, 1, 1, 1, 0): 'C', - (0, 1, 1, 1, 1, 0, 1): 'D', - (1, 0, 0, 1, 1, 1, 1): 'E', - (1, 0, 0, 0, 1, 1, 1): 'F', -} - -class Decoder(srd.Decoder): - api_version = 3 - id = 'seven_segment' - name = 'Segment-7' - longname = '7-segment display' - desc = '7-segment display protocol.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Display'] - channels = ( - {'id': 'a', 'name': 'A', 'desc': 'Segment A'}, - {'id': 'b', 'name': 'B', 'desc': 'Segment B'}, - {'id': 'c', 'name': 'C', 'desc': 'Segment C'}, - {'id': 'd', 'name': 'D', 'desc': 'Segment D'}, - {'id': 'e', 'name': 'E', 'desc': 'Segment E'}, - {'id': 'f', 'name': 'F', 'desc': 'Segment F'}, - {'id': 'g', 'name': 'G', 'desc': 'Segment G'}, - ) - optional_channels = ( - {'id': 'dp', 'name': 'DP', 'desc': 'Decimal point'}, - ) - options = ( - {'id': 'polarity', 'desc': 'Expected polarity', - 'default': 'common-cathode', 'values': ('common-cathode', 'common-anode')}, - ) - annotations = ( - ('decoded-digit', 'Decoded digit'), - ) - annotation_rows = ( - ('decoded-digits', 'Decoded digits', (0,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - pass - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putb(self, ss_block, es_block, data): - self.put(ss_block, es_block, self.out_ann, data) - - def pins_to_hex(self, pins): - return digits.get(pins, None) - - def decode(self): - (s0, s1, s2, s3, s4, s5, s6, dp) = self.wait() - oldpins = (s0, s1, s2, s3, s4, s5, s6, dp) - - # Check if at least the 7 signals are present. - if False in [p in (0, 1) for p in oldpins[:7]]: - raise ChannelError('7 or 8 pins have to be present.') - - lastpos = self.samplenum - - self.have_dp = self.has_channel(7) - - conditions = [{0: 'e'}, {1: 'e'}, {2: 'e'}, {3: 'e'}, {4: 'e'}, {5: 'e'}, {6: 'e'}] - - if self.have_dp: - conditions.append({7: 'e'}) - - while True: - # Wait for any change. - (s0, s1, s2, s3, s4, s5, s6, dp) = self.wait(conditions) - pins = (s0, s1, s2, s3, s4, s5, s6, dp) - - if self.options['polarity'] == 'common-anode': - # Invert all data lines if a common anode display is used. - if self.have_dp: - oldpins = tuple((1 - state for state in oldpins)) - else: - oldpins = tuple((1 - state for state in oldpins[:7])) - - # Convert to character string. - digit = self.pins_to_hex(oldpins[:7]) - - if digit is not None: - dp = oldpins[7] - - # Check if decimal point is present and active. - if self.have_dp and dp == 1: - digit += '.' - - self.putb(lastpos, self.samplenum, [0, [digit]]) - - lastpos = self.samplenum - - oldpins = pins diff --git a/decoders/signature/__init__.py b/decoders/signature/__init__.py deleted file mode 100644 index d37fd4a3..00000000 --- a/decoders/signature/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Shirow Miura -## -## 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, see . -## - -''' -Signature analysis function for troubleshooting logic circuits. -This generates the same signature as Hewlett-Packard 5004A. -''' - -from .pd import Decoder diff --git a/decoders/signature/pd.py b/decoders/signature/pd.py deleted file mode 100644 index 946b2da7..00000000 --- a/decoders/signature/pd.py +++ /dev/null @@ -1,142 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Shirow Miura -## -## 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, see . -## - -import sigrokdecode as srd - -symbol_map = { - 0b0000: '0', - 0b1000: '1', - 0b0100: '2', - 0b1100: '3', - 0b0010: '4', - 0b1010: '5', - 0b0110: '6', - 0b1110: '7', - 0b0001: '8', - 0b1001: '9', - 0b0101: 'A', - 0b1101: 'C', - 0b0011: 'F', - 0b1011: 'H', - 0b0111: 'P', - 0b1111: 'U', -} - -START, STOP, CLOCK, DATA = range(4) - -class Decoder(srd.Decoder): - api_version = 3 - id = 'signature' - name = 'Signature' - longname = 'Signature analysis' - desc = 'Annotate signature of logic patterns.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Debug/trace', 'Util', 'Encoding'] - channels = ( - {'id': 'start', 'name': 'START', 'desc': 'START channel'}, - {'id': 'stop', 'name': 'STOP', 'desc': 'STOP channel'}, - {'id': 'clk', 'name': 'CLOCK', 'desc': 'CLOCK channel'}, - {'id': 'data', 'name': 'DATA', 'desc': 'DATA channel'}, - ) - options = ( - {'id': 'start_edge', 'desc': 'START edge polarity', - 'default': 'rising', 'values': ('rising', 'falling')}, - {'id': 'stop_edge', 'desc': 'STOP edge polarity', - 'default': 'rising', 'values': ('rising', 'falling')}, - {'id': 'clk_edge', 'desc': 'CLOCK edge polarity', - 'default': 'falling', 'values': ('rising', 'falling')}, - {'id': 'annbits', 'desc': 'Enable bit level annotations', - 'default': 'no', 'values': ('yes', 'no')}, - ) - annotations = ( - ('bit0', 'Bit0'), - ('bit1', 'Bit1'), - ('start', 'START'), - ('stop', 'STOP'), - ('signature', 'Signature') - ) - annotation_rows = ( - ('bits', 'Bits', (0, 1, 2, 3)), - ('signatures', 'Signatures', (4,)) - ) - - def __init__(self): - self.reset() - - def reset(self): - pass - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putsig(self, ss, es, signature): - s = ''.join([symbol_map[(signature >> 0) & 0x0f], - symbol_map[(signature >> 4) & 0x0f], - symbol_map[(signature >> 8) & 0x0f], - symbol_map[(signature >> 12) & 0x0f]]) - self.put(ss, es, self.out_ann, [4, [s]]) - - def putb(self, ss, ann): - self.put(ss, self.samplenum, self.out_ann, ann) - - def decode(self): - opt = self.options - start_edge_mode_rising = opt['start_edge'] == 'rising' - stop_edge_mode_rising = opt['stop_edge'] == 'rising' - annbits = opt['annbits'] == 'yes' - gate_is_open = False - sample_start = None - started = False - last_samplenum = 0 - prev_start = 0 if start_edge_mode_rising else 1 - prev_stop = 0 if stop_edge_mode_rising else 1 - shiftreg = 0 - - while True: - start, stop, _, data = self.wait({CLOCK: opt['clk_edge']}) - if start != prev_start and not gate_is_open: - gate_is_open = (start == 1) if start_edge_mode_rising else (start == 0) - if gate_is_open: - # Start sampling. - sample_start = self.samplenum - started = True - elif stop != prev_stop and gate_is_open: - gate_is_open = not ((stop == 1) if stop_edge_mode_rising else (stop == 0)) - if not gate_is_open: - # Stop sampling. - if annbits: - self.putb(last_samplenum, [3, ['STOP', 'STP', 'P']]) - self.putsig(sample_start, self.samplenum, shiftreg) - shiftreg = 0 - sample_start = None - if gate_is_open: - if annbits: - if started: - s = '<{}>'.format(data) - self.putb(last_samplenum, [2, ['START' + s, 'STR' + s, 'S' + s]]) - started = False - else: - self.putb(last_samplenum, [data, [str(data)]]) - incoming = (bin(shiftreg & 0x0291).count('1') + data) & 1 - shiftreg = (incoming << 15) | (shiftreg >> 1) - prev_start = start - prev_stop = stop - last_samplenum = self.samplenum diff --git a/decoders/sipi/__init__.py b/decoders/sipi/__init__.py deleted file mode 100644 index d62e3c11..00000000 --- a/decoders/sipi/__init__.py +++ /dev/null @@ -1,30 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 Soeren Apel -## -## 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, see . -## - -''' -The Serial Inter-Processor Interface (SIPI) is a higher-level protocol that runs -over the LFAST physical interface. Together, they form the NXP Zipwire interface. - -The SIPI interface is also provided by Infineon as HSST, using HSCT for transport. - -For details see https://www.nxp.com/docs/en/application-note/AN5134.pdf and -https://hitex.co.uk/fileadmin/uk-files/downloads/ShieldBuddy/tc27xD_um_v2.2.pdf -''' - -from .pd import Decoder diff --git a/decoders/sipi/pd.py b/decoders/sipi/pd.py deleted file mode 100644 index 5bd58fbb..00000000 --- a/decoders/sipi/pd.py +++ /dev/null @@ -1,181 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2020 Soeren Apel -## -## 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, see . -## - -import sigrokdecode as srd -from binascii import crc_hqx - -# See tc27xD_um_v2.2.pdf, Table 20-2 -# (name, addr byte count, data byte count) -command_codes = { - 0b00000: ('Read byte', 4, 0), - 0b00001: ('Read 2 byte', 4, 0), - 0b00010: ('Read 4 byte', 4, 0), - # Reserved - 0b00100: ('Write byte with ACK', 4, 4), - 0b00101: ('Write 2 byte with ACK', 4, 4), - 0b00110: ('Write 4 byte with ACK', 4, 4), - # Reserved - 0b01000: ('ACK', 0, 0), - 0b01001: ('NACK (Target Error)', 0, 0), - 0b01010: ('Read Answer with ACK', 4, 4), - # Reserved - 0b01100: ('Trigger with ACK', 0, 0), - # Reserved - # Reserved - # Reserved - # Reserved - # Reserved - 0b10010: ('Read 4-byte JTAG ID', 0, 0), - # Reserved - # Reserved - # Reserved - # Reserved - 0b10111: ('Stream 32 byte with ACK', 0, 32) - # Rest is reserved -} - - -ann_header_tag, ann_header_cmd, ann_header_ch, ann_address, ann_data, \ - ann_crc, ann_warning = range(7) - -class Decoder(srd.Decoder): - api_version = 3 - id = 'sipi' - name = 'SIPI (Zipwire)' - longname = 'NXP SIPI interface' - desc = 'Serial Inter-Processor Interface (SIPI) aka Zipwire, aka HSSL' - license = 'gplv2+' - inputs = ['lfast'] - outputs = [] - tags = ['Embedded/industrial'] - annotations = ( - ('header_tag', 'Transaction Tag'), - ('header_cmd', 'Command Code'), - ('header_ch', 'Channel'), - ('address', 'Address'), - ('data', 'Data'), - ('crc', 'CRC'), - ('warning', 'Warning'), - ) - annotation_rows = ( - ('fields', 'Fields', (ann_header_tag, ann_header_cmd, - ann_header_ch, ann_address, ann_data, ann_crc,)), - ('warnings', 'Warnings', (ann_warning,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.byte_len = 0 - self.frame_len = 0 - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.out_binary = self.register(srd.OUTPUT_BINARY) - - def put_ann(self, ss, es, ann_class, value): - self.put(int(ss), int(es), self.out_ann, [ann_class, value]) - - def put_header(self, ss_header, es_header, value): - ss = ss_header - es = ss + 3 * self.bit_len - tag = (value & 0xE000) >> 13 - self.put_ann(ss, es, ann_header_tag, ['{:02X}'.format(tag)]) - - ss = es - es = ss + 5 * self.bit_len - cmd_id = (value & 0x1F00) >> 8 - cmd_name, self.addr_len, self.data_len = \ - command_codes.get(cmd_id, ('Reserved ({:02X})'.format(cmd_id), 0, 0)) - self.frame_len = 2 + 2 + self.addr_len + self.data_len # +Header +CRC - self.put_ann(ss, es, ann_header_cmd, [cmd_name]) - - # Bits 4..7 are reserved and should be 0, warn if they're not - ss = es - es = ss + 4 * self.bit_len - reserved_bits = (value & 0x00F0) >> 4 - if reserved_bits > 0: - self.put_ann(ss, es, ann_warning, ['Reserved bits #4..7 should be 0']) - - ss = es - es = ss + 3 * self.bit_len - ch = (value & 0x000E) >> 1 # See tc27xD_um_v2.2.pdf, Table 20-1 - self.put_ann(ss, es, ann_header_ch, [str(ch)]) - - # Bit 0 is reserved and should be 0, warn if it's not - if (value & 0x0001) == 0x0001: - ss = es - es = ss + self.bit_len - self.put_ann(ss, es, ann_warning, ['Reserved bit #0 should be 0']) - - def put_payload(self, data): - byte_idx = 0 - if self.addr_len > 0: - for value_tuple in data[:self.addr_len]: - ss, es, value = value_tuple - self.put_ann(ss, es, ann_address, ['{:02X}'.format(value)]) - byte_idx = self.addr_len - - if self.data_len > 0: - for value_tuple in data[byte_idx:]: - ss, es, value = value_tuple - self.put_ann(ss, es, ann_data, ['{:02X}'.format(value)]) - - def put_crc(self, ss, es, crc_value, crc_payload_data): - crc_payload = [] - for value_tuple in crc_payload_data: - crc_payload.append(value_tuple[2]) - - calculated_crc = crc_hqx(bytes(crc_payload), 0xFFFF) - - if calculated_crc == crc_value: - self.put_ann(ss, es, ann_crc, ['CRC OK']) - else: - self.put_ann(ss, es, ann_crc, ['Have {:02X} but calculated {:02X}'.format(crc_value, calculated_crc)]) - self.put_ann(ss, es, ann_warning, ['CRC mismatch']) - - def decode(self, ss, es, data): - if len(data) == 1: - self.put_ann(ss, es, ann_warning, ['Header too short']) - return - - # ss and es are now unused, we use them as local variables instead - - self.bit_len = (data[0][1] - data[0][0]) / 8.0 - - byte_idx = 0 - - ss = data[byte_idx][0] - es = data[byte_idx + 1][1] - self.put_header(ss, es, (data[byte_idx][2] << 8) + data[byte_idx + 1][2]) - byte_idx += 2 - - payload_len = self.frame_len - 2 - 2 # -Header -CRC - if payload_len > 0: - self.put_payload(data[byte_idx:-2]) - byte_idx += payload_len - - ss = data[byte_idx][0] - es = data[byte_idx + 1][1] - if byte_idx == len(data) - 2: - # CRC is calculated over header + payload bytes - self.put_crc(ss, es, (data[byte_idx][2] << 8) + data[byte_idx + 1][2], data[0:-2]) - else: - self.put_ann(ss, es, ann_warning, ['CRC incomplete or missing']) diff --git a/decoders/sle44xx/__init__.py b/decoders/sle44xx/__init__.py deleted file mode 100644 index 0eb02856..00000000 --- a/decoders/sle44xx/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Federico Cerutti -## -## 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, see . -## - -''' -SLE 4418/28/32/42 memory cards implement a 2-wire protocol (CLK and I/O) -for data communication, along with the RST signal which resets the card's -internal state, and can terminate currently executing long memory reads. -''' - -from .pd import Decoder diff --git a/decoders/sle44xx/pd.py b/decoders/sle44xx/pd.py deleted file mode 100644 index 9f332077..00000000 --- a/decoders/sle44xx/pd.py +++ /dev/null @@ -1,541 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Federico Cerutti -## -## 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, see . -## - -from common.srdhelper import bitpack_lsb -import sigrokdecode as srd - -class Pin: - RST, CLK, IO, = range(3) - -class Ann: - RESET_SYM, INTR_SYM, START_SYM, STOP_SYM, BIT_SYM, \ - ATR_BYTE, CMD_BYTE, OUT_BYTE, PROC_BYTE, \ - ATR_DATA, CMD_DATA, OUT_DATA, PROC_DATA, \ - = range(13) - -class Bin: - BYTES, = range(1) - -class Decoder(srd.Decoder): - api_version = 3 - id = 'sle44xx' - name = 'SLE 44xx' - longname = 'SLE44xx memory card' - desc = 'SLE 4418/28/32/42 memory card serial protocol' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Memory'] - channels = ( - {'id': 'rst', 'name': 'RST', 'desc': 'Reset line'}, - {'id': 'clk', 'name': 'CLK', 'desc': 'Clock line'}, - {'id': 'io', 'name': 'I/O', 'desc': 'I/O data line'}, - ) - annotations = ( - ('reset_sym', 'Reset Symbol'), - ('intr_sym', 'Interrupt Symbol'), - ('start_sym', 'Start Symbol'), - ('stop_sym', 'Stop Symbol'), - ('bit_sym', 'Bit Symbol'), - ('atr_byte', 'ATR Byte'), - ('cmd_byte', 'Command Byte'), - ('out_byte', 'Outgoing Byte'), - ('proc_byte', 'Processing Byte'), - ('atr_data', 'ATR data'), - ('cmd_data', 'Command data'), - ('out_data', 'Outgoing data'), - ('proc_data', 'Processing data'), - ) - annotation_rows = ( - ('symbols', 'Symbols', (Ann.RESET_SYM, Ann.INTR_SYM, - Ann.START_SYM, Ann.STOP_SYM, Ann.BIT_SYM,)), - ('fields', 'Fields', (Ann.ATR_BYTE, - Ann.CMD_BYTE, Ann.OUT_BYTE, Ann.PROC_BYTE,)), - ('operations', 'Operations', (Ann.ATR_DATA, - Ann.CMD_DATA, Ann.OUT_DATA, Ann.PROC_DATA,)), - ) - binary = ( - ('bytes', 'Bytes'), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.max_addr = 256 - self.bits = [] - self.atr_bytes = [] - self.cmd_bytes = [] - self.cmd_proc = None - self.out_len = None - self.out_bytes = [] - self.proc_state = None - self.state = None - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.out_binary = self.register(srd.OUTPUT_BINARY) - - def putx(self, ss, es, cls, data): - self.put(ss, es, self.out_ann, [cls, data,]) - - def putb(self, ss, es, cls , data): - self.put(ss, es, self.out_binary, [cls, data,]) - - def snums_to_usecs(self, snum_count): - if not self.samplerate: - return None - snums_per_usec = self.samplerate / 1e6 - usecs = snum_count / snums_per_usec - return usecs - - def lookup_proto_ann_txt(self, key, variables): - ann = { - 'RESET_SYM': [Ann.RESET_SYM, 'Reset', 'R',], - 'INTR_SYM': [Ann.INTR_SYM, 'Interrupt', 'Intr', 'I',], - 'START_SYM': [Ann.START_SYM, 'Start', 'ST', 'S',], - 'STOP_SYM': [Ann.STOP_SYM, 'Stop', 'SP', 'P',], - 'BIT_SYM': [Ann.BIT_SYM, '{bit}',], - 'ATR_BYTE': [Ann.ATR_BYTE, - 'Answer To Reset: {data:02x}', - 'ATR: {data:02x}', - '{data:02x}', - ], - 'CMD_BYTE': [Ann.CMD_BYTE, - 'Command: {data:02x}', - 'Cmd: {data:02x}', - '{data:02x}', - ], - 'OUT_BYTE': [Ann.OUT_BYTE, - 'Outgoing data: {data:02x}', - 'Data: {data:02x}', - '{data:02x}', - ], - 'PROC_BYTE': [Ann.PROC_BYTE, - 'Internal processing: {data:02x}', - 'Proc: {data:02x}', - '{data:02x}', - ], - 'ATR_DATA': [Ann.ATR_DATA, - 'Answer To Reset: {data}', - 'ATR: {data}', - '{data}', - ], - 'CMD_DATA': [Ann.CMD_DATA, - 'Command: {data}', - 'Cmd: {data}', - '{data}', - ], - 'OUT_DATA': [Ann.OUT_DATA, - 'Outgoing: {data}', - 'Out: {data}', - '{data}', - ], - 'PROC_DATA': [Ann.PROC_DATA, - 'Processing: {data}', - 'Proc: {data}', - '{data}', - ], - }.get(key, None) - if ann is None: - return None, [] - cls, texts = ann[0], ann[1:] - texts = [t.format(**variables) for t in texts] - return cls, texts - - def text_for_accu_bytes(self, accu): - if not accu: - return None, None, None, None - ss, es = accu[0][1], accu[-1][2] - data = [a[0] for a in accu] - text = " ".join(['{:02x}'.format(a) for a in data]) - return ss, es, data, text - - def flush_queued(self): - '''Flush previously accumulated operations details.''' - - # Can be called when either the completion of an operation got - # detected (reliably), or when some kind of reset condition was - # met while a potential previously observed operation has not - # been postprocessed yet (best effort). Should not harm when the - # routine gets invoked while no data was collected yet, or was - # flushed already. - # BEWARE! Will void internal state. Should really only get called - # "between operations", NOT between fields of an operation. - - if self.atr_bytes: - key = 'ATR_DATA' - ss, es, _, text = self.text_for_accu_bytes(self.atr_bytes) - cls, texts = self.lookup_proto_ann_txt(key, {'data': text}) - self.putx(ss, es, cls, texts) - - if self.cmd_bytes: - key = 'CMD_DATA' - ss, es, _, text = self.text_for_accu_bytes(self.cmd_bytes) - cls, texts = self.lookup_proto_ann_txt(key, {'data': text}) - self.putx(ss, es, cls, texts) - - if self.out_bytes: - key = 'OUT_DATA' - ss, es, _, text = self.text_for_accu_bytes(self.out_bytes) - cls, texts = self.lookup_proto_ann_txt(key, {'data': text}) - self.putx(ss, es, cls, texts) - - if self.proc_state: - key = 'PROC_DATA' - ss = self.proc_state['ss'] - es = self.proc_state['es'] - clk = self.proc_state['clk'] - high = self.proc_state['io1'] - text = '{clk} clocks, I/O {high}'.format(clk = clk, high = int(high)) - usecs = self.snums_to_usecs(es - ss) - if usecs: - msecs = usecs / 1000 - text = '{msecs:.2f} ms, {text}'.format(msecs = msecs, text = text) - cls, texts = self.lookup_proto_ann_txt(key, {'data': text}) - self.putx(ss, es, cls, texts) - - self.atr_bytes = None - self.cmd_bytes = None - self.cmd_proc = None - self.out_len = None - self.out_bytes = None - self.proc_state = None - self.state = None - - def handle_reset(self, ss, es, has_clk): - self.flush_queued() - key = '{}_SYM'.format('RESET' if has_clk else 'INTR') - cls, texts = self.lookup_proto_ann_txt(key, {}) - self.putx(ss, es, cls, texts) - self.bits = [] - self.state = 'ATR' if has_clk else None - - def handle_command(self, ss, is_start): - if is_start: - self.flush_queued() - key = '{}_SYM'.format('START' if is_start else 'STOP') - cls, texts = self.lookup_proto_ann_txt(key, {}) - self.putx(ss, ss, cls, texts) - self.bits = [] - self.state = 'CMD' if is_start else 'DATA' - - def command_check(self, ctrl, addr, data): - '''Interpret CTRL/ADDR/DATA command entry.''' - - # See the Siemens Datasheet section 2.3 Commands. The abbreviated - # text variants are my guesses, terse for readability at coarser - # zoom levels. - codes_table = { - 0x30: { - 'fmt': [ - 'read main memory, addr {addr:02x}', - 'RD-M @{addr:02x}', - ], - 'len': lambda ctrl, addr, data: self.max_addr - addr, - }, - 0x31: { - 'fmt': [ - 'read security memory', - 'RD-S', - ], - 'len': 4, - }, - 0x33: { - 'fmt': [ - 'compare verification data, addr {addr:02x}, data {data:02x}', - 'CMP-V @{addr:02x} ={data:02x}', - ], - 'proc': True, - }, - 0x34: { - 'fmt': [ - 'read protection memory, addr {addr:02x}', - 'RD-P @{addr:02x}', - ], - 'len': 4, - }, - 0x38: { - 'fmt': [ - 'update main memory, addr {addr:02x}, data {data:02x}', - 'WR-M @{addr:02x} ={data:02x}', - ], - 'proc': True, - }, - 0x39: { - 'fmt': [ - 'update security memory, addr {addr:02x}, data {data:02x}', - 'WR-S @{addr:02x} ={data:02x}', - ], - 'proc': True, - }, - 0x3c: { - 'fmt': [ - 'write protection memory, addr {addr:02x}, data {data:02x}', - 'WR-P @{addr:02x} ={data:02x}', - ], - 'proc': True, - }, - } - code = codes_table.get(ctrl, {}) - dflt_fmt = [ - 'unknown, ctrl {ctrl:02x}, addr {addr:02x}, data {data:02x}', - 'UNK-{ctrl:02x} @{addr:02x}, ={data:02x}', - ] - fmt = code.get('fmt', dflt_fmt) - if not isinstance(fmt, (list, tuple,)): - fmt = [fmt,] - texts = [f.format(ctrl = ctrl, addr = addr, data = data) for f in fmt] - length = code.get('len', None) - if callable(length): - length = length(ctrl, addr, data) - is_proc = code.get('proc', False) - return texts, length, is_proc - - def processing_start(self, ss, es, io_high): - self.proc_state = { - 'ss': ss or es, - 'es': es or ss, - 'clk': 0, - 'io1': bool(io_high), - } - - def processing_update(self, es, clk_inc, io_high): - if es is not None and es > self.proc_state['es']: - self.proc_state['es'] = es - self.proc_state['clk'] += clk_inc - if io_high: - self.proc_state['io1'] = True - - def handle_data_byte(self, ss, es, data, bits): - '''Accumulate CMD or OUT data bytes.''' - - if self.state == 'ATR': - if not self.atr_bytes: - self.atr_bytes = [] - self.atr_bytes.append([data, ss, es, bits,]) - if len(self.atr_bytes) == 4: - self.flush_queued() - return - - if self.state == 'CMD': - if not self.cmd_bytes: - self.cmd_bytes = [] - self.cmd_bytes.append([data, ss, es, bits,]) - if len(self.cmd_bytes) == 3: - ctrl, addr, data = [c[0] for c in self.cmd_bytes] - texts, length, proc = self.command_check(ctrl, addr, data) - # Immediately emit the annotation to not lose the text, - # and to support zoom levels for this specific case. - ss, es = self.cmd_bytes[0][1], self.cmd_bytes[-1][2] - cls = Ann.CMD_DATA - self.putx(ss, es, cls, texts) - self.cmd_bytes = [] - # Prepare to continue either at OUT or PROC after CMD. - self.out_len = length - self.cmd_proc = bool(proc) - self.state = None - return - - if self.state == 'OUT': - if not self.out_bytes: - self.out_bytes = [] - self.out_bytes.append([data, ss, es, bits,]) - if self.out_len is not None and len(self.out_bytes) == self.out_len: - self.flush_queued() - return - - def handle_data_bit(self, ss, es, bit): - '''Gather 8 bits of data (or track processing progress).''' - - # Switch late from DATA to either OUT or PROC. We can tell the - # type and potentially fixed length at the end of CMD already, - # but a START/STOP condition may void this information. So we - # do the switch at the first data bit after CMD. - # In the OUT case data bytes get accumulated, until either the - # expected byte count is reached, or another CMD starts. In the - # PROC case a high I/O level terminates execution. - if self.state == 'DATA': - if self.out_len: - self.state = 'OUT' - elif self.cmd_proc: - self.state = 'PROC' - self.processing_start(ss or es, es or ss, bit == 1) - else: - # Implementor's note: Handle unknown situations like - # outgoing data bytes, for the user's convenience. This - # will show OUT bytes even if it's just processing CLK - # cycles with constant or irrelevant I/O bit patterns. - self.state = 'OUT' - if self.state == 'PROC': - high = bit == 1 - if ss is not None: - self.processing_update(ss, 0, high) - if es is not None: - self.processing_update(es, 1, high) - if high: - self.flush_queued() - return - - # This routine gets called two times per bit value. Track the - # bit's value and ss timestamp when the bit period starts. And - # update the es timestamp at the end of the bit's validity. - if ss is not None: - self.bits.append([bit, ss, es or ss]) - return - if es is None: - # Unexpected invocation. Could be a glitch or invalid input - # data, or an interaction with RESET/START/STOP conditions. - self.bits = [] - return - if not self.bits: - return - if bit is not None: - self.bits[-1][0] = bit - # TODO Check for consistent bit level at ss and es when - # the information was available? Is bit data sampled at - # different clock edges depending whether data is sent - # or received? - self.bits[-1][2] = es - # Emit the bit's annotation. See if a byte was received. - bit, ss, es = self.bits[-1] - cls, texts = self.lookup_proto_ann_txt('BIT_SYM', {'bit': bit}) - self.putx(ss, es, cls, texts) - if len(self.bits) < 8: - return - - # Get the data byte value, and the byte's ss/es. Emit the byte's - # annotation and binary output. Pass the byte to upper layers. - # TODO Vary annotation classes with the byte's position within - # a field? To tell CTRL/ADDR/DATA of a CMD entry apart? - bits = self.bits - self.bits = [] - data = bitpack_lsb(bits, 0) - ss = bits[0][1] - es = bits[-1][2] - - key = '{}_BYTE'.format(self.state) - cls, texts = self.lookup_proto_ann_txt(key, {'data': data}) - if cls: - self.putx(ss, es, cls, texts) - self.putb(ss, es, Bin.BYTES, bytes([data])) - - self.handle_data_byte(ss, es, data, bits) - - def decode(self): - '''Decoder's main data interpretation loop.''' - - # Signal conditions tracked by the protocol decoder: - # - Rising and falling RST edges, which span the width of a - # high-active RESET pulse. RST has highest priority, no - # other activity can take place in this period. - # - Rising and falling CLK edges when RST is active. The - # CLK pulse when RST is asserted will reset the card's - # address counter. RST alone can terminate memory reads. - # - Rising and falling CLK edges when RST is inactive. This - # determines the period where BIT values are valid. - # - I/O edges during high CLK. These are START and STOP - # conditions that tell COMMAND and DATA phases apart. - # - Rise of I/O during internal processing. This expression - # is an unconditional part of the .wait() condition set. It - # is assumed that skipping this match in many cases is more - # efficient than the permanent re-construction of the .wait() - # condition list in every loop iteration, and preferrable to - # the maintainance cost of duplicating RST and CLK handling - # when checking I/O during internal processing. - ( - COND_RESET_START, COND_RESET_STOP, - COND_RSTCLK_START, COND_RSTCLK_STOP, - COND_DATA_START, COND_DATA_STOP, - COND_CMD_START, COND_CMD_STOP, - COND_PROC_IOH, - ) = range(9) - conditions = [ - {Pin.RST: 'r'}, - {Pin.RST: 'f'}, - {Pin.RST: 'h', Pin.CLK: 'r'}, - {Pin.RST: 'h', Pin.CLK: 'f'}, - {Pin.RST: 'l', Pin.CLK: 'r'}, - {Pin.RST: 'l', Pin.CLK: 'f'}, - {Pin.CLK: 'h', Pin.IO: 'f'}, - {Pin.CLK: 'h', Pin.IO: 'r'}, - {Pin.RST: 'l', Pin.IO: 'r'}, - ] - - ss_reset = es_reset = ss_clk = es_clk = None - while True: - - is_outgoing = self.state == 'OUT' - is_processing = self.state == 'PROC' - pins = self.wait(conditions) - io = pins[Pin.IO] - - # Handle RESET conditions, including an optional CLK pulse - # while RST is asserted. - if self.matched[COND_RESET_START]: - self.flush_queued() - ss_reset = self.samplenum - es_reset = ss_clk = es_clk = None - continue - if self.matched[COND_RESET_STOP]: - es_reset = self.samplenum - self.handle_reset(ss_reset or 0, es_reset, ss_clk and es_clk) - ss_reset = es_reset = ss_clk = es_clk = None - continue - if self.matched[COND_RSTCLK_START]: - ss_clk = self.samplenum - es_clk = None - continue - if self.matched[COND_RSTCLK_STOP]: - es_clk = self.samplenum - continue - - # Handle data bits' validity boundaries. Also covers the - # periodic check for high I/O level and update of details - # during internal processing. - if self.matched[COND_DATA_START]: - self.handle_data_bit(self.samplenum, None, io) - continue - if self.matched[COND_DATA_STOP]: - self.handle_data_bit(None, self.samplenum, None) - continue - - # Additional check for idle I/O during internal processing, - # independent of CLK edges this time. This assures that the - # decoder ends processing intervals as soon as possible, at - # the most precise timestamp. - if is_processing and self.matched[COND_PROC_IOH]: - self.handle_data_bit(self.samplenum, self.samplenum, io) - continue - - # The START/STOP conditions are only applicable outside of - # "outgoing data" or "internal processing" periods. This is - # what the data sheet specifies. - if not is_outgoing and not is_processing: - if self.matched[COND_CMD_START]: - self.handle_command(self.samplenum, True) - continue - if self.matched[COND_CMD_STOP]: - self.handle_command(self.samplenum, False) - continue diff --git a/decoders/spdif/__init__.py b/decoders/spdif/__init__.py deleted file mode 100755 index 3f5109a7..00000000 --- a/decoders/spdif/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Guenther Wenninger -## -## 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, see . -## - -''' -S/PDIF (Sony/Philips Digital Interface Format) is a serial bus for -transmitting audio data. -''' - -from .pd import Decoder diff --git a/decoders/spdif/pd.py b/decoders/spdif/pd.py deleted file mode 100755 index 532bf825..00000000 --- a/decoders/spdif/pd.py +++ /dev/null @@ -1,246 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Guenther Wenninger -## -## 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, see . -## - -import sigrokdecode as srd - -class SamplerateError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = 'spdif' - name = 'S/PDIF' - longname = 'Sony/Philips Digital Interface Format' - desc = 'Serial bus for connecting digital audio devices.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Audio', 'PC'] - channels = ( - {'id': 'data', 'name': 'Data', 'desc': 'Data line'}, - ) - annotations = ( - ('bitrate', 'Bitrate / baudrate'), - ('preamble', 'Preamble'), - ('bits', 'Bits'), - ('aux', 'Auxillary-audio-databits'), - ('samples', 'Audio Samples'), - ('validity', 'Data Valid'), - ('subcode', 'Subcode data'), - ('chan_stat', 'Channnel Status'), - ('parity', 'Parity Bit'), - ) - annotation_rows = ( - ('info', 'Info', (0, 1, 3, 5, 6, 7, 8)), - ('bits', 'Bits', (2,)), - ('samples', 'Samples', (4,)), - ) - - def putx(self, ss, es, data): - self.put(ss, es, self.out_ann, data) - - def puty(self, data): - self.put(self.ss_edge, self.samplenum, self.out_ann, data) - - def __init__(self): - self.reset() - - def reset(self): - self.state = 'GET FIRST PULSE WIDTH' - self.ss_edge = None - self.first_edge = True - self.samplenum_prev_edge = 0 - self.pulse_width = 0 - - self.clocks = [] - self.range1 = 0 - self.range2 = 0 - - self.preamble_state = 0 - self.preamble = [] - self.seen_preamble = False - self.last_preamble = 0 - - self.first_one = True - self.subframe = [] - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def get_pulse_type(self): - if self.range1 == 0 or self.range2 == 0: - return -1 - if self.pulse_width >= self.range2: - return 2 - elif self.pulse_width >= self.range1: - return 0 - else: - return 1 - - def find_first_pulse_width(self): - if self.pulse_width != 0: - self.clocks.append(self.pulse_width) - self.state = 'GET SECOND PULSE WIDTH' - - def find_second_pulse_width(self): - if self.pulse_width > (self.clocks[0] * 1.3) or \ - self.pulse_width < (self.clocks[0] * 0.7): - self.clocks.append(self.pulse_width) - self.state = 'GET THIRD PULSE WIDTH' - - def find_third_pulse_width(self): - if not ((self.pulse_width > (self.clocks[0] * 1.3) or \ - self.pulse_width < (self.clocks[0] * 0.7)) \ - and (self.pulse_width > (self.clocks[1] * 1.3) or \ - self.pulse_width < (self.clocks[1] * 0.7))): - return - - self.clocks.append(self.pulse_width) - self.clocks.sort() - self.range1 = (self.clocks[0] + self.clocks[1]) / 2 - self.range2 = (self.clocks[1] + self.clocks[2]) / 2 - spdif_bitrate = int(self.samplerate / (self.clocks[2] / 1.5)) - self.ss_edge = 0 - - self.puty([0, ['Signal Bitrate: %d Mbit/s (=> %d kHz)' % \ - (spdif_bitrate, (spdif_bitrate/ (2 * 32)))]]) - - clock_period_nsec = 1000000000 / spdif_bitrate - - self.last_preamble = self.samplenum - - # We are done recovering the clock, now let's decode the data stream. - self.state = 'DECODE STREAM' - - def decode_stream(self): - pulse = self.get_pulse_type() - - if not self.seen_preamble: - # This is probably the start of a preamble, decode it. - if pulse == 2: - self.preamble.append(self.get_pulse_type()) - self.state = 'DECODE PREAMBLE' - self.ss_edge = self.samplenum - self.pulse_width - 1 - return - - # We've seen a preamble. - if pulse == 1 and self.first_one: - self.first_one = False - self.subframe.append([pulse, self.samplenum - \ - self.pulse_width - 1, self.samplenum]) - elif pulse == 1 and not self.first_one: - self.subframe[-1][2] = self.samplenum - self.putx(self.subframe[-1][1], self.samplenum, [2, ['1']]) - self.bitcount += 1 - self.first_one = True - else: - self.subframe.append([pulse, self.samplenum - \ - self.pulse_width - 1, self.samplenum]) - self.putx(self.samplenum - self.pulse_width - 1, - self.samplenum, [2, ['0']]) - self.bitcount += 1 - - if self.bitcount == 28: - aux_audio_data = self.subframe[0:4] - sam, sam_rot = '', '' - for a in aux_audio_data: - sam = sam + str(a[0]) - sam_rot = str(a[0]) + sam_rot - sample = self.subframe[4:24] - for s in sample: - sam = sam + str(s[0]) - sam_rot = str(s[0]) + sam_rot - validity = self.subframe[24:25] - subcode_data = self.subframe[25:26] - channel_status = self.subframe[26:27] - parity = self.subframe[27:28] - - self.putx(aux_audio_data[0][1], aux_audio_data[3][2], \ - [3, ['Aux 0x%x' % int(sam, 2), '0x%x' % int(sam, 2)]]) - self.putx(sample[0][1], sample[19][2], \ - [3, ['Sample 0x%x' % int(sam, 2), '0x%x' % int(sam, 2)]]) - self.putx(aux_audio_data[0][1], sample[19][2], \ - [4, ['Audio 0x%x' % int(sam_rot, 2), '0x%x' % int(sam_rot, 2)]]) - if validity[0][0] == 0: - self.putx(validity[0][1], validity[0][2], [5, ['V']]) - else: - self.putx(validity[0][1], validity[0][2], [5, ['E']]) - self.putx(subcode_data[0][1], subcode_data[0][2], - [6, ['S: %d' % subcode_data[0][0]]]) - self.putx(channel_status[0][1], channel_status[0][2], - [7, ['C: %d' % channel_status[0][0]]]) - self.putx(parity[0][1], parity[0][2], [8, ['P: %d' % parity[0][0]]]) - - self.subframe = [] - self.seen_preamble = False - self.bitcount = 0 - - def decode_preamble(self): - if self.preamble_state == 0: - self.preamble.append(self.get_pulse_type()) - self.preamble_state = 1 - elif self.preamble_state == 1: - self.preamble.append(self.get_pulse_type()) - self.preamble_state = 2 - elif self.preamble_state == 2: - self.preamble.append(self.get_pulse_type()) - self.preamble_state = 0 - self.state = 'DECODE STREAM' - if self.preamble == [2, 0, 1, 0]: - self.puty([1, ['Preamble W', 'W']]) - elif self.preamble == [2, 2, 1, 1]: - self.puty([1, ['Preamble M', 'M']]) - elif self.preamble == [2, 1, 1, 2]: - self.puty([1, ['Preamble B', 'B']]) - else: - self.puty([1, ['Unknown Preamble', 'Unknown Prea.', 'U']]) - self.preamble = [] - self.seen_preamble = True - self.bitcount = 0 - self.first_one = True - - self.last_preamble = self.samplenum - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - - # Throw away first detected edge as it might be mangled data. - self.wait({0: 'e'}) - - while True: - # Wait for any edge (rising or falling). - (data,) = self.wait({0: 'e'}) - self.pulse_width = self.samplenum - self.samplenum_prev_edge - 1 - self.samplenum_prev_edge = self.samplenum - - if self.state == 'GET FIRST PULSE WIDTH': - self.find_first_pulse_width() - elif self.state == 'GET SECOND PULSE WIDTH': - self.find_second_pulse_width() - elif self.state == 'GET THIRD PULSE WIDTH': - self.find_third_pulse_width() - elif self.state == 'DECODE STREAM': - self.decode_stream() - elif self.state == 'DECODE PREAMBLE': - self.decode_preamble() diff --git a/decoders/spiflash/__init__.py b/decoders/spiflash/__init__.py deleted file mode 100755 index 151bd3e2..00000000 --- a/decoders/spiflash/__init__.py +++ /dev/null @@ -1,30 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012-2015 Uwe Hermann -## -## 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, see . -## - -''' -This decoder stacks on top of the 'spi' PD and decodes the xx25 series -SPI (NOR) flash chip protocol. - -It currently supports the MX25L1605D/MX25L3205D/MX25L6405D. - -Details: -http://www.macronix.com/QuickPlace/hq/PageLibrary4825740B00298A3B.nsf/h_Index/3F21BAC2E121E17848257639003A3146/$File/MX25L1605D-3205D-6405D-1.5.pdf -''' - -from .pd import Decoder diff --git a/decoders/spiflash/lists.py b/decoders/spiflash/lists.py deleted file mode 100755 index 5c366bee..00000000 --- a/decoders/spiflash/lists.py +++ /dev/null @@ -1,144 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Uwe Hermann -## -## 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, see . -## - -from collections import OrderedDict - -# OrderedDict which maps command IDs to their names and descriptions. -# Please keep this sorted by command ID. -# Don't forget to update 'Ann' in pd.py if you add/remove items here. -cmds = OrderedDict([ - (0x01, ('WRSR', 'Write status register')), - (0x02, ('PP', 'Page program')), - (0x03, ('READ', 'Read data')), - (0x04, ('WRDI', 'Write disable')), - (0x05, ('RDSR', 'Read status register')), - (0x06, ('WREN', 'Write enable')), - (0x0b, ('FAST/READ', 'Fast read data')), - (0x20, ('SE', 'Sector erase')), - (0x2b, ('RDSCUR', 'Read security register')), - (0x2f, ('WRSCUR', 'Write security register')), - (0x35, ('RDSR2', 'Read status register 2')), - (0x60, ('CE', 'Chip erase')), - (0x70, ('ESRY', 'Enable SO to output RY/BY#')), - (0x80, ('DSRY', 'Disable SO to output RY/BY#')), - (0x82, ('WRITE1', 'Main memory page program through buffer 1 with built-in erase')), - (0x85, ('WRITE2', 'Main memory page program through buffer 2 with built-in erase')), - (0x90, ('REMS', 'Read electronic manufacturer & device ID')), - (0x9f, ('RDID', 'Read identification')), - (0xab, ('RDP/RES', 'Release from deep powerdown / Read electronic ID')), - (0xad, ('CP', 'Continuously program mode')), - (0xb1, ('ENSO', 'Enter secured OTP')), - (0xb9, ('DP', 'Deep power down')), - (0xbb, ('2READ', '2x I/O read')), # a.k.a. "Fast read dual I/O". - (0xc1, ('EXSO', 'Exit secured OTP')), - (0xc7, ('CE2', 'Chip erase')), # Alternative command ID - (0xd7, ('STATUS', 'Status register read')), - (0xd8, ('BE', 'Block erase')), - (0xef, ('REMS2', 'Read ID for 2x I/O mode')), -]) - -device_name = { - 'adesto': { - 0x00: 'AT45Dxxx family, standard series', - }, - 'fidelix': { - 0x15: 'FM25Q32', - }, - 'macronix': { - 0x14: 'MX25L1605D', - 0x15: 'MX25L3205D', - 0x16: 'MX25L6405D', - }, - 'winbond': { - 0x13: 'W25Q80DV', - }, -} - -chips = { - # Adesto - 'adesto_at45db161e': { - 'vendor': 'Adesto', - 'model': 'AT45DB161E', - 'res_id': 0xff, # The chip doesn't emit an ID here. - 'rems_id': 0xffff, # Not supported by the chip. - 'rems2_id': 0xffff, # Not supported by the chip. - 'rdid_id': 0x1f26000100, # RDID and 2 extra "EDI" bytes. - 'page_size': 528, # Configurable, could also be 512 bytes. - 'sector_size': 128 * 1024, - 'block_size': 4 * 1024, - }, - # FIDELIX - 'fidelix_fm25q32': { - 'vendor': 'FIDELIX', - 'model': 'FM25Q32', - 'res_id': 0x15, - 'rems_id': 0xa115, - 'rems2_id': 0xa115, - 'rdid_id': 0xa14016, - 'page_size': 256, - 'sector_size': 4 * 1024, - 'block_size': 64 * 1024, - }, - # Macronix - 'macronix_mx25l1605d': { - 'vendor': 'Macronix', - 'model': 'MX25L1605D', - 'res_id': 0x14, - 'rems_id': 0xc214, - 'rems2_id': 0xc214, - 'rdid_id': 0xc22015, - 'page_size': 256, - 'sector_size': 4 * 1024, - 'block_size': 64 * 1024, - }, - 'macronix_mx25l3205d': { - 'vendor': 'Macronix', - 'model': 'MX25L3205D', - 'res_id': 0x15, - 'rems_id': 0xc215, - 'rems2_id': 0xc215, - 'rdid_id': 0xc22016, - 'page_size': 256, - 'sector_size': 4 * 1024, - 'block_size': 64 * 1024, - }, - 'macronix_mx25l6405d': { - 'vendor': 'Macronix', - 'model': 'MX25L6405D', - 'res_id': 0x16, - 'rems_id': 0xc216, - 'rems2_id': 0xc216, - 'rdid_id': 0xc22017, - 'page_size': 256, - 'sector_size': 4 * 1024, - 'block_size': 64 * 1024, - }, - # Winbond - 'winbond_w25q80dv': { - 'vendor': 'Winbond', - 'model': 'W25Q80DV', - 'res_id': 0x13, - 'rems_id': 0xef13, - 'rems2_id': 0xffff, # Not supported by the chip. - 'rdid_id': 0xef4014, - 'page_size': 256, - 'sector_size': 4 * 1024, - 'block_size': 64 * 1024, # Configurable, could also be 32 * 1024 bytes. - }, -} diff --git a/decoders/spiflash/pd.py b/decoders/spiflash/pd.py deleted file mode 100755 index 5ee22740..00000000 --- a/decoders/spiflash/pd.py +++ /dev/null @@ -1,539 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2011-2016 Uwe Hermann -## -## 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, see . -## - -import sigrokdecode as srd -from .lists import * - -L = len(cmds) - -# Don't forget to keep this in sync with 'cmds' is lists.py. -class Ann: - WRSR, PP, READ, WRDI, RDSR, WREN, FAST_READ, SE, RDSCUR, WRSCUR, \ - RDSR2, CE, ESRY, DSRY, WRITE1, WRITE2, REMS, RDID, RDP_RES, CP, ENSO, DP, \ - READ2X, EXSO, CE2, STATUS, BE, REMS2, \ - BIT, FIELD, WARN = range(L + 3) - -def cmd_annotation_classes(): - return tuple([tuple([cmd[0].lower(), cmd[1]]) for cmd in cmds.values()]) - -def decode_dual_bytes(sio0, sio1): - # Given a byte in SIO0 (MOSI) of even bits and a byte in - # SIO1 (MISO) of odd bits, return a tuple of two bytes. - def combine_byte(even, odd): - result = 0 - for bit in range(4): - if even & (1 << bit): - result |= 1 << (bit*2) - if odd & (1 << bit): - result |= 1 << ((bit*2) + 1) - return result - return (combine_byte(sio0 >> 4, sio1 >> 4), combine_byte(sio0, sio1)) - -def decode_status_reg(data): - # TODO: Additional per-bit(s) self.put() calls with correct start/end. - - # Bits[0:0]: WIP (write in progress) - s = 'W' if (data & (1 << 0)) else 'No w' - ret = '%srite operation in progress.\n' % s - - # Bits[1:1]: WEL (write enable latch) - s = '' if (data & (1 << 1)) else 'not ' - ret += 'Internal write enable latch is %sset.\n' % s - - # Bits[5:2]: Block protect bits - # TODO: More detailed decoding (chip-dependent). - ret += 'Block protection bits (BP3-BP0): 0x%x.\n' % ((data & 0x3c) >> 2) - - # Bits[6:6]: Continuously program mode (CP mode) - s = '' if (data & (1 << 6)) else 'not ' - ret += 'Device is %sin continuously program mode (CP mode).\n' % s - - # Bits[7:7]: SRWD (status register write disable) - s = 'not ' if (data & (1 << 7)) else '' - ret += 'Status register writes are %sallowed.\n' % s - - return ret - -class Decoder(srd.Decoder): - api_version = 3 - id = 'spiflash' - name = 'SPI flash' - longname = 'SPI flash chips' - desc = 'xx25 series SPI (NOR) flash chip protocol.' - license = 'gplv2+' - inputs = ['spi'] - outputs = [] - tags = ['IC', 'Memory'] - annotations = cmd_annotation_classes() + ( - ('bit', 'Bit'), - ('field', 'Field'), - ('warning', 'Warning'), - ) - annotation_rows = ( - ('bits', 'Bits', (L + 0,)), - ('fields', 'Fields', (L + 1,)), - ('commands', 'Commands', tuple(range(len(cmds)))), - ('warnings', 'Warnings', (L + 2,)), - ) - options = ( - {'id': 'chip', 'desc': 'Chip', 'default': tuple(chips.keys())[0], - 'values': tuple(chips.keys())}, - {'id': 'format', 'desc': 'Data format', 'default': 'hex', - 'values': ('hex', 'ascii')}, - ) - - def __init__(self): - self.reset() - - def reset(self): - self.device_id = -1 - self.on_end_transaction = None - self.end_current_transaction() - self.writestate = 0 - - # Build dict mapping command keys to handler functions. Each - # command in 'cmds' (defined in lists.py) has a matching - # handler self.handle_. - def get_handler(cmd): - s = 'handle_%s' % cmds[cmd][0].lower().replace('/', '_') - return getattr(self, s) - self.cmd_handlers = dict((cmd, get_handler(cmd)) for cmd in cmds.keys()) - - def end_current_transaction(self): - if self.on_end_transaction is not None: # Callback for CS# transition. - self.on_end_transaction() - self.on_end_transaction = None - self.state = None - self.cmdstate = 1 - self.addr = 0 - self.data = [] - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.chip = chips[self.options['chip']] - self.vendor = self.options['chip'].split('_')[0] - - def putx(self, data): - # Simplification, most annotations span exactly one SPI byte/packet. - self.put(self.ss, self.es, self.out_ann, data) - - def putf(self, data): - self.put(self.ss_field, self.es_field, self.out_ann, data) - - def putc(self, data): - self.put(self.ss_cmd, self.es_cmd, self.out_ann, data) - - def device(self): - return device_name[self.vendor].get(self.device_id, 'Unknown') - - def vendor_device(self): - return '%s %s' % (self.chip['vendor'], self.device()) - - def cmd_ann_list(self): - x, s = cmds[self.state][0], cmds[self.state][1] - return ['Command: %s (%s)' % (s, x), 'Command: %s' % s, - 'Cmd: %s' % s, 'Cmd: %s' % x, x] - - def cmd_vendor_dev_list(self): - c, d = cmds[self.state], 'Device = %s' % self.vendor_device() - return ['%s (%s): %s' % (c[1], c[0], d), '%s: %s' % (c[1], d), - '%s: %s' % (c[0], d), d, self.vendor_device()] - - def emit_cmd_byte(self): - self.ss_cmd = self.ss - self.putx([Ann.FIELD, self.cmd_ann_list()]) - self.addr = 0 - - def emit_addr_bytes(self, mosi): - self.addr |= (mosi << ((4 - self.cmdstate) * 8)) - b = ((3 - (self.cmdstate - 2)) * 8) - 1 - self.putx([Ann.BIT, - ['Address bits %d..%d: 0x%02x' % (b, b - 7, mosi), - 'Addr bits %d..%d: 0x%02x' % (b, b - 7, mosi), - 'Addr bits %d..%d' % (b, b - 7), 'A%d..A%d' % (b, b - 7)]]) - if self.cmdstate == 2: - self.ss_field = self.ss - if self.cmdstate == 4: - self.es_field = self.es - self.putf([Ann.FIELD, ['Address: 0x%06x' % self.addr, - 'Addr: 0x%06x' % self.addr, '0x%06x' % self.addr]]) - - def handle_wren(self, mosi, miso): - self.putx([Ann.WREN, self.cmd_ann_list()]) - self.writestate = 1 - - def handle_wrdi(self, mosi, miso): - self.putx([Ann.WRDI, self.cmd_ann_list()]) - self.writestate = 0 - - def handle_rdid(self, mosi, miso): - if self.cmdstate == 1: - # Byte 1: Master sends command ID. - self.emit_cmd_byte() - elif self.cmdstate == 2: - # Byte 2: Slave sends the JEDEC manufacturer ID. - self.putx([Ann.FIELD, ['Manufacturer ID: 0x%02x' % miso]]) - elif self.cmdstate == 3: - # Byte 3: Slave sends the memory type. - self.putx([Ann.FIELD, ['Memory type: 0x%02x' % miso]]) - elif self.cmdstate == 4: - # Byte 4: Slave sends the device ID. - self.device_id = miso - self.putx([Ann.FIELD, ['Device ID: 0x%02x' % miso]]) - - if self.cmdstate == 4: - self.es_cmd = self.es - self.putc([Ann.RDID, self.cmd_vendor_dev_list()]) - self.state = None - else: - self.cmdstate += 1 - - def handle_rdsr(self, mosi, miso): - # Read status register: Master asserts CS#, sends RDSR command, - # reads status register byte. If CS# is kept asserted, the status - # register can be read continuously / multiple times in a row. - # When done, the master de-asserts CS# again. - if self.cmdstate == 1: - # Byte 1: Master sends command ID. - self.emit_cmd_byte() - elif self.cmdstate >= 2: - # Bytes 2-x: Slave sends status register as long as master clocks. - self.es_cmd = self.es - self.putx([Ann.BIT, [decode_status_reg(miso)]]) - self.putx([Ann.FIELD, ['Status register']]) - self.putc([Ann.RDSR, self.cmd_ann_list()]) - # Set write latch state. - self.writestate = 1 if (miso & (1 << 1)) else 0 - self.cmdstate += 1 - - def handle_rdsr2(self, mosi, miso): - # Read status register 2: Master asserts CS#, sends RDSR2 command, - # reads status register 2 byte. If CS# is kept asserted, the status - # register 2 can be read continuously / multiple times in a row. - # When done, the master de-asserts CS# again. - if self.cmdstate == 1: - # Byte 1: Master sends command ID. - self.emit_cmd_byte() - elif self.cmdstate >= 2: - # Bytes 2-x: Slave sends status register 2 as long as master clocks. - self.es_cmd = self.es - # TODO: Decode status register 2 correctly. - self.putx([Ann.BIT, [decode_status_reg(miso)]]) - self.putx([Ann.FIELD, ['Status register 2']]) - self.putc([Ann.RDSR2, self.cmd_ann_list()]) - self.cmdstate += 1 - - def handle_wrsr(self, mosi, miso): - # Write status register: Master asserts CS#, sends WRSR command, - # writes 1 or 2 status register byte(s). - # When done, the master de-asserts CS# again. If this doesn't happen - # the WRSR command will not be executed. - if self.cmdstate == 1: - # Byte 1: Master sends command ID. - self.emit_cmd_byte() - elif self.cmdstate == 2: - # Byte 2: Master sends status register 1. - self.putx([Ann.BIT, [decode_status_reg(mosi)]]) - self.putx([Ann.FIELD, ['Status register 1']]) - # Set write latch state. - self.writestate = 1 if (miso & (1 << 1)) else 0 - elif self.cmdstate == 3: - # Byte 3: Master sends status register 2. - # TODO: Decode status register 2 correctly. - self.putx([Ann.BIT, [decode_status_reg(mosi)]]) - self.putx([Ann.FIELD, ['Status register 2']]) - self.es_cmd = self.es - self.putc([Ann.WRSR, self.cmd_ann_list()]) - self.cmdstate += 1 - - def handle_read(self, mosi, miso): - # Read data bytes: Master asserts CS#, sends READ command, sends - # 3-byte address, reads >= 1 data bytes, de-asserts CS#. - if self.cmdstate == 1: - # Byte 1: Master sends command ID. - self.emit_cmd_byte() - elif self.cmdstate in (2, 3, 4): - # Bytes 2/3/4: Master sends read address (24bits, MSB-first). - self.emit_addr_bytes(mosi) - elif self.cmdstate >= 5: - # Bytes 5-x: Master reads data bytes (until CS# de-asserted). - self.es_field = self.es # Will be overwritten for each byte. - if self.cmdstate == 5: - self.ss_field = self.ss - self.on_end_transaction = lambda: self.output_data_block('Data', Ann.READ) - self.data.append(miso) - self.cmdstate += 1 - - def handle_write_common(self, mosi, miso, ann): - # Write data bytes: Master asserts CS#, sends WRITE command, sends - # 3-byte address, writes >= 1 data bytes, de-asserts CS#. - if self.cmdstate == 1: - # Byte 1: Master sends command ID. - self.emit_cmd_byte() - if self.writestate == 0: - self.putc([Ann.WARN, ['Warning: WREN might be missing']]) - elif self.cmdstate in (2, 3, 4): - # Bytes 2/3/4: Master sends write address (24bits, MSB-first). - self.emit_addr_bytes(mosi) - elif self.cmdstate >= 5: - # Bytes 5-x: Master writes data bytes (until CS# de-asserted). - self.es_field = self.es # Will be overwritten for each byte. - if self.cmdstate == 5: - self.ss_field = self.ss - self.on_end_transaction = lambda: self.output_data_block('Data', ann) - self.data.append(mosi) - self.cmdstate += 1 - - def handle_write1(self, mosi, miso): - self.handle_write_common(mosi, miso, Ann.WRITE1) - - def handle_write2(self, mosi, miso): - self.handle_write_common(mosi, miso, Ann.WRITE2) - - def handle_fast_read(self, mosi, miso): - # Fast read: Master asserts CS#, sends FAST READ command, sends - # 3-byte address + 1 dummy byte, reads >= 1 data bytes, de-asserts CS#. - if self.cmdstate == 1: - # Byte 1: Master sends command ID. - self.emit_cmd_byte() - elif self.cmdstate in (2, 3, 4): - # Bytes 2/3/4: Master sends read address (24bits, MSB-first). - self.emit_addr_bytes(mosi) - elif self.cmdstate == 5: - self.putx([Ann.BIT, ['Dummy byte: 0x%02x' % mosi]]) - elif self.cmdstate >= 6: - # Bytes 6-x: Master reads data bytes (until CS# de-asserted). - self.es_field = self.es # Will be overwritten for each byte. - if self.cmdstate == 6: - self.ss_field = self.ss - self.on_end_transaction = lambda: self.output_data_block('Data', Ann.FAST_READ) - self.data.append(miso) - self.cmdstate += 1 - - def handle_2read(self, mosi, miso): - # 2x I/O read (fast read dual I/O): Master asserts CS#, sends 2READ - # command, sends 3-byte address + 1 dummy byte, reads >= 1 data bytes, - # de-asserts CS#. All data after the command is sent via two I/O pins. - # MOSI = SIO0 = even bits, MISO = SIO1 = odd bits. - if self.cmdstate != 1: - b1, b2 = decode_dual_bytes(mosi, miso) - if self.cmdstate == 1: - # Byte 1: Master sends command ID. - self.emit_cmd_byte() - elif self.cmdstate == 2: - # Bytes 2/3(/4): Master sends read address (24bits, MSB-first). - # Handle bytes 2 and 3 here. - self.emit_addr_bytes(b1) - self.cmdstate = 3 - self.emit_addr_bytes(b2) - elif self.cmdstate == 4: - # Byte 5: Dummy byte. Also handle byte 4 (address LSB) here. - self.emit_addr_bytes(b1) - self.cmdstate = 5 - self.putx([Ann.BIT, ['Dummy byte: 0x%02x' % b2]]) - elif self.cmdstate >= 6: - # Bytes 6-x: Master reads data bytes (until CS# de-asserted). - self.es_field = self.es # Will be overwritten for each byte. - if self.cmdstate == 6: - self.ss_field = self.ss - self.on_end_transaction = lambda: self.output_data_block('Data', Ann.READ2X) - self.data.append(b1) - self.data.append(b2) - self.cmdstate += 1 - - def handle_status(self, mosi, miso): - if self.cmdstate == 1: - # Byte 1: Master sends command ID. - self.emit_cmd_byte() - self.on_end_transaction = lambda: self.putc([Ann.STATUS, [cmds[self.state][1]]]) - else: - # Will be overwritten for each byte. - self.es_cmd = self.es - self.es_field = self.es - if self.cmdstate == 2: - self.ss_field = self.ss - self.putx([Ann.BIT, ['Status register byte %d: 0x%02x' % ((self.cmdstate % 2) + 1, miso)]]) - self.cmdstate += 1 - - # TODO: Warn/abort if we don't see the necessary amount of bytes. - def handle_se(self, mosi, miso): - if self.cmdstate == 1: - # Byte 1: Master sends command ID. - self.emit_cmd_byte() - if self.writestate == 0: - self.putx([Ann.WARN, ['Warning: WREN might be missing']]) - elif self.cmdstate in (2, 3, 4): - # Bytes 2/3/4: Master sends sector address (24bits, MSB-first). - self.emit_addr_bytes(mosi) - - if self.cmdstate == 4: - self.es_cmd = self.es - d = 'Erase sector %d (0x%06x)' % (self.addr, self.addr) - self.putc([Ann.SE, [d]]) - # TODO: Max. size depends on chip, check that too if possible. - if self.addr % 4096 != 0: - # Sector addresses must be 4K-aligned (same for all 3 chips). - self.putc([Ann.WARN, ['Warning: Invalid sector address!']]) - self.state = None - else: - self.cmdstate += 1 - - def handle_be(self, mosi, miso): - pass # TODO - - def handle_ce(self, mosi, miso): - self.putx([Ann.CE, self.cmd_ann_list()]) - if self.writestate == 0: - self.putx([Ann.WARN, ['Warning: WREN might be missing']]) - - def handle_ce2(self, mosi, miso): - self.putx([Ann.CE2, self.cmd_ann_list()]) - if self.writestate == 0: - self.putx([Ann.WARN, ['Warning: WREN might be missing']]) - - def handle_pp(self, mosi, miso): - # Page program: Master asserts CS#, sends PP command, sends 3-byte - # page address, sends >= 1 data bytes, de-asserts CS#. - if self.cmdstate == 1: - # Byte 1: Master sends command ID. - self.emit_cmd_byte() - elif self.cmdstate in (2, 3, 4): - # Bytes 2/3/4: Master sends page address (24bits, MSB-first). - self.emit_addr_bytes(mosi) - elif self.cmdstate >= 5: - # Bytes 5-x: Master sends data bytes (until CS# de-asserted). - self.es_field = self.es # Will be overwritten for each byte. - if self.cmdstate == 5: - self.ss_field = self.ss - self.on_end_transaction = lambda: self.output_data_block('Data', Ann.PP) - self.data.append(mosi) - self.cmdstate += 1 - - def handle_cp(self, mosi, miso): - pass # TODO - - def handle_dp(self, mosi, miso): - pass # TODO - - def handle_rdp_res(self, mosi, miso): - if self.cmdstate == 1: - # Byte 1: Master sends command ID. - self.emit_cmd_byte() - elif self.cmdstate in (2, 3, 4): - # Bytes 2/3/4: Master sends three dummy bytes. - self.putx([Ann.FIELD, ['Dummy byte: %02x' % mosi]]) - elif self.cmdstate == 5: - # Byte 5: Slave sends device ID. - self.es_cmd = self.es - self.device_id = miso - self.putx([Ann.FIELD, ['Device ID: %s' % self.device()]]) - d = 'Device = %s' % self.vendor_device() - self.putc([Ann.RDP_RES, self.cmd_vendor_dev_list()]) - self.state = None - self.cmdstate += 1 - - def handle_rems(self, mosi, miso): - if self.cmdstate == 1: - # Byte 1: Master sends command ID. - self.emit_cmd_byte() - elif self.cmdstate in (2, 3): - # Bytes 2/3: Master sends two dummy bytes. - self.putx([Ann.FIELD, ['Dummy byte: 0x%02x' % mosi]]) - elif self.cmdstate == 4: - # Byte 4: Master sends 0x00 or 0x01. - # 0x00: Master wants manufacturer ID as first reply byte. - # 0x01: Master wants device ID as first reply byte. - self.manufacturer_id_first = True if (mosi == 0x00) else False - d = 'manufacturer' if (mosi == 0x00) else 'device' - self.putx([Ann.FIELD, ['Master wants %s ID first' % d]]) - elif self.cmdstate == 5: - # Byte 5: Slave sends manufacturer ID (or device ID). - self.ids = [miso] - d = 'Manufacturer' if self.manufacturer_id_first else 'Device' - self.putx([Ann.FIELD, ['%s ID: 0x%02x' % (d, miso)]]) - elif self.cmdstate == 6: - # Byte 6: Slave sends device ID (or manufacturer ID). - self.ids.append(miso) - d = 'Device' if self.manufacturer_id_first else 'Manufacturer' - self.putx([Ann.FIELD, ['%s ID: 0x%02x' % (d, miso)]]) - - if self.cmdstate == 6: - id_ = self.ids[1] if self.manufacturer_id_first else self.ids[0] - self.device_id = id_ - self.es_cmd = self.es - self.putc([Ann.REMS, self.cmd_vendor_dev_list()]) - self.state = None - else: - self.cmdstate += 1 - - def handle_rems2(self, mosi, miso): - pass # TODO - - def handle_enso(self, mosi, miso): - pass # TODO - - def handle_exso(self, mosi, miso): - pass # TODO - - def handle_rdscur(self, mosi, miso): - pass # TODO - - def handle_wrscur(self, mosi, miso): - pass # TODO - - def handle_esry(self, mosi, miso): - pass # TODO - - def handle_dsry(self, mosi, miso): - pass # TODO - - def output_data_block(self, label, idx): - # Print accumulated block of data - # (called on CS# de-assert via self.on_end_transaction callback). - self.es_cmd = self.es # End on the CS# de-assert sample. - if self.options['format'] == 'hex': - s = ' '.join([('%02x' % b) for b in self.data]) - else: - s = ''.join(map(chr, self.data)) - self.putf([Ann.FIELD, ['%s (%d bytes)' % (label, len(self.data))]]) - self.putc([idx, ['%s (addr 0x%06x, %d bytes): %s' % \ - (cmds[self.state][1], self.addr, len(self.data), s)]]) - - def decode(self, ss, es, data): - ptype, mosi, miso = data - - self.ss, self.es = ss, es - - if ptype == 'CS-CHANGE': - self.end_current_transaction() - - if ptype != 'DATA': - return - - # If we encountered a known chip command, enter the resp. state. - if self.state is None: - self.state = mosi - self.cmdstate = 1 - - # Handle commands. - try: - self.cmd_handlers[self.state](mosi, miso) - except KeyError: - self.putx([Ann.BIT, ['Unknown command: 0x%02x' % mosi]]) - self.state = None diff --git a/decoders/ssi32/__init__.py b/decoders/ssi32/__init__.py deleted file mode 100755 index cd6890fa..00000000 --- a/decoders/ssi32/__init__.py +++ /dev/null @@ -1,28 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2016 Robert Bosch Car Multimedia GmbH -## Authors: Oleksij Rempel -## -## -## -## 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, see . -## - -''' -This decoder stacks on top of the 'spi' PD and decodes the Bosch -SSI32 protocol. -''' - -from .pd import Decoder diff --git a/decoders/ssi32/pd.py b/decoders/ssi32/pd.py deleted file mode 100755 index 51608039..00000000 --- a/decoders/ssi32/pd.py +++ /dev/null @@ -1,127 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2016 Robert Bosch Car Multimedia GmbH -## Authors: Oleksij Rempel -## -## -## -## 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, see . -## - -import sigrokdecode as srd - -class Decoder(srd.Decoder): - api_version = 3 - id = 'ssi32' - name = 'SSI32' - longname = 'Synchronous Serial Interface (32bit)' - desc = 'Synchronous Serial Interface (32bit) protocol.' - license = 'gplv2+' - inputs = ['spi'] - outputs = [] - tags = ['Embedded/industrial'] - options = ( - {'id': 'msgsize', 'desc': 'Message size', 'default': 64}, - ) - annotations = ( - ('ctrl-tx', 'CTRL TX'), - ('ack-tx', 'ACK TX'), - ('ctrl-rx', 'CTRL RX'), - ('ack-rx', 'ACK RX'), - ) - annotation_rows = ( - ('tx', 'TX', (0, 1)), - ('rx', 'RX', (2, 3)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.ss_cmd, self.es_cmd = 0, 0 - self.mosi_bytes = [] - self.miso_bytes = [] - self.es_array = [] - self.rx_size = 0 - self.tx_size = 0 - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putx(self, data): - self.put(self.ss_cmd, self.es_cmd, self.out_ann, data) - - def reset_data(self): - self.mosi_bytes = [] - self.miso_bytes = [] - self.es_array = [] - - def handle_ack(self): - # Only first byte should have ACK data, other 3 bytes are reserved. - self.es_cmd = self.es_array[0] - self.putx([1, ['> ACK:0x%02x' % (self.mosi_bytes[0])]]) - self.putx([3, ['< ACK:0x%02x' % (self.miso_bytes[0])]]) - - def handle_ctrl(self): - mosi = miso = '' - self.tx_size = self.mosi_bytes[2] - self.rx_size = self.miso_bytes[2] - - if self.tx_size > 0: - mosi = ', DATA:0x' + ''.join(format(x, '02x') for x in self.mosi_bytes[4:self.tx_size + 4]) - if self.rx_size > 0: - miso = ', DATA:0x' + ''.join(format(x, '02x') for x in self.miso_bytes[4:self.rx_size + 4]) - - self.es_cmd = self.es_array[self.tx_size + 3] - self.putx([0, ['> CTRL:0x%02x, LUN:0x%02x, SIZE:0x%02x, CRC:0x%02x%s' - % (self.mosi_bytes[0], self.mosi_bytes[1], - self.mosi_bytes[2], self.mosi_bytes[3], mosi)]]) - - self.es_cmd = self.es_array[self.rx_size + 3] - self.putx([2, ['< CTRL:0x%02x, LUN:0x%02x, SIZE:0x%02x, CRC:0x%02x%s' - % (self.miso_bytes[0], self.miso_bytes[1], - self.miso_bytes[2], self.miso_bytes[3], miso)]]) - - def decode(self, ss, es, data): - ptype = data[0] - if ptype == 'CS-CHANGE': - self.reset_data() - return - - # Don't care about anything else. - if ptype != 'DATA': - return - mosi, miso = data[1:] - - self.ss, self.es = ss, es - - if len(self.mosi_bytes) == 0: - self.ss_cmd = ss - self.mosi_bytes.append(mosi) - self.miso_bytes.append(miso) - self.es_array.append(es) - - if self.mosi_bytes[0] & 0x80: - if len(self.mosi_bytes) < 4: - return - - self.handle_ack() - self.reset_data() - else: - if len(self.mosi_bytes) < self.options['msgsize']: - return - - self.handle_ctrl() - self.reset_data() diff --git a/decoders/st25r39xx_spi/__init__.py b/decoders/st25r39xx_spi/__init__.py deleted file mode 100644 index 3803789e..00000000 --- a/decoders/st25r39xx_spi/__init__.py +++ /dev/null @@ -1,31 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019-2020 Benjamin Vernoux -## -## 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, see . -## - -''' -This decoder stacks on top of the SPI PD and decodes the st25r39xx High performance NFC universal device and EMVCo reader protocol (SPI mode). - -It has been successfully tested with the st25r3916, other chips of this family may or may not be fully supported but not been verified. - -Please note that the SPI interface uses clock polarity 0 and clock phase 1, which is not the default setting. - -Details: -https://www.st.com/resource/en/datasheet/st25r3916.pdf -''' - -from .pd import Decoder diff --git a/decoders/st25r39xx_spi/lists.py b/decoders/st25r39xx_spi/lists.py deleted file mode 100644 index 14297654..00000000 --- a/decoders/st25r39xx_spi/lists.py +++ /dev/null @@ -1,231 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019-2020 Benjamin Vernoux -## -## 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, see . -## -## v0.1 - 17 September 2019 B.VERNOUX using ST25R3916 Datasheet DS12484 Rev 1 (January 2019) -## v0.2 - 28 April 2020 B.VERNOUX using ST25R3916 Datasheet DS12484 Rev 2 (December 2019) https://www.st.com/resource/en/datasheet/st25r3916.pdf -## v0.3 - 17 June 2020 B.VERNOUX using ST25R3916 Datasheet DS12484 Rev 3 (04 June 2020) https://www.st.com/resource/en/datasheet/st25r3916.pdf - -## ST25R3916 Datasheet DS12484 Rev 3 (04 June 2020) §4.4 Direct commands -dir_cmd = { -# addr: 'name' -# Set Default - 0xC0: 'SET_DEFAULT', - 0xC1: 'SET_DEFAULT', -# Stop All Activities - 0xC2: 'STOP', - 0xC3: 'STOP', -# Transmit With CRC - 0xC4: 'TXCRC', -# Transmit Without CRC - 0xC5: 'TXNOCRC', -# Transmit REQA - 0xC6: 'TXREQA', -# Transmit WUPA - 0xC7: 'TXWUPA', -# NFC Initial Field ON - 0xC8: 'NFCINITFON', -# NFC Response Field ON - 0xC9: 'NFCRESFON', -# Go to Sense (Idle) - 0xCD: 'GOIDLE', -# Go to Sleep (Halt) - 0xCE: 'GOHALT', -# Mask Receive Data / Stops receivers and RX decoders - 0xD0: 'STOPRX', -# Unmask Receive Data / Starts receivers and RX decoders - 0xD1: 'STARRX', -# Change AM Modulation state - 0xD2: 'SETAMSTATE', -# Measure Amplitude - 0xD3: 'MAMP', -# Reset RX Gain - 0xD5: 'RSTRXGAIN', -# Adjust Regulators - 0xD6: 'ADJREG', -# Calibrate Driver Timing - 0xD8: 'CALDRVTIM', -# Measure Phase - 0xD9: 'MPHASE', -# Clear RSSI - 0xDA: 'CLRRSSI', -# Clear FIFO - 0xDB: 'CLRFIFO', -# Enter Transparent Mode - 0xDC: 'TRMODE', -# Calibrate Capacitive Sensor - 0xDD: 'CALCAPA', -# Measure Capacitance - 0xDE: 'MCAPA', -# Measure Power Supply - 0xDF: 'MPOWER', -# Start General Purpose Timer - 0xE0: 'STARGPTIM', -# Start Wake-up Timer - 0xE1: 'STARWTIM', -# Start Mask-receive Timer - 0xE2: 'STARMSKTIM', -# Start No-response Timer - 0xE3: 'STARNRESPTIM', -# Start PPON2 Timer - 0xE4: 'STARPPON2TIM', -# Stop No-response Timer - 0xE8: 'STOPNRESTIM', -# RFU / Not Used - 0xFA: 'RFU', -# Register Space-B Access - 0xFB: 'REGSPACEB', -# Register Test access - 0xFC: 'TESTACCESS' -# Other codes => RFU / Not Used -} - -## ST25R3916 Datasheet DS12484 Rev 2 (December 2019) §4.5 Registers Table 17. List of registers - Space A -## ST25R3916 Datasheet DS12484 Rev 2 (December 2019) §4.3.3 Serial peripheral interface (SPI) Table 11. SPI operation modes -regsSpaceA = { -# addr: 'name' -# §4.5 Registers Table 17. List of registers - Space A -# IO configuration - 0x00: 'IOCFG1', - 0x01: 'IOCFG2', -# Operation control and mode definition - 0x02: 'OPCTRL', - 0x03: 'MODEDEF', - 0x04: 'BITRATE', -# Protocol configuration - 0x05: 'TYPEA', - 0x06: 'TYPEB', - 0x07: 'TYPEBF', - 0x08: 'NFCIP1', - 0x09: 'STREAM', - 0x0A: 'AUX', -# Receiver configuration - 0x0B: 'RXCFG1', - 0x0C: 'RXCFG2', - 0x0D: 'RXCFG3', - 0x0E: 'RXCFG4', -# Timer definition - 0x0F: 'MSKRXTIM', - 0x10: 'NRESPTIM1', - 0x11: 'NRESPTIM2', - 0x12: 'TIMEMV', - 0x13: 'GPTIM1', - 0x14: 'GPTIM2', - 0x15: 'PPON2', -# Interrupt and associated reporting - 0x16: 'MSKMAINIRQ', - 0x17: 'MSKTIMNFCIRQ', - 0x18: 'MSKERRWAKEIRQ', - 0x19: 'TARGIRQ', - 0x1A: 'MAINIRQ', - 0x1B: 'TIMNFCIRQ', - 0x1C: 'ERRWAKEIRQ', - 0x1D: 'TARGIRQ', - 0x1E: 'FIFOSTAT1', - 0x1F: 'FIFOSTAT2', - 0x20: 'COLLDISP', - 0x21: 'TARGDISP', -# Definition of number of transmitted bytes - 0x22: 'NBTXB1', - 0x23: 'NBTXB2', - 0x24: 'BITRATEDET', -# A/D converter output - 0x25: 'ADCONVOUT', -# Antenna calibration - 0x26: 'ANTTUNECTRL1', - 0x27: 'ANTTUNECTRL2', -# Antenna driver and modulation - 0x28: 'TXDRV', - 0x29: 'TARGMOD', -# External field detector threshold - 0x2A: 'EXTFIELDON', - 0x2B: 'EXTFIELDOFF', -# Regulator - 0x2C: 'REGVDDCTRL', -# Receiver state display - 0x2D: 'RSSIDISP', - 0x2E: 'GAINSTATE', -# Capacitive sensor - 0x2F: 'CAPACTRL', - 0x30: 'CAPADISP', -# Auxiliary display - 0x31: 'AUXDISP', -# Wake-up - 0x32: 'WAKETIMCTRL', - 0x33: 'AMPCFG', - 0x34: 'AMPREF', - 0x35: 'AMPAAVGDISP', - 0x36: 'AMPDISP', - 0x37: 'PHASECFG', - 0x38: 'PHASEREF', - 0x39: 'PHASEAAVGDISP', - 0x3A: 'PHASEDISP', - 0x3B: 'CAPACFG', - 0x3C: 'CAPAREF', - 0x3D: 'CAPAAAVGDISP', - 0x3E: 'CAPADISP', -# IC identity - 0x3F: 'ICIDENT', -## ST25R3916 Datasheet DS12484 Rev 2 (December 2019) §4.3.3 Serial peripheral interface (SPI) Table 11. SPI operation modes - 0xA0: 'PT_memLoadA', - 0xA8: 'PT_memLoadF', - 0xAC: 'PT_memLoadTSN', - 0xBF: 'PT_memRead' -} - -## ST25R3916 Datasheet DS12484 Rev 2 (December 2019) §4.5 Registers Table 18. List of registers - Space B -regsSpaceB = { -# addr: 'name' -# §4.5 Registers Table 18. List of registers - Space B -# Protocol configuration - 0x05: 'EMDSUPPRCONF', - 0x06: 'SUBCSTARTIM', -# Receiver configuration - 0x0B: 'P2PRXCONF', - 0x0C: 'CORRCONF1', - 0x0D: 'CORRCONF2', -# Timer definition - 0x0F: 'SQUELSHTIM', - 0x15: 'NFCGUARDTIM', -# Antenna driver and modulation - 0x28: 'AUXMODSET', - 0x29: 'TXDRVTIM', -# External field detector threshold - 0x2A: 'RESAMMODE', - 0x2B: 'TXDRVTIMDISP', -# Regulator - 0x2C: 'REGDISP', -# Protection - 0x30: 'OSHOOTCONF1', - 0x31: 'OSHOOTCONF2', - 0x32: 'USHOOTCONF1', - 0x33: 'USHOOTCONF2' -} - -## ST25R3916 Datasheet DS12484 Rev 2 (December 2019) §4.4.17 Test access -regsTest = { -# addr: 'name' -# §4.4.17 Test access (Typo in datasheet it is not register 0x00 but 0x01) - 0x01: 'ANTSTOBS' -} - -## Optional TODO add important status bit fields / ANN_STATUS -## Interrupt and associated reporting => Registers Space A from Address (hex) 0x16 to 0x21 -## §4.5.58 RSSI display register -## §4.5.59 Gain reduction state register -## ... - diff --git a/decoders/st25r39xx_spi/pd.py b/decoders/st25r39xx_spi/pd.py deleted file mode 100644 index 1b0df073..00000000 --- a/decoders/st25r39xx_spi/pd.py +++ /dev/null @@ -1,350 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019-2020 Benjamin Vernoux -## -## 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, see . -## - -import sigrokdecode as srd -from collections import namedtuple -from common.srdhelper import SrdIntEnum -from .lists import * - -Ann = SrdIntEnum.from_str('Ann', 'BURST_READ BURST_WRITE \ - BURST_READB BURST_WRITEB BURST_READT BURST_WRITET \ - DIRECTCMD FIFO_WRITE FIFO_READ STATUS WARN') - -Pos = namedtuple('Pos', ['ss', 'es']) -Data = namedtuple('Data', ['mosi', 'miso']) - -class Decoder(srd.Decoder): - api_version = 3 - id = 'st25r39xx_spi' - name = 'ST25R39xx (SPI mode)' - longname = 'STMicroelectronics ST25R39xx' - desc = 'High performance NFC universal device and EMVCo reader protocol.' - license = 'gplv2+' - inputs = ['spi'] - outputs = [] - tags = ['IC', 'Wireless/RF'] - annotations = ( - ('Read', 'Burst register read'), - ('Write', 'Burst register write'), - ('ReadB', 'Burst register SpaceB read'), - ('WriteB', 'Burst register SpaceB write'), - ('ReadT', 'Burst register Test read'), - ('WriteT', 'Burst register Test write'), - ('Cmd', 'Direct command'), - ('FIFOW', 'FIFO write'), - ('FIFOR', 'FIFO read'), - ('status_reg', 'Status register'), - ('warning', 'Warning'), - ) - annotation_rows = ( - ('regs', 'Regs', (Ann.prefixes('BURST_'))), - ('cmds', 'Commands', (Ann.DIRECTCMD,)), - ('data', 'Data', (Ann.prefixes('FIFO_'))), - ('status', 'Status register', (Ann.STATUS,)), - ('warnings', 'Warnings', (Ann.WARN,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.next() - self.requirements_met = True - self.cs_was_released = False - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def warn(self, pos, msg): - '''Put a warning message 'msg' at 'pos'.''' - self.put(pos.ss, pos.es, self.out_ann, [Ann.WARN, [msg]]) - - def putp(self, pos, ann, msg): - '''Put an annotation message 'msg' at 'pos'.''' - self.put(pos.ss, pos.es, self.out_ann, [ann, [msg]]) - - def putp2(self, pos, ann, msg1, msg2): - '''Put an annotation message 'msg' at 'pos'.''' - self.put(pos.ss, pos.es, self.out_ann, [ann, [msg1, msg2]]) - - def next(self): - '''Resets the decoder after a complete command was decoded.''' - # 'True' for the first byte after CS# went low. - self.first = True - - # The current command, and the minimum and maximum number - # of data bytes to follow. - self.cmd = None - self.min = 0 - self.max = 0 - - # Used to collect the bytes after the command byte - # (and the start/end sample number). - self.mb = [] - self.ss_mb = -1 - self.es_mb = -1 - - def mosi_bytes(self): - '''Returns the collected MOSI bytes of a multi byte command.''' - return [b.mosi for b in self.mb] - - def miso_bytes(self): - '''Returns the collected MISO bytes of a multi byte command.''' - return [b.miso for b in self.mb] - - def decode_command(self, pos, b): - '''Decodes the command byte 'b' at position 'pos' and prepares - the decoding of the following data bytes.''' - c = self.parse_command(b) - if c is None: - self.warn(pos, 'Unknown command') - return - - self.cmd, self.dat, self.min, self.max = c - - if self.cmd == 'Cmd': - self.putp(pos, Ann.DIRECTCMD, self.format_command()) - else: - # Don't output anything now, the command is merged with - # the data bytes following it. - self.ss_mb = pos.ss - - def format_command(self): - '''Returns the label for the current command.''' - if self.cmd in ('Write', 'Read', 'WriteB', 'ReadB', 'WriteT', 'ReadT', 'FIFO Write', 'FIFO Read'): - return self.cmd - if self.cmd == 'Cmd': - reg = dir_cmd.get(self.dat, 'Unknown direct command') - return '{} {}'.format(self.cmd, reg) - else: - return 'TODO Cmd {}'.format(self.cmd) - - def parse_command(self, b): - '''Parses the command byte. - Returns a tuple consisting of: - - the name of the command - - additional data needed to dissect the following bytes - - minimum number of following bytes - - maximum number of following bytes (None for infinite) - ''' - addr = b & 0x3F - # previous command was 'Space B' - if self.cmd == 'Space B': - if (b & 0xC0) == 0x00: - return ('WriteB', addr, 1, 99999) - if (b & 0xC0) == 0x40: - return ('ReadB', addr, 1, 99999) - else: - self.warn(pos, 'Unknown address/command combination') - # previous command was 'TestAccess' - elif self.cmd == 'TestAccess': - if (b & 0xC0) == 0x00: - return ('WriteT', addr, 1, 99999) - if (b & 0xC0) == 0x40: - return ('ReadT', addr, 1, 99999) - else: - self.warn(pos, 'Unknown address/command combination') - else: - # Space A regs or other operation modes (except Space B) - # Register Write 0b00xxxxxx 0x00 to 0x3F => 'Write' - # Register Read 0b01xxxxxx 0x40 to 0x7F => 'Read' - if (b <= 0x7F): - if (b & 0xC0) == 0x00: - return ('Write', addr, 1, 99999) - if (b & 0xC0) == 0x40: - return ('Read', addr, 1, 99999) - else: - self.warn(pos, 'Unknown address/command combination') - else: - # FIFO Load 0b10000000 0x80 => 'FIFO Write' - # PT_memory loadA-config 0b10100000 0xA0 => 'Write' - # PT_memory loadF-config 0b10101000 0xA8 => 'Write' - # PT_memory loadTSN data 0b10101100 0xAC => 'Write' - # PT_memory Read 0b10111111 0xBF => 'Read' - # FIFO Read 0b10011111 0x9F => 'FIFO Read' - # Direct Command 0b11xxx1xx 0xC0 to 0xE8 => 'Cmd' - # Register Space-B Access 0b11111011 0xFB => 'Space B' - # Register Test Access 0b11111100 0xFC => 'TestAccess' - if b == 0x80: - return ('FIFO Write', b, 1, 99999) - if b == 0xA0: - return ('Write', b, 1, 99999) - if b == 0xA8: - return ('Write', b, 1, 99999) - if b == 0xAC: - return ('Write', b, 1, 99999) - if b == 0xBF: - return ('Read', b, 1, 99999) - if b == 0x9F: - return ('FIFO Read', b, 1, 99999) - if (b >= 0x0C and b <= 0xE8) : - return ('Cmd', b, 0, 0) - if b == 0xFB: - return ('Space B', b, 0, 0) - if b == 0xFC: - return ('TestAccess', b, 0, 0) - else: - self.warn(pos, 'Unknown address/command combination') - - def decode_reg(self, pos, ann, regid, data): - '''Decodes a register. - pos -- start and end sample numbers of the register - ann -- the annotation number that is used to output the register. - regid -- may be either an integer used as a key for the 'regs' - dictionary, or a string directly containing a register name.' - data -- the register content. - ''' - if type(regid) == int: - if (ann == Ann.FIFO_READ) or (ann == Ann.FIFO_WRITE): - name = '' - elif (ann == Ann.BURST_READB) or (ann == Ann.BURST_WRITEB): - # Get the name of the register. - if regid not in regsSpaceB: - self.warn(pos, 'Unknown register SpaceB') - return - name = '{} ({:02X})'.format(regsSpaceB[regid], regid) - elif (ann == Ann.BURST_READT) or (ann == Ann.BURST_WRITET): - # Get the name of the register. - if regid not in regsTest: - self.warn(pos, 'Unknown register Test') - return - name = '{} ({:02X})'.format(regsTest[regid], regid) - else: - # Get the name of the register. - if regid not in regsSpaceA: - self.warn(pos, 'Unknown register SpaceA') - return - name = '{} ({:02X})'.format(regsSpaceA[regid], regid) - else: - name = regid - - if regid == 'STATUS' and ann == Ann.STATUS: - label = 'Status' - self.decode_status_reg(pos, ann, data, label) - else: - label = '{}: {}'.format(self.format_command(), name) - self.decode_mb_data(pos, ann, data, label) - - def decode_status_reg(self, pos, ann, data, label): - '''Decodes the data bytes 'data' of a status register at position - 'pos'. The decoded data is prefixed with 'label'.''' - - def decode_mb_data(self, pos, ann, data, label): - '''Decodes the data bytes 'data' of a multibyte command at position - 'pos'. The decoded data is prefixed with 'label'.''' - - def escape(b): - return '{:02X}'.format(b) - - data = ' '.join([escape(b) for b in data]) - if (ann == Ann.FIFO_WRITE) or (ann == Ann.FIFO_READ): - text = '{}{}'.format(label, data) - else: - text = '{} = {}'.format(label, data) - self.putp(pos, ann, text) - - def finish_command(self, pos): - '''Decodes the remaining data bytes at position 'pos'.''' - if self.cmd == 'Write': - self.decode_reg(pos, Ann.BURST_WRITE, self.dat, self.mosi_bytes()) - elif self.cmd == 'Read': - self.decode_reg(pos, Ann.BURST_READ, self.dat, self.miso_bytes()) - elif self.cmd == 'WriteB': - self.decode_reg(pos, Ann.BURST_WRITEB, self.dat, self.mosi_bytes()) - elif self.cmd == 'ReadB': - self.decode_reg(pos, Ann.BURST_READB, self.dat, self.miso_bytes()) - elif self.cmd == 'WriteT': - self.decode_reg(pos, Ann.BURST_WRITET, self.dat, self.mosi_bytes()) - elif self.cmd == 'ReadT': - self.decode_reg(pos, Ann.BURST_READT, self.dat, self.miso_bytes()) - elif self.cmd == 'FIFO Write': - self.decode_reg(pos, Ann.FIFO_WRITE, self.dat, self.mosi_bytes()) - elif self.cmd == 'FIFO Read': - self.decode_reg(pos, Ann.FIFO_READ, self.dat, self.miso_bytes()) - elif self.cmd == 'Cmd': - self.decode_reg(pos, Ann.DIRECTCMD, self.dat, self.mosi_bytes()) - else: - self.warn(pos, 'Unhandled command {}'.format(self.cmd)) - - def decode(self, ss, es, data): - if not self.requirements_met: - return - - ptype, data1, data2 = data - - if ptype == 'CS-CHANGE': - if data1 is None: - if data2 is None: - self.requirements_met = False - raise ChannelError('CS# pin required.') - elif data2 == 1: - self.cs_was_released = True - - if data1 == 0 and data2 == 1: - # Rising edge, the complete command is transmitted, process - # the bytes that were sent after the command byte. - if self.cmd: - # Check if we got the minimum number of data bytes - # after the command byte. - if len(self.mb) < self.min: - self.warn((ss, ss), 'Missing data bytes') - elif self.mb: - self.finish_command(Pos(self.ss_mb, self.es_mb)) - - self.next() - self.cs_was_released = True - - elif ptype == 'DATA' and self.cs_was_released: - mosi, miso = data1, data2 - pos = Pos(ss, es) - - if miso is None or mosi is None: - self.requirements_met = False - raise ChannelError('Both MISO and MOSI pins are required.') - - if self.first: - # Register Space-B Access 0b11111011 0xFB => 'Space B' - if mosi == 0xFB: - self.first = True - # First MOSI byte 'Space B' command. - self.decode_command(pos, mosi) - # First MISO byte is always the status register. - #self.decode_reg(pos, ANN_STATUS, 'STATUS', [miso]) - # Register TestAccess Access 0b11111100 0xFC => 'TestAccess' - elif mosi == 0xFC: - self.first = True - # First MOSI byte 'TestAccess' command. - self.decode_command(pos, mosi) - # First MISO byte is always the status register. - #self.decode_reg(pos, ANN_STATUS, 'STATUS', [miso]) - else: - self.first = False - # First MOSI byte is always the command. - self.decode_command(pos, mosi) - # First MISO byte is always the status register. - #self.decode_reg(pos, ANN_STATUS, 'STATUS', [miso]) - else: - if not self.cmd or len(self.mb) >= self.max: - self.warn(pos, 'Excess byte') - else: - # Collect the bytes after the command byte. - if self.ss_mb == -1: - self.ss_mb = ss - self.es_mb = es - self.mb.append(Data(mosi, miso)) diff --git a/decoders/st7735/__init__.py b/decoders/st7735/__init__.py deleted file mode 100755 index 771578c6..00000000 --- a/decoders/st7735/__init__.py +++ /dev/null @@ -1,27 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Aleksander Alekseev -## -## 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, see . -## - -''' -This decoder decodes the Sitronix ST7735 TFT controller protocol. - -Details: -http://www.displayfuture.com/Display/datasheet/controller/ST7735.pdf -''' - -from .pd import Decoder diff --git a/decoders/st7735/pd.py b/decoders/st7735/pd.py deleted file mode 100755 index 252b1887..00000000 --- a/decoders/st7735/pd.py +++ /dev/null @@ -1,173 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Aleksander Alekseev -## -## 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, see . - -import sigrokdecode as srd - -MAX_DATA_LEN = 128 - -# Command ID -> name, short description -META = { - 0x00: {'name': 'NOP ', 'desc': 'No operation'}, - 0x01: {'name': 'SWRESET', 'desc': 'Software reset'}, - 0x04: {'name': 'RDDID ', 'desc': 'Read display ID'}, - 0x09: {'name': 'RDDST ', 'desc': 'Read display status'}, - 0x10: {'name': 'SLPIN ', 'desc': 'Sleep in & booster off'}, - 0x11: {'name': 'SLPOUT ', 'desc': 'Sleep out & booster on'}, - 0x12: {'name': 'PTLON ', 'desc': 'Partial mode on'}, - 0x13: {'name': 'NORON ', 'desc': 'Partial off (normal)'}, - 0x20: {'name': 'INVOFF ', 'desc': 'Display inversion off'}, - 0x21: {'name': 'INVON ', 'desc': 'Display inversion on'}, - 0x28: {'name': 'DISPOFF', 'desc': 'Display off'}, - 0x29: {'name': 'DISPON ', 'desc': 'Display on'}, - 0x2A: {'name': 'CASET ', 'desc': 'Column address set'}, - 0x2B: {'name': 'RASET ', 'desc': 'Row address set'}, - 0x2C: {'name': 'RAMWR ', 'desc': 'Memory write'}, - 0x2E: {'name': 'RAMRD ', 'desc': 'Memory read'}, - 0x30: {'name': 'PTLAR ', 'desc': 'Partial start/end address set'}, - 0x36: {'name': 'MADCTL ', 'desc': 'Memory data address control'}, - 0x3A: {'name': 'COLMOD ', 'desc': 'Interface pixel format'}, - 0xB1: {'name': 'FRMCTR1', 'desc': 'Frame rate control (in normal mode / full colors)'}, - 0xB2: {'name': 'FRMCTR2', 'desc': 'Frame rate control (in idle mode / 8-colors)'}, - 0xB3: {'name': 'FRMCTR3', 'desc': 'Frame rate control (in partial mode / full colors) '}, - 0xB4: {'name': 'INVCTR ', 'desc': 'Display inversion control'}, - 0xB6: {'name': 'DISSET5', 'desc': 'Display function set 5'}, - 0xC0: {'name': 'PWCTR1 ', 'desc': 'Power control 1'}, - 0xC1: {'name': 'PWCTR2 ', 'desc': 'Power control 2'}, - 0xC2: {'name': 'PWCTR3 ', 'desc': 'Power control 3'}, - 0xC3: {'name': 'PWCTR4 ', 'desc': 'Power control 4'}, - 0xC4: {'name': 'PWCTR5 ', 'desc': 'Power control 5'}, - 0xC5: {'name': 'VMCTR1 ', 'desc': 'VCOM control 1'}, - 0xDA: {'name': 'RDID1 ', 'desc': 'Read ID1'}, - 0xDB: {'name': 'RDID2 ', 'desc': 'Read ID2'}, - 0xDC: {'name': 'RDID3 ', 'desc': 'Read ID3'}, - 0xDD: {'name': 'RDID4 ', 'desc': 'Read ID4'}, - 0xFC: {'name': 'PWCTR6 ', 'desc': 'Power control 6'}, - 0xE0: {'name': 'GMCTRP1', 'desc': 'Gamma \'+\'polarity correction characteristics setting'}, - 0xE1: {'name': 'GMCTRN1', 'desc': 'Gamma \'-\'polarity correction characteristics setting'}, -} - -class Ann: - BITS, CMD, DATA, DESC = range(4) - -class Decoder(srd.Decoder): - api_version = 3 - id = 'st7735' - name = 'ST7735' - longname = 'Sitronix ST7735' - desc = 'Sitronix ST7735 TFT controller protocol.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Display', 'IC'] - channels = ( - {'id': 'cs', 'name': 'CS#', 'desc': 'Chip-select'}, - {'id': 'clk', 'name': 'CLK', 'desc': 'Clock'}, - {'id': 'mosi', 'name': 'MOSI', 'desc': 'Master out, slave in'}, - {'id': 'dc', 'name': 'DC', 'desc': 'Data or command'} - ) - annotations = ( - ('bit', 'Bit'), - ('command', 'Command'), - ('data', 'Data'), - ('description', 'Description'), - ) - annotation_rows = ( - ('bits', 'Bits', (Ann.BITS,)), - ('fields', 'Fields', (Ann.CMD, Ann.DATA)), - ('description', 'Description', (Ann.DESC,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.accum_byte = 0 - self.accum_bits_num = 0 - self.bit_ss = -1 - self.byte_ss = -1 - self.current_bit = -1 - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def put_desc(self, ss, es, cmd, data): - if cmd == -1: - return - if META[cmd]: - self.put(ss, es, self.out_ann, [Ann.DESC, - ['%s: %s' % (META[cmd]['name'].strip(), META[cmd]['desc'])]]) - else: - # Default description: - dots = '' - if len(data) == MAX_DATA_LEN: - data = data[:-1] - dots = '...' - data_str = '(none)' - if len(data) > 0: - data_str = ' '.join(['%02X' % b for b in data]) - self.put(ss, es, self.out_ann, [Ann.DESC, - ['Unknown command: %02X. Data: %s%s' % (cmd, data_str, dots)]]) - - def decode(self): - current_cmd = -1 - current_data = [] - desc_ss = -1 - desc_es = -1 - self.reset() - while True: - # Check data on both CLK edges. - (cs, clk, mosi, dc) = self.wait({1: 'e'}) - - if cs == 1: # Wait for CS = low, ignore the rest. - self.reset() - continue - - if clk == 1: - # Read one bit. - self.bit_ss = self.samplenum - if self.accum_bits_num == 0: - self.byte_ss = self.samplenum - self.current_bit = mosi - - if (clk == 0) and (self.current_bit >= 0): - # Process one bit. - self.put(self.bit_ss, self.samplenum, self.out_ann, - [Ann.BITS, [str(self.current_bit)]]) - self.accum_byte = (self.accum_byte << 1) | self.current_bit # MSB-first. - self.accum_bits_num += 1 - if self.accum_bits_num == 8: - # Process one byte. - ann = Ann.DATA if dc else Ann.CMD # DC = low for commands. - self.put(self.byte_ss, self.samplenum, self.out_ann, - [ann, ['%02X' % self.accum_byte]]) - if ann == Ann.CMD: - self.put_desc(desc_ss, desc_es, current_cmd, current_data) - desc_ss = self.byte_ss - desc_es = self.samplenum # For cmds without data. - current_cmd = self.accum_byte - current_data = [] - else: - if len(current_data) < MAX_DATA_LEN: - current_data += [self.accum_byte] - desc_es = self.samplenum - - self.accum_bits_num = 0 - self.accum_byte = 0 - self.byte_ss = -1 - self.current_bit = -1 - self.bit_ss = -1 diff --git a/decoders/st7789/__init__.py b/decoders/st7789/__init__.py deleted file mode 100644 index 5a57c5be..00000000 --- a/decoders/st7789/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -This decoder decodes the Sitronix ST7789 TFT controller protocol. - -Details: https://www.newhavendisplay.com/appnotes/datasheets/LCDs/ST7789V.pdf -""" - -from .pd import Decoder diff --git a/decoders/st7789/pd.py b/decoders/st7789/pd.py deleted file mode 100644 index b8141ac7..00000000 --- a/decoders/st7789/pd.py +++ /dev/null @@ -1,296 +0,0 @@ -import sigrokdecode as srd - -COMMAND_MAP = { - 0x00: {"name": "NOP", "desc": "Empty command",}, - 0x01: {"name": "SWRESET", "desc": "Software Reset",}, - 0x04: {"name": "RDDID", "desc": "Read Display ID",}, - 0x09: {"name": "RDDST", "desc": "Read Display Status",}, - 0x0A: {"name": "RDDPM", "desc": "Read Display Power Mode",}, - 0x0B: {"name": "RDDMADCTL", "desc": "Read Display MADCTL",}, - 0x0C: {"name": "RDDCOLMOD", "desc": "Read Display Pixel Format",}, - 0x0D: {"name": "RDDIM", "desc": "Read Display Image Mode",}, - 0x0E: {"name": "RDDSM", "desc": "Read Display Signal Mode",}, - 0x0F: {"name": "RDDSDR", "desc": "Read Display Self-Diagnostic Result",}, - 0x10: {"name": "SLPIN", "desc": "Sleep in",}, - 0x11: {"name": "SLPOUT", "desc": "Sleep Out",}, - 0x12: {"name": "PTLON", "desc": "Partial Display Mode On",}, - 0x13: {"name": "NORON", "desc": "Normal Display Mode On",}, - 0x20: {"name": "INVOFF", "desc": "Display Inversion Off",}, - 0x21: {"name": "INVON", "desc": "Display Inversion On",}, - 0x26: {"name": "GAMSET", "desc": "Gamma Set",}, - 0x28: {"name": "DISPOFF", "desc": "Display Off",}, - 0x29: {"name": "DISPON", "desc": "Display On",}, - 0x2A: {"name": "CASET", "desc": "Column Address Set",}, - 0x2B: {"name": "RASET", "desc": "Row Address Set",}, - 0x2C: {"name": "RAMWR", "desc": "Memory Write",}, - 0x2E: {"name": "RAMRD", "desc": "Memory Read",}, - 0x30: {"name": "PTLAR", "desc": "Partial Area",}, - 0x33: {"name": "VSCRDEF", "desc": "Vertical Scrolling Definition",}, - 0x34: {"name": "TEOFF", "desc": "Tearing Effect Line OFF",}, - 0x35: {"name": "TEON", "desc": "Tearing Effect Line On",}, - 0x36: {"name": "MADCTL", "desc": "Memory Data Access Control",}, - 0x37: {"name": "VSCSAD", "desc": "Vertical Scroll Start Address of RAM",}, - 0x38: {"name": "IDMOFF", "desc": "Idle Mode Off",}, - 0x39: {"name": "IDMON", "desc": "Idle mode on",}, - 0x3A: {"name": "COLMOD", "desc": "Interface Pixel Format",}, - 0x3C: {"name": "WRMEMC", "desc": "Write Memory Continue",}, - 0x3E: {"name": "RDMEMC", "desc": "Read Memory Continue",}, - 0x44: {"name": "STE", "desc": "Set Tear Scanline",}, - 0x45: {"name": "GSCAN", "desc": "Get Scanline",}, - 0x51: {"name": "WRDISBV", "desc": "Write Display Brightness",}, - 0x52: {"name": "RDDISBV", "desc": "Read Display Brightness Value",}, - 0x53: {"name": "WRCTRLD", "desc": "Write CTRL Display",}, - 0x54: {"name": "RDCTRLD", "desc": "Read CTRL Value Display",}, - 0x55: { - "name": "WRCACE", - "desc": "Write Content Adaptive Brightness Control and Color Enhancement", - }, - 0x56: {"name": "RDCABC", "desc": "Read Content Adaptive Brightness Control",}, - 0x5E: {"name": "WRCABCMB", "desc": "Write CABC Minimum Brightness",}, - 0x5F: {"name": "RDCABCMB", "desc": "Read CABC Minimum Brightness",}, - 0x68: { - "name": "RDABCSDR", - "desc": "Read Automatic Brightness Control Self-Diagnostic Result", - }, - 0xDA: {"name": "RDID1", "desc": "Read ID1",}, - 0xDB: {"name": "RDID2", "desc": "Read ID2",}, - 0xDC: {"name": "RDID3", "desc": "Read ID3",}, - 0xB0: {"name": "RAMCTRL", "desc": "RAM Control",}, - 0xB1: {"name": "RGBCTRL", "desc": "RGB Interface Control",}, - 0xB2: {"name": "PORCTRL", "desc": "Porch Setting",}, - 0xB3: { - "name": "FRCTRL1", - "desc": "Frame Rate Control 1 (In partial mode/ idle colors)", - }, - 0xB5: {"name": "PARCTRL", "desc": "Partial mode Control",}, - 0xB7: {"name": "GCTRL", "desc": "Gate Control",}, - 0xB8: {"name": "GTADJ", "desc": "Gate On Timing Adjustment",}, - 0xBA: {"name": "DGMEN", "desc": "Digital Gamma Enable",}, - 0xBB: {"name": "VCOMS", "desc": "VCOMS Setting",}, - 0xC0: {"name": "LCMCTRL", "desc": "LCM Control",}, - 0xC1: {"name": "IDSET", "desc": "ID Code Setting",}, - 0xC2: {"name": "VDVVRHEN", "desc": "VDV and VRH Command Enable",}, - 0xC3: {"name": "VRHS", "desc": "VRH Set",}, - 0xC4: {"name": "VDVS", "desc": "VDV Set",}, - 0xC5: {"name": "VCMOFSET", "desc": "VCOMS Offset Set",}, - 0xC6: {"name": "FRCTRL2", "desc": "Frame Rate Control in Normal Mode",}, - 0xC7: {"name": "CABCCTRL", "desc": "CABC Control",}, - 0xC8: {"name": "REGSEL1", "desc": "Register Value Selection 1",}, - 0xCA: {"name": "REGSEL2", "desc": "Register Value Selection 2",}, - 0xCC: {"name": "PWMFRSEL", "desc": "PWM Frequency Selection",}, - 0xD0: {"name": "PWCTRL1", "desc": "Power Control 1",}, - 0xD2: {"name": "VAPVANEN", "desc": "Enable VAP/VAN signal output",}, - 0xDF: {"name": "CMD2EN", "desc": "Command 2 Enable",}, - 0xE0: {"name": "PVGAMCTRL", "desc": "Positive Voltage Gamma Control",}, - 0xE1: {"name": "NVGAMCTRL", "desc": "Negative Voltage Gamma Control",}, - 0xE2: {"name": "DGMLUTR", "desc": "Digital Gamma Look-up Table for Red",}, - 0xE3: {"name": "DGMLUTB", "desc": "Digital Gamma Look-up Table for Blue",}, - 0xE4: {"name": "GATECTRL", "desc": "Gate Control",}, - 0xE7: {"name": "SPI2EN", "desc": "SPI2 Enable",}, - 0xE8: {"name": "PWCTRL2", "desc": "Power Control 2",}, - 0xE9: {"name": "EQCTRL", "desc": "Equalize time control",}, - 0xEC: {"name": "PROMCTRL", "desc": "Program Mode Control",}, - 0xFA: {"name": "PROMEN", "desc": "Program Mode Enable",}, - 0xFC: {"name": "NVMSET", "desc": "NVM Setting",}, - 0xFE: {"name": "PROMACT", "desc": "Program action",}, -} - - -def _get_annotation_index(annotations, name): - for index, annotation in enumerate(annotations): - if annotation[0] == name: - return index - raise RuntimeError(f"Unknown annotation {repr(name)}: {repr(annotations)}") - - -class Decoder(srd.Decoder): - api_version = 3 - id = "st7789" - name = "ST7789" - longname = "Sitronix ST7789" - desc = "Sitronix ST7789 TFT controller protocol." - license = "gplv2+" - inputs = ["logic"] - outputs = [] - channels = ( - {"id": "csx", "name": "CSX", "desc": "Chip selection signal"}, - {"id": "dcx", "name": "DCX", "desc": "Clock signal"}, - {"id": "sdo", "name": "SDO", "desc": "Serial output data"}, - {"id": "wrx", "name": "WRX", "desc": "Command / data"}, - ) - optional_channels = tuple() - tags = ["Display", "SPI"] - annotations = ( - ("bit", "Bit"), - ("command", "Command"), - ("data", "Data"), - ("cmd_data", "Command + Data"), - ("asserted", "Assertion"), - ) - - annotation_rows = ( - ("bits", "Bits", (_get_annotation_index(annotations, "bit"),)), - ( - "bytes", - "Bytes", - ( - _get_annotation_index(annotations, "command"), - _get_annotation_index(annotations, "data"), - ), - ), - ( - "cmd_data", - "Command + Data", - (_get_annotation_index(annotations, "cmd_data"),), - ), - ("asserted", "Assertion", (_get_annotation_index(annotations, "asserted"),)), - ) - - def _get_channel_index(self, name): - for index, channel in enumerate(self.channels): - if channel["name"] == name: - return index - raise RuntimeError("Implementation bug.") - - def __init__(self): - self.reset() - - def reset(self): - pass - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def _get_cmd_str(self, cmd): - if cmd in COMMAND_MAP: - return COMMAND_MAP[cmd]["name"] + "(%02X)" % cmd - else: - return "Unknown(%02X)" % cmd - - def _get_cmd_data_str(self, cmd, data_list): - cmd_str = self._get_cmd_str(cmd) - - if data_list: - ret_str = f"{cmd_str}: " - for v in data_list: - ret_str += " %02X" % v - return ret_str - else: - return cmd_str - - def decode(self): - last_cmd = None - last_cmd_data_sample_startnum = None - last_cmd_data_sample_endnum = None - last_cmd_data_list = [] - - while True: - self.wait({self._get_channel_index("CSX"): "f"}) - csx_start_samplenum = self.samplenum - - bit = None - bit_count = 0 - byte = 0 - byte_sample_startnum = None - - while True: - # FIXME {self._get_channel_index("DCX"): "r"} - (csx, dcx, sdo, wrx) = self.wait( - [ - {self._get_channel_index("CSX"): "r"}, - {self._get_channel_index("DCX"): "e"}, - ] - ) - if csx == 1: - self.put( - csx_start_samplenum, - self.samplenum, - self.out_ann, - [ - _get_annotation_index(self.annotations, "asserted"), - ["Asserted"], - ], - ) - - if last_cmd is not None: - self.put( - last_cmd_data_sample_startnum, - last_cmd_data_sample_endnum, - self.out_ann, - [ - _get_annotation_index(self.annotations, "cmd_data"), - [self._get_cmd_data_str(last_cmd, last_cmd_data_list)], - ], - ) - last_cmd = None - last_cmd_data_sample_startnum = None - last_cmd_data_sample_endnum = None - last_cmd_data_list = [] - - break - - if dcx == 1 and bit is None: - bit = sdo - bit_start_samplenum = self.samplenum - bit_count += 1 - byte = (byte << 1) | bit - if byte_sample_startnum is None: - byte_sample_startnum = self.samplenum - - if dcx == 0 and bit is not None: - self.put( - bit_start_samplenum, - self.samplenum, - self.out_ann, - [_get_annotation_index(self.annotations, "bit"), [str(bit)]], - ) - bit = None - if bit_count == 8: - if wrx: - last_cmd_data_sample_endnum = self.samplenum - last_cmd_data_list.append(byte) - self.put( - byte_sample_startnum, - self.samplenum, - self.out_ann, - [ - _get_annotation_index(self.annotations, "data"), - ["Data(%02X)" % byte], - ], - ) - else: - self.put( - byte_sample_startnum, - self.samplenum, - self.out_ann, - [ - _get_annotation_index(self.annotations, "command"), - [self._get_cmd_str(byte)], - ], - ) - - if last_cmd is not None: - self.put( - last_cmd_data_sample_startnum, - last_cmd_data_sample_endnum, - self.out_ann, - [ - _get_annotation_index( - self.annotations, "cmd_data" - ), - [ - self._get_cmd_data_str( - last_cmd, last_cmd_data_list - ) - ], - ], - ) - last_cmd_data_list = [] - - last_cmd = byte - last_cmd_data_sample_startnum = byte_sample_startnum - last_cmd_data_sample_endnum = self.samplenum - - byte = 0 - bit_count = 0 - byte_sample_startnum = None diff --git a/decoders/stepper_motor/__init__.py b/decoders/stepper_motor/__init__.py deleted file mode 100755 index 9126104f..00000000 --- a/decoders/stepper_motor/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Petteri Aimonen -## -## 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, see . -## - -''' -This PD decodes the stepper motor controller signals (step / dir) and -shows the step speed and absolute position of the stepper motor. -''' - -from .pd import Decoder diff --git a/decoders/stepper_motor/pd.py b/decoders/stepper_motor/pd.py deleted file mode 100755 index 2a7009a0..00000000 --- a/decoders/stepper_motor/pd.py +++ /dev/null @@ -1,95 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Petteri Aimonen -## -## 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, see . -## - -import sigrokdecode as srd - -class Decoder(srd.Decoder): - api_version = 3 - id = 'stepper_motor' - name = 'Stepper motor' - longname = 'Stepper motor position / speed' - desc = 'Absolute position and movement speed from step/dir.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Embedded/industrial'] - channels = ( - {'id': 'step', 'name': 'Step', 'desc': 'Step pulse'}, - {'id': 'dir', 'name': 'Direction', 'desc': 'Direction select'}, - ) - options = ( - {'id': 'unit', 'desc': 'Unit', 'default': 'steps', - 'values': ('steps', 'mm')}, - {'id': 'steps_per_mm', 'desc': 'Steps per mm', 'default': 100.0}, - ) - annotations = ( - ('speed', 'Speed'), - ('position', 'Position') - ) - annotation_rows = ( - ('speed', 'Speed', (0,)), - ('position', 'Position', (1,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.oldstep = None - self.ss_prev_step = None - self.pos = 0 - self.prev_speed = None - self.prev_pos = None - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - if self.options['unit'] == 'steps': - self.scale = 1 - self.format = '%0.0f' - self.unit = 'steps' - else: - self.scale = self.options['steps_per_mm'] - self.format = '%0.2f' - self.unit = 'mm' - - def step(self, ss, direction): - if self.ss_prev_step is not None: - if self.samplerate: - delta = ss - self.ss_prev_step - speed = self.samplerate / delta / self.scale - speed_txt = self.format % speed - self.put(self.ss_prev_step, ss, self.out_ann, - [0, [speed_txt + ' ' + self.unit + '/s', speed_txt]]) - pos_txt = self.format % (self.pos / self.scale) - self.put(self.ss_prev_step, ss, self.out_ann, - [1, [pos_txt + ' ' + self.unit, pos_txt]]) - - self.pos += (1 if direction else -1) - self.ss_prev_step = ss - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def decode(self): - while True: - (step, direction) = self.wait({0: 'r'}) - self.step(self.samplenum, direction) diff --git a/decoders/swd/__init__.py b/decoders/swd/__init__.py deleted file mode 100755 index a141239b..00000000 --- a/decoders/swd/__init__.py +++ /dev/null @@ -1,34 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Angus Gratton -## -## 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, see . -## - -''' -This PD decodes the ARM SWD (version 1) protocol, as described in the -"ARM Debug Interface v5.2" Architecture Specification. - -Not supported: - * Turnaround periods other than the default 1, as set in DLCR.TURNROUND - (should be trivial to add) - * SWD protocol version 2 (multi-drop support, etc.) - -Details: -http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ihi0031c/index.html -(Registration required) -''' - -from .pd import Decoder diff --git a/decoders/swd/pd.py b/decoders/swd/pd.py deleted file mode 100755 index 3f81e03d..00000000 --- a/decoders/swd/pd.py +++ /dev/null @@ -1,350 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Angus Gratton -## -## 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, see . -## - -import sigrokdecode as srd -import re - -''' -OUTPUT_PYTHON format: - -Packet: -[, ] - -: - - 'AP_READ' (AP read) - - 'DP_READ' (DP read) - - 'AP_WRITE' (AP write) - - 'DP_WRITE' (DP write) - - 'LINE_RESET' (line reset sequence) - -: - - tuple of address, ack state, data for the given sequence -''' - -swd_states = [ - 'IDLE', # Idle/unknown - 'REQUEST', # Request phase (first 8 bits) - 'ACK', # Ack phase (next 3 bits) - 'READ', # Reading phase (next 32 bits for reads) - 'WRITE', # Writing phase (next 32 bits for write) - 'DPARITY', # Data parity phase -] - -# Regexes for matching SWD data out of bitstring ('1' / '0' characters) format -RE_SWDSWITCH = re.compile(bin(0xE79E)[:1:-1] + '$') -RE_SWDREQ = re.compile(r'1(?P.)(?P.)(?P..)(?P.)01$') -RE_IDLE = re.compile('0' * 50 + '$') - -# Sample edges -RISING = 1 -FALLING = 0 - -ADDR_DP_SELECT = 0x8 -ADDR_DP_CTRLSTAT = 0x4 - -BIT_SELECT_CTRLSEL = 1 -BIT_CTRLSTAT_ORUNDETECT = 1 - -ANNOTATIONS = ['reset', 'enable', 'read', 'write', 'ack', 'data', 'parity'] - -class Decoder(srd.Decoder): - api_version = 3 - id = 'swd' - name = 'SWD' - longname = 'Serial Wire Debug' - desc = 'Two-wire protocol for debug access to ARM CPUs.' - license = 'gplv2+' - inputs = ['logic'] - outputs = ['swd'] - tags = ['Debug/trace'] - channels = ( - {'id': 'swclk', 'name': 'SWCLK', 'desc': 'Master clock'}, - {'id': 'swdio', 'name': 'SWDIO', 'desc': 'Data input/output'}, - ) - options = ( - {'id': 'strict_start', - 'desc': 'Wait for a line reset before starting to decode', - 'default': 'no', 'values': ('yes', 'no')}, - ) - annotations = ( - ('reset', 'RESET'), - ('enable', 'ENABLE'), - ('read', 'READ'), - ('write', 'WRITE'), - ('ack', 'ACK'), - ('data', 'DATA'), - ('parity', 'PARITY'), - ) - - def __init__(self): - self.reset() - - def reset(self): - # SWD data/clock state - self.state = 'UNKNOWN' - self.sample_edge = RISING - self.ack = None # Ack state of the current phase - self.ss_req = 0 # Start sample of current req - self.turnaround = 0 # Number of turnaround edges to ignore before continuing - self.bits = '' # Bits from SWDIO are accumulated here, matched against expected sequences - self.samplenums = [] # Sample numbers that correspond to the samples in self.bits - self.linereset_count = 0 - - # SWD debug port state - self.data = None - self.addr = None - self.rw = None # Are we inside an SWD read or a write? - self.ctrlsel = 0 # 'ctrlsel' is bit 0 in the SELECT register. - self.orundetect = 0 # 'orundetect' is bit 0 in the CTRLSTAT register. - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.out_python = self.register(srd.OUTPUT_PYTHON) - if self.options['strict_start'] == 'no': - self.state = 'REQ' # No need to wait for a LINE RESET. - - def putx(self, ann, length, data): - '''Output annotated data.''' - ann = ANNOTATIONS.index(ann) - try: - ss = self.samplenums[-length] - except IndexError: - ss = self.samplenums[0] - if self.state == 'REQ': - self.ss_req = ss - es = self.samplenum - self.put(ss, es, self.out_ann, [ann, [data]]) - - def putp(self, ptype, pdata): - self.put(self.ss_req, self.samplenum, self.out_python, [ptype, pdata]) - - def put_python_data(self): - '''Emit Python data item based on current SWD packet contents.''' - ptype = { - ('AP', 'R'): 'AP_READ', - ('AP', 'W'): 'AP_WRITE', - ('DP', 'R'): 'DP_READ', - ('DP', 'W'): 'DP_WRITE', - }[(self.apdp, self.rw)] - self.putp(ptype, (self.addr, self.data, self.ack)) - - def decode(self): - while True: - # Wait for any clock edge. - (clk, dio) = self.wait({0: 'e'}) - - # Count rising edges with DIO held high, - # as a line reset (50+ high edges) can happen from any state. - if clk == RISING: - if dio == 1: - self.linereset_count += 1 - else: - if self.linereset_count >= 50: - self.putx('reset', self.linereset_count, 'LINERESET') - self.putp('LINE_RESET', None) - self.reset_state() - self.linereset_count = 0 - - # Otherwise, we only care about either rising or falling edges - # (depending on sample_edge, set according to current state). - if clk != self.sample_edge: - continue - - # Turnaround bits get skipped. - if self.turnaround > 0: - self.turnaround -= 1 - continue - - self.bits += str(dio) - self.samplenums.append(self.samplenum) - { - 'UNKNOWN': self.handle_unknown_edge, - 'REQ': self.handle_req_edge, - 'ACK': self.handle_ack_edge, - 'DATA': self.handle_data_edge, - 'DPARITY': self.handle_dparity_edge, - }[self.state]() - - def next_state(self): - '''Step to the next SWD state, reset internal counters accordingly.''' - self.bits = '' - self.samplenums = [] - self.linereset_count = 0 - if self.state == 'UNKNOWN': - self.state = 'REQ' - self.sample_edge = RISING - self.turnaround = 0 - elif self.state == 'REQ': - self.state = 'ACK' - self.sample_edge = FALLING - self.turnaround = 1 - elif self.state == 'ACK': - self.state = 'DATA' - self.sample_edge = RISING if self.rw == 'W' else FALLING - self.turnaround = 0 if self.rw == 'R' else 2 - elif self.state == 'DATA': - self.state = 'DPARITY' - elif self.state == 'DPARITY': - #self.put_python_data() - self.state = 'REQ' - self.sample_edge = RISING - self.turnaround = 1 if self.rw == 'R' else 0 - - def reset_state(self): - '''Line reset (or equivalent), wait for a new pending SWD request.''' - #if self.state != 'REQ': # Emit a Python data item. - # self.put_python_data() - # Clear state. - self.bits = '' - self.samplenums = [] - self.linereset_count = 0 - self.turnaround = 0 - self.sample_edge = RISING - self.data = '' - self.ack = None - self.state = 'REQ' - - def handle_unknown_edge(self): - ''' - Clock edge in the UNKNOWN state. - In the unknown state, clock edges get ignored until we see a line - reset (which is detected in the decode method, not here.) - ''' - pass - - def handle_req_edge(self): - '''Clock edge in the REQ state (waiting for SWD r/w request).''' - # Check for a JTAG->SWD enable sequence. - m = re.search(RE_SWDSWITCH, self.bits) - if m is not None: - self.putx('enable', 16, 'JTAG->SWD') - self.reset_state() - return - - # Or a valid SWD Request packet. - m = re.search(RE_SWDREQ, self.bits) - if m is not None: - calc_parity = sum([int(x) for x in m.group('rw') + m.group('apdp') + m.group('addr')]) % 2 - parity = '' if str(calc_parity) == m.group('parity') else 'E' - self.rw = 'R' if m.group('rw') == '1' else 'W' - self.apdp = 'AP' if m.group('apdp') == '1' else 'DP' - self.addr = int(m.group('addr')[::-1], 2) << 2 - self.putx('read' if self.rw == 'R' else 'write', 8, self.get_address_description()) - self.next_state() - return - - def handle_ack_edge(self): - '''Clock edge in the ACK state (waiting for complete ACK sequence).''' - if len(self.bits) < 3: - return - if self.bits == '100': - self.putx('ack', 3, 'OK') - self.ack = 'OK' - self.next_state() - elif self.bits == '001': - self.putx('ack', 3, 'FAULT') - self.ack = 'FAULT' - if self.orundetect == 1: - self.next_state() - else: - self.reset_state() - self.turnaround = 1 - elif self.bits == '010': - self.putx('ack', 3, 'WAIT') - self.ack = 'WAIT' - if self.orundetect == 1: - self.next_state() - else: - self.reset_state() - self.turnaround = 1 - elif self.bits == '111': - self.putx('ack', 3, 'NOREPLY') - self.ack = 'NOREPLY' - self.reset_state() - else: - self.putx('ack', 3, 'ERROR') - self.ack = 'ERROR' - self.reset_state() - - def handle_data_edge(self): - '''Clock edge in the DATA state (waiting for 32 bits to clock past).''' - if len(self.bits) < 32: - return - self.data = 0 - self.dparity = 0 - for x in range(32): - if self.bits[x] == '1': - self.data += (1 << x) - self.dparity += 1 - self.dparity = self.dparity % 2 - - self.putx('data', 32, '0x%08x' % self.data) - self.next_state() - - def handle_dparity_edge(self): - '''Clock edge in the DPARITY state (clocking in parity bit).''' - if str(self.dparity) != self.bits: - self.putx('parity', 1, str(self.dparity) + self.bits) # PARITY ERROR - elif self.rw == 'W': - self.handle_completed_write() - self.next_state() - - def handle_completed_write(self): - ''' - Update internal state of the debug port based on a completed - write operation. - ''' - if self.apdp != 'DP': - return - elif self.addr == ADDR_DP_SELECT: - self.ctrlsel = self.data & BIT_SELECT_CTRLSEL - elif self.addr == ADDR_DP_CTRLSTAT and self.ctrlsel == 0: - self.orundetect = self.data & BIT_CTRLSTAT_ORUNDETECT - - def get_address_description(self): - ''' - Return a human-readable description of the currently selected address, - for annotated results. - ''' - if self.apdp == 'DP': - if self.rw == 'R': - # Tables 2-4 & 2-5 in ADIv5.2 spec ARM document IHI 0031C - return { - 0: 'IDCODE', - 0x4: 'R CTRL/STAT' if self.ctrlsel == 0 else 'R DLCR', - 0x8: 'RESEND', - 0xC: 'RDBUFF' - }[self.addr] - elif self.rw == 'W': - # Tables 2-4 & 2-5 in ADIv5.2 spec ARM document IHI 0031C - return { - 0: 'W ABORT', - 0x4: 'W CTRL/STAT' if self.ctrlsel == 0 else 'W DLCR', - 0x8: 'W SELECT', - 0xC: 'W RESERVED' - }[self.addr] - elif self.apdp == 'AP': - if self.rw == 'R': - return 'R AP%x' % self.addr - elif self.rw == 'W': - return 'W AP%x' % self.addr - - # Any legitimate operations shouldn't fall through to here, probably - # a decoder bug. - return '? %s%s%x' % (self.rw, self.apdp, self.addr) diff --git a/decoders/swim/__init__.py b/decoders/swim/__init__.py deleted file mode 100755 index cd18b857..00000000 --- a/decoders/swim/__init__.py +++ /dev/null @@ -1,29 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Mike Jagdis -## -## 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 -## - -''' -SWIM is a single wire interface for STM8 series 8-bit microcontrollers -that allows non-intrusive read/wite access to be performed on-the-fly -to the memory and registers of the MCU for debug and flashing purposes. - -See the STMicroelectronics document UM0470 for details. -''' - -from .pd import Decoder diff --git a/decoders/swim/pd.py b/decoders/swim/pd.py deleted file mode 100755 index 8c12ea7b..00000000 --- a/decoders/swim/pd.py +++ /dev/null @@ -1,304 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Mike Jagdis -## -## 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 -## - -import math -import sigrokdecode as srd - -class SamplerateError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = 'swim' - name = 'SWIM' - longname = 'STM8 SWIM bus' - desc = 'STM8 Single Wire Interface Module (SWIM) protocol.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Debug/trace'] - options = ( - {'id': 'debug', 'desc': 'Debug', 'default': 'no', 'values': ('yes', 'no') }, - ) - channels = ( - {'id': 'swim', 'name': 'SWIM', 'desc': 'SWIM data line'}, - ) - annotations = ( - ('bit', 'Bit'), - ('enterseq', 'SWIM enter sequence'), - ('start-host', 'Start bit (host)'), - ('start-target', 'Start bit (target)'), - ('parity', 'Parity bit'), - ('ack', 'Acknowledgement'), - ('nack', 'Negative acknowledgement'), - ('byte-write', 'Byte write'), - ('byte-read', 'Byte read'), - ('cmd-unknown', 'Unknown SWIM command'), - ('cmd', 'SWIM command'), - ('bytes', 'Byte count'), - ('address', 'Address'), - ('data-write', 'Data write'), - ('data-read', 'Data read'), - ('debug', 'Debug'), - ) - annotation_rows = ( - ('bits', 'Bits', (0,)), - ('framing', 'Framing', (2, 3, 4, 5, 6, 7, 8)), - ('protocol', 'Protocol', (1, 9, 10, 11, 12, 13, 14)), - ('debug', 'Debug', (15,)), - ) - binary = ( - ('tx', 'Dump of data written to target'), - ('rx', 'Dump of data read from target'), - ) - - def __init__(self): - # SWIM clock for the target is normally HSI/2 where HSI is 8MHz +- 5% - # although the divisor can be removed by setting the SWIMCLK bit in - # the CLK_SWIMCCR register. There is no standard for the host so we - # will be generous and assume it is using an 8MHz +- 10% oscillator. - # We do not need to be accurate. We just need to avoid treating enter - # sequence pulses as bits. A synchronization frame will cause this - # to be adjusted. - self.HSI = 8000000 - self.HSI_min = self.HSI * 0.9 - self.HSI_max = self.HSI * 1.1 - self.swim_clock = self.HSI_min / 2 - - self.eseq_edge = [[-1, None], [-1, None]] - self.eseq_pairnum = 0 - self.eseq_pairstart = None - - self.reset() - - def reset(self): - self.bit_edge = [[-1, None], [-1, None]] - self.bit_maxlen = -1 - self.bitseq_len = 0 - self.bitseq_end = None - self.proto_state = 'CMD' - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def adjust_timings(self): - # A low-speed bit is 22 SWIM clocks long. - # There are options to shorten bits to 10 clocks or use HSI rather - # than HSI/2 as the SWIM clock but the longest valid bit should be no - # more than this many samples. This does not need to be accurate. - # It exists simply to prevent bits extending unecessarily far into - # trailing bus-idle periods. This will be adjusted every time we see - # a synchronization frame or start bit in order to show idle periods - # as accurately as possible. - self.bit_reflen = math.ceil(self.samplerate * 22 / self.swim_clock) - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.out_binary = self.register(srd.OUTPUT_BINARY) - - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - - # A synchronization frame is a low that lasts for more than 64 but no - # more than 128 SWIM clock periods based on the standard SWIM clock. - # Note: we also allow for the possibility that the SWIM clock divisor - # has been disabled here. - self.sync_reflen_min = math.floor(self.samplerate * 64 / self.HSI_max) - self.sync_reflen_max = math.ceil(self.samplerate * 128 / (self.HSI_min / 2)) - - self.debug = True if self.options['debug'] == 'yes' else False - - # The SWIM entry sequence is 4 pulses at 2kHz followed by 4 at 1kHz. - self.eseq_reflen = math.ceil(self.samplerate / 2048) - - self.adjust_timings() - - def protocol(self): - if self.proto_state == 'CMD': - # Command - if self.bitseq_value == 0x00: - self.put(self.bitseq_start, self.bitseq_end, self.out_ann, [10, ['system reset', 'SRST', '!']]) - elif self.bitseq_value == 0x01: - self.proto_state = 'N' - self.put(self.bitseq_start, self.bitseq_end, self.out_ann, [10, ['read on-the-fly', 'ROTF', 'r']]) - elif self.bitseq_value == 0x02: - self.proto_state = 'N' - self.put(self.bitseq_start, self.bitseq_end, self.out_ann, [10, ['write on-the-fly', 'WOTF', 'w']]) - else: - self.put(self.bitseq_start, self.bitseq_end, self.out_ann, [9, ['unknown', 'UNK']]) - elif self.proto_state == 'N': - # Number of bytes - self.proto_byte_count = self.bitseq_value - self.proto_state = '@E' - self.put(self.bitseq_start, self.bitseq_end, self.out_ann, [11, ['byte count 0x%02x' % self.bitseq_value, 'bytes 0x%02x' % self.bitseq_value, '0x%02x' % self.bitseq_value, '%02x' % self.bitseq_value, '%x' % self.bitseq_value]]) - elif self.proto_state == '@E': - # Address byte 1 - self.proto_addr = self.bitseq_value - self.proto_addr_start = self.bitseq_start - self.proto_state = '@H' - elif self.proto_state == '@H': - # Address byte 2 - self.proto_addr = (self.proto_addr << 8) | self.bitseq_value - self.proto_state = '@L' - elif self.proto_state == '@L': - # Address byte 3 - self.proto_addr = (self.proto_addr << 8) | self.bitseq_value - self.proto_state = 'D' - self.put(self.proto_addr_start, self.bitseq_end, self.out_ann, [12, ['address 0x%06x' % self.proto_addr, 'addr 0x%06x' % self.proto_addr, '0x%06x' % self.proto_addr, '%06x' %self.proto_addr, '%x' % self.proto_addr]]) - else: - if self.proto_byte_count > 0: - self.proto_byte_count -= 1 - if self.proto_byte_count == 0: - self.proto_state = 'CMD' - - self.put(self.bitseq_start, self.bitseq_end, self.out_ann, [13 + self.bitseq_dir, ['0x%02x' % self.bitseq_value, '%02x' % self.bitseq_value, '%x' % self.bitseq_value]]) - self.put(self.bitseq_start, self.bitseq_end, self.out_binary, [0 + self.bitseq_dir, bytes([self.bitseq_value])]) - if self.debug: - self.put(self.bitseq_start, self.bitseq_end, self.out_ann, [15, ['%d more' % self.proto_byte_count, '%d' % self.proto_byte_count]]) - - def bitseq(self, bitstart, bitend, bit): - if self.bitseq_len == 0: - # Looking for start of a bit sequence (command or byte). - self.bit_reflen = bitend - bitstart - self.bitseq_value = 0 - self.bitseq_dir = bit - self.bitseq_len = 1 - self.put(bitstart, bitend, self.out_ann, [2 + self.bitseq_dir, ['start', 's']]) - elif (self.proto_state == 'CMD' and self.bitseq_len == 4) or (self.proto_state != 'CMD' and self.bitseq_len == 9): - # Parity bit - self.bitseq_end = bitstart - self.bitseq_len += 1 - - self.put(bitstart, bitend, self.out_ann, [4, ['parity', 'par', 'p']]) - - # The start bit is not data but was used for parity calculation. - self.bitseq_value &= 0xff - self.put(self.bitseq_start, self.bitseq_end, self.out_ann, [7 + self.bitseq_dir, ['0x%02x' % self.bitseq_value, '%02x' % self.bitseq_value, '%x' % self.bitseq_value]]) - elif (self.proto_state == 'CMD' and self.bitseq_len == 5) or (self.proto_state != 'CMD' and self.bitseq_len == 10): - # ACK/NACK bit. - if bit: - self.put(bitstart, bitend, self.out_ann, [5, ['ack', 'a']]) - else: - self.put(bitstart, bitend, self.out_ann, [6, ['nack', 'n']]) - - # We only pass data that was ack'd up the stack. - if bit: - self.protocol() - - self.bitseq_len = 0 - else: - if self.bitseq_len == 1: - self.bitseq_start = bitstart - self.bitseq_value = (self.bitseq_value << 1) | bit - self.bitseq_len += 1 - - def bit(self, start, mid, end): - if mid - start >= end - mid: - self.put(start, end, self.out_ann, [0, ['0']]) - bit = 0 - else: - self.put(start, end, self.out_ann, [0, ['1']]) - bit = 1 - - self.bitseq(start, end, bit) - - def detect_synchronize_frame(self, start, end): - # Strictly speaking, synchronization frames are only recognised when - # SWIM is active. A falling edge on reset disables SWIM and an enter - # sequence is needed to re-enable it. However we do not want to be - # reliant on seeing the NRST pin just for that and we also want to be - # able to decode SWIM even if we just sample parts of the dialogue. - # For this reason we limit ourselves to only recognizing - # synchronization frames that have believable lengths based on our - # knowledge of the range of possible SWIM clocks. - if self.samplenum - self.eseq_edge[1][1] >= self.sync_reflen_min and self.samplenum - self.eseq_edge[1][1] <= self.sync_reflen_max: - self.put(self.eseq_edge[1][1], self.samplenum, self.out_ann, [1, ['synchronization frame', 'synchronization', 'sync', 's']]) - - # A low that lasts for more than 64 SWIM clock periods causes a - # reset of the SWIM communication state machine and will switch - # the SWIM to low-speed mode (SWIM_CSR.HS is cleared). - self.reset() - - # The low SHOULD last 128 SWIM clocks. This is used to - # resynchronize in order to allow for variation in the frequency - # of the internal RC oscillator. - self.swim_clock = 128 * (self.samplerate / (self.samplenum - self.eseq_edge[1][1])) - self.adjust_timings() - - def eseq_potential_start(self, start, end): - self.eseq_pairstart = start - self.eseq_reflen = end - start - self.eseq_pairnum = 1 - - def detect_enter_sequence(self, start, end): - # According to the spec the enter sequence is four pulses at 2kHz - # followed by four at 1kHz. We do not check the frequency but simply - # check the lengths of successive pulses against the first. This means - # we have no need to account for the accuracy (or lack of) of the - # host's oscillator. - if self.eseq_pairnum == 0 or abs(self.eseq_reflen - (end - start)) > 2: - self.eseq_potential_start(start, end) - - elif self.eseq_pairnum < 4: - # The next three pulses should be the same length as the first. - self.eseq_pairnum += 1 - - if self.eseq_pairnum == 4: - self.eseq_reflen /= 2 - else: - # The final four pulses should each be half the length of the - # initial pair. Again, a mismatch causes us to reset and use the - # current pulse as a new potential enter sequence start. - self.eseq_pairnum += 1 - if self.eseq_pairnum == 8: - # Four matching pulses followed by four more that match each - # other but are half the length of the first 4. SWIM is active! - self.put(self.eseq_pairstart, end, self.out_ann, [1, ['enter sequence', 'enter seq', 'enter', 'ent', 'e']]) - self.eseq_pairnum = 0 - - def decode(self): - while True: - if self.bit_maxlen >= 0: - (swim,) = self.wait() - self.bit_maxlen -= 1 - else: - (swim,) = self.wait({0: 'e'}) - - if swim != self.eseq_edge[1][0]: - if swim == 1 and self.eseq_edge[1][1] is not None: - self.detect_synchronize_frame(self.eseq_edge[1][1], self.samplenum) - if self.eseq_edge[0][1] is not None: - self.detect_enter_sequence(self.eseq_edge[0][1], self.samplenum) - self.eseq_edge.pop(0) - self.eseq_edge.append([swim, self.samplenum]) - - if (swim != self.bit_edge[1][0] and (swim != 1 or self.bit_edge[1][0] != -1)) or self.bit_maxlen == 0: - if self.bit_maxlen == 0 and self.bit_edge[1][0] == 1: - swim = -1 - - if self.bit_edge[1][0] != 0 and swim == 0: - self.bit_maxlen = self.bit_reflen - - if self.bit_edge[0][0] == 0 and self.bit_edge[1][0] == 1 and self.samplenum - self.bit_edge[0][1] <= self.bit_reflen + 10: - self.bit(self.bit_edge[0][1], self.bit_edge[1][1], self.samplenum) - - self.bit_edge.pop(0) - self.bit_edge.append([swim, self.samplenum]) diff --git a/decoders/t55xx/__init__.py b/decoders/t55xx/__init__.py deleted file mode 100755 index 01184350..00000000 --- a/decoders/t55xx/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Benjamin Larsson -## -## 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, see . -## - -''' -T55xx is a 100-150kHz RFID protocol according to the Atmel e555x -downlink/write protocol (pulse interval coding). -''' - -from .pd import Decoder diff --git a/decoders/t55xx/pd.py b/decoders/t55xx/pd.py deleted file mode 100755 index d345d318..00000000 --- a/decoders/t55xx/pd.py +++ /dev/null @@ -1,326 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Benjamin Larsson -## -## 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, see . -## - -import sigrokdecode as srd - -class SamplerateError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = 't55xx' - name = 'T55xx' - longname = 'RFID T55xx' - desc = 'T55xx 100-150kHz RFID protocol.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['IC', 'RFID'] - channels = ( - {'id': 'data', 'name': 'Data', 'desc': 'Data line'}, - ) - options = ( - {'id': 'coilfreq', 'desc': 'Coil frequency', 'default': 125000}, - {'id': 'start_gap', 'desc': 'Start gap min', 'default': 20}, - {'id': 'w_gap', 'desc': 'Write gap min', 'default': 20}, - {'id': 'w_one_min', 'desc': 'Write one min', 'default': 48}, - {'id': 'w_one_max', 'desc': 'Write one max', 'default': 63}, - {'id': 'w_zero_min', 'desc': 'Write zero min', 'default': 16}, - {'id': 'w_zero_max', 'desc': 'Write zero max', 'default': 31}, - {'id': 'em4100_decode', 'desc': 'EM4100 decode', 'default': 'on', - 'values': ('on', 'off')}, - ) - annotations = ( - ('bit_value', 'Bit value'), - ('start_gap', 'Start gap'), - ('write_gap', 'Write gap'), - ('write_mode_exit', 'Write mode exit'), - ('bit', 'Bit'), - ('opcode', 'Opcode'), - ('lock', 'Lock'), - ('data', 'Data'), - ('password', 'Password'), - ('address', 'Address'), - ('bitrate', 'Bitrate'), - ) - annotation_rows = ( - ('bits', 'Bits', (0,)), - ('structure', 'Structure', (1, 2, 3, 4)), - ('fields', 'Fields', (5, 6, 7, 8, 9)), - ('decode', 'Decode', (10,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.last_samplenum = None - self.lastlast_samplenum = None - self.state = 'START_GAP' - self.bits_pos = [[0 for col in range(3)] for row in range(70)] - self.br_string = ['RF/8', 'RF/16', 'RF/32', 'RF/40', - 'RF/50', 'RF/64', 'RF/100', 'RF/128'] - self.mod_str1 = ['Direct', 'Manchester', 'Biphase', 'Reserved'] - self.mod_str2 = ['Direct', 'PSK1', 'PSK2', 'PSK3', 'FSK1', 'FSK2', - 'FSK1a', 'FSK2a'] - self.pskcf_str = ['RF/2', 'RF/4', 'RF/8', 'Reserved'] - self.em4100_decode1_partial = 0 - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - self.field_clock = self.samplerate / self.options['coilfreq'] - self.wzmax = self.options['w_zero_max'] * self.field_clock - self.wzmin = self.options['w_zero_min'] * self.field_clock - self.womax = self.options['w_one_max'] * self.field_clock - self.womin = self.options['w_one_min'] * self.field_clock - self.startgap = self.options['start_gap'] * self.field_clock - self.writegap = self.options['w_gap'] * self.field_clock - self.nogap = 64 * self.field_clock - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def decode_config(self, idx): - safer_key = self.bits_pos[idx][0]<<3 | self.bits_pos[idx+1][0]<<2 | \ - self.bits_pos[idx+2][0]<<1 | self.bits_pos[idx+3][0] - self.put(self.bits_pos[idx][1], self.bits_pos[idx+3][2], self.out_ann, - [10, ['Safer Key' + ': %X' % safer_key,'%X' % safer_key]]) - bitrate = self.bits_pos[idx+11][0]<<2 | self.bits_pos[idx+12][0]<<1 | \ - self.bits_pos[idx+13][0] - self.put(self.bits_pos[idx+11][1], self.bits_pos[idx+13][2], - self.out_ann, [10, ['Data Bit Rate: ' + \ - self.br_string[bitrate], self.br_string[bitrate]]]) - modulation1 = self.bits_pos[idx+15][0]<<1 | self.bits_pos[idx+16][0] - modulation2 = self.bits_pos[idx+17][0]<<2 | \ - self.bits_pos[idx+18][0]<<1 | self.bits_pos[idx+19][0] - if modulation1 == 0: - mod_string = self.mod_str2[modulation2] - else: - mod_string = self.mod_str1[modulation1] - self.put(self.bits_pos[idx+15][1], self.bits_pos[idx+19][2], - self.out_ann, [10, ['Modulation: ' + mod_string, mod_string]]) - psk_cf = self.bits_pos[idx+20][0]<<1 | self.bits_pos[idx+21][0] - self.put(self.bits_pos[idx+20][1], self.bits_pos[idx+21][2], - self.out_ann, [10, ['PSK-CF: ' + self.pskcf_str[psk_cf], - self.pskcf_str[psk_cf]]]) - self.put(self.bits_pos[idx+22][1], self.bits_pos[idx+22][2], - self.out_ann, [10, ['AOR' + ': %d' % \ - (self.bits_pos[idx+22][0]),'%d' % (self.bits_pos[idx+22][0])]]) - maxblock = self.bits_pos[idx+24][0]<<2 | self.bits_pos[idx+25][0]<<1 | \ - self.bits_pos[idx+26][0] - self.put(self.bits_pos[idx+24][1], self.bits_pos[idx+26][2], - self.out_ann, [10, ['Max-Block' + ': %d' % maxblock, - '%d' % maxblock]]) - self.put(self.bits_pos[idx+27][1], self.bits_pos[idx+27][2], - self.out_ann, [10, ['PWD' + ': %d' % \ - (self.bits_pos[idx+27][0]),'%d' % (self.bits_pos[idx+27][0])]]) - self.put(self.bits_pos[idx+28][1], self.bits_pos[idx+28][2], - self.out_ann, [10, ['ST-sequence terminator' + ': %d' % \ - (self.bits_pos[idx+28][0]),'%d' % (self.bits_pos[idx+28][0])]]) - self.put(self.bits_pos[idx+31][1], self.bits_pos[idx+31][2], - self.out_ann, [10, ['POR delay' + ': %d' % \ - (self.bits_pos[idx+31][0]),'%d' % (self.bits_pos[idx+31][0])]]) - - def put4bits(self, idx): - bits = self.bits_pos[idx][0]<<3 | self.bits_pos[idx+1][0]<<2 | \ - self.bits_pos[idx+2][0]<<1 | self.bits_pos[idx+3][0] - self.put(self.bits_pos[idx][1], self.bits_pos[idx+3][2], self.out_ann, - [10, ['%X' % bits]]) - - def em4100_decode1(self, idx): - self.put(self.bits_pos[idx][1], self.bits_pos[idx+8][2], self.out_ann, - [10, ['EM4100 header', 'EM header', 'Header', 'H']]) - self.put4bits(idx+9) - self.put4bits(idx+14) - self.put4bits(idx+19) - self.put4bits(idx+24) - self.em4100_decode1_partial = self.bits_pos[idx+29][0]<<3 | \ - self.bits_pos[idx+30][0]<<2 | self.bits_pos[idx+31][0]<<1 - self.put(self.bits_pos[idx+29][1], self.bits_pos[idx+31][2], - self.out_ann, [10, ['Partial nibble']]) - - def em4100_decode2(self, idx): - if self.em4100_decode1_partial != 0: - bits = self.em4100_decode1_partial + self.bits_pos[idx][0] - self.put(self.bits_pos[idx][1], self.bits_pos[idx][2], - self.out_ann, [10, ['%X' % bits]]) - self.em4100_decode1_partial = 0 - else: - self.put(self.bits_pos[idx][1], self.bits_pos[idx][2], - self.out_ann, [10, ['Partial nibble']]) - - self.put4bits(idx+2) - self.put4bits(idx+7) - self.put4bits(idx+12) - self.put4bits(idx+17) - self.put4bits(idx+22) - self.put(self.bits_pos[idx+27][1], self.bits_pos[idx+31][2], - self.out_ann, [10, ['EM4100 trailer']]) - - def get_32_bits(self, idx): - retval = 0 - for i in range(0, 32): - retval <<= 1 - retval |= self.bits_pos[i+idx][0] - return retval - - def get_3_bits(self, idx): - retval = self.bits_pos[idx][0]<<2 | self.bits_pos[idx+1][0]<<1 | \ - self.bits_pos[idx+2][0] - return retval - - def put_fields(self): - if (self.bit_nr == 70): - self.put(self.bits_pos[0][1], self.bits_pos[1][2], self.out_ann, - [5, ['Opcode' + ': %d%d' % (self.bits_pos[0][0], - self.bits_pos[1][0]), '%d%d' % (self.bits_pos[0][0], - self.bits_pos[1][0])]]) - password = self.get_32_bits(2) - self.put(self.bits_pos[2][1], self.bits_pos[33][2], self.out_ann, - [8, ['Password' + ': %X' % password, '%X' % password]]) - self.put(self.bits_pos[34][1], self.bits_pos[34][2], self.out_ann, - [6, ['Lock' + ': %X' % self.bits_pos[34][0], - '%X' % self.bits_pos[34][0]]]) - data = self.get_32_bits(35) - self.put(self.bits_pos[35][1], self.bits_pos[66][2], self.out_ann, - [7, ['Data' + ': %X' % data, '%X' % data]]) - addr = self.get_3_bits(67) - self.put(self.bits_pos[67][1], self.bits_pos[69][2], self.out_ann, - [9, ['Addr' + ': %X' % addr, '%X' % addr]]) - if addr == 0: - self.decode_config(35) - if addr == 7: - self.put(self.bits_pos[35][1], self.bits_pos[66][2], - self.out_ann, [10, ['Password' + ': %X' % data, - '%X' % data]]) - # If we are programming EM4100 data we can decode it halfway. - if addr == 1 and self.options['em4100_decode'] == 'on': - self.em4100_decode1(35) - if addr == 2 and self.options['em4100_decode'] == 'on': - self.em4100_decode2(35) - - if (self.bit_nr == 38): - self.put(self.bits_pos[0][1], self.bits_pos[1][2], self.out_ann, - [5, ['Opcode' + ': %d%d' % (self.bits_pos[0][0], - self.bits_pos[1][0]), '%d%d' % (self.bits_pos[0][0], - self.bits_pos[1][0])]]) - self.put(self.bits_pos[2][1], self.bits_pos[2][2], self.out_ann, - [6, ['Lock' + ': %X' % self.bits_pos[2][0], - '%X' % self.bits_pos[2][0]]]) - data = self.get_32_bits(3) - self.put(self.bits_pos[3][1], self.bits_pos[34][2], self.out_ann, - [7, ['Data' + ': %X' % data, '%X' % data]]) - addr = self.get_3_bits(35) - self.put(self.bits_pos[35][1], self.bits_pos[37][2], self.out_ann, - [9, ['Addr' + ': %X' % addr, '%X' % addr]]) - if addr == 0: - self.decode_config(3) - if addr == 7: - self.put(self.bits_pos[3][1], self.bits_pos[34][2], - self.out_ann, [10, ['Password' + ': %X' % data, - '%X' % data]]) - # If we are programming EM4100 data we can decode it halfway. - if addr == 1 and self.options['em4100_decode'] == 'on': - self.em4100_decode1(3) - if addr == 2 and self.options['em4100_decode'] == 'on': - self.em4100_decode2(3) - - if (self.bit_nr == 2): - self.put(self.bits_pos[0][1], self.bits_pos[1][2], self.out_ann, - [5, ['Opcode' + ': %d%d' % (self.bits_pos[0][0], - self.bits_pos[1][0]), '%d%d' % (self.bits_pos[0][0], - self.bits_pos[1][0])]]) - self.bit_nr = 0 - - def add_bits_pos(self, bit, bit_start, bit_end): - if self.bit_nr < 70: - self.bits_pos[self.bit_nr][0] = bit - self.bits_pos[self.bit_nr][1] = bit_start - self.bits_pos[self.bit_nr][2] = bit_end - self.bit_nr += 1 - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - - self.last_samplenum = 0 - self.lastlast_samplenum = 0 - self.last_edge = 0 - self.oldpl = 0 - self.oldpp = 0 - self.oldsamplenum = 0 - self.last_bit_pos = 0 - self.old_gap_start = 0 - self.old_gap_end = 0 - self.gap_detected = 0 - self.bit_nr = 0 - - while True: - (pin,) = self.wait({0: 'e'}) - - pl = self.samplenum - self.oldsamplenum - pp = pin - samples = self.samplenum - self.last_samplenum - - if self.state == 'WRITE_GAP': - if pl > self.writegap: - self.gap_detected = 1 - self.put(self.last_samplenum, self.samplenum, - self.out_ann, [2, ['Write gap']]) - if (self.last_samplenum-self.old_gap_end) > self.nogap: - self.gap_detected = 0 - self.state = 'START_GAP' - self.put(self.old_gap_end, self.last_samplenum, - self.out_ann, [3, ['Write mode exit']]) - self.put_fields() - - if self.state == 'START_GAP': - if pl > self.startgap: - self.gap_detected = 1 - self.put(self.last_samplenum, self.samplenum, - self.out_ann, [1, ['Start gap']]) - self.state = 'WRITE_GAP' - - if self.gap_detected == 1: - self.gap_detected = 0 - if (self.last_samplenum - self.old_gap_end) > self.wzmin \ - and (self.last_samplenum - self.old_gap_end) < self.wzmax: - self.put(self.old_gap_end, self.last_samplenum, - self.out_ann, [0, ['0']]) - self.put(self.old_gap_end, self.last_samplenum, - self.out_ann, [4, ['Bit']]) - self.add_bits_pos(0, self.old_gap_end, - self.last_samplenum) - if (self.last_samplenum - self.old_gap_end) > self.womin \ - and (self.last_samplenum - self.old_gap_end) < self.womax: - self.put(self.old_gap_end, self.last_samplenum, - self.out_ann, [0, ['1']]) - self.put(self.old_gap_end, self.last_samplenum, - self.out_ann, [4, ['Bit']]) - self.add_bits_pos(1, self.old_gap_end, self.last_samplenum) - - self.old_gap_start = self.last_samplenum - self.old_gap_end = self.samplenum - - self.oldpl = pl - self.oldpp = pp - self.oldsamplenum = self.samplenum - self.last_samplenum = self.samplenum diff --git a/decoders/tca6408a/__init__.py b/decoders/tca6408a/__init__.py deleted file mode 100755 index 5373c311..00000000 --- a/decoders/tca6408a/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 alberink -## -## 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, see . -## - -''' -This decoder stacks on top of the 'i2c' PD and decodes the Texas Instruments -TCA6408A 8-bit I²C I/O expander protocol. -''' - -from .pd import Decoder diff --git a/decoders/tca6408a/pd.py b/decoders/tca6408a/pd.py deleted file mode 100755 index 49245174..00000000 --- a/decoders/tca6408a/pd.py +++ /dev/null @@ -1,132 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## Copyright (C) 2013 Matt Ranostay -## Copyright (C) 2014 alberink -## -## 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, see . -## - -import sigrokdecode as srd - -class Decoder(srd.Decoder): - api_version = 3 - id = 'tca6408a' - name = 'TI TCA6408A' - longname = 'Texas Instruments TCA6408A' - desc = 'Texas Instruments TCA6408A 8-bit I²C I/O expander.' - license = 'gplv2+' - inputs = ['i2c'] - outputs = [] - tags = ['Embedded/industrial', 'IC'] - annotations = ( - ('register', 'Register type'), - ('value', 'Register value'), - ('warnings', 'Warning messages'), - ) - annotation_rows = ( - ('regs', 'Registers', (0, 1)), - ('warnings', 'Warnings', (2,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.state = 'IDLE' - self.chip = -1 - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putx(self, data): - self.put(self.ss, self.es, self.out_ann, data) - - def handle_reg_0x00(self, b): - self.putx([1, ['State of inputs: %02X' % b]]) - - def handle_reg_0x01(self, b): - self.putx([1, ['Outputs set: %02X' % b ]]) - - def handle_reg_0x02(self, b): - self.putx([1, ['Polarity inverted: %02X' % b]]) - - def handle_reg_0x03(self, b): - self.putx([1, ['Configuration: %02X' % b]]) - - def handle_write_reg(self, b): - if b == 0: - self.putx([0, ['Input port', 'In', 'I']]) - elif b == 1: - self.putx([0, ['Output port', 'Out', 'O']]) - elif b == 2: - self.putx([0, ['Polarity inversion register', 'Pol', 'P']]) - elif b == 3: - self.putx([0, ['Configuration register', 'Conf', 'C']]) - - def check_correct_chip(self, addr): - if addr not in (0x20, 0x21): - self.putx([2, ['Warning: I²C slave 0x%02X not a TCA6408A ' - 'compatible chip.' % addr]]) - self.state = 'IDLE' - - def decode(self, ss, es, data): - cmd, databyte = data - - # Store the start/end samples of this I²C packet. - self.ss, self.es = ss, es - - # State machine. - if self.state == 'IDLE': - # Wait for an I²C START condition. - if cmd != 'START': - return - self.state = 'GET SLAVE ADDR' - elif self.state == 'GET SLAVE ADDR': - self.chip = databyte - self.state = 'GET REG ADDR' - elif self.state == 'GET REG ADDR': - # Wait for a data write (master selects the slave register). - if cmd in ('ADDRESS READ', 'ADDRESS WRITE'): - self.check_correct_chip(databyte) - if cmd != 'DATA WRITE': - return - self.reg = databyte - self.handle_write_reg(self.reg) - self.state = 'WRITE IO REGS' - elif self.state == 'WRITE IO REGS': - # If we see a Repeated Start here, the master wants to read. - if cmd == 'START REPEAT': - self.state = 'READ IO REGS' - return - # Otherwise: Get data bytes until a STOP condition occurs. - if cmd == 'DATA WRITE': - handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg) - handle_reg(databyte) - elif cmd == 'STOP': - self.state = 'IDLE' - self.chip = -1 - elif self.state == 'READ IO REGS': - # Wait for an address read operation. - if cmd == 'ADDRESS READ': - self.state = 'READ IO REGS2' - self.chip = databyte - return - elif self.state == 'READ IO REGS2': - if cmd == 'DATA READ': - handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg) - handle_reg(databyte) - elif cmd == 'STOP': - self.state = 'IDLE' diff --git a/decoders/tdm_audio/__init__.py b/decoders/tdm_audio/__init__.py deleted file mode 100644 index a95e16e3..00000000 --- a/decoders/tdm_audio/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Ben Dooks -## -## 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, see . -## - -''' -TDM Audio is an audio serial bus for moving audio data between devices -(usually on the same board) which can carry one or more channels of data. -''' - -from .pd import Decoder diff --git a/decoders/tdm_audio/pd.py b/decoders/tdm_audio/pd.py deleted file mode 100644 index e805706f..00000000 --- a/decoders/tdm_audio/pd.py +++ /dev/null @@ -1,116 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Ben Dooks -## -## 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, see . -## - -import sigrokdecode as srd - -MAX_CHANNELS = 8 - -class Decoder(srd.Decoder): - api_version = 3 - id = 'tdm_audio' - name = 'TDM audio' - longname = 'Time division multiplex audio' - desc = 'TDM multi-channel audio protocol.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Audio'] - channels = ( - { 'id': 'clock', 'name': 'Bitclk', 'desc': 'Data bit clock' }, - { 'id': 'frame', 'name': 'Framesync', 'desc': 'Frame sync' }, - { 'id': 'data', 'name': 'Data', 'desc': 'Serial data' }, - ) - options = ( - {'id': 'bps', 'desc': 'Bits per sample', 'default': 16 }, - {'id': 'channels', 'desc': 'Channels per frame', 'default': MAX_CHANNELS }, - {'id': 'edge', 'desc': 'Clock edge to sample on', 'default': 'rising', 'values': ('rising', 'falling') } - ) - annotations = tuple(('ch%d' % i, 'Ch%d' % i) for i in range(MAX_CHANNELS)) - annotation_rows = tuple(('ch%d-vals' % i, 'Ch%d' % i, (i,)) for i in range(MAX_CHANNELS)) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.channels = MAX_CHANNELS - self.channel = 0 - self.bitdepth = 16 - self.bitcount = 0 - self.samplecount = 0 - self.lastsync = 0 - self.lastframe = 0 - self.data = 0 - self.ss_block = None - - def metdatadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.bitdepth = self.options['bps'] - self.edge = self.options['edge'] - - def decode(self): - while True: - # Wait for edge of clock (sample on rising/falling edge). - clock, frame, data = self.wait({0: self.edge[0]}) - - self.data = (self.data << 1) | data - self.bitcount += 1 - - if self.ss_block is not None: - if self.bitcount >= self.bitdepth: - self.bitcount = 0 - self.channel += 1 - - c1 = 'Channel %d' % self.channel - c2 = 'C%d' % self.channel - c3 = '%d' % self.channel - if self.bitdepth <= 8: - v = '%02x' % self.data - elif self.bitdepth <= 16: - v = '%04x' % self.data - else: - v = '%08x' % self.data - - if self.channel < self.channels: - ch = self.channel - else: - ch = 0 - - self.put(self.ss_block, self.samplenum, self.out_ann, - [ch, ['%s: %s' % (c1, v), '%s: %s' % (c2, v), - '%s: %s' % (c3, v)]]) - self.data = 0 - self.ss_block = self.samplenum - self.samplecount += 1 - - # Check for new frame. - # Note, frame may be a single clock, or active for the first - # sample in the frame. - if frame != self.lastframe and frame == 1: - self.channel = 0 - self.bitcount = 0 - self.data = 0 - if self.ss_block is None: - self.ss_block = 0 - - self.lastframe = frame diff --git a/decoders/timing/__init__.py b/decoders/timing/__init__.py deleted file mode 100755 index 179487b3..00000000 --- a/decoders/timing/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Torsten Duwe -## -## 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, see . -## - -''' -Timing decoder, find the time between edges. -''' - -from .pd import Decoder diff --git a/decoders/timing/pd.py b/decoders/timing/pd.py deleted file mode 100755 index 20ca2c4e..00000000 --- a/decoders/timing/pd.py +++ /dev/null @@ -1,128 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Torsten Duwe -## Copyright (C) 2014 Sebastien Bourdelin -## -## 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, see . -## - -import sigrokdecode as srd -from collections import deque - -class SamplerateError(Exception): - pass - -def normalize_time(t): - if abs(t) >= 1.0: - return '%.3f s (%.3f Hz)' % (t, (1/t)) - elif abs(t) >= 0.001: - if 1/t/1000 < 1: - return '%.3f ms (%.3f Hz)' % (t * 1000.0, (1/t)) - else: - return '%.3f ms (%.3f kHz)' % (t * 1000.0, (1/t)/1000) - elif abs(t) >= 0.000001: - if 1/t/1000/1000 < 1: - return '%.3f μs (%.3f kHz)' % (t * 1000.0 * 1000.0, (1/t)/1000) - else: - return '%.3f μs (%.3f MHz)' % (t * 1000.0 * 1000.0, (1/t)/1000/1000) - elif abs(t) >= 0.000000001: - if 1/t/1000/1000/1000: - return '%.3f ns (%.3f MHz)' % (t * 1000.0 * 1000.0 * 1000.0, (1/t)/1000/1000) - else: - return '%.3f ns (%.3f GHz)' % (t * 1000.0 * 1000.0 * 1000.0, (1/t)/1000/1000/1000) - else: - return '%f' % t - -class Decoder(srd.Decoder): - api_version = 3 - id = 'timing' - name = 'Timing' - longname = 'Timing calculation with frequency and averaging' - desc = 'Calculate time between edges.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Clock/timing', 'Util'] - channels = ( - {'id': 'data', 'name': 'Data', 'desc': 'Data line'}, - ) - annotations = ( - ('time', 'Time'), - ('average', 'Average'), - ('delta', 'Delta'), - ) - annotation_rows = ( - ('time', 'Time', (0,)), - ('average', 'Average', (1,)), - ('delta', 'Delta', (2,)), - ) - options = ( - { 'id': 'avg_period', 'desc': 'Averaging period', 'default': 100 }, - { 'id': 'edge', 'desc': 'Edges to check', 'default': 'any', 'values': ('any', 'rising', 'falling') }, - { 'id': 'delta', 'desc': 'Show delta from last', 'default': 'no', 'values': ('yes', 'no') }, - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.last_samplenum = None - self.last_n = deque() - self.chunks = 0 - self.level_changed = False - self.last_t = None - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.edge = self.options['edge'] - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - while True: - if self.edge == 'rising': - self.wait({0: 'r'}) - elif self.edge == 'falling': - self.wait({0: 'f'}) - else: - self.wait({0: 'e'}) - - if not self.last_samplenum: - self.last_samplenum = self.samplenum - continue - samples = self.samplenum - self.last_samplenum - t = samples / self.samplerate - - if t > 0: - self.last_n.append(t) - if len(self.last_n) > self.options['avg_period']: - self.last_n.popleft() - - self.put(self.last_samplenum, self.samplenum, self.out_ann, - [0, [normalize_time(t)]]) - if self.options['avg_period'] > 0: - self.put(self.last_samplenum, self.samplenum, self.out_ann, - [1, [normalize_time(sum(self.last_n) / len(self.last_n))]]) - if self.last_t and self.options['delta'] == 'yes': - self.put(self.last_samplenum, self.samplenum, self.out_ann, - [2, [normalize_time(t - self.last_t)]]) - - self.last_t = t - self.last_samplenum = self.samplenum diff --git a/decoders/tlc5620/__init__.py b/decoders/tlc5620/__init__.py deleted file mode 100755 index a642ef64..00000000 --- a/decoders/tlc5620/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -''' -The Texas Instruments TLC5620 is an 8-bit quad DAC. -''' - -from .pd import Decoder diff --git a/decoders/tlc5620/pd.py b/decoders/tlc5620/pd.py deleted file mode 100755 index eec040bc..00000000 --- a/decoders/tlc5620/pd.py +++ /dev/null @@ -1,210 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012-2015 Uwe Hermann -## Copyright (C) 2019 DreamSourceLab -## -## 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, see . -## - -import sigrokdecode as srd - -dacs = { - 0: 'DACA', - 1: 'DACB', - 2: 'DACC', - 3: 'DACD', -} - -class Decoder(srd.Decoder): - api_version = 3 - id = 'tlc5620' - name = 'TI TLC5620' - longname = 'Texas Instruments TLC5620' - desc = 'Texas Instruments TLC5620 8-bit quad DAC.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['IC', 'Analog/digital'] - channels = ( - {'id': 'clk', 'name': 'CLK', 'desc': 'Serial interface clock'}, - {'id': 'data', 'name': 'DATA', 'desc': 'Serial interface data'}, - ) - optional_channels = ( - {'id': 'load', 'name': 'LOAD', 'desc': 'Serial interface load control'}, - {'id': 'ldac', 'name': 'LDAC', 'desc': 'Load DAC'}, - ) - options = ( - {'id': 'vref_a', 'desc': 'Reference voltage DACA (V)', 'default': 3.3}, - {'id': 'vref_b', 'desc': 'Reference voltage DACB (V)', 'default': 3.3}, - {'id': 'vref_c', 'desc': 'Reference voltage DACC (V)', 'default': 3.3}, - {'id': 'vref_d', 'desc': 'Reference voltage DACD (V)', 'default': 3.3}, - ) - annotations = ( - ('dac-select', 'DAC select'), - ('gain', 'Gain'), - ('value', 'DAC value'), - ('data-latch', 'Data latch point'), - ('ldac-fall', 'LDAC falling edge'), - ('bit', 'Bit'), - ('reg-write', 'Register write'), - ('voltage-update', 'Voltage update'), - ('voltage-update-all', 'Voltage update (all DACs)'), - ('invalid-cmd', 'Invalid command'), - ) - annotation_rows = ( - ('bits', 'Bits', (5,)), - ('fields', 'Fields', (0, 1, 2)), - ('registers', 'Registers', (6, 7)), - ('voltage-updates', 'Voltage updates', (8,)), - ('events', 'Events', (3, 4)), - ('errors', 'Errors', (9,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.bits = [] - self.ss_dac_first = None - self.ss_dac = self.es_dac = 0 - self.ss_gain = self.es_gain = 0 - self.ss_value = self.es_value = 0 - self.dac_select = self.gain = self.dac_value = None - self.dacval = {'A': '?', 'B': '?', 'C': '?', 'D': '?'} - self.gains = {'A': '?', 'B': '?', 'C': '?', 'D': '?'} - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def handle_11bits(self): - # Only look at the last 11 bits, the rest is ignored by the TLC5620. - if len(self.bits) > 11: - self.bits = self.bits[-11:] - - # If there are less than 11 bits, something is probably wrong. - if len(self.bits) < 11: - ss, es = self.samplenum, self.samplenum - if len(self.bits) >= 2: - ss = self.bits[0][1] - es = self.bits[-1][1] + (self.bits[1][1] - self.bits[0][1]) - self.put(ss, es, self.out_ann, [9, ['Command too short']]) - self.bits = [] - return False - - self.ss_dac = self.bits[0][1] - self.es_dac = self.ss_gain = self.bits[2][1] - self.es_gain = self.ss_value = self.bits[3][1] - self.clock_width = self.es_gain - self.ss_gain - self.es_value = self.bits[10][1] + self.clock_width # Guessed. - - if self.ss_dac_first is None: - self.ss_dac_first = self.ss_dac - - s = ''.join(str(i[0]) for i in self.bits[:2]) - self.dac_select = s = dacs[int(s, 2)] - self.put(self.ss_dac, self.es_dac, self.out_ann, - [0, ['DAC select: %s' % s, 'DAC sel: %s' % s, - 'DAC: %s' % s, 'D: %s' % s, s, s[3]]]) - - self.gain = g = 1 + self.bits[2][0] - self.put(self.ss_gain, self.es_gain, self.out_ann, - [1, ['Gain: x%d' % g, 'G: x%d' % g, 'x%d' % g]]) - - s = ''.join(str(i[0]) for i in self.bits[3:]) - self.dac_value = v = int(s, 2) - self.put(self.ss_value, self.es_value, self.out_ann, - [2, ['DAC value: %d' % v, 'Value: %d' % v, 'Val: %d' % v, - 'V: %d' % v, '%d' % v]]) - - # Emit an annotation for each bit. - for i in range(1, 11): - self.put(self.bits[i - 1][1], self.bits[i][1], self.out_ann, - [5, [str(self.bits[i - 1][0])]]) - self.put(self.bits[10][1], self.bits[10][1] + self.clock_width, - self.out_ann, [5, [str(self.bits[10][0])]]) - - self.bits = [] - - return True - - def handle_falling_edge_load(self): - if not self.handle_11bits(): - return - s, v, g = self.dac_select, self.dac_value, self.gain - self.put(self.samplenum, self.samplenum, self.out_ann, - [3, ['Falling edge on LOAD', 'LOAD fall', 'F']]) - vref = self.options['vref_%s' % self.dac_select[3].lower()] - v = '%.2fV' % (vref * (v / 256) * self.gain) - if self.ldac == 0: - # If LDAC is low, the voltage is set immediately. - self.put(self.ss_dac, self.es_value, self.out_ann, - [7, ['Setting %s voltage to %s' % (s, v), - '%s=%s' % (s, v)]]) - else: - # If LDAC is high, the voltage is not set immediately, but rather - # stored in a register. When LDAC goes low all four DAC voltages - # (DAC A/B/C/D) will be set at the same time. - self.put(self.ss_dac, self.es_value, self.out_ann, - [6, ['Setting %s register value to %s' % \ - (s, v), '%s=%s' % (s, v)]]) - # Save the last value the respective DAC was set to. - self.dacval[self.dac_select[-1]] = str(self.dac_value) - self.gains[self.dac_select[-1]] = self.gain - - def handle_falling_edge_ldac(self): - self.put(self.samplenum, self.samplenum, self.out_ann, - [4, ['Falling edge on LDAC', 'LDAC fall', 'LDAC', 'L']]) - - # Don't emit any annotations if we didn't see any register writes. - if self.ss_dac_first is None: - return - - # Calculate voltages based on Vref and the per-DAC gain. - dacval = {} - for key, val in self.dacval.items(): - if val == '?': - dacval[key] = '?' - else: - vref = self.options['vref_%s' % key.lower()] - v = vref * (int(val) / 256) * self.gains[key] - dacval[key] = '%.2fV' % v - - s = ''.join(['DAC%s=%s ' % (d, dacval[d]) for d in 'ABCD']).strip() - self.put(self.ss_dac_first, self.samplenum, self.out_ann, - [8, ['Updating voltages: %s' % s, s, s.replace('DAC', '')]]) - self.ss_dac_first = None - - def handle_new_dac_bit(self, datapin): - self.bits.append([datapin, self.samplenum]) - - def decode(self): - while True: - # DATA is shifted in the DAC on the falling CLK edge (MSB-first). - # A falling edge of LOAD will latch the data. - - # Wait for one (or multiple) of the following conditions: - # a) Falling edge on CLK, and/or - # b) Falling edge on LOAD, and/or - # b) Falling edge on LDAC - (clk, data, load, ldac) = self.wait([{0: 'f'}, {2: 'f'}, {3: 'f'}]) - self.ldac = ldac - - # Handle those conditions (one or more) that matched this time. - if (self.matched & (0b1 << 0)): - self.handle_new_dac_bit(data) - if (self.matched & (0b1 << 1)): - self.handle_falling_edge_load() - if (self.matched & (0b1 << 2)): - self.handle_falling_edge_ldac() diff --git a/decoders/usb_packet/__init__.py b/decoders/usb_packet/__init__.py deleted file mode 100755 index 5cd7c56b..00000000 --- a/decoders/usb_packet/__init__.py +++ /dev/null @@ -1,43 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -''' -This decoder stacks on top of the 'usb_signalling' PD and decodes the USB -(low-speed and full-speed) packet protocol. - -Protocol layer (USB spec, chapter 8): - -Bit/byte ordering: Bits are sent onto the bus LSB-first. Multibyte fields -are transmitted in little-endian order (i.e., LSB to MSB). - -SYNC field: All packets begin with a SYNC field (8 bits). - -Packet field format: Packets start with an SOP (Start Of Packet) delimiter -that is part of the SYNC field, and end with an EOP (End Of Packet). - -PID: A PID (packet identifier) follows the SYNC field of every packet. A PID -consists of a 4-bit packet type field, and a 4 bit check field. -The check field is the one's complement of the packet type field. - -Details: -https://en.wikipedia.org/wiki/USB -http://www.usb.org/developers/docs/ -''' - -from .pd import Decoder diff --git a/decoders/usb_packet/pd.py b/decoders/usb_packet/pd.py deleted file mode 100755 index e262074e..00000000 --- a/decoders/usb_packet/pd.py +++ /dev/null @@ -1,397 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2011 Gareth McMullin -## Copyright (C) 2012-2014 Uwe Hermann -## -## 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, see . -## - -import sigrokdecode as srd - -''' -OUTPUT_PYTHON format: - -Packet: -[, ] - -, : - - 'SYNC', - - 'PID', - - 'ADDR', - - 'EP', - - 'CRC5', - - 'CRC5 ERROR', - - 'CRC16', - - 'CRC16 ERROR', - - 'EOP', - - 'FRAMENUM', - - 'DATABYTE', - - 'HUBADDR', - - 'SC', - - 'PORT', - - 'S', - - 'E/U', - - 'ET', - - 'PACKET', [, , ] - -, , : - - 'TOKEN', 'OUT', [, , , , , ] - - 'TOKEN', 'IN', [, , , , , ] - - 'TOKEN', 'SOF', [, , , , ] - - 'TOKEN', 'SETUP', [, , , , , ] - - 'DATA', 'DATA0', [, , , , ] - - 'DATA', 'DATA1', [, , , , ] - - 'DATA', 'DATA2', [, , , , ] - - 'DATA', 'MDATA', [, , , , ] - - 'HANDSHAKE', 'ACK', [, , ] - - 'HANDSHAKE', 'NAK', [, , ] - - 'HANDSHAKE', 'STALL', [, , ] - - 'HANDSHAKE', 'NYET', [, , ] - - 'SPECIAL', 'PRE', [, , , , , ] - - 'SPECIAL', 'ERR', [, , ] - - 'SPECIAL', 'SPLIT', - [, , , , , , , , , ] - - 'SPECIAL', 'PING', [, , , , , ] - - 'SPECIAL', 'Reserved', None - -: SYNC field bitstring, normally '00000001' (8 chars). -: Packet ID bitstring, e.g. '11000011' for DATA0 (8 chars). -: Address field number, 0-127 (7 bits). -: Endpoint number, 0-15 (4 bits). -: CRC-5 number (5 bits). -: CRC-16 number (16 bits). -: End of packet marker. List of symbols, usually ['SE0', 'SE0', 'J']. -: USB (micro)frame number, 0-2047 (11 bits). -: A single data byte, e.g. 0x55. -: List of data bytes, e.g. [0x55, 0xaa, 0x99] (0 - 1024 bytes). -: TODO -: TODO -: TODO -: TODO -: TODO -: TODO -''' - -# Packet IDs (PIDs). -# The first 4 bits are the 'packet type' field, the last 4 bits are the -# 'check field' (each bit in the check field must be the inverse of the resp. -# bit in the 'packet type' field; if not, that's a 'PID error'). -# For the 4-bit strings, the left-most '1' or '0' is the LSB, i.e. it's sent -# to the bus first. -pids = { - # Tokens - '10000111': ['OUT', 'Address & EP number in host-to-function transaction'], - '10010110': ['IN', 'Address & EP number in function-to-host transaction'], - '10100101': ['SOF', 'Start-Of-Frame marker & frame number'], - '10110100': ['SETUP', 'Address & EP number in host-to-function transaction for SETUP to a control pipe'], - - # Data - # Note: DATA2 and MDATA are HS-only. - '11000011': ['DATA0', 'Data packet PID even'], - '11010010': ['DATA1', 'Data packet PID odd'], - '11100001': ['DATA2', 'Data packet PID HS, high bandwidth isosynchronous transaction in a microframe'], - '11110000': ['MDATA', 'Data packet PID HS for split and high-bandwidth isosynchronous transactions'], - - # Handshake - '01001011': ['ACK', 'Receiver accepts error-free packet'], - '01011010': ['NAK', 'Receiver cannot accept or transmitter cannot send'], - '01111000': ['STALL', 'EP halted or control pipe request unsupported'], - '01101001': ['NYET', 'No response yet from receiver'], - - # Special - '00111100': ['PRE', 'Host-issued preamble; enables downstream bus traffic to low-speed devices'], - #'00111100': ['ERR', 'Split transaction error handshake'], - '00011110': ['SPLIT', 'HS split transaction token'], - '00101101': ['PING', 'HS flow control probe for a bulk/control EP'], - '00001111': ['Reserved', 'Reserved PID'], -} - -def get_category(pidname): - if pidname in ('OUT', 'IN', 'SOF', 'SETUP'): - return 'TOKEN' - elif pidname in ('DATA0', 'DATA1', 'DATA2', 'MDATA'): - return 'DATA' - elif pidname in ('ACK', 'NAK', 'STALL', 'NYET'): - return 'HANDSHAKE' - else: - return 'SPECIAL' - -def ann_index(pidname): - l = ['OUT', 'IN', 'SOF', 'SETUP', 'DATA0', 'DATA1', 'DATA2', 'MDATA', - 'ACK', 'NAK', 'STALL', 'NYET', 'PRE', 'ERR', 'SPLIT', 'PING', - 'Reserved'] - if pidname not in l: - return 28 - return l.index(pidname) + 11 - -def bitstr_to_num(bitstr): - if not bitstr: - return 0 - l = list(bitstr) - l.reverse() - return int(''.join(l), 2) - -def reverse_number(num, count): - out = list(count * '0') - for i in range(0, count): - if num >> i & 1: - out[i] = '1' - return int(''.join(out), 2) - -def calc_crc5(bitstr): - poly5 = 0x25 - crc5 = 0x1f - for bit in bitstr: - crc5 <<= 1 - if int(bit) != (crc5 >> 5): - crc5 ^= poly5 - crc5 &= 0x1f - crc5 ^= 0x1f - return reverse_number(crc5, 5) - -def calc_crc16(bitstr): - poly16 = 0x18005 - crc16 = 0xffff - for bit in bitstr: - crc16 <<= 1 - if int(bit) != (crc16 >> 16): - crc16 ^= poly16 - crc16 &= 0xffff - crc16 ^= 0xffff - return reverse_number(crc16, 16) - -class Decoder(srd.Decoder): - api_version = 3 - id = 'usb_packet' - name = 'USB packet' - longname = 'Universal Serial Bus (LS/FS) packet' - desc = 'USB (low-speed and full-speed) packet protocol.' - license = 'gplv2+' - inputs = ['usb_signalling'] - outputs = ['usb_packet'] - tags = ['PC'] - options = ( - {'id': 'signalling', 'desc': 'Signalling', - 'default': 'full-speed', 'values': ('full-speed', 'low-speed')}, - ) - annotations = ( - ('sync-ok', 'SYNC'), - ('sync-err', 'SYNC (error)'), - ('pid', 'PID'), - ('framenum', 'FRAMENUM'), - ('addr', 'ADDR'), - ('ep', 'EP'), - ('crc5-ok', 'CRC5'), - ('crc5-err', 'CRC5 (error)'), - ('data', 'DATA'), - ('crc16-ok', 'CRC16'), - ('crc16-err', 'CRC16 (error)'), - ('packet-out', 'Packet: OUT'), - ('packet-in', 'Packet: IN'), - ('packet-sof', 'Packet: SOF'), - ('packet-setup', 'Packet: SETUP'), - ('packet-data0', 'Packet: DATA0'), - ('packet-data1', 'Packet: DATA1'), - ('packet-data2', 'Packet: DATA2'), - ('packet-mdata', 'Packet: MDATA'), - ('packet-ack', 'Packet: ACK'), - ('packet-nak', 'Packet: NAK'), - ('packet-stall', 'Packet: STALL'), - ('packet-nyet', 'Packet: NYET'), - ('packet-pre', 'Packet: PRE'), - ('packet-err', 'Packet: ERR'), - ('packet-split', 'Packet: SPLIT'), - ('packet-ping', 'Packet: PING'), - ('packet-reserved', 'Packet: Reserved'), - ('packet-invalid', 'Packet: Invalid'), - ) - annotation_rows = ( - ('fields', 'Packet fields', tuple(range(10 + 1))), - ('packet', 'Packets', tuple(range(11, 28 + 1))), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.bits = [] - self.packet = [] - self.packet_summary = '' - self.ss = self.es = None - self.ss_packet = self.es_packet = None - self.state = 'WAIT FOR SOP' - - def putpb(self, data): - self.put(self.ss, self.es, self.out_python, data) - - def putb(self, data): - self.put(self.ss, self.es, self.out_ann, data) - - def putpp(self, data): - self.put(self.ss_packet, self.es_packet, self.out_python, data) - - def putp(self, data): - self.put(self.ss_packet, self.es_packet, self.out_ann, data) - - def start(self): - self.out_python = self.register(srd.OUTPUT_PYTHON) - self.out_ann = self.register(srd.OUTPUT_ANN) - - def handle_packet(self): - packet = '' - for (bit, ss, es) in self.bits: - packet += bit - - if len(packet) < 8: - self.putp([28, ['Invalid packet (shorter than 8 bits)']]) - return - - # Bits[0:7]: SYNC - sync = packet[:7 + 1] - self.ss, self.es = self.bits[0][1], self.bits[7][2] - # The SYNC pattern for low-speed/full-speed is KJKJKJKK (00000001). - if sync != '00000001': - self.putpb(['SYNC ERROR', sync]) - self.putb([1, ['SYNC ERROR: %s' % sync, 'SYNC ERR: %s' % sync, - 'SYNC ERR', 'SE', 'S']]) - else: - self.putpb(['SYNC', sync]) - self.putb([0, ['SYNC: %s' % sync, 'SYNC', 'S']]) - self.packet.append(sync) - - if len(packet) < 16: - self.putp([28, ['Invalid packet (shorter than 16 bits)']]) - return - - # Bits[8:15]: PID - pid = packet[8:15 + 1] - pidname = pids.get(pid, ('UNKNOWN', 'Unknown PID'))[0] - self.ss, self.es = self.bits[8][1], self.bits[15][2] - self.putpb(['PID', pidname]) - self.putb([2, ['PID: %s' % pidname, pidname, pidname[0]]]) - self.packet.append(pid) - self.packet_summary += pidname - - if pidname in ('OUT', 'IN', 'SOF', 'SETUP', 'PING'): - if len(packet) < 32: - self.putp([28, ['Invalid packet (shorter than 32 bits)']]) - return - - if pidname == 'SOF': - # Bits[16:26]: Framenum - framenum = bitstr_to_num(packet[16:26 + 1]) - self.ss, self.es = self.bits[16][1], self.bits[26][2] - self.putpb(['FRAMENUM', framenum]) - self.putb([3, ['Frame: %d' % framenum, 'Frame', 'Fr', 'F']]) - self.packet.append(framenum) - self.packet_summary += ' %d' % framenum - else: - # Bits[16:22]: Addr - addr = bitstr_to_num(packet[16:22 + 1]) - self.ss, self.es = self.bits[16][1], self.bits[22][2] - self.putpb(['ADDR', addr]) - self.putb([4, ['Address: %d' % addr, 'Addr: %d' % addr, - 'Addr', 'A']]) - self.packet.append(addr) - self.packet_summary += ' ADDR %d' % addr - - # Bits[23:26]: EP - ep = bitstr_to_num(packet[23:26 + 1]) - self.ss, self.es = self.bits[23][1], self.bits[26][2] - self.putpb(['EP', ep]) - self.putb([5, ['Endpoint: %d' % ep, 'EP: %d' % ep, 'EP', 'E']]) - self.packet.append(ep) - self.packet_summary += ' EP %d' % ep - - # Bits[27:31]: CRC5 - crc5 = bitstr_to_num(packet[27:31 + 1]) - crc5_calc = calc_crc5(packet[16:27]) - self.ss, self.es = self.bits[27][1], self.bits[31][2] - if crc5 == crc5_calc: - self.putpb(['CRC5', crc5]) - self.putb([6, ['CRC5: 0x%02X' % crc5, 'CRC5', 'C']]) - else: - self.putpb(['CRC5 ERROR', crc5]) - self.putb([7, ['CRC5 ERROR: 0x%02X' % crc5, 'CRC5 ERR', 'CE', 'C']]) - self.packet.append(crc5) - elif pidname in ('DATA0', 'DATA1', 'DATA2', 'MDATA'): - # Bits[16:packetlen-16]: Data - data = packet[16:-16] - # TODO: len(data) must be a multiple of 8. - databytes = [] - self.packet_summary += ' [' - for i in range(0, len(data), 8): - db = bitstr_to_num(data[i:i + 8]) - self.ss, self.es = self.bits[16 + i][1], self.bits[23 + i][2] - self.putpb(['DATABYTE', db]) - self.putb([8, ['Databyte: %02X' % db, 'Data: %02X' % db, - 'DB: %02X' % db, '%02X' % db]]) - databytes.append(db) - self.packet_summary += ' %02X' % db - self.packet_summary += ' ]' - - # Convenience Python output (no annotation) for all bytes together. - self.ss, self.es = self.bits[16][1], self.bits[-16][2] - self.putpb(['DATABYTES', databytes]) - self.packet.append(databytes) - - # Bits[packetlen-16:packetlen]: CRC16 - crc16 = bitstr_to_num(packet[-16:]) - crc16_calc = calc_crc16(packet[16:-16]) - self.ss, self.es = self.bits[-16][1], self.bits[-1][2] - if crc16 == crc16_calc: - self.putpb(['CRC16', crc16]) - self.putb([9, ['CRC16: 0x%04X' % crc16, 'CRC16', 'C']]) - else: - self.putpb(['CRC16 ERROR', crc16]) - self.putb([10, ['CRC16 ERROR: 0x%04X' % crc16, 'CRC16 ERR', 'CE', 'C']]) - self.packet.append(crc16) - elif pidname in ('ACK', 'NAK', 'STALL', 'NYET', 'ERR'): - pass # Nothing to do, these only have SYNC+PID+EOP fields. - elif pidname in ('PRE'): - pass # Nothing to do, PRE only has SYNC+PID fields. - else: - pass # TODO: Handle 'SPLIT' and possibly 'Reserved' packets. - - # Output a (summary of) the whole packet. - pcategory, pname, pinfo = get_category(pidname), pidname, self.packet - self.putpp(['PACKET', [pcategory, pname, pinfo]]) - self.putp([ann_index(pidname), ['%s' % self.packet_summary]]) - - self.packet, self.packet_summary = [], '' - - def decode(self, ss, es, data): - (ptype, pdata) = data - - # We only care about certain packet types for now. - if ptype not in ('SOP', 'BIT', 'EOP', 'ERR'): - return - - # State machine. - if self.state == 'WAIT FOR SOP': - if ptype != 'SOP': - return - self.ss_packet = ss - self.state = 'GET BIT' - elif self.state == 'GET BIT': - if ptype == 'BIT': - self.bits.append([pdata, ss, es]) - elif ptype == 'EOP' or ptype == 'ERR': - self.es_packet = es - self.handle_packet() - self.packet, self.packet_summary = [], '' - self.bits, self.state = [], 'WAIT FOR SOP' - else: - pass # TODO: Error diff --git a/decoders/usb_power_delivery/__init__.py b/decoders/usb_power_delivery/__init__.py deleted file mode 100755 index 43dfd5d6..00000000 --- a/decoders/usb_power_delivery/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Google, Inc -## -## 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, see . -## - -''' -USB Power Delivery - baseband protocol decoder / checker. -''' - -from .pd import * diff --git a/decoders/usb_power_delivery/pd.py b/decoders/usb_power_delivery/pd.py deleted file mode 100755 index 45077f27..00000000 --- a/decoders/usb_power_delivery/pd.py +++ /dev/null @@ -1,639 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Google, Inc -## Copyright (C) 2018 davidanger -## Copyright (C) 2018 Peter Hazenberg -## -## 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, see . -## - -import sigrokdecode as srd -import struct -import zlib # for crc32 - -# BMC encoding with a 600kHz datarate -UI_US = 1000000/600000.0 - -# Threshold to discriminate half-1 from 0 in Binary Mark Conding -THRESHOLD_US = (UI_US + 2 * UI_US) / 2 - -# Control Message type -CTRL_TYPES = { - 0: 'reserved', - 1: 'GOOD CRC', - 2: 'GOTO MIN', - 3: 'ACCEPT', - 4: 'REJECT', - 5: 'PING', - 6: 'PS RDY', - 7: 'GET SOURCE CAP', - 8: 'GET SINK CAP', - 9: 'DR SWAP', - 10: 'PR SWAP', - 11: 'VCONN SWAP', - 12: 'WAIT', - 13: 'SOFT RESET', - 14: 'reserved', - 15: 'reserved', - 16: 'Not Supported', - 17: 'Get_Source_Cap_Extended', - 18: 'Get_Status', - 19: 'FR_Swap', - 20: 'Get_PPS_Status', - 21: 'Get_Country_Codes', -} - -# Data message type -DATA_TYPES = { - 1: 'SOURCE CAP', - 2: 'REQUEST', - 3: 'BIST', - 4: 'SINK CAP', - 5: 'Battery_Status', - 6: 'Alert', - 7: 'Get_Country_Info', - 15: 'VDM' -} - -# 4b5b encoding of the symbols -DEC4B5B = [ - 0x10, # Error 00000 - 0x10, # Error 00001 - 0x10, # Error 00010 - 0x10, # Error 00011 - 0x10, # Error 00100 - 0x10, # Error 00101 - 0x13, # Sync-3 00110 - 0x14, # RST-1 00111 - 0x10, # Error 01000 - 0x01, # 1 = 0001 01001 - 0x04, # 4 = 0100 01010 - 0x05, # 5 = 0101 01011 - 0x10, # Error 01100 - 0x16, # EOP 01101 - 0x06, # 6 = 0110 01110 - 0x07, # 7 = 0111 01111 - 0x10, # Error 10000 - 0x12, # Sync-2 10001 - 0x08, # 8 = 1000 10010 - 0x09, # 9 = 1001 10011 - 0x02, # 2 = 0010 10100 - 0x03, # 3 = 0011 10101 - 0x0A, # A = 1010 10110 - 0x0B, # B = 1011 10111 - 0x11, # Sync-1 11000 - 0x15, # RST-2 11001 - 0x0C, # C = 1100 11010 - 0x0D, # D = 1101 11011 - 0x0E, # E = 1110 11100 - 0x0F, # F = 1111 11101 - 0x00, # 0 = 0000 11110 - 0x10, # Error 11111 -] -SYM_ERR = 0x10 -SYNC1 = 0x11 -SYNC2 = 0x12 -SYNC3 = 0x13 -RST1 = 0x14 -RST2 = 0x15 -EOP = 0x16 -SYNC_CODES = [SYNC1, SYNC2, SYNC3] -HRST_CODES = [RST1, RST1, RST1, RST2] - -SOP_SEQUENCES = [ - (SYNC1, SYNC1, SYNC1, SYNC2), - (SYNC1, SYNC1, SYNC3, SYNC3), - (SYNC1, SYNC3, SYNC1, SYNC3), - (SYNC1, RST2, RST2, SYNC3), - (SYNC1, RST2, SYNC3, SYNC2), - (RST1, SYNC1, RST1, SYNC3), - (RST1, RST1, RST1, RST2), -] -START_OF_PACKETS = { - SOP_SEQUENCES[0]: 'SOP', - SOP_SEQUENCES[1]: "SOP'", - SOP_SEQUENCES[2]: 'SOP"', - SOP_SEQUENCES[3]: "SOP' Debug", - SOP_SEQUENCES[4]: 'SOP" Debug', - SOP_SEQUENCES[5]: 'Cable Reset', - SOP_SEQUENCES[6]: 'Hard Reset', -} - -SYM_NAME = [ - ['0x0', '0'], - ['0x1', '1'], - ['0x2', '2'], - ['0x3', '3'], - ['0x4', '4'], - ['0x5', '5'], - ['0x6', '6'], - ['0x7', '7'], - ['0x8', '8'], - ['0x9', '9'], - ['0xA', 'A'], - ['0xB', 'B'], - ['0xC', 'C'], - ['0xD', 'D'], - ['0xE', 'E'], - ['0xF', 'F'], - ['ERROR', 'X'], - ['SYNC-1', 'S1'], - ['SYNC-2', 'S2'], - ['SYNC-3', 'S3'], - ['RST-1', 'R1'], - ['RST-2', 'R2'], - ['EOP', '#'], -] - -RDO_FLAGS = { - (1 << 23): 'unchunked', - (1 << 24): 'no_suspend', - (1 << 25): 'comm_cap', - (1 << 26): 'cap_mismatch', - (1 << 27): 'give_back' -} - -BIST_MODES = { - 0: 'Receiver', - 1: 'Transmit', - 2: 'Counters', - 3: 'Carrier 0', - 4: 'Carrier 1', - 5: 'Carrier 2', - 6: 'Carrier 3', - 7: 'Eye', -} - -VDM_CMDS = { - 1: 'Disc Ident', - 2: 'Disc SVID', - 3: 'Disc Mode', - 4: 'Enter Mode', - 5: 'Exit Mode', - 6: 'Attention', - # 16..31: SVID Specific Commands - # DisplayPort Commands - 16: 'DP Status', - 17: 'DP Configure', -} -VDM_ACK = ['REQ', 'ACK', 'NAK', 'BSY'] - - -class SamplerateError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = 'usb_power_delivery' - name = 'USB PD' - longname = 'USB Power Delivery' - desc = 'USB Power Delivery protocol.' - license = 'gplv2+' - inputs = ['logic'] - outputs = ['usb_pd'] - tags = ['PC'] - channels = ( - {'id': 'cc1', 'name': 'CC1', 'desc': 'Configuration Channel 1'}, - ) - optional_channels = ( - {'id': 'cc2', 'name': 'CC2', 'desc': 'Configuration Channel 2'}, - ) - options = ( - {'id': 'fulltext', 'desc': 'Full text decoding of packets', - 'default': 'no', 'values': ('yes', 'no')}, - ) - annotations = ( - ('type', 'Packet Type'), - ('preamble', 'Preamble'), - ('sop', 'Start of Packet'), - ('header', 'Header'), - ('data', 'Data'), - ('crc', 'Checksum'), - ('eop', 'End Of Packet'), - ('sym', '4b5b symbols'), - ('warnings', 'Warnings'), - ('src', 'Source Message'), - ('snk', 'Sink Message'), - ('payload', 'Payload'), - ('text', 'Plain text'), - ) - annotation_rows = ( - ('4b5b', 'Symbols', (7,)), - ('phase', 'Parts', (1, 2, 3, 4, 5, 6)), - ('payload', 'Payload', (11,)), - ('type', 'Type', (0, 9, 10)), - ('warnings', 'Warnings', (8,)), - ('text', 'Full text', (12,)), - ) - binary = ( - ('raw-data', 'RAW binary data'), - ) - - stored_pdos = {} - - def get_request(self, rdo): - pos = (rdo >> 28) & 7 - - op_ma = ((rdo >> 10) & 0x3ff) * 0.01 - max_ma = (rdo & 0x3ff) * 0.01 - - mark = self.cap_mark[pos] - if mark == 3: - op_v = ((rdo >> 9) & 0x7ff) * 0.02 - op_a = (rdo & 0x3f) * 0.05 - t_settings = '%gV %gA' % (op_v, op_a) - elif mark == 2: - op_w = ((rdo >> 10) & 0x3ff) * 0.25 - mp_w = (rdo & 0x3ff) * 0.25 - t_settings = '%gW (operating)' % op_w - else: - op_a = ((rdo >> 10) & 0x3ff) * 0.01 - max_a = (rdo & 0x3ff) * 0.01 - t_settings = '%gA (operating) / %gA (max)' % (op_a, max_a) - - t_flags = '' - for f in sorted(RDO_FLAGS.keys(), reverse = True): - if rdo & f: - t_flags += ' [' + RDO_FLAGS[f] + ']' - - if pos in self.stored_pdos.keys(): - t_pdo = '#%d: %s' % (pos, self.stored_pdos[pos]) - else: - t_pdo = '#%d' % (pos) - - return '(PDO %s) %s%s' % (t_pdo, t_settings, t_flags) - - def get_source_sink_cap(self, pdo, idx, source): - t1 = (pdo >> 30) & 3 - self.cap_mark[idx] = t1 - - flags = {} - if t1 == 0: - t_name = 'Fixed' - if source: - flags = { - (1 << 29): 'dual_role_power', - (1 << 28): 'suspend', - (1 << 27): 'unconstrained', - (1 << 26): 'comm_cap', - (1 << 25): 'dual_role_data', - (1 << 24): 'unchunked', - } - else: # Sink - flags = { - (1 << 29): 'dual_role_power', - (1 << 28): 'high_capability', - (1 << 27): 'unconstrained', - (1 << 26): 'comm_cap', - (1 << 25): 'dual_role_data', - (0b01 << 23): 'fr_swap default power', - (0b10 << 23): 'fr_swap 1.5 A', - (0b11 << 23): 'fr_swap 3.0 A', - } - mv = ((pdo >> 10) & 0x3ff) * 0.05 - ma = ((pdo >> 0) & 0x3ff) * 0.01 - p = '%gV %gA (%gW)' % (mv, ma, mv*ma) - self.stored_pdos[idx] = '%s %gV' % (t_name, mv) - elif t1 == 1: - t_name = 'Battery' - flags = {} # No flags defined for Battery PDO in PD 3.0 spec - minv = ((pdo >> 10) & 0x3ff) * 0.05 - maxv = ((pdo >> 20) & 0x3ff) * 0.05 - mw = ((pdo >> 0) & 0x3ff) * 0.25 - p = '%g/%gV %gW' % (minv, maxv, mw) - self.stored_pdos[idx] = '%s %g/%gV' % (t_name, minv, maxv) - elif t1 == 2: - t_name = 'Variable' - flags = {} # No flags defined for Variable PDO in PD 3.0 spec - minv = ((pdo >> 10) & 0x3ff) * 0.05 - maxv = ((pdo >> 20) & 0x3ff) * 0.05 - ma = ((pdo >> 0) & 0x3ff) * 0.01 - p = '%g/%gV %gA' % (minv, maxv, ma) - self.stored_pdos[idx] = '%s %g/%gV' % (t_name, minv, maxv) - elif t1 == 3: - t2 = (pdo >> 28) & 3 - if t2 == 0: - t_name = 'Programmable|PPS' - flags = { - (1 << 29): 'power_limited', - } - minv = ((pdo >> 8) & 0xff) * 0.1 - maxv = ((pdo >> 17) & 0xff) * 0.1 - ma = ((pdo >> 0) & 0xff) * 0.05 - p = '%g/%gV %gA' % (minv, maxv, ma) - if (pdo >> 27) & 0x1: - p += ' [limited]' - self.stored_pdos[idx] = '%s %g/%gV' % (t_name, minv, maxv) - else: - t_name = 'Reserved APDO: '+bin(t2) - p = '[raw: %s]' % (bin(pdo)) - self.stored_pdos[idx] = '%s %s' % (t_name, p) - t_flags = '' - for f in sorted(flags.keys(), reverse = True): - if pdo & f: - t_flags += ' [' + flags[f] + ']' - return '[%s] %s%s' % (t_name, p, t_flags) - - def get_vdm(self, idx, data): - if idx == 0: # VDM header - vid = data >> 16 - struct = data & (1 << 15) - txt = 'VDM' - if struct: # Structured VDM - cmd = data & 0x1f - src = data & (1 << 5) - ack = (data >> 6) & 3 - pos = (data >> 8) & 7 - ver = (data >> 13) & 3 - txt = VDM_ACK[ack] + ' ' - txt += VDM_CMDS[cmd] if cmd in VDM_CMDS else 'cmd?' - txt += ' pos %d' % (pos) if pos else ' ' - else: # Unstructured VDM - txt = 'unstruct [%04x]' % (data & 0x7fff) - txt += ' SVID:%04x' % (vid) - else: # VDM payload - txt = 'VDO:%08x' % (data) - return txt - - def get_bist(self, idx, data): - mode = data >> 28 - counter = data & 0xffff - mode_name = BIST_MODES[mode] if mode in BIST_MODES else 'INVALID' - if mode == 2: - mode_name = 'Counter[= %d]' % (counter) - # TODO: Check all 0 bits are 0 / emit warnings. - return 'mode %s' % (mode_name) if idx == 0 else 'invalid BRO' - - def putpayload(self, s0, s1, idx): - t = self.head_type() - txt = '['+str(idx+1)+'] ' - if t == 2: - txt += self.get_request(self.data[idx]) - elif t == 1 or t == 4: - txt += self.get_source_sink_cap(self.data[idx], idx+1, t==1) - elif t == 15: - txt += self.get_vdm(idx, self.data[idx]) - elif t == 3: - txt += self.get_bist(idx, self.data[idx]) - self.putx(s0, s1, [11, [txt, txt]]) - self.text += ' - ' + txt - - def puthead(self): - ann_type = 9 if self.head_power_role() else 10 - role = 'SRC' if self.head_power_role() else 'SNK' - if self.head_data_role() != self.head_power_role(): - role += '/DFP' if self.head_data_role() else '/UFP' - t = self.head_type() - if self.head_count() == 0: - shortm = CTRL_TYPES[t] - else: - shortm = DATA_TYPES[t] if t in DATA_TYPES else 'DAT???' - - longm = '(r{:d}) {:s}[{:d}]: {:s}'.format(self.head_rev(), role, self.head_id(), shortm) - self.putx(0, -1, [ann_type, [longm, shortm]]) - self.text += longm - - def head_id(self): - return (self.head >> 9) & 7 - - def head_power_role(self): - return (self.head >> 8) & 1 - - def head_data_role(self): - return (self.head >> 5) & 1 - - def head_rev(self): - return ((self.head >> 6) & 3) + 1 - - def head_type(self): - return self.head & 0xF - - def head_count(self): - return (self.head >> 12) & 7 - - def putx(self, s0, s1, data): - self.put(self.edges[s0], self.edges[s1], self.out_ann, data) - - def putwarn(self, longm, shortm): - self.putx(0, -1, [8, [longm, shortm]]) - - def compute_crc32(self): - bdata = struct.pack('= 3: - return START_OF_PACKETS[seq] - return None - - def scan_eop(self): - for i in range(len(self.bits) - 19): - k = (self.get_sym(i, rec=False), self.get_sym(i+5, rec=False), - self.get_sym(i+10, rec=False), self.get_sym(i+15, rec=False)) - sym = START_OF_PACKETS.get(k, None) - if not sym: - sym = self.find_corrupted_sop(k) - # We have an interesting symbol sequence. - if sym: - # Annotate the preamble. - self.putx(0, i, [1, ['Preamble', '...']]) - # Annotate each symbol. - self.rec_sym(i, k[0]) - self.rec_sym(i+5, k[1]) - self.rec_sym(i+10, k[2]) - self.rec_sym(i+15, k[3]) - if sym == 'Hard Reset': - self.text += 'HRST' - return -1 # Hard reset - elif sym == 'Cable Reset': - self.text += 'CRST' - return -1 # Cable reset - else: - self.putx(i, i+20, [2, [sym, 'S']]) - return i+20 - self.putx(0, len(self.bits), [1, ['Junk???', 'XXX']]) - self.text += 'Junk???' - self.putwarn('No start of packet found', 'XXX') - return -1 # No Start Of Packet - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.idx = 0 - self.packet_seq = 0 - self.previous = 0 - self.startsample = None - self.bits = [] - self.edges = [] - self.bad = [] - self.half_one = False - self.start_one = 0 - self.stored_pdos = {} - self.cap_mark = [0, 0, 0, 0, 0, 0, 0, 0] - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - # 0 is 2 UI, space larger than 1.5x 0 is definitely wrong. - self.maxbit = self.us2samples(3 * UI_US) - # Duration threshold between half 1 and 0. - self.threshold = self.us2samples(THRESHOLD_US) - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.out_binary = self.register(srd.OUTPUT_BINARY) - self.out_bitrate = self.register( - srd.OUTPUT_META, - meta=(int, 'Bitrate', 'Bitrate during the packet') - ) - - def us2samples(self, us): - return int(us * self.samplerate / 1000000) - - def decode_packet(self): - self.data = [] - self.idx = 0 - self.text = '' - - if len(self.edges) < 50: - return # Not a real PD packet - - self.packet_seq += 1 - tstamp = float(self.startsample) / self.samplerate - self.text += '#%-4d (%8.6fms): ' % (self.packet_seq, tstamp*1000) - - self.idx = self.scan_eop() - if self.idx < 0: - # Full text trace of the issue. - self.putx(0, self.idx, [12, [self.text, '...']]) - return # No real packet: ABORT. - - # Packet header - self.head = self.get_short() - self.putx(self.idx-20, self.idx, [3, ['H:%04x' % (self.head), 'HD']]) - self.puthead() - - # Decode data payload - for i in range(self.head_count()): - self.data.append(self.get_word()) - self.putx(self.idx-40, self.idx, - [4, ['[%d]%08x' % (i, self.data[i]), 'D%d' % (i)]]) - self.putpayload(self.idx-40, self.idx, i) - - # CRC check - self.crc = self.get_word() - ccrc = self.compute_crc32() - if self.crc != ccrc: - self.putwarn('Bad CRC %08x != %08x' % (self.crc, ccrc), 'CRC!') - self.putx(self.idx-40, self.idx, [5, ['CRC:%08x' % (self.crc), 'CRC']]) - - # End of Packet - if len(self.bits) >= self.idx + 5 and self.get_sym(self.idx) == EOP: - self.putx(self.idx, self.idx + 5, [6, ['EOP', 'E']]) - self.idx += 5 - else: - self.putwarn('No EOP', 'EOP!') - # Full text trace - if self.options['fulltext'] == 'yes': - self.putx(0, self.idx, [12, [self.text, '...']]) - - # Meta data for bitrate - ss, es = self.edges[0], self.edges[-1] - bitrate = self.samplerate*len(self.bits) / float(es - ss) - self.put(es, ss, self.out_bitrate, int(bitrate)) - # Raw binary data (BMC decoded) - self.put(es, ss, self.out_binary, [0, bytes(self.bits)]) - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - while True: - self.wait([{0: 'e'}, {1: 'e'}, {'skip': int(self.samplerate/1e3)}]) - - # First sample of the packet, just record the start date. - if not self.startsample: - self.startsample = self.samplenum - self.previous = self.samplenum - continue - - diff = self.samplenum - self.previous - - # Large idle: use it as the end of packet. - if diff > self.maxbit: - # The last edge of the packet. - self.edges.append(self.previous) - # Export the packet. - self.decode_packet() - # Reset for next packet. - self.startsample = self.samplenum - self.bits = [] - self.edges = [] - self.bad = [] - self.half_one = False - self.start_one = 0 - else: # Add the bit to the packet. - is_zero = diff > self.threshold - if is_zero and not self.half_one: - self.bits.append(0) - self.edges.append(self.previous) - elif not is_zero and self.half_one: - self.bits.append(1) - self.edges.append(self.start_one) - self.half_one = False - elif not is_zero and not self.half_one: - self.half_one = True - self.start_one = self.previous - else: # Invalid BMC sequence - self.bad.append((self.start_one, self.previous)) - # TODO: Try to recover. - self.bits.append(0) - self.edges.append(self.previous) - self.half_one = False - self.previous = self.samplenum diff --git a/decoders/usb_request/__init__.py b/decoders/usb_request/__init__.py deleted file mode 100755 index 66723dc2..00000000 --- a/decoders/usb_request/__init__.py +++ /dev/null @@ -1,49 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Stefan Brüns -## -## 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, see . -## - -''' -This decoder stacks on top of the 'usb_packet' PD and decodes the USB -(low-speed and full-speed) transactions. - -Transactions and requests are tracked per device address and endpoint. - -Tracking of CONTROL requests is quite accurate, as these always start with -a SETUP token and are completed by an IN or OUT transaction, the status -packet. All transactions during the DATA stage are combined. - -For BULK and INTERRUPT requests, each transaction starts with an IN or OUT -request, and is considered completed after the first transaction containing -data has been ACKed. Normally a request is only completed after a short or -zero length packet, but this would require knowledge about the max packet -size of an endpoint. - -All INTERRUPT requests are treated as BULK requests, as on the link layer -both are identical. - -The PCAP binary output contains 'SUBMIT' and 'COMPLETE' records. For -CONTROL request, the SUBMIT contains the SETUP request, the data is -either contained in the SUBMIT (Host-to-Device) or the COMPLETE -(Device-to-Host) record. - -Details: -https://en.wikipedia.org/wiki/USB -http://www.usb.org/developers/docs/ -''' - -from .pd import Decoder diff --git a/decoders/usb_request/pd.py b/decoders/usb_request/pd.py deleted file mode 100755 index 49b0b350..00000000 --- a/decoders/usb_request/pd.py +++ /dev/null @@ -1,371 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2015 Stefan Brüns -## -## 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, see . -## - -import sigrokdecode as srd -import struct - -class SamplerateError(Exception): - pass - -class pcap_usb_pkt(): - # Linux usbmon format, see Documentation/usb/usbmon.txt - h = b'\x00\x00\x00\x00' # ID part 1 - h += b'\x00\x00\x00\x00' # ID part 2 - h += b'C' # 'S'ubmit / 'C'omplete / 'E'rror - h += b'\x03' # ISO (0), Intr, Control, Bulk (3) - h += b'\x00' # Endpoint - h += b'\x00' # Device address - h += b'\x00\x00' # Bus number - h += b'-' # Setup tag - 0: Setup present, '-' otherwise - h += b'<' # Data tag - '<' no data, 0 otherwise - # Timestamp - h += b'\x00\x00\x00\x00' # TS seconds part 1 - h += b'\x00\x00\x00\x00' # TS seconds part 2 - h += b'\x00\x00\x00\x00' # TS useconds - # - h += b'\x00\x00\x00\x00' # Status 0: OK - h += b'\x00\x00\x00\x00' # URB length - h += b'\x00\x00\x00\x00' # Data length - # Setup packet data, valid if setup tag == 0 - h += b'\x00' # bmRequestType - h += b'\x00' # bRequest - h += b'\x00\x00' # wValue - h += b'\x00\x00' # wIndex - h += b'\x00\x00' # wLength - # - h += b'\x00\x00\x00\x00' # ISO/interrupt interval - h += b'\x00\x00\x00\x00' # ISO start frame - h += b'\x00\x00\x00\x00' # URB flags - h += b'\x00\x00\x00\x00' # Number of ISO descriptors - - def __init__(self, req, ts, is_submit): - self.header = bytearray(pcap_usb_pkt.h) - self.data = b'' - self.set_urbid(req['id']) - self.set_urbtype('S' if is_submit else 'C') - self.set_timestamp(ts) - self.set_addr_ep(req['addr'], req['ep']) - if req['type'] in ('SETUP IN', 'SETUP OUT'): - self.set_transfertype(2) # Control - self.set_setup(req['setup_data']) - if req['type'] in ('BULK IN'): - self.set_addr_ep(req['addr'], 0x80 | req['ep']) - self.set_data(req['data']) - - def set_urbid(self, urbid): - self.header[4:8] = struct.pack('>I', urbid) - - def set_urbtype(self, urbtype): - self.header[8] = ord(urbtype) - - def set_transfertype(self, transfertype): - self.header[9] = transfertype - - def set_addr_ep(self, addr, ep): - self.header[11] = addr - self.header[10] = ep - - def set_timestamp(self, ts): - self.timestamp = ts - self.header[20:24] = struct.pack('>I', ts[0]) # seconds - self.header[24:28] = struct.pack('>I', ts[1]) # microseconds - - def set_data(self, data): - self.data = data - self.header[15] = 0 - self.header[36:40] = struct.pack('>I', len(data)) - - def set_setup(self, data): - self.header[14] = 0 - self.header[40:48] = data - - def packet(self): - return bytes(self.header) + bytes(self.data) - - def record_header(self): - # See https://wiki.wireshark.org/Development/LibpcapFileFormat. - (secs, usecs) = self.timestamp - h = struct.pack('>I', secs) # TS seconds - h += struct.pack('>I', usecs) # TS microseconds - # No truncation, so both lengths are the same. - h += struct.pack('>I', len(self)) # Captured len (usb hdr + data) - h += struct.pack('>I', len(self)) # Original len - return h - - def __len__(self): - return 64 + len(self.data) - -class Decoder(srd.Decoder): - api_version = 3 - id = 'usb_request' - name = 'USB request' - longname = 'Universal Serial Bus (LS/FS) transaction/request' - desc = 'USB (low-speed/full-speed) transaction/request protocol.' - license = 'gplv2+' - inputs = ['usb_packet'] - outputs = ['usb_request'] - tags = ['PC'] - annotations = ( - ('request-setup-read', 'Setup: Device-to-host'), - ('request-setup-write', 'Setup: Host-to-device'), - ('request-bulk-read', 'Bulk: Device-to-host'), - ('request-bulk-write', 'Bulk: Host-to-device'), - ('errors', 'Unexpected packets'), - ) - annotation_rows = ( - ('request', 'USB requests', tuple(range(4))), - ('errors', 'Errors', (4,)), - ) - binary = ( - ('pcap', 'PCAP format'), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.request = {} - self.request_id = 0 - self.transaction_state = 'IDLE' - self.ss_transaction = None - self.es_transaction = None - self.transaction_ep = None - self.transaction_addr = None - self.wrote_pcap_header = False - - def putr(self, ss, es, data): - self.put(ss, es, self.out_ann, data) - - def putb(self, ts, data): - self.put(ts, ts, self.out_binary, data) - - def pcap_global_header(self): - # See https://wiki.wireshark.org/Development/LibpcapFileFormat. - h = b'\xa1\xb2\xc3\xd4' # Magic, indicate microsecond ts resolution - h += b'\x00\x02' # Major version 2 - h += b'\x00\x04' # Minor version 4 - h += b'\x00\x00\x00\x00' # Correction vs. UTC, seconds - h += b'\x00\x00\x00\x00' # Timestamp accuracy - h += b'\xff\xff\xff\xff' # Max packet len - # LINKTYPE_USB_LINUX_MMAPPED 220 - # Linux usbmon format, see Documentation/usb/usbmon.txt. - h += b'\x00\x00\x00\xdc' # Link layer - return h - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - if self.samplerate: - self.secs_per_sample = float(1) / float(self.samplerate) - - def start(self): - self.out_binary = self.register(srd.OUTPUT_BINARY) - self.out_ann = self.register(srd.OUTPUT_ANN) - - def handle_transfer(self): - request_started = 0 - request_end = self.handshake in ('ACK', 'STALL', 'timeout') - ep = self.transaction_ep - addr = self.transaction_addr - - # Handle protocol STALLs, condition lasts until next SETUP transfer (8.5.3.4) - if self.transaction_type == 'SETUP' and (addr, ep) in self.request: - request = self.request[(addr,ep)] - if request['type'] in ('SETUP IN', 'SETUP OUT'): - request['es'] = self.ss_transaction - self.handle_request(0, 1) - - if not (addr, ep) in self.request: - self.request[(addr, ep)] = {'setup_data': [], 'data': [], - 'type': None, 'ss': self.ss_transaction, 'es': None, - 'id': self.request_id, 'addr': addr, 'ep': ep} - self.request_id += 1 - request_started = 1 - request = self.request[(addr,ep)] - - if request_end: - request['es'] = self.es_transaction - request['handshake'] = self.handshake - - # BULK or INTERRUPT transfer - if request['type'] in (None, 'BULK IN') and self.transaction_type == 'IN': - request['type'] = 'BULK IN' - request['data'] += self.transaction_data - self.handle_request(request_started, request_end) - elif request['type'] in (None, 'BULK OUT') and self.transaction_type == 'OUT': - request['type'] = 'BULK OUT' - request['data'] += self.transaction_data - self.handle_request(request_started, request_end) - - # CONTROL, SETUP stage - elif request['type'] is None and self.transaction_type == 'SETUP': - request['setup_data'] = self.transaction_data - request['wLength'] = struct.unpack(' transaction_timeout: - self.es_transaction = transaction_timeout - self.handshake = 'timeout' - self.handle_transfer() - self.transaction_state = 'IDLE' - - if self.transaction_state != 'IDLE': - self.putr(ss, es, [4, ['ERR: received %s token in state %s' % - (pname, self.transaction_state)]]) - return - - sync, pid, addr, ep, crc5 = pinfo - self.transaction_data = [] - self.ss_transaction = ss - self.es_transaction = es - self.transaction_state = 'TOKEN RECEIVED' - self.transaction_ep = ep - self.transaction_addr = addr - self.transaction_type = pname # IN OUT SETUP - - elif pcategory == 'DATA': - if self.transaction_state != 'TOKEN RECEIVED': - self.putr(ss, es, [4, ['ERR: received %s token in state %s' % - (pname, self.transaction_state)]]) - return - - self.transaction_data = pinfo[2] - self.transaction_state = 'DATA RECEIVED' - - elif pcategory == 'HANDSHAKE': - if self.transaction_state not in ('TOKEN RECEIVED', 'DATA RECEIVED'): - self.putr(ss, es, [4, ['ERR: received %s token in state %s' % - (pname, self.transaction_state)]]) - return - - self.handshake = pname - self.transaction_state = 'IDLE' - self.es_transaction = es - self.handle_transfer() - - elif pname == 'PRE': - return - - else: - self.putr(ss, es, [4, ['ERR: received unhandled %s token in state %s' % - (pname, self.transaction_state)]]) - return diff --git a/decoders/usb_signalling/__init__.py b/decoders/usb_signalling/__init__.py deleted file mode 100755 index eae18870..00000000 --- a/decoders/usb_signalling/__init__.py +++ /dev/null @@ -1,50 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2012 Uwe Hermann -## -## 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, see . -## - -''' -This PD decodes the USB (low-speed and full-speed) signalling protocol. - -Electrical/signalling layer (USB spec, chapter 7): - -USB signalling consists of two signal lines, both driven at 3.3V -logic levels. The signals are DP (D+) and DM (D-), and normally operate in -differential mode. - -Low-speed: The state where DP=1,DM=0 is K, the state DP=0,DM=1 is J. -Full-speed: The state where DP=1,DM=0 is J, the state DP=0,DM=1 is K. - -A state SE0 is defined where DP=DM=0. This common mode signal is used to -signal a reset or end of packet (EOP). A state SE1 is defined where DP=DM=1. - -Data transmitted on the USB is encoded with NRZI. A transition from J to K -or vice-versa indicates a logic 0, while no transition indicates a logic 1. -If 6 ones are transmitted consecutively, a zero is inserted to force a -transition. This is known as bit stuffing. - -Data is transferred at a rate of 1.5Mbit/s (low-speed) / 12Mbit/s (full-speed). - -The SE0 transmitted to signal an end-of-packet is two bit intervals long -(low-speed: 1.25uS - 1.50uS, full-speed: 160ns - 175ns). - -Details: -https://en.wikipedia.org/wiki/USB -http://www.usb.org/developers/docs/ -''' - -from .pd import Decoder diff --git a/decoders/usb_signalling/pd.py b/decoders/usb_signalling/pd.py deleted file mode 100755 index 65a2b35c..00000000 --- a/decoders/usb_signalling/pd.py +++ /dev/null @@ -1,352 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2011 Gareth McMullin -## Copyright (C) 2012-2013 Uwe Hermann -## Copyright (C) 2019 DreamSourceLab -## -## 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, see . -## - -import sigrokdecode as srd - -''' -OUTPUT_PYTHON format: - -Packet: -[, ] - -, : - - 'SOP', None - - 'SYM', - - 'BIT', - - 'STUFF BIT', None - - 'EOP', None - - 'ERR', None - - 'KEEP ALIVE', None - - 'RESET', None - -: - - 'J', 'K', 'SE0', or 'SE1' - -: - - '0' or '1' - - Note: Symbols like SE0, SE1, and the J that's part of EOP don't yield 'BIT'. -''' - -# Low-/full-speed symbols. -# Note: Low-speed J and K are inverted compared to the full-speed J and K! -symbols = { - 'low-speed': { - # (, ): - (0, 0): 'SE0', - (1, 0): 'K', - (0, 1): 'J', - (1, 1): 'SE1', - }, - 'full-speed': { - # (, ): - (0, 0): 'SE0', - (1, 0): 'J', - (0, 1): 'K', - (1, 1): 'SE1', - }, - 'automatic': { - # (, ): - (0, 0): 'SE0', - (1, 0): 'FS_J', - (0, 1): 'LS_J', - (1, 1): 'SE1', - }, - # After a PREamble PID, the bus segment between Host and Hub uses LS - # signalling rate and FS signalling polarity (USB 2.0 spec, 11.8.4: "For - # both upstream and downstream low-speed data, the hub is responsible for - # inverting the polarity of the data before transmitting to/from a - # low-speed port."). - 'low-speed-rp': { - # (, ): - (0, 0): 'SE0', - (1, 0): 'J', - (0, 1): 'K', - (1, 1): 'SE1', - }, -} - -bitrates = { - 'low-speed': 1500000, # 1.5Mb/s (+/- 1.5%) - 'low-speed-rp': 1500000, # 1.5Mb/s (+/- 1.5%) - 'full-speed': 12000000, # 12Mb/s (+/- 0.25%) - 'automatic': None -} - -sym_annotation = { - 'J': [0, ['J']], - 'K': [1, ['K']], - 'SE0': [2, ['SE0', '0']], - 'SE1': [3, ['SE1', '1']], -} - -class SamplerateError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = 'usb_signalling' - name = 'USB signalling' - longname = 'Universal Serial Bus (LS/FS) signalling' - desc = 'USB (low-speed/full-speed) signalling protocol.' - license = 'gplv2+' - inputs = ['logic'] - outputs = ['usb_signalling'] - tags = ['PC'] - channels = ( - {'id': 'dp', 'name': 'D+', 'desc': 'USB D+ signal'}, - {'id': 'dm', 'name': 'D-', 'desc': 'USB D- signal'}, - ) - options = ( - {'id': 'signalling', 'desc': 'Signalling', - 'default': 'automatic', 'values': ('automatic', 'full-speed', 'low-speed')}, - ) - annotations = ( - ('sym-j', 'J symbol'), - ('sym-k', 'K symbol'), - ('sym-se0', 'SE0 symbol'), - ('sym-se1', 'SE1 symbol'), - ('sop', 'Start of packet (SOP)'), - ('eop', 'End of packet (EOP)'), - ('bit', 'Bit'), - ('stuffbit', 'Stuff bit'), - ('error', 'Error'), - ('keep-alive', 'Low-speed keep-alive'), - ('reset', 'Reset'), - ) - annotation_rows = ( - ('bits', 'Bits', (4, 5, 6, 7, 8, 9, 10)), - ('symbols', 'Symbols', (0, 1, 2, 3)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self.oldsym = 'J' # The "idle" state is J. - self.ss_block = None - self.samplenum = 0 - self.bitrate = None - self.bitwidth = None - self.samplepos = None - self.samplenum_target = None - self.samplenum_edge = None - self.samplenum_lastedge = 0 - self.edgepins = None - self.consecutive_ones = 0 - self.bits = None - self.state = 'IDLE' - - def start(self): - self.out_python = self.register(srd.OUTPUT_PYTHON) - self.out_ann = self.register(srd.OUTPUT_ANN) - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - self.signalling = self.options['signalling'] - if self.signalling != 'automatic': - self.update_bitrate() - - def update_bitrate(self): - self.bitrate = bitrates[self.signalling] - self.bitwidth = float(self.samplerate) / float(self.bitrate) - - def putpx(self, data): - s = self.samplenum_edge - self.put(s, s, self.out_python, data) - - def putx(self, data): - s = self.samplenum_edge - self.put(s, s, self.out_ann, data) - - def putpm(self, data): - e = self.samplenum_edge - self.put(self.ss_block, e, self.out_python, data) - - def putm(self, data): - e = self.samplenum_edge - self.put(self.ss_block, e, self.out_ann, data) - - def putpb(self, data): - s, e = self.samplenum_lastedge, self.samplenum_edge - self.put(s, e, self.out_python, data) - - def putb(self, data): - s, e = self.samplenum_lastedge, self.samplenum_edge - self.put(s, e, self.out_ann, data) - - def set_new_target_samplenum(self): - self.samplepos += self.bitwidth - self.samplenum_target = int(self.samplepos) - self.samplenum_lastedge = self.samplenum_edge - self.samplenum_edge = int(self.samplepos - (self.bitwidth / 2)) - - def wait_for_sop(self, sym): - # Wait for a Start of Packet (SOP), i.e. a J->K symbol change. - if sym != 'K' or self.oldsym != 'J': - return - self.consecutive_ones = 0 - self.bits = '' - self.update_bitrate() - self.samplepos = self.samplenum - (self.bitwidth / 2) + 0.5 - self.set_new_target_samplenum() - self.putpx(['SOP', None]) - self.putx([4, ['SOP', 'S']]) - self.state = 'GET BIT' - - def handle_bit(self, b): - if self.consecutive_ones == 6: - if b == '0': - # Stuff bit. - self.putpb(['STUFF BIT', None]) - self.putb([7, ['Stuff bit: 0', 'SB: 0', '0']]) - self.consecutive_ones = 0 - else: - self.putpb(['ERR', None]) - self.putb([8, ['Bit stuff error', 'BS ERR', 'B']]) - self.state = 'IDLE' - else: - # Normal bit (not a stuff bit). - self.putpb(['BIT', b]) - self.putb([6, ['%s' % b]]) - if b == '1': - self.consecutive_ones += 1 - else: - self.consecutive_ones = 0 - - def get_eop(self, sym): - # EOP: SE0 for >= 1 bittime (usually 2 bittimes), then J. - self.set_new_target_samplenum() - self.putpb(['SYM', sym]) - self.putb(sym_annotation[sym]) - self.oldsym = sym - if sym == 'SE0': - pass - elif sym == 'J': - # Got an EOP. - self.putpm(['EOP', None]) - self.putm([5, ['EOP', 'E']]) - self.state = 'WAIT IDLE' - else: - self.putpm(['ERR', None]) - self.putm([8, ['EOP Error', 'EErr', 'E']]) - self.state = 'IDLE' - - def get_bit(self, sym): - self.set_new_target_samplenum() - b = '0' if self.oldsym != sym else '1' - self.oldsym = sym - if sym == 'SE0': - # Start of an EOP. Change state, save edge - self.state = 'GET EOP' - self.ss_block = self.samplenum_lastedge - else: - self.handle_bit(b) - self.putpb(['SYM', sym]) - self.putb(sym_annotation[sym]) - if len(self.bits) <= 16: - self.bits += b - if len(self.bits) == 16 and self.bits == '0000000100111100': - # Sync and low-speed PREamble seen - self.putpx(['EOP', None]) - self.state = 'IDLE' - self.signalling = 'low-speed-rp' - self.update_bitrate() - self.oldsym = 'J' - if b == '0': - edgesym = symbols[self.signalling][tuple(self.edgepins)] - if edgesym not in ('SE0', 'SE1'): - if edgesym == sym: - self.bitwidth = self.bitwidth - (0.001 * self.bitwidth) - self.samplepos = self.samplepos - (0.01 * self.bitwidth) - else: - self.bitwidth = self.bitwidth + (0.001 * self.bitwidth) - self.samplepos = self.samplepos + (0.01 * self.bitwidth) - - def handle_idle(self, sym): - self.samplenum_edge = self.samplenum - se0_length = float(self.samplenum - self.samplenum_lastedge) / self.samplerate - if se0_length > 2.5e-6: # 2.5us - self.putpb(['RESET', None]) - self.putb([10, ['Reset', 'Res', 'R']]) - self.signalling = self.options['signalling'] - elif se0_length > 1.2e-6 and self.signalling == 'low-speed': - self.putpb(['KEEP ALIVE', None]) - self.putb([9, ['Keep-alive', 'KA', 'A']]) - - if self.options['signalling'] == 'automatic' and sym == 'FS_J': - self.signalling = 'full-speed' - elif self.options['signalling'] == 'automatic' and sym == 'LS_J': - self.signalling = 'low-speed' - else: - self.signalling = self.options['signalling'] - self.update_bitrate() - - self.oldsym = 'J' - self.state = 'IDLE' - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - - # Seed internal state from the very first sample. - (dp, dm) = self.wait() - sym = symbols[self.options['signalling']][(dp, dm)] - self.handle_idle(sym) - - while True: - # State machine. - if self.state == 'IDLE': - # Wait for any edge on either DP and/or DM. - (dp, dm) = self.wait([{0: 'e'}, {1: 'e'}]) - sym = symbols[self.signalling][(dp, dm)] - if sym == 'SE0': - self.samplenum_lastedge = self.samplenum - self.state = 'WAIT IDLE' - else: - self.wait_for_sop(sym) - self.edgepins = (dp, dm) - elif self.state in ('GET BIT', 'GET EOP'): - # Wait until we're in the middle of the desired bit. - if (self.samplenum_edge > self.samplenum): - (dp, dm) = self.wait([{'skip': self.samplenum_edge - self.samplenum}]) - self.edgepins = (dp, dm) - if (self.samplenum_target > self.samplenum): - (dp, dm) = self.wait([{'skip': self.samplenum_target - self.samplenum}]) - - sym = symbols[self.signalling][(dp, dm)] - if self.state == 'GET BIT': - self.get_bit(sym) - elif self.state == 'GET EOP': - self.get_eop(sym) - elif self.state == 'WAIT IDLE': - # Skip "all-low" input. Wait for high level on either DP or DM. - (dp, dm) = self.wait() - while not dp and not dm: - (dp, dm) = self.wait([{0: 'h'}, {1: 'h'}]) - if self.samplenum - self.samplenum_lastedge > 1: - sym = symbols[self.options['signalling']][(dp, dm)] - self.handle_idle(sym) - else: - sym = symbols[self.signalling][(dp, dm)] - self.wait_for_sop(sym) - self.edgepins = (dp, dm) diff --git a/decoders/wiegand/__init__.py b/decoders/wiegand/__init__.py deleted file mode 100755 index d7d9a8c7..00000000 --- a/decoders/wiegand/__init__.py +++ /dev/null @@ -1,28 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2016 Sean Burford -## -## 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, see . -## - -''' -The Wiegand interface is a de facto wiring standard commonly used to connect -a card swipe mechanism to the rest of an electronic entry system. - -Details: -https://en.wikipedia.org/wiki/Wiegand_interface -''' - -from .pd import Decoder diff --git a/decoders/wiegand/pd.py b/decoders/wiegand/pd.py deleted file mode 100755 index a93be109..00000000 --- a/decoders/wiegand/pd.py +++ /dev/null @@ -1,148 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2016 Sean Burford -## -## 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, see . -## - -import sigrokdecode as srd - -class SamplerateError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 3 - id = 'wiegand' - name = 'Wiegand' - longname = 'Wiegand interface' - desc = 'Wiegand interface for electronic entry systems.' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - tags = ['Embedded/industrial', 'RFID'] - channels = ( - {'id': 'd0', 'name': 'D0', 'desc': 'Data 0 line'}, - {'id': 'd1', 'name': 'D1', 'desc': 'Data 1 line'}, - ) - options = ( - {'id': 'active', 'desc': 'Data lines active level', - 'default': 'low', 'values': ('low', 'high')}, - {'id': 'bitwidth_ms', 'desc': 'Single bit width in milliseconds', - 'default': 4, 'values': (1, 2, 4, 8, 16, 32)}, - ) - annotations = ( - ('bits', 'Bits'), - ('state', 'State'), - ) - annotation_rows = ( - ('bits', 'Binary value', (0,)), - ('state', 'Stream state', (1,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.samplerate = None - self._samples_per_bit = 10 - - self._d0_prev = None - self._d1_prev = None - - self._state = None - self.ss_state = None - - self.ss_bit = None - self.es_bit = None - self._bit = None - self._bits = [] - - def start(self): - 'Register output types and verify user supplied decoder values.' - self.out_ann = self.register(srd.OUTPUT_ANN) - self._active = 1 if self.options['active'] == 'high' else 0 - self._inactive = 1 - self._active - - def metadata(self, key, value): - 'Receive decoder metadata about the data stream.' - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - if self.samplerate: - ms_per_sample = 1000 * (1.0 / self.samplerate) - ms_per_bit = float(self.options['bitwidth_ms']) - self._samples_per_bit = int(max(1, int(ms_per_bit / ms_per_sample))) - - def _update_state(self, state, bit=None): - 'Update state and bit values when they change.' - if self._bit is not None: - self._bits.append(self._bit) - self.put(self.ss_bit, self.samplenum, self.out_ann, - [0, [str(self._bit)]]) - self._bit = bit - self.ss_bit = self.samplenum - if bit is not None: - # Set a timeout so that the final bit ends. - self.es_bit = self.samplenum + self._samples_per_bit - else: - self.es_bit = None - - if state != self._state: - ann = None - if self._state == 'data': - accum_bits = ''.join(str(x) for x in self._bits) - ann = [1, ['%d bits %s' % (len(self._bits), accum_bits), - '%d bits' % len(self._bits)]] - elif self._state == 'invalid': - ann = [1, [self._state]] - if ann: - self.put(self.ss_state, self.samplenum, self.out_ann, ann) - self.ss_state = self.samplenum - self._state = state - self._bits = [] - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - while True: - # TODO: Come up with more appropriate self.wait() conditions. - (d0, d1) = self.wait() - - if d0 == self._d0_prev and d1 == self._d1_prev: - if self.es_bit and self.samplenum >= self.es_bit: - if (d0, d1) == (self._inactive, self._inactive): - self._update_state('idle') - else: - self._update_state('invalid') - continue - - if self._state in (None, 'idle', 'data'): - if (d0, d1) == (self._active, self._inactive): - self._update_state('data', 0) - elif (d0, d1) == (self._inactive, self._active): - self._update_state('data', 1) - elif (d0, d1) == (self._active, self._active): - self._update_state('invalid') - elif self._state == 'invalid': - # Wait until we see an idle state before leaving invalid. - # This prevents inverted lines from being misread. - if (d0, d1) == (self._inactive, self._inactive): - self._update_state('idle') - - self._d0_prev, self._d1_prev = d0, d1 - - def report(self): - return '%s: %s D0 %d D1 %d (active on %d), %d samples per bit' % ( - self.name, self._state, self._d0_prev, self._d1_prev, - self._active, self._samples_per_bit) diff --git a/decoders/x2444m/__init__.py b/decoders/x2444m/__init__.py deleted file mode 100644 index 70d21466..00000000 --- a/decoders/x2444m/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Stefan Petersen -## -## 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, see . -## - -''' -This decoder stacks on top of the 'spi' PD and decodes the Xicor X2444M/P -nonvolatile static RAM protocol. -''' - -from .pd import Decoder diff --git a/decoders/x2444m/pd.py b/decoders/x2444m/pd.py deleted file mode 100644 index 290cc368..00000000 --- a/decoders/x2444m/pd.py +++ /dev/null @@ -1,111 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Stefan Petersen -## -## 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, see . -## - -import re -import sigrokdecode as srd - -registers = { - 0x80: ['WRDS', 0, lambda _: ''], - 0x81: ['STO', 1, lambda _: ''], - 0x82: ['SLEEP', 2, lambda _: ''], - 0x83: ['WRITE', 3, lambda v: '0x%x' % v], - 0x84: ['WREN', 4, lambda _: ''], - 0x85: ['RCL', 5, lambda _: ''], - 0x86: ['READ', 6, lambda v: '0x%x' % v], - 0x87: ['READ', 7, lambda v: '0x%x' % v], -} - -class Decoder(srd.Decoder): - api_version = 3 - id = 'x2444m' - name = 'X2444M/P' - longname = 'Xicor X2444M/P' - desc = 'Xicor X2444M/P nonvolatile static RAM protocol.' - license = 'gplv2+' - inputs = ['spi'] - outputs = [] - tags = ['IC', 'Memory'] - annotations = ( - ('wrds', 'Write disable'), - ('sto', 'Store RAM data in EEPROM'), - ('sleep', 'Enter sleep mode'), - ('write', 'Write data into RAM'), - ('wren', 'Write enable'), - ('rcl', 'Recall EEPROM data into RAM'), - ('read', 'Data read from RAM'), - ('read', 'Data read from RAM'), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.cs_start = 0 - self.cs_asserted = False - self.cmd_digit = 0 - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def putreadwrite(self, ss, es, reg, idx, addr, value): - self.put(ss, es, self.out_ann, - [idx, ['%s: %s => 0x%4.4x' % (reg, addr, value), - '%s: %s => 0x%4.4x' % (reg[0], addr, value), reg[0]]]) - - def putcmd(self, ss, es, reg, idx): - self.put(ss, es, self.out_ann, [idx, [reg, reg[0]]]) - - def decode(self, ss, es, data): - ptype, mosi, miso = data - - if ptype == 'DATA': - if not self.cs_asserted: - return - - if self.cmd_digit == 0: - self.addr = mosi - self.addr_start = ss - elif self.cmd_digit > 0: - self.read_value = (self.read_value << 8) + miso - self.write_value = (self.write_value << 8) + mosi - self.cmd_digit += 1 - elif ptype == 'CS-CHANGE': - self.cs_asserted = (miso == 1) - # When not asserted, CS has just changed from asserted to deasserted. - if not self.cs_asserted: - # Only one digit, simple command. Else read/write. - if self.cmd_digit == 1: - name, idx, decoder = registers[self.addr & 0x87] - self.putcmd(self.addr_start, es, name, idx) - elif self.cmd_digit > 1: - name, idx, decoder = registers[self.addr & 0x87] - if name == 'READ': - value = self.read_value - elif name == 'WRITE': - value = self.write_value - else: - value = 0 - self.putreadwrite(self.addr_start, es, name, idx, - decoder((self.addr >> 3) & 0x0f), value) - - if self.cs_asserted: - self.cs_start = ss - self.cmd_digit = 0 - self.read_value = 0 - self.write_value = 0 diff --git a/decoders/xfp/__init__.py b/decoders/xfp/__init__.py deleted file mode 100755 index 72f35950..00000000 --- a/decoders/xfp/__init__.py +++ /dev/null @@ -1,38 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2013 Bert Vermeulen -## -## 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, see . -## - -''' -This PD decodes the XFP I²C management interface structures/protocol. - -XFP modules include an I²C interface, used to monitor and control various -aspects of the module. The specification defines an I²C slave at address -0x50 (0xa0) which returns 128 bytes of a standard structure ("lower memory"), -and, after setting a table number in lower memory, a set of 256 "higher -memory" tables, which can be mapped to different subdevices on the XFP. - -Only one table is defined in the specification: table 0x01, the default on -module startup. Other table are either reserved for future expansion, or -available for vendor-specific extensions. This decoder supports both lower -memory and table 0x01. - -Details: -ftp://ftp.seagate.com/sff/INF-8077.PDF (XFP specification) -''' - -from .pd import Decoder diff --git a/decoders/xfp/pd.py b/decoders/xfp/pd.py deleted file mode 100755 index ded76946..00000000 --- a/decoders/xfp/pd.py +++ /dev/null @@ -1,482 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2013 Bert Vermeulen -## -## 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 . -## - -import sigrokdecode as srd -from common.plugtrx import (MODULE_ID, ALARM_THRESHOLDS, AD_READOUTS, GCS_BITS, - CONNECTOR, TRANSCEIVER, SERIAL_ENCODING, XMIT_TECH, CDR, DEVICE_TECH, - ENHANCED_OPTS, AUX_TYPES) - -class Decoder(srd.Decoder): - api_version = 3 - id = 'xfp' - name = 'XFP' - longname = '10 Gigabit Small Form Factor Pluggable Module (XFP)' - desc = 'XFP I²C management interface structures/protocol' - license = 'gplv3+' - inputs = ['i2c'] - outputs = [] - tags = ['Networking'] - annotations = ( - ('fieldnames-and-values', 'XFP structure field names and values'), - ('fields', 'XFP structure fields'), - ) - - def __init__(self): - self.reset() - - def reset(self): - # Received data items, used as an index into samplenum/data - self.cnt = -1 - # Start/end sample numbers per data item - self.sn = [] - # Multi-byte structure buffer - self.buf = [] - # Filled in by address 0x7f in low memory - self.cur_highmem_page = 0 - # Filled in by extended ID value in table 2 - self.have_clei = False - # Handlers for each field in the structure, keyed by the end - # index of that field. Each handler is fed all unhandled bytes - # up until that point, so mark unused space with the dummy - # handler self.ignore(). - self.MAP_LOWER_MEMORY = { - 0: self.module_id, - 1: self.signal_cc, - 57: self.alarm_warnings, - 59: self.vps, - 69: self.ignore, - 71: self.ber, - 75: self.wavelength_cr, - 79: self.fec_cr, - 95: self.int_ctrl, - 109: self.ad_readout, - 111: self.gcs, - 117: self.ignore, - 118: self.ignore, - 122: self.ignore, - 126: self.ignore, - 127: self.page_select, - } - self.MAP_HIGH_TABLE_1 = { - 128: self.module_id, - 129: self.ext_module_id, - 130: self.connector, - 138: self.transceiver, - 139: self.serial_encoding, - 140: self.br_min, - 141: self.br_max, - 142: self.link_length_smf, - 143: self.link_length_e50, - 144: self.link_length_50um, - 145: self.link_length_625um, - 146: self.link_length_copper, - 147: self.device_tech, - 163: self.vendor, - 164: self.cdr, - 167: self.vendor_oui, - 183: self.vendor_pn, - 185: self.vendor_rev, - 187: self.wavelength, - 189: self.wavelength_tolerance, - 190: self.max_case_temp, - 191: self.ignore, - 195: self.power_supply, - 211: self.vendor_sn, - 219: self.manuf_date, - 220: self.diag_mon, - 221: self.enhanced_opts, - 222: self.aux_mon, - 223: self.ignore, - 255: self.maybe_ascii, - } - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def decode(self, ss, es, data): - cmd, data = data - - # We only care about actual data bytes that are read (for now). - if cmd != 'DATA READ': - return - - self.cnt += 1 - self.sn.append([ss, es]) - - self.buf.append(data) - if self.cnt < 0x80: - if self.cnt in self.MAP_LOWER_MEMORY: - self.MAP_LOWER_MEMORY[self.cnt](self.buf) - self.buf.clear() - elif self.cnt < 0x0100 and self.cur_highmem_page == 0x01: - # Serial ID memory map - if self.cnt in self.MAP_HIGH_TABLE_1: - self.MAP_HIGH_TABLE_1[self.cnt](self.buf) - self.buf.clear() - - # Annotation helper - def annotate(self, key, value, start_cnt=None, end_cnt=None): - if start_cnt is None: - start_cnt = self.cnt - len(self.buf) + 1 - if end_cnt is None: - end_cnt = self.cnt - self.put(self.sn[start_cnt][0], self.sn[end_cnt][1], - self.out_ann, [0, [key + ": " + value]]) - self.put(self.sn[start_cnt][0], self.sn[end_cnt][1], - self.out_ann, [1, [value]]) - - # Placeholder handler, needed to advance the buffer past unused or - # reserved space in the structures. - def ignore(self, data): - pass - - # Show as ASCII if possible - def maybe_ascii(self, data): - for i in range(len(data)): - if data[i] >= 0x20 and data[i] < 0x7f: - cnt = self.cnt - len(data) + 1 - self.annotate("Vendor ID", chr(data[i]), cnt, cnt) - - # Convert 16-bit two's complement values, with each increment - # representing 1/256C, to degrees Celsius. - def to_temp(self, value): - if value & 0x8000: - value = -((value ^ 0xffff) + 1) - temp = value / 256.0 - return "%.1f C" % temp - - # TX bias current in uA. Each increment represents 0.2uA - def to_current(self, value): - current = value / 500000.0 - return "%.1f mA" % current - - # Power in mW, with each increment representing 0.1uW - def to_power(self, value): - power = value / 10000.0 - return "%.2f mW" % power - - # Wavelength in increments of 0.05nm - def to_wavelength(self, value): - wl = value / 20 - return "%d nm" % wl - - # Wavelength in increments of 0.005nm - def to_wavelength_tolerance(self, value): - wl = value / 200.0 - return "%.1f nm" % wl - - def module_id(self, data): - self.annotate("Module identifier", MODULE_ID.get(data[0], "Unknown")) - - def signal_cc(self, data): - # No good data available. - if (data[0] != 0x00): - self.annotate("Signal Conditioner Control", "%.2x" % data[0]) - - def alarm_warnings(self, data): - cnt_idx = self.cnt - len(data) - idx = 0 - while idx < 56: - if idx == 8: - # Skip over reserved A/D flag thresholds - idx += 8 - value = (data[idx] << 8) | data[idx + 1] - if value != 0: - name = ALARM_THRESHOLDS.get(idx, "...") - if idx in (0, 2, 4, 6): - self.annotate(name, self.to_temp(value), - cnt_idx + idx, cnt_idx + idx + 1) - elif idx in (16, 18, 20, 22): - self.annotate(name, self.to_current(value), - cnt_idx + idx, cnt_idx + idx + 1) - elif idx in (24, 26, 28, 30, 32, 34, 36, 38): - self.annotate(name, self.to_power(value), - cnt_idx + idx, cnt_idx + idx + 1) - else: - self.annotate(name, "%d" % name, value, cnt_idx + idx, - cnt_idx + idx + 1) - idx += 2 - - def vps(self, data): - # No good data available. - if (data != [0, 0]): - self.annotate("VPS", "%.2x%.2x" % (data[0], data[1])) - - def ber(self, data): - # No good data available. - if (data != [0, 0]): - self.annotate("BER", str(data)) - - def wavelength_cr(self, data): - # No good data available. - if (data != [0, 0, 0, 0]): - self.annotate("WCR", str(data)) - - def fec_cr(self, data): - if (data != [0, 0, 0, 0]): - self.annotate("FEC", str(data)) - - def int_ctrl(self, data): - # No good data available. Also boring. - out = [] - for d in data: - out.append("%.2x" % d) - self.annotate("Interrupt bits", ' '.join(out)) - - def ad_readout(self, data): - cnt_idx = self.cnt - len(data) + 1 - idx = 0 - while idx < 14: - if idx == 2: - # Skip over reserved field - idx += 2 - value = (data[idx] << 8) | data[idx + 1] - name = AD_READOUTS.get(idx, "...") - if value != 0: - if idx == 0: - self.annotate(name, self.to_temp(value), - cnt_idx + idx, cnt_idx + idx + 1) - elif idx == 4: - self.annotate(name, self.to_current(value), - cnt_idx + idx, cnt_idx + idx + 1) - elif idx in (6, 8): - self.annotate(name, self.to_power(value), - cnt_idx + idx, cnt_idx + idx + 1) - else: - self.annotate(name, str(value), cnt_idx + idx, - cnt_idx + idx + 1) - idx += 2 - - def gcs(self, data): - allbits = (data[0] << 8) | data[1] - out = [] - for b in range(13): - if allbits & 0x8000: - out.append(GCS_BITS[b]) - allbits <<= 1 - self.annotate("General Control/Status", ', '.join(out)) - - def page_select(self, data): - self.cur_highmem_page = data[0] - - def ext_module_id(self, data): - out = ["Power level %d module" % ((data[0] >> 6) + 1)] - if data[0] & 0x20 == 0: - out.append("CDR") - if data[0] & 0x10 == 0: - out.append("TX ref clock input required") - if data[0] & 0x08 == 0: - self.have_clei = True - self.annotate("Extended id", ', '.join(out)) - - def connector(self, data): - if data[0] in CONNECTOR: - self.annotate("Connector", CONNECTOR[data[0]]) - - def transceiver(self, data): - out = [] - for t in range(8): - if data[t] == 0: - continue - value = data[t] - for b in range(8): - if value & 0x80: - if len(TRANSCEIVER[t]) < b + 1: - out.append("(unknown)") - else: - out.append(TRANSCEIVER[t][b]) - value <<= 1 - self.annotate("Transceiver compliance", ', '.join(out)) - - def serial_encoding(self, data): - out = [] - value = data[0] - for b in range(8): - if value & 0x80: - if len(SERIAL_ENCODING) < b + 1: - out.append("(unknown)") - else: - out.append(SERIAL_ENCODING[b]) - value <<= 1 - self.annotate("Serial encoding support", ', '.join(out)) - - def br_min(self, data): - # Increments represent 100Mb/s - rate = data[0] / 10.0 - self.annotate("Minimum bit rate", "%.3f GB/s" % rate) - - def br_max(self, data): - # Increments represent 100Mb/s - rate = data[0] / 10.0 - self.annotate("Maximum bit rate", "%.3f GB/s" % rate) - - def link_length_smf(self, data): - if data[0] == 0: - length = "(standard)" - elif data[0] == 255: - length = "> 254 km" - else: - length = "%d km" % data[0] - self.annotate("Link length (SMF)", length) - - def link_length_e50(self, data): - if data[0] == 0: - length = "(standard)" - elif data[0] == 255: - length = "> 508 m" - else: - length = "%d m" % (data[0] * 2) - self.annotate("Link length (extended, 50μm MMF)", length) - - def link_length_50um(self, data): - if data[0] == 0: - length = "(standard)" - elif data[0] == 255: - length = "> 254 m" - else: - length = "%d m" % data[0] - self.annotate("Link length (50μm MMF)", length) - - def link_length_625um(self, data): - if data[0] == 0: - length = "(standard)" - elif data[0] == 255: - length = "> 254 m" - else: - length = "%d m" % (data[0]) - self.annotate("Link length (62.5μm MMF)", length) - - def link_length_copper(self, data): - if data[0] == 0: - length = "(unknown)" - elif data[0] == 255: - length = "> 254 m" - else: - length = "%d m" % (data[0] * 2) - self.annotate("Link length (copper)", length) - - def device_tech(self, data): - out = [] - xmit = data[0] >> 4 - if xmit <= len(XMIT_TECH) - 1: - out.append("%s transmitter" % XMIT_TECH[xmit]) - dev = data[0] & 0x0f - for b in range(4): - out.append(DEVICE_TECH[b][(dev >> (3 - b)) & 0x01]) - self.annotate("Device technology", ', '.join(out)) - - def vendor(self, data): - name = bytes(data).strip().decode('ascii').strip('\x00') - if name: - self.annotate("Vendor", name) - - def cdr(self, data): - out = [] - value = data[0] - for b in range(8): - if value & 0x80: - out.append(CDR[b]) - value <<= 1 - self.annotate("CDR support", ', '.join(out)) - - def vendor_oui(self, data): - if data != [0, 0, 0]: - self.annotate("Vendor OUI", "%.2X-%.2X-%.2X" % tuple(data)) - - def vendor_pn(self, data): - name = bytes(data).strip().decode('ascii').strip('\x00') - if name: - self.annotate("Vendor part number", name) - - def vendor_rev(self, data): - name = bytes(data).strip().decode('ascii').strip('\x00') - if name: - self.annotate("Vendor revision", name) - - def wavelength(self, data): - value = (data[0] << 8) | data[1] - self.annotate("Wavelength", self.to_wavelength(value)) - - def wavelength_tolerance(self, data): - value = (data[0] << 8) | data[1] - self.annotate("Wavelength tolerance", self.to_wavelength_tolerance(value)) - - def max_case_temp(self, data): - self.annotate("Maximum case temperature", "%d C" % data[0]) - - def power_supply(self, data): - out = [] - self.annotate("Max power dissipation", - "%.3f W" % (data[0] * 0.02), self.cnt - 3, self.cnt - 3) - self.annotate("Max power dissipation (powered down)", - "%.3f W" % (data[1] * 0.01), self.cnt - 2, self.cnt - 2) - value = (data[2] >> 4) * 0.050 - self.annotate("Max current required (5V supply)", - "%.3f A" % value, self.cnt - 1, self.cnt - 1) - value = (data[2] & 0x0f) * 0.100 - self.annotate("Max current required (3.3V supply)", - "%.3f A" % value, self.cnt - 1, self.cnt - 1) - value = (data[3] >> 4) * 0.100 - self.annotate("Max current required (1.8V supply)", - "%.3f A" % value, self.cnt, self.cnt) - value = (data[3] & 0x0f) * 0.050 - self.annotate("Max current required (-5.2V supply)", - "%.3f A" % value, self.cnt, self.cnt) - - def vendor_sn(self, data): - name = bytes(data).strip().decode('ascii').strip('\x00') - if name: - self.annotate("Vendor serial number", name) - - def manuf_date(self, data): - y = int(bytes(data[0:2])) + 2000 - m = int(bytes(data[2:4])) - d = int(bytes(data[4:6])) - mnf = "%.4d-%.2d-%.2d" % (y, m, d) - lot = bytes(data[6:]).strip().decode('ascii').strip('\x00') - if lot: - mnf += " lot " + lot - self.annotate("Manufacturing date", mnf) - - def diag_mon(self, data): - out = [] - if data[0] & 0x10: - out.append("BER support") - else: - out.append("no BER support") - if data[0] & 0x08: - out.append("average power measurement") - else: - out.append("OMA power measurement") - self.annotate("Diagnostic monitoring", ', '.join(out)) - - def enhanced_opts(self, data): - out = [] - value = data[0] - for b in range(8): - if value & 0x80: - out.append(ENHANCED_OPTS[b]) - value <<= 1 - self.annotate("Enhanced option support", ', '.join(out)) - - def aux_mon(self, data): - aux = AUX_TYPES[data[0] >> 4] - self.annotate("AUX1 monitoring", aux) - aux = AUX_TYPES[data[0] & 0x0f] - self.annotate("AUX2 monitoring", aux) diff --git a/decoders/xy2-100/__init__.py b/decoders/xy2-100/__init__.py deleted file mode 100644 index 676e1aff..00000000 --- a/decoders/xy2-100/__init__.py +++ /dev/null @@ -1,28 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Uli Huber -## -## 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, see . -## - -''' -XY2-100 is a serial bus for connecting galvo systems to controllers - -Details: - -http://www.newson.be/doc.php?id=XY2-100 -''' - -from .pd import Decoder diff --git a/decoders/xy2-100/pd.py b/decoders/xy2-100/pd.py deleted file mode 100644 index 47c4182c..00000000 --- a/decoders/xy2-100/pd.py +++ /dev/null @@ -1,242 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2019 Uli Huber -## Copyright (C) 2020 Soeren Apel -## -## 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, see . -## - -import sigrokdecode as srd - -ann_bit, ann_stat_bit, ann_type, ann_command, ann_parameter, ann_parity, ann_pos, ann_status, ann_warning = range(9) -frame_type_none, frame_type_command, frame_type_16bit_pos, frame_type_18bit_pos = range(4) - -class Decoder(srd.Decoder): - api_version = 3 - id = 'xy2-100' - name = 'XY2-100' - longname = 'XY2-100(E) and XY-200(E) galvanometer protocol' - desc = 'Serial protocol for galvanometer positioning in laser systems' - license = 'gplv2+' - inputs = ['logic'] - outputs = [] - - tags = ['Embedded/industrial'] - - channels = ( - {'id': 'clk', 'name': 'CLK', 'desc': 'Clock'}, - {'id': 'sync', 'name': 'SYNC', 'desc': 'Sync'}, - {'id': 'data', 'name': 'DATA', 'desc': 'X, Y or Z axis data'}, - ) - optional_channels = ( - {'id': 'status', 'name': 'STAT', 'desc': 'X, Y or Z axis status'}, - ) - - annotations = ( - ('bit', 'Data Bit'), - ('stat_bit', 'Status Bit'), - ('type', 'Frame Type'), - ('command', 'Command'), - ('parameter', 'Parameter'), - ('parity', 'Parity'), - ('position', 'Position'), - ('status', 'Status'), - ('warning', 'Human-readable warnings'), - ) - annotation_rows = ( - ('bits', 'Data Bits', (ann_bit,)), - ('stat_bits', 'Status Bits', (ann_stat_bit,)), - ('data', 'Data', (ann_type, ann_command, ann_parameter, ann_parity)), - ('positions', 'Positions', (ann_pos,)), - ('statuses', 'Statuses', (ann_status,)), - ('warnings', 'Warnings', (ann_warning,)), - ) - - def __init__(self): - self.samplerate = None - self.reset() - - def reset(self): - self.bits = [] - self.stat_bits = [] - self.stat_skip_bit = True - - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - - def put_ann(self, ss, es, ann_class, value): - self.put(ss, es, self.out_ann, [ann_class, value]) - - def process_bit(self, sync, bit_ss, bit_es, bit_value): - self.put_ann(bit_ss, bit_es, ann_bit, ['%d' % bit_value]) - self.bits.append((bit_ss, bit_es, bit_value)) - - if sync == 0: - if len(self.bits) < 20: - self.put_ann(self.bits[0][0], bit_es, ann_warning, ['Not enough data bits']) - self.reset() - return - - # Bit structure: - # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 - # T --------------- 18-bit pos ----------------- PARITY or - # -TYPE-- ------------ 16-bit pos -------------- PARITY or - # -TYPE-- -8-bit command -8-bit parameter value- PARITY - - # Calculate parity, excluding the parity bit itself - parity = 0 - for ss, es, value in self.bits[:-1]: - parity ^= value - - par_ss, par_es, par_value = self.bits[19] - parity_even = 0 - parity_odd = 0 - if (par_value == parity): - parity_even = 1 - else: - parity_odd = 1 - - type_1_value = self.bits[0][2] - type_3_value = (self.bits[0][2] << 2) | (self.bits[1][2] << 1) | self.bits[2][2] - - # Determine frame type - type = frame_type_none - parity_status = ['X', 'Unknown'] - type_ss = self.bits[0][0] - type_es = self.bits[2][1] - - ### 18-bit position - if (type_1_value == 1) and (parity_odd == 1): - type = frame_type_18bit_pos - type_es = self.bits[0][1] - self.put_ann(self.bits[0][0], bit_es, ann_warning, ['Careful: 18-bit position frames with wrong parity and command frames with wrong parity cannot be identified']) - ### 16-bit position - elif (type_3_value == 1): - type = frame_type_16bit_pos - if (parity_even == 1): - parity_status = ['OK'] - else: - parity_status = ['NOK'] - self.put_ann(self.bits[0][0], bit_es, ann_warning, ['Parity error', 'PE']) - ### Command - elif (type_3_value == 7) and (parity_even == 1): - type = frame_type_command - self.put_ann(self.bits[0][0], bit_es, ann_warning, ['Careful: 18-bit position frames with wrong parity and command frames with wrong parity cannot be identified']) - ### Other - else: - self.put_ann(self.bits[0][0], bit_es, ann_warning, ['Error', 'Unknown command or parity error']) - self.reset() - return - - # Output command and parity annotations - if (type == frame_type_16bit_pos): - self.put_ann(type_ss, type_es, ann_type, ['16 bit Position Frame', '16 bit Pos', 'Pos', 'P']) - if (type == frame_type_18bit_pos): - self.put_ann(type_ss, type_es, ann_type, ['18 bit Position Frame', '18 bit Pos', 'Pos', 'P']) - if (type == frame_type_command): - self.put_ann(type_ss, type_es, ann_type, ['Command Frame', 'Command', 'C']) - - self.put_ann(par_ss, par_es, ann_parity, parity_status) - - # Output value - if (type == frame_type_16bit_pos) or (type == frame_type_18bit_pos): - pos = 0 - - if (type == frame_type_16bit_pos): - count = 15 - for ss, es, value in self.bits[3:19]: - pos |= value << count - count -= 1 - pos = pos if pos < 32768 else pos - 65536 - else: - count = 17 - for ss, es, value in self.bits[3:19]: - pos |= value << count - count -= 1 - pos = pos if pos < 131072 else pos - 262144 - - self.put_ann(type_es, par_ss, ann_pos, ['%d' % pos]) - - if (type == frame_type_command): - count = 7 - cmd = 0 - cmd_es = 0 - for ss, es, value in self.bits[3:11]: - cmd |= value << count - count -= 1 - cmd_es = es - self.put_ann(type_es, cmd_es, ann_command, ['Command 0x%X' % cmd, 'Cmd 0x%X' % cmd, '0x%X' % cmd]) - - count = 7 - param = 0 - for ss, es, value in self.bits[11:19]: - param |= value << count - count -= 1 - self.put_ann(cmd_es, par_ss, ann_parameter, ['Parameter 0x%X / %d' % (param, param), '0x%X / %d' % (param, param),'0x%X' % param]) - - self.reset() - - def process_stat_bit(self, sync, bit_ss, bit_es, bit_value): - if self.stat_skip_bit: - self.stat_skip_bit = False - return - - self.put_ann(bit_ss, bit_es, ann_stat_bit, ['%d' % bit_value]) - self.stat_bits.append((bit_ss, bit_es, bit_value)) - - if (sync == 0) and (len(self.stat_bits) == 19): - stat_ss = self.stat_bits[0][0] - stat_es = self.stat_bits[18][1] - - status = 0 - count = 18 - for ss, es, value in self.stat_bits: - status |= value << count - count -= 1 - self.put_ann(stat_ss, stat_es, ann_status, ['Status 0x%X' % status, '0x%X' % status]) - - def decode(self): - bit_ss = None - bit_es = None - bit_value = 0 - stat_ss = None - stat_es = None - stat_value = 0 - sync_value = 0 - has_stat = self.has_channel(3) - - while True: - # Wait for any edge on clk - clk, sync, data, stat = self.wait({0: 'e'}) - - if clk == 1: - stat_value = stat - - bit_es = self.samplenum - if bit_ss: - self.process_bit(sync_value, bit_ss, bit_es, bit_value) - bit_ss = self.samplenum - else: - bit_value = data - sync_value = sync - - stat_es = self.samplenum - if stat_ss and has_stat: - self.process_stat_bit(sync_value, stat_ss, stat_es, stat_value) - stat_ss = self.samplenum diff --git a/decoders/z80/__init__.py b/decoders/z80/__init__.py deleted file mode 100755 index 52ff9bac..00000000 --- a/decoders/z80/__init__.py +++ /dev/null @@ -1,36 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Daniel Elstner -## -## 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 . -## - -''' -The Zilog Z80 is an 8-bit microprocessor compatible with the Intel 8080. - -In addition to the 8-bit data bus, this decoder requires the input signals -/M1 (machine cycle), /RD (read) and /WR (write) to do its work. An explicit -clock signal is not required. However, the Z80 CPU clock may be used as -sampling clock, if applicable. - -Notes on the Z80 opcode format and descriptions of both documented and -"undocumented" opcodes are available here: - -Details: -http://www.z80.info/decoding.htm -http://clrhome.org/table/ -''' - -from .pd import Decoder diff --git a/decoders/z80/pd.py b/decoders/z80/pd.py deleted file mode 100755 index 9af310e2..00000000 --- a/decoders/z80/pd.py +++ /dev/null @@ -1,359 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Daniel Elstner -## -## 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 . -## - -import sigrokdecode as srd -from functools import reduce -from .tables import instr_table_by_prefix -import string - -class Ann: - ADDR, MEMRD, MEMWR, IORD, IOWR, INSTR, ROP, WOP, WARN = range(9) -class Row: - ADDRBUS, DATABUS, INSTRUCTIONS, OPERANDS, WARNINGS = range(5) -class Pin: - D0, D7 = 0, 7 - M1, RD, WR, MREQ, IORQ = range(8, 13) - A0, A15 = 13, 28 -class Cycle: - NONE, MEMRD, MEMWR, IORD, IOWR, FETCH, INTACK = range(7) - -# Provide custom format type 'H' for hexadecimal output -# with leading decimal digit (assembler syntax). -class AsmFormatter(string.Formatter): - def format_field(self, value, format_spec): - if format_spec.endswith('H'): - result = format(value, format_spec[:-1] + 'X') - return result if result[0] in string.digits else '0' + result - else: - return format(value, format_spec) - -formatter = AsmFormatter() - -ann_data_cycle_map = { - Cycle.MEMRD: Ann.MEMRD, - Cycle.MEMWR: Ann.MEMWR, - Cycle.IORD: Ann.IORD, - Cycle.IOWR: Ann.IOWR, - Cycle.FETCH: Ann.MEMRD, - Cycle.INTACK: Ann.IORD, -} - -def reduce_bus(bus): - if 0xFF in bus: - return None # unassigned bus channels - else: - return reduce(lambda a, b: (a << 1) | b, reversed(bus)) - -def signed_byte(byte): - return byte if byte < 128 else byte - 256 - -class Decoder(srd.Decoder): - api_version = 3 - id = 'z80' - name = 'Z80' - longname = 'Zilog Z80 CPU' - desc = 'Zilog Z80 microprocessor disassembly.' - license = 'gplv3+' - inputs = ['logic'] - outputs = [] - tags = ['Retro computing'] - channels = tuple({ - 'id': 'd%d' % i, - 'name': 'D%d' % i, - 'desc': 'Data bus line %d' % i - } for i in range(8) - ) + ( - {'id': 'm1', 'name': '/M1', 'desc': 'Machine cycle 1'}, - {'id': 'rd', 'name': '/RD', 'desc': 'Memory or I/O read'}, - {'id': 'wr', 'name': '/WR', 'desc': 'Memory or I/O write'}, - ) - optional_channels = ( - {'id': 'mreq', 'name': '/MREQ', 'desc': 'Memory request'}, - {'id': 'iorq', 'name': '/IORQ', 'desc': 'I/O request'}, - ) + tuple({ - 'id': 'a%d' % i, - 'name': 'A%d' % i, - 'desc': 'Address bus line %d' % i - } for i in range(16) - ) - annotations = ( - ('addr', 'Memory or I/O address'), - ('memrd', 'Byte read from memory'), - ('memwr', 'Byte written to memory'), - ('iord', 'Byte read from I/O port'), - ('iowr', 'Byte written to I/O port'), - ('instr', 'Z80 CPU instruction'), - ('rop', 'Value of input operand'), - ('wop', 'Value of output operand'), - ('warn', 'Warning message'), - ) - annotation_rows = ( - ('addrbus', 'Address bus', (Ann.ADDR,)), - ('databus', 'Data bus', (Ann.MEMRD, Ann.MEMWR, Ann.IORD, Ann.IOWR)), - ('instructions', 'Instructions', (Ann.INSTR,)), - ('operands', 'Operands', (Ann.ROP, Ann.WOP)), - ('warnings', 'Warnings', (Ann.WARN,)) - ) - - def __init__(self): - self.reset() - - def reset(self): - self.prev_cycle = Cycle.NONE - self.op_state = self.state_IDLE - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.bus_data = None - self.samplenum = None - self.addr_start = None - self.data_start = None - self.dasm_start = None - self.pend_addr = None - self.pend_data = None - self.ann_data = None - self.ann_dasm = None - self.prev_cycle = Cycle.NONE - self.op_state = self.state_IDLE - self.instr_len = 0 - - def decode(self): - while True: - # TODO: Come up with more appropriate self.wait() conditions. - (d0, d1, d2, d3, d4, d5, d6, d7, m1, rd, wr, mreq, iorq, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) = self.wait() - pins = (d0, d1, d2, d3, d4, d5, d6, d7, m1, rd, wr, mreq, iorq, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) - cycle = Cycle.NONE - if pins[Pin.MREQ] != 1: # default to asserted - if pins[Pin.RD] == 0: - cycle = Cycle.FETCH if pins[Pin.M1] == 0 else Cycle.MEMRD - elif pins[Pin.WR] == 0: - cycle = Cycle.MEMWR - elif pins[Pin.IORQ] == 0: # default to not asserted - if pins[Pin.M1] == 0: - cycle = Cycle.INTACK - elif pins[Pin.RD] == 0: - cycle = Cycle.IORD - elif pins[Pin.WR] == 0: - cycle = Cycle.IOWR - - if cycle != Cycle.NONE: - self.bus_data = reduce_bus(pins[Pin.D0:Pin.D7+1]) - if cycle != self.prev_cycle: - if self.prev_cycle == Cycle.NONE: - self.on_cycle_begin(reduce_bus(pins[Pin.A0:Pin.A15+1])) - elif cycle == Cycle.NONE: - self.on_cycle_end() - else: - self.on_cycle_trans() - self.prev_cycle = cycle - - def on_cycle_begin(self, bus_addr): - if self.pend_addr is not None: - self.put_text(self.addr_start, Ann.ADDR, - '{:04X}'.format(self.pend_addr)) - self.addr_start = self.samplenum - self.pend_addr = bus_addr - - def on_cycle_end(self): - self.instr_len += 1 - self.op_state = self.op_state() - if self.ann_dasm is not None: - self.put_disasm() - if self.op_state == self.state_RESTART: - self.op_state = self.state_IDLE() - - if self.ann_data is not None: - self.put_text(self.data_start, self.ann_data, - '{:02X}'.format(self.pend_data)) - self.data_start = self.samplenum - self.pend_data = self.bus_data - self.ann_data = ann_data_cycle_map[self.prev_cycle] - - def on_cycle_trans(self): - self.put_text(self.samplenum - 1, Ann.WARN, - 'Illegal transition between control states') - self.pend_addr = None - self.ann_data = None - self.ann_dasm = None - - def put_disasm(self): - text = formatter.format(self.mnemonic, r=self.arg_reg, d=self.arg_dis, - j=self.arg_dis+self.instr_len, i=self.arg_imm, - ro=self.arg_read, wo=self.arg_write) - self.put_text(self.dasm_start, self.ann_dasm, text) - self.ann_dasm = None - self.dasm_start = self.samplenum - - def put_text(self, ss, ann_idx, ann_text): - self.put(ss, self.samplenum, self.out_ann, [ann_idx, [ann_text]]) - - def state_RESTART(self): - return self.state_IDLE - - def state_IDLE(self): - if self.prev_cycle != Cycle.FETCH: - return self.state_IDLE - self.want_dis = 0 - self.want_imm = 0 - self.want_read = 0 - self.want_write = 0 - self.want_wr_be = False - self.op_repeat = False - self.arg_dis = 0 - self.arg_imm = 0 - self.arg_read = 0 - self.arg_write = 0 - self.arg_reg = '' - self.mnemonic = '' - self.instr_pend = False - self.read_pend = False - self.write_pend = False - self.dasm_start = self.samplenum - self.op_prefix = 0 - self.instr_len = 0 - if self.bus_data in (0xCB, 0xED, 0xDD, 0xFD): - return self.state_PRE1 - else: - return self.state_OPCODE - - def state_PRE1(self): - if self.prev_cycle != Cycle.FETCH: - self.mnemonic = 'Prefix not followed by fetch' - self.ann_dasm = Ann.WARN - return self.state_RESTART - self.op_prefix = self.pend_data - if self.op_prefix in (0xDD, 0xFD): - if self.bus_data == 0xCB: - return self.state_PRE2 - if self.bus_data in (0xDD, 0xED, 0xFD): - return self.state_PRE1 - return self.state_OPCODE - - def state_PRE2(self): - if self.prev_cycle != Cycle.MEMRD: - self.mnemonic = 'Missing displacement' - self.ann_dasm = Ann.WARN - return self.state_RESTART - self.op_prefix = (self.op_prefix << 8) | self.pend_data - return self.state_PREDIS - - def state_PREDIS(self): - if self.prev_cycle != Cycle.MEMRD: - self.mnemonic = 'Missing opcode' - self.ann_dasm = Ann.WARN - return self.state_RESTART - self.arg_dis = signed_byte(self.pend_data) - return self.state_OPCODE - - def state_OPCODE(self): - (table, self.arg_reg) = instr_table_by_prefix[self.op_prefix] - self.op_prefix = 0 - instruction = table.get(self.pend_data, None) - if instruction is None: - self.mnemonic = 'Invalid instruction' - self.ann_dasm = Ann.WARN - return self.state_RESTART - (self.want_dis, self.want_imm, self.want_read, want_write, - self.op_repeat, self.mnemonic) = instruction - self.want_write = abs(want_write) - self.want_wr_be = (want_write < 0) - if self.want_dis > 0: - return self.state_POSTDIS - if self.want_imm > 0: - return self.state_IMM1 - self.ann_dasm = Ann.INSTR - if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD): - return self.state_ROP1 - if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR): - return self.state_WOP1 - return self.state_RESTART - - def state_POSTDIS(self): - self.arg_dis = signed_byte(self.pend_data) - if self.want_imm > 0: - return self.state_IMM1 - self.ann_dasm = Ann.INSTR - if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD): - return self.state_ROP1 - if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR): - return self.state_WOP1 - return self.state_RESTART - - def state_IMM1(self): - self.arg_imm = self.pend_data - if self.want_imm > 1: - return self.state_IMM2 - self.ann_dasm = Ann.INSTR - if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD): - return self.state_ROP1 - if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR): - return self.state_WOP1 - return self.state_RESTART - - def state_IMM2(self): - self.arg_imm |= self.pend_data << 8 - self.ann_dasm = Ann.INSTR - if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD): - return self.state_ROP1 - if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR): - return self.state_WOP1 - return self.state_RESTART - - def state_ROP1(self): - self.arg_read = self.pend_data - if self.want_read < 2: - self.mnemonic = '{ro:02X}' - self.ann_dasm = Ann.ROP - if self.want_write > 0: - return self.state_WOP1 - if self.want_read > 1: - return self.state_ROP2 - if self.op_repeat and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD): - return self.state_ROP1 - return self.state_RESTART - - def state_ROP2(self): - self.arg_read |= self.pend_data << 8 - self.mnemonic = '{ro:04X}' - self.ann_dasm = Ann.ROP - if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR): - return self.state_WOP1 - return self.state_RESTART - - def state_WOP1(self): - self.arg_write = self.pend_data - if self.want_read > 1: - return self.state_ROP2 - if self.want_write > 1: - return self.state_WOP2 - self.mnemonic = '{wo:02X}' - self.ann_dasm = Ann.WOP - if self.want_read > 0 and self.op_repeat and \ - self.prev_cycle in (Cycle.MEMRD, Cycle.IORD): - return self.state_ROP1 - return self.state_RESTART - - def state_WOP2(self): - if self.want_wr_be: - self.arg_write = (self.arg_write << 8) | self.pend_data - else: - self.arg_write |= self.pend_data << 8 - self.mnemonic = '{wo:04X}' - self.ann_dasm = Ann.WOP - return self.state_RESTART diff --git a/decoders/z80/tables.py b/decoders/z80/tables.py deleted file mode 100755 index ec77dae3..00000000 --- a/decoders/z80/tables.py +++ /dev/null @@ -1,1083 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2014 Daniel Elstner -## -## 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 . -## - -''' -Instruction tuple: (d, i, ro, wo, rep, format string) - - The placeholders d and i are the number of bytes in the instruction - used for the displacement and the immediate operand, respectively. An - operand consisting of more than one byte is assembled in little endian - order. - The placeholders ro and wo are the number of bytes the instruction - is expected to read or write, respectively. These counts are used - for both memory and I/O access, but not for immediate operands. - A negative value indicates that the operand byte order is big endian - rather than the usual little endian. - The placeholder rep is a boolean used to mark repeating instructions. - The format string should refer to the {d} and {i} operands by name. - Displacements are interpreted as signed integers, whereas immediate - operands are always read as unsigned. The tables for instructions - operating on the IX/IY index registers additionally use {r} in the - format string as a placeholder for the register name. - Relative jump instructions may specify {j} instead of {d} to output - the displacement relative to the start of the instruction. -''' - -# Instructions without a prefix -main_instructions = { - 0x00: (0, 0, 0, 0, False, 'NOP'), - 0x01: (0, 2, 0, 0, False, 'LD BC,{i:04H}h'), - 0x02: (0, 0, 0, 1, False, 'LD (BC),A'), - 0x03: (0, 0, 0, 0, False, 'INC BC'), - 0x04: (0, 0, 0, 0, False, 'INC B'), - 0x05: (0, 0, 0, 0, False, 'DEC B'), - 0x06: (0, 1, 0, 0, False, 'LD B,{i:02H}h'), - 0x07: (0, 0, 0, 0, False, 'RLCA'), - 0x08: (0, 0, 0, 0, False, 'EX AF,AF\''), - 0x09: (0, 0, 0, 0, False, 'ADD HL,BC'), - 0x0A: (0, 0, 1, 0, False, 'LD A,(BC)'), - 0x0B: (0, 0, 0, 0, False, 'DEC BC'), - 0x0C: (0, 0, 0, 0, False, 'INC C'), - 0x0D: (0, 0, 0, 0, False, 'DEC C'), - 0x0E: (0, 1, 0, 0, False, 'LD C,{i:02H}h'), - 0x0F: (0, 0, 0, 0, False, 'RRCA'), - - 0x10: (1, 0, 0, 0, False, 'DJNZ ${j:+d}'), - 0x11: (0, 2, 0, 0, False, 'LD DE,{i:04H}h'), - 0x12: (0, 0, 0, 1, False, 'LD (DE),A'), - 0x13: (0, 0, 0, 0, False, 'INC DE'), - 0x14: (0, 0, 0, 0, False, 'INC D'), - 0x15: (0, 0, 0, 0, False, 'DEC D'), - 0x16: (0, 1, 0, 0, False, 'LD D,{i:02H}h'), - 0x17: (0, 0, 0, 0, False, 'RLA'), - 0x18: (1, 0, 0, 0, False, 'JR ${j:+d}'), - 0x19: (0, 0, 0, 0, False, 'ADD HL,DE'), - 0x1A: (0, 0, 1, 0, False, 'LD A,(DE)'), - 0x1B: (0, 0, 0, 0, False, 'DEC DE'), - 0x1C: (0, 0, 0, 0, False, 'INC E'), - 0x1D: (0, 0, 0, 0, False, 'DEC E'), - 0x1E: (0, 1, 0, 0, False, 'LD E,{i:02H}h'), - 0x1F: (0, 0, 0, 0, False, 'RRA'), - - 0x20: (1, 0, 0, 0, False, 'JR NZ,${j:+d}'), - 0x21: (0, 2, 0, 0, False, 'LD HL,{i:04H}h'), - 0x22: (0, 2, 0, 2, False, 'LD ({i:04H}h),HL'), - 0x23: (0, 0, 0, 0, False, 'INC HL'), - 0x24: (0, 0, 0, 0, False, 'INC H'), - 0x25: (0, 0, 0, 0, False, 'DEC H'), - 0x26: (0, 1, 0, 0, False, 'LD H,{i:02H}h'), - 0x27: (0, 0, 0, 0, False, 'DAA'), - 0x28: (1, 0, 0, 0, False, 'JR Z,${j:+d}'), - 0x29: (0, 0, 0, 0, False, 'ADD HL,HL'), - 0x2A: (0, 2, 2, 0, False, 'LD HL,({i:04H}h)'), - 0x2B: (0, 0, 0, 0, False, 'DEC HL'), - 0x2C: (0, 0, 0, 0, False, 'INC L'), - 0x2D: (0, 0, 0, 0, False, 'DEC L'), - 0x2E: (0, 1, 0, 0, False, 'LD L,{i:02H}h'), - 0x2F: (0, 0, 0, 0, False, 'CPL'), - - 0x30: (1, 0, 0, 0, False, 'JR NC,${j:+d}'), - 0x31: (0, 2, 0, 0, False, 'LD SP,{i:04H}h'), - 0x32: (0, 2, 0, 1, False, 'LD ({i:04H}h),A'), - 0x33: (0, 0, 0, 0, False, 'INC SP'), - 0x34: (0, 0, 1, 1, False, 'INC (HL)'), - 0x35: (0, 0, 1, 1, False, 'DEC (HL)'), - 0x36: (0, 1, 0, 1, False, 'LD (HL),{i:02H}h'), - 0x37: (0, 0, 0, 0, False, 'SCF'), - 0x38: (1, 0, 0, 0, False, 'JR C,${j:+d}'), - 0x39: (0, 0, 0, 0, False, 'ADD HL,SP'), - 0x3A: (0, 2, 1, 0, False, 'LD A,({i:04H}h)'), - 0x3B: (0, 0, 0, 0, False, 'DEC SP'), - 0x3C: (0, 0, 0, 0, False, 'INC A'), - 0x3D: (0, 0, 0, 0, False, 'DEC A'), - 0x3E: (0, 1, 0, 0, False, 'LD A,{i:02H}h'), - 0x3F: (0, 0, 0, 0, False, 'CCF'), - - 0x40: (0, 0, 0, 0, False, 'LD B,B'), - 0x41: (0, 0, 0, 0, False, 'LD B,C'), - 0x42: (0, 0, 0, 0, False, 'LD B,D'), - 0x43: (0, 0, 0, 0, False, 'LD B,E'), - 0x44: (0, 0, 0, 0, False, 'LD B,H'), - 0x45: (0, 0, 0, 0, False, 'LD B,L'), - 0x46: (0, 0, 1, 0, False, 'LD B,(HL)'), - 0x47: (0, 0, 0, 0, False, 'LD B,A'), - 0x48: (0, 0, 0, 0, False, 'LD C,B'), - 0x49: (0, 0, 0, 0, False, 'LD C,C'), - 0x4A: (0, 0, 0, 0, False, 'LD C,D'), - 0x4B: (0, 0, 0, 0, False, 'LD C,E'), - 0x4C: (0, 0, 0, 0, False, 'LD C,H'), - 0x4D: (0, 0, 0, 0, False, 'LD C,L'), - 0x4E: (0, 0, 1, 0, False, 'LD C,(HL)'), - 0x4F: (0, 0, 0, 0, False, 'LD C,A'), - - 0x50: (0, 0, 0, 0, False, 'LD D,B'), - 0x51: (0, 0, 0, 0, False, 'LD D,C'), - 0x52: (0, 0, 0, 0, False, 'LD D,D'), - 0x53: (0, 0, 0, 0, False, 'LD D,E'), - 0x54: (0, 0, 0, 0, False, 'LD D,H'), - 0x55: (0, 0, 0, 0, False, 'LD D,L'), - 0x56: (0, 0, 1, 0, False, 'LD D,(HL)'), - 0x57: (0, 0, 0, 0, False, 'LD D,A'), - 0x58: (0, 0, 0, 0, False, 'LD E,B'), - 0x59: (0, 0, 0, 0, False, 'LD E,C'), - 0x5A: (0, 0, 0, 0, False, 'LD E,D'), - 0x5B: (0, 0, 0, 0, False, 'LD E,E'), - 0x5C: (0, 0, 0, 0, False, 'LD E,H'), - 0x5D: (0, 0, 0, 0, False, 'LD E,L'), - 0x5E: (0, 0, 1, 0, False, 'LD E,(HL)'), - 0x5F: (0, 0, 0, 0, False, 'LD E,A'), - - 0x60: (0, 0, 0, 0, False, 'LD H,B'), - 0x61: (0, 0, 0, 0, False, 'LD H,C'), - 0x62: (0, 0, 0, 0, False, 'LD H,D'), - 0x63: (0, 0, 0, 0, False, 'LD H,E'), - 0x64: (0, 0, 0, 0, False, 'LD H,H'), - 0x65: (0, 0, 0, 0, False, 'LD H,L'), - 0x66: (0, 0, 1, 0, False, 'LD H,(HL)'), - 0x67: (0, 0, 0, 0, False, 'LD H,A'), - 0x68: (0, 0, 0, 0, False, 'LD L,B'), - 0x69: (0, 0, 0, 0, False, 'LD L,C'), - 0x6A: (0, 0, 0, 0, False, 'LD L,D'), - 0x6B: (0, 0, 0, 0, False, 'LD L,E'), - 0x6C: (0, 0, 0, 0, False, 'LD L,H'), - 0x6D: (0, 0, 0, 0, False, 'LD L,L'), - 0x6E: (0, 0, 1, 0, False, 'LD L,(HL)'), - 0x6F: (0, 0, 0, 0, False, 'LD L,A'), - - 0x70: (0, 0, 0, 1, False, 'LD (HL),B'), - 0x71: (0, 0, 0, 1, False, 'LD (HL),C'), - 0x72: (0, 0, 0, 1, False, 'LD (HL),D'), - 0x73: (0, 0, 0, 1, False, 'LD (HL),E'), - 0x74: (0, 0, 0, 1, False, 'LD (HL),H'), - 0x75: (0, 0, 0, 1, False, 'LD (HL),L'), - 0x76: (0, 0, 0, 0, False, 'HALT'), - 0x77: (0, 0, 0, 1, False, 'LD (HL),A'), - 0x78: (0, 0, 0, 0, False, 'LD A,B'), - 0x79: (0, 0, 0, 0, False, 'LD A,C'), - 0x7A: (0, 0, 0, 0, False, 'LD A,D'), - 0x7B: (0, 0, 0, 0, False, 'LD A,E'), - 0x7C: (0, 0, 0, 0, False, 'LD A,H'), - 0x7D: (0, 0, 0, 0, False, 'LD A,L'), - 0x7E: (0, 0, 1, 0, False, 'LD A,(HL)'), - 0x7F: (0, 0, 0, 0, False, 'LD A,A'), - - 0x80: (0, 0, 0, 0, False, 'ADD A,B'), - 0x81: (0, 0, 0, 0, False, 'ADD A,C'), - 0x82: (0, 0, 0, 0, False, 'ADD A,D'), - 0x83: (0, 0, 0, 0, False, 'ADD A,E'), - 0x84: (0, 0, 0, 0, False, 'ADD A,H'), - 0x85: (0, 0, 0, 0, False, 'ADD A,L'), - 0x86: (0, 0, 1, 0, False, 'ADD A,(HL)'), - 0x87: (0, 0, 0, 0, False, 'ADD A,A'), - 0x88: (0, 0, 0, 0, False, 'ADC A,B'), - 0x89: (0, 0, 0, 0, False, 'ADC A,C'), - 0x8A: (0, 0, 0, 0, False, 'ADC A,D'), - 0x8B: (0, 0, 0, 0, False, 'ADC A,E'), - 0x8C: (0, 0, 0, 0, False, 'ADC A,H'), - 0x8D: (0, 0, 0, 0, False, 'ADC A,L'), - 0x8E: (0, 0, 1, 0, False, 'ADC A,(HL)'), - 0x8F: (0, 0, 0, 0, False, 'ADC A,A'), - - 0x90: (0, 0, 0, 0, False, 'SUB B'), - 0x91: (0, 0, 0, 0, False, 'SUB C'), - 0x92: (0, 0, 0, 0, False, 'SUB D'), - 0x93: (0, 0, 0, 0, False, 'SUB E'), - 0x94: (0, 0, 0, 0, False, 'SUB H'), - 0x95: (0, 0, 0, 0, False, 'SUB L'), - 0x96: (0, 0, 1, 0, False, 'SUB (HL)'), - 0x97: (0, 0, 0, 0, False, 'SUB A'), - 0x98: (0, 0, 0, 0, False, 'SBC A,B'), - 0x99: (0, 0, 0, 0, False, 'SBC A,C'), - 0x9A: (0, 0, 0, 0, False, 'SBC A,D'), - 0x9B: (0, 0, 0, 0, False, 'SBC A,E'), - 0x9C: (0, 0, 0, 0, False, 'SBC A,H'), - 0x9D: (0, 0, 0, 0, False, 'SBC A,L'), - 0x9E: (0, 0, 1, 0, False, 'SBC A,(HL)'), - 0x9F: (0, 0, 0, 0, False, 'SBC A,A'), - - 0xA0: (0, 0, 0, 0, False, 'AND B'), - 0xA1: (0, 0, 0, 0, False, 'AND C'), - 0xA2: (0, 0, 0, 0, False, 'AND D'), - 0xA3: (0, 0, 0, 0, False, 'AND E'), - 0xA4: (0, 0, 0, 0, False, 'AND H'), - 0xA5: (0, 0, 0, 0, False, 'AND L'), - 0xA6: (0, 0, 1, 0, False, 'AND (HL)'), - 0xA7: (0, 0, 0, 0, False, 'AND A'), - 0xA8: (0, 0, 0, 0, False, 'XOR B'), - 0xA9: (0, 0, 0, 0, False, 'XOR C'), - 0xAA: (0, 0, 0, 0, False, 'XOR D'), - 0xAB: (0, 0, 0, 0, False, 'XOR E'), - 0xAC: (0, 0, 0, 0, False, 'XOR H'), - 0xAD: (0, 0, 0, 0, False, 'XOR L'), - 0xAE: (0, 0, 1, 0, False, 'XOR (HL)'), - 0xAF: (0, 0, 0, 0, False, 'XOR A'), - - 0xB0: (0, 0, 0, 0, False, 'OR B'), - 0xB1: (0, 0, 0, 0, False, 'OR C'), - 0xB2: (0, 0, 0, 0, False, 'OR D'), - 0xB3: (0, 0, 0, 0, False, 'OR E'), - 0xB4: (0, 0, 0, 0, False, 'OR H'), - 0xB5: (0, 0, 0, 0, False, 'OR L'), - 0xB6: (0, 0, 1, 0, False, 'OR (HL)'), - 0xB7: (0, 0, 0, 0, False, 'OR A'), - 0xB8: (0, 0, 0, 0, False, 'CP B'), - 0xB9: (0, 0, 0, 0, False, 'CP C'), - 0xBA: (0, 0, 0, 0, False, 'CP D'), - 0xBB: (0, 0, 0, 0, False, 'CP E'), - 0xBC: (0, 0, 0, 0, False, 'CP H'), - 0xBD: (0, 0, 0, 0, False, 'CP L'), - 0xBE: (0, 0, 1, 0, False, 'CP (HL)'), - 0xBF: (0, 0, 0, 0, False, 'CP A'), - - 0xC0: (0, 0, 2, 0, False, 'RET NZ'), - 0xC1: (0, 0, 2, 0, False, 'POP BC'), - 0xC2: (0, 2, 0, 0, False, 'JP NZ,{i:04H}h'), - 0xC3: (0, 2, 0, 0, False, 'JP {i:04H}h'), - 0xC4: (0, 2, 0,-2, False, 'CALL NZ,{i:04H}h'), - 0xC5: (0, 0, 0,-2, False, 'PUSH BC'), - 0xC6: (0, 1, 0, 0, False, 'ADD A,{i:02H}h'), - 0xC7: (0, 0, 0,-2, False, 'RST 00h'), - 0xC8: (0, 0, 2, 0, False, 'RET Z'), - 0xC9: (0, 0, 2, 0, False, 'RET'), - 0xCA: (0, 2, 0, 0, False, 'JP Z,{i:04H}h'), - - 0xCC: (0, 2, 0,-2, False, 'CALL Z,{i:04H}h'), - 0xCD: (0, 2, 0,-2, False, 'CALL {i:04H}h'), - 0xCE: (0, 1, 0, 0, False, 'ADC A,{i:02H}h'), - 0xCF: (0, 0, 0,-2, False, 'RST 08h'), - - 0xD0: (0, 0, 2, 0, False, 'RET NC'), - 0xD1: (0, 0, 2, 0, False, 'POP DE'), - 0xD2: (0, 2, 0, 0, False, 'JP NC,{i:04H}h'), - 0xD3: (0, 1, 0, 1, False, 'OUT ({i:02H}h),A'), - 0xD4: (0, 2, 0,-2, False, 'CALL NC,{i:04H}h'), - 0xD5: (0, 0, 0,-2, False, 'PUSH DE'), - 0xD6: (0, 1, 0, 0, False, 'SUB {i:02H}h'), - 0xD7: (0, 0, 0,-2, False, 'RST 10h'), - 0xD8: (0, 0, 2, 0, False, 'RET C'), - 0xD9: (0, 0, 0, 0, False, 'EXX'), - 0xDA: (0, 2, 0, 0, False, 'JP C,{i:04H}h'), - 0xDB: (0, 1, 1, 0, False, 'IN A,({i:02H}h)'), - 0xDC: (0, 2, 0,-2, False, 'CALL C,{i:04H}h'), - - 0xDE: (0, 1, 0, 0, False, 'SBC A,{i:02H}h'), - 0xDF: (0, 0, 0,-2, False, 'RST 18h'), - - 0xE0: (0, 0, 2, 0, False, 'RET PO'), - 0xE1: (0, 0, 2, 0, False, 'POP HL'), - 0xE2: (0, 2, 0, 0, False, 'JP PO,{i:04H}h'), - 0xE3: (0, 0, 2, 2, False, 'EX (SP),HL'), - 0xE4: (0, 2, 0,-2, False, 'CALL PO,{i:04H}h'), - 0xE5: (0, 0, 0,-2, False, 'PUSH HL'), - 0xE6: (0, 1, 0, 0, False, 'AND {i:02H}h'), - 0xE7: (0, 0, 0,-2, False, 'RST 20h'), - 0xE8: (0, 0, 2, 0, False, 'RET PE'), - 0xE9: (0, 0, 0, 0, False, 'JP (HL)'), - 0xEA: (0, 2, 0, 0, False, 'JP PE,{i:04H}h'), - 0xEB: (0, 0, 0, 0, False, 'EX DE,HL'), - 0xEC: (0, 2, 0,-2, False, 'CALL PE,{i:04H}h'), - - 0xEE: (0, 1, 0, 0, False, 'XOR {i:02H}h'), - 0xEF: (0, 0, 0,-2, False, 'RST 28h'), - - 0xF0: (0, 0, 2, 0, False, 'RET P'), - 0xF1: (0, 0, 2, 0, False, 'POP AF'), - 0xF2: (0, 2, 0, 0, False, 'JP P,{i:04H}h'), - 0xF3: (0, 0, 0, 0, False, 'DI'), - 0xF4: (0, 2, 0,-2, False, 'CALL P,{i:04H}h'), - 0xF5: (0, 0, 0,-2, False, 'PUSH AF'), - 0xF6: (0, 1, 0, 0, False, 'OR {i:02H}h'), - 0xF7: (0, 0, 0,-2, False, 'RST 30h'), - 0xF8: (0, 0, 2, 0, False, 'RET M'), - 0xF9: (0, 0, 0, 0, False, 'LD SP,HL'), - 0xFA: (0, 2, 0, 0, False, 'JP M,{i:04H}h'), - 0xFB: (0, 0, 0, 0, False, 'EI'), - 0xFC: (0, 2, 0,-2, False, 'CALL M,{i:04H}h'), - - 0xFE: (0, 1, 0, 0, False, 'CP {i:02H}h'), - 0xFF: (0, 0, 0,-2, False, 'RST 38h') -} - -# Instructions with ED prefix -extended_instructions = { - 0x40: (0, 0, 1, 0, False, 'IN B,(C)'), - 0x41: (0, 0, 0, 1, False, 'OUT (C),B'), - 0x42: (0, 0, 0, 0, False, 'SBC HL,BC'), - 0x43: (0, 2, 0, 2, False, 'LD ({i:04H}h),BC'), - 0x44: (0, 0, 0, 0, False, 'NEG'), - 0x45: (0, 0, 2, 0, False, 'RETN'), - 0x46: (0, 0, 0, 0, False, 'IM 0'), - 0x47: (0, 0, 0, 0, False, 'LD I,A'), - 0x48: (0, 0, 1, 0, False, 'IN C,(C)'), - 0x49: (0, 0, 0, 1, False, 'OUT (C),C'), - 0x4A: (0, 0, 0, 0, False, 'ADC HL,BC'), - 0x4B: (0, 2, 2, 0, False, 'LD BC,({i:04H}h)'), - 0x4C: (0, 0, 0, 0, False, 'NEG'), - 0x4D: (0, 0, 2, 0, False, 'RETI'), - 0x4E: (0, 0, 0, 0, False, 'IM 0/1'), - 0x4F: (0, 0, 0, 0, False, 'LD R,A'), - - 0x50: (0, 0, 1, 0, False, 'IN D,(C)'), - 0x51: (0, 0, 0, 1, False, 'OUT (C),D'), - 0x52: (0, 0, 0, 0, False, 'SBC HL,DE'), - 0x53: (0, 2, 0, 2, False, 'LD ({i:04H}h),DE'), - 0x54: (0, 0, 0, 0, False, 'NEG'), - 0x55: (0, 0, 2, 0, False, 'RETN'), - 0x56: (0, 0, 0, 0, False, 'IM 1'), - 0x57: (0, 0, 0, 0, False, 'LD A,I'), - 0x58: (0, 0, 1, 0, False, 'IN E,(C)'), - 0x59: (0, 0, 0, 1, False, 'OUT (C),E'), - 0x5A: (0, 0, 0, 0, False, 'ADC HL,DE'), - 0x5B: (0, 2, 2, 0, False, 'LD DE,({i:04H}h)'), - 0x5C: (0, 0, 0, 0, False, 'NEG'), - 0x5D: (0, 0, 2, 0, False, 'RETN'), - 0x5E: (0, 0, 0, 0, False, 'IM 2'), - 0x5F: (0, 0, 0, 0, False, 'LD A,R'), - - 0x60: (0, 0, 1, 0, False, 'IN H,(C)'), - 0x61: (0, 0, 0, 1, False, 'OUT (C),H'), - 0x62: (0, 0, 0, 0, False, 'SBC HL,HL'), - 0x63: (0, 2, 0, 2, False, 'LD ({i:04H}h),HL'), - 0x64: (0, 0, 0, 0, False, 'NEG'), - 0x65: (0, 0, 2, 0, False, 'RETN'), - 0x66: (0, 0, 0, 0, False, 'IM 0'), - 0x67: (0, 0, 1, 1, False, 'RRD'), - 0x68: (0, 0, 1, 0, False, 'IN L,(C)'), - 0x69: (0, 0, 0, 1, False, 'OUT (C),L'), - 0x6A: (0, 0, 0, 0, False, 'ADC HL,HL'), - 0x6B: (0, 2, 2, 0, False, 'LD HL,({i:04H}h)'), - 0x6C: (0, 0, 0, 0, False, 'NEG'), - 0x6D: (0, 0, 2, 0, False, 'RETN'), - 0x6E: (0, 0, 0, 0, False, 'IM 0/1'), - 0x6F: (0, 0, 1, 1, False, 'RLD'), - - 0x70: (0, 0, 1, 0, False, 'IN (C)'), - 0x71: (0, 0, 0, 1, False, 'OUT (C),0'), - 0x72: (0, 0, 0, 0, False, 'SBC HL,SP'), - 0x73: (0, 2, 0, 2, False, 'LD ({i:04H}h),SP'), - 0x74: (0, 0, 0, 0, False, 'NEG'), - 0x75: (0, 0, 2, 0, False, 'RETN'), - 0x76: (0, 0, 0, 0, False, 'IM 1'), - - 0x78: (0, 0, 1, 0, False, 'IN A,(C)'), - 0x79: (0, 0, 0, 1, False, 'OUT (C),A'), - 0x7A: (0, 0, 0, 0, False, 'ADC HL,SP'), - 0x7B: (0, 2, 2, 0, False, 'LD SP,({i:04H}h)'), - 0x7C: (0, 0, 0, 0, False, 'NEG'), - 0x7D: (0, 0, 2, 0, False, 'RETN'), - 0x7E: (0, 0, 0, 0, False, 'IM 2'), - - 0xA0: (0, 0, 1, 1, False, 'LDI'), - 0xA1: (0, 0, 1, 0, False, 'CPI'), - 0xA2: (0, 0, 1, 1, False, 'INI'), - 0xA3: (0, 0, 1, 1, False, 'OUTI'), - - 0xA8: (0, 0, 1, 1, False, 'LDD'), - 0xA9: (0, 0, 1, 0, False, 'CPD'), - 0xAA: (0, 0, 1, 1, False, 'IND'), - 0xAB: (0, 0, 1, 1, False, 'OUTD'), - - 0xB0: (0, 0, 1, 1, True, 'LDIR'), - 0xB1: (0, 0, 1, 0, True, 'CPIR'), - 0xB2: (0, 0, 1, 1, True, 'INIR'), - 0xB3: (0, 0, 1, 1, True, 'OTIR'), - - 0xB8: (0, 0, 1, 1, True, 'LDDR'), - 0xB9: (0, 0, 1, 0, True, 'CPDR'), - 0xBA: (0, 0, 1, 1, True, 'INDR'), - 0xBB: (0, 0, 1, 1, True, 'OTDR') -} - -# Instructions with CB prefix -bit_instructions = { - 0x00: (0, 0, 0, 0, False, 'RLC B'), - 0x01: (0, 0, 0, 0, False, 'RLC C'), - 0x02: (0, 0, 0, 0, False, 'RLC D'), - 0x03: (0, 0, 0, 0, False, 'RLC E'), - 0x04: (0, 0, 0, 0, False, 'RLC H'), - 0x05: (0, 0, 0, 0, False, 'RLC L'), - 0x06: (0, 0, 1, 1, False, 'RLC (HL)'), - 0x07: (0, 0, 0, 0, False, 'RLC A'), - 0x08: (0, 0, 0, 0, False, 'RRC B'), - 0x09: (0, 0, 0, 0, False, 'RRC C'), - 0x0A: (0, 0, 0, 0, False, 'RRC D'), - 0x0B: (0, 0, 0, 0, False, 'RRC E'), - 0x0C: (0, 0, 0, 0, False, 'RRC H'), - 0x0D: (0, 0, 0, 0, False, 'RRC L'), - 0x0E: (0, 0, 1, 1, False, 'RRC (HL)'), - 0x0F: (0, 0, 0, 0, False, 'RRC A'), - - 0x10: (0, 0, 0, 0, False, 'RL B'), - 0x11: (0, 0, 0, 0, False, 'RL C'), - 0x12: (0, 0, 0, 0, False, 'RL D'), - 0x13: (0, 0, 0, 0, False, 'RL E'), - 0x14: (0, 0, 0, 0, False, 'RL H'), - 0x15: (0, 0, 0, 0, False, 'RL L'), - 0x16: (0, 0, 1, 1, False, 'RL (HL)'), - 0x17: (0, 0, 0, 0, False, 'RL A'), - 0x18: (0, 0, 0, 0, False, 'RR B'), - 0x19: (0, 0, 0, 0, False, 'RR C'), - 0x1A: (0, 0, 0, 0, False, 'RR D'), - 0x1B: (0, 0, 0, 0, False, 'RR E'), - 0x1C: (0, 0, 0, 0, False, 'RR H'), - 0x1D: (0, 0, 0, 0, False, 'RR L'), - 0x1E: (0, 0, 1, 1, False, 'RR (HL)'), - 0x1F: (0, 0, 0, 0, False, 'RR A'), - - 0x20: (0, 0, 0, 0, False, 'SLA B'), - 0x21: (0, 0, 0, 0, False, 'SLA C'), - 0x22: (0, 0, 0, 0, False, 'SLA D'), - 0x23: (0, 0, 0, 0, False, 'SLA E'), - 0x24: (0, 0, 0, 0, False, 'SLA H'), - 0x25: (0, 0, 0, 0, False, 'SLA L'), - 0x26: (0, 0, 1, 1, False, 'SLA (HL)'), - 0x27: (0, 0, 0, 0, False, 'SLA A'), - 0x28: (0, 0, 0, 0, False, 'SRA B'), - 0x29: (0, 0, 0, 0, False, 'SRA C'), - 0x2A: (0, 0, 0, 0, False, 'SRA D'), - 0x2B: (0, 0, 0, 0, False, 'SRA E'), - 0x2C: (0, 0, 0, 0, False, 'SRA H'), - 0x2D: (0, 0, 0, 0, False, 'SRA L'), - 0x2E: (0, 0, 1, 1, False, 'SRA (HL)'), - 0x2F: (0, 0, 0, 0, False, 'SRA A'), - - 0x30: (0, 0, 0, 0, False, 'SLL B'), - 0x31: (0, 0, 0, 0, False, 'SLL C'), - 0x32: (0, 0, 0, 0, False, 'SLL D'), - 0x33: (0, 0, 0, 0, False, 'SLL E'), - 0x34: (0, 0, 0, 0, False, 'SLL H'), - 0x35: (0, 0, 0, 0, False, 'SLL L'), - 0x36: (0, 0, 1, 1, False, 'SLL (HL)'), - 0x37: (0, 0, 0, 0, False, 'SLL A'), - 0x38: (0, 0, 0, 0, False, 'SRL B'), - 0x39: (0, 0, 0, 0, False, 'SRL C'), - 0x3A: (0, 0, 0, 0, False, 'SRL D'), - 0x3B: (0, 0, 0, 0, False, 'SRL E'), - 0x3C: (0, 0, 0, 0, False, 'SRL H'), - 0x3D: (0, 0, 0, 0, False, 'SRL L'), - 0x3E: (0, 0, 1, 1, False, 'SRL (HL)'), - 0x3F: (0, 0, 0, 0, False, 'SRL A'), - - 0x40: (0, 0, 0, 0, False, 'BIT 0,B'), - 0x41: (0, 0, 0, 0, False, 'BIT 0,C'), - 0x42: (0, 0, 0, 0, False, 'BIT 0,D'), - 0x43: (0, 0, 0, 0, False, 'BIT 0,E'), - 0x44: (0, 0, 0, 0, False, 'BIT 0,H'), - 0x45: (0, 0, 0, 0, False, 'BIT 0,L'), - 0x46: (0, 0, 1, 0, False, 'BIT 0,(HL)'), - 0x47: (0, 0, 0, 0, False, 'BIT 0,A'), - 0x48: (0, 0, 0, 0, False, 'BIT 1,B'), - 0x49: (0, 0, 0, 0, False, 'BIT 1,C'), - 0x4A: (0, 0, 0, 0, False, 'BIT 1,D'), - 0x4B: (0, 0, 0, 0, False, 'BIT 1,E'), - 0x4C: (0, 0, 0, 0, False, 'BIT 1,H'), - 0x4D: (0, 0, 0, 0, False, 'BIT 1,L'), - 0x4E: (0, 0, 1, 0, False, 'BIT 1,(HL)'), - 0x4F: (0, 0, 0, 0, False, 'BIT 1,A'), - - 0x50: (0, 0, 0, 0, False, 'BIT 2,B'), - 0x51: (0, 0, 0, 0, False, 'BIT 2,C'), - 0x52: (0, 0, 0, 0, False, 'BIT 2,D'), - 0x53: (0, 0, 0, 0, False, 'BIT 2,E'), - 0x54: (0, 0, 0, 0, False, 'BIT 2,H'), - 0x55: (0, 0, 0, 0, False, 'BIT 2,L'), - 0x56: (0, 0, 1, 0, False, 'BIT 2,(HL)'), - 0x57: (0, 0, 0, 0, False, 'BIT 2,A'), - 0x58: (0, 0, 0, 0, False, 'BIT 3,B'), - 0x59: (0, 0, 0, 0, False, 'BIT 3,C'), - 0x5A: (0, 0, 0, 0, False, 'BIT 3,D'), - 0x5B: (0, 0, 0, 0, False, 'BIT 3,E'), - 0x5C: (0, 0, 0, 0, False, 'BIT 3,H'), - 0x5D: (0, 0, 0, 0, False, 'BIT 3,L'), - 0x5E: (0, 0, 1, 0, False, 'BIT 3,(HL)'), - 0x5F: (0, 0, 0, 0, False, 'BIT 3,A'), - - 0x60: (0, 0, 0, 0, False, 'BIT 4,B'), - 0x61: (0, 0, 0, 0, False, 'BIT 4,C'), - 0x62: (0, 0, 0, 0, False, 'BIT 4,D'), - 0x63: (0, 0, 0, 0, False, 'BIT 4,E'), - 0x64: (0, 0, 0, 0, False, 'BIT 4,H'), - 0x65: (0, 0, 0, 0, False, 'BIT 4,L'), - 0x66: (0, 0, 1, 0, False, 'BIT 4,(HL)'), - 0x67: (0, 0, 0, 0, False, 'BIT 4,A'), - 0x68: (0, 0, 0, 0, False, 'BIT 5,B'), - 0x69: (0, 0, 0, 0, False, 'BIT 5,C'), - 0x6A: (0, 0, 0, 0, False, 'BIT 5,D'), - 0x6B: (0, 0, 0, 0, False, 'BIT 5,E'), - 0x6C: (0, 0, 0, 0, False, 'BIT 5,H'), - 0x6D: (0, 0, 0, 0, False, 'BIT 5,L'), - 0x6E: (0, 0, 1, 0, False, 'BIT 5,(HL)'), - 0x6F: (0, 0, 0, 0, False, 'BIT 5,A'), - - 0x70: (0, 0, 0, 0, False, 'BIT 6,B'), - 0x71: (0, 0, 0, 0, False, 'BIT 6,C'), - 0x72: (0, 0, 0, 0, False, 'BIT 6,D'), - 0x73: (0, 0, 0, 0, False, 'BIT 6,E'), - 0x74: (0, 0, 0, 0, False, 'BIT 6,H'), - 0x75: (0, 0, 0, 0, False, 'BIT 6,L'), - 0x76: (0, 0, 1, 0, False, 'BIT 6,(HL)'), - 0x77: (0, 0, 0, 0, False, 'BIT 6,A'), - 0x78: (0, 0, 0, 0, False, 'BIT 7,B'), - 0x79: (0, 0, 0, 0, False, 'BIT 7,C'), - 0x7A: (0, 0, 0, 0, False, 'BIT 7,D'), - 0x7B: (0, 0, 0, 0, False, 'BIT 7,E'), - 0x7C: (0, 0, 0, 0, False, 'BIT 7,H'), - 0x7D: (0, 0, 0, 0, False, 'BIT 7,L'), - 0x7E: (0, 0, 1, 0, False, 'BIT 7,(HL)'), - 0x7F: (0, 0, 0, 0, False, 'BIT 7,A'), - - 0x80: (0, 0, 0, 0, False, 'RES 0,B'), - 0x81: (0, 0, 0, 0, False, 'RES 0,C'), - 0x82: (0, 0, 0, 0, False, 'RES 0,D'), - 0x83: (0, 0, 0, 0, False, 'RES 0,E'), - 0x84: (0, 0, 0, 0, False, 'RES 0,H'), - 0x85: (0, 0, 0, 0, False, 'RES 0,L'), - 0x86: (0, 0, 1, 1, False, 'RES 0,(HL)'), - 0x87: (0, 0, 0, 0, False, 'RES 0,A'), - 0x88: (0, 0, 0, 0, False, 'RES 1,B'), - 0x89: (0, 0, 0, 0, False, 'RES 1,C'), - 0x8A: (0, 0, 0, 0, False, 'RES 1,D'), - 0x8B: (0, 0, 0, 0, False, 'RES 1,E'), - 0x8C: (0, 0, 0, 0, False, 'RES 1,H'), - 0x8D: (0, 0, 0, 0, False, 'RES 1,L'), - 0x8E: (0, 0, 1, 1, False, 'RES 1,(HL)'), - 0x8F: (0, 0, 0, 0, False, 'RES 1,A'), - - 0x90: (0, 0, 0, 0, False, 'RES 2,B'), - 0x91: (0, 0, 0, 0, False, 'RES 2,C'), - 0x92: (0, 0, 0, 0, False, 'RES 2,D'), - 0x93: (0, 0, 0, 0, False, 'RES 2,E'), - 0x94: (0, 0, 0, 0, False, 'RES 2,H'), - 0x95: (0, 0, 0, 0, False, 'RES 2,L'), - 0x96: (0, 0, 1, 1, False, 'RES 2,(HL)'), - 0x97: (0, 0, 0, 0, False, 'RES 2,A'), - 0x98: (0, 0, 0, 0, False, 'RES 3,B'), - 0x99: (0, 0, 0, 0, False, 'RES 3,C'), - 0x9A: (0, 0, 0, 0, False, 'RES 3,D'), - 0x9B: (0, 0, 0, 0, False, 'RES 3,E'), - 0x9C: (0, 0, 0, 0, False, 'RES 3,H'), - 0x9D: (0, 0, 0, 0, False, 'RES 3,L'), - 0x9E: (0, 0, 1, 1, False, 'RES 3,(HL)'), - 0x9F: (0, 0, 0, 0, False, 'RES 3,A'), - - 0xA0: (0, 0, 0, 0, False, 'RES 4,B'), - 0xA1: (0, 0, 0, 0, False, 'RES 4,C'), - 0xA2: (0, 0, 0, 0, False, 'RES 4,D'), - 0xA3: (0, 0, 0, 0, False, 'RES 4,E'), - 0xA4: (0, 0, 0, 0, False, 'RES 4,H'), - 0xA5: (0, 0, 0, 0, False, 'RES 4,L'), - 0xA6: (0, 0, 1, 1, False, 'RES 4,(HL)'), - 0xA7: (0, 0, 0, 0, False, 'RES 4,A'), - 0xA8: (0, 0, 0, 0, False, 'RES 5,B'), - 0xA9: (0, 0, 0, 0, False, 'RES 5,C'), - 0xAA: (0, 0, 0, 0, False, 'RES 5,D'), - 0xAB: (0, 0, 0, 0, False, 'RES 5,E'), - 0xAC: (0, 0, 0, 0, False, 'RES 5,H'), - 0xAD: (0, 0, 0, 0, False, 'RES 5,L'), - 0xAE: (0, 0, 1, 1, False, 'RES 5,(HL)'), - 0xAF: (0, 0, 0, 0, False, 'RES 5,A'), - - 0xB0: (0, 0, 0, 0, False, 'RES 6,B'), - 0xB1: (0, 0, 0, 0, False, 'RES 6,C'), - 0xB2: (0, 0, 0, 0, False, 'RES 6,D'), - 0xB3: (0, 0, 0, 0, False, 'RES 6,E'), - 0xB4: (0, 0, 0, 0, False, 'RES 6,H'), - 0xB5: (0, 0, 0, 0, False, 'RES 6,L'), - 0xB6: (0, 0, 1, 1, False, 'RES 6,(HL)'), - 0xB7: (0, 0, 0, 0, False, 'RES 6,A'), - 0xB8: (0, 0, 0, 0, False, 'RES 7,B'), - 0xB9: (0, 0, 0, 0, False, 'RES 7,C'), - 0xBA: (0, 0, 0, 0, False, 'RES 7,D'), - 0xBB: (0, 0, 0, 0, False, 'RES 7,E'), - 0xBC: (0, 0, 0, 0, False, 'RES 7,H'), - 0xBD: (0, 0, 0, 0, False, 'RES 7,L'), - 0xBE: (0, 0, 1, 1, False, 'RES 7,(HL)'), - 0xBF: (0, 0, 0, 0, False, 'RES 7,A'), - - 0xC0: (0, 0, 0, 0, False, 'SET 0,B'), - 0xC1: (0, 0, 0, 0, False, 'SET 0,C'), - 0xC2: (0, 0, 0, 0, False, 'SET 0,D'), - 0xC3: (0, 0, 0, 0, False, 'SET 0,E'), - 0xC4: (0, 0, 0, 0, False, 'SET 0,H'), - 0xC5: (0, 0, 0, 0, False, 'SET 0,L'), - 0xC6: (0, 0, 1, 1, False, 'SET 0,(HL)'), - 0xC7: (0, 0, 0, 0, False, 'SET 0,A'), - 0xC8: (0, 0, 0, 0, False, 'SET 1,B'), - 0xC9: (0, 0, 0, 0, False, 'SET 1,C'), - 0xCA: (0, 0, 0, 0, False, 'SET 1,D'), - 0xCB: (0, 0, 0, 0, False, 'SET 1,E'), - 0xCC: (0, 0, 0, 0, False, 'SET 1,H'), - 0xCD: (0, 0, 0, 0, False, 'SET 1,L'), - 0xCE: (0, 0, 1, 1, False, 'SET 1,(HL)'), - 0xCF: (0, 0, 0, 0, False, 'SET 1,A'), - - 0xD0: (0, 0, 0, 0, False, 'SET 2,B'), - 0xD1: (0, 0, 0, 0, False, 'SET 2,C'), - 0xD2: (0, 0, 0, 0, False, 'SET 2,D'), - 0xD3: (0, 0, 0, 0, False, 'SET 2,E'), - 0xD4: (0, 0, 0, 0, False, 'SET 2,H'), - 0xD5: (0, 0, 0, 0, False, 'SET 2,L'), - 0xD6: (0, 0, 1, 1, False, 'SET 2,(HL)'), - 0xD7: (0, 0, 0, 0, False, 'SET 2,A'), - 0xD8: (0, 0, 0, 0, False, 'SET 3,B'), - 0xD9: (0, 0, 0, 0, False, 'SET 3,C'), - 0xDA: (0, 0, 0, 0, False, 'SET 3,D'), - 0xDB: (0, 0, 0, 0, False, 'SET 3,E'), - 0xDC: (0, 0, 0, 0, False, 'SET 3,H'), - 0xDD: (0, 0, 0, 0, False, 'SET 3,L'), - 0xDE: (0, 0, 1, 1, False, 'SET 3,(HL)'), - 0xDF: (0, 0, 0, 0, False, 'SET 3,A'), - - 0xE0: (0, 0, 0, 0, False, 'SET 4,B'), - 0xE1: (0, 0, 0, 0, False, 'SET 4,C'), - 0xE2: (0, 0, 0, 0, False, 'SET 4,D'), - 0xE3: (0, 0, 0, 0, False, 'SET 4,E'), - 0xE4: (0, 0, 0, 0, False, 'SET 4,H'), - 0xE5: (0, 0, 0, 0, False, 'SET 4,L'), - 0xE6: (0, 0, 1, 1, False, 'SET 4,(HL)'), - 0xE7: (0, 0, 0, 0, False, 'SET 4,A'), - 0xE8: (0, 0, 0, 0, False, 'SET 5,B'), - 0xE9: (0, 0, 0, 0, False, 'SET 5,C'), - 0xEA: (0, 0, 0, 0, False, 'SET 5,D'), - 0xEB: (0, 0, 0, 0, False, 'SET 5,E'), - 0xEC: (0, 0, 0, 0, False, 'SET 5,H'), - 0xED: (0, 0, 0, 0, False, 'SET 5,L'), - 0xEE: (0, 0, 1, 1, False, 'SET 5,(HL)'), - 0xEF: (0, 0, 0, 0, False, 'SET 5,A'), - - 0xF0: (0, 0, 0, 0, False, 'SET 6,B'), - 0xF1: (0, 0, 0, 0, False, 'SET 6,C'), - 0xF2: (0, 0, 0, 0, False, 'SET 6,D'), - 0xF3: (0, 0, 0, 0, False, 'SET 6,E'), - 0xF4: (0, 0, 0, 0, False, 'SET 6,H'), - 0xF5: (0, 0, 0, 0, False, 'SET 6,L'), - 0xF6: (0, 0, 1, 1, False, 'SET 6,(HL)'), - 0xF7: (0, 0, 0, 0, False, 'SET 6,A'), - 0xF8: (0, 0, 0, 0, False, 'SET 7,B'), - 0xF9: (0, 0, 0, 0, False, 'SET 7,C'), - 0xFA: (0, 0, 0, 0, False, 'SET 7,D'), - 0xFB: (0, 0, 0, 0, False, 'SET 7,E'), - 0xFC: (0, 0, 0, 0, False, 'SET 7,H'), - 0xFD: (0, 0, 0, 0, False, 'SET 7,L'), - 0xFE: (0, 0, 1, 1, False, 'SET 7,(HL)'), - 0xFF: (0, 0, 0, 0, False, 'SET 7,A') -} - -# Instructions with DD or FD prefix -index_instructions = { - 0x09: (0, 0, 0, 0, False, 'ADD {r},BC'), - - 0x19: (0, 0, 0, 0, False, 'ADD {r},DE'), - - 0x21: (0, 2, 0, 0, False, 'LD {r},{i:04H}h'), - 0x22: (0, 2, 0, 2, False, 'LD ({i:04H}h),{r}'), - 0x23: (0, 0, 0, 0, False, 'INC {r}'), - 0x24: (0, 0, 0, 0, False, 'INC {r}h'), - 0x25: (0, 0, 0, 0, False, 'DEC {r}h'), - 0x26: (0, 1, 0, 0, False, 'LD {r}h,{i:02H}h'), - - 0x29: (0, 0, 0, 0, False, 'ADD {r},{r}'), - 0x2A: (0, 2, 2, 0, False, 'LD {r},({i:04H}h)'), - 0x2B: (0, 0, 0, 0, False, 'DEC {r}'), - 0x2C: (0, 0, 0, 0, False, 'INC {r}l'), - 0x2D: (0, 0, 0, 0, False, 'DEC {r}l'), - 0x2E: (0, 1, 0, 0, False, 'LD {r}l,{i:02H}h'), - - 0x34: (1, 0, 1, 1, False, 'INC ({r}{d:+d})'), - 0x35: (1, 0, 1, 1, False, 'DEC ({r}{d:+d})'), - 0x36: (1, 1, 0, 1, False, 'LD ({r}{d:+d}),{i:02H}h'), - - 0x39: (0, 0, 0, 0, False, 'ADD {r},SP'), - - 0x44: (0, 0, 0, 0, False, 'LD B,{r}h'), - 0x45: (0, 0, 0, 0, False, 'LD B,{r}l'), - 0x46: (1, 0, 1, 0, False, 'LD B,({r}{d:+d})'), - - 0x4C: (0, 0, 0, 0, False, 'LD C,{r}h'), - 0x4D: (0, 0, 0, 0, False, 'LD C,{r}l'), - 0x4E: (1, 0, 1, 0, False, 'LD C,({r}{d:+d})'), - - 0x54: (0, 0, 0, 0, False, 'LD D,{r}h'), - 0x55: (0, 0, 0, 0, False, 'LD D,{r}l'), - 0x56: (1, 0, 1, 0, False, 'LD D,({r}{d:+d})'), - - 0x5C: (0, 0, 0, 0, False, 'LD E,{r}h'), - 0x5D: (0, 0, 0, 0, False, 'LD E,{r}l'), - 0x5E: (1, 0, 1, 0, False, 'LD E,({r}{d:+d})'), - - 0x60: (0, 0, 0, 0, False, 'LD {r}h,B'), - 0x61: (0, 0, 0, 0, False, 'LD {r}h,C'), - 0x62: (0, 0, 0, 0, False, 'LD {r}h,D'), - 0x63: (0, 0, 0, 0, False, 'LD {r}h,E'), - 0x64: (0, 0, 0, 0, False, 'LD {r}h,{r}h'), - 0x65: (0, 0, 0, 0, False, 'LD {r}h,{r}l'), - 0x66: (1, 0, 1, 0, False, 'LD H,({r}{d:+d})'), - 0x67: (0, 0, 0, 0, False, 'LD {r}h,A'), - 0x68: (0, 0, 0, 0, False, 'LD {r}l,B'), - 0x69: (0, 0, 0, 0, False, 'LD {r}l,C'), - 0x6A: (0, 0, 0, 0, False, 'LD {r}l,D'), - 0x6B: (0, 0, 0, 0, False, 'LD {r}l,E'), - 0x6C: (0, 0, 0, 0, False, 'LD {r}l,{r}h'), - 0x6D: (0, 0, 0, 0, False, 'LD {r}l,{r}l'), - 0x6E: (1, 0, 1, 0, False, 'LD L,({r}{d:+d})'), - 0x6F: (0, 0, 0, 0, False, 'LD {r}l,A'), - - 0x70: (1, 0, 0, 1, False, 'LD ({r}{d:+d}),B'), - 0x71: (1, 0, 0, 1, False, 'LD ({r}{d:+d}),C'), - 0x72: (1, 0, 0, 1, False, 'LD ({r}{d:+d}),D'), - 0x73: (1, 0, 0, 1, False, 'LD ({r}{d:+d}),E'), - 0x74: (1, 0, 0, 1, False, 'LD ({r}{d:+d}),H'), - 0x75: (1, 0, 0, 1, False, 'LD ({r}{d:+d}),L'), - - 0x77: (1, 0, 0, 1, False, 'LD ({r}{d:+d}),A'), - - 0x7C: (0, 0, 0, 0, False, 'LD A,{r}h'), - 0x7D: (0, 0, 0, 0, False, 'LD A,{r}l'), - 0x7E: (1, 0, 1, 0, False, 'LD A,({r}{d:+d})'), - - 0x84: (0, 0, 0, 0, False, 'ADD A,{r}h'), - 0x85: (0, 0, 0, 0, False, 'ADD A,{r}l'), - 0x86: (1, 0, 1, 0, False, 'ADD A,({r}{d:+d})'), - - 0x8C: (0, 0, 0, 0, False, 'ADC A,{r}h'), - 0x8D: (0, 0, 0, 0, False, 'ADC A,{r}l'), - 0x8E: (1, 0, 1, 0, False, 'ADC A,({r}{d:+d})'), - - 0x94: (0, 0, 0, 0, False, 'SUB {r}h'), - 0x95: (0, 0, 0, 0, False, 'SUB {r}l'), - 0x96: (1, 0, 1, 0, False, 'SUB ({r}{d:+d})'), - - 0x9C: (0, 0, 0, 0, False, 'SBC A,{r}h'), - 0x9D: (0, 0, 0, 0, False, 'SBC A,{r}l'), - 0x9E: (1, 0, 1, 0, False, 'SBC A,({r}{d:+d})'), - - 0xA4: (0, 0, 0, 0, False, 'AND {r}h'), - 0xA5: (0, 0, 0, 0, False, 'AND {r}l'), - 0xA6: (1, 0, 1, 0, False, 'AND ({r}{d:+d})'), - - 0xAC: (0, 0, 0, 0, False, 'XOR {r}h'), - 0xAD: (0, 0, 0, 0, False, 'XOR {r}l'), - 0xAE: (1, 0, 1, 0, False, 'XOR ({r}{d:+d})'), - - 0xB4: (0, 0, 0, 0, False, 'OR {r}h'), - 0xB5: (0, 0, 0, 0, False, 'OR {r}l'), - 0xB6: (1, 0, 1, 0, False, 'OR ({r}{d:+d})'), - - 0xBC: (0, 0, 0, 0, False, 'CP {r}h'), - 0xBD: (0, 0, 0, 0, False, 'CP {r}l'), - 0xBE: (1, 0, 1, 0, False, 'CP ({r}{d:+d})'), - - 0xE1: (0, 0, 2, 0, False, 'POP {r}'), - - 0xE3: (0, 0, 2, 2, False, 'EX (SP),{r}'), - - 0xE5: (0, 0, 0,-2, False, 'PUSH {r}'), - - 0xE9: (0, 0, 0, 0, False, 'JP ({r})'), - - 0xF9: (0, 0, 0, 0, False, 'LD SP,{r}') -} - -# Instructions with DD CB or FD CB prefix. -# For these instructions, the displacement precedes the opcode byte. -# This is handled as a special case in the code, and thus the entries -# in this table specify 0 for the displacement length. -index_bit_instructions = { - 0x00: (0, 0, 1, 1, False, 'RLC ({r}{d:+d}),B'), - 0x01: (0, 0, 1, 1, False, 'RLC ({r}{d:+d}),C'), - 0x02: (0, 0, 1, 1, False, 'RLC ({r}{d:+d}),D'), - 0x03: (0, 0, 1, 1, False, 'RLC ({r}{d:+d}),E'), - 0x04: (0, 0, 1, 1, False, 'RLC ({r}{d:+d}),H'), - 0x05: (0, 0, 1, 1, False, 'RLC ({r}{d:+d}),L'), - 0x06: (0, 0, 1, 1, False, 'RLC ({r}{d:+d})'), - 0x07: (0, 0, 1, 1, False, 'RLC ({r}{d:+d}),A'), - 0x08: (0, 0, 1, 1, False, 'RRC ({r}{d:+d}),B'), - 0x09: (0, 0, 1, 1, False, 'RRC ({r}{d:+d}),C'), - 0x0A: (0, 0, 1, 1, False, 'RRC ({r}{d:+d}),D'), - 0x0B: (0, 0, 1, 1, False, 'RRC ({r}{d:+d}),E'), - 0x0C: (0, 0, 1, 1, False, 'RRC ({r}{d:+d}),H'), - 0x0D: (0, 0, 1, 1, False, 'RRC ({r}{d:+d}),L'), - 0x0E: (0, 0, 1, 1, False, 'RRC ({r}{d:+d})'), - 0x0F: (0, 0, 1, 1, False, 'RRC ({r}{d:+d}),A'), - - 0x10: (0, 0, 1, 1, False, 'RL ({r}{d:+d}),B'), - 0x11: (0, 0, 1, 1, False, 'RL ({r}{d:+d}),C'), - 0x12: (0, 0, 1, 1, False, 'RL ({r}{d:+d}),D'), - 0x13: (0, 0, 1, 1, False, 'RL ({r}{d:+d}),E'), - 0x14: (0, 0, 1, 1, False, 'RL ({r}{d:+d}),H'), - 0x15: (0, 0, 1, 1, False, 'RL ({r}{d:+d}),L'), - 0x16: (0, 0, 1, 1, False, 'RL ({r}{d:+d})'), - 0x17: (0, 0, 1, 1, False, 'RL ({r}{d:+d}),A'), - 0x18: (0, 0, 1, 1, False, 'RR ({r}{d:+d}),B'), - 0x19: (0, 0, 1, 1, False, 'RR ({r}{d:+d}),C'), - 0x1A: (0, 0, 1, 1, False, 'RR ({r}{d:+d}),D'), - 0x1B: (0, 0, 1, 1, False, 'RR ({r}{d:+d}),E'), - 0x1C: (0, 0, 1, 1, False, 'RR ({r}{d:+d}),H'), - 0x1D: (0, 0, 1, 1, False, 'RR ({r}{d:+d}),L'), - 0x1E: (0, 0, 1, 1, False, 'RR ({r}{d:+d})'), - 0x1F: (0, 0, 1, 1, False, 'RR ({r}{d:+d}),A'), - - 0x20: (0, 0, 1, 1, False, 'SLA ({r}{d:+d}),B'), - 0x21: (0, 0, 1, 1, False, 'SLA ({r}{d:+d}),C'), - 0x22: (0, 0, 1, 1, False, 'SLA ({r}{d:+d}),D'), - 0x23: (0, 0, 1, 1, False, 'SLA ({r}{d:+d}),E'), - 0x24: (0, 0, 1, 1, False, 'SLA ({r}{d:+d}),H'), - 0x25: (0, 0, 1, 1, False, 'SLA ({r}{d:+d}),L'), - 0x26: (0, 0, 1, 1, False, 'SLA ({r}{d:+d})'), - 0x27: (0, 0, 1, 1, False, 'SLA ({r}{d:+d}),A'), - 0x28: (0, 0, 1, 1, False, 'SRA ({r}{d:+d}),B'), - 0x29: (0, 0, 1, 1, False, 'SRA ({r}{d:+d}),C'), - 0x2A: (0, 0, 1, 1, False, 'SRA ({r}{d:+d}),D'), - 0x2B: (0, 0, 1, 1, False, 'SRA ({r}{d:+d}),E'), - 0x2C: (0, 0, 1, 1, False, 'SRA ({r}{d:+d}),H'), - 0x2D: (0, 0, 1, 1, False, 'SRA ({r}{d:+d}),L'), - 0x2E: (0, 0, 1, 1, False, 'SRA ({r}{d:+d})'), - 0x2F: (0, 0, 1, 1, False, 'SRA ({r}{d:+d}),A'), - - 0x30: (0, 0, 1, 1, False, 'SLL ({r}{d:+d}),B'), - 0x31: (0, 0, 1, 1, False, 'SLL ({r}{d:+d}),C'), - 0x32: (0, 0, 1, 1, False, 'SLL ({r}{d:+d}),D'), - 0x33: (0, 0, 1, 1, False, 'SLL ({r}{d:+d}),E'), - 0x34: (0, 0, 1, 1, False, 'SLL ({r}{d:+d}),H'), - 0x35: (0, 0, 1, 1, False, 'SLL ({r}{d:+d}),L'), - 0x36: (0, 0, 1, 1, False, 'SLL ({r}{d:+d})'), - 0x37: (0, 0, 1, 1, False, 'SLL ({r}{d:+d}),A'), - 0x38: (0, 0, 1, 1, False, 'SRL ({r}{d:+d}),B'), - 0x39: (0, 0, 1, 1, False, 'SRL ({r}{d:+d}),C'), - 0x3A: (0, 0, 1, 1, False, 'SRL ({r}{d:+d}),D'), - 0x3B: (0, 0, 1, 1, False, 'SRL ({r}{d:+d}),E'), - 0x3C: (0, 0, 1, 1, False, 'SRL ({r}{d:+d}),H'), - 0x3D: (0, 0, 1, 1, False, 'SRL ({r}{d:+d}),L'), - 0x3E: (0, 0, 1, 1, False, 'SRL ({r}{d:+d})'), - 0x3F: (0, 0, 1, 1, False, 'SRL ({r}{d:+d}),A'), - - 0x40: (0, 0, 1, 0, False, 'BIT 0,({r}{d:+d})'), - 0x41: (0, 0, 1, 0, False, 'BIT 0,({r}{d:+d})'), - 0x42: (0, 0, 1, 0, False, 'BIT 0,({r}{d:+d})'), - 0x43: (0, 0, 1, 0, False, 'BIT 0,({r}{d:+d})'), - 0x44: (0, 0, 1, 0, False, 'BIT 0,({r}{d:+d})'), - 0x45: (0, 0, 1, 0, False, 'BIT 0,({r}{d:+d})'), - 0x46: (0, 0, 1, 0, False, 'BIT 0,({r}{d:+d})'), - 0x47: (0, 0, 1, 0, False, 'BIT 0,({r}{d:+d})'), - 0x48: (0, 0, 1, 0, False, 'BIT 1,({r}{d:+d})'), - 0x49: (0, 0, 1, 0, False, 'BIT 1,({r}{d:+d})'), - 0x4A: (0, 0, 1, 0, False, 'BIT 1,({r}{d:+d})'), - 0x4B: (0, 0, 1, 0, False, 'BIT 1,({r}{d:+d})'), - 0x4C: (0, 0, 1, 0, False, 'BIT 1,({r}{d:+d})'), - 0x4D: (0, 0, 1, 0, False, 'BIT 1,({r}{d:+d})'), - 0x4E: (0, 0, 1, 0, False, 'BIT 1,({r}{d:+d})'), - 0x4F: (0, 0, 1, 0, False, 'BIT 1,({r}{d:+d})'), - - 0x50: (0, 0, 1, 0, False, 'BIT 2,({r}{d:+d})'), - 0x51: (0, 0, 1, 0, False, 'BIT 2,({r}{d:+d})'), - 0x52: (0, 0, 1, 0, False, 'BIT 2,({r}{d:+d})'), - 0x53: (0, 0, 1, 0, False, 'BIT 2,({r}{d:+d})'), - 0x54: (0, 0, 1, 0, False, 'BIT 2,({r}{d:+d})'), - 0x55: (0, 0, 1, 0, False, 'BIT 2,({r}{d:+d})'), - 0x56: (0, 0, 1, 0, False, 'BIT 2,({r}{d:+d})'), - 0x57: (0, 0, 1, 0, False, 'BIT 2,({r}{d:+d})'), - 0x58: (0, 0, 1, 0, False, 'BIT 3,({r}{d:+d})'), - 0x59: (0, 0, 1, 0, False, 'BIT 3,({r}{d:+d})'), - 0x5A: (0, 0, 1, 0, False, 'BIT 3,({r}{d:+d})'), - 0x5B: (0, 0, 1, 0, False, 'BIT 3,({r}{d:+d})'), - 0x5C: (0, 0, 1, 0, False, 'BIT 3,({r}{d:+d})'), - 0x5D: (0, 0, 1, 0, False, 'BIT 3,({r}{d:+d})'), - 0x5E: (0, 0, 1, 0, False, 'BIT 3,({r}{d:+d})'), - 0x5F: (0, 0, 1, 0, False, 'BIT 3,({r}{d:+d})'), - - 0x60: (0, 0, 1, 0, False, 'BIT 4,({r}{d:+d})'), - 0x61: (0, 0, 1, 0, False, 'BIT 4,({r}{d:+d})'), - 0x62: (0, 0, 1, 0, False, 'BIT 4,({r}{d:+d})'), - 0x63: (0, 0, 1, 0, False, 'BIT 4,({r}{d:+d})'), - 0x64: (0, 0, 1, 0, False, 'BIT 4,({r}{d:+d})'), - 0x65: (0, 0, 1, 0, False, 'BIT 4,({r}{d:+d})'), - 0x66: (0, 0, 1, 0, False, 'BIT 4,({r}{d:+d})'), - 0x67: (0, 0, 1, 0, False, 'BIT 4,({r}{d:+d})'), - 0x68: (0, 0, 1, 0, False, 'BIT 5,({r}{d:+d})'), - 0x69: (0, 0, 1, 0, False, 'BIT 5,({r}{d:+d})'), - 0x6A: (0, 0, 1, 0, False, 'BIT 5,({r}{d:+d})'), - 0x6B: (0, 0, 1, 0, False, 'BIT 5,({r}{d:+d})'), - 0x6C: (0, 0, 1, 0, False, 'BIT 5,({r}{d:+d})'), - 0x6D: (0, 0, 1, 0, False, 'BIT 5,({r}{d:+d})'), - 0x6E: (0, 0, 1, 0, False, 'BIT 5,({r}{d:+d})'), - 0x6F: (0, 0, 1, 0, False, 'BIT 5,({r}{d:+d})'), - - 0x70: (0, 0, 1, 0, False, 'BIT 6,({r}{d:+d})'), - 0x71: (0, 0, 1, 0, False, 'BIT 6,({r}{d:+d})'), - 0x72: (0, 0, 1, 0, False, 'BIT 6,({r}{d:+d})'), - 0x73: (0, 0, 1, 0, False, 'BIT 6,({r}{d:+d})'), - 0x74: (0, 0, 1, 0, False, 'BIT 6,({r}{d:+d})'), - 0x75: (0, 0, 1, 0, False, 'BIT 6,({r}{d:+d})'), - 0x76: (0, 0, 1, 0, False, 'BIT 6,({r}{d:+d})'), - 0x77: (0, 0, 1, 0, False, 'BIT 6,({r}{d:+d})'), - 0x78: (0, 0, 1, 0, False, 'BIT 7,({r}{d:+d})'), - 0x79: (0, 0, 1, 0, False, 'BIT 7,({r}{d:+d})'), - 0x7A: (0, 0, 1, 0, False, 'BIT 7,({r}{d:+d})'), - 0x7B: (0, 0, 1, 0, False, 'BIT 7,({r}{d:+d})'), - 0x7C: (0, 0, 1, 0, False, 'BIT 7,({r}{d:+d})'), - 0x7D: (0, 0, 1, 0, False, 'BIT 7,({r}{d:+d})'), - 0x7E: (0, 0, 1, 0, False, 'BIT 7,({r}{d:+d})'), - 0x7F: (0, 0, 1, 0, False, 'BIT 7,({r}{d:+d})'), - - 0x80: (0, 0, 1, 1, False, 'RES 0,({r}{d:+d}),B'), - 0x81: (0, 0, 1, 1, False, 'RES 0,({r}{d:+d}),C'), - 0x82: (0, 0, 1, 1, False, 'RES 0,({r}{d:+d}),D'), - 0x83: (0, 0, 1, 1, False, 'RES 0,({r}{d:+d}),E'), - 0x84: (0, 0, 1, 1, False, 'RES 0,({r}{d:+d}),H'), - 0x85: (0, 0, 1, 1, False, 'RES 0,({r}{d:+d}),L'), - 0x86: (0, 0, 1, 1, False, 'RES 0,({r}{d:+d})'), - 0x87: (0, 0, 1, 1, False, 'RES 0,({r}{d:+d}),A'), - 0x88: (0, 0, 1, 1, False, 'RES 1,({r}{d:+d}),B'), - 0x89: (0, 0, 1, 1, False, 'RES 1,({r}{d:+d}),C'), - 0x8A: (0, 0, 1, 1, False, 'RES 1,({r}{d:+d}),D'), - 0x8B: (0, 0, 1, 1, False, 'RES 1,({r}{d:+d}),E'), - 0x8C: (0, 0, 1, 1, False, 'RES 1,({r}{d:+d}),H'), - 0x8D: (0, 0, 1, 1, False, 'RES 1,({r}{d:+d}),L'), - 0x8E: (0, 0, 1, 1, False, 'RES 1,({r}{d:+d})'), - 0x8F: (0, 0, 1, 1, False, 'RES 1,({r}{d:+d}),A'), - - 0x90: (0, 0, 1, 1, False, 'RES 2,({r}{d:+d}),B'), - 0x91: (0, 0, 1, 1, False, 'RES 2,({r}{d:+d}),C'), - 0x92: (0, 0, 1, 1, False, 'RES 2,({r}{d:+d}),D'), - 0x93: (0, 0, 1, 1, False, 'RES 2,({r}{d:+d}),E'), - 0x94: (0, 0, 1, 1, False, 'RES 2,({r}{d:+d}),H'), - 0x95: (0, 0, 1, 1, False, 'RES 2,({r}{d:+d}),L'), - 0x96: (0, 0, 1, 1, False, 'RES 2,({r}{d:+d})'), - 0x97: (0, 0, 1, 1, False, 'RES 2,({r}{d:+d}),A'), - 0x98: (0, 0, 1, 1, False, 'RES 3,({r}{d:+d}),B'), - 0x99: (0, 0, 1, 1, False, 'RES 3,({r}{d:+d}),C'), - 0x9A: (0, 0, 1, 1, False, 'RES 3,({r}{d:+d}),D'), - 0x9B: (0, 0, 1, 1, False, 'RES 3,({r}{d:+d}),E'), - 0x9C: (0, 0, 1, 1, False, 'RES 3,({r}{d:+d}),H'), - 0x9D: (0, 0, 1, 1, False, 'RES 3,({r}{d:+d}),L'), - 0x9E: (0, 0, 1, 1, False, 'RES 3,({r}{d:+d})'), - 0x9F: (0, 0, 1, 1, False, 'RES 3,({r}{d:+d}),A'), - - 0xA0: (0, 0, 1, 1, False, 'RES 4,({r}{d:+d}),B'), - 0xA1: (0, 0, 1, 1, False, 'RES 4,({r}{d:+d}),C'), - 0xA2: (0, 0, 1, 1, False, 'RES 4,({r}{d:+d}),D'), - 0xA3: (0, 0, 1, 1, False, 'RES 4,({r}{d:+d}),E'), - 0xA4: (0, 0, 1, 1, False, 'RES 4,({r}{d:+d}),H'), - 0xA5: (0, 0, 1, 1, False, 'RES 4,({r}{d:+d}),L'), - 0xA6: (0, 0, 1, 1, False, 'RES 4,({r}{d:+d})'), - 0xA7: (0, 0, 1, 1, False, 'RES 4,({r}{d:+d}),A'), - 0xA8: (0, 0, 1, 1, False, 'RES 5,({r}{d:+d}),B'), - 0xA9: (0, 0, 1, 1, False, 'RES 5,({r}{d:+d}),C'), - 0xAA: (0, 0, 1, 1, False, 'RES 5,({r}{d:+d}),D'), - 0xAB: (0, 0, 1, 1, False, 'RES 5,({r}{d:+d}),E'), - 0xAC: (0, 0, 1, 1, False, 'RES 5,({r}{d:+d}),H'), - 0xAD: (0, 0, 1, 1, False, 'RES 5,({r}{d:+d}),L'), - 0xAE: (0, 0, 1, 1, False, 'RES 5,({r}{d:+d})'), - 0xAF: (0, 0, 1, 1, False, 'RES 5,({r}{d:+d}),A'), - - 0xB0: (0, 0, 1, 1, False, 'RES 6,({r}{d:+d}),B'), - 0xB1: (0, 0, 1, 1, False, 'RES 6,({r}{d:+d}),C'), - 0xB2: (0, 0, 1, 1, False, 'RES 6,({r}{d:+d}),D'), - 0xB3: (0, 0, 1, 1, False, 'RES 6,({r}{d:+d}),E'), - 0xB4: (0, 0, 1, 1, False, 'RES 6,({r}{d:+d}),H'), - 0xB5: (0, 0, 1, 1, False, 'RES 6,({r}{d:+d}),L'), - 0xB6: (0, 0, 1, 1, False, 'RES 6,({r}{d:+d})'), - 0xB7: (0, 0, 1, 1, False, 'RES 6,({r}{d:+d}),A'), - 0xB8: (0, 0, 1, 1, False, 'RES 7,({r}{d:+d}),B'), - 0xB9: (0, 0, 1, 1, False, 'RES 7,({r}{d:+d}),C'), - 0xBA: (0, 0, 1, 1, False, 'RES 7,({r}{d:+d}),D'), - 0xBB: (0, 0, 1, 1, False, 'RES 7,({r}{d:+d}),E'), - 0xBC: (0, 0, 1, 1, False, 'RES 7,({r}{d:+d}),H'), - 0xBD: (0, 0, 1, 1, False, 'RES 7,({r}{d:+d}),L'), - 0xBE: (0, 0, 1, 1, False, 'RES 7,({r}{d:+d})'), - 0xBF: (0, 0, 1, 1, False, 'RES 7,({r}{d:+d}),A'), - - 0xC0: (0, 0, 1, 1, False, 'SET 0,({r}{d:+d}),B'), - 0xC1: (0, 0, 1, 1, False, 'SET 0,({r}{d:+d}),C'), - 0xC2: (0, 0, 1, 1, False, 'SET 0,({r}{d:+d}),D'), - 0xC3: (0, 0, 1, 1, False, 'SET 0,({r}{d:+d}),E'), - 0xC4: (0, 0, 1, 1, False, 'SET 0,({r}{d:+d}),H'), - 0xC5: (0, 0, 1, 1, False, 'SET 0,({r}{d:+d}),L'), - 0xC6: (0, 0, 1, 1, False, 'SET 0,({r}{d:+d})'), - 0xC7: (0, 0, 1, 1, False, 'SET 0,({r}{d:+d}),A'), - 0xC8: (0, 0, 1, 1, False, 'SET 1,({r}{d:+d}),B'), - 0xC9: (0, 0, 1, 1, False, 'SET 1,({r}{d:+d}),C'), - 0xCA: (0, 0, 1, 1, False, 'SET 1,({r}{d:+d}),D'), - 0xCB: (0, 0, 1, 1, False, 'SET 1,({r}{d:+d}),E'), - 0xCC: (0, 0, 1, 1, False, 'SET 1,({r}{d:+d}),H'), - 0xCD: (0, 0, 1, 1, False, 'SET 1,({r}{d:+d}),L'), - 0xCE: (0, 0, 1, 1, False, 'SET 1,({r}{d:+d})'), - 0xCF: (0, 0, 1, 1, False, 'SET 1,({r}{d:+d}),A'), - - 0xD0: (0, 0, 1, 1, False, 'SET 2,({r}{d:+d}),B'), - 0xD1: (0, 0, 1, 1, False, 'SET 2,({r}{d:+d}),C'), - 0xD2: (0, 0, 1, 1, False, 'SET 2,({r}{d:+d}),D'), - 0xD3: (0, 0, 1, 1, False, 'SET 2,({r}{d:+d}),E'), - 0xD4: (0, 0, 1, 1, False, 'SET 2,({r}{d:+d}),H'), - 0xD5: (0, 0, 1, 1, False, 'SET 2,({r}{d:+d}),L'), - 0xD6: (0, 0, 1, 1, False, 'SET 2,({r}{d:+d})'), - 0xD7: (0, 0, 1, 1, False, 'SET 2,({r}{d:+d}),A'), - 0xD8: (0, 0, 1, 1, False, 'SET 3,({r}{d:+d}),B'), - 0xD9: (0, 0, 1, 1, False, 'SET 3,({r}{d:+d}),C'), - 0xDA: (0, 0, 1, 1, False, 'SET 3,({r}{d:+d}),D'), - 0xDB: (0, 0, 1, 1, False, 'SET 3,({r}{d:+d}),E'), - 0xDC: (0, 0, 1, 1, False, 'SET 3,({r}{d:+d}),H'), - 0xDD: (0, 0, 1, 1, False, 'SET 3,({r}{d:+d}),L'), - 0xDE: (0, 0, 1, 1, False, 'SET 3,({r}{d:+d})'), - 0xDF: (0, 0, 1, 1, False, 'SET 3,({r}{d:+d}),A'), - - 0xE0: (0, 0, 1, 1, False, 'SET 4,({r}{d:+d}),B'), - 0xE1: (0, 0, 1, 1, False, 'SET 4,({r}{d:+d}),C'), - 0xE2: (0, 0, 1, 1, False, 'SET 4,({r}{d:+d}),D'), - 0xE3: (0, 0, 1, 1, False, 'SET 4,({r}{d:+d}),E'), - 0xE4: (0, 0, 1, 1, False, 'SET 4,({r}{d:+d}),H'), - 0xE5: (0, 0, 1, 1, False, 'SET 4,({r}{d:+d}),L'), - 0xE6: (0, 0, 1, 1, False, 'SET 4,({r}{d:+d})'), - 0xE7: (0, 0, 1, 1, False, 'SET 4,({r}{d:+d}),A'), - 0xE8: (0, 0, 1, 1, False, 'SET 5,({r}{d:+d}),B'), - 0xE9: (0, 0, 1, 1, False, 'SET 5,({r}{d:+d}),C'), - 0xEA: (0, 0, 1, 1, False, 'SET 5,({r}{d:+d}),D'), - 0xEB: (0, 0, 1, 1, False, 'SET 5,({r}{d:+d}),E'), - 0xEC: (0, 0, 1, 1, False, 'SET 5,({r}{d:+d}),H'), - 0xED: (0, 0, 1, 1, False, 'SET 5,({r}{d:+d}),L'), - 0xEE: (0, 0, 1, 1, False, 'SET 5,({r}{d:+d})'), - 0xEF: (0, 0, 1, 1, False, 'SET 5,({r}{d:+d}),A'), - - 0xF0: (0, 0, 1, 1, False, 'SET 6,({r}{d:+d}),B'), - 0xF1: (0, 0, 1, 1, False, 'SET 6,({r}{d:+d}),C'), - 0xF2: (0, 0, 1, 1, False, 'SET 6,({r}{d:+d}),D'), - 0xF3: (0, 0, 1, 1, False, 'SET 6,({r}{d:+d}),E'), - 0xF4: (0, 0, 1, 1, False, 'SET 6,({r}{d:+d}),H'), - 0xF5: (0, 0, 1, 1, False, 'SET 6,({r}{d:+d}),L'), - 0xF6: (0, 0, 1, 1, False, 'SET 6,({r}{d:+d})'), - 0xF7: (0, 0, 1, 1, False, 'SET 6,({r}{d:+d}),A'), - 0xF8: (0, 0, 1, 1, False, 'SET 7,({r}{d:+d}),B'), - 0xF9: (0, 0, 1, 1, False, 'SET 7,({r}{d:+d}),C'), - 0xFA: (0, 0, 1, 1, False, 'SET 7,({r}{d:+d}),D'), - 0xFB: (0, 0, 1, 1, False, 'SET 7,({r}{d:+d}),E'), - 0xFC: (0, 0, 1, 1, False, 'SET 7,({r}{d:+d}),H'), - 0xFD: (0, 0, 1, 1, False, 'SET 7,({r}{d:+d}),L'), - 0xFE: (0, 0, 1, 1, False, 'SET 7,({r}{d:+d})'), - 0xFF: (0, 0, 1, 1, False, 'SET 7,({r}{d:+d}),A') -} - -instr_table_by_prefix = { - 0: (main_instructions, ''), - 0xED: (extended_instructions, ''), - 0xCB: (bit_instructions, ''), - 0xDD: (index_instructions, 'IX'), - 0xFD: (index_instructions, 'IY'), - 0xDDCB: (index_bit_instructions, 'IX'), - 0xFDCB: (index_bit_instructions, 'IY') -} diff --git a/test/decode_test/core.c b/test/decode_test/core.c deleted file mode 100755 index f09a6e87..00000000 --- a/test/decode_test/core.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * This file is part of the libsigrokdecode project. - * - * Copyright (C) 2013 Uwe Hermann - * - * 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, see . - */ - -#include -#include /* First, to avoid compiler warning. */ -#include -#include -#include "lib.h" - -/* - * Check various basic init related things. - * - * - Check whether an srd_init() call with path == NULL works. - * If it returns != SRD_OK (or segfaults) this test will fail. - * - * - Check whether a subsequent srd_exit() works. - * If it returns != SRD_OK (or segfaults) this test will fail. - */ -START_TEST(test_init_exit) -{ - int ret; - - ret = srd_init(NULL); - fail_unless(ret == SRD_OK, "srd_init() failed: %d.", ret); - ret = srd_exit(); - fail_unless(ret == SRD_OK, "srd_exit() failed: %d.", ret); -} -END_TEST - -/* - * Check whether nested srd_init()/srd_exit() calls work/fail correctly. - * Two consecutive srd_init() calls without any srd_exit() inbetween are - * not allowed and should fail. However, two consecutive srd_exit() calls - * are currently allowed, the second one will just be a NOP basically. - */ -START_TEST(test_init_exit_2) -{ - int ret; - - ret = srd_init(NULL); - fail_unless(ret == SRD_OK, "srd_init() 1 failed: %d.", ret); - ret = srd_init(NULL); - fail_unless(ret != SRD_OK, "srd_init() 2 didn't fail: %d.", ret); - ret = srd_exit(); - fail_unless(ret == SRD_OK, "srd_exit() 2 failed: %d.", ret); - ret = srd_exit(); - fail_unless(ret == SRD_OK, "srd_exit() 1 failed: %d.", ret); -} -END_TEST - -/* - * Check whether three nested srd_init()/srd_exit() calls work/fail correctly. - */ -START_TEST(test_init_exit_3) -{ - int ret; - - ret = srd_init(NULL); - fail_unless(ret == SRD_OK, "srd_init() 1 failed: %d.", ret); - ret = srd_init(NULL); - fail_unless(ret != SRD_OK, "srd_init() 2 didn't fail: %d.", ret); - ret = srd_init(NULL); - fail_unless(ret != SRD_OK, "srd_init() 3 didn't fail: %d.", ret); - ret = srd_exit(); - fail_unless(ret == SRD_OK, "srd_exit() 3 failed: %d.", ret); - ret = srd_exit(); - fail_unless(ret == SRD_OK, "srd_exit() 2 failed: %d.", ret); - ret = srd_exit(); - fail_unless(ret == SRD_OK, "srd_exit() 1 failed: %d.", ret); -} -END_TEST - -Suite *suite_core(void) -{ - Suite *s; - TCase *tc; - - s = suite_create("core"); - - tc = tcase_create("init_exit"); - tcase_add_checked_fixture(tc, srdtest_setup, srdtest_teardown); - tcase_add_test(tc, test_init_exit); - tcase_add_test(tc, test_init_exit_2); - tcase_add_test(tc, test_init_exit_3); - suite_add_tcase(s, tc); - - return s; -} diff --git a/test/decode_test/decoder.c b/test/decode_test/decoder.c deleted file mode 100755 index 36784102..00000000 --- a/test/decode_test/decoder.c +++ /dev/null @@ -1,467 +0,0 @@ -/* - * This file is part of the libsigrokdecode project. - * - * Copyright (C) 2013 Uwe Hermann - * - * 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, see . - */ - -#include -#include /* First, to avoid compiler warning. */ -#include -#include -#include "lib.h" - -/* - * Check whether srd_decoder_load_all() works. - * If it returns != SRD_OK (or segfaults) this test will fail. - */ -START_TEST(test_load_all) -{ - int ret; - - srd_init(DECODERS_TESTDIR); - ret = srd_decoder_load_all(); - fail_unless(ret == SRD_OK, "srd_decoder_load_all() failed: %d.", ret); - srd_exit(); -} -END_TEST - -/* - * Check whether srd_decoder_load_all() fails without prior srd_init(). - * If it returns != SRD_OK (or segfaults) this test will fail. - * See also: http://sigrok.org/bugzilla/show_bug.cgi?id=178 - */ -START_TEST(test_load_all_no_init) -{ - int ret; - - ret = srd_decoder_load_all(); - fail_unless(ret != SRD_OK, "srd_decoder_load_all() didn't fail properly."); -} -END_TEST - -/* - * Check whether srd_decoder_load() works. - * If it returns != SRD_OK (or segfaults) this test will fail. - */ -START_TEST(test_load) -{ - int ret; - - srd_init(DECODERS_TESTDIR); - ret = srd_decoder_load("uart"); - fail_unless(ret == SRD_OK, "srd_decoder_load(uart) failed: %d.", ret); - ret = srd_decoder_load("spi"); - fail_unless(ret == SRD_OK, "srd_decoder_load(spi) failed: %d.", ret); - ret = srd_decoder_load("usb_signalling"); - fail_unless(ret == SRD_OK, "srd_decoder_load(usb_signalling) failed: %d.", ret); - srd_exit(); -} -END_TEST - -/* - * Check whether srd_decoder_load() fails for non-existing or bogus PDs. - * If it returns SRD_OK (or segfaults) this test will fail. - */ -START_TEST(test_load_bogus) -{ - srd_init(DECODERS_TESTDIR); - /* http://sigrok.org/bugzilla/show_bug.cgi?id=176 */ - fail_unless(srd_decoder_load(NULL) != SRD_OK); - fail_unless(srd_decoder_load("") != SRD_OK); - fail_unless(srd_decoder_load(" ") != SRD_OK); - fail_unless(srd_decoder_load("nonexisting") != SRD_OK); - fail_unless(srd_decoder_load("UART") != SRD_OK); - fail_unless(srd_decoder_load("UaRt") != SRD_OK); - fail_unless(srd_decoder_load("u a r t") != SRD_OK); - fail_unless(srd_decoder_load("uart ") != SRD_OK); - fail_unless(srd_decoder_load(" uart") != SRD_OK); - fail_unless(srd_decoder_load(" uart ") != SRD_OK); - fail_unless(srd_decoder_load("uart spi") != SRD_OK); - srd_exit(); -} -END_TEST - -/* - * Check whether srd_decoder_load() works/fails for valid/bogus PDs. - * If it returns incorrect values (or segfaults) this test will fail. - */ -START_TEST(test_load_valid_and_bogus) -{ - srd_init(DECODERS_TESTDIR); - fail_unless(srd_decoder_load("") != SRD_OK); - fail_unless(srd_decoder_load("uart") == SRD_OK); - fail_unless(srd_decoder_load("") != SRD_OK); - fail_unless(srd_decoder_load("spi") == SRD_OK); - fail_unless(srd_decoder_load("") != SRD_OK); - fail_unless(srd_decoder_load("can") == SRD_OK); - fail_unless(srd_decoder_load("") != SRD_OK); - srd_exit(); -} -END_TEST - -/* - * Check whether srd_decoder_load() fails when run multiple times. - * If it returns a value != SRD_OK (or segfaults) this test will fail. - * See also: http://sigrok.org/bugzilla/show_bug.cgi?id=177 - */ -START_TEST(test_load_multiple) -{ - int ret; - - srd_init(DECODERS_TESTDIR); - ret = srd_decoder_load("uart"); - fail_unless(ret == SRD_OK, "Loading uart PD 1x failed: %d", ret); - ret = srd_decoder_load("uart"); - fail_unless(ret == SRD_OK, "Loading uart PD 2x failed: %d", ret); - ret = srd_decoder_load("uart"); - fail_unless(ret == SRD_OK, "Loading uart PD 3x failed: %d", ret); - srd_exit(); -} -END_TEST - -/* - * Check whether srd_decoder_load() fails if a non-existing PD dir is used. - * If it returns SRD_OK (or segfaults) this test will fail. - */ -START_TEST(test_load_nonexisting_pd_dir) -{ -#if 0 - /* TODO: Build libsigrokdecode with no default PD dir. */ - srd_init("/nonexisting_dir"); - fail_unless(srd_decoder_load("spi") != SRD_OK); - fail_unless(g_slist_length((GSList *)srd_decoder_list()) == 0); - srd_exit(); -#endif -} -END_TEST - -/* - * Check whether srd_decoder_unload_all() works. - * If it returns != SRD_OK (or segfaults) this test will fail. - */ -START_TEST(test_unload_all) -{ - int ret; - - srd_init(DECODERS_TESTDIR); - ret = srd_decoder_load_all(); - fail_unless(ret == SRD_OK, "srd_decoder_load_all() failed: %d.", ret); - ret = srd_decoder_unload_all(); - fail_unless(ret == SRD_OK, "srd_decoder_unload_all() failed: %d.", ret); - srd_exit(); -} -END_TEST - -/* - * Check whether srd_decoder_unload_all() works without prior srd_init(). - * If it returns != SRD_OK (or segfaults) this test will fail. - */ -START_TEST(test_unload_all_no_init) -{ - int ret; - - ret = srd_decoder_unload_all(); - fail_unless(ret == SRD_OK, "srd_decoder_unload_all() failed: %d.", ret); -} -END_TEST - -/* - * Check whether srd_decoder_unload_all() works multiple times. - * If it returns != SRD_OK (or segfaults) this test will fail. - */ -START_TEST(test_unload_all_multiple) -{ - int ret, i; - - srd_init(DECODERS_TESTDIR); - for (i = 0; i < 10; i++) { - ret = srd_decoder_load_all(); - fail_unless(ret == SRD_OK, "srd_decoder_load_all() failed: %d.", ret); - ret = srd_decoder_unload_all(); - fail_unless(ret == SRD_OK, "srd_decoder_unload_all() failed: %d.", ret); - } - srd_exit(); -} -END_TEST - -/* - * Check whether srd_decoder_unload_all() works multiple times (no load). - * If it returns != SRD_OK (or segfaults) this test will fail. - */ -START_TEST(test_unload_all_multiple_noload) -{ - int ret, i; - - srd_init(DECODERS_TESTDIR); - for (i = 0; i < 10; i++) { - ret = srd_decoder_unload_all(); - fail_unless(ret == SRD_OK, "srd_decoder_unload_all() failed: %d.", ret); - } - srd_exit(); -} -END_TEST - -/* - * Check whether srd_decoder_unload() works. - * If it returns != SRD_OK (or segfaults) this test will fail. - */ -START_TEST(test_unload) -{ - int ret; - struct srd_decoder *dec; - - srd_init(DECODERS_TESTDIR); - ret = srd_decoder_load("uart"); - fail_unless(ret == SRD_OK, "srd_decoder_load(uart) failed: %d.", ret); - dec = srd_decoder_get_by_id("uart"); - fail_unless(dec != NULL); - ret = srd_decoder_unload(dec); - fail_unless(ret == SRD_OK, "srd_decoder_unload() failed: %d.", ret); - srd_exit(); -} -END_TEST - -/* - * Check whether srd_decoder_unload(NULL) fails. - * If it returns SRD_OK (or segfaults) this test will fail. - */ -START_TEST(test_unload_null) -{ - srd_init(DECODERS_TESTDIR); - fail_unless(srd_decoder_unload(NULL) != SRD_OK); - srd_exit(); -} -END_TEST - -/* - * Check whether srd_decoder_unload(NULL) fails without prior srd_init(). - * If it returns SRD_OK (or segfaults) this test will fail. - */ -START_TEST(test_unload_null_no_init) -{ - fail_unless(srd_decoder_unload(NULL) != SRD_OK); -} -END_TEST - -/* - * Check whether srd_decoder_list() returns a non-empty list. - * If it returns an empty list (or segfaults) this test will fail. - */ -START_TEST(test_decoder_list) -{ - srd_init(DECODERS_TESTDIR); - srd_decoder_load_all(); - fail_unless(srd_decoder_list() != NULL); - srd_exit(); -} -END_TEST - -/* - * Check whether srd_decoder_list() without prior srd_decoder_load_all() - * returns an empty list (return value != NULL). - * If it returns a non-empty list (or segfaults) this test will fail. - */ -START_TEST(test_decoder_list_no_load) -{ - srd_init(DECODERS_TESTDIR); - fail_unless(srd_decoder_list() == NULL); - srd_exit(); -} -END_TEST - -/* - * Check whether srd_decoder_list() without prior srd_init() - * returns an empty list. - * If it returns a non-empty list (or segfaults) this test will fail. - * See also: http://sigrok.org/bugzilla/show_bug.cgi?id=178 - */ -START_TEST(test_decoder_list_no_init) -{ - srd_decoder_load_all(); - fail_unless(srd_decoder_list() == NULL); -} -END_TEST - -/* - * Check whether srd_decoder_list() without prior srd_init() and without - * prior srd_decoder_load_all() returns an empty list. - * If it returns a non-empty list (or segfaults) this test will fail. - */ -START_TEST(test_decoder_list_no_init_no_load) -{ - fail_unless(srd_decoder_list() == NULL); -} -END_TEST - -/* - * Check whether srd_decoder_list() returns the correct number of PDs. - * If it returns a wrong number (or segfaults) this test will fail. - */ -START_TEST(test_decoder_list_correct_numbers) -{ - srd_init(DECODERS_TESTDIR); - fail_unless(g_slist_length((GSList *)srd_decoder_list()) == 0); - srd_decoder_load("spi"); - fail_unless(g_slist_length((GSList *)srd_decoder_list()) == 1); - srd_decoder_load("uart"); - fail_unless(g_slist_length((GSList *)srd_decoder_list()) == 2); - srd_decoder_load("can"); - fail_unless(g_slist_length((GSList *)srd_decoder_list()) == 3); - srd_decoder_load("can"); /* Load same PD twice. */ - fail_unless(g_slist_length((GSList *)srd_decoder_list()) == 3); - srd_exit(); -} -END_TEST - -/* - * Check whether srd_decoder_get_by_id() works. - * If it returns NULL for valid PDs (or segfaults) this test will fail. - */ -START_TEST(test_get_by_id) -{ - srd_init(DECODERS_TESTDIR); - srd_decoder_load("uart"); - fail_unless(srd_decoder_get_by_id("uart") != NULL); - fail_unless(srd_decoder_get_by_id("can") == NULL); - srd_decoder_load("can"); - fail_unless(srd_decoder_get_by_id("uart") != NULL); - fail_unless(srd_decoder_get_by_id("can") != NULL); - srd_exit(); -} -END_TEST - -/* - * Check whether srd_decoder_get_by_id() works multiple times in a row. - * If it returns NULL for valid PDs (or segfaults) this test will fail. - */ -START_TEST(test_get_by_id_multiple) -{ - srd_init(DECODERS_TESTDIR); - srd_decoder_load("uart"); - fail_unless(srd_decoder_get_by_id("uart") != NULL); - fail_unless(srd_decoder_get_by_id("uart") != NULL); - fail_unless(srd_decoder_get_by_id("uart") != NULL); - fail_unless(srd_decoder_get_by_id("uart") != NULL); - srd_exit(); -} -END_TEST - -/* - * Check whether srd_decoder_get_by_id() fails for bogus PDs. - * If it returns a value != NULL (or segfaults) this test will fail. - */ -START_TEST(test_get_by_id_bogus) -{ - srd_init(DECODERS_TESTDIR); - fail_unless(srd_decoder_get_by_id(NULL) == NULL); - fail_unless(srd_decoder_get_by_id("") == NULL); - fail_unless(srd_decoder_get_by_id(" ") == NULL); - fail_unless(srd_decoder_get_by_id("nonexisting") == NULL); - fail_unless(srd_decoder_get_by_id("sPi") == NULL); - fail_unless(srd_decoder_get_by_id("SPI") == NULL); - fail_unless(srd_decoder_get_by_id("s p i") == NULL); - fail_unless(srd_decoder_get_by_id(" spi") == NULL); - fail_unless(srd_decoder_get_by_id("spi ") == NULL); - fail_unless(srd_decoder_get_by_id(" spi ") == NULL); - fail_unless(srd_decoder_get_by_id("spi uart") == NULL); - srd_exit(); -} -END_TEST - -/* - * Check whether srd_decoder_doc_get() works. - * If it returns NULL for valid PDs (or segfaults) this test will fail. - */ -START_TEST(test_doc_get) -{ - struct srd_decoder *dec; - char *doc; - - srd_init(DECODERS_TESTDIR); - srd_decoder_load("uart"); - dec = srd_decoder_get_by_id("uart"); - doc = srd_decoder_doc_get(dec); - fail_unless(doc != NULL); - g_free(doc); - srd_exit(); -} -END_TEST - -/* - * Check whether srd_decoder_doc_get() fails with NULL as argument. - * If it returns a value != NULL (or segfaults) this test will fail. - * See also: http://sigrok.org/bugzilla/show_bug.cgi?id=179 - */ -START_TEST(test_doc_get_null) -{ - srd_init(DECODERS_TESTDIR); - fail_unless(srd_decoder_doc_get(NULL) == NULL); - srd_exit(); -} -END_TEST - -Suite *suite_decoder(void) -{ - Suite *s; - TCase *tc; - - s = suite_create("decoder"); - - tc = tcase_create("load"); - tcase_set_timeout(tc, 0); - tcase_add_checked_fixture(tc, srdtest_setup, srdtest_teardown); - tcase_add_test(tc, test_load_all); - tcase_add_test(tc, test_load_all_no_init); - tcase_add_test(tc, test_load); - tcase_add_test(tc, test_load_bogus); - tcase_add_test(tc, test_load_valid_and_bogus); - tcase_add_test(tc, test_load_multiple); - tcase_add_test(tc, test_load_nonexisting_pd_dir); - suite_add_tcase(s, tc); - - tc = tcase_create("unload"); - tcase_add_checked_fixture(tc, srdtest_setup, srdtest_teardown); - tcase_add_test(tc, test_unload_all); - tcase_add_test(tc, test_unload_all_no_init); - tcase_add_test(tc, test_unload_all_multiple); - tcase_add_test(tc, test_unload_all_multiple_noload); - tcase_add_test(tc, test_unload); - tcase_add_test(tc, test_unload_null); - tcase_add_test(tc, test_unload_null_no_init); - suite_add_tcase(s, tc); - - tc = tcase_create("list"); - tcase_add_checked_fixture(tc, srdtest_setup, srdtest_teardown); - tcase_add_test(tc, test_decoder_list); - tcase_add_test(tc, test_decoder_list_no_load); - tcase_add_test(tc, test_decoder_list_no_init); - tcase_add_test(tc, test_decoder_list_no_init_no_load); - tcase_add_test(tc, test_decoder_list_correct_numbers); - suite_add_tcase(s, tc); - - tc = tcase_create("get_by_id"); - tcase_add_test(tc, test_get_by_id); - tcase_add_test(tc, test_get_by_id_multiple); - tcase_add_test(tc, test_get_by_id_bogus); - suite_add_tcase(s, tc); - - tc = tcase_create("doc_get"); - tcase_add_test(tc, test_doc_get); - tcase_add_test(tc, test_doc_get_null); - suite_add_tcase(s, tc); - - return s; -} diff --git a/test/decode_test/inst.c b/test/decode_test/inst.c deleted file mode 100755 index fd8f709a..00000000 --- a/test/decode_test/inst.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - * This file is part of the libsigrokdecode project. - * - * Copyright (C) 2013 Uwe Hermann - * - * 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, see . - */ - -#include -#include /* First, to avoid compiler warning. */ -#include -#include -#include "lib.h" - -/* - * Check whether srd_inst_new() works. - * If it returns NULL (or segfaults) this test will fail. - */ -START_TEST(test_inst_new) -{ - struct srd_session *sess; - struct srd_decoder_inst *inst; - - srd_init(DECODERS_TESTDIR); - srd_decoder_load("uart"); - srd_session_new(&sess); - inst = srd_inst_new(sess, "uart", NULL); - fail_unless(inst != NULL, "srd_inst_new() failed."); - srd_exit(); -} -END_TEST - -/* - * Check whether multiple srd_inst_new() calls work. - * If any of them returns NULL (or segfaults) this test will fail. - */ -START_TEST(test_inst_new_multiple) -{ - struct srd_session *sess; - struct srd_decoder_inst *inst1, *inst2, *inst3; - - inst1 = inst2 = inst3 = NULL; - - srd_init(DECODERS_TESTDIR); - srd_decoder_load_all(); - srd_session_new(&sess); - - /* Multiple srd_inst_new() calls must work. */ - inst1 = srd_inst_new(sess, "uart", NULL); - fail_unless(inst1 != NULL, "srd_inst_new() 1 failed."); - inst2 = srd_inst_new(sess, "spi", NULL); - fail_unless(inst2 != NULL, "srd_inst_new() 2 failed."); - inst3 = srd_inst_new(sess, "can", NULL); - fail_unless(inst3 != NULL, "srd_inst_new() 3 failed."); - - /* The returned instance pointers must not be the same. */ - fail_unless(inst1 != inst2); - fail_unless(inst1 != inst3); - fail_unless(inst2 != inst3); - - /* Each instance must have another py_inst than any of the others. */ - fail_unless(inst1->py_inst != inst2->py_inst); - fail_unless(inst1->py_inst != inst3->py_inst); - fail_unless(inst2->py_inst != inst3->py_inst); - - srd_exit(); -} -END_TEST - -/* - * Check whether srd_inst_option_set() works for an empty options hash. - * If it returns != SRD_OK (or segfaults) this test will fail. - */ -START_TEST(test_inst_option_set_empty) -{ - int ret; - struct srd_session *sess; - struct srd_decoder_inst *inst; - GHashTable *options; - - srd_init(DECODERS_TESTDIR); - srd_decoder_load_all(); - srd_session_new(&sess); - inst = srd_inst_new(sess, "uart", NULL); - options = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, - (GDestroyNotify)g_variant_unref); - ret = srd_inst_option_set(inst, options); - fail_unless(ret == SRD_OK, "srd_inst_option_set() with empty options " - "hash failed: %d.", ret); - srd_exit(); -} -END_TEST - -/* - * Check whether srd_inst_option_set() works for bogus options. - * If it returns != SRD_OK (or segfaults) this test will fail. - */ -START_TEST(test_inst_option_set_bogus) -{ - int ret; - struct srd_session *sess; - struct srd_decoder_inst *inst; - GHashTable *options; - - srd_init(DECODERS_TESTDIR); - srd_decoder_load_all(); - srd_session_new(&sess); - inst = srd_inst_new(sess, "uart", NULL); - - options = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, - (GDestroyNotify)g_variant_unref); - - /* NULL instance. */ - ret = srd_inst_option_set(NULL, options); - fail_unless(ret != SRD_OK, "srd_inst_option_set() with NULL " - "instance failed: %d.", ret); - - /* NULL 'options' GHashTable. */ - ret = srd_inst_option_set(inst, NULL); - fail_unless(ret != SRD_OK, "srd_inst_option_set() with NULL " - "options hash failed: %d.", ret); - - /* NULL instance and NULL 'options' GHashTable. */ - ret = srd_inst_option_set(NULL, NULL); - fail_unless(ret != SRD_OK, "srd_inst_option_set() with NULL " - "instance and NULL options hash failed: %d.", ret); - - srd_exit(); -} -END_TEST - -Suite *suite_inst(void) -{ - Suite *s; - TCase *tc; - - s = suite_create("inst"); - - tc = tcase_create("new"); - tcase_add_checked_fixture(tc, srdtest_setup, srdtest_teardown); - tcase_add_test(tc, test_inst_new); - tcase_add_test(tc, test_inst_new_multiple); - suite_add_tcase(s, tc); - - tc = tcase_create("option"); - tcase_add_checked_fixture(tc, srdtest_setup, srdtest_teardown); - tcase_add_test(tc, test_inst_option_set_empty); - tcase_add_test(tc, test_inst_option_set_bogus); - suite_add_tcase(s, tc); - - return s; -} diff --git a/test/decode_test/lib.h b/test/decode_test/lib.h deleted file mode 100755 index a4c1dd6b..00000000 --- a/test/decode_test/lib.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * This file is part of the libsigrokdecode project. - * - * Copyright (C) 2013 Uwe Hermann - * - * 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, see . - */ - -#ifndef LIBSIGROKDECODE_TESTS_LIB_H -#define LIBSIGROKDECODE_TESTS_LIB_H - -void srdtest_setup(void); -void srdtest_teardown(void); - -Suite *suite_core(void); -Suite *suite_decoder(void); -Suite *suite_inst(void); -Suite *suite_session(void); - -#endif diff --git a/test/decode_test/main.c b/test/decode_test/main.c deleted file mode 100755 index 879440c9..00000000 --- a/test/decode_test/main.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * This file is part of the libsigrokdecode project. - * - * Copyright (C) 2013 Uwe Hermann - * - * 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, see . - */ - -#include -#include /* First, to avoid compiler warning. */ -#include -#include -#include "lib.h" - -void srdtest_setup(void) -{ - /* Silence libsigrokdecode while the unit tests run. */ - srd_log_loglevel_set(SRD_LOG_NONE); -} - -void srdtest_teardown(void) -{ -} - -int main(void) -{ - int ret; - Suite *s; - SRunner *srunner; - - s = suite_create("mastersuite"); - srunner = srunner_create(s); - - /* Add all testsuites to the master suite. */ - srunner_add_suite(srunner, suite_core()); - srunner_add_suite(srunner, suite_decoder()); - srunner_add_suite(srunner, suite_inst()); - srunner_add_suite(srunner, suite_session()); - - srunner_run_all(srunner, CK_VERBOSE); - ret = srunner_ntests_failed(srunner); - srunner_free(srunner); - - return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} diff --git a/test/decode_test/session.c b/test/decode_test/session.c deleted file mode 100755 index 73b7669e..00000000 --- a/test/decode_test/session.c +++ /dev/null @@ -1,290 +0,0 @@ -/* - * This file is part of the libsigrokdecode project. - * - * Copyright (C) 2013 Uwe Hermann - * - * 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, see . - */ - -#include -#include /* First, to avoid compiler warning. */ -#include -#include -#include -#include -#include "lib.h" - -/* - * Check whether srd_session_new() works. - * If it returns != SRD_OK (or segfaults) this test will fail. - */ -START_TEST(test_session_new) -{ - int ret; - struct srd_session *sess; - - srd_init(NULL); - ret = srd_session_new(&sess); - fail_unless(ret == SRD_OK, "srd_session_new() failed: %d.", ret); - srd_exit(); -} -END_TEST - -/* - * Check whether srd_session_new() fails for bogus parameters. - * If it returns SRD_OK (or segfaults) this test will fail. - */ -START_TEST(test_session_new_bogus) -{ - int ret; - - srd_init(NULL); - ret = srd_session_new(NULL); - fail_unless(ret != SRD_OK, "srd_session_new(NULL) worked."); - srd_exit(); -} -END_TEST - -/* - * Check whether multiple srd_session_new() calls work. - * If any call returns != SRD_OK (or segfaults) this test will fail. - */ -START_TEST(test_session_new_multiple) -{ - int ret; - struct srd_session *sess1, *sess2, *sess3; - - sess1 = sess2 = sess3 = NULL; - - srd_init(NULL); - - /* Multiple srd_session_new() calls must work. */ - ret = srd_session_new(&sess1); - fail_unless(ret == SRD_OK, "srd_session_new() 1 failed: %d.", ret); - ret = srd_session_new(&sess2); - fail_unless(ret == SRD_OK, "srd_session_new() 2 failed: %d.", ret); - ret = srd_session_new(&sess3); - fail_unless(ret == SRD_OK, "srd_session_new() 3 failed: %d.", ret); - - /* The returned session pointers must all be non-NULL. */ - fail_unless(sess1 != NULL); - fail_unless(sess2 != NULL); - fail_unless(sess3 != NULL); - - /* The returned session pointers must not be the same. */ - fail_unless(sess1 != sess2); - fail_unless(sess1 != sess3); - fail_unless(sess2 != sess3); - - /* Each session must have another ID than any other session. */ - fail_unless(sess1->session_id != sess2->session_id); - fail_unless(sess1->session_id != sess3->session_id); - fail_unless(sess2->session_id != sess3->session_id); - - /* Destroying any of the sessions must work. */ - ret = srd_session_destroy(sess1); - fail_unless(ret == SRD_OK, "srd_session_destroy() 1 failed: %d.", ret); - ret = srd_session_destroy(sess2); - fail_unless(ret == SRD_OK, "srd_session_destroy() 2 failed: %d.", ret); - ret = srd_session_destroy(sess3); - fail_unless(ret == SRD_OK, "srd_session_destroy() 3 failed: %d.", ret); - - srd_exit(); -} -END_TEST - -/* - * Check whether srd_session_destroy() works. - * If it returns != SRD_OK (or segfaults) this test will fail. - */ -START_TEST(test_session_destroy) -{ - int ret; - struct srd_session *sess; - - srd_init(NULL); - srd_session_new(&sess); - ret = srd_session_destroy(sess); - fail_unless(ret == SRD_OK, "srd_session_destroy() failed: %d.", ret); - srd_exit(); -} -END_TEST - -/* - * Check whether srd_session_destroy() fails for bogus sessions. - * If it returns SRD_OK (or segfaults) this test will fail. - */ -START_TEST(test_session_destroy_bogus) -{ - int ret; - - srd_init(NULL); - ret = srd_session_destroy(NULL); - fail_unless(ret != SRD_OK, "srd_session_destroy() failed: %d.", ret); - srd_exit(); -} -END_TEST - -static void conf_check_ok(struct srd_session *sess, int key, uint64_t x) -{ - int ret; - - ret = srd_session_metadata_set(sess, key, g_variant_new_uint64(x)); - fail_unless(ret == SRD_OK, "srd_session_metadata_set(%p, %d, %" - PRIu64 ") failed: %d.", sess, key, x, ret); -} - -static void conf_check_fail(struct srd_session *sess, int key, uint64_t x) -{ - int ret; - GVariant *value = g_variant_new_uint64(x); - - ret = srd_session_metadata_set(sess, key, value); - fail_unless(ret != SRD_OK, "srd_session_metadata_set(%p, %d, %" - PRIu64 ") worked.", sess, key, x); - if (ret != SRD_OK) - g_variant_unref(value); -} - -static void conf_check_fail_null(struct srd_session *sess, int key) -{ - int ret; - - ret = srd_session_metadata_set(sess, key, NULL); - fail_unless(ret != SRD_OK, - "srd_session_metadata_set(NULL) for key %d worked.", key); -} - -static void conf_check_fail_str(struct srd_session *sess, int key, const char *s) -{ - int ret; - GVariant *value = g_variant_new_string(s); - - ret = srd_session_metadata_set(sess, key, value); - fail_unless(ret != SRD_OK, "srd_session_metadata_set() for key %d " - "failed: %d.", key, ret); - if (ret != SRD_OK) - g_variant_unref(value); -} - -/* - * Check whether srd_session_metadata_set() works. - * If it returns != SRD_OK (or segfaults) this test will fail. - */ -START_TEST(test_session_metadata_set) -{ - uint64_t i; - struct srd_session *sess; - - srd_init(NULL); - srd_session_new(&sess); - /* Try a bunch of values. */ - for (i = 0; i < 1000; i++) - conf_check_ok(sess, SRD_CONF_SAMPLERATE, i); - /* Try the max. possible value. */ - conf_check_ok(sess, SRD_CONF_SAMPLERATE, UINT64_MAX); - srd_session_destroy(sess); - srd_exit(); -} -END_TEST - -/* - * Check whether srd_session_metadata_set() fails with invalid input. - * If it returns SRD_OK (or segfaults) this test will fail. - */ -START_TEST(test_session_metadata_set_bogus) -{ - struct srd_session *sess; - - srd_init(NULL); - srd_session_new(&sess); - - /* Incorrect GVariant type (currently only uint64 is used). */ - conf_check_fail_str(sess, SRD_CONF_SAMPLERATE, ""); - conf_check_fail_str(sess, SRD_CONF_SAMPLERATE, "Foo"); - - /* NULL data pointer. */ - conf_check_fail_null(sess, SRD_CONF_SAMPLERATE); - - /* NULL session. */ - conf_check_fail(NULL, SRD_CONF_SAMPLERATE, 0); - - /* Invalid keys. */ - conf_check_fail(sess, -1, 0); - conf_check_fail(sess, 9, 0); - conf_check_fail(sess, 123, 0); - - srd_session_destroy(sess); - srd_exit(); -} -END_TEST - -/* - * Check whether srd_session_terminate_reset() succeeds on newly created - * sessions, as well as after calling start() and meta(). No data is fed - * to decoders here. - */ -START_TEST(test_session_reset_nodata) -{ - struct srd_session *sess; - int ret; - GVariant *data; - - srd_init(NULL); - srd_session_new(&sess); - ret = srd_session_terminate_reset(sess); - fail_unless(ret == SRD_OK, "srd_session_terminate_reset() failed: %d.", ret); - ret = srd_session_start(sess); - fail_unless(ret == SRD_OK, "srd_session_start() failed: %d.", ret); - ret = srd_session_terminate_reset(sess); - fail_unless(ret == SRD_OK, "srd_session_terminate_reset() failed: %d.", ret); - data = g_variant_new_uint64(1000000); - ret = srd_session_metadata_set(sess, SRD_CONF_SAMPLERATE, data); - fail_unless(ret == SRD_OK, "srd_session_metadata_set() failed: %d.", ret); - ret = srd_session_terminate_reset(sess); - fail_unless(ret == SRD_OK, "srd_session_terminate_reset() failed: %d.", ret); - ret = srd_session_destroy(sess); - fail_unless(ret == SRD_OK, "srd_session_destroy() failed: %d.", ret); - srd_exit(); -} -END_TEST - -Suite *suite_session(void) -{ - Suite *s; - TCase *tc; - - s = suite_create("session"); - - tc = tcase_create("new_destroy"); - tcase_add_checked_fixture(tc, srdtest_setup, srdtest_teardown); - tcase_add_test(tc, test_session_new); - tcase_add_test(tc, test_session_new_bogus); - tcase_add_test(tc, test_session_new_multiple); - tcase_add_test(tc, test_session_destroy); - tcase_add_test(tc, test_session_destroy_bogus); - suite_add_tcase(s, tc); - - tc = tcase_create("config"); - tcase_add_checked_fixture(tc, srdtest_setup, srdtest_teardown); - tcase_add_test(tc, test_session_metadata_set); - tcase_add_test(tc, test_session_metadata_set_bogus); - suite_add_tcase(s, tc); - - tc = tcase_create("reset"); - tcase_add_test(tc, test_session_reset_nodata); - suite_add_tcase(s, tc); - - return s; -} From 7d32e53d0248b55017aa71686529314244257d43 Mon Sep 17 00:00:00 2001 From: DreamSourceLab Date: Thu, 27 Jan 2022 19:23:31 -0800 Subject: [PATCH 60/60] move decoders --- .../decoders/0-i2c/__init__.py | 25 + libsigrokdecode4DSL/decoders/0-i2c/pd.py | 259 ++ .../decoders/0-spi/__init__.py | 32 + libsigrokdecode4DSL/decoders/0-spi/pd.py | 275 +++ .../decoders/0-uart/__init__.py | 40 + libsigrokdecode4DSL/decoders/0-uart/pd.py | 353 +++ .../decoders/1-i2c/__init__.py | 25 + libsigrokdecode4DSL/decoders/1-i2c/pd.py | 295 +++ .../decoders/1-spi/__init__.py | 32 + libsigrokdecode4DSL/decoders/1-spi/pd.py | 352 +++ .../decoders/1-uart/__init__.py | 40 + libsigrokdecode4DSL/decoders/1-uart/pd.py | 441 ++++ .../decoders/a7105/__init__.py | 25 + libsigrokdecode4DSL/decoders/a7105/pd.py | 356 +++ libsigrokdecode4DSL/decoders/ac97/__init__.py | 36 + libsigrokdecode4DSL/decoders/ac97/pd.py | 505 ++++ .../decoders/ad5626/__init__.py | 25 + libsigrokdecode4DSL/decoders/ad5626/pd.py | 62 + .../decoders/ad79x0/__init__.py | 25 + libsigrokdecode4DSL/decoders/ad79x0/pd.py | 137 ++ .../decoders/ade77xx/__init__.py | 32 + libsigrokdecode4DSL/decoders/ade77xx/lists.py | 102 + libsigrokdecode4DSL/decoders/ade77xx/pd.py | 131 + .../decoders/adf435x/__init__.py | 29 + libsigrokdecode4DSL/decoders/adf435x/pd.py | 144 ++ .../decoders/adns5020/__init__.py | 27 + libsigrokdecode4DSL/decoders/adns5020/pd.py | 116 + .../decoders/adxl345/__init__.py | 26 + libsigrokdecode4DSL/decoders/adxl345/lists.py | 96 + libsigrokdecode4DSL/decoders/adxl345/pd.py | 453 ++++ .../decoders/am230x/__init__.py | 36 + libsigrokdecode4DSL/decoders/am230x/pd.py | 229 ++ .../decoders/amulet_ascii/__init__.py | 28 + .../decoders/amulet_ascii/lists.py | 73 + .../decoders/amulet_ascii/pd.py | 699 ++++++ .../decoders/arm_etmv3/__init__.py | 25 + libsigrokdecode4DSL/decoders/arm_etmv3/pd.py | 567 +++++ .../decoders/arm_itm/__init__.py | 25 + libsigrokdecode4DSL/decoders/arm_itm/pd.py | 373 +++ .../decoders/arm_tpiu/__init__.py | 28 + libsigrokdecode4DSL/decoders/arm_tpiu/pd.py | 131 + .../decoders/atsha204a/__init__.py | 30 + libsigrokdecode4DSL/decoders/atsha204a/pd.py | 323 +++ libsigrokdecode4DSL/decoders/aud/__init__.py | 31 + libsigrokdecode4DSL/decoders/aud/pd.py | 107 + .../decoders/avr_isp/__init__.py | 25 + libsigrokdecode4DSL/decoders/avr_isp/parts.py | 41 + libsigrokdecode4DSL/decoders/avr_isp/pd.py | 213 ++ .../decoders/avr_pdi/__init__.py | 42 + libsigrokdecode4DSL/decoders/avr_pdi/pd.py | 576 +++++ .../decoders/caliper/__init__.py | 36 + libsigrokdecode4DSL/decoders/caliper/pd.py | 146 ++ libsigrokdecode4DSL/decoders/can/__init__.py | 29 + libsigrokdecode4DSL/decoders/can/pd.py | 415 ++++ .../decoders/cc1101/__init__.py | 28 + libsigrokdecode4DSL/decoders/cc1101/lists.py | 115 + libsigrokdecode4DSL/decoders/cc1101/pd.py | 296 +++ libsigrokdecode4DSL/decoders/cec/__init__.py | 25 + libsigrokdecode4DSL/decoders/cec/pd.py | 312 +++ .../decoders/cec/protocoldata.py | 117 + libsigrokdecode4DSL/decoders/cfp/__init__.py | 34 + libsigrokdecode4DSL/decoders/cfp/pd.py | 110 + .../decoders/cjtag-oscan0/__init__.py | 37 + .../decoders/cjtag-oscan0/pd.py | 390 +++ .../decoders/common/__init__.py | 19 + .../decoders/common/plugtrx/__init__.py | 20 + .../decoders/common/plugtrx/mod.py | 192 ++ .../decoders/common/sdcard/__init__.py | 20 + .../decoders/common/sdcard/mod.py | 151 ++ .../decoders/common/srdhelper/__init__.py | 20 + .../decoders/common/srdhelper/mod.py | 84 + .../decoders/counter/__init__.py | 28 + libsigrokdecode4DSL/decoders/counter/pd.py | 145 ++ libsigrokdecode4DSL/decoders/dali/__init__.py | 24 + libsigrokdecode4DSL/decoders/dali/lists.py | 98 + libsigrokdecode4DSL/decoders/dali/pd.py | 245 ++ .../decoders/dcf77/__init__.py | 28 + libsigrokdecode4DSL/decoders/dcf77/pd.py | 311 +++ .../decoders/dmx512/__init__.py | 25 + libsigrokdecode4DSL/decoders/dmx512/pd.py | 179 ++ .../decoders/ds1307/__init__.py | 25 + libsigrokdecode4DSL/decoders/ds1307/pd.py | 264 ++ .../decoders/ds2408/__init__.py | 25 + libsigrokdecode4DSL/decoders/ds2408/pd.py | 129 + .../decoders/ds243x/__init__.py | 25 + libsigrokdecode4DSL/decoders/ds243x/pd.py | 270 +++ .../decoders/ds28ea00/__init__.py | 25 + libsigrokdecode4DSL/decoders/ds28ea00/pd.py | 93 + libsigrokdecode4DSL/decoders/dsi/__init__.py | 24 + libsigrokdecode4DSL/decoders/dsi/pd.py | 157 ++ libsigrokdecode4DSL/decoders/edid/__init__.py | 35 + libsigrokdecode4DSL/decoders/edid/config | 1 + libsigrokdecode4DSL/decoders/edid/pd.py | 668 ++++++ libsigrokdecode4DSL/decoders/edid/pnpids.txt | 2135 +++++++++++++++++ .../decoders/eeprom24xx/__init__.py | 25 + .../decoders/eeprom24xx/lists.py | 204 ++ libsigrokdecode4DSL/decoders/eeprom24xx/pd.py | 433 ++++ .../decoders/eeprom93xx/__init__.py | 32 + libsigrokdecode4DSL/decoders/eeprom93xx/pd.py | 141 ++ .../decoders/em4100/__init__.py | 24 + libsigrokdecode4DSL/decoders/em4100/pd.py | 238 ++ .../decoders/em4305/__init__.py | 24 + libsigrokdecode4DSL/decoders/em4305/pd.py | 394 +++ .../decoders/enc28j60/__init__.py | 32 + .../decoders/enc28j60/lists.py | 161 ++ libsigrokdecode4DSL/decoders/enc28j60/pd.py | 294 +++ .../decoders/flexray/__init__.py | 32 + libsigrokdecode4DSL/decoders/flexray/pd.py | 413 ++++ libsigrokdecode4DSL/decoders/fsi/__init__.py | 25 + libsigrokdecode4DSL/decoders/fsi/pd.py | 574 +++++ libsigrokdecode4DSL/decoders/gpib/__init__.py | 24 + libsigrokdecode4DSL/decoders/gpib/pd.py | 182 ++ .../decoders/graycode/__init__.py | 24 + libsigrokdecode4DSL/decoders/graycode/pd.py | 200 ++ .../decoders/guess_bitrate/__init__.py | 40 + .../decoders/guess_bitrate/pd.py | 79 + libsigrokdecode4DSL/decoders/hdcp/__init__.py | 27 + libsigrokdecode4DSL/decoders/hdcp/pd.py | 191 ++ .../decoders/i2cdemux/__init__.py | 27 + libsigrokdecode4DSL/decoders/i2cdemux/pd.py | 80 + .../decoders/i2cfilter/__init__.py | 37 + libsigrokdecode4DSL/decoders/i2cfilter/pd.py | 93 + libsigrokdecode4DSL/decoders/i2s/__init__.py | 29 + libsigrokdecode4DSL/decoders/i2s/pd.py | 214 ++ libsigrokdecode4DSL/decoders/iec/__init__.py | 24 + libsigrokdecode4DSL/decoders/iec/pd.py | 168 ++ .../decoders/ieee488/__init__.py | 26 + libsigrokdecode4DSL/decoders/ieee488/pd.py | 748 ++++++ .../decoders/ir_irmp/__init__.py | 25 + .../decoders/ir_irmp/irmp_library.py | 137 ++ libsigrokdecode4DSL/decoders/ir_irmp/pd.py | 137 ++ .../decoders/ir_nec/__init__.py | 24 + libsigrokdecode4DSL/decoders/ir_nec/lists.py | 50 + libsigrokdecode4DSL/decoders/ir_nec/pd.py | 237 ++ .../decoders/ir_rc5/__init__.py | 24 + libsigrokdecode4DSL/decoders/ir_rc5/lists.py | 93 + libsigrokdecode4DSL/decoders/ir_rc5/pd.py | 187 ++ .../decoders/ir_rc6/__init__.py | 24 + libsigrokdecode4DSL/decoders/ir_rc6/pd.py | 205 ++ .../decoders/ir_sirc/__init__.py | 26 + libsigrokdecode4DSL/decoders/ir_sirc/lists.py | 201 ++ libsigrokdecode4DSL/decoders/ir_sirc/pd.py | 215 ++ .../decoders/jitter/__init__.py | 29 + libsigrokdecode4DSL/decoders/jitter/pd.py | 198 ++ libsigrokdecode4DSL/decoders/jtag/__init__.py | 30 + libsigrokdecode4DSL/decoders/jtag/pd.py | 289 +++ .../decoders/jtag_ejtag/__init__.py | 25 + libsigrokdecode4DSL/decoders/jtag_ejtag/pd.py | 408 ++++ .../decoders/jtag_stm32/__init__.py | 29 + libsigrokdecode4DSL/decoders/jtag_stm32/pd.py | 269 +++ .../decoders/lfast/__init__.py | 35 + libsigrokdecode4DSL/decoders/lfast/pd.py | 335 +++ libsigrokdecode4DSL/decoders/lin/__init__.py | 28 + libsigrokdecode4DSL/decoders/lin/pd.py | 235 ++ libsigrokdecode4DSL/decoders/lm75/__init__.py | 25 + libsigrokdecode4DSL/decoders/lm75/pd.py | 186 ++ libsigrokdecode4DSL/decoders/lpc/__init__.py | 25 + libsigrokdecode4DSL/decoders/lpc/pd.py | 547 +++++ .../decoders/ltc242x/__init__.py | 25 + libsigrokdecode4DSL/decoders/ltc242x/pd.py | 86 + .../decoders/ltc26x7/__init__.py | 25 + libsigrokdecode4DSL/decoders/ltc26x7/pd.py | 187 ++ .../decoders/maple_bus/__init__.py | 25 + libsigrokdecode4DSL/decoders/maple_bus/pd.py | 219 ++ .../decoders/max7219/__init__.py | 25 + libsigrokdecode4DSL/decoders/max7219/pd.py | 115 + .../decoders/mcs48/__init__.py | 31 + libsigrokdecode4DSL/decoders/mcs48/pd.py | 119 + libsigrokdecode4DSL/decoders/mdio/__init__.py | 39 + libsigrokdecode4DSL/decoders/mdio/pd.py | 327 +++ .../decoders/microwire/__init__.py | 40 + libsigrokdecode4DSL/decoders/microwire/pd.py | 195 ++ libsigrokdecode4DSL/decoders/midi/__init__.py | 28 + libsigrokdecode4DSL/decoders/midi/lists.py | 840 +++++++ libsigrokdecode4DSL/decoders/midi/pd.py | 627 +++++ .../decoders/miller/__init__.py | 26 + libsigrokdecode4DSL/decoders/miller/pd.py | 190 ++ .../decoders/mipi_dsi/__init__.py | 24 + libsigrokdecode4DSL/decoders/mipi_dsi/pd.py | 218 ++ .../decoders/mipi_rffe/__init__.py | 25 + libsigrokdecode4DSL/decoders/mipi_rffe/pd.py | 510 ++++ .../decoders/mlx90614/__init__.py | 25 + libsigrokdecode4DSL/decoders/mlx90614/pd.py | 78 + .../decoders/modbus/__init__.py | 28 + libsigrokdecode4DSL/decoders/modbus/pd.py | 934 +++++++ .../decoders/morse/__init__.py | 28 + libsigrokdecode4DSL/decoders/morse/pd.py | 250 ++ .../decoders/mrf24j40/__init__.py | 25 + .../decoders/mrf24j40/lists.py | 165 ++ libsigrokdecode4DSL/decoders/mrf24j40/pd.py | 137 ++ .../decoders/mxc6225xu/__init__.py | 28 + libsigrokdecode4DSL/decoders/mxc6225xu/pd.py | 217 ++ .../decoders/nes_gamepad/__init__.py | 54 + .../decoders/nes_gamepad/pd.py | 105 + .../decoders/nrf24l01/__init__.py | 29 + libsigrokdecode4DSL/decoders/nrf24l01/pd.py | 370 +++ .../decoders/nrf905/__init__.py | 26 + libsigrokdecode4DSL/decoders/nrf905/pd.py | 301 +++ .../decoders/numbers_and_state/__init__.py | 41 + .../decoders/numbers_and_state/pd.py | 377 +++ .../decoders/nunchuk/__init__.py | 30 + libsigrokdecode4DSL/decoders/nunchuk/pd.py | 207 ++ .../decoders/onewire_link/__init__.py | 56 + .../decoders/onewire_link/pd.py | 347 +++ .../decoders/onewire_network/__init__.py | 56 + .../decoders/onewire_network/pd.py | 185 ++ libsigrokdecode4DSL/decoders/ook/__init__.py | 36 + libsigrokdecode4DSL/decoders/ook/pd.py | 484 ++++ .../decoders/ook_oregon/__init__.py | 25 + .../decoders/ook_oregon/lists.py | 75 + libsigrokdecode4DSL/decoders/ook_oregon/pd.py | 389 +++ .../decoders/ook_vis/__init__.py | 25 + libsigrokdecode4DSL/decoders/ook_vis/pd.py | 194 ++ .../decoders/pan1321/__init__.py | 25 + libsigrokdecode4DSL/decoders/pan1321/pd.py | 164 ++ .../decoders/parallel/__init__.py | 34 + libsigrokdecode4DSL/decoders/parallel/pd.py | 213 ++ .../decoders/pca9571/__init__.py | 25 + libsigrokdecode4DSL/decoders/pca9571/pd.py | 102 + libsigrokdecode4DSL/decoders/pjdl/__init__.py | 27 + libsigrokdecode4DSL/decoders/pjdl/pd.py | 723 ++++++ libsigrokdecode4DSL/decoders/pjon/__init__.py | 25 + libsigrokdecode4DSL/decoders/pjon/pd.py | 603 +++++ libsigrokdecode4DSL/decoders/ps2/__init__.py | 26 + libsigrokdecode4DSL/decoders/ps2/pd.py | 193 ++ libsigrokdecode4DSL/decoders/pwm/__init__.py | 24 + libsigrokdecode4DSL/decoders/pwm/pd.py | 141 ++ libsigrokdecode4DSL/decoders/qi/__init__.py | 25 + libsigrokdecode4DSL/decoders/qi/pd.py | 244 ++ libsigrokdecode4DSL/decoders/qspi/__init__.py | 31 + libsigrokdecode4DSL/decoders/qspi/pd.py | 226 ++ .../decoders/rc_encode/__init__.py | 36 + libsigrokdecode4DSL/decoders/rc_encode/pd.py | 167 ++ .../decoders/rfm12/__init__.py | 25 + libsigrokdecode4DSL/decoders/rfm12/pd.py | 497 ++++ .../decoders/rgb_led_spi/__init__.py | 25 + .../decoders/rgb_led_spi/pd.py | 70 + .../decoders/rgb_led_ws281x/__init__.py | 27 + .../decoders/rgb_led_ws281x/pd.py | 195 ++ .../decoders/rtc8564/__init__.py | 25 + libsigrokdecode4DSL/decoders/rtc8564/pd.py | 254 ++ .../decoders/sae_j1850_vpw/__init__.py | 24 + .../decoders/sae_j1850_vpw/pd.py | 165 ++ .../decoders/sda2506/__init__.py | 24 + libsigrokdecode4DSL/decoders/sda2506/pd.py | 144 ++ .../decoders/sdcard_sd/__init__.py | 24 + libsigrokdecode4DSL/decoders/sdcard_sd/pd.py | 583 +++++ .../decoders/sdcard_spi/__init__.py | 68 + libsigrokdecode4DSL/decoders/sdcard_spi/pd.py | 465 ++++ libsigrokdecode4DSL/decoders/sdq/__init__.py | 28 + libsigrokdecode4DSL/decoders/sdq/pd.py | 131 + .../decoders/seven_segment/__init__.py | 24 + .../decoders/seven_segment/pd.py | 136 ++ .../decoders/signature/__init__.py | 25 + libsigrokdecode4DSL/decoders/signature/pd.py | 142 ++ libsigrokdecode4DSL/decoders/sipi/__init__.py | 30 + libsigrokdecode4DSL/decoders/sipi/pd.py | 181 ++ .../decoders/sle44xx/__init__.py | 26 + libsigrokdecode4DSL/decoders/sle44xx/pd.py | 541 +++++ .../decoders/spdif/__init__.py | 25 + libsigrokdecode4DSL/decoders/spdif/pd.py | 246 ++ .../decoders/spiflash/__init__.py | 30 + .../decoders/spiflash/lists.py | 144 ++ libsigrokdecode4DSL/decoders/spiflash/pd.py | 539 +++++ .../decoders/ssi32/__init__.py | 28 + libsigrokdecode4DSL/decoders/ssi32/pd.py | 127 + .../decoders/st25r39xx_spi/__init__.py | 31 + .../decoders/st25r39xx_spi/lists.py | 231 ++ .../decoders/st25r39xx_spi/pd.py | 350 +++ .../decoders/st7735/__init__.py | 27 + libsigrokdecode4DSL/decoders/st7735/pd.py | 173 ++ .../decoders/st7789/__init__.py | 7 + libsigrokdecode4DSL/decoders/st7789/pd.py | 296 +++ .../decoders/stepper_motor/__init__.py | 25 + .../decoders/stepper_motor/pd.py | 95 + libsigrokdecode4DSL/decoders/swd/__init__.py | 34 + libsigrokdecode4DSL/decoders/swd/pd.py | 350 +++ libsigrokdecode4DSL/decoders/swim/__init__.py | 29 + libsigrokdecode4DSL/decoders/swim/pd.py | 304 +++ .../decoders/t55xx/__init__.py | 25 + libsigrokdecode4DSL/decoders/t55xx/pd.py | 326 +++ .../decoders/tca6408a/__init__.py | 25 + libsigrokdecode4DSL/decoders/tca6408a/pd.py | 132 + .../decoders/tdm_audio/__init__.py | 25 + libsigrokdecode4DSL/decoders/tdm_audio/pd.py | 116 + .../decoders/timing/__init__.py | 24 + libsigrokdecode4DSL/decoders/timing/pd.py | 128 + .../decoders/tlc5620/__init__.py | 24 + libsigrokdecode4DSL/decoders/tlc5620/pd.py | 210 ++ .../decoders/usb_packet/__init__.py | 43 + libsigrokdecode4DSL/decoders/usb_packet/pd.py | 397 +++ .../decoders/usb_power_delivery/__init__.py | 24 + .../decoders/usb_power_delivery/pd.py | 639 +++++ .../decoders/usb_request/__init__.py | 49 + .../decoders/usb_request/pd.py | 371 +++ .../decoders/usb_signalling/__init__.py | 50 + .../decoders/usb_signalling/pd.py | 352 +++ .../decoders/wiegand/__init__.py | 28 + libsigrokdecode4DSL/decoders/wiegand/pd.py | 148 ++ .../decoders/x2444m/__init__.py | 25 + libsigrokdecode4DSL/decoders/x2444m/pd.py | 111 + libsigrokdecode4DSL/decoders/xfp/__init__.py | 38 + libsigrokdecode4DSL/decoders/xfp/pd.py | 482 ++++ .../decoders/xy2-100/__init__.py | 28 + libsigrokdecode4DSL/decoders/xy2-100/pd.py | 242 ++ libsigrokdecode4DSL/decoders/z80/__init__.py | 36 + libsigrokdecode4DSL/decoders/z80/pd.py | 359 +++ libsigrokdecode4DSL/decoders/z80/tables.py | 1083 +++++++++ 308 files changed, 50027 insertions(+) create mode 100644 libsigrokdecode4DSL/decoders/0-i2c/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/0-i2c/pd.py create mode 100644 libsigrokdecode4DSL/decoders/0-spi/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/0-spi/pd.py create mode 100644 libsigrokdecode4DSL/decoders/0-uart/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/0-uart/pd.py create mode 100644 libsigrokdecode4DSL/decoders/1-i2c/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/1-i2c/pd.py create mode 100644 libsigrokdecode4DSL/decoders/1-spi/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/1-spi/pd.py create mode 100644 libsigrokdecode4DSL/decoders/1-uart/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/1-uart/pd.py create mode 100644 libsigrokdecode4DSL/decoders/a7105/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/a7105/pd.py create mode 100644 libsigrokdecode4DSL/decoders/ac97/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/ac97/pd.py create mode 100644 libsigrokdecode4DSL/decoders/ad5626/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/ad5626/pd.py create mode 100644 libsigrokdecode4DSL/decoders/ad79x0/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/ad79x0/pd.py create mode 100644 libsigrokdecode4DSL/decoders/ade77xx/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/ade77xx/lists.py create mode 100644 libsigrokdecode4DSL/decoders/ade77xx/pd.py create mode 100644 libsigrokdecode4DSL/decoders/adf435x/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/adf435x/pd.py create mode 100644 libsigrokdecode4DSL/decoders/adns5020/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/adns5020/pd.py create mode 100644 libsigrokdecode4DSL/decoders/adxl345/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/adxl345/lists.py create mode 100644 libsigrokdecode4DSL/decoders/adxl345/pd.py create mode 100644 libsigrokdecode4DSL/decoders/am230x/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/am230x/pd.py create mode 100644 libsigrokdecode4DSL/decoders/amulet_ascii/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/amulet_ascii/lists.py create mode 100644 libsigrokdecode4DSL/decoders/amulet_ascii/pd.py create mode 100644 libsigrokdecode4DSL/decoders/arm_etmv3/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/arm_etmv3/pd.py create mode 100644 libsigrokdecode4DSL/decoders/arm_itm/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/arm_itm/pd.py create mode 100644 libsigrokdecode4DSL/decoders/arm_tpiu/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/arm_tpiu/pd.py create mode 100644 libsigrokdecode4DSL/decoders/atsha204a/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/atsha204a/pd.py create mode 100644 libsigrokdecode4DSL/decoders/aud/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/aud/pd.py create mode 100644 libsigrokdecode4DSL/decoders/avr_isp/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/avr_isp/parts.py create mode 100644 libsigrokdecode4DSL/decoders/avr_isp/pd.py create mode 100644 libsigrokdecode4DSL/decoders/avr_pdi/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/avr_pdi/pd.py create mode 100644 libsigrokdecode4DSL/decoders/caliper/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/caliper/pd.py create mode 100644 libsigrokdecode4DSL/decoders/can/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/can/pd.py create mode 100644 libsigrokdecode4DSL/decoders/cc1101/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/cc1101/lists.py create mode 100644 libsigrokdecode4DSL/decoders/cc1101/pd.py create mode 100644 libsigrokdecode4DSL/decoders/cec/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/cec/pd.py create mode 100644 libsigrokdecode4DSL/decoders/cec/protocoldata.py create mode 100644 libsigrokdecode4DSL/decoders/cfp/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/cfp/pd.py create mode 100644 libsigrokdecode4DSL/decoders/cjtag-oscan0/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/cjtag-oscan0/pd.py create mode 100644 libsigrokdecode4DSL/decoders/common/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/common/plugtrx/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/common/plugtrx/mod.py create mode 100644 libsigrokdecode4DSL/decoders/common/sdcard/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/common/sdcard/mod.py create mode 100644 libsigrokdecode4DSL/decoders/common/srdhelper/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/common/srdhelper/mod.py create mode 100644 libsigrokdecode4DSL/decoders/counter/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/counter/pd.py create mode 100644 libsigrokdecode4DSL/decoders/dali/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/dali/lists.py create mode 100644 libsigrokdecode4DSL/decoders/dali/pd.py create mode 100644 libsigrokdecode4DSL/decoders/dcf77/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/dcf77/pd.py create mode 100644 libsigrokdecode4DSL/decoders/dmx512/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/dmx512/pd.py create mode 100644 libsigrokdecode4DSL/decoders/ds1307/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/ds1307/pd.py create mode 100644 libsigrokdecode4DSL/decoders/ds2408/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/ds2408/pd.py create mode 100644 libsigrokdecode4DSL/decoders/ds243x/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/ds243x/pd.py create mode 100644 libsigrokdecode4DSL/decoders/ds28ea00/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/ds28ea00/pd.py create mode 100644 libsigrokdecode4DSL/decoders/dsi/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/dsi/pd.py create mode 100644 libsigrokdecode4DSL/decoders/edid/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/edid/config create mode 100644 libsigrokdecode4DSL/decoders/edid/pd.py create mode 100644 libsigrokdecode4DSL/decoders/edid/pnpids.txt create mode 100644 libsigrokdecode4DSL/decoders/eeprom24xx/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/eeprom24xx/lists.py create mode 100644 libsigrokdecode4DSL/decoders/eeprom24xx/pd.py create mode 100644 libsigrokdecode4DSL/decoders/eeprom93xx/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/eeprom93xx/pd.py create mode 100644 libsigrokdecode4DSL/decoders/em4100/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/em4100/pd.py create mode 100644 libsigrokdecode4DSL/decoders/em4305/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/em4305/pd.py create mode 100644 libsigrokdecode4DSL/decoders/enc28j60/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/enc28j60/lists.py create mode 100644 libsigrokdecode4DSL/decoders/enc28j60/pd.py create mode 100644 libsigrokdecode4DSL/decoders/flexray/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/flexray/pd.py create mode 100644 libsigrokdecode4DSL/decoders/fsi/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/fsi/pd.py create mode 100644 libsigrokdecode4DSL/decoders/gpib/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/gpib/pd.py create mode 100644 libsigrokdecode4DSL/decoders/graycode/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/graycode/pd.py create mode 100644 libsigrokdecode4DSL/decoders/guess_bitrate/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/guess_bitrate/pd.py create mode 100644 libsigrokdecode4DSL/decoders/hdcp/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/hdcp/pd.py create mode 100644 libsigrokdecode4DSL/decoders/i2cdemux/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/i2cdemux/pd.py create mode 100644 libsigrokdecode4DSL/decoders/i2cfilter/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/i2cfilter/pd.py create mode 100644 libsigrokdecode4DSL/decoders/i2s/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/i2s/pd.py create mode 100644 libsigrokdecode4DSL/decoders/iec/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/iec/pd.py create mode 100644 libsigrokdecode4DSL/decoders/ieee488/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/ieee488/pd.py create mode 100644 libsigrokdecode4DSL/decoders/ir_irmp/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/ir_irmp/irmp_library.py create mode 100644 libsigrokdecode4DSL/decoders/ir_irmp/pd.py create mode 100644 libsigrokdecode4DSL/decoders/ir_nec/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/ir_nec/lists.py create mode 100644 libsigrokdecode4DSL/decoders/ir_nec/pd.py create mode 100644 libsigrokdecode4DSL/decoders/ir_rc5/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/ir_rc5/lists.py create mode 100644 libsigrokdecode4DSL/decoders/ir_rc5/pd.py create mode 100644 libsigrokdecode4DSL/decoders/ir_rc6/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/ir_rc6/pd.py create mode 100644 libsigrokdecode4DSL/decoders/ir_sirc/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/ir_sirc/lists.py create mode 100644 libsigrokdecode4DSL/decoders/ir_sirc/pd.py create mode 100644 libsigrokdecode4DSL/decoders/jitter/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/jitter/pd.py create mode 100644 libsigrokdecode4DSL/decoders/jtag/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/jtag/pd.py create mode 100644 libsigrokdecode4DSL/decoders/jtag_ejtag/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/jtag_ejtag/pd.py create mode 100644 libsigrokdecode4DSL/decoders/jtag_stm32/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/jtag_stm32/pd.py create mode 100644 libsigrokdecode4DSL/decoders/lfast/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/lfast/pd.py create mode 100644 libsigrokdecode4DSL/decoders/lin/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/lin/pd.py create mode 100644 libsigrokdecode4DSL/decoders/lm75/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/lm75/pd.py create mode 100644 libsigrokdecode4DSL/decoders/lpc/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/lpc/pd.py create mode 100644 libsigrokdecode4DSL/decoders/ltc242x/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/ltc242x/pd.py create mode 100644 libsigrokdecode4DSL/decoders/ltc26x7/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/ltc26x7/pd.py create mode 100644 libsigrokdecode4DSL/decoders/maple_bus/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/maple_bus/pd.py create mode 100644 libsigrokdecode4DSL/decoders/max7219/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/max7219/pd.py create mode 100644 libsigrokdecode4DSL/decoders/mcs48/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/mcs48/pd.py create mode 100644 libsigrokdecode4DSL/decoders/mdio/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/mdio/pd.py create mode 100644 libsigrokdecode4DSL/decoders/microwire/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/microwire/pd.py create mode 100644 libsigrokdecode4DSL/decoders/midi/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/midi/lists.py create mode 100644 libsigrokdecode4DSL/decoders/midi/pd.py create mode 100644 libsigrokdecode4DSL/decoders/miller/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/miller/pd.py create mode 100644 libsigrokdecode4DSL/decoders/mipi_dsi/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/mipi_dsi/pd.py create mode 100644 libsigrokdecode4DSL/decoders/mipi_rffe/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/mipi_rffe/pd.py create mode 100644 libsigrokdecode4DSL/decoders/mlx90614/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/mlx90614/pd.py create mode 100644 libsigrokdecode4DSL/decoders/modbus/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/modbus/pd.py create mode 100644 libsigrokdecode4DSL/decoders/morse/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/morse/pd.py create mode 100644 libsigrokdecode4DSL/decoders/mrf24j40/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/mrf24j40/lists.py create mode 100644 libsigrokdecode4DSL/decoders/mrf24j40/pd.py create mode 100644 libsigrokdecode4DSL/decoders/mxc6225xu/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/mxc6225xu/pd.py create mode 100644 libsigrokdecode4DSL/decoders/nes_gamepad/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/nes_gamepad/pd.py create mode 100644 libsigrokdecode4DSL/decoders/nrf24l01/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/nrf24l01/pd.py create mode 100644 libsigrokdecode4DSL/decoders/nrf905/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/nrf905/pd.py create mode 100644 libsigrokdecode4DSL/decoders/numbers_and_state/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/numbers_and_state/pd.py create mode 100644 libsigrokdecode4DSL/decoders/nunchuk/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/nunchuk/pd.py create mode 100644 libsigrokdecode4DSL/decoders/onewire_link/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/onewire_link/pd.py create mode 100644 libsigrokdecode4DSL/decoders/onewire_network/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/onewire_network/pd.py create mode 100644 libsigrokdecode4DSL/decoders/ook/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/ook/pd.py create mode 100644 libsigrokdecode4DSL/decoders/ook_oregon/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/ook_oregon/lists.py create mode 100644 libsigrokdecode4DSL/decoders/ook_oregon/pd.py create mode 100644 libsigrokdecode4DSL/decoders/ook_vis/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/ook_vis/pd.py create mode 100644 libsigrokdecode4DSL/decoders/pan1321/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/pan1321/pd.py create mode 100644 libsigrokdecode4DSL/decoders/parallel/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/parallel/pd.py create mode 100644 libsigrokdecode4DSL/decoders/pca9571/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/pca9571/pd.py create mode 100644 libsigrokdecode4DSL/decoders/pjdl/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/pjdl/pd.py create mode 100644 libsigrokdecode4DSL/decoders/pjon/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/pjon/pd.py create mode 100644 libsigrokdecode4DSL/decoders/ps2/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/ps2/pd.py create mode 100644 libsigrokdecode4DSL/decoders/pwm/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/pwm/pd.py create mode 100644 libsigrokdecode4DSL/decoders/qi/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/qi/pd.py create mode 100644 libsigrokdecode4DSL/decoders/qspi/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/qspi/pd.py create mode 100644 libsigrokdecode4DSL/decoders/rc_encode/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/rc_encode/pd.py create mode 100644 libsigrokdecode4DSL/decoders/rfm12/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/rfm12/pd.py create mode 100644 libsigrokdecode4DSL/decoders/rgb_led_spi/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/rgb_led_spi/pd.py create mode 100644 libsigrokdecode4DSL/decoders/rgb_led_ws281x/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/rgb_led_ws281x/pd.py create mode 100644 libsigrokdecode4DSL/decoders/rtc8564/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/rtc8564/pd.py create mode 100644 libsigrokdecode4DSL/decoders/sae_j1850_vpw/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/sae_j1850_vpw/pd.py create mode 100644 libsigrokdecode4DSL/decoders/sda2506/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/sda2506/pd.py create mode 100644 libsigrokdecode4DSL/decoders/sdcard_sd/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/sdcard_sd/pd.py create mode 100644 libsigrokdecode4DSL/decoders/sdcard_spi/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/sdcard_spi/pd.py create mode 100644 libsigrokdecode4DSL/decoders/sdq/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/sdq/pd.py create mode 100644 libsigrokdecode4DSL/decoders/seven_segment/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/seven_segment/pd.py create mode 100644 libsigrokdecode4DSL/decoders/signature/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/signature/pd.py create mode 100644 libsigrokdecode4DSL/decoders/sipi/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/sipi/pd.py create mode 100644 libsigrokdecode4DSL/decoders/sle44xx/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/sle44xx/pd.py create mode 100644 libsigrokdecode4DSL/decoders/spdif/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/spdif/pd.py create mode 100644 libsigrokdecode4DSL/decoders/spiflash/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/spiflash/lists.py create mode 100644 libsigrokdecode4DSL/decoders/spiflash/pd.py create mode 100644 libsigrokdecode4DSL/decoders/ssi32/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/ssi32/pd.py create mode 100644 libsigrokdecode4DSL/decoders/st25r39xx_spi/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/st25r39xx_spi/lists.py create mode 100644 libsigrokdecode4DSL/decoders/st25r39xx_spi/pd.py create mode 100644 libsigrokdecode4DSL/decoders/st7735/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/st7735/pd.py create mode 100644 libsigrokdecode4DSL/decoders/st7789/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/st7789/pd.py create mode 100644 libsigrokdecode4DSL/decoders/stepper_motor/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/stepper_motor/pd.py create mode 100644 libsigrokdecode4DSL/decoders/swd/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/swd/pd.py create mode 100644 libsigrokdecode4DSL/decoders/swim/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/swim/pd.py create mode 100644 libsigrokdecode4DSL/decoders/t55xx/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/t55xx/pd.py create mode 100644 libsigrokdecode4DSL/decoders/tca6408a/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/tca6408a/pd.py create mode 100644 libsigrokdecode4DSL/decoders/tdm_audio/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/tdm_audio/pd.py create mode 100644 libsigrokdecode4DSL/decoders/timing/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/timing/pd.py create mode 100644 libsigrokdecode4DSL/decoders/tlc5620/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/tlc5620/pd.py create mode 100644 libsigrokdecode4DSL/decoders/usb_packet/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/usb_packet/pd.py create mode 100644 libsigrokdecode4DSL/decoders/usb_power_delivery/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/usb_power_delivery/pd.py create mode 100644 libsigrokdecode4DSL/decoders/usb_request/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/usb_request/pd.py create mode 100644 libsigrokdecode4DSL/decoders/usb_signalling/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/usb_signalling/pd.py create mode 100644 libsigrokdecode4DSL/decoders/wiegand/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/wiegand/pd.py create mode 100644 libsigrokdecode4DSL/decoders/x2444m/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/x2444m/pd.py create mode 100644 libsigrokdecode4DSL/decoders/xfp/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/xfp/pd.py create mode 100644 libsigrokdecode4DSL/decoders/xy2-100/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/xy2-100/pd.py create mode 100644 libsigrokdecode4DSL/decoders/z80/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/z80/pd.py create mode 100644 libsigrokdecode4DSL/decoders/z80/tables.py diff --git a/libsigrokdecode4DSL/decoders/0-i2c/__init__.py b/libsigrokdecode4DSL/decoders/0-i2c/__init__.py new file mode 100644 index 00000000..2a36b060 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/0-i2c/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +''' +I²C (Inter-Integrated Circuit) is a bidirectional, multi-master +bus using two signals (SCL = serial clock line, SDA = serial data line). +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/0-i2c/pd.py b/libsigrokdecode4DSL/decoders/0-i2c/pd.py new file mode 100644 index 00000000..dad9922d --- /dev/null +++ b/libsigrokdecode4DSL/decoders/0-i2c/pd.py @@ -0,0 +1,259 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2010-2016 Uwe Hermann +## Copyright (C) 2019 DreamSourceLab +## +## 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, see . +## + +# TODO: Look into arbitration, collision detection, clock synchronisation, etc. +# TODO: Implement support for inverting SDA/SCL levels (0->1 and 1->0). +# TODO: Implement support for detecting various bus errors. + +import sigrokdecode as srd + +''' +OUTPUT_PYTHON format: + +Packet: +[, ] + +: + - 'START' (START condition) + - 'START REPEAT' (Repeated START condition) + - 'ADDRESS READ' (Slave address, read) + - 'ADDRESS WRITE' (Slave address, write) + - 'DATA READ' (Data, read) + - 'DATA WRITE' (Data, write) + - 'STOP' (STOP condition) + - 'ACK' (ACK bit) + - 'NACK' (NACK bit) + - 'BITS' (: list of data/address bits and their ss/es numbers) + + is the data or address byte associated with the 'ADDRESS*' and 'DATA*' +command. Slave addresses do not include bit 0 (the READ/WRITE indication bit). +For example, a slave address field could be 0x51 (instead of 0xa2). +For 'START', 'START REPEAT', 'STOP', 'ACK', and 'NACK' is None. +''' + +# CMD: [annotation-type-index, long annotation, short annotation] +proto = { + 'START': [0, 'Start', 'S'], + 'START REPEAT': [1, 'Start repeat', 'Sr'], + 'STOP': [2, 'Stop', 'P'], + 'ACK': [3, 'ACK', 'A'], + 'NACK': [4, 'NACK', 'N'], + 'ADDRESS READ': [5, 'Address read', 'AR'], + 'ADDRESS WRITE': [6, 'Address write', 'AW'], + 'DATA READ': [7, 'Data read', 'DR'], + 'DATA WRITE': [8, 'Data write', 'DW'], +} + +class Decoder(srd.Decoder): + api_version = 3 + id = '0:i2c' + name = '0:I²C' + longname = 'Inter-Integrated Circuit' + desc = 'Two-wire, multi-master, serial bus.' + license = 'gplv2+' + inputs = ['logic'] + outputs = ['i2c'] + tags = ['Embedded/industrial'] + channels = ( + {'id': 'scl', 'type': 8, 'name': 'SCL', 'desc': 'Serial clock line'}, + {'id': 'sda', 'type': 108, 'name': 'SDA', 'desc': 'Serial data line'}, + ) + options = ( + {'id': 'address_format', 'desc': 'Displayed slave address format', + 'default': 'shifted', 'values': ('shifted', 'unshifted')}, + ) + annotations = ( + ('7', 'start', 'Start condition'), + ('6', 'repeat-start', 'Repeat start condition'), + ('1', 'stop', 'Stop condition'), + ('5', 'ack', 'ACK'), + ('0', 'nack', 'NACK'), + ('112', 'address-read', 'Address read'), + ('111', 'address-write', 'Address write'), + ('110', 'data-read', 'Data read'), + ('109', 'data-write', 'Data write'), + ('1000', 'warnings', 'Human-readable warnings'), + ) + annotation_rows = ( + ('addr-data', 'Address/Data', (0, 1, 2, 3, 4, 5, 6, 7, 8)), + ('warnings', 'Warnings', (9,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.ss = self.es = self.ss_byte = -1 + self.bitcount = 0 + self.databyte = 0 + self.wr = -1 + self.is_repeat_start = 0 + self.state = 'FIND START' + self.pdu_start = None + self.pdu_bits = 0 + self.bits = [] + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + self.put(self.ss, self.es, self.out_ann, data) + + def handle_start(self): + self.ss, self.es = self.samplenum, self.samplenum + self.pdu_start = self.samplenum + self.pdu_bits = 0 + cmd = 'START REPEAT' if (self.is_repeat_start == 1) else 'START' + self.putx([proto[cmd][0], proto[cmd][1:]]) + self.state = 'FIND ADDRESS' + self.bitcount = self.databyte = 0 + self.is_repeat_start = 1 + self.wr = -1 + self.bits = [] + + # Gather 8 bits of data plus the ACK/NACK bit. + def handle_address_or_data(self, scl, sda): + self.pdu_bits += 1 + + # Address and data are transmitted MSB-first. + self.databyte <<= 1 + self.databyte |= sda + + # Remember the start of the first data/address bit. + if self.bitcount == 0: + self.ss_byte = self.samplenum + + # Store individual bits and their start/end samplenumbers. + # In the list, index 0 represents the LSB (I²C transmits MSB-first). + self.bits.insert(0, [sda, self.samplenum, self.samplenum]) + if self.bitcount > 0: + self.bits[1][2] = self.samplenum + if self.bitcount == 7: + self.bitwidth = self.bits[1][2] - self.bits[2][2] + self.bits[0][2] += self.bitwidth + + # Return if we haven't collected all 8 + 1 bits, yet. + if self.bitcount < 7: + self.bitcount += 1 + return + + d = self.databyte + if self.state == 'FIND ADDRESS': + # The READ/WRITE bit is only in address bytes, not data bytes. + self.wr = 0 if (self.databyte & 1) else 1 + if self.options['address_format'] == 'shifted': + d = d >> 1 + + bin_class = -1 + if self.state == 'FIND ADDRESS' and self.wr == 1: + cmd = 'ADDRESS WRITE' + bin_class = 1 + elif self.state == 'FIND ADDRESS' and self.wr == 0: + cmd = 'ADDRESS READ' + bin_class = 0 + elif self.state == 'FIND DATA' and self.wr == 1: + cmd = 'DATA WRITE' + bin_class = 3 + elif self.state == 'FIND DATA' and self.wr == 0: + cmd = 'DATA READ' + bin_class = 2 + + self.ss, self.es = self.ss_byte, self.samplenum + self.bitwidth + + if cmd.startswith('ADDRESS'): + self.ss, self.es = self.samplenum, self.samplenum + self.bitwidth + w = ['Write', 'Wr', 'W'] if self.wr else ['Read', 'Rd', 'R'] + self.putx([proto[cmd][0], w]) + self.ss, self.es = self.ss_byte, self.samplenum + + self.putx([proto[cmd][0], ['%s: {$}' % proto[cmd][1], '%s: {$}' % proto[cmd][2], '{$}', d]]) + + # Done with this packet. + self.bitcount = self.databyte = 0 + self.bits = [] + self.state = 'FIND ACK' + + def get_ack(self, scl, sda): + self.ss, self.es = self.samplenum, self.samplenum + self.bitwidth + cmd = 'NACK' if (sda == 1) else 'ACK' + self.putx([proto[cmd][0], proto[cmd][1:]]) + # There could be multiple data bytes in a row, so either find + # another data byte or a STOP condition next. + self.state = 'FIND DATA' + + def handle_stop(self): + cmd = 'STOP' + self.ss, self.es = self.samplenum, self.samplenum + self.putx([proto[cmd][0], proto[cmd][1:]]) + self.state = 'FIND START' + self.is_repeat_start = 0 + self.wr = -1 + self.bits = [] + + def decode(self): + while True: + # State machine. + if self.state == 'FIND START': + # Wait for a START condition (S): SCL = high, SDA = falling. + self.wait({0: 'h', 1: 'f'}) + self.handle_start() + elif self.state == 'FIND ADDRESS': + # Wait for any of the following conditions (or combinations): + # a) Data sampling of receiver: SCL = rising, and/or + # b) START condition (S): SCL = high, SDA = falling, and/or + # c) STOP condition (P): SCL = high, SDA = rising + (scl, sda) = self.wait([{0: 'r'}, {0: 'h', 1: 'f'}, {0: 'h', 1: 'r'}]) + + # Check which of the condition(s) matched and handle them. + if (self.matched & (0b1 << 0)): + self.handle_address_or_data(scl, sda) + elif (self.matched & (0b1 << 1)): + self.handle_start() + elif (self.matched & (0b1 << 2)): + self.handle_stop() + elif self.state == 'FIND DATA': + # Wait for any of the following conditions (or combinations): + # a) Data sampling of receiver: SCL = rising, and/or + # b) START condition (S): SCL = high, SDA = falling, and/or + # c) STOP condition (P): SCL = high, SDA = rising + (scl, sda) = self.wait([{0: 'r'}, {0: 'h', 1: 'f'}, {0: 'h', 1: 'r'}]) + + # Check which of the condition(s) matched and handle them. + if (self.matched & (0b1 << 0)): + self.handle_address_or_data(scl, sda) + elif (self.matched & (0b1 << 1)): + self.handle_start() + elif (self.matched & (0b1 << 2)): + self.handle_stop() + elif self.state == 'FIND ACK': + # Wait for any of the following conditions (or combinations): + # a) a data/ack bit: SCL = rising. + # b) STOP condition (P): SCL = high, SDA = rising + (scl, sda) = self.wait([{0: 'r'}, {0: 'h', 1: 'r'}]) + if (self.matched & (0b1 << 0)): + self.get_ack(scl, sda) + elif (self.matched & (0b1 << 1)): + self.handle_stop() + diff --git a/libsigrokdecode4DSL/decoders/0-spi/__init__.py b/libsigrokdecode4DSL/decoders/0-spi/__init__.py new file mode 100644 index 00000000..dc5cbc05 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/0-spi/__init__.py @@ -0,0 +1,32 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +''' +The SPI (Serial Peripheral Interface) protocol decoder supports synchronous +SPI(-like) protocols with a clock line, a MISO and MOSI line for data +transfer in two directions, and an optional CS# pin. + +Either MISO or MOSI (but not both) can be optional. + +If CS# is supplied, data is only decoded when CS# is asserted (clock +transitions where CS# is not asserted are ignored). If CS# is not supplied, +data is decoded on every clock transition (depending on SPI mode). +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/0-spi/pd.py b/libsigrokdecode4DSL/decoders/0-spi/pd.py new file mode 100644 index 00000000..2d397f02 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/0-spi/pd.py @@ -0,0 +1,275 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2011 Gareth McMullin +## Copyright (C) 2012-2014 Uwe Hermann +## Copyright (C) 2019 DreamSourceLab +## +## 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, see . +## + +import sigrokdecode as srd +from collections import namedtuple + +Data = namedtuple('Data', ['ss', 'es', 'val']) + +''' +OUTPUT_PYTHON format: + +Packet: +[, , ] + +: + - 'DATA': contains the MOSI data, contains the MISO data. + The data is _usually_ 8 bits (but can also be fewer or more bits). + Both data items are Python numbers (not strings), or None if the respective + channel was not supplied. + - 'BITS': / contain a list of bit values in this MOSI/MISO data + item, and for each of those also their respective start-/endsample numbers. + - 'CS-CHANGE': is the old CS# pin value, is the new value. + Both data items are Python numbers (0/1), not strings. At the beginning of + the decoding a packet is generated with = None and being the + initial state of the CS# pin or None if the chip select pin is not supplied. + - 'TRANSFER': / contain a list of Data() namedtuples for each + byte transferred during this block of CS# asserted time. Each Data() has + fields ss, es, and val. + +Examples: + ['CS-CHANGE', None, 1] + ['CS-CHANGE', 1, 0] + ['DATA', 0xff, 0x3a] + ['BITS', [[1, 80, 82], [1, 83, 84], [1, 85, 86], [1, 87, 88], + [1, 89, 90], [1, 91, 92], [1, 93, 94], [1, 95, 96]], + [[0, 80, 82], [1, 83, 84], [0, 85, 86], [1, 87, 88], + [1, 89, 90], [1, 91, 92], [0, 93, 94], [0, 95, 96]]] + ['DATA', 0x65, 0x00] + ['DATA', 0xa8, None] + ['DATA', None, 0x55] + ['CS-CHANGE', 0, 1] + ['TRANSFER', [Data(ss=80, es=96, val=0xff), ...], + [Data(ss=80, es=96, val=0x3a), ...]] +''' + +# Key: (CPOL, CPHA). Value: SPI mode. +# Clock polarity (CPOL) = 0/1: Clock is low/high when inactive. +# Clock phase (CPHA) = 0/1: Data is valid on the leading/trailing clock edge. +spi_mode = { + (0, 0): 0, # Mode 0 + (0, 1): 1, # Mode 1 + (1, 0): 2, # Mode 2 + (1, 1): 3, # Mode 3 +} + +class ChannelError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = '0:spi' + name = '0:SPI' + longname = 'Serial Peripheral Interface' + desc = 'Full-duplex, synchronous, serial bus.' + license = 'gplv2+' + inputs = ['logic'] + outputs = ['spi'] + tags = ['Embedded/industrial'] + channels = ( + {'id': 'clk', 'type': 0, 'name': 'CLK', 'desc': 'Clock'}, + ) + optional_channels = ( + {'id': 'miso', 'type': 107, 'name': 'MISO', 'desc': 'Master in, slave out'}, + {'id': 'mosi', 'type': 109, 'name': 'MOSI', 'desc': 'Master out, slave in'}, + {'id': 'cs', 'type': -1, 'name': 'CS#', 'desc': 'Chip-select'}, + ) + options = ( + {'id': 'cs_polarity', 'desc': 'CS# polarity', 'default': 'active-low', + 'values': ('active-low', 'active-high')}, + {'id': 'cpol', 'desc': 'Clock polarity (CPOL)', 'default': 0, + 'values': (0, 1)}, + {'id': 'cpha', 'desc': 'Clock phase (CPHA)', 'default': 0, + 'values': (0, 1)}, + {'id': 'bitorder', 'desc': 'Bit order', + 'default': 'msb-first', 'values': ('msb-first', 'lsb-first')}, + {'id': 'wordsize', 'desc': 'Word size', 'default': 8, + 'values': tuple(range(4,129,1))}, + ) + annotations = ( + ('106', 'miso-data', 'MISO data'), + ('108', 'mosi-data', 'MOSI data'), + ) + annotation_rows = ( + ('miso-data', 'MISO data', (0,)), + ('mosi-data', 'MOSI data', (1,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.bitcount = 0 + self.misodata = self.mosidata = 0 + self.misobits = [] + self.mosibits = [] + self.ss_block = -1 + self.samplenum = -1 + self.ss_transfer = -1 + self.cs_was_deasserted = False + self.have_cs = self.have_miso = self.have_mosi = None + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.bw = (self.options['wordsize'] + 7) // 8 + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def putw(self, data): + self.put(self.ss_block, self.samplenum, self.out_ann, data) + + def putdata(self): + # Pass MISO and MOSI bits and then data to the next PD up the stack. + so = self.misodata if self.have_miso else None + si = self.mosidata if self.have_mosi else None + + if self.have_miso: + ss, es = self.misobits[-1][1], self.misobits[0][2] + if self.have_mosi: + ss, es = self.mosibits[-1][1], self.mosibits[0][2] + + # Dataword annotations. + if self.have_miso: + self.put(ss, es, self.out_ann, [0, [self.misodata]]) + if self.have_mosi: + self.put(ss, es, self.out_ann, [1, [self.mosidata]]) + + def reset_decoder_state(self): + self.misodata = 0 if self.have_miso else None + self.mosidata = 0 if self.have_mosi else None + self.misobits = [] if self.have_miso else None + self.mosibits = [] if self.have_mosi else None + self.bitcount = 0 + + def cs_asserted(self, cs): + active_low = (self.options['cs_polarity'] == 'active-low') + return (cs == 0) if active_low else (cs == 1) + + def handle_bit(self, miso, mosi, clk, cs): + # If this is the first bit of a dataword, save its sample number. + if self.bitcount == 0: + self.ss_block = self.samplenum + self.cs_was_deasserted = \ + not self.cs_asserted(cs) if self.have_cs else False + + ws = self.options['wordsize'] + bo = self.options['bitorder'] + + # Receive MISO bit into our shift register. + if self.have_miso: + if bo == 'msb-first': + self.misodata |= miso << (ws - 1 - self.bitcount) + else: + self.misodata |= miso << self.bitcount + + # Receive MOSI bit into our shift register. + if self.have_mosi: + if bo == 'msb-first': + self.mosidata |= mosi << (ws - 1 - self.bitcount) + else: + self.mosidata |= mosi << self.bitcount + + # Guesstimate the endsample for this bit (can be overridden below). + es = self.samplenum + if self.bitcount > 0: + if self.have_miso: + es += self.samplenum - self.misobits[0][1] + elif self.have_mosi: + es += self.samplenum - self.mosibits[0][1] + + if self.have_miso: + self.misobits.insert(0, [miso, self.samplenum, es]) + if self.have_mosi: + self.mosibits.insert(0, [mosi, self.samplenum, es]) + + if self.bitcount > 0 and self.have_miso: + self.misobits[1][2] = self.samplenum + if self.bitcount > 0 and self.have_mosi: + self.mosibits[1][2] = self.samplenum + + self.bitcount += 1 + + # Continue to receive if not enough bits were received, yet. + if self.bitcount != ws: + return + + self.putdata() + + self.reset_decoder_state() + + def find_clk_edge(self, miso, mosi, clk, cs, first): + if self.have_cs and (first or (self.matched & (0b1 << self.have_cs))): + # Send all CS# pin value changes. + oldcs = None if first else 1 - cs + + # Reset decoder state when CS# changes (and the CS# pin is used). + self.reset_decoder_state() + + # We only care about samples if CS# is asserted. + if self.have_cs and not self.cs_asserted(cs): + return + + # Ignore sample if the clock pin hasn't changed. + if first or not (self.matched & (0b1 << 0)): + return + + # Found the correct clock edge, now get the SPI bit(s). + self.handle_bit(miso, mosi, clk, cs) + + def decode(self): + # The CLK input is mandatory. Other signals are (individually) + # optional. Yet either MISO or MOSI (or both) must be provided. + # Tell stacked decoders when we don't have a CS# signal. + if not self.has_channel(0): + raise ChannelError('CLK pin required.') + self.have_miso = self.has_channel(1) + self.have_mosi = self.has_channel(2) + if not self.have_miso and not self.have_mosi: + raise ChannelError('Either MISO or MOSI (or both) pins required.') + self.have_cs = self.has_channel(3) + + # We want all CLK changes. We want all CS changes if CS is used. + # Map 'have_cs' from boolean to an integer index. This simplifies + # evaluation in other locations. + # Sample data on rising/falling clock edge (depends on mode). + mode = spi_mode[self.options['cpol'], self.options['cpha']] + if mode == 0 or mode == 3: # Sample on rising clock edge + wait_cond = [{0: 'r'}] + else: # Sample on falling clock edge + wait_cond = [{0: 'f'}] + + if self.have_cs: + self.have_cs = len(wait_cond) + wait_cond.append({3: 'e'}) + + # "Pixel compatibility" with the v2 implementation. Grab and + # process the very first sample before checking for edges. The + # previous implementation did this by seeding old values with + # None, which led to an immediate "change" in comparison. + (clk, miso, mosi, cs) = self.wait({}) + self.find_clk_edge(miso, mosi, clk, cs, True) + + while True: + (clk, miso, mosi, cs) = self.wait(wait_cond) + self.find_clk_edge(miso, mosi, clk, cs, False) diff --git a/libsigrokdecode4DSL/decoders/0-uart/__init__.py b/libsigrokdecode4DSL/decoders/0-uart/__init__.py new file mode 100644 index 00000000..ce6136f1 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/0-uart/__init__.py @@ -0,0 +1,40 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +''' +UART (Universal Asynchronous Receiver Transmitter) is a simple serial +communication protocol which allows two devices to talk to each other. + +This decoder should work on all "UART-like" async protocols with one +start bit (0), 5-9 databits, an (optional) parity bit, and one or more +stop bits (1), in this order. + +It can be run on one signal line (RX or TX) only, or on two lines (RX + TX). + +There are various standards for the physical layer specification of the +signals, including RS232, (TTL) UART, RS485, and others. However, the logic +level of the respective pins is only relevant when acquiring the data via +a logic analyzer (you have to select the correct logic analyzer and/or +the correct place where to probe). Once the data is in digital form and +matches the "UART" description above, this protocol decoder can work with +it though, no matter whether the source was on TTL UART levels, or RS232, +or others. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/0-uart/pd.py b/libsigrokdecode4DSL/decoders/0-uart/pd.py new file mode 100644 index 00000000..9edf2254 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/0-uart/pd.py @@ -0,0 +1,353 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2011-2014 Uwe Hermann +## Copyright (C) 2019 DreamSourceLab +## +## 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, see . +## + +import sigrokdecode as srd +from common.srdhelper import bitpack +from math import floor, ceil + +''' +OUTPUT_PYTHON format: + +Packet: +[, , ] + +This is the list of s and their respective values: + - 'STARTBIT': The data is the (integer) value of the start bit (0/1). + - 'DATA': This is always a tuple containing two items: + - 1st item: the (integer) value of the UART data. Valid values + range from 0 to 511 (as the data can be up to 9 bits in size). + - 2nd item: the list of individual data bits and their ss/es numbers. + - 'PARITYBIT': The data is the (integer) value of the parity bit (0/1). + - 'STOPBIT': The data is the (integer) value of the stop bit (0 or 1). + - 'INVALID STARTBIT': The data is the (integer) value of the start bit (0/1). + - 'INVALID STOPBIT': The data is the (integer) value of the stop bit (0/1). + - 'PARITY ERROR': The data is a tuple with two entries. The first one is + the expected parity value, the second is the actual parity value. + - 'FRAME': The data is always a tuple containing two items: The (integer) + value of the UART data, and a boolean which reflects the validity of the + UART frame. + +''' + +# Given a parity type to check (odd, even, zero, one), the value of the +# parity bit, the value of the data, and the length of the data (5-9 bits, +# usually 8 bits) return True if the parity is correct, False otherwise. +# 'none' is _not_ allowed as value for 'parity_type'. +def parity_ok(parity_type, parity_bit, data, num_data_bits): + + # Handle easy cases first (parity bit is always 1 or 0). + if parity_type == 'zero': + return parity_bit == 0 + elif parity_type == 'one': + return parity_bit == 1 + + # Count number of 1 (high) bits in the data (and the parity bit itself!). + ones = bin(data).count('1') + parity_bit + + # Check for odd/even parity. + if parity_type == 'odd': + return (ones % 2) == 1 + elif parity_type == 'even': + return (ones % 2) == 0 + +class SamplerateError(Exception): + pass + +class ChannelError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = '0:uart' + name = '0:UART' + longname = 'Universal Asynchronous Receiver/Transmitter' + desc = 'Asynchronous, serial bus.' + license = 'gplv2+' + inputs = ['logic'] + outputs = ['uart'] + tags = ['Embedded/industrial'] + channels = ( + {'id': 'rxtx', 'type': 209, 'name': 'RX/TX', 'desc': 'UART transceive line'}, + ) + options = ( + {'id': 'baudrate', 'desc': 'Baud rate', 'default': 115200}, + {'id': 'num_data_bits', 'desc': 'Data bits', 'default': 8, + 'values': tuple(range(4,129,1))}, + {'id': 'parity_type', 'desc': 'Parity type', 'default': 'none', + 'values': ('none', 'odd', 'even', 'zero', 'one')}, + {'id': 'parity_check', 'desc': 'Check parity?', 'default': 'yes', + 'values': ('yes', 'no')}, + {'id': 'num_stop_bits', 'desc': 'Stop bits', 'default': 1.0, + 'values': (0.0, 0.5, 1.0, 1.5, 2.0, 2.5)}, + {'id': 'bit_order', 'desc': 'Bit order', 'default': 'lsb-first', + 'values': ('lsb-first', 'msb-first')}, + {'id': 'format', 'desc': 'Data format', 'default': 'hex', + 'values': ('ascii', 'dec', 'hex', 'oct', 'bin')}, + {'id': 'invert', 'desc': 'Invert Signal?', 'default': 'no', + 'values': ('yes', 'no')}, + {'id': 'anno_startstop', 'desc': 'Display Start/Stop?', 'default': 'no', + 'values': ('yes', 'no')}, + ) + annotations = ( + ('108', 'data', 'data'), + ('7', 'start', 'start bits'), + ('6', 'parity-ok', 'parity OK bits'), + ('0', 'parity-err', 'parity error bits'), + ('1', 'stop', 'stop bits'), + ('1000', 'warnings', 'warnings'), + ) + annotation_rows = ( + ('data', 'RX/TX', (0, 1, 2, 3, 4)), + ('warnings', 'Warnings', (5,)), + ) + idle_state = 'WAIT FOR START BIT' + + def putx(self, data): + s, halfbit = self.startsample, self.bit_width / 2.0 + if self.options['anno_startstop'] == 'yes' : + self.put(s - floor(halfbit), self.samplenum + ceil(halfbit), self.out_ann, data) + else : + self.put(self.frame_start, self.samplenum + ceil(halfbit * (1+self.options['num_stop_bits'])), self.out_ann, data) + + def putg(self, data): + s, halfbit = self.samplenum, self.bit_width / 2.0 + self.put(s - floor(halfbit), s + ceil(halfbit), self.out_ann, data) + + def putgse(self, ss, es, data): + self.put(ss, es, self.out_ann, data) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.samplenum = 0 + self.frame_start = -1 + self.frame_valid = None + self.startbit = -1 + self.cur_data_bit = 0 + self.datavalue = 0 + self.paritybit = -1 + self.stopbit1 = -1 + self.startsample = -1 + self.state = 'WAIT FOR START BIT' + self.databits = [] + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.bw = (self.options['num_data_bits'] + 7) // 8 + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + # The width of one UART bit in number of samples. + self.bit_width = float(self.samplerate) / float(self.options['baudrate']) + + def get_sample_point(self, bitnum): + # Determine absolute sample number of a bit slot's sample point. + # bitpos is the samplenumber which is in the middle of the + # specified UART bit (0 = start bit, 1..x = data, x+1 = parity bit + # (if used) or the first stop bit, and so on). + # The samples within bit are 0, 1, ..., (bit_width - 1), therefore + # index of the middle sample within bit window is (bit_width - 1) / 2. + bitpos = self.frame_start + (self.bit_width - 1) / 2.0 + bitpos += bitnum * self.bit_width + return bitpos + + def wait_for_start_bit(self, signal): + # Save the sample number where the start bit begins. + self.frame_start = self.samplenum + self.frame_valid = True + + self.state = 'GET START BIT' + + def get_start_bit(self, signal): + self.startbit = signal + + # The startbit must be 0. If not, we report an error and wait + # for the next start bit (assuming this one was spurious). + if self.startbit != 0: + self.putg([5, ['Frame error', 'Frame err', 'FE']]) + self.frame_valid = False + es = self.samplenum + ceil(self.bit_width / 2.0) + self.state = 'WAIT FOR START BIT' + return + + self.cur_data_bit = 0 + self.datavalue = 0 + self.startsample = -1 + + if self.options['anno_startstop'] == 'yes': + self.putg([1, ['Start bit', 'Start', 'S']]) + + self.state = 'GET DATA BITS' + + def get_data_bits(self, signal): + # Save the sample number of the middle of the first data bit. + if self.startsample == -1: + self.startsample = self.samplenum + + # Store individual data bits and their start/end samplenumbers. + s, halfbit = self.samplenum, int(self.bit_width / 2) + self.databits.append([signal, s - halfbit, s + halfbit]) + + # Return here, unless we already received all data bits. + self.cur_data_bit += 1 + if self.cur_data_bit < self.options['num_data_bits']: + return + + # Convert accumulated data bits to a data value. + bits = [b[0] for b in self.databits] + if self.options['bit_order'] == 'msb-first': + bits.reverse() + self.datavalue = bitpack(bits) + self.putx([0, [self.datavalue]]) + #b = self.datavalue + #formatted = self.format_value(b) + #if formatted is not None: + # self.putx([0, [formatted]]) + + self.databits = [] + + # Advance to either reception of the parity bit, or reception of + # the STOP bits if parity is not applicable. + self.state = 'GET PARITY BIT' + if self.options['parity_type'] == 'none': + self.state = 'GET STOP BITS' + + def format_value(self, v): + # Format value 'v' according to configured options. + # Reflects the user selected kind of representation, as well as + # the number of data bits in the UART frames. + + fmt, bits = self.options['format'], self.options['num_data_bits'] + + # Assume "is printable" for values from 32 to including 126, + # below 32 is "control" and thus not printable, above 127 is + # "not ASCII" in its strict sense, 127 (DEL) is not printable, + # fall back to hex representation for non-printables. + if fmt == 'ascii': + if v in range(32, 126 + 1): + return chr(v) + hexfmt = "[{:02X}]" if bits <= 8 else "[{:03X}]" + return hexfmt.format(v) + + # Mere number to text conversion without prefix and padding + # for the "decimal" output format. + if fmt == 'dec': + return "{:d}".format(v) + + # Padding with leading zeroes for hex/oct/bin formats, but + # without a prefix for density -- since the format is user + # specified, there is no ambiguity. + if fmt == 'hex': + digits = (bits + 4 - 1) // 4 + fmtchar = "X" + elif fmt == 'oct': + digits = (bits + 3 - 1) // 3 + fmtchar = "o" + elif fmt == 'bin': + digits = bits + fmtchar = "b" + else: + fmtchar = None + if fmtchar is not None: + fmt = "{{:0{:d}{:s}}}".format(digits, fmtchar) + return fmt.format(v) + + return None + + def get_parity_bit(self, signal): + self.paritybit = signal + + if parity_ok(self.options['parity_type'], self.paritybit, + self.datavalue, self.options['num_data_bits']): + self.putg([2, ['Parity bit', 'Parity', 'P']]) + else: + # TODO: Return expected/actual parity values. + self.putg([3, ['Parity error', 'Parity err', 'PE']]) + self.frame_valid = False + + self.state = 'GET STOP BITS' + + # TODO: Currently only supports 1 stop bit. + def get_stop_bits(self, signal): + self.stopbit1 = signal + + # Stop bits must be 1. If not, we report an error. + if self.stopbit1 != 1: + self.putg([5, ['Frame error', 'Frame err', 'FE']]) + self.frame_valid = False + + if self.options['anno_startstop'] == 'yes': + self.putg([2, ['Stop bit', 'Stop', 'T']]) + + # Pass the complete UART frame to upper layers. + es = self.samplenum + ceil(self.bit_width / 2.0) + + self.state = 'WAIT FOR START BIT' + + def get_wait_cond(self, inv): + # Return condititions that are suitable for Decoder.wait(). Those + # conditions either match the falling edge of the START bit, or + # the sample point of the next bit time. + state = self.state + if state == 'WAIT FOR START BIT': + return {0: 'r' if inv else 'f'} + if state == 'GET START BIT': + bitnum = 0 + elif state == 'GET DATA BITS': + bitnum = 1 + self.cur_data_bit + elif state == 'GET PARITY BIT': + bitnum = 1 + self.options['num_data_bits'] + elif state == 'GET STOP BITS': + bitnum = 1 + self.options['num_data_bits'] + bitnum += 0 if self.options['parity_type'] == 'none' else 1 + want_num = ceil(self.get_sample_point(bitnum)) + return {'skip': want_num - self.samplenum} + + def inspect_sample(self, signal, inv): + # Inspect a sample returned by .wait() for the specified UART line. + if inv: + signal = not signal + + state = self.state + if state == 'WAIT FOR START BIT': + self.wait_for_start_bit(signal) + elif state == 'GET START BIT': + self.get_start_bit(signal) + elif state == 'GET DATA BITS': + self.get_data_bits(signal) + elif state == 'GET PARITY BIT': + self.get_parity_bit(signal) + elif state == 'GET STOP BITS': + self.get_stop_bits(signal) + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + + inv = self.options['invert'] == 'yes' + + while True: + conds = self.get_wait_cond(inv) + (rxtx, ) = self.wait(conds) + if (self.matched & (0b1 << 0)): + self.inspect_sample(rxtx, inv) diff --git a/libsigrokdecode4DSL/decoders/1-i2c/__init__.py b/libsigrokdecode4DSL/decoders/1-i2c/__init__.py new file mode 100644 index 00000000..2a36b060 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/1-i2c/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +''' +I²C (Inter-Integrated Circuit) is a bidirectional, multi-master +bus using two signals (SCL = serial clock line, SDA = serial data line). +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/1-i2c/pd.py b/libsigrokdecode4DSL/decoders/1-i2c/pd.py new file mode 100644 index 00000000..a163eba4 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/1-i2c/pd.py @@ -0,0 +1,295 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2010-2016 Uwe Hermann +## Copyright (C) 2019 DreamSourceLab +## +## 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, see . +## + +# TODO: Look into arbitration, collision detection, clock synchronisation, etc. +# TODO: Implement support for inverting SDA/SCL levels (0->1 and 1->0). +# TODO: Implement support for detecting various bus errors. + +import sigrokdecode as srd + +''' +OUTPUT_PYTHON format: + +Packet: +[, ] + +: + - 'START' (START condition) + - 'START REPEAT' (Repeated START condition) + - 'ADDRESS READ' (Slave address, read) + - 'ADDRESS WRITE' (Slave address, write) + - 'DATA READ' (Data, read) + - 'DATA WRITE' (Data, write) + - 'STOP' (STOP condition) + - 'ACK' (ACK bit) + - 'NACK' (NACK bit) + - 'BITS' (: list of data/address bits and their ss/es numbers) + + is the data or address byte associated with the 'ADDRESS*' and 'DATA*' +command. Slave addresses do not include bit 0 (the READ/WRITE indication bit). +For example, a slave address field could be 0x51 (instead of 0xa2). +For 'START', 'START REPEAT', 'STOP', 'ACK', and 'NACK' is None. +''' + +# CMD: [annotation-type-index, long annotation, short annotation] +proto = { + 'START': [0, 'Start', 'S'], + 'START REPEAT': [1, 'Start repeat', 'Sr'], + 'STOP': [2, 'Stop', 'P'], + 'ACK': [3, 'ACK', 'A'], + 'NACK': [4, 'NACK', 'N'], + 'BIT': [5, 'Bit', 'B'], + 'ADDRESS READ': [6, 'Address read', 'AR'], + 'ADDRESS WRITE': [7, 'Address write', 'AW'], + 'DATA READ': [8, 'Data read', 'DR'], + 'DATA WRITE': [9, 'Data write', 'DW'], +} + +class Decoder(srd.Decoder): + api_version = 3 + id = '1:i2c' + name = '1:I²C' + longname = 'Inter-Integrated Circuit' + desc = 'Two-wire, multi-master, serial bus.' + license = 'gplv2+' + inputs = ['logic'] + outputs = ['i2c'] + tags = ['Embedded/industrial'] + channels = ( + {'id': 'scl', 'type': 8, 'name': 'SCL', 'desc': 'Serial clock line'}, + {'id': 'sda', 'type': 108, 'name': 'SDA', 'desc': 'Serial data line'}, + ) + options = ( + {'id': 'address_format', 'desc': 'Displayed slave address format', + 'default': 'shifted', 'values': ('shifted', 'unshifted')}, + ) + annotations = ( + ('7', 'start', 'Start condition'), + ('6', 'repeat-start', 'Repeat start condition'), + ('1', 'stop', 'Stop condition'), + ('5', 'ack', 'ACK'), + ('0', 'nack', 'NACK'), + ('208', 'bit', 'Data/address bit'), + ('112', 'address-read', 'Address read'), + ('111', 'address-write', 'Address write'), + ('110', 'data-read', 'Data read'), + ('109', 'data-write', 'Data write'), + ('1000', 'warnings', 'Human-readable warnings'), + ) + annotation_rows = ( + ('bits', 'Bits', (5,)), + ('addr-data', 'Address/Data', (0, 1, 2, 3, 4, 6, 7, 8, 9)), + ('warnings', 'Warnings', (10,)), + ) + binary = ( + ('address-read', 'Address read'), + ('address-write', 'Address write'), + ('data-read', 'Data read'), + ('data-write', 'Data write'), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.ss = self.es = self.ss_byte = -1 + self.bitcount = 0 + self.databyte = 0 + self.wr = -1 + self.is_repeat_start = 0 + self.state = 'FIND START' + self.pdu_start = None + self.pdu_bits = 0 + self.bits = [] + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def start(self): + self.out_python = self.register(srd.OUTPUT_PYTHON) + self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_binary = self.register(srd.OUTPUT_BINARY) + self.out_bitrate = self.register(srd.OUTPUT_META, + meta=(int, 'Bitrate', 'Bitrate from Start bit to Stop bit')) + + def putx(self, data): + self.put(self.ss, self.es, self.out_ann, data) + + def putp(self, data): + self.put(self.ss, self.es, self.out_python, data) + + def putb(self, data): + self.put(self.ss, self.es, self.out_binary, data) + + def handle_start(self): + self.ss, self.es = self.samplenum, self.samplenum + self.pdu_start = self.samplenum + self.pdu_bits = 0 + cmd = 'START REPEAT' if (self.is_repeat_start == 1) else 'START' + self.putp([cmd, None]) + self.putx([proto[cmd][0], proto[cmd][1:]]) + self.state = 'FIND ADDRESS' + self.bitcount = self.databyte = 0 + self.is_repeat_start = 1 + self.wr = -1 + self.bits = [] + + # Gather 8 bits of data plus the ACK/NACK bit. + def handle_address_or_data(self, scl, sda): + self.pdu_bits += 1 + + # Address and data are transmitted MSB-first. + self.databyte <<= 1 + self.databyte |= sda + + # Remember the start of the first data/address bit. + if self.bitcount == 0: + self.ss_byte = self.samplenum + + # Store individual bits and their start/end samplenumbers. + # In the list, index 0 represents the LSB (I²C transmits MSB-first). + self.bits.insert(0, [sda, self.samplenum, self.samplenum]) + if self.bitcount > 0: + self.bits[1][2] = self.samplenum + if self.bitcount == 7: + self.bitwidth = self.bits[1][2] - self.bits[2][2] + self.bits[0][2] += self.bitwidth + + # Return if we haven't collected all 8 + 1 bits, yet. + if self.bitcount < 7: + self.bitcount += 1 + return + + d = self.databyte + if self.state == 'FIND ADDRESS': + # The READ/WRITE bit is only in address bytes, not data bytes. + self.wr = 0 if (self.databyte & 1) else 1 + if self.options['address_format'] == 'shifted': + d = d >> 1 + + bin_class = -1 + if self.state == 'FIND ADDRESS' and self.wr == 1: + cmd = 'ADDRESS WRITE' + bin_class = 1 + elif self.state == 'FIND ADDRESS' and self.wr == 0: + cmd = 'ADDRESS READ' + bin_class = 0 + elif self.state == 'FIND DATA' and self.wr == 1: + cmd = 'DATA WRITE' + bin_class = 3 + elif self.state == 'FIND DATA' and self.wr == 0: + cmd = 'DATA READ' + bin_class = 2 + + self.ss, self.es = self.ss_byte, self.samplenum + self.bitwidth + + self.putp(['BITS', self.bits]) + self.putp([cmd, d]) + + self.putb([bin_class, bytes([d])]) + + for bit in self.bits: + self.put(bit[1], bit[2], self.out_ann, [5, ['%d' % bit[0]]]) + + if cmd.startswith('ADDRESS'): + self.ss, self.es = self.samplenum, self.samplenum + self.bitwidth + w = ['Write', 'Wr', 'W'] if self.wr else ['Read', 'Rd', 'R'] + self.putx([0, w]) + self.ss, self.es = self.ss_byte, self.samplenum + + self.putx([proto[cmd][0], ['%s: {$}' % proto[cmd][1], '%s: {$}' % proto[cmd][2], '{$}', d]]) + + # Done with this packet. + self.bitcount = self.databyte = 0 + self.bits = [] + self.state = 'FIND ACK' + + def get_ack(self, scl, sda): + self.ss, self.es = self.samplenum, self.samplenum + self.bitwidth + cmd = 'NACK' if (sda == 1) else 'ACK' + self.putp([cmd, None]) + self.putx([proto[cmd][0], proto[cmd][1:]]) + # There could be multiple data bytes in a row, so either find + # another data byte or a STOP condition next. + self.state = 'FIND DATA' + + def handle_stop(self): + # Meta bitrate + if self.samplerate: + elapsed = 1 / float(self.samplerate) * (self.samplenum - self.pdu_start + 1) + bitrate = int(1 / elapsed * self.pdu_bits) + self.put(self.ss_byte, self.samplenum, self.out_bitrate, bitrate) + + cmd = 'STOP' + self.ss, self.es = self.samplenum, self.samplenum + self.putp([cmd, None]) + self.putx([proto[cmd][0], proto[cmd][1:]]) + self.state = 'FIND START' + self.is_repeat_start = 0 + self.wr = -1 + self.bits = [] + + def decode(self): + while True: + # State machine. + if self.state == 'FIND START': + # Wait for a START condition (S): SCL = high, SDA = falling. + self.wait({0: 'h', 1: 'f'}) + self.handle_start() + elif self.state == 'FIND ADDRESS': + # Wait for any of the following conditions (or combinations): + # a) Data sampling of receiver: SCL = rising, and/or + # b) START condition (S): SCL = high, SDA = falling, and/or + # c) STOP condition (P): SCL = high, SDA = rising + (scl, sda) = self.wait([{0: 'r'}, {0: 'h', 1: 'f'}, {0: 'h', 1: 'r'}]) + + # Check which of the condition(s) matched and handle them. + if (self.matched & (0b1 << 0)): + self.handle_address_or_data(scl, sda) + elif (self.matched & (0b1 << 1)): + self.handle_start() + elif (self.matched & (0b1 << 2)): + self.handle_stop() + elif self.state == 'FIND DATA': + # Wait for any of the following conditions (or combinations): + # a) Data sampling of receiver: SCL = rising, and/or + # b) START condition (S): SCL = high, SDA = falling, and/or + # c) STOP condition (P): SCL = high, SDA = rising + (scl, sda) = self.wait([{0: 'r'}, {0: 'h', 1: 'f'}, {0: 'h', 1: 'r'}]) + + # Check which of the condition(s) matched and handle them. + if (self.matched & (0b1 << 0)): + self.handle_address_or_data(scl, sda) + elif (self.matched & (0b1 << 1)): + self.handle_start() + elif (self.matched & (0b1 << 2)): + self.handle_stop() + elif self.state == 'FIND ACK': + # Wait for any of the following conditions (or combinations): + # a) a data/ack bit: SCL = rising. + # b) STOP condition (P): SCL = high, SDA = rising + (scl, sda) = self.wait([{0: 'r'}, {0: 'h', 1: 'r'}]) + if (self.matched & (0b1 << 0)): + self.get_ack(scl, sda) + elif (self.matched & (0b1 << 1)): + self.handle_stop() + diff --git a/libsigrokdecode4DSL/decoders/1-spi/__init__.py b/libsigrokdecode4DSL/decoders/1-spi/__init__.py new file mode 100644 index 00000000..dc5cbc05 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/1-spi/__init__.py @@ -0,0 +1,32 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +''' +The SPI (Serial Peripheral Interface) protocol decoder supports synchronous +SPI(-like) protocols with a clock line, a MISO and MOSI line for data +transfer in two directions, and an optional CS# pin. + +Either MISO or MOSI (but not both) can be optional. + +If CS# is supplied, data is only decoded when CS# is asserted (clock +transitions where CS# is not asserted are ignored). If CS# is not supplied, +data is decoded on every clock transition (depending on SPI mode). +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/1-spi/pd.py b/libsigrokdecode4DSL/decoders/1-spi/pd.py new file mode 100644 index 00000000..e17e6adb --- /dev/null +++ b/libsigrokdecode4DSL/decoders/1-spi/pd.py @@ -0,0 +1,352 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2011 Gareth McMullin +## Copyright (C) 2012-2014 Uwe Hermann +## Copyright (C) 2019 DreamSourceLab +## +## 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, see . +## + +import sigrokdecode as srd +from collections import namedtuple + +Data = namedtuple('Data', ['ss', 'es', 'val']) + +''' +OUTPUT_PYTHON format: + +Packet: +[, , ] + +: + - 'DATA': contains the MOSI data, contains the MISO data. + The data is _usually_ 8 bits (but can also be fewer or more bits). + Both data items are Python numbers (not strings), or None if the respective + channel was not supplied. + - 'BITS': / contain a list of bit values in this MOSI/MISO data + item, and for each of those also their respective start-/endsample numbers. + - 'CS-CHANGE': is the old CS# pin value, is the new value. + Both data items are Python numbers (0/1), not strings. At the beginning of + the decoding a packet is generated with = None and being the + initial state of the CS# pin or None if the chip select pin is not supplied. + - 'TRANSFER': / contain a list of Data() namedtuples for each + byte transferred during this block of CS# asserted time. Each Data() has + fields ss, es, and val. + +Examples: + ['CS-CHANGE', None, 1] + ['CS-CHANGE', 1, 0] + ['DATA', 0xff, 0x3a] + ['BITS', [[1, 80, 82], [1, 83, 84], [1, 85, 86], [1, 87, 88], + [1, 89, 90], [1, 91, 92], [1, 93, 94], [1, 95, 96]], + [[0, 80, 82], [1, 83, 84], [0, 85, 86], [1, 87, 88], + [1, 89, 90], [1, 91, 92], [0, 93, 94], [0, 95, 96]]] + ['DATA', 0x65, 0x00] + ['DATA', 0xa8, None] + ['DATA', None, 0x55] + ['CS-CHANGE', 0, 1] + ['TRANSFER', [Data(ss=80, es=96, val=0xff), ...], + [Data(ss=80, es=96, val=0x3a), ...]] +''' + +# Key: (CPOL, CPHA). Value: SPI mode. +# Clock polarity (CPOL) = 0/1: Clock is low/high when inactive. +# Clock phase (CPHA) = 0/1: Data is valid on the leading/trailing clock edge. +spi_mode = { + (0, 0): 0, # Mode 0 + (0, 1): 1, # Mode 1 + (1, 0): 2, # Mode 2 + (1, 1): 3, # Mode 3 +} + +class ChannelError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = '1:spi' + name = '1:SPI' + longname = 'Serial Peripheral Interface' + desc = 'Full-duplex, synchronous, serial bus.' + license = 'gplv2+' + inputs = ['logic'] + outputs = ['spi'] + tags = ['Embedded/industrial'] + channels = ( + {'id': 'clk', 'type': 0, 'name': 'CLK', 'desc': 'Clock'}, + ) + optional_channels = ( + {'id': 'miso', 'type': 107, 'name': 'MISO', 'desc': 'Master in, slave out'}, + {'id': 'mosi', 'type': 109, 'name': 'MOSI', 'desc': 'Master out, slave in'}, + {'id': 'cs', 'type': -1, 'name': 'CS#', 'desc': 'Chip-select'}, + ) + options = ( + {'id': 'cs_polarity', 'desc': 'CS# polarity', 'default': 'active-low', + 'values': ('active-low', 'active-high')}, + {'id': 'cpol', 'desc': 'Clock polarity (CPOL)', 'default': 0, + 'values': (0, 1)}, + {'id': 'cpha', 'desc': 'Clock phase (CPHA)', 'default': 0, + 'values': (0, 1)}, + {'id': 'bitorder', 'desc': 'Bit order', + 'default': 'msb-first', 'values': ('msb-first', 'lsb-first')}, + {'id': 'wordsize', 'desc': 'Word size', 'default': 8, + 'values': tuple(range(5,129,1))}, + {'id': 'frame', 'desc': 'Frame Decoder', 'default': 'no', + 'values': ('yes', 'no')}, + ) + annotations = ( + ('106', 'miso-data', 'MISO data'), + ('108', 'mosi-data', 'MOSI data'), + ('207', 'miso-bits', 'MISO bits'), + ('209', 'mosi-bits', 'MOSI bits'), + ('1000', 'warnings', 'Human-readable warnings'), + + ('6', 'miso-transfer', 'MISO transfer'), + ('8', 'mosi-transfer', 'MOSI transfer'), + ) + annotation_rows = ( + ('miso-bits', 'MISO bits', (2,)), + ('miso-data', 'MISO data', (0,)), + ('miso-transfer', 'MISO transfer', (5,)), + ('mosi-bits', 'MOSI bits', (3,)), + ('mosi-data', 'MOSI data', (1,)), + ('mosi-transfer', 'MOSI transfer', (6,)), + ('other', 'Other', (4,)), + ) + binary = ( + ('miso', 'MISO'), + ('mosi', 'MOSI'), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.bitcount = 0 + self.misodata = self.mosidata = 0 + self.misobits = [] + self.mosibits = [] + self.misobytes = [] + self.mosibytes = [] + self.ss_block = -1 + self.samplenum = -1 + self.ss_transfer = -1 + self.cs_was_deasserted = False + self.have_cs = self.have_miso = self.have_mosi = None + + def start(self): + self.out_python = self.register(srd.OUTPUT_PYTHON) + self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_binary = self.register(srd.OUTPUT_BINARY) + self.out_bitrate = self.register(srd.OUTPUT_META, + meta=(int, 'Bitrate', 'Bitrate during transfers')) + self.bw = (self.options['wordsize'] + 7) // 8 + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def putw(self, data): + self.put(self.ss_block, self.samplenum, self.out_ann, data) + + def putdata(self, frame): + # Pass MISO and MOSI bits and then data to the next PD up the stack. + so = self.misodata if self.have_miso else None + si = self.mosidata if self.have_mosi else None + so_bits = self.misobits if self.have_miso else None + si_bits = self.mosibits if self.have_mosi else None + + if self.have_miso: + ss, es = self.misobits[-1][1], self.misobits[0][2] + bdata = so.to_bytes(self.bw, byteorder='big') + self.put(ss, es, self.out_binary, [0, bdata]) + if self.have_mosi: + ss, es = self.mosibits[-1][1], self.mosibits[0][2] + bdata = si.to_bytes(self.bw, byteorder='big') + self.put(ss, es, self.out_binary, [1, bdata]) + + self.put(ss, es, self.out_python, ['BITS', si_bits, so_bits]) + self.put(ss, es, self.out_python, ['DATA', si, so]) + + if frame: + if self.have_miso: + self.misobytes.append(Data(ss=ss, es=es, val=so)) + if self.have_mosi: + self.mosibytes.append(Data(ss=ss, es=es, val=si)) + + # Bit annotations. + if self.have_miso: + for bit in self.misobits: + self.put(bit[1], bit[2], self.out_ann, [2, ['%d' % bit[0]]]) + if self.have_mosi: + for bit in self.mosibits: + self.put(bit[1], bit[2], self.out_ann, [3, ['%d' % bit[0]]]) + + # Dataword annotations. + if self.have_miso: + self.put(ss, es, self.out_ann, [0, ['%02X' % self.misodata]]) + if self.have_mosi: + self.put(ss, es, self.out_ann, [1, ['%02X' % self.mosidata]]) + + def reset_decoder_state(self): + self.misodata = 0 if self.have_miso else None + self.mosidata = 0 if self.have_mosi else None + self.misobits = [] if self.have_miso else None + self.mosibits = [] if self.have_mosi else None + self.bitcount = 0 + + def cs_asserted(self, cs): + active_low = (self.options['cs_polarity'] == 'active-low') + return (cs == 0) if active_low else (cs == 1) + + def handle_bit(self, miso, mosi, clk, cs, frame): + # If this is the first bit of a dataword, save its sample number. + if self.bitcount == 0: + self.ss_block = self.samplenum + self.cs_was_deasserted = \ + not self.cs_asserted(cs) if self.have_cs else False + + ws = self.options['wordsize'] + bo = self.options['bitorder'] + + # Receive MISO bit into our shift register. + if self.have_miso: + if bo == 'msb-first': + self.misodata |= miso << (ws - 1 - self.bitcount) + else: + self.misodata |= miso << self.bitcount + + # Receive MOSI bit into our shift register. + if self.have_mosi: + if bo == 'msb-first': + self.mosidata |= mosi << (ws - 1 - self.bitcount) + else: + self.mosidata |= mosi << self.bitcount + + # Guesstimate the endsample for this bit (can be overridden below). + es = self.samplenum + if self.bitcount > 0: + if self.have_miso: + es += self.samplenum - self.misobits[0][1] + elif self.have_mosi: + es += self.samplenum - self.mosibits[0][1] + + if self.have_miso: + self.misobits.insert(0, [miso, self.samplenum, es]) + if self.have_mosi: + self.mosibits.insert(0, [mosi, self.samplenum, es]) + + if self.bitcount > 0 and self.have_miso: + self.misobits[1][2] = self.samplenum + if self.bitcount > 0 and self.have_mosi: + self.mosibits[1][2] = self.samplenum + + self.bitcount += 1 + + # Continue to receive if not enough bits were received, yet. + if self.bitcount != ws: + return + + self.putdata(frame) + + # Meta bitrate. + if self.samplerate: + elapsed = 1 / float(self.samplerate) + elapsed *= (self.samplenum - self.ss_block + 1) + bitrate = int(1 / elapsed * ws) + self.put(self.ss_block, self.samplenum, self.out_bitrate, bitrate) + + if self.have_cs and self.cs_was_deasserted: + self.putw([4, ['CS# was deasserted during this data word!']]) + + self.reset_decoder_state() + + def find_clk_edge(self, miso, mosi, clk, cs, first, frame): + if self.have_cs and (first or (self.matched & (0b1 << self.have_cs))): + # Send all CS# pin value changes. + oldcs = None if first else 1 - cs + self.put(self.samplenum, self.samplenum, self.out_python, + ['CS-CHANGE', oldcs, cs]) + + if frame: + if self.cs_asserted(cs): + self.ss_transfer = self.samplenum + self.misobytes = [] + self.mosibytes = [] + elif self.ss_transfer != -1: + if self.have_miso: + self.put(self.ss_transfer, self.samplenum, self.out_ann, + [5, [' '.join(format(x.val, '02X') for x in self.misobytes)]]) + if self.have_mosi: + self.put(self.ss_transfer, self.samplenum, self.out_ann, + [6, [' '.join(format(x.val, '02X') for x in self.mosibytes)]]) + self.put(self.ss_transfer, self.samplenum, self.out_python, + ['TRANSFER', self.mosibytes, self.misobytes]) + + # Reset decoder state when CS# changes (and the CS# pin is used). + self.reset_decoder_state() + + # We only care about samples if CS# is asserted. + if self.have_cs and not self.cs_asserted(cs): + return + + # Ignore sample if the clock pin hasn't changed. + if first or not (self.matched & (0b1 << 0)): + return + + # Found the correct clock edge, now get the SPI bit(s). + self.handle_bit(miso, mosi, clk, cs, frame) + + def decode(self): + # The CLK input is mandatory. Other signals are (individually) + # optional. Yet either MISO or MOSI (or both) must be provided. + # Tell stacked decoders when we don't have a CS# signal. + if not self.has_channel(0): + raise ChannelError('CLK pin required.') + self.have_miso = self.has_channel(1) + self.have_mosi = self.has_channel(2) + if not self.have_miso and not self.have_mosi: + raise ChannelError('Either MISO or MOSI (or both) pins required.') + self.have_cs = self.has_channel(3) + if not self.have_cs: + self.put(0, 0, self.out_python, ['CS-CHANGE', None, None]) + + frame = self.options['frame'] == 'yes' + + # We want all CLK changes. We want all CS changes if CS is used. + # Map 'have_cs' from boolean to an integer index. This simplifies + # evaluation in other locations. + # Sample data on rising/falling clock edge (depends on mode). + mode = spi_mode[self.options['cpol'], self.options['cpha']] + if mode == 0 or mode == 3: # Sample on rising clock edge + wait_cond = [{0: 'r'}] + else: # Sample on falling clock edge + wait_cond = [{0: 'f'}] + + if self.have_cs: + self.have_cs = len(wait_cond) + wait_cond.append({3: 'e'}) + + # "Pixel compatibility" with the v2 implementation. Grab and + # process the very first sample before checking for edges. The + # previous implementation did this by seeding old values with + # None, which led to an immediate "change" in comparison. + (clk, miso, mosi, cs) = self.wait({}) + self.find_clk_edge(miso, mosi, clk, cs, True, frame) + + while True: + (clk, miso, mosi, cs) = self.wait(wait_cond) + self.find_clk_edge(miso, mosi, clk, cs, False, frame) diff --git a/libsigrokdecode4DSL/decoders/1-uart/__init__.py b/libsigrokdecode4DSL/decoders/1-uart/__init__.py new file mode 100644 index 00000000..ce6136f1 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/1-uart/__init__.py @@ -0,0 +1,40 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +''' +UART (Universal Asynchronous Receiver Transmitter) is a simple serial +communication protocol which allows two devices to talk to each other. + +This decoder should work on all "UART-like" async protocols with one +start bit (0), 5-9 databits, an (optional) parity bit, and one or more +stop bits (1), in this order. + +It can be run on one signal line (RX or TX) only, or on two lines (RX + TX). + +There are various standards for the physical layer specification of the +signals, including RS232, (TTL) UART, RS485, and others. However, the logic +level of the respective pins is only relevant when acquiring the data via +a logic analyzer (you have to select the correct logic analyzer and/or +the correct place where to probe). Once the data is in digital form and +matches the "UART" description above, this protocol decoder can work with +it though, no matter whether the source was on TTL UART levels, or RS232, +or others. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/1-uart/pd.py b/libsigrokdecode4DSL/decoders/1-uart/pd.py new file mode 100644 index 00000000..f3d6181c --- /dev/null +++ b/libsigrokdecode4DSL/decoders/1-uart/pd.py @@ -0,0 +1,441 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2011-2014 Uwe Hermann +## Copyright (C) 2019 DreamSourceLab +## +## 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, see . +## + +import sigrokdecode as srd +from common.srdhelper import bitpack +from math import floor, ceil + +''' +OUTPUT_PYTHON format: + +Packet: +[, , ] + +This is the list of s and their respective values: + - 'STARTBIT': The data is the (integer) value of the start bit (0/1). + - 'DATA': This is always a tuple containing two items: + - 1st item: the (integer) value of the UART data. Valid values + range from 0 to 511 (as the data can be up to 9 bits in size). + - 2nd item: the list of individual data bits and their ss/es numbers. + - 'PARITYBIT': The data is the (integer) value of the parity bit (0/1). + - 'STOPBIT': The data is the (integer) value of the stop bit (0 or 1). + - 'INVALID STARTBIT': The data is the (integer) value of the start bit (0/1). + - 'INVALID STOPBIT': The data is the (integer) value of the stop bit (0/1). + - 'PARITY ERROR': The data is a tuple with two entries. The first one is + the expected parity value, the second is the actual parity value. + - 'BREAK': The data is always 0. + - 'FRAME': The data is always a tuple containing two items: The (integer) + value of the UART data, and a boolean which reflects the validity of the + UART frame. + +''' + +# Given a parity type to check (odd, even, zero, one), the value of the +# parity bit, the value of the data, and the length of the data (5-9 bits, +# usually 8 bits) return True if the parity is correct, False otherwise. +# 'none' is _not_ allowed as value for 'parity_type'. +def parity_ok(parity_type, parity_bit, data, num_data_bits): + + # Handle easy cases first (parity bit is always 1 or 0). + if parity_type == 'zero': + return parity_bit == 0 + elif parity_type == 'one': + return parity_bit == 1 + + # Count number of 1 (high) bits in the data (and the parity bit itself!). + ones = bin(data).count('1') + parity_bit + + # Check for odd/even parity. + if parity_type == 'odd': + return (ones % 2) == 1 + elif parity_type == 'even': + return (ones % 2) == 0 + +class SamplerateError(Exception): + pass + +class ChannelError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = '1:uart' + name = '1:UART' + longname = 'Universal Asynchronous Receiver/Transmitter' + desc = 'Asynchronous, serial bus.' + license = 'gplv2+' + inputs = ['logic'] + outputs = ['uart'] + tags = ['Embedded/industrial'] + channels = ( + {'id': 'rxtx', 'type': 209, 'name': 'RX/TX', 'desc': 'UART transceive line'}, + ) + options = ( + {'id': 'baudrate', 'desc': 'Baud rate', 'default': 115200}, + {'id': 'num_data_bits', 'desc': 'Data bits', 'default': 8, + 'values': tuple(range(4,129,1))}, + {'id': 'parity_type', 'desc': 'Parity type', 'default': 'none', + 'values': ('none', 'odd', 'even', 'zero', 'one')}, + {'id': 'parity_check', 'desc': 'Check parity?', 'default': 'yes', + 'values': ('yes', 'no')}, + {'id': 'num_stop_bits', 'desc': 'Stop bits', 'default': 1.0, + 'values': (0.0, 0.5, 1.0, 1.5, 2.0, 2.5)}, + {'id': 'bit_order', 'desc': 'Bit order', 'default': 'lsb-first', + 'values': ('lsb-first', 'msb-first')}, + {'id': 'format', 'desc': 'Data format', 'default': 'hex', + 'values': ('ascii', 'dec', 'hex', 'oct', 'bin')}, + {'id': 'invert', 'desc': 'Invert Signal?', 'default': 'no', + 'values': ('yes', 'no')}, + {'id': 'anno_startstop', 'desc': 'Display Start/Stop?', 'default': 'yes', + 'values': ('yes', 'no')}, + ) + annotations = ( + ('108', 'data', 'data'), + ('7', 'start', 'start bits'), + ('6', 'parity-ok', 'parity OK bits'), + ('0', 'parity-err', 'parity error bits'), + ('1', 'stop', 'stop bits'), + ('1000', 'warnings', 'warnings'), + ('209', 'data-bits', 'data bits'), + ('10', 'break', 'break'), + ) + annotation_rows = ( + ('data', 'RX/TX', (0, 1, 2, 3, 4)), + ('data-bits', 'Bits', (6,)), + ('warnings', 'Warnings', (5,)), + ('break', 'break', (7,)), + ) + binary = ( + ('rxtx', 'RX/TX dump'), + ) + idle_state = 'WAIT FOR START BIT' + + def putx(self, data): + s, halfbit = self.startsample, self.bit_width / 2.0 + if self.options['anno_startstop'] == 'yes' : + self.put(s - floor(halfbit), self.samplenum + ceil(halfbit), self.out_ann, data) + else : + self.put(self.frame_start, self.samplenum + ceil(halfbit * (1+self.options['num_stop_bits'])), self.out_ann, data) + + def putpx(self, data): + s, halfbit = self.startsample, self.bit_width / 2.0 + self.put(s - floor(halfbit), self.samplenum + ceil(halfbit), self.out_python, data) + + def putg(self, data): + s, halfbit = self.samplenum, self.bit_width / 2.0 + self.put(s - floor(halfbit), s + ceil(halfbit), self.out_ann, data) + + def putp(self, data): + s, halfbit = self.samplenum, self.bit_width / 2.0 + self.put(s - floor(halfbit), s + ceil(halfbit), self.out_python, data) + + def putgse(self, ss, es, data): + self.put(ss, es, self.out_ann, data) + + def putpse(self, ss, es, data): + self.put(ss, es, self.out_python, data) + + def putbin(self, data): + s, halfbit = self.startsample, self.bit_width / 2.0 + self.put(s - floor(halfbit), self.samplenum + ceil(halfbit), self.out_binary, data) + + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.samplenum = 0 + self.frame_start = -1 + self.frame_valid = None + self.startbit = -1 + self.cur_data_bit = 0 + self.datavalue = 0 + self.paritybit = -1 + self.stopbit1 = -1 + self.startsample = -1 + self.state = 'WAIT FOR START BIT' + self.databits = [] + self.break_start = None + + def start(self): + self.out_python = self.register(srd.OUTPUT_PYTHON) + self.out_binary = self.register(srd.OUTPUT_BINARY) + self.out_ann = self.register(srd.OUTPUT_ANN) + self.bw = (self.options['num_data_bits'] + 7) // 8 + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + # The width of one UART bit in number of samples. + self.bit_width = float(self.samplerate) / float(self.options['baudrate']) + + def get_sample_point(self, bitnum): + # Determine absolute sample number of a bit slot's sample point. + # bitpos is the samplenumber which is in the middle of the + # specified UART bit (0 = start bit, 1..x = data, x+1 = parity bit + # (if used) or the first stop bit, and so on). + # The samples within bit are 0, 1, ..., (bit_width - 1), therefore + # index of the middle sample within bit window is (bit_width - 1) / 2. + bitpos = self.frame_start + (self.bit_width - 1) / 2.0 + bitpos += bitnum * self.bit_width + return bitpos + + def wait_for_start_bit(self, signal): + # Save the sample number where the start bit begins. + self.frame_start = self.samplenum + self.frame_valid = True + + self.state = 'GET START BIT' + + def get_start_bit(self, signal): + self.startbit = signal + + # The startbit must be 0. If not, we report an error and wait + # for the next start bit (assuming this one was spurious). + if self.startbit != 0: + self.putp(['INVALID STARTBIT', 0, self.startbit]) + self.putg([5, ['Frame error', 'Frame err', 'FE']]) + self.frame_valid = False + es = self.samplenum + ceil(self.bit_width / 2.0) + self.putpse(self.frame_start, es, ['FRAME', 0, + (self.datavalue, self.frame_valid)]) + self.state = 'WAIT FOR START BIT' + return + + self.cur_data_bit = 0 + self.datavalue = 0 + self.startsample = -1 + + self.putp(['STARTBIT', 0, self.startbit]) + if self.options['anno_startstop'] == 'yes': + self.putg([1, ['Start bit', 'Start', 'S']]) + + self.state = 'GET DATA BITS' + + def get_data_bits(self, signal): + # Save the sample number of the middle of the first data bit. + if self.startsample == -1: + self.startsample = self.samplenum + + self.putg([6, ['%d' % signal]]) + + # Store individual data bits and their start/end samplenumbers. + s, halfbit = self.samplenum, int(self.bit_width / 2) + self.databits.append([signal, s - halfbit, s + halfbit]) + + # Return here, unless we already received all data bits. + self.cur_data_bit += 1 + if self.cur_data_bit < self.options['num_data_bits']: + return + + # Convert accumulated data bits to a data value. + bits = [b[0] for b in self.databits] + if self.options['bit_order'] == 'msb-first': + bits.reverse() + self.datavalue = bitpack(bits) + self.putpx(['DATA', 0, (self.datavalue, self.databits)]) + + self.putx([0, [self.datavalue]]) + + b = self.datavalue + #formatted = self.format_value(b) + #if formatted is not None: + # self.putx([0, [formatted]]) + + bdata = b.to_bytes(self.bw, byteorder='big') + self.putbin([0, bdata]) + self.putbin([1, bdata]) + + self.databits = [] + + # Advance to either reception of the parity bit, or reception of + # the STOP bits if parity is not applicable. + self.state = 'GET PARITY BIT' + if self.options['parity_type'] == 'none': + self.state = 'GET STOP BITS' + + def format_value(self, v): + # Format value 'v' according to configured options. + # Reflects the user selected kind of representation, as well as + # the number of data bits in the UART frames. + + fmt, bits = self.options['format'], self.options['num_data_bits'] + + # Assume "is printable" for values from 32 to including 126, + # below 32 is "control" and thus not printable, above 127 is + # "not ASCII" in its strict sense, 127 (DEL) is not printable, + # fall back to hex representation for non-printables. + if fmt == 'ascii': + if v in range(32, 126 + 1): + return chr(v) + hexfmt = "[{:02X}]" if bits <= 8 else "[{:03X}]" + return hexfmt.format(v) + + # Mere number to text conversion without prefix and padding + # for the "decimal" output format. + if fmt == 'dec': + return "{:d}".format(v) + + # Padding with leading zeroes for hex/oct/bin formats, but + # without a prefix for density -- since the format is user + # specified, there is no ambiguity. + if fmt == 'hex': + digits = (bits + 4 - 1) // 4 + fmtchar = "X" + elif fmt == 'oct': + digits = (bits + 3 - 1) // 3 + fmtchar = "o" + elif fmt == 'bin': + digits = bits + fmtchar = "b" + else: + fmtchar = None + if fmtchar is not None: + fmt = "{{:0{:d}{:s}}}".format(digits, fmtchar) + return fmt.format(v) + + return None + + def get_parity_bit(self, signal): + self.paritybit = signal + + if parity_ok(self.options['parity_type'], self.paritybit, + self.datavalue, self.options['num_data_bits']): + self.putp(['PARITYBIT', 0, self.paritybit]) + self.putg([2, ['Parity bit', 'Parity', 'P']]) + else: + # TODO: Return expected/actual parity values. + self.putp(['PARITY ERROR', 0, (0, 1)]) # FIXME: Dummy tuple... + self.putg([3, ['Parity error', 'Parity err', 'PE']]) + self.frame_valid = False + + self.state = 'GET STOP BITS' + + # TODO: Currently only supports 1 stop bit. + def get_stop_bits(self, signal): + self.stopbit1 = signal + + # Stop bits must be 1. If not, we report an error. + if self.stopbit1 != 1: + self.putp(['INVALID STOPBIT', 0, self.stopbit1]) + self.putg([5, ['Frame error', 'Frame err', 'FE']]) + self.frame_valid = False + + self.putp(['STOPBIT', 0, self.stopbit1]) + if self.options['anno_startstop'] == 'yes': + self.putg([2, ['Stop bit', 'Stop', 'T']]) + + # Pass the complete UART frame to upper layers. + es = self.samplenum + ceil(self.bit_width / 2.0) + self.putpse(self.frame_start, es, ['FRAME', 0, + (self.datavalue, self.frame_valid)]) + + self.state = 'WAIT FOR START BIT' + + def handle_break(self): + self.putpse(self.frame_start, self.samplenum, + ['BREAK', 0, 0]) + self.putgse(self.frame_start, self.samplenum, + [7, ['Break condition', 'Break', 'Brk', 'B']]) + self.state = 'WAIT FOR START BIT' + + def get_wait_cond(self, inv): + # Return condititions that are suitable for Decoder.wait(). Those + # conditions either match the falling edge of the START bit, or + # the sample point of the next bit time. + state = self.state + if state == 'WAIT FOR START BIT': + return {0: 'r' if inv else 'f'} + if state == 'GET START BIT': + bitnum = 0 + elif state == 'GET DATA BITS': + bitnum = 1 + self.cur_data_bit + elif state == 'GET PARITY BIT': + bitnum = 1 + self.options['num_data_bits'] + elif state == 'GET STOP BITS': + bitnum = 1 + self.options['num_data_bits'] + bitnum += 0 if self.options['parity_type'] == 'none' else 1 + want_num = ceil(self.get_sample_point(bitnum)) + return {'skip': want_num - self.samplenum} + + def inspect_sample(self, signal, inv): + # Inspect a sample returned by .wait() for the specified UART line. + if inv: + signal = not signal + + state = self.state + if state == 'WAIT FOR START BIT': + self.wait_for_start_bit(signal) + elif state == 'GET START BIT': + self.get_start_bit(signal) + elif state == 'GET DATA BITS': + self.get_data_bits(signal) + elif state == 'GET PARITY BIT': + self.get_parity_bit(signal) + elif state == 'GET STOP BITS': + self.get_stop_bits(signal) + + def inspect_edge(self, signal, inv): + # Inspect edges, independently from traffic, to detect break conditions. + if inv: + signal = not signal + if not signal: + # Signal went low. Start another interval. + self.break_start = self.samplenum + return + # Signal went high. Was there an extended period with low signal? + if self.break_start is None: + return + diff = self.samplenum - self.break_start + if diff >= self.break_min_sample_count: + self.handle_break() + self.break_start = None + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + + inv = self.options['invert'] == 'yes' + cond_data_idx = None + + # Determine the number of samples for a complete frame's time span. + # A period of low signal (at least) that long is a break condition. + frame_samples = 1 # START + frame_samples += self.options['num_data_bits'] + frame_samples += 0 if self.options['parity_type'] == 'none' else 1 + frame_samples += self.options['num_stop_bits'] + frame_samples *= self.bit_width + self.break_min_sample_count = ceil(frame_samples) + cond_edge_idx = None + + while True: + conds = [] + + cond_data_idx = len(conds) + conds.append(self.get_wait_cond(inv)) + cond_edge_idx = len(conds) + conds.append({0: 'e'}) + + (rxtx, ) = self.wait(conds) + if cond_data_idx is not None and (self.matched & (0b1 << cond_data_idx)): + self.inspect_sample(rxtx, inv) + if cond_edge_idx is not None and (self.matched & (0b1 << cond_edge_idx)): + self.inspect_edge(rxtx, inv) diff --git a/libsigrokdecode4DSL/decoders/a7105/__init__.py b/libsigrokdecode4DSL/decoders/a7105/__init__.py new file mode 100644 index 00000000..a011c987 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/a7105/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Jens Steinhauser +## +## 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, see . +## + +''' +This decoder stacks on top of the 'spi' PD and decodes the protocol spoken +by the AMICCOM A7105 2.4GHz transceiver chips. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/a7105/pd.py b/libsigrokdecode4DSL/decoders/a7105/pd.py new file mode 100644 index 00000000..d441c666 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/a7105/pd.py @@ -0,0 +1,356 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 Richard Li +## +## 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, see . +## + +import sigrokdecode as srd + +class ChannelError(Exception): + pass + +regs = { +# addr: ('name', size) + 0x00: ('MODE', 1), + 0x01: ('MODE_CTRL', 1), + 0x02: ('CALC', 1), + 0x03: ('FIFO_I', 1), + 0x04: ('FIFO_II', 1), + 0x05: ('FIFO_DATA', 1), + 0x06: ('ID_DATA', 1), + 0x07: ('RC_OSC_I', 1), + 0x08: ('RC_OSC_II', 1), + 0x09: ('RC_OSC_III', 1), + 0x0a: ('CKO_PIN', 1), + 0x0b: ('GPIO1_PIN_I', 1), + 0x0c: ('GPIO2_PIN_II', 1), + 0x0d: ('CLOCK', 1), + 0x0e: ('DATA_RATE', 1), + 0x0f: ('PLL_I', 1), + 0x10: ('PLL_II', 1), + 0x11: ('PLL_III', 1), + 0x12: ('PLL_IV', 1), + 0x13: ('PLL_V', 1), + 0x14: ('TX_I', 1), + 0x15: ('TX_II', 1), + 0x16: ('DELAY_I', 1), + 0x17: ('DELAY_II', 1), + 0x18: ('RX', 1), + 0x19: ('RX_GAIN_I', 1), + 0x1a: ('RX_GAIN_II', 1), + 0x1b: ('RX_GAIN_III', 1), + 0x1c: ('RX_GAIN_IV', 1), + 0x1d: ('RSSI_THRES', 1), + 0x1e: ('ADC', 1), + 0x1f: ('CODE_I', 1), + 0x20: ('CODE_II', 1), + 0x21: ('CODE_III', 1), + 0x22: ('IF_CAL_I', 1), + 0x23: ('IF_CAL_II', 1), + 0x24: ('VCO_CURR_CAL', 1), + 0x25: ('VCO_SB_CALC_I', 1), + 0x26: ('VCO_SB_CALC_II', 1), + 0x27: ('BATT_DETECT', 1), + 0x28: ('TX_TEST', 1), + 0x29: ('RX_DEM_TEST_I', 1), + 0x2a: ('RX_DEM_TEST_II', 1), + 0x2b: ('CPC', 1), + 0x2c: ('CRYSTAL_TEST', 1), + 0x2d: ('PLL_TEST', 1), + 0x2e: ('VCO_TEST_I', 1), + 0x2f: ('VCO_TEST_II', 1), + 0x30: ('IFAT', 1), + 0x31: ('RSCALE', 1), + 0x32: ('FILTER_TEST', 1), + 0x33: ('UNKNOWN', 1), +} + +class Decoder(srd.Decoder): + api_version = 3 + id = 'a7105' + name = 'A7105' + longname = 'AMICCOM A7105' + desc = '2.4GHz FSK/GFSK Transceiver with 2K ~ 500Kbps data rate.' + license = 'gplv2+' + inputs = ['spi'] + outputs = [] + tags = ['IC', 'Wireless/RF'] + options = ( + {'id': 'hex_display', 'desc': 'Display payload in Hex', 'default': 'yes', + 'values': ('yes', 'no')}, + ) + annotations = ( + # Sent from the host to the chip. + ('cmd', 'Commands sent to the device'), + ('tx-data', 'Payload sent to the device'), + + # Returned by the chip. + ('rx-data', 'Payload read from the device'), + + ('warning', 'Warnings'), + ) + ann_cmd = 0 + ann_tx = 1 + ann_rx = 2 + ann_warn = 3 + annotation_rows = ( + ('commands', 'Commands', (ann_cmd, ann_tx, ann_rx)), + ('warnings', 'Warnings', (ann_warn,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.next() + self.requirements_met = True + self.cs_was_released = False + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def warn(self, pos, msg): + '''Put a warning message 'msg' at 'pos'.''' + self.put(pos[0], pos[1], self.out_ann, [self.ann_warn, [msg]]) + + def putp(self, pos, ann, msg): + '''Put an annotation message 'msg' at 'pos'.''' + self.put(pos[0], pos[1], self.out_ann, [ann, [msg]]) + + def next(self): + '''Resets the decoder after a complete command was decoded.''' + # 'True' for the first byte after CS went low. + self.first = True + + # The current command, and the minimum and maximum number + # of data bytes to follow. + self.cmd = None + self.min = 0 + self.max = 0 + + # Used to collect the bytes after the command byte + # (and the start/end sample number). + self.mb = [] + self.mb_s = -1 + self.mb_e = -1 + + def mosi_bytes(self): + '''Returns the collected MOSI bytes of a multi byte command.''' + return [b[0] for b in self.mb] + + def miso_bytes(self): + '''Returns the collected MISO bytes of a multi byte command.''' + return [b[1] for b in self.mb] + + def decode_command(self, pos, b): + '''Decodes the command byte 'b' at position 'pos' and prepares + the decoding of the following data bytes.''' + c = self.parse_command(b) + if c is None: + self.warn(pos, 'unknown command') + return + + self.cmd, self.dat, self.min, self.max = c + + if self.cmd in ('W_REGISTER', 'R_REGISTER'): + # Don't output anything now, the command is merged with + # the data bytes following it. + self.mb_s = pos[0] + else: + self.putp(pos, self.ann_cmd, self.format_command()) + + def format_command(self): + '''Returns the label for the current command.''' + return 'Cmd {}'.format(self.cmd) + + def parse_command(self, b): + '''Parses the command byte. + + Returns a tuple consisting of: + - the name of the command + - additional data needed to dissect the following bytes + - minimum number of following bytes + - maximum number of following bytes + ''' + + if b == 0x05: + return ('W_TX_FIFO', None, 1, 32) + elif b == 0x45: + return ('R_RX_FIFO', None, 1, 32) + if b == 0x06: + return ('W_ID', None, 1, 4) + elif b == 0x46: + return ('R_ID', None, 1, 4) + elif (b & 0b10000000) == 0: + if (b & 0b01000000) == 0: + c = 'W_REGISTER' + else: + c = 'R_REGISTER' + d = b & 0b00111111 + return (c, d, 1, 1) + + else: + cmd = b & 0b11110000 + if cmd == 0b10000000: + return ('SLEEP_MODE', None, 0, 0) + if cmd == 0b10010000: + return ('IDLE_MODE', None, 0, 0) + if cmd == 0b10100000: + return ('STANDBY_MODE', None, 0, 0) + if cmd == 0b10110000: + return ('PLL_MODE', None, 0, 0) + if cmd == 0b11000000: + return ('RX_MODE', None, 0, 0) + if cmd == 0b11010000: + return ('TX_MODE', None, 0, 0) + if cmd == 0b11100000: + return ('FIFO_WRITE_PTR_RESET', None, 0, 0) + if cmd == 0b11110000: + return ('FIFO_READ_PTR_RESET', None, 0, 0) + + def decode_register(self, pos, ann, regid, data): + '''Decodes a register. + + pos -- start and end sample numbers of the register + ann -- is the annotation number that is used to output the register. + regid -- may be either an integer used as a key for the 'regs' + dictionary, or a string directly containing a register name.' + data -- is the register content. + ''' + + if type(regid) == int: + # Get the name of the register. + if regid not in regs: + self.warn(pos, 'unknown register') + return + name = regs[regid][0] + else: + name = regid + + # Multi byte register come LSByte first. + data = reversed(data) + + label = '{}: {}'.format(self.format_command(), name) + + self.decode_mb_data(pos, ann, data, label, True) + + def decode_mb_data(self, pos, ann, data, label, always_hex): + '''Decodes the data bytes 'data' of a multibyte command at position + 'pos'. The decoded data is prefixed with 'label'. If 'always_hex' is + True, all bytes are decoded as hex codes, otherwise only non + printable characters are escaped.''' + + if always_hex: + def escape(b): + return '{:02X}'.format(b) + else: + def escape(b): + c = chr(b) + if not str.isprintable(c): + return '\\x{:02X}'.format(b) + return c + + data = ''.join([escape(b) for b in data]) + text = '{} = "{}"'.format(label, data.strip()) + self.putp(pos, ann, text) + + def finish_command(self, pos): + '''Decodes the remaining data bytes at position 'pos'.''' + + always_hex = self.options['hex_display'] == 'yes' + if self.cmd == 'R_REGISTER': + self.decode_register(pos, self.ann_cmd, + self.dat, self.miso_bytes()) + elif self.cmd == 'W_REGISTER': + self.decode_register(pos, self.ann_cmd, + self.dat, self.mosi_bytes()) + elif self.cmd == 'R_RX_FIFO': + self.decode_mb_data(pos, self.ann_rx, + self.miso_bytes(), 'RX FIFO', always_hex) + elif self.cmd == 'W_TX_FIFO': + self.decode_mb_data(pos, self.ann_tx, + self.mosi_bytes(), 'TX FIFO', always_hex) + elif self.cmd == 'R_ID': + self.decode_mb_data(pos, self.ann_rx, + self.miso_bytes(), 'R ID', always_hex) + elif self.cmd == 'W_ID': + self.decode_mb_data(pos, self.ann_tx, + self.mosi_bytes(), 'W ID', always_hex) + + def decode(self, ss, es, data): + if not self.requirements_met: + return + + ptype, data1, data2 = data + + if ptype == 'TRANSFER': + if self.cmd: + # Check if we got the minimum number of data bytes + # after the command byte. + if len(self.mb) < self.min: + self.warn((ss, ss), 'missing data bytes') + elif self.mb: + self.finish_command((self.mb_s, self.mb_e)) + + self.next() + self.cs_was_released = True + elif ptype == 'CS-CHANGE': + if data1 is None: + if data2 is None: + self.requirements_met = False + raise ChannelError('CS# pin required.') + elif data2 == 1: + self.cs_was_released = True + + if data1 == 0 and data2 == 1: + # Rising edge, the complete command is transmitted, process + # the bytes that were send after the command byte. + if self.cmd: + # Check if we got the minimum number of data bytes + # after the command byte. + if len(self.mb) < self.min: + self.warn((ss, ss), 'missing data bytes') + elif self.mb: + self.finish_command((self.mb_s, self.mb_e)) + + self.next() + self.cs_was_released = True + elif ptype == 'DATA' and self.cs_was_released: + mosi, miso = data1, data2 + pos = (ss, es) + + if miso is None and mosi is None: + self.requirements_met = False + raise ChannelError('Either MISO or MOSI pins required (3 wires SPI).') + + if miso is None: + miso = mosi + if mosi is None: + mosi = miso + + if self.first: + self.first = False + # First byte is always the command. + self.decode_command(pos, mosi) + else: + if not self.cmd or len(self.mb) >= self.max: + self.warn(pos, 'excess byte') + else: + # Collect the bytes after the command byte. + if self.mb_s == -1: + self.mb_s = ss + self.mb_e = es + self.mb.append((mosi, miso)) diff --git a/libsigrokdecode4DSL/decoders/ac97/__init__.py b/libsigrokdecode4DSL/decoders/ac97/__init__.py new file mode 100644 index 00000000..8b96e8aa --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ac97/__init__.py @@ -0,0 +1,36 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2017 Gerhard Sittig +## +## 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, see . +## + +''' +AC'97 (Audio Codec '97) was specifically designed by Intel for audio and +modem I/O functionality in mainstream PC systems. See the specification in +http://download.intel.com/support/motherboards/desktop/sb/ac97_r23.pdf + +AC'97 communicates full duplex data (SDATA_IN, SDATA_OUT), where bits +are clocked by the BIT_CLK and frames are signalled by the SYNC signals. +A low active RESET# line completes the set of signals. + +Frames repeat at a nominal frequency of 48kHz, and consist of 256 bits +each. One 16bit slot contains management information, twelve 20bit slots +follow which carry data for three management and nine audio/modem channels. +Optionally two slots of one frame can get combined for higher resolution +on fewer channels, or double data rate. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/ac97/pd.py b/libsigrokdecode4DSL/decoders/ac97/pd.py new file mode 100644 index 00000000..3f79eefa --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ac97/pd.py @@ -0,0 +1,505 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2017 Gerhard Sittig +## Copyright (C) 2019 DreamSourceLab +## +## 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, see . +## + +# This implementation is incomplete. TODO items: +# - Support the optional RESET# pin, detect cold and warm reset. +# - Split slot values into audio samples of their respective width and +# frequency (either on user provided parameters, or from inspection of +# decoded register access). + +import sigrokdecode as srd + +class ChannelError(Exception): + pass + +class Pins: + (SYNC, BIT_CLK, SDATA_OUT, SDATA_IN, RESET) = range(5) + +class Ann: + ( + BITS_OUT, BITS_IN, + SLOT_OUT_RAW, SLOT_OUT_TAG, SLOT_OUT_ADDR, SLOT_OUT_DATA, + SLOT_OUT_03, SLOT_OUT_04, SLOT_OUT_05, SLOT_OUT_06, + SLOT_OUT_07, SLOT_OUT_08, SLOT_OUT_09, SLOT_OUT_10, + SLOT_OUT_11, SLOT_OUT_IO, + SLOT_IN_RAW, SLOT_IN_TAG, SLOT_IN_ADDR, SLOT_IN_DATA, + SLOT_IN_03, SLOT_IN_04, SLOT_IN_05, SLOT_IN_06, + SLOT_IN_07, SLOT_IN_08, SLOT_IN_09, SLOT_IN_10, + SLOT_IN_11, SLOT_IN_IO, + WARN, ERROR, + ) = range(32) + ( + BIN_FRAME_OUT, + BIN_FRAME_IN, + BIN_SLOT_RAW_OUT, + BIN_SLOT_RAW_IN, + ) = range(4) + +class Decoder(srd.Decoder): + api_version = 3 + id = 'ac97' + name = "AC '97" + longname = "Audio Codec '97" + desc = 'Audio and modem control for PC systems.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Audio', 'PC'] + channels = ( + {'id': 'sync', 'name': 'SYNC', 'desc': 'Frame synchronization'}, + {'id': 'clk', 'name': 'BIT_CLK', 'desc': 'Data bits clock'}, + ) + optional_channels = ( + {'id': 'out', 'name': 'SDATA_OUT', 'desc': 'Data output'}, + {'id': 'in', 'name': 'SDATA_IN', 'desc': 'Data input'}, + {'id': 'rst', 'name': 'RESET#', 'desc': 'Reset line'}, + ) + annotations = ( + ('bit-out', 'Output bits'), + ('bit-in', 'Input bits'), + ('slot-out-raw', 'Output raw value'), + ('slot-out-tag', 'Output TAG'), + ('slot-out-cmd-addr', 'Output command address'), + ('slot-out-cmd-data', 'Output command data'), + ('slot-out-03', 'Output slot 3'), + ('slot-out-04', 'Output slot 4'), + ('slot-out-05', 'Output slot 5'), + ('slot-out-06', 'Output slot 6'), + ('slot-out-07', 'Output slot 7'), + ('slot-out-08', 'Output slot 8'), + ('slot-out-09', 'Output slot 9'), + ('slot-out-10', 'Output slot 10'), + ('slot-out-11', 'Output slot 11'), + ('slot-out-io-ctrl', 'Output I/O control'), + ('slot-in-raw', 'Input raw value'), + ('slot-in-tag', 'Input TAG'), + ('slot-in-sts-addr', 'Input status address'), + ('slot-in-sts-data', 'Input status data'), + ('slot-in-03', 'Input slot 3'), + ('slot-in-04', 'Input slot 4'), + ('slot-in-05', 'Input slot 5'), + ('slot-in-06', 'Input slot 6'), + ('slot-in-07', 'Input slot 7'), + ('slot-in-08', 'Input slot 8'), + ('slot-in-09', 'Input slot 9'), + ('slot-in-10', 'Input slot 10'), + ('slot-in-11', 'Input slot 11'), + ('slot-in-io-sts', 'Input I/O status'), + # TODO: Add more annotation classes: + # TAG: 'ready', 'valid', 'id', 'rsv' + # CMD ADDR: 'r/w', 'addr', 'unused' + # CMD DATA: 'data', 'unused' + # 3-11: 'data', 'unused', 'double data' + ('warning', 'Warning'), + ('error', 'Error'), + ) + annotation_rows = ( + ('bits-out', 'Output bits', (Ann.BITS_OUT,)), + ('slots-out-raw', 'Output numbers', (Ann.SLOT_OUT_RAW,)), + ('slots-out', 'Output slots', ( + Ann.SLOT_OUT_TAG, Ann.SLOT_OUT_ADDR, Ann.SLOT_OUT_DATA, + Ann.SLOT_OUT_03, Ann.SLOT_OUT_04, Ann.SLOT_OUT_05, Ann.SLOT_OUT_06, + Ann.SLOT_OUT_07, Ann.SLOT_OUT_08, Ann.SLOT_OUT_09, Ann.SLOT_OUT_10, + Ann.SLOT_OUT_11, Ann.SLOT_OUT_IO,)), + ('bits-in', 'Input bits', (Ann.BITS_IN,)), + ('slots-in-raw', 'Input numbers', (Ann.SLOT_IN_RAW,)), + ('slots-in', 'Input slots', ( + Ann.SLOT_IN_TAG, Ann.SLOT_IN_ADDR, Ann.SLOT_IN_DATA, + Ann.SLOT_IN_03, Ann.SLOT_IN_04, Ann.SLOT_IN_05, Ann.SLOT_IN_06, + Ann.SLOT_IN_07, Ann.SLOT_IN_08, Ann.SLOT_IN_09, Ann.SLOT_IN_10, + Ann.SLOT_IN_11, Ann.SLOT_IN_IO,)), + ('warnings', 'Warnings', (Ann.WARN,)), + ('errors', 'Errors', (Ann.ERROR,)), + ) + binary = ( + ('frame-out', 'Frame bits, output data'), + ('frame-in', 'Frame bits, input data'), + ('slot-raw-out', 'Raw slot bits, output data'), + ('slot-raw-in', 'Raw slot bits, input data'), + # TODO: Which (other) binary classes to implement? + # - Are binary annotations per audio slot useful? + # - Assume 20bit per slot, in 24bit units? Or assume 16bit + # audio samples? Observe register access and derive width + # of the audio data? Dump channels 3-11 or 1-12? + ) + + def putx(self, ss, es, cls, data): + self.put(ss, es, self.out_ann, [cls, data]) + + def putf(self, frombit, bitcount, cls, data): + ss = self.frame_ss_list[frombit] + es = self.frame_ss_list[frombit + bitcount] + self.putx(ss, es, cls, data) + + def putb(self, frombit, bitcount, cls, data): + ss = self.frame_ss_list[frombit] + es = self.frame_ss_list[frombit + bitcount] + self.put(ss, es, self.out_binary, [cls, data]) + + def __init__(self): + self.out_binary = None + self.out_ann = None + self.reset() + + def reset(self): + self.frame_ss_list = None + self.frame_slot_lens = [0, 16] + [16 + 20 * i for i in range(1, 13)] + self.frame_total_bits = self.frame_slot_lens[-1] + self.handle_slots = { + 0: self.handle_slot_00, + 1: self.handle_slot_01, + 2: self.handle_slot_02, + } + + def start(self): + if not self.out_binary: + self.out_binary = self.register(srd.OUTPUT_BINARY) + if not self.out_ann: + self.out_ann = self.register(srd.OUTPUT_ANN) + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def bits_to_int(self, bits): + # Convert MSB-first bit sequence to integer value. + if not bits: + return 0 + count = len(bits) + value = sum([2 ** (count - 1 - i) for i in range(count) if bits[i]]) + return value + + def bits_to_bin_ann(self, bits): + # Convert MSB-first bit sequence to binary annotation data. + # It's assumed that the number of bits does not (in useful ways) + # fit into an integer, and we need to create an array of bytes + # from the data afterwards, anyway. Hence the separate routine + # and the conversion of eight bits each. + out = [] + count = len(bits) + while count > 0: + count -= 8 + by, bits = bits[:8], bits[8:] + by = self.bits_to_int(by) + out.append(by) + out = bytes(out) + return out + + def int_to_nibble_text(self, value, bitcount): + # Convert number to hex digits for given bit count. + digits = (bitcount + 3) // 4 + text = '{{:0{:d}x}}'.format(digits).format(value) + return text + + def get_bit_field(self, data, size, off, count): + shift = size - off - count + data >>= shift + mask = (1 << count) - 1 + data &= mask + return data + + def flush_frame_bits(self): + # Flush raw frame bits to binary annotation. + anncls = Ann.BIN_FRAME_OUT + data = self.frame_bits_out[:] + count = len(data) + data = self.bits_to_bin_ann(data) + self.putb(0, count, anncls, data) + + anncls = Ann.BIN_FRAME_IN + data = self.frame_bits_in[:] + count = len(data) + data = self.bits_to_bin_ann(data) + self.putb(0, count, anncls, data) + + def start_frame(self, ss): + # Mark the start of a frame. + if self.frame_ss_list: + # Flush bits if we had a frame before the frame which is + # starting here. + self.flush_frame_bits() + self.frame_ss_list = [ss] + self.frame_bits_out = [] + self.frame_bits_in = [] + self.frame_slot_data_out = [] + self.frame_slot_data_in = [] + self.have_slots = {True: None, False: None} + + def handle_slot_dummy(self, slotidx, bitidx, bitcount, is_out, data): + # Handle slot x, default/fallback handler. + # Only process data of slots 1-12 when slot 0 says "valid". + if not self.have_slots[is_out]: + return + if not self.have_slots[is_out][slotidx]: + return + + # Emit a naive annotation with just the data bits that we saw + # for the slot (hex nibbles for density). For audio data this + # can be good enough. Slots with special meaning should not end + # up calling the dummy handler. + text = self.int_to_nibble_text(data, bitcount) + anncls = Ann.SLOT_OUT_TAG if is_out else Ann.SLOT_IN_TAG + self.putf(bitidx, bitcount, anncls + slotidx, [text]) + + # Emit binary output for the data that is contained in slots + # which end up calling the default handler. This transparently + # should translate to "the slots with audio data", as other + # slots which contain management data should have their specific + # handler routines. In the present form, this approach might be + # good enough to get a (header-less) audio stream for typical + # setups where only line-in or line-out are in use. + # + # TODO: Improve this early prototype implementation. For now the + # decoder just exports the upper 16 bits of each audio channel + # that happens to be valid. For an improved implementation, it + # either takes user provided specs or more smarts like observing + # register access (if the capture includes it). + anncls = Ann.BIN_SLOT_RAW_OUT if is_out else Ann.BIN_SLOT_RAW_IN + data_bin = data >> 4 + data_bin &= 0xffff + data_bin = data_bin.to_bytes(2, byteorder = 'big') + self.putb(bitidx, bitcount, anncls, data_bin) + + def handle_slot_00(self, slotidx, bitidx, bitcount, is_out, data): + # Handle slot 0, TAG. + slotpos = self.frame_slot_lens[slotidx] + fieldoff = 0 + anncls = Ann.SLOT_OUT_TAG if is_out else Ann.SLOT_IN_TAG + + fieldlen = 1 + ready = self.get_bit_field(data, bitcount, fieldoff, fieldlen) + text = ['READY: 1', 'READY', 'RDY', 'R'] if ready else ['ready: 0', 'rdy', '-'] + self.putf(slotpos + fieldoff, fieldlen, anncls, text) + fieldoff += fieldlen + + fieldlen = 12 + valid = self.get_bit_field(data, bitcount, fieldoff, fieldlen) + text = ['VALID: {:3x}'.format(valid), '{:3x}'.format(valid)] + self.putf(slotpos + fieldoff, fieldlen, anncls, text) + have_slots = [True] + [False] * 12 + for idx in range(12): + have_slots[idx + 1] = bool(valid & (1 << (11 - idx))) + self.have_slots[is_out] = have_slots + fieldoff += fieldlen + + fieldlen = 1 + rsv = self.get_bit_field(data, bitcount, fieldoff, fieldlen) + if rsv != 0: + text = ['reserved bit error', 'rsv error', 'rsv'] + self.putf(slotpos + fieldoff, fieldlen, Ann.ERROR, text) + fieldoff += fieldlen + + # TODO: Will input slot 0 have a Codec ID, or 3 reserved bits? + fieldlen = 2 + codec = self.get_bit_field(data, bitcount, fieldoff, fieldlen) + text = ['CODEC: {:1x}'.format(codec), '{:1x}'.format(codec)] + self.putf(slotpos + fieldoff, fieldlen, anncls, text) + fieldoff += fieldlen + + def handle_slot_01(self, slotidx, bitidx, bitcount, is_out, data): + # Handle slot 1, command/status address. + slotpos = self.frame_slot_lens[slotidx] + if not self.have_slots[is_out]: + return + if not self.have_slots[is_out][slotidx]: + return + fieldoff = 0 + anncls = Ann.SLOT_OUT_TAG if is_out else Ann.SLOT_IN_TAG + anncls += slotidx + + fieldlen = 1 + if is_out: + is_read = self.get_bit_field(data, bitcount, fieldoff, fieldlen) + text = ['READ', 'RD', 'R'] if is_read else ['WRITE', 'WR', 'W'] + self.putf(slotpos + fieldoff, fieldlen, anncls, text) + # TODO: Check for the "atomic" constraint? Some operations + # involve address _and_ data, which cannot be spread across + # several frames. Slot 0 and 1 _must_ be provided within the + # same frame (the test should occur in the handler for slot + # 2 of course, in slot 1 we don't know what will follow). + else: + rsv = self.get_bit_field(data, bitcount, fieldoff, fieldlen) + if rsv != 0: + text = ['reserved bit error', 'rsv error', 'rsv'] + self.putf(slotpos + fieldoff, fieldlen, Ann.ERROR, text) + fieldoff += fieldlen + + fieldlen = 7 + regaddr = self.get_bit_field(data, bitcount, fieldoff, fieldlen) + # TODO: Present 0-63 or 0-126 as the address of the 16bit register? + text = ['ADDR: {:2x}'.format(regaddr), '{:2x}'.format(regaddr)] + self.putf(slotpos + fieldoff, fieldlen, anncls, text) + if regaddr & 0x01: + text = ['odd register address', 'odd reg addr', 'odd addr', 'odd'] + self.putf(slotpos + fieldoff, fieldlen, Ann.ERROR, text) + fieldoff += fieldlen + + # Strictly speaking there are 10 data request bits and 2 reserved + # bits for input slots, and 12 reserved bits for output slots. We + # test for 10 and 2 bits, to simplify the logic. Only in case of + # non-zero reserved bits for outputs this will result in "a little + # strange" an annotation. This is a cosmetic issue, we don't mind. + fieldlen = 10 + reqdata = self.get_bit_field(data, bitcount, fieldoff, fieldlen) + if is_out and reqdata != 0: + text = ['reserved bit error', 'rsv error', 'rsv'] + self.putf(slotpos + fieldoff, fieldlen, Ann.ERROR, text) + if not is_out: + text = ['REQ: {:3x}'.format(reqdata), '{:3x}'.format(reqdata)] + self.putf(slotpos + fieldoff, fieldlen, anncls, text) + fieldoff += fieldlen + + fieldlen = 2 + rsv = self.get_bit_field(data, bitcount, fieldoff, fieldlen) + if rsv != 0: + text = ['reserved bit error', 'rsv error', 'rsv'] + self.putf(slotpos + fieldoff, fieldlen, Ann.ERROR, text) + fieldoff += fieldlen + + def handle_slot_02(self, slotidx, bitidx, bitcount, is_out, data): + # Handle slot 2, command/status data. + slotpos = self.frame_slot_lens[slotidx] + if not self.have_slots[is_out]: + return + if not self.have_slots[is_out][slotidx]: + return + fieldoff = 0 + anncls = Ann.SLOT_OUT_TAG if is_out else Ann.SLOT_IN_TAG + anncls += slotidx + + fieldlen = 16 + rwdata = self.get_bit_field(data, bitcount, fieldoff, fieldlen) + # TODO: Check for zero output data when the operation is a read. + # TODO: Check for the "atomic" constraint. + text = ['DATA: {:4x}'.format(rwdata), '{:4x}'.format(rwdata)] + self.putf(slotpos + fieldoff, fieldlen, anncls, text) + fieldoff += fieldlen + + fieldlen = 4 + rsv = self.get_bit_field(data, bitcount, fieldoff, fieldlen) + if rsv != 0: + text = ['reserved bits error', 'rsv error', 'rsv'] + self.putf(slotpos + fieldoff, fieldlen, Ann.ERROR, text) + fieldoff += fieldlen + + # TODO: Implement other slots. + # - 1: cmd/status addr (check status vs command) + # - 2: cmd/status data (check status vs command) + # - 3-11: audio out/in + # - 12: io control/status (modem GPIO(?)) + + def handle_slot(self, slotidx, data_out, data_in): + # Process a received slot of a frame. + func = self.handle_slots.get(slotidx, self.handle_slot_dummy) + bitidx = self.frame_slot_lens[slotidx] + bitcount = self.frame_slot_lens[slotidx + 1] - bitidx + if data_out is not None: + func(slotidx, bitidx, bitcount, True, data_out) + if data_in is not None: + func(slotidx, bitidx, bitcount, False, data_in) + + def handle_bits(self, ss, es, bit_out, bit_in): + # Process a received pair of bits. + # Emit the bits' annotations. Only interpret the data when we + # are in a frame (have seen the start of the frame, and don't + # exceed the expected number of bits in a frame). + if bit_out is not None: + self.putx(ss, es, Ann.BITS_OUT, ['{:d}'.format(bit_out)]) + if bit_in is not None: + self.putx(ss, es, Ann.BITS_IN, ['{:d}'.format(bit_in)]) + if self.frame_ss_list is None: + return + self.frame_ss_list.append(es) + have_len = len(self.frame_ss_list) - 1 + if have_len > self.frame_total_bits: + return + + # Accumulate the bits within the frame, until one slot of the + # frame has become available. + slot_idx = 0 + if bit_out is not None: + self.frame_bits_out.append(bit_out) + slot_idx = len(self.frame_slot_data_out) + if bit_in is not None: + self.frame_bits_in.append(bit_in) + slot_idx = len(self.frame_slot_data_in) + want_len = self.frame_slot_lens[slot_idx + 1] + if have_len != want_len: + return + prev_len = self.frame_slot_lens[slot_idx] + + # Convert bits to integer values. This shall simplify extraction + # of bit fields in multiple other locations. + slot_data_out = None + if bit_out is not None: + slot_bits = self.frame_bits_out[prev_len:] + slot_data = self.bits_to_int(slot_bits) + self.frame_slot_data_out.append(slot_data) + slot_data_out = slot_data + slot_data_in = None + if bit_in is not None: + slot_bits = self.frame_bits_in[prev_len:] + slot_data = self.bits_to_int(slot_bits) + self.frame_slot_data_in.append(slot_data) + slot_data_in = slot_data + + # Emit simple annotations for the integer values, until upper + # layer decode stages will be implemented. + slot_len = have_len - prev_len + slot_ss = self.frame_ss_list[prev_len] + slot_es = self.frame_ss_list[have_len] + if slot_data_out is not None: + slot_text = self.int_to_nibble_text(slot_data_out, slot_len) + self.putx(slot_ss, slot_es, Ann.SLOT_OUT_RAW, [slot_text]) + if slot_data_in is not None: + slot_text = self.int_to_nibble_text(slot_data_in, slot_len) + self.putx(slot_ss, slot_es, Ann.SLOT_IN_RAW, [slot_text]) + + self.handle_slot(slot_idx, slot_data_out, slot_data_in) + + def decode(self): + have_sdo = self.has_channel(Pins.SDATA_OUT) + have_sdi = self.has_channel(Pins.SDATA_IN) + if not have_sdo and not have_sdi: + raise ChannelError('Either SDATA_OUT or SDATA_IN (or both) are required.') + have_reset = self.has_channel(Pins.RESET) + + # Data is sampled at falling CLK edges. Annotations need to span + # the period between rising edges. SYNC rises one cycle _before_ + # the start of a frame. Grab the earliest SYNC sample we can get + # and advance to the start of a bit time. Then keep getting the + # samples and the end of all subsequent bit times. + prev_sync = [None, None, None] + (sync, bit_clk, sdata_out, sdata_in, reset) = self.wait({Pins.BIT_CLK: 'e'}) + if bit_clk == 0: + prev_sync[-1] = sync + (sync, bit_clk, sdata_out, sdata_in, reset) = self.wait({Pins.BIT_CLK: 'r'}) + bit_ss = self.samplenum + while True: + (sync, bit_clk, sdata_out, sdata_in, reset) = self.wait({Pins.BIT_CLK: 'f'}) + prev_sync.pop(0) + prev_sync.append(sync) + self.wait({Pins.BIT_CLK: 'r'}) + if prev_sync[0] == 0 and prev_sync[1] == 1: + self.start_frame(bit_ss) + self.handle_bits(bit_ss, self.samplenum, + sdata_out if have_sdo else None, + sdata_in if have_sdi else None) + bit_ss = self.samplenum diff --git a/libsigrokdecode4DSL/decoders/ad5626/__init__.py b/libsigrokdecode4DSL/decoders/ad5626/__init__.py new file mode 100644 index 00000000..5f67799b --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ad5626/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 Analog Devices Inc. +## +## 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 . +## + +''' +This decoder stacks on top of the 'spi' PD and decodes the +Analog Devices AD5626 protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/ad5626/pd.py b/libsigrokdecode4DSL/decoders/ad5626/pd.py new file mode 100644 index 00000000..cffee83d --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ad5626/pd.py @@ -0,0 +1,62 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 Analog Devices Inc. +## +## 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 . +## + +import sigrokdecode as srd + +class Decoder(srd.Decoder): + api_version = 3 + id = 'ad5626' + name = 'AD5626' + longname = 'Analog Devices AD5626' + desc = 'Analog Devices AD5626 12-bit nanoDAC.' + license = 'gplv2+' + inputs = ['spi'] + outputs = [] + tags = ['IC', 'Analog/digital'] + annotations = ( + ('voltage', 'Voltage'), + ) + + def __init__(self,): + self.reset() + + def reset(self): + self.data = 0 + self.ss = 0 + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def decode(self, ss, es, data): + ptype = data[0] + + if ptype == 'CS-CHANGE': + cs_old, cs_new = data[1:] + if cs_old is not None and cs_old == 0 and cs_new == 1: + self.data >>= 1 + self.data /= 1000 + self.put(self.ss, es, self.out_ann, [0, ['%.3fV' % self.data]]) + self.data = 0 + elif cs_old is not None and cs_old == 1 and cs_new == 0: + self.ss = ss + elif ptype == 'BITS': + mosi = data[1] + for bit in reversed(mosi): + self.data = self.data | bit[0] + self.data <<= 1 diff --git a/libsigrokdecode4DSL/decoders/ad79x0/__init__.py b/libsigrokdecode4DSL/decoders/ad79x0/__init__.py new file mode 100644 index 00000000..0e81f17b --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ad79x0/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 Analog Devices Inc. +## +## 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 . +## + +''' +This decoder stacks on top of the 'spi' PD and decodes the +Analog Devices AD7910/AD7920 protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/ad79x0/pd.py b/libsigrokdecode4DSL/decoders/ad79x0/pd.py new file mode 100644 index 00000000..3d7ab731 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ad79x0/pd.py @@ -0,0 +1,137 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 Analog Devices Inc. +## +## 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 . +## + +import sigrokdecode as srd + +modes = { + 0: ['Normal Mode', 'Normal', 'Norm', 'N'], + 1: ['Power Down Mode', 'Power Down', 'PD'], + 2: ['Power Up Mode', 'Power Up', 'PU'], +} + +input_voltage_format = ['%.6fV', '%.2fV'] + +validation = { + 'invalid': ['Invalid data', 'Invalid', 'N/A'], + 'incomplete': ['Incomplete conversion', 'Incomplete', 'I'], + 'complete': ['Complete conversion', 'Complete', 'C'], +} + +class Decoder(srd.Decoder): + api_version = 3 + id = 'ad79x0' + name = 'AD79x0' + longname = 'Analog Devices AD79x0' + desc = 'Analog Devices AD7910/AD7920 12-bit ADC.' + license = 'gplv2+' + inputs = ['spi'] + outputs = [] + tags = ['IC', 'Analog/digital'] + annotations = ( + ('mode', 'Mode'), + ('voltage', 'Voltage'), + ('validation', 'Validation'), + ) + annotation_rows = ( + ('modes', 'Modes', (0,)), + ('voltages', 'Voltages', (1,)), + ('data_validation', 'Data validation', (2,)), + ) + options = ( + {'id': 'vref', 'desc': 'Reference voltage (V)', 'default': 1.5}, + ) + + def __init__(self,): + self.reset() + + def reset(self): + self.samplerate = 0 + self.samples_bit = -1 + self.ss = -1 + self.start_sample = 0 + self.previous_state = 0 + self.data = 0 + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def put_validation(self, pos, msg): + self.put(pos[0], pos[1], self.out_ann, [2, validation[msg]]) + + def put_data(self, pos, input_voltage): + ann = [] + for format in input_voltage_format: + ann.append(format % input_voltage) + self.put(pos[0], pos[1], self.out_ann, [1, ann]) + + def put_mode(self, pos, msg): + self.put(pos[0], pos[1], self.out_ann, [0, modes[msg]]) + + def decode(self, ss, es, data): + ptype = data[0] + + if ptype == 'CS-CHANGE': + cs_old, cs_new = data[1:] + if cs_old is not None and cs_old == 0 and cs_new == 1: + if self.samples_bit == -1: + return + self.data >>= 1 + nb_bits = (ss - self.ss) // self.samples_bit + if nb_bits >= 10: + if self.data == 0xFFF: + self.put_mode([self.start_sample, es], 2) + self.previous_state = 0 + self.put_validation([self.start_sample, es], 'invalid') + else: + self.put_mode([self.start_sample, es], 0) + if nb_bits == 16: + self.put_validation([self.start_sample, es], 'complete') + elif nb_bits < 16: + self.put_validation([self.start_sample, es], 'incomplete') + vin = (self.data / ((2**12) - 1)) * self.options['vref'] + self.put_data([self.start_sample, es], vin) + elif nb_bits < 10: + self.put_mode([self.start_sample, es], 1) + self.previous_state = 1 + self.put_validation([self.start_sample, es], 'invalid') + + self.ss = -1 + self.samples_bit = -1 + self.data = 0 + elif cs_old is not None and cs_old == 1 and cs_new == 0: + self.start_sample = ss + self.samples_bit = -1 + + elif ptype == 'BITS': + if data[2] is None: + return + miso = data[2] + if self.samples_bit == -1: + self.samples_bit = miso[0][2] - miso[0][1] + + if self.ss == -1: + self.ss = ss + + for bit in reversed(miso): + self.data = self.data | bit[0] + self.data <<= 1 diff --git a/libsigrokdecode4DSL/decoders/ade77xx/__init__.py b/libsigrokdecode4DSL/decoders/ade77xx/__init__.py new file mode 100644 index 00000000..cbe8689d --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ade77xx/__init__.py @@ -0,0 +1,32 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2017 Karl Palsson +## +## 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 +## + +''' +This decoder stacks on top of the 'spi' PD and decodes Analog Devices +ADE77xx command/responses. + +The ADE77xx is a "Poly Phase Multifunction Energy Metering IC with Per Phase +Information". + +This PD has been tested with an ADE7758 so far, support for other devices +from the ADE77xx series can be added in the future. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/ade77xx/lists.py b/libsigrokdecode4DSL/decoders/ade77xx/lists.py new file mode 100644 index 00000000..f556389d --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ade77xx/lists.py @@ -0,0 +1,102 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2017 Karl Palsson +## +## Permission is hereby granted, free of charge, to any person obtaining a copy +## of this software and associated documentation files (the "Software"), to deal +## in the Software without restriction, including without limitation the rights +## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +## copies of the Software, and to permit persons to whom the Software is +## furnished to do so, subject to the following conditions: +## +## The above copyright notice and this permission notice shall be included in all +## copies or substantial portions of the Software. +## +## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +## SOFTWARE. + +from collections import OrderedDict + +# Generated from datasheet rev E, using tabula. +regs = OrderedDict([ + (0x1, ('AWATTHR', 'Watt-Hour Accumulation Register for Phase A. Active power is accumulated over time in this read-only register. The AWATTHR register can hold a maximum of 0.52 seconds of active energy information with full-scale analog inputs before it overflows (see the Active Energy Calculation section). Bit 0 and Bit 1 of the COMPMODE register determine how the active energy is processed from the six analog inputs.', 'R', 16, 'S', 0x0)), + (0x2, ('BWATTHR', 'Watt-Hour Accumulation Register for Phase B.', 'R', 16, 'S', 0x0)), + (0x3, ('CWATTHR', 'Watt-Hour Accumulation Register for Phase C.', 'R', 16, 'S', 0x0)), + (0x4, ('AVARHR', 'VAR-Hour Accumulation Register for Phase A. Reactive power is accumulated over time in this read-only register. The AVARHR register can hold a maximum of 0.52 seconds of reactive energy information with full-scale analog inputs before it overflows (see the Reactive Energy Calculation section). Bit 0 and Bit 1 of the COMPMODE register determine how the reactive energy is processed from the six analog inputs.', 'R', 16, 'S', 0x0)), + (0x5, ('BVARHR', 'VAR-Hour Accumulation Register for Phase B.', 'R', 16, 'S', 0x0)), + (0x6, ('CVARHR', 'VAR-Hour Accumulation Register for Phase C.', 'R', 16, 'S', 0x0)), + (0x7, ('AVAHR', 'VA-Hour Accumulation Register for Phase A. Apparent power is accumulated over time in this read-only register. The AVAHR register can hold a maximum of 1.15 seconds of apparent energy information with full-scale analog inputs before it overflows (see the Apparent Energy Calculation section). Bit 0 and Bit 1 of the COMPMODE register determine how the apparent energy is processed from the six analog inputs.', 'R', 16, 'S', 0x0)), + (0x8, ('BVAHR', 'VA-Hour Accumulation Register for Phase B.', 'R', 16, 'S', 0x0)), + (0x9, ('CVAHR', 'VA-Hour Accumulation Register for Phase C.', 'R', 16, 'S', 0x0)), + (0xa, ('AIRMS', 'Phase A Current Channel RMS Register. The register contains the rms component of the Phase A input of the current channel. The source is selected by data bits in the mode register.', 'R', 24, 'S', 0x0)), + (0xb, ('BIRMS', 'Phase B Current Channel RMS Register.', 'R', 24, 'S', 0x0)), + (0xc, ('CIRMS', 'Phase C Current Channel RMS Register.', 'R', 24, 'S', 0x0)), + (0xd, ('AVRMS', 'Phase A Voltage Channel RMS Register.', 'R', 24, 'S', 0x0)), + (0xe, ('BVRMS', 'Phase B Voltage Channel RMS Register.', 'R', 24, 'S', 0x0)), + (0xf, ('CVRMS', 'Phase C Voltage Channel RMS Register.', 'R', 24, 'S', 0x0)), + (0x10, ('FREQ', 'Frequency of the Line Input Estimated by the Zero-Crossing Processing. It can also display the period of the line input. Bit 7 of the LCYCMODE register determines if the reading is frequency or period. Default is frequency. Data Bit 0 and Bit 1 of the MMODE register determine the voltage channel used for the frequency or period calculation.', 'R', 12, 'U', 0x0)), + (0x11, ('TEMP', 'Temperature Register. This register contains the result of the latest temperature conversion. Refer to the Temperature Measurement section for details on how to interpret the content of this register.', 'R', 8, 'S', 0x0)), + (0x12, ('WFORM', 'Waveform Register. This register contains the digitized waveform of one of the six analog inputs or the digitized power waveform. The source is selected by Data Bit 0 to Bit 4 in the WAVMODE register.', 'R', 24, 'S', 0x0)), + (0x13, ('OPMODE', 'Operational Mode Register. This register defines the general configuration of the ADE7758 (see Table 18).', 'R/W', 8, 'U', 0x4)), + (0x14, ('MMODE', 'Measurement Mode Register. This register defines the channel used for period and peak detection measurements (see Table 19).', 'R/W', 8, 'U', 0xfc)), + (0x15, ('WAVMODE', 'Waveform Mode Register. This register defines the channel and sampling frequency used in the waveform sampling mode (see Table 20).', 'R/W', 8, 'U', 0x0)), + (0x16, ('COMPMODE', 'Computation Mode Register. This register configures the formula applied for the energy and line active energy measurements (see Table 22).', 'R/W', 8, 'U', 0x1c)), + (0x17, ('LCYCMODE', 'Line Cycle Mode Register. This register configures the line cycle accumulation mode for WATT-HR', 'R/W', 8, 'U', 0x78)), + (0x18, ('Mask', 'IRQ Mask Register. It determines if an interrupt event generates an active-low output at the IRQ pin (see the Interrupts section).', 'R/W', 24, 'U', 0x0)), + (0x19, ('Status', 'IRQ Status Register. This register contains information regarding the source of the ADE7758 interrupts (see the Interrupts section).', 'R', 24, 'U', 0x0)), + (0x1a, ('RSTATUS', 'IRQ Reset Status Register. Same as the STATUS register, except that its contents are reset to 0 (all flags cleared) after a read operation.', 'R', 24, 'U', 0x0)), + (0x1b, ('ZXTOUT', 'Zero-Cross Timeout Register. If no zero crossing is detected within the time period specified by this register', 'R/W', 16, 'U', 0xffff)), + (0x1c, ('LINECYC', 'Line Cycle Register. The content of this register sets the number of half-line cycles that the active', 'R/W', 16, 'U', 0xffff)), + (0x1d, ('SAGCYC', 'SAG Line Cycle Register. This register specifies the number of consecutive half-line cycles where voltage channel input may fall below a threshold level. This register is common to the three line voltage SAG detection. The detection threshold is specified by the SAGLVL register (see the Line Voltage SAG Detection section).', 'R/W', 8, 'U', 0xff)), + (0x1e, ('SAGLVL', 'SAG Voltage Level. This register specifies the detection threshold for the SAG event. This register is common to all three phases’ line voltage SAG detections. See the description of the SAGCYC register for details.', 'R/W', 8, 'U', 0x0)), + (0x1f, ('VPINTLVL', 'Voltage Peak Level Interrupt Threshold Register. This register sets the level of the voltage peak detection. Bit 5 to Bit 7 of the MMODE register determine which phases are to be monitored. If the selected voltage phase exceeds this level', 'R/W', 8, 'U', 0xff)), + (0x20, ('IPINTLVL', 'Current Peak Level Interrupt Threshold Register. This register sets the level of the current peak detection. Bit 5 to Bit 7 of the MMODE register determine which phases are to be monitored. If the selected current phase exceeds this level', 'R/W', 8, 'U', 0xff)), + (0x21, ('VPEAK', 'Voltage Peak Register. This register contains the value of the peak voltage waveform that has occurred within a fixed number of half-line cycles. The number of half-line cycles is set by the LINECYC register.', 'R', 8, 'U', 0x0)), + (0x22, ('IPEAK', 'Current Peak Register. This register holds the value of the peak current waveform that has occurred within a fixed number of half-line cycles. The number of half-line cycles is set by the LINECYC register.', 'R', 8, 'U', 0x0)), + (0x23, ('Gain', 'PGA Gain Register. This register is used to adjust the gain selection for the PGA in the current and voltage channels (see the Analog Inputs section).', 'R/W', 8, 'U', 0x0)), + (0x24, ('AVRMSGAIN', 'Phase A VRMS Gain Register. The range of the voltage rms calculation can be adjusted by writing to this register. It has an adjustment range of ±50% with a resolution of 0.0244%/LSB.', 'R/W', 12, 'S', 0x0)), + (0x25, ('BVRMSGAIN', 'Phase B VRMS Gain Register.', 'R/W', 12, 'S', 0x0)), + (0x26, ('CVRMSGAIN', 'Phase C VRMS Gain Register.', 'R/W', 12, 'S', 0x0)), + (0x27, ('AIGAIN', 'Phase A Current Gain Register. This register is not recommended to be used and it should be kept at 0', 'R/W', 12, 'S', 0x0)), + (0x28, ('BIGAIN', 'Phase B Current Gain Register. This register is not recommended to be used and it should be kept at 0', 'R/W', 12, 'S', 0x0)), + (0x29, ('CIGAIN', 'Phase C Current Gain Register. This register is not recommended to be used and it should be kept at 0', 'R/W', 12, 'S', 0x0)), + (0x2a, ('AWG', 'Phase A Watt Gain Register. The range of the watt calculation can be adjusted by writing to this register. It has an adjustment range of ±50% with a resolution of 0.0244%/LSB.', 'R/W', 12, 'S', 0x0)), + (0x2b, ('BWG', 'Phase B Watt Gain Register.', 'R/W', 12, 'S', 0x0)), + (0x2c, ('CWG', 'Phase C Watt Gain Register.', 'R/W', 12, 'S', 0x0)), + (0x2d, ('AVARG', 'Phase A VAR Gain Register. The range of the VAR calculation can be adjusted by writing to this register. It has an adjustment range of ±50% with a resolution of 0.0244%/LSB.', 'R/W', 12, 'S', 0x0)), + (0x2e, ('BVARG', 'Phase B VAR Gain Register.', 'R/W', 12, 'S', 0x0)), + (0x2f, ('CVARG', 'Phase C VAR Gain Register.', 'R/W', 12, 'S', 0x0)), + (0x30, ('AVAG', 'Phase A VA Gain Register. The range of the VA calculation can be adjusted by writing to this register. It has an adjustment range of ±50% with a resolution of 0.0244%/LSB.', 'R/W', 12, 'S', 0x0)), + (0x31, ('BVAG', 'Phase B VA Gain Register.', 'R/W', 12, 'S', 0x0)), + (0x32, ('CVAG', 'Phase C VA Gain Register.', 'R/W', 12, 'S', 0x0)), + (0x33, ('AVRMSOS', 'Phase A Voltage RMS Offset Correction Register.', 'R/W', 12, 'S', 0x0)), + (0x34, ('BVRMSOS', 'Phase B Voltage RMS Offset Correction Register.', 'R/W', 12, 'S', 0x0)), + (0x35, ('CVRMSOS', 'Phase C Voltage RMS Offset Correction Register.', 'R/W', 12, 'S', 0x0)), + (0x36, ('AIRMSOS', 'Phase A Current RMS Offset Correction Register.', 'R/W', 12, 'S', 0x0)), + (0x37, ('BIRMSOS', 'Phase B Current RMS Offset Correction Register.', 'R/W', 12, 'S', 0x0)), + (0x38, ('CIRMSOS', 'Phase C Current RMS Offset Correction Register.', 'R/W', 12, 'S', 0x0)), + (0x39, ('AWATTOS', 'Phase A Watt Offset Calibration Register.', 'R/W', 12, 'S', 0x0)), + (0x3a, ('BWATTOS', 'Phase B Watt Offset Calibration Register.', 'R/W', 12, 'S', 0x0)), + (0x3b, ('CWATTOS', 'Phase C Watt Offset Calibration Register.', 'R/W', 12, 'S', 0x0)), + (0x3c, ('AVAROS', 'Phase A VAR Offset Calibration Register.', 'R/W', 12, 'S', 0x0)), + (0x3d, ('BVAROS', 'Phase B VAR Offset Calibration Register.', 'R/W', 12, 'S', 0x0)), + (0x3e, ('CVAROS', 'Phase C VAR Offset Calibration Register.', 'R/W', 12, 'S', 0x0)), + (0x3f, ('APHCAL', 'Phase A Phase Calibration Register. The phase relationship between the current and voltage channel can be adjusted by writing to this signed 7-bit register (see the Phase Compensation section).', 'R/W', 7, 'S', 0x0)), + (0x40, ('BPHCAL', 'Phase B Phase Calibration Register.', 'R/W', 7, 'S', 0x0)), + (0x41, ('CPHCAL', 'Phase C Phase Calibration Register.', 'R/W', 7, 'S', 0x0)), + (0x42, ('WDIV', 'Active Energy Register Divider.', 'R/W', 8, 'U', 0x0)), + (0x43, ('VARDIV', 'Reactive Energy Register Divider.', 'R/W', 8, 'U', 0x0)), + (0x44, ('VADIV', 'Apparent Energy Register Divider.', 'R/W', 8, 'U', 0x0)), + (0x45, ('APCFNUM', 'Active Power CF Scaling Numerator Register. The content of this register is used in the numerator of the APCF output scaling calculation. Bits [15:13] indicate reverse polarity active power measurement for Phase A', 'R/W', 16, 'U', 0x0)), + (0x46, ('APCFDEN', 'Active Power CF Scaling Denominator Register. The content of this register is used in the denominator of the APCF output scaling.', 'R/W', 12, 'U', 0x3f)), + (0x47, ('VARCFNUM', 'Reactive Power CF Scaling Numerator Register. The content of this register is used in the numerator of the VARCF output scaling. Bits [15:13] indicate reverse polarity reactive power measurement for Phase A', 'R/W', 16, 'U', 0x0)), + (0x48, ('VARCFDEN', 'Reactive Power CF Scaling Denominator Register. The content of this register is used in the denominator of the VARCF output scaling.', 'R/W', 12, 'U', 0x3f)), + (0x7e, ('CHKSUM', 'Checksum Register. The content of this register represents the sum of all the ones in the last register read from the SPI port.', 'R', 8, 'U', None)), + (0x7f, ('Version', 'Version of the Die.', 'R', 8, 'U', None)), +]) diff --git a/libsigrokdecode4DSL/decoders/ade77xx/pd.py b/libsigrokdecode4DSL/decoders/ade77xx/pd.py new file mode 100644 index 00000000..5a24a25e --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ade77xx/pd.py @@ -0,0 +1,131 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2017 Karl Palsson +## +## Permission is hereby granted, free of charge, to any person obtaining a copy +## of this software and associated documentation files (the "Software"), to deal +## in the Software without restriction, including without limitation the rights +## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +## copies of the Software, and to permit persons to whom the Software is +## furnished to do so, subject to the following conditions: +## +## The above copyright notice and this permission notice shall be included in all +## copies or substantial portions of the Software. +## +## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +## SOFTWARE. + +import math +import sigrokdecode as srd +from .lists import * + +class Decoder(srd.Decoder): + api_version = 3 + id = 'ade77xx' + name = 'ADE77xx' + longname = 'Analog Devices ADE77xx' + desc = 'Poly phase multifunction energy metering IC protocol.' + license = 'mit' + inputs = ['spi'] + outputs = [] + tags = ['Analog/digital', 'IC', 'Sensor'] + annotations = ( + ('read', 'Register read commands'), + ('write', 'Register write commands'), + ('warning', 'Warnings'), + ) + annotation_rows = ( + ('read', 'Read', (0,)), + ('write', 'Write', (1,)), + ('warnings', 'Warnings', (2,)), + ) + + def reset_data(self): + self.expected = 0 + self.mosi_bytes, self.miso_bytes = [], [] + + def __init__(self): + self.reset() + + def reset(self): + self.ss_cmd, self.es_cmd = 0, 0 + self.reset_data() + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + self.put(self.ss_cmd, self.es_cmd, self.out_ann, data) + + def put_warn(self, pos, msg): + self.put(pos[0], pos[1], self.out_ann, [2, [msg]]) + + def decode(self, ss, es, data): + ptype = data[0] + if ptype == 'CS-CHANGE': + # Bear in mind, that CS is optional according to the datasheet. + # If we transition high mid-stream, toss out our data and restart. + cs_old, cs_new = data[1:] + if cs_old is not None and cs_old == 0 and cs_new == 1: + if len(self.mosi_bytes) > 0 and len(self.mosi_bytes[1:]) < self.expected: + # Mark short read/write for reg at least! + self.es_cmd = es + write, reg = self.cmd & 0x80, self.cmd & 0x7f + rblob = regs.get(reg) + idx = 1 if write else 0 + self.putx([idx, ['%s: %s' % (rblob[0], "SHORT")]]) + self.put_warn([self.ss_cmd, es], "Short transfer!") + self.reset_data() + return + + # Don't care about anything else. + if ptype != 'DATA': + return + mosi, miso = data[1:] + + if len(self.mosi_bytes) == 0: + self.ss_cmd = ss + self.mosi_bytes.append(mosi) + self.miso_bytes.append(miso) + + # A transfer is 2-4 bytes, (command + 1..3 byte reg). + if len(self.mosi_bytes) < 2: + return + + self.cmd = self.mosi_bytes[0] + write, reg = self.cmd & 0x80, self.cmd & 0x7f + rblob = regs.get(reg) + if not rblob: + # If you don't have CS, this will _destroy_ comms! + self.put_warn([self.ss_cmd, es], 'Unknown register!') + return + + self.expected = math.ceil(rblob[3] / 8) + if len(self.mosi_bytes[1:]) != self.expected: + return + valo, vali = None, None + self.es_cmd = es + if self.expected == 3: + valo = self.mosi_bytes[1] << 16 | self.mosi_bytes[2] << 8 | \ + self.mosi_bytes[3] + vali = self.miso_bytes[1] << 16 | self.miso_bytes[2] << 8 | \ + self.miso_bytes[3] + elif self.expected == 2: + valo = self.mosi_bytes[1] << 8 | self.mosi_bytes[2] + vali = self.miso_bytes[1] << 8 | self.miso_bytes[2] + elif self.expected == 1: + valo = self.mosi_bytes[1] + vali = self.miso_bytes[1] + + if write: + self.putx([1, ['%s: %#x' % (rblob[0], valo)]]) + else: + self.putx([0, ['%s: %#x' % (rblob[0], vali)]]) + + self.reset_data() diff --git a/libsigrokdecode4DSL/decoders/adf435x/__init__.py b/libsigrokdecode4DSL/decoders/adf435x/__init__.py new file mode 100644 index 00000000..1c89e2dc --- /dev/null +++ b/libsigrokdecode4DSL/decoders/adf435x/__init__.py @@ -0,0 +1,29 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2017 Joel Holdsworth +## +## 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, see . +## + +''' +This decoder stacks on top of the 'spi' PD and decodes the protocol spoken +by the Analog Devices ADF4350 and ADF4351 RF synthesizer chips. + +Details: +http://www.analog.com/media/en/technical-documentation/data-sheets/ADF4350.pdf +http://www.analog.com/media/en/technical-documentation/data-sheets/ADF4351.pdf +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/adf435x/pd.py b/libsigrokdecode4DSL/decoders/adf435x/pd.py new file mode 100644 index 00000000..f6c6e6e0 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/adf435x/pd.py @@ -0,0 +1,144 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2017 Joel Holdsworth +## +## 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 . +## + +import sigrokdecode as srd + +def disabled_enabled(v): + return ['Disabled', 'Enabled'][v] + +def output_power(v): + return '%+ddBm' % [-4, -1, 2, 5][v] + +regs = { +# reg: name offset width parser + 0: [ + ('FRAC', 3, 12, None), + ('INT', 15, 16, lambda v: 'Not Allowed' if v < 32 else v) + ], + 1: [ + ('MOD', 3, 12, None), + ('Phase', 15, 12, None), + ('Prescalar', 27, 1, lambda v: ['4/5', '8/9'][v]), + ('Phase Adjust', 28, 1, lambda v: ['Off', 'On'][v]), + ], + 2: [ + ('Counter Reset', 3, 1, disabled_enabled), + ('Charge Pump Three-State', 4, 1, disabled_enabled), + ('Power-Down', 5, 1, disabled_enabled), + ('PD Polarity', 6, 1, lambda v: ['Negative', 'Positive'][v]), + ('LDP', 7, 1, lambda v: ['10ns', '6ns'][v]), + ('LDF', 8, 1, lambda v: ['FRAC-N', 'INT-N'][v]), + ('Charge Pump Current Setting', 9, 4, lambda v: '%0.2fmA @ 5.1kΩ' % + [0.31, 0.63, 0.94, 1.25, 1.56, 1.88, 2.19, 2.50, + 2.81, 3.13, 3.44, 3.75, 4.06, 4.38, 4.69, 5.00][v]), + ('Double Buffer', 13, 1, disabled_enabled), + ('R Counter', 14, 10, None), + ('RDIV2', 24, 1, disabled_enabled), + ('Reference Doubler', 25, 1, disabled_enabled), + ('MUXOUT', 26, 3, lambda v: + ['Three-State Output', 'DVdd', 'DGND', 'R Counter Output', 'N Divider Output', + 'Analog Lock Detect', 'Digital Lock Detect', 'Reserved'][v]), + ('Low Noise and Low Spur Modes', 29, 2, lambda v: + ['Low Noise Mode', 'Reserved', 'Reserved', 'Low Spur Mode'][v]) + ], + 3: [ + ('Clock Divider', 3, 12, None), + ('Clock Divider Mode', 15, 2, lambda v: + ['Clock Divider Off', 'Fast Lock Enable', 'Resync Enable', 'Reserved'][v]), + ('CSR Enable', 18, 1, disabled_enabled), + ('Charge Cancellation', 21, 1, disabled_enabled), + ('ABP', 22, 1, lambda v: ['6ns (FRAC-N)', '3ns (INT-N)'][v]), + ('Band Select Clock Mode', 23, 1, lambda v: ['Low', 'High'][v]) + ], + 4: [ + ('Output Power', 3, 2, output_power), + ('Output Enable', 5, 1, disabled_enabled), + ('AUX Output Power', 6, 2, output_power), + ('AUX Output Select', 8, 1, lambda v: ['Divided Output', 'Fundamental'][v]), + ('AUX Output Enable', 9, 1, disabled_enabled), + ('MTLD', 10, 1, disabled_enabled), + ('VCO Power-Down', 11, 1, lambda v: + 'VCO Powered ' + ('Down' if v == 1 else 'Up')), + ('Band Select Clock Divider', 12, 8, None), + ('RF Divider Select', 20, 3, lambda v: '÷' + str(2**v)), + ('Feedback Select', 23, 1, lambda v: ['Divided', 'Fundamental'][v]), + ], + 5: [ + ('LD Pin Mode', 22, 2, lambda v: + ['Low', 'Digital Lock Detect', 'Low', 'High'][v]) + ] +} + +ANN_REG = 0 + +class Decoder(srd.Decoder): + api_version = 3 + id = 'adf435x' + name = 'ADF435x' + longname = 'Analog Devices ADF4350/1' + desc = 'Wideband synthesizer with integrated VCO.' + license = 'gplv3+' + inputs = ['spi'] + outputs = [] + tags = ['Clock/timing', 'IC', 'Wireless/RF'] + annotations = ( + # Sent from the host to the chip. + ('register', 'Register written to the device'), + ) + annotation_rows = ( + ('registers', 'Register writes', (ANN_REG,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.bits = [] + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def decode_bits(self, offset, width): + return (sum([(1 << i) if self.bits[offset + i][0] else 0 for i in range(width)]), + (self.bits[offset + width - 1][1], self.bits[offset][2])) + + def decode_field(self, name, offset, width, parser): + val, pos = self.decode_bits(offset, width) + self.put(pos[0], pos[1], self.out_ann, [ANN_REG, + ['%s: %s' % (name, parser(val) if parser else str(val))]]) + return val + + def decode(self, ss, es, data): + + ptype, data1, data2 = data + + if ptype == 'CS-CHANGE': + if data1 == 1: + if len(self.bits) == 32: + reg_value, reg_pos = self.decode_bits(0, 3) + self.put(reg_pos[0], reg_pos[1], self.out_ann, [ANN_REG, + ['Register: %d' % reg_value, 'Reg: %d' % reg_value, + '[%d]' % reg_value]]) + if reg_value < len(regs): + field_descs = regs[reg_value] + for field_desc in field_descs: + field = self.decode_field(*field_desc) + self.bits = [] + if ptype == 'BITS': + self.bits = data1 + self.bits diff --git a/libsigrokdecode4DSL/decoders/adns5020/__init__.py b/libsigrokdecode4DSL/decoders/adns5020/__init__.py new file mode 100644 index 00000000..e519da44 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/adns5020/__init__.py @@ -0,0 +1,27 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Karl Palsson +## +## 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, see . +## + +''' +This decoder stacks on top of the 'spi' PD and decodes ADNS-5020 optical mouse +sensor commands and data. + +Use MOSI for the SDIO shared line. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/adns5020/pd.py b/libsigrokdecode4DSL/decoders/adns5020/pd.py new file mode 100644 index 00000000..9ac778e0 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/adns5020/pd.py @@ -0,0 +1,116 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Karl Palsson +## +## 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, see . +## + +import sigrokdecode as srd + +regs = { + 0: 'Product_ID', + 1: 'Revision_ID', + 2: 'Motion', + 3: 'Delta_X', + 4: 'Delta_Y', + 5: 'SQUAL', + 6: 'Shutter_Upper', + 7: 'Shutter_Lower', + 8: 'Maximum_Pixel', + 9: 'Pixel_Sum', + 0xa: 'Minimum_Pixel', + 0xb: 'Pixel_Grab', + 0xd: 'Mouse_Control', + 0x3a: 'Chip_Reset', + 0x3f: 'Inv_Rev_ID', + 0x63: 'Motion_Burst', +} + +class Decoder(srd.Decoder): + api_version = 3 + id = 'adns5020' + name = 'ADNS-5020' + longname = 'Avago ADNS-5020' + desc = 'Bidirectional optical mouse sensor protocol.' + license = 'gplv2+' + inputs = ['spi'] + outputs = [] + tags = ['IC', 'PC', 'Sensor'] + annotations = ( + ('read', 'Register read commands'), + ('write', 'Register write commands'), + ('warning', 'Warnings'), + ) + annotation_rows = ( + ('read', 'Read', (0,)), + ('write', 'Write', (1,)), + ('warnings', 'Warnings', (2,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.ss_cmd, self.es_cmd = 0, 0 + self.mosi_bytes = [] + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + self.put(self.ss_cmd, self.es_cmd, self.out_ann, data) + + def put_warn(self, pos, msg): + self.put(pos[0], pos[1], self.out_ann, [2, [msg]]) + + def decode(self, ss, es, data): + ptype = data[0] + if ptype == 'CS-CHANGE': + # If we transition high mid-stream, toss out our data and restart. + cs_old, cs_new = data[1:] + if cs_old is not None and cs_old == 0 and cs_new == 1: + if len(self.mosi_bytes) not in [0, 2]: + self.put_warn([self.ss_cmd, es], 'Misplaced CS#!') + self.mosi_bytes = [] + return + + # Don't care about anything else. + if ptype != 'DATA': + return + mosi, miso = data[1:] + + self.ss, self.es = ss, es + + if len(self.mosi_bytes) == 0: + self.ss_cmd = ss + self.mosi_bytes.append(mosi) + + # Writes/reads are mostly two transfers (burst mode is different). + if len(self.mosi_bytes) != 2: + return + + self.es_cmd = es + cmd, arg = self.mosi_bytes + write = cmd & 0x80 + reg = cmd & 0x7f + reg_desc = regs.get(reg, 'Reserved %#x' % reg) + if reg > 0x63: + reg_desc = 'Unknown' + if write: + self.putx([1, ['%s: %#x' % (reg_desc, arg)]]) + else: + self.putx([0, ['%s: %d' % (reg_desc, arg)]]) + + self.mosi_bytes = [] diff --git a/libsigrokdecode4DSL/decoders/adxl345/__init__.py b/libsigrokdecode4DSL/decoders/adxl345/__init__.py new file mode 100644 index 00000000..e46bce9f --- /dev/null +++ b/libsigrokdecode4DSL/decoders/adxl345/__init__.py @@ -0,0 +1,26 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 Analog Devices Inc. +## +## 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 +## + +''' +This decoder stacks on top of the 'spi' PD and decodes the +Analog Devices ADXL345 protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/adxl345/lists.py b/libsigrokdecode4DSL/decoders/adxl345/lists.py new file mode 100644 index 00000000..c22ef3e0 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/adxl345/lists.py @@ -0,0 +1,96 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 Analog Devices Inc. +## +## 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 +## + +error_messages = { + 'interrupt': ['Interrupt'], + 'undesirable': ['Undesirable behavior'], + 'dis_single': ['Disable single tap'], + 'dis_double': ['Disable double tap'], + 'dis_single_double': ['Disable single/double tap'], +} + +rate_code = { + 0x00: 0.1, + 0x01: 0.2, + 0x02: 0.39, + 0x03: 0.78, + 0x04: 1.56, + 0x05: 3.13, + 0x06: 6.25, + 0x07: 12.5, + 0x08: 25, + 0x09: 50, + 0x0A: 100, + 0x0B: 200, + 0x0C: 400, + 0x0D: 800, + 0x0E: 1600, + 0x0F: 3200, +} + +fifo_modes = { + 0x00: 'Bypass', + 0x01: 'FIFO', + 0x02: 'Stream', + 0x03: 'Trigger', +} + +operations = { + 0x00: ['WRITE REG', 'WRITE', 'W'], + 0x01: ['READ REG', 'READ', 'R'], +} + +number_bytes = { + 0x00: ['SINGLE BYTE', 'SING BYTE', '1 BYTE', '1B'], + 0x01: ['MULTIPLE BYTES', 'MULTI BYTES', 'n*BYTES', 'n*B'], +} + +registers = { + 0x00: ['DEVID', 'DID', 'ID'], + 0x1D: ['THRESH_TAP', 'TH_TAP', 'TH_T'], + 0x1E: ['OFSX', 'OFX'], + 0x1F: ['OFSY', 'OFY'], + 0x20: ['OFSZ', 'OFZ'], + 0x21: ['DUR'], + 0x22: ['Latent', 'Lat'], + 0x23: ['Window', 'Win'], + 0x24: ['THRESH_ACT', 'TH_ACT', 'TH_A'], + 0x25: ['THRESH_INACT', 'TH_INACT', 'TH_I'], + 0x26: ['TIME_INACT', 'TI_INACT', 'TI_I'], + 0x27: ['ACT_INACT_CTL', 'ACT_I_CTL', 'A_I_C'], + 0x28: ['THRESH_FF', 'TH_FF'], + 0x29: ['TIME_FF', 'TI_FF'], + 0x2A: ['TAP_AXES', 'TAP_AX', 'TP_AX'], + 0x2B: ['ACT_TAP_STATUS', 'ACT_TAP_STAT', 'ACT_TP_ST', 'A_T_S'], + 0x2C: ['BW_RATE', 'BW_R'], + 0x2D: ['POWER_CTL', 'PW_CTL', 'PW_C'], + 0x2E: ['INT_ENABLE', 'INT_EN', 'I_EN'], + 0x2F: ['INT_MAP', 'I_M'], + 0x30: ['INT_SOURCE', 'INT_SRC', 'I_SRC', 'I_S'], + 0x31: ['DATA_FORMAT', 'DATA_FRM', 'D_FRM', 'D_F'], + 0x32: ['DATAX0', 'DX0', 'X0'], + 0x33: ['DATAX1', 'DX1', 'X1'], + 0x34: ['DATAY0', 'DY0', 'Y0'], + 0x35: ['DATAY1', 'DY1', 'Y1'], + 0x36: ['DATAZ0', 'DZ0', 'Z0'], + 0x37: ['DATAZ1', 'DZ1', 'Z1'], + 0x38: ['FIFO_CTL', 'FIF_CT', 'F_C'], + 0x39: ['FIFO_STATUS', 'FIFO_STAT', 'FIF_ST', 'F_S'], +} diff --git a/libsigrokdecode4DSL/decoders/adxl345/pd.py b/libsigrokdecode4DSL/decoders/adxl345/pd.py new file mode 100644 index 00000000..2d53e4c0 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/adxl345/pd.py @@ -0,0 +1,453 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 Analog Devices Inc. +## +## 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 . +## + +import sigrokdecode as srd +from common.srdhelper import SrdIntEnum +from .lists import * + +WORD_SIZE = 8 + +class Channel(): + MISO, MOSI = range(2) + +class Operation(): + READ, WRITE = range(2) + +class BitType(): + ENABLE = {1: ['Enable %s', 'En %s', '%s '], 0: ['Disable %s', 'Dis %s', '!%s '],} + SOURCE = {1: ['Involve %s', 'Inv %s', '%s'], 0: ['Not involve %s', 'Not inv %s', '!%s'],} + INTERRUPT = {1: ['INT2 %s', 'I2: %s '], 0: ['INT1 %s', 'I1:%s '],} + AC_DC = {1: ['%s ac', 'ac'], 0: ['%s dc', 'dc'],} + UNUSED = {1: ['N/A'], 0: ['N/A'],} + OTHER = 0 + +class Bit(): + def __init__(self, name, type, values=None): + self.value = 0 + self.name = name + self.type = type + self.values = values + + def set_value(self, value): + self.value = value + + def get_bit_annotation(self): + if self.type == BitType.OTHER: + annotation = self.values[self.value].copy() + else: + annotation = self.type[self.value].copy() + + for index in range(len(annotation)): + if '%s' in annotation[index]: + annotation[index] = str(annotation[index] % self.name) + return annotation + +Ann = SrdIntEnum.from_str('Ann', 'READ WRITE MB REG_ADDRESS REG_DATA WARNING') + +St = SrdIntEnum.from_str('St', 'IDLE ADDRESS_BYTE DATA') + +class Decoder(srd.Decoder): + api_version = 3 + id = 'adxl345' + name = 'ADXL345' + longname = 'Analog Devices ADXL345' + desc = 'Analog Devices ADXL345 3-axis accelerometer.' + license = 'gplv2+' + inputs = ['spi'] + outputs = [] + tags = ['IC', 'Sensor'] + annotations = ( + ('read', 'Read'), + ('write', 'Write'), + ('mb', 'Multiple bytes'), + ('reg-address', 'Register address'), + ('reg-data', 'Register data'), + ('warning', 'Warning'), + ) + annotation_rows = ( + ('reg', 'Registers', (Ann.READ, Ann.WRITE, Ann.MB, Ann.REG_ADDRESS)), + ('data', 'Data', (Ann.REG_DATA, Ann.WARNING)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.mosi, self.miso = [], [] + self.reg = [] + self.operation = None + self.address = 0 + self.data = -1 + self.state = St.IDLE + self.ss, self.es = -1, -1 + self.samples_per_bit = 0 + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + self.put(self.ss, self.es, self.out_ann, data) + + def putb(self, data, index): + start = self.ss + (self.samples_per_bit * index) + self.put(start, start + self.samples_per_bit, self.out_ann, data) + + def putbs(self, data, start_index, stop_index): + start_index = self.reverse_bit_index(start_index, WORD_SIZE) + stop_index = self.reverse_bit_index(stop_index, WORD_SIZE) + start = self.ss + (self.samples_per_bit * start_index) + stop = start + (self.samples_per_bit * (stop_index - start_index + 1)) + self.put(start, stop, self.out_ann, data) + + def handle_reg_with_scaling_factor(self, data, factor, name, unit, error_msg): + if data == 0 and error_msg is not None: + self.putx([Ann.WARNING, error_msg]) + else: + result = (data * factor) / 1000 + self.putx([Ann.REG_DATA, ['%s: %f %s' % (name, result, unit), '%f %s' % (result, unit)]]) + + def handle_reg_bit_msg(self, bit, index, en_msg, dis_msg): + self.putb([Ann.REG_DATA, [en_msg if bit else dis_msg]], index) + + def interpret_bits(self, data, bits): + bits_values = [] + for offset in range(8): + bits_values.insert(0, (data & (1 << offset)) >> offset) + + for index in range(len(bits)): + if bits[index] is None: + continue + bit = bits[index] + bit.set_value(bits_values[index]) + self.putb([Ann.REG_DATA, bit.get_bit_annotation()], index) + + return list(reversed(bits_values)) + + def reverse_bit_index(self, index, word_size): + return word_size - index - 1 + + def get_decimal_number(self, bits, start_index, stop_index): + number = 0 + interval = range(start_index, stop_index + 1, 1) + for index, offset in zip(interval, range(len(interval))): + bit = bits[index] + number = number | (bit << offset) + return number + + def get_axis_value(self, data, axis): + if self.data != - 1: + data <<= 8 + self.data |= data + self.put(self.start_index, self.es, self.out_ann, + [Ann.REG_DATA, ['%s: 0x%04X' % (axis, self.data), str(data)]]) + self.data = -1 + else: + self.putx([Ann.REG_DATA, [str(data)]]) + + def handle_reg_0x1d(self, data): + self.handle_reg_with_scaling_factor(data, 62.5, 'Threshold', 'g', + error_messages['undesirable']) + + def handle_reg_0x1e(self, data): + self.handle_reg_with_scaling_factor(data, 15.6, 'OFSX', 'g', None) + + def handle_reg_0x1f(self, data): + self.handle_reg_with_scaling_factor(data, 15.6, 'OFSY', 'g', None) + + def handle_reg_0x20(self, data): + self.handle_reg_with_scaling_factor(data, 15.6, 'OFSZ', 'g', None) + + def handle_reg_0x21(self, data): + self.handle_reg_with_scaling_factor(data, 0.625, 'Duration', 's', + error_messages['dis_single_double']) + + def handle_reg_0x22(self, data): + self.handle_reg_with_scaling_factor(data, 1.25, 'Latency', 's', + error_messages['dis_double']) + + def handle_reg_0x23(self, data): + self.handle_reg_with_scaling_factor(data, 1.25, 'Window', 's', + error_messages['dis_double']) + + def handle_reg_0x24(self, data): + self.handle_reg_0x1d(data) + + def handle_reg_0x25(self, data): + self.handle_reg_0x1d(data) + + def handle_reg_0x26(self, data): + self.handle_reg_with_scaling_factor(data, 1000, 'Time', 's', + error_messages['interrupt']) + + def handle_reg_0x27(self, data): + bits = [Bit('ACT', BitType.AC_DC), + Bit('ACT_X', BitType.ENABLE), + Bit('ACT_Y', BitType.ENABLE), + Bit('ACT_Z', BitType.ENABLE), + Bit('INACT', BitType.AC_DC), + Bit('INACT_X', BitType.ENABLE), + Bit('INACT_Y', BitType.ENABLE), + Bit('INACT_Z', BitType.ENABLE)] + self.interpret_bits(data, bits) + + def handle_reg_0x28(self, data): + self.handle_reg_0x1d(data) + + def handle_reg_0x29(self, data): + self.handle_reg_with_scaling_factor(data, 5, 'Time', 's', + error_messages['undesirable']) + + def handle_reg_0x2a(self, data): + bits = [Bit('', BitType.UNUSED), + Bit('', BitType.UNUSED), + Bit('', BitType.UNUSED), + Bit('', BitType.UNUSED), + Bit('', BitType.OTHER, {1: ['Suppressed', 'Suppr', 'S'], + 0: ['Unsuppressed', 'Unsuppr', 'Uns'],}), + Bit('TAP_X', BitType.ENABLE), + Bit('TAP_Y', BitType.ENABLE), + Bit('TAP_Z', BitType.ENABLE)] + self.interpret_bits(data, bits) + + def handle_reg_0x2b(self, data): + bits = [Bit('', BitType.UNUSED), + Bit('ACT_X', BitType.SOURCE), + Bit('ACT_Y', BitType.SOURCE), + Bit('ACT_Z', BitType.SOURCE), + Bit('', BitType.OTHER, {1: ['Asleep', 'Asl'], + 0: ['Not asleep', 'Not asl', '!Asl'],}), + Bit('TAP_X', BitType.SOURCE), + Bit('TAP_Y', BitType.SOURCE), + Bit('TAP_Z', BitType.SOURCE)] + self.interpret_bits(data, bits) + + def handle_reg_0x2c(self, data): + bits = [Bit('', BitType.UNUSED), + Bit('', BitType.UNUSED), + Bit('', BitType.UNUSED), + Bit('', BitType.OTHER, {1: ['Reduce power', 'Reduce pw', 'Red pw'], 0: ['Normal operation', 'Normal op', 'Norm op'],})] + bits_values = self.interpret_bits(data, bits) + + start_index, stop_index = 0, 3 + rate = self.get_decimal_number(bits_values, start_index, stop_index) + self.putbs([Ann.REG_DATA, ['%f' % rate_code[rate]]], stop_index, start_index) + + def handle_reg_0x2d(self, data): + bits = [Bit('', BitType.UNUSED), + Bit('', BitType.UNUSED), + Bit('', BitType.OTHER, {1: ['Link'], 0: ['Unlink'], }), + Bit('AUTO_SLEEP', BitType.ENABLE), + Bit('', BitType.OTHER, {1: ['Measurement mode', 'Measurement', 'Meas'], 0: ['Standby mode', 'Standby'], }), + Bit('', BitType.OTHER, {1: ['Sleep mode', 'Sleep', 'Slp'], 0: ['Normal mode', 'Normal', 'Nrm'],})] + bits_values = self.interpret_bits(data, bits) + + start_index, stop_index = 0, 1 + wakeup = self.get_decimal_number(bits_values, start_index, stop_index) + frequency = 2 ** (~wakeup & 0x03) + self.putbs([Ann.REG_DATA, ['%d Hz' % frequency]], stop_index, start_index) + + def handle_reg_0x2e(self, data): + bits = [Bit('DATA_READY', BitType.ENABLE), + Bit('SINGLE_TAP', BitType.ENABLE), + Bit('DOUBLE_TAP', BitType.ENABLE), + Bit('Activity', BitType.ENABLE), + Bit('Inactivity', BitType.ENABLE), + Bit('FREE_FALL', BitType.ENABLE), + Bit('Watermark', BitType.ENABLE), + Bit('Overrun', BitType.ENABLE)] + self.interpret_bits(data, bits) + + def handle_reg_0x2f(self, data): + bits = [Bit('DATA_READY', BitType.INTERRUPT), + Bit('SINGLE_TAP', BitType.INTERRUPT), + Bit('DOUBLE_TAP', BitType.INTERRUPT), + Bit('Activity', BitType.INTERRUPT), + Bit('Inactivity', BitType.INTERRUPT), + Bit('FREE_FALL', BitType.INTERRUPT), + Bit('Watermark', BitType.INTERRUPT), + Bit('Overrun', BitType.INTERRUPT)] + self.interpret_bits(data, bits) + + def handle_reg_0x30(self, data): + bits = [Bit('DATA_READY', BitType.SOURCE), + Bit('SINGLE_TAP', BitType.SOURCE), + Bit('DOUBLE_TAP', BitType.SOURCE), + Bit('Activity', BitType.SOURCE), + Bit('Inactivity', BitType.SOURCE), + Bit('FREE_FALL', BitType.SOURCE), + Bit('Watermark', BitType.SOURCE), + Bit('Overrun', BitType.SOURCE)] + self.interpret_bits(data, bits) + + def handle_reg_0x31(self, data): + bits = [Bit('SELF_TEST', BitType.ENABLE), + Bit('', BitType.OTHER, {1: ['3-wire SPI', '3-SPI'], 0: ['4-wire SPI', '4-SPI'],}), + Bit('', BitType.OTHER, {1: ['INT ACT LOW', 'INT LOW'], 0: ['INT ACT HIGH', 'INT HIGH'],}), + Bit('', BitType.UNUSED), + Bit('', BitType.OTHER, {1: ['Full resolution', 'Full res'], 0: ['10-bit mode', '10-bit'],}), + Bit('', BitType.OTHER, {1: ['MSB mode', 'MSB'], 0: ['LSB mode', 'LSB'],})] + bits_values = self.interpret_bits(data, bits) + + start_index, stop_index = 0, 1 + range_g = self.get_decimal_number(bits_values, start_index, stop_index) + result = 2 ** (range_g + 1) + self.putbs([Ann.REG_DATA, ['+/-%d g' % result]], stop_index, start_index) + + def handle_reg_0x32(self, data): + self.data = data + self.putx([Ann.REG_DATA, [str(data)]]) + + def handle_reg_0x33(self, data): + self.get_axis_value(data, 'X') + + def handle_reg_0x34(self, data): + self.handle_reg_0x32(data) + + def handle_reg_0x35(self, data): + self.get_axis_value(data, 'Y') + + def handle_reg_0x36(self, data): + self.handle_reg_0x32(data) + + def handle_reg_0x37(self, data): + self.get_axis_value(data, 'Z') + + def handle_reg_0x38(self, data): + bits = [None, + None, + Bit('', BitType.OTHER, {1: ['Trig-INT2', 'INT2'], 0: ['Trig-INT1', 'INT1'], })] + bits_values = self.interpret_bits(data, bits) + + start_index, stop_index = 6, 7 + fifo = self.get_decimal_number(bits_values, start_index, stop_index) + self.putbs([Ann.REG_DATA, [fifo_modes[fifo]]], stop_index, start_index) + + start_index, stop_index = 0, 4 + samples = self.get_decimal_number(bits_values, start_index, stop_index) + self.putbs([Ann.REG_DATA, ['Samples: %d' % samples, '%d' % samples]], stop_index, start_index) + + def handle_reg_0x39(self, data): + bits = [Bit('', BitType.OTHER, {1: ['Triggered', 'Trigg'], 0: ['Not triggered', 'Not trigg'],}), + Bit('', BitType.UNUSED)] + bits_values = self.interpret_bits(data, bits) + + start_index, stop_index = 0, 5 + entries = self.get_decimal_number(bits_values, start_index, stop_index) + self.putbs([Ann.REG_DATA, ['Entries: %d' % entries, '%d' % entries]], stop_index, start_index) + + def get_bit(self, channel): + if (channel == Channel.MOSI and self.mosi is None) or \ + (channel == Channel.MISO and self.miso is None): + raise Exception('No available data') + + mosi_bit, miso_bit = 0, 0 + if self.miso is not None: + if len(self.mosi) < 0: + raise Exception('No available data') + miso_bit = self.miso.pop(0) + if self.miso is not None: + if len(self.miso) < 0: + raise Exception('No available data') + mosi_bit = self.mosi.pop(0) + + if channel == Channel.MOSI: + return mosi_bit + return miso_bit + + def decode(self, ss, es, data): + ptype = data[0] + + if ptype == 'CS-CHANGE': + cs_old, cs_new = data[1:] + if cs_old is not None and cs_old == 1 and cs_new == 0: + self.ss, self.es = ss, es + self.state = St.ADDRESS_BYTE + else: + self.state = St.IDLE + + elif ptype == 'BITS': + if data[1] is not None: + self.mosi = list(reversed(data[1])) + if data[2] is not None: + self.miso = list(reversed(data[2])) + + if self.mosi is None and self.miso is None: + return + + if self.state == St.ADDRESS_BYTE: + # OPERATION BIT + op_bit = self.get_bit(Channel.MOSI) + self.put(op_bit[1], op_bit[2], self.out_ann, + [Ann.READ if op_bit[0] else Ann.WRITE, operations[op_bit[0]]]) + self.operation = Operation.READ if op_bit[0] else Operation.WRITE + # MULTIPLE-BYTE BIT + mb_bit = self.get_bit(Channel.MOSI) + self.put(mb_bit[1], mb_bit[2], self.out_ann, [Ann.MB, number_bytes[mb_bit[0]]]) + + # REGISTER 6-BIT ADDRESS + self.address = 0 + start_sample = self.mosi[0][1] + addr_bit = [] + for i in range(6): + addr_bit = self.get_bit(Channel.MOSI) + self.address |= addr_bit[0] + self.address <<= 1 + self.address >>= 1 + self.put(start_sample, addr_bit[2], self.out_ann, + [Ann.REG_ADDRESS, ['ADDRESS: 0x%02X' % self.address, 'ADDR: 0x%02X' + % self.address, '0x%02X' % self.address]]) + self.ss = -1 + self.state = St.DATA + + elif self.state == St.DATA: + self.reg.extend(self.mosi if self.operation == Operation.WRITE else self.miso) + + self.mosi, self.miso = [], [] + if self.ss == -1: + self.ss, self.es = self.reg[0][1], es + self.samples_per_bit = self.reg[0][2] - self.ss + + if len(self.reg) < 8: + return + else: + reg_value = 0 + reg_bit = [] + for offset in range(7, -1, -1): + reg_bit = self.reg.pop(0) + + mask = reg_bit[0] << offset + reg_value |= mask + + if self.address < 0x00 or self.address > 0x39: + return + + if self.address in [0x32, 0x34, 0x36]: + self.start_index = self.ss + + if 0x1D > self.address >= 0x00: + self.put(self.ss, reg_bit[2], self.out_ann, [Ann.REG_ADDRESS, [str(self.address)]]) + self.put(self.ss, reg_bit[2], self.out_ann, [Ann.REG_DATA, [str(reg_value)]]) + else: + self.put(self.ss, reg_bit[2], self.out_ann, [Ann.REG_ADDRESS, registers[self.address]]) + handle_reg = getattr(self, 'handle_reg_0x%02x' % self.address) + handle_reg(reg_value) + + self.reg = [] + self.address += 1 + self.ss = -1 diff --git a/libsigrokdecode4DSL/decoders/am230x/__init__.py b/libsigrokdecode4DSL/decoders/am230x/__init__.py new file mode 100644 index 00000000..280c8856 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/am230x/__init__.py @@ -0,0 +1,36 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Johannes Roemer +## +## 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, see . +## + +''' +This decoder handles the proprietary single wire communication protocol used +by the Aosong AM230x/DHTxx/RHTxx series of digital humidity and temperature +sensors. + +Sample rate: +A sample rate of at least 200kHz is recommended to properly detect all the +elements of the protocol. + +Options: +The AM230x and DHTxx/RHTxx digital humidity and temperature sensors use the +same single-wire protocol with different encoding of the measured values. +Therefore the option 'device' must be used to properly decode the +communication of the respective sensor. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/am230x/pd.py b/libsigrokdecode4DSL/decoders/am230x/pd.py new file mode 100644 index 00000000..fbc68d39 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/am230x/pd.py @@ -0,0 +1,229 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Johannes Roemer +## +## 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, see . +## + +import sigrokdecode as srd + +# Define valid timing values (in microseconds). +timing = { + 'START LOW' : {'min': 750, 'max': 25000}, + 'START HIGH' : {'min': 10, 'max': 10000}, + 'RESPONSE LOW' : {'min': 50, 'max': 90}, + 'RESPONSE HIGH' : {'min': 50, 'max': 90}, + 'BIT LOW' : {'min': 45, 'max': 90}, + 'BIT 0 HIGH' : {'min': 20, 'max': 35}, + 'BIT 1 HIGH' : {'min': 65, 'max': 80}, +} + +class SamplerateError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = 'am230x' + name = 'AM230x' + longname = 'Aosong AM230x/DHTxx/RHTxx' + desc = 'Aosong AM230x/DHTxx/RHTxx humidity/temperature sensor.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['IC', 'Sensor'] + channels = ( + {'id': 'sda', 'name': 'SDA', 'desc': 'Single wire serial data line'}, + ) + options = ( + {'id': 'device', 'desc': 'Device type', + 'default': 'am230x', 'values': ('am230x/rht', 'dht11')}, + ) + annotations = ( + ('start', 'Start'), + ('response', 'Response'), + ('bit', 'Bit'), + ('end', 'End'), + ('byte', 'Byte'), + ('humidity', 'Relative humidity in percent'), + ('temperature', 'Temperature in degrees Celsius'), + ('checksum', 'Checksum'), + ) + annotation_rows = ( + ('bits', 'Bits', (0, 1, 2, 3)), + ('bytes', 'Bytes', (4,)), + ('results', 'Results', (5, 6, 7)), + ) + + def putfs(self, data): + self.put(self.fall, self.samplenum, self.out_ann, data) + + def putb(self, data): + self.put(self.bytepos[-1], self.samplenum, self.out_ann, data) + + def putv(self, data): + self.put(self.bytepos[-2], self.samplenum, self.out_ann, data) + + def reset_variables(self): + self.state = 'WAIT FOR START LOW' + self.fall = 0 + self.rise = 0 + self.bits = [] + self.bytepos = [] + + def is_valid(self, name): + dt = 0 + if name.endswith('LOW'): + dt = self.samplenum - self.fall + elif name.endswith('HIGH'): + dt = self.samplenum - self.rise + if dt >= self.cnt[name]['min'] and dt <= self.cnt[name]['max']: + return True + return False + + def bits2num(self, bitlist): + number = 0 + for i in range(len(bitlist)): + number += bitlist[-1 - i] * 2**i + return number + + def calculate_humidity(self, bitlist): + h = 0 + if self.options['device'] == 'dht11': + h = self.bits2num(bitlist[0:8]) + else: + h = self.bits2num(bitlist) / 10 + return h + + def calculate_temperature(self, bitlist): + t = 0 + if self.options['device'] == 'dht11': + t = self.bits2num(bitlist[0:8]) + else: + t = self.bits2num(bitlist[1:]) / 10 + if bitlist[0] == 1: + t = -t + return t + + def calculate_checksum(self, bitlist): + checksum = 0 + for i in range(8, len(bitlist) + 1, 8): + checksum += self.bits2num(bitlist[i-8:i]) + return checksum % 256 + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.reset_variables() + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def metadata(self, key, value): + if key != srd.SRD_CONF_SAMPLERATE: + return + self.samplerate = value + # Convert microseconds to sample counts. + self.cnt = {} + for e in timing: + self.cnt[e] = {} + for t in timing[e]: + self.cnt[e][t] = timing[e][t] * self.samplerate / 1000000 + + def handle_byte(self, bit): + self.bits.append(bit) + self.putfs([2, ['Bit: %d' % bit, '%d' % bit]]) + self.fall = self.samplenum + self.state = 'WAIT FOR BIT HIGH' + if len(self.bits) % 8 == 0: + byte = self.bits2num(self.bits[-8:]) + self.putb([4, ['Byte: %#04x' % byte, '%#04x' % byte]]) + if len(self.bits) == 16: + h = self.calculate_humidity(self.bits[-16:]) + self.putv([5, ['Humidity: %.1f %%' % h, 'RH = %.1f %%' % h]]) + elif len(self.bits) == 32: + t = self.calculate_temperature(self.bits[-16:]) + self.putv([6, ['Temperature: %.1f °C' % t, 'T = %.1f °C' % t]]) + elif len(self.bits) == 40: + parity = self.bits2num(self.bits[-8:]) + if parity == self.calculate_checksum(self.bits[0:32]): + self.putb([7, ['Checksum: OK', 'OK']]) + else: + self.putb([7, ['Checksum: not OK', 'NOK']]) + self.state = 'WAIT FOR END' + self.bytepos.append(self.samplenum) + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + while True: + # State machine. + if self.state == 'WAIT FOR START LOW': + self.wait({0: 'f'}) + self.fall = self.samplenum + self.state = 'WAIT FOR START HIGH' + elif self.state == 'WAIT FOR START HIGH': + self.wait({0: 'r'}) + if self.is_valid('START LOW'): + self.rise = self.samplenum + self.state = 'WAIT FOR RESPONSE LOW' + else: + self.reset_variables() + elif self.state == 'WAIT FOR RESPONSE LOW': + self.wait({0: 'f'}) + if self.is_valid('START HIGH'): + self.putfs([0, ['Start', 'S']]) + self.fall = self.samplenum + self.state = 'WAIT FOR RESPONSE HIGH' + else: + self.reset_variables() + elif self.state == 'WAIT FOR RESPONSE HIGH': + self.wait({0: 'r'}) + if self.is_valid('RESPONSE LOW'): + self.rise = self.samplenum + self.state = 'WAIT FOR FIRST BIT' + else: + self.reset_variables() + elif self.state == 'WAIT FOR FIRST BIT': + self.wait({0: 'f'}) + if self.is_valid('RESPONSE HIGH'): + self.putfs([1, ['Response', 'R']]) + self.fall = self.samplenum + self.bytepos.append(self.samplenum) + self.state = 'WAIT FOR BIT HIGH' + else: + self.reset_variables() + elif self.state == 'WAIT FOR BIT HIGH': + self.wait({0: 'r'}) + if self.is_valid('BIT LOW'): + self.rise = self.samplenum + self.state = 'WAIT FOR BIT LOW' + else: + self.reset_variables() + elif self.state == 'WAIT FOR BIT LOW': + self.wait({0: 'f'}) + if self.is_valid('BIT 0 HIGH'): + bit = 0 + elif self.is_valid('BIT 1 HIGH'): + bit = 1 + else: + self.reset_variables() + continue + self.handle_byte(bit) + elif self.state == 'WAIT FOR END': + self.wait({0: 'r'}) + self.putfs([3, ['End', 'E']]) + self.reset_variables() diff --git a/libsigrokdecode4DSL/decoders/amulet_ascii/__init__.py b/libsigrokdecode4DSL/decoders/amulet_ascii/__init__.py new file mode 100644 index 00000000..7d2c8c35 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/amulet_ascii/__init__.py @@ -0,0 +1,28 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Vesa-Pekka Palmu +## +## 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, see . +## + +''' +This decoder stacks on top of the 'uart' PD and decodes the ASCII protocol +for Amulet LCD display controllers. + +Currently the decoder treats both RX and TX the same way, decoding all +message types. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/amulet_ascii/lists.py b/libsigrokdecode4DSL/decoders/amulet_ascii/lists.py new file mode 100644 index 00000000..92e27a95 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/amulet_ascii/lists.py @@ -0,0 +1,73 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Vesa-Pekka Palmu +## +## 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, see . +## + +from collections import OrderedDict + +# OrderedDict which maps command IDs to their names and descriptions. +cmds = OrderedDict([ + (0xA0, ('PAGE', 'Jump to page')), + (0xD0, ('GBV', 'Get byte variable')), + (0xD1, ('GWV', 'Get word variable')), + (0xD2, ('GSV', 'Get string variable')), + (0xD3, ('GLV', 'Get label variable')), + (0xD4, ('GRPC', 'Get RPC buffer')), + (0xD5, ('SBV', 'Set byte variable')), + (0xD6, ('SWV', 'Set word variable')), + (0xD7, ('SSV', 'Set string variable')), + (0xD8, ('RPC', 'Invoke RPC')), + (0xD9, ('LINE', 'Draw line')), + (0xDA, ('RECT', 'Draw rectangle')), + (0xDB, ('FRECT', 'Draw filled rectangle')), + (0xDC, ('PIXEL', 'Draw pixel')), + (0xDD, ('GBVA', 'Get byte variable array')), + (0xDE, ('GWVA', 'Get word variable array')), + (0xDF, ('SBVA', 'Set byte variable array')), + (0xE0, ('GBVR', 'Get byte variable reply')), + (0xE1, ('GWVR', 'Get word variable reply')), + (0xE2, ('GSVR', 'Get string variable reply')), + (0xE3, ('GLVR', 'Get label variable reply')), + (0xE4, ('GRPCR', 'Get RPC buffer reply')), + (0xE5, ('SBVR', 'Set byte variable reply')), + (0xE6, ('SWVR', 'Set word variable reply')), + (0xE7, ('SSVR', 'Set string variable reply')), + (0xE8, ('RPCR', 'Invoke RPC reply')), + (0xE9, ('LINER', 'Draw line reply')), + (0xEA, ('RECTR', 'Draw rectangle')), + (0xEB, ('FRECTR', 'Draw filled rectangle reply')), + (0xEC, ('PIXELR', 'Draw pixel reply')), + (0xED, ('GBVAR', 'Get byte variable array reply')), + (0xEE, ('GWVAR', 'Get word variable array reply')), + (0xEF, ('SBVAR', 'Set byte variable array reply')), + (0xF0, ('ACK', 'Acknowledgment')), + (0xF1, ('NACK', 'Negative acknowledgment')), + (0xF2, ('SWVA', 'Set word variable array')), + (0xF3, ('SWVAR', 'Set word variable array reply')), + (0xF4, ('GCV', 'Get color variable')), + (0xF5, ('GCVR', 'Get color variable reply')), + (0xF6, ('SCV', 'Set color variable')), + (0xF7, ('SCVR', 'Set color variable reply')), +]) + +cmds_with_high_bytes = [ + 0xA0, # PAGE - Page change + 0xD7, # SVV - Set string variable + 0xE7, # SVVR - Set string variable reply + 0xE2, # GSVR - Get string variable reply + 0xE3, # GLVR - Get label variable reply +] diff --git a/libsigrokdecode4DSL/decoders/amulet_ascii/pd.py b/libsigrokdecode4DSL/decoders/amulet_ascii/pd.py new file mode 100644 index 00000000..71953234 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/amulet_ascii/pd.py @@ -0,0 +1,699 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Vesa-Pekka Palmu +## +## 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 . +## + +import sigrokdecode as srd +from math import ceil +from common.srdhelper import SrdIntEnum +from .lists import * + +L = len(cmds) +RX = 0 +TX = 1 + +Ann = SrdIntEnum.from_list('Ann', + [c[0] for c in cmds.values()] + ['BIT', 'FIELD', 'WARN']) + +def cmd_annotation_classes(): + return tuple([tuple([cmd[0].lower(), cmd[1]]) for cmd in cmds.values()]) + +class Decoder(srd.Decoder): + api_version = 3 + id = 'amulet_ascii' + name = 'Amulet ASCII' + longname = 'Amulet LCD ASCII' + desc = 'Amulet Technologies LCD controller ASCII protocol.' + license = 'gplv3+' + inputs = ['uart'] + outputs = [] + tags = ['Display'] + annotations = cmd_annotation_classes() + ( + ('bit', 'Bit'), + ('field', 'Field'), + ('warning', 'Warning'), + ) + annotation_rows = ( + ('bits', 'Bits', (L + 0,)), + ('fields', 'Fields', (L + 1,)), + ('commands', 'Commands', tuple(range(L))), + ('warnings', 'Warnings', (L + 2,)), + ) + options = ( + {'id': 'ms_chan', 'desc': 'Master -> slave channel', + 'default': 'RX', 'values': ('RX', 'TX')}, + {'id': 'sm_chan', 'desc': 'Slave -> master channel', + 'default': 'TX', 'values': ('RX', 'TX')}, + ) + + def __init__(self): + self.reset() + + def reset(self): + self.state = None + self.cmdstate = None + + # Build dict mapping command keys to handler functions. Each + # command in 'cmds' (defined in lists.py) has a matching + # handler self.handle_. + def get_handler(cmd): + s = 'handle_%s' % cmds[cmd][0].lower().replace('/', '_') + return getattr(self, s) + self.cmd_handlers = dict((cmd, get_handler(cmd)) for cmd in cmds.keys()) + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + # Simplification, most annotations span exactly one SPI byte/packet. + self.put(self.ss, self.es, self.out_ann, data) + + def putf(self, data): + self.put(self.ss_field, self.es_field, self.out_ann, data) + + def putc(self, data): + self.put(self.ss_cmd, self.es_cmd, self.out_ann, data) + + def cmd_ann_list(self): + x, s = cmds[self.state][0], cmds[self.state][1] + return ['Command: %s (%s)' % (s, x), 'Command: %s' % s, + 'Cmd: %s' % s, 'Cmd: %s' % x, x] + + def emit_cmd_byte(self): + self.ss_cmd = self.ss + self.putx([Ann.FIELD, self.cmd_ann_list()]) + + def emit_addr_bytes(self, pdata): + if self.cmdstate == 2: + self.ss_field = self.ss + self.addr = chr(pdata) + self.putx([Ann.BIT, ['Address high nibble: %c' % pdata, + 'Addr high 0x%c' % pdata, 'Addr h 0x%c' % pdata]]) + elif self.cmdstate == 3: + self.es_field = self.es + self.addr += chr(pdata) + self.addr = int(self.addr, 16) + self.putx([Ann.BIT, ['Address low nibble: %c' % pdata, + 'Addr low 0x%c' % pdata, 'Addr l 0x%c' % pdata]]) + self.putf([Ann.FIELD, ['Address: 0x%02X' % self.addr, + 'Addr: 0x%02X' % self.addr, '0x%02X' % self.addr]]) + + def emit_cmd_end(self, data): + self.es_cmd = self.es + self.putc(data) + self.state = None + + def handle_read(self, data): + if self.cmdstate == 1: + self.emit_cmd_byte() + self.addr = 0 + elif self.cmdstate == 2: + self.emit_addr_bytes(pdata) + elif self.cmdstate == 3: + self.emit_addr_bytes(pdata) + self.cmdstate += 1 + + def handle_set_common(self, pdata): + if self.cmdstate == 1: + self.addr = 0 + self.emit_addr_bytes(pdata) + + def emit_not_implemented(self, data): + self.es_cmd = self.es + self.putc([Ann.WARN, ['Command not decoded', 'Not decoded']]) + self.emit_cmd_end(data) + + def handle_string(self, pdata, ann_class): + # TODO: unicode / string modifiers... + self.handle_set_common(pdata) + if self.cmdstate == 4: + self.ss_field = self.ss + self.value = '' + if pdata == 0x00: + # Null terminated string ends. + self.es_field = self.es + self.putx([Ann.BIT, ['NULL']]) + self.putf([Ann.FIELD, ['Value: %s' % self.value, + 'Val: %s' % self.value, '%s' % self.value]]) + self.emit_cmd_end([ann_class, self.cmd_ann_list()]) + return + if self.cmdstate > 3: + self.value += chr(pdata) + self.putx([Ann.BIT, ['%c' % pdata]]) + self.cmdstate += 1 + + # Command handlers + + # Page change 0xA0, 0x02, index_high, index_low, checksum + def handle_page(self, pdata): + if self.cmdstate == 2: + if pdata == 0x02: + self.ss_field = self.ss_cmd + self.es_field = self.es + self.putf([Ann.FIELD, self.cmd_ann_list()]) + self.checksum = 0xA0 + 0x02 + else: + self.putx([Ann.WARN, ['Illegal second byte for page change', + 'Illegal byte']]) + self.state = None + elif self.cmdstate == 3: + self.ss_field = self.ss + self.checksum += pdata + self.page[0] = pdata + elif self.cmdstate == 4: + self.checksum += pdata + self.page[1] = pdata + self.es_field = self.es + if self.page[0] == self.page [1] == 0xFF: + # Soft reset trigger + self.putf(Ann.WARN, ['Soft reset', 'Reset']) + else: + page = chr(self.page[0]) + chr(self.page[1]) + self.putf(Ann.FIELD, ['Page index: 0x%s' % page, + 'Page: 0x%s' % page, '0x%s' % page]) + elif self.cmdstate == 5: + self.checksum += pdata + if (self.checksum & 0xFF) != 0: + self.putx([Ann.WARN, ['Checksum error', 'Error', 'ERR']]) + else: + self.putx([Ann.FIELD, ['Checksum OK', 'OK']]) + self.emit_cmd_end(Ann.PAGE) + self.cmdstate += 1 + + # Value reads: command byte, address high nibble, address low nibble + + # Get byte value + def handle_gbv(self, pdata): + self.handle_read(pdata) + self.emit_cmd_end([Ann.GBV, self.cmd_ann_list()]) + + # Get word value + def handle_gwv(self, pdata): + self.handle_read(pdata) + self.emit_cmd_end([Ann.GWV, self.cmd_ann_list()]) + + # Get string value + def handle_gsv(self, pdata): + self.handle_read(pdata) + self.emit_cmd_end([Ann.GSV, self.cmd_ann_list()]) + + # Get label value + def handle_glv(self, pdata): + self.handle_read(pdata) + self.emit_cmd_end([Ann.GLV, self.cmd_ann_list()]) + + # Get RPC buffer + def handle_grpc(self, pdata): + if self.cmdstate == 2: + self.ss_field = self.ss + self.flags = int(chr(pdata), 16) << 4 + elif self.cmdstate == 3: + self.flags += int(chr(pdata), 16) + self.es_field = self.es + self.putf([Ann.FIELD, ['RPC flag: 0x%02X' % self.flags]]) + self.emit_cmd_end([Ann.GRPC, self.cmd_ann_list()]) + + # Get byte value array + def handle_gbva(self, pdata): + self.handle_read(pdata) + self.emit_cmd_end([Ann.GBVA, self.cmd_ann_list()]) + + # Get word value array + def handle_gwva(self, pdata): + self.handle_read(pdata) + self.emit_cmd_end([Ann.GWVA, self.cmd_ann_list()]) + + # Get color variable + def handle_gcv(self, pdata): + self.handle_read(pdata) + self.emit_cmd_end([Ann.GCV, self.cmd_ann_list()]) + + # Value setters: command byte, address high nibble, address low nibble, data bytes + + # Set byte value data = high nibble, low nibble + def handle_sbv(self, pdata): + self.handle_set_common(pdata) + if self.cmdstate == 4: + self.ss_field = self.ss + self.value = chr(pdata) + elif self.cmdstate == 5: + self.value += chr(pdata) + self.es_field = self.es + self.putf([Ann.FIELD, ['Value: 0x%s' % self.value, + 'Val: 0x%s' % self.value, '0x%s' % self.value]]) + self.emit_cmd_end([Ann.SBV, self.cmd_ann_list()]) + self.cmdstate += 1 + + # Set word value, msb high, msb low, lsb high, lsb low + def handle_swv(self, pdata): + self.handle_set_common(pdata) + if self.cmdstate > 3: + nibble = self.cmdstate - 4 + if nibble == 0: + self.ss_field = self.ss + self.value = 0 + self.value += int(chr(pdata), 16) << 12 - (4 * nibble) + if nibble == 3: + self.es_field = self.es + self.putf([Ann.FIELD, ['Value: 0x%04x' % self.value, + 'Val: 0x%04x' % self.value, '0x%04x' % self.value]]) + self.emit_cmd_end([Ann.SWV, self.cmd_ann_list()]) + return + self.cmdstate += 1 + + # Set string value, null terminated utf8 strings + def handle_ssv(self, pdata): + self.handle_string(pdata, Ann.SSV) + + # Set byte value array + def handle_sbva(self, pdata): + nibble = (self.cmdstate - 3) % 2 + if self.cmdstate == 2: + self.addr = int(chr(pdata), 16) << 4 + self.ss_field = self.ss + self.putx([Ann.BIT, ['Address high nibble: %c' % pdata, + 'Addr high 0x%c' % pdata, '0x%c' % pdata]]) + elif self.cmdstate == 3: + self.addr += int(chr(pdata), 16) + self.es_field = self.ss + self.putx([Ann.BIT, ['Address low nibble: %c' % pdata, + 'Addr low 0x%c' % pdata, '0x%c' % pdata]]) + self.putf([Ann.FIELD, ['Address: 0x%02X' % self.addr, + 'Addr: 0x%02X' % self.addr, '0x%02X' % self.addr]]) + elif stage == 2: + if pdata == 0x00: + # Null terminated list + self.emit_cmd_end([Ann.SBVA, self.cmd_ann_list()]) + return + self.value = int(chr(pdata), 16) << 4 + else: + self.value += int(chr(pdata), 16) + self.es_field = self.es + self.putf([Ann.FIELD, ['Value 0x%02X' % self.value, + '0x%02X' % self.value]]) + self.cmdstate += 1 + + # Set word value array + def handle_swva(self, pdata): + nibble = (self.cmdstate - 3) % 4 + if self.cmdstate == 2: + self.addr = int(chr(pdata), 16) << 4 + self.ss_field = self.ss + self.putx([Ann.BIT, ['Address high nibble: %c' % pdata, + 'Addr high 0x%c' % pdata, '0x%c' % pdata]]) + elif self.cmdstate == 3: + self.addr += int(chr(pdata), 16) + self.es_field = self.ss + self.putx([Ann.BIT, ['Address low nibble: %c' % pdata, + 'Addr low 0x%c' % pdata, '0x%c' % pdata]]) + self.putf([Ann.FIELD, ['Address: 0x%02X' % self.addr, + 'Addr: 0x%02X' % self.addr, '0x%02X' % self.addr]]) + self.value = 0 + else: + self.value += int(chr(pdata), 16) << 12 - (4 * nibble) + if nibble == 0: + if pdata == 0x00: + # Null terminated list + self.emit_cmd_end([Ann.SWVA, self.cmd_ann_list()]) + return + self.ss_field = self.ss + if nibble == 3: + self.es_field = self.es + self.putf([Ann.FIELD, ['Value 0x%04X' % self.value, + '0x%04X' % self.value]]) + self.cmdstate += 1 + + # Set color variable + def handle_scv(self, pdata): + if self.cmdstate == 8: + self.emit_not_implemented([Ann.SCV, self.cmd_ann_list()]) + self.cmdstate += 1 + + # RPC trigger + def handle_rpc(self, pdata): + self.handle_read(pdata) + self.emit_cmd_end([Ann.RPC, self.cmd_ann_list()]) + + # Drawing + + # Decode pair of (x,y) 16bit coordinates + def decode_coords(self, pdata): + if self.cmdstate == 1: + self.coords[0] = 0 + self.coords[1] = 0 + self.coords[2] = 0 + self.coords[3] = 0 + if self.cmdstate < 18: + # Coordinates + nibble = (self.cmdstate - 1) % 4 + i = (self.cmdstate - 1) / 4 + self.coords[i] += int(chr(pdata), 16) << 12 - (4 * nibble) + if nibble == 0: + self.ss_field = self.ss + elif nibble == 3: + self.es_field = self.es + self.putf([Ann.FIELD, ['Coordinate 0x%04X' % self.coords[i]], + ['0x%04X' % self.coords[i]]]) + + # TODO: There are actually two protocol revisions for drawing. + # Both use 4 bytes for 16bit x and y pairs for start and end. + # The older follows this by a pattern selector and then line weight. + # Newer version has 6 bytes for 8bit RGB color... + + # Draw line + def handle_line(self, pdata): + decode_coords(pdata) + if self.cmdstate == 18: + self.es_cmd = self.es + self.putc([Ann.LINE, self.cmd_ann_list()]) + self.putc([Ann.WARN, ['Line pattern / Color not implemented']]) + self.state = None + self.cmdstate += 1 + + # Draw rectange + def handle_rect(self, pdata): + decode_coords(pdata) + if self.cmdstate == 18: + self.es_cmd = self.es + self.putc([Ann.RECT, self.cmd_ann_list()]) + self.putc([Ann.WARN, ['Line pattern / Color not implemented']]) + self.state = None + self.cmdstate += 1 + + # Draw filled rectangle + def handle_frect(self, pdata): + decode_coords(pdata) + if self.cmdstate == 18: + self.es_cmd = self.es + self.putc([Ann.FRECT, self.cmd_ann_list()]) + self.putc([Ann.WARN, ['Fill pattern / Color not implemented']]) + self.state = None + self.cmdstate += 1 + + # Draw pixel + def handle_pixel(self, pdata): + self.es_cmd = self.es + self.putc([Ann.WARN, ['Draw pixel documentation is missing.', 'Undocumented']]) + self.state = None + + # Replies + def handle_gbvr(self, pdata): + self.emit_add_bytes(pdata) + if self.cmdstate == 4: + self.ss_field = self.ss + self.value = int(chr(pdata), 16) << 4 + self.putx([Ann.BIT, ['High nibble 0x%s' % pdata, '0x%s' % pdata]]) + elif self.cmdstate == 5: + self.value += int(chr(pdata), 16) + self.putx([Ann.BIT, ['Low nibble 0x%s' % pdata, '0x%s' % pdata]]) + self.es_field = self.es + self.putf([Ann.FIELD, ['Value: 0x%02X' % self.value, + '0x%02X' % self.value]]) + self.emit_cmd_end([Ann.GBVR, self.cmd_ann_list()]) + self.cmdstate += 1 + + def handle_gwvr(self, pdata): + self.emit_add_bytes(pdata) + if self.cmdstate > 3: + nibble = self.cmdstate - 3 + if nibble == 0: + self.value = 0 + self.ss_field = self.ss + self.value += int(chr(pdata), 16) << 12 - (4 * nibble) + self.putx([Ann.BIT, ['0x%s' % pdata]]) + if nibble == 3: + self.putf([Ann.FIELD, ['Value: 0x%04x' % self.value, + '0x%04X' % self.value]]) + self.es_cmd = self.ss + self.emit_cmd_end([Ann.GWVR, self.cmd_ann_list()]) + self.cmdstate += 1 + + def handle_gsvr(self, pdata): + self.handle_string(pdata, Ann.GSVR) + + def handle_glvr(self, pdata): + self.handle_string(pdata, Ann.GLVR) + + def handle_grpcr(self, pdata): + self.handle_addr(pdata) + if self.cmdstate > 3: + nibble = (self.cmdstate - 3) % 2 + if nibble == 0: + if pdata == 0x00: + self.emit_cmd_end([Ann.GRPCR, self.cmd_ann_list()]) + return + self.value = int(chr(pdata), 16) << 4 + self.ss_field = self.ss + self.putx([Ann.BIT, ['0x%s' % pdata]]) + if nibble == 2: + self.value += int(chr(pdata), 16) + self.es_field = self.es + self.putx([Ann.BIT, ['0x%s' % pdata]]) + self.putf([Ann.FIELD, ['0x%02X' % self.value]]) + self.cmdstate += 1 + + def handle_sbvr(self, pdata): + self.handle_set_common(pdata) + if self.cmdstate == 4: + self.ss_field = self.ss + self.value = chr(pdata) + elif self.cmdstate == 5: + self.value += chr(pdata) + self.es_field = self.es + self.putf([Ann.FIELD, ['Value: 0x%s' % self.value, + 'Val: 0x%s' % self.value, '0x%s' % self.value]]) + self.emit_cmd_end([Ann.SBVR, self.cmd_ann_list()]) + self.cmdstate += 1 + + def handle_swvr(self, pdata): + self.handle_set_common(pdata) + if self.cmdstate == 4: + self.ss_field = self.ss + self.value = (pdata - 0x30) << 4 + elif self.cmdstate == 5: + self.value += (pdata - 0x30) + self.value = self.value << 8 + elif self.cmdstate == 6: + self.value += (pdata - 0x30) << 4 + elif self.cmdstate == 7: + self.value += (pdata - 0x30) + self.es_field = self.es + self.putf([Ann.FIELD, ['Value: 0x%04x' % self.value, + 'Val: 0x%04x' % self.value, '0x%04x' % self.value]]) + self.emit_cmd_end([Ann.SWVR, self.cmd_ann_list()]) + self.state = None + self.cmdstate += 1 + + def handle_ssvr(self, pdata): + self.handle_string(pdata, Ann.SSVR) + + def handle_rpcr(self, pdata): + self.handle_read(pdata) + self.emit_cmd_end([Ann.RPCR, self.cmd_ann_list()]) + + def handle_liner(self, pdata): + decode_coords(pdata) + if self.cmdstate == 18: + self.es_cmd = self.es + self.putc([Ann.LINER, self.cmd_ann_list()]) + self.putc([Ann.WARN, ['Line pattern / Color not implemented']]) + self.state = None + self.cmdstate += 1 + + def handle_rectr(self, pdata): + decode_coords(pdata) + if self.cmdstate == 18: + self.es_cmd = self.es + self.putc([Ann.RECTR, self.cmd_ann_list()]) + self.putc([Ann.WARN, ['Line pattern / Color not implemented']]) + self.state = None + self.cmdstate += 1 + + def handle_frectr(self, pdata): + decode_coords(pdata) + if self.cmdstate == 18: + self.es_cmd = self.es + self.putc([Ann.FRECTR, self.cmd_ann_list()]) + self.putc([Ann.WARN, ['Line pattern / Color not implemented']]) + self.state = None + self.cmdstate += 1 + + def handle_pixelr(self, pdata): + self.es_cmd = self.es + self.putc([Ann.WARN,['Draw pixel documentation is missing.', 'Undocumented']]) + self.state = None + + def handle_gbvar(self, pdata): + nibble = (self.cmdstate - 3) % 2 + if self.cmdstate == 2: + self.addr = int(chr(pdata), 16) << 4 + self.ss_field = self.ss + self.putx([Ann.BIT, ['Address high nibble: %c' % pdata, + 'Addr high 0x%c' % pdata, '0x%c' % pdata]]) + elif self.cmdstate == 3: + self.addr += int(chr(pdata), 16) + self.es_field = self.ss + self.putx([Ann.BIT, ['Address low nibble: %c' % pdata, + 'Addr low 0x%c' % pdata, '0x%c' % pdata]]) + self.putf([Ann.FIELD, ['Address: 0x%02X' % self.addr, + 'Addr: 0x%02X' % self.addr, '0x%02X' % self.addr]]) + elif stage == 2: + if pdata == 0x00: + # Null terminated list + self.emit_cmd_end([Ann.GBVAR, self.cmd_ann_list()]) + return + self.value = int(chr(pdata), 16) << 4 + else: + self.value += int(chr(pdata), 16) + self.es_field = self.es + self.putf([Ann.FIELD, ['Value 0x%02X' % self.value, + '0x%02X' % self.value]]) + self.cmdstate += 1 + + def handle_gwvar(self, pdata): + nibble = (self.cmdstate - 3) % 4 + if self.cmdstate == 2: + self.addr = int(chr(pdata), 16) << 4 + self.ss_field = self.ss + self.putx([Ann.BIT, ['Address high nibble: %c' % pdata, + 'Addr high 0x%c' % pdata, '0x%c' % pdata]]) + elif self.cmdstate == 3: + self.addr += int(chr(pdata), 16) + self.es_field = self.ss + self.putx([Ann.BIT, ['Address low nibble: %c' % pdata, + 'Addr low 0x%c' % pdata, '0x%c' % pdata]]) + self.putf([Ann.FIELD, ['Address: 0x%02X' % self.addr, + 'Addr: 0x%02X' % self.addr, '0x%02X' % self.addr]]) + self.value = 0 + else: + self.value += int(chr(pdata), 16) << 12 - (4 * nibble) + if nibble == 0: + if pdata == 0x00: + # Null terminated list + self.emit_cmd_end([Ann.GWVAR, self.cmd_ann_list()]) + return + self.ss_field = self.ss + if nibble == 3: + self.es_field = self.es + self.putf([Ann.FIELD, ['Value 0x%04X' % self.value, + '0x%04X' % self.value]]) + self.cmdstate += 1 + + # Get byte variable array reply + def handle_sbvar(self, pdata): + nibble = (self.cmdstate - 3) % 2 + if self.cmdstate == 2: + self.addr = int(chr(pdata), 16) << 4 + self.ss_field = self.ss + self.putx([Ann.BIT, ['Address high nibble: %c' % pdata, + 'Addr high 0x%c' % pdata, '0x%c' % pdata]]) + elif self.cmdstate == 3: + self.addr += int(chr(pdata), 16) + self.es_field = self.ss + self.putx([Ann.BIT, ['Address low nibble: %c' % pdata, + 'Addr low 0x%c' % pdata, '0x%c' % pdata]]) + self.putf([Ann.FIELD, ['Address: 0x%02X' % self.addr, + 'Addr: 0x%02X' % self.addr, '0x%02X' % self.addr]]) + elif stage == 2: + if pdata == 0x00: + # Null terminated list + self.emit_cmd_end([Ann.SBVAR, self.cmd_ann_list()]) + return + self.value = int(chr(pdata), 16) << 4 + else: + self.value += int(chr(pdata), 16) + self.es_field = self.es + self.putf([Ann.FIELD, ['Value 0x%02X' % self.value, + '0x%02X' % self.value]]) + self.cmdstate += 1 + + # Set word variable array reply + def handle_swvar(self, pdata): + nibble = (self.cmdstate - 3) % 4 + if self.cmdstate == 2: + self.addr = int(chr(pdata), 16) << 4 + self.ss_field = self.ss + self.putx([Ann.BIT, ['Address high nibble: %c' % pdata, + 'Addr high 0x%c' % pdata, '0x%c' % pdata]]) + elif self.cmdstate == 3: + self.addr += int(chr(pdata), 16) + self.es_field = self.ss + self.putx([Ann.BIT, ['Address low nibble: %c' % pdata, + 'Addr low 0x%c' % pdata, '0x%c' % pdata]]) + self.putf([Ann.FIELD, ['Address: 0x%02X' % self.addr, + 'Addr: 0x%02X' % self.addr, '0x%02X' % self.addr]]) + self.value = 0 + else: + self.value += int(chr(pdata), 16) << 12 - (4 * nibble) + if nibble == 0: + if pdata == 0x00: + # Null terminated list + self.emit_cmd_end([Ann.SWVAR, self.cmd_ann_list()]) + return + self.ss_field = self.ss + if nibble == 3: + self.es_field = self.es + self.putf([Ann.FIELD, ['Value 0x%04X' % self.value, + '0x%04X' % self.value]]) + self.cmdstate += 1 + + def handle_gcvr(self, pdata): + if self.cmdstate == 8: + self.emit_not_implemented([Ann.SCV, self.cmd_ann_list()]) + self.cmdstate += 1 + + def handle_scvr(self, pdata): + if self.cmdstate == 8: + self.emit_not_implemented([Ann.SCV, self.cmd_ann_list()]) + self.cmdstate += 1 + + # ACK & NACK + + def handle_ack(self, pdata): + self.putx([Ann.ACK, self.cmd_ann_list()]) + self.state = None + + def handle_nack(self, pdata): + self.putx([Ann.NACK, self.cmd_ann_list()]) + self.state = None + + def decode(self, ss, es, data): + ptype, rxtx, pdata = data + + self.ss, self.es = ss, es + + if ptype != 'DATA': + return + + # Handle commands. + try: + abort_current = (0xD0 <= pdata[0] <= 0xF7) and \ + (not (self.state in cmds_with_high_bytes)) and \ + self.state != None + if abort_current: + self.putx([Ann.WARN, ['Command aborted by invalid byte', 'Abort']]) + self.state = pdata[0] + self.emit_cmd_byte() + self.cmdstate = 1 + if self.state is None: + self.state = pdata[0] + self.emit_cmd_byte() + self.cmdstate = 1 + self.cmd_handlers[self.state](pdata[0]) + except KeyError: + self.putx([Ann.WARN, ['Unknown command: 0x%02x' % pdata[0]]]) + self.state = None diff --git a/libsigrokdecode4DSL/decoders/arm_etmv3/__init__.py b/libsigrokdecode4DSL/decoders/arm_etmv3/__init__.py new file mode 100644 index 00000000..617063ca --- /dev/null +++ b/libsigrokdecode4DSL/decoders/arm_etmv3/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Petteri Aimonen +## +## 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, see . +## + +''' +This decoder stacks on top of the 'uart' PD and decodes packets of +the ARMv7m Embedded Trace Macroblock v3.x. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/arm_etmv3/pd.py b/libsigrokdecode4DSL/decoders/arm_etmv3/pd.py new file mode 100644 index 00000000..6649b46e --- /dev/null +++ b/libsigrokdecode4DSL/decoders/arm_etmv3/pd.py @@ -0,0 +1,567 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Petteri Aimonen +## +## 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, see . +## + +import sigrokdecode as srd +import subprocess +import re + +# See ETMv3 Signal Protocol table 7-11: 'Encoding of Exception[8:0]'. +exc_names = [ + 'No exception', 'IRQ1', 'IRQ2', 'IRQ3', 'IRQ4', 'IRQ5', 'IRQ6', 'IRQ7', + 'IRQ0', 'UsageFault', 'NMI', 'SVC', 'DebugMon', 'MemManage', 'PendSV', + 'SysTick', 'Reserved', 'Reset', 'BusFault', 'Reserved', 'Reserved' +] + +for i in range(8, 496): + exc_names.append('IRQ%d' % i) + +def parse_varint(bytes_): + '''Parse an integer where the top bit is the continuation bit. + Returns value and number of parsed bytes.''' + v = 0 + for i, b in enumerate(bytes_): + v |= (b & 0x7F) << (i * 7) + if b & 0x80 == 0: + return v, i+1 + return v, len(bytes_) + +def parse_uint(bytes_): + '''Parse little-endian integer.''' + v = 0 + for i, b in enumerate(bytes_): + v |= b << (i * 8) + return v + +def parse_exc_info(bytes_): + '''Parse exception information bytes from a branch packet.''' + if len(bytes_) < 1: + return None + + excv, exclen = parse_varint(bytes_) + if bytes_[exclen - 1] & 0x80 != 0x00: + return None # Exception info not complete. + + if exclen == 2 and excv & (1 << 13): + # Exception byte 1 was skipped, fix up the decoding. + excv = (excv & 0x7F) | ((excv & 0x3F80) << 7) + + ns = excv & 1 + exc = ((excv >> 1) & 0x0F) | ((excv >> 7) & 0x1F0) + cancel = (excv >> 5) & 1 + altisa = (excv >> 6) & 1 + hyp = (excv >> 12) & 1 + resume = (excv >> 14) & 0x0F + return (ns, exc, cancel, altisa, hyp, resume) + +def parse_branch_addr(bytes_, ref_addr, cpu_state, branch_enc): + '''Parse encoded branch address. + Returns addr, addrlen, cpu_state, exc_info. + Returns None if packet is not yet complete''' + + addr, addrlen = parse_varint(bytes_) + + if bytes_[addrlen - 1] & 0x80 != 0x00: + return None # Branch address not complete. + + addr_bits = 7 * addrlen + + have_exc_info = False + if branch_enc == 'original': + if addrlen == 5 and bytes_[4] & 0x40: + have_exc_info = True + elif branch_enc == 'alternative': + addr_bits -= 1 # Top bit of address indicates exc_info. + if addrlen >= 2 and addr & (1 << addr_bits): + have_exc_info = True + addr &= ~(1 << addr_bits) + + exc_info = None + if have_exc_info: + exc_info = parse_exc_info(bytes_[addrlen:]) + if exc_info is None: + return None # Exception info not complete. + + if addrlen == 5: + # Possible change in CPU state. + if bytes_[4] & 0xB8 == 0x08: + cpu_state = 'arm' + elif bytes_[4] & 0xB0 == 0x10: + cpu_state = 'thumb' + elif bytes_[4] & 0xA0 == 0x20: + cpu_state = 'jazelle' + else: + raise NotImplementedError('Unhandled branch byte 4: 0x%02x' % bytes_[4]) + + # Shift the address according to current CPU state. + if cpu_state == 'arm': + addr = (addr & 0xFFFFFFFE) << 1 + addr_bits += 1 + elif cpu_state == 'thumb': + addr = addr & 0xFFFFFFFE + elif cpu_state == 'jazelle': + addr = (addr & 0xFFFFFFFFE) >> 1 + addr_bits -= 1 + else: + raise NotImplementedError('Unhandled state: ' + cpu_state) + + # If the address wasn't full, fill in with the previous address. + if addrlen < 5: + addr |= ref_addr & (0xFFFFFFFF << addr_bits) + + return addr, addrlen, cpu_state, exc_info + +class Decoder(srd.Decoder): + api_version = 3 + id = 'arm_etmv3' + name = 'ARM ETMv3' + longname = 'ARM Embedded Trace Macroblock v3' + desc = 'ARM ETM v3 instruction trace protocol.' + license = 'gplv2+' + inputs = ['uart'] + outputs = [] + tags = ['Debug/trace'] + annotations = ( + ('trace', 'Trace info'), + ('branch', 'Branches'), + ('exception', 'Exceptions'), + ('execution', 'Instruction execution'), + ('data', 'Data access'), + ('pc', 'Program counter'), + ('instr_e', 'Executed instructions'), + ('instr_n', 'Not executed instructions'), + ('source', 'Source code'), + ('location', 'Current location'), + ('function', 'Current function'), + ) + annotation_rows = ( + ('trace', 'Trace info', (0,)), + ('flow', 'Code flow', (1, 2, 3,)), + ('data', 'Data access', (4,)), + ('pc', 'Program counter', (5,)), + ('instruction', 'Instructions', (6, 7,)), + ('source', 'Source code', (8,)), + ('location', 'Current location', (9,)), + ('function', 'Current function', (10,)), + ) + options = ( + {'id': 'objdump', 'desc': 'objdump path', + 'default': 'arm-none-eabi-objdump'}, + {'id': 'objdump_opts', 'desc': 'objdump options', + 'default': '-lSC'}, + {'id': 'elffile', 'desc': '.elf path', + 'default': ''}, + {'id': 'branch_enc', 'desc': 'Branch encoding', + 'default': 'alternative', 'values': ('alternative', 'original')}, + ) + + def __init__(self): + self.reset() + + def reset(self): + self.buf = [] + self.syncbuf = [] + self.prevsample = 0 + self.last_branch = 0 + self.cpu_state = 'arm' + self.current_pc = 0 + self.current_loc = None + self.current_func = None + self.next_instr_lookup = {} + self.file_lookup = {} + self.func_lookup = {} + self.disasm_lookup = {} + self.source_lookup = {} + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.load_objdump() + + def load_objdump(self): + '''Parse disassembly obtained from objdump into two tables: + next_instr_lookup: Find the next PC addr from current PC. + disasm_lookup: Find the instruction text from current PC. + source_lookup: Find the source code line from current PC. + ''' + if not (self.options['objdump'] and self.options['elffile']): + return + + opts = [self.options['objdump']] + opts += self.options['objdump_opts'].split() + opts += [self.options['elffile']] + + try: + disasm = subprocess.check_output(opts) + except subprocess.CalledProcessError: + return + + disasm = disasm.decode('utf-8', 'replace') + + instpat = re.compile('\s*([0-9a-fA-F]+):\t+([0-9a-fA-F ]+)\t+([a-zA-Z][^;]+)\s*;?.*') + branchpat = re.compile('(b|bl|b..|bl..|cbnz|cbz)(?:\.[wn])?\s+(?:r[0-9]+,\s*)?([0-9a-fA-F]+)') + filepat = re.compile('[^\s]+[/\\\\]([a-zA-Z0-9._-]+:[0-9]+)(?:\s.*)?') + funcpat = re.compile('[0-9a-fA-F]+\s*<([^>]+)>:.*') + + prev_src = '' + prev_file = '' + prev_func = '' + + for line in disasm.split('\n'): + m = instpat.match(line) + if m: + addr = int(m.group(1), 16) + raw = m.group(2) + disas = m.group(3).strip().replace('\t', ' ') + self.disasm_lookup[addr] = disas + self.source_lookup[addr] = prev_src + self.file_lookup[addr] = prev_file + self.func_lookup[addr] = prev_func + + # Next address in direct sequence. + ilen = len(raw.replace(' ', '')) // 2 + next_n = addr + ilen + + # Next address if branch is taken. + bm = branchpat.match(disas) + if bm: + next_e = int(bm.group(2), 16) + else: + next_e = next_n + + self.next_instr_lookup[addr] = (next_n, next_e) + else: + m = funcpat.match(line) + if m: + prev_func = m.group(1) + prev_src = None + else: + m = filepat.match(line) + if m: + prev_file = m.group(1) + prev_src = None + else: + prev_src = line.strip() + + def flush_current_loc(self): + if self.current_loc is not None: + ss, es, loc, src = self.current_loc + if loc: + self.put(ss, es, self.out_ann, [9, [loc]]) + if src: + self.put(ss, es, self.out_ann, [8, [src]]) + self.current_loc = None + + def flush_current_func(self): + if self.current_func is not None: + ss, es, func = self.current_func + if func: + self.put(ss, es, self.out_ann, [10, [func]]) + self.current_func = None + + def instructions_executed(self, exec_status): + '''Advance program counter based on executed instructions. + Argument is a list of False for not executed and True for executed + instructions. + ''' + + if len(exec_status) == 0: + return + + tdelta = max(1, (self.prevsample - self.startsample) / len(exec_status)) + + for i, exec_status in enumerate(exec_status): + pc = self.current_pc + default_next = pc + 2 if self.cpu_state == 'thumb' else pc + 4 + target_n, target_e = self.next_instr_lookup.get(pc, (default_next, default_next)) + ss = self.startsample + round(tdelta * i) + es = self.startsample + round(tdelta * (i+1)) + + self.put(ss, es, self.out_ann, + [5, ['PC 0x%08x' % pc, '0x%08x' % pc, '%08x' % pc]]) + + new_loc = self.file_lookup.get(pc) + new_src = self.source_lookup.get(pc) + new_dis = self.disasm_lookup.get(pc) + new_func = self.func_lookup.get(pc) + + # Report source line only when it changes. + if self.current_loc is not None: + if new_loc != self.current_loc[2] or new_src != self.current_loc[3]: + self.flush_current_loc() + + if self.current_loc is None: + self.current_loc = [ss, es, new_loc, new_src] + else: + self.current_loc[1] = es + + # Report function name only when it changes. + if self.current_func is not None: + if new_func != self.current_func[2]: + self.flush_current_func() + + if self.current_func is None: + self.current_func = [ss, es, new_func] + else: + self.current_func[1] = es + + # Report instruction every time. + if new_dis: + if exec_status: + a = [6, ['Executed: ' + new_dis, new_dis, new_dis.split()[0]]] + else: + a = [7, ['Not executed: ' + new_dis, new_dis, new_dis.split()[0]]] + self.put(ss, es, self.out_ann, a) + + if exec_status: + self.current_pc = target_e + else: + self.current_pc = target_n + + def get_packet_type(self, byte): + '''Identify packet type based on its first byte. + See ARM IHI0014Q section "ETMv3 Signal Protocol" "Packet Types" + ''' + if byte & 0x01 == 0x01: + return 'branch' + elif byte == 0x00: + return 'a_sync' + elif byte == 0x04: + return 'cyclecount' + elif byte == 0x08: + return 'i_sync' + elif byte == 0x0C: + return 'trigger' + elif byte & 0xF3 in (0x20, 0x40, 0x60): + return 'ooo_data' + elif byte == 0x50: + return 'store_failed' + elif byte == 0x70: + return 'i_sync' + elif byte & 0xDF in (0x54, 0x58, 0x5C): + return 'ooo_place' + elif byte == 0x3C: + return 'vmid' + elif byte & 0xD3 == 0x02: + return 'data' + elif byte & 0xFB == 0x42: + return 'timestamp' + elif byte == 0x62: + return 'data_suppressed' + elif byte == 0x66: + return 'ignore' + elif byte & 0xEF == 0x6A: + return 'value_not_traced' + elif byte == 0x6E: + return 'context_id' + elif byte == 0x76: + return 'exception_exit' + elif byte == 0x7E: + return 'exception_entry' + elif byte & 0x81 == 0x80: + return 'p_header' + else: + return 'unknown' + + def fallback(self, buf): + ptype = self.get_packet_type(buf[0]) + return [0, ['Unhandled ' + ptype + ': ' + ' '.join(['%02x' % b for b in buf])]] + + def handle_a_sync(self, buf): + if buf[-1] == 0x80: + return [0, ['Synchronization']] + + def handle_exception_exit(self, buf): + return [2, ['Exception exit']] + + def handle_exception_entry(self, buf): + return [2, ['Exception entry']] + + def handle_i_sync(self, buf): + contextid_bytes = 0 # This is the default ETM config. + + if len(buf) < 6: + return None # Packet definitely not full yet. + + if buf[0] == 0x08: # No cycle count. + cyclecount = None + idx = 1 + contextid_bytes # Index to info byte. + elif buf[0] == 0x70: # With cycle count. + cyclecount, cyclen = parse_varint(buf[1:6]) + idx = 1 + cyclen + contextid_bytes + + if len(buf) <= idx + 4: + return None + infobyte = buf[idx] + addr = parse_uint(buf[idx+1:idx+5]) + + reasoncode = (infobyte >> 5) & 3 + reason = ('Periodic', 'Tracing enabled', 'After overflow', 'Exit from debug')[reasoncode] + jazelle = (infobyte >> 4) & 1 + nonsec = (infobyte >> 3) & 1 + altisa = (infobyte >> 2) & 1 + hypervisor = (infobyte >> 1) & 1 + thumb = addr & 1 + addr &= 0xFFFFFFFE + + if reasoncode == 0 and self.current_pc != addr: + self.put(self.startsample, self.prevsample, self.out_ann, + [0, ['WARN: Unexpected PC change 0x%08x -> 0x%08x' % \ + (self.current_pc, addr)]]) + elif reasoncode != 0: + # Reset location when the trace has been interrupted. + self.flush_current_loc() + self.flush_current_func() + + self.last_branch = addr + self.current_pc = addr + + if jazelle: + self.cpu_state = 'jazelle' + elif thumb: + self.cpu_state = 'thumb' + else: + self.cpu_state = 'arm' + + cycstr = '' + if cyclecount is not None: + cycstr = ', cyclecount %d' % cyclecount + + if infobyte & 0x80: # LSIP packet + self.put(self.startsample, self.prevsample, self.out_ann, + [0, ['WARN: LSIP I-Sync packet not implemented']]) + + return [0, ['I-Sync: %s, PC 0x%08x, %s state%s' % \ + (reason, addr, self.cpu_state, cycstr), \ + 'I-Sync: %s 0x%08x' % (reason, addr)]] + + def handle_trigger(self, buf): + return [0, ['Trigger event', 'Trigger']] + + def handle_p_header(self, buf): + # Only non cycle-accurate mode supported. + if buf[0] & 0x83 == 0x80: + n = (buf[0] >> 6) & 1 + e = (buf[0] >> 2) & 15 + + self.instructions_executed([1] * e + [0] * n) + + if n: + return [3, ['%d instructions executed, %d skipped due to ' \ + 'condition codes' % (e, n), + '%d ins exec, %d skipped' % (e, n), + '%dE,%dN' % (e, n)]] + else: + return [3, ['%d instructions executed' % e, + '%d ins exec' % e, '%dE' % e]] + elif buf[0] & 0xF3 == 0x82: + i1 = (buf[0] >> 3) & 1 + i2 = (buf[0] >> 2) & 1 + self.instructions_executed([not i1, not i2]) + txt1 = ('executed', 'skipped') + txt2 = ('E', 'S') + return [3, ['Instruction 1 %s, instruction 2 %s' % (txt1[i1], txt1[i2]), + 'I1 %s, I2 %s' % (txt2[i1], txt2[i2]), + '%s,%s' % (txt2[i1], txt2[i2])]] + else: + return self.fallback(buf) + + def handle_branch(self, buf): + if buf[-1] & 0x80 != 0x00: + return None # Not complete yet. + + brinfo = parse_branch_addr(buf, self.last_branch, self.cpu_state, + self.options['branch_enc']) + + if brinfo is None: + return None # Not complete yet. + + addr, addrlen, cpu_state, exc_info = brinfo + self.last_branch = addr + self.current_pc = addr + + txt = '' + + if cpu_state != self.cpu_state: + txt += ', to %s state' % cpu_state + self.cpu_state = cpu_state + + annidx = 1 + + if exc_info: + annidx = 2 + ns, exc, cancel, altisa, hyp, resume = exc_info + if ns: + txt += ', to non-secure state' + if exc: + if exc < len(exc_names): + txt += ', exception %s' % exc_names[exc] + else: + txt += ', exception 0x%02x' % exc + if cancel: + txt += ', instr cancelled' + if altisa: + txt += ', to AltISA' + if hyp: + txt += ', to hypervisor' + if resume: + txt += ', instr resume 0x%02x' % resume + + return [annidx, ['Branch to 0x%08x%s' % (addr, txt), + 'B 0x%08x%s' % (addr, txt)]] + + def decode(self, ss, es, data): + ptype, rxtx, pdata = data + + if ptype != 'DATA': + return + + # Reset packet if there is a long pause between bytes. + # This helps getting the initial synchronization. + self.byte_len = es - ss + if ss - self.prevsample > 16 * self.byte_len: + self.flush_current_loc() + self.flush_current_func() + self.buf = [] + self.prevsample = es + + self.buf.append(pdata[0]) + + # Store the start time of the packet. + if len(self.buf) == 1: + self.startsample = ss + + # Keep separate buffer for detection of sync packets. + # Sync packets override everything else, so that we can regain sync + # even if some packets are corrupted. + self.syncbuf = self.syncbuf[-4:] + [pdata[0]] + if self.syncbuf == [0x00, 0x00, 0x00, 0x00, 0x80]: + self.buf = self.syncbuf + self.syncbuf = [] + + # See if it is ready to be decoded. + ptype = self.get_packet_type(self.buf[0]) + if hasattr(self, 'handle_' + ptype): + func = getattr(self, 'handle_' + ptype) + data = func(self.buf) + else: + data = self.fallback(self.buf) + + if data is not None: + if data: + self.put(self.startsample, es, self.out_ann, data) + self.buf = [] diff --git a/libsigrokdecode4DSL/decoders/arm_itm/__init__.py b/libsigrokdecode4DSL/decoders/arm_itm/__init__.py new file mode 100644 index 00000000..1733d36d --- /dev/null +++ b/libsigrokdecode4DSL/decoders/arm_itm/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Petteri Aimonen +## +## 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, see . +## + +''' +This decoder stacks on top of the 'uart' or 'arm_tpiu' PD and decodes the +ARM Cortex-M processor trace data from Instrumentation Trace Macroblock. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/arm_itm/pd.py b/libsigrokdecode4DSL/decoders/arm_itm/pd.py new file mode 100644 index 00000000..64149787 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/arm_itm/pd.py @@ -0,0 +1,373 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Petteri Aimonen +## +## 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, see . +## + +import sigrokdecode as srd +import string +import subprocess +import re + +ARM_EXCEPTIONS = { + 0: 'Thread', + 1: 'Reset', + 2: 'NMI', + 3: 'HardFault', + 4: 'MemManage', + 5: 'BusFault', + 6: 'UsageFault', + 11: 'SVCall', + 12: 'Debug Monitor', + 14: 'PendSV', + 15: 'SysTick', +} + +class Decoder(srd.Decoder): + api_version = 3 + id = 'arm_itm' + name = 'ARM ITM' + longname = 'ARM Instrumentation Trace Macroblock' + desc = 'ARM Cortex-M / ARMv7m ITM trace protocol.' + license = 'gplv2+' + inputs = ['uart'] + outputs = [] + tags = ['Debug/trace'] + options = ( + {'id': 'objdump', 'desc': 'objdump path', + 'default': 'arm-none-eabi-objdump'}, + {'id': 'objdump_opts', 'desc': 'objdump options', + 'default': '-lSC'}, + {'id': 'elffile', 'desc': '.elf path', + 'default': ''}, + ) + annotations = ( + ('trace', 'Trace information'), + ('timestamp', 'Timestamp'), + ('software', 'Software message'), + ('dwt_event', 'DWT event'), + ('dwt_watchpoint', 'DWT watchpoint'), + ('dwt_exc', 'Exception trace'), + ('dwt_pc', 'Program counter'), + ('mode_thread', 'Current mode: thread'), + ('mode_irq', 'Current mode: IRQ'), + ('mode_exc', 'Current mode: Exception'), + ('location', 'Current location'), + ('function', 'Current function'), + ) + annotation_rows = ( + ('trace', 'Trace information', (0, 1)), + ('software', 'Software trace', (2,)), + ('dwt_event', 'DWT event', (3,)), + ('dwt_watchpoint', 'DWT watchpoint', (4,)), + ('dwt_exc', 'Exception trace', (5,)), + ('dwt_pc', 'Program counter', (6,)), + ('mode', 'Current mode', (7, 8, 9)), + ('location', 'Current location', (10,)), + ('function', 'Current function', (11,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.buf = [] + self.syncbuf = [] + self.swpackets = {} + self.prevsample = 0 + self.dwt_timestamp = 0 + self.current_mode = None + self.file_lookup = {} + self.func_lookup = {} + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.load_objdump() + + def load_objdump(self): + '''Parse disassembly obtained from objdump into a lookup tables''' + if not (self.options['objdump'] and self.options['elffile']): + return + + opts = [self.options['objdump']] + opts += self.options['objdump_opts'].split() + opts += [self.options['elffile']] + + try: + disasm = subprocess.check_output(opts) + except subprocess.CalledProcessError: + return + + disasm = disasm.decode('utf-8', 'replace') + + instpat = re.compile('\s*([0-9a-fA-F]+):\t+([0-9a-fA-F ]+)\t+([a-zA-Z][^;]+)\s*;?.*') + filepat = re.compile('[^\s]+[/\\\\]([a-zA-Z0-9._-]+:[0-9]+)(?:\s.*)?') + funcpat = re.compile('[0-9a-fA-F]+\s*<([^>]+)>:.*') + + prev_file = '' + prev_func = '' + + for line in disasm.split('\n'): + m = instpat.match(line) + if m: + addr = int(m.group(1), 16) + self.file_lookup[addr] = prev_file + self.func_lookup[addr] = prev_func + else: + m = funcpat.match(line) + if m: + prev_func = m.group(1) + else: + m = filepat.match(line) + if m: + prev_file = m.group(1) + + def get_packet_type(self, byte): + '''Identify packet type based on its first byte. + See ARMv7-M_ARM.pdf section "Debug ITM and DWT" "Packet Types" + ''' + if byte & 0x7F == 0: + return 'sync' + elif byte == 0x70: + return 'overflow' + elif byte & 0x0F == 0 and byte & 0xF0 != 0: + return 'timestamp' + elif byte & 0x0F == 0x08: + return 'sw_extension' + elif byte & 0x0F == 0x0C: + return 'hw_extension' + elif byte & 0x0F == 0x04: + return 'reserved' + elif byte & 0x04 == 0x00: + return 'software' + else: + return 'hardware' + + def mode_change(self, new_mode): + if self.current_mode is not None: + start, mode = self.current_mode + if mode.startswith('Thread'): + ann_idx = 7 + elif mode.startswith('IRQ'): + ann_idx = 8 + else: + ann_idx = 9 + self.put(start, self.startsample, self.out_ann, [ann_idx, [mode]]) + + if new_mode is None: + self.current_mode = None + else: + self.current_mode = (self.startsample, new_mode) + + def location_change(self, pc): + new_loc = self.file_lookup.get(pc) + new_func = self.func_lookup.get(pc) + ss = self.startsample + es = self.prevsample + + if new_loc is not None: + self.put(ss, es, self.out_ann, [10, [new_loc]]) + + if new_func is not None: + self.put(ss, es, self.out_ann, [11, [new_func]]) + + def fallback(self, buf): + ptype = self.get_packet_type(buf[0]) + return [0, [('Unhandled %s: ' % ptype) + ' '.join(['%02x' % b for b in buf])]] + + def handle_overflow(self, buf): + return [0, ['Overflow']] + + def handle_hardware(self, buf): + '''Handle packets from hardware source, i.e. DWT block.''' + plen = (0, 1, 2, 4)[buf[0] & 0x03] + pid = buf[0] >> 3 + if len(buf) != plen + 1: + return None # Not complete yet. + + if pid == 0: + text = 'DWT events:' + if buf[1] & 0x20: + text += ' Cyc' + if buf[1] & 0x10: + text += ' Fold' + if buf[1] & 0x08: + text += ' LSU' + if buf[1] & 0x04: + text += ' Sleep' + if buf[1] & 0x02: + text += ' Exc' + if buf[1] & 0x01: + text += ' CPI' + return [3, [text]] + elif pid == 1: + excnum = ((buf[2] & 1) << 8) | buf[1] + event = (buf[2] >> 4) + excstr = ARM_EXCEPTIONS.get(excnum, 'IRQ %d' % (excnum - 16)) + if event == 1: + self.mode_change(excstr) + return [5, ['Enter: ' + excstr, 'E ' + excstr]] + elif event == 2: + self.mode_change(None) + return [5, ['Exit: ' + excstr, 'X ' + excstr]] + elif event == 3: + self.mode_change(excstr) + return [5, ['Resume: ' + excstr, 'R ' + excstr]] + elif pid == 2: + pc = buf[1] | (buf[2] << 8) | (buf[3] << 16) | (buf[4] << 24) + self.location_change(pc) + return [6, ['PC: 0x%08x' % pc]] + elif (buf[0] & 0xC4) == 0x84: + comp = (buf[0] & 0x30) >> 4 + what = 'Read' if (buf[0] & 0x08) == 0 else 'Write' + if plen == 1: + data = '0x%02x' % (buf[1]) + elif plen == 2: + data = '0x%04x' % (buf[1] | (buf[2] << 8)) + else: + data = '0x%08x' % (buf[1] | (buf[2] << 8) | (buf[3] << 16) | (buf[4] << 24)) + return [4, ['Watchpoint %d: %s data %s' % (comp, what, data), + 'WP%d: %s %s' % (comp, what[0], data)]] + elif (buf[0] & 0xCF) == 0x47: + comp = (buf[0] & 0x30) >> 4 + addr = buf[1] | (buf[2] << 8) | (buf[3] << 16) | (buf[4] << 24) + self.location_change(addr) + return [4, ['Watchpoint %d: PC 0x%08x' % (comp, addr), + 'WP%d: PC 0x%08x' % (comp, addr)]] + elif (buf[0] & 0xCF) == 0x4E: + comp = (buf[0] & 0x30) >> 4 + offset = buf[1] | (buf[2] << 8) + return [4, ['Watchpoint %d: address 0x????%04x' % (comp, offset), + 'WP%d: A 0x%04x' % (comp, offset)]] + + return self.fallback(buf) + + def handle_software(self, buf): + '''Handle packets generated by software running on the CPU.''' + plen = (0, 1, 2, 4)[buf[0] & 0x03] + pid = buf[0] >> 3 + if len(buf) != plen + 1: + return None # Not complete yet. + + if plen == 1 and chr(buf[1]) in string.printable: + self.add_delayed_sw(pid, chr(buf[1])) + return [] # Handled but no data to output. + + self.push_delayed_sw() + + if plen == 1: + return [2, ['%d: 0x%02x' % (pid, buf[1])]] + elif plen == 2: + return [2, ['%d: 0x%02x%02x' % (pid, buf[2], buf[1])]] + elif plen == 4: + return [2, ['%d: 0x%02x%02x%02x%02x' % (pid, buf[4], buf[3], buf[2], buf[1])]] + + def handle_timestamp(self, buf): + '''Handle timestamp packets, which indicate the time of some DWT event packet.''' + if buf[-1] & 0x80 != 0: + return None # Not complete yet. + + if buf[0] & 0x80 == 0: + tc = 0 + ts = buf[0] >> 4 + else: + tc = (buf[0] & 0x30) >> 4 + ts = buf[1] & 0x7F + if len(buf) > 2: + ts |= (buf[2] & 0x7F) << 7 + if len(buf) > 3: + ts |= (buf[3] & 0x7F) << 14 + if len(buf) > 4: + ts |= (buf[4] & 0x7F) << 21 + + self.dwt_timestamp += ts + + if tc == 0: + msg = '(exact)' + elif tc == 1: + msg = '(timestamp delayed)' + elif tc == 2: + msg = '(event delayed)' + elif tc == 3: + msg = '(event and timestamp delayed)' + + return [1, ['Timestamp: %d %s' % (self.dwt_timestamp, msg)]] + + def add_delayed_sw(self, pid, c): + '''We join printable characters from software source so that printed + strings are easy to read. Joining is done by PID so that different + sources do not get confused with each other.''' + if self.swpackets.get(pid) is not None: + self.swpackets[pid][1] = self.prevsample + self.swpackets[pid][2] += c + else: + self.swpackets[pid] = [self.startsample, self.prevsample, c] + + def push_delayed_sw(self): + for pid, packet in self.swpackets.items(): + if packet is None: + continue + ss, prevtime, text = packet + # Heuristic criterion: Text has ended if at least 16 byte + # durations after previous received byte. Actual delay depends + # on printf implementation on target. + if self.prevsample - prevtime > 16 * self.byte_len: + self.put(ss, prevtime, self.out_ann, [2, ['%d: "%s"' % (pid, text)]]) + self.swpackets[pid] = None + + def decode(self, ss, es, data): + ptype, rxtx, pdata = data + + # For now, ignore all UART packets except the actual data packets. + if ptype != 'DATA': + return + + self.byte_len = es - ss + + # Reset packet if there is a long pause between bytes. + # TPIU framing can introduce small pauses, but more than 1 frame + # should reset packet. + if ss - self.prevsample > 16 * self.byte_len: + self.push_delayed_sw() + self.buf = [] + self.prevsample = es + + # Build up the current packet byte by byte. + self.buf.append(pdata[0]) + + # Store the start time of the packet. + if len(self.buf) == 1: + self.startsample = ss + + # Keep separate buffer for detection of sync packets. + # Sync packets override everything else, so that we can regain sync + # even if some packets are corrupted. + self.syncbuf = self.syncbuf[-5:] + [pdata[0]] + if self.syncbuf == [0, 0, 0, 0, 0, 0x80]: + self.buf = self.syncbuf + + # See if it is ready to be decoded. + ptype = self.get_packet_type(self.buf[0]) + if hasattr(self, 'handle_' + ptype): + func = getattr(self, 'handle_' + ptype) + data = func(self.buf) + else: + data = self.fallback(self.buf) + + if data is not None: + if data: + self.put(self.startsample, es, self.out_ann, data) + self.buf = [] diff --git a/libsigrokdecode4DSL/decoders/arm_tpiu/__init__.py b/libsigrokdecode4DSL/decoders/arm_tpiu/__init__.py new file mode 100644 index 00000000..ce9c3744 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/arm_tpiu/__init__.py @@ -0,0 +1,28 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Petteri Aimonen +## +## 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, see . +## + +''' +This decoder stacks on top of the 'uart' PD and decodes the frame format +of ARMv7m Trace Port Interface Unit. + +It filters the data coming from various trace sources (such as ARMv7m ITM +and ETM blocks) into separate streams that can be further decoded by other PDs. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/arm_tpiu/pd.py b/libsigrokdecode4DSL/decoders/arm_tpiu/pd.py new file mode 100644 index 00000000..29b4605f --- /dev/null +++ b/libsigrokdecode4DSL/decoders/arm_tpiu/pd.py @@ -0,0 +1,131 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Petteri Aimonen +## +## 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, see . +## + +import sigrokdecode as srd + +class Decoder(srd.Decoder): + api_version = 3 + id = 'arm_tpiu' + name = 'ARM TPIU' + longname = 'ARM Trace Port Interface Unit' + desc = 'Filter TPIU formatted trace data into separate streams.' + license = 'gplv2+' + inputs = ['uart'] + outputs = ['uart'] # Emulate uart output so that arm_itm/arm_etm can stack. + tags = ['Debug/trace'] + options = ( + {'id': 'stream', 'desc': 'Stream index', 'default': 1}, + {'id': 'sync_offset', 'desc': 'Initial sync offset', 'default': 0}, + ) + annotations = ( + ('stream', 'Current stream'), + ('data', 'Stream data'), + ) + annotation_rows = ( + ('stream', 'Current stream', (0,)), + ('data', 'Stream data', (1,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.buf = [] + self.syncbuf = [] + self.prevsample = 0 + self.stream = 0 + self.ss_stream = None + self.bytenum = 0 + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_python = self.register(srd.OUTPUT_PYTHON) + + def stream_changed(self, ss, stream): + if self.stream != stream: + if self.stream != 0: + self.put(self.ss_stream, ss, self.out_ann, + [0, ['Stream %d' % self.stream, 'S%d' % self.stream]]) + self.stream = stream + self.ss_stream = ss + + def emit_byte(self, ss, es, byte): + if self.stream == self.options['stream']: + self.put(ss, es, self.out_ann, [1, ['0x%02x' % byte]]) + self.put(ss, es, self.out_python, ['DATA', 0, (byte, [])]) + + def process_frame(self, buf): + # Byte 15 contains the lowest bits of bytes 0, 2, ... 14. + lowbits = buf[15][2] + + for i in range(0, 15, 2): + # Odd bytes can be stream ID or data. + delayed_stream_change = None + lowbit = (lowbits >> (i // 2)) & 0x01 + if buf[i][2] & 0x01 != 0: + if lowbit: + delayed_stream_change = buf[i][2] >> 1 + else: + self.stream_changed(buf[i][0], buf[i][2] >> 1) + else: + byte = buf[i][2] | lowbit + self.emit_byte(buf[i][0], buf[i][1], byte) + + # Even bytes are always data. + if i < 14: + self.emit_byte(buf[i+1][0], buf[i+1][1], buf[i+1][2]) + + # The stream change can be delayed to occur after the data byte. + if delayed_stream_change is not None: + self.stream_changed(buf[i+1][1], delayed_stream_change) + + def decode(self, ss, es, data): + ptype, rxtx, pdata = data + + if ptype != 'DATA': + return + + # Reset packet if there is a long pause between bytes. + self.byte_len = es - ss + if ss - self.prevsample > self.byte_len: + self.buf = [] + self.prevsample = es + + self.buf.append((ss, es, pdata[0])) + self.bytenum += 1 + + # Allow skipping N first bytes of the data. By adjusting the sync + # value, one can get initial synchronization as soon as the trace + # starts. + if self.bytenum < self.options['sync_offset']: + self.buf = [] + return + + # Keep separate buffer for detection of sync packets. + # Sync packets override everything else, so that we can regain sync + # even if some packets are corrupted. + self.syncbuf = self.syncbuf[-3:] + [pdata[0]] + if self.syncbuf == [0xFF, 0xFF, 0xFF, 0x7F]: + self.buf = [] + self.syncbuf = [] + return + + if len(self.buf) == 16: + self.process_frame(self.buf) + self.buf = [] diff --git a/libsigrokdecode4DSL/decoders/atsha204a/__init__.py b/libsigrokdecode4DSL/decoders/atsha204a/__init__.py new file mode 100644 index 00000000..fd0f4288 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/atsha204a/__init__.py @@ -0,0 +1,30 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Michalis Pappas +## +## 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, see . +## + +''' +This decoder stacks on top of the 'i2c' PD and decodes the +Microchip ATSHA204A and ATECC508A crypto authentication protocol. + +The decoder might also support the following devices (untested): + * ATSHA204 + * ATECC108 + * ATECC108A +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/atsha204a/pd.py b/libsigrokdecode4DSL/decoders/atsha204a/pd.py new file mode 100644 index 00000000..c666332a --- /dev/null +++ b/libsigrokdecode4DSL/decoders/atsha204a/pd.py @@ -0,0 +1,323 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Michalis Pappas +## +## 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, see . +## + +import sigrokdecode as srd + +WORD_ADDR_RESET = 0x00 +WORD_ADDR_SLEEP = 0x01 +WORD_ADDR_IDLE = 0x02 +WORD_ADDR_COMMAND = 0x03 + +WORD_ADDR = {0x00: 'RESET', 0x01: 'SLEEP', 0x02: 'IDLE', 0x03: 'COMMAND'} + +OPCODE_COUNTER = 0x24 +OPCODE_DERIVE_KEY = 0x1c +OPCODE_DEV_REV = 0x30 +OPCODE_ECDH = 0x43 +OPCODE_GEN_DIG = 0x15 +OPCODE_GEN_KEY = 0x40 +OPCODE_HMAC = 0x11 +OPCODE_CHECK_MAC = 0x28 +OPCODE_LOCK = 0x17 +OPCODE_MAC = 0x08 +OPCODE_NONCE = 0x16 +OPCODE_PAUSE = 0x01 +OPCODE_PRIVWRITE = 0x46 +OPCODE_RANDOM = 0x1b +OPCODE_READ = 0x02 +OPCODE_SHA = 0x47 +OPCODE_SIGN = 0x41 +OPCODE_UPDATE_EXTRA = 0x20 +OPCODE_VERIFY = 0x45 +OPCODE_WRITE = 0x12 + +OPCODES = { + 0x01: 'Pause', + 0x02: 'Read', + 0x08: 'MAC', + 0x11: 'HMAC', + 0x12: 'Write', + 0x15: 'GenDig', + 0x16: 'Nonce', + 0x17: 'Lock', + 0x1b: 'Random', + 0x1c: 'DeriveKey', + 0x20: 'UpdateExtra', + 0x24: 'Counter', + 0x28: 'CheckMac', + 0x30: 'DevRev', + 0x40: 'GenKey', + 0x41: 'Sign', + 0x43: 'ECDH', + 0x45: 'Verify', + 0x46: 'PrivWrite', + 0x47: 'SHA', +} + +ZONE_CONFIG = 0x00 +ZONE_OTP = 0x01 +ZONE_DATA = 0x02 + +ZONES = {0x00: 'CONFIG', 0x01: 'OTP', 0x02: 'DATA'} + +STATUS_SUCCESS = 0x00 +STATUS_CHECKMAC_FAIL = 0x01 +STATUS_PARSE_ERROR = 0x03 +STATUS_EXECUTION_ERROR = 0x0f +STATUS_READY = 0x11 +STATUS_CRC_COMM_ERROR = 0xff + +STATUS = { + 0x00: 'Command success', + 0x01: 'Checkmac failure', + 0x03: 'Parse error', + 0x0f: 'Execution error', + 0x11: 'Ready', + 0xff: 'CRC / communications error', +} + +class Decoder(srd.Decoder): + api_version = 3 + id = 'atsha204a' + name = 'ATSHA204A' + longname = 'Microchip ATSHA204A' + desc = 'Microchip ATSHA204A family crypto authentication protocol.' + license = 'gplv2+' + inputs = ['i2c'] + outputs = [] + tags = ['Security/crypto', 'IC', 'Memory'] + annotations = ( + ('waddr', 'Word address'), + ('count', 'Count'), + ('opcode', 'Opcode'), + ('param1', 'Param1'), + ('param2', 'Param2'), + ('data', 'Data'), + ('crc', 'CRC'), + ('status', 'Status'), + ('warning', 'Warning'), + ) + annotation_rows = ( + ('frame', 'Frame', (0, 1, 2, 3, 4, 5, 6)), + ('status', 'Status', (7,)), + ('warnings', 'Warnings', (8,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.state = 'IDLE' + self.waddr = self.opcode = -1 + self.ss_block = self.es_block = 0 + self.bytes = [] + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def output_tx_bytes(self): + b = self.bytes + if len(b) < 1: # Ignore wakeup. + return + self.waddr = b[0][2] + self.put_waddr(b[0]) + if self.waddr == WORD_ADDR_COMMAND: + count = b[1][2] + self.put_count(b[1]) + if len(b) - 1 != count: + self.put_warning(b[0][0], b[-1][1], + 'Invalid frame length: Got {}, expecting {} '.format( + len(b) - 1, count)) + return + self.opcode = b[2][2] + self.put_opcode(b[2]) + self.put_param1(b[3]) + self.put_param2([b[4], b[5]]) + self.put_data(b[6:-2]) + self.put_crc([b[-2], b[-1]]) + + def output_rx_bytes(self): + b = self.bytes + count = b[0][2] + self.put_count(b[0]) + if self.waddr == WORD_ADDR_RESET: + self.put_data([b[1]]) + self.put_crc([b[2], b[3]]) + self.put_status(b[0][0], b[-1][1], b[1][2]) + elif self.waddr == WORD_ADDR_COMMAND: + if count == 4: # Status / Error. + self.put_data([b[1]]) + self.put_crc([b[2], b[3]]) + self.put_status(b[0][0], b[-1][1], b[1][2]) + else: + self.put_data(b[1:-2]) + self.put_crc([b[-2], b[-1]]) + + def putx(self, s, data): + self.put(s[0], s[1], self.out_ann, data) + + def puty(self, s, data): + self.put(s[0][0], s[1][1], self.out_ann, data) + + def putz(self, ss, es, data): + self.put(ss, es, self.out_ann, data) + + def put_waddr(self, s): + self.putx(s, [0, ['Word addr: %s' % WORD_ADDR[s[2]]]]) + + def put_count(self, s): + self.putx(s, [1, ['Count: %s' % s[2]]]) + + def put_opcode(self, s): + self.putx(s, [2, ['Opcode: %s' % OPCODES[s[2]]]]) + + def put_param1(self, s): + op = self.opcode + if op in (OPCODE_CHECK_MAC, OPCODE_COUNTER, OPCODE_DEV_REV, \ + OPCODE_ECDH, OPCODE_GEN_KEY, OPCODE_HMAC, OPCODE_MAC, \ + OPCODE_NONCE, OPCODE_RANDOM, OPCODE_SHA, OPCODE_SIGN, \ + OPCODE_VERIFY): + self.putx(s, [3, ['Mode: %02X' % s[2]]]) + elif op == OPCODE_DERIVE_KEY: + self.putx(s, [3, ['Random: %s' % s[2]]]) + elif op == OPCODE_PRIVWRITE: + self.putx(s, [3, ['Encrypted: {}'.format('Yes' if s[2] & 0x40 else 'No')]]) + elif op == OPCODE_GEN_DIG: + self.putx(s, [3, ['Zone: %s' % ZONES[s[2]]]]) + elif op == OPCODE_LOCK: + self.putx(s, [3, ['Zone: {}, Summary: {}'.format( + 'DATA/OTP' if s[2] else 'CONFIG', + 'Ignored' if s[2] & 0x80 else 'Used')]]) + elif op == OPCODE_PAUSE: + self.putx(s, [3, ['Selector: %02X' % s[2]]]) + elif op == OPCODE_READ: + self.putx(s, [3, ['Zone: {}, Length: {}'.format(ZONES[s[2] & 0x03], + '32 bytes' if s[2] & 0x90 else '4 bytes')]]) + elif op == OPCODE_WRITE: + self.putx(s, [3, ['Zone: {}, Encrypted: {}, Length: {}'.format(ZONES[s[2] & 0x03], + 'Yes' if s[2] & 0x40 else 'No', '32 bytes' if s[2] & 0x90 else '4 bytes')]]) + else: + self.putx(s, [3, ['Param1: %02X' % s[2]]]) + + def put_param2(self, s): + op = self.opcode + if op == OPCODE_DERIVE_KEY: + self.puty(s, [4, ['TargetKey: {:02x} {:02x}'.format(s[1][2], s[0][2])]]) + elif op in (OPCODE_COUNTER, OPCODE_ECDH, OPCODE_GEN_KEY, OPCODE_PRIVWRITE, \ + OPCODE_SIGN, OPCODE_VERIFY): + self.puty(s, [4, ['KeyID: {:02x} {:02x}'.format(s[1][2], s[0][2])]]) + elif op in (OPCODE_NONCE, OPCODE_PAUSE, OPCODE_RANDOM): + self.puty(s, [4, ['Zero: {:02x} {:02x}'.format(s[1][2], s[0][2])]]) + elif op in (OPCODE_HMAC, OPCODE_MAC, OPCODE_CHECK_MAC, OPCODE_GEN_DIG): + self.puty(s, [4, ['SlotID: {:02x} {:02x}'.format(s[1][2], s[0][2])]]) + elif op == OPCODE_LOCK: + self.puty(s, [4, ['Summary: {:02x} {:02x}'.format(s[1][2], s[0][2])]]) + elif op in (OPCODE_READ, OPCODE_WRITE): + self.puty(s, [4, ['Address: {:02x} {:02x}'.format(s[1][2], s[0][2])]]) + elif op == OPCODE_UPDATE_EXTRA: + self.puty(s, [4, ['NewValue: {:02x}'.format(s[0][2])]]) + else: + self.puty(s, [4, ['-']]) + + def put_data(self, s): + if len(s) == 0: + return + op = self.opcode + if op == OPCODE_CHECK_MAC: + self.putz(s[0][0], s[31][1], [5, ['ClientChal: %s' % ' '.join(format(i[2], '02x') for i in s[0:32])]]) + self.putz(s[32][0], s[63][1], [5, ['ClientResp: %s' % ' '.join(format(i[2], '02x') for i in s[32:64])]]) + self.putz(s[64][0], s[76][1], [5, ['OtherData: %s' % ' '.join(format(i[2], '02x') for i in s[64:77])]]) + elif op == OPCODE_DERIVE_KEY: + self.putz(s[0][0], s[31][1], [5, ['MAC: %s' % ' '.join(format(i[2], '02x') for i in s)]]) + elif op == OPCODE_ECDH: + self.putz(s[0][0], s[31][1], [5, ['Pub X: %s' % ' '.join(format(i[2], '02x') for i in s[0:32])]]) + self.putz(s[32][0], s[63][1], [5, ['Pub Y: %s' % ' '.join(format(i[2], '02x') for i in s[32:64])]]) + elif op in (OPCODE_GEN_DIG, OPCODE_GEN_KEY): + self.putz(s[0][0], s[3][1], [5, ['OtherData: %s' % ' '.join(format(i[2], '02x') for i in s)]]) + elif op == OPCODE_MAC: + self.putz(s[0][0], s[31][1], [5, ['Challenge: %s' % ' '.join(format(i[2], '02x') for i in s)]]) + elif op == OPCODE_PRIVWRITE: + if len(s) > 36: # Key + MAC. + self.putz(s[0][0], s[-35][1], [5, ['Value: %s' % ' '.join(format(i[2], '02x') for i in s)]]) + self.putz(s[-32][0], s[-1][1], [5, ['MAC: %s' % ' '.join(format(i[2], '02x') for i in s)]]) + else: # Just value. + self.putz(s[0][0], s[-1][1], [5, ['Value: %s' % ' '.join(format(i[2], '02x') for i in s)]]) + elif op == OPCODE_VERIFY: + if len(s) >= 64: # ECDSA components (always present) + self.putz(s[0][0], s[31][1], [5, ['ECDSA R: %s' % ' '.join(format(i[2], '02x') for i in s[0:32])]]) + self.putz(s[32][0], s[63][1], [5, ['ECDSA S: %s' % ' '.join(format(i[2], '02x') for i in s[32:64])]]) + if len(s) == 83: # OtherData (follow ECDSA components in validate / invalidate mode) + self.putz(s[64][0], s[82][1], [5, ['OtherData: %s' % ' '.join(format(i[2], '02x') for i in s[64:83])]]) + if len(s) == 128: # Public key components (follow ECDSA components in external mode) + self.putz(s[64][0], s[95][1], [5, ['Pub X: %s' % ' '.join(format(i[2], '02x') for i in s[64:96])]]) + self.putz(s[96][0], s[127][1], [5, ['Pub Y: %s' % ' '.join(format(i[2], '02x') for i in s[96:128])]]) + elif op == OPCODE_WRITE: + if len(s) > 32: # Value + MAC. + self.putz(s[0][0], s[-31][1], [5, ['Value: %s' % ' '.join(format(i[2], '02x') for i in s)]]) + self.putz(s[-32][0], s[-1][1], [5, ['MAC: %s' % ' '.join(format(i[2], '02x') for i in s)]]) + else: # Just value. + self.putz(s[0][0], s[-1][1], [5, ['Value: %s' % ' '.join(format(i[2], '02x') for i in s)]]) + else: + self.putz(s[0][0], s[-1][1], [5, ['Data: %s' % ' '.join(format(i[2], '02x') for i in s)]]) + + def put_crc(self, s): + self.puty(s, [6, ['CRC: {:02X} {:02X}'.format(s[0][2], s[1][2])]]) + + def put_status(self, ss, es, status): + self.putz(ss, es, [7, ['Status: %s' % STATUS[status]]]) + + def put_warning(self, ss, es, msg): + self.putz(ss, es, [8, ['Warning: %s' % msg]]) + + def decode(self, ss, es, data): + cmd, databyte = data + # State machine. + if self.state == 'IDLE': + # Wait for an I²C START condition. + if cmd != 'START': + return + self.state = 'GET SLAVE ADDR' + self.ss_block = ss + elif self.state == 'GET SLAVE ADDR': + # Wait for an address read/write operation. + if cmd == 'ADDRESS READ': + self.state = 'READ REGS' + elif cmd == 'ADDRESS WRITE': + self.state = 'WRITE REGS' + elif self.state == 'READ REGS': + if cmd == 'DATA READ': + self.bytes.append([ss, es, databyte]) + elif cmd == 'STOP': + self.es_block = es + # Reset the opcode before received data, as this causes + # responses to be displayed incorrectly. + self.opcode = -1 + if len(self.bytes) > 0: + self.output_rx_bytes() + self.waddr = -1 + self.bytes = [] + self.state = 'IDLE' + elif self.state == 'WRITE REGS': + if cmd == 'DATA WRITE': + self.bytes.append([ss, es, databyte]) + elif cmd == 'STOP': + self.es_block = es + self.output_tx_bytes() + self.bytes = [] + self.state = 'IDLE' diff --git a/libsigrokdecode4DSL/decoders/aud/__init__.py b/libsigrokdecode4DSL/decoders/aud/__init__.py new file mode 100644 index 00000000..10b74234 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/aud/__init__.py @@ -0,0 +1,31 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2016 fenugrec +## +## 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, see . +## + +''' +This protocol decoder decodes the AUD (Advanced User Debugger) interface +of certain Renesas / Hitachi microcontrollers, when set in Branch Trace mode. + +AUD has two modes, this PD currently only supports "Branch Trace" mode. + +Details: +http://www.renesas.eu/products/mpumcu/superh/sh7050/sh7058/Documentation.jsp +("rej09b0046 - SH7058 Hardware manual") +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/aud/pd.py b/libsigrokdecode4DSL/decoders/aud/pd.py new file mode 100644 index 00000000..ad93634f --- /dev/null +++ b/libsigrokdecode4DSL/decoders/aud/pd.py @@ -0,0 +1,107 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2016 fenugrec +## Copyright (C) 2019 DreamSourceLab +## +## 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, see . +## + +# TODO: +# - Annotations are very crude and could be improved. +# - Annotate every nibble? Would give insight on interrupted shifts. +# - Annotate invalid "command" nibbles while SYNC==1? + +import sigrokdecode as srd + +class Decoder(srd.Decoder): + api_version = 3 + id = 'aud' + name = 'AUD' + longname = 'Advanced User Debugger' + desc = 'Renesas/Hitachi Advanced User Debugger (AUD) protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Debug/trace'] + channels = ( + {'id': 'audck', 'name': 'AUDCK', 'desc': 'AUD clock'}, + {'id': 'naudsync', 'name': 'nAUDSYNC', 'desc': 'AUD sync'}, + {'id': 'audata3', 'name': 'AUDATA3', 'desc': 'AUD data line 3'}, + {'id': 'audata2', 'name': 'AUDATA2', 'desc': 'AUD data line 2'}, + {'id': 'audata1', 'name': 'AUDATA1', 'desc': 'AUD data line 1'}, + {'id': 'audata0', 'name': 'AUDATA0', 'desc': 'AUD data line 0'}, + ) + annotations = ( + ('dest', 'Destination address'), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.ncnt = 0 + self.nmax = 0 + self.addr = 0 + self.lastaddr = 0 + self.ss = 0 + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + self.put(self.ss, self.samplenum, self.out_ann, data) + + def handle_clk_edge(self, clk, sync, datapins): + # Reconstruct nibble. + nib = 0 + for i in range(4): + nib |= datapins[3-i] << i + + # sync == 1: annotate if finished; update cmd. + # TODO: Annotate idle level (nibble = 0x03 && SYNC=1). + if sync == 1: + if (self.ncnt == self.nmax) and (self.nmax != 0): + # Done shifting an address: annotate. + self.putx([0, ['0x%08X' % self.addr]]) + self.lastaddr = self.addr + + self.ncnt = 0 + self.addr = self.lastaddr + self.ss = self.samplenum + if nib == 0x08: + self.nmax = 1 + elif nib == 0x09: + self.nmax = 2 + elif nib == 0x0a: + self.nmax = 4 + elif nib == 0x0b: + self.nmax = 8 + else: + # Undefined or idle. + self.nmax = 0 + else: + # sync == 0, valid cmd: start or continue shifting in nibbles. + if (self.nmax > 0): + # Clear tgt nibble. + self.addr &= ~(0x0F << (self.ncnt * 4)) + # Set nibble. + self.addr |= nib << (self.ncnt * 4) + self.ncnt += 1 + + def decode(self): + while True: + (clk, sync, d3, d2, d1, d0) = self.wait({0: 'r'}) + d = (d3, d2, d1, d0) + self.handle_clk_edge(clk, sync, d) diff --git a/libsigrokdecode4DSL/decoders/avr_isp/__init__.py b/libsigrokdecode4DSL/decoders/avr_isp/__init__.py new file mode 100644 index 00000000..e3d90525 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/avr_isp/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +''' +This decoder stacks on top of the 'spi' PD and decodes the In-System +Programming (ISP) protocol of some Atmel AVR 8-bit microcontrollers. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/avr_isp/parts.py b/libsigrokdecode4DSL/decoders/avr_isp/parts.py new file mode 100644 index 00000000..0767789a --- /dev/null +++ b/libsigrokdecode4DSL/decoders/avr_isp/parts.py @@ -0,0 +1,41 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +# Device code addresses: +# 0x00: vendor code, 0x01: part family + flash size, 0x02: part number + +# Vendor code +vendor_code = { + 0x1e: 'Atmel', + 0x00: 'Device locked', +} + +# (Part family + flash size, part number) +part = { + (0x90, 0x01): 'AT90S1200', + (0x91, 0x01): 'AT90S2313', + (0x92, 0x01): 'AT90S4414', + (0x92, 0x05): 'ATmega48', # 4kB flash + (0x93, 0x01): 'AT90S8515', + (0x93, 0x0a): 'ATmega88', # 8kB flash + (0x94, 0x06): 'ATmega168', # 16kB flash + (0xff, 0xff): 'Device code erased, or target missing', + (0x01, 0x02): 'Device locked', + # TODO: Lots more entries. +} diff --git a/libsigrokdecode4DSL/decoders/avr_isp/pd.py b/libsigrokdecode4DSL/decoders/avr_isp/pd.py new file mode 100644 index 00000000..a0719b73 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/avr_isp/pd.py @@ -0,0 +1,213 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012-2014 Uwe Hermann +## +## 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, see . +## + +import sigrokdecode as srd +from .parts import * + +VENDOR_CODE_ATMEL = 0x1e + +class Decoder(srd.Decoder): + api_version = 3 + id = 'avr_isp' + name = 'AVR ISP' + longname = 'AVR In-System Programming' + desc = 'Atmel AVR In-System Programming (ISP) protocol.' + license = 'gplv2+' + inputs = ['spi'] + outputs = [] + tags = ['Debug/trace'] + annotations = ( + ('pe', 'Programming enable'), + ('rsb0', 'Read signature byte 0'), + ('rsb1', 'Read signature byte 1'), + ('rsb2', 'Read signature byte 2'), + ('ce', 'Chip erase'), + ('rfb', 'Read fuse bits'), + ('rhfb', 'Read high fuse bits'), + ('refb', 'Read extended fuse bits'), + ('warnings', 'Warnings'), + ('dev', 'Device'), + ) + annotation_rows = ( + ('bits', 'Bits', ()), + ('commands', 'Commands', tuple(range(7 + 1))), + ('warnings', 'Warnings', (8,)), + ('dev', 'Device', (9,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.state = 'IDLE' + self.mosi_bytes, self.miso_bytes = [], [] + self.ss_cmd, self.es_cmd = 0, 0 + self.xx, self.yy, self.zz, self.mm = 0, 0, 0, 0 + self.ss_device = None + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + self.put(self.ss_cmd, self.es_cmd, self.out_ann, data) + + def handle_cmd_programming_enable(self, cmd, ret): + # Programming enable. + # Note: The chip doesn't send any ACK for 'Programming enable'. + self.putx([0, ['Programming enable']]) + + # Sanity check on reply. + if ret[1:4] != [0xac, 0x53, cmd[2]]: + self.putx([8, ['Warning: Unexpected bytes in reply!']]) + + def handle_cmd_read_signature_byte_0x00(self, cmd, ret): + # Signature byte 0x00: vendor code. + self.vendor_code = ret[3] + v = vendor_code[self.vendor_code] + self.putx([1, ['Vendor code: 0x%02x (%s)' % (ret[3], v)]]) + + # Store for later. + self.xx = cmd[1] # Same as ret[2]. + self.yy = cmd[3] + self.zz = ret[0] + + # Sanity check on reply. + if ret[1] != 0x30 or ret[2] != cmd[1]: + self.putx([8, ['Warning: Unexpected bytes in reply!']]) + + # Sanity check for the vendor code. + if self.vendor_code != VENDOR_CODE_ATMEL: + self.putx([8, ['Warning: Vendor code was not 0x1e (Atmel)!']]) + + def handle_cmd_read_signature_byte_0x01(self, cmd, ret): + # Signature byte 0x01: part family and memory size. + self.part_fam_flash_size = ret[3] + self.putx([2, ['Part family / memory size: 0x%02x' % ret[3]]]) + + # Store for later. + self.mm = cmd[3] + self.ss_device = self.ss_cmd + + # Sanity check on reply. + if ret[1] != 0x30 or ret[2] != cmd[1] or ret[0] != self.yy: + self.putx([8, ['Warning: Unexpected bytes in reply!']]) + + def handle_cmd_read_signature_byte_0x02(self, cmd, ret): + # Signature byte 0x02: part number. + self.part_number = ret[3] + self.putx([3, ['Part number: 0x%02x' % ret[3]]]) + + p = part[(self.part_fam_flash_size, self.part_number)] + data = [9, ['Device: Atmel %s' % p]] + self.put(self.ss_device, self.es_cmd, self.out_ann, data) + + # Sanity check on reply. + if ret[1] != 0x30 or ret[2] != self.xx or ret[0] != self.mm: + self.putx([8, ['Warning: Unexpected bytes in reply!']]) + + self.xx, self.yy, self.zz, self.mm = 0, 0, 0, 0 + + def handle_cmd_chip_erase(self, cmd, ret): + # Chip erase (erases both flash an EEPROM). + # Upon successful chip erase, the lock bits will also be erased. + # The only way to end a Chip Erase cycle is to release RESET#. + self.putx([4, ['Chip erase']]) + + # TODO: Check/handle RESET#. + + # Sanity check on reply. + bit = (ret[2] & (1 << 7)) >> 7 + if ret[1] != 0xac or bit != 1 or ret[3] != cmd[2]: + self.putx([8, ['Warning: Unexpected bytes in reply!']]) + + def handle_cmd_read_fuse_bits(self, cmd, ret): + # Read fuse bits. + self.putx([5, ['Read fuse bits: 0x%02x' % ret[3]]]) + + # TODO: Decode fuse bits. + # TODO: Sanity check on reply. + + def handle_cmd_read_fuse_high_bits(self, cmd, ret): + # Read fuse high bits. + self.putx([6, ['Read fuse high bits: 0x%02x' % ret[3]]]) + + # TODO: Decode fuse bits. + # TODO: Sanity check on reply. + + def handle_cmd_read_extended_fuse_bits(self, cmd, ret): + # Read extended fuse bits. + self.putx([7, ['Read extended fuse bits: 0x%02x' % ret[3]]]) + + # TODO: Decode fuse bits. + # TODO: Sanity check on reply. + + def handle_command(self, cmd, ret): + if cmd[:2] == [0xac, 0x53]: + self.handle_cmd_programming_enable(cmd, ret) + elif cmd[0] == 0xac and (cmd[1] & (1 << 7)) == (1 << 7): + self.handle_cmd_chip_erase(cmd, ret) + elif cmd[:3] == [0x50, 0x00, 0x00]: + self.handle_cmd_read_fuse_bits(cmd, ret) + elif cmd[:3] == [0x58, 0x08, 0x00]: + self.handle_cmd_read_fuse_high_bits(cmd, ret) + elif cmd[:3] == [0x50, 0x08, 0x00]: + self.handle_cmd_read_extended_fuse_bits(cmd, ret) + elif cmd[0] == 0x30 and cmd[2] == 0x00: + self.handle_cmd_read_signature_byte_0x00(cmd, ret) + elif cmd[0] == 0x30 and cmd[2] == 0x01: + self.handle_cmd_read_signature_byte_0x01(cmd, ret) + elif cmd[0] == 0x30 and cmd[2] == 0x02: + self.handle_cmd_read_signature_byte_0x02(cmd, ret) + else: + c = '%02x %02x %02x %02x' % tuple(cmd) + r = '%02x %02x %02x %02x' % tuple(ret) + self.putx([0, ['Unknown command: %s (reply: %s)!' % (c, r)]]) + + def decode(self, ss, es, data): + ptype, mosi, miso = data + + # For now, only use DATA and BITS packets. + if ptype not in ('DATA', 'BITS'): + return + + # Store the individual bit values and ss/es numbers. The next packet + # is guaranteed to be a 'DATA' packet belonging to this 'BITS' one. + if ptype == 'BITS': + self.miso_bits, self.mosi_bits = miso, mosi + return + + self.ss, self.es = ss, es + + if len(self.mosi_bytes) == 0: + self.ss_cmd = ss + + # Append new bytes. + self.mosi_bytes.append(mosi) + self.miso_bytes.append(miso) + + # All commands consist of 4 bytes. + if len(self.mosi_bytes) < 4: + return + + self.es_cmd = es + + self.handle_command(self.mosi_bytes, self.miso_bytes) + + self.mosi_bytes = [] + self.miso_bytes = [] diff --git a/libsigrokdecode4DSL/decoders/avr_pdi/__init__.py b/libsigrokdecode4DSL/decoders/avr_pdi/__init__.py new file mode 100644 index 00000000..1c61dea7 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/avr_pdi/__init__.py @@ -0,0 +1,42 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2016 Gerhard Sittig +## +## 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, see . +## + +''' +PDI (Program and Debug Interface) is an Atmel proprietary interface for +external programming and on-chip debugging of the device. + +See the Atmel Application Note AVR1612 "PDI programming driver" and the +"Program and Debug Interface" section in the Xmega A manual for details. + +The protocol uses two pins: the RESET pin and one dedicated DATA pin. +The RESET pin provides a clock, the DATA pin communicates serial frames +with a start bit, eight data bits, an even parity bit, and two stop bits. +Data communication is bidirectional and half duplex, the device will +provide response data after reception of a respective request. + +Protocol frames communicate opcodes and their arguments, which provides +random and sequential access to the device's address space. By accessing +the registers of internal peripherals, especially the NVM controller, +it's possible to identify the device, read from and write to several +kinds of memory (signature rows, fuses and lock bits, internal flash and +EEPROM, memory mapped peripherals), and to control execution of software +on the device. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/avr_pdi/pd.py b/libsigrokdecode4DSL/decoders/avr_pdi/pd.py new file mode 100644 index 00000000..45705950 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/avr_pdi/pd.py @@ -0,0 +1,576 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2011-2014 Uwe Hermann +## Copyright (C) 2016 Gerhard Sittig +## Copyright (C) 2019 DreamSourceLab +## +## 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, see . +## + +# Note the implementation details: +# +# Although the Atmel literature suggests (does not explicitly mandate, +# but shows in diagrams) that two stop bits are used in the protocol, +# the decoder loses synchronization with ATxmega generated responses +# when it expects more than one stop bit. Since the chip's hardware is +# fixed, this is not an implementation error in some programmer software. +# Since this is a protocol decoder which does not participate in the +# communication (does not actively send data), we can read the data +# stream with one stop bit, and transparently keep working when two +# are used. +# +# Annotations in the UART fields level differ from Atmel literature. +# Wrong parity bits are referred to as "parity error". Low stop bits are +# referred to as "frame error". +# +# The PDI component in the device starts disabled. Enabling PDI +# communication is done by raising DATA and clocking RESET with a +# minimum frequency. PDI communication automatically gets disabled when +# RESET "is inactive" for a certain period of time. The specific timing +# conditions are rather fuzzy in the literature (phrased weakly), and +# are device dependent (refer to the minumum RESET pulse width). This +# protocol decoder implementation internally prepares for but currently +# does not support these enable and disable phases. On the one hand it +# avoids excess external dependencies or wrong results for legal input +# data. On the other hand the decoder works when input streams start in +# the middle of an established connection. +# +# Communication peers detect physical collisions. The decoder can't. +# Upon collisions, a peer will cease any subsequent transmission, until +# a BREAK is seen. Synchronization can get enforced by sending two BREAK +# conditions. The first will cause a collision, the second will re-enable +# the peer. The decoder has no concept of physical collisions. It stops +# the interpretation of instructions when BREAK is seen, and assumes +# that a new instruction will start after BREAK. +# +# This protocol decoder only supports PDI communication over UART frames. +# It lacks support for PDI over JTAG. This would require separation into +# multiple protocol decoder layers (UART physical, JTAG physical, PDI +# instructions, optionally device support on top of PDI. There is some +# more potential for future extensions: +# - The JTAG physical has dedicated TX and RX directions. This decoder +# only picks up communicated bytes but does not check which "line" +# they are communicated on (not applicable to half duplex UART). +# - PDI over JTAG uses "special frame error" conditions to communicate +# additional symbols: BREAK (0xBB with parity 1), DELAY (0xDB with +# parity 1), and EMPTY (0xEB with parity 1). +# - Another "device support" layer might interpret device specific +# timings, and might map addresses used in memory access operations +# to component names, or even register names and bit fields(?). It's +# quite deep a rabbithole though... + +import sigrokdecode as srd +from collections import namedtuple + +class Ann: + '''Annotation and binary output classes.''' + ( + BIT, START, DATA, PARITY_OK, PARITY_ERR, + STOP_OK, STOP_ERR, BREAK, + OPCODE, DATA_PROG, DATA_DEV, PDI_BREAK, + ENABLE, DISABLE, COMMAND, + ) = range(15) + ( + BIN_BYTES, + ) = range(1) + +Bit = namedtuple('Bit', 'val ss es') + +class PDI: + '''PDI protocol instruction opcodes, and operand formats.''' + ( + OP_LDS, OP_LD, OP_STS, OP_ST, + OP_LDCS, OP_REPEAT, OP_STCS, OP_KEY, + ) = range(8) + pointer_format_nice = [ + '*(ptr)', + '*(ptr++)', + 'ptr', + 'ptr++ (rsv)', + ] + pointer_format_terse = [ + '*p', + '*p++', + 'p', + '(rsv)', + ] + ctrl_reg_name = { + 0: 'status', + 1: 'reset', + 2: 'ctrl', + } + +class Decoder(srd.Decoder): + api_version = 3 + id = 'avr_pdi' + name = 'AVR PDI' + longname = 'Atmel Program and Debug Interface' + desc = 'Atmel ATxmega Program and Debug Interface (PDI) protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Debug/trace'] + channels = ( + {'id': 'reset', 'name': 'RESET', 'desc': 'RESET / PDI_CLK'}, + {'id': 'data', 'name': 'DATA', 'desc': 'PDI_DATA'}, + ) + annotations = ( + ('uart-bit', 'UART bit'), + ('start-bit', 'Start bit'), + ('data-bit', 'Data bit'), + ('parity-ok', 'Parity OK bit'), + ('parity-err', 'Parity error bit'), + ('stop-ok', 'Stop OK bit'), + ('stop-err', 'Stop error bit'), + ('break', 'BREAK condition'), + ('opcode', 'Instruction opcode'), + ('data-prog', 'Programmer data'), + ('data-dev', 'Device data'), + ('pdi-break', 'BREAK at PDI level'), + ('enable', 'Enable PDI'), + ('disable', 'Disable PDI'), + ('cmd-data', 'PDI command with data'), + ) + annotation_rows = ( + ('uart_bits', 'UART bits', (Ann.BIT,)), + ('uart_fields', 'UART fields', (Ann.START, Ann.DATA, Ann.PARITY_OK, + Ann.PARITY_ERR, Ann.STOP_OK, Ann.STOP_ERR, Ann.BREAK)), + ('pdi_fields', 'PDI fields', (Ann.OPCODE, Ann.DATA_PROG, Ann.DATA_DEV, + Ann.PDI_BREAK)), + ('pdi_cmds', 'PDI Cmds', (Ann.ENABLE, Ann.DISABLE, Ann.COMMAND)), + ) + binary = ( + ('bytes', 'PDI protocol bytes'), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.clear_state() + + def clear_state(self): + # Track bit times and bit values. + self.ss_last_fall = None + self.data_sample = None + self.ss_curr_fall = None + # Collect UART frame bits into byte values. + self.bits = [] + self.zero_count = 0 + self.zero_ss = None + self.break_ss = None + self.break_es = None + self.clear_insn() + + def clear_insn(self): + # Collect instructions and their arguments, + # properties of the current instructions. + self.insn_rep_count = 0 + self.insn_opcode = None + self.insn_wr_counts = [] + self.insn_rd_counts = [] + # Accumulation of data items as bytes pass by. + self.insn_dat_bytes = [] + self.insn_dat_count = 0 + self.insn_ss_data = None + # Next layer "commands", instructions plus operands. + self.cmd_ss = None + self.cmd_insn_parts_nice = [] + self.cmd_insn_parts_terse = [] + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_binary = self.register(srd.OUTPUT_BINARY) + + def put_ann_bit(self, bit_nr, ann_idx): + b = self.bits[bit_nr] + self.put(b.ss, b.es, self.out_ann, [ann_idx, [str(b.val)]]) + + def put_ann_data(self, bit_nr, ann_data): + b = self.bits[bit_nr] + self.put(b.ss, b.es, self.out_ann, ann_data) + + def put_ann_row_val(self, ss, es, row, value): + self.put(ss, es, self.out_ann, [row, value]) + + def put_bin_bytes(self, ss, es, row, value): + self.put(ss, es, self.out_binary, [row, value]) + + def handle_byte(self, ss, es, byteval): + '''Handle a byte at the PDI protocol layer.''' + + # Handle BREAK conditions, which will abort any + # potentially currently executing instruction. + is_break = byteval is None + if is_break: + self.cmd_insn_parts_nice.append('BREAK') + self.cmd_insn_parts_terse.append('BRK') + self.insn_rep_count = 0 + # Will FALLTHROUGH to "end of instruction" below. + + # Decode instruction opcodes and argument sizes + # from the first byte of a transaction. + if self.insn_opcode is None and not is_break: + opcode = (byteval & 0xe0) >> 5 + arg30 = byteval & 0x0f + arg32 = (byteval & 0x0c) >> 2 + arg10 = byteval & 0x03 + self.insn_opcode = opcode + self.cmd_ss = ss + mnemonics = None + if opcode == PDI.OP_LDS: + # LDS: load data, direct addressing. + # Writes an address, reads a data item. + width_addr = arg32 + 1 + width_data = arg10 + 1 + self.insn_wr_counts = [width_addr] + self.insn_rd_counts = [width_data] + mnemonics = [ + 'Insn: LDS a{:d}, m{:d}'.format(width_addr, width_data), + 'LDS a{:d}, m{:d}'.format(width_addr, width_data), 'LDS', + ] + self.cmd_insn_parts_nice = ['LDS'] + self.cmd_insn_parts_terse = ['LDS'] + elif opcode == PDI.OP_LD: + # LD: load data, indirect addressing. + # Reads a data item, with optional repeat. + ptr_txt = PDI.pointer_format_nice[arg32] + ptr_txt_terse = PDI.pointer_format_terse[arg32] + width_data = arg10 + 1 + self.insn_wr_counts = [] + self.insn_rd_counts = [width_data] + if self.insn_rep_count: + self.insn_rd_counts.extend(self.insn_rep_count * [width_data]) + self.insn_rep_count = 0 + mnemonics = [ + 'Insn: LD {:s} m{:d}'.format(ptr_txt, width_data), + 'LD {:s} m{:d}'.format(ptr_txt, width_data), 'LD', + ] + self.cmd_insn_parts_nice = ['LD', ptr_txt] + self.cmd_insn_parts_terse = ['LD', ptr_txt_terse] + elif opcode == PDI.OP_STS: + # STS: store data, direct addressing. + # Writes an address, writes a data item. + width_addr = arg32 + 1 + width_data = arg10 + 1 + self.insn_wr_counts = [width_addr, width_data] + self.insn_rd_counts = [] + mnemonics = [ + 'Insn: STS a{:d}, i{:d}'.format(width_addr, width_data), + 'STS a{:d}, i{:d}'.format(width_addr, width_data), 'STS', + ] + self.cmd_insn_parts_nice = ['STS'] + self.cmd_insn_parts_terse = ['STS'] + elif opcode == PDI.OP_ST: + # ST: store data, indirect addressing. + # Writes a data item, with optional repeat. + ptr_txt = PDI.pointer_format_nice[arg32] + ptr_txt_terse = PDI.pointer_format_terse[arg32] + width_data = arg10 + 1 + self.insn_wr_counts = [width_data] + self.insn_rd_counts = [] + if self.insn_rep_count: + self.insn_wr_counts.extend(self.insn_rep_count * [width_data]) + self.insn_rep_count = 0 + mnemonics = [ + 'Insn: ST {:s} i{:d}'.format(ptr_txt, width_data), + 'ST {:s} i{:d}'.format(ptr_txt, width_data), 'ST', + ] + self.cmd_insn_parts_nice = ['ST', ptr_txt] + self.cmd_insn_parts_terse = ['ST', ptr_txt_terse] + elif opcode == PDI.OP_LDCS: + # LDCS: load control/status. + # Loads exactly one byte. + reg_num = arg30 + reg_txt = PDI.ctrl_reg_name.get(reg_num, 'r{:d}'.format(reg_num)) + reg_txt_terse = '{:d}'.format(reg_num) + self.insn_wr_counts = [] + self.insn_rd_counts = [1] + mnemonics = [ + 'Insn: LDCS {:s}, m1'.format(reg_txt), + 'LDCS {:s}, m1'.format(reg_txt), 'LDCS', + ] + self.cmd_insn_parts_nice = ['LDCS', reg_txt] + self.cmd_insn_parts_terse = ['LDCS', reg_txt_terse] + elif opcode == PDI.OP_STCS: + # STCS: store control/status. + # Writes exactly one byte. + reg_num = arg30 + reg_txt = PDI.ctrl_reg_name.get(reg_num, 'r{:d}'.format(reg_num)) + reg_txt_terse = '{:d}'.format(reg_num) + self.insn_wr_counts = [1] + self.insn_rd_counts = [] + mnemonics = [ + 'Insn: STCS {:s}, i1'.format(reg_txt), + 'STCS {:s}, i1'.format(reg_txt), 'STCS', + ] + self.cmd_insn_parts_nice = ['STCS', reg_txt] + self.cmd_insn_parts_terse = ['STCS', reg_txt_terse] + elif opcode == PDI.OP_REPEAT: + # REPEAT: sets repeat count for the next instruction. + # Reads repeat count from following bytes. + width_data = arg10 + 1 + self.insn_wr_counts = [width_data] + self.insn_rd_counts = [] + mnemonics = [ + 'Insn: REPEAT i{:d}'.format(width_data), + 'REPEAT i{:d}'.format(width_data), 'REP', + ] + self.cmd_insn_parts_nice = ['REPEAT'] + self.cmd_insn_parts_terse = ['REP'] + elif opcode == PDI.OP_KEY: + # KEY: set activation key (enables PDIBUS mmap access). + # Writes a sequence of 8 bytes, fixed length. + width_data = 8 + self.insn_wr_counts = [width_data] + self.insn_rd_counts = [] + mnemonics = [ + 'Insn: KEY i{:d}'.format(width_data), + 'KEY i{:d}'.format(width_data), 'KEY', + ] + self.cmd_insn_parts_nice = ['KEY'] + self.cmd_insn_parts_terse = ['KEY'] + + # Emit an annotation for the instruction opcode. + self.put_ann_row_val(ss, es, Ann.OPCODE, mnemonics) + + # Prepare to write/read operands/data bytes. + self.insn_dat_bytes = [] + if self.insn_wr_counts: + self.insn_dat_count = self.insn_wr_counts[0] + return + if self.insn_rd_counts: + self.insn_dat_count = self.insn_rd_counts[0] + return + # FALLTHROUGH. + # When there are no operands or data bytes to read, + # then fall through to the end of the instruction + # handling below (which emits annotations). + + # Read bytes which carry operands (addresses, immediates) + # or data values for memory access. + if self.insn_dat_count and not is_break: + + # Accumulate received bytes until another multi byte + # data item is complete. + if not self.insn_dat_bytes: + self.insn_ss_data = ss + self.insn_dat_bytes.append(byteval) + self.insn_dat_count -= 1 + if self.insn_dat_count: + return + + # Determine the data item's duration and direction, + # "consume" its length spec (to simplify later steps). + data_ss = self.insn_ss_data + data_es = es + if self.insn_wr_counts: + data_ann = Ann.DATA_PROG + data_width = self.insn_wr_counts.pop(0) + elif self.insn_rd_counts: + data_ann = Ann.DATA_DEV + data_width = self.insn_rd_counts.pop(0) + + # PDI communicates multi-byte data items in little endian + # order. Get a nice textual representation of the number, + # wide and narrow for several zoom levels. + self.insn_dat_bytes.reverse() + data_txt_digits = ''.join(['{:02x}'.format(b) for b in self.insn_dat_bytes]) + data_txt_hex = '0x' + data_txt_digits + data_txt_prefix = 'Data: ' + data_txt_hex + data_txts = [data_txt_prefix, data_txt_hex, data_txt_digits] + self.insn_dat_bytes = [] + + # Emit an annotation for the data value. + self.put_ann_row_val(data_ss, data_es, data_ann, data_txts) + + # Collect detailled information which describes the whole + # command when combined (for a next layer annotation, + # spanning the complete command). + self.cmd_insn_parts_nice.append(data_txt_hex) + self.cmd_insn_parts_terse.append(data_txt_digits) + + # Send out write data first until exhausted, + # then drain expected read data. + if self.insn_wr_counts: + self.insn_dat_count = self.insn_wr_counts[0] + return + if self.insn_rd_counts: + self.insn_dat_count = self.insn_rd_counts[0] + return + + # FALLTHROUGH. + # When all operands and data bytes were seen, + # terminate the inspection of the instruction. + + # Postprocess the instruction after its operands were seen. + cmd_es = es + cmd_txt_nice = ' '.join(self.cmd_insn_parts_nice) + cmd_txt_terse = ' '.join(self.cmd_insn_parts_terse) + cmd_txts = [cmd_txt_nice, cmd_txt_terse] + self.put_ann_row_val(self.cmd_ss, cmd_es, Ann.COMMAND, cmd_txts) + if self.insn_opcode == PDI.OP_REPEAT and not is_break: + # The last communicated data item is the repeat + # count for the next instruction (i.e. it will + # execute N+1 times when "REPEAT N" is specified). + count = int(self.cmd_insn_parts_nice[-1], 0) + self.insn_rep_count = count + + # Have the state for instruction decoding cleared, but make sure + # to carry over REPEAT count specs between instructions. They + # start out as zero, will be setup by REPEAT instructions, need + # to get passed to the instruction which follows REPEAT. The + # instruction which sees a non-zero repeat count which will + # consume the counter and drop it to zero, then the counter + # remains at zero until the next REPEAT instruction. + save_rep_count = self.insn_rep_count + self.clear_insn() + self.insn_rep_count = save_rep_count + + def handle_bits(self, ss, es, bitval): + '''Handle a bit at the UART layer.''' + + # Concentrate annotation literals here for easier maintenance. + ann_class_text = { + Ann.START: ['Start bit', 'Start', 'S'], + Ann.PARITY_OK: ['Parity OK', 'Par OK', 'P'], + Ann.PARITY_ERR: ['Parity error', 'Par ERR', 'PE'], + Ann.STOP_OK: ['Stop bit', 'Stop', 'T'], + Ann.STOP_ERR: ['Stop bit error', 'Stop ERR', 'TE'], + Ann.BREAK: ['Break condition', 'BREAK', 'BRK'], + } + def put_uart_field(bitpos, annclass): + self.put_ann_data(bitpos, [annclass, ann_class_text[annclass]]) + + # The number of bits which form one UART frame. Note that + # the decoder operates with only one stop bit. + frame_bitcount = 1 + 8 + 1 + 1 + + # Detect adjacent runs of all-zero bits. This is meant + # to cope when BREAK conditions appear at any arbitrary + # position, it need not be "aligned" to an UART frame. + if bitval == 1: + self.zero_count = 0 + elif bitval == 0: + if not self.zero_count: + self.zero_ss = ss + self.zero_count += 1 + if self.zero_count == frame_bitcount: + self.break_ss = self.zero_ss + + # BREAK conditions are _at_minimum_ the length of a UART frame, but + # can span an arbitrary number of bit times. Track the "end sample" + # value of the last low bit we have seen, and emit the annotation only + # after the line went idle (high) again. Pass BREAK to the upper layer + # as well. When the line is low, BREAK still is pending. When the line + # is high, the current bit cannot be START, thus return from here. + if self.break_ss is not None: + if bitval == '0': + self.break_es = es + return + self.put(self.break_ss, self.break_es, self.out_ann, + [Ann.BREAK, ann_class_text[Ann.BREAK]]) + self.handle_byte(self.break_ss, self.break_es, None) + self.break_ss = None + self.break_es = None + self.bits = [] + return + + # Ignore high bits when waiting for START. + if not self.bits and bitval == 1: + return + + # Store individual bits and their start/end sample numbers, + # until a complete frame was received. + self.bits.append(Bit(bitval, ss, es)) + if len(self.bits) < frame_bitcount: + return + + # Get individual fields of the UART frame. + bits_num = sum([b.val << pos for pos, b in enumerate(self.bits)]) + if False: + # This logic could detect BREAK conditions which are aligned to + # UART frames. Which was obsoleted by the above detection at + # arbitrary positions. The code still can be useful to detect + # "other kinds of frame errors" which carry valid symbols for + # upper layers (the Atmel literature suggests "break", "delay", + # and "empty" symbols when PDI is communicated over different + # physical layers). + if bits_num == 0: # BREAK + self.break_ss = self.bits[0].ss + self.break_es = es + self.bits = [] + return + start_bit = bits_num & 0x01; bits_num >>= 1 + data_val = bits_num & 0xff; bits_num >>= 8 + data_text = '{:02x}'.format(data_val) + parity_bit = bits_num & 0x01; bits_num >>= 1 + stop_bit = bits_num & 0x01; bits_num >>= 1 + + # Check for frame errors. START _must_ have been low + # according to the above accumulation logic. + parity_ok = (bin(data_val).count('1') + parity_bit) % 2 == 0 + stop_ok = stop_bit == 1 + valid_frame = parity_ok and stop_ok + + # Emit annotations. + for idx in range(frame_bitcount): + self.put_ann_bit(idx, Ann.BIT) + put_uart_field(0, Ann.START) + self.put(self.bits[1].ss, self.bits[8].es, self.out_ann, + [Ann.DATA, ['Data: ' + data_text, 'D: ' + data_text, data_text]]) + put_uart_field(9, Ann.PARITY_OK if parity_ok else Ann.PARITY_ERR) + put_uart_field(10, Ann.STOP_OK if stop_ok else Ann.STOP_ERR) + + # Emit binary data stream. Have bytes interpreted at higher layers. + if valid_frame: + byte_ss, byte_es = self.bits[0].ss, self.bits[-1].es + self.put_bin_bytes(byte_ss, byte_es, Ann.BIN_BYTES, bytes([data_val])) + self.handle_byte(byte_ss, byte_es, data_val) + + # Reset internal state for the next frame. + self.bits = [] + + def handle_clk_edge(self, clock_pin, data_pin): + # Sample the data line on rising clock edges. Always, for TX and for + # RX bytes alike. + if clock_pin == 1: + self.data_sample = data_pin + return + + # Falling clock edges are boundaries for bit slots. Inspect previously + # sampled bits on falling clock edges, when the start and end sample + # numbers were determined. Only inspect bit slots of known clock + # periods (avoid interpreting the DATA line when the "enabled" state + # has not yet been determined). + self.ss_last_fall = self.ss_curr_fall + self.ss_curr_fall = self.samplenum + if self.ss_last_fall is None: + return + + # Have the past bit slot processed. + bit_ss, bit_es = self.ss_last_fall, self.ss_curr_fall + bit_val = self.data_sample + self.handle_bits(bit_ss, bit_es, bit_val) + + def decode(self): + while True: + (clock_pin, data_pin) = self.wait({0: 'e'}) + self.handle_clk_edge(clock_pin, data_pin) diff --git a/libsigrokdecode4DSL/decoders/caliper/__init__.py b/libsigrokdecode4DSL/decoders/caliper/__init__.py new file mode 100644 index 00000000..44dab08b --- /dev/null +++ b/libsigrokdecode4DSL/decoders/caliper/__init__.py @@ -0,0 +1,36 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 Tomas Mudrunka +## +## 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, see . +## + +''' +This decoder interprets the digital output of cheap generic calipers +(usually made in China), and shows the measured value in millimeters +or inches. + +Notice that these devices often communicate on voltage levels below +3.3V and may require additional circuitry to capture the signal. + +This decoder does not work for calipers using the Digimatic protocol +(eg. Mitutoyo and similar brands). + +For more information see: +http://www.shumatech.com/support/chinese_scales.htm +https://www.instructables.com/id/Reading-Digital-Callipers-with-an-Arduino-USB/ +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/caliper/pd.py b/libsigrokdecode4DSL/decoders/caliper/pd.py new file mode 100644 index 00000000..20a2a555 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/caliper/pd.py @@ -0,0 +1,146 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 Tomas Mudrunka +## +## Permission is hereby granted, free of charge, to any person obtaining a copy +## of this software and associated documentation files (the "Software"), to deal +## in the Software without restriction, including without limitation the rights +## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +## copies of the Software, and to permit persons to whom the Software is +## furnished to do so, subject to the following conditions: +## +## The above copyright notice and this permission notice shall be included in all +## copies or substantial portions of the Software. +## +## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +## SOFTWARE. + +import sigrokdecode as srd +from common.srdhelper import bitpack + +# Millimeters per inch. +mm_per_inch = 25.4 + +class Decoder(srd.Decoder): + api_version = 3 + id = 'caliper' + name = 'Caliper' + longname = 'Digital calipers' + desc = 'Protocol of cheap generic digital calipers.' + license = 'mit' + inputs = ['logic'] + outputs = [] + channels = ( + {'id': 'clk', 'name': 'CLK', 'desc': 'Serial clock line'}, + {'id': 'data', 'name': 'DATA', 'desc': 'Serial data line'}, + ) + options = ( + {'id': 'timeout_ms', 'desc': 'Packet timeout in ms, 0 to disable', + 'default': 10}, + {'id': 'unit', 'desc': 'Convert units', 'default': 'keep', + 'values': ('keep', 'mm', 'inch')}, + {'id': 'changes', 'desc': 'Changes only', 'default': 'no', + 'values': ('no', 'yes')}, + ) + tags = ['Analog/digital', 'Sensor'] + annotations = ( + ('measurement', 'Measurement'), + ('warning', 'Warning'), + ) + annotation_rows = ( + ('measurements', 'Measurements', (0,)), + ('warnings', 'Warnings', (1,)), + ) + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def __init__(self): + self.reset() + + def reset(self): + self.ss, self.es = 0, 0 + self.number_bits = [] + self.flags_bits = [] + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putg(self, ss, es, cls, data): + self.put(ss, es, self.out_ann, [cls, data]) + + def decode(self): + last_sent = None + timeout_ms = self.options['timeout_ms'] + want_unit = self.options['unit'] + show_all = self.options['changes'] == 'no' + wait_cond = [{0: 'r'}] + if timeout_ms: + snum_per_ms = self.samplerate / 1000 + timeout_snum = timeout_ms * snum_per_ms + wait_cond.append({'skip': round(timeout_snum)}) + while True: + # Sample data at the rising clock edge. Optionally timeout + # after inactivity for a user specified period. Present the + # number of unprocessed bits to the user for diagnostics. + clk, data = self.wait(wait_cond) + if timeout_ms and not self.matched[0]: + if self.number_bits or self.flags_bits: + count = len(self.number_bits) + len(self.flags_bits) + self.putg(self.ss, self.samplenum, 1, [ + 'timeout with {} bits in buffer'.format(count), + 'timeout ({} bits)'.format(count), + 'timeout', + ]) + self.reset() + continue + + # Store position of first bit and last activity. + # Shift in measured number and flag bits. + if not self.ss: + self.ss = self.samplenum + self.es = self.samplenum + if len(self.number_bits) < 16: + self.number_bits.append(data) + continue + if len(self.flags_bits) < 8: + self.flags_bits.append(data) + if len(self.flags_bits) < 8: + continue + + # Get raw values from received data bits. Run the number + # conversion, controlled by flags and/or user specs. + negative = bool(self.flags_bits[4]) + is_inch = bool(self.flags_bits[7]) + number = bitpack(self.number_bits) + if negative: + number = -number + if is_inch: + number /= 2000 + if want_unit == 'mm': + number *= mm_per_inch + is_inch = False + else: + number /= 100 + if want_unit == 'inch': + number = round(number / mm_per_inch, 4) + is_inch = True + unit = 'in' if is_inch else 'mm' + + # Construct and emit an annotation. + if show_all or (number, unit) != last_sent: + self.putg(self.ss, self.es, 0, [ + '{number}{unit}'.format(**locals()), + '{number}'.format(**locals()), + ]) + last_sent = (number, unit) + + # Reset internal state for the start of the next packet. + self.reset() diff --git a/libsigrokdecode4DSL/decoders/can/__init__.py b/libsigrokdecode4DSL/decoders/can/__init__.py new file mode 100644 index 00000000..47f571d6 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/can/__init__.py @@ -0,0 +1,29 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +''' +CAN (Controller Area Network) is a field bus protocol for distributed +real-time control. + +This decoder assumes that a single CAN_RX line is sampled (e.g. on +the digital output side of a CAN transceiver IC such as the Microchip +MCP-2515DM-BM). +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/can/pd.py b/libsigrokdecode4DSL/decoders/can/pd.py new file mode 100644 index 00000000..3e630ee1 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/can/pd.py @@ -0,0 +1,415 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012-2013 Uwe Hermann +## Copyright (C) 2019 DreamSourceLab +## +## 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, see . +## + +import sigrokdecode as srd + +class SamplerateError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = 'can' + name = 'CAN' + longname = 'Controller Area Network' + desc = 'Field bus protocol for distributed realtime control.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Automotive'] + channels = ( + {'id': 'can_rx', 'name': 'CAN RX', 'desc': 'CAN bus line'}, + ) + options = ( + {'id': 'bitrate', 'desc': 'Bitrate (bits/s)', 'default': 1000000}, + {'id': 'sample_point', 'desc': 'Sample point (%)', 'default': 70.0}, + ) + annotations = ( + ('data', 'CAN payload data'), + ('sof', 'Start of frame'), + ('eof', 'End of frame'), + ('id', 'Identifier'), + ('ext-id', 'Extended identifier'), + ('full-id', 'Full identifier'), + ('ide', 'Identifier extension bit'), + ('reserved-bit', 'Reserved bit 0 and 1'), + ('rtr', 'Remote transmission request'), + ('srr', 'Substitute remote request'), + ('dlc', 'Data length count'), + ('crc-sequence', 'CRC sequence'), + ('crc-delimiter', 'CRC delimiter'), + ('ack-slot', 'ACK slot'), + ('ack-delimiter', 'ACK delimiter'), + ('stuff-bit', 'Stuff bit'), + ('warnings', 'Human-readable warnings'), + ('bit', 'Bit'), + ) + annotation_rows = ( + ('bits', 'Bits', (15, 17)), + ('fields', 'Fields', tuple(range(15))), + ('warnings', 'Warnings', (16,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.reset_variables() + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + self.bit_width = float(self.samplerate) / float(self.options['bitrate']) + self.sample_point = (self.bit_width / 100.0) * self.options['sample_point'] + + # Generic helper for CAN bit annotations. + def putg(self, ss, es, data): + left, right = int(self.sample_point), int(self.bit_width - self.sample_point) + self.put(ss - left, es + right, self.out_ann, data) + + # Single-CAN-bit annotation using the current samplenum. + def putx(self, data): + self.putg(self.samplenum, self.samplenum, data) + + # Single-CAN-bit annotation using the samplenum of CAN bit 12. + def put12(self, data): + self.putg(self.ss_bit12, self.ss_bit12, data) + + # Multi-CAN-bit annotation from self.ss_block to current samplenum. + def putb(self, data): + self.putg(self.ss_block, self.samplenum, data) + + def reset_variables(self): + self.state = 'IDLE' + self.sof = self.frame_type = self.dlc = None + self.rawbits = [] # All bits, including stuff bits + self.bits = [] # Only actual CAN frame bits (no stuff bits) + self.curbit = 0 # Current bit of CAN frame (bit 0 == SOF) + self.last_databit = 999 # Positive value that bitnum+x will never match + self.ss_block = None + self.ss_bit12 = None + self.ss_databytebits = [] + + # Poor man's clock synchronization. Use signal edges which change to + # dominant state in rather simple ways. This naive approach is neither + # aware of the SYNC phase's width nor the specific location of the edge, + # but improves the decoder's reliability when the input signal's bitrate + # does not exactly match the nominal rate. + def dom_edge_seen(self, force = False): + self.dom_edge_snum = self.samplenum + self.dom_edge_bcount = self.curbit + + def bit_sampled(self): + # EMPTY + pass + + # Determine the position of the next desired bit's sample point. + def get_sample_point(self, bitnum): + samplenum = self.dom_edge_snum + samplenum += int(self.bit_width * (bitnum - self.dom_edge_bcount)) + samplenum += int(self.sample_point) + return samplenum + + def is_stuff_bit(self): + # CAN uses NRZ encoding and bit stuffing. + # After 5 identical bits, a stuff bit of opposite value is added. + # But not in the CRC delimiter, ACK, and end of frame fields. + if len(self.bits) > self.last_databit + 17: + return False + last_6_bits = self.rawbits[-6:] + if last_6_bits not in ([0, 0, 0, 0, 0, 1], [1, 1, 1, 1, 1, 0]): + return False + + # Stuff bit. Keep it in self.rawbits, but drop it from self.bits. + self.bits.pop() # Drop last bit. + return True + + def is_valid_crc(self, crc_bits): + return True # TODO + + def decode_error_frame(self, bits): + pass # TODO + + def decode_overload_frame(self, bits): + pass # TODO + + # Both standard and extended frames end with CRC, CRC delimiter, ACK, + # ACK delimiter, and EOF fields. Handle them in a common function. + # Returns True if the frame ended (EOF), False otherwise. + def decode_frame_end(self, can_rx, bitnum): + + # Remember start of CRC sequence (see below). + if bitnum == (self.last_databit + 1): + self.ss_block = self.samplenum + + # CRC sequence (15 bits) + elif bitnum == (self.last_databit + 15): + x = self.last_databit + 1 + crc_bits = self.bits[x:x + 15 + 1] + self.crc = int(''.join(str(d) for d in crc_bits), 2) + self.putb([11, ['CRC sequence: 0x%04x' % self.crc, + 'CRC: 0x%04x' % self.crc, 'CRC']]) + if not self.is_valid_crc(crc_bits): + self.putb([16, ['CRC is invalid']]) + + # CRC delimiter bit (recessive) + elif bitnum == (self.last_databit + 16): + self.putx([12, ['CRC delimiter: %d' % can_rx, + 'CRC d: %d' % can_rx, 'CRC d']]) + if can_rx != 1: + self.putx([16, ['CRC delimiter must be a recessive bit']]) + + # ACK slot bit (dominant: ACK, recessive: NACK) + elif bitnum == (self.last_databit + 17): + ack = 'ACK' if can_rx == 0 else 'NACK' + self.putx([13, ['ACK slot: %s' % ack, 'ACK s: %s' % ack, 'ACK s']]) + + # ACK delimiter bit (recessive) + elif bitnum == (self.last_databit + 18): + self.putx([14, ['ACK delimiter: %d' % can_rx, + 'ACK d: %d' % can_rx, 'ACK d']]) + if can_rx != 1: + self.putx([16, ['ACK delimiter must be a recessive bit']]) + + # Remember start of EOF (see below). + elif bitnum == (self.last_databit + 19): + self.ss_block = self.samplenum + + # End of frame (EOF), 7 recessive bits + elif bitnum == (self.last_databit + 25): + self.putb([2, ['End of frame', 'EOF', 'E']]) + if self.rawbits[-7:] != [1, 1, 1, 1, 1, 1, 1]: + self.putb([16, ['End of frame (EOF) must be 7 recessive bits']]) + self.reset_variables() + return True + + return False + + # Returns True if the frame ended (EOF), False otherwise. + def decode_standard_frame(self, can_rx, bitnum): + + # Bit 14: RB0 (reserved bit) + # Has to be sent dominant, but receivers should accept recessive too. + if bitnum == 14: + self.putx([7, ['Reserved bit 0: %d' % can_rx, + 'RB0: %d' % can_rx, 'RB0']]) + + # Bit 12: Remote transmission request (RTR) bit + # Data frame: dominant, remote frame: recessive + # Remote frames do not contain a data field. + rtr = 'remote' if self.bits[12] == 1 else 'data' + self.put12([8, ['Remote transmission request: %s frame' % rtr, + 'RTR: %s frame' % rtr, 'RTR']]) + + # Remember start of DLC (see below). + elif bitnum == 15: + self.ss_block = self.samplenum + + # Bits 15-18: Data length code (DLC), in number of bytes (0-8). + elif bitnum == 18: + self.dlc = int(''.join(str(d) for d in self.bits[15:18 + 1]), 2) + self.putb([10, ['Data length code: %d' % self.dlc, + 'DLC: %d' % self.dlc, 'DLC']]) + self.last_databit = 18 + (self.dlc * 8) + if self.dlc > 8: + self.putb([16, ['Data length code (DLC) > 8 is not allowed']]) + + # Remember all databyte bits, except the very last one. + elif bitnum in range(19, self.last_databit): + self.ss_databytebits.append(self.samplenum) + + # Bits 19-X: Data field (0-8 bytes, depending on DLC) + # The bits within a data byte are transferred MSB-first. + elif bitnum == self.last_databit: + self.ss_databytebits.append(self.samplenum) # Last databyte bit. + for i in range(self.dlc): + x = 18 + (8 * i) + 1 + b = int(''.join(str(d) for d in self.bits[x:x + 8]), 2) + ss = self.ss_databytebits[i * 8] + es = self.ss_databytebits[((i + 1) * 8) - 1] + self.putg(ss, es, [0, ['Data byte %d: 0x%02x' % (i, b), + 'DB %d: 0x%02x' % (i, b), 'DB']]) + self.ss_databytebits = [] + + elif bitnum > self.last_databit: + return self.decode_frame_end(can_rx, bitnum) + + return False + + # Returns True if the frame ended (EOF), False otherwise. + def decode_extended_frame(self, can_rx, bitnum): + + # Remember start of EID (see below). + if bitnum == 14: + self.ss_block = self.samplenum + + # Bits 14-31: Extended identifier (EID[17..0]) + elif bitnum == 31: + self.eid = int(''.join(str(d) for d in self.bits[14:]), 2) + s = '%d (0x%x)' % (self.eid, self.eid) + self.putb([4, ['Extended Identifier: %s' % s, + 'Extended ID: %s' % s, 'Extended ID', 'EID']]) + + self.fullid = self.id << 18 | self.eid + s = '%d (0x%x)' % (self.fullid, self.fullid) + self.putb([5, ['Full Identifier: %s' % s, 'Full ID: %s' % s, + 'Full ID', 'FID']]) + + # Bit 12: Substitute remote request (SRR) bit + self.put12([9, ['Substitute remote request: %d' % self.bits[12], + 'SRR: %d' % self.bits[12], 'SRR']]) + + # Bit 32: Remote transmission request (RTR) bit + # Data frame: dominant, remote frame: recessive + # Remote frames do not contain a data field. + if bitnum == 32: + rtr = 'remote' if can_rx == 1 else 'data' + self.putx([8, ['Remote transmission request: %s frame' % rtr, + 'RTR: %s frame' % rtr, 'RTR']]) + + # Bit 33: RB1 (reserved bit) + elif bitnum == 33: + self.putx([7, ['Reserved bit 1: %d' % can_rx, + 'RB1: %d' % can_rx, 'RB1']]) + + # Bit 34: RB0 (reserved bit) + elif bitnum == 34: + self.putx([7, ['Reserved bit 0: %d' % can_rx, + 'RB0: %d' % can_rx, 'RB0']]) + + # Remember start of DLC (see below). + elif bitnum == 35: + self.ss_block = self.samplenum + + # Bits 35-38: Data length code (DLC), in number of bytes (0-8). + elif bitnum == 38: + self.dlc = int(''.join(str(d) for d in self.bits[35:38 + 1]), 2) + self.putb([10, ['Data length code: %d' % self.dlc, + 'DLC: %d' % self.dlc, 'DLC']]) + self.last_databit = 38 + (self.dlc * 8) + + # Remember all databyte bits, except the very last one. + elif bitnum in range(39, self.last_databit): + self.ss_databytebits.append(self.samplenum) + + # Bits 39-X: Data field (0-8 bytes, depending on DLC) + # The bits within a data byte are transferred MSB-first. + elif bitnum == self.last_databit: + self.ss_databytebits.append(self.samplenum) # Last databyte bit. + for i in range(self.dlc): + x = 38 + (8 * i) + 1 + b = int(''.join(str(d) for d in self.bits[x:x + 8]), 2) + ss = self.ss_databytebits[i * 8] + es = self.ss_databytebits[((i + 1) * 8) - 1] + self.putg(ss, es, [0, ['Data byte %d: 0x%02x' % (i, b), + 'DB %d: 0x%02x' % (i, b), 'DB']]) + self.ss_databytebits = [] + + elif bitnum > self.last_databit: + return self.decode_frame_end(can_rx, bitnum) + + return False + + def handle_bit(self, can_rx): + self.rawbits.append(can_rx) + self.bits.append(can_rx) + + # Get the index of the current CAN frame bit (without stuff bits). + bitnum = len(self.bits) - 1 + + # If this is a stuff bit, remove it from self.bits and ignore it. + if self.is_stuff_bit(): + self.putx([15, [str(can_rx)]]) + self.curbit += 1 # Increase self.curbit (bitnum is not affected). + return + else: + self.putx([17, [str(can_rx)]]) + + # Bit 0: Start of frame (SOF) bit + if bitnum == 0: + self.putx([1, ['Start of frame', 'SOF', 'S']]) + if can_rx != 0: + self.putx([16, ['Start of frame (SOF) must be a dominant bit']]) + + # Remember start of ID (see below). + elif bitnum == 1: + self.ss_block = self.samplenum + + # Bits 1-11: Identifier (ID[10..0]) + # The bits ID[10..4] must NOT be all recessive. + elif bitnum == 11: + self.id = int(''.join(str(d) for d in self.bits[1:]), 2) + s = '%d (0x%x)' % (self.id, self.id), + self.putb([3, ['Identifier: %s' % s, 'ID: %s' % s, 'ID']]) + if (self.id & 0x7f0) == 0x7f0: + self.putb([16, ['Identifier bits 10..4 must not be all recessive']]) + + # RTR or SRR bit, depending on frame type (gets handled later). + elif bitnum == 12: + # self.putx([0, ['RTR/SRR: %d' % can_rx]]) # Debug only. + self.ss_bit12 = self.samplenum + + # Bit 13: Identifier extension (IDE) bit + # Standard frame: dominant, extended frame: recessive + elif bitnum == 13: + ide = self.frame_type = 'standard' if can_rx == 0 else 'extended' + self.putx([6, ['Identifier extension bit: %s frame' % ide, + 'IDE: %s frame' % ide, 'IDE']]) + + # Bits 14-X: Frame-type dependent, passed to the resp. handlers. + elif bitnum >= 14: + if self.frame_type == 'standard': + done = self.decode_standard_frame(can_rx, bitnum) + else: + done = self.decode_extended_frame(can_rx, bitnum) + + # The handlers return True if a frame ended (EOF). + if done: + return + + # After a frame there are 3 intermission bits (recessive). + # After these bits, the bus is considered free. + + self.curbit += 1 + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + + while True: + # State machine. + if self.state == 'IDLE': + # Wait for a dominant state (logic 0) on the bus. + (can_rx,) = self.wait({0: 'l'}) + self.sof = self.samplenum + self.dom_edge_seen(force = True) + self.state = 'GET BITS' + elif self.state == 'GET BITS': + # Wait until we're in the correct bit/sampling position. + pos = self.get_sample_point(self.curbit) + (can_rx,) = self.wait([{'skip': pos - self.samplenum}, {0: 'f'}]) + if (self.matched & (0b1 << 1)): + self.dom_edge_seen() + if (self.matched & (0b1 << 0)): + self.handle_bit(can_rx) + self.bit_sampled() diff --git a/libsigrokdecode4DSL/decoders/cc1101/__init__.py b/libsigrokdecode4DSL/decoders/cc1101/__init__.py new file mode 100644 index 00000000..68fc7987 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/cc1101/__init__.py @@ -0,0 +1,28 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Marco Geisler +## +## 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, see . +## + +''' +This decoder stacks on top of the 'spi' PD and decodes the protocol spoken +by the Texas Instruments low-power sub-1GHz RF transceiver chips. + +Details: +http://www.ti.com/lit/ds/symlink/cc1101.pdf +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/cc1101/lists.py b/libsigrokdecode4DSL/decoders/cc1101/lists.py new file mode 100644 index 00000000..dfb9b07f --- /dev/null +++ b/libsigrokdecode4DSL/decoders/cc1101/lists.py @@ -0,0 +1,115 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Marco Geisler +## +## 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, see . +## + +regs = { +# addr: 'name' + 0x00: 'IOCFG2', + 0x01: 'IOCFG1', + 0x02: 'IOCFG0', + 0x03: 'FIFOTHR', + 0x04: 'SYNC1', + 0x05: 'SYNC0', + 0x06: 'PKTLEN', + 0x07: 'PKTCTRL1', + 0x08: 'PKTCTRL0', + 0x09: 'ADDR', + 0x0A: 'CHANNR', + 0x0B: 'FSCTRL1', + 0x0C: 'FSCTRL0', + 0x0D: 'FREQ2', + 0x0E: 'FREQ1', + 0x0F: 'FREQ0', + 0x10: 'MDMCFG4', + 0x11: 'MDMCFG3', + 0x12: 'MDMCFG2', + 0x13: 'MDMCFG1', + 0x14: 'MDMCFG0', + 0x15: 'DEVIATN', + 0x16: 'MCSM2', + 0x17: 'MCSM1', + 0x18: 'MCSM0', + 0x19: 'FOCCFG', + 0x1A: 'BSCFG', + 0x1B: 'AGCTRL2', + 0x1C: 'AGCTRL1', + 0x1D: 'AGCTRL0', + 0x1E: 'WOREVT1', + 0x1F: 'WOREVT0', + 0x20: 'WORCTRL', + 0x21: 'FREND1', + 0x22: 'FREND0', + 0x23: 'FSCAL3', + 0x24: 'FSCAL2', + 0x25: 'FSCAL1', + 0x26: 'FSCAL0', + 0x27: 'RCCTRL1', + 0x28: 'RCCTRL0', + 0x29: 'FSTEST', + 0x2A: 'PTEST', + 0x2B: 'AGCTEST', + 0x2C: 'TEST2', + 0x2D: 'TEST1', + 0x2E: 'TEST0', + 0x30: 'PARTNUM', + 0x31: 'VERSION', + 0x32: 'FREQEST', + 0x33: 'LQI', + 0x34: 'RSSI', + 0x35: 'MARCSTATE', + 0x36: 'WORTIME1', + 0x37: 'WORTIME0', + 0x38: 'PKTSTATUS', + 0x39: 'VCO_VC_DAC', + 0x3A: 'TXBYTES', + 0x3B: 'RXBYTES', + 0x3C: 'RCCTRL1_STATUS', + 0x3D: 'RCCTRL0_STATUS', + 0x3E: 'PATABLE', + 0x3F: 'FIFO' +} + +strobes = { +# addr: 'name' + 0x30: 'SRES', + 0x31: 'SFSTXON', + 0x32: 'SXOFF', + 0x33: 'SCAL', + 0x34: 'SRX', + 0x35: 'STX', + 0x36: 'SIDLE', + 0x37: '', + 0x38: 'SWOR', + 0x39: 'SPWD', + 0x3A: 'SFRX', + 0x3B: 'SFTX', + 0x3C: 'SWORRST', + 0x3D: 'SNOP' +} + +status_reg_states = { +# value: 'state name' + 0b000: 'IDLE', + 0b001: 'RX', + 0b010: 'TX', + 0b011: 'FSTXON', + 0b100: 'CALIBRATE', + 0b101: 'SETTLING', + 0b110: 'RXFIFO_OVERFLOW', + 0b111: 'TXFIFO_OVERFLOW' +} diff --git a/libsigrokdecode4DSL/decoders/cc1101/pd.py b/libsigrokdecode4DSL/decoders/cc1101/pd.py new file mode 100644 index 00000000..8407b510 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/cc1101/pd.py @@ -0,0 +1,296 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Marco Geisler +## +## 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, see . +## + +import sigrokdecode as srd +from collections import namedtuple +from .lists import * + +ANN_STROBE, ANN_SINGLE_READ, ANN_SINGLE_WRITE, ANN_BURST_READ, \ + ANN_BURST_WRITE, ANN_STATUS_READ, ANN_STATUS, ANN_WARN = range(8) + +Pos = namedtuple('Pos', ['ss', 'es']) +Data = namedtuple('Data', ['mosi', 'miso']) + +class ChannelError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = 'cc1101' + name = 'CC1101' + longname = 'Texas Instruments CC1101' + desc = 'Low-power sub-1GHz RF transceiver chip.' + license = 'gplv2+' + inputs = ['spi'] + outputs = [] + tags = ['IC', 'Wireless/RF'] + annotations = ( + ('strobe', 'Command strobe'), + ('single_read', 'Single register read'), + ('single_write', 'Single register write'), + ('burst_read', 'Burst register read'), + ('burst_write', 'Burst register write'), + ('status', 'Status register'), + ('warning', 'Warning'), + ) + annotation_rows = ( + ('cmd', 'Commands', (ANN_STROBE,)), + ('data', 'Data', (ANN_SINGLE_READ, ANN_SINGLE_WRITE, ANN_BURST_READ, + ANN_BURST_WRITE, ANN_STATUS_READ)), + ('status', 'Status register', (ANN_STATUS,)), + ('warnings', 'Warnings', (ANN_WARN,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.next() + self.requirements_met = True + self.cs_was_released = False + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def warn(self, pos, msg): + '''Put a warning message 'msg' at 'pos'.''' + self.put(pos.ss, pos.es, self.out_ann, [ANN_WARN, [msg]]) + + def putp(self, pos, ann, msg): + '''Put an annotation message 'msg' at 'pos'.''' + self.put(pos.ss, pos.es, self.out_ann, [ann, [msg]]) + + def putp2(self, pos, ann, msg1, msg2): + '''Put an annotation message 'msg' at 'pos'.''' + self.put(pos.ss, pos.es, self.out_ann, [ann, [msg1, msg2]]) + + def next(self): + '''Resets the decoder after a complete command was decoded.''' + # 'True' for the first byte after CS# went low. + self.first = True + + # The current command, and the minimum and maximum number + # of data bytes to follow. + self.cmd = None + self.min = 0 + self.max = 0 + + # Used to collect the bytes after the command byte + # (and the start/end sample number). + self.mb = [] + self.ss_mb = -1 + self.es_mb = -1 + + def mosi_bytes(self): + '''Returns the collected MOSI bytes of a multi byte command.''' + return [b.mosi for b in self.mb] + + def miso_bytes(self): + '''Returns the collected MISO bytes of a multi byte command.''' + return [b.miso for b in self.mb] + + def decode_command(self, pos, b): + '''Decodes the command byte 'b' at position 'pos' and prepares + the decoding of the following data bytes.''' + c = self.parse_command(b) + if c is None: + self.warn(pos, 'unknown command') + return + + self.cmd, self.dat, self.min, self.max = c + + if self.cmd == 'Strobe': + self.putp(pos, ANN_STROBE, self.format_command()) + else: + # Don't output anything now, the command is merged with + # the data bytes following it. + self.ss_mb = pos.ss + + def format_command(self): + '''Returns the label for the current command.''' + if self.cmd in ('Read', 'Burst read', 'Write', 'Burst write', 'Status read'): + return self.cmd + if self.cmd == 'Strobe': + reg = strobes.get(self.dat, 'unknown strobe') + return '{} {}'.format(self.cmd, reg) + else: + return 'TODO Cmd {}'.format(self.cmd) + + def parse_command(self, b): + '''Parses the command byte. + + Returns a tuple consisting of: + - the name of the command + - additional data needed to dissect the following bytes + - minimum number of following bytes + - maximum number of following bytes (None for infinite) + ''' + + addr = b & 0x3F + if (addr < 0x30) or (addr == 0x3E) or (addr == 0x3F): + if (b & 0xC0) == 0x00: + return ('Write', addr, 1, 1) + if (b & 0xC0) == 0x40: + return ('Burst write', addr, 1, 99999) + if (b & 0xC0) == 0x80: + return ('Read', addr, 1, 1) + if (b & 0xC0) == 0xC0: + return ('Burst read', addr, 1, 99999) + else: + self.warn(pos, 'unknown address/command combination') + else: + if (b & 0x40) == 0x00: + return ('Strobe', addr, 0, 0) + if (b & 0xC0) == 0xC0: + return ('Status read', addr, 1, 99999) + else: + self.warn(pos, 'unknown address/command combination') + + def decode_reg(self, pos, ann, regid, data): + '''Decodes a register. + + pos -- start and end sample numbers of the register + ann -- the annotation number that is used to output the register. + regid -- may be either an integer used as a key for the 'regs' + dictionary, or a string directly containing a register name.' + data -- the register content. + ''' + + if type(regid) == int: + # Get the name of the register. + if regid not in regs: + self.warn(pos, 'unknown register') + return + name = '{} ({:02X})'.format(regs[regid], regid) + else: + name = regid + + if regid == 'STATUS' and ann == ANN_STATUS: + label = 'Status' + self.decode_status_reg(pos, ann, data, label) + else: + if self.cmd in ('Write', 'Read', 'Status read', 'Burst read', 'Burst write'): + label = '{}: {}'.format(self.format_command(), name) + else: + label = 'Reg ({}) {}'.format(self.cmd, name) + self.decode_mb_data(pos, ann, data, label) + + def decode_status_reg(self, pos, ann, data, label): + '''Decodes the data bytes 'data' of a status register at position + 'pos'. The decoded data is prefixed with 'label'.''' + status = data[0] + # bit 7 --> CHIP_RDYn + if status & 0b10000000 == 0b10000000: + longtext_chiprdy = 'CHIP_RDYn is high! ' + else: + longtext_chiprdy = '' + # bits 6:4 --> STATE + state = (status & 0x70) >> 4 + longtext_state = 'STATE is {}, '.format(status_reg_states[state]) + # bits 3:0 --> FIFO_BYTES_AVAILABLE + fifo_bytes = status & 0x0F + if self.cmd in ('Single read', 'Status read', 'Burst read'): + longtext_fifo = '{} bytes available in RX FIFO'.format(fifo_bytes) + else: + longtext_fifo = '{} bytes free in TX FIFO'.format(fifo_bytes) + + text = '{} = {:02X}'.format(label, status) + longtext = ''.join([text, '; ', longtext_chiprdy, longtext_state, longtext_fifo]) + self.putp2(pos, ann, longtext, text) + + def decode_mb_data(self, pos, ann, data, label): + '''Decodes the data bytes 'data' of a multibyte command at position + 'pos'. The decoded data is prefixed with 'label'.''' + + def escape(b): + return '{:02X}'.format(b) + + data = ' '.join([escape(b) for b in data]) + text = '{} = {}'.format(label, data) + self.putp(pos, ann, text) + + def finish_command(self, pos): + '''Decodes the remaining data bytes at position 'pos'.''' + + if self.cmd == 'Write': + self.decode_reg(pos, ANN_SINGLE_WRITE, self.dat, self.mosi_bytes()) + elif self.cmd == 'Burst write': + self.decode_reg(pos, ANN_BURST_WRITE, self.dat, self.mosi_bytes()) + elif self.cmd == 'Read': + self.decode_reg(pos, ANN_SINGLE_READ, self.dat, self.miso_bytes()) + elif self.cmd == 'Burst read': + self.decode_reg(pos, ANN_BURST_READ, self.dat, self.miso_bytes()) + elif self.cmd == 'Strobe': + self.decode_reg(pos, ANN_STROBE, self.dat, self.mosi_bytes()) + elif self.cmd == 'Status read': + self.decode_reg(pos, ANN_STATUS_READ, self.dat, self.miso_bytes()) + else: + self.warn(pos, 'unhandled command') + + def decode(self, ss, es, data): + if not self.requirements_met: + return + + ptype, data1, data2 = data + + if ptype == 'CS-CHANGE': + if data1 is None: + if data2 is None: + self.requirements_met = False + raise ChannelError('CS# pin required.') + elif data2 == 1: + self.cs_was_released = True + + if data1 == 0 and data2 == 1: + # Rising edge, the complete command is transmitted, process + # the bytes that were sent after the command byte. + if self.cmd: + # Check if we got the minimum number of data bytes + # after the command byte. + if len(self.mb) < self.min: + self.warn((ss, ss), 'missing data bytes') + elif self.mb: + self.finish_command(Pos(self.ss_mb, self.es_mb)) + + self.next() + self.cs_was_released = True + + elif ptype == 'DATA' and self.cs_was_released: + mosi, miso = data1, data2 + pos = Pos(ss, es) + + if miso is None or mosi is None: + self.requirements_met = False + raise ChannelError('Both MISO and MOSI pins required.') + + if self.first: + self.first = False + # First MOSI byte is always the command. + self.decode_command(pos, mosi) + # First MISO byte is always the status register. + self.decode_reg(pos, ANN_STATUS, 'STATUS', [miso]) + else: + if not self.cmd or len(self.mb) >= self.max: + self.warn(pos, 'excess byte') + else: + # Collect the bytes after the command byte. + if self.ss_mb == -1: + self.ss_mb = ss + self.es_mb = es + self.mb.append(Data(mosi, miso)) diff --git a/libsigrokdecode4DSL/decoders/cec/__init__.py b/libsigrokdecode4DSL/decoders/cec/__init__.py new file mode 100644 index 00000000..4138b62b --- /dev/null +++ b/libsigrokdecode4DSL/decoders/cec/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Jorge Solla Rubiales +## +## 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, see . +## + +''' +The Consumer Electronics Control (CEC) protocol allows users to command and +control devices connected through HDMI. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/cec/pd.py b/libsigrokdecode4DSL/decoders/cec/pd.py new file mode 100644 index 00000000..363a0497 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/cec/pd.py @@ -0,0 +1,312 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Jorge Solla Rubiales +## Copyright (C) 2019 DreamSourceLab +## +## 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, see . +## + +import sigrokdecode as srd +from .protocoldata import * + +# Pulse types +class Pulse: + INVALID, START, ZERO, ONE = range(4) + +# Protocol stats +class Stat: + WAIT_START, GET_BITS, WAIT_EOM, WAIT_ACK = range(4) + +# Pulse times in milliseconds +timing = { + Pulse.START: { + 'low': { 'min': 3.5, 'max': 3.9 }, + 'total': { 'min': 4.3, 'max': 4.7 } + }, + Pulse.ZERO: { + 'low': { 'min': 1.3, 'max': 1.7 }, + 'total': { 'min': 2.05, 'max': 2.75 } + }, + Pulse.ONE: { + 'low': { 'min': 0.4, 'max': 0.8 }, + 'total': { 'min': 2.05, 'max': 2.75 } + } +} + +class ChannelError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = 'cec' + name = 'CEC' + longname = 'HDMI-CEC' + desc = 'HDMI Consumer Electronics Control (CEC) protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Display', 'PC'] + channels = ( + {'id': 'cec', 'name': 'CEC', 'desc': 'CEC bus data'}, + ) + annotations = ( + ('st', 'Start'), + ('eom-0', 'End of message'), + ('eom-1', 'Message continued'), + ('nack', 'ACK not set'), + ('ack', 'ACK set'), + ('bits', 'Bits'), + ('bytes', 'Bytes'), + ('frames', 'Frames'), + ('sections', 'Sections'), + ('warnings', 'Warnings') + ) + annotation_rows = ( + ('bits', 'Bits', (0, 1, 2, 3, 4, 5)), + ('bytes', 'Bytes', (6,)), + ('frames', 'Frames', (7,)), + ('sections', 'Sections', (8,)), + ('warnings', 'Warnings', (9,)) + ) + + def __init__(self): + self.reset() + + def precalculate(self): + # Restrict max length of ACK/NACK labels to 2 BIT pulses. + bit_time = timing[Pulse.ZERO]['total']['min'] * 2 + self.max_ack_len_samples = round((bit_time / 1000) * self.samplerate) + + def reset(self): + self.stat = Stat.WAIT_START + self.samplerate = None + self.fall_start = None + self.fall_end = None + self.rise = None + self.reset_frame_vars() + + def reset_frame_vars(self): + self.eom = None + self.bit_count = 0 + self.byte_count = 0 + self.byte = 0 + self.byte_start = None + self.frame_start = None + self.frame_end = None + self.is_nack = 0 + self.cmd_bytes = [] + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + self.precalculate() + + def handle_frame(self, is_nack): + if self.fall_start is None or self.fall_end is None: + return + + i = 0 + string = '' + while i < len(self.cmd_bytes): + string += '{:02x}'.format(self.cmd_bytes[i]['val']) + if i != (len(self.cmd_bytes) - 1): + string += ':' + i += 1 + + self.put(self.frame_start, self.frame_end, self.out_ann, [7, [string]]) + + i = 0 + operands = 0 + string = '' + while i < len(self.cmd_bytes): + if i == 0: # Parse header + (src, dst) = decode_header(self.cmd_bytes[i]['val']) + string = 'HDR: ' + src + ', ' + dst + elif i == 1: # Parse opcode + string += ' | OPC: ' + opcodes.get(self.cmd_bytes[i]['val'], 'Invalid') + else: # Parse operands + if operands == 0: + string += ' | OPS: ' + operands += 1 + string += '0x{:02x}'.format(self.cmd_bytes[i]['val']) + if i != len(self.cmd_bytes) - 1: + string += ', ' + i += 1 + + # Header only commands are PINGS + if i == 1: + string += ' | OPC: PING' if self.eom else ' | OPC: NONE. Aborted cmd' + + # Add extra information (ack of the command from the destination) + string += ' | R: NACK' if is_nack else ' | R: ACK' + + self.put(self.frame_start, self.frame_end, self.out_ann, [8, [string]]) + + def process(self): + zero_time = ((self.rise - self.fall_start) / self.samplerate) * 1000.0 + total_time = ((self.fall_end - self.fall_start) / self.samplerate) * 1000.0 + pulse = Pulse.INVALID + + # VALIDATION: Identify pulse based on length of the low period + for key in timing: + if zero_time >= timing[key]['low']['min'] and zero_time <= timing[key]['low']['max']: + pulse = key + break + + # VALIDATION: Invalid pulse + if pulse == Pulse.INVALID: + self.stat = Stat.WAIT_START + self.put(self.fall_start, self.fall_end, self.out_ann, [9, ['Invalid pulse: Wrong timing']]) + return + + # VALIDATION: If waiting for start, discard everything else + if self.stat == Stat.WAIT_START and pulse != Pulse.START: + self.put(self.fall_start, self.fall_end, self.out_ann, [9, ['Expected START: BIT found']]) + return + + # VALIDATION: If waiting for ACK or EOM, only BIT pulses (0/1) are expected + if (self.stat == Stat.WAIT_ACK or self.stat == Stat.WAIT_EOM) and pulse == Pulse.START: + self.put(self.fall_start, self.fall_end, self.out_ann, [9, ['Expected BIT: START received)']]) + self.stat = Stat.WAIT_START + + # VALIDATION: ACK bit pulse remains high till the next frame (if any): Validate only min time of the low period + if self.stat == Stat.WAIT_ACK and pulse != Pulse.START: + if total_time < timing[pulse]['total']['min']: + pulse = Pulse.INVALID + self.put(self.fall_start, self.fall_end, self.out_ann, [9, ['ACK pulse below minimun time']]) + self.stat = Stat.WAIT_START + return + + # VALIDATION / PING FRAME DETECTION: Initiator doesn't sets the EOM = 1 but stops sending when ack doesn't arrive + if self.stat == Stat.GET_BITS and pulse == Pulse.START: + # Make sure we received a complete byte to consider it a valid ping + if self.bit_count == 0: + self.handle_frame(self.is_nack) + else: + self.put(self.frame_start, self.samplenum, self.out_ann, [9, ['ERROR: Incomplete byte received']]) + + # Set wait start so we receive next frame + self.stat = Stat.WAIT_START + + # VALIDATION: Check timing of the BIT (0/1) pulse in any other case (not waiting for ACK) + if self.stat != Stat.WAIT_ACK and pulse != Pulse.START: + if total_time < timing[pulse]['total']['min'] or total_time > timing[pulse]['total']['max']: + self.put(self.fall_start, self.fall_end, self.out_ann, [9, ['Bit pulse exceeds total pulse timespan']]) + pulse = Pulse.INVALID + self.stat = Stat.WAIT_START + return + + if pulse == Pulse.ZERO: + bit = 0 + elif pulse == Pulse.ONE: + bit = 1 + + # STATE: WAIT START + if self.stat == Stat.WAIT_START: + self.stat = Stat.GET_BITS + self.reset_frame_vars() + self.put(self.fall_start, self.fall_end, self.out_ann, [0, ['ST']]) + + # STATE: GET BITS + elif self.stat == Stat.GET_BITS: + # Reset stats on first bit + if self.bit_count == 0: + self.byte_start = self.fall_start + self.byte = 0 + + # If 1st byte of the datagram save its sample num + if len(self.cmd_bytes) == 0: + self.frame_start = self.fall_start + + self.byte += (bit << (7 - self.bit_count)) + self.bit_count += 1 + self.put(self.fall_start, self.fall_end, self.out_ann, [5, [str(bit)]]) + + if self.bit_count == 8: + self.bit_count = 0 + self.byte_count += 1 + self.stat = Stat.WAIT_EOM + self.put(self.byte_start, self.samplenum, self.out_ann, [6, ['0x{:02x}'.format(self.byte)]]) + self.cmd_bytes.append({'st': self.byte_start, 'ed': self.samplenum, 'val': self.byte}) + + # STATE: WAIT EOM + elif self.stat == Stat.WAIT_EOM: + self.eom = bit + self.frame_end = self.fall_end + + a = [2, ['EOM=Y']] if self.eom else [1, ['EOM=N']] + self.put(self.fall_start, self.fall_end, self.out_ann, a) + + self.stat = Stat.WAIT_ACK + + # STATE: WAIT ACK + elif self.stat == Stat.WAIT_ACK: + # If a frame with broadcast destination is being sent, the ACK is + # inverted: a 0 is considered a NACK, therefore we invert the value + # of the bit here, so we match the real meaning of it. + if (self.cmd_bytes[0]['val'] & 0x0F) == 0x0F: + bit = ~bit & 0x01 + + if (self.fall_end - self.fall_start) > self.max_ack_len_samples: + ann_end = self.fall_start + self.max_ack_len_samples + else: + ann_end = self.fall_end + + if bit: + # Any NACK detected in the frame is enough to consider the + # whole frame NACK'd. + self.is_nack = 1 + self.put(self.fall_start, ann_end, self.out_ann, [3, ['NACK']]) + else: + self.put(self.fall_start, ann_end, self.out_ann, [4, ['ACK']]) + + # After ACK bit, wait for new datagram or continue reading current + # one based on EOM value. + if self.eom or self.is_nack: + self.stat = Stat.WAIT_START + self.handle_frame(self.is_nack) + else: + self.stat = Stat.GET_BITS + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + + # Wait for first falling edge. + self.wait({0: 'f'}) + self.fall_end = self.samplenum + + while True: + self.wait({0: 'r'}) + self.rise = self.samplenum + + if self.stat == Stat.WAIT_ACK: + self.wait([{0: 'f'}, {'skip': self.max_ack_len_samples}]) + else: + self.wait([{0: 'f'}]) + + self.fall_start = self.fall_end + self.fall_end = self.samplenum + self.process() + + # If there was a timeout while waiting for ACK: RESYNC. + # Note: This is an expected situation as no new falling edge will + # happen until next frame is transmitted. + if self.matched == 0b10: + self.wait({0: 'f'}) + self.fall_end = self.samplenum diff --git a/libsigrokdecode4DSL/decoders/cec/protocoldata.py b/libsigrokdecode4DSL/decoders/cec/protocoldata.py new file mode 100644 index 00000000..78c3b6f5 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/cec/protocoldata.py @@ -0,0 +1,117 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Jorge Solla Rubiales +## +## 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, see . +## + +logical_adresses = [ + 'TV', + 'Recording_1', + 'Recording_2', + 'Tuner_1', + 'Playback_1', + 'AudioSystem', + 'Tuner2', + 'Tuner3', + 'Playback_2', + 'Recording_3', + 'Tuner_4', + 'Playback_3', + 'Backup_1', + 'Backup_2', + 'FreeUse', +] + +# List taken from LibCEC. +opcodes = { + 0x82: 'ACTIVE_SOURCE', + 0x04: 'IMAGE_VIEW_ON', + 0x0D: 'TEXT_VIEW_ON', + 0x9D: 'INACTIVE_SOURCE', + 0x85: 'REQUEST_ACTIVE_SOURCE', + 0x80: 'ROUTING_CHANGE', + 0x81: 'ROUTING_INFORMATION', + 0x86: 'SET_STREAM_PATH', + 0x36: 'STANDBY', + 0x0B: 'RECORD_OFF', + 0x09: 'RECORD_ON', + 0x0A: 'RECORD_STATUS', + 0x0F: 'RECORD_TV_SCREEN', + 0x33: 'CLEAR_ANALOGUE_TIMER', + 0x99: 'CLEAR_DIGITAL_TIMER', + 0xA1: 'CLEAR_EXTERNAL_TIMER', + 0x34: 'SET_ANALOGUE_TIMER', + 0x97: 'SET_DIGITAL_TIMER', + 0xA2: 'SET_EXTERNAL_TIMER', + 0x67: 'SET_TIMER_PROGRAM_TITLE', + 0x43: 'TIMER_CLEARED_STATUS', + 0x35: 'TIMER_STATUS', + 0x9E: 'CEC_VERSION', + 0x9F: 'GET_CEC_VERSION', + 0x83: 'GIVE_PHYSICAL_ADDRESS', + 0x91: 'GET_MENU_LANGUAGE', + 0x84: 'REPORT_PHYSICAL_ADDRESS', + 0x32: 'SET_MENU_LANGUAGE', + 0x42: 'DECK_CONTROL', + 0x1B: 'DECK_STATUS', + 0x1A: 'GIVE_DECK_STATUS', + 0x41: 'PLAY', + 0x08: 'GIVE_TUNER_DEVICE_STATUS', + 0x92: 'SELECT_ANALOGUE_SERVICE', + 0x93: 'SELECT_DIGITAL_SERVICE', + 0x07: 'TUNER_DEVICE_STATUS', + 0x06: 'TUNER_STEP_DECREMENT', + 0x05: 'TUNER_STEP_INCREMENT', + 0x87: 'DEVICE_VENDOR_ID', + 0x8C: 'GIVE_DEVICE_VENDOR_ID', + 0x89: 'VENDOR_COMMAND', + 0xA0: 'VENDOR_COMMAND_WITH_ID', + 0x8A: 'VENDOR_REMOTE_BUTTON_DOWN', + 0x8B: 'VENDOR_REMOTE_BUTTON_UP', + 0x64: 'SET_OSD_STRING', + 0x46: 'GIVE_OSD_NAME', + 0x47: 'SET_OSD_NAME', + 0x8D: 'MENU_REQUEST', + 0x8E: 'MENU_STATUS', + 0x44: 'USER_CONTROL_PRESSED', + 0x45: 'USER_CONTROL_RELEASE', + 0x8F: 'GIVE_DEVICE_POWER_STATUS', + 0x90: 'REPORT_POWER_STATUS', + 0x00: 'FEATURE_ABORT', + 0xFF: 'ABORT', + 0x71: 'GIVE_AUDIO_STATUS', + 0x7D: 'GIVE_SYSTEM_AUDIO_MODE_STATUS', + 0x7A: 'REPORT_AUDIO_STATUS', + 0x72: 'SET_SYSTEM_AUDIO_MODE', + 0x70: 'SYSTEM_AUDIO_MODE_REQUEST', + 0x7E: 'SYSTEM_AUDIO_MODE_STATUS', + 0x9A: 'SET_AUDIO_RATE', +} + +def resolve_logical_address(id_, is_initiator): + if id_ < 0 or id_ > 0x0F: + return 'Invalid' + + # Special handling of 0x0F. + if id_ == 0x0F: + return 'Unregistered' if is_initiator else 'Broadcast' + + return logical_adresses[id_] + +def decode_header(header): + src = (header & 0xF0) >> 4 + dst = (header & 0x0F) + return (resolve_logical_address(src, 1), resolve_logical_address(dst, 0)) diff --git a/libsigrokdecode4DSL/decoders/cfp/__init__.py b/libsigrokdecode4DSL/decoders/cfp/__init__.py new file mode 100644 index 00000000..351e893b --- /dev/null +++ b/libsigrokdecode4DSL/decoders/cfp/__init__.py @@ -0,0 +1,34 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Elias Oenal +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are met: +## +## 1. Redistributions of source code must retain the above copyright notice, +## this list of conditions and the following disclaimer. +## 2. Redistributions in binary form must reproduce the above copyright notice, +## this list of conditions and the following disclaimer in the documentation +## and/or other materials provided with the distribution. +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +## ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +## LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +## POSSIBILITY OF SUCH DAMAGE. +## + +''' +This decoder stacks on top of the 'mdio' PD and decodes the CFP 100G +pluggable transceiver protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/cfp/pd.py b/libsigrokdecode4DSL/decoders/cfp/pd.py new file mode 100644 index 00000000..9638ba19 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/cfp/pd.py @@ -0,0 +1,110 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Elias Oenal +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are met: +## +## 1. Redistributions of source code must retain the above copyright notice, +## this list of conditions and the following disclaimer. +## 2. Redistributions in binary form must reproduce the above copyright notice, +## this list of conditions and the following disclaimer in the documentation +## and/or other materials provided with the distribution. +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +## ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +## LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +## POSSIBILITY OF SUCH DAMAGE. +## + +import sigrokdecode as srd + +MODULE_ID = { + 0x00: 'Unknown or unspecified', + 0x01: 'GBIC', + 0x02: 'Module/connector soldered to motherboard', + 0x03: 'SFP', + 0x04: '300 pin XSBI', + 0x05: 'XENPAK', + 0x06: 'XFP', + 0x07: 'XFF', + 0x08: 'XFP-E', + 0x09: 'XPAK', + 0x0a: 'X2', + 0x0B: 'DWDM-SFP', + 0x0C: 'QSFP', + 0x0D: 'QSFP+', + 0x0E: 'CFP', + 0x0F: 'CXP (TBD)', + 0x11: 'CFP2', + 0x12: 'CFP4', +} + +class Decoder(srd.Decoder): + api_version = 3 + id = 'cfp' + name = 'CFP' + longname = '100 Gigabit C form-factor pluggable' + desc = '100 Gigabit C form-factor pluggable (CFP) protocol.' + license = 'BSD' + inputs = ['mdio'] + outputs = [] + tags = ['Networking'] + annotations = ( + ('register', 'Register'), + ('decode', 'Decode'), + ) + annotation_rows = ( + ('registers', 'Registers', (0,)), + ('decodes', 'Decodes', (1,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + pass + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + self.put(self.ss, self.es, self.out_ann, data) + + def decode(self, ss, es, data): + self.ss, self.es = ss, es + for (clause45, clause45_addr, is_read, portad, devad, reg) in data: + if not is_read: + continue + if clause45_addr in range(0x8000, 0x807F + 1): + self.putx([0, ['CFP NVR 1: Basic ID register', 'NVR1']]) + if clause45_addr == 0x8000: + self.putx([1, ['Module identifier: %s' % \ + MODULE_ID.get(reg, 'Reserved')]]) + elif clause45_addr in range(0x8080, 0x80FF + 1): + self.putx([0, ['CFP NVR 2: Extended ID register', 'NVR2']]) + elif clause45_addr in range(0x8100, 0x817F + 1): + self.putx([0, ['CFP NVR 3: Network lane specific register', 'NVR3']]) + elif clause45_addr in range(0x8180, 0x81FF + 1): + self.putx([0, ['CFP NVR 4', 'NVR4']]) + elif clause45_addr in range(0x8400, 0x847F + 1): + self.putx([0, ['Vendor NVR 1: Vendor data register', 'V-NVR1']]) + elif clause45_addr in range(0x8480, 0x84FF + 1): + self.putx([0, ['Vendor NVR 2: Vendor data register', 'V-NVR2']]) + elif clause45_addr in range(0x8800, 0x887F + 1): + self.putx([0, ['User NVR 1: User data register', 'U-NVR1']]) + elif clause45_addr in range(0x8880, 0x88FF + 1): + self.putx([0, ['User NVR 2: User data register', 'U-NVR2']]) + elif clause45_addr in range(0xA000, 0xA07F + 1): + self.putx([0, ['CFP Module VR 1: CFP Module level control and DDM register', 'Mod-VR1']]) + elif clause45_addr in range(0xA080, 0xA0FF + 1): + self.putx([0, ['MLG VR 1: MLG Management Interface register', 'MLG-VR1']]) diff --git a/libsigrokdecode4DSL/decoders/cjtag-oscan0/__init__.py b/libsigrokdecode4DSL/decoders/cjtag-oscan0/__init__.py new file mode 100644 index 00000000..46444052 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/cjtag-oscan0/__init__.py @@ -0,0 +1,37 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012-2015 Uwe Hermann +## Copyright (C) 2019 Zhiyuan Wan +## Copyright (C) 2019 Kongou Hikari +## +## 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 +## + +''' +JTAG (Joint Test Action Group), a.k.a. "IEEE 1149.1: Standard Test Access Port +and Boundary-Scan Architecture", is a protocol used for testing, debugging, +and flashing various digital ICs. + +Details: +https://en.wikipedia.org/wiki/Joint_Test_Action_Group +http://focus.ti.com/lit/an/ssya002c/ssya002c.pdf + +This decoders handles a tiny part of IEEE 1149.7, the so called CJTAG OSCAN1 +format +http://developers-club.com/posts/237885/ +''' + +from .pd import Decoder \ No newline at end of file diff --git a/libsigrokdecode4DSL/decoders/cjtag-oscan0/pd.py b/libsigrokdecode4DSL/decoders/cjtag-oscan0/pd.py new file mode 100644 index 00000000..44cf89f0 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/cjtag-oscan0/pd.py @@ -0,0 +1,390 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012-2015 Uwe Hermann +## Copyright (C) 2019 DreamSourceLab +## Copyright (C) 2019 Zhiyuan Wan +## Copyright (C) 2019 Kongou Hikari +## +## Version: +## Modified by Shiqiu Nie(369614718@qq.com) +## Date: 2017-01-11 +## Descript: +## 1. 2017-01-10 Fixed TDI/TDO data decode, when JTAG TAP run into +## SHIFT-IR/SHIFT-DR status,the first bit is not a valid bit. +## 2. 2017-01-11 Fixed decode when shift only one bit. +## +## 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, see . +## + +import sigrokdecode as srd + +''' +OUTPUT_PYTHON format: + +Packet: +[, ] + +: + - 'NEW STATE': is the new state of the JTAG state machine. + Valid values: 'TEST-LOGIC-RESET', 'RUN-TEST/IDLE', 'SELECT-DR-SCAN', + 'CAPTURE-DR', 'SHIFT-DR', 'EXIT1-DR', 'PAUSE-DR', 'EXIT2-DR', 'UPDATE-DR', + 'SELECT-IR-SCAN', 'CAPTURE-IR', 'SHIFT-IR', 'EXIT1-IR', 'PAUSE-IR', + 'EXIT2-IR', 'UPDATE-IR'. + - 'IR TDI': Bitstring that was clocked into the IR register. + - 'IR TDO': Bitstring that was clocked out of the IR register. + - 'DR TDI': Bitstring that was clocked into the DR register. + - 'DR TDO': Bitstring that was clocked out of the DR register. + +All bitstrings are a list consisting of two items. The first is a sequence +of '1' and '0' characters (the right-most character is the LSB. Example: +'01110001', where 1 is the LSB). The second item is a list of ss/es values +for each bit that is in the bitstring. +''' + +jtag_states = [ + # Intro "tree" + 'TEST-LOGIC-RESET', 'RUN-TEST/IDLE', + # DR "tree" + 'SELECT-DR-SCAN', 'CAPTURE-DR', 'UPDATE-DR', 'PAUSE-DR', + 'SHIFT-DR', 'EXIT1-DR', 'EXIT2-DR', + # IR "tree" + 'SELECT-IR-SCAN', 'CAPTURE-IR', 'UPDATE-IR', 'PAUSE-IR', + 'SHIFT-IR', 'EXIT1-IR', 'EXIT2-IR', +] + +class Decoder(srd.Decoder): + api_version = 3 + id = 'cjtag_oscan1' + name = 'cJTAG OScan1' + longname = 'Compact Joint Test Action Group (IEEE 1149.7)' + desc = 'Protocol for testing, debugging, and flashing ICs, Now this plugin has no ZBS support, it only supports Oscan1 format.' + license = 'gplv2+' + inputs = ['logic'] + outputs = ['jtag'] + tags = ['Debug/trace'] + channels = ( + {'id': 'tdi', 'name': 'TDI', 'desc': 'Test data input'}, + {'id': 'tdo', 'name': 'TDO', 'desc': 'Test data output'}, + {'id': 'tck', 'name': 'TCK', 'desc': 'Test clock'}, + {'id': 'tms', 'name': 'TMS', 'desc': 'Test mode select'}, + ) + optional_channels = ( + {'id': 'trst', 'name': 'TRST#', 'desc': 'Test reset'}, + {'id': 'srst', 'name': 'SRST#', 'desc': 'System reset'}, + {'id': 'rtck', 'name': 'RTCK', 'desc': 'Return clock signal'}, + ) + annotations = tuple([tuple([s.lower(), s]) for s in jtag_states]) + ( \ + ('bit-tdi', 'Bit (TDI)'), + ('bit-tdo', 'Bit (TDO)'), + ('bitstring-tdi', 'Bitstring (TDI)'), + ('bitstring-tdo', 'Bitstring (TDO)'), + ('bit-tms', 'Bit (TMS)'), + ('state-tapc', 'TAPC State'), + ) + annotation_rows = ( + ('bits-tdi', 'Bits (TDI)', (16,)), + ('bits-tdo', 'Bits (TDO)', (17,)), + ('bitstrings-tdi', 'Bitstring (TDI)', (18,)), + ('bitstrings-tdo', 'Bitstring (TDO)', (19,)), + ('bit-tms', 'Bit (TMS)', (20,)), + ('state-tapc', 'TAPC State', (21,)), + ('states', 'States', tuple(range(15 + 1))), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.state = 'TEST-LOGIC-RESET' + # self.state = 'RUN-TEST/IDLE' + self.cjtagstate = '4-WIRE' + self.oldcjtagstate = None + self.escape_edges = 0 + self.oaclen = 0 + self.oldtms = 0 + self.oacp = 0 + self.oscan1cycle = 0 + self.oldstate = None + self.bits_tdi = [] + self.bits_tdo = [] + self.bits_samplenums_tdi = [] + self.bits_samplenums_tdo = [] + self.ss_item = self.es_item = None + self.ss_bitstring = self.es_bitstring = None + self.saved_item = None + self.first = True + self.first_bit = True + self.bits_cnt = 0 + self.data_ready = False + + def start(self): + self.out_python = self.register(srd.OUTPUT_PYTHON) + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + self.put(self.ss_item, self.es_item, self.out_ann, data) + + def putp(self, data): + self.put(self.ss_item, self.es_item, self.out_python, data) + + def putx_bs(self, data): + self.put(self.ss_bitstring, self.es_bitstring, self.out_ann, data) + + def putp_bs(self, data): + self.put(self.ss_bitstring, self.es_bitstring, self.out_python, data) + + def advance_state_machine(self, tms): + self.oldstate = self.state + + if self.cjtagstate.startswith("CJTAG-"): + self.oacp = self.oacp + 1 + if (self.oacp > 4 and self.oaclen == 12): + self.cjtagstate = 'CJTAG-EC' + + if (self.oacp == 8 and tms == 0): + self.oaclen = 36 + if (self.oacp > 8 and self.oaclen == 36): + self.cjtagstate = 'CJTAG-SPARE' + if (self.oacp > 13 and self.oaclen == 36): + self.cjtagstate = 'CJTAG-TPDEL' + if (self.oacp > 16 and self.oaclen == 36): + self.cjtagstate = 'CJTAG-TPREV' + if (self.oacp > 18 and self.oaclen == 36): + self.cjtagstate = 'CJTAG-TPST' + if (self.oacp > 23 and self.oaclen == 36): + self.cjtagstate = 'CJTAG-RDYC' + if (self.oacp > 25 and self.oaclen == 36): + self.cjtagstate = 'CJTAG-DLYC' + if (self.oacp > 27 and self.oaclen == 36): + self.cjtagstate = 'CJTAG-SCNFMT' + + if (self.oacp > 8 and self.oaclen == 12): + self.cjtagstate = 'CJTAG-CP' + if (self.oacp > 32 and self.oaclen == 36): + self.cjtagstate = 'CJTAG-CP' + + if (self.oacp > self.oaclen): + self.cjtagstate = 'OSCAN1' + self.oscan1cycle = 1 + self.state = 'TEST-LOGIC-RESET' # Because Nuclei cJTAG device asserts a reset during cJTAG online activating. + + else : + # Intro "tree" + if self.state == 'TEST-LOGIC-RESET': + self.state = 'TEST-LOGIC-RESET' if (tms) else 'RUN-TEST/IDLE' + elif self.state == 'RUN-TEST/IDLE': + self.state = 'SELECT-DR-SCAN' if (tms) else 'RUN-TEST/IDLE' + + # DR "tree" + elif self.state == 'SELECT-DR-SCAN': + self.state = 'SELECT-IR-SCAN' if (tms) else 'CAPTURE-DR' + elif self.state == 'CAPTURE-DR': + self.state = 'EXIT1-DR' if (tms) else 'SHIFT-DR' + elif self.state == 'SHIFT-DR': + self.state = 'EXIT1-DR' if (tms) else 'SHIFT-DR' + elif self.state == 'EXIT1-DR': + self.state = 'UPDATE-DR' if (tms) else 'PAUSE-DR' + elif self.state == 'PAUSE-DR': + self.state = 'EXIT2-DR' if (tms) else 'PAUSE-DR' + elif self.state == 'EXIT2-DR': + self.state = 'UPDATE-DR' if (tms) else 'SHIFT-DR' + elif self.state == 'UPDATE-DR': + self.state = 'SELECT-DR-SCAN' if (tms) else 'RUN-TEST/IDLE' + + # IR "tree" + elif self.state == 'SELECT-IR-SCAN': + self.state = 'TEST-LOGIC-RESET' if (tms) else 'CAPTURE-IR' + elif self.state == 'CAPTURE-IR': + self.state = 'EXIT1-IR' if (tms) else 'SHIFT-IR' + elif self.state == 'SHIFT-IR': + self.state = 'EXIT1-IR' if (tms) else 'SHIFT-IR' + elif self.state == 'EXIT1-IR': + self.state = 'UPDATE-IR' if (tms) else 'PAUSE-IR' + elif self.state == 'PAUSE-IR': + self.state = 'EXIT2-IR' if (tms) else 'PAUSE-IR' + elif self.state == 'EXIT2-IR': + self.state = 'UPDATE-IR' if (tms) else 'SHIFT-IR' + elif self.state == 'UPDATE-IR': + self.state = 'SELECT-DR-SCAN' if (tms) else 'RUN-TEST/IDLE' + + def handle_rising_tck_edge(self, tdi, tdo, tck, tms, trst, srst, rtck): + # Rising TCK edges always advance the state machine. + + self.advance_state_machine(tms) + + if self.first: + # Save the start sample and item for later (no output yet). + self.ss_item = self.samplenum + self.first = False + else: + # Output the saved item (from the last CLK edge to the current). + self.es_item = self.samplenum + # Output the old state (from last rising TCK edge to current one). + self.putx([jtag_states.index(self.oldstate), [self.oldstate]]) + self.putp(['NEW STATE', self.state]) + self.putx([21, [self.oldcjtagstate]]) + if(self.oldcjtagstate.startswith("CJTAG-")): + self.putx([20, [str(self.oldtms)]]) + #self.putx([20, [str(tms)]]) + #self.putx([16, [str(tdi)]]) + #self.putx([17, [str(tdo)]]) + self.oldtms = tms + # Upon SHIFT-IR/SHIFT-DR collect the current TDI/TDO values. + if self.state.startswith('SHIFT-'): + #if self.first_bit: + #self.ss_bitstring = self.samplenum + # self.first_bit = False + + #else: + if self.bits_cnt > 0: + if self.bits_cnt == 1: + self.ss_bitstring = self.samplenum + + if self.bits_cnt > 1: + self.putx([16, [str(self.bits_tdi[0])]]) + self.putx([17, [str(self.bits_tdo[0])]]) + # Use self.samplenum as ES of the previous bit. + self.bits_samplenums_tdi[0][1] = self.samplenum + self.bits_samplenums_tdo[0][1] = self.samplenum + + self.bits_tdi.insert(0, tdi) + self.bits_tdo.insert(0, tdo) + + # Use self.samplenum as SS of the current bit. + self.bits_samplenums_tdi.insert(0, [self.samplenum, -1]) + self.bits_samplenums_tdo.insert(0, [self.samplenum, -1]) + + self.bits_cnt = self.bits_cnt + 1 + + # Output all TDI/TDO bits if we just switched from SHIFT-* to EXIT1-*. + if self.oldstate.startswith('SHIFT-') and \ + self.state.startswith('EXIT1-'): + + #self.es_bitstring = self.samplenum + if self.bits_cnt > 0: + if self.bits_cnt == 1: # Only shift one bit + self.ss_bitstring = self.samplenum + self.bits_tdi.insert(0, tdi) + self.bits_tdo.insert(0, tdo) + ## Use self.samplenum as SS of the current bit. + self.bits_samplenums_tdi.insert(0, [self.samplenum, -1]) + self.bits_samplenums_tdo.insert(0, [self.samplenum, -1]) + else: + ### ---------------------------------------------------------------- + self.putx([16, [str(self.bits_tdi[0])]]) + self.putx([17, [str(self.bits_tdo[0])]]) + ### Use self.samplenum as ES of the previous bit. + self.bits_samplenums_tdi[0][1] = self.samplenum + self.bits_samplenums_tdo[0][1] = self.samplenum + + self.bits_tdi.insert(0, tdi) + self.bits_tdo.insert(0, tdo) + + ## Use self.samplenum as SS of the current bit. + self.bits_samplenums_tdi.insert(0, [self.samplenum, -1]) + self.bits_samplenums_tdo.insert(0, [self.samplenum, -1]) + ## ---------------------------------------------------------------- + + self.data_ready = True + + self.first_bit = True + self.bits_cnt = 0 + if self.oldstate.startswith('EXIT'):# and \ + #self.state.startswith('PAUSE-'): + if self.data_ready: + self.data_ready = False + self.es_bitstring = self.samplenum + t = self.state[-2:] + ' TDI' + b = ''.join(map(str, self.bits_tdi)) + h = ' (0x%X' % int('0b' + b, 2) + ')' + s = t + ': ' + h + ', ' + str(len(self.bits_tdi)) + ' bits' #b + + self.putx_bs([18, [s]]) + self.bits_samplenums_tdi[0][1] = self.samplenum # ES of last bit. + self.putp_bs([t, [b, self.bits_samplenums_tdi]]) + self.putx([16, [str(self.bits_tdi[0])]]) # Last bit. + self.bits_tdi = [] + self.bits_samplenums_tdi = [] + + t = self.state[-2:] + ' TDO' + b = ''.join(map(str, self.bits_tdo)) + h = ' (0x%X' % int('0b' + b, 2) + ')' + s = t + ': ' + h + ', ' + str(len(self.bits_tdo)) + ' bits' #+ b + self.putx_bs([19, [s]]) + self.bits_samplenums_tdo[0][1] = self.samplenum # ES of last bit. + self.putp_bs([t, [b, self.bits_samplenums_tdo]]) + self.putx([17, [str(self.bits_tdo[0])]]) # Last bit. + self.bits_tdo = [] + self.bits_samplenums_tdo = [] + + #self.first_bit = True + #self.bits_cnt = 0 + + #self.ss_bitstring = self.samplenum + + self.ss_item = self.samplenum + + def handle_tms_edge(self, tck, tms): + self.escape_edges = self.escape_edges + 1 + #print ("Detected escape sequence " + str(self.escape_edges)) + #self.es_item = self.samplenum + #self.putx([20, [str(self.escape_edges)]]) + def handle_tapc_state(self, tck, tms): + self.oldcjtagstate = self.cjtagstate + + if self.escape_edges >= 8: + self.cjtagstate = '4-WIRE' + if self.escape_edges == 6 : #| self.escape_edges == 7: + self.cjtagstate = 'CJTAG-OAC' + self.oacp = 0 + self.oaclen = 12 + + self.escape_edges = 0 + + def decode(self): + tdi_real = 0 + tms_real = 0 + tdo_real = 0 + + while True: + # Wait for a rising edge on TCK. + + (tdi, tdo, tck, tms, trst, srst, rtck) = self.wait({2: 'r'}) + self.handle_tapc_state(tck, tms) + + if(self.cjtagstate == 'OSCAN1'): + if(self.oscan1cycle == 0): #nTDI + if(tms == 0): + tdi_real = 1 + else: + tdi_real = 0 + self.oscan1cycle = 1 + elif(self.oscan1cycle == 1): #TMS + tms_real = tms + self.oscan1cycle = 2 + elif(self.oscan1cycle == 2): #TDO + tdo_real = tms + self.handle_rising_tck_edge(tdi_real, tdo_real, tck, tms_real, trst, srst, rtck) + self.oscan1cycle = 0 + else: + self.handle_rising_tck_edge(tdi, tdo, tck, tms, trst, srst, rtck) + + while (tck == 1): + (tdi, tdo, tck, tms_n, trst, srst, rtck) = self.wait([{2: 'f'}, {3: 'e'}]) + if(tms_n != tms): + tms = tms_n + self.handle_tms_edge(tck, tms) + + + diff --git a/libsigrokdecode4DSL/decoders/common/__init__.py b/libsigrokdecode4DSL/decoders/common/__init__.py new file mode 100644 index 00000000..2a0beb50 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/common/__init__.py @@ -0,0 +1,19 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2016 Uwe Hermann +## +## 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, see . +## + diff --git a/libsigrokdecode4DSL/decoders/common/plugtrx/__init__.py b/libsigrokdecode4DSL/decoders/common/plugtrx/__init__.py new file mode 100644 index 00000000..8dd0822b --- /dev/null +++ b/libsigrokdecode4DSL/decoders/common/plugtrx/__init__.py @@ -0,0 +1,20 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2016 Bert Vermeulen +## +## 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 . +## + +from .mod import * diff --git a/libsigrokdecode4DSL/decoders/common/plugtrx/mod.py b/libsigrokdecode4DSL/decoders/common/plugtrx/mod.py new file mode 100644 index 00000000..3d1b66dd --- /dev/null +++ b/libsigrokdecode4DSL/decoders/common/plugtrx/mod.py @@ -0,0 +1,192 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2016 Bert Vermeulen +## +## 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 . +## + +# This module contains definitions for use by pluggable network adapters, +# such as SFP, XFP etc. + +MODULE_ID = { + 0x01: 'GBIC', + 0x02: 'Integrated module/connector', + 0x03: 'SFP', + 0x04: '300-pin XBI', + 0x05: 'XENPAK', + 0x06: 'XFP', + 0x07: 'XFF', + 0x08: 'XFP-E', + 0x09: 'XPAK', + 0x0a: 'X2', +} + +ALARM_THRESHOLDS = { + 0: 'Temp high alarm', + 2: 'Temp low alarm', + 4: 'Temp high warning', + 6: 'Temp low warning', + 16: 'Bias high alarm', + 18: 'Bias low alarm', + 20: 'Bias high warning', + 22: 'Bias low warning', + 24: 'TX power high alarm', + 26: 'TX power low alarm', + 28: 'TX power high warning', + 30: 'TX power low warning', + 32: 'RX power high alarm', + 34: 'RX power low alarm', + 36: 'RX power high warning', + 38: 'RX power low warning', + 40: 'AUX 1 high alarm', + 42: 'AUX 1 low alarm', + 44: 'AUX 1 high warning', + 46: 'AUX 1 low warning', + 48: 'AUX 2 high alarm', + 50: 'AUX 2 low alarm', + 52: 'AUX 2 high warning', + 54: 'AUX 2 low warning', +} + +AD_READOUTS = { + 0: 'Module temperature', + 4: 'TX bias current', + 6: 'Measured TX output power', + 8: 'Measured RX input power', + 10: 'AUX 1 measurement', + 12: 'AUX 2 measurement', +} + +GCS_BITS = [ + 'TX disable', + 'Soft TX disable', + 'MOD_NR', + 'P_Down', + 'Soft P_Down', + 'Interrupt', + 'RX_LOS', + 'Data_Not_Ready', + 'TX_NR', + 'TX_Fault', + 'TX_CDR not locked', + 'RX_NR', + 'RX_CDR not locked', +] + +CONNECTOR = { + 0x01: 'SC', + 0x02: 'Fibre Channel style 1 copper', + 0x03: 'Fibre Channel style 2 copper', + 0x04: 'BNC/TNC', + 0x05: 'Fibre Channel coax', + 0x06: 'FiberJack', + 0x07: 'LC', + 0x08: 'MT-RJ', + 0x09: 'MU', + 0x0a: 'SG', + 0x0b: 'Optical pigtail', + 0x20: 'HSSDC II', + 0x21: 'Copper pigtail', +} + +TRANSCEIVER = [ + # 10GB Ethernet + ['10GBASE-SR', '10GBASE-LR', '10GBASE-ER', '10GBASE-LRM', '10GBASE-SW', + '10GBASE-LW', '10GBASE-EW'], + # 10GB Fibre Channel + ['1200-MX-SN-I', '1200-SM-LL-L', 'Extended Reach 1550 nm', + 'Intermediate reach 1300 nm FP'], + # 10GB Copper + [], + # 10GB low speed + ['1000BASE-SX / 1xFC MMF', '1000BASE-LX / 1xFC SMF', '2xFC MMF', + '2xFC SMF', 'OC48-SR', 'OC48-IR', 'OC48-LR'], + # 10GB SONET/SDH interconnect + ['I-64.1r', 'I-64.1', 'I-64.2r', 'I-64.2', 'I-64.3', 'I-64.5'], + # 10GB SONET/SDH short haul + ['S-64.1', 'S-64.2a', 'S-64.2b', 'S-64.3a', 'S-64.3b', 'S-64.5a', 'S-64.5b'], + # 10GB SONET/SDH long haul + ['L-64.1', 'L-64.2a', 'L-64.2b', 'L-64.2c', 'L-64.3', 'G.959.1 P1L1-2D2'], + # 10GB SONET/SDH very long haul + ['V-64.2a', 'V-64.2b', 'V-64.3'], +] + +SERIAL_ENCODING = [ + '64B/66B', + '8B/10B', + 'SONET scrambled', + 'NRZ', + 'RZ', +] + +XMIT_TECH = [ + '850 nm VCSEL', + '1310 nm VCSEL', + '1550 nm VCSEL', + '1310 nm FP', + '1310 nm DFB', + '1550 nm DFB', + '1310 nm EML' + '1550 nm EML' + 'copper', +] + +CDR = [ + '9.95Gb/s', + '10.3Gb/s', + '10.5Gb/s', + '10.7Gb/s', + '11.1Gb/s', + '(unknown)', + 'lineside loopback mode', + 'XFI loopback mode', +] + +DEVICE_TECH = [ + ['no wavelength control', 'sctive wavelength control'], + ['uncooled transmitter device', 'cooled transmitter'], + ['PIN detector', 'APD detector'], + ['transmitter not tunable', 'transmitter tunable'], +] + +ENHANCED_OPTS = [ + 'VPS', + 'soft TX_DISABLE', + 'soft P_Down', + 'VPS LV regulator mode', + 'VPS bypassed regulator mode', + 'active FEC control', + 'wavelength tunability', + 'CMU', +] + +AUX_TYPES = [ + 'not implemented', + 'APD bias voltage', + '(unknown)', + 'TEC current', + 'laser temperature', + 'laser wavelength', + '5V supply voltage', + '3.3V supply voltage', + '1.8V supply voltage', + '-5.2V supply voltage', + '5V supply current', + '(unknown)', + '(unknown)', + '3.3V supply current', + '1.8V supply current', + '-5.2V supply current', +] diff --git a/libsigrokdecode4DSL/decoders/common/sdcard/__init__.py b/libsigrokdecode4DSL/decoders/common/sdcard/__init__.py new file mode 100644 index 00000000..fb323856 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/common/sdcard/__init__.py @@ -0,0 +1,20 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012-2014 Uwe Hermann +## +## 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, see . +## + +from .mod import * diff --git a/libsigrokdecode4DSL/decoders/common/sdcard/mod.py b/libsigrokdecode4DSL/decoders/common/sdcard/mod.py new file mode 100644 index 00000000..2ef33238 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/common/sdcard/mod.py @@ -0,0 +1,151 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012-2014 Uwe Hermann +## +## 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, see . +## + +# Normal commands (CMD) +# Unlisted items are 'Reserved' as per SD spec. The 'Unknown' items don't +# seem to be mentioned in the spec, but aren't marked as reserved either. +cmd_names = { + 0: 'GO_IDLE_STATE', + 1: 'SEND_OP_COND', # Reserved in SD mode + 2: 'ALL_SEND_CID', + 3: 'SEND_RELATIVE_ADDR', + 4: 'SET_DSR', + 5: 'IO_SEND_OP_COND', # SDIO-only + 6: 'SWITCH_FUNC', # New since spec 1.10 + 7: 'SELECT/DESELECT_CARD', + 8: 'SEND_IF_COND', + 9: 'SEND_CSD', + 10: 'SEND_CID', + 11: 'VOLTAGE_SWITCH', + 12: 'STOP_TRANSMISSION', + 13: 'SEND_STATUS', + # 14: Reserved + 15: 'GO_INACTIVE_STATE', + 16: 'SET_BLOCKLEN', + 17: 'READ_SINGLE_BLOCK', + 18: 'READ_MULTIPLE_BLOCK', + 19: 'SEND_TUNING_BLOCK', + 20: 'SPEED_CLASS_CONTROL', + # 21-22: Reserved + 23: 'SET_BLOCK_COUNT', + 24: 'WRITE_BLOCK', + 25: 'WRITE_MULTIPLE_BLOCK', + 26: 'Reserved for manufacturer', + 27: 'PROGRAM_CSD', + 28: 'SET_WRITE_PROT', + 29: 'CLR_WRITE_PROT', + 30: 'SEND_WRITE_PROT', + # 31: Reserved + 32: 'ERASE_WR_BLK_START', # SPI mode: ERASE_WR_BLK_START_ADDR + 33: 'ERASE_WR_BLK_END', # SPI mode: ERASE_WR_BLK_END_ADDR + 34: 'Reserved for CMD6', # New since spec 1.10 + 35: 'Reserved for CMD6', # New since spec 1.10 + 36: 'Reserved for CMD6', # New since spec 1.10 + 37: 'Reserved for CMD6', # New since spec 1.10 + 38: 'ERASE', + # 39: Reserved + 40: 'Reserved for security specification', + # 41: Reserved + 42: 'LOCK_UNLOCK', + # 43-49: Reserved + 50: 'Reserved for CMD6', # New since spec 1.10 + # 51: Reserved + 52: 'IO_RW_DIRECT', # SDIO-only + 53: 'IO_RW_EXTENDED', # SDIO-only + 54: 'Unknown', + 55: 'APP_CMD', + 56: 'GEN_CMD', + 57: 'Reserved for CMD6', # New since spec 1.10 + 58: 'READ_OCR', # Reserved in SD mode + 59: 'CRC_ON_OFF', # Reserved in SD mode + 60: 'Reserved for manufacturer', + 61: 'Reserved for manufacturer', + 62: 'Reserved for manufacturer', + 63: 'Reserved for manufacturer', +} + +# Application-specific commands (ACMD) +# Unlisted items are 'Reserved' as per SD spec. The 'Unknown' items don't +# seem to be mentioned in the spec, but aren't marked as reserved either. +acmd_names = { + # 1-5: Reserved + 6: 'SET_BUS_WIDTH', + # 7-12: Reserved + 13: 'SD_STATUS', + 14: 'Reserved for Security Application', + 15: 'Reserved for Security Application', + 16: 'Reserved for Security Application', + # 17: Reserved + 18: 'Reserved for SD security applications', + # 19-21: Reserved + 22: 'SEND_NUM_WR_BLOCKS', + 23: 'SET_WR_BLK_ERASE_COUNT', + # 24: Reserved + 25: 'Reserved for SD security applications', + 26: 'Reserved for SD security applications', + 27: 'Reserved for security specification', + 28: 'Reserved for security specification', + # 29: Reserved + 30: 'Reserved for security specification', + 31: 'Reserved for security specification', + 32: 'Reserved for security specification', + 33: 'Reserved for security specification', + 34: 'Reserved for security specification', + 35: 'Reserved for security specification', + # 36-37: Reserved + 38: 'Reserved for SD security applications', + # 39-40: Reserved + 41: 'SD_SEND_OP_COND', + 42: 'SET_CLR_CARD_DETECT', + 43: 'Reserved for SD security applications', + 44: 'Reserved for SD security applications', + 45: 'Reserved for SD security applications', + 46: 'Reserved for SD security applications', + 47: 'Reserved for SD security applications', + 48: 'Reserved for SD security applications', + 49: 'Reserved for SD security applications', + 50: 'Unknown', + 51: 'SEND_SCR', + 52: 'Reserved for security specification', + 53: 'Reserved for security specification', + 54: 'Reserved for security specification', + 55: 'Non-existant', # Doesn't exist (equivalent to CMD55) + 56: 'Reserved for security specification', + 57: 'Reserved for security specification', + 58: 'Reserved for security specification', + 59: 'Reserved for security specification', + 60: 'Unknown', + 61: 'Unknown', + 62: 'Unknown', + 63: 'Unknown', +} + +accepted_voltages = { + 0b0001: '2.7-3.6V', + 0b0010: 'reserved for low voltage range', + 0b0100: 'reserved', + 0b1000: 'reserved', + # All other values: "not defined". +} + +sd_status = { + # 311:0: Reserved for manufacturer + # 391:312: Reserved +} + diff --git a/libsigrokdecode4DSL/decoders/common/srdhelper/__init__.py b/libsigrokdecode4DSL/decoders/common/srdhelper/__init__.py new file mode 100644 index 00000000..fb323856 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/common/srdhelper/__init__.py @@ -0,0 +1,20 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012-2014 Uwe Hermann +## +## 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, see . +## + +from .mod import * diff --git a/libsigrokdecode4DSL/decoders/common/srdhelper/mod.py b/libsigrokdecode4DSL/decoders/common/srdhelper/mod.py new file mode 100644 index 00000000..6c45af98 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/common/srdhelper/mod.py @@ -0,0 +1,84 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012-2020 Uwe Hermann +## +## 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, see . +## + +from enum import Enum, IntEnum, unique +from itertools import chain +import re + +# Return the specified BCD number (max. 8 bits) as integer. +def bcd2int(b): + return (b & 0x0f) + ((b >> 4) * 10) + +def bin2int(s: str): + return int('0b' + s, 2) + +def bitpack(bits): + return sum([b << i for i, b in enumerate(bits)]) + +def bitunpack(num, minbits=0): + res = [] + while num or minbits > 0: + res.append(num & 1) + num >>= 1 + minbits -= 1 + return tuple(res) + +@unique +class SrdStrEnum(Enum): + @classmethod + def from_list(cls, name, l): + # Keys are limited/converted to [A-Z0-9_], values can be any string. + items = [(re.sub('[^A-Z0-9_]', '_', l[i]), l[i]) for i in range(len(l))] + return cls(name, items) + + @classmethod + def from_str(cls, name, s): + return cls.from_list(name, s.split()) + +@unique +class SrdIntEnum(IntEnum): + @classmethod + def _prefix(cls, p): + return tuple([a.value for a in cls if a.name.startswith(p)]) + + @classmethod + def prefixes(cls, prefix_list): + if isinstance(prefix_list, str): + prefix_list = prefix_list.split() + return tuple(chain(*[cls._prefix(p) for p in prefix_list])) + + @classmethod + def _suffix(cls, s): + return tuple([a.value for a in cls if a.name.endswith(s)]) + + @classmethod + def suffixes(cls, suffix_list): + if isinstance(suffix_list, str): + suffix_list = suffix_list.split() + return tuple(chain(*[cls._suffix(s) for s in suffix_list])) + + @classmethod + def from_list(cls, name, l): + # Manually construct (Python 3.4 is missing the 'start' argument). + # Python defaults to start=1, but we want start=0. + return cls(name, [(l[i], i) for i in range(len(l))]) + + @classmethod + def from_str(cls, name, s): + return cls.from_list(name, s.split()) diff --git a/libsigrokdecode4DSL/decoders/counter/__init__.py b/libsigrokdecode4DSL/decoders/counter/__init__.py new file mode 100644 index 00000000..505148dd --- /dev/null +++ b/libsigrokdecode4DSL/decoders/counter/__init__.py @@ -0,0 +1,28 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Stefan Brüns +## +## 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, see . +## + +''' +This decoder is a simple edge counter. + +It can count rising and/or falling edges, provides an optional reset +signal. It can also divide the count to e.g. count the number of +fixed-length words (where a word corresponds to e.g. 9 clock edges). +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/counter/pd.py b/libsigrokdecode4DSL/decoders/counter/pd.py new file mode 100644 index 00000000..b0b1af71 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/counter/pd.py @@ -0,0 +1,145 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Stefan Brüns +## +## 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, see . +## + +import sigrokdecode as srd + +PIN_DATA, PIN_RESET = range(2) +ROW_EDGE, ROW_WORD, ROW_RESET = range(3) + +class Decoder(srd.Decoder): + api_version = 3 + id = 'counter' + name = 'Counter' + longname = 'Edge counter' + desc = 'Count the number of edges in a signal.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Util'] + channels = ( + {'id': 'data', 'name': 'Data', 'desc': 'Data line'}, + ) + optional_channels = ( + {'id': 'reset', 'name': 'Reset', 'desc': 'Reset line'}, + ) + annotations = ( + ('edge_count', 'Edge count'), + ('word_count', 'Word count'), + ('word_reset', 'Word reset'), + ) + annotation_rows = ( + ('edge_counts', 'Edges', (ROW_EDGE,)), + ('word_counts', 'Words', (ROW_WORD,)), + ('word_resets', 'Word resets', (ROW_RESET,)), + ) + options = ( + {'id': 'data_edge', 'desc': 'Edges to count (data)', 'default': 'any', + 'values': ('any', 'rising', 'falling')}, + {'id': 'divider', 'desc': 'Count divider (word width)', 'default': 0}, + {'id': 'reset_edge', 'desc': 'Edge which clears counters (reset)', + 'default': 'falling', 'values': ('rising', 'falling')}, + {'id': 'edge_off', 'desc': 'Edge counter value after start/reset', 'default': 0}, + {'id': 'word_off', 'desc': 'Word counter value after start/reset', 'default': 0}, + {'id': 'dead_cycles', 'desc': 'Ignore this many edges after reset', 'default': 0}, + {'id': 'start_with_reset', 'desc': 'Assume decode starts with reset', + 'default': 'no', 'values': ('no', 'yes')}, + ) + + def __init__(self): + self.reset() + + def reset(self): + pass + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putc(self, cls, ss, annlist): + self.put(ss, self.samplenum, self.out_ann, [cls, annlist]) + + def decode(self): + opt_edge_map = {'rising': 'r', 'falling': 'f', 'any': 'e'} + + data_edge = self.options['data_edge'] + divider = self.options['divider'] + if divider < 0: + divider = 0 + reset_edge = self.options['reset_edge'] + + condition = [{PIN_DATA: opt_edge_map[data_edge]}] + have_reset = self.has_channel(PIN_RESET) + if have_reset: + cond_reset = len(condition) + condition.append({PIN_RESET: opt_edge_map[reset_edge]}) + + edge_count = int(self.options['edge_off']) + edge_start = None + word_count = int(self.options['word_off']) + word_start = None + + if self.options['start_with_reset'] == 'yes': + dead_count = int(self.options['dead_cycles']) + else: + dead_count = 0 + + while True: + self.wait(condition) + now = self.samplenum + + if have_reset and (self.matched & (0b1 < +## +## 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, see . +## + +''' +DALI is a biphase/manchester based lighting control protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/dali/lists.py b/libsigrokdecode4DSL/decoders/dali/lists.py new file mode 100644 index 00000000..e9d3a4ba --- /dev/null +++ b/libsigrokdecode4DSL/decoders/dali/lists.py @@ -0,0 +1,98 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Jeremy Swanson +## +## 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, see . +## + +# DALI extended commands +extended_commands = { + 0xA1: ['Terminate special processes', 'Terminate'], + 0xA3: ['DTR = DATA', 'DTR'], + 0xA5: ['INITIALISE', 'INIT'], + 0xA7: ['RANDOMISE', 'RAND'], + 0xA9: ['COMPARE', 'COMP'], + 0xAB: ['WITHDRAW', 'WDRAW'], + 0xB1: ['SET SEARCH H', 'SAH'], + 0xB3: ['SET SEARCH M', 'SAM'], + 0xB5: ['SET SEARCH L', 'SAL'], + 0xB7: ['Program Short Address', 'ProgSA'], + 0xB9: ['Verify Short Address', 'VfySA'], + 0xBB: ['Query Short Address', 'QryShort'], + 0xBD: ['Physical Selection', 'PysSel'], + 0xC1: ['Enable Device Type X', 'EnTyp'], + 0xC3: ['DTR1 = DATA', 'DTR1'], + 0xC5: ['DTR2 = DATA', 'DTR2'], + 0xC7: ['Write Memory Location', 'WRI'], +} + +# List of commands +dali_commands = { + 0x00: ['Immediate Off', 'IOFF'], + 0x01: ['Up 200ms', 'Up'], + 0x02: ['Down 200ms', 'Down'], + 0x03: ['Step Up', 'Step+'], + 0x04: ['Step Down', 'Step-'], + 0x05: ['Recall Maximum Level', 'Recall Max'], + 0x06: ['Recall Minimum Level', 'Recall Min'], + 0x07: ['Step down and off', 'Down Off'], + 0x08: ['Step ON and UP', 'On Up'], + 0x20: ['Reset', 'Rst'], + 0x21: ['Store Dim Level in DTR', 'Level -> DTR'], + 0x2A: ['Store DTR as Max Level', 'DTR->Max'], + 0x2B: ['Store DTR as Min Level', 'DTR->Min'], + 0x2C: ['Store DTR as Fail Level', 'DTR->Fail'], + 0x2D: ['Store DTR as Power On Level', 'DTR->Poweron'], + 0x2E: ['Store DTR as Fade Time', 'DTR->Fade'], + 0x2F: ['Store DTR as Fade Rate', 'DTR->Rate'], + 0x80: ['Store DTR as Short Address', 'DTR->Add'], + 0x81: ['Enable Memory Write', 'WEn'], + 0x90: ['Query Status', 'Status'], + 0x91: ['Query Ballast', 'Ballast'], + 0x92: ['Query Lamp Failure', 'LmpFail'], + 0x93: ['Query Power On', 'Power On'], + 0x94: ['Query Limit Error', 'Limit Err'], + 0x95: ['Query Reset', 'Reset State'], + 0x96: ['Query Missing Short Address', 'NoSrt'], + 0x97: ['Query Version', 'Ver'], + 0x98: ['Query DTR', 'GetDTR'], + 0x99: ['Query Device Type', 'Type'], + 0x9A: ['Query Physical Minimum', 'PhysMin'], + 0x9B: ['Query Power Fail', 'PowerFailed'], + 0x9C: ['Query DTR1', 'GetDTR1'], + 0x9D: ['Query DTR2', 'GetDTR2'], + 0xA0: ['Query Level', 'GetLevel'], + 0xA1: ['Query Max Level', 'GetMax'], + 0xA2: ['Query Min Level', 'GetMin'], + 0xA3: ['Query Power On', 'GetPwrOn'], + 0xA4: ['Query Fail Level', 'GetFail'], + 0xA5: ['Query Fade Rate', 'GetRate'], + 0xA6: ['Query Power Fail', 'PwrFail'], + 0xC0: ['Query Groups 0-7', 'GetGrpsL'], + 0xC1: ['Query Groups 7-15', 'GetGrpsH'], + 0xC2: ['Query BRNH', 'BRNH'], + 0xC3: ['Query BRNM', 'BRNM'], + 0xC4: ['Query BRNL', 'BRNL'], + 0xC5: ['Query Memory', 'GetMem'], +} + +# DALI device type 8 +dali_device_type8 = { + 0xE0: ['Set Temp X-Y Coordinate', 'Set X-Y'], + 0xE2: ['Activate Colour Set point', 'Activate SetPoint'], + 0xE7: ['Set Colour Temperature Tc', 'DTRs->ColTemp'], + 0xF9: ['Query Features', 'QryFeats'], + 0xFA: ['Query Current Setpoint Colour', 'GetSetPoint'], +} diff --git a/libsigrokdecode4DSL/decoders/dali/pd.py b/libsigrokdecode4DSL/decoders/dali/pd.py new file mode 100644 index 00000000..53147463 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/dali/pd.py @@ -0,0 +1,245 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Jeremy Swanson +## +## 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, see . +## + +import sigrokdecode as srd +from .lists import * + +class SamplerateError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = 'dali' + name = 'DALI' + longname = 'Digital Addressable Lighting Interface' + desc = 'Digital Addressable Lighting Interface (DALI) protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Embedded/industrial', 'Lighting'] + channels = ( + {'id': 'dali', 'name': 'DALI', 'desc': 'DALI data line'}, + ) + options = ( + {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-low', + 'values': ('active-low', 'active-high')}, + ) + annotations = ( + ('bit', 'Bit'), + ('startbit', 'Startbit'), + ('sbit', 'Select bit'), + ('ybit', 'Individual or group'), + ('address', 'Address'), + ('command', 'Command'), + ('reply', 'Reply data'), + ('raw', 'Raw data'), + ) + annotation_rows = ( + ('bits', 'Bits', (0,)), + ('raw', 'Raw data', (7,)), + ('fields', 'Fields', (1, 2, 3, 4, 5, 6)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.samplenum = None + self.edges, self.bits, self.ss_es_bits = [], [], [] + self.state = 'IDLE' + self.dev_type = None + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.old_dali = 1 if self.options['polarity'] == 'active-low' else 0 + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + # One bit: 833.33us (one half low, one half high). + # This is how may samples are in 1TE. + self.halfbit = int((self.samplerate * 0.0008333) / 2.0) + + def putb(self, bit1, bit2, data): + ss, es = self.ss_es_bits[bit1][0], self.ss_es_bits[bit2][1] + self.put(ss, es, self.out_ann, data) + + def handle_bits(self, length): + a, c, f, g, b = 0, 0, 0, 0, self.bits + # Individual raw bits. + for i in range(length): + if i == 0: + ss = max(0, self.bits[0][0]) + else: + ss = self.ss_es_bits[i - 1][1] + es = self.bits[i][0] + (self.halfbit * 2) + self.ss_es_bits.append([ss, es]) + self.putb(i, i, [0, ['%d' % self.bits[i][1]]]) + # Bits[0:0]: Startbit + s = ['Startbit: %d' % b[0][1], 'ST: %d' % b[0][1], 'ST', 'S', 'S'] + self.putb(0, 0, [1, s]) + self.putb(0, 0, [7, s]) + # Bits[1:8] + for i in range(8): + f |= (b[1 + i][1] << (7 - i)) + if length == 9: # BACKWARD Frame + s = ['Reply: %02X' % f, 'Rply: %02X' % f, + 'Rep: %02X' % f, 'R: %02X' % f, 'R'] + self.putb(1, 8, [7, s]) + s = ['Reply: %d' % f, 'Rply: %d' % f, + 'Rep: %d' % f, 'R: %d' % f, 'R'] + self.putb(1, 8, [6, s]) + return + + # FORWARD FRAME + # Bits[9:16]: Command/data (MSB-first) + for i in range(8): + c |= (b[9 + i][1] << (7 - i)) + # Raw output + s = ['Raw data: %02X' % f, 'Raw: %02X' % f, + 'Raw: %02X' % f, 'R: %02X' % f, 'R'] + self.putb(1, 8, [7, s]) + s = ['Raw data: %02X' % c, 'Raw: %02X' % c, + 'Raw: %02X' % c, 'R: %02X' % c, 'R'] + self.putb(9, 16, [7, s]) + + # Bits[8:8]: Select bit + # s = ['Selectbit: %d' % b[8][1], 'SEL: %d' % b[8][1], 'SEL', 'SE', 'S'] + if b[8][1] == 1: + s = ['Command', 'Comd', 'COM', 'CO', 'C'] + else: + s = ['Arc Power Level', 'Arc Pwr', 'ARC', 'AC', 'A'] + self.putb(8, 8, [1, s]) + + # f &= 254 # Clear the select bit. + if f >= 254: # BROADCAST + s = ['BROADCAST', 'Brdcast', 'BC', 'B', 'B'] + self.putb(1, 7, [5, s]) + elif f >= 160: # Extended command 0b10100000 + if f == 0xC1: # DALI_ENABLE_DEVICE_TYPE_X + self.dev_type = -1 + x = extended_commands.get(f, ['Unknown', 'Unk']) + s = ['Extended Command: %02X (%s)' % (f, x[0]), + 'XC: %02X (%s)' % (f, x[1]), + 'XC: %02X' % f, 'X: %02X' % f, 'X'] + self.putb(1, 8, [5, s]) + elif f >= 128: # Group + # Bits[1:1]: Ybit + s = ['YBit: %d' % b[1][1], 'YB: %d' % b[1][1], 'YB', 'Y', 'Y'] + self.putb(1, 1, [3, s]) + g = (f & 127) >> 1 + s = ['Group address: %d' % g, 'Group: %d' % g, + 'GP: %d' % g, 'G: %d' % g, 'G'] + self.putb(2,7, [4, s]) + else: # Short address + # Bits[1:1]: Ybit + s = ['YBit: %d' % b[1][1], 'YB: %d' % b[1][1], 'YB', 'Y', 'Y'] + self.putb(1, 1, [3, s]) + a = f >> 1 + s = ['Short address: %d' % a, 'Addr: %d' % a, + 'Addr: %d' % a, 'A: %d' % a, 'A'] + self.putb(2, 7, [4, s]) + + # Bits[9:16]: Command/data (MSB-first) + if f >= 160 and f < 254: + if self.dev_type == -1: + self.dev_type = c + s = ['Type: %d' % c, 'Typ: %d' % c, + 'Typ: %d' % c, 'T: %d' % c, 'D'] + else: + self.dev_type = None + s = ['Data: %d' % c, 'Dat: %d' % c, + 'Dat: %d' % c, 'D: %d' % c, 'D'] + elif b[8][1] == 1: + un = c & 0xF0 + ln = c & 0x0F + if un == 0x10: # Set scene command + x = ['Recall Scene %d' % ln, 'SC %d' % ln] + elif un == 0x40: + x = ['Store DTR as Scene %d' % ln, 'SC %d = DTR' % ln] + elif un == 0x50: + x = ['Delete Scene %d' % ln, 'DEL SC %d' % ln] + elif un == 0x60: + x = ['Add to Group %d' % ln, 'Grp %d Add' % ln] + elif un == 0x70: + x = ['Remove from Group %d' % ln, 'Grp %d Del' % ln] + elif un == 0xB0: + x = ['Query Scene %d Level' % ln, 'Sc %d Level' % ln] + elif c >= 224: # Application specific commands + if self.dev_type == 8: + x = dali_device_type8.get(c, ['Unknown App', 'Unk']) + else: + x = ['Application Specific Command %d' % c, 'App Cmd %d' % c] + else: + x = dali_commands.get(c, ['Unknown', 'Unk']) + s = ['Command: %d (%s)' % (c, x[0]), 'Com: %d (%s)' % (c, x[1]), + 'Com: %d' % c, 'C: %d' % c, 'C'] + else: + s = ['Arc Power Level: %d' % c, 'Level: %d' % c, + 'Lev: %d' % c, 'L: %d' % c, 'L'] + self.putb(9, 16, [5, s]) + + def reset_decoder_state(self): + self.edges, self.bits, self.ss_es_bits = [], [], [] + self.state = 'IDLE' + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + bit = 0 + while True: + # TODO: Come up with more appropriate self.wait() conditions. + (dali,) = self.wait() + if self.options['polarity'] == 'active-high': + dali ^= 1 # Invert. + + # State machine. + if self.state == 'IDLE': + # Wait for any edge (rising or falling). + if self.old_dali == dali: + continue + self.edges.append(self.samplenum) + self.state = 'PHASE0' + self.old_dali = dali + continue + + if self.old_dali != dali: + self.edges.append(self.samplenum) + elif self.samplenum == (self.edges[-1] + int(self.halfbit * 1.5)): + self.edges.append(self.samplenum - int(self.halfbit * 0.5)) + else: + continue + + bit = self.old_dali + if self.state == 'PHASE0': + self.phase0 = bit + self.state = 'PHASE1' + elif self.state == 'PHASE1': + if (bit == 1) and (self.phase0 == 1): # Stop bit. + if len(self.bits) == 17 or len(self.bits) == 9: + # Forward or Backward. + self.handle_bits(len(self.bits)) + self.reset_decoder_state() # Reset upon errors. + continue + else: + self.bits.append([self.edges[-3], bit]) + self.state = 'PHASE0' + + self.old_dali = dali diff --git a/libsigrokdecode4DSL/decoders/dcf77/__init__.py b/libsigrokdecode4DSL/decoders/dcf77/__init__.py new file mode 100644 index 00000000..caadcff8 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/dcf77/__init__.py @@ -0,0 +1,28 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +''' +This PD decodes the DCF77 protocol (a European long-wave time signal that +uses a 77.5kHz carrier frequency). + +Details: +http://en.wikipedia.org/wiki/DCF77 +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/dcf77/pd.py b/libsigrokdecode4DSL/decoders/dcf77/pd.py new file mode 100644 index 00000000..7365134e --- /dev/null +++ b/libsigrokdecode4DSL/decoders/dcf77/pd.py @@ -0,0 +1,311 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012-2016 Uwe Hermann +## +## 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, see . +## + +import sigrokdecode as srd +import calendar +from common.srdhelper import bcd2int + +class SamplerateError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = 'dcf77' + name = 'DCF77' + longname = 'DCF77 time protocol' + desc = 'European longwave time signal (77.5kHz carrier signal).' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Clock/timing'] + channels = ( + {'id': 'data', 'name': 'DATA', 'desc': 'DATA line'}, + ) + annotations = ( + ('start-of-minute', 'Start of minute'), + ('special-bits', 'Special bits (civil warnings, weather forecast)'), + ('call-bit', 'Call bit'), + ('summer-time', 'Summer time announcement'), + ('cest', 'CEST bit'), + ('cet', 'CET bit'), + ('leap-second', 'Leap second bit'), + ('start-of-time', 'Start of encoded time'), + ('minute', 'Minute'), + ('minute-parity', 'Minute parity bit'), + ('hour', 'Hour'), + ('hour-parity', 'Hour parity bit'), + ('day', 'Day of month'), + ('day-of-week', 'Day of week'), + ('month', 'Month'), + ('year', 'Year'), + ('date-parity', 'Date parity bit'), + ('raw-bits', 'Raw bits'), + ('unknown-bits', 'Unknown bits'), + ('warnings', 'Human-readable warnings'), + ) + annotation_rows = ( + ('bits', 'Bits', (17, 18)), + ('fields', 'Fields', tuple(range(0, 16 + 1))), + ('warnings', 'Warnings', (19,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.state = 'WAIT FOR RISING EDGE' + self.ss_bit = self.ss_bit_old = self.es_bit = self.ss_block = 0 + self.datebits = [] + self.bitcount = 0 # Counter for the DCF77 bits (0..58) + self.dcf77_bitnumber_is_known = 0 + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def putx(self, data): + # Annotation for a single DCF77 bit. + self.put(self.ss_bit, self.es_bit, self.out_ann, data) + + def putb(self, data): + # Annotation for a multi-bit DCF77 field. + self.put(self.ss_block, self.samplenum, self.out_ann, data) + + # TODO: Which range to use? Only the 100ms/200ms or full second? + def handle_dcf77_bit(self, bit): + c = self.bitcount + + # Create one annotation for each DCF77 bit (containing the 0/1 value). + # Use 'Unknown DCF77 bit x: val' if we're not sure yet which of the + # 0..58 bits it is (because we haven't seen a 'new minute' marker yet). + # Otherwise, use 'DCF77 bit x: val'. + s = 'B' if self.dcf77_bitnumber_is_known else 'Unknown b' + ann = 17 if self.dcf77_bitnumber_is_known else 18 + self.putx([ann, ['%sit %d: %d' % (s, c, bit), '%d' % bit]]) + + # If we're not sure yet which of the 0..58 DCF77 bits we have, return. + # We don't want to decode bogus data. + if not self.dcf77_bitnumber_is_known: + return + + # Collect bits 36-58, we'll need them for a parity check later. + if c in range(36, 58 + 1): + self.datebits.append(bit) + + # Output specific "decoded" annotations for the respective DCF77 bits. + if c == 0: + # Start of minute: DCF bit 0. + if bit == 0: + self.putx([0, ['Start of minute (always 0)', + 'Start of minute', 'SoM']]) + else: + self.putx([19, ['Start of minute != 0', 'SoM != 0']]) + elif c in range(1, 14 + 1): + # Special bits (civil warnings, weather forecast): DCF77 bits 1-14. + if c == 1: + self.tmp = bit + self.ss_block = self.ss_bit + else: + self.tmp |= (bit << (c - 1)) + if c == 14: + s = '{:014b}'.format(self.tmp) + self.putb([1, ['Special bits: %s' % s, 'SB: %s' % s]]) + elif c == 15: + s = '' if (bit == 1) else 'not ' + self.putx([2, ['Call bit: %sset' % s, 'CB: %sset' % s]]) + # TODO: Previously this bit indicated use of the backup antenna. + elif c == 16: + s = '' if (bit == 1) else 'not ' + x = 'yes' if (bit == 1) else 'no' + self.putx([3, ['Summer time announcement: %sactive' % s, + 'Summer time: %sactive' % s, + 'Summer time: %s' % x, 'ST: %s' % x]]) + elif c == 17: + s = '' if (bit == 1) else 'not ' + x = 'yes' if (bit == 1) else 'no' + self.putx([4, ['CEST: %sin effect' % s, 'CEST: %s' % x]]) + elif c == 18: + s = '' if (bit == 1) else 'not ' + x = 'yes' if (bit == 1) else 'no' + self.putx([5, ['CET: %sin effect' % s, 'CET: %s' % x]]) + elif c == 19: + s = '' if (bit == 1) else 'not ' + x = 'yes' if (bit == 1) else 'no' + self.putx([6, ['Leap second announcement: %sactive' % s, + 'Leap second: %sactive' % s, + 'Leap second: %s' % x, 'LS: %s' % x]]) + elif c == 20: + # Start of encoded time: DCF bit 20. + if bit == 1: + self.putx([7, ['Start of encoded time (always 1)', + 'Start of encoded time', 'SoeT']]) + else: + self.putx([19, ['Start of encoded time != 1', 'SoeT != 1']]) + elif c in range(21, 27 + 1): + # Minutes (0-59): DCF77 bits 21-27 (BCD format). + if c == 21: + self.tmp = bit + self.ss_block = self.ss_bit + else: + self.tmp |= (bit << (c - 21)) + if c == 27: + m = bcd2int(self.tmp) + self.putb([8, ['Minutes: %d' % m, 'Min: %d' % m]]) + elif c == 28: + # Even parity over minute bits (21-28): DCF77 bit 28. + self.tmp |= (bit << (c - 21)) + parity = bin(self.tmp).count('1') + s = 'OK' if ((parity % 2) == 0) else 'INVALID!' + self.putx([9, ['Minute parity: %s' % s, 'Min parity: %s' % s]]) + elif c in range(29, 34 + 1): + # Hours (0-23): DCF77 bits 29-34 (BCD format). + if c == 29: + self.tmp = bit + self.ss_block = self.ss_bit + else: + self.tmp |= (bit << (c - 29)) + if c == 34: + self.putb([10, ['Hours: %d' % bcd2int(self.tmp)]]) + elif c == 35: + # Even parity over hour bits (29-35): DCF77 bit 35. + self.tmp |= (bit << (c - 29)) + parity = bin(self.tmp).count('1') + s = 'OK' if ((parity % 2) == 0) else 'INVALID!' + self.putx([11, ['Hour parity: %s' % s]]) + elif c in range(36, 41 + 1): + # Day of month (1-31): DCF77 bits 36-41 (BCD format). + if c == 36: + self.tmp = bit + self.ss_block = self.ss_bit + else: + self.tmp |= (bit << (c - 36)) + if c == 41: + self.putb([12, ['Day: %d' % bcd2int(self.tmp)]]) + elif c in range(42, 44 + 1): + # Day of week (1-7): DCF77 bits 42-44 (BCD format). + # A value of 1 means Monday, 7 means Sunday. + if c == 42: + self.tmp = bit + self.ss_block = self.ss_bit + else: + self.tmp |= (bit << (c - 42)) + if c == 44: + d = bcd2int(self.tmp) + try: + dn = calendar.day_name[d - 1] # day_name[0] == Monday + self.putb([13, ['Day of week: %d (%s)' % (d, dn), + 'DoW: %d (%s)' % (d, dn)]]) + except IndexError: + self.putb([19, ['Day of week: %d (%s)' % (d, 'invalid'), + 'DoW: %d (%s)' % (d, 'inv')]]) + elif c in range(45, 49 + 1): + # Month (1-12): DCF77 bits 45-49 (BCD format). + if c == 45: + self.tmp = bit + self.ss_block = self.ss_bit + else: + self.tmp |= (bit << (c - 45)) + if c == 49: + m = bcd2int(self.tmp) + try: + mn = calendar.month_name[m] # month_name[1] == January + self.putb([14, ['Month: %d (%s)' % (m, mn), + 'Mon: %d (%s)' % (m, mn)]]) + except IndexError: + self.putb([19, ['Month: %d (%s)' % (m, 'invalid'), + 'Mon: %d (%s)' % (m, 'inv')]]) + elif c in range(50, 57 + 1): + # Year (0-99): DCF77 bits 50-57 (BCD format). + if c == 50: + self.tmp = bit + self.ss_block = self.ss_bit + else: + self.tmp |= (bit << (c - 50)) + if c == 57: + self.putb([15, ['Year: %d' % bcd2int(self.tmp)]]) + elif c == 58: + # Even parity over date bits (36-58): DCF77 bit 58. + parity = self.datebits.count(1) + s = 'OK' if ((parity % 2) == 0) else 'INVALID!' + self.putx([16, ['Date parity: %s' % s, 'DP: %s' % s]]) + self.datebits = [] + else: + self.putx([19, ['Invalid DCF77 bit: %d' % c, + 'Invalid bit: %d' % c, 'Inv: %d' % c]]) + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + while True: + if self.state == 'WAIT FOR RISING EDGE': + # Wait until the next rising edge occurs. + self.wait({0: 'r'}) + + # Save the sample number where the DCF77 bit begins. + self.ss_bit = self.samplenum + + # Calculate the length (in ms) between two rising edges. + len_edges = self.ss_bit - self.ss_bit_old + len_edges_ms = int((len_edges / self.samplerate) * 1000) + + # The time between two rising edges is usually around 1000ms. + # For DCF77 bit 59, there is no rising edge at all, i.e. the + # time between DCF77 bit 59 and DCF77 bit 0 (of the next + # minute) is around 2000ms. Thus, if we see an edge with a + # 2000ms distance to the last one, this edge marks the + # beginning of a new minute (and DCF77 bit 0 of that minute). + if len_edges_ms in range(1600, 2400 + 1): + self.bitcount = 0 + self.ss_bit_old = self.ss_bit + self.dcf77_bitnumber_is_known = 1 + + self.ss_bit_old = self.ss_bit + self.state = 'GET BIT' + + elif self.state == 'GET BIT': + # Wait until the next falling edge occurs. + self.wait({0: 'f'}) + + # Save the sample number where the DCF77 bit ends. + self.es_bit = self.samplenum + + # Calculate the length (in ms) of the current high period. + len_high = self.samplenum - self.ss_bit + len_high_ms = int((len_high / self.samplerate) * 1000) + + # If the high signal was 100ms long, that encodes a 0 bit. + # If it was 200ms long, that encodes a 1 bit. + if len_high_ms in range(40, 160 + 1): + bit = 0 + elif len_high_ms in range(161, 260 + 1): + bit = 1 + else: + bit = -1 + + if bit in (0, 1): + self.handle_dcf77_bit(bit) + self.bitcount += 1 + else: + self.putx([19, ['Invalid bit timing', 'Inv timing', 'Inv']]) + + self.state = 'WAIT FOR RISING EDGE' diff --git a/libsigrokdecode4DSL/decoders/dmx512/__init__.py b/libsigrokdecode4DSL/decoders/dmx512/__init__.py new file mode 100644 index 00000000..b5e57836 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/dmx512/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2016 Fabian J. Stumpf +## +## 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, see . +## + +''' +DMX512 (Digital MultipleX 512) is a protocol based on RS485, used to control +professional lighting fixtures. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/dmx512/pd.py b/libsigrokdecode4DSL/decoders/dmx512/pd.py new file mode 100644 index 00000000..355095ee --- /dev/null +++ b/libsigrokdecode4DSL/decoders/dmx512/pd.py @@ -0,0 +1,179 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2016 Fabian J. Stumpf +## +## 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, see . +## + +import sigrokdecode as srd + +class Decoder(srd.Decoder): + api_version = 3 + id = 'dmx512' + name = 'DMX512' + longname = 'Digital MultipleX 512' + desc = 'Digital MultipleX 512 (DMX512) lighting protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Embedded/industrial', 'Lighting'] + channels = ( + {'id': 'dmx', 'name': 'DMX data', 'desc': 'Any DMX data line'}, + ) + options = ( + {'id': 'invert', 'desc': 'Invert Signal?', 'default': 'no', + 'values': ('yes', 'no')}, + ) + annotations = ( + ('bit', 'Bit'), + ('break', 'Break'), + ('mab', 'Mark after break'), + ('startbit', 'Start bit'), + ('stopbits', 'Stop bit'), + ('startcode', 'Start code'), + ('channel', 'Channel'), + ('interframe', 'Interframe'), + ('interpacket', 'Interpacket'), + ('data', 'Data'), + ('error', 'Error'), + ) + annotation_rows = ( + ('name', 'Logical', (1, 2, 5, 6, 7, 8)), + ('data', 'Data', (9,)), + ('bits', 'Bits', (0, 3, 4)), + ('errors', 'Errors', (10,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.sample_usec = None + self.run_start = -1 + self.state = 'FIND BREAK' + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + self.sample_usec = 1 / value * 1000000 + self.skip_per_bit = int(4 / self.sample_usec) + + def putr(self, data): + self.put(self.run_start, self.samplenum, self.out_ann, data) + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + + inv = self.options['invert'] == 'yes' + + (dmx,) = self.wait({0: 'h' if inv else 'l'}) + self.run_start = self.samplenum + + while True: + # Seek for an interval with no state change with a length between + # 88 and 1000000 us (BREAK). + if self.state == 'FIND BREAK': + (dmx,) = self.wait({0: 'f' if inv else 'r'}) + runlen = (self.samplenum - self.run_start) * self.sample_usec + if runlen > 88 and runlen < 1000000: + self.putr([1, ['Break']]) + self.state = 'MARK MAB' + self.channel = 0 + elif runlen >= 1000000: + # Error condition. + self.putr([10, ['Invalid break length']]) + else: + (dmx,) = self.wait({0: 'h' if inv else 'l'}) + self.run_start = self.samplenum + # Directly following the BREAK is the MARK AFTER BREAK. + elif self.state == 'MARK MAB': + self.run_start = self.samplenum + (dmx,) = self.wait({0: 'r' if inv else 'f'}) + self.putr([2, ['MAB']]) + self.state = 'READ BYTE' + self.channel = 0 + self.bit = 0 + self.aggreg = dmx + self.run_start = self.samplenum + # Mark and read a single transmitted byte + # (start bit, 8 data bits, 2 stop bits). + elif self.state == 'READ BYTE': + bit_start = self.samplenum + bit_end = self.run_start + (self.bit + 1) * self.skip_per_bit + (dmx,) = self.wait({'skip': round(self.skip_per_bit/2)}) + bit_value = not dmx if inv else dmx + + if self.bit == 0: + self.byte = 0 + self.put(bit_start, bit_end, + self.out_ann, [3, ['Start bit']]) + if bit_value != 0: + # (Possibly) invalid start bit, mark but don't fail. + self.put(bit_start, bit_end, + self.out_ann, [10, ['Invalid start bit']]) + elif self.bit >= 9: + self.put(bit_start, bit_end, + self.out_ann, [4, ['Stop bit']]) + if bit_value != 1: + # Invalid stop bit, mark. + self.put(bit_start, bit_end, + self.out_ann, [10, ['Invalid stop bit']]) + if self.bit == 10: + # On invalid 2nd stop bit, search for new break. + self.state = 'FIND BREAK' + else: + # Label and process one bit. + self.put(bit_start, bit_end, + self.out_ann, [0, [str(bit_value)]]) + self.byte |= bit_value << (self.bit - 1) + + # Label a complete byte. + if self.state == 'READ BYTE' and self.bit == 10: + if self.channel == 0: + d = [5, ['Start code']] + else: + d = [6, ['Channel ' + str(self.channel)]] + self.put(self.run_start, bit_end, self.out_ann, d) + self.put(self.run_start + self.skip_per_bit, + bit_end - 2 * self.skip_per_bit, + self.out_ann, [9, [str(self.byte) + ' / ' + \ + str(hex(self.byte))]]) + # Continue by scanning the IFT. + self.channel += 1 + self.run_start = self.samplenum + self.state = 'MARK IFT' + + self.bit += 1 + (dmx,) = self.wait({'skip': round(bit_end - self.samplenum)}) + # Mark the INTERFRAME-TIME between bytes / INTERPACKET-TIME between packets. + elif self.state == 'MARK IFT': + self.run_start = self.samplenum + if self.channel > 512: + (dmx,) = self.wait({0: 'h' if inv else 'l'}) + self.putr([8, ['Interpacket']]) + self.state = 'FIND BREAK' + self.run_start = self.samplenum + else: + if (not dmx if inv else dmx): + (dmx,) = self.wait({0: 'h' if inv else 'l'}) + self.putr([7, ['Interframe']]) + self.state = 'READ BYTE' + self.bit = 0 + self.run_start = self.samplenum diff --git a/libsigrokdecode4DSL/decoders/ds1307/__init__.py b/libsigrokdecode4DSL/decoders/ds1307/__init__.py new file mode 100644 index 00000000..faf4ce68 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ds1307/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2013 Matt Ranostay +## +## 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, see . +## + +''' +This decoder stacks on top of the 'i2c' PD and decodes the Dallas DS1307 +real-time clock (RTC) specific registers and commands. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/ds1307/pd.py b/libsigrokdecode4DSL/decoders/ds1307/pd.py new file mode 100644 index 00000000..f8ebe195 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ds1307/pd.py @@ -0,0 +1,264 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012-2014 Uwe Hermann +## Copyright (C) 2013 Matt Ranostay +## +## 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, see . +## + +import re +import sigrokdecode as srd +from common.srdhelper import bcd2int + +days_of_week = ( + 'Sunday', 'Monday', 'Tuesday', 'Wednesday', + 'Thursday', 'Friday', 'Saturday', +) + +regs = ( + 'Seconds', 'Minutes', 'Hours', 'Day', 'Date', 'Month', 'Year', + 'Control', 'RAM', +) + +bits = ( + 'Clock halt', 'Seconds', 'Reserved', 'Minutes', '12/24 hours', 'AM/PM', + 'Hours', 'Day', 'Date', 'Month', 'Year', 'OUT', 'SQWE', 'RS', 'RAM', +) + +rates = { + 0b00: '1Hz', + 0b01: '4096Hz', + 0b10: '8192Hz', + 0b11: '32768Hz', +} + +DS1307_I2C_ADDRESS = 0x68 + +def regs_and_bits(): + l = [('reg-' + r.lower(), r + ' register') for r in regs] + l += [('bit-' + re.sub('\/| ', '-', b).lower(), b + ' bit') for b in bits] + return tuple(l) + +class Decoder(srd.Decoder): + api_version = 3 + id = 'ds1307' + name = 'DS1307' + longname = 'Dallas DS1307' + desc = 'Dallas DS1307 realtime clock module protocol.' + license = 'gplv2+' + inputs = ['i2c'] + outputs = [] + tags = ['Clock/timing', 'IC'] + annotations = regs_and_bits() + ( + ('read-datetime', 'Read date/time'), + ('write-datetime', 'Write date/time'), + ('reg-read', 'Register read'), + ('reg-write', 'Register write'), + ('warnings', 'Warnings'), + ) + annotation_rows = ( + ('bits', 'Bits', tuple(range(9, 24))), + ('regs', 'Registers', tuple(range(9))), + ('date-time', 'Date/time', (24, 25, 26, 27)), + ('warnings', 'Warnings', (28,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.state = 'IDLE' + self.hours = -1 + self.minutes = -1 + self.seconds = -1 + self.days = -1 + self.date = -1 + self.months = -1 + self.years = -1 + self.bits = [] + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + self.put(self.ss, self.es, self.out_ann, data) + + def putd(self, bit1, bit2, data): + self.put(self.bits[bit1][1], self.bits[bit2][2], self.out_ann, data) + + def putr(self, bit): + self.put(self.bits[bit][1], self.bits[bit][2], self.out_ann, + [11, ['Reserved bit', 'Reserved', 'Rsvd', 'R']]) + + def handle_reg_0x00(self, b): # Seconds (0-59) / Clock halt bit + self.putd(7, 0, [0, ['Seconds', 'Sec', 'S']]) + ch = 1 if (b & (1 << 7)) else 0 + self.putd(7, 7, [9, ['Clock halt: %d' % ch, 'Clk hlt: %d' % ch, + 'CH: %d' % ch, 'CH']]) + s = self.seconds = bcd2int(b & 0x7f) + self.putd(6, 0, [10, ['Second: %d' % s, 'Sec: %d' % s, 'S: %d' % s, 'S']]) + + def handle_reg_0x01(self, b): # Minutes (0-59) + self.putd(7, 0, [1, ['Minutes', 'Min', 'M']]) + self.putr(7) + m = self.minutes = bcd2int(b & 0x7f) + self.putd(6, 0, [12, ['Minute: %d' % m, 'Min: %d' % m, 'M: %d' % m, 'M']]) + + def handle_reg_0x02(self, b): # Hours (1-12+AM/PM or 0-23) + self.putd(7, 0, [2, ['Hours', 'H']]) + self.putr(7) + ampm_mode = True if (b & (1 << 6)) else False + if ampm_mode: + self.putd(6, 6, [13, ['12-hour mode', '12h mode', '12h']]) + a = 'PM' if (b & (1 << 5)) else 'AM' + self.putd(5, 5, [14, [a, a[0]]]) + h = self.hours = bcd2int(b & 0x1f) + self.putd(4, 0, [15, ['Hour: %d' % h, 'H: %d' % h, 'H']]) + else: + self.putd(6, 6, [13, ['24-hour mode', '24h mode', '24h']]) + h = self.hours = bcd2int(b & 0x3f) + self.putd(5, 0, [15, ['Hour: %d' % h, 'H: %d' % h, 'H']]) + + def handle_reg_0x03(self, b): # Day / day of week (1-7) + self.putd(7, 0, [3, ['Day of week', 'Day', 'D']]) + for i in (7, 6, 5, 4, 3): + self.putr(i) + w = self.days = bcd2int(b & 0x07) + ws = days_of_week[self.days - 1] + self.putd(2, 0, [16, ['Weekday: %s' % ws, 'WD: %s' % ws, 'WD', 'W']]) + + def handle_reg_0x04(self, b): # Date (1-31) + self.putd(7, 0, [4, ['Date', 'D']]) + for i in (7, 6): + self.putr(i) + d = self.date = bcd2int(b & 0x3f) + self.putd(5, 0, [17, ['Date: %d' % d, 'D: %d' % d, 'D']]) + + def handle_reg_0x05(self, b): # Month (1-12) + self.putd(7, 0, [5, ['Month', 'Mon', 'M']]) + for i in (7, 6, 5): + self.putr(i) + m = self.months = bcd2int(b & 0x1f) + self.putd(4, 0, [18, ['Month: %d' % m, 'Mon: %d' % m, 'M: %d' % m, 'M']]) + + def handle_reg_0x06(self, b): # Year (0-99) + self.putd(7, 0, [6, ['Year', 'Y']]) + y = self.years = bcd2int(b & 0xff) + self.years += 2000 + self.putd(7, 0, [19, ['Year: %d' % y, 'Y: %d' % y, 'Y']]) + + def handle_reg_0x07(self, b): # Control Register + self.putd(7, 0, [7, ['Control', 'Ctrl', 'C']]) + for i in (6, 5, 3, 2): + self.putr(i) + o = 1 if (b & (1 << 7)) else 0 + s = 1 if (b & (1 << 4)) else 0 + s2 = 'en' if (b & (1 << 4)) else 'dis' + r = rates[b & 0x03] + self.putd(7, 7, [20, ['Output control: %d' % o, + 'OUT: %d' % o, 'O: %d' % o, 'O']]) + self.putd(4, 4, [21, ['Square wave output: %sabled' % s2, + 'SQWE: %sabled' % s2, 'SQWE: %d' % s, 'S: %d' % s, 'S']]) + self.putd(1, 0, [22, ['Square wave output rate: %s' % r, + 'Square wave rate: %s' % r, 'SQW rate: %s' % r, 'Rate: %s' % r, + 'RS: %s' % s, 'RS', 'R']]) + + def handle_reg_0x3f(self, b): # RAM (bytes 0x08-0x3f) + self.putd(7, 0, [8, ['RAM', 'R']]) + self.putd(7, 0, [23, ['SRAM: 0x%02X' % b, '0x%02X' % b]]) + + def output_datetime(self, cls, rw): + # TODO: Handle read/write of only parts of these items. + d = '%s, %02d.%02d.%4d %02d:%02d:%02d' % ( + days_of_week[self.days - 1], self.date, self.months, + self.years, self.hours, self.minutes, self.seconds) + self.put(self.ss_block, self.es, self.out_ann, + [cls, ['%s date/time: %s' % (rw, d)]]) + + def handle_reg(self, b): + r = self.reg if self.reg < 8 else 0x3f + fn = getattr(self, 'handle_reg_0x%02x' % r) + fn(b) + # Honor address auto-increment feature of the DS1307. When the + # address reaches 0x3f, it will wrap around to address 0. + self.reg += 1 + if self.reg > 0x3f: + self.reg = 0 + + def is_correct_chip(self, addr): + if addr == DS1307_I2C_ADDRESS: + return True + self.put(self.ss_block, self.es, self.out_ann, + [28, ['Ignoring non-DS1307 data (slave 0x%02X)' % addr]]) + return False + + def decode(self, ss, es, data): + cmd, databyte = data + + # Collect the 'BITS' packet, then return. The next packet is + # guaranteed to belong to these bits we just stored. + if cmd == 'BITS': + self.bits = databyte + return + + # Store the start/end samples of this I²C packet. + self.ss, self.es = ss, es + + # State machine. + if self.state == 'IDLE': + # Wait for an I²C START condition. + if cmd != 'START': + return + self.state = 'GET SLAVE ADDR' + self.ss_block = ss + elif self.state == 'GET SLAVE ADDR': + # Wait for an address write operation. + if cmd != 'ADDRESS WRITE': + return + if not self.is_correct_chip(databyte): + self.state = 'IDLE' + return + self.state = 'GET REG ADDR' + elif self.state == 'GET REG ADDR': + # Wait for a data write (master selects the slave register). + if cmd != 'DATA WRITE': + return + self.reg = databyte + self.state = 'WRITE RTC REGS' + elif self.state == 'WRITE RTC REGS': + # If we see a Repeated Start here, it's an RTC read. + if cmd == 'START REPEAT': + self.state = 'READ RTC REGS' + return + # Otherwise: Get data bytes until a STOP condition occurs. + if cmd == 'DATA WRITE': + self.handle_reg(databyte) + elif cmd == 'STOP': + self.output_datetime(25, 'Written') + self.state = 'IDLE' + elif self.state == 'READ RTC REGS': + # Wait for an address read operation. + if cmd != 'ADDRESS READ': + return + if not self.is_correct_chip(databyte): + self.state = 'IDLE' + return + self.state = 'READ RTC REGS2' + elif self.state == 'READ RTC REGS2': + if cmd == 'DATA READ': + self.handle_reg(databyte) + elif cmd == 'STOP': + self.output_datetime(24, 'Read') + self.state = 'IDLE' diff --git a/libsigrokdecode4DSL/decoders/ds2408/__init__.py b/libsigrokdecode4DSL/decoders/ds2408/__init__.py new file mode 100644 index 00000000..b196ce97 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ds2408/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +''' +This decoder stacks on top of the 'onewire_network' PD and decodes the +Maxim DS2408 1-Wire 8-channel addressable switch protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/ds2408/pd.py b/libsigrokdecode4DSL/decoders/ds2408/pd.py new file mode 100644 index 00000000..33f2873f --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ds2408/pd.py @@ -0,0 +1,129 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Mariusz Bialonczyk +## +## 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, see . +## + +import sigrokdecode as srd + +# Dictionary of FUNCTION commands and their names. +command = { + 0xf0: 'Read PIO Registers', + 0xf5: 'Channel Access Read', + 0x5a: 'Channel Access Write', + 0xcc: 'Write Conditional Search Register', + 0xc3: 'Reset Activity Latches', + 0x3c: 'Disable Test Mode', +} + +class Decoder(srd.Decoder): + api_version = 3 + id = 'ds2408' + name = 'DS2408' + longname = 'Maxim DS2408' + desc = '1-Wire 8-channel addressable switch.' + license = 'gplv2+' + inputs = ['onewire_network'] + outputs = [] + tags = ['Embedded/industrial', 'IC'] + annotations = ( + ('text', 'Human-readable text'), + ) + + def __init__(self): + self.reset() + + def reset(self): + # Bytes for function command. + self.bytes = [] + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + self.put(self.ss, self.es, self.out_ann, data) + + def decode(self, ss, es, data): + code, val = data + + if code == 'RESET/PRESENCE': + self.ss, self.es = ss, es + self.putx([0, ['Reset/presence: %s' + % ('true' if val else 'false')]]) + self.bytes = [] + elif code == 'ROM': + self.ss, self.es = ss, es + family_code = val & 0xff + self.putx([0, ['ROM: 0x%016x (family code 0x%02x)' % (val, family_code)]]) + self.bytes = [] + elif code == 'DATA': + self.bytes.append(val) + if 1 == len(self.bytes): + self.ss, self.es = ss, es + if val not in command: + self.putx([0, ['Unrecognized command: 0x%02x' % val]]) + else: + self.putx([0, ['%s (0x%02x)' % (command[val], val)]]) + elif 0xf0 == self.bytes[0]: # Read PIO Registers + if 2 == len(self.bytes): + self.ss = ss + elif 3 == len(self.bytes): + self.es = es + self.putx([0, ['Target address: 0x%04x' + % ((self.bytes[2] << 8) + self.bytes[1])]]) + elif 3 < len(self.bytes): + self.ss, self.es = ss, es + self.putx([0, ['Data: 0x%02x' % self.bytes[-1]]]) + elif 0xf5 == self.bytes[0]: # Channel Access Read + if 2 == len(self.bytes): + self.ss = ss + elif 2 < len(self.bytes): + self.ss, self.es = ss, es + self.putx([0, ['PIO sample: 0x%02x' % self.bytes[-1]]]) + elif 0x5a == self.bytes[0]: # Channel Access Write + if 2 == len(self.bytes): + self.ss = ss + elif 3 == len(self.bytes): + self.es = es + if (self.bytes[-1] == (self.bytes[-2] ^ 0xff)): + self.putx([0, ['Data: 0x%02x (bit-inversion correct: 0x%02x)' % (self.bytes[-2], self.bytes[-1])]]) + else: + self.putx([0, ['Data error: second byte (0x%02x) is not bit-inverse of first (0x%02x)' % (self.bytes[-1], self.bytes[-2])]]) + elif 3 < len(self.bytes): + self.ss, self.es = ss, es + if 0xaa == self.bytes[-1]: + self.putx([0, ['Success']]) + elif 0xff == self.bytes[-1]: + self.putx([0, ['Fail New State']]) + elif 0xcc == self.bytes[0]: # Write Conditional Search Register + if 2 == len(self.bytes): + self.ss = ss + elif 3 == len(self.bytes): + self.es = es + self.putx([0, ['Target address: 0x%04x' + % ((self.bytes[2] << 8) + self.bytes[1])]]) + elif 3 < len(self.bytes): + self.ss, self.es = ss, es + self.putx([0, ['Data: 0x%02x' % self.bytes[-1]]]) + elif 0xc3 == self.bytes[0]: # Reset Activity Latches + if 2 == len(self.bytes): + self.ss = ss + elif 2 < len(self.bytes): + self.ss, self.es = ss, es + if 0xaa == self.bytes[-1]: + self.putx([0, ['Success']]) + else: + self.putx([0, ['Invalid byte']]) diff --git a/libsigrokdecode4DSL/decoders/ds243x/__init__.py b/libsigrokdecode4DSL/decoders/ds243x/__init__.py new file mode 100644 index 00000000..c460e045 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ds243x/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2017 Kevin Redon +## +## 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, see . +## + +''' +This decoder stacks on top of the 'onewire_network' PD and decodes the +Maxim DS243x (1-Wire EEPROM) protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/ds243x/pd.py b/libsigrokdecode4DSL/decoders/ds243x/pd.py new file mode 100644 index 00000000..7f9f6660 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ds243x/pd.py @@ -0,0 +1,270 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2017 Kevin Redon +## Copyright (C) 2017 Soeren Apel +## +## 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, see . +## + +import sigrokdecode as srd + +# Dictionary of FUNCTION commands and their names. +commands_2432 = { + 0x0f: 'Write scratchpad', + 0xaa: 'Read scratchpad', + 0x55: 'Copy scratchpad', + 0xf0: 'Read memory', + 0x5a: 'Load first secret', + 0x33: 'Compute next secret', + 0xa5: 'Read authenticated page', +} + +commands_2433 = { + 0x0f: 'Write scratchpad', + 0xaa: 'Read scratchpad', + 0x55: 'Copy scratchpad', + 0xf0: 'Read memory', +} + +# Maxim DS243x family code, present at the end of the ROM code. +family_codes = { + 0x33: ('DS2432', commands_2432), + 0x23: ('DS2433', commands_2433), +} + +# Calculate the CRC-16 checksum. +# Initial value: 0x0000, xor-in: 0x0000, polynom 0x8005, xor-out: 0xffff. +def crc16(byte_array): + reverse = 0xa001 # Use the reverse polynom to make algo simpler. + crc = 0x0000 # Initial value. + # Reverse CRC calculation. + for byte in byte_array: + for bit in range(8): + if (byte ^ crc) & 1: + crc = (crc >> 1) ^ reverse + else: + crc >>= 1 + byte >>= 1 + crc ^= 0xffff # Invert CRC. + return crc + +class Decoder(srd.Decoder): + api_version = 3 + id = 'ds243x' + name = 'DS243x' + longname = 'Maxim DS2432/3' + desc = 'Maxim DS243x series 1-Wire EEPROM protocol.' + license = 'gplv2+' + inputs = ['onewire_network'] + outputs = [] + tags = ['IC', 'Memory'] + annotations = ( + ('text', 'Human-readable text'), + ) + binary = ( + ('mem_read', 'Data read from memory'), + ) + + def __init__(self): + self.reset() + + def reset(self): + # Bytes for function command. + self.bytes = [] + self.family_code = None + self.family = '' + self.commands = commands_2432 # Use max command set until we know better. + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_binary = self.register(srd.OUTPUT_BINARY) + + def putx(self, data): + self.put(self.ss, self.es, self.out_ann, data) + + def decode(self, ss, es, data): + code, val = data + + if code == 'RESET/PRESENCE': + self.ss, self.es = ss, es + self.putx([0, ['Reset/presence: %s' + % ('true' if val else 'false')]]) + self.bytes = [] + elif code == 'ROM': + self.ss, self.es = ss, es + self.family_code = val & 0xff + + s = None + if self.family_code in family_codes: + self.family, self.commands = family_codes[val & 0xff] + s = 'is 0x%02x, %s detected' % (self.family_code, self.family) + else: + s = '0x%02x unknown' % (self.family_code) + + self.putx([0, ['ROM: 0x%016x (%s)' % (val, 'family code ' + s), + 'ROM: 0x%016x (%s)' % (val, self.family)]]) + self.bytes = [] + elif code == 'DATA': + self.bytes.append(val) + if 1 == len(self.bytes): + self.ss, self.es = ss, es + if val not in self.commands: + self.putx([0, ['Unrecognized command: 0x%02x' % val]]) + else: + self.putx([0, ['Function command: %s (0x%02x)' + % (self.commands[val], val)]]) + elif 0x0f == self.bytes[0]: # Write scratchpad + if 2 == len(self.bytes): + self.ss = ss + elif 3 == len(self.bytes): + self.es = es + self.putx([0, ['Target address: 0x%04x' + % ((self.bytes[2] << 8) + self.bytes[1])]]) + elif 4 == len(self.bytes): + self.ss = ss + elif 11 == len(self.bytes): + self.es = es + self.putx([0, ['Data: ' + (','.join(format(n, '#04x') + for n in self.bytes[3:11]))]]) + elif 12 == len(self.bytes): + self.ss = ss + elif 13 == len(self.bytes): + self.es = es + self.putx([0, ['CRC: ' + + ('ok' if crc16(self.bytes[0:11]) == (self.bytes[11] + + (self.bytes[12] << 8)) else 'error')]]) + elif 0xaa == self.bytes[0]: # Read scratchpad + if 2 == len(self.bytes): + self.ss = ss + elif 3 == len(self.bytes): + self.es = es + self.putx([0, ['Target address: 0x%04x' + % ((self.bytes[2] << 8) + self.bytes[1])]]) + elif 4 == len(self.bytes): + self.ss, self.es = ss, es + self.putx([0, ['Data status (E/S): 0x%02x' + % (self.bytes[3])]]) + elif 5 == len(self.bytes): + self.ss = ss + elif 12 == len(self.bytes): + self.es = es + self.putx([0, ['Data: ' + (','.join(format(n, '#04x') + for n in self.bytes[4:12]))]]) + elif 13 == len(self.bytes): + self.ss = ss + elif 14 == len(self.bytes): + self.es = es + self.putx([0, ['CRC: ' + + ('ok' if crc16(self.bytes[0:12]) == (self.bytes[12] + + (self.bytes[13] << 8)) else 'error')]]) + elif 0x5a == self.bytes[0]: # Load first secret + if 2 == len(self.bytes): + self.ss = ss + elif 4 == len(self.bytes): + self.es = es + self.putx([0, ['Authorization pattern (TA1, TA2, E/S): ' + + (','.join(format(n, '#04x') + for n in self.bytes[1:4]))]]) + elif 4 < len(self.bytes): + self.ss, self.es = ss, es + if (0xaa == self.bytes[-1] or 0x55 == self.bytes[-1]): + self.putx([0, ['End of operation']]) + elif 0x33 == self.bytes[0]: # Compute next secret + if 2 == len(self.bytes): + self.ss = ss + elif 3 == len(self.bytes): + self.es = es + self.putx([0, ['Target address: 0x%04x' + % ((self.bytes[2] << 8) + self.bytes[1])]]) + elif 3 < len(self.bytes): + self.ss, self.es = ss, es + if (0xaa == self.bytes[-1] or 0x55 == self.bytes[-1]): + self.putx([0, ['End of operation']]) + elif 0x55 == self.bytes[0]: # Copy scratchpad + if 2 == len(self.bytes): + self.ss = ss + elif 4 == len(self.bytes): + self.es = es + self.putx([0, ['Authorization pattern (TA1, TA2, E/S): ' + + (','.join(format(n, '#04x') + for n in self.bytes[1:4]))]]) + elif 5 == len(self.bytes): + self.ss = ss + elif 24 == len(self.bytes): + self.es = es + mac = ','.join(format(n, '#04x') for n in self.bytes[4:24]) + self.putx([0, ['Message authentication code: ' + mac, + 'MAC: ' + mac]]) + elif 24 < len(self.bytes): + self.ss, self.es = ss, es + if (0xaa == self.bytes[-1] or 0x55 == self.bytes[-1]): + self.putx([0, ['Operation succeeded']]) + elif (0 == self.bytes[-1]): + self.putx([0, ['Operation failed']]) + elif 0xa5 == self.bytes[0]: # Read authenticated page + if 2 == len(self.bytes): + self.ss = ss + elif 3 == len(self.bytes): + self.es = es + self.putx([0, ['Target address: 0x%04x' + % ((self.bytes[2] << 8) + self.bytes[1])]]) + elif 4 == len(self.bytes): + self.ss = ss + elif 35 == len(self.bytes): + self.es = es + self.putx([0, ['Data: ' + (','.join(format(n, '#04x') + for n in self.bytes[3:35]))]]) + elif 36 == len(self.bytes): + self.ss, self.es = ss, es + self.putx([0, ['Padding: ' + + ('ok' if 0xff == self.bytes[-1] else 'error')]]) + elif 37 == len(self.bytes): + self.ss = ss + elif 38 == len(self.bytes): + self.es = es + self.putx([0, ['CRC: ' + + ('ok' if crc16(self.bytes[0:36]) == (self.bytes[36] + + (self.bytes[37] << 8)) else 'error')]]) + elif 39 == len(self.bytes): + self.ss = ss + elif 58 == len(self.bytes): + self.es = es + mac = ','.join(format(n, '#04x') for n in self.bytes[38:58]) + self.putx([0, ['Message authentication code: ' + mac, + 'MAC: ' + mac]]) + elif 59 == len(self.bytes): + self.ss = ss + elif 60 == len(self.bytes): + self.es = es + self.putx([0, ['MAC CRC: ' + + ('ok' if crc16(self.bytes[38:58]) == (self.bytes[58] + + (self.bytes[59] << 8)) else 'error')]]) + elif 60 < len(self.bytes): + self.ss, self.es = ss, es + if (0xaa == self.bytes[-1] or 0x55 == self.bytes[-1]): + self.putx([0, ['Operation completed']]) + elif 0xf0 == self.bytes[0]: # Read memory + if 2 == len(self.bytes): + self.ss = ss + elif 3 == len(self.bytes): + self.es = es + self.putx([0, ['Target address: 0x%04x' + % ((self.bytes[2] << 8) + self.bytes[1])]]) + elif 3 < len(self.bytes): + self.ss, self.es = ss, es + self.putx([0, ['Data: 0x%02x' % (self.bytes[-1])]]) + + bdata = self.bytes[-1].to_bytes(1, byteorder='big') + self.put(ss, es, self.out_binary, [0, bdata]) diff --git a/libsigrokdecode4DSL/decoders/ds28ea00/__init__.py b/libsigrokdecode4DSL/decoders/ds28ea00/__init__.py new file mode 100644 index 00000000..31550707 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ds28ea00/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +''' +This decoder stacks on top of the 'onewire_network' PD and decodes the +Maxim DS28EA00 1-Wire digital thermometer protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/ds28ea00/pd.py b/libsigrokdecode4DSL/decoders/ds28ea00/pd.py new file mode 100644 index 00000000..9a578449 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ds28ea00/pd.py @@ -0,0 +1,93 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Iztok Jeras +## +## 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, see . +## + +import sigrokdecode as srd + +# Dictionary of FUNCTION commands and their names. +command = { + # Scratchpad + 0x4e: 'Write scratchpad', + 0xbe: 'Read scratchpad', + 0x48: 'Copy scratchpad', + # Thermometer + 0x44: 'Convert temperature', + 0xb4: 'Read power mode', + 0xb8: 'Recall EEPROM', + 0xf5: 'PIO access read', + 0xA5: 'PIO access write', + 0x99: 'Chain', +} + +class Decoder(srd.Decoder): + api_version = 3 + id = 'ds28ea00' + name = 'DS28EA00' + longname = 'Maxim DS28EA00 1-Wire digital thermometer' + desc = '1-Wire digital thermometer with Sequence Detect and PIO.' + license = 'gplv2+' + inputs = ['onewire_network'] + outputs = [] + tags = ['IC', 'Sensor'] + annotations = ( + ('text', 'Human-readable text'), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.trn_beg = 0 + self.trn_end = 0 + self.state = 'ROM' + self.rom = 0x0000000000000000 + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + self.put(self.ss, self.es, self.out_ann, data) + + def decode(self, ss, es, data): + code, val = data + + self.ss, self.es = ss, es + + # State machine. + if code == 'RESET/PRESENCE': + self.putx([0, ['Reset/presence: %s' + % ('true' if val else 'false')]]) + self.state = 'ROM' + elif code == 'ROM': + self.rom = val + self.putx([0, ['ROM: 0x%016x' % (val)]]) + self.state = 'COMMAND' + elif code == 'DATA': + if self.state == 'COMMAND': + if val not in command: + self.putx([0, ['Unrecognized command: 0x%02x' % val]]) + return + self.putx([0, ['Function command: 0x%02x \'%s\'' + % (val, command[val])]]) + self.state = command[val].upper() + elif self.state == 'READ SCRATCHPAD': + self.putx([0, ['Scratchpad data: 0x%02x' % val]]) + elif self.state == 'CONVERT TEMPERATURE': + self.putx([0, ['Temperature conversion status: 0x%02x' % val]]) + elif self.state in [s.upper() for s in command.values()]: + self.putx([0, ['TODO \'%s\': 0x%02x' % (self.state, val)]]) diff --git a/libsigrokdecode4DSL/decoders/dsi/__init__.py b/libsigrokdecode4DSL/decoders/dsi/__init__.py new file mode 100644 index 00000000..bfba8672 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/dsi/__init__.py @@ -0,0 +1,24 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Jeremy Swanson +## +## 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, see . +## + +''' +DSI is a biphase/manchester based lighting control protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/dsi/pd.py b/libsigrokdecode4DSL/decoders/dsi/pd.py new file mode 100644 index 00000000..7ce95179 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/dsi/pd.py @@ -0,0 +1,157 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Jeremy Swanson +## +## 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, see . +## + +import sigrokdecode as srd + +class SamplerateError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = 'dsi' + name = 'DSI' + longname = 'Digital Serial Interface' + desc = 'Digital Serial Interface (DSI) lighting protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Embedded/industrial', 'Lighting'] + channels = ( + {'id': 'dsi', 'name': 'DSI', 'desc': 'DSI data line'}, + ) + options = ( + {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-high', + 'values': ('active-low', 'active-high')}, + ) + annotations = ( + ('bit', 'Bit'), + ('startbit', 'Start bit'), + ('level', 'Dimmer level'), + ('raw', 'Raw data'), + ) + annotation_rows = ( + ('bits', 'Bits', (0,)), + ('raw', 'Raw data', (3,)), + ('fields', 'Fields', (1, 2)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.samplenum = None + self.edges, self.bits, self.ss_es_bits = [], [], [] + self.state = 'IDLE' + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.old_dsi = 1 if self.options['polarity'] == 'active-low' else 0 + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + # One bit: 1666.7us (one half low, one half high). + # This is how many samples are in 1TE. + self.halfbit = int((self.samplerate * 0.0016667) / 2.0) + + def putb(self, bit1, bit2, data): + ss, es = self.ss_es_bits[bit1][0], self.ss_es_bits[bit2][1] + self.put(ss, es, self.out_ann, data) + + def handle_bits(self, length): + a, c, f, g, b = 0, 0, 0, 0, self.bits + # Individual raw bits. + for i in range(length): + if i == 0: + ss = max(0, self.bits[0][0]) + else: + ss = self.ss_es_bits[i - 1][1] + es = self.bits[i][0] + (self.halfbit * 2) + self.ss_es_bits.append([ss, es]) + self.putb(i, i, [0, ['%d' % self.bits[i][1]]]) + # Bits[0:0]: Startbit + s = ['Startbit: %d' % b[0][1], 'ST: %d' % b[0][1], 'ST', 'S', 'S'] + self.putb(0, 0, [1, s]) + self.putb(0, 0, [3, s]) + # Bits[1:8] + for i in range(8): + f |= (b[1 + i][1] << (7 - i)) + g = f / 2.55 + if length == 9: # BACKWARD Frame + s = ['Data: %02X' % f, 'Dat: %02X' % f, + 'Dat: %02X' % f, 'D: %02X' % f, 'D'] + self.putb(1, 8, [3, s]) + s = ['Level: %d%%' % g, 'Lev: %d%%' % g, + 'Lev: %d%%' % g, 'L: %d' % g, 'D'] + self.putb(1, 8, [2, s]) + return + + def reset_decoder_state(self): + self.edges, self.bits, self.ss_es_bits = [], [], [] + self.state = 'IDLE' + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + bit = 0 + while True: + (self.dsi,) = self.wait() + if self.options['polarity'] == 'active-high': + self.dsi ^= 1 # Invert. + + # State machine. + if self.state == 'IDLE': + # Wait for any edge (rising or falling). + if self.old_dsi == self.dsi: + continue + # Add in the first half of the start bit. + self.edges.append(self.samplenum - int(self.halfbit)) + self.edges.append(self.samplenum) + # Start bit is 0->1. + self.phase0 = self.dsi ^ 1 + self.state = 'PHASE1' + self.old_dsi = self.dsi + # Get the next sample point. + self.old_dsi = self.dsi + continue + + if self.old_dsi != self.dsi: + self.edges.append(self.samplenum) + elif self.samplenum == (self.edges[-1] + int(self.halfbit * 1.5)): + self.edges.append(self.samplenum - int(self.halfbit * 0.5)) + else: + continue + + bit = self.old_dsi + if self.state == 'PHASE0': + self.phase0 = bit + self.state = 'PHASE1' + elif self.state == 'PHASE1': + if (bit == 1) and (self.phase0 == 1): # Stop bit. + if len(self.bits) == 17 or len(self.bits) == 9: + # Forward or Backward. + self.handle_bits(len(self.bits)) + self.reset_decoder_state() # Reset upon errors. + continue + else: + self.bits.append([self.edges[-3], bit]) + self.state = 'PHASE0' + + self.old_dsi = self.dsi diff --git a/libsigrokdecode4DSL/decoders/edid/__init__.py b/libsigrokdecode4DSL/decoders/edid/__init__.py new file mode 100644 index 00000000..256d839d --- /dev/null +++ b/libsigrokdecode4DSL/decoders/edid/__init__.py @@ -0,0 +1,35 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Bert Vermeulen +## +## 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, see . +## + +''' +Extended Display Identification Data (EDID) 1.3 structure decoder. + +The three-character vendor ID as specified in the EDID standard refers to +a Plug and Play ID (PNPID). The list of PNPID assignments is done by Microsoft. + +The 'pnpids.txt' file included with this protocol decoder is derived from +the list of assignments downloadable from that page. It was retrieved in +January 2012. + +Details: +https://en.wikipedia.org/wiki/Extended_display_identification_data +http://msdn.microsoft.com/en-us/windows/hardware/gg463195 +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/edid/config b/libsigrokdecode4DSL/decoders/edid/config new file mode 100644 index 00000000..ba74a8f7 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/edid/config @@ -0,0 +1 @@ +extra-install pnpids.txt diff --git a/libsigrokdecode4DSL/decoders/edid/pd.py b/libsigrokdecode4DSL/decoders/edid/pd.py new file mode 100644 index 00000000..2d7460ce --- /dev/null +++ b/libsigrokdecode4DSL/decoders/edid/pd.py @@ -0,0 +1,668 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Bert Vermeulen +## +## 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 . +## + +# TODO: +# - EDID < 1.3 +# - add short annotations +# - Signal level standard field in basic display parameters block +# - Additional color point descriptors +# - Additional standard timing descriptors +# - Extensions + +import sigrokdecode as srd +import os + +EDID_HEADER = [0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00] +OFF_VENDOR = 8 +OFF_VERSION = 18 +OFF_BASIC = 20 +OFF_CHROM = 25 +OFF_EST_TIMING = 35 +OFF_STD_TIMING = 38 +OFF_DET_TIMING = 54 +OFF_NUM_EXT = 126 +OFF_CHECKSUM = 127 + +# Pre-EDID established timing modes +est_modes = [ + '720x400@70Hz', + '720x400@88Hz', + '640x480@60Hz', + '640x480@67Hz', + '640x480@72Hz', + '640x480@75Hz', + '800x600@56Hz', + '800x600@60Hz', + '800x600@72Hz', + '800x600@75Hz', + '832x624@75Hz', + '1024x768@87Hz(i)', + '1024x768@60Hz', + '1024x768@70Hz', + '1024x768@75Hz', + '1280x1024@75Hz', + '1152x870@75Hz', +] + +# X:Y display aspect ratios, as used in standard timing modes +xy_ratio = [ + (16, 10), + (4, 3), + (5, 4), + (16, 9), +] + +# Annotation classes +ANN_FIELDS = 0 +ANN_SECTIONS = 1 + +class Decoder(srd.Decoder): + api_version = 3 + id = 'edid' + name = 'EDID' + longname = 'Extended Display Identification Data' + desc = 'Data structure describing display device capabilities.' + license = 'gplv3+' + inputs = ['i2c'] + outputs = [] + tags = ['Display', 'Memory', 'PC'] + annotations = ( + ('fields', 'EDID structure fields'), + ('sections', 'EDID structure sections'), + ) + annotation_rows = ( + ('sections', 'Sections', (1,)), + ('fields', 'Fields', (0,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.state = None + # Received data items, used as an index into samplenum/data + self.cnt = 0 + # Start/end sample numbers per data item + self.sn = [] + # Received data + self.cache = [] + # Random read offset + self.offset = 0 + # Extensions + self.extension = 0 + self.ext_sn = [[]] + self.ext_cache = [[]] + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def decode(self, ss, es, data): + cmd, data = data + + if cmd == 'ADDRESS WRITE' and data == 0x50: + self.state = 'offset' + self.ss = ss + return + + if cmd == 'ADDRESS READ' and data == 0x50: + if self.extension > 0: + self.state = 'extensions' + s = str(self.extension) + t = ["Extension: " + s, "X: " + s, s] + else: + self.state = 'header' + t = ["EDID"] + self.put(ss, es, self.out_ann, [ANN_SECTIONS, t]) + return + + if cmd == 'DATA WRITE' and self.state == 'offset': + self.offset = data + self.extension = self.offset // 128 + self.cnt = self.offset % 128 + if self.extension > 0: + ext = self.extension - 1 + l = len(self.ext_sn[ext]) + # Truncate or extend to self.cnt. + self.sn = self.ext_sn[ext][0:self.cnt] + [0] * max(0, self.cnt - l) + self.cache = self.ext_cache[ext][0:self.cnt] + [0] * max(0, self.cnt - l) + else: + l = len(self.sn) + self.sn = self.sn[0:self.cnt] + [0] * max(0, self.cnt - l) + self.cache = self.cache[0:self.cnt] + [0] * max(0, self.cnt - l) + ss = self.ss if self.ss else ss + s = str(data) + t = ["Offset: " + s, "O: " + s, s] + self.put(ss, es, self.out_ann, [ANN_SECTIONS, t]) + return + + # We only care about actual data bytes that are read (for now). + if cmd != 'DATA READ': + return + + self.cnt += 1 + if self.extension > 0: + self.ext_sn[self.extension - 1].append([ss, es]) + self.ext_cache[self.extension - 1].append(data) + else: + self.sn.append([ss, es]) + self.cache.append(data) + + if self.state is None or self.state == 'header': + # Wait for the EDID header + if self.cnt >= OFF_VENDOR: + if self.cache[-8:] == EDID_HEADER: + # Throw away any garbage before the header + self.sn = self.sn[-8:] + self.cache = self.cache[-8:] + self.cnt = 8 + self.state = 'edid' + self.put(self.sn[0][0], es, self.out_ann, + [ANN_SECTIONS, ['Header']]) + self.put(self.sn[0][0], es, self.out_ann, + [ANN_FIELDS, ['Header pattern']]) + elif self.state == 'edid': + if self.cnt == OFF_VERSION: + self.decode_vid(-10) + self.decode_pid(-8) + self.decode_serial(-6) + self.decode_mfrdate(-2) + self.put(self.sn[OFF_VENDOR][0], es, self.out_ann, + [ANN_SECTIONS, ['Vendor/product']]) + elif self.cnt == OFF_BASIC: + self.put(self.sn[OFF_VERSION][0], es, self.out_ann, + [ANN_SECTIONS, ['EDID Version']]) + self.put(self.sn[OFF_VERSION][0], self.sn[OFF_VERSION][1], + self.out_ann, [ANN_FIELDS, + ['Version %d' % self.cache[-2]]]) + self.put(self.sn[OFF_VERSION+1][0], self.sn[OFF_VERSION+1][1], + self.out_ann, [ANN_FIELDS, + ['Revision %d' % self.cache[-1]]]) + elif self.cnt == OFF_CHROM: + self.put(self.sn[OFF_BASIC][0], es, self.out_ann, + [ANN_SECTIONS, ['Basic display']]) + self.decode_basicdisplay(-5) + elif self.cnt == OFF_EST_TIMING: + self.put(self.sn[OFF_CHROM][0], es, self.out_ann, + [ANN_SECTIONS, ['Color characteristics']]) + self.decode_chromaticity(-10) + elif self.cnt == OFF_STD_TIMING: + self.put(self.sn[OFF_EST_TIMING][0], es, self.out_ann, + [ANN_SECTIONS, ['Established timings']]) + self.decode_est_timing(-3) + elif self.cnt == OFF_DET_TIMING: + self.put(self.sn[OFF_STD_TIMING][0], es, self.out_ann, + [ANN_SECTIONS, ['Standard timings']]) + self.decode_std_timing(self.cnt - 16) + elif self.cnt == OFF_NUM_EXT: + self.decode_descriptors(-72) + elif self.cnt == OFF_CHECKSUM: + self.put(ss, es, self.out_ann, + [0, ['Extensions present: %d' % self.cache[self.cnt-1]]]) + elif self.cnt == OFF_CHECKSUM+1: + checksum = 0 + for i in range(128): + checksum += self.cache[i] + if checksum % 256 == 0: + csstr = 'OK' + else: + csstr = 'WRONG!' + self.put(ss, es, self.out_ann, [0, ['Checksum: %d (%s)' % ( + self.cache[self.cnt-1], csstr)]]) + self.state = 'extensions' + + elif self.state == 'extensions': + cache = self.ext_cache[self.extension - 1] + sn = self.ext_sn[self.extension - 1] + v = cache[self.cnt - 1] + if self.cnt == 1: + if v == 2: + self.put(ss, es, self.out_ann, [1, ['Extensions Tag', 'Tag']]) + else: + self.put(ss, es, self.out_ann, [1, ['Bad Tag']]) + elif self.cnt == 2: + self.put(ss, es, self.out_ann, [1, ['Version']]) + self.put(ss, es, self.out_ann, [0, [str(v)]]) + elif self.cnt == 3: + self.put(ss, es, self.out_ann, [1, ['DTD offset']]) + self.put(ss, es, self.out_ann, [0, [str(v)]]) + elif self.cnt == 4: + self.put(ss, es, self.out_ann, [1, ['Format support | DTD count']]) + support = "Underscan: {0}, {1} Audio, YCbCr: {2}".format( + "yes" if v & 0x80 else "no", + "Basic" if v & 0x40 else "No", + ["None", "422", "444", "422+444"][(v & 0x30) >> 4]) + self.put(ss, es, self.out_ann, [0, ['{0}, DTDs: {1}'.format(support, v & 0xf)]]) + elif self.cnt <= cache[2]: + if self.cnt == cache[2]: + self.put(sn[4][0], es, self.out_ann, [1, ['Data block collection']]) + self.decode_data_block_collection(cache[4:], sn[4:]) + elif (self.cnt - cache[2]) % 18 == 0: + n = (self.cnt - cache[2]) / 18 + if n <= cache[3] & 0xf: + self.put(sn[self.cnt - 18][0], es, self.out_ann, [1, ['DTD']]) + self.decode_descriptors(-18) + + elif self.cnt == 127: + dtd_last = cache[2] + (cache[3] & 0xf) * 18 + self.put(sn[dtd_last][0], es, self.out_ann, [1, ['Padding']]) + elif self.cnt == 128: + checksum = sum(cache) % 256 + self.put(ss, es, self.out_ann, [0, ['Checksum: %d (%s)' % ( + cache[self.cnt-1], 'Wrong' if checksum else 'OK')]]) + + def ann_field(self, start, end, annotation): + annotation = annotation if isinstance(annotation, list) else [annotation] + sn = self.ext_sn[self.extension - 1] if self.extension else self.sn + self.put(sn[start][0], sn[end][1], + self.out_ann, [ANN_FIELDS, annotation]) + + def lookup_pnpid(self, pnpid): + pnpid_file = os.path.join(os.path.dirname(__file__), 'pnpids.txt') + if os.path.exists(pnpid_file): + for line in open(pnpid_file).readlines(): + if line.find(pnpid + ';') == 0: + return line[4:].strip() + return '' + + def decode_vid(self, offset): + pnpid = chr(64 + ((self.cache[offset] & 0x7c) >> 2)) + pnpid += chr(64 + (((self.cache[offset] & 0x03) << 3) + | ((self.cache[offset+1] & 0xe0) >> 5))) + pnpid += chr(64 + (self.cache[offset+1] & 0x1f)) + vendor = self.lookup_pnpid(pnpid) + if vendor: + pnpid += ' (%s)' % vendor + self.ann_field(offset, offset+1, pnpid) + + def decode_pid(self, offset): + pidstr = 'Product 0x%.2x%.2x' % (self.cache[offset+1], self.cache[offset]) + self.ann_field(offset, offset+1, pidstr) + + def decode_serial(self, offset): + serialnum = (self.cache[offset+3] << 24) \ + + (self.cache[offset+2] << 16) \ + + (self.cache[offset+1] << 8) \ + + self.cache[offset] + serialstr = '' + is_alnum = True + for i in range(4): + if not chr(self.cache[offset+3-i]).isalnum(): + is_alnum = False + break + serialstr += chr(self.cache[offset+3-i]) + serial = serialstr if is_alnum else str(serialnum) + self.ann_field(offset, offset+3, 'Serial ' + serial) + + def decode_mfrdate(self, offset): + datestr = '' + if self.cache[offset]: + datestr += 'week %d, ' % self.cache[offset] + datestr += str(1990 + self.cache[offset+1]) + if datestr: + self.ann_field(offset, offset+1, ['Manufactured ' + datestr, datestr]) + + def decode_basicdisplay(self, offset): + # Video input definition + vid = self.cache[offset] + if vid & 0x80: + # Digital + self.ann_field(offset, offset, 'Video input: VESA DFP 1.') + else: + # Analog + sls = (vid & 60) >> 5 + self.ann_field(offset, offset, 'Signal level standard: %.2x' % sls) + if vid & 0x10: + self.ann_field(offset, offset, 'Blank-to-black setup expected') + syncs = '' + if vid & 0x08: + syncs += 'separate syncs, ' + if vid & 0x04: + syncs += 'composite syncs, ' + if vid & 0x02: + syncs += 'sync on green, ' + if vid & 0x01: + syncs += 'Vsync serration required, ' + if syncs: + self.ann_field(offset, offset, 'Supported syncs: %s' % syncs[:-2]) + # Max horizontal/vertical image size + if self.cache[offset+1] != 0 and self.cache[offset+2] != 0: + # Projectors have this set to 0 + sizestr = '%dx%dcm' % (self.cache[offset+1], self.cache[offset+2]) + self.ann_field(offset+1, offset+2, 'Physical size: ' + sizestr) + # Display transfer characteristic (gamma) + if self.cache[offset+3] != 0xff: + gamma = (self.cache[offset+3] + 100) / 100 + self.ann_field(offset+3, offset+3, 'Gamma: %1.2f' % gamma) + # Feature support + fs = self.cache[offset+4] + dpms = '' + if fs & 0x80: + dpms += 'standby, ' + if fs & 0x40: + dpms += 'suspend, ' + if fs & 0x20: + dpms += 'active off, ' + if dpms: + self.ann_field(offset+4, offset+4, 'DPMS support: %s' % dpms[:-2]) + dt = (fs & 0x18) >> 3 + dtstr = '' + if dt == 0: + dtstr = 'Monochrome' + elif dt == 1: + dtstr = 'RGB color' + elif dt == 2: + dtstr = 'non-RGB multicolor' + if dtstr: + self.ann_field(offset+4, offset+4, 'Display type: %s' % dtstr) + if fs & 0x04: + self.ann_field(offset+4, offset+4, 'Color space: standard sRGB') + # Save this for when we decode the first detailed timing descriptor + self.have_preferred_timing = (fs & 0x02) == 0x02 + if fs & 0x01: + gft = '' + else: + gft = 'not ' + self.ann_field(offset+4, offset+4, + 'Generalized timing formula: %ssupported' % gft) + + def convert_color(self, value): + # Convert from 10-bit packet format to float + outval = 0.0 + for i in range(10): + if value & 0x01: + outval += 2 ** -(10-i) + value >>= 1 + return outval + + def decode_chromaticity(self, offset): + redx = (self.cache[offset+2] << 2) + ((self.cache[offset] & 0xc0) >> 6) + redy = (self.cache[offset+3] << 2) + ((self.cache[offset] & 0x30) >> 4) + self.ann_field(offset, offset+9, 'Chromacity red: X %1.3f, Y %1.3f' % ( + self.convert_color(redx), self.convert_color(redy))) + + greenx = (self.cache[offset+4] << 2) + ((self.cache[offset] & 0x0c) >> 6) + greeny = (self.cache[offset+5] << 2) + ((self.cache[offset] & 0x03) >> 4) + self.ann_field(offset, offset+9, 'Chromacity green: X %1.3f, Y %1.3f' % ( + self.convert_color(greenx), self.convert_color(greeny))) + + bluex = (self.cache[offset+6] << 2) + ((self.cache[offset+1] & 0xc0) >> 6) + bluey = (self.cache[offset+7] << 2) + ((self.cache[offset+1] & 0x30) >> 4) + self.ann_field(offset, offset+9, 'Chromacity blue: X %1.3f, Y %1.3f' % ( + self.convert_color(bluex), self.convert_color(bluey))) + + whitex = (self.cache[offset+8] << 2) + ((self.cache[offset+1] & 0x0c) >> 6) + whitey = (self.cache[offset+9] << 2) + ((self.cache[offset+1] & 0x03) >> 4) + self.ann_field(offset, offset+9, 'Chromacity white: X %1.3f, Y %1.3f' % ( + self.convert_color(whitex), self.convert_color(whitey))) + + def decode_est_timing(self, offset): + # Pre-EDID modes + bitmap = (self.cache[offset] << 9) \ + + (self.cache[offset+1] << 1) \ + + ((self.cache[offset+2] & 0x80) >> 7) + modestr = '' + for i in range(17): + if bitmap & (1 << (16-i)): + modestr += est_modes[i] + ', ' + if modestr: + self.ann_field(offset, offset+2, + 'Supported established modes: %s' % modestr[:-2]) + + def decode_std_timing(self, offset): + modestr = '' + for i in range(0, 16, 2): + if self.cache[offset+i] == 0x01 and self.cache[offset+i+1] == 0x01: + # Unused field + continue + x = (self.cache[offset+i] + 31) * 8 + ratio = (self.cache[offset+i+1] & 0xc0) >> 6 + ratio_x, ratio_y = xy_ratio[ratio] + y = x / ratio_x * ratio_y + refresh = (self.cache[offset+i+1] & 0x3f) + 60 + modestr += '%dx%d@%dHz, ' % (x, y, refresh) + if modestr: + self.ann_field(offset, offset + 15, + 'Supported standard modes: %s' % modestr[:-2]) + + def decode_detailed_timing(self, cache, sn, offset, is_first): + if is_first and self.have_preferred_timing: + # Only on first detailed timing descriptor + section = 'Preferred' + else: + section = 'Detailed' + section += ' timing descriptor' + + self.put(sn[0][0], sn[17][1], + self.out_ann, [ANN_SECTIONS, [section]]) + + pixclock = float((cache[1] << 8) + cache[0]) / 100 + self.ann_field(offset, offset+1, 'Pixel clock: %.2f MHz' % pixclock) + + horiz_active = ((cache[4] & 0xf0) << 4) + cache[2] + horiz_blank = ((cache[4] & 0x0f) << 8) + cache[3] + self.ann_field(offset+2, offset+4, 'Horizontal active: %d, blanking: %d' % (horiz_active, horiz_blank)) + + vert_active = ((cache[7] & 0xf0) << 4) + cache[5] + vert_blank = ((cache[7] & 0x0f) << 8) + cache[6] + self.ann_field(offset+5, offset+7, 'Vertical active: %d, blanking: %d' % (vert_active, vert_blank)) + + horiz_sync_off = ((cache[11] & 0xc0) << 2) + cache[8] + horiz_sync_pw = ((cache[11] & 0x30) << 4) + cache[9] + vert_sync_off = ((cache[11] & 0x0c) << 2) + ((cache[10] & 0xf0) >> 4) + vert_sync_pw = ((cache[11] & 0x03) << 4) + (cache[10] & 0x0f) + + syncs = (horiz_sync_off, horiz_sync_pw, vert_sync_off, vert_sync_pw) + self.ann_field(offset+8, offset+11, [ + 'Horizontal sync offset: %d, pulse width: %d, Vertical sync offset: %d, pulse width: %d' % syncs, + 'HSync off: %d, pw: %d, VSync off: %d, pw: %d' % syncs]) + + horiz_size = ((cache[14] & 0xf0) << 4) + cache[12] + vert_size = ((cache[14] & 0x0f) << 8) + cache[13] + self.ann_field(offset+12, offset+14, 'Physical size: %dx%dmm' % (horiz_size, vert_size)) + + horiz_border = cache[15] + self.ann_field(offset+15, offset+15, 'Horizontal border: %d pixels' % horiz_border) + vert_border = cache[16] + self.ann_field(offset+16, offset+16, 'Vertical border: %d lines' % vert_border) + + features = 'Flags: ' + if cache[17] & 0x80: + features += 'interlaced, ' + stereo = (cache[17] & 0x60) >> 5 + if stereo: + if cache[17] & 0x01: + features += '2-way interleaved stereo (' + features += ['right image on even lines', + 'left image on even lines', + 'side-by-side'][stereo-1] + features += '), ' + else: + features += 'field sequential stereo (' + features += ['right image on sync=1', 'left image on sync=1', + '4-way interleaved'][stereo-1] + features += '), ' + sync = (cache[17] & 0x18) >> 3 + sync2 = (cache[17] & 0x06) >> 1 + posneg = ['negative', 'positive'] + features += 'sync type ' + if sync == 0x00: + features += 'analog composite (serrate on RGB)' + elif sync == 0x01: + features += 'bipolar analog composite (serrate on RGB)' + elif sync == 0x02: + features += 'digital composite (serrate on composite polarity ' \ + + (posneg[sync2 & 0x01]) + ')' + elif sync == 0x03: + features += 'digital separate (' + features += 'Vsync polarity ' + (posneg[(sync2 & 0x02) >> 1]) + features += ', Hsync polarity ' + (posneg[sync2 & 0x01]) + features += ')' + features += ', ' + self.ann_field(offset+17, offset+17, features[:-2]) + + def decode_descriptor(self, cache, offset): + tag = cache[3] + self.ann_field(offset, offset+1, "Flag") + self.ann_field(offset+2, offset+2, "Flag (reserved)") + self.ann_field(offset+3, offset+3, "Tag: {0:X}".format(tag)) + self.ann_field(offset+4, offset+4, "Flag") + + sn = self.ext_sn[self.extension - 1] if self.extension else self.sn + + if tag == 0xff: + # Monitor serial number + self.put(sn[offset][0], sn[offset+17][1], self.out_ann, + [ANN_SECTIONS, ['Serial number']]) + text = bytes(cache[5:][:13]).decode(encoding='cp437', errors='replace') + self.ann_field(offset+5, offset+17, text.strip()) + elif tag == 0xfe: + # Text + self.put(sn[offset][0], sn[offset+17][1], self.out_ann, + [ANN_SECTIONS, ['Text']]) + text = bytes(cache[5:][:13]).decode(encoding='cp437', errors='replace') + self.ann_field(offset+5, offset+17, text.strip()) + elif tag == 0xfc: + # Monitor name + self.put(sn[offset][0], sn[offset+17][1], self.out_ann, + [ANN_SECTIONS, ['Monitor name']]) + text = bytes(cache[5:][:13]).decode(encoding='cp437', errors='replace') + self.ann_field(offset+5, offset+17, text.strip()) + elif tag == 0xfd: + # Monitor range limits + self.put(sn[offset][0], sn[offset+17][1], self.out_ann, + [ANN_SECTIONS, ['Monitor range limits']]) + self.ann_field(offset+5, offset+5, [ + 'Minimum vertical rate: {0}Hz'.format(cache[5]), + 'VSync >= {0}Hz'.format(cache[5])]) + self.ann_field(offset+6, offset+6, [ + 'Maximum vertical rate: {0}Hz'.format(cache[6]), + 'VSync <= {0}Hz'.format(cache[6])]) + self.ann_field(offset+7, offset+7, [ + 'Minimum horizontal rate: {0}kHz'.format(cache[7]), + 'HSync >= {0}kHz'.format(cache[7])]) + self.ann_field(offset+8, offset+8, [ + 'Maximum horizontal rate: {0}kHz'.format(cache[8]), + 'HSync <= {0}kHz'.format(cache[8])]) + self.ann_field(offset+9, offset+9, [ + 'Maximum pixel clock: {0}MHz'.format(cache[9] * 10), + 'PixClk <= {0}MHz'.format(cache[9] * 10)]) + if cache[10] == 0x02: + self.ann_field(offset+10, offset+10, ['Secondary timing formula supported', '2nd GTF: yes']) + self.ann_field(offset+11, offset+17, ['GTF']) + else: + self.ann_field(offset+10, offset+10, ['Secondary timing formula unsupported', '2nd GTF: no']) + self.ann_field(offset+11, offset+17, ['Padding']) + elif tag == 0xfb: + # Additional color point data + self.put(sn[offset][0], sn[offset+17][1], self.out_ann, + [ANN_SECTIONS, ['Additional color point data']]) + elif tag == 0xfa: + # Additional standard timing definitions + self.put(sn[offset][0], sn[offset+17][1], self.out_ann, + [ANN_SECTIONS, ['Additional standard timing definitions']]) + else: + self.put(sn[offset][0], sn[offset+17][1], self.out_ann, + [ANN_SECTIONS, ['Unknown descriptor']]) + + def decode_descriptors(self, offset): + # 4 consecutive 18-byte descriptor blocks + cache = self.ext_cache[self.extension - 1] if self.extension else self.cache + sn = self.ext_sn[self.extension - 1] if self.extension else self.sn + + for i in range(offset, 0, 18): + if cache[i] != 0 or cache[i+1] != 0: + self.decode_detailed_timing(cache[i:], sn[i:], i, i == offset) + else: + if cache[i+2] == 0 or cache[i+4] == 0: + self.decode_descriptor(cache[i:], i) + + def decode_data_block(self, tag, cache, sn): + codes = { 0: ['0: Reserved'], + 1: ['1: Audio Data Block', 'Audio'], + 2: ['2: Video Data Block', 'Video'], + 3: ['3: Vendor Specific Data Block', 'VSDB'], + 4: ['4: Speacker Allocation Data Block', 'SADB'], + 5: ['5: VESA DTC Data Block', 'DTC'], + 6: ['6: Reserved'], + 7: ['7: Extended', 'Ext'] } + ext_codes = { 0: [ '0: Video Capability Data Block', 'VCDB'], + 1: [ '1: Vendor Specific Video Data Block', 'VSVDB'], + 17: ['17: Vendor Specific Audio Data Block', 'VSADB'], } + if tag < 7: + code = codes[tag] + ext_len = 0 + if tag == 1: + aformats = { 1: '1 (LPCM)' } + rates = [ '192', '176', '96', '88', '48', '44', '32' ] + + aformat = cache[1] >> 3 + sup_rates = [ i for i in range(0, 8) if (1 << i) & cache[2] ] + + data = "Format: {0} Channels: {1}".format( + aformats.get(aformat, aformat), (cache[1] & 0x7) + 1) + data += " Rates: " + " ".join(rates[6 - i] for i in sup_rates) + data += " Extra: [{0:02X}]".format(cache[3]) + + elif tag ==2: + data = "VIC: " + data += ", ".join("{0}{1}".format(v & 0x7f, + ['', ' (Native)'][v >> 7]) + for v in cache[1:]) + + elif tag ==3: + ouis = { b'\x00\x0c\x03': 'HDMI Licensing, LLC' } + oui = bytes(cache[3:0:-1]) + ouis = ouis.get(oui, None) + data = "OUI: " + " ".join('{0:02X}'.format(x) for x in oui) + data += " ({0})".format(ouis) if ouis else "" + data += ", PhyAddr: {0}.{1}.{2}.{3}".format( + cache[4] >> 4, cache[4] & 0xf, cache[5] >> 4, cache[5] & 0xf) + data += ", [" + " ".join('{0:02X}'.format(x) for x in cache[6:]) + "]" + + elif tag ==4: + speakers = [ 'FL/FR', 'LFE', 'FC', 'RL/RR', + 'RC', 'FLC/FRC', 'RLC/RRC', 'FLW/FRW', + 'FLH/FRH', 'TC', 'FCH' ] + sup_speakers = cache[1] + (cache[2] << 8) + sup_speakers = [ i for i in range(0, 8) if (1 << i) & sup_speakers ] + data = "Speakers: " + " ".join(speakers[i] for i in sup_speakers) + + else: + data = " ".join('{0:02X}'.format(x) for x in cache[1:]) + + else: + # Extended tags + ext_len = 1 + ext_code = ext_codes.get(cache[1], ['Unknown', '?']) + code = zip(codes[7], [", ", ": "], ext_code) + code = [ "".join(x) for x in code ] + data = " ".join('{0:02X}'.format(x) for x in cache[2:]) + + self.put(sn[0][0], sn[0 + ext_len][1], self.out_ann, + [ANN_FIELDS, code]) + self.put(sn[1 + ext_len][0], sn[len(cache) - 1][1], self.out_ann, + [ANN_FIELDS, [data]]) + + def decode_data_block_collection(self, cache, sn): + offset = 0 + while offset < len(cache): + length = 1 + cache[offset] & 0x1f + tag = cache[offset] >> 5 + self.decode_data_block(tag, cache[offset:offset + length], sn[offset:]) + offset += length diff --git a/libsigrokdecode4DSL/decoders/edid/pnpids.txt b/libsigrokdecode4DSL/decoders/edid/pnpids.txt new file mode 100644 index 00000000..1ced20c5 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/edid/pnpids.txt @@ -0,0 +1,2135 @@ +AAE;Anatek Electronics Inc. +AAT;Ann Arbor Technologies +ABA;ABBAHOME INC. +ABC;AboCom System Inc +ABD;Allen Bradley Company +ABE;Alcatel Bell +ABO;Alcatel Bell +ABT;Anchor Bay Technologies, Inc. +ABV;Advanced Research Technology +ACA;Ariel Corporation +ACB;Aculab Ltd +ACC;Accton Technology Corporation +ACD;AWETA BV +ACE;Actek Engineering Pty Ltd +ACG;A&R Cambridge Ltd +ACH;Archtek Telecom Corporation +ACI;Ancor Communications Inc +ACK;Acksys +ACL;Apricot Computers +ACM;Acroloop Motion Control Systems Inc +ACO;Allion Computer Inc. +ACP;Aspen Tech Inc +ACR;Acer Technologies +ACS;Altos Computer Systems +ACT;Applied Creative Technology +ACU;Acculogic +ACV;ActivCard S.A +ADA;Addi-Data GmbH +ADB;Aldebbaron +ADC;Acnhor Datacomm +ADD;Advanced Peripheral Devices Inc +ADE;Arithmos, Inc. +ADH;Aerodata Holdings Ltd +ADI;ADI Systems Inc +ADK;Adtek System Science Company Ltd +ADL;ASTRA Security Products Ltd +ADM;Ad Lib MultiMedia Inc +ADN;Analog & Digital Devices Tel. Inc +ADP;Adaptec Inc +ADR;Nasa Ames Research Center +ADS;Analog Devices Inc +ADT;Adtek +ADT;Aved Display Technologies +ADV;Advanced Micro Devices Inc +ADX;Adax Inc +AEC;Antex Electronics Corporation +AED;Advanced Electronic Designs, Inc. +AEI;Actiontec Electric Inc +AEJ;Alpha Electronics Company +AEM;ASEM S.p.A. +AEP;Aetas Peripheral International +AET;Aethra Telecomunicazioni S.r.l. +AFA;Alfa Inc +AGC;Beijing Aerospace Golden Card Electronic Engineering Co.,Ltd. +AGI;Artish Graphics Inc +AGL;Argolis +AGM;Advan Int'l Corporation +AGT;Agilent Technologies +AHC;Advantech Co., Ltd. +AIC;Arnos Insturments & Computer Systems +AIE;Altmann Industrieelektronik +AII;Amptron International Inc. +AIL;Altos India Ltd +AIM;AIMS Lab Inc +AIR;Advanced Integ. Research Inc +AIS;Alien Internet Services +AIW;Aiwa Company Ltd +AIX;ALTINEX, INC. +AJA;AJA Video Systems, Inc. +AKB;Akebia Ltd +AKE;AKAMI Electric Co.,Ltd +AKI;AKIA Corporation +AKL;AMiT Ltd +AKM;Asahi Kasei Microsystems Company Ltd +AKP;Atom Komplex Prylad +AKY;Askey Computer Corporation +ALA;Alacron Inc +ALC;Altec Corporation +ALD;In4S Inc +ALG;Realtek Semiconductor Corp. +ALH;AL Systems +ALI;Acer Labs +ALJ;Altec Lansing +ALK;Acrolink Inc +ALL;Alliance Semiconductor Corporation +ALM;Acutec Ltd. +ALN;Alana Technologies +ALO;Algolith Inc. +ALP;Alps Electric Company Ltd +ALR;Advanced Logic +ALS;Avance Logic Inc +ALS;Texas Advanced optoelectronics Solutions, Inc +ALT;Altra +ALV;AlphaView LCD +ALX;ALEXON Co.,Ltd. +AMA;Asia Microelectronic Development Inc +AMB;Ambient Technologies, Inc. +AMC;Attachmate Corporation +AMD;Amdek Corporation +AMI;American Megatrends Inc +AML;Anderson Multimedia Communications (HK) Limited +AMN;Amimon LTD. +AMP;AMP Inc +AMT;AMT International Industry +AMX;AMX LLC +ANA;Anakron +ANC;Ancot +AND;Adtran Inc +ANI;Anigma Inc +ANK;Anko Electronic Company Ltd +ANL;Analogix Semiconductor, Inc +ANO;Anorad Corporation +ANP;Andrew Network Production +ANR;ANR Ltd +ANS;Ansel Communication Company +ANT;Ace CAD Enterprise Company Ltd +ANX;Acer Netxus Inc +AOA;AOpen Inc. +AOE;Advanced Optics Electronics, Inc. +AOL;America OnLine +AOT;Alcatel +APC;American Power Conversion +APD;AppliAdata +APG;Horner Electric Inc +API;A Plus Info Corporation +APL;Aplicom Oy +APM;Applied Memory Tech +APN;Appian Tech Inc +APP;Apple Computer Inc +APR;Aprilia s.p.a. +APS;Autologic Inc +APT;Audio Processing Technology Ltd +APV;A+V Link +APX;AP Designs Ltd +ARC;Alta Research Corporation +ARE;ICET S.p.A. +ARG;Argus Electronics Co., LTD +ARI;Argosy Research Inc +ARK;Ark Logic Inc +ARL;Arlotto Comnet Inc +ARM;Arima +ARO;Poso International B.V. +ARS;Arescom Inc +ART;Corion Industrial Corporation +ASC;Ascom Strategic Technology Unit +ASD;USC Information Sciences Institute +ASE;AseV Display Labs +ASI;Ahead Systems +ASK;Ask A/S +ASL;AccuScene Corporation Ltd +ASM;ASEM S.p.A. +ASN;Asante Tech Inc +ASP;ASP Microelectronics Ltd +AST;AST Research Inc +ASU;Asuscom Network Inc +ASX;AudioScience +ASY;Rockwell Collins / Airshow Systems +ATA;Allied Telesyn International (Asia) Pte Ltd +ATC;Ably-Tech Corporation +ATD;Alpha Telecom Inc +ATE;Innovate Ltd +ATH;Athena Informatica S.R.L. +ATI;Allied Telesis KK +ATK;Allied Telesyn Int'l +ATL;Arcus Technology Ltd +ATM;ATM Ltd +ATN;Athena Smartcard Solutions Ltd. +ATO;ASTRO DESIGN, INC. +ATP;Alpha-Top Corporation +ATT;AT&T +ATV;Office Depot, Inc. +ATX;Athenix Corporation +AUI;Alps Electric Inc +AUO;DO NOT USE - AUO +AUR;Aureal Semiconductor +AUT;Autotime Corporation +AVA;Avaya Communication +AVC;Auravision Corporation +AVD;Avid Electronics Corporation +AVE;Add Value Enterpises (Asia) Pte Ltd +AVI;Nippon Avionics Co.,Ltd +AVM;AVM GmbH +AVN ;Advance Computer Corporation +AVO;Avocent Corporation +AVR;AVerMedia Information, Inc. +AVT;Avtek (Electronics) Pty Ltd +AVV;SBS Technologies (Canada), Inc. (was Avvida Systems, Inc.) +AWC;Access Works Comm Inc +AWL;Aironet Wireless Communications, Inc +AWS;Wave Systems +AXB;Adrienne Electronics Corporation +AXC;AXIOMTEK CO., LTD. +AXE;D-Link Systems Inc (used as 2nd pnpid) +AXI;American Magnetics +AXL;Axel +AXP;American Express +AXT;Axtend Technologies Inc +AXX;Axxon Computer Corporation +AXY;AXYZ Automation Services, Inc +AYD;Aydin Displays +AYR;Airlib, Inc +AZM;AZ Middelheim - Radiotherapy +AZT;Aztech Systems Ltd +BAC;Biometric Access Corporation +BAN;Banyan +BBB;an-najah university +BBH;B&Bh +BBL;Brain Boxes Limited +BCC;Beaver Computer Corporaton +BCD;Dr. Seufert GmbH +BCM;Broadcom +BCQ;Deutsche Telekom Berkom GmbH +BCS;Booria CAD/CAM systems +BDO;Brahler ICS +BDR;Blonder Tongue Labs, Inc. +BDS;Barco Display Systems +BEC;Elektro Beckhoff GmbH +BEI;Beckworth Enterprises Inc +BEK;Beko Elektronik A.S. +BEL;Beltronic Industrieelektronik GmbH +BEO;Baug & Olufsen +BFE;B.F. Engineering Corporation +BGB;Barco Graphics N.V +BGT;Budzetron Inc +BHZ;BitHeadz, Inc. +BIC;Big Island Communications +BII;Boeckeler Instruments Inc +BIL;Billion Electric Company Ltd +BIO;BioLink Technologies International, Inc. +BIT;Bit 3 Computer +BLI;Busicom +BLN;BioLink Technologies +BLP;Bloomberg L.P. +BMI;Benson Medical Instruments Company +BML;BIOMED Lab +BMS;BIOMEDISYS +BNE;Bull AB +BNK;Banksia Tech Pty Ltd +BNO;Bang & Olufsen +BNS;Boulder Nonlinear Systems +BOB;Rainy Orchard +BOE;BOE +BOI;NINGBO BOIGLE DIGITAL TECHNOLOGY CO.,LTD +BOS;BOS +BPD;Micro Solutions, Inc. +BPU;Best Power +BRA;Braemac Pty Ltd +BRC;BARC +BRG;Bridge Information Co., Ltd +BRI;Boca Research Inc +BRM;Braemar Inc +BRO;BROTHER INDUSTRIES,LTD. +BSE;Bose Corporation +BSL;Biomedical Systems Laboratory +BST;BodySound Technologies, Inc. +BTC;Bit 3 Computer +BTE;Brilliant Technology +BTF;Bitfield Oy +BTI;BusTech Inc +BUF;Yasuhiko Shirai Melco Inc +BUJ;ATI Tech Inc +BUL;Bull +BUR;Bernecker & Rainer Ind-Eletronik GmbH +BUS;BusTek +BUT;21ST CENTURY ENTERTAINMENT +BWK;Bitworks Inc. +BXE;Buxco Electronics +BYD;byd:sign corporation +CAA;Castles Automation Co., Ltd +CAC;CA & F Elettronica +CAG;CalComp +CAI;Canon Inc. +CAL;Acon +CAM;Cambridge Audio +CAN;Canopus Company Ltd +CAN;Carrera Computer Inc +CAN;CORNEA +CAR;Cardinal Company Ltd +CAS;CASIO COMPUTER CO.,LTD +CAT;Consultancy in Advanced Technology +CBI;ComputerBoards Inc +CBR;Cebra Tech A/S +CBT;Cabletime Ltd +CBX;Cybex Computer Products Corporation +CCC;C-Cube Microsystems +CCI;Cache +CCJ;CONTEC CO.,LTD. +CCL;CCL/ITRI +CCP;Capetronic USA Inc +CDC;Core Dynamics Corporation +CDD;Convergent Data Devices +CDE;Colin.de +CDG;Christie Digital Systems Inc +CDI;Concept Development Inc +CDK;Cray Communications +CDN;Codenoll Technical Corporation +CDP;CalComp +CDS;Computer Diagnostic Systems +CDT;IBM Corporation +CDV;Convergent Design Inc. +CEA;Consumer Electronics Association +CEC;Chicony Electronics Company Ltd +CED;Cambridge Electronic Design Ltd +CEF;Cefar Digital Vision +CEI;Crestron Electronics, Inc. +CEM;MEC Electronics GmbH +CEN;Centurion Technologies P/L +CEP;C-DAC +CER;Ceronix +CET;TEC CORPORATION +CFG;Atlantis +CGA;Chunghwa Picture Tubes, LTD +CGS;Chyron Corp +CHA;Chase Research PLC +CHC;Chic Technology Corp. +CHD;ChangHong Electric Co.,Ltd +CHE;Acer Inc +CHG;Sichuan Changhong Electric CO, LTD. +CHI;Chrontel Inc +CHL;Chloride-R&D +CHM;CHIC TECHNOLOGY CORP. +CHO;Sichuang Changhong Corporation +CHP;CH Products +CHS;Agentur Chairos +CHT;Chunghwa Picture Tubes,LTD. +CHY;Cherry GmbH +CIC;Comm. Intelligence Corporation +CII;Cromack Industries Inc +CIL;Citicom Infotech Private Limited +CIN;Citron GmbH +CIP;Ciprico Inc +CIR;Cirrus Logic Inc +CIS;Cisco Systems Inc +CIT;Citifax Limited +CKC;The Concept Keyboard Company Ltd +CKJ;Carina System Co., Ltd. +CLA;Clarion Company Ltd +CLD;COMMAT L.t.d. +CLE;Classe Audio +CLG;CoreLogic +CLI;Cirrus Logic Inc +CLM;CrystaLake Multimedia +CLO;Clone Computers +CLT;automated computer control systems +CLV;Clevo Company +CLX;CardLogix +CMC;CMC Ltd +CMD;Colorado MicroDisplay, Inc. +CMG;Chenming Mold Ind. Corp. +CMI;C-Media Electronics +CMM;Comtime GmbH +CMN;Chimei Innolux Corporation +CMO;Chi Mei Optoelectronics corp. +CMR;Cambridge Research Systems Ltd +CMS;CompuMaster Srl +CMX;Comex Electronics AB +CNB;American Power Conversion +CNC;Alvedon Computers Ltd +CNE;Cine-tal +CNI;Connect Int'l A/S +CNN;Canon Inc +CNT;COINT Multimedia Systems +COB;COBY Electronics Co., Ltd +COD;CODAN Pty. Ltd. +COI;Codec Inc. +COL;Rockwell Collins, Inc. +COM;Comtrol Corporation +CON;Contec Company Ltd +COO;coolux GmbH +COR;Corollary Inc +COS;CoStar Corporation +COT;Core Technology Inc +COW;Polycow Productions +CPC;Ciprico Inc +CPD;CompuAdd +CPI;Computer Peripherals Inc +CPL;Compal Electronics Inc +CPQ;Compaq Computer Company +CPT;cPATH +CPX;Powermatic Data Systems +CRC;CONRAC GmbH +CRD;Cardinal Technical Inc +CRE;Creative Labs Inc +CRI;Crio Inc. +CRL;Creative Logic   +CRN;Cornerstone Imaging +CRO;Extraordinary Technologies PTY Limited +CRQ;Cirque Corporation +CRS;Crescendo Communication Inc +CRV;Cerevo Inc. +CRX;Cyrix Corporation +CSB;Transtex SA +CSC;Crystal Semiconductor +CSD;Cresta Systems Inc +CSE;Concept Solutions & Engineering +CSI;Cabletron System Inc +CSO;California Institute of Technology +CSS;CSS Laboratories +CST;CSTI Inc +CTA;CoSystems Inc +CTC;CTC Communication Development Company Ltd +CTE;Chunghwa Telecom Co., Ltd. +CTL;Creative Technology Ltd +CTM;Computerm Corporation +CTN;Computone Products +CTP;Computer Technology Corporation +CTS;Comtec Systems Co., Ltd. +CTX;Creatix Polymedia GmbH +CUB;Cubix Corporation +CUK;Calibre UK Ltd +CVA;Covia Inc. +CVS;Clarity Visual Systems +CWR;Connectware Inc +CXT;Conexant Systems +CYB;CyberVision +CYC;Cylink Corporation +CYD;Cyclades Corporation +CYL;Cyberlabs +CYT;Cytechinfo Inc +CYV;Cyviz AS +CYW;Cyberware +CYX;Cyrix Corporation +CZE;Carl Zeiss AG +DAC;Digital Acoustics Corporation +DAE;Digatron Industrie Elektronik GmbH +DAI;DAIS SET Ltd. +DAK;Daktronics +DAL;Digital Audio Labs Inc +DAN;Danelec Marine A/S +DAS;DAVIS AS +DAT;Datel Inc +DAU;Daou Tech Inc +DAV;Davicom Semiconductor Inc +DAW;DA2 Technologies Inc +DAX;Data Apex Ltd +DBD;Diebold Inc. +DBI;DigiBoard Inc +DBK;Databook Inc +DBL;Doble Engineering Company +DBN;DB Networks Inc +DCA;Digital Communications Association +DCC;Dale Computer Corporation +DCD;Datacast LLC +DCE;dSPACE GmbH +DCI;Concepts Inc +DCL;Dynamic Controls Ltd +DCM;DCM Data Products +DCO;Dialogue Technology Corporation +DCR;Decros Ltd +DCS;Diamond Computer Systems Inc +DCT;Dancall Telecom A/S +DCV;Datatronics Technology Inc +DDA;DA2 Technologies Corporation +DDD;Danka Data Devices +DDI;Data Display AG +DDS;Barco, n.v. +DDT;Datadesk Technologies Inc +DEC;Digital Equipment Corporation +DEI;Deico Electronics +DEL;Dell Inc. +DEN;Densitron Computers Ltd +DEX;idex displays +DFI;DFI +DFK;SharkTec A/S +DGA;Digiital Arts Inc +DGC;Data General Corporation +DGI;DIGI International +DGK;DugoTech Co., LTD +DGP;Digicorp European sales S.A. +DGS;Diagsoft Inc +DGT;The Dearborn Group +DGT;Dearborn Group Technology +DHP;DH Print +DHQ;Quadram +DHT;Projectavision Inc +DIA;Diadem +DIG;Digicom S.p.A. +DII;Dataq Instruments Inc +DIM;dPict Imaging, Inc. +DIN;Daintelecom Co., Ltd +DIS;Diseda S.A. +DIT;Dragon Information Technology +DJE;Capstone Visua lProduct Development +DJP;Maygay Machines, Ltd +DKY;Datakey Inc +DLB;Dolby Laboratories Inc. +DLC;Diamond Lane Comm. Corporation +DLG;Digital-Logic GmbH +DLK;D-Link Systems Inc +DLL;Dell Inc +DLT;Digitelec Informatique Park Cadera +DMB;Digicom Systems Inc +DMC;Dune Microsystems Corporation +DMM;Dimond Multimedia Systems Inc +DMP;D&M Holdings Inc, Professional Business Company +DMS;DOME imaging systems +DMT;Distributed Management Task Force, Inc. (DMTF) +DMV;NDS Ltd +DNA;DNA Enterprises, Inc. +DNG;Apache Micro Peripherals Inc +DNI;Deterministic Networks Inc. +DNT;Dr. Neuhous Telekommunikation GmbH +DNV;DiCon +DOL;Dolman Technologies Group Inc +DOM;Dome Imaging Systems +DON;DENON, Ltd. +DOT;Dotronic Mikroelektronik GmbH +DPA;DigiTalk Pro AV +DPC;Delta Electronics Inc +DPI;DocuPoint +DPL;Digital Projection Limited +DPM;ADPM Synthesis sas +DPS;Digital Processing Systems +DPT;DPT +DPX;DpiX, Inc. +DQB;Datacube Inc +DRB;Dr. Bott KG +DRC;Data Ray Corp. +DRD;DIGITAL REFLECTION INC. +DRI;Data Race Inc +DSD;DS Multimedia Pte Ltd +DSI;Digitan Systems Inc +DSM;DSM Digital Services GmbH +DSP;Domain Technology Inc +DTA;DELTATEC +DTC;DTC Tech Corporation +DTE;Dimension Technologies, Inc. +DTI;Diversified Technology, Inc. +DTK;Dynax Electronics (HK) Ltd +DTL;e-Net Inc +DTN;Datang Telephone Co +DTO;Deutsche Thomson OHG +DTT;Design & Test Technology, Inc. +DTX;Data Translation +DUA;Dosch & Amand GmbH & Company KG +DUN;NCR Corporation +DVD;Dictaphone Corporation +DVL;Devolo AG +DVS;Digital Video System +DVT;Data Video +DWE;Daewoo Electronics Company Ltd +DXC;Digipronix Control Systems +DXL;Dextera Labs Inc +DXP;Data Expert Corporation +DXS;Signet +DYC;Dycam Inc +DYM;Dymo-CoStar Corporation +DYN;Askey Computer Corporation +DYX;Dynax Electronics (HK) Ltd +EAS;Evans and Sutherland Computer +EBH;Data Price Informatica +EBT;HUALONG TECHNOLOGY CO., LTD +ECA;Electro Cam Corp. +ECC;ESSential Comm. Corporation +ECI;Enciris Technologies +ECK;Eugene Chukhlomin Sole Proprietorship, d.b.a. +ECL;Excel Company Ltd +ECM;E-Cmos Tech Corporation +ECO;Echo Speech Corporation +ECP;Elecom Company Ltd +ECS;Elitegroup Computer Systems Company Ltd +ECT;Enciris Technologies +EDC;e.Digital Corporation +EDG;Electronic-Design GmbH +EDI;Edimax Tech. Company Ltd +EDM;EDMI +EDT;Emerging Display Technologies Corp +EEE;ET&T Technology Company Ltd +EEH;EEH Datalink GmbH +EEP;E.E.P.D. GmbH +EES;EE Solutions, Inc. +EGD;EIZO GmbH Display Technologies +EGL;Eagle Technology +EGN;Egenera, Inc. +EGO;Ergo Electronics +EHJ;Epson Research +EHN;Enhansoft +EIC;Eicon Technology Corporation +EKA;MagTek Inc. +EKC;Eastman Kodak Company +EKS;EKSEN YAZILIM +ELA;ELAD srl +ELC;Electro Scientific Ind +ELE;Elecom Company Ltd +ELG;Elmeg GmbH Kommunikationstechnik +ELI;Edsun Laboratories +ELL;Electrosonic Ltd +ELM;Elmic Systems Inc +ELO;Elo TouchSystems Inc +ELO;Tyco Electronics +ELS;ELSA GmbH +ELT;Element Labs, Inc. +ELX;Elonex PLC +EMB;Embedded computing inc ltd +EMC;eMicro Corporation +EME;EMiNE TECHNOLOGY COMPANY, LTD. +EMG;EMG Consultants Inc +EMI;Ex Machina Inc +EMU;Emulex Corporation +ENC;Eizo Nanao Corporation +END;ENIDAN Technologies Ltd +ENE;ENE Technology Inc. +ENI;Efficient Networks +ENS;Ensoniq Corporation +ENT;Enterprise Comm. & Computing Inc +EPC;Empac +EPI;Envision Peripherals, Inc +EPN;EPiCON Inc. +EPS;KEPS +EQP;Equipe Electronics Ltd. +EQX;Equinox Systems Inc +ERG;Ergo System +ERI;Ericsson Mobile Communications AB +ERN;Ericsson, Inc. +ERP;Euraplan GmbH +ERT;Escort Insturments Corporation +ESA;Elbit Systems of America +ESC;Eden Sistemas de Computacao S/A +ESD;Ensemble Designs, Inc +ESG;ELCON Systemtechnik GmbH +ESI;Extended Systems, Inc. +ESK;ES&S +ESS;ESS Technology Inc +EST;Embedded Solution Technology +ESY;E-Systems Inc +ETC;Everton Technology Company Ltd +ETD;ELAN MICROELECTRONICS CORPORATION +ETH;Etherboot Project +ETI;Eclipse Tech Inc +ETK;eTEK Labs Inc. +ETL;Evertz Microsystems Ltd. +ETS;Electronic Trade Solutions Ltd +ETT;E-Tech Inc +EUT;Ericsson Mobile Networks B.V. +EVI;eviateg GmbH +EVX;Everex +EXA;Exabyte +EXC;Excession Audio +EXI;Exide Electronics +EXN;RGB Systems, Inc. dba Extron Electronics +EXP;Data Export Corporation +EXT;Exatech Computadores & Servicos Ltda +EXX;Exxact GmbH +EXY;Exterity Ltd +EZE;EzE Technologies +EZP;Storm Technology +FAR;Farallon Computing +FBI;Interface Corporation +FCB;Furukawa Electric Company Ltd +FCG;First International Computer Ltd +FCS;Focus Enhancements, Inc. +FDC;Future Domain +FDT;Fujitsu Display Technologies Corp. +FEC;FURUNO ELECTRIC CO., LTD. +FEL;Fellowes & Questec +FEN;Fen Systems Ltd. +FER;Ferranti Int'L +FFI;Fairfield Industries +FGD;Lisa Draexlmaier GmbH +FGL;Fujitsu General Limited. +FHL;FHLP +FIC;Formosa Industrial Computing Inc +FIL;Forefront Int'l Ltd +FIN;Finecom Co., Ltd. +FIR;Chaplet Systems Inc +FIS;FLY-IT Simulators +FIT;Feature Integration Technology Inc. +FJC;Fujitsu Takamisawa Component Limited +FJS;Fujitsu Spain +FJT;F.J. Tieman BV +FLE;ADTI Media, Inc +FLI;Faroudja Laboratories +FLY;Butterfly Communications +FMA;Fast Multimedia AG +FMC;Ford Microelectronics Inc +FMI;Fujitsu Microelect Inc +FMI;Fellowes, Inc. +FML;Fujitsu Microelect Ltd +FMZ;Formoza-Altair +FNC;Fanuc LTD +FNI;Funai Electric Co., Ltd. +FOA;FOR-A Company Limited +FOS;Foss Tecator +FOX;HON HAI PRECISON IND.CO.,LTD. +FPE;Fujitsu Peripherals Ltd +FPS;Deltec Corporation +FPX;Cirel Systemes +FRC;Force Computers +FRD;Freedom Scientific BLV +FRE;Forvus Research Inc +FRI;Fibernet Research Inc +FRS;South Mountain Technologies, LTD +FSC;Future Systems Consulting KK +FSI;Fore Systems Inc +FST;Modesto PC Inc +FTC;Futuretouch Corporation +FTE;Frontline Test Equipment Inc. +FTG;FTG Data Systems +FTI;FastPoint Technologies, Inc. +FTN;Fountain Technologies Inc +FTR;Mediasonic +FUJ;Fujitsu Ltd +FUN;sisel muhendislik +FUS;Fujitsu Siemens Computers GmbH +FVC;First Virtual Corporation +FVX;C-C-C Group Plc +FWA;Attero Tech, LLC +FWR;Flat Connections Inc +FXX;Fuji Xerox +FZC;Founder Group Shenzhen Co. +FZI;FZI Forschungszentrum Informatik +GAG;Gage Applied Sciences Inc +GAL;Galil Motion Control +GAU;Gaudi Co., Ltd. +GCC;GCC Technologies Inc +GCI;Gateway Comm. Inc +GCS;Grey Cell Systems Ltd +GDC;General Datacom +GDI;G. Diehl ISDN GmbH +GDS;GDS +GDT;Vortex Computersysteme GmbH +GEF;GE Fanuc Embedded Systems +GEH;GE Intelligent Platforms - Huntsville +GEM;Gem Plus +GEN;Genesys ATE Inc +GEO;GEO Sense +GES;GES Singapore Pte Ltd +GET;Getac Technology Corporation +GFM;GFMesstechnik GmbH +GFN;Gefen Inc. +GGL;Google Inc. +GIC;General Inst. Corporation +GIM;Guillemont International +GIS;AT&T Global Info Solutions +GJN;Grand Junction Networks +GLE;AD electronics +GLM;Genesys Logic +GLS;Gadget Labs LLC +GMK;GMK Electronic Design GmbH +GML;General Information Systems +GMM;GMM Research Inc +GMN;GEMINI 2000 Ltd +GMX;GMX Inc +GND;Gennum Corporation +GNN;GN Nettest Inc +GNZ;Gunze Ltd +GRA;Graphica Computer +GRE;GOLD RAIN ENTERPRISES CORP. +GRH;Granch Ltd +GRV;Advanced Gravis +GRY;Robert Gray Company +GSB;NIPPONDENCHI CO,.LTD +GSC;General Standards Corporation +GSM;Goldstar Company Ltd +GST;Graphic SystemTechnology +GSY;Grossenbacher Systeme AG +GTC;Graphtec Corporation +GTI;Goldtouch +GTK;G-Tech Corporation +GTM;Garnet System Company Ltd +GTS;Geotest Marvin Test Systems Inc +GTT;General Touch Technology Co., Ltd. +GUD;Guntermann & Drunck GmbH +GUZ;Guzik Technical Enterprises +GVC;GVC Corporation +GVL;Global Village Communication +GWI;GW Instruments +GWY;Gateway 2000 +GZE;GUNZE Limited +HAE;Haider electronics +HAI;Haivision Systems Inc. +HAL;Halberthal +HAN;Hanchang System Corporation +HAY;Hayes Microcomputer Products Inc +HCA;DAT +HCE;Hitachi Consumer Electronics Co., Ltd +HCL;HCL America Inc +HCM;HCL Peripherals +HCP;Hitachi Computer Products Inc +HCW;Hauppauge Computer Works Inc +HDC;HardCom Elektronik & Datateknik +HDI;HD-INFO d.o.o. +HDV;Holografika kft. +HEC;Hitachi Engineering Company Ltd +HEC;Hisense Electric Co., Ltd. +HEL;Hitachi Micro Systems Europe Ltd +HER;Ascom Business Systems +HET;HETEC Datensysteme GmbH +HHC;HIRAKAWA HEWTECH CORP. +HIB;Hibino Corporation +HIC;Hitachi Information Technology Co., Ltd. +HIK;Hikom Co., Ltd. +HIL;Hilevel Technology +HIT;Hitachi America Ltd +HJI;Harris & Jeffries Inc +HKA;HONKO MFG. CO., LTD. +HKG;Josef Heim KG +HMC;Hualon Microelectric Corporation +HMK;hmk Daten-System-Technik BmbH +HMX;HUMAX Co., Ltd. +HNS;Hughes Network Systems +HOB;HOB Electronic GmbH +HOE;Hosiden Corporation +HOL;Holoeye Photonics AG +HPA;Zytor Communications +HPC;Hewlett Packard Co. +HPD;Hewlett Packard +HPI;Headplay, Inc. +HPK;HAMAMATSU PHOTONICS K.K. +HPQ;HP +HPR;H.P.R. Electronics GmbH +HRC;Hercules +HRE;Qingdao Haier Electronics Co., Ltd. +HRL;Herolab GmbH +HRS;Harris Semiconductor +HRT;HERCULES +HSC;Hagiwara Sys-Com Company Ltd +HSD;HannStar Display Corp +HSM;AT&T Microelectronics +HSP;HannStar Display Corp +HTC;Hitachi Ltd +HTI;Hampshire Company, Inc. +HTK;Holtek Microelectronics Inc +HTX;Hitex Systementwicklung GmbH +HUB;GAI-Tronics, A Hubbell Company +HUM;IMP Electronics Ltd. +HWA;Harris Canada Inc +HWC;DBA Hans Wedemeyer +HWD;Highwater Designs Ltd +HWP;Hewlett Packard +HXM;Hexium Ltd. +HYC;Hypercope Gmbh Aachen +HYD;Hydis Technologies.Co.,LTD +HYO;HYC CO., LTD. +HYP;Hyphen Ltd +HYR;Hypertec Pty Ltd +HYT;Heng Yu Technology (HK) Limited +HYV;Hynix Semiconductor +IAF;Institut f r angewandte Funksystemtechnik GmbH +IAI;Integration Associates, Inc. +IAT;IAT Germany GmbH +IBC;Integrated Business Systems +IBI;INBINE.CO.LTD +IBM;IBM Brasil +IBM;IBM France +IBP;IBP Instruments GmbH +IBR;IBR GmbH +ICA;ICA Inc +ICC;BICC Data Networks Ltd +ICD;ICD Inc +ICE;IC Ensemble +ICI;Infotek Communication Inc +ICM;Intracom SA +ICN;Sanyo Icon +ICO;Intel Corp +ICS;Integrated Circuit Systems +ICV;Inside Contactless +ICX;ICCC A/S +IDC;International Datacasting Corporation +IDE;IDE Associates +IDK;IDK Corporation +IDO;IDEO Product Development +IDP;Integrated Device Technology, Inc. +IDS;Interdigital Sistemas de Informacao +IDT;International Display Technology +IDX;IDEXX Labs +IEC;Interlace Engineering Corporation +IEE;IEE +IEI;Interlink Electronics +IFS;In Focus Systems Inc +IFT;Informtech +IFX;Infineon Technologies AG +IGC;Intergate Pty Ltd +IGM;IGM Communi +IHE;InHand Electronics +IIC;ISIC Innoscan Industrial Computers A/S +III;Intelligent Instrumentation +IIN;IINFRA Co., Ltd +IKS;Ikos Systems Inc +ILC;Image Logic Corporation +ILS;Innotech Corporation +IMA;Imagraph +IMC;IMC Networks +IMD;ImasDe Canarias S.A. +IME;Imagraph +IMG;IMAGENICS Co., Ltd. +IMI;International Microsystems Inc +IMM;Immersion Corporation +IMN;Impossible Production +IMP;Impression Products Incorporated +IMT;Inmax Technology Corporation +INC;Home Row Inc +IND;ILC +INE;Inventec Electronics (M) Sdn. Bhd. +INF;Inframetrics Inc +ING;Integraph Corporation +INI;Initio Corporation +INK;Indtek Co., Ltd. +INL;InnoLux Display Corporation +INM;InnoMedia Inc +INN;Innovent Systems, Inc. +INO;Innolab Pte Ltd +INP;Interphase Corporation +INS;Ines GmbH +INT;Interphase Corporation +inu;Inovatec S.p.A. +INV;Inviso, Inc. +INZ;Best Buy +IOA;CRE Technology Corporation +IOD;I-O Data Device Inc +IOM;Iomega +ION;Inside Out Networks +IOS;i-O Display System +IOT;I/OTech Inc +IPC;IPC Corporation +IPD;Industrial Products Design, Inc. +IPI;Intelligent Platform Management Interface (IPMI) forum (Intel, HP, NEC, Dell) +IPM;IPM Industria Politecnica Meridionale SpA +IPN;Performance Technologies +IPR;Ithaca Peripherals +IPS;IPS, Inc. (Intellectual Property Solutions, Inc.) +IPT;International Power Technologies +IPW;IPWireless, Inc +IQT;IMAGEQUEST Co., Ltd +IRD;IRdata +ISA;Symbol Technologies +ISC;Id3 Semiconductors +ISG;Insignia Solutions Inc +ISI;Interface Solutions +ISL;Isolation Systems +ISM;Image Stream Medical +ISP;IntreSource Systems Pte Ltd +ISR;INSIS Co., LTD. +ISS;ISS Inc +IST;Intersolve Technologies +ISY;International Integrated Systems,Inc.(IISI) +ITA;Itausa Export North America +ITC;Intercom Inc +ITD;Internet Technology Corporation +ITE;Integrated Tech Express Inc +ITK;ITK Telekommunikation AG +ITL;Inter-Tel +ITM;ITM inc. +ITN;The NTI Group +ITP;IT-PRO Consulting und Systemhaus GmbH +ITR;Infotronic America, Inc. +ITS;IDTECH +ITT;I&T Telecom. +ITX;integrated Technology Express Inc +IUC;ICSL +IVI;Intervoice Inc +IVM;Liyama North America +IWR;Icuiti Corporation +IWX;Intelliworxx, Inc. +IXD;Intertex Data AB +JAC;Astec Inc +JAE;Japan Aviation Electronics Industry, Limited +JAS;Janz Automationssysteme AG +JAT;Jaton Corporation +JAZ;Carrera Computer Inc (used as second pnpid) +JCE;Jace Tech Inc +JDL;Japan Digital Laboratory Co.,Ltd. +JEN;N-Vision +JET;JET POWER TECHNOLOGY CO., LTD. +JFX;Jones Futurex Inc +JGD;University College +JIC;Jaeik Information & Communication Co., Ltd. +JMT;Micro Technical Company Ltd +JPC;JPC Technology Limited +JPW;Wallis Hamilton Industries +JQE;CNet Technical Inc +JSD;JS DigiTech, Inc +JSI;Jupiter Systems, Inc. +JSK;SANKEN ELECTRIC CO., LTD +JTS;JS Motorsports +JTY;jetway security micro,inc +JUK;Janich & Klass Computertechnik GmbH +JUP;Jupiter Systems +JVC;JVC +JWD;Video International Inc. +JWL;Jewell Instruments, LLC +JWS;JWSpencer & Co. +JWY;Jetway Information Co., Ltd +KAR;Karna +KBI;Kidboard Inc +KBL;Kobil Systems GmbH +KCL;Keycorp Ltd +KDE;KDE +KDK;Kodiak Tech +KDM;Korea Data Systems Co., Ltd. +KDS;KDS USA +KEC;Kyushu Electronics Systems Inc +KEM;Kontron Embedded Modules GmbH +KES;Kesa Corporation +KEY;Key Tech Inc +KFC;SCD Tech +KFE ;Komatsu Forest +KFX;Kofax Image Products +KIS;KiSS Technology A/S +KMC;Mitsumi Company Ltd +KML;Kensington Microware Ltd +KNC;Konica corporation +KNX;Nutech Marketing PTL +KOB;Kobil Systems GmbH +KOD;Eastman Kodak Company +KOE;KOLTER ELECTRONIC +KOL;Kollmorgen Motion Technologies Group +KOW;KOWA Company,LTD. +KPC;King Phoenix Company +KRL;Krell Industries Inc. +KRM;Kroma Telecom +KRY;Kroy LLC +KSC;Kinetic Systems Corporation +KSL;Karn Solutions Ltd. +KSX;King Tester Corporation +KTC;Kingston Tech Corporation +KTD;Takahata Electronics Co.,Ltd. +KTE;K-Tech +KTG;Kayser-Threde GmbH +KTI;Konica Technical Inc +KTK;Key Tronic Corporation +KTN;Katron Tech Inc +KUR;Kurta Corporation +KVA;Kvaser AB +KWD;Kenwood Corporation +KYC;Kyocera Corporation +KYE;KYE Syst Corporation +KYK;Samsung Electronics America Inc +KZI;K-Zone International co. Ltd. +KZN;K-Zone International +LAB;ACT Labs Ltd +LAC;LaCie +LAF;Microline +LAG;Laguna Systems +LAN;Sodeman Lancom Inc +LAS;LASAT Comm. A/S +LAV;Lava Computer MFG Inc +LBO;Lubosoft +LCC;LCI +LCD;Toshiba Matsushita Display Technology Co., Ltd +LCE;La Commande Electronique +LCI;Lite-On Communication Inc +LCM;Latitude Comm. +LCN;LEXICON +LCS;Longshine Electronics Company +LCT;Labcal Technologies +LDT;LogiDataTech Electronic GmbH +LEC;Lectron Company Ltd +LED;Long Engineering Design Inc +LEG;Legerity, Inc +LEN;Lenovo Group Limited +LEO;First International Computer Inc +LEX;Lexical Ltd +LGC;Logic Ltd +LGI;Logitech Inc +LGS;LG Semicom Company Ltd +LGX;Lasergraphics, Inc. +LHA;Lars Haagh ApS +LHE;Lung Hwa Electronics Company Ltd +LHT;Lighthouse Technologies Limited +LIP;Linked IP GmbH +LIT;Lithics Silicon Technology +LJX;Datalogic Corporation +LKM;Likom Technology Sdn. Bhd. +LLL;L-3 Communications +LMG;Lucent Technologies +LMI;Lexmark Int'l Inc +LMP;Leda Media Products +LMT;Laser Master +LND;Land Computer Company Ltd +LNK;Link Tech Inc +LNR;Linear Systems Ltd. +LNT;LANETCO International +LNV;Lenovo +LOC;Locamation B.V. +LOE;Loewe Opta GmbH +LOG;Logicode Technology Inc +LPE;El-PUSK Co., Ltd. +LPI;Design Technology +LPL;DO NOT USE - LPL +LSC;LifeSize Communications +LSI;Loughborough Sound Images +LSJ;LSI Japan Company Ltd +LSL;Logical Solutions +LSY;LSI Systems Inc +LTC;Labtec Inc +LTI;Jongshine Tech Inc +LTK;Lucidity Technology Company Ltd +LTN;Litronic Inc +LTS;LTS Scale LLC +LTV;Leitch Technology International Inc. +LTW;Lightware, Inc +LUC;Lucent Technologies +LUM;Lumagen, Inc. +LUX;Luxxell Research Inc +LWC;Labway Corporation +LWR;Lightware Visual Engineering +LWW;Lanier Worldwide +LXN;Luxeon +LXS;ELEA CardWare +LZX;Lightwell Company Ltd +MAC;MAC System Company Ltd +MAD;Xedia Corporation +MAE;Maestro Pty Ltd +MAG;MAG InnoVision +MAI;Mutoh America Inc +MAL;Meridian Audio Ltd +MAN;LGIC +MAS;Mass Inc. +MAT;Matsushita Electric Ind. Company Ltd +MAX;Rogen Tech Distribution Inc +MAY;Maynard Electronics +MAZ;MAZeT GmbH +MBC;MBC +MBD;Microbus PLC +MBM;Marshall Electronics +MBV;Moreton Bay +MCA;American Nuclear Systems Inc +MCC;Micro Industries +MCD;McDATA Corporation +MCE;Metz-Werke GmbH & Co KG +MCG;Motorola Computer Group +MCI;Micronics Computers +MCL;Motorola Communications Israel +MCM;Metricom Inc +MCN;Micron Electronics Inc +MCO;Motion Computing Inc. +MCP;Magni Systems Inc +MCQ;Mat's Computers +MCR;Marina Communicaitons +MCS;Micro Computer Systems +MCT;Microtec +MDA;Media4 Inc +MDC;Midori Electronics +MDD;MODIS +MDG;Madge Networks +MDI;Micro Design Inc +MDK;Mediatek Corporation +MDO;Panasonic +MDR;Medar Inc +MDS;Micro Display Systems Inc +MDT;Magus Data Tech +MDV;MET Development Inc +MDX;MicroDatec GmbH +MDY;Microdyne Inc +MEC;Mega System Technologies Inc +MED;Messeltronik Dresden GmbH +MEE;Mitsubishi Electric Engineering Co., Ltd. +MEG;Abeam Tech Ltd +MEI;Panasonic Industry Company +MEL;Mitsubishi Electric Corporation +MEN;MEN Mikroelectronik Nueruberg GmbH +MEQ;Matelect Ltd. +MET;Metheus Corporation +MFG;MicroField Graphics Inc +MFI;Micro Firmware +MFR;MediaFire Corp. +MGA;Mega System Technologies, Inc. +MGC;Mentor Graphics Corporation +MGE;Schneider Electric S.A. +MGL;M-G Technology Ltd +MGT;Megatech R & D Company +MIC;Micom Communications Inc +MID;miro Displays +MII;Mitec Inc +MIL;Marconi Instruments Ltd +MIN;Minicom Digital Signage +MIP;micronpc.com +MIR;Miro Computer Prod. +MIS;Modular Industrial Solutions Inc +MIT;MCM Industrial Technology GmbH +MJI;MARANTZ JAPAN, INC. +MJS;MJS Designs +MKC;Media Tek Inc. +MKT;MICROTEK Inc. +MKV;Trtheim Technology +MLD;Deep Video Imaging Ltd +MLG;Micrologica AG +MLI;McIntosh Laboratory Inc. +MLM;Millennium Engineering Inc +MLN;Mark Levinson +MLS;Milestone EPE +MLX;Mylex Corporation +MMA;Micromedia AG +MMD;Micromed Biotecnologia Ltd +MMF;Minnesota Mining and Manufacturing +MMI;Multimax +MMM;Electronic Measurements +MMN;MiniMan Inc +MMS;MMS Electronics +MNC;Mini Micro Methods Ltd +MNL;Monorail Inc +MNP;Microcom +MOD;Modular Technology +MOM;Momentum Data Systems +MOS;Moses Corporation +MOT;Motorola UDS +MPC;M-Pact Inc +MPI;Mediatrix Peripherals Inc +MPJ;Microlab +MPL;Maple Research Inst. Company Ltd +MPN;Mainpine Limited +MPS;mps Software GmbH +MPX;Micropix Technologies, Ltd. +MQP;MultiQ Products AB +MRA;Miranda Technologies Inc +MRC;Marconi Simulation & Ty-Coch Way Training +MRD;MicroDisplay Corporation +MRK;Maruko & Company Ltd +MRL;Miratel +MRO;Medikro Oy +MRT;Merging Technologies +MSA;Micro Systemation AB +MSC;Mouse Systems Corporation +MSD;Datenerfassungs- und Informationssysteme +MSF;M-Systems Flash Disk Pioneers +MSG;MSI GmbH +MSH;Microsoft +MSI;Microstep +MSK;Megasoft Inc +MSL;MicroSlate Inc. +MSM;Advanced Digital Systems +MSP;Mistral Solutions [P] Ltd. +MST;MS Telematica +MSU;motorola +MSV;Mosgi Corporation +MSX;Micomsoft Co., Ltd. +MSY;MicroTouch Systems Inc +MTB;Media Technologies Ltd. +MTC;Mars-Tech Corporation +MTD;MindTech Display Co. Ltd +MTE;MediaTec GmbH +MTH;Micro-Tech Hearing Instruments +MTI;MaxCom Technical Inc +MTI;Motorola Inc. +MTK;Microtek International Inc. +MTL;Mitel Corporation +MTN;Mtron Storage Technology Co., Ltd. +MTR;Mitron computer Inc +MTS;Multi-Tech Systems +MTU;Mark of the Unicorn Inc +MTX;Matrox +MUD;Multi-Dimension Institute +MUK;mainpine limited +MVD;Microvitec PLC +MVI;Media Vision Inc +MVM;SOBO VISION +MVS;Microvision +MVX;COM 1 +MWI;Multiwave Innovation Pte Ltd +MWR;mware +MWY;Microway Inc +MXD;MaxData Computer GmbH & Co.KG +MXI;Macronix Inc +MXL;Hitachi Maxell, Ltd. +MXP;Maxpeed Corporation +MXT;Maxtech Corporation +MXV;MaxVision Corporation +MYA;Monydata +MYR;Myriad Solutions Ltd +MYX;Micronyx Inc +NAC;Ncast Corporation +NAD;NAD Electronics +NAK;Nakano Engineering Co.,Ltd. +NAL;Network Alchemy +NAT;NaturalPoint Inc. +NAV;Navigation Corporation +NAX;Naxos Tecnologia +NBL;N*Able Technologies Inc +NBS;National Key Lab. on ISN +NBT;NingBo Bestwinning Technology CO., Ltd +NCA;Nixdorf Company +NCC;NCR Corporation +NCE;Norcent Technology, Inc. +NCI;NewCom Inc +NCL;NetComm Ltd +NCR;NCR Electronics +NCS;Northgate Computer Systems +NCT;NEC CustomTechnica, Ltd. +NDC;National DataComm Corporaiton +NDI;National Display Systems +NDK;Naitoh Densei CO., LTD. +NDL;Network Designers +NDS;Nokia Data +NEC;NEC Corporation +NEO;NEO TELECOM CO.,LTD. +NET;Mettler Toledo +NEU;NEUROTEC - EMPRESA DE PESQUISA E DESENVOLVIMENTO EM BIOMEDICINA +NEX;Nexgen Mediatech Inc., +NFC;BTC Korea Co., Ltd +NFS;Number Five Software +NGC;Network General +NGS;A D S Exports +NHT;Vinci Labs +NIC;National Instruments Corporation +NIS;Nissei Electric Company +NIT;Network Info Technology +NIX;Seanix Technology Inc +NLC;Next Level Communications +NMP;Nokia Mobile Phones +NMS;Natural Micro System +NMV;NEC-Mitsubishi Electric Visual Systems Corporation +NMX;Neomagic +NNC;NNC +NOE;NordicEye AB +NOI;North Invent A/S +NOK;Nokia Display Products +NOR;Norand Corporation +NOT;Not Limited Inc +NPI;Network Peripherals Inc +NRL;U.S. Naval Research Lab +NRT;Beijing Northern Radiantelecom Co. +NRV;Taugagreining hf +NSC;National Semiconductor Corporation +NSI;NISSEI ELECTRIC CO.,LTD +NSP;Nspire System Inc. +NSS;Newport Systems Solutions +NST;Network Security Technology Co +NTC;NeoTech S.R.L +NTI;New Tech Int'l Company +NTL;National Transcomm. Ltd +NTN;Nuvoton Technology Corporation +NTR;N-trig Innovative Technologies, Inc. +NTS;Nits Technology Inc. +NTT;NTT Advanced Technology Corporation +NTW;Networth Inc +NTX;Netaccess Inc +NUG;NU Technology, Inc. +NUI;NU Inc. +NVC;NetVision Corporation +NVD;Nvidia +NVI;NuVision US, Inc. +NVL;Novell Inc +NVT;Navatek Engineering Corporation +NWC;NW Computer Engineering +NWP;NovaWeb Technologies Inc +NWS;Newisys, Inc. +NXC;NextCom K.K. +NXG;Nexgen +NXP;NXP Semiconductors bv. +NXQ;Nexiq Technologies, Inc. +NXS;Technology Nexus Secure Open Systems AB +NYC;nakayo telecommunications,inc. +OAK;Oak Tech Inc +OAS;Oasys Technology Company +OBS;Optibase Technologies +OCD;Macraigor Systems Inc +OCN;Olfan +OCS;Open Connect Solutions +ODM;ODME Inc. +ODR;Odrac +OEC;ORION ELECTRIC CO.,LTD +OEI;Optum Engineering Inc. +OIC;Option Industrial Computers +OIM;Option International +OIN;Option International +OKI;OKI Electric Industrial Company Ltd +OLC;Olicom A/S +OLD;Olidata S.p.A. +OLI;Olivetti +OLT;Olitec S.A. +OLV;Olitec S.A. +OLY;OLYMPUS CORPORATION +OMC;OBJIX Multimedia Corporation +OMN;Omnitel +OMR;Omron Corporation +ONE;Oneac Corporation +ONK;ONKYO Corporation +ONL;OnLive, Inc +ONS;On Systems Inc +ONW;OPEN Networks Ltd +ONX;SOMELEC Z.I. Du Vert Galanta +OOS;OSRAM +OPC;Opcode Inc +OPI;D.N.S. Corporation +OPT;OPTi Inc +OPV;Optivision Inc +OQI;Oksori Company Ltd +ORG;ORGA Kartensysteme GmbH +ORI;OSR Open Systems Resources, Inc. +ORN;ORION ELECTRIC CO., LTD. +OSA;OSAKA Micro Computer, Inc. +OSP;OPTI-UPS Corporation +OSR;Oksori Company Ltd +OTB;outsidetheboxstuff.com +OTI;Orchid Technology +OTM;Optoma Corporation           +OTT;OPTO22, Inc. +OUK;OUK Company Ltd +OWL;Mediacom Technologies Pte Ltd +OXU;Oxus Research S.A. +OYO;Shadow Systems +OZO;Tribe Computer Works Inc +PAC;Pacific Avionics Corporation +PAD;Promotion and Display Technology Ltd. +PAK;Many CNC System Co., Ltd. +PAM;Peter Antesberger Messtechnik +PAN;The Panda Project +PAR;Parallan Comp Inc +PBI;Pitney Bowes +PBL;Packard Bell Electronics +PBN;Packard Bell NEC +PBV;Pitney Bowes +PCA;Philips BU Add On Card +PCB;OCTAL S.A. +PCC;PowerCom Technology Company Ltd +PCG;First Industrial Computer Inc +PCI;Pioneer Computer Inc +PCK;PCBANK21 +PCL;pentel.co.,ltd +PCM;PCM Systems Corporation +PCO;Performance Concepts Inc., +PCP;Procomp USA Inc +PCS;TOSHIBA PERSONAL COMPUTER SYSTEM CORPRATION +PCT;PC-Tel Inc +PCW;Pacific CommWare Inc +PCX;PC Xperten +PDM;Psion Dacom Plc. +PDN;AT&T Paradyne +PDR;Pure Data Inc +PDS;PD Systems International Ltd +PDT;PDTS - Prozessdatentechnik und Systeme +PDV;Prodrive B.V. +PEC;POTRANS Electrical Corp. +PEI;PEI Electronics Inc +PEL;Primax Electric Ltd +PEN;Interactive Computer Products Inc +PEP;Peppercon AG +PER;Perceptive Signal Technologies +PET;Practical Electronic Tools +PFT;Telia ProSoft AB +PGM;Paradigm Advanced Research Centre +PGP;propagamma kommunikation +PGS;Princeton Graphic Systems +PHC;Pijnenburg Beheer N.V. +PHE;Philips Medical Systems Boeblingen GmbH +PHI;DO NOT USE - PHI +PHL;Philips Consumer Electronics Company +PHO;Photonics Systems Inc. +PHS;Philips Communication Systems +PHY;Phylon Communications +PIE;Pacific Image Electronics Company Ltd +PIM;Prism, LLC +PIO;Pioneer Electronic Corporation +PIX;Pixie Tech Inc +PJA;Projecta +PJD;Projectiondesign AS +PJT;Pan Jit International Inc. +PKA;Acco UK ltd. +PLC;Pro-Log Corporation +PLF;Panasonic Avionics Corporation +PLM;PROLINK Microsystems Corp. +PLT;PT Hartono Istana Teknologi +PLV;PLUS Vision Corp. +PLX;Parallax Graphics +PLY;Polycom Inc. +PMC;PMC Consumer Electronics Ltd +PMD;TDK USA Corporation +PMM;Point Multimedia System +PMT;Promate Electronic Co., Ltd. +PMX;Photomatrix +PNG;Microsoft +PNG;P.I. Engineering Inc +PNL;Panelview, Inc. +PNP;Microsoft +PNR;Planar Systems, Inc. +PNS;PanaScope +PNX;Phoenix Technologies, Ltd. +POL;PolyComp (PTY) Ltd. +PON;Perpetual Technologies, LLC +POR;Portalis LC +PPC;Phoenixtec Power Company Ltd +PPD;MEPhI +PPI;Practical Peripherals +PPM;Clinton Electronics Corp. +PPP;Purup Prepress AS +PPR;PicPro +PPX;Perceptive Pixel Inc. +PQI;Pixel Qi +PRA;PRO/AUTOMATION +PRC;PerComm +PRD;Praim S.R.L. +PRF;Digital Electronics Corporation +PRG;The Phoenix Research Group Inc +PRI;Priva Hortimation BV +PRM;Prometheus +PRO;Proteon +PRS;Leutron Vision +PRX;Proxima Corporation +PSA;Advanced Signal Processing Technologies +PSC;Philips Semiconductors +PSD;Peus-Systems GmbH +PSE;Practical Solutions Pte., Ltd. +PSI;PSI-Perceptive Solutions Inc +PSL;Perle Systems Limited +PSM;Prosum +PST;Global Data SA +PTC;PS Technology Corporation +PTG;Cipher Systems Inc +PTH;Pathlight Technology Inc +PTI;Promise Technology Inc +PTL;Pantel Inc +PTS;Plain Tree Systems Inc +PTW;DO NOT USE +PVC;DO NOT USE +PVG;Proview Global Co., Ltd +PVI;Prime view international Co., Ltd +PVM;Penta Studiotechnik GmbH +PVN;Pixel Vision +PVP;Klos Technologies, Inc. +PXC;Phoenix Contact +PXE;PIXELA CORPORATION +PXL;The Moving Pixel Company +PXM;Proxim Inc +QCC;QuakeCom Company Ltd +QCH;Metronics Inc +QCI;Quanta Computer Inc +QCK;Quick Corporation +QCL;Quadrant Components Inc +QCP;Qualcomm Inc +QDI;Quantum Data Incorporated +QDM;Quadram +QDS;Quanta Display Inc. +QFF;Padix Co., Inc. +QFI;Quickflex, Inc +QLC;Q-Logic +QQQ;Chuomusen Co., Ltd. +QSI;Quantum Solutions, Inc. +QTD;Quantum 3D Inc +QTH;Questech Ltd +QTI;Quicknet Technologies Inc +QTM;Quantum +QTR;Qtronix Corporation +QUA;Quatographic AG +QUE;Questra Consulting +QVU;Quartics +RAC;Racore Computer Products Inc +RAD;Radisys Corporation +RAI;Rockwell Automation/Intecolor +RAN;Rancho Tech Inc +RAR;Raritan, Inc. +RAS;RAScom Inc +RAT;Rent-A-Tech +RAY;Raylar Design, Inc. +RCE;Parc d'Activite des Bellevues +RCH;Reach Technology Inc +RCI;RC International +RCN;Radio Consult SRL +RCO;Rockwell Collins +RDI;Rainbow Displays, Inc. +RDM;Tremon Enterprises Company Ltd +RDS;Radius Inc +REA;Real D +REC;ReCom +RED;Research Electronics Development Inc +REF;Reflectivity, Inc. +REL;Reliance Electric Ind Corporation +REM;SCI Systems Inc. +REN;Renesas Technology Corp. +RES;ResMed Pty Ltd +RGL;Robertson Geologging Ltd +RHM;Rohm Company Ltd +RIC;RICOH COMPANY, LTD. +RII;Racal Interlan Inc +RIO;Rios Systems Company Ltd +RIT;Ritech Inc +RIV;Rivulet Communications +RJA;Roland Corporation +RJS;Advanced Engineering +RKC;Reakin Technolohy Corporation +RLD;MEPCO +RLN;RadioLAN Inc +RMC;Raritan Computer, Inc +RMP;Research Machines +RMT;Roper Mobile +RNB;Rainbow Technologies +ROB;Robust Electronics GmbH +ROH;Rohm Co., Ltd. +ROK;Rockwell International +ROP;Roper International Ltd +RPI;RoomPro Technologies +RPT;R.P.T.Intergroups +RRI;Radicom Research Inc +RSC;PhotoTelesis +RSH;ADC-Centre +RSI;Rampage Systems Inc +RSN;Radiospire Networks, Inc. +RSQ;R Squared +RSS;Rockwell Semiconductor Systems +RSX;Rapid Tech Corporation +RTC;Relia Technologies +RTI;Rancho Tech Inc +RTK;DO NOT USE +RTL;Realtek Semiconductor Company Ltd +RTS;Raintree Systems +RUN;RUNCO International +RUP;Ups Manufactoring s.r.l. +RVC;RSI Systems Inc +RVI;Realvision Inc +RVL;Reveal Computer Prod +RWC;Red Wing Corporation +RXT;Tectona SoftSolutions (P) Ltd., +SAA;Sanritz Automation Co.,Ltd. +SAE;Saab Aerotech +SAG;Sedlbauer +SAI;Sage Inc +SAK;Saitek Ltd +SAM;Samsung Electric Company +SAN;Sanyo Electric Co.,Ltd. +SAS;Stores Automated Systems Inc +SAT;Shuttle Tech +SBC;Shanghai Bell Telephone Equip Mfg Co +SBD;Softbed - Consulting & Development Ltd +SBI;SMART Technologies Inc. +SBS;SBS-or Industrial Computers GmbH +SBT;Senseboard Technologies AB +SCC;SORD Computer Corporation +SCD;Sanyo Electric Company Ltd +SCE;Sun Corporation +SCH;Schlumberger Cards +SCI;System Craft +SCL;Sigmacom Co., Ltd. +SCM;SCM Microsystems Inc +SCN;Scanport, Inc. +SCO;SORCUS Computer GmbH +SCP;Scriptel Corporation +SCR;Systran Corporation +SCS;Nanomach Anstalt +SCT;Smart Card Technology +SDA;SAT (Societe Anonyme) +SDD;Intrada-SDD Ltd +SDE;Sherwood Digital Electronics Corporation +SDF;SODIFF E&T CO., Ltd. +SDH;Communications Specialies, Inc. +SDI;Samtron Displays Inc +SDK;SAIT-Devlonics +SDR;SDR Systems +SDS;SunRiver Data System +SDT;Siemens AG +SDX;SDX Business Systems Ltd +SEA;Seanix Technology Inc. +SEB;system elektronik GmbH +SEC;Seiko Epson Corporation +SEE;SeeColor Corporation +SEG;DO NOT USE +SEI;Seitz & Associates Inc +SEL;Way2Call Communications +SEM;Samsung Electronics Company Ltd +SEN;Sencore +SEO;SEOS Ltd +SEP;SEP Eletronica Ltda. +SER;Sony Ericsson Mobile Communications Inc. +SES;Session Control LLC +SET;SendTek Corporation +SFM;TORNADO Company +SFT;Mikroforum Ring 3 +SGC;Spectragraphics Corporation +SGD;Sigma Designs, Inc. +SGE;Kansai Electric Company Ltd +SGI;Scan Group Ltd +SGL;Super Gate Technology Company Ltd +SGM;SAGEM +SGO;Logos Design A/S +SGT;Stargate Technology +SGX;Silicon Graphics Inc +SGZ;Systec Computer GmbH +SHC;ShibaSoku Co., Ltd. +SHG;Soft & Hardware development Goldammer GmbH +SHI;Jiangsu Shinco Electronic Group Co., Ltd +SHP;Sharp Corporation +SHR;Digital Discovery +SHT;Shin Ho Tech +SIA;SIEMENS AG +SIB;Sanyo Electric Company Ltd +SIC;Sysmate Corporation +SID;Seiko Instruments Information Devices Inc +SIE;Siemens +SIG;Sigma Designs Inc +SII;Silicon Image, Inc. +SIL;Silicon Laboratories, Inc +SIM;S3 Inc +SIN;Singular Technology Co., Ltd. +SIR;Sirius Technologies Pty Ltd +SIS;Silicon Integrated Systems Corporation +SIT;Sitintel +SIU;Seiko Instruments USA Inc +SIX;Zuniq Data Corporation +SJE;Sejin Electron Inc +SKD;Schneider & Koch +SKT;Samsung Electro-Mechanics Company Ltd +SKY;SKYDATA S.P.A. +SLA;Systeme Lauer GmbH&Co KG +SLB;Shlumberger Ltd +SLC;Syslogic Datentechnik AG +SLF;StarLeaf +SLH;Silicon Library Inc. +SLI;Symbios Logic Inc +SLK;Silitek Corporation +SLM;Solomon Technology Corporation +SLR;Schlumberger Technology Corporate +SLS;Schnick-Schnack-Systems GmbH +SLT;Salt Internatioinal Corp. +SLX;Specialix +SMA;SMART Modular Technologies +SMB;Schlumberger +SMC;Standard Microsystems Corporation +SME;Sysmate Company +SMI;SpaceLabs Medical Inc +SMK;SMK CORPORATION +SML;Sumitomo Metal Industries, Ltd. +SMM;Shark Multimedia Inc +SMO;STMicroelectronics +SMP;Simple Computing +SMR;B.& V. s.r.l. +SMS;Silicom Multimedia Systems Inc +SMT;Silcom Manufacturing Tech Inc +SNC;Sentronic International Corp. +SNI;Siemens Microdesign GmbH +SNK;S&K Electronics +SNO;SINOSUN TECHNOLOGY CO., LTD +SNP;Siemens Nixdorf Info Systems +SNS;Cirtech (UK) Ltd +SNT;SuperNet Inc +SNW;Snell & Wilcox +SNX;Sonix Comm. Ltd +SNY;Sony +SOI;Silicon Optix Corporation +SOL;Solitron Technologies Inc +SON;Sony +SOR;Sorcus Computer GmbH +SOT;Sotec Company Ltd +SOY;SOYO Group, Inc +SPC;SpinCore Technologies, Inc +SPE;SPEA Software AG +SPH;G&W Instruments GmbH +SPI;SPACE-I Co., Ltd. +SPK;SpeakerCraft +SPL;Smart Silicon Systems Pty Ltd +SPN;Sapience Corporation +SPR;pmns GmbH +SPS;Synopsys Inc +SPT;Sceptre Tech Inc +SPU;SIM2 Multimedia S.P.A. +SPX;Simplex Time Recorder Co. +SQT;Sequent Computer Systems Inc +SRC;Integrated Tech Express Inc +SRD;Setred +SRF;Surf Communication Solutions Ltd +SRG;Intuitive Surgical, Inc. +SRT;SeeReal Technologies GmbH +SSC;Sierra Semiconductor Inc +SSD;FlightSafety International +SSE;Samsung Electronic Co. +SSI;S-S Technology Inc +SSJ;Sankyo Seiki Mfg.co., Ltd +SSP;Spectrum Signal Proecessing Inc +SSS;S3 Inc +SST;SystemSoft Corporation +STA;ST Electronics Systems Assembly Pte Ltd +STB;STB Systems Inc +STC;STAC Electronics +STD;STD Computer Inc +STE;SII Ido-Tsushin Inc +STF;Starflight Electronics +STG;StereoGraphics Corp. +STH;Semtech Corporation +STI;Smart Tech Inc +STK;SANTAK CORP. +STL;SigmaTel Inc +STM;SGS Thomson Microelectronics +STN;Samsung Electronics America +STO;Stollmann E+V GmbH +STP;StreamPlay Ltd +STR;Starlight Networks Inc +STS;SITECSYSTEM CO., LTD. +STT;Star Paging Telecom Tech (Shenzhen) Co. Ltd. +STW;Starwin Inc. +STY;SDS Technologies +SUB;Subspace Comm. Inc +SUM;Summagraphics Corporation +SUN;Sun Electronics Corporation +SUP;Supra Corporation +SUR;Surenam Computer Corporation +SVA;SGEG +SVC;Intellix Corp. +SVD;SVD Computer +SVI;Sun Microsystems +SVS;SVSI +SVT;SEVIT Co., Ltd. +SWC;Software Café +SWI;Sierra Wireless Inc. +SWL;Sharedware Ltd +SWS;Static +SWT;Software Technologies Group,Inc. +SXB;Syntax-Brillian +SXD;Silex technology, Inc. +SXL;SolutionInside +SXT;SHARP TAKAYA ELECTRONIC INDUSTRY CO.,LTD. +SYC;Sysmic +SYE;SY Electronics Ltd +SYK;Stryker Communications +SYL;Sylvania Computer Products +SYM;Symicron Computer Communications Ltd. +SYN;Synaptics Inc +SYP;SYPRO Co Ltd +SYS;Sysgration Ltd +SYT;Seyeon Tech Company Ltd +SYV;SYVAX Inc +SYX;Prime Systems, Inc. +TAA;Tandberg +TAB;Todos Data System AB +TAG;Teles AG +TAI;Toshiba America Info Systems Inc +TAM;Tamura Seisakusyo Ltd +TAS;Taskit Rechnertechnik GmbH +TAT;Teleliaison Inc +TAX;Taxan (Europe) Ltd +TBB;Triple S Engineering Inc +TBC;Turbo Communication, Inc +TBS;Turtle Beach System +TCC;Tandon Corporation +TCD;Taicom Data Systems Co., Ltd. +TCE;Century Corporation +TCH;Interaction Systems, Inc +TCI;Tulip Computers Int'l B.V. +TCJ;TEAC America Inc +TCL;Technical Concepts Ltd +TCM;3Com Corporation +TCN;Tecnetics (PTY) Ltd +TCO;Thomas-Conrad Corporation +TCR;Thomson Consumer Electronics +TCS;Tatung Company of America Inc +TCT;Telecom Technology Centre Co. Ltd. +TCX;FREEMARS Heavy Industries +TDC;Teradici +TDD;Tandberg Data Display AS +TDK;TDK USA Corporation +TDM;Tandem Computer Europe Inc +TDP;3D Perception +TDS;Tri-Data Systems Inc +TDT;TDT +TDV;TDVision Systems, Inc. +TDY;Tandy Electronics +TEA;TEAC System Corporation +TEC;Tecmar Inc +TEK;Tektronix Inc +TEL;Promotion and Display Technology Ltd. +TER;TerraTec Electronic GmbH +TGI;TriGem Computer Inc +TGM;TriGem Computer,Inc. +TGS;Torus Systems Ltd +TGV;Grass Valley Germany GmbH +THN;Thundercom Holdings Sdn. Bhd. +TIC;Trigem KinfoComm +TIP;TIPTEL AG +TIV;OOO Technoinvest +TIX;Tixi.Com GmbH +TKC;Taiko Electric Works.LTD +TKN;Teknor Microsystem Inc +TKO;TouchKo, Inc. +TKS;TimeKeeping Systems, Inc. +TLA;Ferrari Electronic GmbH +TLD;Telindus +TLI;TOSHIBA TELI CORPORATION +TLK;Telelink AG +TLS;Teleste Educational OY +TLT;Dai Telecom S.p.A. +TLV;S3 Inc +TLX;Telxon Corporation +TMC;Techmedia Computer Systems Corporation +TME;AT&T Microelectronics +TMI;Texas Microsystem +TMM;Time Management, Inc. +TMR;Taicom International Inc +TMS;Trident Microsystems Ltd +TMT;T-Metrics Inc. +TMX;Thermotrex Corporation +TNC;TNC Industrial Company Ltd +TNJ;DO NOT USE +TNM;TECNIMAGEN SA +TNY;Tennyson Tech Pty Ltd +TOE;TOEI Electronics Co., Ltd. +TOG;The OPEN Group +TOP;Orion Communications Co., Ltd. +TOS;Toshiba Corporation +TOU;Touchstone Technology +TPC;Touch Panel Systems Corporation +TPE;Technology Power Enterprises Inc +TPJ;(none) +TPK;TOPRE CORPORATION +TPR;Topro Technology Inc +TPS;Teleprocessing Systeme GmbH +TPT;Thruput Ltd +TPV;Top Victory Electronics ( Fujian ) Company Ltd +TPZ;Ypoaz Systems Inc +TRA;TriTech Microelectronics International +TRC;Trioc AB +TRD;Trident Microsystem Inc +TRE;Tremetrics +TRI;Tricord Systems +TRL;Royal Information +TRM;Tekram Technology Company Ltd +TRN;Datacommunicatie Tron B.V. +TRS;Torus Systems Ltd +TRU;Aashima Technology B.V. +TRX;Trex Enterprises +TSB;Toshiba America Info Systems Inc +TSC;Sanyo Electric Company Ltd +TSD;TechniSat Digital GmbH +TSE;Tottori Sanyo Electric +TSF;Racal-Airtech Software Forge Ltd +TSG;The Software Group Ltd +TSI;TeleVideo Systems +TSL;Tottori SANYO Electric Co., Ltd. +TSP;U.S. Navy +TST;Transtream Inc +TSV;TRANSVIDEO +TSY;TouchSystems +TTA;Topson Technology Co., Ltd. +TTB;National Semiconductor Japan Ltd +TTC;Telecommunications Techniques Corporation +TTE;TTE, Inc. +TTI;Trenton Terminals Inc +TTK;Totoku Electric Company Ltd +TTL;2-Tel B.V. +TTS;TechnoTrend Systemtechnik GmbH +TTY;TRIDELITY Display Solutions GmbH +TUT;Tut Systems +TVD;Tecnovision +TVI;Truevision +TVM;Taiwan Video & Monitor Corporation +TVO;TV One Ltd +TVR;TV Interactive Corporation +TVS;TVS Electronics Limited +TWA;Tidewater Association +TWE;Kontron Electronik +TWH;Twinhead International Corporation +TWI;Easytel oy +TWK;TOWITOKO electronics GmbH +TWX;TEKWorx Limited +TXL;Trixel Ltd +TXN;Texas Insturments +TXT;Textron Defense System +TYN;Tyan Computer Corporation +UAS;Ultima Associates Pte Ltd +UBI;Ungermann-Bass Inc +UBL;Ubinetics Ltd. +UDN;Uniden Corporation +UEC;Ultima Electronics Corporation +UEG;Elitegroup Computer Systems Company Ltd +UEI;Universal Electronics Inc +UET;Universal Empowering Technologies +UFG;UNIGRAF-USA +UFO;UFO Systems Inc +UHB;XOCECO +UIC;Uniform Industrial Corporation +UJR;Ueda Japan Radio Co., Ltd. +ULT;Ultra Network Tech +UMC;United Microelectr Corporation +UMG;Umezawa Giken Co.,Ltd +UMM;Universal Multimedia +UNA;Unisys DSD +UNB;Unisys Corporation +UNC;Unisys Corporation +UND;DO NOT USE - UND +UNE;DO NOT USE - UNE +UNF;DO NOT USE - UNF +UNI;Unisys Corporation +UNI;Uniform Industry Corp. +UNM;Unisys Corporation +UNO;Unisys Corporation +UNP;Unitop +UNS;Unisys Corporation +UNT;Unisys Corporation +UNY;Unicate +UPP;UPPI +UPS;Systems Enhancement +URD;Video Computer S.p.A. +USA;Utimaco Safeware AG +USD;U.S. Digital Corporation +USI;Universal Scientific Industrial Co., Ltd. +USR;U.S. Robotics Inc +UTD;Up to Date Tech +UWC;Uniwill Computer Corp. +VAL;Valence Computing Corporation +VAR;Varian Australia Pty Ltd +VBT;Valley Board Ltda +VCC;Virtual Computer Corporation +VCI;VistaCom Inc +VCJ;Victor Company of Japan, Limited +VCM;Vector Magnetics, LLC +VCX;VCONEX +VDA;Victor Data Systems +VDC;VDC Display Systems +VDM;Vadem +VDO;Video & Display Oriented Corporation +VDS;Vidisys GmbH & Company +VDT;Viditec, Inc. +VEC;Vector Informatik GmbH +VEK;Vektrex +VES;Vestel Elektronik Sanayi ve Ticaret A. S. +VFI;VeriFone Inc +VHI;Macrocad Development Inc. +VIA;VIA Tech Inc +VIB;Tatung UK Ltd +VIC;Victron B.V. +VID;Ingram Macrotron Germany +VIK;Viking Connectors +VIN;Vine Micros Ltd +VIR;Visual Interface, Inc +VIS;Visioneer +VIT;Visitech AS +VLB;ValleyBoard Ltda. +VLT;VideoLan Technologies +VMI;Vermont Microsystems +VML;Vine Micros Limited +VNC;Vinca Corporation +VOB;MaxData Computer AG +VPI;Video Products Inc +VPR;Best Buy +VQ@;Vision Quest +VRC;Virtual Resources Corporation +VSC;ViewSonic Corporation +VSD;3M +VSI;VideoServer +VSN;Ingram Macrotron +VSP;Vision Systems GmbH +VSR;V-Star Electronics Inc. +VTC;VTel Corporation +VTG;Voice Technologies Group Inc +VTI;VLSI Tech Inc +VTK;Viewteck Co., Ltd. +VTL;Vivid Technology Pte Ltd +VTM;Miltope Corporation +VTN;VIDEOTRON CORP. +VTS;VTech Computers Ltd +VTV;VATIV Technologies +VUT;Vutrix (UK) Ltd +VWB;Vweb Corp. +WAC;Wacom Tech +WAL;Wave Access +WAN;DO NOT USE +WAV;Wavephore +WBN;MicroSoftWare +WBS;WB Systemtechnik GmbH +WCI;Wisecom Inc +WCS;Woodwind Communications Systems Inc +WDC;Western Digital +WDE;Westinghouse Digital Electronics +WEB;WebGear Inc +WEC;Winbond Electronics Corporation +WEL ; W-DEV +WEY;WEY Design AG +WHI;Whistle Communications +WII;Innoware Inc +WIL;WIPRO Information Technology Ltd +WIN;Wintop Technology Inc +WIP;Wipro Infotech +WKH;Uni-Take Int'l Inc. +WLD;Wildfire Communications Inc +WML;Wolfson Microelectronics Ltd +WMO;Westermo Teleindustri AB +WMT;Winmate Communication Inc +WNI;WillNet Inc. +WNV;Winnov L.P. +WNX;Wincor Nixdorf International GmbH +WPA;Matsushita Communication Industrial Co., Ltd. +WPI;Wearnes Peripherals International (Pte) Ltd +WRC;WiNRADiO Communications +WSC;CIS Technology Inc +WSP;Wireless And Smart Products Inc. +WST;Wistron Corporation +WTC;ACC Microelectronics +WTI;WorkStation Tech +WTK;Wearnes Thakral Pte +WTS;Restek Electric Company Ltd +WVM;Wave Systems Corporation +WWV;World Wide Video, Inc. +WXT;Woxter Technology Co. Ltd +WYS;Myse Technology +WYT;Wooyoung Image & Information Co.,Ltd. +XAC;XAC Automation Corp +XAD;Alpha Data +XDM;XDM Ltd. +XER;DO NOT USE +XFG;Jan Strapko - FOTO +XFO;EXFO Electro Optical Engineering +XIN;Xinex Networks Inc +XIO;Xiotech Corporation +XIR;Xirocm Inc +XIT;Xitel Pty ltd +XLX;Xilinx, Inc. +XMM;C3PO S.L. +XNT;XN Technologies, Inc. +XOC;DO NOT USE +XQU;SHANGHAI SVA-DAV ELECTRONICS CO., LTD +XRC;Xircom Inc +XRO;XORO ELECTRONICS (CHENGDU) LIMITED +XSN;Xscreen AS +XST;XS Technologies Inc +XSY;XSYS +XTD;Icuiti Corporation +XTE;X2E GmbH +XTL;Crystal Computer +XTN;X-10 (USA) Inc +XYC;Xycotec Computer GmbH +YED;Y-E Data Inc +YHQ;Yokogawa Electric Corporation +YHW;Exacom SA +YMH;Yamaha Corporation +YOW;American Biometric Company +ZAN;Zandar Technologies plc +ZAX;Zefiro Acoustics +ZAZ;Zazzle Technologies +ZBR;Zebra Technologies International, LLC +ZCT;ZeitControl cardsystems GmbH +ZDS;Zenith Data Systems +ZGT;Zenith Data Systems +ZIC;ZTEIC DESIGN CO., LTD. +ZMT;Zalman Tech Co., Ltd. +ZMZ;Z Microsystems +ZNI;Zetinet Inc +ZNX;Znyx Adv. Systems +ZOW;Zowie Intertainment, Inc +ZRN;Zoran Corporation +ZSE;Zenith Data Systems +ZTC;ZyDAS Technology Corporation +ZTE;ZTE Corporation +ZTI;Zoom Telephonics Inc +ZTM;ZT Group Int'l Inc. +ZYD;Zydacron Inc +ZYP;Zypcom Inc +ZYT;Zytex Computers +ZYX;Zyxel +ZZZ;Boca Research Inc diff --git a/libsigrokdecode4DSL/decoders/eeprom24xx/__init__.py b/libsigrokdecode4DSL/decoders/eeprom24xx/__init__.py new file mode 100644 index 00000000..7d496fce --- /dev/null +++ b/libsigrokdecode4DSL/decoders/eeprom24xx/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Uwe Hermann +## +## 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, see . +## + +''' +This decoder stacks on top of the 'i2c' PD and decodes the +industry standard 24xx series serial EEPROM protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/eeprom24xx/lists.py b/libsigrokdecode4DSL/decoders/eeprom24xx/lists.py new file mode 100644 index 00000000..c6ee63d5 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/eeprom24xx/lists.py @@ -0,0 +1,204 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Uwe Hermann +## +## 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, see . +## + +# +# Chip specific properties: +# +# - vendor: chip manufacturer +# - model: chip model +# - size: total EEPROM size (in number of bytes) +# - page_size: page size (in number of bytes) +# - page_wraparound: Whether writes wrap-around at page boundaries +# - addr_bytes: number of EEPROM address bytes used +# - addr_pins: number of address pins (A0/A1/A2) on this chip +# - max_speed: max. supported I²C speed (in kHz) +# +chips = { + # Generic chip (128 bytes, 8 bytes page size) + 'generic': { + 'vendor': '', + 'model': 'Generic', + 'size': 128, + 'page_size': 8, + 'page_wraparound': True, + 'addr_bytes': 1, + 'addr_pins': 3, + 'max_speed': 400, + }, + + # Microchip + 'microchip_24aa65': { + 'vendor': 'Microchip', + 'model': '24AA65', + 'size': 8 * 1024, + 'page_size': 64, # Actually 8, but there are 8 pages of "input cache" + 'page_wraparound': True, + 'addr_bytes': 2, + 'addr_pins': 3, + 'max_speed': 400, + }, + 'microchip_24lc65': { + 'vendor': 'Microchip', + 'model': '24LC65', + 'size': 8 * 1024, + 'page_size': 64, # Actually 8, but there are 8 pages of "input cache" + 'page_wraparound': True, + 'addr_bytes': 2, + 'addr_pins': 3, + 'max_speed': 400, + }, + 'microchip_24c65': { + 'vendor': 'Microchip', + 'model': '24C65', + 'size': 8 * 1024, + 'page_size': 64, # Actually 8, but there are 8 pages of "input cache" + 'page_wraparound': True, + 'addr_bytes': 2, + 'addr_pins': 3, + 'max_speed': 400, + }, + 'microchip_24aa64': { + 'vendor': 'Microchip', + 'model': '24AA64', + 'size': 8 * 1024, + 'page_size': 32, + 'page_wraparound': True, + 'addr_bytes': 2, + 'addr_pins': 3, + 'max_speed': 400, # 100 for VCC < 2.5V + }, + 'microchip_24lc64': { + 'vendor': 'Microchip', + 'model': '24LC64', + 'size': 8 * 1024, + 'page_size': 32, + 'page_wraparound': True, + 'addr_bytes': 2, + 'addr_pins': 3, + 'max_speed': 400, + }, + 'microchip_24aa02uid': { + 'vendor': 'Microchip', + 'model': '24AA02UID', + 'size': 256, + 'page_size': 8, + 'page_wraparound': True, + 'addr_bytes': 1, + 'addr_pins': 0, # Pins A0, A1, A2 not used + 'max_speed': 400, + }, + 'microchip_24aa025uid': { + 'vendor': 'Microchip', + 'model': '24AA025UID', + 'size': 256, + 'page_size': 16, + 'page_wraparound': True, + 'addr_bytes': 1, + 'addr_pins': 3, + 'max_speed': 400, + }, + 'microchip_24aa025uid_sot23': { + 'vendor': 'Microchip', + 'model': '24AA025UID (SOT-23)', + 'size': 256, + 'page_size': 16, + 'page_wraparound': True, + 'addr_bytes': 1, + 'addr_pins': 2, # SOT-23 package: A2 not available + 'max_speed': 400, + }, + + # ON Semiconductor + 'onsemi_cat24c256': { + 'vendor': 'ON Semiconductor', + 'model': 'CAT24C256', + 'size': 32 * 1024, + 'page_size': 64, + 'page_wraparound': True, + 'addr_bytes': 2, + 'addr_pins': 3, + 'max_speed': 1000, + }, + 'onsemi_cat24m01': { + 'vendor': 'ON Semiconductor', + 'model': 'CAT24M01', + 'size': 128 * 1024, + 'page_size': 256, + 'page_wraparound': True, + 'addr_bytes': 2, + 'addr_pins': 2, # Pin A0 not connected + 'max_speed': 1000, + }, + + # Siemens + 'siemens_slx_24c01': { + 'vendor': 'Siemens', + 'model': 'SLx 24C01', + 'size': 128, + 'page_size': 8, + 'page_wraparound': True, + 'addr_bytes': 1, + 'addr_pins': 0, # Pins A0, A1, A2 are not connected (NC) + 'max_speed': 400, + }, + 'siemens_slx_24c02': { + 'vendor': 'Siemens', + 'model': 'SLx 24C02', + 'size': 256, + 'page_size': 8, + 'page_wraparound': True, + 'addr_bytes': 1, + 'addr_pins': 0, # Pins A0, A1, A2 are not connected (NC) + 'max_speed': 400, + }, + + # ST + 'st_m24c01': { + 'vendor': 'ST', + 'model': 'M24C01', + 'size': 128, + 'page_size': 16, + 'page_wraparound': True, + 'addr_bytes': 1, + 'addr_pins': 3, # Called E0, E1, E2 on this chip. + 'max_speed': 400, + }, + 'st_m24c02': { + 'vendor': 'ST', + 'model': 'M24C02', + 'size': 256, + 'page_size': 16, + 'page_wraparound': True, + 'addr_bytes': 1, + 'addr_pins': 3, # Called E0, E1, E2 on this chip. + 'max_speed': 400, + }, + + # Xicor + 'xicor_x24c02': { + 'vendor': 'Xicor', + 'model': 'X24C02', + 'size': 256, + 'page_size': 4, + 'page_wraparound': True, + 'addr_bytes': 1, + 'addr_pins': 3, + 'max_speed': 100, + }, +} diff --git a/libsigrokdecode4DSL/decoders/eeprom24xx/pd.py b/libsigrokdecode4DSL/decoders/eeprom24xx/pd.py new file mode 100644 index 00000000..033a44b2 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/eeprom24xx/pd.py @@ -0,0 +1,433 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Uwe Hermann +## +## 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, see . +## + +import sigrokdecode as srd +from .lists import * + +class Decoder(srd.Decoder): + api_version = 3 + id = 'eeprom24xx' + name = '24xx EEPROM' + longname = '24xx I²C EEPROM' + desc = '24xx series I²C EEPROM protocol.' + license = 'gplv2+' + inputs = ['i2c'] + outputs = [] + tags = ['IC', 'Memory'] + options = ( + {'id': 'chip', 'desc': 'Chip', 'default': 'generic', + 'values': tuple(chips.keys())}, + {'id': 'addr_counter', 'desc': 'Initial address counter value', + 'default': 0}, + ) + annotations = ( + # Warnings + ('warnings', 'Warnings'), + # Bits/bytes + ('control-code', 'Control code'), + ('address-pin', 'Address pin (A0/A1/A2)'), + ('rw-bit', 'Read/write bit'), + ('word-addr-byte', 'Word address byte'), + ('data-byte', 'Data byte'), + # Fields + ('control-word', 'Control word'), + ('word-addr', 'Word address'), + ('data', 'Data'), + # Operations + ('byte-write', 'Byte write'), + ('page-write', 'Page write'), + ('cur-addr-read', 'Current address read'), + ('random-read', 'Random read'), + ('seq-random-read', 'Sequential random read'), + ('seq-cur-addr-read', 'Sequential current address read'), + ('ack-polling', 'Acknowledge polling'), + ('set-bank-addr', 'Set bank address'), # SBA. Only 34AA04. + ('read-bank-addr', 'Read bank address'), # RBA. Only 34AA04. + ('set-wp', 'Set write protection'), # SWP + ('clear-all-wp', 'Clear all write protection'), # CWP + ('read-wp', 'Read write protection status'), # RPS + ) + annotation_rows = ( + ('bits-bytes', 'Bits/bytes', (1, 2, 3, 4, 5)), + ('fields', 'Fields', (6, 7, 8)), + ('ops', 'Operations', tuple(range(9, 21))), + ('warnings', 'Warnings', (0,)), + ) + binary = ( + ('binary', 'Binary'), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.reset_variables() + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_binary = self.register(srd.OUTPUT_BINARY) + self.chip = chips[self.options['chip']] + self.addr_counter = self.options['addr_counter'] + + def putb(self, data): + self.put(self.ss_block, self.es_block, self.out_ann, data) + + def putbin(self, data): + self.put(self.ss_block, self.es_block, self.out_binary, data) + + def putbits(self, bit1, bit2, bits, data): + self.put(bits[bit1][1], bits[bit2][2], self.out_ann, data) + + def reset_variables(self): + self.state = 'WAIT FOR START' + self.packets = [] + self.bytebuf = [] + self.is_cur_addr_read = False + self.is_random_access_read = False + self.is_seq_random_read = False + self.is_byte_write = False + self.is_page_write = False + + def packet_append(self): + self.packets.append([self.ss, self.es, self.cmd, self.databyte, self.bits]) + if self.cmd in ('DATA READ', 'DATA WRITE'): + self.bytebuf.append(self.databyte) + + def hexbytes(self, idx): + return ' '.join(['%02X' % b for b in self.bytebuf[idx:]]) + + def put_control_word(self, bits): + s = ''.join(['%d' % b[0] for b in reversed(bits[4:])]) + self.putbits(7, 4, bits, [1, ['Control code bits: ' + s, + 'Control code: ' + s, 'Ctrl code: ' + s, 'Ctrl code', 'Ctrl', 'C']]) + for i in reversed(range(self.chip['addr_pins'])): + self.putbits(i + 1, i + 1, bits, + [2, ['Address bit %d: %d' % (i, bits[i + 1][0]), + 'Addr bit %d' % i, 'A%d' % i, 'A']]) + s1 = 'read' if bits[0][0] == 1 else 'write' + s2 = 'R' if bits[0][0] == 1 else 'W' + self.putbits(0, 0, bits, [3, ['R/W bit: ' + s1, 'R/W', 'RW', s2]]) + self.putbits(7, 0, bits, [6, ['Control word', 'Control', 'CW', 'C']]) + + def put_word_addr(self, p): + if self.chip['addr_bytes'] == 1: + a = p[1][3] + self.put(p[1][0], p[1][1], self.out_ann, + [4, ['Word address byte: %02X' % a, 'Word addr byte: %02X' % a, + 'Addr: %02X' % a, 'A: %02X' % a, '%02X' % a]]) + self.put(p[1][0], p[1][1], self.out_ann, [7, ['Word address', + 'Word addr', 'Addr', 'A']]) + self.addr_counter = a + else: + a = p[1][3] + self.put(p[1][0], p[1][1], self.out_ann, + [4, ['Word address high byte: %02X' % a, + 'Word addr high byte: %02X' % a, + 'Addr high: %02X' % a, 'AH: %02X' % a, '%02X' % a]]) + a = p[2][3] + self.put(p[2][0], p[2][1], self.out_ann, + [4, ['Word address low byte: %02X' % a, + 'Word addr low byte: %02X' % a, + 'Addr low: %02X' % a, 'AL: %02X' % a, '%02X' % a]]) + self.put(p[1][0], p[2][1], self.out_ann, [7, ['Word address', + 'Word addr', 'Addr', 'A']]) + self.addr_counter = (p[1][3] << 8) | p[2][3] + + def put_data_byte(self, p): + if self.chip['addr_bytes'] == 1: + s = '%02X' % self.addr_counter + else: + s = '%04X' % self.addr_counter + self.put(p[0], p[1], self.out_ann, [5, ['Data byte %s: %02X' % \ + (s, p[3]), 'Data byte: %02X' % p[3], \ + 'Byte: %02X' % p[3], 'DB: %02X' % p[3], '%02X' % p[3]]]) + + def put_data_bytes(self, idx, cls, s): + for p in self.packets[idx:]: + self.put_data_byte(p) + self.addr_counter += 1 + self.put(self.packets[idx][0], self.packets[-1][1], self.out_ann, + [8, ['Data', 'D']]) + a = ''.join(['%s' % c[0] for c in s.split()]).upper() + self.putb([cls, ['%s (%s): %s' % (s, self.addr_and_len(), \ + self.hexbytes(self.chip['addr_bytes'])), + '%s (%s)' % (s, self.addr_and_len()), s, a, s[0]]]) + self.putbin([0, bytes(self.bytebuf[self.chip['addr_bytes']:])]) + + def addr_and_len(self): + if self.chip['addr_bytes'] == 1: + a = '%02X' % self.bytebuf[0] + else: + a = '%02X%02X' % tuple(self.bytebuf[:2]) + num_data_bytes = len(self.bytebuf) - self.chip['addr_bytes'] + d = '%d bytes' % num_data_bytes + if num_data_bytes <= 1: + d = d[:-1] + return 'addr=%s, %s' % (a, d) + + def decide_on_seq_or_rnd_read(self): + if len(self.bytebuf) < 2: + self.reset_variables() + return + if len(self.bytebuf) == 2: + self.is_random_access_read = True + else: + self.is_seq_random_read = True + + def put_operation(self): + idx = 1 + self.chip['addr_bytes'] + if self.is_byte_write: + # Byte write: word address, one data byte. + self.put_word_addr(self.packets) + self.put_data_bytes(idx, 9, 'Byte write') + elif self.is_page_write: + # Page write: word address, two or more data bytes. + self.put_word_addr(self.packets) + intitial_addr = self.addr_counter + self.put_data_bytes(idx, 10, 'Page write') + num_bytes_to_write = len(self.packets[idx:]) + if num_bytes_to_write > self.chip['page_size']: + self.putb([0, ['Warning: Wrote %d bytes but page size is ' + 'only %d bytes!' % (num_bytes_to_write, + self.chip['page_size'])]]) + page1 = int(intitial_addr / self.chip['page_size']) + page2 = int((self.addr_counter - 1) / self.chip['page_size']) + if page1 != page2: + self.putb([0, ['Warning: Page write crossed page boundary ' + 'from page %d to %d!' % (page1, page2)]]) + elif self.is_cur_addr_read: + # Current address read: no word address, one data byte. + self.put_data_byte(self.packets[1]) + self.put(self.packets[1][0], self.packets[-1][1], self.out_ann, + [8, ['Data', 'D']]) + self.putb([11, ['Current address read: %02X' % self.bytebuf[0], + 'Current address read', 'Cur addr read', 'CAR', 'C']]) + self.putbin([0, bytes([self.bytebuf[0]])]) + self.addr_counter += 1 + elif self.is_random_access_read: + # Random access read: word address, one data byte. + self.put_control_word(self.packets[idx][4]) + self.put_word_addr(self.packets) + self.put_data_bytes(idx + 1, 12, 'Random access read') + elif self.is_seq_random_read: + # Sequential random read: word address, two or more data bytes. + self.put_control_word(self.packets[idx][4]) + self.put_word_addr(self.packets) + self.put_data_bytes(idx + 1, 13, 'Sequential random read') + + def handle_wait_for_start(self): + # Wait for an I²C START condition. + if self.cmd not in ('START', 'START REPEAT'): + return + self.ss_block = self.ss + self.state = 'GET CONTROL WORD' + + def handle_get_control_word(self): + # The packet after START must be an ADDRESS READ or ADDRESS WRITE. + if self.cmd not in ('ADDRESS READ', 'ADDRESS WRITE'): + self.reset_variables() + return + self.packet_append() + self.put_control_word(self.bits) + self.state = '%s GET ACK NACK AFTER CONTROL WORD' % self.cmd[8] + + def handle_r_get_ack_nack_after_control_word(self): + if self.cmd == 'ACK': + self.state = 'R GET WORD ADDR OR BYTE' + elif self.cmd == 'NACK': + self.es_block = self.es + self.putb([0, ['Warning: No reply from slave!']]) + self.reset_variables() + else: + self.reset_variables() + + def handle_r_get_word_addr_or_byte(self): + if self.cmd == 'STOP': + self.es_block = self.es + self.putb([0, ['Warning: Slave replied, but master aborted!']]) + self.reset_variables() + return + elif self.cmd != 'DATA READ': + self.reset_variables() + return + self.packet_append() + self.state = 'R GET ACK NACK AFTER WORD ADDR OR BYTE' + + def handle_r_get_ack_nack_after_word_addr_or_byte(self): + if self.cmd == 'ACK': + self.state = 'R GET RESTART' + elif self.cmd == 'NACK': + self.is_cur_addr_read = True + self.state = 'GET STOP AFTER LAST BYTE' + else: + self.reset_variables() + + def handle_r_get_restart(self): + if self.cmd == 'RESTART': + self.state = 'R READ BYTE' + else: + self.reset_variables() + + def handle_r_read_byte(self): + if self.cmd == 'DATA READ': + self.packet_append() + self.state = 'R GET ACK NACK AFTER BYTE WAS READ' + else: + self.reset_variables() + + def handle_r_get_ack_nack_after_byte_was_read(self): + if self.cmd == 'ACK': + self.state = 'R READ BYTE' + elif self.cmd == 'NACK': + # It's either a RANDOM READ or a SEQUENTIAL READ. + self.state = 'GET STOP AFTER LAST BYTE' + else: + self.reset_variables() + + def handle_w_get_ack_nack_after_control_word(self): + if self.cmd == 'ACK': + self.state = 'W GET WORD ADDR' + elif self.cmd == 'NACK': + self.es_block = self.es + self.putb([0, ['Warning: No reply from slave!']]) + self.reset_variables() + else: + self.reset_variables() + + def handle_w_get_word_addr(self): + if self.cmd == 'STOP': + self.es_block = self.es + self.putb([0, ['Warning: Slave replied, but master aborted!']]) + self.reset_variables() + return + elif self.cmd != 'DATA WRITE': + self.reset_variables() + return + self.packet_append() + self.state = 'W GET ACK AFTER WORD ADDR' + + def handle_w_get_ack_after_word_addr(self): + if self.cmd == 'ACK': + self.state = 'W DETERMINE EEPROM READ OR WRITE' + else: + self.reset_variables() + + def handle_w_determine_eeprom_read_or_write(self): + if self.cmd == 'START REPEAT': + # It's either a RANDOM ACCESS READ or SEQUENTIAL RANDOM READ. + self.state = 'R2 GET CONTROL WORD' + elif self.cmd == 'DATA WRITE': + self.packet_append() + self.state = 'W GET ACK NACK AFTER BYTE WAS WRITTEN' + else: + self.reset_variables() + + def handle_w_write_byte(self): + if self.cmd == 'DATA WRITE': + self.packet_append() + self.state = 'W GET ACK NACK AFTER BYTE WAS WRITTEN' + elif self.cmd == 'STOP': + if len(self.bytebuf) < 2: + self.reset_variables() + return + self.es_block = self.es + if len(self.bytebuf) == 2: + self.is_byte_write = True + else: + self.is_page_write = True + self.put_operation() + self.reset_variables() + elif self.cmd == 'START REPEAT': + # It's either a RANDOM ACCESS READ or SEQUENTIAL RANDOM READ. + self.state = 'R2 GET CONTROL WORD' + else: + self.reset_variables() + + def handle_w_get_ack_nack_after_byte_was_written(self): + if self.cmd == 'ACK': + self.state = 'W WRITE BYTE' + else: + self.reset_variables() + + def handle_r2_get_control_word(self): + if self.cmd == 'ADDRESS READ': + self.packet_append() + self.state = 'R2 GET ACK AFTER ADDR READ' + else: + self.reset_variables() + + def handle_r2_get_ack_after_addr_read(self): + if self.cmd == 'ACK': + self.state = 'R2 READ BYTE' + else: + self.reset_variables() + + def handle_r2_read_byte(self): + if self.cmd == 'DATA READ': + self.packet_append() + self.state = 'R2 GET ACK NACK AFTER BYTE WAS READ' + elif self.cmd == 'STOP': + self.decide_on_seq_or_rnd_read() + self.es_block = self.es + self.putb([0, ['Warning: STOP expected after a NACK (not ACK)']]) + self.put_operation() + self.reset_variables() + else: + self.reset_variables() + + def handle_r2_get_ack_nack_after_byte_was_read(self): + if self.cmd == 'ACK': + self.state = 'R2 READ BYTE' + elif self.cmd == 'NACK': + self.decide_on_seq_or_rnd_read() + self.state = 'GET STOP AFTER LAST BYTE' + else: + self.reset_variables() + + def handle_get_stop_after_last_byte(self): + if self.cmd == 'STOP': + self.es_block = self.es + self.put_operation() + self.reset_variables() + elif self.cmd == 'START REPEAT': + self.es_block = self.es + self.putb([0, ['Warning: STOP expected (not RESTART)']]) + self.put_operation() + self.reset_variables() + self.ss_block = self.ss + self.state = 'GET CONTROL WORD' + else: + self.reset_variables() + + def decode(self, ss, es, data): + self.cmd, self.databyte = data + + # Collect the 'BITS' packet, then return. The next packet is + # guaranteed to belong to these bits we just stored. + if self.cmd == 'BITS': + self.bits = self.databyte + return + + # Store the start/end samples of this I²C packet. + self.ss, self.es = ss, es + + # State machine. + s = 'handle_%s' % self.state.lower().replace(' ', '_') + handle_state = getattr(self, s) + handle_state() diff --git a/libsigrokdecode4DSL/decoders/eeprom93xx/__init__.py b/libsigrokdecode4DSL/decoders/eeprom93xx/__init__.py new file mode 100644 index 00000000..c8eaf7a0 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/eeprom93xx/__init__.py @@ -0,0 +1,32 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2017 Kevin Redon +## +## 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, see . +## + +''' +This decoder stacks on top of the 'microwire' PD and decodes the 93xx EEPROM +specific instructions. + +The implemented instructions come from the STMicroelectronics M93Cx6 EEPROM +datasheet. They are compatible with the Atmel AT93Cxx EEPROM with slightly +different names. + +Warning: Other EEPROMs using Microwire might have different operation codes +and instructions. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/eeprom93xx/pd.py b/libsigrokdecode4DSL/decoders/eeprom93xx/pd.py new file mode 100644 index 00000000..7b64e59a --- /dev/null +++ b/libsigrokdecode4DSL/decoders/eeprom93xx/pd.py @@ -0,0 +1,141 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2017 Kevin Redon +## +## 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, see . +## + +import sigrokdecode as srd + +class Decoder(srd.Decoder): + api_version = 3 + id = 'eeprom93xx' + name = '93xx EEPROM' + longname = '93xx Microwire EEPROM' + desc = '93xx series Microwire EEPROM protocol.' + license = 'gplv2+' + inputs = ['microwire'] + outputs = [] + tags = ['IC', 'Memory'] + options = ( + {'id': 'addresssize', 'desc': 'Address size', 'default': 8}, + {'id': 'wordsize', 'desc': 'Word size', 'default': 16}, + ) + annotations = ( + ('si-data', 'SI data'), + ('so-data', 'SO data'), + ('warning', 'Warning'), + ) + annotation_rows = ( + ('data', 'Data', (0, 1)), + ('warnings', 'Warnings', (2,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.frame = [] + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.addresssize = self.options['addresssize'] + self.wordsize = self.options['wordsize'] + + def put_address(self, data): + # Get address (MSb first). + a = 0 + for b in range(len(data)): + a += (data[b].si << (len(data) - b - 1)) + self.put(data[0].ss, data[-1].es, self.out_ann, + [0, ['Address: 0x%x' % a, 'Addr: 0x%x' % a, '0x%x' % a]]) + + def put_word(self, si, data): + # Decode word (MSb first). + word = 0 + for b in range(len(data)): + d = data[b].si if si else data[b].so + word += (d << (len(data) - b - 1)) + idx = 0 if si else 1 + self.put(data[0].ss, data[-1].es, + self.out_ann, [idx, ['Data: 0x%x' % word, '0x%x' % word]]) + + def decode(self, ss, es, data): + if len(data) < (2 + self.addresssize): + self.put(ss, es, self.out_ann, [2, ['Not enough packet bits']]) + return + + opcode = (data[0].si << 1) + (data[1].si << 0) + + if opcode == 2: + # READ instruction. + self.put(data[0].ss, data[1].es, + self.out_ann, [0, ['Read word', 'READ']]) + self.put_address(data[2:2 + self.addresssize]) + + # Get all words. + word_start = 2 + self.addresssize + while len(data) - word_start > 0: + # Check if there are enough bits for a word. + if len(data) - word_start < self.wordsize: + self.put(data[word_start].ss, data[len(data) - 1].es, + self.out_ann, [2, ['Not enough word bits']]) + break + self.put_word(False, data[word_start:word_start + self.wordsize]) + # Go to next word. + word_start += self.wordsize + elif opcode == 1: + # WRITE instruction. + self.put(data[0].ss, data[1].es, + self.out_ann, [0, ['Write word', 'WRITE']]) + self.put_address(data[2:2 + self.addresssize]) + # Get word. + if len(data) < 2 + self.addresssize + self.wordsize: + self.put(data[2 + self.addresssize].ss, + data[len(data) - 1].ss, + self.out_ann, [2, ['Not enough word bits']]) + else: + self.put_word(True, data[2 + self.addresssize:2 + self.addresssize + self.wordsize]) + elif opcode == 3: + # ERASE instruction. + self.put(data[0].ss, data[1].es, + self.out_ann, [0, ['Erase word', 'ERASE']]) + self.put_address(data[2:2 + self.addresssize]) + elif opcode == 0: + if data[2].si == 1 and data[3].si == 1: + # WEN instruction. + self.put(data[0].ss, data[2 + self.addresssize - 1].es, + self.out_ann, [0, ['Write enable', 'WEN']]) + elif data[2].si == 0 and data[3].si == 0: + # WDS instruction. + self.put(data[0].ss, data[2 + self.addresssize - 1].es, + self.out_ann, [0, ['Write disable', 'WDS']]) + elif data[2].si == 1 and data[3].si == 0: + # ERAL instruction. + self.put(data[0].ss, data[2 + self.addresssize - 1].es, + self.out_ann, [0, ['Erase all memory', + 'Erase all', 'ERAL']]) + elif data[2].si == 0 and data[3].si == 1: + # WRAL instruction. + self.put(data[0].ss, data[2 + self.addresssize - 1].es, + self.out_ann, [0, ['Write all memory', + 'Write all', 'WRAL']]) + # Get word. + if len(data) < 2 + self.addresssize + self.wordsize: + self.put(data[2 + self.addresssize].ss, + data[len(data) - 1].ss, + self.out_ann, [2, ['Not enough word bits']]) + else: + self.put_word(True, data[2 + self.addresssize:2 + self.addresssize + self.wordsize]) diff --git a/libsigrokdecode4DSL/decoders/em4100/__init__.py b/libsigrokdecode4DSL/decoders/em4100/__init__.py new file mode 100644 index 00000000..c3c95e28 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/em4100/__init__.py @@ -0,0 +1,24 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Benjamin Larsson +## +## 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, see . +## + +''' +EM4100 is a biphase/manchester/PSK based 100-150kHz RFID protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/em4100/pd.py b/libsigrokdecode4DSL/decoders/em4100/pd.py new file mode 100644 index 00000000..7f42ad70 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/em4100/pd.py @@ -0,0 +1,238 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Benjamin Larsson +## +## 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, see . +## + +import sigrokdecode as srd + +class SamplerateError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = 'em4100' + name = 'EM4100' + longname = 'RFID EM4100' + desc = 'EM4100 100-150kHz RFID protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['IC', 'RFID'] + channels = ( + {'id': 'data', 'name': 'Data', 'desc': 'Data line'}, + ) + options = ( + {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-high', + 'values': ('active-low', 'active-high')}, + {'id': 'datarate' , 'desc': 'Data rate', 'default': 64, + 'values': (64, 32, 16)}, +# {'id': 'coding', 'desc': 'Bit coding', 'default': 'biphase', +# 'values': ('biphase', 'manchester', 'psk')}, + {'id': 'coilfreq', 'desc': 'Coil frequency', 'default': 125000}, + ) + annotations = ( + ('bit', 'Bit'), + ('header', 'Header'), + ('version-customer', 'Version/customer'), + ('data', 'Data'), + ('rowparity-ok', 'Row parity OK'), + ('rowparity-err', 'Row parity error'), + ('colparity-ok', 'Column parity OK'), + ('colparity-err', 'Column parity error'), + ('stopbit', 'Stop bit'), + ('tag', 'Tag'), + ) + annotation_rows = ( + ('bits', 'Bits', (0,)), + ('fields', 'Fields', (1, 2, 3, 4, 5, 6, 7, 8)), + ('tags', 'Tags', (9,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.oldpin = None + self.last_samplenum = None + self.lastlast_samplenum = None + self.last_edge = 0 + self.bit_width = 0 + self.halfbit_limit = 0 + self.oldpp = 0 + self.oldpl = 0 + self.oldsamplenum = 0 + self.last_bit_pos = 0 + self.ss_first = 0 + self.first_one = 0 + self.state = 'HEADER' + self.data = 0 + self.data_bits = 0 + self.ss_data = 0 + self.data_parity = 0 + self.payload_cnt = 0 + self.data_col_parity = [0, 0, 0, 0, 0, 0] + self.col_parity = [0, 0, 0, 0, 0, 0] + self.tag = 0 + self.all_row_parity_ok = True + self.col_parity_pos = [] + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + self.bit_width = (self.samplerate / self.options['coilfreq']) * self.options['datarate'] + self.halfbit_limit = self.bit_width/2 + self.bit_width/4 + self.polarity = 0 if self.options['polarity'] == 'active-low' else 1 + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putbit(self, bit, ss, es): + self.put(ss, es, self.out_ann, [0, [str(bit)]]) + if self.state == 'HEADER': + if bit == 1: + if self.first_one > 0: + self.first_one += 1 + if self.first_one == 9: + self.put(self.ss_first, es, self.out_ann, + [1, ['Header', 'Head', 'He', 'H']]) + self.first_one = 0 + self.state = 'PAYLOAD' + return + if self.first_one == 0: + self.first_one = 1 + self.ss_first = ss + + if bit == 0: + self.first_one = 0 + return + + if self.state == 'PAYLOAD': + self.payload_cnt += 1 + if self.data_bits == 0: + self.ss_data = ss + self.data = 0 + self.data_parity = 0 + self.data_bits += 1 + if self.data_bits == 5: + s = 'Version/customer' if self.payload_cnt <= 10 else 'Data' + c = 2 if self.payload_cnt <= 10 else 3 + self.put(self.ss_data, ss, self.out_ann, + [c, [s + ': %X' % self.data, '%X' % self.data]]) + s = 'OK' if self.data_parity == bit else 'ERROR' + c = 4 if s == 'OK' else 5 + if s == 'ERROR': + self.all_row_parity_ok = False + self.put(ss, es, self.out_ann, + [c, ['Row parity: ' + s, 'RP: ' + s, 'RP', 'R']]) + self.tag = (self.tag << 4) | self.data + self.data_bits = 0 + if self.payload_cnt == 50: + self.state = 'TRAILER' + self.payload_cnt = 0 + + self.data_parity ^= bit + self.data_col_parity[self.data_bits] ^= bit + self.data = (self.data << 1) | bit + return + + if self.state == 'TRAILER': + self.payload_cnt += 1 + if self.data_bits == 0: + self.ss_data = ss + self.data = 0 + self.data_parity = 0 + self.data_bits += 1 + self.col_parity[self.data_bits] = bit + self.col_parity_pos.append([ss, es]) + + if self.data_bits == 5: + self.put(ss, es, self.out_ann, [8, ['Stop bit', 'SB', 'S']]) + + for i in range(1, 5): + s = 'OK' if self.data_col_parity[i] == \ + self.col_parity[i] else 'ERROR' + c = 6 if s == 'OK' else 7 + self.put(self.col_parity_pos[i - 1][0], + self.col_parity_pos[i - 1][1], self.out_ann, + [c, ['Column parity %d: %s' % (i, s), + 'CP%d: %s' % (i, s), 'CP%d' % i, 'C']]) + + # Emit an annotation for valid-looking tags. + all_col_parity_ok = (self.data_col_parity[1:5] == self.col_parity[1:5]) + if all_col_parity_ok and self.all_row_parity_ok: + self.put(self.ss_first, es, self.out_ann, + [9, ['Tag: %010X' % self.tag, 'Tag', 'T']]) + + self.tag = 0 + self.data_bits = 0 + + if self.payload_cnt == 5: + self.state = 'HEADER' + self.payload_cnt = 0 + self.data_col_parity = [0, 0, 0, 0, 0, 0] + self.col_parity = [0, 0, 0, 0, 0, 0] + self.col_parity_pos = [] + self.all_row_parity_ok = True + + def manchester_decode(self, pl, pp, pin): + bit = self.oldpin ^ self.polarity + if pl > self.halfbit_limit: + es = int(self.samplenum - pl/2) + if self.oldpl > self.halfbit_limit: + ss = int(self.oldsamplenum - self.oldpl/2) + else: + ss = int(self.oldsamplenum - self.oldpl) + self.putbit(bit, ss, es) + self.last_bit_pos = int(self.samplenum - pl/2) + else: + es = int(self.samplenum) + if self.oldpl > self.halfbit_limit: + ss = int(self.oldsamplenum - self.oldpl/2) + self.putbit(bit, ss, es) + self.last_bit_pos = int(self.samplenum) + else: + if self.last_bit_pos <= self.oldsamplenum - self.oldpl: + ss = int(self.oldsamplenum - self.oldpl) + self.putbit(bit, ss, es) + self.last_bit_pos = int(self.samplenum) + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + + # Initialize internal state from the very first sample. + (pin,) = self.wait() + self.oldpin = pin + self.last_samplenum = self.samplenum + self.lastlast_samplenum = self.samplenum + self.last_edge = self.samplenum + self.oldpl = 0 + self.oldpp = 0 + self.oldsamplenum = 0 + self.last_bit_pos = 0 + + while True: + # Ignore identical samples, only process edges. + (pin,) = self.wait({0: 'e'}) + pl = self.samplenum - self.oldsamplenum + pp = pin + self.manchester_decode(pl, pp, pin) + self.oldpl = pl + self.oldpp = pp + self.oldsamplenum = self.samplenum + self.oldpin = pin diff --git a/libsigrokdecode4DSL/decoders/em4305/__init__.py b/libsigrokdecode4DSL/decoders/em4305/__init__.py new file mode 100644 index 00000000..df437787 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/em4305/__init__.py @@ -0,0 +1,24 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Benjamin Larsson +## +## 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, see . +## + +''' +EM4305 is a 100-150kHz RFID protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/em4305/pd.py b/libsigrokdecode4DSL/decoders/em4305/pd.py new file mode 100644 index 00000000..6297643c --- /dev/null +++ b/libsigrokdecode4DSL/decoders/em4305/pd.py @@ -0,0 +1,394 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2016 Benjamin Larsson +## +## 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, see . +## + +import sigrokdecode as srd + +class SamplerateError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = 'em4305' + name = 'EM4305' + longname = 'RFID EM4205/EM4305' + desc = 'EM4205/EM4305 100-150kHz RFID protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['IC', 'RFID'] + channels = ( + {'id': 'data', 'name': 'Data', 'desc': 'Data line'}, + ) + options = ( + {'id': 'coilfreq', 'desc': 'Coil frequency', 'default': 125000}, + {'id': 'first_field_stop', 'desc': 'First field stop min', 'default': 40}, + {'id': 'w_gap', 'desc': 'Write gap min', 'default': 12}, + {'id': 'w_one_max', 'desc': 'Write one max', 'default': 32}, + {'id': 'w_zero_on_min', 'desc': 'Write zero on min', 'default': 15}, + {'id': 'w_zero_off_max', 'desc': 'Write zero off max', 'default': 27}, + {'id': 'em4100_decode', 'desc': 'EM4100 decode', 'default': 'on', + 'values': ('on', 'off')}, + ) + annotations = ( + ('bit_value', 'Bit value'), + ('first_field_stop', 'First field stop'), + ('write_gap', 'Write gap'), + ('write_mode_exit', 'Write mode exit'), + ('bit', 'Bit'), + ('opcode', 'Opcode'), + ('lock', 'Lock'), + ('data', 'Data'), + ('password', 'Password'), + ('address', 'Address'), + ('bitrate', 'Bitrate'), + ) + annotation_rows = ( + ('bits', 'Bits', (0,)), + ('structure', 'Structure', (1, 2, 3, 4)), + ('fields', 'Fields', (5, 6, 7, 8, 9)), + ('decode', 'Decode', (10,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.last_samplenum = None + self.state = 'FFS_SEARCH' + self.bits_pos = [[0 for col in range(3)] for row in range(70)] + self.br_string = ['RF/8', 'RF/16', 'Unused', 'RF/32', 'RF/40', + 'Unused', 'Unused', 'RF/64',] + self.encoder = ['not used', 'Manchester', 'Bi-phase', 'not used'] + self.delayed_on = ['No delay', 'Delayed on - BP/8', 'Delayed on - BP/4', 'No delay'] + self.em4100_decode1_partial = 0 + self.cmds = ['Invalid', 'Login', 'Write word', 'Invalid', 'Read word', 'Disable', 'Protect', 'Invalid'] + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + self.field_clock = self.samplerate / self.options['coilfreq'] + self.wzmax = self.options['w_zero_off_max'] * self.field_clock + self.wzmin = self.options['w_zero_on_min'] * self.field_clock + self.womax = self.options['w_one_max'] * self.field_clock + self.ffs = self.options['first_field_stop'] * self.field_clock + self.writegap = self.options['w_gap'] * self.field_clock + self.nogap = 300 * self.field_clock + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def decode_config(self, idx): + bitrate = self.get_3_bits(idx+2) + self.put(self.bits_pos[idx][1], self.bits_pos[idx+5][2], + self.out_ann, [10, ['Data rate: ' + \ + self.br_string[bitrate], self.br_string[bitrate]]]) + encoding = self.bits_pos[idx+6][0]<<0 | self.bits_pos[idx+7][0]<<1 + self.put(self.bits_pos[idx+6][1], self.bits_pos[idx+10][2], + self.out_ann, [10, ['Encoder: ' + \ + self.encoder[encoding], self.encoder[encoding]]]) + self.put(self.bits_pos[idx+11][1], self.bits_pos[idx+12][2], self.out_ann, + [10, ['Zero bits', 'ZB']]) + delay_on = self.bits_pos[idx+13][0]<<0 | self.bits_pos[idx+14][0]<<1 + self.put(self.bits_pos[idx+13][1], self.bits_pos[idx+14][2], + self.out_ann, [10, ['Delayed on: ' + \ + self.delayed_on[delay_on], self.delayed_on[delay_on]]]) + lwr = self.bits_pos[idx+15][0]<<3 | self.bits_pos[idx+16][0]<<2 | \ + self.bits_pos[idx+18][0]<<1 | self.bits_pos[idx+19][0]<<0 + self.put(self.bits_pos[idx+15][1], self.bits_pos[idx+19][2], + self.out_ann, [10, ['Last default read word: %d' % lwr, 'LWR: %d' % lwr, '%d' % lwr]]) + self.put(self.bits_pos[idx+20][1], self.bits_pos[idx+20][2], + self.out_ann, [10, ['Read login: %d' % self.bits_pos[idx+20][0], '%d' % self.bits_pos[idx+20][0]]]) + self.put(self.bits_pos[idx+21][1], self.bits_pos[idx+21][2], self.out_ann, + [10, ['Zero bits', 'ZB']]) + self.put(self.bits_pos[idx+22][1], self.bits_pos[idx+22][2], + self.out_ann, [10, ['Write login: %d' % self.bits_pos[idx+22][0], '%d' % self.bits_pos[idx+22][0]]]) + self.put(self.bits_pos[idx+23][1], self.bits_pos[idx+24][2], self.out_ann, + [10, ['Zero bits', 'ZB']]) + self.put(self.bits_pos[idx+25][1], self.bits_pos[idx+25][2], + self.out_ann, [10, ['Disable: %d' % self.bits_pos[idx+25][0], '%d' % self.bits_pos[idx+25][0]]]) + self.put(self.bits_pos[idx+27][1], self.bits_pos[idx+27][2], + self.out_ann, [10, ['Reader talk first: %d' % self.bits_pos[idx+27][0], 'RTF: %d' % self.bits_pos[idx+27][0]]]) + self.put(self.bits_pos[idx+28][1], self.bits_pos[idx+28][2], self.out_ann, + [10, ['Zero bits', 'ZB']]) + self.put(self.bits_pos[idx+29][1], self.bits_pos[idx+29][2], + self.out_ann, [10, ['Pigeon mode: %d' % self.bits_pos[idx+29][0], '%d' % self.bits_pos[idx+29][0]]]) + self.put(self.bits_pos[idx+30][1], self.bits_pos[idx+34][2], + self.out_ann, [10, ['Reserved', 'Res', 'R']]) + + def put4bits(self, idx): + bits = self.bits_pos[idx][0]<<3 | self.bits_pos[idx+1][0]<<2 | \ + self.bits_pos[idx+2][0]<<1 | self.bits_pos[idx+3][0] + self.put(self.bits_pos[idx][1], self.bits_pos[idx+3][2], self.out_ann, + [10, ['%X' % bits]]) + + def em4100_decode1(self, idx): + self.put(self.bits_pos[idx][1], self.bits_pos[idx+9][2], self.out_ann, + [10, ['EM4100 header', 'EM header', 'Header', 'H']]) + self.put4bits(idx+10) + bits = self.bits_pos[idx+15][0]<<3 | self.bits_pos[idx+16][0]<<2 | \ + self.bits_pos[idx+18][0]<<1 | self.bits_pos[idx+19][0]<<0 + self.put(self.bits_pos[idx+15][1], self.bits_pos[idx+19][2], self.out_ann, + [10, ['%X' % bits]]) + self.put4bits(idx+21) + self.put4bits(idx+27) + self.em4100_decode1_partial = self.bits_pos[idx+32][0]<<3 | \ + self.bits_pos[idx+33][0]<<2 | self.bits_pos[idx+34][0]<<1 + self.put(self.bits_pos[idx+32][1], self.bits_pos[idx+34][2], + self.out_ann, [10, ['Partial nibble']]) + + def em4100_decode2(self, idx): + if self.em4100_decode1_partial != 0: + bits = self.em4100_decode1_partial + self.bits_pos[idx][0] + self.put(self.bits_pos[idx][1], self.bits_pos[idx][2], + self.out_ann, [10, ['%X' % bits]]) + self.em4100_decode1_partial = 0 + else: + self.put(self.bits_pos[idx][1], self.bits_pos[idx][2], + self.out_ann, [10, ['Partial nibble']]) + + self.put4bits(idx+2) + bits = self.bits_pos[idx+7][0]<<3 | self.bits_pos[idx+9][0]<<2 | \ + self.bits_pos[idx+10][0]<<1 | self.bits_pos[idx+11][0]<<0 + self.put(self.bits_pos[idx+7][1], self.bits_pos[idx+11][2], self.out_ann, + [10, ['%X' % bits]]) + self.put4bits(idx+13) + self.put4bits(idx+19) + bits = self.bits_pos[idx+24][0]<<3 | self.bits_pos[idx+25][0]<<2 | \ + self.bits_pos[idx+27][0]<<1 | self.bits_pos[idx+28][0]<<0 + self.put(self.bits_pos[idx+24][1], self.bits_pos[idx+28][2], self.out_ann, + [10, ['%X' % bits]]) + self.put(self.bits_pos[idx+30][1], self.bits_pos[idx+34][2], + self.out_ann, [10, ['EM4100 trailer']]) + + def get_32_bits(self, idx): + return self.get_8_bits(idx+27)<<24 | self.get_8_bits(idx+18)<<16 | \ + self.get_8_bits(idx+9)<<8 | self.get_8_bits(idx) + + def get_8_bits(self, idx): + retval = 0 + for i in range(0, 8): + retval <<= 1 + retval |= self.bits_pos[i+idx][0] + return retval + + def get_3_bits(self, idx): + return self.bits_pos[idx][0]<<2 | self.bits_pos[idx+1][0]<<1 | \ + self.bits_pos[idx+2][0] + + def get_4_bits(self, idx): + return self.bits_pos[idx][0]<<0 | self.bits_pos[idx+1][0]<<1 | \ + self.bits_pos[idx+2][0]<<2 | self.bits_pos[idx+3][0]<<3 + + def print_row_parity(self, idx, length): + parity = 0 + for i in range(0, length): + parity += self.bits_pos[i+idx][0] + parity = parity & 0x1 + if parity == self.bits_pos[idx+length][0]: + self.put(self.bits_pos[idx+length][1], self.bits_pos[idx+length][2], self.out_ann, + [5, ['Row parity OK', 'Parity OK', 'OK']]) + else: + self.put(self.bits_pos[idx+length][1], self.bits_pos[idx+length][2], self.out_ann, + [5, ['Row parity failed', 'Parity failed', 'Fail']]) + + def print_col_parity(self, idx): + data_1 = self.get_8_bits(idx) + data_2 = self.get_8_bits(idx+9) + data_3 = self.get_8_bits(idx+9+9) + data_4 = self.get_8_bits(idx+9+9+9) + col_par = self.get_8_bits(idx+9+9+9+9) + col_par_calc = data_1^data_2^data_3^data_4 + + if col_par == col_par_calc: + self.put(self.bits_pos[idx+9+9+9+9][1], self.bits_pos[idx+9+9+9+9+7][2], self.out_ann, + [5, ['Column parity OK', 'Parity OK', 'OK']]) + else: + self.put(self.bits_pos[idx+9+9+9+9][1], self.bits_pos[idx+9+9+9+9+7][2], self.out_ann, + [5, ['Column parity failed', 'Parity failed', 'Fail']]) + + def print_8bit_data(self, idx): + data = self.get_8_bits(idx) + self.put(self.bits_pos[idx][1], self.bits_pos[idx+7][2], self.out_ann, + [9, ['Data' + ': %X' % data, '%X' % data]]) + + def put_fields(self): + if self.bit_nr == 50: + self.put(self.bits_pos[0][1], self.bits_pos[0][2], self.out_ann, + [4, ['Logic zero']]) + self.put(self.bits_pos[1][1], self.bits_pos[4][2], self.out_ann, + [4, ['Command', 'Cmd', 'C']]) + self.put(self.bits_pos[5][1], self.bits_pos[49][2], self.out_ann, + [4, ['Password', 'Passwd', 'Pass', 'P']]) + # Get command. + cmd = self.get_3_bits(1) + self.put(self.bits_pos[1][1], self.bits_pos[3][2], self.out_ann, + [5, [self.cmds[cmd]]]) + self.print_row_parity(1, 3) + + # Print data. + self.print_8bit_data(5) + self.print_row_parity(5, 8) + self.print_8bit_data(14) + self.print_row_parity(14, 8) + self.print_8bit_data(23) + self.print_row_parity(23, 8) + self.print_8bit_data(32) + self.print_row_parity(32, 8) + self.print_col_parity(5) + if self.bits_pos[49][0] == 0: + self.put(self.bits_pos[49][1], self.bits_pos[49][2], self.out_ann, + [5, ['Stop bit', 'Stop', 'SB']]) + else: + self.put(self.bits_pos[49][1], self.bits_pos[49][2], self.out_ann, + [5, ['Stop bit error', 'Error']]) + + if cmd == 1: + password = self.get_32_bits(5) + self.put(self.bits_pos[12][1], self.bits_pos[46][2], self.out_ann, + [10, ['Login password: %X' % password]]) + + if self.bit_nr == 57: + self.put(self.bits_pos[0][1], self.bits_pos[0][2], self.out_ann, + [4, ['Logic zero', 'LZ']]) + self.put(self.bits_pos[1][1], self.bits_pos[4][2], self.out_ann, + [4, ['Command', 'Cmd', 'C']]) + self.put(self.bits_pos[5][1], self.bits_pos[11][2], self.out_ann, + [4, ['Address', 'Addr', 'A']]) + self.put(self.bits_pos[12][1], self.bits_pos[56][2], self.out_ann, + [4, ['Data', 'Da', 'D']]) + + # Get command. + cmd = self.get_3_bits(1) + self.put(self.bits_pos[1][1], self.bits_pos[3][2], self.out_ann, + [5, [self.cmds[cmd]]]) + self.print_row_parity(1, 3) + + # Get address. + addr = self.get_4_bits(5) + self.put(self.bits_pos[5][1], self.bits_pos[8][2], self.out_ann, + [9, ['Addr' + ': %d' % addr, '%d' % addr]]) + self.put(self.bits_pos[9][1], self.bits_pos[10][2], self.out_ann, + [5, ['Zero bits', 'ZB']]) + self.print_row_parity(5, 6) + # Print data. + self.print_8bit_data(12) + self.print_row_parity(12, 8) + self.print_8bit_data(21) + self.print_row_parity(21, 8) + self.print_8bit_data(30) + self.print_row_parity(30, 8) + self.print_8bit_data(39) + self.print_row_parity(39, 8) + self.print_col_parity(12) + if self.bits_pos[56][0] == 0: + self.put(self.bits_pos[56][1], self.bits_pos[56][2], self.out_ann, + [5, ['Stop bit', 'Stop', 'SB']]) + else: + self.put(self.bits_pos[56][1], self.bits_pos[56][2], self.out_ann, + [5, ['Stop bit error', 'Error']]) + + if addr == 4: + self.decode_config(12) + + if addr == 2: + password = self.get_32_bits(12) + self.put(self.bits_pos[12][1], self.bits_pos[46][2], self.out_ann, + [10, ['Write password: %X' % password]]) + + # If we are programming EM4100 data we can decode it halfway. + if addr == 5 and self.options['em4100_decode'] == 'on': + self.em4100_decode1(12) + if addr == 6 and self.options['em4100_decode'] == 'on': + self.em4100_decode2(12) + + self.bit_nr = 0 + + def add_bits_pos(self, bit, ss_bit, es_bit): + if self.bit_nr < 70: + self.bits_pos[self.bit_nr][0] = bit + self.bits_pos[self.bit_nr][1] = ss_bit + self.bits_pos[self.bit_nr][2] = es_bit + self.bit_nr += 1 + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + + # Initialize internal state. + self.last_samplenum = self.samplenum + self.oldsamplenum = 0 + self.old_gap_end = 0 + self.gap_detected = 0 + self.bit_nr = 0 + + while True: + # Ignore identical samples, only process edges. + (pin,) = self.wait({0: 'e'}) + + pl = self.samplenum - self.oldsamplenum + pp = pin + samples = self.samplenum - self.last_samplenum + + if self.state == 'FFS_DETECTED': + if pl > self.writegap: + self.gap_detected = 1 + if (self.last_samplenum - self.old_gap_end) > self.nogap: + self.gap_detected = 0 + self.state = 'FFS_SEARCH' + self.put(self.old_gap_end, self.last_samplenum, + self.out_ann, [3, ['Write mode exit']]) + self.put_fields() + + if self.state == 'FFS_SEARCH': + if pl > self.ffs: + self.gap_detected = 1 + self.put(self.last_samplenum, self.samplenum, + self.out_ann, [1, ['First field stop', 'Field stop', 'FFS']]) + self.state = 'FFS_DETECTED' + + if self.gap_detected == 1: + self.gap_detected = 0 + if (self.last_samplenum - self.old_gap_end) > self.wzmin \ + and (self.last_samplenum - self.old_gap_end) < self.wzmax: + self.put(self.old_gap_end, self.samplenum, + self.out_ann, [0, ['0']]) + self.add_bits_pos(0, self.old_gap_end, self.samplenum) + if (self.last_samplenum - self.old_gap_end) > self.womax \ + and (self.last_samplenum-self.old_gap_end) < self.nogap: + # One or more 1 bits + one_bits = (int)((self.last_samplenum - self.old_gap_end) / self.womax) + for ox in range(0, one_bits): + bs = (int)(self.old_gap_end+ox*self.womax) + be = (int)(self.old_gap_end+ox*self.womax + self.womax) + self.put(bs, be, self.out_ann, [0, ['1']]) + self.add_bits_pos(1, bs, be) + if (self.samplenum - self.last_samplenum) > self.wzmin \ + and (self.samplenum - self.last_samplenum) < self.wzmax: + bs = (int)(self.old_gap_end+one_bits*self.womax) + self.put(bs, self.samplenum, self.out_ann, [0, ['0']]) + self.add_bits_pos(0, bs, self.samplenum) + + self.old_gap_end = self.samplenum + + if self.state == 'SKIP': + self.state = 'FFS_SEARCH' + + self.oldsamplenum = self.samplenum + self.last_samplenum = self.samplenum diff --git a/libsigrokdecode4DSL/decoders/enc28j60/__init__.py b/libsigrokdecode4DSL/decoders/enc28j60/__init__.py new file mode 100644 index 00000000..42f4377e --- /dev/null +++ b/libsigrokdecode4DSL/decoders/enc28j60/__init__.py @@ -0,0 +1,32 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Jiahao Li +## +## Permission is hereby granted, free of charge, to any person obtaining a copy +## of this software and associated documentation files (the "Software"), to deal +## in the Software without restriction, including without limitation the rights +## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +## copies of the Software, and to permit persons to whom the Software is +## furnished to do so, subject to the following conditions: +## +## The above copyright notice and this permission notice shall be included in all +## copies or substantial portions of the Software. +## +## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +## SOFTWARE. + +''' +This decoder stacks on top of the 'spi' PD and decodes the protocol spoken +by the Microchip ENC28J60 Ethernet chip. + +Details: +http://ww1.microchip.com/downloads/en/DeviceDoc/39662e.pdf +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/enc28j60/lists.py b/libsigrokdecode4DSL/decoders/enc28j60/lists.py new file mode 100644 index 00000000..59fbc1f2 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/enc28j60/lists.py @@ -0,0 +1,161 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Jiahao Li +## +## Permission is hereby granted, free of charge, to any person obtaining a copy +## of this software and associated documentation files (the "Software"), to deal +## in the Software without restriction, including without limitation the rights +## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +## copies of the Software, and to permit persons to whom the Software is +## furnished to do so, subject to the following conditions: +## +## The above copyright notice and this permission notice shall be included in all +## copies or substantial portions of the Software. +## +## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +## SOFTWARE. + +REGS = [ + [ + 'ERDPTL', + 'ERDPTH', + 'EWRPTL', + 'EWRPTH', + 'ETXSTL', + 'ETXSTH', + 'ETXNDL', + 'ETXNDH', + 'ERXSTL', + 'ERXSTH', + 'ERXNDL', + 'ERXNDH', + 'ERXRDPTL', + 'ERXRDPTH', + 'ERXWRPTL', + 'ERXWRPTH', + 'EDMASTL', + 'EDMASTH', + 'EDMANDL', + 'EDMANDH', + 'EDMADSTL', + 'EDMADSTH', + 'EDMACSL', + 'EDMACSH', + '—', + '—', + 'Reserved', + 'EIE', + 'EIR', + 'ESTAT', + 'ECON2', + 'ECON1', + ], + [ + 'EHT0', + 'EHT1', + 'EHT2', + 'EHT3', + 'EHT4', + 'EHT5', + 'EHT6', + 'EHT7', + 'EPMM0', + 'EPMM1', + 'EPMM2', + 'EPMM3', + 'EPMM4', + 'EPMM5', + 'EPMM6', + 'EPMM7', + 'EPMCSL', + 'EPMCSH', + '—', + '—', + 'EPMOL', + 'EPMOH', + 'Reserved', + 'Reserved', + 'ERXFCON', + 'EPKTCNT', + 'Reserved', + 'EIE', + 'EIR', + 'ESTAT', + 'ECON2', + 'ECON1', + ], + [ + 'MACON1', + 'Reserved', + 'MACON3', + 'MACON4', + 'MABBIPG', + '—', + 'MAIPGL', + 'MAIPGH', + 'MACLCON1', + 'MACLCON2', + 'MAMXFLL', + 'MAMXFLH', + 'Reserved', + 'Reserved', + 'Reserved', + '—', + 'Reserved', + 'Reserved', + 'MICMD', + '—', + 'MIREGADR', + 'Reserved', + 'MIWRL', + 'MIWRH', + 'MIRDL', + 'MIRDH', + 'Reserved', + 'EIE', + 'EIR', + 'ESTAT', + 'ECON2', + 'ECON1', + ], + [ + 'MAADR5', + 'MAADR6', + 'MAADR3', + 'MAADR4', + 'MAADR1', + 'MAADR2', + 'EBSTSD', + 'EBSTCON', + 'EBSTCSL', + 'EBSTCSH', + 'MISTAT', + '—', + '—', + '—', + '—', + '—', + '—', + '—', + 'EREVID', + '—', + '—', + 'ECOCON', + 'Reserved', + 'EFLOCON', + 'EPAUSL', + 'EPAUSH', + 'Reserved', + 'EIE', + 'EIR', + 'ESTAT', + 'ECON2', + 'ECON1', + ], +] diff --git a/libsigrokdecode4DSL/decoders/enc28j60/pd.py b/libsigrokdecode4DSL/decoders/enc28j60/pd.py new file mode 100644 index 00000000..f7a6625a --- /dev/null +++ b/libsigrokdecode4DSL/decoders/enc28j60/pd.py @@ -0,0 +1,294 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Jiahao Li +## +## Permission is hereby granted, free of charge, to any person obtaining a copy +## of this software and associated documentation files (the "Software"), to deal +## in the Software without restriction, including without limitation the rights +## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +## copies of the Software, and to permit persons to whom the Software is +## furnished to do so, subject to the following conditions: +## +## The above copyright notice and this permission notice shall be included in all +## copies or substantial portions of the Software. +## +## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +## SOFTWARE. + +import sigrokdecode as srd +from .lists import * + +OPCODE_MASK = 0b11100000 +REG_ADDR_MASK = 0b00011111 + +OPCODE_HANDLERS = { + 0b00000000: '_process_rcr', + 0b00100000: '_process_rbm', + 0b01000000: '_process_wcr', + 0b01100000: '_process_wbm', + 0b10000000: '_process_bfs', + 0b10100000: '_process_bfc', + 0b11100000: '_process_src', +} + +(ANN_RCR, ANN_RBM, ANN_WCR, ANN_WBM, ANN_BFS, ANN_BFC, ANN_SRC, ANN_DATA, +ANN_REG_ADDR, ANN_WARNING) = range(10) + +REG_ADDR_ECON1 = 0x1F +BIT_ECON1_BSEL0 = 0b00000001 +BIT_ECON1_BSEL1 = 0b00000010 + +class Decoder(srd.Decoder): + api_version = 3 + id = 'enc28j60' + name = 'ENC28J60' + longname = 'Microchip ENC28J60' + desc = 'Microchip ENC28J60 10Base-T Ethernet controller protocol.' + license = 'mit' + inputs = ['spi'] + outputs = [] + tags = ['Embedded/industrial', 'Networking'] + annotations = ( + ('rcr', 'Read Control Register'), + ('rbm', 'Read Buffer Memory'), + ('wcr', 'Write Control Register'), + ('wbm', 'Write Buffer Memory'), + ('bfs', 'Bit Field Set'), + ('bfc', 'Bit Field Clear'), + ('src', 'System Reset Command'), + ('data', 'Data'), + ('reg-addr', 'Register Address'), + ('warning', 'Warning'), + ) + annotation_rows = ( + ('commands', 'Commands', + (ANN_RCR, ANN_RBM, ANN_WCR, ANN_WBM, ANN_BFS, ANN_BFC, ANN_SRC)), + ('fields', 'Fields', (ANN_DATA, ANN_REG_ADDR)), + ('warnings', 'Warnings', (ANN_WARNING,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.mosi = [] + self.miso = [] + self.ranges = [] + self.cmd_ss = None + self.cmd_es = None + self.range_ss = None + self.range_es = None + self.active = False + self.bsel0 = None + self.bsel1 = None + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putc(self, data): + self.put(self.cmd_ss, self.cmd_es, self.out_ann, data) + + def putr(self, data): + self.put(self.range_ss, self.range_es, self.out_ann, data) + + def _process_command(self): + if len(self.mosi) == 0: + self.active = False + return + + header = self.mosi[0] + opcode = header & OPCODE_MASK + + if opcode not in OPCODE_HANDLERS: + self._put_command_warning("Unknown opcode.") + self.active = False + return + + getattr(self, OPCODE_HANDLERS[opcode])() + + self.active = False + + def _get_register_name(self, reg_addr): + if (self.bsel0 is None) or (self.bsel1 is None): + # We don't know the bank we're in yet. + return None + else: + bank = (self.bsel1 << 1) + self.bsel0 + return REGS[bank][reg_addr] + + def _put_register_header(self): + reg_addr = self.mosi[0] & REG_ADDR_MASK + reg_name = self._get_register_name(reg_addr) + + self.range_ss, self.range_es = self.cmd_ss, self.ranges[1][0] + + if reg_name is None: + # We don't know the bank we're in yet. + self.putr([ANN_REG_ADDR, [ + 'Reg Bank ? Addr 0x{0:02X}'.format(reg_addr), + '?:{0:02X}'.format(reg_addr)]]) + self.putr([ANN_WARNING, ['Warning: Register bank not known yet.', + 'Warning']]) + else: + self.putr([ANN_REG_ADDR, ['Reg {0}'.format(reg_name), + '{0}'.format(reg_name)]]) + + if (reg_name == '-') or (reg_name == 'Reserved'): + self.putr([ANN_WARNING, ['Warning: Invalid register accessed.', + 'Warning']]) + + def _put_data_byte(self, data, byte_index, binary=False): + self.range_ss = self.ranges[byte_index][0] + if byte_index == len(self.mosi) - 1: + self.range_es = self.cmd_es + else: + self.range_es = self.ranges[byte_index + 1][0] + + if binary: + self.putr([ANN_DATA, ['Data 0b{0:08b}'.format(data), + '{0:08b}'.format(data)]]) + else: + self.putr([ANN_DATA, ['Data 0x{0:02X}'.format(data), + '{0:02X}'.format(data)]]) + + def _put_command_warning(self, reason): + self.putc([ANN_WARNING, ['Warning: {0}'.format(reason), 'Warning']]) + + def _process_rcr(self): + self.putc([ANN_RCR, ['Read Control Register', 'RCR']]) + + if (len(self.mosi) != 2) and (len(self.mosi) != 3): + self._put_command_warning('Invalid command length.') + return + + self._put_register_header() + + reg_name = self._get_register_name(self.mosi[0] & REG_ADDR_MASK) + if reg_name is None: + # We can't tell if we're accessing MAC/MII registers or not + # Let's trust the user in this case. + pass + else: + if (reg_name[0] == 'M') and (len(self.mosi) != 3): + self._put_command_warning('Attempting to read a MAC/MII ' + + 'register without using the dummy byte.') + return + + if (reg_name[0] != 'M') and (len(self.mosi) != 2): + self._put_command_warning('Attempting to read a non-MAC/MII ' + + 'register using the dummy byte.') + return + + if len(self.mosi) == 2: + self._put_data_byte(self.miso[1], 1) + else: + self.range_ss, self.range_es = self.ranges[1][0], self.ranges[2][0] + self.putr([ANN_DATA, ['Dummy Byte', 'Dummy']]) + self._put_data_byte(self.miso[2], 2) + + def _process_rbm(self): + if self.mosi[0] != 0b00111010: + self._put_command_warning('Invalid header byte.') + return + + self.putc([ANN_RBM, ['Read Buffer Memory: Length {0}'.format( + len(self.mosi) - 1), 'RBM']]) + + for i in range(1, len(self.miso)): + self._put_data_byte(self.miso[i], i) + + def _process_wcr(self): + self.putc([ANN_WCR, ['Write Control Register', 'WCR']]) + + if len(self.mosi) != 2: + self._put_command_warning('Invalid command length.') + return + + self._put_register_header() + self._put_data_byte(self.mosi[1], 1) + + if self.mosi[0] & REG_ADDR_MASK == REG_ADDR_ECON1: + self.bsel0 = (self.mosi[1] & BIT_ECON1_BSEL0) >> 0 + self.bsel1 = (self.mosi[1] & BIT_ECON1_BSEL1) >> 1 + + def _process_wbm(self): + if self.mosi[0] != 0b01111010: + self._put_command_warning('Invalid header byte.') + return + + self.putc([ANN_WBM, ['Write Buffer Memory: Length {0}'.format( + len(self.mosi) - 1), 'WBM']]) + + for i in range(1, len(self.mosi)): + self._put_data_byte(self.mosi[i], i) + + def _process_bfc(self): + self.putc([ANN_BFC, ['Bit Field Clear', 'BFC']]) + + if len(self.mosi) != 2: + self._put_command_warning('Invalid command length.') + return + + self._put_register_header() + self._put_data_byte(self.mosi[1], 1, True) + + if self.mosi[0] & REG_ADDR_MASK == REG_ADDR_ECON1: + if self.mosi[1] & BIT_ECON1_BSEL0: + self.bsel0 = 0 + if self.mosi[1] & BIT_ECON1_BSEL1: + self.bsel1 = 0 + + def _process_bfs(self): + self.putc([ANN_BFS, ['Bit Field Set', 'BFS']]) + + if len(self.mosi) != 2: + self._put_command_warning('Invalid command length.') + return + + self._put_register_header() + self._put_data_byte(self.mosi[1], 1, True) + + if self.mosi[0] & REG_ADDR_MASK == REG_ADDR_ECON1: + if self.mosi[1] & BIT_ECON1_BSEL0: + self.bsel0 = 1 + if self.mosi[1] & BIT_ECON1_BSEL1: + self.bsel1 = 1 + + def _process_src(self): + self.putc([ANN_SRC, ['System Reset Command', 'SRC']]) + + if len(self.mosi) != 1: + self._put_command_warning('Invalid command length.') + return + + self.bsel0 = 0 + self.bsel1 = 0 + + def decode(self, ss, es, data): + ptype, data1, data2 = data + + if ptype == 'CS-CHANGE': + new_cs = data2 + + if new_cs == 0: + self.active = True + self.cmd_ss = ss + self.mosi = [] + self.miso = [] + self.ranges = [] + elif new_cs == 1: + if self.active: + self.cmd_es = es + self._process_command() + elif ptype == 'DATA': + mosi, miso = data1, data2 + + self.mosi.append(mosi) + self.miso.append(miso) + self.ranges.append((ss, es)) diff --git a/libsigrokdecode4DSL/decoders/flexray/__init__.py b/libsigrokdecode4DSL/decoders/flexray/__init__.py new file mode 100644 index 00000000..73dc7fa1 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/flexray/__init__.py @@ -0,0 +1,32 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Stephan Thiele +## +## 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, see . +## + +''' +FlexRay is a fast, deterministic and fault-tolerant fieldbus system +which is used in cars in high security related areas like X-by-Wire. + +It is the result of the FlexRay consortium which consisted of BMW, +Daimler, Motorola (today Freescale) and Philips, with the goal of +working out a common standard automotive bus system. + +This decoder assumes that at least one channel of a logic level RX line +of a transceiver is sampled (e.g. NXP TJA1080). +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/flexray/pd.py b/libsigrokdecode4DSL/decoders/flexray/pd.py new file mode 100644 index 00000000..8ec30439 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/flexray/pd.py @@ -0,0 +1,413 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Stephan Thiele +## +## 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, see . +## + +import sigrokdecode as srd + +# Selection of constants as defined in FlexRay specification 3.0.1 Chapter A.1: +class Const: + cChannelIdleDelimiter = 11 + cCrcInitA = 0xFEDCBA + cCrcInitB = 0xABCDEF + cCrcPolynomial = 0x5D6DCB + cCrcSize = 24 + cCycleCountMax = 63 + cdBSS = 2 + cdCAS = 30 + cdFES = 2 + cdFSS = 1 + cHCrcInit = 0x01A + cHCrcPolynomial = 0x385 + cHCrcSize = 11 + cSamplesPerBit = 8 + cSlotIDMax = 2047 + cStaticSlotIDMax = 1023 + cVotingSamples = 5 + +class SamplerateError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = 'flexray' + name = 'FlexRay' + longname = 'FlexRay' + desc = 'Automotive network communications protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Automotive'] + channels = ( + {'id': 'channel', 'name': 'Channel', 'desc': 'FlexRay bus channel'}, + ) + options = ( + {'id': 'channel_type', 'desc': 'Channel type', 'default': 'A', + 'values': ('A', 'B')}, + {'id': 'bitrate', 'desc': 'Bitrate (bit/s)', 'default': 10000000, + 'values': (10000000, 5000000, 2500000)}, + ) + annotations = ( + ('data', 'FlexRay payload data'), + ('tss', 'Transmission start sequence'), + ('fss', 'Frame start sequence'), + ('reserved-bit', 'Reserved bit'), + ('ppi', 'Payload preamble indicator'), + ('null-frame', 'Nullframe indicator'), + ('sync-frame', 'Full identifier'), + ('startup-frame', 'Startup frame indicator'), + ('id', 'Frame ID'), + ('length', 'Data length'), + ('header-crc', 'Header CRC'), + ('cycle', 'Cycle code'), + ('data-byte', 'Data byte'), + ('frame-crc', 'Frame CRC'), + ('fes', 'Frame end sequence'), + ('bss', 'Byte start sequence'), + ('warning', 'Warning'), + ('bit', 'Bit'), + ('cid', 'Channel idle delimiter'), + ('dts', 'Dynamic trailing sequence'), + ('cas', 'Collision avoidance symbol'), + ) + annotation_rows = ( + ('bits', 'Bits', (15, 17)), + ('fields', 'Fields', tuple(range(15)) + (18, 19, 20)), + ('warnings', 'Warnings', (16,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.reset_variables() + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + bitrate = float(self.options['bitrate']) + self.samplerate = value + self.bit_width = float(self.samplerate) / bitrate + self.sample_point = (self.bit_width / 100.0) * self.sample_point_percent + + # Generic helper for FlexRay bit annotations. + def putg(self, ss, es, data): + left, right = int(self.sample_point), int(self.bit_width - self.sample_point) + self.put(ss - left, es + right, self.out_ann, data) + + # Single-FlexRay-bit annotation using the current samplenum. + def putx(self, data): + self.putg(self.samplenum, self.samplenum, data) + + # Multi-FlexRay-bit annotation from self.ss_block to current samplenum. + def putb(self, data): + self.putg(self.ss_block, self.samplenum, data) + + # Generic CRC algorithm for any bit size and any data length. Used for + # 11-bit header and 24-bit trailer. Not very efficient but at least it + # works for now. + # + # TODO: + # - use precalculated tables to increase performance. + # - Add support for reverse CRC calculations. + + @staticmethod + def crc(data, data_len_bits, polynom, crc_len_bits, iv=0, xor=0): + reg = iv ^ xor + + for i in range(data_len_bits - 1, -1, -1): + bit = ((reg >> (crc_len_bits - 1)) & 0x1) ^ ((data >> i) & 0x1) + reg <<= 1 + if bit: + reg ^= polynom + + mask = (1 << crc_len_bits) - 1 + crc = reg & mask + + return crc ^ xor + + def reset_variables(self): + self.sample_point_percent = 50 # TODO: use vote based sampling + self.state = 'IDLE' + self.tss_start = self.tss_end = self.frame_type = self.dlc = None + self.rawbits = [] # All bits, including byte start sequence bits + self.bits = [] # Only actual FlexRay frame bits (no byte start sequence bits) + self.curbit = 0 # Current bit of FlexRay frame (bit 0 == FSS) + self.last_databit = 999 # Positive value that bitnum+x will never match + self.last_xmit_bit = 999 # Positive value that bitnum+x will never match + self.ss_block = None + self.ss_databytebits = [] + self.end_of_frame = False + self.dynamic_frame = False + self.ss_bit0 = None + self.ss_bit1 = None + self.ss_bit2 = None + + # Poor man's clock synchronization. Use signal edges which change to + # dominant state in rather simple ways. This naive approach is neither + # aware of the SYNC phase's width nor the specific location of the edge, + # but improves the decoder's reliability when the input signal's bitrate + # does not exactly match the nominal rate. + def dom_edge_seen(self, force=False): + self.dom_edge_snum = self.samplenum + self.dom_edge_bcount = self.curbit + + # Determine the position of the next desired bit's sample point. + def get_sample_point(self, bitnum): + samplenum = self.dom_edge_snum + samplenum += self.bit_width * (bitnum - self.dom_edge_bcount) + samplenum += self.sample_point + return int(samplenum) + + def is_bss_sequence(self): + # FlexRay uses NRZ encoding and adds a binary 10 sequence before each + # byte. After each 8 data bits, a BSS sequence is added but not after + # frame CRC. + + if self.end_of_frame: + return False + + if (len(self.rawbits) - 2) % 10 == 0: + return True + elif (len(self.rawbits) - 3) % 10 == 0: + return True + + return False + + def handle_bit(self, fr_rx): + self.rawbits.append(fr_rx) + self.bits.append(fr_rx) + + # Get the index of the current FlexRay frame bit. + bitnum = len(self.bits) - 1 + + # If this is a byte start sequence remove it from self.bits and ignore it. + if self.is_bss_sequence(): + self.bits.pop() + + if bitnum > 1: + self.putx([15, [str(fr_rx)]]) + else: + if len(self.rawbits) == 2: + self.ss_bit1 = self.samplenum + elif len(self.rawbits) == 3: + self.ss_bit2 = self.samplenum + + self.curbit += 1 # Increase self.curbit (bitnum is not affected). + return + else: + if bitnum > 1: + self.putx([17, [str(fr_rx)]]) + + # Bit 0: Frame start sequence (FSS) bit + if bitnum == 0: + self.ss_bit0 = self.samplenum + + # Bit 1: Start of header + elif bitnum == 1: + if self.rawbits[:3] == [1, 1, 0]: + self.put(self.tss_start, self.tss_end, self.out_ann, + [1, ['Transmission start sequence', 'TSS']]) + + self.putg(self.ss_bit0, self.ss_bit0, [17, [str(self.rawbits[:3][0])]]) + self.putg(self.ss_bit0, self.ss_bit0, [2, ['FSS', 'Frame start sequence']]) + self.putg(self.ss_bit1, self.ss_bit1, [15, [str(self.rawbits[:3][1])]]) + self.putg(self.ss_bit2, self.ss_bit2, [15, [str(self.rawbits[:3][2])]]) + self.putx([17, [str(fr_rx)]]) + self.putx([3, ['Reserved bit: %d' % fr_rx, 'RB: %d' % fr_rx, 'RB']]) + else: + self.put(self.tss_start, self.tss_end, self.out_ann, + [20, ['Collision avoidance symbol', 'CAS']]) + self.reset_variables() + + # TODO: warning, if sequence is neither [1, 1, 0] nor [1, 1, 1] + + # Bit 2: Payload preamble indicator. Must be 0 if null frame indicator is 0. + elif bitnum == 2: + self.putx([4, ['Payload preamble indicator: %d' % fr_rx, + 'PPI: %d' % fr_rx]]) + + # Bit 3: Null frame indicator (inversed) + elif bitnum == 3: + data_type = 'data frame' if fr_rx else 'null frame' + self.putx([5, ['Null frame indicator: %s' % data_type, + 'NF: %d' % fr_rx, 'NF']]) + + # Bit 4: Sync frame indicator + # Must be 1 if startup frame indicator is 1. + elif bitnum == 4: + self.putx([6, ['Sync frame indicator: %d' % fr_rx, + 'Sync: %d' % fr_rx, 'Sync']]) + + # Bit 5: Startup frame indicator + elif bitnum == 5: + self.putx([7, ['Startup frame indicator: %d' % fr_rx, + 'Startup: %d' % fr_rx, 'Startup']]) + + # Remember start of ID (see below). + elif bitnum == 6: + self.ss_block = self.samplenum + + # Bits 6-16: Frame identifier (ID[10..0]) + # ID must NOT be 0. + elif bitnum == 16: + self.id = int(''.join(str(d) for d in self.bits[6:]), 2) + self.putb([8, ['Frame ID: %d' % self.id, 'ID: %d' % self.id, + '%d' % self.id]]) + + # Remember start of payload length (see below). + elif bitnum == 17: + self.ss_block = self.samplenum + + # Bits 17-23: Payload length (Length[7..0]) + # Payload length in header is the half of the real payload size. + elif bitnum == 23: + self.payload_length = int(''.join(str(d) for d in self.bits[17:]), 2) + self.putb([9, ['Payload length: %d' % self.payload_length, + 'Length: %d' % self.payload_length, + '%d' % self.payload_length]]) + + # Remember start of header CRC (see below). + elif bitnum == 24: + self.ss_block = self.samplenum + + # Bits 24-34: Header CRC (11-bit) (HCRC[11..0]) + # Calculation of header CRC is equal on both channels. + elif bitnum == 34: + bits = ''.join([str(b) for b in self.bits[4:24]]) + header_to_check = int(bits, 2) + expected_crc = self.crc(header_to_check, len(bits), + Const.cHCrcPolynomial, Const.cHCrcSize, Const.cHCrcInit) + self.header_crc = int(''.join(str(d) for d in self.bits[24:]), 2) + + crc_ok = self.header_crc == expected_crc + crc_ann = "OK" if crc_ok else "bad" + + self.putb([10, ['Header CRC: 0x%X (%s)' % (self.header_crc, crc_ann), + '0x%X (%s)' % (self.header_crc, crc_ann), + '0x%X' % self.header_crc]]) + + # Remember start of cycle code (see below). + elif bitnum == 35: + self.ss_block = self.samplenum + + # Bits 35-40: Cycle code (Cyc[6..0]) + # Cycle code. Must be between 0 and 63. + elif bitnum == 40: + self.cycle = int(''.join(str(d) for d in self.bits[35:]), 2) + self.putb([11, ['Cycle: %d' % self.cycle, 'Cyc: %d' % self.cycle, + '%d' % self.cycle]]) + self.last_databit = 41 + 2 * self.payload_length * 8 + + # Remember all databyte bits, except the very last one. + elif bitnum in range(41, self.last_databit): + self.ss_databytebits.append(self.samplenum) + + # Bits 41-X: Data field (0-254 bytes, depending on length) + # The bits within a data byte are transferred MSB-first. + elif bitnum == self.last_databit: + self.ss_databytebits.append(self.samplenum) # Last databyte bit. + for i in range(2 * self.payload_length): + x = 40 + (8 * i) + 1 + b = int(''.join(str(d) for d in self.bits[x:x + 8]), 2) + ss = self.ss_databytebits[i * 8] + es = self.ss_databytebits[((i + 1) * 8) - 1] + self.putg(ss, es, [12, ['Data byte %d: 0x%02x' % (i, b), + 'DB%d: 0x%02x' % (i, b), '%02X' % b]]) + self.ss_databytebits = [] + self.ss_block = self.samplenum # Remember start of trailer CRC. + + # Trailer CRC (24-bit) (CRC[11..0]) + # Initialization vector of channel A and B are different, so CRCs are + # different for same data. + elif bitnum == self.last_databit + 23: + bits = ''.join([str(b) for b in self.bits[1:-24]]) + frame_to_check = int(bits, 2) + iv = Const.cCrcInitA if self.options['channel_type'] == 'A' else Const.cCrcInitB + expected_crc = self.crc(frame_to_check, len(bits), + Const.cCrcPolynomial, Const.cCrcSize, iv=iv) + self.frame_crc = int(''.join(str(d) for d in self.bits[self.last_databit:]), 2) + + crc_ok = self.frame_crc == expected_crc + crc_ann = "OK" if crc_ok else "bad" + + self.putb([13, ['Frame CRC: 0x%X (%s)' % (self.frame_crc, crc_ann), + '0x%X (%s)' % (self.frame_crc, crc_ann), + '0x%X' % self.frame_crc]]) + self.end_of_frame = True + + # Remember start of frame end sequence (see below). + elif bitnum == self.last_databit + 24: + self.ss_block = self.samplenum + + # Frame end sequence, must be 1 followed by 0. + elif bitnum == self.last_databit + 25: + self.putb([14, ['Frame end sequence', 'FES']]) + + # Check for DTS + elif bitnum == self.last_databit + 26: + if not fr_rx: + self.dynamic_frame = True + else: + self.last_xmit_bit = bitnum + self.ss_block = self.samplenum + + # Remember start of channel idle delimiter (see below). + elif bitnum == self.last_xmit_bit: + self.ss_block = self.samplenum + + # Channel idle limiter (CID[11..0]) + elif bitnum == self.last_xmit_bit + Const.cChannelIdleDelimiter - 1: + self.putb([18, ['Channel idle delimiter', 'CID']]) + self.reset_variables() + + # DTS if dynamic frame + elif bitnum > self.last_databit + 27: + if self.dynamic_frame: + if fr_rx: + if self.last_xmit_bit == 999: + self.putb([19, ['Dynamic trailing sequence', 'DTS']]) + self.last_xmit_bit = bitnum + 1 + self.ss_block = self.samplenum + + self.curbit += 1 + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + + while True: + # State machine. + if self.state == 'IDLE': + # Wait for a dominant state (logic 0) on the bus. + (fr_rx,) = self.wait({0: 'l'}) + self.tss_start = self.samplenum + (fr_rx,) = self.wait({0: 'h'}) + self.tss_end = self.samplenum + self.dom_edge_seen(force = True) + self.state = 'GET BITS' + elif self.state == 'GET BITS': + # Wait until we're in the correct bit/sampling position. + pos = self.get_sample_point(self.curbit) + (fr_rx,) = self.wait([{'skip': pos - self.samplenum}, {0: 'f'}]) + if self.matched[1]: + self.dom_edge_seen() + if self.matched[0]: + self.handle_bit(fr_rx) diff --git a/libsigrokdecode4DSL/decoders/fsi/__init__.py b/libsigrokdecode4DSL/decoders/fsi/__init__.py new file mode 100644 index 00000000..8d589923 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/fsi/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 Raptor Engineering, LLC +## +## This program is free software: you can redistribute it and/or modify +## it under the terms of the GNU Affero 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 Affero General Public License for more details. +## +## You should have received a copy of the GNU Affero General Public License +## along with this program. If not, see . +## + +''' +FSI is a low level serial protocol used by various devices on OpenPOWER +systems such as the Raptor Talos II and Blackbird. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/fsi/pd.py b/libsigrokdecode4DSL/decoders/fsi/pd.py new file mode 100644 index 00000000..4b6b69f6 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/fsi/pd.py @@ -0,0 +1,574 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 Raptor Engineering, LLC +## +## This program is free software: you can redistribute it and/or modify +## it under the terms of the GNU Affero 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 Affero General Public License for more details. +## +## You should have received a copy of the GNU Affero General Public License +## along with this program. If not, see . +## + +import sigrokdecode as srd + +# ... +fields = { + # START field (indicates the start of a transaction) + 'START': { + 0b1: 'Start of FSI cycle', + }, +} + +class Decoder(srd.Decoder): + api_version = 3 + id = 'fsi' + name = 'FSI' + longname = 'Flexible Service Interface' + desc = 'Protocol for FSI devices on Raptor OpenPOWER systems.' + license = 'agplv3' + inputs = ['logic'] + outputs = [] + tags = ['PC'] + channels = ( + {'id': 'data', 'name': 'DATA', 'desc': 'Frame'}, + {'id': 'clock', 'name': 'CLOCK', 'desc': 'Clock'}, + ) + annotations = ( + ('warnings', 'Warnings'), + ('start', 'Start'), + ('cycle-type', 'Cycle type'), + ('direction', 'Direction'), + ('addr', 'Address'), + ('data', 'Data'), + ('commands', 'Commands'), + ('crc', 'CRC'), + ('turn-around', 'TAR'), + ) + annotation_rows = ( + ('data', 'Data', (1, 2, 3, 4, 5, 6, 7, 8,)), + ('warnings', 'Warnings', (0,)), + ) + + def __init__(self): + self.tar_cycles = 3 + self.reset() + + def reset(self): + self.state = 'IDLE' + self.break_start_sample_number = 0 + self.break_counter = 0 + self.samplenum = 0 + self.samplenum_prev = 0 + self.fsi_data_prev = 0 + self.fsi_data_break_prev = 0 + self.crc_internal = 0 + self.response_received = 0 + self.crc_calculating = 0 + self.busy_seq_count = 0 + self.valid_response = 0 + self.prev_address = {} + self.prev_address_valid = {0: False, 1: False, 2: False, 3: False} + self.ss_block = None + self.es_block = None + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putb(self, data): + self.put(self.ss_block, self.es_block, self.out_ann, data) + + def decode(self): + while True: + # FSI is clocked out on the falling edge and latched in on the rising edge of the clock...according to the specification. + # That said, the specification is not clear on what this actually means (and it doesn't follow industry convention). + # Real IBM POWER9 hardware is verified to work in the following mode: + # FSI data being sent to the master is latched by the master logic at the falling edge of the FSI clock + # FSI data being from to the master is strobed by the master logic at the falling edge of the FSI clock + # FSI data being sent to the slave is latched by the slave logic at the rising edge of the FSI clock + # FSI data being from to the slave is strobed by the slave logic at the rising edge of the FSI clock + # + # The above means that we have to be able to make a reasonable guess as to who is transmitting (the master or the slave) + # in order to know which edge to sample on + + # Wait for either clock edge + (data, clk) = self.wait({1: 'e'}) + + # FSI data is electrically inverted + fsi_data = not data + fsi_clk = clk + current_sample_number = self.samplenum + + # Detect BREAK commands + # Note these can only be sent by the master, so sample on the rising clock edge only + if (fsi_clk): + if (self.fsi_data_break_prev == 1): + self.break_counter = self.break_counter + 1 + if (self.break_counter == 256): + self.ss_block = self.break_start_sample_number + self.es_block = current_sample_number + self.putb([6, ['BREAK']]) + self.state = 'BREAK_TAR_QUEUED' + self.busy_seq_count = 0 + self.valid_response = 0 + self.prev_address = {} + self.prev_address_valid = {0: False, 1: False, 2: False, 3: False} + self.ss_block = current_sample_number + else: + if (self.break_counter > 256): + self.es_block = current_sample_number + self.putb([0, ['BREAK asserted in excess of specification cycles']]) + self.break_start_sample_number = current_sample_number + self.break_counter = 0 + self.fsi_data_break_prev = fsi_data + + if ((self.state == 'TAR') or (self.state == 'RX_SLAVE_ID') or (self.state == 'RESPONSE') or (self.state == 'RX_DATA') + or (self.state == 'RX_IPOLL_INTERRUPT_FIELD') or (self.state == 'RX_IPOLL_DMA_CONTROL_FIELD') or (self.state == 'RX_IPOLL_DMA_CONTROL_FIELD') + or ((self.state == 'CRC') and (self.valid_response))): + # Slave is / should be transmitting, sample on falling clock edge only + if (fsi_clk): + continue + else: + # Master is / should be transmitting, sample on rising clock edge only + if (not fsi_clk): + continue + + # Transfer state machine + if (self.state == 'IDLE'): + self.crc_internal = 0 + self.response_received = 0 + if (self.fsi_data_prev == 1): + self.tx_slave_id = 0 + self.data_count = 2 + self.ss_block = self.samplenum_prev + self.es_block = current_sample_number + self.putb([1, ['START']]) + self.ss_block = current_sample_number + self.crc_calculating = 1 + self.state = 'TX_SLAVE_ID' + + elif (self.state == 'TX_SLAVE_ID'): + self.crc_calculating = 1 + if (self.data_count > 0): + self.tx_slave_id = (self.tx_slave_id >> 1) | (self.fsi_data_prev << 1) + self.data_count = self.data_count - 1 + if (self.data_count == 0): + self.es_block = current_sample_number + self.putb([5, ['Slave ID: 0x%01x' % self.tx_slave_id]]) + self.ss_block = current_sample_number + self.command_count = 0 + self.command_code = 0 + self.command = None + self.valid_command = False + self.state = 'COMMAND' + + elif (self.state == 'COMMAND'): + self.crc_calculating = 1 + self.command_code = (self.command_code << 1) | self.fsi_data_prev + self.command_count = self.command_count + 1 + if ((self.command_count == 3) and (self.command_code == 0b100)): + self.command = 'ABS_ADR' + self.valid_command = True + elif ((self.command_count == 3) and (self.command_code == 0b101)): + self.command = 'REL_ADR' + self.valid_command = True + elif ((self.command_count == 2) and (self.command_code == 0b11)): + self.command = 'SAME_ADR' + self.valid_command = True + elif ((self.command_count == 3) and (self.command_code == 0b010)): + self.command = 'D_POLL' + self.valid_command = True + elif ((self.command_count == 3) and (self.command_code == 0b011)): + self.command = 'E_POLL' + self.valid_command = True + elif ((self.command_count == 3) and (self.command_code == 0b001)): + self.command = 'I_POLL' + self.valid_command = True + if ((self.command_count > 7) or (self.valid_command == True)): + if (self.command_count == 8): + self.es_block = current_sample_number + self.putb([6, ['Invalid command code: 0x%02x/%d' % (self.command_code, self.command_count)]]) + self.putb([0, ['%s' % 'Invalid command code']]) + self.ss_block = current_sample_number + self.state = 'IDLE' + else: + self.es_block = current_sample_number + self.putb([6, ['Command: %s (0x%02x/%d)' % (self.command, self.command_code, self.command_count)]]) + self.ss_block = current_sample_number + if (self.command == 'ABS_ADR'): + self.address_length = 21 + self.address_count = 0 + self.address = 0 + self.state = 'DIRECTION' + elif (self.command == 'REL_ADR'): + self.address_length = 8 + self.address_count = 0 + self.address = 0 + self.state = 'DIRECTION' + elif (self.command == 'SAME_ADR'): + self.address_length = 2 + self.address_count = 0 + self.address = 0 + self.state = 'DIRECTION' + elif (self.command == 'D_POLL'): + self.crc = 0 + self.crc_count = 0 + self.state = 'CRC' + elif (self.command == 'E_POLL'): + self.crc = 0 + self.crc_count = 0 + self.state = 'CRC' + elif (self.command == 'I_POLL'): + self.crc = 0 + self.crc_count = 0 + self.state = 'CRC' + else: + self.state = 'IDLE' + + elif (self.state == 'DIRECTION'): + self.crc_calculating = 1 + self.direction = self.fsi_data_prev + self.es_block = current_sample_number + if (self.direction == 1): + self.putb([3, ['Direction: %s' % 'Read']]) + else: + self.putb([3, ['Direction: %s' % 'Write']]) + self.ss_block = current_sample_number + if (self.command == 'REL_ADR'): + self.state = 'REL_ADDRESS_SIGN' + else: + self.state = 'ADDRESS' + + elif (self.state == 'REL_ADDRESS_SIGN'): + self.crc_calculating = 1 + self.relative_address_negative = self.fsi_data_prev + self.es_block = current_sample_number + if (self.relative_address_negative == 1): + self.putb([5, ['Relative address sign: %s' % '(-)']]) + else: + self.putb([5, ['Relative address sign: %s' % '(+)']]) + self.ss_block = current_sample_number + self.state = 'ADDRESS' + + elif (self.state == 'ADDRESS'): + self.crc_calculating = 1 + self.address = (self.address << 1) | self.fsi_data_prev + self.address_count = self.address_count + 1 + if (self.address_count >= self.address_length): + self.address_raw = self.address + if (self.prev_address_valid[self.tx_slave_id]): + if (self.command == 'SAME_ADR'): + self.address = (self.prev_address[self.tx_slave_id] & ~0b11) | (self.address_raw & 0b11) + elif (self.command == 'REL_ADR'): + if (self.relative_address_negative): + self.address = self.prev_address[self.tx_slave_id] - (0x100 - self.address_raw) + else: + self.address = self.prev_address[self.tx_slave_id] + self.address_raw + self.es_block = current_sample_number + if (((self.command == 'SAME_ADR') or (self.command == 'REL_ADR'))): + self.putb([5, ['Address: 0x%06x (0x%03x)' % (self.address, self.address_raw)]]) + if (not self.prev_address_valid[self.tx_slave_id]): + self.putb([0, ['%s' % 'Base address for relative address not captured']]) + else: + self.putb([5, ['Address: 0x%06x' % self.address]]) + self.ss_block = current_sample_number + self.state = 'DATA_SIZE' + + elif (self.state == 'DATA_SIZE'): + self.crc_calculating = 1 + if (self.direction and ((self.address_raw & 3) == 3) and self.fsi_data_prev): + # OpenFSI suffers from an unfortunate conflict between the SAME_ADR command + # and the TERM command. Both start with 2'b11 and since both are variable + # length it is impossible to determine if a TERM command was sent until this + # point in the receiver process! + # + # Set correct command code for further processing + self.command_code = 0b111111 + self.command_count = 6 + self.command = 'TERM' + self.es_block = current_sample_number + self.putb([6, ['Command: %s (0x%02x/%d)' % (self.command, self.command_code, self.command_count)]]) + self.ss_block = current_sample_number + self.direction = 0 + self.busy_seq_count = 0 + self.crc = 0 + self.crc_count = 0 + self.state = 'CRC' + else: + if (self.fsi_data_prev == 0): + self.data_size = 'BYTE' + else: + if ((self.address_raw & 3) == 1): + self.data_size = 'WORD' + # Force lowest address bits to specification-mandated values if required + self.address = (self.address & ~3) | 1 + elif ((self.address_raw & 1) == 0): + self.data_size = 'HALF_WORD' + # Force lowest address bits to specification-mandated values if required + self.address = self.address & ~1 + else: + self.data_size = 'UNKNOWN' + self.es_block = current_sample_number + if (self.data_size == 'UNKNOWN'): + self.putb([0, ['Data Size: %s' % 'UNKNOWN']]) + self.state = 'IDLE' + else: + self.putb([3, ['Data Size: %s' % self.data_size]]) + if (self.direction == 1): + self.crc = 0 + self.crc_count = 0 + self.state = 'CRC' + else: + self.data = 0 + self.data_count = 0 + if (self.data_size == 'BYTE'): + self.data_length = 8 + elif (self.data_size == 'HALF_WORD'): + self.data_length = 16 + elif (self.data_size == 'WORD'): + self.data_length = 32 + else: + self.data_size = None + self.state = 'TX_DATA' + self.ss_block = current_sample_number + + elif (self.state == 'TX_DATA'): + self.crc_calculating = 1 + self.data = (self.data << 1) | self.fsi_data_prev + self.data_count = self.data_count + 1 + if (self.data_count >= self.data_length): + self.es_block = current_sample_number + if (self.data_size == 'BYTE'): + self.putb([5, ['Data: 0x%02x' % self.data]]) + elif (self.data_size == 'HALF_WORD'): + self.putb([5, ['Data: 0x%04x' % self.data]]) + else: + self.putb([5, ['Data: 0x%08x' % self.data]]) + self.ss_block = current_sample_number + self.crc = 0 + self.crc_count = 0 + self.state = 'CRC' + + elif (self.state == 'CRC'): + if (self.crc_count == 0): + self.computed_crc_tx_end = self.crc_internal + self.crc_calculating = 1 + self.crc = (self.crc << 1) | self.fsi_data_prev + self.crc_count = self.crc_count + 1 + if (self.crc_count >= 4): + self.es_block = current_sample_number + if (self.crc == self.computed_crc_tx_end): + self.putb([7, ['CRC: 0x%01x (GOOD)' % self.crc]]) + if (self.response_received): + if (((self.command == 'ABS_ADR') or (self.command == 'REL_ADR') or (self.command == 'SAME_ADR')) + and ((self.response == 'ACK_D') or (self.response == 'ACK'))): + self.prev_address[self.tx_slave_id] = self.address + self.prev_address_valid[self.tx_slave_id] = True + else: + self.putb([7, ['CRC: 0x%01x (BAD)' % self.crc]]) + self.putb([0, ['%s' % 'Bad CRC']]) + self.ss_block = current_sample_number + self.tar_timer = 0 + self.state = 'TAR' + self.timeout_counter = 0 + + elif (self.state == 'BREAK_TAR_QUEUED'): + # Special case, since break operates outside of the main state machine + # This state is a safe entry point into the main state machine + self.tar_timer = 0 + self.state = 'BREAK_TAR' + + elif (self.state == 'BREAK_TAR'): + self.tar_timer = self.tar_timer + 1 + if (self.tar_timer > self.tar_cycles): + self.crc_calculating = 0 + self.crc_internal = 0 + self.es_block = current_sample_number + self.putb([8, ['%s' % 'TAR']]) + self.ss_block = current_sample_number + self.state = 'IDLE' + + elif (self.state == 'TAR'): + self.crc_calculating = 0 + self.crc_internal = 0 + self.tar_timer = self.tar_timer + 1 + if (self.tar_timer > self.tar_cycles): + if (self.response_received == 1): + self.response_received = 0 + if (self.rx_slave_id == self.tx_slave_id): + if (self.response == 'BUSY'): + self.busy_seq_count = self.busy_seq_count + 1 + else: + self.busy_seq_count = 0 + # Sequence complete + self.state = 'IDLE' + if (self.timeout_counter == 0): + self.es_block = self.samplenum_prev + self.putb([8, ['%s' % 'TAR']]) + self.ss_block = current_sample_number + if (self.fsi_data_prev == 1): + self.crc_calculating = 1 + self.rx_slave_id = 0 + self.data_count = 2 + if (self.state == 'IDLE'): + # Already processed response message, was going to IDLE state + self.state = 'TX_SLAVE_ID' + else: + self.state = 'RX_SLAVE_ID' + self.ss_block = self.samplenum_prev + self.es_block = current_sample_number + self.putb([1, ['START']]) + self.ss_block = current_sample_number + else: + self.timeout_counter = self.timeout_counter + 1 + if (self.timeout_counter >= 256): + self.es_block = current_sample_number + self.putb([8, ['%s' % 'Response timeout']]) + self.putb([0, ['%s' % 'Response timeout']]) + self.state = 'IDLE' + + elif (self.state == 'RX_SLAVE_ID'): + self.crc_calculating = 1 + self.response_received = 1 + if (self.data_count > 0): + self.rx_slave_id = (self.rx_slave_id >> 1) | (self.fsi_data_prev << 1) + self.data_count = self.data_count - 1 + if (self.data_count == 0): + self.es_block = current_sample_number + self.putb([5, ['Slave ID: 0x%01x' % self.rx_slave_id]]) + if (self.rx_slave_id != self.tx_slave_id): + self.putb([0, ['%s' % 'Slave ID does not match active transaction']]) + self.ss_block = current_sample_number + self.response_count = 0 + self.response_code = 0 + self.response = None + self.valid_response = False + self.state = 'RESPONSE' + + elif (self.state == 'RESPONSE'): + self.crc_calculating = 1 + self.response_code = (self.response_code << 1) | self.fsi_data_prev + self.response_count = self.response_count + 1 + if ((self.command == 'I_POLL') and (self.rx_slave_id == self.tx_slave_id) and (self.response_count == 1) and (self.response_code == 0b0)): + self.response = 'I_POLL_RSP' + self.valid_response = True + elif ((self.response_count == 2) and (self.response_code == 0b00)): + if (self.direction == 1): + self.response = 'ACK_D' + else: + self.response = 'ACK' + self.valid_response = True + elif ((self.response_count == 2) and (self.response_code == 0b01)): + self.response = 'BUSY' + self.valid_response = True + elif ((self.response_count == 2) and (self.response_code == 0b10)): + self.response = 'ERR_A' + self.valid_response = True + elif ((self.response_count == 2) and (self.response_code == 0b11)): + self.response = 'ERR_C' + self.valid_response = True + if ((self.response_count > 2) or (self.valid_response == True)): + if (self.response_count == 8): + self.es_block = current_sample_number + self.putb([6, ['Invalid response code: 0x%02x/%d' % (self.response_code, self.response_count)]]) + self.putb([0, ['%s' % 'Invalid response code']]) + self.ss_block = current_sample_number + self.state = 'IDLE' + else: + self.es_block = current_sample_number + self.putb([6, ['Response: %s (0x%02x/%d)' % (self.response, self.response_code, self.response_count)]]) + self.ss_block = current_sample_number + if (self.response == 'ACK_D'): + self.data = 0 + self.data_count = 0 + if (self.data_size == 'BYTE'): + self.data_length = 8 + elif (self.data_size == 'HALF_WORD'): + self.data_length = 16 + elif (self.data_size == 'WORD'): + self.data_length = 32 + else: + self.data_size = None + #self.state = 'DIRECTION' + self.state = 'RX_DATA' + elif (self.response == 'ACK'): + self.crc = 0 + self.crc_count = 0 + self.state = 'CRC' + elif (self.response == 'BUSY'): + self.crc = 0 + self.crc_count = 0 + self.state = 'CRC' + elif (self.response == 'ERR_A'): + self.crc = 0 + self.crc_count = 0 + self.state = 'CRC' + elif (self.response == 'ERR_C'): + self.crc = 0 + self.crc_count = 0 + self.state = 'CRC' + elif (self.response == 'I_POLL_RSP'): + self.data = 0 + self.data_count = 0 + self.data_length = 2 + self.state = 'RX_IPOLL_INTERRUPT_FIELD' + else: + self.state = 'IDLE' + + elif (self.state == 'RX_DATA'): + self.crc_calculating = 1 + self.data = (self.data << 1) | self.fsi_data_prev + self.data_count = self.data_count + 1 + if (self.data_count >= self.data_length): + self.es_block = current_sample_number + self.putb([5, ['Data: 0x%08x' % self.data]]) + self.ss_block = current_sample_number + self.crc = 0 + self.crc_count = 0 + self.state = 'CRC' + + elif (self.state == 'RX_IPOLL_INTERRUPT_FIELD'): + self.crc_calculating = 1 + self.data = (self.data << 1) | self.fsi_data_prev + self.data_count = self.data_count + 1 + if (self.data_count >= self.data_length): + self.es_block = current_sample_number + self.putb([5, ['Interrupt Field: 0x%01x' % self.data]]) + self.ss_block = current_sample_number + self.data = 0 + self.data_count = 0 + self.data_length = 3 + self.state = 'RX_IPOLL_DMA_CONTROL_FIELD' + + elif (self.state == 'RX_IPOLL_DMA_CONTROL_FIELD'): + self.crc_calculating = 1 + self.data = (self.data << 1) | self.fsi_data_prev + self.data_count = self.data_count + 1 + if (self.data_count >= self.data_length): + self.es_block = current_sample_number + self.putb([5, ['DMA Control Field: 0x%01x' % self.data]]) + self.ss_block = current_sample_number + self.crc = 0 + self.crc_count = 0 + self.state = 'CRC' + + # CRC calculation + # Implement Galios-type LFSR for polynomial 0x7 (MSB first) + crc_prev = self.crc_internal + if (self.crc_calculating): + crc_feedback = (((crc_prev >> 3) & 1) ^ self.fsi_data_prev) & 1 + if (self.crc_calculating): + self.crc_internal = (self.crc_internal & ~(1 << 0)) | ((crc_feedback & 1) << 0) + self.crc_internal = (self.crc_internal & ~(1 << 1)) | ((((crc_prev & 1) ^ crc_feedback) & 1) << 1) + self.crc_internal = (self.crc_internal & ~(1 << 2)) | (((((crc_prev >> 1) & 1) ^ crc_feedback) & 1) << 2) + self.crc_internal = (self.crc_internal & ~(1 << 3)) | ((((crc_prev >> 2) & 1) & 1) << 3) + + self.fsi_data_prev = fsi_data + self.samplenum_prev = current_sample_number diff --git a/libsigrokdecode4DSL/decoders/gpib/__init__.py b/libsigrokdecode4DSL/decoders/gpib/__init__.py new file mode 100644 index 00000000..3b546ef1 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/gpib/__init__.py @@ -0,0 +1,24 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2016 Rudolf Reuter +## +## 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, see . +## + +''' +This protocol decoder can decode the GPIB (IEEE-488) protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/gpib/pd.py b/libsigrokdecode4DSL/decoders/gpib/pd.py new file mode 100644 index 00000000..f0c963c2 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/gpib/pd.py @@ -0,0 +1,182 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2016 Rudolf Reuter +## Copyright (C) 2019 DreamSourceLab +## +## 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, see . +## + +import sigrokdecode as srd + +class Decoder(srd.Decoder): + api_version = 3 + id = 'gpib' + name = 'GPIB' + longname = 'General Purpose Interface Bus' + desc = 'IEEE-488 General Purpose Interface Bus (GPIB / HPIB).' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['PC'] + channels = ( + {'id': 'dio1' , 'name': 'DIO1', 'desc': 'Data I/O bit 1'}, + {'id': 'dio2' , 'name': 'DIO2', 'desc': 'Data I/O bit 2'}, + {'id': 'dio3' , 'name': 'DIO3', 'desc': 'Data I/O bit 3'}, + {'id': 'dio4' , 'name': 'DIO4', 'desc': 'Data I/O bit 4'}, + {'id': 'dio5' , 'name': 'DIO5', 'desc': 'Data I/O bit 5'}, + {'id': 'dio6' , 'name': 'DIO6', 'desc': 'Data I/O bit 6'}, + {'id': 'dio7' , 'name': 'DIO7', 'desc': 'Data I/O bit 7'}, + {'id': 'dio8' , 'name': 'DIO8', 'desc': 'Data I/O bit 8'}, + {'id': 'eoi', 'name': 'EOI', 'desc': 'End or identify'}, + {'id': 'dav', 'name': 'DAV', 'desc': 'Data valid'}, + {'id': 'nrfd', 'name': 'NRFD', 'desc': 'Not ready for data'}, + {'id': 'ndac', 'name': 'NDAC', 'desc': 'Not data accepted'}, + {'id': 'ifc', 'name': 'IFC', 'desc': 'Interface clear'}, + {'id': 'srq', 'name': 'SRQ', 'desc': 'Service request'}, + {'id': 'atn', 'name': 'ATN', 'desc': 'Attention'}, + {'id': 'ren', 'name': 'REN', 'desc': 'Remote enable'}, + ) + options = ( + {'id': 'sample_total', 'desc': 'Total number of samples', 'default': 0}, + ) + annotations = ( + ('items', 'Items'), + ('gpib', 'DAT/CMD'), + ('eoi', 'EOI'), + ) + annotation_rows = ( + ('bytes', 'Bytes', (0,)), + ('gpib', 'DAT/CMD', (1,)), + ('eoi', 'EOI', (2,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.items = [] + self.itemcount = 0 + self.saved_item = None + self.saved_ATN = False + self.saved_EOI = False + self.samplenum = 0 + self.ss_item = self.es_item = None + self.first = True + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putb(self, data): + self.put(self.ss_item, self.es_item, self.out_ann, data) + + def handle_bits(self, datapins): + dbyte = 0x20 + dATN = False + item2 = False + dEOI = False + item3 = False + # If this is the first item in a word, save its sample number. + if self.itemcount == 0: + self.ss_word = self.samplenum + + # Get the bits for this item. + item = 0 + for i in range(8): + item |= datapins[i] << i + + item = item ^ 0xff # Invert data byte. + self.items.append(item) + self.itemcount += 1 + + if datapins[14] == 0: + item2 = True + if datapins[8] == 0: + item3 = True + + if self.first: + # Save the start sample and item for later (no output yet). + self.ss_item = self.samplenum + self.first = False + self.saved_item = item + self.saved_ATN = item2 + self.saved_EOI = item3 + else: + # Output the saved item. + dbyte = self.saved_item + dATN = self.saved_ATN + dEOI = self.saved_EOI + self.es_item = self.samplenum + self.putb([0, ['%02X' % self.saved_item]]) + + # Encode item byte to GPIB convention. + self.strgpib = ' ' + if dATN: # ATN, decode commands. + if dbyte == 0x01: self.strgpib = 'GTL' + if dbyte == 0x04: self.strgpib = 'SDC' + if dbyte == 0x05: self.strgpib = 'PPC' + if dbyte == 0x08: self.strgpib = 'GET' + if dbyte == 0x09: self.strgpib = 'TCT' + if dbyte == 0x11: self.strgpib = 'LLO' + if dbyte == 0x14: self.strgpib = 'DCL' + if dbyte == 0x15: self.strgpib = 'PPU' + if dbyte == 0x18: self.strgpib = 'SPE' + if dbyte == 0x19: self.strgpib = 'SPD' + if dbyte == 0x3f: self.strgpib = 'UNL' + if dbyte == 0x5f: self.strgpib = 'UNT' + if dbyte > 0x1f and dbyte < 0x3f: # Address Listener. + self.strgpib = 'L' + chr(dbyte + 0x10) + if dbyte > 0x3f and dbyte < 0x5f: # Address Talker + self.strgpib = 'T' + chr(dbyte - 0x10) + else: + if dbyte > 0x1f and dbyte < 0x7f: + self.strgpib = chr(dbyte) + if dbyte == 0x0a: + self.strgpib = 'LF' + if dbyte == 0x0d: + self.strgpib = 'CR' + + self.putb([1, [self.strgpib]]) + self.strEOI = ' ' + if dEOI: + self.strEOI = 'EOI' + self.putb([2, [self.strEOI]]) + + self.ss_item = self.samplenum + self.saved_item = item + self.saved_ATN = item2 + self.saved_EOI = item3 + + if self.itemcount < 16: + return + + self.itemcount, self.items = 0, [] + + def decode(self): + + # Inspect samples at falling edge of DAV. But make sure to also + # start inspection when the capture happens to start with low + # DAV level. Optionally enforce processing when a user specified + # sample number was reached. + waitcond = [{9: 'l'}] + lsn = self.options['sample_total'] + if lsn: + waitcond.append({'skip': lsn}) + while True: + if lsn: + waitcond[1]['skip'] = lsn - self.samplenum - 1 + (d1, d2, d3, d4, d5, d6, d7, d8, eoi, dav, nrfd, ndac, ifc, srq, atn, ren) = self.wait(waitcond) + pins = (d1, d2, d3, d4, d5, d6, d7, d8, eoi, dav, nrfd, ndac, ifc, srq, atn, ren) + self.handle_bits(pins) + waitcond[0][9] = 'f' diff --git a/libsigrokdecode4DSL/decoders/graycode/__init__.py b/libsigrokdecode4DSL/decoders/graycode/__init__.py new file mode 100644 index 00000000..90ef824c --- /dev/null +++ b/libsigrokdecode4DSL/decoders/graycode/__init__.py @@ -0,0 +1,24 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2017 Christoph Rackwitz +## +## 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, see . +## + +''' +Gray code and rotary encoder protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/graycode/pd.py b/libsigrokdecode4DSL/decoders/graycode/pd.py new file mode 100644 index 00000000..9303c33a --- /dev/null +++ b/libsigrokdecode4DSL/decoders/graycode/pd.py @@ -0,0 +1,200 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2017 Christoph Rackwitz +## Copyright (C) 2019 DreamSourceLab +## +## 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, see . +## + +import math +import sigrokdecode as srd +from collections import deque +from common.srdhelper import bitpack, bitunpack + +def gray_encode(plain): + return plain & (plain >> 1) + +def gray_decode(gray): + temp = gray + temp ^= (temp >> 8) + temp ^= (temp >> 4) + temp ^= (temp >> 2) + temp ^= (temp >> 1) + return temp + +def prefix_fmt(value, emin=None): + sgn = (value > 0) - (value < 0) + value = abs(value) + p = math.log10(value) if value else 0 + value = sgn * math.floor(value * 10**int(3 - p)) * 10**-int(3 - p) + e = p // 3 * 3 + if emin is not None and e < emin: + e = emin + value *= 10**-e + p -= e + decimals = 2 - int(p) + prefixes = {-9: 'n', -6: 'µ', -3: 'm', 0: '', 3: 'k', 6: 'M', 9: 'G'} + return '{0:.{1}f} {2}'.format(value, decimals, prefixes[e]) + +class ChannelMapError(Exception): + pass + +class Value: + def __init__(self, onchange): + self.onchange = onchange + self.timestamp = None + self.value = None + + def get(self): + return self.value + + def set(self, timestamp, newval): + if newval != self.value: + if self.value is not None: + self.onchange(self.timestamp, self.value, timestamp, newval) + + self.value = newval + self.timestamp = timestamp + elif False: + if self.value is not None: + self.onchange(self.timestamp, self.value, timestamp, newval) + +MAX_CHANNELS = 8 # 10 channels causes some weird problems... + +class Decoder(srd.Decoder): + api_version = 3 + id = 'graycode' + name = 'Gray code' + longname = 'Gray code and rotary encoder' + desc = 'Accumulate rotary encoder increments, provide statistics.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Encoding'] + optional_channels = tuple( + {'id': 'd{}'.format(i), 'name': 'D{}'.format(i), 'desc': 'Data line {}'.format(i)} + for i in range(MAX_CHANNELS) + ) + options = ( + {'id': 'edges', 'desc': 'Edges per rotation', 'default': 0}, + {'id': 'avg_period', 'desc': 'Averaging period', 'default': 10}, + ) + annotations = ( + ('phase', 'Phase'), + ('increment', 'Increment'), + ('count', 'Count'), + ('turns', 'Turns'), + ('interval', 'Interval'), + ('average', 'Average'), + ('rpm', 'Rate'), + ) + annotation_rows = tuple((u, v, (i,)) for i, (u, v) in enumerate(annotations)) + + def __init__(self): + self.reset() + + def reset(self): + self.num_channels = 0 + self.samplerate = None + self.last_n = deque() + + self.phase = Value(self.on_phase) + self.increment = Value(self.on_increment) + self.count = Value(self.on_count) + self.turns = Value(self.on_turns) + + def on_phase(self, told, vold, tnew, vnew): + self.put(told, tnew, self.out_ann, [0, ['{}'.format(vold)]]) + + def on_increment(self, told, vold, tnew, vnew): + if vold == 0: + message = '0' + elif abs(vold) == self.ENCODER_STEPS // 2: + message = '±π' + else: + message = '{:+d}'.format(vold) + self.put(told, tnew, self.out_ann, [1, [message]]) + + def on_count(self, told, vold, tnew, vnew): + self.put(told, tnew, self.out_ann, [2, ['{}'.format(vold)]]) + + def on_turns(self, told, vold, tnew, vnew): + self.put(told, tnew, self.out_ann, [3, ['{:+d}'.format(vold)]]) + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def decode(self): + chmask = [self.has_channel(i) for i in range(MAX_CHANNELS)] + self.num_channels = sum(chmask) + if chmask != [i < self.num_channels for i in range(MAX_CHANNELS)]: + raise ChannelMapError('Assigned channels need to be contiguous') + + self.ENCODER_STEPS = 1 << self.num_channels + + (d0, d1, d2, d3, d4, d5, d6, d7) = self.wait() + startbits = (d0, d1, d2, d3, d4, d5, d6, d7) + curtime = self.samplenum + + self.turns.set(self.samplenum, 0) + self.count.set(self.samplenum, 0) + self.phase.set(self.samplenum, gray_decode(bitpack(startbits[:self.num_channels]))) + + while True: + prevtime = curtime + (d0, d1, d2, d3, d4, d5, d6, d7) = self.wait([{i: 'e'} for i in range(self.num_channels)]) + bits = (d0, d1, d2, d3, d4, d5, d6, d7) + curtime = self.samplenum + + oldcount = self.count.get() + oldphase = self.phase.get() + + newphase = gray_decode(bitpack(bits[:self.num_channels])) + self.phase.set(self.samplenum, newphase) + + phasedelta_raw = (newphase - oldphase + (self.ENCODER_STEPS // 2 - 1)) % self.ENCODER_STEPS - (self.ENCODER_STEPS // 2 - 1) + phasedelta = phasedelta_raw + self.increment.set(self.samplenum, phasedelta) + if abs(phasedelta) == self.ENCODER_STEPS // 2: + phasedelta = 0 + + self.count.set(self.samplenum, self.count.get() + phasedelta) + + if self.options['edges']: + self.turns.set(self.samplenum, self.count.get() // self.options['edges']) + + if self.samplerate: + period = (curtime - prevtime) / self.samplerate + freq = abs(phasedelta_raw) / period + + self.put(prevtime, curtime, self.out_ann, [4, [ + '{}s, {}Hz'.format(prefix_fmt(period), prefix_fmt(freq))]]) + + if self.options['avg_period']: + self.last_n.append((abs(phasedelta_raw), period)) + if len(self.last_n) > self.options['avg_period']: + self.last_n.popleft() + + avg_period = sum(v for u, v in self.last_n) / (sum(u for u, v in self.last_n) or 1) + self.put(prevtime, curtime, self.out_ann, [5, [ + '{}s, {}Hz'.format(prefix_fmt(avg_period), + prefix_fmt(1 / avg_period))]]) + + if self.options['edges']: + self.put(prevtime, curtime, self.out_ann, [6, ['{}rpm'.format(prefix_fmt(60 * freq / self.options['edges'], emin=0))]]) diff --git a/libsigrokdecode4DSL/decoders/guess_bitrate/__init__.py b/libsigrokdecode4DSL/decoders/guess_bitrate/__init__.py new file mode 100644 index 00000000..a02bf183 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/guess_bitrate/__init__.py @@ -0,0 +1,40 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2013 Uwe Hermann +## +## 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, see . +## + +''' +This protocol decoder tries to guess the bitrate / baudrate of the +communication on the specified channel. + +Typically this will be used to guess / detect the baudrate used in a UART +communication snippet, but it could also be used to guess bitrates of certain +other protocols or buses. + +It should be noted that this is nothing more than a simple guess / heuristic, +and that there are various cases in practice where the detection of the +bitrate or baudrate will not necessarily have the expected result. + +The precision of the estimated bitrate / baudrate will also depend on the +samplerate used to sample the respective channel. For good results it is +recommended to use a logic analyzer samplerate that is much higher than +the expected bitrate/baudrate that might be used on the channel. + +The last annotation emitted by the decoder will be the best bitrate guess. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/guess_bitrate/pd.py b/libsigrokdecode4DSL/decoders/guess_bitrate/pd.py new file mode 100644 index 00000000..462fa8aa --- /dev/null +++ b/libsigrokdecode4DSL/decoders/guess_bitrate/pd.py @@ -0,0 +1,79 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2013-2016 Uwe Hermann +## +## 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, see . +## + +import sigrokdecode as srd + +class SamplerateError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = 'guess_bitrate' + name = 'Guess bitrate' + longname = 'Guess bitrate/baudrate' + desc = 'Guess the bitrate/baudrate of a UART (or other) protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Clock/timing', 'Util'] + channels = ( + {'id': 'data', 'name': 'Data', 'desc': 'Data line'}, + ) + annotations = ( + ('bitrate', 'Bitrate / baudrate'), + ) + + def putx(self, data): + self.put(self.ss_edge, self.samplenum, self.out_ann, data) + + def __init__(self): + self.reset() + + def reset(self): + self.ss_edge = None + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + + # Get the first edge on the data line. + self.wait({0: 'e'}) + self.ss_edge = self.samplenum + + # Get any subsequent edge on the data line. Get the smallest + # distance between any two transitions, assuming it corresponds + # to one bit time of the respective bitrate of the input stream. + # This heuristics keeps getting better for longer captures. + bitwidth = None + while True: + self.wait({0: 'e'}) + + b = self.samplenum - self.ss_edge + if bitwidth is None or b < bitwidth: + bitwidth = b + bitrate = int(float(self.samplerate) / float(b)) + self.putx([0, ['%d' % bitrate]]) + self.ss_edge = self.samplenum diff --git a/libsigrokdecode4DSL/decoders/hdcp/__init__.py b/libsigrokdecode4DSL/decoders/hdcp/__init__.py new file mode 100644 index 00000000..f2e10b6a --- /dev/null +++ b/libsigrokdecode4DSL/decoders/hdcp/__init__.py @@ -0,0 +1,27 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Dave Craig +## +## 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, see . +## + +''' +This decoder stacks on top of the 'i2c' PD and decodes HDCP messages. + +Details: +https://www.digital-cp.com/sites/default/files/specifications/HDCP%20on%20HDMI%20Specification%20Rev2_2_Final1.pdf +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/hdcp/pd.py b/libsigrokdecode4DSL/decoders/hdcp/pd.py new file mode 100644 index 00000000..157b23a3 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/hdcp/pd.py @@ -0,0 +1,191 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Dave Craig +## +## 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, see . +## + +import sigrokdecode as srd + +msg_ids = { + 2: 'AKE_Init', + 3: 'AKE_Send_Cert', + 4: 'AKE_No_stored_km', + 5: 'AKE_Stored_km', + + 7: 'AKE_Send_H_prime', + 8: 'AKE_Send_Pairing_Info', + + 9: 'LC_Init', + 10: 'LC_Send_L_prime', + + 11: 'SKE_Send_Eks', + 12: 'RepeaterAuth_Send_ReceiverID_List', + + 15: 'RepeaterAuth_Send_Ack', + 16: 'RepeaterAuth_Stream_Manage', + 17: 'RepeaterAuth_Stream_Ready', +} + +write_items = { + 0x00: '1.4 Bksv - Receiver KSV', + 0x08: '1.4 Ri\' - Link Verification', + 0x0a: '1.4 Pj\' - Enhanced Link Verification', + 0x10: '1.4 Aksv - Transmitter KSV', + 0x15: '1.4 Ainfo - Transmitter KSV', + 0x18: '1.4 An - Session random number', + 0x20: '1.4 V\'H0', + 0x24: '1.4 V\'H1', + 0x28: '1.4 V\'H2', + 0x2c: '1.4 V\'H3', + 0x30: '1.4 V\'H4', + 0x40: '1.4 Bcaps', + 0x41: '1.4 Bstatus', + 0x43: '1.4 KSV FIFO', + 0x50: 'HDCP2Version', + 0x60: 'Write_Message', + 0x70: 'RxStatus', + 0x80: 'Read_Message', +} + +class Decoder(srd.Decoder): + api_version = 3 + id = 'hdcp' + name = 'HDCP' + longname = 'HDCP over HDMI' + desc = 'HDCP protocol over HDMI.' + license = 'gplv2+' + inputs = ['i2c'] + outputs = ['hdcp'] + tags = ['PC', 'Security/crypto'] + annotations = \ + tuple(('message-0x%02X' % i, 'Message 0x%02X' % i) for i in range(18)) + ( + ('summary', 'Summary'), + ('warning', 'Warning'), + ) + annotation_rows = ( + ('messages', 'Messages', tuple(range(18))), + ('summaries', 'Summaries', (18,)), + ('warnings', 'Warnings', (19,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.state = 'IDLE' + self.stack = [] + self.msg = -1 + self.ss = self.es = self.ss_block = self.es_block = 0 + self.init_seq = [] + self.valid = 0 + self.type = '' + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putb(self, data): + self.put(self.ss_block, self.es_block, self.out_ann, data) + + def decode(self, ss, es, data): + cmd, databyte = data + + # Collect the 'BITS' packet, then return. The next packet is + # guaranteed to belong to these bits we just stored. + if cmd == 'BITS': + self.bits = databyte + return + + self.ss, self.es = ss, es + + # State machine. + if self.state == 'IDLE': + # Wait for an I2C START condition. + if cmd == 'START': + self.reset() + self.ss_block = ss + elif cmd != 'START REPEAT': + return + self.state = 'GET SLAVE ADDR' + elif self.state == 'GET SLAVE ADDR': + if cmd == 'ADDRESS READ': + self.state = 'BUFFER DATA' + if databyte != 0x3a: + self.state = 'IDLE' + elif cmd == 'ADDRESS WRITE': + self.state = 'WRITE OFFSET' + if databyte != 0x3a: + self.state = 'IDLE' + elif self.state == 'WRITE OFFSET': + if cmd == 'DATA WRITE': + if databyte in write_items: + self.type = write_items[databyte] + if databyte in (0x10, 0x15, 0x18, 0x60): + self.state = 'BUFFER DATA' + # If we are reading, then jump back to IDLE for a start repeat. + # If we are writing, then just continue onwards. + if self.state == 'BUFFER DATA': + pass + elif self.type != '': + self.state = 'IDLE' + elif self.state == 'BUFFER DATA': + if cmd in ('STOP', 'NACK'): + self.es_block = es + self.state = 'IDLE' + if self.type == '': + return + if not self.stack: + self.putb([18, ['%s' % (self.type)]]) + return + if self.type == 'RxStatus': + rxstatus = (self.stack.pop() << 8) | self.stack.pop() + reauth_req = (rxstatus & 0x800) != 0 + ready = (rxstatus & 0x400) != 0 + length = rxstatus & 0x3ff + text = '%s, reauth %s, ready %s, length %s' % \ + (self.type, reauth_req, ready, length) + self.putb([18, [text]]) + elif self.type == '1.4 Bstatus': + bstatus = (self.stack.pop() << 8) | self.stack.pop() + device_count = bstatus & 0x7f + max_devs_exceeded = (bstatus & 0x80) != 0 + depth = ((bstatus & 0x700) >> 8) + max_cascase_exceeded = bstatus & 0x800 + hdmi_mode = (bstatus & 0x1000) != 0 + text = '%s, %s devices, depth %s, hdmi mode %s' % \ + (self.type, device_count, depth, hdmi_mode) + self.putb([18, [text]]) + elif self.type == 'Read_Message': + msg = self.stack.pop(0) + self.putb([msg, ['%s, %s' % (self.type, + msg_ids.get(msg, 'Invalid'))]]) + elif self.type == 'Write_Message': + msg = self.stack.pop(0) + self.putb([msg, ['%s, %s' % (self.type, + msg_ids.get(msg, 'Invalid'))]]) + elif self.type == 'HDCP2Version': + version = self.stack.pop(0) + if (version & 0x4): + self.putb([18, ['HDCP2']]) + else: + self.putb([18, ['NOT HDCP2']]) + else: + self.putb([18, ['%s' % (self.type)]]) + elif cmd == 'DATA READ': + # Stack up our data bytes. + self.stack.append(databyte) + elif cmd == 'DATA WRITE': + # Stack up our data bytes. + self.stack.append(databyte) diff --git a/libsigrokdecode4DSL/decoders/i2cdemux/__init__.py b/libsigrokdecode4DSL/decoders/i2cdemux/__init__.py new file mode 100644 index 00000000..e3e9a913 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/i2cdemux/__init__.py @@ -0,0 +1,27 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +''' +This is a generic I²C demultiplexing protocol decoder. + +It takes an I²C stream as input and outputs multiple I²C streams, each +stream containing only I²C packets for one specific I²C slave. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/i2cdemux/pd.py b/libsigrokdecode4DSL/decoders/i2cdemux/pd.py new file mode 100644 index 00000000..d6841d32 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/i2cdemux/pd.py @@ -0,0 +1,80 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +import sigrokdecode as srd + +class Decoder(srd.Decoder): + api_version = 3 + id = 'i2cdemux' + name = 'I²C demux' + longname = 'I²C demultiplexer' + desc = 'Demux I²C packets into per-slave-address streams.' + license = 'gplv2+' + inputs = ['i2c'] + outputs = [] # TODO: Only known at run-time. + tags = ['Util'] + + def __init__(self): + self.reset() + + def reset(self): + self.packets = [] # Local cache of I²C packets + self.slaves = [] # List of known slave addresses + self.stream = -1 # Current output stream + self.streamcount = 0 # Number of created output streams + + def start(self): + self.out_python = [] + + # Grab I²C packets into a local cache, until an I²C STOP condition + # packet comes along. At some point before that STOP condition, there + # will have been an ADDRESS READ or ADDRESS WRITE which contains the + # I²C address of the slave that the master wants to talk to. + # We use this slave address to figure out which output stream should + # get the whole chunk of packets (from START to STOP). + def decode(self, ss, es, data): + + cmd, databyte = data + + # Add the I²C packet to our local cache. + self.packets.append([ss, es, data]) + + if cmd in ('ADDRESS READ', 'ADDRESS WRITE'): + if databyte in self.slaves: + self.stream = self.slaves.index(databyte) + return + + # We're never seen this slave, add a new stream. + self.slaves.append(databyte) + self.out_python.append(self.register(srd.OUTPUT_PYTHON, + proto_id='i2c-%s' % hex(databyte))) + self.stream = self.streamcount + self.streamcount += 1 + elif cmd == 'STOP': + if self.stream == -1: + raise Exception('Invalid stream!') # FIXME? + + # Send the whole chunk of I²C packets to the correct stream. + for p in self.packets: + self.put(p[0], p[1], self.out_python[self.stream], p[2]) + + self.packets = [] + self.stream = -1 + else: + pass # Do nothing, only add the I²C packet to our cache. diff --git a/libsigrokdecode4DSL/decoders/i2cfilter/__init__.py b/libsigrokdecode4DSL/decoders/i2cfilter/__init__.py new file mode 100644 index 00000000..be97bf0a --- /dev/null +++ b/libsigrokdecode4DSL/decoders/i2cfilter/__init__.py @@ -0,0 +1,37 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Bert Vermeulen +## +## 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 . +## + +''' +This is a generic I²C filtering protocol decoder. + +It takes input from the I²C protocol decoder and removes all traffic +except that from/to the specified slave address and/or direction. + +It then outputs the filtered data again as OUTPUT_PROTO of type/format 'i2c' +(up the protocol decoder stack). No annotations are output. + +The I²C slave address to filter out should be passed in as an option +'address', as an integer. A specific read or write operation can be selected +with the 'direction' option, which should be 'read', 'write', or 'both'. + +Both of these are optional; if no options are specified the entire payload +of the I²C session will be output. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/i2cfilter/pd.py b/libsigrokdecode4DSL/decoders/i2cfilter/pd.py new file mode 100644 index 00000000..7798e17a --- /dev/null +++ b/libsigrokdecode4DSL/decoders/i2cfilter/pd.py @@ -0,0 +1,93 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Bert Vermeulen +## Copyright (C) 2012 Uwe Hermann +## +## 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 . +## + +# TODO: Support for filtering out multiple slave/direction pairs? + +import sigrokdecode as srd + +class Decoder(srd.Decoder): + api_version = 3 + id = 'i2cfilter' + name = 'I²C filter' + longname = 'I²C filter' + desc = 'Filter out addresses/directions in an I²C stream.' + license = 'gplv3+' + inputs = ['i2c'] + outputs = ['i2c'] + tags = ['Util'] + options = ( + {'id': 'address', 'desc': 'Address to filter out of the I²C stream', + 'default': 0}, + {'id': 'direction', 'desc': 'Direction to filter', 'default': 'both', + 'values': ('read', 'write', 'both')} + ) + + def __init__(self): + self.reset() + + def reset(self): + self.curslave = -1 + self.curdirection = None + self.packets = [] # Local cache of I²C packets + + def start(self): + self.out_python = self.register(srd.OUTPUT_PYTHON, proto_id='i2c') + if self.options['address'] not in range(0, 127 + 1): + raise Exception('Invalid slave (must be 0..127).') + + # Grab I²C packets into a local cache, until an I²C STOP condition + # packet comes along. At some point before that STOP condition, there + # will have been an ADDRESS READ or ADDRESS WRITE which contains the + # I²C address of the slave that the master wants to talk to. + # If that slave shall be filtered, output the cache (all packets from + # START to STOP) as proto 'i2c', otherwise drop it. + def decode(self, ss, es, data): + + cmd, databyte = data + + # Add the I²C packet to our local cache. + self.packets.append([ss, es, data]) + + if cmd in ('ADDRESS READ', 'ADDRESS WRITE'): + self.curslave = databyte + self.curdirection = cmd[8:].lower() + elif cmd in ('STOP', 'START REPEAT'): + # If this chunk was not for the correct slave, drop it. + if self.options['address'] == 0: + pass + elif self.curslave != self.options['address']: + self.packets = [] + return + + # If this chunk was not in the right direction, drop it. + if self.options['direction'] == 'both': + pass + elif self.options['direction'] != self.curdirection: + self.packets = [] + return + + # TODO: START->STOP chunks with both read and write (Repeat START) + # Otherwise, send out the whole chunk of I²C packets. + for p in self.packets: + self.put(p[0], p[1], self.out_python, p[2]) + + self.packets = [] + else: + pass # Do nothing, only add the I²C packet to our cache. diff --git a/libsigrokdecode4DSL/decoders/i2s/__init__.py b/libsigrokdecode4DSL/decoders/i2s/__init__.py new file mode 100644 index 00000000..a0b7097f --- /dev/null +++ b/libsigrokdecode4DSL/decoders/i2s/__init__.py @@ -0,0 +1,29 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Joel Holdsworth +## +## 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, see . +## + +''' +I²S (Integrated Interchip Sound) is a serial bus for connecting digital +audio devices (usually on the same device/board). + +Details: +http://www.nxp.com/acrobat_download/various/I2SBUS.pdf +http://en.wikipedia.org/wiki/I2s +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/i2s/pd.py b/libsigrokdecode4DSL/decoders/i2s/pd.py new file mode 100644 index 00000000..7e4959ec --- /dev/null +++ b/libsigrokdecode4DSL/decoders/i2s/pd.py @@ -0,0 +1,214 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Joel Holdsworth +## Copyright (C) 2019 DreamSourceLab +## +## 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, see . +## + +import sigrokdecode as srd +import struct + +''' +OUTPUT_PYTHON format: + +Packet: +[, ] + +, : + - 'DATA', [, ] + +: 'L' or 'R' +: integer +''' + +class Decoder(srd.Decoder): + api_version = 3 + id = 'i2s' + name = 'I²S' + longname = 'Integrated Interchip Sound' + desc = 'Serial bus for connecting digital audio devices.' + license = 'gplv2+' + inputs = ['logic'] + outputs = ['i2s'] + tags = ['Audio', 'PC'] + channels = ( + {'id': 'sck', 'name': 'SCK', 'desc': 'Bit clock line'}, + {'id': 'ws', 'name': 'WS', 'desc': 'Word select line'}, + {'id': 'sd', 'name': 'SD', 'desc': 'Serial data line'}, + ) + options = ( + {'id': 'ws_polarity', 'desc': 'WS polarity', 'default': 'left-high', + 'values': ('left-low', 'left-high')}, + {'id': 'clk_edge', 'desc': 'SCK active edge', 'default': 'rising-edge', + 'values': ('rising-edge', 'falling-edge')}, + {'id': 'bit_shift', 'desc': 'Bit shift', 'default': 'none', + 'values': ('right-shifted by one', 'none')}, + {'id': 'bit_align', 'desc': 'Bit align', 'default': 'left-aligned', + 'values': ('left-aligned', 'right-aligned')}, + {'id': 'bitorder', 'desc': 'Bit order', + 'default': 'msb-first', 'values': ('msb-first', 'lsb-first')}, + {'id': 'wordsize', 'desc': 'Word size', 'default': 16, + 'values': tuple(range(4,129,1))}, + ) + annotations = ( + ('left', 'Left channel'), + ('right', 'Right channel'), + ('warnings', 'Warnings'), + ) + binary = ( + ('wav', 'WAV file'), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.oldws = 1 + self.bitcount = 0 + self.data = 0 + self.samplesreceived = 0 + self.first_sample = None + self.ss_block = None + self.wordlength = -1 + self.wrote_wav_header = False + + def start(self): + self.out_python = self.register(srd.OUTPUT_PYTHON) + self.out_binary = self.register(srd.OUTPUT_BINARY) + self.out_ann = self.register(srd.OUTPUT_ANN) + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def putpb(self, data): + self.put(self.ss_block, self.samplenum, self.out_python, data) + + def putbin(self, data): + self.put(self.ss_block, self.samplenum, self.out_binary, data) + + def putb(self, data): + self.put(self.ss_block, self.samplenum, self.out_ann, data) + + def report(self): + # Calculate the sample rate. + samplerate = '?' + if self.ss_block is not None and \ + self.first_sample is not None and \ + self.ss_block > self.first_sample and \ + self.samplerate: + samplerate = '%d' % (self.samplesreceived * + self.samplerate / (self.ss_block - + self.first_sample)) + + return 'I²S: %d %d-bit samples received at %sHz' % \ + (self.samplesreceived, self.wordlength, samplerate) + + def wav_header(self): + # Chunk descriptor + h = b'RIFF' + h += b'\x24\x80\x00\x00' # Chunk size (2084) + h += b'WAVE' + # Fmt subchunk + h += b'fmt ' + h += b'\x10\x00\x00\x00' # Subchunk size (16 bytes) + h += b'\x01\x00' # Audio format (0x0001 == PCM) + h += b'\x02\x00' # Number of channels (2) + h += b'\x80\x3e\x00\x00' # Samplerate (16000) + h += b'\x00\xfa\x00\x00' # Byterate (64000) + h += b'\x04\x00' # Blockalign (4) + h += b'\x20\x00' # Bits per sample (32) + # Data subchunk + h += b'data' + h += b'\xff\xff\xff\xff' # Subchunk size (4G bytes) TODO + return h + + def wav_sample(self, sample): + return struct.pack(' self.bitcount: + self.putb([2, ['Received %d-bit word, expected %d-bit ' + 'word' % (self.bitcount, self.wordlength)]]) + else: + if (left_algined and msb) or (not left_algined and not msb): + self.data >>= self.bitcount - self.wordlength + else: + self.data &= int("1"*self.wordlength, 2) + self.oldws = self.oldws if left_high else not self.oldws + idx = 0 if self.oldws else 1 + c1 = 'Left channel' if self.oldws else 'Right channel' + c2 = 'Left' if self.oldws else 'Right' + c3 = 'L' if self.oldws else 'R' + v = '%08x' % self.data + self.putpb(['DATA', [c3, self.data]]) + self.putb([idx, ['%s: %s' % (c1, v), '%s: %s' % (c2, v), + '%s: %s' % (c3, v), c3]]) + self.putbin([0, self.wav_sample(self.data)]) + + + # Reset decoder state. + self.data = 0 if right_shifted else self.last + self.bitcount = 0 if right_shifted else 1 + self.ss_block = self.samplenum + + # Save the first sample position. + if self.first_sample is None: + self.first_sample = self.samplenum + + self.oldws = ws diff --git a/libsigrokdecode4DSL/decoders/iec/__init__.py b/libsigrokdecode4DSL/decoders/iec/__init__.py new file mode 100644 index 00000000..fa0d96f3 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/iec/__init__.py @@ -0,0 +1,24 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2017 Marcus Comstedt +## +## 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, see . +## + +''' +This protocol decoder can decode the Commodore serial IEEE-488 (IEC) protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/iec/pd.py b/libsigrokdecode4DSL/decoders/iec/pd.py new file mode 100644 index 00000000..8acd1d1f --- /dev/null +++ b/libsigrokdecode4DSL/decoders/iec/pd.py @@ -0,0 +1,168 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2017 Marcus Comstedt +## Copyright (C) 2019 DreamSourceLab +## +## 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, see . +## + +import sigrokdecode as srd + +step_wait_conds = ( + [{2: 'f'}, {0: 'l', 1: 'h'}], + [{2: 'f'}, {0: 'h', 1: 'h'}, {1: 'l'}], + [{2: 'f'}, {0: 'f'}, {1: 'l'}], + [{2: 'f'}, {1: 'e'}], +) + +class Decoder(srd.Decoder): + api_version = 3 + id = 'iec' + name = 'IEC' + longname = 'Commodore IEC bus' + desc = 'Commodore serial IEEE-488 (IEC) bus protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['PC', 'Retro computing'] + channels = ( + {'id': 'data', 'name': 'DATA', 'desc': 'Data I/O'}, + {'id': 'clk', 'name': 'CLK', 'desc': 'Clock'}, + {'id': 'atn', 'name': 'ATN', 'desc': 'Attention'}, + ) + optional_channels = ( + {'id': 'srq', 'name': 'SRQ', 'desc': 'Service request'}, + ) + annotations = ( + ('items', 'Items'), + ('gpib', 'DAT/CMD'), + ('eoi', 'EOI'), + ) + annotation_rows = ( + ('bytes', 'Bytes', (0,)), + ('gpib', 'DAT/CMD', (1,)), + ('eoi', 'EOI', (2,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.saved_ATN = False + self.saved_EOI = False + self.ss_item = self.es_item = None + self.step = 0 + self.bits = 0 + self.numbits = 0 + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putb(self, data): + self.put(self.ss_item, self.es_item, self.out_ann, data) + + def handle_bits(self): + # Output the saved item. + dbyte = self.bits + dATN = self.saved_ATN + dEOI = self.saved_EOI + self.es_item = self.samplenum + self.putb([0, ['%02X' % dbyte]]) + + # Encode item byte to GPIB convention. + self.strgpib = ' ' + if dATN: # ATN, decode commands. + # Note: Commands < 0x20 are not used on IEC bus. + if dbyte == 0x01: self.strgpib = 'GTL' + if dbyte == 0x04: self.strgpib = 'SDC' + if dbyte == 0x05: self.strgpib = 'PPC' + if dbyte == 0x08: self.strgpib = 'GET' + if dbyte == 0x09: self.strgpib = 'TCT' + if dbyte == 0x11: self.strgpib = 'LLO' + if dbyte == 0x14: self.strgpib = 'DCL' + if dbyte == 0x15: self.strgpib = 'PPU' + if dbyte == 0x18: self.strgpib = 'SPE' + if dbyte == 0x19: self.strgpib = 'SPD' + + if dbyte == 0x3f: self.strgpib = 'UNL' + if dbyte == 0x5f: self.strgpib = 'UNT' + if dbyte > 0x1f and dbyte < 0x3f: # Address listener. + self.strgpib = 'L' + chr(dbyte + 0x10) + if dbyte > 0x3f and dbyte < 0x5f: # Address talker. + self.strgpib = 'T' + chr(dbyte - 0x10) + if dbyte > 0x5f and dbyte < 0x70: # Channel reopen. + self.strgpib = 'R' + chr(dbyte - 0x30) + if dbyte > 0xdf and dbyte < 0xf0: # Channel close. + self.strgpib = 'C' + chr(dbyte - 0xb0) + if dbyte > 0xef: # Channel open. + self.strgpib = 'O' + chr(dbyte - 0xc0) + else: + if dbyte > 0x1f and dbyte < 0x7f: + self.strgpib = chr(dbyte) + if dbyte == 0x0a: + self.strgpib = 'LF' + if dbyte == 0x0d: + self.strgpib = 'CR' + + self.putb([1, [self.strgpib]]) + self.strEOI = ' ' + if dEOI: + self.strEOI = 'EOI' + self.putb([2, [self.strEOI]]) + + def decode(self): + while True: + + (data, clk, atn, srq) = self.wait(step_wait_conds[self.step]) + + if (self.matched & (0b1 << 0)): + # Falling edge on ATN, reset step. + self.step = 0 + + if self.step == 0: + # Don't use self.matched[1] here since we might come from + # a step with different conds due to the code above. + if data == 0 and clk == 1: + # Rising edge on CLK while DATA is low: Ready to send. + self.step = 1 + elif self.step == 1: + if data == 1 and clk == 1: + # Rising edge on DATA while CLK is high: Ready for data. + self.ss_item = self.samplenum + self.saved_ATN = not atn + self.saved_EOI = False + self.bits = 0 + self.numbits = 0 + self.step = 2 + elif clk == 0: + # CLK low again, transfer aborted. + self.step = 0 + elif self.step == 2: + if data == 0 and clk == 1: + # DATA goes low while CLK is still high, EOI confirmed. + self.saved_EOI = True + elif clk == 0: + self.step = 3 + elif self.step == 3: + if (self.matched & (0b1 << 1)): + if clk == 1: + # Rising edge on CLK; latch DATA. + self.bits |= data << self.numbits + elif clk == 0: + # Falling edge on CLK; end of bit. + self.numbits += 1 + if self.numbits == 8: + self.handle_bits() + self.step = 0 diff --git a/libsigrokdecode4DSL/decoders/ieee488/__init__.py b/libsigrokdecode4DSL/decoders/ieee488/__init__.py new file mode 100644 index 00000000..4240114a --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ieee488/__init__.py @@ -0,0 +1,26 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Gerhard Sittig +## +## 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, see . +## + +''' +This protocol decoder can decode the GPIB (IEEE-488) protocol. Both variants +of (up to) 16 parallel lines as well as serial communication (IEC bus) are +supported in this implementation. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/ieee488/pd.py b/libsigrokdecode4DSL/decoders/ieee488/pd.py new file mode 100644 index 00000000..4531cb30 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ieee488/pd.py @@ -0,0 +1,748 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2016 Rudolf Reuter +## Copyright (C) 2017 Marcus Comstedt +## Copyright (C) 2019 Gerhard Sittig +## +## 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, see . +## + +# This file was created from earlier implementations of the 'gpib' and +# the 'iec' protocol decoders. It combines the parallel and the serial +# transmission variants in a single instance with optional inputs for +# maximum code re-use. + +# TODO +# - Extend annotations for improved usability. +# - Keep talkers' data streams on separate annotation rows? Is this useful +# here at the GPIB level, or shall stacked decoders dispatch these? May +# depend on how often captures get inspected which involve multiple peers. +# - Make serial bit annotations optional? Could slow down interactive +# exploration for long captures (see USB). +# - Move the inlined Commodore IEC peripherals support to a stacked decoder +# when more peripherals get added. +# - SCPI over GPIB may "represent somewhat naturally" here already when +# text lines are a single run of data at the GPIB layer (each line between +# the address spec and either EOI or ATN). So a stacked SCPI decoder may +# only become necessary when the text lines' content shall get inspected. + +import sigrokdecode as srd +from common.srdhelper import bitpack + +''' +OUTPUT_PYTHON format for stacked decoders: + +General packet format: +[, , ] + +This is the list of s and their respective values: + +Raw bits and bytes at the physical transport level: + - 'IEC_BIT': is not applicable, is the transport's bit value. + - 'GPIB_RAW': is not applicable, is the transport's + byte value. Data bytes are in the 0x00-0xff range, command/address + bytes are in the 0x100-0x1ff range. + +GPIB level byte fields (commands, addresses, pieces of data): + - 'COMMAND': is not applicable, is the command's byte value. + - 'LISTEN': is the listener address (0-30), is the raw + byte value (including the 0x20 offset). + - 'TALK': is the talker address (0-30), is the raw byte + value (including the 0x40 offset). + - 'SECONDARY': is the secondary address (0-31), is the + raw byte value (including the 0x60 offset). + - 'MSB_SET': as well as are the raw byte value (including + the 0x80 offset). This usually does not happen for GPIB bytes with ATN + active, but was observed with the IEC bus and Commodore floppy drives, + when addressing channels within the device. + - 'DATA_BYTE': is the talker address (when available), + is the raw data byte (transport layer, ATN inactive). + +Extracted payload information (peers and their communicated data): + - 'TALK_LISTEN': is the current talker, is the list of + current listeners. These updates for the current "connected peers" + are sent when the set of peers changes, i.e. after talkers/listeners + got selected or deselected. Of course the data only covers what could + be gathered from the input data. Some controllers may not explicitly + address themselves, or captures may not include an early setup phase. + - 'TALKER_BYTES': is the talker address (when available), + is the accumulated byte sequence between addressing a talker and EOI, + or the next command/address. + - 'TALKER_TEXT': is the talker address (when available), + is the accumulated text sequence between addressing a talker and EOI, + or the next command/address. +''' + +class ChannelError(Exception): + pass + +def _format_ann_texts(fmts, **args): + if not fmts: + return None + return [fmt.format(**args) for fmt in fmts] + +_cmd_table = { + # Command codes in the 0x00-0x1f range. + 0x01: ['Go To Local', 'GTL'], + 0x04: ['Selected Device Clear', 'SDC'], + 0x05: ['Parallel Poll Configure', 'PPC'], + 0x08: ['Global Execute Trigger', 'GET'], + 0x09: ['Take Control', 'TCT'], + 0x11: ['Local Lock Out', 'LLO'], + 0x14: ['Device Clear', 'DCL'], + 0x15: ['Parallel Poll Unconfigure', 'PPU'], + 0x18: ['Serial Poll Enable', 'SPE'], + 0x19: ['Serial Poll Disable', 'SPD'], + # Unknown type of command. + None: ['Unknown command 0x{cmd:02x}', 'command 0x{cmd:02x}', 'cmd {cmd:02x}', 'C{cmd_ord:c}'], + # Special listener/talker "addresses" (deselecting previous peers). + 0x3f: ['Unlisten', 'UNL'], + 0x5f: ['Untalk', 'UNT'], +} + +def _is_command(b): + # Returns a tuple of booleans (or None when not applicable) whether + # the raw GPIB byte is: a command, an un-listen, an un-talk command. + if b in range(0x00, 0x20): + return True, None, None + if b in range(0x20, 0x40) and (b & 0x1f) == 31: + return True, True, False + if b in range(0x40, 0x60) and (b & 0x1f) == 31: + return True, False, True + return False, None, None + +def _is_listen_addr(b): + if b in range(0x20, 0x40): + return b & 0x1f + return None + +def _is_talk_addr(b): + if b in range(0x40, 0x60): + return b & 0x1f + return None + +def _is_secondary_addr(b): + if b in range(0x60, 0x80): + return b & 0x1f + return None + +def _is_msb_set(b): + if b & 0x80: + return b + return None + +def _get_raw_byte(b, atn): + # "Decorate" raw byte values for stacked decoders. + return b | 0x100 if atn else b + +def _get_raw_text(b, atn): + return ['{leader}{data:02x}'.format(leader = '/' if atn else '', data = b)] + +def _get_command_texts(b): + fmts = _cmd_table.get(b, None) + known = fmts is not None + if not fmts: + fmts = _cmd_table.get(None, None) + if not fmts: + return known, None + return known, _format_ann_texts(fmts, cmd = b, cmd_ord = ord('0') + b) + +def _get_address_texts(b): + laddr = _is_listen_addr(b) + taddr = _is_talk_addr(b) + saddr = _is_secondary_addr(b) + msb = _is_msb_set(b) + fmts = None + if laddr is not None: + fmts = ['Listen {addr:d}', 'L {addr:d}', 'L{addr_ord:c}'] + addr = laddr + elif taddr is not None: + fmts = ['Talk {addr:d}', 'T {addr:d}', 'T{addr_ord:c}'] + addr = taddr + elif saddr is not None: + fmts = ['Secondary {addr:d}', 'S {addr:d}', 'S{addr_ord:c}'] + addr = saddr + elif msb is not None: # For IEC bus compat. + fmts = ['Secondary {addr:d}', 'S {addr:d}', 'S{addr_ord:c}'] + addr = msb + return _format_ann_texts(fmts, addr = addr, addr_ord = ord('0') + addr) + +def _get_data_text(b): + # TODO Move the table of ASCII control characters to a common location? + # TODO Move the "printable with escapes" logic to a common helper? + _control_codes = { + 0x00: 'NUL', + 0x01: 'SOH', + 0x02: 'STX', + 0x03: 'ETX', + 0x04: 'EOT', + 0x05: 'ENQ', + 0x06: 'ACK', + 0x07: 'BEL', + 0x08: 'BS', + 0x09: 'TAB', + 0x0a: 'LF', + 0x0b: 'VT', + 0x0c: 'FF', + 0x0d: 'CR', + 0x0e: 'SO', + 0x0f: 'SI', + 0x10: 'DLE', + 0x11: 'DC1', + 0x12: 'DC2', + 0x13: 'DC3', + 0x14: 'DC4', + 0x15: 'NAK', + 0x16: 'SYN', + 0x17: 'ETB', + 0x18: 'CAN', + 0x19: 'EM', + 0x1a: 'SUB', + 0x1b: 'ESC', + 0x1c: 'FS', + 0x1d: 'GS', + 0x1e: 'RS', + 0x1f: 'US', + } + # Yes, exclude 0x7f (DEL) here. It's considered non-printable. + if b in range(0x20, 0x7f) and b not in ('[', ']'): + return '{:s}'.format(chr(b)) + elif b in _control_codes: + return '[{:s}]'.format(_control_codes[b]) + # Use a compact yet readable and unambigous presentation for bytes + # which contain non-printables. The format that is used here is + # compatible with 93xx EEPROM and UART decoders. + return '[{:02x}]'.format(b) + +( + PIN_DIO1, PIN_DIO2, PIN_DIO3, PIN_DIO4, + PIN_DIO5, PIN_DIO6, PIN_DIO7, PIN_DIO8, + PIN_EOI, PIN_DAV, PIN_NRFD, PIN_NDAC, + PIN_IFC, PIN_SRQ, PIN_ATN, PIN_REN, + PIN_CLK, +) = range(17) +PIN_DATA = PIN_DIO1 + +( + ANN_RAW_BIT, ANN_RAW_BYTE, + ANN_CMD, ANN_LADDR, ANN_TADDR, ANN_SADDR, ANN_DATA, + ANN_EOI, + ANN_TEXT, + # TODO Want to provide one annotation class per talker address (0-30)? + ANN_IEC_PERIPH, + ANN_WARN, +) = range(11) + +( + BIN_RAW, + BIN_DATA, + # TODO Want to provide one binary annotation class per talker address (0-30)? +) = range(2) + +class Decoder(srd.Decoder): + api_version = 3 + id = 'ieee488' + name = 'IEEE-488' + longname = 'IEEE-488 GPIB/HPIB/IEC' + desc = 'IEEE-488 General Purpose Interface Bus (GPIB/HPIB or IEC).' + license = 'gplv2+' + inputs = ['logic'] + outputs = ['ieee488'] + tags = ['PC', 'Retro computing'] + channels = ( + {'id': 'dio1' , 'name': 'DIO1/DATA', + 'desc': 'Data I/O bit 1, or serial data'}, + ) + optional_channels = ( + {'id': 'dio2' , 'name': 'DIO2', 'desc': 'Data I/O bit 2'}, + {'id': 'dio3' , 'name': 'DIO3', 'desc': 'Data I/O bit 3'}, + {'id': 'dio4' , 'name': 'DIO4', 'desc': 'Data I/O bit 4'}, + {'id': 'dio5' , 'name': 'DIO5', 'desc': 'Data I/O bit 5'}, + {'id': 'dio6' , 'name': 'DIO6', 'desc': 'Data I/O bit 6'}, + {'id': 'dio7' , 'name': 'DIO7', 'desc': 'Data I/O bit 7'}, + {'id': 'dio8' , 'name': 'DIO8', 'desc': 'Data I/O bit 8'}, + {'id': 'eoi', 'name': 'EOI', 'desc': 'End or identify'}, + {'id': 'dav', 'name': 'DAV', 'desc': 'Data valid'}, + {'id': 'nrfd', 'name': 'NRFD', 'desc': 'Not ready for data'}, + {'id': 'ndac', 'name': 'NDAC', 'desc': 'Not data accepted'}, + {'id': 'ifc', 'name': 'IFC', 'desc': 'Interface clear'}, + {'id': 'srq', 'name': 'SRQ', 'desc': 'Service request'}, + {'id': 'atn', 'name': 'ATN', 'desc': 'Attention'}, + {'id': 'ren', 'name': 'REN', 'desc': 'Remote enable'}, + {'id': 'clk', 'name': 'CLK', 'desc': 'Serial clock'}, + ) + options = ( + {'id': 'iec_periph', 'desc': 'Decode Commodore IEC bus peripherals details', + 'default': 'no', 'values': ('no', 'yes')}, + {'id': 'delim', 'desc': 'Payload data delimiter', + 'default': 'eol', 'values': ('none', 'eol')}, + ) + annotations = ( + ('bit', 'IEC bit'), + ('raw', 'Raw byte'), + ('cmd', 'Command'), + ('laddr', 'Listener address'), + ('taddr', 'Talker address'), + ('saddr', 'Secondary address'), + ('data', 'Data byte'), + ('eoi', 'EOI'), + ('text', 'Talker text'), + ('periph', 'IEC bus peripherals'), + ('warning', 'Warning'), + ) + annotation_rows = ( + ('bits', 'IEC bits', (ANN_RAW_BIT,)), + ('raws', 'Raw bytes', (ANN_RAW_BYTE,)), + ('gpib', 'Commands/data', (ANN_CMD, ANN_LADDR, ANN_TADDR, ANN_SADDR, ANN_DATA,)), + ('eois', 'EOI', (ANN_EOI,)), + ('texts', 'Talker texts', (ANN_TEXT,)), + ('periphs', 'IEC peripherals', (ANN_IEC_PERIPH,)), + ('warnings', 'Warnings', (ANN_WARN,)), + ) + binary = ( + ('raw', 'Raw bytes'), + ('data', 'Talker bytes'), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.curr_raw = None + self.curr_atn = None + self.curr_eoi = None + self.latch_atn = None + self.latch_eoi = None + self.accu_bytes = [] + self.accu_text = [] + self.ss_raw = None + self.es_raw = None + self.ss_eoi = None + self.es_eoi = None + self.ss_text = None + self.es_text = None + self.last_talker = None + self.last_listener = [] + self.last_iec_addr = None + self.last_iec_sec = None + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_bin = self.register(srd.OUTPUT_BINARY) + self.out_python = self.register(srd.OUTPUT_PYTHON) + + def putg(self, ss, es, data): + self.put(ss, es, self.out_ann, data) + + def putbin(self, ss, es, data): + self.put(ss, es, self.out_bin, data) + + def putpy(self, ss, es, ptype, addr, pdata): + self.put(ss, es, self.out_python, [ptype, addr, pdata]) + + def emit_eoi_ann(self, ss, es): + self.putg(ss, es, [ANN_EOI, ['EOI']]) + + def emit_bin_ann(self, ss, es, ann_cls, data): + self.putbin(ss, es, [ann_cls, bytes(data)]) + + def emit_data_ann(self, ss, es, ann_cls, data): + self.putg(ss, es, [ann_cls, data]) + + def emit_warn_ann(self, ss, es, data): + self.putg(ss, es, [ANN_WARN, data]) + + def flush_bytes_text_accu(self): + if self.accu_bytes and self.ss_text is not None and self.es_text is not None: + self.emit_bin_ann(self.ss_text, self.es_text, BIN_DATA, bytearray(self.accu_bytes)) + self.putpy(self.ss_text, self.es_text, 'TALKER_BYTES', self.last_talker, bytearray(self.accu_bytes)) + self.accu_bytes = [] + if self.accu_text and self.ss_text is not None and self.es_text is not None: + text = ''.join(self.accu_text) + self.emit_data_ann(self.ss_text, self.es_text, ANN_TEXT, [text]) + self.putpy(self.ss_text, self.es_text, 'TALKER_TEXT', self.last_talker, text) + self.accu_text = [] + self.ss_text = self.es_text = None + + def check_extra_flush(self, b): + # Optionally flush previously accumulated runs of payload data + # according to user specified conditions. + if self.options['delim'] == 'none': + return + if not self.accu_bytes: + return + + # This implementation exlusively handles "text lines", but adding + # support for more variants here is straight forward. + # + # Search for the first data byte _after_ a user specified text + # line termination sequence was seen. The termination sequence's + # alphabet may be variable, and the sequence may span multiple + # data bytes. We accept either CR or LF, and combine the CR+LF + # sequence to strive for maximum length annotations for improved + # readability at different zoom levels. It's acceptable that this + # implementation would also combine multiple line terminations + # like LF+LF. + term_chars = (10, 13) + is_eol = b in term_chars + had_eol = self.accu_bytes[-1] in term_chars + if had_eol and not is_eol: + self.flush_bytes_text_accu() + + def handle_ifc_change(self, ifc): + # Track IFC line for parallel input. + # Assertion of IFC de-selects all talkers and listeners. + if ifc: + self.last_talker = None + self.last_listener = [] + self.flush_bytes_text_accu() + + def handle_eoi_change(self, eoi): + # Track EOI line for parallel and serial input. + if eoi: + self.ss_eoi = self.samplenum + self.curr_eoi = eoi + else: + self.es_eoi = self.samplenum + if self.ss_eoi and self.latch_eoi: + self.emit_eoi_ann(self.ss_eoi, self.es_eoi) + self.es_text = self.es_eoi + self.flush_bytes_text_accu() + self.ss_eoi = self.es_eoi = None + self.curr_eoi = None + + def handle_atn_change(self, atn): + # Track ATN line for parallel and serial input. + self.curr_atn = atn + if atn: + self.flush_bytes_text_accu() + + def handle_iec_periph(self, ss, es, addr, sec, data): + # The annotation is optional. + if self.options['iec_periph'] != 'yes': + return + # Void internal state. + if addr is None and sec is None and data is None: + self.last_iec_addr = None + self.last_iec_sec = None + return + # Grab and evaluate new input. + _iec_addr_names = { + # TODO Add more items here. See the "Device numbering" section + # of the https://en.wikipedia.org/wiki/Commodore_bus page. + 8: 'Disk 0', + 9: 'Disk 1', + } + _iec_disk_range = range(8, 16) + if addr is not None: + self.last_iec_addr = addr + name = _iec_addr_names.get(addr, None) + if name: + self.emit_data_ann(ss, es, ANN_IEC_PERIPH, [name]) + addr = self.last_iec_addr # Simplify subsequent logic. + if sec is not None: + # BEWARE! The secondary address is a full byte and includes + # the 0x60 offset, to also work when the MSB was set. + self.last_iec_sec = sec + subcmd, channel = sec & 0xf0, sec & 0x0f + channel_ord = ord('0') + channel + if addr is not None and addr in _iec_disk_range: + subcmd_fmts = { + 0x60: ['Reopen {ch:d}', 'Re {ch:d}', 'R{ch_ord:c}'], + 0xe0: ['Close {ch:d}', 'Cl {ch:d}', 'C{ch_ord:c}'], + 0xf0: ['Open {ch:d}', 'Op {ch:d}', 'O{ch_ord:c}'], + }.get(subcmd, None) + if subcmd_fmts: + texts = _format_ann_texts(subcmd_fmts, ch = channel, ch_ord = channel_ord) + self.emit_data_ann(ss, es, ANN_IEC_PERIPH, texts) + sec = self.last_iec_sec # Simplify subsequent logic. + if data is not None: + if addr is None or sec is None: + return + # TODO Process data depending on peripheral type and channel? + + def handle_data_byte(self): + if not self.curr_atn: + self.check_extra_flush(self.curr_raw) + b = self.curr_raw + texts = _get_raw_text(b, self.curr_atn) + self.emit_data_ann(self.ss_raw, self.es_raw, ANN_RAW_BYTE, texts) + self.emit_bin_ann(self.ss_raw, self.es_raw, BIN_RAW, b.to_bytes(1, byteorder='big')) + self.putpy(self.ss_raw, self.es_raw, 'GPIB_RAW', None, _get_raw_byte(b, self.curr_atn)) + if self.curr_atn: + ann_cls = None + upd_iec = False, + py_type = None + py_peers = False + is_cmd, is_unl, is_unt = _is_command(b) + laddr = _is_listen_addr(b) + taddr = _is_talk_addr(b) + saddr = _is_secondary_addr(b) + msb = _is_msb_set(b) + if is_cmd: + known, texts = _get_command_texts(b) + if not known: + warn_texts = ['Unknown GPIB command', 'unknown', 'UNK'] + self.emit_warn_ann(self.ss_raw, self.es_raw, warn_texts) + ann_cls = ANN_CMD + py_type, py_addr = 'COMMAND', None + if is_unl: + self.last_listener = [] + py_peers = True + if is_unt: + self.last_talker = None + py_peers = True + if is_unl or is_unt: + upd_iec = True, None, None, None + elif laddr is not None: + addr = laddr + texts = _get_address_texts(b) + ann_cls = ANN_LADDR + py_type, py_addr = 'LISTEN', addr + if addr == self.last_talker: + self.last_talker = None + self.last_listener.append(addr) + upd_iec = True, addr, None, None + py_peers = True + elif taddr is not None: + addr = taddr + texts = _get_address_texts(b) + ann_cls = ANN_TADDR + py_type, py_addr = 'TALK', addr + if addr in self.last_listener: + self.last_listener.remove(addr) + self.last_talker = addr + upd_iec = True, addr, None, None + py_peers = True + elif saddr is not None: + addr = saddr + texts = _get_address_texts(b) + ann_cls = ANN_SADDR + upd_iec = True, None, b, None + py_type, py_addr = 'SECONDARY', addr + elif msb is not None: + # These are not really "secondary addresses", but they + # are used by the Commodore IEC bus (floppy channels). + texts = _get_address_texts(b) + ann_cls = ANN_SADDR + upd_iec = True, None, b, None + py_type, py_addr = 'MSB_SET', b + if ann_cls is not None and texts is not None: + self.emit_data_ann(self.ss_raw, self.es_raw, ann_cls, texts) + if upd_iec[0]: + self.handle_iec_periph(self.ss_raw, self.es_raw, upd_iec[1], upd_iec[2], upd_iec[3]) + if py_type: + self.putpy(self.ss_raw, self.es_raw, py_type, py_addr, b) + if py_peers: + self.last_listener.sort() + self.putpy(self.ss_raw, self.es_raw, 'TALK_LISTEN', self.last_talker, self.last_listener) + else: + self.accu_bytes.append(b) + text = _get_data_text(b) + if not self.accu_text: + self.ss_text = self.ss_raw + self.accu_text.append(text) + self.es_text = self.es_raw + self.emit_data_ann(self.ss_raw, self.es_raw, ANN_DATA, [text]) + self.handle_iec_periph(self.ss_raw, self.es_raw, None, None, b) + self.putpy(self.ss_raw, self.es_raw, 'DATA_BYTE', self.last_talker, b) + + def handle_dav_change(self, dav, data): + if dav: + # Data availability starts when the flag goes active. + self.ss_raw = self.samplenum + self.curr_raw = bitpack(data) + self.latch_atn = self.curr_atn + self.latch_eoi = self.curr_eoi + return + # Data availability ends when the flag goes inactive. Handle the + # previously captured data byte according to associated flags. + self.es_raw = self.samplenum + self.handle_data_byte() + self.ss_raw = self.es_raw = None + self.curr_raw = None + + def inject_dav_phase(self, ss, es, data): + # Inspection of serial input has resulted in one raw byte which + # spans a given period of time. Pretend we had seen a DAV active + # phase, to re-use code for the parallel transmission. + self.ss_raw = ss + self.curr_raw = bitpack(data) + self.latch_atn = self.curr_atn + self.latch_eoi = self.curr_eoi + self.es_raw = es + self.handle_data_byte() + self.ss_raw = self.es_raw = None + self.curr_raw = None + + def invert_pins(self, pins): + # All lines (including data bits!) are low active and thus need + # to get inverted to receive their logical state (high active, + # regular data bit values). Cope with inputs being optional. + return [1 - p if p in (0, 1) else p for p in pins] + + def decode_serial(self, has_clk, has_data_1, has_atn, has_srq): + if not has_clk or not has_data_1 or not has_atn: + raise ChannelError('IEC bus needs at least ATN and serial CLK and DATA.') + + # This is a rephrased version of decoders/iec/pd.py:decode(). + # SRQ was not used there either. Magic numbers were eliminated. + ( + STEP_WAIT_READY_TO_SEND, + STEP_WAIT_READY_FOR_DATA, + STEP_PREP_DATA_TEST_EOI, + STEP_CLOCK_DATA_BITS, + ) = range(4) + step_wait_conds = ( + [{PIN_ATN: 'f'}, {PIN_DATA: 'l', PIN_CLK: 'h'}], + [{PIN_ATN: 'f'}, {PIN_DATA: 'h', PIN_CLK: 'h'}, {PIN_CLK: 'l'}], + [{PIN_ATN: 'f'}, {PIN_DATA: 'f'}, {PIN_CLK: 'l'}], + [{PIN_ATN: 'f'}, {PIN_CLK: 'e'}], + ) + step = STEP_WAIT_READY_TO_SEND + bits = [] + + while True: + + # Sample input pin values. Keep DATA/CLK in verbatim form to + # re-use 'iec' decoder logic. Turn ATN to positive logic for + # easier processing. The data bits get handled during byte + # accumulation. + pins = self.wait(step_wait_conds[step]) + data, clk = pins[PIN_DATA], pins[PIN_CLK] + atn, = self.invert_pins([pins[PIN_ATN]]) + + if self.matched[0]: + # Falling edge on ATN, reset step. + step = STEP_WAIT_READY_TO_SEND + + if step == STEP_WAIT_READY_TO_SEND: + # Don't use self.matched[1] here since we might come from + # a step with different conds due to the code above. + if data == 0 and clk == 1: + # Rising edge on CLK while DATA is low: Ready to send. + step = STEP_WAIT_READY_FOR_DATA + elif step == STEP_WAIT_READY_FOR_DATA: + if data == 1 and clk == 1: + # Rising edge on DATA while CLK is high: Ready for data. + ss_byte = self.samplenum + self.handle_atn_change(atn) + if self.curr_eoi: + self.handle_eoi_change(False) + bits = [] + step = STEP_PREP_DATA_TEST_EOI + elif clk == 0: + # CLK low again, transfer aborted. + step = STEP_WAIT_READY_TO_SEND + elif step == STEP_PREP_DATA_TEST_EOI: + if data == 0 and clk == 1: + # DATA goes low while CLK is still high, EOI confirmed. + self.handle_eoi_change(True) + elif clk == 0: + step = STEP_CLOCK_DATA_BITS + ss_bit = self.samplenum + elif step == STEP_CLOCK_DATA_BITS: + if self.matched[1]: + if clk == 1: + # Rising edge on CLK; latch DATA. + bits.append(data) + elif clk == 0: + # Falling edge on CLK; end of bit. + es_bit = self.samplenum + self.emit_data_ann(ss_bit, es_bit, ANN_RAW_BIT, ['{:d}'.format(bits[-1])]) + self.putpy(ss_bit, es_bit, 'IEC_BIT', None, bits[-1]) + ss_bit = self.samplenum + if len(bits) == 8: + es_byte = self.samplenum + self.inject_dav_phase(ss_byte, es_byte, bits) + if self.curr_eoi: + self.handle_eoi_change(False) + step = STEP_WAIT_READY_TO_SEND + + def decode_parallel(self, has_data_n, has_dav, has_atn, has_eoi, has_srq): + + if False in has_data_n or not has_dav or not has_atn: + raise ChannelError('IEEE-488 needs at least ATN and DAV and eight DIO lines.') + has_ifc = self.has_channel(PIN_IFC) + + # Capture data lines at the falling edge of DAV, process their + # values at rising DAV edge (when data validity ends). Also make + # sure to start inspection when the capture happens to start with + # low signal levels, i.e. won't include the initial falling edge. + # Scan for ATN/EOI edges as well (including the trick which works + # around initial pin state). + # Map low-active physical transport lines to positive logic here, + # to simplify logical inspection/decoding of communicated data, + # and to avoid redundancy and inconsistency in later code paths. + waitcond = [] + idx_dav = len(waitcond) + waitcond.append({PIN_DAV: 'l'}) + idx_atn = len(waitcond) + waitcond.append({PIN_ATN: 'l'}) + idx_eoi = None + if has_eoi: + idx_eoi = len(waitcond) + waitcond.append({PIN_EOI: 'l'}) + idx_ifc = None + if has_ifc: + idx_ifc = len(waitcond) + waitcond.append({PIN_IFC: 'l'}) + while True: + pins = self.wait(waitcond) + pins = self.invert_pins(pins) + + # BEWARE! Order of evaluation does matter. For low samplerate + # captures, many edges fall onto the same sample number. So + # we process active edges of flags early (before processing + # data bits), and inactive edges late (after data got processed). + if idx_ifc is not None and self.matched[idx_ifc] and pins[PIN_IFC] == 1: + self.handle_ifc_change(pins[PIN_IFC]) + if idx_eoi is not None and self.matched[idx_eoi] and pins[PIN_EOI] == 1: + self.handle_eoi_change(pins[PIN_EOI]) + if self.matched[idx_atn] and pins[PIN_ATN] == 1: + self.handle_atn_change(pins[PIN_ATN]) + if self.matched[idx_dav]: + self.handle_dav_change(pins[PIN_DAV], pins[PIN_DIO1:PIN_DIO8 + 1]) + if self.matched[idx_atn] and pins[PIN_ATN] == 0: + self.handle_atn_change(pins[PIN_ATN]) + if idx_eoi is not None and self.matched[idx_eoi] and pins[PIN_EOI] == 0: + self.handle_eoi_change(pins[PIN_EOI]) + if idx_ifc is not None and self.matched[idx_ifc] and pins[PIN_IFC] == 0: + self.handle_ifc_change(pins[PIN_IFC]) + + waitcond[idx_dav][PIN_DAV] = 'e' + waitcond[idx_atn][PIN_ATN] = 'e' + if has_eoi: + waitcond[idx_eoi][PIN_EOI] = 'e' + if has_ifc: + waitcond[idx_ifc][PIN_IFC] = 'e' + + def decode(self): + # The decoder's boilerplate declares some of the input signals as + # optional, but only to support both serial and parallel variants. + # The CLK signal discriminates the two. For either variant some + # of the "optional" signals are not really optional for proper + # operation of the decoder. Check these conditions here. + has_clk = self.has_channel(PIN_CLK) + has_data_1 = self.has_channel(PIN_DIO1) + has_data_n = [bool(self.has_channel(pin) for pin in range(PIN_DIO1, PIN_DIO8 + 1))] + has_dav = self.has_channel(PIN_DAV) + has_atn = self.has_channel(PIN_ATN) + has_eoi = self.has_channel(PIN_EOI) + has_srq = self.has_channel(PIN_SRQ) + if has_clk: + self.decode_serial(has_clk, has_data_1, has_atn, has_srq) + else: + self.decode_parallel(has_data_n, has_dav, has_atn, has_eoi, has_srq) diff --git a/libsigrokdecode4DSL/decoders/ir_irmp/__init__.py b/libsigrokdecode4DSL/decoders/ir_irmp/__init__.py new file mode 100644 index 00000000..b6bbff60 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ir_irmp/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Rene Staffen +## +## 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, see . +## + +''' +IRMP is a multi protocol infrared remote protocol decoder. See +https://www.mikrocontroller.net/articles/IRMP for details. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/ir_irmp/irmp_library.py b/libsigrokdecode4DSL/decoders/ir_irmp/irmp_library.py new file mode 100644 index 00000000..5ec65222 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ir_irmp/irmp_library.py @@ -0,0 +1,137 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Rene Staffen +## +## 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, see . +## + +''' +Python binding for the IRMP library. +''' + +import ctypes +import platform + +class IrmpLibrary: + ''' + Library instance for an infrared protocol detector. + ''' + + __usable_instance = None + + class ResultData(ctypes.Structure): + _fields_ = [ + ( 'protocol', ctypes.c_uint32, ), + ( 'protocol_name', ctypes.c_char_p, ), + ( 'address', ctypes.c_uint32, ), + ( 'command', ctypes.c_uint32, ), + ( 'flags', ctypes.c_uint32, ), + ( 'start_sample', ctypes.c_uint32, ), + ( 'end_sample', ctypes.c_uint32, ), + ] + + FLAG_REPETITION = 1 << 0 + FLAG_RELEASE = 1 << 1 + + def _library_filename(self): + ''' + Determine the library filename depending on the platform. + ''' + + if platform.uname()[0] == 'Linux': + return 'libirmp.so' + if platform.uname()[0] == 'Darwin': + return 'libirmp.dylib' + return 'irmp.dll' + + def _library_setup_api(self): + ''' + Lookup the C library's API routines. Declare their prototypes. + ''' + + if not self._lib: + return False + + self._lib.irmp_get_sample_rate.restype = ctypes.c_uint32 + self._lib.irmp_get_sample_rate.argtypes = [] + + self._lib.irmp_reset_state.restype = None + self._lib.irmp_reset_state.argtypes = [] + + self._lib.irmp_add_one_sample.restype = ctypes.c_int + self._lib.irmp_add_one_sample.argtypes = [ ctypes.c_int, ] + + if False: + self._lib.irmp_detect_buffer.restype = self.ResultData + self._lib.irmp_detect_buffer.argtypes = [ ctypes.POINTER(ctypes.c_uint8), ctypes.c_size_t, ] + + self._lib.irmp_get_result_data.restype = ctypes.c_int + self._lib.irmp_get_result_data.argtypes = [ ctypes.POINTER(self.ResultData), ] + + self._lib.irmp_get_protocol_name.restype = ctypes.c_char_p + self._lib.irmp_get_protocol_name.argtypes = [ ctypes.c_uint32, ] + + # Create a result buffer that's local to the library instance. + self._data = self.ResultData() + + return True + + def __init__(self): + ''' + Create a library instance. + ''' + + # Only create a working instance for the first invocation. + # Degrade all other instances, make them fail "late" during + # execution, so that users will see the errors. + self._lib = None + self._data = None + if IrmpLibrary.__usable_instance is None: + filename = self._library_filename() + self._lib = ctypes.cdll.LoadLibrary(filename) + self._library_setup_api() + IrmpLibrary.__usable_instance = self + + def get_sample_rate(self): + if not self._lib: + return None + return self._lib.irmp_get_sample_rate() + + def reset_state(self): + if not self._lib: + return None + self._lib.irmp_reset_state() + + def add_one_sample(self, level): + if not self._lib: + raise Exception("IRMP library limited to a single instance.") + if not self._lib.irmp_add_one_sample(int(level)): + return False + self._lib.irmp_get_result_data(ctypes.byref(self._data)) + return True + + def get_result_data(self): + if not self._data: + return None + return { + 'proto_nr': self._data.protocol, + 'proto_name': self._data.protocol_name.decode('UTF-8', 'ignore'), + 'address': self._data.address, + 'command': self._data.command, + 'repeat': bool(self._data.flags & self.FLAG_REPETITION), + 'release': bool(self._data.flags & self.FLAG_RELEASE), + 'start': self._data.start_sample, + 'end': self._data.end_sample, + } diff --git a/libsigrokdecode4DSL/decoders/ir_irmp/pd.py b/libsigrokdecode4DSL/decoders/ir_irmp/pd.py new file mode 100644 index 00000000..979c1e01 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ir_irmp/pd.py @@ -0,0 +1,137 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Gump Yang +## Copyright (C) 2019 Rene Staffen +## +## 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, see . +## + +from . import irmp_library +import sigrokdecode as srd + +class SamplerateError(Exception): + pass + +class LibraryError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = 'ir_irmp' + name = 'IR IRMP' + longname = 'IR IRMP' + desc = 'IRMP infrared remote control multi protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['IR'] + channels = ( + {'id': 'ir', 'name': 'IR', 'desc': 'Data line'}, + ) + options = ( + {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-low', + 'values': ('active-low', 'active-high')}, + ) + annotations = ( + ('packet', 'Packet'), + ) + annotation_rows = ( + ('packets', 'IR Packets', (0,)), + ) + + def putframe(self, data): + '''Emit annotation for an IR frame.''' + + # Cache result data fields in local variables. Get the ss/es + # timestamps, scaled to sample numbers. + nr = data['proto_nr'] + name = data['proto_name'] + addr = data['address'] + cmd = data['command'] + repeat = data['repeat'] + release = data['release'] + ss = data['start'] * self.rate_factor + es = data['end'] * self.rate_factor + + # Prepare display texts for several zoom levels. + # Implementor's note: Keep list lengths for flags aligned during + # maintenance. Make sure there are as many flags text variants + # as are referenced by annotation text variants. Differing list + # lengths or dynamic refs will severely complicate the logic. + rep_txts = ['repeat', 'rep', 'r'] + rel_txts = ['release', 'rel', 'R'] + flag_txts = [None,] * len(rep_txts) + for zoom in range(len(flag_txts)): + flag_txts[zoom] = [] + if repeat: + flag_txts[zoom].append(rep_txts[zoom]) + if release: + flag_txts[zoom].append(rel_txts[zoom]) + flag_txts = [' '.join(t) or '-' for t in flag_txts] + flg = flag_txts # Short name for .format() references. + txts = [ + 'Protocol: {name} ({nr}), Address 0x{addr:04x}, Command: 0x{cmd:04x}, Flags: {flg[0]}'.format(**locals()), + 'P: {name} ({nr}), Addr: 0x{addr:x}, Cmd: 0x{cmd:x}, Flg: {flg[1]}'.format(**locals()), + 'P: {nr} A: 0x{addr:x} C: 0x{cmd:x} F: {flg[1]}'.format(**locals()), + 'C:{cmd:x} A:{addr:x} {flg[2]}'.format(**locals()), + 'C:{cmd:x}'.format(**locals()), + ] + + # Emit the annotation from details which were constructed above. + self.put(ss, es, self.out_ann, [0, txts]) + + def __init__(self): + self.irmp = None + self.reset() + + def reset(self): + self.want_reset = True + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def decode(self): + if not self.irmp: + try: + self.irmp = irmp_library.IrmpLibrary() + except Exception as e: + txt = e.args[0] + raise LibraryError(txt) + if self.irmp: + self.lib_rate = self.irmp.get_sample_rate() + if not self.irmp or not self.lib_rate: + raise LibraryError('Cannot access IRMP library. One instance limit exceeded?') + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + if self.samplerate % self.lib_rate: + raise SamplerateError('Capture samplerate must be multiple of library samplerate ({})'.format(self.lib_rate)) + self.rate_factor = int(self.samplerate / self.lib_rate) + if self.want_reset: + self.irmp.reset_state() + self.want_reset = False + + self.active = 0 if self.options['polarity'] == 'active-low' else 1 + ir, = self.wait() + while True: + if self.active == 1: + ir = 1 - ir + if self.irmp.add_one_sample(ir): + data = self.irmp.get_result_data() + self.putframe(data) + ir, = self.wait([{'skip': self.rate_factor}]) diff --git a/libsigrokdecode4DSL/decoders/ir_nec/__init__.py b/libsigrokdecode4DSL/decoders/ir_nec/__init__.py new file mode 100644 index 00000000..c361c3dc --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ir_nec/__init__.py @@ -0,0 +1,24 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Gump Yang +## +## 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, see . +## + +''' +NEC is a pulse-distance based infrared remote control protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/ir_nec/lists.py b/libsigrokdecode4DSL/decoders/ir_nec/lists.py new file mode 100644 index 00000000..7d47a46d --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ir_nec/lists.py @@ -0,0 +1,50 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Uwe Hermann +## +## 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, see . +## + +# Addresses/devices. Items that are not listed are reserved/unknown. +address = { + 0x40: 'Matsui TV', +} + +digits = { + 0: ['0', '0'], + 1: ['1', '1'], + 2: ['2', '2'], + 3: ['3', '3'], + 4: ['4', '4'], + 5: ['5', '5'], + 6: ['6', '6'], + 7: ['7', '7'], + 8: ['8', '8'], + 9: ['9', '9'], +} + +# Commands. Items that are not listed are reserved/unknown. +command = { + 0x40: dict(list(digits.items()) + list({ + 11: ['-/--', '-/--'], + 16: ['Mute', 'M'], + 18: ['Standby', 'StBy'], + 26: ['Volume up', 'Vol+'], + 27: ['Program up', 'P+'], + 30: ['Volume down', 'Vol-'], + 31: ['Program down', 'P-'], + 68: ['AV', 'AV'], + }.items())), +} diff --git a/libsigrokdecode4DSL/decoders/ir_nec/pd.py b/libsigrokdecode4DSL/decoders/ir_nec/pd.py new file mode 100644 index 00000000..830892e8 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ir_nec/pd.py @@ -0,0 +1,237 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Gump Yang +## Copyright (C) 2019 DreamSourceLab +## +## 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, see . +## + +import sigrokdecode as srd +from .lists import * + +class SamplerateError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = 'ir_nec' + name = 'IR NEC' + longname = 'IR NEC' + desc = 'NEC infrared remote control protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['IR'] + channels = ( + {'id': 'ir', 'name': 'IR', 'desc': 'Data line'}, + ) + options = ( + {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-low', + 'values': ('active-low', 'active-high')}, + {'id': 'cd_freq', 'desc': 'Carrier Frequency', 'default': 0}, + ) + annotations = ( + ('bit', 'Bit'), + ('agc-pulse', 'AGC pulse'), + ('longpause', 'Long pause'), + ('shortpause', 'Short pause'), + ('stop-bit', 'Stop bit'), + ('leader-code', 'Leader code'), + ('addr', 'Address'), + ('addr-inv', 'Address#'), + ('cmd', 'Command'), + ('cmd-inv', 'Command#'), + ('repeat-code', 'Repeat code'), + ('remote', 'Remote'), + ('warnings', 'Warnings'), + ) + annotation_rows = ( + ('bits', 'Bits', (0, 1, 2, 3, 4)), + ('fields', 'Fields', (5, 6, 7, 8, 9, 10)), + ('remote', 'Remote', (11,)), + ('warnings', 'Warnings', (12,)), + ) + + def putx(self, data): + self.put(self.ss_start, self.samplenum, self.out_ann, data) + + def putb(self, data): + self.put(self.ss_bit, self.samplenum, self.out_ann, data) + + def putd(self, data): + name = self.state.title() + d = {'ADDRESS': 6, 'ADDRESS#': 7, 'COMMAND': 8, 'COMMAND#': 9} + s = {'ADDRESS': ['ADDR', 'A'], 'ADDRESS#': ['ADDR#', 'A#'], + 'COMMAND': ['CMD', 'C'], 'COMMAND#': ['CMD#', 'C#']} + self.putx([d[self.state], ['%s: 0x%02X' % (name, data), + '%s: 0x%02X' % (s[self.state][0], data), + '%s: 0x%02X' % (s[self.state][1], data), s[self.state][1]]]) + + def putstop(self, ss): + self.put(ss, ss + self.stop, self.out_ann, + [4, ['Stop bit', 'Stop', 'St', 'S']]) + + def putpause(self, p): + self.put(self.ss_start, self.ss_other_edge, self.out_ann, + [1, ['AGC pulse', 'AGC', 'A']]) + idx = 2 if p == 'Long' else 3 + self.put(self.ss_other_edge, self.samplenum, self.out_ann, + [idx, [p + ' pause', '%s-pause' % p[0], '%sP' % p[0], 'P']]) + + def putremote(self): + dev = address.get(self.addr, 'Unknown device') + buttons = command.get(self.addr, None) + if buttons is None: + btn = ['Unknown', 'Unk'] + else: + btn = buttons.get(self.cmd, ['Unknown', 'Unk']) + self.put(self.ss_remote, self.ss_bit + self.stop, self.out_ann, + [11, ['%s: %s' % (dev, btn[0]), '%s: %s' % (dev, btn[1]), + '%s' % btn[1]]]) + + def __init__(self): + self.reset() + + def reset(self): + self.state = 'IDLE' + self.ss_bit = self.ss_start = self.ss_other_edge = self.ss_remote = 0 + self.data = self.count = self.active = None + self.addr = self.cmd = None + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.active = 0 if self.options['polarity'] == 'active-low' else 1 + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + self.tolerance = 0.05 # +/-5% + self.lc = int(self.samplerate * 0.0135) - 1 # 13.5ms + self.rc = int(self.samplerate * 0.01125) - 1 # 11.25ms + self.dazero = int(self.samplerate * 0.001125) - 1 # 1.125ms + self.daone = int(self.samplerate * 0.00225) - 1 # 2.25ms + self.stop = int(self.samplerate * 0.000652) - 1 # 0.652ms + + def compare_with_tolerance(self, measured, base): + return (measured >= base * (1 - self.tolerance) + and measured <= base * (1 + self.tolerance)) + + def handle_bit(self, tick): + ret = None + if self.compare_with_tolerance(tick, self.dazero): + ret = 0 + elif self.compare_with_tolerance(tick, self.daone): + ret = 1 + if ret in (0, 1): + self.putb([0, ['%d' % ret]]) + self.data |= (ret << self.count) # LSB-first + self.count = self.count + 1 + self.ss_bit = self.samplenum + + def data_ok(self): + ret, name = (self.data >> 8) & (self.data & 0xff), self.state.title() + if self.count == 8: + if self.state == 'ADDRESS': + self.addr = self.data + if self.state == 'COMMAND': + self.cmd = self.data + self.putd(self.data) + self.ss_start = self.samplenum + return True + if ret == 0: + self.putd(self.data >> 8) + else: + self.putx([12, ['%s error: 0x%04X' % (name, self.data)]]) + self.data = self.count = 0 + self.ss_bit = self.ss_start = self.samplenum + return ret == 0 + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + + cd_count = None + if self.options['cd_freq']: + cd_count = int(self.samplerate / self.options['cd_freq']) + 1 + prev_ir = None + + while True: + # Detect changes in the presence of an active input signal. + # The decoder can either be fed an already filtered RX signal + # or optionally can detect the presence of a carrier. Periods + # of inactivity (signal changes slower than the carrier freq, + # if specified) pass on the most recently sampled level. This + # approach works for filtered and unfiltered input alike, and + # only slightly extends the active phase of input signals with + # carriers included by one period of the carrier frequency. + # IR based communication protocols can cope with this slight + # inaccuracy just fine by design. Enabling carrier detection + # on already filtered signals will keep the length of their + # active period, but will shift their signal changes by one + # carrier period before they get passed to decoding logic. + if cd_count: + (cur_ir,) = self.wait([{0: 'e'}, {'skip': cd_count}]) + if (self.matched & (0b1 << 0)): + cur_ir = self.active + if cur_ir == prev_ir: + continue + prev_ir = cur_ir + self.ir = cur_ir + else: + (self.ir,) = self.wait({0: 'e'}) + + if self.ir != self.active: + # Save the non-active edge, then wait for the next edge. + self.ss_other_edge = self.samplenum + continue + + b = self.samplenum - self.ss_bit + + # State machine. + if self.state == 'IDLE': + if self.compare_with_tolerance(b, self.lc): + self.putpause('Long') + self.putx([5, ['Leader code', 'Leader', 'LC', 'L']]) + self.ss_remote = self.ss_start + self.data = self.count = 0 + self.state = 'ADDRESS' + elif self.compare_with_tolerance(b, self.rc): + self.putpause('Short') + self.putstop(self.samplenum) + self.samplenum += self.stop + self.putx([10, ['Repeat code', 'Repeat', 'RC', 'R']]) + self.data = self.count = 0 + self.ss_bit = self.ss_start = self.samplenum + elif self.state == 'ADDRESS': + self.handle_bit(b) + if self.count == 8: + self.state = 'ADDRESS#' if self.data_ok() else 'IDLE' + elif self.state == 'ADDRESS#': + self.handle_bit(b) + if self.count == 16: + self.state = 'COMMAND' if self.data_ok() else 'IDLE' + elif self.state == 'COMMAND': + self.handle_bit(b) + if self.count == 8: + self.state = 'COMMAND#' if self.data_ok() else 'IDLE' + elif self.state == 'COMMAND#': + self.handle_bit(b) + if self.count == 16: + self.state = 'STOP' if self.data_ok() else 'IDLE' + elif self.state == 'STOP': + self.putstop(self.ss_bit) + self.putremote() + self.ss_bit = self.ss_start = self.samplenum + self.state = 'IDLE' diff --git a/libsigrokdecode4DSL/decoders/ir_rc5/__init__.py b/libsigrokdecode4DSL/decoders/ir_rc5/__init__.py new file mode 100644 index 00000000..7a209b19 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ir_rc5/__init__.py @@ -0,0 +1,24 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Uwe Hermann +## +## 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, see . +## + +''' +RC-5 is a biphase/manchester based infrared remote control protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/ir_rc5/lists.py b/libsigrokdecode4DSL/decoders/ir_rc5/lists.py new file mode 100644 index 00000000..4a8c958d --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ir_rc5/lists.py @@ -0,0 +1,93 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Uwe Hermann +## +## 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, see . +## + +# Systems/addresses (0..31). Items that are not listed are reserved/unknown. +system = { + 0: ['TV receiver 1', 'TV1'], + 1: ['TV receiver 2', 'TV2'], + 2: ['Teletext', 'Txt'], + 3: ['Extension to TV1 and TV2', 'Ext TV1/TV2'], + 4: ['LaserVision player', 'LV'], + 5: ['Video cassette recorder 1', 'VCR1'], + 6: ['Video cassette recorder 2', 'VCR2'], + 7: ['Experimental', 'Exp'], + 8: ['Satellite TV receiver 1', 'Sat1'], + 9: ['Extension to VCR1 and VCR2', 'Ext VCR1/VCR2'], + 10: ['Satellite TV receiver 2', 'Sat2'], + 12: ['Compact disc video player', 'CD-Video'], + 13: ['Camcorder', 'Cam'], + 14: ['Photo on compact disc player', 'CD-Photo'], + 16: ['Audio preamplifier 1', 'Preamp1'], + 17: ['Radio tuner', 'Tuner'], + 18: ['Analog cassette recoder 1', 'Rec1'], + 19: ['Audio preamplifier 2', 'Preamp2'], + 20: ['Compact disc player', 'CD'], + 21: ['Audio stack or record player', 'Combi'], + 22: ['Audio satellite', 'Sat'], + 23: ['Analog cassette recoder 2', 'Rec2'], + 26: ['Compact disc recorder', 'CD-R'], + 29: ['Lighting 1', 'Light1'], + 30: ['Lighting 2', 'Light2'], + 31: ['Telephone', 'Phone'], +} + +digits = { + 0: ['0', '0'], + 1: ['1', '1'], + 2: ['2', '2'], + 3: ['3', '3'], + 4: ['4', '4'], + 5: ['5', '5'], + 6: ['6', '6'], + 7: ['7', '7'], + 8: ['8', '8'], + 9: ['9', '9'], +} + +# Commands (0..63 for RC-5, and 0..127 for Extended RC-5). +# Items that are not listed are reserved/unknown. +command = { + 'TV': dict(list(digits.items()) + list({ + 10: ['-/--', '-/--'], + 11: ['Channel/program', 'Ch/P'], + 12: ['Standby', 'StBy'], + 13: ['Mute', 'M'], + 14: ['Personal preferences', 'PP'], + 15: ['Display', 'Disp'], + 16: ['Volume up', 'Vol+'], + 17: ['Volume down', 'Vol-'], + 18: ['Brightness up', 'Br+'], + 19: ['Brightness down', 'Br-'], + 20: ['Saturation up', 'S+'], + 21: ['Saturation down', 'S-'], + 32: ['Program up', 'P+'], + 33: ['Program down', 'P-'], + }.items())), + 'VCR': dict(list(digits.items()) + list({ + 10: ['-/--', '-/--'], + 12: ['Standby', 'StBy'], + 32: ['Program up', 'P+'], + 33: ['Program down', 'P-'], + 50: ['Fast rewind', 'FRW'], + 52: ['Fast forward', 'FFW'], + 53: ['Play', 'Pl'], + 54: ['Stop', 'St'], + 55: ['Recording', 'Rec'], + }.items())), +} diff --git a/libsigrokdecode4DSL/decoders/ir_rc5/pd.py b/libsigrokdecode4DSL/decoders/ir_rc5/pd.py new file mode 100644 index 00000000..e18a90bf --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ir_rc5/pd.py @@ -0,0 +1,187 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Uwe Hermann +## +## 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, see . +## + +import sigrokdecode as srd +from .lists import * + +class SamplerateError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = 'ir_rc5' + name = 'IR RC-5' + longname = 'IR RC-5' + desc = 'RC-5 infrared remote control protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['IR'] + channels = ( + {'id': 'ir', 'name': 'IR', 'desc': 'IR data line'}, + ) + options = ( + {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-low', + 'values': ('active-low', 'active-high')}, + {'id': 'protocol', 'desc': 'Protocol type', 'default': 'standard', + 'values': ('standard', 'extended')}, + ) + annotations = ( + ('bit', 'Bit'), + ('startbit1', 'Startbit 1'), + ('startbit2', 'Startbit 2'), + ('togglebit-0', 'Toggle bit 0'), + ('togglebit-1', 'Toggle bit 1'), + ('address', 'Address'), + ('command', 'Command'), + ) + annotation_rows = ( + ('bits', 'Bits', (0,)), + ('fields', 'Fields', (1, 2, 3, 4, 5, 6)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.samplenum = None + self.edges, self.bits, self.ss_es_bits = [], [], [] + self.state = 'IDLE' + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.old_ir = 1 if self.options['polarity'] == 'active-low' else 0 + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + # One bit: 1.78ms (one half low, one half high). + self.halfbit = int((self.samplerate * 0.00178) / 2.0) + + def putb(self, bit1, bit2, data): + ss, es = self.ss_es_bits[bit1][0], self.ss_es_bits[bit2][1] + self.put(ss, es, self.out_ann, data) + + def handle_bits(self): + a, c, b = 0, 0, self.bits + # Individual raw bits. + for i in range(14): + if i == 0: + ss = max(0, self.bits[0][0] - self.halfbit) + else: + ss = self.ss_es_bits[i - 1][1] + es = self.bits[i][0] + self.halfbit + self.ss_es_bits.append([ss, es]) + self.putb(i, i, [0, ['%d' % self.bits[i][1]]]) + # Bits[0:0]: Startbit 1 + s = ['Startbit1: %d' % b[0][1], 'SB1: %d' % b[0][1], 'SB1', 'S1', 'S'] + self.putb(0, 0, [1, s]) + # Bits[1:1]: Startbit 2 + ann_idx = 2 + s = ['Startbit2: %d' % b[1][1], 'SB2: %d' % b[1][1], 'SB2', 'S2', 'S'] + if self.options['protocol'] == 'extended': + s = ['CMD[6]#: %d' % b[1][1], 'C6#: %d' % b[1][1], 'C6#', 'C#', 'C'] + ann_idx = 6 + self.putb(1, 1, [ann_idx, s]) + # Bits[2:2]: Toggle bit + s = ['Togglebit: %d' % b[2][1], 'Toggle: %d' % b[2][1], + 'TB: %d' % b[2][1], 'TB', 'T'] + self.putb(2, 2, [3 if b[2][1] == 0 else 4, s]) + # Bits[3:7]: Address (MSB-first) + for i in range(5): + a |= (b[3 + i][1] << (4 - i)) + x = system.get(a, ['Unknown', 'Unk']) + s = ['Address: %d (%s)' % (a, x[0]), 'Addr: %d (%s)' % (a, x[1]), + 'Addr: %d' % a, 'A: %d' % a, 'A'] + self.putb(3, 7, [5, s]) + # Bits[8:13]: Command (MSB-first) + for i in range(6): + c |= (b[8 + i][1] << (5 - i)) + if self.options['protocol'] == 'extended': + inverted_bit6 = 1 if b[1][1] == 0 else 0 + c |= (inverted_bit6 << 6) + cmd_type = 'VCR' if x[1] in ('VCR1', 'VCR2') else 'TV' + x = command[cmd_type].get(c, ['Unknown', 'Unk']) + s = ['Command: %d (%s)' % (c, x[0]), 'Cmd: %d (%s)' % (c, x[1]), + 'Cmd: %d' % c, 'C: %d' % c, 'C'] + self.putb(8, 13, [6, s]) + + def edge_type(self): + # Categorize according to distance from last edge (short/long). + distance = self.samplenum - self.edges[-1] + s, l, margin = self.halfbit, self.halfbit * 2, int(self.halfbit / 2) + if distance in range(l - margin, l + margin + 1): + return 'l' + elif distance in range(s - margin, s + margin + 1): + return 's' + else: + return 'e' # Error, invalid edge distance. + + def reset_decoder_state(self): + self.edges, self.bits, self.ss_es_bits = [], [], [] + self.state = 'IDLE' + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + while True: + + (self.ir,) = self.wait() + + # Wait for any edge (rising or falling). + if self.old_ir == self.ir: + continue + + # State machine. + if self.state == 'IDLE': + bit = 1 + self.edges.append(self.samplenum) + self.bits.append([self.samplenum, bit]) + self.state = 'MID1' + self.old_ir = self.ir + continue + edge = self.edge_type() + if edge == 'e': + self.reset_decoder_state() # Reset state machine upon errors. + continue + if self.state == 'MID1': + self.state = 'START1' if edge == 's' else 'MID0' + bit = None if edge == 's' else 0 + elif self.state == 'MID0': + self.state = 'START0' if edge == 's' else 'MID1' + bit = None if edge == 's' else 1 + elif self.state == 'START1': + if edge == 's': + self.state = 'MID1' + bit = 1 if edge == 's' else None + elif self.state == 'START0': + if edge == 's': + self.state = 'MID0' + bit = 0 if edge == 's' else None + + self.edges.append(self.samplenum) + if bit is not None: + self.bits.append([self.samplenum, bit]) + + if len(self.bits) == 14: + self.handle_bits() + self.reset_decoder_state() + + self.old_ir = self.ir diff --git a/libsigrokdecode4DSL/decoders/ir_rc6/__init__.py b/libsigrokdecode4DSL/decoders/ir_rc6/__init__.py new file mode 100644 index 00000000..b2cb9f9a --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ir_rc6/__init__.py @@ -0,0 +1,24 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Benedikt Otto +## +## 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, see . +## + +''' +RC-6 is a biphase/manchester based infrared remote control protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/ir_rc6/pd.py b/libsigrokdecode4DSL/decoders/ir_rc6/pd.py new file mode 100644 index 00000000..e195dbd1 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ir_rc6/pd.py @@ -0,0 +1,205 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Benedikt Otto +## +## 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, see . +## + +import sigrokdecode as srd + +class SamplerateError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = 'ir_rc6' + name = 'IR RC-6' + longname = 'IR RC-6' + desc = 'RC-6 infrared remote control protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['IR'] + channels = ( + {'id': 'ir', 'name': 'IR', 'desc': 'IR data line'}, + ) + options = ( + {'id': 'polarity', 'desc': 'Polarity', 'default': 'auto', + 'values': ('auto', 'active-low', 'active-high')}, + ) + annotations = ( + ('bit', 'Bit'), + ('sync', 'Sync'), + ('startbit', 'Startbit'), + ('field', 'Field'), + ('togglebit', 'Togglebit'), + ('address', 'Address'), + ('command', 'Command'), + ) + annotation_rows = ( + ('bits', 'Bits', (0,)), + ('fields', 'Fields', (1, 2, 3, 4, 5, 6)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.edges, self.deltas, self.bits = [], [], [] + self.state = 'IDLE' + self.mode = 0 + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + # One bit: 0.889ms (one half low, one half high). + self.halfbit = int((self.samplerate * 0.000889) / 2.0) + + def putb(self, bit, data): + self.put(bit[0], bit[1], self.out_ann, data) + + def putbits(self, bit1, bit2, data): + self.put(bit1[0], bit2[1], self.out_ann, data) + + def putx(self, ss, es, data): + self.put(ss, es, self.out_ann, data) + + def handle_bit(self): + if len(self.bits) != 6: + return + if self.bits[0][2] == 8 and self.bits[0][3] == 1: + self.putb(self.bits[0], [1, ['Synchronisation', 'Sync']]) + else: + return + if self.bits[1][3] == 1: + self.putb(self.bits[1], [2, ['Startbit', 'Start']]) + else: + return + self.mode = sum([self.bits[2 + i][3] << (2 - i) for i in range(3)]) + self.putbits(self.bits[2], self.bits[4], [3, ['Field: %d' % self.mode]]) + self.putb(self.bits[5], [4, ['Toggle: %d' % self.bits[5][3]]]) + + def handle_package(self): + # Sync and start bits have to be 1. + if self.bits[0][3] == 0 or self.bits[1][3] == 0: + return + if len(self.bits) <= 6: + return + + if self.mode == 0 and len(self.bits) == 22: # Mode 0 standard + value = sum([self.bits[6 + i][3] << (7 - i) for i in range(8)]) + self.putbits(self.bits[6], self.bits[13], [5, ['Address: %0.2X' % value]]) + + value = sum([self.bits[14 + i][3] << (7 - i) for i in range(8)]) + self.putbits(self.bits[14], self.bits[21], [6, ['Data: %0.2X' % value]]) + + self.bits = [] + + if self.mode == 6 and len(self.bits) >= 15: # Mode 6 + if self.bits[6][3] == 0: # Short addr, Mode 6A + value = sum([self.bits[6 + i][3] << (7 - i) for i in range(8)]) + self.putbits(self.bits[6], self.bits[13], [5, ['Address: %0.2X' % value]]) + + num_data_bits = len(self.bits) - 14 + value = sum([self.bits[14 + i][3] << (num_data_bits - 1 - i) for i in range(num_data_bits)]) + self.putbits(self.bits[14], self.bits[-1], [6, ['Data: %X' % value]]) + + self.bits = [] + + elif len(self.bits) >= 23: # Long addr, Mode 6B + value = sum([self.bits[6 + i][3] << (15 - i) for i in range(16)]) + self.putbits(self.bits[6], self.bits[21], [5, ['Address: %0.2X' % value]]) + + num_data_bits = len(self.bits) - 22 + value = sum([self.bits[22 + i][3] << (num_data_bits - 1 - i) for i in range(num_data_bits)]) + self.putbits(self.bits[22], self.bits[-1], [6, ['Data: %X' % value]]) + + self.bits = [] + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + value = 0 + num_edges = -1 + self.invert = False + + while True: + conditions = [{0: 'e'}] + if self.state == 'DATA': + conditions.append({'skip': self.halfbit * 6}) + (self.ir,) = self.wait(conditions) + + if len(conditions) == 2: + if self.matched[1]: + self.state = 'IDLE' + + self.edges.append(self.samplenum) + if len(self.edges) < 2: + continue + + delta = (self.edges[-1] - self.edges[-2]) / self.halfbit + delta = int(delta + 0.5) + self.deltas.append(delta) + + if len(self.deltas) < 2: + continue + + if self.deltas[-2:] == [6, 2]: + self.state = 'SYNC' + num_edges = 0 + self.bits = [] + + if self.options['polarity'] == 'auto': + value = 1 + else: + value = self.ir if self.options['polarity'] == 'active-high' else 1 - self.ir + + self.bits.append((self.edges[-3], self.edges[-1], 8, value)) + self.invert = self.ir == 0 + self.putb(self.bits[-1], [0, ['%d' % value]]) # Add bit. + + if (num_edges % 2) == 0: # Only count every second edge. + if self.deltas[-2] in [1, 2, 3] and self.deltas[-1] in [1, 2, 3, 6]: + self.state = 'DATA' + if self.deltas[-2] != self.deltas[-1]: + # Insert border between 2 bits. + self.edges.insert(-1, self.edges[-2] + self.deltas[-2] * self.halfbit) + total = self.deltas[-1] + self.deltas[-1] = self.deltas[-2] + self.deltas.append(total - self.deltas[-1]) + + self.bits.append((self.edges[-4], self.edges[-2], self.deltas[-2] * 2, value)) + + num_edges += 1 + else: + self.bits.append((self.edges[-3], self.edges[-1], self.deltas[-1] * 2, value)) + + self.putb(self.bits[-1], [0, ['%d' % value]]) # Add bit. + + if len(self.bits) > 0: + self.handle_bit() + if self.state == 'IDLE': + self.handle_package() + + if self.options['polarity'] == 'auto': + value = self.ir if self.invert else 1 - self.ir + else: + value = self.ir if self.options['polarity'] == 'active-low' else 1 - self.ir + + num_edges += 1 diff --git a/libsigrokdecode4DSL/decoders/ir_sirc/__init__.py b/libsigrokdecode4DSL/decoders/ir_sirc/__init__.py new file mode 100644 index 00000000..4061ed73 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ir_sirc/__init__.py @@ -0,0 +1,26 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 Tom Flanagan +## +## 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, see . +## + +''' +Decoder for the Sony IR remote control protocol (SIRC). + +https://www.sbprojects.net/knowledge/ir/sirc.php +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/ir_sirc/lists.py b/libsigrokdecode4DSL/decoders/ir_sirc/lists.py new file mode 100644 index 00000000..5c6d8fa6 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ir_sirc/lists.py @@ -0,0 +1,201 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 Tom Flanagan +## +## 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, see . +## + +NUMBERS = { + 0x00: '1', + 0x01: '2', + 0x02: '3', + 0x03: '4', + 0x04: '5', + 0x05: '6', + 0x06: '7', + 0x07: '8', + 0x08: '9', + 0x09: '0/10', +} + +ADDRESSES = { + # TV + (0x01, None): (['TV: ', 'TV:'], { + 0x15: 'Power', + 0x25: 'Input', + + 0x33: 'Right', + 0x34: 'Left', + 0x3A: 'Display', + + 0x60: 'Home', + 0x65: 'Enter', + + 0x74: 'Up', + 0x75: 'Down', + + }), + + # Video + (0x0B, None): (['Video: ', 'V:'], { + 0x18: 'Stop', + 0x19: 'Pause', + 0x1A: 'Play', + 0x1B: 'Rewind', + 0x1C: 'Fast Forward', + + 0x42: 'Up', + 0x43: 'Down', + 0x4D: 'Home', + + 0x51: 'Enter', + 0x5A: 'Display', + + 0x61: 'Right', + 0x62: 'Left', + }), + + # BR Input select + (0x10, 0x28): (['BlueRay: ', 'BR:'], { + 0x16: 'BlueRay', + }), + + # Amp, Game, Sat, Tuner, USB + (0x10, 0x08): (['Playback: ', 'PB:'], { + 0x2A: 'Shuffle', + 0x2C: 'Repeat', + 0x2E: 'Folder Down', + 0x2F: 'Folder Up', + + 0x30: 'Previous', + 0x31: 'Next', + 0x32: 'Play', + 0x33: 'Rewind', + 0x34: 'Fast Forward', + 0x38: 'Stop', + 0x39: 'Pause', + + 0x73: 'Options', + 0x7D: 'Return', + }), + + # CD + (0x11, None): (['CD: ', 'CD:'], { + 0x28: 'Display', + + 0x30: 'Previous', + 0x31: 'Next', + 0x32: 'Play', + 0x33: 'Rewind', + 0x34: 'Fast Forward', + 0x38: 'Stop', + 0x39: 'Pause', + }), + + # BD + (0x1A, 0xE2): (['BlueRay: ', 'BD:'], { + 0x18: 'Stop', + 0x19: 'Pause', + 0x1A: 'Play', + 0x1B: 'Rewind', + 0x1C: 'Fast Forward', + + 0x29: 'Menu', + 0x2C: 'Top Menu', + + 0x39: 'Up', + 0x3A: 'Down', + 0x3B: 'Left', + 0x3C: 'Right', + 0x3D: 'Enter', + 0x3F: 'Options', + + 0x41: 'Display', + 0x42: 'Home', + 0x43: 'Return', + + 0x56: 'Next', + 0x57: 'Previous', + }), + + # DVD + (0x1A, 0x49): (['DVD: ', 'DVD:'], { + 0x0B: 'Enter', + 0x0E: 'Return', + 0x17: 'Options', + + 0x1A: 'Top Menu', + 0x1B: 'Menu', + + 0x30: 'Previous', + 0x31: 'Next', + 0x32: 'Play', + 0x33: 'Rewind', + 0x34: 'Fast Forward', + 0x38: 'Stop', + 0x39: 'Pause', + + 0x54: 'Display', + + 0x7B: 'Left', + 0x7C: 'Right', + 0x79: 'Up', + 0x7A: 'Down', + }), + + # Amp, Game, Sat, Tuner, USB modes + (0x30, None): (['Keypad: ', 'KP:'], { + 0x0C: 'Enter', + + 0x12: 'Volume Up', + 0x13: 'Volume Down', + 0x14: 'Mute', + 0x15: 'Power', + + 0x21: 'Tuner', + 0x22: 'Video', + 0x25: 'CD', + + 0x4D: 'Home', + 0x4B: 'Display', + + 0x60: 'Sleep', + 0x6A: 'TV', + + 0x53: 'Home', + + 0x7C: 'Game', + 0x7D: 'DVD', + }), + + # Amp, Game, Sat, Tuner, USB modes + (0xB0, None): (['Arrows: ', 'Ar:'], { + 0x7A: 'Left', + 0x7B: 'Right', + 0x78: 'Up', + 0x79: 'Down', + 0x77: 'Amp Menu', + }), + + # TV mode + (0x97, None): (['TV Extra', 'TV:'], { + 0x23: 'Return', + 0x36: 'Options', + + }), +} + +for (address, extended), (name, commands) in ADDRESSES.items(): + commands.update(NUMBERS) diff --git a/libsigrokdecode4DSL/decoders/ir_sirc/pd.py b/libsigrokdecode4DSL/decoders/ir_sirc/pd.py new file mode 100644 index 00000000..14ba63f0 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ir_sirc/pd.py @@ -0,0 +1,215 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 Tom Flanagan +## +## 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, see . +## + +from common.srdhelper import bitpack_lsb +from .lists import ADDRESSES +import sigrokdecode as srd + +class SamplerateError(Exception): + pass + +class SIRCError(Exception): + pass + +class SIRCErrorSilent(SIRCError): + pass + +class Ann: + BIT, AGC, PAUSE, START, CMD, ADDR, EXT, REMOTE, WARN = range(9) + +AGC_USEC = 2400 +ONE_USEC = 1200 +ZERO_USEC = 600 +PAUSE_USEC = 600 + +class Decoder(srd.Decoder): + api_version = 3 + id = 'ir_sirc' + name = 'IR SIRC' + longname = 'Sony IR (SIRC)' + desc = 'Sony infrared remote control protocol (SIRC).' + license = 'gplv2+' + tags = ['IR'] + inputs = ['logic'] + outputs = [] + channels = ( + {'id': 'ir', 'name': 'IR', 'desc': 'IR data line'}, + ) + options = ( + {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-low', + 'values': ('active-low', 'active-high')}, + ) + annotations = ( + ('bit', 'Bit'), + ('agc', 'AGC'), + ('pause', 'Pause'), + ('start', 'Start'), + ('command', 'Command'), + ('address', 'Address'), + ('extended', 'Extended'), + ('remote', 'Remote'), + ('warning', 'Warning'), + ) + annotation_rows = ( + ('bits', 'Bits', (Ann.BIT, Ann.AGC, Ann.PAUSE)), + ('fields', 'Fields', (Ann.START, Ann.CMD, Ann.ADDR, Ann.EXT)), + ('remotes', 'Remotes', (Ann.REMOTE,)), + ('warnings', 'Warnings', (Ann.WARN,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + pass + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.active = self.options['polarity'] == 'active-high' + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + self.snum_per_us = self.samplerate / 1e6 + + def putg(self, ss, es, cls, texts): + self.put(ss, es, self.out_ann, [cls, texts]) + + def tolerance(self, ss, es, expected): + microseconds = (es - ss) / self.snum_per_us + tolerance = expected * 0.30 + return (expected - tolerance) < microseconds < (expected + tolerance) + + def wait_wrap(self, conds, timeout): + if timeout is not None: + to = int(timeout * self.snum_per_us) + conds.append({'skip': to}) + ss = self.samplenum + pins = self.wait(conds) + es = self.samplenum + return pins, ss, es, self.matched + + def read_pulse(self, high, time): + e = 'f' if high else 'r' + max_time = int(time * 1.30) + (ir,), ss, es, (edge, timeout) = self.wait_wrap([{0: e}], max_time) + if timeout or not self.tolerance(ss, es, time): + raise SIRCError('Timeout') + return ir, ss, es, (edge, timeout) + + def read_bit(self): + e = 'f' if self.active else 'r' + _, high_ss, high_es, (edge, timeout) = self.wait_wrap([{0: e}], 2000) + if timeout: + raise SIRCError('Bit High Timeout') + if self.tolerance(high_ss, high_es, ONE_USEC): + bit = 1 + elif self.tolerance(high_ss, high_es, ZERO_USEC): + bit = 0 + else: + raise SIRCError('Bit Low Timeout') + try: + _, low_ss, low_es, _ = self.read_pulse(not self.active, PAUSE_USEC) + good = True + except SIRCError: + low_es = high_es + int(PAUSE_USEC * self.snum_per_us) + good = False + self.putg(high_ss, low_es, Ann.BIT, ['{}'.format(bit)]) + return bit, high_ss, low_es, good + + def read_signal(self): + # Start code + try: + _, agc_ss, agc_es, _ = self.read_pulse(self.active, AGC_USEC) + _, pause_ss, pause_es, _ = self.read_pulse(not self.active, PAUSE_USEC) + except SIRCError: + raise SIRCErrorSilent('not an SIRC message') + self.putg(agc_ss, agc_es, Ann.AGC, ['AGC', 'A']) + self.putg(pause_ss, pause_es, Ann.PAUSE, ['Pause', 'P']) + self.putg(agc_ss, pause_es, Ann.START, ['Start', 'S']) + + # Read bits + bits = [] + while True: + bit, ss, es, good = self.read_bit() + bits.append((bit, ss, es)) + if len(bits) > 20: + raise SIRCError('too many bits') + if not good: + if len(bits) == 12: + command = bits[0:7] + address = bits[7:12] + extended = [] + elif len(bits) == 15: + command = bits[0:7] + address = bits[7:15] + extended = [] + elif len(bits) == 20: + command = bits[0:7] + address = bits[7:12] + extended = bits[12:20] + else: + raise SIRCError('incorrect bits count {}'.format(len(bits))) + break + + command_num = bitpack_lsb(command, 0) + address_num = bitpack_lsb(address, 0) + command_str = '0x{:02X}'.format(command_num) + address_str = '0x{:02X}'.format(address_num) + self.putg(command[0][1], command[-1][2], Ann.CMD, [ + 'Command: {}'.format(command_str), + 'C:{}'.format(command_str), + ]) + self.putg(address[0][1], address[-1][2], Ann.ADDR, [ + 'Address: {}'.format(address_str), + 'A:{}'.format(address_str), + ]) + extended_num = None + if extended: + extended_num = bitpack_lsb(extended, 0) + extended_str = '0x{:02X}'.format(extended_num) + self.putg(extended[0][1], extended[-1][2], Ann.EXT, [ + 'Extended: {}'.format(extended_str), + 'E:{}'.format(extended_str), + ]) + return address_num, command_num, extended_num, bits[0][1], bits[-1][2] + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + + unknown = (['Unknown Device: ', 'UNK: '], {}) + while True: + e = 'h' if self.active else 'l' + _, _, frame_ss, _ = self.wait_wrap([{0: e}], None) + try: + addr, cmd, ext, payload_ss, payload_es = self.read_signal() + names, cmds = ADDRESSES.get((addr, ext), unknown) + text = cmds.get(cmd, 'Unknown') + self.putg(frame_ss, payload_es, Ann.REMOTE, [ + n + text for n in names + ]) + except SIRCErrorSilent as e: + pass + except SIRCError as e: + self.putg(frame_ss, self.samplenum, Ann.WARN, [ + 'Error: {}'.format(e), + 'Error', + 'E', + ]) diff --git a/libsigrokdecode4DSL/decoders/jitter/__init__.py b/libsigrokdecode4DSL/decoders/jitter/__init__.py new file mode 100644 index 00000000..3394ad75 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/jitter/__init__.py @@ -0,0 +1,29 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Sebastien Bourdelin +## +## 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, see . +## + +''' +This protocol decoder retrieves the timing jitter between two digital signals. + +It allows to define a clock source channel and a resulting signal channel. + +Each time a significant edge is detected in the clock source, we calculate the +elapsed time before the resulting signal answers and report the timing jitter. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/jitter/pd.py b/libsigrokdecode4DSL/decoders/jitter/pd.py new file mode 100644 index 00000000..8ea1aa67 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/jitter/pd.py @@ -0,0 +1,198 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Sebastien Bourdelin +## +## 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, see . +## + +import sigrokdecode as srd + +# Helper dictionary for edge detection. +edge_detector = { + 'rising': lambda x, y: bool(not x and y), + 'falling': lambda x, y: bool(x and not y), + 'both': lambda x, y: bool(x ^ y), +} + +class SamplerateError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = 'jitter' + name = 'Jitter' + longname = 'Timing jitter calculation' + desc = 'Retrieves the timing jitter between two digital signals.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Clock/timing', 'Util'] + channels = ( + {'id': 'clk', 'name': 'Clock', 'desc': 'Clock reference channel'}, + {'id': 'sig', 'name': 'Resulting signal', 'desc': 'Resulting signal controlled by the clock'}, + ) + options = ( + {'id': 'clk_polarity', 'desc': 'Clock edge polarity', + 'default': 'rising', 'values': ('rising', 'falling', 'both')}, + {'id': 'sig_polarity', 'desc': 'Resulting signal edge polarity', + 'default': 'rising', 'values': ('rising', 'falling', 'both')}, + ) + annotations = ( + ('jitter', 'Jitter value'), + ('clk_missed', 'Clock missed'), + ('sig_missed', 'Signal missed'), + ) + annotation_rows = ( + ('jitter', 'Jitter values', (0,)), + ('clk_missed', 'Clock missed', (1,)), + ('sig_missed', 'Signal missed', (2,)), + ) + binary = ( + ('ascii-float', 'Jitter values as newline-separated ASCII floats'), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.state = 'CLK' + self.samplerate = None + self.oldclk, self.oldsig = 0, 0 + self.clk_start = None + self.sig_start = None + self.clk_missed = 0 + self.sig_missed = 0 + + def start(self): + self.clk_edge = edge_detector[self.options['clk_polarity']] + self.sig_edge = edge_detector[self.options['sig_polarity']] + self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_binary = self.register(srd.OUTPUT_BINARY) + self.out_clk_missed = self.register(srd.OUTPUT_META, + meta=(int, 'Clock missed', 'Clock transition missed')) + self.out_sig_missed = self.register(srd.OUTPUT_META, + meta=(int, 'Signal missed', 'Resulting signal transition missed')) + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + # Helper function for jitter time annotations. + def putx(self, delta): + # Adjust granularity. + if delta == 0 or delta >= 1: + delta_s = '%.1fs' % (delta) + elif delta <= 1e-12: + delta_s = '%.1ffs' % (delta * 1e15) + elif delta <= 1e-9: + delta_s = '%.1fps' % (delta * 1e12) + elif delta <= 1e-6: + delta_s = '%.1fns' % (delta * 1e9) + elif delta <= 1e-3: + delta_s = '%.1fμs' % (delta * 1e6) + else: + delta_s = '%.1fms' % (delta * 1e3) + + self.put(self.clk_start, self.sig_start, self.out_ann, [0, [delta_s]]) + + # Helper function for ASCII float jitter values (one value per line). + def putb(self, delta): + if delta is None: + return + # Format the delta to an ASCII float value terminated by a newline. + x = str(delta) + '\n' + self.put(self.clk_start, self.sig_start, self.out_binary, + [0, x.encode('UTF-8')]) + + # Helper function for missed clock and signal annotations. + def putm(self, data): + self.put(self.samplenum, self.samplenum, self.out_ann, data) + + def handle_clk(self, clk, sig): + if self.clk_start == self.samplenum: + # Clock transition already treated. + # We have done everything we can with this sample. + return True + + if self.clk_edge(self.oldclk, clk): + # Clock edge found. + # We note the sample and move to the next state. + self.clk_start = self.samplenum + self.state = 'SIG' + return False + else: + if self.sig_start is not None \ + and self.sig_start != self.samplenum \ + and self.sig_edge(self.oldsig, sig): + # If any transition in the resulting signal + # occurs while we are waiting for a clock, + # we increase the missed signal counter. + self.sig_missed += 1 + self.put(self.samplenum, self.samplenum, self.out_sig_missed, self.sig_missed) + self.putm([2, ['Missed signal', 'MS']]) + # No clock edge found, we have done everything we + # can with this sample. + return True + + def handle_sig(self, clk, sig): + if self.sig_start == self.samplenum: + # Signal transition already treated. + # We have done everything we can with this sample. + return True + + if self.sig_edge(self.oldsig, sig): + # Signal edge found. + # We note the sample, calculate the jitter + # and move to the next state. + self.sig_start = self.samplenum + self.state = 'CLK' + # Calculate and report the timing jitter. + delta = (self.sig_start - self.clk_start) / self.samplerate + self.putx(delta) + self.putb(delta) + return False + else: + if self.clk_start != self.samplenum \ + and self.clk_edge(self.oldclk, clk): + # If any transition in the clock signal + # occurs while we are waiting for a resulting + # signal, we increase the missed clock counter. + self.clk_missed += 1 + self.put(self.samplenum, self.samplenum, self.out_clk_missed, self.clk_missed) + self.putm([1, ['Missed clock', 'MC']]) + # No resulting signal edge found, we have done + # everything we can with this sample. + return True + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + while True: + # Wait for a transition on CLK and/or SIG. + (clk, sig) = self.wait([{0: 'e'}, {1: 'e'}]) + + # State machine: + # For each sample we can move 2 steps forward in the state machine. + while True: + # Clock state has the lead. + if self.state == 'CLK': + if self.handle_clk(clk, sig): + break + if self.state == 'SIG': + if self.handle_sig(clk, sig): + break + + # Save current CLK/SIG values for the next round. + self.oldclk, self.oldsig = clk, sig diff --git a/libsigrokdecode4DSL/decoders/jtag/__init__.py b/libsigrokdecode4DSL/decoders/jtag/__init__.py new file mode 100644 index 00000000..51bb6299 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/jtag/__init__.py @@ -0,0 +1,30 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +''' +JTAG (Joint Test Action Group), a.k.a. "IEEE 1149.1: Standard Test Access Port +and Boundary-Scan Architecture", is a protocol used for testing, debugging, +and flashing various digital ICs. + +Details: +https://en.wikipedia.org/wiki/Joint_Test_Action_Group +http://focus.ti.com/lit/an/ssya002c/ssya002c.pdf +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/jtag/pd.py b/libsigrokdecode4DSL/decoders/jtag/pd.py new file mode 100644 index 00000000..e9c629b6 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/jtag/pd.py @@ -0,0 +1,289 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012-2015 Uwe Hermann +## Copyright (C) 2019 DreamSourceLab +## +## Version: +## Modified by Shiqiu Nie(369614718@qq.com) +## Date: 2017-01-11 +## Descript: +## 1. 2017-01-10 Fixed TDI/TDO data decode, when JTAG TAP run into +## SHIFT-IR/SHIFT-DR status,the first bit is not a valid bit. +## 2. 2017-01-11 Fixed decode when shift only one bit. +## +## 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, see . +## + +import sigrokdecode as srd + +''' +OUTPUT_PYTHON format: + +Packet: +[, ] + +: + - 'NEW STATE': is the new state of the JTAG state machine. + Valid values: 'TEST-LOGIC-RESET', 'RUN-TEST/IDLE', 'SELECT-DR-SCAN', + 'CAPTURE-DR', 'SHIFT-DR', 'EXIT1-DR', 'PAUSE-DR', 'EXIT2-DR', 'UPDATE-DR', + 'SELECT-IR-SCAN', 'CAPTURE-IR', 'SHIFT-IR', 'EXIT1-IR', 'PAUSE-IR', + 'EXIT2-IR', 'UPDATE-IR'. + - 'IR TDI': Bitstring that was clocked into the IR register. + - 'IR TDO': Bitstring that was clocked out of the IR register. + - 'DR TDI': Bitstring that was clocked into the DR register. + - 'DR TDO': Bitstring that was clocked out of the DR register. + +All bitstrings are a list consisting of two items. The first is a sequence +of '1' and '0' characters (the right-most character is the LSB. Example: +'01110001', where 1 is the LSB). The second item is a list of ss/es values +for each bit that is in the bitstring. +''' + +jtag_states = [ + # Intro "tree" + 'TEST-LOGIC-RESET', 'RUN-TEST/IDLE', + # DR "tree" + 'SELECT-DR-SCAN', 'CAPTURE-DR', 'UPDATE-DR', 'PAUSE-DR', + 'SHIFT-DR', 'EXIT1-DR', 'EXIT2-DR', + # IR "tree" + 'SELECT-IR-SCAN', 'CAPTURE-IR', 'UPDATE-IR', 'PAUSE-IR', + 'SHIFT-IR', 'EXIT1-IR', 'EXIT2-IR', +] + +class Decoder(srd.Decoder): + api_version = 3 + id = 'jtag' + name = 'JTAG' + longname = 'Joint Test Action Group (IEEE 1149.1)' + desc = 'Protocol for testing, debugging, and flashing ICs.' + license = 'gplv2+' + inputs = ['logic'] + outputs = ['jtag'] + tags = ['Debug/trace'] + channels = ( + {'id': 'tdi', 'name': 'TDI', 'desc': 'Test data input'}, + {'id': 'tdo', 'name': 'TDO', 'desc': 'Test data output'}, + {'id': 'tck', 'name': 'TCK', 'desc': 'Test clock'}, + {'id': 'tms', 'name': 'TMS', 'desc': 'Test mode select'}, + ) + optional_channels = ( + {'id': 'trst', 'name': 'TRST#', 'desc': 'Test reset'}, + {'id': 'srst', 'name': 'SRST#', 'desc': 'System reset'}, + {'id': 'rtck', 'name': 'RTCK', 'desc': 'Return clock signal'}, + ) + annotations = tuple([tuple([s.lower(), s]) for s in jtag_states]) + ( \ + ('bit-tdi', 'Bit (TDI)'), + ('bit-tdo', 'Bit (TDO)'), + ('bitstring-tdi', 'Bitstring (TDI)'), + ('bitstring-tdo', 'Bitstring (TDO)'), + ) + annotation_rows = ( + ('bits-tdi', 'Bits (TDI)', (16,)), + ('bits-tdo', 'Bits (TDO)', (17,)), + ('bitstrings-tdi', 'Bitstring (TDI)', (18,)), + ('bitstrings-tdo', 'Bitstring (TDO)', (19,)), + ('states', 'States', tuple(range(15 + 1))), + ) + + def __init__(self): + self.reset() + + def reset(self): + # self.state = 'TEST-LOGIC-RESET' + self.state = 'RUN-TEST/IDLE' + self.oldstate = None + self.bits_tdi = [] + self.bits_tdo = [] + self.bits_samplenums_tdi = [] + self.bits_samplenums_tdo = [] + self.ss_item = self.es_item = None + self.ss_bitstring = self.es_bitstring = None + self.saved_item = None + self.first = True + self.first_bit = True + self.bits_cnt = 0 + self.data_ready = False + + def start(self): + self.out_python = self.register(srd.OUTPUT_PYTHON) + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + self.put(self.ss_item, self.es_item, self.out_ann, data) + + def putp(self, data): + self.put(self.ss_item, self.es_item, self.out_python, data) + + def putx_bs(self, data): + self.put(self.ss_bitstring, self.es_bitstring, self.out_ann, data) + + def putp_bs(self, data): + self.put(self.ss_bitstring, self.es_bitstring, self.out_python, data) + + def advance_state_machine(self, tms): + self.oldstate = self.state + + # Intro "tree" + if self.state == 'TEST-LOGIC-RESET': + self.state = 'TEST-LOGIC-RESET' if (tms) else 'RUN-TEST/IDLE' + elif self.state == 'RUN-TEST/IDLE': + self.state = 'SELECT-DR-SCAN' if (tms) else 'RUN-TEST/IDLE' + + # DR "tree" + elif self.state == 'SELECT-DR-SCAN': + self.state = 'SELECT-IR-SCAN' if (tms) else 'CAPTURE-DR' + elif self.state == 'CAPTURE-DR': + self.state = 'EXIT1-DR' if (tms) else 'SHIFT-DR' + elif self.state == 'SHIFT-DR': + self.state = 'EXIT1-DR' if (tms) else 'SHIFT-DR' + elif self.state == 'EXIT1-DR': + self.state = 'UPDATE-DR' if (tms) else 'PAUSE-DR' + elif self.state == 'PAUSE-DR': + self.state = 'EXIT2-DR' if (tms) else 'PAUSE-DR' + elif self.state == 'EXIT2-DR': + self.state = 'UPDATE-DR' if (tms) else 'SHIFT-DR' + elif self.state == 'UPDATE-DR': + self.state = 'SELECT-DR-SCAN' if (tms) else 'RUN-TEST/IDLE' + + # IR "tree" + elif self.state == 'SELECT-IR-SCAN': + self.state = 'TEST-LOGIC-RESET' if (tms) else 'CAPTURE-IR' + elif self.state == 'CAPTURE-IR': + self.state = 'EXIT1-IR' if (tms) else 'SHIFT-IR' + elif self.state == 'SHIFT-IR': + self.state = 'EXIT1-IR' if (tms) else 'SHIFT-IR' + elif self.state == 'EXIT1-IR': + self.state = 'UPDATE-IR' if (tms) else 'PAUSE-IR' + elif self.state == 'PAUSE-IR': + self.state = 'EXIT2-IR' if (tms) else 'PAUSE-IR' + elif self.state == 'EXIT2-IR': + self.state = 'UPDATE-IR' if (tms) else 'SHIFT-IR' + elif self.state == 'UPDATE-IR': + self.state = 'SELECT-DR-SCAN' if (tms) else 'RUN-TEST/IDLE' + + def handle_rising_tck_edge(self, tdi, tdo, tck, tms, trst, srst, rtck): + # Rising TCK edges always advance the state machine. + self.advance_state_machine(tms) + + if self.first: + # Save the start sample and item for later (no output yet). + self.ss_item = self.samplenum + self.first = False + else: + # Output the saved item (from the last CLK edge to the current). + self.es_item = self.samplenum + # Output the old state (from last rising TCK edge to current one). + self.putx([jtag_states.index(self.oldstate), [self.oldstate]]) + self.putp(['NEW STATE', self.state]) + + # Upon SHIFT-IR/SHIFT-DR collect the current TDI/TDO values. + if self.state.startswith('SHIFT-'): + #if self.first_bit: + #self.ss_bitstring = self.samplenum + # self.first_bit = False + + #else: + if self.bits_cnt > 0: + if self.bits_cnt == 1: + self.ss_bitstring = self.samplenum + + if self.bits_cnt > 1: + self.putx([16, [str(self.bits_tdi[0])]]) + self.putx([17, [str(self.bits_tdo[0])]]) + # Use self.samplenum as ES of the previous bit. + self.bits_samplenums_tdi[0][1] = self.samplenum + self.bits_samplenums_tdo[0][1] = self.samplenum + + self.bits_tdi.insert(0, tdi) + self.bits_tdo.insert(0, tdo) + + # Use self.samplenum as SS of the current bit. + self.bits_samplenums_tdi.insert(0, [self.samplenum, -1]) + self.bits_samplenums_tdo.insert(0, [self.samplenum, -1]) + + self.bits_cnt = self.bits_cnt + 1 + + # Output all TDI/TDO bits if we just switched from SHIFT-* to EXIT1-*. + if self.oldstate.startswith('SHIFT-') and \ + self.state.startswith('EXIT1-'): + + #self.es_bitstring = self.samplenum + if self.bits_cnt > 0: + if self.bits_cnt == 1: # Only shift one bit + self.ss_bitstring = self.samplenum + self.bits_tdi.insert(0, tdi) + self.bits_tdo.insert(0, tdo) + ## Use self.samplenum as SS of the current bit. + self.bits_samplenums_tdi.insert(0, [self.samplenum, -1]) + self.bits_samplenums_tdo.insert(0, [self.samplenum, -1]) + else: + ### ---------------------------------------------------------------- + self.putx([16, [str(self.bits_tdi[0])]]) + self.putx([17, [str(self.bits_tdo[0])]]) + ### Use self.samplenum as ES of the previous bit. + self.bits_samplenums_tdi[0][1] = self.samplenum + self.bits_samplenums_tdo[0][1] = self.samplenum + + self.bits_tdi.insert(0, tdi) + self.bits_tdo.insert(0, tdo) + + ## Use self.samplenum as SS of the current bit. + self.bits_samplenums_tdi.insert(0, [self.samplenum, -1]) + self.bits_samplenums_tdo.insert(0, [self.samplenum, -1]) + ## ---------------------------------------------------------------- + + self.data_ready = True + + self.first_bit = True + self.bits_cnt = 0 + if self.oldstate.startswith('EXIT'):# and \ + #self.state.startswith('PAUSE-'): + if self.data_ready: + self.data_ready = False + self.es_bitstring = self.samplenum + t = self.state[-2:] + ' TDI' + b = ''.join(map(str, self.bits_tdi)) + h = ' (0x%X' % int('0b' + b, 2) + ')' + s = t + ': ' + h + ', ' + str(len(self.bits_tdi)) + ' bits' #b + + self.putx_bs([18, [s]]) + self.bits_samplenums_tdi[0][1] = self.samplenum # ES of last bit. + self.putp_bs([t, [b, self.bits_samplenums_tdi]]) + self.putx([16, [str(self.bits_tdi[0])]]) # Last bit. + self.bits_tdi = [] + self.bits_samplenums_tdi = [] + + t = self.state[-2:] + ' TDO' + b = ''.join(map(str, self.bits_tdo)) + h = ' (0x%X' % int('0b' + b, 2) + ')' + s = t + ': ' + h + ', ' + str(len(self.bits_tdo)) + ' bits' #+ b + self.putx_bs([19, [s]]) + self.bits_samplenums_tdo[0][1] = self.samplenum # ES of last bit. + self.putp_bs([t, [b, self.bits_samplenums_tdo]]) + self.putx([17, [str(self.bits_tdo[0])]]) # Last bit. + self.bits_tdo = [] + self.bits_samplenums_tdo = [] + + #self.first_bit = True + #self.bits_cnt = 0 + + #self.ss_bitstring = self.samplenum + + self.ss_item = self.samplenum + + def decode(self): + while True: + # Wait for a rising edge on TCK. + (tdi, tdo, tck, tms, trst, srst, rtck) = self.wait({2: 'r'}) + self.handle_rising_tck_edge(tdi, tdo, tck, tms, trst, srst, rtck) diff --git a/libsigrokdecode4DSL/decoders/jtag_ejtag/__init__.py b/libsigrokdecode4DSL/decoders/jtag_ejtag/__init__.py new file mode 100644 index 00000000..1c66dcd5 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/jtag_ejtag/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Vladislav Ivanov +## +## 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, see . +## + +''' +This decoder stacks on top of the 'jtag' PD and decodes JTAG data specific +to the MIPS EJTAG protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/jtag_ejtag/pd.py b/libsigrokdecode4DSL/decoders/jtag_ejtag/pd.py new file mode 100644 index 00000000..f16f0b4e --- /dev/null +++ b/libsigrokdecode4DSL/decoders/jtag_ejtag/pd.py @@ -0,0 +1,408 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Vladislav Ivanov +## +## 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, see . +## + +import sigrokdecode as srd +from common.srdhelper import bin2int + +class Instruction(object): + IDCODE = 0x01 + IMPCODE = 0x03 + ADDRESS = 0x08 + DATA = 0x09 + CONTROL = 0x0A + ALL = 0x0B + EJTAGBOOT = 0x0C + NORMALBOOT = 0x0D + FASTDATA = 0x0E + TCBCONTROLA = 0x10 + TCBCONTROLB = 0x11 + TCBDATA = 0x12 + TCBCONTROLC = 0x13 + PCSAMPLE = 0x14 + TCBCONTROLD = 0x15 + TCBCONTROLE = 0x16 + +class State(object): + RESET = 0 + DEVICE_ID = 1 + IMPLEMENTATION = 2 + DATA = 3 + ADDRESS = 4 + CONTROL = 5 + FASTDATA = 6 + PC_SAMPLE = 7 + BYPASS = 8 + +class ControlReg(object): + PRACC = (1 << 18) + PRNW = (1 << 19) + +class Ann(object): + INSTRUCTION = 0 + REGISTER = 1 + CONTROL_FIELD_IN = 10 + CONTROL_FIELD_OUT = 11 + PRACC = 12 + +ejtag_insn = { + 0x00: ['Free', 'Boundary scan'], + 0x01: ['IDCODE', 'Select Device Identification (ID) register'], + 0x02: ['Free', 'Boundary scan'], + 0x03: ['IMPCODE', 'Select Implementation register'], + 0x08: ['ADDRESS', 'Select Address register'], + 0x09: ['DATA', 'Select Data register'], + 0x0A: ['CONTROL', 'Select EJTAG Control register'], + 0x0B: ['ALL', 'Select the Address, Data and EJTAG Control registers'], + 0x0C: ['EJTAGBOOT', 'Fetch code from the debug exception vector after reset'], + 0x0D: ['NORMALBOOT', 'Execute the reset handler after reset'], + 0x0E: ['FASTDATA', 'Select the Data and Fastdata registers'], + 0x0F: ['Reserved', 'Reserved'], + 0x10: ['TCBCONTROLA', 'Select the control register TCBTraceControl'], + 0x11: ['TCBCONTROLB', 'Selects trace control block register B'], + 0x12: ['TCBDATA', 'Access the registers specified by TCBCONTROLB'], + 0x13: ['TCBCONTROLC', 'Select trace control block register C'], + 0x14: ['PCSAMPLE', 'Select the PCsample register'], + 0x15: ['TCBCONTROLD', 'Select trace control block register D'], + 0x16: ['TCBCONTROLE', 'Select trace control block register E'], + 0x17: ['FDC', 'Select Fast Debug Channel'], + 0x1C: ['Free', 'Boundary scan'], +} + +ejtag_reg = { + 0x00: 'RESET', + 0x01: 'DEVICE_ID', + 0x02: 'IMPLEMENTATION', + 0x03: 'DATA', + 0x04: 'ADDRESS', + 0x05: 'CONTROL', + 0x06: 'FASTDATA', + 0x07: 'PC_SAMPLE', + 0x08: 'BYPASS', +} + +ejtag_control_reg = [ + [31, 31, 'Rocc', [ + # Read + ['No reset ocurred', 'Reset ocurred'], + # Write + ['Acknowledge reset', 'No effect'], + ]], + [30, 29, 'Psz', [ + ['Access: byte', 'Access: halfword', 'Access: word', 'Access: triple'], + ]], + [23, 23, 'VPED', [ + ['VPE disabled', 'VPE enabled'], + ]], + [22, 22, 'Doze', [ + ['Processor is not in low-power mode', 'Processor is in low-power mode'], + ]], + [21, 21, 'Halt', [ + ['Internal system bus clock is running', 'Internal system bus clock is stopped'], + ]], + [20, 20, 'Per Rst', [ + ['No peripheral reset applied', 'Peripheral reset applied'], + ['Deassert peripheral reset', 'Assert peripheral reset'], + ]], + [19, 19, 'PRn W', [ + ['Read processor access', 'Write processor access'], + ]], + [18, 18, 'Pr Acc', [ + ['No pending processor access', 'Pending processor access'], + ['Finish processor access', 'Don\'t finish processor access'], + ]], + [16, 16, 'Pr Rst', [ + ['No processor reset applied', 'Processor reset applied'], + ['Deassert processor reset', 'Assert system reset'], + ]], + [15, 15, 'Prob En', [ + ['Probe will not serve processor accesses', 'Probe will service processor accesses'], + ]], + [14, 14, 'Prob Trap', [ + ['Default location', 'DMSEG fetch'], + ['Set to default location', 'Set to DMSEG fetch'], + ]], + [13, 13, 'ISA On Debug', [ + ['MIPS32/MIPS64 ISA', 'microMIPS ISA'], + ['Set to MIPS32/MIPS64 ISA', 'Set to microMIPS ISA'], + ]], + [12, 12, 'EJTAG Brk', [ + ['No pending debug interrupt', 'Pending debug interrupt'], + ['No effect', 'Request debug interrupt'], + ]], + [3, 3, 'DM', [ + ['Not in debug mode', 'In debug mode'], + ]], +] + +ejtag_state_map = { + Instruction.IDCODE: State.DEVICE_ID, + Instruction.IMPCODE: State.IMPLEMENTATION, + Instruction.DATA: State.DATA, + Instruction.ADDRESS: State.ADDRESS, + Instruction.CONTROL: State.CONTROL, + Instruction.FASTDATA: State.FASTDATA, +} + +class RegData(object): + def __init__(self): + self.ss = None + self.es = None + self.data = None + +class LastData(object): + def __init__(self): + self.data_in = RegData() + self.data_out = RegData() + +class PraccState(object): + def reset(self): + self.address_in = None + self.address_out = None + self.data_in = None + self.data_out = None + self.write = False + self.ss = 0 + self.es = 0 + + def __init__(self): + self.reset() + +regs_items = { + 'ann': tuple([tuple([s.lower(), s]) for s in list(ejtag_reg.values())]), + 'rows_range': tuple(range(1, 1 + 9)), +} + +class Decoder(srd.Decoder): + api_version = 3 + id = 'jtag_ejtag' + name = 'JTAG / EJTAG' + longname = 'Joint Test Action Group / EJTAG (MIPS)' + desc = 'MIPS EJTAG protocol.' + license = 'gplv2+' + inputs = ['jtag'] + outputs = [] + tags = ['Debug/trace'] + annotations = ( + ('instruction', 'Instruction'), + ) + regs_items['ann'] + ( + ('control_field_in', 'Control field in'), + ('control_field_out', 'Control field out'), + ('pracc', 'PrAcc'), + ) + annotation_rows = ( + ('instructions', 'Instructions', (0,)), + ('regs', 'Registers', regs_items['rows_range']), + ('control_fields_in', 'Control fields in', (10,)), + ('control_fields_out', 'Control fields out', (11,)), + ('pracc', 'PrAcc', (12,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.state = State.RESET + self.pracc_state = PraccState() + + def put_current(self, data): + self.put(self.ss, self.es, self.out_ann, data) + + def put_at(self, ss: int, es: int, data): + self.put(ss, es, self.out_ann, data) + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def select_reg(self, ir_value: int): + self.state = ejtag_state_map.get(ir_value, State.RESET) + + def parse_pracc(self): + control_in = bin2int(self.last_data['in']['data'][0]) + control_out = bin2int(self.last_data['out']['data'][0]) + + # Check if JTAG master acknowledges a pending PrAcc. + if not ((not (control_in & ControlReg.PRACC)) and \ + (control_out & ControlReg.PRACC)): + return + + ss, es = self.pracc_state.ss, self.pracc_state.es + pracc_write = (control_out & ControlReg.PRNW) != 0 + + s = 'PrAcc: ' + s += 'Store' if pracc_write else 'Load/Fetch' + + if pracc_write: + if self.pracc_state.address_out is not None: + s += ', A:' + ' 0x{:08X}'.format(self.pracc_state.address_out) + if self.pracc_state.data_out is not None: + s += ', D:' + ' 0x{:08X}'.format(self.pracc_state.data_out) + else: + if self.pracc_state.address_out is not None: + s += ', A:' + ' 0x{:08X}'.format(self.pracc_state.address_out) + if self.pracc_state.data_in is not None: + s += ', D:' + ' 0x{:08X}'.format(self.pracc_state.data_in) + + self.pracc_state.reset() + + self.put_at(ss, es, [Ann.PRACC, [s]]) + + def parse_control_reg(self, ann): + reg_write = ann == Ann.CONTROL_FIELD_IN + control_bit_positions = [] + data_select = 'in' if (reg_write) else 'out' + + control_bit_positions = self.last_data[data_select]['data'][1] + control_data = self.last_data[data_select]['data'][0] + + # Annotate control register fields. + for field in ejtag_control_reg: + start_bit = 31 - field[1] + end_bit = 31 - field[0] + comment = field[2] + value_descriptions = [] + + if reg_write: + if len(field[3]) < 2: + continue + value_descriptions = field[3][1] + else: + value_descriptions = field[3][0] + + ss = control_bit_positions[start_bit][0] + es = control_bit_positions[end_bit][1] + + value_str = control_data[end_bit : start_bit + 1] + value_index = bin2int(value_str) + + short_desc = comment + ': ' + value_str + long_desc = value_descriptions[value_index] if len(value_descriptions) > value_index else '?' + + self.put_at(ss, es, [ann, [long_desc, short_desc]]) + + def check_last_data(self): + if not hasattr(self, 'last_data'): + self.last_data = {'in': {}, 'out': {}} + + def handle_fastdata(self, val, ann): + spracc_write_desc = { + 0: ['0', 'SPrAcc: 0', 'Request completion of Fastdata access'], + 1: ['1', 'SPrAcc: 1', 'No effect'], + } + spracc_read_desc = { + 0: ['0', 'SPrAcc: 0', 'Fastdata access failure'], + 1: ['1', 'SPrAcc: 1', 'Successful completion of Fastdata access'], + } + + bitstring = val[0] + bit_sample_pos = val[1] + fastdata_state = bitstring[32] + data = bin2int(bitstring[0:32]) + + fastdata_bit_pos = bit_sample_pos[32] + data_pos = [bit_sample_pos[31][0], bit_sample_pos[0][1]] + + ss_fastdata, es_fastdata = fastdata_bit_pos + ss_data, es_data = data_pos + + display_data = [ann, ['0x{:08X}'.format(data)]] + spracc_display_data = [] + + if ann == Ann.CONTROL_FIELD_IN: + spracc_display_data = [ann, spracc_write_desc[int(fastdata_state)]] + elif ann == Ann.CONTROL_FIELD_OUT: + spracc_display_data = [ann, spracc_read_desc[int(fastdata_state)]] + + self.put_at(ss_fastdata, es_fastdata, spracc_display_data) + self.put_at(ss_data, es_data, display_data) + + def handle_dr_tdi(self, val): + value = bin2int(val[0]) + self.check_last_data() + self.last_data['in'] = {'ss': self.ss, 'es': self.es, 'data': val} + + self.pracc_state.ss, self.pracc_state.es = self.ss, self.es + + if self.state == State.ADDRESS: + self.pracc_state.address_in = value + elif self.state == State.DATA: + self.pracc_state.data_in = value + elif self.state == State.FASTDATA: + self.handle_fastdata(val, Ann.CONTROL_FIELD_IN) + + def handle_dr_tdo(self, val): + value = bin2int(val[0]) + self.check_last_data() + self.last_data['out'] = {'ss': self.ss, 'es': self.es, 'data': val} + if self.state == State.ADDRESS: + self.pracc_state.address_out = value + elif self.state == State.DATA: + self.pracc_state.data_out = value + elif self.state == State.FASTDATA: + self.handle_fastdata(val, Ann.CONTROL_FIELD_OUT) + + def handle_ir_tdi(self, val): + code = bin2int(val[0]) + hexval = '0x{:02X}'.format(code) + if code in ejtag_insn: + # Format instruction name. + insn = ejtag_insn[code] + s_short = insn[0] + s_long = insn[0] + ': ' + insn[1] + ' (' + hexval + ')' + # Display it and select data register. + self.put_current([Ann.INSTRUCTION, [s_long, s_short]]) + else: + self.put_current([Ann.INSTRUCTION, [hexval, 'IR TDI ({})'.format(hexval)]]) + self.select_reg(code) + + def handle_new_state(self, new_state): + if new_state != 'UPDATE-DR' or not hasattr(self, 'last_data'): + return + + if self.state == State.RESET: + return + + reg_name = ejtag_reg[self.state] + ann_index = Ann.REGISTER + self.state + display_data = [ann_index, [reg_name]] + self.put_at(self.last_data['in']['ss'], self.last_data['in']['es'], display_data) + + if self.state == State.CONTROL: + control_bit_positions = self.last_data['in']['data'][1] + bit_count = len(control_bit_positions) + # Check if control register data length is correct. + if bit_count != 32: + error_display = [Ann.REGISTER, ['Error: length != 32']] + self.put_at(self.last_data['in']['ss'], self.last_data['in']['es'], error_display) + return + self.parse_control_reg(Ann.CONTROL_FIELD_IN) + self.parse_control_reg(Ann.CONTROL_FIELD_OUT) + self.parse_pracc() + + def decode(self, ss: int, es: int, data): + cmd, val = data + self.ss, self.es = ss, es + + if cmd == 'IR TDI': + self.handle_ir_tdi(val) + elif cmd == 'DR TDI': + self.handle_dr_tdi(val) + elif cmd == 'DR TDO': + self.handle_dr_tdo(val) + elif cmd == 'NEW STATE': + self.handle_new_state(val) diff --git a/libsigrokdecode4DSL/decoders/jtag_stm32/__init__.py b/libsigrokdecode4DSL/decoders/jtag_stm32/__init__.py new file mode 100644 index 00000000..bf69e8e0 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/jtag_stm32/__init__.py @@ -0,0 +1,29 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +''' +This decoder stacks on top of the 'jtag' PD and decodes JTAG data specific to +the STM32 microcontroller series. + +Details: +https://en.wikipedia.org/wiki/STM32 +http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/REFERENCE_MANUAL/CD00171190.pdf (e.g. chapter 31.7: "JTAG debug port") +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/jtag_stm32/pd.py b/libsigrokdecode4DSL/decoders/jtag_stm32/pd.py new file mode 100644 index 00000000..82558b82 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/jtag_stm32/pd.py @@ -0,0 +1,269 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012-2015 Uwe Hermann +## +## 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, see . +## + +import sigrokdecode as srd + +# JTAG debug port data registers (in IR[3:0]) and their sizes (in bits) +# Note: The ARM DAP-DP is not IEEE 1149.1 (JTAG) compliant (as per ARM docs), +# as it does not implement the EXTEST, SAMPLE, and PRELOAD instructions. +# Instead, BYPASS is decoded for any of these instructions. +ir = { + '1111': ['BYPASS', 1], # Bypass register + '1110': ['IDCODE', 32], # ID code register + '1010': ['DPACC', 35], # Debug port access register + '1011': ['APACC', 35], # Access port access register + '1000': ['ABORT', 35], # Abort register # TODO: 32 bits? Datasheet typo? +} + +# Boundary scan data registers (in IR[8:4]) and their sizes (in bits) +bs_ir = { + '11111': ['BYPASS', 1], # Bypass register +} + +# ARM Cortex-M3 r1p1-01rel0 ID code +cm3_idcode = 0x3ba00477 + +# http://infocenter.arm.com/help/topic/com.arm.doc.ddi0413c/Chdjibcg.html +cm3_idcode_ver = { + 0x3: 'JTAG-DP', + 0x2: 'SW-DP', +} +cm3_idcode_part = { + 0xba00: 'JTAG-DP', + 0xba10: 'SW-DP', +} + +# http://infocenter.arm.com/help/topic/com.arm.doc.faqs/ka14408.html +jedec_id = { + 5: { + 0x3b: 'ARM Ltd.', + }, +} + +# JTAG ID code in the STM32F10xxx BSC (boundary scan) TAP +jtag_idcode = { + 0x06412041: 'Low-density device, rev. A', + 0x06410041: 'Medium-density device, rev. A', + 0x16410041: 'Medium-density device, rev. B/Z/Y', + 0x06414041: 'High-density device, rev. A/Z/Y', + 0x06430041: 'XL-density device, rev. A', + 0x06418041: 'Connectivity-line device, rev. A/Z', +} + +# ACK[2:0] in the DPACC/APACC registers (unlisted values are reserved) +ack_val = { + '001': 'WAIT', + '010': 'OK/FAULT', +} + +# 32bit debug port registers (addressed via A[3:2]) +dp_reg = { + '00': 'Reserved', # Must be kept at reset value + '01': 'DP CTRL/STAT', + '10': 'DP SELECT', + '11': 'DP RDBUFF', +} + +# APB-AP registers (each of them 32 bits wide) +apb_ap_reg = { + 0x00: ['CSW', 'Control/status word'], + 0x04: ['TAR', 'Transfer address'], + # 0x08: Reserved SBZ + 0x0c: ['DRW', 'Data read/write'], + 0x10: ['BD0', 'Banked data 0'], + 0x14: ['BD1', 'Banked data 1'], + 0x18: ['BD2', 'Banked data 2'], + 0x1c: ['BD3', 'Banked data 3'], + # 0x20-0xf4: Reserved SBZ + 0x800000000: ['ROM', 'Debug ROM address'], + 0xfc: ['IDR', 'Identification register'], +} + +# TODO: Split off generic ARM/Cortex-M3 parts into another protocol decoder? + +# Bits[31:28]: Version (here: 0x3) +# JTAG-DP: 0x3, SW-DP: 0x2 +# Bits[27:12]: Part number (here: 0xba00) +# JTAG-DP: 0xba00, SW-DP: 0xba10 +# Bits[11:1]: JEDEC (JEP-106) manufacturer ID (here: 0x23b) +# Bits[11:8]: Continuation code ('ARM Ltd.': 0x04) +# Bits[7:1]: Identity code ('ARM Ltd.': 0x3b) +# Bits[0:0]: Reserved (here: 0x1) +def decode_device_id_code(bits): + id_hex = '0x%x' % int('0b' + bits, 2) + ver = cm3_idcode_ver.get(int('0b' + bits[-32:-28], 2), 'UNKNOWN') + part = cm3_idcode_part.get(int('0b' + bits[-28:-12], 2), 'UNKNOWN') + ids = jedec_id.get(int('0b' + bits[-12:-8], 2) + 1, {}) + manuf = ids.get(int('0b' + bits[-7:-1], 2), 'UNKNOWN') + return (id_hex, manuf, ver, part) + +# DPACC is used to access debug port registers (CTRL/STAT, SELECT, RDBUFF). +# APACC is used to access all Access Port (AHB-AP) registers. + +# APACC/DPACC, when transferring data IN: +# Bits[34:3] = DATA[31:0]: 32bit data to transfer (write request) +# Bits[2:1] = A[3:2]: 2-bit address (debug/access port register) +# Bits[0:0] = RnW: Read request (1) or write request (0) +def data_in(instruction, bits): + data, a, rnw = bits[:-3], bits[-3:-1], bits[-1] + data_hex = '0x%x' % int('0b' + data, 2) + r = 'Read request' if (rnw == '1') else 'Write request' + # reg = dp_reg[a] if (instruction == 'DPACC') else apb_ap_reg[a] + reg = dp_reg[a] if (instruction == 'DPACC') else a # TODO + return 'New transaction: DATA: %s, A: %s, RnW: %s' % (data_hex, reg, r) + +# APACC/DPACC, when transferring data OUT: +# Bits[34:3] = DATA[31:0]: 32bit data which is read (read request) +# Bits[2:0] = ACK[2:0]: 3-bit acknowledge +def data_out(bits): + data, ack = bits[:-3], bits[-3:] + data_hex = '0x%x' % int('0b' + data, 2) + ack_meaning = ack_val.get(ack, 'Reserved') + return 'Previous transaction result: DATA: %s, ACK: %s' \ + % (data_hex, ack_meaning) + +class Decoder(srd.Decoder): + api_version = 3 + id = 'jtag_stm32' + name = 'JTAG / STM32' + longname = 'Joint Test Action Group / ST STM32' + desc = 'ST STM32-specific JTAG protocol.' + license = 'gplv2+' + inputs = ['jtag'] + outputs = [] + tags = ['Debug/trace'] + annotations = ( + ('item', 'Item'), + ('field', 'Field'), + ('command', 'Command'), + ('warning', 'Warning'), + ) + annotation_rows = ( + ('items', 'Items', (0,)), + ('fields', 'Fields', (1,)), + ('commands', 'Commands', (2,)), + ('warnings', 'Warnings', (3,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.state = 'IDLE' + self.samplenums = None + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + self.put(self.ss, self.es, self.out_ann, data) + + def putf(self, s, e, data): + self.put(self.samplenums[s][0], self.samplenums[e][1], self.out_ann, data) + + def handle_reg_bypass(self, cmd, bits): + self.putx([0, ['BYPASS: ' + bits]]) + + def handle_reg_idcode(self, cmd, bits): + bits = bits[1:] + + id_hex, manuf, ver, part = decode_device_id_code(bits) + cc = '0x%x' % int('0b' + bits[-12:-8], 2) + ic = '0x%x' % int('0b' + bits[-7:-1], 2) + + self.putf(0, 0, [1, ['Reserved', 'Res', 'R']]) + self.putf(8, 11, [0, ['Continuation code: %s' % cc, 'CC', 'C']]) + self.putf(1, 7, [0, ['Identity code: %s' % ic, 'IC', 'I']]) + self.putf(1, 11, [1, ['Manufacturer: %s' % manuf, 'Manuf', 'M']]) + self.putf(12, 27, [1, ['Part: %s' % part, 'Part', 'P']]) + self.putf(28, 31, [1, ['Version: %s' % ver, 'Version', 'V']]) + self.putf(32, 32, [1, ['BYPASS (BS TAP)', 'BS', 'B']]) + + self.putx([2, ['IDCODE: %s (%s: %s/%s)' % \ + decode_device_id_code(bits)]]) + + def handle_reg_dpacc(self, cmd, bits): + bits = bits[1:] + s = data_in('DPACC', bits) if (cmd == 'DR TDI') else data_out(bits) + self.putx([2, [s]]) + + def handle_reg_apacc(self, cmd, bits): + bits = bits[1:] + s = data_in('APACC', bits) if (cmd == 'DR TDI') else data_out(bits) + self.putx([2, [s]]) + + def handle_reg_abort(self, cmd, bits): + bits = bits[1:] + # Bits[31:1]: reserved. Bit[0]: DAPABORT. + a = '' if (bits[0] == '1') else 'No ' + s = 'DAPABORT = %s: %sDAP abort generated' % (bits[0], a) + self.putx([2, [s]]) + + # Warn if DAPABORT[31:1] contains non-zero bits. + if (bits[:-1] != ('0' * 31)): + self.putx([3, ['WARNING: DAPABORT[31:1] reserved!']]) + + def handle_reg_unknown(self, cmd, bits): + bits = bits[1:] + self.putx([2, ['Unknown instruction: %s' % bits]]) + + def decode(self, ss, es, data): + cmd, val = data + + self.ss, self.es = ss, es + + if cmd != 'NEW STATE': + # The right-most char in the 'val' bitstring is the LSB. + val, self.samplenums = val + self.samplenums.reverse() + + if cmd == 'IR TDI': + # Switch to the state named after the instruction, or 'UNKNOWN'. + # The STM32F10xxx has two serially connected JTAG TAPs, the + # boundary scan tap (5 bits) and the Cortex-M3 TAP (4 bits). + # See UM 31.5 "STM32F10xxx JTAG TAP connection" for details. + self.state = ir.get(val[5:9], ['UNKNOWN', 0])[0] + bstap_ir = bs_ir.get(val[:5], ['UNKNOWN', 0])[0] + self.putf(4, 8, [1, ['IR (BS TAP): ' + bstap_ir]]) + self.putf(0, 3, [1, ['IR (M3 TAP): ' + self.state]]) + self.putx([2, ['IR: %s' % self.state]]) + + # State machine + if self.state == 'BYPASS': + # Here we're interested in incoming bits (TDI). + if cmd != 'DR TDI': + return + handle_reg = getattr(self, 'handle_reg_%s' % self.state.lower()) + handle_reg(cmd, val) + self.state = 'IDLE' + elif self.state in ('IDCODE', 'ABORT', 'UNKNOWN'): + # Here we're interested in outgoing bits (TDO). + if cmd != 'DR TDO': + return + handle_reg = getattr(self, 'handle_reg_%s' % self.state.lower()) + handle_reg(cmd, val) + self.state = 'IDLE' + elif self.state in ('DPACC', 'APACC'): + # Here we're interested in incoming and outgoing bits (TDI/TDO). + if cmd not in ('DR TDI', 'DR TDO'): + return + handle_reg = getattr(self, 'handle_reg_%s' % self.state.lower()) + handle_reg(cmd, val) + if cmd == 'DR TDO': # Assumes 'DR TDI' comes before 'DR TDO'. + self.state = 'IDLE' diff --git a/libsigrokdecode4DSL/decoders/lfast/__init__.py b/libsigrokdecode4DSL/decoders/lfast/__init__.py new file mode 100644 index 00000000..681f4f9e --- /dev/null +++ b/libsigrokdecode4DSL/decoders/lfast/__init__.py @@ -0,0 +1,35 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 Soeren Apel +## +## 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, see . +## + +''' +LFAST is a physical communication interface used mainly by the NXP Zipwire +interface. It's a framed asynchronous serial interface using differential +TX/RX pairs, capable of data rates of up to 320 MBit/s. + +This interface is also provided by Infineon as HSCT. + +As with most differential signals, it's sufficient to measure TXP or RXP, no +need for a differential probe. The REFCLK used by the hardware isn't needed by +this protocol decoder either. + +For details see https://www.nxp.com/docs/en/application-note/AN5134.pdf and +https://hitex.co.uk/fileadmin/uk-files/downloads/ShieldBuddy/tc27xD_um_v2.2.pdf +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/lfast/pd.py b/libsigrokdecode4DSL/decoders/lfast/pd.py new file mode 100644 index 00000000..7476e59a --- /dev/null +++ b/libsigrokdecode4DSL/decoders/lfast/pd.py @@ -0,0 +1,335 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 Soeren Apel +## +## 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, see . +## + +import sigrokdecode as srd +from common.srdhelper import bitpack +import decimal + +''' +OUTPUT_PYTHON format: + +[ss, es, data] where data is a data byte of the LFAST payload. All bytes of +the payload are sent at once, each with its start and end sample. +''' + +# See tc27xD_um_v2.2.pdf, Table 20-10 +payload_sizes = { + 0b000: '8 bit', + 0b001: '32 bit / 4 byte', + 0b010: '64 bit / 8 byte', + 0b011: '96 bit / 12 byte', + 0b100: '128 bit / 16 byte', + 0b101: '256 bit / 32 byte', + 0b110: '512 bit / 64 byte', + 0b111: '288 bit / 36 byte' +} + +# See tc27xD_um_v2.2.pdf, Table 20-10 +payload_byte_sizes = { + 0b000: 1, + 0b001: 4, + 0b010: 8, + 0b011: 12, + 0b100: 16, + 0b101: 32, + 0b110: 64, + 0b111: 36 +} + +# See tc27xD_um_v2.2.pdf, Table 20-11 +channel_types = { + 0b0000: 'Interface Control / PING', + 0b0001: 'Unsolicited Status (32 bit)', + 0b0010: 'Slave Interface Control / Read', + 0b0011: 'CTS Transfer', + 0b0100: 'Data Channel A', + 0b0101: 'Data Channel B', + 0b0110: 'Data Channel C', + 0b0111: 'Data Channel D', + 0b1000: 'Data Channel E', + 0b1001: 'Data Channel F', + 0b1010: 'Data Channel G', + 0b1011: 'Data Channel H', + 0b1100: 'Reserved', + 0b1101: 'Reserved', + 0b1110: 'Reserved', + 0b1111: 'Reserved', +} + +# See tc27xD_um_v2.2.pdf, Table 20-12 +control_payloads = { + 0x00: 'PING', + 0x01: 'Reserved', + 0x02: 'Slave interface clock multiplier start', + 0x04: 'Slave interface clock multiplier stop', + 0x08: 'Use 5 MBaud for M->S', + 0x10: 'Use 320 MBaud for M->S', + 0x20: 'Use 5 MBaud for S->M', + 0x40: 'Use 20 MBaud for S->M (needs 20 MHz SysClk)', + 0x80: 'Use 320 MBaud for S->M', + 0x31: 'Enable slave interface transmitter', + 0x32: 'Disable slave interface transmitter', + 0x34: 'Enable clock test mode', + 0x38: 'Disable clock test mode and payload loopback', + 0xFF: 'Enable payload loopback', +} + + +ann_bit, ann_sync, ann_header_pl_size, ann_header_ch_type, ann_header_cts, \ + ann_payload, ann_control_data, ann_sleepbit, ann_warning = range(9) +state_sync, state_header, state_payload, state_sleepbit = range(4) + +class Decoder(srd.Decoder): + api_version = 3 + id = 'lfast' + name = 'LFAST' + longname = 'NXP LFAST interface' + desc = 'Differential high-speed P2P interface' + license = 'gplv2+' + inputs = ['logic'] + outputs = ['lfast'] + tags = ['Embedded/industrial'] + channels = ( + {'id': 'data', 'name': 'Data', 'desc': 'TXP or RXP'}, + ) + annotations = ( + ('bit', 'Bits'), + ('sync', 'Sync Pattern'), + ('header_pl_size', 'Payload Size'), + ('header_ch_type', 'Logical Channel Type'), + ('header_cts', 'Clear To Send'), + ('payload', 'Payload'), + ('ctrl_data', 'Control Data'), + ('sleep', 'Sleep Bit'), + ('warning', 'Warning'), + ) + annotation_rows = ( + ('bits', 'Bits', (ann_bit,)), + ('fields', 'Fields', (ann_sync, ann_header_pl_size, ann_header_ch_type, + ann_header_cts, ann_payload, ann_control_data, ann_sleepbit,)), + ('warnings', 'Warnings', (ann_warning,)), + ) + + def __init__(self): + decimal.getcontext().rounding = decimal.ROUND_HALF_UP + self.bit_len = 0xFFFFFFFF + self.reset() + + def reset(self): + self.prev_bit_len = self.bit_len + self.ss = self.es = 0 + self.ss_payload = self.es_payload = 0 + self.ss_byte = 0 + self.bits = [] + self.payload = [] + self.payload_size = 0 # Expected number of bytes, as read from header + self.bit_len = 0 # Length of one bit time, in samples + self.timeout = 0 # Desired timeout for next edge, in samples + self.ch_type_id = 0 # ID of channel type + self.state = state_sync + + def metadata(self, key, value): + pass + + def start(self): + self.out_python = self.register(srd.OUTPUT_PYTHON) + self.out_ann = self.register(srd.OUTPUT_ANN) + + def put_ann(self, ss, es, ann_class, value): + self.put(ss, es, self.out_ann, [ann_class, value]) + + def put_payload(self): + self.put(self.ss_payload, self.es_payload, self.out_python, self.payload) + + def handle_sync(self): + if len(self.bits) == 1: + self.ss_sync = self.ss_bit + + if len(self.bits) == 16: + value = bitpack(self.bits) + if value == 0xA84B: + self.put_ann(self.ss_sync, self.es_bit, ann_sync, ['Sync OK']) + else: + self.put_ann(self.ss_sync, self.es_bit, ann_warning, ['Wrong Sync Value: {:02X}'.format(value)]) + self.reset() + + # Only continue if we didn't just reset + if self.ss > 0: + self.bits = [] + self.state = state_header + self.timeout = int(9.4 * self.bit_len) + + def handle_header(self): + if len(self.bits) == 1: + self.ss_header = self.ss_bit + + if len(self.bits) == 8: + # See tc27xD_um_v2.2.pdf, Figure 20-47, for the header structure + bit_len = (self.es_bit - self.ss_header) / 8 + value = bitpack(self.bits) + + ss = self.ss_header + es = ss + 3 * bit_len + size_id = (value & 0xE0) >> 5 + size = payload_sizes.get(size_id) + self.payload_size = payload_byte_sizes.get(size_id) + self.put_ann(int(ss), int(es), ann_header_pl_size, [size]) + + ss = es + es = ss + 4 * bit_len + self.ch_type_id = (value & 0x1E) >> 1 + ch_type = channel_types.get(self.ch_type_id) + self.put_ann(int(ss), int(es), ann_header_ch_type, [ch_type]) + + ss = es + es = ss + bit_len + cts = value & 0x01 + self.put_ann(int(ss), int(es), ann_header_cts, ['{}'.format(cts)]) + + self.bits = [] + self.state = state_payload + self.timeout = int(9.4 * self.bit_len) + + def handle_payload(self): + self.timeout = int((self.payload_size - len(self.payload)) * 8 * self.bit_len) + + if len(self.bits) == 1: + self.ss_byte = self.ss_bit + if self.ss_payload == 0: + self.ss_payload = self.ss_bit + + if len(self.bits) == 8: + value = bitpack(self.bits) + value_hex = '{:02X}'.format(value) + + # Control transfers have no SIPI payload, show them as control transfers + # Check the channel_types list for the meaning of the magic values + if (self.ch_type_id >= 0b0100) and (self.ch_type_id <= 0b1011): + self.put_ann(self.ss_byte, self.es_bit, ann_payload, [value_hex]) + else: + # Control transfers are 8-bit transfers, so only evaluate the first byte + if len(self.payload) == 0: + ctrl_data = control_payloads.get(value, value_hex) + self.put_ann(self.ss_byte, self.es_bit, ann_control_data, [ctrl_data]) + else: + self.put_ann(self.ss_byte, self.es_bit, ann_control_data, [value_hex]) + + self.bits = [] + self.es_payload = self.es_bit + self.payload.append((self.ss_byte, self.es_payload, value)) + + if (len(self.payload) == self.payload_size): + self.timeout = int(1.4 * self.bit_len) + self.state = state_sleepbit + + def handle_sleepbit(self): + if len(self.bits) == 0: + self.put_ann(self.ss_bit, self.es_bit, ann_sleepbit, ['No LVDS sleep mode request', 'No sleep', 'N']) + elif len(self.bits) > 1: + self.put_ann(self.ss_bit, self.es_bit, ann_warning, ['Expected only the sleep bit, got {} bits instead'.format(len(self.bits))]) + else: + if self.bits[0] == 1: + self.put_ann(self.ss_bit, self.es_bit, ann_sleepbit, ['LVDS sleep mode request', 'Sleep', 'Y']) + else: + self.put_ann(self.ss_bit, self.es_bit, ann_sleepbit, ['No LVDS sleep mode request', 'No sleep', 'N']) + + # We only send the payload out if this is an actual data transfer; + # check the channel_types list for the meaning of the magic values + if (self.ch_type_id >= 0b0100) and (self.ch_type_id <= 0b1011): + if len(self.payload) > 0: + self.put_payload() + + def decode(self): + while True: + if self.timeout == 0: + rising_edge, = self.wait({0: 'e'}) + else: + rising_edge, = self.wait([{0: 'e'}, {'skip': self.timeout}]) + + # If this is the first edge, we only update ss + if self.ss == 0: + self.ss = self.samplenum + # Let's set the timeout for the sync pattern as well + self.timeout = int(16.2 * self.prev_bit_len) + continue + + self.es = self.samplenum + + # Check for the sleep bit if this is a timeout condition + if (len(self.matched) == 2) and self.matched[1]: + rising_edge = ~rising_edge + if self.state == state_sync: + self.reset() + continue + elif self.state == state_sleepbit: + self.ss_bit += self.bit_len + self.es_bit = self.ss_bit + self.bit_len + self.handle_sleepbit() + self.reset() + continue + + # Shouldn't happen but we check just in case + if int(self.es - self.ss) == 0: + continue + + # We use the first bit to deduce the bit length + if self.bit_len == 0: + self.bit_len = self.es - self.ss + + # Determine number of bits covered by this edge + bit_count = (self.es - self.ss) / self.bit_len + bit_count = int(decimal.Decimal(bit_count).to_integral_value()) + + if bit_count == 0: + self.put_ann(self.ss, self.es, ann_warning, ['Bit time too short']) + self.reset() + continue + + bit_value = '0' if rising_edge else '1' + + divided_len = (self.es - self.ss) / bit_count + for i in range(bit_count): + self.ss_bit = int(self.ss + i * divided_len) + self.es_bit = int(self.ss_bit + divided_len) + self.put_ann(self.ss_bit, self.es_bit, ann_bit, [bit_value]) + + # Place the new bit at the front of the bit list + self.bits.insert(0, (0 if rising_edge else 1)) + + if self.state == state_sync: + self.handle_sync() + elif self.state == state_header: + self.handle_header() + elif self.state == state_payload: + self.handle_payload() + elif self.state == state_sleepbit: + self.handle_sleepbit() + self.reset() + + if self.ss == 0: + break # Because reset() was called, invalidating everything + + # Only update ss if we didn't just perform a reset + if self.ss > 0: + self.ss = self.samplenum + + # If we got here when a timeout occurred, we have processed all null + # bits that we could and should reset now to find the next packet + if (len(self.matched) == 2) and self.matched[1]: + self.reset() diff --git a/libsigrokdecode4DSL/decoders/lin/__init__.py b/libsigrokdecode4DSL/decoders/lin/__init__.py new file mode 100644 index 00000000..f5b2835f --- /dev/null +++ b/libsigrokdecode4DSL/decoders/lin/__init__.py @@ -0,0 +1,28 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Stephan Thiele +## +## 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, see . +## + +''' +This decoder stacks on top of the 'uart' PD and decodes the LIN +(Local Interconnect Network) protocol. + +LIN is layered on top of the UART (async serial) protocol, with 8n1 settings. +Bytes are sent LSB-first. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/lin/pd.py b/libsigrokdecode4DSL/decoders/lin/pd.py new file mode 100644 index 00000000..c6db6787 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/lin/pd.py @@ -0,0 +1,235 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Stephan Thiele +## +## 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, see . +## + +import sigrokdecode as srd + +class LinFsm: + class State: + WaitForBreak = 'WAIT_FOR_BREAK' + Sync = 'SYNC' + Pid = 'PID' + Data = 'DATA' + Checksum = 'CHECKSUM' + Error = 'ERROR' + + def transit(self, target_state): + if not self._transition_allowed(target_state): + return False + self.state = target_state + return True + + def _transition_allowed(self, target_state): + if target_state == LinFsm.State.Error: + return True + return target_state in self.allowed_state[self.state] + + def reset(self): + self.state = LinFsm.State.WaitForBreak + + def __init__(self): + a = dict() + a[LinFsm.State.WaitForBreak] = (LinFsm.State.Sync,) + a[LinFsm.State.Sync] = (LinFsm.State.Pid,) + a[LinFsm.State.Pid] = (LinFsm.State.Data,) + a[LinFsm.State.Data] = (LinFsm.State.Data, LinFsm.State.Checksum) + a[LinFsm.State.Checksum] = (LinFsm.State.WaitForBreak,) + a[LinFsm.State.Error] = (LinFsm.State.Sync,) + self.allowed_state = a + + self.state = None + self.reset() + +class Decoder(srd.Decoder): + api_version = 3 + id = 'lin' + name = 'LIN' + longname = 'Local Interconnect Network' + desc = 'Local Interconnect Network (LIN) protocol.' + license = 'gplv2+' + inputs = ['uart'] + outputs = [] + tags = ['Automotive'] + options = ( + {'id': 'version', 'desc': 'Protocol version', 'default': 2, 'values': (1, 2)}, + ) + annotations = ( + ('data', 'LIN data'), + ('control', 'Protocol info'), + ('error', 'Error descriptions'), + ('inline_error', 'Protocol violations and errors'), + ) + annotation_rows = ( + ('data', 'Data', (0, 1, 3)), + ('error', 'Error', (2,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.fsm = LinFsm() + self.lin_header = [] + self.lin_rsp = [] + self.lin_version = None + self.out_ann = None + self.ss_block = None + self.es_block = None + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.lin_version = self.options['version'] + + def putx(self, data): + self.put(self.ss_block, self.es_block, self.out_ann, data) + + def wipe_break_null_byte(self, value): + # Upon a break condition a null byte is received which must be ignored. + if self.fsm.state not in (LinFsm.State.WaitForBreak, LinFsm.State.Error): + if len(self.lin_rsp): + value = self.lin_rsp.pop()[2] + else: + self.lin_header.pop() + + if value != 0: + self.fsm.transit(LinFsm.State.Error) + self.handle_error(None) + return False + + return True + + def handle_wait_for_break(self, value): + self.wipe_break_null_byte(value) + + def handle_break(self, value): + if self.fsm.state not in (LinFsm.State.WaitForBreak, LinFsm.State.Error): + if self.wipe_break_null_byte(value): + self.fsm.transit(LinFsm.State.Checksum) + self.handle_checksum() + + self.fsm.reset() + self.fsm.transit(LinFsm.State.Sync) + + self.putx([1, ['Break condition', 'Break', 'Brk', 'B']]) + + def handle_sync(self, value): + self.fsm.transit(LinFsm.State.Pid) + self.lin_header.append((self.ss_block, self.es_block, value)) + + def handle_pid(self, value): + self.fsm.transit(LinFsm.State.Data) + self.lin_header.append((self.ss_block, self.es_block, value)) + + def handle_data(self, value): + self.lin_rsp.append((self.ss_block, self.es_block, value)) + + def handle_checksum(self): + sync = self.lin_header.pop(0) if len(self.lin_header) else None + + self.put(sync[0], sync[1], self.out_ann, [0, ['Sync', 'S']]) + + if sync[2] != 0x55: + self.put(sync[0], sync[1], self.out_ann, + [2, ['Sync is not 0x55', 'Not 0x55', '!= 0x55']]) + + pid = self.lin_header.pop(0) if len(self.lin_header) else None + checksum = self.lin_rsp.pop() if len(self.lin_rsp) else None + + if pid: + id_ = pid[2] & 0x3F + parity = pid[2] >> 6 + + expected_parity = self.calc_parity(pid[2]) + parity_valid = parity == expected_parity + + if not parity_valid: + self.put(pid[0], pid[1], self.out_ann, [2, ['P != %d' % expected_parity]]) + + ann_class = 0 if parity_valid else 3 + self.put(pid[0], pid[1], self.out_ann, [ann_class, [ + 'ID: %02X Parity: %d (%s)' % (id_, parity, 'ok' if parity_valid else 'bad'), + 'ID: 0x%02X' % id_, 'I: %d' % id_ + ]]) + + if len(self.lin_rsp): + checksum_valid = self.checksum_is_valid(pid[2], self.lin_rsp, checksum[2]) + + for b in self.lin_rsp: + self.put(b[0], b[1], self.out_ann, [0, ['Data: 0x%02X' % b[2], 'D: 0x%02X' % b[2]]]) + + ann_class = 0 if checksum_valid else 3 + self.put(checksum[0], checksum[1], self.out_ann, + [ann_class, ['Checksum: 0x%02X' % checksum[2], 'Checksum', 'Chk', 'C']]) + + if not checksum_valid: + self.put(checksum[0], checksum[1], self.out_ann, [2, ['Checksum invalid']]) + else: + pass # No response. + + self.lin_header.clear() + self.lin_rsp.clear() + + def handle_error(self, dummy): + self.putx([3, ['Error', 'Err', 'E']]) + + def checksum_is_valid(self, pid, data, checksum): + if self.lin_version == 2: + id_ = pid & 0x3F + + if id_ != 60 and id_ != 61: + checksum += pid + + for d in data: + checksum += d[2] + + carry_bits = int(checksum / 256) + checksum += carry_bits + + return checksum & 0xFF == 0xFF + + @staticmethod + def calc_parity(pid): + id_ = [((pid & 0x3F) >> i) & 1 for i in range(8)] + + p0 = id_[0] ^ id_[1] ^ id_[2] ^ id_[4] + p1 = not (id_[1] ^ id_[3] ^ id_[4] ^ id_[5]) + + return (p0 << 0) | (p1 << 1) + + def decode(self, ss, es, data): + ptype, rxtx, pdata = data + + self.ss_block, self.es_block = ss, es + + # Ignore all UART packets except the actual data packets or BREAK. + if ptype == 'BREAK': + self.handle_break(pdata) + if ptype != 'DATA': + return + + # We're only interested in the byte value (not individual bits). + pdata = pdata[0] + + # Short LIN overview: + # - Message begins with a BREAK (0x00) for at least 13 bittimes. + # - Break is always followed by a SYNC byte (0x55). + # - Sync byte is followed by a PID byte (Protected Identifier). + # - PID byte is followed by 1 - 8 data bytes and a final checksum byte. + + handler = getattr(self, 'handle_%s' % self.fsm.state.lower()) + handler(pdata) diff --git a/libsigrokdecode4DSL/decoders/lm75/__init__.py b/libsigrokdecode4DSL/decoders/lm75/__init__.py new file mode 100644 index 00000000..83ce811b --- /dev/null +++ b/libsigrokdecode4DSL/decoders/lm75/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +''' +This decoder stacks on top of the 'i2c' PD and decodes the National LM75 +(and compatibles) temperature sensor protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/lm75/pd.py b/libsigrokdecode4DSL/decoders/lm75/pd.py new file mode 100644 index 00000000..14df1b52 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/lm75/pd.py @@ -0,0 +1,186 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +# TODO: Better support for various LM75 compatible devices. + +import sigrokdecode as srd + +# LM75 only supports 9 bit resolution, compatible devices usually 9-12 bits. +resolution = { + # CONFIG[6:5]: + 0x00: 9, + 0x01: 10, + 0x02: 11, + 0x03: 12, +} + +ft = { + # CONFIG[4:3]: + 0x00: 1, + 0x01: 2, + 0x02: 4, + 0x03: 6, +} + +class Decoder(srd.Decoder): + api_version = 3 + id = 'lm75' + name = 'LM75' + longname = 'National LM75' + desc = 'National LM75 (and compatibles) temperature sensor.' + license = 'gplv2+' + inputs = ['i2c'] + outputs = [] + tags = ['Sensor'] + options = ( + {'id': 'sensor', 'desc': 'Sensor type', 'default': 'lm75', + 'values': ('lm75',)}, + {'id': 'resolution', 'desc': 'Resolution (bits)', 'default': 9, + 'values': (9, 10, 11, 12)}, + ) + annotations = ( + ('celsius', 'Temperature in degrees Celsius'), + ('kelvin', 'Temperature in Kelvin'), + ('text-verbose', 'Human-readable text (verbose)'), + ('text', 'Human-readable text'), + ('warnings', 'Human-readable warnings'), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.state = 'IDLE' + self.reg = 0x00 # Currently selected register + self.databytes = [] + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + # Helper for annotations which span exactly one I²C packet. + self.put(self.ss, self.es, self.out_ann, data) + + def putb(self, data): + # Helper for annotations which span a block of I²C packets. + self.put(self.ss_block, self.es_block, self.out_ann, data) + + def warn_upon_invalid_slave(self, addr): + # LM75 and compatible devices have a 7-bit I²C slave address where + # the 4 MSBs are fixed to 1001, and the 3 LSBs are configurable. + # Thus, valid slave addresses (1001xxx) range from 0x48 to 0x4f. + if addr not in range(0x48, 0x4f + 1): + s = 'Warning: I²C slave 0x%02x not an LM75 compatible sensor.' + self.putx([4, [s % addr]]) + + def output_temperature(self, s, rw): + # TODO: Support for resolutions other than 9 bit. + before, after = self.databytes[0], (self.databytes[1] >> 7) * 5 + celsius = float('%d.%d' % (before, after)) + kelvin = celsius + 273.15 + self.putb([0, ['%s: %.1f °C' % (s, celsius)]]) + self.putb([1, ['%s: %.1f K' % (s, kelvin)]]) + + # Warn about the temperature register (0x00) being read-only. + if s == 'Temperature' and rw == 'WRITE': + s = 'Warning: The temperature register is read-only!' + self.putb([4, [s]]) + + def handle_temperature_reg(self, b, s, rw): + # Common helper for the temperature/T_HYST/T_OS registers. + if len(self.databytes) == 0: + self.ss_block = self.ss + self.databytes.append(b) + return + self.databytes.append(b) + self.es_block = self.es + self.output_temperature(s, rw) + self.databytes = [] + + def handle_reg_0x00(self, b, rw): + # Temperature register (16bits, read-only). + self.handle_temperature_reg(b, 'Temperature', rw) + + def handle_reg_0x01(self, b, rw): + # Configuration register (8 bits, read/write). + # TODO: Bit-exact annotation ranges. + + sd = b & (1 << 0) + tmp = 'normal operation' if (sd == 0) else 'shutdown mode' + s = 'SD = %d: %s\n' % (sd, tmp) + s2 = 'SD = %s, ' % tmp + + cmp_int = b & (1 << 1) + tmp = 'comparator' if (cmp_int == 0) else 'interrupt' + s += 'CMP/INT = %d: %s mode\n' % (cmp_int, tmp) + s2 += 'CMP/INT = %s, ' % tmp + + pol = b & (1 << 2) + tmp = 'low' if (pol == 0) else 'high' + s += 'POL = %d: OS polarity is active-%s\n' % (pol, tmp) + s2 += 'POL = active-%s, ' % tmp + + bits = (b & ((1 << 4) | (1 << 3))) >> 3 + s += 'Fault tolerance setting: %d bit(s)\n' % ft[bits] + s2 += 'FT = %d' % ft[bits] + + # Not supported by LM75, but by various compatible devices. + if self.options['sensor'] != 'lm75': # TODO + bits = (b & ((1 << 6) | (1 << 5))) >> 5 + s += 'Resolution: %d bits\n' % resolution[bits] + s2 += ', resolution = %d' % resolution[bits] + + self.putx([2, [s]]) + self.putx([3, [s2]]) + + def handle_reg_0x02(self, b, rw): + # T_HYST register (16 bits, read/write). + self.handle_temperature_reg(b, 'T_HYST trip temperature', rw) + + def handle_reg_0x03(self, b, rw): + # T_OS register (16 bits, read/write). + self.handle_temperature_reg(b, 'T_OS trip temperature', rw) + + def decode(self, ss, es, data): + cmd, databyte = data + + # Store the start/end samples of this I²C packet. + self.ss, self.es = ss, es + + # State machine. + if self.state == 'IDLE': + # Wait for an I²C START condition. + if cmd != 'START': + return + self.state = 'GET SLAVE ADDR' + elif self.state == 'GET SLAVE ADDR': + # Wait for an address read/write operation. + if cmd in ('ADDRESS READ', 'ADDRESS WRITE'): + self.warn_upon_invalid_slave(databyte) + self.state = cmd[8:] + ' REGS' # READ REGS / WRITE REGS + elif self.state in ('READ REGS', 'WRITE REGS'): + if cmd in ('DATA READ', 'DATA WRITE'): + handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg) + handle_reg(databyte, cmd[5:]) # READ / WRITE + elif cmd == 'STOP': + # TODO: Any output? + self.state = 'IDLE' + else: + # self.putx([0, ['Ignoring: %s (data=%s)' % (cmd, databyte)]]) + pass diff --git a/libsigrokdecode4DSL/decoders/lpc/__init__.py b/libsigrokdecode4DSL/decoders/lpc/__init__.py new file mode 100644 index 00000000..52277587 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/lpc/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +''' +LPC (Low Pin Count) is a protocol for low-bandwidth devices used on +some PC mainboards, such as the "BIOS chip" or the so-called "Super I/O". +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/lpc/pd.py b/libsigrokdecode4DSL/decoders/lpc/pd.py new file mode 100644 index 00000000..6ae13f4a --- /dev/null +++ b/libsigrokdecode4DSL/decoders/lpc/pd.py @@ -0,0 +1,547 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012-2013 Uwe Hermann +## Copyright (C) 2019 DreamSourceLab +## Copyright (C) 2020 Raptor Engineering, LLC +## +## 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, see . +## + +import sigrokdecode as srd + +# ... +fields = { + # START field (indicates start or stop of a transaction) + 'START': { + 0b0000: 'Start of cycle for a target', + 0b0001: 'Reserved', + 0b0010: 'Grant for bus master 0', + 0b0011: 'Grant for bus master 1', + 0b0100: 'Reserved', + 0b0101: 'TPM', + 0b0110: 'Reserved', + 0b0111: 'Reserved', + 0b1000: 'Reserved', + 0b1001: 'Reserved', + 0b1010: 'Reserved', + 0b1011: 'Reserved', + 0b1100: 'Reserved', + 0b1101: 'Start of cycle for a Firmware Memory Read cycle', + 0b1110: 'Start of cycle for a Firmware Memory Write cycle', + 0b1111: 'Stop/abort (end of a cycle for a target)', + }, + # Cycle type / direction field + # Bit 0 (LAD[0]) is unused, should always be 0. + # Neither host nor peripheral are allowed to drive 0b11x0. + 'CT_DR': { + 0b0000: 'I/O read', + 0b0001: 'I/O read', + 0b0010: 'I/O write', + 0b0011: 'I/O write', + 0b0100: 'Memory read', + 0b0101: 'Memory read', + 0b0110: 'Memory write', + 0b0111: 'Memory write', + 0b1000: 'DMA read', + 0b1001: 'DMA read', + 0b1010: 'DMA write', + 0b1011: 'DMA write', + 0b1100: 'Reserved / not allowed', + 0b1101: 'Reserved / not allowed', + 0b1110: 'Reserved / not allowed', + 0b1111: 'Reserved / not allowed', + }, + # Cycle type / direction field + # False for read cycle, True for write cycle + 'CT_DR_WR': { + 0b0000: False, + 0b0001: False, + 0b0010: True, + 0b0011: True, + 0b0100: False, + 0b0101: False, + 0b0110: True, + 0b0111: True, + 0b1000: False, + 0b1001: False, + 0b1010: True, + 0b1011: True, + 0b1100: False, + 0b1101: False, + 0b1110: False, + 0b1111: False, + }, + # SIZE field (determines how many bytes are to be transferred) + # Bits[3:2] are reserved, must be driven to 0b00. + # Neither host nor peripheral are allowed to drive 0b0010. + 'SIZE': { + 0b0000: '8 bits (1 byte)', + 0b0001: '16 bits (2 bytes)', + 0b0010: 'Reserved / not allowed', + 0b0011: '32 bits (4 bytes)', + }, + # CHANNEL field (bits[2:0] contain the DMA channel number) + 'CHANNEL': { + 0b0000: '0', + 0b0001: '1', + 0b0010: '2', + 0b0011: '3', + 0b0100: '4', + 0b0101: '5', + 0b0110: '6', + 0b0111: '7', + }, + # SYNC field (used to add wait states) + 'SYNC': { + 0b0000: 'Ready', + 0b0001: 'Reserved', + 0b0010: 'Reserved', + 0b0011: 'Reserved', + 0b0100: 'Reserved', + 0b0101: 'Short wait', + 0b0110: 'Long wait', + 0b0111: 'Reserved', + 0b1000: 'Reserved', + 0b1001: 'Ready more (DMA only)', + 0b1010: 'Error', + 0b1011: 'Reserved', + 0b1100: 'Reserved', + 0b1101: 'Reserved', + 0b1110: 'Reserved', + 0b1111: 'Reserved', + }, +} + +class Decoder(srd.Decoder): + api_version = 3 + id = 'lpc' + name = 'LPC' + longname = 'Low Pin Count' + desc = 'Protocol for low-bandwidth devices on PC mainboards.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['PC'] + channels = ( + {'id': 'lframe', 'name': 'LFRAME#', 'desc': 'Frame'}, + {'id': 'lclk', 'name': 'LCLK', 'desc': 'Clock'}, + {'id': 'lad0', 'name': 'LAD[0]', 'desc': 'Addr/control/data 0'}, + {'id': 'lad1', 'name': 'LAD[1]', 'desc': 'Addr/control/data 1'}, + {'id': 'lad2', 'name': 'LAD[2]', 'desc': 'Addr/control/data 2'}, + {'id': 'lad3', 'name': 'LAD[3]', 'desc': 'Addr/control/data 3'}, + ) + optional_channels = ( + {'id': 'lreset', 'name': 'LRESET#', 'desc': 'Reset'}, + {'id': 'ldrq', 'name': 'LDRQ#', 'desc': 'Encoded DMA / bus master request'}, + {'id': 'serirq', 'name': 'SERIRQ', 'desc': 'Serialized IRQ'}, + {'id': 'clkrun', 'name': 'CLKRUN#', 'desc': 'Clock run'}, + {'id': 'lpme', 'name': 'LPME#', 'desc': 'LPC power management event'}, + {'id': 'lpcpd', 'name': 'LPCPD#', 'desc': 'Power down'}, + {'id': 'lsmi', 'name': 'LSMI#', 'desc': 'System Management Interrupt'}, + ) + annotations = ( + ('warnings', 'Warnings'), + ('start', 'Start'), + ('cycle-type', 'Cycle-type/direction'), + ('addr', 'Address'), + ('tar1', 'Turn-around cycle 1'), + ('sync', 'Sync'), + ('timeout', 'Time Out'), + ('data', 'Data'), + ('tar2', 'Turn-around cycle 2'), + ) + annotation_rows = ( + ('data', 'Data', (1, 2, 3, 4, 5, 6, 7, 8)), + ('warnings', 'Warnings', (0,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.state = 'IDLE' + self.oldlclk = -1 + self.samplenum = 0 + self.lad = -1 + self.addr = 0 + self.direction = 0 + self.cur_nibble = 0 + self.cycle_type = -1 + self.databyte = 0 + self.tarcount = 0 + self.synccount = 0 + self.timeoutcount = 0 + self.oldpins = None + self.ss_block = self.es_block = None + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putb(self, data): + self.put(self.ss_block, self.es_block, self.out_ann, data) + + def handle_get_start(self, lframe): + # LAD[3:0]: START field (1 clock cycle). + + # The last value of LAD[3:0] before LFRAME# gets de-asserted is what + # the peripherals must use. However, the host can keep LFRAME# asserted + # multiple clocks, and we output all START fields that occur, even + # though the peripherals are supposed to ignore all but the last one. + self.es_block = self.samplenum + self.putb([1, [fields['START'][self.oldlad], 'START', 'St', 'S']]) + self.ss_block = self.samplenum + + + # LFRAME# is asserted (low). Wait until it gets de-asserted again + # (the host is allowed to keep it asserted multiple clocks). + if lframe != 1: + return + + if (self.oldlad == 0b0000 or self.oldlad == 0b0101): + self.start_field = self.oldlad + self.state = 'GET CT/DR' + elif (self.oldlad == 0b1101 or self.oldlad == 0b1110): + self.start_field = self.oldlad + if (self.oldlad == 0b1110): + self.direction = True + else: + self.direction = False + self.state = 'GET FW IDSEL' + else: + self.state = 'IDLE' + + def handle_get_ct_dr(self): + # LAD[3:0]: Cycle type / direction field (1 clock cycle). + + self.cycle_type = fields['CT_DR'][self.oldlad] + self.direction = fields['CT_DR_WR'][self.oldlad] + + # TODO: Warning/error on invalid cycle types. + if self.cycle_type == 'Reserved': + self.putb([0, ['Invalid cycle type (%s)' % self.oldlad_bits]]) + + self.es_block = self.samplenum + self.putb([2, ['Cycle type: %s' % self.cycle_type]]) + self.ss_block = self.samplenum + + self.state = 'GET ADDR' + self.addr = 0 + self.cur_nibble = 0 + + def handle_get_fw_idsel(self): + # LAD[3:0]: IDSEL field (1 clock cycle). + self.es_block = self.samplenum + s = 'IDSEL: 0x%%0%dx' % self.oldlad + self.putb([3, [s % self.oldlad]]) + self.ss_block = self.samplenum + + self.state = 'GET FW ADDR' + self.addr = 0 + self.cur_nibble = 0 + + def handle_get_fw_addr(self): + # LAD[3:0]: ADDR field (7 clock cycles). + addr_nibbles = 7 # Address is 28bits. + + # Addresses are driven MSN-first. + offset = ((addr_nibbles - 1) - self.cur_nibble) * 4 + if (offset < 0): + self.putb([0, ['Warning: Invalid address shift: %d' % offset]]) + self.state = 'IDLE' + return + self.addr |= (self.oldlad << offset) + + # Continue if we haven't seen all ADDR cycles, yet. + if (self.cur_nibble < addr_nibbles - 1): + self.cur_nibble += 1 + return + + self.es_block = self.samplenum + s = 'Address: 0x%%0%dx' % addr_nibbles + self.putb([3, [s % self.addr]]) + self.ss_block = self.samplenum + + self.state = 'GET FW MSIZE' + + def handle_get_fw_msize(self): + # LAD[3:0]: MSIZE field (1 clock cycle). + self.es_block = self.samplenum + s = 'MSIZE: 0x%%0%dx' % self.oldlad + self.putb([3, [s % self.oldlad]]) + self.ss_block = self.samplenum + self.msize = self.oldlad + + if self.direction == 1: + self.state = 'GET FW DATA' + self.cycle_count = 0 + self.dataword = 0 + self.cur_nibble = 0 + else: + self.state = 'GET TAR' + self.tar_count = 0 + + def handle_get_addr(self): + # LAD[3:0]: ADDR field (4/8/0 clock cycles). + + # I/O cycles: 4 ADDR clocks. Memory cycles: 8 ADDR clocks. + # DMA cycles: no ADDR clocks at all. + if self.cycle_type in ('I/O read', 'I/O write'): + addr_nibbles = 4 # Address is 16bits. + elif self.cycle_type in ('Memory read', 'Memory write'): + addr_nibbles = 8 # Address is 32bits. + else: + addr_nibbles = 0 # TODO: How to handle later on? + + # Addresses are driven MSN-first. + offset = ((addr_nibbles - 1) - self.cur_nibble) * 4 + if (offset < 0): + self.putb([0, ['Warning: Invalid address shift: %d' % offset]]) + self.state = 'IDLE' + return + self.addr |= (self.oldlad << offset) + + # Continue if we haven't seen all ADDR cycles, yet. + if (self.cur_nibble < addr_nibbles - 1): + self.cur_nibble += 1 + return + + self.es_block = self.samplenum + s = 'Address: 0x%%0%dx' % addr_nibbles + self.putb([3, [s % self.addr]]) + self.ss_block = self.samplenum + + if self.direction == 1: + self.state = 'GET DATA' + self.cycle_count = 0 + else: + self.state = 'GET TAR' + self.tar_count = 0 + + def handle_get_tar(self): + # LAD[3:0]: First TAR (turn-around) field (2 clock cycles). + + self.es_block = self.samplenum + self.putb([4, ['TAR, cycle %d: %s' % (self.tarcount, self.oldlad_bits)]]) + self.ss_block = self.samplenum + + # On the first TAR clock cycle LAD[3:0] is driven to 1111 by + # either the host or peripheral. On the second clock cycle, + # the host or peripheral tri-states LAD[3:0], but its value + # should still be 1111, due to pull-ups on the LAD lines. + if self.oldlad_bits != '1111': + self.putb([0, ['TAR, cycle %d: %s (expected 1111)' % \ + (self.tarcount, self.oldlad_bits)]]) + + if (self.tarcount != 1): + self.tarcount += 1 + return + + self.tarcount = 0 + self.state = 'GET SYNC' + + def handle_get_sync(self, lframe): + # LAD[3:0]: SYNC field (1-n clock cycles). + + self.sync_val = self.oldlad_bits + self.cycle_type = fields['SYNC'][self.oldlad] + + self.es_block = self.samplenum + # TODO: Warnings if reserved value are seen? + if self.cycle_type == 'Reserved': + self.putb([0, ['SYNC, cycle %d: %s (reserved value)' % \ + (self.synccount, self.sync_val)]]) + + self.es_block = self.samplenum + self.putb([5, ['SYNC, cycle %d: %s' % (self.synccount, self.sync_val)]]) + self.ss_block = self.samplenum + + # TODO + if (self.cycle_type != 'Short wait' and self.cycle_type != 'Long wait'): + self.cycle_count = 0 + if (lframe == 0): + self.state = 'GET TIMEOUT' + elif (self.start_field == 0b1101 or self.start_field == 0b1110): + self.state = 'GET FW DATA' + self.cycle_count = 0 + self.dataword = 0 + self.cur_nibble = 0 + else: + self.state = 'GET DATA' + + def handle_get_timeout(self): + # LFRAME#: tie low (4 clock cycles). + + if (self.oldlframe != 0): + self.putb([0, ['TIMEOUT cycle, LFRAME# must be low for 4 LCLk cycles']]) + self.timeoutcount = 0 + self.state = 'IDLE' + return + + self.es_block = self.samplenum + self.putb([6, ['Timeout %d' % self.timeoutcount]]) + self.ss_block = self.samplenum + + if (self.timeoutcount != 3): + self.timeoutcount += 1 + return + + self.timeoutcount = 0 + self.state = 'IDLE' + + def handle_get_fw_data(self): + # LAD[3:0]: DATA field + if (self.msize == 0b0000): + data_nibbles = 2 # Data is 8bits. + elif (self.msize == 0b0001): + data_nibbles = 4 # Data is 16bits. + elif (self.msize == 0b0010): + data_nibbles = 8 # Data is 32bits. + elif (self.msize == 0b0100): + data_nibbles = 32 # Data is 128bits. + elif (self.msize == 0b0111): + data_nibbles = 256 # Data is 1024bits. + else: + self.putb([0, ['Warning: Invalid MSIZE: %d' % self.msize]]) + self.state = 'IDLE' + return + + # Data is driven LSN-first. + nibble_swap = self.cur_nibble % 2 + offset = ((data_nibbles - 1) - self.cur_nibble) * 4 + if (nibble_swap): + offset += 4 + else: + offset -= 4 + if (offset < 0): + self.putb([0, ['Warning: Invalid data shift: %d' % offset]]) + self.state = 'IDLE' + return + self.dataword |= (self.oldlad << offset) + + # Continue if we haven't seen all DATA cycles, yet. + if (self.cur_nibble < data_nibbles - 1): + self.cur_nibble += 1 + return + + self.es_block = self.samplenum + s = 'DATA: 0x%%0%dx' % data_nibbles + self.putb([3, [s % self.dataword]]) + self.ss_block = self.samplenum + + self.cycle_count = 0 + self.state = 'GET TAR2' + + def handle_get_data(self): + # LAD[3:0]: DATA field (2 clock cycles). + + # Data is driven LSN-first. + if (self.cycle_count == 0): + self.databyte = self.oldlad + elif (self.cycle_count == 1): + self.databyte |= (self.oldlad << 4) + else: + self.putb([0, ['Warning: Invalid cycle_count: %d' % self.cycle_count]]) + self.state = 'IDLE' + return + + if (self.cycle_count != 1): + self.cycle_count += 1 + return + + self.es_block = self.samplenum + self.putb([7, ['DATA: 0x%02x' % self.databyte]]) + self.ss_block = self.samplenum + + self.cycle_count = 0 + self.state = 'GET TAR2' + + def handle_get_tar2(self): + # LAD[3:0]: Second TAR field (2 clock cycles). + + self.es_block = self.samplenum + self.putb([8, ['TAR, cycle %d: %s' % (self.tarcount, self.oldlad_bits)]]) + self.ss_block = self.samplenum + + # On the first TAR clock cycle LAD[3:0] is driven to 1111 by + # either the host or peripheral. On the second clock cycle, + # the host or peripheral tri-states LAD[3:0], but its value + # should still be 1111, due to pull-ups on the LAD lines. + if self.oldlad_bits != '1111': + self.putb([0, ['Warning: TAR, cycle %d: %s (expected 1111)' + % (self.tarcount, self.oldlad_bits)]]) + + if (self.tarcount != 1): + self.tarcount += 1 + return + + self.tarcount = 0 + self.state = 'IDLE' + + def decode(self): + while True: + + # Only look at the signals upon rising LCLK edges. The LPC clock + # is the same as the PCI clock (which is sampled at rising edges). + (lframe, lclk, lad0, lad1, lad2, lad3, lreset, ldrq, serirq, clkrun, lpme, lpcpd, lsmi) = self.wait({1: 'r'}) + + # Store LAD[3:0] bit values (one nibble) in local variables. + # Most (but not all) states need this. + lad = (lad3 << 3) | (lad2 << 2) | (lad1 << 1) | lad0 + lad_bits = '{:04b}'.format(lad) + # self.putb([0, ['LAD: %s' % lad_bits]]) + + # TODO: Only memory read/write is currently supported/tested. + + # Detect host cycle abort requests + if (lframe == 0) and (self.oldlframe == 0): + self.state = 'GET TIMEOUT' + + # State machine + if self.state == 'IDLE': + # A valid LPC cycle starts with LFRAME# being asserted (low). + if lframe == 0: + self.ss_block = self.samplenum + self.state = 'GET START' + self.lad = -1 + else: + self.wait({0: 'f'}) + elif self.state == 'GET START': + self.handle_get_start(lframe) + elif self.state == 'GET CT/DR': + self.handle_get_ct_dr() + elif self.state == 'GET ADDR': + self.handle_get_addr() + elif self.state == 'GET FW IDSEL': + self.handle_get_fw_idsel() + elif self.state == 'GET FW ADDR': + self.handle_get_fw_addr() + elif self.state == 'GET FW MSIZE': + self.handle_get_fw_msize() + elif self.state == 'GET TAR': + self.handle_get_tar() + elif self.state == 'GET SYNC': + self.handle_get_sync(lframe) + elif self.state == 'GET TIMEOUT': + self.handle_get_timeout() + elif self.state == 'GET FW DATA': + self.handle_get_fw_data() + elif self.state == 'GET DATA': + self.handle_get_data() + elif self.state == 'GET TAR2': + self.handle_get_tar2() + + self.oldlframe = lframe + self.oldlad = lad + self.oldlad_bits = lad_bits diff --git a/libsigrokdecode4DSL/decoders/ltc242x/__init__.py b/libsigrokdecode4DSL/decoders/ltc242x/__init__.py new file mode 100644 index 00000000..43d9d346 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ltc242x/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 Analog Devices Inc. +## +## 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 . +## + +''' +This decoder stacks on top of the 'spi' PD and decodes the +Linear Technology LTC2421/LTC2422 protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/ltc242x/pd.py b/libsigrokdecode4DSL/decoders/ltc242x/pd.py new file mode 100644 index 00000000..27ae5b99 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ltc242x/pd.py @@ -0,0 +1,86 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 Analog Devices Inc. +## +## 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 . +## + +import sigrokdecode as srd + +input_voltage_format = ['%.6fV', '%.2fV'] + +class Decoder(srd.Decoder): + api_version = 3 + id = 'ltc242x' + name = 'LTC242x' + longname = 'Linear Technology LTC242x' + desc = 'Linear Technology LTC2421/LTC2422 1-/2-channel 20-bit ADC.' + license = 'gplv2+' + inputs = ['spi'] + outputs = [] + tags = ['IC', 'Analog/digital'] + annotations = ( + ('ch0_voltage', 'CH0 voltage'), + ('ch1_voltage', 'CH1 voltage'), + ) + annotation_rows = ( + ('ch0_voltages', 'CH0 voltages', (0,)), + ('ch1_voltages', 'CH1 voltages', (1,)), + ) + options = ( + {'id': 'vref', 'desc': 'Reference voltage (V)', 'default': 1.5}, + ) + + def __init__(self): + self.reset() + + def reset(self): + self.data = 0 + self.ss, self.es = 0, 0 + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def handle_input_voltage(self, data): + input_voltage = data & 0x3FFFFF + input_voltage = -(2**21 - input_voltage) + input_voltage = (input_voltage / 0xfffff) * self.options['vref'] + ann = [] + for format in input_voltage_format: + ann.append(format % input_voltage) + + channel = (data & (1 << 22)) >> 22 + self.put(self.ss, self.es, self.out_ann, [channel, ann]) + + def decode(self, ss, es, data): + ptype = data[0] + + if ptype == 'CS-CHANGE': + cs_old, cs_new = data[1:] + if cs_old is not None and cs_old == 0 and cs_new == 1: + self.es = es + self.data >>= 1 + self.handle_input_voltage(self.data) + + self.data = 0 + elif cs_old is not None and cs_old == 1 and cs_new == 0: + self.ss = ss + + elif ptype == 'BITS': + miso = data[2] + for bit in reversed(miso): + self.data = self.data | bit[0] + + self.data <<= 1 diff --git a/libsigrokdecode4DSL/decoders/ltc26x7/__init__.py b/libsigrokdecode4DSL/decoders/ltc26x7/__init__.py new file mode 100644 index 00000000..efedd4d3 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ltc26x7/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 Analog Devices Inc. +## +## 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 . +## + +''' +This decoder stacks on top of the 'i2c' PD and decodes the +Linear Technology LTC2607/LTC2617/LTC2627 protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/ltc26x7/pd.py b/libsigrokdecode4DSL/decoders/ltc26x7/pd.py new file mode 100644 index 00000000..3255d5fd --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ltc26x7/pd.py @@ -0,0 +1,187 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 Analog Devices Inc. +## +## 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 . +## + +import sigrokdecode as srd + +slave_address = { + 0x00: ['GND', 'GND', 'GND', 'G'], + 0x01: ['FLOAT', 'FLOAT', 'FLOAT', 'F'], + 0x02: ['VCC', 'VCC', 'VCC', 'V'], +} + +commands = { + 0x00: ['Write Input Register', 'Write In Reg', 'Wr In Reg', 'WIR'], + 0x01: ['Update DAC', 'Update', 'U'], + 0x03: ['Write and Power Up DAC', 'Write & Power Up', 'W&PU'], + 0x04: ['Power Down DAC', 'Power Down', 'PD'], + 0x0F: ['No Operation', 'No Op', 'NO'], +} + +addresses = { + 0x00: ['DAC A', 'A'], + 0x01: ['DAC B', 'B'], + 0x0F: ['All DACs', 'All'], +} + +input_voltage_format = ['%.6fV', '%.2fV'] + +class Decoder(srd.Decoder): + api_version = 3 + id = 'ltc26x7' + name = 'LTC26x7' + longname = 'Linear Technology LTC26x7' + desc = 'Linear Technology LTC26x7 16-/14-/12-bit rail-to-rail DACs.' + license = 'gplv2+' + inputs = ['i2c'] + outputs = [] + tags = ['IC', 'Analog/digital'] + options = ( + {'id': 'chip', 'desc': 'Chip', 'default': 'ltc2607', + 'values': ('ltc2607', 'ltc2617', 'ltc2627')}, + {'id': 'vref', 'desc': 'Reference voltage (V)', 'default': 1.5}, + ) + annotations = ( + ('slave_addr', 'Slave address'), + ('command', 'Command'), + ('address', 'Address'), + ('dac_a_voltage', 'DAC A voltage'), + ('dac_b_voltage', 'DAC B voltage'), + ) + annotation_rows = ( + ('addr_cmd', 'Address/command', (0, 1, 2)), + ('dac_a_voltages', 'DAC A voltages', (3,)), + ('dac_b_voltages', 'DAC B voltages', (4,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.state = 'IDLE' + self.ss = -1 + self.data = 0x00 + self.dac_val = 0 + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def convert_ternary_str(self, n): + if n == 0: + return [0, 0, 0] + nums = [] + while n: + n, r = divmod(n, 3) + nums.append(r) + while len(nums) < 3: + nums.append(0) + return list(reversed(nums)) + + def handle_slave_addr(self, data): + if data == 0x73: + ann = ['Global address', 'Global addr', 'Glob addr', 'GA'] + self.put(self.ss, self.es, self.out_ann, [0, ann]) + return + ann = ['CA2=%s CA1=%s CA0=%s', '2=%s 1=%s 0=%s', '%s %s %s', '%s %s %s'] + addr = 0 + for i in range(7): + if i in [2, 3]: + continue + offset = i + if i > 3: + offset -= 2 + mask = 1 << i + if data & mask: + mask = 1 << offset + addr |= mask + + addr -= 0x04 + ternary_values = self.convert_ternary_str(addr) + for i in range(len(ann)): + ann[i] = ann[i] % (slave_address[ternary_values[0]][i], + slave_address[ternary_values[1]][i], + slave_address[ternary_values[2]][i]) + self.put(self.ss, self.es, self.out_ann, [0, ann]) + + def handle_cmd_addr(self, data): + cmd_val = (data >> 4) & 0x0F + self.dac_val = (data & 0x0F) + sm = (self.ss + self.es) // 2 + + self.put(self.ss, sm, self.out_ann, [1, commands[cmd_val]]) + self.put(sm, self.es, self.out_ann, [2, addresses[self.dac_val]]) + + def handle_data(self, data): + self.data = (self.data << 8) & 0xFF00 + self.data += data + if self.options['chip'] == 'ltc2617': + self.data = (self.data >> 2) + self.data = (self.options['vref'] * self.data) / 0x3FFF + elif self.options['chip'] == 'ltc2627': + self.data = (self.data >> 4) + self.data = (self.options['vref'] * self.data) / 0x0FFF + else: + self.data = (self.options['vref'] * self.data) / 0xFFFF + ann = [] + for format in input_voltage_format: + ann.append(format % self.data) + self.data = 0 + + if self.dac_val == 0x0F: # All DACs (A and B). + self.put(self.ss, self.es, self.out_ann, [3 + 0, ann]) + self.put(self.ss, self.es, self.out_ann, [3 + 1, ann]) + else: + self.put(self.ss, self.es, self.out_ann, [3 + self.dac_val, ann]) + + def decode(self, ss, es, data): + cmd, databyte = data + self.es = es + + # State machine. + if self.state == 'IDLE': + # Wait for an I²C START condition. + if cmd != 'START': + return + self.state = 'GET SLAVE ADDR' + elif self.state == 'GET SLAVE ADDR': + # Wait for an address write operation. + if cmd != 'ADDRESS WRITE': + return + self.ss = ss + self.handle_slave_addr(databyte) + self.ss = -1 + self.state = 'GET CMD ADDR' + elif self.state == 'GET CMD ADDR': + if cmd != 'DATA WRITE': + return + self.ss = ss + self.handle_cmd_addr(databyte) + self.ss = -1 + self.state = 'WRITE DATA' + elif self.state == 'WRITE DATA': + if cmd == 'DATA WRITE': + if self.ss == -1: + self.ss = ss + self.data = databyte + return + self.handle_data(databyte) + self.ss = -1 + elif cmd == 'STOP': + self.state = 'IDLE' + else: + return diff --git a/libsigrokdecode4DSL/decoders/maple_bus/__init__.py b/libsigrokdecode4DSL/decoders/maple_bus/__init__.py new file mode 100644 index 00000000..33b90a5b --- /dev/null +++ b/libsigrokdecode4DSL/decoders/maple_bus/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2017 Marcus Comstedt +## +## 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, see . +## + +''' +Maple bus is serial communication protocol used by peripherals for the +SEGA Dreamcast game console. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/maple_bus/pd.py b/libsigrokdecode4DSL/decoders/maple_bus/pd.py new file mode 100644 index 00000000..0e4e6043 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/maple_bus/pd.py @@ -0,0 +1,219 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2017 Marcus Comstedt +## Copyright (C) 2019 DreamSourceLab +## +## 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, see . +## + +import sigrokdecode as srd + +ann = [ + ['Size', 'L'], + ['SrcAP', 'S'], + ['DstAP', 'D'], + ['Cmd', 'C'], + ['Data'], + ['Cksum', 'K'], +] + +class Decoder(srd.Decoder): + api_version = 3 + id = 'maple_bus' + name = 'Maple bus' + longname = 'SEGA Maple bus' + desc = 'Maple bus peripheral protocol for SEGA Dreamcast.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Retro computing'] + channels = ( + {'id': 'sdcka', 'name': 'SDCKA', 'desc': 'Data/clock line A'}, + {'id': 'sdckb', 'name': 'SDCKB', 'desc': 'Data/clock line B'}, + ) + annotations = ( + ('start', 'Start pattern'), + ('end', 'End pattern'), + ('start-with-crc', 'Start pattern with CRC'), + ('occupancy', 'SDCKB occupancy pattern'), + ('reset', 'RESET pattern'), + ('bit', 'Bit'), + ('size', 'Data size'), + ('source', 'Source AP'), + ('dest', 'Destination AP'), + ('command', 'Command'), + ('data', 'Data'), + ('checksum', 'Checksum'), + ('frame-error', 'Frame error'), + ('checksum-error', 'Checksum error'), + ('size-error', 'Size error'), + ) + annotation_rows = ( + ('bits', 'Bits', (0, 1, 2, 3, 4, 5)), + ('fields', 'Fields', (6, 7, 8, 9, 10, 11)), + ('warnings', 'Warnings', (12, 13, 14)), + ) + binary = ( + ('size', 'Data size'), + ('source', 'Source AP'), + ('dest', 'Destination AP'), + ('command', 'Command code'), + ('data', 'Data'), + ('checksum', 'Checksum'), + ) + + def __init__(self): + self.reset() + + def reset(self): + pass + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_binary = self.register(srd.OUTPUT_BINARY) + self.pending_bit_pos = None + + def putx(self, data): + self.put(self.ss, self.es, self.out_ann, data) + + def putb(self, data): + self.put(self.ss, self.es, self.out_binary, data) + + def byte_annotation(self, bintype, d): + return [bintype + 6, + ['%s: %02X' % (name, d) for name in ann[bintype]] + ['%02X' % d]] + + def got_start(self): + self.putx([0, ['Start pattern', 'Start', 'S']]) + + def got_end(self): + self.putx([1, ['End pattern', 'End', 'E']]) + if self.length != self.expected_length + 1: + self.putx([14, ['Size error', 'L error', 'LE']]) + + def got_start_with_crc(self): + self.putx([2, ['Start pattern with CRC', 'Start CRC', 'SC']]) + + def got_occupancy(self): + self.putx([3, ['SDCKB occupancy pattern', 'Occupancy', 'O']]) + + def got_reset(self): + self.putx([4, ['RESET pattern', 'RESET', 'R']]) + + def output_pending_bit(self): + if self.pending_bit_pos: + self.put(self.pending_bit_pos, self.pending_bit_pos, self.out_ann, [5, ['Bit: %d' % self.pending_bit, '%d' % self.pending_bit]]) + + def got_bit(self, n): + self.output_pending_bit() + self.data = self.data * 2 + n + self.pending_bit = n + self.pending_bit_pos = self.samplenum + + def got_byte(self): + self.output_pending_bit() + bintype = 4 + if self.length < 4: + if self.length == 0: + self.expected_length = 4 * (self.data + 1) + bintype = self.length + elif self.length == self.expected_length: + bintype = 5 + if self.data != self.checksum: + self.putx([13, ['Cksum error', 'K error', 'KE']]) + self.length = self.length + 1 + self.checksum = self.checksum ^ self.data + self.putx(self.byte_annotation(bintype, self.data)) + self.putb([bintype, bytes([self.data])]) + self.pending_bit_pos = None + + def frame_error(self): + self.putx([7, ['Frame error', 'F error', 'FE']]) + + def handle_start(self): + self.wait({0: 'l', 1: 'h'}) + self.ss = self.samplenum + count = 0 + while True: + (sdcka, sdckb) = self.wait([{1: 'f'}, {0: 'r'}]) + if (self.matched & (0b1 << 0)): + count = count + 1 + if (self.matched & (0b1 << 1)): + self.es = self.samplenum + if sdckb == 1: + if count == 4: + self.got_start() + return True + elif count == 6: + self.got_start_with_crc() + return True + elif count == 8: + self.got_occupancy() + return False + elif count >= 14: + self.got_reset() + return False + self.frame_error() + return False + + def handle_byte_or_stop(self): + self.ss = self.samplenum + self.pending_bit_pos = None + initial = True + counta = 0 + countb = 0 + self.data = 0 + while countb < 4: + (sdcka, sdckb) = self.wait([{0: 'f'}, {1: 'f'}]) + self.es = self.samplenum + if (self.matched & (0b1 << 0)): + if counta == countb: + self.got_bit(sdckb) + counta = counta + 1 + elif counta == 1 and countb == 0 and self.data == 0 and sdckb == 0: + self.wait([{0: 'h', 1: 'h'}, {0: 'f'}, {1: 'f'}]) + self.es = self.samplenum + if (self.matched & (0b1 << 0)): + self.got_end() + else: + self.frame_error() + return False + else: + self.frame_error() + return False + elif (self.matched & (0b1 << 1)): + if counta == countb + 1: + self.got_bit(sdcka) + countb = countb + 1 + elif counta == 0 and countb == 0 and sdcka == 1 and initial: + self.ss = self.samplenum + initial = False + else: + self.frame_error() + return False + self.wait({0: 'h'}) + self.es = self.samplenum + self.got_byte() + return True + + def decode(self): + while True: + while not self.handle_start(): + pass + self.length = 0 + self.expected_length = 4 + self.checksum = 0 + while self.handle_byte_or_stop(): + pass diff --git a/libsigrokdecode4DSL/decoders/max7219/__init__.py b/libsigrokdecode4DSL/decoders/max7219/__init__.py new file mode 100644 index 00000000..673d3040 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/max7219/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Paul Evans +## +## 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, see . +## + +''' +This decoder stacks on top of the 'spi' PD and decodes the Maxim MAX7219 and +MAX7221 LED matrix driver protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/max7219/pd.py b/libsigrokdecode4DSL/decoders/max7219/pd.py new file mode 100644 index 00000000..53067a67 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/max7219/pd.py @@ -0,0 +1,115 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Paul Evans +## +## 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, see . +## + +import re +import sigrokdecode as srd + +def _decode_intensity(val): + intensity = val & 0x0f + if intensity == 0: + return 'min' + elif intensity == 15: + return 'max' + else: + return intensity + +registers = { + 0x00: ['No-op', lambda _: ''], + 0x09: ['Decode', lambda v: '0b{:08b}'.format(v)], + 0x0A: ['Intensity', _decode_intensity], + 0x0B: ['Scan limit', lambda v: 1 + v], + 0x0C: ['Shutdown', lambda v: 'off' if v else 'on'], + 0x0F: ['Display test', lambda v: 'on' if v else 'off'] +} + +ann_reg, ann_digit, ann_warning = range(3) + +class Decoder(srd.Decoder): + api_version = 3 + id = 'max7219' + name = 'MAX7219' + longname = 'Maxim MAX7219/MAX7221' + desc = 'Maxim MAX72xx series 8-digit LED display driver.' + license = 'gplv2+' + inputs = ['spi'] + outputs = [] + tags = ['Display'] + annotations = ( + ('register', 'Registers written to the device'), + ('digit', 'Digits displayed on the device'), + ('warnings', 'Human-readable warnings'), + ) + annotation_rows = ( + ('commands', 'Commands', (ann_reg, ann_digit)), + ('warnings', 'Warnings', (ann_warning,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + pass + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.pos = 0 + self.cs_start = 0 + + def putreg(self, ss, es, reg, value): + self.put(ss, es, self.out_ann, [ann_reg, ['%s: %s' % (reg, value)]]) + + def putdigit(self, ss, es, digit, value): + self.put(ss, es, self.out_ann, [ann_digit, ['Digit %d: %02X' % (digit, value)]]) + + def putwarn(self, ss, es, message): + self.put(ss, es, self.out_ann, [ann_warning, [message]]) + + def decode(self, ss, es, data): + ptype, mosi, _ = data + + if ptype == 'DATA': + if not self.cs_asserted: + return + + if self.pos == 0: + self.addr = mosi + self.addr_start = ss + elif self.pos == 1: + if self.addr >= 1 and self.addr <= 8: + self.putdigit(self.addr_start, es, self.addr, mosi) + elif self.addr in registers: + name, decoder = registers[self.addr] + self.putreg(self.addr_start, es, name, decoder(mosi)) + else: + self.putwarn(self.addr_start, es, + 'Unknown register %02X' % (self.addr)) + + self.pos += 1 + elif ptype == 'CS-CHANGE': + self.cs_asserted = mosi + if self.cs_asserted: + self.pos = 0 + self.cs_start = ss + else: + if self.pos == 1: + # Don't warn if pos=0 so that CS# glitches don't appear + # as spurious warnings. + self.putwarn(self.cs_start, es, 'Short write') + elif self.pos > 2: + self.putwarn(self.cs_start, es, 'Overlong write') diff --git a/libsigrokdecode4DSL/decoders/mcs48/__init__.py b/libsigrokdecode4DSL/decoders/mcs48/__init__.py new file mode 100644 index 00000000..b989a2a8 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/mcs48/__init__.py @@ -0,0 +1,31 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 fenugrec +## +## 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, see . +## + +''' +This protocol decoder de-multiplexes Intel MCS-48 (8039, 8048, etc.) external +program memory accesses. + +This requires 14 channels: 8 for D0-D7 (data and lower 8 bits of address), +4 for A8-A11 (output on port P2), ALE and PSEN. + +An optional A12 is supported, which may be an arbitrary I/O pin driven by +software (use case is dumping ROM of an HP 3478A). +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/mcs48/pd.py b/libsigrokdecode4DSL/decoders/mcs48/pd.py new file mode 100644 index 00000000..50216a41 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/mcs48/pd.py @@ -0,0 +1,119 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 fenugrec +## Copyright (C) 2019 DreamSourceLab +## +## 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, see . +## + +import sigrokdecode as srd + +class ChannelError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = 'mcs48' + name = 'MCS-48' + longname = 'Intel MCS-48' + desc = 'Intel MCS-48 external memory access protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Retro computing'] + channels = ( + {'id': 'ale', 'name': 'ALE', 'desc': 'Address latch enable'}, + {'id': 'psen', 'name': '/PSEN', 'desc': 'Program store enable'}, + ) + tuple({ + 'id': 'd%d' % i, + 'name': 'D%d' % i, + 'desc': 'CPU data line %d' % i + } for i in range(0, 8) + ) + tuple({ + 'id': 'a%d' % i, + 'name': 'A%d' % i, + 'desc': 'CPU address line %d' % i + } for i in range(8, 12) + ) + optional_channels = tuple({ + 'id': 'a%d' % i, + 'name': 'A%d' % i, + 'desc': 'CPU address line %d' % i + } for i in range(12, 13) + ) + annotations = ( + ('romdata', 'Address:Data'), + ) + binary = ( + ('romdata', 'AAAA:DD'), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.addr = 0 + self.addr_s = 0 + self.data = 0 + self.data_s = 0 + + # Flag to make sure we get an ALE pulse first. + self.started = 0 + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_bin = self.register(srd.OUTPUT_BINARY) + + def newaddr(self, addr, data): + # Falling edge on ALE: reconstruct address. + self.started = 1 + addr = sum([bit << i for i, bit in enumerate(addr)]) + addr <<= len(data) + addr |= sum([bit << i for i, bit in enumerate(data)]) + self.addr = addr + self.addr_s = self.samplenum + + def newdata(self, data): + # Edge on PSEN: get data. + data = sum([bit << i for i, bit in enumerate(data)]) + self.data = data + self.data_s = self.samplenum + if self.started: + anntext = '{:04X}:{:02X}'.format(self.addr, self.data) + self.put(self.addr_s, self.data_s, self.out_ann, [0, [anntext]]) + bindata = self.addr.to_bytes(2, byteorder='big') + bindata += self.data.to_bytes(1, byteorder='big') + self.put(self.addr_s, self.data_s, self.out_bin, [0, bindata]) + + def decode(self): + # Address bits above A11 are optional, and are considered to be A12+. + # This logic needs more adjustment when more bank address pins are + # to get supported. For now, having just A12 is considered sufficient. + has_bank = self.has_channel(14) + bank_pin_count = 1 if has_bank else 0 + # Sample address on the falling ALE edge. + # Save data on falling edge of PSEN. + while True: + (ale, psen, d0, d1, d2, d3, d4, d5, d6, d7, a8, a9, a10, a11, a12) = self.wait([{0: 'f'}, {1: 'r'}]) + data = (d0, d1, d2, d3, d4, d5, d6, d7) + addr = (a8, a9, a10, a11) + bank = (a12, ) + if has_bank: + addr += bank[:bank_pin_count] + # Handle those conditions (one or more) that matched this time. + if (self.matched & (0b1 << 0)): + self.newaddr(addr, data) + if (self.matched & (0b1 << 1)): + self.newdata(data) diff --git a/libsigrokdecode4DSL/decoders/mdio/__init__.py b/libsigrokdecode4DSL/decoders/mdio/__init__.py new file mode 100644 index 00000000..98213b97 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/mdio/__init__.py @@ -0,0 +1,39 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2016 Elias Oenal +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are met: +## +## 1. Redistributions of source code must retain the above copyright notice, +## this list of conditions and the following disclaimer. +## 2. Redistributions in binary form must reproduce the above copyright notice, +## this list of conditions and the following disclaimer in the documentation +## and/or other materials provided with the distribution. +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +## ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +## LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +## POSSIBILITY OF SUCH DAMAGE. +## + +''' +The MDIO (Management Data Input/Output) protocol decoder supports the +MII Management serial bus (a bidirectional bus between the PHY and the STA), +with a clock line (MDC) and a bi-directional data line (MDIO). + +MDIO is also known as SMI (Serial Management Interface). + +It's part of the Ethernet standard. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/mdio/pd.py b/libsigrokdecode4DSL/decoders/mdio/pd.py new file mode 100644 index 00000000..9ea76c9e --- /dev/null +++ b/libsigrokdecode4DSL/decoders/mdio/pd.py @@ -0,0 +1,327 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2016 Elias Oenal +## Copyright (C) 2019 DreamSourceLab +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are met: +## +## 1. Redistributions of source code must retain the above copyright notice, +## this list of conditions and the following disclaimer. +## 2. Redistributions in binary form must reproduce the above copyright notice, +## this list of conditions and the following disclaimer in the documentation +## and/or other materials provided with the distribution. +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +## ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +## LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +## POSSIBILITY OF SUCH DAMAGE. +## + +import sigrokdecode as srd + +class Decoder(srd.Decoder): + api_version = 3 + id = 'mdio' + name = 'MDIO' + longname = 'Management Data Input/Output' + desc = 'MII management bus between MAC and PHY.' + license = 'bsd' + inputs = ['logic'] + outputs = ['mdio'] + tags = ['Networking'] + channels = ( + {'id': 'mdc', 'name': 'MDC', 'desc': 'Clock'}, + {'id': 'mdio', 'name': 'MDIO', 'desc': 'Data'}, + ) + options = ( + {'id': 'show_debug_bits', 'desc': 'Show debug bits', + 'default': 'no', 'values': ('yes', 'no')}, + ) + annotations = ( + ('bit-val', 'Bit value'), + ('bit-num', 'Bit number'), + ('frame', 'Frame'), + ('frame-idle', 'Bus idle state'), + ('frame-error', 'Frame error'), + ('decode', 'Decode'), + ) + annotation_rows = ( + ('bit-val', 'Bit value', (0,)), + ('bit-num', 'Bit number', (1,)), + ('frame', 'Frame', (2, 3)), + ('frame-error', 'Frame error', (4,)), + ('decode', 'Decode', (5,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.illegal_bus = 0 + self.samplenum = -1 + self.clause45_addr = -1 # Clause 45 is context sensitive. + self.reset_decoder_state() + + def start(self): + self.out_python = self.register(srd.OUTPUT_PYTHON) + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putbit(self, mdio, ss, es): + self.put(ss, es, self.out_ann, [0, ['%d' % mdio]]) + if self.options['show_debug_bits'] == 'yes': + self.put(ss, es, self.out_ann, [1, ['%d' % (self.bitcount - 1), '%d' % ((self.bitcount - 1) % 10)]]) + + def putff(self, data): + self.put(self.ss_frame_field, self.samplenum, self.out_ann, data) + + def putdata(self): + self.put(self.ss_frame_field, self.mdiobits[0][2], self.out_ann, + [2, ['DATA: %04X' % self.data, 'DATA', 'D']]) + + if self.clause45 and self.opcode == 0: + self.clause45_addr = self.data + + # Decode data. + if self.opcode > 0 or not self.clause45: + decoded_min = '' + if self.clause45 and self.clause45_addr != -1: + decoded_min += str.format('ADDR: %04X ' % self.clause45_addr) + elif self.clause45: + decoded_min += str.format('ADDR: UKWN ') + + if self.clause45 and self.opcode > 1 \ + or (not self.clause45 and self.opcode): + decoded_min += str.format('READ: %04X' % self.data) + is_read = 1 + else: + decoded_min += str.format('WRITE: %04X' % self.data) + is_read = 0 + decoded_ext = str.format(' %s: %02d' % \ + ('PRTAD' if self.clause45 else 'PHYAD', self.portad)) + decoded_ext += str.format(' %s: %02d' % \ + ('DEVAD' if self.clause45 else 'REGAD', self.devad)) + if self.ta_invalid or self.op_invalid: + decoded_ext += ' ERROR' + self.put(self.ss_frame, self.mdiobits[0][2], self.out_ann, + [5, [decoded_min + decoded_ext, decoded_min]]) + + self.put(self.ss_frame, self.mdiobits[0][2], self.out_python, + [(bool(self.clause45), int(self.clause45_addr), \ + bool(is_read), int(self.portad), int(self.devad), \ + int(self.data))]) + + # Post read increment address. + if self.clause45 and self.opcode == 2 and self.clause45_addr != -1: + self.clause45_addr += 1 + + def reset_decoder_state(self): + self.mdiobits = [] + self.bitcount = -1 + self.opcode = -1 + self.clause45 = 0 + self.ss_frame = -1 + self.ss_frame_field = -1 + self.preamble_len = 0 + self.ta_invalid = -1 + self.op_invalid = '' + self.portad = -1 + self.portad_bits = 5 + self.devad = -1 + self.devad_bits = 5 + self.data = -1 + self.data_bits = 16 + self.state = 'PRE' + + def state_PRE(self, mdio): + if self.illegal_bus: + if mdio == 0: # Stay in illegal bus state. + return + else: # Leave and continue parsing. + self.illegal_bus = 0 + self.put(self.ss_illegal, self.samplenum, self.out_ann, + [4, ['ILLEGAL BUS STATE', 'ILL']]) + self.ss_frame = self.samplenum + + if self.ss_frame == -1: + self.ss_frame = self.samplenum + + if mdio == 1: + self.preamble_len += 1 + + # Valid MDIO can't clock more than 16 succeeding ones without being + # in either IDLE or PRE. + if self.preamble_len > 16: + if self.preamble_len >= 10000 + 32: + self.put(self.ss_frame, self.mdiobits[32][1], self.out_ann, + [3, ['IDLE #%d' % (self.preamble_len - 32), 'IDLE', 'I']]) + self.ss_frame = self.mdiobits[32][1] + self.preamble_len = 32 + # This is getting out of hand, free some memory. + del self.mdiobits[33:-1] + if mdio == 0: + if self.preamble_len < 32: + self.ss_frame = self.mdiobits[self.preamble_len][1] + self.put(self.ss_frame, self.samplenum, self.out_ann, + [4, ['SHORT PREAMBLE', 'SHRT PRE']]) + elif self.preamble_len > 32: + self.ss_frame = self.mdiobits[32][1] + self.put(self.mdiobits[self.preamble_len][1], + self.mdiobits[32][1], self.out_ann, + [3, ['IDLE #%d' % (self.preamble_len - 32), + 'IDLE', 'I']]) + self.preamble_len = 32 + else: + self.ss_frame = self.mdiobits[32][1] + self.put(self.ss_frame, self.samplenum, self.out_ann, + [2, ['PRE #%d' % self.preamble_len, 'PRE', 'P']]) + self.ss_frame_field = self.samplenum + self.state = 'ST' + elif mdio == 0: + self.ss_illegal = self.ss_frame + self.illegal_bus = 1 + + def state_ST(self, mdio): + if mdio == 0: + self.clause45 = 1 + self.state = 'OP' + + def state_OP(self, mdio): + if self.opcode == -1: + if self.clause45: + st = ['ST (Clause 45)', 'ST 45'] + else: + st = ['ST (Clause 22)', 'ST 22'] + self.putff([2, st + ['ST', 'S']]) + self.ss_frame_field = self.samplenum + + if mdio: + self.opcode = 2 + else: + self.opcode = 0 + else: + if self.clause45: + self.state = 'PRTAD' + self.opcode += mdio + else: + if mdio == self.opcode: + self.op_invalid = 'invalid for Clause 22' + self.state = 'PRTAD' + + def state_PRTAD(self, mdio): + if self.portad == -1: + self.portad = 0 + if self.clause45: + if self.opcode == 0: + op = ['OP: ADDR', 'OP: A'] + elif self.opcode == 1: + op = ['OP: WRITE', 'OP: W'] + elif self.opcode == 2: + op = ['OP: READINC', 'OP: RI'] + elif self.opcode == 3: + op = ['OP: READ', 'OP: R'] + else: + op = ['OP: READ', 'OP: R'] if self.opcode else ['OP: WRITE', 'OP: W'] + self.putff([2, op + ['OP', 'O']]) + if self.op_invalid: + self.putff([4, ['OP %s' % self.op_invalid, 'OP', 'O']]) + self.ss_frame_field = self.samplenum + self.portad_bits -= 1 + self.portad |= mdio << self.portad_bits + if not self.portad_bits: + self.state = 'DEVAD' + + def state_DEVAD(self, mdio): + if self.devad == -1: + self.devad = 0 + if self.clause45: + prtad = ['PRTAD: %02d' % self.portad, 'PRT', 'P'] + else: + prtad = ['PHYAD: %02d' % self.portad, 'PHY', 'P'] + self.putff([2, prtad]) + self.ss_frame_field = self.samplenum + self.devad_bits -= 1 + self.devad |= mdio << self.devad_bits + if not self.devad_bits: + self.state = 'TA' + + def state_TA(self, mdio): + if self.ta_invalid == -1: + self.ta_invalid = '' + if self.clause45: + regad = ['DEVAD: %02d' % self.devad, 'DEV', 'D'] + else: + regad = ['REGAD: %02d' % self.devad, 'REG', 'R'] + self.putff([2, regad]) + self.ss_frame_field = self.samplenum + if mdio != 1 and ((self.clause45 and self.opcode < 2) + or (not self.clause45 and self.opcode == 0)): + self.ta_invalid = ' invalid (bit1)' + else: + if mdio != 0: + if self.ta_invalid: + self.ta_invalid = ' invalid (bit1 and bit2)' + else: + self.ta_invalid = ' invalid (bit2)' + self.state = 'DATA' + + def state_DATA(self, mdio): + if self.data == -1: + self.data = 0 + self.putff([2, ['TA', 'T']]) + if self.ta_invalid: + self.putff([4, ['TA%s' % self.ta_invalid, 'TA', 'T']]) + self.ss_frame_field = self.samplenum + self.data_bits -= 1 + self.data |= mdio << self.data_bits + if not self.data_bits: + # Output final bit. + self.mdiobits[0][2] = self.mdiobits[0][1] + self.quartile_cycle_length() + self.bitcount += 1 + self.putbit(self.mdiobits[0][0], self.mdiobits[0][1], self.mdiobits[0][2]) + self.putdata() + self.reset_decoder_state() + + def process_state(self, argument, mdio): + method_name = 'state_' + str(argument) + method = getattr(self, method_name) + return method(mdio) + + # Returns the first quartile point of the frames cycle lengths. This is a + # conservative guess for the end of the last cycle. On average it will be + # more likely to fall short, than being too long, which makes for better + # readability in GUIs. + def quartile_cycle_length(self): + # 48 is the minimum number of samples we have to have at the end of a + # frame. The last sample only has a leading clock edge and is ignored. + bitlen = [] + for i in range(1, 49): + bitlen.append(self.mdiobits[i][2] - self.mdiobits[i][1]) + bitlen = sorted(bitlen) + return bitlen[12] + + def handle_bit(self, mdio): + self.bitcount += 1 + self.mdiobits.insert(0, [mdio, self.samplenum, -1]) + + if self.bitcount > 0: + self.mdiobits[1][2] = self.samplenum # Note end of last cycle. + # Output the last bit we processed. + self.putbit(self.mdiobits[1][0], self.mdiobits[1][1], self.mdiobits[1][2]) + + self.process_state(self.state, mdio) + + def decode(self): + while True: + # Process pin state upon rising MDC edge. + (mdc, mdio) = self.wait({0: 'r'}) + self.handle_bit(mdio) diff --git a/libsigrokdecode4DSL/decoders/microwire/__init__.py b/libsigrokdecode4DSL/decoders/microwire/__init__.py new file mode 100644 index 00000000..53f52d09 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/microwire/__init__.py @@ -0,0 +1,40 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2017 Kevin Redon +## +## 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, see . +## + +''' +Microwire is a 3-wire half-duplex synchronous serial communication protocol. + +Originally from National Semiconductor, it is often used in EEPROM chips with +device specific commands on top of the bit stream. + +Channels: + + - CS: chip select, active high + - SK: clock line, for the synchronous communication (idle low) + - SI: slave data input, output by the master and parsed by the selected slave + on rising edge of clock line (idle low) + - SO: slave data output, output by the selected slave and changed on rising + edge of clock line, or goes from low to high when ready during status + check (idle high impedance) + +The channel names might vary from chip to chip but the underlying function is +the same. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/microwire/pd.py b/libsigrokdecode4DSL/decoders/microwire/pd.py new file mode 100644 index 00000000..47d87b85 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/microwire/pd.py @@ -0,0 +1,195 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2017 Kevin Redon +## Copyright (C) 2019 DreamSourceLab +## +## 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, see . +## + +import sigrokdecode as srd +from collections import namedtuple + +''' +OUTPUT_PYTHON format: + +Packet: +[namedtuple('ss': bit start sample number, + 'es': bit end sample number, + 'si': SI bit, + 'so': SO bit, + ), ...] + +Since address and word size are variable, a list of all bits in each packet +need to be output. Since Microwire is a synchronous protocol with separate +input and output lines (SI and SO) they are provided together, but because +Microwire is half-duplex only the SI or SO bits will be considered at once. +To be able to annotate correctly the instructions formed by the bit, the start +and end sample number of each bit (pair of SI/SO bit) are provided. +''' + +PyPacket = namedtuple('PyPacket', 'ss es si so') +Packet = namedtuple('Packet', 'samplenum matched cs sk si so') + +class Decoder(srd.Decoder): + api_version = 3 + id = 'microwire' + name = 'Microwire' + longname = 'Microwire' + desc = '3-wire, half-duplex, synchronous serial bus.' + license = 'gplv2+' + inputs = ['logic'] + outputs = ['microwire'] + tags = ['Embedded/industrial'] + channels = ( + {'id': 'cs', 'name': 'CS', 'desc': 'Chip select'}, + {'id': 'sk', 'name': 'SK', 'desc': 'Clock'}, + {'id': 'si', 'name': 'SI', 'desc': 'Slave in'}, + {'id': 'so', 'name': 'SO', 'desc': 'Slave out'}, + ) + annotations = ( + ('start-bit', 'Start bit'), + ('si-bit', 'SI bit'), + ('so-bit', 'SO bit'), + ('status-check-ready', 'Status check ready'), + ('status-check-busy', 'Status check busy'), + ('warning', 'Warning'), + ) + annotation_rows = ( + ('si-bits', 'SI bits', (0, 1)), + ('so-bits', 'SO bits', (2,)), + ('status', 'Status', (3, 4)), + ('warnings', 'Warnings', (5,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + pass + + def start(self): + self.out_python = self.register(srd.OUTPUT_PYTHON) + self.out_ann = self.register(srd.OUTPUT_ANN) + + def decode(self): + while True: + # Wait for slave to be selected on rising CS. + (cs, sk, si, so) = self.wait({0: 'r'}) + if sk: + self.put(self.samplenum, self.samplenum, self.out_ann, + [5, ['Clock should be low on start', + 'Clock high on start', 'Clock high', 'SK high']]) + sk = 0 # Enforce correct state for correct clock handling. + # Because we don't know if this is bit communication or a + # status check we have to collect the SI and SO values on SK + # edges while the chip is selected and figure out afterwards. + packet = [] + while cs: + # Save change. + packet.append(Packet(self.samplenum, self.matched, cs, sk, si, so)) + edge = 'r' if sk == 0 else 'f' + (cs, sk, si, so) = self.wait([{0: 'l'}, {1: edge}, {3: 'e'}]) + # Save last change. + packet.append(Packet(self.samplenum, self.matched, cs, sk, si, so)) + + # Figure out if this is a status check. + # Either there is no clock or no start bit (on first rising edge). + status_check = True + for change in packet: + # Get first clock rising edge. + if (change.matched & (0b1 << 1)) and change.sk: + if change.si: + status_check = False + break + + # The packet is for a status check. + # SO low = busy, SO high = ready. + # The SO signal might be noisy in the beginning because it starts + # in high impedance. + if status_check: + start_samplenum = packet[0].samplenum + bit_so = packet[0].so + # Check for SO edges. + for change in packet: + if (change.matched & (0b1 << 2)): + if bit_so == 0 and change.so: + # Rising edge Busy -> Ready. + self.put(start_samplenum, change.samplenum, + self.out_ann, [4, ['Busy', 'B']]) + start_samplenum = change.samplenum + bit_so = change.so + # Put last state. + if bit_so == 0: + self.put(start_samplenum, packet[-1].samplenum, + self.out_ann, [4, ['Busy', 'B']]) + else: + self.put(start_samplenum, packet[-1].samplenum, + self.out_ann, [3, ['Ready', 'R']]) + else: + # Bit communication. + # Since the slave samples SI on clock rising edge we do the + # same. Because the slave changes SO on clock rising edge we + # sample on the falling edge. + bit_start = 0 # Rising clock sample of bit start. + bit_si = 0 # SI value at rising clock edge. + bit_so = 0 # SO value at falling clock edge. + start_bit = True # Start bit incoming (first bit). + pydata = [] # Python output data. + for change in packet: + if (change.matched & (0b1 << 1)): + # Clock edge. + if change.sk: # Rising clock edge. + if bit_start > 0: # Bit completed. + if start_bit: + if bit_si == 0: # Start bit missing. + self.put(bit_start, change.samplenum, + self.out_ann, + [5, ['Start bit not high', + 'Start bit low']]) + else: + self.put(bit_start, change.samplenum, + self.out_ann, + [0, ['Start bit', 'S']]) + start_bit = False + else: + self.put(bit_start, change.samplenum, + self.out_ann, + [1, ['SI bit: %d' % bit_si, + 'SI: %d' % bit_si, + '%d' % bit_si]]) + self.put(bit_start, change.samplenum, + self.out_ann, + [2, ['SO bit: %d' % bit_so, + 'SO: %d' % bit_so, + '%d' % bit_so]]) + pydata.append(PyPacket(bit_start, + change.samplenum, bit_si, bit_so)) + bit_start = change.samplenum + bit_si = change.si + else: # Falling clock edge. + bit_so = change.so + elif (change.matched & (0b1 << 0)) and \ + change.cs == 0 and change.sk == 0: + # End of packet. + self.put(bit_start, change.samplenum, self.out_ann, + [1, ['SI bit: %d' % bit_si, + 'SI: %d' % bit_si, '%d' % bit_si]]) + self.put(bit_start, change.samplenum, self.out_ann, + [2, ['SO bit: %d' % bit_so, + 'SO: %d' % bit_so, '%d' % bit_so]]) + pydata.append(PyPacket(bit_start, change.samplenum, + bit_si, bit_so)) + self.put(packet[0].samplenum, packet[len(packet) - 1].samplenum, + self.out_python, pydata) diff --git a/libsigrokdecode4DSL/decoders/midi/__init__.py b/libsigrokdecode4DSL/decoders/midi/__init__.py new file mode 100644 index 00000000..378b0167 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/midi/__init__.py @@ -0,0 +1,28 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2013 Uwe Hermann +## +## 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, see . +## + +''' +This decoder stacks on top of the 'uart' PD and decodes the MIDI +(Musical Instrument Digital Interface) protocol. + +MIDI is layered on top of the UART (async serial) protocol, with a fixed +baud rate of 31250 baud (+/- 1%) and 8n1 settings. Bytes are sent LSB-first. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/midi/lists.py b/libsigrokdecode4DSL/decoders/midi/lists.py new file mode 100644 index 00000000..1e628615 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/midi/lists.py @@ -0,0 +1,840 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2013-2016 Uwe Hermann +## Copyright (C) 2016 Chris Dreher +## +## 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, see . +## + +# Each status byte has 3 string names, each shorter than the previous +status_bytes = { + # Channel voice messages + 0x80: ['note off', 'note off', 'N off'], + 0x90: ['note on', 'note on', 'N on'], # However, velocity = 0 means "note off". + 0xa0: ['polyphonic key pressure / aftertouch', 'key pressure', 'KP' ], + 0xb0: ['control change', 'ctrl chg', 'CC'], + 0xc0: ['program change', 'prgm chg', 'PC'], + 0xd0: ['channel pressure / aftertouch', 'channel pressure', 'CP'], + 0xe0: ['pitch bend change', 'pitch bend', 'PB'], + + # Channel mode messages + # 0xb0: 'select channel mode', # Note: Same as 'control change'. + + # System exclusive messages + 0xf0: ['system exclusive', 'SysEx', 'SE'], + + # System common messages + 0xf1: ['MIDI time code quarter frame', 'MIDI time code', 'MIDI time'], + 0xf2: ['song position pointer', 'song position', 'song pos'], + 0xf3: ['song select', 'song select', 'song sel'], + 0xf4: ['undefined 0xf4', 'undef 0xf4', 'undef'], + 0xf5: ['undefined 0xf5', 'undef 0xf5', 'undef'], + 0xf6: ['tune request', 'tune request', 'tune req'], + 0xf7: ['end of system exclusive (EOX)', 'end of SysEx', 'EOX'], + + # System real time messages + 0xf8: ['timing clock', 'timing clock', 'clock'], + 0xf9: ['undefined 0xf9', 'undef 0xf9', 'undef'], + 0xfa: ['start', 'start', 's'], + 0xfb: ['continue', 'continue', 'cont'], + 0xfc: ['stop', 'stop', 'st'], + 0xfd: ['undefined 0xfd', 'undef 0xfd', 'undef'], + 0xfe: ['active sensing', 'active sensing', 'sensing'], + 0xff: ['system reset', 'reset', 'rst'], +} + +# Universal system exclusive (SysEx) messages, non-realtime (0x7e) +universal_sysex_nonrealtime = { + (0x00, None): 'unused', + (0x01, None): 'sample dump header', + (0x02, None): 'sample data packet', + (0x03, None): 'sample dump request', + + (0x04, None): 'MIDI time code', + (0x04, 0x00): 'special', + (0x04, 0x01): 'punch in points', + (0x04, 0x02): 'punch out points', + (0x04, 0x03): 'delete punch in point', + (0x04, 0x04): 'delete punch out point', + (0x04, 0x05): 'event start point', + (0x04, 0x06): 'event stop point', + (0x04, 0x07): 'event start points with additional info', + (0x04, 0x08): 'event stop points with additional info', + (0x04, 0x09): 'delete event start point', + (0x04, 0x0a): 'delete event stop point', + (0x04, 0x0b): 'cue points', + (0x04, 0x0c): 'cue points with additional info', + (0x04, 0x0d): 'delete cue point', + (0x04, 0x0e): 'event name in additional info', + + (0x05, None): 'sample dump extensions', + (0x05, 0x01): 'multiple loop points', + (0x05, 0x02): 'loop points request', + + (0x06, None): 'general information', + (0x06, 0x01): 'identity request', + (0x06, 0x02): 'identity reply', + + (0x07, None): 'file dump', + (0x07, 0x01): 'header', + (0x07, 0x02): 'data packet', + (0x07, 0x03): 'request', + + (0x08, None): 'MIDI tuning standard', + (0x08, 0x00): 'bulk dump request', + (0x08, 0x01): 'bulk dump reply', + + (0x09, None): 'general MIDI', + (0x09, 0x01): 'general MIDI system on', + (0x09, 0x02): 'general MIDI system off', + + (0x7b, None): 'end of file', + (0x7c, None): 'wait', + (0x7d, None): 'cancel', + (0x7e, None): 'nak', + (0x7f, None): 'ack', +} + +# Universal system exclusive (SysEx) messages, realtime (0x7f) +universal_sysex_realtime = { + (0x00, None): 'unused', + + (0x01, None): 'MIDI time code', + (0x01, 0x01): 'full message', + (0x01, 0x02): 'user bits', + + (0x02, None): 'MIDI show control', + (0x02, 0x00): 'MSC extensions', + # (0x02, TODO): 'TODO', # 0x01 - 0x7f: MSC commands. + + (0x03, None): 'notation information', + (0x03, 0x01): 'bar number', + (0x03, 0x02): 'time signature (immediate)', + (0x03, 0x42): 'time signature (delayed)', + + (0x04, None): 'device control', + (0x04, 0x01): 'master volume', + (0x04, 0x02): 'master balance', + + (0x05, None): 'real time MTC cueing', + (0x05, 0x00): 'special', + (0x05, 0x01): 'punch in points', + (0x05, 0x02): 'punch out points', + (0x05, 0x03): 'reserved', + (0x05, 0x04): 'reserved', + (0x05, 0x05): 'event start points', + (0x05, 0x06): 'event stop points', + (0x05, 0x07): 'event start points with additional info', + (0x05, 0x08): 'event stop points with additional info', + (0x05, 0x09): 'reserved', + (0x05, 0x0a): 'reserved', + (0x05, 0x0b): 'cue points', + (0x05, 0x0c): 'cue points with additional info', + (0x05, 0x0d): 'reserved', + (0x05, 0x0e): 'event name in additional info', + + (0x06, None): 'MIDI machine control commands', + # (0x06, TODO): 'TODO', # 0x00 - 0x7f: MMC commands. + + (0x07, None): 'MIDI machine control responses', + # (0x07, TODO): 'TODO', # 0x00 - 0x7f: MMC commands. + + (0x08, None): 'MIDI tuning standard', + (0x85, 0x02): 'note change', +} + +# Note: Not all IDs are used/listed, i.e. there are some "holes". +sysex_manufacturer_ids = { + # American group (range 01-1f, 000001-001f7f) + (0x01,): 'Sequential', + (0x02,): 'IDP', + (0x03,): 'Voyetra/Octave-Plateau', + (0x04,): 'Moog', + (0x05,): 'Passport Designs', + (0x06,): 'Lexicon', + (0x07,): 'Kurzweil', + (0x08,): 'Fender', + (0x09,): 'Gulbransen', + (0x0a,): 'AKG Acoustics', + (0x0b,): 'Voyce Music', + (0x0c,): 'Waveframe Corp', + (0x0d,): 'ADA Signal Processors', + (0x0e,): 'Garfield Electronics', + (0x0f,): 'Ensoniq', + (0x10,): 'Oberheim', + (0x11,): 'Apple Computer', + (0x12,): 'Grey Matter Response', + (0x13,): 'Digidesign', + (0x14,): 'Palm Tree Instruments', + (0x15,): 'JLCooper Electronics', + (0x16,): 'Lowrey', + (0x17,): 'Adams-Smith', + (0x18,): 'Emu Systems', + (0x19,): 'Harmony Systems', + (0x1a,): 'ART', + (0x1b,): 'Baldwin', + (0x1c,): 'Eventide', + (0x1d,): 'Inventronics', + (0x1f,): 'Clarity', + + (0x00, 0x00, 0x01): 'Time Warner Interactive', + (0x00, 0x00, 0x07): 'Digital Music Corp.', + (0x00, 0x00, 0x08): 'IOTA Systems', + (0x00, 0x00, 0x09): 'New England Digital', + (0x00, 0x00, 0x0a): 'Artisyn', + (0x00, 0x00, 0x0b): 'IVL Technologies', + (0x00, 0x00, 0x0c): 'Southern Music Systems', + (0x00, 0x00, 0x0d): 'Lake Butler Sound Company', + (0x00, 0x00, 0x0e): 'Alesis', + (0x00, 0x00, 0x10): 'DOD Electronics', + (0x00, 0x00, 0x11): 'Studer-Editech', + (0x00, 0x00, 0x14): 'Perfect Fretworks', + (0x00, 0x00, 0x15): 'KAT', + (0x00, 0x00, 0x16): 'Opcode', + (0x00, 0x00, 0x17): 'Rane Corp.', + (0x00, 0x00, 0x18): 'Anadi Inc.', + (0x00, 0x00, 0x19): 'KMX', + (0x00, 0x00, 0x1a): 'Allen & Heath Brenell', + (0x00, 0x00, 0x1b): 'Peavy Electronics', + (0x00, 0x00, 0x1c): '360 Systems', + (0x00, 0x00, 0x1d): 'Spectrum Design and Development', + (0x00, 0x00, 0x1e): 'Marquis Music', + (0x00, 0x00, 0x1f): 'Zeta Systems', + + (0x00, 0x00, 0x20): 'Axxes', + (0x00, 0x00, 0x21): 'Orban', + (0x00, 0x00, 0x24): 'KTI', + (0x00, 0x00, 0x25): 'Breakaway Technologies', + (0x00, 0x00, 0x26): 'CAE', + (0x00, 0x00, 0x29): 'Rocktron Corp.', + (0x00, 0x00, 0x2a): 'PianoDisc', + (0x00, 0x00, 0x2b): 'Cannon Research Group', + (0x00, 0x00, 0x2d): 'Rogers Instrument Corp.', + (0x00, 0x00, 0x2e): 'Blue Sky Logic', + (0x00, 0x00, 0x2f): 'Encore Electronics', + + (0x00, 0x00, 0x30): 'Uptown', + (0x00, 0x00, 0x31): 'Voce', + (0x00, 0x00, 0x32): 'CTI Audio, Inc. (Music. Intel Dev.)', + (0x00, 0x00, 0x33): 'S&S Research', + (0x00, 0x00, 0x34): 'Broderbund Software, Inc.', + (0x00, 0x00, 0x35): 'Allen Organ Co.', + (0x00, 0x00, 0x37): 'Music Quest', + (0x00, 0x00, 0x38): 'APHEX', + (0x00, 0x00, 0x39): 'Gallien Krueger', + (0x00, 0x00, 0x3a): 'IBM', + (0x00, 0x00, 0x3c): 'Hotz Instruments Technologies', + (0x00, 0x00, 0x3d): 'ETA Lighting', + (0x00, 0x00, 0x3e): 'NSI Corporation', + (0x00, 0x00, 0x3f): 'Ad Lib, Inc.', + + (0x00, 0x00, 0x40): 'Richmond Sound Design', + (0x00, 0x00, 0x41): 'Microsoft', + (0x00, 0x00, 0x42): 'The Software Toolworks', + (0x00, 0x00, 0x43): 'Niche/RJMG', + (0x00, 0x00, 0x44): 'Intone', + (0x00, 0x00, 0x47): 'GT Electronics / Groove Tubes', + (0x00, 0x00, 0x49): 'Timeline Vista', + (0x00, 0x00, 0x4a): 'Mesa Boogie', + (0x00, 0x00, 0x4c): 'Sequoia Development', + (0x00, 0x00, 0x4d): 'Studio Electronics', + (0x00, 0x00, 0x4e): 'Euphonix', + (0x00, 0x00, 0x4f): 'InterMIDI, Inc.', + + (0x00, 0x00, 0x50): 'MIDI Solutions', + (0x00, 0x00, 0x51): '3DO Company', + (0x00, 0x00, 0x52): 'Lightwave Research', + (0x00, 0x00, 0x53): 'Micro-W', + (0x00, 0x00, 0x54): 'Spectral Synthesis', + (0x00, 0x00, 0x55): 'Lone Wolf', + (0x00, 0x00, 0x56): 'Studio Technologies', + (0x00, 0x00, 0x57): 'Peterson EMP', + (0x00, 0x00, 0x58): 'Atari', + (0x00, 0x00, 0x59): 'Marion Systems', + (0x00, 0x00, 0x5a): 'Design Event', + (0x00, 0x00, 0x5b): 'Winjammer Software', + (0x00, 0x00, 0x5c): 'AT&T Bell Labs', + (0x00, 0x00, 0x5e): 'Symetrix', + (0x00, 0x00, 0x5f): 'MIDI the World', + + (0x00, 0x00, 0x60): 'Desper Products', + (0x00, 0x00, 0x61): 'Micros\'N MIDI', + (0x00, 0x00, 0x62): 'Accordians Intl', + (0x00, 0x00, 0x63): 'EuPhonics', + (0x00, 0x00, 0x64): 'Musonix', + (0x00, 0x00, 0x65): 'Turtle Beach Systems', + (0x00, 0x00, 0x66): 'Mackie Designs', + (0x00, 0x00, 0x67): 'Compuserve', + (0x00, 0x00, 0x68): 'BES Technologies', + (0x00, 0x00, 0x69): 'QRS Music Rolls', + (0x00, 0x00, 0x6a): 'P G Music', + (0x00, 0x00, 0x6b): 'Sierra Semiconductor', + (0x00, 0x00, 0x6c): 'EpiGraf Audio Visual', + (0x00, 0x00, 0x6d): 'Electronics Deiversified', + (0x00, 0x00, 0x6e): 'Tune 1000', + (0x00, 0x00, 0x6f): 'Advanced Micro Devices', + + (0x00, 0x00, 0x70): 'Mediamation', + (0x00, 0x00, 0x71): 'Sabine Music', + (0x00, 0x00, 0x72): 'Woog Labs', + (0x00, 0x00, 0x73): 'Micropolis', + (0x00, 0x00, 0x74): 'Ta Horng Musical Inst.', + (0x00, 0x00, 0x75): 'eTek (formerly Forte)', + (0x00, 0x00, 0x76): 'Electrovoice', + (0x00, 0x00, 0x77): 'Midisoft', + (0x00, 0x00, 0x78): 'Q-Sound Labs', + (0x00, 0x00, 0x79): 'Westrex', + (0x00, 0x00, 0x7a): 'NVidia', + (0x00, 0x00, 0x7b): 'ESS Technology', + (0x00, 0x00, 0x7c): 'MediaTrix Peripherals', + (0x00, 0x00, 0x7d): 'Brooktree', + (0x00, 0x00, 0x7e): 'Otari', + (0x00, 0x00, 0x7f): 'Key Electronics', + + (0x00, 0x01, 0x01): 'Crystalake Multimedia', + (0x00, 0x01, 0x02): 'Crystal Semiconductor', + (0x00, 0x01, 0x03): 'Rockwell Semiconductor', + + # European group (range 20-3f, 002000-003f7f) + (0x20,): 'Passac', + (0x21,): 'SIEL', + (0x22,): 'Synthaxe', + (0x24,): 'Hohner', + (0x25,): 'Twister', + (0x26,): 'Solton', + (0x27,): 'Jellinghaus MS', + (0x28,): 'Southworth Music Systems', + (0x29,): 'PPG', + (0x2a,): 'JEN', + (0x2b,): 'SSL Limited', + (0x2c,): 'Audio Veritrieb', + (0x2f,): 'Elka', + + (0x30,): 'Dynacord', + (0x31,): 'Viscount', + (0x33,): 'Clavia Digital Instruments', + (0x34,): 'Audio Architecture', + (0x35,): 'GeneralMusic Corp.', + (0x39,): 'Soundcraft Electronics', + (0x3b,): 'Wersi', + (0x3c,): 'Avab Elektronik Ab', + (0x3d,): 'Digigram', + (0x3e,): 'Waldorf Electronics', + (0x3f,): 'Quasimidi', + + (0x00, 0x20, 0x00): 'Dream', + (0x00, 0x20, 0x01): 'Strand Lighting', + (0x00, 0x20, 0x02): 'Amek Systems', + (0x00, 0x20, 0x04): 'Böhm Electronic', + (0x00, 0x20, 0x06): 'Trident Audio', + (0x00, 0x20, 0x07): 'Real World Studio', + (0x00, 0x20, 0x09): 'Yes Technology', + (0x00, 0x20, 0x0a): 'Audiomatica', + (0x00, 0x20, 0x0b): 'Bontempi/Farfisa', + (0x00, 0x20, 0x0c): 'F.B.T. Elettronica', + (0x00, 0x20, 0x0d): 'MidiTemp', + (0x00, 0x20, 0x0e): 'LA Audio (Larking Audio)', + (0x00, 0x20, 0x0f): 'Zero 88 Lighting Limited', + + (0x00, 0x20, 0x10): 'Micon Audio Electronics GmbH', + (0x00, 0x20, 0x11): 'Forefront Technology', + (0x00, 0x20, 0x13): 'Kenton Electronics', + (0x00, 0x20, 0x15): 'ADB', + (0x00, 0x20, 0x16): 'Marshall Products', + (0x00, 0x20, 0x17): 'DDA', + (0x00, 0x20, 0x18): 'BSS', + (0x00, 0x20, 0x19): 'MA Lighting Technology', + (0x00, 0x20, 0x1a): 'Fatar', + (0x00, 0x20, 0x1b): 'QSC Audio', + (0x00, 0x20, 0x1c): 'Artisan Classic Organ', + (0x00, 0x20, 0x1d): 'Orla Spa', + (0x00, 0x20, 0x1e): 'Pinnacle Audio', + (0x00, 0x20, 0x1f): 'TC Electronics', + + (0x00, 0x20, 0x20): 'Doepfer Musikelektronik', + (0x00, 0x20, 0x21): 'Creative Technology Pte', + (0x00, 0x20, 0x22): 'Minami/Seiyddo', + (0x00, 0x20, 0x23): 'Goldstar', + (0x00, 0x20, 0x24): 'Midisoft s.a.s di M. Cima', + (0x00, 0x20, 0x25): 'Samick', + (0x00, 0x20, 0x26): 'Penny and Giles', + (0x00, 0x20, 0x27): 'Acorn Computer', + (0x00, 0x20, 0x28): 'LSC Electronics', + (0x00, 0x20, 0x29): 'Novation EMS', + (0x00, 0x20, 0x2a): 'Samkyung Mechatronics', + (0x00, 0x20, 0x2b): 'Medeli Electronics', + (0x00, 0x20, 0x2c): 'Charlie Lab', + (0x00, 0x20, 0x2d): 'Blue Chip Music Tech', + (0x00, 0x20, 0x2e): 'BEE OH Corp', + + # Japanese group (range 40-5f, 004000-005f7f) + (0x40,): 'Kawai', + (0x41,): 'Roland', + (0x42,): 'Korg', + (0x43,): 'Yamaha', + (0x44,): 'Casio', + (0x46,): 'Kamiya Studio', + (0x47,): 'Akai', + (0x48,): 'Japan Victor', + (0x49,): 'Mesosha', + (0x4a,): 'Hoshino Gakki', + (0x4b,): 'Fujitsu Elect', + (0x4c,): 'Sony', + (0x4d,): 'Nisshin Onpa', + (0x4e,): 'TEAC', + (0x50,): 'Matsushita Electric', + (0x51,): 'Fostex', + (0x52,): 'Zoom', + (0x53,): 'Midori Electronics', + (0x54,): 'Matsushita Communication Industrial', + (0x55,): 'Suzuki Musical Inst. Mfg.', + + # Other (range 60-7c, 006000-007f7f) + + # Special (7d-7f) + (0x7d,): 'Non-Commercial', + (0x7e,): 'Universal Non-Realtime', + (0x7f,): 'Universal Realtime', +} + +control_functions = { + 0x00: ['bank select MSB', 'bank MSB', 'bank-M'], + 0x01: ['modulation wheel/lever MSB', 'modulation MSB', 'mod-M'], + 0x02: ['breath controller MSB', 'breath MSB', 'breath-M'], + # 0x03: undefined MSB + 0x04: ['foot controller MSB', 'foot MSB', 'foot-M'], + 0x05: ['portamento time MSB', 'portamento MSB', 'porta-M'], + 0x06: ['data entry MSB', 'data entry MSB', 'data-M'], + 0x07: ['channel volume MSB (formerly main volume)', 'channel volume MSB', 'ch vol-M'], + 0x08: ['balance MSB', 'bal MSB', 'bal-M'], + # 0x09: undefined MSB + 0x0a: ['pan MSB', 'pan MSB', 'pan-M'], + 0x0b: ['expression controller MSB', 'expression MSB', 'expr-M'], + 0x0c: ['effect control 1 MSB', 'effect 1 MSB', 'eff-1-M'], + 0x0d: ['effect control 2 MSB', 'effect 2 MSB', 'eff-2-M'], + # 0x0e-0x0f: undefined MSB + 0x10: ['general purpose controller 1 MSB', 'GP ctrl 1 MSB', 'GPC-1-M'], + 0x11: ['general purpose controller 2 MSB', 'GP ctrl 2 MSB', 'GPC-2-M'], + 0x12: ['general purpose controller 3 MSB', 'GP ctrl 3 MSB', 'GPC-3-M'], + 0x13: ['general purpose controller 4 MSB', 'GP ctrl 4 MSB', 'GPC-4-M'], + # 0x14-0x1f: undefined MSB + 0x20: ['bank select LSB', 'bank LSB', 'bank-L'], + 0x21: ['modulation wheel/lever LSB', 'modulation LSB', 'mod-L'], + 0x22: ['breath controller LSB', 'breath LSB', 'breath-L'], + # 0x23: undefined LSB + 0x24: ['foot controller LSB', 'foot LSB', 'foot-L'], + 0x25: ['portamento time LSB', 'portamento LSB', 'porta-L'], + 0x26: ['data entry LSB', 'data entry LSB', 'data-L'], + 0x27: ['channel volume LSB (formerly main volume)', 'channel volume LSB', 'ch vol-L'], + 0x28: ['balance LSB', 'bal LSB', 'bal-L'], + # 0x29: undefined LSB + 0x2a: ['pan LSB', 'pan LSB', 'pan-L'], + 0x2b: ['expression controller LSB', 'expression LSB', 'expr-L'], + 0x2c: ['effect control 1 LSB', 'effect 1 LSB', 'eff-1-L'], + 0x2d: ['effect control 2 LSB', 'effect 2 LSB', 'eff-2-L'], + # 0x2e-0x2f: undefined LSB + 0x30: ['general purpose controller 1 LSB', 'GP ctrl 1 LSB', 'GPC-1-L'], + 0x31: ['general purpose controller 2 LSB', 'GP ctrl 2 LSB', 'GPC-2-L'], + 0x32: ['general purpose controller 3 LSB', 'GP ctrl 3 LSB', 'GPC-3-L'], + 0x33: ['general purpose controller 4 LSB', 'GP ctrl 4 LSB', 'GPC-4-L'], + # 0x34-0x3f: undefined LSB + 0x40: ['damper pedal (sustain)', 'sustain', 'sust'], + 0x41: ['portamento on/off', 'porta on/off', 'porta on/off'], + 0x42: ['sostenuto', 'sostenuto', 'sostenuto'], + 0x43: ['soft pedal', 'soft pedal', 'soft pedal'], + 0x44: ['legato footswitch', 'legato switch', 'legato'], # vv: 00-3f = normal, 40-7f = legato + 0x45: ['hold 2', 'hold 2', 'hold 2'], + 0x46: ['sound controller 1 (default: sound variation)', 'sound ctrl 1', 'snd ctrl 1'], + 0x47: ['sound controller 2 (default: timbre / harmonic intensity)', 'sound ctrl 2', 'snd ctrl 2'], + 0x48: ['sound controller 3 (default: release time)', 'sound ctrl 3', 'snd ctrl 3'], + 0x49: ['sound controller 4 (default: attack time)', 'sound ctrl 4', 'snd ctrl 4'], + 0x4a: ['sound controller 5 (default: brightness)', 'sound ctrl 5', 'snd ctrl 5'], + 0x4b: ['sound controller 6 (GM2 default: decay time)', 'sound ctrl 6', 'snd ctrl 6'], + 0x4c: ['sound controller 7 (GM2 default: vibrato rate)', 'sound ctrl 7', 'snd ctrl 7'], + 0x4d: ['sound controller 8 (GM2 default: vibrato depth)', 'sound ctrl 8', 'snd ctrl 8'], + 0x4e: ['sound controller 9 (GM2 default: vibrato delay)', 'sound ctrl 9', 'snd ctrl 9'], + 0x4f: ['sound controller 10', 'sound ctrl 10', 'snd ctrl 10'], + 0x50: ['general purpose controller 5', 'GP controller 5', 'GPC-5'], + 0x51: ['general purpose controller 6', 'GP controller 6', 'GPC-6'], + 0x52: ['general purpose controller 7', 'GP controller 7', 'GPC-7'], + 0x53: ['general purpose controller 8', 'GP controller 8', 'GPC-8'], + 0x54: ['portamento control', 'portamento ctrl', 'porta ctrl'], + # 0x55-0x5a: undefined + 0x5b: ['effects 1 depth (formerly external effects depth)', 'effects 1 depth', 'eff 1 depth'], + 0x5c: ['effects 2 depth (formerly tremolo depth)', 'effects 2 depth', 'eff 2 depth'], + 0x5d: ['effects 3 depth (formerly chorus depth)', 'effects 3 depth', 'eff 3 depth'], + 0x5e: ['effects 4 depth (formerly celeste/detune depth)', 'effects 4 depth', 'eff 4 depth'], + 0x5f: ['effects 5 depth (formerly phaser depth)', 'effects 5 depth', 'eff 5 depth'], + 0x60: ['data increment', 'data inc', 'data++'], + 0x61: ['data decrement', 'data dec', 'data--'], + 0x62: ['Non-Registered Parameter Number LSB', 'NRPN LSB', 'NRPN-L'], + 0x63: ['Non-Registered Parameter Number MSB', 'NRPN MSB', 'NRPN-M'], + 0x64: ['Registered Parameter Number LSB', 'RPN LSB', 'RPN-L'], + 0x65: ['Registered Parameter Number MSB', 'RPN MSB', 'RPN-M'], + # 0x66-0x77: undefined + # 0x78-0x7f: reserved for channel mode messages + 0x78: ['all sound off', 'all snd off', 'snd off'], + 0x79: ['reset all controllers', 'reset all ctrls', 'reset ctrls'], + 0x7a: ['local control', 'local ctrl', 'local ctrl'], + 0x7b: ['all notes off', 'notes off', 'notes off'], + 0x7c: ['omni mode off', 'omni off', 'omni off'], # all notes off + 0x7d: ['omni mode on', 'omni on', 'omni on'], # all notes off + 0x7e: ['mono mode on', 'mono on', 'mono'], # mono mode on, all notes off + 0x7f: ['poly mode on', 'poly on', 'poly'], # mono mode off, all notes off +} + +gm_instruments = { + 1: 'Acoustic Grand Piano', + 2: 'Bright Acoustic Piano', + 3: 'Electric Grand Piano', + 4: 'Honky-tonk Piano', + 5: 'Electric Piano 1', + 6: 'Electric Piano 2', + 7: 'Harpsichord', + 8: 'Clavi', + 9: 'Celesta', + 10: 'Glockenspiel', + 11: 'Music Box', + 12: 'Vibraphone', + 13: 'Marimba', + 14: 'Xylophone', + 15: 'Tubular Bells', + 16: 'Dulcimer', + 17: 'Drawbar Organ', + 18: 'Percussive Organ', + 19: 'Rock Organ', + 20: 'Church Organ', + 21: 'Reed Organ', + 22: 'Accordion', + 23: 'Harmonica', + 24: 'Tango Accordion', + 25: 'Acoustic Guitar (nylon)', + 26: 'Acoustic Guitar (steel)', + 27: 'Electric Guitar (jazz)', + 28: 'Electric Guitar (clean)', + 29: 'Electric Guitar (muted)', + 30: 'Overdriven Guitar', + 31: 'Distortion Guitar', + 32: 'Guitar harmonics', + 33: 'Acoustic Bass', + 34: 'Electric Bass (finger)', + 35: 'Electric Bass (pick)', + 36: 'Fretless Bass', + 37: 'Slap Bass 1', + 38: 'Slap Bass 2', + 39: 'Synth Bass 1', + 40: 'Synth Bass 2', + 41: 'Violin', + 42: 'Viola', + 43: 'Cello', + 44: 'Contrabass', + 45: 'Tremolo Strings', + 46: 'Pizzicato Strings', + 47: 'Orchestral Harp', + 48: 'Timpani', + 49: 'String Ensemble 1', + 50: 'String Ensemble 2', + 51: 'SynthStrings 1', + 52: 'SynthStrings 2', + 53: 'Choir Aahs', + 54: 'Voice Oohs', + 55: 'Synth Voice', + 56: 'Orchestra Hit', + 57: 'Trumpet', + 58: 'Trombone', + 59: 'Tuba', + 60: 'Muted Trumpet', + 61: 'French Horn', + 62: 'Brass Section', + 63: 'SynthBrass 1', + 64: 'SynthBrass 2', + 65: 'Soprano Sax', + 66: 'Alto Sax', + 67: 'Tenor Sax', + 68: 'Baritone Sax', + 69: 'Oboe', + 70: 'English Horn', + 71: 'Bassoon', + 72: 'Clarinet', + 73: 'Piccolo', + 74: 'Flute', + 75: 'Recorder', + 76: 'Pan Flute', + 77: 'Blown Bottle', + 78: 'Shakuhachi', + 79: 'Whistle', + 80: 'Ocarina', + 81: 'Lead 1 (square)', + 82: 'Lead 2 (sawtooth)', + 83: 'Lead 3 (calliope)', + 84: 'Lead 4 (chiff)', + 85: 'Lead 5 (charang)', + 86: 'Lead 6 (voice)', + 87: 'Lead 7 (fifths)', + 88: 'Lead 8 (bass + lead)', + 89: 'Pad 1 (new age)', + 90: 'Pad 2 (warm)', + 91: 'Pad 3 (polysynth)', + 92: 'Pad 4 (choir)', + 93: 'Pad 5 (bowed)', + 94: 'Pad 6 (metallic)', + 95: 'Pad 7 (halo)', + 96: 'Pad 8 (sweep)', + 97: 'FX 1 (rain)', + 98: 'FX 2 (soundtrack)', + 99: 'FX 3 (crystal)', + 100: 'FX 4 (atmosphere)', + 101: 'FX 5 (brightness)', + 102: 'FX 6 (goblins)', + 103: 'FX 7 (echoes)', + 104: 'FX 8 (sci-fi)', + 105: 'Sitar', + 106: 'Banjo', + 107: 'Shamisen', + 108: 'Koto', + 109: 'Kalimba', + 110: 'Bag pipe', + 111: 'Fiddle', + 112: 'Shanai', + 113: 'Tinkle Bell', + 114: 'Agogo', + 115: 'Steel Drums', + 116: 'Woodblock', + 117: 'Taiko Drum', + 118: 'Melodic Tom', + 119: 'Synth Drum', + 120: 'Reverse Cymbal', + 121: 'Guitar Fret Noise', + 122: 'Breath Noise', + 123: 'Seashore', + 124: 'Bird Tweet', + 125: 'Telephone Ring', + 126: 'Helicopter', + 127: 'Applause', + 128: 'Gunshot', +} + +drum_kit = { + 1: 'GM Standard Kit', + 9: 'GS Room Kit', + 17: 'GS Power Kit', + 25: 'GS Power Kit', + 26: 'GS TR-808 Kit', + 33: 'GS Jazz Kit', + 41: 'GS Brush Kit', + 49: 'GS Orchestra Kit', + 57: 'GS Sound FX Kit', + 128: 'GS CM-64/CM-32 Kit', +} + +# Each quarter frame type has 2 string names, each shorter than the previous +quarter_frame_type = { + 0: ['frame count LS nibble', 'frame LSN'], + 1: ['frame count MS nibble', 'frame MSN'], + 2: ['seconds LS nibble', 'sec LSN'], + 3: ['seconds MS nibble', 'sec MSN'], + 4: ['minutes LS nibble', 'min LSN'], + 5: ['minutes MS nibble', 'min MSN'], + 6: ['hours LS nibble', 'hrs LSN'], + 7: ['hours MS nibble and SMPTE type', 'hrs MSN'], +} + +smpte_type = { + 0: '24 fps', + 1: '25 fps', + 2: '30 fps (drop-frame)', + 3: '30 fps (non-drop)', +} + +chromatic_notes = { + 0: 'C-1', + 1: 'C#-1', + 2: 'D-1', + 3: 'D#-1', + 4: 'E-1', + 5: 'F-1', + 6: 'F#-1', + 7: 'G-1', + 8: 'G#-1', + 9: 'A-1', + 10: 'A#-1', + 11: 'B-1', + 12: 'C0', + 13: 'C#0', + 14: 'D0', + 15: 'D#0', + 16: 'E0', + 17: 'F0', + 18: 'F#0', + 19: 'G0', + 20: 'G#0', + 21: 'A0', + 22: 'A#0', + 23: 'B0', + 24: 'C1', + 25: 'C#1', + 26: 'D1', + 27: 'D#1', + 28: 'E1', + 29: 'F1', + 30: 'F#1', + 31: 'G1', + 32: 'G#1', + 33: 'A1', + 34: 'A#1', + 35: 'B1', + 36: 'C2', + 37: 'C#2', + 38: 'D2', + 39: 'D#2', + 40: 'E2', + 41: 'F2', + 42: 'F#2', + 43: 'G2', + 44: 'G#2', + 45: 'A2', + 46: 'A#2', + 47: 'B2', + 48: 'C3', + 49: 'C#3', + 50: 'D3', + 51: 'D#3', + 52: 'E3', + 53: 'F3', + 54: 'F#3', + 55: 'G3', + 56: 'G#3', + 57: 'A3', + 58: 'A#3', + 59: 'B3', + 60: 'C4', + 61: 'C#4', + 62: 'D4', + 63: 'D#4', + 64: 'E4', + 65: 'F4', + 66: 'F#4', + 67: 'G4', + 68: 'G#4', + 69: 'A4', + 70: 'A#4', + 71: 'B4', + 72: 'C5', + 73: 'C#5', + 74: 'D5', + 75: 'D#5', + 76: 'E5', + 77: 'F5', + 78: 'F#5', + 79: 'G5', + 80: 'G#5', + 81: 'A5', + 82: 'A#5', + 83: 'B5', + 84: 'C6', + 85: 'C#6', + 86: 'D6', + 87: 'D#6', + 88: 'E6', + 89: 'F6', + 90: 'F#6', + 91: 'G6', + 92: 'G#6', + 93: 'A6', + 94: 'A#6', + 95: 'B6', + 96: 'C7', + 97: 'C#7', + 98: 'D7', + 99: 'D#7', + 100: 'E7', + 101: 'F7', + 102: 'F#7', + 103: 'G7', + 104: 'G#7', + 105: 'A7', + 106: 'A#7', + 107: 'B7', + 108: 'C8', + 109: 'C#8', + 110: 'D8', + 111: 'D#8', + 112: 'E8', + 113: 'F8', + 114: 'F#8', + 115: 'G8', + 116: 'G#8', + 117: 'A8', + 118: 'A#8', + 119: 'B8', + 120: 'C9', + 121: 'C#9', + 122: 'D9', + 123: 'D#9', + 124: 'E9', + 125: 'F9', + 126: 'F#9', + 127: 'G9', +} + +percussion_notes = { + 35: 'Acoustic Bass Drum', + 36: 'Bass Drum 1', + 37: 'Side Stick', + 38: 'Acoustic Snare', + 39: 'Hand Clap', + 40: 'Electric Snare', + 41: 'Low Floor Tom', + 42: 'Closed Hi Hat', + 43: 'High Floor Tom', + 44: 'Pedal Hi-Hat', + 45: 'Low Tom', + 46: 'Open Hi-Hat', + 47: 'Low-Mid Tom', + 48: 'Hi Mid Tom', + 49: 'Crash Cymbal 1', + 50: 'High Tom', + 51: 'Ride Cymbal 1', + 52: 'Chinese Cymbal', + 53: 'Ride Bell', + 54: 'Tambourine', + 55: 'Splash Cymbal', + 56: 'Cowbell', + 57: 'Crash Cymbal 2', + 58: 'Vibraslap', + 59: 'Ride Cymbal 2', + 60: 'Hi Bongo', + 61: 'Low Bongo', + 62: 'Mute Hi Conga', + 63: 'Open Hi Conga', + 64: 'Low Conga', + 65: 'High Timbale', + 66: 'Low Timbale', + 67: 'High Agogo', + 68: 'Low Agogo', + 69: 'Cabasa', + 70: 'Maracas', + 71: 'Short Whistle', + 72: 'Long Whistle', + 73: 'Short Guiro', + 74: 'Long Guiro', + 75: 'Claves', + 76: 'Hi Wood Block', + 77: 'Low Wood Block', + 78: 'Mute Cuica', + 79: 'Open Cuica', + 80: 'Mute Triangle', + 81: 'Open Triangle', +} diff --git a/libsigrokdecode4DSL/decoders/midi/pd.py b/libsigrokdecode4DSL/decoders/midi/pd.py new file mode 100644 index 00000000..ae35e123 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/midi/pd.py @@ -0,0 +1,627 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2013-2016 Uwe Hermann +## Copyright (C) 2016 Chris Dreher +## +## 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, see . +## + +import sigrokdecode as srd +from .lists import * + +RX = 0 +TX = 1 + +class Decoder(srd.Decoder): + api_version = 3 + id = 'midi' + name = 'MIDI' + longname = 'Musical Instrument Digital Interface' + desc = 'Musical Instrument Digital Interface (MIDI) protocol.' + license = 'gplv2+' + inputs = ['uart'] + outputs = [] + tags = ['Audio', 'PC'] + annotations = ( + ('text-verbose', 'Human-readable text (verbose)'), + ('text-sysreal-verbose', 'Human-readable SysReal text (verbose)'), + ('text-error', 'Human-readable Error text'), + ) + annotation_rows = ( + ('normal', 'Normal', (0, 2)), + ('sys-real', 'SysReal', (1,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.state = 'IDLE' + self.status_byte = 0 + self.explicit_status_byte = False + self.cmd = [] + self.ss = None + self.es = None + self.ss_block = None + self.es_block = None + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + self.put(self.ss_block, self.es_block, self.out_ann, data) + + def get_note_name(self, channel, note): + if channel != 10: + return chromatic_notes[note] + else: + return 'assuming ' + percussion_notes.get(note, 'undefined') + + def check_for_garbage_flush(self, is_flushed): + if is_flushed: + if self.explicit_status_byte: + self.cmd.insert(0, self.status_byte) + self.handle_garbage_msg(None) + + def soft_clear_status_byte(self): + self.explicit_status_byte = False + + def hard_clear_status_byte(self): + self.status_byte = 0 + self.explicit_status_byte = False + + def set_status_byte(self, newbyte): + self.status_byte = newbyte + self.explicit_status_byte = True + + def handle_channel_msg_0x80(self, is_flushed): + # Note off: 8n kk vv + # n = channel, kk = note, vv = velocity + c = self.cmd + if len(c) < 2: + self.check_for_garbage_flush(is_flushed) + return + self.es_block = self.es + msg, chan = self.status_byte & 0xf0, (self.status_byte & 0x0f) + 1 + note, velocity = c[0], c[1] + note_name = self.get_note_name(chan, note) + self.putx([0, ['Channel %d: %s (note = %d \'%s\', velocity = %d)' % \ + (chan, status_bytes[msg][0], note, note_name, velocity), + 'ch %d: %s %d, velocity = %d' % \ + (chan, status_bytes[msg][1], note, velocity), + '%d: %s %d, vel %d' % \ + (chan, status_bytes[msg][2], note, velocity)]]) + self.cmd, self.state = [], 'IDLE' + self.soft_clear_status_byte() + + def handle_channel_msg_0x90(self, is_flushed): + # Note on: 9n kk vv + # n = channel, kk = note, vv = velocity + # If velocity == 0 that actually means 'note off', though. + c = self.cmd + if len(c) < 2: + self.check_for_garbage_flush(is_flushed) + return + self.es_block = self.es + msg, chan = self.status_byte & 0xf0, (self.status_byte & 0x0f) + 1 + note, velocity = c[0], c[1] + s = status_bytes[0x80] if (velocity == 0) else status_bytes[msg] + note_name = self.get_note_name(chan, note) + self.putx([0, ['Channel %d: %s (note = %d \'%s\', velocity = %d)' % \ + (chan, s[0], note, note_name, velocity), + 'ch %d: %s %d, velocity = %d' % \ + (chan, s[1], note, velocity), + '%d: %s %d, vel %d' % \ + (chan, s[2], note, velocity)]]) + self.cmd, self.state = [], 'IDLE' + self.soft_clear_status_byte() + + def handle_channel_msg_0xa0(self, is_flushed): + # Polyphonic key pressure / aftertouch: An kk vv + # n = channel, kk = polyphonic key pressure, vv = pressure value + c = self.cmd + if len(c) < 2: + self.check_for_garbage_flush(is_flushed) + return + self.es_block = self.es + msg, chan = self.status_byte & 0xf0, (self.status_byte & 0x0f) + 1 + note, pressure = c[0], c[1] + note_name = self.get_note_name(chan, note) + self.putx([0, ['Channel %d: %s of %d for note = %d \'%s\'' % \ + (chan, status_bytes[msg][0], pressure, note, note_name), + 'ch %d: %s %d for note %d' % \ + (chan, status_bytes[msg][1], pressure, note), + '%d: %s %d, N %d' % \ + (chan, status_bytes[msg][2], pressure, note)]]) + self.cmd, self.state = [], 'IDLE' + self.soft_clear_status_byte() + + def handle_controller_0x44(self): + # Legato footswitch: Bn 44 vv + # n = channel, vv = value (<= 0x3f: normal, > 0x3f: legato) + c = self.cmd + msg, chan = self.status_byte & 0xf0, (self.status_byte & 0x0f) + 1 + vv = c[1] + t = ('normal', 'no') if vv <= 0x3f else ('legato', 'yes') + self.putx([0, ['Channel %d: %s \'%s\' = %s' % \ + (chan, status_bytes[msg][0], + control_functions[0x44][0], t[0]), + 'ch %d: %s \'%s\' = %s' % \ + (chan, status_bytes[msg][1], + control_functions[0x44][1], t[0]), + '%d: %s \'%s\' = %s' % \ + (chan, status_bytes[msg][2], + control_functions[0x44][2], t[1])]]) + + def handle_controller_0x54(self): + # Portamento control (PTC): Bn 54 kk + # n = channel, kk = source note for pitch reference + c = self.cmd + msg, chan = self.status_byte & 0xf0, (self.status_byte & 0x0f) + 1 + kk = c[1] + kk_name = self.get_note_name(chan, kk) + self.putx([0, ['Channel %d: %s \'%s\' (source note = %d / %s)' % \ + (chan, status_bytes[msg][0], + control_functions[0x54][0], kk, kk_name), + 'ch %d: %s \'%s\' (source note = %d)' % \ + (chan, status_bytes[msg][1], + control_functions[0x54][1], kk), + '%d: %s \'%s\' (src N %d)' % \ + (chan, status_bytes[msg][2], + control_functions[0x54][2], kk)]]) + + def handle_controller_generic(self): + c = self.cmd + msg, chan = self.status_byte & 0xf0, (self.status_byte & 0x0f) + 1 + fn, param = c[0], c[1] + default_name = 'undefined' + ctrl_fn = control_functions.get(fn, default_name) + if ctrl_fn == default_name: + ctrl_fn = ('undefined 0x%02x' % fn, 'undef 0x%02x' % fn, '0x%02x' % fn) + self.putx([0, ['Channel %d: %s \'%s\' (param = 0x%02x)' % \ + (chan, status_bytes[msg][0], ctrl_fn[0], param), + 'ch %d: %s \'%s\' (param = 0x%02x)' % \ + (chan, status_bytes[msg][1], ctrl_fn[1], param), + '%d: %s \'%s\' is 0x%02x' % \ + (chan, status_bytes[msg][2], ctrl_fn[2], param)]]) + + def handle_channel_mode(self): + # Channel Mode: Bn mm vv + # n = channel, mm = mode number (120 - 127), vv = value + c = self.cmd + msg, chan = self.status_byte & 0xf0, (self.status_byte & 0x0f) + 1 + mm, vv = c[0], c[1] + mode_fn = control_functions.get(mm, ('undefined', 'undef', 'undef')) + # Decode the value based on the mode number. + vv_string = ('', '') + if mm == 122: # mode = local control? + if vv == 0: + vv_string = ('off', 'off') + elif vv == 127: # mode = poly mode on? + vv_string = ('on', 'on') + else: + vv_string = ('(non-standard param value of 0x%02x)' % vv, + '0x%02x' % vv) + elif mm == 126: # mode = mono mode on? + if vv != 0: + vv_string = ('(%d channels)' % vv, '(%d ch)' % vv) + else: + vv_string = ('(channels \'basic\' through 16)', + '(ch \'basic\' thru 16)') + elif vv != 0: # All other channel mode messages expect vv == 0. + vv_string = ('(non-standard param value of 0x%02x)' % vv, + '0x%02x' % vv) + self.putx([0, ['Channel %d: %s \'%s\' %s' % \ + (chan, status_bytes[msg][0], mode_fn[0], vv_string[0]), + 'ch %d: %s \'%s\' %s' % \ + (chan, status_bytes[msg][1], mode_fn[1], vv_string[1]), + '%d: %s \'%s\' %s' % \ + (chan, status_bytes[msg][2], mode_fn[2], vv_string[1])]]) + self.cmd, self.state = [], 'IDLE' + self.soft_clear_status_byte() + + def handle_channel_msg_0xb0(self, is_flushed): + # Control change (or channel mode messages): Bn cc vv + # n = channel, cc = control number (0 - 119), vv = control value + c = self.cmd + if len(c) < 2: + self.check_for_garbage_flush(is_flushed) + return + self.es_block = self.es + if c[0] in range(0x78, 0x7f + 1): + self.handle_channel_mode() + return + handle_ctrl = getattr(self, 'handle_controller_0x%02x' % c[0], + self.handle_controller_generic) + handle_ctrl() + self.cmd, self.state = [], 'IDLE' + self.soft_clear_status_byte() + + def handle_channel_msg_0xc0(self, is_flushed): + # Program change: Cn pp + # n = channel, pp = program number (0 - 127) + c = self.cmd + if len(c) < 1: + self.check_for_garbage_flush(is_flushed) + return + self.es_block = self.es + msg, chan = self.status_byte & 0xf0, (self.status_byte & 0x0f) + 1 + pp = self.cmd[0] + 1 + change_type = 'instrument' + name = '' + if chan != 10: # channel != percussion + name = gm_instruments.get(pp, 'undefined') + else: + change_type = 'drum kit' + name = drum_kit.get(pp, 'undefined') + self.putx([0, ['Channel %d: %s to %s %d (assuming %s)' % \ + (chan, status_bytes[msg][0], change_type, pp, name), + 'ch %d: %s to %s %d' % \ + (chan, status_bytes[msg][1], change_type, pp), + '%d: %s %d' % \ + (chan, status_bytes[msg][2], pp)]]) + self.cmd, self.state = [], 'IDLE' + self.soft_clear_status_byte() + + def handle_channel_msg_0xd0(self, is_flushed): + # Channel pressure / aftertouch: Dn vv + # n = channel, vv = pressure value + c = self.cmd + if len(c) < 1: + self.check_for_garbage_flush(is_flushed) + return + self.es_block = self.es + msg, chan = self.status_byte & 0xf0, (self.status_byte & 0x0f) + 1 + vv = self.cmd[0] + self.putx([0, ['Channel %d: %s %d' % (chan, status_bytes[msg][0], vv), + 'ch %d: %s %d' % (chan, status_bytes[msg][1], vv), + '%d: %s %d' % (chan, status_bytes[msg][2], vv)]]) + self.cmd, self.state = [], 'IDLE' + self.soft_clear_status_byte() + + def handle_channel_msg_0xe0(self, is_flushed): + # Pitch bend change: En ll mm + # n = channel, ll = pitch bend change LSB, mm = pitch bend change MSB + c = self.cmd + if len(c) < 2: + self.check_for_garbage_flush(is_flushed) + return + self.es_block = self.es + msg, chan = self.status_byte & 0xf0, (self.status_byte & 0x0f) + 1 + ll, mm = self.cmd[0], self.cmd[1] + decimal = (mm << 7) + ll + self.putx([0, ['Channel %d: %s 0x%02x 0x%02x (%d)' % \ + (chan, status_bytes[msg][0], ll, mm, decimal), + 'ch %d: %s 0x%02x 0x%02x (%d)' % \ + (chan, status_bytes[msg][1], ll, mm, decimal), + '%d: %s (%d)' % \ + (chan, status_bytes[msg][2], decimal)]]) + self.cmd, self.state = [], 'IDLE' + self.soft_clear_status_byte() + + def handle_channel_msg_generic(self, is_flushed): + # TODO: It should not be possible to hit this code. + # It currently can not be unit tested. + msg_type = self.status_byte & 0xf0 + self.es_block = self.es + self.putx([2, ['Unknown channel message type: 0x%02x' % msg_type]]) + self.cmd, self.state = [], 'IDLE' + self.soft_clear_status_byte() + + def handle_channel_msg(self, newbyte): + if newbyte is not None: + if newbyte >= 0x80: + self.set_status_byte(newbyte) + else: + self.cmd.append(newbyte) + msg_type = self.status_byte & 0xf0 + handle_msg = getattr(self, 'handle_channel_msg_0x%02x' % msg_type, + self.handle_channel_msg_generic) + handle_msg(newbyte is None) + + def handle_sysex_msg(self, newbyte): + # SysEx message: 1 status byte, 1-3 manuf. bytes, x data bytes, EOX byte + # + # SysEx messages are variable length, can be terminated by EOX or + # by any non-SysReal status byte, and it clears self.status_byte. + # + # Note: All System message codes don't utilize self.status_byte. + self.hard_clear_status_byte() + if newbyte != 0xf7 and newbyte is not None: # EOX + self.cmd.append(newbyte) + return + self.es_block = self.es + # Note: Unlike other methods, this code pops bytes out of self.cmd + # to isolate the data. + msg = self.cmd.pop(0) + if len(self.cmd) < 1: + self.putx([2, ['%s: truncated manufacturer code (<1 bytes)' % \ + status_bytes[msg][0], + '%s: truncated manufacturer (<1 bytes)' % \ + status_bytes[msg][1], + '%s: trunc. manu.' % status_bytes[msg][2]]]) + self.cmd, self.state = [], 'IDLE' + return + # Extract the manufacturer name (or SysEx realtime or non-realtime). + m1 = self.cmd.pop(0) + manu = (m1,) + if m1 == 0x00: # If byte == 0, then 2 more manufacturer bytes follow. + if len(self.cmd) < 2: + self.putx([2, ['%s: truncated manufacturer code (<3 bytes)' % \ + status_bytes[msg][0], + '%s: truncated manufacturer (<3 bytes)' % \ + status_bytes[msg][1], + '%s: trunc. manu.' % status_bytes[msg][2]]]) + self.cmd, self.state = [], 'IDLE' + return + manu = (m1, self.cmd.pop(0), self.cmd.pop(0)) + default_name = 'undefined' + manu_name = sysex_manufacturer_ids.get(manu, default_name) + if manu_name == default_name: + if len(manu) == 3: + manu_name = ('%s (0x%02x 0x%02x 0x%02x)' % \ + (default_name, manu[0], manu[1], manu[2]), + default_name) + else: + manu_name = ('%s (0x%02x)' % (default_name, manu[0]), + default_name) + else: + manu_name = (manu_name, manu_name) + # Extract the payload, display in 1 of 2 formats + # TODO: Write methods to decode SysEx realtime & non-realtime payloads. + payload0 = '' + payload1 = '' + while len(self.cmd) > 0: + byte = self.cmd.pop(0) + payload0 += '0x%02x ' % (byte) + payload1 += '%02x ' % (byte) + if payload0 == '': + payload0 = '' + payload1 = '<>' + payload = (payload0, payload1) + self.putx([0, ['%s: for \'%s\' with payload %s' % \ + (status_bytes[msg][0], manu_name[0], payload[0]), + '%s: \'%s\', payload %s' % \ + (status_bytes[msg][1], manu_name[1], payload[1]), + '%s: \'%s\', payload %s' % \ + (status_bytes[msg][2], manu_name[1], payload[1])]]) + self.cmd, self.state = [], 'IDLE' + + def handle_syscommon_midi_time_code_quarter_frame_msg(self, newbyte): + # MIDI time code quarter frame: F1 nd + # n = message type + # d = values + # + # Note: All System message codes don't utilize self.status_byte, + # and System Exclusive and System Common clear it. + c = self.cmd + if len(c) < 2: + if newbyte is None: + self.handle_garbage_msg(None) + return + msg = c[0] + nn, dd = (c[1] & 0x70) >> 4, c[1] & 0x0f + group = ('System Common', 'SysCom', 'SC') + self.es_block = self.es + if nn != 7: # If message type does not contain SMPTE type. + self.putx([0, ['%s: %s of %s, value 0x%01x' % \ + (group[0], status_bytes[msg][0], + quarter_frame_type[nn][0], dd), + '%s: %s of %s, value 0x%01x' % \ + (group[1], status_bytes[msg][1], + quarter_frame_type[nn][1], dd), + '%s: %s of %s, value 0x%01x' % \ + (group[2], status_bytes[msg][2], + quarter_frame_type[nn][1], dd)]]) + self.cmd, self.state = [], 'IDLE' + return + tt = (dd & 0x6) >> 1 + self.putx([0, ['%s: %s of %s, value 0x%01x for %s' % \ + (group[0], status_bytes[msg][0], \ + quarter_frame_type[nn][0], dd, smpte_type[tt]), + '%s: %s of %s, value 0x%01x for %s' % \ + (group[1], status_bytes[msg][1], \ + quarter_frame_type[nn][1], dd, smpte_type[tt]), + '%s: %s of %s, value 0x%01x for %s' % \ + (group[2], status_bytes[msg][2], \ + quarter_frame_type[nn][1], dd, smpte_type[tt])]]) + self.cmd, self.state = [], 'IDLE' + + def handle_syscommon_msg(self, newbyte): + # System common messages + # + # There are 5 simple formats (which are directly handled here) and + # 1 complex one called MIDI time code quarter frame. + # + # Note: While the MIDI lists 0xf7 as a "system common" message, it + # is actually only used with SysEx messages so it is processed there. + # + # Note: All System message codes don't utilize self.status_byte. + self.hard_clear_status_byte() + if newbyte is not None: + self.cmd.append(newbyte) + c = self.cmd + msg = c[0] + group = ('System Common', 'SysCom', 'SC') + if msg == 0xf1: + # MIDI time code quarter frame + self.handle_syscommon_midi_time_code_quarter_frame_msg(newbyte) + return + elif msg == 0xf2: + # Song position pointer: F2 ll mm + # ll = LSB position, mm = MSB position + if len(c) < 3: + if newbyte is None: + self.handle_garbage_msg(None) + return + ll, mm = c[1], c[2] + decimal = (mm << 7) + ll + self.es_block = self.es + self.putx([0, ['%s: %s 0x%02x 0x%02x (%d)' % \ + (group[0], status_bytes[msg][0], ll, mm, decimal), + '%s: %s 0x%02x 0x%02x (%d)' % \ + (group[1], status_bytes[msg][1], ll, mm, decimal), + '%s: %s (%d)' % \ + (group[2], status_bytes[msg][2], decimal)]]) + elif msg == 0xf3: + # Song select: F3 ss + # ss = song selection number + if len(c) < 2: + if newbyte is None: + self.handle_garbage_msg(None) + return + ss = c[1] + self.es_block = self.es + self.putx([0, ['%s: %s number %d' % \ + (group[0], status_bytes[msg][0], ss), + '%s: %s number %d' % \ + (group[1], status_bytes[msg][1], ss), + '%s: %s # %d' % \ + (group[2], status_bytes[msg][2], ss)]]) + elif msg == 0xf4 or msg == 0xf5 or msg == 0xf6: + # Undefined 0xf4, Undefined 0xf5, and Tune Request (respectively). + # All are only 1 byte long with no data bytes. + self.es_block = self.es + self.putx([0, ['%s: %s' % (group[0], status_bytes[msg][0]), + '%s: %s' % (group[1], status_bytes[msg][1]), + '%s: %s' % (group[2], status_bytes[msg][2])]]) + self.cmd, self.state = [], 'IDLE' + + def handle_sysrealtime_msg(self, newbyte): + # System realtime message: 0b11111ttt (t = message type) + # + # Important: These messages are handled differently from all others + # because they are allowed to temporarily interrupt other messages. + # The interrupted messages resume after the realtime message is done. + # Thus, they mostly leave 'self' the way it was found. + # + # Note: All System message codes don't utilize self.status_byte. + old_ss_block, old_es_block = self.ss_block, self.es_block + self.ss_block, self.es_block = self.ss, self.es + group = ('System Realtime', 'SysReal', 'SR') + self.putx([1, ['%s: %s' % (group[0], status_bytes[newbyte][0]), + '%s: %s' % (group[1], status_bytes[newbyte][1]), + '%s: %s' % (group[2], status_bytes[newbyte][2])]]) + self.ss_block, self.es_block = old_ss_block, old_es_block + # Deliberately not resetting self.cmd or self.state. + + def handle_garbage_msg(self, newbyte): + # Handle messages that are either not handled or are corrupt. + self.es_block = self.es + if newbyte is not None: + self.cmd.append(newbyte) + return + payload = '' + max_bytes = 16 # Put a limit on the length on the hex dump. + for index in range(len(self.cmd)): + if index == max_bytes: + payload += ' ...' + break + if index == 0: + payload = '0x%02x' % self.cmd[index] + else: + payload += ' 0x%02x' % self.cmd[index] + self.putx([2, ['UNHANDLED DATA: %s' % payload, + 'UNHANDLED', '???', '?']]) + self.cmd, self.state = [], 'IDLE' + self.hard_clear_status_byte() + + def handle_state(self, state, newbyte): + # 'newbyte' can either be: + # 1. Value between 0x00-0xff, deal with the byte normally. + # 2. Value of 'None' which means "flush any buffered data". + if state == 'HANDLE CHANNEL MSG': + self.handle_channel_msg(newbyte) + elif state == 'HANDLE SYSEX MSG': + self.handle_sysex_msg(newbyte) + elif state == 'HANDLE SYSCOMMON MSG': + self.handle_syscommon_msg(newbyte) + elif state == 'HANDLE SYSREALTIME MSG': + self.handle_sysrealtime_msg(newbyte) + elif state == 'BUFFER GARBAGE MSG': + self.handle_garbage_msg(newbyte) + + def get_next_state(self, newbyte): + # 'newbyte' must be a valid byte between 0x00 and 0xff. + # + # Try to determine the state based off of the 'newbyte' parameter. + if newbyte in range(0x80, 0xef + 1): + return 'HANDLE CHANNEL MSG' + if newbyte == 0xf0: + return 'HANDLE SYSEX MSG' + if newbyte in range(0xf1, 0xf7): + return'HANDLE SYSCOMMON MSG' + if newbyte in range(0xf8, 0xff + 1): + return 'HANDLE SYSREALTIME MSG' + # Passing 0xf7 is an error; messages don't start with 0xf7. + if newbyte == 0xf7: + return 'BUFFER GARBAGE MSG' + # Next, base the state off of self.status_byte. + if self.status_byte < 0x80: + return 'BUFFER GARBAGE MSG' + return self.get_next_state(self.status_byte) + + def decode(self, ss, es, data): + ptype, rxtx, pdata = data + state = 'IDLE' + + # For now, ignore all UART packets except the actual data packets. + if ptype != 'DATA': + return + + # We're only interested in the byte value (not individual bits). + pdata = pdata[0] + + # Short MIDI overview: + # - Status bytes are 0x80-0xff, data bytes are 0x00-0x7f. + # - Most messages: 1 status byte, 1-2 data bytes. + # - Real-time system messages: always 1 byte. + # - SysEx messages: 1 status byte, n data bytes, EOX byte. + # + # Aspects of the MIDI protocol that complicate decoding: + # - MIDI System Realtime messages can briefly interrupt other + # messages already in progress. + # - "Running Status" allows for omitting the status byte in most + # scenarios if sequential messages have the same status byte. + # - System Exclusive (SysEx) messages can be terminated by ANY + # status byte (not limited to EOX byte). + + # State machine. + if pdata >= 0x80 and pdata != 0xf7: + state = self.get_next_state(pdata) + if state != 'HANDLE SYSREALTIME MSG' and self.state != 'IDLE': + # Flush the previous data since a new message is starting. + self.handle_state(self.state, None) + # Cache ss and es -after- flushing previous data. + self.ss, self.es = ss, es + # This is a status byte, remember the start sample. + if state != 'HANDLE SYSREALTIME MSG': + self.ss_block = ss + elif self.state == 'IDLE' or self.state == 'BUFFER GARBAGE MSG': + # Deal with "running status" or that we're buffering garbage. + self.ss, self.es = ss, es + if self.state == 'IDLE': + self.ss_block = ss + state = self.get_next_state(pdata) + else: + self.ss, self.es = ss, es + state = self.state + + # Yes, this is intentionally _not_ an 'elif' here. + if state != 'HANDLE SYSREALTIME MSG': + self.state = state + if state == 'BUFFER GARBAGE MSG': + self.status_byte = 0 + self.handle_state(state, pdata) diff --git a/libsigrokdecode4DSL/decoders/miller/__init__.py b/libsigrokdecode4DSL/decoders/miller/__init__.py new file mode 100644 index 00000000..ce0d4941 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/miller/__init__.py @@ -0,0 +1,26 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2017 Christoph Rackwitz +## +## 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, see . +## + +''' +The Miller protocol decoder supports (modified) Miller encoded data. + +E.g. used in NFC communication at 106 kbaud. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/miller/pd.py b/libsigrokdecode4DSL/decoders/miller/pd.py new file mode 100644 index 00000000..f41711f1 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/miller/pd.py @@ -0,0 +1,190 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2017 Christoph Rackwitz +## +## 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, see . +## + +# http://www.gorferay.com/type-a-communications-interface/ +# https://resources.infosecinstitute.com/introduction-rfid-security/ +# https://www.radio-electronics.com/info/wireless/nfc/near-field-communications-modulation-rf-signal-interface.php +# https://www.researchgate.net/figure/Modified-Miller-Code_fig16_283498836 + +# Miller: either edge +# modified Miller: falling edge + +import sigrokdecode as srd + +def roundto(x, k=1.0): + return round(x / k) * k + +class Decoder(srd.Decoder): + api_version = 3 + id = 'miller' + name = 'Miller' + longname = 'Miller encoding' + desc = 'Miller encoding protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Encoding'] + channels = ( + {'id': 'data', 'name': 'Data', 'desc': 'Data signal'}, + ) + options = ( + {'id': 'baudrate', 'desc': 'Baud rate', 'default': 106000}, + {'id': 'edge', 'desc': 'Edge', 'default': 'falling', 'values': ('rising', 'falling', 'either')}, + ) + annotations = ( + ('bit', 'Bit'), + ('bitstring', 'Bitstring'), + ) + annotation_rows = tuple((u, v, (i,)) for i, (u, v) in enumerate(annotations)) + binary = ( + ('raw', 'Raw binary'), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_binary = self.register(srd.OUTPUT_BINARY) + + def decode_bits(self): + timeunit = self.samplerate / self.options['baudrate'] + edgetype = self.options['edge'][0] + + self.wait({0: edgetype}) # first symbol, beginning of unit + prevedge = self.samplenum + + # start of message: '0' + prevbit = 0 + yield (0, prevedge, prevedge + timeunit) + expectedstart = self.samplenum + timeunit + + # end of message: '0' followed by one idle symbol + + while True: + self.wait([{0: edgetype}, {'skip': int(3 * timeunit)}]) + got_timeout = (self.matched & (0b1 << 1)) + sampledelta = (self.samplenum - prevedge) + prevedge = self.samplenum + timedelta = roundto(sampledelta / timeunit, 0.5) + + # a mark stands for a 1 bit + # a mark has an edge in the middle + + # a space stands for a 0 bit + # a space either has an edge at the beginning or no edge at all + # after a mark, a space is edge-less + # after a space, a space has an edge + + # we get 1.0, 1.5, 2.0 times between edges + + # end of transmission is always a space, either edged or edge-less + + if prevbit == 0: # space -> ??? + if timedelta == 1.0: # 1.0 units -> space + yield (0, self.samplenum, self.samplenum + timeunit) + prevbit = 0 + expectedstart = self.samplenum + timeunit + elif timedelta == 1.5: # 1.5 units -> mark + yield (1, expectedstart, self.samplenum + 0.5*timeunit) + prevbit = 1 + expectedstart = self.samplenum + timeunit*0.5 + elif timedelta >= 2.0: + # idle symbol (end of message) + yield None + else: + # assert timedelta >= 2.0 + yield (False, self.samplenum - sampledelta, self.samplenum) + break + else: # mark -> ??? + if timedelta <= 0.5: + yield (False, self.samplenum - sampledelta, self.samplenum) + break + if timedelta == 1.0: # 1.0 units -> mark again (1.5 from start) + yield (1, expectedstart, self.samplenum + 0.5*timeunit) + prevbit = 1 + expectedstart = self.samplenum + 0.5*timeunit + elif timedelta == 1.5: # 1.5 units -> space (no pulse) and space (pulse) + yield (0, expectedstart, self.samplenum) + yield (0, self.samplenum, self.samplenum + timeunit) + prevbit = 0 + expectedstart = self.samplenum + timeunit + elif timedelta == 2.0: # 2.0 units -> space (no pulse) and mark (pulse) + yield (0, expectedstart, expectedstart + timeunit) + yield (1, self.samplenum - 0.5*timeunit, self.samplenum + 0.5*timeunit) + prevbit = 1 + expectedstart = self.samplenum + timeunit*0.5 + else: # longer -> space and end of message + yield (0, expectedstart, expectedstart + timeunit) + yield None + break + + def decode_run(self): + numbits = 0 + bitvalue = 0 + bitstring = '' + stringstart = None + stringend = None + + for bit in self.decode_bits(): + if bit is None: + break + + (value, ss, es) = bit + + if value is False: + self.put(int(ss), int(es), self.out_ann, [1, ['ERROR']]) + else: + self.put(int(ss), int(es), self.out_ann, [0, ['{}'.format(value)]]) + + if value is False: + numbits = 0 + break + + if stringstart is None: + stringstart = ss + + stringend = es + + bitvalue |= value << numbits + numbits += 1 + + bitstring += '{}'.format(value) + if numbits % 4 == 0: + bitstring += ' ' + + if not numbits: + return + + self.put(int(stringstart), int(stringend), self.out_ann, [1, ['{}'.format(bitstring)]]) + + numbytes = numbits // 8 + (numbits % 8 > 0) + bytestring = bitvalue.to_bytes(numbytes, 'little') + self.put(int(stringstart), int(stringend), self.out_binary, [0, bytestring]) + + def decode(self): + while True: + self.decode_run() diff --git a/libsigrokdecode4DSL/decoders/mipi_dsi/__init__.py b/libsigrokdecode4DSL/decoders/mipi_dsi/__init__.py new file mode 100644 index 00000000..5935127a --- /dev/null +++ b/libsigrokdecode4DSL/decoders/mipi_dsi/__init__.py @@ -0,0 +1,24 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +''' + +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/mipi_dsi/pd.py b/libsigrokdecode4DSL/decoders/mipi_dsi/pd.py new file mode 100644 index 00000000..a7e1f71d --- /dev/null +++ b/libsigrokdecode4DSL/decoders/mipi_dsi/pd.py @@ -0,0 +1,218 @@ +## +## This file is part of the libsigrokdecode project. +## Author: Shiqiu Nie (369614718@qq.com) +## Version: 0.2 +## Date: 2019-07-01 +## History: +## 1. 2019-07-01 Create decoder +## 2. 2017-01-17 V0.1,Decode EscMode,BTA,Data,Stop,Idle +## 3. 2019-07-01 V0.2,Support for V3 decoder +## +## Copyright (C) 2010-2016 Uwe Hermann +## Copyright (C) 2019 DreamSourceLab +## +## 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, see . +## + +# TODO: + +import sigrokdecode as srd + +''' +OUTPUT_PYTHON format: + +Packet: +[, ] + +: + + + is the data or address byte associated with the 'ADDRESS*' and 'DATA*' +command. +''' + +# CMD: [annotation-type-index, long annotation, short annotation] +proto = { + 'ESC Mode': [0, 'Escape mode entry', 'ESC'], + 'BTA': [1, 'Bi-directional Data Lane Turnaround','BTA'], + 'DATA': [2, 'Data', 'Data'], + 'STOP': [3, 'Stop', 'S'], + 'LPDT': [4, 'LPDT Command', 'LPDT'], + 'DI': [5, 'Data Identifier', 'DI'], + 'ECC': [6, 'Error Correction Code', 'ECC'], + 'WC': [7, 'Word count', 'WC'], + 'CRC': [8, 'CheckSUM', 'CRC'], + 'ULPS': [9, 'Ultra-Low Power State', 'ULPS'], + 'IDLE': [10,'Idle', 'Idle'], +} +# LP state +lp_state = ['LP-00','LP-01','LP-10','LP-11'] + +class Decoder(srd.Decoder): + api_version = 3 + id = 'MIPI_DSI' + name = 'MIPI_DSI' + longname = 'MIPI Display Serial Interface' + desc = 'MIPI Display Serial Interface low power communication' + license = 'gplv2+' + inputs = ['logic'] + outputs = ['mipi_dsi'] + tags = ['Embedded/industrial'] + channels = ( + {'id': 'D0N', 'type': 8, 'name': 'D0N', 'desc': 'LP data 0 neg'}, + {'id': 'D0P', 'type': 108, 'name': 'D0P', 'desc': 'LP data 0 pos'}, + ) + options = ( + + ) + annotations = ( + ('111', 'LP-00', 'LP-00'), + ('110', 'LP-01', 'LP-01'), + ('109', 'LP-10', 'LP-10'), + ('108', 'LP-11', 'LP-11'), + ('7', 'EscapeMode', 'Escape mode'), + ('6', 'BTA', 'Bi-directional Data Lane Turnaround'), + ('112', 'LPDT', 'LPDT'), + ('0', 'DI', 'Data identifier'), + ('12', 'ECC', 'ECC'), + ('11', 'WC', 'Word count'), + ('107', 'CRC', 'CheckSUM'), + ('5', 'Stop', 'Stop condition'), + ('1', 'Idle', 'Idle'), + ) + annotation_rows = ( + ('LPData', 'LPData', (0, 1, 2, 3,)), + ('LP', 'LP', (4, 5, 6, 7, 8, 9, 10)), + ) + binary = ( + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.ss = self.es = self.ss_byte = -1 + self.bitcount = 0 + self.databyte = 0 + self.is_esc_bta = 0 # 0=ESC Mode 1=BTA Mode + self.state = 'FIND START' + self.pdu_start = None + self.pdu_bits = 0 + self.bits = [] + self.findmode_state = 'Find Mode state0' + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def start(self): + self.out_python = self.register(srd.OUTPUT_PYTHON) + self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_binary = self.register(srd.OUTPUT_BINARY) + self.out_bitrate = self.register(srd.OUTPUT_META, + meta=(int, 'Bitrate', 'Bitrate from Start bit to Stop bit')) + + def putx(self, data): + self.put(self.ss, self.es, self.out_ann, data) + + def putp(self, data): + self.put(self.ss, self.es, self.out_python, data) + + def putb(self, data): + self.put(self.ss, self.es, self.out_binary, data) + + def handle_start(self): + self.ss, self.es = self.samplenum, self.samplenum + self.pdu_start = self.samplenum + self.pdu_bits = 0 + self.state = 'FIND MODE' + self.bitcount = self.databyte = 0 + self.findmode_state = 'Find Mode state0' + self.bits = [] + + def handle_esc_bta(self, d0n, d0p): + self.es = self.samplenum + cmd = 'ESC Mode' if(d0n == 1) else 'BTA' + self.putp([cmd, None]) + self.putx([proto[cmd][0], proto[cmd][1:]]) + self.bitcount = self.databyte = 0 + self.bits = [] + self.state = 'FIND DATA' + self.ss = self.samplenum + + def handle_stop(self): + cmd = 'STOP' + self.es = self.samplenum + self.putp([cmd, None]) + self.putx([proto[cmd][0], proto[cmd][1:]]) + self.state = 'FIND START' + self.is_esc_bta = 0 + self.bits = [] + + def handle_data(self, d0n, d0p): + self.pdu_bits += 1 + + self.databyte >>= 1 + if d0p: + self.databyte |= 0x80 + + if self.bitcount == 0: + self.ss_byte = self.samplenum + + if self.bitcount < 7: + self.bitcount += 1 + return + + d = self.databyte + + self.es = self.samplenum + h = '0x%02X' % d + cmd = 'DATA' + self.putb([cmd, None]) + self.putx([proto[cmd][0], [h]]) + + self.bitcount = self.databyte = 0 + self.bits = [] + self.state = 'FIND DATA' + self.ss = self.samplenum + + def decode(self): + while True: + # State machine. + if self.state == 'FIND START': + # Wait for a START condition (S): D0P = high, D0N = falling. + self.wait({0: 'f', 1: 'h'}) + self.handle_start() + elif self.state == 'FIND MODE': + if self.findmode_state == 'Find Mode state0': + self.wait({0: 'l', 1: 'l'}) + self.findmode_state = 'Find Mode state1' + elif self.findmode_state == 'Find Mode state1': + (d0n, d0p) = self.wait([{0: 'h', 1: 'l'}, {0: 'l', 1: 'h'}]) + self.findmode_state = 'Find Mode state2' + elif self.findmode_state == 'Find Mode state2': + self.wait({0: 'l', 1: 'l'}) + self.handle_esc_bta(d0n, d0p) + #self.findmode_state = 'Find Mode state0' + elif self.state == 'FIND DATA': + (d0n, d0p) = self.wait([{0: 'h', 1: 'l'}, {0: 'l', 1: 'h'}]) + self.wait([{0: 'l', 1: 'l'}, {0: 'h', 1: 'h'}]) + + if (self.matched & (0b1 << 0)): + self.handle_data(d0n, d0p) + else : + self.handle_stop() + + diff --git a/libsigrokdecode4DSL/decoders/mipi_rffe/__init__.py b/libsigrokdecode4DSL/decoders/mipi_rffe/__init__.py new file mode 100644 index 00000000..c63ab855 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/mipi_rffe/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +''' +RFFE(RF Front-End Control Interface)is a bidirectional, single-master +bus using two signals (SCLK = serial clock line, SDATA = serial data line). +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/mipi_rffe/pd.py b/libsigrokdecode4DSL/decoders/mipi_rffe/pd.py new file mode 100644 index 00000000..a8673d03 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/mipi_rffe/pd.py @@ -0,0 +1,510 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2010-2016 Uwe Hermann +## Copyright (C) 2020 DreamSourceLab +## +## 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, see . +## + +# TODO: Look into arbitration, collision detection, clock synchronisation, etc. +# TODO: Implement support for inverting SDATA/SCLK levels (0->1 and 1->0). +# TODO: Implement support for detecting various bus errors. + +import sigrokdecode as srd + +''' +OUTPUT_PYTHON format: + +Packet: +[SSC,, ] + +SSC:Sequence Start Condition + +: + - 'SA' (Slave Address) + - 'COMMAND' (command Key) + - 'BC' (Byte Count) + - 'P' (Parity) + - 'ADDRESS' (Register Address) + - 'DATA WRITE0' (Register 0 Write Data) +: + - 'ADDRESS' (Register Address) + - 'P' (Parity) + - 'BP' (Bus Park) + - 'DATA READ' (Data, read) + - 'DATA WRITE' (Data, write) + + : A Command Frame shall consist of a 4-bit Slave address field, an 8-bit command payload field, and a single parity bit. + + : A Data or Address Frame shall consist of eight data bits or eight address bits, respectively, and a single parity bit. +''' +# cmd: [annotation-type-index, long annotation, short annotation] +proto = { + 'SSC': [0, 'Sequence Start Condition', 'SSC'], + 'SA': [1, 'Slave Address', 'SA'], + 'ERW': [2, 'Extended Register Write', 'ERW'], + 'ERR': [3, 'Extended Register Read', 'ERR'], + 'ERWL': [4, 'Extended Register Write Long', 'ERWL'], + 'ERRL': [5, 'Extended Register Read Long', 'ERRL'], + 'RW': [6, 'Register Write', 'RW'], + 'RR': [7, 'Register Read', 'RR'], + 'R0W': [8, 'Register 0 Write', 'R0W'], + 'BC': [9, 'Byte', 'BC'], + 'P': [10, 'Parity', 'P'], + 'ADDRESS': [11, 'Address', 'A'], + 'BP': [12, 'Bus Pack', 'BP'], + 'DATA': [13, 'Data ', 'DATA'], + 'CMD_WARNINGS': [14, 'Command Warnings', 'CMD_WARN'], + 'BIC': [15, 'Bus Idle Condition ', 'BIC'], + 'BC_WARNINGS': [16, 'BC Warnings', 'BC_WARN'], + 'IJE': [17, 'Illegal Jump Edge', 'IJE_WAEN'], + 'PW': [18, 'Parity warnings', 'P_WAEN'], +} + +class Decoder(srd.Decoder): + api_version = 3 + id = 'mipi_rffe' + name = 'MIPI_RFFE' + longname = 'RF Front-End Control Interface' + desc = 'Two-wire, single-master, serial bus.' + license = 'gplv2+' + inputs = ['logic'] + outputs = ['mipi_rffe'] + tags = ['Embedded/industrial'] + channels = ( + {'id': 'sclk', 'type': 8, 'name': 'SCLK', 'desc': 'Serial clock line'}, + {'id': 'sdata', 'type': 108, 'name': 'SDATA', 'desc': 'Serial data line'}, + ) + options = ( + {'id': 'error_display', 'desc': 'Error display options', + 'default': 'display', 'values': ('display', 'not_display')}, + ) + annotations = ( + ('7', 'ssc', 'Sequence Start Condition'), + ('6', 'sa', 'Slave Address'), + ('1', 'erw', 'Extended register write'), + ('5', 'err', 'Extended register read'), + ('0', 'erwl', 'Extended register write long'), + ('112', 'errl', 'Extended register read long'), + ('111', 'rw', 'Register write'), + ('110', 'rr', 'Register read'), + ('109', 'r0w', 'Register 0 write'), + ('108', 'bc', 'Byte'), + ('7', 'p', 'Parity'), + ('75', 'address', 'Address'), + ('70', 'bp', 'Bus pack'), + ('65', 'data', 'DATA'), + ('1000', 'Command warnings', 'Command warnings'), + ('50', 'Bus Idle Condition ', 'Bus Idle Condition '), + ('1000', 'BC warnings', 'BC warnings'), + ('1000', 'Illegal Jump Edge', 'IJE_WAEN'), + ('1000', 'Parity warnings', 'Parity warnings'), + ) + annotation_rows = ( + ('command-data', 'Command/Data', (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 , 11, 12, 13 ,15)), + ('warnings', 'Warnings', (14,16,17,18,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.ss = self.es = -1 + self.bitcount = 0 + self.databyte = 0 + self.state = 'FIND SSC' + self.extended = -1 + self.cmdkey = 'NULL' + self.BC = 0 + self.bits = 0 + self.Pcount = 0 + self.BPcount = 0 + self.ADDcount = 0 + self.BPss = 0 + self.SSCs = 0 + self.Pes = 0 + self.sdata = -1 + self.Pdata = -1 + self.parity = False + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self._display = 1 if self.options['error_display'] == 'display' else 0 + + def putx(self, data): + self.put(self.ss, self.es, self.out_ann, data) + + def Parity(self): + self.parity = True + if self.Pcount == 1 : + if self.cmdkey == 'ERW' : + self.Pdata = self.Pdata + (0*(2**(self.Pkey+1))) + if self.cmdkey == 'ERR' : + self.Pdata = self.Pdata + (2*(2**(self.Pkey+1))) + if self.cmdkey == 'ERWL' : + self.Pdata = self.Pdata + (6*(2**(self.Pkey+1))) + if self.cmdkey == 'ERRL' : + self.Pdata = self.Pdata + (7*(2**(self.Pkey+1))) + if self.cmdkey == 'RW' : + self.Pdata = self.Pdata + (2*(2**(self.Pkey+1))) + if self.cmdkey == 'RR' : + self.Pdata = self.Pdata + (3*(2**(self.Pkey+1))) + if self.cmdkey == 'R0W' : + self.Pdata = self.Pdata + (1*(2**(self.Pkey+1))) + while self.Pdata : + self.parity = not self.parity + self.Pdata = self.Pdata & (self.Pdata - 1) + self.Pdata = self.Pkey = 0 + + + def handle_BP(self,cmd,state): + + self.ss = self.Pes + self.es = self.samplenum + self.putx([proto[cmd][0], proto[cmd][1:]]) + self.state = state + + def handle(self,cmd,state,key,key0): + key1 = key + if key > 7 : + key = 7 + if self.bitcount == 0: + self.DATAss = self.samplenum + + if self.bitcount < key: + while True : + if self._display : + (sclk, sdata) = self.wait([{0: 'f'},{0: 'l', 1: 'e'}]) + if (self.matched & (0b1 << 0)): + self.databyte <<= 1 + self.databyte |= sdata + break + if (self.matched & (0b1 << 1)): + self.ss = self.samplenum + (sclk, sdata) = self.wait([{0: 'f'},{0: 'l', 1: 'e'}]) + if (self.matched & (0b1 << 0)): + self.es = self.samplenum + self.putx([proto['IJE'][0], proto['IJE'][1:]]) + self.databyte <<= 1 + self.databyte |= sdata + break + if (self.matched & (0b1 << 1)): + self.es = self.samplenum + self.putx([proto['IJE'][0], proto['IJE'][1:]]) + else : + (sclk, sdata) = self.wait({0: 'f'}) + self.databyte <<= 1 + self.databyte |= sdata + break + + self.bitcount += 1 + return + + while True : + if self._display : + (sclk, sdata) = self.wait([{0: 'f'},{0: 'l', 1: 'e'}]) + if (self.matched & (0b1 << 0)): + self.databyte <<= 1 + self.databyte |= sdata + break + if (self.matched & (0b1 << 1)): + self.ss = self.samplenum + (sclk, sdata) = self.wait([{0: 'f'},{0: 'l', 1: 'e'}]) + if (self.matched & (0b1 << 0)): + self.es = self.samplenum + self.putx([proto['IJE'][0], proto['IJE'][1:]]) + self.databyte <<= 1 + self.databyte |= sdata + break + if (self.matched & (0b1 << 1)): + self.es = self.samplenum + self.putx([proto['IJE'][0], proto['IJE'][1:]]) + else : + (sclk, sdata) = self.wait({0: 'f'}) + self.databyte <<= 1 + self.databyte |= sdata + break + self.wait({0 : 'r'}) + d = self.databyte + self.ss = self.DATAss + self.es = self.samplenum + if cmd != 'P': + self.Pdata = d + self.Pkey = key + if cmd == 'BC': + self.BC = d + if self.cmdkey == 'ERW' or self.cmdkey == 'ERR' : + if self.BC < 4 or self.BC > 16 : + self.putx([proto['BC_WARNINGS'][0], proto['BC_WARNINGS'][1:]]) + self.init() + return + else : + if self.BC < 1 or self.BC > 8 : + self.putx([proto['BC_WARNINGS'][0], proto['BC_WARNINGS'][1:]]) + self.init() + return + if cmd == 'P': + self.Pes = self.samplenum + if self._display : + self.Parity() + if self.parity != d : + self.putx([proto['PW'][0], proto['PW'][1:]]) + self.putx([proto[cmd][0], ['%s: %d' % (proto[cmd][1],d), + '%s: %d' % (proto[cmd][2],d), '%d' % d]]) + self.bitcount = self.databyte = 0 + self.state = state + return + self.putx([proto[cmd][0], ['%s[%d:%d]: %02X' % (proto[cmd][1],key1,key0,d), + '%s[%d:%d]: %02X' % (proto[cmd][2],key1,key0,d), '%02X' % d]]) + self.bitcount = self.databyte = 0 + if cmd == 'DATA': + self.bits -= 8 + self.state = state + + + + + def handle_CMD(self): + if self.bitcount == 0: + self.DATAss = self.samplenum + (sclk, sdata) = self.wait({0: 'f'}) + if sdata : + self.wait({0 : 'r'}) + self.cmdset('R0W','FIND DATA') + return + + if self.bitcount == 1: + if self.sdata : + self.extended = 0 + else : + self.extended = 1 + + if self.bitcount == 2: + if not self.extended : + if self.sdata : + self.cmdset('RR','FIND ADDRESS') + return + else : + self.cmdset('RW','FIND ADDRESS') + return + + if self.bitcount == 3: + if not self.sdata : + if self.extended : + self.cmdset('ERR','FIND BTEY_COUNT') + return + else : + self.cmdset('ERW','FIND BTEY_COUNT') + return + elif self.extended : + self.ss = self.DATAss + self.es = self.samplenum + self.putx([proto['CMD_WARNINGS'][0], proto['CMD_WARNINGS'][1:]]) + self.init() + return + + if self.bitcount == 4: + if self.sdata : + self.cmdset('ERRL','FIND BTEY_COUNT') + return + else : + self.cmdset('ERWL','FIND BTEY_COUNT') + return + + if self.bitcount <4: + while True : + if self._display : + (sclk,self.sdata) = self.wait([{0: 'f'},{0: 'l', 1: 'e'}]) + if (self.matched & (0b1 << 0)): + break + if (self.matched & (0b1 << 1)): + self.ss = self.samplenum + (sclk,self.sdata) = self.wait([{0: 'f'},{0: 'l', 1: 'e'}]) + if (self.matched & (0b1 << 0)): + self.es = self.samplenum + self.putx([proto['IJE'][0], proto['IJE'][1:]]) + break + if (self.matched & (0b1 << 1)): + self.es = self.samplenum + self.putx([proto['IJE'][0], proto['IJE'][1:]]) + else : + (sclk,self.sdata) = self.wait({0: 'f'}) + break + self.wait({0 : 'r'}) + self.bitcount += 1 + + def cmdset(self,cmd,state): + self.ss = self.DATAss + self.es = self.samplenum + self.putx([proto[cmd][0], proto[cmd][1:]]) + self.state = state + self.bitcount = 0 + self.extended = -1 + self.cmdkey = cmd + + def initBP(self,sclk,sdata,state,key): + self.handle_BP('BP',state) + self.state = state + if key : + self.init() + + def init(self): + self.cmdkey = 'NULL' + self.ADDcount = 0 + self.Pcount = 0 + self.BPcount = 0 + self.BC = 0 + self.bitcount = 0 + self.Pes = 0 + self.state = 'FIND SSC' + + + + + def decode(self): + while True: + if self.state == 'FIND SSC': + self.wait({0: 'l', 1: 'r'}) + self.BPss = self.samplenum + self.wait([{0: 'h'},{0: 'l', 1: 'f'}]) + if (self.matched & (0b1 << 0)): + continue + if (self.matched & (0b1 << 1)): + self.wait([{0: 'l', 1: 'e'},{0: 'r'}]) + if (self.matched & (0b1 << 0)): + continue + if (self.matched & (0b1 << 1)): + self.ss,self.es = self.BPss,self.samplenum + self.putx([proto['SSC'][0], proto['SSC'][1:]]) + self.state = 'FIND SLAVE ADDRESS' + + elif self.state == 'FIND SLAVE ADDRESS': + self.handle('SA','FIND COMMAND',3,0) + + elif self.state == 'FIND COMMAND': + self.handle_CMD() + + elif self.state == 'FIND BTEY_COUNT': + if self.cmdkey == 'ERW' or self.cmdkey == 'ERR' : + self.handle('BC','FIND PARITY',3,0) + else : + self.handle('BC','FIND PARITY',2,0) + self.bits = self.BC*8 + + elif self.state == 'FIND ADDRESS': + if self.cmdkey == 'RW' or self.cmdkey == 'RR' : + self.handle('ADDRESS','FIND PARITY',4,0) + elif self.cmdkey == 'ERR' or self.cmdkey == 'ERW' : + self.handle('ADDRESS','FIND PARITY',7,0) + else : + if self.Pcount == 1 : + self.handle('ADDRESS','FIND PARITY',15,8) + else : + self.handle('ADDRESS','FIND PARITY',7,0) + + elif self.state == 'FIND DATA': + if self.cmdkey == 'R0W' : + self.handle('DATA','FIND PARITY',6,0) + elif self.cmdkey == 'RW' or self.cmdkey == 'RR' : + self.handle('DATA','FIND PARITY',7,0) + else : + self.handle('DATA','FIND PARITY',self.bits-1,self.bits-8) + + elif self.state == 'FIND PARITY': + self.Pcount += 1 + self.handle('P','NULL',0,0) + if self.cmdkey == 'R0W' : + self.state = 'FIND BUS_PARK' + + elif self.cmdkey == 'ERW' : + if self.Pcount == 1 : + self.ADDcount,self.state = 1,'FIND ADDRESS' + elif self.Pcount == 2 : + self.state = 'FIND DATA' + elif self.Pcount == self.BC + 2 : + self.state = 'FIND BUS_PARK' + continue + elif self.Pcount > 2 : + self.state = 'FIND DATA' + + elif self.cmdkey == 'ERR' : + if self.Pcount == 1 : + self.ADDcount,self.state = 1,'FIND ADDRESS' + elif self.Pcount == 2 : + self.BPcount,self.state = 1,'FIND BUS_PARK' + elif self.Pcount == self.BC + 2 : + self.BPcount =2 + self.state = 'FIND BUS_PARK' + continue + elif self.Pcount > 2 : + self.state = 'FIND DATA' + + elif self.cmdkey == 'ERWL' : + if self.Pcount == 1 : + self.ADDcount,self.state = 2,'FIND ADDRESS' + elif self.Pcount == 2 : + self.ADDcount,self.state = 1,'FIND ADDRESS' + elif self.Pcount == 3 : + self.state = 'FIND DATA' + elif self.Pcount == self.BC + 3 : + self.state = 'FIND BUS_PARK' + continue + elif self.Pcount > 3 : + self.state = 'FIND DATA' + + elif self.cmdkey == 'ERRL' : + if self.Pcount == 1 : + self.ADDcount,self.state = 2,'FIND ADDRESS' + elif self.Pcount == 2 : + self.ADDcount,self.state = 1,'FIND ADDRESS' + elif self.Pcount == 3 : + self.BPcount,self.state = 1,'FIND BUS_PARK' + elif self.Pcount == self.BC + 3 : + self.BPcount =2 + self.state = 'FIND BUS_PARK' + continue + elif self.Pcount > 3 : + self.state = 'FIND DATA' + + elif self.cmdkey == 'RW' : + if self.Pcount == 1 : + self.state = 'FIND DATA' + elif self.Pcount == 2 : + self.BPcount,self.state = 1,'FIND BUS_PARK' + + elif self.cmdkey == 'RR' : + self.state = 'FIND BUS_PARK' + self.BPcount = 1 if (self.Pcount == 1) else 2 + + elif self.state == 'FIND BUS_PARK': + (sclk, sdata) = self.wait({0: 'l', 1: 'l'}) + self.ss = self.samplenum + if self.cmdkey == 'ERR' or self.cmdkey == 'ERRL' or self.cmdkey == 'RR': + key = 0 if (self.BPcount == 1) else 1 + self.initBP(sclk,sdata,'FIND DATA',key) + else : + self.initBP(sclk,sdata,'FIND SSC',1) + + + + + + + \ No newline at end of file diff --git a/libsigrokdecode4DSL/decoders/mlx90614/__init__.py b/libsigrokdecode4DSL/decoders/mlx90614/__init__.py new file mode 100644 index 00000000..2e20c4d9 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/mlx90614/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +''' +This decoder stacks on top of the 'i2c' PD and decodes the Melexis MLX90614 +infrared thermometer protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/mlx90614/pd.py b/libsigrokdecode4DSL/decoders/mlx90614/pd.py new file mode 100644 index 00000000..f0dbe22a --- /dev/null +++ b/libsigrokdecode4DSL/decoders/mlx90614/pd.py @@ -0,0 +1,78 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +import sigrokdecode as srd + +class Decoder(srd.Decoder): + api_version = 3 + id = 'mlx90614' + name = 'MLX90614' + longname = 'Melexis MLX90614' + desc = 'Melexis MLX90614 infrared thermometer protocol.' + license = 'gplv2+' + inputs = ['i2c'] + outputs = [] + tags = ['IC', 'Sensor'] + annotations = ( + ('celsius', 'Temperature in degrees Celsius'), + ('kelvin', 'Temperature in Kelvin'), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.state = 'IGNORE START REPEAT' + self.data = [] + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + self.put(self.ss, self.es, self.out_ann, data) + + # Quick hack implementation! This needs to be improved a lot! + def decode(self, ss, es, data): + cmd, databyte = data + + # State machine. + if self.state == 'IGNORE START REPEAT': + if cmd != 'START REPEAT': + return + self.state = 'IGNORE ADDRESS WRITE' + elif self.state == 'IGNORE ADDRESS WRITE': + if cmd != 'ADDRESS WRITE': + return + self.state = 'GET TEMPERATURE' + elif self.state == 'GET TEMPERATURE': + if cmd != 'DATA WRITE': + return + if len(self.data) == 0: + self.data.append(databyte) + self.ss = ss + elif len(self.data) == 1: + self.data.append(databyte) + self.es = es + else: + kelvin = (self.data[0] | (self.data[1] << 8)) * 0.02 + celsius = kelvin - 273.15 + self.putx([0, ['Temperature: %3.2f °C' % celsius]]) + self.putx([1, ['Temperature: %3.2f K' % kelvin]]) + self.state = 'IGNORE START REPEAT' + self.data = [] diff --git a/libsigrokdecode4DSL/decoders/modbus/__init__.py b/libsigrokdecode4DSL/decoders/modbus/__init__.py new file mode 100644 index 00000000..b60eea15 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/modbus/__init__.py @@ -0,0 +1,28 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Bart de Waal +## +## 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, see . +## + +''' +This decoder stacks on top of the 'uart' PD and decodes Modbus RTU, +a protocol with a single a client and one or more servers. + +The RX channel will be checked for both client->server and server->client +communication, the TX channel only for client->server. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/modbus/pd.py b/libsigrokdecode4DSL/decoders/modbus/pd.py new file mode 100644 index 00000000..487acf1f --- /dev/null +++ b/libsigrokdecode4DSL/decoders/modbus/pd.py @@ -0,0 +1,934 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Bart de Waal +## Copyright (C) 2019 DreamSourceLab +## +## 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 . +## + +import sigrokdecode as srd +from math import ceil + +RX = 0 +TX = 1 + +class No_more_data(Exception): + '''This exception is a signal that we should stop parsing an ADU as there + is no more data to parse.''' + pass + +class Data: + '''The Data class is used to hold the bytes from the serial decode.''' + def __init__(self, start, end, data): + self.start = start + self.end = end + self.data = data + +class Modbus_ADU: + '''An Application Data Unit is what Modbus calls one message. + Protocol decoders are supposed to keep track of state and then provide + decoded data to the backend as it reads it. In Modbus' case, the state is + the ADU up to that point. This class represents the state and writes the + messages to the backend. + This class is for the common infrastructure between CS and SC. It should + not be used directly, only inhereted from.''' + + def __init__(self, parent, start, write_channel, annotation_prefix): + self.data = [] # List of all the data received up to now + self.parent = parent # Reference to the decoder object + self.start = start + self.last_read = start # The last moment parsed by this ADU object + self.write_channel = write_channel + self.last_byte_put = -1 + self.annotation_prefix = annotation_prefix + # Any Modbus message needs to be at least 4 bytes long. The Modbus + # function may make this longer. + self.minimum_length = 4 + + # This variable is used by an external function to determine when the + # next frame should be started. + self.startNewFrame = False + + # If there is an error in a frame, we'd like to highlight it. Keep + # track of errors. + self.hasError = False + + def add_data(self, start, end, data): + '''Let the frame handle another piece of data. + start: start of this data + end: end of this data + data: data as received from the UART decoder''' + ptype, rxtx, pdata = data + self.last_read = end + if ptype == 'DATA': + self.data.append(Data(start, end, pdata[0])) + self.parse() # parse() is defined in the specific type of ADU. + + def puti(self, byte_to_put, annotation, message): + '''This class keeps track of how much of the data has already been + annotated. This function tells the parent class to write message, but + only if it hasn't written about this bit before. + byte_to_put: Only write if it hasn't yet written byte_to_put. It will + write from the start of self.last_byte_put+1 to the end + of byte_to_put. + annotation: Annotation to write to, without annotation_prefix. + message: Message to write.''' + if byte_to_put > len(self.data) - 1: + # If the byte_to_put hasn't been read yet. + raise No_more_data + + if annotation == 'error': + self.hasError = True + + if byte_to_put > self.last_byte_put: + self.parent.puta( + self.data[self.last_byte_put + 1].start, + self.data[byte_to_put].end, + self.annotation_prefix + annotation, + message) + self.last_byte_put = byte_to_put + raise No_more_data + + def putl(self, annotation, message, maximum=None): + '''Puts the last byte on the stack with message. The contents of the + last byte will be applied to message using format.''' + last_byte_address = len(self.data) - 1 + if maximum is not None and last_byte_address > maximum: + return + self.puti(last_byte_address, annotation, + message.format(self.data[-1].data)) + + def close(self, message_overflow): + '''Function to be called when next message is started. As there is + always space between one message and the next, we can use that space + for errors at the end.''' + # TODO: Figure out how to make this happen for last message. + data = self.data + if len(data) < self.minimum_length: + if len(data) == 0: + # Sometimes happens with noise, safe to ignore. + return + self.parent.puta( + data[self.last_byte_put].end, message_overflow, + self.annotation_prefix + 'error', + 'Message too short or not finished') + self.hasError = True + if self.hasError and self.parent.options['channel'] == 'RX': + # If we are on RX mode (so client->server and server->client + # messages can be seperated) we like to mark blocks containing + # errors. We don't do this in TX mode, because then we interpret + # each frame as both a client->server and server->client frame, and + # one of those is bound to contain an error, making highlighting + # frames useless. + self.parent.puta(data[0].start, data[-1].end, + 'error-indication', 'Frame contains error') + if len(data) > 256: + try: + self.puti(len(data) - 1, self.annotation_prefix + 'error', + 'Modbus data frames are limited to 256 bytes') + except No_more_data: + pass + + def check_crc(self, byte_to_put): + '''Check the CRC code, data[byte_to_put] is the 2nd byte of the CRC.''' + crc_byte1, crc_byte2 = self.calc_crc(byte_to_put) + data = self.data + if data[-2].data == crc_byte1 and data[-1].data == crc_byte2: + self.puti(byte_to_put, 'crc', 'CRC correct') + else: + self.puti(byte_to_put, 'error', + 'CRC should be {} {}'.format(crc_byte1, crc_byte2)) + + def half_word(self, start): + '''Return the half word (16 bit) value starting at start bytes in. If + it goes out of range it raises the usual errors.''' + if (start + 1) > (len(self.data) - 1): + # If there isn't enough length to access data[start + 1]. + raise No_more_data + return self.data[start].data * 0x100 + self.data[start + 1].data + + def calc_crc(self, last_byte): + '''Calculate the CRC, as described in the spec. + The last byte of the CRC should be data[last_byte].''' + if last_byte < 3: + # Every Modbus ADU should be as least 4 long, so we should never + # have to calculate a CRC on something shorter. + raise Exception('Could not calculate CRC: message too short') + + result = 0xFFFF + magic_number = 0xA001 # As defined in the modbus specification. + for byte in self.data[:last_byte - 1]: + result = result ^ byte.data + for i in range(8): + LSB = result & 1 + result = result >> 1 + if (LSB): # If the LSB is true. + result = result ^ magic_number + byte1 = result & 0xFF + byte2 = (result & 0xFF00) >> 8 + return (byte1, byte2) + + def parse_write_single_coil(self): + '''Parse function 5, write single coil.''' + self.minimum_length = 8 + + self.puti(1, 'function', 'Function 5: Write Single Coil') + + address = self.half_word(2) + self.puti(3, 'address', + 'Address 0x{:X} / {:d}'.format(address, address + 10000)) + + raw_value = self.half_word(4) + value = 'Invalid Coil Value' + if raw_value == 0x0000: + value = 'Coil Value OFF' + elif raw_value == 0xFF00: + value = 'Coil Value ON' + self.puti(5, 'data', value) + + self.check_crc(7) + + def parse_write_single_register(self): + '''Parse function 6, write single register.''' + self.minimum_length = 8 + + self.puti(1, 'function', 'Function 6: Write Single Register') + + address = self.half_word(2) + self.puti(3, 'address', + 'Address 0x{:X} / {:d}'.format(address, address + 30000)) + + value = self.half_word(4) + value_formatted = 'Register Value 0x{0:X} / {0:d}'.format(value) + self.puti(5, 'data', value_formatted) + + self.check_crc(7) + + def parse_diagnostics(self): + '''Parse function 8, diagnostics. This function has many subfunctions, + but they are all more or less the same.''' + self.minimum_length = 8 + + self.puti(1, 'function', 'Function 8: Diagnostics') + + diag_subfunction = { + 0: 'Return Query data', + 1: 'Restart Communications Option', + 2: 'Return Diagnostics Register', + 3: 'Change ASCII Input Delimiter', + 4: 'Force Listen Only Mode', + 10: 'Clear Counters and Diagnostic Register', + 11: 'Return Bus Message Count', + 12: 'Return Bus Communication Error Count', + 13: 'Return Bus Exception Error Count', + 14: 'Return Slave Message Count', + 15: 'Return Slave No Response Count', + 16: 'Return Slave NAK Count', + 17: 'Return Slave Busy Count', + 18: 'Return Bus Character Overrun Count', + 20: 'Return Overrun Counter and Flag', + } + subfunction = self.half_word(2) + subfunction_name = diag_subfunction.get(subfunction, + 'Reserved subfunction') + self.puti(3, 'data', + 'Subfunction {}: {}'.format(subfunction, subfunction_name)) + + diagnostic_data = self.half_word(4) + self.puti(5, 'data', + 'Data Field: {0} / 0x{0:04X}'.format(diagnostic_data)) + + self.check_crc(7) + + def parse_mask_write_register(self): + '''Parse function 22, Mask Write Register.''' + self.minimum_length = 10 + data = self.data + + self.puti(1, 'function', 'Function 22: Mask Write Register') + + address = self.half_word(2) + self.puti(3, 'address', + 'Address 0x{:X} / {:d}'.format(address, address + 30001)) + + self.half_word(4) # To make sure we don't oveflow data. + and_mask_1 = data[4].data + and_mask_2 = data[5].data + self.puti(5, 'data', + 'AND mask: {:08b} {:08b}'.format(and_mask_1, and_mask_2)) + + self.half_word(6) # To make sure we don't oveflow data. + or_mask_1 = data[6].data + or_mask_2 = data[7].data + self.puti(7, 'data', + 'OR mask: {:08b} {:08b}'.format(or_mask_1, or_mask_2)) + + self.check_crc(9) + + def parse_not_implemented(self): + '''Explicitly mark certain functions as legal functions, but not + implemented in this parser. This is due to the author not being able to + find anything (hardware or software) that supports these functions.''' + # TODO: Implement these functions. + + # Mentioning what function it is is no problem. + function = self.data[1].data + functionname = { + 20: 'Read File Record', + 21: 'Write File Record', + 24: 'Read FIFO Queue', + 43: 'Read Device Identification/Encapsulated Interface Transport', + }[function] + self.puti(1, 'function', + 'Function {}: {} (not supported)'.format(function, functionname)) + + # From there on out we can keep marking it unsupported. + self.putl('data', 'This function is not currently supported') + +class Modbus_ADU_SC(Modbus_ADU): + '''SC stands for Server -> Client.''' + def parse(self): + '''Select which specific Modbus function we should parse.''' + data = self.data + + # This try-catch is being used as flow control. + try: + server_id = data[0].data + if 1 <= server_id <= 247: + message = 'Slave ID: {}'.format(server_id) + else: + message = 'Slave ID {} is invalid' + self.puti(0, 'server-id', message) + + function = data[1].data + if function == 1 or function == 2: + self.parse_read_bits() + elif function == 3 or function == 4 or function == 23: + self.parse_read_registers() + elif function == 5: + self.parse_write_single_coil() + elif function == 6: + self.parse_write_single_register() + elif function == 7: + self.parse_read_exception_status() + elif function == 8: + self.parse_diagnostics() + elif function == 11: + self.parse_get_comm_event_counter() + elif function == 12: + self.parse_get_comm_event_log() + elif function == 15 or function == 16: + self.parse_write_multiple() + elif function == 17: + self.parse_report_server_id() + elif function == 22: + self.parse_mask_write_register() + elif function in {21, 21, 24, 43}: + self.parse_not_implemented() + elif function > 0x80: + self.parse_error() + else: + self.puti(1, 'error', + 'Unknown function: {}'.format(data[1].data)) + self.putl('error', 'Unknown function') + + # If the message gets here without raising an exception, the + # message goes on longer than it should. + self.putl('error', 'Message too long') + + except No_more_data: + # Just a message saying we don't need to parse anymore this round. + pass + + def parse_read_bits(self): + self.mimumum_length = 5 + + data = self.data + function = data[1].data + + if function == 1: + self.puti(1, 'function', 'Function 1: Read Coils') + else: + self.puti(1, 'function', 'Function 2: Read Discrete Inputs') + + bytecount = self.data[2].data + self.minimum_length = 5 + bytecount # 3 before data, 2 CRC. + self.puti(2, 'length', 'Byte count: {}'.format(bytecount)) + + # From here on out, we expect registers on 3 and 4, 5 and 6 etc. + # So registers never start when the length is even. + self.putl('data', '{:08b}', bytecount + 2) + self.check_crc(bytecount + 4) + + def parse_read_registers(self): + self.mimumum_length = 5 + + data = self.data + + function = data[1].data + if function == 3: + self.puti(1, 'function', 'Function 3: Read Holding Registers') + elif function == 4: + self.puti(1, 'function', 'Function 4: Read Input Registers') + elif function == 23: + self.puti(1, 'function', 'Function 23: Read/Write Multiple Registers') + + bytecount = self.data[2].data + self.minimum_length = 5 + bytecount # 3 before data, 2 CRC. + if bytecount % 2 == 0: + self.puti(2, 'length', 'Byte count: {}'.format(bytecount)) + else: + self.puti(2, 'error', + 'Error: Odd byte count ({})'.format(bytecount)) + + # From here on out, we expect registers on 3 and 4, 5 and 6 etc. + # So registers never start when the length is even. + if len(data) % 2 == 1: + register_value = self.half_word(-2) + self.putl('data', '0x{0:04X} / {0}'.format(register_value), + bytecount + 2) + else: + raise No_more_data + + self.check_crc(bytecount + 4) + + def parse_read_exception_status(self): + self.mimumum_length = 5 + + self.puti(1, 'function', 'Function 7: Read Exception Status') + exception_status = self.data[2].data + self.puti(2, 'data', + 'Exception status: {:08b}'.format(exception_status)) + self.check_crc(4) + + def parse_get_comm_event_counter(self): + self.mimumum_length = 8 + + self.puti(1, 'function', 'Function 11: Get Comm Event Counter') + + status = self.half_word(2) + if status == 0x0000: + self.puti(3, 'data', 'Status: not busy') + elif status == 0xFFFF: + self.puti(3, 'data', 'Status: busy') + else: + self.puti(3, 'error', 'Bad status: 0x{:04X}'.format(status)) + + count = self.half_word(4) + self.puti(5, 'data', 'Event Count: {}'.format(count)) + self.check_crc(7) + + def parse_get_comm_event_log(self): + self.mimumum_length = 11 + self.puti(1, 'function', 'Function 12: Get Comm Event Log') + + data = self.data + + bytecount = data[2].data + self.puti(2, 'length', 'Bytecount: {}'.format(bytecount)) + # The bytecount is the length of everything except the slaveID, + # function code, bytecount and CRC. + self.mimumum_length = 5 + bytecount + + status = self.half_word(3) + if status == 0x0000: + self.puti(4, 'data', 'Status: not busy') + elif status == 0xFFFF: + self.puti(4, 'data', 'Status: busy') + else: + self.puti(4, 'error', 'Bad status: 0x{:04X}'.format(status)) + + event_count = self.half_word(5) + self.puti(6, 'data', 'Event Count: {}'.format(event_count)) + + message_count = self.half_word(7) + self.puti(8, 'data', 'Message Count: {}'.format(message_count)) + + self.putl('data', 'Event: 0x{:02X}'.format(data[-1].data), + bytecount + 2) + + self.check_crc(bytecount + 4) + + def parse_write_multiple(self): + '''Function 15 and 16 are almost the same, so we can parse them both + using one function.''' + self.mimumum_length = 8 + + function = self.data[1].data + if function == 15: + data_unit = 'Coils' + max_outputs = 0x07B0 + long_address_offset = 10001 + elif function == 16: + data_unit = 'Registers' + max_outputs = 0x007B + long_address_offset = 30001 + + self.puti(1, 'function', + 'Function {}: Write Multiple {}'.format(function, data_unit)) + + starting_address = self.half_word(2) + # Some instruction manuals use a long form name for addresses, this is + # listed here for convienience. + address_name = long_address_offset + starting_address + self.puti(3, 'address', + 'Start at address 0x{:X} / {:d}'.format(starting_address, + address_name)) + + quantity_of_outputs = self.half_word(4) + if quantity_of_outputs <= max_outputs: + self.puti(5, 'data', + 'Write {} {}'.format(quantity_of_outputs, data_unit)) + else: + self.puti(5, 'error', + 'Bad value: {} {}. Max is {}'.format(quantity_of_outputs, + data_unit, max_outputs)) + + self.check_crc(7) + + def parse_report_server_id(self): + # Buildup of this function: + # 1 byte serverID + # 1 byte function (17) + # 1 byte bytecount + # 1 byte serverID (counts for bytecount) + # 1 byte Run Indicator Status (counts for bytecount) + # bytecount - 2 bytes of device specific data (counts for bytecount) + # 2 bytes of CRC + self.mimumum_length = 7 + data = self.data + self.puti(1, 'function', 'Function 17: Report Server ID') + + bytecount = data[2].data + self.puti(2, 'length', 'Data is {} bytes long'.format(bytecount)) + + self.puti(3, 'data', 'serverID: {}'.format(data[3].data)) + + run_indicator_status = data[4].data + if run_indicator_status == 0x00: + self.puti(4, 'data', 'Run Indicator status: Off') + elif run_indicator_status == 0xFF: + self.puti(4, 'data', 'Run Indicator status: On') + else: + self.puti(4, 'error', + 'Bad Run Indicator status: 0x{:X}'.format(run_indicator_status)) + + self.putl('data', 'Device specific data: {}, "{}"'.format(data[-1].data, + chr(data[-1].data)), 2 + bytecount) + + self.check_crc(4 + bytecount) + + def parse_error(self): + '''Parse a Modbus error message.''' + self.mimumum_length = 5 + # The function code of an error is always 0x80 above the function call + # that caused it. + functioncode = self.data[1].data - 0x80 + + functions = { + 1: 'Read Coils', + 2: 'Read Discrete Inputs', + 3: 'Read Holding Registers', + 4: 'Read Input Registers', + 5: 'Write Single Coil', + 6: 'Write Single Register', + 7: 'Read Exception Status', + 8: 'Diagnostic', + 11: 'Get Com Event Counter', + 12: 'Get Com Event Log', + 15: 'Write Multiple Coils', + 16: 'Write Multiple Registers', + 17: 'Report Slave ID', + 20: 'Read File Record', + 21: 'Write File Record', + 22: 'Mask Write Register', + 23: 'Read/Write Multiple Registers', + 24: 'Read FIFO Queue', + 43: 'Read Device Identification/Encapsulated Interface Transport', + } + functionname = '{}: {}'.format(functioncode, + functions.get(functioncode, 'Unknown function')) + self.puti(1, 'function', + 'Error for function {}'.format(functionname)) + + error = self.data[2].data + errorcodes = { + 1: 'Illegal Function', + 2: 'Illegal Data Address', + 3: 'Illegal Data Value', + 4: 'Slave Device Failure', + 5: 'Acknowledge', + 6: 'Slave Device Busy', + 8: 'Memory Parity Error', + 10: 'Gateway Path Unavailable', + 11: 'Gateway Target Device failed to respond', + } + errorname = '{}: {}'.format(error, errorcodes.get(error, 'Unknown')) + self.puti(2, 'data', 'Error {}'.format(errorname)) + self.check_crc(4) + +class Modbus_ADU_CS(Modbus_ADU): + '''CS stands for Client -> Server.''' + def parse(self): + '''Select which specific Modbus function we should parse.''' + data = self.data + + # This try-catch is being used as flow control. + try: + server_id = data[0].data + message = '' + if server_id == 0: + message = 'Broadcast message' + elif 1 <= server_id <= 247: + message = 'Slave ID: {}'.format(server_id) + elif 248 <= server_id <= 255: + message = 'Slave ID: {} (reserved address)'.format(server_id) + self.puti(0, 'server-id', message) + + function = data[1].data + if function >= 1 and function <= 4: + self.parse_read_data_command() + if function == 5: + self.parse_write_single_coil() + if function == 6: + self.parse_write_single_register() + if function in {7, 11, 12, 17}: + self.parse_single_byte_request() + elif function == 8: + self.parse_diagnostics() + if function in {15, 16}: + self.parse_write_multiple() + elif function == 22: + self.parse_mask_write_register() + elif function == 23: + self.parse_read_write_registers() + elif function in {21, 21, 24, 43}: + self.parse_not_implemented() + else: + self.puti(1, 'error', + 'Unknown function: {}'.format(data[1].data)) + self.putl('error', 'Unknown function') + + # If the message gets here without raising an exception, the + # message goes on longer than it should. + self.putl('error', 'Message too long') + + except No_more_data: + # Just a message saying we don't need to parse anymore this round. + pass + + def parse_read_data_command(self): + '''Interpret a command to read x units of data starting at address, ie + functions 1, 2, 3 and 4, and write the result to the annotations.''' + data = self.data + self.minimum_length = 8 + + function = data[1].data + functionname = {1: 'Read Coils', + 2: 'Read Discrete Inputs', + 3: 'Read Holding Registers', + 4: 'Read Input Registers', + }[function] + + self.puti(1, 'function', + 'Function {}: {}'.format(function, functionname)) + + starting_address = self.half_word(2) + # Some instruction manuals use a long form name for addresses, this is + # listed here for convienience. + # Example: holding register 60 becomes 30061. + address_name = 10000 * function + 1 + starting_address + self.puti(3, 'address', + 'Start at address 0x{:X} / {:d}'.format(starting_address, + address_name)) + + self.puti(5, 'length', + 'Read {:d} units of data'.format(self.half_word(4))) + self.check_crc(7) + + def parse_single_byte_request(self): + '''Some Modbus functions have no arguments, this parses those.''' + function = self.data[1].data + function_name = {7: 'Read Exception Status', + 11: 'Get Comm Event Counter', + 12: 'Get Comm Event Log', + 17: 'Report Slave ID', + }[function] + self.puti(1, 'function', + 'Function {}: {}'.format(function, function_name)) + + self.check_crc(3) + + def parse_write_multiple(self): + '''Function 15 and 16 are almost the same, so we can parse them both + using one function.''' + self.mimumum_length = 9 + + function = self.data[1].data + if function == 15: + data_unit = 'Coils' + max_outputs = 0x07B0 + ratio_bytes_data = 1/8 + long_address_offset = 10001 + elif function == 16: + data_unit = 'Registers' + max_outputs = 0x007B + ratio_bytes_data = 2 + long_address_offset = 30001 + + self.puti(1, 'function', + 'Function {}: Write Multiple {}'.format(function, data_unit)) + + starting_address = self.half_word(2) + # Some instruction manuals use a long form name for addresses, this is + # listed here for convienience. + address_name = long_address_offset + starting_address + self.puti(3, 'address', + 'Start at address 0x{:X} / {:d}'.format(starting_address, + address_name)) + + quantity_of_outputs = self.half_word(4) + if quantity_of_outputs <= max_outputs: + self.puti(5, 'length', + 'Write {} {}'.format(quantity_of_outputs, data_unit)) + else: + self.puti(5, 'error', + 'Bad value: {} {}. Max is {}'.format(quantity_of_outputs, + data_unit, max_outputs)) + proper_bytecount = ceil(quantity_of_outputs * ratio_bytes_data) + + bytecount = self.data[6].data + if bytecount == proper_bytecount: + self.puti(6, 'length', 'Byte count: {}'.format(bytecount)) + else: + self.puti(6, 'error', + 'Bad byte count, is {}, should be {}'.format(bytecount, + proper_bytecount)) + self.mimumum_length = bytecount + 9 + + self.putl('data', 'Value 0x{:X}', 6 + bytecount) + + self.check_crc(bytecount + 8) + + def parse_read_file_record(self): + self.puti(1, 'function', 'Function 20: Read file records') + + data = self.data + + bytecount = data[2].data + + self.minimum_length = 5 + bytecount + # 1 for serverID, 1 for function, 1 for bytecount, 2 for CRC. + + if 0x07 <= bytecount <= 0xF5: + self.puti(2, 'length', 'Request is {} bytes long'.format(bytecount)) + else: + self.puti(2, 'error', + 'Request claims to be {} bytes long, legal values are between' + ' 7 and 247'.format(bytecount)) + + current_byte = len(data) - 1 + # Function 20 is a number of sub-requests, the first starting at 3, + # the total length of the sub-requests is bytecount. + if current_byte <= bytecount + 2: + step = (current_byte - 3) % 7 + if step == 0: + if data[current_byte].data == 6: + self.puti(current_byte, 'data', 'Start sub-request') + else: + self.puti(current_byte, 'error', + 'First byte of subrequest should be 0x06') + elif step == 1: + raise No_more_data + elif step == 2: + file_number = self.half_word(current_byte - 1) + self.puti(current_byte, 'data', + 'Read File number {}'.format(file_number)) + elif step == 3: + raise No_more_data + elif step == 4: + record_number = self.half_word(current_byte - 1) + self.puti(current_byte, 'address', + 'Read from record number {}'.format(record_number)) + # TODO: Check if within range. + elif step == 5: + raise No_more_data + elif step == 6: + records_to_read = self.half_word(current_byte - 1) + self.puti(current_byte, 'length', + 'Read {} records'.format(records_to_read)) + self.check_crc(4 + bytecount) + + def parse_read_write_registers(self): + '''Parse function 23: Read/Write multiple registers.''' + self.minimum_length = 13 + + self.puti(1, 'function', 'Function 23: Read/Write Multiple Registers') + + starting_address = self.half_word(2) + # Some instruction manuals use a long form name for addresses, this is + # listed here for convienience. + # Example: holding register 60 becomes 30061. + address_name = 30001 + starting_address + self.puti(3, 'address', + 'Read starting at address 0x{:X} / {:d}'.format(starting_address, + address_name)) + + self.puti(5, 'length', 'Read {:d} units of data'.format(self.half_word(4))) + + starting_address = self.half_word(6) + self.puti(7, 'address', + 'Write starting at address 0x{:X} / {:d}'.format(starting_address, + address_name)) + + quantity_of_outputs = self.half_word(8) + self.puti(9, 'length', + 'Write {} registers'.format(quantity_of_outputs)) + proper_bytecount = quantity_of_outputs * 2 + + bytecount = self.data[10].data + if bytecount == proper_bytecount: + self.puti(10, 'length', 'Byte count: {}'.format(bytecount)) + else: + self.puti(10, 'error', + 'Bad byte count, is {}, should be {}'.format(bytecount, + proper_bytecount)) + self.mimumum_length = bytecount + 13 + + self.putl('data', 'Data, value 0x{:02X}', 10 + bytecount) + + self.check_crc(bytecount + 12) + +class Decoder(srd.Decoder): + api_version = 3 + id = 'modbus' + name = 'Modbus' + longname = 'Modbus RTU over RS232/RS485' + desc = 'Modbus RTU protocol for industrial applications.' + license = 'gplv3+' + inputs = ['uart'] + outputs = ['modbus'] + tags = ['Embedded/industrial'] + annotations = ( + ('sc-server-id', ''), + ('sc-function', ''), + ('sc-crc', ''), + ('sc-address', ''), + ('sc-data', ''), + ('sc-length', ''), + ('sc-error', ''), + ('cs-server-id', ''), + ('cs-function', ''), + ('cs-crc', ''), + ('cs-address', ''), + ('cs-data', ''), + ('cs-length', ''), + ('cs-error', ''), + ('error-indication', ''), + ) + annotation_rows = ( + ('sc', 'Server->client', (7, 8, 9, 10, 11, 12, 13)), + ('cs', 'Client->server', (0, 1, 2, 3, 4, 5, 6)), + ('error-indicator', 'Errors in frame', (14,)), + ) + options = ( + {'id': 'channel', 'desc': 'Direction', 'default': 'TX', + 'values': ('TX', 'RX')}, + ) + + def __init__(self): + self.reset() + + def reset(self): + self.ADUSc = None # Start off with empty slave -> client ADU. + self.ADUCs = None # Start off with empty client -> slave ADU. + + # The reason we have both (despite not supporting full duplex comms) is + # because we want to be able to decode the message as both client -> + # server and server -> client, and let the user see which of the two + # the ADU was. + + self.bitlength = None # We will later test how long a bit is. + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def puta(self, start, end, ann_str, message): + '''Put an annotation from start to end, with ann as a + string. This means you don't have to know the ann's + number to write annotations to it.''' + ann = [s[0] for s in self.annotations].index(ann_str) + self.put(start, end, self.out_ann, [ann, [message]]) + + def decode_adu(self, ss, es, data, direction): + '''Decode the next byte or bit (depending on type) in the ADU. + ss: Start time of the data + es: End time of the data + data: Data as passed from the UART decoder + direction: Is this data for the Cs (client -> server) or Sc (server -> + client) being decoded right now?''' + ptype, rxtx, pdata = data + + # We don't have a nice way to get the baud rate from UART, so we have + # to figure out how long a bit lasts. We do this by looking at the + # length of (probably) the startbit. + if self.bitlength is None: + if ptype == 'STARTBIT' or ptype == 'STOPBIT': + self.bitlength = es - ss + else: + # If we don't know the bitlength yet, we can't start decoding. + return + + # Select the ADU, create the ADU if needed. + # We set ADU.startNewFrame = True when we know the old one is over. + if direction == 'Sc': + if (self.ADUSc is None) or self.ADUSc.startNewFrame: + self.ADUSc = Modbus_ADU_SC(self, ss, TX, 'sc-') + ADU = self.ADUSc + if direction == 'Cs': + if self.ADUCs is None or self.ADUCs.startNewFrame: + self.ADUCs = Modbus_ADU_CS(self, ss, TX, 'cs-') + ADU = self.ADUCs + + # We need to determine if the last ADU is over. + # According to the Modbus spec, there should be 3.5 characters worth of + # space between each message. But if within a message there is a length + # of more than 1.5 character, that's an error. For our purposes + # somewhere between seems fine. + # A character is 11 bits long, so (3.5 + 1.5)/2 * 11 ~= 28 + # TODO: Display error for too short or too long. + if (ss - ADU.last_read) <= self.bitlength * 28: + ADU.add_data(ss, es, data) + else: + # It's been too long since the last part of the ADU! + # If there is any data in the ADU we need to show it to the user + if len(ADU.data) > 0: + # Extend errors for 3 bits after last byte, we can guarantee + # space. + ADU.close(ADU.data[-1].end + self.bitlength * 3) + + ADU.startNewFrame = True + # Restart this function, it will make a new ADU for us. + self.decode_adu(ss, es, data, direction) + + def decode(self, ss, es, data): + ptype, rxtx, pdata = data + + # Decide what ADU(s) we need this packet to go to. + # Note that it's possible to go to both ADUs. + if self.options['channel'] == 'TX': + self.decode_adu(ss, es, data, 'Sc') + if self.options['channel'] == 'RX': + self.decode_adu(ss, es, data, 'Cs') diff --git a/libsigrokdecode4DSL/decoders/morse/__init__.py b/libsigrokdecode4DSL/decoders/morse/__init__.py new file mode 100644 index 00000000..5d916247 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/morse/__init__.py @@ -0,0 +1,28 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2017 Christoph Rackwitz +## +## 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, see . +## + +''' +Morse code is a method of transmitting text information as a series of +on-off tones. + +Details: +https://en.wikipedia.org/wiki/Morse_code +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/morse/pd.py b/libsigrokdecode4DSL/decoders/morse/pd.py new file mode 100644 index 00000000..8b5cb829 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/morse/pd.py @@ -0,0 +1,250 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2017 Christoph Rackwitz +## +## 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, see . +## + +import sigrokdecode as srd + +def decode_ditdah(s): + return tuple({'-': 3, '.': 1}[c] for c in s) + +def encode_ditdah(tpl): + return ''.join({1: '.', 3: '-'}[c] for c in tpl) + +# https://www.itu.int/dms_pubrec/itu-r/rec/m/R-REC-M.1677-1-200910-I!!PDF-E.pdf +# Recommendation ITU-R M.1677-1 +# (10/2009) +# International Morse code +alphabet = { + # 1.1.1 Letters + '.-': 'a', + '-...': 'b', + '-.-.': 'c', + '-..': 'd', + '.': 'e', + '..-..': 'é', # "accented" + '..-.': 'f', + '--.': 'g', + '....': 'h', + '..': 'i', + '.---': 'j', + '-.-': 'k', + '.-..': 'l', + '--': 'm', + '-.': 'n', + '---': 'o', + '.--.': 'p', + '--.-': 'q', + '.-.': 'r', + '...': 's', + '-': 't', + '..-': 'u', + '...-': 'v', + '.--': 'w', + '-..-': 'x', + '-.--': 'y', + '--..': 'z', + + # 1.1.2 Figures + '.----': '1', + '..---': '2', + '...--': '3', + '....-': '4', + '.....': '5', + '-....': '6', + '--...': '7', + '---..': '8', + '----.': '9', + '-----': '0', + + # 1.1.3 Punctuation marks and miscellaneous signs + '.-.-.-': '.', # Full stop (period) + '--..--': ',', # Comma + '---...': ':', # Colon or division sign + '..--..': '?', # Question mark (note of interrogation or request for repetition of a transmission not understood) + '.----.': '’', # Apostrophe + '-....-': '-', # Hyphen or dash or subtraction sign + '-..-.': '/', # Fraction bar or division sign + '-.--.': '(', # Left-hand bracket (parenthesis) + '-.--.-': ')', # Right-hand bracket (parenthesis) + '.-..-.': '“ ”', # Inverted commas (quotation marks) (before and after the words) + '-...-': '=', # Double hyphen + '...-.': 'UNDERSTOOD', # Understood + '........': 'ERROR', # Error (eight dots) + '.-.-.': '+', # Cross or addition sign + '.-...': 'WAIT', # Wait + '...-.-': 'EOW', # End of work + '-.-.-': 'START', # Starting signal (to precede every transmission) + '.--.-.': '@', # Commercial at + + #'-.-': 'ITT', # K: Invitation to transmit + + # 3.2.1 For the multiplication sign, the signal corresponding to the letter X shall be transmitted. + #'-..-': '×', # Multiplication sign +} + +alphabet = {decode_ditdah(k): v for k, v in alphabet.items()} + +# 2 Spacing and length of the signals (right side is just for printing). +symbols = { # level, time units + # 2.1 A dash is equal to three dots. + (1, 1): '*', + (1, 3): '===', + # 2.2 The space between the signals forming the same letter is equal to one dot. + (0, 1): '_', + # 2.3 The space between two letters is equal to three dots. + (0, 3): '__', + # 2.4 The space between two words is equal to seven dots. + (0, 7): '___', +} + +class Decoder(srd.Decoder): + api_version = 3 + id = 'morse' + name = 'Morse' + longname = 'Morse code' + desc = 'Demodulated morse code protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Encoding'] + channels = ( + {'id': 'data', 'name': 'Data', 'desc': 'Data line'}, + ) + options = ( + {'id': 'timeunit', 'desc': 'Time unit (guess)', 'default': 0.1}, + ) + annotations = ( + ('time', 'Time'), + ('units', 'Units'), + ('symbol', 'Symbol'), + ('letter', 'Letter'), + ('word', 'Word'), + ) + annotation_rows = tuple((u, v, (i,)) for i, (u, v) in enumerate(annotations)) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_binary = self.register(srd.OUTPUT_BINARY) + + def decode_symbols(self): + # Annotate symbols, emit symbols, handle timeout via token. + + timeunit = self.options['timeunit'] + + self.wait({0: 'r'}) + prevtime = self.samplenum # Time of an actual edge. + + while True: + (val,) = self.wait([{0: 'e'}, {'skip': int(5 * self.samplerate * timeunit)}]) + + pval = 1 - val + curtime = self.samplenum + dt = (curtime - prevtime) / self.samplerate + units = dt / timeunit + iunits = int(max(1, round(units))) + error = abs(units - iunits) + + symbol = (pval, iunits) + + if (self.matched & (0b1 << 1)): + yield None # Flush word. + continue + + self.put(prevtime, curtime, self.out_ann, [0, ['{:.3g}'.format(dt)]]) + + if symbol in symbols: + self.put(prevtime, curtime, self.out_ann, [1, ['{:.1f}*{:.3g}'.format(units, timeunit)]]) + yield (prevtime, curtime, symbol) + else: + self.put(prevtime, curtime, self.out_ann, [1, ['!! {:.1f}*{:.3g} !!'.format(units, timeunit)]]) + + prevtime = curtime + + thisunit = dt / iunits + timeunit += (thisunit - timeunit) * 0.2 * max(0, 1 - 2*error) # Adapt. + + def decode_morse(self): + # Group symbols into letters. + sequence = () + s0 = s1 = None + + for item in self.decode_symbols(): + do_yield = False + if item is not None: # Level + width. + (t0, t1, symbol) = item + (sval, sunits) = symbol + if sval == 1: + if s0 is None: + s0 = t0 + s1 = t1 + sequence += (sunits,) + else: + # Generate "flush" for end of letter, end of word. + if sunits >= 3: + do_yield = True + else: + do_yield = True + if do_yield: + if sequence: + yield (s0, s1, alphabet.get(sequence, encode_ditdah(sequence))) + sequence = () + s0 = s1 = None + if item is None: + yield None # Pass through flush of 5+ space. + + def decode(self): + + # Strictly speaking there is no point in running this decoder + # when the sample rate is unknown or zero. But the previous + # implementation already fell back to a rate of 1 in that case. + # We stick with this approach, to not introduce new constraints + # for existing use scenarios. + if not self.samplerate: + self.samplerate = 1.0 + + # Annotate letters, group into words. + s0 = s1 = None + word = '' + for item in self.decode_morse(): + do_yield = False + + if item is not None: # Append letter. + (t0, t1, letter) = item + self.put(t0, t1, self.out_ann, [3, [letter]]) + if s0 is None: + s0 = t0 + s1 = t1 + word += letter + else: + do_yield = True + + if do_yield: # Flush of word. + if word: + self.put(s0, s1, self.out_ann, [4, [word]]) + word = '' + s0 = s1 = None diff --git a/libsigrokdecode4DSL/decoders/mrf24j40/__init__.py b/libsigrokdecode4DSL/decoders/mrf24j40/__init__.py new file mode 100644 index 00000000..37b8b5c3 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/mrf24j40/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Karl Palsson +## +## 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, see . +## + +''' +This decoder stacks on top of the 'spi' PD and decodes Microchip MRF24J40 +IEEE 802.15.4 2.4 GHz RF tranceiver commands and data. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/mrf24j40/lists.py b/libsigrokdecode4DSL/decoders/mrf24j40/lists.py new file mode 100644 index 00000000..f5931c24 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/mrf24j40/lists.py @@ -0,0 +1,165 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Karl Palsson +## +## 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, see . +## + +sregs = { + 0: 'RXMCR', + 1: 'PANIDL', + 2: 'PANIDH', + 3: 'SADRL', + 4: 'SADRH', + 5: 'EADR0', + 6: 'EADR1', + 7: 'EADR2', + 8: 'EADR3', + 9: 'EADR4', + 0xa: 'EADR5', + 0xb: 'EADR6', + 0xc: 'EADR7', + 0xd: 'RXFLUSH', + 0xe: 'Reserved', + 0xf: 'Reserved', + 0x10: 'ORDER', + 0x11: 'TXMCR', + 0x12: 'ACKTMOUT', + 0x13: 'ESLOTG1', + 0x14: 'SYMTICKL', + 0x15: 'SYMTICKH', + 0x16: 'PACON0', + 0x17: 'PACON1', + 0x18: 'PACON2', + 0x19: 'Reserved', + 0x1a: 'TXBCON0', + 0x1b: 'TXNCON', + 0x1c: 'TXG1CON', + 0x1d: 'TXG2CON', + 0x1e: 'ESLOTG23', + 0x1f: 'ESLOTG45', + 0x20: 'ESLOTG67', + 0x21: 'TXPEND', + 0x22: 'WAKECON', + 0x23: 'FRMOFFSET', + 0x24: 'TXSTAT', + 0x25: 'TXBCON1', + 0x26: 'GATECLK', + 0x27: 'TXTIME', + 0x28: 'HSYMTIMRL', + 0x29: 'HSYMTIMRH', + 0x2a: 'SOFTRST', + 0x2b: 'Reserved', + 0x2c: 'SECCON0', + 0x2d: 'SECCON1', + 0x2e: 'TXSTBL', + 0x2f: 'Reserved', + 0x30: 'RXSR', + 0x31: 'INTSTAT', + 0x32: 'INTCON', + 0x33: 'GPIO', + 0x34: 'TRISGPIO', + 0x35: 'SLPACK', + 0x36: 'RFCTL', + 0x37: 'SECCR2', + 0x38: 'BBREG0', + 0x39: 'BBREG1', + 0x3a: 'BBREG2', + 0x3b: 'BBREG3', + 0x3c: 'BBREG4', + 0x3d: 'Reserved', + 0x3e: 'BBREG6', + 0x3f: 'CCAEDTH', +} + +lregs = { + 0x200: 'RFCON0', + 0x201: 'RFCON1', + 0x202: 'RFCON2', + 0x203: 'RFCON3', + 0x204: 'Reserved', + 0x205: 'RFCON5', + 0x206: 'RFCON6', + 0x207: 'RFCON7', + 0x208: 'RFCON8', + 0x209: 'SLPCAL0', + 0x20A: 'SLPCAL1', + 0x20B: 'SLPCAL2', + 0x20C: 'Reserved', + 0x20D: 'Reserved', + 0x20E: 'Reserved', + 0x20F: 'RFSTATE', + 0x210: 'RSSI', + 0x211: 'SLPCON0', + 0x212: 'Reserved', + 0x213: 'Reserved', + 0x214: 'Reserved', + 0x215: 'Reserved', + 0x216: 'Reserved', + 0x217: 'Reserved', + 0x218: 'Reserved', + 0x219: 'Reserved', + 0x21A: 'Reserved', + 0x21B: 'Reserved', + 0x21C: 'Reserved', + 0x21D: 'Reserved', + 0x21E: 'Reserved', + 0x21F: 'Reserved', + 0x220: 'SLPCON1', + 0x221: 'Reserved', + 0x222: 'WAKETIMEL', + 0x223: 'WAKETIMEH', + 0x224: 'REMCNTL', + 0x225: 'REMCNTH', + 0x226: 'MAINCNT0', + 0x227: 'MAINCNT1', + 0x228: 'MAINCNT2', + 0x229: 'MAINCNT3', + 0x22A: 'Reserved', + 0x22B: 'Reserved', + 0x22C: 'Reserved', + 0x22D: 'Reserved', + 0x22E: 'Reserved', + 0x22F: 'TESTMODE', + 0x230: 'ASSOEADR0', + 0x231: 'ASSOEADR1', + 0x232: 'ASSOEADR2', + 0x233: 'ASSOEADR3', + 0x234: 'ASSOEADR4', + 0x235: 'ASSOEADR5', + 0x236: 'ASSOEADR6', + 0x237: 'ASSOEADR7', + 0x238: 'ASSOSADR0', + 0x239: 'ASSOSADR1', + 0x23A: 'Reserved', + 0x23B: 'Reserved', + 0x23C: 'Unimplemented', + 0x23D: 'Unimplemented', + 0x23E: 'Unimplemented', + 0x23F: 'Unimplemented', + 0x240: 'UPNONCE0', + 0x241: 'UPNONCE1', + 0x242: 'UPNONCE2', + 0x243: 'UPNONCE3', + 0x244: 'UPNONCE4', + 0x245: 'UPNONCE5', + 0x246: 'UPNONCE6', + 0x247: 'UPNONCE7', + 0x248: 'UPNONCE8', + 0x249: 'UPNONCE9', + 0x24A: 'UPNONCE10', + 0x24B: 'UPNONCE11', + 0x24C: 'UPNONCE12' +} diff --git a/libsigrokdecode4DSL/decoders/mrf24j40/pd.py b/libsigrokdecode4DSL/decoders/mrf24j40/pd.py new file mode 100644 index 00000000..b242ee66 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/mrf24j40/pd.py @@ -0,0 +1,137 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Karl Palsson +## +## 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, see . +## + +import sigrokdecode as srd +from .lists import * + +class Decoder(srd.Decoder): + api_version = 3 + id = 'mrf24j40' + name = 'MRF24J40' + longname = 'Microchip MRF24J40' + desc = 'IEEE 802.15.4 2.4 GHz RF tranceiver chip.' + license = 'gplv2+' + inputs = ['spi'] + outputs = [] + tags = ['IC', 'Wireless/RF'] + annotations = ( + ('sread', 'Short register read commands'), + ('swrite', 'Short register write commands'), + ('lread', 'Long register read commands'), + ('lwrite', 'Long register write commands'), + ('warning', 'Warnings'), + ) + annotation_rows = ( + ('read', 'Read', (0, 2)), + ('write', 'Write', (1, 3)), + ('warnings', 'Warnings', (4,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.ss_cmd, self.es_cmd = 0, 0 + self.mosi_bytes = [] + self.miso_bytes = [] + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + self.put(self.ss_cmd, self.es_cmd, self.out_ann, data) + + def putw(self, pos, msg): + self.put(pos[0], pos[1], self.out_ann, [4, [msg]]) + + def reset_data(self): + self.mosi_bytes = [] + self.miso_bytes = [] + + def handle_short(self): + write = self.mosi_bytes[0] & 0x1 + reg = (self.mosi_bytes[0] >> 1) & 0x3f + reg_desc = sregs.get(reg, 'illegal') + if write: + self.putx([1, ['%s: %#x' % (reg_desc, self.mosi_bytes[1])]]) + else: + self.putx([0, ['%s: %#x' % (reg_desc, self.miso_bytes[1])]]) + + def handle_long(self): + dword = self.mosi_bytes[0] << 8 | self.mosi_bytes[1] + write = dword & (0x1 << 4) + reg = dword >> 5 & 0x3ff + if reg >= 0x0: + reg_desc = 'TX:%#x' % reg + if reg >= 0x80: + reg_desc = 'TX beacon:%#x' % reg + if reg >= 0x100: + reg_desc = 'TX GTS1:%#x' % reg + if reg >= 0x180: + reg_desc = 'TX GTS2:%#x' % reg + if reg >= 0x200: + reg_desc = lregs.get(reg, 'illegal') + if reg >= 0x280: + reg_desc = 'Security keys:%#x' % reg + if reg >= 0x2c0: + reg_desc = 'Reserved:%#x' % reg + if reg >= 0x300: + reg_desc = 'RX:%#x' % reg + + if write: + self.putx([3, ['%s: %#x' % (reg_desc, self.mosi_bytes[2])]]) + else: + self.putx([2, ['%s: %#x' % (reg_desc, self.miso_bytes[2])]]) + + def decode(self, ss, es, data): + ptype = data[0] + if ptype == 'CS-CHANGE': + # If we transition high mid-stream, toss out our data and restart. + cs_old, cs_new = data[1:] + if cs_old is not None and cs_old == 0 and cs_new == 1: + if len(self.mosi_bytes) not in (0, 2, 3): + self.putw([self.ss_cmd, es], 'Misplaced CS!') + self.reset_data() + return + + # Don't care about anything else. + if ptype != 'DATA': + return + mosi, miso = data[1:] + + self.ss, self.es = ss, es + + if len(self.mosi_bytes) == 0: + self.ss_cmd = ss + self.mosi_bytes.append(mosi) + self.miso_bytes.append(miso) + + # Everything is either 2 bytes or 3 bytes. + if len(self.mosi_bytes) < 2: + return + + if self.mosi_bytes[0] & 0x80: + if len(self.mosi_bytes) == 3: + self.es_cmd = es + self.handle_long() + self.reset_data() + else: + self.es_cmd = es + self.handle_short() + self.reset_data() diff --git a/libsigrokdecode4DSL/decoders/mxc6225xu/__init__.py b/libsigrokdecode4DSL/decoders/mxc6225xu/__init__.py new file mode 100644 index 00000000..2aaa726f --- /dev/null +++ b/libsigrokdecode4DSL/decoders/mxc6225xu/__init__.py @@ -0,0 +1,28 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +''' +This decoder stacks on top of the 'i2c' PD and decodes the MEMSIC MXC6225XU +digital thermal orientation sensor (DTOS) protocol. + +The chip's I²C interface supports standard mode and fast mode (max. 400kHz). +Its I²C slave address is 0x2a. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/mxc6225xu/pd.py b/libsigrokdecode4DSL/decoders/mxc6225xu/pd.py new file mode 100644 index 00000000..e9617782 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/mxc6225xu/pd.py @@ -0,0 +1,217 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +import sigrokdecode as srd + +# Definitions of various bits in MXC6225XU registers. +status = { + # SH[1:0] + 'sh': { + 0b00: 'none', + 0b01: 'shake left', + 0b10: 'shake right', + 0b11: 'undefined', + }, + # ORI[1:0] and OR[1:0] (same format) + 'ori': { + 0b00: 'vertical in upright orientation', + 0b01: 'rotated 90 degrees clockwise', + 0b10: 'vertical in inverted orientation', + 0b11: 'rotated 90 degrees counterclockwise', + }, + # SHTH[1:0] + 'shth': { + 0b00: '0.5g', + 0b01: '1.0g', + 0b10: '1.5g', + 0b11: '2.0g', + }, + # SHC[1:0] + 'shc': { + 0b00: '16', + 0b01: '32', + 0b10: '64', + 0b11: '128', + }, + # ORC[1:0] + 'orc': { + 0b00: '16', + 0b01: '32', + 0b10: '64', + 0b11: '128', + }, +} + +class Decoder(srd.Decoder): + api_version = 3 + id = 'mxc6225xu' + name = 'MXC6225XU' + longname = 'MEMSIC MXC6225XU' + desc = 'Digital Thermal Orientation Sensor (DTOS) protocol.' + license = 'gplv2+' + inputs = ['i2c'] + outputs = [] + tags = ['IC', 'Sensor'] + annotations = ( + ('text', 'Human-readable text'), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.state = 'IDLE' + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + self.put(self.ss, self.es, self.out_ann, data) + + def handle_reg_0x00(self, b): + # XOUT: 8-bit x-axis acceleration output. + # Data is in 2's complement, values range from -128 to 127. + self.putx([0, ['XOUT: %d' % b]]) + + def handle_reg_0x01(self, b): + # YOUT: 8-bit y-axis acceleration output. + # Data is in 2's complement, values range from -128 to 127. + self.putx([0, ['YOUT: %d' % b]]) + + def handle_reg_0x02(self, b): + # STATUS: Orientation and shake status. + + # Bits[7:7]: INT + int_val = (b >> 7) & 1 + s = 'unchanged and no' if (int_val == 0) else 'changed or' + ann = 'INT = %d: Orientation %s shake event occurred\n' % (int_val, s) + + # Bits[6:5]: SH[1:0] + sh = (((b >> 6) & 1) << 1) | ((b >> 5) & 1) + ann += 'SH[1:0] = %s: Shake event: %s\n' % \ + (bin(sh)[2:], status['sh'][sh]) + + # Bits[4:4]: TILT + tilt = (b >> 4) & 1 + s = '' if (tilt == 0) else 'not ' + ann += 'TILT = %d: Orientation measurement is %svalid\n' % (tilt, s) + + # Bits[3:2]: ORI[1:0] + ori = (((b >> 3) & 1) << 1) | ((b >> 2) & 1) + ann += 'ORI[1:0] = %s: %s\n' % (bin(ori)[2:], status['ori'][ori]) + + # Bits[1:0]: OR[1:0] + or_val = (((b >> 1) & 1) << 1) | ((b >> 0) & 1) + ann += 'OR[1:0] = %s: %s\n' % (bin(or_val)[2:], status['ori'][or_val]) + + # ann += 'b = %s\n' % (bin(b)) + + self.putx([0, [ann]]) + + def handle_reg_0x03(self, b): + # DETECTION: Powerdown, orientation and shake detection parameters. + # Note: This is a write-only register. + + # Bits[7:7]: PD + pd = (b >> 7) & 1 + s = 'Do not power down' if (pd == 0) else 'Power down' + ann = 'PD = %d: %s the device (into a low-power state)\n' % (pd, s) + + # Bits[6:6]: SHM + shm = (b >> 6) & 1 + ann = 'SHM = %d: Set shake mode to %d\n' % (shm, shm) + + # Bits[5:4]: SHTH[1:0] + shth = (((b >> 5) & 1) << 1) | ((b >> 4) & 1) + ann += 'SHTH[1:0] = %s: Set shake threshold to %s\n' \ + % (bin(shth)[2:], status['shth'][shth]) + + # Bits[3:2]: SHC[1:0] + shc = (((b >> 3) & 1) << 1) | ((b >> 2) & 1) + ann += 'SHC[1:0] = %s: Set shake count to %s readings\n' \ + % (bin(shc)[2:], status['shc'][shc]) + + # Bits[1:0]: ORC[1:0] + orc = (((b >> 1) & 1) << 1) | ((b >> 0) & 1) + ann += 'ORC[1:0] = %s: Set orientation count to %s readings\n' \ + % (bin(orc)[2:], status['orc'][orc]) + + self.putx([0, [ann]]) + + # TODO: Fixup, this is copy-pasted from another PD. + # TODO: Handle/check the ACKs/NACKs. + def decode(self, ss, es, data): + cmd, databyte = data + + # Store the start/end samples of this I²C packet. + self.ss, self.es = ss, es + + # State machine. + if self.state == 'IDLE': + # Wait for an I²C START condition. + if cmd != 'START': + return + self.state = 'GET SLAVE ADDR' + elif self.state == 'GET SLAVE ADDR': + # Wait for an address write operation. + # TODO: We should only handle packets to the slave(?) + if cmd != 'ADDRESS WRITE': + return + self.state = 'GET REG ADDR' + elif self.state == 'GET REG ADDR': + # Wait for a data write (master selects the slave register). + if cmd != 'DATA WRITE': + return + self.reg = databyte + self.state = 'WRITE REGS' + elif self.state == 'WRITE REGS': + # If we see a Repeated Start here, it's a multi-byte read. + if cmd == 'START REPEAT': + self.state = 'READ REGS' + return + # Otherwise: Get data bytes until a STOP condition occurs. + if cmd == 'DATA WRITE': + handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg) + handle_reg(databyte) + self.reg += 1 + # TODO: Check for NACK! + elif cmd == 'STOP': + # TODO + self.state = 'IDLE' + else: + pass # TODO + elif self.state == 'READ REGS': + # Wait for an address read operation. + # TODO: We should only handle packets to the slave(?) + if cmd == 'ADDRESS READ': + self.state = 'READ REGS2' + return + else: + pass # TODO + elif self.state == 'READ REGS2': + if cmd == 'DATA READ': + handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg) + handle_reg(databyte) + self.reg += 1 + # TODO: Check for NACK! + elif cmd == 'STOP': + # TODO + self.state = 'IDLE' + else: + pass # TODO? diff --git a/libsigrokdecode4DSL/decoders/nes_gamepad/__init__.py b/libsigrokdecode4DSL/decoders/nes_gamepad/__init__.py new file mode 100644 index 00000000..e7543748 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/nes_gamepad/__init__.py @@ -0,0 +1,54 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Stephan Thiele +## +## 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, see . +## + +''' +This decoder stacks on top of the 'spi' PD and decodes the button states +of an NES gamepad. + +The SPI decoder needs to be configured as follows: + +Clock polarity = 1 +Clock phase = 0 +Bit order = msb-first +Word size = 8 + +Chip-select is not used and must not be assigned to any channel. + +Hardware setup is as follows: + ___ + GND |o \ + CUP |o o| VCC + OUT 0 |o o| D3 + D1 |o o| D4 + ----- +NES Gamepad Connector + +VCC - Power 5V +GND - Ground +CUP - Shift register clock (CLK) +OUT 0 - Shift register latch (optional) +D1 - Gamepad data (MOSI) +D3 - Data (unused) +D4 - Data (unused) + +Data pins D3 and D4 are not used by the standard gamepad but +by special controllers like the Nintento Zapper light gun. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/nes_gamepad/pd.py b/libsigrokdecode4DSL/decoders/nes_gamepad/pd.py new file mode 100644 index 00000000..b276e5db --- /dev/null +++ b/libsigrokdecode4DSL/decoders/nes_gamepad/pd.py @@ -0,0 +1,105 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Stephan Thiele +## +## 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, see . +## + +import sigrokdecode as srd + +class Decoder(srd.Decoder): + api_version = 3 + id = 'nes_gamepad' + name = 'NES gamepad' + longname = 'Nintendo Entertainment System gamepad' + desc = 'NES gamepad button states.' + license = 'gplv2+' + inputs = ['spi'] + outputs = [] + tags = ['Retro computing'] + options = ( + # Currently only the standard controller is supported. This might be + # extended by special controllers like the Nintendo Zapper light gun. + {'id': 'variant', 'desc': 'Gamepad variant', + 'default': 'Standard gamepad', 'values': ('Standard gamepad',)}, + ) + annotations = ( + ('button', 'Button state'), + ('no-press', 'No button press'), + ('not-connected', 'Gamepad unconnected') + ) + annotation_rows = ( + ('buttons', 'Button states', (0,)), + ('no-presses', 'No button presses', (1,)), + ('not-connected-vals', 'Gamepad unconnected', (2,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.variant = None + self.ss_block = None + self.es_block = None + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.variant = self.options['variant'] + + def putx(self, data): + self.put(self.ss_block, self.es_block, self.out_ann, data) + + def handle_data(self, value): + if value == 0xFF: + self.putx([1, ['No button is pressed']]) + return + + if value == 0x00: + self.putx([2, ['Gamepad is not connected']]) + return + + buttons = [ + 'A', + 'B', + 'Select', + 'Start', + 'North', + 'South', + 'West', + 'East' + ] + + bits = format(value, '08b') + button_str = '' + + for b in enumerate(bits): + button_index = b[0] + button_is_pressed = b[1] == '0' + + if button_is_pressed: + if button_str != '': + button_str += ' + ' + button_str += buttons[button_index] + + self.putx([0, ['%s' % button_str]]) + + def decode(self, ss, es, data): + ptype, mosi, miso = data + self.ss_block, self.es_block = ss, es + + if ptype != 'DATA': + return + + self.handle_data(miso) diff --git a/libsigrokdecode4DSL/decoders/nrf24l01/__init__.py b/libsigrokdecode4DSL/decoders/nrf24l01/__init__.py new file mode 100644 index 00000000..60124780 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/nrf24l01/__init__.py @@ -0,0 +1,29 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Jens Steinhauser +## +## 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, see . +## + +''' +This decoder stacks on top of the 'spi' PD and decodes the protocol spoken +by the Nordic Semiconductor nRF24L01 and nRF24L01+ 2.4GHz transceiver chips. + +Details: +http://www.nordicsemi.com/eng/Products/2.4GHz-RF/nRF24L01 +http://www.nordicsemi.com/eng/Products/2.4GHz-RF/nRF24L01P +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/nrf24l01/pd.py b/libsigrokdecode4DSL/decoders/nrf24l01/pd.py new file mode 100644 index 00000000..89a2d3b4 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/nrf24l01/pd.py @@ -0,0 +1,370 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Jens Steinhauser +## Copyright (C) 2019 DreamSourceLab +## +## 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, see . +## + +import sigrokdecode as srd + +class ChannelError(Exception): + pass + +regs = { +# addr: ('name', size) + 0x00: ('CONFIG', 1), + 0x01: ('EN_AA', 1), + 0x02: ('EN_RXADDR', 1), + 0x03: ('SETUP_AW', 1), + 0x04: ('SETUP_RETR', 1), + 0x05: ('RF_CH', 1), + 0x06: ('RF_SETUP', 1), + 0x07: ('STATUS', 1), + 0x08: ('OBSERVE_TX', 1), + 0x09: ('RPD', 1), + 0x0a: ('RX_ADDR_P0', 5), + 0x0b: ('RX_ADDR_P1', 5), + 0x0c: ('RX_ADDR_P2', 1), + 0x0d: ('RX_ADDR_P3', 1), + 0x0e: ('RX_ADDR_P4', 1), + 0x0f: ('RX_ADDR_P5', 1), + 0x10: ('TX_ADDR', 5), + 0x11: ('RX_PW_P0', 1), + 0x12: ('RX_PW_P1', 1), + 0x13: ('RX_PW_P2', 1), + 0x14: ('RX_PW_P3', 1), + 0x15: ('RX_PW_P4', 1), + 0x16: ('RX_PW_P5', 1), + 0x17: ('FIFO_STATUS', 1), + 0x1c: ('DYNPD', 1), + 0x1d: ('FEATURE', 1), +} + +xn297_regs = { + 0x19: ('DEMOD_CAL', 1), + 0x1a: ('RF_CAL2', 6), + 0x1b: ('DEM_CAL2', 3), + 0x1e: ('RF_CAL', 3), + 0x1f: ('BB_CAL', 5), +} + +class Decoder(srd.Decoder): + api_version = 3 + id = 'nrf24l01' + name = 'nRF24L01(+)' + longname = 'Nordic Semiconductor nRF24L01(+)' + desc = '2.4GHz RF transceiver chip.' + license = 'gplv2+' + inputs = ['spi'] + outputs = [] + tags = ['IC', 'Wireless/RF'] + options = ( + {'id': 'chip', 'desc': 'Chip type', + 'default': 'nrf24l01', 'values': ('nrf24l01', 'xn297')}, + {'id': 'hex_display', 'desc': 'Display payload in Hex', 'default': 'yes', + 'values': ('yes', 'no')}, + ) + annotations = ( + # Sent from the host to the chip. + ('cmd', 'Commands sent to the device'), + ('tx-data', 'Payload sent to the device'), + + # Returned by the chip. + ('register', 'Registers read from the device'), + ('rx-data', 'Payload read from the device'), + + ('warning', 'Warnings'), + ) + ann_cmd = 0 + ann_tx = 1 + ann_reg = 2 + ann_rx = 3 + ann_warn = 4 + annotation_rows = ( + ('commands', 'Commands', (ann_cmd, ann_tx)), + ('responses', 'Responses', (ann_reg, ann_rx)), + ('warnings', 'Warnings', (ann_warn,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.next() + self.requirements_met = True + self.cs_was_released = False + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + if self.options['chip'] == 'xn297': + regs.update(xn297_regs) + + def warn(self, pos, msg): + '''Put a warning message 'msg' at 'pos'.''' + self.put(pos[0], pos[1], self.out_ann, [self.ann_warn, [msg]]) + + def putp(self, pos, ann, msg): + '''Put an annotation message 'msg' at 'pos'.''' + self.put(pos[0], pos[1], self.out_ann, [ann, [msg]]) + + def next(self): + '''Resets the decoder after a complete command was decoded.''' + # 'True' for the first byte after CS went low. + self.first = True + + # The current command, and the minimum and maximum number + # of data bytes to follow. + self.cmd = None + self.min = 0 + self.max = 0 + + # Used to collect the bytes after the command byte + # (and the start/end sample number). + self.mb = [] + self.mb_s = -1 + self.mb_e = -1 + + def mosi_bytes(self): + '''Returns the collected MOSI bytes of a multi byte command.''' + return [b[0] for b in self.mb] + + def miso_bytes(self): + '''Returns the collected MISO bytes of a multi byte command.''' + return [b[1] for b in self.mb] + + def decode_command(self, pos, b): + '''Decodes the command byte 'b' at position 'pos' and prepares + the decoding of the following data bytes.''' + c = self.parse_command(b) + if c is None: + self.warn(pos, 'unknown command') + return + + self.cmd, self.dat, self.min, self.max = c + + if self.cmd in ('W_REGISTER', 'ACTIVATE', 'RST_FSPI'): + # Don't output anything now, the command is merged with + # the data bytes following it. + self.mb_s = pos[0] + else: + self.putp(pos, self.ann_cmd, self.format_command()) + + def format_command(self): + '''Returns the label for the current command.''' + if self.cmd == 'R_REGISTER': + reg = regs[self.dat][0] if self.dat in regs else 'unknown register' + return 'Cmd R_REGISTER "{}"'.format(reg) + else: + return 'Cmd {}'.format(self.cmd) + + def parse_command(self, b): + '''Parses the command byte. + + Returns a tuple consisting of: + - the name of the command + - additional data needed to dissect the following bytes + - minimum number of following bytes + - maximum number of following bytes + ''' + buflen = 32 + if self.options['chip'] == 'xn297': + buglen = 64 + if (b & 0xe0) in (0b00000000, 0b00100000): + c = 'R_REGISTER' if not (b & 0xe0) else 'W_REGISTER' + d = b & 0x1f + m = regs[d][1] if d in regs else 1 + return (c, d, 1, m) + if b == 0b01010000: + # nRF24L01 only + return ('ACTIVATE', None, 1, 1) + if b == 0b01100001: + return ('R_RX_PAYLOAD', None, 1, buflen) + if b == 0b01100000: + return ('R_RX_PL_WID', None, 1, 1) + if b == 0b10100000: + return ('W_TX_PAYLOAD', None, 1, buflen) + if b == 0b10110000: + return ('W_TX_PAYLOAD_NOACK', None, 1, buflen) + if (b & 0xf8) == 0b10101000: + return ('W_ACK_PAYLOAD', b & 0x07, 1, buflen) + if b == 0b11100001: + return ('FLUSH_TX', None, 0, 0) + if b == 0b11100010: + return ('FLUSH_RX', None, 0, 0) + if b == 0b11100011: + return ('REUSE_TX_PL', None, 0, 0) + if b == 0b11111111: + return ('NOP', None, 0, 0) + + if self.options['chip'] == 'xn297': + if b == 0b11111101: + return ('CE_FSPI_ON', None, 1, 1) + if b == 0b11111100: + return ('CE_FSPI_OFF', None, 1, 1) + if b == 0b01010011: + return ('RST_FSPI', None, 1, 1) + + def decode_register(self, pos, ann, regid, data): + '''Decodes a register. + + pos -- start and end sample numbers of the register + ann -- is the annotation number that is used to output the register. + regid -- may be either an integer used as a key for the 'regs' + dictionary, or a string directly containing a register name.' + data -- is the register content. + ''' + + if type(regid) == int: + # Get the name of the register. + if regid not in regs: + self.warn(pos, 'unknown register') + return + name = regs[regid][0] + else: + name = regid + + # Multi byte register come LSByte first. + data = reversed(data) + + if self.cmd == 'W_REGISTER' and ann == self.ann_cmd: + # The 'W_REGISTER' command is merged with the following byte(s). + label = '{}: {}'.format(self.format_command(), name) + else: + label = 'Reg {}'.format(name) + + self.decode_mb_data(pos, ann, data, label, True) + + def decode_mb_data(self, pos, ann, data, label, always_hex): + '''Decodes the data bytes 'data' of a multibyte command at position + 'pos'. The decoded data is prefixed with 'label'. If 'always_hex' is + True, all bytes are decoded as hex codes, otherwise only non + printable characters are escaped.''' + + if always_hex: + def escape(b): + return '{:02X}'.format(b) + else: + def escape(b): + c = chr(b) + if not str.isprintable(c): + return '\\x{:02X}'.format(b) + return c + + data = ''.join([escape(b) for b in data]) + text = '{} = "{}"'.format(label, data.strip()) + self.putp(pos, ann, text) + + def finish_command(self, pos): + '''Decodes the remaining data bytes at position 'pos'.''' + + always_hex = self.options['hex_display'] == 'yes' + if self.cmd == 'R_REGISTER': + self.decode_register(pos, self.ann_reg, + self.dat, self.miso_bytes()) + elif self.cmd == 'W_REGISTER': + self.decode_register(pos, self.ann_cmd, + self.dat, self.mosi_bytes()) + elif self.cmd == 'R_RX_PAYLOAD': + self.decode_mb_data(pos, self.ann_rx, + self.miso_bytes(), 'RX payload', always_hex) + elif (self.cmd == 'W_TX_PAYLOAD' or + self.cmd == 'W_TX_PAYLOAD_NOACK'): + self.decode_mb_data(pos, self.ann_tx, + self.mosi_bytes(), 'TX payload', always_hex) + elif self.cmd == 'W_ACK_PAYLOAD': + lbl = 'ACK payload for pipe {}'.format(self.dat) + self.decode_mb_data(pos, self.ann_tx, + self.mosi_bytes(), lbl, always_hex) + elif self.cmd == 'R_RX_PL_WID': + msg = 'Payload width = {}'.format(self.mb[0][1]) + self.putp(pos, self.ann_reg, msg) + elif self.cmd == 'ACTIVATE': + if self.mosi_bytes()[0] == 0x8c: + self.cmd = 'DEACTIVATE' + elif self.mosi_bytes()[0] != 0x73: + self.warn(pos, 'wrong data for "ACTIVATE" command') + self.putp(pos, self.ann_cmd, self.format_command()) + elif self.cmd == 'RST_FSPI': + if self.mosi_bytes()[0] == 0x5a: + self.cmd = 'RST_FSPI_HOLD' + elif self.mosi_bytes()[0] == 0xa5: + self.cmd = 'RST_FSPI_RELS' + else: + self.warn(pos, 'wrong data for "RST_FSPI" command') + self.putp(pos, self.ann_cmd, self.format_command()) + + + def decode(self, ss, es, data): + if not self.requirements_met: + return + + ptype, data1, data2 = data + + if ptype == 'TRANSFER': + if self.cmd: + # Check if we got the minimum number of data bytes + # after the command byte. + if len(self.mb) < self.min: + self.warn((ss, ss), 'missing data bytes') + elif self.mb: + self.finish_command((self.mb_s, self.mb_e)) + + self.next() + self.cs_was_released = True + elif ptype == 'CS-CHANGE': + if data1 is None: + if data2 is None: + self.requirements_met = False + raise ChannelError('CS# pin required.') + elif data2 == 1: + self.cs_was_released = True + + if data1 == 0 and data2 == 1: + # Rising edge, the complete command is transmitted, process + # the bytes that were send after the command byte. + if self.cmd: + # Check if we got the minimum number of data bytes + # after the command byte. + if len(self.mb) < self.min: + self.warn((ss, ss), 'missing data bytes') + elif self.mb: + self.finish_command((self.mb_s, self.mb_e)) + + self.next() + self.cs_was_released = True + elif ptype == 'DATA' and self.cs_was_released: + mosi, miso = data1, data2 + pos = (ss, es) + + if miso is None or mosi is None: + self.requirements_met = False + raise ChannelError('Both MISO and MOSI pins required.') + + if self.first: + self.first = False + # First MOSI byte is always the command. + self.decode_command(pos, mosi) + # First MISO byte is always the status register. + self.decode_register(pos, self.ann_reg, 'STATUS', [miso]) + else: + if not self.cmd or len(self.mb) >= self.max: + self.warn(pos, 'excess byte') + else: + # Collect the bytes after the command byte. + if self.mb_s == -1: + self.mb_s = ss + self.mb_e = es + self.mb.append((mosi, miso)) diff --git a/libsigrokdecode4DSL/decoders/nrf905/__init__.py b/libsigrokdecode4DSL/decoders/nrf905/__init__.py new file mode 100644 index 00000000..c6d35abb --- /dev/null +++ b/libsigrokdecode4DSL/decoders/nrf905/__init__.py @@ -0,0 +1,26 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 Jorge Solla Rubiales +## +## 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 +## + +''' +This decoder stacks on top of the 'spi' PD and decodes the Nordic Semiconductor +NRF905 (433/868/915MHz transceiver) command/responses. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/nrf905/pd.py b/libsigrokdecode4DSL/decoders/nrf905/pd.py new file mode 100644 index 00000000..12949fea --- /dev/null +++ b/libsigrokdecode4DSL/decoders/nrf905/pd.py @@ -0,0 +1,301 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 Jorge Solla Rubiales +## +## Permission is hereby granted, free of charge, to any person obtaining a copy +## of this software and associated documentation files (the "Software"), to deal +## in the Software without restriction, including without limitation the rights +## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +## copies of the Software, and to permit persons to whom the Software is +## furnished to do so, subject to the following conditions: +## +## The above copyright notice and this permission notice shall be included in all +## copies or substantial portions of the Software. +## +## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +## SOFTWARE. + +import sigrokdecode as srd +from common.srdhelper import SrdIntEnum + +CFG_REGS = { + 0: [{'name': 'CH_NO', 'stbit': 7, 'nbits': 8}], + 1: [ + {'name': 'AUTO_RETRAN', 'stbit': 5, 'nbits': 1, + 'opts': {0: 'No retransmission', 1: 'Retransmission of data packet'}}, + {'name': 'RX_RED_PWR', 'stbit': 4, 'nbits': 1, + 'opts': {0: 'Normal operation', 1: 'Reduced power'}}, + {'name': 'PA_PWR', 'stbit': 3, 'nbits': 2, + 'opts': {0: '-10 dBm', 1: '-2 dBm', 2: '+6 dBm', 3: '+10 dBm'}}, + {'name': 'HFREQ_PLL', 'stbit': 1, 'nbits': 1, + 'opts': {0: '433 MHz', 1: '868 / 915 MHz'}}, + {'name': 'CH_NO_8', 'stbit': 0, 'nbits': 1}, + ], + 2: [ + {'name': 'TX_AFW (TX addr width)', 'stbit': 6, 'nbits': 3}, + {'name': 'RX_AFW (RX addr width)', 'stbit': 2, 'nbits': 3}, + ], + 3: [{'name': 'RW_PW (RX payload width)', 'stbit': 5, 'nbits': 6}], + 4: [{'name': 'TX_PW (TX payload width)', 'stbit': 5, 'nbits': 6}], + 5: [{'name': 'RX_ADDR_0', 'stbit': 7, 'nbits': 8}], + 6: [{'name': 'RX_ADDR_1', 'stbit': 7, 'nbits': 8}], + 7: [{'name': 'RX_ADDR_2', 'stbit': 7, 'nbits': 8}], + 8: [{'name': 'RX_ADDR_3', 'stbit': 7, 'nbits': 8}], + 9: [ + {'name': 'CRC_MODE', 'stbit': 7, 'nbits': 1, + 'opts': {0: '8 CRC check bit', 1: '16 CRC check bit'}}, + {'name': 'CRC_EN', 'stbit': 6, 'nbits': 1, + 'opts': {0: 'Disabled', 1: 'Enabled'}}, + {'name': 'XOR', 'stbit': 5, 'nbits': 3, + 'opts': {0: '4 MHz', 1: '8 MHz', 2: '12 MHz', + 3: '16 MHz', 4: '20 MHz'}}, + {'name': 'UP_CLK_EN', 'stbit': 2, 'nbits': 1, + 'opts': {0: 'No external clock signal avail.', + 1: 'External clock signal enabled'}}, + {'name': 'UP_CLK_FREQ', 'stbit': 1, 'nbits': 2, + 'opts': {0: '4 MHz', 1: '2 MHz', 2: '1 MHz', 3: '500 kHz'}}, + ], +} + +CHN_CFG = [ + {'name': 'PA_PWR', 'stbit': 3, 'nbits': 2, + 'opts': {0: '-10 dBm', 1: '-2 dBm', 2: '+6 dBm', 3: '+10 dBm'}}, + {'name': 'HFREQ_PLL', 'stbit': 1, 'nbits': 1, + 'opts': {0: '433 MHz', 1: '868 / 915 MHz'}}, +] + +STAT_REG = [ + {'name': 'AM', 'stbit': 7, 'nbits': 1}, + {'name': 'DR', 'stbit': 5, 'nbits': 1}, +] + +Ann = SrdIntEnum.from_str('Ann', 'CMD REG_WR REG_RD TX RX RESP WARN') + +class Decoder(srd.Decoder): + api_version = 3 + id = 'nrf905' + name = 'nRF905' + longname = 'Nordic Semiconductor nRF905' + desc = '433/868/933MHz transceiver chip.' + license = 'mit' + inputs = ['spi'] + outputs = [] + tags = ['IC', 'Wireless/RF'] + annotations = ( + ('cmd', 'Command sent to the device'), + ('reg-write', 'Config register written to the device'), + ('reg-read', 'Config register read from the device'), + ('tx-data', 'Payload sent to the device'), + ('rx-data', 'Payload read from the device'), + ('resp', 'Response to commands received from the device'), + ('warning', 'Warning'), + ) + annotation_rows = ( + ('commands', 'Commands', (Ann.CMD,)), + ('responses', 'Responses', (Ann.RESP,)), + ('registers', 'Registers', (Ann.REG_WR, Ann.REG_RD)), + ('tx', 'Transmitted data', (Ann.TX,)), + ('rx', 'Received data', (Ann.RX,)), + ('warnings', 'Warnings', (Ann.WARN,)), + ) + + def __init__(self): + self.ss_cmd, self.es_cmd = 0, 0 + self.cs_asserted = False + self.reset() + + def reset(self): + self.mosi_bytes, self.miso_bytes = [], [] + self.cmd_samples = {'ss': 0, 'es': 0} + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def extract_bits(self, byte, start_bit, num_bits): + begin = 7 - start_bit + end = begin + num_bits + if begin < 0 or end > 8: + return 0 + binary = format(byte, '08b')[begin:end] + return int(binary, 2) + + def extract_vars(self, reg_vars, reg_value): + # Iterate all vars on current register. + data = '' + for var in reg_vars: + var_value = self.extract_bits(reg_value, var['stbit'], var['nbits']) + data += var['name'] + ' = ' + str(var_value) + opt = '' + + # If var has options, just add the option meaning. + if 'opts' in var: + opt = var['opts'].get(var_value, 'unknown') + data += ' (' + opt + ')' + + # Add var separator. + if reg_vars.index(var) != len(reg_vars) - 1: + data += ' | ' + return data + + def parse_config_register(self, addr, value, is_write): + reg_value = value[0] + data = 'CFG_REG[' + hex(addr) + '] -> ' + + # Get register vars for this register. + if addr in CFG_REGS: + reg_vars = CFG_REGS[addr] + else: + # Invalid register address. + self.put(value[1], value[2], + self.out_ann, [Ann.WARN, ['Invalid reg. addr']]) + return + + data += self.extract_vars(reg_vars, reg_value) + + ann = Ann.REG_WR if is_write else Ann.REG_RD + self.put(value[1], value[2], self.out_ann, [ann, [data]]) + + def parse_config_registers(self, addr, registers, is_write): + i = 0 + while i < len(registers): + reg_addr = i + addr + if reg_addr <= 9: + self.parse_config_register(reg_addr, registers[i], is_write) + i += 1 + + def dump_cmd_bytes(self, prefix, cmd_bytes, ann): + ss, es = cmd_bytes[1][1], 0 + data = '' + for byte in cmd_bytes[1:]: + data += format(byte[0], '02X') + ' ' + es = byte[2] + self.put(ss, es, self.out_ann, [ann, [prefix + data]]) + + def handle_WC(self): + start_addr = self.mosi_bytes[0][0] & 0x0F + if start_addr > 9: + return + self.parse_config_registers(start_addr, self.mosi_bytes[1:], True) + + def handle_RC(self): + start_addr = self.mosi_bytes[0][0] & 0x0F + if start_addr > 9: + return + self.parse_config_registers(start_addr, self.miso_bytes[1:], False) + + def handle_WTP(self): + self.dump_cmd_bytes('Write TX payload.: ', self.mosi_bytes, Ann.TX) + + def handle_RTP(self): + self.dump_cmd_bytes('Read TX payload: ', self.miso_bytes, Ann.RESP) + + def handle_WTA(self): + self.dump_cmd_bytes('Write TX addr: ', self.mosi_bytes, Ann.REG_WR) + + def handle_RTA(self): + self.dump_cmd_bytes('Read TX addr: ', self.miso_bytes, Ann.RESP) + + def handle_RRP(self): + self.dump_cmd_bytes('Read RX payload: ', self.miso_bytes, Ann.RX) + + def handle_CC(self): + cmd, dta = self.mosi_bytes[0], self.mosi_bytes[1] + channel = ((cmd[0] & 0x01) << 8) + dta + data = self.extract_vars(CHN_CFG, cmd[0]) + data += '| CHN = ' + str(channel) + self.put(self.mosi_bytes[0][1], self.mosi_bytes[1][2], + self.out_ann, [Ann.REG_WR, [data]]) + + def handle_STAT(self): + status = 'STAT = ' + self.extract_vars(STAT_REG, self.miso_bytes[0][0]) + self.put(self.miso_bytes[0][1], self.miso_bytes[0][2], + self.out_ann, [Ann.REG_RD, [status]]) + + def process_cmd(self): + cmd, cmd_name, cmd_hnd = '', '', None + + for byte in self.mosi_bytes: + cmd += hex(byte[0]) + ' ' + + cmd = self.mosi_bytes[0][0] + + if (cmd & 0xF0) == 0x00: + cmd_name, cmd_hnd = 'CMD: W_CONFIG (WC)', self.handle_WC + elif (cmd & 0xF0) == 0x10: + cmd_name, cmd_hnd = 'CMD: R_CONFIG (RC)', self.handle_RC + elif cmd == 0x20: + cmd_name, cmd_hnd = 'CMD: W_TX_PAYLOAD (WTP)', self.handle_WTP + elif cmd == 0x21: + cmd_name, cmd_hnd = 'CMD: R_TX_PAYLOAD (RTP)', self.handle_RTP + elif cmd == 0x22: + cmd_name, cmd_hnd = 'CMD: W_TX_ADDRESS (WTA)', self.handle_WTA + elif cmd == 0x23: + cmd_name, cmd_hnd = 'CMD: R_TX_ADDRESS (RTA)', self.handle_RTA + elif cmd == 0x24: + cmd_name, cmd_hnd = 'CMD: R_RX_PAYLOAD (RRP)', self.handle_RRP + elif (cmd & 0xF0 == 0x80): + cmd_name, cmd_hnd = 'CMD: CHANNEL_CONFIG (CC)', self.handle_CC + + # Report command name. + self.put(self.cmd_samples['ss'], self.cmd_samples['es'], + self.out_ann, [Ann.CMD, [cmd_name]]) + + # Handle status byte. + self.handle_STAT() + + # Handle command. + if cmd_hnd is not None: + cmd_hnd() + + def set_cs_status(self, sample, asserted): + if self.cs_asserted == asserted: + return + + if asserted: + self.cmd_samples['ss'] = sample + self.cmd_samples['es'] = -1 + else: + self.cmd_samples['es'] = sample + + self.cs_asserted = asserted + + def decode(self, ss, es, data): + ptype, data1, data2 = data + + if ptype == 'CS-CHANGE': + if data1 is None and data2 is None: + self.requirements_met = False + raise ChannelError('CS# pin required.') + + if data1 is None and data2 == 0: + self.set_cs_status(ss, True) + + elif data1 is None and data2 == 1: + self.set_cs_status(ss, False) + + elif data1 == 1 and data2 == 0: + self.set_cs_status(ss, True) + + elif data1 == 0 and data2 == 1: + self.set_cs_status(ss, False) + if len(self.mosi_bytes): + self.process_cmd() + self.reset() + + elif ptype == 'DATA': + # Ignore traffic if CS is not asserted. + if self.cs_asserted is False: + return + + mosi, miso = data1, data2 + if miso is None or mosi is None: + raise ChannelError('Both MISO and MOSI pins required.') + + self.mosi_bytes.append((mosi, ss, es)) + self.miso_bytes.append((miso, ss, es)) diff --git a/libsigrokdecode4DSL/decoders/numbers_and_state/__init__.py b/libsigrokdecode4DSL/decoders/numbers_and_state/__init__.py new file mode 100644 index 00000000..4fe42a34 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/numbers_and_state/__init__.py @@ -0,0 +1,41 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Comlab AG +## Copyright (C) 2020 Gerhard Sittig +## +## 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, see . +## + +''' +This protocol decoder takes a set of logic input signals, and interprets +their bit pattern according to user specifications as different kinds of +numbers, or an enumeration of e.g. machine states. + +Supported formats are: signed and unsigned integers, fixed point numbers, +IEEE754 floating point numbers, and number to text mapping controlled by +external data files. (Support for half precision floats depends on the +Python runtime, and may not universally be available.) + +User provided text mapping files can either use the JSON format: + {"one": 1, "two": 2, "four": 4} +or the Python programming language: + enumtext = { 1: "one", 2: "two", 3: "three", } + +In addition to all enum values on one row (sequential presentation of +the data), a limited number of enum values also are shown in tabular +presentation, which can help visualize state machines or task switches. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/numbers_and_state/pd.py b/libsigrokdecode4DSL/decoders/numbers_and_state/pd.py new file mode 100644 index 00000000..b8ac87e7 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/numbers_and_state/pd.py @@ -0,0 +1,377 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Comlab AG +## Copyright (C) 2020 Gerhard Sittig +## +## 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, see . +## + +# This implementation started as a "vector slicer", then turned into the +# "numbers and states" decoder, because users always had the freedom to +# connect any logic signal to either of the decoder inputs. That's when +# slicing vectors took second seat, and just was not needed any longer +# in the strict sense. +# +# TODO +# - Find an appropriate number of input channels, and maximum enum slots. +# - Re-check correctness of signed integers. Signed fixed point is based +# on integers and transparently benefits from fixes and improvements. +# - Local formatting in individual decoders becomes obsolete when common +# support for user selected formatting gets introduced. +# - There is overlap with the 'parallel' decoder. Ideally the numbers +# decoder could stack on top of parallel, but parallel currently is +# severely limited in its number of input channels, and dramatically +# widening the parallel decoder may be undesirable. + +from common.srdhelper import bitpack +import json +import sigrokdecode as srd +import struct + +''' +OUTPUT_PYTHON format: + +Packet: +[, ] + +This is a list of s and their respective values: + - 'RAW': The data is a tuple of bit count and bit pattern (a number, + assuming unsigned integer presentation of the input data bit pattern). + - 'NUMBER': The data is the conversion result of the bit pattern. + - 'ENUM': The data is a tuple of the raw number and its mapped text. +''' + +# TODO Better raise the number of channels to 32. This allows access to +# IEEE754 single precision numbers, and shall cover most busses, _and_ +# remains within most logic analyzers' capabilities, and keeps the UI +# dialog somewhat managable. What's a good default for the number of +# enum slots (which translate to annotation rows)? Notice that 2 to the +# power of the channel count is way out of the question. :) +_max_channels = 16 +_max_enum_slots = 32 + +class ChannelError(Exception): + pass + +class Pin: + CLK, BIT_0 = range(2) + BIT_N = BIT_0 + _max_channels + +class Ann: + RAW, NUM = range(2) + ENUM_0 = NUM + 1 + ENUM_OVR = ENUM_0 + _max_enum_slots + ENUMS = range(ENUM_0, ENUM_OVR) + WARN = ENUM_OVR + 1 + + @staticmethod + def enum_indices(): + return [i for i in range(Ann.ENUMS)] + + @staticmethod + def get_enum_idx(code): + if code in range(_max_enum_slots): + return Ann.ENUM_0 + code + return Ann.ENUM_OVR + +def _channel_decl(count): + return tuple([ + {'id': 'bit{}'.format(i), 'name': 'Bit{}'.format(i), 'desc': 'Bit position {}'.format(i)} + for i in range(count) + ]) + +def _enum_cls_decl(count): + return tuple([ + ('enum{}'.format(i), 'Enumeration slot {}'.format(i)) + for i in range(count) + ] + [('enumovr', 'Enumeration overflow')]) + +def _enum_rows_decl(count): + return tuple([ + ('enums{}'.format(i), 'Enumeration slots {}'.format(i), (Ann.ENUM_0 + i,)) + for i in range(count) + ] + [('enumsovr', 'Enumeration overflows', (Ann.ENUM_OVR,))]) + +class Decoder(srd.Decoder): + api_version = 3 + id = 'numbers_and_state' + name = 'Numbers and State' + longname = 'Interpret bit patters as numbers or state enums' + desc = 'Interpret bit patterns as different kinds of numbers (integer, float, enum).' + license = 'gplv2+' + inputs = ['logic'] + outputs = ['numbers_and_state'] + tags = ['Encoding', 'Util'] + optional_channels = ( + {'id': 'clk', 'name': 'Clock', 'desc': 'Clock'}, + ) + _channel_decl(_max_channels) + options = ( + {'id': 'clkedge', 'desc': 'Clock edge', 'default': 'rising', + 'values': ('rising', 'falling', 'either')}, + {'id': 'count', 'desc': 'Total bits count', 'default': 0}, + {'id': 'interp', 'desc': 'Interpretation', 'default': 'unsigned', + 'values': ('unsigned', 'signed', 'fixpoint', 'fixsigned', 'ieee754', 'enum')}, + {'id': 'fracbits', 'desc': 'Fraction bits count', 'default': 0}, + {'id': 'mapping', 'desc': 'Enum to text map file', + 'default': 'enumtext.json'}, + {'id': 'format', 'desc': 'Number format', 'default': '-', + 'values': ('-', 'bin', 'oct', 'dec', 'hex')}, + ) + annotations = ( + ('raw', 'Raw pattern'), + ('number', 'Number'), + ) + _enum_cls_decl(_max_enum_slots) + ( + ('warning', 'Warning'), + ) + annotation_rows = ( + ('raws', 'Raw bits', (Ann.RAW,)), + ('numbers', 'Numbers', (Ann.NUM,)), + ) + _enum_rows_decl(_max_enum_slots) + ( + ('warnings', 'Warnings', (Ann.WARN,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + pass + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_python = self.register(srd.OUTPUT_PYTHON) + + def putg(self, ss, es, cls, data): + self.put(ss, es, self.out_ann, [cls, data]) + + def putpy(self, ss, es, ptype, pdata): + self.put(ss, es, self.out_python, (ptype, pdata)) + + def grab_pattern(self, pins): + '''Get a bit pattern from potentially incomplete probes' values.''' + + # Pad and trim the input data, to achieve the user specified + # total number of bits. Map all unassigned signals to 0 (low). + # Return raw number (unsigned integer interpreation). + bits = pins + (None,) * self.bitcount + bits = bits[:self.bitcount] + bits = [b if b in (0, 1) else 0 for b in bits] + pattern = bitpack(bits) + return pattern + + def handle_pattern(self, ss, es, pattern): + fmt = '{{:0{}b}}'.format(self.bitcount) + txt = fmt.format(pattern) + self.putg(ss, es, Ann.RAW, [txt]) + self.putpy(ss, es, 'RAW', (self.bitcount, pattern)) + + try: + value = self.interpreter(ss, es, pattern) + except: + value = None + if value is None: + return + self.putpy(ss, es, 'NUMBER', value) + try: + formatted = self.formatter(ss, es, value) + except: + formatted = None + if formatted: + self.putg(ss, es, Ann.NUM, formatted) + if self.interpreter == self.interp_enum: + cls = Ann.get_enum_idx(pattern) + self.putg(ss, es, cls, formatted) + self.putpy(ss, es, 'ENUM', (value, formatted)) + + def interp_unsigned(self, ss, es, pattern): + value = pattern + return value + + def interp_signed(self, ss, es, pattern): + if not 'signmask' in self.interp_state: + self.interp_state.update({ + 'signmask': 1 << (self.bitcount - 1), + 'signfull': 1 << self.bitcount, + }) + is_neg = pattern & self.interp_state['signmask'] + if is_neg: + value = -(self.interp_state['signfull'] - pattern) + else: + value = pattern + return value + + def interp_fixpoint(self, ss, es, pattern): + if not 'fixdiv' in self.interp_state: + self.interp_state.update({ + 'fixsign': self.options['interp'] == 'fixsigned', + 'fixdiv': 2 ** self.options['fracbits'], + }) + if self.interp_state['fixsign']: + value = self.interp_signed(ss, es, pattern) + else: + value = self.interp_unsigned(ss, es, pattern) + value /= self.interp_state['fixdiv'] + return value + + def interp_ieee754(self, ss, es, pattern): + if not 'ieee_has_16bit' in self.interp_state: + self.interp_state.update({ + 'ieee_fmt_int_16': '=H', + 'ieee_fmt_flt_16': '=e', + 'ieee_fmt_int_32': '=L', + 'ieee_fmt_flt_32': '=f', + 'ieee_fmt_int_64': '=Q', + 'ieee_fmt_flt_64': '=d', + }) + try: + fmt = self.interp_state.update['ieee_fmt_flt_16'] + has_16bit_support = 8 * struct.calcsize(fmt) == 16 + except: + has_16bit_support = False + self.interp_state['ieee_has_16bit'] = has_16bit_support + if self.bitcount == 16: + if not self.interp_state['ieee_has_16bit']: + return None + buff = struct.pack(self.interp_state['ieee_fmt_int_16'], pattern) + value, = struct.unpack(self.interp_state['ieee_fmt_flt_16'], buff) + return value + if self.bitcount == 32: + buff = struct.pack(self.interp_state['ieee_fmt_int_32'], pattern) + value, = struct.unpack(self.interp_state['ieee_fmt_flt_32'], buff) + return value + if self.bitcount == 64: + buff = struct.pack(self.interp_state['ieee_fmt_int_64'], pattern) + value, = struct.unpack(self.interp_state['ieee_fmt_flt_64'], buff) + return value + return None + + def interp_enum(self, ss, es, pattern): + if not 'enum_map' in self.interp_state: + self.interp_state.update({ + 'enum_fn': self.options['mapping'], + 'enum_map': {}, + 'enum_have_map': False, + }) + try: + fn = self.interp_state['enum_fn'] + # TODO Optionally try in several locations? Next to the + # decoder implementation? Where else? Expect users to + # enter absolute paths? + with open(fn, 'r') as f: + maptext = f.read() + maptable = {} + if fn.endswith('.js') or fn.endswith('.json'): + # JSON requires string literals on the LHS, so the + # table is written "in reverse order". + js_table = json.loads(maptext) + for k, v in js_table.items(): + maptable[v] = k + elif fn.endswith('.py'): + # Expect a specific identifier at the Python module + # level, and assume that it's a dictionary. + py_table = {} + exec(maptext, py_table) + maptable.update(py_table['enumtext']) + self.interp_state['enum_map'].update(maptable) + self.interp_state['enum_have_map'] = True + except: + # Silently ignore failure. This happens while the user + # is typing the filename, and is non-fatal. If the file + # exists and is not readable or not valid or of unknown + # format, the worst thing that can happen is that the + # decoder implementation keeps using "anonymous" phrases + # until a mapping has become available. No harm is done. + # This decoder cannot tell intermediate from final file + # read attempts, so we cannot raise severity here. + pass + value = self.interp_state['enum_map'].get(pattern, None) + if value is None: + value = pattern + return value + + def format_native(self, ss, es, value): + return ['{}'.format(value),] + + def format_bin(self, ss, es, value): + if not self.format_string: + self.format_string = '{{:0{}b}}'.format(self.bitcount) + return [self.format_string.format(value)] + + def format_oct(self, ss, es, value): + if not self.format_string: + self.format_string = '{{:0{}o}}'.format((self.bitcount + 3 - 1) // 3) + return [self.format_string.format(value)] + + def format_dec(self, ss, es, value): + if not self.format_string: + self.format_string = '{:d}' + return [self.format_string.format(value)] + + def format_hex(self, ss, es, value): + if not self.format_string: + self.format_string = '{{:0{}x}}'.format((self.bitcount + 4 - 1) // 4) + return [self.format_string.format(value)] + + def decode(self): + channels = [ch for ch in range(_max_channels) if self.has_channel(ch)] + have_clk = Pin.CLK in channels + if have_clk: + channels.remove(Pin.CLK) + if not channels: + raise ChannelError("Need at least one bit channel.") + if have_clk: + clkedge = { + 'rising': 'r', + 'falling': 'f', + 'either': 'e', + }.get(self.options['clkedge']) + wait_cond = {Pin.CLK: clkedge} + else: + wait_cond = [{ch: 'e'} for ch in channels] + + bitcount = self.options['count'] + if not bitcount: + bitcount = channels[-1] - Pin.BIT_0 + 1 + self.bitcount = bitcount + + self.interpreter = { + 'unsigned': self.interp_unsigned, + 'signed': self.interp_signed, + 'fixpoint': self.interp_fixpoint, + 'fixsigned': self.interp_fixpoint, + 'ieee754': self.interp_ieee754, + 'enum': self.interp_enum, + }.get(self.options['interp']) + self.interp_state = {} + self.formatter = { + '-': self.format_native, + 'bin': self.format_bin, + 'oct': self.format_oct, + 'dec': self.format_dec, + 'hex': self.format_hex, + }.get(self.options['format']) + self.format_string = None + + pins = self.wait() + ss = self.samplenum + prev_pattern = self.grab_pattern(pins[Pin.BIT_0:]) + while True: + pins = self.wait(wait_cond) + es = self.samplenum + pattern = self.grab_pattern(pins[Pin.BIT_0:]) + if pattern == prev_pattern: + continue + self.handle_pattern(ss, es, prev_pattern) + ss = es + prev_pattern = pattern diff --git a/libsigrokdecode4DSL/decoders/nunchuk/__init__.py b/libsigrokdecode4DSL/decoders/nunchuk/__init__.py new file mode 100644 index 00000000..a6092c45 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/nunchuk/__init__.py @@ -0,0 +1,30 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +''' +This decoder stacks on top of the 'i2c' PD and decodes the Nintendo Wii +Nunchuk controller protocol. + +Details: +http://wiibrew.org/wiki/Wiimote/Extension_Controllers/Nunchuck +http://todbot.com/blog/2008/02/18/wiichuck-wii-nunchuck-adapter-available/ +https://www.sparkfun.com/products/9281 +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/nunchuk/pd.py b/libsigrokdecode4DSL/decoders/nunchuk/pd.py new file mode 100644 index 00000000..59b10289 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/nunchuk/pd.py @@ -0,0 +1,207 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2010-2014 Uwe Hermann +## +## 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, see . +## + +import sigrokdecode as srd + +class Decoder(srd.Decoder): + api_version = 3 + id = 'nunchuk' + name = 'Nunchuk' + longname = 'Nintendo Wii Nunchuk' + desc = 'Nintendo Wii Nunchuk controller protocol.' + license = 'gplv2+' + inputs = ['i2c'] + outputs = [] + tags = ['Sensor'] + annotations = \ + tuple(('reg-0x%02X' % i, 'Register 0x%02X' % i) for i in range(6)) + ( + ('bit-bz', 'BZ bit'), + ('bit-bc', 'BC bit'), + ('bit-ax', 'AX bits'), + ('bit-ay', 'AY bits'), + ('bit-az', 'AZ bits'), + ('nunchuk-write', 'Nunchuk write'), + ('cmd-init', 'Init command'), + ('summary', 'Summary'), + ('warnings', 'Warnings'), + ) + annotation_rows = ( + ('regs', 'Registers', tuple(range(13))), + ('summary', 'Summary', (13,)), + ('warnings', 'Warnings', (14,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.state = 'IDLE' + self.sx = self.sy = self.ax = self.ay = self.az = self.bz = self.bc = -1 + self.databytecount = 0 + self.reg = 0x00 + self.ss = self.es = self.ss_block = self.es_block = 0 + self.init_seq = [] + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + self.put(self.ss, self.es, self.out_ann, data) + + def putb(self, data): + self.put(self.ss_block, self.es_block, self.out_ann, data) + + def putd(self, bit1, bit2, data): + self.put(self.bits[bit1][1], self.bits[bit2][2], self.out_ann, data) + + def handle_reg_0x00(self, databyte): + self.ss_block = self.ss + self.sx = databyte + self.putx([0, ['Analog stick X position: 0x%02X' % self.sx, + 'SX: 0x%02X' % self.sx]]) + + def handle_reg_0x01(self, databyte): + self.sy = databyte + self.putx([1, ['Analog stick Y position: 0x%02X' % self.sy, + 'SY: 0x%02X' % self.sy]]) + + def handle_reg_0x02(self, databyte): + self.ax = databyte << 2 + self.putx([2, ['Accelerometer X value bits[9:2]: 0x%03X' % self.ax, + 'AX[9:2]: 0x%03X' % self.ax]]) + + def handle_reg_0x03(self, databyte): + self.ay = databyte << 2 + self.putx([3, ['Accelerometer Y value bits[9:2]: 0x%03X' % self.ay, + 'AY[9:2]: 0x%03X' % self.ay]]) + + def handle_reg_0x04(self, databyte): + self.az = databyte << 2 + self.putx([4, ['Accelerometer Z value bits[9:2]: 0x%03X' % self.az, + 'AZ[9:2]: 0x%03X' % self.az]]) + + def handle_reg_0x05(self, databyte): + self.es_block = self.es + self.bz = (databyte & (1 << 0)) >> 0 # Bits[0:0] + self.bc = (databyte & (1 << 1)) >> 1 # Bits[1:1] + ax_rest = (databyte & (3 << 2)) >> 2 # Bits[3:2] + ay_rest = (databyte & (3 << 4)) >> 4 # Bits[5:4] + az_rest = (databyte & (3 << 6)) >> 6 # Bits[7:6] + self.ax |= ax_rest + self.ay |= ay_rest + self.az |= az_rest + + # self.putx([5, ['Register 5', 'Reg 5', 'R5']]) + + s = '' if (self.bz == 0) else 'not ' + self.putd(0, 0, [6, ['Z: %spressed' % s, 'BZ: %d' % self.bz]]) + + s = '' if (self.bc == 0) else 'not ' + self.putd(1, 1, [7, ['C: %spressed' % s, 'BC: %d' % self.bc]]) + + self.putd(3, 2, [8, ['Accelerometer X value bits[1:0]: 0x%X' % ax_rest, + 'AX[1:0]: 0x%X' % ax_rest]]) + + self.putd(5, 4, [9, ['Accelerometer Y value bits[1:0]: 0x%X' % ay_rest, + 'AY[1:0]: 0x%X' % ay_rest]]) + + self.putd(7, 6, [10, ['Accelerometer Z value bits[1:0]: 0x%X' % az_rest, + 'AZ[1:0]: 0x%X' % az_rest]]) + + self.reg = 0x00 + + def output_full_block_if_possible(self): + # For now, only output summary annotations if all values are available. + t = (self.sx, self.sy, self.ax, self.ay, self.az, self.bz, self.bc) + if -1 in t: + return + bz = 'pressed' if self.bz == 0 else 'not pressed' + bc = 'pressed' if self.bc == 0 else 'not pressed' + s = 'Analog stick: %d/%d, accelerometer: %d/%d/%d, Z: %s, C: %s' % \ + (self.sx, self.sy, self.ax, self.ay, self.az, bz, bc) + self.putb([13, [s]]) + + def handle_reg_write(self, databyte): + self.putx([11, ['Nunchuk write: 0x%02X' % databyte]]) + if len(self.init_seq) < 2: + self.init_seq.append(databyte) + + def output_init_seq(self): + if len(self.init_seq) != 2: + self.putb([14, ['Init sequence was %d bytes long (2 expected)' % \ + len(self.init_seq)]]) + return + + if self.init_seq != [0x40, 0x00]: + self.putb([14, ['Unknown init sequence (expected: 0x40 0x00)']]) + return + + # TODO: Detect Nunchuk clones (they have different init sequences). + + self.putb([12, ['Initialize Nunchuk', 'Init Nunchuk', 'Init', 'I']]) + + def decode(self, ss, es, data): + cmd, databyte = data + + # Collect the 'BITS' packet, then return. The next packet is + # guaranteed to belong to these bits we just stored. + if cmd == 'BITS': + self.bits = databyte + return + + self.ss, self.es = ss, es + + # State machine. + if self.state == 'IDLE': + # Wait for an I²C START condition. + if cmd != 'START': + return + self.state = 'GET SLAVE ADDR' + self.ss_block = ss + elif self.state == 'GET SLAVE ADDR': + # Wait for an address read/write operation. + if cmd == 'ADDRESS READ': + self.state = 'READ REGS' + elif cmd == 'ADDRESS WRITE': + self.state = 'WRITE REGS' + elif self.state == 'READ REGS': + if cmd == 'DATA READ': + handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg) + handle_reg(databyte) + self.reg += 1 + elif cmd == 'STOP': + self.es_block = es + self.output_full_block_if_possible() + self.sx = self.sy = self.ax = self.ay = self.az = -1 + self.bz = self.bc = -1 + self.state = 'IDLE' + else: + # self.putx([14, ['Ignoring: %s (data=%s)' % (cmd, databyte)]]) + pass + elif self.state == 'WRITE REGS': + if cmd == 'DATA WRITE': + self.handle_reg_write(databyte) + elif cmd == 'STOP': + self.es_block = es + self.output_init_seq() + self.init_seq = [] + self.state = 'IDLE' + else: + # self.putx([14, ['Ignoring: %s (data=%s)' % (cmd, databyte)]]) + pass diff --git a/libsigrokdecode4DSL/decoders/onewire_link/__init__.py b/libsigrokdecode4DSL/decoders/onewire_link/__init__.py new file mode 100644 index 00000000..abd55671 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/onewire_link/__init__.py @@ -0,0 +1,56 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## Copyright (C) 2017 Kevin Redon +## +## 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, see . +## + +''' +This protocol decoder handles the 1-Wire link layer. + +The 1-Wire protocol enables bidirectional communication over a single wire +(and ground) between a single master and one or multiple slaves. The protocol +is layered: + + - Link layer (reset, presence detection, reading/writing bits) + - Network layer (skip/search/match device ROM addresses) + - Transport layer (transport data between 1-Wire master and device) + +Sample rate: +A sufficiently high samplerate is required to properly detect all the elements +of the protocol. A lower samplerate can be used if the master does not use +overdrive communication speed. The following minimal values should be used: + + - overdrive available: 2MHz minimum, 5MHz suggested + - overdrive not available: 400kHz minimum, 1MHz suggested + +Channels: +1-Wire requires a single signal, but some master implementations might have a +separate signal used to deliver power to the bus during temperature conversion +as an example. + + - owr (1-Wire signal line) + +Options: +1-Wire is an asynchronous protocol with fixed timing values, so the decoder +must know the samplerate. +Two speeds are available: normal and overdrive. The decoder detects when +switching speed, but the user can set which to start decoding with: + + - overdrive (to decode starting with overdrive speed) +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/onewire_link/pd.py b/libsigrokdecode4DSL/decoders/onewire_link/pd.py new file mode 100644 index 00000000..6592279e --- /dev/null +++ b/libsigrokdecode4DSL/decoders/onewire_link/pd.py @@ -0,0 +1,347 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2017 Kevin Redon +## +## 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, see . +## + +import sigrokdecode as srd + +class SamplerateError(Exception): + pass + +# Timing values in us for the signal at regular and overdrive speed. +timing = { + 'RSTL': { + 'min': { + False: 480.0, + True: 48.0, + }, + 'max': { + False: 960.0, + True: 80.0, + }, + }, + 'RSTH': { + 'min': { + False: 480.0, + True: 48.0, + }, + }, + 'PDH': { + 'min': { + False: 15.0, + True: 2.0, + }, + 'max': { + False: 60.0, + True: 6.0, + }, + }, + 'PDL': { + 'min': { + False: 60.0, + True: 8.0, + }, + 'max': { + False: 240.0, + True: 24.0, + }, + }, + 'SLOT': { + 'min': { + False: 60.0, + True: 6.0, + }, + 'max': { + False: 120.0, + True: 16.0, + }, + }, + 'REC': { + 'min': { + False: 1.0, + True: 1.0, + }, + }, + 'LOWR': { + 'min': { + False: 1.0, + True: 1.0, + }, + 'max': { + False: 15.0, + True: 2.0, + }, + }, +} + +class Decoder(srd.Decoder): + api_version = 3 + id = 'onewire_link' + name = 'OneWire link layer' + longname = '1-Wire serial communication bus (link layer)' + desc = 'Bidirectional, half-duplex, asynchronous serial bus.' + license = 'gplv2+' + inputs = ['logic'] + outputs = ['onewire_link'] + tags = ['Embedded/industrial'] + channels = ( + {'id': 'owr', 'name': 'OWR', 'desc': '1-Wire signal line'}, + ) + options = ( + {'id': 'overdrive', 'desc': 'Start in overdrive speed', + 'default': 'no', 'values': ('yes', 'no')}, + ) + annotations = ( + ('bit', 'Bit'), + ('warnings', 'Warnings'), + ('reset', 'Reset'), + ('presence', 'Presence'), + ('overdrive', 'Overdrive speed notifications'), + ) + annotation_rows = ( + ('bits', 'Bits', (0, 2, 3)), + ('info', 'Info', (4,)), + ('warnings', 'Warnings', (1,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.state = 'INITIAL' + self.present = 0 + self.bit = 0 + self.bit_count = -1 + self.command = 0 + self.overdrive = False + self.fall = 0 + self.rise = 0 + + def start(self): + self.out_python = self.register(srd.OUTPUT_PYTHON) + self.out_ann = self.register(srd.OUTPUT_ANN) + self.overdrive = (self.options['overdrive'] == 'yes') + self.fall = 0 + self.rise = 0 + self.bit_count = -1 + + def putm(self, data): + self.put(0, 0, self.out_ann, data) + + def putpfs(self, data): + self.put(self.fall, self.samplenum, self.out_python, data) + + def putfs(self, data): + self.put(self.fall, self.samplenum, self.out_ann, data) + + def putfr(self, data): + self.put(self.fall, self.rise, self.out_ann, data) + + def putprs(self, data): + self.put(self.rise, self.samplenum, self.out_python, data) + + def putrs(self, data): + self.put(self.rise, self.samplenum, self.out_ann, data) + + def checks(self): + # Check if samplerate is appropriate. + if self.options['overdrive'] == 'yes': + if self.samplerate < 2000000: + self.putm([1, ['Sampling rate is too low. Must be above ' + + '2MHz for proper overdrive mode decoding.']]) + elif self.samplerate < 5000000: + self.putm([1, ['Sampling rate is suggested to be above 5MHz ' + + 'for proper overdrive mode decoding.']]) + else: + if self.samplerate < 400000: + self.putm([1, ['Sampling rate is too low. Must be above ' + + '400kHz for proper normal mode decoding.']]) + elif self.samplerate < 1000000: + self.putm([1, ['Sampling rate is suggested to be above ' + + '1MHz for proper normal mode decoding.']]) + + def metadata(self, key, value): + if key != srd.SRD_CONF_SAMPLERATE: + return + self.samplerate = value + + def wait_falling_timeout(self, start, t): + # Wait until either a falling edge is seen, and/or the specified + # number of samples have been skipped (i.e. time has passed). + cnt = int((t[self.overdrive] / 1000000.0) * self.samplerate) + samples_to_skip = (start + cnt) - self.samplenum + samples_to_skip = samples_to_skip if (samples_to_skip > 0) else 0 + return self.wait([{0: 'f'}, {'skip': samples_to_skip}]) + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + self.checks() + while True: + # State machine. + if self.state == 'INITIAL': # Unknown initial state. + # Wait until we reach the idle high state. + self.wait({0: 'h'}) + self.rise = self.samplenum + self.state = 'IDLE' + elif self.state == 'IDLE': # Idle high state. + # Wait for falling edge. + self.wait({0: 'f'}) + self.fall = self.samplenum + # Get time since last rising edge. + time = ((self.fall - self.rise) / self.samplerate) * 1000000.0 + if self.rise > 0 and \ + time < timing['REC']['min'][self.overdrive]: + self.putfr([1, ['Recovery time not long enough' + 'Recovery too short', + 'REC < ' + str(timing['REC']['min'][self.overdrive])]]) + # A reset pulse or slot can start on a falling edge. + self.state = 'LOW' + # TODO: Check minimum recovery time. + elif self.state == 'LOW': # Reset pulse or slot. + # Wait for rising edge. + self.wait({0: 'r'}) + self.rise = self.samplenum + # Detect reset or slot base on timing. + time = ((self.rise - self.fall) / self.samplerate) * 1000000.0 + if time >= timing['RSTL']['min'][False]: # Normal reset pulse. + if time > timing['RSTL']['max'][False]: + self.putfr([1, ['Too long reset pulse might mask interrupt ' + + 'signalling by other devices', + 'Reset pulse too long', + 'RST > ' + str(timing['RSTL']['max'][False])]]) + # Regular reset pulse clears overdrive speed. + if self.overdrive: + self.putfr([4, ['Exiting overdrive mode', 'Overdrive off']]) + self.overdrive = False + self.putfr([2, ['Reset', 'Rst', 'R']]) + self.state = 'PRESENCE DETECT HIGH' + elif self.overdrive == True and \ + time >= timing['RSTL']['min'][self.overdrive] and \ + time < timing['RSTL']['max'][self.overdrive]: + # Overdrive reset pulse. + self.putfr([2, ['Reset', 'Rst', 'R']]) + self.state = 'PRESENCE DETECT HIGH' + elif time < timing['SLOT']['max'][self.overdrive]: + # Read/write time slot. + if time < timing['LOWR']['min'][self.overdrive]: + self.putfr([1, ['Low signal not long enough', + 'Low too short', + 'LOW < ' + str(timing['LOWR']['min'][self.overdrive])]]) + if time < timing['LOWR']['max'][self.overdrive]: + self.bit = 1 # Short pulse is a 1 bit. + else: + self.bit = 0 # Long pulse is a 0 bit. + # Wait for end of slot. + self.state = 'SLOT' + else: + # Timing outside of known states. + self.putfr([1, ['Erroneous signal', 'Error', 'Err', 'E']]) + self.state = 'IDLE' + elif self.state == 'PRESENCE DETECT HIGH': # Wait for slave presence signal. + # Wait for a falling edge and/or presence detect signal. + self.wait_falling_timeout(self.rise, timing['PDH']['max']) + + # Calculate time since rising edge. + time = ((self.samplenum - self.rise) / self.samplerate) * 1000000.0 + + if (self.matched & (0b1 << 0)) and not (self.matched & (0b1 << 1)): + # Presence detected. + if time < timing['PDH']['min'][self.overdrive]: + self.putrs([1, ['Presence detect signal is too early', + 'Presence detect too early', + 'PDH < ' + str(timing['PDH']['min'][self.overdrive])]]) + self.fall = self.samplenum + self.state = 'PRESENCE DETECT LOW' + else: # No presence detected. + self.putrs([3, ['Presence: false', 'Presence', 'Pres', 'P']]) + self.putprs(['RESET/PRESENCE', False]) + self.state = 'IDLE' + elif self.state == 'PRESENCE DETECT LOW': # Slave presence signalled. + # Wait for end of presence signal (on rising edge). + self.wait({0: 'r'}) + # Calculate time since start of presence signal. + time = ((self.samplenum - self.fall) / self.samplerate) * 1000000.0 + if time < timing['PDL']['min'][self.overdrive]: + self.putfs([1, ['Presence detect signal is too short', + 'Presence detect too short', + 'PDL < ' + str(timing['PDL']['min'][self.overdrive])]]) + elif time > timing['PDL']['max'][self.overdrive]: + self.putfs([1, ['Presence detect signal is too long', + 'Presence detect too long', + 'PDL > ' + str(timing['PDL']['max'][self.overdrive])]]) + if time > timing['RSTH']['min'][self.overdrive]: + self.rise = self.samplenum + # Wait for end of presence detect. + self.state = 'PRESENCE DETECT' + + # End states (for additional checks). + if self.state == 'SLOT': # Wait for end of time slot. + # Wait for a falling edge and/or end of timeslot. + self.wait_falling_timeout(self.fall, timing['SLOT']['min']) + + if (self.matched & (0b1 << 0)) and not (self.matched & (0b1 << 1)): + # Low detected before end of slot. + self.putfs([1, ['Time slot not long enough', + 'Slot too short', + 'SLOT < ' + str(timing['SLOT']['min'][self.overdrive])]]) + # Don't output invalid bit. + self.fall = self.samplenum + self.state = 'LOW' + else: # End of time slot. + # Output bit. + self.putfs([0, ['Bit: %d' % self.bit, '%d' % self.bit]]) + self.putpfs(['BIT', self.bit]) + # Save command bits. + if self.bit_count >= 0: + self.command += (self.bit << self.bit_count) + self.bit_count += 1 + # Check for overdrive ROM command. + if self.bit_count >= 8: + if self.command == 0x3c or self.command == 0x69: + self.overdrive = True + self.put(self.samplenum, self.samplenum, + self.out_ann, + [4, ['Entering overdrive mode', 'Overdrive on']]) + self.bit_count = -1 + self.state = 'IDLE' + + if self.state == 'PRESENCE DETECT': + # Wait for a falling edge and/or end of presence detect. + self.wait_falling_timeout(self.rise, timing['RSTH']['min']) + + if (self.matched & (0b1 << 0)) and not (self.matched & (0b1 << 1)): + # Low detected before end of presence detect. + self.putfs([1, ['Presence detect not long enough', + 'Presence detect too short', + 'RTSH < ' + str(timing['RSTH']['min'][self.overdrive])]]) + # Inform about presence detected. + self.putrs([3, ['Slave presence detected', 'Slave present', + 'Present', 'P']]) + self.putprs(['RESET/PRESENCE', True]) + self.fall = self.samplenum + self.state = 'LOW' + else: # End of time slot. + # Inform about presence detected. + self.putrs([3, ['Presence: true', 'Presence', 'Pres', 'P']]) + self.putprs(['RESET/PRESENCE', True]) + self.rise = self.samplenum + # Start counting the first 8 bits to get the ROM command. + self.bit_count = 0 + self.command = 0 + self.state = 'IDLE' diff --git a/libsigrokdecode4DSL/decoders/onewire_network/__init__.py b/libsigrokdecode4DSL/decoders/onewire_network/__init__.py new file mode 100644 index 00000000..60907efa --- /dev/null +++ b/libsigrokdecode4DSL/decoders/onewire_network/__init__.py @@ -0,0 +1,56 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +''' +This decoder stacks on top of the 'onewire_link' PD and decodes the +1-Wire protocol (network layer). + +The 1-Wire protocol enables bidirectional communication over a single wire +(and ground) between a single master and one or multiple slaves. The protocol +is layered: + + - Link layer (reset, presence detection, reading/writing bits) + - Network layer (skip/search/match device ROM addresses) + - Transport layer (transport data between 1-Wire master and device) + +Network layer: + +The following link layer annotations are shown: + + - RESET/PRESENCE True/False + The event is marked from the signal negative edge to the end of the reset + high period. It is also reported if there are any devices attached to the + bus. + +The following network layer annotations are shown: + + - ROM command + The requested ROM command is displayed as an 8bit hex value and by name. + - ROM + The 64bit value of the addressed device is displayed: + Family code (1 byte) + serial number (6 bytes) + CRC (1 byte) + - Data + Data intended for the transport layer is displayed as an 8bit hex value. + +TODO: + - Add CRC checks, to see if there were communication errors on the wire. + - Add reporting original/complement address values from the search algorithm. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/onewire_network/pd.py b/libsigrokdecode4DSL/decoders/onewire_network/pd.py new file mode 100644 index 00000000..ef302aea --- /dev/null +++ b/libsigrokdecode4DSL/decoders/onewire_network/pd.py @@ -0,0 +1,185 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Iztok Jeras +## +## 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, see . +## + +import sigrokdecode as srd + +# Dictionary of ROM commands and their names, next state. +command = { + 0x33: ['Read ROM' , 'GET ROM' ], + 0x0f: ['Conditional read ROM' , 'GET ROM' ], + 0xcc: ['Skip ROM' , 'TRANSPORT' ], + 0x55: ['Match ROM' , 'GET ROM' ], + 0xf0: ['Search ROM' , 'SEARCH ROM'], + 0xec: ['Conditional search ROM' , 'SEARCH ROM'], + 0x3c: ['Overdrive skip ROM' , 'TRANSPORT' ], + 0x69: ['Overdrive match ROM' , 'GET ROM' ], + 0xa5: ['Resume' , 'TRANSPORT' ], + 0x96: ['DS2408: Disable Test Mode' , 'GET ROM' ], +} + +class Decoder(srd.Decoder): + api_version = 3 + id = 'onewire_network' + name = '1-Wire network layer' + longname = '1-Wire serial communication bus (network layer)' + desc = 'Bidirectional, half-duplex, asynchronous serial bus.' + license = 'gplv2+' + inputs = ['onewire_link'] + outputs = ['onewire_network'] + tags = ['Embedded/industrial'] + annotations = ( + ('text', 'Human-readable text'), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.ss_block = 0 + self.es_block = 0 + self.state = 'COMMAND' + self.bit_cnt = 0 + self.search = 'P' + self.data_p = 0x0 + self.data_n = 0x0 + self.data = 0x0 + self.rom = 0x0000000000000000 + + def start(self): + self.out_python = self.register(srd.OUTPUT_PYTHON) + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + # Helper function for most annotations. + self.put(self.ss_block, self.es_block, self.out_ann, data) + + def puty(self, data): + # Helper function for most protocol packets. + self.put(self.ss_block, self.es_block, self.out_python, data) + + def decode(self, ss, es, data): + code, val = data + + # State machine. + if code == 'RESET/PRESENCE': + self.search = 'P' + self.bit_cnt = 0 + self.put(ss, es, self.out_ann, + [0, ['Reset/presence: %s' % ('true' if val else 'false')]]) + self.put(ss, es, self.out_python, ['RESET/PRESENCE', val]) + self.state = 'COMMAND' + return + + # For now we're only interested in 'RESET/PRESENCE' and 'BIT' packets. + if code != 'BIT': + return + + if self.state == 'COMMAND': + # Receiving and decoding a ROM command. + if self.onewire_collect(8, val, ss, es) == 0: + return + if self.data in command: + self.putx([0, ['ROM command: 0x%02x \'%s\'' + % (self.data, command[self.data][0])]]) + self.state = command[self.data][1] + else: + self.putx([0, ['ROM command: 0x%02x \'%s\'' + % (self.data, 'unrecognized')]]) + self.state = 'COMMAND ERROR' + elif self.state == 'GET ROM': + # A 64 bit device address is selected. + # Family code (1 byte) + serial number (6 bytes) + CRC (1 byte) + if self.onewire_collect(64, val, ss, es) == 0: + return + self.rom = self.data & 0xffffffffffffffff + self.putx([0, ['ROM: 0x%016x' % self.rom]]) + self.puty(['ROM', self.rom]) + self.state = 'TRANSPORT' + elif self.state == 'SEARCH ROM': + # A 64 bit device address is searched for. + # Family code (1 byte) + serial number (6 bytes) + CRC (1 byte) + if self.onewire_search(64, val, ss, es) == 0: + return + self.rom = self.data & 0xffffffffffffffff + self.putx([0, ['ROM: 0x%016x' % self.rom]]) + self.puty(['ROM', self.rom]) + self.state = 'TRANSPORT' + elif self.state == 'TRANSPORT': + # The transport layer is handled in byte sized units. + if self.onewire_collect(8, val, ss, es) == 0: + return + self.putx([0, ['Data: 0x%02x' % self.data]]) + self.puty(['DATA', self.data]) + elif self.state == 'COMMAND ERROR': + # Since the command is not recognized, print raw data. + if self.onewire_collect(8, val, ss, es) == 0: + return + self.putx([0, ['ROM error data: 0x%02x' % self.data]]) + + # Data collector. + def onewire_collect(self, length, val, ss, es): + # Storing the sample this sequence begins with. + if self.bit_cnt == 0: + self.ss_block = ss + self.data = self.data & ~(1 << self.bit_cnt) | (val << self.bit_cnt) + self.bit_cnt += 1 + # Storing the sample this sequence ends with. + # In case the full length of the sequence is received, return 1. + if self.bit_cnt == length: + self.es_block = es + self.data = self.data & ((1 << length) - 1) + self.bit_cnt = 0 + return 1 + else: + return 0 + + # Search collector. + def onewire_search(self, length, val, ss, es): + # Storing the sample this sequence begins with. + if (self.bit_cnt == 0) and (self.search == 'P'): + self.ss_block = ss + + if self.search == 'P': + # Master receives an original address bit. + self.data_p = self.data_p & ~(1 << self.bit_cnt) | \ + (val << self.bit_cnt) + self.search = 'N' + elif self.search == 'N': + # Master receives a complemented address bit. + self.data_n = self.data_n & ~(1 << self.bit_cnt) | \ + (val << self.bit_cnt) + self.search = 'D' + elif self.search == 'D': + # Master transmits an address bit. + self.data = self.data & ~(1 << self.bit_cnt) | (val << self.bit_cnt) + self.search = 'P' + self.bit_cnt += 1 + + # Storing the sample this sequence ends with. + # In case the full length of the sequence is received, return 1. + if self.bit_cnt == length: + self.es_block = es + self.data_p = self.data_p & ((1 << length) - 1) + self.data_n = self.data_n & ((1 << length) - 1) + self.data = self.data & ((1 << length) - 1) + self.search = 'P' + self.bit_cnt = 0 + return 1 + else: + return 0 diff --git a/libsigrokdecode4DSL/decoders/ook/__init__.py b/libsigrokdecode4DSL/decoders/ook/__init__.py new file mode 100644 index 00000000..24e493bb --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ook/__init__.py @@ -0,0 +1,36 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Steve R +## +## 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, see . +## + +''' +OOK decodes On-off keying based remote control protocols. + +It is aimed at 433MHz but should also work with other common RC frequencies. +The input can be captured directly from a transmitter (before the modulation +stage) or demodulated by an RF receiver. + +Over the air captured traces will be a lot noisier and will probably need the +area of interest to be zoomed onto, then selected with the "Cursors" and the +"Save Selected Range As" feature to be used to extract it from the noise. + +There is a limited amount of pre-filtering and garbage removal built into the +decoder which can sometimes extract signals directly from a larger over the air +trace. It depends heavily on your environment. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/ook/pd.py b/libsigrokdecode4DSL/decoders/ook/pd.py new file mode 100644 index 00000000..559291c4 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ook/pd.py @@ -0,0 +1,484 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Steve R +## +## 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, see . +## + +import sigrokdecode as srd + +''' +OUTPUT_PYTHON format: +Samples: The Samples array is sent when a DECODE_TIMEOUT occurs. +[, , ] + is the sample number of the start of the decoded bit. This may not line +up with the pulses that were converted into the decoded bit particularly for +Manchester encoding. + is the sample number of the end of the decoded bit. + is a single character string which is the state of the decoded bit. +This can be +'0' zero or low +'1' one or high +'E' Error or invalid. This can be caused by missing transitions or the wrong +pulse lengths according to the rules for the particular encoding. In some cases +this is intentional (Oregon 1 preamble) and is part of the sync pattern. In +other cases the signal could simply be broken. + +If there are more than self.max_errors (default 5) in decoding then the +OUTPUT_PYTHON is not sent as the data is assumed to be worthless. +There also needs to be a low for five times the preamble period at the end of +each set of pulses to trigger a DECODE_TIMEOUT and get the OUTPUT_PYTHON sent. +''' + +class SamplerateError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = 'ook' + name = 'OOK' + longname = 'On-off keying' + desc = 'On-off keying protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = ['ook'] + tags = ['Encoding'] + channels = ( + {'id': 'data', 'name': 'Data', 'desc': 'Data line'}, + ) + annotations = ( + ('frame', 'Frame'), + ('info', 'Info'), + ('1111', '1111'), + ('1010', '1010'), + ('diffman', 'Diff Man'), + ('nrz', 'NRZ'), + ) + annotation_rows = ( + ('frame', 'Framing',(0,)), + ('info', 'Info', (1,)), + ('man1111', 'Man 1111', (2,)), + ('man1010', 'Man 1010', (3,)), + ('diffman', 'Diff Man', (4,)), + ('nrz', 'NRZ', (5,)), + ) + binary = ( + ('pulse-lengths', 'Pulse lengths'), + ) + options = ( + {'id': 'invert', 'desc': 'Invert data', 'default': 'no', + 'values': ('no', 'yes')}, + {'id': 'decodeas', 'desc': 'Decode type', 'default': 'Manchester', + 'values': ('NRZ', 'Manchester', 'Diff Manchester')}, + {'id': 'preamble', 'desc': 'Preamble', 'default': 'auto', + 'values': ('auto', '1010', '1111')}, + {'id': 'preamlen', 'desc': 'Filter length', 'default': '7', + 'values': ('0', '3', '4', '5', '6', '7', '8', '9', '10')}, + {'id': 'diffmanvar', 'desc': 'Transition at start', 'default': '1', + 'values': ('1', '0')}, + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.ss = self.es = -1 + self.ss_1111 = self.ss_1010 = -1 + self.samplenumber_last = None + self.sample_first = None + self.sample_high = 0 + self.sample_low = 0 + self.edge_count = 0 + self.word_first = None + self.word_count = 0 + self.state = 'IDLE' + self.lstate = None + self.lstate_1010 = None + self.insync = 0 # Preamble in sync flag + self.man_errors = 0 + self.man_errors_1010 = 0 + self.preamble = [] # Preamble buffer + self.half_time = -1 # Half time for man 1111 + self.half_time_1010 = 0 # Half time for man 1010 + self.pulse_lengths = [] # Pulse lengths + self.decoded = [] # Decoded stream + self.decoded_1010 = [] # Decoded stream + self.diff_man_trans = '0' # Transition + self.diff_man_len = 1 # Length of pulse in half clock periods + self.max_errors = 5 # Max number of errors to output OOK + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_python = self.register(srd.OUTPUT_PYTHON) + self.out_binary = self.register(srd.OUTPUT_BINARY) + self.invert = self.options['invert'] + self.decodeas = self.options['decodeas'] + self.preamble_val = self.options['preamble'] + self.preamble_len = self.options['preamlen'] + self.diffmanvar = self.options['diffmanvar'] + + def putx(self, data): + self.put(self.ss, self.es, self.out_ann, data) + + def putp(self, data): + self.put(self.ss, self.es, self.out_python, data) + + def dump_pulse_lengths(self): + if self.samplerate: + self.pulse_lengths[-1] = self.sample_first # Fix final pulse length. + s = 'Pulses(us)=' + s += ','.join(str(int(int(x) * 1000000 / self.samplerate)) + for x in self.pulse_lengths) + s += '\n' + self.put(self.samplenum - 10, self.samplenum, self.out_binary, + [0, bytes([ord(c) for c in s])]) + + def decode_nrz(self, start, samples, state): + self.pulse_lengths.append(samples) + # Use different high and low widths to compensate skewed waveforms. + dsamples = self.sample_high if state == '1' else self.sample_low + self.ss, self.es = start, start + samples + while samples > dsamples * 0.5: + if samples >= dsamples * 1.5: # More than one bit. + self.es = self.ss + dsamples + self.putx([5, [state]]) + self.decoded.append([self.ss, self.es, state]) + self.edge_count += 1 + elif samples >= dsamples * 0.5 and samples < dsamples * 1.5: # Last bit. + self.putx([5, [state]]) + self.decoded.append([self.ss, self.es, state]) + self.edge_count += 1 + else: + self.edge_count += 1 + samples -= dsamples + self.ss += dsamples + self.es += dsamples + + # Ensure 2nd row doesn't go past end of 1st row. + if self.es > self.samplenum: + self.es = self.samplenum + + if self.state == 'DECODE_TIMEOUT': # Five bits - reset. + self.ss = self.decoded[0][0] + self.es = self.decoded[len(self.decoded) - 1][1] + self.dump_pulse_lengths() + self.putp(self.decoded) + self.decode_timeout() + break + + def lock_onto_preamble(self, samples, state): # Filters and recovers clock. + self.edge_count += 1 + l2s = 5 # Max ratio of long to short pulses. + + # Filter incoming pulses to remove random noise. + if self.state == 'DECODE_TIMEOUT': + self.preamble = [] + self.edge_count = 0 + self.word_first = self.samplenum + self.sample_first = self.samplenum - self.samplenumber_last + self.state = 'WAITING_FOR_PREAMBLE' + self.man_errors = 0 + + pre_detect = int(self.preamble_len) # Number of valid pulses to detect. + pre_samples = self.samplenum - self.samplenumber_last + if len(self.preamble) > 0: + if (pre_samples * l2s < self.preamble[-1][1] or + self.preamble[-1][1] * l2s < pre_samples): # Garbage in. + self.put(self.samplenum, self.samplenum, + self.out_ann, [0, ['R']]) # Display resets. + self.preamble = [] # Clear buffer. + self.preamble.append([self.samplenumber_last, + pre_samples, state]) + self.edge_count = 0 + self.samplenumber_last = self.samplenum + self.word_first = self.samplenum + else: + self.preamble.append([self.samplenumber_last, + pre_samples, state]) + else: + self.preamble.append([self.samplenumber_last, + pre_samples, state]) + + pre = self.preamble + if len(self.preamble) == pre_detect: # Have a valid series of pulses. + if self.preamble[0][2] == '1': + self.sample_high = self.preamble[0][1] # Allows skewed pulses. + self.sample_low = self.preamble[1][1] + else: + self.sample_high = self.preamble[1][1] + self.sample_low = self.preamble[0][1] + + self.edge_count = 0 + + for i in range(len(self.preamble)): + if i > 1: + if (pre[i][1] > pre[i - 2][1] * 1.25 or + pre[i][1] * 1.25 < pre[i - 2][1]): # Adjust ref width. + if pre[i][2] == '1': + self.sample_high = pre[i][1] + else: + self.sample_low = pre[i][1] + + # Display start of preamble. + if self.decodeas == 'NRZ': + self.decode_nrz(pre[i][0], pre[i][1], pre[i][2]) + if self.decodeas == 'Manchester': + self.decode_manchester(pre[i][0], pre[i][1], pre[i][2]) + if self.decodeas == 'Diff Manchester': + self.es = pre[i][0] + pre[i][1] + self.decode_diff_manchester(pre[i][0], pre[i][1], pre[i][2]) + + # Used to timeout signal. + self.sample_first = int((self.sample_high + self.sample_low)/2) + self.insync = 1 + self.state = 'DECODING' + self.lstate = state + self.lstate_1010 = state + + def decode_diff_manchester(self, start, samples, state): + self.pulse_lengths.append(samples) + + # Use different high and low widths to compensate skewed waveforms. + dsamples = self.sample_high if state == '1' else self.sample_low + + self.es = start + samples + p_length = round(samples / dsamples) # Find relative pulse length. + + if self.edge_count == 0: + self.diff_man_trans = '1' # Very first pulse must be a transition. + self.diff_man_len = 1 # Must also be a half pulse. + self.ss = start + elif self.edge_count % 2 == 1: # Time to make a decision. + if self.diffmanvar == '0': # Transition at self.ss is a zero. + self.diff_man_trans = '0' if self.diff_man_trans == '1' else '1' + if self.diff_man_len == 1 and p_length == 1: + self.putx([4, [self.diff_man_trans]]) + self.decoded.append([self.ss, self.es, self.diff_man_trans]) + self.diff_man_trans = '1' + elif self.diff_man_len == 1 and p_length == 2: + self.es -= int(samples / 2) + self.putx([4, [self.diff_man_trans]]) + self.decoded.append([self.ss, self.es, self.diff_man_trans]) + self.diff_man_trans = '0' + self.edge_count += 1 # Add a virt edge to keep in sync with clk. + elif self.diff_man_len == 2 and p_length == 1: + self.putx([4, [self.diff_man_trans]]) + self.decoded.append([self.ss, self.es, self.diff_man_trans]) + self.diff_man_trans = '1' + elif self.diff_man_len == 2 and p_length == 2: # Double illegal E E. + self.es -= samples + self.putx([4, ['E']]) + self.decoded.append([self.ss, self.es, 'E']) + self.ss = self.es + self.es += samples + self.putx([4, ['E']]) + self.decoded.append([self.ss, self.es, 'E']) + self.diff_man_trans = '1' + elif self.diff_man_len == 1 and p_length > 4: + if self.state == 'DECODE_TIMEOUT': + self.es = self.ss + 2 * self.sample_first + self.putx([4, [self.diff_man_trans]]) # Write error. + self.decoded.append([self.ss, self.es, self.diff_man_trans]) + self.ss = self.decoded[0][0] + self.es = self.decoded[len(self.decoded) - 1][1] + self.dump_pulse_lengths() + if self.man_errors < self.max_errors: + self.putp(self.decoded) + else: + error_message = 'Probably not Diff Manchester encoded' + self.ss = self.word_first + self.putx([1, [error_message]]) + self.decode_timeout() + self.diff_man_trans = '1' + self.ss = self.es + self.diff_man_len = p_length # Save the previous length. + self.edge_count += 1 + + def decode_manchester_sim(self, start, samples, state, + dsamples, half_time, lstate, ss, pream): + ook_bit = [] + errors = 0 + if self.edge_count == 0: + half_time += 1 + if samples > 0.75 * dsamples and samples <= 1.5 * dsamples: # Long p. + half_time += 2 + if half_time % 2 == 0: # Transition. + es = start + else: + es = start + int(samples / 2) + if ss == start: + lstate = 'E' + es = start + samples + if not (self.edge_count == 0 and pream == '1010'): # Skip first p. + ook_bit = [ss, es, lstate] + lstate = state + ss = es + elif samples > 0.25 * dsamples and samples <= 0.75 * dsamples: # Short p. + half_time += 1 + if (half_time % 2 == 0): # Transition. + es = start + samples + ook_bit = [ss, es, lstate] + lstate = state + ss = es + else: # 1st half. + ss = start + lstate = state + else: # Too long or too short - error. + errors = 1 + if self.state != 'DECODE_TIMEOUT': # Error condition. + lstate = 'E' + es = ss + samples + else: # Assume final half bit buried in timeout pulse. + es = ss + self.sample_first + ook_bit = [ss, es, lstate] + ss = es + + return (half_time, lstate, ss, ook_bit, errors) + + def decode_manchester(self, start, samples, state): + self.pulse_lengths.append(samples) + + # Use different high and low widths to compensate skewed waveforms. + dsamples = self.sample_high if state == '1' else self.sample_low + + if self.preamble_val != '1010': # 1111 preamble is half clock T. + (self.half_time, self.lstate, self.ss_1111, ook_bit, errors) = ( + self.decode_manchester_sim(start, samples, state, dsamples * 2, + self.half_time, self.lstate, + self.ss_1111, '1111')) + self.man_errors += errors + if ook_bit != []: + self.decoded.append([ook_bit[0], ook_bit[1], ook_bit[2]]) + + if self.preamble_val != '1111': # 1010 preamble is clock T. + (self.half_time_1010, self.lstate_1010, self.ss_1010, + ook_bit, errors) = ( + self.decode_manchester_sim(start, samples, state, dsamples, + self.half_time_1010, self.lstate_1010, + self.ss_1010, '1010')) + self.man_errors_1010 += errors + if ook_bit != []: + self.decoded_1010.append([ook_bit[0], ook_bit[1], ook_bit[2]]) + + self.edge_count += 1 + + # Stream display and save ook_bit. + if ook_bit != []: + self.ss, self.es = ook_bit[0], ook_bit[1] + if self.preamble_val == '1111': + self.putx([2, [ook_bit[2]]]) + if self.preamble_val == '1010': + self.putx([3, [ook_bit[2]]]) + + if self.state == 'DECODE_TIMEOUT': # End of packet. + self.dump_pulse_lengths() + + decoded = [] + # If 1010 preamble has less errors use it. + if (self.preamble_val == '1010' or + (self.man_errors_1010 < self.max_errors and + self.man_errors_1010 < self.man_errors and + len(self.decoded_1010) > 0)): + decoded = self.decoded_1010 + man_errors = self.man_errors_1010 + d_row = 3 + else: + decoded = self.decoded + man_errors = self.man_errors + d_row = 2 + + if self.preamble_val == 'auto': # Display OOK packet. + for i in range(len(decoded)): + self.ss, self.es = decoded[i][0], decoded[i][1] + self.putx([d_row, [decoded[i][2]]]) + + if (man_errors < self.max_errors and len(decoded) > 0): + self.ss, self.es = decoded[0][0], decoded[len(decoded) - 1][1] + self.putp(decoded) + else: + error_message = 'Not Manchester encoded or wrong preamble' + self.ss = self.word_first + self.putx([1, [error_message]]) + + self.put(self.es, self.es, self.out_ann, [0, ['T']]) # Mark timeout. + self.decode_timeout() + + def decode_timeout(self): + self.word_count = 0 + self.samplenumber_last = None + self.edge_count = 0 + self.man_errors = 0 # Clear the bit error counters. + self.man_errors_1010 = 0 + self.state = 'IDLE' + self.wait({0: 'e'}) # Get rid of long pulse. + self.samplenumber_last = self.samplenum + self.word_first = self.samplenum + self.insync = 0 # Preamble in sync flag + self.preamble = [] # Preamble buffer + self.half_time = -1 # Half time for man 1111 + self.half_time_1010 = 0 # Half time for man 1010 + self.decoded = [] # Decoded bits + self.decoded_1010 = [] # Decoded bits for man 1010 + self.pulse_lengths = [] + + def decode(self): + while True: + if self.edge_count == 0: # Waiting for a signal. + (ook,) = self.wait({0: 'e'}) + self.state = 'DECODING' + else: + (ook,) = self.wait([{0: 'e'}, {'skip': 5 * self.sample_first}]) + if (self.matched & (0b1 << 1)) and not (self.matched & (0b1 << 0)): # No edges for 5 p's. + self.state = 'DECODE_TIMEOUT' + + if not self.samplenumber_last: # Set counters to start of signal. + self.samplenumber_last = self.samplenum + self.word_first = self.samplenum + continue + samples = self.samplenum - self.samplenumber_last + if not self.sample_first: # Get number of samples for first pulse. + self.sample_first = samples + + pinstate = ook + if self.state == 'DECODE_TIMEOUT': # No edge so flip the state. + pinstate = int(not pinstate) + if self.invert == 'yes': # Invert signal. + pinstate = int(not pinstate) + state = '0' if pinstate else '1' + + # No preamble filtering or checking and no skew correction. + if self.preamble_len == '0': + self.sample_high = self.sample_first + self.sample_low = self.sample_first + self.insync = 0 + + if self.insync == 0: + self.lock_onto_preamble(samples, state) + else: + if self.decodeas == 'NRZ': + self.decode_nrz(self.samplenumber_last, samples, state) + if self.decodeas == 'Manchester': + self.decode_manchester(self.samplenumber_last, + samples, state) + if self.decodeas == 'Diff Manchester': + self.decode_diff_manchester(self.samplenumber_last, + samples, state) + + self.samplenumber_last = self.samplenum diff --git a/libsigrokdecode4DSL/decoders/ook_oregon/__init__.py b/libsigrokdecode4DSL/decoders/ook_oregon/__init__.py new file mode 100644 index 00000000..f1a1fdf4 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ook_oregon/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Steve R +## +## 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, see . +## + +''' +This decoder stacks on top of the 'ook' PD and decodes the Oregon Scientific +433MHz remote control protocol for weather sensors. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/ook_oregon/lists.py b/libsigrokdecode4DSL/decoders/ook_oregon/lists.py new file mode 100644 index 00000000..c46c4cc7 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ook_oregon/lists.py @@ -0,0 +1,75 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Steve R +## +## 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, see . +## + +# Most of the info here comes from "434MHz RF Protocol Descriptions for +# Wireless Weather Sensors - October 2015" Known Sensor ID Codes - p25. + +# Format is 4 hex digit ID code followed by a LIST of models that use that +# ID and the type of sensor. +# SensorID is used as the hash in a Python hash table, so it must be upper case. +# The type of sensor is used to decode and display readings in the L2 decode, +# it's case-sensitive. +# Be very careful with the formatting ' [] and commas. + +sensor = { +# 'SensorID': [['model1', 'model2'], 'type'], + '1984': [['WGR800'], 'Wind'], # The newer anemometer with no temperature/RH sensor. + '1994': [['WGR800'], 'Wind'], # The original anemometer which included a temperature/RH sensor. + '1A2D': [['THGR228N'], 'Temp_Hum1'], + '1A3D': [['THGR918'], ''], + '1D20': [['THGN123N', 'THGR122NX', 'THGN123N', 'THGR228N'], 'Temp_Hum'], + '1D30': [['THGN500', 'THGN132N'], ''], + '2914': [['PCR800'], 'Rain'], + '2A19': [['PCR800'], 'Rain1'], + '2A1D': [['RGR918'], 'Rain'], + '2D10': [['RGR968', 'PGR968 '], 'Rain1'], + '3A0D': [['STR918', 'WGR918'], 'Wind'], + '5A5D': [['BTHR918'], ''], + '5A6D': [['BTHR918N'], 'Temp_Hum_Baro'], + '5D53': [['BTHGN129'], 'Baro'], + '5D60': [['BTHR968'], 'Temp_Hum_Baro'], + 'C844': [['THWR800'], 'Temp'], + 'CC13': [['RTGR328N'], 'Temp_Hum'], + 'CC23': [['THGR328N'], 'Temp_Hum'], + 'CD39': [['RTHR328N'], 'Temp'], + 'D874': [['UVN800'], 'UV1'], + 'EA4C': [['THWR288A'], 'Temp'], + 'EC40': [['THN132N', 'THR238NF'], 'Temp'], + 'EC70': [['UVR128'], 'UV'], + 'F824': [['THGN800', 'THGN801', 'THGR810'], 'Temp_Hum'], + 'F8B4': [['THGR810'], 'Temp_Hum'], +# '': ['PSR01'], '', ''], +# '': ['RTGR328NA'], '', ''], +# '': ['THC268'], '', ''], +# '': ['THWR288A-JD'], '', ''], +# '': ['THGR268'], '', ''], +# '': ['THR268'], '', ''], +} + +# The sensor checksum exceptions are used to calculate the right checksum for +# sensors that don't follow the v1, v2.1 and v3 methods. For instance a v2.1 +# sensor that has a v3 checksum. +sensor_checksum = { +# 'SensorID': ['checksum_method', 'comment'], + '1D20': ['v3', 'THGR228N'], + '5D60': ['v3', 'BTHR918N'], + 'EC40': ['v3', 'THN132N'], +} + +dir_table = ['N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW', 'N'] diff --git a/libsigrokdecode4DSL/decoders/ook_oregon/pd.py b/libsigrokdecode4DSL/decoders/ook_oregon/pd.py new file mode 100644 index 00000000..225f5983 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ook_oregon/pd.py @@ -0,0 +1,389 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Steve R +## +## 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, see . +## + +import sigrokdecode as srd +import math +from .lists import * + +class Decoder(srd.Decoder): + api_version = 3 + id = 'ook_oregon' + name = 'Oregon' + longname = 'Oregon Scientific' + desc = 'Oregon Scientific weather sensor protocol.' + license = 'gplv2+' + inputs = ['ook'] + outputs = [] + tags = ['Sensor'] + annotations = ( + ('bit', 'Bit'), + ('field', 'Field'), + ('l2', 'Level 2'), + ('pre', 'Preamble'), + ('syn', 'Sync'), + ('id', 'SensorID'), + ('ch', 'Channel'), + ('roll', 'Rolling code'), + ('f1', 'Flags1'), + ) + annotation_rows = ( + ('bits', 'Bits', (0,)), + ('fields', 'Fields', (1, 3, 4)), + ('l2', 'Level 2', (2,)), + ) + binary = ( + ('data-hex', 'Hex data'), + ) + options = ( + {'id': 'unknown', 'desc': 'Unknown type is', 'default': 'Unknown', + 'values': ('Unknown', 'Temp', 'Temp_Hum', 'Temp_Hum1', 'Temp_Hum_Baro', + 'Temp_Hum_Baro1', 'UV', 'UV1', 'Wind', 'Rain', 'Rain1')}, + ) + + def __init__(self): + self.reset() + + def reset(self): + self.decoded = [] # Local cache of decoded OOK. + self.skip = None + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_binary = self.register(srd.OUTPUT_BINARY) + self.unknown = self.options['unknown'] + + def putx(self, data): + self.put(self.ss, self.es, self.out_ann, data) + + def dump_oregon_hex(self, start, finish): + nib = self.decoded_nibbles + hexstring = '' + for x in nib: + hexstring += str(x[3]) if x[3] != '' else ' ' + s = 'Oregon ' + self.ver + ' \"' + hexstring.upper() + '\"\n' + self.put(start, finish, self.out_binary, + [0, bytes([ord(c) for c in s])]) + + def oregon_put_pre_and_sync(self, len_pream, len_sync, ver): + ook = self.decoded + self.decode_pos = len_pream + self.ss, self.es = ook[0][0], ook[self.decode_pos][0] + self.putx([1, ['Oregon ' + ver + ' Preamble', ver + ' Preamble', + ver + ' Pre', ver]]) + self.decode_pos += len_sync + self.ss, self.es = ook[len_pream][0], ook[self.decode_pos][0] + self.putx([1, ['Sync', 'Syn', 'S']]) + + # Strip off preamble and sync bits. + self.decoded = self.decoded[self.decode_pos:] + self.ookstring = self.ookstring[self.decode_pos:] + self.ver = ver + + def oregon(self): + self.ookstring = '' + self.decode_pos = 0 + ook = self.decoded + for i in range(len(ook)): + self.ookstring += ook[i][2] + if '10011001' in self.ookstring[:40]: + (preamble, data) = self.ookstring.split('10011001', 1) + if len(data) > 0 and len(preamble) > 16: + self.oregon_put_pre_and_sync(len(preamble), 8, 'v2.1') + self.oregon_v2() + elif 'E1100' in self.ookstring[:17]: + (preamble, data) = self.ookstring.split('E1100', 1) + if len(data) > 0 and len(preamble) <= 12: + self.oregon_put_pre_and_sync(len(preamble), 5, 'v1') + self.oregon_v1() + elif '0101' in self.ookstring[:28]: + (preamble, data) = self.ookstring.split('0101', 1) + if len(data) > 0 and len(preamble) > 12: + self.oregon_put_pre_and_sync(len(preamble), 4, 'v3') + self.oregon_v3() + elif len(self.ookstring) > 16: # Ignore short packets. + error_message = 'Not Oregon or wrong preamble' + self.ss, self.es = ook[0][0], ook[len(ook) - 1][1] + self.putx([1,[error_message]]) + + def oregon_v1(self): + ook = self.decoded + self.decode_pos = 0 + self.decoded_nibbles = [] + if len(self.decoded) >= 32: # Check there are at least 8 nibbles. + self.oregon_put_nib('RollingCode', ook[self.decode_pos][0], + ook[self.decode_pos + 3][1], 4) + self.oregon_put_nib('Ch', ook[self.decode_pos][0], + ook[self.decode_pos + 3][1], 4) + self.oregon_put_nib('Temp', ook[self.decode_pos][0], + ook[self.decode_pos + 15][1], 16) + self.oregon_put_nib('Checksum', ook[self.decode_pos][0], + ook[self.decode_pos + 7][1], 8) + + self.dump_oregon_hex(ook[0][0], ook[len(ook) - 1][1]) + + # L2 decode. + self.oregon_temp(2) + self.oregon_channel(1) + self.oregon_battery(2) + self.oregon_checksum_v1() + + def oregon_v2(self): # Convert to v3 format - discard odd bits. + self.decode_pos = 0 + self.ookstring = self.ookstring[1::2] + for i in range(len(self.decoded)): + if i % 2 == 1: + self.decoded[i][0] = self.decoded[i - 1][0] # Re-align start pos. + self.decoded = self.decoded[1::2] # Discard left hand bits. + self.oregon_v3() # Decode with v3 decoder. + + def oregon_nibbles(self, ookstring): + num_nibbles = int(len(ookstring) / 4) + nibbles = [] + for i in range(num_nibbles): + nibble = ookstring[4 * i : 4 * i + 4] + nibble = nibble[::-1] # Reversed from right. + nibbles.append(nibble) + return nibbles + + def oregon_put_nib(self, label, start, finish, numbits): + param = self.ookstring[self.decode_pos:self.decode_pos + numbits] + param = self.oregon_nibbles(param) + if 'E' in ''.join(param): # Blank out fields with errors. + result = '' + else: + result = hex(int(''.join(param), 2))[2:] + if len(result) < numbits / 4: # Reinstate leading zeros. + result = '0' * (int(numbits / 4) - len(result)) + result + if label != '': + label += ': ' + self.put(start, finish, self.out_ann, [1, [label + result, result]]) + if label == '': # No label - use nibble position. + label = int(self.decode_pos / 4) + for i in range(len(param)): + ss = self.decoded[self.decode_pos + (4 * i)][0] + es = self.decoded[self.decode_pos + (4 * i) + 3][1] + # Blank out nibbles with errors. + result = '' if ('E' in param[i]) else hex(int(param[i], 2))[2:] + # Save nibbles for L2 decoder. + self.decoded_nibbles.append([ss, es, label, result]) + self.decode_pos += numbits + + def oregon_v3(self): + self.decode_pos = 0 + self.decoded_nibbles = [] + ook = self.decoded + + if len(self.decoded) >= 32: # Check there are at least 8 nibbles. + self.oregon_put_nib('SensorID', ook[self.decode_pos][0], + ook[self.decode_pos + 16][0], 16) + self.oregon_put_nib('Ch', ook[self.decode_pos][0], + ook[self.decode_pos + 3][1], 4) + self.oregon_put_nib('RollingCode', ook[self.decode_pos][0], + ook[self.decode_pos + 7][1], 8) + self.oregon_put_nib('Flags1', ook[self.decode_pos][0], + ook[self.decode_pos + 3][1], 4) + + rem_nibbles = len(self.ookstring[self.decode_pos:]) // 4 + for i in range(rem_nibbles): # Display and save rest of nibbles. + self.oregon_put_nib('', ook[self.decode_pos][0], + ook[self.decode_pos + 3][1], 4) + self.dump_oregon_hex(ook[0][0], ook[len(ook) - 1][1]) + self.oregon_level2() # Level 2 decode. + else: + error_message = 'Too short to decode' + self.put(ook[0][0], ook[-1][1], self.out_ann, [1, [error_message]]) + + def oregon_put_l2_param(self, offset, digits, dec_point, pre_label, label): + nib = self.decoded_nibbles + result = 0 + out_string = ''.join(str(x[3]) for x in nib[offset:offset + digits]) + if len(out_string) == digits: + for i in range(dec_point, 0, -1): + result += int(nib[offset + dec_point - i][3], 16) / pow(10, i) + for i in range(dec_point, digits): + result += int(nib[offset + i][3], 16) * pow(10, i - dec_point) + result = '%g' % (result) + else: + result = '' + es = nib[offset + digits - 1][1] + if label == '\u2103': + es = nib[offset + digits][1] # Align temp to include +/- nibble. + self.put(nib[offset][0], es, self.out_ann, + [2, [pre_label + result + label, result]]) + + def oregon_temp(self, offset): + nib = self.decoded_nibbles + if nib[offset + 3][3] != '': + temp_sign = str(int(nib[offset + 3][3], 16)) + temp_sign = '-' if temp_sign != '0' else '+' + else: + temp_sign = '?' + self.oregon_put_l2_param(offset, 3, 1, temp_sign, '\u2103') + + def oregon_baro(self, offset): + nib = self.decoded_nibbles + baro = '' + if not (nib[offset + 2][3] == '' or nib[offset + 1][3] == '' + or nib[offset][3] == ''): + baro = str(int(nib[offset + 1][3] + nib[offset][3], 16) + 856) + self.put(nib[offset][0], nib[offset + 3][1], + self.out_ann, [2, [baro + ' mb', baro]]) + + def oregon_wind_dir(self, offset): + nib = self.decoded_nibbles + if nib[offset][3] != '': + w_dir = int(int(nib[offset][3], 16) * 22.5) + w_compass = dir_table[math.floor((w_dir + 11.25) / 22.5)] + self.put(nib[offset][0], nib[offset][1], self.out_ann, + [2, [w_compass + ' (' + str(w_dir) + '\u00b0)', w_compass]]) + + def oregon_channel(self, offset): + nib = self.decoded_nibbles + channel = '' + if nib[offset][3] != '': + ch = int(nib[offset][3], 16) + if self.ver != 'v3': # May not be true for all v2.1 sensors. + if ch != 0: + bit_pos = 0 + while ((ch & 1) == 0): + bit_pos += 1 + ch = ch >> 1 + if self.ver == 'v2.1': + bit_pos += 1 + channel = str(bit_pos) + elif self.ver == 'v3': # Not sure if this applies to all v3's. + channel = str(ch) + if channel != '': + self.put(nib[offset][0], nib[offset][1], + self.out_ann, [2, ['Ch ' + channel, channel]]) + + def oregon_battery(self, offset): + nib = self.decoded_nibbles + batt = 'OK' + if nib[offset][3] != '': + if (int(nib[offset][3], 16) >> 2) & 0x1 == 1: + batt = 'Low' + self.put(nib[offset][0], nib[offset][1], + self.out_ann, [2, ['Batt ' + batt, batt]]) + + def oregon_level2(self): # v2 and v3 level 2 decoder. + nib = self.decoded_nibbles + self.sensor_id = (nib[0][3] + nib[1][3] + nib[2][3] + nib[3][3]).upper() + nl, sensor_type = sensor.get(self.sensor_id, [['Unknown'], 'Unknown']) + names = ','.join(nl) + # Allow user to try decoding an unknown sensor. + if sensor_type == 'Unknown' and self.unknown != 'Unknown': + sensor_type = self.unknown + self.put(nib[0][0], nib[3][1], self.out_ann, + [2, [names + ' - ' + sensor_type, names, nl[0]]]) + self.oregon_channel(4) + self.oregon_battery(7) + if sensor_type == 'Rain': + self.oregon_put_l2_param(8, 4, 2, '', ' in/hr') # Rain rate + self.oregon_put_l2_param(12, 6, 3, 'Total ', ' in') # Rain total + self.oregon_checksum(18) + if sensor_type == 'Rain1': + self.oregon_put_l2_param(8, 3, 1, '', ' mm/hr') # Rain rate + self.oregon_put_l2_param(11, 5, 1, 'Total ', ' mm') # Rain total + self.oregon_checksum(18) + if sensor_type == 'Temp': + self.oregon_temp(8) + self.oregon_checksum(12) + if sensor_type == 'Temp_Hum_Baro': + self.oregon_temp(8) + self.oregon_put_l2_param(12, 2, 0, 'Hum ', '%') # Hum + self.oregon_baro(15) # Baro + self.oregon_checksum(19) + if sensor_type == 'Temp_Hum_Baro1': + self.oregon_temp(8) + self.oregon_put_l2_param(12, 2, 0, 'Hum ', '%') # Hum + self.oregon_baro(14) # Baro + if sensor_type == 'Temp_Hum': + self.oregon_temp(8) + self.oregon_put_l2_param(12, 2, 0, 'Hum ', '%') # Hum + self.oregon_checksum(15) + if sensor_type == 'Temp_Hum1': + self.oregon_temp(8) + self.oregon_put_l2_param(12, 2, 0, 'Hum ', '%') # Hum + self.oregon_checksum(14) + if sensor_type == 'UV': + self.oregon_put_l2_param(8, 2, 0, '', '') # UV + if sensor_type == 'UV1': + self.oregon_put_l2_param(11, 2, 0,'' ,'') # UV + if sensor_type == 'Wind': + self.oregon_wind_dir(8) + self.oregon_put_l2_param(11, 3, 1, 'Gust ', ' m/s') # Wind gust + self.oregon_put_l2_param(14, 3, 1, 'Speed ', ' m/s') # Wind speed + self.oregon_checksum(17) + + def oregon_put_checksum(self, nibbles, checksum): + nib = self.decoded_nibbles + result = 'BAD' + if (nibbles + 1) < len(nib): + if (nib[nibbles + 1][3] != '' and nib[nibbles][3] != '' + and checksum != -1): + if self.ver != 'v1': + if checksum == (int(nib[nibbles + 1][3], 16) * 16 + + int(nib[nibbles][3], 16)): + result = 'OK' + else: + if checksum == (int(nib[nibbles][3], 16) * 16 + + int(nib[nibbles + 1][3], 16)): + result = 'OK' + rx_check = (nib[nibbles + 1][3] + nib[nibbles][3]).upper() + details = '%s Calc %s Rx %s ' % (result, hex(checksum)[2:].upper(), + rx_check) + self.put(nib[nibbles][0], nib[nibbles + 1][1], + self.out_ann, [2, ['Checksum ' + details, result]]) + + def oregon_checksum(self, nibbles): + checksum = 0 + for i in range(nibbles): # Add reversed nibbles. + nibble = self.ookstring[i * 4 : i * 4 + 4] + nibble = nibble[::-1] # Reversed from right. + if 'E' in nibble: # Abort checksum if there are errors. + checksum = -1 + break + checksum += int(nibble, 2) + if checksum > 255: + checksum -= 255 # Make it roll over at 255. + chk_ver, comment = sensor_checksum.get(self.sensor_id, + ['Unknown', 'Unknown']) + if chk_ver != 'Unknown': + self.ver = chk_ver + if self.ver == 'v2.1': + checksum -= 10 # Subtract 10 from v2 checksums. + self.oregon_put_checksum(nibbles, checksum) + + def oregon_checksum_v1(self): + nib = self.decoded_nibbles + checksum = 0 + for i in range(3): # Add the first three bytes. + if nib[2 * i][3] == '' or nib[2 * i + 1][3] == '': # Abort if blank. + checksum = -1 + break + checksum += ((int(nib[2 * i][3], 16) & 0xF) << 4 | + (int(nib[2 * i + 1][3], 16) & 0xF)) + if checksum > 255: + checksum -= 255 # Make it roll over at 255. + self.oregon_put_checksum(6, checksum) + + def decode(self, ss, es, data): + self.decoded = data + self.oregon() diff --git a/libsigrokdecode4DSL/decoders/ook_vis/__init__.py b/libsigrokdecode4DSL/decoders/ook_vis/__init__.py new file mode 100644 index 00000000..f50f9ef8 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ook_vis/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Steve R +## +## 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, see . +## + +''' +This decoder stacks on top of the 'ook' PD and visualizes protocol details +in various ways. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/ook_vis/pd.py b/libsigrokdecode4DSL/decoders/ook_vis/pd.py new file mode 100644 index 00000000..f985b96f --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ook_vis/pd.py @@ -0,0 +1,194 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Steve R +## +## 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, see . +## + +import sigrokdecode as srd +from common.srdhelper import bcd2int + +class Decoder(srd.Decoder): + api_version = 3 + id = 'ook_vis' + name = 'OOK visualisation' + longname = 'On-off keying visualisation' + desc = 'OOK visualisation in various formats.' + license = 'gplv2+' + inputs = ['ook'] + outputs = ['ook'] + tags = ['Encoding'] + annotations = ( + ('bit', 'Bit'), + ('ref', 'Reference'), + ('field', 'Field'), + ('ref_field', 'Ref field'), + ('level2', 'L2'), + ('ref_level2', 'Ref L2'), + ) + annotation_rows = ( + ('bits', 'Bits', (0,)), + ('compare', 'Compare', (1,)), + ('fields', 'Fields', (2,)), + ('ref_fields', 'Ref fields', (3,)), + ('level2', 'L2', (4,)), + ('ref_level2', 'Ref L2', (5,)), + ) + options = ( + {'id': 'displayas', 'desc': 'Display as', 'default': 'Nibble - Hex', + 'values': ('Byte - Hex', 'Byte - Hex rev', 'Byte - BCD', + 'Byte - BCD rev', 'Nibble - Hex', 'Nibble - Hex rev', 'Nibble - BCD', + 'Nibble - BCD rev')}, + {'id': 'synclen', 'desc': 'Sync length', 'default': '4', + 'values': ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10')}, + {'id': 'syncoffset', 'desc': 'Sync offset', 'default': '0', + 'values': ('-4', '-3', '-2', '-1', '0', '1', '2', '3', '4')}, + {'id': 'refsample', 'desc': 'Compare', 'default': 'off', 'values': + ('off', 'show numbers', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', + '21', '22', '23', '24', '25', '26', '27', '28', '29', '30')}, + ) + + def __init__(self): + self.reset() + + def reset(self): + self.decoded = [] # Local cache of decoded OOK. + self.ookstring = '' + self.ookcache = [] + self.trace_num = 0 + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_python = self.register(srd.OUTPUT_PYTHON) + self.displayas = self.options['displayas'] + self.sync_length = self.options['synclen'] + self.sync_offset = self.options['syncoffset'] + self.ref = self.options['refsample'] + + def putx(self, data): + self.put(self.ss, self.es, self.out_ann, data) + + def putp(self, data): + self.put(self.ss, self.es, self.out_python, data) + + def display_level2(self, bits, line): + self.decode_pos = 0 + ook = self.decoded + # Find the end of the preamble which could be 1010 or 1111. + if len(ook) > 1: + preamble_end = len(ook) + 1 + char_first = ook[0][2] + char_second = ook[1][2] + if char_first == char_second: # 1111 + preamble = '1111' + char_last = char_first + else: + preamble = '1010' + char_last = char_second + for i in range(len(ook)): + if preamble == '1111': + if ook[i][2] != char_last: + preamble_end = i + break + else: + char_last = ook[i][2] + else: + if ook[i][2] != char_last: + char_last = ook[i][2] + else: + preamble_end = i + break + + if len(ook) >= preamble_end: + preamble_end += int(self.sync_offset) - 1 + self.ss, self.es = ook[0][0], ook[preamble_end][1] + self.putx([line, ['Preamble', 'Pre', 'P']]) + self.decode_pos += preamble_end + + if len(ook) > self.decode_pos + int(self.sync_length): + self.ss = self.es + self.es = ook[self.decode_pos + int(self.sync_length)][1] + self.putx([line, ['Sync', 'Syn', 'S']]) + self.decode_pos += int(self.sync_length) + 1 + + ookstring = self.ookstring[self.decode_pos:] + rem_nibbles = len(ookstring) // bits + for i in range(rem_nibbles): # Display the rest of nibbles. + self.ss = ook[self.decode_pos][0] + self.es = ook[self.decode_pos + bits - 1][1] + self.put_field(bits, line) + + def put_field(self, numbits, line): + param = self.ookstring[self.decode_pos:self.decode_pos + numbits] + if 'rev' in self.displayas: + param = param[::-1] # Reversed from right. + if not 'E' in param: # Format if no errors. + if 'Hex' in self.displayas: + param = hex(int(param, 2))[2:] + elif 'BCD' in self.displayas: + param = bcd2int(int(param, 2)) + self.putx([line, [str(param)]]) + self.decode_pos += numbits + + def display_all(self): + ookstring = '' + self.decode_pos = 0 + ook = self.decoded + for i in range(len(ook)): + self.ookstring += ook[i][2] + bits = 4 if 'Nibble' in self.displayas else 8 + rem_nibbles = len(self.ookstring) // bits + for i in range(rem_nibbles): # Display the rest of the nibbles. + self.ss = ook[self.decode_pos][0] + self.es = ook[self.decode_pos + bits - 1][1] + self.put_field(bits, 2) + + self.display_level2(bits, 4) # Display L2 decode. + + if (self.ref != 'off' and self.ref != 'show numbers' and + len(self.ookcache) >= int(self.ref)): # Compare traces. + ref = int(self.ref) - 1 + self.display_ref(self.trace_num, ref) + if len(self.ookcache) == int(self.ref): # Backfill. + for i in range(0, ref): + self.display_ref(i, ref) + elif self.ref == 'show numbers': # Display ref numbers. + self.ss = self.ookcache[self.trace_num][0][0] + end_sig = len(self.ookcache[self.trace_num]) - 1 + self.es = self.ookcache[self.trace_num][end_sig][1] + self.putx([1, [str(self.trace_num + 1)]]) + + def display_ref(self, t_num, ref): + display_len = len(self.ookcache[ref]) + if len(self.ookcache[t_num]) < len(self.ookcache[ref]): + display_len = len(self.ookcache[t_num]) + for i in range(display_len): + self.ss = self.ookcache[t_num][i][0] + self.es = self.ookcache[t_num][i][1] + self.putx([1, [self.ookcache[ref][i][2]]]) + + def add_to_cache(self): # Cache the OOK so it can be used as a reference. + self.ookcache.append(self.decoded) + + def decode(self, ss, es, data): + self.decoded = data + self.add_to_cache() + self.display_all() + self.ookstring = '' + self.trace_num += 1 + self.ss = ss + self.es = es + self.putp(data) # Send data up the stack. diff --git a/libsigrokdecode4DSL/decoders/pan1321/__init__.py b/libsigrokdecode4DSL/decoders/pan1321/__init__.py new file mode 100644 index 00000000..428fc91f --- /dev/null +++ b/libsigrokdecode4DSL/decoders/pan1321/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +''' +This decoder stacks on top of the 'uart' PD and decodes the Panasonic PAN1321 +Bluetooth module Serial Port Profile (SPP) protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/pan1321/pd.py b/libsigrokdecode4DSL/decoders/pan1321/pd.py new file mode 100644 index 00000000..6c931147 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/pan1321/pd.py @@ -0,0 +1,164 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012-2013 Uwe Hermann +## +## 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, see . +## + +import sigrokdecode as srd + +# ... +RX = 0 +TX = 1 + +class Decoder(srd.Decoder): + api_version = 3 + id = 'pan1321' + name = 'PAN1321' + longname = 'Panasonic PAN1321' + desc = 'Bluetooth RF module with Serial Port Profile (SPP).' + license = 'gplv2+' + inputs = ['uart'] + outputs = [] + tags = ['Wireless/RF'] + annotations = ( + ('text-verbose', 'Human-readable text (verbose)'), + ('text', 'Human-readable text'), + ('warnings', 'Human-readable warnings'), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.cmd = ['', ''] + self.ss_block = None + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + self.put(self.ss_block, self.es_block, self.out_ann, data) + + def handle_host_command(self, rxtx, s): + if s.startswith('AT+JAAC'): + # AT+JAAC= (0 or 1) + p = s[s.find('=') + 1:] + if p not in ('0', '1'): + self.putx([2, ['Warning: Invalid JAAC parameter "%s"' % p]]) + return + x = 'Auto' if (p == '1') else 'Don\'t auto' + self.putx([0, ['%s-accept new connections' % x]]) + self.putx([1, ['%s-accept connections' % x]]) + elif s.startswith('AT+JPRO'): + # AT+JPRO= (0 or 1) + p = s[s.find('=') + 1:] + if p not in ('0', '1'): + self.putx([2, ['Warning: Invalid JPRO parameter "%s"' % p]]) + return + onoff = 'off' if (p == '0') else 'on' + x = 'Leaving' if (p == '0') else 'Entering' + self.putx([0, ['%s production mode' % x]]) + self.putx([1, ['Production mode = %s' % onoff]]) + elif s.startswith('AT+JRES'): + # AT+JRES + if s != 'AT+JRES': # JRES has no params. + self.putx([2, ['Warning: Invalid JRES usage.']]) + return + self.putx([0, ['Triggering a software reset']]) + self.putx([1, ['Reset']]) + elif s.startswith('AT+JSDA'): + # AT+JSDA=, (l: length in bytes, d: data) + # l is (max?) 3 decimal digits and ranges from 1 to MTU size. + # Data can be ASCII or binary values (l bytes total). + l, d = s[s.find('=') + 1:].split(',') + if not l.isnumeric(): + self.putx([2, ['Warning: Invalid data length "%s".' % l]]) + if int(l) != len(d): + self.putx([2, ['Warning: Data length mismatch (%d != %d).' % \ + (int(l), len(d))]]) + # TODO: Warn if length > MTU size (which is firmware-dependent + # and is negotiated by both Bluetooth devices upon connection). + b = ''.join(['%02x ' % ord(c) for c in d])[:-1] + self.putx([0, ['Sending %d data bytes: %s' % (int(l), b)]]) + self.putx([1, ['Send %d = %s' % (int(l), b)]]) + elif s.startswith('AT+JSEC'): + # AT+JSEC=,,,, + # secmode: Security mode 1 or 3 (default). + # linkkey_info: Must be 1 or 2. Has no function according to docs. + # pintype: 1: variable pin (default), 2: fixed pin. + # pinlen: PIN length (2 decimal digits). Max. PIN length is 16. + # pin: The Bluetooth PIN ('pinlen' chars). Used if pintype=2. + # Note: AT+JSEC (if used) must be the first command after reset. + # TODO: Parse all the other parameters. + pin = s[-4:] + self.putx([0, ['Host set the Bluetooth PIN to "' + pin + '"']]) + self.putx([1, ['PIN = ' + pin]]) + elif s.startswith('AT+JSLN'): + # AT+JSLN=, + # namelen: Friendly name length (2 decimal digits). Max. len is 18. + # name: The Bluetooth "friendly name" ('namelen' ASCII characters). + name = s[s.find(',') + 1:] + self.putx([0, ['Host set the Bluetooth name to "' + name + '"']]) + self.putx([1, ['BT name = ' + name]]) + else: + self.putx([0, ['Host sent unsupported command: %s' % s]]) + self.putx([1, ['Unsupported command: %s' % s]]) + + def handle_device_reply(self, rxtx, s): + if s == 'ROK': + self.putx([0, ['Device initialized correctly']]) + self.putx([1, ['Init']]) + elif s == 'OK': + self.putx([0, ['Device acknowledged last command']]) + self.putx([1, ['ACK']]) + elif s.startswith('ERR'): + error = s[s.find('=') + 1:] + self.putx([0, ['Device sent error code ' + error]]) + self.putx([1, ['ERR = ' + error]]) + else: + self.putx([0, ['Device sent an unknown reply: %s' % s]]) + self.putx([1, ['Unknown reply: %s' % s]]) + + def decode(self, ss, es, data): + ptype, rxtx, pdata = data + + # For now, ignore all UART packets except the actual data packets. + if ptype != 'DATA': + return + + # We're only interested in the byte value (not individual bits). + pdata = pdata[0] + + # If this is the start of a command/reply, remember the start sample. + if self.cmd[rxtx] == '': + self.ss_block = ss + + # Append a new (ASCII) byte to the currently built/parsed command. + self.cmd[rxtx] += chr(pdata) + + # Get packets/bytes until an \r\n sequence is found (end of command). + if self.cmd[rxtx][-2:] != '\r\n': + return + + # Handle host commands and device replies. + # We remove trailing \r\n from the strings before handling them. + self.es_block = es + if rxtx == RX: + self.handle_device_reply(rxtx, self.cmd[rxtx][:-2]) + elif rxtx == TX: + self.handle_host_command(rxtx, self.cmd[rxtx][:-2]) + + self.cmd[rxtx] = '' diff --git a/libsigrokdecode4DSL/decoders/parallel/__init__.py b/libsigrokdecode4DSL/decoders/parallel/__init__.py new file mode 100644 index 00000000..100523ec --- /dev/null +++ b/libsigrokdecode4DSL/decoders/parallel/__init__.py @@ -0,0 +1,34 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2013 Uwe Hermann +## +## 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, see . +## + +''' +This protocol decoder can decode synchronous parallel buses with various +number of data bits/channels and one (optional) clock line. + +If no clock line is supplied, the decoder works slightly differently in +that it interprets every transition on any of the supplied data channels +like there had been a clock transition. + +It is required to use the lowest data channels, and use consecutive ones. +For example, for a 4-bit sync parallel bus, channels D0/D1/D2/D3 (and CLK) +should be used. Using combinations like D7/D12/D3/D15 is not supported. +For an 8-bit bus you should use D0-D7, for a 16-bit bus use D0-D15 and so on. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/parallel/pd.py b/libsigrokdecode4DSL/decoders/parallel/pd.py new file mode 100644 index 00000000..d7544c16 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/parallel/pd.py @@ -0,0 +1,213 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2013-2016 Uwe Hermann +## +## 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, see . +## + +import sigrokdecode as srd +from common.srdhelper import bitpack + +''' +OUTPUT_PYTHON format: + +Packet: +[, ] + +, + - 'ITEM', [, ] + - 'WORD', [, , ] + +: + - A single item (a number). It can be of arbitrary size. The max. number + of bits in this item is specified in . + +: + - The size of an item (in bits). For a 4-bit parallel bus this is 4, + for a 16-bit parallel bus this is 16, and so on. + +: + - A single word (a number). It can be of arbitrary size. The max. number + of bits in this word is specified in . The (exact) number + of items in this word is specified in . + +: + - The size of a word (in bits). For a 2-item word with 8-bit items + is 16, for a 3-item word with 4-bit items + is 12, and so on. + +: + - The size of a word (in number of items). For a 4-item word (no matter + how many bits each item consists of) is 4, for a 7-item + word is 7, and so on. +''' + +def channel_list(num_channels): + l = [{'id': 'clk', 'name': 'CLK', 'desc': 'Clock line'}] + for i in range(num_channels): + d = {'id': 'd%d' % i, 'name': 'D%d' % i, 'desc': 'Data line %d' % i} + l.append(d) + return tuple(l) + +class ChannelError(Exception): + pass + +NUM_CHANNELS = 8 + +class Decoder(srd.Decoder): + api_version = 3 + id = 'parallel' + name = 'Parallel' + longname = 'Parallel sync bus' + desc = 'Generic parallel synchronous bus.' + license = 'gplv2+' + inputs = ['logic'] + outputs = ['parallel'] + tags = ['Util'] + optional_channels = channel_list(NUM_CHANNELS) + options = ( + {'id': 'clock_edge', 'desc': 'Clock edge to sample on', + 'default': 'rising', 'values': ('rising', 'falling')}, + {'id': 'wordsize', 'desc': 'Data wordsize (# bus cycles)', + 'default': 0}, + {'id': 'endianness', 'desc': 'Data endianness', + 'default': 'little', 'values': ('little', 'big')}, + ) + annotations = ( + ('items', 'Items'), + ('words', 'Words'), + ) + annotation_rows = ( + ('items', 'Items', (0,)), + ('words', 'Words', (1,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.items = [] + self.saved_item = None + self.ss_item = self.es_item = None + self.saved_word = None + self.ss_word = self.es_word = None + self.first = True + + def start(self): + self.out_python = self.register(srd.OUTPUT_PYTHON) + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putpb(self, data): + self.put(self.ss_item, self.es_item, self.out_python, data) + + def putb(self, data): + self.put(self.ss_item, self.es_item, self.out_ann, data) + + def putpw(self, data): + self.put(self.ss_word, self.es_word, self.out_python, data) + + def putw(self, data): + self.put(self.ss_word, self.es_word, self.out_ann, data) + + def handle_bits(self, item, used_pins): + + # If a word was previously accumulated, then emit its annotation + # now after its end samplenumber became available. + if self.saved_word is not None: + if self.options['wordsize'] > 0: + self.es_word = self.samplenum + self.putw([1, [self.fmt_word.format(self.saved_word)]]) + self.putpw(['WORD', self.saved_word]) + self.saved_word = None + + # Defer annotations for individual items until the next sample + # is taken, and the previous sample's end samplenumber has + # become available. + if self.first: + # Save the start sample and item for later (no output yet). + self.ss_item = self.samplenum + self.first = False + self.saved_item = item + else: + # Output the saved item (from the last CLK edge to the current). + self.es_item = self.samplenum + self.putpb(['ITEM', self.saved_item]) + self.putb([0, [self.fmt_item.format(self.saved_item)]]) + self.ss_item = self.samplenum + self.saved_item = item + + # Get as many items as the configured wordsize specifies. + if not self.items: + self.ss_word = self.samplenum + self.items.append(item) + ws = self.options['wordsize'] + if len(self.items) < ws: + return + + # Collect words and prepare annotation details, but defer emission + # until the end samplenumber becomes available. + endian = self.options['endianness'] + if endian == 'big': + self.items.reverse() + word = sum([self.items[i] << (i * used_pins) for i in range(ws)]) + self.saved_word = word + self.items = [] + + def decode(self): + # Determine which (optional) channels have input data. Insist in + # a non-empty input data set. Cope with sparse connection maps. + # Store enough state to later "compress" sampled input data. + max_possible = len(self.optional_channels) + idx_channels = [ + idx if self.has_channel(idx) else None + for idx in range(max_possible) + ] + has_channels = [idx for idx in idx_channels if idx is not None] + if not has_channels: + raise ChannelError('At least one channel has to be supplied.') + max_connected = max(has_channels) + + # Determine .wait() conditions, depending on the presence of a + # clock signal. Either inspect samples on the configured edge of + # the clock, or inspect samples upon ANY edge of ANY of the pins + # which provide input data. + if self.has_channel(0): + edge = self.options['clock_edge'][0] + conds = {0: edge} + else: + conds = [{idx: 'e'} for idx in has_channels] + + # Pre-determine which input data to strip off, the width of + # individual items and multiplexed words, as well as format + # strings here. This simplifies call sites which run in tight + # loops later. + idx_strip = max_connected + 1 + num_item_bits = idx_strip - 1 + num_word_items = self.options['wordsize'] + num_word_bits = num_item_bits * num_word_items + num_digits = (num_item_bits + 3) // 4 + self.fmt_item = "{{:0{}x}}".format(num_digits) + num_digits = (num_word_bits + 3) // 4 + self.fmt_word = "{{:0{}x}}".format(num_digits) + + # Keep processing the input stream. Assume "always zero" for + # not-connected input lines. Pass data bits (all inputs except + # clock) to the handle_bits() method. + while True: + (clk, d0, d1, d2, d3, d4, d5, d6, d7) = self.wait(conds) + pins = (clk, d0, d1, d2, d3, d4, d5, d6, d7) + bits = [0 if idx is None else pins[idx] for idx in idx_channels] + item = bitpack(bits[1:idx_strip]) + self.handle_bits(item, num_item_bits) diff --git a/libsigrokdecode4DSL/decoders/pca9571/__init__.py b/libsigrokdecode4DSL/decoders/pca9571/__init__.py new file mode 100644 index 00000000..28152d93 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/pca9571/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Mickael Bosch +## +## 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, see . +## + +''' +This decoder stacks on top of the 'i2c' PD and decodes the NXP Semiconductors +PCA9571 8-bit I²C output expander protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/pca9571/pd.py b/libsigrokdecode4DSL/decoders/pca9571/pd.py new file mode 100644 index 00000000..df309e91 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/pca9571/pd.py @@ -0,0 +1,102 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Mickael Bosch +## +## 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, see . +## + +import sigrokdecode as srd + +NUM_OUTPUT_CHANNELS = 8 + +# TODO: Other I²C functions: general call / reset address, device ID address. + +class Decoder(srd.Decoder): + api_version = 3 + id = 'pca9571' + name = 'PCA9571' + longname = 'NXP PCA9571' + desc = 'NXP PCA9571 8-bit I²C output expander.' + license = 'gplv2+' + inputs = ['i2c'] + outputs = [] + tags = ['Embedded/industrial', 'IC'] + annotations = ( + ('register', 'Register type'), + ('value', 'Register value'), + ('warning', 'Warning messages'), + ) + annotation_rows = ( + ('regs', 'Registers', (0, 1)), + ('warnings', 'Warnings', (2,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.state = 'IDLE' + self.last_write = 0xFF # Chip port default state is high. + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + self.put(self.ss, self.es, self.out_ann, data) + + def handle_io(self, b): + if self.state == 'READ DATA': + operation = ['Outputs read', 'R'] + if b != self.last_write: + self.putx([2, ['Warning: read value and last write value ' + '(%02X) are different' % self.last_write]]) + else: + operation = ['Outputs set', 'W'] + self.last_write = b + self.putx([1, [operation[0] + ': %02X' % b, + operation[1] + ': %02X' % b]]) + + def check_correct_chip(self, addr): + if addr != 0x25: + self.putx([2, ['Warning: I²C slave 0x%02X not a PCA9571 ' + 'compatible chip.' % addr]]) + return False + return True + + def decode(self, ss, es, data): + cmd, databyte = data + self.ss, self.es = ss, es + + # State machine. + if cmd in ('ACK', 'BITS'): # Discard 'ACK' and 'BITS'. + pass + elif cmd in ('START', 'START REPEAT'): # Start a communication. + self.state = 'GET SLAVE ADDR' + elif cmd in ('NACK', 'STOP'): # Reset the state machine. + self.state = 'IDLE' + elif cmd in ('ADDRESS READ', 'ADDRESS WRITE'): + if ((self.state == 'GET SLAVE ADDR') and + self.check_correct_chip(databyte)): + if cmd == 'ADDRESS READ': + self.state = 'READ DATA' + else: + self.state = 'WRITE DATA' + else: + self.state = 'IDLE' + elif cmd in ('DATA READ', 'DATA WRITE'): + if self.state in ('READ DATA', 'WRITE DATA'): + self.handle_io(databyte) + else: + self.state = 'IDLE' diff --git a/libsigrokdecode4DSL/decoders/pjdl/__init__.py b/libsigrokdecode4DSL/decoders/pjdl/__init__.py new file mode 100644 index 00000000..c3cc8559 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/pjdl/__init__.py @@ -0,0 +1,27 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 Gerhard Sittig +## +## 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, see . +## + +''' +This protocol decoder interprets the PJDL data link of the PJON protocol. +Bytes and frames get extracted from single wire serial communication +(which often is referred to as "software bitbang" because that's what +the Arduino reference implementation happens to do). +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/pjdl/pd.py b/libsigrokdecode4DSL/decoders/pjdl/pd.py new file mode 100644 index 00000000..d5cc39f2 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/pjdl/pd.py @@ -0,0 +1,723 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 Gerhard Sittig +## +## 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, see . +## + +# See the https://www.pjon.org/ PJON project page and especially the +# https://www.pjon.org/PJDL-specification-v4.1.php PJDL v4.1 spec for +# the "Padded Jittering Data Link" single wire serial data link layer. + +# TODO +# - Improve (fix, and extend) carrier sense support. Detection of the +# idle/busy connection state is incomplete and fragile. Getting 'IDLE' +# operational in the PJDL decoder would greatly help the PJON decoder +# to flush ACK details before the start of new frames. +# - Check the correctness of timing assumptions. This implementation has +# support for tolerances, which the spec does not discuss. Though real +# world traffic was found to not decode at all with strict spec values +# and without tolerances, while communication peers were able to talk +# to each other. This needs more attention. +# - Check robustness when input data contains glitches. The spec does +# not discuss how to handle these. Data bit sampling happens to work +# because their value is taken at the center of the bit time. But +# pad bits suffer badly from glitches, which breaks frame inspection +# as well. +# - Cleanup the decoder implementation in general terms. Some details +# have become obsolete ("edges", "pads"), and/or are covered by other +# code paths. +# - Implement more data link decoders which can feed their output into +# the PJON protocol decoder. Candidates are: PJDLR, PJDLS, TSDL. +# - Determine whether or not the data link layer should interpret any +# frame content. From my perspective it should not, and needs not in +# the strict sense. Possible gains would be getting the (expected!) +# packet length, or whether a synchronous response is requested. But +# this would duplicate knowledge which should remain internal to the +# PJON decoder. And this link layer decoder neither shall assume that +# the input data would be correct, or complete. Instead the decoder +# shall remain usable on captures which demonstrate faults, and be +# helpful in pointing them out. The design goal is to extract the +# maximum of information possible, and pass it on as transparently +# as possible. + +import sigrokdecode as srd +from common.srdhelper import bitpack +from math import ceil, floor + +''' +OUTPUT_PYTHON format for stacked decoders: + +General packet format: +[, ] + +This is the list of s and their respective values: + +Carrier sense: +- 'IDLE': is the pin level (always 0). +- 'BUSY': is always True. + +Raw bit slots: +- 'PAD_BIT': is the pin level (always 1). +- 'DATA_BIT': is the pin level (0, or 1). +- 'SHORT_BIT': is the pin level (always 1). +- 'SYNC_LOSS': is an arbitrary text (internal use only). + +Date bytes and frames: +- 'SYNC_PAD': is True. Spans the high pad bit as well as the + low data bit. +- 'DATA_BYTE': is the byte value (0..255). +- 'FRAME_INIT': is True. Spans three sync pads. +- 'FRAME_DATA': is the sequence of bytes in the frame. Non-data + phases in the frame get represented by strings instead of numbers + ('INIT', 'SYNC', 'SHORT', 'WAIT'). Frames can be incomplete, depending + on the decoder's input data. +- 'SYNC_RESP_WAIT': is always True. + +Notice that this link layer decoder is not aware of frame content. Will +neither check packet length, nor variable width fields, nor verify the +presence of requested synchronous responses. Cannot tell the sequence of +frame bytes then ACK bytes (without wait phase) from just frame bytes. +An upper layer protocol decoder will interpret content, the link layer +decoder remains as transparent as possible, and will neither assume +correct nor complete input data. +''' + +# Carrier sense, and synchronization loss implementation is currently +# incomplete, and results in too many too short annotations, some of +# them spurious and confusing. TODO Improve the implementation. +_with_ann_carrier = False +_with_ann_sync_loss = False + +PIN_DATA, = range(1) +ANN_CARRIER_BUSY, ANN_CARRIER_IDLE, \ +ANN_PAD_BIT, ANN_LOW_BIT, ANN_DATA_BIT, ANN_SHORT_DATA, ANN_SYNC_LOSS, \ +ANN_DATA_BYTE, \ +ANN_FRAME_INIT, ANN_FRAME_BYTES, ANN_FRAME_WAIT, \ + = range(11) + +class SamplerateError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = 'pjdl' + name = 'PJDL' + longname = 'Padded Jittering Data Link' + desc = 'PJDL, a single wire serial link layer for PJON.' + license = 'gplv2+' + inputs = ['logic'] + outputs = ['pjon_link'] + tags = ['Embedded/industrial'] + channels = ( + {'id': 'data' , 'name': 'DATA', 'desc': 'Single wire data'}, + ) + options = ( + {'id': 'mode', 'desc': 'Communication mode', + 'default': 1, 'values': (1, 2, 3, 4)}, + {'id': 'idle_add_us', 'desc': 'Added idle time (us)', 'default': 4}, + ) + annotations = ( + ('cs_busy', 'Carrier busy'), + ('cs_idle', 'Carrier idle'), + ('bit_pad', 'Pad bit'), + ('bit_low', 'Low bit'), + ('bit_data', 'Data bit'), + ('bit_short', 'Short data'), + ('sync_loss', 'Sync loss'), + ('byte', 'Data byte'), + ('frame_init', 'Frame init'), + ('frame_bytes', 'Frame bytes'), + ('frame_wait', 'Frame wait'), + ) + annotation_rows = ( + ('carriers', 'Carriers', (ANN_CARRIER_BUSY, ANN_CARRIER_IDLE,)), + ('bits', 'Bits', (ANN_PAD_BIT, ANN_LOW_BIT, ANN_DATA_BIT, ANN_SHORT_DATA,)), + ('bytes', 'Bytes', (ANN_FRAME_INIT, ANN_DATA_BYTE, ANN_FRAME_WAIT,)), + ('frames', 'Frames', (ANN_FRAME_BYTES,)), + ('warns', 'Warnings', (ANN_SYNC_LOSS,)), + ) + + # Communication modes' data bit and pad bit duration (in us), and + # tolerances in percent and absolute (us). + mode_times = { + 1: (44, 116), + 2: (40, 92), + 3: (28, 88), + 4: (26, 60), + } + time_tol_perc = 10 + time_tol_abs = 1.5 + + def __init__(self): + self.reset() + + def reset(self): + self.reset_state() + + def reset_state(self): + self.carrier_want_idle = True + self.carrier_is_busy = False + self.carrier_is_idle = False + self.carrier_idle_ss = None + self.carrier_busy_ss = None + self.syncpad_fall_ss = None + + self.edges = None + self.symbols = None + self.sync_pads = None + self.data_bits = None + self.frame_bytes = None + self.short_bits = None + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_python = self.register(srd.OUTPUT_PYTHON) + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + self.span_prepare() + + def putg(self, ss, es, data): + cls = data[0] + if not _with_ann_carrier and cls in (ANN_CARRIER_BUSY, ANN_CARRIER_IDLE): + return + if not _with_ann_sync_loss and cls in (ANN_SYNC_LOSS,): + return + self.put(ss, es, self.out_ann, data) + + def putpy(self, ss, es, ptype, pdata): + self.put(ss, es, self.out_python, [ptype, pdata]) + + def symbols_clear(self): + syms = self.symbols or [] + self.symbols = [] + return syms + + def symbols_append(self, ss, es, symbol, data = None): + if self.symbols is None: + self.symbols = [] + item = (ss, es, symbol, data) + self.symbols.append(item) + + def symbols_get_last(self, count = None): + if not self.symbols: + return None + if count is None: + count = 1 + if len(self.symbols) < count: + return None + items = self.symbols[-count:] + if count == 1: + items = items[0] + return items + + def symbols_update_last(self, ss, es, symbol, data = None): + if not self.symbols: + return None + item = list(self.symbols[-1]) + if ss is not None: + item[0] = ss + if es is not None: + item[1] = es + if symbol is not None: + item[2] = symbol + if data is not None: + item[3] = data + self.symbols[-1] = tuple(item) + + def symbols_has_prev(self, want_items): + if not isinstance(want_items, (list, tuple,)): + want_items = [want_items] + if self.symbols is None: + return False + if len(self.symbols) < len(want_items): + return False + sym_off = len(self.symbols) - len(want_items) + for idx, want_item in enumerate(want_items): + if self.symbols[sym_off + idx][2] != want_item: + return False + return True + + def symbols_collapse(self, count, symbol, data = None, squeeze = None): + if self.symbols is None: + return None + if len(self.symbols) < count: + return None + self.symbols, last_data = self.symbols[:-count], self.symbols[-count:] + while squeeze and self.symbols and self.symbols[-1][2] == squeeze: + last_data.insert(0, self.symbols.pop()) + ss, es = last_data[0][0], last_data[-1][1] + if data is None: + data = last_data + item = (ss, es, symbol, data) + self.symbols.append(item) + + def frame_flush(self): + syms = self.symbols_clear() + while syms and syms[0][2] == 'IDLE': + syms.pop(0) + while syms and syms[-1][2] == 'IDLE': + syms.pop(-1) + if not syms: + return + text = [] + data = [] + for sym in syms: + if sym[2] == 'FRAME_INIT': + text.append('INIT') + data.append('INIT') + continue + if sym[2] == 'SYNC_PAD': + if not text or text[-1] != 'SYNC': + text.append('SYNC') + data.append('SYNC') + continue + if sym[2] == 'DATA_BYTE': + b = [bit[3] for bit in sym[3] if bit[2] == 'DATA_BIT'] + b = bitpack(b) + text.append('{:02x}'.format(b)) + data.append(b) + continue + if sym[2] == 'SHORT_BIT': + if not text or text[-1] != 'SHORT': + text.append('SHORT') + data.append('SHORT') + continue + if sym[2] == 'WAIT_ACK': + text.append('WAIT') + data.append('WAIT') + continue + text = ' '.join(text) + ss, es = syms[0][0], syms[-1][1] + self.putg(ss, es, [ANN_FRAME_BYTES, [text]]) + self.putpy(ss, es, 'FRAME_DATA', data) + + def carrier_flush(self): + # Force annotations if BUSY started, or if IDLE tracking started + # and kept running for long enough. This will be called before + # internal state reset, so we won't manipulate internal variables, + # and can afford to emit annotations which haven't met their + # proper end condition yet. + if self.carrier_busy_ss: + ss, es = self.carrier_busy_ss, self.samplenum + self.putg(ss, es, [ANN_CARRIER_BUSY, ['BUSY']]) + if self.carrier_idle_ss: + ss, es = self.carrier_idle_ss, self.samplenum + ss += int(self.idle_width) + if ss < es: + self.putg(ss, es, [ANN_CARRIER_IDLE, ['IDLE']]) + + def carrier_set_idle(self, on, ss, es): + if on: + # IDLE starts here, or continues. + if not self.carrier_idle_ss: + self.carrier_idle_ss = int(ss) + if not self.symbols_has_prev('IDLE'): + self.symbols_append(ss, ss, 'IDLE') + self.symbols_update_last(None, es, None) + # HACK We have seen an IDLE condition. This implementation + # loses details which are used to track IDLE, but it's more + # important to start accumulation of a new frame here. + self.frame_flush() + self.reset_state() + # end of HACK + self.carrier_is_idle = True + self.carrier_want_idle = False + return + # IDLE ends here. + if self.symbols_has_prev('IDLE'): + self.symbols_update_last(None, es, None) + self.carrier_flush() + self.carrier_is_idle = False + self.carrier_idle_ss = None + + def carrier_set_busy(self, on, snum): + self.carrier_is_busy = on + if on: + self.carrier_is_idle = None + if not self.carrier_busy_ss: + self.carrier_busy_ss = snum + return + if self.carrier_busy_ss: + self.putg(self.carrier_busy_ss, snum, [ANN_CARRIER_BUSY, ['BUSY']]) + self.carrier_busy_ss = None + self.carrier_is_busy = False + + def carrier_check(self, level, snum): + + # When HIGH is seen, immediately end IDLE and switch to BUSY. + if level: + self.carrier_set_idle(False, snum, snum) + self.carrier_set_busy(True, snum) + return + + # LOW is seen. Start tracking an IDLE period if not done yet. + if not self.carrier_idle_ss: + self.carrier_idle_ss = int(snum) + + # End BUSY when LOW persisted for an exact data byte's length. + # Start IDLE when LOW persisted for a data byte's length plus + # the user specified additional period. + span = snum - self.carrier_idle_ss + if span >= self.byte_width: + self.carrier_set_busy(False, snum) + if span >= self.idle_width: + self.carrier_set_idle(True, self.carrier_idle_ss + self.idle_width, snum) + + def span_prepare(self): + '''Prepare calculation of durations in terms of samples.''' + + # Determine samples per microsecond, and sample counts for + # several bit types, and sample count for a data byte's + # length, including optional extra time. Determine ranges + # for bit widths (tolerance margin). + + # Get times in microseconds. + mode_times = self.mode_times[self.options['mode']] + mode_times = [t * 1.0 for t in mode_times] + self.data_width, self.pad_width = mode_times + self.byte_width = self.pad_width + 9 * self.data_width + self.add_idle_width = self.options['idle_add_us'] + self.idle_width = self.byte_width + self.add_idle_width + + # Derive ranges (add tolerance) and scale to sample counts. + self.usec_width = self.samplerate / 1e6 + self.hold_high_width = 9 * self.time_tol_abs * self.usec_width + + def _get_range(width): + reladd = self.time_tol_perc / 100 + absadd = self.time_tol_abs + lower = min(width * (1 - reladd), width - absadd) + upper = max(width * (1 + reladd), width + absadd) + lower = floor(lower * self.usec_width) + upper = ceil(upper * self.usec_width) + return (lower, upper + 1) + + self.data_bit_1_range = _get_range(self.data_width * 1) + self.data_bit_2_range = _get_range(self.data_width * 2) + self.data_bit_3_range = _get_range(self.data_width * 3) + self.data_bit_4_range = _get_range(self.data_width * 4) + self.short_data_range = _get_range(self.data_width / 4) + self.pad_bit_range = _get_range(self.pad_width) + + self.data_width *= self.usec_width + self.pad_width *= self.usec_width + self.byte_width *= self.usec_width + self.idle_width *= self.usec_width + + self.lookahead_width = int(4 * self.data_width) + + def span_snum_to_us(self, count): + return count / self.usec_width + + def span_is_pad(self, span): + return span in range(*self.pad_bit_range) + + def span_is_data(self, span): + if span in range(*self.data_bit_1_range): + return 1 + if span in range(*self.data_bit_2_range): + return 2 + if span in range(*self.data_bit_3_range): + return 3 + if span in range(*self.data_bit_4_range): + return 4 + return False + + def span_is_short(self, span): + return span in range(*self.short_data_range) + + def wait_until(self, want): + '''Wait until a given location, but keep sensing carrier.''' + + # Implementor's note: Avoids skip values below 1. This version + # "may overshoot" by one sample. Which should be acceptable for + # this specific use case (can put the sample point of a bit time + # out of the center by some 4% under worst case conditions). + + want = int(want) + while True: + diff = max(want - self.samplenum, 1) + pins = self.wait([{PIN_DATA: 'e'}, {'skip': diff}]) + self.carrier_check(pins[PIN_DATA], self.samplenum) + if self.samplenum >= want: + return pins + # UNREACH + + def decode(self): + if not self.samplerate or self.samplerate < 1e6: + raise SamplerateError('Need a samplerate of at least 1MSa/s') + + # As a special case the first low period in the input capture is + # saught regardless of whether we can see its falling edge. This + # approach is also used to recover after synchronization was lost. + # + # The important condition here in the main loop is: Get the next + # edge's position, but time out after a maximum period of four + # data bits. This allows for the detection of SYNC pulses, also + # responds "soon enough" to DATA bits where edges can be few + # within a data byte. Also avoids excessive waits for unexpected + # communication errors. + # + # DATA bits within a byte are taken at fixed intervals relative + # to the SYNC-PAD's falling edge. It's essential to check the + # carrier at every edge, also during DATA bit sampling. Simple + # skips to the desired sample point could break that feature. + while True: + + # Help kick-start the IDLE condition detection after + # decoder state reset. + if not self.edges: + curr_level, = self.wait({PIN_DATA: 'l'}) + self.carrier_check(curr_level, self.samplenum) + self.edges = [self.samplenum] + continue + + # Advance to the next edge, or over a medium span without an + # edge. Prepare to classify the distance to derive bit types + # from these details. + last_snum = self.samplenum + curr_level, = self.wait([{PIN_DATA: 'e'}, {'skip': self.lookahead_width}]) + self.carrier_check(curr_level, self.samplenum) + bit_level = curr_level + edge_seen = self.matched[0] + if edge_seen: + bit_level = 1 - bit_level + if not self.edges: + self.edges = [self.samplenum] + continue + self.edges.append(self.samplenum) + curr_snum = self.samplenum + + # Check bit width (can also be multiple data bits). + span = self.edges[-1] - self.edges[-2] + is_pad = bit_level and self.span_is_pad(span) + is_data = self.span_is_data(span) + is_short = bit_level and self.span_is_short(span) + + if is_pad: + # BEWARE! Use ss value of last edge (genuinely seen, or + # inserted after a DATA byte) for PAD bit annotations. + ss, es = self.edges[-2], curr_snum + texts = ['PAD', '{:d}'.format(bit_level)] + self.putg(ss, es, [ANN_PAD_BIT, texts]) + self.symbols_append(ss, es, 'PAD_BIT', bit_level) + ss, es = self.symbols_get_last()[:2] + self.putpy(ss, es, 'PAD_BIT', bit_level) + continue + + if is_short: + ss, es = last_snum, curr_snum + texts = ['SHORT', '{:d}'.format(bit_level)] + self.putg(ss, es, [ANN_SHORT_DATA, texts]) + self.symbols_append(ss, es, 'SHORT_BIT', bit_level) + ss, es = self.symbols_get_last()[:2] + self.putpy(ss, es, 'SHORT_BIT', bit_level) + continue + + # Force IDLE period check when the decoder seeks to sync + # to the input data stream. + if not bit_level and not self.symbols and self.carrier_want_idle: + continue + + # Accept arbitrary length LOW phases after DATA bytes(!) or + # SHORT pulses, but not within a DATA byte or SYNC-PAD etc. + # This covers the late start of the next SYNC-PAD (byte of + # a frame, or ACK byte after a frame, or the start of the + # next frame). + if not bit_level: + if self.symbols_has_prev('DATA_BYTE'): + continue + if self.symbols_has_prev('SHORT_BIT'): + continue + if self.symbols_has_prev('WAIT_ACK'): + continue + + # Get (consume!) the LOW DATA bit after a PAD. + took_low = False + if is_data and not bit_level and self.symbols_has_prev('PAD_BIT'): + took_low = True + is_data -= 1 + next_snum = int(last_snum + self.data_width) + ss, es = last_snum, next_snum + texts = ['ZERO', '{:d}'.format(bit_level)] + self.putg(ss, es, [ANN_LOW_BIT, texts]) + self.symbols_append(ss, es, 'ZERO_BIT', bit_level) + ss, es = self.symbols_get_last()[:2] + self.putpy(ss, es, 'DATA_BIT', bit_level) + self.data_fall_time = last_snum + last_snum = next_snum + # Turn the combination of PAD and LOW DATA into SYNC-PAD. + # Start data bit accumulation after a SYNC-PAD was seen. + sync_pad_seq = ['PAD_BIT', 'ZERO_BIT'] + if self.symbols_has_prev(sync_pad_seq): + self.symbols_collapse(len(sync_pad_seq), 'SYNC_PAD') + ss, es = self.symbols_get_last()[:2] + self.putpy(ss, es, 'SYNC_PAD', True) + self.data_bits = [] + # Turn three subsequent SYNC-PAD into FRAME-INIT. Start the + # accumulation of frame bytes when FRAME-INIT was seen. + frame_init_seq = 3 * ['SYNC_PAD'] + if self.symbols_has_prev(frame_init_seq): + self.symbols_collapse(len(frame_init_seq), 'FRAME_INIT') + # Force a flush of the previous frame after we have + # reliably detected the start of another one. This is a + # workaround for this decoder's inability to detect the + # end of a frame after an ACK was seen or byte counts + # have been reached. We cannot assume perfect input, + # thus we leave all interpretation of frame content to + # upper layers. Do keep the recently queued FRAME_INIT + # symbol across the flush operation. + if len(self.symbols) > 1: + keep = self.symbols.pop(-1) + self.frame_flush() + self.symbols.clear() + self.symbols.append(keep) + ss, es = self.symbols_get_last()[:2] + texts = ['FRAME INIT', 'INIT', 'I'] + self.putg(ss, es, [ANN_FRAME_INIT, texts]) + self.putpy(ss, es, 'FRAME_INIT', True) + self.frame_bytes = [] + # Collapse SYNC-PAD after SHORT+ into a WAIT-ACK. Include + # all leading SHORT bits in the WAIT as well. + wait_ack_seq = ['SHORT_BIT', 'SYNC_PAD'] + if self.symbols_has_prev(wait_ack_seq): + self.symbols_collapse(len(wait_ack_seq), 'WAIT_ACK', + squeeze = 'SHORT_BIT') + ss, es = self.symbols_get_last()[:2] + texts = ['WAIT for sync response', 'WAIT response', 'WAIT', 'W'] + self.putg(ss, es, [ANN_FRAME_WAIT, texts]) + self.putpy(ss, es, 'SYNC_RESP_WAIT', True) + if took_low and not is_data: + # Start at the very next edge if we just consumed a LOW + # after a PAD bit, and the DATA bit count is exhausted. + # This improves robustness, deals with inaccurate edge + # positions. (Motivated by real world captures, the spec + # would not discuss bit time tolerances.) + continue + + # When we get here, the only remaining (the only supported) + # activity is the collection of a data byte's DATA bits. + # These are not taken by the main loop's "edge search, with + # a timeout" approach, which is "too tolerant". Instead all + # DATA bits get sampled at a fixed interval and relative to + # the SYNC-PAD's falling edge. We expect to have seen the + # data byte' SYNC-PAD before. If we haven't, the decoder is + # not yet synchronized to the input data. + if not is_data: + fast_cont = edge_seen and curr_level + ss, es = last_snum, curr_snum + texts = ['failed pulse length check', 'pulse length', 'length'] + self.putg(ss, es, [ANN_SYNC_LOSS, texts]) + self.frame_flush() + self.carrier_flush() + self.reset_state() + if fast_cont: + self.edges = [self.samplenum] + continue + if not self.symbols_has_prev('SYNC_PAD'): + # Fast reponse to the specific combination of: no-sync, + # edge seen, and current high level. In this case we + # can reset internal state, but also can continue the + # interpretation right after the most recently seen + # rising edge, which could start the next PAD time. + # Otherwise continue slow interpretation after reset. + fast_cont = edge_seen and curr_level + self.frame_flush() + self.carrier_flush() + self.reset_state() + if fast_cont: + self.edges = [self.samplenum] + continue + + # The main loop's "edge search with period timeout" approach + # can have provided up to three more DATA bits after the LOW + # bit of the SYNC-PAD. Consume them immediately in that case, + # otherwise .wait() for their sample point. Stick with float + # values for bit sample points and bit time boundaries for + # improved accuracy, only round late to integers when needed. + bit_field = [] + bit_ss = self.data_fall_time + self.data_width + for bit_idx in range(8): + bit_es = bit_ss + self.data_width + bit_snum = (bit_es + bit_ss) / 2 + if bit_snum > self.samplenum: + bit_level, = self.wait_until(bit_snum) + ss, es = ceil(bit_ss), floor(bit_es) + texts = ['{:d}'.format(bit_level)] + self.putg(ss, es, [ANN_DATA_BIT, texts]) + self.symbols_append(ss, es, 'DATA_BIT', bit_level) + ss, es = self.symbols_get_last()[:2] + self.putpy(ss, es, 'DATA_BIT', bit_level) + bit_field.append(bit_level) + if self.data_bits is not None: + self.data_bits.append(bit_level) + bit_ss = bit_es + end_snum = bit_es + curr_level, = self.wait_until(end_snum) + curr_snum = self.samplenum + + # We are at the exact _calculated_ boundary of the last DATA + # bit time. Improve robustness for those situations where + # the transmitter's and the sender's timings differ within a + # margin, and the transmitter may hold the last DATA bit's + # HIGH level for a little longer. + # + # When no falling edge is seen within the maximum tolerance + # for the last DATA bit, then this could be the combination + # of a HIGH DATA bit and a PAD bit without a LOW in between. + # Fake an edge in that case, to re-use existing code paths. + # Make sure to keep referencing times to the last SYNC pad's + # falling edge. This is the last reliable condition we have. + if curr_level: + hold = self.hold_high_width + curr_level, = self.wait([{PIN_DATA: 'l'}, {'skip': int(hold)}]) + self.carrier_check(curr_level, self.samplenum) + if self.matched[1]: + self.edges.append(curr_snum) + curr_level = 1 - curr_level + curr_snum = self.samplenum + + # Get the byte value from the bits (when available). + # TODO Has the local 'bit_field' become obsolete, or should + # self.data_bits go away? + data_byte = bitpack(bit_field) + if self.data_bits is not None: + data_byte = bitpack(self.data_bits) + self.data_bits.clear() + if self.frame_bytes is not None: + self.frame_bytes.append(data_byte) + + # Turn a sequence of a SYNC-PAD and eight DATA bits into a + # DATA-BYTE symbol. + byte_seq = ['SYNC_PAD'] + 8 * ['DATA_BIT'] + if self.symbols_has_prev(byte_seq): + self.symbols_collapse(len(byte_seq), 'DATA_BYTE') + ss, es = self.symbols_get_last()[:2] + texts = ['{:02x}'.format(data_byte)] + self.putg(ss, es, [ANN_DATA_BYTE, texts]) + self.putpy(ss, es, 'DATA_BYTE', data_byte) + + # Optionally terminate the accumulation of a frame when a + # WAIT-ACK period was followed by a DATA-BYTE? This could + # flush the current packet before the next FRAME-INIT or + # IDLE are seen, and increases usability for short input + # data (aggressive trimming). It won't help when WAIT is + # not seen, though. + sync_resp_seq = ['WAIT_ACK'] + ['DATA_BYTE'] + if self.symbols_has_prev(sync_resp_seq): + self.frame_flush() diff --git a/libsigrokdecode4DSL/decoders/pjon/__init__.py b/libsigrokdecode4DSL/decoders/pjon/__init__.py new file mode 100644 index 00000000..579fb591 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/pjon/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 Gerhard Sittig +## +## 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, see . +## + +''' +This protocol decoder interprets the PJON protocol on top of the PJDL +link layer (and potentially other link layers). +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/pjon/pd.py b/libsigrokdecode4DSL/decoders/pjon/pd.py new file mode 100644 index 00000000..b23cfb84 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/pjon/pd.py @@ -0,0 +1,603 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 Gerhard Sittig +## +## 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, see . +## + +# See the https://www.pjon.org/ PJON project page and especially the +# https://www.pjon.org/PJON-protocol-specification-v3.2.php protocol +# specification, which can use different link layers. + +# TODO +# - Check for the correct order of optional fields (the spec is not as +# explicit on these details as I'd expect). +# - Check decoder's robustness, completeness, and correctness when more +# captures become available. Currently there are only few, which only +# cover minimal communication, and none of the protocol's flexibility. +# The decoder was essentially written based on the available docs, and +# then took some arbitrary choices and liberties to cope with real life +# data from an example setup. Strictly speaking this decoder violates +# the spec, and errs towards the usability side. + +import sigrokdecode as srd +import struct + +ANN_RX_INFO, ANN_HDR_CFG, ANN_PKT_LEN, ANN_META_CRC, ANN_TX_INFO, \ +ANN_SVC_ID, ANN_PKT_ID, ANN_ANON_DATA, ANN_PAYLOAD, ANN_END_CRC, \ +ANN_SYN_RSP, \ +ANN_RELATION, \ +ANN_WARN, \ + = range(13) + +def calc_crc8(data): + crc = 0 + for b in data: + crc ^= b + for i in range(8): + odd = crc % 2 + crc >>= 1 + if odd: + crc ^= 0x97 + return crc + +def calc_crc32(data): + crc = 0xffffffff + for b in data: + crc ^= b + for i in range(8): + odd = crc % 2 + crc >>= 1 + if odd: + crc ^= 0xedb88320 + crc ^= 0xffffffff + return crc + +class Decoder(srd.Decoder): + api_version = 3 + id = 'pjon' + name = 'PJON' + longname = 'PJON' + desc = 'The PJON protocol.' + license = 'gplv2+' + inputs = ['pjon_link'] + outputs = [] + tags = ['Embedded/industrial'] + annotations = ( + ('rx_info', 'Receiver ID'), + ('hdr_cfg', 'Header config'), + ('pkt_len', 'Packet length'), + ('meta_crc', 'Meta CRC'), + ('tx_info', 'Sender ID'), + ('port', 'Service ID'), + ('pkt_id', 'Packet ID'), + ('anon', 'Anonymous data'), + ('payload', 'Payload'), + ('end_crc', 'End CRC'), + ('syn_rsp', 'Sync response'), + ('relation', 'Relation'), + ('warning', 'Warning'), + ) + annotation_rows = ( + ('fields', 'Fields', ( + ANN_RX_INFO, ANN_HDR_CFG, ANN_PKT_LEN, ANN_META_CRC, ANN_TX_INFO, + ANN_SVC_ID, ANN_ANON_DATA, ANN_PAYLOAD, ANN_END_CRC, ANN_SYN_RSP, + )), + ('relations', 'Relations', (ANN_RELATION,)), + ('warnings', 'Warnings', (ANN_WARN,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.reset_frame() + + def reset_frame(self): + self.frame_ss = None + self.frame_es = None + self.frame_rx_id = None + self.frame_tx_id = None + self.frame_payload_text = None + self.frame_bytes = None + self.frame_has_ack = None + self.ack_bytes = None + self.ann_ss = None + self.ann_es = None + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putg(self, ss, es, ann, data): + self.put(ss, es, self.out_ann, [ann, data]) + + def frame_flush(self): + if not self.frame_bytes: + return + if not self.frame_ss or not self.frame_es: + return + + # Emit "communication relation" details. + # TODO Include the service ID (port number) as well? + text = [] + if self.frame_rx_id is not None: + text.append("RX {}".format(self.frame_rx_id[-1])) + if self.frame_tx_id is not None: + text.append("TX {}".format(self.frame_tx_id[-1])) + if self.frame_payload_text is not None: + text.append("DATA {}".format(self.frame_payload_text)) + if self.frame_has_ack is not None: + text.append("ACK {:02x}".format(self.frame_has_ack)) + if text: + text = " - ".join(text) + self.putg(self.frame_ss, self.frame_es, ANN_RELATION, [text]) + + def handle_field_get_desc(self, idx = None): + '''Lookup description of a PJON frame field.''' + if not self.field_desc: + return None + if idx is None: + idx = self.field_desc_idx + if idx >= 0 and idx >= len(self.field_desc): + return None + if idx < 0 and abs(idx) > len(self.field_desc): + return None + desc = self.field_desc[idx] + return desc + + def handle_field_add_desc(self, fmt, hdl, cls = None): + '''Register description for a PJON frame field.''' + item = { + 'format': fmt, + 'width': struct.calcsize(fmt), + 'handler': hdl, + 'anncls': cls, + } + self.field_desc.append(item) + + def handle_field_seed_desc(self): + '''Seed list of PJON frame fields' descriptions.''' + + # At the start of a PJON frame, the layout of only two fields + # is known. Subsequent fields (their presence, and width) depend + # on the content of the header config field. + + self.field_desc = [] + self.handle_field_add_desc(' 15 and not self.cfg_crc32: + warn_texts.append('length above 15 needs CRC32') + if pl_len < 1: + warn_texts.append('suspicious payload length') + pl_len = 0 + if warn_texts: + warn_texts = ', '.join(warn_texts) + self.putg(self.ann_ss, self.ann_es, ANN_WARN, [warn_texts]) + pl_fmt = '>{:d}B'.format(pl_len) + + desc = self.handle_field_get_desc(-2) + desc['format'] = pl_fmt + desc['width'] = struct.calcsize(pl_fmt) + + # Have the caller emit the annotation for the packet length. + # Provide information of different detail level for zooming. + texts = [ + 'LENGTH {:d} (PAYLOAD {:d})'.format(pkt_len, pl_len), + 'LEN {:d} (PL {:d})'.format(pkt_len, pl_len), + '{:d} ({:d})'.format(pkt_len, pl_len), + '{:d}'.format(pkt_len), + ] + return texts + + def handle_field_common_crc(self, have, is_meta): + '''Process a CRC field of a PJON frame.''' + + # CRC algorithm and width are configurable, and can differ + # across meta and end checksums in a frame's fields. + caption = 'META' if is_meta else 'END' + crc_len = 8 if is_meta else 32 if self.cfg_crc32 else 8 + crc_bytes = crc_len // 8 + crc_fmt = '{:08x}' if crc_len == 32 else '{:02x}' + have_text = crc_fmt.format(have) + + # Check received against expected checksum. Emit warnings. + warn_texts = [] + data = self.frame_bytes[:-crc_bytes] + want = calc_crc32(data) if crc_len == 32 else calc_crc8(data) + if want != have: + want_text = crc_fmt.format(want) + warn_texts.append('CRC mismatch - want {} have {}'.format(want_text, have_text)) + if warn_texts: + warn_texts = ', '.join(warn_texts) + self.putg(self.ann_ss, self.ann_es, ANN_WARN, [warn_texts]) + + # Provide text representation for frame field, caller emits + # the annotation. + texts = [ + '{}_CRC {}'.format(caption, have_text), + 'CRC {}'.format(have_text), + have_text, + ] + return texts + + def handle_field_meta_crc(self, b): + '''Process initial CRC (meta) field of a PJON frame.''' + # Caller provides a list of values. We want a single scalar. + b = b[0] + return self.handle_field_common_crc(b, True) + + def handle_field_end_crc(self, b): + '''Process end CRC (total frame) field of a PJON frame.''' + # Caller provides a list of values. We want a single scalar. + b = b[0] + return self.handle_field_common_crc(b, False) + + def handle_field_common_bus(self, b): + '''Common handling of bus ID details. Used for RX and TX.''' + bus_id = b[:4] + bus_num = struct.unpack('>L', bytearray(bus_id)) + bus_txt = '.'.join(['{:d}'.format(b) for b in bus_id]) + return bus_num, bus_txt + + def handle_field_rx_bus(self, b): + '''Process receiver bus ID field of a PJON frame.''' + + # When we get here, there always should be an RX ID already. + bus_num, bus_txt = self.handle_field_common_bus(b[:4]) + rx_txt = "{} {}".format(bus_txt, self.frame_rx_id[-1]) + self.frame_rx_id = (bus_num, self.frame_rx_id[0], rx_txt) + + # Provide text representation for frame field, caller emits + # the annotation. + texts = [ + 'RX_BUS {}'.format(bus_txt), + bus_txt, + ] + return texts + + def handle_field_tx_bus(self, b): + '''Process transmitter bus ID field of a PJON frame.''' + + # The TX ID field is optional, as is the use of bus ID fields. + # In the TX info case the TX bus ID is seen before the TX ID. + bus_num, bus_txt = self.handle_field_common_bus(b[:4]) + self.frame_tx_id = (bus_num, None, bus_txt) + + # Provide text representation for frame field, caller emits + # the annotation. + texts = [ + 'TX_BUS {}'.format(bus_txt), + bus_txt, + ] + return texts + + def handle_field_tx_id(self, b): + '''Process transmitter ID field of a PJON frame.''' + + b = b[0] + + id_txt = "{:d}".format(b) + if self.frame_tx_id is None: + self.frame_tx_id = (b, id_txt) + else: + tx_txt = "{} {}".format(self.frame_tx_id[-1], id_txt) + self.frame_tx_id = (self.frame_tx_id[0], b, tx_txt) + + # Provide text representation for frame field, caller emits + # the annotation. + texts = [ + 'TX_ID {}'.format(id_txt), + id_txt, + ] + return texts + + def handle_field_payload(self, b): + '''Process payload data field of a PJON frame.''' + + text = ' '.join(['{:02x}'.format(v) for v in b]) + self.frame_payload = b[:] + self.frame_payload_text = text + + texts = [ + 'PAYLOAD {}'.format(text), + text, + ] + return texts + + def handle_field_sync_resp(self, b): + '''Process synchronous response for a PJON frame.''' + + self.frame_has_ack = b + + texts = [ + 'ACK {:02x}'.format(b), + '{:02x}'.format(b), + ] + return texts + + def decode(self, ss, es, data): + ptype, pdata = data + + # Start frame bytes accumulation when FRAME_INIT is seen. Flush + # previously accumulated frame bytes when a new frame starts. + if ptype == 'FRAME_INIT': + self.frame_flush() + self.reset_frame() + self.frame_bytes = [] + self.handle_field_seed_desc() + self.frame_ss = ss + self.frame_es = es + return + + # Use IDLE as another (earlier) trigger to flush frames. Also + # trigger flushes on FRAME-DATA which mean that the link layer + # inspection has seen the end of a protocol frame. + # + # TODO Improve usability? Emit warnings for PJON frames where + # FRAME_DATA was seen but FRAME_INIT wasn't? So that users can + # become aware of broken frames. + if ptype in ('IDLE', 'FRAME_DATA'): + self.frame_flush() + self.reset_frame() + return + + # Switch from data bytes to response bytes when WAIT is seen. + if ptype == 'SYNC_RESP_WAIT': + self.ack_bytes = [] + self.ann_ss, self.ann_es = None, None + return + + # Accumulate data bytes as they arrive. Put them in the bucket + # which corresponds to its most recently seen leader. + if ptype == 'DATA_BYTE': + b = pdata + self.frame_es = es + + # Are we collecting response bytes (ACK)? + if self.ack_bytes is not None: + if not self.ann_ss: + self.ann_ss = ss + self.ack_bytes.append(b) + self.ann_es = es + text = self.handle_field_sync_resp(b) + if text: + self.putg(self.ann_ss, self.ann_es, ANN_SYN_RSP, text) + self.ann_ss, self.ann_es = None, None + return + + # Are we collecting frame content? + if self.frame_bytes is not None: + if not self.ann_ss: + self.ann_ss = ss + self.frame_bytes.append(b) + self.ann_es = es + + # Has the field value become available yet? + desc = self.handle_field_get_desc() + if not desc: + return + width = desc.get('width', None) + if not width: + return + self.field_desc_got += 1 + if self.field_desc_got != width: + return + + # Grab most recent received field as a byte array. Get + # the values that it contains. + fmt = desc.get('format', '>B') + raw = bytearray(self.frame_bytes[-width:]) + values = struct.unpack(fmt, raw) + + # Process the value, and get its presentation. Can be + # mere formatting, or serious execution of logic. + hdl = desc.get('handler', '{!r}') + if isinstance(hdl, str): + text = [hdl.format(*values)] + elif isinstance(hdl, (list, tuple)): + text = [f.format(*values) for f in hdl] + elif hdl: + text = hdl(values) + cls = desc.get('anncls', ANN_ANON_DATA) + + # Emit annotation unless the handler routine already did. + if cls is not None and text: + self.putg(self.ann_ss, self.ann_es, cls, text) + self.ann_ss, self.ann_es = None, None + + # Advance scan position for to-get-received field. + self.field_desc_idx += 1 + self.field_desc_got = 0 + return + + # Unknown phase, not collecting. Not synced yet to the input? + return + + # Unknown or unhandled kind of link layer output. + return diff --git a/libsigrokdecode4DSL/decoders/ps2/__init__.py b/libsigrokdecode4DSL/decoders/ps2/__init__.py new file mode 100644 index 00000000..75c47687 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ps2/__init__.py @@ -0,0 +1,26 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2016 Daniel Schulte +## +## 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, see . +## + +''' +This protocol decoder can decode PS/2 device -> host communication. + +Host -> device communication is currently not supported. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/ps2/pd.py b/libsigrokdecode4DSL/decoders/ps2/pd.py new file mode 100644 index 00000000..fc6972bb --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ps2/pd.py @@ -0,0 +1,193 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2016 Daniel Schulte +## Copyright (C) 2019 DreamSourceLab +## +## 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, see . +## + +import sigrokdecode as srd +from collections import namedtuple + +class Ann: + BIT, HSTART, DSTART, STOP, PARITY_OK, PARITY_ERR, DATA, WORD, ACK = range(9) + +Bit = namedtuple('Bit', 'val ss es') + +class Decoder(srd.Decoder): + api_version = 3 + id = 'ps2' + name = 'PS/2' + longname = 'PS/2' + desc = 'PS/2 keyboard/mouse interface.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['PC'] + channels = ( + {'id': 'clk', 'type': 0, 'name': 'Clock', 'desc': 'Clock line'}, + {'id': 'data', 'type': 107, 'name': 'Data', 'desc': 'Data line'}, + ) + options = ( + {'id': 'HtoD_Clock', 'desc': 'HtoD_Clock', + 'default': 'rise', 'values': ('rise', 'fall')}, + {'id': 'DtoH_Clock', 'desc': 'DtoH_Clock', + 'default': 'fall', 'values': ('fall', 'rise')}, + ) + annotations = ( + ('207', 'bit', 'Bit'), + ('109', 'HSTART', 'HSTART'), + ('50', 'DSTART', 'DSTART'), + ('1000', 'stop-bit', 'Stop bit'), + ('7', 'parity-ok', 'Parity OK bit'), + ('1000', 'parity-err', 'Parity error bit'), + ('40', 'data-bit', 'Data bit'), + ('65', 'word', 'Word'), + ('75', 'ACK', 'ACK'), + ) + annotation_rows = ( + ('bits', 'Bits', (0,)), + ('fields', 'Fields', (1, 2, 3, 4, 5, 6, 7, 8)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.bits = [] + self.samplenum = 0 + self.bitcount = 0 + self.state = 'NULL' + self.ss = self.es = 0 + self.HtoDss = 0 + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.HtoD = 1 if self.options['HtoD_Clock'] == 'rise' else 0 + self.DtoH = 1 if self.options['DtoH_Clock'] == 'fall' else 0 + def putb(self, bit, ann_idx): + b = self.bits[bit] + self.put(b.ss, b.es, self.out_ann, [ann_idx, [str(b.val)]]) + + def putx(self, bit, ann): + self.put(self.bits[bit].ss, self.bits[bit].es, self.out_ann, ann) + + def handle_bits(self, datapin): + # Ignore non start condition bits (useful during keyboard init). + if self.bitcount == 0 and datapin == 1: + self.state = 'HtoD' + (clock_pin, datapin) = self.wait({0: 'r'}) + + + # Store individual bits and their start/end samplenumbers. + self.bits.append(Bit(datapin, self.samplenum, self.samplenum)) + + # Fix up end sample numbers of the bits. + if self.bitcount > 0: + b = self.bits[self.bitcount - 1] + self.bits[self.bitcount - 1] = Bit(b.val, b.ss, self.samplenum) + if self.bitcount == 11: + self.bitwidth = self.bits[1].es - self.bits[2].es + b = self.bits[-1] + self.bits[-1] = Bit(b.val, b.ss, b.es + self.bitwidth) + + # Find all 11 bits. Start + 8 data + odd parity + stop. + if self.bitcount < 11: + self.bitcount += 1 + return + + # Extract data word. + word = 0 + for i in range(8): + word |= (self.bits[i + 1].val << i) + + # Calculate parity. + parity_ok = (bin(word).count('1') + self.bits[9].val) % 2 == 1 + + # Emit annotations. + for i in range(11): + self.putb(i, Ann.BIT) + if self.state == 'HtoD': + self.putx(0, [Ann.HSTART, ['Host Start', 'HStart', 'HS']]) + if self.state == 'DtoH': + self.putx(0, [Ann.DSTART, ['Device Start', 'Device', 'DS']]) + self.put(self.bits[1].ss, self.bits[8].es, self.out_ann, [Ann.WORD, + ['Data: %02x' % word, 'D: %02x' % word, '%02x' % word]]) + if parity_ok: + self.putx(9, [Ann.PARITY_OK, ['Parity OK', 'Par OK', 'P']]) + else: + self.putx(9, [Ann.PARITY_ERR, ['Parity error', 'Par err', 'PE']]) + self.putx(10, [Ann.STOP, ['Stop bit', 'Stop', 'St', 'T']]) + + self.bits, self.bitcount = [], 0 + self.state == 'NULL' + + def decode(self): + while True: + # Sample data bits on falling clock edge. + if self.bitcount == 0: + if self.HtoDss : + self.state = 'HtoD' + (clock_pin, data_pin) = self.wait({0: 'r',1: 'l'}) + self.handle_bits(data_pin) + (clock_pin, data_pin) = self.wait({0: 'f'}) + else: + (clock_pin, data_pin) = self.wait([{0: 'f',1: 'r'},{0: 'f',1: 'f'},{0: 'f',1: 'h'},{0: 'f',1: 'l'}]) + if (self.matched & (0b1 << 0)): + continue + if (self.matched & (0b1 << 1)): + self.state = 'HtoD' + (clock_pin, data_pin) = self.wait({0: 'r',1: 'l'}) + self.handle_bits(data_pin) + (clock_pin, data_pin) = self.wait({0: 'f'}) + if (self.matched & (0b1 << 2)): + self.state = 'HtoD' + (clock_pin, data_pin) = self.wait({0: 'r',1: 'l'}) + self.handle_bits(data_pin) + (clock_pin, data_pin) = self.wait({0: 'f'}) + if (self.matched & (0b1 << 3)): + self.state = 'DtoH' + self.handle_bits(data_pin) + if self.state == 'HtoD': + if self.HtoD : + (clock_pin, data_pin) = self.wait({0: 'r'}) + else: + (clock_pin, data_pin) = self.wait({0: 'f'}) + self.handle_bits(data_pin) + if (self.bitcount == 10): + (clock_pin, data_pin) = self.wait({0: 'r'}) + self.handle_bits(data_pin) + if (self.bitcount == 11): + (clock_pin, data_pin) = self.wait({0: 'f'}) + self.handle_bits(data_pin) + self.ss = self.samplenum + (clock_pin, data_pin) = self.wait({0: 'r'}) + self.es = self.samplenum + self.put(self.ss,self.es,self.out_ann,[Ann.ACK, ['ACK', 'ACK', 'ACK', 'A']]) + self.HtoDss = 0 + if self.state == 'DtoH': + if self.DtoH : + (clock_pin, data_pin) = self.wait({0: 'f'}) + else: + (clock_pin, data_pin) = self.wait({0: 'r'}) + self.handle_bits(data_pin) + if (self.bitcount == 11): + (clock_pin, data_pin) = self.wait([{1: 'f'},{0: 'r'}]) + if (self.matched & (0b1 << 0)): + self.handle_bits(data_pin) + self.HtoDss = 1 + if (self.matched & (0b1 << 1)): + self.handle_bits(data_pin) + self.HtoDss = 0 \ No newline at end of file diff --git a/libsigrokdecode4DSL/decoders/pwm/__init__.py b/libsigrokdecode4DSL/decoders/pwm/__init__.py new file mode 100644 index 00000000..8f039766 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/pwm/__init__.py @@ -0,0 +1,24 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Torsten Duwe +## +## 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, see . +## + +''' +Pulse-width modulation (PWM) a.k.a pulse-duration modulation (PDM) decoder. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/pwm/pd.py b/libsigrokdecode4DSL/decoders/pwm/pd.py new file mode 100644 index 00000000..d8626ee0 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/pwm/pd.py @@ -0,0 +1,141 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Torsten Duwe +## Copyright (C) 2014 Sebastien Bourdelin +## +## 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, see . +## + +import sigrokdecode as srd + +class SamplerateError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = 'pwm' + name = 'PWM' + longname = 'Pulse-width modulation' + desc = 'Analog level encoded in duty cycle percentage.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Encoding'] + channels = ( + {'id': 'data', 'name': 'Data', 'desc': 'Data line'}, + ) + options = ( + {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-high', + 'values': ('active-low', 'active-high')}, + ) + annotations = ( + ('duty-cycle', 'Duty cycle'), + ('period', 'Period'), + ) + annotation_rows = ( + ('duty-cycle', 'Duty cycle', (0,)), + ('period', 'Period', (1,)), + ) + binary = ( + ('raw', 'RAW file'), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.ss_block = self.es_block = None + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_binary = self.register(srd.OUTPUT_BINARY) + self.out_average = \ + self.register(srd.OUTPUT_META, + meta=(float, 'Average', 'PWM base (cycle) frequency')) + + def putx(self, data): + self.put(self.ss_block, self.es_block, self.out_ann, data) + + def putp(self, period_t): + # Adjust granularity. + if period_t == 0 or period_t >= 1: + period_s = '%.1f s' % (period_t) + elif period_t <= 1e-12: + period_s = '%.1f fs' % (period_t * 1e15) + elif period_t <= 1e-9: + period_s = '%.1f ps' % (period_t * 1e12) + elif period_t <= 1e-6: + period_s = '%.1f ns' % (period_t * 1e9) + elif period_t <= 1e-3: + period_s = '%.1f μs' % (period_t * 1e6) + else: + period_s = '%.1f ms' % (period_t * 1e3) + + self.put(self.ss_block, self.es_block, self.out_ann, [1, [period_s]]) + + def putb(self, data): + self.put(self.ss_block, self.es_block, self.out_binary, data) + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + + num_cycles = 0 + average = 0 + + # Wait for an "active" edge (depends on config). This starts + # the first full period of the inspected signal waveform. + self.wait({0: 'f' if self.options['polarity'] == 'active-low' else 'r'}) + self.first_samplenum = self.samplenum + + # Keep getting samples for the period's middle and terminal edges. + # At the same time that last sample starts the next period. + while True: + + # Get the next two edges. Setup some variables that get + # referenced in the calculation and in put() routines. + start_samplenum = self.samplenum + self.wait({0: 'e'}) + end_samplenum = self.samplenum + self.wait({0: 'e'}) + self.ss_block = start_samplenum + self.es_block = self.samplenum + + # Calculate the period, the duty cycle, and its ratio. + period = self.samplenum - start_samplenum + duty = end_samplenum - start_samplenum + ratio = float(duty / period) + + # Report the duty cycle in percent. + percent = float(ratio * 100) + self.putx([0, ['%f%%' % percent]]) + + # Report the duty cycle in the binary output. + self.putb([0, bytes([int(ratio * 256)])]) + + # Report the period in units of time. + period_t = float(period / self.samplerate) + self.putp(period_t) + + # Update and report the new duty cycle average. + num_cycles += 1 + average += percent + self.put(self.first_samplenum, self.es_block, self.out_average, + float(average / num_cycles)) diff --git a/libsigrokdecode4DSL/decoders/qi/__init__.py b/libsigrokdecode4DSL/decoders/qi/__init__.py new file mode 100644 index 00000000..0d49d17b --- /dev/null +++ b/libsigrokdecode4DSL/decoders/qi/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Josef Gajdusek +## +## 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, see . +## + +''' +This decoder decodes demodulated data streams used by the Qi standard +for communication from the receiver to the charging station. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/qi/pd.py b/libsigrokdecode4DSL/decoders/qi/pd.py new file mode 100644 index 00000000..b750d9ce --- /dev/null +++ b/libsigrokdecode4DSL/decoders/qi/pd.py @@ -0,0 +1,244 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Josef Gajdusek +## +## 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, see . +## + +import sigrokdecode as srd +import operator +import collections +from functools import reduce + +end_codes = ( + 'Unknown', + 'Charge Complete', + 'Internal Fault', + 'Over Temperature', + 'Over Voltage', + 'Over Current', + 'Battery Failure', + 'Reconfigure', + 'No Response', +) + +class SamplerateError(Exception): + pass + +def calc_checksum(packet): + return reduce(operator.xor, packet[:-1]) + +def bits_to_uint(bits): + # LSB first + return reduce(lambda i, v: (i >> 1) | (v << (len(bits) - 1)), bits, 0) + +class Decoder(srd.Decoder): + api_version = 3 + id = 'qi' + name = 'Qi' + longname = 'Qi charger protocol' + desc = 'Protocol used by Qi receiver.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Embedded/industrial', 'Wireless/RF'] + channels = ( + {'id': 'qi', 'name': 'Qi', 'desc': 'Demodulated Qi data line'}, + ) + annotations = ( + ('bits', 'Bits'), + ('bytes-errors', 'Bit errors'), + ('bytes-start', 'Start bits'), + ('bytes-info', 'Info bits'), + ('bytes-data', 'Data bytes'), + ('packets-data', 'Packet data'), + ('packets-checksum-ok', 'Packet checksum'), + ('packets-checksum-err', 'Packet checksum'), + ) + annotation_rows = ( + ('bits', 'Bits', (0,)), + ('bytes', 'Bytes', (1, 2, 3, 4)), + ('packets', 'Packets', (5, 6, 7)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.reset_variables() + + def reset_variables(self): + self.counter = 0 + self.prev = None + self.state = 'IDLE' + self.lastbit = 0 + self.bytestart = 0 + self.deq = collections.deque(maxlen = 2) + self.bits = [] + self.bitsi = [0] + self.bytesi = [] + self.packet = [] + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + self.bit_width = float(self.samplerate) / 2e3 + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.reset_variables() + + def packet_len(self, byte): + if 0x00 <= byte <= 0x1f: + return int(1 + (byte - 0) / 32) + if 0x20 <= byte <= 0x7f: + return int(2 + (byte - 32) / 16) + if 0x80 <= byte <= 0xdf: + return int(8 + (byte - 128) / 8) + if 0xe0 <= byte <= 0xff: + return int(20 + (byte - 224) / 4) + + def in_tolerance(self, l): + return (0.75 * self.bit_width) < l < (1.25 * self.bit_width) + + def putp(self, data): + self.put(self.bytesi[0], self.bytesi[-1], self.out_ann, [5, data]) + + def process_packet(self): + if self.packet[0] == 0x01: # Signal Strength + self.putp(['Signal Strength: %d' % self.packet[1], + 'SS: %d' % self.packet[1], 'SS']) + elif self.packet[0] == 0x02: # End Power Transfer + reason = end_codes[self.packet[1]] if self.packet[1] < len(end_codes) else 'Reserved' + self.putp(['End Power Transfer: %s' % reason, + 'EPT: %s' % reason, 'EPT']) + elif self.packet[0] == 0x03: # Control Error + val = self.packet[1] if self.packet[1] < 128 else (self.packet[1] & 0x7f) - 128 + self.putp(['Control Error: %d' % val, 'CE: %d' % val, 'CE']) + elif self.packet[0] == 0x04: # Received Power + self.putp(['Received Power: %d' % self.packet[1], + 'RP: %d' % self.packet[1], 'RP']) + elif self.packet[0] == 0x05: # Charge Status + self.putp(['Charge Status: %d' % self.packet[1], + 'CS: %d' % self.packet[1], 'CS']) + elif self.packet[0] == 0x06: # Power Control Hold-off + self.putp(['Power Control Hold-off: %dms' % self.packet[1], + 'PCH: %d' % self.packet[1]], 'PCH') + elif self.packet[0] == 0x51: # Configuration + powerclass = (self.packet[1] & 0xc0) >> 7 + maxpower = self.packet[1] & 0x3f + prop = (self.packet[3] & 0x80) >> 7 + count = self.packet[3] & 0x07 + winsize = (self.packet[4] & 0xf8) >> 3 + winoff = self.packet[4] & 0x07 + self.putp(['Configuration: Power Class = %d, Maximum Power = %d, Prop = %d,' + 'Count = %d, Window Size = %d, Window Offset = %d' % + (powerclass, maxpower, prop, count, winsize, winoff), + 'C: PC = %d MP = %d P = %d C = %d WS = %d WO = %d' % + (powerclass, maxpower, prop, count, winsize, winoff), + 'Configuration', 'C']) + elif self.packet[0] == 0x71: # Identification + version = '%d.%d' % ((self.packet[1] & 0xf0) >> 4, self.packet[1] & 0x0f) + mancode = '%02x%02x' % (self.packet[2], self.packet[3]) + devid = '%02x%02x%02x%02x' % (self.packet[4] & ~0x80, + self.packet[5], self.packet[6], self.packet[7]) + self.putp(['Identification: Version = %s, Manufacturer = %s, ' \ + 'Device = %s' % (version, mancode, devid), + 'ID: %s %s %s' % (version, mancode, devid), 'ID']) + elif self.packet[0] == 0x81: # Extended Identification + edevid = '%02x%02x%02x%02x%02x%02x%02x%02x' % self.packet[1:-1] + self.putp(['Extended Identification: %s' % edevid, + 'EI: %s' % edevid, 'EI']) + elif self.packet[0] in (0x18, 0x19, 0x28, 0x29, 0x38, 0x48, 0x58, 0x68, + 0x78, 0x85, 0xa4, 0xc4, 0xe2): # Proprietary + self.putp(['Proprietary', 'P']) + else: # Unknown + self.putp(['Unknown', '?']) + self.put(self.bytesi[-1], self.samplenum, self.out_ann, + [6, ['Checksum OK', 'OK']] if \ + calc_checksum(self.packet) == self.packet[-1] + else [6, ['Checksum error', 'ERR']]) + + def process_byte(self): + self.put(self.bytestart, self.bitsi[0], self.out_ann, + ([2, ['Start bit', 'Start', 'S']]) if self.bits[0] == 0 else + ([1, ['Start error', 'Start err', 'SE']])) + databits = self.bits[1:9] + data = bits_to_uint(databits) + parity = reduce(lambda i, v: (i + v) % 2, databits, 1) + self.put(self.bitsi[0], self.bitsi[8], self.out_ann, [4, ['%02x' % data]]) + self.put(self.bitsi[8], self.bitsi[9], self.out_ann, + ([3, ['Parity bit', 'Parity', 'P']]) if self.bits[9] == parity else + ([1, ['Parity error', 'Parity err', 'PE']])) + self.put(self.bitsi[9], self.bitsi[10], self.out_ann, + ([3, ['Stop bit', 'Stop', 'S']]) if self.bits[10] == 1 else + ([1, ['Stop error', 'Stop err', 'SE']])) + + self.bytesi.append(self.bytestart) + self.packet.append(data) + if self.packet_len(self.packet[0]) + 2 == len(self.packet): + self.process_packet() + self.bytesi.clear() + self.packet.clear() + + def add_bit(self, bit): + self.bits.append(bit) + self.bitsi.append(self.samplenum) + + if self.state == 'IDLE' and len(self.bits) >= 5 and \ + self.bits[-5:] == [1, 1, 1, 1, 0]: + self.state = 'DATA' + self.bytestart = self.bitsi[-2] + self.bits = [0] + self.bitsi = [self.samplenum] + self.packet.clear() + elif self.state == 'DATA' and len(self.bits) == 11: + self.process_byte() + self.bytestart = self.samplenum + self.bits.clear() + self.bitsi.clear() + if self.state != 'IDLE': + self.put(self.lastbit, self.samplenum, self.out_ann, [0, ['%d' % bit]]) + self.lastbit = self.samplenum + + def handle_transition(self, l, htl): + self.deq.append(l) + if len(self.deq) >= 2 and \ + (self.in_tolerance(self.deq[-1] + self.deq[-2]) or \ + htl and self.in_tolerance(l * 2) and \ + self.deq[-2] > 1.25 * self.bit_width): + self.add_bit(1) + self.deq.clear() + elif self.in_tolerance(l): + self.add_bit(0) + self.deq.clear() + elif l > (1.25 * self.bit_width): + self.state = 'IDLE' + self.bytesi.clear() + self.packet.clear() + self.bits.clear() + self.bitsi.clear() + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + + (qi,) = self.wait() + self.handle_transition(self.samplenum, qi == 0) + while True: + prev = self.samplenum + (qi,) = self.wait({0: 'e'}) + self.handle_transition(self.samplenum - prev, qi == 0) diff --git a/libsigrokdecode4DSL/decoders/qspi/__init__.py b/libsigrokdecode4DSL/decoders/qspi/__init__.py new file mode 100644 index 00000000..10b74234 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/qspi/__init__.py @@ -0,0 +1,31 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2016 fenugrec +## +## 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, see . +## + +''' +This protocol decoder decodes the AUD (Advanced User Debugger) interface +of certain Renesas / Hitachi microcontrollers, when set in Branch Trace mode. + +AUD has two modes, this PD currently only supports "Branch Trace" mode. + +Details: +http://www.renesas.eu/products/mpumcu/superh/sh7050/sh7058/Documentation.jsp +("rej09b0046 - SH7058 Hardware manual") +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/qspi/pd.py b/libsigrokdecode4DSL/decoders/qspi/pd.py new file mode 100644 index 00000000..e0aa4f2a --- /dev/null +++ b/libsigrokdecode4DSL/decoders/qspi/pd.py @@ -0,0 +1,226 @@ +### +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 DreamSourceLab +## +## 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, see . +## + +import sigrokdecode as srd +from collections import namedtuple + +Data = namedtuple('Data', ['ss', 'es', 'val']) + + +# Key: (CPOL, CPHA). Value: SPI mode. +# Clock polarity (CPOL) = 0/1: Clock is low/high when inactive. +# Clock phase (CPHA) = 0/1: Data is valid on the leading/trailing clock edge. +spi_mode = { + (0, 0): 0, # Mode 0 + (0, 1): 1, # Mode 1 + (1, 0): 2, # Mode 2 + (1, 1): 3, # Mode 3 +} + +class ChannelError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = 'qspi' + name = 'QSPI' + longname = 'Quad Serial Peripheral Interface' + desc = 'Full-duplex, synchronous, serial bus.' + license = 'gplv2+' + inputs = ['logic'] + outputs = ['spi'] + tags = ['Embedded/industrial'] + channels = ( + {'id': 'clk', 'type': 0, 'name': 'CLK', 'desc': 'Clock'}, + {'id': 'io0', 'type': 107, 'name': 'IO0', 'desc': 'Data i/o 0'}, + ) + optional_channels = ( + {'id': 'io1', 'type': 107, 'name': 'IO1', 'desc': 'Data i/o 1'}, + {'id': 'io2', 'type': 107, 'name': 'IO2', 'desc': 'Data i/o 2'}, + {'id': 'io3', 'type': 107, 'name': 'IO3', 'desc': 'Data i/o 3'}, + {'id': 'cs', 'type': -1, 'name': 'CS#', 'desc': 'Chip-select'}, + ) + options = ( + {'id': 'cs_polarity', 'desc': 'CS# polarity', 'default': 'active-low', + 'values': ('active-low', 'active-high')}, + {'id': 'cpol', 'desc': 'Clock polarity (CPOL)', 'default': 0, + 'values': (0, 1)}, + {'id': 'cpha', 'desc': 'Clock phase (CPHA)', 'default': 0, + 'values': (0, 1)}, + {'id': 'bitorder', 'desc': 'Bit order', + 'default': 'msb-first', 'values': ('msb-first', 'lsb-first')}, + {'id': 'wordsize', 'desc': 'Word size', 'default': 8}, + ) + annotations = ( + ('106', 'data', 'data'), + ) + annotation_rows = ( + ('data', 'data', (0,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.bitcount = 0 + self.data = 0 + self.bits = [] + self.ss_block = -1 + self.samplenum = -1 + self.ss_transfer = -1 + self.cs_was_deasserted = False + self.have_cs = self.have_io1 = self.have_io3 = None + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.bw = (self.options['wordsize'] + 7) // 8 + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def putw(self, data): + self.put(self.ss_block, self.samplenum, self.out_ann, data) + + def putdata(self): + # Pass bits and then data to the next PD up the stack. + ss, es = self.bits[-1][1], self.bits[0][2] + + # Dataword annotations. + self.put(ss, es, self.out_ann, [0, ['%02X' % self.data]]) + + def reset_decoder_state(self): + self.data = 0 + self.bits = [] + self.bitcount = 0 + + def cs_asserted(self, cs): + active_low = (self.options['cs_polarity'] == 'active-low') + return (cs == 0) if active_low else (cs == 1) + + def handle_bit(self, datapins, clk, cs): + # If this is the first bit of a dataword, save its sample number. + if self.bitcount == 0: + self.ss_block = self.samplenum + self.cs_was_deasserted = \ + not self.cs_asserted(cs) if self.have_cs else False + + bo = self.options['bitorder'] + ws = self.options['wordsize'] + if self.have_io3: + nibws = ws >> 2 + elif self.have_io1: + nibws = ws >> 1 + else: + nibws = ws + + # Receive bit into our shift register. + if self.have_io3: + for i in range(4): + if bo == 'msb-first': + self.data |= datapins[i] << (ws - 1 - self.bitcount*4 - i) + else: + self.data |= datapins[3-i] << (self.bitcount*4 + i) + elif self.have_io1: + for i in range(2): + if bo == 'msb-first': + self.data |= datapins[i+2] << (ws - 1 - self.bitcount*2 - i) + else: + self.data |= datapins[3-i] << (self.bitcount*2 + i) + else: + if bo == 'msb-first': + self.data |= datapins[3] << (ws - 1 - self.bitcount) + else: + self.data |= datapins[3] << self.bitcount + + # Guesstimate the endsample for this bit (can be overridden below). + es = self.samplenum + if self.bitcount > 0: + es += self.samplenum - self.bits[0][1] + + self.bits.insert(0, [datapins[3], self.samplenum, es]) + + if self.bitcount > 0: + self.bits[1][2] = self.samplenum + + self.bitcount += 1 + + # Continue to receive if not enough bits were received, yet. + if self.bitcount != nibws: + return + + self.putdata() + + self.reset_decoder_state() + + def find_clk_edge(self, datapins, clk, cs, first): + if self.have_cs and (first or (self.matched & (0b1 << self.have_cs))): + # Send all CS# pin value changes. + oldcs = None if first else 1 - cs + + # Reset decoder state when CS# changes (and the CS# pin is used). + self.reset_decoder_state() + + # We only care about samples if CS# is asserted. + if self.have_cs and not self.cs_asserted(cs): + return + + # Ignore sample if the clock pin hasn't changed. + if first or not (self.matched & (0b1 << 0)): + return + + # Found the correct clock edge, now get the SPI bit(s). + self.handle_bit(datapins, clk, cs) + + def decode(self): + # The CLK & IO0 input is mandatory. Other signals are (individually) + # optional. Tell stacked decoders when we don't have a CS# signal. + if not self.has_channel(0): + raise ChannelError('CLK pin required.') + self.have_io1 = self.has_channel(2) + self.have_io3 = self.has_channel(3) & self.has_channel(4) + self.have_cs = self.has_channel(5) + + # We want all CLK changes. We want all CS changes if CS is used. + # Map 'have_cs' from boolean to an integer index. This simplifies + # evaluation in other locations. + # Sample data on rising/falling clock edge (depends on mode). + mode = spi_mode[self.options['cpol'], self.options['cpha']] + if mode == 0 or mode == 3: # Sample on rising clock edge + wait_cond = [{0: 'r'}] + else: # Sample on falling clock edge + wait_cond = [{0: 'f'}] + + if self.have_cs: + self.have_cs = len(wait_cond) + wait_cond.append({5: 'e'}) + + # "Pixel compatibility" with the v2 implementation. Grab and + # process the very first sample before checking for edges. The + # previous implementation did this by seeding old values with + # None, which led to an immediate "change" in comparison. + (clk, d0, d1, d2, d3, cs) = self.wait({}) + d = (d3, d2, d1, d0); + self.find_clk_edge(d, clk, cs, True) + + while True: + (clk, d0, d1, d2, d3, cs) = self.wait(wait_cond) + d = (d3, d2, d1, d0); + self.find_clk_edge(d, clk, cs, False)# diff --git a/libsigrokdecode4DSL/decoders/rc_encode/__init__.py b/libsigrokdecode4DSL/decoders/rc_encode/__init__.py new file mode 100644 index 00000000..db78dc1e --- /dev/null +++ b/libsigrokdecode4DSL/decoders/rc_encode/__init__.py @@ -0,0 +1,36 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Steve R +## +## 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, see . +## + +''' +This PD decodes the remote control protocol which is frequently used +within key fobs and power socket remotes. + +They contain encoding chips like the PT2262 which converts the button +pressed and address settings into a series of pulses which is then +transmitted over whatever frequency and modulation that the designer +chooses. These devices operate at a number of frequencies including 433MHz. + +This PD should also decode the HX2262 and SC5262 which are equivalents. + +The decoder also contains some additional decoding for a Maplin L95AR +remote control and will turn the received signal into which button was +pressed and what the address code DIP switches are set to. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/rc_encode/pd.py b/libsigrokdecode4DSL/decoders/rc_encode/pd.py new file mode 100644 index 00000000..daeca092 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/rc_encode/pd.py @@ -0,0 +1,167 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Steve R +## +## 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, see . +## + +import sigrokdecode as srd + +bitvals = ('0', '1', 'f', 'U') + +def decode_bit(edges): + # Datasheet says long pulse is 3 times short pulse. + lmin = 2 # long min multiplier + lmax = 5 # long max multiplier + eqmin = 0.5 # equal min multiplier + eqmax = 1.5 # equal max multiplier + if ( # 0 -___-___ + (edges[1] >= edges[0] * lmin and edges[1] <= edges[0] * lmax) and + (edges[2] >= edges[0] * eqmin and edges[2] <= edges[0] * eqmax) and + (edges[3] >= edges[0] * lmin and edges[3] <= edges[0] * lmax)): + return '0' + elif ( # 1 ---_---_ + (edges[0] >= edges[1] * lmin and edges[0] <= edges[1] * lmax) and + (edges[0] >= edges[2] * eqmin and edges[0] <= edges[2] * eqmax) and + (edges[0] >= edges[3] * lmin and edges[0] <= edges[3] * lmax)): + return '1' + elif ( # float ---_-___ + (edges[1] >= edges[0] * lmin and edges[1] <= edges[0] * lmax) and + (edges[2] >= edges[0] * lmin and edges[2] <= edges[0]* lmax) and + (edges[3] >= edges[0] * eqmin and edges[3] <= edges[0] * eqmax)): + return 'f' + else: + return 'U' + +def pinlabels(bit_count): + if bit_count <= 6: + return 'A%i' % (bit_count - 1) + else: + return 'A%i/D%i' % (bit_count - 1, 12 - bit_count) + +def decode_model(model, bits): + if model == 'maplin_l95ar': + address = 'Addr' # Address pins A0 to A5 + for i in range(0, 6): + address += ' %i:' % (i + 1) + ('on' if bits[i][0] == '0' else 'off') + button = 'Button' + # Button pins A6/D5 to A11/D0 + if bits[6][0] == '0' and bits[11][0] == '0': + button += ' A ON/OFF' + elif bits[7][0] == '0' and bits[11][0] == '0': + button += ' B ON/OFF' + elif bits[9][0] == '0' and bits[11][0] == '0': + button += ' C ON/OFF' + elif bits[8][0] == '0' and bits[11][0] == '0': + button += ' D ON/OFF' + else: + button += ' Unknown' + return ['%s' % address, bits[0][1], bits[5][2], \ + '%s' % button, bits[6][1], bits[11][2]] + +class Decoder(srd.Decoder): + api_version = 3 + id = 'rc_encode' + name = 'RC encode' + longname = 'Remote control encoder' + desc = 'PT2262/HX2262/SC5262 remote control encoder protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['IC', 'IR'] + channels = ( + {'id': 'data', 'name': 'Data', 'desc': 'Data line'}, + ) + annotations = ( + ('bit-0', 'Bit 0'), + ('bit-1', 'Bit 1'), + ('bit-f', 'Bit f'), + ('bit-U', 'Bit U'), + ('bit-sync', 'Bit sync'), + ('pin', 'Pin'), + ('code-word-addr', 'Code word address'), + ('code-word-data', 'Code word data'), + ) + annotation_rows = ( + ('bits', 'Bits', (0, 1, 2, 3, 4)), + ('pins', 'Pins', (5,)), + ('code-words', 'Code words', (6, 7)), + ) + options = ( + {'id': 'remote', 'desc': 'Remote', 'default': 'none', + 'values': ('none', 'maplin_l95ar')}, + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplenumber_last = None + self.pulses = [] + self.bits = [] + self.labels = [] + self.bit_count = 0 + self.ss = None + self.es = None + self.state = 'IDLE' + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.model = self.options['remote'] + + def putx(self, data): + self.put(self.ss, self.es, self.out_ann, data) + + def decode(self): + while True: + self.wait({0: 'e'}) + self.state = 'DECODING' + + if not self.samplenumber_last: # Set counters to start of signal. + self.samplenumber_last = self.samplenum + self.ss = self.samplenum + continue + + if self.bit_count < 12: # Decode A0 to A11. + self.bit_count += 1 + for i in range(0, 4): # Get four pulses for each bit. + if i > 0: + self.wait({0: 'e'}) # Get next 3 edges. + samples = self.samplenum - self.samplenumber_last + self.pulses.append(samples) # Save the pulse width. + self.samplenumber_last = self.samplenum + self.es = self.samplenum + self.bits.append([decode_bit(self.pulses), self.ss, + self.es]) # Save states and times. + idx = bitvals.index(decode_bit(self.pulses)) + self.putx([idx, [decode_bit(self.pulses)]]) # Write decoded bit. + self.putx([5, [pinlabels(self.bit_count)]]) # Write pin labels. + self.pulses = [] + self.ss = self.samplenum + else: + if self.model != 'none': + self.labels = decode_model(self.model, self.bits) + self.put(self.labels[1], self.labels[2], self.out_ann, + [6, [self.labels[0]]]) # Write model decode. + self.put(self.labels[4], self.labels[5], self.out_ann, + [7, [self.labels[3]]]) # Write model decode. + samples = self.samplenum - self.samplenumber_last + self.wait({'skip': 8 * samples}) # Wait for end of sync bit. + self.es = self.samplenum + self.putx([4, ['Sync']]) # Write sync label. + self.reset() # Reset and wait for next set of pulses. + self.state = 'DECODE_TIMEOUT' + if not self.state == 'DECODE_TIMEOUT': + self.samplenumber_last = self.samplenum diff --git a/libsigrokdecode4DSL/decoders/rfm12/__init__.py b/libsigrokdecode4DSL/decoders/rfm12/__init__.py new file mode 100644 index 00000000..2fc6de7b --- /dev/null +++ b/libsigrokdecode4DSL/decoders/rfm12/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Sławek Piotrowski +## +## 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, see . +## + +''' +This decoder stacks on top of the 'spi' PD and decodes the HopeRF RFM12 +wireless transceiver control protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/rfm12/pd.py b/libsigrokdecode4DSL/decoders/rfm12/pd.py new file mode 100644 index 00000000..d3df13a9 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/rfm12/pd.py @@ -0,0 +1,497 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Sławek Piotrowski +## +## 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, see . +## + +import sigrokdecode as srd + +class Decoder(srd.Decoder): + api_version = 3 + id = 'rfm12' + name = 'RFM12' + longname = 'HopeRF RFM12' + desc = 'HopeRF RFM12 wireless transceiver control protocol.' + license = 'gplv2+' + inputs = ['spi'] + outputs = [] + tags = ['Wireless/RF'] + annotations = ( + ('cmd', 'Command'), + ('params', 'Command parameters'), + ('disabled', 'Disabled bits'), + ('return', 'Returned values'), + ('disabled_return', 'Disabled returned values'), + ('interpretation', 'Interpretation'), + ) + annotation_rows = ( + ('commands', 'Commands', (0, 1, 2)), + ('return', 'Return', (3, 4)), + ('interpretation', 'Interpretation', (5,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.mosi_bytes, self.miso_bytes = [], [] + self.mosi_bits, self.miso_bits = [], [] + self.row_pos = [0, 0, 0] + + self.ann_to_row = [0, 0, 0, 1, 1, 2] + + # Initialize with Power-On-Reset values. + self.last_status = [0x00, 0x00] + self.last_config = 0x08 + self.last_power = 0x08 + self.last_freq = 0x680 + self.last_data_rate = 0x23 + self.last_fifo_and_reset = 0x80 + self.last_afc = 0xF7 + self.last_transceiver = 0x00 + self.last_pll = 0x77 + + def advance_ann(self, ann, length): + row = self.ann_to_row[ann] + self.row_pos[row] += length + + def putx(self, ann, length, description): + if not isinstance(description, list): + description = [description] + row = self.ann_to_row[ann] + bit = self.row_pos[row] + self.put(self.mosi_bits[bit][1], self.mosi_bits[bit + length - 1][2], + self.out_ann, [ann, description]) + bit += length + self.row_pos[row] = bit + + def describe_bits(self, data, names): + i = 0x01 << len(names) - 1 + bit = 0 + while i != 0: + if names[bit] != '': + self.putx(1 if (data & i) else 2, 1, names[bit]) + i >>= 1 + bit += 1 + + def describe_return_bits(self, data, names): + i = 0x01 << len(names) - 1 + bit = 0 + while i != 0: + if names[bit] != '': + self.putx(3 if (data & i) else 4, 1, names[bit]) + else: + self.advance_ann(3, 1) + i >>= 1 + bit += 1 + + def describe_changed_bits(self, data, old_data, names): + changes = data ^ old_data + i = 0x01 << (len(names) - 1) + bit = 0 + while i != 0: + if names[bit] != '' and changes & i: + s = ['+', 'Turning on'] if (data & i) else ['-', 'Turning off'] + self.putx(5, 1, s) + else: + self.advance_ann(5, 1) + i >>= 1 + bit += 1 + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def handle_configuration_cmd(self, cmd, ret): + self.putx(0, 8, ['Configuration command', 'Configuration']) + NAMES = [['Internal data register', 'el'], ['FIFO mode', 'ef']] + + bits = (cmd[1] & 0xC0) >> 6 + old_bits = (self.last_config & 0xC0) >> 6 + self.describe_bits(bits, NAMES) + self.describe_changed_bits(bits, old_bits, NAMES) + + FREQUENCIES = ['315', '433', '868', '915'] + f = FREQUENCIES[(cmd[1] & 0x30) >> 4] + 'MHz' + self.putx(1, 2, ['Frequency: ' + f, f]) + if cmd[1] & 0x30 != self.last_config & 0x30: + self.putx(5, 2, ['Changed', '~']) + + c = '%.1fpF' % (8.5 + (cmd[1] & 0xF) * 0.5) + self.putx(1, 4, ['Capacitance: ' + c, c]) + if cmd[1] & 0xF != self.last_config & 0xF: + self.putx(5, 4, ['Changed', '~']) + + self.last_config = cmd[1] + + def handle_power_management_cmd(self, cmd, ret): + self.putx(0, 8, ['Power management', 'Power']) + NAMES = [['Receiver chain', 'er'], ['Baseband circuit', 'ebb'], + ['Transmission', 'et'], ['Synthesizer', 'es'], + ['Crystal oscillator', 'ex'], ['Low battery detector', 'eb'], + ['Wake-up timer', 'ew'], ['Clock output off switch', 'dc']] + + self.describe_bits(cmd[1], NAMES) + + power = cmd[1] + + # Some bits imply other, even if they are set to 0. + if power & 0x80: + power |= 0x58 + if power & 0x20: + power |= 0x18 + self.describe_changed_bits(power, self.last_power, NAMES) + + self.last_power = power + + def handle_frequency_setting_cmd(self, cmd, ret): + self.putx(0, 4, ['Frequency setting', 'Frequency']) + f = ((cmd[1] & 0xF) << 8) + cmd[2] + self.putx(0, 12, ['F = %3.4f' % f]) + self.row_pos[2] -= 4 + if self.last_freq != f: + self.putx(5, 12, ['Changing', '~']) + self.last_freq = f + + def handle_data_rate_cmd(self, cmd, ret): + self.putx(0, 8, ['Data rate command', 'Data rate']) + r = cmd[1] & 0x7F + cs = (cmd[1] & 0x80) >> 7 + rate = 10000 / 29.0 / (r + 1) / (1 + 7 * cs) + self.putx(0, 8, ['%3.1fkbps' % rate]) + if self.last_data_rate != cmd[1]: + self.putx(5, 8, ['Changing', '~']) + self.last_data_rate = cmd[1] + + def handle_receiver_control_cmd(self, cmd, ret): + self.putx(0, 5, ['Receiver control command']) + s = 'interrupt input' if (cmd[0] & 0x04) else 'VDI output' + self.putx(0, 1, ['pin16 = ' + s]) + VDI_NAMES = ['Fast', 'Medium', 'Slow', 'Always on'] + vdi_speed = VDI_NAMES[cmd[0] & 0x3] + self.putx(0, 2, ['VDI: %s' % vdi_speed]) + BANDWIDTH_NAMES = ['Reserved', '400kHz', '340kHz', '270kHz', '200kHz', + '134kHz', '67kHz', 'Reserved'] + bandwidth = BANDWIDTH_NAMES[(cmd[1] & 0xE0) >> 5] + self.putx(0, 3, ['Bandwidth: %s' % bandwidth]) + LNA_GAIN_NAMES = [0, -6, -14, -20] + lna_gain = LNA_GAIN_NAMES[(cmd[1] & 0x18) >> 3] + self.putx(0, 2, ['LNA gain: %ddB' % lna_gain]) + RSSI_THRESHOLD_NAMES = ['-103', '-97', '-91', '-85', '-79', '-73', + 'Reserved', 'Reserved'] + rssi_threshold = RSSI_THRESHOLD_NAMES[cmd[1] & 0x7] + self.putx(0, 3, ['RSSI threshold: %s' % rssi_threshold]) + + def handle_data_filter_cmd(self, cmd, ret): + self.putx(0, 8, ['Data filter command']) + if cmd[1] & 0x80: + clock_recovery = 'auto' + elif cmd[1] & 0x40: + clock_recovery = 'fast' + else: + clock_recovery = 'slow' + self.putx(0, 2, ['Clock recovery: %s mode' % clock_recovery]) + self.advance_ann(0, 1) # Should always be 1. + s = 'analog' if (cmd[1] & 0x10) else 'digital' + self.putx(0, 1, ['Data filter: ' + s]) + self.advance_ann(0, 1) # Should always be 1. + self.putx(0, 3, ['DQD threshold: %d' % (cmd[1] & 0x7)]) + + def handle_fifo_and_reset_cmd(self, cmd, ret): + self.putx(0, 8, ['FIFO and reset command']) + fifo_level = (cmd[1] & 0xF0) >> 4 + self.putx(0, 4, ['FIFO trigger level: %d' % fifo_level]) + last_fifo_level = (self.last_fifo_and_reset & 0xF0) >> 4 + if fifo_level != last_fifo_level: + self.putx(5, 4, ['Changing', '~']) + else: + self.advance_ann(5, 4) + s = 'one byte' if (cmd[1] & 0x08) else 'two bytes' + self.putx(0, 1, ['Synchron length: ' + s]) + if (cmd[1] & 0x08) != (self.last_fifo_and_reset & 0x08): + self.putx(5, 1, ['Changing', '~']) + else: + self.advance_ann(5, 1) + + if cmd[1] & 0x04: + fifo_fill = 'Always' + elif cmd[1] & 0x02: + fifo_fill = 'After synchron pattern' + else: + fifo_fill = 'Never' + self.putx(0, 2, ['FIFO fill: %s' % fifo_fill]) + if (cmd[1] & 0x06) != (self.last_fifo_and_reset & 0x06): + self.putx(5, 2, ['Changing', '~']) + else: + self.advance_ann(5, 2) + + s = 'non-sensitive' if (cmd[1] & 0x01) else 'sensitive' + self.putx(0, 1, ['Reset mode: ' + s]) + if (cmd[1] & 0x01) != (self.last_fifo_and_reset & 0x01): + self.putx(5, 1, ['Changing', '~']) + else: + self.advance_ann(5, 1) + + self.last_fifo_and_reset = cmd[1] + + def handle_synchron_pattern_cmd(self, cmd, ret): + self.putx(0, 8, ['Synchron pattern command']) + if self.last_fifo_and_reset & 0x08: + self.putx(0, 8, ['Pattern: 0x2D%02X' % pattern]) + else: + self.putx(0, 8, ['Pattern: %02X' % pattern]) + + def handle_fifo_read_cmd(self, cmd, ret): + self.putx(0, 8, ['FIFO read command', 'FIFO read']) + self.putx(3, 8, ['Data: %02X' % ret[1]]) + + def handle_afc_cmd(self, cmd, ret): + self.putx(0, 8, ['AFC command']) + MODES = ['Off', 'Once', 'During receiving', 'Always'] + mode = (cmd[1] & 0xC0) >> 6 + self.putx(0, 2, ['Mode: %s' % MODES[mode]]) + if (cmd[1] & 0xC0) != (self.last_afc & 0xC0): + self.putx(5, 2, ['Changing', '~']) + else: + self.advance_ann(5, 2) + + range_limit = (cmd[1] & 0x30) >> 4 + FREQ_TABLE = [0.0, 2.5, 5.0, 7.5] + freq_delta = FREQ_TABLE[(self.last_config & 0x30) >> 4] + + if range_limit == 0: + self.putx(0, 2, ['Range: No limit']) + elif range_limit == 1: + self.putx(0, 2, ['Range: +/-%dkHz' % (15 * freq_delta)]) + elif range_limit == 2: + self.putx(0, 2, ['Range: +/-%dkHz' % (7 * freq_delta)]) + elif range_limit == 3: + self.putx(0, 2, ['Range: +/-%dkHz' % (3 * freq_delta)]) + + if (cmd[1] & 0x30) != (self.last_afc & 0x30): + self.putx(5, 2, ['Changing', '~']) + else: + self.advance_ann(5, 2) + + NAMES = ['Strobe edge', 'High accuracy mode', 'Enable offset register', + 'Enable offset calculation'] + self.describe_bits(cmd[1] & 0xF, NAMES) + self.describe_changed_bits(cmd[1] & 0xF, self.last_afc & 0xF, NAMES) + + self.last_afc = cmd[1] + + def handle_transceiver_control_cmd(self, cmd, ret): + self.putx(0, 8, ['Transceiver control command']) + self.putx(0, 4, ['FSK frequency delta: %dkHz' % (15 * ((cmd[1] & 0xF0) >> 4))]) + if cmd[1] & 0xF0 != self.last_transceiver & 0xF0: + self.putx(5, 4, ['Changing', '~']) + else: + self.advance_ann(5, 4) + + POWERS = [0, -2.5, -5, -7.5, -10, -12.5, -15, -17.5] + self.advance_ann(0, 1) + self.advance_ann(5, 1) + self.putx(0,3, ['Relative power: %dB' % (cmd[1] & 0x07)]) + if (cmd[1] & 0x07) != (self.last_transceiver & 0x07): + self.putx(5, 3, ['Changing', '~']) + else: + self.advance_ann(5, 3) + self.last_transceiver = cmd[1] + + def handle_pll_setting_cmd(self, cmd, ret): + self.putx(0, 8, ['PLL setting command']) + self.advance_ann(0, 1) + self.putx(0, 2, ['Clock buffer rise and fall time']) + self.advance_ann(0, 1) + self.advance_ann(5, 4) + NAMES = [['Delay in phase detector', 'dly'], ['Disable dithering', 'ddit']] + self.describe_bits((cmd[1] & 0xC) >> 2, NAMES) + self.describe_changed_bits((cmd[1] & 0xC) >> 2, (self.last_pll & 0xC) >> 2, NAMES) + s = '256kbps, high' if (cmd[1] & 0x01) else '86.2kbps, low' + self.putx(0, 1, ['Max bit rate: %s noise' % s]) + + self.advance_ann(5, 1) + if (cmd[1] & 0x01) != (self.last_pll & 0x01): + self.putx(5, 1, ['Changing', '~']) + + self.last_pll = cmd[1] + + def handle_transmitter_register_cmd(self, cmd, ret): + self.putx(0, 8, ['Transmitter register command', 'Transmit']) + self.putx(0, 8, ['Data: %s' % cmd[1], '%s' % cmd[1]]) + + def handle_software_reset_cmd(self, cmd, ret): + self.putx(0, 16, ['Software reset command']) + + def handle_wake_up_timer_cmd(self, cmd, ret): + self.putx(0, 3, ['Wake-up timer command', 'Timer']) + r = cmd[0] & 0x1F + m = cmd[1] + time = 1.03 * m * pow(2, r) + 0.5 + self.putx(0, 13, ['Time: %7.2f' % time]) + + def handle_low_duty_cycle_cmd(self, cmd, ret): + self.putx(0, 16, ['Low duty cycle command']) + + def handle_low_battery_detector_cmd(self, cmd, ret): + self.putx(0, 8, ['Low battery detector command']) + NAMES = ['1', '1.25', '1.66', '2', '2.5', '3.33', '5', '10'] + clock = NAMES[(cmd[1] & 0xE0) >> 5] + self.putx(0, 3, ['Clock output: %sMHz' % clock, '%sMHz' % clock]) + self.advance_ann(0, 1) + v = 2.25 + (cmd[1] & 0x0F) * 0.1 + self.putx(0, 4, ['Low battery voltage: %1.2fV' % v, '%1.2fV' % v]) + + def handle_status_read_cmd(self, cmd, ret): + self.putx(0, 8, ['Status read command', 'Status']) + NAMES = ['RGIT/FFIT', 'POR', 'RGUR/FFOV', 'WKUP', 'EXT', 'LBD', + 'FFEM', 'RSSI/ATS', 'DQD', 'CRL', 'ATGL'] + status = (ret[0] << 3) + (ret[1] >> 5) + self.row_pos[1] -= 8 + self.row_pos[2] -= 8 + self.describe_return_bits(status, NAMES) + receiver_enabled = (self.last_power & 0x80) >> 7 + + if ret[0] & 0x80: + if receiver_enabled: + s = 'Received data in FIFO' + else: + s = 'Transmit register ready' + self.putx(5, 1, s) + else: + self.advance_ann(5, 1) + if ret[0] & 0x40: + self.putx(5, 1, 'Power on Reset') + else: + self.advance_ann(5, 1) + if ret[0] & 0x20: + if receiver_enabled: + s = 'RX FIFO overflow' + else: + s = 'Transmit register under run' + self.putx(5, 1, s) + else: + self.advance_ann(5, 1) + if ret[0] & 0x10: + self.putx(5, 1, 'Wake-up timer') + else: + self.advance_ann(5, 1) + if ret[0] & 0x08: + self.putx(5, 1, 'External interrupt') + else: + self.advance_ann(5, 1) + if ret[0] & 0x04: + self.putx(5, 1, 'Low battery') + else: + self.advance_ann(5, 1) + if ret[0] & 0x02: + self.putx(5, 1, 'FIFO is empty') + else: + self.advance_ann(5, 1) + if ret[0] & 0x01: + if receiver_enabled: + s = 'Incoming signal above limit' + else: + s = 'Antenna detected RF signal' + self.putx(5, 1, s) + else: + self.advance_ann(5, 1) + if ret[1] & 0x80: + self.putx(5, 1, 'Data quality detector') + else: + self.advance_ann(5, 1) + if ret[1] & 0x40: + self.putx(5, 1, 'Clock recovery locked') + else: + self.advance_ann(5, 1) + self.advance_ann(5, 1) + + self.putx(3, 5, ['AFC offset']) + if (self.last_status[1] & 0x1F) != (ret[1] & 0x1F): + self.putx(5, 5, ['Changed', '~']) + self.last_status = ret + + def handle_cmd(self, cmd, ret): + if cmd[0] == 0x80: + self.handle_configuration_cmd(cmd, ret) + elif cmd[0] == 0x82: + self.handle_power_management_cmd(cmd, ret) + elif cmd[0] & 0xF0 == 0xA0: + self.handle_frequency_setting_cmd(cmd, ret) + elif cmd[0] == 0xC6: + self.handle_data_rate_cmd(cmd, ret) + elif cmd[0] & 0xF8 == 0x90: + self.handle_receiver_control_cmd(cmd, ret) + elif cmd[0] == 0xC2: + self.handle_data_filter_cmd(cmd, ret) + elif cmd[0] == 0xCA: + self.handle_fifo_and_reset_cmd(cmd, ret) + elif cmd[0] == 0xCE: + self.handle_synchron_pattern_cmd(cmd, ret) + elif cmd[0] == 0xB0: + self.handle_fifo_read_cmd(cmd, ret) + elif cmd[0] == 0xC4: + self.handle_afc_cmd(cmd, ret) + elif cmd[0] & 0xFE == 0x98: + self.handle_transceiver_control_cmd(cmd, ret) + elif cmd[0] == 0xCC: + self.handle_pll_setting_cmd(cmd, ret) + elif cmd[0] == 0xB8: + self.handle_transmitter_register_cmd(cmd, ret) + elif cmd[0] == 0xFE: + self.handle_software_reset_cmd(cmd, ret) + elif cmd[0] & 0xE0 == 0xE0: + self.handle_wake_up_timer_cmd(cmd, ret) + elif cmd[0] == 0xC8: + self.handle_low_duty_cycle_cmd(cmd, ret) + elif cmd[0] == 0xC0: + self.handle_low_battery_detector_cmd(cmd, ret) + elif cmd[0] == 0x00: + self.handle_status_read_cmd(cmd, ret) + else: + c = '%02x %02x' % tuple(cmd) + r = '%02x %02x' % tuple(ret) + self.putx(0, 16, ['Unknown command: %s (reply: %s)!' % (c, r)]) + + def decode(self, ss, es, data): + ptype, mosi, miso = data + + # For now, only use DATA and BITS packets. + if ptype not in ('DATA', 'BITS'): + return + + # Store the individual bit values and ss/es numbers. The next packet + # is guaranteed to be a 'DATA' packet belonging to this 'BITS' one. + if ptype == 'BITS': + if mosi is not None: + self.mosi_bits.extend(reversed(mosi)) + if miso is not None: + self.miso_bits.extend(reversed(miso)) + return + + # Append new bytes. + self.mosi_bytes.append(mosi) + self.miso_bytes.append(miso) + + # All commands consist of 2 bytes. + if len(self.mosi_bytes) < 2: + return + + self.row_pos = [0, 8, 8] + + self.handle_cmd(self.mosi_bytes, self.miso_bytes) + + self.mosi_bytes, self.miso_bytes = [], [] + self.mosi_bits, self.miso_bits = [], [] diff --git a/libsigrokdecode4DSL/decoders/rgb_led_spi/__init__.py b/libsigrokdecode4DSL/decoders/rgb_led_spi/__init__.py new file mode 100644 index 00000000..1cf62eb8 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/rgb_led_spi/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Matt Ranostay +## +## 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, see . +## + +''' +This decoder stacks on top of the 'spi' PD and decodes generic RGB LED string +values that are clocked over SPI in RGB values. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/rgb_led_spi/pd.py b/libsigrokdecode4DSL/decoders/rgb_led_spi/pd.py new file mode 100644 index 00000000..ee94c6bf --- /dev/null +++ b/libsigrokdecode4DSL/decoders/rgb_led_spi/pd.py @@ -0,0 +1,70 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Matt Ranostay +## +## 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, see . +## + +import sigrokdecode as srd + +class Decoder(srd.Decoder): + api_version = 3 + id = 'rgb_led_spi' + name = 'RGB LED (SPI)' + longname = 'RGB LED string decoder (SPI)' + desc = 'RGB LED string protocol (RGB values clocked over SPI).' + license = 'gplv2+' + inputs = ['spi'] + outputs = [] + tags = ['Display'] + annotations = ( + ('rgb', 'RGB values'), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.ss_cmd, self.es_cmd = 0, 0 + self.mosi_bytes = [] + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + self.put(self.ss_cmd, self.es_cmd, self.out_ann, data) + + def decode(self, ss, es, data): + ptype, mosi, miso = data + + # Only care about data packets. + if ptype != 'DATA': + return + self.ss, self.es = ss, es + + if len(self.mosi_bytes) == 0: + self.ss_cmd = ss + self.mosi_bytes.append(mosi) + + # RGB value == 3 bytes + if len(self.mosi_bytes) != 3: + return + + red, green, blue = self.mosi_bytes + rgb_value = int(red) << 16 | int(green) << 8 | int(blue) + + self.es_cmd = es + self.putx([0, ['#%.6x' % rgb_value]]) + self.mosi_bytes = [] diff --git a/libsigrokdecode4DSL/decoders/rgb_led_ws281x/__init__.py b/libsigrokdecode4DSL/decoders/rgb_led_ws281x/__init__.py new file mode 100644 index 00000000..20de109f --- /dev/null +++ b/libsigrokdecode4DSL/decoders/rgb_led_ws281x/__init__.py @@ -0,0 +1,27 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2016 Vladimir Ermakov +## +## 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 . +## + +''' +WS281x RGB LED protocol decoder. + +Details: +https://cpldcpu.wordpress.com/2014/01/14/light_ws2812-library-v2-0-part-i-understanding-the-ws2812/ +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/rgb_led_ws281x/pd.py b/libsigrokdecode4DSL/decoders/rgb_led_ws281x/pd.py new file mode 100644 index 00000000..0ea283ea --- /dev/null +++ b/libsigrokdecode4DSL/decoders/rgb_led_ws281x/pd.py @@ -0,0 +1,195 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2016 Vladimir Ermakov +## Copyright (C) 2019 DreamSourceLab +## Copyright (C) 2021 Michael Miller +## +## 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 . +## + +import sigrokdecode as srd +from functools import reduce + +class SamplerateError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = 'rgb_led_ws281x' + name = 'RGB LED WS2812+' + longname = 'RGB LED color decoder' + desc = 'Decodes colors from bus pulses for single wire RGB leds like APA106, WS2811, WS2812, WS2813, SK6812, TM1829, TM1814, and TX1812.' + license = 'gplv3+' + inputs = ['logic'] + outputs = [] + tags = ['Display', 'IC'] + channels = ( + {'id': 'din', 'name': 'DIN', 'desc': 'DIN data line'}, + ) + options = ( + {'id': 'colors', 'desc': 'Colors', 'default': 'GRB', + 'values': ( 'GRB', 'RGB', 'BRG', 'RBG', 'BGR', 'GRBW', 'RGBW', 'WRGB', 'LBGR', 'LGRB', 'LRGB', 'LRBG', 'LGBR', 'LBRG')}, + {'id': 'polarity', 'desc': 'Polarity', 'default': 'normal', + 'values': ('normal', 'inverted')}, + ) + annotations = ( + ('bit', 'Bit'), + ('reset', 'RESET'), + ('rgb', 'RGB'), + ) + annotation_rows = ( + ('bit', 'Bits', (0, 1)), + ('rgb', 'RGB', (2,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.state = 'FIND RESET' + self.samplerate = None + self.ss_packet = None + self.ss = None + self.es = None + self.bits = [] + self.bit_ = None + self.colorsize = None + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def handle_bits(self, samplenum): + if len(self.bits) == self.colorsize: + elems = reduce(lambda a, b: (a << 1) | b, self.bits) + if self.colorsize == 24: + if self.options['colors'] == 'GRB': + rgb = (elems & 0xff0000) >> 8 | (elems & 0x00ff00) << 8 | (elems & 0x0000ff) + elif self.options['colors'] == 'RGB': + rgb = elems + elif self.options['colors'] == 'BRG': + rgb = (elems & 0xff0000) >> 16 | (elems & 0x00ffff) << 8 + elif self.options['colors'] == 'RBG': + rgb = (elems & 0xff0000) | (elems & 0x00ff00) >> 8 | (elems & 0x0000ff) << 8 + elif self.options['colors'] == 'BGR': + rgb = (elems & 0xff0000) >> 16 | (elems & 0x00ff00) | (elems & 0x0000ff) << 16 + + self.put(self.ss_packet, samplenum, self.out_ann, + [2, ['RGB#%06x' % rgb]]) + else: + if self.options['colors'] == 'GRBW': + rgb = (elems & 0xff000000) >> 16 | (elems & 0x00ff0000) | (elems & 0x0000ff00) >> 8 + w = (elems & 0x000000ff) + elif self.options['colors'] == 'RGBW': + rgb = (elems & 0xffffff00) >> 8 + w = (elems & 0x000000ff) + elif self.options['colors'] == 'WRGB': + rgb = (elems & 0x00ffffff) + w = (elems & 0xff000000) >> 32 + elif self.options['colors'] == 'LBGR': + rgb = (elems & 0x0000ff00) | (elems & 0x00ff0000) >> 16 | (elems & 0x000000ff) << 16 + w = (elems & 0xff000000) >> 32 + elif self.options['colors'] == 'LGRB': + rgb = (elems & 0x000000ff) | (elems & 0x00ff0000) >> 8 | (elems & 0x0000ff00) << 8 + w = (elems & 0xff000000) >> 32 + elif self.options['colors'] == 'LRGB': + rgb = (elems & 0x00ffffff) + w = (elems & 0xff000000) >> 32 + elif self.options['colors'] == 'LRBG': + rgb = (elems & 0x00ff0000) | (elems & 0x0000ff00) >> 8 | (elems & 0x000000ff) << 8 + w = (elems & 0xff000000) >> 32 + elif self.options['colors'] == 'LGBR': + rgb = (elems & 0x00ffff00) >> 8 | (elems & 0x000000ff) << 16 + w = (elems & 0xff000000) >> 32 + elif self.options['colors'] == 'LBRG': + rgb = (elems & 0x00ff0000) >> 16 | (elems & 0x0000ffff) << 8 + w = (elems & 0xff000000) >> 32 + + self.put(self.ss_packet, samplenum, self.out_ann, + [2, ['RGB#%06x #%02x' % (rgb, w)]]) + + self.bits = [] + self.ss_packet = samplenum + + def check_bit_(self, samplenum): + period = samplenum - self.ss + tH_samples = self.es - self.ss + tH = tH_samples / self.samplerate + if tH >= 625e-9: + self.bit_ = True + else: + # Ideal duty for T0H: 33%, T1H: 66%. + self.bit_ = (tH_samples / period) > 0.5 + + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + + if len(self.options['colors']) == 4: + self.colorsize = 32 + else: + self.colorsize = 24 + + while True: + if self.state == 'FIND RESET': + self.wait({0: 'l' if self.options['polarity'] == 'normal' else 'h'}) + self.ss = self.samplenum + self.wait({0: 'e'}) + self.es = self.samplenum + if ((self.es - self.ss) / self.samplerate > 50e-6): + self.state = 'RESET' + elif ((self.es - self.ss) / self.samplerate > 3e-6): + self.bits = [] + self.ss = self.samplenum + self.ss_packet = self.samplenum + self.wait({0: 'e'}) + self.state = 'BIT FALLING' + elif self.state == 'RESET': + self.put(self.ss, self.es, self.out_ann, [1, ['RESET', 'RST', 'R']]) + self.bits = [] + self.ss = self.samplenum + self.ss_packet = self.samplenum + self.wait({0: 'e'}) + self.state = 'BIT FALLING' + elif self.state == 'BIT FALLING': + self.es = self.samplenum + self.wait({0: 'e'}) + if ((self.samplenum - self.es) / self.samplerate > 50e-6): + self.check_bit_(self.samplenum) + self.put(self.ss, self.es, self.out_ann, + [0, ['%d' % self.bit_]]) + self.bits.append(self.bit_) + self.handle_bits(self.es) + + self.ss = self.es + self.es = self.samplenum + self.state = 'RESET' + else: + self.state = 'BIT RISING' + elif self.state == 'BIT RISING': + self.check_bit_(self.samplenum) + self.put(self.ss, self.samplenum, self.out_ann, + [0, ['%d' % self.bit_]]) + self.bits.append(self.bit_) + self.handle_bits(self.samplenum) + + self.ss = self.samplenum + self.wait({0: 'e'}) + self.state = 'BIT FALLING' diff --git a/libsigrokdecode4DSL/decoders/rtc8564/__init__.py b/libsigrokdecode4DSL/decoders/rtc8564/__init__.py new file mode 100644 index 00000000..f17e7515 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/rtc8564/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +''' +This decoder stacks on top of the 'i2c' PD and decodes the Epson +RTC-8564 JE/NB real-time clock (RTC) protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/rtc8564/pd.py b/libsigrokdecode4DSL/decoders/rtc8564/pd.py new file mode 100644 index 00000000..b57fae64 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/rtc8564/pd.py @@ -0,0 +1,254 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012-2014 Uwe Hermann +## +## 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, see . +## + +import sigrokdecode as srd +from common.srdhelper import bcd2int + +def reg_list(): + l = [] + for i in range(8 + 1): + l.append(('reg-0x%02x' % i, 'Register 0x%02x' % i)) + + return tuple(l) + +class Decoder(srd.Decoder): + api_version = 3 + id = 'rtc8564' + name = 'RTC-8564' + longname = 'Epson RTC-8564 JE/NB' + desc = 'Realtime clock module protocol.' + license = 'gplv2+' + inputs = ['i2c'] + outputs = [] + tags = ['Clock/timing'] + annotations = reg_list() + ( + ('read', 'Read date/time'), + ('write', 'Write date/time'), + ('bit-reserved', 'Reserved bit'), + ('bit-vl', 'VL bit'), + ('bit-century', 'Century bit'), + ('reg-read', 'Register read'), + ('reg-write', 'Register write'), + ) + annotation_rows = ( + ('bits', 'Bits', tuple(range(0, 8 + 1)) + (11, 12, 13)), + ('regs', 'Register access', (14, 15)), + ('date-time', 'Date/time', (9, 10)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.state = 'IDLE' + self.hours = -1 + self.minutes = -1 + self.seconds = -1 + self.days = -1 + self.weekdays = -1 + self.months = -1 + self.years = -1 + self.bits = [] + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + self.put(self.ss, self.es, self.out_ann, data) + + def putd(self, bit1, bit2, data): + self.put(self.bits[bit1][1], self.bits[bit2][2], self.out_ann, data) + + def putr(self, bit): + self.put(self.bits[bit][1], self.bits[bit][2], self.out_ann, + [11, ['Reserved bit', 'Reserved', 'Rsvd', 'R']]) + + def handle_reg_0x00(self, b): # Control register 1 + pass + + def handle_reg_0x01(self, b): # Control register 2 + ti_tp = 1 if (b & (1 << 4)) else 0 + af = 1 if (b & (1 << 3)) else 0 + tf = 1 if (b & (1 << 2)) else 0 + aie = 1 if (b & (1 << 1)) else 0 + tie = 1 if (b & (1 << 0)) else 0 + + ann = '' + + s = 'repeated' if ti_tp else 'single-shot' + ann += 'TI/TP = %d: %s operation upon fixed-cycle timer interrupt '\ + 'events\n' % (ti_tp, s) + s = '' if af else 'no ' + ann += 'AF = %d: %salarm interrupt detected\n' % (af, s) + s = '' if tf else 'no ' + ann += 'TF = %d: %sfixed-cycle timer interrupt detected\n' % (tf, s) + s = 'enabled' if aie else 'prohibited' + ann += 'AIE = %d: INT# pin output %s when an alarm interrupt '\ + 'occurs\n' % (aie, s) + s = 'enabled' if tie else 'prohibited' + ann += 'TIE = %d: INT# pin output %s when a fixed-cycle interrupt '\ + 'event occurs\n' % (tie, s) + + self.putx([1, [ann]]) + + def handle_reg_0x02(self, b): # Seconds / Voltage-low bit + vl = 1 if (b & (1 << 7)) else 0 + self.putd(7, 7, [12, ['Voltage low: %d' % vl, 'Volt. low: %d' % vl, + 'VL: %d' % vl, 'VL']]) + s = self.seconds = bcd2int(b & 0x7f) + self.putd(6, 0, [2, ['Second: %d' % s, 'Sec: %d' % s, 'S: %d' % s, 'S']]) + + def handle_reg_0x03(self, b): # Minutes + self.putr(7) + m = self.minutes = bcd2int(b & 0x7f) + self.putd(6, 0, [3, ['Minute: %d' % m, 'Min: %d' % m, 'M: %d' % m, 'M']]) + + def handle_reg_0x04(self, b): # Hours + self.putr(7) + self.putr(6) + h = self.hours = bcd2int(b & 0x3f) + self.putd(5, 0, [4, ['Hour: %d' % h, 'H: %d' % h, 'H']]) + + def handle_reg_0x05(self, b): # Days + self.putr(7) + self.putr(6) + d = self.days = bcd2int(b & 0x3f) + self.putd(5, 0, [5, ['Day: %d' % d, 'D: %d' % d, 'D']]) + + def handle_reg_0x06(self, b): # Weekdays + for i in (7, 6, 5, 4, 3): + self.putr(i) + w = self.weekdays = bcd2int(b & 0x07) + self.putd(2, 0, [6, ['Weekday: %d' % w, 'WD: %d' % w, 'WD', 'W']]) + + def handle_reg_0x07(self, b): # Months / century bit + c = 1 if (b & (1 << 7)) else 0 + self.putd(7, 7, [13, ['Century bit: %d' % c, 'Century: %d' % c, + 'Cent: %d' % c, 'C: %d' % c, 'C']]) + self.putr(6) + self.putr(5) + m = self.months = bcd2int(b & 0x1f) + self.putd(4, 0, [7, ['Month: %d' % m, 'Mon: %d' % m, 'M: %d' % m, 'M']]) + + def handle_reg_0x08(self, b): # Years + y = self.years = bcd2int(b & 0xff) + self.putx([8, ['Year: %d' % y, 'Y: %d' % y, 'Y']]) + + def handle_reg_0x09(self, b): # Alarm, minute + pass + + def handle_reg_0x0a(self, b): # Alarm, hour + pass + + def handle_reg_0x0b(self, b): # Alarm, day + pass + + def handle_reg_0x0c(self, b): # Alarm, weekday + pass + + def handle_reg_0x0d(self, b): # CLKOUT output + pass + + def handle_reg_0x0e(self, b): # Timer setting + pass + + def handle_reg_0x0f(self, b): # Down counter for fixed-cycle timer + pass + + def decode(self, ss, es, data): + cmd, databyte = data + + # Collect the 'BITS' packet, then return. The next packet is + # guaranteed to belong to these bits we just stored. + if cmd == 'BITS': + self.bits = databyte + return + + # Store the start/end samples of this I²C packet. + self.ss, self.es = ss, es + + # State machine. + if self.state == 'IDLE': + # Wait for an I²C START condition. + if cmd != 'START': + return + self.state = 'GET SLAVE ADDR' + self.ss_block = ss + elif self.state == 'GET SLAVE ADDR': + # Wait for an address write operation. + # TODO: We should only handle packets to the RTC slave (0xa2/0xa3). + if cmd != 'ADDRESS WRITE': + return + self.state = 'GET REG ADDR' + elif self.state == 'GET REG ADDR': + # Wait for a data write (master selects the slave register). + if cmd != 'DATA WRITE': + return + self.reg = databyte + self.state = 'WRITE RTC REGS' + elif self.state == 'WRITE RTC REGS': + # If we see a Repeated Start here, it's probably an RTC read. + if cmd == 'START REPEAT': + self.state = 'READ RTC REGS' + return + # Otherwise: Get data bytes until a STOP condition occurs. + if cmd == 'DATA WRITE': + r, s = self.reg, '%02X: %02X' % (self.reg, databyte) + self.putx([15, ['Write register %s' % s, 'Write reg %s' % s, + 'WR %s' % s, 'WR', 'W']]) + handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg) + handle_reg(databyte) + self.reg += 1 + # TODO: Check for NACK! + elif cmd == 'STOP': + # TODO: Handle read/write of only parts of these items. + d = '%02d.%02d.%02d %02d:%02d:%02d' % (self.days, self.months, + self.years, self.hours, self.minutes, self.seconds) + self.put(self.ss_block, es, self.out_ann, + [9, ['Write date/time: %s' % d, 'Write: %s' % d, + 'W: %s' % d]]) + self.state = 'IDLE' + else: + pass # TODO + elif self.state == 'READ RTC REGS': + # Wait for an address read operation. + # TODO: We should only handle packets to the RTC slave (0xa2/0xa3). + if cmd == 'ADDRESS READ': + self.state = 'READ RTC REGS2' + return + else: + pass # TODO + elif self.state == 'READ RTC REGS2': + if cmd == 'DATA READ': + r, s = self.reg, '%02X: %02X' % (self.reg, databyte) + self.putx([15, ['Read register %s' % s, 'Read reg %s' % s, + 'RR %s' % s, 'RR', 'R']]) + handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg) + handle_reg(databyte) + self.reg += 1 + # TODO: Check for NACK! + elif cmd == 'STOP': + d = '%02d.%02d.%02d %02d:%02d:%02d' % (self.days, self.months, + self.years, self.hours, self.minutes, self.seconds) + self.put(self.ss_block, es, self.out_ann, + [10, ['Read date/time: %s' % d, 'Read: %s' % d, + 'R: %s' % d]]) + self.state = 'IDLE' + else: + pass # TODO? diff --git a/libsigrokdecode4DSL/decoders/sae_j1850_vpw/__init__.py b/libsigrokdecode4DSL/decoders/sae_j1850_vpw/__init__.py new file mode 100644 index 00000000..6894bfde --- /dev/null +++ b/libsigrokdecode4DSL/decoders/sae_j1850_vpw/__init__.py @@ -0,0 +1,24 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2016 Anthony Symons +## +## 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, see . +## + +''' +SAE J1850 Variable Pulse Width decoder. Decode GM VPW 1X and 4X Vehicle Bus. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/sae_j1850_vpw/pd.py b/libsigrokdecode4DSL/decoders/sae_j1850_vpw/pd.py new file mode 100644 index 00000000..fd2389ec --- /dev/null +++ b/libsigrokdecode4DSL/decoders/sae_j1850_vpw/pd.py @@ -0,0 +1,165 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2016 Anthony Symons +## +## 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, see . +## + +import sigrokdecode as srd + +class SamplerateError(Exception): + pass + +def timeuf(t): + return int (t * 1000.0 * 1000.0) + +class Ann: + ANN_RAW, ANN_SOF, ANN_IFS, ANN_DATA, \ + ANN_PACKET = range(5) + +class Decoder(srd.Decoder): + api_version = 3 + id = 'sae_j1850_vpw' + name = 'SAE J1850 VPW' + longname = 'SAE J1850 VPW.' + desc = 'SAE J1850 Variable Pulse Width 1x and 4x.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Automotive'] + channels = ( + {'id': 'data', 'name': 'Data', 'desc': 'Data line'}, + ) + annotations = ( + ('raw', 'Raw'), + ('sof', 'SOF'), + ('ifs', 'EOF/IFS'), + ('data', 'Data'), + ('packet', 'Packet'), + ) + annotation_rows = ( + ('raws', 'Raws', (Ann.ANN_RAW, Ann.ANN_SOF, Ann.ANN_IFS,)), + ('bytes', 'Bytes', (Ann.ANN_DATA,)), + ('packets', 'Packets', (Ann.ANN_PACKET,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.state = 'IDLE' + self.samplerate = None + self.byte = 0 # the byte offset in the packet + self.mode = 0 # for by packet decode + self.data = 0 # the current byte + self.datastart = 0 # sample number this byte started at + self.csa = 0 # track the last byte seperately to retrospectively add the CS marker + self.csb = 0 + self.count = 0 # which bit number we are up to + self.active = 0 # which logic level is considered active + + # vpw timings. ideal, min and max tollerances. + # From SAE J1850 1995 rev section 23.406 + + self.sof = 200 + self.sofl = 164 + self.sofh = 245 # 240 by the spec, 245 so a 60us 4x sample will pass + self.long = 128 + self.longl = 97 + self.longh = 170 # 164 by the spec but 170 for low sample rate tolerance. + self.short = 64 + self.shortl = 24 # 35 by the spec, 24 to allow down to 6us as measured in practice for 4x @ 1mhz sampling + self.shorth = 97 + self.ifs = 240 + self.spd = 1 # set to 4 when a 4x SOF is detected (VPW high speed frame) + + def handle_bit(self, ss, es, b): + self.data |= (b << 7-self.count) # MSB-first + self.put(ss, es, self.out_ann, [Ann.ANN_RAW, ["%d" % b]]) + if self.count == 0: + self.datastart = ss + if self.count == 7: + self.csa = self.datastart # for CS + self.csb = self.samplenum # for CS + self.put(self.datastart, self.samplenum, self.out_ann, [Ann.ANN_DATA, ["%02X" % self.data]]) + # add protocol parsing here + if self.byte == 0: + self.put(self.datastart, self.samplenum, self.out_ann, [Ann.ANN_PACKET, ['Priority','Prio','P']]) + elif self.byte == 1: + self.put(self.datastart, self.samplenum, self.out_ann, [Ann.ANN_PACKET, ['Destination','Dest','D']]) + elif self.byte == 2: + self.put(self.datastart, self.samplenum, self.out_ann, [Ann.ANN_PACKET, ['Source','Src','S']]) + elif self.byte == 3: + self.put(self.datastart, self.samplenum, self.out_ann, [Ann.ANN_PACKET, ['Mode','M']]) + self.mode = self.data + elif self.mode == 1 and self.byte == 4: # mode 1 payload + self.put(self.datastart, self.samplenum, self.out_ann, [Ann.ANN_PACKET, ['Pid','P']]) + + # prepare for next byte + self.count = -1 + self.data = 0 + self.byte = self.byte + 1 # track packet offset + self.count = self.count + 1 + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + + self.wait({0: 'e'}) + es = self.samplenum + while True: + ss = es + pin, = self.wait({0: 'e'}) + es = self.samplenum + + samples = es - ss + t = timeuf(samples / self.samplerate) + if self.state == 'IDLE': # detect and set speed from the size of sof + if pin == self.active and t in range(self.sofl , self.sofh): + self.put(ss, es, self.out_ann, [Ann.ANN_RAW, ['1X SOF', 'S1', 'S']]) + self.spd = 1 + self.data = 0 + self.count = 0 + self.state = 'DATA' + elif pin == self.active and t in range(int(self.sofl / 4) , int(self.sofh / 4)): + self.put(ss, es, self.out_ann, [Ann.ANN_RAW, ['4X SOF', 'S4', '4']]) + self.spd = 4 + self.data = 0 + self.count = 0 + self.state = 'DATA' + + elif self.state == 'DATA': + if t >= int(self.ifs / self.spd): + self.state = 'IDLE' + self.put(ss, es, self.out_ann, [Ann.ANN_RAW, ["EOF/IFS", "E"]]) # EOF=239-280 IFS=281+ + self.put(self.csa, self.csb, self.out_ann, [Ann.ANN_PACKET, ['Checksum','CS','C']]) # retrospective print of CS + self.byte = 0 # reset packet offset + elif t in range(int(self.shortl / self.spd), int(self.shorth / self.spd)): + if pin == self.active: + self.handle_bit(ss, es, 1) + else: + self.handle_bit(ss, es, 0) + elif t in range(int(self.longl / self.spd), int(self.longh / self.spd)): + if pin == self.active: + self.handle_bit(ss, es, 0) + else: + self.handle_bit(ss, es, 1) diff --git a/libsigrokdecode4DSL/decoders/sda2506/__init__.py b/libsigrokdecode4DSL/decoders/sda2506/__init__.py new file mode 100644 index 00000000..bf555109 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/sda2506/__init__.py @@ -0,0 +1,24 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Max Weller +## +## 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, see . +## + +''' +Decoder for Siemens EEPROM SDA 2506-5. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/sda2506/pd.py b/libsigrokdecode4DSL/decoders/sda2506/pd.py new file mode 100644 index 00000000..813bff6a --- /dev/null +++ b/libsigrokdecode4DSL/decoders/sda2506/pd.py @@ -0,0 +1,144 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Max Weller +## Copyright (C) 2019 DreamSourceLab +## +## 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, see . +## + +import re +import sigrokdecode as srd + +ann_cmdbit, ann_databit, ann_cmd, ann_data, ann_warning = range(5) + +class Decoder(srd.Decoder): + api_version = 3 + id = 'sda2506' + name = 'SDA2506' + longname = 'Siemens SDA 2506-5' + desc = 'Serial nonvolatile 1-Kbit EEPROM.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['IC', 'Memory'] + channels = ( + {'id': 'clk', 'name': 'CLK', 'desc': 'Clock'}, + {'id': 'd', 'name': 'DATA', 'desc': 'Data'}, + {'id': 'ce', 'name': 'CE#', 'desc': 'Chip-enable'}, + ) + annotations = ( + ('cmdbit', 'Command bit'), + ('databit', 'Data bit'), + ('cmd', 'Command'), + ('data', 'Data byte'), + ('warnings', 'Human-readable warnings'), + ) + annotation_rows = ( + ('bits', 'Bits', (ann_cmdbit, ann_databit)), + ('commands', 'Commands', (ann_cmd,)), + ('data', 'Data', (ann_data,)), + ('warnings', 'Warnings', (ann_warning,)), + ) + + def __init__(self): + self.samplerate = None + self.reset() + + def reset(self): + self.cmdbits = [] + self.databits = [] + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putbit(self, ss, es, typ, value): + self.put(ss, es, self.out_ann, [typ, ['%s' % (value)]]) + + def putdata(self, ss, es): + value = 0 + for i in range(8): + value = (value << 1) | self.databits[i] + self.put(ss, es, self.out_ann, [ann_data, ['%02X' % (value)]]) + + def decode_bits(self, offset, width): + out = 0 + for i in range(width): + out = (out << 1) | self.cmdbits[offset + i][0] + return (out, self.cmdbits[offset + width - 1][1], self.cmdbits[offset][2]) + + def decode_field(self, name, offset, width): + val, ss, es = self.decode_bits(offset, width) + self.put(ss, es, self.out_ann, [ann_data, ['%s: %02X' % (name, val)]]) + return val + + def decode(self): + while True: + # Wait for CLK edge or CE edge. + (clk, d, ce) = self.wait([{0: 'e'}, {2: 'e'}]) + + if (self.matched & (0b1 << 0)) and ce == 1 and clk == 1: + # Rising clk edge and command mode. + bitstart = self.samplenum + self.wait({0: 'f'}) + self.cmdbits = [(d, bitstart, self.samplenum)] + self.cmdbits + if len(self.cmdbits) > 24: + self.cmdbits = self.cmdbits[0:24] + self.putbit(bitstart, self.samplenum, ann_cmdbit, d) + elif (self.matched & (0b1 << 0)) and ce == 0 and clk == 0: + # Falling clk edge and data mode. + bitstart = self.samplenum + (clk, d, ce) = self.wait([{'skip': int(2.5 * (1e6 / self.samplerate))}, {0: 'r'}, {2: 'e'}]) # Wait 25 us for data ready. + if (self.matched & (0b1 << 2)) and not (self.matched & 0b011): + self.wait([{0: 'r'}, {2: 'e'}]) + if len(self.databits) == 0: + self.datastart = bitstart + self.databits = [d] + self.databits + self.putbit(bitstart, self.samplenum, ann_databit, d) + if len(self.databits) == 8: + self.putdata(self.datastart, self.samplenum) + self.databits = [] + elif (self.matched & (0b1 << 1)) and ce == 0: + # Chip enable edge. + try: + self.decode_field('addr', 1, 7) + self.decode_field('CB', 0, 1) + if self.cmdbits[0][0] == 0: + # Beginning read command. + self.decode_field('read', 1, 7) + self.put(self.cmdbits[7][1], self.samplenum, + self.out_ann, [ann_cmd, ['read' ]]) + elif d == 0: + # Beginning write command. + self.decode_field('data', 8, 8) + addr, ss, es = self.decode_bits(1, 7) + data, ss, es = self.decode_bits(8, 8) + cmdstart = self.samplenum + self.wait({2: 'r'}) + self.put(cmdstart, self.samplenum, self.out_ann, + [ann_cmd, ['Write to %02X: %02X' % (addr, data)]]) + else: + # Beginning erase command. + val, ss, es = self.decode_bits(1, 7) + cmdstart = self.samplenum + self.wait({2: 'r'}) + self.put(cmdstart, self.samplenum, self.out_ann, + [ann_cmd, ['Erase: %02X' % (val)]]) + self.databits = [] + except Exception as ex: + self.reset() diff --git a/libsigrokdecode4DSL/decoders/sdcard_sd/__init__.py b/libsigrokdecode4DSL/decoders/sdcard_sd/__init__.py new file mode 100644 index 00000000..7c334222 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/sdcard_sd/__init__.py @@ -0,0 +1,24 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Uwe Hermann +## +## 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, see . +## + +''' +SD card (SD mode) low-level protocol decoder. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/sdcard_sd/pd.py b/libsigrokdecode4DSL/decoders/sdcard_sd/pd.py new file mode 100644 index 00000000..292d0a6c --- /dev/null +++ b/libsigrokdecode4DSL/decoders/sdcard_sd/pd.py @@ -0,0 +1,583 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015-2020 Uwe Hermann +## +## 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, see . +## + +import sigrokdecode as srd +from common.srdhelper import SrdIntEnum, SrdStrEnum +from common.sdcard import (cmd_names, acmd_names, accepted_voltages, sd_status) + +responses = '1 1b 2 3 6 7'.split() +token_fields = 'START TRANSMISSION CMD ARG CRC END'.split() +reg_card_status = 'OUT_OF_RANGE ADDRESS_ERROR BLOCK_LEN_ERROR ERASE_SEQ_ERROR \ + ERASE_PARAM WP_VIOLATION CARD_IS_LOCKED LOCK_UNLOCK_FAILED COM_CRC_ERROR \ + ILLEGAL_COMMAND CARD_ECC_FAILED CC_ERROR ERROR RSVD_DEFERRED_RESPONSE \ + CSD_OVERWRITE WP_ERASE_SKIP CARD_ECC_DISABLED ERASE_RESET CURRENT_STATE \ + READY_FOR_DATA RSVD FX_EVENT APP_CMD RSVD_SDIO AKE_SEQ_ERROR RSVD_APP_CMD \ + RSVD_TESTMODE'.split() +reg_cid = 'MID OID PNM PRV PSN RSVD MDT CRC ONE'.split() +reg_csd = 'CSD_STRUCTURE RSVD TAAC NSAC TRAN_SPEED CCC READ_BL_LEN \ + READ_BL_PARTIAL WRITE_BLK_MISALIGN READ_BLK_MISALIGN DSR_IMP C_SIZE \ + VDD_R_CURR_MIN VDD_R_CURR_MAX VDD_W_CURR_MIN VDD_W_CURR_MAX C_SIZE_MULT \ + ERASE_BLK_EN SECTOR_SIZE WP_GRP_SIZE WP_GRP_ENABLE R2W_FACTOR \ + WRITE_BL_LEN WRITE_BL_PARTIAL FILE_FORMAT_GRP COPY PERM_WRITE_PROTECT \ + TMP_WRITE_PROTECT FILE_FORMAT CRC ONE'.split() + +Pin = SrdIntEnum.from_str('Pin', 'CMD CLK DAT0 DAT1 DAT2 DAT3') + +a = ['CMD%d' % i for i in range(64)] + ['ACMD%d' % i for i in range(64)] + \ + ['RESPONSE_R' + r.upper() for r in responses] + \ + ['R_STATUS_' + r for r in reg_card_status] + \ + ['R_CID_' + r for r in reg_cid] + \ + ['R_CSD_' + r for r in reg_csd] + \ + ['BIT_' + r for r in ('0', '1')] + \ + ['F_' + f for f in token_fields] + \ + ['DECODED_BIT', 'DECODED_F'] +Ann = SrdIntEnum.from_list('Ann', a) + +s = ['GET_COMMAND_TOKEN', 'HANDLE_CMD999'] + \ + ['HANDLE_CMD%d' % i for i in range(64)] + \ + ['HANDLE_ACMD%d' % i for i in range(64)] + \ + ['GET_RESPONSE_R%s' % r.upper() for r in responses] +St = SrdStrEnum.from_list('St', s) + +class Bit: + def __init__(self, s, e, b): + self.ss, self.es, self.bit = s, e ,b + +class Decoder(srd.Decoder): + api_version = 3 + id = 'sdcard_sd' + name = 'SD card (SD mode)' + longname = 'Secure Digital card (SD mode)' + desc = 'Secure Digital card (SD mode) low-level protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Memory'] + channels = ( + {'id': 'cmd', 'name': 'CMD', 'desc': 'Command'}, + {'id': 'clk', 'name': 'CLK', 'desc': 'Clock'}, + ) + optional_channels = ( + {'id': 'dat0', 'name': 'DAT0', 'desc': 'Data pin 0'}, + {'id': 'dat1', 'name': 'DAT1', 'desc': 'Data pin 1'}, + {'id': 'dat2', 'name': 'DAT2', 'desc': 'Data pin 2'}, + {'id': 'dat3', 'name': 'DAT3', 'desc': 'Data pin 3'}, + ) + annotations = \ + tuple(('cmd%d' % i, 'CMD%d' % i) for i in range(64)) + \ + tuple(('acmd%d' % i, 'ACMD%d' % i) for i in range(64)) + \ + tuple(('response_r%s' % r, 'R%s' % r) for r in responses) + \ + tuple(('reg_status_' + r.lower(), 'Status: ' + r) for r in reg_card_status) + \ + tuple(('reg_cid_' + r.lower(), 'CID: ' + r) for r in reg_cid) + \ + tuple(('reg_csd_' + r.lower(), 'CSD: ' + r) for r in reg_csd) + \ + tuple(('bit_' + r, 'Bit ' + r) for r in ('0', '1')) + \ + tuple(('field-' + r.lower(), r) for r in token_fields) + \ + ( \ + ('decoded-bit', 'Decoded bit'), + ('decoded-field', 'Decoded field'), + ) + annotation_rows = ( + ('raw-bits', 'Raw bits', Ann.prefixes('BIT_')), + ('decoded-bits', 'Decoded bits', (Ann.DECODED_BIT,) + Ann.prefixes('R_')), + ('decoded-fields', 'Decoded fields', (Ann.DECODED_F,)), + ('fields', 'Fields', Ann.prefixes('F_')), + ('commands', 'Commands', Ann.prefixes('CMD ACMD RESPONSE_')), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.state = St.GET_COMMAND_TOKEN + self.token = [] + self.is_acmd = False # Indicates CMD vs. ACMD + self.cmd = None + self.last_cmd = None + self.arg = None + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putt(self, data): + self.put(self.token[0].ss, self.token[47].es, self.out_ann, data) + + def putf(self, s, e, data): + self.put(self.token[s].ss, self.token[e].es, self.out_ann, data) + + def puta(self, s, e, data): + self.put(self.token[47 - 8 - e].ss, self.token[47 - 8 - s].es, + self.out_ann, data) + + def putc(self, desc): + cmd = Ann.ACMD0 + self.cmd if self.is_acmd else self.cmd + self.last_cmd = cmd + self.putt([cmd, ['%s: %s' % (self.cmd_str, desc), self.cmd_str, + self.cmd_str.split(' ')[0]]]) + + def putr(self, r): + self.putt([r, ['Response: %s' % r.name.split('_')[1]]]) + + def cmd_name(self, cmd): + c = acmd_names if self.is_acmd else cmd_names + return c.get(cmd, 'Unknown') + + def get_token_bits(self, cmd_pin, n): + # Get a bit, return True if we already got 'n' bits, False otherwise. + self.token.append(Bit(self.samplenum, self.samplenum, cmd_pin)) + if len(self.token) > 0: + self.token[len(self.token) - 2].es = self.samplenum + if len(self.token) < n: + return False + self.token[n - 1].es += self.token[n - 1].ss - self.token[n - 2].ss + return True + + def is_from_host(self): + # CMD[46:46]: Transmission bit (1 == host), (0 == card) + return self.token[1].bit == 1 + + def is_from_card(self): + # CMD[46:46]: Transmission bit (1 == host), (0 == card) + return self.token[1].bit == 0 + + def handle_common_token_fields(self): + s = self.token + + # Annotations for each individual bit. + for bit in range(len(self.token)): + self.putf(bit, bit, [Ann.BIT_0 + s[bit].bit, ['%d' % s[bit].bit]]) + + # CMD[47:47]: Start bit (always 0) + self.putf(0, 0, [Ann.F_START, ['Start bit', 'Start', 'S']]) + + # CMD[46:46]: Transmission bit (1 == host) + t = 'host' if s[1].bit == 1 else 'card' + self.putf(1, 1, [Ann.F_TRANSMISSION, ['Transmission: ' + t, 'T: ' + t, 'T']]) + + # CMD[45:40]: Command index (BCD; valid: 0-63) + self.cmd = int('0b' + ''.join([str(s[i].bit) for i in range(2, 8)]), 2) + c = '%s (%d)' % (self.cmd_name(self.cmd), self.cmd) + self.putf(2, 7, [Ann.F_CMD, ['Command: ' + c, 'Cmd: ' + c, + 'CMD%d' % self.cmd, 'Cmd', 'C']]) + + # CMD[39:08]: Argument + self.arg = int('0b' + ''.join([str(s[i].bit) for i in range(8, 40)]), 2) + self.putf(8, 39, [Ann.F_ARG, ['Argument: 0x%08x' % self.arg, 'Arg', 'A']]) + + # CMD[07:01]: CRC7 + self.crc = int('0b' + ''.join([str(s[i].bit) for i in range(40, 47)]), 2) + self.putf(40, 46, [Ann.F_CRC, ['CRC: 0x%x' % self.crc, 'CRC', 'C']]) + + # CMD[00:00]: End bit (always 1) + self.putf(47, 47, [Ann.F_END, ['End bit', 'End', 'E']]) + + def get_command_token(self, cmd_pin): + # Command tokens (48 bits) are sent serially (MSB-first) by the host + # (over the CMD line), either to one SD card or to multiple ones. + # + # Format: + # - Bits[47:47]: Start bit (always 0) + # - Bits[46:46]: Transmission bit (1 == host) + # - Bits[45:40]: Command index (BCD; valid: 0-63) + # - Bits[39:08]: Argument + # - Bits[07:01]: CRC7 + # - Bits[00:00]: End bit (always 1) + + if not self.get_token_bits(cmd_pin, 48): + return + if not self.is_from_host(): + # Bad state due to a decoding mistake or a protocol error, + # drop the current token to try to recover from this situation. + self.token, self.state = [], St.GET_COMMAND_TOKEN + return + + self.handle_cmd() + + def handle_cmd(self): + self.handle_common_token_fields() + + # Handle command. + s = 'ACMD' if self.is_acmd else 'CMD' + self.cmd_str = '%s%d (%s)' % (s, self.cmd, self.cmd_name(self.cmd)) + if hasattr(self, 'handle_%s%d' % (s.lower(), self.cmd)): + self.state = St['HANDLE_CMD%d' % self.cmd] + else: + self.state = St.HANDLE_CMD999 + self.putc('%s%d' % (s, self.cmd)) + + def handle_cmd0(self): + # CMD0 (GO_IDLE_STATE) -> no response + self.puta(0, 31, [Ann.DECODED_F, ['Stuff bits', 'Stuff', 'SB', 'S']]) + self.putc('Reset all SD cards') + self.token, self.state = [], St.GET_COMMAND_TOKEN + + def handle_cmd2(self): + # CMD2 (ALL_SEND_CID) -> R2 + self.puta(0, 31, [Ann.DECODED_F, ['Stuff bits', 'Stuff', 'SB', 'S']]) + self.putc('Ask card for CID number') + self.token, self.state = [], St.GET_RESPONSE_R2 + + def handle_cmd3(self): + # CMD3 (SEND_RELATIVE_ADDR) -> R6 + self.puta(0, 31, [Ann.DECODED_F, ['Stuff bits', 'Stuff', 'SB', 'S']]) + self.putc('Ask card for new relative card address (RCA)') + self.token, self.state = [], St.GET_RESPONSE_R6 + + def handle_cmd6(self): + # CMD6 (SWITCH_FUNC) -> R1 + self.putc('Switch/check card function') + self.token, self.state = [], St.GET_RESPONSE_R1 + + def handle_cmd7(self): + # CMD7 (SELECT/DESELECT_CARD) -> R1b + self.putc('Select / deselect card') + self.token, self.state = [], St.GET_RESPONSE_R6 + + def handle_cmd8(self): + # CMD8 (SEND_IF_COND) -> R7 + self.puta(12, 31, [Ann.DECODED_F, ['Reserved', 'Res', 'R']]) + self.puta(8, 11, [Ann.DECODED_F, ['Supply voltage', 'Voltage', 'VHS', 'V']]) + self.puta(0, 7, [Ann.DECODED_F, ['Check pattern', 'Check pat', 'Check', 'C']]) + self.putc('Send interface condition to card') + self.token, self.state = [], St.GET_RESPONSE_R7 + # TODO: Handle case when card doesn't reply with R7 (no reply at all). + + def handle_cmd9(self): + # CMD9 (SEND_CSD) -> R2 + self.puta(16, 31, [Ann.DECODED_F, ['RCA', 'R']]) + self.puta(0, 15, [Ann.DECODED_F, ['Stuff bits', 'Stuff', 'SB', 'S']]) + self.putc('Send card-specific data (CSD)') + self.token, self.state = [], St.GET_RESPONSE_R2 + + def handle_cmd10(self): + # CMD10 (SEND_CID) -> R2 + self.puta(16, 31, [Ann.DECODED_F, ['RCA', 'R']]) + self.puta(0, 15, [Ann.DECODED_F, ['Stuff bits', 'Stuff', 'SB', 'S']]) + self.putc('Send card identification data (CID)') + self.token, self.state = [], St.GET_RESPONSE_R2 + + def handle_cmd13(self): + # CMD13 (SEND_STATUS) -> R1 + self.puta(16, 31, [Ann.DECODED_F, ['RCA', 'R']]) + self.puta(0, 15, [Ann.DECODED_F, ['Stuff bits', 'Stuff', 'SB', 'S']]) + self.putc('Send card status register') + self.token, self.state = [], St.GET_RESPONSE_R1 + + def handle_cmd16(self): + # CMD16 (SET_BLOCKLEN) -> R1 + self.puta(0, 31, [Ann.DECODED_F, ['Block length', 'Blocklen', 'BL', 'B']]) + self.putc('Set the block length to %d bytes' % self.arg) + self.token, self.state = [], St.GET_RESPONSE_R1 + + def handle_cmd55(self): + # CMD55 (APP_CMD) -> R1 + self.puta(16, 31, [Ann.DECODED_F, ['RCA', 'R']]) + self.puta(0, 15, [Ann.DECODED_F, ['Stuff bits', 'Stuff', 'SB', 'S']]) + self.putc('Next command is an application-specific command') + self.is_acmd = True + self.token, self.state = [], St.GET_RESPONSE_R1 + + def handle_acmd6(self): + # ACMD6 (SET_BUS_WIDTH) -> R1 + self.putc('Read SD config register (SCR)') + self.token, self.state = [], St.GET_RESPONSE_R1 + + def handle_acmd13(self): + # ACMD13 (SD_STATUS) -> R1 + self.puta(0, 31, [Ann.DECODED_F, ['Stuff bits', 'Stuff', 'SB', 'S']]) + self.putc('Set SD status') + self.token, self.state = [], St.GET_RESPONSE_R1 + + def handle_acmd41(self): + # ACMD41 (SD_SEND_OP_COND) -> R3 + self.puta(0, 23, [Ann.DECODED_F, + ['VDD voltage window', 'VDD volt', 'VDD', 'V']]) + self.puta(24, 24, [Ann.DECODED_F, ['S18R']]) + self.puta(25, 27, [Ann.DECODED_F, ['Reserved', 'Res', 'R']]) + self.puta(28, 28, [Ann.DECODED_F, ['XPC']]) + self.puta(29, 29, [Ann.DECODED_F, + ['Reserved for eSD', 'Reserved', 'Res', 'R']]) + self.puta(30, 30, [Ann.DECODED_F, + ['Host capacity support info', 'Host capacity', 'HCS', 'H']]) + self.puta(31, 31, [Ann.DECODED_F, ['Reserved', 'Res', 'R']]) + self.putc('Send HCS info and activate the card init process') + self.token, self.state = [], St.GET_RESPONSE_R3 + + def handle_acmd51(self): + # ACMD51 (SEND_SCR) -> R1 + self.putc('Read SD config register (SCR)') + self.token, self.state = [], St.GET_RESPONSE_R1 + + def handle_cmd999(self): + self.token, self.state = [], St.GET_RESPONSE_R1 + + def handle_acmd999(self): + self.token, self.state = [], St.GET_RESPONSE_R1 + + def handle_reg_status(self): + self.putf(8, 8, [Ann.R_STATUS_OUT_OF_RANGE, ['OUT_OF_RANGE']]) + self.putf(9, 9, [Ann.R_STATUS_ADDRESS_ERROR, ['ADDRESS_ERROR']]) + self.putf(10, 10, [Ann.R_STATUS_BLOCK_LEN_ERROR, ['BLOCK_LEN_ERROR']]) + self.putf(11, 11, [Ann.R_STATUS_ERASE_SEQ_ERROR, ['ERASE_SEQ_ERROR']]) + self.putf(12, 12, [Ann.R_STATUS_ERASE_PARAM, ['ERASE_PARAM']]) + self.putf(13, 13, [Ann.R_STATUS_WP_VIOLATION, ['WP_VIOLATION']]) + self.putf(14, 14, [Ann.R_STATUS_CARD_IS_LOCKED, ['CARD_IS_LOCKED']]) + self.putf(15, 15, [Ann.R_STATUS_LOCK_UNLOCK_FAILED, ['LOCK_UNLOCK_FAILED']]) + self.putf(16, 16, [Ann.R_STATUS_COM_CRC_ERROR, ['COM_CRC_ERROR']]) + self.putf(17, 17, [Ann.R_STATUS_ILLEGAL_COMMAND, ['ILLEGAL_COMMAND']]) + self.putf(18, 18, [Ann.R_STATUS_CARD_ECC_FAILED, ['CARD_ECC_FAILED']]) + self.putf(19, 19, [Ann.R_STATUS_CC_ERROR, ['CC_ERROR']]) + self.putf(20, 20, [Ann.R_STATUS_ERROR, ['ERROR']]) + self.putf(21, 21, [Ann.R_STATUS_RSVD, ['Reserved', 'RSVD', 'R']]) + self.putf(22, 22, [Ann.R_STATUS_RSVD_DEFERRED_RESPONSE, ['Reserved for DEFERRED_RESPONSE', 'RSVD_DEFERRED_RESPONSE']]) + self.putf(23, 23, [Ann.R_STATUS_CSD_OVERWRITE, ['CSD_OVERWRITE']]) + self.putf(24, 24, [Ann.R_STATUS_WP_ERASE_SKIP, ['WP_ERASE_SKIP']]) + self.putf(25, 25, [Ann.R_STATUS_CARD_ECC_DISABLED, ['CARD_ECC_DISABLED']]) + self.putf(26, 26, [Ann.R_STATUS_ERASE_RESET, ['ERASE_RESET']]) + self.putf(27, 30, [Ann.R_STATUS_CURRENT_STATE, ['CURRENT_STATE']]) + self.putf(31, 31, [Ann.R_STATUS_READY_FOR_DATA, ['READY_FOR_DATA']]) + self.putf(32, 32, [Ann.R_STATUS_RSVD, ['RSVD']]) + self.putf(33, 33, [Ann.R_STATUS_FX_EVENT, ['FX_EVENT']]) + self.putf(34, 34, [Ann.R_STATUS_APP_CMD, ['APP_CMD']]) + self.putf(35, 35, [Ann.R_STATUS_RSVD_SDIO, ['Reserved for SDIO card', 'RSVD_SDIO']]) + self.putf(36, 36, [Ann.R_STATUS_AKE_SEQ_ERROR, ['AKE_SEQ_ERROR']]) + self.putf(37, 37, [Ann.R_STATUS_RSVD_APP_CMD, ['Reserved for application specific commands', 'RSVD_APP_CMD']]) + self.putf(38, 39, [Ann.R_STATUS_RSVD_TESTMODE, ['Reserved for manufacturer test mode', 'RSVD_TESTMODE']]) + + def handle_reg_cid(self): + self.putf(8, 15, [Ann.R_CID_MID, ['Manufacturer ID', 'MID']]) + self.putf(16, 31, [Ann.R_CID_OID, ['OEM/application ID', 'OID']]) + self.putf(32, 71, [Ann.R_CID_PNM, ['Product name', 'PNM']]) + self.putf(72, 79, [Ann.R_CID_PRV, ['Product revision', 'PRV']]) + self.putf(80, 111, [Ann.R_CID_PSN, ['Product serial number', 'PSN']]) + self.putf(112, 115, [Ann.R_CID_RSVD, ['Reserved', 'RSVD', 'R']]) + self.putf(116, 127, [Ann.R_CID_MDT, ['Manufacturing date', 'MDT']]) + self.putf(128, 134, [Ann.R_CID_CRC, ['CRC7 checksum', 'CRC']]) + self.putf(135, 135, [Ann.R_CID_ONE, ['Always 1', '1']]) + + def handle_reg_csd(self): + self.putf(8, 9, [Ann.R_CSD_CSD_STRUCTURE, ['CSD structure', 'CSD_STRUCTURE']]) + self.putf(10, 15, [Ann.R_CSD_RSVD, ['Reserved', 'RSVD', 'R']]) + self.putf(16, 23, [Ann.R_CSD_TAAC, ['Data read access-time - 1', 'TAAC']]) + self.putf(24, 31, [Ann.R_CSD_NSAC, ['Data read access-time - 2 in CLK cycles (NSAC * 100)', 'NSAC']]) + self.putf(32, 39, [Ann.R_CSD_TRAN_SPEED, ['Max. data transfer rate', 'TRAN_SPEED']]) + self.putf(40, 51, [Ann.R_CSD_CCC, ['Card command classes', 'CCC']]) + self.putf(52, 55, [Ann.R_CSD_READ_BL_LEN, ['Max. read data block length', 'READ_BL_LEN']]) + self.putf(56, 56, [Ann.R_CSD_READ_BL_PARTIAL, ['Partial blocks for read allowed', 'READ_BL_PARTIAL']]) + self.putf(57, 57, [Ann.R_CSD_WRITE_BLK_MISALIGN, ['Write block misalignment', 'WRITE_BLK_MISALIGN']]) + self.putf(58, 58, [Ann.R_CSD_READ_BLK_MISALIGN, ['Read block misalignment', 'READ_BLK_MISALIGN']]) + self.putf(59, 59, [Ann.R_CSD_DSR_IMP, ['DSR implemented', 'DSR_IMP']]) + self.putf(60, 61, [Ann.R_CSD_RSVD, ['Reserved', 'RSVD', 'R']]) + self.putf(62, 73, [Ann.R_CSD_C_SIZE, ['Device size', 'C_SIZE']]) + self.putf(74, 76, [Ann.R_CSD_VDD_R_CURR_MIN, ['Max. read current @VDD min', 'VDD_R_CURR_MIN']]) + self.putf(77, 79, [Ann.R_CSD_VDD_R_CURR_MAX, ['Max. read current @VDD max', 'VDD_R_CURR_MAX']]) + self.putf(80, 82, [Ann.R_CSD_VDD_W_CURR_MIN, ['Max. write current @VDD min', 'VDD_W_CURR_MIN']]) + self.putf(83, 85, [Ann.R_CSD_VDD_W_CURR_MAX, ['Max. write current @VDD max', 'VDD_W_CURR_MAX']]) + self.putf(86, 88, [Ann.R_CSD_C_SIZE_MULT, ['Device size multiplier', 'C_SIZE_MULT']]) + self.putf(89, 89, [Ann.R_CSD_ERASE_BLK_EN, ['Erase single block enable', 'ERASE_BLK_EN']]) + self.putf(90, 96, [Ann.R_CSD_SECTOR_SIZE, ['Erase sector size', 'SECTOR_SIZE']]) + self.putf(97, 103, [Ann.R_CSD_WP_GRP_SIZE, ['Write protect group size', 'WP_GRP_SIZE']]) + self.putf(104, 104, [Ann.R_CSD_WP_GRP_ENABLE, ['Write protect group enable', 'WP_GRP_ENABLE']]) + self.putf(105, 106, [Ann.R_CSD_RSVD, ['Reserved', 'RSVD', 'R']]) + self.putf(107, 109, [Ann.R_CSD_R2W_FACTOR, ['Write speed factor', 'R2W_FACTOR']]) + self.putf(110, 113, [Ann.R_CSD_WRITE_BL_LEN, ['Max. write data block length', 'WRITE_BL_LEN']]) + self.putf(114, 114, [Ann.R_CSD_WRITE_BL_PARTIAL, ['Partial blocks for write allowed', 'WRITE_BL_PARTIAL']]) + self.putf(115, 119, [Ann.R_CSD_RSVD, ['Reserved', 'RSVD']]) + self.putf(120, 120, [Ann.R_CSD_FILE_FORMAT_GRP, ['File format group', 'FILE_FORMAT_GRP']]) + self.putf(121, 121, [Ann.R_CSD_COPY, ['Copy flag', 'COPY']]) + self.putf(122, 122, [Ann.R_CSD_PERM_WRITE_PROTECT, ['Permanent write protection', 'PERM_WRITE_PROTECT']]) + self.putf(123, 123, [Ann.R_CSD_TMP_WRITE_PROTECT, ['Temporary write protection', 'TMP_WRITE_PROTECT']]) + self.putf(124, 125, [Ann.R_CSD_FILE_FORMAT, ['File format', 'FILE_FORMAT']]) + self.putf(126, 127, [Ann.R_CSD_RSVD, ['Reserved', 'RSVD', 'R']]) + self.putf(128, 134, [Ann.R_CSD_CRC, ['CRC', 'CRC', 'C']]) + self.putf(135, 135, [Ann.R_CSD_ONE, ['Always 1', '1']]) + + # Response tokens can have one of four formats (depends on content). + # They can have a total length of 48 or 136 bits. + # They're sent serially (MSB-first) by the card that the host + # addressed previously, or (synchronously) by all connected cards. + + def handle_response_r1(self, cmd_pin): + # R1: Normal response command + # - Bits[47:47]: Start bit (always 0) + # - Bits[46:46]: Transmission bit (0 == card) + # - Bits[45:40]: Command index (BCD; valid: 0-63) + # - Bits[39:08]: Card status + # - Bits[07:01]: CRC7 + # - Bits[00:00]: End bit (always 1) + if not self.get_token_bits(cmd_pin, 48): + return + assert(self.is_from_card()) + self.handle_common_token_fields() + self.putr(Ann.RESPONSE_R1) + self.puta(0, 31, [Ann.DECODED_F, ['Card status', 'Status', 'S']]) + self.handle_reg_status() + + self.token, self.state = [], St.GET_COMMAND_TOKEN + + def handle_response_r1b(self, cmd_pin): + # R1b: Same as R1 with an optional busy signal (on the data line) + if not self.get_token_bits(cmd_pin, 48): + return + assert(self.is_from_card()) + self.handle_common_token_fields() + self.puta(0, 31, [Ann.DECODED_F, ['Card status', 'Status', 'S']]) + self.putr(Ann.RESPONSE_R1B) + self.token, self.state = [], St.GET_COMMAND_TOKEN + + def handle_response_r2(self, cmd_pin): + # R2: CID/CSD register + # - Bits[135:135]: Start bit (always 0) + # - Bits[134:134]: Transmission bit (0 == card) + # - Bits[133:128]: Reserved (always 0b111111) + # - Bits[127:001]: CID or CSD register including internal CRC7 + # - Bits[000:000]: End bit (always 1) + if not self.get_token_bits(cmd_pin, 136): + return + assert(self.is_from_card()) + # Annotations for each individual bit. + for bit in range(len(self.token)): + self.putf(bit, bit, [Ann.BIT_0 + self.token[bit].bit, ['%d' % self.token[bit].bit]]) + self.putf(0, 0, [Ann.F_START, ['Start bit', 'Start', 'S']]) + t = 'host' if self.token[1].bit == 1 else 'card' + self.putf(1, 1, [Ann.F_TRANSMISSION, ['Transmission: ' + t, 'T: ' + t, 'T']]) + self.putf(2, 7, [Ann.F_CMD, ['Reserved', 'Res', 'R']]) + self.putf(8, 134, [Ann.F_ARG, ['Argument', 'Arg', 'A']]) + self.putf(135, 135, [Ann.F_END, ['End bit', 'End', 'E']]) + self.putf(8, 134, [Ann.DECODED_F, ['CID/CSD register', 'CID/CSD', 'C']]) + self.putf(0, 135, [Ann.RESPONSE_R2, ['Response: R2']]) + + if self.last_cmd in (Ann.CMD2, Ann.CMD10): + self.handle_reg_cid() + + if self.last_cmd == Ann.CMD9: + self.handle_reg_csd() + + self.token, self.state = [], St.GET_COMMAND_TOKEN + + def handle_response_r3(self, cmd_pin): + # R3: OCR register + # - Bits[47:47]: Start bit (always 0) + # - Bits[46:46]: Transmission bit (0 == card) + # - Bits[45:40]: Reserved (always 0b111111) + # - Bits[39:08]: OCR register + # - Bits[07:01]: Reserved (always 0b111111) + # - Bits[00:00]: End bit (always 1) + if not self.get_token_bits(cmd_pin, 48): + return + assert(self.is_from_card()) + self.putr(Ann.RESPONSE_R3) + # Annotations for each individual bit. + for bit in range(len(self.token)): + self.putf(bit, bit, [Ann.BIT_0 + self.token[bit].bit, ['%d' % self.token[bit].bit]]) + self.putf(0, 0, [Ann.F_START, ['Start bit', 'Start', 'S']]) + t = 'host' if self.token[1].bit == 1 else 'card' + self.putf(1, 1, [Ann.F_TRANSMISSION, ['Transmission: ' + t, 'T: ' + t, 'T']]) + self.putf(2, 7, [Ann.F_CMD, ['Reserved', 'Res', 'R']]) + self.putf(8, 39, [Ann.F_ARG, ['Argument', 'Arg', 'A']]) + self.putf(40, 46, [Ann.F_CRC, ['Reserved', 'Res', 'R']]) + self.putf(47, 47, [Ann.F_END, ['End bit', 'End', 'E']]) + self.puta(0, 31, [Ann.DECODED_F, ['OCR register', 'OCR reg', 'OCR', 'O']]) + self.token, self.state = [], St.GET_COMMAND_TOKEN + + def handle_response_r6(self, cmd_pin): + # R6: Published RCA response + # - Bits[47:47]: Start bit (always 0) + # - Bits[46:46]: Transmission bit (0 == card) + # - Bits[45:40]: Command index (always 0b000011) + # - Bits[39:24]: Argument[31:16]: New published RCA of the card + # - Bits[23:08]: Argument[15:0]: Card status bits + # - Bits[07:01]: CRC7 + # - Bits[00:00]: End bit (always 1) + if not self.get_token_bits(cmd_pin, 48): + return + assert(self.is_from_card()) + self.handle_common_token_fields() + self.puta(0, 15, [Ann.DECODED_F, ['Card status bits', 'Status', 'S']]) + self.puta(16, 31, [Ann.DECODED_F, ['Relative card address', 'RCA', 'R']]) + self.putr(Ann.RESPONSE_R6) + self.token, self.state = [], St.GET_COMMAND_TOKEN + + def handle_response_r7(self, cmd_pin): + # R7: Card interface condition + # - Bits[47:47]: Start bit (always 0) + # - Bits[46:46]: Transmission bit (0 == card) + # - Bits[45:40]: Command index (always 0b001000) + # - Bits[39:20]: Reserved bits (all-zero) + # - Bits[19:16]: Voltage accepted + # - Bits[15:08]: Echo-back of check pattern + # - Bits[07:01]: CRC7 + # - Bits[00:00]: End bit (always 1) + if not self.get_token_bits(cmd_pin, 48): + return + assert(self.is_from_card()) + self.handle_common_token_fields() + + self.putr(Ann.RESPONSE_R7) + + # Arg[31:12]: Reserved bits (all-zero) + self.puta(12, 31, [Ann.DECODED_F, ['Reserved', 'Res', 'R']]) + + # Arg[11:08]: Voltage accepted + v = ''.join(str(i.bit) for i in self.token[28:32]) + av = accepted_voltages.get(int('0b' + v, 2), 'Unknown') + self.puta(8, 11, [Ann.DECODED_F, + ['Voltage accepted: ' + av, 'Voltage', 'Volt', 'V']]) + + # Arg[07:00]: Echo-back of check pattern + self.puta(0, 7, [Ann.DECODED_F, + ['Echo-back of check pattern', 'Echo', 'E']]) + + self.token, self.state = [], St.GET_COMMAND_TOKEN + + def decode(self): + while True: + conds = {Pin.CLK: 'r'} + + # Wait for start bit (CMD = 0). + if ((self.state == St.GET_COMMAND_TOKEN or + self.state.value.startswith('GET_RESPONSE')) and + (len(self.token) == 0)): + conds.update({Pin.CMD: 'l'}) + + # Wait for a rising CLK edge. + (cmd_pin, clk, dat0, dat1, dat2, dat3) = self.wait(conds) + + # State machine. + if self.state == St.GET_COMMAND_TOKEN: + self.get_command_token(cmd_pin) + elif self.state.value.startswith('HANDLE_CMD'): + # Call the respective handler method for the command. + a, cmdstr = 'a' if self.is_acmd else '', self.state.value[10:].lower() + handle_cmd = getattr(self, 'handle_%scmd%s' % (a, cmdstr)) + handle_cmd() + # Leave ACMD mode again after the first command after CMD55. + if self.is_acmd and cmdstr not in ('55', '63'): + self.is_acmd = False + elif self.state.value.startswith('GET_RESPONSE'): + # Call the respective handler method for the response. + s = 'handle_response_%s' % self.state.value[13:].lower() + handle_response = getattr(self, s) + + # AssertionError can be raised when the token we are trying + # to handle as a response is in fact a command. + # (Transmission bit is 1). Just re-handle the token as command. + try: + handle_response(cmd_pin) + except AssertionError: + self.handle_cmd() diff --git a/libsigrokdecode4DSL/decoders/sdcard_spi/__init__.py b/libsigrokdecode4DSL/decoders/sdcard_spi/__init__.py new file mode 100644 index 00000000..a0945162 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/sdcard_spi/__init__.py @@ -0,0 +1,68 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +''' +This decoder stacks on top of the 'spi' PD and decodes the SD card +(SPI mode) low-level protocol. + +Most SD cards can be accessed via two different protocols/modes: SD mode +or SPI mode. + +All SD cards are in SD mode upon powerup. They can be switched to SPI mode +using a special method involving CMD0 (see spec). Once in SPI mode, the mode +can no longer be changed without a power-cycle of the card. + +SPI mode properties (differences to SD mode): + * The 'sdcard_spi' PD stacks on top of the 'spi' PD. This is not possible + for the 'sdcard_sd' PD, as that protocol is not SPI related at all. + Hence 'sdcard_spi' and 'sdcard_sd' are two separate PDs. + * The state machines for SPI mode and SD mode are different. + * In SPI mode, data transfers are byte-oriented (commands/data are multiples + of 8 bits, with the CS# pin asserted respectively), unlike SD mode where + commands/data are bit-oriented with parallel transmission of 1 or 4 bits. + * While the SPI mode command set has some commands in common with the + SD mode command set, they are not the same and also not a subset/superset. + Some commands are only available in SD mode (e.g. CMD2), some only + in SPI mode (e.g. CMD1). + * Response types of commands also differ between SD mode and SPI mode. + E.g. CMD9 has an R2 response in SD mode, but R1 in SPI mode. + * The commands and functions in SD mode defined after version 2.00 of the + spec are NOT supported in SPI mode. + * SPI mode: The selected SD card ALWAYS responds to commands (unlike SD mode). + * Upon data retrieval problems (read operations) the card will respond with + an error response (and no data), as opposed to a timeout in SD mode. + * SPI mode: For every data block sent to the card (write operations) the host + gets a data response token from the card. + * SDSC: A data block can be max. one card write block, min. 1 byte. + * SDHC/SDXC: Block length is fixed to 512. The block length set by CMD16 + is only used for CDM42 (not for memory data transfers). Thus, partial + read/write operations are disabled in SPI mode. + * SPI mode: Write protected commands (CMD28, CMD29, CMD30) are not supported. + * The SD mode state machine is NOT used. All commands that are supported + in SPI mode are always available. + * Per default the card is in CRC OFF mode. Exception: CMD0 (which is used to + switch to SPI mode) needs a valid CRC. + * The APP_CMD status bit is not available in SPI mode. + * TODO: Switch function command differences. + * In SPI mode cards cannot guarantee their speed class (the host should + assume class 0, no matter what the card indicates). + * The RCA register is not accessible in SPI mode. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/sdcard_spi/pd.py b/libsigrokdecode4DSL/decoders/sdcard_spi/pd.py new file mode 100644 index 00000000..962438f1 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/sdcard_spi/pd.py @@ -0,0 +1,465 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012-2014 Uwe Hermann +## +## 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, see . +## + +import sigrokdecode as srd +from common.sdcard import (cmd_names, acmd_names) + +class Decoder(srd.Decoder): + api_version = 3 + id = 'sdcard_spi' + name = 'SD card (SPI mode)' + longname = 'Secure Digital card (SPI mode)' + desc = 'Secure Digital card (SPI mode) low-level protocol.' + license = 'gplv2+' + inputs = ['spi'] + outputs = [] + tags = ['Memory'] + annotations = \ + tuple(('cmd%d' % i, 'CMD%d' % i) for i in range(64)) + \ + tuple(('acmd%d' % i, 'ACMD%d' % i) for i in range(64)) + ( \ + ('r1', 'R1 reply'), + ('r1b', 'R1B reply'), + ('r2', 'R2 reply'), + ('r3', 'R3 reply'), + ('r7', 'R7 reply'), + ('bits', 'Bits'), + ('bit-warnings', 'Bit warnings'), + ) + annotation_rows = ( + ('bits', 'Bits', (133, 134)), + ('cmd-reply', 'Commands/replies', tuple(range(133))), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.state = 'IDLE' + self.ss, self.es = 0, 0 + self.ss_bit, self.es_bit = 0, 0 + self.ss_cmd, self.es_cmd = 0, 0 + self.cmd_token = [] + self.cmd_token_bits = [] + self.is_acmd = False # Indicates CMD vs. ACMD + self.blocklen = 0 + self.read_buf = [] + self.cmd_str = '' + self.is_cmd24 = False + self.cmd24_start_token_found = False + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + self.put(self.ss_cmd, self.es_cmd, self.out_ann, data) + + def putc(self, cmd, desc): + self.putx([cmd, ['%s: %s' % (self.cmd_str, desc)]]) + + def putb(self, data): + self.put(self.ss_bit, self.es_bit, self.out_ann, data) + + def cmd_name(self, cmd): + c = acmd_names if self.is_acmd else cmd_names + s = c.get(cmd, 'Unknown') + # SD mode names for CMD32/33: ERASE_WR_BLK_{START,END}. + # SPI mode names for CMD32/33: ERASE_WR_BLK_{START,END}_ADDR. + if cmd in (32, 33): + s += '_ADDR' + return s + + def handle_command_token(self, mosi, miso): + # Command tokens (6 bytes) are sent (MSB-first) by the host. + # + # Format: + # - CMD[47:47]: Start bit (always 0) + # - CMD[46:46]: Transmitter bit (1 == host) + # - CMD[45:40]: Command index (BCD; valid: 0-63) + # - CMD[39:08]: Argument + # - CMD[07:01]: CRC7 + # - CMD[00:00]: End bit (always 1) + + if len(self.cmd_token) == 0: + self.ss_cmd = self.ss + + self.cmd_token.append(mosi) + self.cmd_token_bits.append(self.mosi_bits) + + # All command tokens are 6 bytes long. + if len(self.cmd_token) < 6: + return + + self.es_cmd = self.es + + t = self.cmd_token + + # CMD or ACMD? + s = 'ACMD' if self.is_acmd else 'CMD' + + def tb(byte, bit): + return self.cmd_token_bits[5 - byte][bit] + + # Bits[47:47]: Start bit (always 0) + bit, self.ss_bit, self.es_bit = tb(5, 7)[0], tb(5, 7)[1], tb(5, 7)[2] + if bit == 0: + self.putb([134, ['Start bit: %d' % bit]]) + else: + self.putb([135, ['Start bit: %s (Warning: Must be 0!)' % bit]]) + + # Bits[46:46]: Transmitter bit (1 == host) + bit, self.ss_bit, self.es_bit = tb(5, 6)[0], tb(5, 6)[1], tb(5, 6)[2] + if bit == 1: + self.putb([134, ['Transmitter bit: %d' % bit]]) + else: + self.putb([135, ['Transmitter bit: %d (Warning: Must be 1!)' % bit]]) + + # Bits[45:40]: Command index (BCD; valid: 0-63) + cmd = self.cmd_index = t[0] & 0x3f + self.ss_bit, self.es_bit = tb(5, 5)[1], tb(5, 0)[2] + self.putb([134, ['Command: %s%d (%s)' % (s, cmd, self.cmd_name(cmd))]]) + + # Bits[39:8]: Argument + self.arg = (t[1] << 24) | (t[2] << 16) | (t[3] << 8) | t[4] + self.ss_bit, self.es_bit = tb(4, 7)[1], tb(1, 0)[2] + self.putb([134, ['Argument: 0x%04x' % self.arg]]) + + # Bits[7:1]: CRC7 + # TODO: Check CRC7. + crc = t[5] >> 1 + self.ss_bit, self.es_bit = tb(0, 7)[1], tb(0, 1)[2] + self.putb([134, ['CRC7: 0x%01x' % crc]]) + + # Bits[0:0]: End bit (always 1) + bit, self.ss_bit, self.es_bit = tb(0, 0)[0], tb(0, 0)[1], tb(0, 0)[2] + if bit == 1: + self.putb([134, ['End bit: %d' % bit]]) + else: + self.putb([135, ['End bit: %d (Warning: Must be 1!)' % bit]]) + + # Handle command. + if cmd in (0, 1, 9, 16, 17, 24, 41, 49, 55, 59): + self.state = 'HANDLE CMD%d' % cmd + self.cmd_str = '%s%d (%s)' % (s, cmd, self.cmd_name(cmd)) + else: + self.state = 'HANDLE CMD999' + a = '%s%d: %02x %02x %02x %02x %02x %02x' % ((s, cmd) + tuple(t)) + self.putx([cmd, [a]]) + + def handle_cmd0(self): + # CMD0: GO_IDLE_STATE + self.putc(0, 'Reset the SD card') + self.state = 'GET RESPONSE R1' + + def handle_cmd1(self): + # CMD1: SEND_OP_COND + self.putc(1, 'Send HCS info and activate the card init process') + hcs = (self.arg & (1 << 30)) >> 30 + self.ss_bit = self.cmd_token_bits[5 - 4][6][1] + self.es_bit = self.cmd_token_bits[5 - 4][6][2] + self.putb([134, ['HCS: %d' % hcs]]) + self.state = 'GET RESPONSE R1' + + def handle_cmd9(self): + # CMD9: SEND_CSD (128 bits / 16 bytes) + self.putc(9, 'Ask card to send its card specific data (CSD)') + if len(self.read_buf) == 0: + self.ss_cmd = self.ss + self.read_buf.append(self.miso) + # FIXME + ### if len(self.read_buf) < 16: + if len(self.read_buf) < 16 + 4: + return + self.es_cmd = self.es + self.read_buf = self.read_buf[4:] # TODO: Document or redo. + self.putx([9, ['CSD: %s' % self.read_buf]]) + # TODO: Decode all bits. + self.read_buf = [] + ### self.state = 'GET RESPONSE R1' + self.state = 'IDLE' + + def handle_cmd10(self): + # CMD10: SEND_CID (128 bits / 16 bytes) + self.putc(10, 'Ask card to send its card identification (CID)') + self.read_buf.append(self.miso) + if len(self.read_buf) < 16: + return + self.putx([10, ['CID: %s' % self.read_buf]]) + # TODO: Decode all bits. + self.read_buf = [] + self.state = 'GET RESPONSE R1' + + def handle_cmd16(self): + # CMD16: SET_BLOCKLEN + self.blocklen = self.arg + # TODO: Sanity check on block length. + self.putc(16, 'Set the block length to %d bytes' % self.blocklen) + self.state = 'GET RESPONSE R1' + + def handle_cmd17(self): + # CMD17: READ_SINGLE_BLOCK + self.putc(17, 'Read a block from address 0x%04x' % self.arg) + if len(self.read_buf) == 0: + self.ss_cmd = self.ss + self.read_buf.append(self.miso) + if len(self.read_buf) < self.blocklen + 2: # FIXME + return + self.es_cmd = self.es + self.read_buf = self.read_buf[2:] # FIXME + self.putx([17, ['Block data: %s' % self.read_buf]]) + self.read_buf = [] + self.state = 'GET RESPONSE R1' + + def handle_cmd24(self): + # CMD24: WRITE_BLOCK + self.putc(24, 'Write a block to address 0x%04x' % self.arg) + self.is_cmd24 = True + self.state = 'GET RESPONSE R1' + + def handle_cmd49(self): + self.state = 'GET RESPONSE R1' + + def handle_cmd55(self): + # CMD55: APP_CMD + self.putc(55, 'Next command is an application-specific command') + self.is_acmd = True + self.state = 'GET RESPONSE R1' + + def handle_cmd59(self): + # CMD59: CRC_ON_OFF + crc_on_off = self.arg & (1 << 0) + s = 'on' if crc_on_off == 1 else 'off' + self.putc(59, 'Turn the SD card CRC option %s' % s) + self.state = 'GET RESPONSE R1' + + def handle_acmd41(self): + # ACMD41: SD_SEND_OP_COND + self.putc(64 + 41, 'Send HCS info and activate the card init process') + self.state = 'GET RESPONSE R1' + + def handle_cmd999(self): + self.state = 'GET RESPONSE R1' + + def handle_cid_register(self): + # Card Identification (CID) register, 128bits + + cid = self.cid + + # Manufacturer ID: CID[127:120] (8 bits) + mid = cid[15] + + # OEM/Application ID: CID[119:104] (16 bits) + oid = (cid[14] << 8) | cid[13] + + # Product name: CID[103:64] (40 bits) + pnm = 0 + for i in range(12, 8 - 1, -1): + pnm <<= 8 + pnm |= cid[i] + + # Product revision: CID[63:56] (8 bits) + prv = cid[7] + + # Product serial number: CID[55:24] (32 bits) + psn = 0 + for i in range(6, 3 - 1, -1): + psn <<= 8 + psn |= cid[i] + + # RESERVED: CID[23:20] (4 bits) + + # Manufacturing date: CID[19:8] (12 bits) + # TODO + + # CRC7 checksum: CID[7:1] (7 bits) + # TODO + + # Not used, always 1: CID[0:0] (1 bit) + # TODO + + def handle_response_r1(self, res): + # The R1 response token format (1 byte). + # Sent by the card after every command except for SEND_STATUS. + + self.ss_cmd, self.es_cmd = self.miso_bits[7][1], self.miso_bits[0][2] + self.putx([65, ['R1: 0x%02x' % res]]) + + def putbit(bit, data): + b = self.miso_bits[bit] + self.ss_bit, self.es_bit = b[1], b[2] + self.putb([134, data]) + + # Bit 0: 'In idle state' bit + s = '' if (res & (1 << 0)) else 'not ' + putbit(0, ['Card is %sin idle state' % s]) + + # Bit 1: 'Erase reset' bit + s = '' if (res & (1 << 1)) else 'not ' + putbit(1, ['Erase sequence %scleared' % s]) + + # Bit 2: 'Illegal command' bit + s = 'I' if (res & (1 << 2)) else 'No i' + putbit(2, ['%sllegal command detected' % s]) + + # Bit 3: 'Communication CRC error' bit + s = 'failed' if (res & (1 << 3)) else 'was successful' + putbit(3, ['CRC check of last command %s' % s]) + + # Bit 4: 'Erase sequence error' bit + s = 'E' if (res & (1 << 4)) else 'No e' + putbit(4, ['%srror in the sequence of erase commands' % s]) + + # Bit 5: 'Address error' bit + s = 'M' if (res & (1 << 4)) else 'No m' + putbit(5, ['%sisaligned address used in command' % s]) + + # Bit 6: 'Parameter error' bit + s = '' if (res & (1 << 4)) else 'not ' + putbit(6, ['Command argument %soutside allowed range' % s]) + + # Bit 7: Always set to 0 + putbit(7, ['Bit 7 (always 0)']) + + if self.is_cmd24: + self.state = 'HANDLE DATA BLOCK CMD24' + + def handle_response_r1b(self, res): + # TODO + pass + + def handle_response_r2(self, res): + # TODO + pass + + def handle_response_r3(self, res): + # TODO + pass + + # Note: Response token formats R4 and R5 are reserved for SDIO. + + # TODO: R6? + + def handle_response_r7(self, res): + # TODO + pass + + def handle_data_cmd24(self, mosi): + if self.cmd24_start_token_found: + if len(self.read_buf) == 0: + self.ss_data = self.ss + if not self.blocklen: + # Assume a fixed block size when inspection of the + # previous traffic did not provide the respective + # parameter value. + # TODO Make the default block size a user adjustable option? + self.blocklen = 512 + self.read_buf.append(mosi) + # Wait until block transfer completed. + if len(self.read_buf) < self.blocklen: + return + self.es_data = self.es + self.put(self.ss_data, self.es_data, self.out_ann, [24, ['Block data: %s' % self.read_buf]]) + self.read_buf = [] + self.state = 'DATA RESPONSE' + elif mosi == 0xfe: + self.put(self.ss, self.es, self.out_ann, [24, ['Start Block']]) + self.cmd24_start_token_found = True + + def handle_data_response(self, miso): + # Data Response token (1 byte). + # + # Format: + # - Bits[7:5]: Don't care. + # - Bits[4:4]: Always 0. + # - Bits[3:1]: Status. + # - 010: Data accepted. + # - 101: Data rejected due to a CRC error. + # - 110: Data rejected due to a write error. + # - Bits[0:0]: Always 1. + miso &= 0x1f + if miso & 0x11 != 0x01: + # This is not the byte we are waiting for. + # Should we return to IDLE here? + return + m = self.miso_bits + self.put(m[7][1], m[5][2], self.out_ann, [134, ['Don\'t care']]) + self.put(m[4][1], m[4][2], self.out_ann, [134, ['Always 0']]) + if miso == 0x05: + self.put(m[3][1], m[1][2], self.out_ann, [134, ['Data accepted']]) + elif miso == 0x0b: + self.put(m[3][1], m[1][2], self.out_ann, [134, ['Data rejected (CRC error)']]) + elif miso == 0x0d: + self.put(m[3][1], m[1][2], self.out_ann, [134, ['Data rejected (write error)']]) + self.put(m[0][1], m[0][2], self.out_ann, [134, ['Always 1']]) + ann_class = None + if self.is_cmd24: + ann_class = 24 + if ann_class is not None: + self.put(self.ss, self.es, self.out_ann, [ann_class, ['Data Response']]) + self.state = 'IDLE' + + def decode(self, ss, es, data): + ptype, mosi, miso = data + + # For now, only use DATA and BITS packets. + if ptype not in ('DATA', 'BITS'): + return + + # Store the individual bit values and ss/es numbers. The next packet + # is guaranteed to be a 'DATA' packet belonging to this 'BITS' one. + if ptype == 'BITS': + self.miso_bits, self.mosi_bits = miso, mosi + return + + self.ss, self.es = ss, es + + # State machine. + if self.state == 'IDLE': + # Ignore stray 0xff bytes, some devices seem to send those!? + if mosi == 0xff: # TODO? + return + self.state = 'GET COMMAND TOKEN' + self.handle_command_token(mosi, miso) + elif self.state == 'GET COMMAND TOKEN': + self.handle_command_token(mosi, miso) + elif self.state.startswith('HANDLE CMD'): + self.miso, self.mosi = miso, mosi + # Call the respective handler method for the command. + a, cmdstr = 'a' if self.is_acmd else '', self.state[10:].lower() + handle_cmd = getattr(self, 'handle_%scmd%s' % (a, cmdstr)) + handle_cmd() + self.cmd_token = [] + self.cmd_token_bits = [] + # Leave ACMD mode again after the first command after CMD55. + if self.is_acmd and cmdstr != '55': + self.is_acmd = False + elif self.state.startswith('GET RESPONSE'): + # Ignore stray 0xff bytes, some devices seem to send those!? + if miso == 0xff: # TODO? + return + # Call the respective handler method for the response. + # Assume return to IDLE state, but allow response handlers + # to advance to some other state when applicable. + s = 'handle_response_%s' % self.state[13:].lower() + handle_response = getattr(self, s) + self.state = 'IDLE' + handle_response(miso) + elif self.state == 'HANDLE DATA BLOCK CMD24': + self.handle_data_cmd24(mosi) + elif self.state == 'DATA RESPONSE': + self.handle_data_response(miso) diff --git a/libsigrokdecode4DSL/decoders/sdq/__init__.py b/libsigrokdecode4DSL/decoders/sdq/__init__.py new file mode 100644 index 00000000..3fc10438 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/sdq/__init__.py @@ -0,0 +1,28 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019-2020 Philip Åkesson +## +## 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, see . +## + +''' +The SDQ protocol was developed by Texas Instruments, and is used in +devices like battery pack authentication. Apple uses SDQ in MagSafe +and Lightning connectors, as well as some batteries. + +See https://www.ti.com/lit/ds/symlink/bq26100.pdf for details. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/sdq/pd.py b/libsigrokdecode4DSL/decoders/sdq/pd.py new file mode 100644 index 00000000..66df4202 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/sdq/pd.py @@ -0,0 +1,131 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019-2020 Philip Åkesson +## +## 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, see . +## + +from common.srdhelper import bitpack +import sigrokdecode as srd + +class SamplerateError(Exception): + pass + +class Pin: + SDQ, = range(1) + +class Ann: + BIT, BYTE, BREAK, = range(3) + +class Decoder(srd.Decoder): + api_version = 3 + id = 'sdq' + name = 'SDQ' + longname = 'Texas Instruments SDQ' + desc = 'Texas Instruments SDQ. The SDQ protocol is also used by Apple.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Embedded/industrial'] + channels = ( + {'id': 'sdq', 'name': 'SDQ', 'desc': 'Single wire SDQ data line.'}, + ) + options = ( + {'id': 'bitrate', 'desc': 'Bit rate', 'default': 98425}, + ) + annotations = ( + ('bit', 'Bit'), + ('byte', 'Byte'), + ('break', 'Break'), + ) + annotation_rows = ( + ('bits', 'Bits', (Ann.BIT,)), + ('bytes', 'Bytes', (Ann.BYTE,)), + ('breaks', 'Breaks', (Ann.BREAK,)), + ) + + def puts(self, data): + self.put(self.startsample, self.samplenum, self.out_ann, data) + + def putetu(self, data): + self.put(self.startsample, self.startsample + int(self.bit_width), self.out_ann, data) + + def putbetu(self, data): + self.put(self.bytepos, self.startsample + int(self.bit_width), self.out_ann, data) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.startsample = 0 + self.bits = [] + self.bytepos = 0 + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def handle_bit(self, bit): + self.bits.append(bit) + self.putetu([Ann.BIT, [ + 'Bit: {:d}'.format(bit), + '{:d}'.format(bit), + ]]) + + if len(self.bits) == 8: + byte = bitpack(self.bits) + self.putbetu([Ann.BYTE, [ + 'Byte: 0x{:02x}'.format(byte), + '0x{:02x}'.format(byte), + ]]) + self.bits = [] + self.bytepos = 0 + + def handle_break(self): + self.puts([Ann.BREAK, ['Break', 'BR']]) + self.bits = [] + self.startsample = self.samplenum + self.bytepos = 0 + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + self.bit_width = float(self.samplerate) / float(self.options['bitrate']) + self.half_bit_width = self.bit_width / 2.0 + # BREAK if the line is low for longer than this. + break_threshold = self.bit_width * 1.2 + + # Wait until the line is high before inspecting input data. + sdq, = self.wait({Pin.SDQ: 'h'}) + while True: + # Get the length of a low pulse (falling to rising edge). + sdq, = self.wait({Pin.SDQ: 'f'}) + self.startsample = self.samplenum + if self.bytepos == 0: + self.bytepos = self.samplenum + sdq, = self.wait({Pin.SDQ: 'r'}) + + # Check for 0 or 1 data bits, or the BREAK symbol. + delta = self.samplenum - self.startsample + if delta > break_threshold: + self.handle_break() + elif delta > self.half_bit_width: + self.handle_bit(0) + else: + self.handle_bit(1) diff --git a/libsigrokdecode4DSL/decoders/seven_segment/__init__.py b/libsigrokdecode4DSL/decoders/seven_segment/__init__.py new file mode 100644 index 00000000..ea03e4f2 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/seven_segment/__init__.py @@ -0,0 +1,24 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Benedikt Otto +## +## 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, see . +## + +''' +This decoder decodes the output of a 7-segment display. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/seven_segment/pd.py b/libsigrokdecode4DSL/decoders/seven_segment/pd.py new file mode 100644 index 00000000..edabf04a --- /dev/null +++ b/libsigrokdecode4DSL/decoders/seven_segment/pd.py @@ -0,0 +1,136 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Benedikt Otto +## +## 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, see . +## + +import sigrokdecode as srd + +class ChannelError(Exception): + pass + +digits = { + (0, 0, 0, 0, 0, 0, 0): ' ', + (1, 1, 1, 1, 1, 1, 0): '0', + (0, 1, 1, 0, 0, 0, 0): '1', + (1, 1, 0, 1, 1, 0, 1): '2', + (1, 1, 1, 1, 0, 0, 1): '3', + (0, 1, 1, 0, 0, 1, 1): '4', + (1, 0, 1, 1, 0, 1, 1): '5', + (1, 0, 1, 1, 1, 1, 1): '6', + (1, 1, 1, 0, 0, 0, 0): '7', + (1, 1, 1, 1, 1, 1, 1): '8', + (1, 1, 1, 1, 0, 1, 1): '9', + (1, 1, 1, 0, 1, 1, 1): 'A', + (0, 0, 1, 1, 1, 1, 1): 'B', + (1, 0, 0, 1, 1, 1, 0): 'C', + (0, 1, 1, 1, 1, 0, 1): 'D', + (1, 0, 0, 1, 1, 1, 1): 'E', + (1, 0, 0, 0, 1, 1, 1): 'F', +} + +class Decoder(srd.Decoder): + api_version = 3 + id = 'seven_segment' + name = 'Segment-7' + longname = '7-segment display' + desc = '7-segment display protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Display'] + channels = ( + {'id': 'a', 'name': 'A', 'desc': 'Segment A'}, + {'id': 'b', 'name': 'B', 'desc': 'Segment B'}, + {'id': 'c', 'name': 'C', 'desc': 'Segment C'}, + {'id': 'd', 'name': 'D', 'desc': 'Segment D'}, + {'id': 'e', 'name': 'E', 'desc': 'Segment E'}, + {'id': 'f', 'name': 'F', 'desc': 'Segment F'}, + {'id': 'g', 'name': 'G', 'desc': 'Segment G'}, + ) + optional_channels = ( + {'id': 'dp', 'name': 'DP', 'desc': 'Decimal point'}, + ) + options = ( + {'id': 'polarity', 'desc': 'Expected polarity', + 'default': 'common-cathode', 'values': ('common-cathode', 'common-anode')}, + ) + annotations = ( + ('decoded-digit', 'Decoded digit'), + ) + annotation_rows = ( + ('decoded-digits', 'Decoded digits', (0,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + pass + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putb(self, ss_block, es_block, data): + self.put(ss_block, es_block, self.out_ann, data) + + def pins_to_hex(self, pins): + return digits.get(pins, None) + + def decode(self): + (s0, s1, s2, s3, s4, s5, s6, dp) = self.wait() + oldpins = (s0, s1, s2, s3, s4, s5, s6, dp) + + # Check if at least the 7 signals are present. + if False in [p in (0, 1) for p in oldpins[:7]]: + raise ChannelError('7 or 8 pins have to be present.') + + lastpos = self.samplenum + + self.have_dp = self.has_channel(7) + + conditions = [{0: 'e'}, {1: 'e'}, {2: 'e'}, {3: 'e'}, {4: 'e'}, {5: 'e'}, {6: 'e'}] + + if self.have_dp: + conditions.append({7: 'e'}) + + while True: + # Wait for any change. + (s0, s1, s2, s3, s4, s5, s6, dp) = self.wait(conditions) + pins = (s0, s1, s2, s3, s4, s5, s6, dp) + + if self.options['polarity'] == 'common-anode': + # Invert all data lines if a common anode display is used. + if self.have_dp: + oldpins = tuple((1 - state for state in oldpins)) + else: + oldpins = tuple((1 - state for state in oldpins[:7])) + + # Convert to character string. + digit = self.pins_to_hex(oldpins[:7]) + + if digit is not None: + dp = oldpins[7] + + # Check if decimal point is present and active. + if self.have_dp and dp == 1: + digit += '.' + + self.putb(lastpos, self.samplenum, [0, [digit]]) + + lastpos = self.samplenum + + oldpins = pins diff --git a/libsigrokdecode4DSL/decoders/signature/__init__.py b/libsigrokdecode4DSL/decoders/signature/__init__.py new file mode 100644 index 00000000..d37fd4a3 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/signature/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Shirow Miura +## +## 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, see . +## + +''' +Signature analysis function for troubleshooting logic circuits. +This generates the same signature as Hewlett-Packard 5004A. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/signature/pd.py b/libsigrokdecode4DSL/decoders/signature/pd.py new file mode 100644 index 00000000..946b2da7 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/signature/pd.py @@ -0,0 +1,142 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Shirow Miura +## +## 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, see . +## + +import sigrokdecode as srd + +symbol_map = { + 0b0000: '0', + 0b1000: '1', + 0b0100: '2', + 0b1100: '3', + 0b0010: '4', + 0b1010: '5', + 0b0110: '6', + 0b1110: '7', + 0b0001: '8', + 0b1001: '9', + 0b0101: 'A', + 0b1101: 'C', + 0b0011: 'F', + 0b1011: 'H', + 0b0111: 'P', + 0b1111: 'U', +} + +START, STOP, CLOCK, DATA = range(4) + +class Decoder(srd.Decoder): + api_version = 3 + id = 'signature' + name = 'Signature' + longname = 'Signature analysis' + desc = 'Annotate signature of logic patterns.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Debug/trace', 'Util', 'Encoding'] + channels = ( + {'id': 'start', 'name': 'START', 'desc': 'START channel'}, + {'id': 'stop', 'name': 'STOP', 'desc': 'STOP channel'}, + {'id': 'clk', 'name': 'CLOCK', 'desc': 'CLOCK channel'}, + {'id': 'data', 'name': 'DATA', 'desc': 'DATA channel'}, + ) + options = ( + {'id': 'start_edge', 'desc': 'START edge polarity', + 'default': 'rising', 'values': ('rising', 'falling')}, + {'id': 'stop_edge', 'desc': 'STOP edge polarity', + 'default': 'rising', 'values': ('rising', 'falling')}, + {'id': 'clk_edge', 'desc': 'CLOCK edge polarity', + 'default': 'falling', 'values': ('rising', 'falling')}, + {'id': 'annbits', 'desc': 'Enable bit level annotations', + 'default': 'no', 'values': ('yes', 'no')}, + ) + annotations = ( + ('bit0', 'Bit0'), + ('bit1', 'Bit1'), + ('start', 'START'), + ('stop', 'STOP'), + ('signature', 'Signature') + ) + annotation_rows = ( + ('bits', 'Bits', (0, 1, 2, 3)), + ('signatures', 'Signatures', (4,)) + ) + + def __init__(self): + self.reset() + + def reset(self): + pass + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putsig(self, ss, es, signature): + s = ''.join([symbol_map[(signature >> 0) & 0x0f], + symbol_map[(signature >> 4) & 0x0f], + symbol_map[(signature >> 8) & 0x0f], + symbol_map[(signature >> 12) & 0x0f]]) + self.put(ss, es, self.out_ann, [4, [s]]) + + def putb(self, ss, ann): + self.put(ss, self.samplenum, self.out_ann, ann) + + def decode(self): + opt = self.options + start_edge_mode_rising = opt['start_edge'] == 'rising' + stop_edge_mode_rising = opt['stop_edge'] == 'rising' + annbits = opt['annbits'] == 'yes' + gate_is_open = False + sample_start = None + started = False + last_samplenum = 0 + prev_start = 0 if start_edge_mode_rising else 1 + prev_stop = 0 if stop_edge_mode_rising else 1 + shiftreg = 0 + + while True: + start, stop, _, data = self.wait({CLOCK: opt['clk_edge']}) + if start != prev_start and not gate_is_open: + gate_is_open = (start == 1) if start_edge_mode_rising else (start == 0) + if gate_is_open: + # Start sampling. + sample_start = self.samplenum + started = True + elif stop != prev_stop and gate_is_open: + gate_is_open = not ((stop == 1) if stop_edge_mode_rising else (stop == 0)) + if not gate_is_open: + # Stop sampling. + if annbits: + self.putb(last_samplenum, [3, ['STOP', 'STP', 'P']]) + self.putsig(sample_start, self.samplenum, shiftreg) + shiftreg = 0 + sample_start = None + if gate_is_open: + if annbits: + if started: + s = '<{}>'.format(data) + self.putb(last_samplenum, [2, ['START' + s, 'STR' + s, 'S' + s]]) + started = False + else: + self.putb(last_samplenum, [data, [str(data)]]) + incoming = (bin(shiftreg & 0x0291).count('1') + data) & 1 + shiftreg = (incoming << 15) | (shiftreg >> 1) + prev_start = start + prev_stop = stop + last_samplenum = self.samplenum diff --git a/libsigrokdecode4DSL/decoders/sipi/__init__.py b/libsigrokdecode4DSL/decoders/sipi/__init__.py new file mode 100644 index 00000000..d62e3c11 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/sipi/__init__.py @@ -0,0 +1,30 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 Soeren Apel +## +## 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, see . +## + +''' +The Serial Inter-Processor Interface (SIPI) is a higher-level protocol that runs +over the LFAST physical interface. Together, they form the NXP Zipwire interface. + +The SIPI interface is also provided by Infineon as HSST, using HSCT for transport. + +For details see https://www.nxp.com/docs/en/application-note/AN5134.pdf and +https://hitex.co.uk/fileadmin/uk-files/downloads/ShieldBuddy/tc27xD_um_v2.2.pdf +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/sipi/pd.py b/libsigrokdecode4DSL/decoders/sipi/pd.py new file mode 100644 index 00000000..5bd58fbb --- /dev/null +++ b/libsigrokdecode4DSL/decoders/sipi/pd.py @@ -0,0 +1,181 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2020 Soeren Apel +## +## 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, see . +## + +import sigrokdecode as srd +from binascii import crc_hqx + +# See tc27xD_um_v2.2.pdf, Table 20-2 +# (name, addr byte count, data byte count) +command_codes = { + 0b00000: ('Read byte', 4, 0), + 0b00001: ('Read 2 byte', 4, 0), + 0b00010: ('Read 4 byte', 4, 0), + # Reserved + 0b00100: ('Write byte with ACK', 4, 4), + 0b00101: ('Write 2 byte with ACK', 4, 4), + 0b00110: ('Write 4 byte with ACK', 4, 4), + # Reserved + 0b01000: ('ACK', 0, 0), + 0b01001: ('NACK (Target Error)', 0, 0), + 0b01010: ('Read Answer with ACK', 4, 4), + # Reserved + 0b01100: ('Trigger with ACK', 0, 0), + # Reserved + # Reserved + # Reserved + # Reserved + # Reserved + 0b10010: ('Read 4-byte JTAG ID', 0, 0), + # Reserved + # Reserved + # Reserved + # Reserved + 0b10111: ('Stream 32 byte with ACK', 0, 32) + # Rest is reserved +} + + +ann_header_tag, ann_header_cmd, ann_header_ch, ann_address, ann_data, \ + ann_crc, ann_warning = range(7) + +class Decoder(srd.Decoder): + api_version = 3 + id = 'sipi' + name = 'SIPI (Zipwire)' + longname = 'NXP SIPI interface' + desc = 'Serial Inter-Processor Interface (SIPI) aka Zipwire, aka HSSL' + license = 'gplv2+' + inputs = ['lfast'] + outputs = [] + tags = ['Embedded/industrial'] + annotations = ( + ('header_tag', 'Transaction Tag'), + ('header_cmd', 'Command Code'), + ('header_ch', 'Channel'), + ('address', 'Address'), + ('data', 'Data'), + ('crc', 'CRC'), + ('warning', 'Warning'), + ) + annotation_rows = ( + ('fields', 'Fields', (ann_header_tag, ann_header_cmd, + ann_header_ch, ann_address, ann_data, ann_crc,)), + ('warnings', 'Warnings', (ann_warning,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.byte_len = 0 + self.frame_len = 0 + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_binary = self.register(srd.OUTPUT_BINARY) + + def put_ann(self, ss, es, ann_class, value): + self.put(int(ss), int(es), self.out_ann, [ann_class, value]) + + def put_header(self, ss_header, es_header, value): + ss = ss_header + es = ss + 3 * self.bit_len + tag = (value & 0xE000) >> 13 + self.put_ann(ss, es, ann_header_tag, ['{:02X}'.format(tag)]) + + ss = es + es = ss + 5 * self.bit_len + cmd_id = (value & 0x1F00) >> 8 + cmd_name, self.addr_len, self.data_len = \ + command_codes.get(cmd_id, ('Reserved ({:02X})'.format(cmd_id), 0, 0)) + self.frame_len = 2 + 2 + self.addr_len + self.data_len # +Header +CRC + self.put_ann(ss, es, ann_header_cmd, [cmd_name]) + + # Bits 4..7 are reserved and should be 0, warn if they're not + ss = es + es = ss + 4 * self.bit_len + reserved_bits = (value & 0x00F0) >> 4 + if reserved_bits > 0: + self.put_ann(ss, es, ann_warning, ['Reserved bits #4..7 should be 0']) + + ss = es + es = ss + 3 * self.bit_len + ch = (value & 0x000E) >> 1 # See tc27xD_um_v2.2.pdf, Table 20-1 + self.put_ann(ss, es, ann_header_ch, [str(ch)]) + + # Bit 0 is reserved and should be 0, warn if it's not + if (value & 0x0001) == 0x0001: + ss = es + es = ss + self.bit_len + self.put_ann(ss, es, ann_warning, ['Reserved bit #0 should be 0']) + + def put_payload(self, data): + byte_idx = 0 + if self.addr_len > 0: + for value_tuple in data[:self.addr_len]: + ss, es, value = value_tuple + self.put_ann(ss, es, ann_address, ['{:02X}'.format(value)]) + byte_idx = self.addr_len + + if self.data_len > 0: + for value_tuple in data[byte_idx:]: + ss, es, value = value_tuple + self.put_ann(ss, es, ann_data, ['{:02X}'.format(value)]) + + def put_crc(self, ss, es, crc_value, crc_payload_data): + crc_payload = [] + for value_tuple in crc_payload_data: + crc_payload.append(value_tuple[2]) + + calculated_crc = crc_hqx(bytes(crc_payload), 0xFFFF) + + if calculated_crc == crc_value: + self.put_ann(ss, es, ann_crc, ['CRC OK']) + else: + self.put_ann(ss, es, ann_crc, ['Have {:02X} but calculated {:02X}'.format(crc_value, calculated_crc)]) + self.put_ann(ss, es, ann_warning, ['CRC mismatch']) + + def decode(self, ss, es, data): + if len(data) == 1: + self.put_ann(ss, es, ann_warning, ['Header too short']) + return + + # ss and es are now unused, we use them as local variables instead + + self.bit_len = (data[0][1] - data[0][0]) / 8.0 + + byte_idx = 0 + + ss = data[byte_idx][0] + es = data[byte_idx + 1][1] + self.put_header(ss, es, (data[byte_idx][2] << 8) + data[byte_idx + 1][2]) + byte_idx += 2 + + payload_len = self.frame_len - 2 - 2 # -Header -CRC + if payload_len > 0: + self.put_payload(data[byte_idx:-2]) + byte_idx += payload_len + + ss = data[byte_idx][0] + es = data[byte_idx + 1][1] + if byte_idx == len(data) - 2: + # CRC is calculated over header + payload bytes + self.put_crc(ss, es, (data[byte_idx][2] << 8) + data[byte_idx + 1][2], data[0:-2]) + else: + self.put_ann(ss, es, ann_warning, ['CRC incomplete or missing']) diff --git a/libsigrokdecode4DSL/decoders/sle44xx/__init__.py b/libsigrokdecode4DSL/decoders/sle44xx/__init__.py new file mode 100644 index 00000000..0eb02856 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/sle44xx/__init__.py @@ -0,0 +1,26 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Federico Cerutti +## +## 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, see . +## + +''' +SLE 4418/28/32/42 memory cards implement a 2-wire protocol (CLK and I/O) +for data communication, along with the RST signal which resets the card's +internal state, and can terminate currently executing long memory reads. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/sle44xx/pd.py b/libsigrokdecode4DSL/decoders/sle44xx/pd.py new file mode 100644 index 00000000..9f332077 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/sle44xx/pd.py @@ -0,0 +1,541 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Federico Cerutti +## +## 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, see . +## + +from common.srdhelper import bitpack_lsb +import sigrokdecode as srd + +class Pin: + RST, CLK, IO, = range(3) + +class Ann: + RESET_SYM, INTR_SYM, START_SYM, STOP_SYM, BIT_SYM, \ + ATR_BYTE, CMD_BYTE, OUT_BYTE, PROC_BYTE, \ + ATR_DATA, CMD_DATA, OUT_DATA, PROC_DATA, \ + = range(13) + +class Bin: + BYTES, = range(1) + +class Decoder(srd.Decoder): + api_version = 3 + id = 'sle44xx' + name = 'SLE 44xx' + longname = 'SLE44xx memory card' + desc = 'SLE 4418/28/32/42 memory card serial protocol' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Memory'] + channels = ( + {'id': 'rst', 'name': 'RST', 'desc': 'Reset line'}, + {'id': 'clk', 'name': 'CLK', 'desc': 'Clock line'}, + {'id': 'io', 'name': 'I/O', 'desc': 'I/O data line'}, + ) + annotations = ( + ('reset_sym', 'Reset Symbol'), + ('intr_sym', 'Interrupt Symbol'), + ('start_sym', 'Start Symbol'), + ('stop_sym', 'Stop Symbol'), + ('bit_sym', 'Bit Symbol'), + ('atr_byte', 'ATR Byte'), + ('cmd_byte', 'Command Byte'), + ('out_byte', 'Outgoing Byte'), + ('proc_byte', 'Processing Byte'), + ('atr_data', 'ATR data'), + ('cmd_data', 'Command data'), + ('out_data', 'Outgoing data'), + ('proc_data', 'Processing data'), + ) + annotation_rows = ( + ('symbols', 'Symbols', (Ann.RESET_SYM, Ann.INTR_SYM, + Ann.START_SYM, Ann.STOP_SYM, Ann.BIT_SYM,)), + ('fields', 'Fields', (Ann.ATR_BYTE, + Ann.CMD_BYTE, Ann.OUT_BYTE, Ann.PROC_BYTE,)), + ('operations', 'Operations', (Ann.ATR_DATA, + Ann.CMD_DATA, Ann.OUT_DATA, Ann.PROC_DATA,)), + ) + binary = ( + ('bytes', 'Bytes'), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.max_addr = 256 + self.bits = [] + self.atr_bytes = [] + self.cmd_bytes = [] + self.cmd_proc = None + self.out_len = None + self.out_bytes = [] + self.proc_state = None + self.state = None + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_binary = self.register(srd.OUTPUT_BINARY) + + def putx(self, ss, es, cls, data): + self.put(ss, es, self.out_ann, [cls, data,]) + + def putb(self, ss, es, cls , data): + self.put(ss, es, self.out_binary, [cls, data,]) + + def snums_to_usecs(self, snum_count): + if not self.samplerate: + return None + snums_per_usec = self.samplerate / 1e6 + usecs = snum_count / snums_per_usec + return usecs + + def lookup_proto_ann_txt(self, key, variables): + ann = { + 'RESET_SYM': [Ann.RESET_SYM, 'Reset', 'R',], + 'INTR_SYM': [Ann.INTR_SYM, 'Interrupt', 'Intr', 'I',], + 'START_SYM': [Ann.START_SYM, 'Start', 'ST', 'S',], + 'STOP_SYM': [Ann.STOP_SYM, 'Stop', 'SP', 'P',], + 'BIT_SYM': [Ann.BIT_SYM, '{bit}',], + 'ATR_BYTE': [Ann.ATR_BYTE, + 'Answer To Reset: {data:02x}', + 'ATR: {data:02x}', + '{data:02x}', + ], + 'CMD_BYTE': [Ann.CMD_BYTE, + 'Command: {data:02x}', + 'Cmd: {data:02x}', + '{data:02x}', + ], + 'OUT_BYTE': [Ann.OUT_BYTE, + 'Outgoing data: {data:02x}', + 'Data: {data:02x}', + '{data:02x}', + ], + 'PROC_BYTE': [Ann.PROC_BYTE, + 'Internal processing: {data:02x}', + 'Proc: {data:02x}', + '{data:02x}', + ], + 'ATR_DATA': [Ann.ATR_DATA, + 'Answer To Reset: {data}', + 'ATR: {data}', + '{data}', + ], + 'CMD_DATA': [Ann.CMD_DATA, + 'Command: {data}', + 'Cmd: {data}', + '{data}', + ], + 'OUT_DATA': [Ann.OUT_DATA, + 'Outgoing: {data}', + 'Out: {data}', + '{data}', + ], + 'PROC_DATA': [Ann.PROC_DATA, + 'Processing: {data}', + 'Proc: {data}', + '{data}', + ], + }.get(key, None) + if ann is None: + return None, [] + cls, texts = ann[0], ann[1:] + texts = [t.format(**variables) for t in texts] + return cls, texts + + def text_for_accu_bytes(self, accu): + if not accu: + return None, None, None, None + ss, es = accu[0][1], accu[-1][2] + data = [a[0] for a in accu] + text = " ".join(['{:02x}'.format(a) for a in data]) + return ss, es, data, text + + def flush_queued(self): + '''Flush previously accumulated operations details.''' + + # Can be called when either the completion of an operation got + # detected (reliably), or when some kind of reset condition was + # met while a potential previously observed operation has not + # been postprocessed yet (best effort). Should not harm when the + # routine gets invoked while no data was collected yet, or was + # flushed already. + # BEWARE! Will void internal state. Should really only get called + # "between operations", NOT between fields of an operation. + + if self.atr_bytes: + key = 'ATR_DATA' + ss, es, _, text = self.text_for_accu_bytes(self.atr_bytes) + cls, texts = self.lookup_proto_ann_txt(key, {'data': text}) + self.putx(ss, es, cls, texts) + + if self.cmd_bytes: + key = 'CMD_DATA' + ss, es, _, text = self.text_for_accu_bytes(self.cmd_bytes) + cls, texts = self.lookup_proto_ann_txt(key, {'data': text}) + self.putx(ss, es, cls, texts) + + if self.out_bytes: + key = 'OUT_DATA' + ss, es, _, text = self.text_for_accu_bytes(self.out_bytes) + cls, texts = self.lookup_proto_ann_txt(key, {'data': text}) + self.putx(ss, es, cls, texts) + + if self.proc_state: + key = 'PROC_DATA' + ss = self.proc_state['ss'] + es = self.proc_state['es'] + clk = self.proc_state['clk'] + high = self.proc_state['io1'] + text = '{clk} clocks, I/O {high}'.format(clk = clk, high = int(high)) + usecs = self.snums_to_usecs(es - ss) + if usecs: + msecs = usecs / 1000 + text = '{msecs:.2f} ms, {text}'.format(msecs = msecs, text = text) + cls, texts = self.lookup_proto_ann_txt(key, {'data': text}) + self.putx(ss, es, cls, texts) + + self.atr_bytes = None + self.cmd_bytes = None + self.cmd_proc = None + self.out_len = None + self.out_bytes = None + self.proc_state = None + self.state = None + + def handle_reset(self, ss, es, has_clk): + self.flush_queued() + key = '{}_SYM'.format('RESET' if has_clk else 'INTR') + cls, texts = self.lookup_proto_ann_txt(key, {}) + self.putx(ss, es, cls, texts) + self.bits = [] + self.state = 'ATR' if has_clk else None + + def handle_command(self, ss, is_start): + if is_start: + self.flush_queued() + key = '{}_SYM'.format('START' if is_start else 'STOP') + cls, texts = self.lookup_proto_ann_txt(key, {}) + self.putx(ss, ss, cls, texts) + self.bits = [] + self.state = 'CMD' if is_start else 'DATA' + + def command_check(self, ctrl, addr, data): + '''Interpret CTRL/ADDR/DATA command entry.''' + + # See the Siemens Datasheet section 2.3 Commands. The abbreviated + # text variants are my guesses, terse for readability at coarser + # zoom levels. + codes_table = { + 0x30: { + 'fmt': [ + 'read main memory, addr {addr:02x}', + 'RD-M @{addr:02x}', + ], + 'len': lambda ctrl, addr, data: self.max_addr - addr, + }, + 0x31: { + 'fmt': [ + 'read security memory', + 'RD-S', + ], + 'len': 4, + }, + 0x33: { + 'fmt': [ + 'compare verification data, addr {addr:02x}, data {data:02x}', + 'CMP-V @{addr:02x} ={data:02x}', + ], + 'proc': True, + }, + 0x34: { + 'fmt': [ + 'read protection memory, addr {addr:02x}', + 'RD-P @{addr:02x}', + ], + 'len': 4, + }, + 0x38: { + 'fmt': [ + 'update main memory, addr {addr:02x}, data {data:02x}', + 'WR-M @{addr:02x} ={data:02x}', + ], + 'proc': True, + }, + 0x39: { + 'fmt': [ + 'update security memory, addr {addr:02x}, data {data:02x}', + 'WR-S @{addr:02x} ={data:02x}', + ], + 'proc': True, + }, + 0x3c: { + 'fmt': [ + 'write protection memory, addr {addr:02x}, data {data:02x}', + 'WR-P @{addr:02x} ={data:02x}', + ], + 'proc': True, + }, + } + code = codes_table.get(ctrl, {}) + dflt_fmt = [ + 'unknown, ctrl {ctrl:02x}, addr {addr:02x}, data {data:02x}', + 'UNK-{ctrl:02x} @{addr:02x}, ={data:02x}', + ] + fmt = code.get('fmt', dflt_fmt) + if not isinstance(fmt, (list, tuple,)): + fmt = [fmt,] + texts = [f.format(ctrl = ctrl, addr = addr, data = data) for f in fmt] + length = code.get('len', None) + if callable(length): + length = length(ctrl, addr, data) + is_proc = code.get('proc', False) + return texts, length, is_proc + + def processing_start(self, ss, es, io_high): + self.proc_state = { + 'ss': ss or es, + 'es': es or ss, + 'clk': 0, + 'io1': bool(io_high), + } + + def processing_update(self, es, clk_inc, io_high): + if es is not None and es > self.proc_state['es']: + self.proc_state['es'] = es + self.proc_state['clk'] += clk_inc + if io_high: + self.proc_state['io1'] = True + + def handle_data_byte(self, ss, es, data, bits): + '''Accumulate CMD or OUT data bytes.''' + + if self.state == 'ATR': + if not self.atr_bytes: + self.atr_bytes = [] + self.atr_bytes.append([data, ss, es, bits,]) + if len(self.atr_bytes) == 4: + self.flush_queued() + return + + if self.state == 'CMD': + if not self.cmd_bytes: + self.cmd_bytes = [] + self.cmd_bytes.append([data, ss, es, bits,]) + if len(self.cmd_bytes) == 3: + ctrl, addr, data = [c[0] for c in self.cmd_bytes] + texts, length, proc = self.command_check(ctrl, addr, data) + # Immediately emit the annotation to not lose the text, + # and to support zoom levels for this specific case. + ss, es = self.cmd_bytes[0][1], self.cmd_bytes[-1][2] + cls = Ann.CMD_DATA + self.putx(ss, es, cls, texts) + self.cmd_bytes = [] + # Prepare to continue either at OUT or PROC after CMD. + self.out_len = length + self.cmd_proc = bool(proc) + self.state = None + return + + if self.state == 'OUT': + if not self.out_bytes: + self.out_bytes = [] + self.out_bytes.append([data, ss, es, bits,]) + if self.out_len is not None and len(self.out_bytes) == self.out_len: + self.flush_queued() + return + + def handle_data_bit(self, ss, es, bit): + '''Gather 8 bits of data (or track processing progress).''' + + # Switch late from DATA to either OUT or PROC. We can tell the + # type and potentially fixed length at the end of CMD already, + # but a START/STOP condition may void this information. So we + # do the switch at the first data bit after CMD. + # In the OUT case data bytes get accumulated, until either the + # expected byte count is reached, or another CMD starts. In the + # PROC case a high I/O level terminates execution. + if self.state == 'DATA': + if self.out_len: + self.state = 'OUT' + elif self.cmd_proc: + self.state = 'PROC' + self.processing_start(ss or es, es or ss, bit == 1) + else: + # Implementor's note: Handle unknown situations like + # outgoing data bytes, for the user's convenience. This + # will show OUT bytes even if it's just processing CLK + # cycles with constant or irrelevant I/O bit patterns. + self.state = 'OUT' + if self.state == 'PROC': + high = bit == 1 + if ss is not None: + self.processing_update(ss, 0, high) + if es is not None: + self.processing_update(es, 1, high) + if high: + self.flush_queued() + return + + # This routine gets called two times per bit value. Track the + # bit's value and ss timestamp when the bit period starts. And + # update the es timestamp at the end of the bit's validity. + if ss is not None: + self.bits.append([bit, ss, es or ss]) + return + if es is None: + # Unexpected invocation. Could be a glitch or invalid input + # data, or an interaction with RESET/START/STOP conditions. + self.bits = [] + return + if not self.bits: + return + if bit is not None: + self.bits[-1][0] = bit + # TODO Check for consistent bit level at ss and es when + # the information was available? Is bit data sampled at + # different clock edges depending whether data is sent + # or received? + self.bits[-1][2] = es + # Emit the bit's annotation. See if a byte was received. + bit, ss, es = self.bits[-1] + cls, texts = self.lookup_proto_ann_txt('BIT_SYM', {'bit': bit}) + self.putx(ss, es, cls, texts) + if len(self.bits) < 8: + return + + # Get the data byte value, and the byte's ss/es. Emit the byte's + # annotation and binary output. Pass the byte to upper layers. + # TODO Vary annotation classes with the byte's position within + # a field? To tell CTRL/ADDR/DATA of a CMD entry apart? + bits = self.bits + self.bits = [] + data = bitpack_lsb(bits, 0) + ss = bits[0][1] + es = bits[-1][2] + + key = '{}_BYTE'.format(self.state) + cls, texts = self.lookup_proto_ann_txt(key, {'data': data}) + if cls: + self.putx(ss, es, cls, texts) + self.putb(ss, es, Bin.BYTES, bytes([data])) + + self.handle_data_byte(ss, es, data, bits) + + def decode(self): + '''Decoder's main data interpretation loop.''' + + # Signal conditions tracked by the protocol decoder: + # - Rising and falling RST edges, which span the width of a + # high-active RESET pulse. RST has highest priority, no + # other activity can take place in this period. + # - Rising and falling CLK edges when RST is active. The + # CLK pulse when RST is asserted will reset the card's + # address counter. RST alone can terminate memory reads. + # - Rising and falling CLK edges when RST is inactive. This + # determines the period where BIT values are valid. + # - I/O edges during high CLK. These are START and STOP + # conditions that tell COMMAND and DATA phases apart. + # - Rise of I/O during internal processing. This expression + # is an unconditional part of the .wait() condition set. It + # is assumed that skipping this match in many cases is more + # efficient than the permanent re-construction of the .wait() + # condition list in every loop iteration, and preferrable to + # the maintainance cost of duplicating RST and CLK handling + # when checking I/O during internal processing. + ( + COND_RESET_START, COND_RESET_STOP, + COND_RSTCLK_START, COND_RSTCLK_STOP, + COND_DATA_START, COND_DATA_STOP, + COND_CMD_START, COND_CMD_STOP, + COND_PROC_IOH, + ) = range(9) + conditions = [ + {Pin.RST: 'r'}, + {Pin.RST: 'f'}, + {Pin.RST: 'h', Pin.CLK: 'r'}, + {Pin.RST: 'h', Pin.CLK: 'f'}, + {Pin.RST: 'l', Pin.CLK: 'r'}, + {Pin.RST: 'l', Pin.CLK: 'f'}, + {Pin.CLK: 'h', Pin.IO: 'f'}, + {Pin.CLK: 'h', Pin.IO: 'r'}, + {Pin.RST: 'l', Pin.IO: 'r'}, + ] + + ss_reset = es_reset = ss_clk = es_clk = None + while True: + + is_outgoing = self.state == 'OUT' + is_processing = self.state == 'PROC' + pins = self.wait(conditions) + io = pins[Pin.IO] + + # Handle RESET conditions, including an optional CLK pulse + # while RST is asserted. + if self.matched[COND_RESET_START]: + self.flush_queued() + ss_reset = self.samplenum + es_reset = ss_clk = es_clk = None + continue + if self.matched[COND_RESET_STOP]: + es_reset = self.samplenum + self.handle_reset(ss_reset or 0, es_reset, ss_clk and es_clk) + ss_reset = es_reset = ss_clk = es_clk = None + continue + if self.matched[COND_RSTCLK_START]: + ss_clk = self.samplenum + es_clk = None + continue + if self.matched[COND_RSTCLK_STOP]: + es_clk = self.samplenum + continue + + # Handle data bits' validity boundaries. Also covers the + # periodic check for high I/O level and update of details + # during internal processing. + if self.matched[COND_DATA_START]: + self.handle_data_bit(self.samplenum, None, io) + continue + if self.matched[COND_DATA_STOP]: + self.handle_data_bit(None, self.samplenum, None) + continue + + # Additional check for idle I/O during internal processing, + # independent of CLK edges this time. This assures that the + # decoder ends processing intervals as soon as possible, at + # the most precise timestamp. + if is_processing and self.matched[COND_PROC_IOH]: + self.handle_data_bit(self.samplenum, self.samplenum, io) + continue + + # The START/STOP conditions are only applicable outside of + # "outgoing data" or "internal processing" periods. This is + # what the data sheet specifies. + if not is_outgoing and not is_processing: + if self.matched[COND_CMD_START]: + self.handle_command(self.samplenum, True) + continue + if self.matched[COND_CMD_STOP]: + self.handle_command(self.samplenum, False) + continue diff --git a/libsigrokdecode4DSL/decoders/spdif/__init__.py b/libsigrokdecode4DSL/decoders/spdif/__init__.py new file mode 100644 index 00000000..3f5109a7 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/spdif/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Guenther Wenninger +## +## 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, see . +## + +''' +S/PDIF (Sony/Philips Digital Interface Format) is a serial bus for +transmitting audio data. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/spdif/pd.py b/libsigrokdecode4DSL/decoders/spdif/pd.py new file mode 100644 index 00000000..532bf825 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/spdif/pd.py @@ -0,0 +1,246 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Guenther Wenninger +## +## 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, see . +## + +import sigrokdecode as srd + +class SamplerateError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = 'spdif' + name = 'S/PDIF' + longname = 'Sony/Philips Digital Interface Format' + desc = 'Serial bus for connecting digital audio devices.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Audio', 'PC'] + channels = ( + {'id': 'data', 'name': 'Data', 'desc': 'Data line'}, + ) + annotations = ( + ('bitrate', 'Bitrate / baudrate'), + ('preamble', 'Preamble'), + ('bits', 'Bits'), + ('aux', 'Auxillary-audio-databits'), + ('samples', 'Audio Samples'), + ('validity', 'Data Valid'), + ('subcode', 'Subcode data'), + ('chan_stat', 'Channnel Status'), + ('parity', 'Parity Bit'), + ) + annotation_rows = ( + ('info', 'Info', (0, 1, 3, 5, 6, 7, 8)), + ('bits', 'Bits', (2,)), + ('samples', 'Samples', (4,)), + ) + + def putx(self, ss, es, data): + self.put(ss, es, self.out_ann, data) + + def puty(self, data): + self.put(self.ss_edge, self.samplenum, self.out_ann, data) + + def __init__(self): + self.reset() + + def reset(self): + self.state = 'GET FIRST PULSE WIDTH' + self.ss_edge = None + self.first_edge = True + self.samplenum_prev_edge = 0 + self.pulse_width = 0 + + self.clocks = [] + self.range1 = 0 + self.range2 = 0 + + self.preamble_state = 0 + self.preamble = [] + self.seen_preamble = False + self.last_preamble = 0 + + self.first_one = True + self.subframe = [] + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def get_pulse_type(self): + if self.range1 == 0 or self.range2 == 0: + return -1 + if self.pulse_width >= self.range2: + return 2 + elif self.pulse_width >= self.range1: + return 0 + else: + return 1 + + def find_first_pulse_width(self): + if self.pulse_width != 0: + self.clocks.append(self.pulse_width) + self.state = 'GET SECOND PULSE WIDTH' + + def find_second_pulse_width(self): + if self.pulse_width > (self.clocks[0] * 1.3) or \ + self.pulse_width < (self.clocks[0] * 0.7): + self.clocks.append(self.pulse_width) + self.state = 'GET THIRD PULSE WIDTH' + + def find_third_pulse_width(self): + if not ((self.pulse_width > (self.clocks[0] * 1.3) or \ + self.pulse_width < (self.clocks[0] * 0.7)) \ + and (self.pulse_width > (self.clocks[1] * 1.3) or \ + self.pulse_width < (self.clocks[1] * 0.7))): + return + + self.clocks.append(self.pulse_width) + self.clocks.sort() + self.range1 = (self.clocks[0] + self.clocks[1]) / 2 + self.range2 = (self.clocks[1] + self.clocks[2]) / 2 + spdif_bitrate = int(self.samplerate / (self.clocks[2] / 1.5)) + self.ss_edge = 0 + + self.puty([0, ['Signal Bitrate: %d Mbit/s (=> %d kHz)' % \ + (spdif_bitrate, (spdif_bitrate/ (2 * 32)))]]) + + clock_period_nsec = 1000000000 / spdif_bitrate + + self.last_preamble = self.samplenum + + # We are done recovering the clock, now let's decode the data stream. + self.state = 'DECODE STREAM' + + def decode_stream(self): + pulse = self.get_pulse_type() + + if not self.seen_preamble: + # This is probably the start of a preamble, decode it. + if pulse == 2: + self.preamble.append(self.get_pulse_type()) + self.state = 'DECODE PREAMBLE' + self.ss_edge = self.samplenum - self.pulse_width - 1 + return + + # We've seen a preamble. + if pulse == 1 and self.first_one: + self.first_one = False + self.subframe.append([pulse, self.samplenum - \ + self.pulse_width - 1, self.samplenum]) + elif pulse == 1 and not self.first_one: + self.subframe[-1][2] = self.samplenum + self.putx(self.subframe[-1][1], self.samplenum, [2, ['1']]) + self.bitcount += 1 + self.first_one = True + else: + self.subframe.append([pulse, self.samplenum - \ + self.pulse_width - 1, self.samplenum]) + self.putx(self.samplenum - self.pulse_width - 1, + self.samplenum, [2, ['0']]) + self.bitcount += 1 + + if self.bitcount == 28: + aux_audio_data = self.subframe[0:4] + sam, sam_rot = '', '' + for a in aux_audio_data: + sam = sam + str(a[0]) + sam_rot = str(a[0]) + sam_rot + sample = self.subframe[4:24] + for s in sample: + sam = sam + str(s[0]) + sam_rot = str(s[0]) + sam_rot + validity = self.subframe[24:25] + subcode_data = self.subframe[25:26] + channel_status = self.subframe[26:27] + parity = self.subframe[27:28] + + self.putx(aux_audio_data[0][1], aux_audio_data[3][2], \ + [3, ['Aux 0x%x' % int(sam, 2), '0x%x' % int(sam, 2)]]) + self.putx(sample[0][1], sample[19][2], \ + [3, ['Sample 0x%x' % int(sam, 2), '0x%x' % int(sam, 2)]]) + self.putx(aux_audio_data[0][1], sample[19][2], \ + [4, ['Audio 0x%x' % int(sam_rot, 2), '0x%x' % int(sam_rot, 2)]]) + if validity[0][0] == 0: + self.putx(validity[0][1], validity[0][2], [5, ['V']]) + else: + self.putx(validity[0][1], validity[0][2], [5, ['E']]) + self.putx(subcode_data[0][1], subcode_data[0][2], + [6, ['S: %d' % subcode_data[0][0]]]) + self.putx(channel_status[0][1], channel_status[0][2], + [7, ['C: %d' % channel_status[0][0]]]) + self.putx(parity[0][1], parity[0][2], [8, ['P: %d' % parity[0][0]]]) + + self.subframe = [] + self.seen_preamble = False + self.bitcount = 0 + + def decode_preamble(self): + if self.preamble_state == 0: + self.preamble.append(self.get_pulse_type()) + self.preamble_state = 1 + elif self.preamble_state == 1: + self.preamble.append(self.get_pulse_type()) + self.preamble_state = 2 + elif self.preamble_state == 2: + self.preamble.append(self.get_pulse_type()) + self.preamble_state = 0 + self.state = 'DECODE STREAM' + if self.preamble == [2, 0, 1, 0]: + self.puty([1, ['Preamble W', 'W']]) + elif self.preamble == [2, 2, 1, 1]: + self.puty([1, ['Preamble M', 'M']]) + elif self.preamble == [2, 1, 1, 2]: + self.puty([1, ['Preamble B', 'B']]) + else: + self.puty([1, ['Unknown Preamble', 'Unknown Prea.', 'U']]) + self.preamble = [] + self.seen_preamble = True + self.bitcount = 0 + self.first_one = True + + self.last_preamble = self.samplenum + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + + # Throw away first detected edge as it might be mangled data. + self.wait({0: 'e'}) + + while True: + # Wait for any edge (rising or falling). + (data,) = self.wait({0: 'e'}) + self.pulse_width = self.samplenum - self.samplenum_prev_edge - 1 + self.samplenum_prev_edge = self.samplenum + + if self.state == 'GET FIRST PULSE WIDTH': + self.find_first_pulse_width() + elif self.state == 'GET SECOND PULSE WIDTH': + self.find_second_pulse_width() + elif self.state == 'GET THIRD PULSE WIDTH': + self.find_third_pulse_width() + elif self.state == 'DECODE STREAM': + self.decode_stream() + elif self.state == 'DECODE PREAMBLE': + self.decode_preamble() diff --git a/libsigrokdecode4DSL/decoders/spiflash/__init__.py b/libsigrokdecode4DSL/decoders/spiflash/__init__.py new file mode 100644 index 00000000..151bd3e2 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/spiflash/__init__.py @@ -0,0 +1,30 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012-2015 Uwe Hermann +## +## 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, see . +## + +''' +This decoder stacks on top of the 'spi' PD and decodes the xx25 series +SPI (NOR) flash chip protocol. + +It currently supports the MX25L1605D/MX25L3205D/MX25L6405D. + +Details: +http://www.macronix.com/QuickPlace/hq/PageLibrary4825740B00298A3B.nsf/h_Index/3F21BAC2E121E17848257639003A3146/$File/MX25L1605D-3205D-6405D-1.5.pdf +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/spiflash/lists.py b/libsigrokdecode4DSL/decoders/spiflash/lists.py new file mode 100644 index 00000000..5c366bee --- /dev/null +++ b/libsigrokdecode4DSL/decoders/spiflash/lists.py @@ -0,0 +1,144 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Uwe Hermann +## +## 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, see . +## + +from collections import OrderedDict + +# OrderedDict which maps command IDs to their names and descriptions. +# Please keep this sorted by command ID. +# Don't forget to update 'Ann' in pd.py if you add/remove items here. +cmds = OrderedDict([ + (0x01, ('WRSR', 'Write status register')), + (0x02, ('PP', 'Page program')), + (0x03, ('READ', 'Read data')), + (0x04, ('WRDI', 'Write disable')), + (0x05, ('RDSR', 'Read status register')), + (0x06, ('WREN', 'Write enable')), + (0x0b, ('FAST/READ', 'Fast read data')), + (0x20, ('SE', 'Sector erase')), + (0x2b, ('RDSCUR', 'Read security register')), + (0x2f, ('WRSCUR', 'Write security register')), + (0x35, ('RDSR2', 'Read status register 2')), + (0x60, ('CE', 'Chip erase')), + (0x70, ('ESRY', 'Enable SO to output RY/BY#')), + (0x80, ('DSRY', 'Disable SO to output RY/BY#')), + (0x82, ('WRITE1', 'Main memory page program through buffer 1 with built-in erase')), + (0x85, ('WRITE2', 'Main memory page program through buffer 2 with built-in erase')), + (0x90, ('REMS', 'Read electronic manufacturer & device ID')), + (0x9f, ('RDID', 'Read identification')), + (0xab, ('RDP/RES', 'Release from deep powerdown / Read electronic ID')), + (0xad, ('CP', 'Continuously program mode')), + (0xb1, ('ENSO', 'Enter secured OTP')), + (0xb9, ('DP', 'Deep power down')), + (0xbb, ('2READ', '2x I/O read')), # a.k.a. "Fast read dual I/O". + (0xc1, ('EXSO', 'Exit secured OTP')), + (0xc7, ('CE2', 'Chip erase')), # Alternative command ID + (0xd7, ('STATUS', 'Status register read')), + (0xd8, ('BE', 'Block erase')), + (0xef, ('REMS2', 'Read ID for 2x I/O mode')), +]) + +device_name = { + 'adesto': { + 0x00: 'AT45Dxxx family, standard series', + }, + 'fidelix': { + 0x15: 'FM25Q32', + }, + 'macronix': { + 0x14: 'MX25L1605D', + 0x15: 'MX25L3205D', + 0x16: 'MX25L6405D', + }, + 'winbond': { + 0x13: 'W25Q80DV', + }, +} + +chips = { + # Adesto + 'adesto_at45db161e': { + 'vendor': 'Adesto', + 'model': 'AT45DB161E', + 'res_id': 0xff, # The chip doesn't emit an ID here. + 'rems_id': 0xffff, # Not supported by the chip. + 'rems2_id': 0xffff, # Not supported by the chip. + 'rdid_id': 0x1f26000100, # RDID and 2 extra "EDI" bytes. + 'page_size': 528, # Configurable, could also be 512 bytes. + 'sector_size': 128 * 1024, + 'block_size': 4 * 1024, + }, + # FIDELIX + 'fidelix_fm25q32': { + 'vendor': 'FIDELIX', + 'model': 'FM25Q32', + 'res_id': 0x15, + 'rems_id': 0xa115, + 'rems2_id': 0xa115, + 'rdid_id': 0xa14016, + 'page_size': 256, + 'sector_size': 4 * 1024, + 'block_size': 64 * 1024, + }, + # Macronix + 'macronix_mx25l1605d': { + 'vendor': 'Macronix', + 'model': 'MX25L1605D', + 'res_id': 0x14, + 'rems_id': 0xc214, + 'rems2_id': 0xc214, + 'rdid_id': 0xc22015, + 'page_size': 256, + 'sector_size': 4 * 1024, + 'block_size': 64 * 1024, + }, + 'macronix_mx25l3205d': { + 'vendor': 'Macronix', + 'model': 'MX25L3205D', + 'res_id': 0x15, + 'rems_id': 0xc215, + 'rems2_id': 0xc215, + 'rdid_id': 0xc22016, + 'page_size': 256, + 'sector_size': 4 * 1024, + 'block_size': 64 * 1024, + }, + 'macronix_mx25l6405d': { + 'vendor': 'Macronix', + 'model': 'MX25L6405D', + 'res_id': 0x16, + 'rems_id': 0xc216, + 'rems2_id': 0xc216, + 'rdid_id': 0xc22017, + 'page_size': 256, + 'sector_size': 4 * 1024, + 'block_size': 64 * 1024, + }, + # Winbond + 'winbond_w25q80dv': { + 'vendor': 'Winbond', + 'model': 'W25Q80DV', + 'res_id': 0x13, + 'rems_id': 0xef13, + 'rems2_id': 0xffff, # Not supported by the chip. + 'rdid_id': 0xef4014, + 'page_size': 256, + 'sector_size': 4 * 1024, + 'block_size': 64 * 1024, # Configurable, could also be 32 * 1024 bytes. + }, +} diff --git a/libsigrokdecode4DSL/decoders/spiflash/pd.py b/libsigrokdecode4DSL/decoders/spiflash/pd.py new file mode 100644 index 00000000..5ee22740 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/spiflash/pd.py @@ -0,0 +1,539 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2011-2016 Uwe Hermann +## +## 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, see . +## + +import sigrokdecode as srd +from .lists import * + +L = len(cmds) + +# Don't forget to keep this in sync with 'cmds' is lists.py. +class Ann: + WRSR, PP, READ, WRDI, RDSR, WREN, FAST_READ, SE, RDSCUR, WRSCUR, \ + RDSR2, CE, ESRY, DSRY, WRITE1, WRITE2, REMS, RDID, RDP_RES, CP, ENSO, DP, \ + READ2X, EXSO, CE2, STATUS, BE, REMS2, \ + BIT, FIELD, WARN = range(L + 3) + +def cmd_annotation_classes(): + return tuple([tuple([cmd[0].lower(), cmd[1]]) for cmd in cmds.values()]) + +def decode_dual_bytes(sio0, sio1): + # Given a byte in SIO0 (MOSI) of even bits and a byte in + # SIO1 (MISO) of odd bits, return a tuple of two bytes. + def combine_byte(even, odd): + result = 0 + for bit in range(4): + if even & (1 << bit): + result |= 1 << (bit*2) + if odd & (1 << bit): + result |= 1 << ((bit*2) + 1) + return result + return (combine_byte(sio0 >> 4, sio1 >> 4), combine_byte(sio0, sio1)) + +def decode_status_reg(data): + # TODO: Additional per-bit(s) self.put() calls with correct start/end. + + # Bits[0:0]: WIP (write in progress) + s = 'W' if (data & (1 << 0)) else 'No w' + ret = '%srite operation in progress.\n' % s + + # Bits[1:1]: WEL (write enable latch) + s = '' if (data & (1 << 1)) else 'not ' + ret += 'Internal write enable latch is %sset.\n' % s + + # Bits[5:2]: Block protect bits + # TODO: More detailed decoding (chip-dependent). + ret += 'Block protection bits (BP3-BP0): 0x%x.\n' % ((data & 0x3c) >> 2) + + # Bits[6:6]: Continuously program mode (CP mode) + s = '' if (data & (1 << 6)) else 'not ' + ret += 'Device is %sin continuously program mode (CP mode).\n' % s + + # Bits[7:7]: SRWD (status register write disable) + s = 'not ' if (data & (1 << 7)) else '' + ret += 'Status register writes are %sallowed.\n' % s + + return ret + +class Decoder(srd.Decoder): + api_version = 3 + id = 'spiflash' + name = 'SPI flash' + longname = 'SPI flash chips' + desc = 'xx25 series SPI (NOR) flash chip protocol.' + license = 'gplv2+' + inputs = ['spi'] + outputs = [] + tags = ['IC', 'Memory'] + annotations = cmd_annotation_classes() + ( + ('bit', 'Bit'), + ('field', 'Field'), + ('warning', 'Warning'), + ) + annotation_rows = ( + ('bits', 'Bits', (L + 0,)), + ('fields', 'Fields', (L + 1,)), + ('commands', 'Commands', tuple(range(len(cmds)))), + ('warnings', 'Warnings', (L + 2,)), + ) + options = ( + {'id': 'chip', 'desc': 'Chip', 'default': tuple(chips.keys())[0], + 'values': tuple(chips.keys())}, + {'id': 'format', 'desc': 'Data format', 'default': 'hex', + 'values': ('hex', 'ascii')}, + ) + + def __init__(self): + self.reset() + + def reset(self): + self.device_id = -1 + self.on_end_transaction = None + self.end_current_transaction() + self.writestate = 0 + + # Build dict mapping command keys to handler functions. Each + # command in 'cmds' (defined in lists.py) has a matching + # handler self.handle_. + def get_handler(cmd): + s = 'handle_%s' % cmds[cmd][0].lower().replace('/', '_') + return getattr(self, s) + self.cmd_handlers = dict((cmd, get_handler(cmd)) for cmd in cmds.keys()) + + def end_current_transaction(self): + if self.on_end_transaction is not None: # Callback for CS# transition. + self.on_end_transaction() + self.on_end_transaction = None + self.state = None + self.cmdstate = 1 + self.addr = 0 + self.data = [] + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.chip = chips[self.options['chip']] + self.vendor = self.options['chip'].split('_')[0] + + def putx(self, data): + # Simplification, most annotations span exactly one SPI byte/packet. + self.put(self.ss, self.es, self.out_ann, data) + + def putf(self, data): + self.put(self.ss_field, self.es_field, self.out_ann, data) + + def putc(self, data): + self.put(self.ss_cmd, self.es_cmd, self.out_ann, data) + + def device(self): + return device_name[self.vendor].get(self.device_id, 'Unknown') + + def vendor_device(self): + return '%s %s' % (self.chip['vendor'], self.device()) + + def cmd_ann_list(self): + x, s = cmds[self.state][0], cmds[self.state][1] + return ['Command: %s (%s)' % (s, x), 'Command: %s' % s, + 'Cmd: %s' % s, 'Cmd: %s' % x, x] + + def cmd_vendor_dev_list(self): + c, d = cmds[self.state], 'Device = %s' % self.vendor_device() + return ['%s (%s): %s' % (c[1], c[0], d), '%s: %s' % (c[1], d), + '%s: %s' % (c[0], d), d, self.vendor_device()] + + def emit_cmd_byte(self): + self.ss_cmd = self.ss + self.putx([Ann.FIELD, self.cmd_ann_list()]) + self.addr = 0 + + def emit_addr_bytes(self, mosi): + self.addr |= (mosi << ((4 - self.cmdstate) * 8)) + b = ((3 - (self.cmdstate - 2)) * 8) - 1 + self.putx([Ann.BIT, + ['Address bits %d..%d: 0x%02x' % (b, b - 7, mosi), + 'Addr bits %d..%d: 0x%02x' % (b, b - 7, mosi), + 'Addr bits %d..%d' % (b, b - 7), 'A%d..A%d' % (b, b - 7)]]) + if self.cmdstate == 2: + self.ss_field = self.ss + if self.cmdstate == 4: + self.es_field = self.es + self.putf([Ann.FIELD, ['Address: 0x%06x' % self.addr, + 'Addr: 0x%06x' % self.addr, '0x%06x' % self.addr]]) + + def handle_wren(self, mosi, miso): + self.putx([Ann.WREN, self.cmd_ann_list()]) + self.writestate = 1 + + def handle_wrdi(self, mosi, miso): + self.putx([Ann.WRDI, self.cmd_ann_list()]) + self.writestate = 0 + + def handle_rdid(self, mosi, miso): + if self.cmdstate == 1: + # Byte 1: Master sends command ID. + self.emit_cmd_byte() + elif self.cmdstate == 2: + # Byte 2: Slave sends the JEDEC manufacturer ID. + self.putx([Ann.FIELD, ['Manufacturer ID: 0x%02x' % miso]]) + elif self.cmdstate == 3: + # Byte 3: Slave sends the memory type. + self.putx([Ann.FIELD, ['Memory type: 0x%02x' % miso]]) + elif self.cmdstate == 4: + # Byte 4: Slave sends the device ID. + self.device_id = miso + self.putx([Ann.FIELD, ['Device ID: 0x%02x' % miso]]) + + if self.cmdstate == 4: + self.es_cmd = self.es + self.putc([Ann.RDID, self.cmd_vendor_dev_list()]) + self.state = None + else: + self.cmdstate += 1 + + def handle_rdsr(self, mosi, miso): + # Read status register: Master asserts CS#, sends RDSR command, + # reads status register byte. If CS# is kept asserted, the status + # register can be read continuously / multiple times in a row. + # When done, the master de-asserts CS# again. + if self.cmdstate == 1: + # Byte 1: Master sends command ID. + self.emit_cmd_byte() + elif self.cmdstate >= 2: + # Bytes 2-x: Slave sends status register as long as master clocks. + self.es_cmd = self.es + self.putx([Ann.BIT, [decode_status_reg(miso)]]) + self.putx([Ann.FIELD, ['Status register']]) + self.putc([Ann.RDSR, self.cmd_ann_list()]) + # Set write latch state. + self.writestate = 1 if (miso & (1 << 1)) else 0 + self.cmdstate += 1 + + def handle_rdsr2(self, mosi, miso): + # Read status register 2: Master asserts CS#, sends RDSR2 command, + # reads status register 2 byte. If CS# is kept asserted, the status + # register 2 can be read continuously / multiple times in a row. + # When done, the master de-asserts CS# again. + if self.cmdstate == 1: + # Byte 1: Master sends command ID. + self.emit_cmd_byte() + elif self.cmdstate >= 2: + # Bytes 2-x: Slave sends status register 2 as long as master clocks. + self.es_cmd = self.es + # TODO: Decode status register 2 correctly. + self.putx([Ann.BIT, [decode_status_reg(miso)]]) + self.putx([Ann.FIELD, ['Status register 2']]) + self.putc([Ann.RDSR2, self.cmd_ann_list()]) + self.cmdstate += 1 + + def handle_wrsr(self, mosi, miso): + # Write status register: Master asserts CS#, sends WRSR command, + # writes 1 or 2 status register byte(s). + # When done, the master de-asserts CS# again. If this doesn't happen + # the WRSR command will not be executed. + if self.cmdstate == 1: + # Byte 1: Master sends command ID. + self.emit_cmd_byte() + elif self.cmdstate == 2: + # Byte 2: Master sends status register 1. + self.putx([Ann.BIT, [decode_status_reg(mosi)]]) + self.putx([Ann.FIELD, ['Status register 1']]) + # Set write latch state. + self.writestate = 1 if (miso & (1 << 1)) else 0 + elif self.cmdstate == 3: + # Byte 3: Master sends status register 2. + # TODO: Decode status register 2 correctly. + self.putx([Ann.BIT, [decode_status_reg(mosi)]]) + self.putx([Ann.FIELD, ['Status register 2']]) + self.es_cmd = self.es + self.putc([Ann.WRSR, self.cmd_ann_list()]) + self.cmdstate += 1 + + def handle_read(self, mosi, miso): + # Read data bytes: Master asserts CS#, sends READ command, sends + # 3-byte address, reads >= 1 data bytes, de-asserts CS#. + if self.cmdstate == 1: + # Byte 1: Master sends command ID. + self.emit_cmd_byte() + elif self.cmdstate in (2, 3, 4): + # Bytes 2/3/4: Master sends read address (24bits, MSB-first). + self.emit_addr_bytes(mosi) + elif self.cmdstate >= 5: + # Bytes 5-x: Master reads data bytes (until CS# de-asserted). + self.es_field = self.es # Will be overwritten for each byte. + if self.cmdstate == 5: + self.ss_field = self.ss + self.on_end_transaction = lambda: self.output_data_block('Data', Ann.READ) + self.data.append(miso) + self.cmdstate += 1 + + def handle_write_common(self, mosi, miso, ann): + # Write data bytes: Master asserts CS#, sends WRITE command, sends + # 3-byte address, writes >= 1 data bytes, de-asserts CS#. + if self.cmdstate == 1: + # Byte 1: Master sends command ID. + self.emit_cmd_byte() + if self.writestate == 0: + self.putc([Ann.WARN, ['Warning: WREN might be missing']]) + elif self.cmdstate in (2, 3, 4): + # Bytes 2/3/4: Master sends write address (24bits, MSB-first). + self.emit_addr_bytes(mosi) + elif self.cmdstate >= 5: + # Bytes 5-x: Master writes data bytes (until CS# de-asserted). + self.es_field = self.es # Will be overwritten for each byte. + if self.cmdstate == 5: + self.ss_field = self.ss + self.on_end_transaction = lambda: self.output_data_block('Data', ann) + self.data.append(mosi) + self.cmdstate += 1 + + def handle_write1(self, mosi, miso): + self.handle_write_common(mosi, miso, Ann.WRITE1) + + def handle_write2(self, mosi, miso): + self.handle_write_common(mosi, miso, Ann.WRITE2) + + def handle_fast_read(self, mosi, miso): + # Fast read: Master asserts CS#, sends FAST READ command, sends + # 3-byte address + 1 dummy byte, reads >= 1 data bytes, de-asserts CS#. + if self.cmdstate == 1: + # Byte 1: Master sends command ID. + self.emit_cmd_byte() + elif self.cmdstate in (2, 3, 4): + # Bytes 2/3/4: Master sends read address (24bits, MSB-first). + self.emit_addr_bytes(mosi) + elif self.cmdstate == 5: + self.putx([Ann.BIT, ['Dummy byte: 0x%02x' % mosi]]) + elif self.cmdstate >= 6: + # Bytes 6-x: Master reads data bytes (until CS# de-asserted). + self.es_field = self.es # Will be overwritten for each byte. + if self.cmdstate == 6: + self.ss_field = self.ss + self.on_end_transaction = lambda: self.output_data_block('Data', Ann.FAST_READ) + self.data.append(miso) + self.cmdstate += 1 + + def handle_2read(self, mosi, miso): + # 2x I/O read (fast read dual I/O): Master asserts CS#, sends 2READ + # command, sends 3-byte address + 1 dummy byte, reads >= 1 data bytes, + # de-asserts CS#. All data after the command is sent via two I/O pins. + # MOSI = SIO0 = even bits, MISO = SIO1 = odd bits. + if self.cmdstate != 1: + b1, b2 = decode_dual_bytes(mosi, miso) + if self.cmdstate == 1: + # Byte 1: Master sends command ID. + self.emit_cmd_byte() + elif self.cmdstate == 2: + # Bytes 2/3(/4): Master sends read address (24bits, MSB-first). + # Handle bytes 2 and 3 here. + self.emit_addr_bytes(b1) + self.cmdstate = 3 + self.emit_addr_bytes(b2) + elif self.cmdstate == 4: + # Byte 5: Dummy byte. Also handle byte 4 (address LSB) here. + self.emit_addr_bytes(b1) + self.cmdstate = 5 + self.putx([Ann.BIT, ['Dummy byte: 0x%02x' % b2]]) + elif self.cmdstate >= 6: + # Bytes 6-x: Master reads data bytes (until CS# de-asserted). + self.es_field = self.es # Will be overwritten for each byte. + if self.cmdstate == 6: + self.ss_field = self.ss + self.on_end_transaction = lambda: self.output_data_block('Data', Ann.READ2X) + self.data.append(b1) + self.data.append(b2) + self.cmdstate += 1 + + def handle_status(self, mosi, miso): + if self.cmdstate == 1: + # Byte 1: Master sends command ID. + self.emit_cmd_byte() + self.on_end_transaction = lambda: self.putc([Ann.STATUS, [cmds[self.state][1]]]) + else: + # Will be overwritten for each byte. + self.es_cmd = self.es + self.es_field = self.es + if self.cmdstate == 2: + self.ss_field = self.ss + self.putx([Ann.BIT, ['Status register byte %d: 0x%02x' % ((self.cmdstate % 2) + 1, miso)]]) + self.cmdstate += 1 + + # TODO: Warn/abort if we don't see the necessary amount of bytes. + def handle_se(self, mosi, miso): + if self.cmdstate == 1: + # Byte 1: Master sends command ID. + self.emit_cmd_byte() + if self.writestate == 0: + self.putx([Ann.WARN, ['Warning: WREN might be missing']]) + elif self.cmdstate in (2, 3, 4): + # Bytes 2/3/4: Master sends sector address (24bits, MSB-first). + self.emit_addr_bytes(mosi) + + if self.cmdstate == 4: + self.es_cmd = self.es + d = 'Erase sector %d (0x%06x)' % (self.addr, self.addr) + self.putc([Ann.SE, [d]]) + # TODO: Max. size depends on chip, check that too if possible. + if self.addr % 4096 != 0: + # Sector addresses must be 4K-aligned (same for all 3 chips). + self.putc([Ann.WARN, ['Warning: Invalid sector address!']]) + self.state = None + else: + self.cmdstate += 1 + + def handle_be(self, mosi, miso): + pass # TODO + + def handle_ce(self, mosi, miso): + self.putx([Ann.CE, self.cmd_ann_list()]) + if self.writestate == 0: + self.putx([Ann.WARN, ['Warning: WREN might be missing']]) + + def handle_ce2(self, mosi, miso): + self.putx([Ann.CE2, self.cmd_ann_list()]) + if self.writestate == 0: + self.putx([Ann.WARN, ['Warning: WREN might be missing']]) + + def handle_pp(self, mosi, miso): + # Page program: Master asserts CS#, sends PP command, sends 3-byte + # page address, sends >= 1 data bytes, de-asserts CS#. + if self.cmdstate == 1: + # Byte 1: Master sends command ID. + self.emit_cmd_byte() + elif self.cmdstate in (2, 3, 4): + # Bytes 2/3/4: Master sends page address (24bits, MSB-first). + self.emit_addr_bytes(mosi) + elif self.cmdstate >= 5: + # Bytes 5-x: Master sends data bytes (until CS# de-asserted). + self.es_field = self.es # Will be overwritten for each byte. + if self.cmdstate == 5: + self.ss_field = self.ss + self.on_end_transaction = lambda: self.output_data_block('Data', Ann.PP) + self.data.append(mosi) + self.cmdstate += 1 + + def handle_cp(self, mosi, miso): + pass # TODO + + def handle_dp(self, mosi, miso): + pass # TODO + + def handle_rdp_res(self, mosi, miso): + if self.cmdstate == 1: + # Byte 1: Master sends command ID. + self.emit_cmd_byte() + elif self.cmdstate in (2, 3, 4): + # Bytes 2/3/4: Master sends three dummy bytes. + self.putx([Ann.FIELD, ['Dummy byte: %02x' % mosi]]) + elif self.cmdstate == 5: + # Byte 5: Slave sends device ID. + self.es_cmd = self.es + self.device_id = miso + self.putx([Ann.FIELD, ['Device ID: %s' % self.device()]]) + d = 'Device = %s' % self.vendor_device() + self.putc([Ann.RDP_RES, self.cmd_vendor_dev_list()]) + self.state = None + self.cmdstate += 1 + + def handle_rems(self, mosi, miso): + if self.cmdstate == 1: + # Byte 1: Master sends command ID. + self.emit_cmd_byte() + elif self.cmdstate in (2, 3): + # Bytes 2/3: Master sends two dummy bytes. + self.putx([Ann.FIELD, ['Dummy byte: 0x%02x' % mosi]]) + elif self.cmdstate == 4: + # Byte 4: Master sends 0x00 or 0x01. + # 0x00: Master wants manufacturer ID as first reply byte. + # 0x01: Master wants device ID as first reply byte. + self.manufacturer_id_first = True if (mosi == 0x00) else False + d = 'manufacturer' if (mosi == 0x00) else 'device' + self.putx([Ann.FIELD, ['Master wants %s ID first' % d]]) + elif self.cmdstate == 5: + # Byte 5: Slave sends manufacturer ID (or device ID). + self.ids = [miso] + d = 'Manufacturer' if self.manufacturer_id_first else 'Device' + self.putx([Ann.FIELD, ['%s ID: 0x%02x' % (d, miso)]]) + elif self.cmdstate == 6: + # Byte 6: Slave sends device ID (or manufacturer ID). + self.ids.append(miso) + d = 'Device' if self.manufacturer_id_first else 'Manufacturer' + self.putx([Ann.FIELD, ['%s ID: 0x%02x' % (d, miso)]]) + + if self.cmdstate == 6: + id_ = self.ids[1] if self.manufacturer_id_first else self.ids[0] + self.device_id = id_ + self.es_cmd = self.es + self.putc([Ann.REMS, self.cmd_vendor_dev_list()]) + self.state = None + else: + self.cmdstate += 1 + + def handle_rems2(self, mosi, miso): + pass # TODO + + def handle_enso(self, mosi, miso): + pass # TODO + + def handle_exso(self, mosi, miso): + pass # TODO + + def handle_rdscur(self, mosi, miso): + pass # TODO + + def handle_wrscur(self, mosi, miso): + pass # TODO + + def handle_esry(self, mosi, miso): + pass # TODO + + def handle_dsry(self, mosi, miso): + pass # TODO + + def output_data_block(self, label, idx): + # Print accumulated block of data + # (called on CS# de-assert via self.on_end_transaction callback). + self.es_cmd = self.es # End on the CS# de-assert sample. + if self.options['format'] == 'hex': + s = ' '.join([('%02x' % b) for b in self.data]) + else: + s = ''.join(map(chr, self.data)) + self.putf([Ann.FIELD, ['%s (%d bytes)' % (label, len(self.data))]]) + self.putc([idx, ['%s (addr 0x%06x, %d bytes): %s' % \ + (cmds[self.state][1], self.addr, len(self.data), s)]]) + + def decode(self, ss, es, data): + ptype, mosi, miso = data + + self.ss, self.es = ss, es + + if ptype == 'CS-CHANGE': + self.end_current_transaction() + + if ptype != 'DATA': + return + + # If we encountered a known chip command, enter the resp. state. + if self.state is None: + self.state = mosi + self.cmdstate = 1 + + # Handle commands. + try: + self.cmd_handlers[self.state](mosi, miso) + except KeyError: + self.putx([Ann.BIT, ['Unknown command: 0x%02x' % mosi]]) + self.state = None diff --git a/libsigrokdecode4DSL/decoders/ssi32/__init__.py b/libsigrokdecode4DSL/decoders/ssi32/__init__.py new file mode 100644 index 00000000..cd6890fa --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ssi32/__init__.py @@ -0,0 +1,28 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2016 Robert Bosch Car Multimedia GmbH +## Authors: Oleksij Rempel +## +## +## +## 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, see . +## + +''' +This decoder stacks on top of the 'spi' PD and decodes the Bosch +SSI32 protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/ssi32/pd.py b/libsigrokdecode4DSL/decoders/ssi32/pd.py new file mode 100644 index 00000000..51608039 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/ssi32/pd.py @@ -0,0 +1,127 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2016 Robert Bosch Car Multimedia GmbH +## Authors: Oleksij Rempel +## +## +## +## 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, see . +## + +import sigrokdecode as srd + +class Decoder(srd.Decoder): + api_version = 3 + id = 'ssi32' + name = 'SSI32' + longname = 'Synchronous Serial Interface (32bit)' + desc = 'Synchronous Serial Interface (32bit) protocol.' + license = 'gplv2+' + inputs = ['spi'] + outputs = [] + tags = ['Embedded/industrial'] + options = ( + {'id': 'msgsize', 'desc': 'Message size', 'default': 64}, + ) + annotations = ( + ('ctrl-tx', 'CTRL TX'), + ('ack-tx', 'ACK TX'), + ('ctrl-rx', 'CTRL RX'), + ('ack-rx', 'ACK RX'), + ) + annotation_rows = ( + ('tx', 'TX', (0, 1)), + ('rx', 'RX', (2, 3)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.ss_cmd, self.es_cmd = 0, 0 + self.mosi_bytes = [] + self.miso_bytes = [] + self.es_array = [] + self.rx_size = 0 + self.tx_size = 0 + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + self.put(self.ss_cmd, self.es_cmd, self.out_ann, data) + + def reset_data(self): + self.mosi_bytes = [] + self.miso_bytes = [] + self.es_array = [] + + def handle_ack(self): + # Only first byte should have ACK data, other 3 bytes are reserved. + self.es_cmd = self.es_array[0] + self.putx([1, ['> ACK:0x%02x' % (self.mosi_bytes[0])]]) + self.putx([3, ['< ACK:0x%02x' % (self.miso_bytes[0])]]) + + def handle_ctrl(self): + mosi = miso = '' + self.tx_size = self.mosi_bytes[2] + self.rx_size = self.miso_bytes[2] + + if self.tx_size > 0: + mosi = ', DATA:0x' + ''.join(format(x, '02x') for x in self.mosi_bytes[4:self.tx_size + 4]) + if self.rx_size > 0: + miso = ', DATA:0x' + ''.join(format(x, '02x') for x in self.miso_bytes[4:self.rx_size + 4]) + + self.es_cmd = self.es_array[self.tx_size + 3] + self.putx([0, ['> CTRL:0x%02x, LUN:0x%02x, SIZE:0x%02x, CRC:0x%02x%s' + % (self.mosi_bytes[0], self.mosi_bytes[1], + self.mosi_bytes[2], self.mosi_bytes[3], mosi)]]) + + self.es_cmd = self.es_array[self.rx_size + 3] + self.putx([2, ['< CTRL:0x%02x, LUN:0x%02x, SIZE:0x%02x, CRC:0x%02x%s' + % (self.miso_bytes[0], self.miso_bytes[1], + self.miso_bytes[2], self.miso_bytes[3], miso)]]) + + def decode(self, ss, es, data): + ptype = data[0] + if ptype == 'CS-CHANGE': + self.reset_data() + return + + # Don't care about anything else. + if ptype != 'DATA': + return + mosi, miso = data[1:] + + self.ss, self.es = ss, es + + if len(self.mosi_bytes) == 0: + self.ss_cmd = ss + self.mosi_bytes.append(mosi) + self.miso_bytes.append(miso) + self.es_array.append(es) + + if self.mosi_bytes[0] & 0x80: + if len(self.mosi_bytes) < 4: + return + + self.handle_ack() + self.reset_data() + else: + if len(self.mosi_bytes) < self.options['msgsize']: + return + + self.handle_ctrl() + self.reset_data() diff --git a/libsigrokdecode4DSL/decoders/st25r39xx_spi/__init__.py b/libsigrokdecode4DSL/decoders/st25r39xx_spi/__init__.py new file mode 100644 index 00000000..3803789e --- /dev/null +++ b/libsigrokdecode4DSL/decoders/st25r39xx_spi/__init__.py @@ -0,0 +1,31 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019-2020 Benjamin Vernoux +## +## 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, see . +## + +''' +This decoder stacks on top of the SPI PD and decodes the st25r39xx High performance NFC universal device and EMVCo reader protocol (SPI mode). + +It has been successfully tested with the st25r3916, other chips of this family may or may not be fully supported but not been verified. + +Please note that the SPI interface uses clock polarity 0 and clock phase 1, which is not the default setting. + +Details: +https://www.st.com/resource/en/datasheet/st25r3916.pdf +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/st25r39xx_spi/lists.py b/libsigrokdecode4DSL/decoders/st25r39xx_spi/lists.py new file mode 100644 index 00000000..14297654 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/st25r39xx_spi/lists.py @@ -0,0 +1,231 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019-2020 Benjamin Vernoux +## +## 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, see . +## +## v0.1 - 17 September 2019 B.VERNOUX using ST25R3916 Datasheet DS12484 Rev 1 (January 2019) +## v0.2 - 28 April 2020 B.VERNOUX using ST25R3916 Datasheet DS12484 Rev 2 (December 2019) https://www.st.com/resource/en/datasheet/st25r3916.pdf +## v0.3 - 17 June 2020 B.VERNOUX using ST25R3916 Datasheet DS12484 Rev 3 (04 June 2020) https://www.st.com/resource/en/datasheet/st25r3916.pdf + +## ST25R3916 Datasheet DS12484 Rev 3 (04 June 2020) §4.4 Direct commands +dir_cmd = { +# addr: 'name' +# Set Default + 0xC0: 'SET_DEFAULT', + 0xC1: 'SET_DEFAULT', +# Stop All Activities + 0xC2: 'STOP', + 0xC3: 'STOP', +# Transmit With CRC + 0xC4: 'TXCRC', +# Transmit Without CRC + 0xC5: 'TXNOCRC', +# Transmit REQA + 0xC6: 'TXREQA', +# Transmit WUPA + 0xC7: 'TXWUPA', +# NFC Initial Field ON + 0xC8: 'NFCINITFON', +# NFC Response Field ON + 0xC9: 'NFCRESFON', +# Go to Sense (Idle) + 0xCD: 'GOIDLE', +# Go to Sleep (Halt) + 0xCE: 'GOHALT', +# Mask Receive Data / Stops receivers and RX decoders + 0xD0: 'STOPRX', +# Unmask Receive Data / Starts receivers and RX decoders + 0xD1: 'STARRX', +# Change AM Modulation state + 0xD2: 'SETAMSTATE', +# Measure Amplitude + 0xD3: 'MAMP', +# Reset RX Gain + 0xD5: 'RSTRXGAIN', +# Adjust Regulators + 0xD6: 'ADJREG', +# Calibrate Driver Timing + 0xD8: 'CALDRVTIM', +# Measure Phase + 0xD9: 'MPHASE', +# Clear RSSI + 0xDA: 'CLRRSSI', +# Clear FIFO + 0xDB: 'CLRFIFO', +# Enter Transparent Mode + 0xDC: 'TRMODE', +# Calibrate Capacitive Sensor + 0xDD: 'CALCAPA', +# Measure Capacitance + 0xDE: 'MCAPA', +# Measure Power Supply + 0xDF: 'MPOWER', +# Start General Purpose Timer + 0xE0: 'STARGPTIM', +# Start Wake-up Timer + 0xE1: 'STARWTIM', +# Start Mask-receive Timer + 0xE2: 'STARMSKTIM', +# Start No-response Timer + 0xE3: 'STARNRESPTIM', +# Start PPON2 Timer + 0xE4: 'STARPPON2TIM', +# Stop No-response Timer + 0xE8: 'STOPNRESTIM', +# RFU / Not Used + 0xFA: 'RFU', +# Register Space-B Access + 0xFB: 'REGSPACEB', +# Register Test access + 0xFC: 'TESTACCESS' +# Other codes => RFU / Not Used +} + +## ST25R3916 Datasheet DS12484 Rev 2 (December 2019) §4.5 Registers Table 17. List of registers - Space A +## ST25R3916 Datasheet DS12484 Rev 2 (December 2019) §4.3.3 Serial peripheral interface (SPI) Table 11. SPI operation modes +regsSpaceA = { +# addr: 'name' +# §4.5 Registers Table 17. List of registers - Space A +# IO configuration + 0x00: 'IOCFG1', + 0x01: 'IOCFG2', +# Operation control and mode definition + 0x02: 'OPCTRL', + 0x03: 'MODEDEF', + 0x04: 'BITRATE', +# Protocol configuration + 0x05: 'TYPEA', + 0x06: 'TYPEB', + 0x07: 'TYPEBF', + 0x08: 'NFCIP1', + 0x09: 'STREAM', + 0x0A: 'AUX', +# Receiver configuration + 0x0B: 'RXCFG1', + 0x0C: 'RXCFG2', + 0x0D: 'RXCFG3', + 0x0E: 'RXCFG4', +# Timer definition + 0x0F: 'MSKRXTIM', + 0x10: 'NRESPTIM1', + 0x11: 'NRESPTIM2', + 0x12: 'TIMEMV', + 0x13: 'GPTIM1', + 0x14: 'GPTIM2', + 0x15: 'PPON2', +# Interrupt and associated reporting + 0x16: 'MSKMAINIRQ', + 0x17: 'MSKTIMNFCIRQ', + 0x18: 'MSKERRWAKEIRQ', + 0x19: 'TARGIRQ', + 0x1A: 'MAINIRQ', + 0x1B: 'TIMNFCIRQ', + 0x1C: 'ERRWAKEIRQ', + 0x1D: 'TARGIRQ', + 0x1E: 'FIFOSTAT1', + 0x1F: 'FIFOSTAT2', + 0x20: 'COLLDISP', + 0x21: 'TARGDISP', +# Definition of number of transmitted bytes + 0x22: 'NBTXB1', + 0x23: 'NBTXB2', + 0x24: 'BITRATEDET', +# A/D converter output + 0x25: 'ADCONVOUT', +# Antenna calibration + 0x26: 'ANTTUNECTRL1', + 0x27: 'ANTTUNECTRL2', +# Antenna driver and modulation + 0x28: 'TXDRV', + 0x29: 'TARGMOD', +# External field detector threshold + 0x2A: 'EXTFIELDON', + 0x2B: 'EXTFIELDOFF', +# Regulator + 0x2C: 'REGVDDCTRL', +# Receiver state display + 0x2D: 'RSSIDISP', + 0x2E: 'GAINSTATE', +# Capacitive sensor + 0x2F: 'CAPACTRL', + 0x30: 'CAPADISP', +# Auxiliary display + 0x31: 'AUXDISP', +# Wake-up + 0x32: 'WAKETIMCTRL', + 0x33: 'AMPCFG', + 0x34: 'AMPREF', + 0x35: 'AMPAAVGDISP', + 0x36: 'AMPDISP', + 0x37: 'PHASECFG', + 0x38: 'PHASEREF', + 0x39: 'PHASEAAVGDISP', + 0x3A: 'PHASEDISP', + 0x3B: 'CAPACFG', + 0x3C: 'CAPAREF', + 0x3D: 'CAPAAAVGDISP', + 0x3E: 'CAPADISP', +# IC identity + 0x3F: 'ICIDENT', +## ST25R3916 Datasheet DS12484 Rev 2 (December 2019) §4.3.3 Serial peripheral interface (SPI) Table 11. SPI operation modes + 0xA0: 'PT_memLoadA', + 0xA8: 'PT_memLoadF', + 0xAC: 'PT_memLoadTSN', + 0xBF: 'PT_memRead' +} + +## ST25R3916 Datasheet DS12484 Rev 2 (December 2019) §4.5 Registers Table 18. List of registers - Space B +regsSpaceB = { +# addr: 'name' +# §4.5 Registers Table 18. List of registers - Space B +# Protocol configuration + 0x05: 'EMDSUPPRCONF', + 0x06: 'SUBCSTARTIM', +# Receiver configuration + 0x0B: 'P2PRXCONF', + 0x0C: 'CORRCONF1', + 0x0D: 'CORRCONF2', +# Timer definition + 0x0F: 'SQUELSHTIM', + 0x15: 'NFCGUARDTIM', +# Antenna driver and modulation + 0x28: 'AUXMODSET', + 0x29: 'TXDRVTIM', +# External field detector threshold + 0x2A: 'RESAMMODE', + 0x2B: 'TXDRVTIMDISP', +# Regulator + 0x2C: 'REGDISP', +# Protection + 0x30: 'OSHOOTCONF1', + 0x31: 'OSHOOTCONF2', + 0x32: 'USHOOTCONF1', + 0x33: 'USHOOTCONF2' +} + +## ST25R3916 Datasheet DS12484 Rev 2 (December 2019) §4.4.17 Test access +regsTest = { +# addr: 'name' +# §4.4.17 Test access (Typo in datasheet it is not register 0x00 but 0x01) + 0x01: 'ANTSTOBS' +} + +## Optional TODO add important status bit fields / ANN_STATUS +## Interrupt and associated reporting => Registers Space A from Address (hex) 0x16 to 0x21 +## §4.5.58 RSSI display register +## §4.5.59 Gain reduction state register +## ... + diff --git a/libsigrokdecode4DSL/decoders/st25r39xx_spi/pd.py b/libsigrokdecode4DSL/decoders/st25r39xx_spi/pd.py new file mode 100644 index 00000000..1b0df073 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/st25r39xx_spi/pd.py @@ -0,0 +1,350 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019-2020 Benjamin Vernoux +## +## 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, see . +## + +import sigrokdecode as srd +from collections import namedtuple +from common.srdhelper import SrdIntEnum +from .lists import * + +Ann = SrdIntEnum.from_str('Ann', 'BURST_READ BURST_WRITE \ + BURST_READB BURST_WRITEB BURST_READT BURST_WRITET \ + DIRECTCMD FIFO_WRITE FIFO_READ STATUS WARN') + +Pos = namedtuple('Pos', ['ss', 'es']) +Data = namedtuple('Data', ['mosi', 'miso']) + +class Decoder(srd.Decoder): + api_version = 3 + id = 'st25r39xx_spi' + name = 'ST25R39xx (SPI mode)' + longname = 'STMicroelectronics ST25R39xx' + desc = 'High performance NFC universal device and EMVCo reader protocol.' + license = 'gplv2+' + inputs = ['spi'] + outputs = [] + tags = ['IC', 'Wireless/RF'] + annotations = ( + ('Read', 'Burst register read'), + ('Write', 'Burst register write'), + ('ReadB', 'Burst register SpaceB read'), + ('WriteB', 'Burst register SpaceB write'), + ('ReadT', 'Burst register Test read'), + ('WriteT', 'Burst register Test write'), + ('Cmd', 'Direct command'), + ('FIFOW', 'FIFO write'), + ('FIFOR', 'FIFO read'), + ('status_reg', 'Status register'), + ('warning', 'Warning'), + ) + annotation_rows = ( + ('regs', 'Regs', (Ann.prefixes('BURST_'))), + ('cmds', 'Commands', (Ann.DIRECTCMD,)), + ('data', 'Data', (Ann.prefixes('FIFO_'))), + ('status', 'Status register', (Ann.STATUS,)), + ('warnings', 'Warnings', (Ann.WARN,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.next() + self.requirements_met = True + self.cs_was_released = False + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def warn(self, pos, msg): + '''Put a warning message 'msg' at 'pos'.''' + self.put(pos.ss, pos.es, self.out_ann, [Ann.WARN, [msg]]) + + def putp(self, pos, ann, msg): + '''Put an annotation message 'msg' at 'pos'.''' + self.put(pos.ss, pos.es, self.out_ann, [ann, [msg]]) + + def putp2(self, pos, ann, msg1, msg2): + '''Put an annotation message 'msg' at 'pos'.''' + self.put(pos.ss, pos.es, self.out_ann, [ann, [msg1, msg2]]) + + def next(self): + '''Resets the decoder after a complete command was decoded.''' + # 'True' for the first byte after CS# went low. + self.first = True + + # The current command, and the minimum and maximum number + # of data bytes to follow. + self.cmd = None + self.min = 0 + self.max = 0 + + # Used to collect the bytes after the command byte + # (and the start/end sample number). + self.mb = [] + self.ss_mb = -1 + self.es_mb = -1 + + def mosi_bytes(self): + '''Returns the collected MOSI bytes of a multi byte command.''' + return [b.mosi for b in self.mb] + + def miso_bytes(self): + '''Returns the collected MISO bytes of a multi byte command.''' + return [b.miso for b in self.mb] + + def decode_command(self, pos, b): + '''Decodes the command byte 'b' at position 'pos' and prepares + the decoding of the following data bytes.''' + c = self.parse_command(b) + if c is None: + self.warn(pos, 'Unknown command') + return + + self.cmd, self.dat, self.min, self.max = c + + if self.cmd == 'Cmd': + self.putp(pos, Ann.DIRECTCMD, self.format_command()) + else: + # Don't output anything now, the command is merged with + # the data bytes following it. + self.ss_mb = pos.ss + + def format_command(self): + '''Returns the label for the current command.''' + if self.cmd in ('Write', 'Read', 'WriteB', 'ReadB', 'WriteT', 'ReadT', 'FIFO Write', 'FIFO Read'): + return self.cmd + if self.cmd == 'Cmd': + reg = dir_cmd.get(self.dat, 'Unknown direct command') + return '{} {}'.format(self.cmd, reg) + else: + return 'TODO Cmd {}'.format(self.cmd) + + def parse_command(self, b): + '''Parses the command byte. + Returns a tuple consisting of: + - the name of the command + - additional data needed to dissect the following bytes + - minimum number of following bytes + - maximum number of following bytes (None for infinite) + ''' + addr = b & 0x3F + # previous command was 'Space B' + if self.cmd == 'Space B': + if (b & 0xC0) == 0x00: + return ('WriteB', addr, 1, 99999) + if (b & 0xC0) == 0x40: + return ('ReadB', addr, 1, 99999) + else: + self.warn(pos, 'Unknown address/command combination') + # previous command was 'TestAccess' + elif self.cmd == 'TestAccess': + if (b & 0xC0) == 0x00: + return ('WriteT', addr, 1, 99999) + if (b & 0xC0) == 0x40: + return ('ReadT', addr, 1, 99999) + else: + self.warn(pos, 'Unknown address/command combination') + else: + # Space A regs or other operation modes (except Space B) + # Register Write 0b00xxxxxx 0x00 to 0x3F => 'Write' + # Register Read 0b01xxxxxx 0x40 to 0x7F => 'Read' + if (b <= 0x7F): + if (b & 0xC0) == 0x00: + return ('Write', addr, 1, 99999) + if (b & 0xC0) == 0x40: + return ('Read', addr, 1, 99999) + else: + self.warn(pos, 'Unknown address/command combination') + else: + # FIFO Load 0b10000000 0x80 => 'FIFO Write' + # PT_memory loadA-config 0b10100000 0xA0 => 'Write' + # PT_memory loadF-config 0b10101000 0xA8 => 'Write' + # PT_memory loadTSN data 0b10101100 0xAC => 'Write' + # PT_memory Read 0b10111111 0xBF => 'Read' + # FIFO Read 0b10011111 0x9F => 'FIFO Read' + # Direct Command 0b11xxx1xx 0xC0 to 0xE8 => 'Cmd' + # Register Space-B Access 0b11111011 0xFB => 'Space B' + # Register Test Access 0b11111100 0xFC => 'TestAccess' + if b == 0x80: + return ('FIFO Write', b, 1, 99999) + if b == 0xA0: + return ('Write', b, 1, 99999) + if b == 0xA8: + return ('Write', b, 1, 99999) + if b == 0xAC: + return ('Write', b, 1, 99999) + if b == 0xBF: + return ('Read', b, 1, 99999) + if b == 0x9F: + return ('FIFO Read', b, 1, 99999) + if (b >= 0x0C and b <= 0xE8) : + return ('Cmd', b, 0, 0) + if b == 0xFB: + return ('Space B', b, 0, 0) + if b == 0xFC: + return ('TestAccess', b, 0, 0) + else: + self.warn(pos, 'Unknown address/command combination') + + def decode_reg(self, pos, ann, regid, data): + '''Decodes a register. + pos -- start and end sample numbers of the register + ann -- the annotation number that is used to output the register. + regid -- may be either an integer used as a key for the 'regs' + dictionary, or a string directly containing a register name.' + data -- the register content. + ''' + if type(regid) == int: + if (ann == Ann.FIFO_READ) or (ann == Ann.FIFO_WRITE): + name = '' + elif (ann == Ann.BURST_READB) or (ann == Ann.BURST_WRITEB): + # Get the name of the register. + if regid not in regsSpaceB: + self.warn(pos, 'Unknown register SpaceB') + return + name = '{} ({:02X})'.format(regsSpaceB[regid], regid) + elif (ann == Ann.BURST_READT) or (ann == Ann.BURST_WRITET): + # Get the name of the register. + if regid not in regsTest: + self.warn(pos, 'Unknown register Test') + return + name = '{} ({:02X})'.format(regsTest[regid], regid) + else: + # Get the name of the register. + if regid not in regsSpaceA: + self.warn(pos, 'Unknown register SpaceA') + return + name = '{} ({:02X})'.format(regsSpaceA[regid], regid) + else: + name = regid + + if regid == 'STATUS' and ann == Ann.STATUS: + label = 'Status' + self.decode_status_reg(pos, ann, data, label) + else: + label = '{}: {}'.format(self.format_command(), name) + self.decode_mb_data(pos, ann, data, label) + + def decode_status_reg(self, pos, ann, data, label): + '''Decodes the data bytes 'data' of a status register at position + 'pos'. The decoded data is prefixed with 'label'.''' + + def decode_mb_data(self, pos, ann, data, label): + '''Decodes the data bytes 'data' of a multibyte command at position + 'pos'. The decoded data is prefixed with 'label'.''' + + def escape(b): + return '{:02X}'.format(b) + + data = ' '.join([escape(b) for b in data]) + if (ann == Ann.FIFO_WRITE) or (ann == Ann.FIFO_READ): + text = '{}{}'.format(label, data) + else: + text = '{} = {}'.format(label, data) + self.putp(pos, ann, text) + + def finish_command(self, pos): + '''Decodes the remaining data bytes at position 'pos'.''' + if self.cmd == 'Write': + self.decode_reg(pos, Ann.BURST_WRITE, self.dat, self.mosi_bytes()) + elif self.cmd == 'Read': + self.decode_reg(pos, Ann.BURST_READ, self.dat, self.miso_bytes()) + elif self.cmd == 'WriteB': + self.decode_reg(pos, Ann.BURST_WRITEB, self.dat, self.mosi_bytes()) + elif self.cmd == 'ReadB': + self.decode_reg(pos, Ann.BURST_READB, self.dat, self.miso_bytes()) + elif self.cmd == 'WriteT': + self.decode_reg(pos, Ann.BURST_WRITET, self.dat, self.mosi_bytes()) + elif self.cmd == 'ReadT': + self.decode_reg(pos, Ann.BURST_READT, self.dat, self.miso_bytes()) + elif self.cmd == 'FIFO Write': + self.decode_reg(pos, Ann.FIFO_WRITE, self.dat, self.mosi_bytes()) + elif self.cmd == 'FIFO Read': + self.decode_reg(pos, Ann.FIFO_READ, self.dat, self.miso_bytes()) + elif self.cmd == 'Cmd': + self.decode_reg(pos, Ann.DIRECTCMD, self.dat, self.mosi_bytes()) + else: + self.warn(pos, 'Unhandled command {}'.format(self.cmd)) + + def decode(self, ss, es, data): + if not self.requirements_met: + return + + ptype, data1, data2 = data + + if ptype == 'CS-CHANGE': + if data1 is None: + if data2 is None: + self.requirements_met = False + raise ChannelError('CS# pin required.') + elif data2 == 1: + self.cs_was_released = True + + if data1 == 0 and data2 == 1: + # Rising edge, the complete command is transmitted, process + # the bytes that were sent after the command byte. + if self.cmd: + # Check if we got the minimum number of data bytes + # after the command byte. + if len(self.mb) < self.min: + self.warn((ss, ss), 'Missing data bytes') + elif self.mb: + self.finish_command(Pos(self.ss_mb, self.es_mb)) + + self.next() + self.cs_was_released = True + + elif ptype == 'DATA' and self.cs_was_released: + mosi, miso = data1, data2 + pos = Pos(ss, es) + + if miso is None or mosi is None: + self.requirements_met = False + raise ChannelError('Both MISO and MOSI pins are required.') + + if self.first: + # Register Space-B Access 0b11111011 0xFB => 'Space B' + if mosi == 0xFB: + self.first = True + # First MOSI byte 'Space B' command. + self.decode_command(pos, mosi) + # First MISO byte is always the status register. + #self.decode_reg(pos, ANN_STATUS, 'STATUS', [miso]) + # Register TestAccess Access 0b11111100 0xFC => 'TestAccess' + elif mosi == 0xFC: + self.first = True + # First MOSI byte 'TestAccess' command. + self.decode_command(pos, mosi) + # First MISO byte is always the status register. + #self.decode_reg(pos, ANN_STATUS, 'STATUS', [miso]) + else: + self.first = False + # First MOSI byte is always the command. + self.decode_command(pos, mosi) + # First MISO byte is always the status register. + #self.decode_reg(pos, ANN_STATUS, 'STATUS', [miso]) + else: + if not self.cmd or len(self.mb) >= self.max: + self.warn(pos, 'Excess byte') + else: + # Collect the bytes after the command byte. + if self.ss_mb == -1: + self.ss_mb = ss + self.es_mb = es + self.mb.append(Data(mosi, miso)) diff --git a/libsigrokdecode4DSL/decoders/st7735/__init__.py b/libsigrokdecode4DSL/decoders/st7735/__init__.py new file mode 100644 index 00000000..771578c6 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/st7735/__init__.py @@ -0,0 +1,27 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Aleksander Alekseev +## +## 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, see . +## + +''' +This decoder decodes the Sitronix ST7735 TFT controller protocol. + +Details: +http://www.displayfuture.com/Display/datasheet/controller/ST7735.pdf +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/st7735/pd.py b/libsigrokdecode4DSL/decoders/st7735/pd.py new file mode 100644 index 00000000..252b1887 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/st7735/pd.py @@ -0,0 +1,173 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Aleksander Alekseev +## +## 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, see . + +import sigrokdecode as srd + +MAX_DATA_LEN = 128 + +# Command ID -> name, short description +META = { + 0x00: {'name': 'NOP ', 'desc': 'No operation'}, + 0x01: {'name': 'SWRESET', 'desc': 'Software reset'}, + 0x04: {'name': 'RDDID ', 'desc': 'Read display ID'}, + 0x09: {'name': 'RDDST ', 'desc': 'Read display status'}, + 0x10: {'name': 'SLPIN ', 'desc': 'Sleep in & booster off'}, + 0x11: {'name': 'SLPOUT ', 'desc': 'Sleep out & booster on'}, + 0x12: {'name': 'PTLON ', 'desc': 'Partial mode on'}, + 0x13: {'name': 'NORON ', 'desc': 'Partial off (normal)'}, + 0x20: {'name': 'INVOFF ', 'desc': 'Display inversion off'}, + 0x21: {'name': 'INVON ', 'desc': 'Display inversion on'}, + 0x28: {'name': 'DISPOFF', 'desc': 'Display off'}, + 0x29: {'name': 'DISPON ', 'desc': 'Display on'}, + 0x2A: {'name': 'CASET ', 'desc': 'Column address set'}, + 0x2B: {'name': 'RASET ', 'desc': 'Row address set'}, + 0x2C: {'name': 'RAMWR ', 'desc': 'Memory write'}, + 0x2E: {'name': 'RAMRD ', 'desc': 'Memory read'}, + 0x30: {'name': 'PTLAR ', 'desc': 'Partial start/end address set'}, + 0x36: {'name': 'MADCTL ', 'desc': 'Memory data address control'}, + 0x3A: {'name': 'COLMOD ', 'desc': 'Interface pixel format'}, + 0xB1: {'name': 'FRMCTR1', 'desc': 'Frame rate control (in normal mode / full colors)'}, + 0xB2: {'name': 'FRMCTR2', 'desc': 'Frame rate control (in idle mode / 8-colors)'}, + 0xB3: {'name': 'FRMCTR3', 'desc': 'Frame rate control (in partial mode / full colors) '}, + 0xB4: {'name': 'INVCTR ', 'desc': 'Display inversion control'}, + 0xB6: {'name': 'DISSET5', 'desc': 'Display function set 5'}, + 0xC0: {'name': 'PWCTR1 ', 'desc': 'Power control 1'}, + 0xC1: {'name': 'PWCTR2 ', 'desc': 'Power control 2'}, + 0xC2: {'name': 'PWCTR3 ', 'desc': 'Power control 3'}, + 0xC3: {'name': 'PWCTR4 ', 'desc': 'Power control 4'}, + 0xC4: {'name': 'PWCTR5 ', 'desc': 'Power control 5'}, + 0xC5: {'name': 'VMCTR1 ', 'desc': 'VCOM control 1'}, + 0xDA: {'name': 'RDID1 ', 'desc': 'Read ID1'}, + 0xDB: {'name': 'RDID2 ', 'desc': 'Read ID2'}, + 0xDC: {'name': 'RDID3 ', 'desc': 'Read ID3'}, + 0xDD: {'name': 'RDID4 ', 'desc': 'Read ID4'}, + 0xFC: {'name': 'PWCTR6 ', 'desc': 'Power control 6'}, + 0xE0: {'name': 'GMCTRP1', 'desc': 'Gamma \'+\'polarity correction characteristics setting'}, + 0xE1: {'name': 'GMCTRN1', 'desc': 'Gamma \'-\'polarity correction characteristics setting'}, +} + +class Ann: + BITS, CMD, DATA, DESC = range(4) + +class Decoder(srd.Decoder): + api_version = 3 + id = 'st7735' + name = 'ST7735' + longname = 'Sitronix ST7735' + desc = 'Sitronix ST7735 TFT controller protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Display', 'IC'] + channels = ( + {'id': 'cs', 'name': 'CS#', 'desc': 'Chip-select'}, + {'id': 'clk', 'name': 'CLK', 'desc': 'Clock'}, + {'id': 'mosi', 'name': 'MOSI', 'desc': 'Master out, slave in'}, + {'id': 'dc', 'name': 'DC', 'desc': 'Data or command'} + ) + annotations = ( + ('bit', 'Bit'), + ('command', 'Command'), + ('data', 'Data'), + ('description', 'Description'), + ) + annotation_rows = ( + ('bits', 'Bits', (Ann.BITS,)), + ('fields', 'Fields', (Ann.CMD, Ann.DATA)), + ('description', 'Description', (Ann.DESC,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.accum_byte = 0 + self.accum_bits_num = 0 + self.bit_ss = -1 + self.byte_ss = -1 + self.current_bit = -1 + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def put_desc(self, ss, es, cmd, data): + if cmd == -1: + return + if META[cmd]: + self.put(ss, es, self.out_ann, [Ann.DESC, + ['%s: %s' % (META[cmd]['name'].strip(), META[cmd]['desc'])]]) + else: + # Default description: + dots = '' + if len(data) == MAX_DATA_LEN: + data = data[:-1] + dots = '...' + data_str = '(none)' + if len(data) > 0: + data_str = ' '.join(['%02X' % b for b in data]) + self.put(ss, es, self.out_ann, [Ann.DESC, + ['Unknown command: %02X. Data: %s%s' % (cmd, data_str, dots)]]) + + def decode(self): + current_cmd = -1 + current_data = [] + desc_ss = -1 + desc_es = -1 + self.reset() + while True: + # Check data on both CLK edges. + (cs, clk, mosi, dc) = self.wait({1: 'e'}) + + if cs == 1: # Wait for CS = low, ignore the rest. + self.reset() + continue + + if clk == 1: + # Read one bit. + self.bit_ss = self.samplenum + if self.accum_bits_num == 0: + self.byte_ss = self.samplenum + self.current_bit = mosi + + if (clk == 0) and (self.current_bit >= 0): + # Process one bit. + self.put(self.bit_ss, self.samplenum, self.out_ann, + [Ann.BITS, [str(self.current_bit)]]) + self.accum_byte = (self.accum_byte << 1) | self.current_bit # MSB-first. + self.accum_bits_num += 1 + if self.accum_bits_num == 8: + # Process one byte. + ann = Ann.DATA if dc else Ann.CMD # DC = low for commands. + self.put(self.byte_ss, self.samplenum, self.out_ann, + [ann, ['%02X' % self.accum_byte]]) + if ann == Ann.CMD: + self.put_desc(desc_ss, desc_es, current_cmd, current_data) + desc_ss = self.byte_ss + desc_es = self.samplenum # For cmds without data. + current_cmd = self.accum_byte + current_data = [] + else: + if len(current_data) < MAX_DATA_LEN: + current_data += [self.accum_byte] + desc_es = self.samplenum + + self.accum_bits_num = 0 + self.accum_byte = 0 + self.byte_ss = -1 + self.current_bit = -1 + self.bit_ss = -1 diff --git a/libsigrokdecode4DSL/decoders/st7789/__init__.py b/libsigrokdecode4DSL/decoders/st7789/__init__.py new file mode 100644 index 00000000..5a57c5be --- /dev/null +++ b/libsigrokdecode4DSL/decoders/st7789/__init__.py @@ -0,0 +1,7 @@ +""" +This decoder decodes the Sitronix ST7789 TFT controller protocol. + +Details: https://www.newhavendisplay.com/appnotes/datasheets/LCDs/ST7789V.pdf +""" + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/st7789/pd.py b/libsigrokdecode4DSL/decoders/st7789/pd.py new file mode 100644 index 00000000..b8141ac7 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/st7789/pd.py @@ -0,0 +1,296 @@ +import sigrokdecode as srd + +COMMAND_MAP = { + 0x00: {"name": "NOP", "desc": "Empty command",}, + 0x01: {"name": "SWRESET", "desc": "Software Reset",}, + 0x04: {"name": "RDDID", "desc": "Read Display ID",}, + 0x09: {"name": "RDDST", "desc": "Read Display Status",}, + 0x0A: {"name": "RDDPM", "desc": "Read Display Power Mode",}, + 0x0B: {"name": "RDDMADCTL", "desc": "Read Display MADCTL",}, + 0x0C: {"name": "RDDCOLMOD", "desc": "Read Display Pixel Format",}, + 0x0D: {"name": "RDDIM", "desc": "Read Display Image Mode",}, + 0x0E: {"name": "RDDSM", "desc": "Read Display Signal Mode",}, + 0x0F: {"name": "RDDSDR", "desc": "Read Display Self-Diagnostic Result",}, + 0x10: {"name": "SLPIN", "desc": "Sleep in",}, + 0x11: {"name": "SLPOUT", "desc": "Sleep Out",}, + 0x12: {"name": "PTLON", "desc": "Partial Display Mode On",}, + 0x13: {"name": "NORON", "desc": "Normal Display Mode On",}, + 0x20: {"name": "INVOFF", "desc": "Display Inversion Off",}, + 0x21: {"name": "INVON", "desc": "Display Inversion On",}, + 0x26: {"name": "GAMSET", "desc": "Gamma Set",}, + 0x28: {"name": "DISPOFF", "desc": "Display Off",}, + 0x29: {"name": "DISPON", "desc": "Display On",}, + 0x2A: {"name": "CASET", "desc": "Column Address Set",}, + 0x2B: {"name": "RASET", "desc": "Row Address Set",}, + 0x2C: {"name": "RAMWR", "desc": "Memory Write",}, + 0x2E: {"name": "RAMRD", "desc": "Memory Read",}, + 0x30: {"name": "PTLAR", "desc": "Partial Area",}, + 0x33: {"name": "VSCRDEF", "desc": "Vertical Scrolling Definition",}, + 0x34: {"name": "TEOFF", "desc": "Tearing Effect Line OFF",}, + 0x35: {"name": "TEON", "desc": "Tearing Effect Line On",}, + 0x36: {"name": "MADCTL", "desc": "Memory Data Access Control",}, + 0x37: {"name": "VSCSAD", "desc": "Vertical Scroll Start Address of RAM",}, + 0x38: {"name": "IDMOFF", "desc": "Idle Mode Off",}, + 0x39: {"name": "IDMON", "desc": "Idle mode on",}, + 0x3A: {"name": "COLMOD", "desc": "Interface Pixel Format",}, + 0x3C: {"name": "WRMEMC", "desc": "Write Memory Continue",}, + 0x3E: {"name": "RDMEMC", "desc": "Read Memory Continue",}, + 0x44: {"name": "STE", "desc": "Set Tear Scanline",}, + 0x45: {"name": "GSCAN", "desc": "Get Scanline",}, + 0x51: {"name": "WRDISBV", "desc": "Write Display Brightness",}, + 0x52: {"name": "RDDISBV", "desc": "Read Display Brightness Value",}, + 0x53: {"name": "WRCTRLD", "desc": "Write CTRL Display",}, + 0x54: {"name": "RDCTRLD", "desc": "Read CTRL Value Display",}, + 0x55: { + "name": "WRCACE", + "desc": "Write Content Adaptive Brightness Control and Color Enhancement", + }, + 0x56: {"name": "RDCABC", "desc": "Read Content Adaptive Brightness Control",}, + 0x5E: {"name": "WRCABCMB", "desc": "Write CABC Minimum Brightness",}, + 0x5F: {"name": "RDCABCMB", "desc": "Read CABC Minimum Brightness",}, + 0x68: { + "name": "RDABCSDR", + "desc": "Read Automatic Brightness Control Self-Diagnostic Result", + }, + 0xDA: {"name": "RDID1", "desc": "Read ID1",}, + 0xDB: {"name": "RDID2", "desc": "Read ID2",}, + 0xDC: {"name": "RDID3", "desc": "Read ID3",}, + 0xB0: {"name": "RAMCTRL", "desc": "RAM Control",}, + 0xB1: {"name": "RGBCTRL", "desc": "RGB Interface Control",}, + 0xB2: {"name": "PORCTRL", "desc": "Porch Setting",}, + 0xB3: { + "name": "FRCTRL1", + "desc": "Frame Rate Control 1 (In partial mode/ idle colors)", + }, + 0xB5: {"name": "PARCTRL", "desc": "Partial mode Control",}, + 0xB7: {"name": "GCTRL", "desc": "Gate Control",}, + 0xB8: {"name": "GTADJ", "desc": "Gate On Timing Adjustment",}, + 0xBA: {"name": "DGMEN", "desc": "Digital Gamma Enable",}, + 0xBB: {"name": "VCOMS", "desc": "VCOMS Setting",}, + 0xC0: {"name": "LCMCTRL", "desc": "LCM Control",}, + 0xC1: {"name": "IDSET", "desc": "ID Code Setting",}, + 0xC2: {"name": "VDVVRHEN", "desc": "VDV and VRH Command Enable",}, + 0xC3: {"name": "VRHS", "desc": "VRH Set",}, + 0xC4: {"name": "VDVS", "desc": "VDV Set",}, + 0xC5: {"name": "VCMOFSET", "desc": "VCOMS Offset Set",}, + 0xC6: {"name": "FRCTRL2", "desc": "Frame Rate Control in Normal Mode",}, + 0xC7: {"name": "CABCCTRL", "desc": "CABC Control",}, + 0xC8: {"name": "REGSEL1", "desc": "Register Value Selection 1",}, + 0xCA: {"name": "REGSEL2", "desc": "Register Value Selection 2",}, + 0xCC: {"name": "PWMFRSEL", "desc": "PWM Frequency Selection",}, + 0xD0: {"name": "PWCTRL1", "desc": "Power Control 1",}, + 0xD2: {"name": "VAPVANEN", "desc": "Enable VAP/VAN signal output",}, + 0xDF: {"name": "CMD2EN", "desc": "Command 2 Enable",}, + 0xE0: {"name": "PVGAMCTRL", "desc": "Positive Voltage Gamma Control",}, + 0xE1: {"name": "NVGAMCTRL", "desc": "Negative Voltage Gamma Control",}, + 0xE2: {"name": "DGMLUTR", "desc": "Digital Gamma Look-up Table for Red",}, + 0xE3: {"name": "DGMLUTB", "desc": "Digital Gamma Look-up Table for Blue",}, + 0xE4: {"name": "GATECTRL", "desc": "Gate Control",}, + 0xE7: {"name": "SPI2EN", "desc": "SPI2 Enable",}, + 0xE8: {"name": "PWCTRL2", "desc": "Power Control 2",}, + 0xE9: {"name": "EQCTRL", "desc": "Equalize time control",}, + 0xEC: {"name": "PROMCTRL", "desc": "Program Mode Control",}, + 0xFA: {"name": "PROMEN", "desc": "Program Mode Enable",}, + 0xFC: {"name": "NVMSET", "desc": "NVM Setting",}, + 0xFE: {"name": "PROMACT", "desc": "Program action",}, +} + + +def _get_annotation_index(annotations, name): + for index, annotation in enumerate(annotations): + if annotation[0] == name: + return index + raise RuntimeError(f"Unknown annotation {repr(name)}: {repr(annotations)}") + + +class Decoder(srd.Decoder): + api_version = 3 + id = "st7789" + name = "ST7789" + longname = "Sitronix ST7789" + desc = "Sitronix ST7789 TFT controller protocol." + license = "gplv2+" + inputs = ["logic"] + outputs = [] + channels = ( + {"id": "csx", "name": "CSX", "desc": "Chip selection signal"}, + {"id": "dcx", "name": "DCX", "desc": "Clock signal"}, + {"id": "sdo", "name": "SDO", "desc": "Serial output data"}, + {"id": "wrx", "name": "WRX", "desc": "Command / data"}, + ) + optional_channels = tuple() + tags = ["Display", "SPI"] + annotations = ( + ("bit", "Bit"), + ("command", "Command"), + ("data", "Data"), + ("cmd_data", "Command + Data"), + ("asserted", "Assertion"), + ) + + annotation_rows = ( + ("bits", "Bits", (_get_annotation_index(annotations, "bit"),)), + ( + "bytes", + "Bytes", + ( + _get_annotation_index(annotations, "command"), + _get_annotation_index(annotations, "data"), + ), + ), + ( + "cmd_data", + "Command + Data", + (_get_annotation_index(annotations, "cmd_data"),), + ), + ("asserted", "Assertion", (_get_annotation_index(annotations, "asserted"),)), + ) + + def _get_channel_index(self, name): + for index, channel in enumerate(self.channels): + if channel["name"] == name: + return index + raise RuntimeError("Implementation bug.") + + def __init__(self): + self.reset() + + def reset(self): + pass + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def _get_cmd_str(self, cmd): + if cmd in COMMAND_MAP: + return COMMAND_MAP[cmd]["name"] + "(%02X)" % cmd + else: + return "Unknown(%02X)" % cmd + + def _get_cmd_data_str(self, cmd, data_list): + cmd_str = self._get_cmd_str(cmd) + + if data_list: + ret_str = f"{cmd_str}: " + for v in data_list: + ret_str += " %02X" % v + return ret_str + else: + return cmd_str + + def decode(self): + last_cmd = None + last_cmd_data_sample_startnum = None + last_cmd_data_sample_endnum = None + last_cmd_data_list = [] + + while True: + self.wait({self._get_channel_index("CSX"): "f"}) + csx_start_samplenum = self.samplenum + + bit = None + bit_count = 0 + byte = 0 + byte_sample_startnum = None + + while True: + # FIXME {self._get_channel_index("DCX"): "r"} + (csx, dcx, sdo, wrx) = self.wait( + [ + {self._get_channel_index("CSX"): "r"}, + {self._get_channel_index("DCX"): "e"}, + ] + ) + if csx == 1: + self.put( + csx_start_samplenum, + self.samplenum, + self.out_ann, + [ + _get_annotation_index(self.annotations, "asserted"), + ["Asserted"], + ], + ) + + if last_cmd is not None: + self.put( + last_cmd_data_sample_startnum, + last_cmd_data_sample_endnum, + self.out_ann, + [ + _get_annotation_index(self.annotations, "cmd_data"), + [self._get_cmd_data_str(last_cmd, last_cmd_data_list)], + ], + ) + last_cmd = None + last_cmd_data_sample_startnum = None + last_cmd_data_sample_endnum = None + last_cmd_data_list = [] + + break + + if dcx == 1 and bit is None: + bit = sdo + bit_start_samplenum = self.samplenum + bit_count += 1 + byte = (byte << 1) | bit + if byte_sample_startnum is None: + byte_sample_startnum = self.samplenum + + if dcx == 0 and bit is not None: + self.put( + bit_start_samplenum, + self.samplenum, + self.out_ann, + [_get_annotation_index(self.annotations, "bit"), [str(bit)]], + ) + bit = None + if bit_count == 8: + if wrx: + last_cmd_data_sample_endnum = self.samplenum + last_cmd_data_list.append(byte) + self.put( + byte_sample_startnum, + self.samplenum, + self.out_ann, + [ + _get_annotation_index(self.annotations, "data"), + ["Data(%02X)" % byte], + ], + ) + else: + self.put( + byte_sample_startnum, + self.samplenum, + self.out_ann, + [ + _get_annotation_index(self.annotations, "command"), + [self._get_cmd_str(byte)], + ], + ) + + if last_cmd is not None: + self.put( + last_cmd_data_sample_startnum, + last_cmd_data_sample_endnum, + self.out_ann, + [ + _get_annotation_index( + self.annotations, "cmd_data" + ), + [ + self._get_cmd_data_str( + last_cmd, last_cmd_data_list + ) + ], + ], + ) + last_cmd_data_list = [] + + last_cmd = byte + last_cmd_data_sample_startnum = byte_sample_startnum + last_cmd_data_sample_endnum = self.samplenum + + byte = 0 + bit_count = 0 + byte_sample_startnum = None diff --git a/libsigrokdecode4DSL/decoders/stepper_motor/__init__.py b/libsigrokdecode4DSL/decoders/stepper_motor/__init__.py new file mode 100644 index 00000000..9126104f --- /dev/null +++ b/libsigrokdecode4DSL/decoders/stepper_motor/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Petteri Aimonen +## +## 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, see . +## + +''' +This PD decodes the stepper motor controller signals (step / dir) and +shows the step speed and absolute position of the stepper motor. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/stepper_motor/pd.py b/libsigrokdecode4DSL/decoders/stepper_motor/pd.py new file mode 100644 index 00000000..2a7009a0 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/stepper_motor/pd.py @@ -0,0 +1,95 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Petteri Aimonen +## +## 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, see . +## + +import sigrokdecode as srd + +class Decoder(srd.Decoder): + api_version = 3 + id = 'stepper_motor' + name = 'Stepper motor' + longname = 'Stepper motor position / speed' + desc = 'Absolute position and movement speed from step/dir.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Embedded/industrial'] + channels = ( + {'id': 'step', 'name': 'Step', 'desc': 'Step pulse'}, + {'id': 'dir', 'name': 'Direction', 'desc': 'Direction select'}, + ) + options = ( + {'id': 'unit', 'desc': 'Unit', 'default': 'steps', + 'values': ('steps', 'mm')}, + {'id': 'steps_per_mm', 'desc': 'Steps per mm', 'default': 100.0}, + ) + annotations = ( + ('speed', 'Speed'), + ('position', 'Position') + ) + annotation_rows = ( + ('speed', 'Speed', (0,)), + ('position', 'Position', (1,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.oldstep = None + self.ss_prev_step = None + self.pos = 0 + self.prev_speed = None + self.prev_pos = None + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + if self.options['unit'] == 'steps': + self.scale = 1 + self.format = '%0.0f' + self.unit = 'steps' + else: + self.scale = self.options['steps_per_mm'] + self.format = '%0.2f' + self.unit = 'mm' + + def step(self, ss, direction): + if self.ss_prev_step is not None: + if self.samplerate: + delta = ss - self.ss_prev_step + speed = self.samplerate / delta / self.scale + speed_txt = self.format % speed + self.put(self.ss_prev_step, ss, self.out_ann, + [0, [speed_txt + ' ' + self.unit + '/s', speed_txt]]) + pos_txt = self.format % (self.pos / self.scale) + self.put(self.ss_prev_step, ss, self.out_ann, + [1, [pos_txt + ' ' + self.unit, pos_txt]]) + + self.pos += (1 if direction else -1) + self.ss_prev_step = ss + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def decode(self): + while True: + (step, direction) = self.wait({0: 'r'}) + self.step(self.samplenum, direction) diff --git a/libsigrokdecode4DSL/decoders/swd/__init__.py b/libsigrokdecode4DSL/decoders/swd/__init__.py new file mode 100644 index 00000000..a141239b --- /dev/null +++ b/libsigrokdecode4DSL/decoders/swd/__init__.py @@ -0,0 +1,34 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Angus Gratton +## +## 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, see . +## + +''' +This PD decodes the ARM SWD (version 1) protocol, as described in the +"ARM Debug Interface v5.2" Architecture Specification. + +Not supported: + * Turnaround periods other than the default 1, as set in DLCR.TURNROUND + (should be trivial to add) + * SWD protocol version 2 (multi-drop support, etc.) + +Details: +http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ihi0031c/index.html +(Registration required) +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/swd/pd.py b/libsigrokdecode4DSL/decoders/swd/pd.py new file mode 100644 index 00000000..3f81e03d --- /dev/null +++ b/libsigrokdecode4DSL/decoders/swd/pd.py @@ -0,0 +1,350 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Angus Gratton +## +## 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, see . +## + +import sigrokdecode as srd +import re + +''' +OUTPUT_PYTHON format: + +Packet: +[, ] + +: + - 'AP_READ' (AP read) + - 'DP_READ' (DP read) + - 'AP_WRITE' (AP write) + - 'DP_WRITE' (DP write) + - 'LINE_RESET' (line reset sequence) + +: + - tuple of address, ack state, data for the given sequence +''' + +swd_states = [ + 'IDLE', # Idle/unknown + 'REQUEST', # Request phase (first 8 bits) + 'ACK', # Ack phase (next 3 bits) + 'READ', # Reading phase (next 32 bits for reads) + 'WRITE', # Writing phase (next 32 bits for write) + 'DPARITY', # Data parity phase +] + +# Regexes for matching SWD data out of bitstring ('1' / '0' characters) format +RE_SWDSWITCH = re.compile(bin(0xE79E)[:1:-1] + '$') +RE_SWDREQ = re.compile(r'1(?P.)(?P.)(?P..)(?P.)01$') +RE_IDLE = re.compile('0' * 50 + '$') + +# Sample edges +RISING = 1 +FALLING = 0 + +ADDR_DP_SELECT = 0x8 +ADDR_DP_CTRLSTAT = 0x4 + +BIT_SELECT_CTRLSEL = 1 +BIT_CTRLSTAT_ORUNDETECT = 1 + +ANNOTATIONS = ['reset', 'enable', 'read', 'write', 'ack', 'data', 'parity'] + +class Decoder(srd.Decoder): + api_version = 3 + id = 'swd' + name = 'SWD' + longname = 'Serial Wire Debug' + desc = 'Two-wire protocol for debug access to ARM CPUs.' + license = 'gplv2+' + inputs = ['logic'] + outputs = ['swd'] + tags = ['Debug/trace'] + channels = ( + {'id': 'swclk', 'name': 'SWCLK', 'desc': 'Master clock'}, + {'id': 'swdio', 'name': 'SWDIO', 'desc': 'Data input/output'}, + ) + options = ( + {'id': 'strict_start', + 'desc': 'Wait for a line reset before starting to decode', + 'default': 'no', 'values': ('yes', 'no')}, + ) + annotations = ( + ('reset', 'RESET'), + ('enable', 'ENABLE'), + ('read', 'READ'), + ('write', 'WRITE'), + ('ack', 'ACK'), + ('data', 'DATA'), + ('parity', 'PARITY'), + ) + + def __init__(self): + self.reset() + + def reset(self): + # SWD data/clock state + self.state = 'UNKNOWN' + self.sample_edge = RISING + self.ack = None # Ack state of the current phase + self.ss_req = 0 # Start sample of current req + self.turnaround = 0 # Number of turnaround edges to ignore before continuing + self.bits = '' # Bits from SWDIO are accumulated here, matched against expected sequences + self.samplenums = [] # Sample numbers that correspond to the samples in self.bits + self.linereset_count = 0 + + # SWD debug port state + self.data = None + self.addr = None + self.rw = None # Are we inside an SWD read or a write? + self.ctrlsel = 0 # 'ctrlsel' is bit 0 in the SELECT register. + self.orundetect = 0 # 'orundetect' is bit 0 in the CTRLSTAT register. + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_python = self.register(srd.OUTPUT_PYTHON) + if self.options['strict_start'] == 'no': + self.state = 'REQ' # No need to wait for a LINE RESET. + + def putx(self, ann, length, data): + '''Output annotated data.''' + ann = ANNOTATIONS.index(ann) + try: + ss = self.samplenums[-length] + except IndexError: + ss = self.samplenums[0] + if self.state == 'REQ': + self.ss_req = ss + es = self.samplenum + self.put(ss, es, self.out_ann, [ann, [data]]) + + def putp(self, ptype, pdata): + self.put(self.ss_req, self.samplenum, self.out_python, [ptype, pdata]) + + def put_python_data(self): + '''Emit Python data item based on current SWD packet contents.''' + ptype = { + ('AP', 'R'): 'AP_READ', + ('AP', 'W'): 'AP_WRITE', + ('DP', 'R'): 'DP_READ', + ('DP', 'W'): 'DP_WRITE', + }[(self.apdp, self.rw)] + self.putp(ptype, (self.addr, self.data, self.ack)) + + def decode(self): + while True: + # Wait for any clock edge. + (clk, dio) = self.wait({0: 'e'}) + + # Count rising edges with DIO held high, + # as a line reset (50+ high edges) can happen from any state. + if clk == RISING: + if dio == 1: + self.linereset_count += 1 + else: + if self.linereset_count >= 50: + self.putx('reset', self.linereset_count, 'LINERESET') + self.putp('LINE_RESET', None) + self.reset_state() + self.linereset_count = 0 + + # Otherwise, we only care about either rising or falling edges + # (depending on sample_edge, set according to current state). + if clk != self.sample_edge: + continue + + # Turnaround bits get skipped. + if self.turnaround > 0: + self.turnaround -= 1 + continue + + self.bits += str(dio) + self.samplenums.append(self.samplenum) + { + 'UNKNOWN': self.handle_unknown_edge, + 'REQ': self.handle_req_edge, + 'ACK': self.handle_ack_edge, + 'DATA': self.handle_data_edge, + 'DPARITY': self.handle_dparity_edge, + }[self.state]() + + def next_state(self): + '''Step to the next SWD state, reset internal counters accordingly.''' + self.bits = '' + self.samplenums = [] + self.linereset_count = 0 + if self.state == 'UNKNOWN': + self.state = 'REQ' + self.sample_edge = RISING + self.turnaround = 0 + elif self.state == 'REQ': + self.state = 'ACK' + self.sample_edge = FALLING + self.turnaround = 1 + elif self.state == 'ACK': + self.state = 'DATA' + self.sample_edge = RISING if self.rw == 'W' else FALLING + self.turnaround = 0 if self.rw == 'R' else 2 + elif self.state == 'DATA': + self.state = 'DPARITY' + elif self.state == 'DPARITY': + #self.put_python_data() + self.state = 'REQ' + self.sample_edge = RISING + self.turnaround = 1 if self.rw == 'R' else 0 + + def reset_state(self): + '''Line reset (or equivalent), wait for a new pending SWD request.''' + #if self.state != 'REQ': # Emit a Python data item. + # self.put_python_data() + # Clear state. + self.bits = '' + self.samplenums = [] + self.linereset_count = 0 + self.turnaround = 0 + self.sample_edge = RISING + self.data = '' + self.ack = None + self.state = 'REQ' + + def handle_unknown_edge(self): + ''' + Clock edge in the UNKNOWN state. + In the unknown state, clock edges get ignored until we see a line + reset (which is detected in the decode method, not here.) + ''' + pass + + def handle_req_edge(self): + '''Clock edge in the REQ state (waiting for SWD r/w request).''' + # Check for a JTAG->SWD enable sequence. + m = re.search(RE_SWDSWITCH, self.bits) + if m is not None: + self.putx('enable', 16, 'JTAG->SWD') + self.reset_state() + return + + # Or a valid SWD Request packet. + m = re.search(RE_SWDREQ, self.bits) + if m is not None: + calc_parity = sum([int(x) for x in m.group('rw') + m.group('apdp') + m.group('addr')]) % 2 + parity = '' if str(calc_parity) == m.group('parity') else 'E' + self.rw = 'R' if m.group('rw') == '1' else 'W' + self.apdp = 'AP' if m.group('apdp') == '1' else 'DP' + self.addr = int(m.group('addr')[::-1], 2) << 2 + self.putx('read' if self.rw == 'R' else 'write', 8, self.get_address_description()) + self.next_state() + return + + def handle_ack_edge(self): + '''Clock edge in the ACK state (waiting for complete ACK sequence).''' + if len(self.bits) < 3: + return + if self.bits == '100': + self.putx('ack', 3, 'OK') + self.ack = 'OK' + self.next_state() + elif self.bits == '001': + self.putx('ack', 3, 'FAULT') + self.ack = 'FAULT' + if self.orundetect == 1: + self.next_state() + else: + self.reset_state() + self.turnaround = 1 + elif self.bits == '010': + self.putx('ack', 3, 'WAIT') + self.ack = 'WAIT' + if self.orundetect == 1: + self.next_state() + else: + self.reset_state() + self.turnaround = 1 + elif self.bits == '111': + self.putx('ack', 3, 'NOREPLY') + self.ack = 'NOREPLY' + self.reset_state() + else: + self.putx('ack', 3, 'ERROR') + self.ack = 'ERROR' + self.reset_state() + + def handle_data_edge(self): + '''Clock edge in the DATA state (waiting for 32 bits to clock past).''' + if len(self.bits) < 32: + return + self.data = 0 + self.dparity = 0 + for x in range(32): + if self.bits[x] == '1': + self.data += (1 << x) + self.dparity += 1 + self.dparity = self.dparity % 2 + + self.putx('data', 32, '0x%08x' % self.data) + self.next_state() + + def handle_dparity_edge(self): + '''Clock edge in the DPARITY state (clocking in parity bit).''' + if str(self.dparity) != self.bits: + self.putx('parity', 1, str(self.dparity) + self.bits) # PARITY ERROR + elif self.rw == 'W': + self.handle_completed_write() + self.next_state() + + def handle_completed_write(self): + ''' + Update internal state of the debug port based on a completed + write operation. + ''' + if self.apdp != 'DP': + return + elif self.addr == ADDR_DP_SELECT: + self.ctrlsel = self.data & BIT_SELECT_CTRLSEL + elif self.addr == ADDR_DP_CTRLSTAT and self.ctrlsel == 0: + self.orundetect = self.data & BIT_CTRLSTAT_ORUNDETECT + + def get_address_description(self): + ''' + Return a human-readable description of the currently selected address, + for annotated results. + ''' + if self.apdp == 'DP': + if self.rw == 'R': + # Tables 2-4 & 2-5 in ADIv5.2 spec ARM document IHI 0031C + return { + 0: 'IDCODE', + 0x4: 'R CTRL/STAT' if self.ctrlsel == 0 else 'R DLCR', + 0x8: 'RESEND', + 0xC: 'RDBUFF' + }[self.addr] + elif self.rw == 'W': + # Tables 2-4 & 2-5 in ADIv5.2 spec ARM document IHI 0031C + return { + 0: 'W ABORT', + 0x4: 'W CTRL/STAT' if self.ctrlsel == 0 else 'W DLCR', + 0x8: 'W SELECT', + 0xC: 'W RESERVED' + }[self.addr] + elif self.apdp == 'AP': + if self.rw == 'R': + return 'R AP%x' % self.addr + elif self.rw == 'W': + return 'W AP%x' % self.addr + + # Any legitimate operations shouldn't fall through to here, probably + # a decoder bug. + return '? %s%s%x' % (self.rw, self.apdp, self.addr) diff --git a/libsigrokdecode4DSL/decoders/swim/__init__.py b/libsigrokdecode4DSL/decoders/swim/__init__.py new file mode 100644 index 00000000..cd18b857 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/swim/__init__.py @@ -0,0 +1,29 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Mike Jagdis +## +## 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 +## + +''' +SWIM is a single wire interface for STM8 series 8-bit microcontrollers +that allows non-intrusive read/wite access to be performed on-the-fly +to the memory and registers of the MCU for debug and flashing purposes. + +See the STMicroelectronics document UM0470 for details. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/swim/pd.py b/libsigrokdecode4DSL/decoders/swim/pd.py new file mode 100644 index 00000000..8c12ea7b --- /dev/null +++ b/libsigrokdecode4DSL/decoders/swim/pd.py @@ -0,0 +1,304 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Mike Jagdis +## +## 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 +## + +import math +import sigrokdecode as srd + +class SamplerateError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = 'swim' + name = 'SWIM' + longname = 'STM8 SWIM bus' + desc = 'STM8 Single Wire Interface Module (SWIM) protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Debug/trace'] + options = ( + {'id': 'debug', 'desc': 'Debug', 'default': 'no', 'values': ('yes', 'no') }, + ) + channels = ( + {'id': 'swim', 'name': 'SWIM', 'desc': 'SWIM data line'}, + ) + annotations = ( + ('bit', 'Bit'), + ('enterseq', 'SWIM enter sequence'), + ('start-host', 'Start bit (host)'), + ('start-target', 'Start bit (target)'), + ('parity', 'Parity bit'), + ('ack', 'Acknowledgement'), + ('nack', 'Negative acknowledgement'), + ('byte-write', 'Byte write'), + ('byte-read', 'Byte read'), + ('cmd-unknown', 'Unknown SWIM command'), + ('cmd', 'SWIM command'), + ('bytes', 'Byte count'), + ('address', 'Address'), + ('data-write', 'Data write'), + ('data-read', 'Data read'), + ('debug', 'Debug'), + ) + annotation_rows = ( + ('bits', 'Bits', (0,)), + ('framing', 'Framing', (2, 3, 4, 5, 6, 7, 8)), + ('protocol', 'Protocol', (1, 9, 10, 11, 12, 13, 14)), + ('debug', 'Debug', (15,)), + ) + binary = ( + ('tx', 'Dump of data written to target'), + ('rx', 'Dump of data read from target'), + ) + + def __init__(self): + # SWIM clock for the target is normally HSI/2 where HSI is 8MHz +- 5% + # although the divisor can be removed by setting the SWIMCLK bit in + # the CLK_SWIMCCR register. There is no standard for the host so we + # will be generous and assume it is using an 8MHz +- 10% oscillator. + # We do not need to be accurate. We just need to avoid treating enter + # sequence pulses as bits. A synchronization frame will cause this + # to be adjusted. + self.HSI = 8000000 + self.HSI_min = self.HSI * 0.9 + self.HSI_max = self.HSI * 1.1 + self.swim_clock = self.HSI_min / 2 + + self.eseq_edge = [[-1, None], [-1, None]] + self.eseq_pairnum = 0 + self.eseq_pairstart = None + + self.reset() + + def reset(self): + self.bit_edge = [[-1, None], [-1, None]] + self.bit_maxlen = -1 + self.bitseq_len = 0 + self.bitseq_end = None + self.proto_state = 'CMD' + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def adjust_timings(self): + # A low-speed bit is 22 SWIM clocks long. + # There are options to shorten bits to 10 clocks or use HSI rather + # than HSI/2 as the SWIM clock but the longest valid bit should be no + # more than this many samples. This does not need to be accurate. + # It exists simply to prevent bits extending unecessarily far into + # trailing bus-idle periods. This will be adjusted every time we see + # a synchronization frame or start bit in order to show idle periods + # as accurately as possible. + self.bit_reflen = math.ceil(self.samplerate * 22 / self.swim_clock) + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_binary = self.register(srd.OUTPUT_BINARY) + + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + + # A synchronization frame is a low that lasts for more than 64 but no + # more than 128 SWIM clock periods based on the standard SWIM clock. + # Note: we also allow for the possibility that the SWIM clock divisor + # has been disabled here. + self.sync_reflen_min = math.floor(self.samplerate * 64 / self.HSI_max) + self.sync_reflen_max = math.ceil(self.samplerate * 128 / (self.HSI_min / 2)) + + self.debug = True if self.options['debug'] == 'yes' else False + + # The SWIM entry sequence is 4 pulses at 2kHz followed by 4 at 1kHz. + self.eseq_reflen = math.ceil(self.samplerate / 2048) + + self.adjust_timings() + + def protocol(self): + if self.proto_state == 'CMD': + # Command + if self.bitseq_value == 0x00: + self.put(self.bitseq_start, self.bitseq_end, self.out_ann, [10, ['system reset', 'SRST', '!']]) + elif self.bitseq_value == 0x01: + self.proto_state = 'N' + self.put(self.bitseq_start, self.bitseq_end, self.out_ann, [10, ['read on-the-fly', 'ROTF', 'r']]) + elif self.bitseq_value == 0x02: + self.proto_state = 'N' + self.put(self.bitseq_start, self.bitseq_end, self.out_ann, [10, ['write on-the-fly', 'WOTF', 'w']]) + else: + self.put(self.bitseq_start, self.bitseq_end, self.out_ann, [9, ['unknown', 'UNK']]) + elif self.proto_state == 'N': + # Number of bytes + self.proto_byte_count = self.bitseq_value + self.proto_state = '@E' + self.put(self.bitseq_start, self.bitseq_end, self.out_ann, [11, ['byte count 0x%02x' % self.bitseq_value, 'bytes 0x%02x' % self.bitseq_value, '0x%02x' % self.bitseq_value, '%02x' % self.bitseq_value, '%x' % self.bitseq_value]]) + elif self.proto_state == '@E': + # Address byte 1 + self.proto_addr = self.bitseq_value + self.proto_addr_start = self.bitseq_start + self.proto_state = '@H' + elif self.proto_state == '@H': + # Address byte 2 + self.proto_addr = (self.proto_addr << 8) | self.bitseq_value + self.proto_state = '@L' + elif self.proto_state == '@L': + # Address byte 3 + self.proto_addr = (self.proto_addr << 8) | self.bitseq_value + self.proto_state = 'D' + self.put(self.proto_addr_start, self.bitseq_end, self.out_ann, [12, ['address 0x%06x' % self.proto_addr, 'addr 0x%06x' % self.proto_addr, '0x%06x' % self.proto_addr, '%06x' %self.proto_addr, '%x' % self.proto_addr]]) + else: + if self.proto_byte_count > 0: + self.proto_byte_count -= 1 + if self.proto_byte_count == 0: + self.proto_state = 'CMD' + + self.put(self.bitseq_start, self.bitseq_end, self.out_ann, [13 + self.bitseq_dir, ['0x%02x' % self.bitseq_value, '%02x' % self.bitseq_value, '%x' % self.bitseq_value]]) + self.put(self.bitseq_start, self.bitseq_end, self.out_binary, [0 + self.bitseq_dir, bytes([self.bitseq_value])]) + if self.debug: + self.put(self.bitseq_start, self.bitseq_end, self.out_ann, [15, ['%d more' % self.proto_byte_count, '%d' % self.proto_byte_count]]) + + def bitseq(self, bitstart, bitend, bit): + if self.bitseq_len == 0: + # Looking for start of a bit sequence (command or byte). + self.bit_reflen = bitend - bitstart + self.bitseq_value = 0 + self.bitseq_dir = bit + self.bitseq_len = 1 + self.put(bitstart, bitend, self.out_ann, [2 + self.bitseq_dir, ['start', 's']]) + elif (self.proto_state == 'CMD' and self.bitseq_len == 4) or (self.proto_state != 'CMD' and self.bitseq_len == 9): + # Parity bit + self.bitseq_end = bitstart + self.bitseq_len += 1 + + self.put(bitstart, bitend, self.out_ann, [4, ['parity', 'par', 'p']]) + + # The start bit is not data but was used for parity calculation. + self.bitseq_value &= 0xff + self.put(self.bitseq_start, self.bitseq_end, self.out_ann, [7 + self.bitseq_dir, ['0x%02x' % self.bitseq_value, '%02x' % self.bitseq_value, '%x' % self.bitseq_value]]) + elif (self.proto_state == 'CMD' and self.bitseq_len == 5) or (self.proto_state != 'CMD' and self.bitseq_len == 10): + # ACK/NACK bit. + if bit: + self.put(bitstart, bitend, self.out_ann, [5, ['ack', 'a']]) + else: + self.put(bitstart, bitend, self.out_ann, [6, ['nack', 'n']]) + + # We only pass data that was ack'd up the stack. + if bit: + self.protocol() + + self.bitseq_len = 0 + else: + if self.bitseq_len == 1: + self.bitseq_start = bitstart + self.bitseq_value = (self.bitseq_value << 1) | bit + self.bitseq_len += 1 + + def bit(self, start, mid, end): + if mid - start >= end - mid: + self.put(start, end, self.out_ann, [0, ['0']]) + bit = 0 + else: + self.put(start, end, self.out_ann, [0, ['1']]) + bit = 1 + + self.bitseq(start, end, bit) + + def detect_synchronize_frame(self, start, end): + # Strictly speaking, synchronization frames are only recognised when + # SWIM is active. A falling edge on reset disables SWIM and an enter + # sequence is needed to re-enable it. However we do not want to be + # reliant on seeing the NRST pin just for that and we also want to be + # able to decode SWIM even if we just sample parts of the dialogue. + # For this reason we limit ourselves to only recognizing + # synchronization frames that have believable lengths based on our + # knowledge of the range of possible SWIM clocks. + if self.samplenum - self.eseq_edge[1][1] >= self.sync_reflen_min and self.samplenum - self.eseq_edge[1][1] <= self.sync_reflen_max: + self.put(self.eseq_edge[1][1], self.samplenum, self.out_ann, [1, ['synchronization frame', 'synchronization', 'sync', 's']]) + + # A low that lasts for more than 64 SWIM clock periods causes a + # reset of the SWIM communication state machine and will switch + # the SWIM to low-speed mode (SWIM_CSR.HS is cleared). + self.reset() + + # The low SHOULD last 128 SWIM clocks. This is used to + # resynchronize in order to allow for variation in the frequency + # of the internal RC oscillator. + self.swim_clock = 128 * (self.samplerate / (self.samplenum - self.eseq_edge[1][1])) + self.adjust_timings() + + def eseq_potential_start(self, start, end): + self.eseq_pairstart = start + self.eseq_reflen = end - start + self.eseq_pairnum = 1 + + def detect_enter_sequence(self, start, end): + # According to the spec the enter sequence is four pulses at 2kHz + # followed by four at 1kHz. We do not check the frequency but simply + # check the lengths of successive pulses against the first. This means + # we have no need to account for the accuracy (or lack of) of the + # host's oscillator. + if self.eseq_pairnum == 0 or abs(self.eseq_reflen - (end - start)) > 2: + self.eseq_potential_start(start, end) + + elif self.eseq_pairnum < 4: + # The next three pulses should be the same length as the first. + self.eseq_pairnum += 1 + + if self.eseq_pairnum == 4: + self.eseq_reflen /= 2 + else: + # The final four pulses should each be half the length of the + # initial pair. Again, a mismatch causes us to reset and use the + # current pulse as a new potential enter sequence start. + self.eseq_pairnum += 1 + if self.eseq_pairnum == 8: + # Four matching pulses followed by four more that match each + # other but are half the length of the first 4. SWIM is active! + self.put(self.eseq_pairstart, end, self.out_ann, [1, ['enter sequence', 'enter seq', 'enter', 'ent', 'e']]) + self.eseq_pairnum = 0 + + def decode(self): + while True: + if self.bit_maxlen >= 0: + (swim,) = self.wait() + self.bit_maxlen -= 1 + else: + (swim,) = self.wait({0: 'e'}) + + if swim != self.eseq_edge[1][0]: + if swim == 1 and self.eseq_edge[1][1] is not None: + self.detect_synchronize_frame(self.eseq_edge[1][1], self.samplenum) + if self.eseq_edge[0][1] is not None: + self.detect_enter_sequence(self.eseq_edge[0][1], self.samplenum) + self.eseq_edge.pop(0) + self.eseq_edge.append([swim, self.samplenum]) + + if (swim != self.bit_edge[1][0] and (swim != 1 or self.bit_edge[1][0] != -1)) or self.bit_maxlen == 0: + if self.bit_maxlen == 0 and self.bit_edge[1][0] == 1: + swim = -1 + + if self.bit_edge[1][0] != 0 and swim == 0: + self.bit_maxlen = self.bit_reflen + + if self.bit_edge[0][0] == 0 and self.bit_edge[1][0] == 1 and self.samplenum - self.bit_edge[0][1] <= self.bit_reflen + 10: + self.bit(self.bit_edge[0][1], self.bit_edge[1][1], self.samplenum) + + self.bit_edge.pop(0) + self.bit_edge.append([swim, self.samplenum]) diff --git a/libsigrokdecode4DSL/decoders/t55xx/__init__.py b/libsigrokdecode4DSL/decoders/t55xx/__init__.py new file mode 100644 index 00000000..01184350 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/t55xx/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Benjamin Larsson +## +## 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, see . +## + +''' +T55xx is a 100-150kHz RFID protocol according to the Atmel e555x +downlink/write protocol (pulse interval coding). +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/t55xx/pd.py b/libsigrokdecode4DSL/decoders/t55xx/pd.py new file mode 100644 index 00000000..d345d318 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/t55xx/pd.py @@ -0,0 +1,326 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Benjamin Larsson +## +## 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, see . +## + +import sigrokdecode as srd + +class SamplerateError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = 't55xx' + name = 'T55xx' + longname = 'RFID T55xx' + desc = 'T55xx 100-150kHz RFID protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['IC', 'RFID'] + channels = ( + {'id': 'data', 'name': 'Data', 'desc': 'Data line'}, + ) + options = ( + {'id': 'coilfreq', 'desc': 'Coil frequency', 'default': 125000}, + {'id': 'start_gap', 'desc': 'Start gap min', 'default': 20}, + {'id': 'w_gap', 'desc': 'Write gap min', 'default': 20}, + {'id': 'w_one_min', 'desc': 'Write one min', 'default': 48}, + {'id': 'w_one_max', 'desc': 'Write one max', 'default': 63}, + {'id': 'w_zero_min', 'desc': 'Write zero min', 'default': 16}, + {'id': 'w_zero_max', 'desc': 'Write zero max', 'default': 31}, + {'id': 'em4100_decode', 'desc': 'EM4100 decode', 'default': 'on', + 'values': ('on', 'off')}, + ) + annotations = ( + ('bit_value', 'Bit value'), + ('start_gap', 'Start gap'), + ('write_gap', 'Write gap'), + ('write_mode_exit', 'Write mode exit'), + ('bit', 'Bit'), + ('opcode', 'Opcode'), + ('lock', 'Lock'), + ('data', 'Data'), + ('password', 'Password'), + ('address', 'Address'), + ('bitrate', 'Bitrate'), + ) + annotation_rows = ( + ('bits', 'Bits', (0,)), + ('structure', 'Structure', (1, 2, 3, 4)), + ('fields', 'Fields', (5, 6, 7, 8, 9)), + ('decode', 'Decode', (10,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.last_samplenum = None + self.lastlast_samplenum = None + self.state = 'START_GAP' + self.bits_pos = [[0 for col in range(3)] for row in range(70)] + self.br_string = ['RF/8', 'RF/16', 'RF/32', 'RF/40', + 'RF/50', 'RF/64', 'RF/100', 'RF/128'] + self.mod_str1 = ['Direct', 'Manchester', 'Biphase', 'Reserved'] + self.mod_str2 = ['Direct', 'PSK1', 'PSK2', 'PSK3', 'FSK1', 'FSK2', + 'FSK1a', 'FSK2a'] + self.pskcf_str = ['RF/2', 'RF/4', 'RF/8', 'Reserved'] + self.em4100_decode1_partial = 0 + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + self.field_clock = self.samplerate / self.options['coilfreq'] + self.wzmax = self.options['w_zero_max'] * self.field_clock + self.wzmin = self.options['w_zero_min'] * self.field_clock + self.womax = self.options['w_one_max'] * self.field_clock + self.womin = self.options['w_one_min'] * self.field_clock + self.startgap = self.options['start_gap'] * self.field_clock + self.writegap = self.options['w_gap'] * self.field_clock + self.nogap = 64 * self.field_clock + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def decode_config(self, idx): + safer_key = self.bits_pos[idx][0]<<3 | self.bits_pos[idx+1][0]<<2 | \ + self.bits_pos[idx+2][0]<<1 | self.bits_pos[idx+3][0] + self.put(self.bits_pos[idx][1], self.bits_pos[idx+3][2], self.out_ann, + [10, ['Safer Key' + ': %X' % safer_key,'%X' % safer_key]]) + bitrate = self.bits_pos[idx+11][0]<<2 | self.bits_pos[idx+12][0]<<1 | \ + self.bits_pos[idx+13][0] + self.put(self.bits_pos[idx+11][1], self.bits_pos[idx+13][2], + self.out_ann, [10, ['Data Bit Rate: ' + \ + self.br_string[bitrate], self.br_string[bitrate]]]) + modulation1 = self.bits_pos[idx+15][0]<<1 | self.bits_pos[idx+16][0] + modulation2 = self.bits_pos[idx+17][0]<<2 | \ + self.bits_pos[idx+18][0]<<1 | self.bits_pos[idx+19][0] + if modulation1 == 0: + mod_string = self.mod_str2[modulation2] + else: + mod_string = self.mod_str1[modulation1] + self.put(self.bits_pos[idx+15][1], self.bits_pos[idx+19][2], + self.out_ann, [10, ['Modulation: ' + mod_string, mod_string]]) + psk_cf = self.bits_pos[idx+20][0]<<1 | self.bits_pos[idx+21][0] + self.put(self.bits_pos[idx+20][1], self.bits_pos[idx+21][2], + self.out_ann, [10, ['PSK-CF: ' + self.pskcf_str[psk_cf], + self.pskcf_str[psk_cf]]]) + self.put(self.bits_pos[idx+22][1], self.bits_pos[idx+22][2], + self.out_ann, [10, ['AOR' + ': %d' % \ + (self.bits_pos[idx+22][0]),'%d' % (self.bits_pos[idx+22][0])]]) + maxblock = self.bits_pos[idx+24][0]<<2 | self.bits_pos[idx+25][0]<<1 | \ + self.bits_pos[idx+26][0] + self.put(self.bits_pos[idx+24][1], self.bits_pos[idx+26][2], + self.out_ann, [10, ['Max-Block' + ': %d' % maxblock, + '%d' % maxblock]]) + self.put(self.bits_pos[idx+27][1], self.bits_pos[idx+27][2], + self.out_ann, [10, ['PWD' + ': %d' % \ + (self.bits_pos[idx+27][0]),'%d' % (self.bits_pos[idx+27][0])]]) + self.put(self.bits_pos[idx+28][1], self.bits_pos[idx+28][2], + self.out_ann, [10, ['ST-sequence terminator' + ': %d' % \ + (self.bits_pos[idx+28][0]),'%d' % (self.bits_pos[idx+28][0])]]) + self.put(self.bits_pos[idx+31][1], self.bits_pos[idx+31][2], + self.out_ann, [10, ['POR delay' + ': %d' % \ + (self.bits_pos[idx+31][0]),'%d' % (self.bits_pos[idx+31][0])]]) + + def put4bits(self, idx): + bits = self.bits_pos[idx][0]<<3 | self.bits_pos[idx+1][0]<<2 | \ + self.bits_pos[idx+2][0]<<1 | self.bits_pos[idx+3][0] + self.put(self.bits_pos[idx][1], self.bits_pos[idx+3][2], self.out_ann, + [10, ['%X' % bits]]) + + def em4100_decode1(self, idx): + self.put(self.bits_pos[idx][1], self.bits_pos[idx+8][2], self.out_ann, + [10, ['EM4100 header', 'EM header', 'Header', 'H']]) + self.put4bits(idx+9) + self.put4bits(idx+14) + self.put4bits(idx+19) + self.put4bits(idx+24) + self.em4100_decode1_partial = self.bits_pos[idx+29][0]<<3 | \ + self.bits_pos[idx+30][0]<<2 | self.bits_pos[idx+31][0]<<1 + self.put(self.bits_pos[idx+29][1], self.bits_pos[idx+31][2], + self.out_ann, [10, ['Partial nibble']]) + + def em4100_decode2(self, idx): + if self.em4100_decode1_partial != 0: + bits = self.em4100_decode1_partial + self.bits_pos[idx][0] + self.put(self.bits_pos[idx][1], self.bits_pos[idx][2], + self.out_ann, [10, ['%X' % bits]]) + self.em4100_decode1_partial = 0 + else: + self.put(self.bits_pos[idx][1], self.bits_pos[idx][2], + self.out_ann, [10, ['Partial nibble']]) + + self.put4bits(idx+2) + self.put4bits(idx+7) + self.put4bits(idx+12) + self.put4bits(idx+17) + self.put4bits(idx+22) + self.put(self.bits_pos[idx+27][1], self.bits_pos[idx+31][2], + self.out_ann, [10, ['EM4100 trailer']]) + + def get_32_bits(self, idx): + retval = 0 + for i in range(0, 32): + retval <<= 1 + retval |= self.bits_pos[i+idx][0] + return retval + + def get_3_bits(self, idx): + retval = self.bits_pos[idx][0]<<2 | self.bits_pos[idx+1][0]<<1 | \ + self.bits_pos[idx+2][0] + return retval + + def put_fields(self): + if (self.bit_nr == 70): + self.put(self.bits_pos[0][1], self.bits_pos[1][2], self.out_ann, + [5, ['Opcode' + ': %d%d' % (self.bits_pos[0][0], + self.bits_pos[1][0]), '%d%d' % (self.bits_pos[0][0], + self.bits_pos[1][0])]]) + password = self.get_32_bits(2) + self.put(self.bits_pos[2][1], self.bits_pos[33][2], self.out_ann, + [8, ['Password' + ': %X' % password, '%X' % password]]) + self.put(self.bits_pos[34][1], self.bits_pos[34][2], self.out_ann, + [6, ['Lock' + ': %X' % self.bits_pos[34][0], + '%X' % self.bits_pos[34][0]]]) + data = self.get_32_bits(35) + self.put(self.bits_pos[35][1], self.bits_pos[66][2], self.out_ann, + [7, ['Data' + ': %X' % data, '%X' % data]]) + addr = self.get_3_bits(67) + self.put(self.bits_pos[67][1], self.bits_pos[69][2], self.out_ann, + [9, ['Addr' + ': %X' % addr, '%X' % addr]]) + if addr == 0: + self.decode_config(35) + if addr == 7: + self.put(self.bits_pos[35][1], self.bits_pos[66][2], + self.out_ann, [10, ['Password' + ': %X' % data, + '%X' % data]]) + # If we are programming EM4100 data we can decode it halfway. + if addr == 1 and self.options['em4100_decode'] == 'on': + self.em4100_decode1(35) + if addr == 2 and self.options['em4100_decode'] == 'on': + self.em4100_decode2(35) + + if (self.bit_nr == 38): + self.put(self.bits_pos[0][1], self.bits_pos[1][2], self.out_ann, + [5, ['Opcode' + ': %d%d' % (self.bits_pos[0][0], + self.bits_pos[1][0]), '%d%d' % (self.bits_pos[0][0], + self.bits_pos[1][0])]]) + self.put(self.bits_pos[2][1], self.bits_pos[2][2], self.out_ann, + [6, ['Lock' + ': %X' % self.bits_pos[2][0], + '%X' % self.bits_pos[2][0]]]) + data = self.get_32_bits(3) + self.put(self.bits_pos[3][1], self.bits_pos[34][2], self.out_ann, + [7, ['Data' + ': %X' % data, '%X' % data]]) + addr = self.get_3_bits(35) + self.put(self.bits_pos[35][1], self.bits_pos[37][2], self.out_ann, + [9, ['Addr' + ': %X' % addr, '%X' % addr]]) + if addr == 0: + self.decode_config(3) + if addr == 7: + self.put(self.bits_pos[3][1], self.bits_pos[34][2], + self.out_ann, [10, ['Password' + ': %X' % data, + '%X' % data]]) + # If we are programming EM4100 data we can decode it halfway. + if addr == 1 and self.options['em4100_decode'] == 'on': + self.em4100_decode1(3) + if addr == 2 and self.options['em4100_decode'] == 'on': + self.em4100_decode2(3) + + if (self.bit_nr == 2): + self.put(self.bits_pos[0][1], self.bits_pos[1][2], self.out_ann, + [5, ['Opcode' + ': %d%d' % (self.bits_pos[0][0], + self.bits_pos[1][0]), '%d%d' % (self.bits_pos[0][0], + self.bits_pos[1][0])]]) + self.bit_nr = 0 + + def add_bits_pos(self, bit, bit_start, bit_end): + if self.bit_nr < 70: + self.bits_pos[self.bit_nr][0] = bit + self.bits_pos[self.bit_nr][1] = bit_start + self.bits_pos[self.bit_nr][2] = bit_end + self.bit_nr += 1 + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + + self.last_samplenum = 0 + self.lastlast_samplenum = 0 + self.last_edge = 0 + self.oldpl = 0 + self.oldpp = 0 + self.oldsamplenum = 0 + self.last_bit_pos = 0 + self.old_gap_start = 0 + self.old_gap_end = 0 + self.gap_detected = 0 + self.bit_nr = 0 + + while True: + (pin,) = self.wait({0: 'e'}) + + pl = self.samplenum - self.oldsamplenum + pp = pin + samples = self.samplenum - self.last_samplenum + + if self.state == 'WRITE_GAP': + if pl > self.writegap: + self.gap_detected = 1 + self.put(self.last_samplenum, self.samplenum, + self.out_ann, [2, ['Write gap']]) + if (self.last_samplenum-self.old_gap_end) > self.nogap: + self.gap_detected = 0 + self.state = 'START_GAP' + self.put(self.old_gap_end, self.last_samplenum, + self.out_ann, [3, ['Write mode exit']]) + self.put_fields() + + if self.state == 'START_GAP': + if pl > self.startgap: + self.gap_detected = 1 + self.put(self.last_samplenum, self.samplenum, + self.out_ann, [1, ['Start gap']]) + self.state = 'WRITE_GAP' + + if self.gap_detected == 1: + self.gap_detected = 0 + if (self.last_samplenum - self.old_gap_end) > self.wzmin \ + and (self.last_samplenum - self.old_gap_end) < self.wzmax: + self.put(self.old_gap_end, self.last_samplenum, + self.out_ann, [0, ['0']]) + self.put(self.old_gap_end, self.last_samplenum, + self.out_ann, [4, ['Bit']]) + self.add_bits_pos(0, self.old_gap_end, + self.last_samplenum) + if (self.last_samplenum - self.old_gap_end) > self.womin \ + and (self.last_samplenum - self.old_gap_end) < self.womax: + self.put(self.old_gap_end, self.last_samplenum, + self.out_ann, [0, ['1']]) + self.put(self.old_gap_end, self.last_samplenum, + self.out_ann, [4, ['Bit']]) + self.add_bits_pos(1, self.old_gap_end, self.last_samplenum) + + self.old_gap_start = self.last_samplenum + self.old_gap_end = self.samplenum + + self.oldpl = pl + self.oldpp = pp + self.oldsamplenum = self.samplenum + self.last_samplenum = self.samplenum diff --git a/libsigrokdecode4DSL/decoders/tca6408a/__init__.py b/libsigrokdecode4DSL/decoders/tca6408a/__init__.py new file mode 100644 index 00000000..5373c311 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/tca6408a/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 alberink +## +## 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, see . +## + +''' +This decoder stacks on top of the 'i2c' PD and decodes the Texas Instruments +TCA6408A 8-bit I²C I/O expander protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/tca6408a/pd.py b/libsigrokdecode4DSL/decoders/tca6408a/pd.py new file mode 100644 index 00000000..49245174 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/tca6408a/pd.py @@ -0,0 +1,132 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## Copyright (C) 2013 Matt Ranostay +## Copyright (C) 2014 alberink +## +## 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, see . +## + +import sigrokdecode as srd + +class Decoder(srd.Decoder): + api_version = 3 + id = 'tca6408a' + name = 'TI TCA6408A' + longname = 'Texas Instruments TCA6408A' + desc = 'Texas Instruments TCA6408A 8-bit I²C I/O expander.' + license = 'gplv2+' + inputs = ['i2c'] + outputs = [] + tags = ['Embedded/industrial', 'IC'] + annotations = ( + ('register', 'Register type'), + ('value', 'Register value'), + ('warnings', 'Warning messages'), + ) + annotation_rows = ( + ('regs', 'Registers', (0, 1)), + ('warnings', 'Warnings', (2,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.state = 'IDLE' + self.chip = -1 + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + self.put(self.ss, self.es, self.out_ann, data) + + def handle_reg_0x00(self, b): + self.putx([1, ['State of inputs: %02X' % b]]) + + def handle_reg_0x01(self, b): + self.putx([1, ['Outputs set: %02X' % b ]]) + + def handle_reg_0x02(self, b): + self.putx([1, ['Polarity inverted: %02X' % b]]) + + def handle_reg_0x03(self, b): + self.putx([1, ['Configuration: %02X' % b]]) + + def handle_write_reg(self, b): + if b == 0: + self.putx([0, ['Input port', 'In', 'I']]) + elif b == 1: + self.putx([0, ['Output port', 'Out', 'O']]) + elif b == 2: + self.putx([0, ['Polarity inversion register', 'Pol', 'P']]) + elif b == 3: + self.putx([0, ['Configuration register', 'Conf', 'C']]) + + def check_correct_chip(self, addr): + if addr not in (0x20, 0x21): + self.putx([2, ['Warning: I²C slave 0x%02X not a TCA6408A ' + 'compatible chip.' % addr]]) + self.state = 'IDLE' + + def decode(self, ss, es, data): + cmd, databyte = data + + # Store the start/end samples of this I²C packet. + self.ss, self.es = ss, es + + # State machine. + if self.state == 'IDLE': + # Wait for an I²C START condition. + if cmd != 'START': + return + self.state = 'GET SLAVE ADDR' + elif self.state == 'GET SLAVE ADDR': + self.chip = databyte + self.state = 'GET REG ADDR' + elif self.state == 'GET REG ADDR': + # Wait for a data write (master selects the slave register). + if cmd in ('ADDRESS READ', 'ADDRESS WRITE'): + self.check_correct_chip(databyte) + if cmd != 'DATA WRITE': + return + self.reg = databyte + self.handle_write_reg(self.reg) + self.state = 'WRITE IO REGS' + elif self.state == 'WRITE IO REGS': + # If we see a Repeated Start here, the master wants to read. + if cmd == 'START REPEAT': + self.state = 'READ IO REGS' + return + # Otherwise: Get data bytes until a STOP condition occurs. + if cmd == 'DATA WRITE': + handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg) + handle_reg(databyte) + elif cmd == 'STOP': + self.state = 'IDLE' + self.chip = -1 + elif self.state == 'READ IO REGS': + # Wait for an address read operation. + if cmd == 'ADDRESS READ': + self.state = 'READ IO REGS2' + self.chip = databyte + return + elif self.state == 'READ IO REGS2': + if cmd == 'DATA READ': + handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg) + handle_reg(databyte) + elif cmd == 'STOP': + self.state = 'IDLE' diff --git a/libsigrokdecode4DSL/decoders/tdm_audio/__init__.py b/libsigrokdecode4DSL/decoders/tdm_audio/__init__.py new file mode 100644 index 00000000..a95e16e3 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/tdm_audio/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Ben Dooks +## +## 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, see . +## + +''' +TDM Audio is an audio serial bus for moving audio data between devices +(usually on the same board) which can carry one or more channels of data. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/tdm_audio/pd.py b/libsigrokdecode4DSL/decoders/tdm_audio/pd.py new file mode 100644 index 00000000..e805706f --- /dev/null +++ b/libsigrokdecode4DSL/decoders/tdm_audio/pd.py @@ -0,0 +1,116 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Ben Dooks +## +## 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, see . +## + +import sigrokdecode as srd + +MAX_CHANNELS = 8 + +class Decoder(srd.Decoder): + api_version = 3 + id = 'tdm_audio' + name = 'TDM audio' + longname = 'Time division multiplex audio' + desc = 'TDM multi-channel audio protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Audio'] + channels = ( + { 'id': 'clock', 'name': 'Bitclk', 'desc': 'Data bit clock' }, + { 'id': 'frame', 'name': 'Framesync', 'desc': 'Frame sync' }, + { 'id': 'data', 'name': 'Data', 'desc': 'Serial data' }, + ) + options = ( + {'id': 'bps', 'desc': 'Bits per sample', 'default': 16 }, + {'id': 'channels', 'desc': 'Channels per frame', 'default': MAX_CHANNELS }, + {'id': 'edge', 'desc': 'Clock edge to sample on', 'default': 'rising', 'values': ('rising', 'falling') } + ) + annotations = tuple(('ch%d' % i, 'Ch%d' % i) for i in range(MAX_CHANNELS)) + annotation_rows = tuple(('ch%d-vals' % i, 'Ch%d' % i, (i,)) for i in range(MAX_CHANNELS)) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.channels = MAX_CHANNELS + self.channel = 0 + self.bitdepth = 16 + self.bitcount = 0 + self.samplecount = 0 + self.lastsync = 0 + self.lastframe = 0 + self.data = 0 + self.ss_block = None + + def metdatadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.bitdepth = self.options['bps'] + self.edge = self.options['edge'] + + def decode(self): + while True: + # Wait for edge of clock (sample on rising/falling edge). + clock, frame, data = self.wait({0: self.edge[0]}) + + self.data = (self.data << 1) | data + self.bitcount += 1 + + if self.ss_block is not None: + if self.bitcount >= self.bitdepth: + self.bitcount = 0 + self.channel += 1 + + c1 = 'Channel %d' % self.channel + c2 = 'C%d' % self.channel + c3 = '%d' % self.channel + if self.bitdepth <= 8: + v = '%02x' % self.data + elif self.bitdepth <= 16: + v = '%04x' % self.data + else: + v = '%08x' % self.data + + if self.channel < self.channels: + ch = self.channel + else: + ch = 0 + + self.put(self.ss_block, self.samplenum, self.out_ann, + [ch, ['%s: %s' % (c1, v), '%s: %s' % (c2, v), + '%s: %s' % (c3, v)]]) + self.data = 0 + self.ss_block = self.samplenum + self.samplecount += 1 + + # Check for new frame. + # Note, frame may be a single clock, or active for the first + # sample in the frame. + if frame != self.lastframe and frame == 1: + self.channel = 0 + self.bitcount = 0 + self.data = 0 + if self.ss_block is None: + self.ss_block = 0 + + self.lastframe = frame diff --git a/libsigrokdecode4DSL/decoders/timing/__init__.py b/libsigrokdecode4DSL/decoders/timing/__init__.py new file mode 100644 index 00000000..179487b3 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/timing/__init__.py @@ -0,0 +1,24 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Torsten Duwe +## +## 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, see . +## + +''' +Timing decoder, find the time between edges. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/timing/pd.py b/libsigrokdecode4DSL/decoders/timing/pd.py new file mode 100644 index 00000000..20ca2c4e --- /dev/null +++ b/libsigrokdecode4DSL/decoders/timing/pd.py @@ -0,0 +1,128 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Torsten Duwe +## Copyright (C) 2014 Sebastien Bourdelin +## +## 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, see . +## + +import sigrokdecode as srd +from collections import deque + +class SamplerateError(Exception): + pass + +def normalize_time(t): + if abs(t) >= 1.0: + return '%.3f s (%.3f Hz)' % (t, (1/t)) + elif abs(t) >= 0.001: + if 1/t/1000 < 1: + return '%.3f ms (%.3f Hz)' % (t * 1000.0, (1/t)) + else: + return '%.3f ms (%.3f kHz)' % (t * 1000.0, (1/t)/1000) + elif abs(t) >= 0.000001: + if 1/t/1000/1000 < 1: + return '%.3f μs (%.3f kHz)' % (t * 1000.0 * 1000.0, (1/t)/1000) + else: + return '%.3f μs (%.3f MHz)' % (t * 1000.0 * 1000.0, (1/t)/1000/1000) + elif abs(t) >= 0.000000001: + if 1/t/1000/1000/1000: + return '%.3f ns (%.3f MHz)' % (t * 1000.0 * 1000.0 * 1000.0, (1/t)/1000/1000) + else: + return '%.3f ns (%.3f GHz)' % (t * 1000.0 * 1000.0 * 1000.0, (1/t)/1000/1000/1000) + else: + return '%f' % t + +class Decoder(srd.Decoder): + api_version = 3 + id = 'timing' + name = 'Timing' + longname = 'Timing calculation with frequency and averaging' + desc = 'Calculate time between edges.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Clock/timing', 'Util'] + channels = ( + {'id': 'data', 'name': 'Data', 'desc': 'Data line'}, + ) + annotations = ( + ('time', 'Time'), + ('average', 'Average'), + ('delta', 'Delta'), + ) + annotation_rows = ( + ('time', 'Time', (0,)), + ('average', 'Average', (1,)), + ('delta', 'Delta', (2,)), + ) + options = ( + { 'id': 'avg_period', 'desc': 'Averaging period', 'default': 100 }, + { 'id': 'edge', 'desc': 'Edges to check', 'default': 'any', 'values': ('any', 'rising', 'falling') }, + { 'id': 'delta', 'desc': 'Show delta from last', 'default': 'no', 'values': ('yes', 'no') }, + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.last_samplenum = None + self.last_n = deque() + self.chunks = 0 + self.level_changed = False + self.last_t = None + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.edge = self.options['edge'] + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + while True: + if self.edge == 'rising': + self.wait({0: 'r'}) + elif self.edge == 'falling': + self.wait({0: 'f'}) + else: + self.wait({0: 'e'}) + + if not self.last_samplenum: + self.last_samplenum = self.samplenum + continue + samples = self.samplenum - self.last_samplenum + t = samples / self.samplerate + + if t > 0: + self.last_n.append(t) + if len(self.last_n) > self.options['avg_period']: + self.last_n.popleft() + + self.put(self.last_samplenum, self.samplenum, self.out_ann, + [0, [normalize_time(t)]]) + if self.options['avg_period'] > 0: + self.put(self.last_samplenum, self.samplenum, self.out_ann, + [1, [normalize_time(sum(self.last_n) / len(self.last_n))]]) + if self.last_t and self.options['delta'] == 'yes': + self.put(self.last_samplenum, self.samplenum, self.out_ann, + [2, [normalize_time(t - self.last_t)]]) + + self.last_t = t + self.last_samplenum = self.samplenum diff --git a/libsigrokdecode4DSL/decoders/tlc5620/__init__.py b/libsigrokdecode4DSL/decoders/tlc5620/__init__.py new file mode 100644 index 00000000..a642ef64 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/tlc5620/__init__.py @@ -0,0 +1,24 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +''' +The Texas Instruments TLC5620 is an 8-bit quad DAC. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/tlc5620/pd.py b/libsigrokdecode4DSL/decoders/tlc5620/pd.py new file mode 100644 index 00000000..eec040bc --- /dev/null +++ b/libsigrokdecode4DSL/decoders/tlc5620/pd.py @@ -0,0 +1,210 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012-2015 Uwe Hermann +## Copyright (C) 2019 DreamSourceLab +## +## 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, see . +## + +import sigrokdecode as srd + +dacs = { + 0: 'DACA', + 1: 'DACB', + 2: 'DACC', + 3: 'DACD', +} + +class Decoder(srd.Decoder): + api_version = 3 + id = 'tlc5620' + name = 'TI TLC5620' + longname = 'Texas Instruments TLC5620' + desc = 'Texas Instruments TLC5620 8-bit quad DAC.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['IC', 'Analog/digital'] + channels = ( + {'id': 'clk', 'name': 'CLK', 'desc': 'Serial interface clock'}, + {'id': 'data', 'name': 'DATA', 'desc': 'Serial interface data'}, + ) + optional_channels = ( + {'id': 'load', 'name': 'LOAD', 'desc': 'Serial interface load control'}, + {'id': 'ldac', 'name': 'LDAC', 'desc': 'Load DAC'}, + ) + options = ( + {'id': 'vref_a', 'desc': 'Reference voltage DACA (V)', 'default': 3.3}, + {'id': 'vref_b', 'desc': 'Reference voltage DACB (V)', 'default': 3.3}, + {'id': 'vref_c', 'desc': 'Reference voltage DACC (V)', 'default': 3.3}, + {'id': 'vref_d', 'desc': 'Reference voltage DACD (V)', 'default': 3.3}, + ) + annotations = ( + ('dac-select', 'DAC select'), + ('gain', 'Gain'), + ('value', 'DAC value'), + ('data-latch', 'Data latch point'), + ('ldac-fall', 'LDAC falling edge'), + ('bit', 'Bit'), + ('reg-write', 'Register write'), + ('voltage-update', 'Voltage update'), + ('voltage-update-all', 'Voltage update (all DACs)'), + ('invalid-cmd', 'Invalid command'), + ) + annotation_rows = ( + ('bits', 'Bits', (5,)), + ('fields', 'Fields', (0, 1, 2)), + ('registers', 'Registers', (6, 7)), + ('voltage-updates', 'Voltage updates', (8,)), + ('events', 'Events', (3, 4)), + ('errors', 'Errors', (9,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.bits = [] + self.ss_dac_first = None + self.ss_dac = self.es_dac = 0 + self.ss_gain = self.es_gain = 0 + self.ss_value = self.es_value = 0 + self.dac_select = self.gain = self.dac_value = None + self.dacval = {'A': '?', 'B': '?', 'C': '?', 'D': '?'} + self.gains = {'A': '?', 'B': '?', 'C': '?', 'D': '?'} + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def handle_11bits(self): + # Only look at the last 11 bits, the rest is ignored by the TLC5620. + if len(self.bits) > 11: + self.bits = self.bits[-11:] + + # If there are less than 11 bits, something is probably wrong. + if len(self.bits) < 11: + ss, es = self.samplenum, self.samplenum + if len(self.bits) >= 2: + ss = self.bits[0][1] + es = self.bits[-1][1] + (self.bits[1][1] - self.bits[0][1]) + self.put(ss, es, self.out_ann, [9, ['Command too short']]) + self.bits = [] + return False + + self.ss_dac = self.bits[0][1] + self.es_dac = self.ss_gain = self.bits[2][1] + self.es_gain = self.ss_value = self.bits[3][1] + self.clock_width = self.es_gain - self.ss_gain + self.es_value = self.bits[10][1] + self.clock_width # Guessed. + + if self.ss_dac_first is None: + self.ss_dac_first = self.ss_dac + + s = ''.join(str(i[0]) for i in self.bits[:2]) + self.dac_select = s = dacs[int(s, 2)] + self.put(self.ss_dac, self.es_dac, self.out_ann, + [0, ['DAC select: %s' % s, 'DAC sel: %s' % s, + 'DAC: %s' % s, 'D: %s' % s, s, s[3]]]) + + self.gain = g = 1 + self.bits[2][0] + self.put(self.ss_gain, self.es_gain, self.out_ann, + [1, ['Gain: x%d' % g, 'G: x%d' % g, 'x%d' % g]]) + + s = ''.join(str(i[0]) for i in self.bits[3:]) + self.dac_value = v = int(s, 2) + self.put(self.ss_value, self.es_value, self.out_ann, + [2, ['DAC value: %d' % v, 'Value: %d' % v, 'Val: %d' % v, + 'V: %d' % v, '%d' % v]]) + + # Emit an annotation for each bit. + for i in range(1, 11): + self.put(self.bits[i - 1][1], self.bits[i][1], self.out_ann, + [5, [str(self.bits[i - 1][0])]]) + self.put(self.bits[10][1], self.bits[10][1] + self.clock_width, + self.out_ann, [5, [str(self.bits[10][0])]]) + + self.bits = [] + + return True + + def handle_falling_edge_load(self): + if not self.handle_11bits(): + return + s, v, g = self.dac_select, self.dac_value, self.gain + self.put(self.samplenum, self.samplenum, self.out_ann, + [3, ['Falling edge on LOAD', 'LOAD fall', 'F']]) + vref = self.options['vref_%s' % self.dac_select[3].lower()] + v = '%.2fV' % (vref * (v / 256) * self.gain) + if self.ldac == 0: + # If LDAC is low, the voltage is set immediately. + self.put(self.ss_dac, self.es_value, self.out_ann, + [7, ['Setting %s voltage to %s' % (s, v), + '%s=%s' % (s, v)]]) + else: + # If LDAC is high, the voltage is not set immediately, but rather + # stored in a register. When LDAC goes low all four DAC voltages + # (DAC A/B/C/D) will be set at the same time. + self.put(self.ss_dac, self.es_value, self.out_ann, + [6, ['Setting %s register value to %s' % \ + (s, v), '%s=%s' % (s, v)]]) + # Save the last value the respective DAC was set to. + self.dacval[self.dac_select[-1]] = str(self.dac_value) + self.gains[self.dac_select[-1]] = self.gain + + def handle_falling_edge_ldac(self): + self.put(self.samplenum, self.samplenum, self.out_ann, + [4, ['Falling edge on LDAC', 'LDAC fall', 'LDAC', 'L']]) + + # Don't emit any annotations if we didn't see any register writes. + if self.ss_dac_first is None: + return + + # Calculate voltages based on Vref and the per-DAC gain. + dacval = {} + for key, val in self.dacval.items(): + if val == '?': + dacval[key] = '?' + else: + vref = self.options['vref_%s' % key.lower()] + v = vref * (int(val) / 256) * self.gains[key] + dacval[key] = '%.2fV' % v + + s = ''.join(['DAC%s=%s ' % (d, dacval[d]) for d in 'ABCD']).strip() + self.put(self.ss_dac_first, self.samplenum, self.out_ann, + [8, ['Updating voltages: %s' % s, s, s.replace('DAC', '')]]) + self.ss_dac_first = None + + def handle_new_dac_bit(self, datapin): + self.bits.append([datapin, self.samplenum]) + + def decode(self): + while True: + # DATA is shifted in the DAC on the falling CLK edge (MSB-first). + # A falling edge of LOAD will latch the data. + + # Wait for one (or multiple) of the following conditions: + # a) Falling edge on CLK, and/or + # b) Falling edge on LOAD, and/or + # b) Falling edge on LDAC + (clk, data, load, ldac) = self.wait([{0: 'f'}, {2: 'f'}, {3: 'f'}]) + self.ldac = ldac + + # Handle those conditions (one or more) that matched this time. + if (self.matched & (0b1 << 0)): + self.handle_new_dac_bit(data) + if (self.matched & (0b1 << 1)): + self.handle_falling_edge_load() + if (self.matched & (0b1 << 2)): + self.handle_falling_edge_ldac() diff --git a/libsigrokdecode4DSL/decoders/usb_packet/__init__.py b/libsigrokdecode4DSL/decoders/usb_packet/__init__.py new file mode 100644 index 00000000..5cd7c56b --- /dev/null +++ b/libsigrokdecode4DSL/decoders/usb_packet/__init__.py @@ -0,0 +1,43 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +''' +This decoder stacks on top of the 'usb_signalling' PD and decodes the USB +(low-speed and full-speed) packet protocol. + +Protocol layer (USB spec, chapter 8): + +Bit/byte ordering: Bits are sent onto the bus LSB-first. Multibyte fields +are transmitted in little-endian order (i.e., LSB to MSB). + +SYNC field: All packets begin with a SYNC field (8 bits). + +Packet field format: Packets start with an SOP (Start Of Packet) delimiter +that is part of the SYNC field, and end with an EOP (End Of Packet). + +PID: A PID (packet identifier) follows the SYNC field of every packet. A PID +consists of a 4-bit packet type field, and a 4 bit check field. +The check field is the one's complement of the packet type field. + +Details: +https://en.wikipedia.org/wiki/USB +http://www.usb.org/developers/docs/ +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/usb_packet/pd.py b/libsigrokdecode4DSL/decoders/usb_packet/pd.py new file mode 100644 index 00000000..e262074e --- /dev/null +++ b/libsigrokdecode4DSL/decoders/usb_packet/pd.py @@ -0,0 +1,397 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2011 Gareth McMullin +## Copyright (C) 2012-2014 Uwe Hermann +## +## 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, see . +## + +import sigrokdecode as srd + +''' +OUTPUT_PYTHON format: + +Packet: +[, ] + +, : + - 'SYNC', + - 'PID', + - 'ADDR', + - 'EP', + - 'CRC5', + - 'CRC5 ERROR', + - 'CRC16', + - 'CRC16 ERROR', + - 'EOP', + - 'FRAMENUM', + - 'DATABYTE', + - 'HUBADDR', + - 'SC', + - 'PORT', + - 'S', + - 'E/U', + - 'ET', + - 'PACKET', [, , ] + +, , : + - 'TOKEN', 'OUT', [, , , , , ] + - 'TOKEN', 'IN', [, , , , , ] + - 'TOKEN', 'SOF', [, , , , ] + - 'TOKEN', 'SETUP', [, , , , , ] + - 'DATA', 'DATA0', [, , , , ] + - 'DATA', 'DATA1', [, , , , ] + - 'DATA', 'DATA2', [, , , , ] + - 'DATA', 'MDATA', [, , , , ] + - 'HANDSHAKE', 'ACK', [, , ] + - 'HANDSHAKE', 'NAK', [, , ] + - 'HANDSHAKE', 'STALL', [, , ] + - 'HANDSHAKE', 'NYET', [, , ] + - 'SPECIAL', 'PRE', [, , , , , ] + - 'SPECIAL', 'ERR', [, , ] + - 'SPECIAL', 'SPLIT', + [, , , , , , , , , ] + - 'SPECIAL', 'PING', [, , , , , ] + - 'SPECIAL', 'Reserved', None + +: SYNC field bitstring, normally '00000001' (8 chars). +: Packet ID bitstring, e.g. '11000011' for DATA0 (8 chars). +: Address field number, 0-127 (7 bits). +: Endpoint number, 0-15 (4 bits). +: CRC-5 number (5 bits). +: CRC-16 number (16 bits). +: End of packet marker. List of symbols, usually ['SE0', 'SE0', 'J']. +: USB (micro)frame number, 0-2047 (11 bits). +: A single data byte, e.g. 0x55. +: List of data bytes, e.g. [0x55, 0xaa, 0x99] (0 - 1024 bytes). +: TODO +: TODO +: TODO +: TODO +: TODO +: TODO +''' + +# Packet IDs (PIDs). +# The first 4 bits are the 'packet type' field, the last 4 bits are the +# 'check field' (each bit in the check field must be the inverse of the resp. +# bit in the 'packet type' field; if not, that's a 'PID error'). +# For the 4-bit strings, the left-most '1' or '0' is the LSB, i.e. it's sent +# to the bus first. +pids = { + # Tokens + '10000111': ['OUT', 'Address & EP number in host-to-function transaction'], + '10010110': ['IN', 'Address & EP number in function-to-host transaction'], + '10100101': ['SOF', 'Start-Of-Frame marker & frame number'], + '10110100': ['SETUP', 'Address & EP number in host-to-function transaction for SETUP to a control pipe'], + + # Data + # Note: DATA2 and MDATA are HS-only. + '11000011': ['DATA0', 'Data packet PID even'], + '11010010': ['DATA1', 'Data packet PID odd'], + '11100001': ['DATA2', 'Data packet PID HS, high bandwidth isosynchronous transaction in a microframe'], + '11110000': ['MDATA', 'Data packet PID HS for split and high-bandwidth isosynchronous transactions'], + + # Handshake + '01001011': ['ACK', 'Receiver accepts error-free packet'], + '01011010': ['NAK', 'Receiver cannot accept or transmitter cannot send'], + '01111000': ['STALL', 'EP halted or control pipe request unsupported'], + '01101001': ['NYET', 'No response yet from receiver'], + + # Special + '00111100': ['PRE', 'Host-issued preamble; enables downstream bus traffic to low-speed devices'], + #'00111100': ['ERR', 'Split transaction error handshake'], + '00011110': ['SPLIT', 'HS split transaction token'], + '00101101': ['PING', 'HS flow control probe for a bulk/control EP'], + '00001111': ['Reserved', 'Reserved PID'], +} + +def get_category(pidname): + if pidname in ('OUT', 'IN', 'SOF', 'SETUP'): + return 'TOKEN' + elif pidname in ('DATA0', 'DATA1', 'DATA2', 'MDATA'): + return 'DATA' + elif pidname in ('ACK', 'NAK', 'STALL', 'NYET'): + return 'HANDSHAKE' + else: + return 'SPECIAL' + +def ann_index(pidname): + l = ['OUT', 'IN', 'SOF', 'SETUP', 'DATA0', 'DATA1', 'DATA2', 'MDATA', + 'ACK', 'NAK', 'STALL', 'NYET', 'PRE', 'ERR', 'SPLIT', 'PING', + 'Reserved'] + if pidname not in l: + return 28 + return l.index(pidname) + 11 + +def bitstr_to_num(bitstr): + if not bitstr: + return 0 + l = list(bitstr) + l.reverse() + return int(''.join(l), 2) + +def reverse_number(num, count): + out = list(count * '0') + for i in range(0, count): + if num >> i & 1: + out[i] = '1' + return int(''.join(out), 2) + +def calc_crc5(bitstr): + poly5 = 0x25 + crc5 = 0x1f + for bit in bitstr: + crc5 <<= 1 + if int(bit) != (crc5 >> 5): + crc5 ^= poly5 + crc5 &= 0x1f + crc5 ^= 0x1f + return reverse_number(crc5, 5) + +def calc_crc16(bitstr): + poly16 = 0x18005 + crc16 = 0xffff + for bit in bitstr: + crc16 <<= 1 + if int(bit) != (crc16 >> 16): + crc16 ^= poly16 + crc16 &= 0xffff + crc16 ^= 0xffff + return reverse_number(crc16, 16) + +class Decoder(srd.Decoder): + api_version = 3 + id = 'usb_packet' + name = 'USB packet' + longname = 'Universal Serial Bus (LS/FS) packet' + desc = 'USB (low-speed and full-speed) packet protocol.' + license = 'gplv2+' + inputs = ['usb_signalling'] + outputs = ['usb_packet'] + tags = ['PC'] + options = ( + {'id': 'signalling', 'desc': 'Signalling', + 'default': 'full-speed', 'values': ('full-speed', 'low-speed')}, + ) + annotations = ( + ('sync-ok', 'SYNC'), + ('sync-err', 'SYNC (error)'), + ('pid', 'PID'), + ('framenum', 'FRAMENUM'), + ('addr', 'ADDR'), + ('ep', 'EP'), + ('crc5-ok', 'CRC5'), + ('crc5-err', 'CRC5 (error)'), + ('data', 'DATA'), + ('crc16-ok', 'CRC16'), + ('crc16-err', 'CRC16 (error)'), + ('packet-out', 'Packet: OUT'), + ('packet-in', 'Packet: IN'), + ('packet-sof', 'Packet: SOF'), + ('packet-setup', 'Packet: SETUP'), + ('packet-data0', 'Packet: DATA0'), + ('packet-data1', 'Packet: DATA1'), + ('packet-data2', 'Packet: DATA2'), + ('packet-mdata', 'Packet: MDATA'), + ('packet-ack', 'Packet: ACK'), + ('packet-nak', 'Packet: NAK'), + ('packet-stall', 'Packet: STALL'), + ('packet-nyet', 'Packet: NYET'), + ('packet-pre', 'Packet: PRE'), + ('packet-err', 'Packet: ERR'), + ('packet-split', 'Packet: SPLIT'), + ('packet-ping', 'Packet: PING'), + ('packet-reserved', 'Packet: Reserved'), + ('packet-invalid', 'Packet: Invalid'), + ) + annotation_rows = ( + ('fields', 'Packet fields', tuple(range(10 + 1))), + ('packet', 'Packets', tuple(range(11, 28 + 1))), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.bits = [] + self.packet = [] + self.packet_summary = '' + self.ss = self.es = None + self.ss_packet = self.es_packet = None + self.state = 'WAIT FOR SOP' + + def putpb(self, data): + self.put(self.ss, self.es, self.out_python, data) + + def putb(self, data): + self.put(self.ss, self.es, self.out_ann, data) + + def putpp(self, data): + self.put(self.ss_packet, self.es_packet, self.out_python, data) + + def putp(self, data): + self.put(self.ss_packet, self.es_packet, self.out_ann, data) + + def start(self): + self.out_python = self.register(srd.OUTPUT_PYTHON) + self.out_ann = self.register(srd.OUTPUT_ANN) + + def handle_packet(self): + packet = '' + for (bit, ss, es) in self.bits: + packet += bit + + if len(packet) < 8: + self.putp([28, ['Invalid packet (shorter than 8 bits)']]) + return + + # Bits[0:7]: SYNC + sync = packet[:7 + 1] + self.ss, self.es = self.bits[0][1], self.bits[7][2] + # The SYNC pattern for low-speed/full-speed is KJKJKJKK (00000001). + if sync != '00000001': + self.putpb(['SYNC ERROR', sync]) + self.putb([1, ['SYNC ERROR: %s' % sync, 'SYNC ERR: %s' % sync, + 'SYNC ERR', 'SE', 'S']]) + else: + self.putpb(['SYNC', sync]) + self.putb([0, ['SYNC: %s' % sync, 'SYNC', 'S']]) + self.packet.append(sync) + + if len(packet) < 16: + self.putp([28, ['Invalid packet (shorter than 16 bits)']]) + return + + # Bits[8:15]: PID + pid = packet[8:15 + 1] + pidname = pids.get(pid, ('UNKNOWN', 'Unknown PID'))[0] + self.ss, self.es = self.bits[8][1], self.bits[15][2] + self.putpb(['PID', pidname]) + self.putb([2, ['PID: %s' % pidname, pidname, pidname[0]]]) + self.packet.append(pid) + self.packet_summary += pidname + + if pidname in ('OUT', 'IN', 'SOF', 'SETUP', 'PING'): + if len(packet) < 32: + self.putp([28, ['Invalid packet (shorter than 32 bits)']]) + return + + if pidname == 'SOF': + # Bits[16:26]: Framenum + framenum = bitstr_to_num(packet[16:26 + 1]) + self.ss, self.es = self.bits[16][1], self.bits[26][2] + self.putpb(['FRAMENUM', framenum]) + self.putb([3, ['Frame: %d' % framenum, 'Frame', 'Fr', 'F']]) + self.packet.append(framenum) + self.packet_summary += ' %d' % framenum + else: + # Bits[16:22]: Addr + addr = bitstr_to_num(packet[16:22 + 1]) + self.ss, self.es = self.bits[16][1], self.bits[22][2] + self.putpb(['ADDR', addr]) + self.putb([4, ['Address: %d' % addr, 'Addr: %d' % addr, + 'Addr', 'A']]) + self.packet.append(addr) + self.packet_summary += ' ADDR %d' % addr + + # Bits[23:26]: EP + ep = bitstr_to_num(packet[23:26 + 1]) + self.ss, self.es = self.bits[23][1], self.bits[26][2] + self.putpb(['EP', ep]) + self.putb([5, ['Endpoint: %d' % ep, 'EP: %d' % ep, 'EP', 'E']]) + self.packet.append(ep) + self.packet_summary += ' EP %d' % ep + + # Bits[27:31]: CRC5 + crc5 = bitstr_to_num(packet[27:31 + 1]) + crc5_calc = calc_crc5(packet[16:27]) + self.ss, self.es = self.bits[27][1], self.bits[31][2] + if crc5 == crc5_calc: + self.putpb(['CRC5', crc5]) + self.putb([6, ['CRC5: 0x%02X' % crc5, 'CRC5', 'C']]) + else: + self.putpb(['CRC5 ERROR', crc5]) + self.putb([7, ['CRC5 ERROR: 0x%02X' % crc5, 'CRC5 ERR', 'CE', 'C']]) + self.packet.append(crc5) + elif pidname in ('DATA0', 'DATA1', 'DATA2', 'MDATA'): + # Bits[16:packetlen-16]: Data + data = packet[16:-16] + # TODO: len(data) must be a multiple of 8. + databytes = [] + self.packet_summary += ' [' + for i in range(0, len(data), 8): + db = bitstr_to_num(data[i:i + 8]) + self.ss, self.es = self.bits[16 + i][1], self.bits[23 + i][2] + self.putpb(['DATABYTE', db]) + self.putb([8, ['Databyte: %02X' % db, 'Data: %02X' % db, + 'DB: %02X' % db, '%02X' % db]]) + databytes.append(db) + self.packet_summary += ' %02X' % db + self.packet_summary += ' ]' + + # Convenience Python output (no annotation) for all bytes together. + self.ss, self.es = self.bits[16][1], self.bits[-16][2] + self.putpb(['DATABYTES', databytes]) + self.packet.append(databytes) + + # Bits[packetlen-16:packetlen]: CRC16 + crc16 = bitstr_to_num(packet[-16:]) + crc16_calc = calc_crc16(packet[16:-16]) + self.ss, self.es = self.bits[-16][1], self.bits[-1][2] + if crc16 == crc16_calc: + self.putpb(['CRC16', crc16]) + self.putb([9, ['CRC16: 0x%04X' % crc16, 'CRC16', 'C']]) + else: + self.putpb(['CRC16 ERROR', crc16]) + self.putb([10, ['CRC16 ERROR: 0x%04X' % crc16, 'CRC16 ERR', 'CE', 'C']]) + self.packet.append(crc16) + elif pidname in ('ACK', 'NAK', 'STALL', 'NYET', 'ERR'): + pass # Nothing to do, these only have SYNC+PID+EOP fields. + elif pidname in ('PRE'): + pass # Nothing to do, PRE only has SYNC+PID fields. + else: + pass # TODO: Handle 'SPLIT' and possibly 'Reserved' packets. + + # Output a (summary of) the whole packet. + pcategory, pname, pinfo = get_category(pidname), pidname, self.packet + self.putpp(['PACKET', [pcategory, pname, pinfo]]) + self.putp([ann_index(pidname), ['%s' % self.packet_summary]]) + + self.packet, self.packet_summary = [], '' + + def decode(self, ss, es, data): + (ptype, pdata) = data + + # We only care about certain packet types for now. + if ptype not in ('SOP', 'BIT', 'EOP', 'ERR'): + return + + # State machine. + if self.state == 'WAIT FOR SOP': + if ptype != 'SOP': + return + self.ss_packet = ss + self.state = 'GET BIT' + elif self.state == 'GET BIT': + if ptype == 'BIT': + self.bits.append([pdata, ss, es]) + elif ptype == 'EOP' or ptype == 'ERR': + self.es_packet = es + self.handle_packet() + self.packet, self.packet_summary = [], '' + self.bits, self.state = [], 'WAIT FOR SOP' + else: + pass # TODO: Error diff --git a/libsigrokdecode4DSL/decoders/usb_power_delivery/__init__.py b/libsigrokdecode4DSL/decoders/usb_power_delivery/__init__.py new file mode 100644 index 00000000..43dfd5d6 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/usb_power_delivery/__init__.py @@ -0,0 +1,24 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Google, Inc +## +## 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, see . +## + +''' +USB Power Delivery - baseband protocol decoder / checker. +''' + +from .pd import * diff --git a/libsigrokdecode4DSL/decoders/usb_power_delivery/pd.py b/libsigrokdecode4DSL/decoders/usb_power_delivery/pd.py new file mode 100644 index 00000000..45077f27 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/usb_power_delivery/pd.py @@ -0,0 +1,639 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Google, Inc +## Copyright (C) 2018 davidanger +## Copyright (C) 2018 Peter Hazenberg +## +## 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, see . +## + +import sigrokdecode as srd +import struct +import zlib # for crc32 + +# BMC encoding with a 600kHz datarate +UI_US = 1000000/600000.0 + +# Threshold to discriminate half-1 from 0 in Binary Mark Conding +THRESHOLD_US = (UI_US + 2 * UI_US) / 2 + +# Control Message type +CTRL_TYPES = { + 0: 'reserved', + 1: 'GOOD CRC', + 2: 'GOTO MIN', + 3: 'ACCEPT', + 4: 'REJECT', + 5: 'PING', + 6: 'PS RDY', + 7: 'GET SOURCE CAP', + 8: 'GET SINK CAP', + 9: 'DR SWAP', + 10: 'PR SWAP', + 11: 'VCONN SWAP', + 12: 'WAIT', + 13: 'SOFT RESET', + 14: 'reserved', + 15: 'reserved', + 16: 'Not Supported', + 17: 'Get_Source_Cap_Extended', + 18: 'Get_Status', + 19: 'FR_Swap', + 20: 'Get_PPS_Status', + 21: 'Get_Country_Codes', +} + +# Data message type +DATA_TYPES = { + 1: 'SOURCE CAP', + 2: 'REQUEST', + 3: 'BIST', + 4: 'SINK CAP', + 5: 'Battery_Status', + 6: 'Alert', + 7: 'Get_Country_Info', + 15: 'VDM' +} + +# 4b5b encoding of the symbols +DEC4B5B = [ + 0x10, # Error 00000 + 0x10, # Error 00001 + 0x10, # Error 00010 + 0x10, # Error 00011 + 0x10, # Error 00100 + 0x10, # Error 00101 + 0x13, # Sync-3 00110 + 0x14, # RST-1 00111 + 0x10, # Error 01000 + 0x01, # 1 = 0001 01001 + 0x04, # 4 = 0100 01010 + 0x05, # 5 = 0101 01011 + 0x10, # Error 01100 + 0x16, # EOP 01101 + 0x06, # 6 = 0110 01110 + 0x07, # 7 = 0111 01111 + 0x10, # Error 10000 + 0x12, # Sync-2 10001 + 0x08, # 8 = 1000 10010 + 0x09, # 9 = 1001 10011 + 0x02, # 2 = 0010 10100 + 0x03, # 3 = 0011 10101 + 0x0A, # A = 1010 10110 + 0x0B, # B = 1011 10111 + 0x11, # Sync-1 11000 + 0x15, # RST-2 11001 + 0x0C, # C = 1100 11010 + 0x0D, # D = 1101 11011 + 0x0E, # E = 1110 11100 + 0x0F, # F = 1111 11101 + 0x00, # 0 = 0000 11110 + 0x10, # Error 11111 +] +SYM_ERR = 0x10 +SYNC1 = 0x11 +SYNC2 = 0x12 +SYNC3 = 0x13 +RST1 = 0x14 +RST2 = 0x15 +EOP = 0x16 +SYNC_CODES = [SYNC1, SYNC2, SYNC3] +HRST_CODES = [RST1, RST1, RST1, RST2] + +SOP_SEQUENCES = [ + (SYNC1, SYNC1, SYNC1, SYNC2), + (SYNC1, SYNC1, SYNC3, SYNC3), + (SYNC1, SYNC3, SYNC1, SYNC3), + (SYNC1, RST2, RST2, SYNC3), + (SYNC1, RST2, SYNC3, SYNC2), + (RST1, SYNC1, RST1, SYNC3), + (RST1, RST1, RST1, RST2), +] +START_OF_PACKETS = { + SOP_SEQUENCES[0]: 'SOP', + SOP_SEQUENCES[1]: "SOP'", + SOP_SEQUENCES[2]: 'SOP"', + SOP_SEQUENCES[3]: "SOP' Debug", + SOP_SEQUENCES[4]: 'SOP" Debug', + SOP_SEQUENCES[5]: 'Cable Reset', + SOP_SEQUENCES[6]: 'Hard Reset', +} + +SYM_NAME = [ + ['0x0', '0'], + ['0x1', '1'], + ['0x2', '2'], + ['0x3', '3'], + ['0x4', '4'], + ['0x5', '5'], + ['0x6', '6'], + ['0x7', '7'], + ['0x8', '8'], + ['0x9', '9'], + ['0xA', 'A'], + ['0xB', 'B'], + ['0xC', 'C'], + ['0xD', 'D'], + ['0xE', 'E'], + ['0xF', 'F'], + ['ERROR', 'X'], + ['SYNC-1', 'S1'], + ['SYNC-2', 'S2'], + ['SYNC-3', 'S3'], + ['RST-1', 'R1'], + ['RST-2', 'R2'], + ['EOP', '#'], +] + +RDO_FLAGS = { + (1 << 23): 'unchunked', + (1 << 24): 'no_suspend', + (1 << 25): 'comm_cap', + (1 << 26): 'cap_mismatch', + (1 << 27): 'give_back' +} + +BIST_MODES = { + 0: 'Receiver', + 1: 'Transmit', + 2: 'Counters', + 3: 'Carrier 0', + 4: 'Carrier 1', + 5: 'Carrier 2', + 6: 'Carrier 3', + 7: 'Eye', +} + +VDM_CMDS = { + 1: 'Disc Ident', + 2: 'Disc SVID', + 3: 'Disc Mode', + 4: 'Enter Mode', + 5: 'Exit Mode', + 6: 'Attention', + # 16..31: SVID Specific Commands + # DisplayPort Commands + 16: 'DP Status', + 17: 'DP Configure', +} +VDM_ACK = ['REQ', 'ACK', 'NAK', 'BSY'] + + +class SamplerateError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = 'usb_power_delivery' + name = 'USB PD' + longname = 'USB Power Delivery' + desc = 'USB Power Delivery protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = ['usb_pd'] + tags = ['PC'] + channels = ( + {'id': 'cc1', 'name': 'CC1', 'desc': 'Configuration Channel 1'}, + ) + optional_channels = ( + {'id': 'cc2', 'name': 'CC2', 'desc': 'Configuration Channel 2'}, + ) + options = ( + {'id': 'fulltext', 'desc': 'Full text decoding of packets', + 'default': 'no', 'values': ('yes', 'no')}, + ) + annotations = ( + ('type', 'Packet Type'), + ('preamble', 'Preamble'), + ('sop', 'Start of Packet'), + ('header', 'Header'), + ('data', 'Data'), + ('crc', 'Checksum'), + ('eop', 'End Of Packet'), + ('sym', '4b5b symbols'), + ('warnings', 'Warnings'), + ('src', 'Source Message'), + ('snk', 'Sink Message'), + ('payload', 'Payload'), + ('text', 'Plain text'), + ) + annotation_rows = ( + ('4b5b', 'Symbols', (7,)), + ('phase', 'Parts', (1, 2, 3, 4, 5, 6)), + ('payload', 'Payload', (11,)), + ('type', 'Type', (0, 9, 10)), + ('warnings', 'Warnings', (8,)), + ('text', 'Full text', (12,)), + ) + binary = ( + ('raw-data', 'RAW binary data'), + ) + + stored_pdos = {} + + def get_request(self, rdo): + pos = (rdo >> 28) & 7 + + op_ma = ((rdo >> 10) & 0x3ff) * 0.01 + max_ma = (rdo & 0x3ff) * 0.01 + + mark = self.cap_mark[pos] + if mark == 3: + op_v = ((rdo >> 9) & 0x7ff) * 0.02 + op_a = (rdo & 0x3f) * 0.05 + t_settings = '%gV %gA' % (op_v, op_a) + elif mark == 2: + op_w = ((rdo >> 10) & 0x3ff) * 0.25 + mp_w = (rdo & 0x3ff) * 0.25 + t_settings = '%gW (operating)' % op_w + else: + op_a = ((rdo >> 10) & 0x3ff) * 0.01 + max_a = (rdo & 0x3ff) * 0.01 + t_settings = '%gA (operating) / %gA (max)' % (op_a, max_a) + + t_flags = '' + for f in sorted(RDO_FLAGS.keys(), reverse = True): + if rdo & f: + t_flags += ' [' + RDO_FLAGS[f] + ']' + + if pos in self.stored_pdos.keys(): + t_pdo = '#%d: %s' % (pos, self.stored_pdos[pos]) + else: + t_pdo = '#%d' % (pos) + + return '(PDO %s) %s%s' % (t_pdo, t_settings, t_flags) + + def get_source_sink_cap(self, pdo, idx, source): + t1 = (pdo >> 30) & 3 + self.cap_mark[idx] = t1 + + flags = {} + if t1 == 0: + t_name = 'Fixed' + if source: + flags = { + (1 << 29): 'dual_role_power', + (1 << 28): 'suspend', + (1 << 27): 'unconstrained', + (1 << 26): 'comm_cap', + (1 << 25): 'dual_role_data', + (1 << 24): 'unchunked', + } + else: # Sink + flags = { + (1 << 29): 'dual_role_power', + (1 << 28): 'high_capability', + (1 << 27): 'unconstrained', + (1 << 26): 'comm_cap', + (1 << 25): 'dual_role_data', + (0b01 << 23): 'fr_swap default power', + (0b10 << 23): 'fr_swap 1.5 A', + (0b11 << 23): 'fr_swap 3.0 A', + } + mv = ((pdo >> 10) & 0x3ff) * 0.05 + ma = ((pdo >> 0) & 0x3ff) * 0.01 + p = '%gV %gA (%gW)' % (mv, ma, mv*ma) + self.stored_pdos[idx] = '%s %gV' % (t_name, mv) + elif t1 == 1: + t_name = 'Battery' + flags = {} # No flags defined for Battery PDO in PD 3.0 spec + minv = ((pdo >> 10) & 0x3ff) * 0.05 + maxv = ((pdo >> 20) & 0x3ff) * 0.05 + mw = ((pdo >> 0) & 0x3ff) * 0.25 + p = '%g/%gV %gW' % (minv, maxv, mw) + self.stored_pdos[idx] = '%s %g/%gV' % (t_name, minv, maxv) + elif t1 == 2: + t_name = 'Variable' + flags = {} # No flags defined for Variable PDO in PD 3.0 spec + minv = ((pdo >> 10) & 0x3ff) * 0.05 + maxv = ((pdo >> 20) & 0x3ff) * 0.05 + ma = ((pdo >> 0) & 0x3ff) * 0.01 + p = '%g/%gV %gA' % (minv, maxv, ma) + self.stored_pdos[idx] = '%s %g/%gV' % (t_name, minv, maxv) + elif t1 == 3: + t2 = (pdo >> 28) & 3 + if t2 == 0: + t_name = 'Programmable|PPS' + flags = { + (1 << 29): 'power_limited', + } + minv = ((pdo >> 8) & 0xff) * 0.1 + maxv = ((pdo >> 17) & 0xff) * 0.1 + ma = ((pdo >> 0) & 0xff) * 0.05 + p = '%g/%gV %gA' % (minv, maxv, ma) + if (pdo >> 27) & 0x1: + p += ' [limited]' + self.stored_pdos[idx] = '%s %g/%gV' % (t_name, minv, maxv) + else: + t_name = 'Reserved APDO: '+bin(t2) + p = '[raw: %s]' % (bin(pdo)) + self.stored_pdos[idx] = '%s %s' % (t_name, p) + t_flags = '' + for f in sorted(flags.keys(), reverse = True): + if pdo & f: + t_flags += ' [' + flags[f] + ']' + return '[%s] %s%s' % (t_name, p, t_flags) + + def get_vdm(self, idx, data): + if idx == 0: # VDM header + vid = data >> 16 + struct = data & (1 << 15) + txt = 'VDM' + if struct: # Structured VDM + cmd = data & 0x1f + src = data & (1 << 5) + ack = (data >> 6) & 3 + pos = (data >> 8) & 7 + ver = (data >> 13) & 3 + txt = VDM_ACK[ack] + ' ' + txt += VDM_CMDS[cmd] if cmd in VDM_CMDS else 'cmd?' + txt += ' pos %d' % (pos) if pos else ' ' + else: # Unstructured VDM + txt = 'unstruct [%04x]' % (data & 0x7fff) + txt += ' SVID:%04x' % (vid) + else: # VDM payload + txt = 'VDO:%08x' % (data) + return txt + + def get_bist(self, idx, data): + mode = data >> 28 + counter = data & 0xffff + mode_name = BIST_MODES[mode] if mode in BIST_MODES else 'INVALID' + if mode == 2: + mode_name = 'Counter[= %d]' % (counter) + # TODO: Check all 0 bits are 0 / emit warnings. + return 'mode %s' % (mode_name) if idx == 0 else 'invalid BRO' + + def putpayload(self, s0, s1, idx): + t = self.head_type() + txt = '['+str(idx+1)+'] ' + if t == 2: + txt += self.get_request(self.data[idx]) + elif t == 1 or t == 4: + txt += self.get_source_sink_cap(self.data[idx], idx+1, t==1) + elif t == 15: + txt += self.get_vdm(idx, self.data[idx]) + elif t == 3: + txt += self.get_bist(idx, self.data[idx]) + self.putx(s0, s1, [11, [txt, txt]]) + self.text += ' - ' + txt + + def puthead(self): + ann_type = 9 if self.head_power_role() else 10 + role = 'SRC' if self.head_power_role() else 'SNK' + if self.head_data_role() != self.head_power_role(): + role += '/DFP' if self.head_data_role() else '/UFP' + t = self.head_type() + if self.head_count() == 0: + shortm = CTRL_TYPES[t] + else: + shortm = DATA_TYPES[t] if t in DATA_TYPES else 'DAT???' + + longm = '(r{:d}) {:s}[{:d}]: {:s}'.format(self.head_rev(), role, self.head_id(), shortm) + self.putx(0, -1, [ann_type, [longm, shortm]]) + self.text += longm + + def head_id(self): + return (self.head >> 9) & 7 + + def head_power_role(self): + return (self.head >> 8) & 1 + + def head_data_role(self): + return (self.head >> 5) & 1 + + def head_rev(self): + return ((self.head >> 6) & 3) + 1 + + def head_type(self): + return self.head & 0xF + + def head_count(self): + return (self.head >> 12) & 7 + + def putx(self, s0, s1, data): + self.put(self.edges[s0], self.edges[s1], self.out_ann, data) + + def putwarn(self, longm, shortm): + self.putx(0, -1, [8, [longm, shortm]]) + + def compute_crc32(self): + bdata = struct.pack('= 3: + return START_OF_PACKETS[seq] + return None + + def scan_eop(self): + for i in range(len(self.bits) - 19): + k = (self.get_sym(i, rec=False), self.get_sym(i+5, rec=False), + self.get_sym(i+10, rec=False), self.get_sym(i+15, rec=False)) + sym = START_OF_PACKETS.get(k, None) + if not sym: + sym = self.find_corrupted_sop(k) + # We have an interesting symbol sequence. + if sym: + # Annotate the preamble. + self.putx(0, i, [1, ['Preamble', '...']]) + # Annotate each symbol. + self.rec_sym(i, k[0]) + self.rec_sym(i+5, k[1]) + self.rec_sym(i+10, k[2]) + self.rec_sym(i+15, k[3]) + if sym == 'Hard Reset': + self.text += 'HRST' + return -1 # Hard reset + elif sym == 'Cable Reset': + self.text += 'CRST' + return -1 # Cable reset + else: + self.putx(i, i+20, [2, [sym, 'S']]) + return i+20 + self.putx(0, len(self.bits), [1, ['Junk???', 'XXX']]) + self.text += 'Junk???' + self.putwarn('No start of packet found', 'XXX') + return -1 # No Start Of Packet + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.idx = 0 + self.packet_seq = 0 + self.previous = 0 + self.startsample = None + self.bits = [] + self.edges = [] + self.bad = [] + self.half_one = False + self.start_one = 0 + self.stored_pdos = {} + self.cap_mark = [0, 0, 0, 0, 0, 0, 0, 0] + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + # 0 is 2 UI, space larger than 1.5x 0 is definitely wrong. + self.maxbit = self.us2samples(3 * UI_US) + # Duration threshold between half 1 and 0. + self.threshold = self.us2samples(THRESHOLD_US) + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_binary = self.register(srd.OUTPUT_BINARY) + self.out_bitrate = self.register( + srd.OUTPUT_META, + meta=(int, 'Bitrate', 'Bitrate during the packet') + ) + + def us2samples(self, us): + return int(us * self.samplerate / 1000000) + + def decode_packet(self): + self.data = [] + self.idx = 0 + self.text = '' + + if len(self.edges) < 50: + return # Not a real PD packet + + self.packet_seq += 1 + tstamp = float(self.startsample) / self.samplerate + self.text += '#%-4d (%8.6fms): ' % (self.packet_seq, tstamp*1000) + + self.idx = self.scan_eop() + if self.idx < 0: + # Full text trace of the issue. + self.putx(0, self.idx, [12, [self.text, '...']]) + return # No real packet: ABORT. + + # Packet header + self.head = self.get_short() + self.putx(self.idx-20, self.idx, [3, ['H:%04x' % (self.head), 'HD']]) + self.puthead() + + # Decode data payload + for i in range(self.head_count()): + self.data.append(self.get_word()) + self.putx(self.idx-40, self.idx, + [4, ['[%d]%08x' % (i, self.data[i]), 'D%d' % (i)]]) + self.putpayload(self.idx-40, self.idx, i) + + # CRC check + self.crc = self.get_word() + ccrc = self.compute_crc32() + if self.crc != ccrc: + self.putwarn('Bad CRC %08x != %08x' % (self.crc, ccrc), 'CRC!') + self.putx(self.idx-40, self.idx, [5, ['CRC:%08x' % (self.crc), 'CRC']]) + + # End of Packet + if len(self.bits) >= self.idx + 5 and self.get_sym(self.idx) == EOP: + self.putx(self.idx, self.idx + 5, [6, ['EOP', 'E']]) + self.idx += 5 + else: + self.putwarn('No EOP', 'EOP!') + # Full text trace + if self.options['fulltext'] == 'yes': + self.putx(0, self.idx, [12, [self.text, '...']]) + + # Meta data for bitrate + ss, es = self.edges[0], self.edges[-1] + bitrate = self.samplerate*len(self.bits) / float(es - ss) + self.put(es, ss, self.out_bitrate, int(bitrate)) + # Raw binary data (BMC decoded) + self.put(es, ss, self.out_binary, [0, bytes(self.bits)]) + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + while True: + self.wait([{0: 'e'}, {1: 'e'}, {'skip': int(self.samplerate/1e3)}]) + + # First sample of the packet, just record the start date. + if not self.startsample: + self.startsample = self.samplenum + self.previous = self.samplenum + continue + + diff = self.samplenum - self.previous + + # Large idle: use it as the end of packet. + if diff > self.maxbit: + # The last edge of the packet. + self.edges.append(self.previous) + # Export the packet. + self.decode_packet() + # Reset for next packet. + self.startsample = self.samplenum + self.bits = [] + self.edges = [] + self.bad = [] + self.half_one = False + self.start_one = 0 + else: # Add the bit to the packet. + is_zero = diff > self.threshold + if is_zero and not self.half_one: + self.bits.append(0) + self.edges.append(self.previous) + elif not is_zero and self.half_one: + self.bits.append(1) + self.edges.append(self.start_one) + self.half_one = False + elif not is_zero and not self.half_one: + self.half_one = True + self.start_one = self.previous + else: # Invalid BMC sequence + self.bad.append((self.start_one, self.previous)) + # TODO: Try to recover. + self.bits.append(0) + self.edges.append(self.previous) + self.half_one = False + self.previous = self.samplenum diff --git a/libsigrokdecode4DSL/decoders/usb_request/__init__.py b/libsigrokdecode4DSL/decoders/usb_request/__init__.py new file mode 100644 index 00000000..66723dc2 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/usb_request/__init__.py @@ -0,0 +1,49 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Stefan Brüns +## +## 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, see . +## + +''' +This decoder stacks on top of the 'usb_packet' PD and decodes the USB +(low-speed and full-speed) transactions. + +Transactions and requests are tracked per device address and endpoint. + +Tracking of CONTROL requests is quite accurate, as these always start with +a SETUP token and are completed by an IN or OUT transaction, the status +packet. All transactions during the DATA stage are combined. + +For BULK and INTERRUPT requests, each transaction starts with an IN or OUT +request, and is considered completed after the first transaction containing +data has been ACKed. Normally a request is only completed after a short or +zero length packet, but this would require knowledge about the max packet +size of an endpoint. + +All INTERRUPT requests are treated as BULK requests, as on the link layer +both are identical. + +The PCAP binary output contains 'SUBMIT' and 'COMPLETE' records. For +CONTROL request, the SUBMIT contains the SETUP request, the data is +either contained in the SUBMIT (Host-to-Device) or the COMPLETE +(Device-to-Host) record. + +Details: +https://en.wikipedia.org/wiki/USB +http://www.usb.org/developers/docs/ +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/usb_request/pd.py b/libsigrokdecode4DSL/decoders/usb_request/pd.py new file mode 100644 index 00000000..49b0b350 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/usb_request/pd.py @@ -0,0 +1,371 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Stefan Brüns +## +## 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, see . +## + +import sigrokdecode as srd +import struct + +class SamplerateError(Exception): + pass + +class pcap_usb_pkt(): + # Linux usbmon format, see Documentation/usb/usbmon.txt + h = b'\x00\x00\x00\x00' # ID part 1 + h += b'\x00\x00\x00\x00' # ID part 2 + h += b'C' # 'S'ubmit / 'C'omplete / 'E'rror + h += b'\x03' # ISO (0), Intr, Control, Bulk (3) + h += b'\x00' # Endpoint + h += b'\x00' # Device address + h += b'\x00\x00' # Bus number + h += b'-' # Setup tag - 0: Setup present, '-' otherwise + h += b'<' # Data tag - '<' no data, 0 otherwise + # Timestamp + h += b'\x00\x00\x00\x00' # TS seconds part 1 + h += b'\x00\x00\x00\x00' # TS seconds part 2 + h += b'\x00\x00\x00\x00' # TS useconds + # + h += b'\x00\x00\x00\x00' # Status 0: OK + h += b'\x00\x00\x00\x00' # URB length + h += b'\x00\x00\x00\x00' # Data length + # Setup packet data, valid if setup tag == 0 + h += b'\x00' # bmRequestType + h += b'\x00' # bRequest + h += b'\x00\x00' # wValue + h += b'\x00\x00' # wIndex + h += b'\x00\x00' # wLength + # + h += b'\x00\x00\x00\x00' # ISO/interrupt interval + h += b'\x00\x00\x00\x00' # ISO start frame + h += b'\x00\x00\x00\x00' # URB flags + h += b'\x00\x00\x00\x00' # Number of ISO descriptors + + def __init__(self, req, ts, is_submit): + self.header = bytearray(pcap_usb_pkt.h) + self.data = b'' + self.set_urbid(req['id']) + self.set_urbtype('S' if is_submit else 'C') + self.set_timestamp(ts) + self.set_addr_ep(req['addr'], req['ep']) + if req['type'] in ('SETUP IN', 'SETUP OUT'): + self.set_transfertype(2) # Control + self.set_setup(req['setup_data']) + if req['type'] in ('BULK IN'): + self.set_addr_ep(req['addr'], 0x80 | req['ep']) + self.set_data(req['data']) + + def set_urbid(self, urbid): + self.header[4:8] = struct.pack('>I', urbid) + + def set_urbtype(self, urbtype): + self.header[8] = ord(urbtype) + + def set_transfertype(self, transfertype): + self.header[9] = transfertype + + def set_addr_ep(self, addr, ep): + self.header[11] = addr + self.header[10] = ep + + def set_timestamp(self, ts): + self.timestamp = ts + self.header[20:24] = struct.pack('>I', ts[0]) # seconds + self.header[24:28] = struct.pack('>I', ts[1]) # microseconds + + def set_data(self, data): + self.data = data + self.header[15] = 0 + self.header[36:40] = struct.pack('>I', len(data)) + + def set_setup(self, data): + self.header[14] = 0 + self.header[40:48] = data + + def packet(self): + return bytes(self.header) + bytes(self.data) + + def record_header(self): + # See https://wiki.wireshark.org/Development/LibpcapFileFormat. + (secs, usecs) = self.timestamp + h = struct.pack('>I', secs) # TS seconds + h += struct.pack('>I', usecs) # TS microseconds + # No truncation, so both lengths are the same. + h += struct.pack('>I', len(self)) # Captured len (usb hdr + data) + h += struct.pack('>I', len(self)) # Original len + return h + + def __len__(self): + return 64 + len(self.data) + +class Decoder(srd.Decoder): + api_version = 3 + id = 'usb_request' + name = 'USB request' + longname = 'Universal Serial Bus (LS/FS) transaction/request' + desc = 'USB (low-speed/full-speed) transaction/request protocol.' + license = 'gplv2+' + inputs = ['usb_packet'] + outputs = ['usb_request'] + tags = ['PC'] + annotations = ( + ('request-setup-read', 'Setup: Device-to-host'), + ('request-setup-write', 'Setup: Host-to-device'), + ('request-bulk-read', 'Bulk: Device-to-host'), + ('request-bulk-write', 'Bulk: Host-to-device'), + ('errors', 'Unexpected packets'), + ) + annotation_rows = ( + ('request', 'USB requests', tuple(range(4))), + ('errors', 'Errors', (4,)), + ) + binary = ( + ('pcap', 'PCAP format'), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.request = {} + self.request_id = 0 + self.transaction_state = 'IDLE' + self.ss_transaction = None + self.es_transaction = None + self.transaction_ep = None + self.transaction_addr = None + self.wrote_pcap_header = False + + def putr(self, ss, es, data): + self.put(ss, es, self.out_ann, data) + + def putb(self, ts, data): + self.put(ts, ts, self.out_binary, data) + + def pcap_global_header(self): + # See https://wiki.wireshark.org/Development/LibpcapFileFormat. + h = b'\xa1\xb2\xc3\xd4' # Magic, indicate microsecond ts resolution + h += b'\x00\x02' # Major version 2 + h += b'\x00\x04' # Minor version 4 + h += b'\x00\x00\x00\x00' # Correction vs. UTC, seconds + h += b'\x00\x00\x00\x00' # Timestamp accuracy + h += b'\xff\xff\xff\xff' # Max packet len + # LINKTYPE_USB_LINUX_MMAPPED 220 + # Linux usbmon format, see Documentation/usb/usbmon.txt. + h += b'\x00\x00\x00\xdc' # Link layer + return h + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + if self.samplerate: + self.secs_per_sample = float(1) / float(self.samplerate) + + def start(self): + self.out_binary = self.register(srd.OUTPUT_BINARY) + self.out_ann = self.register(srd.OUTPUT_ANN) + + def handle_transfer(self): + request_started = 0 + request_end = self.handshake in ('ACK', 'STALL', 'timeout') + ep = self.transaction_ep + addr = self.transaction_addr + + # Handle protocol STALLs, condition lasts until next SETUP transfer (8.5.3.4) + if self.transaction_type == 'SETUP' and (addr, ep) in self.request: + request = self.request[(addr,ep)] + if request['type'] in ('SETUP IN', 'SETUP OUT'): + request['es'] = self.ss_transaction + self.handle_request(0, 1) + + if not (addr, ep) in self.request: + self.request[(addr, ep)] = {'setup_data': [], 'data': [], + 'type': None, 'ss': self.ss_transaction, 'es': None, + 'id': self.request_id, 'addr': addr, 'ep': ep} + self.request_id += 1 + request_started = 1 + request = self.request[(addr,ep)] + + if request_end: + request['es'] = self.es_transaction + request['handshake'] = self.handshake + + # BULK or INTERRUPT transfer + if request['type'] in (None, 'BULK IN') and self.transaction_type == 'IN': + request['type'] = 'BULK IN' + request['data'] += self.transaction_data + self.handle_request(request_started, request_end) + elif request['type'] in (None, 'BULK OUT') and self.transaction_type == 'OUT': + request['type'] = 'BULK OUT' + request['data'] += self.transaction_data + self.handle_request(request_started, request_end) + + # CONTROL, SETUP stage + elif request['type'] is None and self.transaction_type == 'SETUP': + request['setup_data'] = self.transaction_data + request['wLength'] = struct.unpack(' transaction_timeout: + self.es_transaction = transaction_timeout + self.handshake = 'timeout' + self.handle_transfer() + self.transaction_state = 'IDLE' + + if self.transaction_state != 'IDLE': + self.putr(ss, es, [4, ['ERR: received %s token in state %s' % + (pname, self.transaction_state)]]) + return + + sync, pid, addr, ep, crc5 = pinfo + self.transaction_data = [] + self.ss_transaction = ss + self.es_transaction = es + self.transaction_state = 'TOKEN RECEIVED' + self.transaction_ep = ep + self.transaction_addr = addr + self.transaction_type = pname # IN OUT SETUP + + elif pcategory == 'DATA': + if self.transaction_state != 'TOKEN RECEIVED': + self.putr(ss, es, [4, ['ERR: received %s token in state %s' % + (pname, self.transaction_state)]]) + return + + self.transaction_data = pinfo[2] + self.transaction_state = 'DATA RECEIVED' + + elif pcategory == 'HANDSHAKE': + if self.transaction_state not in ('TOKEN RECEIVED', 'DATA RECEIVED'): + self.putr(ss, es, [4, ['ERR: received %s token in state %s' % + (pname, self.transaction_state)]]) + return + + self.handshake = pname + self.transaction_state = 'IDLE' + self.es_transaction = es + self.handle_transfer() + + elif pname == 'PRE': + return + + else: + self.putr(ss, es, [4, ['ERR: received unhandled %s token in state %s' % + (pname, self.transaction_state)]]) + return diff --git a/libsigrokdecode4DSL/decoders/usb_signalling/__init__.py b/libsigrokdecode4DSL/decoders/usb_signalling/__init__.py new file mode 100644 index 00000000..eae18870 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/usb_signalling/__init__.py @@ -0,0 +1,50 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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, see . +## + +''' +This PD decodes the USB (low-speed and full-speed) signalling protocol. + +Electrical/signalling layer (USB spec, chapter 7): + +USB signalling consists of two signal lines, both driven at 3.3V +logic levels. The signals are DP (D+) and DM (D-), and normally operate in +differential mode. + +Low-speed: The state where DP=1,DM=0 is K, the state DP=0,DM=1 is J. +Full-speed: The state where DP=1,DM=0 is J, the state DP=0,DM=1 is K. + +A state SE0 is defined where DP=DM=0. This common mode signal is used to +signal a reset or end of packet (EOP). A state SE1 is defined where DP=DM=1. + +Data transmitted on the USB is encoded with NRZI. A transition from J to K +or vice-versa indicates a logic 0, while no transition indicates a logic 1. +If 6 ones are transmitted consecutively, a zero is inserted to force a +transition. This is known as bit stuffing. + +Data is transferred at a rate of 1.5Mbit/s (low-speed) / 12Mbit/s (full-speed). + +The SE0 transmitted to signal an end-of-packet is two bit intervals long +(low-speed: 1.25uS - 1.50uS, full-speed: 160ns - 175ns). + +Details: +https://en.wikipedia.org/wiki/USB +http://www.usb.org/developers/docs/ +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/usb_signalling/pd.py b/libsigrokdecode4DSL/decoders/usb_signalling/pd.py new file mode 100644 index 00000000..65a2b35c --- /dev/null +++ b/libsigrokdecode4DSL/decoders/usb_signalling/pd.py @@ -0,0 +1,352 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2011 Gareth McMullin +## Copyright (C) 2012-2013 Uwe Hermann +## Copyright (C) 2019 DreamSourceLab +## +## 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, see . +## + +import sigrokdecode as srd + +''' +OUTPUT_PYTHON format: + +Packet: +[, ] + +, : + - 'SOP', None + - 'SYM', + - 'BIT', + - 'STUFF BIT', None + - 'EOP', None + - 'ERR', None + - 'KEEP ALIVE', None + - 'RESET', None + +: + - 'J', 'K', 'SE0', or 'SE1' + +: + - '0' or '1' + - Note: Symbols like SE0, SE1, and the J that's part of EOP don't yield 'BIT'. +''' + +# Low-/full-speed symbols. +# Note: Low-speed J and K are inverted compared to the full-speed J and K! +symbols = { + 'low-speed': { + # (, ): + (0, 0): 'SE0', + (1, 0): 'K', + (0, 1): 'J', + (1, 1): 'SE1', + }, + 'full-speed': { + # (, ): + (0, 0): 'SE0', + (1, 0): 'J', + (0, 1): 'K', + (1, 1): 'SE1', + }, + 'automatic': { + # (, ): + (0, 0): 'SE0', + (1, 0): 'FS_J', + (0, 1): 'LS_J', + (1, 1): 'SE1', + }, + # After a PREamble PID, the bus segment between Host and Hub uses LS + # signalling rate and FS signalling polarity (USB 2.0 spec, 11.8.4: "For + # both upstream and downstream low-speed data, the hub is responsible for + # inverting the polarity of the data before transmitting to/from a + # low-speed port."). + 'low-speed-rp': { + # (, ): + (0, 0): 'SE0', + (1, 0): 'J', + (0, 1): 'K', + (1, 1): 'SE1', + }, +} + +bitrates = { + 'low-speed': 1500000, # 1.5Mb/s (+/- 1.5%) + 'low-speed-rp': 1500000, # 1.5Mb/s (+/- 1.5%) + 'full-speed': 12000000, # 12Mb/s (+/- 0.25%) + 'automatic': None +} + +sym_annotation = { + 'J': [0, ['J']], + 'K': [1, ['K']], + 'SE0': [2, ['SE0', '0']], + 'SE1': [3, ['SE1', '1']], +} + +class SamplerateError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = 'usb_signalling' + name = 'USB signalling' + longname = 'Universal Serial Bus (LS/FS) signalling' + desc = 'USB (low-speed/full-speed) signalling protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = ['usb_signalling'] + tags = ['PC'] + channels = ( + {'id': 'dp', 'name': 'D+', 'desc': 'USB D+ signal'}, + {'id': 'dm', 'name': 'D-', 'desc': 'USB D- signal'}, + ) + options = ( + {'id': 'signalling', 'desc': 'Signalling', + 'default': 'automatic', 'values': ('automatic', 'full-speed', 'low-speed')}, + ) + annotations = ( + ('sym-j', 'J symbol'), + ('sym-k', 'K symbol'), + ('sym-se0', 'SE0 symbol'), + ('sym-se1', 'SE1 symbol'), + ('sop', 'Start of packet (SOP)'), + ('eop', 'End of packet (EOP)'), + ('bit', 'Bit'), + ('stuffbit', 'Stuff bit'), + ('error', 'Error'), + ('keep-alive', 'Low-speed keep-alive'), + ('reset', 'Reset'), + ) + annotation_rows = ( + ('bits', 'Bits', (4, 5, 6, 7, 8, 9, 10)), + ('symbols', 'Symbols', (0, 1, 2, 3)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self.oldsym = 'J' # The "idle" state is J. + self.ss_block = None + self.samplenum = 0 + self.bitrate = None + self.bitwidth = None + self.samplepos = None + self.samplenum_target = None + self.samplenum_edge = None + self.samplenum_lastedge = 0 + self.edgepins = None + self.consecutive_ones = 0 + self.bits = None + self.state = 'IDLE' + + def start(self): + self.out_python = self.register(srd.OUTPUT_PYTHON) + self.out_ann = self.register(srd.OUTPUT_ANN) + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + self.signalling = self.options['signalling'] + if self.signalling != 'automatic': + self.update_bitrate() + + def update_bitrate(self): + self.bitrate = bitrates[self.signalling] + self.bitwidth = float(self.samplerate) / float(self.bitrate) + + def putpx(self, data): + s = self.samplenum_edge + self.put(s, s, self.out_python, data) + + def putx(self, data): + s = self.samplenum_edge + self.put(s, s, self.out_ann, data) + + def putpm(self, data): + e = self.samplenum_edge + self.put(self.ss_block, e, self.out_python, data) + + def putm(self, data): + e = self.samplenum_edge + self.put(self.ss_block, e, self.out_ann, data) + + def putpb(self, data): + s, e = self.samplenum_lastedge, self.samplenum_edge + self.put(s, e, self.out_python, data) + + def putb(self, data): + s, e = self.samplenum_lastedge, self.samplenum_edge + self.put(s, e, self.out_ann, data) + + def set_new_target_samplenum(self): + self.samplepos += self.bitwidth + self.samplenum_target = int(self.samplepos) + self.samplenum_lastedge = self.samplenum_edge + self.samplenum_edge = int(self.samplepos - (self.bitwidth / 2)) + + def wait_for_sop(self, sym): + # Wait for a Start of Packet (SOP), i.e. a J->K symbol change. + if sym != 'K' or self.oldsym != 'J': + return + self.consecutive_ones = 0 + self.bits = '' + self.update_bitrate() + self.samplepos = self.samplenum - (self.bitwidth / 2) + 0.5 + self.set_new_target_samplenum() + self.putpx(['SOP', None]) + self.putx([4, ['SOP', 'S']]) + self.state = 'GET BIT' + + def handle_bit(self, b): + if self.consecutive_ones == 6: + if b == '0': + # Stuff bit. + self.putpb(['STUFF BIT', None]) + self.putb([7, ['Stuff bit: 0', 'SB: 0', '0']]) + self.consecutive_ones = 0 + else: + self.putpb(['ERR', None]) + self.putb([8, ['Bit stuff error', 'BS ERR', 'B']]) + self.state = 'IDLE' + else: + # Normal bit (not a stuff bit). + self.putpb(['BIT', b]) + self.putb([6, ['%s' % b]]) + if b == '1': + self.consecutive_ones += 1 + else: + self.consecutive_ones = 0 + + def get_eop(self, sym): + # EOP: SE0 for >= 1 bittime (usually 2 bittimes), then J. + self.set_new_target_samplenum() + self.putpb(['SYM', sym]) + self.putb(sym_annotation[sym]) + self.oldsym = sym + if sym == 'SE0': + pass + elif sym == 'J': + # Got an EOP. + self.putpm(['EOP', None]) + self.putm([5, ['EOP', 'E']]) + self.state = 'WAIT IDLE' + else: + self.putpm(['ERR', None]) + self.putm([8, ['EOP Error', 'EErr', 'E']]) + self.state = 'IDLE' + + def get_bit(self, sym): + self.set_new_target_samplenum() + b = '0' if self.oldsym != sym else '1' + self.oldsym = sym + if sym == 'SE0': + # Start of an EOP. Change state, save edge + self.state = 'GET EOP' + self.ss_block = self.samplenum_lastedge + else: + self.handle_bit(b) + self.putpb(['SYM', sym]) + self.putb(sym_annotation[sym]) + if len(self.bits) <= 16: + self.bits += b + if len(self.bits) == 16 and self.bits == '0000000100111100': + # Sync and low-speed PREamble seen + self.putpx(['EOP', None]) + self.state = 'IDLE' + self.signalling = 'low-speed-rp' + self.update_bitrate() + self.oldsym = 'J' + if b == '0': + edgesym = symbols[self.signalling][tuple(self.edgepins)] + if edgesym not in ('SE0', 'SE1'): + if edgesym == sym: + self.bitwidth = self.bitwidth - (0.001 * self.bitwidth) + self.samplepos = self.samplepos - (0.01 * self.bitwidth) + else: + self.bitwidth = self.bitwidth + (0.001 * self.bitwidth) + self.samplepos = self.samplepos + (0.01 * self.bitwidth) + + def handle_idle(self, sym): + self.samplenum_edge = self.samplenum + se0_length = float(self.samplenum - self.samplenum_lastedge) / self.samplerate + if se0_length > 2.5e-6: # 2.5us + self.putpb(['RESET', None]) + self.putb([10, ['Reset', 'Res', 'R']]) + self.signalling = self.options['signalling'] + elif se0_length > 1.2e-6 and self.signalling == 'low-speed': + self.putpb(['KEEP ALIVE', None]) + self.putb([9, ['Keep-alive', 'KA', 'A']]) + + if self.options['signalling'] == 'automatic' and sym == 'FS_J': + self.signalling = 'full-speed' + elif self.options['signalling'] == 'automatic' and sym == 'LS_J': + self.signalling = 'low-speed' + else: + self.signalling = self.options['signalling'] + self.update_bitrate() + + self.oldsym = 'J' + self.state = 'IDLE' + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + + # Seed internal state from the very first sample. + (dp, dm) = self.wait() + sym = symbols[self.options['signalling']][(dp, dm)] + self.handle_idle(sym) + + while True: + # State machine. + if self.state == 'IDLE': + # Wait for any edge on either DP and/or DM. + (dp, dm) = self.wait([{0: 'e'}, {1: 'e'}]) + sym = symbols[self.signalling][(dp, dm)] + if sym == 'SE0': + self.samplenum_lastedge = self.samplenum + self.state = 'WAIT IDLE' + else: + self.wait_for_sop(sym) + self.edgepins = (dp, dm) + elif self.state in ('GET BIT', 'GET EOP'): + # Wait until we're in the middle of the desired bit. + if (self.samplenum_edge > self.samplenum): + (dp, dm) = self.wait([{'skip': self.samplenum_edge - self.samplenum}]) + self.edgepins = (dp, dm) + if (self.samplenum_target > self.samplenum): + (dp, dm) = self.wait([{'skip': self.samplenum_target - self.samplenum}]) + + sym = symbols[self.signalling][(dp, dm)] + if self.state == 'GET BIT': + self.get_bit(sym) + elif self.state == 'GET EOP': + self.get_eop(sym) + elif self.state == 'WAIT IDLE': + # Skip "all-low" input. Wait for high level on either DP or DM. + (dp, dm) = self.wait() + while not dp and not dm: + (dp, dm) = self.wait([{0: 'h'}, {1: 'h'}]) + if self.samplenum - self.samplenum_lastedge > 1: + sym = symbols[self.options['signalling']][(dp, dm)] + self.handle_idle(sym) + else: + sym = symbols[self.signalling][(dp, dm)] + self.wait_for_sop(sym) + self.edgepins = (dp, dm) diff --git a/libsigrokdecode4DSL/decoders/wiegand/__init__.py b/libsigrokdecode4DSL/decoders/wiegand/__init__.py new file mode 100644 index 00000000..d7d9a8c7 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/wiegand/__init__.py @@ -0,0 +1,28 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2016 Sean Burford +## +## 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, see . +## + +''' +The Wiegand interface is a de facto wiring standard commonly used to connect +a card swipe mechanism to the rest of an electronic entry system. + +Details: +https://en.wikipedia.org/wiki/Wiegand_interface +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/wiegand/pd.py b/libsigrokdecode4DSL/decoders/wiegand/pd.py new file mode 100644 index 00000000..a93be109 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/wiegand/pd.py @@ -0,0 +1,148 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2016 Sean Burford +## +## 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, see . +## + +import sigrokdecode as srd + +class SamplerateError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 3 + id = 'wiegand' + name = 'Wiegand' + longname = 'Wiegand interface' + desc = 'Wiegand interface for electronic entry systems.' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + tags = ['Embedded/industrial', 'RFID'] + channels = ( + {'id': 'd0', 'name': 'D0', 'desc': 'Data 0 line'}, + {'id': 'd1', 'name': 'D1', 'desc': 'Data 1 line'}, + ) + options = ( + {'id': 'active', 'desc': 'Data lines active level', + 'default': 'low', 'values': ('low', 'high')}, + {'id': 'bitwidth_ms', 'desc': 'Single bit width in milliseconds', + 'default': 4, 'values': (1, 2, 4, 8, 16, 32)}, + ) + annotations = ( + ('bits', 'Bits'), + ('state', 'State'), + ) + annotation_rows = ( + ('bits', 'Binary value', (0,)), + ('state', 'Stream state', (1,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.samplerate = None + self._samples_per_bit = 10 + + self._d0_prev = None + self._d1_prev = None + + self._state = None + self.ss_state = None + + self.ss_bit = None + self.es_bit = None + self._bit = None + self._bits = [] + + def start(self): + 'Register output types and verify user supplied decoder values.' + self.out_ann = self.register(srd.OUTPUT_ANN) + self._active = 1 if self.options['active'] == 'high' else 0 + self._inactive = 1 - self._active + + def metadata(self, key, value): + 'Receive decoder metadata about the data stream.' + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + if self.samplerate: + ms_per_sample = 1000 * (1.0 / self.samplerate) + ms_per_bit = float(self.options['bitwidth_ms']) + self._samples_per_bit = int(max(1, int(ms_per_bit / ms_per_sample))) + + def _update_state(self, state, bit=None): + 'Update state and bit values when they change.' + if self._bit is not None: + self._bits.append(self._bit) + self.put(self.ss_bit, self.samplenum, self.out_ann, + [0, [str(self._bit)]]) + self._bit = bit + self.ss_bit = self.samplenum + if bit is not None: + # Set a timeout so that the final bit ends. + self.es_bit = self.samplenum + self._samples_per_bit + else: + self.es_bit = None + + if state != self._state: + ann = None + if self._state == 'data': + accum_bits = ''.join(str(x) for x in self._bits) + ann = [1, ['%d bits %s' % (len(self._bits), accum_bits), + '%d bits' % len(self._bits)]] + elif self._state == 'invalid': + ann = [1, [self._state]] + if ann: + self.put(self.ss_state, self.samplenum, self.out_ann, ann) + self.ss_state = self.samplenum + self._state = state + self._bits = [] + + def decode(self): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + while True: + # TODO: Come up with more appropriate self.wait() conditions. + (d0, d1) = self.wait() + + if d0 == self._d0_prev and d1 == self._d1_prev: + if self.es_bit and self.samplenum >= self.es_bit: + if (d0, d1) == (self._inactive, self._inactive): + self._update_state('idle') + else: + self._update_state('invalid') + continue + + if self._state in (None, 'idle', 'data'): + if (d0, d1) == (self._active, self._inactive): + self._update_state('data', 0) + elif (d0, d1) == (self._inactive, self._active): + self._update_state('data', 1) + elif (d0, d1) == (self._active, self._active): + self._update_state('invalid') + elif self._state == 'invalid': + # Wait until we see an idle state before leaving invalid. + # This prevents inverted lines from being misread. + if (d0, d1) == (self._inactive, self._inactive): + self._update_state('idle') + + self._d0_prev, self._d1_prev = d0, d1 + + def report(self): + return '%s: %s D0 %d D1 %d (active on %d), %d samples per bit' % ( + self.name, self._state, self._d0_prev, self._d1_prev, + self._active, self._samples_per_bit) diff --git a/libsigrokdecode4DSL/decoders/x2444m/__init__.py b/libsigrokdecode4DSL/decoders/x2444m/__init__.py new file mode 100644 index 00000000..70d21466 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/x2444m/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Stefan Petersen +## +## 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, see . +## + +''' +This decoder stacks on top of the 'spi' PD and decodes the Xicor X2444M/P +nonvolatile static RAM protocol. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/x2444m/pd.py b/libsigrokdecode4DSL/decoders/x2444m/pd.py new file mode 100644 index 00000000..290cc368 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/x2444m/pd.py @@ -0,0 +1,111 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Stefan Petersen +## +## 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, see . +## + +import re +import sigrokdecode as srd + +registers = { + 0x80: ['WRDS', 0, lambda _: ''], + 0x81: ['STO', 1, lambda _: ''], + 0x82: ['SLEEP', 2, lambda _: ''], + 0x83: ['WRITE', 3, lambda v: '0x%x' % v], + 0x84: ['WREN', 4, lambda _: ''], + 0x85: ['RCL', 5, lambda _: ''], + 0x86: ['READ', 6, lambda v: '0x%x' % v], + 0x87: ['READ', 7, lambda v: '0x%x' % v], +} + +class Decoder(srd.Decoder): + api_version = 3 + id = 'x2444m' + name = 'X2444M/P' + longname = 'Xicor X2444M/P' + desc = 'Xicor X2444M/P nonvolatile static RAM protocol.' + license = 'gplv2+' + inputs = ['spi'] + outputs = [] + tags = ['IC', 'Memory'] + annotations = ( + ('wrds', 'Write disable'), + ('sto', 'Store RAM data in EEPROM'), + ('sleep', 'Enter sleep mode'), + ('write', 'Write data into RAM'), + ('wren', 'Write enable'), + ('rcl', 'Recall EEPROM data into RAM'), + ('read', 'Data read from RAM'), + ('read', 'Data read from RAM'), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.cs_start = 0 + self.cs_asserted = False + self.cmd_digit = 0 + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putreadwrite(self, ss, es, reg, idx, addr, value): + self.put(ss, es, self.out_ann, + [idx, ['%s: %s => 0x%4.4x' % (reg, addr, value), + '%s: %s => 0x%4.4x' % (reg[0], addr, value), reg[0]]]) + + def putcmd(self, ss, es, reg, idx): + self.put(ss, es, self.out_ann, [idx, [reg, reg[0]]]) + + def decode(self, ss, es, data): + ptype, mosi, miso = data + + if ptype == 'DATA': + if not self.cs_asserted: + return + + if self.cmd_digit == 0: + self.addr = mosi + self.addr_start = ss + elif self.cmd_digit > 0: + self.read_value = (self.read_value << 8) + miso + self.write_value = (self.write_value << 8) + mosi + self.cmd_digit += 1 + elif ptype == 'CS-CHANGE': + self.cs_asserted = (miso == 1) + # When not asserted, CS has just changed from asserted to deasserted. + if not self.cs_asserted: + # Only one digit, simple command. Else read/write. + if self.cmd_digit == 1: + name, idx, decoder = registers[self.addr & 0x87] + self.putcmd(self.addr_start, es, name, idx) + elif self.cmd_digit > 1: + name, idx, decoder = registers[self.addr & 0x87] + if name == 'READ': + value = self.read_value + elif name == 'WRITE': + value = self.write_value + else: + value = 0 + self.putreadwrite(self.addr_start, es, name, idx, + decoder((self.addr >> 3) & 0x0f), value) + + if self.cs_asserted: + self.cs_start = ss + self.cmd_digit = 0 + self.read_value = 0 + self.write_value = 0 diff --git a/libsigrokdecode4DSL/decoders/xfp/__init__.py b/libsigrokdecode4DSL/decoders/xfp/__init__.py new file mode 100644 index 00000000..72f35950 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/xfp/__init__.py @@ -0,0 +1,38 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2013 Bert Vermeulen +## +## 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, see . +## + +''' +This PD decodes the XFP I²C management interface structures/protocol. + +XFP modules include an I²C interface, used to monitor and control various +aspects of the module. The specification defines an I²C slave at address +0x50 (0xa0) which returns 128 bytes of a standard structure ("lower memory"), +and, after setting a table number in lower memory, a set of 256 "higher +memory" tables, which can be mapped to different subdevices on the XFP. + +Only one table is defined in the specification: table 0x01, the default on +module startup. Other table are either reserved for future expansion, or +available for vendor-specific extensions. This decoder supports both lower +memory and table 0x01. + +Details: +ftp://ftp.seagate.com/sff/INF-8077.PDF (XFP specification) +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/xfp/pd.py b/libsigrokdecode4DSL/decoders/xfp/pd.py new file mode 100644 index 00000000..ded76946 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/xfp/pd.py @@ -0,0 +1,482 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2013 Bert Vermeulen +## +## 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 . +## + +import sigrokdecode as srd +from common.plugtrx import (MODULE_ID, ALARM_THRESHOLDS, AD_READOUTS, GCS_BITS, + CONNECTOR, TRANSCEIVER, SERIAL_ENCODING, XMIT_TECH, CDR, DEVICE_TECH, + ENHANCED_OPTS, AUX_TYPES) + +class Decoder(srd.Decoder): + api_version = 3 + id = 'xfp' + name = 'XFP' + longname = '10 Gigabit Small Form Factor Pluggable Module (XFP)' + desc = 'XFP I²C management interface structures/protocol' + license = 'gplv3+' + inputs = ['i2c'] + outputs = [] + tags = ['Networking'] + annotations = ( + ('fieldnames-and-values', 'XFP structure field names and values'), + ('fields', 'XFP structure fields'), + ) + + def __init__(self): + self.reset() + + def reset(self): + # Received data items, used as an index into samplenum/data + self.cnt = -1 + # Start/end sample numbers per data item + self.sn = [] + # Multi-byte structure buffer + self.buf = [] + # Filled in by address 0x7f in low memory + self.cur_highmem_page = 0 + # Filled in by extended ID value in table 2 + self.have_clei = False + # Handlers for each field in the structure, keyed by the end + # index of that field. Each handler is fed all unhandled bytes + # up until that point, so mark unused space with the dummy + # handler self.ignore(). + self.MAP_LOWER_MEMORY = { + 0: self.module_id, + 1: self.signal_cc, + 57: self.alarm_warnings, + 59: self.vps, + 69: self.ignore, + 71: self.ber, + 75: self.wavelength_cr, + 79: self.fec_cr, + 95: self.int_ctrl, + 109: self.ad_readout, + 111: self.gcs, + 117: self.ignore, + 118: self.ignore, + 122: self.ignore, + 126: self.ignore, + 127: self.page_select, + } + self.MAP_HIGH_TABLE_1 = { + 128: self.module_id, + 129: self.ext_module_id, + 130: self.connector, + 138: self.transceiver, + 139: self.serial_encoding, + 140: self.br_min, + 141: self.br_max, + 142: self.link_length_smf, + 143: self.link_length_e50, + 144: self.link_length_50um, + 145: self.link_length_625um, + 146: self.link_length_copper, + 147: self.device_tech, + 163: self.vendor, + 164: self.cdr, + 167: self.vendor_oui, + 183: self.vendor_pn, + 185: self.vendor_rev, + 187: self.wavelength, + 189: self.wavelength_tolerance, + 190: self.max_case_temp, + 191: self.ignore, + 195: self.power_supply, + 211: self.vendor_sn, + 219: self.manuf_date, + 220: self.diag_mon, + 221: self.enhanced_opts, + 222: self.aux_mon, + 223: self.ignore, + 255: self.maybe_ascii, + } + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def decode(self, ss, es, data): + cmd, data = data + + # We only care about actual data bytes that are read (for now). + if cmd != 'DATA READ': + return + + self.cnt += 1 + self.sn.append([ss, es]) + + self.buf.append(data) + if self.cnt < 0x80: + if self.cnt in self.MAP_LOWER_MEMORY: + self.MAP_LOWER_MEMORY[self.cnt](self.buf) + self.buf.clear() + elif self.cnt < 0x0100 and self.cur_highmem_page == 0x01: + # Serial ID memory map + if self.cnt in self.MAP_HIGH_TABLE_1: + self.MAP_HIGH_TABLE_1[self.cnt](self.buf) + self.buf.clear() + + # Annotation helper + def annotate(self, key, value, start_cnt=None, end_cnt=None): + if start_cnt is None: + start_cnt = self.cnt - len(self.buf) + 1 + if end_cnt is None: + end_cnt = self.cnt + self.put(self.sn[start_cnt][0], self.sn[end_cnt][1], + self.out_ann, [0, [key + ": " + value]]) + self.put(self.sn[start_cnt][0], self.sn[end_cnt][1], + self.out_ann, [1, [value]]) + + # Placeholder handler, needed to advance the buffer past unused or + # reserved space in the structures. + def ignore(self, data): + pass + + # Show as ASCII if possible + def maybe_ascii(self, data): + for i in range(len(data)): + if data[i] >= 0x20 and data[i] < 0x7f: + cnt = self.cnt - len(data) + 1 + self.annotate("Vendor ID", chr(data[i]), cnt, cnt) + + # Convert 16-bit two's complement values, with each increment + # representing 1/256C, to degrees Celsius. + def to_temp(self, value): + if value & 0x8000: + value = -((value ^ 0xffff) + 1) + temp = value / 256.0 + return "%.1f C" % temp + + # TX bias current in uA. Each increment represents 0.2uA + def to_current(self, value): + current = value / 500000.0 + return "%.1f mA" % current + + # Power in mW, with each increment representing 0.1uW + def to_power(self, value): + power = value / 10000.0 + return "%.2f mW" % power + + # Wavelength in increments of 0.05nm + def to_wavelength(self, value): + wl = value / 20 + return "%d nm" % wl + + # Wavelength in increments of 0.005nm + def to_wavelength_tolerance(self, value): + wl = value / 200.0 + return "%.1f nm" % wl + + def module_id(self, data): + self.annotate("Module identifier", MODULE_ID.get(data[0], "Unknown")) + + def signal_cc(self, data): + # No good data available. + if (data[0] != 0x00): + self.annotate("Signal Conditioner Control", "%.2x" % data[0]) + + def alarm_warnings(self, data): + cnt_idx = self.cnt - len(data) + idx = 0 + while idx < 56: + if idx == 8: + # Skip over reserved A/D flag thresholds + idx += 8 + value = (data[idx] << 8) | data[idx + 1] + if value != 0: + name = ALARM_THRESHOLDS.get(idx, "...") + if idx in (0, 2, 4, 6): + self.annotate(name, self.to_temp(value), + cnt_idx + idx, cnt_idx + idx + 1) + elif idx in (16, 18, 20, 22): + self.annotate(name, self.to_current(value), + cnt_idx + idx, cnt_idx + idx + 1) + elif idx in (24, 26, 28, 30, 32, 34, 36, 38): + self.annotate(name, self.to_power(value), + cnt_idx + idx, cnt_idx + idx + 1) + else: + self.annotate(name, "%d" % name, value, cnt_idx + idx, + cnt_idx + idx + 1) + idx += 2 + + def vps(self, data): + # No good data available. + if (data != [0, 0]): + self.annotate("VPS", "%.2x%.2x" % (data[0], data[1])) + + def ber(self, data): + # No good data available. + if (data != [0, 0]): + self.annotate("BER", str(data)) + + def wavelength_cr(self, data): + # No good data available. + if (data != [0, 0, 0, 0]): + self.annotate("WCR", str(data)) + + def fec_cr(self, data): + if (data != [0, 0, 0, 0]): + self.annotate("FEC", str(data)) + + def int_ctrl(self, data): + # No good data available. Also boring. + out = [] + for d in data: + out.append("%.2x" % d) + self.annotate("Interrupt bits", ' '.join(out)) + + def ad_readout(self, data): + cnt_idx = self.cnt - len(data) + 1 + idx = 0 + while idx < 14: + if idx == 2: + # Skip over reserved field + idx += 2 + value = (data[idx] << 8) | data[idx + 1] + name = AD_READOUTS.get(idx, "...") + if value != 0: + if idx == 0: + self.annotate(name, self.to_temp(value), + cnt_idx + idx, cnt_idx + idx + 1) + elif idx == 4: + self.annotate(name, self.to_current(value), + cnt_idx + idx, cnt_idx + idx + 1) + elif idx in (6, 8): + self.annotate(name, self.to_power(value), + cnt_idx + idx, cnt_idx + idx + 1) + else: + self.annotate(name, str(value), cnt_idx + idx, + cnt_idx + idx + 1) + idx += 2 + + def gcs(self, data): + allbits = (data[0] << 8) | data[1] + out = [] + for b in range(13): + if allbits & 0x8000: + out.append(GCS_BITS[b]) + allbits <<= 1 + self.annotate("General Control/Status", ', '.join(out)) + + def page_select(self, data): + self.cur_highmem_page = data[0] + + def ext_module_id(self, data): + out = ["Power level %d module" % ((data[0] >> 6) + 1)] + if data[0] & 0x20 == 0: + out.append("CDR") + if data[0] & 0x10 == 0: + out.append("TX ref clock input required") + if data[0] & 0x08 == 0: + self.have_clei = True + self.annotate("Extended id", ', '.join(out)) + + def connector(self, data): + if data[0] in CONNECTOR: + self.annotate("Connector", CONNECTOR[data[0]]) + + def transceiver(self, data): + out = [] + for t in range(8): + if data[t] == 0: + continue + value = data[t] + for b in range(8): + if value & 0x80: + if len(TRANSCEIVER[t]) < b + 1: + out.append("(unknown)") + else: + out.append(TRANSCEIVER[t][b]) + value <<= 1 + self.annotate("Transceiver compliance", ', '.join(out)) + + def serial_encoding(self, data): + out = [] + value = data[0] + for b in range(8): + if value & 0x80: + if len(SERIAL_ENCODING) < b + 1: + out.append("(unknown)") + else: + out.append(SERIAL_ENCODING[b]) + value <<= 1 + self.annotate("Serial encoding support", ', '.join(out)) + + def br_min(self, data): + # Increments represent 100Mb/s + rate = data[0] / 10.0 + self.annotate("Minimum bit rate", "%.3f GB/s" % rate) + + def br_max(self, data): + # Increments represent 100Mb/s + rate = data[0] / 10.0 + self.annotate("Maximum bit rate", "%.3f GB/s" % rate) + + def link_length_smf(self, data): + if data[0] == 0: + length = "(standard)" + elif data[0] == 255: + length = "> 254 km" + else: + length = "%d km" % data[0] + self.annotate("Link length (SMF)", length) + + def link_length_e50(self, data): + if data[0] == 0: + length = "(standard)" + elif data[0] == 255: + length = "> 508 m" + else: + length = "%d m" % (data[0] * 2) + self.annotate("Link length (extended, 50μm MMF)", length) + + def link_length_50um(self, data): + if data[0] == 0: + length = "(standard)" + elif data[0] == 255: + length = "> 254 m" + else: + length = "%d m" % data[0] + self.annotate("Link length (50μm MMF)", length) + + def link_length_625um(self, data): + if data[0] == 0: + length = "(standard)" + elif data[0] == 255: + length = "> 254 m" + else: + length = "%d m" % (data[0]) + self.annotate("Link length (62.5μm MMF)", length) + + def link_length_copper(self, data): + if data[0] == 0: + length = "(unknown)" + elif data[0] == 255: + length = "> 254 m" + else: + length = "%d m" % (data[0] * 2) + self.annotate("Link length (copper)", length) + + def device_tech(self, data): + out = [] + xmit = data[0] >> 4 + if xmit <= len(XMIT_TECH) - 1: + out.append("%s transmitter" % XMIT_TECH[xmit]) + dev = data[0] & 0x0f + for b in range(4): + out.append(DEVICE_TECH[b][(dev >> (3 - b)) & 0x01]) + self.annotate("Device technology", ', '.join(out)) + + def vendor(self, data): + name = bytes(data).strip().decode('ascii').strip('\x00') + if name: + self.annotate("Vendor", name) + + def cdr(self, data): + out = [] + value = data[0] + for b in range(8): + if value & 0x80: + out.append(CDR[b]) + value <<= 1 + self.annotate("CDR support", ', '.join(out)) + + def vendor_oui(self, data): + if data != [0, 0, 0]: + self.annotate("Vendor OUI", "%.2X-%.2X-%.2X" % tuple(data)) + + def vendor_pn(self, data): + name = bytes(data).strip().decode('ascii').strip('\x00') + if name: + self.annotate("Vendor part number", name) + + def vendor_rev(self, data): + name = bytes(data).strip().decode('ascii').strip('\x00') + if name: + self.annotate("Vendor revision", name) + + def wavelength(self, data): + value = (data[0] << 8) | data[1] + self.annotate("Wavelength", self.to_wavelength(value)) + + def wavelength_tolerance(self, data): + value = (data[0] << 8) | data[1] + self.annotate("Wavelength tolerance", self.to_wavelength_tolerance(value)) + + def max_case_temp(self, data): + self.annotate("Maximum case temperature", "%d C" % data[0]) + + def power_supply(self, data): + out = [] + self.annotate("Max power dissipation", + "%.3f W" % (data[0] * 0.02), self.cnt - 3, self.cnt - 3) + self.annotate("Max power dissipation (powered down)", + "%.3f W" % (data[1] * 0.01), self.cnt - 2, self.cnt - 2) + value = (data[2] >> 4) * 0.050 + self.annotate("Max current required (5V supply)", + "%.3f A" % value, self.cnt - 1, self.cnt - 1) + value = (data[2] & 0x0f) * 0.100 + self.annotate("Max current required (3.3V supply)", + "%.3f A" % value, self.cnt - 1, self.cnt - 1) + value = (data[3] >> 4) * 0.100 + self.annotate("Max current required (1.8V supply)", + "%.3f A" % value, self.cnt, self.cnt) + value = (data[3] & 0x0f) * 0.050 + self.annotate("Max current required (-5.2V supply)", + "%.3f A" % value, self.cnt, self.cnt) + + def vendor_sn(self, data): + name = bytes(data).strip().decode('ascii').strip('\x00') + if name: + self.annotate("Vendor serial number", name) + + def manuf_date(self, data): + y = int(bytes(data[0:2])) + 2000 + m = int(bytes(data[2:4])) + d = int(bytes(data[4:6])) + mnf = "%.4d-%.2d-%.2d" % (y, m, d) + lot = bytes(data[6:]).strip().decode('ascii').strip('\x00') + if lot: + mnf += " lot " + lot + self.annotate("Manufacturing date", mnf) + + def diag_mon(self, data): + out = [] + if data[0] & 0x10: + out.append("BER support") + else: + out.append("no BER support") + if data[0] & 0x08: + out.append("average power measurement") + else: + out.append("OMA power measurement") + self.annotate("Diagnostic monitoring", ', '.join(out)) + + def enhanced_opts(self, data): + out = [] + value = data[0] + for b in range(8): + if value & 0x80: + out.append(ENHANCED_OPTS[b]) + value <<= 1 + self.annotate("Enhanced option support", ', '.join(out)) + + def aux_mon(self, data): + aux = AUX_TYPES[data[0] >> 4] + self.annotate("AUX1 monitoring", aux) + aux = AUX_TYPES[data[0] & 0x0f] + self.annotate("AUX2 monitoring", aux) diff --git a/libsigrokdecode4DSL/decoders/xy2-100/__init__.py b/libsigrokdecode4DSL/decoders/xy2-100/__init__.py new file mode 100644 index 00000000..676e1aff --- /dev/null +++ b/libsigrokdecode4DSL/decoders/xy2-100/__init__.py @@ -0,0 +1,28 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Uli Huber +## +## 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, see . +## + +''' +XY2-100 is a serial bus for connecting galvo systems to controllers + +Details: + +http://www.newson.be/doc.php?id=XY2-100 +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/xy2-100/pd.py b/libsigrokdecode4DSL/decoders/xy2-100/pd.py new file mode 100644 index 00000000..47c4182c --- /dev/null +++ b/libsigrokdecode4DSL/decoders/xy2-100/pd.py @@ -0,0 +1,242 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Uli Huber +## Copyright (C) 2020 Soeren Apel +## +## 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, see . +## + +import sigrokdecode as srd + +ann_bit, ann_stat_bit, ann_type, ann_command, ann_parameter, ann_parity, ann_pos, ann_status, ann_warning = range(9) +frame_type_none, frame_type_command, frame_type_16bit_pos, frame_type_18bit_pos = range(4) + +class Decoder(srd.Decoder): + api_version = 3 + id = 'xy2-100' + name = 'XY2-100' + longname = 'XY2-100(E) and XY-200(E) galvanometer protocol' + desc = 'Serial protocol for galvanometer positioning in laser systems' + license = 'gplv2+' + inputs = ['logic'] + outputs = [] + + tags = ['Embedded/industrial'] + + channels = ( + {'id': 'clk', 'name': 'CLK', 'desc': 'Clock'}, + {'id': 'sync', 'name': 'SYNC', 'desc': 'Sync'}, + {'id': 'data', 'name': 'DATA', 'desc': 'X, Y or Z axis data'}, + ) + optional_channels = ( + {'id': 'status', 'name': 'STAT', 'desc': 'X, Y or Z axis status'}, + ) + + annotations = ( + ('bit', 'Data Bit'), + ('stat_bit', 'Status Bit'), + ('type', 'Frame Type'), + ('command', 'Command'), + ('parameter', 'Parameter'), + ('parity', 'Parity'), + ('position', 'Position'), + ('status', 'Status'), + ('warning', 'Human-readable warnings'), + ) + annotation_rows = ( + ('bits', 'Data Bits', (ann_bit,)), + ('stat_bits', 'Status Bits', (ann_stat_bit,)), + ('data', 'Data', (ann_type, ann_command, ann_parameter, ann_parity)), + ('positions', 'Positions', (ann_pos,)), + ('statuses', 'Statuses', (ann_status,)), + ('warnings', 'Warnings', (ann_warning,)), + ) + + def __init__(self): + self.samplerate = None + self.reset() + + def reset(self): + self.bits = [] + self.stat_bits = [] + self.stat_skip_bit = True + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def put_ann(self, ss, es, ann_class, value): + self.put(ss, es, self.out_ann, [ann_class, value]) + + def process_bit(self, sync, bit_ss, bit_es, bit_value): + self.put_ann(bit_ss, bit_es, ann_bit, ['%d' % bit_value]) + self.bits.append((bit_ss, bit_es, bit_value)) + + if sync == 0: + if len(self.bits) < 20: + self.put_ann(self.bits[0][0], bit_es, ann_warning, ['Not enough data bits']) + self.reset() + return + + # Bit structure: + # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 + # T --------------- 18-bit pos ----------------- PARITY or + # -TYPE-- ------------ 16-bit pos -------------- PARITY or + # -TYPE-- -8-bit command -8-bit parameter value- PARITY + + # Calculate parity, excluding the parity bit itself + parity = 0 + for ss, es, value in self.bits[:-1]: + parity ^= value + + par_ss, par_es, par_value = self.bits[19] + parity_even = 0 + parity_odd = 0 + if (par_value == parity): + parity_even = 1 + else: + parity_odd = 1 + + type_1_value = self.bits[0][2] + type_3_value = (self.bits[0][2] << 2) | (self.bits[1][2] << 1) | self.bits[2][2] + + # Determine frame type + type = frame_type_none + parity_status = ['X', 'Unknown'] + type_ss = self.bits[0][0] + type_es = self.bits[2][1] + + ### 18-bit position + if (type_1_value == 1) and (parity_odd == 1): + type = frame_type_18bit_pos + type_es = self.bits[0][1] + self.put_ann(self.bits[0][0], bit_es, ann_warning, ['Careful: 18-bit position frames with wrong parity and command frames with wrong parity cannot be identified']) + ### 16-bit position + elif (type_3_value == 1): + type = frame_type_16bit_pos + if (parity_even == 1): + parity_status = ['OK'] + else: + parity_status = ['NOK'] + self.put_ann(self.bits[0][0], bit_es, ann_warning, ['Parity error', 'PE']) + ### Command + elif (type_3_value == 7) and (parity_even == 1): + type = frame_type_command + self.put_ann(self.bits[0][0], bit_es, ann_warning, ['Careful: 18-bit position frames with wrong parity and command frames with wrong parity cannot be identified']) + ### Other + else: + self.put_ann(self.bits[0][0], bit_es, ann_warning, ['Error', 'Unknown command or parity error']) + self.reset() + return + + # Output command and parity annotations + if (type == frame_type_16bit_pos): + self.put_ann(type_ss, type_es, ann_type, ['16 bit Position Frame', '16 bit Pos', 'Pos', 'P']) + if (type == frame_type_18bit_pos): + self.put_ann(type_ss, type_es, ann_type, ['18 bit Position Frame', '18 bit Pos', 'Pos', 'P']) + if (type == frame_type_command): + self.put_ann(type_ss, type_es, ann_type, ['Command Frame', 'Command', 'C']) + + self.put_ann(par_ss, par_es, ann_parity, parity_status) + + # Output value + if (type == frame_type_16bit_pos) or (type == frame_type_18bit_pos): + pos = 0 + + if (type == frame_type_16bit_pos): + count = 15 + for ss, es, value in self.bits[3:19]: + pos |= value << count + count -= 1 + pos = pos if pos < 32768 else pos - 65536 + else: + count = 17 + for ss, es, value in self.bits[3:19]: + pos |= value << count + count -= 1 + pos = pos if pos < 131072 else pos - 262144 + + self.put_ann(type_es, par_ss, ann_pos, ['%d' % pos]) + + if (type == frame_type_command): + count = 7 + cmd = 0 + cmd_es = 0 + for ss, es, value in self.bits[3:11]: + cmd |= value << count + count -= 1 + cmd_es = es + self.put_ann(type_es, cmd_es, ann_command, ['Command 0x%X' % cmd, 'Cmd 0x%X' % cmd, '0x%X' % cmd]) + + count = 7 + param = 0 + for ss, es, value in self.bits[11:19]: + param |= value << count + count -= 1 + self.put_ann(cmd_es, par_ss, ann_parameter, ['Parameter 0x%X / %d' % (param, param), '0x%X / %d' % (param, param),'0x%X' % param]) + + self.reset() + + def process_stat_bit(self, sync, bit_ss, bit_es, bit_value): + if self.stat_skip_bit: + self.stat_skip_bit = False + return + + self.put_ann(bit_ss, bit_es, ann_stat_bit, ['%d' % bit_value]) + self.stat_bits.append((bit_ss, bit_es, bit_value)) + + if (sync == 0) and (len(self.stat_bits) == 19): + stat_ss = self.stat_bits[0][0] + stat_es = self.stat_bits[18][1] + + status = 0 + count = 18 + for ss, es, value in self.stat_bits: + status |= value << count + count -= 1 + self.put_ann(stat_ss, stat_es, ann_status, ['Status 0x%X' % status, '0x%X' % status]) + + def decode(self): + bit_ss = None + bit_es = None + bit_value = 0 + stat_ss = None + stat_es = None + stat_value = 0 + sync_value = 0 + has_stat = self.has_channel(3) + + while True: + # Wait for any edge on clk + clk, sync, data, stat = self.wait({0: 'e'}) + + if clk == 1: + stat_value = stat + + bit_es = self.samplenum + if bit_ss: + self.process_bit(sync_value, bit_ss, bit_es, bit_value) + bit_ss = self.samplenum + else: + bit_value = data + sync_value = sync + + stat_es = self.samplenum + if stat_ss and has_stat: + self.process_stat_bit(sync_value, stat_ss, stat_es, stat_value) + stat_ss = self.samplenum diff --git a/libsigrokdecode4DSL/decoders/z80/__init__.py b/libsigrokdecode4DSL/decoders/z80/__init__.py new file mode 100644 index 00000000..52ff9bac --- /dev/null +++ b/libsigrokdecode4DSL/decoders/z80/__init__.py @@ -0,0 +1,36 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Daniel Elstner +## +## 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 . +## + +''' +The Zilog Z80 is an 8-bit microprocessor compatible with the Intel 8080. + +In addition to the 8-bit data bus, this decoder requires the input signals +/M1 (machine cycle), /RD (read) and /WR (write) to do its work. An explicit +clock signal is not required. However, the Z80 CPU clock may be used as +sampling clock, if applicable. + +Notes on the Z80 opcode format and descriptions of both documented and +"undocumented" opcodes are available here: + +Details: +http://www.z80.info/decoding.htm +http://clrhome.org/table/ +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/z80/pd.py b/libsigrokdecode4DSL/decoders/z80/pd.py new file mode 100644 index 00000000..9af310e2 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/z80/pd.py @@ -0,0 +1,359 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Daniel Elstner +## +## 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 . +## + +import sigrokdecode as srd +from functools import reduce +from .tables import instr_table_by_prefix +import string + +class Ann: + ADDR, MEMRD, MEMWR, IORD, IOWR, INSTR, ROP, WOP, WARN = range(9) +class Row: + ADDRBUS, DATABUS, INSTRUCTIONS, OPERANDS, WARNINGS = range(5) +class Pin: + D0, D7 = 0, 7 + M1, RD, WR, MREQ, IORQ = range(8, 13) + A0, A15 = 13, 28 +class Cycle: + NONE, MEMRD, MEMWR, IORD, IOWR, FETCH, INTACK = range(7) + +# Provide custom format type 'H' for hexadecimal output +# with leading decimal digit (assembler syntax). +class AsmFormatter(string.Formatter): + def format_field(self, value, format_spec): + if format_spec.endswith('H'): + result = format(value, format_spec[:-1] + 'X') + return result if result[0] in string.digits else '0' + result + else: + return format(value, format_spec) + +formatter = AsmFormatter() + +ann_data_cycle_map = { + Cycle.MEMRD: Ann.MEMRD, + Cycle.MEMWR: Ann.MEMWR, + Cycle.IORD: Ann.IORD, + Cycle.IOWR: Ann.IOWR, + Cycle.FETCH: Ann.MEMRD, + Cycle.INTACK: Ann.IORD, +} + +def reduce_bus(bus): + if 0xFF in bus: + return None # unassigned bus channels + else: + return reduce(lambda a, b: (a << 1) | b, reversed(bus)) + +def signed_byte(byte): + return byte if byte < 128 else byte - 256 + +class Decoder(srd.Decoder): + api_version = 3 + id = 'z80' + name = 'Z80' + longname = 'Zilog Z80 CPU' + desc = 'Zilog Z80 microprocessor disassembly.' + license = 'gplv3+' + inputs = ['logic'] + outputs = [] + tags = ['Retro computing'] + channels = tuple({ + 'id': 'd%d' % i, + 'name': 'D%d' % i, + 'desc': 'Data bus line %d' % i + } for i in range(8) + ) + ( + {'id': 'm1', 'name': '/M1', 'desc': 'Machine cycle 1'}, + {'id': 'rd', 'name': '/RD', 'desc': 'Memory or I/O read'}, + {'id': 'wr', 'name': '/WR', 'desc': 'Memory or I/O write'}, + ) + optional_channels = ( + {'id': 'mreq', 'name': '/MREQ', 'desc': 'Memory request'}, + {'id': 'iorq', 'name': '/IORQ', 'desc': 'I/O request'}, + ) + tuple({ + 'id': 'a%d' % i, + 'name': 'A%d' % i, + 'desc': 'Address bus line %d' % i + } for i in range(16) + ) + annotations = ( + ('addr', 'Memory or I/O address'), + ('memrd', 'Byte read from memory'), + ('memwr', 'Byte written to memory'), + ('iord', 'Byte read from I/O port'), + ('iowr', 'Byte written to I/O port'), + ('instr', 'Z80 CPU instruction'), + ('rop', 'Value of input operand'), + ('wop', 'Value of output operand'), + ('warn', 'Warning message'), + ) + annotation_rows = ( + ('addrbus', 'Address bus', (Ann.ADDR,)), + ('databus', 'Data bus', (Ann.MEMRD, Ann.MEMWR, Ann.IORD, Ann.IOWR)), + ('instructions', 'Instructions', (Ann.INSTR,)), + ('operands', 'Operands', (Ann.ROP, Ann.WOP)), + ('warnings', 'Warnings', (Ann.WARN,)) + ) + + def __init__(self): + self.reset() + + def reset(self): + self.prev_cycle = Cycle.NONE + self.op_state = self.state_IDLE + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.bus_data = None + self.samplenum = None + self.addr_start = None + self.data_start = None + self.dasm_start = None + self.pend_addr = None + self.pend_data = None + self.ann_data = None + self.ann_dasm = None + self.prev_cycle = Cycle.NONE + self.op_state = self.state_IDLE + self.instr_len = 0 + + def decode(self): + while True: + # TODO: Come up with more appropriate self.wait() conditions. + (d0, d1, d2, d3, d4, d5, d6, d7, m1, rd, wr, mreq, iorq, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) = self.wait() + pins = (d0, d1, d2, d3, d4, d5, d6, d7, m1, rd, wr, mreq, iorq, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) + cycle = Cycle.NONE + if pins[Pin.MREQ] != 1: # default to asserted + if pins[Pin.RD] == 0: + cycle = Cycle.FETCH if pins[Pin.M1] == 0 else Cycle.MEMRD + elif pins[Pin.WR] == 0: + cycle = Cycle.MEMWR + elif pins[Pin.IORQ] == 0: # default to not asserted + if pins[Pin.M1] == 0: + cycle = Cycle.INTACK + elif pins[Pin.RD] == 0: + cycle = Cycle.IORD + elif pins[Pin.WR] == 0: + cycle = Cycle.IOWR + + if cycle != Cycle.NONE: + self.bus_data = reduce_bus(pins[Pin.D0:Pin.D7+1]) + if cycle != self.prev_cycle: + if self.prev_cycle == Cycle.NONE: + self.on_cycle_begin(reduce_bus(pins[Pin.A0:Pin.A15+1])) + elif cycle == Cycle.NONE: + self.on_cycle_end() + else: + self.on_cycle_trans() + self.prev_cycle = cycle + + def on_cycle_begin(self, bus_addr): + if self.pend_addr is not None: + self.put_text(self.addr_start, Ann.ADDR, + '{:04X}'.format(self.pend_addr)) + self.addr_start = self.samplenum + self.pend_addr = bus_addr + + def on_cycle_end(self): + self.instr_len += 1 + self.op_state = self.op_state() + if self.ann_dasm is not None: + self.put_disasm() + if self.op_state == self.state_RESTART: + self.op_state = self.state_IDLE() + + if self.ann_data is not None: + self.put_text(self.data_start, self.ann_data, + '{:02X}'.format(self.pend_data)) + self.data_start = self.samplenum + self.pend_data = self.bus_data + self.ann_data = ann_data_cycle_map[self.prev_cycle] + + def on_cycle_trans(self): + self.put_text(self.samplenum - 1, Ann.WARN, + 'Illegal transition between control states') + self.pend_addr = None + self.ann_data = None + self.ann_dasm = None + + def put_disasm(self): + text = formatter.format(self.mnemonic, r=self.arg_reg, d=self.arg_dis, + j=self.arg_dis+self.instr_len, i=self.arg_imm, + ro=self.arg_read, wo=self.arg_write) + self.put_text(self.dasm_start, self.ann_dasm, text) + self.ann_dasm = None + self.dasm_start = self.samplenum + + def put_text(self, ss, ann_idx, ann_text): + self.put(ss, self.samplenum, self.out_ann, [ann_idx, [ann_text]]) + + def state_RESTART(self): + return self.state_IDLE + + def state_IDLE(self): + if self.prev_cycle != Cycle.FETCH: + return self.state_IDLE + self.want_dis = 0 + self.want_imm = 0 + self.want_read = 0 + self.want_write = 0 + self.want_wr_be = False + self.op_repeat = False + self.arg_dis = 0 + self.arg_imm = 0 + self.arg_read = 0 + self.arg_write = 0 + self.arg_reg = '' + self.mnemonic = '' + self.instr_pend = False + self.read_pend = False + self.write_pend = False + self.dasm_start = self.samplenum + self.op_prefix = 0 + self.instr_len = 0 + if self.bus_data in (0xCB, 0xED, 0xDD, 0xFD): + return self.state_PRE1 + else: + return self.state_OPCODE + + def state_PRE1(self): + if self.prev_cycle != Cycle.FETCH: + self.mnemonic = 'Prefix not followed by fetch' + self.ann_dasm = Ann.WARN + return self.state_RESTART + self.op_prefix = self.pend_data + if self.op_prefix in (0xDD, 0xFD): + if self.bus_data == 0xCB: + return self.state_PRE2 + if self.bus_data in (0xDD, 0xED, 0xFD): + return self.state_PRE1 + return self.state_OPCODE + + def state_PRE2(self): + if self.prev_cycle != Cycle.MEMRD: + self.mnemonic = 'Missing displacement' + self.ann_dasm = Ann.WARN + return self.state_RESTART + self.op_prefix = (self.op_prefix << 8) | self.pend_data + return self.state_PREDIS + + def state_PREDIS(self): + if self.prev_cycle != Cycle.MEMRD: + self.mnemonic = 'Missing opcode' + self.ann_dasm = Ann.WARN + return self.state_RESTART + self.arg_dis = signed_byte(self.pend_data) + return self.state_OPCODE + + def state_OPCODE(self): + (table, self.arg_reg) = instr_table_by_prefix[self.op_prefix] + self.op_prefix = 0 + instruction = table.get(self.pend_data, None) + if instruction is None: + self.mnemonic = 'Invalid instruction' + self.ann_dasm = Ann.WARN + return self.state_RESTART + (self.want_dis, self.want_imm, self.want_read, want_write, + self.op_repeat, self.mnemonic) = instruction + self.want_write = abs(want_write) + self.want_wr_be = (want_write < 0) + if self.want_dis > 0: + return self.state_POSTDIS + if self.want_imm > 0: + return self.state_IMM1 + self.ann_dasm = Ann.INSTR + if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD): + return self.state_ROP1 + if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR): + return self.state_WOP1 + return self.state_RESTART + + def state_POSTDIS(self): + self.arg_dis = signed_byte(self.pend_data) + if self.want_imm > 0: + return self.state_IMM1 + self.ann_dasm = Ann.INSTR + if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD): + return self.state_ROP1 + if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR): + return self.state_WOP1 + return self.state_RESTART + + def state_IMM1(self): + self.arg_imm = self.pend_data + if self.want_imm > 1: + return self.state_IMM2 + self.ann_dasm = Ann.INSTR + if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD): + return self.state_ROP1 + if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR): + return self.state_WOP1 + return self.state_RESTART + + def state_IMM2(self): + self.arg_imm |= self.pend_data << 8 + self.ann_dasm = Ann.INSTR + if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD): + return self.state_ROP1 + if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR): + return self.state_WOP1 + return self.state_RESTART + + def state_ROP1(self): + self.arg_read = self.pend_data + if self.want_read < 2: + self.mnemonic = '{ro:02X}' + self.ann_dasm = Ann.ROP + if self.want_write > 0: + return self.state_WOP1 + if self.want_read > 1: + return self.state_ROP2 + if self.op_repeat and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD): + return self.state_ROP1 + return self.state_RESTART + + def state_ROP2(self): + self.arg_read |= self.pend_data << 8 + self.mnemonic = '{ro:04X}' + self.ann_dasm = Ann.ROP + if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR): + return self.state_WOP1 + return self.state_RESTART + + def state_WOP1(self): + self.arg_write = self.pend_data + if self.want_read > 1: + return self.state_ROP2 + if self.want_write > 1: + return self.state_WOP2 + self.mnemonic = '{wo:02X}' + self.ann_dasm = Ann.WOP + if self.want_read > 0 and self.op_repeat and \ + self.prev_cycle in (Cycle.MEMRD, Cycle.IORD): + return self.state_ROP1 + return self.state_RESTART + + def state_WOP2(self): + if self.want_wr_be: + self.arg_write = (self.arg_write << 8) | self.pend_data + else: + self.arg_write |= self.pend_data << 8 + self.mnemonic = '{wo:04X}' + self.ann_dasm = Ann.WOP + return self.state_RESTART diff --git a/libsigrokdecode4DSL/decoders/z80/tables.py b/libsigrokdecode4DSL/decoders/z80/tables.py new file mode 100644 index 00000000..ec77dae3 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/z80/tables.py @@ -0,0 +1,1083 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2014 Daniel Elstner +## +## 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 . +## + +''' +Instruction tuple: (d, i, ro, wo, rep, format string) + + The placeholders d and i are the number of bytes in the instruction + used for the displacement and the immediate operand, respectively. An + operand consisting of more than one byte is assembled in little endian + order. + The placeholders ro and wo are the number of bytes the instruction + is expected to read or write, respectively. These counts are used + for both memory and I/O access, but not for immediate operands. + A negative value indicates that the operand byte order is big endian + rather than the usual little endian. + The placeholder rep is a boolean used to mark repeating instructions. + The format string should refer to the {d} and {i} operands by name. + Displacements are interpreted as signed integers, whereas immediate + operands are always read as unsigned. The tables for instructions + operating on the IX/IY index registers additionally use {r} in the + format string as a placeholder for the register name. + Relative jump instructions may specify {j} instead of {d} to output + the displacement relative to the start of the instruction. +''' + +# Instructions without a prefix +main_instructions = { + 0x00: (0, 0, 0, 0, False, 'NOP'), + 0x01: (0, 2, 0, 0, False, 'LD BC,{i:04H}h'), + 0x02: (0, 0, 0, 1, False, 'LD (BC),A'), + 0x03: (0, 0, 0, 0, False, 'INC BC'), + 0x04: (0, 0, 0, 0, False, 'INC B'), + 0x05: (0, 0, 0, 0, False, 'DEC B'), + 0x06: (0, 1, 0, 0, False, 'LD B,{i:02H}h'), + 0x07: (0, 0, 0, 0, False, 'RLCA'), + 0x08: (0, 0, 0, 0, False, 'EX AF,AF\''), + 0x09: (0, 0, 0, 0, False, 'ADD HL,BC'), + 0x0A: (0, 0, 1, 0, False, 'LD A,(BC)'), + 0x0B: (0, 0, 0, 0, False, 'DEC BC'), + 0x0C: (0, 0, 0, 0, False, 'INC C'), + 0x0D: (0, 0, 0, 0, False, 'DEC C'), + 0x0E: (0, 1, 0, 0, False, 'LD C,{i:02H}h'), + 0x0F: (0, 0, 0, 0, False, 'RRCA'), + + 0x10: (1, 0, 0, 0, False, 'DJNZ ${j:+d}'), + 0x11: (0, 2, 0, 0, False, 'LD DE,{i:04H}h'), + 0x12: (0, 0, 0, 1, False, 'LD (DE),A'), + 0x13: (0, 0, 0, 0, False, 'INC DE'), + 0x14: (0, 0, 0, 0, False, 'INC D'), + 0x15: (0, 0, 0, 0, False, 'DEC D'), + 0x16: (0, 1, 0, 0, False, 'LD D,{i:02H}h'), + 0x17: (0, 0, 0, 0, False, 'RLA'), + 0x18: (1, 0, 0, 0, False, 'JR ${j:+d}'), + 0x19: (0, 0, 0, 0, False, 'ADD HL,DE'), + 0x1A: (0, 0, 1, 0, False, 'LD A,(DE)'), + 0x1B: (0, 0, 0, 0, False, 'DEC DE'), + 0x1C: (0, 0, 0, 0, False, 'INC E'), + 0x1D: (0, 0, 0, 0, False, 'DEC E'), + 0x1E: (0, 1, 0, 0, False, 'LD E,{i:02H}h'), + 0x1F: (0, 0, 0, 0, False, 'RRA'), + + 0x20: (1, 0, 0, 0, False, 'JR NZ,${j:+d}'), + 0x21: (0, 2, 0, 0, False, 'LD HL,{i:04H}h'), + 0x22: (0, 2, 0, 2, False, 'LD ({i:04H}h),HL'), + 0x23: (0, 0, 0, 0, False, 'INC HL'), + 0x24: (0, 0, 0, 0, False, 'INC H'), + 0x25: (0, 0, 0, 0, False, 'DEC H'), + 0x26: (0, 1, 0, 0, False, 'LD H,{i:02H}h'), + 0x27: (0, 0, 0, 0, False, 'DAA'), + 0x28: (1, 0, 0, 0, False, 'JR Z,${j:+d}'), + 0x29: (0, 0, 0, 0, False, 'ADD HL,HL'), + 0x2A: (0, 2, 2, 0, False, 'LD HL,({i:04H}h)'), + 0x2B: (0, 0, 0, 0, False, 'DEC HL'), + 0x2C: (0, 0, 0, 0, False, 'INC L'), + 0x2D: (0, 0, 0, 0, False, 'DEC L'), + 0x2E: (0, 1, 0, 0, False, 'LD L,{i:02H}h'), + 0x2F: (0, 0, 0, 0, False, 'CPL'), + + 0x30: (1, 0, 0, 0, False, 'JR NC,${j:+d}'), + 0x31: (0, 2, 0, 0, False, 'LD SP,{i:04H}h'), + 0x32: (0, 2, 0, 1, False, 'LD ({i:04H}h),A'), + 0x33: (0, 0, 0, 0, False, 'INC SP'), + 0x34: (0, 0, 1, 1, False, 'INC (HL)'), + 0x35: (0, 0, 1, 1, False, 'DEC (HL)'), + 0x36: (0, 1, 0, 1, False, 'LD (HL),{i:02H}h'), + 0x37: (0, 0, 0, 0, False, 'SCF'), + 0x38: (1, 0, 0, 0, False, 'JR C,${j:+d}'), + 0x39: (0, 0, 0, 0, False, 'ADD HL,SP'), + 0x3A: (0, 2, 1, 0, False, 'LD A,({i:04H}h)'), + 0x3B: (0, 0, 0, 0, False, 'DEC SP'), + 0x3C: (0, 0, 0, 0, False, 'INC A'), + 0x3D: (0, 0, 0, 0, False, 'DEC A'), + 0x3E: (0, 1, 0, 0, False, 'LD A,{i:02H}h'), + 0x3F: (0, 0, 0, 0, False, 'CCF'), + + 0x40: (0, 0, 0, 0, False, 'LD B,B'), + 0x41: (0, 0, 0, 0, False, 'LD B,C'), + 0x42: (0, 0, 0, 0, False, 'LD B,D'), + 0x43: (0, 0, 0, 0, False, 'LD B,E'), + 0x44: (0, 0, 0, 0, False, 'LD B,H'), + 0x45: (0, 0, 0, 0, False, 'LD B,L'), + 0x46: (0, 0, 1, 0, False, 'LD B,(HL)'), + 0x47: (0, 0, 0, 0, False, 'LD B,A'), + 0x48: (0, 0, 0, 0, False, 'LD C,B'), + 0x49: (0, 0, 0, 0, False, 'LD C,C'), + 0x4A: (0, 0, 0, 0, False, 'LD C,D'), + 0x4B: (0, 0, 0, 0, False, 'LD C,E'), + 0x4C: (0, 0, 0, 0, False, 'LD C,H'), + 0x4D: (0, 0, 0, 0, False, 'LD C,L'), + 0x4E: (0, 0, 1, 0, False, 'LD C,(HL)'), + 0x4F: (0, 0, 0, 0, False, 'LD C,A'), + + 0x50: (0, 0, 0, 0, False, 'LD D,B'), + 0x51: (0, 0, 0, 0, False, 'LD D,C'), + 0x52: (0, 0, 0, 0, False, 'LD D,D'), + 0x53: (0, 0, 0, 0, False, 'LD D,E'), + 0x54: (0, 0, 0, 0, False, 'LD D,H'), + 0x55: (0, 0, 0, 0, False, 'LD D,L'), + 0x56: (0, 0, 1, 0, False, 'LD D,(HL)'), + 0x57: (0, 0, 0, 0, False, 'LD D,A'), + 0x58: (0, 0, 0, 0, False, 'LD E,B'), + 0x59: (0, 0, 0, 0, False, 'LD E,C'), + 0x5A: (0, 0, 0, 0, False, 'LD E,D'), + 0x5B: (0, 0, 0, 0, False, 'LD E,E'), + 0x5C: (0, 0, 0, 0, False, 'LD E,H'), + 0x5D: (0, 0, 0, 0, False, 'LD E,L'), + 0x5E: (0, 0, 1, 0, False, 'LD E,(HL)'), + 0x5F: (0, 0, 0, 0, False, 'LD E,A'), + + 0x60: (0, 0, 0, 0, False, 'LD H,B'), + 0x61: (0, 0, 0, 0, False, 'LD H,C'), + 0x62: (0, 0, 0, 0, False, 'LD H,D'), + 0x63: (0, 0, 0, 0, False, 'LD H,E'), + 0x64: (0, 0, 0, 0, False, 'LD H,H'), + 0x65: (0, 0, 0, 0, False, 'LD H,L'), + 0x66: (0, 0, 1, 0, False, 'LD H,(HL)'), + 0x67: (0, 0, 0, 0, False, 'LD H,A'), + 0x68: (0, 0, 0, 0, False, 'LD L,B'), + 0x69: (0, 0, 0, 0, False, 'LD L,C'), + 0x6A: (0, 0, 0, 0, False, 'LD L,D'), + 0x6B: (0, 0, 0, 0, False, 'LD L,E'), + 0x6C: (0, 0, 0, 0, False, 'LD L,H'), + 0x6D: (0, 0, 0, 0, False, 'LD L,L'), + 0x6E: (0, 0, 1, 0, False, 'LD L,(HL)'), + 0x6F: (0, 0, 0, 0, False, 'LD L,A'), + + 0x70: (0, 0, 0, 1, False, 'LD (HL),B'), + 0x71: (0, 0, 0, 1, False, 'LD (HL),C'), + 0x72: (0, 0, 0, 1, False, 'LD (HL),D'), + 0x73: (0, 0, 0, 1, False, 'LD (HL),E'), + 0x74: (0, 0, 0, 1, False, 'LD (HL),H'), + 0x75: (0, 0, 0, 1, False, 'LD (HL),L'), + 0x76: (0, 0, 0, 0, False, 'HALT'), + 0x77: (0, 0, 0, 1, False, 'LD (HL),A'), + 0x78: (0, 0, 0, 0, False, 'LD A,B'), + 0x79: (0, 0, 0, 0, False, 'LD A,C'), + 0x7A: (0, 0, 0, 0, False, 'LD A,D'), + 0x7B: (0, 0, 0, 0, False, 'LD A,E'), + 0x7C: (0, 0, 0, 0, False, 'LD A,H'), + 0x7D: (0, 0, 0, 0, False, 'LD A,L'), + 0x7E: (0, 0, 1, 0, False, 'LD A,(HL)'), + 0x7F: (0, 0, 0, 0, False, 'LD A,A'), + + 0x80: (0, 0, 0, 0, False, 'ADD A,B'), + 0x81: (0, 0, 0, 0, False, 'ADD A,C'), + 0x82: (0, 0, 0, 0, False, 'ADD A,D'), + 0x83: (0, 0, 0, 0, False, 'ADD A,E'), + 0x84: (0, 0, 0, 0, False, 'ADD A,H'), + 0x85: (0, 0, 0, 0, False, 'ADD A,L'), + 0x86: (0, 0, 1, 0, False, 'ADD A,(HL)'), + 0x87: (0, 0, 0, 0, False, 'ADD A,A'), + 0x88: (0, 0, 0, 0, False, 'ADC A,B'), + 0x89: (0, 0, 0, 0, False, 'ADC A,C'), + 0x8A: (0, 0, 0, 0, False, 'ADC A,D'), + 0x8B: (0, 0, 0, 0, False, 'ADC A,E'), + 0x8C: (0, 0, 0, 0, False, 'ADC A,H'), + 0x8D: (0, 0, 0, 0, False, 'ADC A,L'), + 0x8E: (0, 0, 1, 0, False, 'ADC A,(HL)'), + 0x8F: (0, 0, 0, 0, False, 'ADC A,A'), + + 0x90: (0, 0, 0, 0, False, 'SUB B'), + 0x91: (0, 0, 0, 0, False, 'SUB C'), + 0x92: (0, 0, 0, 0, False, 'SUB D'), + 0x93: (0, 0, 0, 0, False, 'SUB E'), + 0x94: (0, 0, 0, 0, False, 'SUB H'), + 0x95: (0, 0, 0, 0, False, 'SUB L'), + 0x96: (0, 0, 1, 0, False, 'SUB (HL)'), + 0x97: (0, 0, 0, 0, False, 'SUB A'), + 0x98: (0, 0, 0, 0, False, 'SBC A,B'), + 0x99: (0, 0, 0, 0, False, 'SBC A,C'), + 0x9A: (0, 0, 0, 0, False, 'SBC A,D'), + 0x9B: (0, 0, 0, 0, False, 'SBC A,E'), + 0x9C: (0, 0, 0, 0, False, 'SBC A,H'), + 0x9D: (0, 0, 0, 0, False, 'SBC A,L'), + 0x9E: (0, 0, 1, 0, False, 'SBC A,(HL)'), + 0x9F: (0, 0, 0, 0, False, 'SBC A,A'), + + 0xA0: (0, 0, 0, 0, False, 'AND B'), + 0xA1: (0, 0, 0, 0, False, 'AND C'), + 0xA2: (0, 0, 0, 0, False, 'AND D'), + 0xA3: (0, 0, 0, 0, False, 'AND E'), + 0xA4: (0, 0, 0, 0, False, 'AND H'), + 0xA5: (0, 0, 0, 0, False, 'AND L'), + 0xA6: (0, 0, 1, 0, False, 'AND (HL)'), + 0xA7: (0, 0, 0, 0, False, 'AND A'), + 0xA8: (0, 0, 0, 0, False, 'XOR B'), + 0xA9: (0, 0, 0, 0, False, 'XOR C'), + 0xAA: (0, 0, 0, 0, False, 'XOR D'), + 0xAB: (0, 0, 0, 0, False, 'XOR E'), + 0xAC: (0, 0, 0, 0, False, 'XOR H'), + 0xAD: (0, 0, 0, 0, False, 'XOR L'), + 0xAE: (0, 0, 1, 0, False, 'XOR (HL)'), + 0xAF: (0, 0, 0, 0, False, 'XOR A'), + + 0xB0: (0, 0, 0, 0, False, 'OR B'), + 0xB1: (0, 0, 0, 0, False, 'OR C'), + 0xB2: (0, 0, 0, 0, False, 'OR D'), + 0xB3: (0, 0, 0, 0, False, 'OR E'), + 0xB4: (0, 0, 0, 0, False, 'OR H'), + 0xB5: (0, 0, 0, 0, False, 'OR L'), + 0xB6: (0, 0, 1, 0, False, 'OR (HL)'), + 0xB7: (0, 0, 0, 0, False, 'OR A'), + 0xB8: (0, 0, 0, 0, False, 'CP B'), + 0xB9: (0, 0, 0, 0, False, 'CP C'), + 0xBA: (0, 0, 0, 0, False, 'CP D'), + 0xBB: (0, 0, 0, 0, False, 'CP E'), + 0xBC: (0, 0, 0, 0, False, 'CP H'), + 0xBD: (0, 0, 0, 0, False, 'CP L'), + 0xBE: (0, 0, 1, 0, False, 'CP (HL)'), + 0xBF: (0, 0, 0, 0, False, 'CP A'), + + 0xC0: (0, 0, 2, 0, False, 'RET NZ'), + 0xC1: (0, 0, 2, 0, False, 'POP BC'), + 0xC2: (0, 2, 0, 0, False, 'JP NZ,{i:04H}h'), + 0xC3: (0, 2, 0, 0, False, 'JP {i:04H}h'), + 0xC4: (0, 2, 0,-2, False, 'CALL NZ,{i:04H}h'), + 0xC5: (0, 0, 0,-2, False, 'PUSH BC'), + 0xC6: (0, 1, 0, 0, False, 'ADD A,{i:02H}h'), + 0xC7: (0, 0, 0,-2, False, 'RST 00h'), + 0xC8: (0, 0, 2, 0, False, 'RET Z'), + 0xC9: (0, 0, 2, 0, False, 'RET'), + 0xCA: (0, 2, 0, 0, False, 'JP Z,{i:04H}h'), + + 0xCC: (0, 2, 0,-2, False, 'CALL Z,{i:04H}h'), + 0xCD: (0, 2, 0,-2, False, 'CALL {i:04H}h'), + 0xCE: (0, 1, 0, 0, False, 'ADC A,{i:02H}h'), + 0xCF: (0, 0, 0,-2, False, 'RST 08h'), + + 0xD0: (0, 0, 2, 0, False, 'RET NC'), + 0xD1: (0, 0, 2, 0, False, 'POP DE'), + 0xD2: (0, 2, 0, 0, False, 'JP NC,{i:04H}h'), + 0xD3: (0, 1, 0, 1, False, 'OUT ({i:02H}h),A'), + 0xD4: (0, 2, 0,-2, False, 'CALL NC,{i:04H}h'), + 0xD5: (0, 0, 0,-2, False, 'PUSH DE'), + 0xD6: (0, 1, 0, 0, False, 'SUB {i:02H}h'), + 0xD7: (0, 0, 0,-2, False, 'RST 10h'), + 0xD8: (0, 0, 2, 0, False, 'RET C'), + 0xD9: (0, 0, 0, 0, False, 'EXX'), + 0xDA: (0, 2, 0, 0, False, 'JP C,{i:04H}h'), + 0xDB: (0, 1, 1, 0, False, 'IN A,({i:02H}h)'), + 0xDC: (0, 2, 0,-2, False, 'CALL C,{i:04H}h'), + + 0xDE: (0, 1, 0, 0, False, 'SBC A,{i:02H}h'), + 0xDF: (0, 0, 0,-2, False, 'RST 18h'), + + 0xE0: (0, 0, 2, 0, False, 'RET PO'), + 0xE1: (0, 0, 2, 0, False, 'POP HL'), + 0xE2: (0, 2, 0, 0, False, 'JP PO,{i:04H}h'), + 0xE3: (0, 0, 2, 2, False, 'EX (SP),HL'), + 0xE4: (0, 2, 0,-2, False, 'CALL PO,{i:04H}h'), + 0xE5: (0, 0, 0,-2, False, 'PUSH HL'), + 0xE6: (0, 1, 0, 0, False, 'AND {i:02H}h'), + 0xE7: (0, 0, 0,-2, False, 'RST 20h'), + 0xE8: (0, 0, 2, 0, False, 'RET PE'), + 0xE9: (0, 0, 0, 0, False, 'JP (HL)'), + 0xEA: (0, 2, 0, 0, False, 'JP PE,{i:04H}h'), + 0xEB: (0, 0, 0, 0, False, 'EX DE,HL'), + 0xEC: (0, 2, 0,-2, False, 'CALL PE,{i:04H}h'), + + 0xEE: (0, 1, 0, 0, False, 'XOR {i:02H}h'), + 0xEF: (0, 0, 0,-2, False, 'RST 28h'), + + 0xF0: (0, 0, 2, 0, False, 'RET P'), + 0xF1: (0, 0, 2, 0, False, 'POP AF'), + 0xF2: (0, 2, 0, 0, False, 'JP P,{i:04H}h'), + 0xF3: (0, 0, 0, 0, False, 'DI'), + 0xF4: (0, 2, 0,-2, False, 'CALL P,{i:04H}h'), + 0xF5: (0, 0, 0,-2, False, 'PUSH AF'), + 0xF6: (0, 1, 0, 0, False, 'OR {i:02H}h'), + 0xF7: (0, 0, 0,-2, False, 'RST 30h'), + 0xF8: (0, 0, 2, 0, False, 'RET M'), + 0xF9: (0, 0, 0, 0, False, 'LD SP,HL'), + 0xFA: (0, 2, 0, 0, False, 'JP M,{i:04H}h'), + 0xFB: (0, 0, 0, 0, False, 'EI'), + 0xFC: (0, 2, 0,-2, False, 'CALL M,{i:04H}h'), + + 0xFE: (0, 1, 0, 0, False, 'CP {i:02H}h'), + 0xFF: (0, 0, 0,-2, False, 'RST 38h') +} + +# Instructions with ED prefix +extended_instructions = { + 0x40: (0, 0, 1, 0, False, 'IN B,(C)'), + 0x41: (0, 0, 0, 1, False, 'OUT (C),B'), + 0x42: (0, 0, 0, 0, False, 'SBC HL,BC'), + 0x43: (0, 2, 0, 2, False, 'LD ({i:04H}h),BC'), + 0x44: (0, 0, 0, 0, False, 'NEG'), + 0x45: (0, 0, 2, 0, False, 'RETN'), + 0x46: (0, 0, 0, 0, False, 'IM 0'), + 0x47: (0, 0, 0, 0, False, 'LD I,A'), + 0x48: (0, 0, 1, 0, False, 'IN C,(C)'), + 0x49: (0, 0, 0, 1, False, 'OUT (C),C'), + 0x4A: (0, 0, 0, 0, False, 'ADC HL,BC'), + 0x4B: (0, 2, 2, 0, False, 'LD BC,({i:04H}h)'), + 0x4C: (0, 0, 0, 0, False, 'NEG'), + 0x4D: (0, 0, 2, 0, False, 'RETI'), + 0x4E: (0, 0, 0, 0, False, 'IM 0/1'), + 0x4F: (0, 0, 0, 0, False, 'LD R,A'), + + 0x50: (0, 0, 1, 0, False, 'IN D,(C)'), + 0x51: (0, 0, 0, 1, False, 'OUT (C),D'), + 0x52: (0, 0, 0, 0, False, 'SBC HL,DE'), + 0x53: (0, 2, 0, 2, False, 'LD ({i:04H}h),DE'), + 0x54: (0, 0, 0, 0, False, 'NEG'), + 0x55: (0, 0, 2, 0, False, 'RETN'), + 0x56: (0, 0, 0, 0, False, 'IM 1'), + 0x57: (0, 0, 0, 0, False, 'LD A,I'), + 0x58: (0, 0, 1, 0, False, 'IN E,(C)'), + 0x59: (0, 0, 0, 1, False, 'OUT (C),E'), + 0x5A: (0, 0, 0, 0, False, 'ADC HL,DE'), + 0x5B: (0, 2, 2, 0, False, 'LD DE,({i:04H}h)'), + 0x5C: (0, 0, 0, 0, False, 'NEG'), + 0x5D: (0, 0, 2, 0, False, 'RETN'), + 0x5E: (0, 0, 0, 0, False, 'IM 2'), + 0x5F: (0, 0, 0, 0, False, 'LD A,R'), + + 0x60: (0, 0, 1, 0, False, 'IN H,(C)'), + 0x61: (0, 0, 0, 1, False, 'OUT (C),H'), + 0x62: (0, 0, 0, 0, False, 'SBC HL,HL'), + 0x63: (0, 2, 0, 2, False, 'LD ({i:04H}h),HL'), + 0x64: (0, 0, 0, 0, False, 'NEG'), + 0x65: (0, 0, 2, 0, False, 'RETN'), + 0x66: (0, 0, 0, 0, False, 'IM 0'), + 0x67: (0, 0, 1, 1, False, 'RRD'), + 0x68: (0, 0, 1, 0, False, 'IN L,(C)'), + 0x69: (0, 0, 0, 1, False, 'OUT (C),L'), + 0x6A: (0, 0, 0, 0, False, 'ADC HL,HL'), + 0x6B: (0, 2, 2, 0, False, 'LD HL,({i:04H}h)'), + 0x6C: (0, 0, 0, 0, False, 'NEG'), + 0x6D: (0, 0, 2, 0, False, 'RETN'), + 0x6E: (0, 0, 0, 0, False, 'IM 0/1'), + 0x6F: (0, 0, 1, 1, False, 'RLD'), + + 0x70: (0, 0, 1, 0, False, 'IN (C)'), + 0x71: (0, 0, 0, 1, False, 'OUT (C),0'), + 0x72: (0, 0, 0, 0, False, 'SBC HL,SP'), + 0x73: (0, 2, 0, 2, False, 'LD ({i:04H}h),SP'), + 0x74: (0, 0, 0, 0, False, 'NEG'), + 0x75: (0, 0, 2, 0, False, 'RETN'), + 0x76: (0, 0, 0, 0, False, 'IM 1'), + + 0x78: (0, 0, 1, 0, False, 'IN A,(C)'), + 0x79: (0, 0, 0, 1, False, 'OUT (C),A'), + 0x7A: (0, 0, 0, 0, False, 'ADC HL,SP'), + 0x7B: (0, 2, 2, 0, False, 'LD SP,({i:04H}h)'), + 0x7C: (0, 0, 0, 0, False, 'NEG'), + 0x7D: (0, 0, 2, 0, False, 'RETN'), + 0x7E: (0, 0, 0, 0, False, 'IM 2'), + + 0xA0: (0, 0, 1, 1, False, 'LDI'), + 0xA1: (0, 0, 1, 0, False, 'CPI'), + 0xA2: (0, 0, 1, 1, False, 'INI'), + 0xA3: (0, 0, 1, 1, False, 'OUTI'), + + 0xA8: (0, 0, 1, 1, False, 'LDD'), + 0xA9: (0, 0, 1, 0, False, 'CPD'), + 0xAA: (0, 0, 1, 1, False, 'IND'), + 0xAB: (0, 0, 1, 1, False, 'OUTD'), + + 0xB0: (0, 0, 1, 1, True, 'LDIR'), + 0xB1: (0, 0, 1, 0, True, 'CPIR'), + 0xB2: (0, 0, 1, 1, True, 'INIR'), + 0xB3: (0, 0, 1, 1, True, 'OTIR'), + + 0xB8: (0, 0, 1, 1, True, 'LDDR'), + 0xB9: (0, 0, 1, 0, True, 'CPDR'), + 0xBA: (0, 0, 1, 1, True, 'INDR'), + 0xBB: (0, 0, 1, 1, True, 'OTDR') +} + +# Instructions with CB prefix +bit_instructions = { + 0x00: (0, 0, 0, 0, False, 'RLC B'), + 0x01: (0, 0, 0, 0, False, 'RLC C'), + 0x02: (0, 0, 0, 0, False, 'RLC D'), + 0x03: (0, 0, 0, 0, False, 'RLC E'), + 0x04: (0, 0, 0, 0, False, 'RLC H'), + 0x05: (0, 0, 0, 0, False, 'RLC L'), + 0x06: (0, 0, 1, 1, False, 'RLC (HL)'), + 0x07: (0, 0, 0, 0, False, 'RLC A'), + 0x08: (0, 0, 0, 0, False, 'RRC B'), + 0x09: (0, 0, 0, 0, False, 'RRC C'), + 0x0A: (0, 0, 0, 0, False, 'RRC D'), + 0x0B: (0, 0, 0, 0, False, 'RRC E'), + 0x0C: (0, 0, 0, 0, False, 'RRC H'), + 0x0D: (0, 0, 0, 0, False, 'RRC L'), + 0x0E: (0, 0, 1, 1, False, 'RRC (HL)'), + 0x0F: (0, 0, 0, 0, False, 'RRC A'), + + 0x10: (0, 0, 0, 0, False, 'RL B'), + 0x11: (0, 0, 0, 0, False, 'RL C'), + 0x12: (0, 0, 0, 0, False, 'RL D'), + 0x13: (0, 0, 0, 0, False, 'RL E'), + 0x14: (0, 0, 0, 0, False, 'RL H'), + 0x15: (0, 0, 0, 0, False, 'RL L'), + 0x16: (0, 0, 1, 1, False, 'RL (HL)'), + 0x17: (0, 0, 0, 0, False, 'RL A'), + 0x18: (0, 0, 0, 0, False, 'RR B'), + 0x19: (0, 0, 0, 0, False, 'RR C'), + 0x1A: (0, 0, 0, 0, False, 'RR D'), + 0x1B: (0, 0, 0, 0, False, 'RR E'), + 0x1C: (0, 0, 0, 0, False, 'RR H'), + 0x1D: (0, 0, 0, 0, False, 'RR L'), + 0x1E: (0, 0, 1, 1, False, 'RR (HL)'), + 0x1F: (0, 0, 0, 0, False, 'RR A'), + + 0x20: (0, 0, 0, 0, False, 'SLA B'), + 0x21: (0, 0, 0, 0, False, 'SLA C'), + 0x22: (0, 0, 0, 0, False, 'SLA D'), + 0x23: (0, 0, 0, 0, False, 'SLA E'), + 0x24: (0, 0, 0, 0, False, 'SLA H'), + 0x25: (0, 0, 0, 0, False, 'SLA L'), + 0x26: (0, 0, 1, 1, False, 'SLA (HL)'), + 0x27: (0, 0, 0, 0, False, 'SLA A'), + 0x28: (0, 0, 0, 0, False, 'SRA B'), + 0x29: (0, 0, 0, 0, False, 'SRA C'), + 0x2A: (0, 0, 0, 0, False, 'SRA D'), + 0x2B: (0, 0, 0, 0, False, 'SRA E'), + 0x2C: (0, 0, 0, 0, False, 'SRA H'), + 0x2D: (0, 0, 0, 0, False, 'SRA L'), + 0x2E: (0, 0, 1, 1, False, 'SRA (HL)'), + 0x2F: (0, 0, 0, 0, False, 'SRA A'), + + 0x30: (0, 0, 0, 0, False, 'SLL B'), + 0x31: (0, 0, 0, 0, False, 'SLL C'), + 0x32: (0, 0, 0, 0, False, 'SLL D'), + 0x33: (0, 0, 0, 0, False, 'SLL E'), + 0x34: (0, 0, 0, 0, False, 'SLL H'), + 0x35: (0, 0, 0, 0, False, 'SLL L'), + 0x36: (0, 0, 1, 1, False, 'SLL (HL)'), + 0x37: (0, 0, 0, 0, False, 'SLL A'), + 0x38: (0, 0, 0, 0, False, 'SRL B'), + 0x39: (0, 0, 0, 0, False, 'SRL C'), + 0x3A: (0, 0, 0, 0, False, 'SRL D'), + 0x3B: (0, 0, 0, 0, False, 'SRL E'), + 0x3C: (0, 0, 0, 0, False, 'SRL H'), + 0x3D: (0, 0, 0, 0, False, 'SRL L'), + 0x3E: (0, 0, 1, 1, False, 'SRL (HL)'), + 0x3F: (0, 0, 0, 0, False, 'SRL A'), + + 0x40: (0, 0, 0, 0, False, 'BIT 0,B'), + 0x41: (0, 0, 0, 0, False, 'BIT 0,C'), + 0x42: (0, 0, 0, 0, False, 'BIT 0,D'), + 0x43: (0, 0, 0, 0, False, 'BIT 0,E'), + 0x44: (0, 0, 0, 0, False, 'BIT 0,H'), + 0x45: (0, 0, 0, 0, False, 'BIT 0,L'), + 0x46: (0, 0, 1, 0, False, 'BIT 0,(HL)'), + 0x47: (0, 0, 0, 0, False, 'BIT 0,A'), + 0x48: (0, 0, 0, 0, False, 'BIT 1,B'), + 0x49: (0, 0, 0, 0, False, 'BIT 1,C'), + 0x4A: (0, 0, 0, 0, False, 'BIT 1,D'), + 0x4B: (0, 0, 0, 0, False, 'BIT 1,E'), + 0x4C: (0, 0, 0, 0, False, 'BIT 1,H'), + 0x4D: (0, 0, 0, 0, False, 'BIT 1,L'), + 0x4E: (0, 0, 1, 0, False, 'BIT 1,(HL)'), + 0x4F: (0, 0, 0, 0, False, 'BIT 1,A'), + + 0x50: (0, 0, 0, 0, False, 'BIT 2,B'), + 0x51: (0, 0, 0, 0, False, 'BIT 2,C'), + 0x52: (0, 0, 0, 0, False, 'BIT 2,D'), + 0x53: (0, 0, 0, 0, False, 'BIT 2,E'), + 0x54: (0, 0, 0, 0, False, 'BIT 2,H'), + 0x55: (0, 0, 0, 0, False, 'BIT 2,L'), + 0x56: (0, 0, 1, 0, False, 'BIT 2,(HL)'), + 0x57: (0, 0, 0, 0, False, 'BIT 2,A'), + 0x58: (0, 0, 0, 0, False, 'BIT 3,B'), + 0x59: (0, 0, 0, 0, False, 'BIT 3,C'), + 0x5A: (0, 0, 0, 0, False, 'BIT 3,D'), + 0x5B: (0, 0, 0, 0, False, 'BIT 3,E'), + 0x5C: (0, 0, 0, 0, False, 'BIT 3,H'), + 0x5D: (0, 0, 0, 0, False, 'BIT 3,L'), + 0x5E: (0, 0, 1, 0, False, 'BIT 3,(HL)'), + 0x5F: (0, 0, 0, 0, False, 'BIT 3,A'), + + 0x60: (0, 0, 0, 0, False, 'BIT 4,B'), + 0x61: (0, 0, 0, 0, False, 'BIT 4,C'), + 0x62: (0, 0, 0, 0, False, 'BIT 4,D'), + 0x63: (0, 0, 0, 0, False, 'BIT 4,E'), + 0x64: (0, 0, 0, 0, False, 'BIT 4,H'), + 0x65: (0, 0, 0, 0, False, 'BIT 4,L'), + 0x66: (0, 0, 1, 0, False, 'BIT 4,(HL)'), + 0x67: (0, 0, 0, 0, False, 'BIT 4,A'), + 0x68: (0, 0, 0, 0, False, 'BIT 5,B'), + 0x69: (0, 0, 0, 0, False, 'BIT 5,C'), + 0x6A: (0, 0, 0, 0, False, 'BIT 5,D'), + 0x6B: (0, 0, 0, 0, False, 'BIT 5,E'), + 0x6C: (0, 0, 0, 0, False, 'BIT 5,H'), + 0x6D: (0, 0, 0, 0, False, 'BIT 5,L'), + 0x6E: (0, 0, 1, 0, False, 'BIT 5,(HL)'), + 0x6F: (0, 0, 0, 0, False, 'BIT 5,A'), + + 0x70: (0, 0, 0, 0, False, 'BIT 6,B'), + 0x71: (0, 0, 0, 0, False, 'BIT 6,C'), + 0x72: (0, 0, 0, 0, False, 'BIT 6,D'), + 0x73: (0, 0, 0, 0, False, 'BIT 6,E'), + 0x74: (0, 0, 0, 0, False, 'BIT 6,H'), + 0x75: (0, 0, 0, 0, False, 'BIT 6,L'), + 0x76: (0, 0, 1, 0, False, 'BIT 6,(HL)'), + 0x77: (0, 0, 0, 0, False, 'BIT 6,A'), + 0x78: (0, 0, 0, 0, False, 'BIT 7,B'), + 0x79: (0, 0, 0, 0, False, 'BIT 7,C'), + 0x7A: (0, 0, 0, 0, False, 'BIT 7,D'), + 0x7B: (0, 0, 0, 0, False, 'BIT 7,E'), + 0x7C: (0, 0, 0, 0, False, 'BIT 7,H'), + 0x7D: (0, 0, 0, 0, False, 'BIT 7,L'), + 0x7E: (0, 0, 1, 0, False, 'BIT 7,(HL)'), + 0x7F: (0, 0, 0, 0, False, 'BIT 7,A'), + + 0x80: (0, 0, 0, 0, False, 'RES 0,B'), + 0x81: (0, 0, 0, 0, False, 'RES 0,C'), + 0x82: (0, 0, 0, 0, False, 'RES 0,D'), + 0x83: (0, 0, 0, 0, False, 'RES 0,E'), + 0x84: (0, 0, 0, 0, False, 'RES 0,H'), + 0x85: (0, 0, 0, 0, False, 'RES 0,L'), + 0x86: (0, 0, 1, 1, False, 'RES 0,(HL)'), + 0x87: (0, 0, 0, 0, False, 'RES 0,A'), + 0x88: (0, 0, 0, 0, False, 'RES 1,B'), + 0x89: (0, 0, 0, 0, False, 'RES 1,C'), + 0x8A: (0, 0, 0, 0, False, 'RES 1,D'), + 0x8B: (0, 0, 0, 0, False, 'RES 1,E'), + 0x8C: (0, 0, 0, 0, False, 'RES 1,H'), + 0x8D: (0, 0, 0, 0, False, 'RES 1,L'), + 0x8E: (0, 0, 1, 1, False, 'RES 1,(HL)'), + 0x8F: (0, 0, 0, 0, False, 'RES 1,A'), + + 0x90: (0, 0, 0, 0, False, 'RES 2,B'), + 0x91: (0, 0, 0, 0, False, 'RES 2,C'), + 0x92: (0, 0, 0, 0, False, 'RES 2,D'), + 0x93: (0, 0, 0, 0, False, 'RES 2,E'), + 0x94: (0, 0, 0, 0, False, 'RES 2,H'), + 0x95: (0, 0, 0, 0, False, 'RES 2,L'), + 0x96: (0, 0, 1, 1, False, 'RES 2,(HL)'), + 0x97: (0, 0, 0, 0, False, 'RES 2,A'), + 0x98: (0, 0, 0, 0, False, 'RES 3,B'), + 0x99: (0, 0, 0, 0, False, 'RES 3,C'), + 0x9A: (0, 0, 0, 0, False, 'RES 3,D'), + 0x9B: (0, 0, 0, 0, False, 'RES 3,E'), + 0x9C: (0, 0, 0, 0, False, 'RES 3,H'), + 0x9D: (0, 0, 0, 0, False, 'RES 3,L'), + 0x9E: (0, 0, 1, 1, False, 'RES 3,(HL)'), + 0x9F: (0, 0, 0, 0, False, 'RES 3,A'), + + 0xA0: (0, 0, 0, 0, False, 'RES 4,B'), + 0xA1: (0, 0, 0, 0, False, 'RES 4,C'), + 0xA2: (0, 0, 0, 0, False, 'RES 4,D'), + 0xA3: (0, 0, 0, 0, False, 'RES 4,E'), + 0xA4: (0, 0, 0, 0, False, 'RES 4,H'), + 0xA5: (0, 0, 0, 0, False, 'RES 4,L'), + 0xA6: (0, 0, 1, 1, False, 'RES 4,(HL)'), + 0xA7: (0, 0, 0, 0, False, 'RES 4,A'), + 0xA8: (0, 0, 0, 0, False, 'RES 5,B'), + 0xA9: (0, 0, 0, 0, False, 'RES 5,C'), + 0xAA: (0, 0, 0, 0, False, 'RES 5,D'), + 0xAB: (0, 0, 0, 0, False, 'RES 5,E'), + 0xAC: (0, 0, 0, 0, False, 'RES 5,H'), + 0xAD: (0, 0, 0, 0, False, 'RES 5,L'), + 0xAE: (0, 0, 1, 1, False, 'RES 5,(HL)'), + 0xAF: (0, 0, 0, 0, False, 'RES 5,A'), + + 0xB0: (0, 0, 0, 0, False, 'RES 6,B'), + 0xB1: (0, 0, 0, 0, False, 'RES 6,C'), + 0xB2: (0, 0, 0, 0, False, 'RES 6,D'), + 0xB3: (0, 0, 0, 0, False, 'RES 6,E'), + 0xB4: (0, 0, 0, 0, False, 'RES 6,H'), + 0xB5: (0, 0, 0, 0, False, 'RES 6,L'), + 0xB6: (0, 0, 1, 1, False, 'RES 6,(HL)'), + 0xB7: (0, 0, 0, 0, False, 'RES 6,A'), + 0xB8: (0, 0, 0, 0, False, 'RES 7,B'), + 0xB9: (0, 0, 0, 0, False, 'RES 7,C'), + 0xBA: (0, 0, 0, 0, False, 'RES 7,D'), + 0xBB: (0, 0, 0, 0, False, 'RES 7,E'), + 0xBC: (0, 0, 0, 0, False, 'RES 7,H'), + 0xBD: (0, 0, 0, 0, False, 'RES 7,L'), + 0xBE: (0, 0, 1, 1, False, 'RES 7,(HL)'), + 0xBF: (0, 0, 0, 0, False, 'RES 7,A'), + + 0xC0: (0, 0, 0, 0, False, 'SET 0,B'), + 0xC1: (0, 0, 0, 0, False, 'SET 0,C'), + 0xC2: (0, 0, 0, 0, False, 'SET 0,D'), + 0xC3: (0, 0, 0, 0, False, 'SET 0,E'), + 0xC4: (0, 0, 0, 0, False, 'SET 0,H'), + 0xC5: (0, 0, 0, 0, False, 'SET 0,L'), + 0xC6: (0, 0, 1, 1, False, 'SET 0,(HL)'), + 0xC7: (0, 0, 0, 0, False, 'SET 0,A'), + 0xC8: (0, 0, 0, 0, False, 'SET 1,B'), + 0xC9: (0, 0, 0, 0, False, 'SET 1,C'), + 0xCA: (0, 0, 0, 0, False, 'SET 1,D'), + 0xCB: (0, 0, 0, 0, False, 'SET 1,E'), + 0xCC: (0, 0, 0, 0, False, 'SET 1,H'), + 0xCD: (0, 0, 0, 0, False, 'SET 1,L'), + 0xCE: (0, 0, 1, 1, False, 'SET 1,(HL)'), + 0xCF: (0, 0, 0, 0, False, 'SET 1,A'), + + 0xD0: (0, 0, 0, 0, False, 'SET 2,B'), + 0xD1: (0, 0, 0, 0, False, 'SET 2,C'), + 0xD2: (0, 0, 0, 0, False, 'SET 2,D'), + 0xD3: (0, 0, 0, 0, False, 'SET 2,E'), + 0xD4: (0, 0, 0, 0, False, 'SET 2,H'), + 0xD5: (0, 0, 0, 0, False, 'SET 2,L'), + 0xD6: (0, 0, 1, 1, False, 'SET 2,(HL)'), + 0xD7: (0, 0, 0, 0, False, 'SET 2,A'), + 0xD8: (0, 0, 0, 0, False, 'SET 3,B'), + 0xD9: (0, 0, 0, 0, False, 'SET 3,C'), + 0xDA: (0, 0, 0, 0, False, 'SET 3,D'), + 0xDB: (0, 0, 0, 0, False, 'SET 3,E'), + 0xDC: (0, 0, 0, 0, False, 'SET 3,H'), + 0xDD: (0, 0, 0, 0, False, 'SET 3,L'), + 0xDE: (0, 0, 1, 1, False, 'SET 3,(HL)'), + 0xDF: (0, 0, 0, 0, False, 'SET 3,A'), + + 0xE0: (0, 0, 0, 0, False, 'SET 4,B'), + 0xE1: (0, 0, 0, 0, False, 'SET 4,C'), + 0xE2: (0, 0, 0, 0, False, 'SET 4,D'), + 0xE3: (0, 0, 0, 0, False, 'SET 4,E'), + 0xE4: (0, 0, 0, 0, False, 'SET 4,H'), + 0xE5: (0, 0, 0, 0, False, 'SET 4,L'), + 0xE6: (0, 0, 1, 1, False, 'SET 4,(HL)'), + 0xE7: (0, 0, 0, 0, False, 'SET 4,A'), + 0xE8: (0, 0, 0, 0, False, 'SET 5,B'), + 0xE9: (0, 0, 0, 0, False, 'SET 5,C'), + 0xEA: (0, 0, 0, 0, False, 'SET 5,D'), + 0xEB: (0, 0, 0, 0, False, 'SET 5,E'), + 0xEC: (0, 0, 0, 0, False, 'SET 5,H'), + 0xED: (0, 0, 0, 0, False, 'SET 5,L'), + 0xEE: (0, 0, 1, 1, False, 'SET 5,(HL)'), + 0xEF: (0, 0, 0, 0, False, 'SET 5,A'), + + 0xF0: (0, 0, 0, 0, False, 'SET 6,B'), + 0xF1: (0, 0, 0, 0, False, 'SET 6,C'), + 0xF2: (0, 0, 0, 0, False, 'SET 6,D'), + 0xF3: (0, 0, 0, 0, False, 'SET 6,E'), + 0xF4: (0, 0, 0, 0, False, 'SET 6,H'), + 0xF5: (0, 0, 0, 0, False, 'SET 6,L'), + 0xF6: (0, 0, 1, 1, False, 'SET 6,(HL)'), + 0xF7: (0, 0, 0, 0, False, 'SET 6,A'), + 0xF8: (0, 0, 0, 0, False, 'SET 7,B'), + 0xF9: (0, 0, 0, 0, False, 'SET 7,C'), + 0xFA: (0, 0, 0, 0, False, 'SET 7,D'), + 0xFB: (0, 0, 0, 0, False, 'SET 7,E'), + 0xFC: (0, 0, 0, 0, False, 'SET 7,H'), + 0xFD: (0, 0, 0, 0, False, 'SET 7,L'), + 0xFE: (0, 0, 1, 1, False, 'SET 7,(HL)'), + 0xFF: (0, 0, 0, 0, False, 'SET 7,A') +} + +# Instructions with DD or FD prefix +index_instructions = { + 0x09: (0, 0, 0, 0, False, 'ADD {r},BC'), + + 0x19: (0, 0, 0, 0, False, 'ADD {r},DE'), + + 0x21: (0, 2, 0, 0, False, 'LD {r},{i:04H}h'), + 0x22: (0, 2, 0, 2, False, 'LD ({i:04H}h),{r}'), + 0x23: (0, 0, 0, 0, False, 'INC {r}'), + 0x24: (0, 0, 0, 0, False, 'INC {r}h'), + 0x25: (0, 0, 0, 0, False, 'DEC {r}h'), + 0x26: (0, 1, 0, 0, False, 'LD {r}h,{i:02H}h'), + + 0x29: (0, 0, 0, 0, False, 'ADD {r},{r}'), + 0x2A: (0, 2, 2, 0, False, 'LD {r},({i:04H}h)'), + 0x2B: (0, 0, 0, 0, False, 'DEC {r}'), + 0x2C: (0, 0, 0, 0, False, 'INC {r}l'), + 0x2D: (0, 0, 0, 0, False, 'DEC {r}l'), + 0x2E: (0, 1, 0, 0, False, 'LD {r}l,{i:02H}h'), + + 0x34: (1, 0, 1, 1, False, 'INC ({r}{d:+d})'), + 0x35: (1, 0, 1, 1, False, 'DEC ({r}{d:+d})'), + 0x36: (1, 1, 0, 1, False, 'LD ({r}{d:+d}),{i:02H}h'), + + 0x39: (0, 0, 0, 0, False, 'ADD {r},SP'), + + 0x44: (0, 0, 0, 0, False, 'LD B,{r}h'), + 0x45: (0, 0, 0, 0, False, 'LD B,{r}l'), + 0x46: (1, 0, 1, 0, False, 'LD B,({r}{d:+d})'), + + 0x4C: (0, 0, 0, 0, False, 'LD C,{r}h'), + 0x4D: (0, 0, 0, 0, False, 'LD C,{r}l'), + 0x4E: (1, 0, 1, 0, False, 'LD C,({r}{d:+d})'), + + 0x54: (0, 0, 0, 0, False, 'LD D,{r}h'), + 0x55: (0, 0, 0, 0, False, 'LD D,{r}l'), + 0x56: (1, 0, 1, 0, False, 'LD D,({r}{d:+d})'), + + 0x5C: (0, 0, 0, 0, False, 'LD E,{r}h'), + 0x5D: (0, 0, 0, 0, False, 'LD E,{r}l'), + 0x5E: (1, 0, 1, 0, False, 'LD E,({r}{d:+d})'), + + 0x60: (0, 0, 0, 0, False, 'LD {r}h,B'), + 0x61: (0, 0, 0, 0, False, 'LD {r}h,C'), + 0x62: (0, 0, 0, 0, False, 'LD {r}h,D'), + 0x63: (0, 0, 0, 0, False, 'LD {r}h,E'), + 0x64: (0, 0, 0, 0, False, 'LD {r}h,{r}h'), + 0x65: (0, 0, 0, 0, False, 'LD {r}h,{r}l'), + 0x66: (1, 0, 1, 0, False, 'LD H,({r}{d:+d})'), + 0x67: (0, 0, 0, 0, False, 'LD {r}h,A'), + 0x68: (0, 0, 0, 0, False, 'LD {r}l,B'), + 0x69: (0, 0, 0, 0, False, 'LD {r}l,C'), + 0x6A: (0, 0, 0, 0, False, 'LD {r}l,D'), + 0x6B: (0, 0, 0, 0, False, 'LD {r}l,E'), + 0x6C: (0, 0, 0, 0, False, 'LD {r}l,{r}h'), + 0x6D: (0, 0, 0, 0, False, 'LD {r}l,{r}l'), + 0x6E: (1, 0, 1, 0, False, 'LD L,({r}{d:+d})'), + 0x6F: (0, 0, 0, 0, False, 'LD {r}l,A'), + + 0x70: (1, 0, 0, 1, False, 'LD ({r}{d:+d}),B'), + 0x71: (1, 0, 0, 1, False, 'LD ({r}{d:+d}),C'), + 0x72: (1, 0, 0, 1, False, 'LD ({r}{d:+d}),D'), + 0x73: (1, 0, 0, 1, False, 'LD ({r}{d:+d}),E'), + 0x74: (1, 0, 0, 1, False, 'LD ({r}{d:+d}),H'), + 0x75: (1, 0, 0, 1, False, 'LD ({r}{d:+d}),L'), + + 0x77: (1, 0, 0, 1, False, 'LD ({r}{d:+d}),A'), + + 0x7C: (0, 0, 0, 0, False, 'LD A,{r}h'), + 0x7D: (0, 0, 0, 0, False, 'LD A,{r}l'), + 0x7E: (1, 0, 1, 0, False, 'LD A,({r}{d:+d})'), + + 0x84: (0, 0, 0, 0, False, 'ADD A,{r}h'), + 0x85: (0, 0, 0, 0, False, 'ADD A,{r}l'), + 0x86: (1, 0, 1, 0, False, 'ADD A,({r}{d:+d})'), + + 0x8C: (0, 0, 0, 0, False, 'ADC A,{r}h'), + 0x8D: (0, 0, 0, 0, False, 'ADC A,{r}l'), + 0x8E: (1, 0, 1, 0, False, 'ADC A,({r}{d:+d})'), + + 0x94: (0, 0, 0, 0, False, 'SUB {r}h'), + 0x95: (0, 0, 0, 0, False, 'SUB {r}l'), + 0x96: (1, 0, 1, 0, False, 'SUB ({r}{d:+d})'), + + 0x9C: (0, 0, 0, 0, False, 'SBC A,{r}h'), + 0x9D: (0, 0, 0, 0, False, 'SBC A,{r}l'), + 0x9E: (1, 0, 1, 0, False, 'SBC A,({r}{d:+d})'), + + 0xA4: (0, 0, 0, 0, False, 'AND {r}h'), + 0xA5: (0, 0, 0, 0, False, 'AND {r}l'), + 0xA6: (1, 0, 1, 0, False, 'AND ({r}{d:+d})'), + + 0xAC: (0, 0, 0, 0, False, 'XOR {r}h'), + 0xAD: (0, 0, 0, 0, False, 'XOR {r}l'), + 0xAE: (1, 0, 1, 0, False, 'XOR ({r}{d:+d})'), + + 0xB4: (0, 0, 0, 0, False, 'OR {r}h'), + 0xB5: (0, 0, 0, 0, False, 'OR {r}l'), + 0xB6: (1, 0, 1, 0, False, 'OR ({r}{d:+d})'), + + 0xBC: (0, 0, 0, 0, False, 'CP {r}h'), + 0xBD: (0, 0, 0, 0, False, 'CP {r}l'), + 0xBE: (1, 0, 1, 0, False, 'CP ({r}{d:+d})'), + + 0xE1: (0, 0, 2, 0, False, 'POP {r}'), + + 0xE3: (0, 0, 2, 2, False, 'EX (SP),{r}'), + + 0xE5: (0, 0, 0,-2, False, 'PUSH {r}'), + + 0xE9: (0, 0, 0, 0, False, 'JP ({r})'), + + 0xF9: (0, 0, 0, 0, False, 'LD SP,{r}') +} + +# Instructions with DD CB or FD CB prefix. +# For these instructions, the displacement precedes the opcode byte. +# This is handled as a special case in the code, and thus the entries +# in this table specify 0 for the displacement length. +index_bit_instructions = { + 0x00: (0, 0, 1, 1, False, 'RLC ({r}{d:+d}),B'), + 0x01: (0, 0, 1, 1, False, 'RLC ({r}{d:+d}),C'), + 0x02: (0, 0, 1, 1, False, 'RLC ({r}{d:+d}),D'), + 0x03: (0, 0, 1, 1, False, 'RLC ({r}{d:+d}),E'), + 0x04: (0, 0, 1, 1, False, 'RLC ({r}{d:+d}),H'), + 0x05: (0, 0, 1, 1, False, 'RLC ({r}{d:+d}),L'), + 0x06: (0, 0, 1, 1, False, 'RLC ({r}{d:+d})'), + 0x07: (0, 0, 1, 1, False, 'RLC ({r}{d:+d}),A'), + 0x08: (0, 0, 1, 1, False, 'RRC ({r}{d:+d}),B'), + 0x09: (0, 0, 1, 1, False, 'RRC ({r}{d:+d}),C'), + 0x0A: (0, 0, 1, 1, False, 'RRC ({r}{d:+d}),D'), + 0x0B: (0, 0, 1, 1, False, 'RRC ({r}{d:+d}),E'), + 0x0C: (0, 0, 1, 1, False, 'RRC ({r}{d:+d}),H'), + 0x0D: (0, 0, 1, 1, False, 'RRC ({r}{d:+d}),L'), + 0x0E: (0, 0, 1, 1, False, 'RRC ({r}{d:+d})'), + 0x0F: (0, 0, 1, 1, False, 'RRC ({r}{d:+d}),A'), + + 0x10: (0, 0, 1, 1, False, 'RL ({r}{d:+d}),B'), + 0x11: (0, 0, 1, 1, False, 'RL ({r}{d:+d}),C'), + 0x12: (0, 0, 1, 1, False, 'RL ({r}{d:+d}),D'), + 0x13: (0, 0, 1, 1, False, 'RL ({r}{d:+d}),E'), + 0x14: (0, 0, 1, 1, False, 'RL ({r}{d:+d}),H'), + 0x15: (0, 0, 1, 1, False, 'RL ({r}{d:+d}),L'), + 0x16: (0, 0, 1, 1, False, 'RL ({r}{d:+d})'), + 0x17: (0, 0, 1, 1, False, 'RL ({r}{d:+d}),A'), + 0x18: (0, 0, 1, 1, False, 'RR ({r}{d:+d}),B'), + 0x19: (0, 0, 1, 1, False, 'RR ({r}{d:+d}),C'), + 0x1A: (0, 0, 1, 1, False, 'RR ({r}{d:+d}),D'), + 0x1B: (0, 0, 1, 1, False, 'RR ({r}{d:+d}),E'), + 0x1C: (0, 0, 1, 1, False, 'RR ({r}{d:+d}),H'), + 0x1D: (0, 0, 1, 1, False, 'RR ({r}{d:+d}),L'), + 0x1E: (0, 0, 1, 1, False, 'RR ({r}{d:+d})'), + 0x1F: (0, 0, 1, 1, False, 'RR ({r}{d:+d}),A'), + + 0x20: (0, 0, 1, 1, False, 'SLA ({r}{d:+d}),B'), + 0x21: (0, 0, 1, 1, False, 'SLA ({r}{d:+d}),C'), + 0x22: (0, 0, 1, 1, False, 'SLA ({r}{d:+d}),D'), + 0x23: (0, 0, 1, 1, False, 'SLA ({r}{d:+d}),E'), + 0x24: (0, 0, 1, 1, False, 'SLA ({r}{d:+d}),H'), + 0x25: (0, 0, 1, 1, False, 'SLA ({r}{d:+d}),L'), + 0x26: (0, 0, 1, 1, False, 'SLA ({r}{d:+d})'), + 0x27: (0, 0, 1, 1, False, 'SLA ({r}{d:+d}),A'), + 0x28: (0, 0, 1, 1, False, 'SRA ({r}{d:+d}),B'), + 0x29: (0, 0, 1, 1, False, 'SRA ({r}{d:+d}),C'), + 0x2A: (0, 0, 1, 1, False, 'SRA ({r}{d:+d}),D'), + 0x2B: (0, 0, 1, 1, False, 'SRA ({r}{d:+d}),E'), + 0x2C: (0, 0, 1, 1, False, 'SRA ({r}{d:+d}),H'), + 0x2D: (0, 0, 1, 1, False, 'SRA ({r}{d:+d}),L'), + 0x2E: (0, 0, 1, 1, False, 'SRA ({r}{d:+d})'), + 0x2F: (0, 0, 1, 1, False, 'SRA ({r}{d:+d}),A'), + + 0x30: (0, 0, 1, 1, False, 'SLL ({r}{d:+d}),B'), + 0x31: (0, 0, 1, 1, False, 'SLL ({r}{d:+d}),C'), + 0x32: (0, 0, 1, 1, False, 'SLL ({r}{d:+d}),D'), + 0x33: (0, 0, 1, 1, False, 'SLL ({r}{d:+d}),E'), + 0x34: (0, 0, 1, 1, False, 'SLL ({r}{d:+d}),H'), + 0x35: (0, 0, 1, 1, False, 'SLL ({r}{d:+d}),L'), + 0x36: (0, 0, 1, 1, False, 'SLL ({r}{d:+d})'), + 0x37: (0, 0, 1, 1, False, 'SLL ({r}{d:+d}),A'), + 0x38: (0, 0, 1, 1, False, 'SRL ({r}{d:+d}),B'), + 0x39: (0, 0, 1, 1, False, 'SRL ({r}{d:+d}),C'), + 0x3A: (0, 0, 1, 1, False, 'SRL ({r}{d:+d}),D'), + 0x3B: (0, 0, 1, 1, False, 'SRL ({r}{d:+d}),E'), + 0x3C: (0, 0, 1, 1, False, 'SRL ({r}{d:+d}),H'), + 0x3D: (0, 0, 1, 1, False, 'SRL ({r}{d:+d}),L'), + 0x3E: (0, 0, 1, 1, False, 'SRL ({r}{d:+d})'), + 0x3F: (0, 0, 1, 1, False, 'SRL ({r}{d:+d}),A'), + + 0x40: (0, 0, 1, 0, False, 'BIT 0,({r}{d:+d})'), + 0x41: (0, 0, 1, 0, False, 'BIT 0,({r}{d:+d})'), + 0x42: (0, 0, 1, 0, False, 'BIT 0,({r}{d:+d})'), + 0x43: (0, 0, 1, 0, False, 'BIT 0,({r}{d:+d})'), + 0x44: (0, 0, 1, 0, False, 'BIT 0,({r}{d:+d})'), + 0x45: (0, 0, 1, 0, False, 'BIT 0,({r}{d:+d})'), + 0x46: (0, 0, 1, 0, False, 'BIT 0,({r}{d:+d})'), + 0x47: (0, 0, 1, 0, False, 'BIT 0,({r}{d:+d})'), + 0x48: (0, 0, 1, 0, False, 'BIT 1,({r}{d:+d})'), + 0x49: (0, 0, 1, 0, False, 'BIT 1,({r}{d:+d})'), + 0x4A: (0, 0, 1, 0, False, 'BIT 1,({r}{d:+d})'), + 0x4B: (0, 0, 1, 0, False, 'BIT 1,({r}{d:+d})'), + 0x4C: (0, 0, 1, 0, False, 'BIT 1,({r}{d:+d})'), + 0x4D: (0, 0, 1, 0, False, 'BIT 1,({r}{d:+d})'), + 0x4E: (0, 0, 1, 0, False, 'BIT 1,({r}{d:+d})'), + 0x4F: (0, 0, 1, 0, False, 'BIT 1,({r}{d:+d})'), + + 0x50: (0, 0, 1, 0, False, 'BIT 2,({r}{d:+d})'), + 0x51: (0, 0, 1, 0, False, 'BIT 2,({r}{d:+d})'), + 0x52: (0, 0, 1, 0, False, 'BIT 2,({r}{d:+d})'), + 0x53: (0, 0, 1, 0, False, 'BIT 2,({r}{d:+d})'), + 0x54: (0, 0, 1, 0, False, 'BIT 2,({r}{d:+d})'), + 0x55: (0, 0, 1, 0, False, 'BIT 2,({r}{d:+d})'), + 0x56: (0, 0, 1, 0, False, 'BIT 2,({r}{d:+d})'), + 0x57: (0, 0, 1, 0, False, 'BIT 2,({r}{d:+d})'), + 0x58: (0, 0, 1, 0, False, 'BIT 3,({r}{d:+d})'), + 0x59: (0, 0, 1, 0, False, 'BIT 3,({r}{d:+d})'), + 0x5A: (0, 0, 1, 0, False, 'BIT 3,({r}{d:+d})'), + 0x5B: (0, 0, 1, 0, False, 'BIT 3,({r}{d:+d})'), + 0x5C: (0, 0, 1, 0, False, 'BIT 3,({r}{d:+d})'), + 0x5D: (0, 0, 1, 0, False, 'BIT 3,({r}{d:+d})'), + 0x5E: (0, 0, 1, 0, False, 'BIT 3,({r}{d:+d})'), + 0x5F: (0, 0, 1, 0, False, 'BIT 3,({r}{d:+d})'), + + 0x60: (0, 0, 1, 0, False, 'BIT 4,({r}{d:+d})'), + 0x61: (0, 0, 1, 0, False, 'BIT 4,({r}{d:+d})'), + 0x62: (0, 0, 1, 0, False, 'BIT 4,({r}{d:+d})'), + 0x63: (0, 0, 1, 0, False, 'BIT 4,({r}{d:+d})'), + 0x64: (0, 0, 1, 0, False, 'BIT 4,({r}{d:+d})'), + 0x65: (0, 0, 1, 0, False, 'BIT 4,({r}{d:+d})'), + 0x66: (0, 0, 1, 0, False, 'BIT 4,({r}{d:+d})'), + 0x67: (0, 0, 1, 0, False, 'BIT 4,({r}{d:+d})'), + 0x68: (0, 0, 1, 0, False, 'BIT 5,({r}{d:+d})'), + 0x69: (0, 0, 1, 0, False, 'BIT 5,({r}{d:+d})'), + 0x6A: (0, 0, 1, 0, False, 'BIT 5,({r}{d:+d})'), + 0x6B: (0, 0, 1, 0, False, 'BIT 5,({r}{d:+d})'), + 0x6C: (0, 0, 1, 0, False, 'BIT 5,({r}{d:+d})'), + 0x6D: (0, 0, 1, 0, False, 'BIT 5,({r}{d:+d})'), + 0x6E: (0, 0, 1, 0, False, 'BIT 5,({r}{d:+d})'), + 0x6F: (0, 0, 1, 0, False, 'BIT 5,({r}{d:+d})'), + + 0x70: (0, 0, 1, 0, False, 'BIT 6,({r}{d:+d})'), + 0x71: (0, 0, 1, 0, False, 'BIT 6,({r}{d:+d})'), + 0x72: (0, 0, 1, 0, False, 'BIT 6,({r}{d:+d})'), + 0x73: (0, 0, 1, 0, False, 'BIT 6,({r}{d:+d})'), + 0x74: (0, 0, 1, 0, False, 'BIT 6,({r}{d:+d})'), + 0x75: (0, 0, 1, 0, False, 'BIT 6,({r}{d:+d})'), + 0x76: (0, 0, 1, 0, False, 'BIT 6,({r}{d:+d})'), + 0x77: (0, 0, 1, 0, False, 'BIT 6,({r}{d:+d})'), + 0x78: (0, 0, 1, 0, False, 'BIT 7,({r}{d:+d})'), + 0x79: (0, 0, 1, 0, False, 'BIT 7,({r}{d:+d})'), + 0x7A: (0, 0, 1, 0, False, 'BIT 7,({r}{d:+d})'), + 0x7B: (0, 0, 1, 0, False, 'BIT 7,({r}{d:+d})'), + 0x7C: (0, 0, 1, 0, False, 'BIT 7,({r}{d:+d})'), + 0x7D: (0, 0, 1, 0, False, 'BIT 7,({r}{d:+d})'), + 0x7E: (0, 0, 1, 0, False, 'BIT 7,({r}{d:+d})'), + 0x7F: (0, 0, 1, 0, False, 'BIT 7,({r}{d:+d})'), + + 0x80: (0, 0, 1, 1, False, 'RES 0,({r}{d:+d}),B'), + 0x81: (0, 0, 1, 1, False, 'RES 0,({r}{d:+d}),C'), + 0x82: (0, 0, 1, 1, False, 'RES 0,({r}{d:+d}),D'), + 0x83: (0, 0, 1, 1, False, 'RES 0,({r}{d:+d}),E'), + 0x84: (0, 0, 1, 1, False, 'RES 0,({r}{d:+d}),H'), + 0x85: (0, 0, 1, 1, False, 'RES 0,({r}{d:+d}),L'), + 0x86: (0, 0, 1, 1, False, 'RES 0,({r}{d:+d})'), + 0x87: (0, 0, 1, 1, False, 'RES 0,({r}{d:+d}),A'), + 0x88: (0, 0, 1, 1, False, 'RES 1,({r}{d:+d}),B'), + 0x89: (0, 0, 1, 1, False, 'RES 1,({r}{d:+d}),C'), + 0x8A: (0, 0, 1, 1, False, 'RES 1,({r}{d:+d}),D'), + 0x8B: (0, 0, 1, 1, False, 'RES 1,({r}{d:+d}),E'), + 0x8C: (0, 0, 1, 1, False, 'RES 1,({r}{d:+d}),H'), + 0x8D: (0, 0, 1, 1, False, 'RES 1,({r}{d:+d}),L'), + 0x8E: (0, 0, 1, 1, False, 'RES 1,({r}{d:+d})'), + 0x8F: (0, 0, 1, 1, False, 'RES 1,({r}{d:+d}),A'), + + 0x90: (0, 0, 1, 1, False, 'RES 2,({r}{d:+d}),B'), + 0x91: (0, 0, 1, 1, False, 'RES 2,({r}{d:+d}),C'), + 0x92: (0, 0, 1, 1, False, 'RES 2,({r}{d:+d}),D'), + 0x93: (0, 0, 1, 1, False, 'RES 2,({r}{d:+d}),E'), + 0x94: (0, 0, 1, 1, False, 'RES 2,({r}{d:+d}),H'), + 0x95: (0, 0, 1, 1, False, 'RES 2,({r}{d:+d}),L'), + 0x96: (0, 0, 1, 1, False, 'RES 2,({r}{d:+d})'), + 0x97: (0, 0, 1, 1, False, 'RES 2,({r}{d:+d}),A'), + 0x98: (0, 0, 1, 1, False, 'RES 3,({r}{d:+d}),B'), + 0x99: (0, 0, 1, 1, False, 'RES 3,({r}{d:+d}),C'), + 0x9A: (0, 0, 1, 1, False, 'RES 3,({r}{d:+d}),D'), + 0x9B: (0, 0, 1, 1, False, 'RES 3,({r}{d:+d}),E'), + 0x9C: (0, 0, 1, 1, False, 'RES 3,({r}{d:+d}),H'), + 0x9D: (0, 0, 1, 1, False, 'RES 3,({r}{d:+d}),L'), + 0x9E: (0, 0, 1, 1, False, 'RES 3,({r}{d:+d})'), + 0x9F: (0, 0, 1, 1, False, 'RES 3,({r}{d:+d}),A'), + + 0xA0: (0, 0, 1, 1, False, 'RES 4,({r}{d:+d}),B'), + 0xA1: (0, 0, 1, 1, False, 'RES 4,({r}{d:+d}),C'), + 0xA2: (0, 0, 1, 1, False, 'RES 4,({r}{d:+d}),D'), + 0xA3: (0, 0, 1, 1, False, 'RES 4,({r}{d:+d}),E'), + 0xA4: (0, 0, 1, 1, False, 'RES 4,({r}{d:+d}),H'), + 0xA5: (0, 0, 1, 1, False, 'RES 4,({r}{d:+d}),L'), + 0xA6: (0, 0, 1, 1, False, 'RES 4,({r}{d:+d})'), + 0xA7: (0, 0, 1, 1, False, 'RES 4,({r}{d:+d}),A'), + 0xA8: (0, 0, 1, 1, False, 'RES 5,({r}{d:+d}),B'), + 0xA9: (0, 0, 1, 1, False, 'RES 5,({r}{d:+d}),C'), + 0xAA: (0, 0, 1, 1, False, 'RES 5,({r}{d:+d}),D'), + 0xAB: (0, 0, 1, 1, False, 'RES 5,({r}{d:+d}),E'), + 0xAC: (0, 0, 1, 1, False, 'RES 5,({r}{d:+d}),H'), + 0xAD: (0, 0, 1, 1, False, 'RES 5,({r}{d:+d}),L'), + 0xAE: (0, 0, 1, 1, False, 'RES 5,({r}{d:+d})'), + 0xAF: (0, 0, 1, 1, False, 'RES 5,({r}{d:+d}),A'), + + 0xB0: (0, 0, 1, 1, False, 'RES 6,({r}{d:+d}),B'), + 0xB1: (0, 0, 1, 1, False, 'RES 6,({r}{d:+d}),C'), + 0xB2: (0, 0, 1, 1, False, 'RES 6,({r}{d:+d}),D'), + 0xB3: (0, 0, 1, 1, False, 'RES 6,({r}{d:+d}),E'), + 0xB4: (0, 0, 1, 1, False, 'RES 6,({r}{d:+d}),H'), + 0xB5: (0, 0, 1, 1, False, 'RES 6,({r}{d:+d}),L'), + 0xB6: (0, 0, 1, 1, False, 'RES 6,({r}{d:+d})'), + 0xB7: (0, 0, 1, 1, False, 'RES 6,({r}{d:+d}),A'), + 0xB8: (0, 0, 1, 1, False, 'RES 7,({r}{d:+d}),B'), + 0xB9: (0, 0, 1, 1, False, 'RES 7,({r}{d:+d}),C'), + 0xBA: (0, 0, 1, 1, False, 'RES 7,({r}{d:+d}),D'), + 0xBB: (0, 0, 1, 1, False, 'RES 7,({r}{d:+d}),E'), + 0xBC: (0, 0, 1, 1, False, 'RES 7,({r}{d:+d}),H'), + 0xBD: (0, 0, 1, 1, False, 'RES 7,({r}{d:+d}),L'), + 0xBE: (0, 0, 1, 1, False, 'RES 7,({r}{d:+d})'), + 0xBF: (0, 0, 1, 1, False, 'RES 7,({r}{d:+d}),A'), + + 0xC0: (0, 0, 1, 1, False, 'SET 0,({r}{d:+d}),B'), + 0xC1: (0, 0, 1, 1, False, 'SET 0,({r}{d:+d}),C'), + 0xC2: (0, 0, 1, 1, False, 'SET 0,({r}{d:+d}),D'), + 0xC3: (0, 0, 1, 1, False, 'SET 0,({r}{d:+d}),E'), + 0xC4: (0, 0, 1, 1, False, 'SET 0,({r}{d:+d}),H'), + 0xC5: (0, 0, 1, 1, False, 'SET 0,({r}{d:+d}),L'), + 0xC6: (0, 0, 1, 1, False, 'SET 0,({r}{d:+d})'), + 0xC7: (0, 0, 1, 1, False, 'SET 0,({r}{d:+d}),A'), + 0xC8: (0, 0, 1, 1, False, 'SET 1,({r}{d:+d}),B'), + 0xC9: (0, 0, 1, 1, False, 'SET 1,({r}{d:+d}),C'), + 0xCA: (0, 0, 1, 1, False, 'SET 1,({r}{d:+d}),D'), + 0xCB: (0, 0, 1, 1, False, 'SET 1,({r}{d:+d}),E'), + 0xCC: (0, 0, 1, 1, False, 'SET 1,({r}{d:+d}),H'), + 0xCD: (0, 0, 1, 1, False, 'SET 1,({r}{d:+d}),L'), + 0xCE: (0, 0, 1, 1, False, 'SET 1,({r}{d:+d})'), + 0xCF: (0, 0, 1, 1, False, 'SET 1,({r}{d:+d}),A'), + + 0xD0: (0, 0, 1, 1, False, 'SET 2,({r}{d:+d}),B'), + 0xD1: (0, 0, 1, 1, False, 'SET 2,({r}{d:+d}),C'), + 0xD2: (0, 0, 1, 1, False, 'SET 2,({r}{d:+d}),D'), + 0xD3: (0, 0, 1, 1, False, 'SET 2,({r}{d:+d}),E'), + 0xD4: (0, 0, 1, 1, False, 'SET 2,({r}{d:+d}),H'), + 0xD5: (0, 0, 1, 1, False, 'SET 2,({r}{d:+d}),L'), + 0xD6: (0, 0, 1, 1, False, 'SET 2,({r}{d:+d})'), + 0xD7: (0, 0, 1, 1, False, 'SET 2,({r}{d:+d}),A'), + 0xD8: (0, 0, 1, 1, False, 'SET 3,({r}{d:+d}),B'), + 0xD9: (0, 0, 1, 1, False, 'SET 3,({r}{d:+d}),C'), + 0xDA: (0, 0, 1, 1, False, 'SET 3,({r}{d:+d}),D'), + 0xDB: (0, 0, 1, 1, False, 'SET 3,({r}{d:+d}),E'), + 0xDC: (0, 0, 1, 1, False, 'SET 3,({r}{d:+d}),H'), + 0xDD: (0, 0, 1, 1, False, 'SET 3,({r}{d:+d}),L'), + 0xDE: (0, 0, 1, 1, False, 'SET 3,({r}{d:+d})'), + 0xDF: (0, 0, 1, 1, False, 'SET 3,({r}{d:+d}),A'), + + 0xE0: (0, 0, 1, 1, False, 'SET 4,({r}{d:+d}),B'), + 0xE1: (0, 0, 1, 1, False, 'SET 4,({r}{d:+d}),C'), + 0xE2: (0, 0, 1, 1, False, 'SET 4,({r}{d:+d}),D'), + 0xE3: (0, 0, 1, 1, False, 'SET 4,({r}{d:+d}),E'), + 0xE4: (0, 0, 1, 1, False, 'SET 4,({r}{d:+d}),H'), + 0xE5: (0, 0, 1, 1, False, 'SET 4,({r}{d:+d}),L'), + 0xE6: (0, 0, 1, 1, False, 'SET 4,({r}{d:+d})'), + 0xE7: (0, 0, 1, 1, False, 'SET 4,({r}{d:+d}),A'), + 0xE8: (0, 0, 1, 1, False, 'SET 5,({r}{d:+d}),B'), + 0xE9: (0, 0, 1, 1, False, 'SET 5,({r}{d:+d}),C'), + 0xEA: (0, 0, 1, 1, False, 'SET 5,({r}{d:+d}),D'), + 0xEB: (0, 0, 1, 1, False, 'SET 5,({r}{d:+d}),E'), + 0xEC: (0, 0, 1, 1, False, 'SET 5,({r}{d:+d}),H'), + 0xED: (0, 0, 1, 1, False, 'SET 5,({r}{d:+d}),L'), + 0xEE: (0, 0, 1, 1, False, 'SET 5,({r}{d:+d})'), + 0xEF: (0, 0, 1, 1, False, 'SET 5,({r}{d:+d}),A'), + + 0xF0: (0, 0, 1, 1, False, 'SET 6,({r}{d:+d}),B'), + 0xF1: (0, 0, 1, 1, False, 'SET 6,({r}{d:+d}),C'), + 0xF2: (0, 0, 1, 1, False, 'SET 6,({r}{d:+d}),D'), + 0xF3: (0, 0, 1, 1, False, 'SET 6,({r}{d:+d}),E'), + 0xF4: (0, 0, 1, 1, False, 'SET 6,({r}{d:+d}),H'), + 0xF5: (0, 0, 1, 1, False, 'SET 6,({r}{d:+d}),L'), + 0xF6: (0, 0, 1, 1, False, 'SET 6,({r}{d:+d})'), + 0xF7: (0, 0, 1, 1, False, 'SET 6,({r}{d:+d}),A'), + 0xF8: (0, 0, 1, 1, False, 'SET 7,({r}{d:+d}),B'), + 0xF9: (0, 0, 1, 1, False, 'SET 7,({r}{d:+d}),C'), + 0xFA: (0, 0, 1, 1, False, 'SET 7,({r}{d:+d}),D'), + 0xFB: (0, 0, 1, 1, False, 'SET 7,({r}{d:+d}),E'), + 0xFC: (0, 0, 1, 1, False, 'SET 7,({r}{d:+d}),H'), + 0xFD: (0, 0, 1, 1, False, 'SET 7,({r}{d:+d}),L'), + 0xFE: (0, 0, 1, 1, False, 'SET 7,({r}{d:+d})'), + 0xFF: (0, 0, 1, 1, False, 'SET 7,({r}{d:+d}),A') +} + +instr_table_by_prefix = { + 0: (main_instructions, ''), + 0xED: (extended_instructions, ''), + 0xCB: (bit_instructions, ''), + 0xDD: (index_instructions, 'IX'), + 0xFD: (index_instructions, 'IY'), + 0xDDCB: (index_bit_instructions, 'IX'), + 0xFDCB: (index_bit_instructions, 'IY') +}