]> sigrok.org Git - libsigrok.git/blobdiff - bindings/cxx/classes.cpp
SR_DF_ANALOG_OLD and sr_datafeed_analog_old renames.
[libsigrok.git] / bindings / cxx / classes.cpp
index ec9b6d8f289e8bddd5825fe3b3b33601951f066a..3e441f72252c2e4a34ebe30c303cd7a0e4b07a1c 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "libsigrok/libsigrok.hpp"
+/* Needed for isascii(), as used in the GNU libstdc++ headers */
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE 600
+#endif
+
+#include <config.h>
+#include <libsigrokcxx/libsigrokcxx.hpp>
 
 #include <sstream>
+#include <cmath>
 
 namespace sigrok
 {
@@ -65,6 +72,50 @@ Error::~Error() throw()
 {
 }
 
+ResourceReader::~ResourceReader()
+{
+}
+
+SR_PRIV int ResourceReader::open_callback(struct sr_resource *res,
+               const char *name, void *cb_data)
+{
+       try {
+               auto *const reader = static_cast<ResourceReader*>(cb_data);
+               reader->open(res, name);
+       } catch (const Error &err) {
+               return err.result;
+       } catch (...) {
+               return SR_ERR;
+       }
+       return SR_OK;
+}
+
+SR_PRIV int ResourceReader::close_callback(struct sr_resource *res, void *cb_data)
+{
+       try {
+               auto *const reader = static_cast<ResourceReader*>(cb_data);
+               reader->close(res);
+       } catch (const Error &err) {
+               return err.result;
+       } catch (...) {
+               return SR_ERR;
+       }
+       return SR_OK;
+}
+
+SR_PRIV ssize_t ResourceReader::read_callback(const struct sr_resource *res,
+               void *buf, size_t count, void *cb_data)
+{
+       try {
+               auto *const reader = static_cast<ResourceReader*>(cb_data);
+               return reader->read(res, buf, count);
+       } catch (const Error &err) {
+               return err.result;
+       } catch (...) {
+               return SR_ERR;
+       }
+}
+
 shared_ptr<Context> Context::create()
 {
        return shared_ptr<Context>(new Context(), Context::Deleter());
@@ -76,7 +127,7 @@ Context::Context() :
 {
        check(sr_init(&_structure));
 
-       struct sr_dev_driver **driver_list = sr_driver_list();
+       struct sr_dev_driver **driver_list = sr_driver_list(_structure);
        if (driver_list)
                for (int i = 0; driver_list[i]; i++)
                        _drivers[driver_list[i]->name] =
@@ -160,16 +211,6 @@ void Context::set_log_level(const LogLevel *level)
        check(sr_log_loglevel_set(level->id()));
 }
 
-string Context::log_domain()
-{
-       return valid_string(sr_log_logdomain_get());
-}
-
-void Context::set_log_domain(string value)
-{
-       check(sr_log_logdomain_set(value.c_str()));
-}
-
 static int call_log_callback(void *cb_data, int loglevel, const char *format, va_list args)
 {
        va_list args_copy;
@@ -199,13 +240,26 @@ void Context::set_log_callback(LogCallbackFunction callback)
 {
        _log_callback = callback;
        check(sr_log_callback_set(call_log_callback, &_log_callback));
-} 
+}
 
 void Context::set_log_callback_default()
 {
        check(sr_log_callback_set_default());
        _log_callback = nullptr;
-} 
+}
+
+void Context::set_resource_reader(ResourceReader *reader)
+{
+       if (reader) {
+               check(sr_resource_set_hooks(_structure,
+                               &ResourceReader::open_callback,
+                               &ResourceReader::close_callback,
+                               &ResourceReader::read_callback, reader));
+       } else {
+               check(sr_resource_set_hooks(_structure,
+                               nullptr, nullptr, nullptr, nullptr));
+       }
+}
 
 shared_ptr<Session> Context::create_session()
 {
@@ -213,6 +267,77 @@ shared_ptr<Session> Context::create_session()
                new Session(shared_from_this()), Session::Deleter());
 }
 
+shared_ptr<UserDevice> Context::create_user_device(
+               string vendor, string model, string version)
+{
+       return shared_ptr<UserDevice>(
+               new UserDevice(vendor, model, version), UserDevice::Deleter());
+}
+
+shared_ptr<Packet> Context::create_header_packet(Glib::TimeVal start_time)
+{
+       auto header = g_new(struct sr_datafeed_header, 1);
+       header->feed_version = 1;
+       header->starttime.tv_sec = start_time.tv_sec;
+       header->starttime.tv_usec = start_time.tv_usec;
+       auto packet = g_new(struct sr_datafeed_packet, 1);
+       packet->type = SR_DF_HEADER;
+       packet->payload = header;
+       return shared_ptr<Packet>(new Packet(nullptr, packet), Packet::Deleter());
+}
+
+shared_ptr<Packet> Context::create_meta_packet(
+       map<const ConfigKey *, Glib::VariantBase> config)
+{
+       auto meta = g_new0(struct sr_datafeed_meta, 1);
+       for (auto input : config)
+       {
+               auto key = input.first;
+               auto value = input.second;
+               auto output = g_new(struct sr_config, 1);
+               output->key = key->id();
+               output->data = value.gobj();
+               g_variant_ref(output->data);
+               meta->config = g_slist_append(meta->config, output);
+       }
+       auto packet = g_new(struct sr_datafeed_packet, 1);
+       packet->type = SR_DF_META;
+       packet->payload = meta;
+       return shared_ptr<Packet>(new Packet(nullptr, packet), Packet::Deleter());
+}
+
+shared_ptr<Packet> Context::create_logic_packet(
+       void *data_pointer, size_t data_length, unsigned int unit_size)
+{
+       auto logic = g_new(struct sr_datafeed_logic, 1);
+       logic->length = data_length;
+       logic->unitsize = unit_size;
+       logic->data = data_pointer;
+       auto packet = g_new(struct sr_datafeed_packet, 1);
+       packet->type = SR_DF_LOGIC;
+       packet->payload = logic;
+       return shared_ptr<Packet>(new Packet(nullptr, packet), Packet::Deleter());
+}
+
+shared_ptr<Packet> Context::create_analog_old_packet(
+       vector<shared_ptr<Channel> > channels,
+       float *data_pointer, unsigned int num_samples, const Quantity *mq,
+       const Unit *unit, vector<const QuantityFlag *> mqflags)
+{
+       auto analog = g_new0(struct sr_datafeed_analog_old, 1);
+       for (auto channel : channels)
+               analog->channels = g_slist_append(analog->channels, channel->_structure);
+       analog->num_samples = num_samples;
+       analog->mq = mq->id();
+       analog->unit = unit->id();
+       analog->mqflags = QuantityFlag::mask_from_flags(mqflags);
+       analog->data = data_pointer;
+       auto packet = g_new(struct sr_datafeed_packet, 1);
+       packet->type = SR_DF_ANALOG_OLD;
+       packet->payload = analog;
+       return shared_ptr<Packet>(new Packet(nullptr, packet), Packet::Deleter());
+}
+
 shared_ptr<Session> Context::load_session(string filename)
 {
        return shared_ptr<Session>(
@@ -246,6 +371,20 @@ shared_ptr<Input> Context::open_stream(string header)
                new Input(shared_from_this(), input), Input::Deleter());
 }
 
+map<string, string> Context::serials(shared_ptr<Driver> driver)
+{
+       GSList *serial_list = sr_serial_list(driver ? driver->_structure : NULL);
+       map<string, string> serials;
+
+       for (GSList *serial = serial_list; serial; serial = serial->next) {
+               struct sr_serial_port *port = (sr_serial_port *) serial->data;
+               serials[string(port->name)] = string(port->description);
+       }
+
+       g_slist_free_full(serial_list, (GDestroyNotify)sr_serial_free);
+       return serials;
+}
+
 Driver::Driver(struct sr_dev_driver *structure) :
        ParentOwned(structure),
        Configurable(structure, NULL, NULL),
@@ -255,8 +394,6 @@ Driver::Driver(struct sr_dev_driver *structure) :
 
 Driver::~Driver()
 {
-       for (auto device : _devices)
-               delete device;
 }
 
 string Driver::name()
@@ -279,11 +416,6 @@ vector<shared_ptr<HardwareDevice>> Driver::scan(
                _initialized = true;
        }
 
-       /* Clear all existing instances. */
-       for (auto device : _devices)
-               delete device;
-       _devices.clear();
-
        /* Translate scan options to GSList of struct sr_config pointers. */
        GSList *option_list = NULL;
        for (auto entry : options)
@@ -302,20 +434,20 @@ vector<shared_ptr<HardwareDevice>> Driver::scan(
        /* Free option list. */
        g_slist_free_full(option_list, g_free);
 
+
        /* Create device objects. */
+       vector<shared_ptr<HardwareDevice>> result;
        for (GSList *device = device_list; device; device = device->next)
        {
                auto sdi = (struct sr_dev_inst *) device->data;
-               _devices.push_back(new HardwareDevice(this, sdi));
+               result.push_back(shared_ptr<HardwareDevice>(
+                       new HardwareDevice(shared_from_this(), sdi),
+                       HardwareDevice::Deleter()));
        }
 
        /* Free GSList returned from scan. */
        g_slist_free(device_list);
 
-       /* Create list of shared pointers to device instances for return. */
-       vector<shared_ptr<HardwareDevice>> result;
-       for (auto device : _devices)
-               result.push_back(device->get_shared_pointer(_parent));
        return result;
 }
 
@@ -358,22 +490,32 @@ Glib::VariantContainerBase Configurable::config_list(const ConfigKey *key)
        return Glib::VariantContainerBase(data);
 }
 
-vector<const ConfigKey *> Configurable::config_keys(const ConfigKey *key)
+map<const ConfigKey *, set<Capability>> Configurable::config_keys(const ConfigKey *key)
 {
        GVariant *gvar_opts;
        gsize num_opts;
-       const int32_t *opts;
-       vector<const ConfigKey *> result;
+       const uint32_t *opts;
+       map<const ConfigKey *, set<Capability>> result;
 
        check(sr_config_list(
                config_driver, config_sdi, config_channel_group,
                key->id(), &gvar_opts));
 
-       opts = (const int32_t *) g_variant_get_fixed_array(
-               gvar_opts, &num_opts, sizeof(int32_t));
+       opts = (const uint32_t *) g_variant_get_fixed_array(
+               gvar_opts, &num_opts, sizeof(uint32_t));
 
        for (gsize i = 0; i < num_opts; i++)
-               result.push_back(ConfigKey::get(opts[i]));
+       {
+               auto key = ConfigKey::get(opts[i] & SR_CONF_MASK);
+               set<Capability> capabilities;
+               if (opts[i] & SR_CONF_GET)
+                       capabilities.insert(GET);
+               if (opts[i] & SR_CONF_SET)
+                       capabilities.insert(SET);
+               if (opts[i] & SR_CONF_LIST)
+                       capabilities.insert(LIST);
+               result[key] = capabilities;
+       }
 
        g_variant_unref(gvar_opts);
 
@@ -385,18 +527,18 @@ bool Configurable::config_check(const ConfigKey *key,
 {
        GVariant *gvar_opts;
        gsize num_opts;
-       const int32_t *opts;
+       const uint32_t *opts;
 
        if (sr_config_list(config_driver, config_sdi, config_channel_group,
                        index_key->id(), &gvar_opts) != SR_OK)
                return false;
 
-       opts = (const int32_t *) g_variant_get_fixed_array(
-               gvar_opts, &num_opts, sizeof(int32_t));
+       opts = (const uint32_t *) g_variant_get_fixed_array(
+               gvar_opts, &num_opts, sizeof(uint32_t));
 
        for (gsize i = 0; i < num_opts; i++)
        {
-               if (opts[i] == key->id())
+               if ((opts[i] & SR_CONF_MASK) == (uint32_t) key->id())
                {
                        g_variant_unref(gvar_opts);
                        return true;
@@ -409,16 +551,16 @@ bool Configurable::config_check(const ConfigKey *key,
 }
 
 Device::Device(struct sr_dev_inst *structure) :
-       Configurable(structure->driver, structure, NULL),
+       Configurable(sr_dev_inst_driver_get(structure), structure, NULL),
        _structure(structure)
 {
-       for (GSList *entry = structure->channels; entry; entry = entry->next)
+       for (GSList *entry = sr_dev_inst_channels_get(structure); entry; entry = entry->next)
        {
                auto channel = (struct sr_channel *) entry->data;
                _channels[channel] = new Channel(channel);
        }
 
-       for (GSList *entry = structure->channel_groups; entry; entry = entry->next)
+       for (GSList *entry = sr_dev_inst_channel_groups_get(structure); entry; entry = entry->next)
        {
                auto group = (struct sr_channel_group *) entry->data;
                _channel_groups[group->name] = new ChannelGroup(this, group);
@@ -433,39 +575,35 @@ Device::~Device()
                delete entry.second;
 }
 
-string Device::description()
+string Device::vendor()
 {
-       ostringstream s;
-
-       vector<string> parts =
-               {vendor(), model(), version()};
-
-       for (string part : parts)
-               if (part.length() > 0)
-                       s << part;
+       return valid_string(sr_dev_inst_vendor_get(_structure));
+}
 
-       return s.str();
+string Device::model()
+{
+       return valid_string(sr_dev_inst_model_get(_structure));
 }
 
-string Device::vendor()
+string Device::version()
 {
-       return valid_string(_structure->vendor);
+       return valid_string(sr_dev_inst_version_get(_structure));
 }
 
-string Device::model()
+string Device::serial_number()
 {
-       return valid_string(_structure->model);
+       return valid_string(sr_dev_inst_sernum_get(_structure));
 }
 
-string Device::version()
+string Device::connection_id()
 {
-       return valid_string(_structure->version);
+       return valid_string(sr_dev_inst_connid_get(_structure));
 }
 
 vector<shared_ptr<Channel>> Device::channels()
 {
        vector<shared_ptr<Channel>> result;
-       for (auto channel = _structure->channels; channel; channel = channel->next)
+       for (auto channel = sr_dev_inst_channels_get(_structure); channel; channel = channel->next)
                result.push_back(
                        _channels[(struct sr_channel *) channel->data]->get_shared_pointer(
                                get_shared_from_this()));
@@ -500,8 +638,9 @@ void Device::close()
        check(sr_dev_close(_structure));
 }
 
-HardwareDevice::HardwareDevice(Driver *driver, struct sr_dev_inst *structure) :
-       ParentOwned(structure),
+HardwareDevice::HardwareDevice(shared_ptr<Driver> driver,
+               struct sr_dev_inst *structure) :
+       UserOwned(structure),
        Device(structure),
        _driver(driver)
 {
@@ -518,7 +657,35 @@ shared_ptr<Device> HardwareDevice::get_shared_from_this()
 
 shared_ptr<Driver> HardwareDevice::driver()
 {
-       return _driver->get_shared_pointer(_parent);
+       return _driver;
+}
+
+UserDevice::UserDevice(string vendor, string model, string version) :
+       UserOwned(sr_dev_inst_user_new(
+               vendor.c_str(), model.c_str(), version.c_str())),
+       Device(UserOwned::_structure)
+{
+}
+
+UserDevice::~UserDevice()
+{
+}
+
+shared_ptr<Device> UserDevice::get_shared_from_this()
+{
+       return static_pointer_cast<Device>(shared_from_this());
+}
+
+shared_ptr<Channel> UserDevice::add_channel(unsigned int index,
+       const ChannelType *type, string name)
+{
+       check(sr_dev_inst_channel_add(Device::_structure,
+               index, type->id(), name.c_str()));
+       struct sr_channel *structure = (struct sr_channel *)
+                       g_slist_last(sr_dev_inst_channels_get(Device::_structure))->data;
+       Channel *channel = new Channel(structure);
+       _channels[structure] = channel;
+       return get_channel(structure);
 }
 
 Channel::Channel(struct sr_channel *structure) :
@@ -538,8 +705,7 @@ string Channel::name()
 
 void Channel::set_name(string name)
 {
-       check(sr_dev_channel_name_set(_parent->_structure,
-               _structure->index, name.c_str()));
+       check(sr_dev_channel_name_set(_structure, name.c_str()));
 }
 
 const ChannelType *Channel::type()
@@ -554,7 +720,7 @@ bool Channel::enabled()
 
 void Channel::set_enabled(bool value)
 {
-       check(sr_dev_channel_enable(_parent->_structure, _structure->index, value));
+       check(sr_dev_channel_enable(_structure, value));
 }
 
 unsigned int Channel::index()
@@ -565,7 +731,7 @@ unsigned int Channel::index()
 ChannelGroup::ChannelGroup(Device *device,
                struct sr_channel_group *structure) :
        ParentOwned(structure),
-       Configurable(device->_structure->driver, device->_structure, structure)
+       Configurable(sr_dev_inst_driver_get(device->_structure), device->_structure, structure)
 {
        for (GSList *entry = structure->channels; entry; entry = entry->next)
                _channels.push_back(device->_channels[(struct sr_channel *)entry->data]);
@@ -701,60 +867,11 @@ DatafeedCallbackData::DatafeedCallbackData(Session *session,
 void DatafeedCallbackData::run(const struct sr_dev_inst *sdi,
        const struct sr_datafeed_packet *pkt)
 {
-       auto device = _session->_devices[sdi];
+       auto device = _session->get_device(sdi);
        auto packet = shared_ptr<Packet>(new Packet(device, pkt), Packet::Deleter());
        _callback(device, packet);
 }
 
-SourceCallbackData::SourceCallbackData(shared_ptr<EventSource> source) :
-       _source(source)
-{
-}
-
-bool SourceCallbackData::run(int revents)
-{
-       return _source->_callback((Glib::IOCondition) revents);
-}
-
-shared_ptr<EventSource> EventSource::create(int fd, Glib::IOCondition events,
-       int timeout, SourceCallbackFunction callback)
-{
-       auto result = new EventSource(timeout, callback);
-       result->_type = EventSource::SOURCE_FD;
-       result->_fd = fd;
-       result->_events = events;
-       return shared_ptr<EventSource>(result, EventSource::Deleter());
-}
-
-shared_ptr<EventSource> EventSource::create(Glib::PollFD pollfd, int timeout,
-       SourceCallbackFunction callback)
-{
-       auto result = new EventSource(timeout, callback);
-       result->_type = EventSource::SOURCE_POLLFD;
-       result->_pollfd = pollfd;
-       return shared_ptr<EventSource>(result, EventSource::Deleter());
-}
-
-shared_ptr<EventSource> EventSource::create(Glib::RefPtr<Glib::IOChannel> channel,
-       Glib::IOCondition events, int timeout, SourceCallbackFunction callback)
-{
-       auto result = new EventSource(timeout, callback);
-       result->_type = EventSource::SOURCE_IOCHANNEL;
-       result->_channel = channel;
-       result->_events = events;
-       return shared_ptr<EventSource>(result, EventSource::Deleter());
-}
-
-EventSource::EventSource(int timeout, SourceCallbackFunction callback) :
-       _timeout(timeout),
-       _callback(callback)
-{
-}
-
-EventSource::~EventSource()
-{
-}
-
 SessionDevice::SessionDevice(struct sr_dev_inst *structure) :
        ParentOwned(structure),
        Device(structure)
@@ -772,27 +889,24 @@ shared_ptr<Device> SessionDevice::get_shared_from_this()
 
 Session::Session(shared_ptr<Context> context) :
        UserOwned(_structure),
-       _context(context),
-       _saving(false)
+       _context(context)
 {
-       check(sr_session_new(&_structure));
+       check(sr_session_new(context->_structure, &_structure));
        _context->_session = this;
 }
 
 Session::Session(shared_ptr<Context> context, string filename) :
        UserOwned(_structure),
        _context(context),
-       _saving(false)
+       _filename(filename)
 {
-       check(sr_session_load(filename.c_str(), &_structure));
+       check(sr_session_load(context->_structure, filename.c_str(), &_structure));
        GSList *dev_list;
        check(sr_session_dev_list(_structure, &dev_list));
        for (GSList *dev = dev_list; dev; dev = dev->next)
        {
                auto sdi = (struct sr_dev_inst *) dev->data;
-               auto device = new SessionDevice(sdi);
-               _devices[sdi] = shared_ptr<SessionDevice>(device,
-                       SessionDevice::Deleter());
+               _owned_devices[sdi] = new SessionDevice(sdi);
        }
        _context->_session = this;
 }
@@ -804,14 +918,25 @@ Session::~Session()
        for (auto callback : _datafeed_callbacks)
                delete callback;
 
-       for (auto entry : _source_callbacks)
+       for (auto entry : _owned_devices)
                delete entry.second;
 }
 
+shared_ptr<Device> Session::get_device(const struct sr_dev_inst *sdi)
+{
+       if (_owned_devices.count(sdi))
+               return static_pointer_cast<Device>(
+                       _owned_devices[sdi]->get_shared_pointer(this));
+       else if (_other_devices.count(sdi))
+               return _other_devices[sdi];
+       else
+               throw Error(SR_ERR_BUG);
+}
+
 void Session::add_device(shared_ptr<Device> device)
 {
        check(sr_session_dev_add(_structure, device->_structure));
-       _devices[device->_structure] = device;
+       _other_devices[device->_structure] = device;
 }
 
 vector<shared_ptr<Device>> Session::devices()
@@ -822,14 +947,14 @@ vector<shared_ptr<Device>> Session::devices()
        for (GSList *dev = dev_list; dev; dev = dev->next)
        {
                auto sdi = (struct sr_dev_inst *) dev->data;
-               result.push_back(_devices[sdi]);
+               result.push_back(get_device(sdi));
        }
        return result;
 }
 
 void Session::remove_devices()
 {
-       _devices.clear();
+       _other_devices.clear();
        check(sr_session_dev_remove_all(_structure));
 }
 
@@ -848,91 +973,29 @@ void Session::stop()
        check(sr_session_stop(_structure));
 }
 
-void Session::begin_save(string filename)
+bool Session::is_running() const
 {
-       _saving = true;
-       _save_initialized = false;
-       _save_filename = filename;
-       _save_samplerate = 0;
+       const int ret = sr_session_is_running(_structure);
+       if (ret < 0)
+               throw Error{ret};
+       return (ret != 0);
 }
 
-void Session::append(shared_ptr<Packet> packet)
+static void session_stopped_callback(void *data)
 {
-       if (!_saving)
-               throw Error(SR_ERR);
-
-       switch (packet->_structure->type)
-       {
-               case SR_DF_META:
-               {
-                       auto meta = (const struct sr_datafeed_meta *)
-                               packet->_structure->payload;
-
-                       for (auto l = meta->config; l; l = l->next)
-                       {
-                               auto config = (struct sr_config *) l->data;
-                               if (config->key == SR_CONF_SAMPLERATE)
-                                       _save_samplerate = g_variant_get_uint64(config->data);
-                       }
-
-                       break;
-               }
-               case SR_DF_LOGIC:
-               {
-                       if (_save_samplerate == 0)
-                       {
-                               GVariant *samplerate;
-
-                               check(sr_config_get(packet->_device->_structure->driver,
-                                       packet->_device->_structure, NULL, SR_CONF_SAMPLERATE,
-                                       &samplerate));
-
-                               _save_samplerate = g_variant_get_uint64(samplerate);
-
-                               g_variant_unref(samplerate);
-                       }
-
-                       if (!_save_initialized)
-                       {
-                               vector<shared_ptr<Channel>> save_channels;
-
-                               for (auto channel : packet->_device->channels())
-                                       if (channel->_structure->enabled &&
-                                                       channel->_structure->type == SR_CHANNEL_LOGIC)
-                                               save_channels.push_back(channel);
-
-                               auto channels = g_new(char *, save_channels.size());
-
-                               int i = 0;
-                               for (auto channel : save_channels)
-                                               channels[i++] = channel->_structure->name;
-                               channels[i] = NULL;
-
-                               int ret = sr_session_save_init(_structure, _save_filename.c_str(),
-                                               _save_samplerate, channels);
-
-                               g_free(channels);
-
-                               if (ret != SR_OK)
-                                       throw Error(ret);
-
-                               _save_initialized = true;
-                       }
-
-                       auto logic = (const struct sr_datafeed_logic *)
-                               packet->_structure->payload;
-
-                       check(sr_session_append(_structure, _save_filename.c_str(),
-                               (uint8_t *) logic->data, logic->unitsize,
-                               logic->length / logic->unitsize));
-               }
-       }
+       auto *const callback = static_cast<SessionStoppedCallback*>(data);
+       (*callback)();
 }
 
-void Session::append(void *data, size_t length, unsigned int unit_size)
+void Session::set_stopped_callback(SessionStoppedCallback callback)
 {
-       check(sr_session_append(_structure, _save_filename.c_str(),
-               (uint8_t *) data, unit_size, length));
+       _stopped_callback = move(callback);
+       if (_stopped_callback)
+               check(sr_session_stopped_callback_set(_structure,
+                               &session_stopped_callback, &_stopped_callback));
+       else
+               check(sr_session_stopped_callback_set(_structure,
+                               nullptr, nullptr));
 }
 
 static void datafeed_callback(const struct sr_dev_inst *sdi,
@@ -958,75 +1021,29 @@ void Session::remove_datafeed_callbacks(void)
        _datafeed_callbacks.clear();
 }
 
-static int source_callback(int fd, int revents, void *cb_data)
-{
-       (void) fd;
-       auto callback = (SourceCallbackData *) cb_data;
-       return callback->run(revents);
-}
-
-void Session::add_source(shared_ptr<EventSource> source)
+shared_ptr<Trigger> Session::trigger()
 {
-       if (_source_callbacks.count(source) == 1)
-               throw Error(SR_ERR_ARG);
-
-       auto cb_data = new SourceCallbackData(source);
-
-       switch (source->_type)
-       {
-               case EventSource::SOURCE_FD:
-                       check(sr_session_source_add(_structure, source->_fd, source->_events,
-                               source->_timeout, source_callback, cb_data));
-                       break;
-               case EventSource::SOURCE_POLLFD:
-                       check(sr_session_source_add_pollfd(_structure,
-                               source->_pollfd.gobj(), source->_timeout, source_callback,
-                               cb_data));
-                       break;
-               case EventSource::SOURCE_IOCHANNEL:
-                       check(sr_session_source_add_channel(_structure,
-                               source->_channel->gobj(), source->_events, source->_timeout,
-                               source_callback, cb_data));
-                       break;
-       }
-
-       _source_callbacks[source] = cb_data;
+       return _trigger;
 }
 
-void Session::remove_source(shared_ptr<EventSource> source)
+void Session::set_trigger(shared_ptr<Trigger> trigger)
 {
-       if (_source_callbacks.count(source) == 0)
-               throw Error(SR_ERR_ARG);
-
-       switch (source->_type)
-       {
-               case EventSource::SOURCE_FD:
-                       check(sr_session_source_remove(_structure, source->_fd));
-                       break;
-               case EventSource::SOURCE_POLLFD:
-                       check(sr_session_source_remove_pollfd(_structure,
-                               source->_pollfd.gobj()));
-                       break;
-               case EventSource::SOURCE_IOCHANNEL:
-                       check(sr_session_source_remove_channel(_structure,
-                               source->_channel->gobj()));
-                       break;
-       }
-
-       delete _source_callbacks[source];
-
-       _source_callbacks.erase(source);
+       if (!trigger)
+               // Set NULL trigger, i.e. remove any trigger from the session.
+               check(sr_session_trigger_set(_structure, NULL));
+       else
+               check(sr_session_trigger_set(_structure, trigger->_structure));
+       _trigger = trigger;
 }
 
-shared_ptr<Trigger> Session::trigger()
+string Session::filename()
 {
-       return _trigger;
+       return _filename;
 }
 
-void Session::set_trigger(shared_ptr<Trigger> trigger)
+shared_ptr<Context> Session::context()
 {
-       check(sr_session_trigger_set(_structure, trigger->_structure));
-       _trigger = trigger;
+       return _context;
 }
 
 Packet::Packet(shared_ptr<Device> device,
@@ -1051,9 +1068,9 @@ Packet::Packet(shared_ptr<Device> device,
                                static_cast<const struct sr_datafeed_logic *>(
                                        structure->payload));
                        break;
-               case SR_DF_ANALOG:
-                       _payload = new Analog(
-                               static_cast<const struct sr_datafeed_analog *>(
+               case SR_DF_ANALOG_OLD:
+                       _payload = new AnalogOld(
+                               static_cast<const struct sr_datafeed_analog_old *>(
                                        structure->payload));
                        break;
                default:
@@ -1175,33 +1192,33 @@ unsigned int Logic::unit_size()
        return _structure->unitsize;
 }
 
-Analog::Analog(const struct sr_datafeed_analog *structure) :
+AnalogOld::AnalogOld(const struct sr_datafeed_analog_old *structure) :
        ParentOwned(structure),
        PacketPayload()
 {
 }
 
-Analog::~Analog()
+AnalogOld::~AnalogOld()
 {
 }
 
-shared_ptr<PacketPayload> Analog::get_shared_pointer(Packet *_parent)
+shared_ptr<PacketPayload> AnalogOld::get_shared_pointer(Packet *_parent)
 {
        return static_pointer_cast<PacketPayload>(
                ParentOwned::get_shared_pointer(_parent));
 }
 
-float *Analog::data_pointer()
+float *AnalogOld::data_pointer()
 {
        return _structure->data;
 }
 
-unsigned int Analog::num_samples()
+unsigned int AnalogOld::num_samples()
 {
        return _structure->num_samples;
 }
 
-vector<shared_ptr<Channel>> Analog::channels()
+vector<shared_ptr<Channel>> AnalogOld::channels()
 {
        vector<shared_ptr<Channel>> result;
        for (auto l = _structure->channels; l; l = l->next)
@@ -1210,17 +1227,17 @@ vector<shared_ptr<Channel>> Analog::channels()
        return result;
 }
 
-const Quantity *Analog::mq()
+const Quantity *AnalogOld::mq()
 {
        return Quantity::get(_structure->mq);
 }
 
-const Unit *Analog::unit()
+const Unit *AnalogOld::unit()
 {
        return Unit::get(_structure->unit);
 }
 
-vector<const QuantityFlag *> Analog::mq_flags()
+vector<const QuantityFlag *> AnalogOld::mq_flags()
 {
        return QuantityFlag::flags_from_mask(_structure->mqflags);
 }
@@ -1244,15 +1261,27 @@ string InputFormat::description()
        return valid_string(sr_input_description_get(_structure));
 }
 
+vector<string> InputFormat::extensions()
+{
+       vector<string> exts;
+       for (const char *const *e = sr_input_extensions_get(_structure);
+               e && *e; e++)
+               exts.push_back(*e);
+       return exts;
+}
+
 map<string, shared_ptr<Option>> InputFormat::options()
 {
        const struct sr_option **options = sr_input_options_get(_structure);
-       auto option_array = shared_ptr<const struct sr_option *>(
-               options, sr_input_options_free);
        map<string, shared_ptr<Option>> result;
-       for (int i = 0; options[i]; i++)
-               result[options[i]->id] = shared_ptr<Option>(
-                       new Option(options[i], option_array), Option::Deleter());
+       if (options)
+       {
+               auto option_array = shared_ptr<const struct sr_option *>(
+                       options, sr_input_options_free);
+               for (int i = 0; options[i]; i++)
+                       result[options[i]->id] = shared_ptr<Option>(
+                               new Option(options[i], option_array), Option::Deleter());
+       }
        return result;
 }
 
@@ -1286,19 +1315,24 @@ shared_ptr<InputDevice> Input::device()
        return _device->get_shared_pointer(shared_from_this());
 }
 
-void Input::send(string data)
+void Input::send(void *data, size_t length)
 {
-       auto gstr = g_string_new(data.c_str());
+       auto gstr = g_string_new_len((gchar *)data, length);
        auto ret = sr_input_send(_structure, gstr);
        g_string_free(gstr, false);
        check(ret);
 }
 
+void Input::end()
+{
+       check(sr_input_end(_structure));
+}
+
 Input::~Input()
 {
        if (_device)
                delete _device;
-       check(sr_input_free(_structure));
+       sr_input_free(_structure);
 }
 
 InputDevice::InputDevice(shared_ptr<Input> input,
@@ -1376,15 +1410,27 @@ string OutputFormat::description()
        return valid_string(sr_output_description_get(_structure));
 }
 
+vector<string> OutputFormat::extensions()
+{
+       vector<string> exts;
+       for (const char *const *e = sr_output_extensions_get(_structure);
+               e && *e; e++)
+               exts.push_back(*e);
+       return exts;
+}
+
 map<string, shared_ptr<Option>> OutputFormat::options()
 {
        const struct sr_option **options = sr_output_options_get(_structure);
-       auto option_array = shared_ptr<const struct sr_option *>(
-               options, sr_output_options_free);
        map<string, shared_ptr<Option>> result;
-       for (int i = 0; options[i]; i++)
-               result[options[i]->id] = shared_ptr<Option>(
-                       new Option(options[i], option_array), Option::Deleter());
+       if (options)
+       {
+               auto option_array = shared_ptr<const struct sr_option *>(
+                       options, sr_output_options_free);
+               for (int i = 0; options[i]; i++)
+                       result[options[i]->id] = shared_ptr<Option>(
+                               new Option(options[i], option_array), Option::Deleter());
+       }
        return result;
 }
 
@@ -1396,10 +1442,33 @@ shared_ptr<Output> OutputFormat::create_output(
                Output::Deleter());
 }
 
+shared_ptr<Output> OutputFormat::create_output(string filename,
+       shared_ptr<Device> device, map<string, Glib::VariantBase> options)
+{
+       return shared_ptr<Output>(
+               new Output(filename, shared_from_this(), device, options),
+               Output::Deleter());
+}
+
+bool OutputFormat::test_flag(const OutputFlag *flag)
+{
+       return sr_output_test_flag(_structure, flag->id());
+}
+
 Output::Output(shared_ptr<OutputFormat> format,
                shared_ptr<Device> device, map<string, Glib::VariantBase> options) :
        UserOwned(sr_output_new(format->_structure,
-               map_to_hash_variant(options), device->_structure)),
+               map_to_hash_variant(options), device->_structure, NULL)),
+       _format(format),
+       _device(device),
+       _options(options)
+{
+}
+
+Output::Output(string filename, shared_ptr<OutputFormat> format,
+               shared_ptr<Device> device, map<string, Glib::VariantBase> options) :
+       UserOwned(sr_output_new(format->_structure,
+               map_to_hash_variant(options), device->_structure, filename.c_str())),
        _format(format),
        _device(device),
        _options(options)
@@ -1427,6 +1496,6 @@ string Output::receive(shared_ptr<Packet> packet)
        }
 }
 
-#include "enums.cpp"
+#include <enums.cpp>
 
 }