From e5f75202a0c2aaefc6c0555c685661880054bd0c Mon Sep 17 00:00:00 2001 From: Sam Moore Date: Wed, 9 Oct 2013 10:04:29 +0800 Subject: [PATCH] Various changes Bug fix in Sensor_CheckData (incorrect format ordering caused segfault if a bad value was found) Added in UWA LDAP auth to parameters file (commented out) Presumably someone else edited stream.c and didn't commit (Jeremy?) --- server/fastcgi.c | 2 +- server/login.c | 8 +- server/parameters | 8 +- server/pin_test.c | 4 +- server/run.sh | 2 +- server/sensor.c | 197 ++++++++++++++++++++++++++------------------- server/sensor.h | 26 +++--- server/stream.c | 10 ++- server/valgrind.sh | 3 +- 9 files changed, 156 insertions(+), 104 deletions(-) diff --git a/server/fastcgi.c b/server/fastcgi.c index d3e4b28..3218a58 100644 --- a/server/fastcgi.c +++ b/server/fastcgi.c @@ -511,7 +511,7 @@ void * FCGI_RequestLoop (void *data) { if (cookie[0] == '\0') { - FCGI_RejectJSON(&context, "Please login."); + FCGI_RejectJSONEx(&context, STATUS_UNAUTHORIZED, "Please login."); continue; } diff --git a/server/login.c b/server/login.c index 5e2128f..a2a11e9 100644 --- a/server/login.c +++ b/server/login.c @@ -210,11 +210,13 @@ void Login_Handler(FCGIContext * context, char * params) char dn[BUFSIZ]; // On a simple LDAP server: - int len = sprintf(dn, "uid=%s,%s", user, g_options.ldap_base_dn); + //int len = sprintf(dn, "uid=%s,%s", user, g_options.ldap_base_dn); // At UWA (hooray) - //char * user_type = (user[0] != '0') : "Students" ? "Staff"; - //int len = sprintf(dn, "cn=%s,ou=%s", user, user_type, g_options.ldap_dn_base); + char * user_type = "Students"; + if (user[0] == '0') + user_type = "Staff"; + int len = sprintf(dn, "cn=%s,ou=%s,%s", user, user_type, g_options.ldap_base_dn); if (len >= BUFSIZ) diff --git a/server/parameters b/server/parameters index 9f33848..6ac1bc1 100644 --- a/server/parameters +++ b/server/parameters @@ -20,11 +20,13 @@ verbosity="$LOGDEBUG" pin_test="0" # Set to the URI to use authentication -auth_uri="ldap://192.168.1.1" -#auth_uri="/etc/shadow" +#auth_uri="ldap://192.168.1.1" +#auth_uri="ldaps://ldap.pheme.uwa.edu.au" #UWA +auth_uri="/etc/shadow" # Set to the dn of the LDAP server -ldap_base_dn="ou=People,dc=daedalus" +#ldap_base_dn="ou=People,dc=daedalus" # Testing +ldap_base_dn="ou=Users,ou=UWA,dc=uwads,dc=uwa,dc=edu,dc=au" #UWA ## OPTIONS TO BE PASSED TO SERVER; DO NOT EDIT diff --git a/server/pin_test.c b/server/pin_test.c index b22cc13..9893072 100644 --- a/server/pin_test.c +++ b/server/pin_test.c @@ -27,7 +27,7 @@ void Pin_Close() ADC_Unexport(i); for (int i = 0; i < PWM_NUM_PINS; ++i) - PWM_Unexport(g_pin_safe_pwm[i]); + PWM_Unexport(i); } bool Pin_Configure(const char *type, int pin_export, int num) @@ -212,4 +212,4 @@ void Pin_Handler(FCGIContext *context, char * params) FCGI_RejectJSON(context, "Invalid pin type"); } -} \ No newline at end of file +} diff --git a/server/run.sh b/server/run.sh index d4e6510..0e52fd9 100755 --- a/server/run.sh +++ b/server/run.sh @@ -84,7 +84,7 @@ echo "Parameters are: $parameters" # TODO: Can tell spawn-fcgi to run the program as an unprivelaged user? # But first will have to work out how to set PWM/GPIO as unprivelaged user fails=0 -while [ $fails -lt 10 ]; do +while [ $fails -lt 1 ]; do spawn-fcgi -p9005 -n -- ./server $parameters error=$? if [ "$error" == "0" ]; then diff --git a/server/sensor.c b/server/sensor.c index bfa8b66..cc942e3 100644 --- a/server/sensor.c +++ b/server/sensor.c @@ -16,22 +16,28 @@ static Sensor g_sensors[NUMSENSORS]; //global to this file /** Array of sensor threshold structures defining the safety values of each sensor**/ const SensorThreshold thresholds[NUMSENSORS]= { //Max Safety, Min safety, Max warning, Min warning - {1,-1,1,-1}, // ANALOG_TEST0 - {500,0,499,0}, // ANALOG_TEST1 - {5000,0,5000,0}, // ANALOG_REALTEST - {5,-5,4,-4}, // ANALOG_FAIL0 - {1,0,1,0}, // DIGITAL_TEST0 - {1,0,1,0}, // DIGITAL_TEST1 - {1,0,1,0}, // DIGITAL_REALTEST - {1,0,1,0} // DIGITAL_FAIL0 + {5000,0,5000,0}, + {5000,0,5000,0}, + {5000,0,5000,0}, + {5000,0,5000,0}, + {5000,0,5000,0}, + {5000,0,5000,0}, + {5000,0,5000,0}, + {5000,0,5000,0}, + {1, 1, 1, 1} }; /** Human readable names for the sensors **/ const char * g_sensor_names[NUMSENSORS] = { - "analog_test0", "analog_test1", - "analog_realtest", "analog_fail0", - "digital_test0", "digital_test1", - "digital_realtest", "digital_fail0" + "strain0", + "strain1", + "strain2", + "strain3", + "pressure0", + "pressure1", + "pressure_feedback", + "microphone", + "enclosure" }; /** @@ -45,13 +51,27 @@ void Sensor_Init() Data_Init(&(g_sensors[i].data_file)); } - // Get the required ADCs - ADC_Export(0); - // GPIO1_28 used as a pulse for sampling - //GPIO_Export(GPIO1_28); - // GPIO0_30 toggled during sampling - //GPIO_Export(GPIO0_30); + + // Get the required ADCs + ADC_Export(ADC0); // Strain gauges x 4 + ADC_Export(ADC1); // Pressure sensor 1 + ADC_Export(ADC2); // Pressure sensor 2 + // ADC3 still unused (!?) + ADC_Export(ADC4); // Pressure regulator feedback(?) signal + ADC_Export(ADC5); // Microphone + + // Get GPIO pins //TODO: Confirm pins used with Electronics Team + GPIO_Export(GPIO0_30); // Mux A (strain 1) + GPIO_Set(GPIO0_30, false); + GPIO_Export(GPIO1_28); // Mux B (strain 2) + GPIO_Set(GPIO1_28, false); + GPIO_Export(GPIO0_31); // Mux C (strain 3) + GPIO_Set(GPIO0_31, false); + GPIO_Export(GPIO1_16); // Mux D (strain 4) + GPIO_Set(GPIO1_16, false); + + GPIO_Export(GPIO0_31); // Enclosure switch } /** @@ -144,13 +164,13 @@ void Sensor_CheckData(SensorId id, double value) { if( value > thresholds[id].max_error || value < thresholds[id].min_error) { - Log(LOGERR, "Sensor %s at %f is above or below its safety value of %f or %f\n", value, g_sensor_names[id],thresholds[id].max_error, thresholds[id].min_error); + Log(LOGERR, "Sensor %s at %f is above or below its safety value of %f or %f\n", g_sensor_names[id],value, thresholds[id].max_error, thresholds[id].min_error); //new function that stops actuators? //Control_SetMode(CONTROL_EMERGENCY, NULL) } else if( value > thresholds[id].max_warn || value < thresholds[id].min_warn) { - Log(LOGWARN, "Sensor %s at %f is above or below its warning value of %f or %f\n", value, g_sensor_names[id],thresholds[id].max_warn, thresholds[id].min_warn); + Log(LOGWARN, "Sensor %s at %f is above or below its warning value of %f or %f\n", g_sensor_names[id],value,thresholds[id].max_warn, thresholds[id].min_warn); } } @@ -164,83 +184,89 @@ void Sensor_CheckData(SensorId id, double value) bool Sensor_Read(Sensor * s, DataPoint * d) { + + + static bool result = true; + + //TODO: Remove this, code should be refactored to not use so many threads + // Although... if it works, it works... + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + + pthread_mutex_lock(&mutex); //TODO: Reduce the critical section + + usleep(10); + // Set time stamp struct timeval t; gettimeofday(&t, NULL); - d->time_stamp = TIMEVAL_DIFF(t, *Control_GetStartTime()); - - static bool result = true; - + d->time_stamp = TIMEVAL_DIFF(t, *Control_GetStartTime()); // Read value based on Sensor Id + int value; bool success = true; + //TODO: Can probably do this nicer than a switch (define a function pointer for each sensor) + // Can probably make the whole sensor thing a lot nicer with a linked list of sensors... + // (Then to add more sensors to the software, someone just writes an appropriate read function and calls Sensor_Add(...) at init) + // (I will do this. Don't do it before I get a chance, I don't trust you :P) switch (s->id) { - case 2: - { - static bool set = false; - int raw_adc = 0; - //GPIO_Set(GPIO0_30, true); - ADC_Read(ADC0, &raw_adc); - d->value = (double)raw_adc; //ADC #0 on the Beaglebone - //Log(LOGDEBUG, "Got value %f from ADC0", d->value); - //GPIO_Set(GPIO0_30, false); - set = !set; - //GPIO_Set(GPIO1_28, set); - - usleep(100000); - - break; - } - - default: - d->value = rand() % 2; - usleep(1000000); + //TODO: Strain gauges should have their own critical section, rest of sensors probably don't need to be in a critical section + case STRAIN0: + success &= GPIO_Set(GPIO0_30, true); + success &= ADC_Read(ADC0); + success &= GPIO_Set(GPIO0_30, false); + if (!success) + Fatal("Error reading strain gauge 0"); break; - - - case ANALOG_TEST0: - { - d->value = (double)(rand() % 100) / 100; + case STRAIN1: + success &= GPIO_Set(GPIO1_28, true); + success &= ADC_Read(ADC0); + success &= GPIO_Set(GPIO1_28, false); + if (!success) + Fatal("Error reading strain gauge 1"); break; - } - case ANALOG_TEST1: - { - static int count = 0; - count %= 500; - d->value = count++; + case STRAIN2: + success &= GPIO_Set(GPIO0_31, true); + success &= ADC_Read(ADC0); + success &= GPIO_Set(GPIO0_31, false); + case STRAIN3: + success &= GPIO_Set(GPIO1_16, true); + success &= ADC_Read(ADC0); + success &= GPIO_Set(GPIO1_16, false); + if (!success) + Fatal("Error reading strain gauge 2"); + break; + case PRESSURE0: + success &= ADC_Read(ADC1, &value); break; - } - - case ANALOG_FAIL0: - d->value = 0; - //d->value = (double)(rand() % 6) * -( rand() % 2) / ( rand() % 100 + 1); - //Gives a value between -5 and 5 + case PRESSURE1: + success &= ADC_Read(ADC5, &value); break; - case DIGITAL_TEST0: - d->value = t.tv_sec % 2; - + case PRESSURE_FEEDBACK: + success &= ADC_Read(ADC4, &value); break; - case DIGITAL_TEST1: - d->value = (t.tv_sec+1)%2; + case MICROPHONE: + success &= ADC_Read(ADC2, &value); break; - case DIGITAL_REALTEST: + case ENCLOSURE: { - d->value = 0; //d->value must be something... valgrind... - // Can pass pin as argument, just using 20 as an example here - // Although since pins will be fixed, can just define it here if we need to - //d->value = pinRead(20); //Pin 20 on the Beaglebone + bool why_do_i_need_to_do_this = false; + success &= GPIO_Read(GPIO0_31, &why_do_i_need_to_do_this); + value = (int)why_do_i_need_to_do_this; break; } - case DIGITAL_FAIL0: - if( rand() % 100 > 98) - d->value = 2; - d->value = rand() % 2; - //Gives 0 or 1 or a 2 every 1/100 times + case DILATOMETER: + { + // Will definitely cause issues included in the same critical section as ADC reads + // (since it will be the longest sensor to sample, everything else will have to keep waiting on it) + value = 0; break; - //default: - // Fatal("Unknown sensor id: %d", s->id); - // break; + } + } + + d->value = (double)(value); //TODO: Calibration? Or do calibration in GUI + + pthread_mutex_unlock(&mutex); //TODO: Reduce the critical section // Perform sanity check based on Sensor's ID and the DataPoint @@ -256,9 +282,18 @@ bool Sensor_Read(Sensor * s, DataPoint * d) #ifdef _BBB //Not all cases have usleep, easiest here. - usleep(1000000); + //TODO: May want to add a control option to adjust the sampling rate for each sensor? + // Also, we can get a more accurate sampling rate if instead of a fixed sleep, we calculate how long to sleep each time. + usleep(100000); #endif - return result; + + /* + if (success) + Log(LOGDEBUG, "Successfully read sensor %d (for once)", s->id); + else + Log(LOGDEBUG, "Failed to read sensor %d (again)", s->id); + */ + return result && success; } /** diff --git a/server/sensor.h b/server/sensor.h index 182d8ae..2e7bf4a 100644 --- a/server/sensor.h +++ b/server/sensor.h @@ -8,22 +8,28 @@ #include "data.h" + + /** Number of sensors **/ -#define NUMSENSORS 8 +#define NUMSENSORS 10 /** Sensor ids - there should be correspondence with the names in g_sensor_names **/ typedef enum SensorId { - ANALOG_TEST0, - ANALOG_TEST1, - ANALOG_REALTEST, - ANALOG_FAIL0, - DIGITAL_TEST0, - DIGITAL_TEST1, - DIGITAL_REALTEST, - DIGITAL_FAIL0 + STRAIN0, + STRAIN1, + STRAIN2, + STRAIN3, + PRESSURE0, + PRESSURE1, + PRESSURE_FEEDBACK, + MICROPHONE, + ENCLOSURE. + DILATOMETER } SensorId; + + /** Human readable names for the sensors **/ extern const char * g_sensor_names[NUMSENSORS]; @@ -40,6 +46,8 @@ typedef struct pthread_t thread; /** Most recently recorded data **/ DataPoint newest_data; + + } Sensor; // Structure to define the warning and error thresholds of the sensors diff --git a/server/stream.c b/server/stream.c index 5fa6150..e1e23c1 100644 --- a/server/stream.c +++ b/server/stream.c @@ -25,8 +25,8 @@ int storeFrame( CvCapture* capture) frame = cvQueryFrame(capture); if( frame == NULL) return 0; //error - //cvSaveImage("../web/images/test.JPG",frame,p); - jpg = cvEncodeImage(".jpg", frame,p); + 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); @@ -35,7 +35,7 @@ int storeFrame( CvCapture* capture) //cvWaitKey(0); cvReleaseImageHeader(&frame); - cvReleaseMat(&jpg); + //cvReleaseMat(&jpg); //fclose( fp); return 1; } @@ -51,10 +51,14 @@ int main (int argc, char** argv) 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?) } diff --git a/server/valgrind.sh b/server/valgrind.sh index e5214bd..fc5c8d3 100755 --- a/server/valgrind.sh +++ b/server/valgrind.sh @@ -1,2 +1,3 @@ #!/bin/bash -valgrind --leak-check=full --show-reachable=yes ./server +. parameters +valgrind ./server $parameters -- 2.20.1