2015-02-26 15:02:31 +00:00
|
|
|
/*
|
|
|
|
PURPOSE: ( Python input processor )
|
|
|
|
REFERENCE: ( Trick Simulation Environment )
|
|
|
|
ASSUMPTIONS AND LIMITATIONS: ( None )
|
|
|
|
CLASS: ( N/A )
|
|
|
|
LIBRARY DEPENDENCY: ( None )
|
|
|
|
PROGRAMMERS: ( Alex Lin NASA 2009 )
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <Python.h>
|
|
|
|
#include <iostream>
|
|
|
|
#include <sstream>
|
|
|
|
#include <vector>
|
|
|
|
#include <string>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <string.h>
|
2024-03-27 19:20:58 +00:00
|
|
|
#include <stdio.h>
|
2015-02-26 15:02:31 +00:00
|
|
|
|
2015-06-01 15:28:29 +00:00
|
|
|
#include "trick/IPPython.hh"
|
|
|
|
#include "trick/MemoryManager.hh"
|
|
|
|
#include "trick/exec_proto.hh"
|
|
|
|
#include "trick/exec_proto.h"
|
2019-06-18 15:59:51 +00:00
|
|
|
#include "trick/message_proto.h"
|
2015-02-26 15:02:31 +00:00
|
|
|
|
|
|
|
Trick::IPPython * the_pip ;
|
|
|
|
|
|
|
|
//Constructor
|
2017-04-20 16:34:50 +00:00
|
|
|
Trick::IPPython::IPPython() : Trick::InputProcessor::InputProcessor() , units_conversion_msgs(true) {
|
2015-02-26 15:02:31 +00:00
|
|
|
the_pip = this ;
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
|
2024-03-27 19:20:58 +00:00
|
|
|
|
|
|
|
// Need to save the state of the main thread to allow child threads to run PyRun variants.
|
|
|
|
static PyThreadState *_save = NULL;
|
|
|
|
|
2015-02-26 15:02:31 +00:00
|
|
|
/**
|
|
|
|
@details
|
|
|
|
-# Loops through all of the memorymanager allocations testing if a name handle was given.
|
|
|
|
-# If a name and a user type_name were given to the allocation
|
|
|
|
-# If the user_type_name is not a Trick core class, prefixed with "Trick::"
|
|
|
|
-# Create a python statement to assign the python name to an address: <name> = trick.castAsTYPE(int(<address>))
|
|
|
|
-# Run the statement in the python interpreter
|
|
|
|
*/
|
|
|
|
void Trick::IPPython::get_TMM_named_variables() {
|
|
|
|
//std::cout << "top level names at initialization" << std::endl ;
|
|
|
|
Trick::ALLOC_INFO_MAP_ITER aim_it ;
|
2024-04-18 16:41:35 +00:00
|
|
|
for ( aim_it = trick_MM->alloc_info_map_begin() ; aim_it != trick_MM->alloc_info_map_end() ; ++aim_it ) {
|
2015-02-26 15:02:31 +00:00
|
|
|
ALLOC_INFO * alloc_info = (*aim_it).second ;
|
|
|
|
if ( alloc_info->name != NULL and alloc_info->user_type_name != NULL ) {
|
|
|
|
std::stringstream ss ;
|
|
|
|
std::string user_type_name = alloc_info->user_type_name ;
|
|
|
|
size_t start_colon ;
|
|
|
|
while ( ( start_colon = user_type_name.find("::") ) != std::string::npos ) {
|
|
|
|
user_type_name.replace( start_colon , 2 , "__" ) ;
|
|
|
|
}
|
|
|
|
// The castAs method may not exist if the class was hidden from SWIG (#ifndef SWIG).
|
|
|
|
// Use a try/except block to test if the method exists or not. If it doesn't exist
|
|
|
|
// don't worry about it. Also only assign python variable if it is pointing to
|
|
|
|
// something python doesn't owns. Otherwise we could free the object we're trying to assign.
|
|
|
|
ss << "try:" << std::endl ;
|
|
|
|
ss << " if '" << alloc_info->name << "' not in globals() or " ;
|
|
|
|
ss << alloc_info->name << ".thisown == False:" << std::endl ;
|
|
|
|
ss << " " << alloc_info->name << " = " ;
|
|
|
|
ss << "trick.castAs" << user_type_name << "(int(" << alloc_info->start << "))" << std::endl ;
|
|
|
|
ss << "except AttributeError:" << std::endl ;
|
|
|
|
ss << " pass" << std::endl ;
|
2024-03-27 19:20:58 +00:00
|
|
|
PyGILState_STATE gstate = PyGILState_Ensure();
|
2015-02-26 15:02:31 +00:00
|
|
|
PyRun_SimpleString(ss.str().c_str()) ;
|
2024-03-27 19:20:58 +00:00
|
|
|
PyGILState_Release(gstate);
|
2015-02-26 15:02:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-20 16:34:50 +00:00
|
|
|
bool Trick::IPPython::get_units_conversion_msgs() {
|
|
|
|
return units_conversion_msgs ;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Trick::IPPython::shoot_the_units_conversion_messenger(bool onoff) {
|
2019-06-18 15:59:51 +00:00
|
|
|
if ( onoff ) {
|
|
|
|
message_publish(MSG_WARNING, "Units conversion messages can no longer be suppressed.\n") ;
|
|
|
|
}
|
2017-04-20 16:34:50 +00:00
|
|
|
}
|
|
|
|
|
2015-02-26 15:02:31 +00:00
|
|
|
//Initialize and run the Python input processor on the user input file.
|
|
|
|
int Trick::IPPython::init() {
|
|
|
|
/** @par Detailed Design: */
|
|
|
|
|
|
|
|
FILE *input_fp ;
|
|
|
|
int ret ;
|
|
|
|
std::string error_message ;
|
|
|
|
|
2016-06-28 18:44:21 +00:00
|
|
|
// Run Py_Initialze first for python 2.x
|
|
|
|
#if PY_VERSION_HEX < 0x03000000
|
2015-02-26 15:02:31 +00:00
|
|
|
Py_Initialize();
|
2016-06-28 18:44:21 +00:00
|
|
|
#endif
|
2015-02-26 15:02:31 +00:00
|
|
|
|
|
|
|
/* Run the Swig generated routine in S_source_wrap.cpp. */
|
|
|
|
init_swig_modules() ;
|
|
|
|
|
2016-06-28 18:44:21 +00:00
|
|
|
// Run Py_Initialze after init_swig_modules for python 3.x
|
|
|
|
#if PY_VERSION_HEX >= 0x03000000
|
|
|
|
Py_Initialize();
|
|
|
|
#endif
|
|
|
|
|
2024-03-27 19:20:58 +00:00
|
|
|
// The following PyRun_ calls do not require the PyGILState guards because no threads are launched
|
2015-02-26 15:02:31 +00:00
|
|
|
/* Import simulation specific routines into interpreter. */
|
|
|
|
PyRun_SimpleString(
|
|
|
|
"import sys\n"
|
|
|
|
"import os\n"
|
|
|
|
"import struct\n"
|
|
|
|
"import binascii\n"
|
2021-05-17 16:08:04 +00:00
|
|
|
"sys.path.append(os.getcwd() + '/trick.zip')\n"
|
2018-03-05 21:17:22 +00:00
|
|
|
"sys.path.append(os.path.join(os.environ['TRICK_HOME'], 'share/trick/pymods'))\n"
|
2016-09-16 14:20:11 +00:00
|
|
|
"sys.path += map(str.strip, os.environ['TRICK_PYTHON_PATH'].split(':'))\n"
|
2015-02-26 15:02:31 +00:00
|
|
|
"import trick\n"
|
|
|
|
"sys.path.append(os.getcwd() + \"/Modified_data\")\n"
|
|
|
|
) ;
|
|
|
|
|
|
|
|
/* Make shortcut names for all known sim_objects. */
|
|
|
|
get_TMM_named_variables() ;
|
|
|
|
|
|
|
|
/* An input file is not required, if the name is empty just return. */
|
|
|
|
if ( input_file.empty() ) {
|
|
|
|
return(0) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((input_fp = fopen(input_file.c_str(), "r")) == NULL) {
|
|
|
|
error_message = "No input file found named " + input_file ;
|
|
|
|
exec_terminate_with_return(-1 , __FILE__ , __LINE__ , error_message.c_str() ) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Read and parse the input file. */
|
|
|
|
if ( verify_input ) {
|
2018-11-06 17:23:12 +00:00
|
|
|
PyRun_SimpleString("sys.settrace(trick.traceit)") ;
|
2015-02-26 15:02:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( (ret = PyRun_SimpleFile(input_fp, input_file.c_str())) != 0 ) {
|
|
|
|
exec_terminate_with_return(ret , __FILE__ , __LINE__ , "Input Processor error\n" ) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( verify_input ) {
|
2023-10-05 15:56:02 +00:00
|
|
|
std::stringstream ss ;
|
|
|
|
ss << "import hashlib" << std::endl ;
|
|
|
|
ss << "input_file = " << "'" << input_file.c_str() << "'" << std::endl;
|
|
|
|
ss << "print('{0} SHA1: {1}'.format(input_file,hashlib.sha1(open(input_file, 'rb').read()).hexdigest()))" << std::endl ;
|
|
|
|
PyRun_SimpleString(ss.str().c_str()) ;
|
2017-01-11 23:40:05 +00:00
|
|
|
exec_terminate_with_return(ret , __FILE__ , __LINE__ , "Input file verification complete\n" ) ;
|
2015-02-26 15:02:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fclose(input_fp) ;
|
|
|
|
|
2024-03-27 19:20:58 +00:00
|
|
|
// Release the GIL from the main thread.
|
|
|
|
Py_UNBLOCK_THREADS
|
|
|
|
|
|
|
|
return(0) ;
|
2015-02-26 15:02:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//Command to parse the given string.
|
|
|
|
int Trick::IPPython::parse(std::string in_string) {
|
|
|
|
|
2016-07-26 18:40:38 +00:00
|
|
|
int ret ;
|
2015-02-26 15:02:31 +00:00
|
|
|
in_string += "\n" ;
|
2024-03-27 19:20:58 +00:00
|
|
|
PyGILState_STATE gstate = PyGILState_Ensure();
|
2016-07-26 18:40:38 +00:00
|
|
|
ret = PyRun_SimpleString(in_string.c_str()) ;
|
2024-03-27 19:20:58 +00:00
|
|
|
PyGILState_Release(gstate);
|
2015-02-26 15:02:31 +00:00
|
|
|
|
2016-07-26 18:40:38 +00:00
|
|
|
return ret ;
|
2015-02-26 15:02:31 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
@details
|
|
|
|
The incoming statement is assumed to be a conditional fragment, i.e. "a > b". We need
|
|
|
|
to get the return value of this fragment by setting the return value of it to a known
|
|
|
|
variable name in the input processor. We can then assign that return value to the
|
|
|
|
incoming return_value reference.
|
|
|
|
|
|
|
|
-# Lock the input processor mutex
|
|
|
|
-# Create a complete statement that assigns the conditional fragment to our return value
|
|
|
|
-# parse the condition
|
|
|
|
-# copy the return value to the incoming cond_return_value
|
|
|
|
-# Unlock the input processor mutex
|
|
|
|
*/
|
|
|
|
int Trick::IPPython::parse_condition(std::string in_string, int & cond_return_val ) {
|
|
|
|
|
|
|
|
in_string = std::string("trick_ip.ip.return_val = ") + in_string + "\n" ;
|
|
|
|
// Running the simple string will set return_val.
|
2024-03-27 19:20:58 +00:00
|
|
|
PyGILState_STATE gstate = PyGILState_Ensure();
|
2023-01-20 21:46:10 +00:00
|
|
|
int py_ret = PyRun_SimpleString(in_string.c_str()) ;
|
2024-03-27 19:20:58 +00:00
|
|
|
PyGILState_Release(gstate);
|
2015-02-26 15:02:31 +00:00
|
|
|
cond_return_val = return_val ;
|
|
|
|
|
2023-01-20 21:46:10 +00:00
|
|
|
return py_ret ;
|
2015-02-26 15:02:31 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-11-08 09:25:07 +00:00
|
|
|
//Restart job that reloads event_list from checkpointable structures
|
2015-02-26 15:02:31 +00:00
|
|
|
int Trick::IPPython::restart() {
|
|
|
|
/* Make shortcut names for all known sim_objects. */
|
|
|
|
get_TMM_named_variables() ;
|
|
|
|
return 0 ;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Trick::IPPython::shutdown() {
|
2024-03-27 19:20:58 +00:00
|
|
|
|
2015-02-26 15:02:31 +00:00
|
|
|
if ( Py_IsInitialized() ) {
|
2024-03-27 19:20:58 +00:00
|
|
|
// Obtain the GIL so that we can shut down properly
|
|
|
|
Py_BLOCK_THREADS
|
2015-02-26 15:02:31 +00:00
|
|
|
Py_Finalize();
|
|
|
|
}
|
|
|
|
return(0) ;
|
|
|
|
}
|
|
|
|
|
2019-06-18 15:59:51 +00:00
|
|
|
//TODO: remove units conversion messenger routines in 2021
|
2017-04-20 16:34:50 +00:00
|
|
|
void shoot_the_units_conversion_messenger() {
|
2019-06-18 15:59:51 +00:00
|
|
|
message_publish(MSG_WARNING, "shoot_the_units_conversion_messenger() is deprecated\n") ;
|
2017-04-20 16:34:50 +00:00
|
|
|
the_pip->shoot_the_units_conversion_messenger(true) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
void revive_the_units_conversion_messenger() {
|
2019-06-18 15:59:51 +00:00
|
|
|
message_publish(MSG_WARNING, "revive_the_units_conversion_messenger() is deprecated\n") ;
|
2017-04-20 16:34:50 +00:00
|
|
|
the_pip->shoot_the_units_conversion_messenger(false) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
int check_units_conversion_messenger_for_signs_of_life() {
|
2019-06-18 15:59:51 +00:00
|
|
|
message_publish(MSG_WARNING, "check_units_conversion_messenger_for_signs_of_life() is deprecated\n") ;
|
2017-04-20 16:34:50 +00:00
|
|
|
return the_pip->get_units_conversion_msgs() ;
|
|
|
|
}
|
2019-06-18 15:59:51 +00:00
|
|
|
//END TODO:
|