diff --git a/docs/documentation/simulation_capabilities/Variable-Server.md b/docs/documentation/simulation_capabilities/Variable-Server.md index 877f5352..5ae7c557 100644 --- a/docs/documentation/simulation_capabilities/Variable-Server.md +++ b/docs/documentation/simulation_capabilities/Variable-Server.md @@ -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 diff --git a/docs/tutorial/TutVariableServer.md b/docs/tutorial/TutVariableServer.md index 98c016bb..6e83e3dc 100644 --- a/docs/tutorial/TutVariableServer.md +++ b/docs/tutorial/TutVariableServer.md @@ -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| ### The Variable Server API @@ -545,6 +601,13 @@ Resume periodic responses. **var\_send()** - Send response immediately. + +**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 + **var\_clear()** - Clear the session variable list. diff --git a/include/trick/VariableServer.hh b/include/trick/VariableServer.hh index 9aee8409..cd2cb5ce 100644 --- a/include/trick/VariableServer.hh +++ b/include/trick/VariableServer.hh @@ -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) ; diff --git a/include/trick/VariableServerThread.hh b/include/trick/VariableServerThread.hh index 1b3ce499..cb133c2d 100644 --- a/include/trick/VariableServerThread.hh +++ b/include/trick/VariableServerThread.hh @@ -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("", ) @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 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 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& 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& 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. diff --git a/include/trick/variable_server_message_types.h b/include/trick/variable_server_message_types.h index a7280cbd..b2e317c3 100644 --- a/include/trick/variable_server_message_types.h +++ b/include/trick/variable_server_message_types.h @@ -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 diff --git a/test/SIM_test_varserv/S_define b/test/SIM_test_varserv/S_define index fb85f3fc..7fed83f8 100644 --- a/test/SIM_test_varserv/S_define +++ b/test/SIM_test_varserv/S_define @@ -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(); } }; diff --git a/test/SIM_test_varserv/models/varserv/include/VS.hh b/test/SIM_test_varserv/models/varserv/include/VS.hh index 69d9654e..93eade0c 100644 --- a/test/SIM_test_varserv/models/varserv/include/VS.hh +++ b/test/SIM_test_varserv/models/varserv/include/VS.hh @@ -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); diff --git a/test/SIM_test_varserv/models/varserv/src/VS_commands.cpp b/test/SIM_test_varserv/models/varserv/src/VS_commands.cpp index 9267b4cf..bf46ddda 100644 --- a/test/SIM_test_varserv/models/varserv/src/VS_commands.cpp +++ b/test/SIM_test_varserv/models/varserv/src/VS_commands.cpp @@ -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); } diff --git a/test/SIM_test_varserv/models/varserv/src/VS_default_data.cpp b/test/SIM_test_varserv/models/varserv/src/VS_default_data.cpp index 09cd1244..18697d16 100644 --- a/test/SIM_test_varserv/models/varserv/src/VS_default_data.cpp +++ b/test/SIM_test_varserv/models/varserv/src/VS_default_data.cpp @@ -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; + } } diff --git a/test/SIM_test_varserv/models/varserv/src/VS_init.cpp b/test/SIM_test_varserv/models/varserv/src/VS_init.cpp index 94439ffb..3d117024 100644 --- a/test/SIM_test_varserv/models/varserv/src/VS_init.cpp +++ b/test/SIM_test_varserv/models/varserv/src/VS_init.cpp @@ -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(hostest); - bob.port = port_num; + comm_device.hostname = const_cast(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"); diff --git a/test/SIM_test_varserv/models/varserv/src/VS_shutdown.cpp b/test/SIM_test_varserv/models/varserv/src/VS_shutdown.cpp index f340c282..c2018438 100644 --- a/test/SIM_test_varserv/models/varserv/src/VS_shutdown.cpp +++ b/test/SIM_test_varserv/models/varserv/src/VS_shutdown.cpp @@ -11,7 +11,7 @@ PROGRAMMERS: ( (Lindsay Landry) (L3) (9-12-2013) ) int VSTest::shutdown() { - tc_disconnect(&bob); + tc_disconnect(&comm_device); return(0); } diff --git a/test/SIM_test_varserv/models/varserv/src/VS_tests.cpp b/test/SIM_test_varserv/models/varserv/src/VS_tests.cpp index 9dffc393..69ce5bfd 100644 --- a/test/SIM_test_varserv/models/varserv/src/VS_tests.cpp +++ b/test/SIM_test_varserv/models/varserv/src/VS_tests.cpp @@ -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); -} diff --git a/test/SIM_test_varserv/models/varserv/src/VS_unittests.cpp b/test/SIM_test_varserv/models/varserv/src/VS_unittests.cpp deleted file mode 100644 index d3ab5cc5..00000000 --- a/test/SIM_test_varserv/models/varserv/src/VS_unittests.cpp +++ /dev/null @@ -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); -} - diff --git a/test/makefile b/test/makefile index 61b0b2ca..1bb0136d 100644 --- a/test/makefile +++ b/test/makefile @@ -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 ) diff --git a/trick_sims/SIM_billiards/models/graphics/cpp/main.cpp b/trick_sims/SIM_billiards/models/graphics/cpp/main.cpp index 003bc9ad..a444675c 100644 --- a/trick_sims/SIM_billiards/models/graphics/cpp/main.cpp +++ b/trick_sims/SIM_billiards/models/graphics/cpp/main.cpp @@ -1,5 +1,4 @@ #include -// #include #include #include #include @@ -13,6 +12,7 @@ #include "Socket.hh" +#define STR_MAX 1024 std::vector 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 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 staticShapes; + std::vector movingShapes; std::vector staticRenderedShapes; std::vector movingRenderedShapes; int numStaticVertices; int numStaticFaces; bool staticRendered = false; - - std::vector movingShapes; - }; void printUsage() { @@ -505,20 +498,76 @@ std::vector split (std::string& str, const char delim) { return ret; } -std::vector parseTrickResponse(std::vector list) { - std::vector ret; - for (int i = 1; i < list.size(); i++) { - ret.push_back(stod(list[i])); - } - return ret; +double totalTime = 0; +std::vector requestTime; + +template +T stringConvert (const std::string& str) +{ + std::istringstream ss(str); + T num; + ss >> num; + return num; } -std::vector parseTrickResponseInt(std::vector list) { - std::vector ret; - for (int i = 1; i < list.size(); i++) { - ret.push_back(stoi(list[i])); +template +std::vector trickResponseConvert (std::string& response) +{ + auto responseSplit = split(response, '\t'); + std::vector result; + // ignore index 0 + for (int i = 1; i < responseSplit.size(); i++) { + result.push_back(stringConvert(responseSplit[i])); + } + return result; +} + +template +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(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 +std::vector getVarList(Socket& socket, std::string varName, int num) { + std::string totalRequest = ""; + std::vector 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(reply); +} + +template +std::vector fold (const std::vector a, const std::vector b) { + std::vector 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(socket, "dyn.table.numBalls"); + // int numBalls = 16; + std::vector radii = getVarList(socket, "dyn.table.balls[%d][0].radius", numBalls); + int numTablePoints = getVar(socket, "dyn.table.numTablePoints"); + enum PolygonType tableShape = PolygonType(getVar(socket, "dyn.table.tableShapeType")); + std::vector table_x = getVarList(socket, "dyn.table.tableShape[%d][0]._x", numTablePoints); + std::vector table_y = getVarList(socket, "dyn.table.tableShape[%d][0]._y", numTablePoints); + std::vector 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 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 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 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(socket, "dyn.table.numPockets"); + + std::vector pocket_x = getVarList(socket, "dyn.table.pockets[%d][0].pos._x", numPockets); + std::vector pocket_y = getVarList(socket, "dyn.table.pockets[%d][0].pos._y", numPockets); + std::vector pocket_r = getVarList(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 pocketData = parseTrickResponse(split(reply, '\t')); - table.addShape(pocketData, Eigen::Vector3d(0.0, 0.0, 0.0), true, CIRCLE, layer_POCKET); + table.addShape(std::vector({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(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 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(socket,format("dyn.table.bumpers[%d][0].numPoints", i)); + PolygonType bumperShapeType = PolygonType(getVar(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 list_x = getVarList(socket, request_x, numPoints); + std::vector list_y = getVarList(socket, request_y, numPoints); + std::vector bumperBorder = fold(list_x, list_y); + table.addShape(bumperBorder, Eigen::Vector3d(0.2,0.4,0.2), true, bumperShapeType, layer_BUMPER); - std::vector 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 ball_x = getVarList(socket, "dyn.table.balls[%d][0].pos._x", numBalls); + std::vector ball_y = getVarList(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 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({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 replyData = parseTrickResponse(split(reply, '\t')); + std::vector replyData = trickResponseConvert(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); diff --git a/trick_source/sim_services/DataRecord/DataRecordGroup.cpp b/trick_source/sim_services/DataRecord/DataRecordGroup.cpp index 0055bc93..8ccabf6b 100644 --- a/trick_source/sim_services/DataRecord/DataRecordGroup.cpp +++ b/trick_source/sim_services/DataRecord/DataRecordGroup.cpp @@ -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 ; diff --git a/trick_source/sim_services/UnitTest/UnitTest.cpp b/trick_source/sim_services/UnitTest/UnitTest.cpp index 07137f80..0a4961f8 100644 --- a/trick_source/sim_services/UnitTest/UnitTest.cpp +++ b/trick_source/sim_services/UnitTest/UnitTest.cpp @@ -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") ; } diff --git a/trick_source/sim_services/VariableServer/VariableServerThread_commands.cpp b/trick_source/sim_services/VariableServer/VariableServerThread_commands.cpp index 3d1ebd2c..87585492 100644 --- a/trick_source/sim_services/VariableServer/VariableServerThread_commands.cpp +++ b/trick_source/sim_services/VariableServer/VariableServerThread_commands.cpp @@ -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 split (const std::string& str, const char delim) { + std::stringstream ss(str); + std::string s; + std::vector 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 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 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(); diff --git a/trick_source/sim_services/VariableServer/VariableServerThread_copy_sim_data.cpp b/trick_source/sim_services/VariableServer/VariableServerThread_copy_sim_data.cpp index 26d77f2d..611825ea 100644 --- a/trick_source/sim_services/VariableServer/VariableServerThread_copy_sim_data.cpp +++ b/trick_source/sim_services/VariableServer/VariableServerThread_copy_sim_data.cpp @@ -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 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; } - diff --git a/trick_source/sim_services/VariableServer/VariableServerThread_loop.cpp b/trick_source/sim_services/VariableServer/VariableServerThread_loop.cpp index 24c82b52..a5190eed 100644 --- a/trick_source/sim_services/VariableServer/VariableServerThread_loop.cpp +++ b/trick_source/sim_services/VariableServer/VariableServerThread_loop.cpp @@ -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" ) ; diff --git a/trick_source/sim_services/VariableServer/VariableServerThread_write_data.cpp b/trick_source/sim_services/VariableServer/VariableServerThread_write_data.cpp index 57717271..59a064ec 100644 --- a/trick_source/sim_services/VariableServer/VariableServerThread_write_data.cpp +++ b/trick_source/sim_services/VariableServer/VariableServerThread_write_data.cpp @@ -6,7 +6,6 @@ PROGRAMMERS: (((Alex Lin) (NASA) (8/06) (--))) #include #include #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& 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& 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 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); } diff --git a/trick_source/sim_services/VariableServer/var_server_ext.cpp b/trick_source/sim_services/VariableServer/var_server_ext.cpp index 5a569b02..dffa6ad9 100644 --- a/trick_source/sim_services/VariableServer/var_server_ext.cpp +++ b/trick_source/sim_services/VariableServer/var_server_ext.cpp @@ -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() ;