clean :
make -C sensors clean
+ make -C actuators clean
$(RM) $(BIN) $(BIN2)
$(RM) *.o
/**
* Add and initialise an Actuator
* @param name - Human readable name of the actuator
- * @param read - Function to call whenever the actuator should be read
+ * @param user_id - Caller specified ID to be associated with this actuator
+ * @param set - Function to call whenever the actuator should be set
* @param init - Function to call to initialise the actuator (may be NULL)
+ * @param cleanup - Function to call to deinitialise the actuator (may be NULL)
+ * @param sanity - Function to call to check that a user specified value is sane (may be NULL)
+ * @param initial_value - The initial value to set the actuator to
* @returns Number of actuators added so far
*/
int Actuator_Add(const char * name, int user_id, SetFn set, InitFn init, CleanFn cleanup, SanityFn sanity, double initial_value)
* Set an Actuator value
* @param a - The Actuator
* @param value - The value to set
+ * @param record - Whether or not to record the value to the Actuator's DataFile.
*/
void Actuator_SetValue(Actuator * a, double value, bool record)
{
/**
* Helper: Begin Actuator response in a given format
* @param context - the FCGIContext
+ * @param a - the actuator to begin a response for
* @param format - Format
- * @param id - ID of Actuator
*/
void Actuator_BeginResponse(FCGIContext * context, Actuator * a, DataFormat format)
{
/**
* Helper: End Actuator response in a given format
* @param context - the FCGIContext
- * @param id - ID of the Actuator
+ * @param a - the actuator to end a response for
* @param format - Format
*/
void Actuator_EndResponse(FCGIContext * context, Actuator * a, DataFormat format)
return NULL;
}
+/**
+ * Returns the last DataPoint that is currently available.
+ * @param id - The actuator ID for which to retrieve data from
+ * @return The last DataPoint
+ */
DataPoint Actuator_LastData(int id)
{
Actuator * a = &(g_actuators[id]);
/**
* Set a GPIO pin
* @param pin - The pin to set. MUST have been exported before calling this function.
+ * @param value - The value to set the GPIO pin to.
*/
bool GPIO_Set(int pin, bool value)
{
extern bool PWM_Stop(int pin);
#else
+//! @cond Doxygen_Suppress
//Horrible hacks to silence gcc when compiling on systems that are not the BBB
extern bool True_Stub(int arg, ...);
extern bool ADC_Read_Stub(int *val, ...);
#define PWM_Set(pin, polarity, period, duty) True_Stub((int)pin, polarity, period, duty)
#define PWM_Stop(pin) True_Stub((int)pin)
//yuck
-
+//! @endcond
#endif //_BBB
#endif //_BBB_PIN_H
#define BBB_PIN_COUNT 92
/** GPIO0 defines **/
-
#define GPIO0_1 1
#define GPIO0_2 2 // Used for PWM
#define GPIO0_3 3 // Used for PWM
#define ADC5 5
#define ADC6 6
#define ADC7 7
+/** The maximum voltage input to the ADC **/
#define ADC_VOLTAGE_MAX 1800
+/** The maximum raw value from the ADC **/
#define ADC_RAW_MAX (2 << ADC_BITS)
+/** Converts the raw ADC value to a voltage in millivolts **/
#define ADC_TO_MVOLTS(x) ((double)((x)/2 << ADC_BITS) * (double)ADC_VOLTAGE_MAX)
/** Number of ADC pins **/
#define ADC_NUM_PINS 8
-
+/** The path to the ADCs on the BBB **/
#define ADC_DEVICE_PATH "/sys/bus/iio/devices/iio:device0/"
/** PWM names to sysfs numbers **/
(tv)->tv_nsec = ((value) - (int)(value))*1e9; \
}
-extern bool PathExists(const char * path);
+//extern bool PathExists(const char * path);
extern bool DirExists(const char * path);
#include <sys/types.h>
#include <sys/stat.h>
+/**
+ * Control state information (start/stop/pause etc)
+ */
typedef struct ControlData {
- ControlModes current_mode;
- pthread_mutex_t mutex;
- 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];
+ ControlModes current_mode; /** Current experiment mode **/
+ pthread_mutex_t mutex; /** Mutex to serialise access to control methods **/
+ struct timespec start_time; /** Start time of current experiment **/
+ char user_name[31]; /** The user who owns the currently running experiment **/
+ char experiment_dir[BUFSIZ]; /** Directory for experiment **/
+ char experiment_name[BUFSIZ]; /** Name of the current experiment **/
} ControlData;
ControlData g_controls = {CONTROL_STOP, PTHREAD_MUTEX_INITIALIZER, {0}};
+/**
+ * Determines if a directory exists or not.
+ * @param path The path to check
+ * @return true iff the path exists
+ */
bool DirExists(const char *path)
{
DIR *dir = opendir(path);
return false;
}
-bool PathExists(const char *path)
-{
- FILE *fp = fopen(path, "r");
- if (fp) {
- fclose(fp);
- return true;
- }
- return false;
-}
-
/**
* Lists all experiments for the current user.
- * @param The context to work in
+ * @param context The context to work in
*/
void ListExperiments(FCGIContext *context)
{
/**
* 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() {
#ifndef _CONTROL_H
#define _CONTROL_H
+/**
+ * The possible experiment control modes that the server can be in.
+ * At present, CONTROL_EMERGENCY largely does nothing. TODO: Fix this
+ */
typedef enum ControlModes {
CONTROL_START,
CONTROL_PAUSE,
#define INVALID_CHARACTERS "\"*/:<>?\\|. "
/** The same as INVALID_CHARACTERS, except escaped for use in JSON strings **/
#define INVALID_CHARACTERS_JSON "\\\"*/:<>?\\\\|. "
-
+/** The username of a user with no authentication (DEBUG ONLY) **/
#define NOAUTH_USERNAME "_anonymous_noauth"
extern void Control_Handler(FCGIContext *context, char *params);
extern const char* Control_SetMode(ControlModes desired_mode, void * arg);
-extern ControlModes Control_GetMode();
+//extern ControlModes Control_GetMode();
extern const char * Control_GetModeName();
//extern bool Control_Lock();
//extern void Control_Unlock();
* @param df - DataFile to access
* @param start - Info about start_time param
* @param end - Info about end_time param
- * @param fmt - Info about format param
+ * @param format - Info about format param
* @param current_time - Current time
*/
void Data_Handler(DataFile * df, FCGIValue * start, FCGIValue * end, DataFormat format, double current_time)
#ifndef _DATAPOINT_H
#define _DATAPOINT_H
-#define DATA_BUFSIZ 10 // Size to use for DataPoint buffers (TODO: Optimise)
+#define DATA_BUFSIZ 10 /** Size to use for DataPoint buffers (TODO: Optimise) **/
#include "common.h"
/** Enum of output format types for DataPoints **/
typedef enum
{
- JSON, // JSON data
- TSV // Tab seperated vector
+ JSON, /** JSON data */
+ TSV /** Tab seperated vector */
} DataFormat;
/**
*/
typedef struct
{
- FILE * file; // file pointer
- int num_points; // Number of DataPoints in the file
- char * filename; // Name of the file
- pthread_mutex_t mutex; // Mutex around num_points
+ FILE * file; /** file pointer */
+ int num_points; /** Number of DataPoints in the file */
+ char * filename; /** Name of the file */
+ pthread_mutex_t mutex; /** Mutex around num_points */
} DataFile;
extern void Data_Handler(DataFile * df, FCGIValue * start, FCGIValue * end, DataFormat format, double current_time); // Helper; given FCGI params print data
extern DataFormat Data_GetFormat(FCGIValue * fmt); // Helper; convert human readable format string to DataFormat
-
-extern double Data_Callibrate(double value, double map[], int map_size);
-
#endif //_DATAPOINT_H
+++ /dev/null
-/**
- * @file dilatometer.c
- * @purpose Implementation of dilatometer related functions
- */
-
-#include "cv.h"
-#include "highgui_c.h"
-#include "dilatometer.h"
-#include <math.h>
-
-// test positions
-static double test_left, test_right;
-
-// Canny Edge algorithm variables
-int blur = 5;
-int lowThreshold = 30;
-int ratio = 3;
-int kernel_size = 3;
-
-/** Buffers for storing image data. **/
-static CvMat * g_srcRGB = NULL; // Source Image
-static CvMat * g_srcGray = NULL; // Gray scale of source image
-static CvMat * g_edges = NULL; // Detected Edges
-
-/** Pointers for capturing image **/
-static CvCapture * g_capture = NULL;
-static IplImage * frame = NULL; // This is required as you can not use capture with CvMat in C
-
-
-/**
- * Create a test image using left as left edge and right as right edge positions
- */
-void Dilatometer_TestImage()
-{
-
- g_srcRGB = cvCreateMat(480, 640, CV_8UC3);
-
- for( int x = 0; x < 640; ++x)
- {
- for (int y = 0; y < 480; ++y)
- {
- CvScalar s;
- for( int i = 0; i < 3; ++i)
- {
- s.val[i] = 210 + (rand() % 1000) * 1e-0 - (rand() % 1000) * 1e-0;
- // Produce an exponential decay around left edge
- if( x < test_left)
- s.val[i] *= exp( (x - test_left) / 25);
- else if( x < 320)
- s.val[i] *= exp( (test_left - x) / 25);
- // Produce an exponential decay around right edge
- else if( x < test_right)
- s.val[i] *= exp( (x - test_right) / 25);
- else
- s.val[i] *= exp( (test_right - x) / 25);
- }
- cvSet2D(g_srcRGB,y,x,s);
- }
-
- }
- if (g_srcGray == NULL)
- {
- g_srcGray = cvCreateMat(g_srcRGB->rows,g_srcRGB->cols,CV_8UC1);
- }
- cvCvtColor(g_srcRGB,g_srcGray,CV_RGB2GRAY);
-}
-
-/**
- * Cleanup Dilatometer pointers
- */
-void Dilatometer_Cleanup()
-{
- if (g_capture != NULL)
- cvReleaseCapture(&g_capture);
- if (frame != NULL)
- cvReleaseImageHeader(&frame);
- //if (g_srcRGB != NULL)
- // cvReleaseMat(&g_srcRGB); // Causing run time error in cvReleaseMat
- if (g_srcGray != NULL)
- cvReleaseMat(&g_srcGray);
- if (g_edges != NULL)
- cvReleaseMat(&g_edges);
-}
-
-/**
- * Get an image from the Dilatometer
- */
-static bool Dilatometer_GetImage()
-{
- bool result = true;
- // If more than one camera is connected, then input needs to be determined, however the camera ID may change after being unplugged
- if( g_capture == NULL)
- {
- g_capture = cvCreateCameraCapture(0);
- //If cvCreateCameraCapture returns NULL there is an error with the camera
- if( g_capture == NULL)
- {
- result = false;
- return;
- }
- }
-
- // Get the frame and convert it to CvMat
- frame = cvQueryFrame(g_capture);
- CvMat stub;
- g_srcRGB = cvGetMat(frame,&stub,0,0);
-
- if( g_srcRGB == NULL)
- result = false;
-
- // Convert the image to grayscale
- if (g_srcGray == NULL)
- {
- g_srcGray = cvCreateMat(g_srcRGB->rows,g_srcRGB->cols,CV_8UC1);
- }
-
- cvCvtColor(g_srcRGB,g_srcGray,CV_RGB2GRAY);
-
- return result;
-}
-
-void CannyThreshold()
-{
- if ( g_edges == NULL)
- {
- g_edges = cvCreateMat(g_srcGray->rows,g_srcGray->cols,CV_8UC1);
- }
-
- // Commented out lines are used during testing to show the image to screen, can also save the test images
- //cvShowImage("display", g_srcGray);
- //cvWaitKey(0);
-
- // Reduce noise with a kernel blurxblur. Input the grayscale source image, output to edges. (0's mean it's determined from kernel sizes)
- cvSmooth( g_srcGray, g_edges, CV_GAUSSIAN, blur, blur ,0 ,0 );
-
- //Save the image
- //cvSaveImage("test_blurred.jpg",g_edges,0);
-
- //cvShowImage("display", g_edges);
- //cvWaitKey(0);
-
- // Find the edges in the image
- cvCanny( g_edges, g_edges, lowThreshold, lowThreshold*ratio, kernel_size );
-
- //Save the image
- //cvSaveImage("test_edge.jpg",g_edges,0);
-
- //cvShowImage("display", g_edges);
- //cvWaitKey(0);
-
-}
-
- /**
- * Read the dilatometer image. The value changed will correspond to the new location of the edge.
- * @param val - Will store the read value if successful
- * @param samples - Number of rows to scan (increasing will slow down performance!)
- * @returns true on successful read
- */
-bool Dilatometer_GetEdge( double * value, int samples)
-{
- bool result = false;
- double average = 0;
- // Get the image from the camera
- result = Dilatometer_GetImage();
- // If an error occured when capturing image then return
- if (!result)
- return result;
-
- // Apply the Canny Edge theorem to the image
- CannyThreshold();
-
- int width = g_edges->cols;
- int height = g_edges->rows;
-
- // If the number of samples is greater than the image height, sample every row
- if( samples > height)
- {
- samples = height;
- }
-
- int sample_height;
- int num_edges = 0; // Number of edges. if each sample location has an edge, then num_edges = samples
-
- for (int i=0; i<samples; i++)
- {
- // Determine the position in the rows to find the edges.
- // This will give you a number of evenly spaced samples
- sample_height = ceil(height * (i + 1) / samples) -1;
-
- // Need to go through each pixel of a row and find all the locations of a line. If there is more than one pixel, average it. note this only works if the canny edge algorithm returns lines about the actual line (no outliers).
-
- int edge_location=0;
- int num=0;
- for ( int col = 0; col < width; col++)
- {
- // Count the number of points
- // Get the threshold of the pixel at the current location
- CvScalar value = cvGet2D(g_edges, sample_height, col);
- if( value.val[0]> THRES)
- {
- edge_location += col;
- num++;
- }
- }
- if( num > 0)
- {
- average += ( edge_location / num );
- num_edges++;
- }
- }
- if (num_edges > 0)
- average /= num_edges;
-
- if( average > 0)
- {
- result = true; //Successfully found an edge
- *value = average;
- }
- return result;
-}
-
- /**
- * Read the dilatometer image. The value changed will correspond to the new location of the edge.
- * @param val - Will store the read value if successful
- * @returns true on successful read
- */
-bool Dilatometer_Read( double * value)
-{
- bool result = Dilatometer_GetEdge(value, SAMPLES);
- return result;
-}
-
-/**
- * Initialise the dilatometer
- */
-void Dilatometer_Init()
-{
- // Make an initial reading (will allocate memory the first time only).
- double val;
- Dilatometer_GetEdge(&val, 1);
-}
-
-// Overlays a line over the given edge position
-void Draw_Edge(double edge)
-{
- CvScalar value;
- value.val[0]=244;
- for( int i = 0; i < g_srcGray->rows; i++)
- {
- cvSet2D(g_edges,i,edge,value);
- }
- cvShowImage("display", g_edges);
- cvWaitKey(0);
- //cvSaveImage("test_edge_avg.jpg",g_edges,0);
-}
-
-/* // Test algorithm
-static void Dilatometer_GetImageTest( )
-{
- //Generates Test image
- //Dilatometer_TestImage();
-
- //Load Test image
- g_srcGray = cvLoadImageM ("testimage4.jpg",CV_LOAD_IMAGE_GRAYSCALE );
-}*/
-
-/**
- * For testing purposes
- */
-int main(int argc, char ** argv)
-{
- //cvNamedWindow( "display", CV_WINDOW_AUTOSIZE );// Create a window for display.
- //gettimeofday(&start, NULL);
- test_left = 100;
- test_right = 500;
- Dilatometer_Init();
-
- cvNamedWindow( "display", CV_WINDOW_AUTOSIZE);
- //double width;
-
- double edge;
- Dilatometer_GetEdge(&edge,20000);
- //For testing purposes, overlay the given average line over the image
- //Draw_Edge(edge);
-
- cvDestroyWindow("display");
-
- Dilatometer_Cleanup();
-}
-
+++ /dev/null
-/**
- * @file dilatometer.h
- * @brief Declarations for functions to deal with dilatometer
- */
-
-#include "common.h"
-
-//Threshold to determine the edge of the can
-#define THRES 230
-
-//Number of samples of the image to take
-#define SAMPLES 600
-
-extern void Dilatometer_Init(); // Initialise the dilatometer
-extern void Dilatometer_Cleanup(); // Cleanup
-extern bool Dilatometer_Read( double * value); // Read the Dilatometer
-
* the key) has control or not. If validated, the context control_timestamp is
* updated.
* @param context The context to work in
- * @param key The control key to be validated.
* @return TRUE if authorized, FALSE if not.
*/
bool FCGI_HasControl(FCGIContext *context)
* Generic accept response in JSON format.
* @param context The context to work in
* @param description A short description.
- * @param cookie Optional. If given, the cookie field is set to that value.
*/
void FCGI_AcceptJSON(FCGIContext *context, const char *description)
{
/**
* Escapes a string so it can be used safely.
* Currently escapes to ensure the validity for use as a JSON string
- * Does not support unicode specifiers in the form of \uXXXX.
+ * Does not support unicode specifiers in the form of \\uXXXX.
* @param buf The string to be escaped
* @return The escaped string (return value == buf)
*/
#define CONTROL_KEY_BUFSIZ 41
+/**
+ * An entry that describes an expected user parameter for parsing.
+ * To be used in conjunction with @see FCGI_ParseRequest.
+ */
typedef struct FCGIValue {
+ /** The name of the key (from key/value pair) [in] **/
const char *key;
+ /** A pointer to a variable that will hold the parsed value [out] **/
void *value;
+ /** Bit flags that determine things like if the field is required and if it was received [in/out] **/
unsigned flags;
} FCGIValue;
+/** The type of a user (unauthorised, normal, admin). **/
typedef enum {USER_UNAUTH, USER_NORMAL, USER_ADMIN} UserType;
/**Contextual information related to FCGI requests*/
int response_number;
} FCGIContext;
+/** The type definition of a module handler. **/
typedef void (*ModuleHandler) (FCGIContext *context, char *params);
extern bool FCGI_LockControl(FCGIContext *context, const char * user_name, UserType user_type);
static CvCapture * g_capture = NULL;
static int g_captureID = -1;
+/**
+ * Image stream handler. Returns an image to the user.
+ * @param context The context to work in
+ * @param params User specified parameters
+ */
void Image_Handler(FCGIContext * context, char * params)
{
* @param num - Camera id
* @param width - Width to force
* @param height - Height to force
- * @param image - Pointer to CvMat* to set with result
+ * @param frame - Pointer to IplImage* to set with result
* @returns true on success, false on error
*/
bool Camera_GetImage(int num, int width, int height, IplImage ** frame)
return result;
}
+/**
+ * Executed on cleanup. Releases the OpenCV Capture structs.
+ */
void Image_Cleanup()
{
// Release the capture and IplImage pointers
#include "common.h"
#include "cv.h"
-extern void Image_Init();
+//extern void Image_Init();
extern void Image_Handler(FCGIContext * context, char * params);
extern void Image_Cleanup();
extern bool Camera_GetImage(int num, int width, int height, IplImage ** image);
+++ /dev/null
-/**
- * @file interferometer.c
- * @purpose Implementation of interferometer related functions
- */
-
-#include "cv.h"
-#include "highgui_c.h"
-#include "interferometer.h"
-#include <math.h>
-
-/** Buffer for storing image data. Stored as a single intensity value for the laser light **/
-static CvMat * g_data = NULL;
-
-
-/** Camera capture pointer **/
-static CvCapture * g_capture = NULL;
-
-
-struct timeval start;
-
-#define PI 3.141592
-
-// For testing purposes
-double test_omega = 0.05;
-double test_angle = PI/2;
-double test_noise[] = {0,0,0.02};
-double test_phase = 0;
-double test_intensity = 1.0;
-
-
-static void Interferometer_TestSinusoid()
-{
- if (g_capture == NULL)
- {
- g_capture = cvCreateCameraCapture(0);
- }
-
- // Get image from camera
- IplImage * img = cvQueryFrame(g_capture);
-
- // Convert to CvMat
- CvMat stub;
- CvMat * background = cvGetMat(img, &stub, 0, 0);
- // ... Honestly, I have no idea what the "stub" is for
-
- if (g_data == NULL)
- {
- g_data = cvCreateMat(background->rows, background->cols, CV_32FC3);
- }
-
- //cvShowImage("background", background);
-
- for (int x = 0; x < g_data->cols-1; ++x)
- {
- for (int y = 0; y < g_data->rows-1; ++y)
- {
- // Calculate pure sine in test direction
- double r = x*cos(test_angle) + y*sin(test_angle);
- double value = 0.5*test_intensity*(1+sin(test_omega*r + test_phase));
-
- CvScalar s;
- s.val[0] = 0; s.val[1] = 0; s.val[2] = value;
- CvScalar b = cvGet2D(background, y, x);
-
-
- // Add noise & background image
-
- // Get the order the right way round
- double t = b.val[0];
- b.val[0] = b.val[2];
- b.val[2] = t;
- for (int i = 0; i < 3; ++i)
- {
-
- s.val[i] += (rand() % 1000) * 1e-3 * test_noise[i];
- s.val[i] += b.val[i] / 255; // Camera image is 0-255
- }
-
- //printf("set %d,%d\n", x, y);
-
-
-
- cvSet2D(g_data,y, x, s);
- }
- }
-
-
-}
-
-
-/**
- * Get an image from the Interferometer
- */
-static void Interferometer_GetImage()
-{
-
-
- Interferometer_TestSinusoid();
- //TODO: Implement camera
-
-}
-
-/**
- * Initialise the Interferometer
- */
-void Interferometer_Init()
-{
-
- // Make an initial reading (will allocate memory the first time only).
- Interferometer_Read(1);
-}
-
-/**
- * Cleanup Interferometer stuff
- */
-void Interferometer_Cleanup()
-{
- if (g_data != NULL)
- cvReleaseMat(&g_data);
-
- if (g_capture != NULL)
- cvReleaseCapture(&g_capture);
-
-}
-
-/**
- * Read the interferometer; gets the latest image, processes it, spits out a single number
- * @param samples - Number of columns to scan (increasing will slow down performance!)
- * @returns Value proportional to the change in interferometer path length since the last call to this function
- */
-double Interferometer_Read(int samples)
-{
-
-
-
-
- // Get the latest image
- Interferometer_GetImage();
- // Frequency of the sinusoid
- static double omega = 0;
- // Stores locations of nodes
- static int nodes[MAXNODES];
- // Current phase
- static double phase = 0;
-
- // Phase
- double cur_phase = 0;
-
- int xstep = g_data->cols / (samples+1);
-
- // Used for testing to see where the nodes are identified
- // (Can't modify g_data)
- static CvMat * test_overlay = NULL;
- if (test_overlay == NULL)
- {
- // Creates a memory leak; don't do this in the final version!
- test_overlay = cvCreateMat(g_data->rows, g_data->cols, CV_32FC3);
- }
- cvZero(test_overlay);
- //cvCopy(g_data, test_overlay, NULL);
-
- // For each column to sample
- for (int x = xstep; x < g_data->cols; x += xstep)
- {
-
- double avg = 0.5; //TODO: Calculate from image
- double threshold_dif = 0; //TODO: Pick this value
-
- int num_nodes = 0;
-
- // Find nodes
- for (int y = 1; y < g_data->rows-2 && num_nodes < MAXNODES; ++y)
- {
- if (num_nodes == 0 || abs(nodes[num_nodes-1] - y) > 1)
- {
- // A "node" is defined where the ajacent points are on opposite sides of the avg
- double ldif = INTENSITY(cvGet2D(g_data, y-1,x)) - avg;
- double rdif = INTENSITY(cvGet2D(g_data, y+1,x)) - avg;
-
- // If that is the case, the product of the differences will be negative
- if (ldif * rdif < -threshold_dif)
- {
-
- nodes[num_nodes++] = y;
-
- // Put a white line on the overlay to indicate the node was found
- for (int xx = 0; xx < g_data->cols; ++xx)
- {
- CvScalar s; // = cvGet2D(g_data, y, xx);
- s.val[0] = 1; s.val[1] = 1; s.val[2] = 1;
- cvSet2D(test_overlay, y, xx, s);
- }
- }
- }
- }
-
- // Insufficient nodes found to continue
- if (num_nodes < 2)
- {
- --samples;
- continue;
- }
-
- // Estimate angular frequency from two nodes TODO: Average between nodes
- double slice_omega = (PI*(num_nodes-1)) / (nodes[num_nodes-1] - nodes[0]);
- //printf("SLICE: %f vs %f\n", slice_omega, test_omega);
-
- double slice_phase = 0;
- for (int i = 0; i < num_nodes; ++i)
- {
- double this_phase = ((double)(i)*PI - slice_omega * nodes[i]);
- //printf("Node %d gives phase %f\n", i, this_phase);
- slice_phase += this_phase;
- }
- slice_phase /= num_nodes;
- cur_phase += slice_phase;
- }
-
- // Average over samples
- if (samples == 0)
- return 0;
-
- cur_phase /= samples;
-
-
-
- // Get phase change since last call, save current phase
- double result = (cur_phase - phase);
-
- // HACK
- if (abs(result) > 0.5*PI)
- {
- if (result > 0)
- result -= PI;
- else
- result += PI;
- }
- phase = cur_phase;
-
- // Display the image with lines to indicate results of data processing
- //cvShowImage("nodes", test_overlay);
- //cvWaitKey(1);
- cvAdd(test_overlay, g_data, test_overlay, NULL);
- cvShowImage("overlay", test_overlay);
- cvWaitKey(1);
- return result;
-
-}
-
-/**
- * For testing purposes
- */
-int main(int argc, char ** argv)
-{
- //cvNamedWindow( "display", CV_WINDOW_AUTOSIZE );// Create a window for display.
- gettimeofday(&start, NULL);
-
- //Interferometer_Read(1);
- //exit(EXIT_SUCCESS);
-
- Interferometer_Init();
-
- double sum = 0;
- double last_phase = test_phase;
-
- struct timeval now;
- double time = 0;
-
- while (time < 20)
- {
- gettimeofday(&now, NULL);
- time = TIMEVAL_DIFF(now, start);
-
- test_phase = 0.5*PI*sin(time);
-
-
- double delta = Interferometer_Read(1);
- sum += delta;
-
- printf("%f\t%f\t%f\t%f\t%f\n", time, test_phase - last_phase, test_phase, delta, sum);
-
- last_phase = test_phase;
- //break;
- }
-
-}
-
-
+++ /dev/null
-/**
- * @file interferometer.h
- * @purpose Declarations for functions to deal with interferometer
- */
-
-#include "common.h"
-
-//#define INTENSITY(rgb) ((rgb).val[0]*(rgb).val[0] + (rgb).val[1]*(rgb).val[1] + (rgb).val[2]*(rgb).val[2])
-#define INTENSITY(rgb) ((rgb).val[2])
-
-#define MAXNODES 100 //TODO: Choose value based on real data
-
-extern void Interferometer_Init(); // Initialise the interferometer
-extern void Interferometer_Cleanup(); // Cleanup
-extern double Interferometer_Read(); // Read the interferometer
-
-
-
+++ /dev/null
-rm intertest
-make intertest
-./intertest > test.dat
-
-cmd="set title \"Interferometer Test\""
-cmd="$cmd; set xlabel \"Time (s)\""
-cmd="$cmd; set ylabel \"Phase (rad)\""
-cmd="$cmd; plot \"test.dat\" u 1:3 t \"Specified\" w l, \"test.dat\" u 1:5 t \"Calculated\" w p"
-gnuplot --persist -e "$cmd"
-
-cmd="set title \"Interferometer Test\""
-cmd="$cmd; set xlabel \"Time (s)\""
-cmd="$cmd; set ylabel \"Delta Phase (rad)\""
-cmd="$cmd; plot \"test.dat\" u 1:2 t \"Specified\" w l, \"test.dat\" u 1:4 t \"Measured\" w p"
-gnuplot --persist -e "$cmd"
+++ /dev/null
-/**
- * @file microscope.c
- * @purpose Implementation of microscope related functions
- */
-
-#include "cv.h"
-#include "highgui_c.h"
-#include "microscope.h"
-#include <math.h>
-
-// test positions
-static double test_left, test_right;
-
-// Canny Edge algorithm variables
-int lowThreshold = 30;
-int ratio = 3;
-int kernel_size = 3;
-
-/** Buffer for storing image data. Stored as a **/
-static CvMat * g_srcRGB = NULL; // Source Image
-static CvMat * g_srcGray = NULL; // Gray scale of source image
-static CvMat * g_edges = NULL; // Detected Edges
-static CvMat * g_data = NULL; // Image to mask edges onto
-
-
-/** Camera capture pointer **/
-static CvCapture * g_capture = NULL;
-
-/**
- * Create a test image using left as left edge and right as right edge positions
- */
-void Dilatometer_TestImage()
-{
-
- g_srcRGB = cvCreateMat(480, 640, CV_8UC3);
-
- for( int x = 0; x < 640; ++x)
- {
- for (int y = 0; y < 480; ++y)
- {
- CvScalar s;
- for( int i = 0; i < 3; ++i)
- {
- s.val[i] = 210 + (rand() % 1000) * 1e-0 - (rand() % 1000) * 1e-0;
- // Produce an exponential decay around left edge
- if( x < test_left)
- s.val[i] *= exp( (x - test_left) / 25);
- else if( x < 320)
- s.val[i] *= exp( (test_left - x) / 25);
- // Produce an exponential decay around right edge
- else if( x < test_right)
- s.val[i] *= exp( (x - test_right) / 25);
- else
- s.val[i] *= exp( (test_right - x) / 25);
- }
- cvSet2D(g_srcRGB,y,x,s);
- // if( s.val[0] > 200)
- // printf("row: %d, col: %d, %f\n", y, x, s.val[0]);
- }
-
- }
- if (g_data == NULL)
- {
- g_data = cvCreateMat(g_srcRGB->rows,g_srcRGB->cols,CV_8UC1); //IPL_DEPTH_8U?
- }
- cvCvtColor(g_srcRGB,g_data,CV_RGB2GRAY);
-}
-
-/**
- * Initialise the dilatometer
- */
-void Microscope_Init()
-{
-
- // Make an initial reading (will allocate memory the first time only).
- double val;
- Microscope_Read(&val, 1);
-}
-
-/**
- * Cleanup Interferometer stuff
- */
-void Microscope_Cleanup()
-{
- if (g_data != NULL)
- cvReleaseMat(&g_data);
-
- if (g_capture != NULL)
- cvReleaseCapture(&g_capture);
-
-}
-
-/**
- * Get an image from the Dilatometer
- */
-static void Microscope_GetImage()
-{
- //Need to implement camera
-}
-
-void CannyThreshold()
-{
-
- if (g_data == NULL)
- {
- g_data = cvCreateMat(g_srcGray->rows,g_srcGray->cols,CV_8UC1);
- }
-
- if ( g_edges == NULL)
- {
- g_edges = cvCreateMat(g_srcGray->rows,g_srcGray->cols,CV_8UC1);
- }
-
- //g_data = 0;
- cvShowImage("display", g_srcGray);
- cvWaitKey(0);
- // Reduce noise with a kernel 3x3. Input the grayscale source image, output to edges. (0's mean it's determined from kernel sizes)
- cvSmooth( g_srcGray, g_edges, CV_GAUSSIAN, 9, 9 ,0 ,0 );
-
- cvShowImage("display", g_edges);
- cvWaitKey(0);
-
- // Find the edges in the image
- lowThreshold = 35;
- cvCanny( g_edges, g_edges, lowThreshold, lowThreshold*ratio, kernel_size );
-
- cvShowImage("display", g_edges);
- cvWaitKey(0);
-
- // Mask the edges over G_data
- //.copyTo( g_data, g_edges);
-}
-
-// Test algorithm
-static void Microscope_GetImageTest( )
-{
- //Generates Test image
- //Dilatometer_TestImage();
-
- //Load Test image
- g_srcGray = cvLoadImageM ("testimage.jpg",CV_LOAD_IMAGE_GRAYSCALE );
- CannyThreshold();
-}
-
-
- /**
- * Read the microscope image. The value changed will correspond to the new location of the edge.
- * @param val - Will store the read value if successful
- * @param samples - Number of rows to scan (increasing will slow down performance!)
- * @returns true on successful read
- */
-bool Microscope_Read( double * value, int samples)
-{
- bool result = false;
- double average = 0;
- // Get the image from the camera
- Microscope_GetImageTest();
-
- int width = g_edges->cols;
- int height = g_edges->rows;
-
- // If the number of samples is greater than the image height, sample every row
- if( samples > height)
- {
- samples = height;
- }
-
- int sample_height;
- int num_edges = 0; // Number of edges. if each sample location has an edge, then num_edges = samples
-
- for (int i=0; i<samples; i++)
- {
- // Determine the position in the rows to find the edges.
- // This will give you a number of evenly spaced samples
- sample_height = ceil(height * (i + 1) / samples) -1;
-
- // Need to go through each pixel of a row and find all the locations of a line. If there is more than one pixel, average it. note this only works if the canny edge algorithm returns lines about the actual line (no outliers).
-
- int edge_location=0;
- int num=0;
- for ( int col = 0; col < width; col++)
- {
- // Count the number of points
- // Get the threshold of the pixel at the current location
- CvScalar value = cvGet2D(g_edges, sample_height, col);
- //printf("row: %d, col: %d, value: %f\n",sample_height, col, value.val[0]);
- if( value.val[0]> THRES)
- {
- edge_location += col;
- num++;
- }
- }
- if( num > 0)
- {
- average += ( edge_location / num );
- num_edges++;
- printf("average %f\n", average/num_edges);
- }
- }
- if (num_edges > 0)
- average /= num_edges;
-
- if( average > 0)
- {
- result = true; //Successfully found an edge
- *value = average;
- }
- return result;
-}
-
-// Overlays a line over the given edge position
-void Draw_Edge(double edge)
-{
- CvScalar value;
- value.val[0]=244;
- for( int i = 0; i < g_srcGray->rows; i++)
- {
- cvSet2D(g_edges,i,edge,value);
- }
- cvShowImage("display", g_edges);
- cvWaitKey(0);
-}
-
-/**
- * For testing purposes
- */
-int main(int argc, char ** argv)
-{
- //cvNamedWindow( "display", CV_WINDOW_AUTOSIZE );// Create a window for display.
- //gettimeofday(&start, NULL);
- test_left = 100;
- test_right = 500;
- Microscope_Init();
-
- cvNamedWindow( "display", CV_WINDOW_AUTOSIZE);
-// cvShowImage("display", g_data);
-// cvWaitKey(0);
- double width;
-
- double edge;
- Microscope_Read(&edge,15);
- //For testing purposes, overlay the given average line over the image
- Draw_Edge(edge);
-
-}
-
+++ /dev/null
-/**
- * @file microscope.h
- * @brief Declarations for functions to deal with microscope
- */
-
-#include "common.h"
-
-//Threshold to determine the edge of the can
-#define THRES 230
-
-extern void Microscope_Init(); // Initialise the dilatometer
-extern void Microscope_Cleanup(); // Cleanup
-extern bool Microscope_Read( double * value, int samples); // Read the Microscope
-
PWM_Unexport(i);
}
+/**
+ * Configures a pin (Export/Unexport business)
+ * @param type The pin type (GPIO/PWM/ADC)
+ * @param pin_export Whether to export/unexport/leave-as-is the pin
+ * @param num The pin number
+ */
bool Pin_Configure(const char *type, int pin_export, int num)
{
bool ret = true;
* @param user_id - User identifier
* @param read - Function to call whenever the sensor should be read
* @param init - Function to call to initialise the sensor (may be NULL)
- * @param max_error - Maximum error threshold; program will exit if this is exceeded for the sensor reading
- * @param min_error - Minimum error threshold; program will exit if the sensor reading falls below this value
- * @param max_warn - Maximum warning threshold; program will log warnings if the value exceeds this threshold
- * @param min_warn - Minimum warning threshold; program will log warnings if the value falls below this threshold
+ * @param cleanup - Function to call whenever to deinitialise the sensor (may be NULL)
+ * @param sanity - Function to call to check that the sensor value is sane (may be NULL)
* @returns Number of actuators added so far
*/
int Sensor_Add(const char * name, int user_id, ReadFn read, InitFn init, CleanFn cleanup, SanityFn sanity)
/**
* Helper: Begin sensor response in a given format
* @param context - the FCGIContext
- * @param id - ID of sensor
+ * @param s - Sensor to begin the response for
* @param format - Format
*/
void Sensor_BeginResponse(FCGIContext * context, Sensor * s, DataFormat format)
/**
* Helper: End sensor response in a given format
* @param context - the FCGIContext
- * @param id - ID of the sensor
+ * @param s - Sensor to end the response for
* @param format - Format
*/
void Sensor_EndResponse(FCGIContext * context, Sensor * s, DataFormat format)
return g_sensors[id].name;
}
+/**
+ * Returns the last DataPoint that is currently available.
+ * @param id - The sensor ID for which to retrieve data from
+ * @return The last DataPoint
+ */
DataPoint Sensor_LastData(int id)
{
Sensor * s = &(g_sensors[id]);
extern void Sensor_SetMode(Sensor * s, ControlModes mode, void * arg);
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 bool Sensor_Read(Sensor * s, DataPoint * d); // Read a single DataPoint, indicating if it has changed since the last one
extern Sensor * Sensor_Identify(const char * str); // Identify a Sensor from a string
extern void Sensor_Handler(FCGIContext *context, char * params); // Handle a FCGI request for Sensor data
+++ /dev/null
-#include "cv.h"
-#include "highgui_c.h"
-#include <string.h>
-#include <stdio.h>
-
-/*-------------------------------------------------------------------
-
-compile with:
--I/usr/include/opencv -I/usr/include/opencv2/highgui -L/usr/lib -lopencv_highgui -lopencv_core -lopencv_ml -lopencv_imgproc
-
---------------------------------------------------------------------*/
-
-int storeFrame( CvCapture* capture)
-{
- IplImage *frame;
- CvMat* jpg;
-
- //FILE *fp = fopen ("test.jpg", "wb");
-
- int p[3];
- p[0] = CV_IMWRITE_JPEG_QUALITY;
- p[1] = 100; //quality value. 0-100
- p[2] = 0;
-
- frame = cvQueryFrame(capture);
- if( frame == NULL)
- return 0; //error
- cvSaveImage("../web/images/test.JPG",frame,p);
- //jpg = cvEncodeImage(".jpg", frame,p);
- /*pass buf to client, write to file on client*/
- //fwrite(jpg->data.ptr,1,jpg->rows*jpg->cols, fp);
-
- //decjpg = cvDecodeImage(jpg, CV_LOAD_IMAGE_COLOR);
- //cvShowImage( "Display window", decjpg );
-
- //cvWaitKey(0);
- cvReleaseImageHeader(&frame);
- //cvReleaseMat(&jpg);
- //fclose( fp);
- return 1;
-}
-
-int main (int argc, char** argv)
-{
- CvCapture* capture;
- //cvNamedWindow( "Display window", CV_WINDOW_AUTOSIZE );// Create a window for display.
- //Get capture structure for camera, -1 refers to any camera device.
- //If multiple cameras used, need to use specific camera ID
- capture = cvCreateCameraCapture(-1);
- //If cvCreateCameraCapture returns NULL there is an error with the camera
- if( capture == NULL)
- return -1;
-
- cvSetCaptureProperty (capture, CV_CAP_PROP_FOURCC, 'MJPEG');
-
- while(1)
- {
- if( !storeFrame( capture))
- return -1;
- printf("enter to continue");
- getchar();
- //sleep(1); //for now just to make the camera take 1 shot a second, as that's all my camera seems to be able to take/save (camera or function causing this? is 1 second per frame enough?)
- }
-
- //Need to determine how the function is called in respect to system. just leave it running with a while loop? will something turn it on and off? will the function be called once from elsewhere?
- cvReleaseCapture( &capture);
-}
-
--- /dev/null
+The files here are the previous versions of camera/dilatometer/microscope code that once resided in the main `server` folder. They are now placed here because they are no longer in use.
--- /dev/null
+/**
+ * @file dilatometer.c
+ * @purpose Implementation of dilatometer related functions
+ */
+
+#include "cv.h"
+#include "highgui_c.h"
+#include "dilatometer.h"
+#include <math.h>
+
+// test positions
+static double test_left, test_right;
+
+// Canny Edge algorithm variables
+int blur = 5;
+int lowThreshold = 30;
+int ratio = 3;
+int kernel_size = 3;
+
+/** Buffers for storing image data. **/
+static CvMat * g_srcRGB = NULL; // Source Image
+static CvMat * g_srcGray = NULL; // Gray scale of source image
+static CvMat * g_edges = NULL; // Detected Edges
+
+/** Pointers for capturing image **/
+static CvCapture * g_capture = NULL;
+static IplImage * frame = NULL; // This is required as you can not use capture with CvMat in C
+
+
+/**
+ * Create a test image using left as left edge and right as right edge positions
+ */
+void Dilatometer_TestImage()
+{
+
+ g_srcRGB = cvCreateMat(480, 640, CV_8UC3);
+
+ for( int x = 0; x < 640; ++x)
+ {
+ for (int y = 0; y < 480; ++y)
+ {
+ CvScalar s;
+ for( int i = 0; i < 3; ++i)
+ {
+ s.val[i] = 210 + (rand() % 1000) * 1e-0 - (rand() % 1000) * 1e-0;
+ // Produce an exponential decay around left edge
+ if( x < test_left)
+ s.val[i] *= exp( (x - test_left) / 25);
+ else if( x < 320)
+ s.val[i] *= exp( (test_left - x) / 25);
+ // Produce an exponential decay around right edge
+ else if( x < test_right)
+ s.val[i] *= exp( (x - test_right) / 25);
+ else
+ s.val[i] *= exp( (test_right - x) / 25);
+ }
+ cvSet2D(g_srcRGB,y,x,s);
+ }
+
+ }
+ if (g_srcGray == NULL)
+ {
+ g_srcGray = cvCreateMat(g_srcRGB->rows,g_srcRGB->cols,CV_8UC1);
+ }
+ cvCvtColor(g_srcRGB,g_srcGray,CV_RGB2GRAY);
+}
+
+/**
+ * Cleanup Dilatometer pointers
+ */
+void Dilatometer_Cleanup()
+{
+ if (g_capture != NULL)
+ cvReleaseCapture(&g_capture);
+ if (frame != NULL)
+ cvReleaseImageHeader(&frame);
+ //if (g_srcRGB != NULL)
+ // cvReleaseMat(&g_srcRGB); // Causing run time error in cvReleaseMat
+ if (g_srcGray != NULL)
+ cvReleaseMat(&g_srcGray);
+ if (g_edges != NULL)
+ cvReleaseMat(&g_edges);
+}
+
+/**
+ * Get an image from the Dilatometer
+ */
+static bool Dilatometer_GetImage()
+{
+ bool result = true;
+ // If more than one camera is connected, then input needs to be determined, however the camera ID may change after being unplugged
+ if( g_capture == NULL)
+ {
+ g_capture = cvCreateCameraCapture(0);
+ //If cvCreateCameraCapture returns NULL there is an error with the camera
+ if( g_capture == NULL)
+ {
+ result = false;
+ return;
+ }
+ }
+
+ // Get the frame and convert it to CvMat
+ frame = cvQueryFrame(g_capture);
+ CvMat stub;
+ g_srcRGB = cvGetMat(frame,&stub,0,0);
+
+ if( g_srcRGB == NULL)
+ result = false;
+
+ // Convert the image to grayscale
+ if (g_srcGray == NULL)
+ {
+ g_srcGray = cvCreateMat(g_srcRGB->rows,g_srcRGB->cols,CV_8UC1);
+ }
+
+ cvCvtColor(g_srcRGB,g_srcGray,CV_RGB2GRAY);
+
+ return result;
+}
+
+/**
+ * Applies the Canny threshold algorithm to the captured image.
+ */
+void CannyThreshold()
+{
+ if ( g_edges == NULL)
+ {
+ g_edges = cvCreateMat(g_srcGray->rows,g_srcGray->cols,CV_8UC1);
+ }
+
+ // Commented out lines are used during testing to show the image to screen, can also save the test images
+ //cvShowImage("display", g_srcGray);
+ //cvWaitKey(0);
+
+ // Reduce noise with a kernel blurxblur. Input the grayscale source image, output to edges. (0's mean it's determined from kernel sizes)
+ cvSmooth( g_srcGray, g_edges, CV_GAUSSIAN, blur, blur ,0 ,0 );
+
+ //Save the image
+ //cvSaveImage("test_blurred.jpg",g_edges,0);
+
+ //cvShowImage("display", g_edges);
+ //cvWaitKey(0);
+
+ // Find the edges in the image
+ cvCanny( g_edges, g_edges, lowThreshold, lowThreshold*ratio, kernel_size );
+
+ //Save the image
+ //cvSaveImage("test_edge.jpg",g_edges,0);
+
+ //cvShowImage("display", g_edges);
+ //cvWaitKey(0);
+
+}
+
+ /**
+ * Read the dilatometer image. The value changed will correspond to the new location of the edge.
+ * @param val - Will store the read value if successful
+ * @param samples - Number of rows to scan (increasing will slow down performance!)
+ * @returns true on successful read
+ */
+bool Dilatometer_GetEdge( double * value, int samples)
+{
+ bool result = false;
+ double average = 0;
+ // Get the image from the camera
+ result = Dilatometer_GetImage();
+ // If an error occured when capturing image then return
+ if (!result)
+ return result;
+
+ // Apply the Canny Edge theorem to the image
+ CannyThreshold();
+
+ int width = g_edges->cols;
+ int height = g_edges->rows;
+
+ // If the number of samples is greater than the image height, sample every row
+ if( samples > height)
+ {
+ samples = height;
+ }
+
+ int sample_height;
+ int num_edges = 0; // Number of edges. if each sample location has an edge, then num_edges = samples
+
+ for (int i=0; i<samples; i++)
+ {
+ // Determine the position in the rows to find the edges.
+ // This will give you a number of evenly spaced samples
+ sample_height = ceil(height * (i + 1) / samples) -1;
+
+ // Need to go through each pixel of a row and find all the locations of a line. If there is more than one pixel, average it. note this only works if the canny edge algorithm returns lines about the actual line (no outliers).
+
+ int edge_location=0;
+ int num=0;
+ for ( int col = 0; col < width; col++)
+ {
+ // Count the number of points
+ // Get the threshold of the pixel at the current location
+ CvScalar value = cvGet2D(g_edges, sample_height, col);
+ if( value.val[0]> THRES)
+ {
+ edge_location += col;
+ num++;
+ }
+ }
+ if( num > 0)
+ {
+ average += ( edge_location / num );
+ num_edges++;
+ }
+ }
+ if (num_edges > 0)
+ average /= num_edges;
+
+ if( average > 0)
+ {
+ result = true; //Successfully found an edge
+ *value = average;
+ }
+ return result;
+}
+
+ /**
+ * Read the dilatometer image. The value changed will correspond to the new location of the edge.
+ * @param val - Will store the read value if successful
+ * @returns true on successful read
+ */
+bool Dilatometer_Read( double * value)
+{
+ bool result = Dilatometer_GetEdge(value, SAMPLES);
+ return result;
+}
+
+/**
+ * Initialise the dilatometer
+ */
+void Dilatometer_Init()
+{
+ // Make an initial reading (will allocate memory the first time only).
+ double val;
+ Dilatometer_GetEdge(&val, 1);
+}
+
+/**
+ * Overlays a line over the given edge position
+ */
+void Draw_Edge(double edge)
+{
+ CvScalar value;
+ value.val[0]=244;
+ for( int i = 0; i < g_srcGray->rows; i++)
+ {
+ cvSet2D(g_edges,i,edge,value);
+ }
+ cvShowImage("display", g_edges);
+ cvWaitKey(0);
+ //cvSaveImage("test_edge_avg.jpg",g_edges,0);
+}
+
+/* // Test algorithm
+static void Dilatometer_GetImageTest( )
+{
+ //Generates Test image
+ //Dilatometer_TestImage();
+
+ //Load Test image
+ g_srcGray = cvLoadImageM ("testimage4.jpg",CV_LOAD_IMAGE_GRAYSCALE );
+}*/
+
+/**
+ * For testing purposes
+ */
+int main(int argc, char ** argv)
+{
+ //cvNamedWindow( "display", CV_WINDOW_AUTOSIZE );// Create a window for display.
+ //gettimeofday(&start, NULL);
+ test_left = 100;
+ test_right = 500;
+ Dilatometer_Init();
+
+ cvNamedWindow( "display", CV_WINDOW_AUTOSIZE);
+ //double width;
+
+ double edge;
+ Dilatometer_GetEdge(&edge,20000);
+ //For testing purposes, overlay the given average line over the image
+ //Draw_Edge(edge);
+
+ cvDestroyWindow("display");
+
+ Dilatometer_Cleanup();
+}
+
--- /dev/null
+/**
+ * @file dilatometer.h
+ * @brief Declarations for functions to deal with dilatometer
+ */
+
+#include "common.h"
+
+//Threshold to determine the edge of the can
+#define THRES 230
+
+//Number of samples of the image to take
+#define SAMPLES 600
+
+extern void Dilatometer_Init(); // Initialise the dilatometer
+extern void Dilatometer_Cleanup(); // Cleanup
+extern bool Dilatometer_Read( double * value); // Read the Dilatometer
+
--- /dev/null
+/**
+ * @file microscope.c
+ * @purpose Implementation of microscope related functions
+ */
+
+#include "cv.h"
+#include "highgui_c.h"
+#include "microscope.h"
+#include <math.h>
+
+// test positions
+static double test_left, test_right;
+
+// Canny Edge algorithm variables
+int lowThreshold = 30;
+int ratio = 3;
+int kernel_size = 3;
+
+/** Buffer for storing image data. Stored as a **/
+static CvMat * g_srcRGB = NULL; // Source Image
+static CvMat * g_srcGray = NULL; // Gray scale of source image
+static CvMat * g_edges = NULL; // Detected Edges
+static CvMat * g_data = NULL; // Image to mask edges onto
+
+
+/** Camera capture pointer **/
+static CvCapture * g_capture = NULL;
+
+/**
+ * Create a test image using left as left edge and right as right edge positions
+ */
+void Dilatometer_TestImage()
+{
+
+ g_srcRGB = cvCreateMat(480, 640, CV_8UC3);
+
+ for( int x = 0; x < 640; ++x)
+ {
+ for (int y = 0; y < 480; ++y)
+ {
+ CvScalar s;
+ for( int i = 0; i < 3; ++i)
+ {
+ s.val[i] = 210 + (rand() % 1000) * 1e-0 - (rand() % 1000) * 1e-0;
+ // Produce an exponential decay around left edge
+ if( x < test_left)
+ s.val[i] *= exp( (x - test_left) / 25);
+ else if( x < 320)
+ s.val[i] *= exp( (test_left - x) / 25);
+ // Produce an exponential decay around right edge
+ else if( x < test_right)
+ s.val[i] *= exp( (x - test_right) / 25);
+ else
+ s.val[i] *= exp( (test_right - x) / 25);
+ }
+ cvSet2D(g_srcRGB,y,x,s);
+ // if( s.val[0] > 200)
+ // printf("row: %d, col: %d, %f\n", y, x, s.val[0]);
+ }
+
+ }
+ if (g_data == NULL)
+ {
+ g_data = cvCreateMat(g_srcRGB->rows,g_srcRGB->cols,CV_8UC1); //IPL_DEPTH_8U?
+ }
+ cvCvtColor(g_srcRGB,g_data,CV_RGB2GRAY);
+}
+
+/**
+ * Initialise the dilatometer
+ */
+void Microscope_Init()
+{
+
+ // Make an initial reading (will allocate memory the first time only).
+ double val;
+ Microscope_Read(&val, 1);
+}
+
+/**
+ * Cleanup Interferometer stuff
+ */
+void Microscope_Cleanup()
+{
+ if (g_data != NULL)
+ cvReleaseMat(&g_data);
+
+ if (g_capture != NULL)
+ cvReleaseCapture(&g_capture);
+
+}
+
+/**
+ * Get an image from the Dilatometer
+ */
+static void Microscope_GetImage()
+{
+ //Need to implement camera
+}
+
+void CannyThreshold()
+{
+
+ if (g_data == NULL)
+ {
+ g_data = cvCreateMat(g_srcGray->rows,g_srcGray->cols,CV_8UC1);
+ }
+
+ if ( g_edges == NULL)
+ {
+ g_edges = cvCreateMat(g_srcGray->rows,g_srcGray->cols,CV_8UC1);
+ }
+
+ //g_data = 0;
+ cvShowImage("display", g_srcGray);
+ cvWaitKey(0);
+ // Reduce noise with a kernel 3x3. Input the grayscale source image, output to edges. (0's mean it's determined from kernel sizes)
+ cvSmooth( g_srcGray, g_edges, CV_GAUSSIAN, 9, 9 ,0 ,0 );
+
+ cvShowImage("display", g_edges);
+ cvWaitKey(0);
+
+ // Find the edges in the image
+ lowThreshold = 35;
+ cvCanny( g_edges, g_edges, lowThreshold, lowThreshold*ratio, kernel_size );
+
+ cvShowImage("display", g_edges);
+ cvWaitKey(0);
+
+ // Mask the edges over G_data
+ //.copyTo( g_data, g_edges);
+}
+
+// Test algorithm
+static void Microscope_GetImageTest( )
+{
+ //Generates Test image
+ //Dilatometer_TestImage();
+
+ //Load Test image
+ g_srcGray = cvLoadImageM ("testimage.jpg",CV_LOAD_IMAGE_GRAYSCALE );
+ CannyThreshold();
+}
+
+
+ /**
+ * Read the microscope image. The value changed will correspond to the new location of the edge.
+ * @param val - Will store the read value if successful
+ * @param samples - Number of rows to scan (increasing will slow down performance!)
+ * @returns true on successful read
+ */
+bool Microscope_Read( double * value, int samples)
+{
+ bool result = false;
+ double average = 0;
+ // Get the image from the camera
+ Microscope_GetImageTest();
+
+ int width = g_edges->cols;
+ int height = g_edges->rows;
+
+ // If the number of samples is greater than the image height, sample every row
+ if( samples > height)
+ {
+ samples = height;
+ }
+
+ int sample_height;
+ int num_edges = 0; // Number of edges. if each sample location has an edge, then num_edges = samples
+
+ for (int i=0; i<samples; i++)
+ {
+ // Determine the position in the rows to find the edges.
+ // This will give you a number of evenly spaced samples
+ sample_height = ceil(height * (i + 1) / samples) -1;
+
+ // Need to go through each pixel of a row and find all the locations of a line. If there is more than one pixel, average it. note this only works if the canny edge algorithm returns lines about the actual line (no outliers).
+
+ int edge_location=0;
+ int num=0;
+ for ( int col = 0; col < width; col++)
+ {
+ // Count the number of points
+ // Get the threshold of the pixel at the current location
+ CvScalar value = cvGet2D(g_edges, sample_height, col);
+ //printf("row: %d, col: %d, value: %f\n",sample_height, col, value.val[0]);
+ if( value.val[0]> THRES)
+ {
+ edge_location += col;
+ num++;
+ }
+ }
+ if( num > 0)
+ {
+ average += ( edge_location / num );
+ num_edges++;
+ printf("average %f\n", average/num_edges);
+ }
+ }
+ if (num_edges > 0)
+ average /= num_edges;
+
+ if( average > 0)
+ {
+ result = true; //Successfully found an edge
+ *value = average;
+ }
+ return result;
+}
+
+// Overlays a line over the given edge position
+void Draw_Edge(double edge)
+{
+ CvScalar value;
+ value.val[0]=244;
+ for( int i = 0; i < g_srcGray->rows; i++)
+ {
+ cvSet2D(g_edges,i,edge,value);
+ }
+ cvShowImage("display", g_edges);
+ cvWaitKey(0);
+}
+
+/**
+ * For testing purposes
+ */
+int main(int argc, char ** argv)
+{
+ //cvNamedWindow( "display", CV_WINDOW_AUTOSIZE );// Create a window for display.
+ //gettimeofday(&start, NULL);
+ test_left = 100;
+ test_right = 500;
+ Microscope_Init();
+
+ cvNamedWindow( "display", CV_WINDOW_AUTOSIZE);
+// cvShowImage("display", g_data);
+// cvWaitKey(0);
+ double width;
+
+ double edge;
+ Microscope_Read(&edge,15);
+ //For testing purposes, overlay the given average line over the image
+ Draw_Edge(edge);
+
+}
+
--- /dev/null
+/**
+ * @file microscope.h
+ * @brief Declarations for functions to deal with microscope
+ */
+
+#include "common.h"
+
+//Threshold to determine the edge of the can
+#define THRES 230
+
+extern void Microscope_Init(); // Initialise the dilatometer
+extern void Microscope_Cleanup(); // Cleanup
+extern bool Microscope_Read( double * value, int samples); // Read the Microscope
+
--- /dev/null
+#include "cv.h"
+#include "highgui_c.h"
+#include <string.h>
+#include <stdio.h>
+
+/*-------------------------------------------------------------------
+
+compile with:
+-I/usr/include/opencv -I/usr/include/opencv2/highgui -L/usr/lib -lopencv_highgui -lopencv_core -lopencv_ml -lopencv_imgproc
+
+--------------------------------------------------------------------*/
+
+int storeFrame( CvCapture* capture)
+{
+ IplImage *frame;
+ CvMat* jpg;
+
+ //FILE *fp = fopen ("test.jpg", "wb");
+
+ int p[3];
+ p[0] = CV_IMWRITE_JPEG_QUALITY;
+ p[1] = 100; //quality value. 0-100
+ p[2] = 0;
+
+ frame = cvQueryFrame(capture);
+ if( frame == NULL)
+ return 0; //error
+ cvSaveImage("../web/images/test.JPG",frame,p);
+ //jpg = cvEncodeImage(".jpg", frame,p);
+ /*pass buf to client, write to file on client*/
+ //fwrite(jpg->data.ptr,1,jpg->rows*jpg->cols, fp);
+
+ //decjpg = cvDecodeImage(jpg, CV_LOAD_IMAGE_COLOR);
+ //cvShowImage( "Display window", decjpg );
+
+ //cvWaitKey(0);
+ cvReleaseImageHeader(&frame);
+ //cvReleaseMat(&jpg);
+ //fclose( fp);
+ return 1;
+}
+
+int main (int argc, char** argv)
+{
+ CvCapture* capture;
+ //cvNamedWindow( "Display window", CV_WINDOW_AUTOSIZE );// Create a window for display.
+ //Get capture structure for camera, -1 refers to any camera device.
+ //If multiple cameras used, need to use specific camera ID
+ capture = cvCreateCameraCapture(-1);
+ //If cvCreateCameraCapture returns NULL there is an error with the camera
+ if( capture == NULL)
+ return -1;
+
+ cvSetCaptureProperty (capture, CV_CAP_PROP_FOURCC, 'MJPEG');
+
+ while(1)
+ {
+ if( !storeFrame( capture))
+ return -1;
+ printf("enter to continue");
+ getchar();
+ //sleep(1); //for now just to make the camera take 1 shot a second, as that's all my camera seems to be able to take/save (camera or function causing this? is 1 second per frame enough?)
+ }
+
+ //Need to determine how the function is called in respect to system. just leave it running with a while loop? will something turn it on and off? will the function be called once from elsewhere?
+ cvReleaseCapture( &capture);
+}
+
--- /dev/null
+These are the interferometer test files, which once resided in the main `server` directory. They have been moved here because this code is no longer in use.
--- /dev/null
+/**
+ * @file interferometer.c
+ * @purpose Implementation of interferometer related functions
+ */
+
+#include "cv.h"
+#include "highgui_c.h"
+#include "interferometer.h"
+#include <math.h>
+
+/** Buffer for storing image data. Stored as a single intensity value for the laser light **/
+static CvMat * g_data = NULL;
+
+
+/** Camera capture pointer **/
+static CvCapture * g_capture = NULL;
+
+
+struct timeval start;
+
+#define PI 3.141592
+
+// For testing purposes
+double test_omega = 0.05;
+double test_angle = PI/2;
+double test_noise[] = {0,0,0.02};
+double test_phase = 0;
+double test_intensity = 1.0;
+
+
+static void Interferometer_TestSinusoid()
+{
+ if (g_capture == NULL)
+ {
+ g_capture = cvCreateCameraCapture(0);
+ }
+
+ // Get image from camera
+ IplImage * img = cvQueryFrame(g_capture);
+
+ // Convert to CvMat
+ CvMat stub;
+ CvMat * background = cvGetMat(img, &stub, 0, 0);
+ // ... Honestly, I have no idea what the "stub" is for
+
+ if (g_data == NULL)
+ {
+ g_data = cvCreateMat(background->rows, background->cols, CV_32FC3);
+ }
+
+ //cvShowImage("background", background);
+
+ for (int x = 0; x < g_data->cols-1; ++x)
+ {
+ for (int y = 0; y < g_data->rows-1; ++y)
+ {
+ // Calculate pure sine in test direction
+ double r = x*cos(test_angle) + y*sin(test_angle);
+ double value = 0.5*test_intensity*(1+sin(test_omega*r + test_phase));
+
+ CvScalar s;
+ s.val[0] = 0; s.val[1] = 0; s.val[2] = value;
+ CvScalar b = cvGet2D(background, y, x);
+
+
+ // Add noise & background image
+
+ // Get the order the right way round
+ double t = b.val[0];
+ b.val[0] = b.val[2];
+ b.val[2] = t;
+ for (int i = 0; i < 3; ++i)
+ {
+
+ s.val[i] += (rand() % 1000) * 1e-3 * test_noise[i];
+ s.val[i] += b.val[i] / 255; // Camera image is 0-255
+ }
+
+ //printf("set %d,%d\n", x, y);
+
+
+
+ cvSet2D(g_data,y, x, s);
+ }
+ }
+
+
+}
+
+
+/**
+ * Get an image from the Interferometer
+ */
+static void Interferometer_GetImage()
+{
+
+
+ Interferometer_TestSinusoid();
+ //TODO: Implement camera
+
+}
+
+/**
+ * Initialise the Interferometer
+ */
+void Interferometer_Init()
+{
+
+ // Make an initial reading (will allocate memory the first time only).
+ Interferometer_Read(1);
+}
+
+/**
+ * Cleanup Interferometer stuff
+ */
+void Interferometer_Cleanup()
+{
+ if (g_data != NULL)
+ cvReleaseMat(&g_data);
+
+ if (g_capture != NULL)
+ cvReleaseCapture(&g_capture);
+
+}
+
+/**
+ * Read the interferometer; gets the latest image, processes it, spits out a single number
+ * @param samples - Number of columns to scan (increasing will slow down performance!)
+ * @returns Value proportional to the change in interferometer path length since the last call to this function
+ */
+double Interferometer_Read(int samples)
+{
+
+
+
+
+ // Get the latest image
+ Interferometer_GetImage();
+ // Frequency of the sinusoid
+ static double omega = 0;
+ // Stores locations of nodes
+ static int nodes[MAXNODES];
+ // Current phase
+ static double phase = 0;
+
+ // Phase
+ double cur_phase = 0;
+
+ int xstep = g_data->cols / (samples+1);
+
+ // Used for testing to see where the nodes are identified
+ // (Can't modify g_data)
+ static CvMat * test_overlay = NULL;
+ if (test_overlay == NULL)
+ {
+ // Creates a memory leak; don't do this in the final version!
+ test_overlay = cvCreateMat(g_data->rows, g_data->cols, CV_32FC3);
+ }
+ cvZero(test_overlay);
+ //cvCopy(g_data, test_overlay, NULL);
+
+ // For each column to sample
+ for (int x = xstep; x < g_data->cols; x += xstep)
+ {
+
+ double avg = 0.5; //TODO: Calculate from image
+ double threshold_dif = 0; //TODO: Pick this value
+
+ int num_nodes = 0;
+
+ // Find nodes
+ for (int y = 1; y < g_data->rows-2 && num_nodes < MAXNODES; ++y)
+ {
+ if (num_nodes == 0 || abs(nodes[num_nodes-1] - y) > 1)
+ {
+ // A "node" is defined where the ajacent points are on opposite sides of the avg
+ double ldif = INTENSITY(cvGet2D(g_data, y-1,x)) - avg;
+ double rdif = INTENSITY(cvGet2D(g_data, y+1,x)) - avg;
+
+ // If that is the case, the product of the differences will be negative
+ if (ldif * rdif < -threshold_dif)
+ {
+
+ nodes[num_nodes++] = y;
+
+ // Put a white line on the overlay to indicate the node was found
+ for (int xx = 0; xx < g_data->cols; ++xx)
+ {
+ CvScalar s; // = cvGet2D(g_data, y, xx);
+ s.val[0] = 1; s.val[1] = 1; s.val[2] = 1;
+ cvSet2D(test_overlay, y, xx, s);
+ }
+ }
+ }
+ }
+
+ // Insufficient nodes found to continue
+ if (num_nodes < 2)
+ {
+ --samples;
+ continue;
+ }
+
+ // Estimate angular frequency from two nodes TODO: Average between nodes
+ double slice_omega = (PI*(num_nodes-1)) / (nodes[num_nodes-1] - nodes[0]);
+ //printf("SLICE: %f vs %f\n", slice_omega, test_omega);
+
+ double slice_phase = 0;
+ for (int i = 0; i < num_nodes; ++i)
+ {
+ double this_phase = ((double)(i)*PI - slice_omega * nodes[i]);
+ //printf("Node %d gives phase %f\n", i, this_phase);
+ slice_phase += this_phase;
+ }
+ slice_phase /= num_nodes;
+ cur_phase += slice_phase;
+ }
+
+ // Average over samples
+ if (samples == 0)
+ return 0;
+
+ cur_phase /= samples;
+
+
+
+ // Get phase change since last call, save current phase
+ double result = (cur_phase - phase);
+
+ // HACK
+ if (abs(result) > 0.5*PI)
+ {
+ if (result > 0)
+ result -= PI;
+ else
+ result += PI;
+ }
+ phase = cur_phase;
+
+ // Display the image with lines to indicate results of data processing
+ //cvShowImage("nodes", test_overlay);
+ //cvWaitKey(1);
+ cvAdd(test_overlay, g_data, test_overlay, NULL);
+ cvShowImage("overlay", test_overlay);
+ cvWaitKey(1);
+ return result;
+
+}
+
+/**
+ * For testing purposes
+ */
+int main(int argc, char ** argv)
+{
+ //cvNamedWindow( "display", CV_WINDOW_AUTOSIZE );// Create a window for display.
+ gettimeofday(&start, NULL);
+
+ //Interferometer_Read(1);
+ //exit(EXIT_SUCCESS);
+
+ Interferometer_Init();
+
+ double sum = 0;
+ double last_phase = test_phase;
+
+ struct timeval now;
+ double time = 0;
+
+ while (time < 20)
+ {
+ gettimeofday(&now, NULL);
+ time = TIMEVAL_DIFF(now, start);
+
+ test_phase = 0.5*PI*sin(time);
+
+
+ double delta = Interferometer_Read(1);
+ sum += delta;
+
+ printf("%f\t%f\t%f\t%f\t%f\n", time, test_phase - last_phase, test_phase, delta, sum);
+
+ last_phase = test_phase;
+ //break;
+ }
+
+}
+
+
--- /dev/null
+/**
+ * @file interferometer.h
+ * @purpose Declarations for functions to deal with interferometer
+ */
+
+#include "common.h"
+
+//#define INTENSITY(rgb) ((rgb).val[0]*(rgb).val[0] + (rgb).val[1]*(rgb).val[1] + (rgb).val[2]*(rgb).val[2])
+#define INTENSITY(rgb) ((rgb).val[2])
+
+#define MAXNODES 100 //TODO: Choose value based on real data
+
+extern void Interferometer_Init(); // Initialise the interferometer
+extern void Interferometer_Cleanup(); // Cleanup
+extern double Interferometer_Read(); // Read the interferometer
+
+
+
--- /dev/null
+rm intertest
+make intertest
+./intertest > test.dat
+
+cmd="set title \"Interferometer Test\""
+cmd="$cmd; set xlabel \"Time (s)\""
+cmd="$cmd; set ylabel \"Phase (rad)\""
+cmd="$cmd; plot \"test.dat\" u 1:3 t \"Specified\" w l, \"test.dat\" u 1:5 t \"Calculated\" w p"
+gnuplot --persist -e "$cmd"
+
+cmd="set title \"Interferometer Test\""
+cmd="$cmd; set xlabel \"Time (s)\""
+cmd="$cmd; set ylabel \"Delta Phase (rad)\""
+cmd="$cmd; plot \"test.dat\" u 1:2 t \"Specified\" w l, \"test.dat\" u 1:4 t \"Measured\" w p"
+gnuplot --persist -e "$cmd"