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 /**
21 
22 @mainpage API Reference
23 
24 Introduction
25 ------------
26 
27 The libsigrokcxx API provides an object-oriented C++ interface to the
28 functionality in libsigrok, including automatic memory and resource management.
29 
30 It is built on top of the public libsigrok C API, and is designed to be used as
31 a standalone alternative API. Programs should not mix usage of the C and C++
32 APIs; the C++ interface code needs to have full control of all C API calls for
33 resources to be managed correctly.
34 
35 Memory management
36 -----------------
37 
38 All runtime objects created through the C++ API are passed and accessed via
39 shared pointers, using the C++11 std::shared_ptr implementation. This means
40 that a reference count is kept for each object.
41 
42 Shared pointers can be copied and assigned in a user's program, automatically
43 updating their reference count and deleting objects when they are no longer in
44 use. The C++ interface code also keeps track of internal dependencies between
45 libsigrok resources, and ensures that objects are not prematurely deleted when
46 their resources are in use by other objects.
47 
48 This means that management of libsigrokcxx objects and their underlying
49 libsigrok resources can be treated as fully automatic. As long as all shared
50 pointers to objects are deleted or reassigned when no longer in use, all
51 underlying resources will be released at the right time.
52 
53 Getting started
54 ---------------
55 
56 Usage of the C++ API needs to begin with a call to sigrok::Context::create().
57 This will create the global libsigrok context and returns a shared pointer to
58 the sigrok::Context object. Methods on this object provide access to the
59 hardware drivers, input and output formats supported by the library, as well
60 as means of creating other objects such as sessions and triggers.
61 
62 Error handling
63 --------------
64 
65 When any libsigrok C API call returns an error, a sigrok::Error exception is
66 raised, which provides access to the error code and description.
67 
68 */
69 
70 #ifndef LIBSIGROKCXX_HPP
71 #define LIBSIGROKCXX_HPP
72 
73 #include <libsigrok/libsigrok.h>
74 
75 /* Suppress warnings due to glibmm's use of std::auto_ptr<> in a public
76  * header file. To be removed once glibmm is fixed. */
77 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
78 #include <glibmm.h>
79 G_GNUC_END_IGNORE_DEPRECATIONS
80 
81 #include <stdexcept>
82 #include <memory>
83 #include <vector>
84 #include <map>
85 #include <set>
86 
87 namespace sigrok
88 {
89 
90 /* Forward declarations */
91 class SR_API Error;
92 class SR_API Context;
93 class SR_API Driver;
94 class SR_API Device;
95 class SR_API HardwareDevice;
96 class SR_API Channel;
97 class SR_API Session;
98 class SR_API ConfigKey;
99 class SR_API Capability;
100 class SR_API InputFormat;
101 class SR_API OutputFormat;
102 class SR_API OutputFlag;
103 class SR_API LogLevel;
104 class SR_API ChannelGroup;
105 class SR_API Trigger;
106 class SR_API TriggerStage;
107 class SR_API TriggerMatch;
108 class SR_API TriggerMatchType;
109 class SR_API ChannelType;
110 class SR_API Packet;
111 class SR_API PacketPayload;
112 class SR_API PacketType;
113 class SR_API Quantity;
114 class SR_API Unit;
115 class SR_API QuantityFlag;
116 class SR_API Rational;
117 class SR_API Input;
118 class SR_API InputDevice;
119 class SR_API Output;
120 class SR_API DataType;
121 class SR_API Option;
122 class SR_API UserDevice;
123 
124 /** Exception thrown when an error code is returned by any libsigrok call. */
125 class SR_API Error: public std::exception
126 {
127 public:
128 	explicit Error(int result);
129 	~Error() noexcept;
130 	const int result;
131 	const char *what() const noexcept;
132 };
133 
134 /* Base template for classes whose resources are owned by a parent object. */
135 template <class Class, class Parent>
136 class SR_API ParentOwned
137 {
138 private:
139 	/* Weak pointer for shared_from_this() implementation. */
140 	std::weak_ptr<Class> _weak_this;
141 
reset_parent(Class * object)142 	static void reset_parent(Class *object)
143 	{
144 		if (!object->_parent)
145 			throw Error(SR_ERR_BUG);
146 		object->_parent.reset();
147 	}
148 
149 protected:
150 	/*  Parent object which owns this child object's underlying structure.
151 
152 		This shared pointer will be null when this child is unused, but
153 		will be assigned to point to the parent before any shared pointer
154 		to this child is handed out to the user.
155 
156 		When the reference count of this child falls to zero, this shared
157 		pointer to its parent is reset by a custom deleter on the child's
158 		shared pointer.
159 
160 		This strategy ensures that the destructors for both the child and
161 		the parent are called at the correct time, i.e. only when all
162 		references to both the parent and all its children are gone. */
163 	std::shared_ptr<Parent> _parent;
164 
ParentOwned()165 	ParentOwned() {}
166 
167 	/* Note, this implementation will create a new smart_ptr if none exists. */
shared_from_this()168 	std::shared_ptr<Class> shared_from_this()
169 	{
170 		std::shared_ptr<Class> shared = _weak_this.lock();
171 
172 		if (!shared)
173 		{
174 			shared.reset(static_cast<Class *>(this), &reset_parent);
175 			_weak_this = shared;
176 		}
177 
178 		return shared;
179 	}
180 
share_owned_by(std::shared_ptr<Parent> parent)181 	std::shared_ptr<Class> share_owned_by(std::shared_ptr<Parent> parent)
182 	{
183 		if (!parent)
184 			throw Error(SR_ERR_BUG);
185 		this->_parent = parent;
186 		return shared_from_this();
187 	}
188 
189 public:
190 	/* Get parent object that owns this object. */
parent()191 	std::shared_ptr<Parent> parent()
192 	{
193 		return _parent;
194 	}
195 };
196 
197 /* Base template for classes whose resources are owned by the user. */
198 template <class Class>
199 class SR_API UserOwned : public std::enable_shared_from_this<Class>
200 {
201 protected:
UserOwned()202 	UserOwned() {}
203 
shared_from_this()204 	std::shared_ptr<Class> shared_from_this()
205 	{
206 		auto shared = std::enable_shared_from_this<Class>::shared_from_this();
207 		if (!shared)
208 			throw Error(SR_ERR_BUG);
209 		return shared;
210 	}
211 };
212 
213 /** Type of log callback */
214 typedef std::function<void(const LogLevel *, std::string message)> LogCallbackFunction;
215 
216 /** Resource reader delegate. */
217 class SR_API ResourceReader
218 {
219 public:
ResourceReader()220 	ResourceReader() {}
221 	virtual ~ResourceReader();
222 private:
223 	/** Resource open hook. */
224 	virtual void open(struct sr_resource *res, std::string name) = 0;
225 	/** Resource close hook. */
226 	virtual void close(struct sr_resource *res) = 0;
227 	/** Resource read hook. */
228 	virtual size_t read(const struct sr_resource *res, void *buf, size_t count) = 0;
229 
230 	static SR_PRIV int open_callback(struct sr_resource *res,
231 			const char *name, void *cb_data) noexcept;
232 	static SR_PRIV int close_callback(struct sr_resource *res,
233 			void *cb_data) noexcept;
234 	static SR_PRIV gssize read_callback(const struct sr_resource *res,
235 			void *buf, size_t count, void *cb_data) noexcept;
236 	friend class Context;
237 };
238 
239 /** The global libsigrok context */
240 class SR_API Context : public UserOwned<Context>
241 {
242 public:
243 	/** Create new context */
244 	static std::shared_ptr<Context> create();
245 	/** libsigrok package version. */
246 	static std::string package_version();
247 	/** libsigrok library version. */
248 	static std::string lib_version();
249 	/** Available hardware drivers, indexed by name. */
250 	std::map<std::string, std::shared_ptr<Driver> > drivers();
251 	/** Available input formats, indexed by name. */
252 	std::map<std::string, std::shared_ptr<InputFormat> > input_formats();
253 	/** Lookup the responsible input module for an input file. */
254 	std::shared_ptr<InputFormat> input_format_match(std::string filename);
255 	/** Available output formats, indexed by name. */
256 	std::map<std::string, std::shared_ptr<OutputFormat> > output_formats();
257 	/** Current log level. */
258 	const LogLevel *log_level() const;
259 	/** Set the log level.
260 	 * @param level LogLevel to use. */
261 	void set_log_level(const LogLevel *level);
262 	/** Set the log callback.
263 	 * @param callback Callback of the form callback(LogLevel, string). */
264 	void set_log_callback(LogCallbackFunction callback);
265 	/** Set the log callback to the default handler. */
266 	void set_log_callback_default();
267 	/** Install a delegate for reading resource files.
268 	 * @param reader The resource reader delegate, or nullptr to unset. */
269 	void set_resource_reader(ResourceReader *reader);
270 	/** Create a new session. */
271 	std::shared_ptr<Session> create_session();
272 	/** Create a new user device. */
273 	std::shared_ptr<UserDevice> create_user_device(
274 		std::string vendor, std::string model, std::string version);
275 	/** Create a header packet. */
276 	std::shared_ptr<Packet> create_header_packet(Glib::TimeVal start_time);
277 	/** Create a meta packet. */
278 	std::shared_ptr<Packet> create_meta_packet(
279 		std::map<const ConfigKey *, Glib::VariantBase> config);
280 	/** Create a logic packet. */
281 	std::shared_ptr<Packet> create_logic_packet(
282 		void *data_pointer, size_t data_length, unsigned int unit_size);
283 	/** Create an analog packet. */
284 	std::shared_ptr<Packet> create_analog_packet(
285 		std::vector<std::shared_ptr<Channel> > channels,
286 		float *data_pointer, unsigned int num_samples, const Quantity *mq,
287 		const Unit *unit, std::vector<const QuantityFlag *> mqflags);
288 	/** Create an end packet. */
289 	std::shared_ptr<Packet> create_end_packet();
290 	/** Load a saved session.
291 	 * @param filename File name string. */
292 	std::shared_ptr<Session> load_session(std::string filename);
293 	/** Create a new trigger.
294 	 * @param name Name string for new trigger. */
295 	std::shared_ptr<Trigger> create_trigger(std::string name);
296 	/** Open an input file.
297 	 * @param filename File name string. */
298 	std::shared_ptr<Input> open_file(std::string filename);
299 	/** Open an input stream based on header data.
300 	 * @param header Initial data from stream. */
301 	std::shared_ptr<Input> open_stream(std::string header);
302 	std::map<std::string, std::string> serials(std::shared_ptr<Driver> driver) const;
303 private:
304 	struct sr_context *_structure;
305 	std::map<std::string, std::unique_ptr<Driver> > _drivers;
306 	std::map<std::string, std::unique_ptr<InputFormat> > _input_formats;
307 	std::map<std::string, std::unique_ptr<OutputFormat> > _output_formats;
308 	Session *_session;
309 	LogCallbackFunction _log_callback;
310 	Context();
311 	~Context();
312 	friend class Session;
313 	friend class Driver;
314 	friend struct std::default_delete<Context>;
315 };
316 
317 /** An object that can be configured. */
318 class SR_API Configurable
319 {
320 public:
321 	/** Supported configuration keys. */
322 	std::set<const ConfigKey *> config_keys() const;
323 	/** Read configuration for the given key.
324 	 * @param key ConfigKey to read. */
325 	Glib::VariantBase config_get(const ConfigKey *key) const;
326 	/** Set configuration for the given key to a specified value.
327 	 * @param key ConfigKey to set.
328 	 * @param value Value to set. */
329 	void config_set(const ConfigKey *key, const Glib::VariantBase &value);
330 	/** Enumerate available values for the given configuration key.
331 	 * @param key ConfigKey to enumerate values for. */
332 	Glib::VariantContainerBase config_list(const ConfigKey *key) const;
333 	/** Enumerate configuration capabilities for the given configuration key.
334 	 * @param key ConfigKey to enumerate capabilities for. */
335 	std::set<const Capability *> config_capabilities(const ConfigKey *key) const;
336 	/** Check whether a configuration capability is supported for a given key.
337 	 * @param key ConfigKey to check.
338 	 * @param capability Capability to check for. */
339 	bool config_check(const ConfigKey *key, const Capability *capability) const;
340 protected:
341 	Configurable(
342 		struct sr_dev_driver *driver,
343 		struct sr_dev_inst *sdi,
344 		struct sr_channel_group *channel_group);
345 	virtual ~Configurable();
346 	struct sr_dev_driver *config_driver;
347 	struct sr_dev_inst *config_sdi;
348 	struct sr_channel_group *config_channel_group;
349 };
350 
351 /** A hardware driver provided by the library */
352 class SR_API Driver : public ParentOwned<Driver, Context>, public Configurable
353 {
354 public:
355 	/** Name of this driver. */
356 	std::string name() const;
357 	/** Long name for this driver. */
358 	std::string long_name() const;
359 	/** Scan options supported by this driver. */
360 	std::set<const ConfigKey *> scan_options() const;
361 	/** Scan for devices and return a list of devices found.
362 	 * @param options Mapping of (ConfigKey, value) pairs. */
363 	std::vector<std::shared_ptr<HardwareDevice> > scan(std::map<const ConfigKey *, Glib::VariantBase>
364 			options = std::map<const ConfigKey *, Glib::VariantBase>());
365 private:
366 	struct sr_dev_driver *_structure;
367 	bool _initialized;
368 	std::vector<HardwareDevice *> _devices;
369 	explicit Driver(struct sr_dev_driver *structure);
370 	~Driver();
371 	friend class Context;
372 	friend class HardwareDevice;
373 	friend class ChannelGroup;
374 	friend struct std::default_delete<Driver>;
375 };
376 
377 /** A generic device, either hardware or virtual */
378 class SR_API Device : public Configurable
379 {
380 public:
381 	/** Vendor name for this device. */
382 	std::string vendor() const;
383 	/** Model name for this device. */
384 	std::string model() const;
385 	/** Version string for this device. */
386 	std::string version() const;
387 	/** Serial number for this device. */
388 	std::string serial_number() const;
389 	/** Connection ID for this device. */
390 	std::string connection_id() const;
391 	/** List of the channels available on this device. */
392 	std::vector<std::shared_ptr<Channel> > channels();
393 	/** Channel groups available on this device, indexed by name. */
394 	std::map<std::string, std::shared_ptr<ChannelGroup> > channel_groups();
395 	/** Open device. */
396 	void open();
397 	/** Close device. */
398 	void close();
399 protected:
400 	explicit Device(struct sr_dev_inst *structure);
401 	~Device();
402 	virtual std::shared_ptr<Device> get_shared_from_this() = 0;
403 	std::shared_ptr<Channel> get_channel(struct sr_channel *ptr);
404 
405 	struct sr_dev_inst *_structure;
406 	std::map<struct sr_channel *, std::unique_ptr<Channel> > _channels;
407 private:
408 	std::map<std::string, std::unique_ptr<ChannelGroup> > _channel_groups;
409 
410 	friend class Session;
411 	friend class Channel;
412 	friend class ChannelGroup;
413 	friend class Output;
414 	friend class Analog;
415 	friend struct std::default_delete<Device>;
416 };
417 
418 /** A real hardware device, connected via a driver */
419 class SR_API HardwareDevice :
420 	public UserOwned<HardwareDevice>,
421 	public Device
422 {
423 public:
424 	/** Driver providing this device. */
425 	std::shared_ptr<Driver> driver();
426 private:
427 	HardwareDevice(std::shared_ptr<Driver> driver, struct sr_dev_inst *structure);
428 	~HardwareDevice();
429 	std::shared_ptr<Device> get_shared_from_this();
430 	std::shared_ptr<Driver> _driver;
431 
432 	friend class Driver;
433 	friend class ChannelGroup;
434 	friend struct std::default_delete<HardwareDevice>;
435 };
436 
437 /** A virtual device, created by the user */
438 class SR_API UserDevice :
439 	public UserOwned<UserDevice>,
440 	public Device
441 {
442 public:
443 	/** Add a new channel to this device. */
444 	std::shared_ptr<Channel> add_channel(unsigned int index, const ChannelType *type, std::string name);
445 private:
446 	UserDevice(std::string vendor, std::string model, std::string version);
447 	~UserDevice();
448 	std::shared_ptr<Device> get_shared_from_this();
449 
450 	friend class Context;
451 	friend struct std::default_delete<UserDevice>;
452 };
453 
454 /** A channel on a device */
455 class SR_API Channel :
456 	public ParentOwned<Channel, Device>
457 {
458 public:
459 	/** Current name of this channel. */
460 	std::string name() const;
461 	/** Set the name of this channel. *
462 	 * @param name Name string to set. */
463 	void set_name(std::string name);
464 	/** Type of this channel. */
465 	const ChannelType *type() const;
466 	/** Enabled status of this channel. */
467 	bool enabled() const;
468 	/** Set the enabled status of this channel.
469 	 * @param value Boolean value to set. */
470 	void set_enabled(bool value);
471 	/** Get the index number of this channel. */
472 	unsigned int index() const;
473 private:
474 	explicit Channel(struct sr_channel *structure);
475 	~Channel();
476 	struct sr_channel *_structure;
477 	const ChannelType * const _type;
478 	friend class Device;
479 	friend class UserDevice;
480 	friend class ChannelGroup;
481 	friend class Session;
482 	friend class TriggerStage;
483 	friend class Context;
484 	friend struct std::default_delete<Channel>;
485 };
486 
487 /** A group of channels on a device, which share some configuration */
488 class SR_API ChannelGroup :
489 	public ParentOwned<ChannelGroup, Device>,
490 	public Configurable
491 {
492 public:
493 	/** Name of this channel group. */
494 	std::string name() const;
495 	/** List of the channels in this group. */
496 	std::vector<std::shared_ptr<Channel> > channels();
497 private:
498 	ChannelGroup(const Device *device, struct sr_channel_group *structure);
499 	~ChannelGroup();
500 	std::vector<Channel *> _channels;
501 	friend class Device;
502 	friend struct std::default_delete<ChannelGroup>;
503 };
504 
505 /** A trigger configuration */
506 class SR_API Trigger : public UserOwned<Trigger>
507 {
508 public:
509 	/** Name of this trigger configuration. */
510 	std::string name() const;
511 	/** List of the stages in this trigger. */
512 	std::vector<std::shared_ptr<TriggerStage> > stages();
513 	/** Add a new stage to this trigger. */
514 	std::shared_ptr<TriggerStage> add_stage();
515 private:
516 	Trigger(std::shared_ptr<Context> context, std::string name);
517 	~Trigger();
518 	struct sr_trigger *_structure;
519 	std::shared_ptr<Context> _context;
520 	std::vector<std::unique_ptr<TriggerStage> > _stages;
521 	friend class Context;
522 	friend class Session;
523 	friend struct std::default_delete<Trigger>;
524 };
525 
526 /** A stage in a trigger configuration */
527 class SR_API TriggerStage :
528 	public ParentOwned<TriggerStage, Trigger>
529 {
530 public:
531 	/** Index number of this stage. */
532 	int number() const;
533 	/** List of match conditions on this stage. */
534 	std::vector<std::shared_ptr<TriggerMatch> > matches();
535 	/** Add a new match condition to this stage.
536 	 * @param channel Channel to match on.
537 	 * @param type TriggerMatchType to apply. */
538 	void add_match(std::shared_ptr<Channel> channel, const TriggerMatchType *type);
539 	/** Add a new match condition to this stage.
540 	 * @param channel Channel to match on.
541 	 * @param type TriggerMatchType to apply.
542 	 * @param value Threshold value. */
543 	void add_match(std::shared_ptr<Channel> channel, const TriggerMatchType *type, float value);
544 private:
545 	struct sr_trigger_stage *_structure;
546 	std::vector<std::unique_ptr<TriggerMatch> > _matches;
547 	explicit TriggerStage(struct sr_trigger_stage *structure);
548 	~TriggerStage();
549 	friend class Trigger;
550 	friend struct std::default_delete<TriggerStage>;
551 };
552 
553 /** A match condition in a trigger configuration  */
554 class SR_API TriggerMatch :
555 	public ParentOwned<TriggerMatch, TriggerStage>
556 {
557 public:
558 	/** Channel this condition matches on. */
559 	std::shared_ptr<Channel> channel();
560 	/** Type of match. */
561 	const TriggerMatchType *type() const;
562 	/** Threshold value. */
563 	float value() const;
564 private:
565 	TriggerMatch(struct sr_trigger_match *structure, std::shared_ptr<Channel> channel);
566 	~TriggerMatch();
567 	struct sr_trigger_match *_structure;
568 	std::shared_ptr<Channel> _channel;
569 	friend class TriggerStage;
570 	friend struct std::default_delete<TriggerMatch>;
571 };
572 
573 /** Type of session stopped callback */
574 typedef std::function<void()> SessionStoppedCallback;
575 
576 /** Type of datafeed callback */
577 typedef std::function<void(std::shared_ptr<Device>, std::shared_ptr<Packet>)>
578 	DatafeedCallbackFunction;
579 
580 /* Data required for C callback function to call a C++ datafeed callback */
581 class SR_PRIV DatafeedCallbackData
582 {
583 public:
584 	void run(const struct sr_dev_inst *sdi,
585 		const struct sr_datafeed_packet *pkt);
586 private:
587 	DatafeedCallbackFunction _callback;
588 	DatafeedCallbackData(Session *session,
589 		DatafeedCallbackFunction callback);
590 	Session *_session;
591 	friend class Session;
592 };
593 
594 /** A virtual device associated with a stored session */
595 class SR_API SessionDevice :
596 	public ParentOwned<SessionDevice, Session>,
597 	public Device
598 {
599 private:
600 	explicit SessionDevice(struct sr_dev_inst *sdi);
601 	~SessionDevice();
602 	std::shared_ptr<Device> get_shared_from_this();
603 
604 	friend class Session;
605 	friend struct std::default_delete<SessionDevice>;
606 };
607 
608 /** A sigrok session */
609 class SR_API Session : public UserOwned<Session>
610 {
611 public:
612 	/** Add a device to this session.
613 	 * @param device Device to add. */
614 	void add_device(std::shared_ptr<Device> device);
615 	/** List devices attached to this session. */
616 	std::vector<std::shared_ptr<Device> > devices();
617 	/** Remove all devices from this session. */
618 	void remove_devices();
619 	/** Add a datafeed callback to this session.
620 	 * @param callback Callback of the form callback(Device, Packet). */
621 	void add_datafeed_callback(DatafeedCallbackFunction callback);
622 	/** Remove all datafeed callbacks from this session. */
623 	void remove_datafeed_callbacks();
624 	/** Start the session. */
625 	void start();
626 	/** Run the session event loop. */
627 	void run();
628 	/** Stop the session. */
629 	void stop();
630 	/** Return whether the session is running. */
631 	bool is_running() const;
632 	/** Set callback to be invoked on session stop. */
633 	void set_stopped_callback(SessionStoppedCallback callback);
634 	/** Get current trigger setting. */
635 	std::shared_ptr<Trigger> trigger();
636 	/** Get the context. */
637 	std::shared_ptr<Context> context();
638 	/** Set trigger setting.
639 	 * @param trigger Trigger object to use. */
640 	void set_trigger(std::shared_ptr<Trigger> trigger);
641 	/** Get filename this session was loaded from. */
642 	std::string filename() const;
643 private:
644 	explicit Session(std::shared_ptr<Context> context);
645 	Session(std::shared_ptr<Context> context, std::string filename);
646 	~Session();
647 	std::shared_ptr<Device> get_device(const struct sr_dev_inst *sdi);
648 	struct sr_session *_structure;
649 	const std::shared_ptr<Context> _context;
650 	std::map<const struct sr_dev_inst *, std::unique_ptr<SessionDevice> > _owned_devices;
651 	std::map<const struct sr_dev_inst *, std::shared_ptr<Device> > _other_devices;
652 	std::vector<std::unique_ptr<DatafeedCallbackData> > _datafeed_callbacks;
653 	SessionStoppedCallback _stopped_callback;
654 	std::string _filename;
655 	std::shared_ptr<Trigger> _trigger;
656 
657 	friend class Context;
658 	friend class DatafeedCallbackData;
659 	friend class SessionDevice;
660 	friend struct std::default_delete<Session>;
661 };
662 
663 /** A packet on the session datafeed */
664 class SR_API Packet : public UserOwned<Packet>
665 {
666 public:
667 	/** Type of this packet. */
668 	const PacketType *type() const;
669 	/** Payload of this packet. */
670 	std::shared_ptr<PacketPayload> payload();
671 private:
672 	Packet(std::shared_ptr<Device> device,
673 		const struct sr_datafeed_packet *structure);
674 	~Packet();
675 	const struct sr_datafeed_packet *_structure;
676 	std::shared_ptr<Device> _device;
677 	std::unique_ptr<PacketPayload> _payload;
678 
679 	friend class Session;
680 	friend class Output;
681 	friend class DatafeedCallbackData;
682 	friend class Header;
683 	friend class Meta;
684 	friend class Logic;
685 	friend class Analog;
686 	friend class Context;
687 	friend struct std::default_delete<Packet>;
688 };
689 
690 /** Abstract base class for datafeed packet payloads */
691 class SR_API PacketPayload
692 {
693 protected:
694 	PacketPayload();
695 	virtual ~PacketPayload() = 0;
696 private:
697 	virtual std::shared_ptr<PacketPayload> share_owned_by(std::shared_ptr<Packet> parent) = 0;
698 
699 	friend class Packet;
700 	friend class Output;
701 	friend struct std::default_delete<PacketPayload>;
702 };
703 
704 /** Payload of a datafeed header packet */
705 class SR_API Header :
706 	public ParentOwned<Header, Packet>,
707 	public PacketPayload
708 {
709 public:
710 	/* Feed version number. */
711 	int feed_version() const;
712 	/* Start time of this session. */
713 	Glib::TimeVal start_time() const;
714 private:
715 	explicit Header(const struct sr_datafeed_header *structure);
716 	~Header();
717 	std::shared_ptr<PacketPayload> share_owned_by(std::shared_ptr<Packet> parent);
718 
719 	const struct sr_datafeed_header *_structure;
720 
721 	friend class Packet;
722 };
723 
724 /** Payload of a datafeed metadata packet */
725 class SR_API Meta :
726 	public ParentOwned<Meta, Packet>,
727 	public PacketPayload
728 {
729 public:
730 	/* Mapping of (ConfigKey, value) pairs. */
731 	std::map<const ConfigKey *, Glib::VariantBase> config() const;
732 private:
733 	explicit Meta(const struct sr_datafeed_meta *structure);
734 	~Meta();
735 	std::shared_ptr<PacketPayload> share_owned_by(std::shared_ptr<Packet> parent);
736 
737 	const struct sr_datafeed_meta *_structure;
738 	std::map<const ConfigKey *, Glib::VariantBase> _config;
739 
740 	friend class Packet;
741 };
742 
743 /** Payload of a datafeed packet with logic data */
744 class SR_API Logic :
745 	public ParentOwned<Logic, Packet>,
746 	public PacketPayload
747 {
748 public:
749 	/* Pointer to data. */
750 	void *data_pointer();
751 	/* Data length in bytes. */
752 	size_t data_length() const;
753 	/* Size of each sample in bytes. */
754 	unsigned int unit_size() const;
755 private:
756 	explicit Logic(const struct sr_datafeed_logic *structure);
757 	~Logic();
758 	std::shared_ptr<PacketPayload> share_owned_by(std::shared_ptr<Packet> parent);
759 
760 	const struct sr_datafeed_logic *_structure;
761 
762 	friend class Packet;
763 	friend class Analog;
764 	friend struct std::default_delete<Logic>;
765 };
766 
767 /** Payload of a datafeed packet with analog data */
768 class SR_API Analog :
769 	public ParentOwned<Analog, Packet>,
770 	public PacketPayload
771 {
772 public:
773 	/** Pointer to data. */
774 	void *data_pointer();
775 	/**
776 	 * Fills dest pointer with the analog data converted to float.
777 	 * The pointer must have space for num_samples() floats.
778 	 */
779 	void get_data_as_float(float *dest);
780 	/** Number of samples in this packet. */
781 	unsigned int num_samples() const;
782 	/** Channels for which this packet contains data. */
783 	std::vector<std::shared_ptr<Channel> > channels();
784 	/** Size of a single sample in bytes. */
785 	unsigned int unitsize() const;
786 	/** Samples use a signed data type. */
787 	bool is_signed() const;
788 	/** Samples use float. */
789 	bool is_float() const;
790 	/** Samples are stored in big-endian order. */
791 	bool is_bigendian() const;
792 	/**
793 	 * Number of significant digits after the decimal point if positive,
794 	 * or number of non-significant digits before the decimal point if negative
795 	 * (refers to the value we actually read on the wire).
796 	 */
797 	int digits() const;
798 	/** TBD */
799 	bool is_digits_decimal() const;
800 	/** TBD */
801 	std::shared_ptr<Rational> scale();
802 	/** TBD */
803 	std::shared_ptr<Rational> offset();
804 	/** Measured quantity of the samples in this packet. */
805 	const Quantity *mq() const;
806 	/** Unit of the samples in this packet. */
807 	const Unit *unit() const;
808 	/** Measurement flags associated with the samples in this packet. */
809 	std::vector<const QuantityFlag *> mq_flags() const;
810 	/**
811 	 * Provides a Logic packet that contains a conversion of the analog
812 	 * data using a simple threshold.
813 	 *
814 	 * @param threshold Threshold to use.
815 	 * @param data_ptr Pointer to num_samples() bytes where the logic
816 	 *                 samples are stored. When nullptr, memory for
817 	 *                 logic->data_pointer() will be allocated and must
818 	 *                 be freed by the caller.
819 	 */
820 	std::shared_ptr<Logic> get_logic_via_threshold(float threshold,
821 		uint8_t *data_ptr=nullptr) const;
822 	/**
823 	 * Provides a Logic packet that contains a conversion of the analog
824 	 * data using a Schmitt-Trigger.
825 	 *
826 	 * @param lo_thr Low threshold to use (anything below this is low).
827 	 * @param hi_thr High threshold to use (anything above this is high).
828 	 * @param state Points to a byte that contains the current state of the
829 	 *              converter. For best results, set to value of logic
830 	 *              sample n-1.
831 	 * @param data_ptr Pointer to num_samples() bytes where the logic
832 	 *                 samples are stored. When nullptr, memory for
833 	 *                 logic->data_pointer() will be allocated and must be
834 	 *                 freed by the caller.
835 	 */
836 	std::shared_ptr<Logic> get_logic_via_schmitt_trigger(float lo_thr,
837 		float hi_thr, uint8_t *state, uint8_t *data_ptr=nullptr) const;
838 private:
839 	explicit Analog(const struct sr_datafeed_analog *structure);
840 	~Analog();
841 	std::shared_ptr<PacketPayload> share_owned_by(std::shared_ptr<Packet> parent);
842 
843 	const struct sr_datafeed_analog *_structure;
844 
845 	friend class Packet;
846 };
847 
848 /** Number represented by a numerator/denominator integer pair */
849 class SR_API Rational :
850 	public ParentOwned<Rational, Analog>
851 {
852 public:
853 	/** Numerator, i.e. the dividend. */
854 	int64_t numerator() const;
855 	/** Denominator, i.e. the divider. */
856 	uint64_t denominator() const;
857 	/** Actual (lossy) value. */
858 	float value() const;
859 private:
860 	explicit Rational(const struct sr_rational *structure);
861 	~Rational();
862 	std::shared_ptr<Rational> share_owned_by(std::shared_ptr<Analog> parent);
863 
864 	const struct sr_rational *_structure;
865 
866 	friend class Analog;
867 	friend struct std::default_delete<Rational>;
868 };
869 
870 /** An input format supported by the library */
871 class SR_API InputFormat :
872 	public ParentOwned<InputFormat, Context>
873 {
874 public:
875 	/** Name of this input format. */
876 	std::string name() const;
877 	/** Description of this input format. */
878 	std::string description() const;
879 	/** A list of preferred file name extensions for this file format.
880 	 * @note This list is a recommendation only. */
881 	std::vector<std::string> extensions() const;
882 	/** Options supported by this input format. */
883 	std::map<std::string, std::shared_ptr<Option> > options();
884 	/** Create an input using this input format.
885 	 * @param options Mapping of (option name, value) pairs. */
886 	std::shared_ptr<Input> create_input(std::map<std::string, Glib::VariantBase>
887 			options = std::map<std::string, Glib::VariantBase>());
888 private:
889 	explicit InputFormat(const struct sr_input_module *structure);
890 	~InputFormat();
891 
892 	const struct sr_input_module *_structure;
893 
894 	friend class Context;
895 	friend class InputDevice;
896 	friend struct std::default_delete<InputFormat>;
897 };
898 
899 /** An input instance (an input format applied to a file or stream) */
900 class SR_API Input : public UserOwned<Input>
901 {
902 public:
903 	/** Virtual device associated with this input. */
904 	std::shared_ptr<InputDevice> device();
905 	/** Send next stream data.
906 	 * @param data Next stream data.
907 	 * @param length Length of data. */
908 	void send(void *data, size_t length);
909 	/** Signal end of input data. */
910 	void end();
911 	void reset();
912 private:
913 	Input(std::shared_ptr<Context> context, const struct sr_input *structure);
914 	~Input();
915 	const struct sr_input *_structure;
916 	std::shared_ptr<Context> _context;
917 	std::unique_ptr<InputDevice> _device;
918 
919 	friend class Context;
920 	friend class InputFormat;
921 	friend struct std::default_delete<Input>;
922 };
923 
924 /** A virtual device associated with an input */
925 class SR_API InputDevice :
926 	public ParentOwned<InputDevice, Input>,
927 	public Device
928 {
929 private:
930 	InputDevice(std::shared_ptr<Input> input, struct sr_dev_inst *sdi);
931 	~InputDevice();
932 	std::shared_ptr<Device> get_shared_from_this();
933 	std::shared_ptr<Input> _input;
934 	friend class Input;
935 	friend struct std::default_delete<InputDevice>;
936 };
937 
938 /** An option used by an output format */
939 class SR_API Option : public UserOwned<Option>
940 {
941 public:
942 	/** Short name of this option suitable for command line usage. */
943 	std::string id() const;
944 	/** Short name of this option suitable for GUI usage. */
945 	std::string name() const;
946 	/** Description of this option in a sentence. */
947 	std::string description() const;
948 	/** Default value for this option. */
949 	Glib::VariantBase default_value() const;
950 	/** Possible values for this option, if a limited set. */
951 	std::vector<Glib::VariantBase> values() const;
952 	/** Parse a string argument into the appropriate type for this option. */
953 	Glib::VariantBase parse_string(std::string value);
954 private:
955 	Option(const struct sr_option *structure,
956 		std::shared_ptr<const struct sr_option *> structure_array);
957 	~Option();
958 	const struct sr_option *_structure;
959 	std::shared_ptr<const struct sr_option *> _structure_array;
960 
961 	friend class InputFormat;
962 	friend class OutputFormat;
963 	friend struct std::default_delete<Option>;
964 };
965 
966 /** An output format supported by the library */
967 class SR_API OutputFormat :
968 	public ParentOwned<OutputFormat, Context>
969 {
970 public:
971 	/** Name of this output format. */
972 	std::string name() const;
973 	/** Description of this output format. */
974 	std::string description() const;
975 	/** A list of preferred file name extensions for this file format.
976 	 * @note This list is a recommendation only. */
977 	std::vector<std::string> extensions() const;
978 	/** Options supported by this output format. */
979 	std::map<std::string, std::shared_ptr<Option> > options();
980 	/** Create an output using this format.
981 	 * @param device Device to output for.
982 	 * @param options Mapping of (option name, value) pairs. */
983 	std::shared_ptr<Output> create_output(std::shared_ptr<Device> device,
984 		std::map<std::string, Glib::VariantBase> options = std::map<std::string, Glib::VariantBase>());
985 	/** Create an output using this format.
986 	 * @param filename Name of destination file.
987 	 * @param device Device to output for.
988 	 * @param options Mapping of (option name, value) pairs. */
989 	std::shared_ptr<Output> create_output(std::string filename,
990 		std::shared_ptr<Device> device,
991 		std::map<std::string, Glib::VariantBase> options = std::map<std::string, Glib::VariantBase>());
992 	/**
993 	 * Checks whether a given flag is set.
994 	 * @param flag Flag to check
995 	 * @return true if flag is set for this module
996 	 * @see sr_output_flags
997 	 */
998 	bool test_flag(const OutputFlag *flag) const;
999 private:
1000 	explicit OutputFormat(const struct sr_output_module *structure);
1001 	~OutputFormat();
1002 
1003 	const struct sr_output_module *_structure;
1004 
1005 	friend class Context;
1006 	friend class Output;
1007 	friend struct std::default_delete<OutputFormat>;
1008 };
1009 
1010 /** An output instance (an output format applied to a device) */
1011 class SR_API Output : public UserOwned<Output>
1012 {
1013 public:
1014 	/** Update output with data from the given packet.
1015 	 * @param packet Packet to handle. */
1016 	std::string receive(std::shared_ptr<Packet> packet);
1017 	/** Output format in use for this output */
1018 	std::shared_ptr<OutputFormat> format();
1019 private:
1020 	Output(std::shared_ptr<OutputFormat> format, std::shared_ptr<Device> device);
1021 	Output(std::shared_ptr<OutputFormat> format,
1022 		std::shared_ptr<Device> device, std::map<std::string, Glib::VariantBase> options);
1023 	Output(std::string filename, std::shared_ptr<OutputFormat> format,
1024 		std::shared_ptr<Device> device, std::map<std::string, Glib::VariantBase> options);
1025 	~Output();
1026 
1027 	const struct sr_output *_structure;
1028 	const std::shared_ptr<OutputFormat> _format;
1029 	const std::shared_ptr<Device> _device;
1030 	const std::map<std::string, Glib::VariantBase> _options;
1031 
1032 	friend class OutputFormat;
1033 	friend struct std::default_delete<Output>;
1034 };
1035 
1036 /** Base class for objects which wrap an enumeration value from libsigrok */
1037 template <class Class, typename Enum> class SR_API EnumValue
1038 {
1039 public:
1040 	/** The integer constant associated with this value. */
id() const1041 	int id() const
1042 	{
1043 		return static_cast<int>(_id);
1044 	}
1045 	/** The name associated with this value. */
name() const1046 	std::string name() const
1047 	{
1048 		return _name;
1049 	}
1050 	/** Get value associated with a given integer constant. */
get(int id)1051 	static const Class *get(int id)
1052 	{
1053 		const auto pos = _values.find(static_cast<Enum>(id));
1054 		if (pos == _values.end())
1055 			throw Error(SR_ERR_ARG);
1056 		return pos->second;
1057 	}
1058 	/** Get possible values. */
values()1059 	static std::vector<const Class *> values()
1060 	{
1061 		std::vector<const Class *> result;
1062 		for (auto entry : _values)
1063 			result.push_back(entry.second);
1064 		return result;
1065 	}
1066 protected:
EnumValue(Enum id,const char name[])1067 	EnumValue(Enum id, const char name[]) : _id(id), _name(name)
1068 	{
1069 	}
~EnumValue()1070 	~EnumValue()
1071 	{
1072 	}
1073 private:
1074 	static const std::map<const Enum, const Class * const> _values;
1075 	const Enum _id;
1076 	const std::string _name;
1077 };
1078 
1079 }
1080 
1081 #include <libsigrokcxx/enums.hpp>
1082 
1083 #endif
1084