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