3 * @brief Handles all client control requests (admin related)
10 typedef struct ControlData {
11 ControlModes current_mode;
12 pthread_mutex_t mutex;
13 struct timeval start_time;
16 ControlData g_controls = {CONTROL_STOP, PTHREAD_MUTEX_INITIALIZER, {0}};
18 static bool ExperimentExists(const char *experiment_name) {
19 FILE *fp = fopen(experiment_name, "r");
27 * System control handler. This covers high-level control, including
28 * admin related functions and starting/stopping experiments..
29 * @param context The context to work in
30 * @param params The input parameters
32 void Control_Handler(FCGIContext *context, char *params) {
33 const char *action, *key = "", *name = "";
35 ControlModes desired_mode;
37 FCGIValue values[4] = {
38 {"action", &action, FCGI_REQUIRED(FCGI_STRING_T)},
39 {"key", &key, FCGI_STRING_T},
40 {"force", &force, FCGI_BOOL_T},
41 {"name", &name, FCGI_STRING_T}
44 if (!FCGI_ParseRequest(context, params, values, 4))
47 if (!strcmp(action, "lock")) {
48 FCGI_LockControl(context, force);
50 } else if (!strcmp(action, "emergency")) {
51 desired_mode = CONTROL_EMERGENCY;
52 } else if (FCGI_HasControl(context, key)) {
53 if (!strcmp(action, "release")) {
54 FCGI_ReleaseControl(context);
55 } else if (!strcmp(action, "start")) {
56 desired_mode = CONTROL_START;
57 } else if (!strcmp(action, "pause")) {
58 desired_mode = CONTROL_PAUSE;
59 } else if (!strcmp(action, "resume")) {
60 desired_mode = CONTROL_RESUME;
61 } else if (!strcmp(action, "stop")) {
62 desired_mode = CONTROL_STOP;
64 FCGI_RejectJSON(context, "Unknown action specified.");
68 FCGI_RejectJSONEx(context, STATUS_UNAUTHORIZED,
69 "Invalid control key specified.");
74 if (desired_mode == CONTROL_START) {
75 int len = strlen(name);
77 FCGI_RejectJSON(context, "An experiment name must be specified.");
79 } else if (ExperimentExists(name) && !force) {
80 FCGI_RejectJSON(context, "An experiment with that name already exists.");
87 if ((ret = Control_SetMode(desired_mode, arg)) != NULL) {
88 FCGI_RejectJSON(context, ret);
90 FCGI_BeginJSON(context, STATUS_OK);
91 FCGI_JSONPair("description", "ok");
97 * Sets the mode to the desired mode, if possible.
98 * @param desired_mode The mode to be set to
99 * @param arg An argument specific to the mode to be set.
100 * @return NULL on success, an error message on failure.
102 const char* Control_SetMode(ControlModes desired_mode, void * arg)
104 const char *ret = NULL;
106 pthread_mutex_lock(&(g_controls.mutex));
107 if (g_controls.current_mode == CONTROL_EMERGENCY) {
108 ret = "In emergency mode. Restart software.";
109 } else if (g_controls.current_mode == desired_mode) {
110 ret = "Already in desired mode.";
111 } else if (desired_mode == CONTROL_START) {
112 if (g_controls.current_mode == CONTROL_STOP) {
113 FILE *fp = fopen((const char*) arg, "a");
116 gettimeofday(&(g_controls.start_time), NULL);
118 ret = "Failed to create experiment placeholder";
121 ret = "Cannot start when not in a stopped state.";
123 } else if (desired_mode == CONTROL_RESUME) {
124 if (g_controls.current_mode != CONTROL_PAUSE)
125 ret = "Cannot resume when not in a paused state.";
129 Actuator_SetModeAll(desired_mode, arg);
130 Sensor_SetModeAll(desired_mode, arg);
131 g_controls.current_mode = desired_mode;
133 pthread_mutex_unlock(&(g_controls.mutex));
138 * Gets the current mode.
139 * @return The current mode
141 ControlModes Control_GetMode() {
143 pthread_mutex_lock(&(g_controls.mutex));
144 ret = g_controls.current_mode;
145 pthread_mutex_unlock(&(g_controls.mutex));
150 bool Control_Lock() {
151 pthread_mutex_lock(&(g_controls.mutex));
152 if (g_controls.state == STATE_RUNNING || g_controls.state == STATE_PAUSED)
154 pthread_mutex_unlock(&(g_controls.mutex));
158 void Control_Unlock() {
159 pthread_mutex_unlock(&(g_controls.mutex));
163 * Gets the start time for the current experiment
164 * @return the start time
166 const struct timeval* Control_GetStartTime() {
167 return &g_controls.start_time;