Skip to content
Snippets Groups Projects
Commit d0b5685f authored by cs-99's avatar cs-99
Browse files

No commit message

No commit message
parent e456033e
No related branches found
No related tags found
No related merge requests found
...@@ -135,8 +135,10 @@ struct Channel { ...@@ -135,8 +135,10 @@ struct Channel {
std::vector<std::string> vars; // associated variables in Uppaal std::vector<std::string> vars; // associated variables in Uppaal
Channel(std::string name, int32_t id, bool is_input) : name(name), identifier(id), is_input(is_input){}; Channel(std::string name, int32_t id, bool is_input) : name(name), identifier(id), is_input(is_input){};
}; };
std::vector<Channel> channels;
// used in struct Mapping for convenience
std::unique_ptr<Channel> send_channel_decl_msg(bool is_input, std::string name);
void add_var_to_channel(Channel& chan, bool is_input, std::string var);
struct Mapping { struct Mapping {
std::string topic; // ROS topic name std::string topic; // ROS topic name
...@@ -154,13 +156,13 @@ struct Mapping { ...@@ -154,13 +156,13 @@ struct Mapping {
// a pointer to an integer to increment by the amount of bytes added // a pointer to an integer to increment by the amount of bytes added
std::vector<void (*)(int32_t, byte*, int*)> converters_to_topics; std::vector<void (*)(int32_t, byte*, int*)> converters_to_topics;
int channel_index; // TRON channel Channel channel = Channel("", 0, true); // TRON channel
/* note: all vectors need to have the same size /* note: all vectors need to have the same size
example: example:
topic = "example_topic" topic = "example_topic"
byte_offset = [4, 2] byte_offset = [4, 2]
converters = *some pointer converting 8 bytes to int32, nullptr converters = *some pointer converting 8 bytes to int32, nullptr
channel = pointer to struct Channel "example channel" channel = struct Channel "example channel"
This example maps any message from topic "example_topic" to "example_channel". This example maps any message from topic "example_topic" to "example_channel".
8 Bytes starting from index 4 are converted via the given pointer 8 Bytes starting from index 4 are converted via the given pointer
...@@ -173,14 +175,58 @@ struct Mapping { ...@@ -173,14 +175,58 @@ struct Mapping {
The next position is incremented by 4 if there is no conversion function given. The next position is incremented by 4 if there is no conversion function given.
Note that the first 4 Bytes of the topics message are ignored in this example. Note that the first 4 Bytes of the topics message are ignored in this example.
*/ */
};
std::vector<Mapping> mappings;
// Callback used if TRON sends some message
void(*input_callback)(Mapping& map, int32_t*) = nullptr;
Mapping(std::string topic, std::string channel, bool channelIsInput){
this->topic = topic;
this->channel = *send_channel_decl_msg(channelIsInput, channel).get();
}
void add_var_to_mapping(std::string name_tron, int byte_offset,
int32_t (*conv_to_TRON)(byte*, int*) = nullptr,
void (*conv_to_topic)(int32_t, byte*, int*) = nullptr){
add_var_to_channel(this->channel, this->channel.is_input, name_tron);
this->byte_offset.push_back(byte_offset);
this->converters_to_TRON.push_back(conv_to_TRON);
this->converters_to_topics.push_back(conv_to_topic);
}
};
std::list<Mapping> mappings;
std::vector<ros::Publisher> input_publishers; std::vector<ros::Publisher> input_publishers;
// custom callbacks for TRONs messages taking channel name, pointer to values and publisher to publish to // callback publishing to topics like defined in mapping, used for input_callback
// key is pair of topic name and channel name in this order template<class T>
// not using custom fallbacks leads to mapping_callback_to_topics being used void mapping_callback_to_topic(Mapping& map, int32_t* vars){
std::map<std::pair<std::string, std::string>, void(*)(std::string, int32_t*, ros::Publisher&)> input_callbacks; boost::shared_ptr<T> shared_ptr = boost::make_shared<T>();
byte* ptr = reinterpret_cast<byte*>(shared_ptr.get());
int next_pos = 0;
for (int i = 0; i < map.channel.vars.size(); i++){
int32_t val = vars[i];
next_pos += map.byte_offset[i];
if (map.converters_to_topics[i] == nullptr) {
byte* val_bytes;
if (SYS_IS_BIG_ENDIAN){
uint32_t switched_byte_order = htonl(*reinterpret_cast<uint32_t*>(&val));
val = *reinterpret_cast<int32_t*>(&switched_byte_order);
}
val_bytes = reinterpret_cast<byte*>(&val);
ptr[next_pos++] = val_bytes[0];
ptr[next_pos++] = val_bytes[1];
ptr[next_pos++] = val_bytes[2];
ptr[next_pos++] = val_bytes[3];
} else {
map.converters_to_topics[i](val, &ptr[next_pos], &next_pos);
}
}
for (ros::Publisher& pub : input_publishers)
if (pub.getTopic() == map.topic) {
pub.publish(shared_ptr);
return;
}
throw "did not find publisher for topic";
}
// subscribers already have callbacks // subscribers already have callbacks
std::vector<ros::Subscriber> output_subscribers; std::vector<ros::Subscriber> output_subscribers;
...@@ -190,17 +236,6 @@ compared reliably with 0 after testing is terminated */ ...@@ -190,17 +236,6 @@ compared reliably with 0 after testing is terminated */
/* note: TRON only acknowledges if virtual clock is used, which it is not (yet) */ /* note: TRON only acknowledges if virtual clock is used, which it is not (yet) */
int acks_missing = 0; int acks_missing = 0;
// specific functions -----------------------------------------------------
int get_channel_index(std::string chan_name) {
int i = 0;
for (Channel& cur_chan : channels) {
if (cur_chan.name == chan_name) return i;
i++;
}
throw "channel not declared";
}
void get_error_msg(int32_t errorcode) { void get_error_msg(int32_t errorcode) {
ROS_WARN("got error, trying to get corresponding message"); ROS_WARN("got error, trying to get corresponding message");
byte get_err_msg_msg[5]; byte get_err_msg_msg[5];
...@@ -214,14 +249,13 @@ void get_error_msg(int32_t errorcode) { ...@@ -214,14 +249,13 @@ void get_error_msg(int32_t errorcode) {
throw "got error from TRON"; throw "got error from TRON";
} }
void add_var_to_channel(std::string channel, bool is_input, std::string var) { void add_var_to_channel(Channel& chan, bool is_input, std::string var) {
byte msg[6 + var.length()]; byte msg[6 + var.length()];
Channel& chan = channels[get_channel_index(channel)];
msg[0] = is_input ? ADD_VAR_TO_INPUT : ADD_VAR_TO_OUTPUT; msg[0] = is_input ? ADD_VAR_TO_INPUT : ADD_VAR_TO_OUTPUT;
add_int32_in_network_order(chan.identifier, msg, 1); add_int32_in_network_order(chan.identifier, msg, 1);
msg[5] = (byte) var.length(); msg[5] = (byte) var.length();
for (int i = 0; i < var.length(); i++) msg[6+i] = var.at(i); for (int i = 0; i < var.length(); i++) msg[6+i] = var.at(i);
ROS_INFO("attaching variable %s to channel %s", var.c_str(), channel.c_str()); ROS_INFO("attaching variable %s to channel %s", var.c_str(), chan.name.c_str());
send_bytes(socket_fd, msg, 6 + var.length()); send_bytes(socket_fd, msg, 6 + var.length());
int32_t ack = get_int_socket(socket_fd); int32_t ack = get_int_socket(socket_fd);
if (ack < 0) get_error_msg(ack); if (ack < 0) get_error_msg(ack);
...@@ -229,7 +263,7 @@ void add_var_to_channel(std::string channel, bool is_input, std::string var) { ...@@ -229,7 +263,7 @@ void add_var_to_channel(std::string channel, bool is_input, std::string var) {
chan.vars.push_back(var); chan.vars.push_back(var);
} }
void send_channel_decl_msg(bool is_input, std::string name) { std::unique_ptr<Channel> send_channel_decl_msg(bool is_input, std::string name) {
// prepare packet // prepare packet
size_t msg_length = 2 + name.length(); size_t msg_length = 2 + name.length();
byte msg[msg_length]; byte msg[msg_length];
...@@ -250,7 +284,7 @@ void send_channel_decl_msg(bool is_input, std::string name) { ...@@ -250,7 +284,7 @@ void send_channel_decl_msg(bool is_input, std::string name) {
if (channel_identifier == 0) throw "did not get channel identifier"; if (channel_identifier == 0) throw "did not get channel identifier";
// assigned channel ID successfully // assigned channel ID successfully
ROS_INFO("success: identifier for channel %s is %i", name.c_str(), channel_identifier); ROS_INFO("success: identifier for channel %s is %i", name.c_str(), channel_identifier);
channels.push_back(Channel(name, channel_identifier, is_input)); return std::make_unique<Channel>(name, channel_identifier, is_input);
} }
void set_time_unit_and_timeout(uint64_t microseconds, int32_t timeout){ void set_time_unit_and_timeout(uint64_t microseconds, int32_t timeout){
...@@ -291,13 +325,10 @@ void request_start() { ...@@ -291,13 +325,10 @@ void request_start() {
ROS_INFO("success: starting test phase"); ROS_INFO("success: starting test phase");
} }
void report_now(std::string chan_name, uint16_t var_count, int32_t *vars){ void report_now(Channel& chan, uint16_t var_count, int32_t *vars){
std::unique_ptr<byte[]> msg = std::make_unique<byte[]>(6 + 4 * var_count); std::unique_ptr<byte[]> msg = std::make_unique<byte[]>(6 + 4 * var_count);
Channel *chan = nullptr;
for (Channel& cur_chan : channels) if (cur_chan.name == chan_name) chan = &cur_chan;
if (chan == nullptr) throw "channel not declared";
add_int32_in_network_order(chan->identifier, msg.get(), 0); add_int32_in_network_order(chan.identifier, msg.get(), 0);
unsigned short var_count_network_order = htons(var_count); unsigned short var_count_network_order = htons(var_count);
byte *var_count_bytes = reinterpret_cast<byte*>(&var_count_network_order); byte *var_count_bytes = reinterpret_cast<byte*>(&var_count_network_order);
...@@ -307,41 +338,17 @@ void report_now(std::string chan_name, uint16_t var_count, int32_t *vars){ ...@@ -307,41 +338,17 @@ void report_now(std::string chan_name, uint16_t var_count, int32_t *vars){
for (unsigned short i = 0; i < var_count; i++) for (unsigned short i = 0; i < var_count; i++)
add_int32_in_network_order(vars[i], msg.get(), 6 + i * 4); add_int32_in_network_order(vars[i], msg.get(), 6 + i * 4);
ROS_INFO("sending to output channel %s", chan_name.c_str()); ROS_INFO("sending to output channel %s", chan.name.c_str());
if (var_count == 0) ROS_INFO("no variables attached"); if (var_count == 0) ROS_INFO("no variables attached");
for (unsigned short i = 0; i < var_count; i++) for (unsigned short i = 0; i < var_count; i++)
ROS_INFO("attached value %i to variable %s", vars[i], chan->vars[i].c_str()); ROS_INFO("attached value %i to variable %s", vars[i], chan.vars[i].c_str());
send_bytes(socket_fd, msg.get(), 6 + 4 * var_count); send_bytes(socket_fd, msg.get(), 6 + 4 * var_count);
acks_missing++; acks_missing++;
} }
void init_topic_channel_mapping(const std::string topic, const std::string channel){
Mapping map;
map.topic = topic;
map.channel_index = get_channel_index(channel);
mappings.push_back(map);
}
void add_var_to_mapping(std::string topic, std::string channel, int byte_offset,
int32_t (*conv_to_TRON)(byte*, int*) = nullptr,
void (*conv_to_topic)(int32_t, byte*, int*) = nullptr) {
int index = -1;
for (int i = 0; i < mappings.size(); i++) {
Mapping& map = mappings[i];
if (channels[map.channel_index].name == channel && map.topic == topic) index = i;
}
if (index < 0) throw "did not find mapping";
Mapping& map = mappings[index];
map.byte_offset.push_back(byte_offset);
map.converters_to_TRON.push_back(conv_to_TRON);
map.converters_to_topics.push_back(conv_to_topic);
}
// callback reports to TRON like defined in mappings // callback reports to TRON like defined in mappings
template<class T> template<class T>
void mapping_callback_to_TRON(const ros::MessageEvent<T>& event){ void mappings_callback_to_TRON(const ros::MessageEvent<T>& event){
std::string topic = event.getConnectionHeader().at("topic"); std::string topic = event.getConnectionHeader().at("topic");
byte *bytes = reinterpret_cast<byte*>(event.getMessage().get()); byte *bytes = reinterpret_cast<byte*>(event.getMessage().get());
for (Mapping& mapping : mappings) { for (Mapping& mapping : mappings) {
...@@ -361,38 +368,7 @@ void mapping_callback_to_TRON(const ros::MessageEvent<T>& event){ ...@@ -361,38 +368,7 @@ void mapping_callback_to_TRON(const ros::MessageEvent<T>& event){
vars[i] = mapping.converters_to_TRON[i](&bytes[next_pos], &next_pos); vars[i] = mapping.converters_to_TRON[i](&bytes[next_pos], &next_pos);
} }
} }
report_now(channels[mapping.channel_index].name, var_count, vars); report_now(mapping.channel, var_count, vars);
}
}
}
// callback publishing to topics like defined in mappings
template<class T>
void mapping_callback_to_topics(std::string channel, int32_t* vars, ros::Publisher& pub){
for (Mapping& mapping : mappings) {
if (channels[mapping.channel_index].name == channel) {
boost::shared_ptr<T> shared_ptr = boost::make_shared<T>();
byte* ptr = reinterpret_cast<byte*>(shared_ptr.get());
int next_pos = 0;
for (int i = 0; i < channels[mapping.channel_index].vars.size(); i++){
int32_t val = vars[i];
next_pos += mapping.byte_offset[i];
if (mapping.converters_to_topics[i] == nullptr) {
byte* val_bytes;
if (SYS_IS_BIG_ENDIAN){
uint32_t switched_byte_order = htonl(*reinterpret_cast<uint32_t*>(&val));
val = *reinterpret_cast<int32_t*>(&switched_byte_order);
}
val_bytes = reinterpret_cast<byte*>(&val);
ptr[next_pos++] = val_bytes[0];
ptr[next_pos++] = val_bytes[1];
ptr[next_pos++] = val_bytes[2];
ptr[next_pos++] = val_bytes[3];
} else {
mapping.converters_to_topics[i](val, &ptr[next_pos], &next_pos);
}
}
pub.publish(shared_ptr);
} }
} }
} }
...@@ -406,21 +382,18 @@ void configuration_phase(ros::NodeHandle& nh){ ...@@ -406,21 +382,18 @@ void configuration_phase(ros::NodeHandle& nh){
// add callback for mapping (key is pair of topic and channel name) // add callback for mapping (key is pair of topic and channel name)
// for output: add subscribers to output_subscribers // for output: add subscribers to output_subscribers
send_channel_decl_msg(true, "ausloesen"); Mapping map = Mapping("/command", "ausloesen", true);
init_topic_channel_mapping("/command", "ausloesen"); map.add_var_to_mapping("zahl", 0);
add_var_to_channel("ausloesen", true, "zahl"); map.input_callback = mapping_callback_to_topic<std_msgs::Int32>;
add_var_to_mapping("/command", "ausloesen", 0); mappings.push_back(map);
input_publishers.push_back(nh.advertise<std_msgs::Int32>("/command", 1)); input_publishers.push_back(nh.advertise<std_msgs::Int32>("/command", 1));
input_callbacks[std::pair<std::string, std::string>("/command", "ausloesen")]
= mapping_callback_to_topics<std_msgs::Int32>;
// output channels: declare, init mapping, add vars to TRON channel and mapping // output channels: declare, init mapping, add vars to TRON channel and mapping
// add subscriber to list // add subscriber to list
send_channel_decl_msg(false, "position"); map = Mapping("/position", "position", false);
init_topic_channel_mapping("/position", "position"); map.add_var_to_mapping("zahl", 0);
add_var_to_channel("position", false, "zahl"); mappings.push_back(map);
add_var_to_mapping("/position", "position", 0);
output_subscribers.push_back(nh.subscribe("/position", 1, output_subscribers.push_back(nh.subscribe("/position", 1,
mapping_callback_to_TRON<std_msgs::Int32>)); mappings_callback_to_TRON<std_msgs::Int32>));
// not obvious in documentation: local variables are not supported // not obvious in documentation: local variables are not supported
// add_var_to_channel(socketfd, "ausloesen", "lokal"); // add_var_to_channel(socketfd, "ausloesen", "lokal");
uint64_t microseconds = 1000000; // one second uint64_t microseconds = 1000000; // one second
...@@ -453,7 +426,7 @@ void process_TRONs_msgs(){ ...@@ -453,7 +426,7 @@ void process_TRONs_msgs(){
// bytes are channel identifier // bytes are channel identifier
// find corresponding channel // find corresponding channel
const Channel *chan = nullptr; const Channel *chan = nullptr;
for (Channel& cur_chan : channels) if (cur_chan.identifier == next) chan = &cur_chan; for (Mapping& map : mappings) if (map.channel.identifier == next) chan = &map.channel;
/* note: this only happens if message number 12 in TRON User Manual is received, /* note: this only happens if message number 12 in TRON User Manual is received,
which should not be the case according to the documentation */ which should not be the case according to the documentation */
if (chan == nullptr) if (chan == nullptr)
...@@ -480,15 +453,12 @@ void process_TRONs_msgs(){ ...@@ -480,15 +453,12 @@ void process_TRONs_msgs(){
} }
for (Mapping& map : mappings) for (Mapping& map : mappings)
if (channels[map.channel_index].name == chan->name) if (map.channel.name == chan->name)
for (ros::Publisher& pub : input_publishers){ for (ros::Publisher& pub : input_publishers){
if (pub.getTopic() == map.topic) { if (pub.getTopic() == map.topic) {
if (input_callbacks.find( if (map.input_callback != nullptr)
std::pair<std::string, std::string>(map.topic, channels[map.channel_index].name)) map.input_callback(map, vals);
!= input_callbacks.end()) else throw "no callback declared";
input_callbacks.at(std::pair<std::string, std::string>(map.topic, channels[map.channel_index].name))
(chan->name, vals, pub);
else throw "did not find callback";
break; break;
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment