]> sigrok.org Git - pulseview.git/blob - pv/session.cpp
Session: Simplified logic of set_device
[pulseview.git] / pv / session.cpp
1 /*
2  * This file is part of the PulseView project.
3  *
4  * Copyright (C) 2012-14 Joel Holdsworth <joel@airwebreathe.org.uk>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
19  */
20
21 #ifdef ENABLE_DECODE
22 #include <libsigrokdecode/libsigrokdecode.h>
23 #endif
24
25 #include "session.hpp"
26
27 #include "devicemanager.hpp"
28
29 #include "data/analog.hpp"
30 #include "data/analogsegment.hpp"
31 #include "data/decoderstack.hpp"
32 #include "data/logic.hpp"
33 #include "data/logicsegment.hpp"
34 #include "data/decode/decoder.hpp"
35
36 #include "view/analogsignal.hpp"
37 #include "view/decodetrace.hpp"
38 #include "view/logicsignal.hpp"
39
40 #include <cassert>
41 #include <mutex>
42 #include <stdexcept>
43
44 #include <sys/stat.h>
45
46 #include <QDebug>
47
48 #include <libsigrokcxx/libsigrokcxx.hpp>
49
50 using boost::shared_lock;
51 using boost::shared_mutex;
52 using boost::unique_lock;
53
54 using std::dynamic_pointer_cast;
55 using std::function;
56 using std::lock_guard;
57 using std::list;
58 using std::map;
59 using std::mutex;
60 using std::set;
61 using std::shared_ptr;
62 using std::string;
63 using std::unordered_set;
64 using std::vector;
65
66 using sigrok::Analog;
67 using sigrok::Channel;
68 using sigrok::ChannelType;
69 using sigrok::ConfigKey;
70 using sigrok::DatafeedCallbackFunction;
71 using sigrok::Device;
72 using sigrok::Error;
73 using sigrok::HardwareDevice;
74 using sigrok::Header;
75 using sigrok::Logic;
76 using sigrok::Meta;
77 using sigrok::Packet;
78 using sigrok::PacketPayload;
79 using sigrok::Session;
80 using sigrok::SessionDevice;
81
82 using Glib::VariantBase;
83 using Glib::Variant;
84
85 namespace pv {
86 Session::Session(DeviceManager &device_manager) :
87         device_manager_(device_manager),
88         session_(device_manager.context()->create_session()),
89         capture_state_(Stopped),
90         cur_samplerate_(0)
91 {
92         set_default_device();
93 }
94
95 Session::~Session()
96 {
97         // Stop and join to the thread
98         stop_capture();
99 }
100
101 DeviceManager& Session::device_manager()
102 {
103         return device_manager_;
104 }
105
106 const DeviceManager& Session::device_manager() const
107 {
108         return device_manager_;
109 }
110
111 const shared_ptr<sigrok::Session>& Session::session() const
112 {
113         return session_;
114 }
115
116 shared_ptr<Device> Session::device() const
117 {
118         return device_;
119 }
120
121 void Session::set_device(shared_ptr<Device> device)
122 {
123         // Ensure we are not capturing before setting the device
124         stop_capture();
125
126         if (device_) {
127                 session_->remove_datafeed_callbacks();
128
129                 // Did we have a hardware device selected previously?
130                 if (!dynamic_pointer_cast<HardwareDevice>(device_)) {
131                         device_->close();
132                         session_->remove_devices();
133                 }
134         }
135
136         decode_traces_.clear();
137
138         if (device) {
139                 // Are we setting a session device?
140                 const auto session_device =
141                         dynamic_pointer_cast<SessionDevice>(device);
142
143                 if (session_device)
144                         session_ = session_device->parent();
145                 else {
146                         session_ = device_manager_.context()->create_session();
147
148                         try {
149                                 device->open();
150                         } catch(const sigrok::Error &e) {
151                                 throw QString(e.what());
152                         }
153
154                         session_->add_device(device);
155                 }
156
157                 device_ = device;
158                 session_->add_datafeed_callback([=]
159                         (shared_ptr<Device> device, shared_ptr<Packet> packet) {
160                                 data_feed_in(device, packet);
161                         });
162                 device_manager_.update_display_name(device);
163                 update_signals(device);
164         } else
165                 device_ = nullptr;
166
167         device_selected();
168 }
169
170 void Session::set_session_file(const string &name)
171 {
172         const shared_ptr<sigrok::Session> session =
173                 device_manager_.context()->load_session(name);
174         set_device(session->devices()[0]);
175 }
176
177 void Session::set_default_device()
178 {
179         shared_ptr<HardwareDevice> default_device;
180         const list< shared_ptr<HardwareDevice> > &devices =
181                 device_manager_.devices();
182
183         if (!devices.empty()) {
184                 // Fall back to the first device in the list.
185                 default_device = devices.front();
186
187                 // Try and find the demo device and select that by default
188                 for (shared_ptr<HardwareDevice> dev : devices)
189                         if (dev->driver()->name().compare("demo") == 0) {
190                                 default_device = dev;
191                                 break;
192                         }
193
194                 set_device(default_device);
195         }
196 }
197
198 Session::capture_state Session::get_capture_state() const
199 {
200         lock_guard<mutex> lock(sampling_mutex_);
201         return capture_state_;
202 }
203
204 void Session::start_capture(function<void (const QString)> error_handler)
205 {
206         stop_capture();
207
208         // Check that a device instance has been selected.
209         if (!device_) {
210                 qDebug() << "No device selected";
211                 return;
212         }
213
214         // Check that at least one channel is enabled
215         auto channels = device_->channels();
216         bool enabled = std::any_of(channels.begin(), channels.end(),
217                 [](shared_ptr<Channel> channel) { return channel->enabled(); });
218
219         if (!enabled) {
220                 error_handler(tr("No channels enabled."));
221                 return;
222         }
223
224         // Begin the session
225         sampling_thread_ = std::thread(
226                 &Session::sample_thread_proc, this, device_,
227                         error_handler);
228 }
229
230 void Session::stop_capture()
231 {
232         if (get_capture_state() != Stopped)
233                 session_->stop();
234
235         // Check that sampling stopped
236         if (sampling_thread_.joinable())
237                 sampling_thread_.join();
238 }
239
240 set< shared_ptr<data::SignalData> > Session::get_data() const
241 {
242         shared_lock<shared_mutex> lock(signals_mutex_);
243         set< shared_ptr<data::SignalData> > data;
244         for (const shared_ptr<view::Signal> sig : signals_) {
245                 assert(sig);
246                 data.insert(sig->data());
247         }
248
249         return data;
250 }
251
252 boost::shared_mutex& Session::signals_mutex() const
253 {
254         return signals_mutex_;
255 }
256
257 const unordered_set< shared_ptr<view::Signal> >& Session::signals() const
258 {
259         return signals_;
260 }
261
262 #ifdef ENABLE_DECODE
263 bool Session::add_decoder(srd_decoder *const dec)
264 {
265         map<const srd_channel*, shared_ptr<view::LogicSignal> > channels;
266         shared_ptr<data::DecoderStack> decoder_stack;
267
268         try
269         {
270                 lock_guard<boost::shared_mutex> lock(signals_mutex_);
271
272                 // Create the decoder
273                 decoder_stack = shared_ptr<data::DecoderStack>(
274                         new data::DecoderStack(*this, dec));
275
276                 // Make a list of all the channels
277                 std::vector<const srd_channel*> all_channels;
278                 for(const GSList *i = dec->channels; i; i = i->next)
279                         all_channels.push_back((const srd_channel*)i->data);
280                 for(const GSList *i = dec->opt_channels; i; i = i->next)
281                         all_channels.push_back((const srd_channel*)i->data);
282
283                 // Auto select the initial channels
284                 for (const srd_channel *pdch : all_channels)
285                         for (shared_ptr<view::Signal> s : signals_)
286                         {
287                                 shared_ptr<view::LogicSignal> l =
288                                         dynamic_pointer_cast<view::LogicSignal>(s);
289                                 if (l && QString::fromUtf8(pdch->name).
290                                         toLower().contains(
291                                         l->name().toLower()))
292                                         channels[pdch] = l;
293                         }
294
295                 assert(decoder_stack);
296                 assert(!decoder_stack->stack().empty());
297                 assert(decoder_stack->stack().front());
298                 decoder_stack->stack().front()->set_channels(channels);
299
300                 // Create the decode signal
301                 shared_ptr<view::DecodeTrace> d(
302                         new view::DecodeTrace(*this, decoder_stack,
303                                 decode_traces_.size()));
304                 decode_traces_.push_back(d);
305         }
306         catch(std::runtime_error e)
307         {
308                 return false;
309         }
310
311         signals_changed();
312
313         // Do an initial decode
314         decoder_stack->begin_decode();
315
316         return true;
317 }
318
319 vector< shared_ptr<view::DecodeTrace> > Session::get_decode_signals() const
320 {
321         shared_lock<shared_mutex> lock(signals_mutex_);
322         return decode_traces_;
323 }
324
325 void Session::remove_decode_signal(view::DecodeTrace *signal)
326 {
327         for (auto i = decode_traces_.begin(); i != decode_traces_.end(); i++)
328                 if ((*i).get() == signal)
329                 {
330                         decode_traces_.erase(i);
331                         signals_changed();
332                         return;
333                 }
334 }
335 #endif
336
337 void Session::set_capture_state(capture_state state)
338 {
339         lock_guard<mutex> lock(sampling_mutex_);
340         const bool changed = capture_state_ != state;
341         capture_state_ = state;
342         if(changed)
343                 capture_state_changed(state);
344 }
345
346 void Session::update_signals(shared_ptr<Device> device)
347 {
348         assert(device);
349         assert(capture_state_ == Stopped);
350
351         // Detect what data types we will receive
352         auto channels = device->channels();
353         unsigned int logic_channel_count = std::count_if(
354                 channels.begin(), channels.end(),
355                 [] (shared_ptr<Channel> channel) {
356                         return channel->type() == ChannelType::LOGIC; });
357
358         // Create data containers for the logic data segments
359         {
360                 lock_guard<mutex> data_lock(data_mutex_);
361
362                 if (logic_channel_count == 0) {
363                         logic_data_.reset();
364                 } else if (!logic_data_ ||
365                         logic_data_->num_channels() != logic_channel_count) {
366                         logic_data_.reset(new data::Logic(
367                                 logic_channel_count));
368                         assert(logic_data_);
369                 }
370         }
371
372         // Make the Signals list
373         {
374                 unique_lock<shared_mutex> lock(signals_mutex_);
375
376                 unordered_set< shared_ptr<view::Signal> > prev_sigs(signals_);
377                 signals_.clear();
378
379                 for (auto channel : device->channels()) {
380                         shared_ptr<view::Signal> signal;
381
382                         // Find the channel in the old signals
383                         const auto iter = std::find_if(
384                                 prev_sigs.cbegin(), prev_sigs.cend(),
385                                 [&](const shared_ptr<view::Signal> &s) {
386                                         return s->channel() == channel;
387                                 });
388                         if (iter != prev_sigs.end()) {
389                                 // Copy the signal from the old set to the new
390                                 signal = *iter;
391                                 auto logic_signal = dynamic_pointer_cast<
392                                         view::LogicSignal>(signal);
393                                 if (logic_signal)
394                                         logic_signal->set_logic_data(
395                                                 logic_data_);
396                         } else {
397                                 // Create a new signal
398                                 switch(channel->type()->id()) {
399                                 case SR_CHANNEL_LOGIC:
400                                         signal = shared_ptr<view::Signal>(
401                                                 new view::LogicSignal(*this,
402                                                         device, channel,
403                                                         logic_data_));
404                                         break;
405
406                                 case SR_CHANNEL_ANALOG:
407                                 {
408                                         shared_ptr<data::Analog> data(
409                                                 new data::Analog());
410                                         signal = shared_ptr<view::Signal>(
411                                                 new view::AnalogSignal(
412                                                         *this, channel, data));
413                                         break;
414                                 }
415
416                                 default:
417                                         assert(0);
418                                         break;
419                                 }
420                         }
421
422                         assert(signal);
423                         signals_.insert(signal);
424                 }
425         }
426
427         signals_changed();
428 }
429
430 shared_ptr<view::Signal> Session::signal_from_channel(
431         shared_ptr<Channel> channel) const
432 {
433         lock_guard<boost::shared_mutex> lock(signals_mutex_);
434         for (shared_ptr<view::Signal> sig : signals_) {
435                 assert(sig);
436                 if (sig->channel() == channel)
437                         return sig;
438         }
439         return shared_ptr<view::Signal>();
440 }
441
442 void Session::read_sample_rate(shared_ptr<Device> device)
443 {
444         const auto keys = device_->config_keys(ConfigKey::DEVICE_OPTIONS);
445         const auto iter = keys.find(ConfigKey::SAMPLERATE);
446         cur_samplerate_ = (iter != keys.end() &&
447                 (*iter).second.find(sigrok::GET) != (*iter).second.end()) ?
448                 VariantBase::cast_dynamic<Variant<guint64>>(
449                         device->config_get(ConfigKey::SAMPLERATE)).get() : 0;
450 }
451
452 void Session::sample_thread_proc(shared_ptr<Device> device,
453         function<void (const QString)> error_handler)
454 {
455         assert(device);
456         assert(error_handler);
457
458         read_sample_rate(device);
459
460         try {
461                 session_->start();
462         } catch(Error e) {
463                 error_handler(e.what());
464                 return;
465         }
466
467         set_capture_state(session_->trigger() ?
468                 AwaitingTrigger : Running);
469
470         session_->run();
471         set_capture_state(Stopped);
472
473         // Confirm that SR_DF_END was received
474         if (cur_logic_segment_)
475         {
476                 qDebug("SR_DF_END was not received.");
477                 assert(0);
478         }
479 }
480
481 void Session::feed_in_header(shared_ptr<Device> device)
482 {
483         read_sample_rate(device);
484 }
485
486 void Session::feed_in_meta(shared_ptr<Device> device,
487         shared_ptr<Meta> meta)
488 {
489         (void)device;
490
491         for (auto entry : meta->config()) {
492                 switch (entry.first->id()) {
493                 case SR_CONF_SAMPLERATE:
494                         /// @todo handle samplerate changes
495                         break;
496                 default:
497                         // Unknown metadata is not an error.
498                         break;
499                 }
500         }
501
502         signals_changed();
503 }
504
505 void Session::feed_in_frame_begin()
506 {
507         if (cur_logic_segment_ || !cur_analog_segments_.empty())
508                 frame_began();
509 }
510
511 void Session::feed_in_logic(shared_ptr<Logic> logic)
512 {
513         lock_guard<mutex> lock(data_mutex_);
514
515         if (!logic_data_)
516         {
517                 qDebug() << "Unexpected logic packet";
518                 return;
519         }
520
521         if (!cur_logic_segment_)
522         {
523                 // This could be the first packet after a trigger
524                 set_capture_state(Running);
525
526                 // Get sample limit.
527                 const auto keys = device_->config_keys(
528                         ConfigKey::DEVICE_OPTIONS);
529                 const auto iter = keys.find(ConfigKey::LIMIT_SAMPLES);
530                 const uint64_t sample_limit = (iter != keys.end() &&
531                         (*iter).second.find(sigrok::GET) !=
532                         (*iter).second.end()) ?
533                         VariantBase::cast_dynamic<Variant<guint64>>(
534                         device_->config_get(ConfigKey::LIMIT_SAMPLES)).get() : 0;
535
536                 // Create a new data segment
537                 cur_logic_segment_ = shared_ptr<data::LogicSegment>(
538                         new data::LogicSegment(
539                                 logic, cur_samplerate_, sample_limit));
540                 logic_data_->push_segment(cur_logic_segment_);
541
542                 // @todo Putting this here means that only listeners querying
543                 // for logic will be notified. Currently the only user of
544                 // frame_began is DecoderStack, but in future we need to signal
545                 // this after both analog and logic sweeps have begun.
546                 frame_began();
547         }
548         else
549         {
550                 // Append to the existing data segment
551                 cur_logic_segment_->append_payload(logic);
552         }
553
554         data_received();
555 }
556
557 void Session::feed_in_analog(shared_ptr<Analog> analog)
558 {
559         lock_guard<mutex> lock(data_mutex_);
560
561         const vector<shared_ptr<Channel>> channels = analog->channels();
562         const unsigned int channel_count = channels.size();
563         const size_t sample_count = analog->num_samples() / channel_count;
564         const float *data = analog->data_pointer();
565         bool sweep_beginning = false;
566
567         for (auto channel : channels)
568         {
569                 shared_ptr<data::AnalogSegment> segment;
570
571                 // Try to get the segment of the channel
572                 const map< shared_ptr<Channel>, shared_ptr<data::AnalogSegment> >::
573                         iterator iter = cur_analog_segments_.find(channel);
574                 if (iter != cur_analog_segments_.end())
575                         segment = (*iter).second;
576                 else
577                 {
578                         // If no segment was found, this means we havn't
579                         // created one yet. i.e. this is the first packet
580                         // in the sweep containing this segment.
581                         sweep_beginning = true;
582
583                         // Get sample limit.
584                         uint64_t sample_limit;
585                         try {
586                                 sample_limit = VariantBase::cast_dynamic<Variant<guint64>>(
587                                         device_->config_get(ConfigKey::LIMIT_SAMPLES)).get();
588                         } catch (Error) {
589                                 sample_limit = 0;
590                         }
591
592                         // Create a segment, keep it in the maps of channels
593                         segment = shared_ptr<data::AnalogSegment>(
594                                 new data::AnalogSegment(
595                                         cur_samplerate_, sample_limit));
596                         cur_analog_segments_[channel] = segment;
597
598                         // Find the annalog data associated with the channel
599                         shared_ptr<view::AnalogSignal> sig =
600                                 dynamic_pointer_cast<view::AnalogSignal>(
601                                         signal_from_channel(channel));
602                         assert(sig);
603
604                         shared_ptr<data::Analog> data(sig->analog_data());
605                         assert(data);
606
607                         // Push the segment into the analog data.
608                         data->push_segment(segment);
609                 }
610
611                 assert(segment);
612
613                 // Append the samples in the segment
614                 segment->append_interleaved_samples(data++, sample_count,
615                         channel_count);
616         }
617
618         if (sweep_beginning) {
619                 // This could be the first packet after a trigger
620                 set_capture_state(Running);
621         }
622
623         data_received();
624 }
625
626 void Session::data_feed_in(shared_ptr<Device> device, shared_ptr<Packet> packet)
627 {
628         assert(device);
629         assert(packet);
630
631         switch (packet->type()->id()) {
632         case SR_DF_HEADER:
633                 feed_in_header(device);
634                 break;
635
636         case SR_DF_META:
637                 feed_in_meta(device, dynamic_pointer_cast<Meta>(packet->payload()));
638                 break;
639
640         case SR_DF_FRAME_BEGIN:
641                 feed_in_frame_begin();
642                 break;
643
644         case SR_DF_LOGIC:
645                 feed_in_logic(dynamic_pointer_cast<Logic>(packet->payload()));
646                 break;
647
648         case SR_DF_ANALOG:
649                 feed_in_analog(dynamic_pointer_cast<Analog>(packet->payload()));
650                 break;
651
652         case SR_DF_END:
653         {
654                 {
655                         lock_guard<mutex> lock(data_mutex_);
656                         cur_logic_segment_.reset();
657                         cur_analog_segments_.clear();
658                 }
659                 frame_ended();
660                 break;
661         }
662         default:
663                 break;
664         }
665 }
666
667 } // namespace pv