0

I try to send a user defined struct which contains substructs over AMQP from one node to another. I am using the Apache Qpid library at the moment. (I'm currently still testing my code on the PC before i rebuild it for my other devices)

my current method consist of a conversion from the struct to a bytestring and sending that over AMQP to deconverse it on the other side. I do the following

//user defined struct
enum Quality
{
    /// <summary>Value is reliable.</summary>
    QUALITY_GOOD,
    /// <summary>Value not reliable.</summary>
    /// <remarks>
    ///     A variable may be declared unreliable if a sensor is not calibrated or
    ///     if the last query failed but older samples are still usable.
    /// </remarks>
    QUALITY_UNCERTAIN,
    /// <summary>Value is invalid.</summary>
    /// <remarks>
    ///     A variable may be declared bad if the measured value is out of range or
    ///     if a timeout occured.
    /// </remarks>
    QUALITY_BAD
};

struct Payload
{
    /// <summary>Identifier that uniquely points to a single instance.</summary>
    DdsInterface::Id id = DdsInterface::Id();
    /// <summary>Human readable short name.</summary>
    std::string name = "default";
    /// <summary>Actual value.</summary>
    long long value;
    /// <summary>Quality of the Value.</summary>
    Quality quality = QUALITY_GOOD;
    /// <summary>Detailed quality of the variable.</summary>
    QualityDetail qualityDetail = 0;
    /// <summary>Unit of measure.</summary>
    PhysicalQuantity quantity = 0;

    Payload();
    Payload(const DdsInterface::Id id, const std::string topic, const uint64_t counter);
};

//sender function
void QpidAMQP::AMQPPublish(const Payload& payload, bool durability, bool sync)
{
    // Publish to MQTT broker
    qpid::messaging::Message message;
    message.setDurable(durability);
    char b[sizeof (payload)];
    memcpy(b, &payload, sizeof(payload));

    //create stream of bytes to send over the line
    message.setContent(b);
    //message.setContent("testIfSend");
    std::string temp = message.getContent();
    print_bytes(temp.c_str(), sizeof (temp));// used to check the byte data
    this->sender.send(message);
    this->session.sync(sync);
}
//receiver functions
void *check_for_incoming_messages(QpidAMQP* amqp_instance) //called via pthread
{
    qpid::messaging::Message message;

    std::cout << "check for incoming messages" << std::endl;
    while(amqp_instance->getReceiver()->fetch(message, qpid::messaging::Duration::FOREVER))
    {
        amqp_instance->on_message(&message);
    }
    return nullptr;
}

void QpidAMQP::on_message(qpid::messaging::Message *message)
{
    /// make sure message topic and payload are copied!!!
    if (this->handler)
    {
        std::string temp = message->getContent();
        print_bytes(temp.c_str(), sizeof (temp)); // used to check the byte data
        Payload payload; //Re-make the struct
        memcpy(&payload, message->getContent().c_str(), message->getContentSize());

        handler->ReceivedIntegerValue(payload.id.variableId, payload.value);
    }
}

I did check the byte data and they where vastly different.

sender: [ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 63 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 60 32 bf 74 ff 7f 00 00 05 00 00 00 00 00 00 00 74 6f 70 69 63 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ]

receiver: >[ 74 65 73 74 49 66 53 65 6e 64 00 00 00 7f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 a0 ed ff 43 57 7f 00 00 07 00 00 00 00 00 00 00 64 65 66 61 75 6c 74 00 6d 05 77 4b 57 7f 00 00 ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 ]

I used the following code to print this out

void print_bytes(const void *object, size_t size)
{
  // This is for C++; in C just drop the static_cast<>() and assign.
  const unsigned char * const bytes = static_cast<const unsigned char *>(object);
  size_t i;

  printf("[ ");
  for(i = 0; i < size; i++)
  {
    printf("%02x ", bytes[i]);
  }
  printf("]\n");
}

When i send only a string instead of the payload it receives on the other end. But for some reason a user defined struct doesn't work. i want to avoid remapping everything against the qpid map because i will lose the depth of my Payload.id.

If someone has any sugestions to overcome this i would appreciatie it.

Thanks in advance, Nick

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
nickp
  • 15
  • 3

1 Answers1

0

I solved the issue. the problem was that instead of the string instance it copied a pointer instance. By making the std::string name = "default"; into char name[20] = "default"; it copies the real character string. This is how the publisher and subscriber encode en decode the message now.

void QpidAMQP::AMQPPublish(const Payload& payload, bool durability, bool sync)
{
    // Publish to MQTT broker
    //create stream of bytes to send over the line
    qpid::messaging::Message message;
    message.setDurable(durability);
    std::string b;
    b.resize(sizeof(Payload));
    std::memcpy(const_cast<char*>(b.c_str()), &payload, b.size());
    message.setContent(b);
    std::string temp = message.getContent();
    print_bytes(temp.c_str(), temp.size());
    this->sender.send(message);
    this->session.sync(sync);
}
void QpidAMQP::on_message(qpid::messaging::Message *message)
{
    /// make sure message topic and payload are copied!!!
    if (this->handler != nullptr)
    {
        const std::string temp = message->getContent();
        print_bytes(temp.c_str(), temp.size());
        Payload payload;
        std::memcpy(&payload, temp.c_str(), temp.size());//sizeof(message->getContentBytes().c_str()));
        handler->ReceivedIntegerValue(payload.id.variableId, payload.value);
    }
}
nickp
  • 15
  • 3