diff --git a/.gitignore b/.gitignore index 2b0f916e..c889fc34 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,7 @@ DSView/ui_*.h DSView/DSView DSView/install_manifest.txt DSView/qrc_DSView.cpp +DSView/qrc_style.cpp moc_*.cpp moc_*.cpp_parameters diff --git a/DSView/CMakeLists.txt b/DSView/CMakeLists.txt index bc91cc8d..a52c36c8 100644 --- a/DSView/CMakeLists.txt +++ b/DSView/CMakeLists.txt @@ -34,7 +34,7 @@ project(DSView) option(DISABLE_WERROR "Build without -Werror" TRUE) option(ENABLE_SIGNALS "Build with UNIX signals" TRUE) -option(ENABLE_DECODE "Build with libsigrokdecode" TRUE) +option(ENABLE_DECODE "Build with libsigrokdecode4DSL" TRUE) option(ENABLE_COTIRE "Enable cotire" FALSE) option(ENABLE_TESTS "Enable unit tests" FALSE) option(STATIC_PKGDEPS_LIBS "Statically link to (pkg-config) libraries" FALSE) @@ -62,9 +62,10 @@ endif() list(APPEND PKGDEPS "libsigrok4DSL >= 0.2.0" "libusb-1.0 >= 1.0.16" + "libzip >= 0.10" ) if(ENABLE_DECODE) - list(APPEND PKGDEPS "libsigrokdecode>=0.3.0") + list(APPEND PKGDEPS "libsigrokdecode4DSL>=0.4.0") endif() find_package(PkgConfig) @@ -93,6 +94,7 @@ find_package(Threads) find_package(Boost 1.42 COMPONENTS filesystem system thread REQUIRED) find_package(libusb-1.0 REQUIRED) +find_package(libzip REQUIRED) find_package(FFTW REQUIRED) #=============================================================================== @@ -104,7 +106,7 @@ set(DS_DESCRIPTION "A GUI for instruments of DreamSourceLab") set(DS_VERSION_MAJOR 0) set(DS_VERSION_MINOR 9) -set(DS_VERSION_MICRO 6) +set(DS_VERSION_MICRO 7) set(DS_VERSION_STRING ${DS_VERSION_MAJOR}.${DS_VERSION_MINOR}.${DS_VERSION_MICRO} ) @@ -146,7 +148,7 @@ set(DSView_SOURCES pv/view/header.cpp pv/view/cursor.cpp pv/view/analogsignal.cpp - pv/prop/binding/binding_deviceoptions.cpp + pv/prop/binding/deviceoptions.cpp pv/toolbars/trigbar.cpp pv/toolbars/filebar.cpp pv/dock/protocoldock.cpp @@ -202,6 +204,7 @@ set(DSView_SOURCES pv/dialogs/dsmessagebox.cpp pv/dialogs/shadow.cpp pv/dialogs/dsdialog.cpp + pv/dialogs/interval.cpp ) set(DSView_HEADERS @@ -257,17 +260,17 @@ set(DSView_HEADERS pv/dialogs/dsmessagebox.h pv/dialogs/shadow.h pv/dialogs/dsdialog.h + pv/dialogs/interval.h ) set(DSView_FORMS ) set(DSView_RESOURCES - DSView.qrc - darkstyle/style.qrc + DSView.qrc + darkstyle/style.qrc ) - if(ENABLE_DECODE) list(APPEND DSView_SOURCES pv/dock/protocoldock.cpp @@ -396,9 +399,7 @@ set_target_properties(${PROJECT_NAME} PROPERTIES INSTALL_RPATH "/usr/local/lib") # Install the executable. install(TARGETS ${PROJECT_NAME} DESTINATION bin/) install(DIRECTORY res DESTINATION share/${PROJECT_NAME}) -install(DIRECTORY ../libsigrokdecode4DSL/decoders DESTINATION share/${PROJECT_NAME}) install(FILES icons/logo.png DESTINATION share/${PROJECT_NAME} RENAME logo.png) -install(FILES DreamSourceLab.rules DESTINATION /usr/lib/udev/rules.d/) install(FILES DreamSourceLab.rules DESTINATION /etc/udev/rules.d/) install(FILES DSView.desktop DESTINATION /usr/share/applications/) diff --git a/DSView/DSView.desktop b/DSView/DSView.desktop old mode 100755 new mode 100644 diff --git a/DSView/DSView.qrc b/DSView/DSView.qrc index f58808ff..f560529f 100644 --- a/DSView/DSView.qrc +++ b/DSView/DSView.qrc @@ -10,8 +10,6 @@ stylesheet.qss icons/down-arrow.png icons/slider-handle.png - icons/add.png - icons/del.png icons/trigger.png icons/measure.png icons/search-bar.png @@ -55,5 +53,16 @@ icons/maximize.png icons/minimize.png icons/restore.png + icons/nav.png + icons/oneloop.png + icons/repeat.png + icons/moder.png + icons/moder_dis.png + icons/modes.png + icons/modes_dis.png + icons/add.png + icons/del.png + icons/add_dis.png + icons/del_dis.png diff --git a/DSView/darkstyle/style.qss b/DSView/darkstyle/style.qss index 21455512..f23c1ea1 100755 --- a/DSView/darkstyle/style.qss +++ b/DSView/darkstyle/style.qss @@ -65,7 +65,7 @@ QWidget:item:selected QCheckBox { - spacing: 5px; + spacing: 0px; outline: none; color: #bbb; margin-bottom: 2px; @@ -635,7 +635,7 @@ QComboBox::drop-down { subcontrol-origin: padding; subcontrol-position: top right; - width: 15px; + width: 10px; border-left-width: 0px; border-left-color: darkgray; diff --git a/DSView/dsapplication.cpp b/DSView/dsapplication.cpp index 9facc855..98cb6897 100644 --- a/DSView/dsapplication.cpp +++ b/DSView/dsapplication.cpp @@ -34,15 +34,15 @@ bool DSApplication::notify(QObject *receiver_, QEvent *event_) return QApplication::notify(receiver_, event_); } catch ( std::exception& e ) { QMessageBox msg(NULL); - msg.setText("Application Error"); + msg.setText(tr("Application Error")); msg.setInformativeText(e.what()); msg.setStandardButtons(QMessageBox::Ok); msg.setIcon(QMessageBox::Warning); msg.exec(); } catch (...) { QMessageBox msg(NULL); - msg.setText("Application Error"); - msg.setInformativeText("An unexpected error occurred"); + msg.setText(tr("Application Error")); + msg.setInformativeText(tr("An unexpected error occurred")); msg.setStandardButtons(QMessageBox::Ok); msg.setIcon(QMessageBox::Warning); msg.exec(); diff --git a/DSView/icons/add.png b/DSView/icons/add.png old mode 100644 new mode 100755 index efe2e387..24c81886 Binary files a/DSView/icons/add.png and b/DSView/icons/add.png differ diff --git a/DSView/icons/add_dis.png b/DSView/icons/add_dis.png new file mode 100755 index 00000000..b0349001 Binary files /dev/null and b/DSView/icons/add_dis.png differ diff --git a/DSView/icons/arrow-loop.png b/DSView/icons/arrow-loop.png new file mode 100755 index 00000000..d3df3243 Binary files /dev/null and b/DSView/icons/arrow-loop.png differ diff --git a/DSView/icons/del.png b/DSView/icons/del.png old mode 100644 new mode 100755 index ff04e887..527534b4 Binary files a/DSView/icons/del.png and b/DSView/icons/del.png differ diff --git a/DSView/icons/del_dis.png b/DSView/icons/del_dis.png new file mode 100755 index 00000000..d4f418c3 Binary files /dev/null and b/DSView/icons/del_dis.png differ diff --git a/DSView/icons/logo.svg b/DSView/icons/logo.svg new file mode 100755 index 00000000..b713c304 --- /dev/null +++ b/DSView/icons/logo.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/DSView/icons/logo_128.png b/DSView/icons/logo_128.png new file mode 100755 index 00000000..0d46a075 Binary files /dev/null and b/DSView/icons/logo_128.png differ diff --git a/DSView/icons/logo_16.png b/DSView/icons/logo_16.png new file mode 100755 index 00000000..67042eb3 Binary files /dev/null and b/DSView/icons/logo_16.png differ diff --git a/DSView/icons/logo_256.png b/DSView/icons/logo_256.png new file mode 100755 index 00000000..ca65932d Binary files /dev/null and b/DSView/icons/logo_256.png differ diff --git a/DSView/icons/logo_32.png b/DSView/icons/logo_32.png new file mode 100755 index 00000000..ed7b1a4e Binary files /dev/null and b/DSView/icons/logo_32.png differ diff --git a/DSView/icons/logo_48.png b/DSView/icons/logo_48.png new file mode 100755 index 00000000..eb8b4162 Binary files /dev/null and b/DSView/icons/logo_48.png differ diff --git a/DSView/icons/logo_64.png b/DSView/icons/logo_64.png new file mode 100755 index 00000000..8691e890 Binary files /dev/null and b/DSView/icons/logo_64.png differ diff --git a/DSView/icons/moder.png b/DSView/icons/moder.png new file mode 100755 index 00000000..d94f826a Binary files /dev/null and b/DSView/icons/moder.png differ diff --git a/DSView/icons/moder_dis.png b/DSView/icons/moder_dis.png new file mode 100755 index 00000000..8bc44721 Binary files /dev/null and b/DSView/icons/moder_dis.png differ diff --git a/DSView/icons/modes.png b/DSView/icons/modes.png new file mode 100755 index 00000000..c8e465ce Binary files /dev/null and b/DSView/icons/modes.png differ diff --git a/DSView/icons/modes_dis.png b/DSView/icons/modes_dis.png new file mode 100755 index 00000000..375a2a50 Binary files /dev/null and b/DSView/icons/modes_dis.png differ diff --git a/DSView/icons/nav.png b/DSView/icons/nav.png new file mode 100755 index 00000000..03f1f605 Binary files /dev/null and b/DSView/icons/nav.png differ diff --git a/DSView/icons/oneloop.png b/DSView/icons/oneloop.png new file mode 100755 index 00000000..9a03ebb3 Binary files /dev/null and b/DSView/icons/oneloop.png differ diff --git a/DSView/icons/repeat.png b/DSView/icons/repeat.png new file mode 100755 index 00000000..d68d4edb Binary files /dev/null and b/DSView/icons/repeat.png differ diff --git a/DSView/main.cpp b/DSView/main.cpp index d63b2e7f..ba9f38d0 100644 --- a/DSView/main.cpp +++ b/DSView/main.cpp @@ -22,7 +22,7 @@ #ifdef ENABLE_DECODE -#include /* First, so we avoid a _POSIX_C_SOURCE warning. */ +#include /* First, so we avoid a _POSIX_C_SOURCE warning. */ #endif #include @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include "dsapplication.h" #include "pv/devicemanager.h" @@ -143,9 +143,10 @@ int main(int argc, char *argv[]) a.setStyleSheet(qss.readAll()); qss.close(); w.show(); + w.readSettings(); // Run the application - ret = a.exec(); + ret = a.exec(); } catch(std::exception e) { qDebug() << e.what(); diff --git a/DSView/pv/data/analogsnapshot.cpp b/DSView/pv/data/analogsnapshot.cpp index 005885c7..cfc22080 100644 --- a/DSView/pv/data/analogsnapshot.cpp +++ b/DSView/pv/data/analogsnapshot.cpp @@ -91,14 +91,20 @@ void AnalogSnapshot::clear() init(); } -void AnalogSnapshot::first_payload(const sr_datafeed_analog &analog, uint64_t total_sample_count, unsigned int channel_num) +void AnalogSnapshot::first_payload(const sr_datafeed_analog &analog, uint64_t total_sample_count, GSList *channels) { _total_sample_count = total_sample_count; - _channel_num = channel_num; - _unit_size = sizeof(uint16_t)*channel_num; + _channel_num = 0; + for (const GSList *l = channels; l; l = l->next) { + sr_channel *const probe = (sr_channel*)l->data; + assert(probe); + if (probe->type == SR_CHANNEL_ANALOG && probe->enabled) { + _channel_num ++; + } + } bool isOk = true; - uint64_t size = _total_sample_count * _unit_size + sizeof(uint64_t); + uint64_t size = _total_sample_count * _channel_num * BytesPerSample + sizeof(uint64_t); if (size != _capacity) { free_data(); _data = malloc(size); @@ -125,6 +131,13 @@ void AnalogSnapshot::first_payload(const sr_datafeed_analog &analog, uint64_t to } if (isOk) { + for (const GSList *l = channels; l; l = l->next) { + sr_channel *const probe = (sr_channel*)l->data; + assert(probe); + if (probe->type == SR_CHANNEL_ANALOG && probe->enabled) { + _ch_index.push_back(probe->index); + } + } _capacity = size; _memory_failed = false; append_payload(analog); @@ -132,7 +145,6 @@ void AnalogSnapshot::first_payload(const sr_datafeed_analog &analog, uint64_t to } else { free_data(); free_envelop(); - _capacity = 0; _memory_failed = true; } } @@ -147,6 +159,27 @@ void AnalogSnapshot::append_payload( append_payload_to_envelope_levels(); } +void AnalogSnapshot::append_data(void *data, uint64_t samples) +{ + int unit_bytes = BytesPerSample * _channel_num; + if (_sample_count + samples < _total_sample_count) + _sample_count += samples; + else + _sample_count = _total_sample_count; + + if (_ring_sample_count + samples > _total_sample_count) { + memcpy((uint8_t*)_data + _ring_sample_count * unit_bytes, + data, (_total_sample_count - _ring_sample_count) * unit_bytes); + _ring_sample_count = (samples + _ring_sample_count - _total_sample_count) % _total_sample_count; + memcpy((uint8_t*)_data, + data, _ring_sample_count * unit_bytes); + } else { + memcpy((uint8_t*)_data + _ring_sample_count * unit_bytes, + data, samples * unit_bytes); + _ring_sample_count += samples; + } +} + const uint16_t* AnalogSnapshot::get_samples( int64_t start_sample, int64_t end_sample) const { @@ -303,5 +336,20 @@ void AnalogSnapshot::append_payload_to_envelope_levels() } } +int AnalogSnapshot::get_ch_order(int sig_index) +{ + uint16_t order = 0; + for (auto& iter:_ch_index) { + if (iter == sig_index) + break; + order++; + } + + if (order >= _ch_index.size()) + return -1; + else + return order; +} + } // namespace data } // namespace pv diff --git a/DSView/pv/data/analogsnapshot.h b/DSView/pv/data/analogsnapshot.h index 3f2b015a..8767f6c3 100644 --- a/DSView/pv/data/analogsnapshot.h +++ b/DSView/pv/data/analogsnapshot.h @@ -68,6 +68,8 @@ private: static const float LogEnvelopeScaleFactor; static const uint64_t EnvelopeDataUnit; + static const int BytesPerSample = 2; + public: AnalogSnapshot(); @@ -76,7 +78,8 @@ public: void clear(); void init(); - void first_payload(const sr_datafeed_analog &analog, uint64_t total_sample_count, unsigned int channel_num); + void first_payload(const sr_datafeed_analog &analog, + uint64_t total_sample_count, GSList *channels); void append_payload(const sr_datafeed_analog &analog); @@ -86,11 +89,16 @@ public: void get_envelope_section(EnvelopeSection &s, uint64_t start, uint64_t end, float min_length, int probe_index) const; + int get_ch_order(int sig_index); + private: + void append_data(void *data, uint64_t samples); void free_envelop(); void reallocate_envelope(Envelope &l); void append_payload_to_envelope_levels(); + + private: struct Envelope _envelope_levels[2*DS_MAX_ANALOG_PROBES_NUM][ScaleStepCount]; diff --git a/DSView/pv/data/decode/annotation.cpp b/DSView/pv/data/decode/annotation.cpp index f2d30df5..3581817d 100644 --- a/DSView/pv/data/decode/annotation.cpp +++ b/DSView/pv/data/decode/annotation.cpp @@ -20,7 +20,7 @@ */ extern "C" { -#include +#include } #include diff --git a/DSView/pv/data/decode/decoder.cpp b/DSView/pv/data/decode/decoder.cpp index 8d54d7f6..1c8d2a9d 100644 --- a/DSView/pv/data/decode/decoder.cpp +++ b/DSView/pv/data/decode/decoder.cpp @@ -20,12 +20,10 @@ */ #include -#include +#include #include "decoder.h" -#include - using boost::shared_ptr; using std::set; using std::map; @@ -44,10 +42,6 @@ Decoder::Decoder(const srd_decoder *const dec) : Decoder::~Decoder() { - for (map::const_iterator i = _options.begin(); - i != _options.end(); i++) - g_variant_unref((*i).second); - for (map::const_iterator i = _options_back.begin(); i != _options_back.end(); i++) g_variant_unref((*i).second); @@ -68,14 +62,13 @@ void Decoder::show(bool show) _shown = show; } -const map >& +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; @@ -89,6 +82,7 @@ const std::map& Decoder::options() const void Decoder::set_option(const char *id, GVariant *value) { assert(value); + g_variant_unref(_options_back[id]); g_variant_ref(value); _options_back[id] = value; _setted = true; @@ -139,24 +133,8 @@ bool Decoder::have_required_probes() const return true; } -set< shared_ptr > Decoder::get_data() +srd_decoder_inst* Decoder::create_decoder_inst(srd_session *session) const { - set< shared_ptr > data; - for(map >:: - const_iterator i = _probes.begin(); - i != _probes.end(); i++) - { - shared_ptr signal((*i).second); - assert(signal); - data.insert(signal->logic_data()); - } - - return data; -} - -srd_decoder_inst* Decoder::create_decoder_inst(srd_session *session, int unit_size) const -{ - (void)unit_size; GHashTable *const opt_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_variant_unref); @@ -180,13 +158,11 @@ srd_decoder_inst* Decoder::create_decoder_inst(srd_session *session, int unit_si GHashTable *const probes = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_variant_unref); - for(map >:: + for(map:: const_iterator i = _probes.begin(); i != _probes.end(); i++) { - shared_ptr signal((*i).second); - GVariant *const gvar = g_variant_new_int32( - signal->probe()->index); + GVariant *const gvar = g_variant_new_int32((*i).second); g_variant_ref_sink(gvar); g_hash_table_insert(probes, (*i).first->id, gvar); } @@ -196,6 +172,11 @@ srd_decoder_inst* Decoder::create_decoder_inst(srd_session *session, int unit_si return decoder_inst; } +int Decoder::get_channel_type(const srd_channel *ch) +{ + return ch->type; +} + } // decode } // data } // pv diff --git a/DSView/pv/data/decode/decoder.h b/DSView/pv/data/decode/decoder.h index 40fde4e6..4f9d40ad 100644 --- a/DSView/pv/data/decode/decoder.h +++ b/DSView/pv/data/decode/decoder.h @@ -35,15 +35,7 @@ struct srd_channel; struct srd_session; namespace pv { - -namespace view { -class LogicSignal; -} - namespace data { - -class Logic; - namespace decode { class Decoder @@ -58,10 +50,8 @@ public: bool shown() const; void show(bool show = true); - const std::map >& channels() const; - void set_probes(std::map > probes); + const std::map& channels() const; + void set_probes(std::map probes); const std::map& options() const; @@ -69,10 +59,7 @@ public: bool have_required_probes() const; - srd_decoder_inst* create_decoder_inst( - srd_session *session, int unit_size) const; - - std::set< boost::shared_ptr > get_data(); + srd_decoder_inst* create_decoder_inst(srd_session *session) const; void set_decode_region(uint64_t start, uint64_t end); uint64_t decode_start() const; @@ -80,17 +67,17 @@ public: bool commit(); + int get_channel_type(const srd_channel* ch); + private: const srd_decoder *const _decoder; bool _shown; - std::map > - _probes; + std::map _probes; std::map _options; - std::map > - _probes_back; + std::map _probes_back; std::map _options_back; uint64_t _decode_start, _decode_end; diff --git a/DSView/pv/data/decode/row.cpp b/DSView/pv/data/decode/row.cpp index 46fb337f..fd798eb7 100644 --- a/DSView/pv/data/decode/row.cpp +++ b/DSView/pv/data/decode/row.cpp @@ -20,7 +20,7 @@ #include "row.h" -#include +#include namespace pv { namespace data { diff --git a/DSView/pv/data/decode/rowdata.cpp b/DSView/pv/data/decode/rowdata.cpp index 8d3e41e0..c80cbfbd 100644 --- a/DSView/pv/data/decode/rowdata.cpp +++ b/DSView/pv/data/decode/rowdata.cpp @@ -38,6 +38,11 @@ RowData::RowData() : } RowData::~RowData() +{ + clear(); +} + +void RowData::clear() { _annotations.clear(); } @@ -56,7 +61,10 @@ uint64_t RowData::get_max_annotation() const uint64_t RowData::get_min_annotation() const { - return _min_annotation; + if (_min_annotation == UINT64_MAX) + return 10; + else + return _min_annotation; } void RowData::get_annotation_subset( @@ -70,6 +78,18 @@ void RowData::get_annotation_subset( dest.push_back(*i); } +uint64_t RowData::get_annotation_index(uint64_t start_sample) const +{ + uint64_t index = 0; + for (vector::const_iterator i = _annotations.begin(); + i != _annotations.end(); i++) { + if ((*i).start_sample() > start_sample) + break; + index++; + } + return index; +} + bool RowData::push_annotation(const Annotation &a) { try { diff --git a/DSView/pv/data/decode/rowdata.h b/DSView/pv/data/decode/rowdata.h index 40792cb7..72d33456 100644 --- a/DSView/pv/data/decode/rowdata.h +++ b/DSView/pv/data/decode/rowdata.h @@ -47,6 +47,8 @@ public: std::vector &dest, uint64_t start_sample, uint64_t end_sample) const; + uint64_t get_annotation_index(uint64_t start_sample) const; + bool push_annotation(const Annotation &a); uint64_t get_annotation_size() const; @@ -54,6 +56,8 @@ public: bool get_annotation(pv::data::decode::Annotation &ann, uint64_t index) const; + void clear(); + private: uint64_t _max_annotation; uint64_t _min_annotation; diff --git a/DSView/pv/data/decodermodel.cpp b/DSView/pv/data/decodermodel.cpp index 078111a4..614f67ff 100644 --- a/DSView/pv/data/decodermodel.cpp +++ b/DSView/pv/data/decodermodel.cpp @@ -18,7 +18,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include +#include #include #include diff --git a/DSView/pv/data/decoderstack.cpp b/DSView/pv/data/decoderstack.cpp index 233dcc4d..2ad6a532 100644 --- a/DSView/pv/data/decoderstack.cpp +++ b/DSView/pv/data/decoderstack.cpp @@ -35,19 +35,8 @@ #include #include -using boost::lock_guard; -using boost::mutex; -using boost::optional; -using boost::shared_ptr; -using boost::unique_lock; -using std::deque; -using std::make_pair; -using std::max; -using std::min; -using std::list; -using std::map; -using std::pair; -using std::vector; +using namespace boost; +using namespace std; using namespace pv::data::decode; @@ -70,7 +59,8 @@ DecoderStack::DecoderStack(pv::SigSession &session, _samples_decoded(0), _decode_state(Stopped), _options_changed(false), - _no_memory(false) + _no_memory(false), + _mark_index(-1) { connect(&_session, SIGNAL(frame_began()), this, SLOT(on_new_frame())); @@ -79,7 +69,7 @@ DecoderStack::DecoderStack(pv::SigSession &session, connect(&_session, SIGNAL(frame_ended()), this, SLOT(on_frame_ended())); - _stack.push_back(shared_ptr( + _stack.push_back(boost::shared_ptr( new decode::Decoder(dec))); build_row(); @@ -116,7 +106,7 @@ void DecoderStack::push(boost::shared_ptr decoder) void DecoderStack::remove(boost::shared_ptr &decoder) { // Find the decoder in the stack - list< shared_ptr >::iterator iter = _stack.begin(); + list< boost::shared_ptr >::iterator iter = _stack.begin(); for(unsigned int i = 0; i < _stack.size(); i++, iter++) if ((*iter) == decoder) break; @@ -133,7 +123,7 @@ void DecoderStack::build_row() { _rows.clear(); // Add classes - BOOST_FOREACH (const shared_ptr &dec, _stack) + BOOST_FOREACH (const boost::shared_ptr &dec, _stack) { assert(dec); const srd_decoder *const decc = dec->decoder(); @@ -206,6 +196,21 @@ void DecoderStack::get_annotation_subset( 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); + if (iter != _rows.end()) + index = (*iter).second.get_annotation_index(start_sample); + + return index; +} + uint64_t DecoderStack::get_max_annotation(const Row &row) { //lock_guard lock(_output_mutex); @@ -353,84 +358,77 @@ QString DecoderStack::error_message() void DecoderStack::clear() { - //lock_guard decode_lock(_output_mutex); - _sample_count = 0; - _frame_complete = false; - _samples_decoded = 0; - new_decode_data(); - _error_message = QString(); - for (map::iterator i = _rows.begin(); - i != _rows.end(); i++) - _rows[(*i).first] = decode::RowData(); -// _rows.clear(); -// _rows_gshow.clear(); -// _rows_lshow.clear(); -// _class_rows.clear(); - _no_memory = false; + init(); } void DecoderStack::init() { - clear(); + _sample_count = 0; + _frame_complete = false; + _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(); + } + set_mark_index(-1); } void DecoderStack::stop_decode() { //_snapshot.reset(); - - if(_decode_state == Stopped) { - clear(); - return; + if(_decode_state != Stopped) { + if (_decode_thread.get()) { + _decode_thread->interrupt(); + _decode_thread->join(); + _decode_state = Stopped; + } + _decode_thread.reset(); } - - if (_decode_thread.get()) { - _decode_thread->interrupt(); - _decode_thread->join(); - _decode_state = Stopped; - } - _decode_thread.reset(); - clear(); } void DecoderStack::begin_decode() { - shared_ptr logic_signal; - shared_ptr data; + boost::shared_ptr logic_signal; + boost::shared_ptr data; if (!_options_changed) return; _options_changed = false; -// if (_decode_thread.joinable()) { -// _decode_thread.interrupt(); -// _decode_thread.join(); -// } stop_decode(); + init(); // Check that all decoders have the required channels - BOOST_FOREACH(const shared_ptr &dec, _stack) + BOOST_FOREACH(const boost::shared_ptr &dec, _stack) if (!dec->have_required_probes()) { _error_message = tr("One or more required channels " "have not been specified"); return; } -// // Build rows -// build_row(); - // 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 shared_ptr &dec, _stack) - if (dec && !dec->channels().empty() && - ((logic_signal = (*dec->channels().begin()).second)) && - ((data = logic_signal->logic_data()))) - break; + BOOST_FOREACH (const boost::shared_ptr &dec, _stack) { + if (dec && !dec->channels().empty()) { + 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())) + break; + } + if (data) + break; + } + } if (!data) return; // Check we have a snapshot of data - const deque< shared_ptr > &snapshots = + const deque< boost::shared_ptr > &snapshots = data->get_snapshots(); if (snapshots.empty()) return; @@ -438,8 +436,7 @@ void DecoderStack::begin_decode() if (_snapshot->empty()) return; - // Get the samplerate and start time - _start_time = data->get_start_time(); + // Get the samplerate _samplerate = data->samplerate(); if (_samplerate == 0.0) return; @@ -460,27 +457,13 @@ uint64_t DecoderStack::get_max_sample_count() const return max_sample_count; } -boost::optional DecoderStack::wait_for_data() const -{ - //unique_lock input_lock(_input_mutex); - while(!boost::this_thread::interruption_requested() && - !_frame_complete && (uint64_t)_samples_decoded >= _sample_count) - //_input_cond.wait(input_lock); - return boost::make_optional( - !boost::this_thread::interruption_requested() && - ((uint64_t)_samples_decoded < _sample_count || !_frame_complete), - _sample_count); -} - void DecoderStack::decode_data( const uint64_t decode_start, const uint64_t decode_end, - const unsigned int unit_size, srd_session *const session) + srd_session *const session) { - uint8_t *chunk = NULL; + //uint8_t *chunk = NULL; uint64_t last_cnt = 0; uint64_t notify_cnt = (decode_end - decode_start + 1)/100; - const uint64_t chunk_sample_count = - DecodeChunkLength / _snapshot->unit_size(); srd_decoder_inst *logic_di = NULL; // find the first level decoder instant for (GSList *d = session->di_list; d; d = d->next) { @@ -501,41 +484,63 @@ void DecoderStack::decode_data( i < decode_end && !_no_memory) { //lock_guard decode_lock(_global_decode_mutex); + 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) { + chunk.push_back(NULL); + } else { + if (_snapshot->has_data(sig_index)) { + chunk.push_back(_snapshot->get_samples(i, chunk_end, sig_index)); + chunk_const.push_back(_snapshot->get_sample(i, sig_index)); + } else { + _error_message = tr("At least one of selected channels are not enabled."); + return; + } + } + } + if (chunk_end - i > MaxChunkSize) + chunk_end = i + MaxChunkSize; - const uint64_t chunk_end = min( - i + chunk_sample_count, decode_end); - chunk = _snapshot->get_samples(i, chunk_end); - - if (srd_session_send(session, chunk_type, i, chunk_end, chunk, - (chunk_end - i) * unit_size, unit_size, &error) != SRD_OK) { + if (srd_session_send(session, chunk_type, i, chunk_end, + chunk.data(), chunk_const.data(), &error) != SRD_OK) { _error_message = QString::fromLocal8Bit(error); break; } - if (logic_di && logic_di->logic_mask != 0) { + if (logic_di && logic_di->logic_mask != 0 && logic_di->cur_pos < decode_end) { uint64_t cur_pos = logic_di->cur_pos; - assert(cur_pos < _snapshot->get_sample_count()); - uint64_t sample = _snapshot->get_sample(cur_pos) & logic_di->logic_mask; + uint64_t sample; if (logic_di->edge_index == -1) { std::vector pos_vector; cur_pos++; for (int j =0 ; j < logic_di->dec_num_channels; j++) { int index = logic_di->dec_channelmap[j]; - if (index != -1 && (logic_di->logic_mask & (1 << index))) { - bool last_sample = (sample & (1 << index)) ? 1 : 0; + if (index != -1 && (logic_di->logic_mask & (1 << j))) { + bool last_sample = _snapshot->get_sample(cur_pos - 1, index); pos_vector.push_back(cur_pos); _snapshot->get_nxt_edge(pos_vector.back(), last_sample, decode_end, 1, index); } } cur_pos = *std::min_element(pos_vector.begin(), pos_vector.end()); } else { - bool last_sample = (sample & (1 << logic_di->edge_index)) ? 1 : 0; + bool last_sample = _snapshot->get_sample(cur_pos, logic_di->edge_index); do { + sample = 0; cur_pos++; if (!_snapshot->get_nxt_edge(cur_pos, last_sample, decode_end, 1, logic_di->edge_index)) break; - sample = _snapshot->get_sample(cur_pos) & logic_di->logic_mask; - last_sample = (sample & (1 << logic_di->edge_index)) ? 1 : 0; + for (int j =0 ; j < logic_di->dec_num_channels; j++) { + if (logic_di->logic_mask & (1 << j)) { + int index = logic_di->dec_channelmap[j]; + bool index_sample = _snapshot->get_sample(cur_pos, index); + sample += index_sample << j; + if (index == logic_di->edge_index) + last_sample = index_sample; + } + } } while(sample != logic_di->exp_logic); } @@ -544,7 +549,7 @@ void DecoderStack::decode_data( i = decode_end; chunk_type = 0; } else { - i += chunk_sample_count; + i = chunk_end + 1; chunk_type = 1; } @@ -582,18 +587,16 @@ void DecoderStack::decode_proc() _decode_state = Running; - // Create the decoders - const unsigned int unit_size = _snapshot->unit_size(); - // Get the intial sample count { //unique_lock input_lock(_input_mutex); sample_count = _sample_count = _snapshot->get_sample_count(); } - BOOST_FOREACH(const shared_ptr &dec, _stack) + // Create the decoders + BOOST_FOREACH(const boost::shared_ptr &dec, _stack) { - srd_decoder_inst *const di = dec->create_decoder_inst(session, unit_size); + srd_decoder_inst *const di = dec->create_decoder_inst(session); if (!di) { @@ -619,7 +622,7 @@ void DecoderStack::decode_proc() char *error = NULL; if (srd_session_start(session, &error) == SRD_OK) - decode_data(decode_start, decode_end, unit_size, session); + decode_data(decode_start, decode_end, session); else _error_message = QString::fromLocal8Bit(error); @@ -747,5 +750,15 @@ bool DecoderStack::out_of_memory() const return _no_memory; } +void DecoderStack::set_mark_index(int64_t index) +{ + _mark_index = index; +} + +int64_t DecoderStack::get_mark_index() const +{ + return _mark_index; +} + } // namespace data } // namespace pv diff --git a/DSView/pv/data/decoderstack.h b/DSView/pv/data/decoderstack.h index 281a5428..c7baf7cc 100644 --- a/DSView/pv/data/decoderstack.h +++ b/DSView/pv/data/decoderstack.h @@ -21,7 +21,7 @@ #ifndef DSVIEW_PV_DATA_DECODERSTACK_H #define DSVIEW_PV_DATA_DECODERSTACK_H -#include +#include #include @@ -68,6 +68,7 @@ private: static const double DecodeThreshold; static const int64_t DecodeChunkLength; static const unsigned int DecodeNotifyPeriod; + static const uint64_t MaxChunkSize = 1024 * 16; public: enum decode_state { @@ -96,6 +97,9 @@ public: const decode::Row &row, uint64_t start_sample, uint64_t end_sample) const; + uint64_t get_annotation_index( + const decode::Row &row, uint64_t start_sample) const; + uint64_t get_max_annotation(const decode::Row &row); uint64_t get_min_annotation(const decode::Row &row); // except instant(end=start) annotation @@ -137,14 +141,11 @@ public: bool out_of_memory() const; + void set_mark_index(int64_t index); + int64_t get_mark_index() const; + private: - boost::optional wait_for_data() const; - -// void decode_data(const uint64_t sample_count, -// const unsigned int unit_size, srd_session *const session); - - void decode_data(const uint64_t decode_start, const uint64_t decode_end, - const unsigned int unit_size, srd_session *const session); + void decode_data(const uint64_t decode_start, const uint64_t decode_end, srd_session *const session); void decode_proc(); @@ -199,6 +200,8 @@ private: bool _options_changed; bool _no_memory; + int64_t _mark_index; + friend class DecoderStackTest::TwoDecoderStack; }; diff --git a/DSView/pv/data/dsosnapshot.cpp b/DSView/pv/data/dsosnapshot.cpp index 665c0dbe..b3e06955 100644 --- a/DSView/pv/data/dsosnapshot.cpp +++ b/DSView/pv/data/dsosnapshot.cpp @@ -80,6 +80,7 @@ void DsoSnapshot::init() _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; @@ -96,15 +97,29 @@ void DsoSnapshot::clear() init(); } -void DsoSnapshot::first_payload(const sr_datafeed_dso &dso, uint64_t total_sample_count, unsigned int channel_num, bool instant) +void DsoSnapshot::first_payload(const sr_datafeed_dso &dso, uint64_t total_sample_count, + std::map ch_enable, bool instant) { + bool re_alloc = false; + unsigned int channel_num = 0; + for (auto& iter:ch_enable) { + if (iter.second) + channel_num++; + } + assert(channel_num != 0); + + if (total_sample_count != _total_sample_count || + channel_num != _channel_num) + re_alloc = true; + _total_sample_count = total_sample_count; _channel_num = channel_num; _instant = instant; + _ch_enable = ch_enable; bool isOk = true; - uint64_t size = _total_sample_count * _unit_size + sizeof(uint64_t); - if (size != _capacity) { + uint64_t size = _total_sample_count * _channel_num + sizeof(uint64_t); + if (re_alloc || size != _capacity) { free_data(); _data = malloc(size); if (_data) { @@ -137,7 +152,6 @@ void DsoSnapshot::first_payload(const sr_datafeed_dso &dso, uint64_t total_sampl } else { free_data(); free_envelop(); - _capacity = 0; _memory_failed = true; } } @@ -147,7 +161,7 @@ void DsoSnapshot::append_payload(const sr_datafeed_dso &dso) boost::lock_guard lock(_mutex); if (_channel_num > 0 && dso.num_samples != 0) { - refill_data(dso.data, dso.num_samples, _instant); + append_data(dso.data, dso.num_samples, _instant); // Generate the first mip-map from the data if (_envelope_en) @@ -155,6 +169,18 @@ void DsoSnapshot::append_payload(const sr_datafeed_dso &dso) } } +void DsoSnapshot::append_data(void *data, uint64_t samples, bool instant) +{ + if (instant) { + memcpy((uint8_t*)_data + _sample_count * _channel_num, data, samples*_channel_num); + _sample_count = (_sample_count + samples) % (_total_sample_count + 1); + } else { + memcpy((uint8_t*)_data, data, samples*_channel_num); + _sample_count = samples; + } + +} + void DsoSnapshot::enable_envelope(bool enable) { boost::lock_guard lock(_mutex); @@ -382,5 +408,13 @@ double DsoSnapshot::cal_vmean(int index) const return vmean; } +bool DsoSnapshot::has_data(int index) +{ + if (_ch_enable.find(index) != _ch_enable.end()) + return _ch_enable[index]; + else + return false; +} + } // namespace data } // namespace pv diff --git a/DSView/pv/data/dsosnapshot.h b/DSView/pv/data/dsosnapshot.h index df6376e0..e34ca502 100644 --- a/DSView/pv/data/dsosnapshot.h +++ b/DSView/pv/data/dsosnapshot.h @@ -77,7 +77,7 @@ public: void clear(); void init(); - void first_payload(const sr_datafeed_dso &dso, uint64_t total_sample_count, unsigned int channel_num, bool instant); + void first_payload(const sr_datafeed_dso &dso, uint64_t total_sample_count, std::map ch_enable, bool instant); void append_payload(const sr_datafeed_dso &dso); @@ -92,7 +92,10 @@ public: double cal_vrms(double zero_off, int index) const; double cal_vmean(int index) const; + bool has_data(int index); + private: + void append_data(void *data, uint64_t samples, bool instant); void free_envelop(); void reallocate_envelope(Envelope &l); void append_payload_to_envelope_levels(bool header); @@ -102,6 +105,7 @@ private: bool _envelope_en; bool _envelope_done; bool _instant; + std::map _ch_enable; friend class DsoSnapshotTest::Basic; }; diff --git a/DSView/pv/data/logicsnapshot.cpp b/DSView/pv/data/logicsnapshot.cpp index 40ee3087..199f47bc 100644 --- a/DSView/pv/data/logicsnapshot.cpp +++ b/DSView/pv/data/logicsnapshot.cpp @@ -40,30 +40,43 @@ using namespace std; namespace pv { namespace data { -const int LogicSnapshot::MipMapScalePower = 4; -const int LogicSnapshot::MipMapScaleFactor = 1 << MipMapScalePower; -const float LogicSnapshot::LogMipMapScaleFactor = logf(MipMapScaleFactor); -const uint64_t LogicSnapshot::MipMapDataUnit = 64*1024; // bytes +const uint64_t LogicSnapshot::LevelMask[LogicSnapshot::ScaleLevel] = { + ~(~0ULL << ScalePower) << 0 * ScalePower, + ~(~0ULL << ScalePower) << 1 * ScalePower, + ~(~0ULL << ScalePower) << 2 * ScalePower, + ~(~0ULL << ScalePower) << 3 * ScalePower, +}; +const uint64_t LogicSnapshot::LevelOffset[LogicSnapshot::ScaleLevel] = { + 0, + (uint64_t)pow(Scale, 3), + (uint64_t)pow(Scale, 3) + (uint64_t)pow(Scale, 2), + (uint64_t)pow(Scale, 3) + (uint64_t)pow(Scale, 2) + (uint64_t)pow(Scale, 1), +}; LogicSnapshot::LogicSnapshot() : - Snapshot(1, 1, 1), - _last_append_sample(0) + Snapshot(1, 0, 0), + _block_num(0) { - memset(_mip_map, 0, sizeof(_mip_map)); } LogicSnapshot::~LogicSnapshot() { - free_mipmap(); } -void LogicSnapshot::free_mipmap() +void LogicSnapshot::free_data() { - BOOST_FOREACH(MipMapLevel &l, _mip_map) { - if (l.data) - free(l.data); + Snapshot::free_data(); + for(auto& iter:_ch_data) { + for(auto& iter_rn:iter) { + for (unsigned int k = 0; k < Scale; k++) + if (iter_rn.lbp[k] != NULL) + free(iter_rn.lbp[k]); + } + std::vector void_vector; + iter.swap(void_vector); } - memset(_mip_map, 0, sizeof(_mip_map)); + _ch_data.clear(); + _sample_count = 0; } void LogicSnapshot::init() @@ -71,308 +84,602 @@ void LogicSnapshot::init() boost::lock_guard lock(_mutex); _sample_count = 0; _ring_sample_count = 0; + _block_num = 0; + _byte_fraction = 0; + _ch_fraction = 0; + _src_ptr = NULL; + _dest_ptr = NULL; + _data = NULL; _memory_failed = false; _last_ended = true; - for (unsigned int level = 0; level < ScaleStepCount; level++) { - _mip_map[level].length = 0; - _mip_map[level].data_length = 0; - } } void LogicSnapshot::clear() { boost::lock_guard lock(_mutex); free_data(); - free_mipmap(); init(); } -void LogicSnapshot::first_payload(const sr_datafeed_logic &logic, uint64_t total_sample_count, unsigned int channel_num) +void LogicSnapshot::capture_ended() { - _total_sample_count = total_sample_count; - _channel_num = channel_num; - _unit_size = logic.unitsize; + Snapshot::capture_ended(); - bool isOk = true; - uint64_t size = _total_sample_count * _unit_size + sizeof(uint64_t); - if (size != _capacity) { - free_data(); - _data = malloc(size); - if (_data) { - free_mipmap(); - uint64_t mipmap_count = _total_sample_count / MipMapScaleFactor; - for (unsigned int level = 0; level < ScaleStepCount; level++) { - mipmap_count = ((mipmap_count + MipMapDataUnit - 1) / - MipMapDataUnit) * MipMapDataUnit; - _mip_map[level].data = malloc(mipmap_count * _unit_size + sizeof(uint64_t)); - if (!_mip_map[level].data) { - isOk = false; - break; - } - mipmap_count = mipmap_count / MipMapScaleFactor; + //assert(_ch_fraction == 0); + //assert(_byte_fraction == 0); + uint64_t block_index = _ring_sample_count / LeafBlockSamples; + uint64_t block_offset = (_ring_sample_count % LeafBlockSamples) / Scale; + if (block_offset != 0) { + uint64_t index0 = block_index / RootScale; + uint64_t index1 = block_index % RootScale; + int order = 0; + for(auto& iter:_ch_data) { + const uint64_t *end_ptr = (uint64_t *)iter[index0].lbp[index1] + (LeafBlockSamples / Scale); + uint64_t *ptr = (uint64_t *)iter[index0].lbp[index1] + block_offset; + while (ptr < end_ptr) + *ptr++ = 0; + + // calc mipmap of current block + calc_mipmap(order, index0, index1, block_offset * Scale); + + // calc root of current block + if (*((uint64_t *)iter[index0].lbp[index1]) != 0) + iter[index0].value += 1ULL << index1; + if (*((uint64_t *)iter[index0].lbp[index1] + LeafBlockSpace / sizeof(uint64_t) - 1) != 0) { + iter[index0].tog += 1ULL << index1; + } else { + // trim leaf to free space + free(iter[index0].lbp[index1]); + iter[index0].lbp[index1] = NULL; + } + + order++; + } + } + _sample_count = _ring_sample_count; +} + +void LogicSnapshot::first_payload(const sr_datafeed_logic &logic, uint64_t total_sample_count, GSList *channels) +{ + bool channel_changed = false; + uint16_t channel_num = 0; + for (const GSList *l = channels; l; l = l->next) { + sr_channel *const probe = (sr_channel*)l->data; + assert(probe); + if (probe->type == SR_CHANNEL_LOGIC) { + channel_num += probe->enabled; + if (!channel_changed && probe->enabled) { + channel_changed = !has_data(probe->index); } - } else { - isOk = false; } } - if (isOk) { - _capacity = size; - _memory_failed = false; - append_payload(logic); - _last_ended = false; - } else { + if (total_sample_count != _total_sample_count || + channel_num != _channel_num || + channel_changed) { free_data(); - free_mipmap(); - _capacity = 0; - _memory_failed = true; + _total_sample_count = total_sample_count; + _channel_num = channel_num; + uint64_t rootnode_size = (_total_sample_count + RootNodeSamples - 1) / RootNodeSamples; + for (const GSList *l = channels; l; l = l->next) { + sr_channel *const probe = (sr_channel*)l->data; + if (probe->type == SR_CHANNEL_LOGIC && probe->enabled) { + std::vector root_vector; + for (uint64_t j = 0; j < rootnode_size; j++) { + struct RootNode rn; + rn.tog = 0; + rn.value = 0; + memset(rn.lbp, 0, sizeof(rn.lbp)); + root_vector.push_back(rn); + } + _ch_data.push_back(root_vector); + _ch_index.push_back(probe->index); + } + } + } else { + for(auto& iter:_ch_data) { + for(auto& iter_rn:iter) { + iter_rn.tog = 0; + iter_rn.value = 0; + } + } } + + _sample_count = 0; + _last_sample.clear(); + _sample_cnt.clear(); + _block_cnt.clear(); + _ring_sample_cnt.clear(); + for (unsigned int i = 0; i < _channel_num; i++) { + _last_sample.push_back(0); + _sample_cnt.push_back(0); + _block_cnt.push_back(0); + _ring_sample_cnt.push_back(0); + } + + append_payload(logic); + _last_ended = false; } void LogicSnapshot::append_payload( const sr_datafeed_logic &logic) { - assert(_unit_size == logic.unitsize); - assert((logic.length % _unit_size) == 0); - boost::lock_guard lock(_mutex); - append_data(logic.data, logic.length / _unit_size); - - // Generate the first mip-map from the data - append_payload_to_mipmap(); + if (logic.format == LA_CROSS_DATA) + append_cross_payload(logic); + else if (logic.format == LA_SPLIT_DATA) + append_split_payload(logic); } -uint8_t * LogicSnapshot::get_samples(int64_t start_sample, int64_t end_sample) const +void LogicSnapshot::append_cross_payload( + const sr_datafeed_logic &logic) +{ + assert(logic.format == LA_CROSS_DATA); + assert(logic.length >= ScaleSize * _channel_num); + + if (_sample_count >= _total_sample_count) + return; + + uint64_t samples = ceil(logic.length * 8.0 / _channel_num); + + if (_sample_count + samples < _total_sample_count) + _sample_count += samples; + else + _sample_count = _total_sample_count; + + while (_sample_count > _block_num * LeafBlockSamples) { + uint8_t index0 = _block_num / RootScale; + uint8_t index1 = _block_num % RootScale; + for(auto& iter:_ch_data) { + if (iter[index0].lbp[index1] == NULL) + iter[index0].lbp[index1] = malloc(LeafBlockSpace); + if (iter[index0].lbp[index1] == NULL) { + _memory_failed = true; + return; + } + uint64_t *mipmap_ptr = (uint64_t *)iter[index0].lbp[index1] + + (LeafBlockSamples / Scale); + memset(mipmap_ptr, 0, LeafBlockSpace - (LeafBlockSamples / 8)); + } + _block_num++; + } + + _src_ptr = logic.data; + uint64_t len = logic.length; + + // bit align + while (((_ch_fraction != 0) || (_byte_fraction != 0)) && (len != 0)) { + uint8_t *dp_tmp = (uint8_t *)_dest_ptr; + uint8_t *sp_tmp = (uint8_t *)_src_ptr; + do { + //*(uint8_t *)_dest_ptr++ = *(uint8_t *)_src_ptr++; + *dp_tmp++ = *sp_tmp++; + _byte_fraction = (_byte_fraction + 1) % ScaleSize; + len--; + } while ((_byte_fraction != 0) && (len != 0)); + _dest_ptr = dp_tmp; + _src_ptr = sp_tmp; + if (_byte_fraction == 0) { + const uint64_t index0 = _ring_sample_count / RootNodeSamples; + const uint64_t index1 = (_ring_sample_count >> LeafBlockPower) % RootScale; + const uint64_t offset = (_ring_sample_count % LeafBlockSamples) / Scale; + +// _dest_ptr = (uint64_t *)_ch_data[i][index0].lbp[index1] + offset; +// uint64_t mipmap_index = offset / 8 / Scale; +// uint64_t mipmap_offset = (offset / 8) % Scale; +// uint64_t *l1_mipmap = (uint64_t *)_ch_data[i][index0].lbp[index1] + +// (LeafBlockSamples / Scale) + mipmap_index; +// *l1_mipmap += ((_last_sample[i] ^ *(uint64_t *)_dest_ptr) != 0 ? 1ULL : 0ULL) << mipmap_offset; +// _last_sample[i] = *(uint64_t *)_dest_ptr & (1ULL << (Scale - 1)) ? ~0ULL : 0ULL; + + _ch_fraction = (_ch_fraction + 1) % _channel_num; + if (_ch_fraction == 0) + _ring_sample_count += Scale; + _dest_ptr = (uint8_t *)_ch_data[_ch_fraction][index0].lbp[index1] + (offset * ScaleSize); + } + } + + // align data append + { + assert(_ch_fraction == 0); + assert(_byte_fraction == 0); + assert(_ring_sample_count % Scale == 0); + uint64_t pre_index0 = _ring_sample_count / RootNodeSamples; + uint64_t pre_index1 = (_ring_sample_count >> LeafBlockPower) % RootScale; + uint64_t pre_offset = (_ring_sample_count % LeafBlockSamples) / Scale; + uint64_t *src_ptr = NULL; + uint64_t *dest_ptr; + int order = 0; + const uint64_t align_size = len / ScaleSize / _channel_num; + _ring_sample_count += align_size * Scale; + +// uint64_t mipmap_index = pre_offset / Scale; +// uint64_t mipmap_offset = pre_offset % Scale; +// uint64_t *l1_mipmap; + for(auto& iter:_ch_data) { + uint64_t index0 = pre_index0; + uint64_t index1 = pre_index1; + src_ptr = (uint64_t *)_src_ptr + order; + _dest_ptr = iter[index0].lbp[index1]; + dest_ptr = (uint64_t *)_dest_ptr + pre_offset; +// l1_mipmap = (uint64_t *)_dest_ptr + (LeafBlockSamples / Scale) + mipmap_index; + while (src_ptr < (uint64_t *)_src_ptr + (align_size * _channel_num)) { + const uint64_t tmp_u64 = *src_ptr; + *dest_ptr++ = tmp_u64; +// *l1_mipmap += ((_last_sample[i] ^ tmp_u64) != 0 ? 1ULL : 0ULL) << mipmap_offset; +// mipmap_offset = (mipmap_offset + 1) % Scale; +// l1_mipmap += (mipmap_offset == 0); +// _last_sample[i] = tmp_u64 & (1ULL << (Scale - 1)) ? ~0ULL : 0ULL; + src_ptr += _channel_num; + //mipmap + if (dest_ptr == (uint64_t *)_dest_ptr + (LeafBlockSamples / Scale)) { + // calc mipmap of current block + calc_mipmap(order, index0, index1, LeafBlockSamples); + + // calc root of current block + if (*((uint64_t *)iter[index0].lbp[index1]) != 0) + iter[index0].value += 1ULL<< index1; + if (*((uint64_t *)iter[index0].lbp[index1] + LeafBlockSpace / sizeof(uint64_t) - 1) != 0) { + iter[index0].tog += 1ULL << index1; + } else { + // trim leaf to free space + free(iter[index0].lbp[index1]); + iter[index0].lbp[index1] = NULL; + } + + index1++; + if (index1 == RootScale) { + index0++; + index1 = 0; + } + _dest_ptr = iter[index0].lbp[index1]; + dest_ptr = (uint64_t *)_dest_ptr; + } + } + order++; + } + len -= align_size * _channel_num * ScaleSize; + _src_ptr = src_ptr - _channel_num + 1; + } + + // fraction data append + { + uint64_t index0 = _ring_sample_count / RootNodeSamples; + uint64_t index1 = (_ring_sample_count >> LeafBlockPower) % RootScale; + uint64_t offset = (_ring_sample_count % LeafBlockSamples) / 8; + _dest_ptr = (uint8_t *)_ch_data[_ch_fraction][index0].lbp[index1] + offset; + + uint8_t *dp_tmp = (uint8_t *)_dest_ptr; + uint8_t *sp_tmp = (uint8_t *)_src_ptr; + while(len-- != 0) { + //*(uint8_t *)_dest_ptr++ = *(uint8_t *)_src_ptr++; + *dp_tmp++ = *sp_tmp++; + if (++_byte_fraction == ScaleSize) { + _ch_fraction = (_ch_fraction + 1) % _channel_num; + _byte_fraction = 0; + //_dest_ptr = (uint8_t *)_ch_data[_ch_fraction][index0].lbp[index1] + offset; + dp_tmp = (uint8_t *)_ch_data[_ch_fraction][index0].lbp[index1] + offset; + } + } + //_dest_ptr = (uint8_t *)_dest_ptr + _byte_fraction; + _dest_ptr = dp_tmp + _byte_fraction; + } +} + +void LogicSnapshot::append_split_payload( + const sr_datafeed_logic &logic) +{ + assert(logic.format == LA_SPLIT_DATA); + + uint64_t samples = logic.length * 8; + uint16_t order = logic.order; + assert(order < _ch_data.size()); + + if (_sample_cnt[order] >= _total_sample_count) + return; + + if (_sample_cnt[order] + samples < _total_sample_count) + _sample_cnt[order] += samples; + else + _sample_cnt[order] = _total_sample_count; + + while (_sample_cnt[order] > _block_cnt[order] * LeafBlockSamples) { + uint8_t index0 = _block_cnt[order] / RootScale; + uint8_t index1 = _block_cnt[order] % RootScale; + if (_ch_data[order][index0].lbp[index1] == NULL) + _ch_data[order][index0].lbp[index1] = malloc(LeafBlockSpace); + if (_ch_data[order][index0].lbp[index1] == NULL) { + _memory_failed = true; + return; + } + memset(_ch_data[order][index0].lbp[index1], 0, LeafBlockSpace); + _block_cnt[order]++; + } + + while(samples > 0) { + const uint64_t index0 = _ring_sample_cnt[order] / RootNodeSamples; + const uint64_t index1 = (_ring_sample_cnt[order] >> LeafBlockPower) % RootScale; + const uint64_t offset = (_ring_sample_cnt[order] % LeafBlockSamples) / 8; + _dest_ptr = (uint8_t *)_ch_data[order][index0].lbp[index1] + offset; + + uint64_t bblank = (LeafBlockSamples - (_ring_sample_cnt[order] & LeafMask)); + if (samples >= bblank) { + memcpy((uint8_t*)_dest_ptr, (uint8_t *)logic.data, bblank/8); + _ring_sample_cnt[order] += bblank; + samples -= bblank; + + // calc mipmap of current block + calc_mipmap(order, index0, index1, LeafBlockSamples); + + // calc root of current block + if (*((uint64_t *)_ch_data[order][index0].lbp[index1]) != 0) + _ch_data[order][index0].value += 1ULL<< index1; + if (*((uint64_t *)_ch_data[order][index0].lbp[index1] + LeafBlockSpace / sizeof(uint64_t) - 1) != 0) { + _ch_data[order][index0].tog += 1ULL << index1; + } else { + // trim leaf to free space + free(_ch_data[order][index0].lbp[index1]); + _ch_data[order][index0].lbp[index1] = NULL; + } + } else { + memcpy((uint8_t*)_dest_ptr, (uint8_t *)logic.data, samples/8); + _ring_sample_cnt[order] += samples; + samples = 0; + } + } + + _sample_count = *min_element(_sample_cnt.begin(), _sample_cnt.end()); + _ring_sample_count = *min_element(_ring_sample_cnt.begin(), _ring_sample_cnt.end()); +} + +void LogicSnapshot::calc_mipmap(unsigned int order, uint8_t index0, uint8_t index1, uint64_t samples) +{ + uint8_t offset; + uint64_t *src_ptr; + uint64_t *dest_ptr; + unsigned int i; + + // level 1 + src_ptr = (uint64_t *)_ch_data[order][index0].lbp[index1]; + dest_ptr = src_ptr + (LeafBlockSamples / Scale) - 1; + const uint64_t mask = 1ULL << (Scale - 1); + for(i = 0; i < samples / Scale; i++) { + offset = i % Scale; + if (offset == 0) + dest_ptr++; + *dest_ptr += ((_last_sample[order] ^ *src_ptr) != 0 ? 1ULL : 0ULL) << offset; + _last_sample[order] = *src_ptr & mask ? ~0ULL : 0ULL; + src_ptr++; + } + + // level 2/3 + src_ptr = (uint64_t *)_ch_data[order][index0].lbp[index1] + (LeafBlockSamples / Scale); + dest_ptr = src_ptr + (LeafBlockSamples / Scale / Scale) - 1; + for(i = LeafBlockSamples / Scale; i < LeafBlockSpace / sizeof(uint64_t) - 1; i++) { + offset = i % Scale; + if (offset == 0) + dest_ptr++; + *dest_ptr += (*src_ptr != 0 ? 1ULL : 0ULL) << offset; + src_ptr++; + } +} + +const uint8_t *LogicSnapshot::get_samples(uint64_t start_sample, uint64_t &end_sample, + int sig_index) { //assert(data); - assert(start_sample >= 0); - assert(start_sample <= (int64_t)get_sample_count()); - assert(end_sample >= 0); - assert(end_sample <= (int64_t)get_sample_count()); + assert(start_sample < get_sample_count()); + assert(end_sample < get_sample_count()); assert(start_sample <= end_sample); - (void)end_sample; + int order = get_ch_order(sig_index); + uint64_t root_index = start_sample >> (LeafBlockPower + RootScalePower); + uint8_t root_pos = (start_sample & RootMask) >> LeafBlockPower; + uint64_t block_offset = (start_sample & LeafMask) / 8; + end_sample = (root_index << (LeafBlockPower + RootScalePower)) + + (root_pos << LeafBlockPower) + + ~(~0ULL << LeafBlockPower); + end_sample = min(end_sample, get_sample_count() - 1); - //const size_t size = (end_sample - start_sample) * _unit_size; - //memcpy(data, (const uint8_t*)_data + start_sample * _unit_size, size); - return (uint8_t*)_data + start_sample * _unit_size; + if (order == -1 || + _ch_data[order][root_index].lbp[root_pos] == NULL) + return NULL; + else + return (uint8_t *)_ch_data[order][root_index].lbp[root_pos] + block_offset; } -void LogicSnapshot::reallocate_mipmap_level(MipMapLevel &m) +bool LogicSnapshot::get_sample(uint64_t index, int sig_index) { - const uint64_t new_data_length = ((m.length + MipMapDataUnit - 1) / - MipMapDataUnit) * MipMapDataUnit; - if (new_data_length > m.data_length) - { - m.data_length = new_data_length; + int order = get_ch_order(sig_index); + assert(order != -1); + assert(_ch_data[order].size() != 0); + assert(index < get_sample_count()); - // Padding is added to allow for the uint64_t write word -// m.data = realloc(m.data, new_data_length * _unit_size + -// sizeof(uint64_t)); - } + uint64_t index_mask = 1ULL << (index & LevelMask[0]); + uint64_t root_index = index >> (LeafBlockPower + RootScalePower); + uint8_t root_pos = (index & RootMask) >> LeafBlockPower; + uint64_t root_pos_mask = 1ULL << root_pos; + + if ((_ch_data[order][root_index].tog & root_pos_mask) == 0) { + return (_ch_data[order][root_index].value & root_pos_mask) != 0; + } else { + uint64_t *lbp = (uint64_t *)_ch_data[order][root_index].lbp[root_pos]; + return *(lbp + ((index & LeafMask) >> ScalePower)) & index_mask; + } } -void LogicSnapshot::append_payload_to_mipmap() -{ - MipMapLevel &m0 = _mip_map[0]; - uint64_t prev_length; - const uint8_t *src_ptr; - uint8_t *dest_ptr; - uint64_t accumulator; - unsigned int diff_counter; - - // Expand the data buffer to fit the new samples - prev_length = m0.length; - m0.length = _sample_count / MipMapScaleFactor; - - // Break off if there are no new samples to compute - if (m0.length == prev_length) - return; - - reallocate_mipmap_level(m0); - - dest_ptr = (uint8_t*)m0.data + prev_length * _unit_size; - - // Iterate through the samples to populate the first level mipmap - const uint8_t *const end_src_ptr = (uint8_t*)_data + - m0.length * _unit_size * MipMapScaleFactor; - for (src_ptr = (uint8_t*)_data + - prev_length * _unit_size * MipMapScaleFactor; - src_ptr < end_src_ptr;) - { - // Accumulate transitions which have occurred in this sample - accumulator = 0; - diff_counter = MipMapScaleFactor; - while (diff_counter-- > 0) - { - const uint64_t sample = *(uint64_t*)src_ptr; - accumulator |= _last_append_sample ^ sample; - _last_append_sample = sample; - src_ptr += _unit_size; - } - - *(uint64_t*)dest_ptr = accumulator; - dest_ptr += _unit_size; - } - - // Compute higher level mipmaps - for (unsigned int level = 1; level < ScaleStepCount; level++) - { - MipMapLevel &m = _mip_map[level]; - const MipMapLevel &ml = _mip_map[level-1]; - - // Expand the data buffer to fit the new samples - prev_length = m.length; - m.length = ml.length / MipMapScaleFactor; - - // Break off if there are no more samples to computed - if (m.length == prev_length) - break; - - reallocate_mipmap_level(m); - - // Subsample the level lower level - src_ptr = (uint8_t*)ml.data + - _unit_size * prev_length * MipMapScaleFactor; - const uint8_t *const end_dest_ptr = - (uint8_t*)m.data + _unit_size * m.length; - for (dest_ptr = (uint8_t*)m.data + - _unit_size * prev_length; - dest_ptr < end_dest_ptr; - dest_ptr += _unit_size) - { - accumulator = 0; - diff_counter = MipMapScaleFactor; - while (diff_counter-- > 0) - { - accumulator |= *(uint64_t*)src_ptr; - src_ptr += _unit_size; - } - - *(uint64_t*)dest_ptr = accumulator; - } - } -} - -void LogicSnapshot::get_subsampled_edges( - std::vector &edges, - uint64_t start, uint64_t end, - float min_length, int sig_index) +bool LogicSnapshot::get_display_edges(std::vector > &edges, + std::vector > &togs, + uint64_t start, uint64_t end, uint16_t width, uint16_t max_togs, + double pixels_offset, double min_length, uint16_t sig_index) { if (!edges.empty()) edges.clear(); + if (!togs.empty()) + togs.clear(); if (get_sample_count() == 0) - return; + return false; assert(end < get_sample_count()); - assert(start <= end); - assert(min_length > 0); - assert(sig_index >= 0); - assert(sig_index < 64); + assert(start <= end); + assert(min_length > 0); uint64_t index = start; bool last_sample; - const uint64_t block_length = (uint64_t)max(min_length, 1.0f); - const uint64_t sig_mask = 1ULL << sig_index; + bool start_sample; - - // Store the initial state - last_sample = (get_sample(start) & sig_mask) != 0; - edges.push_back(pair(index++, last_sample)); - - while (index + block_length <= end) - { + // Get the initial state + start_sample = last_sample = get_sample(index++, sig_index); + togs.push_back(pair(0, last_sample)); + while(edges.size() < width) { // search next edge - get_nxt_edge(index, last_sample, end, min_length, sig_index); + bool has_edge = get_nxt_edge(index, last_sample, end, 0, sig_index); - //----- Store the edge -----// + // calc the edge position + int64_t gap = (index / min_length) - pixels_offset; + index = max((uint64_t)ceil((floor(index/min_length) + 1) * min_length), index + 1); + while(gap > (int64_t)edges.size() && edges.size() < width) + edges.push_back(pair(false, last_sample)); - // Take the last sample of the quanization block - const int64_t final_index = index + block_length; - if (index + block_length > end) - break; + if (index > end) + last_sample = get_sample(end, sig_index); + else + last_sample = get_sample(index - 1, sig_index); - // Store the final state - const bool final_sample = - (get_sample(final_index - 1) & sig_mask) != 0; - edges.push_back(pair(index, final_sample)); + if (has_edge) { + edges.push_back(pair(true, last_sample)); + if (togs.size() < max_togs) + togs.push_back(pair(edges.size() - 1, last_sample)); + } - index = final_index; - last_sample = final_sample; - } + while(index > end && edges.size() < width) + edges.push_back(pair(false, last_sample)); + } - // Add the final state - const bool end_sample = ((get_sample(end) & sig_mask) != 0); - if ((end != get_sample_count() - 1) || - ((end == get_sample_count() - 1) && end_sample != last_sample)) - edges.push_back(pair(end, end_sample)); + if (togs.size() < max_togs) { + last_sample = get_sample(end, sig_index); + togs.push_back(pair(edges.size() - 1, last_sample)); + } - if (end == get_sample_count() - 1) - edges.push_back(pair(end + 1, ~last_sample)); + return start_sample; } bool LogicSnapshot::get_nxt_edge( uint64_t &index, bool last_sample, uint64_t end, - float min_length, int sig_index) + double min_length, int sig_index) { - unsigned int level; - bool fast_forward; - - //assert(index > 0); - - const unsigned int min_level = max((int)floorf(logf(min_length) / - LogMipMapScaleFactor) - 1, 0); - const uint64_t sig_mask = 1ULL << sig_index; - - if (index >= end) + if (index > end) return false; - //----- Continue to search -----// - level = min_level; + int order = get_ch_order(sig_index); + if (order == -1) + return false; - // We cannot fast-forward if there is no mip-map data at - // at the minimum level. - fast_forward = (_mip_map[level].data != NULL); + //const unsigned int min_level = max((int)floorf(logf(min_length) / logf(Scale)) - 1, 0); + const unsigned int min_level = max((int)(log2f(min_length) - 1) / ScalePower, 0); + uint64_t root_index = index >> (LeafBlockPower + RootScalePower); + uint8_t root_pos = (index & RootMask) >> LeafBlockPower; + bool edge_hit = false; - if (min_length < MipMapScaleFactor) + // linear search for the next transition on the root level + for (int64_t i = root_index; !edge_hit && (index <= end) && i < (int64_t)_ch_data[order].size(); i++) { + uint64_t cur_mask = (~0ULL << root_pos); + do { + uint64_t cur_tog = _ch_data[order][i].tog & cur_mask; + if (cur_tog != 0) { + uint64_t first_edge_pos = bsf_folded(cur_tog); + uint64_t *lbp = (uint64_t *)_ch_data[order][i].lbp[first_edge_pos]; + uint64_t blk_start = (i << (LeafBlockPower + RootScalePower)) + (first_edge_pos << LeafBlockPower); + index = max(blk_start, index); + if (min_level < ScaleLevel) { + uint64_t block_end = min(index | LeafMask, end); + edge_hit = block_nxt_edge(lbp, index, block_end, last_sample, min_level); + } else { + edge_hit = true; + } + if (first_edge_pos == RootScale - 1) + break; + cur_mask = (~0ULL << (first_edge_pos + 1)); + } else { + index = (index + (1 << (LeafBlockPower + RootScalePower))) & + (~0ULL << (LeafBlockPower + RootScalePower)); + break; + } + } while (!edge_hit && index < end); + root_pos = 0; + } + return edge_hit; +} + +bool LogicSnapshot::get_pre_edge(uint64_t &index, bool last_sample, + double min_length, int sig_index) +{ + assert(index < get_sample_count()); + + int order = get_ch_order(sig_index); + if (order == -1) + return false; + + //const unsigned int min_level = max((int)floorf(logf(min_length) / logf(Scale)) - 1, 1); + const unsigned int min_level = max((int)(log2f(min_length) - 1) / ScalePower, 0); + int root_index = index >> (LeafBlockPower + RootScalePower); + uint8_t root_pos = (index & RootMask) >> LeafBlockPower; + bool edge_hit = false; + + // linear search for the previous transition on the root level + for (int64_t i = root_index; !edge_hit && i >= 0; i--) { + uint64_t cur_mask = (~0ULL >> (RootScale - root_pos - 1)); + do { + uint64_t cur_tog = _ch_data[order][i].tog & cur_mask; + if (cur_tog != 0) { + uint64_t first_edge_pos = bsr64(cur_tog); + uint64_t *lbp = (uint64_t *)_ch_data[order][i].lbp[first_edge_pos]; + uint64_t blk_end = ((i << (LeafBlockPower + RootScalePower)) + + (first_edge_pos << LeafBlockPower)) | LeafMask; + index = min(blk_end, index); + if (min_level < ScaleLevel) { + edge_hit = block_pre_edge(lbp, index, last_sample, min_level, sig_index); + } else { + edge_hit = true; + } + if (first_edge_pos == 0) + break; + cur_mask = (~0ULL >> (RootScale - first_edge_pos)); + } else { + break; + } + } while (!edge_hit); + root_pos = RootScale - 1; + } + + return edge_hit; +} + +bool LogicSnapshot::block_nxt_edge(uint64_t *lbp, uint64_t &index, uint64_t block_end, bool last_sample, + unsigned int min_level) +{ + unsigned int level = min_level; + bool fast_forward = true; + const uint64_t last = last_sample ? ~0ULL : 0; + + //----- Search Next Edge Within Current LeafBlock -----// + if (level == 0) { // Search individual samples up to the beginning of // the next first level mip map block - const uint64_t final_index = min(end, - pow2_ceil(index, MipMapScalePower)); - - for (; index < final_index && - (index & ~(~0 << MipMapScalePower)) != 0; - index++) - { - const bool sample = - (get_sample(index) & sig_mask) != 0; - - // If there was a change we cannot fast forward - if (sample != last_sample) { - fast_forward = false; - break; - } - } - } - else - { - // If resolution is less than a mip map block, - // round up to the beginning of the mip-map block - // for this level of detail - const int min_level_scale_power = - (level + 1) * MipMapScalePower; - index = pow2_ceil(index, min_level_scale_power); - if (index >= end) - return false; - - // We can fast forward only if there was no change - const bool sample = - (get_sample(index) & sig_mask) != 0; - if (last_sample != sample) + const uint64_t offset = (index & ~(~0ULL << LeafBlockPower)) >> ScalePower; + const uint64_t mask = last_sample ? ~(~0ULL << (index & LevelMask[0])) : ~0ULL << (index & LevelMask[0]); + uint64_t sample = last_sample ? *(lbp + offset) | mask : *(lbp + offset) & mask; + if (sample ^ last) { + index = (index & ~LevelMask[0]) + bsf_folded(last_sample ? ~sample : sample); fast_forward = false; + } else { + index = ((index >> ScalePower) + 1) << ScalePower; + } + } else { + index = ((index >> level*ScalePower) + 1) << level*ScalePower; } if (fast_forward) { @@ -382,155 +689,94 @@ bool LogicSnapshot::get_nxt_edge( // zooming in on them to find the point where the edge // begins. - // Slide right and zoom out at the beginnings of mip-map + // Zoom out at the beginnings of mip-map // blocks until we encounter a change - while (1) { - const int level_scale_power = - (level + 1) * MipMapScalePower; - const uint64_t offset = - index >> level_scale_power; - - // Check if we reached the last block at this - // level, or if there was a change in this block - if (offset >= _mip_map[level].length || - (get_subsample(level, offset) & - sig_mask)) - break; - - if ((offset & ~(~0 << MipMapScalePower)) == 0) { - // If we are now at the beginning of a - // higher level mip-map block ascend one - // level - if (level + 1 >= ScaleStepCount || - !_mip_map[level + 1].data) - break; - + while (index <= block_end) { + // continue only within current block + if (level == 0) level++; - } else { - // Slide right to the beginning of the - // next mip map block - index = pow2_ceil(index + 1, - level_scale_power); - } - } - - // Zoom in, and slide right until we encounter a change, - // and repeat until we reach min_level - while (1) { - assert(_mip_map[level].data); - const int level_scale_power = - (level + 1) * MipMapScalePower; + (level + 1) * ScalePower; const uint64_t offset = - index >> level_scale_power; + (index & ~(~0ULL << LeafBlockPower)) >> level_scale_power; + const uint64_t mask = ~0ULL << ((index & LevelMask[level]) >> (level*ScalePower)); + uint64_t sample = *(lbp + LevelOffset[level] + offset) & mask; - // Check if we reached the last block at this - // level, or if there was a change in this block - if (offset >= _mip_map[level].length || - (get_subsample(level, offset) & - sig_mask)) { - // Zoom in unless we reached the minimum - // zoom - if (level == min_level) - break; - - level--; + // Check if there was a change in this block + if (sample) { + index = (index & (~0 << (level + 1)*ScalePower)) + (bsf_folded(sample) << level*ScalePower); + break; } else { - // Slide right to the beginning of the - // next mip map block - index = pow2_ceil(index + 1, - level_scale_power); + index = ((index >> (level + 1)*ScalePower) + 1) << (level + 1)*ScalePower; + ++level; } } - // If individual samples within the limit of resolution, - // do a linear search for the next transition within the - // block - if (min_length < MipMapScaleFactor) { - for (; index < end; index++) { - const bool sample = (get_sample(index) & - sig_mask) != 0; - if (sample != last_sample) + // Zoom in until we encounter a change, + // and repeat until we reach min_level + while ((index <= block_end) && (level > min_level)) { + // continue only within current block + level--; + const int level_scale_power = + (level + 1) * ScalePower; + const uint64_t offset = + (index & ~(~0ULL << LeafBlockPower)) >> level_scale_power; + const uint64_t mask = (level == 0 && last_sample) ? + ~(~0ULL << ((index & LevelMask[level]) >> (level*ScalePower))) : + ~0ULL << ((index & LevelMask[level]) >> (level*ScalePower)); + uint64_t sample = (level == 0 && last_sample) ? + *(lbp + LevelOffset[level] + offset) | mask : + *(lbp + LevelOffset[level] + offset) & mask; + + // Update the low level position of the change in this block + if (level == 0 ? sample ^ last : sample) { + index = (index & (~0 << (level + 1)*ScalePower)) + (bsf_folded(level == 0 ? sample ^ last : sample) << level*ScalePower); + if (level == min_level) break; } } } - if (index >= end) - return false; - else - return true; + return (index <= block_end); } -bool LogicSnapshot::get_pre_edge( - uint64_t &index, bool last_sample, - float min_length, int sig_index) +bool LogicSnapshot::block_pre_edge(uint64_t *lbp, uint64_t &index, bool last_sample, + unsigned int min_level, int sig_index) { - unsigned int level; - bool fast_forward; + assert(min_level == 0); - assert(index < get_sample_count()); + unsigned int level = min_level; + bool fast_forward = true; + const uint64_t last = last_sample ? ~0ULL : 0; + uint64_t block_start = index & ~LeafMask; - const unsigned int min_level = max((int)floorf(logf(min_length) / - LogMipMapScaleFactor) - 1, 0); - const uint64_t sig_mask = 1ULL << sig_index; - - //----- Continue to search -----// - level = min_level; - - // We cannot fast-forward if there is no mip-map data at - // at the minimum level. - fast_forward = (_mip_map[level].data != NULL); - - if (min_length < MipMapScaleFactor) + //----- Search Next Edge Within Current LeafBlock -----// + if (level == 0) { - // Search individual samples down to the ending of + // Search individual samples down to the beginning of // the previous first level mip map block - uint64_t final_index; - if (index < (1 << MipMapScalePower)) - final_index = 0; - else - final_index = pow2_ceil(index + 1, MipMapScalePower) - (1 << MipMapScalePower) - 1; - - for (; index >= final_index; index--) - { - const bool sample = - (get_sample(index) & sig_mask) != 0; - - // If there was a change we cannot fast forward - if (sample != last_sample) { - fast_forward = false; - index++; - return true; - } - + const uint64_t offset = (index & ~(~0ULL << LeafBlockPower)) >> ScalePower; + const uint64_t mask = last_sample ? ~(~0ULL >> (Scale - (index & LevelMask[0]) - 1)) : ~0ULL >> (Scale - (index & LevelMask[0]) - 1); + uint64_t sample = last_sample ? *(lbp + offset) | mask : *(lbp + offset) & mask; + if (sample ^ last) { + index = (index & ~LevelMask[0]) + bsr64(last_sample ? ~sample : sample) + 1; + return true; + } else { + index &= ~LevelMask[0]; if (index == 0) return false; - } - } - else - { - // If resolution is less than a mip map block, - // round up to the beginning of the mip-map block - // for this level of detail - const unsigned int min_level_scale_power = - (level + 1) * MipMapScalePower; - if (index < (uint64_t)(1 << min_level_scale_power)) - index = 0; - else - index = pow2_ceil(index, min_level_scale_power) - (1 << min_level_scale_power) - 1; + else + index--; - // We can fast forward only if there was no change - const bool sample = - (get_sample(index) & sig_mask) != 0; - if (last_sample != sample) { - fast_forward = false; - index++; - return true; + // using get_sample() to avoid out of block case + bool sample = get_sample(index, sig_index); + if (sample ^ last_sample) { + index++; + return true; + } else if (index < block_start) { + return false; + } } - - if (index == 0) - return false; } if (fast_forward) { @@ -540,96 +786,305 @@ bool LogicSnapshot::get_pre_edge( // zooming in on them to find the point where the edge // begins. - // Slide left and zoom out at the endings of mip-map + // Zoom out at the beginnings of mip-map // blocks until we encounter a change - while (1) { - const int level_scale_power = - (level + 1) * MipMapScalePower; - const uint64_t offset = - index >> level_scale_power; - - // Check if we reached the first block at this - // level, or if there was a change in this block - if (offset == 0 || - (get_subsample(level, offset) & - sig_mask)) - break; - - if (((offset+1) & ~(~0 << MipMapScalePower)) == 0) { - // If we are now at the ending of a - // higher level mip-map block ascend one - // level - if (level + 1 >= ScaleStepCount || - !_mip_map[level + 1].data) - break; - + while (index > block_start) { + // continue only within current block + if (level == 0) level++; - } else { - // Slide left to the beginning of the - // previous mip map block - index = pow2_ceil(index + 1, - level_scale_power) - (1 << level_scale_power) - 1; - } - } - - // Zoom in, and slide left until we encounter a change, - // and repeat until we reach min_level - while (1) { - assert(_mip_map[level].data); - const int level_scale_power = - (level + 1) * MipMapScalePower; + (level + 1) * ScalePower; const uint64_t offset = - index >> level_scale_power; + (index & ~(~0ULL << LeafBlockPower)) >> level_scale_power; + const uint64_t mask = ~0ULL >> (Scale - ((index & LevelMask[level]) >> (level*ScalePower)) - 1); + uint64_t sample = *(lbp + LevelOffset[level] + offset) & mask; - // Check if we reached the first block at this - // level, or if there was a change in this block - if (offset == 0 || - (get_subsample(level, offset) & - sig_mask)) { - // Zoom in unless we reached the minimum - // zoom - if (level == min_level) - break; - - level--; + // Check if there was a change in this block + if (sample) { + index = (index & (~0 << (level + 1)*ScalePower)) + + (bsr64(sample) << level*ScalePower) + + ~(~0ULL << level*ScalePower); + break; } else { - // Slide left to the ending of the - // previous mip map block - index = pow2_ceil(index + 1, - level_scale_power) - (1 << level_scale_power) - 1; + index = (index >> (level + 1)*ScalePower) << (level + 1)*ScalePower; + if (index == 0) + return false; + else + index--; } } - // If individual samples within the limit of resolution, - // do a linear search for the next transition within the - // block - if (min_length < MipMapScaleFactor) { - for (; index > 0; index--) { - const bool sample = (get_sample(index) & - sig_mask) != 0; - if (sample != last_sample) { + // Zoom in until we encounter a change, + // and repeat until we reach min_level + while ((index >= block_start) && (level > min_level)) { + // continue only within current block + level--; + const int level_scale_power = + (level + 1) * ScalePower; + const uint64_t offset = + (index & ~(~0ULL << LeafBlockPower)) >> level_scale_power; + const uint64_t mask = (level == 0 && last_sample) ? + ~(~0ULL >> (Scale - ((index & LevelMask[level]) >> (level*ScalePower)) - 1)) : + ~0ULL >> (Scale - ((index & LevelMask[level]) >> (level*ScalePower)) - 1); + uint64_t sample = (level == 0 && last_sample) ? + *(lbp + LevelOffset[level] + offset) | mask : + *(lbp + LevelOffset[level] + offset) & mask; + + // Update the low level position of the change in this block + if (level == 0 ? sample ^ last : sample) { + index = (index & (~0 << (level + 1)*ScalePower)) + + (bsr64(level == 0 ? sample ^ last : sample) << level*ScalePower) + + ~(~0ULL << level*ScalePower); + if (level == min_level) { index++; - return true; + break; } + } else { + index = (index & (~0 << (level + 1)*ScalePower)); + } + } + } + + return (index >= block_start) && (index != 0); +} + +bool LogicSnapshot::pattern_search(int64_t start, int64_t end, bool nxt, int64_t &index, + std::map pattern) +{ + int start_match_pos = pattern.size() - 1; + int end_match_pos = 0; + if (pattern.empty()) { + return true; + } else { + for (auto& iter:pattern) { + int char_index = 0; + for (auto& iter_char:iter.second) { + if (iter_char != 'X') { + start_match_pos = min(start_match_pos, char_index); + end_match_pos = max(end_match_pos, char_index); + } + char_index++; + } + } + } + + if (start_match_pos > end_match_pos) + return true; + + std::map cur_sample; + std::map exp_sample; + std::map cur_edge; + std::map exp_edge; + int nxt_match_pos = nxt ? start_match_pos : end_match_pos; + int cur_match_pos = nxt ? nxt_match_pos - 1 : nxt_match_pos + 1; + std::vector exp_index; + bool find_edge; + typedef std::map::iterator it_type; + while(nxt ? index <= end : index >= start) { + // get expacted and current pattern + exp_index.clear(); + for(it_type iterator = pattern.begin(); + iterator != pattern.end(); iterator++) { + uint16_t ch_index = iterator->first; + if (!has_data(ch_index)) + continue; + exp_index.push_back(index); + cur_sample[ch_index] = get_sample(index, ch_index); + + if (iterator->second[nxt_match_pos] == '0') { + exp_sample[ch_index] = false; + } else if (iterator->second[nxt_match_pos] == '1') { + exp_sample[ch_index] = true; + } else if (iterator->second[nxt_match_pos] == 'X') { + exp_sample[ch_index] = cur_sample[ch_index]; + } else if (iterator->second[nxt_match_pos] == 'F') { + exp_sample[ch_index] = false; + exp_edge[ch_index] = true; + } else if (iterator->second[nxt_match_pos] == 'R') { + exp_sample[ch_index] = true; + exp_edge[ch_index] = true; + } else if (iterator->second[nxt_match_pos] == 'C') { + exp_sample[ch_index] = cur_sample[ch_index]; + exp_edge[ch_index] = true; + } + + if (exp_edge.find(ch_index) != exp_edge.end()) { + if (index > start) { + bool sample = get_sample(index - 1, ch_index); + if (sample != cur_sample[ch_index]) + cur_edge[ch_index] = true; + } + } + } + cur_match_pos = nxt_match_pos; + + // pattern compare + if (cur_edge == exp_edge && + cur_sample == exp_sample) + nxt_match_pos += nxt ? 1 : -1; + + if (nxt ? nxt_match_pos > end_match_pos : + nxt_match_pos < start_match_pos) { + // all matched + return true; + } else if (nxt ? nxt_match_pos > cur_match_pos : + nxt_match_pos < cur_match_pos) { + // one stage matched + int64_t sub_index = nxt ? index + 1 : index - 1; + while((nxt ? cur_match_pos++ < end_match_pos : cur_match_pos-- > start_match_pos) && + (nxt ? sub_index <= end : sub_index >= start)) { + // get expacted and current pattern + exp_index.clear(); + for(it_type iterator = pattern.begin(); + iterator != pattern.end(); iterator++) { + uint16_t ch_index = iterator->first; + if (!has_data(ch_index)) + continue; + exp_index.push_back(sub_index); + cur_sample[ch_index] = get_sample(sub_index, ch_index); + + if (iterator->second[cur_match_pos] == '0') { + exp_sample[ch_index] = false; + } else if (iterator->second[cur_match_pos] == '1') { + exp_sample[ch_index] = true; + } else if (iterator->second[cur_match_pos] == 'X') { + exp_sample[ch_index] = cur_sample[ch_index]; + } else if (iterator->second[cur_match_pos] == 'F') { + exp_sample[ch_index] = false; + exp_edge[ch_index] = true; + } else if (iterator->second[cur_match_pos] == 'R') { + exp_sample[ch_index] = true; + exp_edge[ch_index] = true; + } else if (iterator->second[cur_match_pos] == 'C') { + exp_sample[ch_index] = cur_sample[ch_index]; + exp_edge[ch_index] = true; + } + + if (exp_edge.find(ch_index) != exp_edge.end()) { + if (sub_index > start) { + bool sample = get_sample(sub_index - 1, ch_index); + if (sample != cur_sample[ch_index]) + cur_edge[ch_index] = true; + } + } + } + + // pattern compare + if (cur_edge != exp_edge || + cur_sample != exp_sample) { + cur_match_pos = nxt_match_pos - 1; + index += nxt ? 1 : -1; + break; + } else { + sub_index += nxt ? 1 : -1; + } + } + + if (nxt ? cur_match_pos > end_match_pos : + cur_match_pos < start_match_pos) { + index = nxt ? sub_index - 1 : index; + return true; + } else { + return false; + } + } else { + // not matched, find the next index for pattern compare + find_edge = true; + int seq = 0; + for(it_type iterator = pattern.begin(); + iterator != pattern.end(); iterator++) { + uint16_t ch_index = iterator->first; + if (!has_data(ch_index)) + continue; + if (exp_edge.find(ch_index) != exp_edge.end() || + cur_sample[ch_index] != exp_sample[ch_index]) { + do { + if (nxt) { + exp_index[seq] += 1; + find_edge = get_nxt_edge(exp_index[seq], cur_sample[ch_index], end, 1, ch_index); + } else { + exp_index[seq] -= 1; + cur_sample[ch_index] = get_sample(exp_index[seq], ch_index); + find_edge = get_pre_edge(exp_index[seq], cur_sample[ch_index], 1, ch_index); + } + if (find_edge) + cur_sample[ch_index] = get_sample(exp_index[seq], ch_index); + else + break; + }while(cur_sample[ch_index] != exp_sample[ch_index]); + } + seq++; + } + if (find_edge) { + if (nxt) + index = *max_element(exp_index.begin(), exp_index.end()); + else + index = *min_element(exp_index.begin(), exp_index.end()); + } else { + break; } } } return false; } -uint64_t LogicSnapshot::get_subsample(int level, uint64_t offset) const +bool LogicSnapshot::has_data(int sig_index) { - assert(level >= 0); - assert(_mip_map[level].data); - return *(uint64_t*)((uint8_t*)_mip_map[level].data + - _unit_size * offset); + return get_ch_order(sig_index) != -1; } -uint64_t LogicSnapshot::pow2_ceil(uint64_t x, unsigned int power) +int LogicSnapshot::get_block_num() { - const uint64_t p = 1 << power; - return (x + p - 1) / p * p; + return (_ring_sample_count >> LeafBlockPower) + + ((_ring_sample_count & LeafMask) != 0); +} + +uint64_t LogicSnapshot::get_block_size(int block_index) +{ + assert(block_index < get_block_num()); + + if (block_index < get_block_num() - 1) { + return LeafBlockSamples / 8; + } else { + if (_ring_sample_count % LeafBlockSamples == 0) + return LeafBlockSamples / 8; + else + return (_ring_sample_count % LeafBlockSamples) / 8; + } +} + +uint8_t *LogicSnapshot::get_block_buf(int block_index, int sig_index, bool &sample) +{ + assert(block_index < get_block_num()); + + int order = get_ch_order(sig_index); + if (order == -1) { + sample = 0; + return NULL; + } + uint64_t index = block_index / RootScale; + uint8_t pos = block_index % RootScale; + uint8_t *lbp = (uint8_t *)_ch_data[order][index].lbp[pos]; + + if (lbp == NULL) + sample = (_ch_data[order][index].value & 1ULL << pos) != 0; + + return lbp; +} + +int LogicSnapshot::get_ch_order(int sig_index) +{ + uint16_t order = 0; + for (auto& iter:_ch_index) { + if (iter == sig_index) + break; + order++; + } + + if (order >= _ch_index.size()) + return -1; + else + return order; } } // namespace data diff --git a/DSView/pv/data/logicsnapshot.h b/DSView/pv/data/logicsnapshot.h index d1f70635..10656051 100644 --- a/DSView/pv/data/logicsnapshot.h +++ b/DSView/pv/data/logicsnapshot.h @@ -26,6 +26,8 @@ #include "snapshot.h" +#include + #include #include @@ -43,19 +45,30 @@ namespace data { class LogicSnapshot : public Snapshot { private: - struct MipMapLevel - { - uint64_t length; - uint64_t data_length; - void *data; - }; + static const int ScaleLevel = 4; + static const int ScalePower = 6; + static const uint64_t Scale = 1 << ScalePower; + static const int ScaleSize = Scale / 8; + static const int RootScalePower = ScalePower; + static const uint64_t RootScale = 1 << RootScalePower; + static const uint64_t LeafBlockSpace = (Scale + Scale*Scale + + Scale*Scale*Scale + Scale*Scale*Scale*Scale) / 8; + static const uint64_t LeafBlockSamples = 1 << ScaleLevel*ScalePower; + static const uint64_t LeafBlockPower = ScaleLevel*ScalePower; + static const uint64_t RootNodeSamples = LeafBlockSamples*RootScale; + + static const uint64_t RootMask = ~(~0ULL << RootScalePower) << ScaleLevel*ScalePower; + static const uint64_t LeafMask = ~(~0ULL << ScaleLevel*ScalePower); + static const uint64_t LevelMask[ScaleLevel]; + static const uint64_t LevelOffset[ScaleLevel]; private: - static const unsigned int ScaleStepCount = 10; - static const int MipMapScalePower; - static const int MipMapScaleFactor; - static const float LogMipMapScaleFactor; - static const uint64_t MipMapDataUnit; + struct RootNode + { + uint64_t tog; + uint64_t value; + void *lbp[Scale]; + }; public: typedef std::pair EdgePair; @@ -64,50 +77,116 @@ public: LogicSnapshot(); virtual ~LogicSnapshot(); - + void free_data(); void clear(); void init(); - void first_payload(const sr_datafeed_logic &logic, uint64_t total_sample_count, unsigned int channel_num); + void first_payload(const sr_datafeed_logic &logic, uint64_t total_sample_count, GSList *channels); void append_payload(const sr_datafeed_logic &logic); - uint8_t * get_samples(int64_t start_sample, int64_t end_sample) const; + const uint8_t * get_samples(uint64_t start_sample, uint64_t& end_sample, int sig_index); -private: - void free_mipmap(); - void reallocate_mipmap_level(MipMapLevel &m); - void append_payload_to_mipmap(); + bool get_sample(uint64_t index, int sig_index); -public: - /** - * Parses a logic data snapshot to generate a list of transitions - * in a time interval to a given level of detail. - * @param[out] edges The vector to place the edges into. - * @param[in] start The start sample index. - * @param[in] end The end sample index. - * @param[in] min_length The minimum number of samples that - * can be resolved at this level of detail. - * @param[in] sig_index The index of the signal. - **/ - void get_subsampled_edges(std::vector &edges, - uint64_t start, uint64_t end, - float min_length, int sig_index); + void capture_ended(); + + bool get_display_edges(std::vector> &edges, + std::vector> &togs, + uint64_t start, uint64_t end, uint16_t width, + uint16_t max_togs, double pixels_offset, + double min_length, uint16_t sig_index); bool get_nxt_edge(uint64_t &index, bool last_sample, uint64_t end, - float min_length, int sig_index); + double min_length, int sig_index); bool get_pre_edge(uint64_t &index, bool last_sample, - float min_length, int sig_index); + double min_length, int sig_index); + + bool has_data(int sig_index); + int get_block_num(); + uint64_t get_block_size(int block_index); + uint8_t *get_block_buf(int block_index, int sig_index, bool &sample); + + bool pattern_search(int64_t start, int64_t end, bool nxt, int64_t& index, + std::map pattern); private: - uint64_t get_subsample(int level, uint64_t offset) const; + int get_ch_order(int sig_index); + void calc_mipmap(unsigned int order, uint8_t index0, uint8_t index1, uint64_t samples); - static uint64_t pow2_ceil(uint64_t x, unsigned int power); + void append_cross_payload(const sr_datafeed_logic &logic); + void append_split_payload(const sr_datafeed_logic &logic); + + bool block_nxt_edge(uint64_t *lbp, uint64_t &index, uint64_t block_end, bool last_sample, + unsigned int min_level); + + bool block_pre_edge(uint64_t *lbp, uint64_t &index, bool last_sample, + unsigned int min_level, int sig_index); + + inline uint64_t bsf_folded (uint64_t bb) + { + static const int lsb_64_table[64] = { + 63, 30, 3, 32, 59, 14, 11, 33, + 60, 24, 50, 9, 55, 19, 21, 34, + 61, 29, 2, 53, 51, 23, 41, 18, + 56, 28, 1, 43, 46, 27, 0, 35, + 62, 31, 58, 4, 5, 49, 54, 6, + 15, 52, 12, 40, 7, 42, 45, 16, + 25, 57, 48, 13, 10, 39, 8, 44, + 20, 47, 38, 22, 17, 37, 36, 26 + }; + unsigned int folded; + bb ^= bb - 1; + folded = (int) bb ^ (bb >> 32); + return lsb_64_table[folded * 0x78291ACF >> 26]; + } + + inline int bsr32(uint32_t bb) + { + static const char msb_256_table[256] = { + 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4,4, 4, 4, 4,4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + }; + int result = 0; + + if (bb > 0xFFFF) { + bb >>= 16; + result += 16; + } + if (bb > 0xFF) { + bb >>= 8; + result += 8; + } + + return (result + msb_256_table[bb]); + } + + inline uint64_t bsr64(uint64_t bb) + { + const uint32_t hb = bb >> 32; + return hb ? 32 + bsr32((uint32_t)hb) : bsr32((uint32_t)bb); + } private: - struct MipMapLevel _mip_map[ScaleStepCount]; - uint64_t _last_append_sample; + std::vector> _ch_data; + uint64_t _block_num; + uint8_t _byte_fraction; + uint16_t _ch_fraction; + void *_src_ptr; + void *_dest_ptr; + + std::vector _sample_cnt; + std::vector _block_cnt; + std::vector _ring_sample_cnt; + std::vector _last_sample; friend class LogicSnapshotTest::Pow2; friend class LogicSnapshotTest::Basic; diff --git a/DSView/pv/data/mathstack.cpp b/DSView/pv/data/mathstack.cpp index 0bec7874..9f76cb8a 100644 --- a/DSView/pv/data/mathstack.cpp +++ b/DSView/pv/data/mathstack.cpp @@ -157,12 +157,13 @@ const std::vector MathStack::get_fft_spectrum() const return empty; } -const double MathStack::get_fft_spectrum(uint64_t index) const +double MathStack::get_fft_spectrum(uint64_t index) { + double ret = -1; if (_math_state == Stopped && index < _power_spectrum.size()) - return _power_spectrum[index]; - else - return -1; + ret = _power_spectrum[index]; + + return ret; } void MathStack::calc_fft() @@ -193,14 +194,13 @@ void MathStack::calc_fft() if (_snapshot->get_sample_count() < _sample_num*_sample_interval) return; - // Get the samplerate and start time - _start_time = data->get_start_time(); + // Get the samplerate _samplerate = data->samplerate(); if (_samplerate == 0.0) _samplerate = 1.0; // prepare _xn data - const double offset = dsoSig->get_zero_value(); + const double offset = dsoSig->get_hw_offset(); const double vscale = dsoSig->get_vDialValue() * dsoSig->get_factor() * DS_CONF_DSO_VDIVS / (1000*255.0); const uint16_t step = _snapshot->get_channel_num() * _sample_interval; const uint8_t *const samples = _snapshot->get_samples(0, _sample_num*_sample_interval-1, _index); diff --git a/DSView/pv/data/mathstack.h b/DSView/pv/data/mathstack.h index d9e32423..88c5fca3 100644 --- a/DSView/pv/data/mathstack.h +++ b/DSView/pv/data/mathstack.h @@ -86,7 +86,7 @@ public: void set_sample_interval(int interval); const std::vector get_fft_spectrum() const; - const double get_fft_spectrum(uint64_t index) const; + double get_fft_spectrum(uint64_t index); void calc_fft(); diff --git a/DSView/pv/data/signaldata.cpp b/DSView/pv/data/signaldata.cpp index 00c7e5ef..a4cd3af3 100644 --- a/DSView/pv/data/signaldata.cpp +++ b/DSView/pv/data/signaldata.cpp @@ -28,8 +28,7 @@ namespace pv { namespace data { SignalData::SignalData() : - _samplerate(0), - _start_time(0) + _samplerate(0) { } @@ -44,10 +43,5 @@ void SignalData::set_samplerate(double samplerate) _samplerate = samplerate; } -double SignalData::get_start_time() const -{ - return _start_time; -} - } // namespace data } // namespace pv diff --git a/DSView/pv/data/signaldata.h b/DSView/pv/data/signaldata.h index 7f96312e..c74898d1 100644 --- a/DSView/pv/data/signaldata.h +++ b/DSView/pv/data/signaldata.h @@ -42,11 +42,8 @@ public: virtual void init() = 0; - double get_start_time() const; - protected: double _samplerate; - double _start_time; }; } // namespace data diff --git a/DSView/pv/data/snapshot.cpp b/DSView/pv/data/snapshot.cpp index df2c8011..d49fac6e 100644 --- a/DSView/pv/data/snapshot.cpp +++ b/DSView/pv/data/snapshot.cpp @@ -59,7 +59,9 @@ void Snapshot::free_data() free(_data); _data = NULL; _capacity = 0; + _sample_count = 0; } + _ch_index.clear(); } bool Snapshot::memory_failed() const @@ -69,7 +71,7 @@ bool Snapshot::memory_failed() const bool Snapshot::empty() const { - if (get_sample_count() == 0 || _memory_failed || !_data) + if (get_sample_count() == 0) return true; else return false; @@ -106,46 +108,9 @@ unsigned int Snapshot::get_channel_num() const return _channel_num; } -uint64_t Snapshot::get_sample(uint64_t index) const +void Snapshot::capture_ended() { - assert(_data); - assert(index < get_sample_count()); - - return *(uint64_t*)((uint8_t*)_data + index * _unit_size); -} - -void Snapshot::append_data(void *data, uint64_t samples) -{ -// _data = realloc(_data, (_sample_count + samples) * _unit_size + -// sizeof(uint64_t)); - if (_sample_count + samples < _total_sample_count) - _sample_count += samples; - else - _sample_count = _total_sample_count; - - if (_ring_sample_count + samples > _total_sample_count) { - memcpy((uint8_t*)_data + _ring_sample_count * _unit_size, - data, (_total_sample_count - _ring_sample_count) * _unit_size); - _ring_sample_count = (samples + _ring_sample_count - _total_sample_count) % _total_sample_count; - memcpy((uint8_t*)_data, - data, _ring_sample_count * _unit_size); - } else { - memcpy((uint8_t*)_data + _ring_sample_count * _unit_size, - data, samples * _unit_size); - _ring_sample_count += samples; - } -} - -void Snapshot::refill_data(void *data, uint64_t samples, bool instant) -{ - if (instant) { - memcpy((uint8_t*)_data + _sample_count * _channel_num, data, samples*_channel_num); - _sample_count = (_sample_count + samples) % (_total_sample_count + 1); - } else { - memcpy((uint8_t*)_data, data, samples*_channel_num); - _sample_count = samples; - } - + set_last_ended(true); } } // namespace data diff --git a/DSView/pv/data/snapshot.h b/DSView/pv/data/snapshot.h index 5fa3e440..36b935af 100644 --- a/DSView/pv/data/snapshot.h +++ b/DSView/pv/data/snapshot.h @@ -55,17 +55,18 @@ public: unsigned int get_channel_num() const; - uint64_t get_sample(uint64_t index) const; + virtual void capture_ended(); protected: - void append_data(void *data, uint64_t samples); - void refill_data(void *data, uint64_t samples, bool instant); - void free_data(); + virtual void free_data(); protected: mutable boost::recursive_mutex _mutex; + //std::vector _data; void* _data; + std::vector _ch_index; + uint64_t _capacity; unsigned int _channel_num; uint64_t _sample_count; diff --git a/DSView/pv/device/device.cpp b/DSView/pv/device/device.cpp index 74b021f8..56870acf 100644 --- a/DSView/pv/device/device.cpp +++ b/DSView/pv/device/device.cpp @@ -32,7 +32,7 @@ namespace pv { namespace device { Device::Device(sr_dev_inst *sdi) : - _sdi(sdi) + _sdi(sdi) { assert(_sdi); } @@ -50,6 +50,7 @@ void Device::use(SigSession *owner) throw(QString) 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.")); } diff --git a/DSView/pv/device/device.h b/DSView/pv/device/device.h index 435bb4bd..a98ffc0d 100644 --- a/DSView/pv/device/device.h +++ b/DSView/pv/device/device.h @@ -34,7 +34,7 @@ public: sr_dev_inst* dev_inst() const; - void use(SigSession *owner) throw(QString); + void use(SigSession *owner) throw(QString); void release(); diff --git a/DSView/pv/device/devinst.cpp b/DSView/pv/device/devinst.cpp index 347ce869..652c548e 100644 --- a/DSView/pv/device/devinst.cpp +++ b/DSView/pv/device/devinst.cpp @@ -33,7 +33,8 @@ namespace pv { namespace device { DevInst::DevInst() : - _owner(NULL) + _owner(NULL), + _usable(true) { _id = malloc(1); } @@ -82,7 +83,7 @@ GVariant* DevInst::get_config(const sr_channel *ch, const sr_channel_group *grou return data; } -bool DevInst::set_config(const sr_channel *ch, const sr_channel_group *group, int key, GVariant *data) +bool DevInst::set_config(sr_channel *ch, sr_channel_group *group, int key, GVariant *data) { assert(_owner); sr_dev_inst *const sdi = dev_inst(); @@ -206,5 +207,10 @@ void DevInst::run() sr_session_run(); } +bool DevInst::is_usable() const +{ + return _usable; +} + } // device } // pv diff --git a/DSView/pv/device/devinst.h b/DSView/pv/device/devinst.h index dec1b525..b45f515e 100644 --- a/DSView/pv/device/devinst.h +++ b/DSView/pv/device/devinst.h @@ -63,7 +63,7 @@ public: GVariant* get_config(const sr_channel *ch, const sr_channel_group *group, int key); - bool set_config(const sr_channel *ch, const sr_channel_group *group, int key, GVariant *data); + bool set_config(sr_channel *ch, sr_channel_group *group, int key, GVariant *data); GVariant* list_config(const sr_channel_group *group, int key); @@ -118,6 +118,8 @@ public: virtual bool is_trigger_enabled() const; + bool is_usable() const; + public: virtual void start(); @@ -132,6 +134,7 @@ signals: protected: SigSession *_owner; void *_id; + bool _usable; }; } // device diff --git a/DSView/pv/device/file.cpp b/DSView/pv/device/file.cpp index fdc1bd15..d0de5e0c 100644 --- a/DSView/pv/device/file.cpp +++ b/DSView/pv/device/file.cpp @@ -25,6 +25,8 @@ #include +#include + #include #include @@ -63,7 +65,37 @@ File* File::create(QString name) } } - return new InputFile(name); + return new InputFile(name); +} + +QJsonArray File::get_decoders() +{ + struct zip *archive; + struct zip_file *zf; + struct zip_stat zs; + int ret; + char *dec_file; + QJsonArray dec_array; + QJsonParseError error; + + archive = zip_open(_path.toLocal8Bit().data(), 0, &ret); + if (archive) { + /* read "decoders" */ + if (zip_stat(archive, "decoders", 0, &zs) != -1) { + dec_file = (char *)g_try_malloc(zs.size); + if (dec_file) { + zf = zip_fopen_index(archive, zs.index, 0); + zip_fread(zf, dec_file, zs.size); + zip_fclose(zf); + + //QString sessionData = QString::fromUtf8(dec_file); + QJsonDocument sessionDoc = QJsonDocument::fromJson(QByteArray::fromRawData(dec_file, zs.size), &error); + dec_array = sessionDoc.array(); + } + } + } + + return dec_array; } } // device diff --git a/DSView/pv/device/file.h b/DSView/pv/device/file.h index 89a7ddf3..000b950b 100644 --- a/DSView/pv/device/file.h +++ b/DSView/pv/device/file.h @@ -24,6 +24,9 @@ #include +#include +#include + #include "devinst.h" namespace pv { @@ -37,6 +40,8 @@ protected: public: static File* create(QString name); + QJsonArray get_decoders(); + public: QString format_device_title() const; diff --git a/DSView/pv/device/inputfile.cpp b/DSView/pv/device/inputfile.cpp index 967d6f7b..69de8f80 100644 --- a/DSView/pv/device/inputfile.cpp +++ b/DSView/pv/device/inputfile.cpp @@ -48,15 +48,21 @@ sr_dev_inst* InputFile::dev_inst() const void InputFile::use(SigSession *owner) throw(QString) { + (void)owner; assert(!_input); - _input = load_input_file_format(_path, NULL); - File::use(owner); + // only *.dsl file is valid + // don't allow other types of file input + throw tr("Not a valid DSView data file."); + return; - sr_session_new(); +// _input = load_input_file_format(_path, NULL); +// File::use(owner); - if (sr_session_dev_add(_input->sdi) != SR_OK) - throw tr("Failed to add session device."); +// sr_session_new(); + +// if (sr_session_dev_add(_input->sdi) != SR_OK) +// throw tr("Failed to add session device."); } void InputFile::release() @@ -78,7 +84,7 @@ sr_input_format* InputFile::determine_input_file_format(const QString filename) /* If there are no input formats, return NULL right away. */ sr_input_format *const *const inputs = sr_input_list(); if (!inputs) { - g_critical("No supported input formats available."); + g_critical("No supported input formats available."); return NULL; } @@ -90,7 +96,7 @@ sr_input_format* InputFile::determine_input_file_format(const QString filename) /* Return NULL if no input module wanted to touch this. */ if (!inputs[i]) { - g_critical("Error: no matching input module found."); + g_critical("Error: no matching input module found."); return NULL; } diff --git a/DSView/pv/device/sessionfile.cpp b/DSView/pv/device/sessionfile.cpp index c1902c15..ada63fc3 100644 --- a/DSView/pv/device/sessionfile.cpp +++ b/DSView/pv/device/sessionfile.cpp @@ -21,7 +21,7 @@ #include "sessionfile.h" -#include +#include namespace pv { namespace device { diff --git a/DSView/pv/dialogs/calibration.cpp b/DSView/pv/dialogs/calibration.cpp index f9e7995e..32d754ad 100755 --- a/DSView/pv/dialogs/calibration.cpp +++ b/DSView/pv/dialogs/calibration.cpp @@ -45,6 +45,10 @@ const QString Calibration::VOFF = QT_TR_NOOP(" VOFF"); Calibration::Calibration(QWidget *parent) : DSDialog(parent) { +#ifdef Q_OS_OSX + Qt::WindowFlags flags = windowFlags(); + this->setWindowFlags(flags | Qt::Tool); +#endif this->setFixedSize(400, 250); this->setWindowOpacity(0.7); this->setModal(false); @@ -125,7 +129,7 @@ void Calibration::set_device(boost::shared_ptr dev_inst) gain_slider->setRange(-vgain_range/2, vgain_range/2); gain_slider->setValue(vgain - vgain_default); gain_slider->setObjectName(VGAIN+probe->index); - QString gain_string = "Channel" + QString::number(probe->index) + VGAIN; + QString gain_string = tr("Channel") + QString::number(probe->index) + VGAIN; QLabel *gain_label = new QLabel(gain_string, this); _flayout->addRow(gain_label, gain_slider); _slider_list.push_back(gain_slider); @@ -147,7 +151,7 @@ void Calibration::set_device(boost::shared_ptr dev_inst) off_slider->setRange(0, voff_range); off_slider->setValue(voff); off_slider->setObjectName(VOFF+probe->index); - QString off_string = "Channel" + QString::number(probe->index) + VOFF; + QString off_string = tr("Channel") + QString::number(probe->index) + VOFF; QLabel *off_label = new QLabel(off_string, this); _flayout->addRow(off_label, off_slider); _slider_list.push_back(off_slider); @@ -213,7 +217,8 @@ void Calibration::on_save() QProgressDialog dlg(tr("Save Calibration Result... It can take a while."), tr("Cancel"),0,0,this,flags); dlg.setWindowModality(Qt::WindowModal); - dlg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint); + dlg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | + Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint); dlg.setCancelButton(NULL); QFutureWatcher watcher; @@ -239,7 +244,8 @@ void Calibration::on_reset() QProgressDialog dlg(tr("Reset Calibration Result... It can take a while."), tr("Cancel"),0,0,this,flags); dlg.setWindowModality(Qt::WindowModal); - dlg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint); + dlg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | + Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint); dlg.setCancelButton(NULL); QFutureWatcher watcher; diff --git a/DSView/pv/dialogs/deviceoptions.cpp b/DSView/pv/dialogs/deviceoptions.cpp index 74f8f557..0824716d 100644 --- a/DSView/pv/dialogs/deviceoptions.cpp +++ b/DSView/pv/dialogs/deviceoptions.cpp @@ -54,7 +54,7 @@ DeviceOptions::DeviceOptions(QWidget *parent, boost::shared_ptrsetLayout(&_probes_box_layout); _layout.addWidget(_probes_box); } else if (_dev_inst->name().contains("DSCope")){ - _config_button = new QPushButton(tr("Zero Adjustment"), this); + _config_button = new QPushButton(tr("Auto Calibration"), this); _layout.addWidget(_config_button); connect(_config_button, SIGNAL(clicked()), this, SLOT(zero_adj())); @@ -86,8 +86,7 @@ DeviceOptions::DeviceOptions(QWidget *parent, boost::shared_ptr > &properties = @@ -103,10 +102,24 @@ void DeviceOptions::accept() for (const GSList *l = _dev_inst->dev_inst()->channels; l; l = l->next) { sr_channel *const probe = (sr_channel*)l->data; assert(probe); - probe->enabled = (_probes_checkBox_list.at(index)->checkState() == Qt::Checked); index++; + if (probe->enabled) + hasEnabled = true; } + } else { + hasEnabled = true; + } + + if (hasEnabled) { + QDialog::accept(); + } else { + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("Attention")); + msg.mBox()->setInformativeText(tr("All channel disabled! Please enable at least one channel.")); + msg.mBox()->addButton(tr("Ok"), QMessageBox::AcceptRole); + msg.mBox()->setIcon(QMessageBox::Warning); + msg.exec(); } } @@ -147,6 +160,8 @@ void DeviceOptions::setup_probes() int row0 = 0, row1 = 0, col = 0; int index = 0; QString ch_mode; + int vld_ch_num = 0; + int cur_ch_num = 0; while(_probes_box_layout.count() > 0) { @@ -182,10 +197,22 @@ void DeviceOptions::setup_probes() } } + GVariant *gvar = _dev_inst->get_config(NULL, NULL, SR_CONF_VLD_CH_NUM); + if (gvar != NULL) { + vld_ch_num = g_variant_get_int16(gvar); + g_variant_unref(gvar); + } + for (const GSList *l = _dev_inst->dev_inst()->channels; l; l = l->next) { sr_channel *const probe = (sr_channel*)l->data; assert(probe); + if (probe->enabled) + cur_ch_num++; + + if (cur_ch_num > vld_ch_num) + probe->enabled = false; + QLabel *probe_label = new QLabel(QString::number(probe->index), this); QCheckBox *probe_checkBox = new QCheckBox(this); probe_checkBox->setCheckState(probe->enabled ? Qt::Checked : Qt::Unchecked); @@ -197,6 +224,8 @@ void DeviceOptions::setup_probes() index++; col = index % 8; row1 = index / 8; + + connect(probe_checkBox, SIGNAL(released()), this, SLOT(channel_enable())); } QPushButton *_enable_all_probes = new QPushButton(tr("Enable All"), this); @@ -220,8 +249,45 @@ void DeviceOptions::set_all_probes(bool set) } } +void DeviceOptions::enable_max_probes() { + int cur_ch_num = 0; + QVector::iterator iter = _probes_checkBox_list.begin(); + while(iter != _probes_checkBox_list.end()) { + if ((*iter)->isChecked()) + cur_ch_num++; + iter++; + } + + GVariant* gvar = _dev_inst->get_config(NULL, NULL, SR_CONF_VLD_CH_NUM); + if (gvar == NULL) + return; + + int vld_ch_num = g_variant_get_int16(gvar); + g_variant_unref(gvar); + iter = _probes_checkBox_list.begin(); + while(cur_ch_num < vld_ch_num && + iter != _probes_checkBox_list.end()) { + if (!(*iter)->isChecked()) { + (*iter)->setChecked(true); + cur_ch_num++; + } + iter++; + } +} + void DeviceOptions::enable_all_probes() { + GVariant* gvar = _dev_inst->get_config(NULL, NULL, SR_CONF_STREAM); + if (gvar != NULL) { + bool stream_mode = g_variant_get_boolean(gvar); + g_variant_unref(gvar); + + if (stream_mode) { + enable_max_probes(); + return; + } + } + set_all_probes(true); } @@ -237,7 +303,7 @@ void DeviceOptions::zero_adj() dialogs::DSMessageBox msg(this); msg.mBox()->setText(tr("Information")); - msg.mBox()->setInformativeText(tr("Zero adjustment program will be started. Please keep all channels out of singal input. It can take a while!")); + msg.mBox()->setInformativeText(tr("Auto Calibration program will be started. Please keep all channels out of singal input. It can take a while!")); //msg.mBox()->setStandardButtons(QMessageBox::); msg.mBox()->addButton(tr("Ok"), QMessageBox::AcceptRole); msg.mBox()->addButton(tr("Cancel"), QMessageBox::RejectRole); @@ -293,5 +359,47 @@ void DeviceOptions::channel_check() setup_probes(); } +void DeviceOptions::channel_enable() +{ + QCheckBox* sc=dynamic_cast(sender()); + if (sc == NULL || !sc->isChecked()) + return; + + GVariant* gvar = _dev_inst->get_config(NULL, NULL, SR_CONF_STREAM); + if (gvar == NULL) + return; + + bool stream_mode = g_variant_get_boolean(gvar); + g_variant_unref(gvar); + + if (!stream_mode) + return; + + int cur_ch_num = 0; + QVector::iterator i = _probes_checkBox_list.begin(); + while(i != _probes_checkBox_list.end()) { + if ((*i)->isChecked()) + cur_ch_num++; + i++; + } + + gvar = _dev_inst->get_config(NULL, NULL, SR_CONF_VLD_CH_NUM); + if (gvar == NULL) + return; + + int vld_ch_num = g_variant_get_int16(gvar); + g_variant_unref(gvar); + if (cur_ch_num > vld_ch_num) { + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("Information")); + msg.mBox()->setInformativeText(tr("Current mode only suppport max ") + QString::number(vld_ch_num) + tr(" channels!")); + msg.mBox()->addButton(tr("Ok"), QMessageBox::AcceptRole); + msg.mBox()->setIcon(QMessageBox::Information); + msg.exec(); + + sc->setChecked(false); + } +} + } // namespace dialogs } // namespace pv diff --git a/DSView/pv/dialogs/deviceoptions.h b/DSView/pv/dialogs/deviceoptions.h index 6de30d94..52b314ae 100644 --- a/DSView/pv/dialogs/deviceoptions.h +++ b/DSView/pv/dialogs/deviceoptions.h @@ -66,6 +66,7 @@ private: void setup_probes(); void set_all_probes(bool set); + void enable_max_probes(); private slots: void enable_all_probes(); @@ -74,6 +75,7 @@ private slots: void mode_check(); void channel_check(); void on_calibration(); + void channel_enable(); private: boost::shared_ptr _dev_inst; diff --git a/DSView/pv/dialogs/dsdialog.cpp b/DSView/pv/dialogs/dsdialog.cpp index 01f4a685..29986d3a 100755 --- a/DSView/pv/dialogs/dsdialog.cpp +++ b/DSView/pv/dialogs/dsdialog.cpp @@ -36,7 +36,8 @@ DSDialog::DSDialog(QWidget *parent, bool hasClose) : QDialog(parent), _moving(false) { - setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog); + setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog | Qt::WindowSystemMenuHint | + Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint); setAttribute(Qt::WA_TranslucentBackground); build_main(hasClose); diff --git a/DSView/pv/dialogs/dsmessagebox.cpp b/DSView/pv/dialogs/dsmessagebox.cpp index 0491ba3d..4ef58fc5 100755 --- a/DSView/pv/dialogs/dsmessagebox.cpp +++ b/DSView/pv/dialogs/dsmessagebox.cpp @@ -36,7 +36,8 @@ DSMessageBox::DSMessageBox(QWidget *parent) : QDialog(parent), _moving(false) { - setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog); + setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog | Qt::WindowSystemMenuHint | + Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint); setAttribute(Qt::WA_TranslucentBackground); _main = new QWidget(this); QVBoxLayout *mlayout = new QVBoxLayout(_main); @@ -50,7 +51,8 @@ DSMessageBox::DSMessageBox(QWidget *parent) : _main->setGraphicsEffect(bodyShadow); _msg = new QMessageBox(this); - _msg->setWindowFlags(Qt::FramelessWindowHint | Qt::Widget); + _msg->setWindowFlags(Qt::FramelessWindowHint | Qt::Widget | Qt::WindowSystemMenuHint | + Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint); _titlebar = new toolbars::TitleBar(false, this); _titlebar->setTitle(tr("Message")); diff --git a/DSView/pv/dialogs/fftoptions.cpp b/DSView/pv/dialogs/fftoptions.cpp index d1df974f..6c928a0f 100644 --- a/DSView/pv/dialogs/fftoptions.cpp +++ b/DSView/pv/dialogs/fftoptions.cpp @@ -224,7 +224,7 @@ void FftOptions::accept() mathTrace->get_math_stack()->set_sample_num(_len_combobox->currentData().toULongLong()); mathTrace->get_math_stack()->set_sample_interval(_interval_combobox->currentData().toInt()); mathTrace->get_math_stack()->set_windows_index(_window_combobox->currentData().toInt()); - mathTrace->set_view_mode(_view_combobox->currentData().toInt()); + mathTrace->set_view_mode(_view_combobox->currentData().toUInt()); //mathTrace->init_zoom(); mathTrace->set_dbv_range(_dbv_combobox->currentData().toInt()); mathTrace->set_enable(_en_checkbox->isChecked()); diff --git a/DSView/pv/dialogs/interval.cpp b/DSView/pv/dialogs/interval.cpp new file mode 100755 index 00000000..e2ff752b --- /dev/null +++ b/DSView/pv/dialogs/interval.cpp @@ -0,0 +1,75 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2016 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 "interval.h" + +#include + +namespace pv { +namespace dialogs { + +Interval::Interval(SigSession &session, QWidget *parent) : + DSDialog(parent), + _session(session), + _button_box(QDialogButtonBox::Ok, + Qt::Horizontal, this) +{ + setMinimumWidth(300); + _interval_label = new QLabel(tr("Interval(s): "), this); + _interval_spinBox = new QSpinBox(this); + _interval_spinBox->setRange(1, 10); + _interval_spinBox->setButtonSymbols(QAbstractSpinBox::NoButtons); + _interval_slider = new QSlider(Qt::Horizontal, this); + _interval_slider->setRange(1, 10); + 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()); + + QGridLayout *glayout = new QGridLayout(this); + glayout->addWidget(_interval_label, 0, 0); + glayout->addWidget(_interval_spinBox, 0, 1); + glayout->addWidget(_interval_slider, 1, 0, 1, 3); + glayout->addWidget(&_button_box, 2, 2); + + layout()->addLayout(glayout); + setTitle(tr("Repetitive Interval")); + + connect(&_button_box, SIGNAL(accepted()), this, SLOT(accept())); +} + +void Interval::accept() +{ + using namespace Qt; + _session.set_repeat_intvl(_interval_slider->value()); + QDialog::accept(); +} + +void Interval::reject() +{ + using namespace Qt; + + QDialog::reject(); +} + + +} // namespace dialogs +} // namespace pv diff --git a/DSView/pv/dialogs/interval.h b/DSView/pv/dialogs/interval.h new file mode 100755 index 00000000..86e42ade --- /dev/null +++ b/DSView/pv/dialogs/interval.h @@ -0,0 +1,62 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2016 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 DSVIEW_PV_INTERVAL_H +#define DSVIEW_PV_INTERVAL_H + +#include +#include +#include +#include + +#include "../sigsession.h" +#include "../toolbars/titlebar.h" +#include "dsdialog.h" + +namespace pv { +namespace dialogs { + +class Interval : public DSDialog +{ + Q_OBJECT + +public: + Interval(SigSession &session, QWidget *parent); + +protected: + void accept(); + void reject(); + +private: + SigSession &_session; + + QLabel *_interval_label; + QSpinBox *_interval_spinBox; + QSlider *_interval_slider; + + QDialogButtonBox _button_box; +}; + +} // namespace dialogs +} // namespace pv + +#endif // DSVIEW_PV_INTERVAL_H diff --git a/DSView/pv/dialogs/protocolexp.cpp b/DSView/pv/dialogs/protocolexp.cpp index 11f24355..860138e2 100644 --- a/DSView/pv/dialogs/protocolexp.cpp +++ b/DSView/pv/dialogs/protocolexp.cpp @@ -152,7 +152,7 @@ void ProtocolExp::accept() break; } } - out << QString("%1;%2;%3\n") + out << QString("%1,%2,%3\n") .arg("ID") .arg("Time[s]") .arg(title); @@ -180,7 +180,7 @@ void ProtocolExp::accept() 0, decoder_stack->sample_count()-1); if (!annotations.empty()) { BOOST_FOREACH(const Annotation &a, annotations) { - out << QString("%1;%2;%3\n") + out << QString("%1,%2,%3\n") .arg(QString::number(exported)) .arg(QString::number(a.start_sample()*time_pre_samples)) .arg(a.annotations().at(0)); @@ -195,7 +195,8 @@ void ProtocolExp::accept() QProgressDialog dlg(tr("Export Protocol List Result... It can take a while."), tr("Cancel"),0,100,this,flags); dlg.setWindowModality(Qt::WindowModal); - dlg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint); + dlg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | + Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint); QFutureWatcher watcher; connect(&watcher,SIGNAL(finished()),&dlg,SLOT(cancel())); diff --git a/DSView/pv/dialogs/protocollist.cpp b/DSView/pv/dialogs/protocollist.cpp index fbc51379..78fa327c 100644 --- a/DSView/pv/dialogs/protocollist.cpp +++ b/DSView/pv/dialogs/protocollist.cpp @@ -47,6 +47,15 @@ ProtocolList::ProtocolList(QWidget *parent, SigSession &session) : { 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(); + 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))); _protocol_combobox = new QComboBox(this); const std::vector< boost::shared_ptr > decode_sigs( @@ -67,6 +76,7 @@ ProtocolList::ProtocolList(QWidget *parent, SigSession &session) : _flayout->setFormAlignment(Qt::AlignLeft); _flayout->setLabelAlignment(Qt::AlignLeft); _flayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); + _flayout->addRow(new QLabel(tr("Map Zoom: "), this), _map_zoom_combobox); _flayout->addRow(new QLabel(tr("Decoded Protocols: "), this), _protocol_combobox); _layout = new QVBoxLayout(); @@ -185,6 +195,5 @@ void ProtocolList::on_row_check(bool show) _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 8c4524fd..bc6a9891 100644 --- a/DSView/pv/dialogs/protocollist.h +++ b/DSView/pv/dialogs/protocollist.h @@ -62,6 +62,7 @@ private: SigSession &_session; toolbars::TitleBar *_titlebar; + QComboBox *_map_zoom_combobox; QComboBox *_protocol_combobox; std::list _show_checkbox_list; std::list _show_label_list; diff --git a/DSView/pv/dialogs/search.cpp b/DSView/pv/dialogs/search.cpp index 1469df78..cede9607 100644 --- a/DSView/pv/dialogs/search.cpp +++ b/DSView/pv/dialogs/search.cpp @@ -21,53 +21,73 @@ #include "search.h" +#include "../view/logicsignal.h" + #include #include +#include + namespace pv { namespace dialogs { -Search::Search(QWidget *parent, boost::shared_ptr dev_inst, QString pattern) : +Search::Search(QWidget *parent, SigSession &session, std::map pattern) : DSDialog(parent), - _dev_inst(dev_inst) + _session(session) { - assert(_dev_inst); QFont font("Monaco"); font.setStyleHint(QFont::Monospace); font.setFixedPitch(true); + //this->setMinimumWidth(350); - QRegExp value_rx("[10XRFCxrfc ]+"); + QRegExp value_rx("[10XRFCxrfc]+"); QValidator *value_validator = new QRegExpValidator(value_rx, this); - - search_lineEdit.setText(pattern); - search_lineEdit.setValidator(value_validator); - search_lineEdit.setMaxLength(16 * 2 - 1); - search_lineEdit.setInputMask("X X X X X X X X X X X X X X X X"); - search_lineEdit.setFont(font); - - QLabel *search_label = new QLabel("1 1 1 1 1 1\n5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0"); - search_label->setFont(font); - search_buttonBox.addButton(QDialogButtonBox::Ok); search_buttonBox.addButton(QDialogButtonBox::Cancel); QGridLayout *search_layout = new QGridLayout(); - search_layout->setVerticalSpacing(5); - search_layout->addWidget(search_label, 1, 1); - search_layout->addWidget(new QLabel(tr("Search Value: ")), 2,0, Qt::AlignRight); - search_layout->addWidget(&search_lineEdit, 2, 1); - search_layout->addWidget(new QLabel(" "), 3,0); - search_layout->addWidget(new QLabel(tr("X: Don't care\n0: Low level\n1: High level\nR: Rising edge\nF: Falling edge\nC: Rising/Falling edge")), 4, 0); - search_layout->addWidget(&search_buttonBox, 5, 2); + search_layout->setVerticalSpacing(0); + + int index = 0; + BOOST_FOREACH(const boost::shared_ptr sig, + _session.get_signals()) { + assert(sig); + boost::shared_ptr logic_sig; + if (logic_sig = boost::dynamic_pointer_cast(sig)) { + QLineEdit *search_lineEdit = new QLineEdit(this); + if (pattern.find(index) != pattern.end()) + search_lineEdit->setText(pattern[index]); + else + search_lineEdit->setText("X"); + search_lineEdit->setValidator(value_validator); + search_lineEdit->setMaxLength(1); + search_lineEdit->setInputMask("X"); + search_lineEdit->setFont(font); + _search_lineEdit_vec.push_back(search_lineEdit); + + search_layout->addWidget(new QLabel(logic_sig->get_name()+":"), index, 0, Qt::AlignRight); + search_layout->addWidget(new QLabel(QString::number(logic_sig->get_index())), index, 1, Qt::AlignRight); + search_layout->addWidget(search_lineEdit, index, 2); + + connect(search_lineEdit, SIGNAL(editingFinished()), this, SLOT(format())); + + index++; + } + } + + search_layout->addWidget(new QLabel(" "), index,0); + search_layout->addWidget(new QLabel(tr("X: Don't care\n0: Low level\n1: High level\nR: Rising edge\nF: Falling edge\nC: Rising/Falling edge")), 0, 3, index, 1); + search_layout->addWidget(&search_buttonBox, index+1, 3); + search_layout->setColumnStretch(3, 100); layout()->addLayout(search_layout); setTitle(tr("Search Options")); connect(&search_buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(&search_buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - connect(_dev_inst.get(), SIGNAL(device_updated()), this, SLOT(reject())); + connect(_session.get_device().get(), SIGNAL(device_updated()), this, SLOT(reject())); } Search::~Search() @@ -81,10 +101,27 @@ void Search::accept() QDialog::accept(); } -QString Search::get_pattern() +void Search::format() { - QString pattern = search_lineEdit.text(); - //pattern.remove(QChar('/r'), Qt::CaseInsensitive); + QLineEdit *sc = qobject_cast(sender()); + sc->setText(sc->text().toUpper()); +} + +std::map Search::get_pattern() +{ + std::map pattern; + + int index = 0; + BOOST_FOREACH(const boost::shared_ptr sig, + _session.get_signals()) { + assert(sig); + boost::shared_ptr logic_sig; + if (logic_sig = boost::dynamic_pointer_cast(sig)) { + pattern[index] = _search_lineEdit_vec[index]->text(); + index++; + } + } + return pattern; } diff --git a/DSView/pv/dialogs/search.h b/DSView/pv/dialogs/search.h index 7a9d15ac..f4105fb6 100644 --- a/DSView/pv/dialogs/search.h +++ b/DSView/pv/dialogs/search.h @@ -45,23 +45,25 @@ class Search : public DSDialog public: - Search(QWidget *parent = 0, boost::shared_ptr dev_inst = 0, QString pattern = ""); + Search(QWidget *parent, SigSession &session, std::map pattern); ~Search(); - QString get_pattern(); + std::map get_pattern(); protected: void accept(); signals: -public slots: +private slots: + void format(); private: + SigSession &_session; + toolbars::TitleBar *_titlebar; - QLineEdit search_lineEdit; + QVector _search_lineEdit_vec; QDialogButtonBox search_buttonBox; - boost::shared_ptr _dev_inst; }; } // namespace decoder diff --git a/DSView/pv/dialogs/storeprogress.cpp b/DSView/pv/dialogs/storeprogress.cpp index cbd57200..aa2f2916 100644 --- a/DSView/pv/dialogs/storeprogress.cpp +++ b/DSView/pv/dialogs/storeprogress.cpp @@ -2,6 +2,7 @@ * This file is part of the PulseView project. * * Copyright (C) 2014 Joel Holdsworth + * Copyright (C) 2016 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 @@ -21,62 +22,113 @@ #include "storeprogress.h" #include "dsmessagebox.h" +#include "QVBoxLayout" + namespace pv { namespace dialogs { -StoreProgress::StoreProgress(const QString &file_name, - SigSession &session, QWidget *parent) : - QProgressDialog(tr("Saving..."), tr("Cancel"), 0, 0, parent), - _session(file_name.toStdString(), session) +StoreProgress::StoreProgress(SigSession &session, QWidget *parent) : + DSDialog(parent), + _store_session(session), + _button_box(QDialogButtonBox::Cancel, Qt::Horizontal, this), + _done(false) { - connect(&_session, SIGNAL(progress_updated()), - this, SLOT(on_progress_updated())); + this->setModal(true); + + _info.setText("..."); + _progress.setValue(0); + _progress.setMaximum(0); + + QVBoxLayout* add_layout = new QVBoxLayout(this); + add_layout->addWidget(&_info, 0, Qt::AlignCenter); + add_layout->addWidget(&_progress); + add_layout->addWidget(&_button_box); + layout()->addLayout(add_layout); + + connect(&_button_box, SIGNAL(rejected()), this, SLOT(reject())); + connect(&_store_session, SIGNAL(progress_updated()), + this, SLOT(on_progress_updated()), Qt::QueuedConnection); } StoreProgress::~StoreProgress() { - _session.wait(); + _store_session.wait(); } -void StoreProgress::run() +void StoreProgress::reject() { - if (_session.start()) - show(); - else + using namespace Qt; + _store_session.cancel(); + QDialog::reject(); +} + +void StoreProgress::timeout() +{ + if (_done) + close(); + else + QTimer::singleShot(100, this, SLOT(timeout())); +} + +void StoreProgress::save_run() +{ + _info.setText("Saving..."); + if (_store_session.save_start()) + show(); + else show_error(); + + QTimer::singleShot(100, this, SLOT(timeout())); +} + +void StoreProgress::export_run() +{ + _info.setText("Exporting..."); + if (_store_session.export_start()) + show(); + else + show_error(); + + QTimer::singleShot(100, this, SLOT(timeout())); } void StoreProgress::show_error() { - dialogs::DSMessageBox msg(parentWidget()); - msg.mBox()->setText(tr("Failed to save session.")); - msg.mBox()->setInformativeText(_session.error()); - msg.mBox()->setStandardButtons(QMessageBox::Ok); - msg.mBox()->setIcon(QMessageBox::Warning); - msg.exec(); + 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(); + } } -void StoreProgress::closeEvent(QCloseEvent*) +void StoreProgress::closeEvent(QCloseEvent* e) { - _session.cancel(); + _store_session.cancel(); + DSDialog::closeEvent(e); } void StoreProgress::on_progress_updated() { - const std::pair p = _session.progress(); + const std::pair p = _store_session.progress(); assert(p.first <= p.second); - setValue(p.first); - setMaximum(p.second); + _progress.setValue(p.first); + _progress.setMaximum(p.second); - const QString err = _session.error(); + const QString err = _store_session.error(); if (!err.isEmpty()) { show_error(); - close(); + //close(); + _done = true; } - if (p.first == p.second) - close(); + if (p.first == p.second) { + //close(); + _done = true; + } } } // dialogs diff --git a/DSView/pv/dialogs/storeprogress.h b/DSView/pv/dialogs/storeprogress.h index c582e3e1..30cfc841 100644 --- a/DSView/pv/dialogs/storeprogress.h +++ b/DSView/pv/dialogs/storeprogress.h @@ -2,6 +2,7 @@ * This file is part of the PulseView project. * * Copyright (C) 2014 Joel Holdsworth + * Copyright (C) 2016 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 @@ -25,9 +26,13 @@ #include -#include +#include +#include +#include +#include -#include +#include "../storesession.h" +#include "../dialogs/dsdialog.h" #include "../toolbars/titlebar.h" namespace pv { @@ -36,30 +41,43 @@ class SigSession; namespace dialogs { -class StoreProgress : public QProgressDialog +class StoreProgress : public DSDialog { Q_OBJECT public: - StoreProgress(const QString &file_name, SigSession &session, + StoreProgress(SigSession &session, QWidget *parent = 0); virtual ~StoreProgress(); - void run(); + + +protected: + void reject(); private: void show_error(); + void closeEvent(QCloseEvent* e); - void closeEvent(QCloseEvent*); +public slots: + void save_run(); + void export_run(); private slots: void on_progress_updated(); + void timeout(); private: - pv::StoreSession _session; + pv::StoreSession _store_session; + + QLabel _info; + QProgressBar _progress; + QDialogButtonBox _button_box; toolbars::TitleBar *_titlebar; + + bool _done; }; } // dialogs diff --git a/DSView/pv/dialogs/waitingdialog.cpp b/DSView/pv/dialogs/waitingdialog.cpp index c069c61f..bb8ddf36 100644 --- a/DSView/pv/dialogs/waitingdialog.cpp +++ b/DSView/pv/dialogs/waitingdialog.cpp @@ -79,7 +79,7 @@ WaitingDialog::WaitingDialog(QWidget *parent, boost::shared_ptraddWidget(&_button_box); layout()->addLayout(mlayout); - setTitle(tr("Zero Adjustment")); + setTitle(tr("Auto Calibration")); } void WaitingDialog::accept() @@ -100,7 +100,8 @@ void WaitingDialog::accept() QProgressDialog dlg(tr("Save Auto Zero Result... It can take a while."), tr("Cancel"),0,0,this,flags); dlg.setWindowModality(Qt::WindowModal); - dlg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint); + dlg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | + Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint); dlg.setCancelButton(NULL); QFutureWatcher watcher; @@ -130,7 +131,8 @@ void WaitingDialog::reject() QProgressDialog dlg(tr("Load Current Setting... It can take a while."), tr("Cancel"),0,0,this,flags); dlg.setWindowModality(Qt::WindowModal); - dlg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint); + dlg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | + Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint); dlg.setCancelButton(NULL); QFutureWatcher watcher; diff --git a/DSView/pv/dock/measuredock.cpp b/DSView/pv/dock/measuredock.cpp index 27fe3842..fb116eea 100644 --- a/DSView/pv/dock/measuredock.cpp +++ b/DSView/pv/dock/measuredock.cpp @@ -34,14 +34,17 @@ #include "../devicemanager.h" #include "../device/device.h" #include "../device/file.h" +#include "../dialogs/dsdialog.h" +#include "../dialogs/dsmessagebox.h" #include #include #include +#include #include "libsigrok4DSL/libsigrok.h" -using boost::shared_ptr; +using namespace boost; namespace pv { namespace dock { @@ -51,7 +54,11 @@ using namespace pv::view; MeasureDock::MeasureDock(QWidget *parent, View &view, SigSession &session) : QScrollArea(parent), _session(session), - _view(view) + _view(view), + _icon_add(":/icons/add.png"), + _icon_add_dis(":/icons/add_dis.png"), + _icon_del(":/icons/del.png"), + _icon_del_dis(":/icons/del_dis.png") { _widget = new QWidget(this); @@ -67,76 +74,74 @@ MeasureDock::MeasureDock(QWidget *parent, View &view, SigSession &session) : _mouse_layout = new QGridLayout(); _mouse_layout->setVerticalSpacing(5); - _mouse_layout->addWidget(_fen_checkBox, 0, 0, 1, 4); + _mouse_layout->addWidget(_fen_checkBox, 0, 0, 1, 6); _mouse_layout->addWidget(new QLabel(tr("W: "), _widget), 1, 0); _mouse_layout->addWidget(_width_label, 1, 1); - _mouse_layout->addWidget(new QLabel(tr("P: "), _widget), 1, 2); - _mouse_layout->addWidget(_period_label, 1, 3); - _mouse_layout->addWidget(new QLabel(tr("F: "), _widget), 2, 2); - _mouse_layout->addWidget(_freq_label, 2, 3); + _mouse_layout->addWidget(new QLabel(tr("P: "), _widget), 1, 4); + _mouse_layout->addWidget(_period_label, 1, 5); + _mouse_layout->addWidget(new QLabel(tr("F: "), _widget), 2, 4); + _mouse_layout->addWidget(_freq_label, 2, 5); _mouse_layout->addWidget(new QLabel(tr("D: "), _widget), 2, 0); _mouse_layout->addWidget(_duty_label, 2, 1); - _mouse_layout->addWidget(new QLabel(_widget), 0, 4); - _mouse_layout->addWidget(new QLabel(_widget), 1, 4); - _mouse_layout->addWidget(new QLabel(_widget), 2, 4); + _mouse_layout->addWidget(new QLabel(_widget), 0, 6); + _mouse_layout->addWidget(new QLabel(_widget), 1, 6); + _mouse_layout->addWidget(new QLabel(_widget), 2, 6); _mouse_layout->setColumnStretch(5, 1); _mouse_groupBox->setLayout(_mouse_layout); + /* cursor distance group */ + _dist_groupBox = new QGroupBox(tr("Cursor Distance"), _widget); + _dist_groupBox->setMinimumWidth(300); + _dist_add_btn = new QToolButton(_widget); + _dist_add_btn->setIcon(_icon_add); + connect(_dist_add_btn, SIGNAL(clicked()), this, SLOT(add_dist_measure())); - _cursor_groupBox = new QGroupBox(tr("Cursor measurement"), _widget); - _t1_comboBox = new QComboBox(_widget); - _t2_comboBox = new QComboBox(_widget); - _t3_comboBox = new QComboBox(_widget); - _delta_label_t1t2 = new QLabel("##########/##########", _widget); - _delta_label_t2t3 = new QLabel("##########/##########", _widget); - _delta_label_t1t3 = new QLabel("##########/##########", _widget); - _t1_last_index = 0; - _t2_last_index = 0; - _t3_last_index = 0; - _t1_comboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); - _t2_comboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); - _t3_comboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); + _dist_layout = new QGridLayout(_widget); + _dist_layout->setVerticalSpacing(5); + _dist_layout->addWidget(_dist_add_btn, 0, 0); + _dist_layout->addWidget(new QLabel(_widget), 0, 1, 1, 3); + _dist_layout->addWidget(new QLabel(tr("Time/Samples"), _widget), 0, 4); + _dist_layout->addWidget(new QLabel(_widget), 0, 5, 1, 2); + _dist_layout->setColumnStretch(1, 50); + _dist_layout->setColumnStretch(6, 100); + add_dist_measure(); + _dist_groupBox->setLayout(_dist_layout); + /* cursor edges group */ + _edge_groupBox = new QGroupBox(tr("Edges"), _widget); + _edge_groupBox->setMinimumWidth(300); + _edge_add_btn = new QToolButton(_widget); + _edge_add_btn->setIcon(_icon_add); + connect(_edge_add_btn, SIGNAL(clicked()), this, SLOT(add_edge_measure())); + + _edge_layout = new QGridLayout(_widget); + _edge_layout->setVerticalSpacing(5); + _edge_layout->addWidget(_edge_add_btn, 0, 0); + _edge_layout->addWidget(new QLabel(_widget), 0, 1, 1, 4); + _edge_layout->addWidget(new QLabel(tr("Channel"), _widget), 0, 5); + _edge_layout->addWidget(new QLabel(tr("Rising/Falling/Edges"), _widget), 0, 6); + _edge_layout->setColumnStretch(1, 50); + //_edge_layout->setColumnStretch(6, 100); + //add_edge_measure(); + _edge_groupBox->setLayout(_edge_layout); + + /* cursors group */ + _cursor_groupBox = new QGroupBox(tr("Cursors"), _widget); _cursor_layout = new QGridLayout(_widget); - _cursor_layout->setVerticalSpacing(5); - _cursor_layout->addWidget(new QLabel(tr("T1: "), _widget), 0, 0); - _cursor_layout->addWidget(_t1_comboBox, 0, 1); - _cursor_layout->addWidget(new QLabel(tr("T2: "), _widget), 1, 0); - _cursor_layout->addWidget(_t2_comboBox, 1, 1); - _cursor_layout->addWidget(new QLabel(tr("T3: "), _widget), 2, 0); - _cursor_layout->addWidget(_t3_comboBox, 2, 1); - - _cursor_layout->addWidget(new QLabel(tr("Time/Samples"), _widget), 3, 1, 1, 2); - _cursor_layout->addWidget(new QLabel(tr("|T2 - T1|: "), _widget), 4, 0); - _cursor_layout->addWidget(_delta_label_t1t2, 4, 1, 1, 2); - - _cursor_layout->addWidget(new QLabel(tr("|T3 - T2|: "), _widget), 5, 0); - _cursor_layout->addWidget(_delta_label_t2t3, 5, 1, 1, 2); - - _cursor_layout->addWidget(new QLabel(tr("|T3 - T1|: "), _widget), 6, 0); - _cursor_layout->addWidget(_delta_label_t1t3, 6, 1, 1, 2); - - _cursor_layout->addWidget(new QLabel(_widget), 7, 0); - _cursor_layout->addWidget(new QLabel(tr("Cursors"), _widget), 8, 0); - _cursor_layout->addWidget(new QLabel(tr("Time/Samples"), _widget), 8, 1, 1, 2); - - _cursor_layout->addWidget(new QLabel(_widget), 0, 2); - _cursor_layout->addWidget(new QLabel(_widget), 1, 2); - _cursor_layout->addWidget(new QLabel(_widget), 2, 2); - _cursor_layout->setColumnStretch(2, 1); + _cursor_layout->addWidget(new QLabel(tr("Time/Samples"), _widget), 0, 2); + _cursor_layout->addWidget(new QLabel(_widget), 0, 3); + _cursor_layout->setColumnStretch(3, 1); _cursor_groupBox->setLayout(_cursor_layout); QVBoxLayout *layout = new QVBoxLayout(_widget); layout->addWidget(_mouse_groupBox); + layout->addWidget(_dist_groupBox); + layout->addWidget(_edge_groupBox); layout->addWidget(_cursor_groupBox); layout->addStretch(1); _widget->setLayout(layout); - connect(_t1_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(delta_update())); - connect(_t2_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(delta_update())); - connect(_t3_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(delta_update())); - connect(_fen_checkBox, SIGNAL(stateChanged(int)), &_view, SLOT(set_measure_en(int))); connect(&_view, SIGNAL(measure_updated()), this, SLOT(measure_updated())); @@ -157,73 +162,70 @@ void MeasureDock::paintEvent(QPaintEvent *) // style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); } +void MeasureDock::refresh() +{ + +} + +void MeasureDock::reload() +{ + for (QVector ::const_iterator i = _edge_ch_cmb_vec.begin(); + i != _edge_ch_cmb_vec.end(); i++) { + update_probe_selector(*i); + } + reCalc(); +} + void MeasureDock::cursor_update() { using namespace pv::data; - int index = 1; - - disconnect(_t1_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(delta_update())); - disconnect(_t2_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(delta_update())); - disconnect(_t3_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(delta_update())); - _t1_comboBox->clear(); - _t2_comboBox->clear(); - _t3_comboBox->clear(); - if (!_cursor_pushButton_list.empty()) { + for (QVector ::const_iterator i = _cursor_del_btn_vec.begin(); + i != _cursor_del_btn_vec.end(); i++) + delete (*i); for (QVector::Iterator i = _cursor_pushButton_list.begin(); i != _cursor_pushButton_list.end(); i++) delete (*i); for (QVector::Iterator i = _curpos_label_list.begin(); i != _curpos_label_list.end(); i++) delete (*i); - for (QVector::Iterator i = _space_label_list.begin(); - i != _space_label_list.end(); i++) - delete (*i); + _cursor_del_btn_vec.clear(); _cursor_pushButton_list.clear(); _curpos_label_list.clear(); - _space_label_list.clear(); } + update_dist(); + update_edge(); + + int index = 1; for(std::list::iterator i = _view.get_cursorList().begin(); i != _view.get_cursorList().end(); i++) { - QString curCursor = tr("Cursor ")+QString::number(index); - _t1_comboBox->addItem(curCursor); - _t2_comboBox->addItem(curCursor); - _t3_comboBox->addItem(curCursor); + QString curCursor = QString::number(index); + QToolButton *del_btn = new QToolButton(_widget); + del_btn->setIcon(QIcon::fromTheme("measure", + QIcon(":/icons/del.png"))); + del_btn->setCheckable(true); QPushButton *_cursor_pushButton = new QPushButton(curCursor, _widget); + set_cursor_btn_color(_cursor_pushButton); QString _cur_text = _view.get_cm_time(index - 1) + "/" + QString::number(_view.get_cursor_samples(index - 1)); QLabel *_curpos_label = new QLabel(_cur_text, _widget); - QLabel *_space_label = new QLabel(_widget); + _cursor_del_btn_vec.push_back(del_btn); _cursor_pushButton_list.push_back(_cursor_pushButton); _curpos_label_list.push_back(_curpos_label); - _space_label_list.push_back(_space_label); - _cursor_layout->addWidget(_cursor_pushButton, 8 + index, 0); - _cursor_layout->addWidget(_curpos_label, 8 + index, 1, 1, 2); + _cursor_layout->addWidget(del_btn, 1+index, 0); + _cursor_layout->addWidget(_cursor_pushButton, 1 + index, 1); + _cursor_layout->addWidget(_curpos_label, 1 + index, 2); + connect(del_btn, SIGNAL(clicked()), this, SLOT(del_cursor())); connect(_cursor_pushButton, SIGNAL(clicked()), this, SLOT(goto_cursor())); index++; } - _t1_comboBox->setMinimumWidth(_t1_comboBox->sizeHint().width()+30); - _t2_comboBox->setMinimumWidth(_t2_comboBox->sizeHint().width()+30); - _t3_comboBox->setMinimumWidth(_t3_comboBox->sizeHint().width()+30); - if (_t1_last_index < _t1_comboBox->count()) - _t1_comboBox->setCurrentIndex(_t1_last_index); - if (_t2_last_index < _t2_comboBox->count()) - _t2_comboBox->setCurrentIndex(_t2_last_index); - if (_t3_last_index < _t3_comboBox->count()) - _t3_comboBox->setCurrentIndex(_t3_last_index); - - connect(_t1_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(delta_update())); - connect(_t2_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(delta_update())); - connect(_t3_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(delta_update())); - - delta_update(); update(); } @@ -235,7 +237,7 @@ void MeasureDock::measure_updated() _duty_label->setText(_view.get_measure("duty")); } -void MeasureDock::cursor_moved() +void MeasureDock::cursor_moving() { //TimeMarker* grabbed_marker = _view.get_ruler()->get_grabbed_cursor(); if (_view.cursors_shown()) { @@ -248,38 +250,13 @@ void MeasureDock::cursor_moved() index++; } } - delta_update(); + + update_dist(); } -void MeasureDock::delta_update() +void MeasureDock::reCalc() { - QString delta_text; - _t1_last_index = std::max(_t1_comboBox->currentIndex(), 0); - _t2_last_index = std::max(_t2_comboBox->currentIndex(), 0); - _t3_last_index = std::max(_t3_comboBox->currentIndex(), 0); - if (_t1_comboBox->count() != 0 && _t2_comboBox->count() != 0) { - uint64_t delta = abs(_view.get_cursor_samples(_t1_last_index) - - _view.get_cursor_samples(_t2_last_index)); - delta_text = _view.get_cm_delta(_t1_last_index, _t2_last_index) + - "/" + QString::number(delta); - _delta_label_t1t2->setText(delta_text); - } - - if (_t2_comboBox->count() != 0 && _t2_comboBox->count() != 0) { - uint64_t delta = abs(_view.get_cursor_samples(_t2_last_index) - - _view.get_cursor_samples(_t3_last_index)); - delta_text = _view.get_cm_delta(_t2_last_index, _t3_last_index) + - "/" + QString::number(delta); - _delta_label_t2t3->setText(delta_text); - } - - if (_t1_comboBox->count() != 0 && _t3_comboBox->count() != 0) { - uint64_t delta = abs(_view.get_cursor_samples(_t1_last_index) - - _view.get_cursor_samples(_t3_last_index)); - delta_text = _view.get_cm_delta(_t1_last_index, _t3_last_index) + - "/" + QString::number(delta); - _delta_label_t1t3->setText(delta_text); - } + update_edge(); } void MeasureDock::goto_cursor() @@ -297,5 +274,388 @@ void MeasureDock::goto_cursor() } } +void MeasureDock::add_dist_measure() +{ + if (_dist_row_widget_vec.size() > Max_Measure_Limits) + return; + + QWidget *row_widget = new QWidget(_widget); + row_widget->setContentsMargins(0,0,0,0); + QHBoxLayout *row_layout = new QHBoxLayout(row_widget); + row_layout->setContentsMargins(0,0,0,0); + row_layout->setSpacing(0); + row_widget->setLayout(row_layout); + _dist_row_widget_vec.push_back(row_widget); + + QToolButton *del_btn = new QToolButton(row_widget); + del_btn->setIcon(QIcon::fromTheme("measure", + QIcon(":/icons/del.png"))); + del_btn->setCheckable(true); + QPushButton *s_btn = new QPushButton(tr(" "), row_widget); + s_btn->setObjectName("dist"); + QPushButton *e_btn = new QPushButton(tr(" "), row_widget); + e_btn->setObjectName("dist"); + QLabel *r_label = new QLabel(row_widget); + QLabel *g_label = new QLabel(tr("-"), row_widget); + g_label->setContentsMargins(0,0,0,0); + _dist_del_btn_vec.push_back(del_btn); + _dist_s_btn_vec.push_back(s_btn); + _dist_e_btn_vec.push_back(e_btn); + _dist_r_label_vec.push_back(r_label); + + connect(del_btn, SIGNAL(clicked()), this, SLOT(del_dist_measure())); + connect(s_btn, SIGNAL(clicked()), this, SLOT(show_all_coursor())); + connect(e_btn, SIGNAL(clicked()), this, SLOT(show_all_coursor())); + + row_layout->addWidget(del_btn); + row_layout->addSpacing(5); + row_layout->addWidget(s_btn); + row_layout->addWidget(g_label); + row_layout->addWidget(e_btn); + row_layout->addSpacing(5); + row_layout->addWidget(r_label, 100); + + _dist_layout->addWidget(row_widget, _dist_row_widget_vec.size(), 0, 1, 7); + +} + +void MeasureDock::del_dist_measure() +{ + int del_index = 0; + for (QVector ::const_iterator i = _dist_del_btn_vec.begin(); + i != _dist_del_btn_vec.end(); i++) { + if ((*i)->isChecked()) { + _dist_layout->removeWidget(_dist_row_widget_vec.at(del_index)); + + delete _dist_del_btn_vec.at(del_index); + delete _dist_s_btn_vec.at(del_index); + delete _dist_e_btn_vec.at(del_index); + delete _dist_r_label_vec.at(del_index); + delete _dist_row_widget_vec.at(del_index); + + _dist_del_btn_vec.remove(del_index); + _dist_s_btn_vec.remove(del_index); + _dist_e_btn_vec.remove(del_index); + _dist_r_label_vec.remove(del_index); + _dist_row_widget_vec.remove(del_index); + + break; + } + del_index++; + } +} + +void MeasureDock::add_edge_measure() +{ + if (_edge_row_widget_vec.size() > Max_Measure_Limits) + return; + + QWidget *row_widget = new QWidget(_widget); + row_widget->setContentsMargins(0,0,0,0); + QHBoxLayout *row_layout = new QHBoxLayout(row_widget); + row_layout->setContentsMargins(0,0,0,0); + row_layout->setSpacing(0); + row_widget->setLayout(row_layout); + _edge_row_widget_vec.push_back(row_widget); + + QToolButton *del_btn = new QToolButton(row_widget); + del_btn->setIcon(QIcon::fromTheme("measure", + QIcon(":/icons/del.png"))); + del_btn->setCheckable(true); + QPushButton *s_btn = new QPushButton(tr(" "), row_widget); + s_btn->setObjectName("edge"); + QPushButton *e_btn = new QPushButton(tr(" "), row_widget); + e_btn->setObjectName("edge"); + QLabel *r_label = new QLabel(row_widget); + QLabel *g_label = new QLabel(tr("-"), row_widget); + 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); + _edge_del_btn_vec.push_back(del_btn); + _edge_s_btn_vec.push_back(s_btn); + _edge_e_btn_vec.push_back(e_btn); + _edge_ch_cmb_vec.push_back(ch_cmb); + _edge_r_label_vec.push_back(r_label); + + connect(del_btn, SIGNAL(clicked()), this, SLOT(del_edge_measure())); + connect(s_btn, SIGNAL(clicked()), this, SLOT(show_all_coursor())); + connect(e_btn, SIGNAL(clicked()), this, SLOT(show_all_coursor())); + connect(ch_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(update_edge())); + + row_layout->addWidget(del_btn); + row_layout->addSpacing(5); + row_layout->addWidget(s_btn); + row_layout->addWidget(g_label); + row_layout->addWidget(e_btn); + row_layout->addWidget(a_label); + row_layout->addWidget(ch_cmb); + row_layout->addSpacing(5); + row_layout->addWidget(r_label, 100); + + _edge_layout->addWidget(row_widget, _edge_row_widget_vec.size(), 0, 1, 7); + +} + +void MeasureDock::del_edge_measure() +{ + int del_index = 0; + for (QVector ::const_iterator i = _edge_del_btn_vec.begin(); + i != _edge_del_btn_vec.end(); i++) { + if ((*i)->isChecked()) { + _edge_layout->removeWidget(_edge_row_widget_vec.at(del_index)); + + delete _edge_del_btn_vec.at(del_index); + delete _edge_s_btn_vec.at(del_index); + delete _edge_e_btn_vec.at(del_index); + delete _edge_r_label_vec.at(del_index); + delete _edge_ch_cmb_vec.at(del_index); + delete _edge_row_widget_vec.at(del_index); + + _edge_del_btn_vec.remove(del_index); + _edge_s_btn_vec.remove(del_index); + _edge_e_btn_vec.remove(del_index); + _edge_r_label_vec.remove(del_index); + _edge_ch_cmb_vec.remove(del_index); + _edge_row_widget_vec.remove(del_index); + + break; + } + del_index++; + } +} + +void MeasureDock::show_all_coursor() +{ + if (_view.get_cursorList().empty()) { + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("Information")); + msg.mBox()->setInformativeText(tr("Please insert cursor before using cursor measure.")); + msg.mBox()->addButton(tr("Ok"), QMessageBox::AcceptRole); + msg.mBox()->setIcon(QMessageBox::Information); + msg.exec(); + + return; + } + + _sel_btn = qobject_cast(sender()); + + //dialogs::DSDialog cursor_dlg(_widget); + QDialog cursor_dlg(_widget); + cursor_dlg.setWindowFlags(Qt::FramelessWindowHint | Qt::Popup | Qt::WindowSystemMenuHint | + Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint); + int index = 0; + QHBoxLayout *hlayout = NULL; + QVBoxLayout *vlayout = new QVBoxLayout(&cursor_dlg); + for(std::list::iterator i = _view.get_cursorList().begin(); + i != _view.get_cursorList().end(); i++) { + QPushButton *cursor_btn = new QPushButton(QString::number(index+1), &cursor_dlg); + set_cursor_btn_color(cursor_btn); + if ((index % 4) == 0) { + hlayout = new QHBoxLayout(&cursor_dlg); + vlayout->addLayout(hlayout); + //cursor_dlg.layout()->addLayout(hlayout); + } + hlayout->addWidget(cursor_btn); + connect(cursor_btn, SIGNAL(clicked()), &cursor_dlg, SLOT(accept())); + connect(cursor_btn, SIGNAL(clicked()), this, SLOT(set_se_cursor())); + index++; + } + while((index++ % 4) != 0) + hlayout->addWidget(new QLabel(&cursor_dlg)); + + cursor_dlg.setLayout(vlayout); + QRect sel_btn_rect = _sel_btn->geometry(); + sel_btn_rect.moveTopLeft(_sel_btn->parentWidget()->mapToGlobal(sel_btn_rect.topLeft())); + cursor_dlg.setGeometry(sel_btn_rect.left(), sel_btn_rect.bottom()+10, + cursor_dlg.width(), cursor_dlg.height()); + cursor_dlg.exec(); +} + +void MeasureDock::set_se_cursor() +{ + QPushButton *sc = qobject_cast(sender()); + if (_sel_btn) + _sel_btn->setText(sc->text()); + + set_cursor_btn_color(_sel_btn); + + if (_sel_btn->objectName() == "dist") + update_dist(); + else if (_sel_btn->objectName() == "edge") + update_edge(); +} + +const view::Cursor* MeasureDock::find_cousor(int index) +{ + int cur_index = 1; + for(std::list::iterator i = _view.get_cursorList().begin(); + i != _view.get_cursorList().end(); i++) { + if (cur_index == index) { + return (*i); + } + } + + return NULL; +} + +void MeasureDock::update_dist() +{ + int dist_index = 0; + for (QVector::Iterator i = _dist_s_btn_vec.begin(); + i != _dist_s_btn_vec.end(); i++) { + bool start_ret, end_ret; + const unsigned int start = (*i)->text().toInt(&start_ret) - 1; + const unsigned int end = _dist_e_btn_vec[dist_index]->text().toInt(&end_ret) - 1; + + if (start_ret) { + if (start + 1 > _view.get_cursorList().size()) { + (*i)->setText(" "); + set_cursor_btn_color((*i)); + start_ret = false; + } + } + if (end_ret) { + if (end + 1 > _view.get_cursorList().size()) { + _dist_e_btn_vec[dist_index]->setText(" "); + set_cursor_btn_color(_dist_e_btn_vec[dist_index]); + end_ret = false; + } + } + + if (start_ret && end_ret) { + int64_t delta = _view.get_cursor_samples(start) - + _view.get_cursor_samples(end); + QString delta_text = _view.get_cm_delta(start, end) + + "/" + QString::number(delta); + if (delta < 0) + delta_text.replace('+', '-'); + _dist_r_label_vec[dist_index]->setText(delta_text); + } else { + _dist_r_label_vec[dist_index]->setText(" "); + } + + dist_index++; + } +} + +void MeasureDock::update_edge() +{ + int edge_index = 0; + for (QVector::Iterator i = _edge_s_btn_vec.begin(); + i != _edge_s_btn_vec.end(); i++) { + bool start_ret, end_ret; + const unsigned int start = (*i)->text().toInt(&start_ret) - 1; + const unsigned int end = _edge_e_btn_vec[edge_index]->text().toInt(&end_ret) - 1; + + if (start_ret) { + if (start + 1 > _view.get_cursorList().size()) { + (*i)->setText(" "); + set_cursor_btn_color((*i)); + start_ret = false; + } + } + if (end_ret) { + if (end + 1 > _view.get_cursorList().size()) { + _edge_e_btn_vec[edge_index]->setText(" "); + set_cursor_btn_color(_edge_e_btn_vec[edge_index]); + end_ret = false; + } + } + + bool mValid = false; + if (start_ret && end_ret) { + uint64_t rising_edges; + uint64_t falling_edges; + 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; + assert(s); + if ((logicSig = dynamic_pointer_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)) { + QString delta_text = QString::number(rising_edges) + "/" + + QString::number(falling_edges) + "/" + + QString::number(rising_edges + falling_edges); + _edge_r_label_vec[edge_index]->setText(delta_text); + mValid = true; + break; + } + } + } + } + + if (!mValid) + _edge_r_label_vec[edge_index]->setText("-/-/-"); + + edge_index++; + } +} + +void MeasureDock::set_cursor_btn_color(QPushButton *btn) +{ + bool ret; + const unsigned int start = btn->text().toInt(&ret) - 1; + QColor cursor_color = ret ? view::Ruler::CursorColor[start%8] : QColor("#302F2F"); + QString border_width = ret ? "0px" : "1px"; + QString normal = "{background-color:" + cursor_color.name() + + "; color:black" + "; border-width:" + border_width + ";}"; + QString hover = "{background-color:" + cursor_color.darker().name() + + "; color:black" + "; border-width:" + border_width + ";}"; + QString style = "QPushButton:hover" + hover + + "QPushButton" + normal; + btn->setStyleSheet(style); +} + +QComboBox* MeasureDock::create_probe_selector(QWidget *parent) +{ + QComboBox *selector = new QComboBox(parent); + update_probe_selector(selector); + return selector; +} + +void MeasureDock::update_probe_selector(QComboBox *selector) +{ + selector->clear(); + 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); + + if (dynamic_pointer_cast(s) && s->enabled()) + { + selector->addItem(QString::number(s->get_index())); + } + } +} + +void MeasureDock::del_cursor() +{ + int del_index = 0; + Cursor* cursor = NULL; + for (QVector ::const_iterator i = _cursor_del_btn_vec.begin(); + i != _cursor_del_btn_vec.end(); i++) { + if ((*i)->isChecked()) { + int cur_index = 0; + std::list::iterator ite = _view.get_cursorList().begin(); + while (cur_index++ != del_index) + ite++; + cursor = *ite; + break; + } + del_index++; + } + + if (cursor) + _view.del_cursor(cursor); + if (_view.get_cursorList().empty()) + _view.show_cursors(false); + + cursor_update(); + _view.update(); +} + } // namespace dock } // namespace pv diff --git a/DSView/pv/dock/measuredock.h b/DSView/pv/dock/measuredock.h index bb941b0c..d049782d 100644 --- a/DSView/pv/dock/measuredock.h +++ b/DSView/pv/dock/measuredock.h @@ -50,6 +50,7 @@ namespace pv { class SigSession; namespace view { + class Cursor; class View; } @@ -59,21 +60,42 @@ class MeasureDock : public QScrollArea { Q_OBJECT +private: + static const int Max_Measure_Limits = 16; + public: MeasureDock(QWidget *parent, pv::view::View &view, SigSession &session); ~MeasureDock(); void paintEvent(QPaintEvent *); + void reload(); +private: + QComboBox* create_probe_selector(QWidget *parent); + void update_probe_selector(QComboBox *selector); + signals: private slots: - void delta_update(); void goto_cursor(); + void add_dist_measure(); + void del_dist_measure(); + void add_edge_measure(); + void del_edge_measure(); + void show_all_coursor(); + void set_se_cursor(); + const view::Cursor* find_cousor(int index); + void update_dist(); + void update_edge(); + void set_cursor_btn_color(QPushButton *btn); + void del_cursor(); + public slots: void cursor_update(); - void cursor_moved(); + void cursor_moving(); + void reCalc(); void measure_updated(); + void refresh(); private: SigSession &_session; @@ -88,24 +110,37 @@ private: QLabel *_freq_label; QLabel *_duty_label; + QGridLayout *_dist_layout; + QGroupBox *_dist_groupBox; + QToolButton *_dist_add_btn; + QVector _dist_row_widget_vec; + QVector _dist_del_btn_vec; + QVector _dist_s_btn_vec; + QVector _dist_e_btn_vec; + QVector _dist_r_label_vec; + + QGridLayout *_edge_layout; + QGroupBox *_edge_groupBox; + QToolButton *_edge_add_btn; + QVector _edge_row_widget_vec; + QVector _edge_del_btn_vec; + QVector _edge_s_btn_vec; + QVector _edge_e_btn_vec; + QVector _edge_ch_cmb_vec; + QVector _edge_r_label_vec; + + QPushButton *_sel_btn; + QGridLayout *_cursor_layout; QGroupBox *_cursor_groupBox; - QComboBox *_t1_comboBox; - QComboBox *_t2_comboBox; - QComboBox *_t3_comboBox; - QLabel *_delta_label_t1t2; - QLabel *_cnt_label_t1t2; - QLabel *_delta_label_t2t3; - QLabel *_cnt_label_t2t3; - QLabel *_delta_label_t1t3; - QLabel *_cnt_label_t1t3; - int _t1_last_index; - int _t2_last_index; - int _t3_last_index; - + QVector _cursor_del_btn_vec; QVector _cursor_pushButton_list; QVector _curpos_label_list; - QVector _space_label_list; + + QIcon _icon_add; + QIcon _icon_add_dis; + QIcon _icon_del; + QIcon _icon_del_dis; }; } // namespace dock diff --git a/DSView/pv/dock/protocoldock.cpp b/DSView/pv/dock/protocoldock.cpp index 7a32761b..8311c5a5 100644 --- a/DSView/pv/dock/protocoldock.cpp +++ b/DSView/pv/dock/protocoldock.cpp @@ -29,6 +29,7 @@ #include "../dialogs/protocollist.h" #include "../dialogs/protocolexp.h" #include "../dialogs/dsmessagebox.h" +#include "../view/view.h" #include #include @@ -52,12 +53,14 @@ namespace pv { namespace dock { -ProtocolDock::ProtocolDock(QWidget *parent, SigSession &session) : +ProtocolDock::ProtocolDock(QWidget *parent, view::View &view, SigSession &session) : QScrollArea(parent), _session(session), + _view(view), _cur_search_index(-1), _search_edited(false), - _searching(false) + _searching(false), + _add_silent(false) { _up_widget = new QWidget(this); @@ -125,11 +128,19 @@ ProtocolDock::ProtocolDock(QWidget *parent, SigSession &session) : connect(_dn_save_button, SIGNAL(clicked()), this, SLOT(export_table_view())); + _dn_nav_button = new QPushButton(_dn_widget); + _dn_nav_button->setFlat(true); + _dn_nav_button->setIcon(QIcon::fromTheme("protocol", + QIcon(":/icons/nav.png"))); + connect(_dn_nav_button, SIGNAL(clicked()), + this, SLOT(nav_table_view())); + QHBoxLayout *dn_title_layout = new QHBoxLayout(); dn_title_layout->addWidget(_dn_set_button, 0, Qt::AlignLeft); dn_title_layout->addWidget(_dn_save_button, 0, Qt::AlignLeft); dn_title_layout->addWidget(new QLabel(tr("Protocol List Viewer"), _dn_widget), 1, Qt::AlignLeft); - dn_title_layout->addStretch(1); + dn_title_layout->addWidget(_dn_nav_button, 0, Qt::AlignRight); + //dn_title_layout->addStretch(1); _table_view = new QTableView(_dn_widget); _table_view->setModel(_session.get_decoder_model()); @@ -237,7 +248,38 @@ int ProtocolDock::decoder_name_cmp(const void *a, const void *b) ((const srd_decoder*)b)->name); } +bool ProtocolDock::sel_protocol(QString id) +{ + QString name; + GSList *l = g_slist_sort(g_slist_copy( + (GSList*)srd_decoder_list()), decoder_name_cmp); + for(; l; l = l->next) + { + const srd_decoder *const d = (srd_decoder*)l->data; + assert(d); + + const bool have_probes = (d->channels || d->opt_channels) != 0; + if (true == have_probes && + QString::fromUtf8(d->id) == id) { + name = QString::fromUtf8(d->name); + break; + } + } + g_slist_free(l); + + _protocol_combobox->setCurrentText(name); + if (_protocol_combobox->currentText() == name) + return true; + else + return false; +} + void ProtocolDock::add_protocol() +{ + add_protocol(false); +} + +void ProtocolDock::add_protocol(bool silent) { if (_session.get_device()->dev_inst()->mode != LOGIC) { dialogs::DSMessageBox msg(this); @@ -249,7 +291,7 @@ void ProtocolDock::add_protocol() } else { srd_decoder *const decoder = (srd_decoder*)(_protocol_combobox->itemData(_protocol_combobox->currentIndex())).value(); - if (_session.add_decoder(decoder)) { + 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(); @@ -442,6 +484,13 @@ void ProtocolDock::set_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()); + BOOST_FOREACH(boost::shared_ptr d, decode_sigs) { + d->decoder()->set_mark_index(-1); + } } void ProtocolDock::update_model() @@ -494,7 +543,13 @@ void ProtocolDock::item_clicked(const QModelIndex &index) if (decoder_stack) { pv::data::decode::Annotation ann; if (decoder_stack->list_annotation(ann, index.column(), index.row())) { - _session.show_region(ann.start_sample(), ann.end_sample()); + const std::vector< boost::shared_ptr > decode_sigs( + _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); } } _table_view->resizeRowToContents(index.row()); @@ -558,6 +613,41 @@ void ProtocolDock::export_table_view() protocolexp_dlg->exec(); } +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(); + if (decoder_stack) { + uint64_t offset = _view.offset() * (decoder_stack->samplerate() * _view.scale()); + std::map rows = decoder_stack->get_rows_lshow(); + int column = _model_proxy.filterKeyColumn(); + for (std::map::const_iterator i = rows.begin(); + i != rows.end(); i++) { + if ((*i).second && column-- == 0) { + row_index = decoder_stack->get_annotation_index((*i).first, offset); + break; + } + } + QModelIndex index = _model_proxy.mapToSource(_model_proxy.index(row_index, _model_proxy.filterKeyColumn())); + if(index.isValid()){ + _table_view->scrollTo(index); + _table_view->setCurrentIndex(index); + + 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()); + 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); + _view.set_all_update(true); + _view.update(); + } + } +} + void ProtocolDock::search_pre() { search_update(); @@ -707,7 +797,8 @@ void ProtocolDock::search_update() QProgressDialog dlg(tr("Searching..."), tr("Cancel"),0,0,this,flags); dlg.setWindowModality(Qt::WindowModal); - dlg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint); + dlg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | + Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint); dlg.setCancelButton(NULL); QFutureWatcher watcher; diff --git a/DSView/pv/dock/protocoldock.h b/DSView/pv/dock/protocoldock.h index 9a1616fd..ec56170d 100644 --- a/DSView/pv/dock/protocoldock.h +++ b/DSView/pv/dock/protocoldock.h @@ -23,7 +23,7 @@ #ifndef DSVIEW_PV_PROTOCOLDOCK_H #define DSVIEW_PV_PROTOCOLDOCK_H -#include +#include #include #include @@ -52,6 +52,10 @@ namespace data { class DecoderModel; } +namespace view { +class View; +} + namespace dock { class ProtocolDock : public QScrollArea @@ -62,10 +66,12 @@ public: static const uint64_t ProgressRows = 100000; public: - ProtocolDock(QWidget *parent, SigSession &session); + ProtocolDock(QWidget *parent, view::View &view, SigSession &session); ~ProtocolDock(); void del_all_protocol(); + bool sel_protocol(QString name); + void add_protocol(bool silent); protected: void paintEvent(QPaintEvent *); @@ -82,6 +88,7 @@ private slots: void set_model(); void update_model(); void export_table_view(); + void nav_table_view(); void item_clicked(const QModelIndex &index); void column_resize(int index, int old_size, int new_size); void search_pre(); @@ -96,6 +103,7 @@ private: private: SigSession &_session; + view::View &_view; QSortFilterProxyModel _model_proxy; double _cur_search_index; QStringList _str_list; @@ -124,10 +132,13 @@ private: QPushButton *_dn_set_button; QPushButton *_dn_save_button; + QPushButton *_dn_nav_button; mutable boost::mutex _search_mutex; bool _search_edited; bool _searching; + + bool _add_silent; }; } // namespace dock diff --git a/DSView/pv/dock/searchdock.cpp b/DSView/pv/dock/searchdock.cpp index e523abaf..4f81f2ba 100644 --- a/DSView/pv/dock/searchdock.cpp +++ b/DSView/pv/dock/searchdock.cpp @@ -55,8 +55,6 @@ SearchDock::SearchDock(QWidget *parent, View &view, SigSession &session) : _session(session), _view(view) { - _pattern = "X X X X X X X X X X X X X X X X"; - connect(&_pre_button, SIGNAL(clicked()), this, SLOT(on_previous())); connect(&_nxt_button, SIGNAL(clicked()), @@ -113,14 +111,25 @@ void SearchDock::paintEvent(QPaintEvent *) void SearchDock::on_previous() { bool ret; - uint64_t last_pos; - uint8_t *data; - int unit_size; - uint64_t length; - QString value = _search_value->text(); - search_previous(value); + int64_t last_pos; + bool last_hit; + const boost::shared_ptr snapshot(_session.get_snapshot(SR_CHANNEL_LOGIC)); + assert(snapshot); + const boost::shared_ptr logic_snapshot = boost::dynamic_pointer_cast(snapshot); + if (!logic_snapshot || logic_snapshot->empty()) { + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("Search")); + msg.mBox()->setInformativeText(tr("No Sample data!")); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); + msg.exec(); + return; + } + + const int64_t end = logic_snapshot->get_sample_count() - 1; last_pos = _view.get_search_pos(); + last_hit = _view.get_search_hit(); if (last_pos == 0) { dialogs::DSMessageBox msg(this); msg.mBox()->setText(tr("Search")); @@ -130,43 +139,34 @@ void SearchDock::on_previous() msg.exec(); return; } else { - data = (uint8_t*)_session.get_buf(unit_size, length); - if (data == NULL) { + QFuture future; + future = QtConcurrent::run([&]{ + last_pos -= last_hit; + ret = logic_snapshot->pattern_search(0, end, false, last_pos, _pattern); + }); + Qt::WindowFlags flags = Qt::CustomizeWindowHint; + QProgressDialog dlg(tr("Search Previous..."), + tr("Cancel"),0,0,this,flags); + dlg.setWindowModality(Qt::WindowModal); + dlg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | + Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint); + dlg.setCancelButton(NULL); + + QFutureWatcher watcher; + connect(&watcher,SIGNAL(finished()),&dlg,SLOT(cancel())); + watcher.setFuture(future); + dlg.exec(); + + if (!ret) { dialogs::DSMessageBox msg(this); msg.mBox()->setText(tr("Search")); - msg.mBox()->setInformativeText(tr("No Sample data!")); + msg.mBox()->setInformativeText(tr("Pattern not found!")); msg.mBox()->setStandardButtons(QMessageBox::Ok); msg.mBox()->setIcon(QMessageBox::Warning); msg.exec(); return; } else { - QFuture future; - future = QtConcurrent::run([&]{ - ret = search_value(data, unit_size, length, last_pos, 1, value); - }); - Qt::WindowFlags flags = Qt::CustomizeWindowHint; - QProgressDialog dlg(tr("Search Previous..."), - tr("Cancel"),0,0,this,flags); - dlg.setWindowModality(Qt::WindowModal); - dlg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint); - dlg.setCancelButton(NULL); - - QFutureWatcher watcher; - connect(&watcher,SIGNAL(finished()),&dlg,SLOT(cancel())); - watcher.setFuture(future); - dlg.exec(); - - if (!ret) { - dialogs::DSMessageBox msg(this); - msg.mBox()->setText(tr("Search")); - msg.mBox()->setInformativeText(tr("Pattern ") + value + tr(" not found!")); - msg.mBox()->setStandardButtons(QMessageBox::Ok); - msg.mBox()->setIcon(QMessageBox::Warning); - msg.exec(); - return; - } else { - _view.set_search_pos(last_pos); - } + _view.set_search_pos(last_pos, true); } } } @@ -174,15 +174,24 @@ void SearchDock::on_previous() void SearchDock::on_next() { bool ret; - uint64_t last_pos; - int unit_size; - uint64_t length; - uint8_t *data = (uint8_t*)_session.get_buf(unit_size, length); - QString value = _search_value->text(); - search_previous(value); + int64_t last_pos; + const boost::shared_ptr snapshot(_session.get_snapshot(SR_CHANNEL_LOGIC)); + assert(snapshot); + const boost::shared_ptr logic_snapshot = boost::dynamic_pointer_cast(snapshot); - last_pos = _view.get_search_pos(); - if (last_pos == length - 1) { + if (!logic_snapshot || logic_snapshot->empty()) { + dialogs::DSMessageBox msg(this); + msg.mBox()->setText(tr("Search")); + msg.mBox()->setInformativeText(tr("No Sample data!")); + msg.mBox()->setStandardButtons(QMessageBox::Ok); + msg.mBox()->setIcon(QMessageBox::Warning); + msg.exec(); + return; + } + + const int64_t end = logic_snapshot->get_sample_count() - 1; + last_pos = _view.get_search_pos() + _view.get_search_hit(); + if (last_pos >= end) { dialogs::DSMessageBox msg(this); msg.mBox()->setText(tr("Search")); msg.mBox()->setInformativeText(tr("Search cursor at the end position!")); @@ -191,180 +200,58 @@ void SearchDock::on_next() msg.exec(); return; } else { - if (data == NULL) { + QFuture future; + future = QtConcurrent::run([&]{ + ret = logic_snapshot->pattern_search(0, end, true, last_pos, _pattern); + }); + Qt::WindowFlags flags = Qt::CustomizeWindowHint; + QProgressDialog dlg(tr("Search Next..."), + tr("Cancel"),0,0,this,flags); + dlg.setWindowModality(Qt::WindowModal); + dlg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | + Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint); + dlg.setCancelButton(NULL); + + QFutureWatcher watcher; + connect(&watcher,SIGNAL(finished()),&dlg,SLOT(cancel())); + watcher.setFuture(future); + dlg.exec(); + + if (!ret) { dialogs::DSMessageBox msg(this); msg.mBox()->setText(tr("Search")); - msg.mBox()->setInformativeText(tr("No Sample data!")); + msg.mBox()->setInformativeText(tr("Pattern not found!")); msg.mBox()->setStandardButtons(QMessageBox::Ok); msg.mBox()->setIcon(QMessageBox::Warning); msg.exec(); return; } else { - QFuture future; - future = QtConcurrent::run([&]{ - ret = search_value(data, unit_size, length, last_pos, 0, value); - }); - Qt::WindowFlags flags = Qt::CustomizeWindowHint; - QProgressDialog dlg(tr("Search Next..."), - tr("Cancel"),0,0,this,flags); - dlg.setWindowModality(Qt::WindowModal); - dlg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint); - dlg.setCancelButton(NULL); - - QFutureWatcher watcher; - connect(&watcher,SIGNAL(finished()),&dlg,SLOT(cancel())); - watcher.setFuture(future); - dlg.exec(); - - if (!ret) { - dialogs::DSMessageBox msg(this); - msg.mBox()->setText(tr("Search")); - msg.mBox()->setInformativeText(tr("Pattern ") + value + tr(" not found!")); - msg.mBox()->setStandardButtons(QMessageBox::Ok); - msg.mBox()->setIcon(QMessageBox::Warning); - msg.exec(); - return; - } else { - _view.set_search_pos(last_pos); - } + _view.set_search_pos(last_pos, true); } } } void SearchDock::on_set() { - dialogs::Search dlg(this, _session.get_device(), _pattern); + dialogs::Search dlg(this, _session, _pattern); if (dlg.exec()) { _pattern = dlg.get_pattern(); - _pattern.remove(QChar(' '), Qt::CaseInsensitive); - _pattern = _pattern.toUpper(); - _search_value->setText(_pattern); - QFontMetrics fm = this->fontMetrics(); - _search_value->setFixedWidth(fm.width(_pattern)+_search_button->width()+20); - } -} - -bool SearchDock::search_value(const uint8_t *data, int unit_size, uint64_t length, uint64_t& pos, bool left, QString value) -{ - QByteArray pattern = value.toUtf8(); - int i = 0; - uint64_t match_pos = left ? pos - 1 : pos + 1; - bool part_match = false; - int match_bits = unit_size * 8 - 1; - bool unmatch = false; - - while(i <= match_bits) { - unmatch = false; - uint64_t pattern_mask = 1ULL << i; - - if (pattern[match_bits - i] == 'X') { - part_match = true; - } else if (pattern[match_bits - i] == '0') { - //while((match_pos >= 0 && left) || (match_pos < length && !left)) { - while(left || (match_pos < length && !left)) { - if (0 == ((*(uint64_t *)(data + match_pos * unit_size) & pattern_mask) != 0)) { - part_match = true; - break; - } else if ((match_pos == 0 && left) || (match_pos == length - 1 && !left)) { - unmatch = true; - part_match = false; - break; - } else if (part_match) { - unmatch = true; - match_pos = left ? match_pos - 1 : match_pos + 1; - i = 0; - break; - } else if (!part_match) { - match_pos = left ? match_pos - 1 : match_pos + 1; - } - } - } else if (pattern[match_bits - i] == '1') { - //while((match_pos >= 0 && left) || (match_pos < length && !left)) { - while(left || (match_pos < length && !left)) { - if (1 == ((*(uint64_t *)(data + match_pos * unit_size) & pattern_mask) != 0)) { - part_match = true; - break; - } else if ((match_pos == 0 && left) || (match_pos == length - 1 && !left)) { - unmatch = true; - part_match = false; - break; - } else if (part_match) { - unmatch = true; - match_pos = left ? match_pos - 1 : match_pos + 1; - i = 0; - break; - } else if (!part_match) { - match_pos = left ? match_pos - 1 : match_pos + 1; - } - } - }else if (pattern[match_bits - i] == 'R') { - while((match_pos > 0 && left) || (match_pos < length && !left)) { - if (1 == ((*(uint64_t *)(data + match_pos * unit_size) & pattern_mask) != 0) && - 0 == ((*(uint64_t *)(data + (match_pos - 1) * unit_size) & pattern_mask) != 0)) { - part_match = true; - break; - } else if ((match_pos == 1 && left) || (match_pos == length - 1 && !left)) { - unmatch = true; - part_match = false; - break; - } else if (part_match) { - unmatch = true; - match_pos = left ? match_pos - 1 : match_pos + 1; - i = 0; - break; - } else if (!part_match) { - match_pos = left ? match_pos - 1 : match_pos + 1; - } - } - } else if (pattern[match_bits - i] == 'F') { - while((match_pos > 0 && left) || (match_pos < length && !left)) { - if (0 == ((*(uint64_t *)(data + match_pos * unit_size) & pattern_mask) != 0) && - 1 == ((*(uint64_t *)(data + (match_pos - 1) * unit_size) & pattern_mask) != 0)) { - part_match = true; - break; - } else if ((match_pos == 1 && left) || (match_pos == length - 1 && !left)) { - unmatch = true; - part_match = false; - break; - } else if (part_match) { - unmatch = true; - match_pos = left ? match_pos - 1 : match_pos + 1; - i = 0; - break; - } else if (!part_match) { - match_pos = left ? match_pos - 1 : match_pos + 1; - } - } - } else if (pattern[match_bits - i] == 'C') { - while((match_pos > 0 && left) || (match_pos < length && !left)) { - if (((*(uint64_t *)(data + match_pos * unit_size) & pattern_mask) != 0) != - ((*(uint64_t *)(data + (match_pos - 1) * unit_size) & pattern_mask) != 0)) { - part_match = true; - break; - } else if ((match_pos == 1 && left) || (match_pos == length - 1 && !left)) { - unmatch = true; - part_match = false; - break; - } else if (part_match) { - unmatch = true; - match_pos = left ? match_pos - 1 : match_pos + 1; - i = 0; - break; - } else if (!part_match) { - match_pos = left ? match_pos - 1 : match_pos + 1; - } - } + QString search_label; + for (auto& iter:_pattern) { + iter.second.remove(QChar(' '), Qt::CaseInsensitive); + iter.second = iter.second.toUpper(); + search_label.push_back(iter.second); +// if (iter.second != "XXXXXXXXXXXXXXXX") { +// search_label.push_back(QString::number(iter.first)); +// search_label.push_back("/"); +// } } - if (unmatch && !part_match) - break; - else if ((!unmatch && part_match) || !part_match) - i++; + _search_value->setText(search_label); + QFontMetrics fm = this->fontMetrics(); + _search_value->setFixedWidth(fm.width(search_label)+_search_button->width()+20); } - - pos = match_pos; - return !unmatch; } } // namespace dock diff --git a/DSView/pv/dock/searchdock.h b/DSView/pv/dock/searchdock.h index e541cd6b..d99c9b17 100644 --- a/DSView/pv/dock/searchdock.h +++ b/DSView/pv/dock/searchdock.h @@ -70,22 +70,15 @@ public: void paintEvent(QPaintEvent *); -signals: - void search_previous(QString); - void search_next(QString); - public slots: void on_previous(); void on_next(); void on_set(); -private: - bool search_value(const uint8_t* data, int unit_size, uint64_t length, - uint64_t& pos, bool left, QString value); private: SigSession &_session; view::View &_view; - QString _pattern; + std::map _pattern; QPushButton _pre_button; QPushButton _nxt_button; diff --git a/DSView/pv/dock/triggerdock.cpp b/DSView/pv/dock/triggerdock.cpp index 0256df0c..cf5c654c 100644 --- a/DSView/pv/dock/triggerdock.cpp +++ b/DSView/pv/dock/triggerdock.cpp @@ -57,10 +57,10 @@ TriggerDock::TriggerDock(QWidget *parent, SigSession &session) : position_label = new QLabel(tr("Trigger Position: "), _widget); position_spinBox = new QSpinBox(_widget); - position_spinBox->setRange(MinTrigPosition, 99); + position_spinBox->setRange(MinTrigPosition, DS_MAX_TRIG_PERCENT); position_spinBox->setButtonSymbols(QAbstractSpinBox::NoButtons); position_slider = new QSlider(Qt::Horizontal, _widget); - position_slider->setRange(MinTrigPosition, 99); + position_slider->setRange(MinTrigPosition, DS_MAX_TRIG_PERCENT); connect(position_slider, SIGNAL(valueChanged(int)), position_spinBox, SLOT(setValue(int))); connect(position_spinBox, SIGNAL(valueChanged(int)), position_slider, SLOT(setValue(int))); @@ -93,10 +93,10 @@ TriggerDock::TriggerDock(QWidget *parent, SigSession &session) : _value0_lineEdit->setInputMask("X X X X X X X X X X X X X X X X"); _value0_lineEdit->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); _value0_lineEdit_list.push_back(_value0_lineEdit); - QSpinBox *_count0_spinBox = new QSpinBox(_widget); - _count0_spinBox->setRange(1, INT32_MAX); - _count0_spinBox->setButtonSymbols(QAbstractSpinBox::NoButtons); - _count0_spinBox_list.push_back(_count0_spinBox); + QSpinBox *_count_spinBox = new QSpinBox(_widget); + _count_spinBox->setRange(1, INT32_MAX); + _count_spinBox->setButtonSymbols(QAbstractSpinBox::NoButtons); + _count_spinBox_list.push_back(_count_spinBox); QComboBox *_inv0_comboBox = new QComboBox(_widget); _inv0_comboBox->addItem(tr("==")); _inv0_comboBox->addItem(tr("!=")); @@ -109,33 +109,38 @@ TriggerDock::TriggerDock(QWidget *parent, SigSession &session) : _value1_lineEdit->setInputMask("X X X X X X X X X X X X X X X X"); _value1_lineEdit->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); _value1_lineEdit_list.push_back(_value1_lineEdit); - QSpinBox *_count1_spinBox = new QSpinBox(_widget); - _count1_spinBox->setRange(1, INT32_MAX); - _count1_spinBox->setButtonSymbols(QAbstractSpinBox::NoButtons); - _count1_spinBox_list.push_back(_count1_spinBox); QComboBox *_inv1_comboBox = new QComboBox(_widget); _inv1_comboBox->addItem(tr("==")); _inv1_comboBox->addItem(tr("!=")); _inv1_comboBox_list.push_back(_inv1_comboBox); + QCheckBox *_contiguous_checkbox = new QCheckBox(_widget); + _contiguous_checkbox_list.push_back(_contiguous_checkbox); + QLabel *value_exp_label = new QLabel("1 1 1 1 1 1\n5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 ", _widget); - QLabel *inv_exp_label = new QLabel("Inv", _widget); - QLabel *count_exp_label = new QLabel("Counter", _widget); + QLabel *inv_exp_label = new QLabel(tr("Inv"), _widget); + QLabel *count_exp_label = new QLabel(tr("Counter"), _widget); value_exp_label->setFont(font); QVBoxLayout *stage_layout = new QVBoxLayout(); QGridLayout *stage_glayout = new QGridLayout(); stage_glayout->setVerticalSpacing(5); + stage_glayout->addWidget(value_exp_label, 1, 0); stage_glayout->addWidget(inv_exp_label, 1, 1); - stage_glayout->addWidget(count_exp_label, 1, 2); stage_glayout->addWidget(_value0_lineEdit, 2, 0); stage_glayout->addWidget(_inv0_comboBox, 2, 1); - stage_glayout->addWidget(_count0_spinBox, 2, 2); - stage_glayout->addWidget(_logic_comboBox, 2, 3); + stage_glayout->addWidget(_logic_comboBox, 2, 2); stage_glayout->addWidget(_value1_lineEdit, 3, 0); stage_glayout->addWidget(_inv1_comboBox, 3, 1); - stage_glayout->addWidget(_count1_spinBox, 3, 2); + + stage_glayout->addWidget(new QLabel(_widget), 4, 0); + + stage_glayout->addWidget(new QLabel(tr("Contiguous")), 5, 1, 1, 2); + stage_glayout->addWidget(_contiguous_checkbox, 5, 0, 1, 1, Qt::AlignRight); + stage_glayout->addWidget(count_exp_label, 6, 1, 1, 2); + stage_glayout->addWidget(_count_spinBox, 6, 0); + stage_layout->addLayout(stage_glayout); stage_layout->addSpacing(20); stage_layout->addWidget(new QLabel(tr("X: Don't care\n0: Low level\n1: High level\nR: Rising edge\nF: Falling edge\nC: Rising/Falling edge"))); @@ -189,9 +194,9 @@ TriggerDock::TriggerDock(QWidget *parent, SigSession &session) : _serial_value_lineEdit->setInputMask("X X X X X X X X X X X X X X X X"); _serial_value_lineEdit->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); - _serial_vcnt_spinBox = new QSpinBox(_widget); - _serial_vcnt_spinBox->setRange(1, INT32_MAX); - _serial_vcnt_spinBox->setButtonSymbols(QAbstractSpinBox::NoButtons); + _serial_bits_comboBox = new QComboBox(_widget); + for(i = 1; i <= 16; i++) + _serial_bits_comboBox->addItem(QString::number(i)); QLabel *serial_value_exp_label = new QLabel("1 1 1 1 1 1\n5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0", _widget); serial_value_exp_label->setFont(font); @@ -211,11 +216,11 @@ TriggerDock::TriggerDock(QWidget *parent, SigSession &session) : serial_glayout->addWidget(new QLabel(_widget), 5, 0, 1, 5); serial_glayout->addWidget(_serial_data_lable, 6, 0); serial_glayout->addWidget(_serial_data_comboBox, 6, 1); - serial_glayout->addWidget(new QLabel(tr("counter"), _widget), 6, 4); - serial_glayout->addWidget(_serial_value_lable, 7, 0); - serial_glayout->addWidget(_serial_value_lineEdit, 7, 1, 1, 3); - serial_glayout->addWidget(_serial_vcnt_spinBox, 7, 4); - serial_glayout->addWidget(new QLabel(_widget), 7, 5); + serial_glayout->addWidget(new QLabel(tr("Data Bits"), _widget), 7, 0); + serial_glayout->addWidget(_serial_bits_comboBox, 7, 1); + serial_glayout->addWidget(_serial_value_lable, 8, 0); + serial_glayout->addWidget(_serial_value_lineEdit, 8, 1, 1, 3); + serial_layout->addLayout(serial_glayout); serial_layout->addSpacing(20); serial_layout->addWidget(new QLabel(tr("X: Don't care\n0: Low level\n1: High level\nR: Rising edge\nF: Falling edge\nC: Rising/Falling edge"))); @@ -343,27 +348,18 @@ void TriggerDock::value_changed() sc->setText(sc->text().toUpper()); } -void TriggerDock::device_change() +void TriggerDock::device_updated() { - uint64_t max_hd_depth; + uint64_t hw_depth; bool stream = false; uint8_t maxRange; uint64_t sample_limits; - GVariant *gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_MAX_LOGIC_SAMPLELIMITS); + GVariant *gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_HW_DEPTH); if (gvar != NULL) { - max_hd_depth = g_variant_get_uint64(gvar); + hw_depth = g_variant_get_uint64(gvar); g_variant_unref(gvar); if (_session.get_device()->dev_inst()->mode == LOGIC) { - sample_limits = _session.get_device()->get_sample_limit(); - if (max_hd_depth >= sample_limits) - maxRange = 99; - else - maxRange = max_hd_depth*70 / sample_limits; - position_spinBox->setRange(MinTrigPosition, maxRange); - position_slider->setRange(MinTrigPosition, maxRange); - - gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_STREAM); if (gvar != NULL) { @@ -371,6 +367,16 @@ void TriggerDock::device_change() g_variant_unref(gvar); } + sample_limits = _session.get_device()->get_sample_limit(); + if (stream) + maxRange = 1; + else if (hw_depth >= sample_limits) + maxRange = DS_MAX_TRIG_PERCENT; + else + maxRange = ceil(hw_depth * DS_MAX_TRIG_PERCENT / sample_limits); + position_spinBox->setRange(MinTrigPosition, maxRange); + position_slider->setRange(MinTrigPosition, maxRange); + if (_session.get_device()->name().contains("virtual") || stream) { simple_radioButton->setChecked(true); @@ -397,7 +403,7 @@ bool TriggerDock::commit_trigger() ds_trigger_set_mode(SERIAL_TRIGGER); // trigger stage update - ds_trigger_set_stage(stages_comboBox->currentText().toInt()); + ds_trigger_set_stage(stages_comboBox->currentText().toInt() - 1); int i; // trigger value update @@ -410,36 +416,36 @@ bool TriggerDock::commit_trigger() } else if(_adv_tabWidget->currentIndex() == 1){ ds_trigger_stage_set_value(0, TriggerProbes, _serial_start_lineEdit->text().toLocal8Bit().data(), - _value1_lineEdit_list.at(0)->text().toLocal8Bit().data()); + _serial_stop_lineEdit->text().toLocal8Bit().data()); ds_trigger_stage_set_value(1, TriggerProbes, - _serial_stop_lineEdit->text().toLocal8Bit().data(), - _value1_lineEdit_list.at(1)->text().toLocal8Bit().data()); - ds_trigger_stage_set_value(2, TriggerProbes, _serial_edge_lineEdit->text().toLocal8Bit().data(), - _value1_lineEdit_list.at(2)->text().toLocal8Bit().data()); + _value1_lineEdit_list.at(1)->text().toLocal8Bit().data()); + //_serial_data_comboBox const int data_channel = _serial_data_comboBox->currentText().toInt(); char channel[31]; for(i = 0; i < 31; i++){ if (i == (30 - 2*data_channel)) - channel[i] = '1'; - else if (i%2 == 0) channel[i] = '0'; + else if (i%2 == 0) + channel[i] = 'X'; else channel[i] = ' '; } - ds_trigger_stage_set_value(3, TriggerProbes, + ds_trigger_stage_set_value(2, TriggerProbes, channel, - _value1_lineEdit_list.at(3)->text().toLocal8Bit().data()); - ds_trigger_stage_set_value(4, TriggerProbes, + _value1_lineEdit_list.at(2)->text().toLocal8Bit().data()); + ds_trigger_stage_set_value(STriggerDataStage, TriggerProbes, _serial_value_lineEdit->text().toLocal8Bit().data(), - _value1_lineEdit_list.at(4)->text().toLocal8Bit().data()); + _value1_lineEdit_list.at(3)->text().toLocal8Bit().data()); } // trigger logic update for (i = 0; i < stages_comboBox->currentText().toInt(); i++) { + const char logic = (_contiguous_checkbox_list.at(i)->isChecked() << 1) + + _logic_comboBox_list.at(i)->currentIndex(); ds_trigger_stage_set_logic(i, TriggerProbes, - _logic_comboBox_list.at(i)->currentIndex()); + logic); } // trigger inv update @@ -453,12 +459,15 @@ bool TriggerDock::commit_trigger() if (_adv_tabWidget->currentIndex() == 0) { for (i = 0; i < stages_comboBox->currentText().toInt(); i++) { ds_trigger_stage_set_count(i, TriggerProbes, - _count0_spinBox_list.at(i)->value() - 1, - _count1_spinBox_list.at(i)->value() - 1); + _count_spinBox_list.at(i)->value(), + 0); } } else if(_adv_tabWidget->currentIndex() == 1){ - ds_trigger_stage_set_count(4, TriggerProbes, - _serial_vcnt_spinBox->value() - 1, + ds_trigger_stage_set_count(1, TriggerProbes, + 1, + 0); + ds_trigger_stage_set_count(3, TriggerProbes, + _serial_bits_comboBox->currentText().toInt() - 1, 0); } return 1; @@ -475,34 +484,37 @@ void TriggerDock::init() QJsonObject TriggerDock::get_session() { QJsonObject trigSes; - trigSes["triggerMode"] = adv_radioButton->isChecked() ? 1 : 0; + trigSes["advTriggerMode"] = adv_radioButton->isChecked(); trigSes["triggerPos"] = position_slider->value(); trigSes["triggerStages"] = stages_comboBox->currentIndex(); - trigSes["triggerSerial"] = _adv_tabWidget->currentIndex(); + trigSes["triggerTab"] = _adv_tabWidget->currentIndex(); for (int i = 0; i < stages_comboBox->count(); i++) { - QString value0_str = "triggerValue0" + QString::number(i); - QString inv0_str = "triggerInv0" + QString::number(i); - QString count0_str = "triggerCount0" + QString::number(i); - QString value1_str = "triggerValue1" + QString::number(i); - QString inv1_str = "triggerInv1" + QString::number(i); - QString count1_str = "triggerCount1" + QString::number(i); - QString logic_str = "triggerLogic" + QString::number(i); + QString value0_str = "stageTriggerValue0" + QString::number(i); + QString inv0_str = "stageTriggerInv0" + QString::number(i); + QString value1_str = "stageTriggerValue1" + QString::number(i); + QString inv1_str = "stageTriggerInv1" + QString::number(i); + + QString logic_str = "stageTriggerLogic" + QString::number(i); + QString count_str = "stageTriggerCount" + QString::number(i); + QString conti_str = "stageTriggerContiguous" + QString::number(i); + trigSes[value0_str] = _value0_lineEdit_list.at(i)->text(); trigSes[value1_str] = _value1_lineEdit_list.at(i)->text(); trigSes[inv0_str] = _inv0_comboBox_list.at(i)->currentIndex(); trigSes[inv1_str] = _inv1_comboBox_list.at(i)->currentIndex(); - trigSes[count0_str] = _count0_spinBox_list.at(i)->value(); - trigSes[count1_str] = _count1_spinBox_list.at(i)->value(); + trigSes[logic_str] = _logic_comboBox_list.at(i)->currentIndex(); + trigSes[count_str] = _count_spinBox_list.at(i)->value(); + trigSes[conti_str] = _contiguous_checkbox_list.at(i)->isChecked(); } - trigSes["triggerStart"] = _serial_start_lineEdit->text(); - trigSes["triggerStop"] = _serial_stop_lineEdit->text(); - trigSes["triggerClock"] = _serial_edge_lineEdit->text(); - trigSes["triggerChannel"] = _serial_data_comboBox->currentIndex(); - trigSes["triggerData"] = _serial_value_lineEdit->text(); - trigSes["triggerVcnt"] = _serial_vcnt_spinBox->value(); + trigSes["serialTriggerStart"] = _serial_start_lineEdit->text(); + trigSes["serialTriggerStop"] = _serial_stop_lineEdit->text(); + trigSes["serialTriggerClock"] = _serial_edge_lineEdit->text(); + trigSes["serialTriggerChannel"] = _serial_data_comboBox->currentIndex(); + trigSes["serialTriggerData"] = _serial_value_lineEdit->text(); + trigSes["serialTriggerBits"] = _serial_bits_comboBox->currentIndex(); return trigSes; } @@ -511,35 +523,38 @@ void TriggerDock::set_session(QJsonObject ses) { position_slider->setValue(ses["triggerPos"].toDouble()); stages_comboBox->setCurrentIndex(ses["triggerStages"].toDouble()); - _adv_tabWidget->setCurrentIndex(ses["triggerSerial"].toDouble()); - if (ses["triggerMode"].toDouble() == 0) - simple_radioButton->click(); - else + _adv_tabWidget->setCurrentIndex(ses["triggerTab"].toDouble()); + if (ses["advTriggerMode"].toBool()) adv_radioButton->click(); + else + simple_radioButton->click(); for (int i = 0; i < stages_comboBox->count(); i++) { - QString value0_str = "triggerValue0" + QString::number(i); - QString inv0_str = "triggerInv0" + QString::number(i); - QString count0_str = "triggerCount0" + QString::number(i); - QString value1_str = "triggerValue1" + QString::number(i); - QString inv1_str = "triggerInv1" + QString::number(i); - QString count1_str = "triggerCount1" + QString::number(i); - QString logic_str = "triggerLogic" + QString::number(i); + QString value0_str = "stageTriggerValue0" + QString::number(i); + QString inv0_str = "stageTriggerInv0" + QString::number(i); + QString value1_str = "stageTriggerValue1" + QString::number(i); + QString inv1_str = "stageTriggerInv1" + QString::number(i); + + QString logic_str = "stageTriggerLogic" + QString::number(i); + QString count_str = "stageTriggerCount" + QString::number(i); + QString conti_str = "stageTriggerContiguous" + QString::number(i); + _value0_lineEdit_list.at(i)->setText(ses[value0_str].toString()); _value1_lineEdit_list.at(i)->setText(ses[value1_str].toString()); _inv0_comboBox_list.at(i)->setCurrentIndex(ses[inv0_str].toDouble()); _inv1_comboBox_list.at(i)->setCurrentIndex(ses[inv1_str].toDouble()); - _count0_spinBox_list.at(i)->setValue(ses[count0_str].toDouble()); - _count1_spinBox_list.at(i)->setValue(ses[count1_str].toDouble()); + _logic_comboBox_list.at(i)->setCurrentIndex(ses[logic_str].toDouble()); + _count_spinBox_list.at(i)->setValue(ses[count_str].toDouble()); + _contiguous_checkbox_list.at(i)->setChecked(ses[conti_str].toBool()); } - _serial_start_lineEdit->setText(ses["triggerStart"].toString()); - _serial_stop_lineEdit->setText(ses["triggerStop"].toString()); - _serial_edge_lineEdit->setText(ses["triggerClock"].toString()); - _serial_data_comboBox->setCurrentIndex(ses["triggerChannel"].toDouble()); - _serial_value_lineEdit->setText(ses["triggerData"].toString()); - _serial_vcnt_spinBox->setValue(ses["triggerVcnt"].toDouble()); + _serial_start_lineEdit->setText(ses["serialTriggerStart"].toString()); + _serial_stop_lineEdit->setText(ses["serialTriggerStop"].toString()); + _serial_edge_lineEdit->setText(ses["serialTriggerClock"].toString()); + _serial_data_comboBox->setCurrentIndex(ses["serialTriggerChannel"].toDouble()); + _serial_value_lineEdit->setText(ses["serialTriggerData"].toString()); + _serial_bits_comboBox->setCurrentIndex(ses["serialTriggerBits"].toDouble()); } } // namespace dock diff --git a/DSView/pv/dock/triggerdock.h b/DSView/pv/dock/triggerdock.h index 6533b03e..9c88d3b4 100644 --- a/DSView/pv/dock/triggerdock.h +++ b/DSView/pv/dock/triggerdock.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -84,7 +85,7 @@ public slots: void value_changed(); - void device_change(); + void device_updated(); private: @@ -109,11 +110,11 @@ private: QVector _mu_label_list; QVector _logic_comboBox_list; QVector _value0_lineEdit_list; - QVector _count0_spinBox_list; + QVector _count_spinBox_list; QVector _inv0_comboBox_list; QVector _value1_lineEdit_list; - QVector _count1_spinBox_list; QVector _inv1_comboBox_list; + QVector _contiguous_checkbox_list; QTabWidget *_adv_tabWidget; QGroupBox *_serial_groupBox; @@ -128,7 +129,7 @@ private: QLabel *_serial_value_lable; QLineEdit *_serial_value_lineEdit; QLabel *_serial_vcnt_lable; - QSpinBox *_serial_vcnt_spinBox; + QComboBox *_serial_bits_comboBox; }; } // namespace dock diff --git a/DSView/pv/mainframe.cpp b/DSView/pv/mainframe.cpp index 777119eb..1c612b66 100644 --- a/DSView/pv/mainframe.cpp +++ b/DSView/pv/mainframe.cpp @@ -46,7 +46,8 @@ MainFrame::MainFrame(DeviceManager &device_manager, setAttribute(Qt::WA_TranslucentBackground); // Make this a borderless window which can't // be resized or moved via the window system - setWindowFlags(Qt::FramelessWindowHint); + setWindowFlags(Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | + Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint); setMinimumHeight(680); setMinimumWidth(800); //resize(1024, 768); @@ -58,6 +59,7 @@ MainFrame::MainFrame(DeviceManager &device_manager, setWindowIcon(icon); _moving = false; + _draging = false; _startPos = None; _freezing = false; _minimized = false; @@ -118,24 +120,23 @@ MainFrame::MainFrame(DeviceManager &device_manager, _layout->addWidget(_bottom_right, 2, 2); connect(&_timer, SIGNAL(timeout()), this, SLOT(unfreezing())); - readSettings(); + //readSettings(); } 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; - } + 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); @@ -346,6 +347,7 @@ void MainFrame::writeSettings() QSettings settings; settings.beginGroup("MainFrame"); + settings.setValue("isMax", isMaximized()); settings.setValue("size", size()); settings.setValue("pos", pos() + QPoint(geometry().left() - frameGeometry().left(), frameGeometry().right() - geometry().right())); @@ -357,13 +359,28 @@ void MainFrame::readSettings() QSettings settings; QDesktopWidget* desktopWidget = QApplication::desktop(); QRect deskRect = desktopWidget->availableGeometry(); + QPoint default_upleft = QPoint((deskRect.width() - minWidth)/2, (deskRect.height() - minHeight)/2); + QSize default_size = QSize(minWidth, minHeight); settings.beginGroup("MainFrame"); - QSize size = settings.value("size", QSize(minWidth, minHeight)).toSize(); - QPoint pos = settings.value("pos", QPoint((deskRect.width() - minWidth)/2, (deskRect.height() - minHeight)/2)).toPoint(); + bool isMax = settings.value("isMax", false).toBool(); + QSize size = settings.value("size", default_size).toSize(); + QPoint pos = settings.value("pos", default_upleft).toPoint(); settings.endGroup(); - if (size == deskRect.size()) { + // check the restored position is vavlid or not + int i = 0; + for (; i < desktopWidget->screenCount(); i++) { + deskRect = desktopWidget->availableGeometry(i); + if (deskRect.contains(pos)) + break; + } + if (i >= desktopWidget->screenCount()) + pos = default_upleft; + + if (isMax) { + resize(default_size); + move(default_upleft); _titleBar->showMaxRestore(); } else { resize(size); diff --git a/DSView/pv/mainframe.h b/DSView/pv/mainframe.h index 65cab5a8..5d54ee58 100644 --- a/DSView/pv/mainframe.h +++ b/DSView/pv/mainframe.h @@ -64,7 +64,7 @@ public: MainFrame(DeviceManager &device_manager, const char *open_file_name = NULL); - void showMaxRestore(); + void readSettings(); protected: void changeEvent(QEvent* event); @@ -83,7 +83,6 @@ private: void show_border(); void writeSettings(); - void readSettings(); private: toolbars::TitleBar *_titleBar; diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index dd47e3aa..7a6f0bf2 100644 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -22,7 +22,7 @@ #ifdef ENABLE_DECODE -#include +#include #include "dock/protocoldock.h" #endif @@ -106,9 +106,6 @@ MainWindow::MainWindow(DeviceManager &device_manager, Qt::QueuedConnection, Q_ARG(QString, s)); } - test_timer_linked = false; - test_timer.stop(); - test_timer.setSingleShot(true); } void MainWindow::setup_ui() @@ -140,8 +137,10 @@ void MainWindow::setup_ui() SLOT(on_search(bool))); connect(_file_bar, SIGNAL(load_file(QString)), this, SLOT(load_file(QString))); - connect(_file_bar, SIGNAL(save()), this, + 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, @@ -149,17 +148,6 @@ void MainWindow::setup_ui() connect(_file_bar, SIGNAL(store_session(QString)), this, SLOT(store_session(QString))); -#ifdef ENABLE_DECODE - // protocol dock - _protocol_dock=new QDockWidget(tr("Protocol"),this); - _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_widget = new dock::ProtocolDock(_protocol_dock, _session); - _protocol_dock->setWidget(_protocol_widget); - qDebug() << "Protocol decoder enabled!\n"; -#endif // trigger dock _trigger_dock=new QDockWidget(tr("Trigger Setting..."),this); _trigger_dock->setFeatures(QDockWidget::DockWidgetMovable); @@ -189,14 +177,13 @@ void MainWindow::setup_ui() connect(_sampling_bar, SIGNAL(instant_stop()), this, SLOT(instant_stop())); connect(_sampling_bar, SIGNAL(sample_count_changed()), _trigger_widget, - SLOT(device_change())); + SLOT(device_updated())); connect(_sampling_bar, SIGNAL(show_calibration()), _view, SLOT(show_calibration())); connect(_sampling_bar, SIGNAL(hide_calibration()), _view, SLOT(hide_calibration())); connect(_dso_trigger_widget, SIGNAL(set_trig_pos(int)), _view, SLOT(set_trig_pos(int))); - connect(_protocol_widget, SIGNAL(protocol_updated()), _view, SLOT(signals_changed())); setIconSize(QSize(40,40)); addToolBar(_sampling_bar); @@ -205,6 +192,19 @@ void MainWindow::setup_ui() addToolBar(_logo_bar); // Setup the dockWidget +#ifdef ENABLE_DECODE + // protocol dock + _protocol_dock=new QDockWidget(tr("Protocol"),this); + _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_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); _measure_dock->setFeatures(QDockWidget::DockWidgetMovable); @@ -242,19 +242,24 @@ void MainWindow::setup_ui() SLOT(device_attach()), Qt::QueuedConnection); connect(&_session, SIGNAL(device_detach()), this, SLOT(device_detach()), Qt::QueuedConnection); - connect(&_session, SIGNAL(test_data_error()), this, - SLOT(test_data_error())); - connect(&_session, SIGNAL(malloc_error()), this, - SLOT(malloc_error())); - connect(&_session, SIGNAL(hardware_connect_failed()), this, - SLOT(hardware_connect_failed())); - connect(&_session, SIGNAL(on_mode_change()), this, + 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(_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(cursor_moved())); + SLOT(reCalc())); + connect(_view, SIGNAL(prgRate(int)), this, SIGNAL(prgRate(int))); + connect(_view, SIGNAL(update_device_list()), + this, SLOT(update_device_list()), Qt::DirectConnection); // event filter _view->installEventFilter(this); @@ -272,10 +277,10 @@ void MainWindow::setup_ui() // Populate the device list and select the initially selected device _session.set_default_device(boost::bind(&MainWindow::session_error, this, - QString("Set Default Device failed"), _1)); + QString(tr("Set Default Device failed")), _1)); update_device_list(); _session.start_hotplug_proc(boost::bind(&MainWindow::session_error, this, - QString("Hotplug failed"), _1)); + QString(tr("Hotplug failed")), _1)); } void MainWindow::session_error( @@ -292,24 +297,45 @@ void MainWindow::update_device_list() _session.stop_capture(); _view->reload(); - _trigger_widget->device_change(); + _trigger_widget->device_updated(); #ifdef ENABLE_DECODE _protocol_widget->del_all_protocol(); #endif _trig_bar->reload(); - _sampling_bar->reload(); shared_ptr selected_device = _session.get_device(); _device_manager.add_device(selected_device); _sampling_bar->set_device_list(_device_manager.devices(), selected_device); _session.init_signals(); - if(dynamic_pointer_cast(selected_device)) { + shared_ptr file_dev; + if(file_dev = dynamic_pointer_cast(selected_device)) { + #ifdef ENABLE_DECODE + // load decoders + StoreSession ss(_session); + ss.load_decoders(_protocol_widget, file_dev->get_decoders()); + #endif + + // check version + if (selected_device->dev_inst()->mode == LOGIC) { + GVariant* gvar = selected_device->get_config(NULL, NULL, SR_CONF_FILE_VERSION); + if (gvar != NULL) { + 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. " + "This will lead to a slow loading speed. " + "Please resave it after loaded.")); + } + } + } + + // load data const QString errorMessage( - QString("Failed to capture file data!")); - const QString infoMessage; + QString(tr("Failed to capture file data!"))); _session.start_capture(true, boost::bind(&MainWindow::session_error, this, - errorMessage, infoMessage)); + errorMessage, _1)); } if (!selected_device->name().contains("virtual")) { @@ -332,31 +358,30 @@ void MainWindow::update_device_list() _file_bar->set_settings_en(false); _logo_bar->dsl_connected(false); } + _sampling_bar->reload(); _view->status_clear(); _trigger_widget->init(); _dso_trigger_widget->init(); + _measure_widget->reload(); } void MainWindow::reload() { - _trigger_widget->device_change(); + _trigger_widget->device_updated(); _session.reload(); -} - -void MainWindow::mode_changed() -{ - update_device_list(); + _measure_widget->reload(); } void MainWindow::load_file(QString file_name) { try { - //_session.set_file(file_name.toStdString()); + if (strncmp(_session.get_device()->name().toLocal8Bit(), "virtual", 7)) + 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("Set Default Device failed"), _1)); + QString(tr("Set Default Device failed")), _1)); update_device_list(); return; } @@ -380,8 +405,10 @@ void MainWindow::device_attach() _session.get_device()->device_updated(); //_session.stop_hot_plug_proc(); - if (_session.get_capture_state() == SigSession::Running) - _session.stop_capture(); + _session.set_repeating(false); + _session.stop_capture(); + _sampling_bar->set_sampling(false); + _session.capture_state_changed(SigSession::Stopped); struct sr_dev_driver **const drivers = sr_driver_list(); struct sr_dev_driver **driver; @@ -390,8 +417,9 @@ void MainWindow::device_attach() _device_manager.driver_scan(*driver); _session.set_default_device(boost::bind(&MainWindow::session_error, this, - QString("Set Default Device failed"), _1)); + QString(tr("Set Default Device failed")), _1)); update_device_list(); + } void MainWindow::device_detach() @@ -399,8 +427,10 @@ void MainWindow::device_detach() _session.get_device()->device_updated(); //_session.stop_hot_plug_proc(); - if (_session.get_capture_state() == SigSession::Running) - _session.stop_capture(); + _session.set_repeating(false); + _session.stop_capture(); + _sampling_bar->set_sampling(false); + _session.capture_state_changed(SigSession::Stopped); session_save(); _view->hide_calibration(); @@ -412,120 +442,143 @@ void MainWindow::device_detach() _device_manager.driver_scan(*driver); _session.set_default_device(boost::bind(&MainWindow::session_error, this, - QString("Set Default Device failed"), _1)); + QString(tr("Set Default Device failed")), _1)); update_device_list(); } void MainWindow::run_stop() { -#ifdef TEST_MODE - if (!test_timer_linked) { - connect(&test_timer, SIGNAL(timeout()), - this, SLOT(run_stop())); - test_timer_linked = true; - } -#endif - switch(_session.get_capture_state()) { - case SigSession::Init: - case SigSession::Stopped: - if (_session.get_device()->dev_inst()->mode == DSO) - _view->show_trig_cursor(true); - else - _view->show_trig_cursor(false); - _view->update_sample(false); - commit_trigger(false); - _session.start_capture(false, - boost::bind(&MainWindow::session_error, this, - QString("Capture failed"), _1)); - break; - - case SigSession::Running: - _session.stop_capture(); - break; - } -} - -void MainWindow::instant_stop() -{ -#ifdef TEST_MODE - if (!test_timer_linked) { - connect(&test_timer, SIGNAL(timeout()), - this, SLOT(instant_stop())); - test_timer_linked = true; - } -#endif switch(_session.get_capture_state()) { case SigSession::Init: case SigSession::Stopped: - if (_session.get_device()->dev_inst()->mode == DSO) - _view->show_trig_cursor(true); - else - _view->show_trig_cursor(false); - _view->update_sample(true); - commit_trigger(true); - _session.start_capture(true, + _view->capture_init(false); + commit_trigger(false); + _session.start_capture(false, boost::bind(&MainWindow::session_error, this, - QString("Capture failed"), _1)); + QString(tr("Capture failed")), _1)); break; case SigSession::Running: _session.stop_capture(); break; } - } -void MainWindow::test_data_error() +void MainWindow::instant_stop() { + switch(_session.get_capture_state()) { + case SigSession::Init: + case SigSession::Stopped: + _view->capture_init(true); + commit_trigger(true); + _session.start_capture(true, + boost::bind(&MainWindow::session_error, this, + QString(tr("Capture failed")), _1)); + break; + + case SigSession::Running: + _session.stop_capture(); + break; + } +} + +void MainWindow::repeat_resume() +{ + while(_view->session().get_capture_state() == SigSession::Running) + QCoreApplication::processEvents(); + run_stop(); +} + +void MainWindow::show_error() +{ + QString title; + QString details; + QString ch_status = ""; + uint64_t error_pattern; + + switch(_session.get_error()) { + case SigSession::Hw_err: + _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(); + 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(); + _sampling_bar->set_sampling(false); + _session.capture_state_changed(SigSession::Stopped); + title = tr("Data Error"); + error_pattern = _session.get_error_pattern(); + for(int i = 0; i < 16; i++) { + if (error_pattern & 0x01) + ch_status += "X "; + else + ch_status += " "; + ch_status += (i > 9 ? " " : ""); + error_pattern >>= 1; + } + details = tr("the received data are not consist with pre-defined test data!\n") + + tr("0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15\n") + ch_status; + break; + case SigSession::Pkt_data_err: + title = tr("Packet Error"); + details = tr("the content of received packet are not expected!"); + _session.refresh(0); + break; + case SigSession::Data_overflow: + _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; + default: + title = tr("Undefined Error"); + details = tr("Not expected error!"); + break; + } - _session.stop_capture(); dialogs::DSMessageBox msg(this); - msg.mBox()->setText(tr("Data Error")); - msg.mBox()->setInformativeText(tr("The received data is not consistent with pre-defined test data.")); + connect(_session.get_device().get(), SIGNAL(device_updated()), &msg, SLOT(accept())); + QFont font("Monaco"); + font.setStyleHint(QFont::Monospace); + font.setFixedPitch(true); + msg.mBox()->setFont(font); + + msg.mBox()->setText(title); + msg.mBox()->setInformativeText(details); msg.mBox()->setStandardButtons(QMessageBox::Ok); msg.mBox()->setIcon(QMessageBox::Warning); msg.exec(); -} -void MainWindow::malloc_error() -{ - _session.stop_capture(); - dialogs::DSMessageBox msg(this); - msg.mBox()->setText(tr("Malloc Error")); - msg.mBox()->setInformativeText(tr("Not enough memory for this sample!\nPlease reduce the sample depth!")); - msg.mBox()->setStandardButtons(QMessageBox::Ok); - msg.mBox()->setIcon(QMessageBox::Warning); - msg.exec(); -} - -void MainWindow::hardware_connect_failed() -{ - _session.stop_capture(); - dialogs::DSMessageBox msg(this); - msg.mBox()->setText(tr("Hardware Connect Failed")); - msg.mBox()->setInformativeText(tr("Please check hardware connection!")); - msg.mBox()->setStandardButtons(QMessageBox::Ok); - msg.mBox()->setIcon(QMessageBox::Warning); - msg.exec(); + _session.clear_error(); } void MainWindow::capture_state_changed(int state) { - _file_bar->enable_toggle(state != SigSession::Running); - _sampling_bar->set_sampling(state == SigSession::Running); - _view->on_state_changed(state != SigSession::Running); + 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) { - _sampling_bar->enable_toggle(state != SigSession::Running); - _trig_bar->enable_toggle(state != SigSession::Running); - _measure_dock->widget()->setEnabled(state != SigSession::Running); + if (_session.get_device()->dev_inst()->mode != DSO) { + _sampling_bar->enable_toggle(state != SigSession::Running); + _trig_bar->enable_toggle(state != SigSession::Running); + //_measure_dock->widget()->setEnabled(state != SigSession::Running); + _measure_widget->refresh(); + } } -#ifdef TEST_MODE if (state == SigSession::Stopped) { - test_timer.start(qrand()%1000); + prgRate(0); + _view->repeat_unshow(); } -#endif } void MainWindow::session_save() @@ -542,8 +595,9 @@ void MainWindow::session_save() QString mode_name = QString::number(_session.get_device()->dev_inst()->mode); QString file_name = dir.absolutePath() + "/" + driver_name + mode_name + ".dsc"; if (strncmp(driver_name.toLocal8Bit(), "virtual", 7) && - !file_name.isEmpty()) + !file_name.isEmpty()) { store_session(file_name); + } } } @@ -629,35 +683,21 @@ void MainWindow::on_screenShot() void MainWindow::on_save() { using pv::dialogs::StoreProgress; + StoreProgress *dlg = new StoreProgress(_session, this); + dlg->save_run(); +} - const QString DIR_KEY("SavePath"); - QSettings settings; - - // Stop any currently running capture session - _session.stop_capture(); - - // Show the dialog - const QString file_name = QFileDialog::getSaveFileName( - this, tr("Save File"), settings.value(DIR_KEY).toString(), tr("DSView Data (*.dsl)")); - - if (file_name.isEmpty()) - return; - QDir CurrentDir; - settings.setValue(DIR_KEY, CurrentDir.absoluteFilePath(file_name)); - StoreProgress *dlg = new StoreProgress(file_name, _session, this); - dlg->run(); +void MainWindow::on_export() +{ + using pv::dialogs::StoreProgress; + StoreProgress *dlg = new StoreProgress(_session, this); + dlg->export_run(); } bool MainWindow::load_session(QString name) { QFile sessionFile(name); if (!sessionFile.open(QIODevice::ReadOnly)) { -// dialogs::DSMessageBox msg(this); -// msg.mBox()->setText(tr("File Error")); -// msg.mBox()->setInformativeText(tr("Couldn't open session file!")); -// msg.mBox()->setStandardButtons(QMessageBox::Ok); -// msg.mBox()->setIcon(QMessageBox::Warning); -// msg.exec(); qDebug("Warning: Couldn't open session file!"); return false; } @@ -666,6 +706,11 @@ bool MainWindow::load_session(QString name) QJsonDocument sessionDoc = QJsonDocument::fromJson(sessionData.toUtf8()); QJsonObject sessionObj = sessionDoc.object(); + // check session file version + if (!sessionObj.contains("Version") || + sessionObj["Version"].toInt() != Session_Version) + return false; + // check device and mode const sr_dev_inst *const sdi = _session.get_device()->dev_inst(); if (strcmp(sdi->driver->name, sessionObj["Device"].toString().toLocal8Bit()) != 0 || @@ -729,6 +774,9 @@ bool MainWindow::load_session(QString name) if (!isEnabled) probe->enabled = false; } + _sampling_bar->update_record_length(); + _trigger_widget->device_updated(); + //_session.init_signals(); _session.reload(); @@ -749,7 +797,7 @@ bool MainWindow::load_session(QString name) boost::shared_ptr dsoSig; if (dsoSig = dynamic_pointer_cast(s)) { dsoSig->load_settings(); - dsoSig->set_zero_vrate(obj["zeroPos"].toDouble()); + dsoSig->set_zero_vrate(obj["zeroPos"].toDouble(), true); dsoSig->set_trig_vrate(obj["trigValue"].toDouble()); dsoSig->commit_settings(); } @@ -763,6 +811,16 @@ bool MainWindow::load_session(QString name) _trigger_widget->set_session(sessionObj["trigger"].toObject()); } on_trigger(false); + + #ifdef ENABLE_DECODE + // load decoders + if (sessionObj.contains("decoder")) { + StoreSession ss(_session); + ss.load_decoders(_protocol_widget, sessionObj["decoder"].toArray()); + } + #endif + + return true; } bool MainWindow::store_session(QString name) @@ -787,8 +845,8 @@ bool MainWindow::store_session(QString name) gsize num_opts; const sr_dev_inst *const sdi = _session.get_device()->dev_inst(); QJsonObject sessionVar; - QJsonObject triggerVar; QJsonArray channelVar; + sessionVar["Version"]= QJsonValue::fromVariant(Session_Version); sessionVar["Device"] = QJsonValue::fromVariant(sdi->driver->name); sessionVar["DeviceMode"] = QJsonValue::fromVariant(sdi->mode); @@ -844,6 +902,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 QJsonDocument sessionDoc(sessionVar); //sessionFile.write(QString::fromUtf8(sessionDoc.toJson())); @@ -888,11 +950,11 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) break; case Qt::Key_PageUp: _view->set_scale_offset(_view->scale(), - _view->offset() - _view->scale()*_view->get_view_width()); + _view->offset() - _view->get_view_width()); break; case Qt::Key_PageDown: _view->set_scale_offset(_view->scale(), - _view->offset() + _view->scale()*_view->get_view_width()); + _view->offset() + _view->get_view_width()); break; case Qt::Key_Left: diff --git a/DSView/pv/mainwindow.h b/DSView/pv/mainwindow.h index a8e73564..9b3c3284 100644 --- a/DSView/pv/mainwindow.h +++ b/DSView/pv/mainwindow.h @@ -27,7 +27,6 @@ #include #include -#include #include "sigsession.h" @@ -59,10 +58,6 @@ class MeasureDock; class SearchDock; } -namespace dialogs{ -class Calibration; -} - namespace view { class View; } @@ -71,6 +66,9 @@ class MainWindow : public QMainWindow { Q_OBJECT +private: + static constexpr int Session_Version = 2; + public: explicit MainWindow(DeviceManager &device_manager, const char *open_file_name = NULL, @@ -100,8 +98,6 @@ private slots: */ void update_device_list(); - void mode_changed(); - void reload(); void show_session_error( @@ -111,10 +107,6 @@ private slots: void instant_stop(); - void test_data_error(); - - void malloc_error(); - void capture_state_changed(int state); void on_protocol(bool visible); @@ -131,9 +123,16 @@ private slots: void on_save(); + void on_export(); + bool load_session(QString name); bool store_session(QString name); + /* + * repeat + */ + void repeat_resume(); + /* * hotplug slot function */ @@ -143,7 +142,9 @@ private slots: /* * errors */ - void hardware_connect_failed(); + void show_error(); +signals: + void prgRate(int progress); private: DeviceManager &_device_manager; @@ -187,9 +188,6 @@ private: dock::MeasureDock *_measure_widget; QDockWidget *_search_dock; dock::SearchDock * _search_widget; - - QTimer test_timer; - bool test_timer_linked; }; } // namespace pv diff --git a/DSView/pv/prop/binding/binding.cpp b/DSView/pv/prop/binding/binding.cpp index 95fe443f..d778fd5f 100644 --- a/DSView/pv/prop/binding/binding.cpp +++ b/DSView/pv/prop/binding/binding.cpp @@ -79,6 +79,20 @@ QWidget* Binding::get_property_form(QWidget *parent, return form; } +std::map< boost::shared_ptr, + GVariant* > Binding::get_property_value() const +{ + std::map < boost::shared_ptr, + GVariant* > pvalue; + BOOST_FOREACH(shared_ptr p, _properties) + { + assert(p); + pvalue[p] = p->get_value(); + } + + return pvalue; +} + QString Binding::print_gvariant(GVariant *const gvar) { QString s; diff --git a/DSView/pv/prop/binding/binding.h b/DSView/pv/prop/binding/binding.h index ca1462c2..8b413e05 100644 --- a/DSView/pv/prop/binding/binding.h +++ b/DSView/pv/prop/binding/binding.h @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -54,6 +55,9 @@ public: QWidget* get_property_form(QWidget *parent, bool auto_commit = false) const; + std::map< boost::shared_ptr, + GVariant* > get_property_value() const; + static QString print_gvariant(GVariant *const gvar); protected: diff --git a/DSView/pv/prop/binding/decoderoptions.cpp b/DSView/pv/prop/binding/decoderoptions.cpp index c9005bb4..66870403 100644 --- a/DSView/pv/prop/binding/decoderoptions.cpp +++ b/DSView/pv/prop/binding/decoderoptions.cpp @@ -18,7 +18,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include +#include #include "decoderoptions.h" diff --git a/DSView/pv/prop/binding/decoderoptions.h b/DSView/pv/prop/binding/decoderoptions.h index 18a9d67c..62d91ec3 100644 --- a/DSView/pv/prop/binding/decoderoptions.h +++ b/DSView/pv/prop/binding/decoderoptions.h @@ -45,14 +45,16 @@ public: DecoderOptions(boost::shared_ptr decoder_stack, boost::shared_ptr decoder); + GVariant* getter(const char *id); + + void setter(const char *id, GVariant *value); + private: static boost::shared_ptr bind_enum(const QString &name, const srd_decoder_option *option, Property::Getter getter, Property::Setter setter); - GVariant* getter(const char *id); - void setter(const char *id, GVariant *value); private: boost::shared_ptr _decoder_stack; diff --git a/DSView/pv/prop/binding/binding_deviceoptions.cpp b/DSView/pv/prop/binding/deviceoptions.cpp similarity index 98% rename from DSView/pv/prop/binding/binding_deviceoptions.cpp rename to DSView/pv/prop/binding/deviceoptions.cpp index ea9a3c99..9e7e2585 100644 --- a/DSView/pv/prop/binding/binding_deviceoptions.cpp +++ b/DSView/pv/prop/binding/deviceoptions.cpp @@ -87,6 +87,7 @@ DeviceOptions::DeviceOptions(struct sr_dev_inst *sdi) : case SR_CONF_COUPLING: case SR_CONF_EN_CH: case SR_CONF_OPERATION_MODE: + case SR_CONF_BUFFER_OPTIONS: case SR_CONF_THRESHOLD: case SR_CONF_ZERO: case SR_CONF_STREAM: @@ -141,7 +142,7 @@ GVariant* DeviceOptions::config_getter( } void DeviceOptions::config_setter( - const struct sr_dev_inst *sdi, int key, GVariant* value) + struct sr_dev_inst *sdi, int key, GVariant* value) { if (sr_config_set(sdi, NULL, NULL, key, value) != SR_OK) qDebug() << "WARNING: Failed to set value of sample rate"; diff --git a/DSView/pv/prop/binding/deviceoptions.h b/DSView/pv/prop/binding/deviceoptions.h index f9f8d42b..709baf05 100644 --- a/DSView/pv/prop/binding/deviceoptions.h +++ b/DSView/pv/prop/binding/deviceoptions.h @@ -47,7 +47,7 @@ private: static GVariant* config_getter( const struct sr_dev_inst *sdi, int key); static void config_setter( - const struct sr_dev_inst *sdi, int key, GVariant* value); + struct sr_dev_inst *sdi, int key, GVariant* value); void bind_bool(const QString &name, int key); void bind_enum(const QString &name, int key, diff --git a/DSView/pv/prop/bool.cpp b/DSView/pv/prop/bool.cpp index 2dd84890..f51fc4cb 100644 --- a/DSView/pv/prop/bool.cpp +++ b/DSView/pv/prop/bool.cpp @@ -69,6 +69,13 @@ bool Bool::labeled_widget() const return true; } +GVariant* Bool::get_value() const +{ + GVariant *const value = _getter ? _getter() : NULL; + + return value; +} + void Bool::commit() { assert(_setter); diff --git a/DSView/pv/prop/bool.h b/DSView/pv/prop/bool.h index a1b3e2f6..ec69217e 100644 --- a/DSView/pv/prop/bool.h +++ b/DSView/pv/prop/bool.h @@ -42,6 +42,8 @@ public: QWidget* get_widget(QWidget *parent, bool auto_commit); bool labeled_widget() const; + GVariant* get_value() const; + void commit(); private slots: diff --git a/DSView/pv/prop/property.cpp b/DSView/pv/prop/property.cpp index af793309..af37d644 100644 --- a/DSView/pv/prop/property.cpp +++ b/DSView/pv/prop/property.cpp @@ -42,5 +42,10 @@ bool Property::labeled_widget() const return false; } +GVariant* Property::get_value() const +{ + return NULL; +} + } // prop } // pv diff --git a/DSView/pv/prop/property.h b/DSView/pv/prop/property.h index 3a1b165f..117ba9a1 100644 --- a/DSView/pv/prop/property.h +++ b/DSView/pv/prop/property.h @@ -53,6 +53,8 @@ public: bool auto_commit = false) = 0; virtual bool labeled_widget() const; + virtual GVariant* get_value() const; + virtual void commit() = 0; protected: diff --git a/DSView/pv/sigsession.cpp b/DSView/pv/sigsession.cpp index 805be2d8..d071c9a1 100644 --- a/DSView/pv/sigsession.cpp +++ b/DSView/pv/sigsession.cpp @@ -21,7 +21,7 @@ */ #ifdef ENABLE_DECODE -#include +#include #endif #include "sigsession.h" @@ -89,7 +89,13 @@ SigSession* SigSession::_session = NULL; SigSession::SigSession(DeviceManager &device_manager) : _device_manager(device_manager), _capture_state(Init), - _instant(false) + _instant(false), + _error(No_err), + _run_mode(Single), + _repeat_intvl(1), + _repeating(false), + _repeat_hold_prg(0), + _map_zoom(0) { // TODO: This should not be necessary _session = this; @@ -99,11 +105,11 @@ SigSession::SigSession(DeviceManager &device_manager) : register_hotplug_callback(); _view_timer.stop(); _noData_cnt = 0; - _refresh_timer.stop(); - _refresh_timer.setSingleShot(true); _data_lock = false; _data_updated = false; + #ifdef ENABLE_DECODE _decoder_model = new pv::data::DecoderModel(this); + #endif // Create snapshots & data containers _cur_logic_snapshot.reset(new data::LogicSnapshot()); @@ -119,12 +125,6 @@ SigSession::SigSession(DeviceManager &device_manager) : _group_cnt = 0; connect(&_view_timer, SIGNAL(timeout()), this, SLOT(check_update())); - connect(&_refresh_timer, SIGNAL(timeout()), this, SLOT(data_unlock())); - - #ifdef TEST_MODE - _test_timer.setSingleShot(true); - connect(&_test_timer, SIGNAL(timeout()), this, SLOT(stop_capture())); - #endif } SigSession::~SigSession() @@ -172,6 +172,11 @@ void SigSession::set_device(boost::shared_ptr dev_inst) throw(Q _dev_inst->use(this); _cur_samplerate = _dev_inst->get_sample_rate(); _cur_samplelimits = _dev_inst->get_sample_limit(); + + if (_dev_inst->dev_inst()->mode == DSO) + set_run_mode(Repetitive); + else + set_run_mode(Single); } catch(const QString e) { throw(e); return; @@ -200,222 +205,6 @@ void SigSession::set_file(QString name) throw(QString) } } -void SigSession::save_file(const QString name, QWidget* parent, int type){ - unsigned char* data; - int unit_size; - uint64_t sample_count; - if (type == ANALOG) { - const deque< boost::shared_ptr > &snapshots = - _analog_data->get_snapshots(); - if (snapshots.empty()) - return; - const boost::shared_ptr &snapshot = - snapshots.front(); - data = (unsigned char*)snapshot->get_data(); - unit_size = snapshot->unit_size(); - sample_count = snapshot->get_sample_count(); - } else if (type == DSO) { - const deque< boost::shared_ptr > &snapshots = - _dso_data->get_snapshots(); - if (snapshots.empty()) - return; - const boost::shared_ptr &snapshot = - snapshots.front(); - data = (unsigned char*)snapshot->get_data(); - // snapshot->unit_size() is not valid for dso, replaced by enabled channel number - unit_size = get_ch_num(SR_CHANNEL_DSO); - sample_count = snapshot->get_sample_count(); - } else { - const deque< boost::shared_ptr > &snapshots = - _logic_data->get_snapshots(); - if (snapshots.empty()) - return; - const boost::shared_ptr &snapshot = - snapshots.front(); - data = (unsigned char*)snapshot->get_data(); - unit_size = snapshot->unit_size(); - sample_count = snapshot->get_sample_count(); - } - - QFuture future; - future = QtConcurrent::run([&]{ - sr_session_save(name.toLocal8Bit().data(), _dev_inst->dev_inst(), - data, unit_size, sample_count, _trigger_time.toMSecsSinceEpoch(), _trigger_pos); - }); - Qt::WindowFlags flags = Qt::CustomizeWindowHint; - QProgressDialog dlg(tr("Saving capture to file... this can take a while."), - tr("Cancel"),0,0,parent,flags); - dlg.setWindowModality(Qt::WindowModal); - dlg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint); - dlg.setCancelButton(NULL); - - QFutureWatcher watcher; - watcher.setFuture(future); - connect(&watcher,SIGNAL(finished()),&dlg,SLOT(cancel())); - - dlg.exec(); -} - -QList SigSession::getSuportedExportFormats(){ - const struct sr_output_module** supportedModules = sr_output_list(); - QList list; - while(*supportedModules){ - if(*supportedModules == NULL) - break; - if (_dev_inst->dev_inst()->mode == DSO && strcmp((*supportedModules)->id, "csv")) - break; - QString format((*supportedModules)->desc); - format.append(" (*."); - format.append((*supportedModules)->id); - format.append(")"); - list.append(format); - supportedModules++; - } - return list; -} - -void SigSession::cancelSaveFile(){ - saveFileThreadRunning = false; -} - -void SigSession::export_file(const QString name, QWidget* parent, const QString ext){ - boost::shared_ptr snapshot; - int channel_type; - - if (_dev_inst->dev_inst()->mode == LOGIC) { - const deque< boost::shared_ptr > &snapshots = - _logic_data->get_snapshots(); - if(snapshots.empty()) - return; - snapshot = snapshots.front(); - channel_type = SR_CHANNEL_LOGIC; - } else if (_dev_inst->dev_inst()->mode == DSO) { - const deque< boost::shared_ptr > &snapshots = - _dso_data->get_snapshots(); - if(snapshots.empty()) - return; - snapshot = snapshots.front(); - channel_type = SR_CHANNEL_DSO; - } else { - return; - } - - const struct sr_output_module** supportedModules = sr_output_list(); - const struct sr_output_module* outModule = NULL; - while(*supportedModules){ - if(*supportedModules == NULL) - break; - if(!strcmp((*supportedModules)->id, ext.toLocal8Bit().data())){ - outModule = *supportedModules; - break; - } - supportedModules++; - } - if(outModule == NULL) - return; - - - GHashTable *params = g_hash_table_new(g_str_hash, g_str_equal); - GVariant* filenameGVariant = g_variant_new_bytestring(name.toLocal8Bit().data()); - g_hash_table_insert(params, (char*)"filename", filenameGVariant); - GVariant* typeGVariant = g_variant_new_int16(channel_type); - g_hash_table_insert(params, (char*)"type", typeGVariant); - BOOST_FOREACH(const boost::shared_ptr s, _signals) { - boost::shared_ptr dsoSig; - if (dsoSig = dynamic_pointer_cast(s)) { - GVariant* timebaseGVariant = g_variant_new_uint64(dsoSig->get_hDialValue()); - g_hash_table_insert(params, (char*)"timebase", timebaseGVariant); - break; - } - } - - struct sr_output output; - output.module = (sr_output_module*) outModule; - output.sdi = _dev_inst->dev_inst(); - output.param = NULL; - if(outModule->init) - outModule->init(&output, params); - QFile file(name); - file.open(QIODevice::WriteOnly | QIODevice::Text); - QTextStream out(&file); - out.setCodec("UTF-8"); - out.setGenerateByteOrderMark(true); - QFuture future; - if (_dev_inst->dev_inst()->mode == LOGIC) { - future = QtConcurrent::run([&]{ - saveFileThreadRunning = true; - unsigned char* datat = (unsigned char*)snapshot->get_data(); - unsigned int numsamples = snapshot->get_sample_count()*snapshot->unit_size(); - GString *data_out; - unsigned int usize = 8192; - unsigned int size = usize; - struct sr_datafeed_logic lp; - struct sr_datafeed_packet p; - for(uint64_t i = 0; i < numsamples; i+=usize){ - if(numsamples - i < usize) - size = numsamples - i; - lp.data = &datat[i]; - lp.length = size; - lp.unitsize = snapshot->unit_size(); - p.type = SR_DF_LOGIC; - p.payload = &lp; - outModule->receive(&output, &p, &data_out); - if(data_out){ - out << QString::fromUtf8((char*) data_out->str); - g_string_free(data_out,TRUE); - } - emit progressSaveFileValueChanged(i*100/numsamples); - if(!saveFileThreadRunning) - break; - } - }); - } else if (_dev_inst->dev_inst()->mode == DSO) { - future = QtConcurrent::run([&]{ - saveFileThreadRunning = true; - unsigned char* datat = (unsigned char*)snapshot->get_data(); - unsigned int numsamples = snapshot->get_sample_count(); - GString *data_out; - unsigned int usize = 8192; - unsigned int size = usize; - struct sr_datafeed_dso dp; - struct sr_datafeed_packet p; - for(uint64_t i = 0; i < numsamples; i+=usize){ - if(numsamples - i < usize) - size = numsamples - i; - dp.data = &datat[i*snapshot->get_channel_num()]; - dp.num_samples = size; - p.type = SR_DF_DSO; - p.payload = &dp; - outModule->receive(&output, &p, &data_out); - if(data_out){ - out << (char*) data_out->str; - g_string_free(data_out,TRUE); - } - emit progressSaveFileValueChanged(i*100/numsamples); - if(!saveFileThreadRunning) - break; - } - }); - } - - QFutureWatcher watcher; - Qt::WindowFlags flags = Qt::CustomizeWindowHint; - QProgressDialog dlg(tr("Exporting data... this can take a while."), - tr("Cancel"),0,100,parent,flags); - dlg.setWindowModality(Qt::WindowModal); - watcher.setFuture(future); - connect(&watcher,SIGNAL(finished()),&dlg,SLOT(cancel())); - connect(this,SIGNAL(progressSaveFileValueChanged(int)),&dlg,SLOT(setValue(int))); - connect(&dlg,SIGNAL(canceled()),this,SLOT(cancelSaveFile())); - dlg.exec(); - future.waitForFinished(); - // optional, as QFile destructor will already do it: - file.close(); - outModule->cleanup(&output); - g_hash_table_destroy(params); - g_variant_unref(filenameGVariant); -} - void SigSession::set_default_device(boost::function error_handler) { boost::shared_ptr default_device; @@ -511,9 +300,13 @@ void SigSession::set_cur_samplelimits(uint64_t samplelimits) void SigSession::capture_init() { + if (!_instant) + set_repeating(get_run_mode() == Repetitive); _cur_samplerate = _dev_inst->get_sample_rate(); _cur_samplelimits = _dev_inst->get_sample_limit(); _data_updated = false; + _trigger_flag = false; + _hw_replied = false; if (_dev_inst->dev_inst()->mode != LOGIC) _view_timer.start(ViewTime); else @@ -522,11 +315,7 @@ void SigSession::capture_init() data_unlock(); // Init and Set sample rate for all SignalData - // Logic/Analog/Dso - if (_logic_data) { - _logic_data->init(); - _logic_data->set_samplerate(_cur_samplerate); - } + // Analog/Dso if (_analog_data) { _analog_data->init(); _analog_data->set_samplerate(_cur_samplerate); @@ -535,12 +324,42 @@ void SigSession::capture_init() _dso_data->init(); _dso_data->set_samplerate(_cur_samplerate); } + + // MathStack + BOOST_FOREACH(const boost::shared_ptr m, _math_traces) + { + assert(m); + m->get_math_stack()->init(); + m->get_math_stack()->set_samplerate(_cur_samplerate); + } + + // update current hw offset + BOOST_FOREACH(const boost::shared_ptr s, _signals) + { + assert(s); + boost::shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(s)) { + dsoSig->set_zero_vrate(dsoSig->get_zero_vrate(), true); + } + } +} + +void SigSession::logic_init() +{ + // Logic + if (_logic_data) { + _logic_data->init(); + _logic_data->set_samplerate(_cur_samplerate); + } // Group if (_group_data) { _group_data->init(); _group_data->set_samplerate(_cur_samplerate); } #ifdef ENABLE_DECODE + // DecoderModel + pv::data::DecoderModel *decoder_model = get_decoder_model(); + decoder_model->setDecoderStack(NULL); // DecoderStack BOOST_FOREACH(const boost::shared_ptr d, _decode_traces) { @@ -549,29 +368,36 @@ void SigSession::capture_init() d->decoder()->set_samplerate(_cur_samplerate); } #endif - // MathStack - BOOST_FOREACH(const boost::shared_ptr m, _math_traces) - { - assert(m); - m->get_math_stack()->init(); - m->get_math_stack()->set_samplerate(_cur_samplerate); - } } void SigSession::start_capture(bool instant, boost::function error_handler) { - stop_capture(); - capture_init(); - - // Check that a device instance has been selected. + // Check that a device instance has been selected. if (!_dev_inst) { - qDebug() << "No device selected"; - return; - } - + qDebug() << "No device selected"; + capture_state_changed(SigSession::Stopped); + return; + } assert(_dev_inst->dev_inst()); + if (!_dev_inst->is_usable()) { + _error = Hw_err; + session_error(); + capture_state_changed(SigSession::Stopped); + return; + } + + // stop previous capture + stop_capture(); + + // update setting + if (_dev_inst->name() != "virtual-session") + _instant = instant; + else + _instant = true; + capture_init(); + // Check that at least one probe is enabled const GSList *l; for (l = _dev_inst->dev_inst()->channels; l; l = l->next) { @@ -583,16 +409,11 @@ void SigSession::start_capture(bool instant, if (!l) { error_handler(tr("No probes enabled.")); data_updated(); + set_repeating(false); capture_state_changed(SigSession::Stopped); return; } - // update setting - if (_dev_inst->name() != "virtual-session") - _instant = instant; - else - _instant = true; - // Begin the session _sampling_thread.reset(new boost::thread( &SigSession::sample_thread_proc, this, _dev_inst, @@ -619,6 +440,30 @@ void SigSession::stop_capture() _sampling_thread.reset(); } +bool SigSession::get_capture_status(bool &triggered, int &progress) +{ + uint64_t sample_limits = cur_samplelimits(); + sr_status status; + if (sr_status_get(_dev_inst->dev_inst(), &status, SR_STATUS_TRIG_BEGIN, SR_STATUS_TRIG_END) == SR_OK){ + triggered = status.trig_hit & 0x01; + const bool captured_cnt_dec = status.trig_hit & 0x02; + uint64_t captured_cnt = status.trig_hit >> 2; + captured_cnt = ((uint64_t)status.captured_cnt0 + + ((uint64_t)status.captured_cnt1 << 8) + + ((uint64_t)status.captured_cnt2 << 16) + + ((uint64_t)status.captured_cnt3 << 24) + + (captured_cnt << 32)); + if (_dev_inst->dev_inst()->mode == DSO) + captured_cnt = captured_cnt * _signals.size() / get_ch_num(SR_CHANNEL_DSO); + if (captured_cnt_dec) + progress = (sample_limits - captured_cnt) * 100.0 / sample_limits; + else + progress = captured_cnt * 100.0 / sample_limits; + return true; + } + return false; +} + vector< boost::shared_ptr > SigSession::get_signals() { //boost::lock_guard lock(_signals_mutex); @@ -648,47 +493,6 @@ bool SigSession::get_instant() return _instant; } -const void* SigSession::get_buf(int& unit_size, uint64_t &length) -{ - if (_dev_inst->dev_inst()->mode == LOGIC) { - const deque< boost::shared_ptr > &snapshots = - _logic_data->get_snapshots(); - if (snapshots.empty()) - return NULL; - - const boost::shared_ptr &snapshot = - snapshots.front(); - - unit_size = snapshot->unit_size(); - length = snapshot->get_sample_count(); - return snapshot->get_data(); - } else if (_dev_inst->dev_inst()->mode == DSO) { - const deque< boost::shared_ptr > &snapshots = - _dso_data->get_snapshots(); - if (snapshots.empty()) - return NULL; - - const boost::shared_ptr &snapshot = - snapshots.front(); - - unit_size = snapshot->unit_size(); - length = snapshot->get_sample_count(); - return snapshot->get_data(); - } else { - const deque< boost::shared_ptr > &snapshots = - _analog_data->get_snapshots(); - if (snapshots.empty()) - return NULL; - - const boost::shared_ptr &snapshot = - snapshots.front(); - - unit_size = snapshot->unit_size(); - length = snapshot->get_sample_count(); - return snapshot->get_data(); - } -} - void SigSession::set_capture_state(capture_state state) { boost::lock_guard lock(_sampling_mutex); @@ -733,10 +537,6 @@ void SigSession::check_update() data_updated(); _data_updated = false; _noData_cnt = 0; - #ifdef TEST_MODE - if (!_test_timer.isActive()) - _test_timer.start(qrand()%5000); - #endif } else { if (++_noData_cnt >= (WaitShowTime/ViewTime)) nodata_timeout(); @@ -947,24 +747,26 @@ void SigSession::reload() } break; - case SR_CHANNEL_DSO: - signal = boost::shared_ptr( - new view::DsoSignal(_dev_inst,_dso_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) - signal = boost::shared_ptr( - new view::AnalogSignal(_dev_inst, _analog_data, probe)); - break; +// case SR_CHANNEL_ANALOG: +// if (probe->enabled) +// signal = boost::shared_ptr( +// new view::AnalogSignal(_dev_inst, _analog_data, probe)); +// break; } if (signal.get()) sigs.push_back(signal); } - _signals.clear(); - vector< boost::shared_ptr >().swap(_signals); - _signals = sigs; + if (!sigs.empty()) { + _signals.clear(); + vector< boost::shared_ptr >().swap(_signals); + _signals = sigs; + } } mathTraces_rebuild(); @@ -975,7 +777,7 @@ void SigSession::refresh(int holdtime) boost::lock_guard lock(_data_mutex); _data_lock = true; - _refresh_timer.start(holdtime); + QTimer::singleShot(holdtime, this, SLOT(data_unlock())); if (_logic_data) { _logic_data->init(); @@ -1057,9 +859,13 @@ void SigSession::feed_in_meta(const sr_dev_inst *sdi, void SigSession::feed_in_trigger(const ds_trigger_pos &trigger_pos) { + _hw_replied = true; if (_dev_inst->dev_inst()->mode != DSO) { - _trigger_pos = trigger_pos.real_pos; - receive_trigger(_trigger_pos); + _trigger_flag = (trigger_pos.status & 0x01); + if (_trigger_flag) { + _trigger_pos = trigger_pos.real_pos; + receive_trigger(_trigger_pos); + } if (_dev_inst->name() != "virtual-session") { const double time = trigger_pos.real_pos * 1.0 / _cur_samplerate; _trigger_time = QDateTime::currentDateTime(); @@ -1092,15 +898,14 @@ void SigSession::feed_in_logic(const sr_datafeed_logic &logic) } if (logic.data_error == 1) { - test_data_error(); + _error = Test_data_err; + _error_pattern = logic.error_pattern; + session_error(); } if (_cur_logic_snapshot->last_ended()) { - _cur_logic_snapshot->first_payload(logic, _dev_inst->get_sample_limit(), 1); - if (_cur_logic_snapshot->memory_failed()) { - malloc_error(); - return; - } + logic_init(); + _cur_logic_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 @@ -1111,7 +916,13 @@ void SigSession::feed_in_logic(const sr_datafeed_logic &logic) _cur_logic_snapshot->append_payload(logic); } - emit receive_data(logic.length/logic.unitsize); + if (_cur_logic_snapshot->memory_failed()) { + _error = Malloc_err; + session_error(); + return; + } + + emit receive_data(logic.length * 8 / get_ch_num(SR_CHANNEL_LOGIC)); data_received(); //data_updated(); _data_updated = true; @@ -1129,25 +940,30 @@ void SigSession::feed_in_dso(const sr_datafeed_dso &dso) if (_cur_dso_snapshot->last_ended()) { + std::map sig_enable; // reset scale 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_scale(dsoSig->get_view_rect().height() / 256.0f); + if (dsoSig = dynamic_pointer_cast(s)) { + dsoSig->set_scale(dsoSig->get_view_rect().height()); + sig_enable[dsoSig->get_index()] = dsoSig->enabled(); + } } // first payload - _cur_dso_snapshot->first_payload(dso, _dev_inst->get_sample_limit(), get_ch_num(SR_CHANNEL_DSO), _instant); - if (_cur_dso_snapshot->memory_failed()) { - malloc_error(); - return; - } + _cur_dso_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); } + if (_cur_dso_snapshot->memory_failed()) { + _error = Malloc_err; + session_error(); + return; + } + // calculate related math results BOOST_FOREACH(const boost::shared_ptr m, _math_traces) { @@ -1175,16 +991,18 @@ void SigSession::feed_in_analog(const sr_datafeed_analog &analog) if (_cur_analog_snapshot->last_ended()) { // first payload - _cur_analog_snapshot->first_payload(analog, _dev_inst->get_sample_limit(), get_ch_num(SR_CHANNEL_ANALOG)); - if (_cur_analog_snapshot->memory_failed()) { - malloc_error(); - return; - } + _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); } + if (_cur_analog_snapshot->memory_failed()) { + _error = Malloc_err; + session_error(); + return; + } + receive_data(analog.num_samples); //data_updated(); _data_updated = true; @@ -1200,6 +1018,12 @@ void SigSession::data_feed_in(const struct sr_dev_inst *sdi, if (_data_lock) return; + if (packet->type != SR_DF_END && + packet->status != SR_PKT_OK) { + _error = Pkt_data_err; + session_error(); + return; + } switch (packet->type) { case SR_DF_HEADER: @@ -1232,6 +1056,12 @@ void SigSession::data_feed_in(const struct sr_dev_inst *sdi, feed_in_analog(*(const sr_datafeed_analog*)packet->payload); break; + case SR_DF_OVERFLOW: + { + _error = Data_overflow; + session_error(); + break; + } case SR_DF_END: { { @@ -1247,14 +1077,22 @@ void SigSession::data_feed_in(const struct sr_dev_inst *sdi, _cur_group_snapshot.reset(); } } - _cur_logic_snapshot->set_last_ended(true); - _cur_dso_snapshot->set_last_ended(true); - _cur_analog_snapshot->set_last_ended(true); + if (!_cur_logic_snapshot->last_ended()) + _cur_logic_snapshot->capture_ended(); + else if (get_run_mode() != SigSession::Repetitive) + logic_init(); + _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) { + _error = Pkt_data_err; + session_error(); + } frame_ended(); break; } @@ -1403,14 +1241,13 @@ uint16_t SigSession::get_ch_num(int type) } #ifdef ENABLE_DECODE -bool SigSession::add_decoder(srd_decoder *const dec) +bool SigSession::add_decoder(srd_decoder *const dec, bool silent) { bool ret = false; - map > probes; + map probes; boost::shared_ptr decoder_stack; - try - { + try { //lock_guard lock(_signals_mutex); // Create the decoder @@ -1440,13 +1277,14 @@ bool SigSession::add_decoder(srd_decoder *const dec) break; } } - if (d->create_popup()) { + if (silent) { + _decode_traces.push_back(d); + ret = true; + } else if (d->create_popup()) { _decode_traces.push_back(d); ret = true; } - } - catch(std::runtime_error e) - { + } catch(std::runtime_error e) { return false; } @@ -1604,4 +1442,117 @@ void SigSession::nodata_timeout() } } +boost::shared_ptr SigSession::get_snapshot(int type) +{ + if (type == SR_CHANNEL_LOGIC) + return _cur_logic_snapshot; + else if (type == SR_CHANNEL_ANALOG) + return _cur_analog_snapshot; + else if (type == SR_CHANNEL_DSO) + return _cur_dso_snapshot; + else + return NULL; +} + +SigSession::error_state SigSession::get_error() const +{ + return _error; +} + +void SigSession::set_error(error_state state) +{ + _error = state; +} + +void SigSession::clear_error() +{ + _error_pattern = 0; + _error = No_err; +} + +uint64_t SigSession::get_error_pattern() const +{ + return _error_pattern; +} + +SigSession::run_mode SigSession::get_run_mode() const +{ + return _run_mode; +} + +void SigSession::set_run_mode(run_mode mode) +{ + _run_mode = mode; +} + +int SigSession::get_repeat_intvl() const +{ + return _repeat_intvl; +} + +void SigSession::set_repeat_intvl(int interval) +{ + _repeat_intvl = interval; +} + +void SigSession::set_repeating(bool repeat) +{ + _repeating = repeat; + if (!_repeating) + _repeat_hold_prg = 0; +} + +bool SigSession::isRepeating() const +{ + return _repeating; +} + +bool SigSession::repeat_check() +{ + if (get_capture_state() != Stopped || + get_run_mode() != Repetitive || + !isRepeating()) { + return false; + } + + 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())); + return true; + } else { + return true; + } +} + +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) + repeat_resume(); + } +} + +int SigSession::get_repeat_hold() const +{ + if (isRepeating()) + return _repeat_hold_prg; + else + return 0; +} + +void SigSession::set_map_zoom(int index) +{ + _map_zoom = index; +} + +int SigSession::get_map_zoom() const +{ + return _map_zoom; +} + } // namespace pv diff --git a/DSView/pv/sigsession.h b/DSView/pv/sigsession.h index 59cf3327..6b9e33c0 100644 --- a/DSView/pv/sigsession.h +++ b/DSView/pv/sigsession.h @@ -59,6 +59,7 @@ class DeviceManager; namespace data { class SignalData; +class Snapshot; class Analog; class AnalogSnapshot; class Dso; @@ -93,7 +94,7 @@ class SigSession : public QObject private: static constexpr float Oversampling = 2.0f; static const int RefreshTime = 500; - bool saveFileThreadRunning = false; + static const int RepeatHoldDiv = 20; public: static const int ViewTime = 50; @@ -106,6 +107,21 @@ public: Running }; + enum run_mode { + Single, + Repetitive + }; + + enum error_state { + No_err, + Hw_err, + Malloc_err, + Test_data_err, + Test_timeout_err, + Pkt_data_err, + Data_overflow + }; + public: SigSession(DeviceManager &device_manager); @@ -122,10 +138,7 @@ public: void set_file(QString name) throw(QString); - void save_file(const QString name, QWidget* parent, int type); - void set_default_device(boost::function error_handler); - void export_file(const QString name, QWidget* parent, const QString ext); void release_device(device::DevInst *dev_inst); @@ -142,6 +155,8 @@ public: void start_capture(bool instant, boost::function error_handler); void capture_init(); + bool get_capture_status(bool &triggered, int &progress); + void logic_init(); std::set< boost::shared_ptr > get_data() const; @@ -150,10 +165,9 @@ public: std::vector< boost::shared_ptr > get_group_signals(); - QList getSuportedExportFormats(); #ifdef ENABLE_DECODE - bool add_decoder(srd_decoder *const dec); + bool add_decoder(srd_decoder *const dec, bool silent); std::vector< boost::shared_ptr > get_decode_signals() const; @@ -167,20 +181,17 @@ public: void rst_decoder(view::DecodeTrace *signal); pv::data::DecoderModel* get_decoder_model() const; +#endif std::vector< boost::shared_ptr > get_math_signals(); -#endif - void init_signals(); void add_group(); void del_group(); - const void* get_buf(int& unit_size, uint64_t& length); - void start_hotplug_proc(boost::function error_handler); void stop_hotplug_proc(); void register_hotplug_callback(); @@ -195,6 +206,23 @@ public: bool trigd() const; + boost::shared_ptr get_snapshot(int type); + + error_state get_error() const; + void set_error(error_state state); + void clear_error(); + uint64_t get_error_pattern() const; + + run_mode get_run_mode() const; + void set_run_mode(run_mode mode); + int get_repeat_intvl() const; + void set_repeat_intvl(int interval); + bool isRepeating() const; + bool repeat_check(); + int get_repeat_hold() const; + + int get_map_zoom() const; + private: void set_capture_state(capture_state state); @@ -278,17 +306,23 @@ private: QTimer _view_timer; int _noData_cnt; - QTimer _refresh_timer; bool _data_lock; bool _data_updated; - #ifdef TEST_MODE - QTimer _test_timer; - #endif - QDateTime _trigger_time; uint64_t _trigger_pos; bool _trigger_flag; + 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; signals: void capture_state_changed(int state); @@ -297,15 +331,11 @@ signals: void data_updated(); - void start_timer(int); - void receive_data(quint64 length); void device_attach(); void device_detach(); - void test_data_error(); - void receive_trigger(quint64 trigger_pos); void receive_header(); @@ -320,31 +350,35 @@ signals: void device_setted(); - void malloc_error(); - void zero_adj(); void progressSaveFileValueChanged(int percent); void decode_done(); - void show_region(uint64_t start, uint64_t end); - - void hardware_connect_failed(); + void show_region(uint64_t start, uint64_t end, bool keep); void show_wait_trigger(); - void on_mode_change(); + void session_save(); + + void session_error(); + + void repeat_hold(int percent); + void repeat_resume(); public slots: void reload(); void refresh(int holdtime); void stop_capture(); + // repeat + void set_repeating(bool repeat); + void set_map_zoom(int index); private slots: - void cancelSaveFile(); void data_unlock(); void check_update(); void nodata_timeout(); + void repeat_update(); private: // TODO: This should not be necessary. Multiple concurrent diff --git a/DSView/pv/storesession.cpp b/DSView/pv/storesession.cpp index baac25c4..4f79f1bd 100644 --- a/DSView/pv/storesession.cpp +++ b/DSView/pv/storesession.cpp @@ -2,6 +2,7 @@ * This file is part of the PulseView project. * * Copyright (C) 2014 Joel Holdsworth + * Copyright (C) 2016 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 @@ -23,10 +24,22 @@ #include #include #include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include #include +#include + using boost::dynamic_pointer_cast; using boost::mutex; using boost::shared_ptr; @@ -42,14 +55,12 @@ using std::vector; namespace pv { -const size_t StoreSession::BlockSize = 1024 * 1024; - -StoreSession::StoreSession(const std::string &file_name, - SigSession &session) : - _file_name(file_name), +StoreSession::StoreSession(SigSession &session) : _session(session), + _outModule(NULL), _units_stored(0), - _unit_count(0) + _unit_count(0), + _has_error(false) { } @@ -70,132 +81,793 @@ const QString& StoreSession::error() const return _error; } -bool StoreSession::start() -{ - const vector< shared_ptr > sigs(_session.get_signals()); - set< boost::shared_ptr > data_set; - BOOST_FOREACH(const boost::shared_ptr sig, sigs) { - assert(sig); - data_set.insert(sig->data()); - } - - // Check we have logic data - if (data_set.empty() || sigs.empty()) { - _error = tr("No data to save."); - return false; - } - - if (data_set.size() > 1) { - _error = tr("DSView currently only has support for " - "storing a single data stream."); - return false; - } - - // Get the logic data - //shared_ptr data; - if (!(data = dynamic_pointer_cast(*data_set.begin()))) { - _error = tr("DSView currently only has support for " - "storing a logic data."); - return false; - } - - // Get the snapshot - const deque< shared_ptr > &snapshots = - data->get_snapshots(); - - if (snapshots.empty()) { - _error = tr("No snapshots to save."); - return false; - } - - const shared_ptr snapshot(snapshots.front()); - assert(snapshot); - - // Make a list of probes - char **const probes = new char*[sigs.size() + 1]; - for (size_t i = 0; i < sigs.size(); i++) { - shared_ptr sig(sigs[i]); - assert(sig); - probes[i] = strdup(sig->get_name().toUtf8().constData()); - } - probes[sigs.size()] = NULL; - - // Begin storing - if (sr_session_save_init(_file_name.c_str(), - data->samplerate(), probes) != SR_OK) { - _error = tr("Error while saving."); - return false; - } - - // Delete the probes array - for (size_t i = 0; i <= sigs.size(); i++) - free(probes[i]); - delete[] probes; - - _thread = boost::thread(&StoreSession::store_proc, this, snapshot); - return true; -} - void StoreSession::wait() { - if (_thread.joinable()) - _thread.join(); + if (_thread.joinable()) + _thread.join(); } void StoreSession::cancel() { - _thread.interrupt(); + _thread.interrupt(); } -void StoreSession::store_proc(shared_ptr snapshot) +QList StoreSession::getSuportedExportFormats(){ + const struct sr_output_module** supportedModules = sr_output_list(); + QList list; + while(*supportedModules){ + if(*supportedModules == NULL) + break; + if (_session.get_device()->dev_inst()->mode == DSO && strcmp((*supportedModules)->id, "csv")) + break; + QString format((*supportedModules)->desc); + format.append(" (*."); + format.append((*supportedModules)->id); + format.append(")"); + list.append(format); + supportedModules++; + } + return list; +} + +bool StoreSession::save_start() +{ + 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() > 1) { + _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; + } + + const boost::shared_ptr snapshot(_session.get_snapshot(*type_set.begin())); + assert(snapshot); + // Check we have data + if (snapshot->empty()) { + _error = tr("No data to save."); + return false; + } + + const QString DIR_KEY("SavePath"); + QSettings settings; + + // Show the dialog + _file_name = QFileDialog::getSaveFileName( + NULL, tr("Save File"), settings.value(DIR_KEY).toString(), + tr("DSView Data (*.dsl)")); + + if (!_file_name.isEmpty()) { + QFileInfo f(_file_name); + if(f.suffix().compare("dsl")) + _file_name.append(tr(".dsl")); + QDir CurrentDir; + settings.setValue(DIR_KEY, CurrentDir.absoluteFilePath(_file_name)); + + QString meta_file = meta_gen(snapshot); + #ifdef ENABLE_DECODE + QString decoders_file = decoders_gen(); + #else + QString decoders_file = NULL; + #endif + if (meta_file == NULL) { + _error = tr("Generate temp file failed."); + return false; + } else { + sr_session_save_init(_file_name.toLocal8Bit().data(), + meta_file.toLocal8Bit().data(), + decoders_file.toLocal8Bit().data()); + _thread = boost::thread(&StoreSession::save_proc, this, snapshot); + return !_has_error; + } + } + + _error.clear(); + return false; +} + +void StoreSession::save_proc(shared_ptr snapshot) { assert(snapshot); - uint64_t start_sample = 0; + shared_ptr logic_snapshot; + shared_ptr analog_snapshot; + shared_ptr dso_snapshot; - /// TODO: Wrap this in a std::unique_ptr when we transition to C++11 - uint8_t *data = NULL; - //uint8_t *const data = new uint8_t[BlockSize]; - //assert(data); + if (logic_snapshot = boost::dynamic_pointer_cast(snapshot)) { + uint16_t to_save_probes = 0; + BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + if (s->enabled() && logic_snapshot->has_data(s->get_index())) + to_save_probes++; + } + _unit_count = logic_snapshot->get_sample_count() / 8 * to_save_probes; + int num = logic_snapshot->get_block_num(); + bool sample; - const int unit_size = snapshot->unit_size(); - assert(unit_size != 0); - - { - //lock_guard lock(_mutex); - _unit_count = snapshot->get_sample_count(); - } - - const unsigned int samples_per_block = BlockSize / unit_size; - - while (!boost::this_thread::interruption_requested() && - start_sample < _unit_count) - { - progress_updated(); - - const uint64_t end_sample = min( - start_sample + samples_per_block, _unit_count); - data = snapshot->get_samples(start_sample, end_sample); - - if(sr_session_append(_file_name.c_str(), data, unit_size, - end_sample - start_sample) != SR_OK) - { - _error = tr("Error while saving."); - break; - } - - start_sample = end_sample; - - { - //lock_guard lock(_mutex); - _units_stored = start_sample; - } - } + 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(); + if (!s->enabled() || !logic_snapshot->has_data(ch_index)) + continue; + for (int i = 0; !boost::this_thread::interruption_requested() && 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); + if (need_malloc) { + buf = (uint8_t *)malloc(size); + if (buf == NULL) { + _has_error = true; + _error = tr("Malloc failed."); + return; + } + memset(buf, sample ? 0xff : 0x0, size); + } + sr_session_append(_file_name.toLocal8Bit().data(), buf, size, + i, ch_index, ch_type, File_Version); + _units_stored += size; + if (need_malloc) + free(buf); + progress_updated(); + } + } + } + } else { + int ch_type = -1; + BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + ch_type = s->get_type(); + break; + } + if (ch_type != -1) { + uint64_t size = snapshot->get_sample_count() * snapshot->get_channel_num(); + uint8_t *buf = (uint8_t *)snapshot->get_data(); + sr_session_append(_file_name.toLocal8Bit().data(), buf, size, + 0, 0, ch_type, 1); + } + } progress_updated(); +} - //delete[] data; +QString StoreSession::meta_gen(boost::shared_ptr snapshot) +{ + GSList *l; + GVariant *gvar; + FILE *meta; + struct sr_channel *probe; + int probecnt; + char *s; + struct sr_status status; + QString metafile; + + /* 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.toLocal8Bit().data(), "wb"); + fprintf(meta, "[version]\n"); + if (sdi->mode == DSO) + fprintf(meta, "version = %d\n", 1); // should be updated in next version + else + 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); + } + + /* metadata */ + fprintf(meta, "capturefile = data\n"); + fprintf(meta, "total samples = %" PRIu64 "\n", snapshot->get_sample_count()); + + if (sdi->mode == DSO) + fprintf(meta, "total probes = %d\n", g_slist_length(sdi->channels)); + + 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) { + probe = (struct sr_channel *)l->data; + 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()); + } + + s = sr_samplerate_string(_session.cur_samplerate()); + fprintf(meta, "samplerate = %s\n", s); + + 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); + g_variant_unref(gvar); + } + gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_DSO_BITS); + if (gvar != NULL) { + uint8_t tmp_u8 = g_variant_get_byte(gvar); + fprintf(meta, "bits = %d\n", tmp_u8); + g_variant_unref(gvar); + } + } else if (sdi->mode == LOGIC) { + fprintf(meta, "trigger time = %lld\n", _session.get_trigger_time().toMSecsSinceEpoch()); + } + fprintf(meta, "trigger pos = %" PRIu64 "\n", _session.get_trigger_pos()); + + probecnt = 1; + for (l = sdi->channels; l; l = l->next) { + probe = (struct sr_channel *)l->data; + if (probe->enabled || sdi->mode == DSO) { + if (probe->name) + fprintf(meta, "probe%d = %s\n", probe->index, probe->name); + if (probe->trigger) + fprintf(meta, " trigger%d = %s\n", probe->index, probe->trigger); + if (sdi->mode == DSO) { + fprintf(meta, " enable%d = %d\n", probe->index, probe->enabled); + fprintf(meta, " coupling%d = %d\n", probe->index, probe->coupling); + fprintf(meta, " vDiv%d = %" PRIu64 "\n", probe->index, probe->vdiv); + fprintf(meta, " vFactor%d = %d\n", probe->index, probe->vfactor); + fprintf(meta, " vPos%d = %lf\n", probe->index, probe->vpos); + fprintf(meta, " vTrig%d = %d\n", probe->index, probe->trig_value); + if (sr_status_get(sdi, &status, 0, 0) == SR_OK) { + if (probe->index == 0) { + fprintf(meta, " period%d = %" PRIu64 "\n", probe->index, status.ch0_period); + fprintf(meta, " pcnt%d = %" PRIu32 "\n", probe->index, status.ch0_pcnt); + fprintf(meta, " max%d = %d\n", probe->index, status.ch0_max); + fprintf(meta, " min%d = %d\n", probe->index, status.ch0_min); + } else { + fprintf(meta, " period%d = %" PRIu64 "\n", probe->index, status.ch1_period); + fprintf(meta, " pcnt%d = %" PRIu32 "\n", probe->index, status.ch1_pcnt); + fprintf(meta, " max%d = %d\n", probe->index, status.ch1_max); + fprintf(meta, " min%d = %d\n", probe->index, status.ch1_min); + } + } + } + probecnt++; + } + } + + fclose(meta); + + return metafile; +} + +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()); + } + + if (type_set.size() > 1) { + _error = tr("DSView does not currently support" + "file export for multiple data types."); + return false; + } else if (type_set.size() == 0) { + _error = tr("No data to save."); + return false; + } + + const boost::shared_ptr snapshot(_session.get_snapshot(*type_set.begin())); + assert(snapshot); + // Check we have data + if (snapshot->empty()) { + _error = tr("No data to save."); + return false; + } + + const QString DIR_KEY("ExportPath"); + QSettings settings; + + // 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(";;"); + } + _file_name = QFileDialog::getSaveFileName( + NULL, tr("Export Data"), settings.value(DIR_KEY).toString(),filter,&filter); + if (!_file_name.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.absoluteFilePath(_file_name)); + + const struct sr_output_module** supportedModules = sr_output_list(); + while(*supportedModules){ + if(*supportedModules == NULL) + break; + if(!strcmp((*supportedModules)->id, _suffix.toLocal8Bit().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; + } + } + + _error.clear(); + return false; +} + +void StoreSession::export_proc(shared_ptr snapshot) +{ + assert(snapshot); + + shared_ptr logic_snapshot; + shared_ptr analog_snapshot; + shared_ptr dso_snapshot; + int channel_type; + + if (logic_snapshot = boost::dynamic_pointer_cast(snapshot)) { + channel_type = SR_CHANNEL_LOGIC; + } else if (dso_snapshot = boost::dynamic_pointer_cast(snapshot)) { + channel_type = SR_CHANNEL_DSO; + } else { + _has_error = true; + _error = tr("data type don't support."); + return; + } + + GHashTable *params = g_hash_table_new(g_str_hash, g_str_equal); + GVariant* filenameGVariant = g_variant_new_bytestring(_file_name.toLocal8Bit().data()); + g_hash_table_insert(params, (char*)"filename", filenameGVariant); + GVariant* typeGVariant = g_variant_new_int16(channel_type); + g_hash_table_insert(params, (char*)"type", typeGVariant); + BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + boost::shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(s)) { + GVariant* timebaseGVariant = g_variant_new_uint64(dsoSig->get_hDialValue()); + g_hash_table_insert(params, (char*)"timebase", timebaseGVariant); + break; + } + } + + struct sr_output output; + output.module = (sr_output_module*) _outModule; + output.sdi = _session.get_device()->dev_inst(); + output.param = NULL; + if(_outModule->init) + _outModule->init(&output, params); + QFile file(_file_name); + file.open(QIODevice::WriteOnly | QIODevice::Text); + QTextStream out(&file); + out.setCodec("UTF-8"); + out.setGenerateByteOrderMark(true); + + if (channel_type == SR_CHANNEL_LOGIC) { + _unit_count = logic_snapshot->get_sample_count(); + int blk_num = logic_snapshot->get_block_num(); + 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; + 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(); + if (!logic_snapshot->has_data(ch_index)) + continue; + uint8_t *buf = logic_snapshot->get_block_buf(blk, ch_index, sample); + buf_vec.push_back(buf); + buf_sample.push_back(sample); + } + } + + uint16_t unitsize = ceil(buf_vec.size() / 8.0); + GString *data_out; + unsigned int usize = 8192; + unsigned int size = usize; + struct sr_datafeed_logic lp; + struct sr_datafeed_packet p; + for(uint64_t i = 0; !boost::this_thread::interruption_requested() && + 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); + if (xbuf == NULL) { + _has_error = true; + _error = tr("xbuffer malloc failed."); + return; + } + memset(xbuf, 0, size * unitsize); + for (uint64_t j = 0; j < usize; j++) { + for (unsigned int k = 0; k < buf_vec.size(); k++) { + if (buf_vec[k] == NULL && buf_sample[k]) + xbuf[j*unitsize+k/8] += 1 << k%8; + else if (buf_vec[k] && (buf_vec[k][(i+j)/8] & (1 << j%8))) + xbuf[j*unitsize+k/8] += 1 << k%8; + } + } + lp.data = xbuf; + lp.length = size * unitsize; + lp.unitsize = unitsize; + p.type = SR_DF_LOGIC; + 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); + } + + _units_stored += size; + if (xbuf) + free(xbuf); + progress_updated(); + } + } + } else if (channel_type == SR_CHANNEL_DSO) { + _unit_count = snapshot->get_sample_count(); + unsigned char* datat = (unsigned char*)snapshot->get_data(); + GString *data_out; + unsigned int usize = 8192; + unsigned int size = usize; + struct sr_datafeed_dso dp; + struct sr_datafeed_packet p; + 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(); + } + } + + // optional, as QFile destructor will already do it: + file.close(); + _outModule->cleanup(&output); + g_hash_table_destroy(params); + g_variant_unref(filenameGVariant); + + progress_updated(); +} + +#ifdef ENABLE_DECODE +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); + outStream.setCodec("UTF-8"); + outStream.setGenerateByteOrderMark(true); + + QJsonArray dec_array = json_decoders(); + QJsonDocument sessionDoc(dec_array); + outStream << QString::fromUtf8(sessionDoc.toJson()); + sessionFile.close(); + + return file_name; + } else { + return NULL; + } + +} + +QJsonArray StoreSession::json_decoders() +{ + QJsonArray dec_array; + BOOST_FOREACH(boost::shared_ptr 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) { + 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(); + i != dec->channels().end(); i++) { + QJsonObject ch_obj; + ch_obj[(*i).first->id] = QJsonValue::fromVariant((*i).second); + ch_array.push_back(ch_obj); + } + } + + QJsonObject options_obj; + boost::shared_ptr dec_binding( + new prop::binding::DecoderOptions(stack, dec)); + for (GSList *l = d->options; l; l = l->next) + { + const srd_decoder_option *const opt = + (srd_decoder_option*)l->data; + + const std::map& options = dec->options(); + std::map::const_iterator iter = options.find(opt->id); + if (opt->values) { + for (GSList *vl = opt->values; vl; vl = vl->next) { + GVariant *const var = (GVariant*)vl->data; + assert(var); + if (iter == options.end()) { + options_obj[opt->id] = QJsonValue::fromVariant(dec_binding->print_gvariant(opt->def)); + break; + } else if (g_variant_compare((*iter).second, var) == 0) { + options_obj[opt->id] = QJsonValue::fromVariant(dec_binding->print_gvariant(var)); + break; + } + } + } else if (g_variant_is_of_type(opt->def, G_VARIANT_TYPE("d"))) { + GVariant *const var = dec_binding->getter(opt->id); + options_obj[opt->id] = QJsonValue::fromVariant(g_variant_get_double(var)); + g_variant_unref(var); + } else if (g_variant_is_of_type(opt->def, G_VARIANT_TYPE("x"))) { + GVariant *const var = dec_binding->getter(opt->id); + options_obj[opt->id] = QJsonValue::fromVariant(get_double(var)); + g_variant_unref(var); + } else if (g_variant_is_of_type(opt->def, G_VARIANT_TYPE("s"))) { + GVariant *const var = dec_binding->getter(opt->id); + options_obj[opt->id] = QJsonValue::fromVariant(g_variant_get_string(var, NULL)); + g_variant_unref(var); + }else { + continue; + } + } + + + if (have_probes) { + dec_obj["id"] = QJsonValue::fromVariant(d->id); + dec_obj["channel"] = ch_array; + dec_obj["options"] = options_obj; + } else { + QJsonObject stack_obj; + stack_obj["id"] = QJsonValue::fromVariant(d->id); + stack_obj["options"] = options_obj; + stack_array.push_back(stack_obj); + } + show_obj[d->id] = QJsonValue::fromVariant(dec->shown()); + } + 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); + } + dec_obj["show"] = show_obj; + + dec_array.push_back(dec_obj); + } + return dec_array; +} + +void StoreSession::load_decoders(dock::ProtocolDock *widget, QJsonArray dec_array) +{ + 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()); + if (widget->sel_protocol(dec_obj["id"].toString())) + widget->add_protocol(true); + const vector< boost::shared_ptr > 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(); + + if (dec_obj.contains("stacked decoders")) { + foreach(const QJsonValue &value, dec_obj["stacked decoders"].toArray()) { + QJsonObject stacked_obj = value.toObject(); + + GSList *dl = g_slist_copy((GSList*)srd_decoder_list()); + for(; dl; dl = dl->next) { + const srd_decoder *const d = (srd_decoder*)dl->data; + assert(d); + + if (QString::fromUtf8(d->id) == stacked_obj["id"].toString()) { + stack->push(boost::shared_ptr( + new data::decode::Decoder(d))); + break; + } + } + g_slist_free(dl); + } + } + + const std::list< boost::shared_ptr >& decoder = stack->stack(); + BOOST_FOREACH(boost::shared_ptr dec, decoder) { + const srd_decoder *const d = dec->decoder(); + QJsonObject options_obj; + + if (dec == decoder.front()) { + 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()) { + QJsonObject ch_obj = value.toObject(); + if (ch_obj.contains(pdch->id)) { + probe_map[pdch] = ch_obj[pdch->id].toInt(); + break; + } + } + } + + // 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()) { + QJsonObject ch_obj = value.toObject(); + if (ch_obj.contains(pdch->id)) { + probe_map[pdch] = ch_obj[pdch->id].toInt(); + break; + } + } + } + dec->set_probes(probe_map); + options_obj = dec_obj["options"].toObject(); + } else { + foreach(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(); + break; + } + } + } + + for (l = d->options; l; l = l->next) { + const srd_decoder_option *const opt = + (srd_decoder_option*)l->data; + if (options_obj.contains(opt->id)) { + if (opt->values) { + QString enum_option = options_obj[opt->id].toString(); + for (GSList *vl = opt->values; vl; vl = vl->next) { + GVariant *const var = (GVariant*)vl->data; + assert(var); + if (enum_option == QString::fromUtf8(g_variant_get_string(var, NULL))) { + dec->set_option(opt->id, var); + break; + } + } + } else if (g_variant_is_of_type(opt->def, G_VARIANT_TYPE("d"))) { + double d_option = options_obj[opt->id].toDouble(); + dec->set_option(opt->id, g_variant_new_double(d_option)); + } else if (g_variant_is_of_type(opt->def, G_VARIANT_TYPE("x"))) { + int64_t d_option = options_obj[opt->id].toDouble(); + GVariant *new_value = NULL; + const GVariantType *const type = g_variant_get_type(opt->def); + if (g_variant_type_equal(type, G_VARIANT_TYPE_BYTE)) + new_value = g_variant_new_byte(d_option); + else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT16)) + new_value = g_variant_new_int16(d_option); + else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT16)) + new_value = g_variant_new_uint16(d_option); + else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT32)) + new_value = g_variant_new_int32(d_option); + else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT32)) + new_value = g_variant_new_int32(d_option); + else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT64)) + new_value = g_variant_new_int64(d_option); + else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT64)) + new_value = g_variant_new_uint64(d_option); + if (new_value != NULL) + dec->set_option(opt->id, new_value); + } else if (g_variant_is_of_type(opt->def, G_VARIANT_TYPE("s"))) { + QString s_option = options_obj[opt->id].toString(); + dec->set_option(opt->id, g_variant_new_string(s_option.toLocal8Bit().data())); + } + } + } + dec->commit(); + + if (dec_obj.contains("show")) { + QJsonObject show_obj = dec_obj["show"].toObject(); + if (show_obj.contains(d->id)) { + dec->show(show_obj[d->id].toBool()); + } + } + } + + 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()); + } + } + } + } + } + +} +#endif + +double StoreSession::get_double(GVariant *var) +{ + double val = 0; + const GVariantType *const type = g_variant_get_type(var); + assert(type); + + if (g_variant_type_equal(type, G_VARIANT_TYPE_BYTE)) + val = g_variant_get_byte(var); + else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT16)) + val = g_variant_get_int16(var); + else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT16)) + val = g_variant_get_uint16(var); + else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT32)) + val = g_variant_get_int32(var); + else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT32)) + val = g_variant_get_uint32(var); + else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT64)) + val = g_variant_get_int64(var); + else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT64)) + val = g_variant_get_uint64(var); + else + assert(0); + + return val; } } // pv diff --git a/DSView/pv/storesession.h b/DSView/pv/storesession.h index 0493ff84..04911dd6 100644 --- a/DSView/pv/storesession.h +++ b/DSView/pv/storesession.h @@ -2,6 +2,7 @@ * This file is part of the PulseView project. * * Copyright (C) 2014 Joel Holdsworth + * Copyright (C) 2016 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 @@ -22,19 +23,25 @@ #define DSVIEW_PV_STORESESSION_H #include - #include #include #include +#include +#include + namespace pv { class SigSession; namespace data { -class LogicSnapshot; +class Snapshot; +} + +namespace dock { +class ProtocolDock; } class StoreSession : public QObject @@ -42,11 +49,10 @@ class StoreSession : public QObject Q_OBJECT private: - static const size_t BlockSize; + const static int File_Version = 2; public: - StoreSession(const std::string &file_name, - SigSession &session); + StoreSession(SigSession &session); ~StoreSession(); @@ -54,27 +60,48 @@ public: const QString& error() const; - bool start(); + bool save_start(); + + bool export_start(); void wait(); void cancel(); private: - void store_proc(boost::shared_ptr snapshot); + 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(); + double get_double(GVariant * var); signals: void progress_updated(); private: - const std::string _file_name; + 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; }; diff --git a/DSView/pv/toolbars/filebar.cpp b/DSView/pv/toolbars/filebar.cpp index 0514e32b..ce070ea2 100644 --- a/DSView/pv/toolbars/filebar.cpp +++ b/DSView/pv/toolbars/filebar.cpp @@ -91,13 +91,13 @@ FileBar::FileBar(SigSession &session, QWidget *parent) : _action_save->setIcon(QIcon::fromTheme("file", QIcon(":/icons/save.png"))); _action_save->setObjectName(QString::fromUtf8("actionSave")); - connect(_action_save, SIGNAL(triggered()), this, SLOT(on_actionSave_triggered())); + connect(_action_save, SIGNAL(triggered()), this, SIGNAL(on_save())); _action_export = new QAction(this); _action_export->setText(QApplication::translate("File", "&Export...", 0)); _action_export->setIcon(QIcon::fromTheme("file",QIcon(":/icons/export.png"))); _action_export->setObjectName(QString::fromUtf8("actionExport")); - connect(_action_export, SIGNAL(triggered()), this, SLOT(on_actionExport_triggered())); + connect(_action_export, SIGNAL(triggered()), this, SIGNAL(on_export())); _action_capture = new QAction(this); @@ -119,9 +119,6 @@ FileBar::FileBar(SigSession &session, QWidget *parent) : _menu->addAction(_action_capture); _file_button.setMenu(_menu); addWidget(&_file_button); - - _screenshot_timer.setSingleShot(true); - connect(&_screenshot_timer, SIGNAL(timeout()), this, SIGNAL(on_screenShot())); } void FileBar::on_actionOpen_triggered() @@ -131,7 +128,7 @@ void FileBar::on_actionOpen_triggered() // Show the dialog const QString file_name = QFileDialog::getOpenFileName( this, tr("Open File"), settings.value(DIR_KEY).toString(), tr( - "DSView Data (*.dsl);;All Files (*.*)")); + "DSView Data (*.dsl)")); if (!file_name.isEmpty()) { QDir CurrentDir; settings.setValue(DIR_KEY, CurrentDir.absoluteFilePath(file_name)); @@ -158,74 +155,6 @@ void FileBar::show_session_error( msg.exec(); } -void FileBar::on_actionExport_triggered(){ - const QString DIR_KEY("ExportPath"); - QSettings settings; - int unit_size; - uint64_t length; - const void* buf = _session.get_buf(unit_size, length); - if (!buf) { - dialogs::DSMessageBox msg(this); - msg.mBox()->setText(tr("Data Export")); - msg.mBox()->setInformativeText(tr("No data to save!")); - msg.mBox()->setStandardButtons(QMessageBox::Ok); - msg.mBox()->setIcon(QMessageBox::Warning); - msg.exec(); - } else { - QList supportedFormats = _session.getSuportedExportFormats(); - QString filter; - for(int i = 0; i < supportedFormats.count();i++){ - filter.append(supportedFormats[i]); - if(i < supportedFormats.count() - 1) - filter.append(";;"); - } - QString file_name = QFileDialog::getSaveFileName( - this, tr("Export Data"), settings.value(DIR_KEY).toString(),filter,&filter); - if (!file_name.isEmpty()) { - QFileInfo f(file_name); - QStringList list = filter.split('.').last().split(')'); - QString ext = list.first(); - if(f.suffix().compare(ext)) - file_name+=tr(".")+ext; - QDir CurrentDir; - settings.setValue(DIR_KEY, CurrentDir.absoluteFilePath(file_name)); - _session.export_file(file_name, this, ext); - } - } -} - -void FileBar::on_actionSave_triggered() -{ - const QString DIR_KEY("SavePath"); - QSettings settings; - //save(); - int unit_size; - uint64_t length; - const void* buf = _session.get_buf(unit_size, length); - if (!buf) { - dialogs::DSMessageBox msg(this); - msg.mBox()->setText(tr("File Save")); - msg.mBox()->setInformativeText(tr("No data to save!")); - msg.mBox()->setStandardButtons(QMessageBox::Ok); - msg.mBox()->setIcon(QMessageBox::Warning); - msg.exec(); - } else { - QString file_name = QFileDialog::getSaveFileName( - this, tr("Save File"), settings.value(DIR_KEY).toString(), - tr("DSView Data (*.dsl)")); - - if (!file_name.isEmpty()) { - QFileInfo f(file_name); - if(f.suffix().compare("dsl")) - file_name.append(tr(".dsl")); - QDir CurrentDir; - settings.setValue(DIR_KEY, CurrentDir.absoluteFilePath(file_name)); - _session.save_file(file_name, this, _session.get_device()->dev_inst()->mode); - } - } -} - - void FileBar::on_actionLoad_triggered() { const QString DIR_KEY("SessionLoadPath"); @@ -282,7 +211,7 @@ void FileBar::on_actionCapture_triggered() { _file_button.close(); QCoreApplication::sendPostedEvents(); - _screenshot_timer.start(100); + QTimer::singleShot(100, this, SIGNAL(on_screenShot())); } void FileBar::enable_toggle(bool enable) diff --git a/DSView/pv/toolbars/filebar.h b/DSView/pv/toolbars/filebar.h index ea99ac66..0d85b578 100644 --- a/DSView/pv/toolbars/filebar.h +++ b/DSView/pv/toolbars/filebar.h @@ -53,7 +53,8 @@ private: signals: void load_file(QString); - void save(); + void on_save(); + void on_export(); void on_screenShot(); void load_session(QString); void store_session(QString); @@ -63,9 +64,7 @@ private slots: void on_actionStore_triggered(); void on_actionDefault_triggered(); void on_actionOpen_triggered(); - void on_actionSave_triggered(); void on_actionCapture_triggered(); - void on_actionExport_triggered(); private: bool _enable; @@ -84,9 +83,6 @@ private: QAction *_action_save; QAction *_action_export; QAction *_action_capture; - - QTimer _screenshot_timer; - }; } // namespace toolbars diff --git a/DSView/pv/toolbars/samplingbar.cpp b/DSView/pv/toolbars/samplingbar.cpp index b47eeb5f..1375370a 100644 --- a/DSView/pv/toolbars/samplingbar.cpp +++ b/DSView/pv/toolbars/samplingbar.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include "samplingbar.h" @@ -41,6 +42,7 @@ #include "../dialogs/waitingdialog.h" #include "../dialogs/dsmessagebox.h" #include "../view/dsosignal.h" +#include "../dialogs/interval.h" using namespace boost; using boost::shared_ptr; @@ -74,12 +76,15 @@ const uint64_t SamplingBar::RecordLengths[19] = { 40000000, }; +const QString SamplingBar::RLEString = "(RLE)"; + const uint64_t SamplingBar::DefaultRecordLength = 1000000; SamplingBar::SamplingBar(SigSession &session, QWidget *parent) : QToolBar("Sampling Bar", parent), _session(session), _enable(true), + _sampling(false), _device_selector(this), _updating_device_selector(false), _configure_button(this), @@ -94,6 +99,11 @@ SamplingBar::SamplingBar(SigSession &session, QWidget *parent) : _icon_instant_dis(":/icons/instant_dis.png"), _run_stop_button(this), _instant_button(this), + _mode_button(this), + _icon_repeat(":/icons/moder.png"), + _icon_single(":/icons/modes.png"), + _icon_repeat_dis(":/icons/moder_dis.png"), + _icon_single_dis(":/icons/modes_dis.png"), _instant(false) { setMovable(false); @@ -112,6 +122,8 @@ SamplingBar::SamplingBar(SigSession &session, QWidget *parent) : _configure_button.setIcon(QIcon::fromTheme("configure", QIcon(":/icons/params.png"))); + _mode_button.setPopupMode(QToolButton::InstantPopup); + _mode_button.setIcon(_session.get_run_mode() == pv::SigSession::Single ? _icon_single : _icon_repeat); _run_stop_button.setIcon(_icon_start); _instant_button.setIcon(_icon_instant); @@ -138,6 +150,25 @@ SamplingBar::SamplingBar(SigSession &session, QWidget *parent) : addWidget(&_sample_count); addWidget(new QLabel(tr(" @ "))); addWidget(&_sample_rate); + + _action_single = new QAction(this); + _action_single->setText(QApplication::translate("Sampling", "&Single", 0)); + _action_single->setIcon(QIcon::fromTheme("Sampling", + QIcon(":/icons/oneloop.png"))); + connect(_action_single, SIGNAL(triggered()), this, SLOT(on_mode())); + + _action_repeat = new QAction(this); + _action_repeat->setText(QApplication::translate("Sampling", "&Repetitive", 0)); + _action_repeat->setIcon(QIcon::fromTheme("Sampling", + QIcon(":/icons/repeat.png"))); + connect(_action_repeat, SIGNAL(triggered()), this, SLOT(on_mode())); + + _mode_menu = new QMenu(this); + _mode_menu->addAction(_action_single); + _mode_menu->addAction(_action_repeat); + _mode_button.setMenu(_mode_menu); + _mode_action = addWidget(&_mode_button); + _run_stop_action = addWidget(&_run_stop_button); _instant_action = addWidget(&_instant_button); } @@ -245,10 +276,8 @@ void SamplingBar::on_configure() if (test) { update_sample_count_selector_value(); update_sample_rate_selector_value(); - #ifndef TEST_MODE _sample_count.setDisabled(true); _sample_rate.setDisabled(true); - #endif } else if (dev_inst->dev_inst()->mode != DSO) { _sample_count.setDisabled(false); _sample_rate.setDisabled(false); @@ -277,7 +306,7 @@ void SamplingBar::zero_adj() } if (_session.get_capture_state() == pv::SigSession::Running) - run_stop(); + on_run_stop(); } uint64_t SamplingBar::get_record_length() const @@ -322,8 +351,20 @@ void SamplingBar::update_sample_rate() this, SLOT(on_samplerate_sel(int))); } +bool SamplingBar::get_sampling() const +{ + return _sampling; +} + +bool SamplingBar::get_instant() const +{ + return _instant; +} + void SamplingBar::set_sampling(bool sampling) { + lock_guard lock(_sampling_mutex); + _sampling = sampling; if (_instant) { _instant_button.setIcon(sampling ? _icon_stop : _icon_instant); _run_stop_button.setIcon(sampling ? _icon_start_dis : _icon_start); @@ -342,6 +383,9 @@ void SamplingBar::set_sampling(bool sampling) enable_run_stop(true); } + _mode_button.setEnabled(!sampling); + _mode_button.setIcon(sampling ? (_session.get_run_mode() == pv::SigSession::Single ? _icon_single_dis : _icon_repeat_dis) : + (_session.get_run_mode() == pv::SigSession::Single ? _icon_single : _icon_repeat)); _configure_button.setEnabled(!sampling); _configure_button.setIcon(sampling ? QIcon(":/icons/params_dis.png") : QIcon(":/icons/params.png")); @@ -482,7 +526,6 @@ void SamplingBar::on_samplecount_sel(int index) { uint64_t sample_count = 0; - qDebug() << "index: " << index; if (index >= 0) sample_count = _sample_count.itemData( index).value(); @@ -509,13 +552,13 @@ void SamplingBar::on_samplerate_sel(int index) sample_rate = _sample_rate.itemData( index).value(); - boost::shared_ptr _devInst = get_selected_device(); - assert(_devInst); + boost::shared_ptr dev_inst = get_selected_device(); + assert(dev_inst); // Get last samplerate //last_sample_rate = get_selected_device()->get_sample_rate(); - if (_devInst->name() == "DSLogic" && _devInst->dev_inst()->mode != DSO) { + if (dev_inst->name() == "DSLogic" && dev_inst->dev_inst()->mode != DSO) { // Set the samplerate get_selected_device()->set_config(NULL, NULL, SR_CONF_SAMPLERATE, @@ -529,7 +572,8 @@ void SamplingBar::update_sample_count_selector() const uint64_t *elements = NULL; gsize num_elements; bool stream_mode = false; - uint64_t max_sample_count = 0; + uint64_t hw_depth = 0; + uint64_t sw_depth; if (_updating_sample_count) return; @@ -557,9 +601,9 @@ void SamplingBar::update_sample_count_selector() stream_mode = g_variant_get_boolean(gvar); g_variant_unref(gvar); } - gvar = dev_inst->get_config(NULL, NULL, SR_CONF_RLE_SAMPLELIMITS); + gvar = dev_inst->get_config(NULL, NULL, SR_CONF_HW_DEPTH); if (gvar != NULL) { - max_sample_count = g_variant_get_uint64(gvar); + hw_depth = g_variant_get_uint64(gvar); g_variant_unref(gvar); } @@ -570,11 +614,23 @@ void SamplingBar::update_sample_count_selector() gvar_list, &num_elements, sizeof(uint64_t)); _sample_count.clear(); + #if defined(__x86_64__) || defined(_M_X64) + sw_depth = elements[num_elements - 1]; + #elif defined(__i386) || defined(_M_IX86) + int ch_num = _session.get_ch_num(SR_CHANNEL_LOGIC); + if (ch_num <= 0) + sw_depth = SR_GB(8); + else + sw_depth = SR_GB(8) / ch_num; + #endif + for (unsigned int i = 0; i < num_elements; i++) { + if (elements[i] > sw_depth) + break; char *const s = sr_samplecount_string(elements[i]); - if (!stream_mode && (elements[i] > max_sample_count)) - _sample_count.addItem(QString(s)+"(RLE)", + if (!stream_mode && (elements[i] > hw_depth)) + _sample_count.addItem(QString(s)+RLEString, qVariantFromValue(elements[i])); else _sample_count.addItem(QString(s), @@ -647,81 +703,118 @@ void SamplingBar::commit_sample_count() g_variant_new_uint64(sample_count)); } + bool rle_mode = _sample_count.currentText().contains(RLEString); + get_selected_device()->set_config(NULL, NULL, + SR_CONF_RLE, + g_variant_new_boolean(rle_mode)); + _updating_sample_count = false; } void SamplingBar::on_run_stop() { - enable_run_stop(false); - enable_instant(false); - commit_sample_rate(); - commit_sample_count(); - _instant = false; - const 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) { - bool zero = g_variant_get_boolean(gvar); - g_variant_unref(gvar); - if (zero) { - dialogs::DSMessageBox msg(this); - msg.mBox()->setText(tr("Zero Adjustment")); - msg.mBox()->setInformativeText(tr("Please adjust zero skew and save the result!")); - //msg.setStandardButtons(QMessageBox::Ok); - msg.mBox()->addButton(tr("Ok"), QMessageBox::AcceptRole); - msg.mBox()->addButton(tr("Skip"), QMessageBox::RejectRole); - msg.mBox()->setIcon(QMessageBox::Warning); - if (msg.exec()) { - zero_adj(); - } else { - dev_inst->set_config(NULL, NULL, SR_CONF_ZERO, g_variant_new_boolean(false)); - enable_run_stop(true); - enable_instant(true); - } - return; + if (get_sampling() || _session.isRepeating()) { + _session.set_repeating(false); + bool wait_upload = false; + 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); + g_variant_unref(gvar); } } + if (!wait_upload) { + _session.stop_capture(); + _session.capture_state_changed(SigSession::Stopped); + } + } else { + enable_run_stop(false); + enable_instant(false); + commit_sample_rate(); + commit_sample_count(); + _instant = false; + const 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) { + 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("Please adjust zero skew and save the result!")); + //msg.setStandardButtons(QMessageBox::Ok); + msg.mBox()->addButton(tr("Ok"), QMessageBox::AcceptRole); + msg.mBox()->addButton(tr("Skip"), QMessageBox::RejectRole); + msg.mBox()->setIcon(QMessageBox::Warning); + if (msg.exec()) { + zero_adj(); + } else { + dev_inst->set_config(NULL, NULL, SR_CONF_ZERO, g_variant_new_boolean(false)); + enable_run_stop(true); + enable_instant(true); + } + return; + } + } + } + run_stop(); } - run_stop(); } void SamplingBar::on_instant_stop() { - enable_run_stop(false); - enable_instant(false); - commit_sample_rate(); - commit_sample_count(); - _instant = true; - const 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) { - bool zero = g_variant_get_boolean(gvar); - g_variant_unref(gvar); - if (zero) { - dialogs::DSMessageBox msg(this); - msg.mBox()->setText(tr("Zero Adjustment")); - msg.mBox()->setInformativeText(tr("Zero adjustment program will be started. Please keep all channels out of signal input. This 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); - if (msg.exec()) { - zero_adj(); - } else { - dev_inst->set_config(NULL, NULL, SR_CONF_ZERO, g_variant_new_boolean(false)); - enable_run_stop(true); - enable_instant(true); - } - return; + if (get_sampling()) { + _session.set_repeating(false); + bool wait_upload = false; + 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); + g_variant_unref(gvar); } } + if (!wait_upload) { + _session.stop_capture(); + _session.capture_state_changed(SigSession::Stopped); + } + } else { + enable_run_stop(false); + enable_instant(false); + commit_sample_rate(); + commit_sample_count(); + _instant = true; + const 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) { + 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. Please keep all channels out of singal input. 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); + if (msg.exec()) { + zero_adj(); + } else { + dev_inst->set_config(NULL, NULL, SR_CONF_ZERO, g_variant_new_boolean(false)); + enable_run_stop(true); + enable_instant(true); + } + return; + } + } + } + instant_stop(); } - instant_stop(); } void SamplingBar::on_device_selected() @@ -757,6 +850,9 @@ void SamplingBar::enable_toggle(bool enable) if (!test) { _sample_count.setDisabled(!enable); _sample_rate.setDisabled(!enable); + } else { + _sample_count.setDisabled(true); + _sample_rate.setDisabled(true); } } @@ -787,10 +883,17 @@ void SamplingBar::reload() _icon_instant = QIcon(":/icons/instant.png"); _icon_instant_dis = QIcon(":/icons/instant_dis.png"); _instant_button.setIcon(_icon_instant); + if (_session.get_device()->name() == "virtual-session") { + _mode_action->setVisible(false); + } else { + _mode_button.setIcon(_session.get_run_mode() == pv::SigSession::Single ? _icon_single : _icon_repeat); + _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) { + _mode_action->setVisible(false); _run_stop_action->setVisible(true); _instant_action->setVisible(false); enable_toggle(true); @@ -798,6 +901,7 @@ void SamplingBar::reload() _icon_instant = QIcon(":/icons/single.png"); _icon_instant_dis = QIcon(":/icons/single_dis.png"); _instant_button.setIcon(_icon_instant); + _mode_action->setVisible(false); _run_stop_action->setVisible(true); _instant_action->setVisible(true); enable_toggle(false); @@ -805,5 +909,19 @@ void SamplingBar::reload() update(); } +void SamplingBar::on_mode() +{ + QAction *act = qobject_cast(sender()); + if (act == _action_single) { + _mode_button.setIcon(_icon_single); + _session.set_run_mode(pv::SigSession::Single); + } else if (act == _action_repeat) { + _mode_button.setIcon(_icon_repeat); + pv::dialogs::Interval interval_dlg(_session, this); + interval_dlg.exec(); + _session.set_run_mode(pv::SigSession::Repetitive); + } +} + } // namespace toolbars } // namespace pv diff --git a/DSView/pv/toolbars/samplingbar.h b/DSView/pv/toolbars/samplingbar.h index 14e9aa94..8720bf20 100644 --- a/DSView/pv/toolbars/samplingbar.h +++ b/DSView/pv/toolbars/samplingbar.h @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include @@ -64,6 +66,7 @@ private: static const uint64_t RecordLengths[19]; static const uint64_t DefaultRecordLength; static const int ComboBoxMaxWidth = 200; + static const QString RLEString; public: SamplingBar(SigSession &session, QWidget *parent); @@ -80,6 +83,8 @@ public: void update_sample_rate(); void set_sampling(bool sampling); + bool get_sampling() const; + bool get_instant() const; void enable_toggle(bool enable); @@ -110,6 +115,7 @@ private: void setting_adj(); private slots: + void on_mode(); void on_run_stop(); void on_instant_stop(); void on_device_selected(); @@ -127,7 +133,9 @@ public slots: private: SigSession &_session; + mutable boost::recursive_mutex _sampling_mutex; bool _enable; + bool _sampling; QComboBox _device_selector; std::map > @@ -151,6 +159,17 @@ private: QAction* _run_stop_action; QAction* _instant_action; + QAction* _mode_action; + QToolButton _mode_button; + QMenu *_mode_menu; + QAction *_action_repeat; + QAction *_action_single; + + QIcon _icon_repeat; + QIcon _icon_single; + QIcon _icon_repeat_dis; + QIcon _icon_single_dis; + bool _instant; }; diff --git a/DSView/pv/view/analogsignal.cpp b/DSView/pv/view/analogsignal.cpp index 08d38c2e..49755ab8 100644 --- a/DSView/pv/view/analogsignal.cpp +++ b/DSView/pv/view/analogsignal.cpp @@ -85,7 +85,7 @@ void AnalogSignal::paint_mid(QPainter &p, int left, int right) const int y = get_y() + _totalHeight * 0.5; const double scale = _view->scale(); assert(scale > 0); - const double offset = _view->offset(); + const int64_t offset = _view->offset(); const deque< boost::shared_ptr > &snapshots = _data->get_snapshots(); @@ -98,15 +98,15 @@ void AnalogSignal::paint_mid(QPainter &p, int left, int right) if (snapshot->empty()) return; - if (get_index() >= (int)snapshot->get_channel_num()) + const int order = snapshot->get_ch_order(get_index()); + if (order == -1) return; - const double pixels_offset = offset / scale; + const double pixels_offset = offset; const double samplerate = _data->samplerate(); - const double start_time = _data->get_start_time(); const int64_t last_sample = max((int64_t)(snapshot->get_sample_count() - 1), (int64_t)0); const double samples_per_pixel = samplerate * scale; - const double start = samplerate * (offset - start_time); + const double start = offset * samples_per_pixel; const double end = start + samples_per_pixel * (right - left); const int64_t start_sample = min(max((int64_t)floor(start), @@ -117,17 +117,18 @@ void AnalogSignal::paint_mid(QPainter &p, int left, int right) if (samples_per_pixel < EnvelopeThreshold) paint_trace(p, snapshot, y, left, start_sample, end_sample, - pixels_offset, samples_per_pixel); + pixels_offset, samples_per_pixel, order); else paint_envelope(p, snapshot, y, left, start_sample, end_sample, - pixels_offset, samples_per_pixel); + pixels_offset, samples_per_pixel, order); } void AnalogSignal::paint_trace(QPainter &p, const boost::shared_ptr &snapshot, int y, int left, const int64_t start, const int64_t end, - const double pixels_offset, const double samples_per_pixel) + const double pixels_offset, const double samples_per_pixel, + int order) { const int64_t sample_count = end - start; const int64_t channel_num = snapshot->get_channel_num(); @@ -145,7 +146,7 @@ void AnalogSignal::paint_trace(QPainter &p, const float x = (sample / samples_per_pixel - pixels_offset) + left; *point++ = QPointF(x, - y - samples[(sample - start) * channel_num + get_index()] * _scale); + y - samples[(sample - start) * channel_num + order] * _scale); } p.drawPolyline(points, point - points); @@ -157,13 +158,14 @@ void AnalogSignal::paint_trace(QPainter &p, void AnalogSignal::paint_envelope(QPainter &p, const boost::shared_ptr &snapshot, int y, int left, const int64_t start, const int64_t end, - const double pixels_offset, const double samples_per_pixel) + const double pixels_offset, const double samples_per_pixel, + int order) { using namespace Qt; using pv::data::AnalogSnapshot; AnalogSnapshot::EnvelopeSection e; - snapshot->get_envelope_section(e, start, end, samples_per_pixel, get_index()); + snapshot->get_envelope_section(e, start, end, samples_per_pixel, order); if (e.length < 2) return; @@ -201,10 +203,5 @@ void AnalogSignal::paint_envelope(QPainter &p, //delete[] e.samples; } -const std::vector< std::pair > AnalogSignal::cur_edges() const -{ - -} - } // namespace view } // namespace pv diff --git a/DSView/pv/view/analogsignal.h b/DSView/pv/view/analogsignal.h index 12523de7..6b8a407e 100644 --- a/DSView/pv/view/analogsignal.h +++ b/DSView/pv/view/analogsignal.h @@ -64,18 +64,16 @@ public: **/ void paint_mid(QPainter &p, int left, int right); - const std::vector< std::pair > cur_edges() const; - private: - void paint_trace(QPainter &p, - const boost::shared_ptr &snapshot, - int y, int left, const int64_t start, const int64_t end, - const double pixels_offset, const double samples_per_pixel); + void paint_trace(QPainter &p, + const boost::shared_ptr &snapshot, + int y, int left, const int64_t start, const int64_t end, + const double pixels_offset, const double samples_per_pixel, int order); - void paint_envelope(QPainter &p, - const boost::shared_ptr &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, + int y, int left, const int64_t start, const int64_t end, + const double pixels_offset, const double samples_per_pixel, int order); private: boost::shared_ptr _data; diff --git a/DSView/pv/view/cursor.cpp b/DSView/pv/view/cursor.cpp index aaa24582..6fc5ec2d 100644 --- a/DSView/pv/view/cursor.cpp +++ b/DSView/pv/view/cursor.cpp @@ -58,25 +58,31 @@ Cursor::Cursor(View &view, QColor color, uint64_t index) : { } -QRectF Cursor::get_label_rect(const QRect &rect) const +QRect Cursor::get_label_rect(const QRect &rect, bool &visible) const { const double samples_per_pixel = _view.session().cur_samplerate() * _view.scale(); - const double x = _index/samples_per_pixel - (_view.offset() / _view.scale()); + const double cur_offset = _index / samples_per_pixel; + if (cur_offset < _view.offset() || + cur_offset > (_view.offset() + _view.width())) { + visible = false; + return QRect(-1, -1, 0, 0); + } + const int64_t x = _index/samples_per_pixel - _view.offset(); - const QSizeF label_size( + const QSize label_size( _text_size.width() + View::LabelPadding.width() * 2, _text_size.height() + View::LabelPadding.height() * 2); - const float top = rect.height() - label_size.height() - + const int top = rect.height() - label_size.height() - Cursor::Offset - Cursor::ArrowSize - 0.5f; - const float height = label_size.height(); + const int height = label_size.height(); - return QRectF(x - label_size.width() / 2, top, label_size.width(), height); + visible = true; + return QRect(x - label_size.width() / 2, top, label_size.width(), height); } -QRectF Cursor::get_close_rect(const QRect &rect) const +QRect Cursor::get_close_rect(const QRect &rect) const { - const QRectF r(get_label_rect(rect)); - return QRectF(r.right() - CloseSize, r.top(), CloseSize, CloseSize); + return QRect(rect.right() - CloseSize, rect.top(), CloseSize, CloseSize); } void Cursor::paint_label(QPainter &p, const QRect &rect, @@ -85,10 +91,13 @@ void Cursor::paint_label(QPainter &p, const QRect &rect, assert(index > 0); using pv::view::Ruler; + bool visible; - compute_text_size(p, prefix); - const QRectF r(get_label_rect(rect)); - const QRectF close(get_close_rect(rect)); + compute_text_size(p, prefix); + const QRect r(get_label_rect(rect, visible)); + if (!visible) + return; + const QRect close(get_close_rect(r)); p.setPen(Qt::transparent); if (close.contains(QPoint(_view.hover_point().x(), _view.hover_point().y()))) @@ -99,10 +108,10 @@ void Cursor::paint_label(QPainter &p, const QRect &rect, p.setBrush(Ruler::CursorColor[(index - 1) % 8]); p.drawRect(r); - const QPointF points[] = { - QPointF(r.left() + r.width() / 2 - ArrowSize, r.bottom()), - QPointF(r.left() + r.width() / 2 + ArrowSize, r.bottom()), - QPointF(r.left() + r.width() / 2, rect.bottom()), + const QPoint points[] = { + QPoint(r.left() + r.width() / 2 - ArrowSize, r.bottom()), + QPoint(r.left() + r.width() / 2 + ArrowSize, r.bottom()), + QPoint(r.left() + r.width() / 2, rect.bottom()), }; p.drawPolygon(points, countof(points)); @@ -118,7 +127,7 @@ void Cursor::paint_label(QPainter &p, const QRect &rect, p.drawText(r, Qt::AlignCenter | Qt::AlignVCenter, Ruler::format_real_time(_index, _view.session().cur_samplerate())); - const QRectF arrowRect = QRectF(r.bottomLeft().x(), r.bottomLeft().y(), r.width(), ArrowSize); + const QRect arrowRect = QRect(r.bottomLeft().x(), r.bottomLeft().y(), r.width(), ArrowSize); p.drawText(arrowRect, Qt::AlignCenter | Qt::AlignVCenter, QString::number(index)); } @@ -126,18 +135,21 @@ void Cursor::paint_fix_label(QPainter &p, const QRect &rect, unsigned int prefix, QChar label, QColor color) { using pv::view::Ruler; + bool visible; compute_text_size(p, prefix); - const QRectF r(get_label_rect(rect)); + const QRect r(get_label_rect(rect, visible)); + if (!visible) + return; p.setPen(Qt::transparent); p.setBrush(color); p.drawRect(r); - const QPointF points[] = { - QPointF(r.left() + r.width() / 2 - ArrowSize, r.bottom()), - QPointF(r.left() + r.width() / 2 + ArrowSize, r.bottom()), - QPointF(r.left() + r.width() / 2, rect.bottom()), + const QPoint points[] = { + QPoint(r.left() + r.width() / 2 - ArrowSize, r.bottom()), + QPoint(r.left() + r.width() / 2 + ArrowSize, r.bottom()), + QPoint(r.left() + r.width() / 2, rect.bottom()), }; p.drawPolygon(points, countof(points)); @@ -145,14 +157,14 @@ void Cursor::paint_fix_label(QPainter &p, const QRect &rect, p.drawText(r, Qt::AlignCenter | Qt::AlignVCenter, Ruler::format_real_time(_index, _view.session().cur_samplerate())); - const QRectF arrowRect = QRectF(r.bottomLeft().x(), r.bottomLeft().y(), r.width(), ArrowSize); + const QRect arrowRect = QRect(r.bottomLeft().x(), r.bottomLeft().y(), r.width(), ArrowSize); p.drawText(arrowRect, Qt::AlignCenter | Qt::AlignVCenter, label); } void Cursor::compute_text_size(QPainter &p, unsigned int prefix) { (void)prefix; - _text_size = p.boundingRect(QRectF(), 0, + _text_size = p.boundingRect(QRect(), 0, Ruler::format_real_time(_index, _view.session().cur_samplerate())).size(); } diff --git a/DSView/pv/view/cursor.h b/DSView/pv/view/cursor.h index b1205874..72de30e5 100644 --- a/DSView/pv/view/cursor.h +++ b/DSView/pv/view/cursor.h @@ -64,9 +64,9 @@ public: * @param rect The rectangle of the ruler client area. * @return Returns the label rectangle. */ - QRectF get_label_rect(const QRect &rect) const; + QRect get_label_rect(const QRect &rect, bool &visible) const; - QRectF get_close_rect(const QRect &rect) const; + QRect get_close_rect(const QRect &rect) const; /** * Paints the cursor's label to the ruler. diff --git a/DSView/pv/view/decodetrace.cpp b/DSView/pv/view/decodetrace.cpp index aab8148c..f69c5b87 100644 --- a/DSView/pv/view/decodetrace.cpp +++ b/DSView/pv/view/decodetrace.cpp @@ -19,7 +19,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ extern "C" { -#include +#include } #include @@ -179,8 +179,8 @@ void DecodeTrace::paint_back(QPainter &p, int left, int right) // --draw decode region control const double samples_per_pixel = _session.cur_samplerate() * _view->scale(); - const double startX = _decode_start/samples_per_pixel - (_view->offset() / _view->scale()); - const double endX = _decode_end/samples_per_pixel - (_view->offset() / _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; p.setBrush(Signal::dsBlue); @@ -245,41 +245,42 @@ void DecodeTrace::paint_mid(QPainter &p, int left, int right) if (!err.isEmpty()) { draw_error(p, err, left, right); - return; + //return; } - const double scale = _view->scale(); - assert(scale > 0); + const double scale = _view->scale(); + assert(scale > 0); - double samplerate = _decoder_stack->samplerate(); + double samplerate = _decoder_stack->samplerate(); - _cur_row_headings.clear(); + _cur_row_headings.clear(); - // Show sample rate as 1Hz when it is unknown - if (samplerate == 0.0) - samplerate = 1.0; + // Show sample rate as 1Hz when it is unknown + if (samplerate == 0.0) + samplerate = 1.0; - const double pixels_offset = (_view->offset() - - _decoder_stack->get_start_time()) / scale; - const double samples_per_pixel = samplerate * scale; + const int64_t pixels_offset = _view->offset(); + const double samples_per_pixel = samplerate * scale; - const uint64_t start_sample = (uint64_t)max((left + pixels_offset) * - samples_per_pixel, 0.0); + uint64_t start_sample = (uint64_t)max((left + pixels_offset) * + samples_per_pixel, 0.0); uint64_t end_sample = (uint64_t)max((right + pixels_offset) * - samples_per_pixel, 0.0); - const uint64_t samples_decoded = _decoder_stack->samples_decoded(); - if (samples_decoded < start_sample) + samples_per_pixel, 0.0); + BOOST_FOREACH(const boost::shared_ptr &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; - if (samples_decoded < end_sample) - end_sample = samples_decoded; const int annotation_height = _view->get_signalHeight(); - // Iterate through the rows - assert(_view); + // Iterate through the rows + assert(_view); int y = get_y() - (_totalHeight - annotation_height)*0.5; - assert(_decoder_stack); + assert(_decoder_stack); BOOST_FOREACH(boost::shared_ptr dec, _decoder_stack->stack()) { @@ -299,7 +300,8 @@ void DecodeTrace::paint_mid(QPainter &p, int left, int right) const uint64_t max_annotation = _decoder_stack->get_max_annotation(row); const double max_annWidth = max_annotation / samples_per_pixel; - if (max_annWidth > 5) { + if ((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); @@ -310,13 +312,11 @@ void DecodeTrace::paint_mid(QPainter &p, int left, int right) samples_per_pixel, pixels_offset, y, 0, min_annWidth); } - } else if (max_annWidth != 0){ + } else { draw_nodetail(p, annotation_height, left, right, y, 0); } - if (max_annWidth != 0) { - y += annotation_height; - _cur_row_headings.push_back(row.title()); - } + y += annotation_height; + _cur_row_headings.push_back(row.title()); } } } @@ -495,12 +495,50 @@ void DecodeTrace::draw_annotation(const pv::data::decode::Annotation &a, if (start > right + DrawPadding || end < left - DrawPadding) return; + if (_decoder_stack->get_mark_index() == (int64_t)(a.start_sample()+ a.end_sample())/2) { + p.setPen(Signal::dsBlue); + int xpos = (start+end)/2; + int ypos = get_y()+_totalHeight*0.5 + 1; + const QPoint triangle[] = { + QPoint(xpos, ypos), + QPoint(xpos-1, ypos + 1), + QPoint(xpos, ypos + 1), + QPoint(xpos+1, ypos + 1), + QPoint(xpos-2, ypos + 2), + QPoint(xpos-1, ypos + 2), + QPoint(xpos, ypos + 2), + QPoint(xpos+1, ypos + 2), + QPoint(xpos+2, ypos + 2), + }; + p.drawPoints(triangle, 9); + } + if (a.start_sample() == a.end_sample()) draw_instant(a, p, fill, outline, text_color, h, start, y, min_annWidth); - else + else { draw_range(a, p, fill, outline, text_color, h, start, end, y); + if ((a.type()/100 == 2) && (end - start > 20)) { + BOOST_FOREACH(boost::shared_ptr 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()) { + if((sig->get_index() == iter.second) && + (logic_sig = dynamic_pointer_cast(sig))) { + logic_sig->paint_mark(p, start, end, type/100); + break; + } + } + } + } + } + } } void DecodeTrace::draw_nodetail(QPainter &p, @@ -723,13 +761,12 @@ QComboBox* DecodeTrace::create_probe_selector( const vector< boost::shared_ptr > sigs(_session.get_signals()); assert(_decoder_stack); - const map >::const_iterator probe_iter = + const map::const_iterator probe_iter = dec->channels().find(pdch); QComboBox *selector = new QComboBox(parent); - selector->addItem("-", qVariantFromValue((void*)NULL)); + selector->addItem("-", qVariantFromValue(-1)); if (probe_iter == dec->channels().end()) selector->setCurrentIndex(0); @@ -741,9 +778,9 @@ QComboBox* DecodeTrace::create_probe_selector( if (dynamic_pointer_cast(s) && s->enabled()) { selector->addItem(s->get_name(), - qVariantFromValue((void*)s.get())); + qVariantFromValue(s->get_index())); if (probe_iter != dec->channels().end()) { - if ((*probe_iter).second->get_index() == s->get_index()) + if ((*probe_iter).second == s->get_index()) selector->setCurrentIndex(i + 1); } } @@ -756,7 +793,7 @@ void DecodeTrace::commit_decoder_probes(boost::shared_ptr { assert(dec); - map > probe_map; + map probe_map; const vector< boost::shared_ptr > sigs(_session.get_signals()); _index_list.clear(); @@ -765,15 +802,13 @@ void DecodeTrace::commit_decoder_probes(boost::shared_ptr if(s._decoder != dec) break; - const LogicSignal *const selection = - (LogicSignal*)s._combo->itemData( - s._combo->currentIndex()).value(); + const int selection = s._combo->itemData( + s._combo->currentIndex()).value(); BOOST_FOREACH(boost::shared_ptr sig, sigs) - if(sig.get() == selection) { - probe_map[s._pdch] = - dynamic_pointer_cast(sig); - _index_list.push_back(sig->get_index()); + if(sig->get_index() == selection) { + probe_map[s._pdch] = selection; + _index_list.push_back(selection); break; } } diff --git a/DSView/pv/view/devmode.cpp b/DSView/pv/view/devmode.cpp index 6f81f27a..b13a2bff 100644 --- a/DSView/pv/view/devmode.cpp +++ b/DSView/pv/view/devmode.cpp @@ -117,7 +117,7 @@ void DevMode::on_mode_change() if ((*i).first == button) { if (dev_inst->dev_inst()->mode != (*i).second->mode) { _session.stop_capture(); - _session.on_mode_change(); + _session.session_save(); dev_inst->set_config(NULL, NULL, SR_CONF_DEVICE_MODE, g_variant_new_int16((*i).second->mode)); diff --git a/DSView/pv/view/dsldial.cpp b/DSView/pv/view/dsldial.cpp index 6153964b..7d5191f5 100644 --- a/DSView/pv/view/dsldial.cpp +++ b/DSView/pv/view/dsldial.cpp @@ -137,7 +137,7 @@ uint64_t dslDial::get_value() return _value[_sel]; } -bool dslDial::set_value(uint64_t value) +void dslDial::set_value(uint64_t value) { assert(_value.contains(value)); _sel = _value.indexOf(value, 0); diff --git a/DSView/pv/view/dsldial.h b/DSView/pv/view/dsldial.h index 392cf89e..e878bb0f 100644 --- a/DSView/pv/view/dsldial.h +++ b/DSView/pv/view/dsldial.h @@ -53,7 +53,7 @@ public: // get current value uint64_t get_value(); - bool set_value(uint64_t value); + void set_value(uint64_t value); // set/get factor void set_factor(uint64_t factor); diff --git a/DSView/pv/view/dsosignal.cpp b/DSView/pv/view/dsosignal.cpp index a285db4a..aee2e780 100644 --- a/DSView/pv/view/dsosignal.cpp +++ b/DSView/pv/view/dsosignal.cpp @@ -171,9 +171,9 @@ void DsoSignal::set_viewport(pv::view::Viewport *viewport) } -void DsoSignal::set_scale(float scale) +void DsoSignal::set_scale(int height) { - _scale = scale; + _scale = height * 1.0f / (1 << _bits); } float DsoSignal::get_scale() @@ -186,48 +186,37 @@ void DsoSignal::set_enable(bool enable) if (_dev_inst->name() == "DSLogic" && get_index() == 0) return; - _view->session().refresh(INT_MAX); - /* - * avoid race condition for en_ch_num - * data lock need to lock usb event - */ - _dev_inst->set_config(_probe, NULL, SR_CONF_DATALOCK, - g_variant_new_boolean(true)); - set_vDialActive(false); - _dev_inst->set_config(_probe, NULL, SR_CONF_EN_CH, - g_variant_new_boolean(enable)); - int ch_num = _view->session().get_ch_num(SR_CHANNEL_DSO); GVariant* gvar; - uint64_t max_sample_rate; - uint64_t max_sample_limit; - gvar = _dev_inst->get_config(NULL, NULL, SR_CONF_MAX_DSO_SAMPLERATE); + bool cur_enable; + gvar = _dev_inst->get_config(_probe, NULL, SR_CONF_EN_CH); if (gvar != NULL) { - max_sample_rate = g_variant_get_uint64(gvar); + cur_enable = g_variant_get_boolean(gvar); g_variant_unref(gvar); } else { qDebug() << "ERROR: config_get SR_CONF_MAX_DSO_SAMPLERATE failed."; return; } - gvar = _dev_inst->get_config(NULL, NULL, SR_CONF_MAX_DSO_SAMPLELIMITS); - if (gvar != NULL) { - max_sample_limit = g_variant_get_uint64(gvar); - g_variant_unref(gvar); - } else { - qDebug() << "ERROR: config_get SR_CONF_MAX_DSO_SAMPLELIMITS failed."; + if (cur_enable == enable) return; + + bool running = false; + if (_view->session().get_capture_state() == SigSession::Running) { + running = true; + _view->session().stop_capture(); + } + while(_view->session().get_capture_state() == SigSession::Running) + QCoreApplication::processEvents(); + + set_vDialActive(false); + _dev_inst->set_config(_probe, NULL, SR_CONF_EN_CH, + g_variant_new_boolean(enable)); + + if (running) { + update_capture(); + _view->session().repeat_resume(); } - uint64_t sample_limit = (uint64_t)(max_sample_limit / (ch_num ? ch_num : 1)); - uint64_t sample_rate = min((uint64_t)(sample_limit * std::pow(10.0, 9.0) / (_hDial->get_value() * DS_CONF_DSO_HDIVS)), - (uint64_t)(max_sample_rate / (ch_num ? ch_num : 1))); - - _view->set_sample_rate(sample_rate, true); - _view->set_sample_limit(sample_limit, true); - - _dev_inst->set_config(_probe, NULL, SR_CONF_DATALOCK, - g_variant_new_boolean(false)); - _view->session().refresh(RefreshLong); _view->set_update(_viewport, true); _view->update(); } @@ -304,11 +293,11 @@ bool DsoSignal::go_hDialPre(bool setted) uint64_t sample_rate = _view->session().get_device()->get_sample_rate(); const uint64_t min_div = std::pow(10.0, 9.0) / sample_rate; if (_view->session().get_capture_state() != SigSession::Running && - !_data->get_snapshots().empty()) { + !_data->get_snapshots().front()->empty()) { if (_hDial->get_value() > min_div) _hDial->set_sel(_hDial->get_sel() - 1); } else if ((_view->session().get_capture_state() == SigSession::Running || - _data->get_snapshots().empty()) && + _data->get_snapshots().front()->empty()) && !_view->session().get_instant()) { _view->session().refresh(RefreshShort); _hDial->set_sel(_hDial->get_sel() - 1); @@ -346,17 +335,16 @@ bool DsoSignal::go_hDialPre(bool setted) } } -bool DsoSignal::go_hDialCur() +bool DsoSignal::update_capture() { int ch_num = _view->session().get_ch_num(SR_CHANNEL_DSO); if (ch_num == 0) return false; _view->session().refresh(RefreshShort); - uint64_t sample_limit = _view->session().get_device()->get_sample_limit(); - GVariant* gvar; uint64_t max_sample_rate; - gvar = _dev_inst->get_config(NULL, NULL, SR_CONF_MAX_DSO_SAMPLERATE); + uint64_t max_sample_limit; + GVariant *gvar = _dev_inst->get_config(NULL, NULL, SR_CONF_MAX_DSO_SAMPLERATE); if (gvar != NULL) { max_sample_rate = g_variant_get_uint64(gvar); g_variant_unref(gvar); @@ -364,11 +352,19 @@ bool DsoSignal::go_hDialCur() qDebug() << "ERROR: config_get SR_CONF_MAX_DSO_SAMPLERATE failed."; return false; } + gvar = _dev_inst->get_config(NULL, NULL, SR_CONF_MAX_DSO_SAMPLELIMITS); + if (gvar != NULL) { + max_sample_limit = g_variant_get_uint64(gvar); + g_variant_unref(gvar); + } else { + qDebug() << "ERROR: config_get SR_CONF_MAX_DSO_SAMPLELIMITS failed."; + return false; + } + uint64_t sample_limit = (uint64_t)(max_sample_limit / (ch_num ? ch_num : 1)); uint64_t sample_rate = min((uint64_t)(sample_limit * std::pow(10.0, 9.0) / (_hDial->get_value() * DS_CONF_DSO_HDIVS)), (uint64_t)(max_sample_rate / (ch_num ? ch_num : 1))); -// _dev_inst->set_config(NULL, NULL, SR_CONF_SAMPLERATE, -// g_variant_new_uint64(sample_rate)); + _view->set_sample_limit(sample_limit, true); _view->set_sample_rate(sample_rate, true); _dev_inst->set_config(_probe, NULL, SR_CONF_TIMEBASE, @@ -381,10 +377,10 @@ bool DsoSignal::go_hDialNext(bool setted) int ch_num = _view->session().get_ch_num(SR_CHANNEL_DSO); if (ch_num != 0 && !_hDial->isMax()) { if (_view->session().get_capture_state() != SigSession::Running && - !_data->get_snapshots().empty()) { + !_data->get_snapshots().front()->empty()) { _hDial->set_sel(_hDial->get_sel() + 1); } else if ((_view->session().get_capture_state() == SigSession::Running || - _data->get_snapshots().empty()) && + _data->get_snapshots().front()->empty()) && !_view->session().get_instant()) { _view->session().refresh(RefreshShort); _hDial->set_sel(_hDial->get_sel() + 1); @@ -428,15 +424,17 @@ bool DsoSignal::load_settings() GVariant* gvar; // -- enable - //bool enable; - //gvar = _dev_inst->get_config(_probe, NULL, SR_CONF_EN_CH); - //if (gvar != NULL) { - // enable = g_variant_get_boolean(gvar); - // g_variant_unref(gvar); - //} else { - // qDebug() << "ERROR: config_get SR_CONF_EN_CH failed."; - // return false; - //} +// bool enable; +// gvar = _dev_inst->get_config(_probe, NULL, SR_CONF_EN_CH); +// if (gvar != NULL) { +// enable = g_variant_get_boolean(gvar); +// g_variant_unref(gvar); +// } else { +// qDebug() << "ERROR: config_get SR_CONF_EN_CH failed."; +// return false; +// } + + // dso channel bits gvar = _dev_inst->get_config(NULL, NULL, SR_CONF_DSO_BITS); if (gvar != NULL) { _bits = g_variant_get_byte(gvar); @@ -444,7 +442,8 @@ bool DsoSignal::load_settings() } else { _bits = DefaultBits; qDebug("Warning: config_get SR_CONF_DSO_BITS failed, set to %d(default).", DefaultBits); - return false; + if (strncmp(_dev_inst->name().toLocal8Bit(), "virtual", 7)) + return false; } // -- hdiv @@ -515,10 +514,8 @@ bool DsoSignal::load_settings() return false; } _zero_vrate = min(max((0.5 - vpos / (_vDial->get_value() * DS_CONF_DSO_VDIVS)), 0.0), 1.0); - if (_dev_inst->name() == "DSCope") - _zero_value = _zero_vrate * ((1 << _bits) - 1); - else - _zero_value = 0x80; + if (_dev_inst->name().contains("virtual")) + cur_hw_offset = _zero_vrate * ((1 << _bits) - 1); // -- trig_value gvar = _dev_inst->get_config(_probe, NULL, SR_CONF_TRIGGER_VALUE); @@ -528,7 +525,8 @@ bool DsoSignal::load_settings() g_variant_unref(gvar); } else { qDebug() << "ERROR: config_get SR_CONF_TRIGGER_VALUE failed."; - return false; + if (strncmp(_dev_inst->name().toLocal8Bit(), "virtual", 7)) + return false; } if (_view) { @@ -666,29 +664,33 @@ double DsoSignal::get_zero_vrate() return _zero_vrate; } -double DsoSignal::get_zero_value() +double DsoSignal::get_hw_offset() { - return _zero_value; + return cur_hw_offset; } void DsoSignal::set_zero_vpos(int pos) { if (enabled()) { double delta = _trig_delta* get_view_rect().height(); - _zero_vrate = min(max(pos - UpMargin, 0), get_view_rect().height()) * 1.0 / get_view_rect().height(); + set_zero_vrate(min(max(pos - UpMargin, 0), get_view_rect().height()) * 1.0 / get_view_rect().height(), false); set_trig_vpos(get_zero_vpos() + delta, false); - update_offset(); } } -void DsoSignal::set_zero_vrate(double rate) +void DsoSignal::set_zero_vrate(double rate, bool force_update) { _zero_vrate = rate; - if (_dev_inst->name() == "DSCope") - _zero_value = _zero_vrate * ((1 << _bits) - 1); - else - _zero_value = 0x80; update_offset(); + + if (!_dev_inst->name().contains("virtual") && + (force_update || + _view->session().get_capture_state() == SigSession::Running)) { + if (_dev_inst->name() == "DSLogic") + cur_hw_offset = 0x80; + else + cur_hw_offset = _zero_vrate * ((1 << _bits) - 1); + } } void DsoSignal::set_factor(uint64_t factor) @@ -818,8 +820,7 @@ void DsoSignal::paint_back(QPainter &p, int left, int right) const double samplerate = _dev_inst->get_sample_rate(); const double samples_per_pixel = samplerate * _view->scale(); const double shown_rate = min(samples_per_pixel * width * 1.0 / sample_len, 1.0); - const double start_time = _data->get_start_time(); - const double start = samplerate * (_view->offset() - start_time); + const double start = _view->offset() * samples_per_pixel; const double shown_offset = min(start / sample_len, 1.0) * width; const double shown_len = shown_rate * width; const QPointF left_edge[] = {QPoint(shown_offset + 3, UpMargin/2 - 6), @@ -875,7 +876,7 @@ void DsoSignal::paint_mid(QPainter &p, int left, int right) const int y = get_zero_vpos() + height * 0.5; const double scale = _view->scale(); assert(scale > 0); - const double offset = _view->offset(); + const int64_t offset = _view->offset(); const deque< boost::shared_ptr > &snapshots = _data->get_snapshots(); @@ -886,18 +887,16 @@ void DsoSignal::paint_mid(QPainter &p, int left, int right) if (snapshot->empty()) return; - const uint16_t number_channels = snapshot->get_channel_num(); - if (_dev_inst->name() == "DSLogic" && - (unsigned int)get_index() >= number_channels) + if (!snapshot->has_data(get_index())) return; - const double pixels_offset = offset / scale; + const uint16_t number_channels = snapshot->get_channel_num(); + const double pixels_offset = offset; //const double samplerate = _data->samplerate(); const double samplerate = _dev_inst->get_sample_rate(); - const double start_time = _data->get_start_time(); const int64_t last_sample = max((int64_t)(snapshot->get_sample_count() - 1), (int64_t)0); const double samples_per_pixel = samplerate * scale; - const double start = samplerate * (offset - start_time); + const double start = offset * samples_per_pixel; const double end = start + samples_per_pixel * width; const int64_t start_sample = min(max((int64_t)floor(start), @@ -923,6 +922,9 @@ void DsoSignal::paint_fore(QPainter &p, int left, int right) { assert(_view); + bool antialiasing = p.Antialiasing; + p.setRenderHint(QPainter::Antialiasing, false); + QPen pen(Signal::dsGray); pen.setStyle(Qt::DotLine); p.setPen(pen); @@ -967,6 +969,8 @@ void DsoSignal::paint_fore(QPainter &p, int left, int right) // Paint measure paint_measure(p); } + + p.setRenderHint(QPainter::Antialiasing, antialiasing); } QRectF DsoSignal::get_trig_rect(int left, int right) const @@ -1001,9 +1005,6 @@ void DsoSignal::paint_trace(QPainter &p, float top = get_view_rect().top(); float bottom = get_view_rect().bottom(); float zeroP = _zero_vrate * get_view_rect().height() + top;; - if (_dev_inst->name() == "DSCope" && - _view->session().get_capture_state() == SigSession::Running) - _zero_value = _zero_vrate * ((1 << _bits) - 1); float x = (start / samples_per_pixel - pixels_offset) + left; double pixels_per_sample = 1.0/samples_per_pixel; uint8_t offset; @@ -1014,7 +1015,7 @@ void DsoSignal::paint_trace(QPainter &p, //offset = samples[(sample - start)*num_channels]; offset = samples[sample]; - const float y = min(max(top, zeroP + (offset - _zero_value) * _scale), bottom); + const float y = min(max(top, zeroP + (offset - cur_hw_offset) * _scale), bottom); *point++ = QPointF(x, y); x += pixels_per_sample; //*point++ = QPointF(x, top + offset); @@ -1057,9 +1058,6 @@ void DsoSignal::paint_envelope(QPainter &p, float top = get_view_rect().top(); float bottom = get_view_rect().bottom(); float zeroP = _zero_vrate * get_view_rect().height() + top; - if (_dev_inst->name() == "DSCope" && - _view->session().get_capture_state() == SigSession::Running) - _zero_value = _zero_vrate * ((1 << _bits) - 1); for(uint64_t sample = 0; sample < e.length-1; sample++) { const float x = ((e.scale * sample + e.start) / samples_per_pixel - pixels_offset) + left; @@ -1068,8 +1066,8 @@ void DsoSignal::paint_envelope(QPainter &p, // We overlap this sample with the next so that vertical // gaps do not appear during steep rising or falling edges - const float b = min(max(top, ((max(s->max, (s+1)->min) - _zero_value) * _scale + zeroP)), bottom); - const float t = min(max(top, ((min(s->min, (s+1)->max) - _zero_value) * _scale + zeroP)), bottom); + const float b = min(max(top, ((max(s->max, (s+1)->min) - cur_hw_offset) * _scale + zeroP)), bottom); + const float t = min(max(top, ((min(s->min, (s+1)->max) - cur_hw_offset) * _scale + zeroP)), bottom); float h = b - t; if(h >= 0.0f && h <= 1.0f) @@ -1086,11 +1084,6 @@ void DsoSignal::paint_envelope(QPainter &p, //delete[] e.samples; } -const std::vector< std::pair > DsoSignal::cur_edges() const -{ - -} - void DsoSignal::paint_type_options(QPainter &p, int right, const QPoint pt) { int y = get_y(); @@ -1328,21 +1321,21 @@ void DsoSignal::paint_measure(QPainter &p) _min = (index == 0) ? status.ch0_min : status.ch1_min; const uint64_t period = (index == 0) ? status.ch0_period : status.ch1_period; const uint32_t count = (index == 0) ? status.ch0_pcnt : status.ch1_pcnt; - double value_max = (_zero_value - _min) * _scale * _vDial->get_value() * _vDial->get_factor() * DS_CONF_DSO_VDIVS / get_view_rect().height(); - double value_min = (_zero_value - _max) * _scale * _vDial->get_value() * _vDial->get_factor() * DS_CONF_DSO_VDIVS / get_view_rect().height(); + double value_max = (cur_hw_offset - _min) * _scale * _vDial->get_value() * _vDial->get_factor() * DS_CONF_DSO_VDIVS / get_view_rect().height(); + double value_min = (cur_hw_offset - _max) * _scale * _vDial->get_value() * _vDial->get_factor() * DS_CONF_DSO_VDIVS / get_view_rect().height(); double value_p2p = value_max - value_min; _period = (count == 0) ? period * 10.0 : period * 10.0 / count; const int channel_count = _view->session().get_ch_num(SR_CHANNEL_DSO); uint64_t sample_rate = _dev_inst->get_sample_rate(); _period = _period * 200.0 / (channel_count * sample_rate * 1.0 / SR_MHZ(1)); - _ms_string[DSO_MS_VMAX] = "Vmax: " + (abs(value_max) > 1000 ? QString::number(value_max/1000.0, 'f', 2) + "V" : QString::number(value_max, 'f', 2) + "mV"); - _ms_string[DSO_MS_VMIN] = "Vmin: " + (abs(value_min) > 1000 ? QString::number(value_min/1000.0, 'f', 2) + "V" : QString::number(value_min, 'f', 2) + "mV"); - _ms_string[DSO_MS_PERD] = "Perd: " + (abs(_period) > 1000000000 ? QString::number(_period/1000000000, 'f', 2) + "S" : + _ms_string[DSO_MS_VMAX] = tr("Vmax: ") + (abs(value_max) > 1000 ? QString::number(value_max/1000.0, 'f', 2) + "V" : QString::number(value_max, 'f', 2) + "mV"); + _ms_string[DSO_MS_VMIN] = tr("Vmin: ") + (abs(value_min) > 1000 ? QString::number(value_min/1000.0, 'f', 2) + "V" : QString::number(value_min, 'f', 2) + "mV"); + _ms_string[DSO_MS_PERD] = tr("Perd: ") + (abs(_period) > 1000000000 ? QString::number(_period/1000000000, 'f', 2) + "S" : abs(_period) > 1000000 ? QString::number(_period/1000000, 'f', 2) + "mS" : abs(_period) > 1000 ? QString::number(_period/1000, 'f', 2) + "uS" : QString::number(_period, 'f', 2) + "nS"); - _ms_string[DSO_MS_FREQ] = "Freq: " + (abs(_period) > 1000000 ? QString::number(1000000000/_period, 'f', 2) + "Hz" : + _ms_string[DSO_MS_FREQ] = tr("Freq: ") + (abs(_period) > 1000000 ? QString::number(1000000000/_period, 'f', 2) + "Hz" : abs(_period) > 1000 ? QString::number(1000000/_period, 'f', 2) + "kHz" : QString::number(1000/_period, 'f', 2) + "MHz"); - _ms_string[DSO_MS_VP2P] = "Vp-p: " + (abs(value_p2p) > 1000 ? QString::number(value_p2p/1000.0, 'f', 2) + "V" : QString::number(value_p2p, 'f', 2) + "mV"); + _ms_string[DSO_MS_VP2P] = tr("Vp-p: ") + (abs(value_p2p) > 1000 ? QString::number(value_p2p/1000.0, 'f', 2) + "V" : QString::number(value_p2p, 'f', 2) + "mV"); if (_probe->ms_show && _probe->ms_en[DSO_MS_VRMS]) { const deque< boost::shared_ptr > &snapshots = @@ -1350,9 +1343,9 @@ void DsoSignal::paint_measure(QPainter &p) if (!snapshots.empty()) { const boost::shared_ptr &snapshot = snapshots.front(); - const double vrms = snapshot->cal_vrms(_zero_value, get_index()); + const double vrms = snapshot->cal_vrms(cur_hw_offset, get_index()); const double value_vrms = vrms * _scale * _vDial->get_value() * _vDial->get_factor() * DS_CONF_DSO_VDIVS / get_view_rect().height(); - _ms_string[DSO_MS_VRMS] = "Vrms: " + (abs(value_vrms) > 1000 ? QString::number(value_vrms/1000.0, 'f', 2) + "V" : QString::number(value_vrms, 'f', 2) + "mV"); + _ms_string[DSO_MS_VRMS] = tr("Vrms: ") + (abs(value_vrms) > 1000 ? QString::number(value_vrms/1000.0, 'f', 2) + "V" : QString::number(value_vrms, 'f', 2) + "mV"); } } @@ -1363,18 +1356,18 @@ void DsoSignal::paint_measure(QPainter &p) const boost::shared_ptr &snapshot = snapshots.front(); const double vmean = snapshot->cal_vmean(get_index()); - const double value_vmean = (_zero_value - vmean) * _scale * _vDial->get_value() * _vDial->get_factor() * DS_CONF_DSO_VDIVS / get_view_rect().height(); - _ms_string[DSO_MS_VMEA] = "Vmean: " + (abs(value_vmean) > 1000 ? QString::number(value_vmean/1000.0, 'f', 2) + "V" : QString::number(value_vmean, 'f', 2) + "mV"); + const double value_vmean = (cur_hw_offset - vmean) * _scale * _vDial->get_value() * _vDial->get_factor() * DS_CONF_DSO_VDIVS / get_view_rect().height(); + _ms_string[DSO_MS_VMEA] = tr("Vmean: ") + (abs(value_vmean) > 1000 ? QString::number(value_vmean/1000.0, 'f', 2) + "V" : QString::number(value_vmean, 'f', 2) + "mV"); } } } else { - _ms_string[DSO_MS_VMAX] = "Vmax: #####"; - _ms_string[DSO_MS_VMIN] = "Vmin: #####"; - _ms_string[DSO_MS_PERD] = "Perd: #####"; - _ms_string[DSO_MS_FREQ] = "Freq: #####"; - _ms_string[DSO_MS_VP2P] = "Vp-p: #####"; - _ms_string[DSO_MS_VRMS] = "Vrms: #####"; - _ms_string[DSO_MS_VMEA] = "Vmean: #####"; + _ms_string[DSO_MS_VMAX] = tr("Vmax: #####"); + _ms_string[DSO_MS_VMIN] = tr("Vmin: #####"); + _ms_string[DSO_MS_PERD] = tr("Perd: #####"); + _ms_string[DSO_MS_FREQ] = tr("Freq: #####"); + _ms_string[DSO_MS_VP2P] = tr("Vp-p: #####"); + _ms_string[DSO_MS_VRMS] = tr("Vrms: #####"); + _ms_string[DSO_MS_VMEA] = tr("Vmean: #####"); } QColor measure_colour = _colour; @@ -1506,8 +1499,7 @@ bool DsoSignal::measure(const QPointF &p) const double scale = _view->scale(); assert(scale > 0); - const double offset = _view->offset(); - const double pixels_offset = offset / scale; + const int64_t pixels_offset = _view->offset(); const double samplerate = _dev_inst->get_sample_rate(); const double samples_per_pixel = samplerate * scale; @@ -1529,17 +1521,17 @@ bool DsoSignal::measure(const QPointF &p) const uint8_t cur_sample = *snapshot->get_samples(_hover_index, _hover_index, get_index()); const uint8_t nxt_sample = *snapshot->get_samples(nxt_index, nxt_index, get_index()); - _hover_value = (_zero_value - cur_sample) * _scale * _vDial->get_value() * _vDial->get_factor() * DS_CONF_DSO_VDIVS / get_view_rect().height(); + _hover_value = (cur_hw_offset - cur_sample) * _scale * _vDial->get_value() * _vDial->get_factor() * DS_CONF_DSO_VDIVS / get_view_rect().height(); float top = get_view_rect().top(); float bottom = get_view_rect().bottom(); float zeroP = _zero_vrate * get_view_rect().height() + top; float pre_x = (pre_index / samples_per_pixel - pixels_offset); - const float pre_y = min(max(top, zeroP + (pre_sample - _zero_value)* _scale), bottom); + const float pre_y = min(max(top, zeroP + (pre_sample - cur_hw_offset)* _scale), bottom); float x = (_hover_index / samples_per_pixel - pixels_offset); - const float y = min(max(top, zeroP + (cur_sample - _zero_value)* _scale), bottom); + const float y = min(max(top, zeroP + (cur_sample - cur_hw_offset)* _scale), bottom); float nxt_x = (nxt_index / samples_per_pixel - pixels_offset); - const float nxt_y = min(max(top, zeroP + (nxt_sample - _zero_value)* _scale), bottom); + const float nxt_y = min(max(top, zeroP + (nxt_sample - cur_hw_offset)* _scale), bottom); const QRectF slope_rect = QRectF(QPointF(pre_x - 10, pre_y - 10), QPointF(nxt_x + 10, nxt_y + 10)); if (abs(y-p.y()) < 20 || slope_rect.contains(p)) { _hover_point = QPointF(x, y); diff --git a/DSView/pv/view/dsosignal.h b/DSView/pv/view/dsosignal.h index 790bd61c..78d8522d 100644 --- a/DSView/pv/view/dsosignal.h +++ b/DSView/pv/view/dsosignal.h @@ -100,7 +100,7 @@ public: boost::shared_ptr dso_data() const; void set_viewport(pv::view::Viewport *viewport); - void set_scale(float scale); + void set_scale(int height); float get_scale(); /** @@ -115,7 +115,7 @@ public: bool go_vDialNext(); bool go_hDialPre(bool setted); bool go_hDialNext(bool setted); - bool go_hDialCur(); + bool update_capture(); uint64_t get_vDialValue() const; uint64_t get_hDialValue() const; uint16_t get_vDialSel() const; @@ -148,12 +148,12 @@ public: */ int get_zero_vpos(); double get_zero_vrate(); - double get_zero_value(); + double get_hw_offset(); /** * Sets the mid-Y position of this signal. */ void set_zero_vpos(int pos); - void set_zero_vrate(double rate); + void set_zero_vrate(double rate, bool force_update); void update_offset(); /** @@ -180,8 +180,6 @@ public: **/ void paint_fore(QPainter &p, int left, int right); - const std::vector< std::pair > cur_edges() const; - QRect get_view_rect() const; QRectF get_trig_rect(int left, int right) const; @@ -234,7 +232,7 @@ private: int _trig_value; double _trig_delta; double _zero_vrate; - float _zero_value; + float cur_hw_offset; uint8_t _max; uint8_t _min; diff --git a/DSView/pv/view/groupsignal.cpp b/DSView/pv/view/groupsignal.cpp index b48eefe5..0f60328e 100644 --- a/DSView/pv/view/groupsignal.cpp +++ b/DSView/pv/view/groupsignal.cpp @@ -81,7 +81,7 @@ void GroupSignal::paint_mid(QPainter &p, int left, int right) const int y = get_y() + _totalHeight * 0.5; const double scale = _view->scale(); assert(scale > 0); - const double offset = _view->offset(); + const int64_t offset = _view->offset(); _scale = _totalHeight * 1.0f / std::pow(2.0, static_cast(_index_list.size())); @@ -93,12 +93,11 @@ void GroupSignal::paint_mid(QPainter &p, int left, int right) const boost::shared_ptr &snapshot = snapshots.at(_sec_index); - const double pixels_offset = offset / scale; + const double pixels_offset = offset; const double samplerate = _data->samplerate(); - const double start_time = _data->get_start_time(); const int64_t last_sample = snapshot->get_sample_count() - 1; const double samples_per_pixel = samplerate * scale; - const double start = samplerate * (offset - start_time); + const double start = offset * samples_per_pixel; const double end = start + samples_per_pixel * (right - left); const int64_t start_sample = min(max((int64_t)floor(start), @@ -190,11 +189,6 @@ void GroupSignal::paint_envelope(QPainter &p, delete[] e.samples; } -const std::vector< std::pair > GroupSignal::cur_edges() const -{ - -} - void GroupSignal::paint_type_options(QPainter &p, int right, const QPoint pt) { (void)pt; diff --git a/DSView/pv/view/groupsignal.h b/DSView/pv/view/groupsignal.h index 711382ca..cae5aa8b 100644 --- a/DSView/pv/view/groupsignal.h +++ b/DSView/pv/view/groupsignal.h @@ -76,8 +76,6 @@ public: **/ void paint_mid(QPainter &p, int left, int right); - const std::vector< std::pair > cur_edges() const; - QRectF get_rect(GroupSetRegions type, int y, int right); protected: diff --git a/DSView/pv/view/header.cpp b/DSView/pv/view/header.cpp index 6e5e430e..d8aa85ca 100644 --- a/DSView/pv/view/header.cpp +++ b/DSView/pv/view/header.cpp @@ -75,9 +75,6 @@ Header::Header(View &parent) : connect(nameEdit, SIGNAL(editingFinished()), this, SLOT(on_action_set_name_triggered())); - - connect(&_view, SIGNAL(traces_moved()), - this, SLOT(on_traces_moved())); } @@ -322,7 +319,6 @@ void Header::mouseMoveEvent(QMouseEvent *event) } } } - //traces_moved(); } update(); } @@ -380,11 +376,6 @@ void Header::on_action_del_group_triggered() _view.session().del_group(); } -void Header::on_traces_moved() -{ - update(); -} - void Header::header_resize() { //if (nameEdit->isVisible()) { diff --git a/DSView/pv/view/header.h b/DSView/pv/view/header.h index 6d11b2fd..6bad7117 100644 --- a/DSView/pv/view/header.h +++ b/DSView/pv/view/header.h @@ -77,8 +77,6 @@ private slots: void on_action_del_group_triggered(); - void on_traces_moved(); - signals: void traces_moved(); void header_updated(); diff --git a/DSView/pv/view/logicsignal.cpp b/DSView/pv/view/logicsignal.cpp index e5d543b8..093781f5 100644 --- a/DSView/pv/view/logicsignal.cpp +++ b/DSView/pv/view/logicsignal.cpp @@ -20,6 +20,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include #include @@ -74,6 +75,7 @@ LogicSignal::LogicSignal(boost::shared_ptr s, LogicSignal::~LogicSignal() { _cur_edges.clear(); + _cur_pulses.clear(); } const sr_channel* LogicSignal::probe() const @@ -128,8 +130,6 @@ void LogicSignal::paint_mid(QPainter &p, int left, int right) { using pv::view::View; - QLineF *line; - assert(_data); assert(_view); assert(right >= left); @@ -137,10 +137,10 @@ void LogicSignal::paint_mid(QPainter &p, int left, int right) const int y = get_y() + _totalHeight * 0.5; const double scale = _view->scale(); assert(scale > 0); - const double offset = _view->offset(); + const int64_t offset = _view->offset(); - const float high_offset = y - _totalHeight + 0.5f; - const float low_offset = y + 0.5f; + const int high_offset = y - _totalHeight + 0.5f; + const int low_offset = y + 0.5f; const deque< boost::shared_ptr > &snapshots = _data->get_snapshots(); @@ -150,47 +150,60 @@ void LogicSignal::paint_mid(QPainter &p, int left, int right) const boost::shared_ptr &snapshot = snapshots.front(); - if (snapshot->empty()) + if (snapshot->empty() || !snapshot->has_data(_probe->index)) return; - const double pixels_offset = offset / scale; - const double start_time = _data->get_start_time(); const int64_t last_sample = snapshot->get_sample_count() - 1; const double samples_per_pixel = samplerate * scale; - const double start = samplerate * (offset - start_time); - const double end = start + samples_per_pixel * (right - left); - snapshot->get_subsampled_edges(_cur_edges, - min(max((int64_t)floor(start), (int64_t)0), last_sample), - min(max((int64_t)ceil(end), (int64_t)0), last_sample), - samples_per_pixel / Oversampling, _probe->index); - if (_cur_edges.size() < 2) + uint16_t width = right - left; + const double start = offset * samples_per_pixel; + const double end = (offset + width + 1) * samples_per_pixel; + const uint64_t end_index = min(max((int64_t)ceil(end), (int64_t)0), last_sample); + const uint64_t start_index = max((uint64_t)floor(start), (uint64_t)0); + if (start_index > end_index) return; + width = min(width, (uint16_t)ceil((end_index + 1)/samples_per_pixel - offset)); + const uint16_t max_togs = width / TogMaxScale; - // Paint the edges - const unsigned int edge_count = 2 * _cur_edges.size() - 3; - QLineF *const edge_lines = new QLineF[edge_count]; - line = edge_lines; + const bool first_sample = snapshot->get_display_edges(_cur_pulses, _cur_edges, + start_index, end_index, width, max_togs, + offset, + samples_per_pixel, _probe->index); + assert(_cur_pulses.size() >= width); - double preX = ((*(_cur_edges.begin())).first / samples_per_pixel - pixels_offset) + left; - double preY = (*(_cur_edges.begin())).second ? high_offset : low_offset; - vector::const_iterator i; - for ( i = _cur_edges.begin() + 1; i != _cur_edges.end() - 1; i++) { - const double x = ((*i).first / samples_per_pixel - - pixels_offset) + left; - const double y = (*i).second ? high_offset : low_offset; - *line++ = QLineF(preX, preY, x, preY); - *line++ = QLineF(x, high_offset, x, low_offset); - preX = x; - preY = y; + int preX = 0; + int preY = first_sample ? high_offset : low_offset; + int x = preX; + std::vector wave_lines; + if (_cur_edges.size() < max_togs) { + std::vector>::const_iterator i; + for (i = _cur_edges.begin() + 1; i != _cur_edges.end() - 1; i++) { + x = (*i).first; + wave_lines.push_back(QLine(preX, preY, x, preY)); + wave_lines.push_back(QLine(x, high_offset, x, low_offset)); + preX = x; + preY = (*i).second ? high_offset : low_offset; + } + x = (*i).first; + wave_lines.push_back(QLine(preX, preY, x, preY)); + } else { + std::vector>::const_iterator i = _cur_pulses.begin(); + while (i != _cur_pulses.end() - 1) { + if ((*i).first) { + wave_lines.push_back(QLine(preX, preY, x, preY)); + wave_lines.push_back(QLine(x, high_offset, x, low_offset)); + preX = x; + preY = (*i).second ? high_offset : low_offset; + } + x++; + i++; + } + wave_lines.push_back(QLine(preX, preY, x, preY)); } - const double x = ((*i).first / samples_per_pixel - - pixels_offset) + left; - *line++ = QLineF(preX, preY, x, preY); p.setPen(_colour); - p.drawLines(edge_lines, edge_count); - delete[] edge_lines; + p.drawLines(wave_lines.data(), wave_lines.size()); } void LogicSignal::paint_caps(QPainter &p, QLineF *const lines, @@ -216,11 +229,6 @@ void LogicSignal::paint_caps(QPainter &p, QLineF *const lines, p.drawLines(lines, line - lines); } -const std::vector< std::pair > LogicSignal::cur_edges() const -{ - return _cur_edges; -} - void LogicSignal::paint_type_options(QPainter &p, int right, const QPoint pt) { int y = get_y(); @@ -305,32 +313,43 @@ bool LogicSignal::measure(const QPointF &p, uint64_t &index0, uint64_t &index1, const boost::shared_ptr &snapshot = snapshots.front(); - if (snapshot->empty()) + if (snapshot->empty() || !snapshot->has_data(_probe->index)) return false; - uint64_t index = _data->samplerate() * (_view->offset() - _data->get_start_time() + p.x() * _view->scale()); - if (index == 0 || index >= (snapshot->get_sample_count() - 1)) + const uint64_t end = snapshot->get_sample_count() - 1; + uint64_t index = _data->samplerate() * _view->scale() * (_view->offset() + p.x()); + if (index > end) return false; - const uint64_t sig_mask = 1ULL << get_index(); - bool sample = snapshot->get_sample(index) & sig_mask; - index--; - if (!snapshot->get_pre_edge(index, sample, 1, get_index())) - return false; + bool sample = snapshot->get_sample(index, get_index()); + if (index == 0) + index0 = index; + else { + index--; + if (snapshot->get_pre_edge(index, sample, 1, get_index())) + index0 = index; + else + index0 = 0; + } - index0 = index; - sample = snapshot->get_sample(index) & sig_mask; + sample = snapshot->get_sample(index, get_index()); index++; - if (!snapshot->get_nxt_edge(index, sample, snapshot->get_sample_count(), 1, get_index())) - return false; - - index1 = index; - sample = snapshot->get_sample(index) & sig_mask; - index++; - if (!snapshot->get_nxt_edge(index, sample, snapshot->get_sample_count(), 1, get_index())) + if (snapshot->get_nxt_edge(index, sample, end, 1, get_index())) + index1 = index; + else { + if (index0 == 0) + return false; + index1 = end + 1; index2 = 0; - else + return true; + } + + sample = snapshot->get_sample(index, get_index()); + index++; + if (snapshot->get_nxt_edge(index, sample, end, 1, get_index())) index2 = index; + else + index2 = end + 1; return true; } @@ -340,47 +359,54 @@ bool LogicSignal::measure(const QPointF &p, uint64_t &index0, uint64_t &index1, bool LogicSignal::edges(const QPointF &p, uint64_t start, uint64_t &rising, uint64_t &falling) const { - uint64_t index, end; + uint64_t end; const float gap = abs(p.y() - get_y()); if (gap < get_totalHeight() * 0.5) { - const deque< boost::shared_ptr > &snapshots = - _data->get_snapshots(); - if (snapshots.empty()) - return false; - - const boost::shared_ptr &snapshot = - snapshots.front(); - if (snapshot->empty()) - return false; - - end = _data->samplerate() * (_view->offset() - _data->get_start_time() + p.x() * _view->scale()); - index = min(start, end); - end = max(start, end); - start = index; - if (end > (snapshot->get_sample_count() - 1)) - return false; - - const uint64_t sig_mask = 1ULL << get_index(); - bool sample = snapshot->get_sample(start) & sig_mask; - - rising = 0; - falling = 0; - do { - if (snapshot->get_nxt_edge(index, sample, snapshot->get_sample_count(), 1, get_index())) { - if (index > end) - break; - rising += !sample; - falling += sample; - sample = !sample; - } else { - break; - } - } while(index <= end); - return true; + end = _data->samplerate() * _view->scale() * (_view->offset() + p.x()); + return edges(end, start, rising, falling); } return false; } +bool LogicSignal::edges(uint64_t end, uint64_t start, uint64_t &rising, uint64_t &falling) const +{ + const deque< boost::shared_ptr > &snapshots = + _data->get_snapshots(); + if (snapshots.empty()) + return false; + + const boost::shared_ptr &snapshot = + snapshots.front(); + if (snapshot->empty() || !snapshot->has_data(_probe->index)) + return false; + + uint64_t index = min(start, end); + const uint64_t sample_count = snapshot->get_sample_count(); + end = max(start, end); + start = index; + if (end > (sample_count - 1)) + return false; + + const int ch_index = get_index(); + bool sample = snapshot->get_sample(start, ch_index); + + rising = 0; + falling = 0; + do { + if (snapshot->get_nxt_edge(index, sample, sample_count, 1, ch_index)) { + if (index > end) + break; + rising += !sample; + falling += sample; + sample = !sample; + } else { + break; + } + } while(index <= end); + + return true; +} + bool LogicSignal::mouse_press(int right, const QPoint pt) { int y = get_y(); @@ -439,5 +465,38 @@ QRectF LogicSignal::get_rect(LogicSetRegions type, int y, int right) return QRectF(0, 0, 0, 0); } + +void LogicSignal::paint_mark(QPainter &p, int xstart, int xend, int type) +{ + const int ypos = get_y(); + const int msize = 3; + p.setPen(p.brush().color()); + if (type == SRD_CHANNEL_SDATA) { + p.drawEllipse(QPoint(xstart, ypos), msize, msize); + } else if (type == SRD_CHANNEL_SCLK) { + const QPoint triangle[] = { + QPoint(xstart, ypos - 2), + QPoint(xstart-1, ypos - 1), + QPoint(xstart, ypos - 1), + QPoint(xstart+1, ypos - 1), + QPoint(xstart-2, ypos), + QPoint(xstart-1, ypos), + QPoint(xstart, ypos), + QPoint(xstart+1, ypos), + QPoint(xstart+2, ypos), + QPoint(xstart-3, ypos + 1), + QPoint(xstart-2, ypos + 1), + QPoint(xstart-1, ypos + 1), + QPoint(xstart, ypos + 1), + QPoint(xstart+1, ypos + 1), + QPoint(xstart+2, ypos + 1), + QPoint(xstart+3, ypos + 1), + }; + p.drawPoints(triangle, 16); + } else if (type == SRD_CHANNEL_ADATA) { + p.drawEllipse(QPoint((xstart+xend)/2, ypos), msize, msize); + } +} + } // namespace view } // namespace pv diff --git a/DSView/pv/view/logicsignal.h b/DSView/pv/view/logicsignal.h index 32f00683..b34f5646 100644 --- a/DSView/pv/view/logicsignal.h +++ b/DSView/pv/view/logicsignal.h @@ -53,6 +53,8 @@ private: static const int StateHeight; static const int StateRound; + static const int TogMaxScale = 10; + enum LogicSetRegions{ NONTRIG = 0, POSTRIG, @@ -94,16 +96,18 @@ public: **/ void paint_mid(QPainter &p, int left, int right); - const std::vector< std::pair > cur_edges() const; - bool measure(const QPointF &p, uint64_t &index0, uint64_t &index1, uint64_t &index2) const; bool edges(const QPointF &p, uint64_t start, uint64_t &rising, uint64_t &falling) const; + bool edges(uint64_t end, uint64_t start, uint64_t &rising, uint64_t &falling) const; + bool mouse_press(int right, const QPoint pt); QRectF get_rect(LogicSetRegions type, int y, int right); + void paint_mark(QPainter &p, int xstart, int xend, int type); + protected: void paint_type_options(QPainter &p, int right, const QPoint pt); @@ -116,7 +120,8 @@ private: private: boost::shared_ptr _data; - std::vector< std::pair > _cur_edges; + 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 0b6b6f4c..d388e1b5 100644 --- a/DSView/pv/view/mathtrace.cpp +++ b/DSView/pv/view/mathtrace.cpp @@ -108,7 +108,7 @@ int MathTrace::view_mode() const return _view_mode; } -void MathTrace::set_view_mode(int mode) +void MathTrace::set_view_mode(unsigned int mode) { assert(mode < sizeof(FFT_ViewMode)/sizeof(FFT_ViewMode[0])); _view_mode = mode; diff --git a/DSView/pv/view/mathtrace.h b/DSView/pv/view/mathtrace.h index 7bb39783..99786f44 100644 --- a/DSView/pv/view/mathtrace.h +++ b/DSView/pv/view/mathtrace.h @@ -88,7 +88,7 @@ public: std::vector get_dbv_ranges(); int view_mode() const; - void set_view_mode(int mode); + void set_view_mode(unsigned int mode); std::vector get_view_modes_support(); const boost::shared_ptr& get_math_stack() const; diff --git a/DSView/pv/view/ruler.cpp b/DSView/pv/view/ruler.cpp index c14af957..3da9e04f 100644 --- a/DSView/pv/view/ruler.cpp +++ b/DSView/pv/view/ruler.cpp @@ -205,8 +205,9 @@ void Ruler::mouseMoveEvent(QMouseEvent *e) (void)e; if (_grabbed_marker) { - _grabbed_marker->set_index((_view.offset() + - _view.hover_point().x() * _view.scale()) * _view.session().cur_samplerate()); + _grabbed_marker->set_index((_view.offset() + _view.hover_point().x()) * + _view.scale() * _view.session().cur_samplerate()); + _view.cursor_moving(); } update(); @@ -228,6 +229,7 @@ void Ruler::mousePressEvent(QMouseEvent *e) void Ruler::mouseReleaseEvent(QMouseEvent *event) { bool addCursor = false; + bool visible; if (event->button() & Qt::LeftButton) { bool hitCursor = false; if (!_cursor_sel_visible & !_view.get_cursorList().empty()) { @@ -235,10 +237,12 @@ void Ruler::mouseReleaseEvent(QMouseEvent *event) if (_grabbed_marker) { rel_grabbed_cursor(); hitCursor = true; + _view.cursor_moved(); } else { list::iterator i = _view.get_cursorList().begin(); while (i != _view.get_cursorList().end()) { - if ((*i)->get_close_rect(rect()).contains(event->pos())) { + const QRect cursor_rect((*i)->get_label_rect(rect(), visible)); + if ((*i)->get_close_rect(cursor_rect).contains(event->pos())) { _view.del_cursor(*i); if (_view.get_cursorList().empty()) { _cursor_sel_visible = false; @@ -247,7 +251,7 @@ void Ruler::mouseReleaseEvent(QMouseEvent *event) hitCursor = true; break; } - if ((*i)->get_label_rect(rect()).contains(event->pos())) { + if (cursor_rect.contains(event->pos())) { set_grabbed_cursor(*i); _cursor_sel_visible = false; _cursor_go_visible = false; @@ -265,7 +269,7 @@ void Ruler::mouseReleaseEvent(QMouseEvent *event) _cursor_sel_visible = true; } else { int overCursor; - uint64_t index = (_view.offset() + (_cursor_sel_x + 0.5) * _view.scale()) * _view.session().cur_samplerate(); + uint64_t index = (_view.offset() + _cursor_sel_x + 0.5) * _view.scale() * _view.session().cur_samplerate(); overCursor = in_cursor_sel_rect(event->pos()); if (overCursor == 0) { _view.add_cursor(CursorColor[_view.get_cursorList().size() % 8], index); @@ -354,7 +358,7 @@ void Ruler::draw_tick_mark(QPainter &p) typical_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, - AlignLeft | AlignTop, format_time(_view.offset(), + AlignLeft | AlignTop, format_time(_view.offset() * _view.scale(), prefix)).width() + MinValueSpacing; min_width += SpacingIncrement; @@ -369,9 +373,9 @@ void Ruler::draw_tick_mark(QPainter &p) const double minor_tick_period = tick_period / MinorTickSubdivision; const double first_major_division = - floor(_view.offset() / tick_period); + floor(_view.offset() * _view.scale() / tick_period); const double first_minor_division = - ceil(_view.offset() / minor_tick_period); + ceil(_view.offset() * _view.scale() / minor_tick_period); const double t0 = first_major_division * tick_period; int division = (int)round(first_minor_division - @@ -385,7 +389,7 @@ void Ruler::draw_tick_mark(QPainter &p) do { const double t = t0 + division * minor_tick_period; - x = (t - _view.offset()) / _view.scale(); + x = t / _view.scale() - _view.offset(); if (division % MinorTickSubdivision == 0) { @@ -432,7 +436,7 @@ void Ruler::draw_logic_tick_mark(QPainter &p) double typical_width; double tick_period = 0; double scale = _view.scale(); - double offset = _view.offset(); + int64_t offset = _view.offset(); const uint64_t cur_period_scale = ceil((scale * min_width) / abs_min_period); @@ -449,7 +453,7 @@ void Ruler::draw_logic_tick_mark(QPainter &p) _cur_prefix = prefix; assert(prefix < countof(SIPrefixes)); typical_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, - AlignLeft | AlignTop, format_time(offset, + AlignLeft | AlignTop, format_time(offset * scale, prefix)).width() + MinValueSpacing; do { @@ -470,9 +474,9 @@ void Ruler::draw_logic_tick_mark(QPainter &p) assert(minor_prefix < countof(SIPrefixes)); const double first_major_division = - floor(offset / tick_period); + floor(offset * scale / tick_period); const double first_minor_division = - floor(offset / minor_tick_period + 1); + floor(offset * scale / minor_tick_period + 1); const double t0 = first_major_division * tick_period; int division = (int)round(first_minor_division - @@ -482,7 +486,7 @@ void Ruler::draw_logic_tick_mark(QPainter &p) const int tick_y2 = height(); const int minor_tick_y1 = (major_tick_y1 + tick_y2) / 2; - double x; + int x; const double inc_text_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, AlignLeft | AlignTop, @@ -492,7 +496,7 @@ void Ruler::draw_logic_tick_mark(QPainter &p) const double t = t0 + division * minor_tick_period; const double major_t = t0 + floor(division / MinPeriodScale) * tick_period; - x = (t - offset) / scale; + x = t / scale - offset; if (division % MinPeriodScale == 0) { @@ -500,8 +504,8 @@ void Ruler::draw_logic_tick_mark(QPainter &p) p.drawText(x, 2 * ValueMargin, 0, text_height, AlignCenter | AlignTop | TextDontClip, format_time(t, prefix)); - p.drawLine(QPointF(x, major_tick_y1), - QPointF(x, tick_y2)); + p.drawLine(QPoint(x, major_tick_y1), + QPoint(x, tick_y2)); } else { @@ -516,8 +520,8 @@ void Ruler::draw_logic_tick_mark(QPainter &p) p.drawText(x, 2 * ValueMargin, 0, minor_tick_y1 + ValueMargin, AlignCenter | AlignTop | TextDontClip, format_time(t - major_t, minor_prefix)); - p.drawLine(QPointF(x, minor_tick_y1), - QPointF(x, tick_y2)); + p.drawLine(QPoint(x, minor_tick_y1), + QPoint(x, tick_y2)); } division++; @@ -533,13 +537,12 @@ void Ruler::draw_logic_tick_mark(QPainter &p) index++; i++; } - _view.on_cursor_moved(); } if (_view.trig_cursor_shown()) { - _view.get_trig_cursor()->paint_fix_label(p, rect(), prefix, 'T', Trace::dsLightRed); + _view.get_trig_cursor()->paint_fix_label(p, rect(), prefix, 'T', _view.get_trig_cursor()->colour()); } if (_view.search_cursor_shown()) { - _view.get_search_cursor()->paint_fix_label(p, rect(), prefix, 'S', Trace::dsLightBlue); + _view.get_search_cursor()->paint_fix_label(p, rect(), prefix, 'S', _view.get_search_cursor()->colour()); } } @@ -643,7 +646,7 @@ void Ruler::hover_point_changed() update(); } -const double Ruler::get_min_period() const +double Ruler::get_min_period() const { return _min_period / MinPeriodScale; } diff --git a/DSView/pv/view/ruler.h b/DSView/pv/view/ruler.h index 41f415a6..32be2440 100644 --- a/DSView/pv/view/ruler.h +++ b/DSView/pv/view/ruler.h @@ -75,7 +75,7 @@ public: void set_grabbed_cursor(TimeMarker* grabbed_marker); void rel_grabbed_cursor(); - const double get_min_period() const; + double get_min_period() const; private: void paintEvent(QPaintEvent *event); diff --git a/DSView/pv/view/signal.h b/DSView/pv/view/signal.h index 82e17e92..2d73549e 100644 --- a/DSView/pv/view/signal.h +++ b/DSView/pv/view/signal.h @@ -67,8 +67,6 @@ protected: public: virtual boost::shared_ptr data() const = 0; - virtual const std::vector< std::pair > cur_edges() const = 0; - /** * Returns true if the trace is visible and enabled. */ diff --git a/DSView/pv/view/timemarker.cpp b/DSView/pv/view/timemarker.cpp index d6eb74f9..2c8d8d73 100644 --- a/DSView/pv/view/timemarker.cpp +++ b/DSView/pv/view/timemarker.cpp @@ -24,6 +24,7 @@ #include "timemarker.h" #include "view.h" +#include "ruler.h" #include "../device/device.h" #include @@ -48,6 +49,16 @@ TimeMarker::TimeMarker(const TimeMarker &s) : { } +QColor TimeMarker::colour() const +{ + return _colour; +} + +void TimeMarker::set_colour(QColor color) +{ + _colour = color; +} + bool TimeMarker::grabbed() const { return _grabbed; @@ -68,14 +79,15 @@ void TimeMarker::set_index(uint64_t index) time_changed(); } -void TimeMarker::paint(QPainter &p, const QRect &rect, const bool highlight) +void TimeMarker::paint(QPainter &p, const QRect &rect, const bool highlight, int order) { const uint64_t sample_rate = _view.session().cur_samplerate(); const double scale = _view.scale(); const double samples_per_pixel = sample_rate * scale; - const double x = _index/samples_per_pixel - (_view.offset() / scale); - p.setPen((_grabbed | highlight) ? QPen(_colour.lighter(), 2, Qt::DashLine) : QPen(_colour, 1, Qt::DashLine)); - p.drawLine(QPointF(x, rect.top()), QPointF(x, rect.bottom())); + const int64_t x = _index/samples_per_pixel - _view.offset(); + QColor color = (order == -1) ? _colour : Ruler::CursorColor[order%8]; + p.setPen((_grabbed | highlight) ? QPen(color.lighter(), 2, Qt::DashLine) : QPen(color, 1, Qt::DashLine)); + p.drawLine(QPoint(x, rect.top()), QPoint(x, rect.bottom())); } } // namespace view diff --git a/DSView/pv/view/timemarker.h b/DSView/pv/view/timemarker.h index 71ee4cfe..5cd34450 100644 --- a/DSView/pv/view/timemarker.h +++ b/DSView/pv/view/timemarker.h @@ -68,6 +68,12 @@ public: */ void set_index(uint64_t index); + /** + * Gets/Sets colour of the marker + */ + QColor colour() const; + void set_colour(QColor color); + /* * */ @@ -79,14 +85,15 @@ public: * @param p The painter to draw with. * @param rect The rectangle of the viewport client area. */ - virtual void paint(QPainter &p, const QRect &rect, const bool highlight); + virtual void paint(QPainter &p, const QRect &rect, const bool highlight, int order); /** * Gets the marker label rectangle. * @param rect The rectangle of the ruler client area. + * @param visible is this marker in visible area * @return Returns the label rectangle. */ - virtual QRectF get_label_rect(const QRect &rect) const = 0; + virtual QRect get_label_rect(const QRect &rect, bool &visible) const = 0; /** * Paints the marker's label to the ruler. diff --git a/DSView/pv/view/view.cpp b/DSView/pv/view/view.cpp index 4a6f0d2e..f2778e84 100644 --- a/DSView/pv/view/view.cpp +++ b/DSView/pv/view/view.cpp @@ -73,7 +73,7 @@ View::View(SigSession &session, pv::toolbars::SamplingBar *sampling_bar, QWidget QScrollArea(parent), _session(session), _sampling_bar(sampling_bar), - _scale(1e-5), + _scale(10), _preScale(1e-6), _maxscale(1e9), _minscale(1e-15), @@ -81,6 +81,7 @@ View::View(SigSession &session, pv::toolbars::SamplingBar *sampling_bar, QWidget _preOffset(0), _updating_scroll(false), _show_cursors(false), + _search_hit(false), _hover_point(-1, -1), _dso_auto(true) { @@ -113,6 +114,7 @@ View::View(SigSession &session, pv::toolbars::SamplingBar *sampling_bar, QWidget _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); @@ -140,7 +142,7 @@ View::View(SigSession &session, pv::toolbars::SamplingBar *sampling_bar, QWidget layout->setContentsMargins(0,0,0,0); _viewcenter->setLayout(layout); layout->addWidget(_vsplitter, 0, 0); - _viewbottom = new widgets::ViewStatus(this); + _viewbottom = new widgets::ViewStatus(_session, this); _viewbottom->setFixedHeight(StatusHeight); layout->addWidget(_viewbottom, 1, 0); setViewport(_viewcenter); @@ -153,21 +155,21 @@ View::View(SigSession &session, pv::toolbars::SamplingBar *sampling_bar, QWidget this, SLOT(signals_changed()), Qt::DirectConnection); connect(&_session, SIGNAL(data_updated()), this, SLOT(data_updated())); - connect(&_session, SIGNAL(receive_header()), - this, SLOT(receive_header())); 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)), - this, SLOT(show_region(uint64_t, uint64_t))); + 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(mode_changed()), - parent, SLOT(mode_changed()), Qt::DirectConnection); + this, SLOT(mode_changed()), Qt::DirectConnection); connect(_header, SIGNAL(traces_moved()), this, SLOT(on_traces_moved())); @@ -188,7 +190,7 @@ View::View(SigSession &session, pv::toolbars::SamplingBar *sampling_bar, QWidget _trig_cursor = new Cursor(*this, Trace::dsLightRed, 0); _show_search_cursor = false; _search_pos = 0; - _search_cursor = new Cursor(*this, Trace::dsLightBlue, _search_pos); + _search_cursor = new Cursor(*this, Trace::dsGray, _search_pos); _cali = new pv::dialogs::Calibration(this); _cali->hide(); @@ -204,7 +206,7 @@ double View::scale() const return _scale; } -double View::offset() const +int64_t View::offset() const { return _offset; } @@ -219,6 +221,17 @@ double View::get_maxscale() const return _maxscale; } +void View::capture_init(bool instant) +{ + if (_session.get_device()->dev_inst()->mode == DSO) + show_trig_cursor(true); + else if (!_session.isRepeating()) + show_trig_cursor(false); + + update_sample(instant); + status_clear(); +} + void View::zoom(double steps) { zoom(steps, get_view_width() / 2); @@ -241,7 +254,7 @@ void View::update_sample(bool instant) BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { boost::shared_ptr dsoSig; if (dsoSig = dynamic_pointer_cast(s)) { - dsoSig->go_hDialCur(); + dsoSig->update_capture(); break; } } @@ -271,7 +284,6 @@ void View::zoom(double steps, int offset) _preScale = _scale; _preOffset = _offset; - const double cursor_offset = _offset + _scale * offset; if (_session.get_device()->dev_inst()->mode != DSO) { _scale *= std::pow(3.0/2.0, -steps); _scale = max(min(_scale, _maxscale), _minscale); @@ -292,7 +304,7 @@ void View::zoom(double steps, int offset) } } - _offset = cursor_offset - _scale * offset; + _offset = floor((_offset + offset) * (_preScale / _scale) - offset); _offset = max(min(_offset, get_max_offset()), get_min_offset()); if (_scale != _preScale || _offset != _preOffset) { @@ -305,14 +317,14 @@ void View::zoom(double steps, int offset) } -void View::set_scale_offset(double scale, double offset) +void View::set_scale_offset(double scale, int64_t offset) { //if (_session.get_capture_state() == SigSession::Stopped) { _preScale = _scale; _preOffset = _offset; _scale = max(min(scale, _maxscale), _minscale); - _offset = max(min(offset, get_max_offset()), get_min_offset()); + _offset = floor(max(min(offset, get_max_offset()), get_min_offset())); if (_scale != _preScale || _offset != _preOffset) { update_scroll(); @@ -419,15 +431,18 @@ void View::status_clear() _viewbottom->clear(); } -void View::receive_header() +void View::repeat_unshow() { - status_clear(); + _viewbottom->repeat_unshow(); } void View::frame_began() { if (_session.get_device()->dev_inst()->mode == LOGIC) _viewbottom->set_trig_time(_session.get_trigger_time()); + _search_hit = false; + _search_pos = 0; + set_search_pos(_search_pos, _search_hit); } void View::receive_end() @@ -460,7 +475,7 @@ void View::receive_trigger(quint64 trig_pos) _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); + set_scale_offset(_scale, (time / _scale) - (get_view_width() / 2)); } _ruler->update(); @@ -473,16 +488,21 @@ void View::set_trig_pos(int percent) receive_trigger(index); } -void View::set_search_pos(uint64_t search_pos) +void View::set_search_pos(uint64_t search_pos, bool hit) { //assert(search_pos >= 0); const double time = search_pos * 1.0 / _session.cur_samplerate(); _search_pos = search_pos; + _search_hit = hit; _search_cursor->set_index(search_pos); - set_scale_offset(_scale, time - _scale * get_view_width() / 2); - _ruler->update(); - viewport_update(); + _search_cursor->set_colour(hit ? Trace::dsLightBlue : Trace::dsGray); + + if (hit) { + set_scale_offset(_scale, (time / _scale) - (get_view_width() / 2)); + _ruler->update(); + viewport_update(); + } } uint64_t View::get_search_pos() @@ -490,6 +510,11 @@ uint64_t View::get_search_pos() return _search_pos; } +bool View::get_search_hit() +{ + return _search_hit; +} + const QPoint& View::hover_point() const { return _hover_point; @@ -522,14 +547,14 @@ int View::get_signalHeight() return _signalHeight; } -void View::get_scroll_layout(double &length, double &offset) const +void View::get_scroll_layout(int64_t &length, int64_t &offset) const { const set< boost::shared_ptr > data_set = _session.get_data(); if (data_set.empty()) return; - length = _session.get_device()->get_sample_time() / _scale; - offset = _offset / _scale; + length = ceil(_session.cur_sampletime() / _scale); + offset = _offset; } void View::update_scroll() @@ -539,9 +564,10 @@ void View::update_scroll() const QSize areaSize = _viewcenter->size(); // Set the horizontal scroll bar - double length = 0, offset = 0; + int64_t length = 0; + int64_t offset = 0; get_scroll_layout(length, offset); - length = max(length - areaSize.width(), 0.0); + length = max(length - areaSize.width(), (int64_t)0); horizontalScrollBar()->setPageStep(areaSize.width() / 2); @@ -553,7 +579,7 @@ void View::update_scroll() } else { horizontalScrollBar()->setRange(0, MaxScrollValue); horizontalScrollBar()->setSliderPosition( - _offset * MaxScrollValue / (_scale * length)); + _offset * MaxScrollValue / length); } _updating_scroll = false; @@ -569,7 +595,6 @@ void View::update_scale_offset() assert(sample_rate > 0); if (_session.get_device()->dev_inst()->mode != DSO) { - //_scale = (1.0 / sample_rate) / WellPixelsPerSample; _maxscale = _session.cur_sampletime() / (get_view_width() * MaxViewRate); _minscale = (1.0 / sample_rate) / MaxPixelsPerSample; } else { @@ -578,7 +603,6 @@ void View::update_scale_offset() _minscale = 1e-15; } - _scale = max(min(_scale, _maxscale), _minscale); _offset = max(min(_offset, get_max_offset()), get_min_offset()); @@ -591,13 +615,24 @@ void View::update_scale_offset() viewport_update(); } +void View::mode_changed() +{ + const uint64_t sample_rate = _session.cur_samplerate(); + assert(sample_rate > 0); + + if (_session.get_device()->name().contains("virtual")) + _scale = WellSamplesPerPixel * 1.0 / sample_rate; + _scale = max(min(_scale, _maxscale), _minscale); + + update_device_list(); +} + void View::signals_changed() { int total_rows = 0; uint8_t max_height = MaxHeightUnit; vector< boost::shared_ptr > time_traces; vector< boost::shared_ptr > fft_traces; - int bits = 8; BOOST_FOREACH(const boost::shared_ptr t, get_traces(ALL_VIEW)) { if (_trace_view_map[t->get_type()] == TIME_VIEW) @@ -624,7 +659,7 @@ void View::signals_changed() _fft_viewport->setVisible(false); _vsplitter->refresh(); - // Find the decoder in the stack + // Find the _fft_viewport in the stack std::list< Viewport *>::iterator iter = _viewport_list.begin(); for(unsigned int i = 0; i < _viewport_list.size(); i++, iter++) if ((*iter) == _fft_viewport) @@ -671,12 +706,7 @@ void View::signals_changed() boost::shared_ptr dsoSig; if (dsoSig = dynamic_pointer_cast(t)) { - GVariant *gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_DSO_BITS); - if (gvar != NULL) { - bits = g_variant_get_byte(gvar); - g_variant_unref(gvar); - } - dsoSig->set_scale(dsoSig->get_view_rect().height() * 1.0f / (1 << bits)); + dsoSig->set_scale(dsoSig->get_view_rect().height()); } } _time_viewport->clear_measure(); @@ -695,10 +725,11 @@ bool View::eventFilter(QObject *object, QEvent *event) const QMouseEvent *const mouse_event = (QMouseEvent*)event; if (object == _ruler || object == _time_viewport || object == _fft_viewport) { //_hover_point = QPoint(mouse_event->x(), 0); - double cur_periods = (mouse_event->pos().x() * _scale + _offset) / _ruler->get_min_period(); - int integer_x = (round(cur_periods) * _ruler->get_min_period() - _offset ) / _scale; + 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 (cur_deviate_x < 10) + if (_session.get_device()->dev_inst()->mode == LOGIC && + cur_deviate_x < 10) _hover_point = QPoint(integer_x, mouse_event->pos().y()); else _hover_point = mouse_event->pos(); @@ -789,11 +820,12 @@ void View::h_scroll_value_changed(int value) const int range = horizontalScrollBar()->maximum(); if (range < MaxScrollValue) - _offset = _scale * value; + _offset = value; else { - double length = 0, offset; + int64_t length = 0; + int64_t offset = 0; get_scroll_layout(length, offset); - _offset = _scale * length * value / MaxScrollValue; + _offset = floor(length * value / MaxScrollValue); } _offset = max(min(_offset, get_max_offset()), get_min_offset()); @@ -859,7 +891,6 @@ void View::on_traces_moved() update_scroll(); set_update(_time_viewport, true); viewport_update(); - //traces_moved(); } /* @@ -908,7 +939,7 @@ void View::set_cursor_middle(int index) list::iterator i = _cursorList.begin(); while (index-- != 0) i++; - set_scale_offset(_scale, (*i)->index() * 1.0 / _session.cur_samplerate() - _scale * get_view_width() / 2); + set_scale_offset(_scale, (*i)->index() / (_session.cur_samplerate() * _scale) - (get_view_width() / 2)); } void View::on_measure_updated() @@ -945,19 +976,17 @@ uint64_t View::get_cursor_samples(int index) { assert(index < (int)_cursorList.size()); + uint64_t ret = 0; int curIndex = 0; for (list::iterator i = _cursorList.begin(); i != _cursorList.end(); i++) { if (index == curIndex) { - return (*i)->index(); + ret = (*i)->index(); } curIndex++; } -} -void View::on_cursor_moved() -{ - cursor_moved(); + return ret; } void View::set_measure_en(int enable) @@ -982,9 +1011,9 @@ QRect View::get_view_rect() BOOST_FOREACH(const boost::shared_ptr s, sigs) { return s->get_view_rect(); } - } else { - return _viewcenter->rect(); } + + return _viewcenter->rect(); } int View::get_view_width() @@ -1017,15 +1046,18 @@ int View::get_view_height() return view_height; } -double View::get_min_offset() +int64_t View::get_min_offset() { - return -(_scale * (get_view_width() * (1 - MaxViewRate))); + if (MaxViewRate > 1) + return floor(get_view_width() * (1 - MaxViewRate)); + else + return 0; } -double View::get_max_offset() +int64_t View::get_max_offset() { - return _session.get_device()->get_sample_time() - - _scale * (get_view_width() * MaxViewRate); + return ceil((_session.cur_sampletime() / _scale) - + (get_view_width() * MaxViewRate)); } // -- calibration dialog @@ -1047,13 +1079,22 @@ void View::update_calibration() } } -void View::show_region(uint64_t start, uint64_t end) +void View::show_region(uint64_t start, uint64_t end, bool keep) { assert(start <= end); - const double ideal_scale = (end-start) * 2.0 / _session.cur_samplerate() / get_view_width(); - const double new_scale = max(min(ideal_scale, _maxscale), _minscale); - const double new_off = (start + end) * 0.5 / _session.cur_samplerate() - new_scale * get_view_width() / 2; - set_scale_offset(new_scale, new_off); + if (keep) { + set_all_update(true); + update(); + } else if (_session.get_map_zoom() == 0) { + const double ideal_scale = (end-start) * 2.0 / _session.cur_samplerate() / get_view_width(); + const double new_scale = max(min(ideal_scale, _maxscale), _minscale); + const double new_off = (start + end) * 0.5 / (_session.cur_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_samplerate() * new_scale) - (get_view_width() / 2); + set_scale_offset(new_scale, new_off); + } } void View::viewport_update() @@ -1082,8 +1123,48 @@ void View::reload() _viewbottom->setFixedHeight(StatusHeight); else _viewbottom->setFixedHeight(10); +} + +void View::repeat_show() +{ + _viewbottom->update(); +} + +bool View::get_capture_status(bool &triggered, int &progress) +{ + uint64_t sample_limits = _session.cur_samplelimits(); + sr_status status; + if (sr_status_get(_session.get_device()->dev_inst(), &status, SR_STATUS_TRIG_BEGIN, SR_STATUS_TRIG_END) == SR_OK){ + triggered = status.trig_hit & 0x01; + const bool captured_cnt_dec = status.trig_hit & 0x02; + uint64_t captured_cnt = status.trig_hit >> 2; + captured_cnt = ((uint64_t)status.captured_cnt0 + + ((uint64_t)status.captured_cnt1 << 8) + + ((uint64_t)status.captured_cnt2 << 16) + + ((uint64_t)status.captured_cnt3 << 24) + + (captured_cnt << 32)); + if (_session.get_device()->dev_inst()->mode == DSO) + captured_cnt = captured_cnt * _session.get_signals().size() / _session.get_ch_num(SR_CHANNEL_DSO); + if (captured_cnt_dec) + progress = (sample_limits - captured_cnt) * 100.0 / sample_limits; + else + progress = captured_cnt * 100.0 / sample_limits; + return true; + } + + return false; +} + +void View::set_capture_status() +{ + bool triggered; + int progress; + if (_session.get_capture_status(triggered, progress)) { + _viewbottom->set_capture_status(triggered, progress); + _viewbottom->update(); + } } } // namespace view diff --git a/DSView/pv/view/view.h b/DSView/pv/view/view.h index 4132257c..88d62b11 100644 --- a/DSView/pv/view/view.h +++ b/DSView/pv/view/view.h @@ -80,7 +80,7 @@ public: static const QSizeF LabelPadding; - static const int WellPixelsPerSample = 10; + static const int WellSamplesPerPixel = 2048; static constexpr double MaxViewRate = 1.0; static const int MaxPixelsPerSample = 100; @@ -97,14 +97,15 @@ public: double scale() const; /** - * Returns the time offset of the left edge of the view in - * seconds. + * Returns the pixels offset of the left edge of the view */ - double offset() const; + int64_t offset() const; int v_offset() const; - double get_min_offset(); - double get_max_offset(); + int64_t get_min_offset(); + int64_t get_max_offset(); + + void capture_init(bool instant); void zoom(double steps); void zoom(double steps, int offset); @@ -114,7 +115,7 @@ public: * @param scale The new view scale in seconds per pixel. * @param offset The view time offset in seconds. */ - void set_scale_offset(double scale, double offset); + void set_scale_offset(double scale, int64_t offset); void set_preScale_preOffset(); std::vector< boost::shared_ptr > get_traces(int type); @@ -157,8 +158,9 @@ public: Cursor* get_trig_cursor(); Cursor* get_search_cursor(); + bool get_search_hit(); - void set_search_pos(uint64_t search_pos); + void set_search_pos(uint64_t search_pos, bool hit); uint64_t get_search_pos(); @@ -175,8 +177,6 @@ public: QString get_cm_time(int index); QString get_cm_delta(int index1, int index2); - void on_cursor_moved(); - void on_state_changed(bool stop); QRect get_view_rect(); @@ -193,19 +193,25 @@ public: void viewport_update(); + bool get_capture_status(bool &triggered, int &progress); + void set_capture_status(); + signals: void hover_point_changed(); - void traces_moved(); - void cursor_update(); + void cursor_moving(); void cursor_moved(); void measure_updated(); + void prgRate(int progress); + + void update_device_list(); + private: - void get_scroll_layout(double &length, double &offset) const; + void get_scroll_layout(int64_t &length, int64_t &offset) const; void update_scroll(); @@ -228,11 +234,14 @@ public slots: void signals_changed(); void data_updated(); void update_scale_offset(); - void show_region(uint64_t start, uint64_t end); + void show_region(uint64_t start, uint64_t end, bool keep); // -- calibration void update_calibration(); void hide_calibration(); void status_clear(); + void repeat_unshow(); + // -- repeat + void repeat_show(); private slots: @@ -245,8 +254,6 @@ private slots: void header_updated(); - void receive_header(); - void receive_trigger(quint64 trig_pos); void set_trig_pos(int percent); @@ -260,6 +267,8 @@ private slots: void splitterMoved(int pos, int index); + void mode_changed(); + private: SigSession &_session; @@ -279,32 +288,29 @@ private: /// The view time scale in seconds per pixel. double _scale; - double _preScale; - double _maxscale; - double _minscale; + double _preScale; + double _maxscale; + double _minscale; - /// The view time offset in seconds. - double _offset; - double _preOffset; - - int _spanY; - int _signalHeight; - - bool _updating_scroll; + /// The pixels offset of the left edge of the view + int64_t _offset; + int64_t _preOffset; + int _spanY; + int _signalHeight; + bool _updating_scroll; 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; - std::list _cursorList; - - Cursor *_trig_cursor; - bool _show_trig_cursor; - Cursor *_search_cursor; - bool _show_search_cursor; - uint64_t _search_pos; - - QPoint _hover_point; - dialogs::Calibration *_cali; - bool _dso_auto; + QPoint _hover_point; + dialogs::Calibration *_cali; + bool _dso_auto; }; } // namespace view diff --git a/DSView/pv/view/viewport.cpp b/DSView/pv/view/viewport.cpp index 92fdaae1..a7dcee52 100644 --- a/DSView/pv/view/viewport.cpp +++ b/DSView/pv/view/viewport.cpp @@ -57,7 +57,7 @@ Viewport::Viewport(View &parent, View_type type) : _view(parent), _type(type), _need_update(false), - _total_receive_len(0), + _sample_received(0), _action_type(NO_ACTION), _measure_type(NO_MEASURE), _cur_sample(0), @@ -81,15 +81,13 @@ Viewport::Viewport(View &parent, View_type type) : _mm_freq = "#####"; _mm_duty = "#####"; _measure_en = true; - triggered = false; + transfer_started = false; timer_cnt = 0; // drag inertial _drag_strength = 0; _drag_timer.setSingleShot(true); - connect(&_view, SIGNAL(traces_moved()), - this, SLOT(on_traces_moved())); connect(&trigger_timer, SIGNAL(timeout()), this, SLOT(on_trigger_timer())); connect(&_drag_timer, SIGNAL(timeout()), @@ -135,7 +133,7 @@ void Viewport::paintEvent(QPaintEvent *event) { assert(t); t->paint_back(p, 0, _view.get_view_width()); - if (t->enabled() && _view.session().get_device()->dev_inst()->mode == DSO) + if (_view.session().get_device()->dev_inst()->mode == DSO) break; } @@ -151,7 +149,12 @@ void Viewport::paintEvent(QPaintEvent *event) break; case SigSession::Running: - if (_type == TIME_VIEW) { + if (_view.session().isRepeating() && + !transfer_started) { + _view.set_capture_status(); + paintSignals(p); + } else if (_type == TIME_VIEW) { + _view.repeat_unshow(); p.setRenderHint(QPainter::Antialiasing); paintProgress(p); p.setRenderHint(QPainter::Antialiasing, false); @@ -205,27 +208,33 @@ void Viewport::paintSignals(QPainter &p) p.drawPixmap(0, 0, pixmap); // plot cursors + const double samples_per_pixel = _view.session().cur_samplerate() * _view.scale(); if (_view.cursors_shown() && _type == TIME_VIEW) { list::iterator i = _view.get_cursorList().begin(); - double cursorX; - const double samples_per_pixel = _view.session().cur_samplerate() * _view.scale(); + int index = 0; while (i != _view.get_cursorList().end()) { - cursorX = (*i)->index()/samples_per_pixel - (_view.offset() / _view.scale()); + const int64_t cursorX = (*i)->index()/samples_per_pixel - _view.offset(); if (rect().contains(_view.hover_point().x(), _view.hover_point().y()) && qAbs(cursorX - _view.hover_point().x()) <= HitCursorMargin) - (*i)->paint(p, rect(), 1); + (*i)->paint(p, rect(), 1, index); else - (*i)->paint(p, rect(), 0); + (*i)->paint(p, rect(), 0, index); i++; + index++; } } if (_type == TIME_VIEW) { if (_view.trig_cursor_shown()) { - _view.get_trig_cursor()->paint(p, rect(), 0); + _view.get_trig_cursor()->paint(p, rect(), 0, -1); } if (_view.search_cursor_shown()) { - _view.get_search_cursor()->paint(p, rect(), 0); + const int64_t searchX = _view.get_search_cursor()->index()/samples_per_pixel - _view.offset(); + if (rect().contains(_view.hover_point().x(), _view.hover_point().y()) && + qAbs(searchX - _view.hover_point().x()) <= HitCursorMargin) + _view.get_search_cursor()->paint(p, rect(), 1, -1); + else + _view.get_search_cursor()->paint(p, rect(), 0, -1); } // plot zoom rect @@ -276,9 +285,9 @@ void Viewport::paintProgress(QPainter &p) { using pv::view::Signal; - const uint64_t _total_sample_len = _view.session().cur_samplelimits(); + const uint64_t sample_limits = _view.session().cur_samplelimits(); - double progress = -(_total_receive_len * 1.0 / _total_sample_len * 360 * 16); + double progress = -(_sample_received * 1.0 / sample_limits * 360 * 16); int captured_progress = 0; p.setPen(Qt::gray); @@ -344,7 +353,7 @@ void Viewport::paintProgress(QPainter &p) p.drawEllipse(logoPoints[19].x() - 0.5 * logoRadius, logoPoints[19].y() - logoRadius, logoRadius, logoRadius); - if (!triggered) { + if (!transfer_started) { const int width = _view.get_view_width(); const QPoint cenLeftPos = QPoint(width / 2 - 0.05 * width, height() / 2); const QPoint cenRightPos = QPoint(width / 2 + 0.05 * width, height() / 2); @@ -358,38 +367,38 @@ void Viewport::paintProgress(QPainter &p) p.setBrush((timer_cnt % 3) == 2 ? Trace::dsLightBlue : Trace::dsGray); p.drawEllipse(cenRightPos, trigger_radius, trigger_radius); - sr_status status; - if (sr_status_get(_view.session().get_device()->dev_inst(), &status, SR_STATUS_TRIG_BEGIN, SR_STATUS_TRIG_END) == SR_OK){ - const bool triggred = status.trig_hit & 0x01; - uint32_t captured_cnt = (status.captured_cnt0 + - (status.captured_cnt1 << 8) + - (status.captured_cnt2 << 16) + - (status.captured_cnt3 << 24)); - if (_view.session().get_device()->dev_inst()->mode == DSO) - captured_cnt = captured_cnt * _view.session().get_signals().size() / _view.session().get_ch_num(SR_CHANNEL_DSO); - if (triggred) - captured_progress = (_total_sample_len - captured_cnt) * 100.0 / _total_sample_len; - else - captured_progress = captured_cnt * 100.0 / _total_sample_len; - - + bool triggered; + if (_view.session().get_capture_status(triggered, captured_progress)){ p.setPen(Trace::dsLightBlue); QFont font=p.font(); font.setPointSize(10); font.setBold(true); p.setFont(font); QRect status_rect = QRect(cenPos.x() - radius, cenPos.y() + radius * 0.4, radius * 2, radius * 0.5); - if (triggred) + if (triggered) p.drawText(status_rect, Qt::AlignCenter | Qt::AlignVCenter, - "Triggered! " + QString::number(captured_progress)+"% Captured"); + tr("Triggered! ") + QString::number(captured_progress) + tr("% Captured")); else p.drawText(status_rect, Qt::AlignCenter | Qt::AlignVCenter, - "Waiting for Trigger! " + QString::number(captured_progress)+"% Captured"); + tr("Waiting for Trigger! ") + QString::number(captured_progress) + tr("% Captured")); + prgRate(captured_progress); } } else { + if (_view.session().get_error() == SigSession::No_err) { + GVariant *gvar = _view.session().get_device()->get_config(NULL, NULL, SR_CONF_HW_STATUS); + if (gvar != NULL) { + uint8_t hw_info = g_variant_get_byte(gvar); + g_variant_unref(gvar); + if (hw_info & 0x10) { + _view.session().set_error(SigSession::Data_overflow); + _view.session().session_error(); + } + } + } + const int progress100 = ceil(progress / -3.6 / 16); p.setPen(Trace::dsGreen); QFont font=p.font(); @@ -397,6 +406,7 @@ void Viewport::paintProgress(QPainter &p) font.setBold(true); p.setFont(font); p.drawText(rect(), Qt::AlignCenter | Qt::AlignVCenter, QString::number(progress100)+"%"); + prgRate(progress100); } p.setPen(QPen(Trace::dsLightBlue, 4, Qt::SolidLine)); @@ -444,7 +454,7 @@ void Viewport::mousePressEvent(QMouseEvent *event) _action_type = LOGIC_ZOOM; } else if (_view.session().get_device()->dev_inst()->mode == DSO) { if (_hover_hit) { - uint64_t index = (_view.offset() + (event->pos().x() + 0.5) * _view.scale()) * _view.session().cur_samplerate(); + const int64_t index = (_view.offset() + event->pos().x()) * _view.scale() * _view.session().cur_samplerate(); _view.add_cursor(view::Ruler::CursorColor[_view.get_cursorList().size() % 8], index); _view.show_cursors(true); } @@ -460,9 +470,7 @@ void Viewport::mouseMoveEvent(QMouseEvent *event) if (event->buttons() & Qt::LeftButton) { if (_type == TIME_VIEW) { _view.set_scale_offset(_view.scale(), - _mouse_down_offset + - (_mouse_down_point - event->pos()).x() * - _view.scale()); + _mouse_down_offset + (_mouse_down_point - event->pos()).x()); _drag_strength = (_mouse_down_point - event->pos()).x(); } else if (_type == FFT_VIEW) { BOOST_FOREACH(const boost::shared_ptr t, _view.session().get_math_signals()) { @@ -489,7 +497,7 @@ void Viewport::mouseMoveEvent(QMouseEvent *event) if (_action_type == CURS_MOVE) { uint64_t sample_rate = _view.session().cur_samplerate(); TimeMarker* grabbed_marker = _view.get_ruler()->get_grabbed_cursor(); - if (_view.cursors_shown() && grabbed_marker) { + if (grabbed_marker) { int curX = _view.hover_point().x(); uint64_t index0 = 0, index1 = 0, index2 = 0; bool logic = false; @@ -512,13 +520,12 @@ void Viewport::mouseMoveEvent(QMouseEvent *event) } } - const double cur_time = _view.offset() + curX * _view.scale(); + const double cur_time = (_view.offset() + curX) * _view.scale(); const double pos = cur_time * sample_rate; const double pos_delta = pos - (uint64_t)pos; const double samples_per_pixel = sample_rate * _view.scale(); - const double index_offset = _view.offset() / _view.scale(); - const double curP = index0 / samples_per_pixel - index_offset; - const double curN = index1 / samples_per_pixel - index_offset; + const double curP = index0 / samples_per_pixel - _view.offset(); + const double curN = index1 / samples_per_pixel - _view.offset(); if (logic && (curX - curP < SnapMinSpace || curN - curX < SnapMinSpace)) { if (curX - curP < curN - curX) grabbed_marker->set_index(index0); @@ -529,6 +536,12 @@ void Viewport::mouseMoveEvent(QMouseEvent *event) } else { grabbed_marker->set_index((uint64_t)ceil(pos)); } + + if (grabbed_marker == _view.get_search_cursor()) { + _view.set_search_pos(grabbed_marker->index(), false); + } + + _view.cursor_moving(); } } @@ -563,15 +576,23 @@ void Viewport::mouseReleaseEvent(QMouseEvent *event) assert(event); if (_type == TIME_VIEW) { + const double samples_per_pixel = _view.session().cur_samplerate() * _view.scale(); if ((_action_type == NO_ACTION) && (event->button() == Qt::LeftButton)) { // priority 0 + if (_action_type == NO_ACTION && _view.search_cursor_shown()) { + const int64_t searchX = _view.get_search_cursor()->index()/samples_per_pixel - _view.offset(); + if (_view.get_search_cursor()->grabbed()) { + _view.get_ruler()->rel_grabbed_cursor(); + } else if (qAbs(searchX - event->pos().x()) <= HitCursorMargin) { + _view.get_ruler()->set_grabbed_cursor(_view.get_search_cursor()); + _action_type = CURS_MOVE; + } + } if (_action_type == NO_ACTION && _view.cursors_shown()) { list::iterator i = _view.get_cursorList().begin(); - double cursorX; - const double samples_per_pixel = _view.session().cur_samplerate() * _view.scale(); while (i != _view.get_cursorList().end()) { - cursorX = (*i)->index()/samples_per_pixel - (_view.offset() / _view.scale()); + const int64_t cursorX = (*i)->index()/samples_per_pixel - _view.offset(); if ((*i)->grabbed()) { _view.get_ruler()->rel_grabbed_cursor(); } else if (qAbs(cursorX - event->pos().x()) <= HitCursorMargin) { @@ -609,7 +630,7 @@ void Viewport::mouseReleaseEvent(QMouseEvent *event) assert(s); if (abs(event->pos().y() - s->get_y()) < _view.get_signalHeight()) { _action_type = LOGIC_EDGE; - _edge_start = (_view.offset() + (event->pos().x() + 0.5) * _view.scale()) * _view.session().cur_samplerate(); + _edge_start = (_view.offset() + event->pos().x()) * _view.scale() * _view.session().cur_samplerate(); break; } } @@ -664,11 +685,7 @@ void Viewport::mouseReleaseEvent(QMouseEvent *event) } } else if (_action_type == DSO_XM_STEP1) { if (event->button() == Qt::LeftButton) { - const uint64_t sample_rate = _view.session().cur_samplerate(); - const double scale = _view.scale(); - const double samples_per_pixel = sample_rate * scale; - - _dso_xm_index[1] = event->pos().x() * samples_per_pixel + _view.offset() * sample_rate; + _dso_xm_index[1] = (event->pos().x() + _view.offset()) * samples_per_pixel; const uint64_t max_index = max(_dso_xm_index[0], _dso_xm_index[1]); _dso_xm_index[0] = min(_dso_xm_index[0], _dso_xm_index[1]); _dso_xm_index[1] = max_index; @@ -685,10 +702,7 @@ void Viewport::mouseReleaseEvent(QMouseEvent *event) } } else if (_action_type == DSO_XM_STEP2) { if (event->button() == Qt::LeftButton) { - const uint64_t sample_rate = _view.session().cur_samplerate(); - const double scale = _view.scale(); - const double samples_per_pixel = sample_rate * scale; - _dso_xm_index[2] = event->pos().x() * samples_per_pixel + _view.offset() * sample_rate; + _dso_xm_index[2] = (event->pos().x() + _view.offset()) * samples_per_pixel; uint64_t max_index = max(_dso_xm_index[1], _dso_xm_index[2]); _dso_xm_index[1] = min(_dso_xm_index[1], _dso_xm_index[2]); _dso_xm_index[2] = max_index; @@ -709,15 +723,18 @@ void Viewport::mouseReleaseEvent(QMouseEvent *event) } } else if (_action_type == CURS_MOVE) { _action_type = NO_ACTION; - if (_view.cursors_shown()) { - list::iterator i = _view.get_cursorList().begin(); - while (i != _view.get_cursorList().end()) { - if ((*i)->grabbed()) { - _view.get_ruler()->rel_grabbed_cursor(); - } - i++; - } - } + _view.get_ruler()->rel_grabbed_cursor(); + +// if (_view.cursors_shown()) { +// list::iterator i = _view.get_cursorList().begin(); +// while (i != _view.get_cursorList().end()) { +// if ((*i)->grabbed()) { +// _view.get_ruler()->rel_grabbed_cursor(); +// } +// i++; +// } +// } + _view.cursor_moved(); } else if (_action_type == LOGIC_EDGE) { _action_type = NO_ACTION; _edge_rising = 0; @@ -741,9 +758,10 @@ void Viewport::mouseReleaseEvent(QMouseEvent *event) } } else if (_action_type == LOGIC_ZOOM) { if (event->pos().x() != _mouse_down_point.x()) { - const double newOffset = _view.offset() + (min(event->pos().x(), _mouse_down_point.x()) + 0.5) * _view.scale(); + int64_t newOffset = _view.offset() + (min(event->pos().x(), _mouse_down_point.x())); const double newScale = max(min(_view.scale() * abs(event->pos().x() - _mouse_down_point.x()) / _view.get_view_width(), _view.get_maxscale()), _view.get_minscale()); + newOffset = floor(newOffset * (_view.scale() / newScale)); if (newScale != _view.scale()) _view.set_scale_offset(newScale, newOffset); } @@ -764,9 +782,37 @@ void Viewport::mouseDoubleClickEvent(QMouseEvent *event) if (_view.scale() == _view.get_maxscale()) _view.set_preScale_preOffset(); else - _view.set_scale_offset(_view.get_maxscale(), 0); + _view.set_scale_offset(_view.get_maxscale(), _view.get_min_offset()); } else if (event->button() == Qt::LeftButton) { - uint64_t index = (_view.offset() + (event->pos().x() + 0.5) * _view.scale()) * _view.session().cur_samplerate(); + bool logic = false; + 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()); + BOOST_FOREACH(const boost::shared_ptr s, sigs) { + assert(s); + boost::shared_ptr logicSig; + if ((logicSig = dynamic_pointer_cast(s))) { + if (logicSig->measure(event->pos(), index0, index1, index2)) { + logic = true; + break; + } + } + } + } + const uint64_t sample_rate = _view.session().cur_samplerate(); + const double curX = event->pos().x(); + const double samples_per_pixel = sample_rate * _view.scale(); + const double curP = index0 / samples_per_pixel - _view.offset(); + const double curN = index1 / samples_per_pixel - _view.offset(); + if (logic && (curX - curP < SnapMinSpace || curN - curX < SnapMinSpace)) { + if (curX - curP < curN - curX) + index = index0; + else + index = index1; + } else { + index = (_view.offset() + curX) * _view.scale() * sample_rate;; + } _view.add_cursor(view::Ruler::CursorColor[_view.get_cursorList().size() % 8], index); _view.show_cursors(true); } @@ -789,8 +835,7 @@ void Viewport::mouseDoubleClickEvent(QMouseEvent *event) uint64_t sample_rate = _view.session().cur_samplerate(); double scale = _view.scale(); const double samples_per_pixel = sample_rate * scale; - _dso_xm_index[0] = event->pos().x() * samples_per_pixel + - _view.offset() * sample_rate; + _dso_xm_index[0] = (event->pos().x() + _view.offset()) * samples_per_pixel; _dso_xm_y = event->pos().y(); _action_type = DSO_XM_STEP0; } @@ -815,13 +860,12 @@ void Viewport::wheelEvent(QWheelEvent *event) } else if (_type == TIME_VIEW){ if (event->orientation() == Qt::Vertical) { // Vertical scrolling is interpreted as zooming in/out - const double offset = event->x(); + const int offset = event->x(); _view.zoom(event->delta() / 80, offset); } else if (event->orientation() == Qt::Horizontal) { // Horizontal scrolling is interpreted as moving left/right _view.set_scale_offset(_view.scale(), - event->delta() * _view.scale() - + _view.offset()); + event->delta() + _view.offset()); } } @@ -857,22 +901,17 @@ void Viewport::leaveEvent(QEvent *) update(); } -void Viewport::on_traces_moved() -{ - update(); -} - void Viewport::set_receive_len(quint64 length) { if (length == 0) { - _total_receive_len = 0; + _sample_received = 0; start_trigger_timer(333); } else { stop_trigger_timer(); - if (_total_receive_len + length > _view.session().cur_samplelimits()) - _total_receive_len = _view.session().cur_samplelimits(); + if (_sample_received + length > _view.session().cur_samplelimits()) + _sample_received = _view.session().cur_samplelimits(); else - _total_receive_len += length; + _sample_received += length; } update(); } @@ -904,11 +943,10 @@ void Viewport::measure() _mm_period = _thd_sample != 0 ? _view.get_ruler()->format_real_time(_thd_sample - _cur_sample, sample_rate) : "#####"; _mm_freq = _thd_sample != 0 ? _view.get_ruler()->format_real_freq(_thd_sample - _cur_sample, sample_rate) : "#####"; - const double pixels_offset = _view.offset() / _view.scale(); const double samples_per_pixel = sample_rate * _view.scale(); - _cur_preX = _cur_sample / samples_per_pixel - pixels_offset; - _cur_aftX = _nxt_sample / samples_per_pixel - pixels_offset; - _cur_thdX = _thd_sample / samples_per_pixel - pixels_offset; + _cur_preX = _cur_sample / samples_per_pixel - _view.offset(); + _cur_aftX = _nxt_sample / samples_per_pixel - _view.offset(); + _cur_thdX = _thd_sample / samples_per_pixel - _view.offset(); _cur_midY = logicSig->get_y(); _mm_duty = _thd_sample != 0 ? QString::number((_nxt_sample - _cur_sample) * 100.0 / (_thd_sample - _cur_sample), 'f', 2)+"%" : @@ -923,9 +961,8 @@ void Viewport::measure() } } else if (_action_type == LOGIC_EDGE) { if (logicSig->edges(_view.hover_point(), _edge_start, _edge_rising, _edge_falling)) { - const double pixels_offset = _view.offset() / _view.scale(); const double samples_per_pixel = sample_rate * _view.scale(); - _cur_preX = _edge_start / samples_per_pixel - pixels_offset; + _cur_preX = _edge_start / samples_per_pixel - _view.offset(); _cur_aftX = _view.hover_point().x(); _cur_midY = logicSig->get_y() - logicSig->get_totalHeight()/2 - 5; @@ -1086,8 +1123,8 @@ void Viewport::paintMeasure(QPainter &p) const int text_height = p.boundingRect(0, 0, INT_MAX, INT_MAX, Qt::AlignLeft | Qt::AlignTop, "W").height(); const uint64_t sample_rate = _view.session().cur_samplerate(); - const double x = (_dso_ym_index / (sample_rate * _view.scale())) - - _view.offset() /_view.scale(); + const int64_t x = (_dso_ym_index / (sample_rate * _view.scale())) - + _view.offset(); p.drawLine(x-10, _dso_ym_start, x+10, _dso_ym_start); p.drawLine(x, _dso_ym_start, @@ -1135,7 +1172,7 @@ void Viewport::paintMeasure(QPainter &p) QLineF *line; QLineF *const measure_lines = new QLineF[measure_line_count]; line = measure_lines; - double x[DsoMeasureStages]; + int64_t x[DsoMeasureStages]; int dso_xm_stage = 0; if (_action_type == DSO_XM_STEP1) dso_xm_stage = 1; @@ -1146,18 +1183,18 @@ void Viewport::paintMeasure(QPainter &p) for (int i = 0; i < dso_xm_stage; i++) { x[i] = (_dso_xm_index[i] / (sample_rate * _view.scale())) - - _view.offset() /_view.scale(); + _view.offset(); } measure_line_count = 0; if (dso_xm_stage > 0) { - *line++ = QLineF(x[0], _dso_xm_y - 10, + *line++ = QLine(x[0], _dso_xm_y - 10, x[0], _dso_xm_y + 10); measure_line_count += 1; } if (dso_xm_stage > 1) { - *line++ = QLineF(x[1], _dso_xm_y - 10, + *line++ = QLine(x[1], _dso_xm_y - 10, x[1], _dso_xm_y + 10); - *line++ = QLineF(x[0], _dso_xm_y, + *line++ = QLine(x[0], _dso_xm_y, x[1], _dso_xm_y); _mm_width = _view.get_ruler()->format_real_time(_dso_xm_index[1] - _dso_xm_index[0], sample_rate); @@ -1274,14 +1311,14 @@ void Viewport::set_measure_en(int enable) void Viewport::start_trigger_timer(int msec) { assert(msec > 0); - triggered = false; + transfer_started = false; timer_cnt = 0; trigger_timer.start(msec); } void Viewport::stop_trigger_timer() { - triggered = true; + transfer_started = true; timer_cnt = 0; trigger_timer.stop(); } @@ -1294,13 +1331,13 @@ void Viewport::on_trigger_timer() void Viewport::on_drag_timer() { - const double offset = _view.offset(); + const int64_t offset = _view.offset(); const double scale = _view.scale(); if (_view.session().get_capture_state() == SigSession::Stopped && _drag_strength != 0 && offset < _view.get_max_offset() && offset > _view.get_min_offset()) { - _view.set_scale_offset(scale, offset + _drag_strength * scale); + _view.set_scale_offset(scale, offset + _drag_strength); _drag_strength /= DragDamping; if (_drag_strength != 0) _drag_timer.start(DragTimerInterval); diff --git a/DSView/pv/view/viewport.h b/DSView/pv/view/viewport.h index 588dbda0..b87994e3 100644 --- a/DSView/pv/view/viewport.h +++ b/DSView/pv/view/viewport.h @@ -119,7 +119,6 @@ private: void measure(); private slots: - void on_traces_moved(); void on_trigger_timer(); void on_drag_timer(); void set_receive_len(quint64 length); @@ -130,18 +129,19 @@ public slots: signals: void measure_updated(); + void prgRate(int progress); private: View &_view; View_type _type; bool _need_update; - uint64_t _total_receive_len; + uint64_t _sample_received; QPoint _mouse_point; QPoint _mouse_down_point; - double _mouse_down_offset; + int64_t _mouse_down_offset; double _curScale; - double _curOffset; + int64_t _curOffset; int _curSignalHeight; QPixmap pixmap; @@ -152,10 +152,10 @@ private: uint64_t _cur_sample; uint64_t _nxt_sample; uint64_t _thd_sample; - double _cur_preX; - double _cur_aftX; - double _cur_thdX; - double _cur_midY; + int64_t _cur_preX; + int64_t _cur_aftX; + int64_t _cur_thdX; + int _cur_midY; QString _mm_width; QString _mm_period; QString _mm_freq; @@ -169,7 +169,7 @@ private: QString _em_edges; QTimer trigger_timer; - bool triggered; + bool transfer_started; int timer_cnt; boost::shared_ptr _drag_sig; diff --git a/DSView/pv/widgets/border.cpp b/DSView/pv/widgets/border.cpp index 3196d188..42fc3bd5 100644 --- a/DSView/pv/widgets/border.cpp +++ b/DSView/pv/widgets/border.cpp @@ -103,5 +103,10 @@ void Border::paintEvent(QPaintEvent *) } } +void Border::leaveEvent(QEvent*) +{ + //setCursor(Qt::ArrowCursor); +} + } // namespace widgets } // namespace pv diff --git a/DSView/pv/widgets/border.h b/DSView/pv/widgets/border.h index 970ac42f..6e850a85 100644 --- a/DSView/pv/widgets/border.h +++ b/DSView/pv/widgets/border.h @@ -35,6 +35,7 @@ public: protected: void paintEvent(QPaintEvent *); + void leaveEvent(QEvent *); private: int _type; diff --git a/DSView/pv/widgets/decodergroupbox.cpp b/DSView/pv/widgets/decodergroupbox.cpp index 1b802e38..86433eba 100644 --- a/DSView/pv/widgets/decodergroupbox.cpp +++ b/DSView/pv/widgets/decodergroupbox.cpp @@ -19,7 +19,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ extern "C" { -#include +#include } #include "decodergroupbox.h" diff --git a/DSView/pv/widgets/decodermenu.cpp b/DSView/pv/widgets/decodermenu.cpp index e3eac36c..158cdecb 100644 --- a/DSView/pv/widgets/decodermenu.cpp +++ b/DSView/pv/widgets/decodermenu.cpp @@ -19,7 +19,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include +#include #include "decodermenu.h" #include diff --git a/DSView/pv/widgets/viewstatus.cpp b/DSView/pv/widgets/viewstatus.cpp index 50b00b91..05c79a27 100644 --- a/DSView/pv/widgets/viewstatus.cpp +++ b/DSView/pv/widgets/viewstatus.cpp @@ -26,11 +26,14 @@ #include #include "../view/trace.h" +#include "../sigsession.h" namespace pv { namespace widgets { -ViewStatus::ViewStatus(QWidget *parent) : QWidget(parent) +ViewStatus::ViewStatus(SigSession &session, QWidget *parent) : + QWidget(parent), + _session(session) { } @@ -44,12 +47,28 @@ void ViewStatus::paintEvent(QPaintEvent *) p.setPen(pv::view::Trace::DARK_FORE); p.drawText(this->rect(), Qt::AlignLeft | Qt::AlignVCenter, _rle_depth); p.drawText(this->rect(), Qt::AlignRight | Qt::AlignVCenter, _trig_time); + + p.setPen(Qt::NoPen); + p.setBrush(pv::view::Trace::dsLightBlue); + p.drawRect(this->rect().left(), this->rect().bottom() - 3, + _session.get_repeat_hold() * this->rect().width() / 100, 3); + + p.setPen(pv::view::Trace::dsLightBlue); + p.drawText(this->rect(), Qt::AlignCenter | Qt::AlignVCenter, _capture_status); } void ViewStatus::clear() { _trig_time.clear(); _rle_depth.clear(); + _capture_status.clear(); + update(); +} + +void ViewStatus::repeat_unshow() +{ + _capture_status.clear(); + update(); } void ViewStatus::set_trig_time(QDateTime time) @@ -59,7 +78,15 @@ void ViewStatus::set_trig_time(QDateTime time) void ViewStatus::set_rle_depth(uint64_t depth) { - _rle_depth = tr("RLE FULL: ") + QString::number(depth) + tr(" samples captured!"); + _rle_depth = QString::number(depth) + tr(" Samples Captured!"); +} + +void ViewStatus::set_capture_status(bool triggered, int progess) +{ + if (triggered) + _capture_status = tr("Triggered! ") + QString::number(progess) + tr("% Captured"); + else + _capture_status = tr("Waiting for Trigger! ") + QString::number(progess) + tr("% Captured"); } } // namespace widgets diff --git a/DSView/pv/widgets/viewstatus.h b/DSView/pv/widgets/viewstatus.h index 58078d0d..a41f9d31 100644 --- a/DSView/pv/widgets/viewstatus.h +++ b/DSView/pv/widgets/viewstatus.h @@ -24,7 +24,7 @@ #include #include -#include "QDateTime" +#include namespace pv { @@ -36,7 +36,7 @@ class ViewStatus : public QWidget { Q_OBJECT public: - explicit ViewStatus(QWidget *parent = 0); + explicit ViewStatus(SigSession &session, QWidget *parent = 0); void paintEvent(QPaintEvent *); @@ -44,12 +44,17 @@ signals: public slots: void clear(); + void repeat_unshow(); void set_trig_time(QDateTime time); void set_rle_depth(uint64_t depth); + void set_capture_status(bool triggered, int progess); private: + SigSession &_session; + QString _trig_time; QString _rle_depth; + QString _capture_status; }; } // namespace widgets diff --git a/DSView/res/DSCope.bin b/DSView/res/DSCope.bin old mode 100755 new mode 100644 index e56e9a42..da90491c Binary files a/DSView/res/DSCope.bin and b/DSView/res/DSCope.bin differ diff --git a/DSView/res/DSCope.fw b/DSView/res/DSCope.fw old mode 100755 new mode 100644 index 030486b2..2de2f3fb Binary files a/DSView/res/DSCope.fw and b/DSView/res/DSCope.fw differ diff --git a/DSView/res/DSCope1.def.dsc b/DSView/res/DSCope1.def.dsc old mode 100755 new mode 100644 diff --git a/DSView/res/DSCope20.bin b/DSView/res/DSCope20.bin old mode 100755 new mode 100644 index ffd960cb..f4ae400c Binary files a/DSView/res/DSCope20.bin and b/DSView/res/DSCope20.bin differ diff --git a/DSView/res/DSCope20.fw b/DSView/res/DSCope20.fw old mode 100755 new mode 100644 index 5071e785..193c8504 Binary files a/DSView/res/DSCope20.fw and b/DSView/res/DSCope20.fw differ diff --git a/DSView/res/DSCopeTest.dsc b/DSView/res/DSCopeTest.dsc new file mode 100644 index 00000000..9919789f --- /dev/null +++ b/DSView/res/DSCopeTest.dsc @@ -0,0 +1,43 @@ +{ + "Device": "DSCope", + "DeviceMode": 1, + "Horizontal trigger position": "0", + "Operation Mode": "Normal", + "Sample count": "1048576", + "Sample rate": "100000000", + "Time base": "10000", + "Trigger channel": "0", + "Trigger hold off": "0", + "Trigger margin": "8", + "Trigger slope": "0", + "Trigger source": "0", + "Version": 2, + "channel": [ + { + "colour": "#eeb211", + "coupling": 0, + "enabled": true, + "index": 0, + "name": "0", + "trigValue": 0.50196078431372548, + "type": 10001, + "vdiv": 1000, + "vfactor": 1, + "zeroPos": 0.4 + }, + { + "colour": "#009925", + "coupling": 0, + "enabled": true, + "index": 1, + "name": "1", + "trigValue": 0.50196078431372548, + "type": 10001, + "vdiv": 1000, + "vfactor": 1, + "zeroPos": 0.6 + } + ], + "decoder": [ + ] +} diff --git a/DSView/res/DSLogic.fw b/DSView/res/DSLogic.fw old mode 100755 new mode 100644 index f32f92a7..6f048773 Binary files a/DSView/res/DSLogic.fw and b/DSView/res/DSLogic.fw differ diff --git a/DSView/res/DSLogic0.def.dsc b/DSView/res/DSLogic0.def.dsc old mode 100755 new mode 100644 index 83ecadd3..6ae5c7fb --- a/DSView/res/DSLogic0.def.dsc +++ b/DSView/res/DSLogic0.def.dsc @@ -14,7 +14,7 @@ "Trigger slope": "0", "Trigger source": "0", "Using Clock Negedge": 0, - "Using External Clock": 0, + "Using External Clock": 1, "channel": [ { "colour": "#969696", diff --git a/DSView/res/DSLogic1.def.dsc b/DSView/res/DSLogic1.def.dsc old mode 100755 new mode 100644 diff --git a/DSView/res/DSLogic2.def.dsc b/DSView/res/DSLogic2.def.dsc old mode 100755 new mode 100644 diff --git a/DSView/res/DSLogic33.bin b/DSView/res/DSLogic33.bin old mode 100755 new mode 100644 index cac82619..168d68fa Binary files a/DSView/res/DSLogic33.bin and b/DSView/res/DSLogic33.bin differ diff --git a/DSView/res/DSLogic50.bin b/DSView/res/DSLogic50.bin old mode 100755 new mode 100644 index 50bef232..44457683 Binary files a/DSView/res/DSLogic50.bin and b/DSView/res/DSLogic50.bin differ diff --git a/DSView/res/DSLogicBasic.bin b/DSView/res/DSLogicBasic.bin new file mode 100644 index 00000000..fb63035f Binary files /dev/null and b/DSView/res/DSLogicBasic.bin differ diff --git a/DSView/res/DSLogicBasic.fw b/DSView/res/DSLogicBasic.fw new file mode 100644 index 00000000..486c2b4f Binary files /dev/null and b/DSView/res/DSLogicBasic.fw differ diff --git a/DSView/res/DSLogicPlus.bin b/DSView/res/DSLogicPlus.bin new file mode 100644 index 00000000..605392ac Binary files /dev/null and b/DSView/res/DSLogicPlus.bin differ diff --git a/DSView/res/DSLogicPlus.fw b/DSView/res/DSLogicPlus.fw new file mode 100644 index 00000000..69096b44 Binary files /dev/null and b/DSView/res/DSLogicPlus.fw differ diff --git a/DSView/res/DSLogicPro.bin b/DSView/res/DSLogicPro.bin old mode 100755 new mode 100644 index 9074fd57..a236b61d Binary files a/DSView/res/DSLogicPro.bin and b/DSView/res/DSLogicPro.bin differ diff --git a/DSView/res/DSLogicPro.fw b/DSView/res/DSLogicPro.fw old mode 100755 new mode 100644 index 22924c2b..dcf0543a Binary files a/DSView/res/DSLogicPro.fw and b/DSView/res/DSLogicPro.fw differ diff --git a/DSView/res/license.txt b/DSView/res/license.txt new file mode 100644 index 00000000..8ccdad02 --- /dev/null +++ b/DSView/res/license.txt @@ -0,0 +1,20 @@ +Copyright (c) 2017 DreamSourceLab + +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. \ No newline at end of file diff --git a/libsigrok4DSL/Makefile.am b/libsigrok4DSL/Makefile.am index e77f42f4..a22b7522 100644 --- a/libsigrok4DSL/Makefile.am +++ b/libsigrok4DSL/Makefile.am @@ -33,7 +33,6 @@ libsigrok4DSL_la_SOURCES = \ session_file.c \ session_driver.c \ hwdriver.c \ - filter.c \ strutil.c \ log.c \ trigger.c \ diff --git a/libsigrok4DSL/backend.c b/libsigrok4DSL/backend.c index 8acddbc4..22750784 100644 --- a/libsigrok4DSL/backend.c +++ b/libsigrok4DSL/backend.c @@ -261,7 +261,7 @@ static int sanity_check_all_input_modules(void) static int sanity_check_all_output_modules(void) { int i, errors, ret = SR_OK; - struct sr_output_module **outputs; + const struct sr_output_module **outputs; const char *d; sr_spew("Sanity-checking all output modules."); diff --git a/libsigrok4DSL/configure.ac b/libsigrok4DSL/configure.ac index 44d958ea..1b00cca8 100644 --- a/libsigrok4DSL/configure.ac +++ b/libsigrok4DSL/configure.ac @@ -52,6 +52,12 @@ AC_PROG_CPP AC_PROG_INSTALL AC_PROG_LN_S +# https://github.com/rsyslog/rsyslog/issues/1179 +# Seems libtool doesn't honors ARFLAGS, but statically set AR_FLAGS=cru +# This causes a few warnings on build: +# "ar u modifier ignored since D is the default (see U)" +m4_divert_text([DEFAULTS], [: "${ARFLAGS=cr} ${AR_FLAGS=cr}"]) + # Required for per-target flags or subdir-objects with C sources. AM_PROG_CC_C_O diff --git a/libsigrok4DSL/filter.c b/libsigrok4DSL/filter.c deleted file mode 100644 index 11cad5c3..00000000 --- a/libsigrok4DSL/filter.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * 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 . - */ - -#include -#include -#include -#include -#include "libsigrok.h" -#include "libsigrok-internal.h" - -/* Message logging helpers with subsystem-specific prefix string. */ -#define LOG_PREFIX "filter: " -#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args) -#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args) -#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args) -#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args) -#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args) -#define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args) - -/** - * @file - * - * Helper functions to filter out unused probes from samples. - */ - -/** - * @defgroup grp_filter Probe filter - * - * Helper functions to filter out unused probes from samples. - * - * @{ - */ - -/** - * Remove unused probes from samples. - * - * Convert sample from maximum probes -- the way the hardware driver sent - * it -- to a sample taking up only as much space as required, with - * unused probes removed. - * - * The "unit size" is the number of bytes used to store probe values. - * For example, a unit size of 1 means one byte is used (which can store - * 8 probe values, each of them is 1 bit). A unit size of 2 means we can - * store 16 probe values, 3 means we can store 24 probe values, and so on. - * - * If the data coming from the logic analyzer has a unit size of 4 for - * example (as the device has 32 probes), but only 2 of them are actually - * used in an acquisition, this function can convert the samples to only - * use up 1 byte per sample (unit size = 1) instead of 4 bytes per sample. - * - * The output will contain the probe values in the order specified via the - * probelist. For example, if in_unitsize = 4, probelist = [5, 16, 30], and - * out_unitsize = 1, then the output samples (each of them one byte in size) - * will have the following format: bit 0 = value of probe 5, bit 1 = value - * of probe 16, bit 2 = value of probe 30. Unused bit(s) in the output byte(s) - * are zero. - * - * The caller must make sure that length_in is not bigger than the memory - * actually allocated for the input data (data_in), as this function does - * not check that. - * - * @param in_unitsize The unit size (>= 1) of the input (data_in). - * @param out_unitsize The unit size (>= 1) the output shall have (data_out). - * The requested unit size must be big enough to hold as - * much data as is specified by the number of enabled - * probes in 'probelist'. - * @param probe_array Pointer to a list of probe numbers, numbered starting - * from 0. The list is terminated with -1. - * @param data_in Pointer to the input data buffer. Must not be NULL. - * @param length_in The input data length (>= 1), in number of bytes. - * @param data_out Variable which will point to the newly allocated buffer - * of output data. The caller is responsible for g_free()'ing - * the buffer when it's no longer needed. Must not be NULL. - * @param length_out Pointer to the variable which will contain the output - * data length (in number of bytes) when the function - * returns SR_OK. Must not be NULL. - * - * @return SR_OK upon success, SR_ERR_MALLOC upon memory allocation errors, - * or SR_ERR_ARG upon invalid arguments. - * If something other than SR_OK is returned, the values of - * out_unitsize, data_out, and length_out are undefined. - * - * @since 0.1.0 (but the API changed in 0.2.0) - */ -SR_API int sr_filter_probes(unsigned int in_unitsize, unsigned int out_unitsize, - const GArray *probe_array, const uint8_t *data_in, - uint64_t length_in, uint8_t **data_out, - uint64_t *length_out) -{ - unsigned int in_offset, out_offset; - int *probelist, out_bit; - unsigned int i; - uint64_t sample_in, sample_out; - - if (!probe_array) { - sr_err("%s: probe_array was NULL", __func__); - return SR_ERR_ARG; - } - probelist = (int *)probe_array->data; - - if (!data_in) { - sr_err("%s: data_in was NULL", __func__); - return SR_ERR_ARG; - } - - if (!data_out) { - sr_err("%s: data_out was NULL", __func__); - return SR_ERR_ARG; - } - - if (!length_out) { - sr_err("%s: length_out was NULL", __func__); - return SR_ERR_ARG; - } - - /* Are there more probes than the target unit size supports? */ - if (probe_array->len > out_unitsize * 8) { - sr_err("%s: too many probes (%d) for the target unit " - "size (%d)", __func__, probe_array->len, out_unitsize); - return SR_ERR_ARG; - } - - if (!(*data_out = g_try_malloc(length_in))) { - sr_err("%s: data_out malloc failed", __func__); - return SR_ERR_MALLOC; - } - - if (probe_array->len == in_unitsize * 8) { - /* All probes are used -- no need to compress anything. */ - memcpy(*data_out, data_in, length_in); - *length_out = length_in; - return SR_OK; - } - - /* If we reached this point, not all probes are used, so "compress". */ - in_offset = out_offset = 0; - while (in_offset <= length_in - in_unitsize) { - memcpy(&sample_in, data_in + in_offset, in_unitsize); - sample_out = out_bit = 0; - for (i = 0; i < probe_array->len; i++) { - if (sample_in & (1 << (probelist[i]))) - sample_out |= (1 << out_bit); - out_bit++; - } - memcpy((*data_out) + out_offset, &sample_out, out_unitsize); - in_offset += in_unitsize; - out_offset += out_unitsize; - } - *length_out = out_offset; - - return SR_OK; -} - -/** @} */ diff --git a/libsigrok4DSL/hardware/DSL/command.c b/libsigrok4DSL/hardware/DSL/command.c index b23e852e..654824e8 100644 --- a/libsigrok4DSL/hardware/DSL/command.c +++ b/libsigrok4DSL/hardware/DSL/command.c @@ -271,7 +271,7 @@ SR_PRIV int command_wr_nvm(libusb_device_handle *devhdl, unsigned char *ctx, uin return SR_OK; } -SR_PRIV int command_rd_nvm(libusb_device_handle *devhdl, unsigned char *ctx, uint8_t addr, uint8_t len) +SR_PRIV int command_rd_nvm(libusb_device_handle *devhdl, unsigned char *ctx, uint16_t addr, uint8_t len) { int ret; @@ -285,7 +285,7 @@ SR_PRIV int command_rd_nvm(libusb_device_handle *devhdl, unsigned char *ctx, uin LIBUSB_ENDPOINT_OUT, CMD_RD_NVM_PRE, 0x0000, 0x0000, (unsigned char *)&nvm_info, sizeof(struct cmd_nvm_info), 3000); if (ret < 0) { - sr_err("Unable to send CMD_ZERO_RD_PRE command: %s.", + sr_err("Unable to send CMD_RD_NVM_PRE command: %s.", libusb_error_name(ret)); return SR_ERR; } @@ -306,17 +306,16 @@ SR_PRIV int command_rd_nvm(libusb_device_handle *devhdl, unsigned char *ctx, uin return SR_OK; } -SR_PRIV int command_get_fpga_done(libusb_device_handle *devhdl, - uint8_t *fpga_done) +SR_PRIV int command_get_hw_info(libusb_device_handle *devhdl, uint8_t *info) { int ret; ret = libusb_control_transfer(devhdl, LIBUSB_REQUEST_TYPE_VENDOR | - LIBUSB_ENDPOINT_IN, CMD_FPGA_DONE, 0x0000, 0x0000, - fpga_done, 1, 3000); + LIBUSB_ENDPOINT_IN, CMD_GET_HW_INFO, 0x0000, 0x0000, + info, 1, 3000); if (ret < 0) { - sr_err("Unable to get fpga done info: %s.", + sr_err("Unable to get hardware info: %s.", libusb_error_name(ret)); return SR_ERR; } diff --git a/libsigrok4DSL/hardware/DSL/command.h b/libsigrok4DSL/hardware/DSL/command.h index 352fafb2..071ef312 100644 --- a/libsigrok4DSL/hardware/DSL/command.h +++ b/libsigrok4DSL/hardware/DSL/command.h @@ -37,7 +37,7 @@ #define CMD_WR_NVM 0xb9 #define CMD_RD_NVM 0xba #define CMD_RD_NVM_PRE 0xbb -#define CMD_FPGA_DONE 0xbc +#define CMD_GET_HW_INFO 0xbc #define CMD_START_FLAGS_MODE_POS 4 #define CMD_START_FLAGS_WIDE_POS 5 @@ -138,7 +138,7 @@ struct cmd_vga_info { }; struct cmd_nvm_info { - uint8_t addr; + uint16_t addr; uint8_t len; }; @@ -150,7 +150,7 @@ SR_PRIV int command_get_revid_version(libusb_device_handle *devhdl, uint8_t *revid); SR_PRIV int command_start_acquisition(libusb_device_handle *devhdl, uint64_t samplerate, gboolean samplewide, gboolean la_mode); -SR_PRIV int command_stop_acquistition(libusb_device_handle *devhdl); +SR_PRIV int command_stop_acquisition(libusb_device_handle *devhdl); SR_PRIV int command_fpga_config(libusb_device_handle *devhdl); SR_PRIV int command_fpga_setting(libusb_device_handle *devhdl, uint32_t setting_count); @@ -164,8 +164,8 @@ SR_PRIV int command_get_status(libusb_device_handle *devhdl, SR_PRIV int command_wr_reg(libusb_device_handle *devhdl, uint8_t value, uint8_t addr); SR_PRIV int command_wr_nvm(libusb_device_handle *devhdl, unsigned char *ctx, uint8_t len); -SR_PRIV int command_rd_nvm(libusb_device_handle *devhdl, unsigned char *ctx, uint8_t addr, uint8_t len); +SR_PRIV int command_rd_nvm(libusb_device_handle *devhdl, unsigned char *ctx, uint16_t addr, uint8_t len); -SR_PRIV int command_get_fpga_done(libusb_device_handle *devhdl, +SR_PRIV int command_get_hw_info(libusb_device_handle *devhdl, uint8_t *fpga_done); #endif diff --git a/libsigrok4DSL/hardware/DSL/dscope.c b/libsigrok4DSL/hardware/DSL/dscope.c index bd7481ae..a6998ae5 100644 --- a/libsigrok4DSL/hardware/DSL/dscope.c +++ b/libsigrok4DSL/hardware/DSL/dscope.c @@ -52,8 +52,6 @@ static const char *opmodes[] = { "DRAM Loopback Test", }; -static uint16_t opmodes_show_count = 2; - static const char *thresholds[] = { "1.8/2.5/3.3V Level", "5.0V Level", @@ -141,6 +139,7 @@ static const uint64_t samplecounts[] = { SR_MB(32), }; +static uint16_t opmodes_show_count = 2; static const uint8_t zero_base_addr = 0x40; SR_PRIV struct sr_dev_driver DSCope_driver_info; @@ -182,7 +181,7 @@ struct DSL_vga DSCope_vga[] = { {500, DSCOPE_DEFAULT_VGAIN5, DSCOPE_DEFAULT_VGAIN5, DSCOPE_DEFAULT_VOFF, DSCOPE_DEFAULT_VOFF}, {1000,DSCOPE_DEFAULT_VGAIN6, DSCOPE_DEFAULT_VGAIN6, DSCOPE_DEFAULT_VOFF, DSCOPE_DEFAULT_VOFF}, {2000,DSCOPE_DEFAULT_VGAIN7, DSCOPE_DEFAULT_VGAIN7, DSCOPE_DEFAULT_VOFF, DSCOPE_DEFAULT_VOFF}, - {0, 0, 0, 0}, + {0, 0, 0, 0, 0}, }; struct DSL_vga DSCope20_vga[] = { {10, DSCOPE20_DEFAULT_VGAIN0, DSCOPE20_DEFAULT_VGAIN0, DSCOPE20_DEFAULT_VOFF, CALI_VOFF_RANGE-DSCOPE20_DEFAULT_VOFF}, @@ -193,7 +192,7 @@ struct DSL_vga DSCope20_vga[] = { {500, DSCOPE20_DEFAULT_VGAIN5, DSCOPE20_DEFAULT_VGAIN5, DSCOPE20_DEFAULT_VOFF, CALI_VOFF_RANGE-DSCOPE20_DEFAULT_VOFF}, {1000,DSCOPE20_DEFAULT_VGAIN6, DSCOPE20_DEFAULT_VGAIN6, DSCOPE20_DEFAULT_VOFF, CALI_VOFF_RANGE-DSCOPE20_DEFAULT_VOFF}, {2000,DSCOPE20_DEFAULT_VGAIN7, DSCOPE20_DEFAULT_VGAIN7, DSCOPE20_DEFAULT_VOFF, CALI_VOFF_RANGE-DSCOPE20_DEFAULT_VOFF}, - {0, 0, 0, 0}, + {0, 0, 0, 0, 0}, }; /** @@ -264,6 +263,9 @@ static int fpga_setting(const struct sr_dev_inst *sdi) int transferred; int result; int i; + GSList *l; + uint32_t tmp_u32; + uint64_t tmp_u64; devc = sdi->priv; usb = sdi->conn; @@ -271,51 +273,65 @@ static int fpga_setting(const struct sr_dev_inst *sdi) setting.sync = 0xf5a5f5a5; setting.mode_header = 0x0001; - setting.divider_header = 0x0102ffff; - setting.count_header = 0x0302ffff; - setting.trig_pos_header = 0x0502ffff; + setting.divider_header = 0x0102; + setting.count_header = 0x0302; + setting.trig_pos_header = 0x0502; setting.trig_glb_header = 0x0701; - setting.trig_adp_header = 0x0a02ffff; - setting.trig_sda_header = 0x0c02ffff; - setting.trig_mask0_header = 0x1010ffff; - setting.trig_mask1_header = 0x1110ffff; - //setting.trig_mask2_header = 0x1210ffff; - //setting.trig_mask3_header = 0x1310ffff; - setting.trig_value0_header = 0x1410ffff; - setting.trig_value1_header = 0x1510ffff; - //setting.trig_value2_header = 0x1610ffff; - //setting.trig_value3_header = 0x1710ffff; - setting.trig_edge0_header = 0x1810ffff; - setting.trig_edge1_header = 0x1910ffff; - //setting.trig_edge2_header = 0x1a10ffff; - //setting.trig_edge3_header = 0x1b10ffff; - setting.trig_count0_header = 0x1c20ffff; - setting.trig_count1_header = 0x1d20ffff; - //setting.trig_count2_header = 0x1e10ffff; - //setting.trig_count3_header = 0x1f10ffff; - setting.trig_logic0_header = 0x2010ffff; - setting.trig_logic1_header = 0x2110ffff; - //setting.trig_logic2_header = 0x2210ffff; - //setting.trig_logic3_header = 0x2310ffff; + setting.ch_en_header = 0x0801; + setting.trig_header = 0x40a0; setting.end_sync = 0xfa5afa5a; //setting.mode = (test_mode ? 0x8000 : 0x0000) + trigger->trigger_en + (sdi->mode << 4); - setting.mode = ((devc->op_mode == SR_OP_INTERNAL_TEST) << 15) + - ((devc->op_mode == SR_OP_EXTERNAL_TEST) << 14) + - ((devc->op_mode == SR_OP_LOOPBACK_TEST) << 13) + - trigger->trigger_en + - ((sdi->mode == DSO) << 4) + (devc->clock_type << 1) + (devc->clock_edge << 2) + - (((devc->cur_samplerate == SR_MHZ(200) && sdi->mode != DSO) || (sdi->mode == ANALOG)) << 5) + - ((devc->cur_samplerate == SR_MHZ(400)) << 6) + - ((sdi->mode == ANALOG) << 7) + - ((devc->filter == SR_FILTER_1T) << 8) + - (devc->instant << 9); - setting.divider = (uint32_t)ceil(DSCOPE_MAX_SAMPLERATE * 1.0 / devc->cur_samplerate / en_ch_num(sdi)); - setting.count = (uint32_t)(devc->limit_samples / (g_slist_length(sdi->channels) / en_ch_num(sdi))); - setting.trig_pos = (uint32_t)(trigger->trigger_pos / 100.0 * devc->limit_samples); - setting.trig_glb = trigger->trigger_stages; - setting.trig_adp = setting.count - setting.trig_pos - 1; - setting.trig_sda = 0x0; + setting.mode = (trigger->trigger_en << TRIG_EN_BIT) + + (devc->clock_type << CLK_TYPE_BIT) + + (devc->clock_edge << CLK_EDGE_BIT) + + ((sdi->mode == DSO) << DSO_MODE_BIT) + + ((((devc->cur_samplerate == (2 * DSLOGIC_MAX_LOGIC_SAMPLERATE)) && sdi->mode != DSO) || (sdi->mode == ANALOG)) << HALF_MODE_BIT) + + ((devc->cur_samplerate == (4 * DSLOGIC_MAX_LOGIC_SAMPLERATE)) << QUAR_MODE_BIT) + + ((sdi->mode == ANALOG) << ANALOG_MODE_BIT) + + ((devc->filter == SR_FILTER_1T) << FILTER_BIT) + + (devc->instant << INSTANT_BIT) + + ((devc->op_mode == SR_OP_LOOPBACK_TEST) << LPB_TEST_BIT) + + ((devc->op_mode == SR_OP_EXTERNAL_TEST) << EXT_TEST_BIT) + + ((devc->op_mode == SR_OP_INTERNAL_TEST) << INT_TEST_BIT); + + // sample rate divider + tmp_u32 = (sdi->mode == DSO) ? (uint32_t)ceil(DSLOGIC_MAX_DSO_SAMPLERATE * 1.0 / devc->cur_samplerate / en_ch_num(sdi)) : + (uint32_t)ceil(DSLOGIC_MAX_LOGIC_SAMPLERATE * 1.0 / devc->cur_samplerate); + setting.div_l = tmp_u32 & 0x0000ffff; + setting.div_h = tmp_u32 >> 16; + + // capture counter + // analog: 16bits, but sample with half mode(0-7 valid only) + tmp_u64 = (sdi->mode == DSO) ? (devc->limit_samples / (g_slist_length(sdi->channels) / en_ch_num(sdi))) : + (sdi->mode == ANALOG) ? (devc->limit_samples * g_slist_length(sdi->channels) * 4) : + (devc->limit_samples); + tmp_u64 >>= 4; // hardware minimum unit 64 + setting.cnt_l = tmp_u64 & 0x0000ffff; + setting.cnt_h = tmp_u64 >> 16; + + // trigger position + tmp_u32 = (uint32_t)(trigger->trigger_pos / 100.0 * devc->limit_samples); + if (setting.mode & (1 << QUAR_MODE_BIT)) + setting.tpos_l = tmp_u32 & 0x0000fffc; + else if (setting.mode & (1 << HALF_MODE_BIT)) + setting.tpos_l = tmp_u32 & 0x0000fffe; + else + setting.tpos_l = tmp_u32 & 0x0000ffff; + setting.tpos_h = tmp_u32 >> 16; + + // trigger global settings + setting.trig_glb = ((en_ch_num(sdi) & 0xf) << 4) + + trigger->trigger_stages; + + // channel enable mapping + setting.ch_en = 0; + for (l = sdi->channels; l; l = l->next) { + struct sr_channel *probe = (struct sr_channel *)l->data; + setting.ch_en += probe->enabled << probe->index; + } + + // trigger advanced configuration if (trigger->trigger_mode == SIMPLE_TRIGGER) { setting.trig_mask0[0] = ds_trigger_get_mask0(TriggerStages); setting.trig_mask1[0] = ds_trigger_get_mask1(TriggerStages); @@ -326,15 +342,54 @@ static int fpga_setting(const struct sr_dev_inst *sdi) setting.trig_edge0[0] = ds_trigger_get_edge0(TriggerStages); setting.trig_edge1[0] = ds_trigger_get_edge1(TriggerStages); - setting.trig_count0[0] = trigger->trigger0_count[TriggerStages]; - setting.trig_count1[0] = trigger->trigger1_count[TriggerStages]; + if (setting.mode & (1 << QUAR_MODE_BIT)) { + setting.trig_mask0[0] = ((setting.trig_mask0[0] & 0x0f) << 12) + + ((setting.trig_mask0[0] & 0x0f) << 8) + + ((setting.trig_mask0[0] & 0x0f) << 4) + + ((setting.trig_mask0[0] & 0x0f) << 0); + setting.trig_mask1[0] = ((setting.trig_mask1[0] & 0x0f) << 12) + + ((setting.trig_mask1[0] & 0x0f) << 8) + + ((setting.trig_mask1[0] & 0x0f) << 4) + + ((setting.trig_mask1[0] & 0x0f) << 0); + setting.trig_value0[0] = ((setting.trig_value0[0] & 0x0f) << 12) + + ((setting.trig_value0[0] & 0x0f) << 8) + + ((setting.trig_value0[0] & 0x0f) << 4) + + ((setting.trig_value0[0] & 0x0f) << 0); + setting.trig_value1[0] = ((setting.trig_value1[0] & 0x0f) << 12) + + ((setting.trig_value1[0] & 0x0f) << 8) + + ((setting.trig_value1[0] & 0x0f) << 4) + + ((setting.trig_value1[0] & 0x0f) << 0); + setting.trig_edge0[0] = ((setting.trig_edge0[0] & 0x0f) << 12) + + ((setting.trig_edge0[0] & 0x0f) << 8) + + ((setting.trig_edge0[0] & 0x0f) << 4) + + ((setting.trig_edge0[0] & 0x0f) << 0); + setting.trig_edge1[0] = ((setting.trig_edge1[0] & 0x0f) << 12) + + ((setting.trig_edge1[0] & 0x0f) << 8) + + ((setting.trig_edge1[0] & 0x0f) << 4) + + ((setting.trig_edge1[0] & 0x0f) << 0); + } else if (setting.mode & (1 << HALF_MODE_BIT)) { + setting.trig_mask0[0] = ((setting.trig_mask0[0] & 0xff) << 8) + + ((setting.trig_mask0[0] & 0xff) << 0); + setting.trig_mask1[0] = ((setting.trig_mask1[0] & 0xff) << 8) + + ((setting.trig_mask1[0] & 0xff) << 0); + setting.trig_value0[0] = ((setting.trig_value0[0] & 0xff) << 8) + + ((setting.trig_value0[0] & 0xff) << 0); + setting.trig_value1[0] = ((setting.trig_value1[0] & 0xff) << 8) + + ((setting.trig_value1[0] & 0xff) << 0); + setting.trig_edge0[0] = ((setting.trig_edge0[0] & 0xff) << 8) + + ((setting.trig_edge0[0] & 0xff) << 0); + setting.trig_edge1[0] = ((setting.trig_edge1[0] & 0xff) << 8) + + ((setting.trig_edge1[0] & 0xff) << 0); + } setting.trig_logic0[0] = (trigger->trigger_logic[TriggerStages] << 1) + trigger->trigger0_inv[TriggerStages]; setting.trig_logic1[0] = (trigger->trigger_logic[TriggerStages] << 1) + trigger->trigger1_inv[TriggerStages]; + setting.trig_count[0] = trigger->trigger0_count[TriggerStages]; + for (i = 1; i < NUM_TRIGGER_STAGES; i++) { - setting.trig_mask0[i] = 0xff; - setting.trig_mask1[i] = 0xff; + setting.trig_mask0[i] = 0xffff; + setting.trig_mask1[i] = 0xffff; setting.trig_value0[i] = 0; setting.trig_value1[i] = 0; @@ -342,11 +397,10 @@ static int fpga_setting(const struct sr_dev_inst *sdi) setting.trig_edge0[i] = 0; setting.trig_edge1[i] = 0; - setting.trig_count0[i] = 0; - setting.trig_count1[i] = 0; - setting.trig_logic0[i] = 2; setting.trig_logic1[i] = 2; + + setting.trig_count[i] = 0; } } else { for (i = 0; i < NUM_TRIGGER_STAGES; i++) { @@ -359,17 +413,60 @@ static int fpga_setting(const struct sr_dev_inst *sdi) setting.trig_edge0[i] = ds_trigger_get_edge0(i); setting.trig_edge1[i] = ds_trigger_get_edge1(i); - setting.trig_count0[i] = trigger->trigger0_count[i]; - setting.trig_count1[i] = trigger->trigger1_count[i]; + if (setting.mode & (1 << STRIG_MODE_BIT) && i == STriggerDataStage) { + // serial trigger, data mask/value should not be duplicated + } else { + if (setting.mode & (1 << QUAR_MODE_BIT)) { + setting.trig_mask0[i] = ((setting.trig_mask0[i] & 0x0f) << 12) + + ((setting.trig_mask0[i] & 0x0f) << 8) + + ((setting.trig_mask0[i] & 0x0f) << 4) + + ((setting.trig_mask0[i] & 0x0f) << 0); + setting.trig_mask1[i] = ((setting.trig_mask1[i] & 0x0f) << 12) + + ((setting.trig_mask1[i] & 0x0f) << 8) + + ((setting.trig_mask1[i] & 0x0f) << 4) + + ((setting.trig_mask1[i] & 0x0f) << 0); + setting.trig_value0[i] = ((setting.trig_value0[i] & 0x0f) << 12) + + ((setting.trig_value0[i] & 0x0f) << 8) + + ((setting.trig_value0[i] & 0x0f) << 4) + + ((setting.trig_value0[i] & 0x0f) << 0); + setting.trig_value1[i] = ((setting.trig_value1[i] & 0x0f) << 12) + + ((setting.trig_value1[i] & 0x0f) << 8) + + ((setting.trig_value1[i] & 0x0f) << 4) + + ((setting.trig_value1[i] & 0x0f) << 0); + setting.trig_edge0[i] = ((setting.trig_edge0[i] & 0x0f) << 12) + + ((setting.trig_edge0[i] & 0x0f) << 8) + + ((setting.trig_edge0[i] & 0x0f) << 4) + + ((setting.trig_edge0[i] & 0x0f) << 0); + setting.trig_edge1[i] = ((setting.trig_edge1[i] & 0x0f) << 12) + + ((setting.trig_edge1[i] & 0x0f) << 8) + + ((setting.trig_edge1[i] & 0x0f) << 4) + + ((setting.trig_edge1[i] & 0x0f) << 0); + } else if (setting.mode & (1 << HALF_MODE_BIT)) { + setting.trig_mask0[i] = ((setting.trig_mask0[i] & 0xff) << 8) + + ((setting.trig_mask0[i] & 0xff) << 0); + setting.trig_mask1[i] = ((setting.trig_mask1[i] & 0xff) << 8) + + ((setting.trig_mask1[i] & 0xff) << 0); + setting.trig_value0[i] = ((setting.trig_value0[i] & 0xff) << 8) + + ((setting.trig_value0[i] & 0xff) << 0); + setting.trig_value1[i] = ((setting.trig_value1[i] & 0xff) << 8) + + ((setting.trig_value1[i] & 0xff) << 0); + setting.trig_edge0[i] = ((setting.trig_edge0[i] & 0xff) << 8) + + ((setting.trig_edge0[i] & 0xff) << 0); + setting.trig_edge1[i] = ((setting.trig_edge1[i] & 0xff) << 8) + + ((setting.trig_edge1[i] & 0xff) << 0); + } + } setting.trig_logic0[i] = (trigger->trigger_logic[i] << 1) + trigger->trigger0_inv[i]; setting.trig_logic1[i] = (trigger->trigger_logic[i] << 1) + trigger->trigger1_inv[i]; + + setting.trig_count[i] = trigger->trigger0_count[i]; } } result = SR_OK; ret = libusb_bulk_transfer(hdl, 2 | LIBUSB_ENDPOINT_OUT, - &setting, sizeof(struct DSL_setting), + (unsigned char*)&setting, sizeof(struct DSL_setting), &transferred, 1000); if (ret < 0) { @@ -529,19 +626,20 @@ static int DSCope_dev_open(struct sr_dev_inst *sdi) break; } - /* - * Changes in major version mean incompatible/API changes, so - * bail out if we encounter an incompatible version. - * Different minor versions are OK, they should be compatible. - */ - if (vi.major != DSL_REQUIRED_VERSION_MAJOR) { - sr_err("Expected firmware version %d.x, " - "got %d.%d.", DSL_REQUIRED_VERSION_MAJOR, + /* + * Different versions may have incompatible issue, + * Mark for up level process + */ + if (vi.major != DSL_REQUIRED_VERSION_MAJOR || + vi.minor != DSL_REQUIRED_VERSION_MINOR) { + sr_err("Expected firmware version %d.%d, " + "got %d.%d.", DSL_REQUIRED_VERSION_MAJOR, DSL_REQUIRED_VERSION_MINOR, vi.major, vi.minor); - break; + sdi->status = SR_ST_INCOMPATIBLE; + } else { + sdi->status = SR_ST_ACTIVE; } - sdi->status = SR_ST_ACTIVE; sr_info("Opened device %d on %d.%d, " "interface %d, firmware %d.%d.", sdi->index, usb->bus, usb->address, @@ -554,7 +652,8 @@ static int DSCope_dev_open(struct sr_dev_inst *sdi) } libusb_free_device_list(devlist, 1); - if (sdi->status != SR_ST_ACTIVE) + if ((sdi->status != SR_ST_ACTIVE) && + (sdi->status != SR_ST_INCOMPATIBLE)) return SR_ERR; return SR_OK; @@ -601,15 +700,6 @@ static int configure_probes(const struct sr_dev_inst *sdi) } } - if (stage == -1) - /* - * We didn't configure any triggers, make sure acquisition - * doesn't wait for any. - */ - devc->trigger_stage = TRIGGER_FIRED; - else - devc->trigger_stage = 0; - return SR_OK; } @@ -645,6 +735,7 @@ static struct DSL_context *DSCope_dev_new(void) devc->dso_bits = 8; devc->trigger_margin = 8; devc->trigger_channel = 0; + devc->rle_mode = FALSE; return devc; } @@ -660,7 +751,7 @@ static int init(struct sr_context *sr_ctx) } -static struct DSL_vga* get_vga_ptr(struct sr_dev_inst *sdi) +static struct DSL_vga* get_vga_ptr(const struct sr_dev_inst *sdi) { struct DSL_vga *vga_ptr = NULL; if (strcmp(sdi->model, "DSCope") == 0) @@ -671,7 +762,7 @@ static struct DSL_vga* get_vga_ptr(struct sr_dev_inst *sdi) return vga_ptr; } -static uint16_t get_default_trans(struct sr_dev_inst *sdi) +static uint16_t get_default_trans(const struct sr_dev_inst *sdi) { uint16_t trans = 1; if (strcmp(sdi->model, "DSCope") == 0) @@ -682,21 +773,22 @@ static uint16_t get_default_trans(struct sr_dev_inst *sdi) return trans; } -static uint16_t get_default_voff(struct sr_dev_inst *sdi, int ch_index) +static uint16_t get_default_voff(const struct sr_dev_inst *sdi, int ch_index) { uint16_t voff = 0; - if (strcmp(sdi->model, "DSCope") == 0) + if (strcmp(sdi->model, "DSCope") == 0) { voff = DSCOPE_DEFAULT_VOFF; - else if (strcmp(sdi->model, "DSCope20") == 0) + } else if (strcmp(sdi->model, "DSCope20") == 0) { if (ch_index == 1) voff = CALI_VOFF_RANGE - DSCOPE20_DEFAULT_VOFF; else voff = DSCOPE20_DEFAULT_VOFF; + } return voff; } -static uint64_t get_default_vgain(struct sr_dev_inst *sdi, int num) +static uint64_t get_default_vgain(const struct sr_dev_inst *sdi, unsigned int num) { uint64_t vgain = 0; if (strcmp(sdi->model, "DSCope") == 0) { @@ -711,10 +803,10 @@ static uint64_t get_default_vgain(struct sr_dev_inst *sdi, int num) return vgain; } -static int probe_init(struct sr_dev_inst *sdi) +static void probe_init(struct sr_dev_inst *sdi) { int i; - GList *l; + GSList *l; for (l = sdi->channels; l; l = l->next) { struct sr_channel *probe = (struct sr_channel *)l->data; if (sdi->mode == DSO) { @@ -749,9 +841,7 @@ static int set_probes(struct sr_dev_inst *sdi, int num_probes) static int adjust_probes(struct sr_dev_inst *sdi, int num_probes) { uint16_t j; - GSList *l; struct sr_channel *probe; - GSList *p; assert(num_probes > 0); @@ -765,7 +855,7 @@ static int adjust_probes(struct sr_dev_inst *sdi, int num_probes) } while(j > num_probes) { - g_slist_delete_link(sdi->channels, g_slist_last(sdi->channels)); + sdi->channels = g_slist_delete_link(sdi->channels, g_slist_last(sdi->channels)); j--; } @@ -898,7 +988,7 @@ static GSList *dev_mode_list(const struct sr_dev_inst *sdi) { (void)sdi; GSList *l = NULL; - int i; + unsigned int i; for(i = 0; i < ARRAY_SIZE(mode_list); i++) { l = g_slist_append(l, &mode_list[i]); @@ -907,7 +997,7 @@ static GSList *dev_mode_list(const struct sr_dev_inst *sdi) return l; } -static uint64_t dso_vga(struct sr_dev_inst *sdi, struct sr_channel* ch) +static uint64_t dso_vga(const struct sr_dev_inst *sdi, const struct sr_channel* ch) { int i; struct DSL_vga *vga_ptr = get_vga_ptr(sdi); @@ -919,7 +1009,7 @@ static uint64_t dso_vga(struct sr_dev_inst *sdi, struct sr_channel* ch) return 0; } -static uint64_t dso_voff(struct sr_dev_inst *sdi, struct sr_channel* ch) +static uint64_t dso_voff(const struct sr_dev_inst *sdi, const struct sr_channel* ch) { int i; struct DSL_vga *vga_ptr = get_vga_ptr(sdi); @@ -930,7 +1020,7 @@ static uint64_t dso_voff(struct sr_dev_inst *sdi, struct sr_channel* ch) return 0; } -static uint64_t dso_vpos(struct sr_dev_inst *sdi, struct sr_channel* ch) +static uint64_t dso_vpos(const struct sr_dev_inst *sdi, const struct sr_channel* ch) { uint64_t vpos; int vpos_coarse, vpos_fine; @@ -961,7 +1051,7 @@ static uint64_t dso_vpos(struct sr_dev_inst *sdi, struct sr_channel* ch) return 0; } -static uint64_t dso_cmd_gen(struct sr_dev_inst *sdi, struct sr_channel* ch, int id) +static uint64_t dso_cmd_gen(const struct sr_dev_inst *sdi, struct sr_channel* ch, int id) { struct DSL_context *devc; uint64_t cmd = 0; @@ -1117,8 +1207,10 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, struct DSL_context *devc; struct sr_usb_dev_inst *usb; char str[128]; - int i; + unsigned int i; struct DSL_vga *vga_ptr; + uint8_t tmp_u8; + int ret; (void)cg; @@ -1297,20 +1389,10 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, return SR_ERR; *data = g_variant_new_uint64(DSCOPE_MAX_DEPTH); break; - case SR_CONF_MAX_LOGIC_SAMPLERATE: + case SR_CONF_HW_DEPTH: if (!sdi) return SR_ERR; - *data = g_variant_new_uint64(DSCOPE_MAX_SAMPLERATE); - break; - case SR_CONF_MAX_LOGIC_SAMPLELIMITS: - if (!sdi) - return SR_ERR; - *data = g_variant_new_uint64(DSCOPE_MAX_DEPTH); - break; - case SR_CONF_RLE_SAMPLELIMITS: - if (!sdi) - return SR_ERR; - *data = g_variant_new_uint64(DSCOPE_MAX_DEPTH); + *data = g_variant_new_uint64(DSCOPE_INSTANT_DEPTH); break; case SR_CONF_VGAIN: if (!sdi || !ch) @@ -1369,6 +1451,16 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, devc = sdi->priv; *data = g_variant_new_byte(devc->dso_bits); break; + case SR_CONF_HW_STATUS: + if (!sdi) + return SR_ERR; + usb = sdi->conn; + ret = command_get_hw_info(usb->devhdl, &tmp_u8); + if (ret == SR_OK) + *data = g_variant_new_byte(tmp_u8); + else + *data = g_variant_new_byte(0); + break; default: return SR_ERR_NA; } @@ -1378,7 +1470,7 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, struct sr_channel *ch, - const struct sr_channel_group *cg ) + struct sr_channel_group *cg ) { struct DSL_context *devc; const char *stropt; @@ -1438,7 +1530,7 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, sr_dbg("%s: Initial setting for DSO mode failed", __func__); devc->cur_samplerate = DSCOPE_MAX_SAMPLERATE / num_probes; devc->limit_samples = DSCOPE_MAX_DEPTH / num_probes; - } else if (sdi->mode == ANALOG){ + } else { num_probes = devc->profile->dev_caps & DEV_CAPS_16BIT ? MAX_ANALOG_PROBES_NUM : 1; } sr_dev_probes_free(sdi); @@ -1603,7 +1695,7 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, * because the samplelimits may changed */ devc->trigger_hpos = devc->trigger_hrate * en_ch_num(sdi) * devc->limit_samples / 200.0; - if ((ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 1, SR_CONF_HORIZ_TRIGGERPOS))) == SR_OK) + if ((ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, NULL, SR_CONF_HORIZ_TRIGGERPOS))) == SR_OK) sr_dbg("%s: setting DSO Horiz Trigger Position to %d", __func__, devc->trigger_hpos); else @@ -1637,8 +1729,8 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, devc->zero_stage = -1; devc->zero_pcnt = 0; devc->zero_comb = -1; - GList *l; - int i; + GSList *l; + unsigned int i; struct DSL_vga *vga_ptr = get_vga_ptr(sdi); for(l = sdi->channels; l; l = l->next) { struct sr_channel *probe = (struct sr_channel *)l->data; @@ -1689,13 +1781,13 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, for (i=0; vga_ptr && (vga_ptr+i)->key; i++){ *(vgain_ptr+i) = ((probe->index == 0) ? (vga_ptr+i)->vgain0 : (vga_ptr+i)->vgain1) >> 8; } - ret = command_wr_reg(usb->devhdl, 0, EEWP_ADDR); + ret = command_wr_reg(usb->devhdl, bmEEWP, EEWP_ADDR); if (ret == SR_OK) ret = command_wr_nvm(usb->devhdl, (unsigned char *)&zero_info, sizeof(struct cmd_zero_info)); if (ret == SR_OK) ret = command_wr_nvm(usb->devhdl, (unsigned char *)&vga_info, sizeof(struct cmd_vga_info)); if (ret == SR_OK) - ret = command_wr_reg(usb->devhdl, 1, EEWP_ADDR); + ret = command_wr_reg(usb->devhdl, bmZERO, EEWP_ADDR); if (ret != SR_OK) sr_err("DSO channel %d Set Zero command failed!", probe->index); @@ -1717,11 +1809,12 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, int i; struct DSL_vga *vga_ptr = get_vga_ptr(sdi); for (i = 0; vga_ptr && (vga_ptr+i)->key; i++) { - if ((vga_ptr+i)->key == ch->vdiv) + if ((vga_ptr+i)->key == ch->vdiv) { if (ch->index == 0) (vga_ptr+i)->vgain0 = vgain; else if (ch->index == 1) (vga_ptr+i)->vgain1 = vgain; + } } ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, ch, SR_CONF_VDIV)); if (ret == SR_OK) @@ -1747,11 +1840,12 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, int i; struct DSL_vga *vga_ptr = get_vga_ptr(sdi); for (i = 0; vga_ptr && (vga_ptr+i)->key; i++) { - if ((vga_ptr+i)->key == ch->vdiv) + if ((vga_ptr+i)->key == ch->vdiv) { if (ch->index == 0) (vga_ptr+i)->voff0 = voff; else if (ch->index == 1) (vga_ptr+i)->voff1 = voff; + } } ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, ch, SR_CONF_VPOS)); if (ret == SR_OK) @@ -1836,7 +1930,7 @@ static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, static int dso_init(const struct sr_dev_inst *sdi) { - int ret, i; + int ret; GSList *l; struct sr_usb_dev_inst *usb = sdi->conn; @@ -1897,16 +1991,16 @@ static int dso_init(const struct sr_dev_inst *sdi) return ret; } -static int dso_zero(struct sr_dev_inst *sdi, struct sr_status mstatus) +static int dso_zero(const struct sr_dev_inst *sdi, struct sr_status mstatus) { struct DSL_context *devc = sdi->priv; struct sr_usb_dev_inst *usb = sdi->conn; GSList *l; - int ret, i; + int ret; static double vpos_back[2]; static uint64_t vdiv_back[2]; struct DSL_vga *vga_ptr = get_vga_ptr(sdi); - struct sr_channel *probe0, *probe1; + struct sr_channel *probe0 = NULL, *probe1 = NULL; for(l = sdi->channels; l; l = l->next) { struct sr_channel *probe = (struct sr_channel *)l->data; if (probe->index == 0) @@ -1916,7 +2010,7 @@ static int dso_zero(struct sr_dev_inst *sdi, struct sr_status mstatus) } if (devc->zero_stage == -1) { - // initialize before zero adjustment + // initialize before Auto Calibration if (dso_init(sdi) == SR_OK) devc->zero_stage = 0; } else if ((vga_ptr+devc->zero_stage)->key == 0) { @@ -2059,10 +2153,10 @@ static int dev_open(struct sr_dev_inst *sdi) struct sr_usb_dev_inst *usb; struct DSL_context *devc; int ret; - int64_t timediff_us, timediff_ms; - uint8_t fpga_done; + uint8_t hw_info; GSList *l; gboolean zeroed; + gboolean fpga_done; devc = sdi->priv; usb = sdi->conn; @@ -2103,13 +2197,14 @@ static int dev_open(struct sr_dev_inst *sdi) return SR_ERR; } - ret = command_get_fpga_done(usb->devhdl, &fpga_done); + ret = command_get_hw_info(usb->devhdl, &hw_info); if (ret != SR_OK) { - sr_err("Failed to get fpga done infos."); + sr_err("Failed to get hardware infos."); return SR_ERR; } + fpga_done = (hw_info & 0x80) != 0; - if (fpga_done == 0) { + if (sdi->status == SR_ST_ACTIVE && !fpga_done) { if ((ret = command_fpga_config(usb->devhdl)) != SR_OK) { sr_err("%s: Send FPGA configure command failed!", __func__); } else { @@ -2140,7 +2235,7 @@ static int dev_open(struct sr_dev_inst *sdi) config_set(SR_CONF_ZERO, g_variant_new_boolean(TRUE), sdi, NULL, NULL); sr_info("Zero have not been setted!"); } - if (fpga_done == 0) + if (!fpga_done) dso_init(sdi); } @@ -2198,6 +2293,7 @@ static void finish_acquisition(struct DSL_context *devc) sr_err("%s: send SR_DF_END packet", __func__); /* Terminate session. */ packet.type = SR_DF_END; + packet.status = SR_PKT_OK; sr_session_send(devc->cb_data, &packet); if (devc->num_transfers != 0) { @@ -2244,37 +2340,19 @@ static void resubmit_transfer(struct libusb_transfer *transfer) sr_err("%s: %s", __func__, libusb_error_name(ret)); } -static struct sr_config * new_config(int key, GVariant *data) -{ - struct sr_config *config; - - if (!(config = g_try_malloc0(sizeof(struct sr_config)))) { - sr_err("META config malloc failed."); - return NULL; - } - - config->key = key; - config->data = data; - - return config; -} - static void receive_transfer(struct libusb_transfer *transfer) { - gboolean packet_has_error = FALSE; struct sr_datafeed_packet packet; struct sr_datafeed_logic logic; struct sr_datafeed_dso dso; struct sr_datafeed_analog analog; - int trigger_offset, i; - int trigger_offset_bytes; - - const uint8_t *cur_buf = transfer->buffer; + uint8_t *cur_buf = transfer->buffer; struct DSL_context *devc = transfer->user_data; struct sr_dev_inst *sdi = devc->cb_data; const int sample_width = 2; int cur_sample_count = transfer->actual_length / sample_width; + unsigned int i; if (devc->data_lock) { resubmit_transfer(transfer); @@ -2288,97 +2366,24 @@ static void receive_transfer(struct libusb_transfer *transfer) transfer->status, transfer->timeout, transfer->actual_length); switch (transfer->status) { - case LIBUSB_TRANSFER_NO_DEVICE: - case LIBUSB_TRANSFER_CANCELLED: - devc->status = DSL_ERROR; - break; case LIBUSB_TRANSFER_COMPLETED: case LIBUSB_TRANSFER_TIMED_OUT: /* We may have received some data though. */ break; default: - packet_has_error = TRUE; + devc->status = DSL_ERROR; break; } + packet.status = SR_PKT_OK; if (devc->status == DSL_DATA && - (transfer->actual_length == 0 || - packet_has_error)) { - devc->empty_transfer_count++; - if (devc->empty_transfer_count > MAX_EMPTY_TRANSFERS) { - devc->status = DSL_ERROR; - } - } else { - devc->empty_transfer_count = 0; - } - - trigger_offset = 0; - if (devc->status == DSL_DATA && devc->trigger_stage >= 0) { - for (i = 0; i < cur_sample_count; i++) { - const uint16_t cur_sample = devc->sample_wide ? - *((const uint16_t*)cur_buf + i) : - *((const uint8_t*)cur_buf + i); - - if ((cur_sample & devc->trigger_mask[devc->trigger_stage]) == - devc->trigger_value[devc->trigger_stage]) { - /* Match on this trigger stage. */ - devc->trigger_buffer[devc->trigger_stage] = cur_sample; - devc->trigger_stage++; - - if (devc->trigger_stage == NUM_TRIGGER_STAGES || - devc->trigger_mask[devc->trigger_stage] == 0) { - /* Match on all trigger stages, we're done. */ - trigger_offset = i + 1; - - /* - * TODO: Send pre-trigger buffer to session bus. - * Tell the frontend we hit the trigger here. - */ - packet.type = SR_DF_TRIGGER; - packet.payload = NULL; - sr_session_send(sdi, &packet); - - /* - * Send the samples that triggered it, - * since we're skipping past them. - */ - packet.type = SR_DF_LOGIC; - packet.payload = &logic; - logic.unitsize = sizeof(*devc->trigger_buffer); - logic.length = devc->trigger_stage * logic.unitsize; - logic.data = devc->trigger_buffer; - sr_session_send(sdi, &packet); - - devc->trigger_stage = TRIGGER_FIRED; - break; - } - } else if (devc->trigger_stage > 0) { - /* - * We had a match before, but not in the next sample. However, we may - * have a match on this stage in the next bit -- trigger on 0001 will - * fail on seeing 00001, so we need to go back to stage 0 -- but at - * the next sample from the one that matched originally, which the - * counter increment at the end of the loop takes care of. - */ - i -= devc->trigger_stage; - if (i < -1) - i = -1; /* Oops, went back past this buffer. */ - /* Reset trigger stage. */ - devc->trigger_stage = 0; - } - } - } - - if (devc->status == DSL_DATA && devc->trigger_stage == TRIGGER_FIRED) { - /* Send the incoming transfer to the session bus. */ - trigger_offset_bytes = trigger_offset * sample_width; + transfer->actual_length != 0) { // check packet type if (sdi->mode == LOGIC) { packet.type = SR_DF_LOGIC; packet.payload = &logic; - logic.length = transfer->actual_length - trigger_offset_bytes; - logic.unitsize = sample_width; + logic.length = transfer->actual_length; logic.data_error = 0; - logic.data = cur_buf + trigger_offset_bytes; + logic.data = cur_buf; } else if (sdi->mode == DSO) { if (!devc->instant) { const uint32_t mstatus_offset = devc->limit_samples / (g_slist_length(sdi->channels)/en_ch_num(sdi)); @@ -2409,7 +2414,7 @@ static void receive_transfer(struct libusb_transfer *transfer) mstatus.vlen <= (transfer->actual_length - 512) / sample_width) || devc->instant) { devc->roll = (mstatus.stream_mode != 0); - devc->mstatus_valid = TRUE; + devc->mstatus_valid = devc->instant ? FALSE : TRUE; packet.type = SR_DF_DSO; packet.payload = &dso; dso.probes = sdi->channels; @@ -2421,9 +2426,10 @@ static void receive_transfer(struct libusb_transfer *transfer) dso.mqflags = SR_MQFLAG_AC; dso.samplerate_tog = (mstatus.sample_divider_tog != 0); dso.trig_flag = (mstatus.trig_flag != 0); - dso.data = cur_buf + trigger_offset_bytes; + dso.data = cur_buf; } else { - packet.type = SR_DF_ABANDON; + packet.type = SR_DF_DSO; + packet.status = SR_PKT_DATA_ERROR; devc->mstatus_valid = FALSE; } } else { @@ -2434,7 +2440,7 @@ static void receive_transfer(struct libusb_transfer *transfer) analog.mq = SR_MQ_VOLTAGE; analog.unit = SR_UNIT_VOLT; analog.mqflags = SR_MQFLAG_AC; - analog.data = cur_buf + trigger_offset_bytes; + analog.data = (float *)cur_buf; } if (devc->limit_samples) { @@ -2479,14 +2485,14 @@ static void receive_transfer(struct libusb_transfer *transfer) } /* send data to session bus */ - if (packet.type != SR_DF_ABANDON) + if (packet.status != SR_PKT_DATA_ERROR) sr_session_send(sdi, &packet); } devc->num_samples += cur_sample_count; if ((sdi->mode == LOGIC || devc->instant) && devc->limit_samples && - (unsigned int)devc->num_samples >= devc->limit_samples) { + devc->num_samples >= devc->limit_samples) { devc->status = DSL_STOP; } } @@ -2551,7 +2557,7 @@ static int dev_transfer_start(const struct sr_dev_inst *sdi) struct DSL_context *devc; struct sr_usb_dev_inst *usb; struct libusb_transfer *transfer; - unsigned int i, timeout, num_transfers; + unsigned int i, num_transfers; int ret; unsigned char *buf; size_t size; @@ -2560,10 +2566,6 @@ static int dev_transfer_start(const struct sr_dev_inst *sdi) devc = sdi->priv; usb = sdi->conn; -// timeout = get_timeout(devc); -// num_transfers = get_number_of_transfers(devc); -// size = get_buffer_size(devc); - timeout = 500; #ifndef _WIN32 num_transfers = 1; #else @@ -2619,7 +2621,6 @@ static int receive_data(int fd, int revents, const struct sr_dev_inst *sdi) struct drv_context *drvc; struct DSL_context *devc; struct sr_usb_dev_inst *usb; - int i; int ret; (void)fd; @@ -2663,6 +2664,7 @@ static void receive_trigger_pos(struct libusb_transfer *transfer) const struct sr_dev_inst *sdi; int ret; + packet.status = SR_PKT_OK; devc = transfer->user_data; sdi = devc->cb_data; trigger_pos = (struct ds_trigger_pos *)transfer->buffer; @@ -2698,8 +2700,10 @@ static void receive_trigger_pos(struct libusb_transfer *transfer) } } -static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) +static int dev_acquisition_start(struct sr_dev_inst *sdi, void *cb_data) { + (void)cb_data; + struct DSL_context *devc; struct drv_context *drvc; struct sr_usb_dev_inst *usb; @@ -2753,7 +2757,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) } if (devc->zero && devc->zero_stage == -1) { - // initialize before zero adjustment + // initialize before Auto Calibration if ((ret = dso_init(sdi)) == SR_OK) { devc->zero_stage = 0; } else { @@ -2768,7 +2772,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) */ if (sdi->mode == DSO) { devc->trigger_hpos = devc->trigger_hrate * en_ch_num(sdi) * devc->limit_samples / 200.0; - if ((ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 1, SR_CONF_HORIZ_TRIGGERPOS))) == SR_OK) + if ((ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, NULL, SR_CONF_HORIZ_TRIGGERPOS))) == SR_OK) sr_dbg("%s: setting DSO Horiz Trigger Position to %d", __func__, devc->trigger_hpos); else @@ -2788,7 +2792,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) } transfer = libusb_alloc_transfer(0); libusb_fill_bulk_transfer(transfer, usb->devhdl, - 6 | LIBUSB_ENDPOINT_IN, trigger_pos, sizeof(struct ds_trigger_pos), + 6 | LIBUSB_ENDPOINT_IN, (unsigned char*)trigger_pos, sizeof(struct ds_trigger_pos), receive_trigger_pos, devc, 0); if ((ret = libusb_submit_transfer(transfer)) != 0) { sr_err("%s: Failed to submit trigger_pos transfer: %s.", @@ -2831,47 +2835,25 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) return SR_OK; } -static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) +static int dev_acquisition_stop(const struct sr_dev_inst *sdi, void *cb_data) { (void)cb_data; - struct drv_context *drvc; struct DSL_context *devc; struct sr_usb_dev_inst *usb; - drvc = di->priv; devc = sdi->priv; usb = sdi->conn; if (!devc->abort) { devc->abort = TRUE; - command_wr_reg(usb->devhdl, 3, EEWP_ADDR); + command_wr_reg(usb->devhdl, bmFORCE_RDY, EEWP_ADDR); } return SR_OK; } -static int dev_test(struct sr_dev_inst *sdi) -{ - if (sdi) { - struct sr_usb_dev_inst *usb; - struct version_info vi; - int ret; - - usb = sdi->conn; - ret = command_get_fw_version(usb->devhdl, &vi); - if (ret != SR_OK) { - sr_err("Device don't exist!"); - return SR_ERR; - } else { - return SR_OK; - } - } else { - return SR_ERR; - } -} - -static int dev_status_get(struct sr_dev_inst *sdi, struct sr_status *status, int begin, int end) +static int dev_status_get(const struct sr_dev_inst *sdi, struct sr_status *status, int begin, int end) { int ret = SR_ERR; if (sdi) { @@ -2906,7 +2888,6 @@ SR_PRIV struct sr_dev_driver DSCope_driver_info = { .config_list = config_list, .dev_open = dev_open, .dev_close = dev_close, - .dev_test = dev_test, .dev_status_get = dev_status_get, .dev_acquisition_start = dev_acquisition_start, .dev_acquisition_stop = dev_acquisition_stop, diff --git a/libsigrok4DSL/hardware/DSL/dsl.h b/libsigrok4DSL/hardware/DSL/dsl.h index 4916367f..85fce25c 100644 --- a/libsigrok4DSL/hardware/DSL/dsl.h +++ b/libsigrok4DSL/hardware/DSL/dsl.h @@ -44,6 +44,7 @@ #define MAX_EMPTY_TRANSFERS (NUM_SIMUL_TRANSFERS * 2) #define DSL_REQUIRED_VERSION_MAJOR 1 +#define DSL_REQUIRED_VERSION_MINOR 1 #define MAX_8BIT_SAMPLE_RATE DS_MHZ(24) #define MAX_16BIT_SAMPLE_RATE DS_MHZ(12) @@ -51,9 +52,6 @@ /* 6 delay states of up to 256 clock ticks */ #define MAX_SAMPLE_DELAY (6 * 256) -/* Software trigger implementation: positive values indicate trigger stage. */ -#define TRIGGER_FIRED -1 - #define DEV_CAPS_16BIT_POS 0 #define DEV_CAPS_16BIT (1 << DEV_CAPS_16BIT_POS) @@ -67,6 +65,11 @@ #define VPOS_MINISTEP 0.083 #define VPOS_STEP 26.0 +#define DSLOGIC_ATOMIC_BITS 6 +#define DSLOGIC_ATOMIC_SAMPLES (1 << DSLOGIC_ATOMIC_BITS) +#define DSLOGIC_ATOMIC_SIZE (1 << (DSLOGIC_ATOMIC_BITS - 3)) +#define DSLOGIC_ATOMIC_MASK (0xFFFF << DSLOGIC_ATOMIC_BITS) + #define DSLOGIC_MAX_DSO_DEPTH SR_MB(2) //#define DSLOGIC_MAX_DSO_DEPTH SR_KB(2) #define DSLOGIC_MAX_DSO_SAMPLERATE SR_MHZ(200) @@ -78,6 +81,40 @@ #define DSCOPE_MAX_SAMPLERATE SR_MHZ(200) #define DSCOPE_INSTANT_DEPTH SR_MB(32) +/* + * for basic configuration + */ +#define TRIG_EN_BIT 0 +#define CLK_TYPE_BIT 1 +#define CLK_EDGE_BIT 2 +#define RLE_MODE_BIT 3 +#define DSO_MODE_BIT 4 +#define HALF_MODE_BIT 5 +#define QUAR_MODE_BIT 6 +#define ANALOG_MODE_BIT 7 +#define FILTER_BIT 8 +#define INSTANT_BIT 9 +#define STRIG_MODE_BIT 11 +#define STREAM_MODE_BIT 12 +#define LPB_TEST_BIT 13 +#define EXT_TEST_BIT 14 +#define INT_TEST_BIT 15 + +#define bmZERO 0x00 +#define bmEEWP 0x01 +#define bmFORCE_RDY 0x02 +#define bmFORCE_STOP 0x04 +#define bmSCOPE_SET 0x08 +#define bmSCOPE_CLR 0x08 + +/* + * for DSLogic device + * + */ +#define MAX_LOGIC_PROBES 16 +#define DSLOGIC_BASIC_MEM_DEPTH SR_KB(256) +#define DSLOGIC_MEM_DEPTH SR_MB(256) + /* * for DSCope device * trans: x << 8 + y @@ -123,7 +160,7 @@ #define DSO_AUTOTRIG_THRESHOLD 16 -#define TRIG_CHECKID 0xa500005a +#define TRIG_CHECKID 0x55555555 #define DSO_PKTID 0xa500 struct DSL_profile { @@ -142,7 +179,7 @@ struct DSL_profile { uint32_t dev_caps; }; -static const struct DSL_profile supported_DSLogic[3] = { +static const struct DSL_profile supported_DSLogic[] = { /* * DSLogic */ @@ -158,10 +195,29 @@ static const struct DSL_profile supported_DSLogic[3] = { "DSLogicPro.bin", DEV_CAPS_16BIT}, + {0x2A0E, 0x0005, NULL, "DSMso", NULL, + "DSMso.fw", + "DSMso.bin", + "DSMso.bin", + DEV_CAPS_16BIT}, + + {0x2A0E, 0x0020, NULL, "DSLogic PLus", NULL, + "DSLogicPlus.fw", + "DSLogicPlus.bin", + "DSLogicPlus.bin", + DEV_CAPS_16BIT}, + + {0x2A0E, 0x0021, NULL, "DSLogic Basic", NULL, + "DSLogicBasic.fw", + "DSLogicBasic.bin", + "DSLogicBasic.bin", + DEV_CAPS_16BIT}, + + { 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; -static const struct DSL_profile supported_DSCope[3] = { +static const struct DSL_profile supported_DSCope[] = { /* * DSCope */ @@ -180,7 +236,7 @@ static const struct DSL_profile supported_DSCope[3] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; -static const gboolean default_ms_en[DSO_MS_END - DSO_MS_BEGIN] = { +static const gboolean default_ms_en[] = { FALSE, /* DSO_MS_BEGIN */ TRUE, /* DSO_MS_FREQ */ FALSE, /* DSO_MS_PERD */ @@ -189,7 +245,6 @@ static const gboolean default_ms_en[DSO_MS_END - DSO_MS_BEGIN] = { FALSE, /* DSO_MS_VRMS */ FALSE, /* DSO_MS_VMEA */ FALSE, /* DSO_MS_VP2P */ - FALSE, /* DSO_MS_END */ }; enum { @@ -200,7 +255,8 @@ enum { DSL_TRIGGERED = 3, DSL_DATA = 4, DSL_STOP = 5, - DSL_FINISH = 6, + DSL_FINISH = 7, + DSL_ABORT = 8, }; struct DSL_context { @@ -217,6 +273,7 @@ struct DSL_context { uint64_t cur_samplerate; uint64_t limit_samples; uint64_t actual_samples; + uint64_t actual_bytes; /* Operational settings */ gboolean sample_wide; @@ -225,6 +282,7 @@ struct DSL_context { gboolean rle_mode; gboolean instant; uint16_t op_mode; + uint16_t buf_options; uint16_t ch_mode; uint16_t samplerates_size; uint16_t samplecounts_size; @@ -254,7 +312,8 @@ struct DSL_context { gboolean data_lock; uint8_t dso_bits; - int num_samples; + uint64_t num_samples; + uint64_t num_bytes; int submitted_transfers; int empty_transfer_count; @@ -269,69 +328,47 @@ struct DSL_context { int status; gboolean mstatus_valid; gboolean abort; + gboolean overflow; }; +/* + * hardware setting for each capture + */ struct DSL_setting { uint32_t sync; + uint16_t mode_header; // 0 uint16_t mode; - uint32_t divider_header; // 1-2 - uint32_t divider; - uint32_t count_header; // 3-4 - uint32_t count; - uint32_t trig_pos_header; // 5-6 - uint32_t trig_pos; + uint16_t divider_header; // 1-2 + uint16_t div_l; + uint16_t div_h; + uint16_t count_header; // 3-4 + uint16_t cnt_l; + uint16_t cnt_h; + uint16_t trig_pos_header; // 5-6 + uint16_t tpos_l; + uint16_t tpos_h; uint16_t trig_glb_header; // 7 uint16_t trig_glb; - uint32_t trig_adp_header; // 10-11 - uint32_t trig_adp; - uint32_t trig_sda_header; // 12-13 - uint32_t trig_sda; - uint32_t trig_mask0_header; // 16 + uint16_t ch_en_header; // 8 + uint16_t ch_en; + + uint16_t trig_header; // 64 uint16_t trig_mask0[NUM_TRIGGER_STAGES]; - uint32_t trig_mask1_header; // 17 uint16_t trig_mask1[NUM_TRIGGER_STAGES]; - //uint32_t trig_mask2_header; // 18 - //uint16_t trig_mask2[NUM_TRIGGER_STAGES]; - //uint32_t trig_mask3_header; // 19 - //uint16_t trig_mask3[NUM_TRIGGER_STAGES]; - uint32_t trig_value0_header; // 20 uint16_t trig_value0[NUM_TRIGGER_STAGES]; - uint32_t trig_value1_header; // 21 uint16_t trig_value1[NUM_TRIGGER_STAGES]; - //uint32_t trig_value2_header; // 22 - //uint16_t trig_value2[NUM_TRIGGER_STAGES]; - //uint32_t trig_value3_header; // 23 - //uint16_t trig_value3[NUM_TRIGGER_STAGES]; - uint32_t trig_edge0_header; // 24 uint16_t trig_edge0[NUM_TRIGGER_STAGES]; - uint32_t trig_edge1_header; // 25 uint16_t trig_edge1[NUM_TRIGGER_STAGES]; - //uint32_t trig_edge2_header; // 26 - //uint16_t trig_edge2[NUM_TRIGGER_STAGES]; - //uint32_t trig_edge3_header; // 27 - //uint16_t trig_edge3[NUM_TRIGGER_STAGES]; - uint32_t trig_count0_header; // 28 - uint32_t trig_count0[NUM_TRIGGER_STAGES]; - uint32_t trig_count1_header; // 29 - uint32_t trig_count1[NUM_TRIGGER_STAGES]; - //uint32_t trig_count2_header; // 30 - //uint16_t trig_count2[NUM_TRIGGER_STAGES]; - //uint32_t trig_count3_header; // 31 - //uint16_t trig_count3[NUM_TRIGGER_STAGES]; - uint32_t trig_logic0_header; // 32 uint16_t trig_logic0[NUM_TRIGGER_STAGES]; - uint32_t trig_logic1_header; // 33 uint16_t trig_logic1[NUM_TRIGGER_STAGES]; - //uint32_t trig_logic2_header; // 34 - //uint16_t trig_logic2[NUM_TRIGGER_STAGES]; - //uint32_t trig_logic3_header; // 35 - //uint16_t trig_logic3[NUM_TRIGGER_STAGES]; + uint32_t trig_count[NUM_TRIGGER_STAGES]; + uint32_t end_sync; }; struct DSL_vga { - int key; + uint64_t key; uint64_t vgain0; uint64_t vgain1; uint16_t voff0; diff --git a/libsigrok4DSL/hardware/DSL/dslogic.c b/libsigrok4DSL/hardware/DSL/dslogic.c index d314492a..8221f663 100644 --- a/libsigrok4DSL/hardware/DSL/dslogic.c +++ b/libsigrok4DSL/hardware/DSL/dslogic.c @@ -33,13 +33,14 @@ #undef min #define min(a,b) ((a)<(b)?(a):(b)) +#undef max +#define max(a,b) ((a)>(b)?(a):(b)) -static const int single_buffer_time = 20; -static const int total_buffer_time = 200; -static const int buffer_size = 1024 * 1024; -static const int instant_buffer_size = 1024 * 1024; -static const int cons_buffer_size = 128; -static const int buffer_cnt = 4; +static const unsigned int single_buffer_time = 20; +static const unsigned int total_buffer_time = 200; +static const unsigned int instant_buffer_size = 1024 * 1024; +static const unsigned int cons_buffer_size = 128; +static const unsigned int buffer_cnt = 4; static struct sr_dev_mode mode_list[] = { {"LA", LOGIC}, @@ -59,16 +60,23 @@ static const char *opmodes[] = { "DRAM Loopback Test", }; -static uint16_t opmodes_show_count = 3; +static const char *bufoptions[] = { + "Stop immediately", + "Upload captured data", +}; static const char *stream_ch_modes[] = { - "Use Channels 0~15 (Max 10MHz)", - "Use Channels 0~7 (Max 25MHz)", + "Use 16 Channels (Max 20MHz)", + "Use 12 Channels (Max 25MHz)", + "Use 6 Channels (Max 50MHz)", + "Use 3 Channels (Max 100MHz)", }; static const uint16_t stream_ch_num[] = { 16, - 8, + 12, + 6, + 3, }; static const char *buffer_ch_modes[] = { @@ -78,9 +86,9 @@ static const char *buffer_ch_modes[] = { }; static const uint16_t buffer_ch_num[] = { - 16, - 8, - 4, + MAX_LOGIC_PROBES, + MAX_LOGIC_PROBES / 2, + MAX_LOGIC_PROBES / 4, }; static const char *thresholds[] = { @@ -117,6 +125,7 @@ static const int32_t hwcaps[] = { static const int32_t hwoptions[] = { SR_CONF_OPERATION_MODE, + SR_CONF_BUFFER_OPTIONS, SR_CONF_THRESHOLD, SR_CONF_FILTER, SR_CONF_MAX_HEIGHT, @@ -126,6 +135,7 @@ static const int32_t hwoptions[] = { static const int32_t hwoptions_pro[] = { SR_CONF_OPERATION_MODE, + SR_CONF_BUFFER_OPTIONS, SR_CONF_VTH, SR_CONF_FILTER, SR_CONF_MAX_HEIGHT, @@ -134,7 +144,9 @@ static const int32_t hwoptions_pro[] = { }; static const int32_t sessions[] = { + SR_CONF_MAX_HEIGHT, SR_CONF_OPERATION_MODE, + SR_CONF_BUFFER_OPTIONS, SR_CONF_CHANNEL_MODE, SR_CONF_SAMPLERATE, SR_CONF_LIMIT_SAMPLES, @@ -150,7 +162,9 @@ static const int32_t sessions[] = { }; static const int32_t sessions_pro[] = { + SR_CONF_MAX_HEIGHT, SR_CONF_OPERATION_MODE, + SR_CONF_BUFFER_OPTIONS, SR_CONF_CHANNEL_MODE, SR_CONF_SAMPLERATE, SR_CONF_LIMIT_SAMPLES, @@ -236,8 +250,14 @@ static const uint64_t samplecounts[] = { SR_MB(128), SR_MB(256), SR_MB(512), + SR_GB(1), + SR_GB(2), + SR_GB(4), + SR_GB(8), + SR_GB(16), }; +static uint16_t opmodes_show_count = 3; static const uint8_t zero_base_addr = 0x80; SR_PRIV struct sr_dev_driver DSLogic_driver_info; @@ -305,6 +325,32 @@ static int en_ch_num(const struct sr_dev_inst *sdi) return channel_en_cnt; } +static int counts_size(const struct sr_dev_inst *sdi) +{ + struct DSL_context *devc = sdi->priv; + if (strcmp(sdi->model, "DSLogic Basic") == 0) + if (sdi->mode == ANALOG) + return 5; + else if (!devc || devc->op_mode == SR_OP_STREAM) + return ARRAY_SIZE(samplecounts); + else + return 15; + else + if (sdi->mode == ANALOG) + return 15; + else + return ARRAY_SIZE(samplecounts); +} + +static uint64_t channel_depth(const struct sr_dev_inst *sdi) +{ + int ch_num = en_ch_num(sdi); + if (strcmp(sdi->model, "DSLogic Basic") == 0) + return DSLOGIC_BASIC_MEM_DEPTH / (ch_num ? ch_num : 1); + else + return DSLOGIC_MEM_DEPTH / (ch_num ? ch_num : 1); +} + static int fpga_setting(const struct sr_dev_inst *sdi) { struct DSL_context *devc; @@ -315,9 +361,10 @@ static int fpga_setting(const struct sr_dev_inst *sdi) int transferred; int result; int i; - int channel_en_cnt = 0; - int channel_cnt = 0; GSList *l; + uint32_t tmp_u32; + uint64_t tmp_u64; + const int ch_num = en_ch_num(sdi); devc = sdi->priv; usb = sdi->conn; @@ -325,66 +372,68 @@ static int fpga_setting(const struct sr_dev_inst *sdi) setting.sync = 0xf5a5f5a5; setting.mode_header = 0x0001; - setting.divider_header = 0x0102ffff; - setting.count_header = 0x0302ffff; - setting.trig_pos_header = 0x0502ffff; + setting.divider_header = 0x0102; + setting.count_header = 0x0302; + setting.trig_pos_header = 0x0502; setting.trig_glb_header = 0x0701; - setting.trig_adp_header = 0x0a02ffff; - setting.trig_sda_header = 0x0c02ffff; - setting.trig_mask0_header = 0x1010ffff; - setting.trig_mask1_header = 0x1110ffff; - //setting.trig_mask2_header = 0x1210ffff; - //setting.trig_mask3_header = 0x1310ffff; - setting.trig_value0_header = 0x1410ffff; - setting.trig_value1_header = 0x1510ffff; - //setting.trig_value2_header = 0x1610ffff; - //setting.trig_value3_header = 0x1710ffff; - setting.trig_edge0_header = 0x1810ffff; - setting.trig_edge1_header = 0x1910ffff; - //setting.trig_edge2_header = 0x1a10ffff; - //setting.trig_edge3_header = 0x1b10ffff; - setting.trig_count0_header = 0x1c20ffff; - setting.trig_count1_header = 0x1d20ffff; - //setting.trig_count2_header = 0x1e10ffff; - //setting.trig_count3_header = 0x1f10ffff; - setting.trig_logic0_header = 0x2010ffff; - setting.trig_logic1_header = 0x2110ffff; - //setting.trig_logic2_header = 0x2210ffff; - //setting.trig_logic3_header = 0x2310ffff; + setting.ch_en_header = 0x0801; + setting.trig_header = 0x40a0; setting.end_sync = 0xfa5afa5a; - devc->rle_mode = FALSE; - if (sdi->mode == LOGIC && - !devc->stream && - devc->limit_samples > DSLOGIC_MAX_LOGIC_DEPTH*ceil(devc->cur_samplerate * 1.0 / DSLOGIC_MAX_LOGIC_SAMPLERATE)) - devc->rle_mode = TRUE; + // basic configuration + setting.mode = (trigger->trigger_en << TRIG_EN_BIT) + + (devc->clock_type << CLK_TYPE_BIT) + + (devc->clock_edge << CLK_EDGE_BIT) + + (devc->rle_mode << RLE_MODE_BIT) + + ((sdi->mode == DSO) << DSO_MODE_BIT) + + ((((devc->cur_samplerate == (2 * DSLOGIC_MAX_LOGIC_SAMPLERATE)) && sdi->mode != DSO) || (sdi->mode == ANALOG)) << HALF_MODE_BIT) + + ((devc->cur_samplerate == (4 * DSLOGIC_MAX_LOGIC_SAMPLERATE)) << QUAR_MODE_BIT) + + ((sdi->mode == ANALOG) << ANALOG_MODE_BIT) + + ((devc->filter == SR_FILTER_1T) << FILTER_BIT) + + (devc->instant << INSTANT_BIT) + + ((trigger->trigger_mode == SERIAL_TRIGGER) << STRIG_MODE_BIT) + + ((devc->stream) << STREAM_MODE_BIT) + + ((devc->op_mode == SR_OP_LOOPBACK_TEST) << LPB_TEST_BIT) + + ((devc->op_mode == SR_OP_EXTERNAL_TEST) << EXT_TEST_BIT) + + ((devc->op_mode == SR_OP_INTERNAL_TEST) << INT_TEST_BIT); - //setting.mode = (test_mode ? 0x8000 : 0x0000) + trigger->trigger_en + (sdi->mode << 4); - setting.mode = ((devc->op_mode == SR_OP_INTERNAL_TEST) << 15) + - ((devc->op_mode == SR_OP_EXTERNAL_TEST) << 14) + - ((devc->op_mode == SR_OP_LOOPBACK_TEST) << 13) + - ((devc->stream) << 12) + - ((trigger->trigger_mode == SERIAL_TRIGGER) << 11) + - trigger->trigger_en + - ((sdi->mode == DSO) << 4) + (devc->clock_type << 1) + (devc->clock_edge << 2) + - (devc->rle_mode << 3) + - ((((devc->cur_samplerate == (2 * DSLOGIC_MAX_LOGIC_SAMPLERATE)) && sdi->mode != DSO) || (sdi->mode == ANALOG)) << 5) + - ((devc->cur_samplerate == (4 * DSLOGIC_MAX_LOGIC_SAMPLERATE)) << 6) + - ((sdi->mode == ANALOG) << 7) + - ((devc->filter == SR_FILTER_1T) << 8) + - (devc->instant << 9); - - setting.divider = (sdi->mode == DSO) ? (uint32_t)ceil(DSLOGIC_MAX_DSO_SAMPLERATE * 1.0 / devc->cur_samplerate / en_ch_num(sdi)) : - (uint32_t)ceil(DSLOGIC_MAX_LOGIC_SAMPLERATE * 1.0 / devc->cur_samplerate); + // sample rate divider + tmp_u32 = (sdi->mode == DSO) ? (uint32_t)ceil(DSLOGIC_MAX_DSO_SAMPLERATE * 1.0 / devc->cur_samplerate / ch_num) : + (uint32_t)ceil(DSLOGIC_MAX_LOGIC_SAMPLERATE * 1.0 / devc->cur_samplerate); + setting.div_l = tmp_u32 & 0x0000ffff; + setting.div_h = tmp_u32 >> 16; + // capture counter // analog: 16bits, but sample with half mode(0-7 valid only) - setting.count = (sdi->mode == DSO) ? (uint32_t)(devc->limit_samples / (g_slist_length(sdi->channels) / en_ch_num(sdi))) : - (sdi->mode == ANALOG) ? (uint32_t)(devc->limit_samples * g_slist_length(sdi->channels) * 4) : - (uint32_t)(devc->limit_samples); - setting.trig_pos = (uint32_t)(trigger->trigger_pos / 100.0 * devc->limit_samples); - setting.trig_glb = trigger->trigger_stages; - setting.trig_adp = setting.count - setting.trig_pos - 1; - setting.trig_sda = 0x0; + tmp_u64 = (sdi->mode == DSO) ? (devc->limit_samples / (g_slist_length(sdi->channels) / ch_num)) : + (sdi->mode == ANALOG) ? (devc->limit_samples * g_slist_length(sdi->channels) * 4) : + (devc->limit_samples); + tmp_u64 >>= 4; // hardware minimum unit 64 + setting.cnt_l = tmp_u64 & 0x0000ffff; + setting.cnt_h = tmp_u64 >> 16; + + // trigger position + // must be align to minimum parallel bits + tmp_u32 = max((uint32_t)(trigger->trigger_pos / 100.0 * devc->limit_samples), DSLOGIC_ATOMIC_SAMPLES); + if (devc->stream) + tmp_u32 = min(tmp_u32, channel_depth(sdi) * 10 / 100); + else + tmp_u32 = min(tmp_u32, channel_depth(sdi) * DS_MAX_TRIG_PERCENT / 100); + setting.tpos_l = tmp_u32 & DSLOGIC_ATOMIC_MASK; + setting.tpos_h = tmp_u32 >> 16; + + // trigger global settings + setting.trig_glb = ((ch_num & 0xf) << 4) + + trigger->trigger_stages; + + // channel enable mapping + setting.ch_en = 0; + for (l = sdi->channels; l; l = l->next) { + struct sr_channel *probe = (struct sr_channel *)l->data; + setting.ch_en += probe->enabled << probe->index; + } + + // trigger advanced configuration if (trigger->trigger_mode == SIMPLE_TRIGGER) { setting.trig_mask0[0] = ds_trigger_get_mask0(TriggerStages); setting.trig_mask1[0] = ds_trigger_get_mask1(TriggerStages); @@ -395,12 +444,51 @@ static int fpga_setting(const struct sr_dev_inst *sdi) setting.trig_edge0[0] = ds_trigger_get_edge0(TriggerStages); setting.trig_edge1[0] = ds_trigger_get_edge1(TriggerStages); - setting.trig_count0[0] = trigger->trigger0_count[TriggerStages]; - setting.trig_count1[0] = trigger->trigger1_count[TriggerStages]; + if (setting.mode & (1 << QUAR_MODE_BIT)) { + setting.trig_mask0[0] = ((setting.trig_mask0[0] & 0x0f) << 12) + + ((setting.trig_mask0[0] & 0x0f) << 8) + + ((setting.trig_mask0[0] & 0x0f) << 4) + + ((setting.trig_mask0[0] & 0x0f) << 0); + setting.trig_mask1[0] = ((setting.trig_mask1[0] & 0x0f) << 12) + + ((setting.trig_mask1[0] & 0x0f) << 8) + + ((setting.trig_mask1[0] & 0x0f) << 4) + + ((setting.trig_mask1[0] & 0x0f) << 0); + setting.trig_value0[0] = ((setting.trig_value0[0] & 0x0f) << 12) + + ((setting.trig_value0[0] & 0x0f) << 8) + + ((setting.trig_value0[0] & 0x0f) << 4) + + ((setting.trig_value0[0] & 0x0f) << 0); + setting.trig_value1[0] = ((setting.trig_value1[0] & 0x0f) << 12) + + ((setting.trig_value1[0] & 0x0f) << 8) + + ((setting.trig_value1[0] & 0x0f) << 4) + + ((setting.trig_value1[0] & 0x0f) << 0); + setting.trig_edge0[0] = ((setting.trig_edge0[0] & 0x0f) << 12) + + ((setting.trig_edge0[0] & 0x0f) << 8) + + ((setting.trig_edge0[0] & 0x0f) << 4) + + ((setting.trig_edge0[0] & 0x0f) << 0); + setting.trig_edge1[0] = ((setting.trig_edge1[0] & 0x0f) << 12) + + ((setting.trig_edge1[0] & 0x0f) << 8) + + ((setting.trig_edge1[0] & 0x0f) << 4) + + ((setting.trig_edge1[0] & 0x0f) << 0); + } else if (setting.mode & (1 << HALF_MODE_BIT)) { + setting.trig_mask0[0] = ((setting.trig_mask0[0] & 0xff) << 8) + + ((setting.trig_mask0[0] & 0xff) << 0); + setting.trig_mask1[0] = ((setting.trig_mask1[0] & 0xff) << 8) + + ((setting.trig_mask1[0] & 0xff) << 0); + setting.trig_value0[0] = ((setting.trig_value0[0] & 0xff) << 8) + + ((setting.trig_value0[0] & 0xff) << 0); + setting.trig_value1[0] = ((setting.trig_value1[0] & 0xff) << 8) + + ((setting.trig_value1[0] & 0xff) << 0); + setting.trig_edge0[0] = ((setting.trig_edge0[0] & 0xff) << 8) + + ((setting.trig_edge0[0] & 0xff) << 0); + setting.trig_edge1[0] = ((setting.trig_edge1[0] & 0xff) << 8) + + ((setting.trig_edge1[0] & 0xff) << 0); + } setting.trig_logic0[0] = (trigger->trigger_logic[TriggerStages] << 1) + trigger->trigger0_inv[TriggerStages]; setting.trig_logic1[0] = (trigger->trigger_logic[TriggerStages] << 1) + trigger->trigger1_inv[TriggerStages]; + setting.trig_count[0] = trigger->trigger0_count[TriggerStages]; + for (i = 1; i < NUM_TRIGGER_STAGES; i++) { setting.trig_mask0[i] = 0xffff; setting.trig_mask1[i] = 0xffff; @@ -411,11 +499,10 @@ static int fpga_setting(const struct sr_dev_inst *sdi) setting.trig_edge0[i] = 0; setting.trig_edge1[i] = 0; - setting.trig_count0[i] = 0; - setting.trig_count1[i] = 0; - setting.trig_logic0[i] = 2; setting.trig_logic1[i] = 2; + + setting.trig_count[i] = 0; } } else { for (i = 0; i < NUM_TRIGGER_STAGES; i++) { @@ -428,17 +515,61 @@ static int fpga_setting(const struct sr_dev_inst *sdi) setting.trig_edge0[i] = ds_trigger_get_edge0(i); setting.trig_edge1[i] = ds_trigger_get_edge1(i); - setting.trig_count0[i] = trigger->trigger0_count[i]; - setting.trig_count1[i] = trigger->trigger1_count[i]; + if (setting.mode & (1 << STRIG_MODE_BIT) && i == STriggerDataStage) { + // serial trigger, data mask/value should not be duplicated + } else { + if (setting.mode & (1 << QUAR_MODE_BIT)) { + setting.trig_mask0[i] = ((setting.trig_mask0[i] & 0x0f) << 12) + + ((setting.trig_mask0[i] & 0x0f) << 8) + + ((setting.trig_mask0[i] & 0x0f) << 4) + + ((setting.trig_mask0[i] & 0x0f) << 0); + setting.trig_mask1[i] = ((setting.trig_mask1[i] & 0x0f) << 12) + + ((setting.trig_mask1[i] & 0x0f) << 8) + + ((setting.trig_mask1[i] & 0x0f) << 4) + + ((setting.trig_mask1[i] & 0x0f) << 0); + setting.trig_value0[i] = ((setting.trig_value0[i] & 0x0f) << 12) + + ((setting.trig_value0[i] & 0x0f) << 8) + + ((setting.trig_value0[i] & 0x0f) << 4) + + ((setting.trig_value0[i] & 0x0f) << 0); + setting.trig_value1[i] = ((setting.trig_value1[i] & 0x0f) << 12) + + ((setting.trig_value1[i] & 0x0f) << 8) + + ((setting.trig_value1[i] & 0x0f) << 4) + + ((setting.trig_value1[i] & 0x0f) << 0); + setting.trig_edge0[i] = ((setting.trig_edge0[i] & 0x0f) << 12) + + ((setting.trig_edge0[i] & 0x0f) << 8) + + ((setting.trig_edge0[i] & 0x0f) << 4) + + ((setting.trig_edge0[i] & 0x0f) << 0); + setting.trig_edge1[i] = ((setting.trig_edge1[i] & 0x0f) << 12) + + ((setting.trig_edge1[i] & 0x0f) << 8) + + ((setting.trig_edge1[i] & 0x0f) << 4) + + ((setting.trig_edge1[i] & 0x0f) << 0); + } else if (setting.mode & (1 << HALF_MODE_BIT)) { + setting.trig_mask0[i] = ((setting.trig_mask0[i] & 0xff) << 8) + + ((setting.trig_mask0[i] & 0xff) << 0); + setting.trig_mask1[i] = ((setting.trig_mask1[i] & 0xff) << 8) + + ((setting.trig_mask1[i] & 0xff) << 0); + setting.trig_value0[i] = ((setting.trig_value0[i] & 0xff) << 8) + + ((setting.trig_value0[i] & 0xff) << 0); + setting.trig_value1[i] = ((setting.trig_value1[i] & 0xff) << 8) + + ((setting.trig_value1[i] & 0xff) << 0); + setting.trig_edge0[i] = ((setting.trig_edge0[i] & 0xff) << 8) + + ((setting.trig_edge0[i] & 0xff) << 0); + setting.trig_edge1[i] = ((setting.trig_edge1[i] & 0xff) << 8) + + ((setting.trig_edge1[i] & 0xff) << 0); + } + } setting.trig_logic0[i] = (trigger->trigger_logic[i] << 1) + trigger->trigger0_inv[i]; setting.trig_logic1[i] = (trigger->trigger_logic[i] << 1) + trigger->trigger1_inv[i]; + + setting.trig_count[i] = trigger->trigger0_count[i]; } } result = SR_OK; ret = libusb_bulk_transfer(hdl, 2 | LIBUSB_ENDPOINT_OUT, - &setting, sizeof(struct DSL_setting), + (unsigned char *)&setting, + sizeof(struct DSL_setting), &transferred, 1000); if (ret < 0) { @@ -490,11 +621,9 @@ static int fpga_config(struct libusb_device_handle *hdl, const char *filename) if (chunksize == 0) break; - //do { - ret = libusb_bulk_transfer(hdl, 2 | LIBUSB_ENDPOINT_OUT, - buf, chunksize, - &transferred, 1000); - //} while(ret == LIBUSB_ERROR_TIMEOUT); + ret = libusb_bulk_transfer(hdl, 2 | LIBUSB_ENDPOINT_OUT, + buf, chunksize, + &transferred, 1000); if (ret < 0) { sr_err("Unable to configure FPGA of DSLogic: %s.", @@ -599,18 +728,19 @@ static int DSLogic_dev_open(struct sr_dev_inst *sdi) } /* - * Changes in major version mean incompatible/API changes, so - * bail out if we encounter an incompatible version. - * Different minor versions are OK, they should be compatible. + * Different versions may have incompatible issue, + * Mark for up level process */ - if (vi.major != DSL_REQUIRED_VERSION_MAJOR) { - sr_err("Expected firmware version %d.x, " - "got %d.%d.", DSL_REQUIRED_VERSION_MAJOR, + if (vi.major != DSL_REQUIRED_VERSION_MAJOR || + vi.minor != DSL_REQUIRED_VERSION_MINOR) { + sr_err("Expected firmware version %d.%d, " + "got %d.%d.", DSL_REQUIRED_VERSION_MAJOR, DSL_REQUIRED_VERSION_MINOR, vi.major, vi.minor); - break; + sdi->status = SR_ST_INCOMPATIBLE; + } else { + sdi->status = SR_ST_ACTIVE; } - sdi->status = SR_ST_ACTIVE; sr_info("Opened device %d on %d.%d, " "interface %d, firmware %d.%d.", sdi->index, usb->bus, usb->address, @@ -623,7 +753,8 @@ static int DSLogic_dev_open(struct sr_dev_inst *sdi) } libusb_free_device_list(devlist, 1); - if (sdi->status != SR_ST_ACTIVE) + if ((sdi->status != SR_ST_ACTIVE) && + (sdi->status != SR_ST_INCOMPATIBLE)) return SR_ERR; return SR_OK; @@ -664,19 +795,10 @@ static int configure_probes(const struct sr_dev_inst *sdi) } } - if (stage == -1) - /* - * We didn't configure any triggers, make sure acquisition - * doesn't wait for any. - */ - devc->trigger_stage = TRIGGER_FIRED; - else - devc->trigger_stage = 0; - return SR_OK; } -static struct DSL_context *DSLogic_dev_new(void) +static struct DSL_context *DSLogic_dev_new(const struct sr_dev_inst *sdi) { struct DSL_context *devc; @@ -694,10 +816,11 @@ static struct DSL_context *DSLogic_dev_new(void) devc->clock_edge = FALSE; devc->rle_mode = FALSE; devc->instant = FALSE; - devc->op_mode = SR_OP_BUFFER; + devc->op_mode = SR_OP_STREAM; + devc->buf_options = SR_BUF_UPLOAD; devc->ch_mode = 0; - devc->samplerates_size = 14; - devc->samplecounts_size = ARRAY_SIZE(samplecounts); + devc->samplerates_size = 11; + devc->samplecounts_size = counts_size(sdi); devc->th_level = SR_TH_3V3; devc->vth = 1.0; devc->filter = SR_FILTER_NONE; @@ -708,7 +831,7 @@ static struct DSL_context *DSLogic_dev_new(void) devc->trigger_hrate = 0; devc->trigger_holdoff = 0; devc->zero = FALSE; - devc->stream = FALSE; + devc->stream = (devc->op_mode == SR_OP_STREAM); devc->mstatus_valid = FALSE; devc->data_lock = FALSE; devc->max_height = 0; @@ -729,10 +852,10 @@ static int init(struct sr_context *sr_ctx) return std_hw_init(sr_ctx, di, LOG_PREFIX); } -static int probe_init(struct sr_dev_inst *sdi) +static void probe_init(struct sr_dev_inst *sdi) { int i; - GList *l; + GSList *l; for (l = sdi->channels; l; l = l->next) { struct sr_channel *probe = (struct sr_channel *)l->data; if (sdi->mode == DSO) { @@ -766,9 +889,7 @@ static int set_probes(struct sr_dev_inst *sdi, int num_probes) static int adjust_probes(struct sr_dev_inst *sdi, int num_probes) { uint16_t j; - GSList *l; struct sr_channel *probe; - GSList *p; assert(num_probes > 0); @@ -782,7 +903,7 @@ static int adjust_probes(struct sr_dev_inst *sdi, int num_probes) } while(j > num_probes) { - g_slist_delete_link(sdi->channels, g_slist_last(sdi->channels)); + sdi->channels = g_slist_delete_link(sdi->channels, g_slist_last(sdi->channels)); j--; } @@ -867,7 +988,7 @@ static GSList *scan(GSList *options) if (set_probes(sdi, num_logic_probes) != SR_OK) return NULL; - devc = DSLogic_dev_new(); + devc = DSLogic_dev_new(sdi); devc->profile = prof; sdi->priv = devc; drvc->instances = g_slist_append(drvc->instances, sdi); @@ -917,16 +1038,16 @@ static GSList *dev_list(void) static GSList *dev_mode_list(const struct sr_dev_inst *sdi) { GSList *l = NULL; - int i; + unsigned int i; - if (strcmp(sdi->model, "DSLogic Pro") == 0) { - for(i = 0; i < ARRAY_SIZE(pro_mode_list); i++) { - l = g_slist_append(l, &pro_mode_list[i]); - } - } else { + if (strcmp(sdi->model, "DSLogic") == 0) { for(i = 0; i < ARRAY_SIZE(mode_list); i++) { l = g_slist_append(l, &mode_list[i]); } + } else { + for(i = 0; i < ARRAY_SIZE(pro_mode_list); i++) { + l = g_slist_append(l, &pro_mode_list[i]); + } } return l; } @@ -1050,12 +1171,11 @@ static uint64_t dso_cmd_gen(const struct sr_dev_inst *sdi, struct sr_channel* ch return cmd; } -static int dso_init(const struct sr_dev_inst *sdi, gboolean from_eep) +static int dso_init(const struct sr_dev_inst *sdi) { - int ret, i; + int ret; GSList *l; struct sr_usb_dev_inst *usb = sdi->conn; - gboolean zeroed = FALSE; for(l = sdi->channels; l; l = l->next) { struct sr_channel *probe = (struct sr_channel *)l->data; @@ -1116,6 +1236,8 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, struct DSL_context *devc; struct sr_usb_dev_inst *usb; char str[128]; + uint8_t tmp_u8; + int ret; (void)cg; @@ -1167,6 +1289,20 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, devc = sdi->priv; *data = g_variant_new_boolean(devc->rle_mode); break; + case SR_CONF_WAIT_UPLOAD: + if (!sdi) + return SR_ERR; + devc = sdi->priv; + usb = sdi->conn; + if (devc->buf_options == SR_BUF_UPLOAD && + devc->status == DSL_START) { + devc->status = DSL_ABORT; + command_wr_reg(usb->devhdl, bmFORCE_STOP, EEWP_ADDR); + *data = g_variant_new_boolean(TRUE); + } else { + *data = g_variant_new_boolean(FALSE); + } + break; case SR_CONF_INSTANT: if (!sdi) return SR_ERR; @@ -1179,6 +1315,12 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, devc = sdi->priv; *data = g_variant_new_string(opmodes[devc->op_mode]); break; + case SR_CONF_BUFFER_OPTIONS: + if (!sdi) + return SR_ERR; + devc = sdi->priv; + *data = g_variant_new_string(bufoptions[devc->buf_options]); + break; case SR_CONF_CHANNEL_MODE: if (!sdi) return SR_ERR; @@ -1338,22 +1480,11 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, return SR_ERR; *data = g_variant_new_uint64(DSLOGIC_MAX_DSO_DEPTH); break; - case SR_CONF_MAX_LOGIC_SAMPLERATE: - if (!sdi) - return SR_ERR; - *data = g_variant_new_uint64(DSLOGIC_MAX_LOGIC_SAMPLERATE); - break; - case SR_CONF_MAX_LOGIC_SAMPLELIMITS: + case SR_CONF_HW_DEPTH: if (!sdi) return SR_ERR; devc = sdi->priv; - *data = g_variant_new_uint64(DSLOGIC_MAX_LOGIC_DEPTH*ceil(devc->cur_samplerate * 1.0 / DSLOGIC_MAX_LOGIC_SAMPLERATE)); - break; - case SR_CONF_RLE_SAMPLELIMITS: - if (!sdi) - return SR_ERR; - devc = sdi->priv; - *data = g_variant_new_uint64(DSLOGIC_MAX_LOGIC_DEPTH*ceil(samplerates[devc->samplerates_size-1] * 1.0 / DSLOGIC_MAX_LOGIC_SAMPLERATE)); + *data = g_variant_new_uint64(channel_depth(sdi)); break; case SR_CONF_DSO_BITS: if (!sdi) @@ -1361,6 +1492,28 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, devc = sdi->priv; *data = g_variant_new_byte(devc->dso_bits); break; + case SR_CONF_HW_STATUS: + if (!sdi) + return SR_ERR; + devc = sdi->priv; + usb = sdi->conn; + ret = command_get_hw_info(usb->devhdl, &tmp_u8); + if (ret == SR_OK) { + devc->overflow = tmp_u8 & 0x10; + *data = g_variant_new_byte(tmp_u8); + } else { + *data = g_variant_new_byte(0); + } + break; + case SR_CONF_VLD_CH_NUM: + if (!sdi) + return SR_ERR; + devc = sdi->priv; + if (devc->stream) + *data = g_variant_new_int16(stream_ch_num[devc->ch_mode]); + else + *data = g_variant_new_int16(buffer_ch_num[devc->ch_mode]); + break; default: return SR_ERR_NA; } @@ -1370,13 +1523,13 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, struct sr_channel *ch, - const struct sr_channel_group *cg ) + struct sr_channel_group *cg ) { struct DSL_context *devc; const char *stropt; int ret, num_probes; struct sr_usb_dev_inst *usb; - int i; + unsigned int i; struct drv_context *drvc; (void)cg; @@ -1390,12 +1543,15 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, ret = SR_OK; if (id == SR_CONF_SAMPLERATE) { - devc->cur_samplerate = g_variant_get_uint64(data); - if(sdi->mode == DSO) { - devc->sample_wide = (devc->cur_samplerate <= DSLOGIC_MAX_DSO_SAMPLERATE); - ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 0, SR_CONF_SAMPLERATE)); - } else { - devc->sample_wide = (devc->cur_samplerate <= DSLOGIC_MAX_LOGIC_SAMPLERATE); + if ((devc->op_mode != SR_OP_INTERNAL_TEST) && + (devc->op_mode != SR_OP_EXTERNAL_TEST)) { + devc->cur_samplerate = g_variant_get_uint64(data); + if(sdi->mode == DSO) { + devc->sample_wide = (devc->cur_samplerate <= DSLOGIC_MAX_DSO_SAMPLERATE); + ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 0, SR_CONF_SAMPLERATE)); + } else { + devc->sample_wide = (devc->cur_samplerate <= DSLOGIC_MAX_LOGIC_SAMPLERATE); + } } } else if (id == SR_CONF_CLOCK_TYPE) { devc->clock_type = g_variant_get_boolean(data); @@ -1418,9 +1574,10 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, } else if (id == SR_CONF_DEVICE_MODE) { sdi->mode = g_variant_get_int16(data); if (sdi->mode == LOGIC) { + command_wr_reg(usb->devhdl, bmSCOPE_CLR, EEWP_ADDR); num_probes = devc->profile->dev_caps & DEV_CAPS_16BIT ? 16 : 8; - devc->samplecounts_size = ARRAY_SIZE(samplecounts); } else if (sdi->mode == DSO) { + command_wr_reg(usb->devhdl, bmSCOPE_SET, EEWP_ADDR); num_probes = devc->profile->dev_caps & DEV_CAPS_16BIT ? MAX_DSO_PROBES_NUM : 1; ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, NULL, SR_CONF_DSO_SYNC)); if (ret != SR_OK) @@ -1428,19 +1585,19 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, devc->cur_samplerate = DSLOGIC_MAX_DSO_SAMPLERATE / num_probes; devc->limit_samples = DSLOGIC_MAX_DSO_DEPTH / num_probes; devc->samplerates_size = 15; - devc->samplecounts_size = ARRAY_SIZE(samplecounts); - } else if (sdi->mode == ANALOG){ + } else { + command_wr_reg(usb->devhdl, bmSCOPE_CLR, EEWP_ADDR); num_probes = devc->profile->dev_caps & DEV_CAPS_16BIT ? MAX_ANALOG_PROBES_NUM : 1; devc->op_mode = SR_OP_STREAM; devc->stream = TRUE; devc->samplerates_size = 10; - devc->samplecounts_size = 15; } + devc->samplecounts_size = counts_size(sdi); sr_dev_probes_free(sdi); set_probes(sdi, num_probes); sr_dbg("%s: setting mode to %d", __func__, sdi->mode); if (sdi->mode == DSO) { - dso_init(sdi, 0); + dso_init(sdi); } } else if (id == SR_CONF_OPERATION_MODE) { stropt = g_variant_get_string(data, NULL); @@ -1450,28 +1607,38 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, devc->stream = FALSE; devc->ch_mode = 0; devc->samplerates_size = 14; - adjust_probes(sdi, buffer_ch_num[0]); + adjust_probes(sdi, MAX_LOGIC_PROBES); } else if (!strcmp(stropt, opmodes[SR_OP_STREAM]) && (devc->op_mode != SR_OP_STREAM)) { devc->op_mode = SR_OP_STREAM; devc->stream = TRUE; devc->ch_mode = 0; - devc->samplerates_size = 10; - adjust_probes(sdi, stream_ch_num[0]); + devc->samplerates_size = 11; + adjust_probes(sdi, MAX_LOGIC_PROBES); } else if (!strcmp(stropt, opmodes[SR_OP_INTERNAL_TEST]) && (devc->op_mode != SR_OP_INTERNAL_TEST)) { devc->op_mode = SR_OP_INTERNAL_TEST; - devc->stream = FALSE; + if (strcmp(sdi->model, "DSLogic Basic") == 0) { + devc->stream = TRUE; + devc->samplerates_size = 11; + } else { + devc->stream = FALSE; + devc->samplerates_size = 14; + } devc->ch_mode = 0; - devc->samplerates_size = 14; - adjust_probes(sdi, buffer_ch_num[0]); + adjust_probes(sdi, MAX_LOGIC_PROBES); devc->limit_samples = DSLOGIC_MAX_LOGIC_DEPTH; devc->cur_samplerate = DSLOGIC_MAX_LOGIC_SAMPLERATE; devc->sample_wide = TRUE; } else if (!strcmp(stropt, opmodes[SR_OP_EXTERNAL_TEST]) && (devc->op_mode != SR_OP_EXTERNAL_TEST)) { devc->op_mode = SR_OP_EXTERNAL_TEST; - devc->stream = FALSE; + if (strcmp(sdi->model, "DSLogic Basic") == 0) { + devc->stream = TRUE; + devc->samplerates_size = 11; + } else { + devc->stream = FALSE; + devc->samplerates_size = 14; + } devc->ch_mode = 0; - devc->samplerates_size = 14; - adjust_probes(sdi, buffer_ch_num[0]); + adjust_probes(sdi, MAX_LOGIC_PROBES); devc->limit_samples = DSLOGIC_MAX_LOGIC_DEPTH; devc->cur_samplerate = DSLOGIC_MAX_LOGIC_SAMPLERATE; devc->sample_wide = TRUE; @@ -1480,7 +1647,7 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, devc->stream = FALSE; devc->ch_mode = 0; devc->samplerates_size = 14; - adjust_probes(sdi, buffer_ch_num[0]); + adjust_probes(sdi, MAX_LOGIC_PROBES); devc->limit_samples = DSLOGIC_MAX_LOGIC_DEPTH; devc->cur_samplerate = DSLOGIC_MAX_LOGIC_SAMPLERATE; devc->sample_wide = TRUE; @@ -1495,10 +1662,18 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, devc->op_mode = SR_OP_STREAM; devc->stream = TRUE; devc->samplerates_size = 10; - devc->samplecounts_size = 15; } + devc->samplecounts_size = counts_size(sdi); sr_dbg("%s: setting pattern to %d", __func__, devc->op_mode); + } else if (id == SR_CONF_BUFFER_OPTIONS) { + stropt = g_variant_get_string(data, NULL); + if (sdi->mode == LOGIC) { + if (!strcmp(stropt, bufoptions[SR_BUF_STOP])) + devc->buf_options = SR_BUF_STOP; + else if (!strcmp(stropt, bufoptions[SR_BUF_UPLOAD])) + devc->buf_options = SR_BUF_UPLOAD; + } } else if (id == SR_CONF_CHANNEL_MODE) { stropt = g_variant_get_string(data, NULL); if (sdi->mode == LOGIC) { @@ -1506,8 +1681,8 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, for (i = 0; i < ARRAY_SIZE(stream_ch_modes); i++) if (!strcmp(stropt, stream_ch_modes[i])) { devc->ch_mode = i; - devc->samplerates_size = 10 + i * 2; - adjust_probes(sdi, stream_ch_num[i]); + devc->samplerates_size = 11 + i; + adjust_probes(sdi, MAX_LOGIC_PROBES); break; } } else { @@ -1695,7 +1870,7 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, * because the samplelimits may changed */ devc->trigger_hpos = devc->trigger_hrate * en_ch_num(sdi) * devc->limit_samples / 200.0; - if ((ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 1, SR_CONF_HORIZ_TRIGGERPOS))) == SR_OK) + if ((ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, NULL, SR_CONF_HORIZ_TRIGGERPOS))) == SR_OK) sr_dbg("%s: setting DSO Horiz Trigger Position to %d", __func__, devc->trigger_hpos); else @@ -1762,20 +1937,20 @@ static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, case SR_CONF_DEVICE_CONFIGS: // *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, // hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t)); - if (strcmp(sdi->model, "DSLogic Pro") == 0) - *data = g_variant_new_from_data(G_VARIANT_TYPE("ai"), - hwoptions_pro, ARRAY_SIZE(hwoptions_pro)*sizeof(int32_t), TRUE, NULL, NULL); - else + if (strcmp(sdi->model, "DSLogic") == 0) *data = g_variant_new_from_data(G_VARIANT_TYPE("ai"), hwoptions, ARRAY_SIZE(hwoptions)*sizeof(int32_t), TRUE, NULL, NULL); - break; - case SR_CONF_DEVICE_SESSIONS: - if (strcmp(sdi->model, "DSLogic Pro") == 0) - *data = g_variant_new_from_data(G_VARIANT_TYPE("ai"), - sessions_pro, ARRAY_SIZE(sessions_pro)*sizeof(int32_t), TRUE, NULL, NULL); else + *data = g_variant_new_from_data(G_VARIANT_TYPE("ai"), + hwoptions_pro, ARRAY_SIZE(hwoptions_pro)*sizeof(int32_t), TRUE, NULL, NULL); + break; + case SR_CONF_DEVICE_SESSIONS: + if (strcmp(sdi->model, "DSLogic") == 0) *data = g_variant_new_from_data(G_VARIANT_TYPE("ai"), sessions, ARRAY_SIZE(sessions)*sizeof(int32_t), TRUE, NULL, NULL); + else + *data = g_variant_new_from_data(G_VARIANT_TYPE("ai"), + sessions_pro, ARRAY_SIZE(sessions_pro)*sizeof(int32_t), TRUE, NULL, NULL); break; case SR_CONF_SAMPLERATE: g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}")); @@ -1799,6 +1974,9 @@ static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, case SR_CONF_OPERATION_MODE: *data = g_variant_new_strv(opmodes, opmodes_show_count); break; + case SR_CONF_BUFFER_OPTIONS: + *data = g_variant_new_strv(bufoptions, ARRAY_SIZE(bufoptions)); + break; case SR_CONF_CHANNEL_MODE: if (devc->stream) *data = g_variant_new_strv(stream_ch_modes, ARRAY_SIZE(stream_ch_modes)); @@ -1827,10 +2005,9 @@ static int dev_open(struct sr_dev_inst *sdi) { struct sr_usb_dev_inst *usb; struct DSL_context *devc; - GSList *l; int ret; - int64_t timediff_us, timediff_ms; - uint8_t fpga_done; + uint8_t hw_info; + gboolean fpga_done; devc = sdi->priv; usb = sdi->conn; @@ -1871,13 +2048,14 @@ static int dev_open(struct sr_dev_inst *sdi) return SR_ERR; } - ret = command_get_fpga_done(usb->devhdl, &fpga_done); + ret = command_get_hw_info(usb->devhdl, &hw_info); if (ret != SR_OK) { - sr_err("Failed to get fpga done infos."); + sr_err("Failed to get hardware infos."); return SR_ERR; } + fpga_done = (hw_info & 0x80) != 0; - if (fpga_done == 0) { + if (sdi->status == SR_ST_ACTIVE && !fpga_done) { if ((ret = command_fpga_config(usb->devhdl)) != SR_OK) { sr_err("%s: Send FPGA configure command failed!", __func__); } else { @@ -1921,12 +2099,10 @@ static int dev_open(struct sr_dev_inst *sdi) static int dev_close(struct sr_dev_inst *sdi) { struct sr_usb_dev_inst *usb; - struct DSL_context *devc; usb = sdi->conn; if (usb->devhdl == NULL) return SR_ERR; - devc = sdi->priv; sr_info("DSLogic: Closing device %d on %d.%d interface %d.", sdi->index, usb->bus, usb->address, USB_INTERFACE); @@ -1971,6 +2147,7 @@ static void finish_acquisition(struct DSL_context *devc) sr_err("%s: send SR_DF_END packet", __func__); /* Terminate session. */ packet.type = SR_DF_END; + packet.status = SR_PKT_OK; sr_session_send(devc->cb_data, &packet); if (devc->num_transfers != 0) { @@ -1984,23 +2161,23 @@ static void finish_acquisition(struct DSL_context *devc) static void free_transfer(struct libusb_transfer *transfer) { struct DSL_context *devc; - unsigned int i; + unsigned int i; devc = transfer->user_data; - g_free(transfer->buffer); - transfer->buffer = NULL; - libusb_free_transfer(transfer); + g_free(transfer->buffer); + transfer->buffer = NULL; + libusb_free_transfer(transfer); - for (i = 0; i < devc->num_transfers; i++) { - if (devc->transfers[i] == transfer) { - devc->transfers[i] = NULL; - break; - } - } + for (i = 0; i < devc->num_transfers; i++) { + if (devc->transfers[i] == transfer) { + devc->transfers[i] = NULL; + break; + } + } - devc->submitted_transfers--; - if (devc->submitted_transfers == 0 && devc->status != DSL_TRIGGERED) + devc->submitted_transfers--; + if (devc->submitted_transfers == 0) finish_acquisition(devc); } @@ -2020,21 +2197,19 @@ static void resubmit_transfer(struct libusb_transfer *transfer) static void receive_transfer(struct libusb_transfer *transfer) { - gboolean packet_has_error = FALSE; struct sr_datafeed_packet packet; struct sr_datafeed_logic logic; struct sr_datafeed_dso dso; struct sr_datafeed_analog analog; + uint64_t cur_sample_count = 0; - int trigger_offset, i; - int trigger_offset_bytes; - - const uint8_t *cur_buf = transfer->buffer; + uint8_t *cur_buf = transfer->buffer; struct DSL_context *devc = transfer->user_data; struct sr_dev_inst *sdi = devc->cb_data; const int sample_width = (devc->sample_wide) ? 2 : 1; - int cur_sample_count = transfer->actual_length / sample_width; - + + if (devc->status == DSL_START) + devc->status = DSL_DATA; if (devc->data_lock) { resubmit_transfer(transfer); return; @@ -2043,101 +2218,31 @@ static void receive_transfer(struct libusb_transfer *transfer) if (devc->abort) devc->status = DSL_STOP; - sr_info("receive_transfer(): status %d; timeout %d; received %d bytes.", - transfer->status, transfer->timeout, transfer->actual_length); + sr_info("%" PRIu64 ": receive_transfer(): status %d; timeout %d; received %d bytes.", + g_get_monotonic_time(), transfer->status, transfer->timeout, transfer->actual_length); switch (transfer->status) { - case LIBUSB_TRANSFER_NO_DEVICE: - case LIBUSB_TRANSFER_CANCELLED: - devc->status = DSL_ERROR; - break; case LIBUSB_TRANSFER_COMPLETED: case LIBUSB_TRANSFER_TIMED_OUT: /* We may have received some data though. */ break; default: - packet_has_error = TRUE; + devc->status = DSL_ERROR; break; } + packet.status = SR_PKT_OK; if (devc->status == DSL_DATA && - (transfer->actual_length == 0 || - packet_has_error)) { - devc->empty_transfer_count++; - if (devc->empty_transfer_count > MAX_EMPTY_TRANSFERS) { - devc->status = DSL_ERROR; - } - } else { - devc->empty_transfer_count = 0; - } - - trigger_offset = 0; - if (devc->status == DSL_DATA && devc->trigger_stage >= 0) { - for (i = 0; i < cur_sample_count; i++) { - const uint16_t cur_sample = devc->sample_wide ? - *((const uint16_t*)cur_buf + i) : - *((const uint8_t*)cur_buf + i); - - if ((cur_sample & devc->trigger_mask[devc->trigger_stage]) == - devc->trigger_value[devc->trigger_stage]) { - /* Match on this trigger stage. */ - devc->trigger_buffer[devc->trigger_stage] = cur_sample; - devc->trigger_stage++; - - if (devc->trigger_stage == NUM_TRIGGER_STAGES || - devc->trigger_mask[devc->trigger_stage] == 0) { - /* Match on all trigger stages, we're done. */ - trigger_offset = i + 1; - - /* - * TODO: Send pre-trigger buffer to session bus. - * Tell the frontend we hit the trigger here. - */ - packet.type = SR_DF_TRIGGER; - packet.payload = NULL; - sr_session_send(sdi, &packet); - - /* - * Send the samples that triggered it, - * since we're skipping past them. - */ - packet.type = SR_DF_LOGIC; - packet.payload = &logic; - logic.unitsize = sizeof(*devc->trigger_buffer); - logic.length = devc->trigger_stage * logic.unitsize; - logic.data = devc->trigger_buffer; - sr_session_send(sdi, &packet); - - devc->trigger_stage = TRIGGER_FIRED; - break; - } - } else if (devc->trigger_stage > 0) { - /* - * We had a match before, but not in the next sample. However, we may - * have a match on this stage in the next bit -- trigger on 0001 will - * fail on seeing 00001, so we need to go back to stage 0 -- but at - * the next sample from the one that matched originally, which the - * counter increment at the end of the loop takes care of. - */ - i -= devc->trigger_stage; - if (i < -1) - i = -1; /* Oops, went back past this buffer. */ - /* Reset trigger stage. */ - devc->trigger_stage = 0; - } - } - } - - if (devc->status == DSL_DATA && devc->trigger_stage == TRIGGER_FIRED) { + transfer->actual_length != 0) { /* Send the incoming transfer to the session bus. */ - trigger_offset_bytes = trigger_offset * sample_width; // check packet type if (sdi->mode == LOGIC) { packet.type = SR_DF_LOGIC; packet.payload = &logic; - logic.length = transfer->actual_length - trigger_offset_bytes; - logic.unitsize = sample_width; + cur_sample_count = transfer->actual_length * 8 / en_ch_num(sdi) ; + logic.length = transfer->actual_length; + logic.format = LA_CROSS_DATA; logic.data_error = 0; - logic.data = cur_buf + trigger_offset_bytes; + logic.data = cur_buf; } else if (sdi->mode == DSO) { if (!devc->instant) { const uint32_t mstatus_offset = devc->limit_samples / (g_slist_length(sdi->channels)/en_ch_num(sdi)); @@ -2180,9 +2285,10 @@ static void receive_transfer(struct libusb_transfer *transfer) dso.mqflags = SR_MQFLAG_AC; dso.samplerate_tog = (mstatus.sample_divider_tog != 0); dso.trig_flag = (mstatus.trig_flag != 0); - dso.data = cur_buf + trigger_offset_bytes; + dso.data = cur_buf; } else { - packet.type = SR_DF_ABANDON; + packet.type = SR_DF_DSO; + packet.status = SR_PKT_DATA_ERROR; devc->mstatus_valid = FALSE; } } else { @@ -2194,60 +2300,28 @@ static void receive_transfer(struct libusb_transfer *transfer) analog.mq = SR_MQ_VOLTAGE; analog.unit = SR_UNIT_VOLT; analog.mqflags = SR_MQFLAG_AC; - analog.data = cur_buf + trigger_offset_bytes; + analog.data = (float *)cur_buf; } - if ((devc->limit_samples && devc->num_samples < devc->actual_samples) || - (*(struct sr_dev_inst *)(devc->cb_data)).mode != LOGIC ) { - const uint64_t remain_length= (devc->actual_samples - devc->num_samples) * sample_width; + if ((devc->limit_samples && devc->num_bytes < devc->actual_bytes) || + sdi->mode != LOGIC ) { + const uint64_t remain_length= devc->actual_bytes - devc->num_bytes; logic.length = min(logic.length, remain_length); - /* in test mode, check data content*/ - if (devc->op_mode == SR_OP_INTERNAL_TEST) { - //for (i = 0; i < logic.length / sample_width; i++) { - for (i = 0; i < logic.length / 2; i++) { -// const uint16_t cur_sample = devc->sample_wide ? -// *((const uint16_t*)cur_buf + i) : -// *((const uint8_t*)cur_buf + i); - const uint16_t cur_sample = *((const uint16_t*)cur_buf + i); - if (test_init == 1) { - test_sample_value = cur_sample; - test_init = 0; - } - if (cur_sample != test_sample_value) { - logic.data_error = 1; - sr_err("exp: %d; act: %d", test_sample_value, cur_sample); - break; - } - test_sample_value++; - } - } - if (devc->op_mode == SR_OP_EXTERNAL_TEST) { - for (i = 0; i < logic.length / 2; i++) { - const uint16_t cur_sample = *((const uint16_t*)cur_buf + i); - if (test_init == 1) { - test_sample_value = cur_sample; - test_init = 0; - } - if (cur_sample != test_sample_value) { - logic.data_error = 1; - sr_err("exp: %d; act: %d", test_sample_value, cur_sample); - break; - } - test_sample_value = (test_sample_value + 1) % 65001; - //test_sample_value = test_sample_value + 1; - } - } - /* send data to session bus */ - if (packet.type != SR_DF_ABANDON) + if (!devc->overflow) sr_session_send(sdi, &packet); } devc->num_samples += cur_sample_count; - if ((sdi->mode != DSO || devc->instant) && + devc->num_bytes += logic.length; + if (sdi->mode == LOGIC && devc->limit_samples && - (unsigned int)devc->num_samples >= devc->actual_samples) { + devc->num_bytes >= devc->actual_bytes) { + devc->status = DSL_STOP; + } else if ((sdi->mode != DSO || devc->instant) && + devc->limit_samples && + devc->num_samples >= devc->actual_samples) { devc->status = DSL_STOP; } } @@ -2260,10 +2334,11 @@ static void receive_transfer(struct libusb_transfer *transfer) static unsigned int to_bytes_per_ms(struct DSL_context *devc) { + struct sr_dev_inst *sdi = devc->cb_data; if (devc->cur_samplerate > SR_MHZ(100)) - return SR_MHZ(100) / 1000 * (devc->sample_wide ? 2 : 1); + return SR_MHZ(100) / 1000 * en_ch_num(sdi) / 8; else - return devc->cur_samplerate / 1000 * (devc->sample_wide ? 2 : 1) ; + return devc->cur_samplerate / 1000 * en_ch_num(sdi) / 8; } static size_t get_buffer_size(struct DSL_context *devc) @@ -2299,10 +2374,102 @@ static unsigned int get_timeout(struct DSL_context *devc) total_size = get_buffer_size(devc) * get_number_of_transfers(devc); timeout = total_size / to_bytes_per_ms(devc); //return timeout + timeout / 4; /* Leave a headroom of 25% percent. */ - return 1000; + if (devc->op_mode == SR_OP_STREAM) + return timeout + timeout / 4; /* Leave a headroom of 25% percent. */ + else + return 1000; } -static int dev_transfer_start(const struct sr_dev_inst *sdi) +static int receive_data(int fd, int revents, const struct sr_dev_inst *sdi) +{ + int completed = 0; + struct timeval tv; + struct drv_context *drvc; + struct DSL_context *devc; + struct sr_usb_dev_inst *usb; + int ret; + + (void)fd; + (void)revents; + + drvc = di->priv; + devc = sdi->priv; + usb = sdi->conn; + + tv.tv_sec = tv.tv_usec = 0; + libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx, &tv, &completed); + + if (devc->status == DSL_FINISH) { + if (libusb_try_lock_events(drvc->sr_ctx->libusb_ctx) == 0) { + if (libusb_event_handling_ok(drvc->sr_ctx->libusb_ctx)) { + usb = ((struct sr_dev_inst *)devc->cb_data)->conn; + + /* Stop GPIF acquisition */ + if ((ret = command_stop_acquisition (usb->devhdl)) != SR_OK) + sr_err("%s: Sent acquisition stop command failed!", __func__); + else + sr_info("%s: Sent acquisition stop command!", __func__); + + /* Remove polling */ + remove_sources(devc); + } + libusb_unlock_events(drvc->sr_ctx->libusb_ctx); + } + } + + return TRUE; +} + +static void receive_trigger_pos(struct libusb_transfer *transfer) +{ + struct DSL_context *devc; + struct sr_datafeed_packet packet; + struct ds_trigger_pos *trigger_pos; + const struct sr_dev_inst *sdi; + uint64_t remain_cnt; + + packet.status = SR_PKT_OK; + devc = transfer->user_data; + sdi = devc->cb_data; + trigger_pos = (struct ds_trigger_pos *)transfer->buffer; + if (devc->status != DSL_ABORT) + devc->status = DSL_ERROR; + if (!devc->abort && transfer->status == LIBUSB_TRANSFER_COMPLETED && + trigger_pos->check_id == TRIG_CHECKID) { + sr_info("%" PRIu64 ": receive_trigger_pos(): status %d; timeout %d; received %d bytes.", + g_get_monotonic_time(), transfer->status, transfer->timeout, transfer->actual_length); + remain_cnt = trigger_pos->remain_cnt_h; + remain_cnt = (remain_cnt << 32) + trigger_pos->remain_cnt_l; + if (transfer->actual_length == sizeof(struct ds_trigger_pos)) { + if (sdi->mode != LOGIC || + devc->stream || + remain_cnt < devc->limit_samples) { + if (sdi->mode == LOGIC && (!devc->stream || (devc->status == DSL_ABORT))) { + devc->actual_samples = devc->limit_samples - remain_cnt; + devc->actual_bytes = devc->actual_samples / DSLOGIC_ATOMIC_SAMPLES * en_ch_num(sdi) * DSLOGIC_ATOMIC_SIZE; + devc->actual_samples = devc->actual_bytes / en_ch_num(sdi) * 8; + } + + packet.type = SR_DF_TRIGGER; + packet.payload = trigger_pos; + sr_session_send(sdi, &packet); + + devc->status = DSL_DATA; + } + } + } else if (!devc->abort) { + sr_err("%s: trigger packet data error.", __func__); + packet.type = SR_DF_TRIGGER; + packet.payload = trigger_pos; + packet.status = SR_PKT_DATA_ERROR; + sr_session_send(sdi, &packet); + } + + free_transfer(transfer); +} + + +static int start_transfers(const struct sr_dev_inst *sdi) { struct DSL_context *devc; struct sr_usb_dev_inst *usb; @@ -2311,7 +2478,8 @@ static int dev_transfer_start(const struct sr_dev_inst *sdi) int ret; unsigned char *buf; size_t size; - int dso_buffer_size; + unsigned int dso_buffer_size; + struct ds_trigger_pos *trigger_pos; devc = sdi->priv; usb = sdi->conn; @@ -2321,19 +2489,40 @@ static int dev_transfer_start(const struct sr_dev_inst *sdi) else dso_buffer_size = devc->limit_samples * en_ch_num(sdi) + 512; - num_transfers = 1; + num_transfers = (devc->stream) ? get_number_of_transfers(devc) : 1; size = (sdi->mode == DSO) ? dso_buffer_size : - (devc->op_mode == SR_OP_STREAM) ? get_buffer_size(devc) : instant_buffer_size; + (devc->stream) ? get_buffer_size(devc) : instant_buffer_size; - devc->submitted_transfers = 0; - devc->transfers = g_try_malloc0(sizeof(*devc->transfers) * num_transfers); - if (!devc->transfers) { - sr_err("%s: USB transfers malloc failed.", __func__); + /* trigger packet transfer */ + if (!(trigger_pos = g_try_malloc0(sizeof(struct ds_trigger_pos)))) { + sr_err("%s: USB trigger_pos buffer malloc failed.", __func__); return SR_ERR_MALLOC; } + devc->transfers = g_try_malloc0(sizeof(*devc->transfers) * (num_transfers + 1)); + if (!devc->transfers) { + sr_err("%s: USB transfer malloc failed.", __func__); + return SR_ERR_MALLOC; + } + transfer = libusb_alloc_transfer(0); + libusb_fill_bulk_transfer(transfer, usb->devhdl, + 6 | LIBUSB_ENDPOINT_IN, (unsigned char *)trigger_pos, sizeof(struct ds_trigger_pos), + receive_trigger_pos, devc, 0); + if ((ret = libusb_submit_transfer(transfer)) != 0) { + sr_err("%s: Failed to submit trigger_pos transfer: %s.", + __func__, libusb_error_name(ret)); + libusb_free_transfer(transfer); + g_free(trigger_pos); + devc->status = DSL_ERROR; + return SR_ERR; + } else { + devc->num_transfers++; + devc->transfers[0] = transfer; + devc->submitted_transfers++; + } - for (i = 0; i < num_transfers; i++) { + /* data packet transfer */ + for (i = 1; i <= num_transfers; i++) { if (!(buf = g_try_malloc(size))) { sr_err("%s: USB transfer buffer malloc failed.", __func__); return SR_ERR_MALLOC; @@ -2356,108 +2545,19 @@ static int dev_transfer_start(const struct sr_dev_inst *sdi) devc->num_transfers++; } - devc->status = DSL_DATA; - return SR_OK; } - -static int receive_data(int fd, int revents, const struct sr_dev_inst *sdi) +static int dev_acquisition_start(struct sr_dev_inst *sdi, void *cb_data) { - int completed = 0; - struct timeval tv; - struct drv_context *drvc; - struct DSL_context *devc; - struct sr_usb_dev_inst *usb; - int i; - int ret; + (void)cb_data; - (void)fd; - (void)revents; - - drvc = di->priv; - devc = sdi->priv; - usb = sdi->conn; - - tv.tv_sec = tv.tv_usec = 0; - /* broken libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx, &tv, &completed); */ - - if (devc->status == DSL_FINISH) { - /* broken if (libusb_try_lock_events(drvc->sr_ctx->libusb_ctx) == 0) { */ - /* broken if (libusb_event_handling_ok(drvc->sr_ctx->libusb_ctx)) { */ - /* Stop GPIF acquisition */ - usb = ((struct sr_dev_inst *)devc->cb_data)->conn; - if ((ret = command_stop_acquisition (usb->devhdl)) != SR_OK) - sr_err("%s: Sent acquisition stop command failed!", __func__); - else - sr_info("%s: Sent acquisition stop command!", __func__); - - remove_sources(devc); - /* } */ - /* broken libusb_unlock_events(drvc->sr_ctx->libusb_ctx); */ - /* } */ - } - - return TRUE; -} - -static void receive_trigger_pos(struct libusb_transfer *transfer) -{ - struct DSL_context *devc; - struct sr_datafeed_packet packet; - struct ds_trigger_pos *trigger_pos; - const struct sr_dev_inst *sdi; - int ret; - - devc = transfer->user_data; - sdi = devc->cb_data; - trigger_pos = (struct ds_trigger_pos *)transfer->buffer; - devc->status = DSL_ERROR; - if (transfer->status == LIBUSB_TRANSFER_COMPLETED && - trigger_pos->check_id == TRIG_CHECKID) { - sr_info("receive_trigger_pos(): status %d; timeout %d; received %d bytes.", - transfer->status, transfer->timeout, transfer->actual_length); - if (transfer->actual_length == sizeof(struct ds_trigger_pos)) { - if (sdi->mode != LOGIC || devc->stream || trigger_pos->remain_cnt < devc->limit_samples) { - if (sdi->mode == LOGIC && !devc->stream) - devc->actual_samples = (devc->limit_samples - ceil(devc->cur_samplerate * 1.0 / DSLOGIC_MAX_LOGIC_SAMPLERATE) * (trigger_pos->remain_cnt)); - packet.type = SR_DF_TRIGGER; - packet.payload = trigger_pos; - sr_session_send(sdi, &packet); - - devc->status = DSL_TRIGGERED; - devc->num_transfers = 0; - devc->empty_transfer_count = 0; - } - } - } - - if (devc->status == DSL_TRIGGERED) { - // successfull - free_transfer(transfer); - if ((ret = dev_transfer_start(devc->cb_data)) != SR_OK) { - sr_err("%s: could not start data transfer" - "(%d)%d", __func__, ret, errno); - } - } else { - // failed - free_transfer(transfer); - } -} - -static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) -{ struct DSL_context *devc; struct drv_context *drvc; struct sr_usb_dev_inst *usb; - struct libusb_transfer *transfer; - struct ds_trigger_pos *trigger_pos; const struct libusb_pollfd **lupfd; unsigned int i; int ret; - int transferred; - struct sr_datafeed_packet packet; - int header_transferred; test_init = 1; @@ -2471,13 +2571,17 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) //devc->cb_data = cb_data; devc->cb_data = sdi; devc->num_samples = 0; + devc->num_bytes = 0; devc->empty_transfer_count = 0; devc->status = DSL_INIT; devc->num_transfers = 0; devc->submitted_transfers = 0; devc->actual_samples = devc->limit_samples; + devc->actual_bytes = devc->actual_samples / DSLOGIC_ATOMIC_SAMPLES * en_ch_num(sdi) * DSLOGIC_ATOMIC_SIZE; test_sample_value = 0; devc->abort = FALSE; + devc->mstatus_valid = FALSE; + devc->overflow = FALSE; /* Configures devc->trigger_* and devc->sample_wide */ if (configure_probes(sdi) != SR_OK) { @@ -2508,7 +2612,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) */ if (sdi->mode == DSO) { devc->trigger_hpos = devc->trigger_hrate * en_ch_num(sdi) * devc->limit_samples / 200.0; - if ((ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 1, SR_CONF_HORIZ_TRIGGERPOS))) == SR_OK) + if ((ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, NULL, SR_CONF_HORIZ_TRIGGERPOS))) == SR_OK) sr_dbg("%s: setting DSO Horiz Trigger Position to %d", __func__, devc->trigger_hpos); else @@ -2516,37 +2620,18 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) __func__, devc->trigger_hpos); } - /* poll trigger status transfer*/ - if (!(trigger_pos = g_try_malloc0(sizeof(struct ds_trigger_pos)))) { - sr_err("%s: USB trigger_pos buffer malloc failed.", __func__); - return SR_ERR_MALLOC; - } - devc->transfers = g_try_malloc0(sizeof(*devc->transfers)); - if (!devc->transfers) { - sr_err("%s: USB trigger_pos transfer malloc failed.", __func__); - return SR_ERR_MALLOC; - } - transfer = libusb_alloc_transfer(0); - libusb_fill_bulk_transfer(transfer, usb->devhdl, - 6 | LIBUSB_ENDPOINT_IN, trigger_pos, sizeof(struct ds_trigger_pos), - receive_trigger_pos, devc, 0); - if ((ret = libusb_submit_transfer(transfer)) != 0) { - sr_err("%s: Failed to submit trigger_pos transfer: %s.", - __func__, libusb_error_name(ret)); - libusb_free_transfer(transfer); - g_free(trigger_pos); - return SR_ERR; - } else { - devc->num_transfers++; - devc->transfers[0] = transfer; - devc->submitted_transfers++; + /* setup and submit usb transfer */ + if ((ret = start_transfers(devc->cb_data)) != SR_OK) { + sr_err("%s: Could not submit usb transfer" + "(%d)%d", __func__, ret, errno); + return ret; } /* setup callback function for data transfer */ lupfd = libusb_get_pollfds(drvc->sr_ctx->libusb_ctx); for (i = 0; lupfd[i]; i++); if (!(devc->usbfd = g_try_malloc(sizeof(struct libusb_pollfd) * (i + 1)))) - return SR_ERR; + return SR_ERR; for (i = 0; lupfd[i]; i++) { sr_source_add(lupfd[i]->fd, lupfd[i]->events, get_timeout(devc), receive_data, sdi); @@ -2555,14 +2640,13 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) devc->usbfd[i] = -1; free(lupfd); - devc->status = DSL_START; - devc->mstatus_valid = FALSE; if ((ret = command_start_acquisition (usb->devhdl, devc->cur_samplerate, devc->sample_wide, (sdi->mode == LOGIC))) != SR_OK) { devc->status = DSL_ERROR; devc->abort = TRUE; return ret; } + devc->status = DSL_START; /* Send header packet to the session bus. */ //std_session_send_df_header(cb_data, LOG_PREFIX); @@ -2571,7 +2655,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) return SR_OK; } -static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) +static int dev_acquisition_stop(const struct sr_dev_inst *sdi, void *cb_data) { (void)cb_data; @@ -2583,31 +2667,13 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) if (!devc->abort) { devc->abort = TRUE; - command_wr_reg(usb->devhdl, 3, EEWP_ADDR); + command_wr_reg(usb->devhdl, bmFORCE_RDY, EEWP_ADDR); } return SR_OK; } -static int dev_test(struct sr_dev_inst *sdi) -{ - if (sdi) { - struct sr_usb_dev_inst *usb; - struct version_info vi; - int ret = SR_ERR; - - usb = sdi->conn; - ret = command_get_fw_version(usb->devhdl, &vi); - if (ret != SR_OK) - sr_err("Device don't exist!"); - - return ret; - } else { - return SR_ERR; - } -} - -static int dev_status_get(struct sr_dev_inst *sdi, struct sr_status *status, int begin, int end) +static int dev_status_get(const struct sr_dev_inst *sdi, struct sr_status *status, int begin, int end) { int ret = SR_ERR; if (sdi) { @@ -2642,7 +2708,6 @@ SR_PRIV struct sr_dev_driver DSLogic_driver_info = { .config_list = config_list, .dev_open = dev_open, .dev_close = dev_close, - .dev_test = dev_test, .dev_status_get = dev_status_get, .dev_acquisition_start = dev_acquisition_start, .dev_acquisition_stop = dev_acquisition_stop, diff --git a/libsigrok4DSL/hardware/common/ezusb.c b/libsigrok4DSL/hardware/common/ezusb.c index 97d5d63a..b664a16b 100644 --- a/libsigrok4DSL/hardware/common/ezusb.c +++ b/libsigrok4DSL/hardware/common/ezusb.c @@ -64,7 +64,7 @@ SR_PRIV int ezusb_install_firmware(libusb_device_handle *hdl, unsigned char buf[4096]; sr_info("Uploading firmware at %s", filename); - if ((fw = g_fopen(filename, "rb")) == NULL) { + if ((fw = fopen(filename, "rb")) == NULL) { sr_err("Unable to open firmware file %s for reading: %s", filename, strerror(errno)); return SR_ERR; diff --git a/libsigrok4DSL/hardware/demo/demo.c b/libsigrok4DSL/hardware/demo/demo.c index 03e8d2cf..ea766c7b 100644 --- a/libsigrok4DSL/hardware/demo/demo.c +++ b/libsigrok4DSL/hardware/demo/demo.c @@ -112,6 +112,7 @@ struct dev_context { gboolean data_lock; uint8_t max_height; uint8_t dso_bits; + uint64_t samples_not_sent; uint16_t *buf; uint64_t pre_index; @@ -286,7 +287,7 @@ static const char *probe_names[NUM_PROBES + 1] = { }; -static const gboolean default_ms_en[DSO_MS_END - DSO_MS_BEGIN] = { +static const gboolean default_ms_en[] = { FALSE, /* DSO_MS_BEGIN */ TRUE, /* DSO_MS_FREQ */ FALSE, /* DSO_MS_PERD */ @@ -295,7 +296,6 @@ static const gboolean default_ms_en[DSO_MS_END - DSO_MS_BEGIN] = { FALSE, /* DSO_MS_VRMS */ FALSE, /* DSO_MS_VMEA */ FALSE, /* DSO_MS_VP2P */ - FALSE, /* DSO_MS_END */ }; /* Private, per-device-instance driver context. */ @@ -307,7 +307,7 @@ static struct sr_dev_driver *di = &demo_driver_info; extern struct ds_trigger *trigger; -static int hw_dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data); +static int hw_dev_acquisition_stop(const struct sr_dev_inst *sdi, void *cb_data); static int clear_instances(void) { @@ -399,7 +399,7 @@ static GSList *hw_dev_mode_list(const struct sr_dev_inst *sdi) { (void)sdi; GSList *l = NULL; - int i; + unsigned int i; for(i = 0; i < ARRAY_SIZE(mode_list); i++) { l = g_slist_append(l, &mode_list[i]); @@ -471,16 +471,15 @@ static int hw_cleanup(void) return ret; } -static int en_ch_num(const struct sr_dev_inst *sdi) +static unsigned int en_ch_num(const struct sr_dev_inst *sdi) { GSList *l; - int channel_en_cnt = 0; + unsigned int channel_en_cnt = 0; for (l = sdi->channels; l; l = l->next) { struct sr_channel *probe = (struct sr_channel *)l->data; channel_en_cnt += probe->enabled; } - channel_en_cnt += (channel_en_cnt == 0); return channel_en_cnt; } @@ -540,7 +539,7 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, *data = g_variant_new_byte(ch->trig_value); break; case SR_CONF_EN_CH: - *data = g_variant_new_uint64(ch->enabled); + *data = g_variant_new_boolean(ch->enabled); break; case SR_CONF_DATALOCK: *data = g_variant_new_boolean(devc->data_lock); @@ -551,18 +550,18 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, case SR_CONF_MAX_DSO_SAMPLELIMITS: *data = g_variant_new_uint64(DEMO_MAX_DSO_DEPTH); break; - case SR_CONF_MAX_LOGIC_SAMPLERATE: - *data = g_variant_new_uint64(DEMO_MAX_LOGIC_SAMPLERATE); - break; - case SR_CONF_MAX_LOGIC_SAMPLELIMITS: - *data = g_variant_new_uint64(DEMO_MAX_LOGIC_DEPTH); - break; - case SR_CONF_RLE_SAMPLELIMITS: + case SR_CONF_HW_DEPTH: *data = g_variant_new_uint64(DEMO_MAX_LOGIC_DEPTH); break; case SR_CONF_DSO_BITS: *data = g_variant_new_byte(devc->dso_bits); break; + case SR_CONF_HW_STATUS: + *data = g_variant_new_byte(0); + break; + case SR_CONF_VLD_CH_NUM: + *data = g_variant_new_int16(NUM_PROBES); + break; default: return SR_ERR_NA; } @@ -572,7 +571,7 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, struct sr_channel *ch, - const struct sr_channel_group *cg) + struct sr_channel_group *cg) { uint16_t i, j; int ret; @@ -821,14 +820,16 @@ static void samples_generator(uint16_t *buf, uint64_t size, const struct sr_dev_inst *sdi, struct dev_context *devc) { - uint64_t i, pre0_i, pre1_i, index; + uint64_t i, pre0_i, pre1_i; GSList *l; struct sr_channel *probe; int offset; - int start_rand; + unsigned int start_rand; const uint64_t span = DEMO_MAX_DSO_SAMPLERATE / devc->cur_samplerate; const uint64_t len = ARRAY_SIZE(sinx) - 1; - int *pre_buf; + const int *pre_buf; + uint16_t tmp_u16 = 0; + unsigned int ch_num = en_ch_num(sdi) ? en_ch_num(sdi) : 1; switch (devc->sample_generator) { case PATTERN_SINE: /* Sine */ @@ -855,11 +856,30 @@ static void samples_generator(uint16_t *buf, uint64_t size, size != devc->limit_samples) { for (i = 0; i < devc->limit_samples; i++) *(buf + i) = *(buf + ((i + size)%devc->limit_samples)); - } else if (sdi->mode != DSO) { - start_rand = rand()%len; + } else if (sdi->mode == LOGIC) { for (i = 0; i < size; i++) { - index = (i/10/g_slist_length(sdi->channels)+start_rand)%len; - *(buf + i) = (uint16_t)(((const_dc+pre_buf[index]) << 8) + (const_dc+pre_buf[index])); + //index = (i/10/g_slist_length(sdi->channels)+start_rand)%len; + //*(buf + i) = (uint16_t)(((const_dc+pre_buf[index]) << 8) + (const_dc+pre_buf[index])); + tmp_u16 = 0; + if (i < ch_num*4) + *(buf + i) = tmp_u16; + else if (i % 4 == 0) { + start_rand = rand() % (ch_num * 4); + if (start_rand == (i/4 % ch_num)) + tmp_u16 = 0xffff; + *(buf + i) = tmp_u16 ? ~*(buf + i - ch_num*4) : *(buf + i - ch_num*4); + } else { + *(buf + i) = *(buf + i - 1); + } + } + } else if (sdi->mode == ANALOG) { + for (i = 0; i < size; i++) { + if (rand() % (devc->limit_samples / 100) == 0) + *(buf + i) = 0x4000 + rand() % 0x8000; + else if (rand() % (devc->limit_samples / 1000) == 0) + *(buf + i) = 0x7000 + rand() % 0x2000; + else + *(buf + i) = 0x8000; } } else { if (devc->pre_index == 0) { @@ -876,8 +896,8 @@ static void samples_generator(uint16_t *buf, uint64_t size, for (l = sdi->channels; l; l = l->next) { start_rand = devc->pre_index == 0 ? rand()%len : 0; probe = (struct sr_channel *)l->data; - //offset = ceil((0.5 - (probe->vpos/probe->vdiv/10.0)) * 255); - offset = 128; + offset = ceil((0.5 - (probe->vpos/probe->vdiv/10.0)) * 255); + //offset = 128; pre0_i = devc->pre_index; pre1_i = devc->pre_index; for (i = devc->pre_index; i < devc->pre_index + size; i++) { @@ -932,35 +952,46 @@ static int receive_data(int fd, int revents, const struct sr_dev_inst *sdi) struct sr_datafeed_logic logic; struct sr_datafeed_dso dso; struct sr_datafeed_analog analog; - static uint64_t samples_to_send = 0, expected_samplenum, sending_now; + double samples_elaspsed; + uint64_t samples_to_send = 0, sending_now; int64_t time, elapsed; static uint16_t last_sample = 0; uint16_t cur_sample; - int i; + uint64_t i; (void)fd; (void)revents; + packet.status = SR_PKT_OK; /* How many "virtual" samples should we have collected by now? */ time = g_get_monotonic_time(); elapsed = time - devc->starttime; devc->starttime = time; //expected_samplenum = ceil(elapsed / 1000000.0 * devc->cur_samplerate); /* Of those, how many do we still have to send? */ - //samples_to_send = (expected_samplenum - devc->samples_counter) / CONST_LEN * CONST_LEN; - //samples_to_send = expected_samplenum / CONST_LEN * CONST_LEN; - samples_to_send += ceil(elapsed / 1000000.0 * devc->cur_samplerate); + samples_elaspsed = elapsed / 1000000.0 * devc->cur_samplerate; if (devc->limit_samples) { - if (sdi->mode == DSO && !devc->instant) + if (sdi->mode == DSO && !devc->instant) { + samples_to_send = ceil(samples_elaspsed); samples_to_send = MIN(samples_to_send, devc->limit_samples - devc->pre_index); - else if (sdi->mode == ANALOG) - samples_to_send = MIN(samples_to_send * g_slist_length(sdi->channels), - devc->limit_samples - devc->pre_index); - else + } else if (sdi->mode == ANALOG) { + samples_to_send = ceil(samples_elaspsed * g_slist_length(sdi->channels)); + samples_to_send = MIN(samples_to_send, + devc->limit_samples * g_slist_length(sdi->channels) - devc->pre_index); + } else { + samples_to_send = ceil(samples_elaspsed); + samples_to_send += devc->samples_not_sent; + if (samples_to_send < 64) { + devc->samples_not_sent = samples_to_send; + return TRUE; + } else + devc->samples_not_sent = samples_to_send & 63; + samples_to_send = samples_to_send & ~63; samples_to_send = MIN(samples_to_send, devc->limit_samples - devc->samples_counter); + } } if (samples_to_send > 0 && !devc->stop) { @@ -1007,12 +1038,12 @@ static int receive_data(int fd, int revents, const struct sr_dev_inst *sdi) devc->samples_counter = devc->limit_samples; if (devc->trigger_stage == 0){ - samples_to_send -= sending_now; + //samples_to_send -= sending_now; if (sdi->mode == LOGIC) { packet.type = SR_DF_LOGIC; packet.payload = &logic; logic.length = sending_now * (NUM_PROBES >> 3); - logic.unitsize = (NUM_PROBES >> 3); + logic.format = LA_CROSS_DATA; logic.data = devc->buf; } else if (sdi->mode == DSO) { packet.type = SR_DF_DSO; @@ -1036,7 +1067,7 @@ static int receive_data(int fd, int revents, const struct sr_dev_inst *sdi) analog.mq = SR_MQ_VOLTAGE; analog.unit = SR_UNIT_VOLT; analog.mqflags = SR_MQFLAG_AC; - analog.data = devc->buf; + analog.data = (float *)devc->buf; } if (sdi->mode == DSO && !devc->instant) { @@ -1065,7 +1096,7 @@ static int receive_data(int fd, int revents, const struct sr_dev_inst *sdi) return TRUE; } -static int hw_dev_acquisition_start(const struct sr_dev_inst *sdi, +static int hw_dev_acquisition_start(struct sr_dev_inst *sdi, void *cb_data) { struct dev_context *const devc = sdi->priv; @@ -1083,6 +1114,7 @@ static int hw_dev_acquisition_start(const struct sr_dev_inst *sdi, devc->mstatus.captured_cnt2 = 0; devc->mstatus.captured_cnt3 = 0; devc->stop = FALSE; + devc->samples_not_sent = 0; /* * trigger setting @@ -1108,7 +1140,7 @@ static int hw_dev_acquisition_start(const struct sr_dev_inst *sdi, */ sr_session_source_add_channel(devc->channel, G_IO_IN | G_IO_ERR, - (sdi->mode == DSO) ? 50 : 10, receive_data, sdi); + 50, receive_data, sdi); /* Send header packet to the session bus. */ //std_session_send_df_header(cb_data, LOG_PREFIX); @@ -1125,7 +1157,7 @@ static int hw_dev_acquisition_start(const struct sr_dev_inst *sdi, return SR_OK; } -static int hw_dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) +static int hw_dev_acquisition_stop(const struct sr_dev_inst *sdi, void *cb_data) { (void)cb_data; @@ -1144,20 +1176,13 @@ static int hw_dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) /* Send last packet. */ packet.type = SR_DF_END; + packet.status = SR_PKT_OK; sr_session_send(sdi, &packet); return SR_OK; } -static int hw_dev_test(struct sr_dev_inst *sdi) -{ - if (sdi) - return SR_OK; - else - return SR_ERR; -} - -static int hw_dev_status_get(struct sr_dev_inst *sdi, struct sr_status *status, int begin, int end) +static int hw_dev_status_get(const struct sr_dev_inst *sdi, struct sr_status *status, int begin, int end) { (void)begin; (void)end; @@ -1185,7 +1210,6 @@ SR_PRIV struct sr_dev_driver demo_driver_info = { .config_list = config_list, .dev_open = hw_dev_open, .dev_close = hw_dev_close, - .dev_test = hw_dev_test, .dev_status_get = hw_dev_status_get, .dev_acquisition_start = hw_dev_acquisition_start, .dev_acquisition_stop = hw_dev_acquisition_stop, diff --git a/libsigrok4DSL/hwdriver.c b/libsigrok4DSL/hwdriver.c index 15f3eb4f..be319b5f 100644 --- a/libsigrok4DSL/hwdriver.c +++ b/libsigrok4DSL/hwdriver.c @@ -63,7 +63,7 @@ static struct sr_config_info sr_config_info_data[] = { {SR_CONF_CLOCK_TYPE, SR_T_BOOL, "clocktype", "Using External Clock", "Using External Clock", NULL}, {SR_CONF_CLOCK_EDGE, SR_T_BOOL, "clockedge", - "Using Clock Negedge", "Using Clock Negedge", NULL}, + "Using Clock Negedge", "Using Clock Negedge", NULL}, {SR_CONF_CAPTURE_RATIO, SR_T_UINT64, "captureratio", "Pre-trigger capture ratio", "Pre-trigger capture ratio", NULL}, {SR_CONF_PATTERN_MODE, SR_T_CHAR, "pattern", @@ -72,6 +72,8 @@ static struct sr_config_info sr_config_info_data[] = { "Trigger types", "Trigger types", NULL}, {SR_CONF_RLE, SR_T_BOOL, "rle", "Run Length Encoding", "Run Length Encoding", NULL}, + {SR_CONF_WAIT_UPLOAD, SR_T_BOOL, "buf_upload", + "Wait Buffer Upload", "Wait Buffer Upload", NULL}, {SR_CONF_TRIGGER_SLOPE, SR_T_UINT8, "triggerslope", "Trigger slope", "Trigger slope", NULL}, {SR_CONF_TRIGGER_SOURCE, SR_T_UINT8, "triggersource", @@ -104,6 +106,8 @@ static struct sr_config_info sr_config_info_data[] = { "Datalog", "Datalog", NULL}, {SR_CONF_OPERATION_MODE, SR_T_CHAR, "operation", "Operation Mode", "Operation Mode", NULL}, + {SR_CONF_BUFFER_OPTIONS, SR_T_CHAR, "stopoptions", + "Stop Options", "Stop Options", NULL}, {SR_CONF_CHANNEL_MODE, SR_T_CHAR, "channel", "Channel Mode", "Channel Mode", NULL}, {SR_CONF_THRESHOLD, SR_T_CHAR, "threshold", @@ -322,9 +326,9 @@ SR_API int sr_config_get(const struct sr_dev_driver *driver, * but this is not to be flagged as an error by the caller; merely * as an indication that it's not applicable. */ -SR_API int sr_config_set(const struct sr_dev_inst *sdi, - const struct sr_channel *ch, - const struct sr_channel_group *cg, +SR_API int sr_config_set(struct sr_dev_inst *sdi, + struct sr_channel *ch, + struct sr_channel_group *cg, int key, GVariant *data) { int ret; diff --git a/libsigrok4DSL/input/in_binary.c b/libsigrok4DSL/input/in_binary.c index 00b954a8..ad4d0c9b 100644 --- a/libsigrok4DSL/input/in_binary.c +++ b/libsigrok4DSL/input/in_binary.c @@ -109,6 +109,7 @@ static int loadfile(struct sr_input *in, const char *filename) struct context *ctx; ctx = in->internal; + packet.status = SR_PKT_OK; if ((fd = open(filename, O_RDONLY)) == -1) return SR_ERR; diff --git a/libsigrok4DSL/input/in_vcd.c b/libsigrok4DSL/input/in_vcd.c index 61e72d7d..c69c55bf 100644 --- a/libsigrok4DSL/input/in_vcd.c +++ b/libsigrok4DSL/input/in_vcd.c @@ -299,7 +299,7 @@ static int format_match(const char *filename) gchar *name = NULL, *contents = NULL; gboolean status; - file = g_fopen(filename, "r"); + file = fopen(filename, "r"); if (file == NULL) return FALSE; @@ -563,8 +563,9 @@ static int loadfile(struct sr_input *in, const char *filename) uint64_t samplerate; ctx = in->internal; + packet.status = SR_PKT_OK; - if ((file = g_fopen(filename, "r")) == NULL) + if ((file = fopen(filename, "r")) == NULL) return SR_ERR; if (!parse_header(file, ctx)) diff --git a/libsigrok4DSL/input/in_wav.c b/libsigrok4DSL/input/in_wav.c index 500dc09a..f8d87ed3 100644 --- a/libsigrok4DSL/input/in_wav.c +++ b/libsigrok4DSL/input/in_wav.c @@ -142,6 +142,7 @@ static int loadfile(struct sr_input *in, const char *filename) char buf[CHUNK_SIZE]; ctx = in->sdi->priv; + packet.status = SR_PKT_OK; /* Send header packet to the session bus. */ std_session_send_df_header(in->sdi, LOG_PREFIX); diff --git a/libsigrok4DSL/libsigrok.h b/libsigrok4DSL/libsigrok.h index c40428bb..79afa461 100644 --- a/libsigrok4DSL/libsigrok.h +++ b/libsigrok4DSL/libsigrok.h @@ -107,10 +107,13 @@ enum { #define TriggerStages 16 #define TriggerProbes 16 #define TriggerCountBits 16 +#define STriggerDataStage 3 #define DS_CONF_DSO_HDIVS 10 #define DS_CONF_DSO_VDIVS 10 +#define DS_MAX_TRIG_PERCENT 90 + #define DS_RES_PATH "/usr/local/share/DSView/res/" /** libsigrok loglevels. */ @@ -153,8 +156,6 @@ enum { #define SR_PRIV #endif -typedef int (*sr_receive_data_callback_t)(int fd, int revents, const struct sr_dev_inst *sdi); - /** Data types used by sr_config_info(). */ enum { SR_T_UINT64 = 10000, @@ -178,7 +179,7 @@ enum { SR_DF_ANALOG, SR_DF_FRAME_BEGIN, SR_DF_FRAME_END, - SR_DF_ABANDON, + SR_DF_OVERFLOW, }; /** Values for sr_datafeed_analog.mq. */ @@ -300,10 +301,17 @@ enum DSO_MEASURE_TYPE { DSO_MS_END, }; +enum { + SR_PKT_OK, + SR_PKT_SOURCE_ERROR, + SR_PKT_DATA_ERROR, +}; + struct sr_context; struct sr_datafeed_packet { uint16_t type; + uint16_t status; const void *payload; }; @@ -316,10 +324,21 @@ struct sr_datafeed_meta { GSList *config; }; +enum LA_DATA_FORMAT { + LA_CROSS_DATA, + LA_SPLIT_DATA, +}; + struct sr_datafeed_logic { uint64_t length; + /** data format */ + int format; + /** for LA_SPLIT_DATA, indicate the channel index */ + uint16_t index; + uint16_t order; uint16_t unitsize; uint16_t data_error; + uint64_t error_pattern; void *data; }; @@ -435,13 +454,13 @@ struct sr_output { * A pointer to this output format's 'struct sr_output_format'. * The frontend can use this to call the module's callbacks. */ - struct sr_output_module *module; + const struct sr_output_module *module; /** * The device for which this output module is creating output. This * can be used by the module to find out probe names and numbers. */ - struct sr_dev_inst *sdi; + const struct sr_dev_inst *sdi; /** * An optional parameter which the frontend can pass in to the @@ -644,7 +663,7 @@ struct sr_status { uint64_t ch1_period; uint32_t ch1_pcnt; - uint32_t vlen; + int vlen; gboolean stream_mode; uint32_t sample_divider; gboolean sample_divider_tog; @@ -731,6 +750,9 @@ enum { /** The device supports Run Length Encoding. */ SR_CONF_RLE, + /** Need wait to uplad captured data */ + SR_CONF_WAIT_UPLOAD, + /** The device supports setting trigger slope. */ SR_CONF_TRIGGER_SLOPE, @@ -764,9 +786,12 @@ enum { /** DSO configure sync */ SR_CONF_DSO_SYNC, - /** DSO vertical resolution*/ + /** DSO vertical resolution */ SR_CONF_DSO_BITS, + /** Valid channel number */ + SR_CONF_VLD_CH_NUM, + /** Zero */ SR_CONF_ZERO_SET, SR_CONF_ZERO_LOAD, @@ -790,6 +815,7 @@ enum { /** Test */ SR_CONF_TEST, + SR_CONF_EEPROM, /** Volts/div for dso channel. */ SR_CONF_VDIV, @@ -840,6 +866,9 @@ enum { /** Device operation mode */ SR_CONF_OPERATION_MODE, + /** Device buffer options */ + SR_CONF_BUFFER_OPTIONS, + /** Device channel mode */ SR_CONF_CHANNEL_MODE, @@ -851,12 +880,13 @@ enum { SR_CONF_THRESHOLD, SR_CONF_VTH, - /** Device capacity **/ + /** Hardware capacity **/ SR_CONF_MAX_DSO_SAMPLERATE, SR_CONF_MAX_DSO_SAMPLELIMITS, - SR_CONF_MAX_LOGIC_SAMPLERATE, - SR_CONF_MAX_LOGIC_SAMPLELIMITS, - SR_CONF_RLE_SAMPLELIMITS, + SR_CONF_HW_DEPTH, + + /** Hardware status */ + SR_CONF_HW_STATUS, /*--- Special stuff -------------------------------------------------*/ @@ -876,12 +906,15 @@ enum { /** The device supports specifying a capturefile to inject. */ SR_CONF_CAPTUREFILE, - /** The device supports specifying the capturefile unit size. */ - SR_CONF_CAPTURE_UNITSIZE, + /** Session file version */ + SR_CONF_FILE_VERSION, /** The device supports setting the number of probes. */ SR_CONF_CAPTURE_NUM_PROBES, + /** The device supports setting the number of data blocks. */ + SR_CONF_NUM_BLOCKS, + /*--- Acquisition modes ---------------------------------------------*/ /** @@ -972,6 +1005,8 @@ enum { SR_ST_INITIALIZING, /** The device instance is live, but not in use. */ SR_ST_INACTIVE, + /** The device instance has an imcompatible firmware */ + SR_ST_INCOMPATIBLE, /** The device instance is actively in use in a session. */ SR_ST_ACTIVE, /** The device is winding down its session. */ @@ -991,6 +1026,14 @@ enum { SR_OP_LOOPBACK_TEST = 4, }; +/** Device buffer mode */ +enum { + /** Stop immediately */ + SR_BUF_STOP = 0, + /** Upload captured data */ + SR_BUF_UPLOAD = 1, +}; + /** Device threshold level. */ enum { /** 1.8/2.5/3.3 level */ @@ -1039,9 +1082,9 @@ struct sr_dev_driver { const struct sr_channel *ch, const struct sr_channel_group *cg); int (*config_set) (int id, GVariant *data, - const struct sr_dev_inst *sdi, - const struct sr_channel *ch, - const struct sr_channel_group *cg); + struct sr_dev_inst *sdi, + struct sr_channel *ch, + struct sr_channel_group *cg); int (*config_list) (int info_id, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg); @@ -1049,13 +1092,12 @@ struct sr_dev_driver { /* Device-specific */ int (*dev_open) (struct sr_dev_inst *sdi); int (*dev_close) (struct sr_dev_inst *sdi); - int (*dev_test) (struct sr_dev_inst *sdi); - int (*dev_status_get) (struct sr_dev_inst *sdi, + int (*dev_status_get) (const struct sr_dev_inst *sdi, struct sr_status *status, int begin, int end); - int (*dev_acquisition_start) (const struct sr_dev_inst *sdi, + int (*dev_acquisition_start) (struct sr_dev_inst *sdi, void *cb_data); - int (*dev_acquisition_stop) (struct sr_dev_inst *sdi, + int (*dev_acquisition_stop) (const struct sr_dev_inst *sdi, void *cb_data); /* Dynamic */ @@ -1127,10 +1169,14 @@ struct ds_trigger_pos { uint32_t check_id; uint32_t real_pos; uint32_t ram_saddr; - uint32_t remain_cnt; - unsigned char first_block[496]; + uint32_t remain_cnt_l; + uint32_t remain_cnt_h; + uint32_t status; + unsigned char first_block[488]; }; +typedef int (*sr_receive_data_callback_t)(int fd, int revents, const struct sr_dev_inst *sdi); + #include "proto.h" #include "version.h" diff --git a/libsigrok4DSL/output/csv.c b/libsigrok4DSL/output/csv.c index 3617b61f..9befc92f 100644 --- a/libsigrok4DSL/output/csv.c +++ b/libsigrok4DSL/output/csv.c @@ -236,7 +236,7 @@ static int receive(const struct sr_output *o, const struct sr_datafeed_packet *p *out = g_string_sized_new(512); } - for (i = 0; i < dso->num_samples; i++) { + for (i = 0; i < (uint64_t)dso->num_samples; i++) { for (j = 0; j < ctx->num_enabled_channels; j++) { idx = ctx->channel_index[j]; p = dso->data + i * ctx->num_enabled_channels + idx * ((ctx->num_enabled_channels > 1) ? 1 : 0); diff --git a/libsigrok4DSL/proto.h b/libsigrok4DSL/proto.h index 223f1ec0..547f7742 100644 --- a/libsigrok4DSL/proto.h +++ b/libsigrok4DSL/proto.h @@ -58,13 +58,6 @@ SR_API int sr_dev_clear(const struct sr_dev_driver *driver); SR_API int sr_dev_open(struct sr_dev_inst *sdi); SR_API int sr_dev_close(struct sr_dev_inst *sdi); -/*--- filter.c --------------------------------------------------------------*/ - -SR_API int sr_filter_probes(unsigned int in_unitsize, unsigned int out_unitsize, - const GArray *probe_array, const uint8_t *data_in, - uint64_t length_in, uint8_t **data_out, - uint64_t *length_out); - /*--- hwdriver.c ------------------------------------------------------------*/ SR_API struct sr_dev_driver **sr_driver_list(void); @@ -76,9 +69,9 @@ SR_API int sr_config_get(const struct sr_dev_driver *driver, const struct sr_channel *ch, const struct sr_channel_group *cg, int key, GVariant **data); -SR_API int sr_config_set(const struct sr_dev_inst *sdi, - const struct sr_channel *ch, - const struct sr_channel_group *cg, +SR_API int sr_config_set(struct sr_dev_inst *sdi, + struct sr_channel *ch, + struct sr_channel_group *cg, int key, GVariant *data); SR_API int sr_config_list(const struct sr_dev_driver *driver, const struct sr_dev_inst *sdi, @@ -98,7 +91,7 @@ SR_API int sr_session_load(const char *filename); SR_API struct sr_session *sr_session_new(void); SR_API int sr_session_destroy(void); SR_API int sr_session_dev_remove_all(void); -SR_API int sr_session_dev_add(const struct sr_dev_inst *sdi); +SR_API int sr_session_dev_add(struct sr_dev_inst *sdi); SR_API int sr_session_dev_list(GSList **devlist); /* Datafeed setup */ @@ -110,12 +103,9 @@ SR_API int sr_session_datafeed_callback_add(sr_datafeed_callback_t cb, SR_API int sr_session_start(void); SR_API int sr_session_run(void); SR_API int sr_session_stop(void); -SR_API int sr_session_save(const char *filename, const struct sr_dev_inst *sdi, - unsigned char *buf, int unitsize, uint64_t samples, int64_t trig_time, uint64_t trig_pos); -SR_API int sr_session_save_init(const char *filename, uint64_t samplerate, - char **channels); -SR_API int sr_session_append(const char *filename, unsigned char *buf, - int unitsize, int units); +SR_API int sr_session_save_init(const char *filename, const char *metafile, const char *decfile); +SR_API int sr_session_append(const char *filename, const unsigned char *buf, + uint64_t size, int chunk_num, int index, int type, int version); SR_API int sr_session_source_add(int fd, int events, int timeout, sr_receive_data_callback_t cb, const struct sr_dev_inst *sdi); SR_API int sr_session_source_add_pollfd(GPollFD *pollfd, int timeout, @@ -184,4 +174,10 @@ SR_API int ds_trigger_set_en(uint16_t enable); SR_API uint16_t ds_trigger_get_en(); SR_API int ds_trigger_set_mode(uint16_t mode); +SR_PRIV uint64_t ds_trigger_get_mask0(uint16_t stage); +SR_PRIV uint64_t ds_trigger_get_value0(uint16_t stage); +SR_PRIV uint64_t ds_trigger_get_edge0(uint16_t stage); +SR_PRIV uint64_t ds_trigger_get_mask1(uint16_t stage); +SR_PRIV uint64_t ds_trigger_get_value1(uint16_t stage); +SR_PRIV uint64_t ds_trigger_get_edge1(uint16_t stage); #endif diff --git a/libsigrok4DSL/session.c b/libsigrok4DSL/session.c index 87746adb..83baa4c3 100644 --- a/libsigrok4DSL/session.c +++ b/libsigrok4DSL/session.c @@ -51,7 +51,7 @@ struct source { int timeout; sr_receive_data_callback_t cb; - void *cb_data; + const void *cb_data; /* This is used to keep track of the object (fd, pollfd or channel) which is * being polled and will be used to match the source when removing it again. @@ -187,7 +187,7 @@ SR_API int sr_session_dev_remove_all(void) * * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments. */ -SR_API int sr_session_dev_add(const struct sr_dev_inst *sdi) +SR_API int sr_session_dev_add(struct sr_dev_inst *sdi) { int ret; @@ -406,8 +406,14 @@ SR_API int sr_session_run(void) /* 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->sources[0].cb(-1, 0, session->sources[0].cb_data); + while (session->num_sources) { + if (session->abort_session) { + session->sources[0].cb(-1, -1, session->sources[0].cb_data); + break; + } else { + session->sources[0].cb(-1, 0, session->sources[0].cb_data); + } + } } else { /* Real sources, use g_poll() main loop. */ while (session->num_sources) @@ -528,7 +534,10 @@ static void datafeed_dump(const struct sr_datafeed_packet *packet) case SR_DF_FRAME_END: sr_dbg("bus: Received SR_DF_FRAME_END packet."); break; - default: + case SR_DF_OVERFLOW: + sr_dbg("bus: Received SR_DF_OVERFLOW packet."); + break; + default: sr_dbg("bus: Received unknown packet type: %d.", packet->type); break; } diff --git a/libsigrok4DSL/session_driver.c b/libsigrok4DSL/session_driver.c index d61435ff..31d2da5c 100644 --- a/libsigrok4DSL/session_driver.c +++ b/libsigrok4DSL/session_driver.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include "libsigrok.h" #include "libsigrok-internal.h" @@ -38,51 +40,110 @@ /* size of payloads sent across the session bus */ /** @cond PRIVATE */ #define CHUNKSIZE (512 * 1024) +#define UNITLEN 64 /** @endcond */ static uint64_t samplerates[1]; static uint64_t samplecounts[1]; +static const char *maxHeights[] = { + "1X", + "2X", + "3X", + "4X", + "5X", +}; + struct session_vdev { + int version; char *sessionfile; char *capturefile; struct zip *archive; struct zip_file *capfile; void *buf; + void *logic_buf; int bytes_read; + int cur_channel; + int cur_block; + int num_blocks; + gboolean file_opened; uint64_t samplerate; uint64_t total_samples; int64_t trig_time; uint64_t trig_pos; - int unitsize; int num_probes; + int enabled_probes; uint64_t timebase; + uint8_t bits; + uint8_t max_height; struct sr_status mstatus; }; static GSList *dev_insts = NULL; static const int hwcaps[] = { SR_CONF_CAPTUREFILE, - SR_CONF_CAPTURE_UNITSIZE, - 0, }; +static const int hwoptions[] = { + SR_CONF_MAX_HEIGHT, +}; + +static int trans_data(struct sr_dev_inst *sdi) +{ + // translate for old format + struct session_vdev *vdev = sdi->priv; + GSList *l; + struct sr_channel *probe; + + assert(vdev->buf != NULL); + assert(vdev->logic_buf != NULL); + assert(CHUNKSIZE % UNITLEN == 0); + + //int bytes = ceil(vdev->num_probes / 8.0); + int bytes = 2; + uint8_t *src_ptr = (uint8_t *)vdev->buf; + uint64_t *dest_ptr = (uint64_t *)vdev->logic_buf; + for (int k = 0; k < CHUNKSIZE / (UNITLEN * bytes); k++) { + src_ptr = (uint8_t *)vdev->buf + (k * bytes * UNITLEN); + for (l = sdi->channels; l; l = l->next) { + probe = l->data; + if (!probe->enabled) + continue; + uint64_t mask = 1ULL << probe->index; + uint64_t result = 0; + for (int j = 0; j < UNITLEN; j++) { + if (*(uint64_t *)(src_ptr + j * bytes) & mask) + result += 1ULL << j; + } + *dest_ptr++ = result; + } + } + + return SR_OK; +} + static int receive_data(int fd, int revents, const struct sr_dev_inst *cb_sdi) { struct sr_dev_inst *sdi; - struct session_vdev *vdev; + struct session_vdev *vdev = NULL; struct sr_datafeed_packet packet; struct sr_datafeed_logic logic; struct sr_datafeed_dso dso; struct sr_datafeed_analog analog; GSList *l; - int ret, got_data; + int ret; + char file_name[32]; + struct sr_channel *probe = NULL; + GSList *pl; + int channel; + (void)fd; - (void)revents; + //(void)revents; sr_dbg("Feed chunk."); - got_data = FALSE; + ret = 0; + packet.status = SR_PKT_OK; for (l = dev_insts; l; l = l->next) { sdi = l->data; vdev = sdi->priv; @@ -90,46 +151,104 @@ static int receive_data(int fd, int revents, const struct sr_dev_inst *cb_sdi) /* already done with this instance */ continue; - ret = zip_fread(vdev->capfile, vdev->buf, CHUNKSIZE); - if (ret > 0) { - got_data = TRUE; - if (sdi->mode == DSO) { - packet.type = SR_DF_DSO; - packet.payload = &dso; - dso.num_samples = ret / vdev->unitsize; - dso.data = vdev->buf; - dso.probes = sdi->channels; - dso.mq = SR_MQ_VOLTAGE; - dso.unit = SR_UNIT_VOLT; - dso.mqflags = SR_MQFLAG_AC; - } else if (sdi->mode == ANALOG){ - packet.type = SR_DF_ANALOG; - packet.payload = &analog; - analog.probes = sdi->channels; - analog.num_samples = ret / vdev->unitsize; - analog.mq = SR_MQ_VOLTAGE; - analog.unit = SR_UNIT_VOLT; - analog.mqflags = SR_MQFLAG_AC; - analog.data = vdev->buf; - } else { - packet.type = SR_DF_LOGIC; - packet.payload = &logic; - logic.length = ret; - logic.unitsize = vdev->unitsize; - logic.data = vdev->buf; + assert(vdev->cur_channel >= 0); + if (vdev->cur_channel < vdev->num_probes) { + if (vdev->version == 1) { + ret = zip_fread(vdev->capfile, vdev->buf, CHUNKSIZE); + } else if (vdev->version == 2) { + channel = vdev->cur_channel; + pl = sdi->channels; + while (channel--) + pl = pl->next; + probe = (struct sr_channel *)pl->data; + + if (!vdev->file_opened) { + char *type_name = (probe->type == SR_CHANNEL_LOGIC) ? "L" : + (probe->type == SR_CHANNEL_DSO) ? "O" : + (probe->type == SR_CHANNEL_ANALOG) ? "A" : "U"; + snprintf(file_name, 31, "%s-%d/%d", type_name, + probe->index, vdev->cur_block); + if (!(vdev->capfile = zip_fopen(vdev->archive, file_name, 0))) { + sr_err("Failed to open capture file '%s' in " + "session file '%s'.", file_name, vdev->sessionfile); + } else { + vdev->file_opened = TRUE; + } + } + if (vdev->file_opened) + ret = zip_fread(vdev->capfile, vdev->buf, CHUNKSIZE); } - vdev->bytes_read += ret; - sr_session_send(cb_sdi, &packet); - } else { - /* done with this capture file */ - zip_fclose(vdev->capfile); - //g_free(vdev->capturefile); - //g_free(vdev); - //sdi->priv = NULL; - } + + if (!vdev->file_opened) { + packet.type = SR_DF_END; + packet.status = SR_PKT_SOURCE_ERROR; + sr_session_send(cb_sdi, &packet); + sr_session_source_remove(-1); + return FALSE; + } + + if (ret > 0) { + if (sdi->mode == DSO) { + packet.type = SR_DF_DSO; + packet.payload = &dso; + dso.num_samples = ret / vdev->enabled_probes; + dso.data = vdev->buf; + dso.probes = sdi->channels; + dso.mq = SR_MQ_VOLTAGE; + dso.unit = SR_UNIT_VOLT; + dso.mqflags = SR_MQFLAG_AC; + } else if (sdi->mode == ANALOG){ + packet.type = SR_DF_ANALOG; + packet.payload = &analog; + analog.probes = sdi->channels; + analog.num_samples = ret / vdev->num_probes; + analog.mq = SR_MQ_VOLTAGE; + analog.unit = SR_UNIT_VOLT; + analog.mqflags = SR_MQFLAG_AC; + analog.data = vdev->buf; + } else { + packet.type = SR_DF_LOGIC; + packet.payload = &logic; + logic.length = ret; + logic.format = (vdev->version == 2) ? LA_SPLIT_DATA : LA_CROSS_DATA; + if (probe) + logic.index = probe->index; + else + logic.index = 0; + logic.order = vdev->cur_channel; + + if (vdev->version == 1) { + logic.length = ret / 16 * vdev->enabled_probes; + logic.data = vdev->logic_buf; + trans_data(sdi); + } else if (vdev->version == 2) { + logic.length = ret; + logic.data = vdev->buf; + } + } + vdev->bytes_read += ret; + sr_session_send(cb_sdi, &packet); + } else { + /* done with this capture file */ + zip_fclose(vdev->capfile); + + if (vdev->version == 1) { + vdev->cur_channel++; + } else if (vdev->version == 2) { + vdev->file_opened = FALSE; + vdev->cur_block++; + if (vdev->cur_block == vdev->num_blocks) { + vdev->cur_block = 0; + vdev->cur_channel++; + } + } + } + } } - if (!got_data) { + if (!vdev || + vdev->cur_channel >= vdev->num_probes || + revents == -1) { packet.type = SR_DF_END; sr_session_send(cb_sdi, &packet); sr_session_source_remove(-1); @@ -169,12 +288,18 @@ static int dev_open(struct sr_dev_inst *sdi) struct session_vdev *vdev; vdev = sdi->priv; - if (!(vdev->buf = g_try_malloc(CHUNKSIZE))) { + if (!(vdev->buf = g_try_malloc(CHUNKSIZE + sizeof(uint64_t)))) { sr_err("%s: vdev->buf malloc failed", __func__); return SR_ERR_MALLOC; } vdev->trig_pos = 0; vdev->trig_time = 0; + vdev->cur_block = 0; + vdev->cur_channel = 0; + vdev->file_opened = FALSE; + vdev->num_blocks = 0; + vdev->bits = 8; + vdev->max_height = 0; dev_insts = g_slist_append(dev_insts, sdi); @@ -187,6 +312,8 @@ static int dev_close(struct sr_dev_inst *sdi) g_free(vdev->sessionfile); g_free(vdev->capturefile); g_free(vdev->buf); + if (vdev->logic_buf) + g_free(vdev->logic_buf); g_free(sdi->priv); sdi->priv = NULL; @@ -198,6 +325,8 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel *ch, const struct sr_channel_group *cg) { + (void)cg; + struct session_vdev *vdev; switch (id) { @@ -229,6 +358,13 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, } else return SR_ERR; break; + case SR_CONF_DSO_BITS: + if (sdi) { + vdev = sdi->priv; + *data = g_variant_new_byte(vdev->bits); + } else + return SR_ERR; + break; case SR_CONF_EN_CH: if (sdi && ch) { *data = g_variant_new_boolean(ch->enabled); @@ -259,18 +395,53 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, } else return SR_ERR; break; + case SR_CONF_TRIGGER_VALUE: + if (sdi && ch) { + *data = g_variant_new_byte(ch->trig_value); + } else + return SR_ERR; + break; case SR_CONF_MAX_DSO_SAMPLERATE: if (!sdi) return SR_ERR; + vdev = sdi->priv; *data = g_variant_new_uint64(vdev->samplerate); break; case SR_CONF_MAX_DSO_SAMPLELIMITS: if (!sdi) return SR_ERR; + vdev = sdi->priv; *data = g_variant_new_uint64(vdev->total_samples); break; - case SR_CONF_RLE_SAMPLELIMITS: - *data = g_variant_new_uint64(UINT64_MAX); + case SR_CONF_HW_DEPTH: + if (!sdi) + return SR_ERR; + vdev = sdi->priv; + *data = g_variant_new_uint64(vdev->total_samples); + break; + case SR_CONF_MAX_HEIGHT: + if (!sdi) + return SR_ERR; + vdev = sdi->priv; + *data = g_variant_new_string(maxHeights[vdev->max_height]); + break; + case SR_CONF_MAX_HEIGHT_VALUE: + if (!sdi) + return SR_ERR; + vdev = sdi->priv; + *data = g_variant_new_byte(vdev->max_height); + break; + case SR_CONF_VLD_CH_NUM: + if (!sdi) + return SR_ERR; + vdev = sdi->priv; + *data = g_variant_new_int16(vdev->num_probes); + break; + case SR_CONF_FILE_VERSION: + if (!sdi) + return SR_ERR; + vdev = sdi->priv; + *data = g_variant_new_int16(vdev->version); break; default: return SR_ERR_ARG; @@ -279,11 +450,15 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, return SR_OK; } -static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi, +static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, struct sr_channel *ch, - const struct sr_channel_group *cg) + struct sr_channel_group *cg) { + (void)cg; + struct session_vdev *vdev; + const char *stropt; + unsigned int i; vdev = sdi->priv; @@ -297,6 +472,10 @@ static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi, vdev->timebase = g_variant_get_uint64(data); sr_info("Setting timebase to %" PRIu64 ".", vdev->timebase); break; + case SR_CONF_DSO_BITS: + vdev->bits = g_variant_get_byte(data); + sr_info("Setting DSO bits to %d.", vdev->bits); + break; case SR_CONF_SESSIONFILE: vdev->sessionfile = g_strdup(g_variant_get_bytestring(data)); sr_info("Setting sessionfile to '%s'.", vdev->sessionfile); @@ -305,9 +484,10 @@ static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi, vdev->capturefile = g_strdup(g_variant_get_bytestring(data)); sr_info("Setting capturefile to '%s'.", vdev->capturefile); break; - case SR_CONF_CAPTURE_UNITSIZE: - vdev->unitsize = g_variant_get_uint64(data); - break; + case SR_CONF_FILE_VERSION: + vdev->version = g_variant_get_int16(data); + sr_info("Setting file version to '%d'.", vdev->version); + break; case SR_CONF_LIMIT_SAMPLES: vdev->total_samples = g_variant_get_uint64(data); samplecounts[0] = vdev->total_samples; @@ -321,8 +501,17 @@ static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi, vdev->trig_pos = g_variant_get_uint64(data); sr_info("Setting trigger position to %" PRIu64 ".", vdev->trig_pos); break; + case SR_CONF_NUM_BLOCKS: + vdev->num_blocks = g_variant_get_uint64(data); + sr_info("Setting block number to %" PRIu64 ".", vdev->num_blocks); + break; case SR_CONF_CAPTURE_NUM_PROBES: vdev->num_probes = g_variant_get_uint64(data); + if (sdi->mode == LOGIC) { + if (!(vdev->logic_buf = g_try_malloc(CHUNKSIZE/16*vdev->num_probes))) { + sr_err("%s: vdev->logic_buf malloc failed", __func__); + } + } break; case SR_CONF_EN_CH: ch->enabled = g_variant_get_boolean(data); @@ -339,6 +528,9 @@ static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi, case SR_CONF_VPOS: ch->vpos = g_variant_get_double(data); break; + case SR_CONF_TRIGGER_VALUE: + ch->trig_value = g_variant_get_byte(data); + break; case SR_CONF_STATUS_PERIOD: if (ch->index == 0) vdev->mstatus.ch0_period = g_variant_get_uint64(data); @@ -363,6 +555,17 @@ static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi, else vdev->mstatus.ch1_min = g_variant_get_uint64(data); break; + case SR_CONF_MAX_HEIGHT: + stropt = g_variant_get_string(data, NULL); + for (i = 0; i < ARRAY_SIZE(maxHeights); i++) { + if (!strcmp(stropt, maxHeights[i])) { + vdev->max_height = i; + break; + } + } + sr_dbg("%s: setting Signal Max Height to %d", + __func__, vdev->max_height); + break; default: sr_err("Unknown capability: %d.", id); return SR_ERR; @@ -371,8 +574,12 @@ static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi, return SR_OK; } -static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi) +static int config_list(int key, GVariant **data, + const struct sr_dev_inst *sdi, + const struct sr_channel_group *cg) { + (void)cg; + GVariant *gvar; GVariantBuilder gvb; @@ -385,6 +592,12 @@ static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi) *data = g_variant_new_from_data(G_VARIANT_TYPE("ai"), hwcaps, ARRAY_SIZE(hwcaps)*sizeof(int32_t), TRUE, NULL, NULL); break; + case SR_CONF_DEVICE_CONFIGS: +// *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, +// hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t)); + *data = g_variant_new_from_data(G_VARIANT_TYPE("ai"), + hwoptions, ARRAY_SIZE(hwoptions)*sizeof(int32_t), TRUE, NULL, NULL); + break; case SR_CONF_SAMPLERATE: g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}")); // gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), samplerates, @@ -401,14 +614,17 @@ static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi) g_variant_builder_add(&gvb, "{sv}", "samplecounts", gvar); *data = g_variant_builder_end(&gvb); break; - default: + case SR_CONF_MAX_HEIGHT: + *data = g_variant_new_strv(maxHeights, ARRAY_SIZE(maxHeights)); + break; + default: return SR_ERR_ARG; } return SR_OK; } -static int dev_status_get(struct sr_dev_inst *sdi, struct sr_status *status, int begin, int end) +static int dev_status_get(const struct sr_dev_inst *sdi, struct sr_status *status, int begin, int end) { (void)begin; (void)end; @@ -424,15 +640,21 @@ static int dev_status_get(struct sr_dev_inst *sdi, struct sr_status *status, int } } -static int dev_acquisition_start(const struct sr_dev_inst *sdi, +static int dev_acquisition_start(struct sr_dev_inst *sdi, void *cb_data) { + (void)cb_data; + struct zip_stat zs; struct session_vdev *vdev; struct sr_datafeed_packet packet; int ret; + GSList *l; + struct sr_channel *probe; vdev = sdi->priv; + vdev->enabled_probes = 0; + packet.status = SR_PKT_OK; sr_info("Opening archive %s file %s", vdev->sessionfile, vdev->capturefile); @@ -443,17 +665,29 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, return SR_ERR; } - if (zip_stat(vdev->archive, vdev->capturefile, 0, &zs) == -1) { - sr_err("Failed to check capture file '%s' in " - "session file '%s'.", vdev->capturefile, vdev->sessionfile); - return SR_ERR; - } + if (vdev->version == 1) { + if (zip_stat(vdev->archive, vdev->capturefile, 0, &zs) == -1) { + sr_err("Failed to check capture file '%s' in " + "session file '%s'.", vdev->capturefile, vdev->sessionfile); + return SR_ERR; + } - if (!(vdev->capfile = zip_fopen(vdev->archive, vdev->capturefile, 0))) { - sr_err("Failed to open capture file '%s' in " - "session file '%s'.", vdev->capturefile, vdev->sessionfile); - return SR_ERR; - } + if (!(vdev->capfile = zip_fopen(vdev->archive, vdev->capturefile, 0))) { + sr_err("Failed to open capture file '%s' in " + "session file '%s'.", vdev->capturefile, vdev->sessionfile); + return SR_ERR; + } + vdev->file_opened = TRUE; + vdev->cur_channel = vdev->num_probes - 1; + } else { + vdev->cur_channel = 0; + } + + for (l = sdi->channels; l; l = l->next) { + probe = l->data; + if (probe->enabled) + vdev->enabled_probes++; + } /* Send header packet to the session bus. */ std_session_send_df_header(sdi, LOG_PREFIX); @@ -461,7 +695,10 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, /* Send trigger packet to the session bus */ if (vdev->trig_pos != 0) { struct ds_trigger_pos session_trigger; - session_trigger.real_pos = vdev->trig_pos; + if (sdi->mode == DSO) + session_trigger.real_pos = vdev->trig_pos * vdev->enabled_probes / vdev->num_probes; + else + session_trigger.real_pos = vdev->trig_pos; packet.type = SR_DF_TRIGGER; packet.payload = &session_trigger; sr_session_send(sdi, &packet); @@ -489,7 +726,6 @@ SR_PRIV struct sr_dev_driver session_driver = { .config_list = config_list, .dev_open = dev_open, .dev_close = dev_close, - .dev_test = NULL, .dev_status_get = dev_status_get, .dev_acquisition_start = dev_acquisition_start, .dev_acquisition_stop = NULL, diff --git a/libsigrok4DSL/session_file.c b/libsigrok4DSL/session_file.c index bf5b27c5..5b03ddba 100644 --- a/libsigrok4DSL/session_file.c +++ b/libsigrok4DSL/session_file.c @@ -121,16 +121,17 @@ SR_API int sr_session_load(const char *filename) struct zip_stat zs; struct sr_dev_inst *sdi; struct sr_channel *probe; - int ret, devcnt, i, j, k; + int ret, devcnt, i, j; uint16_t probenum; uint64_t tmp_u64, total_probes, enabled_probes; uint16_t p; int64_t tmp_64; - char **sections, **keys, *metafile, *val, s[11]; + char **sections, **keys, *metafile, *val; char probename[SR_MAX_PROBENAME_LEN + 1]; int mode = LOGIC; int channel_type = SR_CHANNEL_LOGIC; double tmp_double; + int version = 1; if (!filename) { sr_err("%s: filename was NULL", __func__); @@ -169,9 +170,15 @@ SR_API int sr_session_load(const char *filename) capturefiles = g_ptr_array_new_with_free_func(g_free); sections = g_key_file_get_groups(kf, NULL); for (i = 0; sections[i]; i++) { - if (!strcmp(sections[i], "version")) - /* nothing really interesting in here yet */ - continue; + if (!strcmp(sections[i], "version")) { + keys = g_key_file_get_keys(kf, sections[i], NULL, NULL); + for (j = 0; keys[j]; j++) { + val = g_key_file_get_string(kf, sections[i], keys[j], NULL); + if (!strcmp(keys[j], "version")) { + version = strtoull(val, NULL, 10); + } + } + } if (!strncmp(sections[i], "header", 6)) { /* device section */ sdi = NULL; @@ -194,14 +201,12 @@ SR_API int sr_session_load(const char *filename) sdi->driver->config_set(SR_CONF_CAPTUREFILE, g_variant_new_bytestring(val), sdi, NULL, NULL); g_ptr_array_add(capturefiles, val); + sdi->driver->config_set(SR_CONF_FILE_VERSION, + g_variant_new_int16(version), sdi, NULL, NULL); } else if (!strcmp(keys[j], "samplerate")) { sr_parse_sizestring(val, &tmp_u64); sdi->driver->config_set(SR_CONF_SAMPLERATE, g_variant_new_uint64(tmp_u64), sdi, NULL, NULL); - } else if (!strcmp(keys[j], "unitsize")) { - tmp_u64 = strtoull(val, NULL, 10); - sdi->driver->config_set(SR_CONF_CAPTURE_UNITSIZE, - g_variant_new_uint64(tmp_u64), sdi, NULL, NULL); } else if (!strcmp(keys[j], "total samples")) { tmp_u64 = strtoull(val, NULL, 10); sdi->driver->config_set(SR_CONF_LIMIT_SAMPLES, @@ -210,6 +215,10 @@ SR_API int sr_session_load(const char *filename) tmp_u64 = strtoull(val, NULL, 10); sdi->driver->config_set(SR_CONF_TIMEBASE, g_variant_new_uint64(tmp_u64), sdi, NULL, NULL); + } else if (!strcmp(keys[j], "bits")) { + tmp_u64 = strtoull(val, NULL, 10); + sdi->driver->config_set(SR_CONF_DSO_BITS, + g_variant_new_byte(tmp_u64), sdi, NULL, NULL); } else if (!strcmp(keys[j], "trigger time")) { tmp_64 = strtoll(val, NULL, 10); sdi->driver->config_set(SR_CONF_TRIGGER_TIME, @@ -218,27 +227,42 @@ SR_API int sr_session_load(const char *filename) tmp_u64 = strtoull(val, NULL, 10); sdi->driver->config_set(SR_CONF_TRIGGER_POS, g_variant_new_uint64(tmp_u64), sdi, NULL, NULL); + } else if (!strcmp(keys[j], "total blocks")) { + tmp_u64 = strtoull(val, NULL, 10); + sdi->driver->config_set(SR_CONF_NUM_BLOCKS, + g_variant_new_uint64(tmp_u64), sdi, NULL, NULL); } else if (!strcmp(keys[j], "total probes")) { total_probes = strtoull(val, NULL, 10); sdi->driver->config_set(SR_CONF_CAPTURE_NUM_PROBES, g_variant_new_uint64(total_probes), sdi, NULL, NULL); - channel_type = (mode == DSO) ? SR_CHANNEL_DSO : - (mode == ANALOG) ? SR_CHANNEL_ANALOG : SR_CHANNEL_LOGIC; - for (p = 0; p < total_probes; p++) { - snprintf(probename, SR_MAX_PROBENAME_LEN, "%" PRIu64, p); - if (!(probe = sr_channel_new(p, channel_type, FALSE, - probename))) - return SR_ERR; - sdi->channels = g_slist_append(sdi->channels, probe); - } + if (version == 1) { + channel_type = (mode == DSO) ? SR_CHANNEL_DSO : + (mode == ANALOG) ? SR_CHANNEL_ANALOG : SR_CHANNEL_LOGIC; + for (p = 0; p < total_probes; p++) { + snprintf(probename, SR_MAX_PROBENAME_LEN, "%u", p); + if (!(probe = sr_channel_new(p, channel_type, FALSE, + probename))) + return SR_ERR; + sdi->channels = g_slist_append(sdi->channels, probe); + } + } } else if (!strncmp(keys[j], "probe", 5)) { if (!sdi) continue; enabled_probes++; tmp_u64 = strtoul(keys[j]+5, NULL, 10); /* sr_session_save() */ - sr_dev_probe_name_set(sdi, tmp_u64, val); - sr_dev_probe_enable(sdi, tmp_u64, TRUE); + if (version == 1) { + sr_dev_probe_name_set(sdi, tmp_u64, val); + sr_dev_probe_enable(sdi, tmp_u64, TRUE); + } else if (version == 2) { + channel_type = (mode == DSO) ? SR_CHANNEL_DSO : + (mode == ANALOG) ? SR_CHANNEL_ANALOG : SR_CHANNEL_LOGIC; + if (!(probe = sr_channel_new(tmp_u64, channel_type, TRUE, + val))) + return SR_ERR; + sdi->channels = g_slist_append(sdi->channels, probe); + } } else if (!strncmp(keys[j], "trigger", 7)) { probenum = strtoul(keys[j]+7, NULL, 10); sr_dev_trigger_set(sdi, probenum, val); @@ -282,6 +306,14 @@ SR_API int sr_session_load(const char *filename) sdi->driver->config_set(SR_CONF_VPOS, g_variant_new_double(tmp_double), sdi, probe, NULL); } + } else if (!strncmp(keys[j], "vTrig", 5)) { + probenum = strtoul(keys[j]+5, NULL, 10); + tmp_u64 = strtod(val, NULL); + if (probenum < g_slist_length(sdi->channels)) { + probe = g_slist_nth(sdi->channels, probenum)->data; + sdi->driver->config_set(SR_CONF_TRIGGER_VALUE, + g_variant_new_byte(tmp_u64), sdi, probe, NULL); + } } else if (!strncmp(keys[j], "period", 6)) { probenum = strtoul(keys[j]+6, NULL, 10); tmp_u64 = strtoull(val, NULL, 10); @@ -326,137 +358,6 @@ SR_API int sr_session_load(const char *filename) return SR_OK; } -/** - * Save the current session to the specified file. - * - * @param filename The name of the filename to save the current session as. - * Must not be NULL. - * @param sdi The device instance from which the data was captured. - * @param buf The data to be saved. - * @param unitsize The number of bytes per sample. - * @param units The number of samples. - * - * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments, or SR_ERR - * upon other errors. - */ -SR_API int sr_session_save(const char *filename, const struct sr_dev_inst *sdi, - unsigned char *buf, int unitsize, uint64_t samples, int64_t trig_time, uint64_t trig_pos) -{ - GSList *l; - GVariant *gvar; - FILE *meta; - struct sr_channel *probe; - struct zip *zipfile; - struct zip_source *versrc, *metasrc, *logicsrc; - int tmpfile, ret, probecnt; - uint64_t samplerate, timeBase, tmp_u64; - char rawname[16], metafile[32], *s; - struct sr_status status; - - if (!filename) { - sr_err("%s: filename was NULL", __func__); - return SR_ERR_ARG; - } - - /* Quietly delete it first, libzip wants replace ops otherwise. */ - unlink(filename); - if (!(zipfile = zip_open(filename, ZIP_CREATE, &ret))) - return SR_ERR; - - /* init "metadata" */ - strcpy(metafile, "DSView-meta-XXXXXX"); - if ((tmpfile = g_mkstemp(metafile)) == -1) - return SR_ERR; - close(tmpfile); - meta = g_fopen(metafile, "wb"); - fprintf(meta, "[version]\n"); - fprintf(meta, "DSView version = %s\n", PACKAGE_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); - } - - /* metadata */ - fprintf(meta, "capturefile = data\n"); - fprintf(meta, "unitsize = %d\n", unitsize); - fprintf(meta, "total samples = %llu\n", samples); - fprintf(meta, "total probes = %d\n", g_slist_length(sdi->channels)); - if (sr_config_get(sdi->driver, sdi, NULL, NULL, SR_CONF_SAMPLERATE, - &gvar) == SR_OK) { - samplerate = g_variant_get_uint64(gvar); - s = sr_samplerate_string(samplerate); - fprintf(meta, "samplerate = %s\n", s); - g_free(s); - g_variant_unref(gvar); - } - if (sdi->mode == DSO && - sr_config_get(sdi->driver, sdi, NULL, NULL, SR_CONF_TIMEBASE, &gvar) == SR_OK) { - timeBase = g_variant_get_uint64(gvar); - fprintf(meta, "hDiv = %llu\n", timeBase); - g_variant_unref(gvar); - } else if (sdi->mode == LOGIC) { - fprintf(meta, "trigger time = %lld\n", trig_time); - } - fprintf(meta, "trigger pos = %llu\n", trig_pos); - - probecnt = 1; - for (l = sdi->channels; l; l = l->next) { - probe = l->data; - if (probe->enabled || sdi->mode == DSO) { - if (probe->name) - fprintf(meta, "probe%d = %s\n", probe->index, probe->name); - if (probe->trigger) - fprintf(meta, " trigger%d = %s\n", probe->index, probe->trigger); - if (sdi->mode == DSO) { - fprintf(meta, " enable%d = %d\n", probe->index, probe->enabled); - fprintf(meta, " coupling%d = %d\n", probe->index, probe->coupling); - fprintf(meta, " vDiv%d = %d\n", probe->index, probe->vdiv); - fprintf(meta, " vFactor%d = %d\n", probe->index, probe->vfactor); - fprintf(meta, " vPos%d = %lf\n", probe->index, probe->vpos); - if (sr_status_get(sdi, &status, 0, 0) == SR_OK) { - if (probe->index == 0) { - fprintf(meta, " period%d = %llu\n", probe->index, status.ch0_period); - fprintf(meta, " pcnt%d = %lu\n", probe->index, status.ch0_pcnt); - fprintf(meta, " max%d = %d\n", probe->index, status.ch0_max); - fprintf(meta, " min%d = %d\n", probe->index, status.ch0_min); - } else { - fprintf(meta, " period%d = %llu\n", probe->index, status.ch1_period); - fprintf(meta, " pcnt%d = %lu\n", probe->index, status.ch1_pcnt); - fprintf(meta, " max%d = %d\n", probe->index, status.ch1_max); - fprintf(meta, " min%d = %d\n", probe->index, status.ch1_min); - } - } - } - probecnt++; - } - } - - if (!(logicsrc = zip_source_buffer(zipfile, buf, - samples * unitsize, FALSE))) - return SR_ERR; - snprintf(rawname, 15, "data"); - if (zip_add(zipfile, rawname, logicsrc) == -1) - return SR_ERR; - fclose(meta); - - if (!(metasrc = zip_source_file(zipfile, metafile, 0, -1))) - return SR_ERR; - if (zip_add(zipfile, "header", metasrc) == -1) - return SR_ERR; - - if ((ret = zip_close(zipfile)) == -1) { - sr_info("error saving zipfile: %s", zip_strerror(zipfile)); - return SR_ERR; - } - - unlink(metafile); - - return SR_OK; -} - /** * Initialize a saved session file. * @@ -472,14 +373,11 @@ SR_API int sr_session_save(const char *filename, const struct sr_dev_inst *sdi, * * @since 0.3.0 */ -SR_API int sr_session_save_init(const char *filename, uint64_t samplerate, - char **channels) +SR_API int sr_session_save_init(const char *filename, const char *metafile, const char *decfile) { - FILE *meta; struct zip *zipfile; - struct zip_source *versrc, *metasrc; - int tmpfile, cnt, ret, i; - char version[1], metafile[32], *s; + struct zip_source *metasrc; + int ret; if (!filename) { sr_err("%s: filename was NULL", __func__); @@ -491,59 +389,41 @@ SR_API int sr_session_save_init(const char *filename, uint64_t samplerate, if (!(zipfile = zip_open(filename, ZIP_CREATE, &ret))) return SR_ERR; - /* "version" */ - version[0] = '2'; - if (!(versrc = zip_source_buffer(zipfile, version, 1, 0))) - return SR_ERR; - if (zip_add(zipfile, "version", versrc) == -1) { - sr_info("error saving version into zipfile: %s", - zip_strerror(zipfile)); - return SR_ERR; - } - - /* init "metadata" */ - strcpy(metafile, "sigrok-meta-XXXXXX"); - if ((tmpfile = g_mkstemp(metafile)) == -1) - return SR_ERR; - close(tmpfile); - meta = g_fopen(metafile, "wb"); - fprintf(meta, "[global]\n"); - fprintf(meta, "sigrok version = %s\n", PACKAGE_VERSION); - - /* metadata */ - fprintf(meta, "[device 1]\n"); - - /* metadata */ - fprintf(meta, "capturefile = logic-1\n"); - cnt = 0; - for (i = 0; channels[i]; i++) - cnt++; - fprintf(meta, "total probes = %d\n", cnt); - s = sr_samplerate_string(samplerate); - fprintf(meta, "samplerate = %s\n", s); - g_free(s); - - for (i = 0; channels[i]; i++) - fprintf(meta, "probe%d = %s\n", i + 1, channels[i]); - - fclose(meta); - + // meta file if (!(metasrc = zip_source_file(zipfile, metafile, 0, -1))) { unlink(metafile); return SR_ERR; } - if (zip_add(zipfile, "metadata", metasrc) == -1) { + + if (zip_add(zipfile, "header", metasrc) == -1) { unlink(metafile); return SR_ERR; } + // decoders file + if (decfile != NULL) { + if (!(metasrc = zip_source_file(zipfile, decfile, 0, -1))) { + unlink(decfile); + return SR_ERR; + } + + if (zip_add(zipfile, "decoders", metasrc) == -1) { + unlink(decfile); + return SR_ERR; + } + } + if ((ret = zip_close(zipfile)) == -1) { sr_info("error saving zipfile: %s", zip_strerror(zipfile)); unlink(metafile); + if (decfile != NULL) + unlink(decfile); return SR_ERR; } unlink(metafile); + if (decfile != NULL) + unlink(decfile); return SR_OK; } @@ -556,8 +436,10 @@ SR_API int sr_session_save_init(const char *filename, uint64_t samplerate, * * @param filename The name of the filename to append to. Must not be NULL. * @param buf The data to be appended. - * @param unitsize The number of bytes per sample. - * @param samples The number of samples. + * @param size Buffer size. + * @param chunk_num chunk number + * @param index channel index + * @param type channel type * * @retval SR_OK Success * @retval SR_ERR_ARG Invalid arguments @@ -565,119 +447,39 @@ SR_API int sr_session_save_init(const char *filename, uint64_t samplerate, * * @since 0.3.0 */ -SR_API int sr_session_append(const char *filename, unsigned char *buf, - int unitsize, int units) +SR_API int sr_session_append(const char *filename, const unsigned char *buf, + uint64_t size, int chunk_num, int index, int type, int version) { struct zip *archive; struct zip_source *logicsrc; - zip_int64_t num_files; - struct zip_file *zf; - struct zip_stat zs; - struct zip_source *metasrc; - GKeyFile *kf; - GError *error; - gsize len; - int chunk_num, next_chunk_num, tmpfile, ret, i; - const char *entry_name; - char *metafile, tmpname[32], chunkname[16]; + int ret; + char chunk_name[16], *type_name; - if ((ret = sr_sessionfile_check(filename)) != SR_OK) - return ret; +// if ((ret = sr_sessionfile_check(filename)) != SR_OK) +// return ret; if (!(archive = zip_open(filename, 0, &ret))) return SR_ERR; - if (zip_stat(archive, "metadata", 0, &zs) == -1) - return SR_ERR; + if (version == 2) { + 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"); + } - metafile = g_malloc(zs.size); - zf = zip_fopen_index(archive, zs.index, 0); - zip_fread(zf, metafile, zs.size); - zip_fclose(zf); - - /* - * If the file was only initialized but doesn't yet have any - * data it in, it won't have a unitsize field in metadata yet. - */ - error = NULL; - kf = g_key_file_new(); - if (!g_key_file_load_from_data(kf, metafile, zs.size, 0, &error)) { - sr_err("Failed to parse metadata: %s.", error->message); + if (!(logicsrc = zip_source_buffer(archive, buf, size, FALSE))) { return SR_ERR; } - g_free(metafile); - tmpname[0] = '\0'; - if (!g_key_file_has_key(kf, "device 1", "unitsize", &error)) { - if (error && error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) { - sr_err("Failed to check unitsize key: %s", error ? error->message : "?"); - return SR_ERR; - } - /* Add unitsize field. */ - g_key_file_set_integer(kf, "device 1", "unitsize", unitsize); - metafile = g_key_file_to_data(kf, &len, &error); - strcpy(tmpname, "sigrok-meta-XXXXXX"); - if ((tmpfile = g_mkstemp(tmpname)) == -1) - return SR_ERR; - if (write(tmpfile, metafile, len) < 0) { - sr_dbg("Failed to create new metadata: %s", strerror(errno)); - g_free(metafile); - unlink(tmpname); - return SR_ERR; - } - close(tmpfile); - if (!(metasrc = zip_source_file(archive, tmpname, 0, -1))) { - sr_err("Failed to create zip source for metadata."); - g_free(metafile); - unlink(tmpname); - return SR_ERR; - } - if (zip_replace(archive, zs.index, metasrc) == -1) { - sr_err("Failed to replace metadata file."); - g_free(metafile); - unlink(tmpname); - return SR_ERR; - } - g_free(metafile); - } - g_key_file_free(kf); - - next_chunk_num = 1; - num_files = zip_get_num_entries(archive, 0); - for (i = 0; i < num_files; i++) { - entry_name = zip_get_name(archive, i, 0); - if (strncmp(entry_name, "logic-1", 7)) - continue; - if (strlen(entry_name) == 7) { - /* This file has no extra chunks, just a single "logic-1". - * Rename it to "logic-1-1" * and continue with chunk 2. */ - if (zip_rename(archive, i, "logic-1-1") == -1) { - sr_err("Failed to rename 'logic-1' to 'logic-1-1'."); - unlink(tmpname); - return SR_ERR; - } - next_chunk_num = 2; - break; - } else if (strlen(entry_name) > 8 && entry_name[7] == '-') { - chunk_num = strtoull(entry_name + 8, NULL, 10); - if (chunk_num >= next_chunk_num) - next_chunk_num = chunk_num + 1; - } - } - snprintf(chunkname, 15, "logic-1-%d", next_chunk_num); - if (!(logicsrc = zip_source_buffer(archive, buf, units * unitsize, FALSE))) { - unlink(tmpname); - return SR_ERR; - } - if (zip_add(archive, chunkname, logicsrc) == -1) { - unlink(tmpname); + if (zip_file_add(archive, chunk_name, logicsrc, ZIP_FL_OVERWRITE) == -1) { return SR_ERR; } if ((ret = zip_close(archive)) == -1) { sr_info("error saving session file: %s", zip_strerror(archive)); - unlink(tmpname); return SR_ERR; } - unlink(tmpname); return SR_OK; } diff --git a/libsigrok4DSL/std.c b/libsigrok4DSL/std.c index cfe031d9..7ade9755 100644 --- a/libsigrok4DSL/std.c +++ b/libsigrok4DSL/std.c @@ -89,6 +89,7 @@ SR_PRIV int std_session_send_df_header(const struct sr_dev_inst *sdi, /* Send header packet to the session bus. */ sr_dbg("%sSending SR_DF_HEADER packet.", prefix); packet.type = SR_DF_HEADER; + packet.status = SR_PKT_OK; packet.payload = (uint8_t *)&header; header.feed_version = 1; gettimeofday(&header.starttime, NULL); @@ -152,6 +153,7 @@ SR_PRIV int std_hw_dev_acquisition_stop_serial(struct sr_dev_inst *sdi, /* Send SR_DF_END packet to the session bus. */ sr_dbg("%sSending SR_DF_END packet.", prefix); packet.type = SR_DF_END; + packet.status = SR_PKT_OK; packet.payload = NULL; if ((ret = sr_session_send(cb_data, &packet)) < 0) { sr_err("%sFailed to send SR_DF_END packet: %d.", prefix, ret); diff --git a/libsigrok4DSL/trigger.c b/libsigrok4DSL/trigger.c index 0f572640..f9d80956 100644 --- a/libsigrok4DSL/trigger.c +++ b/libsigrok4DSL/trigger.c @@ -177,7 +177,6 @@ SR_API int ds_trigger_set_stage(uint16_t stages) SR_API int ds_trigger_set_pos(uint16_t position) { assert(position <= 100); - assert(position >= 0); trigger->trigger_pos = position; @@ -245,7 +244,7 @@ SR_PRIV uint64_t ds_trigger_get_mask0(uint16_t stage) for (i = TriggerProbes - 1; i >= 0 ; i--) { mask = (mask << 1); - mask += (trigger->trigger0[stage][i] == 'X' | trigger->trigger0[stage][i] == 'C'); + mask += (trigger->trigger0[stage][i] == 'X' || trigger->trigger0[stage][i] == 'C'); } return mask; @@ -259,7 +258,7 @@ SR_PRIV uint64_t ds_trigger_get_mask1(uint16_t stage) for (i = TriggerProbes - 1; i >= 0 ; i--) { mask = (mask << 1); - mask += (trigger->trigger1[stage][i] == 'X' | trigger->trigger1[stage][i] == 'C'); + mask += ((trigger->trigger1[stage][i] == 'X') | (trigger->trigger1[stage][i] == 'C')); } return mask; @@ -273,7 +272,7 @@ SR_PRIV uint64_t ds_trigger_get_value0(uint16_t stage) for (i = TriggerProbes - 1; i >= 0 ; i--) { value = (value << 1); - value += (trigger->trigger0[stage][i] == '1' | trigger->trigger0[stage][i] == 'R'); + value += ((trigger->trigger0[stage][i] == '1') | (trigger->trigger0[stage][i] == 'R')); } return value; @@ -287,7 +286,7 @@ SR_PRIV uint64_t ds_trigger_get_value1(uint16_t stage) for (i = TriggerProbes - 1; i >= 0 ; i--) { value = (value << 1); - value += (trigger->trigger1[stage][i] == '1' | trigger->trigger1[stage][i] == 'R'); + value += ((trigger->trigger1[stage][i] == '1') | (trigger->trigger1[stage][i] == 'R')); } return value; @@ -301,8 +300,8 @@ SR_PRIV uint64_t ds_trigger_get_edge0(uint16_t stage) for (i = TriggerProbes - 1; i >= 0 ; i--) { edge = (edge << 1); - edge += (trigger->trigger0[stage][i] == 'R' | trigger->trigger0[stage][i] == 'F' | - trigger->trigger0[stage][i] == 'C'); + edge += ((trigger->trigger0[stage][i] == 'R') | (trigger->trigger0[stage][i] == 'F') | + (trigger->trigger0[stage][i] == 'C')); } return edge; @@ -316,8 +315,8 @@ SR_PRIV uint64_t ds_trigger_get_edge1(uint16_t stage) for (i = TriggerProbes - 1; i >= 0 ; i--) { edge = (edge << 1); - edge += (trigger->trigger1[stage][i] == 'R' | trigger->trigger1[stage][i] == 'F' | - trigger->trigger1[stage][i] == 'C'); + edge += ((trigger->trigger1[stage][i] == 'R') | (trigger->trigger1[stage][i] == 'F') | + (trigger->trigger1[stage][i] == 'C')); } return edge; diff --git a/libsigrokdecode4DSL/Makefile.am b/libsigrokdecode4DSL/Makefile.am index 02f76d9e..3141f2f3 100644 --- a/libsigrokdecode4DSL/Makefile.am +++ b/libsigrokdecode4DSL/Makefile.am @@ -28,9 +28,9 @@ AM_CPPFLAGS = -DDECODERS_DIR='"$(DECODERS_DIR)"' # The tests CFLAGS are a superset of the libsigrokdecode CFLAGS. AM_CFLAGS = $(SRD_EXTRA_CFLAGS) $(SRD_WFLAGS) $(TESTS_CFLAGS) -lib_LTLIBRARIES = libsigrokdecode.la +lib_LTLIBRARIES = libsigrokdecode4DSL.la -libsigrokdecode_la_SOURCES = \ +libsigrokdecode4DSL_la_SOURCES = \ srd.c \ session.c \ decoder.c \ @@ -44,15 +44,15 @@ libsigrokdecode_la_SOURCES = \ error.c \ version.c -libsigrokdecode_la_LIBADD = $(SRD_EXTRA_LIBS) $(LIBSIGROKDECODE_LIBS) -libsigrokdecode_la_LDFLAGS = -version-info $(SRD_LIB_VERSION) -no-undefined +libsigrokdecode4DSL_la_LIBADD = $(SRD_EXTRA_LIBS) $(LIBSIGROKDECODE_LIBS) +libsigrokdecode4DSL_la_LDFLAGS = -version-info $(SRD_LIB_VERSION) -no-undefined pkginclude_HEADERS = libsigrokdecode.h nodist_pkginclude_HEADERS = version.h noinst_HEADERS = libsigrokdecode-internal.h pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = libsigrokdecode.pc +pkgconfig_DATA = libsigrokdecode4DSL.pc EXTRA_DIST = Doxyfile HACKING contrib/sigrok-logo-notext.png @@ -71,7 +71,7 @@ tests_main_SOURCES = \ tests/session.c tests_main_CPPFLAGS = -DDECODERS_DIR='"$(abs_top_srcdir)/decoders"' -tests_main_LDADD = libsigrokdecode.la $(SRD_EXTRA_LIBS) $(TESTS_LIBS) +tests_main_LDADD = libsigrokdecode4DSL.la $(SRD_EXTRA_LIBS) $(TESTS_LIBS) MAINTAINERCLEANFILES = ChangeLog diff --git a/libsigrokdecode4DSL/NEWS b/libsigrokdecode4DSL/NEWS index ec40143b..a98c7fb9 100644 --- a/libsigrokdecode4DSL/NEWS +++ b/libsigrokdecode4DSL/NEWS @@ -1,3 +1,235 @@ +0.4.1 (2016-12-27) +------------------ + +Note: This release does NOT change the libsigrokdecode public C API. This +means existing libsigrokdecode frontends should not require any changes. +However, individual PDs and their output changed, which may require +some adaptations on the user's side in some cases. + + * New supported protocol decoders: + - aud Renesas/Hitachi Advanced User Debugger (AUD) protocol + - avr_pdi Atmel proprietary interface for the ATxmega MCU + - dmx512 Professional lighting control protocol + - em4305 EM4205/EM4305 100-150kHz RFID protocol + - gpib IEEE-488 GPIB / HPIB protocol + - ps2 PS/2 keyboard/mouse interface + - rgb_led_ws281x RGB LED string protocol (WS281x) + - ssi32 Synchronous Serial Interface (32bit) protocol + - t55xx T55xx 100-150kHz RFID protocol + - wiegand Wiegand interface for electronic entry systems + * Introduce a decoders/common facility for code shared between PDs (bug #804). + * Supply metadata to all stacked decoders, not just low-level ones (bug #664). + * Various Doxygen/documentation improvements. + * Factor out a srd_decoder_apiver() internal helper function. + * srd_inst_decode(): Return SRD_ERR_ARG if unitsize is 0. + * Print error messages when decoders fail load time checks (bug #704). + * Fix multiple valgrind warnings (memory leaks and such). + * Build system: Sort PD list alphabetically in "make install". + * mdio: + - Replace PD with a new implementation that also supports Clause 22 and 45. + - Improve annotations slightly. + * xfp: + - Move various constants to common/plugtrx for reusability purposes. + * sdcard_{sd,spi}: + - Move various constants to common/sdcard for reusability purposes. + * usb_request: + - Drop hardcoded samplerate (workaround for the fixed bug #664). + * spiflash: + - Handle CS# transitions, allow variable-length transfers. + - Handle "Fast Read Dual I/O" commands. + - Add a "format" decoder option. + - Implement Release Power-down / Device ID (0xAB) command (bug #845). + - Remove hardcoded Macronix references. + - Add initial FIDELIX FM25Q32 metadata/support. + - Implement WRSR, RDSR2 commands. + - Various annotation improvements. + * timing: + - Add frequency and averaging support. + * midi: + - Decode note names and percussion names (e.g. 'G2', 'Tambourine'). + - Decode instrument names and drum_kit names (e.g. 'GS Orchestra Kit'). + - Handle Polyphonic Pressure / Aftertouch (message 0xAn). + - Handle Program Change (message 0xCn). + - Handle Channel Pressure / Aftertouch (message 0xDn). + - Handle Channel Mode (message 0xBn mm where mm is 120 through 127). + - Handle System Common messages (message 0xF1 through 0xF6), including + full time code decoding. + - SysEx decoding now decodes the 1-3 byte manufacturer field, payload + is now displayed as hex. + - 'undefined' fields now display the value (e.g. 'undefined 0xf4'). + - Add 'MSB' and 'LSB' to many control_functions entries. + - Fix "trapped in state X" bug with handle_channel_msg_generic(), + though this might be dead code. + - Fix bug in sysex_manufacturer_ids; 1-byte manufacturers were not + tuples due to missing comma. + - Fix bug in SysEx state machine; 0xF7 now sent to handle_sysex_msg(). + - Annotations: Provide multiple string versions (shorter and longer ones). + - chromatic_notes in list.py was off by 1 octave. + - Handle "Running Status" where status byte can be omitted. + - SysEx message can be terminated by status byte, not just EOX. + - Handle SysReal messages that interrupt in-progress message transmission. + - Identify and print garbage / truncated data. + - Add 2 new annotations: text-sysreal-verbose and text-error. + * usb_power_delivery: + - Drop problematic exception in us2samples() function (bug #758). + * uart: + - Fix a bug in the output for stacked PDs (when there's RX/TX overlap). + - Various output formatting improvements (e.g. for ASCII and octal). + - Skip frames with invalid start bits. + - Emit 2 bytes for 9-bit UART binary output (bug #708). + - Default to hex format datavalue annotations. + * spi: + - Fix binary output for wordsizes > 8 (bug #686). + * Various decoders: + - Fix some incorrect PD license metadata fields. + - Fix typos, whitespace issues and random other cosmetics in some PDs. + - Use consistent __init__() format across all PDs. + - Move some duplicated code snippets/lists to decoders/common. + +0.4.0 (2016-01-29) +------------------ + +Note: This release DOES change the libsigrokdecode public C API. This +means it is NOT backwards-compatible and frontends will need updates. + + * New supported protocol decoders: + - adns5020 Bidirectional command and data over an SPI-like protocol + - am230x Aosong AM230x/DHTxx/RHTxx humidity/temperature sensor + - arm_etmv3 Decode ETM instruction trace packets + - arm_itm Trace data from Cortex-M / ARMv7m ITM module + - arm_tpiu Filter TPIU formatted trace data into separate streams + - eeprom24xx 24xx series I²C EEPROM protocol + - em4100 EM4100 100-150kHz RFID protocol + - jitter Retrieves the timing jitter between two digital signals + - max7219 8-digit LED display driver + - mdio Half-duplex sync serial bus for MII management (MAC/PHY) + - modbus Modbus RTU protocol for industrial applications + - mrf24j40 IEEE 802.15.4 2.4 GHz RF tranceiver chip + - nrf24l01 2.4GHz transceiver chip + - pwm Analog level encoded in duty cycle percentage + - qi Async serial protocol for Qi charger receivers + - rfm12 HopeRF RFM12 wireless transceiver control protocol + - sdcard_sd Secure Digital card (SD mode) low-level protocol + - spdif Serial bus for connecting digital audio devices + - stepper_motor Absolute position and movement speed from step/dir + - swd Two-wire protocol for debug access to ARM CPUs + - tca6408a Texas Instruments TCA6408A 8-bit I²C I/O expander + - timing Calculate time between edges + - usb_power_delivery USB Power Delivery protocol + - usb_request USB (low-speed and full-speed) transaction/request protocol + * The 'mx25lxx05d' decoder was renamed to 'spiflash' and made more generic. + * arm_itm: + - Use objdump instead of addr2line (bug #564). + * can: + - Emit bit value annotations. + - Improve stuff bit annotation placement. + * ds1307: + - Emit per-bit annotations for registers. + - Add more annotation classes (and annotation rows). + - Handle register 0x07 (control register). + - Handle SRAM register accesses. + - Correctly handle address wrap-around. + - Warn about (and ignore) non-DS1307 traffic. + * edid: + - Handle more EDID structure sections. + - Add annotation rows. + * jitter: + - Avoid Unicode string literals (bug #569). + * jtag: + - Fix/enable OUT_PYTHON output. + - Add more annotations, fix a SHIFT-IR/-DR issue. + * jtag_stm32: + - Fix incorrect handling of registers. + - Decode more fields, improve IDCODE handling. + - Decode IDCODE contents as strings (not just hex values). + * midi: + - Fix two incorrect sample numbers. + - Update for a change (emit databyte/bits at the same time) in the uart PD. + * mrf24j40: + - Fix a register address typo. + * nunchuk: + - Fix inverted button press logic. + * pan1321: + - Update for a change (emit databyte/bits at the same time) in the uart PD. + * onewire_link: + - Fix a bug when the samplerate is too low for the PD (bug #357). + * parallel: + - Enforce that at least one pin must be provided. + * pwm: + - Avoid Unicode string literals (bug #569). + * spi: + - OUT_PYTHON docs: Fix order of MISO/MOSI data items. + - Tell stacked decoders about missing CS# signal. + - Add binary output facilities for MISO/MOSI (bug #424). + - Don't decode data lines if CS# isn't asserted (bug #559). + - Add a 'TRANSFER' output type. + * spiflash: + - Implement FAST READ command. + - Add a 'chip' option in preparation for supporting more devices. + - Fix incorrect 'inputs' field. + * tlc5620: + - Fix incorrect DAC selection decode, add more annotations. + - Only decode the last 11 bits, ignore the rest. + - Properly handle LOAD and LDAC based operations. + - Handle the case of less than 11 bits in a command. + - Add options for per-DAC Vref, show voltages. + * uart: + - Add signal inversion options 'invert_tx' and 'invert_rx'. + - Emit databyte and bits list at the same time to simplify stacked PDs. + - Improve sample positions at high data rates. + - Handle framing errors better. + - Performance-optimize handling of samples when TX and RX are both idle. + * usb_packet: + - Fix incorrect DATA*/MDATA handling (bug #623). + - Handle invalid packets more gracefully (bug #186). + - Calculate and check CRC5/CRC16. + - Handle errors from usb_signalling. + - Handle PREamble transmissions. + * usb_request: + - Handle transmission timeouts. + - Handle PREamble transmissions. + * usb_signalling: + - Track USB symbol width to compensate frequency errors. + - Detect bit stuffing errors. + - Handle symbol errors in EOP state. + - Use explicit positions for packet start/end (avoids glitches). + - Decode RESET and Keep-Alive signalling conditions. + - Add option to automatically set signalling speed. + - Fix SOP detection after an error condition. + - Add signalling states needed after LS PREamble PID. + - Detect PREamble PID. + * Drop the PD testing framework. It's in the 'sigrok-test' repository now + (and is not meant for "end users" or distro packages anyway; it's a pure + developer tool/system). This also fixes some PD test related build issues. + * Makefile.am: Use libtool's -no-undefined option (fixes MinGW shared build). + * Support loading decoders stored in ZIP files. + * Updated build requirements: + - libglib >= 2.28.0 + - Drop obsolete (optional) dependencies: python3-coverage, libsigrok. + * README: Use clearer descriptions for the dependencies. + * Remove all references to the obsolete sigrok-commits mailing list. + * Fix incorrect doxygen comment for srd_decoder_list() function (bug #378). + * configure.ac: + - Fix a shell portability issue ("==" vs. "="). + - Use AM_CFLAGS instead of CFLAGS. + - Only link the 'check' library into the unit tests (not the lib). + * Unit tests: + - Fix out-of-tree build. + * libsigrokdecode.pc (pkg-config) file: + - Fix an issue related to the Python lib dependencies. + - Publish decodersdir variable. + * Add "-git-" suffix to development version numbers. + * Pass unitsize per sample chunk (bug #352). + * Modernize the whole autotools setup. + * Build with _POSIX_C_SOURCE=200112L per default. + * Build: Show CC and CFLAGS in configuration summary. + * Also look for decoders in XDG data directories. + * Restrict Python code to stable ABI subset (PEP 384). + * Fix various memory leaks. + * Fix an issue with PDs not being properly removed upon unload. + * Don't let Python override signal handlers (bug #461). + * configure: Also check for Python 3.5 (bug #739). + 0.3.0 (2014-05-06) ------------------ diff --git a/libsigrokdecode4DSL/README b/libsigrokdecode4DSL/README index 302c653e..686efeff 100644 --- a/libsigrokdecode4DSL/README +++ b/libsigrokdecode4DSL/README @@ -34,7 +34,7 @@ Requirements - automake >= 1.11 (only needed when building from git) - libtool (only needed when building from git) - pkg-config >= 0.22 - - libglib >= 2.24.0 + - libglib >= 2.28.0 - Python >= 3.2 - check >= 0.9.4 (optional, only needed to run unit tests) - doxygen (optional, only needed for the C API docs) diff --git a/libsigrokdecode4DSL/configure.ac b/libsigrokdecode4DSL/configure.ac index 53e8bc1a..02b2f3a6 100644 --- a/libsigrokdecode4DSL/configure.ac +++ b/libsigrokdecode4DSL/configure.ac @@ -21,9 +21,9 @@ AC_PREREQ([2.63]) # libsigrokdecode package version number (NOT the same as shared lib version!). -AC_INIT([libsigrokdecode], [0.4.0], - [sigrok-devel@lists.sourceforge.net], [libsigrokdecode], - [http://www.sigrok.org]) +AC_INIT([libsigrokdecode4DSL], [0.4.0], + [support@dreamsourcelab.com], [libsigrokdecode4DSL], + [http://www.dreamsourcelab.com]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_AUX_DIR([autostuff]) AC_CONFIG_HEADERS([config.h version.h]) @@ -133,7 +133,7 @@ PKG_CHECK_MODULES([TESTS], [$SRD_PKGLIBS_TESTS glib-2.0 $SRD_PKGLIBS]) srd_glib_version=`$PKG_CONFIG --modversion glib-2.0 2>&AS_MESSAGE_LOG_FD` -AC_CONFIG_FILES([Makefile libsigrokdecode.pc]) +AC_CONFIG_FILES([Makefile libsigrokdecode4DSL.pc]) AC_OUTPUT diff --git a/libsigrokdecode4DSL/decoder.c b/libsigrokdecode4DSL/decoder.c index 98463168..27dcbed0 100644 --- a/libsigrokdecode4DSL/decoder.c +++ b/libsigrokdecode4DSL/decoder.c @@ -40,7 +40,7 @@ /** @cond PRIVATE */ -/* The list of protocol decoders. */ +/* The list of loaded protocol decoders. */ static GSList *pd_list = NULL; /* srd.c */ @@ -65,7 +65,7 @@ static gboolean srd_check_init(void) } /** - * Returns the list of supported/loaded protocol decoders. + * Returns the list of loaded protocol decoders. * * This is a GSList of pointers to struct srd_decoder items. * @@ -101,197 +101,530 @@ SRD_API struct srd_decoder *srd_decoder_get_by_id(const char *id) return NULL; } +static void channel_free(void *data) +{ + struct srd_channel *ch = data; + + if (!ch) + return; + + g_free(ch->desc); + g_free(ch->name); + g_free(ch->id); + g_free(ch); +} + +static void variant_free(void *data) +{ + GVariant *var = data; + + if (!var) + return; + + g_variant_unref(var); +} + +static void annotation_row_free(void *data) +{ + struct srd_decoder_annotation_row *row = data; + + if (!row) + return; + + g_slist_free(row->ann_classes); + g_free(row->desc); + g_free(row->id); + g_free(row); +} + +static void decoder_option_free(void *data) +{ + struct srd_decoder_option *opt = data; + + if (!opt) + return; + + g_slist_free_full(opt->values, &variant_free); + variant_free(opt->def); + g_free(opt->desc); + g_free(opt->id); + g_free(opt); +} + +static void decoder_free(struct srd_decoder *dec) +{ + if (!dec) + return; + + Py_XDECREF(dec->py_dec); + Py_XDECREF(dec->py_mod); + + g_slist_free_full(dec->options, &decoder_option_free); + g_slist_free_full(dec->binary, (GDestroyNotify)&g_strfreev); + g_slist_free_full(dec->annotation_rows, &annotation_row_free); + g_slist_free_full(dec->annotations, (GDestroyNotify)&g_strfreev); + g_slist_free_full(dec->opt_channels, &channel_free); + g_slist_free_full(dec->channels, &channel_free); + + g_free(dec->license); + g_free(dec->desc); + g_free(dec->longname); + g_free(dec->name); + g_free(dec->id); + + g_free(dec); +} + static int get_channels(const struct srd_decoder *d, const char *attr, - GSList **pdchl) + GSList **out_pdchl, int offset) { PyObject *py_channellist, *py_entry; struct srd_channel *pdch; - int ret, num_channels, i; + GSList *pdchl; + ssize_t i; if (!PyObject_HasAttrString(d->py_dec, attr)) /* No channels of this type specified. */ return SRD_OK; + pdchl = NULL; + py_channellist = PyObject_GetAttrString(d->py_dec, attr); + if (!py_channellist) + goto except_out; + if (!PyTuple_Check(py_channellist)) { srd_err("Protocol decoder %s %s attribute is not a tuple.", - d->name, attr); - return SRD_ERR_PYTHON; + d->name, attr); + goto err_out; } - if ((num_channels = PyTuple_Size(py_channellist)) == 0) - /* Empty channellist. */ - return SRD_OK; - - ret = SRD_OK; - for (i = 0; i < num_channels; i++) { + for (i = PyTuple_Size(py_channellist) - 1; i >= 0; i--) { py_entry = PyTuple_GetItem(py_channellist, i); + if (!py_entry) + goto except_out; + if (!PyDict_Check(py_entry)) { srd_err("Protocol decoder %s %s attribute is not " - "a list with dict elements.", d->name, attr); - ret = SRD_ERR_PYTHON; - break; + "a list of dict elements.", d->name, attr); + goto err_out; } + pdch = g_malloc0(sizeof(struct srd_channel)); + /* Add to list right away so it doesn't get lost. */ + pdchl = g_slist_prepend(pdchl, pdch); - pdch = g_malloc(sizeof(struct srd_channel)); + if (py_dictitem_as_str(py_entry, "id", &pdch->id) != SRD_OK) + goto err_out; + if (py_dictitem_as_str(py_entry, "name", &pdch->name) != SRD_OK) + goto err_out; + if (py_dictitem_as_str(py_entry, "desc", &pdch->desc) != SRD_OK) + goto err_out; - if ((py_dictitem_as_str(py_entry, "id", &pdch->id)) != SRD_OK) { - ret = SRD_ERR_PYTHON; - break; - } - if ((py_dictitem_as_str(py_entry, "name", &pdch->name)) != SRD_OK) { - ret = SRD_ERR_PYTHON; - break; - } - if ((py_dictitem_as_str(py_entry, "desc", &pdch->desc)) != SRD_OK) { - ret = SRD_ERR_PYTHON; - break; - } - pdch->order = i; - - *pdchl = g_slist_append(*pdchl, pdch); + pdch->type = py_dictitem_to_int(py_entry, "type"); + if (pdch->type < 0) + pdch->type = SRD_CHANNEL_COMMON; + pdch->order = offset + i; } - Py_DecRef(py_channellist); + Py_DECREF(py_channellist); + *out_pdchl = pdchl; - return ret; + return SRD_OK; + +except_out: + srd_exception_catch(NULL, "Failed to get %s list of %s decoder", + attr, d->name); +err_out: + g_slist_free_full(pdchl, &channel_free); + Py_XDECREF(py_channellist); + + return SRD_ERR_PYTHON; } static int get_options(struct srd_decoder *d) { - PyObject *py_opts, *py_opt, *py_val, *py_default, *py_item; - Py_ssize_t opt, i; + PyObject *py_opts, *py_opt, *py_str, *py_values, *py_default, *py_item; + GSList *options; struct srd_decoder_option *o; GVariant *gvar; - gint64 lval; - double dval; - int overflow; - char *sval; + ssize_t opt, i; if (!PyObject_HasAttrString(d->py_dec, "options")) /* No options, that's fine. */ return SRD_OK; + options = NULL; + /* If present, options must be a tuple. */ py_opts = PyObject_GetAttrString(d->py_dec, "options"); + if (!py_opts) + goto except_out; + if (!PyTuple_Check(py_opts)) { srd_err("Protocol decoder %s: options attribute is not " "a tuple.", d->id); - return SRD_ERR_PYTHON; + goto err_out; } - for (opt = 0; opt < PyTuple_Size(py_opts); opt++) { + for (opt = PyTuple_Size(py_opts) - 1; opt >= 0; opt--) { py_opt = PyTuple_GetItem(py_opts, opt); + if (!py_opt) + goto except_out; + if (!PyDict_Check(py_opt)) { srd_err("Protocol decoder %s options: each option " "must consist of a dictionary.", d->name); - return SRD_ERR_PYTHON; - } - if (!(py_val = PyDict_GetItemString(py_opt, "id"))) { - srd_err("Protocol decoder %s option %zd has no " - "id.", d->name, opt); - return SRD_ERR_PYTHON; + goto err_out; } + o = g_malloc0(sizeof(struct srd_decoder_option)); - py_str_as_str(py_val, &o->id); + /* Add to list right away so it doesn't get lost. */ + options = g_slist_prepend(options, o); - if ((py_val = PyDict_GetItemString(py_opt, "desc"))) - py_str_as_str(py_val, &o->desc); + py_str = PyDict_GetItemString(py_opt, "id"); + if (!py_str) { + srd_err("Protocol decoder %s option %zd has no id.", + d->name, opt); + goto err_out; + } + if (py_str_as_str(py_str, &o->id) != SRD_OK) + goto err_out; - if ((py_default = PyDict_GetItemString(py_opt, "default"))) { - if (PyUnicode_Check(py_default)) { - /* UTF-8 string */ - py_str_as_str(py_default, &sval); - o->def = g_variant_new_string(sval); - g_free(sval); - } else if (PyLong_Check(py_default)) { - /* Long */ - lval = PyLong_AsLongAndOverflow(py_default, &overflow); - if (overflow) { - /* Value is < LONG_MIN or > LONG_MAX */ - PyErr_Clear(); - srd_err("Protocol decoder %s option 'default' has " - "invalid default value.", d->name); - return SRD_ERR_PYTHON; - } - o->def = g_variant_new_int64(lval); - } else if (PyFloat_Check(py_default)) { - /* Float */ - if ((dval = PyFloat_AsDouble(py_default)) == -1.0) { - PyErr_Clear(); - srd_err("Protocol decoder %s option 'default' has " - "invalid default value.", d->name); - return SRD_ERR_PYTHON; - } - o->def = g_variant_new_double(dval); - } else { - srd_err("Protocol decoder %s option 'default' has " - "value of unsupported type '%s'.", d->name, - Py_TYPE(py_default)->tp_name); - return SRD_ERR_PYTHON; - } - g_variant_ref_sink(o->def); + py_str = PyDict_GetItemString(py_opt, "desc"); + if (py_str) { + if (py_str_as_str(py_str, &o->desc) != SRD_OK) + goto err_out; } - if ((py_val = PyDict_GetItemString(py_opt, "values"))) { + py_default = PyDict_GetItemString(py_opt, "default"); + if (py_default) { + gvar = py_obj_to_variant(py_default); + if (!gvar) { + srd_err("Protocol decoder %s option 'default' has " + "invalid default value.", d->name); + goto err_out; + } + o->def = g_variant_ref_sink(gvar); + } + + py_values = PyDict_GetItemString(py_opt, "values"); + if (py_values) { /* A default is required if a list of values is * given, since it's used to verify their type. */ if (!o->def) { - srd_err("No default for option '%s'", o->id); - return SRD_ERR_PYTHON; + srd_err("No default for option '%s'.", o->id); + goto err_out; } - if (!PyTuple_Check(py_val)) { + if (!PyTuple_Check(py_values)) { srd_err("Option '%s' values should be a tuple.", o->id); - return SRD_ERR_PYTHON; + goto err_out; } - for (i = 0; i < PyTuple_Size(py_val); i++) { - py_item = PyTuple_GetItem(py_val, i); + + for (i = PyTuple_Size(py_values) - 1; i >= 0; i--) { + py_item = PyTuple_GetItem(py_values, i); + if (!py_item) + goto except_out; + if (Py_TYPE(py_default) != Py_TYPE(py_item)) { srd_err("All values for option '%s' must be " - "of the same type as the default.", - o->id); - return SRD_ERR_PYTHON; + "of the same type as the default.", + o->id); + goto err_out; } - if (PyUnicode_Check(py_item)) { - /* UTF-8 string */ - py_str_as_str(py_item, &sval); - gvar = g_variant_new_string(sval); - g_variant_ref_sink(gvar); - g_free(sval); - o->values = g_slist_append(o->values, gvar); - } else if (PyLong_Check(py_item)) { - /* Long */ - lval = PyLong_AsLongAndOverflow(py_item, &overflow); - if (overflow) { - /* Value is < LONG_MIN or > LONG_MAX */ - PyErr_Clear(); - srd_err("Protocol decoder %s option 'values' " - "has invalid value.", d->name); - return SRD_ERR_PYTHON; - } - gvar = g_variant_new_int64(lval); - g_variant_ref_sink(gvar); - o->values = g_slist_append(o->values, gvar); - } else if (PyFloat_Check(py_item)) { - /* Float */ - if ((dval = PyFloat_AsDouble(py_item)) == -1.0) { - PyErr_Clear(); - srd_err("Protocol decoder %s option 'default' has " - "invalid default value.", d->name); - return SRD_ERR_PYTHON; - } - gvar = g_variant_new_double(dval); - g_variant_ref_sink(gvar); - o->values = g_slist_append(o->values, gvar); + gvar = py_obj_to_variant(py_item); + if (!gvar) { + srd_err("Protocol decoder %s option 'values' " + "contains invalid value.", d->name); + goto err_out; } + o->values = g_slist_prepend(o->values, + g_variant_ref_sink(gvar)); } } - d->options = g_slist_append(d->options, o); + } + d->options = options; + Py_DECREF(py_opts); + + return SRD_OK; + +except_out: + srd_exception_catch(NULL, "Failed to get %s decoder options", d->name); +err_out: + g_slist_free_full(options, &decoder_option_free); + Py_XDECREF(py_opts); + + return SRD_ERR_PYTHON; +} + +/* Convert annotation class attribute to GSList of char **. + */ +static int get_annotations(struct srd_decoder *dec) +{ + PyObject *py_annlist, *py_ann; + GSList *annotations; + char **annpair; + ssize_t i; + int ann_type = 7; + unsigned int j; + + if (!PyObject_HasAttrString(dec->py_dec, "annotations")) + return SRD_OK; + + annotations = NULL; + + py_annlist = PyObject_GetAttrString(dec->py_dec, "annotations"); + if (!py_annlist) + goto except_out; + + if (!PyTuple_Check(py_annlist)) { + srd_err("Protocol decoder %s annotations should " + "be a tuple.", dec->name); + goto err_out; + } + + for (i = 0; i < PyTuple_Size(py_annlist); i++) { + py_ann = PyTuple_GetItem(py_annlist, i); + if (!py_ann) + goto except_out; + + if (!PyTuple_Check(py_ann) || (PyTuple_Size(py_ann) != 3 && PyTuple_Size(py_ann) != 2)) { + srd_err("Protocol decoder %s annotation %zd should " + "be a tuple with two or three elements.", + dec->name, i); + goto err_out; + } + if (py_strseq_to_char(py_ann, &annpair) != SRD_OK) + goto err_out; + + annotations = g_slist_prepend(annotations, annpair); + + if (PyTuple_Size(py_ann) == 3) { + ann_type = 0; + for (j = 0; j < strlen(annpair[0]); j++) + ann_type = ann_type * 10 + (annpair[0][j] - '0'); + dec->ann_types = g_slist_append(dec->ann_types, GINT_TO_POINTER(ann_type)); + } else if (PyTuple_Size(py_ann) == 2) { + dec->ann_types = g_slist_append(dec->ann_types, GINT_TO_POINTER(ann_type)); + ann_type++; + } + } + dec->annotations = annotations; + Py_DECREF(py_annlist); + + return SRD_OK; + +except_out: + srd_exception_catch(NULL, "Failed to get %s decoder annotations", dec->name); +err_out: + g_slist_free_full(annotations, (GDestroyNotify)&g_strfreev); + Py_XDECREF(py_annlist); + + return SRD_ERR_PYTHON; +} + +/* Convert annotation_rows to GSList of 'struct srd_decoder_annotation_row'. + */ +static int get_annotation_rows(struct srd_decoder *dec) +{ + PyObject *py_ann_rows, *py_ann_row, *py_ann_classes, *py_item; + GSList *annotation_rows; + struct srd_decoder_annotation_row *ann_row; + ssize_t i, k; + size_t class_idx; + + if (!PyObject_HasAttrString(dec->py_dec, "annotation_rows")) + return SRD_OK; + + annotation_rows = NULL; + + py_ann_rows = PyObject_GetAttrString(dec->py_dec, "annotation_rows"); + if (!py_ann_rows) + goto except_out; + + if (!PyTuple_Check(py_ann_rows)) { + srd_err("Protocol decoder %s annotation_rows " + "must be a tuple.", dec->name); + goto err_out; + } + + for (i = PyTuple_Size(py_ann_rows) - 1; i >= 0; i--) { + py_ann_row = PyTuple_GetItem(py_ann_rows, i); + if (!py_ann_row) + goto except_out; + + if (!PyTuple_Check(py_ann_row) || PyTuple_Size(py_ann_row) != 3) { + srd_err("Protocol decoder %s annotation_rows " + "must contain only tuples of 3 elements.", + dec->name); + goto err_out; + } + ann_row = g_malloc0(sizeof(struct srd_decoder_annotation_row)); + /* Add to list right away so it doesn't get lost. */ + annotation_rows = g_slist_prepend(annotation_rows, ann_row); + + py_item = PyTuple_GetItem(py_ann_row, 0); + if (!py_item) + goto except_out; + if (py_str_as_str(py_item, &ann_row->id) != SRD_OK) + goto err_out; + + py_item = PyTuple_GetItem(py_ann_row, 1); + if (!py_item) + goto except_out; + if (py_str_as_str(py_item, &ann_row->desc) != SRD_OK) + goto err_out; + + py_ann_classes = PyTuple_GetItem(py_ann_row, 2); + if (!py_ann_classes) + goto except_out; + + if (!PyTuple_Check(py_ann_classes)) { + srd_err("Protocol decoder %s annotation_rows tuples " + "must have a tuple of numbers as 3rd element.", + dec->name); + goto err_out; + } + + for (k = PyTuple_Size(py_ann_classes) - 1; k >= 0; k--) { + py_item = PyTuple_GetItem(py_ann_classes, k); + if (!py_item) + goto except_out; + + if (!PyLong_Check(py_item)) { + srd_err("Protocol decoder %s annotation row " + "class tuple must only contain numbers.", + dec->name); + goto err_out; + } + class_idx = PyLong_AsSize_t(py_item); + if (PyErr_Occurred()) + goto except_out; + + ann_row->ann_classes = g_slist_prepend(ann_row->ann_classes, + GSIZE_TO_POINTER(class_idx)); + } + } + dec->annotation_rows = annotation_rows; + Py_DECREF(py_ann_rows); + + return SRD_OK; + +except_out: + srd_exception_catch(NULL, "Failed to get %s decoder annotation rows", + dec->name); +err_out: + g_slist_free_full(annotation_rows, &annotation_row_free); + Py_XDECREF(py_ann_rows); + + return SRD_ERR_PYTHON; +} + +/* Convert binary classes to GSList of char **. + */ +static int get_binary_classes(struct srd_decoder *dec) +{ + PyObject *py_bin_classes, *py_bin_class; + GSList *bin_classes; + char **bin; + ssize_t i; + + if (!PyObject_HasAttrString(dec->py_dec, "binary")) + return SRD_OK; + + bin_classes = NULL; + + py_bin_classes = PyObject_GetAttrString(dec->py_dec, "binary"); + if (!py_bin_classes) + goto except_out; + + if (!PyTuple_Check(py_bin_classes)) { + srd_err("Protocol decoder %s binary classes should " + "be a tuple.", dec->name); + goto err_out; + } + + for (i = PyTuple_Size(py_bin_classes) - 1; i >= 0; i--) { + py_bin_class = PyTuple_GetItem(py_bin_classes, i); + if (!py_bin_class) + goto except_out; + + if (!PyTuple_Check(py_bin_class) + || PyTuple_Size(py_bin_class) != 2) { + srd_err("Protocol decoder %s binary classes should " + "consist only of tuples of 2 elements.", + dec->name); + goto err_out; + } + if (py_strseq_to_char(py_bin_class, &bin) != SRD_OK) + goto err_out; + + bin_classes = g_slist_prepend(bin_classes, bin); + } + dec->binary = bin_classes; + Py_DECREF(py_bin_classes); + + return SRD_OK; + +except_out: + srd_exception_catch(NULL, "Failed to get %s decoder binary classes", + dec->name); +err_out: + g_slist_free_full(bin_classes, (GDestroyNotify)&g_strfreev); + Py_XDECREF(py_bin_classes); + + return SRD_ERR_PYTHON; +} + +/* Check whether the Decoder class defines the named method. + */ +static int check_method(PyObject *py_dec, const char *mod_name, + const char *method_name) +{ + PyObject *py_method; + int is_callable; + + py_method = PyObject_GetAttrString(py_dec, method_name); + if (!py_method) { + srd_exception_catch(NULL, "Protocol decoder %s Decoder class " + "has no %s() method", mod_name, method_name); + return SRD_ERR_PYTHON; + } + + is_callable = PyCallable_Check(py_method); + Py_DECREF(py_method); + + if (!is_callable) { + srd_err("Protocol decoder %s Decoder class attribute '%s' " + "is not a method.", mod_name, method_name); + return SRD_ERR_PYTHON; } return SRD_OK; } +/** + * Get the API version of the specified decoder. + * + * @param d The decoder to use. Must not be NULL. + * + * @return The API version of the decoder, or 0 upon errors. + */ +SRD_PRIV long srd_decoder_apiver(const struct srd_decoder *d) +{ + PyObject *py_apiver; + long apiver; + + if (!d) + return 0; + + py_apiver = PyObject_GetAttrString(d->py_dec, "api_version"); + apiver = (py_apiver && PyLong_Check(py_apiver)) + ? PyLong_AsLong(py_apiver) : 0; + Py_XDECREF(py_apiver); + + return apiver; +} + /** * Load a protocol decoder module into the embedded Python interpreter. * @@ -303,18 +636,12 @@ static int get_options(struct srd_decoder *d) */ SRD_API int srd_decoder_load(const char *module_name) { - PyObject *py_basedec, *py_method, *py_attr, *py_annlist, *py_ann; - PyObject *py_bin_classes, *py_bin_class, *py_ann_rows, *py_ann_row; - PyObject *py_ann_classes, *py_long; + PyObject *py_basedec; struct srd_decoder *d; - int ret, i, j; - char **ann, **bin, *ann_row_id, *ann_row_desc; - struct srd_channel *pdch; - GSList *l, *ann_classes; - struct srd_decoder_annotation_row *ann_row; - int ann_type = 7; - int ann_len; - + long apiver; + int is_subclass; + const char *fail_txt; + if (!srd_check_init()) return SRD_ERR; @@ -328,251 +655,147 @@ SRD_API int srd_decoder_load(const char *module_name) srd_dbg("Loading protocol decoder '%s'.", module_name); - py_basedec = py_method = py_attr = NULL; - d = g_malloc0(sizeof(struct srd_decoder)); + fail_txt = NULL; - ret = SRD_ERR_PYTHON; + d->py_mod = py_import_by_name(module_name); + if (!d->py_mod) { + fail_txt = "import by name failed"; + goto except_out; + } - /* Import the Python module. */ - if (!(d->py_mod = PyImport_ImportModule(module_name))) { - srd_exception_catch("Import of '%s' failed.", NULL, module_name); + if (!mod_sigrokdecode) { + srd_err("sigrokdecode module not loaded."); + fail_txt = "sigrokdecode(3) not loaded"; goto err_out; } /* Get the 'Decoder' class as Python object. */ - if (!(d->py_dec = PyObject_GetAttrString(d->py_mod, "Decoder"))) { - /* This generated an AttributeError exception. */ - PyErr_Clear(); - srd_err("Decoder class not found in protocol decoder %s.", - module_name); - goto err_out; + d->py_dec = PyObject_GetAttrString(d->py_mod, "Decoder"); + if (!d->py_dec) { + fail_txt = "no 'Decoder' attribute in imported module"; + goto except_out; } - if (!(py_basedec = PyObject_GetAttrString(mod_sigrokdecode, "Decoder"))) { - srd_dbg("sigrokdecode module not loaded."); - goto err_out; + py_basedec = PyObject_GetAttrString(mod_sigrokdecode, "Decoder"); + if (!py_basedec) { + fail_txt = "no 'Decoder' attribute in sigrokdecode(3)"; + goto except_out; } - if (!PyObject_IsSubclass(d->py_dec, py_basedec)) { + is_subclass = PyObject_IsSubclass(d->py_dec, py_basedec); + Py_DECREF(py_basedec); + + if (!is_subclass) { srd_err("Decoder class in protocol decoder module %s is not " "a subclass of sigrokdecode.Decoder.", module_name); + fail_txt = "not a subclass of sigrokdecode.Decoder"; goto err_out; } - Py_CLEAR(py_basedec); /* * Check that this decoder has the correct PD API version. * PDs of different API versions are incompatible and cannot work. */ - py_long = PyObject_GetAttrString(d->py_dec, "api_version"); - if (PyLong_AsLong(py_long) != 2) { - srd_err("Only PDs of API version 2 are supported."); + apiver = srd_decoder_apiver(d); + if (apiver != 2) { + srd_exception_catch(NULL, "Only PD API version 2 is supported, " + "decoder %s has version %ld", module_name, apiver); + fail_txt = "API version mismatch"; goto err_out; } - Py_CLEAR(py_long); - /* Check for a proper start() method. */ - if (!PyObject_HasAttrString(d->py_dec, "start")) { - srd_err("Protocol decoder %s has no start() method Decoder " - "class.", module_name); + /* Check Decoder class for required methods. + */ + if (check_method(d->py_dec, module_name, "start") != SRD_OK) { + fail_txt = "no 'start()' method"; goto err_out; } - py_method = PyObject_GetAttrString(d->py_dec, "start"); - if (!PyFunction_Check(py_method)) { - srd_err("Protocol decoder %s Decoder class attribute 'start' " - "is not a method.", module_name); - goto err_out; - } - Py_CLEAR(py_method); - /* Check for a proper decode() method. */ - if (!PyObject_HasAttrString(d->py_dec, "decode")) { - srd_err("Protocol decoder %s has no decode() method Decoder " - "class.", module_name); + if (check_method(d->py_dec, module_name, "decode") != SRD_OK) { + fail_txt = "no 'decode()' method"; goto err_out; } - py_method = PyObject_GetAttrString(d->py_dec, "decode"); - if (!PyFunction_Check(py_method)) { - srd_err("Protocol decoder %s Decoder class attribute 'decode' " - "is not a method.", module_name); - goto err_out; - } - Py_CLEAR(py_method); /* Store required fields in newly allocated strings. */ - if (py_attr_as_str(d->py_dec, "id", &(d->id)) != SRD_OK) + if (py_attr_as_str(d->py_dec, "id", &(d->id)) != SRD_OK) { + fail_txt = "no 'id' attribute"; goto err_out; + } - if (py_attr_as_str(d->py_dec, "name", &(d->name)) != SRD_OK) + if (py_attr_as_str(d->py_dec, "name", &(d->name)) != SRD_OK) { + fail_txt = "no 'name' attribute"; goto err_out; + } - if (py_attr_as_str(d->py_dec, "longname", &(d->longname)) != SRD_OK) + if (py_attr_as_str(d->py_dec, "longname", &(d->longname)) != SRD_OK) { + fail_txt = "no 'longname' attribute"; goto err_out; + } - if (py_attr_as_str(d->py_dec, "desc", &(d->desc)) != SRD_OK) + if (py_attr_as_str(d->py_dec, "desc", &(d->desc)) != SRD_OK) { + fail_txt = "no 'desc' attribute"; goto err_out; + } - if (py_attr_as_str(d->py_dec, "license", &(d->license)) != SRD_OK) + if (py_attr_as_str(d->py_dec, "license", &(d->license)) != SRD_OK) { + fail_txt = "no 'license' attribute"; goto err_out; + } /* All options and their default values. */ - if (get_options(d) != SRD_OK) + if (get_options(d) != SRD_OK) { + fail_txt = "cannot get options"; goto err_out; + } /* Check and import required channels. */ - if (get_channels(d, "channels", &d->channels) != SRD_OK) + if (get_channels(d, "channels", &d->channels, 0) != SRD_OK) { + fail_txt = "cannot get channels"; goto err_out; + } /* Check and import optional channels. */ - if (get_channels(d, "optional_channels", &d->opt_channels) != SRD_OK) + if (get_channels(d, "optional_channels", &d->opt_channels, + g_slist_length(d->channels)) != SRD_OK) { + fail_txt = "cannot get optional channels"; goto err_out; - - /* - * Fix order numbers for the optional channels. - * - * Example: - * Required channels: r1, r2, r3. Optional: o1, o2, o3, o4. - * 'order' fields in the d->channels list = 0, 1, 2. - * 'order' fields in the d->opt_channels list = 3, 4, 5, 6. - */ - for (l = d->opt_channels; l; l = l->next) { - pdch = l->data; - pdch->order += g_slist_length(d->channels); } - /* Convert annotation class attribute to GSList of char **. */ - d->annotations = NULL; - if (PyObject_HasAttrString(d->py_dec, "annotations")) { - py_annlist = PyObject_GetAttrString(d->py_dec, "annotations"); - if (!PyTuple_Check(py_annlist)) { - srd_err("Protocol decoder %s annotations should " - "be a tuple.", module_name); - goto err_out; - } - for (i = 0; i < PyTuple_Size(py_annlist); i++) { - py_ann = PyTuple_GetItem(py_annlist, i); - if (!PyTuple_Check(py_ann) || (PyTuple_Size(py_ann) != 3 && PyTuple_Size(py_ann) != 2)) { - srd_err("Protocol decoder %s annotation %d should " - "be a tuple with two elements.", module_name, i + 1); - goto err_out; - } - if (py_strseq_to_char(py_ann, &ann) != SRD_OK) { - goto err_out; - } - d->annotations = g_slist_append(d->annotations, ann); - if (PyTuple_Size(py_ann) == 3) { - ann_type = 0; - ann_len = strlen(ann[0]); - for (j = 0; j < ann_len; j++) - ann_type = ann_type * 10 + (ann[0][j] - '0'); - d->ann_types = g_slist_append(d->ann_types, GINT_TO_POINTER(ann_type)); - } else if (PyTuple_Size(py_ann) == 2) { - d->ann_types = g_slist_append(d->ann_types, GINT_TO_POINTER(ann_type)); - ann_type++; - } - } + if (get_annotations(d) != SRD_OK) { + fail_txt = "cannot get annotations"; + goto err_out; } - /* Convert annotation_rows to GSList of 'struct srd_decoder_annotation_row'. */ - d->annotation_rows = NULL; - if (PyObject_HasAttrString(d->py_dec, "annotation_rows")) { - py_ann_rows = PyObject_GetAttrString(d->py_dec, "annotation_rows"); - if (!PyTuple_Check(py_ann_rows)) { - srd_err("Protocol decoder %s annotation row list " - "must be a tuple.", module_name); - goto err_out; - } - for (i = 0; i < PyTuple_Size(py_ann_rows); i++) { - py_ann_row = PyTuple_GetItem(py_ann_rows, i); - if (!PyTuple_Check(py_ann_row)) { - srd_err("Protocol decoder %s annotation rows " - "must be tuples.", module_name); - goto err_out; - } - if (PyTuple_Size(py_ann_row) != 3 - || !PyUnicode_Check(PyTuple_GetItem(py_ann_row, 0)) - || !PyUnicode_Check(PyTuple_GetItem(py_ann_row, 1)) - || !PyTuple_Check(PyTuple_GetItem(py_ann_row, 2))) { - srd_err("Protocol decoder %s annotation rows " - "must contain tuples containing two " - "strings and a tuple.", module_name); - goto err_out; - } - - if (py_str_as_str(PyTuple_GetItem(py_ann_row, 0), &ann_row_id) != SRD_OK) - goto err_out; - - if (py_str_as_str(PyTuple_GetItem(py_ann_row, 1), &ann_row_desc) != SRD_OK) - goto err_out; - - py_ann_classes = PyTuple_GetItem(py_ann_row, 2); - ann_classes = NULL; - for (j = 0; j < PyTuple_Size(py_ann_classes); j++) { - py_long = PyTuple_GetItem(py_ann_classes, j); - if (!PyLong_Check(py_long)) { - srd_err("Protocol decoder %s annotation row class " - "list must only contain numbers.", module_name); - goto err_out; - } - ann_classes = g_slist_append(ann_classes, - GINT_TO_POINTER(PyLong_AsLong(py_long))); - } - - ann_row = g_malloc0(sizeof(struct srd_decoder_annotation_row)); - ann_row->id = ann_row_id; - ann_row->desc = ann_row_desc; - ann_row->ann_classes = ann_classes; - d->annotation_rows = g_slist_append(d->annotation_rows, ann_row); - } + if (get_annotation_rows(d) != SRD_OK) { + fail_txt = "cannot get annotation rows"; + goto err_out; } - /* Convert binary class to GSList of char *. */ - d->binary = NULL; - if (PyObject_HasAttrString(d->py_dec, "binary")) { - py_bin_classes = PyObject_GetAttrString(d->py_dec, "binary"); - if (!PyTuple_Check(py_bin_classes)) { - srd_err("Protocol decoder %s binary classes should " - "be a tuple.", module_name); - goto err_out; - } - for (i = 0; i < PyTuple_Size(py_bin_classes); i++) { - py_bin_class = PyTuple_GetItem(py_bin_classes, i); - if (!PyTuple_Check(py_bin_class)) { - srd_err("Protocol decoder %s binary classes " - "should consist of tuples.", module_name); - goto err_out; - } - if (PyTuple_Size(py_bin_class) != 2 - || !PyUnicode_Check(PyTuple_GetItem(py_bin_class, 0)) - || !PyUnicode_Check(PyTuple_GetItem(py_bin_class, 1))) { - srd_err("Protocol decoder %s binary classes should " - "contain tuples with two strings.", module_name); - goto err_out; - } - - if (py_strseq_to_char(py_bin_class, &bin) != SRD_OK) { - goto err_out; - } - d->binary = g_slist_append(d->binary, bin); - } + if (get_binary_classes(d) != SRD_OK) { + fail_txt = "cannot get binary classes"; + goto err_out; } - - /* Append it to the list of supported/loaded decoders. */ + + /* Append it to the list of loaded decoders. */ pd_list = g_slist_append(pd_list, d); - ret = SRD_OK; + return SRD_OK; -err_out: - if (ret != SRD_OK) { - Py_XDECREF(py_method); - Py_XDECREF(py_basedec); - Py_XDECREF(d->py_dec); - Py_XDECREF(d->py_mod); - g_free(d); +except_out: + if (fail_txt) { + srd_exception_catch(NULL, "Failed to load decoder %s: %s", + module_name, fail_txt); + fail_txt = NULL; + } else { + srd_exception_catch(NULL, "Failed to load decoder %s", module_name); } +err_out: + if (fail_txt) + srd_err("Failed to load decoder %s: %s", module_name, fail_txt); + decoder_free(d); - return ret; + return SRD_ERR_PYTHON; } /** @@ -600,36 +823,18 @@ SRD_API char *srd_decoder_doc_get(const struct srd_decoder *dec) return NULL; if (!(py_str = PyObject_GetAttrString(dec->py_mod, "__doc__"))) { - srd_exception_catch("", NULL); + srd_exception_catch(NULL, "Failed to get docstring"); return NULL; } doc = NULL; if (py_str != Py_None) py_str_as_str(py_str, &doc); - Py_DecRef(py_str); + Py_DECREF(py_str); return doc; } -static void free_channels(GSList *channellist) -{ - GSList *l; - struct srd_channel *pdch; - - if (channellist == NULL) - return; - - for (l = channellist; l; l = l->next) { - pdch = l->data; - g_free(pdch->id); - g_free(pdch->name); - g_free(pdch->desc); - g_free(pdch); - } - g_slist_free(channellist); -} - /** * Unload the specified protocol decoder. * @@ -641,8 +846,6 @@ static void free_channels(GSList *channellist) */ SRD_API int srd_decoder_unload(struct srd_decoder *dec) { - struct srd_decoder_option *o; - struct srd_decoder_annotation_row *row; struct srd_session *sess; GSList *l; @@ -665,44 +868,10 @@ SRD_API int srd_decoder_unload(struct srd_decoder *dec) srd_inst_free_all(sess, NULL); } - for (l = dec->options; l; l = l->next) { - o = l->data; - g_free(o->id); - g_free(o->desc); - g_variant_unref(o->def); - g_free(o); - } - g_slist_free(dec->options); + /* Remove the PD from the list of loaded decoders. */ + pd_list = g_slist_remove(pd_list, dec); - g_slist_foreach(dec->annotations, (GFunc)g_free, NULL); - g_slist_free(dec->annotations); - - for (l = dec->annotation_rows; l; l = l->next) { - row = l->data; - g_free(row->id); - g_free(row->desc); - g_slist_free(row->ann_classes); - g_free(row); - } - g_slist_free(dec->annotation_rows); - - g_slist_foreach(dec->binary, (GFunc)g_free, NULL); - g_slist_free(dec->binary); - - free_channels(dec->channels); - free_channels(dec->opt_channels); - g_free(dec->id); - g_free(dec->name); - g_free(dec->longname); - g_free(dec->desc); - g_free(dec->license); - - /* The module's Decoder class. */ - Py_XDECREF(dec->py_dec); - /* The module itself. */ - Py_XDECREF(dec->py_mod); - - g_free(dec); + decoder_free(dec); return SRD_OK; } @@ -717,7 +886,7 @@ static void srd_decoder_load_all_zip_path(char *path) set = files = prefix_obj = zipimporter = zipimporter_class = NULL; - zipimport_mod = PyImport_ImportModule("zipimport"); + zipimport_mod = py_import_by_name("zipimport"); if (zipimport_mod == NULL) goto err_out; @@ -734,7 +903,7 @@ static void srd_decoder_load_all_zip_path(char *path) goto err_out; files = PyObject_GetAttrString(zipimporter, "_files"); - if (files == NULL) + if (files == NULL || !PyDict_Check(files)) goto err_out; set = PySet_New(NULL); @@ -749,33 +918,32 @@ static void srd_decoder_load_all_zip_path(char *path) while (PyDict_Next(files, &pos, &key, &value)) { char *path, *slash; if (py_str_as_str(key, &path) == SRD_OK) { - if (strlen(path) > prefix_len && - !memcmp(path, prefix, prefix_len) && - (slash = strchr(path+prefix_len, '/'))) { - modname = - PyUnicode_FromStringAndSize(path+prefix_len, - slash-(path+prefix_len)); + if (strlen(path) > prefix_len + && memcmp(path, prefix, prefix_len) == 0 + && (slash = strchr(path + prefix_len, '/'))) { + + modname = PyUnicode_FromStringAndSize(path + prefix_len, + slash - (path + prefix_len)); if (modname == NULL) { PyErr_Clear(); } else { PySet_Add(set, modname); - Py_XDECREF(modname); + Py_DECREF(modname); } } - free(path); + g_free(path); } } - - free(prefix); + g_free(prefix); while ((modname = PySet_Pop(set))) { char *modname_str; if (py_str_as_str(modname, &modname_str) == SRD_OK) { /* The directory name is the module name (e.g. "i2c"). */ srd_decoder_load(modname_str); - free(modname_str); + g_free(modname_str); } - Py_XDECREF(modname); + Py_DECREF(modname); } err_out: @@ -840,13 +1008,7 @@ SRD_API int srd_decoder_load_all(void) */ SRD_API int srd_decoder_unload_all(void) { - GSList *l; - struct srd_decoder *dec; - - for (l = pd_list; l; l = l->next) { - dec = l->data; - srd_decoder_unload(dec); - } + g_slist_foreach(pd_list, (GFunc)srd_decoder_unload, NULL); g_slist_free(pd_list); pd_list = NULL; diff --git a/libsigrokdecode4DSL/decoders/0-spi/.pd.py.swo b/libsigrokdecode4DSL/decoders/0-spi/.pd.py.swo deleted file mode 100755 index ee5f13a0..00000000 Binary files a/libsigrokdecode4DSL/decoders/0-spi/.pd.py.swo and /dev/null differ diff --git a/libsigrokdecode4DSL/decoders/0-spi/.pd.py.swp b/libsigrokdecode4DSL/decoders/0-spi/.pd.py.swp deleted file mode 100755 index 64d9c545..00000000 Binary files a/libsigrokdecode4DSL/decoders/0-spi/.pd.py.swp and /dev/null differ diff --git a/libsigrokdecode4DSL/decoders/0-uart/.pd.py.swo b/libsigrokdecode4DSL/decoders/0-uart/.pd.py.swo deleted file mode 100755 index b503d0a5..00000000 Binary files a/libsigrokdecode4DSL/decoders/0-uart/.pd.py.swo and /dev/null differ diff --git a/libsigrokdecode4DSL/decoders/0-uart/.pd.py.swp b/libsigrokdecode4DSL/decoders/0-uart/.pd.py.swp deleted file mode 100755 index 2c1323a8..00000000 Binary files a/libsigrokdecode4DSL/decoders/0-uart/.pd.py.swp and /dev/null differ diff --git a/libsigrokdecode4DSL/decoders/1-i2c/.pd.py.swo b/libsigrokdecode4DSL/decoders/1-i2c/.pd.py.swo deleted file mode 100755 index efcc3af7..00000000 Binary files a/libsigrokdecode4DSL/decoders/1-i2c/.pd.py.swo and /dev/null differ diff --git a/libsigrokdecode4DSL/decoders/1-i2c/.pd.py.swp b/libsigrokdecode4DSL/decoders/1-i2c/.pd.py.swp deleted file mode 100755 index 152f1b1d..00000000 Binary files a/libsigrokdecode4DSL/decoders/1-i2c/.pd.py.swp and /dev/null differ diff --git a/libsigrokdecode4DSL/decoders/1-i2c/pd.py b/libsigrokdecode4DSL/decoders/1-i2c/pd.py index 88991edb..dc8c77f8 100755 --- a/libsigrokdecode4DSL/decoders/1-i2c/pd.py +++ b/libsigrokdecode4DSL/decoders/1-i2c/pd.py @@ -79,8 +79,8 @@ class Decoder(srd.Decoder): inputs = ['logic'] outputs = ['i2c'] channels = ( - {'id': 'scl', 'name': 'SCL', 'desc': 'Serial clock line'}, - {'id': 'sda', 'name': 'SDA', 'desc': 'Serial data line'}, + {'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', @@ -94,7 +94,7 @@ class Decoder(srd.Decoder): ('0', 'nack', 'NACK'), ('12', 'read', 'Read'), ('11', 'write', 'Write'), - ('108', 'bit', 'Data/address bit'), + ('208', 'bit', 'Data/address bit'), ('112', 'address-read', 'Address read'), ('111', 'address-write', 'Address write'), ('110', 'data-read', 'Data read'), diff --git a/libsigrokdecode4DSL/decoders/1-spi/.pd.py.swn b/libsigrokdecode4DSL/decoders/1-spi/.pd.py.swn deleted file mode 100755 index ed1c9a62..00000000 Binary files a/libsigrokdecode4DSL/decoders/1-spi/.pd.py.swn and /dev/null differ diff --git a/libsigrokdecode4DSL/decoders/1-spi/.pd.py.swo b/libsigrokdecode4DSL/decoders/1-spi/.pd.py.swo deleted file mode 100755 index ee5f13a0..00000000 Binary files a/libsigrokdecode4DSL/decoders/1-spi/.pd.py.swo and /dev/null differ diff --git a/libsigrokdecode4DSL/decoders/1-spi/.pd.py.swp b/libsigrokdecode4DSL/decoders/1-spi/.pd.py.swp deleted file mode 100755 index 64d9c545..00000000 Binary files a/libsigrokdecode4DSL/decoders/1-spi/.pd.py.swp and /dev/null differ diff --git a/libsigrokdecode4DSL/decoders/1-spi/pd.py b/libsigrokdecode4DSL/decoders/1-spi/pd.py index ec1f29e1..f6dba532 100755 --- a/libsigrokdecode4DSL/decoders/1-spi/pd.py +++ b/libsigrokdecode4DSL/decoders/1-spi/pd.py @@ -88,12 +88,12 @@ class Decoder(srd.Decoder): inputs = ['logic'] outputs = ['spi'] channels = ( - {'id': 'clk', 'name': 'CLK', 'desc': 'Clock'}, + {'id': 'clk', 'type': 0, 'name': 'CLK', 'desc': 'Clock'}, ) optional_channels = ( - {'id': 'miso', 'name': 'MISO', 'desc': 'Master in, slave out'}, - {'id': 'mosi', 'name': 'MOSI', 'desc': 'Master out, slave in'}, - {'id': 'cs', 'name': 'CS#', 'desc': 'Chip-select'}, + {'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', @@ -109,8 +109,8 @@ class Decoder(srd.Decoder): annotations = ( ('106', 'miso-data', 'MISO data'), ('108', 'mosi-data', 'MOSI data'), - ('107', 'miso-bits', 'MISO bits'), - ('109', 'mosi-bits', 'MOSI bits'), + ('207', 'miso-bits', 'MISO bits'), + ('209', 'mosi-bits', 'MOSI bits'), ('1000', 'warnings', 'Human-readable warnings'), ) annotation_rows = ( diff --git a/libsigrokdecode4DSL/decoders/1-uart/.pd.py.swo b/libsigrokdecode4DSL/decoders/1-uart/.pd.py.swo deleted file mode 100755 index b503d0a5..00000000 Binary files a/libsigrokdecode4DSL/decoders/1-uart/.pd.py.swo and /dev/null differ diff --git a/libsigrokdecode4DSL/decoders/1-uart/.pd.py.swp b/libsigrokdecode4DSL/decoders/1-uart/.pd.py.swp deleted file mode 100755 index 2c1323a8..00000000 Binary files a/libsigrokdecode4DSL/decoders/1-uart/.pd.py.swp and /dev/null differ diff --git a/libsigrokdecode4DSL/decoders/1-uart/pd.py b/libsigrokdecode4DSL/decoders/1-uart/pd.py index 9d1869e8..159f1a37 100755 --- a/libsigrokdecode4DSL/decoders/1-uart/pd.py +++ b/libsigrokdecode4DSL/decoders/1-uart/pd.py @@ -78,7 +78,7 @@ class Decoder(srd.Decoder): inputs = ['logic'] outputs = ['uart'] channels = ( - {'id': 'rxtx', 'name': 'RX/TX', 'desc': 'UART transceive line'}, + {'id': 'rxtx', 'type': 209, 'name': 'RX/TX', 'desc': 'UART transceive line'}, ) options = ( {'id': 'baudrate', 'desc': 'Baud rate', 'default': 9600}, @@ -104,7 +104,7 @@ class Decoder(srd.Decoder): ('0', 'parity-err', 'parity error bits'), ('1', 'stop', 'stop bits'), ('1000', 'warnings', 'warnings'), - ('109', 'data-bits', 'data bits'), + ('209', 'data-bits', 'data bits'), ) annotation_rows = ( ('data', 'RX/TX', (0, 1, 2, 3, 4)), diff --git a/libsigrokdecode4DSL/decoders/jtag/pd.py b/libsigrokdecode4DSL/decoders/jtag/pd.py index 98919509..b0bae30e 100755 --- a/libsigrokdecode4DSL/decoders/jtag/pd.py +++ b/libsigrokdecode4DSL/decoders/jtag/pd.py @@ -30,10 +30,8 @@ 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', @@ -44,7 +42,6 @@ Packet: - '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 diff --git a/libsigrokdecode4DSL/decoders/lpc/pd.py b/libsigrokdecode4DSL/decoders/lpc/pd.py index 0f055ce5..7bb2fdd8 100755 --- a/libsigrokdecode4DSL/decoders/lpc/pd.py +++ b/libsigrokdecode4DSL/decoders/lpc/pd.py @@ -46,13 +46,21 @@ fields = { # 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', }, # SIZE field (determines how many bytes are to be transferred) # Bits[3:2] are reserved, must be driven to 0b00. @@ -128,26 +136,32 @@ class Decoder(srd.Decoder): ('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)), + ('data', 'Data', (1, 2, 3, 4, 5, 6, 7, 8)), ('warnings', 'Warnings', (0,)), ) def __init__(self): self.state = 'IDLE' self.oldlclk = -1 + self.oldlframe = -1 + self.oldlad = -1 + self.oldlad_bits = -1 self.samplenum = 0 self.clocknum = 0 self.lad = -1 self.addr = 0 self.cur_nibble = 0 + self.start_type = -1 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 @@ -157,38 +171,42 @@ class Decoder(srd.Decoder): def putb(self, data): self.put(self.ss_block, self.es_block, self.out_ann, data) - def handle_get_start(self, lad, lad_bits, lframe): + def handle_get_start(self, lframe): # LAD[3:0]: START field (1 clock cycle). + self.start_type = fields['START'][self.oldlad] # 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'][lad], 'START', 'St', 'S']]) + self.putb([1, [self.start_type, 'START', 'St', 'S']]) self.ss_block = self.samplenum # Output a warning if LAD[3:0] changes while LFRAME# is low. # TODO - if (self.lad != -1 and self.lad != lad): - self.putb([0, ['LAD[3:0] changed while LFRAME# was asserted']]) + #if (self.lad != -1 and self.lad != lad): + # self.putb([0, ['LAD[3:0] changed while LFRAME# was asserted']]) # 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 - self.start_field = self.lad - self.state = 'GET CT/DR' + if (self.oldlad == 0b0000): + self.start_field = self.oldlad + self.state = 'GET CT/DR' + else: + self.state = 'IDLE' - def handle_get_ct_dr(self, lad, lad_bits): + def handle_get_ct_dr(self): # LAD[3:0]: Cycle type / direction field (1 clock cycle). - self.cycle_type = fields['CT_DR'][lad] + self.cycle_type = fields['CT_DR'][self.oldlad] # TODO: Warning/error on invalid cycle types. if self.cycle_type == 'Reserved': - self.putb([0, ['Invalid cycle type (%s)' % lad_bits]]) + self.putb([0, ['Invalid cycle type (%s)' % self.oldlad_bits]]) self.es_block = self.samplenum self.putb([2, ['Cycle type: %s' % self.cycle_type]]) @@ -198,7 +216,7 @@ class Decoder(srd.Decoder): self.addr = 0 self.cur_nibble = 0 - def handle_get_addr(self, lad, lad_bits): + 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. @@ -212,7 +230,7 @@ class Decoder(srd.Decoder): # Addresses are driven MSN-first. offset = ((addr_nibbles - 1) - self.cur_nibble) * 4 - self.addr |= (lad << offset) + self.addr |= (self.oldlad << offset) # Continue if we haven't seen all ADDR cycles, yet. if (self.cur_nibble < addr_nibbles - 1): @@ -227,20 +245,20 @@ class Decoder(srd.Decoder): self.state = 'GET TAR' self.tar_count = 0 - def handle_get_tar(self, lad, lad_bits): + 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, lad_bits)]]) - self.ss_block = self.samplenum + self.putb([4, ['TAR, cycle %d: %s' % (self.tarcount, self.oldlad_bits)]]) # 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 lad_bits != '1111': + if self.oldlad_bits != '1111': self.putb([0, ['TAR, cycle %d: %s (expected 1111)' % \ - (self.tarcount, lad_bits)]]) + (self.tarcount, self.oldlad_bits)]]) + self.ss_block = self.samplenum if (self.tarcount != 1): self.tarcount += 1 @@ -249,34 +267,57 @@ class Decoder(srd.Decoder): self.tarcount = 0 self.state = 'GET SYNC' - def handle_get_sync(self, lad, lad_bits): + def handle_get_sync(self, lframe): # LAD[3:0]: SYNC field (1-n clock cycles). - self.sync_val = lad_bits - self.cycle_type = fields['SYNC'][lad] + 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 self.cycle_count = 0 - self.state = 'GET DATA' + if (lframe == 0): + self.state = 'GET TIMEOUT' + else: + self.state = 'GET DATA' - def handle_get_data(self, lad, lad_bits): + 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_data(self): # LAD[3:0]: DATA field (2 clock cycles). # Data is driven LSN-first. if (self.cycle_count == 0): - self.databyte = lad + self.databyte = self.oldlad elif (self.cycle_count == 1): - self.databyte |= (lad << 4) + self.databyte |= (self.oldlad << 4) else: raise Exception('Invalid cycle_count: %d' % self.cycle_count) @@ -285,26 +326,26 @@ class Decoder(srd.Decoder): return self.es_block = self.samplenum - self.putb([6, ['DATA: 0x%02x' % self.databyte]]) + 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, lad_bits): + def handle_get_tar2(self): # LAD[3:0]: Second TAR field (2 clock cycles). self.es_block = self.samplenum - self.putb([7, ['TAR, cycle %d: %s' % (self.tarcount, lad_bits)]]) + 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 lad_bits != '1111': + if self.oldlad_bits != '1111': self.putb([0, ['Warning: TAR, cycle %d: %s (expected 1111)' - % (self.tarcount, lad_bits)]]) + % (self.tarcount, self.oldlad_bits)]]) if (self.tarcount != 1): self.tarcount += 1 @@ -313,15 +354,8 @@ class Decoder(srd.Decoder): self.tarcount = 0 self.state = 'IDLE' - def decode(self, ss, es, data): - for (self.samplenum, pins) in data: - data.itercnt += 1 - # If none of the pins changed, there's nothing to do. - if self.oldpins == pins: - continue - - # Store current pin values for the next round. - self.oldpins = pins + def decode(self, ss, es, logic): + for (self.samplenum, pins) in logic: # Get individual pin values into local variables. (lframe, lclk, lad0, lad1, lad2, lad3) = pins[:6] @@ -329,40 +363,63 @@ class Decoder(srd.Decoder): # 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). - if not (self.oldlclk == 0 and lclk == 1): - self.oldlclk = lclk - continue + logic.logic_mask = 0b0000000000010 + logic.exp_logic = 0b0000000000010 + logic.edge_index = 1 + logic.cur_pos = self.samplenum + #if not (self.oldlclk == 0 and lclk == 1): + # continue # Store LAD[3:0] bit values (one nibble) in local variables. # Most (but not all) states need this. - if self.state != 'IDLE': - lad = (lad3 << 3) | (lad2 << 2) | (lad1 << 1) | lad0 - lad_bits = bin(lad)[2:].zfill(4) - # self.putb([0, ['LAD: %s' % lad_bits]]) + lad = (lad3 << 3) | (lad2 << 2) | (lad1 << 1) | lad0 + lad_bits = bin(lad)[2:].zfill(4) + # self.putb([0, ['LAD: %s' % lad_bits]]) # TODO: Only memory read/write is currently supported/tested. # State machine if self.state == 'IDLE': # A valid LPC cycle starts with LFRAME# being asserted (low). - if lframe != 0: - continue - self.ss_block = self.samplenum - self.state = 'GET START' - self.lad = -1 - # self.clocknum = 0 + #if lframe != 0: + # continue + if (lframe == 0): + if (self.oldlclk == 0 and lclk == 1): + self.ss_block = self.samplenum + self.state = 'GET START' + self.lad = -1 + # self.clocknum = 0 + else: + logic.logic_mask = 0b0000000000001 + logic.exp_logic = 0b0000000000000 + logic.edge_index = 0 elif self.state == 'GET START': - self.handle_get_start(lad, lad_bits, lframe) + self.handle_get_start(lframe) elif self.state == 'GET CT/DR': - self.handle_get_ct_dr(lad, lad_bits) + self.handle_get_ct_dr() elif self.state == 'GET ADDR': - self.handle_get_addr(lad, lad_bits) + self.handle_get_addr() elif self.state == 'GET TAR': - self.handle_get_tar(lad, lad_bits) + self.handle_get_tar() elif self.state == 'GET SYNC': - self.handle_get_sync(lad, lad_bits) + self.handle_get_sync(lframe) + elif self.state == 'GET TIMEOUT': + self.handle_get_timeout() elif self.state == 'GET DATA': - self.handle_get_data(lad, lad_bits) + self.handle_get_data() elif self.state == 'GET TAR2': - self.handle_get_tar2(lad, lad_bits) + self.handle_get_tar2() + + # Store current pin values for the next round. + self.oldpins = pins + if (logic.edge_index == 1): + self.oldlclk = 0 + else: + self.oldlclk = -1 + if (logic.edge_index == 0): + self.oldlframe = 1 + else: + self.oldlframe = lframe + self.oldlad = lad + self.oldlad_bits = lad_bits diff --git a/libsigrokdecode4DSL/decoders/onewire_link/pd.py.back b/libsigrokdecode4DSL/decoders/onewire_link/pd.py.back deleted file mode 100755 index 03818b7c..00000000 --- a/libsigrokdecode4DSL/decoders/onewire_link/pd.py.back +++ /dev/null @@ -1,289 +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, write to the Free Software -## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -## - -import sigrokdecode as srd - -class SamplerateError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 2 - id = 'onewire_link' - name = 'One-Wire link layer' - longname = 'One-Wire serial communication bus (link layer)' - desc = 'Bidirectional, half-duplex, asynchronous serial bus.' - license = 'gplv2+' - inputs = ['logic'] - outputs = ['onewire_link'] - channels = ( - {'id': 'owr', 'name': 'OWR', 'desc': '1-Wire signal line'}, - ) - optional_channels = ( - {'id': 'pwr', 'name': 'PWR', 'desc': '1-Wire power supply pin'}, - ) - options = ( - {'id': 'overdrive', - 'desc': 'Overdrive mode', 'default': 'no', 'values': ('yes', 'no')}, - # Time options (specified in microseconds): - {'id': 'cnt_normal_bit', - 'desc': 'Normal mode sample bit time (μs)', 'default': 15}, - {'id': 'cnt_normal_slot', - 'desc': 'Normal mode data slot time (μs)', 'default': 60}, - {'id': 'cnt_normal_presence', - 'desc': 'Normal mode sample presence time (μs)', 'default': 75}, - {'id': 'cnt_normal_reset', - 'desc': 'Normal mode reset time (μs)', 'default': 480}, - {'id': 'cnt_overdrive_bit', - 'desc': 'Overdrive mode sample bit time (μs)', 'default': 2}, - {'id': 'cnt_overdrive_slot', - 'desc': 'Overdrive mode data slot time (μs)', 'default': 7.3}, - {'id': 'cnt_overdrive_presence', - 'desc': 'Overdrive mode sample presence time (μs)', 'default': 10}, - {'id': 'cnt_overdrive_reset', - 'desc': 'Overdrive mode reset time (μs)', 'default': 48}, - ) - annotations = ( - ('bit', 'Bit'), - ('warnings', 'Warnings'), - ('reset', 'Reset'), - ('presence', 'Presence'), - ('overdrive', 'Overdrive mode notifications'), - ) - annotation_rows = ( - ('bits', 'Bits', (0, 2, 3)), - ('info', 'Info', (4,)), - ('warnings', 'Warnings', (1,)), - ) - - def putm(self, data): - self.put(0, 0, self.out_ann, data) - - def putpb(self, data): - self.put(self.fall, self.samplenum, self.out_python, data) - - def putb(self, data): - self.put(self.fall, self.samplenum, self.out_ann, data) - - def putx(self, data): - self.put(self.fall, self.cnt_bit[self.overdrive], 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 __init__(self): - self.samplerate = None - self.samplenum = 0 - self.state = 'WAIT FOR FALLING EDGE' - self.present = 0 - self.bit = 0 - self.bit_cnt = 0 - self.command = 0 - self.overdrive = 0 - 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) - - 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.']]) - - # Check if sample times are in the allowed range. - - time_min = float(self.cnt_normal_bit) / self.samplerate - time_max = float(self.cnt_normal_bit + 1) / self.samplerate - if (time_min < 0.000005) or (time_max > 0.000015): - self.putm([1, ['The normal mode data sample time interval ' + - '(%2.1fus-%2.1fus) should be inside (5.0us, 15.0us).' - % (time_min * 1000000, time_max * 1000000)]]) - - time_min = float(self.cnt_normal_presence) / self.samplerate - time_max = float(self.cnt_normal_presence + 1) / self.samplerate - if (time_min < 0.0000681) or (time_max > 0.000075): - self.putm([1, ['The normal mode presence sample time interval ' + - '(%2.1fus-%2.1fus) should be inside (68.1us, 75.0us).' - % (time_min * 1000000, time_max * 1000000)]]) - - time_min = float(self.cnt_overdrive_bit) / self.samplerate - time_max = float(self.cnt_overdrive_bit + 1) / self.samplerate - if (time_min < 0.000001) or (time_max > 0.000002): - self.putm([1, ['The overdrive mode data sample time interval ' + - '(%2.1fus-%2.1fus) should be inside (1.0us, 2.0us).' - % (time_min * 1000000, time_max * 1000000)]]) - - time_min = float(self.cnt_overdrive_presence) / self.samplerate - time_max = float(self.cnt_overdrive_presence + 1) / self.samplerate - if (time_min < 0.0000073) or (time_max > 0.000010): - self.putm([1, ['The overdrive mode presence sample time interval ' + - '(%2.1fus-%2.1fus) should be inside (7.3us, 10.0us).' - % (time_min * 1000000, time_max * 1000000)]]) - - - def metadata(self, key, value): - if key != srd.SRD_CONF_SAMPLERATE: - return - self.samplerate = value - - # The default 1-Wire time base is 30us. This is used to calculate - # sampling times. - samplerate = float(self.samplerate) - - x = float(self.options['cnt_normal_bit']) / 1000000.0 - self.cnt_normal_bit = int(samplerate * x) - 1 - x = float(self.options['cnt_normal_slot']) / 1000000.0 - self.cnt_normal_slot = int(samplerate * x) - 1 - x = float(self.options['cnt_normal_presence']) / 1000000.0 - self.cnt_normal_presence = int(samplerate * x) - 1 - x = float(self.options['cnt_normal_reset']) / 1000000.0 - self.cnt_normal_reset = int(samplerate * x) - 1 - x = float(self.options['cnt_overdrive_bit']) / 1000000.0 - self.cnt_overdrive_bit = int(samplerate * x) - 1 - x = float(self.options['cnt_overdrive_slot']) / 1000000.0 - self.cnt_overdrive_slot = int(samplerate * x) - 1 - x = float(self.options['cnt_overdrive_presence']) / 1000000.0 - self.cnt_overdrive_presence = int(samplerate * x) - 1 - x = float(self.options['cnt_overdrive_reset']) / 1000000.0 - self.cnt_overdrive_reset = int(samplerate * x) - 1 - - # Organize values into lists. - self.cnt_bit = [self.cnt_normal_bit, self.cnt_overdrive_bit] - self.cnt_presence = [self.cnt_normal_presence, self.cnt_overdrive_presence] - self.cnt_reset = [self.cnt_normal_reset, self.cnt_overdrive_reset] - self.cnt_slot = [self.cnt_normal_slot, self.cnt_overdrive_slot] - - def decode(self, ss, es, data): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - for (self.samplenum, (owr, pwr)) in data: - data.itercnt += 1 - if self.samplenum == 0: - self.checks() - # State machine. - if self.state == 'WAIT FOR FALLING EDGE': - # The start of a cycle is a falling edge. - if owr != 0: - continue - # Save the sample number for the falling edge. - self.fall = self.samplenum - # Go to waiting for sample time. - self.state = 'WAIT FOR DATA SAMPLE' - elif self.state == 'WAIT FOR DATA SAMPLE': - # Sample data bit. - t = self.samplenum - self.fall - if t == self.cnt_bit[self.overdrive]: - self.bit = owr - self.state = 'WAIT FOR DATA SLOT END' - elif self.state == 'WAIT FOR DATA SLOT END': - # A data slot ends in a recovery period, otherwise, this is - # probably a reset. - t = self.samplenum - self.fall - if t != self.cnt_slot[self.overdrive]: - continue - - if owr == 0: - # This seems to be a reset slot, wait for its end. - self.state = 'WAIT FOR RISING EDGE' - continue - - self.putb([0, ['Bit: %d' % self.bit, '%d' % self.bit]]) - self.putpb(['BIT', self.bit]) - - # Checking the first command to see if overdrive mode - # should be entered. - if self.bit_cnt <= 8: - self.command |= (self.bit << self.bit_cnt) - elif self.bit_cnt == 8 and self.command in [0x3c, 0x69]: - self.putx([4, ['Entering overdrive mode', 'Overdrive on']]) - # Increment the bit counter. - self.bit_cnt += 1 - # Wait for next slot. - self.state = 'WAIT FOR FALLING EDGE' - elif self.state == 'WAIT FOR RISING EDGE': - # The end of a cycle is a rising edge. - if owr != 1: - continue - - # Check if this was a reset cycle. - t = self.samplenum - self.fall - if t > self.cnt_normal_reset: - # Save the sample number for the rising edge. - self.rise = self.samplenum - self.putfr([2, ['Reset', 'Rst', 'R']]) - self.state = 'WAIT FOR PRESENCE DETECT' - # Exit overdrive mode. - if self.overdrive: - self.putx([4, ['Exiting overdrive mode', 'Overdrive off']]) - self.overdrive = 0 - # Clear command bit counter and data register. - self.bit_cnt = 0 - self.command = 0 - elif (t > self.cnt_overdrive_reset) and self.overdrive: - # Save the sample number for the rising edge. - self.rise = self.samplenum - self.putfr([2, ['Reset', 'Rst', 'R']]) - self.state = 'WAIT FOR PRESENCE DETECT' - # Otherwise this is assumed to be a data bit. - else: - self.state = 'WAIT FOR FALLING EDGE' - elif self.state == 'WAIT FOR PRESENCE DETECT': - # Sample presence status. - t = self.samplenum - self.rise - if t == self.cnt_presence[self.overdrive]: - self.present = owr - self.state = 'WAIT FOR RESET SLOT END' - elif self.state == 'WAIT FOR RESET SLOT END': - # A reset slot ends in a long recovery period. - t = self.samplenum - self.rise - if t != self.cnt_reset[self.overdrive]: - continue - - if owr == 0: - # This seems to be a reset slot, wait for its end. - self.state = 'WAIT FOR RISING EDGE' - continue - - p = 'false' if self.present else 'true' - self.putrs([3, ['Presence: %s' % p, 'Presence', 'Pres', 'P']]) - self.putprs(['RESET/PRESENCE', not self.present]) - - # Wait for next slot. - self.state = 'WAIT FOR FALLING EDGE' - diff --git a/libsigrokdecode4DSL/decoders/spi/__init__.py b/libsigrokdecode4DSL/decoders/spi/__init__.py deleted file mode 100755 index f76bb064..00000000 --- a/libsigrokdecode4DSL/decoders/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, write to the Free Software -## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -## - -''' -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/spi/pd.py b/libsigrokdecode4DSL/decoders/spi/pd.py deleted file mode 100755 index af390b84..00000000 --- a/libsigrokdecode4DSL/decoders/spi/pd.py +++ /dev/null @@ -1,334 +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, write to the Free Software -## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -## - -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 SamplerateError(Exception): - pass - -class ChannelError(Exception): - pass - -class Decoder(srd.Decoder): - api_version = 2 - id = 'spi' - name = 'SPI' - longname = 'Serial Peripheral Interface' - desc = 'Full-duplex, synchronous, serial bus.' - license = 'gplv2+' - inputs = ['logic'] - outputs = ['spi'] - channels = ( - {'id': 'clk', 'name': 'CLK', 'desc': 'Clock'}, - ) - optional_channels = ( - {'id': 'miso', 'name': 'MISO', 'desc': 'Master in, slave out'}, - {'id': 'mosi', 'name': 'MOSI', 'desc': 'Master out, slave in'}, - {'id': 'cs', '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', 'default': 0, - 'values': (0, 1)}, - {'id': 'cpha', 'desc': 'Clock phase', '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 = ( - ('miso-data', 'MISO data'), - ('mosi-data', 'MOSI data'), - ('miso-bits', 'MISO bits'), - ('mosi-bits', 'MOSI bits'), - ('warnings', 'Human-readable warnings'), - ) - annotation_rows = ( - ('miso-data', 'MISO data', (0,)), - ('miso-bits', 'MISO bits', (2,)), - ('mosi-data', 'MOSI data', (1,)), - ('mosi-bits', 'MOSI bits', (3,)), - ('other', 'Other', (4,)), - ) - binary = ( - ('miso', 'MISO'), - ('mosi', 'MOSI'), - ) - - def __init__(self): - self.samplerate = None - self.oldclk = -1 - 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.oldcs = None - self.oldpins = None - self.have_cs = self.have_miso = self.have_mosi = None - self.no_cs_notification = False - - 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_bin = self.register(srd.OUTPUT_BINARY) - self.out_bitrate = self.register(srd.OUTPUT_META, - meta=(int, 'Bitrate', 'Bitrate during transfers')) - - 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 - 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] - #self.put(ss, es, self.out_bin, (0, bytes([so]))) - if self.have_mosi: - ss, es = self.mosibits[-1][1], self.mosibits[0][2] - #self.put(ss, es, self.out_bin, (1, bytes([si]))) - - self.put(ss, es, self.out_python, ['BITS', si_bits, so_bits]) - self.put(ss, es, self.out_python, ['DATA', si, so]) - - 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): - # 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'] - - # Receive MISO bit into our shift register. - if self.have_miso: - if self.options['bitorder'] == '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 self.options['bitorder'] == '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() - - # Meta bitrate. - elapsed = 1 / float(self.samplerate) - elapsed *= (self.samplenum - self.ss_block + 1) - bitrate = int(1 / elapsed * self.options['wordsize']) - 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): - if self.have_cs and self.oldcs != cs: - # Send all CS# pin value changes. - self.put(self.samplenum, self.samplenum, self.out_python, - ['CS-CHANGE', self.oldcs, cs]) - self.oldcs = cs - - if self.cs_asserted(cs): - self.ss_transfer = self.samplenum - self.misobytes = [] - self.mosibytes = [] - else: - 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 clk == self.oldclk: - return - - self.oldclk = clk - - # Sample data on rising/falling clock edge (depends on mode). - mode = spi_mode[self.options['cpol'], self.options['cpha']] - if mode == 0 and clk == 0: # Sample on rising clock edge - return - elif mode == 1 and clk == 1: # Sample on falling clock edge - return - elif mode == 2 and clk == 1: # Sample on falling clock edge - return - elif mode == 3 and clk == 0: # Sample on rising clock edge - return - - # Found the correct clock edge, now get the SPI bit(s). - self.handle_bit(miso, mosi, clk, cs) - - def decode(self, ss, es, data): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - # Either MISO or MOSI can be omitted (but not both). CS# is optional. - for (self.samplenum, pins) in data: - data.itercnt += 1 - # Ignore identical samples early on (for performance reasons). - if self.oldpins == pins: - continue - (clk, miso, mosi, cs) = pins - if self.oldpins == None: - self.oldclk = clk - self.oldpins = pins - self.have_miso = (miso in (0, 1)) - self.have_mosi = (mosi in (0, 1)) - self.have_cs = (cs in (0, 1)) - - # Either MISO or MOSI (but not both) can be omitted. - if not (self.have_miso or self.have_mosi): - raise ChannelError('Either MISO or MOSI (or both) pins required.') - - # Tell stacked decoders that we don't have a CS# signal. - if not self.no_cs_notification and not self.have_cs: - self.put(0, 0, self.out_python, ['CS-CHANGE', None, None]) - self.no_cs_notification = True - - self.find_clk_edge(miso, mosi, clk, cs) diff --git a/libsigrokdecode4DSL/exception.c b/libsigrokdecode4DSL/exception.c index 9662ed50..d389af31 100644 --- a/libsigrokdecode4DSL/exception.c +++ b/libsigrokdecode4DSL/exception.c @@ -22,71 +22,142 @@ #include "libsigrokdecode.h" #include #include -#include /* Python header not pulled in by default. */ +#include + +static char *py_stringify(PyObject *py_obj) +{ + PyObject *py_str, *py_bytes; + char *str = NULL; + + if (!py_obj) + return NULL; + + py_str = PyObject_Str(py_obj); + if (!py_str || !PyUnicode_Check(py_str)) + goto cleanup; + + py_bytes = PyUnicode_AsUTF8String(py_str); + if (!py_bytes) + goto cleanup; + + str = g_strdup(PyBytes_AsString(py_bytes)); + Py_DECREF(py_bytes); + +cleanup: + Py_XDECREF(py_str); + if (!str) { + PyErr_Clear(); + srd_dbg("Failed to stringify object."); + } + return str; +} + +static char *py_get_string_attr(PyObject *py_obj, const char *attr) +{ + PyObject *py_str, *py_bytes; + char *str = NULL; + + if (!py_obj) + return NULL; + + py_str = PyObject_GetAttrString(py_obj, attr); + if (!py_str || !PyUnicode_Check(py_str)) + goto cleanup; + + py_bytes = PyUnicode_AsUTF8String(py_str); + if (!py_bytes) + goto cleanup; + + str = g_strdup(PyBytes_AsString(py_bytes)); + Py_DECREF(py_bytes); + +cleanup: + Py_XDECREF(py_str); + if (!str) { + PyErr_Clear(); + srd_dbg("Failed to get object attribute %s.", attr); + } + return str; +} /** @private */ -SRD_PRIV void srd_exception_catch(const char *format, char **error, ...) +SRD_PRIV void srd_exception_catch(char **error, const char *format, ...) { - PyObject *etype, *evalue, *etb, *py_str; - PyTracebackObject *py_tb; - GString *msg; va_list args; - char *ename, *str, *tracestr; + PyObject *py_etype, *py_evalue, *py_etraceback; + PyObject *py_mod, *py_func, *py_tracefmt; + char *msg, *etype_name, *evalue_str, *tracefmt_str; + const char *etype_name_fallback; + char *final_msg; - if (!PyErr_Occurred()) - /* Nothing is wrong. */ - return; + py_etype = py_evalue = py_etraceback = py_mod = py_func = NULL; - PyErr_Fetch(&etype, &evalue, &etb); - PyErr_NormalizeException(&etype, &evalue, &etb); - - if (!(py_str = PyObject_Str(evalue))) { - /* Shouldn't happen. */ - srd_dbg("Failed to convert exception value to string."); - return; - } - - /* Send the exception error message(s) to srd_err(). */ - if (evalue) - ename = (char *)Py_TYPE(evalue)->tp_name; - else - /* Can be NULL. */ - ename = "(unknown exception)"; - - msg = g_string_sized_new(128); - g_string_append(msg, ename); - g_string_append(msg, ": "); - va_start(args, error); - g_string_append_vprintf(msg, format, args); + va_start(args, format); + msg = g_strdup_vprintf(format, args); va_end(args); - py_str_as_str(py_str, &str); - g_string_append(msg, str); - Py_DecRef(py_str); - srd_err("%s", msg->str); - /* Send a more precise error location to srd_dbg(), if we have it. */ - if (etb && etb != Py_None) { - tracestr = NULL; - py_tb = (PyTracebackObject *)etb; - py_str = PyUnicode_FromFormat("%U:%d in %U", - py_tb->tb_frame->f_code->co_filename, - py_tb->tb_frame->f_lineno, - py_tb->tb_frame->f_code->co_name); - py_str_as_str(py_str, &tracestr); - Py_DecRef(py_str); - g_string_printf(msg, "%s in %s: %s", ename, tracestr, str); - srd_dbg("%s", msg->str); - g_free(tracestr); + PyErr_Fetch(&py_etype, &py_evalue, &py_etraceback); + if (!py_etype) { + /* No current exception, so just print the message. */ + final_msg = g_strjoin(":", msg, "unknown error", NULL); + srd_err("%s.", final_msg); + goto cleanup; } - if (error) - *error = g_strdup(str); - g_free(str); - g_string_free(msg, TRUE); + PyErr_NormalizeException(&py_etype, &py_evalue, &py_etraceback); - Py_XDECREF(etype); - Py_XDECREF(evalue); - Py_XDECREF(etb); + etype_name = py_get_string_attr(py_etype, "__name__"); + evalue_str = py_stringify(py_evalue); + etype_name_fallback = (etype_name) ? etype_name : "(unknown exception)"; + + if (evalue_str) + final_msg = g_strjoin(":", msg, etype_name_fallback, evalue_str, NULL); + else + final_msg = g_strjoin(":", msg, etype_name_fallback, NULL); + + srd_err("%s.", final_msg); + + g_free(evalue_str); + g_free(etype_name); + + /* If there is no traceback object, we are done. */ + if (!py_etraceback) + goto cleanup; + + py_mod = py_import_by_name("traceback"); + if (!py_mod) + goto cleanup; + + py_func = PyObject_GetAttrString(py_mod, "format_exception"); + if (!py_func || !PyCallable_Check(py_func)) + goto cleanup; + + /* Call into Python to format the stack trace. */ + py_tracefmt = PyObject_CallFunctionObjArgs(py_func, + py_etype, py_evalue, py_etraceback, NULL); + if (!py_tracefmt) + goto cleanup; + + tracefmt_str = py_stringify(py_tracefmt); + Py_DECREF(py_tracefmt); + + /* Log the detailed stack trace. */ + if (tracefmt_str) { + srd_dbg("%s", tracefmt_str); + g_free(tracefmt_str); + } + +cleanup: + if (error) + *error = g_strdup(final_msg); + Py_XDECREF(py_func); + Py_XDECREF(py_mod); + Py_XDECREF(py_etraceback); + Py_XDECREF(py_evalue); + Py_XDECREF(py_etype); /* Just in case. */ PyErr_Clear(); + + g_free(msg); + g_free(final_msg); } diff --git a/libsigrokdecode4DSL/instance.c b/libsigrokdecode4DSL/instance.c index 8413dca9..4041b8c5 100644 --- a/libsigrokdecode4DSL/instance.c +++ b/libsigrokdecode4DSL/instance.c @@ -31,8 +31,8 @@ extern SRD_PRIV GSList *sessions; -/* type_logic.c */ -extern SRD_PRIV PyTypeObject srd_logic_type; +/* module_sigrokdecode.c */ +extern SRD_PRIV PyObject *srd_logic_type; /** @endcond */ @@ -156,6 +156,7 @@ SRD_API int srd_inst_option_set(struct srd_decoder_inst *di, /* Not harmful even if we used the default. */ g_hash_table_remove(options, sdo->id); } + Py_DECREF(py_di_options); if (g_hash_table_size(options) != 0) srd_warn("Unknown options specified for '%s'", di->inst_id); @@ -164,7 +165,7 @@ SRD_API int srd_inst_option_set(struct srd_decoder_inst *di, err_out: Py_XDECREF(py_optval); if (PyErr_Occurred()) { - srd_exception_catch("Stray exception in srd_inst_option_set().", NULL); + srd_exception_catch(NULL, "Stray exception in srd_inst_option_set()."); ret = SRD_ERR_PYTHON; } @@ -342,7 +343,7 @@ SRD_API struct srd_decoder_inst *srd_inst_new(struct srd_session *sess, /* Create a new instance of this decoder class. */ if (!(di->py_inst = PyObject_CallObject(dec->py_dec, NULL))) { if (PyErr_Occurred()) - srd_exception_catch("failed to create %s instance: ", NULL, + srd_exception_catch(NULL, "Failed to create %s instance: ", decoder_id); g_free(di->dec_channelmap); g_free(di); @@ -507,15 +508,16 @@ SRD_PRIV int srd_inst_start(struct srd_decoder_inst *di, char **error) di->inst_id); if (!(py_res = PyObject_CallMethod(di->py_inst, "start", NULL))) { - srd_exception_catch("Protocol decoder instance %s: ", error, + srd_exception_catch(error, "Decoder %s", di->inst_id); return SRD_ERR_PYTHON; } Py_DecRef(py_res); if ((di->decoder->channels || di->decoder->opt_channels) != 0 ) { - logic = PyObject_New(srd_logic, &srd_logic_type); - //Py_INCREF(logic); + //logic = PyObject_New(srd_logic, &srd_logic_type); + logic = PyObject_New(srd_logic, (PyTypeObject *)srd_logic_type); + Py_INCREF(logic); logic->di = (struct srd_decoder_inst *)di; logic->sample = PyList_New(2); //Py_INCREF(logic->sample); @@ -542,7 +544,6 @@ SRD_PRIV int srd_inst_start(struct srd_decoder_inst *di, char **error) * set, relative to the start of capture. * @param inbuf The buffer to decode. Must not be NULL. * @param inbuflen Length of the buffer. Must be > 0. - * @param unitsize The number of bytes per sample. * * @return SRD_OK upon success, a (negative) error code otherwise. * @@ -552,32 +553,25 @@ SRD_PRIV int srd_inst_start(struct srd_decoder_inst *di, char **error) */ SRD_PRIV int srd_inst_decode(const struct srd_decoder_inst *di, uint8_t chunk_type, uint64_t start_samplenum, uint64_t end_samplenum, - const uint8_t *inbuf, uint64_t inbuflen, uint64_t unitsize, char **error) + const uint8_t **inbuf, const uint8_t *inbuf_const, char **error) { PyObject *py_res; srd_logic *logic; /* Return an error upon unusable input. */ if (!di) { - srd_dbg("empty decoder instance"); + *error = g_strdup("Empty decoder instance"); return SRD_ERR_ARG; } - if (!inbuf) { - srd_dbg("NULL buffer pointer"); + if (end_samplenum < start_samplenum) { + *error = g_strdup("Invalid start/end index couple"); return SRD_ERR_ARG; } - if (inbuflen == 0) { - srd_dbg("empty buffer"); - return SRD_ERR_ARG; - } - - ((struct srd_decoder_inst *)di)->data_unitsize = unitsize; srd_dbg("Calling decode(), start sample %" PRIu64 ", end sample %" - PRIu64 " (%" PRIu64 " samples, %" PRIu64 " bytes, unitsize = " - "%d), instance %s.", start_samplenum, end_samplenum, - end_samplenum - start_samplenum, inbuflen, di->data_unitsize, - di->inst_id); + PRIu64 " (%" PRIu64 " samples, instance %s.", + start_samplenum, end_samplenum, + end_samplenum - start_samplenum + 1, di->inst_id); /* * Create new srd_logic object. Each iteration around the PD's loop @@ -586,24 +580,25 @@ SRD_PRIV int srd_inst_decode(const struct srd_decoder_inst *di, uint8_t chunk_ty logic = di->py_logic; logic->start_samplenum = start_samplenum; if (chunk_type == 0) { - logic->itercnt = 0; + logic->itercnt = 0; // *inbuf is a byte pointer, 8bit align logic->logic_mask = 0; } - logic->inbuf = (uint8_t *)inbuf; - logic->inbuflen = inbuflen; + logic->inbuf = (uint8_t **)inbuf; + logic->inbuf_const = inbuf_const; + logic->samplenum = end_samplenum - start_samplenum + 1; Py_INCREF(logic); //Py_IncRef(di->py_inst); if (!(py_res = PyObject_CallMethod(di->py_inst, "decode", "KKO", start_samplenum, end_samplenum, logic))) { - srd_exception_catch("Protocol decoder instance %s: ", error, + srd_exception_catch(error, "Decoder %s", di->inst_id); return SRD_ERR_PYTHON; } Py_DecRef(py_res); if (logic->logic_mask == 0) - logic->itercnt -= logic->inbuflen / logic->di->data_unitsize; + logic->itercnt -= logic->samplenum; return SRD_OK; } @@ -627,7 +622,7 @@ SRD_PRIV void srd_inst_free(struct srd_decoder_inst *di) Py_DecRef(di->py_inst); g_free(di->inst_id); g_free(di->dec_channelmap); - g_free(di->channel_samples); + g_free(di->channel_samples); g_slist_free(di->next_di); for (l = di->pd_output; l; l = l->next) { pdo = l->data; diff --git a/libsigrokdecode4DSL/libsigrokdecode-internal.h b/libsigrokdecode4DSL/libsigrokdecode-internal.h index 4bfcc68b..0131907c 100644 --- a/libsigrokdecode4DSL/libsigrokdecode-internal.h +++ b/libsigrokdecode4DSL/libsigrokdecode-internal.h @@ -22,6 +22,9 @@ #ifndef LIBSIGROKDECODE_LIBSIGROKDECODE_INTERNAL_H #define LIBSIGROKDECODE_LIBSIGROKDECODE_INTERNAL_H +/* Use the stable ABI subset as per PEP 384. */ +#define Py_LIMITED_API 0x03020000 + #include /* First, so we avoid a _POSIX_C_SOURCE warning. */ #include "libsigrokdecode.h" #include @@ -33,8 +36,9 @@ typedef struct { struct srd_decoder_inst *di; uint64_t start_samplenum; float itercnt; - uint8_t *inbuf; - uint64_t inbuflen; + uint8_t **inbuf; + const uint8_t *inbuf_const; + uint64_t samplenum; PyObject *sample; uint64_t exp_logic; @@ -57,7 +61,7 @@ SRD_PRIV struct srd_decoder_inst *srd_inst_find_by_obj( const GSList *stack, SRD_PRIV int srd_inst_start(struct srd_decoder_inst *di, char **error); SRD_PRIV int srd_inst_decode(const struct srd_decoder_inst *di, uint8_t chunk_type, uint64_t start_samplenum, uint64_t end_samplenum, - const uint8_t *inbuf, uint64_t inbuflen, uint64_t unitsize, char **error); + const uint8_t **inbuf, const uint8_t *inbuf_const, char **error); SRD_PRIV void srd_inst_free(struct srd_decoder_inst *di); SRD_PRIV void srd_inst_free_all(struct srd_session *sess, GSList *stack); @@ -79,18 +83,37 @@ SRD_PRIV int srd_log(int loglevel, const char *format, ...) G_GNUC_PRINTF(2, 3); #define srd_warn(...) srd_log(SRD_LOG_WARN, __VA_ARGS__) #define srd_err(...) srd_log(SRD_LOG_ERR, __VA_ARGS__) +/* decoder.c */ +SRD_PRIV long srd_decoder_apiver(const struct srd_decoder *d); + +/* type_decoder.c */ +SRD_PRIV PyObject *srd_Decoder_type_new(void); + +/* type_logic.c */ +SRD_PRIV PyObject *srd_logic_type_new(void); + /* module_sigrokdecode.c */ PyMODINIT_FUNC PyInit_sigrokdecode(void); /* util.c */ -SRD_PRIV int py_attr_as_str(const PyObject *py_obj, const char *attr, - char **outstr); -SRD_PRIV int py_dictitem_as_str(const PyObject *py_obj, const char *key, - char **outstr); -SRD_PRIV int py_str_as_str(const PyObject *py_str, char **outstr); -SRD_PRIV int py_strseq_to_char(const PyObject *py_strseq, char ***outstr); +SRD_PRIV PyObject *py_import_by_name(const char *name); +SRD_PRIV int py_attr_as_str(PyObject *py_obj, const char *attr, char **outstr); +SRD_PRIV int py_dictitem_as_str(PyObject *py_obj, const char *key, char **outstr); +SRD_PRIV int py_dictitem_to_int(PyObject *py_obj, const char *key); +SRD_PRIV int py_str_as_str(PyObject *py_str, char **outstr); +SRD_PRIV int py_strseq_to_char(PyObject *py_strseq, char ***out_strv); +SRD_PRIV GVariant *py_obj_to_variant(PyObject *py_obj); /* exception.c */ -SRD_PRIV void srd_exception_catch(const char *format, char **error, ...); +#if defined(G_OS_WIN32) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) +/* + * On MinGW, we need to specify the gnu_printf format flavor or GCC + * will assume non-standard Microsoft printf syntax. + */ +SRD_PRIV void srd_exception_catch(char **error, const char *format, ...) + __attribute__((__format__ (__gnu_printf__, 2, 3))); +#else +SRD_PRIV void srd_exception_catch(char **error, const char *format, ...) G_GNUC_PRINTF(2, 3); +#endif #endif diff --git a/libsigrokdecode4DSL/libsigrokdecode.h b/libsigrokdecode4DSL/libsigrokdecode.h index 162e57b6..14bdd6a2 100644 --- a/libsigrokdecode4DSL/libsigrokdecode.h +++ b/libsigrokdecode4DSL/libsigrokdecode.h @@ -43,7 +43,7 @@ extern "C" { * The correct way to get/use the libsigrokdecode API functions is: * * @code{.c} - * #include + * #include * @endcode */ @@ -146,6 +146,15 @@ enum srd_configkey { SRD_CONF_SAMPLERATE = 10000, }; +enum srd_channel_type { + SRD_CHANNEL_COMMON = -1, + SRD_CHANNEL_SCLK, + SRD_CHANNEL_SDATA, + SRD_CHANNEL_ADATA, +}; + +extern char decoders_path[256]; + struct srd_decoder { /** The decoder ID. Must be non-NULL and unique for all decoders. */ char *id; @@ -213,6 +222,8 @@ struct srd_channel { char *desc; /** The index of the channel, i.e. its order in the list of channels. */ int order; + /** The type of the channel, such us: sclk/sdata/.../others */ + int type; }; struct srd_decoder_option { @@ -237,7 +248,6 @@ struct srd_decoder_inst { GSList *pd_output; int dec_num_channels; int *dec_channelmap; - int data_unitsize; uint8_t *channel_samples; GSList *next_di; uint64_t cur_pos; @@ -294,7 +304,7 @@ SRD_API int srd_session_metadata_set(struct srd_session *sess, int key, GVariant *data); SRD_API int srd_session_send(struct srd_session *sess, uint8_t chunk_type, uint64_t start_samplenum, uint64_t end_samplenum, - const uint8_t *inbuf, uint64_t inbuflen, uint64_t unitsize, char **error); + const uint8_t **inbuf, const uint8_t *inbuf_const, char **error); SRD_API int srd_session_destroy(struct srd_session *sess); SRD_API int srd_pd_output_callback_add(struct srd_session *sess, int output_type, srd_pd_output_callback cb, void *cb_data); diff --git a/libsigrokdecode4DSL/libsigrokdecode.pc.in b/libsigrokdecode4DSL/libsigrokdecode.pc.in deleted file mode 100644 index 3051145d..00000000 --- a/libsigrokdecode4DSL/libsigrokdecode.pc.in +++ /dev/null @@ -1,18 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ -datarootdir=@datarootdir@ -datadir=@datadir@ -pkgdatadir=${datadir}/@PACKAGE_TARNAME@ -decodersdir=${pkgdatadir}/decoders - -Name: libsigrokdecode -Description: Protocol decoder library of the sigrok logic analyzer software -URL: http://www.sigrok.org -Requires: glib-2.0 -Requires.private: @SRD_PKGLIBS@ -Version: @SRD_PACKAGE_VERSION@ -Libs: -L${libdir} -lsigrokdecode -Libs.private: @SRD_EXTRA_LIBS@ -Cflags: -I${includedir} diff --git a/libsigrokdecode4DSL/module_sigrokdecode.c b/libsigrokdecode4DSL/module_sigrokdecode.c index 99fa27fc..54b5573b 100644 --- a/libsigrokdecode4DSL/module_sigrokdecode.c +++ b/libsigrokdecode4DSL/module_sigrokdecode.c @@ -17,17 +17,13 @@ * along with this program. If not, see . */ +#include "libsigrokdecode.h" /* First, so we avoid a _POSIX_C_SOURCE warning. */ +#include "libsigrokdecode-internal.h" #include "config.h" -#include "libsigrokdecode-internal.h" /* First, so we avoid a _POSIX_C_SOURCE warning. */ -#include "libsigrokdecode.h" /** @cond PRIVATE */ -/* type_decoder.c */ -extern SRD_PRIV PyTypeObject srd_Decoder_type; - -/* type_logic.c */ -extern SRD_PRIV PyTypeObject srd_logic_type; +SRD_PRIV PyObject *srd_logic_type = NULL; /* * When initialized, a reference to this module inside the Python interpreter @@ -47,42 +43,45 @@ static struct PyModuleDef sigrokdecode_module = { /** @cond PRIVATE */ PyMODINIT_FUNC PyInit_sigrokdecode(void) { - PyObject *mod; - - /* tp_new needs to be assigned here for compiler portability. */ - srd_Decoder_type.tp_new = PyType_GenericNew; - if (PyType_Ready(&srd_Decoder_type) < 0) - return NULL; - - srd_logic_type.tp_new = PyType_GenericNew; - if (PyType_Ready(&srd_logic_type) < 0) - return NULL; + PyObject *mod, *Decoder_type, *logic_type; mod = PyModule_Create(&sigrokdecode_module); - Py_INCREF(&srd_Decoder_type); - if (PyModule_AddObject(mod, "Decoder", - (PyObject *)&srd_Decoder_type) == -1) - return NULL; - Py_INCREF(&srd_logic_type); - if (PyModule_AddObject(mod, "srd_logic", - (PyObject *)&srd_logic_type) == -1) - return NULL; + if (!mod) + goto err_out; + + Decoder_type = srd_Decoder_type_new(); + if (!Decoder_type) + goto err_out; + if (PyModule_AddObject(mod, "Decoder", Decoder_type) < 0) + goto err_out; + + logic_type = srd_logic_type_new(); + if (!logic_type) + goto err_out; + if (PyModule_AddObject(mod, "srd_logic", logic_type) < 0) + goto err_out; /* Expose output types as symbols in the sigrokdecode module */ - if (PyModule_AddIntConstant(mod, "OUTPUT_ANN", SRD_OUTPUT_ANN) == -1) - return NULL; - if (PyModule_AddIntConstant(mod, "OUTPUT_PYTHON", SRD_OUTPUT_PYTHON) == -1) - return NULL; - if (PyModule_AddIntConstant(mod, "OUTPUT_BINARY", SRD_OUTPUT_BINARY) == -1) - return NULL; - if (PyModule_AddIntConstant(mod, "OUTPUT_META", SRD_OUTPUT_META) == -1) - return NULL; + if (PyModule_AddIntConstant(mod, "OUTPUT_ANN", SRD_OUTPUT_ANN) < 0) + goto err_out; + if (PyModule_AddIntConstant(mod, "OUTPUT_PYTHON", SRD_OUTPUT_PYTHON) < 0) + goto err_out; + if (PyModule_AddIntConstant(mod, "OUTPUT_BINARY", SRD_OUTPUT_BINARY) < 0) + goto err_out; + if (PyModule_AddIntConstant(mod, "OUTPUT_META", SRD_OUTPUT_META) < 0) + goto err_out; /* Expose meta input symbols. */ - if (PyModule_AddIntConstant(mod, "SRD_CONF_SAMPLERATE", SRD_CONF_SAMPLERATE) == -1) - return NULL; + if (PyModule_AddIntConstant(mod, "SRD_CONF_SAMPLERATE", SRD_CONF_SAMPLERATE) < 0) + goto err_out; + srd_logic_type = logic_type; mod_sigrokdecode = mod; return mod; +err_out: + Py_XDECREF(mod); + srd_exception_catch(NULL, "Failed to initialize module"); + + return NULL; } /** @endcond */ diff --git a/libsigrokdecode4DSL/session.c b/libsigrokdecode4DSL/session.c index 676c54bb..67954e30 100644 --- a/libsigrokdecode4DSL/session.c +++ b/libsigrokdecode4DSL/session.c @@ -128,19 +128,27 @@ static int srd_inst_send_meta(struct srd_decoder_inst *di, int key, GVariant *data) { PyObject *py_ret; + GSList *l; + struct srd_decoder_inst *next_di; + int ret; if (key != SRD_CONF_SAMPLERATE) /* This is the only key we pass on to the decoder for now. */ return SRD_OK; - if (!PyObject_HasAttrString(di->py_inst, "metadata")) - /* This decoder doesn't want metadata, that's fine. */ - return SRD_OK; + if (PyObject_HasAttrString(di->py_inst, "metadata")) { + py_ret = PyObject_CallMethod(di->py_inst, "metadata", "lK", + (long)SRD_CONF_SAMPLERATE, + (unsigned long long)g_variant_get_uint64(data)); + Py_XDECREF(py_ret); + } - py_ret = PyObject_CallMethod(di->py_inst, "metadata", "lK", - (long)SRD_CONF_SAMPLERATE, - (unsigned long long)g_variant_get_uint64(data)); - Py_XDECREF(py_ret); + /* Push metadata to all the PDs stacked on top of this one. */ + for (l = di->next_di; l; l = l->next) { + next_di = l->data; + if ((ret = srd_inst_send_meta(next_di, key, data)) != SRD_OK) + return ret; + } return SRD_OK; } @@ -212,16 +220,11 @@ SRD_API int srd_session_metadata_set(struct srd_session *sess, int key, * in channel order, in the least amount of space possible. The default * channel set consists of all required channels + all optional channels. * - * The size of a sample in inbuf is 'unitsize' bytes. If no channel map - * has been configured, it is the minimum number of bytes needed to store - * the default channels. - * * @param sess The session to use. * @param start_samplenum The sample number of the first sample in this chunk. * @param end_samplenum The sample number of the last sample in this chunk. * @param inbuf Pointer to sample data. * @param inbuflen Length in bytes of the buffer. - * @param unitsize The number of bytes per sample. * * @return SRD_OK upon success, a (negative) error code otherwise. * @@ -229,7 +232,7 @@ SRD_API int srd_session_metadata_set(struct srd_session *sess, int key, */ SRD_API int srd_session_send(struct srd_session *sess, uint8_t chunk_type, uint64_t start_samplenum, uint64_t end_samplenum, - const uint8_t *inbuf, uint64_t inbuflen, uint64_t unitsize, char **error) + const uint8_t **inbuf, const uint8_t *inbuf_const, char **error) { GSList *d; int ret; @@ -241,7 +244,7 @@ SRD_API int srd_session_send(struct srd_session *sess, uint8_t chunk_type, for (d = sess->di_list; d; d = d->next) { if ((ret = srd_inst_decode(d->data, chunk_type, start_samplenum, - end_samplenum, inbuf, inbuflen, unitsize, error)) != SRD_OK) + end_samplenum, inbuf, inbuf_const, error)) != SRD_OK) return ret; } diff --git a/libsigrokdecode4DSL/srd.c b/libsigrokdecode4DSL/srd.c index 2226816e..5933f881 100644 --- a/libsigrokdecode4DSL/srd.c +++ b/libsigrokdecode4DSL/srd.c @@ -95,6 +95,23 @@ extern SRD_PRIV int max_session_id; * @{ */ +static int searchpath_add_xdg_dir(const char *datadir) +{ + char *decdir; + int ret; + + decdir = g_build_filename(datadir, PACKAGE_TARNAME, "decoders", NULL); + + if (g_file_test(decdir, G_FILE_TEST_IS_DIR)) + ret = srd_decoder_searchpath_add(decdir); + else + ret = SRD_OK; /* just ignore non-existing directory */ + + g_free(decdir); + + return ret; +} + /** * Initialize libsigrokdecode. * @@ -124,8 +141,10 @@ extern SRD_PRIV int max_session_id; */ SRD_API int srd_init(const char *path) { + const char *const *sys_datadirs; + const char *env_path; + size_t i; int ret; - char *env_path; if (max_session_id != -1) { srd_err("libsigrokdecode is already initialized."); @@ -138,10 +157,27 @@ SRD_API int srd_init(const char *path) PyImport_AppendInittab("sigrokdecode", PyInit_sigrokdecode); /* Initialize the Python interpreter. */ - Py_Initialize(); + Py_InitializeEx(0); - /* Installed decoders. */ - if ((ret = srd_decoder_searchpath_add(DECODERS_DIR)) != SRD_OK) { + /* 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; } @@ -155,7 +191,7 @@ SRD_API int srd_init(const char *path) } /* Environment variable overrides everything, for debugging. */ - if ((env_path = getenv("SIGROKDECODE_DIR"))) { + if ((env_path = g_getenv("SIGROKDECODE_DIR"))) { if ((ret = srd_decoder_searchpath_add(env_path)) != SRD_OK) { Py_Finalize(); return ret; @@ -183,12 +219,9 @@ SRD_API int srd_init(const char *path) */ SRD_API int srd_exit(void) { - GSList *l; - srd_dbg("Exiting libsigrokdecode."); - for (l = sessions; l; l = l->next) - srd_session_destroy((struct srd_session *)l->data); + g_slist_foreach(sessions, (GFunc)srd_session_destroy, NULL); srd_decoder_unload_all(); g_slist_free_full(searchpaths, g_free); @@ -224,36 +257,26 @@ SRD_API int srd_exit(void) SRD_PRIV int srd_decoder_searchpath_add(const char *path) { PyObject *py_cur_path, *py_item; - GString *new_path; - int wc_len, i; - wchar_t *wc_new_path; - char *item; srd_dbg("Adding '%s' to module path.", path); - new_path = g_string_sized_new(256); - g_string_assign(new_path, path); py_cur_path = PySys_GetObject("path"); - for (i = 0; i < PyList_Size(py_cur_path); i++) { - g_string_append(new_path, G_SEARCHPATH_SEPARATOR_S); - py_item = PyList_GetItem(py_cur_path, i); - if (!PyUnicode_Check(py_item)) - /* Shouldn't happen. */ - continue; - if (py_str_as_str(py_item, &item) != SRD_OK) - continue; - g_string_append(new_path, item); - g_free(item); - } + if (!py_cur_path) + return SRD_ERR_PYTHON; - /* Convert to wide chars. */ - wc_len = sizeof(wchar_t) * (new_path->len + 1); - wc_new_path = g_malloc(wc_len); - mbstowcs(wc_new_path, new_path->str, wc_len); - PySys_SetPath(wc_new_path); - g_string_free(new_path, TRUE); - g_free(wc_new_path); - searchpaths = g_slist_append(searchpaths, g_strdup(path)); + py_item = PyUnicode_FromString(path); + if (!py_item) { + srd_exception_catch(NULL, "Failed to create Unicode object"); + return SRD_ERR_PYTHON; + } + if (PyList_Insert(py_cur_path, 0, py_item) < 0) { + srd_exception_catch(NULL, "Failed to insert path element"); + Py_DECREF(py_item); + return SRD_ERR_PYTHON; + } + Py_DECREF(py_item); + + searchpaths = g_slist_prepend(searchpaths, g_strdup(path)); return SRD_OK; } diff --git a/libsigrokdecode4DSL/type_decoder.c b/libsigrokdecode4DSL/type_decoder.c index b922d8a9..907b0d8c 100644 --- a/libsigrokdecode4DSL/type_decoder.c +++ b/libsigrokdecode4DSL/type_decoder.c @@ -22,18 +22,25 @@ #include "libsigrokdecode-internal.h" /* First, so we avoid a _POSIX_C_SOURCE warning. */ #include "libsigrokdecode.h" #include +#include typedef struct { PyObject_HEAD } srd_Decoder; -/* This is only used for nicer srd_dbg() output. */ -static const char *OUTPUT_TYPES[] = { - "OUTPUT_ANN", - "OUTPUT_PYTHON", - "OUTPUT_BINARY", - "OUTPUT_META", -}; +/* This is only used for nicer srd_dbg() output. + */ +static const char *output_type_name(unsigned int idx) +{ + static const char names[][16] = { + "OUTPUT_ANN", + "OUTPUT_PYTHON", + "OUTPUT_BINARY", + "OUTPUT_META", + "(invalid)" + }; + return names[MIN(idx, G_N_ELEMENTS(names) - 1)]; +} static int convert_annotation(struct srd_decoder_inst *di, PyObject *obj, struct srd_proto_data *pdata) @@ -45,9 +52,9 @@ static int convert_annotation(struct srd_decoder_inst *di, PyObject *obj, gpointer ann_type_ptr; /* Should be a list of [annotation class, [string, ...]]. */ - if (!PyList_Check(obj) && !PyTuple_Check(obj)) { - srd_err("Protocol decoder %s submitted %s instead of list.", - di->decoder->name, obj->ob_type->tp_name); + if (!PyList_Check(obj)) { + srd_err("Protocol decoder %s submitted an annotation that" + " is not a list", di->decoder->name); return SRD_ERR_PYTHON; } @@ -63,8 +70,8 @@ static int convert_annotation(struct srd_decoder_inst *di, PyObject *obj, * The first element should be an integer matching a previously * registered annotation class. */ - py_tmp = PyList_GetItem(obj, 0); - if (!PyLong_Check(py_tmp)) { + py_tmp = PyList_GetItem(obj, 0); + if (!PyLong_Check(py_tmp)) { srd_err("Protocol decoder %s submitted annotation list, but " "first element was not an integer.", di->decoder->name); return SRD_ERR_PYTHON; @@ -83,13 +90,13 @@ static int convert_annotation(struct srd_decoder_inst *di, PyObject *obj, ann_type_ptr = g_slist_nth_data(di->decoder->ann_types, ann_class); /* Second element must be a list. */ - py_tmp = PyList_GetItem(obj, 1); - if (!PyList_Check(py_tmp)) { + 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); return SRD_ERR_PYTHON; } - if (py_strseq_to_char(py_tmp, &ann_text) != SRD_OK) { + if (py_strseq_to_char(py_tmp, &ann_text) != SRD_OK) { srd_err("Protocol decoder %s submitted annotation list, but " "second element was malformed.", di->decoder->name); return SRD_ERR_PYTHON; @@ -101,8 +108,6 @@ static int convert_annotation(struct srd_decoder_inst *di, PyObject *obj, pda->ann_text = ann_text; pdata->data = pda; - //Py_DECREF(py_tmp); - return SRD_OK; } @@ -115,26 +120,25 @@ static int convert_binary(struct srd_decoder_inst *di, PyObject *obj, int bin_class; char *class_name, *buf; - /* Should be a tuple of (binary class, bytes). */ - if (!PyTuple_Check(obj)) { - srd_err("Protocol decoder %s submitted SRD_OUTPUT_BINARY with " - "%s instead of tuple.", di->decoder->name, - obj->ob_type->tp_name); + /* Should be a list of [binary class, bytes]. */ + if (!PyList_Check(obj)) { + srd_err("Protocol decoder %s submitted non-list for SRD_OUTPUT_BINARY.", + di->decoder->name); return SRD_ERR_PYTHON; } /* Should have 2 elements. */ - if (PyTuple_Size(obj) != 2) { - srd_err("Protocol decoder %s submitted SRD_OUTPUT_BINARY tuple " + if (PyList_Size(obj) != 2) { + srd_err("Protocol decoder %s submitted SRD_OUTPUT_BINARY list " "with %zd elements instead of 2", di->decoder->name, PyList_Size(obj)); return SRD_ERR_PYTHON; } /* The first element should be an integer. */ - py_tmp = PyTuple_GetItem(obj, 0); + py_tmp = PyList_GetItem(obj, 0); if (!PyLong_Check(py_tmp)) { - srd_err("Protocol decoder %s submitted SRD_OUTPUT_BINARY tuple, " + srd_err("Protocol decoder %s submitted SRD_OUTPUT_BINARY list, " "but first element was not an integer.", di->decoder->name); return SRD_ERR_PYTHON; } @@ -146,9 +150,9 @@ static int convert_binary(struct srd_decoder_inst *di, PyObject *obj, } /* Second element should be bytes. */ - py_tmp = PyTuple_GetItem(obj, 1); + py_tmp = PyList_GetItem(obj, 1); if (!PyBytes_Check(py_tmp)) { - srd_err("Protocol decoder %s submitted SRD_OUTPUT_BINARY tuple, " + srd_err("Protocol decoder %s submitted SRD_OUTPUT_BINARY list, " "but second element was not bytes.", di->decoder->name); return SRD_ERR_PYTHON; } @@ -170,8 +174,6 @@ static int convert_binary(struct srd_decoder_inst *di, PyObject *obj, memcpy((void *)pdb->data, (const void *)buf, pdb->size); pdata->data = pdb; - //Py_DECREF(py_tmp); - return SRD_OK; } @@ -183,7 +185,7 @@ static int convert_meta(struct srd_proto_data *pdata, PyObject *obj) if (pdata->pdo->meta_type == G_VARIANT_TYPE_INT64) { if (!PyLong_Check(obj)) { PyErr_Format(PyExc_TypeError, "This output was registered " - "as 'int', but '%s' was passed.", obj->ob_type->tp_name); + "as 'int', but something else was passed."); return SRD_ERR_PYTHON; } intvalue = PyLong_AsLongLong(obj); @@ -193,7 +195,7 @@ static int convert_meta(struct srd_proto_data *pdata, PyObject *obj) } else if (pdata->pdo->meta_type == G_VARIANT_TYPE_DOUBLE) { if (!PyFloat_Check(obj)) { PyErr_Format(PyExc_TypeError, "This output was registered " - "as 'float', but '%s' was passed.", obj->ob_type->tp_name); + "as 'float', but something else was passed."); return SRD_ERR_PYTHON; } dvalue = PyFloat_AsDouble(obj); @@ -219,37 +221,37 @@ static PyObject *Decoder_put(PyObject *self, PyObject *args) struct srd_proto_data_annotation *pda; char **annotations; - if (!(di = srd_inst_find_by_obj(NULL, self))) { - /* Shouldn't happen. */ - srd_dbg("put(): self instance not found."); - return NULL; - } + if (!(di = srd_inst_find_by_obj(NULL, self))) { + /* Shouldn't happen. */ + srd_dbg("put(): self instance not found."); + return NULL; + } - if (!PyArg_ParseTuple(args, "KKiO", &start_sample, &end_sample, - &output_id, &py_data)) { - /* - * This throws an exception, but by returning NULL here we let - * Python raise it. This results in a much better trace in - * controller.c on the decode() method call. - */ - return NULL; - } + if (!PyArg_ParseTuple(args, "KKiO", &start_sample, &end_sample, + &output_id, &py_data)) { + /* + * This throws an exception, but by returning NULL here we let + * Python raise it. This results in a much better trace in + * controller.c on the decode() method call. + */ + return NULL; + } - if (!(l = g_slist_nth(di->pd_output, output_id))) { - srd_err("Protocol decoder %s submitted invalid output ID %d.", - di->decoder->name, output_id); - return NULL; - } - pdo = l->data; + if (!(l = g_slist_nth(di->pd_output, output_id))) { + srd_err("Protocol decoder %s submitted invalid output ID %d.", + di->decoder->name, output_id); + return NULL; + } + pdo = l->data; - srd_spew("Instance %s put %" PRIu64 "-%" PRIu64 " %s on oid %d.", - di->inst_id, start_sample, end_sample, - OUTPUT_TYPES[pdo->output_type], output_id); + srd_spew("Instance %s put %" PRIu64 "-%" PRIu64 " %s on oid %d.", + di->inst_id, start_sample, end_sample, + output_type_name(pdo->output_type), output_id); - pdata = g_malloc0(sizeof(struct srd_proto_data)); - pdata->start_sample = start_sample; - pdata->end_sample = end_sample; - pdata->pdo = pdo; + pdata = g_malloc0(sizeof(struct srd_proto_data)); + pdata->start_sample = start_sample; + pdata->end_sample = end_sample; + pdata->pdo = pdo; switch (pdo->output_type) { case SRD_OUTPUT_ANN: @@ -279,7 +281,7 @@ static PyObject *Decoder_put(PyObject *self, PyObject *args) if (!(py_res = PyObject_CallMethod( next_di->py_inst, "decode", "KKO", start_sample, end_sample, py_data))) { - srd_exception_catch("Calling %s decode(): ", NULL, + srd_exception_catch(NULL, "Calling %s decode() failed", next_di->inst_id); } Py_XDECREF(py_res); @@ -320,10 +322,9 @@ static PyObject *Decoder_put(PyObject *self, PyObject *args) break; } - g_free(pdata); - //Py_XDECREF(py_data); + g_free(pdata); - Py_RETURN_NONE; + Py_RETURN_NONE; } static PyObject *Decoder_register(PyObject *self, PyObject *args, @@ -363,8 +364,7 @@ static PyObject *Decoder_register(PyObject *self, PyObject *args, else if (meta_type_py == &PyFloat_Type) meta_type_gv = G_VARIANT_TYPE_DOUBLE; else { - PyErr_Format(PyExc_TypeError, "Unsupported type '%s'.", - meta_type_py->tp_name); + PyErr_Format(PyExc_TypeError, "Unsupported type."); return NULL; } } @@ -400,13 +400,24 @@ static PyMethodDef Decoder_methods[] = { {NULL, NULL, 0, NULL} }; -/** @cond PRIVATE */ -SRD_PRIV PyTypeObject srd_Decoder_type = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "sigrokdecode.Decoder", - .tp_basicsize = sizeof(srd_Decoder), - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - .tp_doc = "sigrok Decoder base class", - .tp_methods = Decoder_methods, -}; -/** @endcond */ +/** Create the sigrokdecode.Decoder type. + * @return The new type object. + * @private + */ +SRD_PRIV PyObject *srd_Decoder_type_new(void) +{ + PyType_Spec spec; + PyType_Slot slots[] = { + { Py_tp_doc, "sigrok Decoder base class" }, + { Py_tp_methods, Decoder_methods }, + { Py_tp_new, (void *)&PyType_GenericNew }, + { 0, NULL } + }; + spec.name = "sigrokdecode.Decoder"; + spec.basicsize = sizeof(srd_Decoder); + spec.itemsize = 0; + spec.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; + spec.slots = slots; + + return PyType_FromSpec(&spec); +} diff --git a/libsigrokdecode4DSL/type_logic.c b/libsigrokdecode4DSL/type_logic.c index 5724d738..6f934059 100644 --- a/libsigrokdecode4DSL/type_logic.c +++ b/libsigrokdecode4DSL/type_logic.c @@ -33,28 +33,18 @@ static PyObject *srd_logic_iternext(PyObject *self) { srd_logic *logic; PyObject *py_samplenum, *py_samples; - uint8_t *sample_pos, sample; - int byte_offset, bit_offset, i; + int i; logic = (srd_logic *)self; uint64_t offset = floor(logic->itercnt); logic->di->cur_pos = logic->cur_pos; - logic->di->logic_mask = 0; - logic->di->exp_logic = 0; - if (logic->logic_mask != 0) { - if (logic->edge_index == -1) - logic->di->edge_index = -1; - else - logic->di->edge_index = logic->di->dec_channelmap[logic->edge_index]; - for (i = 0; i < logic->di->dec_num_channels; i++) { - int index = logic->di->dec_channelmap[i]; - if ((logic->logic_mask & (0x01 << i)) && index != -1) { - logic->di->logic_mask += 0x01 << index; - logic->di->exp_logic += ((logic->exp_logic & (0x01 << i)) >> i) << index; - } - } - } - if (offset >= logic->inbuflen / logic->di->data_unitsize || logic->logic_mask != 0) { + logic->di->logic_mask = logic->logic_mask; + logic->di->exp_logic = logic->exp_logic; + logic->di->edge_index = -1; + if (logic->logic_mask != 0 && logic->edge_index != -1) + logic->di->edge_index = logic->di->dec_channelmap[logic->edge_index]; + + if (offset > logic->samplenum || logic->logic_mask != 0) { /* End iteration loop. */ return NULL; } @@ -63,17 +53,19 @@ static PyObject *srd_logic_iternext(PyObject *self) * Convert the bit-packed sample to an array of bytes, with only 0x01 * and 0x00 values, so the PD doesn't need to do any bitshifting. */ - sample_pos = logic->inbuf + offset * logic->di->data_unitsize; for (i = 0; i < logic->di->dec_num_channels; i++) { /* A channelmap value of -1 means "unused optional channel". */ if (logic->di->dec_channelmap[i] == -1) { /* Value of unused channel is 0xff, instead of 0 or 1. */ logic->di->channel_samples[i] = 0xff; } else { - byte_offset = logic->di->dec_channelmap[i] / 8; - bit_offset = logic->di->dec_channelmap[i] % 8; - sample = *(sample_pos + byte_offset) & (1 << bit_offset) ? 1 : 0; - logic->di->channel_samples[i] = sample; + if (*(logic->inbuf + i) == NULL) { + logic->di->channel_samples[i] = *(logic->inbuf_const + i) ? 1 : 0; + } else { + uint64_t inbuf_offset = (offset + (logic->start_samplenum % 8)); + uint8_t *ptr = *(logic->inbuf + i) + (inbuf_offset / 8); + logic->di->channel_samples[i] = *ptr & (1 << (inbuf_offset % 8)) ? 1 : 0; + } } } @@ -102,15 +94,41 @@ static PyMemberDef srd_logic_members[] = { {NULL} /* Sentinel */ }; -/** @cond PRIVATE */ -SRD_PRIV PyTypeObject srd_logic_type = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "srd_logic", - .tp_basicsize = sizeof(srd_logic), - .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_doc = "Sigrokdecode logic sample object", - .tp_members = srd_logic_members, - .tp_iter = srd_logic_iter, - .tp_iternext = srd_logic_iternext, -}; -/** @endcond */ +//static PyMemberDef srd_logic_members[] = { +//// {"itercnt", T_FLOAT, offsetof(srd_logic, itercnt), 0, +//// "next expacted samples offset"}, +// {"logic_mask", T_ULONGLONG, offsetof(srd_logic, logic_mask), 0, +// "next expacted logic value mask"}, +//// {"exp_logic", T_ULONGLONG, offsetof(srd_logic, exp_logic), 0, +//// "next expacted logic value"}, +//// {"edge_index", T_INT, offsetof(srd_logic, edge_index), 0, +//// "channel index of next expacted edge"}, +//// {"cur_pos", T_ULONGLONG, offsetof(srd_logic, cur_pos), 0, +//// "current sample position"}, +// {NULL} /* Sentinel */ +//}; + + +/** Create the srd_logic type. + * @return The new type object. + * @private + */ +SRD_PRIV PyObject *srd_logic_type_new(void) +{ + PyType_Spec spec; + PyType_Slot slots[] = { + { Py_tp_doc, "sigrokdecode logic sample object" }, + { Py_tp_iter, (void *)&srd_logic_iter }, + { Py_tp_iternext, (void *)&srd_logic_iternext }, + { Py_tp_new, (void *)&PyType_GenericNew }, + { Py_tp_members, srd_logic_members }, + { 0, NULL } + }; + spec.name = "srd_logic"; + spec.basicsize = sizeof(srd_logic); + spec.itemsize = 0; + spec.flags = Py_TPFLAGS_DEFAULT; + spec.slots = slots; + + return PyType_FromSpec(&spec); +} diff --git a/libsigrokdecode4DSL/util.c b/libsigrokdecode4DSL/util.c index 93e953eb..6e9bb22b 100644 --- a/libsigrokdecode4DSL/util.c +++ b/libsigrokdecode4DSL/util.c @@ -21,46 +21,63 @@ #include "config.h" #include "libsigrokdecode-internal.h" /* First, so we avoid a _POSIX_C_SOURCE warning. */ #include "libsigrokdecode.h" +#include "config.h" +/** + * Import a Python module by name. + * + * This function is implemented in terms of PyImport_Import() rather than + * PyImport_ImportModule(), so that the import hooks are not bypassed. + * + * @param[in] name The name of the module to load as UTF-8 string. + * @return The Python module object, or NULL if an exception occurred. The + * caller is responsible for evaluating and clearing the Python error state. + * + * @private + */ +SRD_PRIV PyObject *py_import_by_name(const char *name) +{ + PyObject *py_mod, *py_modname; + + py_modname = PyUnicode_FromString(name); + if (!py_modname) + return NULL; + + py_mod = PyImport_Import(py_modname); + Py_DECREF(py_modname); + + return py_mod; +} /** * Get the value of a Python object's attribute, returned as a newly * allocated char *. * - * @param py_obj The object to probe. - * @param attr Name of the attribute to retrieve. - * @param outstr ptr to char * storage to be filled in. + * @param[in] py_obj The object to probe. + * @param[in] attr Name of the attribute to retrieve. + * @param[out] outstr ptr to char * storage to be filled in. * * @return SRD_OK upon success, a (negative) error code otherwise. - * The 'outstr' argument points to a malloc()ed string upon success. + * The 'outstr' argument points to a g_malloc()ed string upon success. * * @private */ -SRD_PRIV int py_attr_as_str(const PyObject *py_obj, const char *attr, - char **outstr) +SRD_PRIV int py_attr_as_str(PyObject *py_obj, const char *attr, char **outstr) { PyObject *py_str; int ret; - if (!PyObject_HasAttrString((PyObject *)py_obj, attr)) { - srd_dbg("%s object has no attribute '%s'.", - Py_TYPE(py_obj)->tp_name, attr); + if (!PyObject_HasAttrString(py_obj, attr)) { + srd_dbg("Object has no attribute '%s'.", attr); return SRD_ERR_PYTHON; } - if (!(py_str = PyObject_GetAttrString((PyObject *)py_obj, attr))) { - srd_exception_catch("", NULL); - return SRD_ERR_PYTHON; - } - - if (!PyUnicode_Check(py_str)) { - srd_dbg("%s attribute should be a string, but is a %s.", - attr, Py_TYPE(py_str)->tp_name); - Py_DecRef(py_str); + if (!(py_str = PyObject_GetAttrString(py_obj, attr))) { + srd_exception_catch(NULL, "Failed to get attribute '%s'", attr); return SRD_ERR_PYTHON; } ret = py_str_as_str(py_str, outstr); - Py_DecRef(py_str); + Py_DECREF(py_str); return ret; } @@ -69,136 +86,215 @@ SRD_PRIV int py_attr_as_str(const PyObject *py_obj, const char *attr, * Get the value of a Python dictionary item, returned as a newly * allocated char *. * - * @param py_obj The dictionary to probe. - * @param key Key of the item to retrieve. - * @param outstr Pointer to char * storage to be filled in. + * @param[in] py_obj The dictionary to probe. + * @param[in] key Key of the item to retrieve. + * @param[out] outstr Pointer to char * storage to be filled in. * * @return SRD_OK upon success, a (negative) error code otherwise. - * The 'outstr' argument points to a malloc()ed string upon success. + * The 'outstr' argument points to a g_malloc()ed string upon success. * * @private */ -SRD_PRIV int py_dictitem_as_str(const PyObject *py_obj, const char *key, +SRD_PRIV int py_dictitem_as_str(PyObject *py_obj, const char *key, char **outstr) { PyObject *py_value; - int ret; - if (!PyDict_Check((PyObject *)py_obj)) { - srd_dbg("Object is a %s, not a dictionary.", - Py_TYPE((PyObject *)py_obj)->tp_name); + if (!PyDict_Check(py_obj)) { + srd_dbg("Object is not a dictionary."); return SRD_ERR_PYTHON; } - if (!(py_value = PyDict_GetItemString((PyObject *)py_obj, key))) { + if (!(py_value = PyDict_GetItemString(py_obj, key))) { srd_dbg("Dictionary has no attribute '%s'.", key); return SRD_ERR_PYTHON; } - if (!PyUnicode_Check(py_value)) { - srd_dbg("Dictionary value for %s should be a string, but is " - "a %s.", key, Py_TYPE(py_value)->tp_name); - return SRD_ERR_PYTHON; - } + return py_str_as_str(py_value, outstr); +} - ret = py_str_as_str(py_value, outstr); +/** + * Get the value of a Python dictionary item, returned as a int. + * + * @param[in] py_obj The dictionary to probe. + * @param[in] key Key of the item to retrieve. + * + * @return -1 upon failed + * + * @private + */ +SRD_PRIV int py_dictitem_to_int(PyObject *py_obj, const char *key) +{ + PyObject *py_value; + long type; - return ret; + if (!PyDict_Check(py_obj)) { + srd_dbg("Object is not a dictionary."); + return -1; + } + + if (!(py_value = PyDict_GetItemString(py_obj, key))) { + srd_dbg("Dictionary has no attribute '%s'.", key); + return -1; + } + + type = PyLong_Check(py_value) ? PyLong_AsLong(py_value) : -1; + + return type; } /** * Get the value of a Python unicode string object, returned as a newly * allocated char *. * - * @param py_str The unicode string object. - * @param outstr ptr to char * storage to be filled in. + * @param[in] py_str The unicode string object. + * @param[out] outstr ptr to char * storage to be filled in. * * @return SRD_OK upon success, a (negative) error code otherwise. - * The 'outstr' argument points to a malloc()ed string upon success. + * The 'outstr' argument points to a g_malloc()ed string upon success. * * @private */ -SRD_PRIV int py_str_as_str(const PyObject *py_str, char **outstr) +SRD_PRIV int py_str_as_str(PyObject *py_str, char **outstr) { - PyObject *py_encstr; - int ret; + PyObject *py_bytes; char *str; - py_encstr = NULL; - str = NULL; - ret = SRD_OK; - - if (!PyUnicode_Check((PyObject *)py_str)) { - srd_dbg("Object is a %s, not a string object.", - Py_TYPE((PyObject *)py_str)->tp_name); - ret = SRD_ERR_PYTHON; - goto err_out; + if (!PyUnicode_Check(py_str)) { + srd_dbg("Object is not a string object."); + return SRD_ERR_PYTHON; } - if (!(py_encstr = PyUnicode_AsEncodedString((PyObject *)py_str, - "utf-8", NULL))) { - ret = SRD_ERR_PYTHON; - goto err_out; - } - if (!(str = PyBytes_AS_STRING(py_encstr))) { - ret = SRD_ERR_PYTHON; - goto err_out; + py_bytes = PyUnicode_AsUTF8String(py_str); + if (py_bytes) { + str = g_strdup(PyBytes_AsString(py_bytes)); + Py_DECREF(py_bytes); + if (str) { + *outstr = str; + return SRD_OK; + } } + srd_exception_catch(NULL, "Failed to extract string"); - *outstr = g_strdup(str); - -err_out: - if (py_encstr) - Py_XDECREF(py_encstr); - - if (PyErr_Occurred()) { - srd_exception_catch("string conversion failed", NULL); - } - - return ret; + return SRD_ERR_PYTHON; } /** - * Convert a Python list of unicode strings to a NULL-terminated UTF8-encoded - * char * array. The caller must g_free() each string when finished. + * Convert a Python list of unicode strings to a C string vector. + * On success, a pointer to a newly allocated NULL-terminated array of + * allocated C strings is written to @a out_strv. The caller must g_free() + * each string and the array itself. * - * @param py_strlist The list object. - * @param outstr ptr to char ** storage to be filled in. + * @param[in] py_strseq The sequence object. + * @param[out] out_strv Address of string vector to be filled in. * * @return SRD_OK upon success, a (negative) error code otherwise. - * The 'outstr' argument points to a g_malloc()ed char** upon success. * * @private */ -SRD_PRIV int py_strseq_to_char(const PyObject *py_strseq, char ***outstr) +SRD_PRIV int py_strseq_to_char(PyObject *py_strseq, char ***out_strv) { - PyObject *py_seq, *py_str; - int list_len, i; - char **out, *str; + PyObject *py_item, *py_bytes; + char **strv, *str; + ssize_t seq_len, i; - list_len = PySequence_Size((PyObject *)py_strseq); - if (!(out = g_try_malloc(sizeof(char *) * (list_len + 1)))) { - srd_err("Failed to g_malloc() 'out'."); + if (!PySequence_Check(py_strseq)) { + srd_err("Object does not provide sequence protocol."); + return SRD_ERR_PYTHON; + } + + seq_len = PySequence_Size(py_strseq); + if (seq_len < 0) { + srd_exception_catch(NULL, "Failed to obtain sequence size"); + return SRD_ERR_PYTHON; + } + + strv = g_try_new0(char *, seq_len + 1); + if (!strv) { + srd_err("Failed to allocate result string vector."); return SRD_ERR_MALLOC; } - for (i = 0; i < list_len; i++) { -// if (!(py_str = PyUnicode_AsEncodedString( -// PySequence_GetItem((PyObject *)py_strseq, i), "utf-8", NULL))) -// return SRD_ERR_PYTHON; -// if (!(str = PyBytes_AS_STRING(py_str))) -// return SRD_ERR_PYTHON; - py_seq = PySequence_GetItem((PyObject *)py_strseq, i); - if (!(py_str = PyUnicode_AsEncodedString(py_seq, "utf-8", NULL))) - return SRD_ERR_PYTHON; - if (!(str = PyBytes_AS_STRING(py_str))) - return SRD_ERR_PYTHON; - out[i] = g_strdup(str); - Py_XDECREF(py_seq); - Py_XDECREF(py_str); + for (i = 0; i < seq_len; i++) { + py_item = PySequence_GetItem(py_strseq, i); + if (!py_item) + goto err_out; + + if (!PyUnicode_Check(py_item)) { + Py_DECREF(py_item); + goto err_out; + } + py_bytes = PyUnicode_AsUTF8String(py_item); + Py_DECREF(py_item); + if (!py_bytes) + goto err_out; + + str = g_strdup(PyBytes_AsString(py_bytes)); + Py_DECREF(py_bytes); + if (!str) + goto err_out; + + strv[i] = str; } - out[i] = NULL; - *outstr = out; + *out_strv = strv; return SRD_OK; + +err_out: + g_strfreev(strv); + srd_exception_catch(NULL, "Failed to obtain string item"); + + return SRD_ERR_PYTHON; +} + +/** + * Convert a Python scalar object to a GLib variant. + * Supported variant types are string, int64 and double. + * + * @param[in] py_obj The Python object. Must not be NULL. + * @return A floating reference to a new variant, or NULL on failure. + * + * @private + */ +SRD_PRIV GVariant *py_obj_to_variant(PyObject *py_obj) +{ + GVariant *var = NULL; + + if (PyUnicode_Check(py_obj)) { /* string */ + PyObject *py_bytes; + const char *str; + + py_bytes = PyUnicode_AsUTF8String(py_obj); + if (py_bytes) { + str = PyBytes_AsString(py_bytes); + if (str) + var = g_variant_new_string(str); + Py_DECREF(py_bytes); + } + if (!var) + srd_exception_catch(NULL, "Failed to extract string value"); + + } else if (PyLong_Check(py_obj)) { /* integer */ + int64_t val; + + val = PyLong_AsLongLong(py_obj); + if (!PyErr_Occurred()) + var = g_variant_new_int64(val); + else + srd_exception_catch(NULL, "Failed to extract integer value"); + + } else if (PyFloat_Check(py_obj)) { /* float */ + double val; + + val = PyFloat_AsDouble(py_obj); + if (!PyErr_Occurred()) + var = g_variant_new_double(val); + else + srd_exception_catch(NULL, "Failed to extract float value"); + + } else { + srd_err("Failed to extract value of unsupported type."); + } + + return var; }