/* PURPOSE: ( Python input processor event capability ) REFERENCE: ( Trick Simulation Environment ) ASSUMPTIONS AND LIMITATIONS: ( None ) CLASS: ( N/A ) LIBRARY DEPENDENCY: ( None ) PROGRAMMERS: ( Alex Lin NASA 2009 ) */ #include #include #include #include #include "trick/IPPythonEvent.hh" #include "trick/IPPython.hh" #include "trick/MemoryManager.hh" #include "trick/exec_proto.h" #include "trick/message_proto.h" #include "trick/message_type.h" #include "trick/memorymanager_c_intf.h" #include "trick/exec_proto.hh" /* Global singleton pointer to the memory manager */ //TODO Use external MM interface extern Trick::MemoryManager * trick_MM ; /* static variables in the IPPythonEvent class */ Trick::IPPython * Trick::IPPythonEvent::ip ; Trick::MTV * Trick::IPPythonEvent::mtv ; bool Trick::IPPythonEvent::info_msg = false ; Trick::condition_t::condition_t() { enabled = 0 ; hold = 0 ; fired = 0 ; fired_count = 0 ; fired_time = -1.0 ; ref = NULL ; job = NULL ; } Trick::action_t::action_t() { enabled = 0 ; ran = 0 ; ran_count = 0 ; ran_time = -1.0 ; job = NULL ; act_type = 0 ; } //Constructor Trick::IPPythonEvent::IPPythonEvent() { is_user_event = true ; manual = false ; manual_fired = false ; condition_count = 0 ; cond_all = false ; action_count = 0 ; fired_count = 0 ; fired_time = -1.0 ; ran_count = 0 ; ran_time = -1.0 ; fired = false ; hold = false ; ran = false ; act = NULL; cond = NULL; } Trick::IPPythonEvent::~IPPythonEvent() { } void Trick::IPPythonEvent::set_python_processor(Trick::IPPython * in_ip) { ip = in_ip ; } void Trick::IPPythonEvent::set_mtv(Trick::MTV * in_mtv) { mtv = in_mtv ; } //Command to make event evaluation require that ALL of event's conditions be true to make action(s) run. int Trick::IPPythonEvent::condition_all() { cond_all = true ; return(0); } //Command to make event evaluation require that ANY of event's conditions be true to make action(s) run (default). int Trick::IPPythonEvent::condition_any() { cond_all = false ; return(0); } //Command to manually fire the event next cycle and hold it fired (enter manual mode, bypasses normal condition processing). void Trick::IPPythonEvent::manual_on() { manual = true ; manual_fired = true ; hold = true ; fired = false ; } //Command to manually fire the event once NOW (enter manual mode, bypasses normal condition processing). void Trick::IPPythonEvent::manual_fire() { manual = true ; manual_fired = true ; hold = false ; fired = false ; process_user_event(exec_get_time_tics()) ; } //Command to manually set the event as not fired (enter manual mode, bypasses normal condition processing). void Trick::IPPythonEvent::manual_off() { manual = true ; manual_fired = false ; hold = false ; fired = false ; } //Command to return to normal event processing (needed to end manual mode after any manual commands). void Trick::IPPythonEvent::manual_done() { manual = false ; manual_fired = false ; hold = false ; } void Trick::IPPythonEvent::add() { added = true ; } void Trick::IPPythonEvent::remove() { added = false ; } // Command to turn on info messages void Trick::IPPythonEvent::set_event_info_msg_on() { info_msg = true; } // Command to turn off info messages void Trick::IPPythonEvent::set_event_info_msg_off() { info_msg = false; } void Trick::IPPythonEvent::restart() { int jj ; for (jj=0; jjjob_class_name.compare("malfunction")) { // enable it if it's a malf job because they are not in any queue job->disabled = false; } condition(num, jobname, comment, NULL, job ); } return(0); } //Command to create a new condition and set its input string (or reset an existing condition string), num is index starting at 0. int Trick::IPPythonEvent::condition(int num, std::string str, std::string comment, REF2* ref, JobData* job) { /** @par Detailed Design: */ if (num == condition_count) { /** @li Add a new condition when num is sequential, i.e. it is equal to condition_count */ condition_count++; if (condition_count == 1) { cond = (Trick::condition_t *)TMM_declare_var_s("Trick::condition_t[1]"); } else { cond = (Trick::condition_t *)TMM_resize_array_1d_a(cond, condition_count); } cond[num].fired_count = 0; cond[num].fired_time = -1.0; } if ((num >=0) && (num < condition_count)) { /** @li This is either a new condition or user is changing the condition. */ /** @li Initialize condition variables - default as enabled. */ cond[num].ref = ref ; cond[num].job = job ; cond[num].enabled = true; cond[num].hold = false; cond[num].fired = false; if (ref != NULL) { cond[num].cond_type = 1; } else if (job != NULL) { cond[num].cond_type = 2; } else cond[num].cond_type = 0; cond[num].str = str; // comment is for display in mtv, if not supplied create a comment containing up to 50 characters of cond string if (comment.empty()) { cond[num].comment = str.substr(0,50); } else { cond[num].comment = comment; } // dummy must contain max conditions used in any event so it can replace any event in mtv when deleted #if 0 if (num == ip->dummy_event.condition_count) { ip->dummy_event.condition(num, "XXX_DELETED_COND"); } #endif } else { /** @li Emit an error if specified index num is not sequential. */ message_publish(MSG_WARNING, "Event condition not added: condition number %d is not sequential.\n", num) ; } return(0); } //Command to set an existing condition to hold, so that when it fires it stays in the fired state. int Trick::IPPythonEvent::condition_hold_on(int num) { if ((num >=0) && (num < condition_count)) { cond[num].hold = true ; } else { message_publish(MSG_WARNING, "Event condition hold not set. Condition number %d is invalid.\n", num) ; } return(0); } //Command to set an existing condition to not hold its fired state. int Trick::IPPythonEvent::condition_hold_off(int num) { if ((num >=0) && (num < condition_count)) { cond[num].hold = false ; } else { message_publish(MSG_WARNING, "Event condition hold not set. Condition number %d is invalid.\n", num) ; } return(0); } //Command to enable an existing condition (default is enabled) so that it is evaluated during event processing. int Trick::IPPythonEvent::condition_enable(int num) { if ((num >=0) && (num < condition_count)) { cond[num].enabled = true ; } else { message_publish(MSG_WARNING, "Event condition not enabled. Condition number %d is invalid.\n", num) ; } return(0); } //Command to disable an existing condition so that it is not evaluated during event processing. int Trick::IPPythonEvent::condition_disable(int num) { if ((num >=0) && (num < condition_count)) { cond[num].enabled = false ; } else { message_publish(MSG_WARNING, "Event condition not disabled. Condition number %d is invalid.\n", num) ; } return(0); } //Accessor function to test if the condition, indicated by num, fired (is currently in the fired state). bool Trick::IPPythonEvent::condition_fired(int num) { if ((num >=0) && (num < condition_count)) { return (cond[num].fired ? true : false) ; } else { message_publish(MSG_WARNING, "Event condition fired state not returned. Condition number %d is invalid.\n", num) ; } return(false); } //Accessor function to see how many times the condition, indicated by num, fired. int Trick::IPPythonEvent::condition_fired_count(int num) { if ((num >=0) && (num < condition_count)) { return (cond[num].fired_count) ; } else { message_publish(MSG_WARNING, "Event condition fired count not returned. Condition number %d is invalid.\n", num) ; } return(0) ; } //Accessor function to see when was the last time the condition, indicated by num, fired. double Trick::IPPythonEvent::condition_fired_time(int num) { if ((num >=0) && (num < condition_count)) { return (cond[num].fired_time) ; } else { message_publish(MSG_WARNING, "Event condition fired time not returned. Condition number %d is invalid.\n", num) ; } return(0.0) ; } //Accessor function to return the condition string, indicated by num. std::string Trick::IPPythonEvent::condition_string(int num) { if ((num >=0) && (num < condition_count)) { return (cond[num].str) ; } else { message_publish(MSG_WARNING, "Event condition string not returned. Condition number %d is invalid.\n", num) ; } return "" ; } //Command to create a new action using a model job (or reset an existing action job), num is index starting at 0. int Trick::IPPythonEvent::action_job(int num, std::string jobname, std::string comment) { /** @par Detailed Design: */ /** @li Find the job for the jobname string and pass it to action() */ JobData *job = exec_get_job(jobname.c_str(),1); /** @li Emit an error if specified jobname does not exist. */ if (job==NULL) { message_publish(MSG_WARNING, "Event action job %s not found. No action was added.\n", jobname.c_str()) ; } else { if (! job->job_class_name.compare("malfunction")) { // enable it if it's a malf job because they are not in any queue job->disabled = false; } action(num, jobname, comment, job, 3 ); } return(0); } //Command to create a new action to turn a model job ON, num is index starting at 0. int Trick::IPPythonEvent::action_job_on(int num, std::string jobname, std::string comment) { /** @par Detailed Design: */ /** @li Find the job for the jobname string and pass it to action() */ JobData *job = exec_get_job(jobname.c_str(),1); /** @li Emit an error if specified jobname does not exist. */ if (job==NULL) { message_publish(MSG_WARNING, "Event action job %s not found. No action was added.\n", jobname.c_str()) ; } else { action(num, jobname, comment, job, 1 ); } return(0); } //Command to create a new action to turn a model job OFF, num is index starting at 0. int Trick::IPPythonEvent::action_job_off(int num, std::string jobname, std::string comment) { /** @par Detailed Design: */ /** @li Find the job for the jobname string and pass it to action() */ JobData *job = exec_get_job(jobname.c_str(),1); /** @li Emit an error if specified jobname does not exist. */ if (job==NULL) { message_publish(MSG_WARNING, "Event action job %s not found. No action was added.\n", jobname.c_str()) ; } else { action(num, jobname, comment, job, 2 ); } return(0); } //Command to create a new action and set its input string (or reset an existing action string), num is index starting at 0. int Trick::IPPythonEvent::action(int num, std::string str, std::string comment, JobData *job, int act_type) { /** @par Detailed Design: */ if (num == action_count) { /** @li Add a new action when num is sequential, i.e. it is equal to action_count */ action_count++; if (action_count == 1) { act = (Trick::action_t *)TMM_declare_var_s("Trick::action_t[1]"); } else { act = (Trick::action_t *)TMM_resize_array_1d_a(act, action_count); } act[num].ran_count = 0; act[num].ran_time = -1.0; } if ((num >=0) && (num < action_count)) { /** @li This is either a new action or user is changing the action. */ /** @li Initialize action variables - default as enabled. */ act[num].job = job ; act[num].act_type = act_type ; act[num].enabled = true; act[num].ran = false; act[num].str = str; // comment is for display in mtv, if not supplied create a comment containing up to 50 characters of act string if (comment.empty()) { act[num].comment = str.substr(0,50); } else { act[num].comment = comment; } // dummy must contain max actions used in any event so it can replace any event in mtv when deleted #if 0 if (num == ip->dummy_event.action_count) { ip->dummy_event.action(num, "XXX_DELETED_ACT"); } #endif } else { /** @li Emit an error if specified index num is not sequential. */ message_publish(MSG_WARNING, "Event action not added: action number %d is not sequential.\n", num) ; } return(0); } //Command to enable an existing action (default is enabled) so that it is run when fired during event processing. int Trick::IPPythonEvent::action_enable(int num) { if ((num >=0) && (num < action_count)) { act[num].enabled = true ; } else { message_publish(MSG_WARNING, "Event action not enabled. Action number %d is invalid.\n", num) ; } return(0); } //Command to disable an existing action so that it is not run when fired during event processing. int Trick::IPPythonEvent::action_disable(int num) { if ((num >=0) && (num < action_count)) { act[num].enabled = false ; } else { message_publish(MSG_WARNING, "Event action not disabled. Action number %d is invalid.\n", num) ; } return(0); } //Accessor function to test if the action, indicated by num, ran. bool Trick::IPPythonEvent::action_ran(int num) { if ((num >=0) && (num < action_count)) { return (act[num].ran ? true : false) ; } else { message_publish(MSG_WARNING, "Event action ran state not returned. Action number %d is invalid.\n", num) ; } return(false); } //Accessor function to see how many times the action, indicated by num, ran. int Trick::IPPythonEvent::action_ran_count(int num) { if ((num >=0) && (num < action_count)) { return (act[num].ran_count) ; } else { message_publish(MSG_WARNING, "Event action ran count not returned. Action number %d is invalid.\n", num) ; } return(0) ; } //Accessor function to see when was the last time the action, indicated by num, ran. double Trick::IPPythonEvent::action_ran_time(int num) { if ((num >=0) && (num < action_count)) { return (act[num].ran_time) ; } else { message_publish(MSG_WARNING, "Event action ran time not returned. Action number %d is invalid.\n", num) ; } return(0.0) ; } int Trick::IPPythonEvent::process( long long curr_time ) { if ( active || manual_fired ) { /** @li If it's a user's input event, process it by calling Trick::IPPython::process_triggers. */ if ( is_user_event ) { // it's an input file event process_user_event(curr_time) ; /** @li Otherwise if it's a trick event (like a read), process it. */ } else { // it's a read event active = false ; ip->parse(act[0].str) ; // keep stats so mtv will show when it ran fired_count++ ; fired_time = curr_time ; ran = true ; ran_count++ ; ran_time = curr_time ; act[0].ran = true ; act[0].ran_count++ ; act[0].ran_time = curr_time ; } } return 0 ; } bool Trick::IPPythonEvent::process_user_event( long long curr_time ) { int ii ; int return_val ; bool it_fired, it_ran; fired = false ; ran = false ; /** @li No need to evaluate any conditions if in manual mode. */ if (! manual) { hold = false ; /** @li Loop thru all conditions. */ for (ii=0; iipointer_present ) { cond[ii].ref->address = follow_address_path(cond[ii].ref) ; } if ( cond[ii].ref->address != NULL ) { return_val = *(bool *)cond[ii].ref->address ; } } else if (cond[ii].job != NULL) { // if it's a job, get its return value bool save_disabled_state = cond[ii].job->disabled; cond[ii].job->disabled = false; return_val = cond[ii].job->call(); cond[ii].job->disabled = save_disabled_state; } else { // otherwise use python to evaluate string std::string full_in_string ; ip->parse_condition(cond[ii].str, return_val) ; } if (return_val) { //TODO: write to log/send_hs that trigger fired cond[ii].fired = true ; cond[ii].fired_count++ ; cond[ii].fired_time = curr_time ; } } // end evaluate condition /** @li If cond_all is true, only set event fired/hold after all enabled conditions evaluated. */ if (ii==0) { fired = cond[ii].fired ; hold = cond[ii].hold ; } else { if (cond_all) { fired &= cond[ii].fired ; hold &= cond[ii].hold ; } else { fired |= cond[ii].fired ; hold |= cond[ii].hold ; } } } //end condition loop } it_fired = manual_fired || fired ; /** @li Set the event's fired state...cond_all: if all conditions fired , otherwise if any condition fired. */ if (it_fired) { fired_count++ ; fired_time = curr_time ; if (info_msg) { message_publish( MSG_INFO , "%12.6f Event %s fired.\n" , exec_get_sim_time() , name.c_str()) ; } if (!manual_fired) { active = false ; } } /** @li If the user specified any actions, run them here if a condition fired or manually fired. */ it_ran = false ; if (it_fired && (action_count > 0)) { /** @li Loop thru all actions. */ for (ii=0; iidisabled = false; break; case 2 : // Off act[ii].job->disabled = true; break; case 3 : // Call bool save_disabled_state = act[ii].job->disabled; act[ii].job->disabled = false; act[ii].job->call(); act[ii].job->disabled = save_disabled_state; break; } } else { // otherwise use python to evaluate string ip->parse(act[ii].str) ; } it_ran = true ; act[ii].ran = true ; act[ii].ran_count++ ; act[ii].ran_time = curr_time ; ran = true ; } /** @li Leave event fired state on if hold is on. */ manual_fired &= hold ; fired &= hold ; } /** @li Set the event's ran state if any actions were run. */ if (it_ran) { ran_count++ ; ran_time = curr_time ; } /** @li Return true if the event fired. */ return(it_fired) ; }