trick/trick_source/sim_services/VariableServer/VariableServerThread_commands.cpp
Alex Lin fb7432d096 Add direct STL checkpointing
Modified ICG to save the non-canonical name for STLs.  This is typically more readable
because it is shorter.  Added code to the variable server to filter out requests accessing
STLs, because those accesses will not currently work.

refs #206
2016-04-04 15:07:57 -05:00

434 lines
13 KiB
C++

#include <string.h>
#include <iostream>
#include <stdlib.h>
#include "trick/VariableServer.hh"
#include "trick/variable_server_message_types.h"
#include "trick/memorymanager_c_intf.h"
#include "trick/tc_proto.h"
#include "trick/exec_proto.h"
#include "trick/command_line_protos.h"
#include "trick/Unit.hh"
#include "trick/message_proto.h"
#include "trick/message_type.h"
#include "trick/TrickConstant.hh"
#include "trick/sie_c_intf.h"
int Trick::VariableServerThread::bad_ref_int = 0 ;
int Trick::VariableServerThread::do_not_resolve_bad_ref_int = 0 ;
REF2* Trick::VariableServerThread::make_time_ref() {
REF2* new_ref;
new_ref = (REF2*)calloc(1, sizeof(REF2));
new_ref->reference = strdup("time") ;
new_ref->units = strdup("s") ;
new_ref->address = (char *)&time ;
new_ref->attr = (ATTRIBUTES*)calloc(1, sizeof(ATTRIBUTES)) ;
new_ref->attr->type = TRICK_DOUBLE ;
new_ref->attr->units = strdup("s") ;
new_ref->attr->size = sizeof(double) ;
return new_ref;
}
REF2* Trick::VariableServerThread::make_error_ref(std::string in_name) {
REF2* new_ref;
new_ref = (REF2*)calloc(1, sizeof(REF2));
new_ref->reference = strdup(in_name.c_str()) ;
new_ref->units = NULL ;
new_ref->address = (char *)&bad_ref_int ;
new_ref->attr = (ATTRIBUTES*)calloc(1, sizeof(ATTRIBUTES)) ;
new_ref->attr->type = TRICK_NUMBER_OF_TYPES ;
new_ref->attr->units = (char *)"--" ;
new_ref->attr->size = sizeof(int) ;
return new_ref;
}
int Trick::VariableServerThread::var_add(std::string in_name) {
VariableReference * new_var ;
REF2 * new_ref ;
if ( in_name.compare("time") == 0 ) {
new_ref = make_time_ref() ;
} else {
new_ref = ref_attributes(const_cast<char*>(in_name.c_str())) ;
}
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);
} else if ( new_ref->attr ) {
if ( new_ref->attr->type == TRICK_STRUCTURED ) {
message_publish(MSG_ERROR, "Variable Server: var_add cant add \"%s\" because its a composite variable.\n", in_name.c_str());
// Replace the REF2 object we got from ref_attributes with an error-ref.
free(new_ref);
new_ref = make_error_ref(in_name);
// set the address of the data to the do_not_resolve address. We won't retry resolving the name
new_ref->address = (char *)&do_not_resolve_bad_ref_int ;
} else if ( new_ref->attr->type == TRICK_STL ) {
message_publish(MSG_ERROR, "Variable Server: var_add cant add \"%s\" because its an STL variable.\n", in_name.c_str());
// Replace the REF2 object we got from ref_attributes with an error-ref.
free(new_ref);
new_ref = make_error_ref(in_name);
// set the address of the data to the do_not_resolve address. We won't retry resolving the name
new_ref->address = (char *)&do_not_resolve_bad_ref_int ;
}
} else {
message_publish(MSG_ERROR, "Variable Server: BAD MOJO - Missing ATTRIBUTES.");
new_ref = make_error_ref(in_name);
}
new_var = new VariableReference(new_ref) ;
vars.push_back(new_var) ;
return(0) ;
}
int Trick::VariableServerThread::var_add(std::string var_name, std::string units_name) {
var_add(var_name) ;
var_units(var_name, units_name) ;
return(0) ;
}
int Trick::VariableServerThread::var_remove(std::string in_name) {
unsigned int ii ;
for ( ii = 0 ; ii < vars.size() ; ii++ ) {
std::string var_name = vars[ii]->ref->reference;
if ( ! var_name.compare(in_name) ) {
vars.erase(vars.begin() + ii) ;
break ;
}
}
return(0) ;
}
int Trick::VariableServerThread::var_units(std::string var_name, std::string units_name) {
unsigned int ii ;
for ( ii = 0 ; ii < vars.size() ; ii++ ) {
if ( ! std::string(vars[ii]->ref->reference).compare(var_name) ) {
if (!units_name.compare("xx")) {
vars[ii]->ref->units = strdup(vars[ii]->ref->attr->units);
}
else {
Unit orig_units(vars[ii]->ref->attr->units) ;
try {
vars[ii]->conversion_factor = orig_units.Conversion_to(units_name.c_str()) ;
vars[ii]->ref->units = strdup(units_name.c_str());
}
catch (Unit::CONVERSION_ERROR & ce_err ) {
message_publish(MSG_ERROR, "Variable Server Error: var_units Units conversion error for \"%s\".\n",var_name.c_str());
return(-1) ;
}
}
}
}
return(0) ;
}
int Trick::VariableServerThread::var_exists(std::string in_name) {
char buf1[5] ;
bool error = false ;
unsigned int msg_type ;
REF2* var_ref = ref_attributes(const_cast<char*>(in_name.c_str()));
if ( var_ref == (REF2*)NULL ) {
error = true;
}
if (binary_data) {
/* send binary 1 or 0 */
msg_type = VS_VAR_EXISTS ;
memcpy(buf1, &msg_type , sizeof(msg_type)) ;
buf1[4] = (error==false);
if (debug >= 2) {
message_publish(MSG_DEBUG, "%p tag=<%s> var_server sending 1 binary byte\n", &connection, connection.client_tag);
}
tc_write(&connection, (char *) buf1, 5);
} else {
/* send ascii "1" or "0" */
sprintf(buf1, "%d\t%d\n", VS_VAR_EXISTS, (error==false));
if (debug >= 2) {
message_publish(MSG_DEBUG, "%p tag=<%s> var_server sending:", &connection, connection.client_tag) ;
message_publish(MSG_NORMAL, "%s\n", buf1);
}
tc_write(&connection, (char *) buf1, strlen(buf1));
}
return(0) ;
}
int Trick::VariableServerThread::var_clear() {
vars.clear() ;
return(0) ;
}
int Trick::VariableServerThread::var_send() {
copy_sim_data();
write_data();
return(0) ;
}
int Trick::VariableServerThread::var_cycle(double in_rate) {
update_rate = in_rate ;
cycle_tics = (long long)(update_rate * exec_get_time_tic_value()) ;
return(0) ;
}
bool Trick::VariableServerThread::get_pause() {
return pause_cmd ;
}
void Trick::VariableServerThread::set_pause( bool on_off) {
pause_cmd = on_off ;
}
int Trick::VariableServerThread::var_exit() {
exit_cmd = true ;
return(0) ;
}
int Trick::VariableServerThread::var_validate_address(bool on_off) {
validate_address = on_off ;
return(0) ;
}
int Trick::VariableServerThread::var_debug(int level) {
debug = level ;
return(0) ;
}
int Trick::VariableServerThread::var_ascii() {
binary_data = 0 ;
return(0) ;
}
int Trick::VariableServerThread::var_binary() {
binary_data = 1 ;
return(0) ;
}
int Trick::VariableServerThread::var_binary_nonames() {
binary_data = 1 ;
binary_data_nonames = 1 ;
return(0) ;
}
int Trick::VariableServerThread::var_set_copy_mode(int mode) {
if ( mode >= VS_COPY_ASYNC and mode <= VS_COPY_TOP_OF_FRAME ) {
copy_mode = (VS_COPY_MODE)mode ;
if ( copy_mode == VS_COPY_SCHEDULED ) {
long long sim_time_tics ;
sim_time_tics = exec_get_time_tics() ;
// round the next call time to a multiple of the cycle
sim_time_tics -= sim_time_tics % cycle_tics ;
next_tics = sim_time_tics + cycle_tics ;
sim_time_tics = exec_get_freeze_time_tics() ;
// round the next call time to a multiple of the cycle
sim_time_tics -= sim_time_tics % cycle_tics ;
freeze_next_tics = sim_time_tics + cycle_tics ;
} else {
next_tics = TRICK_MAX_LONG_LONG ;
}
return 0 ;
}
return -1 ;
}
int Trick::VariableServerThread::var_set_write_mode(int mode) {
if ( mode >= VS_WRITE_ASYNC and mode <= VS_WRITE_WHEN_COPIED ) {
write_mode = (VS_WRITE_MODE)mode ;
return 0 ;
}
return -1 ;
}
int Trick::VariableServerThread::var_sync(int mode) {
switch (mode) {
case 1:
var_set_copy_mode(VS_COPY_SCHEDULED) ;
var_set_write_mode(VS_WRITE_ASYNC) ;
break ;
case 2:
var_set_copy_mode(VS_COPY_SCHEDULED) ;
var_set_write_mode(VS_WRITE_WHEN_COPIED) ;
break ;
case 0:
default:
var_set_copy_mode(VS_COPY_ASYNC) ;
var_set_write_mode(VS_WRITE_ASYNC) ;
break ;
}
return 0 ;
}
int Trick::VariableServerThread::var_set_frame_multiple(unsigned int mult) {
frame_multiple = mult ;
return 0 ;
}
int Trick::VariableServerThread::var_set_frame_offset(unsigned int offset) {
frame_offset = offset ;
return 0 ;
}
int Trick::VariableServerThread::var_set_freeze_frame_multiple(unsigned int mult) {
freeze_frame_multiple = mult ;
return 0 ;
}
int Trick::VariableServerThread::var_set_freeze_frame_offset(unsigned int offset) {
freeze_frame_offset = offset ;
return 0 ;
}
int Trick::VariableServerThread::var_byteswap(bool on_off) {
byteswap = on_off ;
return(0) ;
}
bool Trick::VariableServerThread::get_send_stdio() {
return send_stdio ;
}
int Trick::VariableServerThread::set_send_stdio(bool on_off) {
send_stdio = on_off ;
return(0) ;
}
int Trick::VariableServerThread::var_signal() {
message_publish(MSG_ERROR,"Variable Server Error: var_signal is currently not implemented.\n") ;
return(0) ;
}
int Trick::VariableServerThread::var_multicast(bool on_off) {
multicast = on_off ;
message_publish(MSG_ERROR, "Variable Server Error: var_multicast is currently not implemented.\n") ;
return(0) ;
}
int Trick::VariableServerThread::send_list_size() {
char buf1[12] ;
unsigned int msg_type ;
int var_count;
// send number of variables
var_count = vars.size();
if (binary_data) {
// send in the binary message header format:
// <message_indicator><message_size><number_of_variables>
msg_type = VS_LIST_SIZE;
memcpy(buf1, &msg_type , sizeof(msg_type)) ;
memset(&(buf1[4]), 0, sizeof(int)); // message size = 0
memcpy(&(buf1[8]), &var_count, sizeof(var_count));
if (debug >= 2) {
message_publish(MSG_DEBUG, "%p tag=<%s> var_server sending %d event variables\n", &connection, connection.client_tag, var_count);
}
tc_write(&connection, (char *) buf1, 12);
} else {
// ascii
sprintf(buf1, "%d\t%d\n", VS_LIST_SIZE, var_count);
if (debug >= 2) {
message_publish(MSG_DEBUG, "%p tag=<%s> var_server sending number of event variables:", &connection, connection.client_tag) ;
message_publish(MSG_NORMAL, "%s\n", buf1);
}
tc_write(&connection, (char *) buf1, strlen(buf1));
}
return 0 ;
}
int Trick::VariableServerThread::transmit_file(std::string sie_file) {
const unsigned int packet_size = 4095 ;
FILE * fp ;
unsigned int file_size ;
unsigned int current_size = 0 ;
unsigned int bytes_read ;
char buffer[packet_size] ;
int ret ;
if (debug >= 2) {
message_publish(MSG_DEBUG,"%p tag=<%s> var_server opening %s.\n", &connection, connection.client_tag, sie_file.c_str()) ;
}
if ((fp = fopen(sie_file.c_str() , "r")) == NULL ) {
message_publish(MSG_ERROR,"Variable Server Error: Cannot open %s.\n", sie_file.c_str()) ;
sprintf(buffer, "%d\t-1\n", VS_SIE_RESOURCE) ;
tc_write(&connection , buffer , strlen(buffer)) ;
return(-1) ;
}
fseek(fp , 0L, SEEK_END) ;
file_size = ftell(fp) ;
sprintf(buffer, "%d\t%d\n" , VS_SIE_RESOURCE, file_size) ;
tc_write(&connection , buffer , strlen(buffer)) ;
rewind(fp) ;
// Switch to blocking writes since this could be a large transfer.
if (tc_blockio(&connection, TC_COMM_BLOCKIO)) {
message_publish(MSG_DEBUG,"Variable Server Error: Failed to set TCDevice to TC_COMM_BLOCKIO.\n");
}
while ( current_size < file_size ) {
bytes_read = fread(buffer , 1 , packet_size , fp) ;
ret = tc_write(&connection , buffer , bytes_read ) ;
if (ret != (int)bytes_read) {
message_publish(MSG_ERROR,"Variable Server Error: Failed to send SIE file.\n", sie_file.c_str()) ;
return(-1);
}
current_size += bytes_read ;
}
// Switch back to non-blocking writes.
if (tc_blockio(&connection, TC_COMM_NOBLOCKIO)) {
message_publish(MSG_ERROR,"Variable Server Error: Failed to set TCDevice to TC_COMM_NOBLOCKIO.\n");
return(-1);
}
return(0) ;
}
int Trick::VariableServerThread::send_file(std::string file_name) {
return transmit_file(file_name) ;
}
int Trick::VariableServerThread::send_sie_resource() {
sie_print_xml() ;
return transmit_file(std::string(command_line_args_get_default_dir()) + "/S_sie.resource") ;
}
int Trick::VariableServerThread::send_sie_class() {
sie_class_attr_map_print_xml() ;
return transmit_file(std::string(command_line_args_get_default_dir()) + "/" + "S_sie_class.xml") ;
}
int Trick::VariableServerThread::send_sie_enum() {
sie_enum_attr_map_print_xml() ;
return transmit_file(std::string(command_line_args_get_default_dir()) + "/" + "S_sie_enum.xml") ;
}
int Trick::VariableServerThread::send_sie_top_level_objects() {
sie_top_level_objects_print_xml() ;
return transmit_file(std::string(command_line_args_get_default_dir()) + "/" + "S_sie_top_level_objects.xml") ;
}