-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathreactor_mgr.c
200 lines (150 loc) · 4.84 KB
/
reactor_mgr.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
#include "reactor_mgr.h"
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
#include "status_win.h"
#include "common.h"
#include "reactor.h"
static bool g_initialized = false;
static unsigned int g_tick = 0;
static pthread_mutex_t g_reactor_mgr_mutex = PTHREAD_MUTEX_INITIALIZER;
/* Reactor config. */
static reactor_mgr_mode_t g_mode = reactor_mgr_mode_norealtime;
/* Reactor state. */
static reactor_state_t g_state;
/* Realtime mode variables. */
#define _MANAGER_UPDATE_RATE 1 // Seconds
static bool g_manager_active;
static pthread_t g_manager_thread;
static pthread_cond_t g_manager_cond = PTHREAD_COND_INITIALIZER;
static void _acquire_lock(void) { assert(pthread_mutex_lock(&g_reactor_mgr_mutex) == 0); }
static void _release_lock(void) { assert(pthread_mutex_unlock(&g_reactor_mgr_mutex) == 0); }
#define _EXCL_ACCESS(expr) \
{ \
_acquire_lock(); \
expr; \
_release_lock(); \
}
#define _EXCL_RETURN(type, var) \
{ \
_acquire_lock(); \
type _val = var; \
_release_lock(); \
return _val; \
}
static void* _manager_thread(UNUSED_VAR void* arg) {
struct timespec timeout;
bool done = false;
while(!done) {
/* Get current time and add [_MANAGER_UPDATE_RATE] sec. */
timespec_get(&timeout, TIME_UTC);
timeout.tv_sec += _MANAGER_UPDATE_RATE;
/* Acquire lock. */
_acquire_lock();
/* Wait until we're interrupted or [_MANAGER_UPDATE_RATE] seconds pass. */
int res = 0;
while(res != ETIMEDOUT && g_manager_active) {
res = pthread_cond_timedwait(&g_manager_cond, &g_reactor_mgr_mutex, &timeout);
assert(res == 0 || res == ETIMEDOUT);
}
/* Perform update if we're in realtime mode. */
if(g_mode == reactor_mgr_mode_realtime) {
reactor_update(&g_state);
}
/* Update status. */
status_update(&g_state, g_tick);
/* Update tick. */
g_tick++;
/* Check if we should exit. */
if(!g_manager_active || exit_reason != exit_reason_none) {
done = true;
}
/* Release lock. */
_release_lock();
}
return NULL;
}
static void _start_manager_thread(void) {
/* Set flag to enable updates. */
assert(g_manager_active == false);
g_manager_active = true;
/* Start thread. */
assert(pthread_create(&g_manager_thread, NULL, _manager_thread, NULL) == 0);
}
static void _end_manager_thread(void) {
/* Set flag to disable updates in the manager. */
_acquire_lock();
assert(g_manager_active == true);
g_manager_active = false;
_release_lock();
/* Wake up thread. */
assert(pthread_cond_signal(&g_manager_cond) == 0);
/* Wait for thread to finish. */
assert(pthread_join(g_manager_thread, NULL) == 0);
}
usermode_t reactor_mgr_get_usermode(void) { _EXCL_RETURN(usermode_t, g_state.usermode); }
void reactor_mgr_set_usermode(usermode_t mode) { _EXCL_ACCESS(g_state.usermode = mode); }
bool reactor_mgr_get_safety(void) { _EXCL_RETURN(bool, g_state.safety_enabled); }
void reactor_mgr_set_safety(bool enabled) {
_acquire_lock();
/* Set safety enabled. */
g_state.safety_enabled = enabled;
/* If safety is being disabled, also deactivate safety. */
if(!enabled) {
g_state.safety_active = false;
}
/* If safety is being enabled and temp is above safe temp, activate safety. */
else if(g_state.temp > REACTOR_SAFE_TEMP) {
g_state.safety_active = true;
}
_release_lock();
}
bool reactor_mgr_get_safety_active(void) { _EXCL_RETURN(bool, g_state.safety_active); }
unsigned char reactor_mgr_get_rod_depth(void) { _EXCL_RETURN(unsigned char, g_state.rod_depth); }
void reactor_mgr_set_rod_depth(unsigned char depth) { _EXCL_ACCESS(g_state.rod_depth = depth); }
float reactor_mgr_get_coolant_flow(void) { _EXCL_RETURN(float, g_state.coolant_flow); }
void reactor_mgr_set_coolant_flow(float flow) { _EXCL_ACCESS(g_state.coolant_flow = flow); }
float reactor_mgr_get_temp(void) { _EXCL_RETURN(float, g_state.temp); }
float reactor_mgr_get_coolant_temp(void) { _EXCL_RETURN(float, g_state.coolant_temp); }
void reactor_mgr_update(void) {
_acquire_lock();
/* If we're in norealtime mode, perform an update. */
if(g_mode == reactor_mgr_mode_norealtime) {
reactor_update(&g_state);
}
/* Process any warnings. */
reactor_check_warns(&g_state);
/* Update status window. */
status_update(&g_state, g_tick);
_release_lock();
}
void reactor_mgr_init(reactor_mgr_mode_t mode) {
/* Do nothing if we're already initialized. */
if(g_initialized) {
return;
}
/* Set default state. */
reactor_init(&g_state);
/* Set mode. */
g_mode = mode;
/* Start manager thread. */
_start_manager_thread();
/* Init status window. */
status_init();
/* Update status window. */
status_update(&g_state, g_tick);
g_initialized = true;
}
void reactor_mgr_end(void) {
/* Do nothing if we aren't initialized. */
if(!g_initialized) {
return;
}
/* Stop manager thread. */
_end_manager_thread();
/* Finalize status window. */
status_end();
g_initialized = false;
}
reactor_mgr_mode_t reactor_mgr_get_mode(void) { return g_mode; }