• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nasa / trick / 37027075815

02 Oct 2026 03:27PM UTC coverage: 57.288% (+0.4%) from 56.89%
37027075815

Pull #2215

github

web-flow
Merge 545e0d60b into 6a651622a
Pull Request #2215: feat: Realtime Frame information

2 of 2 new or added lines in 1 file covered. (100.0%)

73 existing lines in 4 files now uncovered.

15085 of 26332 relevant lines covered (57.29%)

478269.87 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.69
/trick_source/sim_services/InputProcessor/IPPythonEvent.cpp
1
/*
2
   PURPOSE: ( Python input processor event capability )
3
   REFERENCE: ( Trick Simulation Environment )
4
   ASSUMPTIONS AND LIMITATIONS: ( None )
5
   CLASS: ( N/A )
6
   LIBRARY DEPENDENCY: ( None )
7
   PROGRAMMERS: ( Alex Lin NASA 2009 )
8
*/
9

10
#include <iostream>
11
#include <string>
12
#include <stdlib.h>
13
#include <string.h>
14

15
#include "trick/IPPythonEvent.hh"
16
#include "trick/IPPython.hh"
17
#include "trick/MemoryManager.hh"
18
#include "trick/exec_proto.h"
19
#include "trick/message_proto.h"
20
#include "trick/message_type.h"
21
#include "trick/memorymanager_c_intf.h"
22
#include "trick/exec_proto.hh"
23

24
/* Global singleton pointer to the memory manager */
25
//TODO Use external MM interface
26
extern Trick::MemoryManager * trick_MM ;
27

28
/* static variables in the IPPythonEvent class */
29
Trick::IPPython * Trick::IPPythonEvent::ip ;
30
Trick::MTV * Trick::IPPythonEvent::mtv ;
31
bool Trick::IPPythonEvent::info_msg = false ;
32
bool Trick::IPPythonEvent::terminate_sim_on_event_python_error = false;
33

34
Trick::condition_t::condition_t() {
25 ✔
35
    enabled = 0 ;
25 ✔
36
    hold = 0 ;
25 ✔
37
    fired = 0 ;
25 ✔
38
    fired_count = 0 ;
25 ✔
39
    fired_time = -1.0 ;
25 ✔
40
    ref = NULL ;
25 ✔
41
    job = NULL ;
25 ✔
42
}
25 ✔
43

44
Trick::action_t::action_t() {
84 ✔
45
    enabled = 0 ;
84 ✔
46
    ran = 0 ;
84 ✔
47
    ran_count = 0 ;
84 ✔
48
    ran_time = -1.0 ;
84 ✔
49
    job = NULL ;
84 ✔
50
    act_type = 0 ;
84 ✔
51
}
84 ✔
52

53
//Constructor
54
Trick::IPPythonEvent::IPPythonEvent() {
510 ✔
55

56

57
    is_user_event = true ;
255 ✔
58
    manual = false ;
255 ✔
59
    manual_fired = false ;
255 ✔
60
    condition_count = 0 ;
255 ✔
61
    cond_all = false ;
255 ✔
62
    action_count = 0 ;
255 ✔
63
    fired_count = 0 ;
255 ✔
64
    fired_time = -1.0 ;
255 ✔
65
    ran_count = 0 ;
255 ✔
66
    ran_time = -1.0 ;
255 ✔
67
    fired = false ;
255 ✔
68
    hold = false ;
255 ✔
69
    ran = false ;
255 ✔
70
    action_list = NULL;
255 ✔
71
    condition_list = NULL;
255 ✔
72
}
255 ✔
73

74
Trick::IPPythonEvent::~IPPythonEvent() {
200 ✔
75

76
    if (TMM_is_alloced((char *)condition_list))
200 ✔
77
    {
78
       for (int ii=0; ii<condition_count; ii++) {
×
79
           if (TMM_is_alloced((char *)condition_list[ii]))
×
80
           {
81
              TMM_delete_var_a(condition_list[ii]);
×
82
           }
83
           condition_list[ii] = 0x0;
×
84
       }
85
       TMM_delete_var_a(condition_list);
×
86
    }
87
    condition_list = 0x0;
200 ✔
88

89
    if (TMM_is_alloced((char *)action_list))
200 ✔
90
    {
91
       for (int ii=0; ii<action_count; ii++) {
2 ✔
92
           if (TMM_is_alloced((char *)action_list[ii]))
1 ✔
93
           {
UNCOV
94
              TMM_delete_var_a(action_list[ii]);
×
95
           }
96
           action_list[ii] = 0x0;
1 ✔
97
       }
98
       TMM_delete_var_a(action_list);
1 ✔
99
    }
100
    action_list = 0x0;
200 ✔
101
}
200 ✔
102

103
void Trick::IPPythonEvent::set_python_processor(Trick::IPPython * in_ip) {
190 ✔
104
    ip = in_ip ;
190 ✔
105
}
190 ✔
106

107
void Trick::IPPythonEvent::set_mtv(Trick::MTV * in_mtv) {
190 ✔
108
    mtv = in_mtv ;
190 ✔
109
}
190 ✔
110

111
//Command to make event evaluation require that ALL of event's conditions be true to make action(s) run.
112
int Trick::IPPythonEvent::condition_all() {
1 ✔
113
    cond_all = true ;
1 ✔
114
    return(0);
1 ✔
115
}
116

117
//Command to make event evaluation require that ANY of event's conditions be true to make action(s) run (default).
118
int Trick::IPPythonEvent::condition_any() {
1 ✔
119
    cond_all = false ;
1 ✔
120
    return(0);
1 ✔
121
}
122

123
//Command to manually fire the event next cycle and hold it fired (enter manual mode, bypasses normal condition processing).
124
void Trick::IPPythonEvent::manual_on() {
1 ✔
125
    manual = true ;
1 ✔
126
    manual_fired = true ;
1 ✔
127
    hold = true ;
1 ✔
128
    fired = false ;
1 ✔
129
}
1 ✔
130

131
//Command to manually fire the event once NOW (enter manual mode, bypasses normal condition processing).
132
void Trick::IPPythonEvent::manual_fire() {
1 ✔
133
    manual = true ;
1 ✔
134
    manual_fired = true ;
1 ✔
135
    hold = false ;
1 ✔
136
    fired = false ;
1 ✔
137
    process_user_event(exec_get_time_tics()) ;
1 ✔
138
}
1 ✔
139

140
//Command to manually set the event as not fired (enter manual mode, bypasses normal condition processing).
141
void Trick::IPPythonEvent::manual_off() {
1 ✔
142
    manual = true ;
1 ✔
143
    manual_fired = false ;
1 ✔
144
    hold = false ;
1 ✔
145
    fired = false ;
1 ✔
146
}
1 ✔
147

148
//Command to return to normal event processing (needed to end manual mode after any manual commands).
149
void Trick::IPPythonEvent::manual_done() {
1 ✔
150
    manual = false ;
1 ✔
151
    manual_fired = false ;
1 ✔
152
    hold = false ;
1 ✔
153
}
1 ✔
154

155
void Trick::IPPythonEvent::add() {
63 ✔
156
    added = true ;
63 ✔
157
}
63 ✔
158

159
void Trick::IPPythonEvent::remove() {
2 ✔
160
    added = false ;
2 ✔
161
}
2 ✔
162

163
// Command to turn on info messages
164
void Trick::IPPythonEvent::set_event_info_msg_on() {
×
165
    info_msg = true;
×
166
}
×
167

168
// Command to turn off info messages
169
void Trick::IPPythonEvent::set_event_info_msg_off() {
×
170
    info_msg = false;
×
171
}
×
172

173
void Trick::IPPythonEvent::terminate_on_event_parse_error(bool on_off) {
3 ✔
174
    terminate_sim_on_event_python_error = on_off;
3 ✔
175
}
3 ✔
176

177
void Trick::IPPythonEvent::restart() {
1 ✔
178
    int jj ;
179

180
    for (jj=0; jj<condition_count; jj++) {
1 ✔
181
        if (condition_list[jj]->cond_type==1) { // condition variable
×
182
            condition_list[jj]->ref = ref_attributes(condition_list[jj]->str.c_str());
×
183
        }
184
        if (condition_list[jj]->cond_type==2) { // condition job
×
185
            condition_list[jj]->job = exec_get_job(condition_list[jj]->str.c_str(),1);
×
186
        }
187
    }
188
    for (jj=0; jj<action_count; jj++) {
2 ✔
189
        if (action_list[jj]->act_type!=0) { // action job
1 ✔
190
            action_list[jj]->job = exec_get_job(action_list[jj]->str.c_str(),1);
×
191
        }
192
    }
193

194
}
1 ✔
195

196
//Command to create a new condition using a model variable (or reset an existing condition variable), num is index starting at 0.
197
int Trick::IPPythonEvent::condition_var(int num, std::string varname, std::string comment) {
7 ✔
198
    /** @par Detailed Design: */
199
    /** @li Find the variable reference for the varname string and pass it to condition() */
200
    REF2* ref = ref_attributes(varname.c_str());
7 ✔
201
    /** @li Emit an error if specified varname does not exist. */
202
    if (ref==NULL) {
7 ✔
203
        message_publish(MSG_WARNING, "Event condition variable %s not found. Setting condition to False.\n", varname.c_str()) ;
×
204
        condition(num, "False", comment, NULL, NULL );
×
205
    } else {
206
        condition(num, varname, comment, ref, NULL );
7 ✔
207
    }
208
    return(0);
7 ✔
209
}
210

211
//Command to create a new condition using a model job (or reset an existing condition job), num is index starting at 0.
212
int Trick::IPPythonEvent::condition_job(int num, std::string jobname, std::string comment) {
1 ✔
213
    /** @par Detailed Design: */
214
    /** @li Find the job for the jobname string and pass it to condition() */
215
    JobData *job = exec_get_job(jobname.c_str(),1);
1 ✔
216
    /** @li Emit an error if specified jobname does not exist. */
217
    if (job==NULL) {
1 ✔
218
        message_publish(MSG_WARNING, "Event condition job %s not found. Setting condition to False.\n", jobname.c_str()) ;
×
219
        condition(num, "False", comment, NULL, NULL );
×
220
    } else {
221
        if (! job->job_class_name.compare("malfunction")) {
1 ✔
222
            // enable it if it's a malf job because they are not in any queue
223
            job->disabled = false;
1 ✔
224
        }
225
        condition(num, jobname, comment, NULL, job );
1 ✔
226
    }
227
    return(0);
1 ✔
228
}
229

230
//Command to create a new condition and set its input string (or reset an existing condition string), num is index starting at 0.
231
int Trick::IPPythonEvent::condition(int num, std::string str, std::string comment, REF2* ref, JobData* job) {
27 ✔
232
    /** @par Detailed Design: */
233

234
    if (num == condition_count) {
27 ✔
235
        /** @li Add a new condition when num is sequential, i.e. it is equal to condition_count */
236
        condition_count++;
25 ✔
237
        if (condition_count == 1) {
25 ✔
238
            condition_list =
22 ✔
239
                (Trick::condition_t **)TMM_declare_var_s("Trick::condition_t*[1]");
22 ✔
240
        } else {
241
            condition_list =
3 ✔
242
                (Trick::condition_t **)TMM_resize_array_1d_a(condition_list, condition_count);
3 ✔
243
        }
244
        condition_list[num] =
50 ✔
245
            (Trick::condition_t *)TMM_declare_var_s("Trick::condition_t");
25 ✔
246
         
247
        condition_list[num]->fired_count = 0;
25 ✔
248
        condition_list[num]->fired_time = -1.0;
25 ✔
249
    }
250
    if ((num >=0) && (num < condition_count)) {
27 ✔
251
        /** @li This is either a new condition or user is changing the condition. */
252
        /** @li Initialize condition variables - default as enabled. */
253
        condition_list[num]->ref = ref ;
27 ✔
254
        condition_list[num]->job = job ;
27 ✔
255
        condition_list[num]->enabled = true;
27 ✔
256
        condition_list[num]->hold = false;
27 ✔
257
        condition_list[num]->fired = false;
27 ✔
258
        if (ref != NULL) {
27 ✔
259
            condition_list[num]->cond_type = 1;
7 ✔
260
        } else if (job != NULL) {
20 ✔
261
            condition_list[num]->cond_type = 2;
1 ✔
262
        } else condition_list[num]->cond_type = 0;
19 ✔
263
        condition_list[num]->str = str;
27 ✔
264
        // comment is for display in mtv, if not supplied create a comment containing up to 50 characters of cond string
265
        if (comment.empty()) {
54 ✔
266
            condition_list[num]->comment = str.substr(0,50);
25 ✔
267
        } else {
268
            condition_list[num]->comment = comment;
2 ✔
269
        }
270
        // dummy must contain max conditions used in any event so it can replace any event in mtv when deleted
271
    } else {
272
        /** @li Emit an error if specified index num is not sequential. */
273
        message_publish(MSG_WARNING, "Event condition not added: condition number %d is not sequential.\n", num) ;
×
274
    }
275
    return(0);
27 ✔
276
}
277

278
//Command to set an existing condition to hold, so that when it fires it stays in the fired state.
279
int Trick::IPPythonEvent::condition_hold_on(int num) {
1 ✔
280

281
    if ((num >=0) && (num < condition_count)) {
1 ✔
282
        condition_list[num]->hold = true ;
1 ✔
283
    } else {
284
        message_publish(MSG_WARNING, "Event condition hold not set. Condition number %d is invalid.\n", num) ;
×
285
    }
286
    return(0);
1 ✔
287
}
288

289
//Command to set an existing condition to not hold its fired state.
290
int Trick::IPPythonEvent::condition_hold_off(int num) {
1 ✔
291

292
    if ((num >=0) && (num < condition_count)) {
1 ✔
293
        condition_list[num]->hold = false ;
1 ✔
294
    } else {
295
        message_publish(MSG_WARNING, "Event condition hold not set. Condition number %d is invalid.\n", num) ;
×
296
    }
297
    return(0);
1 ✔
298
}
299

300
//Command to enable an existing condition (default is enabled) so that it is evaluated during event processing.
301
int Trick::IPPythonEvent::condition_enable(int num) {
×
302

303
    if ((num >=0) && (num < condition_count)) {
×
304
        condition_list[num]->enabled = true ;
×
305
    } else {
306
        message_publish(MSG_WARNING, "Event condition not enabled. Condition number %d is invalid.\n", num) ;
×
307
    }
308
    return(0);
×
309
}
310

311
//Command to disable an existing condition so that it is not evaluated during event processing.
312
int Trick::IPPythonEvent::condition_disable(int num) {
1 ✔
313

314
    if ((num >=0) && (num < condition_count)) {
1 ✔
315
        condition_list[num]->enabled = false ;
1 ✔
316
    } else {
317
        message_publish(MSG_WARNING, "Event condition not disabled. Condition number %d is invalid.\n", num) ;
×
318
    }
319
    return(0);
1 ✔
320
}
321

322
//Accessor function to test if the condition, indicated by num, fired (is currently in the fired state).
323
bool Trick::IPPythonEvent::condition_fired(int num) {
×
324

325
    if ((num >=0) && (num < condition_count)) {
×
326
        return (condition_list[num]->fired ? true : false) ;
×
327
    } else {
328
        message_publish(MSG_WARNING, "Event condition fired state not returned. Condition number %d is invalid.\n", num) ;
×
329
    }
330
    return(false);
×
331
}
332

333
//Accessor function to see how many times the condition, indicated by num, fired.
334
int Trick::IPPythonEvent::condition_fired_count(int num) {
×
335

336
    if ((num >=0) && (num < condition_count)) {
×
337
        return (condition_list[num]->fired_count) ;
×
338
    } else {
339
        message_publish(MSG_WARNING, "Event condition fired count not returned. Condition number %d is invalid.\n", num) ;
×
340
    }
341
    return(0) ;
×
342
}
343

344
//Accessor function to see when was the last time the condition, indicated by num, fired.
345
double Trick::IPPythonEvent::condition_fired_time(int num) {
×
346

347
    if ((num >=0) && (num < condition_count)) {
×
348
        return (condition_list[num]->fired_time) ;
×
349
    } else {
350
        message_publish(MSG_WARNING, "Event condition fired time not returned. Condition number %d is invalid.\n", num) ;
×
351
    }
352
    return(0.0) ;
×
353
}
354

355
//Accessor function to return the condition string, indicated by num.
356
std::string Trick::IPPythonEvent::condition_string(int num) {
×
357

358
    if ((num >=0) && (num < condition_count)) {
×
359
        return (condition_list[num]->str) ;
×
360
    } else {
361
        message_publish(MSG_WARNING, "Event condition string not returned. Condition number %d is invalid.\n", num) ;
×
362
    }
363
    return "" ;
×
364
}
365

366
//Command to create a new action using a model job (or reset an existing action job), num is index starting at 0.
367
int Trick::IPPythonEvent::action_job(int num, std::string jobname, std::string comment) {
4 ✔
368
    /** @par Detailed Design: */
369
    /** @li Find the job for the jobname string and pass it to action() */
370
    JobData *job = exec_get_job(jobname.c_str(),1);
4 ✔
371
    /** @li Emit an error if specified jobname does not exist. */
372
    if (job==NULL) {
4 ✔
373
        message_publish(MSG_WARNING, "Event action job %s not found. No action was added.\n", jobname.c_str()) ;
×
374
    } else {
375
        if (! job->job_class_name.compare("malfunction")) {
4 ✔
376
            // enable it if it's a malf job because they are not in any queue
377
            job->disabled = false;
×
378
        }
379
        action(num, jobname, comment, job, 3 );
4 ✔
380
    }
381
    return(0);
4 ✔
382
}
383

384
//Command to create a new action to turn a model job ON, num is index starting at 0.
385
int Trick::IPPythonEvent::action_job_on(int num, std::string jobname, std::string comment) {
×
386
    /** @par Detailed Design: */
387
    /** @li Find the job for the jobname string and pass it to action() */
388
    JobData *job = exec_get_job(jobname.c_str(),1);
×
389
    /** @li Emit an error if specified jobname does not exist. */
390
    if (job==NULL) {
×
391
        message_publish(MSG_WARNING, "Event action job %s not found. No action was added.\n", jobname.c_str()) ;
×
392
    } else {
393
        action(num, jobname, comment, job, 1 );
×
394
    }
395
    return(0);
×
396
}
397

398
//Command to create a new action to turn a model job OFF, num is index starting at 0.
399
int Trick::IPPythonEvent::action_job_off(int num, std::string jobname, std::string comment) {
1 ✔
400
    /** @par Detailed Design: */
401
    /** @li Find the job for the jobname string and pass it to action() */
402
    JobData *job = exec_get_job(jobname.c_str(),1);
1 ✔
403
    /** @li Emit an error if specified jobname does not exist. */
404
    if (job==NULL) {
1 ✔
405
        message_publish(MSG_WARNING, "Event action job %s not found. No action was added.\n", jobname.c_str()) ;
×
406
    } else {
407
        action(num, jobname, comment, job, 2 );
1 ✔
408
    }
409
    return(0);
1 ✔
410
}
411

412
//Command to create a new action and set its input string (or reset an existing action string), num is index starting at 0.
413
int Trick::IPPythonEvent::action(int num, std::string str, std::string comment, JobData *job, int act_type) {
84 ✔
414
    /** @par Detailed Design: */
415

416
    if (num == action_count) {
84 ✔
417
        /** @li Add a new action when num is sequential, i.e. it is equal to action_count */
418
        action_count++;
83 ✔
419
        if (action_count == 1) {
83 ✔
420
            action_list = (Trick::action_t **)TMM_declare_var_s("Trick::action_t*[1]");
64 ✔
421
        } else {
422
            action_list = (Trick::action_t **)TMM_resize_array_1d_a(action_list, action_count);
19 ✔
423
        }
424
        action_list[num] =
166 ✔
425
            (Trick::action_t *)TMM_declare_var_s("Trick::action_t");
83 ✔
426

427
        action_list[num]->ran_count = 0;
83 ✔
428
        action_list[num]->ran_time = -1.0;
83 ✔
429
    }
430
    if ((num >=0) && (num < action_count)) {
84 ✔
431
        /** @li This is either a new action or user is changing the action. */
432
        /** @li Initialize action variables - default as enabled. */
433
        action_list[num]->job = job ;
84 ✔
434
        action_list[num]->act_type = act_type ;
84 ✔
435
        action_list[num]->enabled = true;
84 ✔
436
        action_list[num]->ran = false;
84 ✔
437
        action_list[num]->str = str;
84 ✔
438
        // comment is for display in mtv, if not supplied create a comment containing up to 50 characters of act string
439
        if (comment.empty()) {
168 ✔
440
            action_list[num]->comment = str.substr(0,50);
81 ✔
441
        } else {
442
            action_list[num]->comment = comment;
3 ✔
443
        }
444
        // dummy must contain max actions used in any event so it can replace any event in mtv when deleted
445
#if 0
446
        if (num == ip->dummy_event.action_count) {
447
            ip->dummy_event.action(num, "XXX_DELETED_ACT");
448
        }
449
#endif
450
    } else {
451
        /** @li Emit an error if specified index num is not sequential. */
452
        message_publish(MSG_WARNING, "Event action not added: action number %d is not sequential.\n", num) ;
×
453
    }
454
    return(0);
84 ✔
455
}
456

457
//Command to enable an existing action (default is enabled) so that it is run when fired during event processing.
458
int Trick::IPPythonEvent::action_enable(int num) {
×
459

460
    if ((num >=0) && (num < action_count)) {
×
461
        action_list[num]->enabled = true ;
×
462
    } else {
463
        message_publish(MSG_WARNING, "Event action not enabled. Action number %d is invalid.\n", num) ;
×
464
    }
465
    return(0);
×
466
}
467

468
//Command to disable an existing action so that it is not run when fired during event processing.
469
int Trick::IPPythonEvent::action_disable(int num) {
1 ✔
470

471
    if ((num >=0) && (num < action_count)) {
1 ✔
472
        action_list[num]->enabled = false ;
1 ✔
473
    } else {
474
        message_publish(MSG_WARNING, "Event action not disabled. Action number %d is invalid.\n", num) ;
×
475
    }
476
    return(0);
1 ✔
477
}
478

479
//Accessor function to test if the action, indicated by num, ran.
480
bool Trick::IPPythonEvent::action_ran(int num) {
×
481

482
    if ((num >=0) && (num < action_count)) {
×
483
        return (action_list[num]->ran ? true : false) ;
×
484
    } else {
485
        message_publish(MSG_WARNING, "Event action ran state not returned. Action number %d is invalid.\n", num) ;
×
486
    }
487
    return(false);
×
488
}
489

490
//Accessor function to see how many times the action, indicated by num, ran.
491
int Trick::IPPythonEvent::action_ran_count(int num) {
×
492

493
    if ((num >=0) && (num < action_count)) {
×
494
        return (action_list[num]->ran_count) ;
×
495
    } else {
496
        message_publish(MSG_WARNING, "Event action ran count not returned. Action number %d is invalid.\n", num) ;
×
497
    }
498
    return(0) ;
×
499
}
500

501
//Accessor function to see when was the last time the action, indicated by num, ran.
502
double Trick::IPPythonEvent::action_ran_time(int num) {
×
503

504
    if ((num >=0) && (num < action_count)) {
×
505
        return (action_list[num]->ran_time) ;
×
506
    } else {
507
        message_publish(MSG_WARNING, "Event action ran time not returned. Action number %d is invalid.\n", num) ;
×
508
    }
509
    return(0.0) ;
×
510
}
511

512
int Trick::IPPythonEvent::process( long long curr_time ) {
146 ✔
513

514
    if ( active || manual_fired ) {
146 ✔
515
            /** @li If it's a user's input event, process it by calling Trick::IPPython::process_triggers. */
516
            if ( is_user_event ) {
146 ✔
517
                // it's an input file event
518
                process_user_event(curr_time) ;
105 ✔
519
            /** @li Otherwise if it's a trick event (like a read), process it. */
520
            } else {
521
                // it's a read event
522
                active = false ;
41 ✔
523
                int ret = ip->parse(action_list[0]->str) ;
41 ✔
524
                if (ret != 0 && terminate_sim_on_event_python_error) {
41 ✔
525
                    exec_terminate_with_return( ret , __FILE__ , __LINE__ , "Python error in event processing" ) ;
1 ✔
526
                }
527
                // keep stats so mtv will show when it ran
528
                fired_count++ ;
40 ✔
529
                fired_time = curr_time ;
40 ✔
530
                ran = true ;
40 ✔
531
                ran_count++ ;
40 ✔
532
                ran_time = curr_time ;
40 ✔
533
                action_list[0]->ran = true ;
40 ✔
534
                action_list[0]->ran_count++ ;
40 ✔
535
                action_list[0]->ran_time = curr_time ;
40 ✔
536
            }
537
    }
538
    return 0 ;
143 ✔
539
}
540

541
bool Trick::IPPythonEvent::process_user_event( long long curr_time ) {
106 ✔
542

543
    int ii ;
544
    int return_val ;
545
    bool it_fired, it_ran;
546

547
    fired = false ;
106 ✔
548
    ran = false ;
106 ✔
549
    /** @li No need to evaluate any conditions if in manual mode. */
550
    if (! manual) {
106 ✔
551
        hold = false ;
93 ✔
552
        /** @li Loop thru all conditions. */
553
        for (ii=0; ii<condition_count; ii++) {
203 ✔
554
            /** @li Skip condition if it's been disabled. */
555
            if (! condition_list[ii]->enabled ) {
111 ✔
556
                condition_list[ii]->fired = false ;
2 ✔
557
                continue ;
2 ✔
558
            }
559
            /** @li No need to evaluate condition if previously fired and hold is on. */
560
            if (condition_list[ii]->hold && condition_list[ii]->fired) {
109 ✔
561
                ;
562
            } else {
563
                /** @li Evaluate the condition and set its fired state. */
564
                condition_list[ii]->fired = false ;
107 ✔
565
                return_val = 0 ;
107 ✔
566
                if (condition_list[ii]->ref != NULL) {
107 ✔
567
                // if it's a variable, get it as a boolean
568
                    if ( condition_list[ii]->ref->pointer_present ) {
47 ✔
569
                        condition_list[ii]->ref->address = follow_address_path(condition_list[ii]->ref) ;
×
570
                    }
571
                    if ( condition_list[ii]->ref->address != NULL ) {
47 ✔
572
                        return_val = *(bool *)condition_list[ii]->ref->address ;
47 ✔
573
                    }
574
                } else if (condition_list[ii]->job != NULL) {
60 ✔
575
                // if it's a job, get its return value
576
                    bool save_disabled_state = condition_list[ii]->job->disabled;
4 ✔
577
                    condition_list[ii]->job->disabled = false;
4 ✔
578
                    return_val = condition_list[ii]->job->call();
4 ✔
579
                    condition_list[ii]->job->disabled = save_disabled_state;
4 ✔
580
                } else {
581
                // otherwise use python to evaluate string
582
                    std::string full_in_string ;
56 ✔
583
                    int python_ret = ip->parse_condition(condition_list[ii]->str, return_val) ;
56 ✔
584
                    if (python_ret != 0 && terminate_sim_on_event_python_error) {
56 ✔
585
                        exec_terminate_with_return( python_ret , __FILE__ , __LINE__ , "Python error in event condition processing" ) ;
1 ✔
586
                    }
587
                }
56 ✔
588
                if (return_val) {
106 ✔
589
                //TODO: write to log/send_hs that trigger fired
590
                    condition_list[ii]->fired = true ;
53 ✔
591
                    condition_list[ii]->fired_count++ ;
53 ✔
592
                    condition_list[ii]->fired_time = curr_time ;
53 ✔
593
                }
594
            } // end evaluate condition
595
            /** @li If cond_all is true, only set event fired/hold after all enabled conditions evaluated. */
596
            if (ii==0) {
108 ✔
597
                fired = condition_list[ii]->fired ;
88 ✔
598
                hold  = condition_list[ii]->hold ;
88 ✔
599
            }  else {
600
                if (cond_all) {
20 ✔
601
                    fired &= condition_list[ii]->fired ;
4 ✔
602
                    hold  &= condition_list[ii]->hold ;
4 ✔
603
                } else {
604
                    fired |= condition_list[ii]->fired ;
16 ✔
605
                    hold  |= condition_list[ii]->hold ;
16 ✔
606
                }
607
            }
608
        } //end condition loop
609
    }
610
    it_fired = manual_fired || fired ;
105 ✔
611
    /** @li Set the event's fired state...cond_all: if all conditions fired , otherwise if any condition fired. */
612
    if (it_fired) {
105 ✔
613
        fired_count++ ;
58 ✔
614
        fired_time = curr_time ;
58 ✔
615
        if (info_msg) {
58 ✔
616
            message_publish( MSG_INFO , "%12.6f Event %s fired.\n" , exec_get_sim_time() , name.c_str()) ;
×
617
        }
618
        if (!manual_fired) {
58 ✔
619
            active = false ;
51 ✔
620
        }
621
    }
622

623
    /** @li If the user specified any actions, run them here if a condition fired or manually fired. */
624
    it_ran = false ;
105 ✔
625
    if (it_fired && (action_count > 0)) {
105 ✔
626
        /** @li Loop thru all actions. */
627
        for (ii=0; ii<action_count; ii++) {
169 ✔
628
            /** @li No need to run action if it's been disabled. */
629
            if (! action_list[ii]->enabled ) {
112 ✔
630
                action_list[ii]->ran = false ;
1 ✔
631
                continue ;
1 ✔
632
            }
633
            /** @li Run the action and set its ran state. */
634
            if (action_list[ii]->job != NULL) {
111 ✔
635
            // if it's a job, do what the action type tells you
636
                switch (action_list[ii]->act_type) {
6 ✔
637
                    case 0 : // python, should not get here
×
638
                        break;
×
639
                    case 1 : // On
×
640
                        action_list[ii]->job->disabled = false;
×
641
                        break;
×
642
                    case 2 : // Off
2 ✔
643
                        action_list[ii]->job->disabled = true;
2 ✔
644
                        break;
2 ✔
645
                    case 3 : // Call
4 ✔
646
                        bool save_disabled_state = action_list[ii]->job->disabled;
4 ✔
647
                        action_list[ii]->job->disabled = false;
4 ✔
648
                        action_list[ii]->job->call();
4 ✔
649
                        action_list[ii]->job->disabled = save_disabled_state;
4 ✔
650
                        break;
4 ✔
651
                }
652
            } else {
653
                // otherwise use python to evaluate string
654
                int ret = ip->parse(action_list[ii]->str) ;
105 ✔
655
                if (ret != 0 && terminate_sim_on_event_python_error) {
105 ✔
656
                    exec_terminate_with_return( ret , __FILE__ , __LINE__ , "Python error in event action processing" ) ;
1 ✔
657
                }
658
            }
659
            it_ran = true ;
110 ✔
660
            action_list[ii]->ran = true ;
110 ✔
661
            action_list[ii]->ran_count++ ;
110 ✔
662
            action_list[ii]->ran_time = curr_time ;
110 ✔
663
            ran = true ;
110 ✔
664
        }
665
        /** @li Leave event fired state on if hold is on. */
666
        manual_fired &= hold ;
57 ✔
667
        fired &= hold ;
57 ✔
668
    }
669
    /** @li Set the event's ran state if any actions were run. */
670
    if (it_ran) {
104 ✔
671
        ran_count++ ;
57 ✔
672
        ran_time = curr_time ;
57 ✔
673
    }
674

675
    /** @li Return true if the event fired. */
676
    return(it_fired) ;
104 ✔
677
}
678

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc