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

nasa / trick / 33202687980

28 Aug 2026 07:10PM UTC coverage: 56.89% (+0.1%) from 56.76%
33202687980

push

github

web-flow
Not all init_attr routines are called at init.  #2165 (#2166)

* Not all init_attr routines are called at init.  #2165

If we are not generating attributes for sim_services, add a line to call each
init_attr function as they are added to the attributes map.

* Not all init_attr routines are called at init. #2165

This commit brings my merge request into reluctant compliance
with the mandated "opening brace on the next line" style.  While
no definitive studies have been published, anecdotal evidence suggests
this style increases vertical scroll distance by 37%, hides control
flow, and shortens the lifespan of mechanical keyboards through
excessive Enter key usage.

* Not all init_attr routines are called at init. #2165

Things get complicated with namespaces.  Had to move the
extern lines for all of the init routines to their own file

* Add the test.

* clang-format and ruff format

---------

Co-authored-by: Hong Chen <hchen99@users.noreply.github.com>

14921 of 26228 relevant lines covered (56.89%)

478847.06 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++) {
6✔
92
           if (TMM_is_alloced((char *)action_list[ii]))
3✔
93
           {
94
              TMM_delete_var_a(action_list[ii]);
×
95
           }
96
           action_list[ii] = 0x0;
3✔
97
       }
98
       TMM_delete_var_a(action_list);
3✔
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