Add semi working control code
authorJeremy Tan <[email protected]>
Sat, 14 Sep 2013 07:44:33 +0000 (15:44 +0800)
committerJeremy Tan <[email protected]>
Sat, 14 Sep 2013 07:44:33 +0000 (15:44 +0800)
server/actuator.c
server/actuator.h
server/control.c
server/control.h
server/fastcgi.c
server/fastcgi.h
server/sensor.c
server/sensor.h

index 425449c..2caa03c 100644 (file)
@@ -54,6 +54,25 @@ void Actuator_Start(Actuator * a, const char * experiment_name)
        pthread_create(&(a->thread), NULL, Actuator_Loop, (void*)(a));
 }
 
+void Actuator_Pause(Actuator *a)
+{
+       if (a->activated)
+       {
+               a->activated = false;
+               Actuator_SetControl(a, NULL);
+               pthread_join(a->thread, NULL); // Wait for thread to exit       
+       }
+}
+
+void Actuator_Resume(Actuator *a)
+{
+       if (!a->activated)
+       {
+               a->activated = true; 
+               pthread_create(&(a->thread), NULL, Actuator_Loop, (void*)(a));
+       }
+}
+
 /**
  * Stop an Actuator
  * @param s - The Actuator to stop
@@ -61,13 +80,23 @@ void Actuator_Start(Actuator * a, const char * experiment_name)
 void Actuator_Stop(Actuator * a)
 {
        // Stop
-       a->activated = false;
-       Actuator_SetControl(a, NULL);
-       pthread_join(a->thread, NULL); // Wait for thread to exit
+       Actuator_Pause(a);
        Data_Close(&(a->data_file)); // Close DataFile
 
 }
 
+void Actuator_PauseAll()
+{
+       for (int i = 0; i < NUMACTUATORS; ++i)
+               Actuator_Pause(g_actuators+i);  
+}
+
+void Actuator_ResumeAll()
+{
+       for (int i = 0; i < NUMACTUATORS; ++i)
+               Actuator_Resume(g_actuators+i); 
+}
+
 /**
  * Stop all Actuators
  */
@@ -256,33 +285,24 @@ void Actuator_Handler(FCGIContext * context, char * params)
 
        DataFormat format = Data_GetFormat(&(values[FORMAT]));
 
-       if (Control_Lock())
-       {
-               // Begin response
-               Actuator_BeginResponse(context, id, format);
-
-               // Set?
-               if (FCGI_RECEIVED(values[SET].flags))
-               {
-                       if (format == JSON)
-                               FCGI_JSONDouble("set", set);
-               
-                       ActuatorControl c;
-                       c.value = set;
-
-                       Actuator_SetControl(a, &c);
-               }
-
-               // Print Data
-               Data_Handler(&(a->data_file), &(values[START_TIME]), &(values[END_TIME]), format, current_time);
-               
-               // Finish response
-               Actuator_EndResponse(context, id, format);
+       // Begin response
+       Actuator_BeginResponse(context, id, format);
 
-               Control_Unlock();
-       }
-       else
+       // Set?
+       if (FCGI_RECEIVED(values[SET].flags))
        {
-               FCGI_RejectJSON(context, "Experiment is not running.");
+               if (format == JSON)
+                       FCGI_JSONDouble("set", set);
+       
+               ActuatorControl c;
+               c.value = set;
+
+               Actuator_SetControl(a, &c);
        }
+
+       // Print Data
+       Data_Handler(&(a->data_file), &(values[START_TIME]), &(values[END_TIME]), format, current_time);
+       
+       // Finish response
+       Actuator_EndResponse(context, id, format);
 }
index df946a0..8a6b644 100644 (file)
@@ -61,6 +61,9 @@ extern void Actuator_Init(); // One off initialisation of *all* Actuators
 extern void Actuator_StartAll(const char * experiment_name); // Start all Actuators
 extern void Actuator_StopAll(); // Stop all Actuators
 
+extern void Actuator_PauseAll();
+extern void Actuator_ResumeAll();
+
 extern void Actuator_Start(Actuator * a, const char * experiment_name); // Start a Actuator
 extern void Actuator_Stop(Actuator * a); // Stop an Actuator
 
index 4c64f02..29d9ef6 100644 (file)
@@ -13,6 +13,13 @@ typedef enum ControlState {
        STATE_RUNNING
 } ControlState;
 
+typedef enum Mode {
+       START,
+       PAUSE,
+       RESUME,
+       STOP
+} Mode;
+
 typedef struct ControlData {
        ControlState state;
        pthread_mutex_t mutex;
@@ -21,6 +28,14 @@ typedef struct ControlData {
 
 ControlData g_controls = {STATE_STOPPED, PTHREAD_MUTEX_INITIALIZER, {0}};
 
+static bool ExperimentExists(const char *experiment_name) {
+       FILE *fp = fopen(experiment_name, "r");
+       if (!fp)
+               return false;
+       fclose(fp);
+       return true;
+}
+
 /**
  * System control handler. This covers high-level control, including
  * admin related functions and starting/stopping experiments..
@@ -30,6 +45,7 @@ ControlData g_controls = {STATE_STOPPED, PTHREAD_MUTEX_INITIALIZER, {0}};
 void Control_Handler(FCGIContext *context, char *params) {
        const char *action, *key = "", *name = "";
        bool force = false;
+       Mode mode;
 
        FCGIValue values[4] = {
                {"action", &action, FCGI_REQUIRED(FCGI_STRING_T)},
@@ -43,27 +59,66 @@ void Control_Handler(FCGIContext *context, char *params) {
        
        if (!strcmp(action, "lock")) {
                FCGI_LockControl(context, force);
+               return;
        } else if (FCGI_HasControl(context, key)) {
                if (!strcmp(action, "release")) {
                        FCGI_ReleaseControl(context);
                } else if (!strcmp(action, "start")) {
-                       FCGI_BeginJSON(context, STATUS_OK);
-                       FCGI_JSONPair("description", "start");
-                       FCGI_EndJSON();
+                       mode = START;
                } else if (!strcmp(action, "pause")) {
-                       FCGI_BeginJSON(context, STATUS_OK);
-                       FCGI_JSONPair("description", "stop");
-                       FCGI_EndJSON();
-               } else if (!strcmp(action, "end")) {
-                       FCGI_BeginJSON(context, STATUS_OK);
-                       FCGI_JSONPair("description", "stop");
-                       FCGI_EndJSON();
+                       mode = PAUSE;
+               } else if (!strcmp(action, "resume")) {
+                       mode = RESUME;
+               } else if (!strcmp(action, "stop")) {
+                       mode = STOP;
                } else {
                        FCGI_RejectJSON(context, "Unknown action specified.");
+                       return;
                }
        } else {
                FCGI_RejectJSONEx(context, STATUS_UNAUTHORIZED, 
                        "Invalid control key specified.");
+               return;
+       }
+
+       switch(mode) {
+               case START:
+                       if (!*name) {
+                               FCGI_RejectJSON(context, "An experiment name must be provided");
+                       } else if (ExperimentExists(name) && !force) {
+                               FCGI_RejectJSONEx(context, STATUS_ALREADYEXISTS,
+                                       "An experiment with the specified name already exists.");
+                       } else if (!Control_Start(name)) {
+                               FCGI_RejectJSON(context, "An experiment is already running.");
+                       } else {
+                               FCGI_BeginJSON(context, STATUS_OK);
+                               FCGI_EndJSON();
+                       }
+                       break;
+               case PAUSE:
+                       if (!Control_Pause()) {
+                               FCGI_RejectJSON(context, "No experiment to pause.");
+                       } else {
+                               FCGI_BeginJSON(context, STATUS_OK);
+                               FCGI_EndJSON();
+                       }
+                       break;
+               case RESUME:
+                       if (!Control_Resume()) {
+                               FCGI_RejectJSON(context, "No experiment to resume.");
+                       } else {
+                               FCGI_BeginJSON(context, STATUS_OK);
+                               FCGI_EndJSON();                         
+                       }
+                       break;
+               case STOP:
+                       if (!Control_Stop()) {
+                               FCGI_RejectJSON(context, "No experiment to stop.");
+                       } else {
+                               FCGI_BeginJSON(context, STATUS_OK);
+                               FCGI_EndJSON();
+                       }
+                       break;
        }
 }
 
@@ -72,20 +127,45 @@ bool Control_Start(const char *experiment_name) {
 
        pthread_mutex_lock(&(g_controls.mutex));
        if (g_controls.state == STATE_STOPPED) {
-               gettimeofday(&(g_controls.start_time), NULL);
-               Sensor_StartAll(experiment_name);
-               Actuator_StartAll(experiment_name);
-               g_controls.state = STATE_RUNNING;
-               ret = true;
+               FILE *fp = fopen(experiment_name, "a");
+               if (fp) {
+                       fclose(fp);
+                       gettimeofday(&(g_controls.start_time), NULL);
+                       Sensor_StartAll(experiment_name);
+                       Actuator_StartAll(experiment_name);
+                       g_controls.state = STATE_RUNNING;
+                       ret = true;
+               }
        }
        pthread_mutex_unlock(&(g_controls.mutex));
        return ret;
 }
 
 
-void Control_Pause() {
+bool Control_Pause() {
+       bool ret = false;
        pthread_mutex_lock(&(g_controls.mutex));
+       if (g_controls.state == STATE_RUNNING) {
+               Actuator_PauseAll();
+               Sensor_PauseAll();
+               g_controls.state = STATE_PAUSED;
+               ret = true;
+       }
        pthread_mutex_unlock(&(g_controls.mutex));
+       return ret;
+}
+
+bool Control_Resume() {
+       bool ret = false;
+       pthread_mutex_lock(&(g_controls.mutex));
+       if (g_controls.state == STATE_PAUSED) {
+               Actuator_ResumeAll();
+               Sensor_ResumeAll();
+               g_controls.state = STATE_RUNNING;
+               ret = true;
+       }
+       pthread_mutex_unlock(&(g_controls.mutex));
+       return ret;
 }
 
 bool Control_Stop() {
@@ -104,7 +184,7 @@ bool Control_Stop() {
 
 bool Control_Lock() {
        pthread_mutex_lock(&(g_controls.mutex));
-       if (g_controls.state == STATE_RUNNING)
+       if (g_controls.state == STATE_RUNNING || g_controls.state == STATE_PAUSED)
                return true;
        pthread_mutex_unlock(&(g_controls.mutex));
        return false;
index f1b95ea..188b13a 100644 (file)
@@ -8,7 +8,8 @@
 /** ID codes for all the actuators **/
 extern void Control_Handler(FCGIContext *context, char *params);
 extern bool Control_Start(const char *experiment_name);
-extern void Control_Pause();
+extern bool Control_Pause();
+extern bool Control_Resume();
 extern bool Control_Stop();
 extern bool Control_Lock();
 extern void Control_Unlock();
index 05dae34..6b2957e 100644 (file)
@@ -439,6 +439,7 @@ void * FCGI_RequestLoop (void *data)
                Log(LOGDEBUG, "Got request #%d", context.response_number);
                ModuleHandler module_handler = NULL;
                char module[BUFSIZ], params[BUFSIZ];
+               bool lock_required = false;
                
                //strncpy doesn't zero-truncate properly
                snprintf(module, BUFSIZ, "%s", getenv("DOCUMENT_URI_LOCAL"));
@@ -462,13 +463,21 @@ void * FCGI_RequestLoop (void *data)
                        module_handler = Control_Handler;
                } else if (!strcmp("sensors", module)) {
                        module_handler = Sensor_Handler;
+                       lock_required = true;
                } else if (!strcmp("actuators", module)) {
                        module_handler = Actuator_Handler;
+                       lock_required = true;
                }
 
                context.current_module = module;
                if (module_handler) {
-                       module_handler(&context, params);
+                       if (lock_required && !Control_Lock()) {
+                               FCGI_RejectJSONEx(&context, STATUS_NOTRUNNING, "Experiment is not running.");
+                       } else {
+                               module_handler(&context, params);
+                               if (lock_required)
+                                       Control_Unlock();
+                       }
                } else {
                        FCGI_RejectJSON(&context, "Unhandled module");
                }
index c1e0b3e..af56301 100644 (file)
@@ -17,7 +17,8 @@ typedef enum StatusCodes {
        STATUS_OK = 1,
        STATUS_ERROR = -1,
        STATUS_UNAUTHORIZED = -2,
-       STATUS_OUTOFRANGE = -3
+       STATUS_NOTRUNNING = -3,
+       STATUS_ALREADYEXISTS = -4
 } StatusCodes;
 
 #define FCGI_PARAM_REQUIRED (1 << 0)
index a151312..867f7d4 100644 (file)
@@ -69,22 +69,43 @@ void Sensor_Start(Sensor * s, const char * experiment_name)
 }
 
 /**
- * Stop a Sensor from recording DataPoints. Blocks until it has stopped.
- * @param s - The Sensor to stop
+ * Pause a sensor from recording DataPoints. Blocks until it is paused.
+ * @param s - The Sensor to pause
  */
-void Sensor_Stop(Sensor * s)
+void Sensor_Pause(Sensor *s)
 {
-       // Stop
        if (s->record_data)
        {
                s->record_data = false;
-               pthread_join(s->thread, NULL); // Wait for thread to exit
-               Data_Close(&(s->data_file)); // Close DataFile
-               s->newest_data.time_stamp = 0;
-               s->newest_data.value = 0;
+               pthread_join(s->thread, NULL);
        }
 }
 
+/**
+ * Resumes a paused sensor.
+ * @param s - The Sensor to resume
+ */
+void Sensor_Resume(Sensor *s)
+{
+       if (!s->record_data)
+       {
+               s->record_data = true;
+               pthread_create(&(s->thread), NULL, Sensor_Loop, (void*)(s));
+       }
+}
+
+/**
+ * Stop a Sensor from recording DataPoints. Blocks until it has stopped.
+ * @param s - The Sensor to stop
+ */
+void Sensor_Stop(Sensor * s)
+{
+       Sensor_Pause(s);
+       Data_Close(&(s->data_file)); // Close DataFile
+       s->newest_data.time_stamp = 0;
+       s->newest_data.value = 0;
+}
+
 /**
  * Stop all Sensors
  */
@@ -94,6 +115,18 @@ void Sensor_StopAll()
                Sensor_Stop(g_sensors+i);
 }
 
+void Sensor_PauseAll()
+{
+       for (int i = 0; i < NUMSENSORS; ++i)
+               Sensor_Pause(g_sensors+i);
+}
+
+void Sensor_ResumeAll()
+{
+       for (int i = 0; i < NUMSENSORS; ++i)
+               Sensor_Resume(g_sensors+i);
+}
+
 /**
  * Start all Sensors
  */
@@ -325,23 +358,14 @@ void Sensor_Handler(FCGIContext *context, char * params)
 
        DataFormat format = Data_GetFormat(&(values[FORMAT]));
 
-       if (Control_Lock())
-       {
-               // Begin response
-               Sensor_BeginResponse(context, id, format);
-
-               // Print Data
-               Data_Handler(&(s->data_file), &(values[START_TIME]), &(values[END_TIME]), format, current_time);
-               
-               // Finish response
-               Sensor_EndResponse(context, id, format);
+       // Begin response
+       Sensor_BeginResponse(context, id, format);
 
-               Control_Unlock();
-       }
-       else
-       {
-               FCGI_RejectJSON(context, "Experiment is not running.");
-       }
+       // Print Data
+       Data_Handler(&(s->data_file), &(values[START_TIME]), &(values[END_TIME]), format, current_time);
+       
+       // Finish response
+       Sensor_EndResponse(context, id, format);
 }
 
 
index 1b44673..6c51ac1 100644 (file)
@@ -55,7 +55,10 @@ extern void Sensor_StartAll(const char * experiment_name); // Start all Sensors
 extern void Sensor_StopAll(); // Stop all Sensors recording data
 extern void Sensor_Start(Sensor * s, const char * experiment_name); // Start a sensor recording datas
 extern void Sensor_Stop(Sensor * s); // Stop a Sensor from recording data
-
+extern void Sensor_Pause(Sensor *s);
+extern void Sensor_Resume(Sensor *s);
+extern void Sensor_PauseAll();
+extern void Sensor_ResumeAll();
 
 extern void * Sensor_Loop(void * args); // Main loop for a thread that handles a Sensor
 extern bool Sensor_Read(Sensor * s, DataPoint * d); // Read a single DataPoint, indicating if it has changed since the last one

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