+/**
+ * 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
+ */
+void PrintData(Sensor * s, int start, int end, OutputType output_type)
+{
+ DataPoint buffer[SENSOR_QUERYBUFSIZ];
+ int index = start;
+
+ if (output_type == JSON)
+ {
+ FCGI_JSONValue("[");
+ }
+
+
+ while (index < end)
+ {
+ 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)
+ {
+ //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;
+ }
+ }
+ index += amount_read;
+ }
+
+ if (output_type == JSON)
+ {
+ FCGI_JSONValue("]");
+ }
+}
+