Updated control stuff
[matches/MCTX3420.git] / server / control.c
1 /**
2  * @file control.c
3  * @brief Handles all client control requests (admin related)
4  */
5 #include "common.h"
6 #include "control.h"
7 #include "sensor.h"
8 #include "actuator.h"
9
10 typedef struct ControlData {
11         ControlModes current_mode;
12         pthread_mutex_t mutex;
13         struct timeval start_time;
14 } ControlData;
15
16 ControlData g_controls = {CONTROL_STOP, PTHREAD_MUTEX_INITIALIZER, {0}};
17
18 static bool ExperimentExists(const char *experiment_name) {
19         FILE *fp = fopen(experiment_name, "r");
20         if (!fp)
21                 return false;
22         fclose(fp);
23         return true;
24 }
25
26 /**
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
31  */
32 void Control_Handler(FCGIContext *context, char *params) {
33         const char *action, *key = "", *name = "";
34         bool force = false;
35         ControlModes desired_mode;
36
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}
42         };
43
44         if (!FCGI_ParseRequest(context, params, values, 4))
45                 return;
46         
47         if (!strcmp(action, "lock")) {
48                 FCGI_LockControl(context, force);
49                 return;
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;
63                 } else {
64                         FCGI_RejectJSON(context, "Unknown action specified.");
65                         return;
66                 }
67         } else {
68                 FCGI_RejectJSONEx(context, STATUS_UNAUTHORIZED, 
69                         "Invalid control key specified.");
70                 return;
71         }
72
73         void *arg = NULL;
74         if (desired_mode == CONTROL_START) {
75                 int len = strlen(name);
76                 if (len <= 0) {
77                         FCGI_RejectJSON(context, "An experiment name must be specified.");
78                         return;
79                 } else if (ExperimentExists(name) && !force) {
80                         FCGI_RejectJSON(context, "An experiment with that name already exists.");
81                         return;
82                 }
83                 arg = (void*)name;
84         }
85
86         const char *ret;
87         if ((ret = Control_SetMode(desired_mode, arg)) != NULL) {
88                 FCGI_RejectJSON(context, ret);
89         } else {
90                 FCGI_BeginJSON(context, STATUS_OK);
91                 FCGI_JSONPair("description", "ok");
92                 FCGI_EndJSON();
93         }
94 }
95
96 /**
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.
101  */
102 const char* Control_SetMode(ControlModes desired_mode, void * arg)
103 {
104         const char *ret = NULL;
105
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");
114                         if (fp) {
115                                 fclose(fp);
116                                 gettimeofday(&(g_controls.start_time), NULL);
117                         } else {
118                                 ret = "Failed to create experiment placeholder";
119                         }
120                 } else {
121                         ret = "Cannot start when not in a stopped state.";
122                 }
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.";
126         }
127         
128         if (ret == NULL) {
129                 Actuator_SetModeAll(desired_mode, arg);
130                 Sensor_SetModeAll(desired_mode, arg);
131                 g_controls.current_mode = desired_mode;
132         }
133         pthread_mutex_unlock(&(g_controls.mutex));
134         return ret;
135 }
136
137 /**
138  * Gets the current mode.
139  * @return The current mode
140  */
141 ControlModes Control_GetMode() {
142         ControlModes ret;
143         pthread_mutex_lock(&(g_controls.mutex));
144         ret = g_controls.current_mode;
145         pthread_mutex_unlock(&(g_controls.mutex));
146         return ret;
147 }
148
149 /*
150 bool Control_Lock() {
151         pthread_mutex_lock(&(g_controls.mutex));
152         if (g_controls.state == STATE_RUNNING || g_controls.state == STATE_PAUSED)
153                 return true;
154         pthread_mutex_unlock(&(g_controls.mutex));
155         return false;
156 }
157
158 void Control_Unlock() {
159         pthread_mutex_unlock(&(g_controls.mutex));
160 }*/
161
162 /**
163  * Gets the start time for the current experiment
164  * @return the start time
165  */
166 const struct timeval* Control_GetStartTime() {
167         return &g_controls.start_time;
168 }

UCC git Repository :: git.ucc.asn.au