Add semi working control code
[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 enum ControlState {
11         STATE_STOPPED,
12         STATE_PAUSED,
13         STATE_RUNNING
14 } ControlState;
15
16 typedef enum Mode {
17         START,
18         PAUSE,
19         RESUME,
20         STOP
21 } Mode;
22
23 typedef struct ControlData {
24         ControlState state;
25         pthread_mutex_t mutex;
26         struct timeval start_time;
27 } ControlData;
28
29 ControlData g_controls = {STATE_STOPPED, PTHREAD_MUTEX_INITIALIZER, {0}};
30
31 static bool ExperimentExists(const char *experiment_name) {
32         FILE *fp = fopen(experiment_name, "r");
33         if (!fp)
34                 return false;
35         fclose(fp);
36         return true;
37 }
38
39 /**
40  * System control handler. This covers high-level control, including
41  * admin related functions and starting/stopping experiments..
42  * @param context The context to work in
43  * @param params The input parameters
44  */
45 void Control_Handler(FCGIContext *context, char *params) {
46         const char *action, *key = "", *name = "";
47         bool force = false;
48         Mode mode;
49
50         FCGIValue values[4] = {
51                 {"action", &action, FCGI_REQUIRED(FCGI_STRING_T)},
52                 {"key", &key, FCGI_STRING_T},
53                 {"force", &force, FCGI_BOOL_T},
54                 {"name", &name, FCGI_STRING_T}
55         };
56
57         if (!FCGI_ParseRequest(context, params, values, 4))
58                 return;
59         
60         if (!strcmp(action, "lock")) {
61                 FCGI_LockControl(context, force);
62                 return;
63         } else if (FCGI_HasControl(context, key)) {
64                 if (!strcmp(action, "release")) {
65                         FCGI_ReleaseControl(context);
66                 } else if (!strcmp(action, "start")) {
67                         mode = START;
68                 } else if (!strcmp(action, "pause")) {
69                         mode = PAUSE;
70                 } else if (!strcmp(action, "resume")) {
71                         mode = RESUME;
72                 } else if (!strcmp(action, "stop")) {
73                         mode = STOP;
74                 } else {
75                         FCGI_RejectJSON(context, "Unknown action specified.");
76                         return;
77                 }
78         } else {
79                 FCGI_RejectJSONEx(context, STATUS_UNAUTHORIZED, 
80                         "Invalid control key specified.");
81                 return;
82         }
83
84         switch(mode) {
85                 case START:
86                         if (!*name) {
87                                 FCGI_RejectJSON(context, "An experiment name must be provided");
88                         } else if (ExperimentExists(name) && !force) {
89                                 FCGI_RejectJSONEx(context, STATUS_ALREADYEXISTS,
90                                         "An experiment with the specified name already exists.");
91                         } else if (!Control_Start(name)) {
92                                 FCGI_RejectJSON(context, "An experiment is already running.");
93                         } else {
94                                 FCGI_BeginJSON(context, STATUS_OK);
95                                 FCGI_EndJSON();
96                         }
97                         break;
98                 case PAUSE:
99                         if (!Control_Pause()) {
100                                 FCGI_RejectJSON(context, "No experiment to pause.");
101                         } else {
102                                 FCGI_BeginJSON(context, STATUS_OK);
103                                 FCGI_EndJSON();
104                         }
105                         break;
106                 case RESUME:
107                         if (!Control_Resume()) {
108                                 FCGI_RejectJSON(context, "No experiment to resume.");
109                         } else {
110                                 FCGI_BeginJSON(context, STATUS_OK);
111                                 FCGI_EndJSON();                         
112                         }
113                         break;
114                 case STOP:
115                         if (!Control_Stop()) {
116                                 FCGI_RejectJSON(context, "No experiment to stop.");
117                         } else {
118                                 FCGI_BeginJSON(context, STATUS_OK);
119                                 FCGI_EndJSON();
120                         }
121                         break;
122         }
123 }
124
125 bool Control_Start(const char *experiment_name) {
126         bool ret = false;
127
128         pthread_mutex_lock(&(g_controls.mutex));
129         if (g_controls.state == STATE_STOPPED) {
130                 FILE *fp = fopen(experiment_name, "a");
131                 if (fp) {
132                         fclose(fp);
133                         gettimeofday(&(g_controls.start_time), NULL);
134                         Sensor_StartAll(experiment_name);
135                         Actuator_StartAll(experiment_name);
136                         g_controls.state = STATE_RUNNING;
137                         ret = true;
138                 }
139         }
140         pthread_mutex_unlock(&(g_controls.mutex));
141         return ret;
142 }
143
144
145 bool Control_Pause() {
146         bool ret = false;
147         pthread_mutex_lock(&(g_controls.mutex));
148         if (g_controls.state == STATE_RUNNING) {
149                 Actuator_PauseAll();
150                 Sensor_PauseAll();
151                 g_controls.state = STATE_PAUSED;
152                 ret = true;
153         }
154         pthread_mutex_unlock(&(g_controls.mutex));
155         return ret;
156 }
157
158 bool Control_Resume() {
159         bool ret = false;
160         pthread_mutex_lock(&(g_controls.mutex));
161         if (g_controls.state == STATE_PAUSED) {
162                 Actuator_ResumeAll();
163                 Sensor_ResumeAll();
164                 g_controls.state = STATE_RUNNING;
165                 ret = true;
166         }
167         pthread_mutex_unlock(&(g_controls.mutex));
168         return ret;
169 }
170
171 bool Control_Stop() {
172         bool ret = false;
173
174         pthread_mutex_lock(&(g_controls.mutex));
175         if (g_controls.state != STATE_STOPPED) {
176                 Actuator_StopAll();
177                 Sensor_StopAll();
178                 g_controls.state = STATE_STOPPED;
179                 ret = true;
180         }
181         pthread_mutex_unlock(&(g_controls.mutex));      
182         return ret;
183 }
184
185 bool Control_Lock() {
186         pthread_mutex_lock(&(g_controls.mutex));
187         if (g_controls.state == STATE_RUNNING || g_controls.state == STATE_PAUSED)
188                 return true;
189         pthread_mutex_unlock(&(g_controls.mutex));
190         return false;
191 }
192
193 void Control_Unlock() {
194         pthread_mutex_unlock(&(g_controls.mutex));
195 }
196
197 const struct timeval* Control_GetStartTime() {
198         return &g_controls.start_time;
199 }

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