Merge branch 'master' of github:szmoore/MCTX3420
authorSam Moore <[email protected]>
Sat, 19 Oct 2013 15:40:22 +0000 (23:40 +0800)
committerSam Moore <[email protected]>
Sat, 19 Oct 2013 15:40:22 +0000 (23:40 +0800)
Conflicts:
server/control.c

15 files changed:
server/Makefile
server/actuator.c
server/common.h
server/control.c
server/control.h
server/data.c
server/fastcgi.c
server/image.h
server/main.c
server/options.h
server/sensor.c
server/sensor.h
server/sensors/pressure.c
server/sensors/resource.c
server/sensors/strain.c

index c5be05f..39a71fb 100644 (file)
@@ -1,6 +1,6 @@
 # Makefile for server software
 CXX = gcc
-FLAGS = -std=c99 -Wall -pedantic -g -I/usr/include/opencv -I/usr/include/opencv2/highgui -L/usr/lib
+FLAGS = -std=gnu99 -Wall -pedantic -g -I/usr/include/opencv -I/usr/include/opencv2/highgui -L/usr/lib
 LIB = -lfcgi -lssl -lcrypto -lpthread -lm -lopencv_highgui -lopencv_core -lopencv_ml -lopencv_imgproc -lldap -lcrypt
 OBJ = log.o control.o data.o fastcgi.o main.o sensor.o actuator.o image.o bbb_pin.o pin_test.o login.o sensors/sensors.a actuators/actuators.a
 RM = rm -f
index 2be4194..1c105db 100644 (file)
@@ -171,9 +171,12 @@ void * Actuator_Loop(void * arg)
 
                Actuator_SetValue(a, a->control.start, true);
                // Currently does discrete steps after specified time intervals
+
+               struct timespec wait;
+               DOUBLE_TO_TIMEVAL(a->control.stepsize, &wait);
                while (!a->control_changed && a->control.steps > 0 && a->activated)
                {
-                       usleep(1e6*(a->control.stepwait));
+                       clock_nanosleep(CLOCK_MONOTONIC, 0, &wait, NULL);
                        a->control.start += a->control.stepsize;
                        Actuator_SetValue(a, a->control.start, true);
                        
@@ -181,7 +184,7 @@ void * Actuator_Loop(void * arg)
                }
                if (a->control_changed)
                        continue;
-               usleep(1e6*(a->control.stepwait));
+               clock_nanosleep(CLOCK_MONOTONIC, 0, &wait, NULL);
 
                //TODO:
                // Note that although this loop has a sleep in it which would seem to make it hard to enforce urgent shutdowns,
@@ -231,8 +234,8 @@ void Actuator_SetValue(Actuator * a, double value, bool record)
        }
 
        // Set time stamp
-       struct timeval t;
-       gettimeofday(&t, NULL);
+       struct timespec t;
+       clock_gettime(CLOCK_MONOTONIC, &t);
        DataPoint d = {TIMEVAL_DIFF(t, *Control_GetStartTime()), a->last_setting.value};
        // Record value change
        if (record)
@@ -296,8 +299,8 @@ void Actuator_EndResponse(FCGIContext * context, Actuator * a, DataFormat format
  */
 void Actuator_Handler(FCGIContext * context, char * params)
 {
-       struct timeval now;
-       gettimeofday(&now, NULL);
+       struct timespec now;
+       clock_gettime(CLOCK_MONOTONIC, &now);
        double current_time = TIMEVAL_DIFF(now, *Control_GetStartTime());
        int id = 0;
        char * name = "";
index fa997c5..0875b34 100644 (file)
@@ -8,9 +8,9 @@
 
 /** Defines required to allow various C standard functions to be used **/
 #define _POSIX_C_SOURCE 200809L
-#define _BSD_SOURCE
+//#define _BSD_SOURCE
 #define _XOPEN_SOURCE 600
-
+#define _GNU_SOURCE
 /** Determine if we're running on the BBB **/
 #ifdef __arm__
        #define _BBB
@@ -21,6 +21,7 @@
 /** The current API version **/
 #define API_VERSION 0
 
+//#define REALTIME_VERSION
 
 
 
 #include <assert.h>
 #include <sys/time.h>
 #include <time.h>
+#include <string.h>
 
 #include "log.h"
 #include "fastcgi.h"
 #include "control.h"
 
 /**Converts a timeval to a double**/
-#define TIMEVAL_TO_DOUBLE(tv) ((tv).tv_sec + 1e-6 * ((tv).tv_usec))
+#define TIMEVAL_TO_DOUBLE(tv) ((tv).tv_sec + 1e-9 * ((tv).tv_nsec))
 /**Takes the tv1-tv2 between two timevals and returns the result as a double*/
-#define TIMEVAL_DIFF(tv1, tv2) ((tv1).tv_sec - (tv2).tv_sec + 1e-6 * ((tv1).tv_usec - (tv2).tv_usec))
-
+#define TIMEVAL_DIFF(tv1, tv2) ((tv1).tv_sec - (tv2).tv_sec + 1e-9 * ((tv1).tv_nsec - (tv2).tv_nsec))
+/** Converts a double time value (in seconds) to a timespec **/
+#define DOUBLE_TO_TIMEVAL(value, tv) { \
+                                                                               (tv)->tv_sec = (int)(value); \
+                                                                               (tv)->tv_nsec = ((value) - (int)(value))*1e9; \
+                                                                       }
 
 extern bool PathExists(const char * path);
 extern bool DirExists(const char * path);
 
 
 
-
 #endif //_COMMON_H
index 4342c8c..6ebaba7 100644 (file)
@@ -14,7 +14,7 @@
 typedef struct ControlData {
        ControlModes current_mode;
        pthread_mutex_t mutex;
-       struct timeval start_time;
+       struct timespec start_time;
        char user_name[31]; // The user who owns the currently running experiment
        char experiment_dir[BUFSIZ]; //Directory for experiment
        char experiment_name[BUFSIZ];
@@ -225,7 +225,7 @@ const char* Control_SetMode(ControlModes desired_mode, void * arg)
                                                path, strerror(errno));
                                        ret = "Couldn't create experiment directory.";
                                } else {
-                                       gettimeofday(&(g_controls.start_time), NULL);
+                                       clock_gettime(CLOCK_MONOTONIC, &(g_controls.start_time));
                                }
                        } else 
                                ret = "Cannot start when not in a stopped state.";
@@ -280,6 +280,6 @@ const char * Control_GetModeName() {
  * Gets the start time for the current experiment
  * @return the start time
  */
-const struct timeval* Control_GetStartTime() {
+const struct timespec * Control_GetStartTime() {
        return &g_controls.start_time;
 }
index 3ceea9f..7081c3f 100644 (file)
@@ -24,6 +24,6 @@ extern ControlModes Control_GetMode();
 extern const char * Control_GetModeName();
 //extern bool Control_Lock();
 //extern void Control_Unlock();
-extern const struct timeval* Control_GetStartTime();
+extern const struct timespec* Control_GetStartTime();
 
 #endif
index dae3172..edfd4c3 100644 (file)
@@ -161,13 +161,13 @@ void Data_PrintByIndexes(DataFile * df, int start_index, int end_index, DataForm
        switch (format)
        {
                case JSON:
-                       fmt_string = "[%f,%f]";
+                       fmt_string = "[%.9f,%f]";
                        separator = ',';
                        // For JSON we need an opening bracket
                        FCGI_PrintRaw("["); 
                        break;
                case TSV:
-                       fmt_string = "%f\t%f";
+                       fmt_string = "%.9f\t%f";
                        separator = '\n';
                        break;
        }
index fd5839e..0a6783f 100644 (file)
@@ -50,9 +50,14 @@ static void IdentifyHandler(FCGIContext *context, char *params) {
        FCGI_BeginJSON(context, STATUS_OK);
        FCGI_JSONPair("description", "MCTX3420 Server API (2013)");
        FCGI_JSONPair("build_date", __DATE__ " " __TIME__);
+       struct timespec t;
+       t.tv_sec = 0; t.tv_nsec = 0;
+       clock_getres(CLOCK_MONOTONIC, &t);
+       FCGI_JSONDouble("clock_getres", TIMEVAL_TO_DOUBLE(t));
        FCGI_JSONLong("api_version", API_VERSION);
        FCGI_JSONBool("logged_in", has_control);
        FCGI_JSONPair("user_name", has_control ? context->user_name : "");
+       
 
        //Sensor and actuator information
        if (ident_sensors) {
@@ -328,8 +333,8 @@ void FCGI_BeginJSON(FCGIContext *context, StatusCodes status_code)
        printf("\t\"module\" : \"%s\"", context->current_module);
        FCGI_JSONLong("status", status_code);
        //Time and running statistics
-       struct timeval now;
-       gettimeofday(&now, NULL);
+       struct timespec now;
+       clock_gettime(CLOCK_MONOTONIC, &now);
        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));
@@ -383,7 +388,7 @@ void FCGI_JSONLong(const char *key, long value)
  */
 void FCGI_JSONDouble(const char *key, double value)
 {
-       printf(",\r\n\t\"%s\" : %f", key, value);
+       printf(",\r\n\t\"%s\" : %.9f", key, value);
 }
 
 /**
@@ -554,8 +559,8 @@ void * FCGI_RequestLoop (void *data)
                
                if (module_handler) 
                {
-                       if (module_handler != Login_Handler && module_handler != IdentifyHandler && module_handler)
-                       //if (false) // Testing
+                       //if (module_handler != Login_Handler && module_handler != IdentifyHandler && module_handler)
+                       if (false) // Testing
                        {
                                if (!FCGI_HasControl(&context, control_key))
                                {
index b62a7bd..3c1ab69 100644 (file)
@@ -8,7 +8,9 @@
 
 #include "common.h"
 
+extern void Image_Init();
 extern void Image_Handler(FCGIContext * context, char * params); 
+extern void Image_Cleanup();
 
 #endif //_IMAGE_H
 
index e7edc7e..fadcd3a 100644 (file)
 #include <signal.h> // for signal handling
 
 
+#ifdef REALTIME_VERSION
+#include <time.h>
+#include <sched.h>
+#include <sys/mman.h>
+#include <sys/utsname.h>
+#endif //REALTIME_VERSION
+
 // --- Variable definitions --- //
 Options g_options; // options passed to program through command line arguments
 
@@ -35,7 +42,7 @@ void ParseArguments(int argc, char ** argv)
        //if (getcwd(g_options.root_dir, sizeof(g_options.root_dir)) == NULL)
        //      Fatal("Couldn't get current working directory - %s", strerror(errno));
 
-       gettimeofday(&(g_options.start_time), NULL); // Start time
+       clock_gettime(CLOCK_MONOTONIC, &(g_options.start_time)); // Start time
 
 
        g_options.auth_method = AUTH_NONE;  // Don't use authentication
@@ -120,6 +127,38 @@ void Cleanup()
        Log(LOGDEBUG, "Finish cleanup.");
 }
 
+
+#ifdef REALTIME_VERSION
+
+#define MAX_SAFE_STACK (8*1024)
+#define NSEC_PER_SEC (1000000000)
+
+void stack_prefault()
+{
+       unsigned char dummy[MAX_SAFE_STACK];
+       memset(dummy, 0, MAX_SAFE_STACK);
+       return;
+}
+
+bool is_realtime()
+{
+       struct utsname u;
+       bool crit1 = 0;
+       bool crit2 = 0;
+       FILE * f;
+       uname(&u);
+       crit1 = (strcasestr(u.version, "PREEMPT RT") != NULL);
+       if (crit1 && ((f = fopen("/sys/kernel/realtime", "r")) != NULL))
+       {
+               int flag;
+               crit2 = ((fscanf(f, "%d", &flag) == 1) && (flag == 1));
+               fclose(f);
+       }
+       return (crit1 && crit2);
+}
+
+#endif //REALTIME_VERSION
+
 /**
  * Main entry point; start worker threads, setup signal handling, wait for threads to exit, exit
  * @param argc - Num args
@@ -129,30 +168,55 @@ void Cleanup()
  */
 int main(int argc, char ** argv)
 {
+
        // Open log before calling ParseArguments (since ParseArguments may call the Log functions)
        openlog("mctxserv", LOG_PID | LOG_PERROR, LOG_USER);
-       Log(LOGINFO, "Server started");
 
        ParseArguments(argc, argv); // Setup the g_options structure from program arguments
 
+       Log(LOGINFO, "Server started");
+
+
+       
+       #ifdef REALTIME_VERSION
+       
+       if (is_realtime())
+       {
+               Log(LOGDEBUG, "Running under realtime kernel");
+       }
+       else
+       {
+               Fatal("Not running under realtime kernel");
+       }
+       struct sched_param param;
+       param.sched_priority = 49;
+       if (sched_setscheduler(0, SCHED_FIFO, &param) < 0)
+               Fatal("sched_setscheduler failed - %s", strerror(errno));
+       if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1)
+               Fatal("mlockall failed - %s", strerror(errno));
+       stack_prefault();
+       #endif //REALTIME_VERSION
+
+       
+
        Sensor_Init();
        Actuator_Init();
        Pin_Init();
        
        // Try and start things
-       /*
+       
        const char *ret;
        if ((ret = Control_SetMode(CONTROL_START, "test")) != NULL)
                Fatal("Control_SetMode failed with '%s'", ret);
-       */
+       
 
        // run request thread in the main thread
        FCGI_RequestLoop(NULL);
 
-       /*
+       
        if ((ret = Control_SetMode(CONTROL_STOP, "test")) != NULL)
                Fatal("Control_SetMode failed with '%s'", ret);
-       */
+       
        //Sensor_StopAll();
        //Actuator_StopAll();
 
index 385a05b..0e0b598 100644 (file)
@@ -15,9 +15,9 @@ typedef struct
        /** Determines at what level log messages are shown **/
        int verbosity;
        /** Time at which program begins to run **/
-       struct timeval start_time;
+       struct timespec start_time;
        /** Time at which program exits **/
-       struct timeval end_time;
+       struct timespec end_time;
 
        /** Whether or not to enable the pin_test module **/
        bool enable_pin;
index c41d39e..ae5cdf4 100644 (file)
@@ -47,8 +47,9 @@ int Sensor_Add(const char * name, int user_id, ReadFn read, InitFn init, CleanFn
        s->init = init; // Set init function
 
        // Start by averaging values taken over a second
-       s->sample_us = 1e6;
+       DOUBLE_TO_TIMEVAL(1e-4, &(s->sample_time));
        s->averages = 1;
+       s->num_read = 0;
 
        // Set sanity function
        s->sanity = sanity;
@@ -59,7 +60,8 @@ int Sensor_Add(const char * name, int user_id, ReadFn read, InitFn init, CleanFn
                        Fatal("Couldn't init sensor %s", name);
        }
 
-
+       s->current_data.time_stamp = 0;
+       s->current_data.value = 0;
        return g_num_sensors;
 }
 
@@ -75,9 +77,9 @@ void Sensor_Init()
 {
        Sensor_Add("cpu_stime", RESOURCE_CPU_SYS, Resource_Read, NULL, NULL, NULL);     
        Sensor_Add("cpu_utime", RESOURCE_CPU_USER, Resource_Read, NULL, NULL, NULL);    
-       Sensor_Add("pressure_high0", PRES_HIGH0, Pressure_Read, Pressure_Init, Pressure_Cleanup, NULL);
-       Sensor_Add("pressure_high1", PRES_HIGH1, Pressure_Read, Pressure_Init, Pressure_Cleanup, NULL);
-       Sensor_Add("pressure_low0", PRES_LOW0, Pressure_Read, Pressure_Init, Pressure_Cleanup, NULL);
+       //Sensor_Add("pressure_high0", PRES_HIGH0, Pressure_Read, Pressure_Init, Pressure_Cleanup, NULL);
+       //Sensor_Add("pressure_high1", PRES_HIGH1, Pressure_Read, Pressure_Init, Pressure_Cleanup, NULL);
+       //Sensor_Add("pressure_low0", PRES_LOW0, Pressure_Read, Pressure_Init, Pressure_Cleanup, NULL);
        //Sensor_Add("../testing/count.py", 0, Piped_Read, Piped_Init, Piped_Cleanup, 1e50,-1e50,1e50,-1e50);
        //Sensor_Add("strain0", STRAIN0, Strain_Read, Strain_Init, 5000,0,5000,0);
        //Sensor_Add("strain1", STRAIN1, Strain_Read, Strain_Init, 5000,0,5000,0);
@@ -203,8 +205,8 @@ void * Sensor_Loop(void * arg)
                d.value = 0;
                bool success = s->read(s->user_id, &(d.value));
 
-               struct timeval t;
-               gettimeofday(&t, NULL);
+               struct timespec t;
+               clock_gettime(CLOCK_MONOTONIC, &t);
                d.time_stamp = TIMEVAL_DIFF(t, *Control_GetStartTime());        
                
                if (success)
@@ -216,12 +218,25 @@ void * Sensor_Loop(void * arg)
                                        Fatal("Sensor %s (%d,%d) reads unsafe value", s->name, s->id, s->user_id);
                                }
                        }
-                       Data_Save(&(s->data_file), &d, 1); // Record it
+                       s->current_data.time_stamp += d.time_stamp;
+                       s->current_data.value += d.value;
+                       
+                       if (++(s->num_read) >= s->averages)
+                       {
+                               s->current_data.time_stamp /= s->averages;
+                               s->current_data.value /= s->averages;
+                               Data_Save(&(s->data_file), &(s->current_data), 1); // Record it
+                               s->num_read = 0;
+                               s->current_data.time_stamp = 0;
+                               s->current_data.value = 0;
+                       }
                }
                else
                        Log(LOGWARN, "Failed to read sensor %s (%d,%d)", s->name, s->id,s->user_id);
 
-               usleep(s->sample_us);
+
+               clock_nanosleep(CLOCK_MONOTONIC, 0, &(s->sample_time), NULL);
+               
        }
        
        // Needed to keep pthreads happy
@@ -292,8 +307,8 @@ void Sensor_EndResponse(FCGIContext * context, Sensor * s, DataFormat format)
  */
 void Sensor_Handler(FCGIContext *context, char * params)
 {
-       struct timeval now;
-       gettimeofday(&now, NULL);
+       struct timespec now;
+       clock_gettime(CLOCK_MONOTONIC, &now);
        double current_time = TIMEVAL_DIFF(now, *Control_GetStartTime());
        int id = 0;
        const char * name = "";
@@ -367,7 +382,7 @@ void Sensor_Handler(FCGIContext *context, char * params)
                        FCGI_RejectJSON(context, "Negative sampling speed!");
                        return;
                }               
-               s->sample_us = 1e6*sample_s;
+               DOUBLE_TO_TIMEVAL(sample_s, &(s->sample_time));
        }
        
        
index 0285252..0fe2136 100644 (file)
@@ -56,7 +56,7 @@ typedef struct
        /** Human readable name of the sensor **/
        const char * name;
        /** Sampling rate **/
-       int sample_us;
+       struct timespec sample_time;
        /** Number of averages per sample **/
        int averages;
 
index ddb46df..61cdbcf 100644 (file)
@@ -46,7 +46,7 @@ double Pressure_Callibrate(int id, int adc)
                case PRES_HIGH1:
                {
                        static const double Vs = 5e3; // In mVs
-                       static const double Pmin = 0.0;
+                       static const double Pmin = 0.0 * PSI_TO_KPA;
                        static const double Pmax = 150.0 * PSI_TO_KPA;
                        double Vout = ADC_TO_MVOLTS(adc);
                        return ((Vout - 0.1*Vs)/(0.8*Vs))*(Pmax - Pmin) + Pmin;
@@ -93,9 +93,10 @@ bool Pressure_Read(int id, double * value)
        //static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
        //pthread_mutex_lock(&mutex);
        bool result = false;
-       if (ADC_Read(Pressure_GetADC(id), value))
+       int adc = 0;
+       if (ADC_Read(Pressure_GetADC(id), &adc))
        {
-               *value = Pressure_Callibrate(id, *value);
+               *value = Pressure_Callibrate(id, adc);
                result = true;
        }
        //pthread_mutex_unlock(&mutex);
index fa52562..80c8594 100644 (file)
@@ -17,10 +17,10 @@ bool Resource_Read(int id, double * value)
        switch (id)
        {
                case RESOURCE_CPU_USER:
-                       *value = TIMEVAL_TO_DOUBLE(usage.ru_utime);
+                       *value = usage.ru_utime.tv_sec + 1e-6*usage.ru_utime.tv_usec;
                        break;
                case RESOURCE_CPU_SYS:
-                       *value = TIMEVAL_TO_DOUBLE(usage.ru_stime);
+                       *value = usage.ru_stime.tv_sec + 1e-6*usage.ru_stime.tv_usec;
                        break;
                default:
                        Log(LOGWARN, "Unknown id %d", id);
index 3ee1624..9492de7 100644 (file)
@@ -33,7 +33,7 @@ static int Strain_To_GPIO(StrainID id)
                default:
                        Fatal("Unknown StrainID %d", id);
                        return -1; // Should never happen
-       }
+  }
 }
 
 /**

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