Merge remote-tracking branch 'upstream/master'
authorCallum <callum@callum-ubuntu.(none)>
Fri, 13 Sep 2013 04:37:04 +0000 (12:37 +0800)
committerCallum <callum@callum-ubuntu.(none)>
Fri, 13 Sep 2013 04:37:04 +0000 (12:37 +0800)
Conflicts:
server/sensor.c
server/sensor.h

1  2 
server/sensor.c
server/sensor.h

diff --cc server/sensor.c
index 2a0e762,227ea42..0000000
deleted file mode 100644,100644
+++ /dev/null
@@@ -1,623 -1,372 +1,0 @@@
--/**
-- * @file sensor.c
-- * @brief Implementation of sensor thread
-- * TODO: Finalise implementation
-- */
--
--#include "common.h"
--#include "sensor.h"
--#include "options.h"
--#include <math.h>
--
--/** Array of sensors, initialised by Sensor_Init **/
--static Sensor g_sensors[NUMSENSORS]; //global to this file
 -
 -/** Human readable names for the sensors **/
--const char * g_sensor_names[NUMSENSORS] = {   
--      "analog_test0", "analog_test1", 
-       "analog_fail0", "digital_test0", 
-       "digital_test1", "digital_fail0"
 -      "digital_test0", "digital_test1"
--};
--
--/**
-  * Checks the sensor data for unsafe or unexpected results 
-  * @param sensor_id - The ID of the sensor
-  * @param value - The value of the sensor to check
 - * One off initialisation of *all* sensors
-- */
- void CheckSensor( SensorId sensor_id, double value)
 -void Sensor_Init()
--{
-       switch (sensor_id)
 -      for (int i = 0; i < NUMSENSORS; ++i)
--      {
-               case ANALOG_FAIL0:
-               {
-                       if( value > ANALOG_FAIL0_SAFETY || value < ANALOG_FAIL0_MIN_SAFETY)
-                       {
-                               Log(LOGERR, "Sensor analog_fail0 is above or below its safety value of %d or %d\n", ANALOG_FAIL0_SAFETY, ANALOG_FAIL0_MIN_SAFETY);
-                       //new function that stops actuators?
-                       }
-                       else if( value > ANALOG_FAIL0_WARN || value < ANALOG_FAIL0_MIN_WARN)
-                       {
-                               Log(LOGWARN, "Sensor analog_test0 is above or below its warning value of %d or %d\n", ANALOG_FAIL0_WARN, ANALOG_FAIL0_MIN_WARN);        
-                       }
-                       break;
-               }
-               case DIGITAL_FAIL0:
-               {       
-                       if( value != 0 && value != 1)
-                       {
-                               Log(LOGERR, "Sensor digital_fail0 is not 0 or 1\n");
-                       }
-                       break;
-               }
-               default:
-               {
-               //So it doesn't complain about the missing cases - in practice we will need all sensors to be checked as above, no need to include a default as we should only pass valid sensor_id's; unless for some reason we have a sensor we don't need to check (but then why would you pass to this function in the first place :P)
-               }
 -              g_sensors[i].id = i;
 -              Data_Init(&(g_sensors[i].data_file));
 -              g_sensors[i].record_data = false;
--      }
--}
--
--/**
-  * Read a data value from a sensor; block until value is read
-  * @param sensor_id - The ID of the sensor
-  * @param d - DataPoint to set
-  * @returns NULL for digital sensors when data is unchanged, otherwise d
 - * Start a Sensor recording DataPoints
 - * @param s - The Sensor to start
 - * @param experiment_name - Prepended to DataFile filename
-- */
- DataPoint * GetData(SensorId sensor_id, DataPoint * d)
 -void Sensor_Start(Sensor * s, const char * experiment_name)
--{
-       // switch based on the sensor_id at the moment for testing;
-       // might be able to just directly access ADC from sensor_id?
-       //TODO: Implement for real sensors
 -      // Set filename
 -      char filename[BUFSIZ];
 -      if (sprintf(filename, "%s_%d", experiment_name, s->id) >= BUFSIZ)
 -      {
 -              Fatal("Experiment name \"%s\" too long (>%d)", experiment_name, BUFSIZ);
 -      }
--
-       
-       //TODO: We should ensure the time is *never* allowed to change on the server if we use gettimeofday
-       //              Another way people might think of getting the time is to count CPU cycles with clock()
-       //              But this will not work because a) CPU clock speed may change on some devices (RPi?) and b) It counts cycles used by all threads
 -      Log(LOGDEBUG, "Sensor %d with DataFile \"%s\"", s->id, filename);
 -      // Open DataFile
 -      Data_Open(&(s->data_file), filename);
 -
 -      s->record_data = true; // Don't forget this!
 -
 -      // Create the thread
 -      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)
 -{
 -      // 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;
 -      }
 -}
 -
 -/**
 - * Stop all Sensors
 - */
 -void Sensor_StopAll()
 -{
 -      for (int i = 0; i < NUMSENSORS; ++i)
 -              Sensor_Stop(g_sensors+i);
 -}
 -
 -/**
 - * Start all Sensors
 - */
 -void Sensor_StartAll(const char * experiment_name)
 -{
 -      for (int i = 0; i < NUMSENSORS; ++i)
 -              Sensor_Start(g_sensors+i, experiment_name);
 -}
 -
 -/**
 - * Read a DataPoint from a Sensor; block until value is read
 - * @param id - The ID of the sensor
 - * @param d - DataPoint to set
 - * @returns True if the DataPoint was different from the most recently recorded.
 - */
 -bool Sensor_Read(Sensor * s, DataPoint * d)
 -{
--      
 -      // Set time stamp
--      struct timeval t;
--      gettimeofday(&t, NULL);
-       d->time_stamp = (t.tv_sec - g_options.start_time.tv_sec) + 1e-6*(t.tv_usec - g_options.start_time.tv_usec);
 -      d->time_stamp = TIMEVAL_DIFF(t, g_options.start_time);
--
-       // Make time relative
-       //d->time_stamp.tv_sec -= g_options.start_time.tv_sec;
-       //d->time_stamp.tv_usec -= g_options.start_time.tv_usec;
-       
-       switch (sensor_id)
 -      // Read value based on Sensor Id
 -      switch (s->id)
--      {
--              case ANALOG_TEST0:
 -                      d->value = (double)(rand() % 100) / 100;
 -                      break;
 -
 -              case ANALOG_TEST1:
--              {
--                      static int count = 0;
--                      d->value = count++;
--                      break;
--              }
-               case ANALOG_TEST1:
-                       d->value = (double)(rand() % 100) / 100;
-                       break;
-               case ANALOG_FAIL0:
-                       d->value = (double)(rand() % 6) * -( rand() % 2) / ( rand() % 100 + 1);
-                       //Gives a value between -5 and 5
-                       CheckSensor(sensor_id, d->value);
-                       break;
-               //TODO: For digital sensors, consider only updating when sensor is actually changed
--              case DIGITAL_TEST0:
--                      d->value = t.tv_sec % 2;
--                      break;
--              case DIGITAL_TEST1:
--                      d->value = (t.tv_sec+1)%2;
-                       break;
-               case DIGITAL_FAIL0:
-                       if( rand() % 100 > 98)
-                               d->value = 2;
-                       d->value = rand() % 2; 
-                       //Gives 0 or 1 or a 2 every 1/100 times
-                       CheckSensor(sensor_id, d->value);
--                      break;
--              default:
-                       Fatal("Unknown sensor id: %d", sensor_id);
 -                      Fatal("Unknown sensor id: %d", s->id);
--                      break;
--      }       
--      usleep(100000); // simulate delay in sensor polling
-       return d;
- }
- /**
-  * Destroy a sensor
-  * @param s - Sensor to destroy
-  */
- void Destroy(Sensor * s)
- {
-       // Maybe move the binary file into long term file storage?
-       fclose(s->file);
- }
--
- /**
-  * Initialise a sensor
-  * @param s - Sensor to initialise
-  */
- void Init(Sensor * s, int id)
- {
-       s->write_index = 0;
-       s->id = id;
-       s->points_written = 0;
-       s->points_read = 0;
 -      // Perform sanity check based on Sensor's ID and the DataPoint
 -      Sensor_CheckData(s->id, d);
--
-       #define FILENAMESIZE 3
-       char filename[FILENAMESIZE];
-       if (s->id >= pow(10, FILENAMESIZE))
 -      // Update latest DataPoint if necessary
 -      bool result = (d->value != s->newest_data.value);
 -      if (result)
--      {
-               Fatal("Too many sensors! FILENAMESIZE is %d; increase it and recompile.", FILENAMESIZE);
 -              s->newest_data.time_stamp = d->time_stamp;
 -              s->newest_data.value = d->value;
--      }
-       pthread_mutex_init(&(s->mutex), NULL);
-               
-       sprintf(filename, "%d", s->id);
-       unlink(filename); //TODO: Move old files somewhere
-       s->file = fopen(filename, "a+b"); // open binary file
-       Log(LOGDEBUG, "Initialised sensor %d; binary file is \"%s\"", id, filename);
 -      return result;
--}
--
--/**
-  * Run the main sensor polling loop
-  * @param arg - Cast to Sensor* - Sensor that the thread will handle
-  * @returns NULL (void* required to use the function with pthreads)
 - * Checks the sensor data for unsafe or unexpected results 
 - * @param sensor_id - The ID of the sensor
 - * @param d - DataPoint to check
-- */
- void * Sensor_Main(void * arg)
 -void Sensor_CheckData(SensorId id, DataPoint * d)
--{
-       Sensor * s = (Sensor*)(arg);
-       while (Thread_Runstate() == RUNNING) //TODO: Exit condition
 -      //TODO: Implement
 -      /*
 -      switch (sensor_id)
--      {
-               // The sensor will write data to a buffer until it is full
-               // Then it will open a file and dump the buffer to the end of it.
-               // Rinse and repeat
-               // The reason I've added the buffer is because locks are expensive
-               // But maybe it's better to just write data straight to the file
-               // I'd like to do some tests by changing SENSOR_DATABUFSIZ
-               while (s->write_index < SENSOR_DATABUFSIZ)
 -              case ANALOG_TEST0:
--              {
-                       DataPoint * d = &(s->buffer[s->write_index]);
-                       if (GetData(s->id, d) == NULL)
 -                      if( *sensor value* > ANALOG_TEST0_SAFETY)
--                      {
-                               Fatal("Error collecting data");
 -                              LogEx(LOGERR, GetData, Sensor analog_test0 is above the safe value);
 -                      //new log function that stops actuators?
--                      }
-                       s->write_index += 1;
-               }
-               //Log(LOGDEBUG, "Filled buffer");
-               // CRITICAL SECTION (no threads should be able to read/write the file at the same time)
-               pthread_mutex_lock(&(s->mutex));
-                       //TODO: Valgrind complains about this fseek: "Syscall param write(buf) points to uninitialised byte(s)"
-                       //              Not sure why, but we should find out and fix it.
-                       fseek(s->file, 0, SEEK_END);
-                       int amount_written = fwrite(s->buffer, sizeof(DataPoint), SENSOR_DATABUFSIZ, s->file);
-                       if (amount_written != SENSOR_DATABUFSIZ)
 -                      //Also include a warning level?
 -                      else if( *sensor value* > ANALOG_TEST0_WARN)
--                      {
-                               Fatal("Wrote %d data points and expected to write %d to \"%s\" - %s", amount_written, SENSOR_DATABUFSIZ, strerror(errno));
 -                              LogEx(LOGWARN, GetData, Sensor analog_test0);   
--                      }
-                       s->points_written += amount_written;
-                       //Log(LOGDEBUG, "Wrote %d data points for sensor %d", amount_written, s->id);
-               pthread_mutex_unlock(&(s->mutex));
-               // End of critical section
-               s->write_index = 0; // reset position in buffer
-               
-       }
-       Log(LOGDEBUG, "Thread for sensor %d exits", s->id);
-       return NULL; 
- }
- /**
-  * Get position in a binary sensor file with a timestamp using a binary search
-  * @param s - Sensor to use
-  * @param time_stamp - Timestamp
-  * @param count - If not NULL, used to provide number of searches required
-  * @param found - If not NULL, set to the closest DataPoint
-  * @returns Integer giving the *closest* index in the file
-  * TODO: Refactor or replace?
-  */
- int FindTime(Sensor * s, double time_stamp, int * count, DataPoint * found)
- {
-       DataPoint d;
-       int lower = 0;
-       int upper = s->points_written - 1;
-       int index = 0;
-       if (count != NULL)
-               *count = 0;     
-       while (upper - lower > 1)
-       {
-               index = lower + ((upper - lower)/2);
-               // Basically anything with fseek is critical; if we don't make it critical the sensor thread may alter data at a random point in the file!
-               // CRITICAL SECTION (May need to rethink how this is done, but I can't see how to do it without fseek :S)
-               // Regarding the suggestion that we have 2 file pointers; one for reading and one for writing:
-               // That seems like it will work... but we will have to be very careful and test it first
-               pthread_mutex_lock(&s->mutex);
-                       fseek(s->file, index*sizeof(DataPoint), SEEK_SET);
-                       int amount_read = fread(&d, sizeof(DataPoint), 1, s->file);
-               pthread_mutex_unlock(&s->mutex);
-               
-               if (amount_read != 1)
-               {
-                       Fatal("Couldn't read single data point from sensor %d", s->id);
-               }
-               if (d.time_stamp > time_stamp)
-               {
-                       upper = index;
-               }
-               else if (d.time_stamp < time_stamp)
-               {
-                       lower = index;
--              }
-               if (count != NULL)
-                       *count += 1;
--      }
-       if (found != NULL)
-               *found = d;
-       return index;
-       
 -      */
--}
 -              
--
--/**
-  * Print sensor data between two indexes in the file, using a given format
-  * @param s - Sensor to use
-  * @param start - Start index
-  * @param end - End index
-  * @param output_type - JSON, CSV or TSV output format
 - * Record data from a single Sensor; to be run in a seperate thread
 - * @param arg - Cast to Sensor* - Sensor that the thread will handle
 - * @returns NULL (void* required to use the function with pthreads)
-- */
- void PrintData(Sensor * s, int start, int end, OutputType output_type)
 -void * Sensor_Loop(void * arg)
--{
-       DataPoint buffer[SENSOR_QUERYBUFSIZ];
-       int index = start;
-       if (output_type == JSON)
-       {
-               FCGI_JSONValue("[");
-       }
 -      Sensor * s = (Sensor*)(arg);
 -      Log(LOGDEBUG, "Sensor %d starts", s->id);
--
-       while (index < end)
 -      // Until the sensor is stopped, record data points
 -      while (s->record_data)
--      {
-               int to_read = end - index;
-               if (to_read > SENSOR_QUERYBUFSIZ)
-               {
-                       to_read = SENSOR_QUERYBUFSIZ;
-               }
-               int amount_read = 0;
-               // CRITICAL SECTION
-               pthread_mutex_lock(&(s->mutex));
-                       fseek(s->file, index*sizeof(DataPoint), SEEK_SET);
-                       amount_read = fread(buffer, sizeof(DataPoint), to_read, s->file);
-               pthread_mutex_unlock(&(s->mutex));
-               // End critical section
-               if (amount_read != to_read)
-               {
-                       Fatal("Failed to read %d DataPoints from sensor %d; read %d instead", to_read, s->id, amount_read);
-               }
-               // Print the data
-               for (int i = 0; i < amount_read; ++i)
 -              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:
--              {
-                       //TODO: Reformat?
-                       switch (output_type)
-                       {
-                               case JSON:
-                                       FCGI_JSONValue("[%f, %f]", buffer[i].time_stamp, buffer[i].value);
-                                       if (i+1 < amount_read)
-                                               FCGI_JSONValue(",");
-                                       break;
-                               case CSV:
-                                       FCGI_PrintRaw("%f,%f\n", buffer[i].time_stamp, buffer[i].value);
-                                       break;
-                               case TSV:
-                               default:
-                                       FCGI_PrintRaw("%f\t%f\n", buffer[i].time_stamp, buffer[i].value);
-                                       break;
-                       }
 -                      //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 += amount_read;
-       }
-       if (output_type == JSON)
-       {
-               FCGI_JSONValue("]");
--      }
- }
 -      
 -      // Needed to keep pthreads happy
--
- /**
-  * Fill buffer with most recent sensor data
-  * TODO: This may be obselete; remove?
-  * @param s - Sensor to use
-  * @param buffer - Buffer to fill
-  * @param bufsiz - Size of buffer to fill
-  * @returns The number of DataPoints actually read
-  */
- int Sensor_Query(Sensor * s, DataPoint * buffer, int bufsiz)
- {
-       int amount_read = 0;
-       //CRITICAL SECTION (Don't access file while sensor thread is writing to it!)
-       pthread_mutex_lock(&(s->mutex));
-               
-               fseek(s->file, -bufsiz*sizeof(DataPoint), SEEK_END);
-               amount_read = fread(buffer, sizeof(DataPoint), bufsiz, s->file);
-               //Log(LOGDEBUG, "Read %d data points", amount_read);            
-       pthread_mutex_unlock(&(s->mutex));
-       return amount_read;
 -      Log(LOGDEBUG, "Sensor %d finished", s->id);
 -      return NULL;
--}
--
--/**
-- * Get a Sensor given an ID string
-- * @param id_str ID string
-- * @returns Sensor* identified by the string; NULL on error
-- */
--Sensor * Sensor_Identify(const char * id_str)
--{
--      char * end;
--      // Parse string as integer
--      int id = strtol(id_str, &end, 10);
--      if (*end != '\0')
--      {
--              return NULL;
--      }
--      // Bounds check
--      if (id < 0 || id >= NUMSENSORS)
--              return NULL;
--
--
--      Log(LOGDEBUG, "Sensor \"%s\" identified", g_sensor_names[id]);
--      return g_sensors+id;
 -}
 -
 -/**
 - * Helper: Begin sensor response in a given format
 - * @param context - the FCGIContext
 - * @param format - Format
 - * @param id - ID of sensor
 - */
 -void Sensor_BeginResponse(FCGIContext * context, SensorId id, DataFormat format)
 -{
 -      // Begin response
 -      switch (format)
 -      {
 -              case JSON:
 -                      FCGI_BeginJSON(context, STATUS_OK);
 -                      FCGI_JSONLong("id", id);
 -                      FCGI_JSONKey("data");
 -                      break;
 -              default:
 -                      FCGI_PrintRaw("Content-type: text/plain\r\n\r\n");
 -                      break;
 -      }
 -}
 -
 -/**
 - * Helper: End sensor response in a given format
 - * @param context - the FCGIContext
 - * @param id - ID of the sensor
 - * @param format - Format
 - */
 -void Sensor_EndResponse(FCGIContext * context, SensorId id, DataFormat format)
 -{
 -      // End response
 -      switch (format)
 -      {
 -              case JSON:
 -                      FCGI_EndJSON();
 -                      break;
 -              default:
 -                      break;
 -      }
--}
--
--/**
-- * Handle a request to the sensor module
-- * @param context - The context to work in
-- * @param params - Parameters passed
-  * TODO: Seriously need to write more helper functions and decrease the size of this function!
-- */
--void Sensor_Handler(FCGIContext *context, char * params)
--{
-       StatusCodes status = STATUS_OK;
-       OutputType output_type = JSON;
-       
-       const char * key; const char * value;
-       Sensor * sensor = NULL;
--      struct timeval now;
--      gettimeofday(&now, NULL);
-       double start_time = -1;
-       double end_time = -1;
-       double current_time = (now.tv_sec - g_options.start_time.tv_sec) + 1e-6*(now.tv_usec - g_options.start_time.tv_usec);
-       bool seek_time = false;
-       bool points_specified = false;
-       int query_size = SENSOR_QUERYBUFSIZ;
-       int start_index = -1;
-       int end_index = -1;
-       while ((params = FCGI_KeyPair(params, &key, &value)) != NULL)
-       {
-               Log(LOGDEBUG, "Got key=%s and value=%s", key, value);
-               if (strcmp(key, "id") == 0)
-               {
-                       if (sensor != NULL)
-                       {
-                               Log(LOGERR, "Only one sensor id should be specified");
-                               status = STATUS_ERROR;
-                               break;
-                       }
-                       if (*value == '\0')
-                       {
-                               Log(LOGERR, "No id specified.");
-                               status = STATUS_ERROR;
-                               break;
-                       }
-                       sensor = Sensor_Identify(value);
-                       if (sensor == NULL)
-                       {
-                               Log(LOGERR, "Invalid sensor id: %s", value);
-                               status = STATUS_ERROR;
-                               break;
-                       }
-               }
-               else if (strcmp(key, "format") == 0)
-               {
-                       if (strcmp(value, "json") == 0)
-                               output_type = JSON;
-                       else if (strcmp(value, "csv") == 0)
-                               output_type = CSV;
-                       else if (strcmp(value, "tsv") == 0)
-                               output_type = TSV;                      
-               }
-               else if (strcmp(key, "points") == 0)
-               {
-                       points_specified = true;
-                       if (strcmp(value, "all") == 0)
-                       {
-                               query_size = sensor->points_written;
-                       }
-                       else
-                       {
-                               char * end;
-                               query_size = strtol(value, &end, 10);
-                               if (*end != '\0')
-                               {
-                                       Log(LOGERR, "Require \"all\" or an integer value: %s = %s", key, value);
-                                       status = STATUS_ERROR;
-                                       break;
-                               }
-                       }
-                       
-               }
-               else if (strcmp(key, "start_time") == 0)
-               {
-                       seek_time = true;
-                       char * end;
-                       start_time = strtod(value, &end);
-                       if (*end != '\0')
-                       {
-                               Log(LOGERR, "Require a double: %s = %s", key, value);
-                               status = STATUS_ERROR;
-                               break;
-                       }                       
-                       // Treat negative values as being relative to the current time
-                       if (start_time < 0)
-                       {
-                               start_time = current_time + start_time;
-                       }
-                       start_time = floor(start_time);
-               }
-               else if (strcmp(key, "end_time") == 0)
-               {
-                       seek_time = true;
-                       char * end;
-                       end_time = strtod(value, &end);
-                       if (*end != '\0')
-                       {
-                               Log(LOGERR, "Require a double: %s = %s", key, value);
-                               status = STATUS_ERROR;
-                               break;
-                       }       
 -      double current_time = TIMEVAL_DIFF(now, g_options.start_time);
--
-                       // Treat negative values as being relative to the current time
-                       if (end_time < 0)
-                       {
-                               end_time = current_time + end_time;
-                       }               
-                       end_time = ceil(end_time);
-               }
-               // For backward compatability:
-               else if (strcmp(key, "dump") == 0)
-               {
-                       output_type = TSV;
-                       query_size = sensor->points_written+1;
-               }
-               else
-               {
-                       Log(LOGERR, "Unknown key \"%s\" (value = %s)", key, value);
-                       status = STATUS_ERROR;
-                       break;
-               }               
-       }
 -      int id = 0;
 -      double start_time = 0;
 -      double end_time = current_time;
 -      char * fmt_str;
--
-       if (status != STATUS_ERROR && sensor == NULL)
-       {
-               Log(LOGERR, "No valid sensor id given");
-               status = STATUS_ERROR;
-       }
 -      // key/value pairs
 -      FCGIValue values[] = {
 -              {"id", &id, FCGI_REQUIRED(FCGI_LONG_T)}, 
 -              {"format", &fmt_str, FCGI_STRING_T}, 
 -              {"start_time", &start_time, FCGI_DOUBLE_T}, 
 -              {"end_time", &end_time, FCGI_DOUBLE_T},
 -      };
--
-       if (status == STATUS_ERROR)
 -      // enum to avoid the use of magic numbers
 -      typedef enum {
 -              ID,
 -              FORMAT,
 -              START_TIME,
 -              END_TIME,
 -      } SensorParams;
 -      
 -      // Fill values appropriately
 -      if (!FCGI_ParseRequest(context, params, values, sizeof(values)/sizeof(FCGIValue)))
--      {
-               FCGI_RejectJSON(context, "Invalid input parameters");
 -              // Error occured; FCGI_RejectJSON already called
--              return;
--      }
--
 -      // Get Sensor
 -      Sensor * s = NULL;
--
-       if (seek_time)
 -      // Error checking on sensor id
 -      if (id < 0 || id >= NUMSENSORS)
--      {
-               if (end_time < 0 && !points_specified)
-                       end_index = sensor->points_written;
-               else
-               {
-                       int count = 0; DataPoint d;
-                       end_index = FindTime(sensor, end_time, &count, &d);
-                       Log(LOGDEBUG, "FindTime - Looked for %f; found [%f,%f] after %d iterations; sensor %d, position %d", end_time, d.time_stamp, d.value, count, sensor->id, end_index);
-               }
-               if (start_time < 0)
-                       start_time = 0;
-               else
-               {
-                       int count = 0; DataPoint d;
-                       start_index = FindTime(sensor, start_time, &count, &d);
-                       Log(LOGDEBUG, "FindTime - Looked for %f; found [%f,%f] after %d iterations; sensor %d, position %d", start_time, d.time_stamp, d.value, count, sensor->id, start_index);
-               }
-               if (points_specified)
-                       end_index = start_index + query_size;
 -              Log(LOGERR, "Invalid id %d", id);
--      }
--      else
--      {
-               start_index = sensor->points_written - query_size;
-               
-               end_index = sensor->points_written;
 -              s = g_sensors+id;
--      }
--      
-       if (start_index < 0)
-       {
-               Log(LOGNOTE, "start_index = %d => Clamped to 0", start_index);
-               start_index = 0;
-       }
-       if (end_index > sensor->points_written)
 -      DataFormat format = JSON;
 -
 -      // Check if format type was specified
 -      if (FCGI_RECEIVED(values[FORMAT].flags))
--      {
-               Log(LOGNOTE, "end_index = %d => Clamped to %d", end_index, sensor->points_written);
-               end_index = sensor->points_written;
 -              if (strcmp(fmt_str, "json") == 0)
 -                      format = JSON;
 -              else if (strcmp(fmt_str, "tsv") == 0)
 -                      format = TSV;
 -              else
 -                      Log(LOGERR, "Unknown format type \"%s\"", fmt_str);
--      }
 -
--      
-       switch (output_type)
-       {
-               case JSON:
-                       FCGI_BeginJSON(context, status);
-                       FCGI_JSONLong("id", sensor->id);
-                       FCGI_JSONKey("data");
-                       PrintData(sensor, start_index, end_index, output_type);
-                       FCGI_EndJSON();
-                       break;
-               default:
-                       FCGI_PrintRaw("Content-type: text/plain\r\n\r\n");
-                       PrintData(sensor, start_index, end_index, output_type);
-                       //Force download with content-disposition
-                       // Sam: This is cool, but I don't think we should do it
-                       //  - letting the user view it in the browser and then save with their own filename is more flexible
-                       //"Content-disposition: attachment;filename=%d.csv\r\n\r\n", sensor->id);
-                       break;
-       }
--      
- }
- /**
-  * Setup Sensors, start Sensor polling thread(s)
-  */
- void Sensor_Spawn()
- {
-       // start sensor threads
-       for (int i = 0; i < NUMSENSORS; ++i)
 -      // Begin response
 -      Sensor_BeginResponse(context, id, format);
 -      
 -      // If a time was specified
 -      if ((s != NULL) && (FCGI_RECEIVED(values[START_TIME].flags) || FCGI_RECEIVED(values[END_TIME].flags)))
--      {
-               Init(g_sensors+i, i);
-               pthread_create(&(g_sensors[i].thread), NULL, Sensor_Main, (void*)(g_sensors+i));
-       }
- }
 -              // Wrap times relative to the current time
 -              if (start_time < 0)
 -                      start_time += current_time;
 -              if (end_time < 0)
 -                      end_time += current_time;
--
- /**
-  * Quit Sensor loops
-  */
- void Sensor_Join()
- {
-       if (!Thread_Runstate())
-       {
-               Fatal("This function should not be called before Thread_QuitProgram");
 -              // Print points by time range
 -              Data_PrintByTimes(&(s->data_file), start_time, end_time, format);
 -
--      }
-       for (int i = 0; i < NUMSENSORS; ++i)
 -      else if (s != NULL) // No time was specified; just return a recent set of points
--      {
-               pthread_join(g_sensors[i].thread, NULL);
-               Destroy(g_sensors+i);
 -              pthread_mutex_lock(&(s->data_file.mutex));
 -                      int start_index = s->data_file.num_points-DATA_BUFSIZ;
 -                      int end_index = s->data_file.num_points-1;
 -              pthread_mutex_unlock(&(s->data_file.mutex));
 -
 -              // Bounds check
 -              if (start_index < 0)
 -                      start_index = 0;
 -              if (end_index < 0)
 -                      end_index = 0;
 -
 -              // Print points by indexes
 -              Log(LOGDEBUG, "Sensor %d file \"%s\" indexes %d->%d", s->id, s->data_file.filename, start_index, end_index);
 -              Data_PrintByIndexes(&(s->data_file), start_index, end_index, format);
--      }
 -      
 -      // Finish response
 -      Sensor_EndResponse(context, id, format);
 -      
--}
 -
 -
diff --cc server/sensor.h
index f834f7a,55b7d89..0000000
deleted file mode 100644,100644
+++ /dev/null
@@@ -1,86 -1,71 +1,0 @@@
--/**
-- * @file sensor.h
-- * @brief Declarations for sensor thread related stuff
-- */
--
--#ifndef _SENSOR_H
--#define _SENSOR_H
--
- /** Number of data points to keep in sensor buffers **/
- #define SENSOR_DATABUFSIZ 10
- /** Size of the query buffer. @see Sensor_Handler **/
- #define SENSOR_QUERYBUFSIZ 10
 -#include "data.h"
--
--/** Number of sensors **/
- #define NUMSENSORS 6
 -#define NUMSENSORS 4
--
--/** Safety Values for sensors **/
- #define ANALOG_FAIL0_WARN 4
- #define ANALOG_FAIL0_SAFETY 5
- #define ANALOG_FAIL0_MIN_WARN -4
- #define ANALOG_FAIL0_MIN_SAFETY -5
 -//TODO: Probably better to use an array instead
 -#define ANALOG_TEST0_SAFETY 1000
 -#define ANALOG_TEST1_SAFETY 1000
 -#define DIGITAL_TEST0_SAFETY 1
 -#define DIGITAL_TEST1_SAFETY 1
--
- typedef enum SensorId {
 -
 -typedef enum SensorId 
 -{
--      ANALOG_TEST0,
--      ANALOG_TEST1,
-       ANALOG_FAIL0,
--      DIGITAL_TEST0,
-       DIGITAL_TEST1,
-       DIGITAL_FAIL0
 -      DIGITAL_TEST1
--} SensorId;
--
- typedef enum
- {
-       JSON, // JSON data
-       CSV, // Comma seperated vector
-       TSV // Tab seperated vector
- } OutputType;
 -
--
--/** Human readable names for the sensors **/
--extern const char * g_sensor_names[NUMSENSORS];
--
- /** Structure to represent data recorded by a sensor at an instant in time **/
- typedef struct
- {
-       /** Time at which data was taken **/
-       double time_stamp; 
-       /** Value of data **/
-       double value;
- } DataPoint;
--
--/** Structure to represent a sensor **/
--typedef struct
--{
--      /** ID number of the sensor **/
--      SensorId id;
-       /** Buffer to store data from the sensor **/
-       DataPoint buffer[SENSOR_DATABUFSIZ];
-       /** Index of last point written in the data buffer **/
-       int write_index;
-       /** Number of points read **/
-       long points_read;
-       /** Number of points written to file **/
-       long points_written;
-       /** Binary file to write data into when buffer is full **/
-       FILE * file;
-       /** Thread running the sensor **/
 -      /** DataFile to store sensor values in **/
 -      DataFile data_file;
 -      /** Indicates whether the Sensor should record data **/
 -      bool record_data;
 -      /** Thread the Sensor is running in **/
--      pthread_t thread;
-       /** Mutex to protect access to stuff **/
-       pthread_mutex_t mutex;
 -      /** Most recently recorded data **/
 -      DataPoint newest_data;
--
-       
--} Sensor;
--
--
 -extern void Sensor_Init(); // One off initialisation of *all* sensors
--
 -extern void Sensor_StartAll(const char * experiment_name); // Start all Sensors recording data
 -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_Spawn(); // Initialise sensor
- extern void Sensor_Join(); //Join sensor threads
- extern void * Sensor_Main(void * args); // main loop for sensor thread; pass a Sensor* cast to void*
--
- extern int Sensor_Query(Sensor * s, DataPoint * buffer, int bufsiz); // fill buffer with sensor data
 -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
 -extern void Sensor_CheckData(SensorId id, DataPoint * d); // Check a DataPoint
 -extern Sensor * Sensor_Identify(const char * str); // Identify a Sensor from a string Id
--
- extern void Sensor_Handler(FCGIContext *context, char * params);
 -extern void Sensor_Handler(FCGIContext *context, char * params); // Handle a FCGI request for Sensor data
 -
 -
--
--#endif //_SENSOR_H
--

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