]> sigrok.org Git - libsigrok.git/blob - bindings/cxx/classes.cpp
Introduce A2L methods
[libsigrok.git] / bindings / cxx / classes.cpp
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2013-2014 Martin Ling <martin-sigrok@earth.li>
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 3 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, see <http://www.gnu.org/licenses/>.
18  */
19
20 /* Needed for isascii(), as used in the GNU libstdc++ headers */
21 #ifndef _XOPEN_SOURCE
22 #define _XOPEN_SOURCE 600
23 #endif
24
25 #include <config.h>
26 #include <libsigrokcxx/libsigrokcxx.hpp>
27
28 #include <sstream>
29 #include <cmath>
30
31 namespace sigrok
32 {
33
34 /** Helper function to translate C errors to C++ exceptions. */
35 static void check(int result)
36 {
37         if (result != SR_OK)
38                 throw Error(result);
39 }
40
41 /** Helper function to obtain valid strings from possibly null input. */
42 static inline const char *valid_string(const char *input)
43 {
44         return (input) ? input : "";
45 }
46
47 /** Helper function to convert between map<string, VariantBase> and GHashTable */
48 static GHashTable *map_to_hash_variant(const map<string, Glib::VariantBase> &input)
49 {
50         auto *const output = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
51                         reinterpret_cast<GDestroyNotify>(&g_variant_unref));
52         for (const auto &entry : input)
53                 g_hash_table_insert(output,
54                         g_strdup(entry.first.c_str()),
55                         entry.second.gobj_copy());
56         return output;
57 }
58
59 Error::Error(int result) : result(result)
60 {
61 }
62
63 const char *Error::what() const noexcept
64 {
65         return sr_strerror(result);
66 }
67
68 Error::~Error() noexcept
69 {
70 }
71
72 ResourceReader::~ResourceReader()
73 {
74 }
75
76 SR_PRIV int ResourceReader::open_callback(struct sr_resource *res,
77                 const char *name, void *cb_data) noexcept
78 {
79         try {
80                 auto *const reader = static_cast<ResourceReader*>(cb_data);
81                 reader->open(res, name);
82         } catch (const Error &err) {
83                 return err.result;
84         } catch (...) {
85                 return SR_ERR;
86         }
87         return SR_OK;
88 }
89
90 SR_PRIV int ResourceReader::close_callback(struct sr_resource *res,
91                 void *cb_data) noexcept
92 {
93         try {
94                 auto *const reader = static_cast<ResourceReader*>(cb_data);
95                 reader->close(res);
96         } catch (const Error &err) {
97                 return err.result;
98         } catch (...) {
99                 return SR_ERR;
100         }
101         return SR_OK;
102 }
103
104 SR_PRIV gssize ResourceReader::read_callback(const struct sr_resource *res,
105                 void *buf, size_t count, void *cb_data) noexcept
106 {
107         try {
108                 auto *const reader = static_cast<ResourceReader*>(cb_data);
109                 return reader->read(res, buf, count);
110         } catch (const Error &err) {
111                 return err.result;
112         } catch (...) {
113                 return SR_ERR;
114         }
115 }
116
117 shared_ptr<Context> Context::create()
118 {
119         return shared_ptr<Context>{new Context{}, default_delete<Context>{}};
120 }
121
122 Context::Context() :
123         _structure(nullptr),
124         _session(nullptr)
125 {
126         check(sr_init(&_structure));
127
128         if (struct sr_dev_driver **driver_list = sr_driver_list(_structure))
129                 for (int i = 0; driver_list[i]; i++) {
130                         unique_ptr<Driver> driver {new Driver{driver_list[i]}};
131                         _drivers.emplace(driver->name(), move(driver));
132                 }
133
134         if (const struct sr_input_module **input_list = sr_input_list())
135                 for (int i = 0; input_list[i]; i++) {
136                         unique_ptr<InputFormat> input {new InputFormat{input_list[i]}};
137                         _input_formats.emplace(input->name(), move(input));
138                 }
139
140         if (const struct sr_output_module **output_list = sr_output_list())
141                 for (int i = 0; output_list[i]; i++) {
142                         unique_ptr<OutputFormat> output {new OutputFormat{output_list[i]}};
143                         _output_formats.emplace(output->name(), move(output));
144                 }
145 }
146
147 string Context::package_version()
148 {
149         return sr_package_version_string_get();
150 }
151
152 string Context::lib_version()
153 {
154         return sr_lib_version_string_get();
155 }
156
157 map<string, shared_ptr<Driver>> Context::drivers()
158 {
159         map<string, shared_ptr<Driver>> result;
160         for (const auto &entry: _drivers) {
161                 const auto &name = entry.first;
162                 const auto &driver = entry.second;
163                 result.emplace(name, driver->share_owned_by(shared_from_this()));
164         }
165         return result;
166 }
167
168 map<string, shared_ptr<InputFormat>> Context::input_formats()
169 {
170         map<string, shared_ptr<InputFormat>> result;
171         for (const auto &entry: _input_formats) {
172                 const auto &name = entry.first;
173                 const auto &input_format = entry.second;
174                 result.emplace(name, input_format->share_owned_by(shared_from_this()));
175         }
176         return result;
177 }
178
179 map<string, shared_ptr<OutputFormat>> Context::output_formats()
180 {
181         map<string, shared_ptr<OutputFormat>> result;
182         for (const auto &entry: _output_formats) {
183                 const auto &name = entry.first;
184                 const auto &output_format = entry.second;
185                 result.emplace(name, output_format->share_owned_by(shared_from_this()));
186         }
187         return result;
188 }
189
190 Context::~Context()
191 {
192         check(sr_exit(_structure));
193 }
194
195 const LogLevel *Context::log_level() const
196 {
197         return LogLevel::get(sr_log_loglevel_get());
198 }
199
200 void Context::set_log_level(const LogLevel *level)
201 {
202         check(sr_log_loglevel_set(level->id()));
203 }
204
205 static int call_log_callback(void *cb_data, int loglevel,
206                 const char *format, va_list args) noexcept
207 {
208         const unique_ptr<char, decltype(&g_free)>
209                 message {g_strdup_vprintf(format, args), &g_free};
210
211         auto *const callback = static_cast<LogCallbackFunction *>(cb_data);
212
213         try {
214                 (*callback)(LogLevel::get(loglevel), message.get());
215         } catch (Error e) {
216                 return e.result;
217         }
218
219         return SR_OK;
220 }
221
222 void Context::set_log_callback(LogCallbackFunction callback)
223 {
224         _log_callback = move(callback);
225         check(sr_log_callback_set(call_log_callback, &_log_callback));
226 }
227
228 void Context::set_log_callback_default()
229 {
230         check(sr_log_callback_set_default());
231         _log_callback = nullptr;
232 }
233
234 void Context::set_resource_reader(ResourceReader *reader)
235 {
236         if (reader) {
237                 check(sr_resource_set_hooks(_structure,
238                                 &ResourceReader::open_callback,
239                                 &ResourceReader::close_callback,
240                                 &ResourceReader::read_callback, reader));
241         } else {
242                 check(sr_resource_set_hooks(_structure,
243                                 nullptr, nullptr, nullptr, nullptr));
244         }
245 }
246
247 shared_ptr<Session> Context::create_session()
248 {
249         return shared_ptr<Session>{new Session{shared_from_this()},
250                 default_delete<Session>{}};
251 }
252
253 shared_ptr<UserDevice> Context::create_user_device(
254                 string vendor, string model, string version)
255 {
256         return shared_ptr<UserDevice>{
257                 new UserDevice{move(vendor), move(model), move(version)},
258                 default_delete<UserDevice>{}};
259 }
260
261 shared_ptr<Packet> Context::create_header_packet(Glib::TimeVal start_time)
262 {
263         auto header = g_new(struct sr_datafeed_header, 1);
264         header->feed_version = 1;
265         header->starttime.tv_sec = start_time.tv_sec;
266         header->starttime.tv_usec = start_time.tv_usec;
267         auto packet = g_new(struct sr_datafeed_packet, 1);
268         packet->type = SR_DF_HEADER;
269         packet->payload = header;
270         return shared_ptr<Packet>{new Packet{nullptr, packet},
271                 default_delete<Packet>{}};
272 }
273
274 shared_ptr<Packet> Context::create_meta_packet(
275         map<const ConfigKey *, Glib::VariantBase> config)
276 {
277         auto meta = g_new0(struct sr_datafeed_meta, 1);
278         for (const auto &input : config) {
279                 const auto &key = input.first;
280                 const auto &value = input.second;
281                 auto *const output = g_new(struct sr_config, 1);
282                 output->key = key->id();
283                 output->data = value.gobj_copy();
284                 meta->config = g_slist_append(meta->config, output);
285         }
286         auto packet = g_new(struct sr_datafeed_packet, 1);
287         packet->type = SR_DF_META;
288         packet->payload = meta;
289         return shared_ptr<Packet>{new Packet{nullptr, packet},
290                 default_delete<Packet>{}};
291 }
292
293 shared_ptr<Packet> Context::create_logic_packet(
294         void *data_pointer, size_t data_length, unsigned int unit_size)
295 {
296         auto logic = g_new(struct sr_datafeed_logic, 1);
297         logic->length = data_length;
298         logic->unitsize = unit_size;
299         logic->data = data_pointer;
300         auto packet = g_new(struct sr_datafeed_packet, 1);
301         packet->type = SR_DF_LOGIC;
302         packet->payload = logic;
303         return shared_ptr<Packet>{new Packet{nullptr, packet}, default_delete<Packet>{}};
304 }
305
306 shared_ptr<Packet> Context::create_analog_packet(
307         vector<shared_ptr<Channel> > channels,
308         const float *data_pointer, unsigned int num_samples, const Quantity *mq,
309         const Unit *unit, vector<const QuantityFlag *> mqflags)
310 {
311         auto analog = g_new0(struct sr_datafeed_analog, 1);
312         auto meaning = g_new0(struct sr_analog_meaning, 1);
313         auto encoding = g_new0(struct sr_analog_encoding, 1);
314         auto spec = g_new0(struct sr_analog_spec, 1);
315
316         analog->meaning = meaning;
317
318         for (const auto &channel : channels)
319                 meaning->channels = g_slist_append(meaning->channels, channel->_structure);
320         meaning->mq = static_cast<sr_mq>(mq->id());
321         meaning->unit = static_cast<sr_unit>(unit->id());
322         meaning->mqflags = static_cast<sr_mqflag>(QuantityFlag::mask_from_flags(move(mqflags)));
323
324         analog->encoding = encoding;
325
326         encoding->unitsize = sizeof(float);
327         encoding->is_signed = TRUE;
328         encoding->is_float = TRUE;
329 #ifdef WORDS_BIGENDIAN
330         encoding->is_bigendian = TRUE;
331 #else
332         encoding->is_bigendian = FALSE;
333 #endif
334         encoding->digits = 0;
335         encoding->is_digits_decimal = FALSE;
336         encoding->scale.p = 1;
337         encoding->scale.q = 1;
338         encoding->offset.p = 0;
339         encoding->offset.q = 1;
340
341         analog->spec = spec;
342
343         spec->spec_digits = 0;
344
345         analog->num_samples = num_samples;
346         analog->data = (float*)data_pointer;
347         auto packet = g_new(struct sr_datafeed_packet, 1);
348         packet->type = SR_DF_ANALOG;
349         packet->payload = analog;
350         return shared_ptr<Packet>{new Packet{nullptr, packet}, default_delete<Packet>{}};
351 }
352
353 shared_ptr<Session> Context::load_session(string filename)
354 {
355         return shared_ptr<Session>{
356                 new Session{shared_from_this(), move(filename)},
357                 default_delete<Session>{}};
358 }
359
360 shared_ptr<Trigger> Context::create_trigger(string name)
361 {
362         return shared_ptr<Trigger>{
363                 new Trigger{shared_from_this(), move(name)},
364                 default_delete<Trigger>{}};
365 }
366
367 shared_ptr<Input> Context::open_file(string filename)
368 {
369         const struct sr_input *input;
370
371         check(sr_input_scan_file(filename.c_str(), &input));
372         return shared_ptr<Input>{
373                 new Input{shared_from_this(), input},
374                 default_delete<Input>{}};
375 }
376
377 shared_ptr<Input> Context::open_stream(string header)
378 {
379         const struct sr_input *input;
380
381         auto gstr = g_string_new(header.c_str());
382         auto ret = sr_input_scan_buffer(gstr, &input);
383         g_string_free(gstr, true);
384         check(ret);
385         return shared_ptr<Input>{
386                 new Input{shared_from_this(), input},
387                 default_delete<Input>{}};
388 }
389
390 map<string, string> Context::serials(shared_ptr<Driver> driver) const
391 {
392         GSList *serial_list = sr_serial_list(driver ? driver->_structure : nullptr);
393         map<string, string> serials;
394
395         for (GSList *serial = serial_list; serial; serial = serial->next) {
396                 auto *const port = static_cast<sr_serial_port *>(serial->data);
397                 serials[string(port->name)] = string(port->description);
398         }
399
400         g_slist_free_full(serial_list,
401                 reinterpret_cast<GDestroyNotify>(&sr_serial_free));
402         return serials;
403 }
404
405 Driver::Driver(struct sr_dev_driver *structure) :
406         Configurable(structure, nullptr, nullptr),
407         _structure(structure),
408         _initialized(false)
409 {
410 }
411
412 Driver::~Driver()
413 {
414 }
415
416 string Driver::name() const
417 {
418         return valid_string(_structure->name);
419 }
420
421 string Driver::long_name() const
422 {
423         return valid_string(_structure->longname);
424 }
425
426 set<const ConfigKey *> Driver::scan_options() const
427 {
428         GArray *opts = sr_driver_scan_options_list(_structure);
429         set<const ConfigKey *> result;
430         if (opts) {
431                 for (guint i = 0; i < opts->len; i++)
432                         result.insert(ConfigKey::get(g_array_index(opts, uint32_t, i)));
433                 g_array_free(opts, TRUE);
434         }
435         return result;
436 }
437
438 vector<shared_ptr<HardwareDevice>> Driver::scan(
439         map<const ConfigKey *, Glib::VariantBase> options)
440 {
441         /* Initialise the driver if not yet done. */
442         if (!_initialized) {
443                 check(sr_driver_init(_parent->_structure, _structure));
444                 _initialized = true;
445         }
446
447         /* Translate scan options to GSList of struct sr_config pointers. */
448         GSList *option_list = nullptr;
449         for (const auto &entry : options) {
450                 const auto &key = entry.first;
451                 const auto &value = entry.second;
452                 auto *const config = g_new(struct sr_config, 1);
453                 config->key = key->id();
454                 config->data = const_cast<GVariant*>(value.gobj());
455                 option_list = g_slist_append(option_list, config);
456         }
457
458         /* Run scan. */
459         GSList *device_list = sr_driver_scan(_structure, option_list);
460
461         /* Free option list. */
462         g_slist_free_full(option_list, g_free);
463
464
465         /* Create device objects. */
466         vector<shared_ptr<HardwareDevice>> result;
467         for (GSList *device = device_list; device; device = device->next) {
468                 auto *const sdi = static_cast<struct sr_dev_inst *>(device->data);
469                 shared_ptr<HardwareDevice> hwdev {
470                         new HardwareDevice{shared_from_this(), sdi},
471                         default_delete<HardwareDevice>{}};
472                 result.push_back(move(hwdev));
473         }
474
475         /* Free GSList returned from scan. */
476         g_slist_free(device_list);
477
478         return result;
479 }
480
481 Configurable::Configurable(
482                 struct sr_dev_driver *driver,
483                 struct sr_dev_inst *sdi,
484                 struct sr_channel_group *cg) :
485         config_driver(driver),
486         config_sdi(sdi),
487         config_channel_group(cg)
488 {
489 }
490
491 Configurable::~Configurable()
492 {
493 }
494
495 set<const ConfigKey *> Configurable::config_keys() const
496 {
497         GArray *opts;
498         set<const ConfigKey *> result;
499
500         opts = sr_dev_options(config_driver, config_sdi, config_channel_group);
501
502         if (opts) {
503                 for (guint i = 0; i < opts->len; i++)
504                         result.insert(ConfigKey::get(g_array_index(opts, uint32_t, i)));
505                 g_array_free(opts, TRUE);
506         }
507
508         return result;
509 }
510
511 Glib::VariantBase Configurable::config_get(const ConfigKey *key) const
512 {
513         GVariant *data;
514         check(sr_config_get(
515                 config_driver, config_sdi, config_channel_group,
516                 key->id(), &data));
517         return Glib::VariantBase(data);
518 }
519
520 void Configurable::config_set(const ConfigKey *key, const Glib::VariantBase &value)
521 {
522         check(sr_config_set(
523                 config_sdi, config_channel_group,
524                 key->id(), const_cast<GVariant*>(value.gobj())));
525 }
526
527 set<const Capability *> Configurable::config_capabilities(const ConfigKey *key) const
528 {
529         int caps = sr_dev_config_capabilities_list(config_sdi,
530                                 config_channel_group, key->id());
531
532         set<const Capability *> result;
533
534         for (auto cap: Capability::values())
535                 if (caps & cap->id())
536                         result.insert(cap);
537
538         return result;
539 }
540
541 bool Configurable::config_check(const ConfigKey *key,
542         const Capability *capability) const
543 {
544         int caps = sr_dev_config_capabilities_list(config_sdi,
545                                 config_channel_group, key->id());
546
547         return (caps & capability->id());
548 }
549
550 Glib::VariantContainerBase Configurable::config_list(const ConfigKey *key) const
551 {
552         GVariant *data;
553         check(sr_config_list(
554                 config_driver, config_sdi, config_channel_group,
555                 key->id(), &data));
556         return Glib::VariantContainerBase(data);
557 }
558
559 Device::Device(struct sr_dev_inst *structure) :
560         Configurable(sr_dev_inst_driver_get(structure), structure, nullptr),
561         _structure(structure)
562 {
563         for (GSList *entry = sr_dev_inst_channels_get(structure); entry; entry = entry->next) {
564                 auto *const ch = static_cast<struct sr_channel *>(entry->data);
565                 unique_ptr<Channel> channel {new Channel{ch}};
566                 _channels.emplace(ch, move(channel));
567         }
568
569         for (GSList *entry = sr_dev_inst_channel_groups_get(structure); entry; entry = entry->next) {
570                 auto *const cg = static_cast<struct sr_channel_group *>(entry->data);
571                 unique_ptr<ChannelGroup> group {new ChannelGroup{this, cg}};
572                 _channel_groups.emplace(group->name(), move(group));
573         }
574 }
575
576 Device::~Device()
577 {
578 }
579
580 string Device::vendor() const
581 {
582         return valid_string(sr_dev_inst_vendor_get(_structure));
583 }
584
585 string Device::model() const
586 {
587         return valid_string(sr_dev_inst_model_get(_structure));
588 }
589
590 string Device::version() const
591 {
592         return valid_string(sr_dev_inst_version_get(_structure));
593 }
594
595 string Device::serial_number() const
596 {
597         return valid_string(sr_dev_inst_sernum_get(_structure));
598 }
599
600 string Device::connection_id() const
601 {
602         return valid_string(sr_dev_inst_connid_get(_structure));
603 }
604
605 vector<shared_ptr<Channel>> Device::channels()
606 {
607         vector<shared_ptr<Channel>> result;
608         for (auto channel = sr_dev_inst_channels_get(_structure); channel; channel = channel->next) {
609                 auto *const ch = static_cast<struct sr_channel *>(channel->data);
610                 result.push_back(_channels[ch]->share_owned_by(get_shared_from_this()));
611         }
612         return result;
613 }
614
615 shared_ptr<Channel> Device::get_channel(struct sr_channel *ptr)
616 {
617         return _channels[ptr]->share_owned_by(get_shared_from_this());
618 }
619
620 map<string, shared_ptr<ChannelGroup>>
621 Device::channel_groups()
622 {
623         map<string, shared_ptr<ChannelGroup>> result;
624         for (const auto &entry: _channel_groups) {
625                 const auto &name = entry.first;
626                 const auto &channel_group = entry.second;
627                 result.emplace(name, channel_group->share_owned_by(get_shared_from_this()));
628         }
629         return result;
630 }
631
632 void Device::open()
633 {
634         check(sr_dev_open(_structure));
635 }
636
637 void Device::close()
638 {
639         check(sr_dev_close(_structure));
640 }
641
642 HardwareDevice::HardwareDevice(shared_ptr<Driver> driver,
643                 struct sr_dev_inst *structure) :
644         Device(structure),
645         _driver(move(driver))
646 {
647 }
648
649 HardwareDevice::~HardwareDevice()
650 {
651 }
652
653 shared_ptr<Device> HardwareDevice::get_shared_from_this()
654 {
655         return static_pointer_cast<Device>(shared_from_this());
656 }
657
658 shared_ptr<Driver> HardwareDevice::driver()
659 {
660         return _driver;
661 }
662
663 UserDevice::UserDevice(string vendor, string model, string version) :
664         Device(sr_dev_inst_user_new(
665                 vendor.c_str(), model.c_str(), version.c_str()))
666 {
667 }
668
669 UserDevice::~UserDevice()
670 {
671 }
672
673 shared_ptr<Device> UserDevice::get_shared_from_this()
674 {
675         return static_pointer_cast<Device>(shared_from_this());
676 }
677
678 shared_ptr<Channel> UserDevice::add_channel(unsigned int index,
679         const ChannelType *type, string name)
680 {
681         check(sr_dev_inst_channel_add(Device::_structure,
682                 index, type->id(), name.c_str()));
683         GSList *const last = g_slist_last(sr_dev_inst_channels_get(Device::_structure));
684         auto *const ch = static_cast<struct sr_channel *>(last->data);
685         unique_ptr<Channel> channel {new Channel{ch}};
686         _channels.emplace(ch, move(channel));
687         return get_channel(ch);
688 }
689
690 Channel::Channel(struct sr_channel *structure) :
691         _structure(structure),
692         _type(ChannelType::get(_structure->type))
693 {
694 }
695
696 Channel::~Channel()
697 {
698 }
699
700 string Channel::name() const
701 {
702         return valid_string(_structure->name);
703 }
704
705 void Channel::set_name(string name)
706 {
707         check(sr_dev_channel_name_set(_structure, name.c_str()));
708 }
709
710 const ChannelType *Channel::type() const
711 {
712         return ChannelType::get(_structure->type);
713 }
714
715 bool Channel::enabled() const
716 {
717         return _structure->enabled;
718 }
719
720 void Channel::set_enabled(bool value)
721 {
722         check(sr_dev_channel_enable(_structure, value));
723 }
724
725 unsigned int Channel::index() const
726 {
727         return _structure->index;
728 }
729
730 ChannelGroup::ChannelGroup(const Device *device,
731                 struct sr_channel_group *structure) :
732         Configurable(sr_dev_inst_driver_get(device->_structure), device->_structure, structure)
733 {
734         for (GSList *entry = config_channel_group->channels; entry; entry = entry->next) {
735                 auto *const ch = static_cast<struct sr_channel *>(entry->data);
736                 /* Note: This relies on Device::_channels to keep the Channel
737                  * objects around over the lifetime of the ChannelGroup. */
738                 _channels.push_back(device->_channels.find(ch)->second.get());
739         }
740 }
741
742 ChannelGroup::~ChannelGroup()
743 {
744 }
745
746 string ChannelGroup::name() const
747 {
748         return valid_string(config_channel_group->name);
749 }
750
751 vector<shared_ptr<Channel>> ChannelGroup::channels()
752 {
753         vector<shared_ptr<Channel>> result;
754         for (const auto &channel : _channels)
755                 result.push_back(channel->share_owned_by(_parent));
756         return result;
757 }
758
759 Trigger::Trigger(shared_ptr<Context> context, string name) :
760         _structure(sr_trigger_new(name.c_str())),
761         _context(move(context))
762 {
763         for (auto *stage = _structure->stages; stage; stage = stage->next) {
764                 unique_ptr<TriggerStage> ts {new TriggerStage{
765                                 static_cast<struct sr_trigger_stage *>(stage->data)}};
766                 _stages.push_back(move(ts));
767         }
768 }
769
770 Trigger::~Trigger()
771 {
772         sr_trigger_free(_structure);
773 }
774
775 string Trigger::name() const
776 {
777         return _structure->name;
778 }
779
780 vector<shared_ptr<TriggerStage>> Trigger::stages()
781 {
782         vector<shared_ptr<TriggerStage>> result;
783         for (const auto &stage : _stages)
784                 result.push_back(stage->share_owned_by(shared_from_this()));
785         return result;
786 }
787
788 shared_ptr<TriggerStage> Trigger::add_stage()
789 {
790         unique_ptr<TriggerStage> stage {new TriggerStage{sr_trigger_stage_add(_structure)}};
791         _stages.push_back(move(stage));
792         return _stages.back()->share_owned_by(shared_from_this());
793 }
794
795 TriggerStage::TriggerStage(struct sr_trigger_stage *structure) :
796         _structure(structure)
797 {
798 }
799
800 TriggerStage::~TriggerStage()
801 {
802 }
803
804 int TriggerStage::number() const
805 {
806         return _structure->stage;
807 }
808
809 vector<shared_ptr<TriggerMatch>> TriggerStage::matches()
810 {
811         vector<shared_ptr<TriggerMatch>> result;
812         for (const auto &match : _matches)
813                 result.push_back(match->share_owned_by(shared_from_this()));
814         return result;
815 }
816
817 void TriggerStage::add_match(shared_ptr<Channel> channel,
818         const TriggerMatchType *type, float value)
819 {
820         check(sr_trigger_match_add(_structure,
821                 channel->_structure, type->id(), value));
822         GSList *const last = g_slist_last(_structure->matches);
823         unique_ptr<TriggerMatch> match {new TriggerMatch{
824                         static_cast<struct sr_trigger_match *>(last->data),
825                         move(channel)}};
826         _matches.push_back(move(match));
827 }
828
829 void TriggerStage::add_match(shared_ptr<Channel> channel,
830         const TriggerMatchType *type)
831 {
832         add_match(move(channel), type, NAN);
833 }
834
835 TriggerMatch::TriggerMatch(struct sr_trigger_match *structure,
836                 shared_ptr<Channel> channel) :
837         _structure(structure),
838         _channel(move(channel))
839 {
840 }
841
842 TriggerMatch::~TriggerMatch()
843 {
844 }
845
846 shared_ptr<Channel> TriggerMatch::channel()
847 {
848         return _channel;
849 }
850
851 const TriggerMatchType *TriggerMatch::type() const
852 {
853         return TriggerMatchType::get(_structure->match);
854 }
855
856 float TriggerMatch::value() const
857 {
858         return _structure->value;
859 }
860
861 DatafeedCallbackData::DatafeedCallbackData(Session *session,
862                 DatafeedCallbackFunction callback) :
863         _callback(move(callback)),
864         _session(session)
865 {
866 }
867
868 void DatafeedCallbackData::run(const struct sr_dev_inst *sdi,
869         const struct sr_datafeed_packet *pkt)
870 {
871         auto device = _session->get_device(sdi);
872         shared_ptr<Packet> packet {new Packet{device, pkt}, default_delete<Packet>{}};
873         _callback(move(device), move(packet));
874 }
875
876 SessionDevice::SessionDevice(struct sr_dev_inst *structure) :
877         Device(structure)
878 {
879 }
880
881 SessionDevice::~SessionDevice()
882 {
883 }
884
885 shared_ptr<Device> SessionDevice::get_shared_from_this()
886 {
887         return static_pointer_cast<Device>(shared_from_this());
888 }
889
890 Session::Session(shared_ptr<Context> context) :
891         _structure(nullptr),
892         _context(move(context))
893 {
894         check(sr_session_new(_context->_structure, &_structure));
895         _context->_session = this;
896 }
897
898 Session::Session(shared_ptr<Context> context, string filename) :
899         _structure(nullptr),
900         _context(move(context)),
901         _filename(move(filename))
902 {
903         check(sr_session_load(_context->_structure, _filename.c_str(), &_structure));
904         GSList *dev_list;
905         check(sr_session_dev_list(_structure, &dev_list));
906         for (GSList *dev = dev_list; dev; dev = dev->next) {
907                 auto *const sdi = static_cast<struct sr_dev_inst *>(dev->data);
908                 unique_ptr<SessionDevice> device {new SessionDevice{sdi}};
909                 _owned_devices.emplace(sdi, move(device));
910         }
911         _context->_session = this;
912 }
913
914 Session::~Session()
915 {
916         check(sr_session_destroy(_structure));
917 }
918
919 shared_ptr<Device> Session::get_device(const struct sr_dev_inst *sdi)
920 {
921         if (_owned_devices.count(sdi))
922                 return static_pointer_cast<Device>(
923                         _owned_devices[sdi]->share_owned_by(shared_from_this()));
924         else if (_other_devices.count(sdi))
925                 return _other_devices[sdi];
926         else
927                 throw Error(SR_ERR_BUG);
928 }
929
930 void Session::add_device(shared_ptr<Device> device)
931 {
932         const auto dev_struct = device->_structure;
933         check(sr_session_dev_add(_structure, dev_struct));
934         _other_devices[dev_struct] = move(device);
935 }
936
937 vector<shared_ptr<Device>> Session::devices()
938 {
939         GSList *dev_list;
940         check(sr_session_dev_list(_structure, &dev_list));
941         vector<shared_ptr<Device>> result;
942         for (GSList *dev = dev_list; dev; dev = dev->next) {
943                 auto *const sdi = static_cast<struct sr_dev_inst *>(dev->data);
944                 result.push_back(get_device(sdi));
945         }
946         return result;
947 }
948
949 void Session::remove_devices()
950 {
951         _other_devices.clear();
952         check(sr_session_dev_remove_all(_structure));
953 }
954
955 void Session::start()
956 {
957         check(sr_session_start(_structure));
958 }
959
960 void Session::run()
961 {
962         check(sr_session_run(_structure));
963 }
964
965 void Session::stop()
966 {
967         check(sr_session_stop(_structure));
968 }
969
970 bool Session::is_running() const
971 {
972         const int ret = sr_session_is_running(_structure);
973         if (ret < 0)
974                 throw Error{ret};
975         return (ret != 0);
976 }
977
978 static void session_stopped_callback(void *data) noexcept
979 {
980         auto *const callback = static_cast<SessionStoppedCallback*>(data);
981         (*callback)();
982 }
983
984 void Session::set_stopped_callback(SessionStoppedCallback callback)
985 {
986         _stopped_callback = move(callback);
987         if (_stopped_callback)
988                 check(sr_session_stopped_callback_set(_structure,
989                                 &session_stopped_callback, &_stopped_callback));
990         else
991                 check(sr_session_stopped_callback_set(_structure,
992                                 nullptr, nullptr));
993 }
994
995 static void datafeed_callback(const struct sr_dev_inst *sdi,
996         const struct sr_datafeed_packet *pkt, void *cb_data) noexcept
997 {
998         auto callback = static_cast<DatafeedCallbackData *>(cb_data);
999         callback->run(sdi, pkt);
1000 }
1001
1002 void Session::add_datafeed_callback(DatafeedCallbackFunction callback)
1003 {
1004         unique_ptr<DatafeedCallbackData> cb_data
1005                 {new DatafeedCallbackData{this, move(callback)}};
1006         check(sr_session_datafeed_callback_add(_structure,
1007                         &datafeed_callback, cb_data.get()));
1008         _datafeed_callbacks.push_back(move(cb_data));
1009 }
1010
1011 void Session::remove_datafeed_callbacks()
1012 {
1013         check(sr_session_datafeed_callback_remove_all(_structure));
1014         _datafeed_callbacks.clear();
1015 }
1016
1017 shared_ptr<Trigger> Session::trigger()
1018 {
1019         return _trigger;
1020 }
1021
1022 void Session::set_trigger(shared_ptr<Trigger> trigger)
1023 {
1024         if (!trigger)
1025                 // Set NULL trigger, i.e. remove any trigger from the session.
1026                 check(sr_session_trigger_set(_structure, nullptr));
1027         else
1028                 check(sr_session_trigger_set(_structure, trigger->_structure));
1029         _trigger = move(trigger);
1030 }
1031
1032 string Session::filename() const
1033 {
1034         return _filename;
1035 }
1036
1037 shared_ptr<Context> Session::context()
1038 {
1039         return _context;
1040 }
1041
1042 Packet::Packet(shared_ptr<Device> device,
1043         const struct sr_datafeed_packet *structure) :
1044         _structure(structure),
1045         _device(move(device))
1046 {
1047         switch (structure->type)
1048         {
1049                 case SR_DF_HEADER:
1050                         _payload.reset(new Header{
1051                                 static_cast<const struct sr_datafeed_header *>(
1052                                         structure->payload)});
1053                         break;
1054                 case SR_DF_META:
1055                         _payload.reset(new Meta{
1056                                 static_cast<const struct sr_datafeed_meta *>(
1057                                         structure->payload)});
1058                         break;
1059                 case SR_DF_LOGIC:
1060                         _payload.reset(new Logic{
1061                                 static_cast<const struct sr_datafeed_logic *>(
1062                                         structure->payload)});
1063                         break;
1064                 case SR_DF_ANALOG:
1065                         _payload.reset(new Analog{
1066                                 static_cast<const struct sr_datafeed_analog *>(
1067                                         structure->payload)});
1068                         break;
1069         }
1070 }
1071
1072 Packet::~Packet()
1073 {
1074 }
1075
1076 const PacketType *Packet::type() const
1077 {
1078         return PacketType::get(_structure->type);
1079 }
1080
1081 shared_ptr<PacketPayload> Packet::payload()
1082 {
1083         if (_payload)
1084                 return _payload->share_owned_by(shared_from_this());
1085         else
1086                 throw Error(SR_ERR_NA);
1087 }
1088
1089 PacketPayload::PacketPayload()
1090 {
1091 }
1092
1093 PacketPayload::~PacketPayload()
1094 {
1095 }
1096
1097 Header::Header(const struct sr_datafeed_header *structure) :
1098         PacketPayload(),
1099         _structure(structure)
1100 {
1101 }
1102
1103 Header::~Header()
1104 {
1105 }
1106
1107 shared_ptr<PacketPayload> Header::share_owned_by(shared_ptr<Packet> _parent)
1108 {
1109         return static_pointer_cast<PacketPayload>(
1110                 ParentOwned::share_owned_by(_parent));
1111 }
1112
1113 int Header::feed_version() const
1114 {
1115         return _structure->feed_version;
1116 }
1117
1118 Glib::TimeVal Header::start_time() const
1119 {
1120         return Glib::TimeVal(
1121                 _structure->starttime.tv_sec,
1122                 _structure->starttime.tv_usec);
1123 }
1124
1125 Meta::Meta(const struct sr_datafeed_meta *structure) :
1126         PacketPayload(),
1127         _structure(structure)
1128 {
1129 }
1130
1131 Meta::~Meta()
1132 {
1133 }
1134
1135 shared_ptr<PacketPayload> Meta::share_owned_by(shared_ptr<Packet> _parent)
1136 {
1137         return static_pointer_cast<PacketPayload>(
1138                 ParentOwned::share_owned_by(_parent));
1139 }
1140
1141 map<const ConfigKey *, Glib::VariantBase> Meta::config() const
1142 {
1143         map<const ConfigKey *, Glib::VariantBase> result;
1144         for (auto l = _structure->config; l; l = l->next) {
1145                 auto *const config = static_cast<struct sr_config *>(l->data);
1146                 result[ConfigKey::get(config->key)] = Glib::VariantBase(config->data, true);
1147         }
1148         return result;
1149 }
1150
1151 Logic::Logic(const struct sr_datafeed_logic *structure) :
1152         PacketPayload(),
1153         _structure(structure)
1154 {
1155 }
1156
1157 Logic::~Logic()
1158 {
1159 }
1160
1161 shared_ptr<PacketPayload> Logic::share_owned_by(shared_ptr<Packet> _parent)
1162 {
1163         return static_pointer_cast<PacketPayload>(
1164                 ParentOwned::share_owned_by(_parent));
1165 }
1166
1167 void *Logic::data_pointer()
1168 {
1169         return _structure->data;
1170 }
1171
1172 size_t Logic::data_length() const
1173 {
1174         return _structure->length;
1175 }
1176
1177 unsigned int Logic::unit_size() const
1178 {
1179         return _structure->unitsize;
1180 }
1181
1182 Analog::Analog(const struct sr_datafeed_analog *structure) :
1183         PacketPayload(),
1184         _structure(structure)
1185 {
1186 }
1187
1188 Analog::~Analog()
1189 {
1190 }
1191
1192 shared_ptr<PacketPayload> Analog::share_owned_by(shared_ptr<Packet> _parent)
1193 {
1194         return static_pointer_cast<PacketPayload>(
1195                 ParentOwned::share_owned_by(_parent));
1196 }
1197
1198 void *Analog::data_pointer()
1199 {
1200         return _structure->data;
1201 }
1202
1203 void Analog::get_data_as_float(float *dest)
1204 {
1205         check(sr_analog_to_float(_structure, dest));
1206 }
1207
1208 unsigned int Analog::num_samples() const
1209 {
1210         return _structure->num_samples;
1211 }
1212
1213 vector<shared_ptr<Channel>> Analog::channels()
1214 {
1215         vector<shared_ptr<Channel>> result;
1216         for (auto l = _structure->meaning->channels; l; l = l->next) {
1217                 auto *const ch = static_cast<struct sr_channel *>(l->data);
1218                 result.push_back(_parent->_device->get_channel(ch));
1219         }
1220         return result;
1221 }
1222
1223 unsigned int Analog::unitsize() const
1224 {
1225         return _structure->encoding->unitsize;
1226 }
1227
1228 bool Analog::is_signed() const
1229 {
1230         return _structure->encoding->is_signed;
1231 }
1232
1233 bool Analog::is_float() const
1234 {
1235         return _structure->encoding->is_float;
1236 }
1237
1238 bool Analog::is_bigendian() const
1239 {
1240         return _structure->encoding->is_bigendian;
1241 }
1242
1243 int Analog::digits() const
1244 {
1245         return _structure->encoding->digits;
1246 }
1247
1248 bool Analog::is_digits_decimal() const
1249 {
1250         return _structure->encoding->is_digits_decimal;
1251 }
1252
1253 shared_ptr<Rational> Analog::scale()
1254 {
1255         unique_ptr<Rational> scale;
1256         scale.reset(new Rational(&(_structure->encoding->scale)));
1257
1258         if (scale)
1259                 return scale->share_owned_by(shared_from_this());
1260         else
1261                 throw Error(SR_ERR_NA);
1262 }
1263
1264 shared_ptr<Rational> Analog::offset()
1265 {
1266         unique_ptr<Rational> offset;
1267         offset.reset(new Rational(&(_structure->encoding->offset)));
1268
1269         if (offset)
1270                 return offset->share_owned_by(shared_from_this());
1271         else
1272                 throw Error(SR_ERR_NA);
1273 }
1274
1275 const Quantity *Analog::mq() const
1276 {
1277         return Quantity::get(_structure->meaning->mq);
1278 }
1279
1280 const Unit *Analog::unit() const
1281 {
1282         return Unit::get(_structure->meaning->unit);
1283 }
1284
1285 vector<const QuantityFlag *> Analog::mq_flags() const
1286 {
1287         return QuantityFlag::flags_from_mask(_structure->meaning->mqflags);
1288 }
1289
1290 shared_ptr<Logic> Analog::get_logic_via_threshold(float threshold,
1291         uint8_t *data_ptr) const
1292 {
1293         auto datafeed = g_new(struct sr_datafeed_logic, 1);
1294         datafeed->length = num_samples();
1295         datafeed->unitsize = 1;
1296
1297         if (data_ptr)
1298                 datafeed->data = data_ptr;
1299         else
1300                 datafeed->data = g_malloc(datafeed->length);
1301
1302         shared_ptr<Logic> logic =
1303                 shared_ptr<Logic>{new Logic{datafeed}, default_delete<Logic>{}};
1304
1305         check(sr_a2l_threshold(_structure, threshold,
1306                 (uint8_t*)datafeed->data, datafeed->length));
1307
1308         return logic;
1309 }
1310
1311 shared_ptr<Logic> Analog::get_logic_via_schmitt_trigger(float lo_thr,
1312         float hi_thr, uint8_t *state, uint8_t *data_ptr) const
1313 {
1314         auto datafeed = g_new(struct sr_datafeed_logic, 1);
1315         datafeed->length = num_samples();
1316         datafeed->unitsize = 1;
1317
1318         if (data_ptr)
1319                 datafeed->data = data_ptr;
1320         else
1321                 datafeed->data = g_malloc(datafeed->length);
1322
1323         shared_ptr<Logic> logic =
1324                 shared_ptr<Logic>{new Logic{datafeed}, default_delete<Logic>{}};
1325
1326         check(sr_a2l_schmitt_trigger(_structure, lo_thr, hi_thr, state,
1327                 (uint8_t*)datafeed->data, datafeed->length));
1328
1329         return logic;
1330 }
1331
1332 Rational::Rational(const struct sr_rational *structure) :
1333         _structure(structure)
1334 {
1335 }
1336
1337 Rational::~Rational()
1338 {
1339 }
1340
1341 shared_ptr<Rational> Rational::share_owned_by(shared_ptr<Analog> _parent)
1342 {
1343         return static_pointer_cast<Rational>(
1344                 ParentOwned::share_owned_by(_parent));
1345 }
1346
1347 int64_t Rational::numerator() const
1348 {
1349         return _structure->p;
1350 }
1351
1352 uint64_t Rational::denominator() const
1353 {
1354         return _structure->q;
1355 }
1356
1357 float Rational::value() const
1358 {
1359         return (float)(_structure->p) / (float)(_structure->q);
1360 }
1361
1362 InputFormat::InputFormat(const struct sr_input_module *structure) :
1363         _structure(structure)
1364 {
1365 }
1366
1367 InputFormat::~InputFormat()
1368 {
1369 }
1370
1371 string InputFormat::name() const
1372 {
1373         return valid_string(sr_input_id_get(_structure));
1374 }
1375
1376 string InputFormat::description() const
1377 {
1378         return valid_string(sr_input_description_get(_structure));
1379 }
1380
1381 vector<string> InputFormat::extensions() const
1382 {
1383         vector<string> exts;
1384         for (const char *const *e = sr_input_extensions_get(_structure);
1385                 e && *e; e++)
1386                 exts.push_back(*e);
1387         return exts;
1388 }
1389
1390 map<string, shared_ptr<Option>> InputFormat::options()
1391 {
1392         map<string, shared_ptr<Option>> result;
1393
1394         if (const struct sr_option **options = sr_input_options_get(_structure)) {
1395                 shared_ptr<const struct sr_option *> option_array
1396                         {options, &sr_input_options_free};
1397                 for (int i = 0; options[i]; i++) {
1398                         shared_ptr<Option> opt {
1399                                 new Option{options[i], option_array},
1400                                 default_delete<Option>{}};
1401                         result.emplace(opt->id(), move(opt));
1402                 }
1403         }
1404         return result;
1405 }
1406
1407 shared_ptr<Input> InputFormat::create_input(
1408         map<string, Glib::VariantBase> options)
1409 {
1410         auto input = sr_input_new(_structure, map_to_hash_variant(options));
1411         if (!input)
1412                 throw Error(SR_ERR_ARG);
1413         return shared_ptr<Input>{new Input{_parent, input}, default_delete<Input>{}};
1414 }
1415
1416 Input::Input(shared_ptr<Context> context, const struct sr_input *structure) :
1417         _structure(structure),
1418         _context(move(context))
1419 {
1420 }
1421
1422 shared_ptr<InputDevice> Input::device()
1423 {
1424         if (!_device) {
1425                 auto sdi = sr_input_dev_inst_get(_structure);
1426                 if (!sdi)
1427                         throw Error(SR_ERR_NA);
1428                 _device.reset(new InputDevice{shared_from_this(), sdi});
1429         }
1430
1431         return _device->share_owned_by(shared_from_this());
1432 }
1433
1434 void Input::send(void *data, size_t length)
1435 {
1436         auto gstr = g_string_new_len(static_cast<char *>(data), length);
1437         auto ret = sr_input_send(_structure, gstr);
1438         g_string_free(gstr, true);
1439         check(ret);
1440 }
1441
1442 void Input::end()
1443 {
1444         check(sr_input_end(_structure));
1445 }
1446
1447 void Input::reset()
1448 {
1449         check(sr_input_reset(_structure));
1450 }
1451
1452 Input::~Input()
1453 {
1454         sr_input_free(_structure);
1455 }
1456
1457 InputDevice::InputDevice(shared_ptr<Input> input,
1458                 struct sr_dev_inst *structure) :
1459         Device(structure),
1460         _input(move(input))
1461 {
1462 }
1463
1464 InputDevice::~InputDevice()
1465 {
1466 }
1467
1468 shared_ptr<Device> InputDevice::get_shared_from_this()
1469 {
1470         return static_pointer_cast<Device>(shared_from_this());
1471 }
1472
1473 Option::Option(const struct sr_option *structure,
1474                 shared_ptr<const struct sr_option *> structure_array) :
1475         _structure(structure),
1476         _structure_array(move(structure_array))
1477 {
1478 }
1479
1480 Option::~Option()
1481 {
1482 }
1483
1484 string Option::id() const
1485 {
1486         return valid_string(_structure->id);
1487 }
1488
1489 string Option::name() const
1490 {
1491         return valid_string(_structure->name);
1492 }
1493
1494 string Option::description() const
1495 {
1496         return valid_string(_structure->desc);
1497 }
1498
1499 Glib::VariantBase Option::default_value() const
1500 {
1501         return Glib::VariantBase(_structure->def, true);
1502 }
1503
1504 vector<Glib::VariantBase> Option::values() const
1505 {
1506         vector<Glib::VariantBase> result;
1507         for (auto l = _structure->values; l; l = l->next) {
1508                 auto *const var = static_cast<GVariant *>(l->data);
1509                 result.push_back(Glib::VariantBase(var, true));
1510         }
1511         return result;
1512 }
1513
1514 Glib::VariantBase Option::parse_string(string value)
1515 {
1516         enum sr_datatype dt;
1517         Glib::VariantBase dflt = default_value();
1518         GVariant *tmpl = dflt.gobj();
1519
1520         if (g_variant_is_of_type(tmpl, G_VARIANT_TYPE_UINT64)) {
1521                 dt = SR_T_UINT64;
1522         } else if (g_variant_is_of_type(tmpl, G_VARIANT_TYPE_STRING)) {
1523                 dt = SR_T_STRING;
1524         } else if (g_variant_is_of_type(tmpl, G_VARIANT_TYPE_BOOLEAN)) {
1525                 dt = SR_T_BOOL;
1526         } else if (g_variant_is_of_type(tmpl, G_VARIANT_TYPE_DOUBLE)) {
1527                 dt = SR_T_FLOAT;
1528         } else if (g_variant_is_of_type(tmpl, G_VARIANT_TYPE_INT32)) {
1529                 dt = SR_T_INT32;
1530         } else {
1531                 throw Error(SR_ERR_BUG);
1532         }
1533         return ConfigKey::parse_string(value, dt);
1534 }
1535
1536 OutputFormat::OutputFormat(const struct sr_output_module *structure) :
1537         _structure(structure)
1538 {
1539 }
1540
1541 OutputFormat::~OutputFormat()
1542 {
1543 }
1544
1545 string OutputFormat::name() const
1546 {
1547         return valid_string(sr_output_id_get(_structure));
1548 }
1549
1550 string OutputFormat::description() const
1551 {
1552         return valid_string(sr_output_description_get(_structure));
1553 }
1554
1555 vector<string> OutputFormat::extensions() const
1556 {
1557         vector<string> exts;
1558         for (const char *const *e = sr_output_extensions_get(_structure);
1559                 e && *e; e++)
1560                 exts.push_back(*e);
1561         return exts;
1562 }
1563
1564 map<string, shared_ptr<Option>> OutputFormat::options()
1565 {
1566         map<string, shared_ptr<Option>> result;
1567
1568         if (const struct sr_option **options = sr_output_options_get(_structure)) {
1569                 shared_ptr<const struct sr_option *> option_array
1570                         {options, &sr_output_options_free};
1571                 for (int i = 0; options[i]; i++) {
1572                         shared_ptr<Option> opt {
1573                                 new Option{options[i], option_array},
1574                                 default_delete<Option>{}};
1575                         result.emplace(opt->id(), move(opt));
1576                 }
1577         }
1578         return result;
1579 }
1580
1581 shared_ptr<Output> OutputFormat::create_output(
1582         shared_ptr<Device> device, map<string, Glib::VariantBase> options)
1583 {
1584         return shared_ptr<Output>{
1585                 new Output{shared_from_this(), move(device), move(options)},
1586                 default_delete<Output>{}};
1587 }
1588
1589 shared_ptr<Output> OutputFormat::create_output(string filename,
1590         shared_ptr<Device> device, map<string, Glib::VariantBase> options)
1591 {
1592         return shared_ptr<Output>{
1593                 new Output{move(filename), shared_from_this(), move(device), move(options)},
1594                 default_delete<Output>{}};
1595 }
1596
1597 bool OutputFormat::test_flag(const OutputFlag *flag) const
1598 {
1599         return sr_output_test_flag(_structure, flag->id());
1600 }
1601
1602 Output::Output(shared_ptr<OutputFormat> format,
1603                 shared_ptr<Device> device, map<string, Glib::VariantBase> options) :
1604         _structure(sr_output_new(format->_structure,
1605                 map_to_hash_variant(options), device->_structure, nullptr)),
1606         _format(move(format)),
1607         _device(move(device)),
1608         _options(move(options))
1609 {
1610 }
1611
1612 Output::Output(string filename, shared_ptr<OutputFormat> format,
1613                 shared_ptr<Device> device, map<string, Glib::VariantBase> options) :
1614         _structure(sr_output_new(format->_structure,
1615                 map_to_hash_variant(options), device->_structure, filename.c_str())),
1616         _format(move(format)),
1617         _device(move(device)),
1618         _options(move(options))
1619 {
1620 }
1621
1622 Output::~Output()
1623 {
1624         check(sr_output_free(_structure));
1625 }
1626
1627 string Output::receive(shared_ptr<Packet> packet)
1628 {
1629         GString *out;
1630         check(sr_output_send(_structure, packet->_structure, &out));
1631         if (out) {
1632                 auto result = string(out->str, out->str + out->len);
1633                 g_string_free(out, true);
1634                 return result;
1635         } else {
1636                 return string();
1637         }
1638 }
1639
1640 #include <enums.cpp>
1641
1642 }