User-defined data types

306 views
Skip to first unread message

Nick Burkitt

unread,
Oct 19, 2016, 4:44:29 PM10/19/16
to Dbus-cxx
Hi.

I'm using dbus-cxx in a project for work. I haven't been able to find any documentation or discussion on how to use it to transmit user-defined data types (i.e. structs). Obviously dbus supports this, and the Signature and MessageIterator classes hint at how it's supposed to be done, but a simple explanation and/or example would be invaluable.

Here's what I want to do:

struct MyData
{
int first_member;
int second_member;
std::vector< double > third_member;
};

DBus::Object::pointer dbus_object = MyDBus::Instance().getConnection()->create_object( OBJECT_PATH);
DBus::Interface::pointer dbus_interface = dbus_object ->create_interface( INTERFACE_NAME );
DBus::signal< void, MyData >::pointer dbus_signal = dbus_interface ->create_signal< void, MyData >( SIGNAL_NAME );

MyData my_data = get_data();
dbus_signal ->emit( my_data );

Presumably MyData needs to implement a method to return a DBus::Signature, and also must be able to supply a DBus::MessageIterator that iterates over the members of MyData.

Any and all hints will be welcome.
Thanks,

-Nick

Robert Middleton

unread,
Oct 19, 2016, 7:22:34 PM10/19/16
to Nick Burkitt, Dbus-cxx
(forgot to reply all to also send to the group, sorry about the duplicates)

Is this being sent as a DBus 'struct' type at all?  The reason I ask is because the signature is going to be different depending on what type of data you have.  I'm going to assume that your data is being sent as a DBus struct for the purposes of this example.

Also, this is going mostly off of memory, so this will almost certainly not work as written, as it has been a long time since I have worked extensively with the library.  Some example code may be useful under examples/basics/types

The first thing that we have to do is to define a signature() method that will give out the right string for the DBus library to parse.  This string is sent along with the message so that the other side of the DBus connection knows how to parse the data.

So our signature() method will look something like the following:

namespace DBus{
  inline std::string signature( struct MyData data ){ 
      return "(" + 
            signature( data.first_member ) + 
            signature( data.second_member ) + 
            signature( data.third_member ) +
            ")";
}

(You could probably just hard-code this value as well, since it won't change.  The signature won't change as long as your struct doesn't change.) If I'm reading your code right and remembering the signature correctly, your signature should be (iiad).

Now that we have our signature() method, we need to define how to pull stuff out of the message when receiving a message and how to encode it onto the bus when sending.  The implementation for that will look something like the following:

DBus::MessageIterator& operator>>(DBus::MessageIterator& i, struct MyData& data ){
    data.first_member = i.get_int32();
    i.next();
    data.second_member = i.get_int32();
    i.next();
    data.third_member = i.get_array_simple();
    i.next();
}

DBus::MessageAppendIterator& operator<<(DBus::MessageAppendIterator& i, const struct MyData& data)
{
  i.append( data.first_member );
  i.append( data.second_member );
  i.append( data.third_member );
  return i;
}

Alternatively, if you're not sending the data as a DBus struct type, you can simply make your signal look like the following:

DBus::signal< void, MyData >::pointer dbus_signal = dbus_interface ->create_signal< void, int, int, std::vector<double> >( SIGNAL_NAME );

-Robert Middleton

--
You received this message because you are subscribed to the Google Groups "Dbus-cxx" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dbus-cxx+unsubscribe@googlegroups.com.
To post to this group, send email to dbus...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/dbus-cxx/b5c8b984-4f2f-4355-9a90-d7ae29f4c9fc%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Nick Burkitt

unread,
Oct 20, 2016, 2:32:08 PM10/20/16
to Dbus-cxx
Hi Robert.

Thanks - that is exactly what I was looking for! And the clearest explanation I've read in a long while. It's almost anticlimactic, given how long I've been looking for an answer to this question. :-)
Thanks again,

-Nick
To unsubscribe from this group and stop receiving emails from it, send an email to dbus-cxx+u...@googlegroups.com.
Message has been deleted

noj...@gmail.com

unread,
Jan 29, 2018, 11:05:45 PM1/29/18
to Dbus-cxx
Hi Nick, Robert,

Were you able to make this work? I'm getting 'std::shared_ptr<DBus::ErrorInvalidTypecast>' when I run:

DBus::ObjectProxy::pointer object = connection->create_object_proxy(DESTINATION, PATH);
DBus::MethodProxy<struct MyData> &getData = *(object->create_method<struct MyData>(NAME, METHOD));
struct MyData dataResult;
dataResult = getData();

Thanks in advance for the help!

Nick Burkitt

unread,
Jan 30, 2018, 1:06:59 PM1/30/18
to Dbus-cxx
Hi nojose.

The key(s) to user-defined data types is to define your type's DBus signature:
struct MyData
{
    static constexpr const char* DBUS_SIGNATURE = "(i)";
    int data;
}

Define a DBus::signature(MyData) method in the DBUS namespace:
namespace DBUS
{
    inline std::string signature(const MyData& data)
    {
        return MyData::DBUS_SIGNATURE;
    }
}

and insertion and extraction operators in the DBUS namespace:
DBus::MessageAppendIterator& operator<<(DBus::MessageAppendIterator& miIterator, const MyData& data);
DBus::MessageIterator& operator>>(DBus::MessageIterator& miIterator, MyData& data);

The order in which things are seen by the compiler is critical, too. If you've already done all of the above, that may be the problem. Let me know - I'll show you the hoops I had to jump through to get that part right.

-Nick

Jose

unread,
Jan 30, 2018, 2:16:26 PM1/30/18
to Dbus-cxx
Hi Nick,

Thanks for the promptly reply. In fact, for the demo client/server I was testing, the order of the includes was an issue. However the service that I need to communicate with is actually returning a "struct" and for that the 'std::shared_ptr<DBus::ErrorInvalidTypecast>' is being thrown. This is the output I get in the console when I call the service using dbus-send

dbus-send --system --print-reply --dest=DESTINATION PATH OBJECT_METHOD
method return time=1517336387.925653 sender=:1.23 -> destination=:1.39 serial=1605 reply_serial=2
   struct {
      int32 1
      int32 2
   }

This might not be related to user-defined data types and I got confused between that and structs. I did look into the messageappenditerator.h and realized the append methods are commented for the CONTAINER_STRUCT type. Does this mean structs are not supported in dbus-cxx? Any hint if/how I could make this work?

Thanks again!
-Jose

Nick Burkitt

unread,
Jan 30, 2018, 3:28:51 PM1/30/18
to Dbus-cxx
Hi Jose.

I believe a DBus struct is simply an arbitrary collection of types represented by the signature "(xyz)", where x, y, and z are the types of the members of the collection. The "struct" part is shown by the enclosing parentheses.
That is supported by dbus-cxx. You just need to define the methods that read (extract) and write (insert) the members of the collection.
So your client has to provide the method for extracting the struct's members from the dbus reply. That's the job of the extraction operator. If your struct looks like this:

struct MyData
{
    int first;
    int second
};

This would be represented by the DBus signature "(ii)".

then your extraction operator would look something like this:

namespace DBus
{
    MessageIterator& operator>>(DBus::MessageIterator& iterator, MyData& data)
    {
        data.first = iterator.get_int32();
        iterator.next();
        data.second = iterator.get_int32();
        iterator.next();
        return iterator;
    }
}

Otherwise, when you create a dbus-cxx method that returns a MyData object and the compiler can't find an extraction operator that accepts a MyData& argument, it won't know what to do.

Does that help at all?

-Nick

Robert Middleton

unread,
Jan 30, 2018, 4:21:07 PM1/30/18
to Nick Burkitt, Dbus-cxx
Check out the code in messageappenditerator.h:
https://sourceforge.net/p/dbus-cxx/code/HEAD/tree/trunk/dbus-cxx/dbus-cxx/messageappenditerator.h#l145

It's commented out, but that is the basic idea of what you have to do
with the struct, in addition to what Nick said. Since a struct is a
container, you need to open the container first, then put everything
into it. Conversely, when you're extracting from the message, you
also need to open the container and extract the data from it:
https://sourceforge.net/p/dbus-cxx/code/HEAD/tree/trunk/dbus-cxx/dbus-cxx/messageiterator.h#l127

Also check out the example for defining your own custom type(which is
convenient in that it defines a struct with two int32 elements in it):
https://sourceforge.net/p/dbus-cxx/code/HEAD/tree/trunk/dbus-cxx/examples/basics/types/

-Robert Middleton
> https://groups.google.com/d/msgid/dbus-cxx/23df8763-5192-4b37-9bb0-9b4b04275b66%40googlegroups.com.

Robert Middleton

unread,
Jan 30, 2018, 4:23:44 PM1/30/18
to Nick Burkitt, Dbus-cxx
Clarification on the last point: the struct has two elements in it,
but they are not packaged in a DBus struct. You have to open/close
the container when you are reading/writing.

-Robert Middleton

noj...@gmail.com

unread,
Feb 10, 2018, 2:00:51 PM2/10/18
to Dbus-cxx
Thanks again to both of you for the help. In case anyone faces this issue, this is how it worked (I only needed the "extraction" method so that's what I'm copying here):

The dbus returns a struct with two double:

dbus-send --system --print-reply --dest=DESTINATION PATH OBJECT_METHOD
method return time=1517336387.925653 sender=:1.23 -> destination=:1.39 serial=1605 reply_serial=2
   struct {
      double 1.0
      double 2.0
   }

I created a struct named "Reading" with the signature "(dd)":

struct Reading
{
    static constexpr const char* DBUS_SIGNATURE = "(dd)";
    double timestamp;
    double value;
};

In the extraction operator I'm opening the container and extracting the data from it:

DBus::MessageIterator &operator>>(DBus::MessageIterator &i, struct Reading &t) {
    DBus::MessageIterator subiter = i.recurse();
    t.timestamp = subiter.get_double();
    subiter.next();
    t.value = subiter.get_double();
    subiter.next();
    i.next()
    return i;
}

-Jose

Kimmy Posey

unread,
Mar 7, 2018, 10:03:49 AM3/7/18
to Dbus-cxx
Nick/Robert/Jose

I followed this discussion and it was very helpful when I was working with a struct containing a handful of doubles and a string.  However, when I tried to add an array I had issues.  In my header:

#include <string>

typedef struct _msgUpdate
{
  static constexpr const char* DBUS_SIGNATURE = "(ad)";
  double   data[255];
} msgUpdate_t;

namespace DBus
{
    inline std::string signature(msgUpdate_t) {return msgUpdate_t::DBUS_SIGNATURE;}
}

#include <dbus-cxx.h>

DBus::MessageIterator &operator>>(DBus::MessageIterator& i, msgUpdate_t& m);
DBus::MessageAppendIterator& operator<<(DBus::MessageAppendIterator& i, const msgUpdate_t& m);


Then in my implementation (extractor only for brevity):

namespace DBus
{
  DBus::MessageIterator &operator>>(DBus::MessageIterator& i, msgUpdate_t& m)
  {
    m.data = i.get_array_simple(); <- error: no matching function for call to 'DBus::MessageIterator::get_array_simple()
                                                         note:   template argument deduction/substitution failed
                                                         
    return i;
  }
}

The compiler can't figure out the template argument for get_array_simple. I must be missing an include or something? Something in the wrong order?

Any clue would be hugely appreciated.  I'm sure I will feel foolish when I see it ...

Thx - Dallas

Nick Burkitt

unread,
Mar 7, 2018, 12:54:32 PM3/7/18
to Kimmy Posey, Dbus-cxx
Hi Kimmy.

get_array_simple is a templated function, so you'll need to specify the type it's supposed to work on:

i.get_array_simple< double >();

-Nick


-Nick

--
You received this message because you are subscribed to a topic in the Google Groups "Dbus-cxx" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/dbus-cxx/AxLXh8AyIj0/unsubscribe.
To unsubscribe from this group and all its topics, send an email to dbus-cxx+unsubscribe@googlegroups.com.

To post to this group, send email to dbus...@googlegroups.com.

Nick Burkitt

unread,
Mar 7, 2018, 1:25:48 PM3/7/18
to Kimmy Posey, Dbus-cxx
Hi Kimmy.

Quitting and going to bed is one of my favorite programming techniques. :-) And one of the most effective.
Happy I was able to help.

-Nick

-------- Original Message --------
Subject: Re: [dbus-cxx] Re: User-defined data types
From: Kimmy Posey <xthunde...@gmail.com>
Date: Wed, March 07, 2018 10:02 am
To: Nick Burkitt <ni...@burkitt.net>

Thanx Nick! I knew that was the problem, but I must have tried some zany syntax and when it failed I gave up too quickly. I really need to sleep ... I'm going cross-eyed

Kimmy Posey

unread,
Mar 7, 2018, 2:20:49 PM3/7/18
to Dbus-cxx
I spoke too soon. Barfs at link time.  Dood do you have a working example I could look at? I'm ready to scream at this point ...


-Nick

To unsubscribe from this group and all its topics, send an email to dbus-cxx+u...@googlegroups.com.
Message has been deleted

Jose Dunia

unread,
Mar 7, 2018, 2:51:21 PM3/7/18
to Kimmy Posey, Dbus-cxx
Kimmy,

Check the messageiterator.h header file, it helped me in general to understand better the different operations and data types. I believe that if you make the signature to be "(a)" and make the 'data' a std::vector<double> instead of an array, that could make the trick. Also, in my case I needed to open the container as Robert suggested (DBus::MessageIterator subiter = i.recurse();)

Hope that helps.
Best,
Jose

To unsubscribe from this group and all its topics, send an email to dbus-cxx+unsubscribe@googlegroups.com.

To post to this group, send email to dbus...@googlegroups.com.

Robert Middleton

unread,
Mar 7, 2018, 6:20:11 PM3/7/18
to Jose Dunia, Kimmy Posey, Dbus-cxx
If you put the code that you're having trouble with on a github repo
or a gist, I think it will be easier to take a look at.

Note that you may also be able to use
MessageIterator::get_array_simple( vector<double>& array ). If I
remember correctly the library doesn't have support for raw arrays; it
uses std::vector instead of a raw array.

-Robert
> --
> You received this message because you are subscribed to the Google Groups
> "Dbus-cxx" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to dbus-cxx+u...@googlegroups.com.
> To post to this group, send email to dbus...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/dbus-cxx/CAJpWk4rSXGhAFwauRBOdhcRW-%2BsJgvvCUzifLoLKUtaPhTg%2B4Q%40mail.gmail.com.

Kimmy Posey

unread,
Mar 8, 2018, 12:41:16 PM3/8/18
to Dbus-cxx
Robert et. al.

Thx for all of your responses.  I think I have it worked out now.  After I got the placement of my headers right and changed the link order of libdbus all seems right.  It was a bit frustrating, but after reading the responses here and taking Nick's (and my own) advice and employing that time-honored programming technique of a good night's sleep, I think I'm on track.

This work is for an embedded project that takes data from a number of external interfaces and yakks them to dbus where other processes consume the data.  It's based on a Yocto build and since there were no official recipes for dbus-cxx, I kind of adopted it.

I noticed that a new version was pushed to the SVN repo just recently, so that indicates that the code is under active development.  Is that true?  I sent an email to Rick asking if he would mind me cloning the code into git and making it available to the Yocto community but got no response.  So I forked it anyway.

Is Rick the sole contributor?

Anyway, I'm gonna post a detailed description here of my little adventure with User Defined Types as I have a number of less trivial examples I need to work up.  Maybe it will be useful to others down the road.

-Dallas

Nick Burkitt

unread,
Mar 8, 2018, 1:54:07 PM3/8/18
to Kimmy Posey, Dbus-cxx
The order in which the compiler see things, and therefore the order of header files is critical, and finicky. My project is very similar to what you describe, and I had to jump through many hoops to make it all work. Robert will have better information about the library's history, but from what I can gather, Rick has fallen off the face of the earth - this may have been a school project at some point, and Robert has assumed the mantle of maintainer. He's done a good job at addressing problems and providing support.
--
Sent from my Android device with K-9 Mail. Please excuse my brevity.

Robert Middleton

unread,
Mar 8, 2018, 5:10:46 PM3/8/18
to Nick Burkitt, Kimmy Posey, Dbus-cxx
To expand on Nick's points, the library is /very/ finicky when it
comes to the header includes and in what order they are used in. I did
put a bit of explanation in time_server.cpp when I was creating this
example: https://sourceforge.net/p/dbus-cxx/code/HEAD/tree/trunk/dbus-cxx/examples/basics/types/time_server.cpp#l20

As for how exactly it started, I am not sure if it was a school project or not.

How I got involved with it was that I was using the library for some
programs(the thought at the time was that it was better-maintained
than dbus-cpp). In the course of using the library, we found(and
fixed) several bugs with the implementation, which I eventually
emailed Rick about(as he was still on the mailing list at that point
if I remember correctly), but he indicated that he was not interested
in maintaining it anymore. He did give me access to the SF repo
though, so I do work on it from time to time(on the rigorous
whenever-I-feel-like-it schedule), or if bugs come up.

At this point however, the actual library implementation seems to be
pretty solid, with the initial patches that I did and the other
testing work that Nick has done. There are a few things that I would
like to do, but unless there's a big push I generally don't do too
much.

This seems to be Rick's website: http://www.rvinyard.com/index.html

-Robert Middleton
> https://groups.google.com/d/msgid/dbus-cxx/09C642AD-A1E3-4FDA-8F61-A9B7AA8F11B7%40gmail.com.

Kimmy Posey

unread,
Mar 10, 2018, 11:20:42 AM3/10/18
to Dbus-cxx
Thanx for the information Robert.  So bottom line is that you are the Maintainer currently (as you have bandwidth). Cool.

I almost have this working for our project but hit a run-time snag I'm hoping one of you guys will have insight into.  I put my test code here:


along with a Call Stack when the error occurs.  The emitter/collector are based on example code from the repo (emitter/receiver version _2).  If you look at myData.cpp you'll see that I first tried a solution based on your original response to Nick.  That resulted a problem similar to what Jose came back with:

root@ccimx6ulsbc:~# ./signalCollector 
Running.terminate called after throwing an instance of 'std::shared_ptr<DBus::ErrorInvalidTypecast>'
Aborted

So I then tried something based on what Jose suggested worked in his case (the section that isn't commented).  That unfortunately resulted in a segfault in the collector because i.recure() returns NULL and of course I'm not checking for that in this example.

So I'm emitting the signal, the signal arrives and then the library sees it and wants to put it in my struct for delivery to the handler. But my extract operator is still wonky.  I'm sure I'm just missing something simple again but clues would be massively appreciated. I know this is time consuming to look at, but I do think it would be useful to others in a similar circumstances down the road.

Thx - Dallas

Jose Dunia

unread,
Mar 10, 2018, 12:31:28 PM3/10/18
to Kimmy Posey, Dbus-cxx
Hi,

In my example I was writing a consumer so I needed only the extraction operator. For the insertion I believe you'll need to wrap the elements you are appending inside a container. In the messageappenditerator.h you can find this idea commented out:

//this->open_container( CONTAINER_STRUCT, std::string() );
...
//m_subiter->append( boost::get<0>(s) );
...
//this->close_container();

So in your code probably there is something on those lines that needs to be done. Probably Robert will have a better insight into this.

DBus::MessageAppendIterator& operator<<(DBus::MessageAppendIterator& i, const struct _myData& f)
{
  // OPEN CONTAINER
  i.append((uint8_t)f.octet);
  i.append((uint32_t)f.dword);
  i.append((std::string)f.deviceName);
  // CLOSE CONTAINER
  return i;
}

Let us know how it goes!

Best,
Jose


To unsubscribe from this group and all its topics, send an email to dbus-cxx+unsubscribe@googlegroups.com.

To post to this group, send email to dbus...@googlegroups.com.

Robert Middleton

unread,
Mar 10, 2018, 2:10:41 PM3/10/18
to Jose Dunia, Kimmy Posey, Dbus-cxx
Okay, I have it figured out(this took longer than I was expecting).

So, there were two problems here:

1. The insertion operator did not open up the struct container at all.
If you run `dbus-monitor --system`, you will see what signals are
being emitted. Example without opening the container:

signal sender=:1.134 -> dest=(null destination) serial=4
path=/test/signal/Object; interface=test.signal.Type; member=Test
byte 128
uint32 65535
string "Hogwaller"

Example with opening the container:

signal sender=:1.133 -> dest=(null destination) serial=2
path=/test/signal/Object; interface=test.signal.Type; member=Test
struct {
byte 128
uint32 65535
string "Hogwaller"
}

2. Because you created your signal using a templated method(
connection->create_signal<void, struct _myData>() ), you don't need to
take in the DBus::SignalMessage::const_pointer, the library handles
that for you. All that is needed in that case is to define a function
that has a signature that matches the message that you want to
receive. That's why you were getting a segfault as well, as it was
trying to extract data improperly. Unfortunately, I don't think that
there's anything that I can do in order to force correct library usage
in this case. :(.

I put the fixed code in my repo of test programs, under the
signal_handler directory: https://github.com/rm5248/dbus-cxx-testprogs

-Robert Middleton
> --
> You received this message because you are subscribed to the Google Groups
> "Dbus-cxx" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to dbus-cxx+u...@googlegroups.com.
> To post to this group, send email to dbus...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/dbus-cxx/CAJpWk4rA21JJ%2BU_JAWRZ2BTxOuUBMOP%2BLO4-YzqhcqTw0Y%2B3Ng%40mail.gmail.com.

Kimmy Posey

unread,
Mar 10, 2018, 4:36:26 PM3/10/18
to Dbus-cxx
Jose/Robert,

Thank you both *so much*! Jose had me on the right track and I was trying to work out the semantics of open_container when Robert's email arrived.  I would have been hours working it out (what can I say ... I'm slow) and likely would have gotten lost on the way.

I had noticed that the signal output in dbus-monitor didn't look like others on the bus so I knew something was amiss on the emitter end with that.  In any event, many, many thanks.  If either of you are ever in RTP or environs, you got my marker for lunch/dinner.  I know every Carolina BBQ joint in these parts so I'll hook you up with some prime pig and a mug or 2 of tasty ale if you like that sort of thing.

One other question that occurs to me is, if you have nested structures, do you have to "open" the inner container object as well?  I assume that would be the case. And also I guess you'd need an additional call to recurse() in the extraction method immediately before access to the sub-fields?

Again, thank you both *very* much,

-Dallas

Robert Middleton

unread,
Mar 10, 2018, 8:03:19 PM3/10/18
to Kimmy Posey, Dbus-cxx
That's correct. Whenever you have nested structures, each nesting
must do the MessageIterator::recurse() on the returned iterator. So
if you have 3 structs nested inside each other, you could potentially
have a call like the following:

DBus::MessageAppendIterator& operator<<(DBus::MessageAppendIterator&
i, datatype d )
{
i.open_container( DBus::CONTAINER_STRUCT, "" );
i.sub_iterator()->open_container( DBus::CONTAINER_STRUCT, "" );
i.sub_iterator()->sub_iterator()->open_container( DBus::CONTAINER_STRUCT, "" );
i.sub_iterator()->sub_iterator()->close_container();
i.sub_iterator()->close_container();
i.close_container();
return i;
}

DBus::MessageIterator &operator>>(DBus::MessageIterator& i, datatype d)
{
DBus::MessageIterator subiter = i.recurse();
DBus::MessageIterator subiter2 = subiter.recurse();
DBus::MessageIterator subiter3 = subiter2.recurse();
return i;
}

(at least, I'm pretty sure that's the case; I haven't had to do that before).

What would probably make more sense in that case is to simply define
each sub-type with its own insertion/extraction operator. So instead
of doing the recurse() 3 times, you have 3 separate structs each with
their own operator<< and operator>>, since that should go and
automatically call the proper insertion/extraction.

-Robert Middleton
> https://groups.google.com/d/msgid/dbus-cxx/4398dc28-9939-4231-b543-47a132802717%40googlegroups.com.

Kimmy Posey

unread,
Mar 14, 2018, 9:34:44 AM3/14/18
to Dbus-cxx
One last variation that you I need to handle is when complex data is signalled but *not* encapsulated in a container, much like my example that you corrected.  An example of this can be found in gpsd.  I don't have the target hardware here with me but I know for certain that it generates signals that look like this contrived example which I generated with a broken custom data type:

signal time=1521033985.059779 sender=:1.91 -> destination=(null destination) serial=4 path=/org/gpsd; interface=org.gpsd; member=fix
   double 1
   int32 2
   double 3
   double 4
   double 5
   double 6
   double 7
   double 8
   double 9
   double 10
   double 11
   double 12
   double 13
   double 14
   string "FAKEGPS!"

So would I have to read these parameters from the message in a manner similar to that in signal_receiver_raw.cpp?  Man this is hard to get my head around ...

Thx - Dallas

Robert Middleton

unread,
Mar 14, 2018, 6:42:33 PM3/14/18
to Kimmy Posey, Dbus-cxx
Yes - but only in this specific case. That's because dbus-cxx uses
libsigc++, which only has a maximum of 7 templated function
parameters. So if the signal/method has up to 7 parameters, you can
do something like this:

DBus::signal_proxy<void, double, int, double, double, double, double,
double, double >::pointer signal =
connection->create_signal_proxy<void, double, int, double, double,
double, double, double, double >("/org/gpsd", "org.gpsd", "fix");

void handle_signal( double param1, int param2, double param3, double
param4, double param5, double param6, double param 7){}

In the case that you posted, that particular signal has more than 7
parameters, so you can't use the templated function. The work around
for this case is to define your own custom type that reads in the 15
arguments for the signal and calls the specific function/callback that
you want to use. It's the same as what we were doing with the custom
type, you just don't have to open or close the container when you are
using the operator<</operator>>.

-Robert Middleton
> https://groups.google.com/d/msgid/dbus-cxx/0ef261ea-adfd-4af8-82b8-28da355a4ece%40googlegroups.com.

Kimmy Posey

unread,
Mar 14, 2018, 10:26:05 PM3/14/18
to Dbus-cxx
Got it. I created a custom data type as follows and it worked great.  Again thx for your help and maybe somebody else will benefit from this thread down the road.

- Dallas

gpsRaw.h

#ifndef GPSRAW_H
#define GPSRAW_H

#include <string>

typedef struct _gpsRaw
{
  static constexpr const char* DBUS_SIGNATURE = "(didddddddddddds)";
  double    time;
  int32_t   mode;
  double    TDOP;
  double    latitude;
  double    longitude;
  double    HDOP;
  double    altitude;
  double    ADOP;
  double    course;
  double    CDOP;
  double    speed;
  double    SDOP;
  double    climb;
  double    CLDOP;
  std::string    deviceName;
} gpsRaw_t;

namespace DBus
{
  inline std::string signature(gpsRaw_t) {return gpsRaw_t::DBUS_SIGNATURE;}
}
 
#include <dbus-cxx.h>

DBus::MessageIterator &operator>>(DBus::MessageIterator& i, gpsRaw_t& f);
DBus::MessageAppendIterator& operator<<(DBus::MessageAppendIterator& i, const gpsRaw_t& f);

#endif // GPSRAW_H

with an implementation like this:

gpsRaw.cpp

#include <inc/gpsRaw.h>

DBus::MessageIterator &operator>>(DBus::MessageIterator& i, gpsRaw_t& f)
{
  i >> f.time;
  i >> f.mode;
  i >> f.TDOP;
  i >> f.latitude;
  i >> f.longitude;
  i >> f.HDOP;
  i >> f.altitude;
  i >> f.ADOP;
  i >> f.course;
  i >> f.CDOP;
  i >> f.speed;
  i >> f.SDOP;
  i >> f.climb;
  i >> f.CLDOP;
  i >> f.deviceName;

  return i;
}

DBus::MessageAppendIterator& operator<<(DBus::MessageAppendIterator& i, const gpsRaw_t& f)
{
  i.append((double)f.time);
  i.append((int32_t)f.mode);
  i.append((double)f.TDOP);
  i.append((double)f.latitude);
  i.append((double)f.longitude);
  i.append((double)f.HDOP);
  i.append((double)f.altitude);
  i.append((double)f.ADOP);
  i.append((double)f.course);
  i.append((double)f.CDOP);
  i.append((double)f.speed);
  i.append((double)f.SDOP);
  i.append((double)f.climb);
  i.append((double)f.CLDOP);
  i.append((std::string)f.deviceName);

  return i;

Kimmy Posey

unread,
Jul 9, 2019, 2:49:52 PM7/9/19
to Dbus-cxx
Robert et. al.,

I hate to resurrect this thread.  However, when you help me with this last year, I was only using a custom datatype in a signal.  At the time, I just assumed that it would be simple to use the same data type in an RPC, but apparently not.  Here is a simple example (sana main) taken from caller_object.cpp and using the myData object (see https://github.com/rm5248/dbus-cxx-testprogs/tree/master/signal_handler) you corrected for me last year:


// C++ headers
#include <string>
#include <array>
#include <iostream>


// Custom data header
#include "inc/myData.h" // See below


class LocalClientProxy: public DBus::ObjectProxy
{
 
protected:
   
LocalClientProxy(DBus::Connection::pointer conn):
     
DBus::ObjectProxy(conn, "com.myCompany.myProduct.messaging", "/com/myCompany/myProduct/LocalClient")
   
{
      m_method_add
= this->create_method<uint8_t,uint8_t,std::string>("LocalClient.Control", "add");
      m_method_rem
= this->create_method<void,uint8_t>("LocalClient.Control", "rem");
      m_method_send
= this->create_method<uint8_t,uint8_t,myData_t>("LocalClient.Control", "send");
   
}
 
public:
   
typedef DBusCxxPointer<LocalClientProxy> pointer;
   
static pointer create(DBus::Connection::pointer conn)
   
{
     
return pointer(new LocalClientProxy(conn));
   
}
   
    uint8_t add
(uint8_t filter, std::string member) { return ((*m_method_add)(filter,member)); }
   
void rem(uint8_t clientID) {(*m_method_rem)(clientID);}
    uint8_t send
(uint8_t clientID, myData_t msg) { return ((*m_method_send)(clientID, msg)); }


 
protected:
   
   
DBus::MethodProxy<uint8_t,uint8_t,std::string>::pointer m_method_add;
   
DBus::MethodProxy<void,uint8_t>::pointer m_method_rem;
   
DBus::MethodProxy<uint8_t,uint8_t,myData_t>::pointer m_method_send;
};


// Here is the header for myData

#ifndef MYDATA_H
#define MYDATA_H


#include <string>
#include <vector>


typedef struct _myData
{
 
static constexpr const char* DBUS_SIGNATURE = "(yus)";
  uint8_t        octet
;
  uint32_t       dword
;
  std
::string    deviceName;
} myData_t;


//------------------------------------------------------------------------------
// Return dbus custom data description. This has to live in the DBus namespace
// in order to work with libdbus-cxx.
//------------------------------------------------------------------------------


namespace DBus
{
   
inline std::string signature(struct _myData) {return _myData::DBUS_SIGNATURE;}
}


// Required to be here I think
#include <dbus-cxx.h>


//------------------------------------------------------------------------------
// These iterators insert/extract a myData struct into/from a DBus::Message.
//------------------------------------------------------------------------------


DBus::MessageIterator &operator>>(DBus::MessageIterator& i, struct _myData& f);
DBus::MessageAppendIterator& operator<<(DBus::MessageAppendIterator& i, const struct _myData& f);


#endif // MYDATA_H


It works fine for the methods "add" and "rem" as obviously they use common data types.  But for some reason, the compiler can't seem to find a signature for myData_t though it is there, and the include for dbus-cxx.inc seems to be in the right place in myData.h.  At least it works when I use it to send/receive a signal.  Here is the error message:

----------Building project:[ caller - Release ]----------
make[1]: Entering directory '/home/dallas/git/DSCR/CollectionProcessor/caller'
/opt/dey/2.2-r3/sysroots/x86_64-deysdk-linux/usr/bin/arm-dey-linux-gnueabi/arm-dey-linux-gnueabi-g++  -c  "/home/dallas/git/DSCR/CollectionProcessor/caller/src/caller.cpp" -std=c++14 -std=c++11 -Wall -marm -mfpu=neon -mfloat-abi=hard -mcpu=cortex-a7 -march=armv7ve --sysroot=/opt/dey/2.2-r3/sysroots/cortexa7hf-neon-dey-linux-gnueabi -pthread -O2 -DNDEBUG  -o ./Release/src_caller.cpp.o -I. -I. -I/home/dallas/git/DSCR/CollectionProcessor/Socket -I/home/dallas/git/DSCR/CollectionProcessor/CustomData -I/home/dallas/git/DSCR/CollectionProcessor/Datalink -I=/usr/include/dbus-cxx-0.9 -I=/usr/include/dbus-1.0 -I=/usr/lib/dbus-1.0/include -I=/usr/include/sigc++-2.0 -I=/usr/lib/sigc++-2.0/include
In file included from /opt/dey/2.2-r3/sysroots/cortexa7hf-neon-dey-linux-gnueabi/usr/include/dbus-cxx-0.9/dbus-cxx/message.h:27:0,
                 from /opt/dey/2.2-r3/sysroots/cortexa7hf-neon-dey-linux-gnueabi/usr/include/dbus-cxx-0.9/dbus-cxx/callmessage.h:19,
                 from /opt/dey/2.2-r3/sysroots/cortexa7hf-neon-dey-linux-gnueabi/usr/include/dbus-cxx-0.9/dbus-cxx.h:25,
                 from ./inc/myData.h:26,
                 from /home/dallas/git/DSCR/CollectionProcessor/caller/src/caller.cpp:7:
/opt/dey/2.2-r3/sysroots/cortexa7hf-neon-dey-linux-gnueabi/usr/include/dbus-cxx-0.9/dbus-cxx/messageappenditerator.h: In instantiation of 'DBus::MessageAppendIterator& DBus::MessageAppendIterator::operator<<(const T&) [with T = _myData]':
/opt/dey/2.2-r3/sysroots/cortexa7hf-neon-dey-linux-gnueabi/usr/include/dbus-cxx-0.9/dbus-cxx/methodproxy.h:162:28:   required from 'T_return DBus::MethodProxy<T_return, T_arg1, T_arg2, sigc::nil, sigc::nil, sigc::nil, sigc::nil, sigc::nil>::operator()(T_arg1, T_arg2) [with T_return = unsigned char; T_arg1 = unsigned char; T_arg2 = _myData]'
/home/dallas/git/DSCR/CollectionProcessor/caller/src/caller.cpp:28:90:   required from here
/opt/dey/2.2-r3/sysroots/cortexa7hf-neon-dey-linux-gnueabi/usr/include/dbus-cxx-0.9/dbus-cxx/messageappenditerator.h:140:9: error: no matching function for call to 'DBus::MessageAppendIterator::append(const _myData&)'
         this->append( v );
         ^~~~

I'm not sure where else I would put the include for myData.h. Furthermore I'm confused about why the compiler is confused.  Thanks for any help you can provide.

-Dallas

Robert Middleton

unread,
Jul 9, 2019, 10:41:24 PM7/9/19
to Kimmy Posey, Dbus-cxx
That's very interesting; nothing seems completely out of place to me
at least, it looks like it should still work. My immediate guess is
that there's something bad with the includes and the order that they
are in, but exactly what that problem is I'm not sure. I did try to
mess around with it for a little but but I didn't get anywhere;
there's some code that I will check in the morning and see if that
sheds any light on the situation.

-Robert Middleton
> --
> You received this message because you are subscribed to the Google Groups "Dbus-cxx" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to dbus-cxx+u...@googlegroups.com.
> To post to this group, send email to dbus...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/dbus-cxx/2baf8aef-a9b4-48e5-906d-abfa584c1cb7%40googlegroups.com.

Nick Burkitt

unread,
Jul 10, 2019, 6:10:01 PM7/10/19
to Robert Middleton, Kimmy Posey, Dbus-cxx
Hi Kimmy.

As has been mentioned already, dbus-cxx is extremely finicky when it comes to the order of header files. To the point where I had to adopt a PIMPL (pointer-to-implementation) pattern for my d-bus API code so that I could get dbus-cxx out of my header files entirely. I also created a separate project in which the access methods for all data that transits the d-bus are defined.
If you can't get beyond the current roadblock, let me know and I'll try to explain how I've set things up.
Good luck!

-Nick


You received this message because you are subscribed to a topic in the Google Groups "Dbus-cxx" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/dbus-cxx/AxLXh8AyIj0/unsubscribe.
To unsubscribe from this group and all its topics, send an email to dbus-cxx+u...@googlegroups.com.

To post to this group, send email to dbus...@googlegroups.com.

Robert Middleton

unread,
Jul 10, 2019, 6:28:02 PM7/10/19
to Nick Burkitt, Kimmy Posey, Dbus-cxx
Okay, so I've figured out /what/ the problem seems to be, but not
/why/ yet. For whatever reason, some of the implementation really,
really doesn't like extra templates(probably due to the aforementioned
pickyness about header includes being in the right order). It works
fine if your custom type is the /first/ element in the template(after
the return value), but if it is not then it errors out and causes the
error that you are seeing.

Because of that, I have two workarounds that are varying levels of stupid:

1. Re-arrange the signature of your 'send' method so that it is the following:
DBus::MethodProxy<uint8_t,myData_t,uint8_t>::pointer m_method_send =
this->create_method<uint8_t,myData_t,uint8_t>("LocalClient.Control",
"send");
2. If you can't change the signature, you can make a custom wrapper
that looks something like this:
struct myDataWrapper{
uint8_t value;
struct myData{
uint8_t octet;
uint32_t dword;
std::string deviceName;
}
};

and then just change your operator>> and operator<< to accept your
myDataWrapper instead. The implementation would look something like
this for the operator<<:
DBus::MessageAppendIterator& operator<<(DBus::MessageAppendIterator&
i, const myDataWrapper& f)
{
i.append( f.value );
i.open_container( DBus::CONTAINER_STRUCT, "" );
i.sub_iterator()->append((uint8_t)f.myData.octet);
i.sub_iterator()->append((uint32_t)f.myData.dword);
i.sub_iterator()->append((std::string)f.myData.deviceName);
i.close_container();

return i;
}

I did something similar to option#2 the other week to get around the
limitation of only having 7 arguments(the method that I was calling
takes 8 arguments).

Created an issue to track: https://github.com/dbus-cxx/dbus-cxx/issues/10

-Robert Middleton
...

samuelna...@gmail.com

unread,
Jul 26, 2019, 6:30:26 AM7/26/19
to Dbus-cxx
Hi Robert,

I'm using a similar data struct and I'm not able to compile it. In my case, I use a struct which has a struct array as a member.
The struct I'm working with is:

struct sResult {
    static constexpr const char* DBUS_SIGNATURE = "(yr)";
    uint8_t res;
    std::vector<sBlock> blocks;
};

And here is the struct of sResult array:

struct sBlock{
    static constexpr const char* DBUS_SIGNATURE = "(ya)";
    uint8_t block;
    std::vector<uint8_t> data;
};



I've already implemented the needed operators for both structures:

namespace DBus {
  inline std::string signature(struct sBlock)     { return sBlock::DBUS_SIGNATURE; }
  inline std::string signature(struct sResult )        { return sResult ::DBUS_SIGNATURE;    }
}

#include <dbus-cxx.h>

DBus::MessageIterator& operator>>(DBus::MessageIterator& i, struct sBlock& t);
DBus::MessageAppendIterator& operator<<(DBus::MessageAppendIterator& i, const struct sBlock& t);

DBus::MessageIterator& operator>>(DBus::MessageIterator& i, struct sResult & t);
DBus::MessageAppendIterator& operator<<(DBus::MessageAppendIterator& i, const struct sResult & t);




DBus::MessageIterator& operator>>(DBus::MessageIterator& i, struct
sBlock& t)
{
  t.block = i.get_uint8();
  i.next();

  t.data = i.get_array_simple<uint8_t>();
  i.next();

  return i;
}


DBus::MessageAppendIterator& operator<<(DBus::MessageAppendIterator& i, const struct
sBlock& t)
{
  i.append(t.block);
  i.append(t.data);

  return i;
}


DBus::MessageIterator& operator>>(DBus::MessageIterator& i, struct
sResult & t)
{
  t.res = i.get_uint8();
  i.next();

  t.
blocks = i.get_array_simple<sBlock>();
  i.next();

  return i;
}


DBus::MessageAppendIterator& operator<<(DBus::MessageAppendIterator& i, const struct
sResult & t)
{
  i.append(t.res);
  i.append(t.
blocks); 

  return i;
}

The compiler is complaining about:
         no matching function for call to ‘type(sBlock&)’
         if ( this->element_type() != DBus::type( type ) ) {
                                      ~~~~~~~~~~^~~~~~~~

and also:
        no matching function for call to ‘type_string(sBlock&)’
           s += type_string(type);
                ~~~~~~~~~~~^~~~~~

What's wrong here? How should I manage this kind of struct?

Thank you!

Robert Middleton

unread,
Jul 26, 2019, 2:43:01 PM7/26/19
to samuelna...@gmail.com, Dbus-cxx
That still looks like something funny with the includes unfortunately,
I'm not quite sure how to fix that without seeing the full context.

However, one thing to fix first that is immediately broken is to fix
the operator>> and operator<<, since they do not open the struct.
e.g. your operator<< needs to look more like this:

DBus::MessageAppendIterator& operator<<(DBus::MessageAppendIterator&
i, const struct sBlock& t)
{
i.open_container( CONTAINER_STRUCT, std::string() );
i.m_subiter.append(t.block);
i.m_subiter.append(t.data);
i.close_container();

return i;
}

(I don't remember the exact syntax and I don't have an example readily
available, so this will probably not work as-is). But your signature
says that it is a struct, which is a sub-container that you must open.
I also have no idea what happens when you have a custom type inside of
another custom type as you have here. You probably can't use
get_array_simple though, as I think that only works for fixed-sized
basic types, which another struct would not be. You probably need to
use get_array_complex:
https://github.com/dbus-cxx/dbus-cxx/blob/f37317ed557eb4c58fe4e2837cfc0a7fc585f6a8/dbus-cxx/messageiterator.h#L334

Although the error indicates that there's no DBus::type() method
defined, have you added something like this to your code?
namespace DBus {
inline std::string signature(struct sBlock) { return
sBlock::DBUS_SIGNATURE; }
inline std::string signature(struct sResult ) { return
sResult ::DBUS_SIGNATURE; }
inline Type type( const struct sBlock& ) { return TYPE_STRUCT; } //
<-------------------------here
}

-Robert Middleton
> --
> You received this message because you are subscribed to the Google Groups "Dbus-cxx" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to dbus-cxx+u...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/dbus-cxx/c704a375-7f78-43b9-bc6e-3948cb0eaa06%40googlegroups.com.

Samuel Navarro

unread,
Jul 29, 2019, 3:45:04 AM7/29/19
to Dbus-cxx
It definitely has to do with the Type, the error comes from get_array_simple. I've tried using get_array_complex as you suggested but I get the same result.
I also added the type with -->  inline Type type( const struct sBlock& ) { return TYPE_STRUCT; }  but nothing changed. Note that I've had add this line after the dbus-cxx.h include and not before as the signatures.

I've been modifying the operators according to all your comments in this thread but I still not sure if they are correct. Let me know if you see something wrong. That's their last version:

namespace DBus {
  inline std::string signature(struct sBlock)     { return sBlock::DBUS_SIGNATURE; }
  inline std::string signature(struct sResult )        { return sResult ::DBUS_SIGNATURE;    }
}

#include <dbus-cxx.h>

inline DBus::Type type( const struct sBlock &) { return DBus::TYPE_STRUCT; }
inline DBus::Type type( const struct
sResult &) { return DBus::TYPE_STRUCT; }

DBus::MessageIterator& operator>>(DBus::MessageIterator& i, struct sBlock& t);
DBus::MessageAppendIterator& operator<<(DBus::MessageAppendIterator& i, const struct sBlock& t);

DBus::MessageIterator& operator>>(DBus::MessageIterator& i, struct sResult & t);
DBus::MessageAppendIterator& operator<<(DBus::MessageAppendIterator& i, const struct sResult & t);

DBus::MessageIterator& operator>>(DBus::MessageIterator& i, struct
sBlock& t)
{

  DBus::MessageIterator subiter = i.recurse();
  subiter >> t.data;
  subiter >> t.block;

  return i;
}


DBus::MessageAppendIterator& operator<<(DBus::MessageAppendIterator& i, const struct
sBlock& t)
{
  i.open_container(DBus::CONTAINER_STRUCT, std::string()); // why 2nd param has to be an empty string?
 
i.sub_iterator()->append(t.data);
  i.sub_iterator()->append(t.block);
  i.close_container();

  return i;
}


DBus::MessageIterator& operator>>(DBus::MessageIterator& i, struct
sResult & t)
{

  DBus::MessageIterator subiter = i.recurse();
  subiter >> t.res;
  subiter >> t.blocks;
// same error as using get_array_complex<sBlock>()

  return i;
}


DBus::MessageAppendIterator& operator<<(DBus::MessageAppendIterator& i, const struct
sResult & t)
{
  i.open_container(DBus::CONTAINER_STRUCT, std::string());
  i.sub_iterator()->append(t.res);
  i.sub_iterator()->append(t.blocks);
  i.close_container();

  return i;
}
> To unsubscribe from this group and stop receiving emails from it, send an email to dbus...@googlegroups.com.

Samuel Navarro

unread,
Jul 29, 2019, 5:32:10 AM7/29/19
to Dbus-cxx
However, adding:

inline std::string type_string( const struct sBlock&  ) { return "Struct"; }

solves the second error:

no matching function for call to ‘type_string(sBlock&)’
            s += type_string(type);
                 ~~~~~~~~~~~^~~~~~

Robert Middleton

unread,
Jul 29, 2019, 2:28:58 PM7/29/19
to Samuel Navarro, Dbus-cxx
If you can post a minimal complete example(e.g. on github), that would
be best. Otherwise it becomes quite hard to figure out what exactly
could be wrong without looking at the entire context.

-Robert Middleton
> To unsubscribe from this group and stop receiving emails from it, send an email to dbus-cxx+u...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/dbus-cxx/bf5309d9-4140-4171-87c2-9feebfbf44bd%40googlegroups.com.

Samuel Navarro

unread,
Jul 30, 2019, 2:40:35 AM7/30/19
to Dbus-cxx
Here is the code on github. It's not quite different from the code posted here but I hope it helps you.
Thank you.

Robert Middleton

unread,
Jul 30, 2019, 10:07:40 PM7/30/19
to Samuel Navarro, Dbus-cxx
It builds fine for me once I put the 'type' method in the DBus
namespace and made sure to include the correct header:

diff --git a/struct_dbus.hpp b/struct_dbus.hpp
index a9844b0..f0e481d 100644
--- a/struct_dbus.hpp
+++ b/struct_dbus.hpp
@@ -2,15 +2,17 @@
#include "variables.hpp"
#include <string>

+#include <dbus-cxx/types.h>
+
namespace DBus {
inline std::string signature(struct sBlock){ return sBlock::DBUS_SIGNATURE; }
inline std::string signature(struct sResult ){ return sResult
::DBUS_SIGNATURE; }
+ inline Type type(const struct sBlock&) { return DBus::TYPE_STRUCT; }
}

#include <dbus-cxx.h>

inline std::string type_string( const struct sBlock& ) { return "Struct"; }
-inline DBus::Type type(const struct sBlock&) { return DBus::TYPE_STRUCT; }

DBus::MessageIterator& operator>>(DBus::MessageIterator& i, struct sBlock& t);
DBus::MessageAppendIterator& operator<<(DBus::MessageAppendIterator&
i, const struct sBlock& t);

Fortunately, none of the headers that are included from types.h affect
the MessageIterator/MesasgeAppendIterator.

-Robert Middleton

On Tue, Jul 30, 2019 at 2:40 AM Samuel Navarro
> To unsubscribe from this group and stop receiving emails from it, send an email to dbus-cxx+u...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/dbus-cxx/9149590e-d493-4498-baff-fc415980d0c8%40googlegroups.com.

Samuel Navarro

unread,
Jul 31, 2019, 4:06:52 AM7/31/19
to Dbus-cxx
That's exactly what I needed. Thank you very much Robert!
Now it compiles perfectly. Unfortunately, something must be wrong with the << operators, because running the application and trying to call the methos with another app crashes both of them.

Here is the error output:

dbus[8912]: arguments to dbus_message_iter_open_container() were incorrect, assertion "(type == DBUS_TYPE_ARRAY && contained_signature && *contained_signature == DBUS_DICT_ENTRY_BEGIN_CHAR) || contained_signature == NULL || contained_signature_validity == DBUS_VALID" failed in file ../../../dbus/dbus-message.c line 2998.
This is normally a bug in some application using the D-Bus library.


I've tried to modify the operators but the same error appears every time I run both applications.
I've uploaded the 2 applications on github so you can see better what I have now. Here is the link again.

Thanks.

Nick Burkitt

unread,
Jul 31, 2019, 7:24:33 PM7/31/19
to Samuel Navarro, Dbus-cxx
Hola Samuel.

Is the D-Bus signature "(ya)" valid? The array signature, "a", is supposed to be followed by the type of the array's elements (e.g. "(yay)". From https://dbus.freedesktop.org/doc/dbus-specification.html:

ARRAY has ASCII character 'a' as type code. The array type code must be followed by a single complete type. The single complete type following the array is the type of each array element. So the simple example is:

          "ai"
       
which is an array of 32-bit integers. But an array can be of any type, such as this array-of-struct-with-two-int32-fields:

          "a(ii)"
       
Or this array of array of integer:

          "aai"  
 
Also, I've found when using dbus-cxx that structs (composite types) have an implied container. That is, rather than specifying "(yay)", you would simply use "yay".
I think the correct signatures would have to be something like this:
struct sBlock{
    static constexpr const char* DBUS_SIGNATURE = "yay";
    uint8_t block;
    std::vector<uint8_t> data;
};

struct sResult {
    static constexpr const char* DBUS_SIGNATURE = "ya(yay)";
    uint8_t res;
    std::vector<sBlock> blocks; 
}; 
When nesting types, I typically use #define for my signatures, which allows me to do things like this:
#define BLOCK_SIGNATURE "yay"
struct sBlock{
    static constexpr const char* DBUS_SIGNATURE = BLOCK_SIGNATURE;
    uint8_t block;
    std::vector<uint8_t> data;
};

#define RESULT_SIGNATURE "ya(" BLOCK_SIGNATURE ")"
struct sResult {
    static constexpr const char* DBUS_SIGNATURE = RESULT_SIGNATURE;
    uint8_t res;
    std::vector<sBlock> blocks; 
}; 
-Nick


You received this message because you are subscribed to a topic in the Google Groups "Dbus-cxx" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/dbus-cxx/AxLXh8AyIj0/unsubscribe.
To unsubscribe from this group and all its topics, send an email to dbus-cxx+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/dbus-cxx/1e52c2dc-240a-42ba-991a-2034a94b4d09%40googlegroups.com.

Nick Burkitt

unread,
Jul 31, 2019, 7:30:04 PM7/31/19
to Dbus-cxx
Hmm. After reviewing my notes, I have to retract my comment about dbus-cxx composite types having implied containers. Keep your parentheses, i.e. "(yay)" and "(ya(yay))".

-Nick
To unsubscribe from this group and all its topics, send an email to dbus...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/dbus-cxx/1e52c2dc-240a-42ba-991a-2034a94b4d09%40googlegroups.com.

Robert Middleton

unread,
Jul 31, 2019, 10:56:56 PM7/31/19
to Nick Burkitt, Dbus-cxx
This is at least a partial fix, but it should be enough for you to
solve at this point:

:~/dbus-cxxp-project/caller$ git diff
diff --git a/callee/functions.hpp b/callee/functions.hpp
index 658e569..eda3f23 100644
--- a/callee/functions.hpp
+++ b/callee/functions.hpp
@@ -35,7 +35,7 @@ sResult doRead(std::vector<uint8_t> blockN)



-std::vector<uint8_t> write(std::vector<sBlock> blocks)
+std::vector<uint8_t> doWrite(std::vector<sBlock> blocks)
{
std::vector<uint8_t> response(blocks.size(), 0);
return response;
diff --git a/callee/struct_dbus.cpp b/callee/struct_dbus.cpp
index 5eb6ddc..016bc5a 100644
--- a/callee/struct_dbus.cpp
+++ b/callee/struct_dbus.cpp
@@ -37,14 +37,19 @@ DBus::MessageIterator&
operator>>(DBus::MessageIterator& i, struct sResult& t)

DBus::MessageAppendIterator& operator<<(DBus::MessageAppendIterator&
i, const struct sResult& t)
{
-// i.open_container(DBus::CONTAINER_STRUCT, std::string());
-// i.sub_iterator()->append(t.res);
-// i.sub_iterator()->append(t.blocks);
-// i.close_container();
-
- i.append(t.res);
- i.append(t.blocks);
+std::cout << "OPER << SRESULT" << std::endl;
+ i.open_container(DBus::CONTAINER_STRUCT, std::string());
+fflush(stdout);
+fflush(stderr);
+ i.sub_iterator()->append(t.res);
+ i.sub_iterator()->append(t.blocks);
+ i.close_container();
+std::cout << "CONTAINTER STRUCT DONE" << std::endl;
return i;
+
+// i.append(t.res);
+ // i.append(t.blocks);
+ // return i;
}


diff --git a/callee/variables.hpp b/callee/variables.hpp
index 567b3a0..dca57f0 100644
--- a/callee/variables.hpp
+++ b/callee/variables.hpp
@@ -5,14 +5,14 @@


struct sBlock{
- static constexpr const char* DBUS_SIGNATURE = "(ya)";
+ static constexpr const char* DBUS_SIGNATURE = "(yay)";
uint8_t block;
std::vector<uint8_t> data;
};


struct sResult {
- static constexpr const char* DBUS_SIGNATURE = "(ya)";
+ static constexpr const char* DBUS_SIGNATURE = "(ya(yay))";
uint8_t res;
std::vector<sBlock> blocks;
};
diff --git a/caller/struct_dbus.cpp b/caller/struct_dbus.cpp
index 5eb6ddc..1caf1ae 100644
--- a/caller/struct_dbus.cpp
+++ b/caller/struct_dbus.cpp
@@ -13,14 +13,15 @@ DBus::MessageIterator&
operator>>(DBus::MessageIterator& i, struct sBlock& t)

DBus::MessageAppendIterator& operator<<(DBus::MessageAppendIterator&
i, const struct sBlock& t)
{
- i.append(t.block);
- i.append(t.data);
+// i.append(t.block);
+// i.append(t.data);
+// return i;
+
+ i.open_container(DBus::CONTAINER_STRUCT, std::string());
+ i.sub_iterator()->append(t.data);
+ i.sub_iterator()->append(t.block);
+ i.close_container();
return i;
-
-// i.open_container(DBus::CONTAINER_STRUCT, std::string());
-// i.sub_iterator()->append(t.data);
-// i.sub_iterator()->append(t.block);
-// i.close_container();
}


diff --git a/caller/variables.hpp b/caller/variables.hpp
index 567b3a0..dca57f0 100644
--- a/caller/variables.hpp
+++ b/caller/variables.hpp
@@ -5,14 +5,14 @@


struct sBlock{
- static constexpr const char* DBUS_SIGNATURE = "(ya)";
+ static constexpr const char* DBUS_SIGNATURE = "(yay)";
uint8_t block;
std::vector<uint8_t> data;
};

struct sResult {
- static constexpr const char* DBUS_SIGNATURE = "(ya)";
+ static constexpr const char* DBUS_SIGNATURE = "(ya(yay))";
uint8_t res;
std::vector<sBlock> blocks;
};


THE IMPORTANT PARTS:
/////////// Array signatures MUST have the type that they include in
the array. Just saying "there's an array here" is not sufficient.
See the documentation on the type system for more information:
https://dbus.freedesktop.org/doc/dbus-specification.html#type-system
struct sBlock{
- static constexpr const char* DBUS_SIGNATURE = "(ya)";
+ static constexpr const char* DBUS_SIGNATURE = "(yay)";
uint8_t block;
std::vector<uint8_t> data;
};

/////////// Similar to the above, since our array has another struct
inside of it, we must include the signature of the struct in our total
signature.
struct sResult {
- static constexpr const char* DBUS_SIGNATURE = "(ya)";
+ static constexpr const char* DBUS_SIGNATURE = "(ya(yay))";
uint8_t res;
std::vector<sBlock> blocks;
};

//////////// Whenever you have a struct, you must open the container
and insert everything into it. The implementation of
MessageAppendIterator::append(vector<T>) shows how this needs to be
done: https://github.com/dbus-cxx/dbus-cxx/blob/3ff5c62bcd0c653be8d7c49ec25d46fb189ecb3c/dbus-cxx/messageappenditerator.h#L100
/////////// You don't need to do the open_container on any arrays, as
that implementation is already provided for you.
DBus::MessageAppendIterator& operator<<(DBus::MessageAppendIterator&
i, const struct sResult& t)
{
+ i.open_container(DBus::CONTAINER_STRUCT, std::string());
+ i.sub_iterator()->append(t.res);
+ i.sub_iterator()->append(t.blocks);
+ i.close_container();
return i;
}


Also if you are having trouble with the signatures, I recommend that
you run dbus-monitor in another terminal; it will show you exactly
what is being sent over the wire. Here's the output from the partial
patch above:

method call sender=:1.79 -> dest=org.freedesktop.DBus serial=1
path=/org/freedesktop/DBus; interface=org.freedesktop.DBus;
member=Hello
method call sender=:1.79 -> dest=dev.example.example1 serial=2
path=/home/dev/Example; interface=dev.example.example1; member=state
method return sender=:1.78 -> dest=:1.79 reply_serial=2
byte 0
method call sender=:1.79 -> dest=dev.example.example1 serial=3
path=/home/dev/Example; interface=dev.example.example1; member=stop
method return sender=:1.78 -> dest=:1.79 reply_serial=3
method call sender=:1.79 -> dest=dev.example.example1 serial=4
path=/home/dev/Example; interface=dev.example.example1; member=start
method return sender=:1.78 -> dest=:1.79 reply_serial=4
method call sender=:1.79 -> dest=dev.example.example1 serial=5
path=/home/dev/Example; interface=dev.example.example2; member=read
array of bytes [
05 05 05 05 05
]
method return sender=:1.78 -> dest=:1.79 reply_serial=5
struct {
byte 0
array [
]
}

Note that we send an array of 5 bytes(each with the value 5), and then
we send back the struct with two members: one byte(value 0) and one
array with no values.

-Robert Middleton
> To unsubscribe from this group and stop receiving emails from it, send an email to dbus-cxx+u...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/dbus-cxx/955a5661-367c-48fb-afae-551cad9614af%40googlegroups.com.

Samuel Navarro

unread,
Aug 2, 2019, 6:47:03 AM8/2/19
to Dbus-cxx
Hi again!
Fixing the signatures and operators as you both said solved the errors. Thank you!

I'm now testing the connections between the callee and the caller and I have problems with the doWrite function.

In the callee main.cpp I've added the method:

object->create_method<std::vector<uint8_t>, std::vector<sBlock> >("dev.example.example2", "write", sigc::ptr_fun(doWrite));

This method required me to implement the signature for std::vector<sBlock> so I've included the implementation in struct_dbus.hpp as follows:

inline std::string signature(std::vector<sBlock>) { return BLOCK_ARRAY_SIGNATURE; }

Where BLOCK_ARRAY_SIGNATURE is a string defined in variables.h:

static constexpr const char* BLOCK_ARRAY_SIGNATURE = "(a(yay))";

Is this rigth? Do I really need to implement that signature for std::vector<sBlock> ?

Everything compiles fine adding this signature but, when running my caller application, the following error appears:

dbus[5397]: Writing an element of type array, but the expected type here is byte
The overall signature expected here was 'a(yay)' and we are on byte 2 of that signature.

The proxy method for doWrite is defined in the caller main.cpp:

DBus::MethodProxy<std::vector<uint8_t>, std::vector<sBlock> >& proxy4 = *(object->create_method<std::vector<uint8_t>, std::vector<sBlock> >("dev.example.example2", "write"));

And the program crashes when it calls this proxy4().

You can see the full code here.

Robert Middleton

unread,
Aug 2, 2019, 10:09:25 AM8/2/19
to Samuel Navarro, Dbus-cxx
You shoudn't have to define the custom signature for the array. Since
the signature() method is already defined for anything that is of type
std::vector, it should automatically be created for you since you have
defined the signature for your custom type(sBlock).

Basically, the rule is that you only need to define the signature
method for custom types. At the moment, 'custom types' includes DBus
structs. You don't need to define the custom signature() method for
any of the following:

- arrays(std::vector)
- maps(std::map)
- primitive types

The important part of including your signature before any of the
dbus-cxx headers is because of how the signatures are generated.
Since the methods are templated, you need all of your includes first
so that the compiler can actually find the methods.

In the unlikely event that you need to define your own signature, the
signature is still wrong. (a(yay)) means
struct{
array [
struct {
uint8_t;
array [
]
}
]
}

where what you want is just a(yay). With the DBus signatures,
anything between () is part of a struct.

-Robert Middleton


On Fri, Aug 2, 2019 at 6:47 AM Samuel Navarro
> To unsubscribe from this group and stop receiving emails from it, send an email to dbus-cxx+u...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/dbus-cxx/46b36142-e024-44ca-bf9d-a1a5c93b2848%40googlegroups.com.

Samuel Navarro

unread,
Aug 7, 2019, 3:26:02 AM8/7/19
to Dbus-cxx
Hi Robert,
I understand why the custom signature for the array doesn't need to be defined but, when I don't do it, the compiler complains:

error: no matching function for call to ‘signature(sBlock&)’
template <typename T> inline std::string signature( const std::vector<T> ) { T t; return DBUS_TYPE_ARRAY_AS_STRING + signature( t ); }
                                                                                                                       ~~~~~~~~~^~~~~

When I define the signature, it compiles fine. However, when I execute the proxy4() the program breaks, even if I define the signature correctly as a(yay).

Robert Middleton

unread,
Aug 7, 2019, 9:55:07 AM8/7/19
to Samuel Navarro, Dbus-cxx
It has been a while since I have done arrays with custom types; that
may be a problem with them still in that you need to define your
custom type with the array(this is due to the include directives being
bad at the moment on the dbus-cxx side). So there are some circular
#includes that I hope to fix with a new version.

Unfortunately it will be a few days before I can get to this again.
You may need to define a new
operator<<(std::vector<sBlock>)/operator>>(std::vector<sBlock>) and
use those.

-Robert Middleton

On Wed, Aug 7, 2019 at 3:26 AM Samuel Navarro
> To unsubscribe from this group and stop receiving emails from it, send an email to dbus-cxx+u...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/dbus-cxx/77664250-5026-4dc1-9aa4-e0448a3d47ae%40googlegroups.com.

Samuel Navarro

unread,
Aug 8, 2019, 4:24:49 AM8/8/19
to Dbus-cxx
Any ideas about implementing those operators?, I'm trying to define them but I'm afraid they doesn't work properly.

Here they are:

DBus::MessageIterator& operator>>(DBus::MessageIterator& i, std::vector<sBlock>& t)

{
    DBus::MessageIterator subiter = i.recurse();
    for (size_t j=0; j < t.size(); j++)
    {

        DBus::MessageIterator subiter2 = subiter.recurse();
        subiter2 >> t[j].data;
        subiter2 >> t[j].block;
    }
    return i;
}


DBus::MessageAppendIterator& operator<<(DBus::MessageAppendIterator& i, const std::vector<sBlock>& t)
{
    i.open_container(DBus::CONTAINER_ARRAY, std::string());

    for (size_t j=0; j < t.size(); j++)
    {
        i.sub_iterator()->open_container(DBus::CONTAINER_STRUCT, std::string());
        i.sub_iterator()->sub_iterator()->append(t[j].data);
        i.sub_iterator()->sub_iterator()->append(t[j].block);

        i.sub_iterator()->close_container();
    }

    i.close_container();
    return i;
}

Robert Middleton

unread,
Aug 12, 2019, 9:31:19 PM8/12/19
to Samuel Navarro, Dbus-cxx
So I'm going purely off of memory here, but I think that what you need
to do for your operator>> is to do something like this:

DBus::MessageIterator& operator>>(DBus::MessageIterator& i,
std::vector<sBlock>& t)
{
i.get_array_complex( t );
return i;
}

And the insertion should be something like this:

DBus::MessageAppendIterator& operator<<(DBus::MessageAppendIterator&
i, const std::vector<sBlock>& t)
{
i.open_container(DBus::CONTAINER_ARRAY, signature(sBlock) );

for( sBlock blk : t ){
i.sub_iterator() << t;
}

i.close_container();
return i;
}

-Robert Middleton

Samuel Navarro

unread,
Aug 13, 2019, 4:35:35 AM8/13/19
to Dbus-cxx
I think I've found a way to implement them without breaking the program. However it's still not working well. The full program is on github

DBus::MessageIterator& operator>>(DBus::MessageIterator& i, std::vector<sBlock>& t)
{
    t = i.get_array_complex<sBlock>();
    return i;

}

DBus::MessageAppendIterator& operator<<(DBus::MessageAppendIterator& i, const std::vector<sBlock>& t)
{
    i.open_container(DBus::CONTAINER_ARRAY, BLOCK_SIGNATURE);

    for (sBlock blk : t)

    {
        i.sub_iterator()->open_container(DBus::CONTAINER_STRUCT, std::string());
        i.sub_iterator()->sub_iterator()->append(blk.block);
        i.sub_iterator()->sub_iterator()->append(blk.data);
        i.sub_iterator()->close_container();
    }

    i.close_container();

    return i;
}

It seems this way is almost fine.
Calling the proxy4 defined in the caller now does not break the program but nothing happens instead. The caller is stopped forever and the calee does not receives nothing.

DBus::MethodProxy<std::vector<uint8_t>, std::vector<sBlock> >& proxy4 = *(object->create_method<std::vector<sBlock>, std::vector<uint8_t> >("dev.example.example2", "write"));

I've also tested to define the proxy4 modifiying the write method, now returning an sBlock array and receiving an uint8_t array.
DBus::MethodProxy<std::vector<sBlock>, std::vector<uint8_t> >& proxy4 = *(object->create_method<std::vector<sBlock>, std::vector<uint8_t> >("dev.example.example2", "write"));

This way the write method in the calee is reached and the programs shows it's outputs correctly but, nothing is returned in the caller and it gets stopped waiting.

Suggestions appreciated.

Robert Middleton

unread,
Aug 13, 2019, 10:08:37 PM8/13/19
to Samuel Navarro, Dbus-cxx
Okay, so the reason that it stops is because the Messageiterator never
goes on. Check this comment[1].

Adding i.next() in operator>> fixes this issue. In the default
operator>> this happens for you automatically[2]. I'm not sure if the
data is correct at all; there are two different ways to use
get_array_complex and I'm not sure if they are equivalent.

Here's the diff(I also turned on the logger so I could see exactly
where it was stopping, and also fixed your method names since the
example provided does not compile as-is).

diff --git a/callee/functions.hpp b/callee/functions.hpp
index 658e569..f854684 100644
--- a/callee/functions.hpp
+++ b/callee/functions.hpp
@@ -35,8 +35,9 @@ sResult doRead(std::vector<uint8_t> blockN)



-std::vector<uint8_t> write(std::vector<sBlock> blocks)
+std::vector<uint8_t> doWrite(std::vector<sBlock> blocks)
{
+std::cout << "calling write" << std::endl;
std::vector<uint8_t> response(blocks.size(), 0);
return response;
}
diff --git a/callee/main.cpp b/callee/main.cpp
index d2c5a99..849b5cf 100644
--- a/callee/main.cpp
+++ b/callee/main.cpp
@@ -1,9 +1,12 @@
#include "functions.hpp"
#include <unistd.h> // sleep

+
int main()
{
int ret;
+ DBus::setLoggingFunction( DBus::logStdErr );
+ DBus::setLogLevel( SL_TRACE );
DBus::init();
DBus::Dispatcher::pointer dispatcher = DBus::Dispatcher::create();
DBus::Connection::pointer conn =
dispatcher->create_connection(DBus::BUS_SESSION);
diff --git a/callee/struct_dbus.cpp b/callee/struct_dbus.cpp
index 4f42736..ef05771 100644
--- a/callee/struct_dbus.cpp
+++ b/callee/struct_dbus.cpp
@@ -7,6 +7,7 @@ DBus::MessageIterator&
operator>>(DBus::MessageIterator& i, struct sBlock& t)
subiter >> t.block;
subiter >> t.data;

+ i.next();
return i;
}

@@ -26,6 +27,7 @@ DBus::MessageIterator&
operator>>(DBus::MessageIterator& i, struct sResult& t)
DBus::MessageIterator subiter = i.recurse();
subiter >> t.res;
subiter >> t.blocks;
+ i.next();
return i;
}

@@ -41,7 +43,10 @@ DBus::MessageAppendIterator&
operator<<(DBus::MessageAppendIterator& i, const st

DBus::MessageIterator& operator>>(DBus::MessageIterator& i,
std::vector<sBlock>& t)
{
+std::cout << "extracting vector<sBlock>" << std::endl;
t = i.get_array_complex<sBlock>();
+ //i.get_array_complex<sBlock>( t );
+std::cout << "vector size is " << t.size() << std::endl;
return i;
}

diff --git a/caller/main.cpp b/caller/main.cpp
index e388682..d15fe39 100644
--- a/caller/main.cpp
+++ b/caller/main.cpp
@@ -38,6 +38,7 @@ int main()
gg.push_back(a);
gg.push_back(a);

+std::cout << "about to call proxy4" << std::endl;
std::vector<uint8_t> bb = proxy4(gg);
std::cout << "this should be 4 and is " << bb.size() << std::endl;


-Robert Middleton

[1]: https://github.com/dbus-cxx/dbus-cxx/blob/eb4bc3116e0d5c9253bbcfa87ccc1b30113a6fa0/dbus-cxx/messageiterator.h#L352
[2]: https://github.com/dbus-cxx/dbus-cxx/blob/eb4bc3116e0d5c9253bbcfa87ccc1b30113a6fa0/dbus-cxx/messageiterator.h#L523
> --
> You received this message because you are subscribed to the Google Groups "Dbus-cxx" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to dbus-cxx+u...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/dbus-cxx/053ed722-1a1c-4c95-97f0-031b4e2b2e1a%40googlegroups.com.

Samuel Navarro

unread,
Sep 2, 2019, 9:32:23 AM9/2/19
to Dbus-cxx
Yes, that was the missing part I needed. Thank you very much!
Now it seems to be running fine.
If new issues does not appear while testing everything, I think this is all I wanted to get.

Thank you all again.
> To unsubscribe from this group and stop receiving emails from it, send an email to dbus...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages