Change control code - some bugfixes, plus stop threads in paused state
authorJeremy Tan <[email protected]>
Sat, 21 Sep 2013 08:27:35 +0000 (16:27 +0800)
committerJeremy Tan <[email protected]>
Sat, 21 Sep 2013 08:27:35 +0000 (16:27 +0800)
server/actuator.c
server/actuator.h
server/control.c
server/control.h
server/fastcgi.c
server/sensor.c
server/sensor.h

index 9d2ad13..c71b05a 100644 (file)
@@ -44,7 +44,6 @@ void Actuator_SetMode(Actuator * a, ControlModes mode, void *arg)
                        {
                                char filename[BUFSIZ];
                                const char *experiment_name = (const char*) arg;
-                               int ret;
 
                                if (snprintf(filename, BUFSIZ, "%s_a%d", experiment_name, a->id) >= BUFSIZ)
                                {
@@ -54,34 +53,43 @@ void Actuator_SetMode(Actuator * a, ControlModes mode, void *arg)
                                Log(LOGDEBUG, "Actuator %d with DataFile \"%s\"", a->id, filename);
                                // Open DataFile
                                Data_Open(&(a->data_file), filename);
-
+                       } 
+               case CONTROL_RESUME:  //Case fallthrough; no break before
+                       {
+                               int ret;
                                a->activated = true; // Don't forget this
-                               a->allow_actuation = true;
-
                                a->control_changed = false;
 
-                               // Create the thread
                                ret = pthread_create(&(a->thread), NULL, Actuator_Loop, (void*)(a));
                                if (ret != 0)
                                {
                                        Fatal("Failed to create Actuator_Loop for Actuator %d", a->id);
                                }
+
+                               Log(LOGDEBUG, "Resuming actuator %d", a->id);
                        }
                break;
 
                case CONTROL_EMERGENCY: //TODO add proper case for emergency
                case CONTROL_PAUSE:
-                       a->allow_actuation = false;
+                       a->activated = false;
+                       Actuator_SetControl(a, NULL);
+                       pthread_join(a->thread, NULL); // Wait for thread to exit
+
+                       Log(LOGDEBUG, "Paused actuator %d", a->id);
                break;
-               case CONTROL_RESUME:
-                       a->allow_actuation = true;
+
                break;
                case CONTROL_STOP:
-                       a->allow_actuation = false;
-                       a->activated = false;
-                       Actuator_SetControl(a, NULL);
-                       pthread_join(a->thread, NULL); // Wait for thread to exit       
+                       if (a->activated) //May have been paused before
+                       {
+                               a->activated = false;
+                               Actuator_SetControl(a, NULL);
+                               pthread_join(a->thread, NULL); // Wait for thread to exit       
+                       }
                        Data_Close(&(a->data_file)); // Close DataFile
+                       
+                       Log(LOGDEBUG, "Stopped actuator %d", a->id);
                break;
                default:
                        Fatal("Unknown control mode: %d", mode);
@@ -121,8 +129,6 @@ void * Actuator_Loop(void * arg)
                pthread_mutex_unlock(&(a->mutex));
                if (!a->activated)
                        break;
-               else if (!a->allow_actuation)
-                       continue;
 
                Actuator_SetValue(a, a->control.value);
        }
@@ -238,8 +244,6 @@ void Actuator_EndResponse(FCGIContext * context, ActuatorId id, DataFormat forma
 }
 
 
-
-
 /**
  * Handle a request for an Actuator
  * @param context - FCGI context
index 81150e8..ee0ed32 100644 (file)
@@ -52,8 +52,6 @@ typedef struct
        pthread_cond_t cond;
        /** Indicates whether the Actuator is running **/
        bool activated;
-       /** Indicates whether the Actuator can be actuated or not **/
-       bool allow_actuation;
 
 } Actuator;
 
index 2c0fd79..5c8a410 100644 (file)
@@ -50,11 +50,6 @@ void Control_Handler(FCGIContext *context, char *params) {
                return;
        } else if (!strcmp(action, "emergency")) {
                desired_mode = CONTROL_EMERGENCY;
-       } else if (!strcmp(action, "query")) {
-               FCGI_BeginJSON(context, STATUS_OK);
-               FCGI_JSONPair("state", Control_GetModeName(Control_GetMode()));
-               FCGI_EndJSON();
-               return;
        } else if (FCGI_HasControl(context, key)) {
                if (!strcmp(action, "release")) {
                        FCGI_ReleaseControl(context);
@@ -78,11 +73,7 @@ void Control_Handler(FCGIContext *context, char *params) {
 
        void *arg = NULL;
        if (desired_mode == CONTROL_START) {
-               int len = strlen(name);
-               if (len <= 0) {
-                       FCGI_RejectJSON(context, "An experiment name must be specified.");
-                       return;
-               } else if (PathExists(name) && !force) {
+               if (PathExists(name) && !force) {
                        FCGI_RejectJSON(context, "An experiment with that name already exists.");
                        return;
                }
@@ -111,26 +102,43 @@ const char* Control_SetMode(ControlModes desired_mode, void * arg)
        const char *ret = NULL;
 
        pthread_mutex_lock(&(g_controls.mutex));
-       if (g_controls.current_mode == CONTROL_EMERGENCY && desired_mode != CONTROL_STOP) {
-               ret = "In emergency mode. Stop before doing anything else.";
-       } else if (g_controls.current_mode == desired_mode) {
-               ret = "Already in desired mode.";
-       } else if (desired_mode == CONTROL_START) {
-               if (g_controls.current_mode == CONTROL_STOP) {
-                       //TODO Sanitise name (ensure it contains no special chars eg \ / .. . 
-                       FILE *fp = fopen((const char*) arg, "a");
-                       if (fp) {
-                               fclose(fp);
-                               gettimeofday(&(g_controls.start_time), NULL);
-                       } else {
-                               ret = "Cannot open experiment name marker";
-                       }
-               } else {
-                       ret = "Cannot start when not in a stopped state.";
-               }
-       } else if (desired_mode == CONTROL_RESUME) {
-               if (g_controls.current_mode != CONTROL_PAUSE)
-                       ret = "Cannot resume when not in a paused state.";
+       if (g_controls.current_mode == desired_mode)
+               ret = "Already in the desired mode.";
+       else if (g_controls.current_mode == CONTROL_EMERGENCY && desired_mode != CONTROL_STOP)
+               ret = "In emergency mode. You must stop before continuing.";
+       else switch (desired_mode) {
+               case CONTROL_START:
+                       if (g_controls.current_mode == CONTROL_STOP) {
+                               const char * name = arg;
+                               if (!*name)
+                                       ret = "An experiment name must be specified";
+                               else if (strpbrk(name, INVALID_CHARACTERS))
+                                       ret = "The experiment name must not contain: " INVALID_CHARACTERS_JSON;
+                               else {
+                                       FILE *fp = fopen((const char*) arg, "a");
+                                       if (fp) {
+                                               fclose(fp);
+                                               gettimeofday(&(g_controls.start_time), NULL);
+                                       } else
+                                               ret = "Cannot open experiment name marker";
+                               }
+                       } else 
+                               ret = "Cannot start when not in a stopped state.";
+               break;
+               case CONTROL_PAUSE:
+                       if (g_controls.current_mode != CONTROL_START)
+                               ret = "Cannot pause when not in a running state.";
+               break;
+               case CONTROL_RESUME:
+                       if (g_controls.current_mode != CONTROL_PAUSE)
+                               ret = "Cannot resume when not in a paused state.";
+               break;
+               case CONTROL_EMERGENCY:
+                       if (g_controls.current_mode != CONTROL_START) //pfft
+                               ret = "Not running so how can there be an emergency.";
+               break;
+               default:
+               break;
        }
        
        if (ret == NULL) {
@@ -146,22 +154,14 @@ const char* Control_SetMode(ControlModes desired_mode, void * arg)
 }
 
 /**
- * Gets the current mode.
- * @return The current mode
- */
-ControlModes Control_GetMode() {
-       return g_controls.current_mode;
-}
-
-/**
- * Gets a string representation of a mode
+ * Gets a string representation of the current mode
  * @param mode The mode to get a string representation of
  * @return The string representation of the mode
  */
-const char * Control_GetModeName(ControlModes mode) {
+const char * Control_GetModeName() {
        const char * ret = "Unknown";
 
-       switch (mode) {
+       switch (g_controls.current_mode) {
                case CONTROL_START: ret = "Running"; break;
                case CONTROL_PAUSE: ret = "Paused"; break;
                case CONTROL_RESUME: ret = "Resumed"; break;
@@ -171,19 +171,6 @@ const char * Control_GetModeName(ControlModes mode) {
        return ret;
 }
 
-/*
-bool Control_Lock() {
-       pthread_mutex_lock(&(g_controls.mutex));
-       if (g_controls.state == STATE_RUNNING || g_controls.state == STATE_PAUSED)
-               return true;
-       pthread_mutex_unlock(&(g_controls.mutex));
-       return false;
-}
-
-void Control_Unlock() {
-       pthread_mutex_unlock(&(g_controls.mutex));
-}*/
-
 /**
  * Gets the start time for the current experiment
  * @return the start time
index 5b51e95..7b3511a 100644 (file)
@@ -13,11 +13,15 @@ typedef enum ControlModes {
        CONTROL_EMERGENCY
 } ControlModes;
 
-/** ID codes for all the actuators **/
+/** Invalid filename characters **/
+#define INVALID_CHARACTERS "\"*/:<>?\\|"
+/** The same as INVALID_CHARACTERS, except escaped for use in JSON strings **/
+#define INVALID_CHARACTERS_JSON "\\\"*/:<>?\\\\|"
+
 extern void Control_Handler(FCGIContext *context, char *params);
 extern const char* Control_SetMode(ControlModes desired_mode, void * arg);
 extern ControlModes Control_GetMode();
-extern const char * Control_GetModeName(ControlModes mode);
+extern const char * Control_GetModeName();
 //extern bool Control_Lock();
 //extern void Control_Unlock();
 extern const struct timeval* Control_GetStartTime();
index b7a3e6b..a648ae8 100644 (file)
@@ -294,6 +294,7 @@ void FCGI_BeginJSON(FCGIContext *context, StatusCodes status_code)
        FCGI_JSONDouble("start_time", TIMEVAL_TO_DOUBLE(g_options.start_time));
        FCGI_JSONDouble("current_time", TIMEVAL_TO_DOUBLE(now));
        FCGI_JSONDouble("running_time", TIMEVAL_DIFF(now, g_options.start_time));
+       FCGI_JSONPair("control_state", Control_GetModeName());
 }
 
 /**
index 5115f99..64c7aa9 100644 (file)
@@ -39,7 +39,6 @@ void Sensor_Init()
        {
                g_sensors[i].id = i;
                Data_Init(&(g_sensors[i].data_file));
-               g_sensors[i].record_data = false;       
        }
 }
 
@@ -61,7 +60,6 @@ void Sensor_SetMode(Sensor * s, ControlModes mode, void * arg)
                                // Set filename
                                char filename[BUFSIZ];
                                const char *experiment_name = (const char*) arg;
-                               int ret;
 
                                if (snprintf(filename, BUFSIZ, "%s_s%d", experiment_name, s->id) >= BUFSIZ)
                                {
@@ -71,9 +69,11 @@ void Sensor_SetMode(Sensor * s, ControlModes mode, void * arg)
                                Log(LOGDEBUG, "Sensor %d with DataFile \"%s\"", s->id, filename);
                                // Open DataFile
                                Data_Open(&(s->data_file), filename);
-
-                               s->activated = true;
-                               s->record_data = true; // Don't forget this!
+                       }
+               case CONTROL_RESUME: //Case fallthrough, no break before
+                       {
+                               int ret;
+                               s->activated = true; // Don't forget this!
 
                                // Create the thread
                                ret = pthread_create(&(s->thread), NULL, Sensor_Loop, (void*)(s));
@@ -81,23 +81,29 @@ void Sensor_SetMode(Sensor * s, ControlModes mode, void * arg)
                                {
                                        Fatal("Failed to create Sensor_Loop for Sensor %d", s->id);
                                }
+
+                               Log(LOGDEBUG, "Resuming sensor %d", s->id);
                        }
-                       break;
+               break;
+
                case CONTROL_EMERGENCY:
                case CONTROL_PAUSE:
-                       s->record_data = false;
-               break;
-               case CONTROL_RESUME:
-                       s->record_data = true;
-               break;
-               case CONTROL_STOP:
                        s->activated = false;
-                       s->record_data = false;
                        pthread_join(s->thread, NULL);
+                       Log(LOGDEBUG, "Paused sensor %d", s->id);
+               break;
+               
+               case CONTROL_STOP:
+                       if (s->activated) //May have been paused before
+                       {
+                               s->activated = false;
+                               pthread_join(s->thread, NULL);
+                       }
 
                        Data_Close(&(s->data_file)); // Close DataFile
                        s->newest_data.time_stamp = 0;
                        s->newest_data.value = 0;
+                       Log(LOGDEBUG, "Stopped sensor %d", s->id);
                break;
                default:
                        Fatal("Unknown control mode: %d", mode);
@@ -128,6 +134,7 @@ void Sensor_CheckData(SensorId id, double value)
        {
                Log(LOGERR, "Sensor %s is above or below its safety value of %f or %f\n", g_sensor_names[id],thresholds[id].max_error, thresholds[id].min_error);
                //new function that stops actuators?
+               //Control_SetMode(CONTROL_EMERGENCY, NULL)
        }
        else if( value > thresholds[id].max_warn || value < thresholds[id].min_warn)
        {
@@ -211,20 +218,12 @@ void * Sensor_Loop(void * arg)
        // Until the sensor is stopped, record data points
        while (s->activated)
        {
-               if (s->record_data)
-               {
-                       DataPoint d;
-                       //Log(LOGDEBUG, "Sensor %d reads data [%f,%f]", s->id, d.time_stamp, d.value);
-                       if (Sensor_Read(s, &d)) // If new DataPoint is read:
-                       {
-                               //Log(LOGDEBUG, "Sensor %d saves data [%f,%f]", s->id, d.time_stamp, d.value);
-                               Data_Save(&(s->data_file), &d, 1); // Record it
-                       }
-               }
-               else
+               DataPoint d;
+               //Log(LOGDEBUG, "Sensor %d reads data [%f,%f]", s->id, d.time_stamp, d.value);
+               if (Sensor_Read(s, &d)) // If new DataPoint is read:
                {
-                       //Do something? wait?
-                       usleep(100000);
+                       //Log(LOGDEBUG, "Sensor %d saves data [%f,%f]", s->id, d.time_stamp, d.value);
+                       Data_Save(&(s->data_file), &d, 1); // Record it
                }
        }
        
index bdab0f9..6c7abaa 100644 (file)
@@ -32,10 +32,8 @@ typedef struct
        SensorId id;
        /** DataFile to store sensor values in **/
        DataFile data_file;
-       /** Indicates whether the Sensor is not stopped **/
+       /** Indicates whether the Sensor is active or not **/
        bool activated;
-       /** Indicates whether the Sensor should record data **/
-       bool record_data;
        /** Thread the Sensor is running in **/
        pthread_t thread;
        /** Most recently recorded data **/

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