From: Sam Moore Date: Sun, 3 Nov 2013 23:09:49 +0000 (-0800) Subject: Merge pull request #85 from Callum-/dilatometer X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=a671f27ecb900f91bf32b8b13edb678009e319c1;hp=ac7555148c78522b9d3baf9d3682660889b999e2;p=matches%2FMCTX3420.git Merge pull request #85 from Callum-/dilatometer Fixed references to figures --- diff --git a/irc/log b/irc/log index 92f80c9..570791a 100644 --- a/irc/log +++ b/irc/log @@ -8240,3 +8240,121 @@ 21:36 -!- MctxBot [~twang@106-68-93-93.dyn.iinet.net.au] has joined #mctxuwa_softdev 21:58 -!- MctxBot [~twang@106-68-93-93.dyn.iinet.net.au] has quit ["reboot"] 22:35 -!- MctxBot [~twang@106-68-93-93.dyn.iinet.net.au] has joined #mctxuwa_softdev +--- Day changed Sun Nov 03 2013 +01:41 -!- Rowan [~Rowan@130.95.91.235] has joined #mctxuwa_softdev +01:44 -!- Rowan [~Rowan@130.95.91.235] has quit [EOF From client] +13:55 -!- jtanx [~asfa@106-68-93-93.dyn.iinet.net.au] has joined #mctxuwa_softdev +15:21 -!- Callum [~Callum@106-69-4-220.dyn.iinet.net.au] has joined #mctxuwa_softdev +15:21 < jtanx> hello +15:21 < Callum> hey +15:22 < jtanx> how's life +15:22 < Callum> ok +15:22 < Callum> that appendix reference +15:23 < jtanx> yeah? +15:23 < Callum> was because i put the canny edge figures in an appendix +15:23 < jtanx> okay, so would that now be figure 2.17 +15:25 < Callum> technically no, im reffering to 2.17 C-F but without the edge line superimposed onto it +15:25 < jtanx> sure +15:26 < Callum> also is the other thing you were referring to when i said graphs instead of figures? +15:26 < Callum> must of glanced over that in my proof read +15:26 < jtanx> "The results can be seen in figure 2.14. From the graphs (Figure ??) +15:27 < Callum> change graphs to figure +15:27 < jtanx> figure 2.17 again? +15:27 < Callum> no +15:27 < Callum> its referring to 2.14 still +15:27 < jtanx> okay +15:27 < jtanx> seems a bit redundant, with the previous sentence +15:28 < Callum> yea. remove previous sentece and say From figure 2.14 it can be.. +15:28 < jtanx> Sure +15:33 < Callum> also +15:33 < Callum> 2.17A and B are the same thing? +15:33 < Callum> ones meant to be grayscale +15:33 < jtanx> so they are... +15:33 < jtanx> woops +15:44 < jtanx> okay, it should be fixed (in my repo for now) +15:50 < Callum> thanks +15:57 < jtanx> no problem +15:57 -!- Callum [~Callum@106-69-4-220.dyn.iinet.net.au] has quit [Connection reset by peer] +16:05 -!- jtanx [~asfa@106-68-93-93.dyn.iinet.net.au] has quit ["reboot this POS computer"] +16:20 -!- jtanx [~asfa@106-68-93-93.dyn.iinet.net.au] has joined #mctxuwa_softdev +17:20 -!- Callum [~Callum@106-69-4-220.dyn.iinet.net.au] has joined #mctxuwa_softdev +17:32 < jtanx> Callum: are you sure you want to leave your section in first person? +17:33 < Callum> hmm. has everyone else done 3rd? +17:33 < jtanx> I think the rest of it is in 3rd +17:34 < jtanx> it's up to you though +17:34 < Callum> well the way i understood it was we were writing about what we did, but if the rest is in 3rd then should probably change it to be consistent +17:34 < Callum> we did individually* +17:34 < Callum> probably doesnt matter +17:34 < Callum> better to go with consistency +17:36 < Callum> most of mine is in 3rd anyway ahah. +17:37 < Callum> just change the first person ones to third then. or i can..but il need to learn how to modify this stuff +17:37 < jtanx> you can just modify your original .doc one and I can probably then make the changes +17:37 < jtanx> if you feel more comfortable with that +17:37 < Callum> it would be easier to modify the final one surely +17:38 < jtanx> Okay +17:38 < jtanx> Well the stuff is in Design.tex +17:38 < jtanx> hmm +17:38 < jtanx> I should probably just merge my stuff first +18:07 < Callum> hmm i should probably go through and fix/make sure references to images are right. i originally had 5 edges images, and sam im presuming? removed the one i was using in the progression +18:08 < jtanx> probably +18:08 < Callum> as i split it in two (one set of images shows 1 images progression, other just shows the end for different values) +18:08 < jtanx> he had some issues reading your original images correctly afaik +18:09 < Callum> hmm. il look into it soon +18:23 -!- Callum_ [~Callum@106-69-4-220.dyn.iinet.net.au] has joined #mctxuwa_softdev +18:34 -!- Callum [~Callum@106-69-4-220.dyn.iinet.net.au] has quit [Ping timeout] +18:37 < Callum_> yea the images arent referenced properly +18:39 < Callum_> also make reference to an image he removed +18:48 < Callum_> can the figure removed be added back and 2.17F be moved to before the current 3? +18:48 < Callum_> or atleast just the second request +18:48 < Callum_> zz. by current 3 i mean the 3 before it +18:48 < jtanx> well, what figure are you referring to that's been removed? +18:48 < Callum_> in my original document +18:48 < Callum_> 2D +18:48 < Callum_> 2C* +18:49 < Callum_> but as 2F is the same original image +18:49 < Callum_> i can just change the values i refer to +18:49 < Callum_> 2.17F +18:49 < Callum_> i must sound pretty confusing right now.. :p +18:49 < jtanx> yes... +18:50 < Callum_> ok. 2.17A,B,F are all from the same original image, C,D,E are from another (which i dont actually show anywhere..oh well) +18:51 < Callum_> in my text i refer to an image which is comment to A,B,F but isnt actually there. but i can change the values i say is used to make it equivalent to F +18:51 < Callum_> TBH i'd probably prefer to have 2 figures, one to show the progression of the images and another to add some more examples. but if thats too hard to do its ok. i can work with wahts there +18:52 < Callum_> progression of 1 image* +18:57 < Callum_> get that? :P +18:59 < jtanx> sort of... +18:59 < jtanx> I don't know +18:59 < jtanx> split figure 2.17 into two +19:00 < jtanx> you're updating the text? +19:02 < Callum_> yea +19:02 < Callum_> i can just leave it as 1 figure, iv switched F and C +19:02 < jtanx> okay +19:08 < Callum_> Also. I think the majority of this should be moved down into the results section +19:08 < Callum_> so its actually next to/after what its referring to +19:12 < Callum_> this automatically numbers stuff yea? so if i want to split a figure all i need to do is copy the format and halve it? +19:12 < jtanx> I'm not sure +19:12 < jtanx> but I'd think so +19:12 < jtanx> so long as you name it appropriately +19:12 < jtanx> do you have latex installed +19:12 < Callum_> yea +19:13 < jtanx> okay +19:15 < Callum_> wait. bi' +19:15 < Callum_> no +19:15 < Callum_> i was saying yea to labelling +19:15 < jtanx> right +19:28 < Callum_> ok well iv fixed the referencing. just left it as 1 figure +21:18 < Callum_> so when are we meeting tomorrow then? +21:18 < jtanx> we have to +21:18 < jtanx> oh right when +21:18 < jtanx> I dunno +21:18 < Callum_> haha +21:51 < jtanx> before 5pm? :P +21:51 < Callum_> sounds good. 4.59 it is :p +21:52 < Callum_> but if we dont set a time il probably end up getting there around 11/12, maybe a bit earlier. depends when i can drag myself out of bad +21:52 < Callum_> bes +21:52 < Callum_> ugh the place you sleep Dx +21:53 < jtanx> haha +21:54 < jtanx> okay, well 11am sounds good I guess +22:03 -!- Callum_ [~Callum@106-69-4-220.dyn.iinet.net.au] has quit [Connection reset by peer] +23:02 -!- MctxBot [~twang@106-68-93-93.dyn.iinet.net.au] has quit [Ping timeout] +23:40 -!- jtanx [~asfa@106-68-93-93.dyn.iinet.net.au] has quit ["ChatZilla 0.9.90.1 [Firefox 24.0/20130910160258]"] +23:46 -!- MctxBot [~twang@106-68-93-93.dyn.iinet.net.au] has joined #mctxuwa_softdev diff --git a/reports/final/titlepage/Titlepage.tex b/reports/final/titlepage/Titlepage.tex index c4e0d89..937f1b1 100644 --- a/reports/final/titlepage/Titlepage.tex +++ b/reports/final/titlepage/Titlepage.tex @@ -1,14 +1,19 @@ \begin{titlepage} -\title{MCTX3420 2013\\Exploding Cans Project\\Software Team Report} +\title{MCTX3420 Mechatronics Design\\Remote System Control of a Pressure Vessel Test Rig\\Software Team Report} \author{Justin Kruger, 20767264 (Chapter \ref{Introduction and Approach})\\ Sam Moore, 20503628 (Editing/Referencing, Sections \ref{Server Program},\ref{Hardware Interfacing},\ref{Authentication Mechanisms} Chapter \ref{Conclusions and Recommendations}), \\ Jeremy Tan, 20933708 (Sections \ref{Server/Client Communication},\ref{Alternative Communication Technologies},\ref{BeagleBone Configuration})\\ Callum Schofield, 20947475 (Section \ref{Image Processing})\\ James Rosher, 20939143 (Section \ref{Human Computer Interaction and the Graphical User Interface}) \\ Rowan Heinrich, 20939081 (Section \ref{GUI Design Process}) \\ \\ \\ - \includegraphics[width=200px]{figures/uwacrest.pdf} -} -\date{November 2013} + \includegraphics[width=150px]{figures/uwacrest.pdf} \\ \\ \\ + \emph{Supervisor:} Adrian Keating <\href{mailto:adrian.keating@uwa.edu.au}{adrian.keating@uwa.edu.au}> \\ + \emph{Co-Supervisor:} Adam Wittek <\href{mailto:adam.wittek@uwa.edu.au}{adam.wittek@uwa.edu.au}> +} + +\date{November 2013} + \maketitle -\centering +\centering + \end{titlepage} diff --git a/server/Doxyfile b/server/Doxyfile index dc0e696..0d7a9a1 100644 --- a/server/Doxyfile +++ b/server/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NUMBER = # for a project that appears at the top of each page and should give viewer # a quick idea about the purpose of the project. Keep the description short. -PROJECT_BRIEF = Server side software to poll sensors, control actuators, and allow remote access +PROJECT_BRIEF = "Server side software to poll sensors, control actuators, and allow remote access" # With the PROJECT_LOGO tag one can specify an logo or icon that is # included in the documentation. The maximum height of the logo should not diff --git a/server/Makefile b/server/Makefile index 00ed880..10be3ec 100644 --- a/server/Makefile +++ b/server/Makefile @@ -28,6 +28,7 @@ microscope : microscope.o clean : make -C sensors clean + make -C actuators clean $(RM) $(BIN) $(BIN2) $(RM) *.o diff --git a/server/actuator.c b/server/actuator.c index 7473485..7716318 100644 --- a/server/actuator.c +++ b/server/actuator.c @@ -16,8 +16,12 @@ static Actuator g_actuators[ACTUATORS_MAX]; /** * 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) @@ -242,6 +246,7 @@ void Actuator_SetControl(Actuator * a, ActuatorControl * c) * 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) { @@ -275,8 +280,8 @@ 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) { @@ -298,7 +303,7 @@ void Actuator_BeginResponse(FCGIContext * context, Actuator * a, DataFormat form /** * 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) @@ -458,6 +463,11 @@ Actuator * Actuator_Identify(const char * name) 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]); diff --git a/server/bbb_pin.c b/server/bbb_pin.c index bd31365..199706f 100644 --- a/server/bbb_pin.c +++ b/server/bbb_pin.c @@ -334,6 +334,7 @@ void ADC_Unexport(int pin) /** * 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) { diff --git a/server/bbb_pin.h b/server/bbb_pin.h index 658b95a..14bc7eb 100644 --- a/server/bbb_pin.h +++ b/server/bbb_pin.h @@ -31,6 +31,7 @@ extern bool PWM_Set(int pin, bool polarity, long period, long duty); // period a 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, ...); @@ -53,7 +54,7 @@ extern bool GPIO_Read_Stub(bool *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 diff --git a/server/bbb_pin_defines.h b/server/bbb_pin_defines.h index cb77dac..7ccda87 100644 --- a/server/bbb_pin_defines.h +++ b/server/bbb_pin_defines.h @@ -10,7 +10,6 @@ #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 @@ -136,13 +135,16 @@ extern const unsigned char g_pin_index_to_gpio[GPIO_NUM_PINS]; #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 **/ diff --git a/server/common.h b/server/common.h index 0875b34..5eee7cc 100644 --- a/server/common.h +++ b/server/common.h @@ -51,7 +51,7 @@ (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); diff --git a/server/control.c b/server/control.c index f81ea00..280a132 100644 --- a/server/control.c +++ b/server/control.c @@ -11,17 +11,25 @@ #include #include +/** + * 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); @@ -32,19 +40,9 @@ bool DirExists(const char *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) { @@ -260,7 +258,6 @@ const char* Control_SetMode(ControlModes desired_mode, void * arg) /** * 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() { diff --git a/server/control.h b/server/control.h index 0dfdc47..e623033 100644 --- a/server/control.h +++ b/server/control.h @@ -5,6 +5,10 @@ #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, @@ -17,12 +21,12 @@ typedef enum ControlModes { #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(); diff --git a/server/data.c b/server/data.c index 19828bc..38eba83 100644 --- a/server/data.c +++ b/server/data.c @@ -292,7 +292,7 @@ int Data_FindByTime(DataFile * df, double time_stamp, DataPoint * closest) * @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) diff --git a/server/data.h b/server/data.h index 0573c2e..6158abe 100644 --- a/server/data.h +++ b/server/data.h @@ -6,7 +6,8 @@ #ifndef _DATAPOINT_H #define _DATAPOINT_H -#define DATA_BUFSIZ 10 // Size to use for DataPoint buffers (TODO: Optimise) +/** Size to use for DataPoint buffers (TODO: Optimise) **/ +#define DATA_BUFSIZ 10 #include "common.h" @@ -23,8 +24,8 @@ typedef struct /** Enum of output format types for DataPoints **/ typedef enum { - JSON, // JSON data - TSV // Tab seperated vector + JSON, /** JSON data */ + TSV /** Tab seperated vector */ } DataFormat; /** @@ -34,10 +35,10 @@ typedef enum */ 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; @@ -54,7 +55,4 @@ extern double Data_Calibrate(double value, double x[], double y[], int size); 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 diff --git a/server/dilatometer.c b/server/dilatometer.c deleted file mode 100644 index 83cdc4c..0000000 --- a/server/dilatometer.c +++ /dev/null @@ -1,290 +0,0 @@ -/** - * @file dilatometer.c - * @purpose Implementation of dilatometer related functions - */ - -#include "cv.h" -#include "highgui_c.h" -#include "dilatometer.h" -#include - -// 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 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(); -} - diff --git a/server/dilatometer.h b/server/dilatometer.h deleted file mode 100644 index 7bb9447..0000000 --- a/server/dilatometer.h +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @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 - diff --git a/server/fastcgi.c b/server/fastcgi.c index 9ff3acc..6006322 100644 --- a/server/fastcgi.c +++ b/server/fastcgi.c @@ -164,7 +164,6 @@ bool FCGI_LockControl(FCGIContext *context, const char * user_name, UserType use * 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) @@ -386,7 +385,6 @@ void FCGI_BeginJSON(FCGIContext *context, StatusCodes status_code) * 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) { @@ -510,7 +508,7 @@ void FCGI_WriteBinary(void * data, size_t size, size_t num_elem) /** * 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) */ diff --git a/server/fastcgi.h b/server/fastcgi.h index a417a43..09884d1 100644 --- a/server/fastcgi.h +++ b/server/fastcgi.h @@ -35,12 +35,20 @@ typedef enum StatusCodes { #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*/ @@ -66,6 +74,7 @@ typedef struct 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); diff --git a/server/image.c b/server/image.c index dcc122d..0e4ff48 100644 --- a/server/image.c +++ b/server/image.c @@ -8,6 +8,11 @@ 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) { @@ -53,7 +58,7 @@ 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) @@ -97,6 +102,9 @@ void Image_Handler(FCGIContext * context, char * params) return result; } +/** + * Executed on cleanup. Releases the OpenCV Capture structs. + */ void Image_Cleanup() { // Release the capture and IplImage pointers diff --git a/server/image.h b/server/image.h index 8e2cd68..9074e85 100644 --- a/server/image.h +++ b/server/image.h @@ -9,7 +9,7 @@ #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); diff --git a/server/interferometer.c b/server/interferometer.c deleted file mode 100644 index 4861318..0000000 --- a/server/interferometer.c +++ /dev/null @@ -1,288 +0,0 @@ -/** - * @file interferometer.c - * @purpose Implementation of interferometer related functions - */ - -#include "cv.h" -#include "highgui_c.h" -#include "interferometer.h" -#include - -/** 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; - } - -} - - diff --git a/server/interferometer.h b/server/interferometer.h deleted file mode 100644 index f545463..0000000 --- a/server/interferometer.h +++ /dev/null @@ -1,18 +0,0 @@ -/** - * @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 - - - diff --git a/server/intertest.sh b/server/intertest.sh deleted file mode 100755 index f3012ad..0000000 --- a/server/intertest.sh +++ /dev/null @@ -1,15 +0,0 @@ -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" diff --git a/server/microscope.c b/server/microscope.c deleted file mode 100644 index e388073..0000000 --- a/server/microscope.c +++ /dev/null @@ -1,246 +0,0 @@ -/** - * @file microscope.c - * @purpose Implementation of microscope related functions - */ - -#include "cv.h" -#include "highgui_c.h" -#include "microscope.h" -#include - -// 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 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); - -} - diff --git a/server/microscope.h b/server/microscope.h deleted file mode 100644 index ca63b5e..0000000 --- a/server/microscope.h +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @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 - diff --git a/server/pin_test.c b/server/pin_test.c index 77c0ef9..8640a60 100644 --- a/server/pin_test.c +++ b/server/pin_test.c @@ -30,6 +30,12 @@ void Pin_Close() 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; diff --git a/server/sensor.c b/server/sensor.c index 4e8ac7f..3919a19 100644 --- a/server/sensor.c +++ b/server/sensor.c @@ -23,10 +23,8 @@ int g_num_sensors = 0; * @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) @@ -277,7 +275,7 @@ Sensor * Sensor_Identify(const char * name) /** * 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) @@ -300,7 +298,7 @@ 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) @@ -424,6 +422,11 @@ const char * Sensor_GetName(int id) 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]); diff --git a/server/sensor.h b/server/sensor.h index 3de48e0..b2bb63c 100644 --- a/server/sensor.h +++ b/server/sensor.h @@ -80,7 +80,7 @@ extern void Sensor_SetModeAll(ControlModes mode, void * arg); 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 diff --git a/server/stream.c b/server/stream.c deleted file mode 100644 index e1e23c1..0000000 --- a/server/stream.c +++ /dev/null @@ -1,68 +0,0 @@ -#include "cv.h" -#include "highgui_c.h" -#include -#include - -/*------------------------------------------------------------------- - -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); -} - diff --git a/testing/Camera/dilatometer/Readme.md b/testing/Camera/dilatometer/Readme.md new file mode 100644 index 0000000..231dd69 --- /dev/null +++ b/testing/Camera/dilatometer/Readme.md @@ -0,0 +1 @@ +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. diff --git a/testing/Camera/dilatometer/dilatometer.c b/testing/Camera/dilatometer/dilatometer.c new file mode 100644 index 0000000..7a85878 --- /dev/null +++ b/testing/Camera/dilatometer/dilatometer.c @@ -0,0 +1,295 @@ +/** + * @file dilatometer.c + * @purpose Implementation of dilatometer related functions + */ + +#include "cv.h" +#include "highgui_c.h" +#include "dilatometer.h" +#include + +// 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 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(); +} + diff --git a/testing/Camera/dilatometer/dilatometer.h b/testing/Camera/dilatometer/dilatometer.h new file mode 100644 index 0000000..7bb9447 --- /dev/null +++ b/testing/Camera/dilatometer/dilatometer.h @@ -0,0 +1,17 @@ +/** + * @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 + diff --git a/testing/Camera/dilatometer/microscope.c b/testing/Camera/dilatometer/microscope.c new file mode 100644 index 0000000..e388073 --- /dev/null +++ b/testing/Camera/dilatometer/microscope.c @@ -0,0 +1,246 @@ +/** + * @file microscope.c + * @purpose Implementation of microscope related functions + */ + +#include "cv.h" +#include "highgui_c.h" +#include "microscope.h" +#include + +// 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 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); + +} + diff --git a/testing/Camera/dilatometer/microscope.h b/testing/Camera/dilatometer/microscope.h new file mode 100644 index 0000000..ca63b5e --- /dev/null +++ b/testing/Camera/dilatometer/microscope.h @@ -0,0 +1,14 @@ +/** + * @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 + diff --git a/testing/Camera/dilatometer/stream.c b/testing/Camera/dilatometer/stream.c new file mode 100644 index 0000000..e1e23c1 --- /dev/null +++ b/testing/Camera/dilatometer/stream.c @@ -0,0 +1,68 @@ +#include "cv.h" +#include "highgui_c.h" +#include +#include + +/*------------------------------------------------------------------- + +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); +} + diff --git a/testing/interferometer/Readme.md b/testing/interferometer/Readme.md new file mode 100644 index 0000000..1692725 --- /dev/null +++ b/testing/interferometer/Readme.md @@ -0,0 +1 @@ +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. diff --git a/testing/interferometer/interferometer.c b/testing/interferometer/interferometer.c new file mode 100644 index 0000000..4861318 --- /dev/null +++ b/testing/interferometer/interferometer.c @@ -0,0 +1,288 @@ +/** + * @file interferometer.c + * @purpose Implementation of interferometer related functions + */ + +#include "cv.h" +#include "highgui_c.h" +#include "interferometer.h" +#include + +/** 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; + } + +} + + diff --git a/testing/interferometer/interferometer.h b/testing/interferometer/interferometer.h new file mode 100644 index 0000000..f545463 --- /dev/null +++ b/testing/interferometer/interferometer.h @@ -0,0 +1,18 @@ +/** + * @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 + + + diff --git a/testing/interferometer/intertest.sh b/testing/interferometer/intertest.sh new file mode 100755 index 0000000..f3012ad --- /dev/null +++ b/testing/interferometer/intertest.sh @@ -0,0 +1,15 @@ +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"