mirror of
https://github.com/nasa/trick.git
synced 2024-12-18 12:56:26 +00:00
Variable Server - var_send_once and integration test (#1330)
* Adds the send_once command and message type, which allows a user to request a variable to be sent immediately and only once (intended to replace the var_add, var_send, var_clear idiom that is commonly used for this purpose) * Minor refactoring of variable server internals to reduce repeated code * Adds SIM_test_varserv to integration test to test basic variable server functionality * Changes graphics client for SIM_billiards to use var_send_once as an example of intended use * Add documentation for var_send_once in docs and tutorial * Set exit_code_enabled in trick unit tests to be true by default * Patch for failing bookworm build
This commit is contained in:
parent
6d56c281e0
commit
9c8799610f
@ -189,6 +189,22 @@ trick.var_send()
|
||||
The var_send command forces the variable server to return the list of values to the
|
||||
client immediately.
|
||||
|
||||
#### Sending variables only once and immediately
|
||||
|
||||
```python
|
||||
trick.var_send_once( string var_name)
|
||||
```
|
||||
|
||||
The var_send_once command forces the variable server to return the value of the given
|
||||
variable to the client immediately.
|
||||
|
||||
```python
|
||||
trick.var_send_once( string var_list, int num_vars)
|
||||
```
|
||||
|
||||
var_send_once can also accept a comma separated list of variables. The number of variables
|
||||
in this list must match num_vars, or it will not be processed.
|
||||
|
||||
#### Changing the Units
|
||||
|
||||
```python
|
||||
@ -386,12 +402,17 @@ unprintable character) that occurs within the character string value will appear
|
||||
escaped character, i.e. preceded by a backslash.
|
||||
|
||||
The 1st value returned in the list will always be a message indicator. The possible
|
||||
values of the message indicator are:
|
||||
- 0 returned variable value(s) from var_add or var_send
|
||||
- 1 returned value from var_exists
|
||||
- 2 returned value from send_sie_resource (special command used by Trick View)
|
||||
- 3 returned value from send_event_data (special command used by Events/Malfunctions Trick View) or var_send_list_size
|
||||
- 4 values redirected from stdio if var_set_send_stdio is enabled
|
||||
values of the message indicator listen in the table below.
|
||||
|
||||
| Name | Value | Meaning |
|
||||
|-------------------|-------|---------|
|
||||
| VS\_IP\_ERROR | -1 | Protocol Error|
|
||||
| VS\_VAR\_LIST | 0 | A list of variable values. |
|
||||
| VS\_VAR\_EXISTS | 1 | Response to var\_exists( variable_name )|
|
||||
| VS\_SIE\_RESOURCE | 2 | Response to send_sie_resource|
|
||||
| VS\_LIST\_SIZE | 3 | Response to var_send_list_size or send_event_data|
|
||||
| VS\_STDIO | 4 | Values Redirected from stdio if var_set_send_stdio is enabled|
|
||||
| VS\_SEND\_ONCE | 5 | Response to var\_send\_once|
|
||||
|
||||
If the variable units are also specified along with the variable name in a var_add or
|
||||
var_units command, then that variable will also have its units specification returned following
|
||||
|
@ -133,8 +133,7 @@ Control Panel, as shown below.
|
||||
The output of the script will display three columns of numbers. The left most
|
||||
number is the [variable server message type](#variable-server-message-types).
|
||||
Here, a message type of 0 indicates that the message is the (tab delimited) list
|
||||
of the values we requested. This is the only message type we'll be concerned
|
||||
with in this tutorial. The two columns to the right of the message number are
|
||||
of the values we requested. The two columns to the right of the message number are
|
||||
the values of ```dyn.cannon.pos[0]``` and ```dyn.cannon.pos[1]```, in the order
|
||||
that they were specified in the script.
|
||||
|
||||
@ -208,14 +207,68 @@ Suppose we wanted to get the value of the initial angle of our cannon. We don't
|
||||
need to get it repeatedly, because it doesn't change. We just want to get it
|
||||
once, and then to repeatedly get the position data, which changes over time.
|
||||
|
||||
For this situation we can use the [**var_send**](#api-var-send) command, which
|
||||
tells the variable server to send the values specified in the session variable
|
||||
list immediately, regardless of whether [**var_pause**](#api-var-pause) was
|
||||
previously commanded.
|
||||
For this situation, we can take one of several approaches. The most straightforward
|
||||
is the [**var_send_once**](#api-var-send-once) command, which tells the variable
|
||||
server to send the values sent as arguments immediately, regardless of whether
|
||||
[**var_pause**](#api-var-pause) was previously commanded.
|
||||
|
||||
To demonstrate how this works, let's add the following code to our script, right
|
||||
after the line where we sent the **var_ascii** command.
|
||||
|
||||
```python
|
||||
client_socket.send( "trick.var_send_once(\"dyn.cannon.init_angle\")\n")
|
||||
line = insock.readline()
|
||||
print line
|
||||
```
|
||||
|
||||
In this code, we simply ask the variable server to immediately send the value of ```dyn.cannon.init_angle```,
|
||||
call ```insock.readline()``` to wait for a response, and print the response when it is received.
|
||||
[**var_send_once**](#api-var-send-once) does not alter the session variable list in any way.
|
||||
|
||||
When we run the client, the first few lines of output should look something like:
|
||||
|
||||
```
|
||||
5 0.5235987755982988
|
||||
|
||||
0 0 0
|
||||
|
||||
0 0 0
|
||||
```
|
||||
|
||||
The [**var_send_once**](#api-var-send-once) command uses a [message type](#variable-server-message-types) of 5
|
||||
to allow a programmer to differentiate between normal session variables and var_send_once variables. var_send_once
|
||||
does not alter or interfere with the session variable list, which would allow both of these features to be
|
||||
used simultaneously in a sim.
|
||||
|
||||
The [**var_send_once**](#api-var-send-once) also allows a user to request multiple variables in a single
|
||||
command. [**var_send_once**](#api-var-send-once) can accept a comma-separated list of variables as the
|
||||
first argument and the number of variables in the list as the second argument.
|
||||
In our example, suppose we also wanted to retrieve the initial speed of the cannonball.
|
||||
We could retrieve both variables with a single command:
|
||||
|
||||
```python
|
||||
client_socket.send( "trick.var_send_once(\"dyn.cannon.init_angle, dyn.cannon.init_speed\", 2)\n")
|
||||
```
|
||||
|
||||
Now, when we run the client, we get both the init_angle and the init_speed with the first message.
|
||||
|
||||
```
|
||||
5 0.5235987755982988 50
|
||||
|
||||
0 0 0
|
||||
|
||||
0 0 0
|
||||
```
|
||||
|
||||
|
||||
Another commonly used pattern to retrieve variables only once is to use the [**var_add**](#api-var-add),
|
||||
[**var_send**](#api-var-send), and [**var_clear**](#api-var-clear) commands. [**var_send**](#api-var-send) tells
|
||||
the variable server to send all **session** variables immediately regardless of whether [**var_pause**](#api-var-pause)
|
||||
was previously commanded.
|
||||
|
||||
To demonstrate how this works, replace the code in the previous listing with the snippet below, right
|
||||
after the line where we sent the **var_ascii** command.
|
||||
|
||||
```python
|
||||
client_socket.send( "trick.var_add(\"dyn.cannon.init_angle\")\n")
|
||||
client_socket.send( "trick.var_send()\n" )
|
||||
@ -224,6 +277,8 @@ print line
|
||||
client_socket.send( "trick.var_clear()\n" )
|
||||
```
|
||||
|
||||
|
||||
|
||||
In this snippet of code, we add ```dyn.cannon.init_angle``` to the session
|
||||
variable list. Then we call [**var_send**](#api-var-send) to tell the variable
|
||||
server to send us the value, and wait for the response by calling
|
||||
@ -501,6 +556,7 @@ Add this to the bottom of RUN_test/input.py to give it a try.
|
||||
| VS\_SIE\_RESOURCE | 2 | Response to send_sie_resource|
|
||||
| VS\_LIST\_SIZE | 3 | Response to var_send_list_size or send_event_data|
|
||||
| VS\_STDIO | 4 | Values Redirected from stdio if var_set_send_stdio is enabled|
|
||||
| VS\_SEND\_ONCE | 5 | Response to var\_send\_once|
|
||||
|
||||
<a id=the-variable-server-api></a>
|
||||
### The Variable Server API
|
||||
@ -545,6 +601,13 @@ Resume periodic responses.
|
||||
**var\_send()** -
|
||||
Send response immediately.
|
||||
|
||||
<a id=api-var-send-once></a>
|
||||
**var\_send\_once( variable_name )** -
|
||||
Immediately send the value of variable_name
|
||||
|
||||
**var\_send\_once( variable_list, num_variables )** -
|
||||
Immediately send the value of all variables in the comma separated variable_list, or an error if the number of variables in the list does not match num_variables
|
||||
|
||||
<a id=api-var-clear></a>
|
||||
**var\_clear()** -
|
||||
Clear the session variable list.
|
||||
|
@ -305,6 +305,8 @@ int var_add(std::string in_name, std::string units_name) ;
|
||||
int var_remove(std::string in_name) ;
|
||||
int var_units(std::string var_name , std::string units_name) ;
|
||||
int var_exists(std::string in_name) ;
|
||||
int var_send_once(std::string in_name) ;
|
||||
int var_send_once(std::string in_name, int numArgs) ;
|
||||
int var_send() ;
|
||||
int var_clear() ;
|
||||
int var_cycle(double in_rate) ;
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include "trick/ThreadBase.hh"
|
||||
#include "trick/VariableServerReference.hh"
|
||||
#include "trick/variable_server_sync_types.h"
|
||||
#include "trick/variable_server_message_types.h"
|
||||
|
||||
|
||||
namespace Trick {
|
||||
|
||||
@ -120,6 +122,16 @@ namespace Trick {
|
||||
*/
|
||||
int var_exists( std::string in_name ) ;
|
||||
|
||||
/**
|
||||
@brief @userdesc Command to immediately send the value of a comma separated list of variables
|
||||
@par Python Usage:
|
||||
@code trick.var_send_once("<in_name_list>", <number of variables in list>) @endcode
|
||||
@param in_name_list - the variables name to retrieve, comma separated
|
||||
@param num_vars - number of vars in in_name_list
|
||||
@return always 0
|
||||
*/
|
||||
int var_send_once(std::string in_name_list, int num_vars);
|
||||
|
||||
/**
|
||||
@brief @userdesc Command to instruct the variable server to immediately send back the values of
|
||||
variables that are registered with the var_add command
|
||||
@ -369,11 +381,22 @@ namespace Trick {
|
||||
*/
|
||||
int copy_sim_data();
|
||||
|
||||
/**
|
||||
@brief Copy given variable values from Trick memory to each variable's output buffer.
|
||||
cyclical indicated whether it is a normal cyclical copy or a send_once copy
|
||||
*/
|
||||
int copy_sim_data(std::vector<VariableReference *> given_vars, bool cyclical);
|
||||
|
||||
/**
|
||||
@brief Write data in the appropriate format (var_ascii or var_binary) from variable output buffers to socket.
|
||||
*/
|
||||
int write_data();
|
||||
|
||||
/**
|
||||
@brief Write data from the given var only to the appropriate format (var_ascii or var_binary) from variable output buffers to socket.
|
||||
*/
|
||||
int write_data(std::vector<VariableReference *> var) ;
|
||||
|
||||
/**
|
||||
@brief gets the send_stdio flag.
|
||||
*/
|
||||
@ -426,9 +449,19 @@ namespace Trick {
|
||||
int transmit_file(std::string file_name);
|
||||
|
||||
/**
|
||||
@brief Called by write_data to write data to socket in var_binary format.
|
||||
@brief Called by write_data to write given variables to socket in var_binary format.
|
||||
*/
|
||||
int write_binary_data( int Start, char *buf1, int PacketNum );
|
||||
int write_binary_data( int Start, char *buf1, const std::vector<VariableReference *>& given_vars, VS_MESSAGE_TYPE message_type);
|
||||
|
||||
/**
|
||||
@brief Called by write_data to write given variables to socket in var_ascii format.
|
||||
*/
|
||||
int write_ascii_data(char * dest_buf, const std::vector<VariableReference *>& given_vars, VS_MESSAGE_TYPE message_type );
|
||||
|
||||
/**
|
||||
@brief Construct a variable reference from the string in_name and handle error checking
|
||||
*/
|
||||
VariableReference* create_var_reference(std::string in_name);
|
||||
|
||||
/**
|
||||
@brief Make a time reference.
|
||||
|
@ -12,7 +12,8 @@ typedef enum {
|
||||
VS_VAR_EXISTS = 1,
|
||||
VS_SIE_RESOURCE = 2,
|
||||
VS_LIST_SIZE = 3 ,
|
||||
VS_STDIO = 4
|
||||
VS_STDIO = 4,
|
||||
VS_SEND_ONCE = 5
|
||||
} VS_MESSAGE_TYPE ;
|
||||
|
||||
#endif
|
||||
|
@ -23,11 +23,10 @@ class testSimObject : public Trick::SimObject {
|
||||
("default_data") vst.default_vars();
|
||||
("initialization") vst.init();
|
||||
("initialization") vst.testAddRemove();
|
||||
("initialization") vst.testUnits();
|
||||
("initialization") vst.testExists();
|
||||
("initialization") vst.testPause();
|
||||
("initialization") vst.testOther();
|
||||
//(1.0, "scheduled") trick_ret = vst.testing();
|
||||
|
||||
("initialization") vst.testSendOnce();
|
||||
("shutdown") vst.shutdown();
|
||||
}
|
||||
};
|
||||
|
@ -11,6 +11,7 @@ PROGRAMMERS: ( (Lindsay Landry) (L3) (9-12-2013) )
|
||||
|
||||
#ifndef VS_HH
|
||||
#define VS_HH
|
||||
|
||||
class VSTest {
|
||||
public:
|
||||
|
||||
@ -19,13 +20,13 @@ class VSTest {
|
||||
char got_read[80];
|
||||
double cycle_rate;
|
||||
|
||||
TCDevice bob;
|
||||
TCDevice comm_device;
|
||||
|
||||
char a;
|
||||
unsigned char b;
|
||||
short c;
|
||||
unsigned short d;
|
||||
int e; /* M xy-position */
|
||||
int e; /* m xy-position */
|
||||
unsigned int f;
|
||||
long g;
|
||||
unsigned long h;
|
||||
@ -34,7 +35,7 @@ class VSTest {
|
||||
long long k;
|
||||
unsigned long long l;
|
||||
bool m;
|
||||
|
||||
int n[5];
|
||||
|
||||
VSTest();
|
||||
~VSTest();
|
||||
@ -51,8 +52,8 @@ class VSTest {
|
||||
int testAddRemove();
|
||||
int testExists();
|
||||
int testPause();
|
||||
int testOther();
|
||||
int testCycle();
|
||||
int testSendOnce();
|
||||
int testUnits();
|
||||
|
||||
private:
|
||||
int get_line(char* thing);
|
||||
|
@ -41,7 +41,7 @@ int VSTest::vs_write(char* cmd_buffer) {
|
||||
int nbytes;
|
||||
|
||||
nbytes = strlen(cmd_buffer);
|
||||
tc_write(&bob, cmd_buffer, nbytes);
|
||||
tc_write(&comm_device, cmd_buffer, nbytes);
|
||||
|
||||
return(0);
|
||||
}
|
||||
@ -65,16 +65,13 @@ int VSTest::vs_read() {
|
||||
break;
|
||||
}
|
||||
|
||||
num = tc_pending(&bob);
|
||||
num = tc_pending(&comm_device);
|
||||
if (num) {
|
||||
tc_read(&bob, read_buffer, num);
|
||||
tc_read(&comm_device, read_buffer, num);
|
||||
get_line(read_buffer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//std::cout << (cpu_t - cpu_st) << std::endl;
|
||||
//std::cout << read_buffer << std::endl;
|
||||
//printLine();
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
@ -25,4 +25,7 @@ int VSTest::default_vars() {
|
||||
k = -12345678912345;//long long
|
||||
l = 12345678912345; //unsigned long
|
||||
m = false; //boolean
|
||||
for (int i = 0; i < 5; i++) {
|
||||
n[i] = i;
|
||||
}
|
||||
}
|
||||
|
@ -15,21 +15,21 @@ int VSTest::init() {
|
||||
char msg[256];
|
||||
|
||||
port_num = var_server_get_port();
|
||||
hostest = var_server_get_hostname();
|
||||
hostest = "localhost";
|
||||
|
||||
memset(&bob, '\0', sizeof(TCDevice));
|
||||
memset(&comm_device, '\0', sizeof(TCDevice));
|
||||
|
||||
bob.hostname = const_cast<char*>(hostest);
|
||||
bob.port = port_num;
|
||||
comm_device.hostname = const_cast<char*>(hostest);
|
||||
comm_device.port = port_num;
|
||||
|
||||
//std::cout << bob.hostname << bob.port << std::endl;
|
||||
|
||||
bob.disable_handshaking = TC_COMM_TRUE;
|
||||
bob.disabled = TC_COMM_FALSE;
|
||||
comm_device.disable_handshaking = TC_COMM_TRUE;
|
||||
comm_device.disabled = TC_COMM_FALSE;
|
||||
|
||||
tc_connect(&bob);
|
||||
tc_connect(&comm_device);
|
||||
|
||||
if ( tc_isValid (&bob) ) {
|
||||
if ( tc_isValid (&comm_device) ) {
|
||||
printf ("connection is valid\n");
|
||||
} else {
|
||||
printf ("connection is NOT valid\n");
|
||||
|
@ -11,7 +11,7 @@ PROGRAMMERS: ( (Lindsay Landry) (L3) (9-12-2013) )
|
||||
|
||||
int VSTest::shutdown() {
|
||||
|
||||
tc_disconnect(&bob);
|
||||
tc_disconnect(&comm_device);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
@ -33,50 +33,38 @@ int VSTest::strcmp_IgnoringWhiteSpace(const char* s1, const char* s2) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Expect cycle time of 0.01 s
|
||||
int VSTest::testCycle() {
|
||||
int VSTest::testUnits() {
|
||||
char msg[256];
|
||||
char suite[] = "VariableServerTest";
|
||||
/*
|
||||
int num, num2;
|
||||
double cpu_t, cpu_st;
|
||||
struct rusage cpu_usg;
|
||||
int result;
|
||||
|
||||
sprintf(msg,"trick.var_add(\"vsx.vst.l\")\n");
|
||||
// INVALID UNIT CHANGE
|
||||
sprintf(msg,"trick.var_add(\"vsx.vst.c\")\ntrick.var_units(\"vsx.vst.c\",\"g\")\n");
|
||||
vs_write(msg);
|
||||
std::cerr << "The purpose of this test is to cause an error. Error messages are expected." << std::endl;
|
||||
vs_read();
|
||||
result = strcmp_IgnoringWhiteSpace("0 -1234", got_read);
|
||||
TRICK_EXPECT_EQ(result, 0, suite, "VariableInvalidUnits")
|
||||
|
||||
// currently bad programming, could get stuck in this loop
|
||||
while (true) {
|
||||
getrusage(RUSAGE_SELF, &cpu_usg);
|
||||
cpu_st = ((double) cpu_usg.ru_utime.tv_sec) + ((double) cpu_usg.ru_utime.tv_usec/1000000.0);
|
||||
// ADD UNITS
|
||||
sprintf(msg,"trick.var_add(\"vsx.vst.e\",\"m\")\n");
|
||||
vs_write(msg);
|
||||
vs_read();
|
||||
result = strcmp_IgnoringWhiteSpace("0 -1234 -123456 {m}", got_read);
|
||||
TRICK_EXPECT_EQ(result, 0, suite, "VariableAddUnits")
|
||||
|
||||
num = tc_pending(&bob);
|
||||
//first read.
|
||||
if (num) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (true) {
|
||||
getrusage(RUSAGE_SELF, &cpu_usg);
|
||||
cpu_t = ((double) cpu_usg.ru_utime.tv_sec) + ((double) cpu_usg.ru_utime.tv_usec/1000000.0);
|
||||
|
||||
num2 = tc_pending(&bob);
|
||||
|
||||
if (num2 == 2*num) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//std::cout << cpu_t - cpu_st << std::endl;
|
||||
// CHANGE UNITS
|
||||
sprintf(msg,"trick.var_units(\"vsx.vst.e\",\"ft\")\n");
|
||||
vs_write(msg);
|
||||
vs_read();
|
||||
result = strcmp_IgnoringWhiteSpace("0 -1234 -405039 {ft}", got_read);
|
||||
TRICK_EXPECT_EQ(result, 0, suite, "VariableChangeUnits")
|
||||
|
||||
// CLEAR VARIABLE SERVER
|
||||
sprintf(msg,"trick.var_clear()\n");
|
||||
vs_write(msg);
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
int VSTest::testAddRemove() {
|
||||
char msg[256];
|
||||
char suite[] = "VariableServerTest";
|
||||
@ -89,37 +77,10 @@ int VSTest::testAddRemove() {
|
||||
std::cout << got_read << std::endl;
|
||||
result = strcmp_IgnoringWhiteSpace("0 -1234", got_read);
|
||||
TRICK_EXPECT_EQ(result, 0, suite, "VariableAddNoUnits")
|
||||
trick_test_add_parent( suite , "VariableAddNoUnits" , "3700107028");
|
||||
|
||||
vs_read();
|
||||
result = strcmp_IgnoringWhiteSpace("0 -1234", got_read);
|
||||
TRICK_EXPECT_EQ(result, 0, suite, "VariableAddCyclic")
|
||||
trick_test_add_parent( suite , "VariableAddCyclic" , "3700107028");
|
||||
|
||||
// INVALID UNIT CHANGE
|
||||
sprintf(msg,"trick.var_units(\"vsx.vst.c\",\"g\")\n");
|
||||
vs_write(msg);
|
||||
std::cerr << "The purpose of this test is to cause an error. Error messages are expected." << std::endl;
|
||||
vs_read();
|
||||
result = strcmp_IgnoringWhiteSpace("0 -1234", got_read);
|
||||
TRICK_EXPECT_EQ(result, 0, suite, "VariableInvalidUnits")
|
||||
trick_test_add_parent( suite , "VariableInvalidUnits" , "");
|
||||
|
||||
// ADD UNITS
|
||||
sprintf(msg,"trick.var_add(\"vsx.vst.e\",\"M\")\n");
|
||||
vs_write(msg);
|
||||
vs_read();
|
||||
result = strcmp_IgnoringWhiteSpace("0 -1234 -123456 {M}", got_read);
|
||||
TRICK_EXPECT_EQ(result, 0, suite, "VariableAddUnits")
|
||||
trick_test_add_parent( suite , "VariableAddUnits" , "3700107028");
|
||||
|
||||
// CHANGE UNITS
|
||||
sprintf(msg,"trick.var_units(\"vsx.vst.e\",\"ft\")\n");
|
||||
vs_write(msg);
|
||||
vs_read();
|
||||
result = strcmp_IgnoringWhiteSpace("0 -1234 -405039 {ft}", got_read);
|
||||
TRICK_EXPECT_EQ(result, 0, suite, "VariableChangeUnits")
|
||||
trick_test_add_parent( suite , "VariableChangeUnits" , "2710769246");
|
||||
|
||||
// REMOVE SINGLE VARIABLE
|
||||
sprintf(msg,"trick.var_remove(\"vsx.vst.e\")\n");
|
||||
@ -127,18 +88,45 @@ int VSTest::testAddRemove() {
|
||||
vs_read();
|
||||
result = strcmp_IgnoringWhiteSpace("0 -1234", got_read);
|
||||
TRICK_EXPECT_EQ(result, 0, suite, "VariableRemove")
|
||||
trick_test_add_parent( suite , "VariableRemove" , "806750761");
|
||||
|
||||
// CLEAR VARIABLE SERVER
|
||||
sprintf(msg,"trick.var_clear()\n");
|
||||
vs_write(msg);
|
||||
vs_read();
|
||||
TRICK_EXPECT_EQ(strcmp(got_read, ""), 0, suite, "VariableClear")
|
||||
trick_test_add_parent( suite , "VariableClear" , "835578702");
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int VSTest::testSendOnce() {
|
||||
char msg[256];
|
||||
char suite[] = "VariableServerTest";
|
||||
int result;
|
||||
|
||||
// SEND ONCE
|
||||
sprintf(msg,"trick.var_send_once(\"vsx.vst.e\")\n");
|
||||
vs_write(msg);
|
||||
vs_read();
|
||||
result = strcmp_IgnoringWhiteSpace("5 -123456", got_read);
|
||||
TRICK_EXPECT_EQ(result, 0, suite, "VariableSendOnce")
|
||||
trick_test_add_parent( suite , "VariableSendOnce" , "");
|
||||
|
||||
// SEND ONCE LIST
|
||||
sprintf(msg,"trick.var_send_once(\"vsx.vst.n[0], vsx.vst.n[1], vsx.vst.n[2],\", 3)\n");
|
||||
vs_write(msg);
|
||||
vs_read();
|
||||
result = strcmp_IgnoringWhiteSpace("5 0 1 2", got_read);
|
||||
TRICK_EXPECT_EQ(result, 0, suite, "VariableSendOnceList")
|
||||
|
||||
// SEND ONCE LIST - WRONG INDICES
|
||||
sprintf(msg,"trick.var_send_once(\"vsx.vst.n[0], vsx.vst.n[1], vsx.vst.n[2],\", 4)\n");
|
||||
vs_write(msg);
|
||||
std::cerr << "The purpose of this test is to cause an error. Error messages are expected." << std::endl;
|
||||
vs_read();
|
||||
result = strcmp_IgnoringWhiteSpace("", got_read);
|
||||
TRICK_EXPECT_EQ(result, 0, suite, "VariableSendOnceListError")
|
||||
}
|
||||
|
||||
int VSTest::testExists() {
|
||||
char msg[256];
|
||||
char suite[] = "VariableServerTest";
|
||||
@ -156,9 +144,9 @@ int VSTest::testExists() {
|
||||
sprintf(msg,"trick.var_exists(\"vsx.vst.z\")\n");
|
||||
vs_write(msg);
|
||||
vs_read();
|
||||
std::cout << "Check variable doesn't exist: " << got_read << std::endl;
|
||||
result = strcmp_IgnoringWhiteSpace("1 0",got_read);
|
||||
TRICK_EXPECT_EQ(result, 0, suite, "VariableNotExists")
|
||||
trick_test_add_parent( suite , "VariableNotExists" , "3587464751");
|
||||
|
||||
sprintf(msg,"trick.var_clear()\n");
|
||||
vs_write(msg);
|
||||
@ -214,16 +202,3 @@ int VSTest::testPause() {
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int VSTest::testOther() {
|
||||
char msg[256];
|
||||
char suite[] = "VariableServerTest";
|
||||
|
||||
sprintf(msg,"trick.var_binary()\n");
|
||||
vs_write(msg);
|
||||
sprintf(msg,"trick.var_add(\"vsx.vst.l\")\n");
|
||||
vs_write(msg);
|
||||
vs_read();
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
@ -1,21 +0,0 @@
|
||||
/******************************TRICK HEADER*************************************
|
||||
PURPOSE: ( Test variable server )
|
||||
REFERENCE: ( None )
|
||||
ASSUMPTIONS AND LIMITATIONS: ( None )
|
||||
CLASS: ( scheduled )
|
||||
LIBRARY DEPENDENCY: ( VS.o )
|
||||
PROGRAMMERS: ( (Lindsay Landry) (L3) (9-12-2013) )
|
||||
*******************************************************************************/
|
||||
#include "../include/VS.hh"
|
||||
#include "sim_services/VariableServer/include/VariableServer.hh"
|
||||
#include "sim_services/UnitTest/include/trick_tests.h"
|
||||
|
||||
int VSTest::test() {
|
||||
|
||||
var_ascii();
|
||||
|
||||
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
@ -36,7 +36,8 @@ SIMS_TO_COMPILE_AND_RUN = \
|
||||
SIM_test_sched \
|
||||
SIM_test_templates \
|
||||
SIM_threads \
|
||||
SIM_trickified
|
||||
SIM_trickified \
|
||||
SIM_test_varserv
|
||||
|
||||
# Sims with problems, no purpose, or maybe shouldn't be a test
|
||||
# SIM_leaks ( should be deleted )
|
||||
|
@ -1,5 +1,4 @@
|
||||
#include <igl/opengl/glfw/Viewer.h>
|
||||
// #include <igl/readOFF.h>
|
||||
#include <igl/opengl/glfw/imgui/ImGuiPlugin.h>
|
||||
#include <igl/opengl/glfw/imgui/ImGuiMenu.h>
|
||||
#include <igl/opengl/glfw/imgui/ImGuiHelpers.h>
|
||||
@ -13,6 +12,7 @@
|
||||
|
||||
#include "Socket.hh"
|
||||
|
||||
#define STR_MAX 1024
|
||||
|
||||
std::vector<Eigen::Vector3d> ball_colors = {Eigen::Vector3d(0.0,0.4,0.0), //green
|
||||
Eigen::Vector3d(1.0,1.0,0.0), //yellow
|
||||
@ -153,7 +153,7 @@ class Circle : public Polygon {
|
||||
}
|
||||
|
||||
bool isValid() const {
|
||||
return points.size() == vertexMax;
|
||||
return points.size() == 1 && radius >= 0;
|
||||
}
|
||||
|
||||
RenderedShape *render() const {
|
||||
@ -298,14 +298,11 @@ class Table {
|
||||
|
||||
// Need to have an agreed upon way to send over variables
|
||||
int addShape(std::vector<double> shapeData, Eigen::Vector3d color, bool isStatic, PolygonType type, double layer) {
|
||||
// std::cout << "In AddShape" << std::endl;
|
||||
Polygon *shape;
|
||||
|
||||
switch (type) {
|
||||
|
||||
case GENERIC: {
|
||||
// Number of points is just data / 2 i guess
|
||||
// std::cout << "Creating generic polygon with " << shapeData.size()/2 << " points" << std::endl;
|
||||
Polygon *newPolygon = new Polygon(shapeData.size()/2, layer);
|
||||
for (int i = 0; i < shapeData.size(); i+=2) {
|
||||
double x = shapeData[i];
|
||||
@ -316,7 +313,6 @@ class Table {
|
||||
break;
|
||||
}
|
||||
case CIRCLE: {
|
||||
// std::cout << "Adding circle" << std::endl;
|
||||
if (shapeData.size() != 3) {
|
||||
std::cout << "Bad shapedata size for circle" << std::endl;
|
||||
return -1;
|
||||
@ -345,7 +341,6 @@ class Table {
|
||||
break;
|
||||
}
|
||||
case RECTANGLE: {
|
||||
// std::cout << "In rectangle" << std::endl;
|
||||
Rectangle *newRectangle = new Rectangle(layer);
|
||||
if (shapeData.size() != 4) {
|
||||
std::cout << "Bad shapedata size for rectangle" << std::endl;
|
||||
@ -481,14 +476,12 @@ class Table {
|
||||
|
||||
private:
|
||||
std::vector<Polygon *> staticShapes;
|
||||
std::vector<Polygon *> movingShapes;
|
||||
std::vector<RenderedShape *> staticRenderedShapes;
|
||||
std::vector<RenderedShape *> movingRenderedShapes;
|
||||
int numStaticVertices;
|
||||
int numStaticFaces;
|
||||
bool staticRendered = false;
|
||||
|
||||
std::vector<Polygon *> movingShapes;
|
||||
|
||||
};
|
||||
|
||||
void printUsage() {
|
||||
@ -505,20 +498,76 @@ std::vector<std::string> split (std::string& str, const char delim) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<double> parseTrickResponse(std::vector<std::string> list) {
|
||||
std::vector<double> ret;
|
||||
for (int i = 1; i < list.size(); i++) {
|
||||
ret.push_back(stod(list[i]));
|
||||
}
|
||||
return ret;
|
||||
double totalTime = 0;
|
||||
std::vector<double> requestTime;
|
||||
|
||||
template <typename T>
|
||||
T stringConvert (const std::string& str)
|
||||
{
|
||||
std::istringstream ss(str);
|
||||
T num;
|
||||
ss >> num;
|
||||
return num;
|
||||
}
|
||||
|
||||
std::vector<int> parseTrickResponseInt(std::vector<std::string> list) {
|
||||
std::vector<int> ret;
|
||||
for (int i = 1; i < list.size(); i++) {
|
||||
ret.push_back(stoi(list[i]));
|
||||
template <typename T>
|
||||
std::vector<T> trickResponseConvert (std::string& response)
|
||||
{
|
||||
auto responseSplit = split(response, '\t');
|
||||
std::vector<T> result;
|
||||
// ignore index 0
|
||||
for (int i = 1; i < responseSplit.size(); i++) {
|
||||
result.push_back(stringConvert<T>(responseSplit[i]));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T getVar(Socket& socket, std::string varName) {
|
||||
std::string requestString = "trick.var_send_once(\"" + varName + "\")\n";
|
||||
std::string reply;
|
||||
|
||||
socket << requestString;
|
||||
socket >> reply;
|
||||
|
||||
return stringConvert<T>(split(reply, '\t')[1]);
|
||||
}
|
||||
|
||||
// Wrapper for sprintf use case bc im tired of dealing with std::string vs char* stuff
|
||||
std::string format(const std::string& formatString, int num) {
|
||||
char *buf = (char *)malloc(formatString.size() + 10);
|
||||
sprintf(buf, formatString.c_str(), num);
|
||||
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
// Assumes the varName string has a %d in it
|
||||
template <typename T>
|
||||
std::vector<T> getVarList(Socket& socket, std::string varName, int num) {
|
||||
std::string totalRequest = "";
|
||||
std::vector<T> result;
|
||||
totalRequest += format(varName, 0);
|
||||
for (int i = 1; i < num; i++) {
|
||||
totalRequest += ", ";
|
||||
totalRequest += format(varName, i);
|
||||
}
|
||||
return ret;
|
||||
|
||||
std::string requestString = "trick.var_send_once(\"" + totalRequest + "\", " + std::to_string(num) + ")\n";
|
||||
|
||||
std::string reply;
|
||||
socket << requestString;
|
||||
socket >> reply;
|
||||
return trickResponseConvert<T>(reply);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::vector<T> fold (const std::vector<T> a, const std::vector<T> b) {
|
||||
std::vector<T> result;
|
||||
for (int i = 0; i < a.size() && i < b.size(); i++) {
|
||||
result.emplace_back (a[i]);
|
||||
result.emplace_back (b[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
@ -543,52 +592,19 @@ int main(int argc, char *argv[])
|
||||
std::string reply;
|
||||
|
||||
socket << "trick.var_set_client_tag(\"PoolTableDisplay\") \n";
|
||||
socket << "trick.var_add(\"dyn.table.numBalls\")\ntrick.var_send() \ntrick.var_clear() \n";
|
||||
socket >> reply;
|
||||
|
||||
auto parsed = split(reply, '\t');
|
||||
int numBalls = stoi(parsed[1]);
|
||||
std::cout << "Number of balls received: " << numBalls << std::endl;
|
||||
|
||||
std::string radiusRequest = "";
|
||||
char* templateString = "trick.var_add(\"dyn.table.balls[%d][0].radius\")\n";
|
||||
for (int i = 0; i < numBalls; i++) {
|
||||
char buf[64];
|
||||
sprintf(buf, templateString, i);
|
||||
radiusRequest += std::string(buf);
|
||||
}
|
||||
|
||||
socket << radiusRequest;
|
||||
socket << "trick.var_send() \ntrick.var_clear() \n";
|
||||
socket >> reply;
|
||||
|
||||
auto radii = parseTrickResponse(split(reply, '\t'));
|
||||
int numBalls = getVar<int>(socket, "dyn.table.numBalls");
|
||||
// int numBalls = 16;
|
||||
std::vector<double> radii = getVarList<double>(socket, "dyn.table.balls[%d][0].radius", numBalls);
|
||||
int numTablePoints = getVar<int>(socket, "dyn.table.numTablePoints");
|
||||
enum PolygonType tableShape = PolygonType(getVar<int>(socket, "dyn.table.tableShapeType"));
|
||||
std::vector<double> table_x = getVarList<double>(socket, "dyn.table.tableShape[%d][0]._x", numTablePoints);
|
||||
std::vector<double> table_y = getVarList<double>(socket, "dyn.table.tableShape[%d][0]._y", numTablePoints);
|
||||
std::vector<double> tablePoints = fold(table_x, table_y);
|
||||
|
||||
Table table;
|
||||
|
||||
socket << "trick.var_add(\"dyn.table.numTablePoints\") \ntrick.var_add(\"dyn.table.tableShapeType\")\n \ntrick.var_send() \ntrick.var_clear() \n";
|
||||
socket >> reply;
|
||||
|
||||
std::vector<double> tableData = parseTrickResponse(split(reply, '\t'));
|
||||
int numTablePoints = tableData[0];
|
||||
enum PolygonType tableShape = PolygonType((int)tableData[1]);
|
||||
|
||||
std::string pointRequest = "";
|
||||
for (int i = 0; i < numTablePoints; i++) {
|
||||
templateString = "trick.var_add(\"dyn.table.tableShape[%d][0]._x\")\ntrick.var_add(\"dyn.table.tableShape[%d][0]._y\")\n";
|
||||
char buf[256];
|
||||
sprintf(buf, templateString, i, i);
|
||||
pointRequest += std::string(buf);
|
||||
}
|
||||
|
||||
socket << pointRequest;
|
||||
socket << "trick.var_send() \ntrick.var_clear() \n";
|
||||
socket >> reply;
|
||||
|
||||
std::vector<double> tablePoints = parseTrickResponse(split(reply, '\t'));
|
||||
table.addShape(tablePoints, Eigen::Vector3d(0.2, 0.6, 0.2), true, tableShape, layer_TABLE);
|
||||
|
||||
|
||||
// Make the rail - translate each point on the table out from center by railWidth
|
||||
std::vector<double> railData;
|
||||
|
||||
@ -601,12 +617,13 @@ int main(int argc, char *argv[])
|
||||
railData.push_back(tablePoints[3] + railWidth);
|
||||
} else {
|
||||
// If it's just a shape then rail is bigger shape
|
||||
// Works with simple convex polygons
|
||||
// Works with simple convex polygons centered at 0,0
|
||||
// Could probably calculate center and make it more general but i dont want to
|
||||
double railWidth = 0.15;
|
||||
for (int i = 0; i < tablePoints.size(); i+=2) {
|
||||
Eigen::Vector2d point(tablePoints[i], tablePoints[i+1]);
|
||||
Eigen::Vector2d railPoint(tablePoints[i], tablePoints[i+1]);
|
||||
point *= railWidth;
|
||||
point = point.normalized() * railWidth;
|
||||
railPoint = railPoint + point;
|
||||
railData.push_back(railPoint(0));
|
||||
railData.push_back(railPoint(1));
|
||||
@ -615,82 +632,41 @@ int main(int argc, char *argv[])
|
||||
|
||||
table.addShape(railData, Eigen::Vector3d(.3, .2, .15), true, tableShape, layer_RAIL);
|
||||
|
||||
socket << "trick.var_add(\"dyn.table.numPockets\")\n \ntrick.var_send() \ntrick.var_clear() \n";
|
||||
socket >> reply;
|
||||
|
||||
int numPockets = stoi(split(reply, '\t')[1]);
|
||||
// pockets
|
||||
int numPockets = getVar<int>(socket, "dyn.table.numPockets");
|
||||
|
||||
std::vector<double> pocket_x = getVarList<double>(socket, "dyn.table.pockets[%d][0].pos._x", numPockets);
|
||||
std::vector<double> pocket_y = getVarList<double>(socket, "dyn.table.pockets[%d][0].pos._y", numPockets);
|
||||
std::vector<double> pocket_r = getVarList<double>(socket, "dyn.table.pockets[%d][0].radius", numPockets);
|
||||
for (int i = 0; i < numPockets; i++) {
|
||||
templateString = "trick.var_add(\"dyn.table.pockets[%d][0].pos._x\")\ntrick.var_add(\"dyn.table.pockets[%d][0].pos._y\")\n\ntrick.var_add(\"dyn.table.pockets[%d][0].radius\")\n";
|
||||
char buf[256];
|
||||
sprintf(buf, templateString, i, i, i);
|
||||
std::string pocketRequest = std::string(buf);
|
||||
|
||||
socket << pocketRequest;
|
||||
socket << "trick.var_send() \ntrick.var_clear() \n";
|
||||
socket >> reply;
|
||||
std::vector<double> pocketData = parseTrickResponse(split(reply, '\t'));
|
||||
table.addShape(pocketData, Eigen::Vector3d(0.0, 0.0, 0.0), true, CIRCLE, layer_POCKET);
|
||||
table.addShape(std::vector<double>({pocket_x[i],pocket_y[i],pocket_r[i]}), Eigen::Vector3d(0.0, 0.0, 0.0), true, CIRCLE, layer_POCKET);
|
||||
}
|
||||
|
||||
// Bumpers
|
||||
socket << "trick.var_add(\"dyn.table.numBumpers\")\n \ntrick.var_send() \ntrick.var_clear() \n";
|
||||
socket >> reply;
|
||||
|
||||
int numBumpers = stoi(split(reply, '\t')[1]);
|
||||
|
||||
std::cout << "Num bumpers: " << numBumpers << std::endl;
|
||||
|
||||
// bumpers
|
||||
int numBumpers = getVar<int>(socket, "dyn.table.numBumpers");
|
||||
for (int i = 0; i < numBumpers; i++) {
|
||||
std::string bumperRequests = "";
|
||||
|
||||
templateString = "trick.var_add(\"dyn.table.bumpers[%d][0].numPoints\")\ntrick.var_add(\"dyn.table.bumpers[%d][0].shapeType\") \n";
|
||||
char buf[256];
|
||||
sprintf(buf, templateString, i, i);
|
||||
bumperRequests += std::string(buf);
|
||||
socket << bumperRequests;
|
||||
socket << "trick.var_send() \ntrick.var_clear() \n";
|
||||
socket >> reply;
|
||||
std::vector<int> bumperData = parseTrickResponseInt(split(reply, '\t'));
|
||||
int bumperPoints = bumperData[0];
|
||||
enum PolygonType bumperShape = PolygonType((int)bumperData[1]);
|
||||
|
||||
templateString = "trick.var_add(\"dyn.table.bumpers[%d][0].renderedShape[%d][0]._x\")\ntrick.var_add(\"dyn.table.bumpers[%d][0].renderedShape[%d][0]._y\")\n";
|
||||
bumperRequests = "";
|
||||
for (int j = 0; j < bumperPoints; j++) {
|
||||
char buf[256];
|
||||
sprintf(buf, templateString, i, j, i, j);
|
||||
bumperRequests += std::string(buf);
|
||||
}
|
||||
socket << bumperRequests;
|
||||
socket << "trick.var_send() \ntrick.var_clear() \n";
|
||||
socket >> reply;
|
||||
int numPoints = getVar<int>(socket,format("dyn.table.bumpers[%d][0].numPoints", i));
|
||||
PolygonType bumperShapeType = PolygonType(getVar<int>(socket,format("dyn.table.bumpers[%d][0].shapeType", i)));
|
||||
|
||||
std::string request_bumper = format("dyn.table.bumpers[%d][0]", i);
|
||||
|
||||
std::string request_x = request_bumper + ".renderedShape[%d][0]._x";
|
||||
std::string request_y = request_bumper + ".renderedShape[%d][0]._y";
|
||||
|
||||
std::vector<double> list_x = getVarList<double>(socket, request_x, numPoints);
|
||||
std::vector<double> list_y = getVarList<double>(socket, request_y, numPoints);
|
||||
std::vector<double> bumperBorder = fold(list_x, list_y);
|
||||
table.addShape(bumperBorder, Eigen::Vector3d(0.2,0.4,0.2), true, bumperShapeType, layer_BUMPER);
|
||||
|
||||
std::vector<double> bumperBorder = parseTrickResponse(split(reply, '\t'));
|
||||
table.addShape(bumperBorder, Eigen::Vector3d(0.2,0.4,0.2), true, bumperShape, layer_BUMPER);
|
||||
}
|
||||
|
||||
|
||||
// socket << "trick.var_pause()\n";
|
||||
// Request all of the ball positions
|
||||
std::string positionRequest = "";
|
||||
templateString = "trick.var_add(\"dyn.table.balls[%d][0].pos._x\")\ntrick.var_add(\"dyn.table.balls[%d][0].pos._y\")\n";
|
||||
|
||||
std::vector<double> ball_x = getVarList<double>(socket, "dyn.table.balls[%d][0].pos._x", numBalls);
|
||||
std::vector<double> ball_y = getVarList<double>(socket, "dyn.table.balls[%d][0].pos._y", numBalls);
|
||||
for (int i = 0; i < numBalls; i++) {
|
||||
char buf[128];
|
||||
sprintf(buf, templateString, i, i);
|
||||
positionRequest += std::string(buf);
|
||||
}
|
||||
|
||||
socket << positionRequest;
|
||||
socket << "trick.var_send() \ntrick.var_clear() \n";
|
||||
socket >> reply;
|
||||
|
||||
auto positions = parseTrickResponse(split(reply, '\t'));
|
||||
|
||||
|
||||
for (int i = 0; i < numBalls; i++) {
|
||||
std::vector<double> circleData = {positions[(i*2)], positions[(i*2 + 1)], radii[i]};
|
||||
Eigen::Vector3d circleColor = ball_colors[i % ball_colors.size()];
|
||||
table.addShape(circleData, circleColor, false, CIRCLE, layer_BALL);
|
||||
table.addShape(std::vector<double>({ball_x[i], ball_y[i], radii[i]}), circleColor, false, CIRCLE, layer_BALL);
|
||||
}
|
||||
|
||||
bool mousePressed = false;
|
||||
@ -740,7 +716,7 @@ int main(int argc, char *argv[])
|
||||
view->callback_pre_draw = [&](igl::opengl::glfw::Viewer& viewer) -> bool {
|
||||
// Look for new data and redraw
|
||||
socket >> reply;
|
||||
std::vector<double> replyData = parseTrickResponse(split(reply, '\t'));
|
||||
std::vector<double> replyData = trickResponseConvert<double>(reply);
|
||||
|
||||
if (replyData.size() <= 1) {
|
||||
return false;
|
||||
@ -824,8 +800,8 @@ int main(int argc, char *argv[])
|
||||
// Need to get nBalls and positions every time
|
||||
socket << "trick.var_pause() \n";
|
||||
socket << "trick.var_add(\"dyn.table.numBalls\")\n";
|
||||
positionRequest = "";
|
||||
templateString = "trick.var_add(\"dyn.table.balls[%d][0].pos._x\")\ntrick.var_add(\"dyn.table.balls[%d][0].pos._y\")\ntrick.var_add(\"dyn.table.balls[%d][0].inPlay\")\n";
|
||||
std::string positionRequest = "";
|
||||
char * templateString = "trick.var_add(\"dyn.table.balls[%d][0].pos._x\")\ntrick.var_add(\"dyn.table.balls[%d][0].pos._y\")\ntrick.var_add(\"dyn.table.balls[%d][0].inPlay\")\n";
|
||||
for (int i = 0; i < numBalls; i++) {
|
||||
char buf[128];
|
||||
sprintf(buf, templateString, i, i, i);
|
||||
|
@ -579,7 +579,6 @@ int Trick::DataRecordGroup::data_record(double in_time) {
|
||||
bool change_detected = false ;
|
||||
|
||||
//TODO: does not handle bitfields correctly!
|
||||
|
||||
if ( record == true ) {
|
||||
if ( freq != DR_Always ) {
|
||||
for (jj = 0; jj < change_buffer.size() ; jj++) {
|
||||
@ -691,6 +690,7 @@ int Trick::DataRecordGroup::write_data(bool must_write) {
|
||||
// buffer_mutex is used in this one place to prevent forced calls of write_data
|
||||
// to not overwrite data being written by the asynchronous thread.
|
||||
pthread_mutex_lock(&buffer_mutex) ;
|
||||
|
||||
local_buffer_num = buffer_num ;
|
||||
if ( (local_buffer_num - writer_num) > max_num ) {
|
||||
num_to_write = max_num ;
|
||||
|
@ -56,7 +56,7 @@ void Trick::TestSuite::delete_test_results() {
|
||||
Trick::UnitTest::UnitTest() {
|
||||
the_unit_test_output = this ;
|
||||
enabled = false ;
|
||||
exit_code_enabled = false ;
|
||||
exit_code_enabled = true ;
|
||||
file_name = std::string("test_details.xml") ;
|
||||
name = std::string("AllTests") ;
|
||||
}
|
||||
|
@ -46,17 +46,18 @@ REF2* Trick::VariableServerThread::make_error_ref(std::string in_name) {
|
||||
return new_ref;
|
||||
}
|
||||
|
||||
int Trick::VariableServerThread::var_add(std::string in_name) {
|
||||
|
||||
VariableReference * new_var ;
|
||||
Trick::VariableReference* Trick::VariableServerThread::create_var_reference(std::string in_name) {
|
||||
REF2 * new_ref ;
|
||||
|
||||
// Time var is treated specially
|
||||
if ( in_name.compare("time") == 0 ) {
|
||||
new_ref = make_time_ref() ;
|
||||
} else {
|
||||
// otherwise ref_attributes takes care of the hard part
|
||||
new_ref = ref_attributes(in_name.c_str()) ;
|
||||
}
|
||||
|
||||
// Check error cases
|
||||
if ( new_ref == NULL ) {
|
||||
message_publish(MSG_ERROR, "Variable Server could not find variable %s.\n", in_name.c_str());
|
||||
new_ref = make_error_ref(in_name);
|
||||
@ -81,7 +82,12 @@ int Trick::VariableServerThread::var_add(std::string in_name) {
|
||||
new_ref = make_error_ref(in_name);
|
||||
}
|
||||
|
||||
new_var = new VariableReference(new_ref) ;
|
||||
// Actually constructs the variable reference in the success case
|
||||
return new VariableReference(new_ref) ;
|
||||
}
|
||||
|
||||
int Trick::VariableServerThread::var_add(std::string in_name) {
|
||||
VariableReference * new_var = create_var_reference(in_name);
|
||||
vars.push_back(new_var) ;
|
||||
|
||||
return(0) ;
|
||||
@ -93,6 +99,36 @@ int Trick::VariableServerThread::var_add(std::string var_name, std::string units
|
||||
return(0) ;
|
||||
}
|
||||
|
||||
// Helper function for var_send_once
|
||||
std::vector<std::string> split (const std::string& str, const char delim) {
|
||||
std::stringstream ss(str);
|
||||
std::string s;
|
||||
std::vector<std::string> ret;
|
||||
while (std::getline(ss, s, delim)) {
|
||||
ret.push_back(s);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Trick::VariableServerThread::var_send_once(std::string in_name, int num_vars) {
|
||||
std::vector<std::string> var_names = split(in_name, ',');
|
||||
|
||||
if (var_names.size() != num_vars) {
|
||||
message_publish(MSG_ERROR, "Number of variables sent to var_send_once (%d) does not match num_vars (%d).\n", var_names.size(), num_vars);
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::vector<VariableReference *> given_vars;
|
||||
for (auto& varName : var_names) {
|
||||
given_vars.push_back(create_var_reference(varName));
|
||||
}
|
||||
copy_sim_data(given_vars, false);
|
||||
write_data(given_vars);
|
||||
|
||||
return(0) ;
|
||||
}
|
||||
|
||||
|
||||
int Trick::VariableServerThread::var_remove(std::string in_name) {
|
||||
|
||||
unsigned int ii ;
|
||||
@ -218,6 +254,7 @@ int Trick::VariableServerThread::var_clear() {
|
||||
return(0) ;
|
||||
}
|
||||
|
||||
|
||||
int Trick::VariableServerThread::var_send() {
|
||||
copy_sim_data();
|
||||
write_data();
|
||||
|
@ -7,23 +7,24 @@
|
||||
#include "trick/exec_proto.h"
|
||||
|
||||
int Trick::VariableServerThread::copy_sim_data() {
|
||||
return copy_sim_data(vars, true);
|
||||
}
|
||||
|
||||
unsigned int ii ;
|
||||
VariableReference * curr_var ;
|
||||
int Trick::VariableServerThread::copy_sim_data(std::vector<VariableReference *> given_vars, bool cyclical) {
|
||||
|
||||
if ( vars.size() == 0 ) {
|
||||
return 0 ;
|
||||
if (given_vars.size() == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( pthread_mutex_trylock(©_mutex) == 0 ) {
|
||||
|
||||
// Get the simulation time we start this copy
|
||||
time = (double)exec_get_time_tics() / exec_get_time_tic_value() ;
|
||||
if (cyclical) {
|
||||
time = (double)exec_get_time_tics() / exec_get_time_tic_value() ;
|
||||
}
|
||||
|
||||
for ( ii = 0 ; ii < vars.size() ; ii++ ) {
|
||||
curr_var = vars[ii] ;
|
||||
for (auto curr_var : given_vars ) {
|
||||
|
||||
// if this variable is unresolved, try to resolve it
|
||||
if (curr_var->ref->address == &bad_ref_int) {
|
||||
REF2 *new_ref = ref_attributes(curr_var->ref->reference);
|
||||
if (new_ref != NULL) {
|
||||
@ -45,9 +46,9 @@ int Trick::VariableServerThread::copy_sim_data() {
|
||||
// any of the memory blocks it knows of. Don't do this if we have a std::string or
|
||||
// wstring type, or we already are pointing to a bad ref.
|
||||
if ( (curr_var->string_type != TRICK_STRING) and
|
||||
(curr_var->string_type != TRICK_WSTRING) and
|
||||
(curr_var->ref->address != &bad_ref_int) and
|
||||
(get_alloc_info_of(curr_var->address) == NULL) ) {
|
||||
(curr_var->string_type != TRICK_WSTRING) and
|
||||
(curr_var->ref->address != &bad_ref_int) and
|
||||
(get_alloc_info_of(curr_var->address) == NULL) ) {
|
||||
std::string save_name(curr_var->ref->reference) ;
|
||||
free(curr_var->ref) ;
|
||||
curr_var->ref = make_error_ref(save_name) ;
|
||||
@ -92,14 +93,13 @@ int Trick::VariableServerThread::copy_sim_data() {
|
||||
}
|
||||
|
||||
// Indicate that sim data has been written and is now ready in the buffer_in's of the vars variable list.
|
||||
var_data_staged = true;
|
||||
packets_copied++ ;
|
||||
if (cyclical) {
|
||||
var_data_staged = true;
|
||||
packets_copied++ ;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(©_mutex) ;
|
||||
}
|
||||
|
||||
|
||||
return (0) ;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -179,8 +179,9 @@ void * Trick::VariableServerThread::thread_body() {
|
||||
} catch (...) {
|
||||
#ifdef __linux
|
||||
#ifdef __GNUC__
|
||||
#if __GNUC__ == 4 && __GNUC_MINOR__ == 1
|
||||
//for gcc 4.1.2 or whatever glib version in RHEL 5 that does not work with the abi::__forced_unwind
|
||||
#if (__GNUC__ == 4 && __GNUC_MINOR__ == 1) || __GNUC__ == 12
|
||||
// for gcc 4.1.2 or whatever glib version in RHEL 5 that does not work with the abi::__forced_unwind
|
||||
// Also seems to have a problem with gcc 12
|
||||
throw;
|
||||
#else
|
||||
message_publish(MSG_ERROR, "\nVARIABLE SERVER caught unknown exception\n" ) ;
|
||||
|
@ -6,7 +6,6 @@ PROGRAMMERS: (((Alex Lin) (NASA) (8/06) (--)))
|
||||
#include <iostream>
|
||||
#include <pthread.h>
|
||||
#include "trick/VariableServer.hh"
|
||||
#include "trick/variable_server_message_types.h"
|
||||
#include "trick/parameter_types.h"
|
||||
#include "trick/bitfield_proto.h"
|
||||
#include "trick/trick_byteswap.h"
|
||||
@ -21,7 +20,9 @@ extern "C" {
|
||||
|
||||
#define MAX_MSG_LEN 8192
|
||||
|
||||
int Trick::VariableServerThread::write_binary_data( int Start, char *buf1, int PacketNum ) {
|
||||
|
||||
int Trick::VariableServerThread::write_binary_data( int Start, char *buf1, const std::vector<VariableReference *>& given_vars, VS_MESSAGE_TYPE message_type) {
|
||||
int vars = 0;
|
||||
int i;
|
||||
int ret ;
|
||||
int HeaderSize, MessageSize;
|
||||
@ -32,27 +33,28 @@ int Trick::VariableServerThread::write_binary_data( int Start, char *buf1, int P
|
||||
char * address = 0 ;
|
||||
char* param_name;
|
||||
|
||||
//remove warning for unused PacketNum... to be deleted.
|
||||
(void)PacketNum ;
|
||||
|
||||
/* start the offset 4 bytes into the message, we'll subtract the sizeof offset at the end */
|
||||
offset = sizeof(msg_type) + sizeof(offset) ;
|
||||
|
||||
/* if we are here the msg_type is good, so send a 0, swapped or not 0 is still 0 */
|
||||
msg_type = VS_VAR_LIST ;
|
||||
if (byteswap) {
|
||||
/* Swap message type bytes */
|
||||
msg_type = trick_byteswap_int((int)message_type) ;
|
||||
} else {
|
||||
msg_type = message_type;
|
||||
}
|
||||
memcpy(buf1, &msg_type , sizeof(msg_type)) ;
|
||||
HeaderSize = sizeof(msg_type);
|
||||
|
||||
offset += sizeof(unsigned int) ;
|
||||
HeaderSize += sizeof(unsigned int);
|
||||
|
||||
for (i = Start; i < (int)vars.size() ; i++) {
|
||||
for (i = Start; i < (int)given_vars.size() ; i++) {
|
||||
|
||||
// data to send was copied to buffer in copy_sim_data
|
||||
address = (char *)vars[i]->buffer_out;
|
||||
size = vars[i]->size ;
|
||||
address = (char *)given_vars[i]->buffer_out;
|
||||
size = given_vars[i]->size ;
|
||||
|
||||
param_name = vars[i]->ref->reference;
|
||||
param_name = given_vars[i]->ref->reference;
|
||||
len = strlen(param_name) ;
|
||||
// when var_binary_nonames, do not put the variable names into the message to be sent
|
||||
if (binary_data_nonames) {
|
||||
@ -66,7 +68,7 @@ int Trick::VariableServerThread::write_binary_data( int Start, char *buf1, int P
|
||||
message_publish(MSG_WARNING, "%p Variable Server buffer[%d] too small (need %d) for symbol %s, SKIPPING IT.\n",
|
||||
&connection, MAX_MSG_LEN,
|
||||
(int)(HeaderSize + MessageSize),
|
||||
vars[i]->ref->reference );
|
||||
given_vars[i]->ref->reference );
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -81,7 +83,7 @@ int Trick::VariableServerThread::write_binary_data( int Start, char *buf1, int P
|
||||
offset += len ;
|
||||
}
|
||||
|
||||
swap_int = trick_byteswap_int(vars[i]->ref->attr->type) ;
|
||||
swap_int = trick_byteswap_int(given_vars[i]->ref->attr->type) ;
|
||||
memcpy(&buf1[offset] , &swap_int , sizeof(int)) ;
|
||||
offset += sizeof(int) ;
|
||||
|
||||
@ -90,7 +92,7 @@ int Trick::VariableServerThread::write_binary_data( int Start, char *buf1, int P
|
||||
offset += sizeof(size) ;
|
||||
|
||||
/* TODO: There is a bug here, this call will want to swap the entire buffer, we may not have the whole buffer */
|
||||
trick_bswap_buffer(&buf1[offset], address, vars[i]->ref->attr, 1);
|
||||
trick_bswap_buffer(&buf1[offset], address, given_vars[i]->ref->attr, 1);
|
||||
offset += size ;
|
||||
}
|
||||
else {
|
||||
@ -105,21 +107,21 @@ int Trick::VariableServerThread::write_binary_data( int Start, char *buf1, int P
|
||||
offset += len ;
|
||||
}
|
||||
|
||||
memcpy(&buf1[offset] , &vars[i]->ref->attr->type , sizeof(int)) ;
|
||||
memcpy(&buf1[offset] , &given_vars[i]->ref->attr->type , sizeof(int)) ;
|
||||
offset += sizeof(int) ;
|
||||
|
||||
memcpy(&buf1[offset] , &size , sizeof(size)) ;
|
||||
offset += sizeof(size) ;
|
||||
|
||||
switch ( vars[i]->ref->attr->type ) {
|
||||
switch ( given_vars[i]->ref->attr->type ) {
|
||||
case TRICK_BITFIELD:
|
||||
temp_i = GET_BITFIELD(address , vars[i]->ref->attr->size ,
|
||||
vars[i]->ref->attr->index[0].start, vars[i]->ref->attr->index[0].size) ;
|
||||
temp_i = GET_BITFIELD(address , given_vars[i]->ref->attr->size ,
|
||||
given_vars[i]->ref->attr->index[0].start, given_vars[i]->ref->attr->index[0].size) ;
|
||||
memcpy(&buf1[offset] , &temp_i , (size_t)size) ;
|
||||
break ;
|
||||
case TRICK_UNSIGNED_BITFIELD:
|
||||
temp_ui = GET_UNSIGNED_BITFIELD(address , vars[i]->ref->attr->size ,
|
||||
vars[i]->ref->attr->index[0].start, vars[i]->ref->attr->index[0].size) ;
|
||||
temp_ui = GET_UNSIGNED_BITFIELD(address , given_vars[i]->ref->attr->size ,
|
||||
given_vars[i]->ref->attr->index[0].start, given_vars[i]->ref->attr->index[0].size) ;
|
||||
memcpy(&buf1[offset] , &temp_ui , (size_t)size) ;
|
||||
break ;
|
||||
case TRICK_NUMBER_OF_TYPES:
|
||||
@ -176,6 +178,65 @@ int Trick::VariableServerThread::write_binary_data( int Start, char *buf1, int P
|
||||
return i;
|
||||
}
|
||||
|
||||
int Trick::VariableServerThread::write_ascii_data(char * dest_buf, const std::vector<VariableReference *>& given_vars, VS_MESSAGE_TYPE message_type ) {
|
||||
|
||||
sprintf(dest_buf, "%d\t", message_type) ;
|
||||
|
||||
for (int i = 0; i < given_vars.size(); i++) {
|
||||
char curr_buf[MAX_MSG_LEN];
|
||||
int ret = vs_format_ascii( given_vars[i] , curr_buf);
|
||||
|
||||
if (ret < 0) {
|
||||
message_publish(MSG_WARNING, "%p Variable Server string buffer[%d] too small for symbol %s, TRUNCATED IT.\n",
|
||||
&connection, MAX_MSG_LEN, given_vars[i]->ref->reference );
|
||||
}
|
||||
|
||||
/* make sure this message will fit in a packet by itself */
|
||||
if( strlen( curr_buf ) + 2 > MAX_MSG_LEN ) {
|
||||
message_publish(MSG_WARNING, "%p Variable Server buffer[%d] too small for symbol %s, TRUNCATED IT.\n",
|
||||
&connection, MAX_MSG_LEN, given_vars[i]->ref->reference );
|
||||
curr_buf[MAX_MSG_LEN - 1] = '\0';
|
||||
}
|
||||
|
||||
int len = strlen(dest_buf) ;
|
||||
|
||||
/* make sure there is space for the next tab or next newline and null */
|
||||
if( len + strlen( curr_buf ) + 2 > MAX_MSG_LEN ) {
|
||||
// If there isn't, send incomplete message
|
||||
if (debug >= 2) {
|
||||
message_publish(MSG_DEBUG, "%p tag=<%s> var_server sending %d ascii bytes:\n%s\n",
|
||||
&connection, connection.client_tag, (int)strlen(dest_buf), dest_buf) ;
|
||||
}
|
||||
|
||||
ret = tc_write(&connection, (char *) dest_buf, len);
|
||||
if ( ret != len ) {
|
||||
return(-1) ;
|
||||
}
|
||||
dest_buf[0] = '\0';
|
||||
}
|
||||
|
||||
strcat(dest_buf, curr_buf);
|
||||
strcat(dest_buf, "\t");
|
||||
}
|
||||
|
||||
int len = strlen(dest_buf) ;
|
||||
|
||||
if ( len > 0 ) {
|
||||
dest_buf[ strlen(dest_buf) - 1 ] = '\n';
|
||||
|
||||
if (debug >= 2) {
|
||||
message_publish(MSG_DEBUG, "%p tag=<%s> var_server sending %d ascii bytes:\n%s\n",
|
||||
&connection, connection.client_tag, (int)strlen(dest_buf), dest_buf) ;
|
||||
}
|
||||
int ret = tc_write(&connection, (char *) dest_buf, (int)strlen(dest_buf));
|
||||
if ( ret != (int)strlen(dest_buf) ) {
|
||||
return(-1) ;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Trick::VariableServerThread::write_data() {
|
||||
|
||||
int ret;
|
||||
@ -185,7 +246,7 @@ int Trick::VariableServerThread::write_data() {
|
||||
|
||||
// do not send anything when there are no variables!
|
||||
if ( vars.size() == 0 or packets_copied == 0 ) {
|
||||
return(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Acquire sole access to vars[ii]->buffer_in. */
|
||||
@ -204,77 +265,60 @@ int Trick::VariableServerThread::write_data() {
|
||||
pthread_mutex_unlock(©_mutex) ;
|
||||
|
||||
if (binary_data) {
|
||||
int Index = 0;
|
||||
int PacketNumber = 0;
|
||||
int index = 0;
|
||||
|
||||
do {
|
||||
ret = write_binary_data( Index, buf1, PacketNumber );
|
||||
ret = write_binary_data( index, buf1, vars, VS_VAR_LIST );
|
||||
if ( ret >= 0 ) {
|
||||
Index = ret ;
|
||||
index = ret ;
|
||||
} else {
|
||||
return(-1) ;
|
||||
}
|
||||
PacketNumber++;
|
||||
} while( Index < (int)vars.size() );
|
||||
} while( index < (int)vars.size() );
|
||||
|
||||
return 0;
|
||||
|
||||
} else { /* ascii mode */
|
||||
char val[MAX_MSG_LEN];
|
||||
|
||||
sprintf(buf1, "0\t") ;
|
||||
|
||||
for (i = 0; i < vars.size(); i++) {
|
||||
|
||||
ret = vs_format_ascii( vars[i] , val);
|
||||
|
||||
if (ret < 0) {
|
||||
message_publish(MSG_WARNING, "%p Variable Server string buffer[%d] too small for symbol %s, TRUNCATED IT.\n",
|
||||
&connection, MAX_MSG_LEN, vars[i]->ref->reference );
|
||||
}
|
||||
|
||||
/* make sure this message will fit in a packet by itself */
|
||||
if( strlen( val ) + 2 > MAX_MSG_LEN ) {
|
||||
message_publish(MSG_WARNING, "%p Variable Server buffer[%d] too small for symbol %s, TRUNCATED IT.\n",
|
||||
&connection, MAX_MSG_LEN, vars[i]->ref->reference );
|
||||
val[MAX_MSG_LEN - 1] = '\0';
|
||||
}
|
||||
|
||||
len = strlen(buf1) ;
|
||||
|
||||
/* make sure there is space for the next tab or next newline and null */
|
||||
if( len + strlen( val ) + 2 > MAX_MSG_LEN ) {
|
||||
|
||||
if (debug >= 2) {
|
||||
message_publish(MSG_DEBUG, "%p tag=<%s> var_server sending %d ascii bytes:\n%s\n",
|
||||
&connection, connection.client_tag, (int)strlen(buf1), buf1) ;
|
||||
}
|
||||
|
||||
ret = tc_write(&connection, (char *) buf1, len);
|
||||
if ( ret != len ) {
|
||||
return(-1) ;
|
||||
}
|
||||
buf1[0] = '\0';
|
||||
}
|
||||
|
||||
strcat(buf1, val);
|
||||
strcat(buf1, "\t");
|
||||
}
|
||||
|
||||
len = strlen(buf1) ;
|
||||
|
||||
if ( len > 0 ) {
|
||||
buf1[ strlen(buf1) - 1 ] = '\n';
|
||||
|
||||
if (debug >= 2) {
|
||||
message_publish(MSG_DEBUG, "%p tag=<%s> var_server sending %d ascii bytes:\n%s\n",
|
||||
&connection, connection.client_tag, (int)strlen(buf1), buf1) ;
|
||||
}
|
||||
ret = tc_write(&connection, (char *) buf1, (int)strlen(buf1));
|
||||
if ( ret != (int)strlen(buf1) ) {
|
||||
return(-1) ;
|
||||
}
|
||||
}
|
||||
return write_ascii_data(buf1, vars, VS_VAR_LIST );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Trick::VariableServerThread::write_data(std::vector<VariableReference *> given_vars) {
|
||||
// do not send anything when there are no variables!
|
||||
if ( given_vars.size() == 0) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Acquire sole access to vars[ii]->buffer_in. */
|
||||
if ( pthread_mutex_trylock(©_mutex) == 0 ) {
|
||||
// Swap buffer_in and buffer_out for each vars[ii].
|
||||
for (int i = 0 ; i < given_vars.size() ; i++ ) {
|
||||
void *temp_p = given_vars[i]->buffer_in;
|
||||
given_vars[i]->buffer_in = given_vars[i]->buffer_out;
|
||||
given_vars[i]->buffer_out = temp_p;
|
||||
}
|
||||
/* Relinquish sole access to vars[ii]->buffer_in. */
|
||||
pthread_mutex_unlock(©_mutex) ;
|
||||
|
||||
char buf1[ MAX_MSG_LEN ];
|
||||
|
||||
if (binary_data) {
|
||||
int index = 0;
|
||||
|
||||
do {
|
||||
int ret = write_binary_data( index, buf1, given_vars, VS_SEND_ONCE );
|
||||
if ( ret >= 0 ) {
|
||||
index = ret ;
|
||||
} else {
|
||||
return(-1) ;
|
||||
}
|
||||
} while( index < (int)given_vars.size() );
|
||||
|
||||
return 0;
|
||||
|
||||
} else { /* ascii mode */
|
||||
return write_ascii_data(buf1, given_vars, VS_SEND_ONCE);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
@ -60,6 +60,24 @@ int var_exists(std::string in_name) {
|
||||
return(0) ;
|
||||
}
|
||||
|
||||
int var_send_once(std::string in_name) {
|
||||
Trick::VariableServerThread * vst ;
|
||||
vst = get_vst() ;
|
||||
if (vst != NULL ) {
|
||||
vst->var_send_once(in_name, 1) ;
|
||||
}
|
||||
return(0) ;
|
||||
}
|
||||
|
||||
int var_send_once(std::string in_name, int num) {
|
||||
Trick::VariableServerThread * vst ;
|
||||
vst = get_vst() ;
|
||||
if (vst != NULL ) {
|
||||
vst->var_send_once(in_name, num) ;
|
||||
}
|
||||
return(0) ;
|
||||
}
|
||||
|
||||
int var_send() {
|
||||
Trick::VariableServerThread * vst ;
|
||||
vst = get_vst() ;
|
||||
|
Loading…
Reference in New Issue
Block a user