Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
B
bachelor thesis
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Christoph Schröter
bachelor thesis
Commits
1fb4ac0f
Commit
1fb4ac0f
authored
4 years ago
by
cs-99
Browse files
Options
Downloads
Patches
Plain Diff
No commit message
No commit message
parent
8d83766b
No related branches found
No related tags found
No related merge requests found
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
main.cpp
+223
-190
223 additions, 190 deletions
main.cpp
with
223 additions
and
190 deletions
main.cpp
+
223
−
190
View file @
1fb4ac0f
#include
<ros/ros.h>
#include
<ros/ros.h>
#include
<ros/console.h>
#include
<stdio.h>
#include
<stdio.h>
#include
<sys/socket.h>
#include
<sys/socket.h>
#include
<netinet/in.h>
#include
<netinet/in.h>
#include
<arpa/inet.h>
#include
<arpa/inet.h>
#include
<std_msgs/Int32.h>
typedef
uint8_t
byte
;
typedef
uint8_t
byte
;
// consts for TRON ----------------------------------------------------------
// some helper functions -----------------------------------------------
const
byte
GET_ERROR_MSG
=
127
;
const
byte
DECL_CHAN_INPUT
=
1
;
const
byte
DECL_CHAN_OUTPUT
=
2
;
const
byte
ADD_VAR_TO_INPUT
=
3
;
const
byte
ADD_VAR_TO_OUTPUT
=
4
;
const
byte
SET_TIME_UNIT
=
5
;
const
byte
SET_TIMEOUT
=
6
;
const
byte
REQUEST_START
=
64
;
const
byte
ANSWER_START
=
0
;
const
int32_t
ACK_SINGLE
=
-
2147483648
;
// 32 Bit int with most significant bit set to 1
// function declarations --------------------------------------------------------
// gets count bytes from socket file descriptor
std
::
unique_ptr
<
byte
[]
>
get_bytes_socket
(
int
fd
,
int
count
);
// log bytes sent/received
// log bytes sent/received
void
byte_info
(
const
byte
*
msg
,
int
msg_length
,
bool
send
=
true
);
inline
void
byte_info
(
const
byte
*
buf
,
int
buf_length
,
bool
send
=
true
){
std
::
stringstream
strstr
;
// wrapping get_bytes_socket for converting to 32 bit integer
strstr
<<
(
send
?
"sending"
:
"received"
)
<<
" bytes:"
;
int32_t
get_int_socket
(
int
fd
);
for
(
int
i
=
0
;
i
<
buf_length
;
i
++
)
strstr
<<
" "
<<
(
int
)
buf
[
i
];
ROS_INFO
(
strstr
.
str
().
c_str
());
// retrieves error message and prints it, then throws
}
void
get_error_msg
(
int
fd
,
int32_t
errorcode
);
// needs fix see implementation
// converts num to network order and adds it to msg starting from index
void
add_int32_in_network_order
(
int32_t
num
,
byte
*
msg
,
int
index
);
// wraps write() for printing and throwing on errors
void
send_bytes
(
int
fd
,
const
byte
*
bytes
,
int
length
);
void
set_time_unit_and_timeout
(
int
fd
,
uint64_t
microseconds
,
int32_t
timeout
);
// attaches UPPAAL variable called var to channel
void
add_var_to_channel
(
int
fd
,
std
::
string
channel
,
bool
is_input
,
std
::
string
var
);
// reports to var_count variables to channel named chan_name
void
report_now
(
int
fd
,
std
::
string
chan_name
,
unsigned
short
var_count
,
int32_t
*
vars
);
// throws if not answered with byte 0
void
request_start
(
int
fd
);
// -------------------------------------------------------------------------------
// gets count bytes from socket file descriptor (with timeout)
const
double
SECONDS_BEFORE_TIMEOUT
=
30
;
const
double
SECONDS_BEFORE_TIMEOUT
=
30
;
struct
Channel
{
int32_t
identifier
;
bool
is_input
;
std
::
vector
<
std
::
string
>
vars
;
// associated variables in Uppaal
Channel
(
int32_t
id
,
bool
is_input
)
:
identifier
(
id
),
is_input
(
is_input
){};
Channel
()
=
default
;
// default constructor needed for std::map
};
std
::
map
<
std
::
string
,
Channel
>
channels
;
std
::
unique_ptr
<
byte
[]
>
get_bytes_socket
(
int
fd
,
int
count
){
std
::
unique_ptr
<
byte
[]
>
get_bytes_socket
(
int
fd
,
int
count
){
std
::
unique_ptr
<
byte
[]
>
arr
=
std
::
make_unique
<
byte
[]
>
(
count
);
std
::
unique_ptr
<
byte
[]
>
arr
=
std
::
make_unique
<
byte
[]
>
(
count
);
int
already_read
=
0
;
int
already_read
=
0
;
...
@@ -81,88 +38,128 @@ std::unique_ptr<byte[]> get_bytes_socket(int fd, int count){
...
@@ -81,88 +38,128 @@ std::unique_ptr<byte[]> get_bytes_socket(int fd, int count){
return
arr
;
// no explicit move needed since return value is rvalue
return
arr
;
// no explicit move needed since return value is rvalue
};
};
int32_t
bytes_to_int_32
(
byte
*
ptr
){
inline
int32_t
bytes_to_int_32
(
byte
*
buf
){
uint32_t
h
=
ntohl
(
*
reinterpret_cast
<
uint32_t
*>
(
ptr
));
uint32_t
h
=
ntohl
(
*
reinterpret_cast
<
uint32_t
*>
(
buf
));
return
*
reinterpret_cast
<
int32_t
*>
(
&
h
);
return
*
reinterpret_cast
<
int32_t
*>
(
&
h
);
}
}
uint16_t
bytes_to_uint_16
(
byte
*
ptr
)
{
inline
uint16_t
bytes_to_uint_16
(
byte
*
buf
)
{
return
ntohs
(
*
reinterpret_cast
<
uint16_t
*>
(
ptr
));
return
ntohs
(
*
reinterpret_cast
<
uint16_t
*>
(
buf
));
}
}
// wrapping get_bytes_socket for converting to 32 bit integer
int32_t
get_int_socket
(
int
fd
)
{
int32_t
get_int_socket
(
int
fd
)
{
auto
ack
=
get_bytes_socket
(
fd
,
4
);
auto
ack
=
get_bytes_socket
(
fd
,
4
);
return
bytes_to_int_32
(
ack
.
get
());
return
bytes_to_int_32
(
ack
.
get
());
}
}
void
add_int32_in_network_order
(
int32_t
num
,
byte
*
msg
,
int
index
){
// converts num to network order and adds it to byte array starting from index
void
add_int32_in_network_order
(
int32_t
num
,
byte
*
buf
,
int
index
){
uint32_t
n
=
htonl
(
*
reinterpret_cast
<
uint32_t
*>
(
&
num
));
uint32_t
n
=
htonl
(
*
reinterpret_cast
<
uint32_t
*>
(
&
num
));
byte
*
bytes
=
reinterpret_cast
<
byte
*>
(
&
n
);
byte
*
bytes
=
reinterpret_cast
<
byte
*>
(
&
n
);
msg
[
index
]
=
bytes
[
0
];
buf
[
index
]
=
bytes
[
0
];
msg
[
++
index
]
=
bytes
[
1
];
buf
[
++
index
]
=
bytes
[
1
];
msg
[
++
index
]
=
bytes
[
2
];
buf
[
++
index
]
=
bytes
[
2
];
msg
[
++
index
]
=
bytes
[
3
];
buf
[
++
index
]
=
bytes
[
3
];
}
}
void
byte_info
(
const
byte
*
msg
,
int
msg_length
,
bool
send
){
// wraps write() for printing and throwing on errors
std
::
stringstream
strstr
;
inline
void
send_bytes
(
int
fd
,
const
byte
*
buf
,
int
length
){
strstr
<<
(
send
?
"sending"
:
"received"
)
<<
" bytes:"
;
byte_info
(
buf
,
length
);
for
(
int
i
=
0
;
i
<
msg_length
;
i
++
)
strstr
<<
" "
<<
(
int
)
msg
[
i
]
;
int
ret
=
write
(
fd
,
(
void
*
)
buf
,
length
)
;
ROS_INFO
(
strstr
.
str
().
c_str
())
;
if
(
ret
<
0
)
throw
"writing failed"
;
}
}
void
send_bytes
(
int
fd
,
const
byte
*
bytes
,
int
length
){
// returns false if nothing more to read and true if 4 bytes are read successfully
byte_info
(
bytes
,
length
);
// used to reduce overhead in testing phase
int
ret
=
write
(
fd
,
(
void
*
)
bytes
,
length
);
inline
bool
read_4_bytes_nonblock
(
int
fd
,
byte
*
buf
)
{
if
(
ret
<
0
)
throw
"writing failed"
;
int
bytes_recv
=
recv
(
fd
,
buf
,
4
,
MSG_DONTWAIT
);
if
(
bytes_recv
==
-
1
)
return
false
;
// nothing more to read
if
(
bytes_recv
==
0
)
throw
"connection was closed"
;
if
(
bytes_recv
!=
4
)
throw
"could not read full 4 bytes"
;
byte_info
(
buf
,
4
,
false
);
return
true
;
}
}
void
get_error_msg
(
int
fd
,
int32_t
errorcode
)
{
// consts for TRON ----------------------------------------------------------
const
byte
GET_ERROR_MSG
=
127
;
const
byte
DECL_CHAN_INPUT
=
1
;
const
byte
DECL_CHAN_OUTPUT
=
2
;
const
byte
ADD_VAR_TO_INPUT
=
3
;
const
byte
ADD_VAR_TO_OUTPUT
=
4
;
const
byte
SET_TIME_UNIT
=
5
;
const
byte
SET_TIMEOUT
=
6
;
const
byte
REQUEST_START
=
64
;
const
byte
ANSWER_START
=
0
;
const
int32_t
ACK_SINGLE
=
1
<<
31
;
// 32 Bit int with most significant bit set to 1
// global vars -------------------------------------------------------------
struct
Channel
{
int32_t
identifier
;
bool
is_input
;
std
::
vector
<
std
::
string
>
vars
;
// associated variables in Uppaal
Channel
(
int32_t
id
,
bool
is_input
)
:
identifier
(
id
),
is_input
(
is_input
){};
Channel
()
=
default
;
// default constructor needed for std::map
};
std
::
map
<
std
::
string
,
Channel
>
channels
;
int
socket_fd
;
// keep track of acknowledgements that are missing
/* note: since communication is asynchronous this value can only be
compared reliably with 0 after testing is terminated */
int
acks_missing
=
0
;
// tron specific functions -----------------------------------------------------
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"
);
std
::
unique_ptr
<
byte
[]
>
get_err_msg_msg
=
std
::
make_unique
<
byte
[]
>
(
5
)
;
byte
get_err_msg_msg
[
5
]
;
get_err_msg_msg
[
0
]
=
GET_ERROR_MSG
;
// get error msg code
get_err_msg_msg
[
0
]
=
GET_ERROR_MSG
;
// get error msg code
add_int32_in_network_order
(
errorcode
,
get_err_msg_msg
.
get
()
,
1
);
add_int32_in_network_order
(
errorcode
,
get_err_msg_msg
,
1
);
send_bytes
(
fd
,
get_err_msg_msg
.
get
()
,
5
);
// connection is closed after this write?
send_bytes
(
socket_
fd
,
get_err_msg_msg
,
5
);
// connection is closed after this write?
byte
err_msg_length
=
get_bytes_socket
(
fd
,
1
)[
0
];
byte
err_msg_length
=
get_bytes_socket
(
socket_
fd
,
1
)[
0
];
auto
err_msg
=
get_bytes_socket
(
fd
,
err_msg_length
);
auto
err_msg
=
get_bytes_socket
(
socket_
fd
,
err_msg_length
);
std
::
string
msg_str
=
std
::
string
(
reinterpret_cast
<
char
*>
(
err_msg
.
get
()),
(
size_t
)
err_msg_length
);
std
::
string
msg_str
=
std
::
string
(
reinterpret_cast
<
char
*>
(
err_msg
.
get
()),
(
size_t
)
err_msg_length
);
ROS_FATAL
(
"TRON sent error message: %s"
,
msg_str
.
c_str
());
ROS_FATAL
(
"TRON sent error message: %s"
,
msg_str
.
c_str
());
throw
"got error from TRON"
;
throw
"got error from TRON"
;
}
}
void
add_var_to_channel
(
int
fd
,
std
::
string
channel
,
bool
is_input
,
std
::
string
var
)
{
void
add_var_to_channel
(
std
::
string
channel
,
bool
is_input
,
std
::
string
var
)
{
std
::
unique_ptr
<
byte
[]
>
msg
=
std
::
make_unique
<
byte
[]
>
(
6
+
var
.
length
()
)
;
byte
msg
[
6
+
var
.
length
()
]
;
if
(
channels
.
find
(
channel
)
==
channels
.
end
())
throw
"channel not declared"
;
if
(
channels
.
find
(
channel
)
==
channels
.
end
())
throw
"channel not declared"
;
Channel
&
chan
=
channels
.
at
(
channel
);
Channel
&
chan
=
channels
.
at
(
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
.
get
()
,
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
(),
channel
.
c_str
());
send_bytes
(
fd
,
msg
.
get
()
,
6
+
var
.
length
());
send_bytes
(
socket_
fd
,
msg
,
6
+
var
.
length
());
int32_t
ack
=
get_int_socket
(
fd
);
int32_t
ack
=
get_int_socket
(
socket_
fd
);
if
(
ack
<
0
)
get_error_msg
(
fd
,
ack
);
if
(
ack
<
0
)
get_error_msg
(
ack
);
ROS_INFO
(
"success: attached variable"
);
ROS_INFO
(
"success: attached variable"
);
chan
.
vars
.
push_back
(
var
);
chan
.
vars
.
push_back
(
var
);
}
}
void
send_channel_decl_msg
(
int
fd
,
bool
is_input
,
std
::
string
name
)
{
void
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
();
std
::
unique_ptr
<
byte
[]
>
msg
=
std
::
make_unique
<
byte
[]
>
(
msg_length
)
;
byte
msg
[
msg_length
]
;
msg
[
0
]
=
is_input
?
DECL_CHAN_INPUT
:
DECL_CHAN_OUTPUT
;
msg
[
0
]
=
is_input
?
DECL_CHAN_INPUT
:
DECL_CHAN_OUTPUT
;
msg
[
1
]
=
name
.
length
();
msg
[
1
]
=
name
.
length
();
for
(
int
i
=
2
,
c
=
0
;
i
<
msg_length
;
i
++
,
c
++
)
msg
[
i
]
=
name
[
c
];
for
(
int
i
=
2
,
c
=
0
;
i
<
msg_length
;
i
++
,
c
++
)
msg
[
i
]
=
name
[
c
];
// send packet
// send packet
ROS_INFO
(
"declaring channel %s as %s"
,
name
.
c_str
(),
(
is_input
?
"input"
:
"output"
));
ROS_INFO
(
"declaring channel %s as %s"
,
name
.
c_str
(),
(
is_input
?
"input"
:
"output"
));
byte_info
(
msg
.
get
()
,
msg_length
);
byte_info
(
msg
,
msg_length
);
write
(
fd
,
(
void
*
)
msg
.
get
()
,
msg_length
);
write
(
socket_
fd
,
(
void
*
)
msg
,
msg_length
);
// get answer from TRON
// get answer from TRON
int32_t
channel_identifier
=
get_int_socket
(
fd
);
int32_t
channel_identifier
=
get_int_socket
(
socket_
fd
);
if
(
channel_identifier
<
0
)
{
// error handling
if
(
channel_identifier
<
0
)
{
// error handling
get_error_msg
(
fd
,
channel_identifier
);
get_error_msg
(
channel_identifier
);
}
}
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
...
@@ -170,8 +167,8 @@ void send_channel_decl_msg(int fd, bool is_input, std::string name) {
...
@@ -170,8 +167,8 @@ void send_channel_decl_msg(int fd, bool is_input, std::string name) {
channels
[
name
]
=
Channel
(
channel_identifier
,
is_input
);
channels
[
name
]
=
Channel
(
channel_identifier
,
is_input
);
}
}
void
set_time_unit_and_timeout
(
int
fd
,
unsigned
long
long
microseconds
,
int32_t
timeout
){
void
set_time_unit_and_timeout
(
uint64_t
microseconds
,
int32_t
timeout
){
std
::
unique_ptr
<
byte
[]
>
msg
=
std
::
make_unique
<
byte
[]
>
(
9
)
;
byte
msg
[
9
]
;
msg
[
0
]
=
SET_TIME_UNIT
;
msg
[
0
]
=
SET_TIME_UNIT
;
byte
*
microseconds_bytes
=
reinterpret_cast
<
byte
*>
(
&
microseconds
);
byte
*
microseconds_bytes
=
reinterpret_cast
<
byte
*>
(
&
microseconds
);
...
@@ -183,32 +180,33 @@ void set_time_unit_and_timeout(int fd, unsigned long long microseconds, int32_t
...
@@ -183,32 +180,33 @@ void set_time_unit_and_timeout(int fd, unsigned long long microseconds, int32_t
for
(
int
i
=
0
;
i
<
8
;
i
++
)
msg
[
i
+
1
]
=
microseconds_bytes
[
7
-
i
];
for
(
int
i
=
0
;
i
<
8
;
i
++
)
msg
[
i
+
1
]
=
microseconds_bytes
[
7
-
i
];
}
}
ROS_INFO
(
"setting time unit: %i microseconds"
,
microseconds
);
ROS_INFO
(
"setting time unit: %i microseconds"
,
microseconds
);
send_bytes
(
fd
,
msg
.
get
()
,
9
);
send_bytes
(
socket_
fd
,
msg
,
9
);
int32_t
ack
=
get_int_socket
(
fd
);
int32_t
ack
=
get_int_socket
(
socket_
fd
);
if
(
ack
!=
0
)
get_error_msg
(
fd
,
ack
);
if
(
ack
!=
0
)
get_error_msg
(
ack
);
ROS_INFO
(
"success: set time unit"
);
ROS_INFO
(
"success: set time unit"
);
msg
.
reset
(
new
byte
[
5
]);
msg
[
0
]
=
SET_TIMEOUT
;
msg
[
0
]
=
SET_TIMEOUT
;
add_int32_in_network_order
(
timeout
,
msg
.
get
()
,
1
);
add_int32_in_network_order
(
timeout
,
msg
,
1
);
ROS_INFO
(
"setting timeout to %i units"
,
timeout
);
ROS_INFO
(
"setting timeout to %i units"
,
timeout
);
send_bytes
(
fd
,
msg
.
get
()
,
5
);
send_bytes
(
socket_
fd
,
msg
,
5
);
ack
=
get_int_socket
(
fd
);
ack
=
get_int_socket
(
socket_
fd
);
if
(
ack
!=
0
)
get_error_msg
(
fd
,
ack
);
if
(
ack
!=
0
)
get_error_msg
(
ack
);
ROS_INFO
(
"success: set timeout"
);
ROS_INFO
(
"success: set timeout"
);
}
}
void
request_start
(
int
fd
)
{
void
request_start
()
{
/* documentation confuses codes for start and getErrorMessage, actually used:
64 is start
127 is gerErrorMessage */
ROS_INFO
(
"requesting start"
);
ROS_INFO
(
"requesting start"
);
byte
start
=
REQUEST_START
;
byte
start
=
REQUEST_START
;
send_bytes
(
fd
,
&
start
,
1
);
send_bytes
(
socket_
fd
,
&
start
,
1
);
byte
answer
=
get_bytes_socket
(
fd
,
1
)[
0
];
byte
answer
=
get_bytes_socket
(
socket_
fd
,
1
)[
0
];
if
(
answer
!=
ANSWER_START
)
throw
"starting failed"
;
if
(
answer
!=
ANSWER_START
)
throw
"starting failed"
;
ROS_INFO
(
"success: starting test phase"
);
ROS_INFO
(
"success: starting test phase"
);
}
}
// nach input verarbeitung weiter machen
void
report_now
(
std
::
string
chan_name
,
uint16_t
var_count
,
int32_t
*
vars
){
void
report_now
(
int
fd
,
std
::
string
chan_name
,
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
);
if
(
channels
.
find
(
chan_name
)
==
channels
.
end
())
throw
"channel not declared"
;
if
(
channels
.
find
(
chan_name
)
==
channels
.
end
())
throw
"channel not declared"
;
Channel
chan
=
channels
.
at
(
chan_name
);
Channel
chan
=
channels
.
at
(
chan_name
);
...
@@ -223,109 +221,144 @@ void report_now(int fd, std::string chan_name, uint16_t var_count, int32_t *vars
...
@@ -223,109 +221,144 @@ void report_now(int fd, 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
);
send_bytes
(
fd
,
msg
.
get
(),
6
+
4
*
var_count
);
ROS_INFO
(
"sending to output channel %s"
,
chan_name
.
c_str
());
if
(
var_count
==
0
)
ROS_INFO
(
"no variables attached"
);
for
(
unsigned
short
i
=
0
;
i
<
var_count
;
i
++
)
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
);
acks_missing
++
;
}
}
int
main
(
int
argc
,
char
**
argv
){
// returns file descriptor
ros
::
init
(
argc
,
argv
,
"TRON dapter"
);
int
create_connected_socket
(
std
::
string
IP
,
uint16_t
port
){
ros
::
NodeHandle
nh
;
const
std
::
string
IP
=
"127.0.0.1"
;
const
short
PORT
=
8080
;
int
socketfd
;
int
socketfd
;
if
((
socketfd
=
socket
(
AF_INET
,
SOCK_STREAM
,
0
))
<
0
)
{
if
((
socketfd
=
socket
(
AF_INET
,
SOCK_STREAM
,
0
))
<
0
)
{
ROS_FATAL
(
"socket could not be created"
);
throw
"failed to create socket"
;
ros
::
shutdown
();
}
}
ROS_INFO
(
"socket created successfully"
);
ROS_INFO
(
"socket created successfully"
);
struct
sockaddr_in
addr
;
struct
sockaddr_in
addr
;
addr
.
sin_family
=
AF_INET
;
addr
.
sin_family
=
AF_INET
;
addr
.
sin_port
=
htons
(
PORT
);
addr
.
sin_port
=
htons
(
port
);
{
{
int
x
=
inet_pton
(
AF_INET
,
IP
.
c_str
(),
&
addr
.
sin_addr
);
int
x
=
inet_pton
(
AF_INET
,
IP
.
c_str
(),
&
addr
.
sin_addr
);
if
(
x
==
1
)
{
if
(
x
!=
1
)
{
ROS_INFO
(
"valid internet address"
);
throw
"IP could not be converted"
;
}
else
{
ROS_FATAL
(
"internet address could not be converted"
);
ros
::
shutdown
();
}
}
}
}
if
(
connect
(
socketfd
,
(
struct
sockaddr
*
)
&
addr
,
sizeof
(
sockaddr_in
))
<
0
)
{
if
(
connect
(
socketfd
,
(
struct
sockaddr
*
)
&
addr
,
sizeof
(
sockaddr_in
))
<
0
)
{
ROS_FATAL
(
"connection failed"
);
throw
"failed to connect"
;
ros
::
shutdown
();
}
ROS_INFO
(
"successfully connected"
);
return
socketfd
;
}
}
ROS_INFO
(
"successfully connected to TRON"
);
try
{
send_channel_decl_msg
(
socketfd
,
true
,
"ausloesen"
);
add_var_to_channel
(
socketfd
,
"ausloesen"
,
true
,
"zahl"
);
send_channel_decl_msg
(
socketfd
,
false
,
"position"
);
add_var_to_channel
(
socketfd
,
"position"
,
false
,
"zahl"
);
// nicht in dokumentation: lokale variablen nicht möglich
//add_var_to_channel(socketfd, "ausloesen", "lokal");
unsigned
long
long
microseconds
=
1000000
;
// one second
// Dokumentation arbeitet mit 2 unsigned ints, äußerst mystisch
set_time_unit_and_timeout
(
socketfd
,
microseconds
,
10
);
// FALSCH IN DOKUMENTATION: Start und error msg byte codes vertauscht
void
configuration_phase
(){
// 64 ist start
/* note: for configuration phase maximum message length is 256 Bytes,
// 127 ist gerErrorMessage
therefore heap allocation can be avoided most of the time in called functions */
request_start
(
socketfd
);
// communication not synchronous anymore after start
send_channel_decl_msg
(
true
,
"ausloesen"
);
add_var_to_channel
(
"ausloesen"
,
true
,
"zahl"
);
send_channel_decl_msg
(
false
,
"position"
);
add_var_to_channel
(
"position"
,
false
,
"zahl"
);
// not obvious in documentation: local variables are not supported
//add_var_to_channel(socketfd, "ausloesen", "lokal");
uint64_t
microseconds
=
1000000
;
// one second
// documentation states 2 signed integers are used for some reason
set_time_unit_and_timeout
(
microseconds
,
100
);
}
// listen to topics
// TODO implement callbacks/topic messages
int
acks_needed
=
0
;
void
process_TRONs_msgs
(){
ros
::
Rate
rate
(
1
);
/* note: TRONs communication after start is not guaranteed to be synchronous,
while
(
ros
::
ok
())
{
thus incoming messages must be checked for their content */
while
(
true
){
// checking for messages arrived
while
(
true
){
// get 4 bytes at a time
// get 4 bytes at a time as an int32
std
::
unique_ptr
<
byte
[]
>
bytes
=
std
::
make_unique
<
byte
[]
>
(
4
);
byte
bytes
[
4
];
int
bytes_recv
=
recv
(
socketfd
,
bytes
.
get
(),
4
,
MSG_DONTWAIT
);
if
(
!
read_4_bytes_nonblock
(
socket_fd
,
bytes
))
if
(
bytes_recv
==
-
1
)
break
;
// nothing more to read
break
;
// no bytes left to process
if
(
bytes_recv
==
0
)
throw
"connection was closed"
;
int32_t
next
=
bytes_to_int_32
(
bytes
);
if
(
bytes_recv
!=
4
)
throw
"could not read full ack or chanID"
;
byte_info
(
bytes
.
get
(),
4
,
false
);
// bytes are acknowledgement
int32_t
next
=
bytes_to_int_32
(
bytes
.
get
());
// if those 4 bytes are acknowledgement decrement amount of acks needed;
if
(
next
==
ACK_SINGLE
)
{
if
(
next
==
ACK_SINGLE
)
{
if
(
--
acks_
needed
<
0
)
throw
"too many acknowledgements"
;
if
(
--
acks_
missing
<
0
)
throw
"too many acknowledgements"
;
ROS_INFO
(
"got acknowledgement for output"
);
ROS_INFO
(
"got acknowledgement for output"
);
continue
;
continue
;
}
}
// bytes are channel identifier
// find corresponding channel
std
::
string
chan_name
;
std
::
string
chan_name
;
for
(
std
::
pair
<
const
std
::
string
,
Channel
>&
pair
:
channels
)
{
for
(
std
::
pair
<
const
std
::
string
,
Channel
>&
pair
:
channels
)
{
if
(
pair
.
second
.
identifier
==
next
)
chan_name
=
pair
.
first
;
if
(
pair
.
second
.
identifier
==
next
)
chan_name
=
pair
.
first
;
}
}
if
(
chan_name
.
empty
())
throw
"channel could not be identified"
;
if
(
chan_name
.
empty
())
/* note: this only happens if message number 12 in TRON User Manual is received,
which should not be the case according to the documentation */
throw
"channel could not be identified"
;
ROS_INFO
(
"got channel identifier (%s) for input"
,
chan_name
.
c_str
());
ROS_INFO
(
"got channel identifier (%s) for input"
,
chan_name
.
c_str
());
// channel identified, assuming following bytes are correct
bytes
=
std
::
make_unique
<
byte
[]
>
(
2
);
// channel identified, assuming all following bytes are correct
recv
(
socketfd
,
bytes
.
get
(),
2
,
MSG_DONTWAIT
);
byte_info
(
bytes
.
get
(),
2
,
false
);
// get number of variables
uint16_t
var_count
=
bytes_to_uint_16
(
bytes
.
get
());
recv
(
socket_fd
,
bytes
,
2
,
MSG_DONTWAIT
);
byte_info
(
bytes
,
2
,
false
);
uint16_t
var_count
=
bytes_to_uint_16
(
bytes
);
ROS_INFO
(
"got variable count %i"
,
var_count
);
ROS_INFO
(
"got variable count %i"
,
var_count
);
// process variables
for
(
uint16_t
i
=
0
;
i
<
var_count
;
i
++
)
{
for
(
uint16_t
i
=
0
;
i
<
var_count
;
i
++
)
{
bytes
=
std
::
make_unique
<
byte
[]
>
(
4
);
recv
(
socket_fd
,
bytes
,
4
,
MSG_DONTWAIT
);
recv
(
socketfd
,
bytes
.
get
(),
4
,
MSG_DONTWAIT
);
next
=
bytes_to_int_32
(
bytes
);
next
=
bytes_to_int_32
(
bytes
.
get
());
Channel
&
c
=
channels
.
at
(
chan_name
);
Channel
&
c
=
channels
.
at
(
chan_name
);
std
::
string
var
=
channels
.
at
(
chan_name
).
vars
[
i
];
std
::
string
var
=
channels
.
at
(
chan_name
).
vars
[
i
];
ROS_INFO
(
"got variable number %i: value of %s is %i"
,
i
+
1
,
channels
.
at
(
chan_name
).
vars
[
i
].
c_str
(),
next
);
ROS_INFO
(
"got variable number %i: value of %s is %i"
,
i
+
1
,
channels
.
at
(
chan_name
).
vars
[
i
].
c_str
(),
next
);
// TODO transfer message to topic
// TODO transfer message to topic
possibly via custom callback
}
}
bytes
=
std
::
make_unique
<
byte
[]
>
(
4
);
add_int32_in_network_order
(
ACK_SINGLE
,
bytes
.
get
(),
0
);
// send acknowledgement
add_int32_in_network_order
(
ACK_SINGLE
,
bytes
,
0
);
ROS_INFO
(
"sending acknowledgement"
);
ROS_INFO
(
"sending acknowledgement"
);
send_bytes
(
socketfd
,
bytes
.
get
()
,
4
);
send_bytes
(
socket
_
fd
,
bytes
,
4
);
}
}
ros
::
spinOnce
();
rate
.
sleep
();
}
}
// erst nach ausloesen input wäre akzeptierbar
void
testCallback
(
const
std_msgs
::
Int32
::
ConstPtr
&
msg
){
int32_t
zahl
=
4
;
int32_t
x
=
msg
->
data
;
//report_now(socketfd, "position", 1, &zahl);
report_now
(
"position"
,
1
,
&
x
);
}
int
main
(
int
argc
,
char
**
argv
){
ros
::
init
(
argc
,
argv
,
"TRON dapter"
);
ros
::
NodeHandle
nh
;
ros
::
Publisher
pub
=
nh
.
advertise
<
std_msgs
::
Int32
>
(
"test_topic"
,
1
);
if
(
!
pub
)
throw
"publisher nicht erstellt"
;
try
{
const
std
::
string
IP
=
"127.0.0.1"
;
const
uint16_t
PORT
=
8080
;
socket_fd
=
create_connected_socket
(
IP
,
PORT
);
configuration_phase
();
// subscribe to topics and add callbacks which use report_now-------------------------------------------
ros
::
Subscriber
sub
=
nh
.
subscribe
(
"test_topic"
,
1
,
testCallback
);
// -----------------------------------------------------------
request_start
();
// testing phase loop
ros
::
Rate
test_phase_freq
(
1
);
int
y
=
2
;
while
(
ros
::
ok
())
{
std_msgs
::
Int32
x
;
x
.
data
=
6
;
if
(
y
==
2
)
pub
.
publish
(
x
);
y
++
;
// TRON does not seem to send acknowledgements back
process_TRONs_msgs
();
ros
::
spinOnce
();
test_phase_freq
.
sleep
();
}
}
catch
(
const
char
*
err
){
}
catch
(
const
char
*
err
){
ROS_FATAL
(
"shutting down: %s"
,
err
);
ROS_FATAL
(
"shutting down: %s"
,
err
);
ros
::
shutdown
();
ros
::
shutdown
();
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment