From: Jeremy Tan Date: Sun, 22 Sep 2013 00:43:17 +0000 (+0800) Subject: Merge branch 'master' of https://github.com/szmoore/MCTX3420.git X-Git-Url: https://git.ucc.asn.au/?p=matches%2FMCTX3420.git;a=commitdiff_plain;h=b7150f722995ea6807182da24653a15693a82698;hp=55e0e3688d07568f988b295239f3673a16c5cc9e Merge branch 'master' of https://github.com/szmoore/MCTX3420.git --- diff --git a/BBB code/Actuator_SetValue_real.c b/BBB code/Actuator_SetValue_real.c index e83020a..fe5e3c5 100644 --- a/BBB code/Actuator_SetValue_real.c +++ b/BBB code/Actuator_SetValue_real.c @@ -1,13 +1,14 @@ #include "pwm.h" char pin_dir = "/sys/class/gpio/gpio"; //move these -int pwm_active = 0; /** Sets a GPIO pin to the desired value * @param value - the value (1 or 0) to write to the pin * @param pin_num - the number of the pin (refer to electronics team) */ +//also need to export and set pin direction + void SetPin(int value, int pin_num) { int pin; char buffer[10]; diff --git a/BBB code/Actuator_SetValue_real2.c b/BBB code/Actuator_SetValue_real2.c new file mode 100644 index 0000000..791de1e --- /dev/null +++ b/BBB code/Actuator_SetValue_real2.c @@ -0,0 +1,55 @@ +#include "gpio.h" +#include "pwm.h" + +void Actuator_SetValue(Actuator * a, double value) +{ + // Set time stamp + struct timeval t; + gettimeofday(&t, NULL); + + DataPoint d = {TIMEVAL_DIFF(t, g_options.start_time), value}; + switch (a->id) + { + case ACTUATOR_TEST0: //LED actuator test code, should blink onboard LED next to Ethernet port + FILE *LEDHandle = NULL; //code reference: http://learnbuildshare.wordpress.com/2013/05/19/beaglebone-black-controlling-user-leds-using-c/ + char *LEDBrightness = "/sys/class/leds/beaglebone\:green\:usr0/brightness"; + if(value == 1) { + if((LEDHandle = fopen(LEDBrightness, "r+")) != NULL) { + fwrite("1", sizeof(char), 1, LEDHandle); + fclose(LEDHandle); + } + else if(value == 0) { + if((LEDHandle = fopen(LEDBrightness, "r+")) != NULL) { + fwrite("0", sizeof(char), 1, LEDHandle); + fclose(LEDHandle); + } + else perror("Pin value should be 1 or 0"); + break; + case ACTUATOR_TEST1: + // Quick actuator function for testing pins + // GPIOPin can be either passed as an argument, or defined here (as pins won't change) + // First way is better and more generalised + int GPIOPin = 13; + // Modify this to only export on first run, unexport on shutdown + pinExport(setValue, GPIOString); + pinDirection(GPIODirection, setValue); + pinSet(value, GPIOValue, setValue); + pinUnexport(setValue, GPIOString); + break; + case ACTUATOR_TEST2: + if (pwminit == 0) { //if inactive, start the pwm module + pwm_init(); + } + if (pwmstart == 0) { + pwm_start(); + pwm_set_period(FREQ); //50Hz defined in pwm header file + } + if(value >= 0 && value <= 1000) { + double duty = value/1000 * 100; //convert pressure to duty percentage + pwm_set_duty((int)duty); //set duty percentage for actuator + } + } + Log(LOGDEBUG, "Actuator %s set to %f", g_actuator_names[a->id], value); + // Record the value + Data_Save(&(a->data_file), &d, 1); +} \ No newline at end of file diff --git a/BBB code/GetData_real.c b/BBB code/GetData_real.c index f52427c..c724e62 100644 --- a/BBB code/GetData_real.c +++ b/BBB code/GetData_real.c @@ -1,64 +1,4 @@ -char adc_dir = "/sys/devices/platform/tsc/ain"; -char pin_dir = "/sys/class/gpio/gpio"; - -/** Open an ADC and return the voltage value from it -* @param adc_num - ADC number, ranges from 0 to 7 on the Beaglebone - @return the converted voltage value if successful -*/ - -//TODO: create a function to lookup the ADC or pin number instead of manually -// specifying it here (so we can keep all the numbers in one place) - -int OpenAnalog(int adc_num) -{ - char adc_path[40]; - snprintf(adc_path, sizeof(adc_path), "%s%d", adc_dir, adc_num); //construct ADC path - int sensor = open(adc_path, O_RDONLY); - char buffer[128]; //I think ADCs are only 12 bits (0-4096) - int read = read(sensor, buffer, sizeof(buffer); //buffer can probably be smaller - if (read != -1) { - buffer[read] = NULL; - int value = atoi(buffer); - double convert = (value/4096) * 1000; //random conversion factor, will be different for each sensor - //lseek(sensor, 0, 0); - close(sensor); - return convert; - } - else { - perror("Failed to get value from sensor"); - close(sensor); - return -1; - } -} - -/** Open a digital pin and return the value from it -* @param pin_num - pin number, specified by electronics team - @return 1 or 0 if reading was successful -*/ - -int OpenDigital(int pin_num) -{ - char pin_path[40]; - snprintf(pin_path, sizeof(pin_path), "%s%d%s", pin_dir, pin_num, "/value"); //construct pin path - int pin = open(pin_path, O_RDONLY); - char ch; - lseek(fd, 0, SEEK_SET); - int read = read(pin, &ch, sizeof(ch); - if (read != -1) { - if (ch != '0') { - close(pin); - return 1; - } - else { - close(pin); - return 0; - } - else { - perror("Failed to get value from pin"); - close(pin); - return -1; - } -} +#include "gpio.h" /** * Read a DataPoint from a Sensor; block until value is read @@ -78,11 +18,11 @@ bool Sensor_Read(Sensor * s, DataPoint * d) switch (s->id) { case ANALOG_TEST0: - d->value = OpenAnalog(0); //ADC #0 on the Beaglebone + d->value = ADCRead(0); //ADC #0 on the Beaglebone break; case ANALOG_TEST1: { - d->value = OpenAnalog(1); + d->value = ADCRead(1); break; } case ANALOG_FAIL0: @@ -90,10 +30,10 @@ bool Sensor_Read(Sensor * s, DataPoint * d) //Gives a value between -5 and 5 break; case DIGITAL_TEST0: - d->value = openDigital(0); //replace 0 with correct pin number + d->value = pinRead(0); //replace 0 with correct pin number break; case DIGITAL_TEST1: - d->value = openDigital(1); //replace 1 with correct pin number + d->value = pinRead(1); //replace 1 with correct pin number break; case DIGITAL_FAIL0: if( rand() % 100 > 98) diff --git a/BBB code/gpio.c b/BBB code/gpio.c new file mode 100644 index 0000000..65f1a51 --- /dev/null +++ b/BBB code/gpio.c @@ -0,0 +1,128 @@ +#include "gpio.h" + +void pinExport(int GPIOPin) { + FILE *myOutputHandle = NULL; + char GPIOString[4]; + char setValue[4]; + sprintf(GPIOString, "%d", GPIOPin); + if ((myOutputHandle = fopen(exportPath, "ab")) == NULL){ + Log(LOGERR, "Unable to export GPIO pin %f\n", GPIOPin); + } + strcpy(setValue, GPIOString); + fwrite(&setValue, sizeof(char), 2, myOutputHandle); + fclose(myOutputHandle); +} + +void pinDirection(int GPIOPin, int io) { + char setValue[4]; + char GPIODirection[64]; + FILE *myOutputHandle = NULL; + snprintf(GPIODirection, sizeof(GPIODirection), "%s%d%s", directionPath, GPIOPin, "/direction"); + if ((myOutputHandle = fopen(GPIODirection, "rb+")) == NULL){ + Log(LOGERR, "Unable to open direction handle for pin %f\n", GPIOPin); + } + if (io == 1) { + strcpy(setValue,"out"); + fwrite(&setValue, sizeof(char), 3, myOutputHandle); + else if (io == 0) { + strcpy(setValue,"in"); + fwrite(&setValue, sizeof(char), 2, myOutputHandle); + else Log(LOGERR, "GPIO direction must be 1 or 0\n"); + fclose(myOutputHandle); +} + +void pinSet(double value, int GPIOPin) { + int val = (int)value; + char GPIOValue[64]; + char setValue[4]; + FILE *myOutputHandle = NULL; + snprintf(GPIOValue, sizeof(GPIOValue), "%s%d%s", valuePath, GPIOPin, "/value"); + if (val == 1) { + if ((myOutputHandle = fopen(GPIOValue, "rb+")) == NULL){ + Log(LOGERR, "Unable to open value handle for pin %f\n", GPIOPin); + } + strcpy(setValue, "1"); // Set value high + fwrite(&setValue, sizeof(char), 1, myOutputHandle); + } + else if (val == 0){ + if ((myOutputHandle = fopen(GPIOValue, "rb+")) == NULL){ + Log(LOGERR, "Unable to open value handle for pin %f\n", GPIOPin); + } + strcpy(setValue, "0"); // Set value low + fwrite(&setValue, sizeof(char), 1, myOutputHandle); + } + else Log(LOGERR, "GPIO value must be 1 or 0\n"); + fclose(myOutputHandle); +} + +/** Open an ADC and return the voltage value from it +* @param adc_num - ADC number, ranges from 0 to 7 on the Beaglebone + @return the converted voltage value if successful +*/ + +//TODO: create a function to lookup the ADC or pin number instead of manually +// specifying it here (so we can keep all the numbers in one place) + +int ADCRead(int adc_num) +{ + char adc_path[64]; + snprintf(adc_path, sizeof(adc_path), "%s%d", ADCPath, adc_num); // Construct ADC path + int sensor = open(adc_path, O_RDONLY); + char buffer[64]; // I think ADCs are only 12 bits (0-4096), buffer can probably be smaller + int read = read(sensor, buffer, sizeof(buffer); + if (read != -1) { + buffer[read] = NULL; + int value = atoi(buffer); + double convert = (value/4096) * 1000; // Random conversion factor, will be different for each sensor (get from datasheets) + // lseek(sensor, 0, 0); (I think this is uneeded as we are reopening the file on each sensor read; if sensor is read continously we'll need this + close(sensor); + return convert; + } + else { + Log(LOGERR, "Failed to get value from ADC %f\n", adc_num); + close(sensor); + return -1; + } +} + +/** Open a digital pin and return the value from it +* @param pin_num - pin number, specified by electronics team + @return 1 or 0 if reading was successful +*/ + +int pinRead(int GPIOPin) +{ + char GPIOValue[64]; + snprintf(GPIOValue, sizeof(GPIOValue), "%s%d%s", valuePath, GPIOPin, "/value"); //construct pin path + int pin = open(GPIOValue, O_RDONLY); + char ch; + lseek(fd, 0, SEEK_SET); + int read = read(pin, &ch, sizeof(ch); + if (read != -1) { + if (ch != '0') { + close(pin); + return 1; + } + else { + close(pin); + return 0; + } + else { + Log(LOGERR, "Failed to get value from pin %f\n", GPIOPin); + close(pin); + return -1; + } +} + +void pinUnexport(int GPIOPin) { + char setValue[4]; + char GPIOString[4]; + sprintf(GPIOString, "%d", GPIOPin); + FILE *myOutputHandle = NULL; + if ((myOutputHandle = fopen(unexportPath, "ab")) == NULL) { + Log(LOGERR, "Couldn't unexport GPIO pin %f\n", GPIOPin); + } + strcpy(setValue, GPIOString); + fwrite(&setValue, sizeof(char), 2, myOutputHandle); + fclose(myOutputHandle); +} \ No newline at end of file diff --git a/BBB code/gpio.h b/BBB code/gpio.h new file mode 100644 index 0000000..1da8470 --- /dev/null +++ b/BBB code/gpio.h @@ -0,0 +1,24 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define exportPath "/sys/class/gpio/export"; +#define unexportPath "/sys/class/gpio/unexport"; +#define valuePath "/sys/class/gpio/gpio"; +#define directionPath "/sys/class/gpio/gpio"; +#define ADCPath "/sys/devices/platform/tsc/ain"; + +void pinExport(int GPIOPin); +void pinDirection(int GPIOPin, int io); +void pinSet(double value, int GPIOPin); +void pinUnexport(int GPIOPin); +int pinRead(int GPIOPin); +int ADCRead(int adc_num); \ No newline at end of file diff --git a/BBB code/pwm.c b/BBB code/pwm.c index b58873e..b86b07e 100644 --- a/BBB code/pwm.c +++ b/BBB code/pwm.c @@ -11,8 +11,10 @@ can modify pwm variables through virtual filesystem: pwm drivers reference: http://processors.wiki.ti.com/index.php/AM335x_PWM_Driver%27s_Guide */ -void pwm_init(void) -{ +static int pwminit = 0; +static int pwmstart = 0; + +void pwm_init(void) { FILE *pwm_mux; int i; volatile uint32_t *epwmss1; @@ -36,8 +38,8 @@ void pwm_init(void) epwmss1[OFFSET_1 / sizeof(uint32_t)] = 0x2; } close(fd); - - pwm_mux = fopen("/sys/kernel/debug/omap_mux/gpmc_a2", "w"); + pwminit = 1; + pwm_mux = fopen(PWMMuxPath, "w"); fprintf(pwm_mux, "6"); // pwm is mux mode 6 fclose(pwm_mux); } @@ -46,41 +48,36 @@ void pwm_init(void) //depends how many pwm modules we have to run //TODO: -void pwm_start(void) -{ +void pwm_start(void) { FILE *pwm_run; - pwm_run = fopen("/sys/class/pwm/ehrpwm.1:0/run", "w"); + pwm_run = fopen(PWMRunPath, "w"); fprintf(pwm_run, "1"); fclose(pwm_run); + pwmstart = 1; } -void pwm_stop(void) -{ +void pwm_stop(void) { FILE *pwm_run; - - pwm_run = fopen("/sys/class/pwm/ehrpwm.1:0/run", "w"); + pwm_run = fopen(PWMRunPath, "w"); fprintf(pwm_run, "0"); fclose(pwm_run); + pwmstart = 0; } //duty_percent is just a regular percentage (i.e. 50 = 50%) -void pwm_set_duty(int duty_percent) -{ +void pwm_set_duty(int duty_percent) { FILE *pwm_duty; - - pwm_duty = fopen("/sys/class/pwm/ehrpwm.1:0/duty_percent", "w"); + pwm_duty = fopen(PWMDutyPath, "w"); fprintf(pwm_duty, "%d", duty_percent); fclose(pwm_duty); } //freq is just normal frequency (i.e. 100 = 100Hz) -void pwm_set_period(int freq) -{ +void pwm_set_period(int freq) { FILE *pwm_period; - - pwm_period = fopen("/sys/class/pwm/ehrpwm.1:0/period_freq", "w"); + pwm_period = fopen(PWMFreqPath, "w"); fprintf(pwm_period, "%d", freq); fclose(pwm_period); } \ No newline at end of file diff --git a/BBB code/pwm.h b/BBB code/pwm.h index 605095f..2c9411b 100644 --- a/BBB code/pwm.h +++ b/BBB code/pwm.h @@ -10,10 +10,14 @@ #include #include -#define START 0x44e00000 // see datasheet of AM335x -#define LENGTH 1024 -#define OFFSET_1 0xcc // offset of PWM1 clock (see datasheet of AM335x p.1018) -#define FREQ 50 //50Hz pwm frequency for pressure regulator +#define START 0x44e00000 // see datasheet of AM335x +#define LENGTH 1024 +#define OFFSET_1 0xcc // offset of PWM1 clock (see datasheet of AM335x p.1018) +#define FREQ 50 //50Hz pwm frequency for pressure regulator +#define PWMMuxPath "/sys/kernel/debug/omap_mux/gpmc_a2" +#define PWMRunPath "/sys/class/pwm/ehrpwm.1:0/run" +#define PWMDutyPath "/sys/class/pwm/ehrpwm.1:0/duty_percent" +#define PWMFreqPath "/sys/class/pwm/ehrpwm.1:0/period_freq" void pwm_init(void); void pwm_start(void); diff --git a/irc/log b/irc/log index 87b7345..1370d76 100644 --- a/irc/log +++ b/irc/log @@ -2699,3 +2699,415 @@ 20:00 -!- MctxBot [~twang@203-59-42-232.dyn.iinet.net.au] has quit [Ping timeout] 21:26 -!- MctxBot [~twang@203-59-42-232.dyn.iinet.net.au] has joined #mctxuwa_softdev 22:58 -!- jtanx [~asfa@203-59-42-232.dyn.iinet.net.au] has quit ["ChatZilla 0.9.90.1 [Firefox 23.0.1/20130814063812]"] +--- Day changed Tue Sep 17 2013 +08:14 -!- jtanx [~asfa@130.95.101.14] has joined #mctxuwa_softdev +09:50 -!- jtanx [~asfa@130.95.101.14] has quit ["ChatZilla 0.9.90.1 [Firefox 23.0.1/20130814063812]"] +15:34 -!- jtanx [~asfa@203-59-42-232.dyn.iinet.net.au] has joined #mctxuwa_softdev +15:34 < jtanx> to run the software not as root, we need to at least add it to the 'video' group so it can access the webcam +15:34 < jtanx> not sure about the sensors +15:34 < jtanx> eg sudo usermod -a -G video debian +15:38 < sam_moore> Ah, cool +15:39 < sam_moore> I think I worked out how to get around the camera crashing without killing the rest of the program, won't implement it for a while though +15:40 -!- MctxBot [~twang@203-59-42-232.dyn.iinet.net.au] has quit [EOF From client] +15:43 -!- jtanx_ [~asfa@220-253-203-124.dyn.iinet.net.au] has joined #mctxuwa_softdev +15:48 -!- MctxBot [~twang@220-253-203-124.dyn.iinet.net.au] has joined #mctxuwa_softdev +15:53 -!- jtanx [~asfa@203-59-42-232.dyn.iinet.net.au] has quit [Ping timeout] +15:57 -!- jtanx_ is now known as jtanx +16:41 -!- jtanx [~asfa@220-253-203-124.dyn.iinet.net.au] has quit [Ping timeout] +16:46 -!- jtanx_ [~asfa@220-253-203-124.dyn.iinet.net.au] has joined #mctxuwa_softdev +16:46 -!- jtanx_ is now known as jtanx +18:02 -!- jtanx [~asfa@220-253-203-124.dyn.iinet.net.au] has quit ["ChatZilla 0.9.90.1 [Firefox 23.0.1/20130814063812]"] +18:16 -!- jtanx [~asfa@220-253-203-124.dyn.iinet.net.au] has joined #mctxuwa_softdev +19:31 -!- MctxBot [~twang@220-253-203-124.dyn.iinet.net.au] has quit [Ping timeout] +22:38 -!- MctxBot [~twang@220-253-203-124.dyn.iinet.net.au] has joined #mctxuwa_softdev +22:49 -!- jtanx [~asfa@220-253-203-124.dyn.iinet.net.au] has quit [Ping timeout] +23:17 -!- Callum [~chatzilla@124-169-175-15.dyn.iinet.net.au] has joined #mctxuwa_softdev +23:18 < Callum> hey +23:23 < sam_moore> Hi +23:24 < Callum> do you know how to do the second question of that assignment? +23:24 < Callum> https://docs.google.com/file/d/0B241H5liqVlnbHZETXRZX1Mwd1k/edit?usp=sharing +23:25 < Callum> rather remember +23:35 < sam_moore> Well, you can eliminate any epsilon^2 when you substitute those formulae for v into the formula for gamma +23:35 < sam_moore> Then it has a really simple taylor expansion +23:35 < Callum> i might have to hunt you down tomorrow to show me. or maybe il be able to think straight tomorrow. +23:38 < sam_moore> You can express one of the epsilons in terms of the other one after that +23:40 < sam_moore> I'm pretty busy tomorrow +23:42 < Callum> mhmm. so no free time at all? coz im fairly free +23:49 < sam_moore> Not from 8:00am until 5:00pm +23:49 < Callum> ohwow. you are busy +23:49 < Callum> im still unsure what im meant to be applyign the taylor expansion to +23:53 < sam_moore> Substitute in the suggested formulae to gamma, simplify it, then apply a taylor expansion +23:53 < sam_moore> Anyway, goodnight, good luck +23:53 < Callum> night +--- Day changed Wed Sep 18 2013 +00:07 -!- Callum [~chatzilla@124-169-175-15.dyn.iinet.net.au] has quit [EOF From client] +07:50 -!- jtanx [~asfa@220-253-203-124.dyn.iinet.net.au] has joined #mctxuwa_softdev +09:11 -!- jtanx [~asfa@220-253-203-124.dyn.iinet.net.au] has quit ["ChatZilla 0.9.90.1 [Firefox 23.0.1/20130814063812]"] +18:50 -!- jtanx [~asfa@220-253-203-124.dyn.iinet.net.au] has joined #mctxuwa_softdev +19:04 -!- MctxBot [~twang@220-253-203-124.dyn.iinet.net.au] has quit [Ping timeout] +21:03 -!- jtanx [~asfa@220-253-203-124.dyn.iinet.net.au] has quit ["ChatZilla 0.9.90.1 [Firefox 24.0/20130910160258]"] +21:39 -!- MctxBot [~twang@220-253-203-124.dyn.iinet.net.au] has joined #mctxuwa_softdev +--- Day changed Thu Sep 19 2013 +16:07 -!- jtanx [~asfa@220-253-203-124.dyn.iinet.net.au] has joined #mctxuwa_softdev +16:08 < jtanx> one thing I forgot to mention - the latest version on git uses syslog +16:08 < jtanx> if you copy the config file (server-configs/rsyslog.d/* ??) to /etc/ +16:09 < jtanx> it will log to /var/log/mctx[something I can't remember].log +16:10 < jtanx> i'm pretty sure you can also create a log file specifically for warning level and above (so it logs in three places, stderr, the normal log, and a special 'error' log), but I haven't set this up yet +18:15 -!- MctxBot_ [~twang@220-253-203-242.dyn.iinet.net.au] has joined #mctxuwa_softdev +18:17 -!- jtanx_ [~asfa@220-253-203-242.dyn.iinet.net.au] has joined #mctxuwa_softdev +18:17 < jtanx_> :0 +18:22 < sam_moore> ? +18:30 -!- MctxBot [~twang@220-253-203-124.dyn.iinet.net.au] has quit [Ping timeout] +18:31 -!- jtanx [~asfa@220-253-203-124.dyn.iinet.net.au] has quit [Ping timeout] +18:50 -!- jtanx_ is now known as jtanx +19:11 -!- jtanx [~asfa@220-253-203-242.dyn.iinet.net.au] has quit [Ping timeout] +19:51 -!- jtanx [~asfa@220-253-203-242.dyn.iinet.net.au] has joined #mctxuwa_softdev +19:52 -!- MctxBot_ is now known as MctxBot +20:24 < jtanx> I got the camera image to be updated in javascript instead: http://mctx.us.to:8080/test/ +20:25 < jtanx> right now it's updated around every ~400ms because my webcam is running through a usb1.1 link which seriously limits how fast it can update +20:36 < jtanx> (its running on a pentium 3 computer) +21:35 -!- jtanx [~asfa@220-253-203-242.dyn.iinet.net.au] has quit ["ChatZilla 0.9.90.1 [Firefox 24.0/20130910160258]"] +--- Day changed Fri Sep 20 2013 +15:38 -!- jtanx [~asfa@220-253-203-242.dyn.iinet.net.au] has joined #mctxuwa_softdev +15:53 -!- MctxBot [~twang@220-253-203-242.dyn.iinet.net.au] has quit [Ping timeout] +18:02 < jtanx> this seems like an interesting option, at least for the cam that just shows the can explode:http://sourceforge.net/apps/mediawiki/mjpg-streamer/index.php?title=Main_Page +18:51 < sam_moore> Cool +18:51 < sam_moore> It, ah +18:52 < sam_moore> Looks like we might have to recompile the kernel to get PWM working +18:52 < sam_moore> Hooray +18:52 < sam_moore> Kernel compiling +18:52 < sam_moore> What could possibly go wrong? +19:02 < jtanx> really?? +19:02 < jtanx> why.... +19:03 < jtanx> no am33xx_pwm module? +19:04 < sam_moore> Not that I can tell +19:05 < jtanx> well crap +19:06 < sam_moore> Well... surely I can find a precompiled kernel somewhere +19:06 < jtanx> it seems that stuff for the BBB is at a really premature stage +19:07 < sam_moore> Yeah, RPi is much nicer +19:07 < jtanx> the BBB is just too new.. +19:07 < sam_moore> What's the point of having fancy things like ADC and PWM... +19:07 < sam_moore> If you can't actually use them without jumping through hoops +19:07 < jtanx> hahaha +19:07 < jtanx> were you referencing this, when you said we might have to recompile the kernel? https://groups.google.com/d/msg/beagleboard/wjbOVE6ItNg/AGYVRhYbTX8J +19:08 < sam_moore> Yeah +19:08 < sam_moore> ... +19:08 < sam_moore> I wonder if I can take the kernel used by Angstrom and stick it in /boot +19:08 < sam_moore> on the SD card +19:09 < jtanx> ._. +19:10 < jtanx> what about kernels from here +19:10 < jtanx> http://rcn-ee.net/deb/precise-armhf/ +19:10 < jtanx> sorry +19:10 < jtanx> http://rcn-ee.net/deb/wheezy-armhf/ +19:11 < jtanx> what's it currently running +19:12 < sam_moore> 3.8.13-bone20 +19:13 < sam_moore> Try 3.8.13-bone28 ? +19:15 < jtanx> what about v3.8.9-bone15 +19:15 < jtanx> oh wait +19:15 < jtanx> ~.~ +19:15 < sam_moore> I wonder why the BBB developers didn't go with debian... +19:15 < jtanx> v3.11.0-bone5 +19:15 < jtanx> yeah +19:15 < jtanx> why angstrom, of all things +19:15 < sam_moore> Is angstrom used anywhere else? +19:16 < jtanx> dunno +19:16 < sam_moore> Other embedded devices, heh +19:16 < sam_moore> Everyone just has to use their own distro :P +19:17 < sam_moore> I didn't see the .11 kernels, I'll try the latest one +19:17 < jtanx> want to try the rc version? lol +19:18 < jtanx> oh the rc versions are older than .11 +19:19 < jtanx> how does it work? +19:19 < jtanx> do you just download from http://rcn-ee.net/deb/wheezy-armhf/v3.11.0-bone5/ +19:19 < jtanx> the .sh script and run it from the BBB? +19:24 < sam_moore> I think so +19:25 < sam_moore> Well... here goes nothing +19:26 < sam_moore> Hopefully between 3.8 and 3.11 they actually enabled PWM by default... +19:27 < sam_moore> It looks like install-me.sh downloads all the .deb files appropriately +19:29 < sam_moore> It's creating files like: /lib/firmware/bone_pwm_P8_36-00 +19:29 < sam_moore> Which looks promising +19:29 < sam_moore> Snoopy is not yet on fire +19:29 < sam_moore> Which is promising +19:29 < sam_moore> Rebooting and praying +19:31 < sam_moore> And... it booted into 3.8.13-bone20 -_- +19:31 < sam_moore> Tempted to just symlink that filename to the new kernel +19:34 < sam_moore> The new kernel exists in /boot, but obviously there's some boot config that needs to get set +19:39 < sam_moore> Ok, screw this, I'm making a symlink just to see if it works +19:40 < jtanx> lol +19:41 < jtanx> no grub +19:43 < jtanx> did update-initramfs run? +19:46 < jtanx> or maybe we need mkimage +19:47 < jtanx> yeah probably need mkimage +19:50 < sam_moore> Um, zImage is a symlink to the kernel +19:50 < sam_moore> But regardless, the new one won't boot +19:50 < sam_moore> Such a pain +19:50 < sam_moore> I wonder if we can just toggle the GPIO pin fast enough to implement PWM +19:56 < sam_moore> Using a decent oscilloscope, I read a 6us period when switching GPIO1_28 on/off as fast as possible +19:59 < sam_moore> That +19:59 < sam_moore> s like 166KHz +19:59 < sam_moore> Heh +19:59 < sam_moore> Maybe the sources you found were closing the file and reopening it? +20:01 < sam_moore> Yeah, wow +20:02 < sam_moore> Using fopen, fprintf and fclose each time takes the period to 224us +20:02 < sam_moore> Or 4KHz +20:03 < sam_moore> Also for future reference, that CRO in G19 is definitely broken; it's always a lovely square wave on the modern oscilloscope I'm testing with now +20:12 < jtanx> haha ok +20:13 < jtanx> but without kernel support your pwm signal won't be very accurate +20:13 < sam_moore> Yeah, I suppose +20:13 < jtanx> how come the new kernel won't boot? +20:14 < sam_moore> No idea +20:14 < jtanx> Hmm +20:14 < jtanx> this lack of documentation on how you do such procedures is pretty crap +20:15 < sam_moore> Yeah, kernel developers aren't great on documentation +20:15 < jtanx> is the mkimage package present? +20:15 < jtanx> if not, install it and try running the install-me script again +20:16 < jtanx> from this: http://www.jeremycole.com/blog/2011/03/09/beagleboard-upgrading-from-debian-5-to-debian-6/ +20:16 < jtanx> it should be just running that install script and rebooting +20:16 < sam_moore> Alright, uboot-mkimage I presume? +20:16 < jtanx> i guess +20:17 < jtanx> and update-initramfs? +20:18 < jtanx> (just looking at what the install-me.sh script uses) +20:18 < sam_moore> Oh, does the script not fail if packages it needs don't exist... +20:18 < sam_moore> -_- +20:19 < jtanx> a quick scan says nup +20:24 < sam_moore> Already had initramfs-tools but not mkimage, so I'll try again +20:27 < sam_moore> I should probably have focused on the ADC reading before PWM +20:27 < sam_moore> We're definitely going to get asked about aliasing again +20:28 < jtanx> urgh yeah +20:28 < sam_moore> I don't have a signal generator here though +20:28 < jtanx> this BBB has definitely not been designed with 'plug n play' in mind +20:28 < sam_moore> Mmm +20:29 < sam_moore> The Angstrom image would work for this stuff, but obviously has limitations in terms of the webserver stuff +20:29 < sam_moore> But even with Angstrom you still have to go through a similar convoluted process to control pins +20:30 < sam_moore> From what I can tell there are two ways to do it +20:30 < sam_moore> SYSFS, which I can't find much documentation on +20:30 < sam_moore> Which is the /sys/class/gpio/ stuff +20:30 < sam_moore> Which actually seems more intuitive than the other way +20:31 < sam_moore> That involves echoing a bunch of cruft to /sys/devices/cape-manager/slots/ or something similar +20:31 < jtanx> hmm +20:32 < sam_moore> There is a /sys/class/pwm +20:32 < sam_moore> But unfortunately whatever you export it complains about +20:32 < sam_moore> Probably because the kernel wasn't compiled with it enabled +20:32 < jtanx> is this with the old kernel? +20:32 < sam_moore> Yeah +20:33 < sam_moore> Hangon, the new one's probably finished building by now +20:34 < jtanx> we don't know if the new one has been compiled with pwm support though +20:34 < sam_moore> Yeah +20:36 < sam_moore> The diff between the config options for the kernels shows that the old one has a comment "CONFIG_EHRPWM_TEST is not set" and the newer one has no reference to it +20:37 < sam_moore> ... +20:37 < sam_moore> Someone at some point +20:37 < sam_moore> Has realised that PWM was not enabled +20:37 < sam_moore> And commented that it isn't enabled +20:37 < sam_moore> WHY THE HELL DIDN'T THEY JUST ENABLE IT +20:37 < jtanx> :P +20:37 < sam_moore> Anyway it still booted off the old kernel +20:37 < sam_moore> Dinner time +20:38 < jtanx> ok +20:57 -!- MctxBot [~twang@220-253-203-242.dyn.iinet.net.au] has joined #mctxuwa_softdev +21:15 < sam_moore> http://www.eewiki.net/display/linuxonarm/BeagleBone+Black#BeagleBoneBlack-LinuxKernel +21:15 < sam_moore> Looks promising +21:16 < sam_moore> Hmm... +21:17 < sam_moore> I'll try using 3.8 but building with the PWM +21:18 < jtanx> building from source - fun fun :P +21:19 < sam_moore> Well in theory I just change a config option +21:19 < jtanx> yeah +21:19 < sam_moore> When that doesn't work and I have to modify the source, that's when the fun begins +21:19 < jtanx> let's just hope it works +21:19 < sam_moore> Yeah, if it doesn't we're (beagle) boned +21:19 < jtanx> oh while you're at it, figure out how to enable the ethernet-over-usb feature +21:19 < sam_moore> Haha +21:20 < jtanx> loljk +21:25 < sam_moore> Hmmm... compiling a kernel is going to take a while +21:26 < sam_moore> Ergh, why am I running it on this Pentium D +21:30 < sam_moore> Hmmm, more troubling... why does a debian wheezy server have OpenSUSE sources in sources.list +21:30 < sam_moore> Oh well, not my problem +21:33 < jtanx> heh +21:33 < sam_moore> How the hell are we going to explain this in the progress report... +21:34 < sam_moore> Also, I didn't fully understand, why can't you use the same image for multiple BBB? +21:34 < sam_moore> Are we going to have to do this all again for the other BBB? +21:34 < sam_moore> Spike I mean +21:37 < jtanx> no idea +21:38 < jtanx> without some sort of debugging cable to see what happens when it boots, who knows +21:38 < sam_moore> :S +21:39 < sam_moore> I love how git gets to the head of the branch +21:39 < sam_moore> By starting at the initial commit +21:39 < sam_moore> And going through every commit and changing the file +21:42 < sam_moore> It hasn't started building yet +21:42 < sam_moore> And the way you customise the build... +21:42 < sam_moore> Is to build it with the defaults, so that the options file exists, then change the options, then build it again -_- +21:43 < jtanx> ಠ ಠ +21:43 < sam_moore> Oh well, I have to go home, I'll try finish this tomorrow +21:43 < sam_moore> Bye +21:43 < jtanx> ok +21:43 < jtanx> bye +23:20 -!- jtanx [~asfa@220-253-203-242.dyn.iinet.net.au] has quit ["ChatZilla 0.9.90.1 [Firefox 24.0/20130910160258]"] +--- Day changed Sat Sep 21 2013 +08:42 -!- jtanx [~asfa@220-253-203-242.dyn.iinet.net.au] has joined #mctxuwa_softdev +11:23 < sam_moore> http://hipstercircuits.com/enable-pwm-on-beaglebone-with-device-tree-overlays/ +11:23 < sam_moore> So... according to this I should add pwm_test as a kernel module +11:24 < sam_moore> "This is it. It is now three o’clock in the morning and I have not slept or eaten in two days. My neck is sore, my ass has fallen asleep and my organs are screaming “slow down, man”. I no longer see [CC]s, [LD]s and [AS]s, I only see blondes, brunettes and redheads flashing before my eyes. With my last ounce of energy I barely manage to type in “reboot” as my face hits the keyboard. And that is when it happens.." +11:25 < sam_moore> Ummm +11:25 < sam_moore> It's awesome that this guy has solved the problem (I think) +11:26 < sam_moore> But a bit depressing that it still isn't in the official kernel +11:29 < sam_moore> I think most people just give up and use Angstrom, which is tempting +11:30 < sam_moore> I still have that HTTP server code... :P +11:45 < sam_moore> Looks like Robert C Nelson's 3.8 kernel does have a pwm_test module +11:45 < sam_moore> Maybe the image you used just had an out of date kernel? +11:45 -!- Irssi: #mctxuwa_softdev: Total of 3 nicks [0 ops, 0 halfops, 0 voices, 3 normal] +11:51 < jtanx> hmm +11:51 < jtanx> no idea +11:51 < jtanx> it was made in july I think and it uses those rcn kernels +11:51 < jtanx> We could always use lighttp +11:51 < jtanx> lighttpd on angstrom if necessary +11:52 < jtanx> lighttpd and install mod_fastcgi +11:55 < jtanx> ok so the image uses 3.8.13-bone20, so maybe it wasn't enabled in that version, but it now is in 3.8.13-bone28? +12:02 < sam_moore> I've just built 3.8.13-bone28 and the module pwm_test exists +12:03 < sam_moore> ... I also copied the code from that guy's blog as pwm_test2 just in case :P +12:03 < sam_moore> I'll have to test it later, but at least we have the kernel module +12:08 < jtanx> nice +12:39 < jtanx> ohhhhh I know why it didn't work from one bbb to the next, using the same image +12:39 < jtanx> When you boot for the first time, it assigns the ethernet port eth0 +12:39 < jtanx> when you then take it out and boot it on a different BBB +12:40 < jtanx> because the ethernet device has a different id, it gets assigned to say eth1 +12:40 < jtanx> and because you don't have any config for eth1 in your network config, there's no internet access +12:40 < jtanx> http://www.eewiki.net/display/linuxonarm/BeagleBone#BeagleBone-Networking:UsingasharedSDcardwithMultipleBeagleBone +12:41 < jtanx> should fix that +13:21 -!- jtanx [~asfa@220-253-203-242.dyn.iinet.net.au] has left #mctxuwa_softdev [] +13:21 -!- jtanx [~asfa@220-253-203-242.dyn.iinet.net.au] has joined #mctxuwa_softdev +15:10 < jtanx> Eh, you know what I'll just stop the threads when you want to pause it +15:10 < jtanx> instead of conditionals +15:11 < jtanx> it's not like you're pausing the experiment that often +15:18 < sam_moore> That's fine +15:19 < sam_moore> The conditional approach is only really necessary if you're constantly pausing the threads +15:19 < sam_moore> I used it for an nbody simulator, so the computation of force and position was split up between threads +15:19 < sam_moore> It's really slow if you have to stop and then recreate the threads on every step +15:22 < sam_moore> Although still actually faster than the single threaded program +15:22 < sam_moore> Well, depending on how many objects you simulated +15:23 < sam_moore> Anyway, just stop the threads, it's simpler to code and the performance effect in our case is probably negligable +15:30 < jtanx> yeah +15:30 < jtanx> say you had an actuator that was being controlled at that instant when an 'emergency stop' was issued +15:31 < jtanx> since an 'emergency stop' is the same as just pausing (eg stopping the thread but keep DataFile open) +15:31 < jtanx> you'd have to wait for that action to be completed before the 'emergency stop' would be propagated +15:34 < jtanx> welp I guess that's why there's hardware safety interlocks +15:38 < jtanx> Also, technically wouldn't it be possible to try to set the actuator value before the current value has been set +15:38 < jtanx> Since there's no queue +15:39 < jtanx> a->control could be overwritten by a new request as Actuator_SetValue operates +16:12 < sam_moore> We want that right? +16:13 < sam_moore> I'll look at it later if I get time +16:14 < jtanx> I don't know if we want that or not +16:15 < jtanx> wait want as in the current behaviour or the behaviour with a queue? +16:16 < sam_moore> The current behaviour +16:16 < sam_moore> I don't think you need a queue +16:16 < sam_moore> You can extend the critical section in Actuator_Loop to stop the current control getting overwritten +16:17 < sam_moore> Move the pthread_mutex_unlock on line 121 to below line 127 (Actuator_SetValue) +16:17 < sam_moore> That way if Actuator_SetControl is called before the value has been successfully set, it will just wait +16:17 < sam_moore> Mutexes actually implement a queue +16:18 < sam_moore> If one thread has a lock on the mutex, subsequent threads that try to access the mutex will queue up; whenever the mutex is unlocked the next thread (if any) which was waiting will get it +16:18 < jtanx> ok +16:23 < jtanx> I'll leave it as is for now +16:23 < sam_moore> Sure +16:49 < sam_moore> PWM working +16:49 < jtanx> nice +16:50 < jtanx> I still don't really understand - did you compile the kernel from scratch +16:50 < jtanx> or did you figure out how to use the install-me.sh script +16:50 < sam_moore> I did, but I didn't need to modify it +16:50 < jtanx> huh +16:50 < jtanx> ok +16:51 < sam_moore> http://www.eewiki.net/display/linuxonarm/BeagleBone+Black#BeagleBoneBlack-LinuxKernel +16:52 < jtanx> so if we do this: http://www.eewiki.net/display/linuxonarm/BeagleBone+Black#BeagleBoneBlack-Networking:UsingasharedSDcardwithMultipleBeagleBone +16:52 < jtanx> We should be able to just copy our image +16:52 < jtanx> and stick it on the electronics' BBB +16:53 < sam_moore> Sounds good +16:53 < sam_moore> I'm glad that worked +16:53 < jtanx> yeah +16:54 < jtanx> I wonder if it also enabled the usb0 stuff (ethernet over usb) +16:58 < sam_moore> PWM appears to have picosecond resolution? Or at least the arguments are in ps +17:02 < jtanx> oO +17:11 < sam_moore> ADC can sample at ~4KHz +17:11 < sam_moore> But... that's using bash +17:11 < sam_moore> It will probably be massively fast when done in C +17:11 < jtanx> um +17:11 < jtanx> is there any need to have it sample at a consistent rate +17:11 < jtanx> as in, with threads there's no guarantee +17:12 < jtanx> of a consistent sampling rate +17:12 < sam_moore> Yes, you're right +17:13 < sam_moore> I don't think we can achieve a consistent sampling rate, but I don't think it's critical that we do +17:14 < sam_moore> As soon as we make our software run in an operating system with a kernel and other processes that can run as well, it gets pretty unfeasable to have a constant sample rate +17:14 < sam_moore> We can have it constant to within an uncertainty I guess +17:15 < jtanx> yeah, true +17:18 < sam_moore> If you wanted a really high constant sample rate (say much faster than 1us which is probably the best case we could get) you'd have to use a more low level embedded device +17:18 < sam_moore> Well I guess you could compile your own kernel for the BBB +17:19 < sam_moore> But either way you'd have to physically run the webserver/GUI interface stuff on a seperate device +17:19 < sam_moore> At this stage my feeling is what we have is good enough given the complexity of all the requirements we were given +17:23 < jtanx> yeah +17:25 < sam_moore> Hmm, I can set some GPIO pins to toggle whenever Sensor_Read is called and get an idea of sample rates and to what degree of accuracy we can quote the time stamps +17:26 < sam_moore> I think I'll write some pin control code +17:26 < sam_moore> I don't trust any of these custom libraries +17:29 < jtanx> custom libraries? +17:36 < sam_moore> Well they aren't really libraries +17:36 < sam_moore> http://www.avrfreaks.net/wiki/index.php/Documentation:Linux/GPIO#Example_of_GPIO_access_from_within_a_C_program +17:37 < sam_moore> Eg: That one has an fopen and fclose each time the value is changed +17:38 < sam_moore> I could google until I find someone that has already written a C library, but chances are it will be slow or broken +17:38 < sam_moore> Since I've worked out how to control the pins I may as well just write the C code to do it +17:39 < jtanx> yep +17:49 < sam_moore> I wonder if I can do this with a macro... +18:30 < sam_moore> Ergh, screw that +18:31 < sam_moore> Ok, I'm going to implement things like: GPIO/ADC/PWM_Export/Unexport to initialise or deinitialise all pins +18:31 < jtanx> Ok +18:31 < jtanx> too much effort with macros? +18:31 < sam_moore> Yeah, +18:32 < sam_moore> I was thinking of having something like "GPIOX_Set()" instead of GPIO_Set(int x)" +18:32 < sam_moore> But that's probably not as nice as I thought it was +18:32 < sam_moore> Anyway, there's an enum in the header file that contains the id of all pins used +18:32 < sam_moore> The implementation defines some structs that wrap around the file descriptors +18:33 < sam_moore> But to use the module you just give it an ID as defined in the enums +18:33 < jtanx> Makes sense +18:33 < jtanx> designing the gui is actually not too bad +18:33 < sam_moore> That's good +18:34 < jtanx> looks ok in ie8 too +18:34 < sam_moore> Nice +18:35 < jtanx> gotta go, dinner +18:35 < sam_moore> Ok +18:35 < sam_moore> Hmm, it would be nice if C had value checking on enums +18:35 < sam_moore> You can define a function that takes an enum type as an argument +18:36 < sam_moore> But people can still just pass any old integer +18:36 < sam_moore> As far as I know +18:36 < sam_moore> eg: typedef enum {FIRST=1, SECOND=10, THIRD=100} EnumType +18:36 < sam_moore> void Foo(EnumType e); +18:37 < sam_moore> If you go Foo(2) it won't complain +18:38 < sam_moore> Annoying +18:38 < sam_moore> That seems like something the compiler would be able to pick up +19:31 < sam_moore> Ergh, I'm getting too obsessive compulsive with this pin thing +19:35 < sam_moore> It's annoying because ADC, GPIO and PWM are treated completely differently +19:35 < sam_moore> You write one thing and it enables *all* the ADCs +19:35 < sam_moore> You have to enable each GPIO pin individually +19:36 < sam_moore> And to enable PWM pins you give a string (not just an integer) +19:37 < sam_moore> Also the location of the pin files is not guaranteed (though it probably doesn't change for a given system configuration) +19:39 < sam_moore> Ah, I found a way to enable pwm with /sys/class/ instead of that cape manager thing +19:39 < sam_moore> I think I'll use that, since at least it's consistent with the GPIO stuff +19:41 < sam_moore> Ooh! +19:41 < sam_moore> http://beagleboard-gsoc13.blogspot.com.au/2013/07/sampling-analogue-signals-using-adc-on.html +19:41 < sam_moore> Provides a driver for continuously sampling with the ADC +19:41 < sam_moore> Oh wait +19:41 < sam_moore> Crap in a bucket +19:42 < sam_moore> Because we're using those multiplexers we can't do that +19:42 < sam_moore> We have to set the multiplexer before each sample +19:42 < sam_moore> Oh well, never mind +19:44 < sam_moore> I suppose we could write our own kernel module :S +19:45 < sam_moore> I think I understand this enough to talk to Adam next time he tries to talk about sample rate +19:46 < sam_moore> 1. It's not actually constant, but we can probably have it constant to within a few us +19:46 < sam_moore> 2. To make it constant would require writing a kernel module +19:47 < sam_moore> Unless electronics stops being stingy and gets one amplifier per channel :P +20:22 < jtanx> hehehe +20:22 < jtanx> next week's adrian though +20:22 < sam_moore> Ah +20:23 < jtanx> grilling time +20:23 < sam_moore> He'll probably ask us the same things :P +20:23 < jtanx> yeah +20:23 < jtanx> but man, so much stuff to go through just to get some readings from a few pins +20:24 < jtanx> so good job with that :P +20:54 < sam_moore> Thanks +22:45 -!- jtanx [~asfa@220-253-203-242.dyn.iinet.net.au] has quit ["ChatZilla 0.9.90.1 [Firefox 24.0/20130910160258]"] +--- Day changed Sun Sep 22 2013 +00:51 < sam_moore> Hell yes +00:51 < sam_moore> PWM controlled through web browser +00:51 < sam_moore> GPIO controlled through web browser diff --git a/server/Makefile b/server/Makefile index 3838876..1302544 100644 --- a/server/Makefile +++ b/server/Makefile @@ -2,7 +2,7 @@ CXX = gcc FLAGS = -std=c99 -Wall -pedantic -g -I/usr/include/opencv -I/usr/include/opencv2/highgui -L/usr/lib LIB = -lfcgi -lssl -lcrypto -lpthread -lm -lopencv_highgui -lopencv_core -lopencv_ml -lopencv_imgproc -OBJ = log.o control.o data.o fastcgi.o main.o sensor.o actuator.o image.o +OBJ = log.o control.o data.o fastcgi.o main.o sensor.o actuator.o image.o bbb_pin.o RM = rm -f BIN = server @@ -10,12 +10,6 @@ BIN = server all : $(BIN) $(BIN2) -stream : stream.c - $(CXX) $(FLAGS) -o stream stream.c $(LIB) - -intertest : interferometer.c - $(CXX) $(FLAGS) -o intertest interferometer.c $(LIB) - $(BIN) : $(OBJ) $(CXX) $(FLAGS) -o $(BIN) $(OBJ) $(LIB) diff --git a/server/actuator.c b/server/actuator.c index c71b05a..f5d7cd6 100644 --- a/server/actuator.c +++ b/server/actuator.c @@ -5,13 +5,16 @@ #include "actuator.h" #include "options.h" +// Files containing GPIO and PWM definitions +#include "bbb_pin.h" + /** Array of Actuators (global to this file) initialised by Actuator_Init **/ static Actuator g_actuators[NUMACTUATORS]; /** Human readable names for the Actuators **/ const char * g_actuator_names[NUMACTUATORS] = { - "actuator_test0", "actuator_test1" + "actuator_test0", "gpio1_16", "EHRPWM0A_duty@60Hz" }; /** @@ -25,6 +28,11 @@ void Actuator_Init() Data_Init(&(g_actuators[i].data_file)); pthread_mutex_init(&(g_actuators[i].mutex), NULL); } + + // Initialise pins used + GPIO_Export(GPIO1_16); + PWM_Export(EHRPWM0A); + } /** @@ -172,6 +180,7 @@ void Actuator_SetValue(Actuator * a, double value) { case ACTUATOR_TEST0: { + // Onboard LEDs test actuator FILE *led_handle = NULL; //code reference: http://learnbuildshare.wordpress.com/2013/05/19/beaglebone-black-controlling-user-leds-using-c/ const char *led_format = "/sys/class/leds/beaglebone:green:usr%d/brightness"; char buf[50]; @@ -194,7 +203,15 @@ void Actuator_SetValue(Actuator * a, double value) } break; case ACTUATOR_TEST1: + GPIO_Set(GPIO1_16, (bool)(value)); break; + case ACTUATOR_TEST2: + { + // PWM analogue actuator (currently generates one PWM signal with first PWM module) + static long freq = 16666666; // This is 60Hz + PWM_Set(EHRPWM0A, true, freq, value * freq); // Set the duty cycle + break; + } } Log(LOGDEBUG, "Actuator %s set to %f", g_actuator_names[a->id], value); @@ -217,6 +234,7 @@ void Actuator_BeginResponse(FCGIContext * context, ActuatorId id, DataFormat for case JSON: FCGI_BeginJSON(context, STATUS_OK); FCGI_JSONLong("id", id); + FCGI_JSONPair("name", g_actuator_names[id]); break; default: FCGI_PrintRaw("Content-type: text/plain\r\n\r\n"); diff --git a/server/actuator.h b/server/actuator.h index ee0ed32..48e0f29 100644 --- a/server/actuator.h +++ b/server/actuator.h @@ -14,13 +14,14 @@ // Might be OK in C++ but not easy in C /** Number of actuators **/ -#define NUMACTUATORS 2 +#define NUMACTUATORS 3 /** List of actuator ids (should be of size NUMACTUATORS) **/ typedef enum { ACTUATOR_TEST0, - ACTUATOR_TEST1 + ACTUATOR_TEST1, + ACTUATOR_TEST2 } ActuatorId; /** Human readable names for the Actuators **/ diff --git a/server/bbb_pin.c b/server/bbb_pin.c new file mode 100644 index 0000000..f8ba011 --- /dev/null +++ b/server/bbb_pin.c @@ -0,0 +1,326 @@ +/** + * @file bbb_pin.c + * @purpose Implementation of BBB pin control functions and structures + * THIS CODE IS NOT THREADSAFE + */ + +#include "bbb_pin.h" + +#include +#include +#include + +/** + * Structure to represent a GPIO pin + * Note: Only accessable to this file; to use the functions pass a GPIOId + */ +typedef struct +{ + int fd_value; + int fd_direction; +} GPIO_Pin; + +/** + * Structure to represent an ADC pin + * Note: Only accessable to this file; to use the functions pass a ADCId + */ +typedef struct +{ + FILE * file_value; +} ADC_Pin; + +/** + * Structure to represent a PWM pin + * Note: Only accessable to this file; to use the functions pass a PWMId + */ +typedef struct +{ + int fd_run; + FILE * file_duty; + FILE * file_period; + int fd_polarity; +} PWM_Pin; + +/** Array of GPIO pins **/ +static GPIO_Pin g_gpio[GPIO_NUM_PINS] = {{0}}; +/** Array of ADC pins **/ +static ADC_Pin g_adc[ADC_NUM_PINS] = {{0}}; +/** Array of PWM pins **/ +static PWM_Pin g_pwm[PWM_NUM_PINS] = {{0}}; + +static char g_buffer[BUFSIZ] = ""; + + + + +/** + * Export a GPIO pin and open the file descriptors + */ +void GPIO_Export(int pin) +{ + if (pin < 0 || pin > GPIO_NUM_PINS) + Fatal("Invalid pin number %d", pin); + + + + // Export the pin + sprintf(g_buffer, "%s/export", GPIO_DEVICE_PATH); + FILE * export = fopen(g_buffer, "w"); + if (export == NULL) + Fatal("Couldn't open %s to export GPIO pin %d - %s", g_buffer, pin, strerror(errno)); + + fprintf(export, "%d", pin); + fclose(export); + + // Setup direction file descriptor + sprintf(g_buffer, "%s/gpio%d/direction", GPIO_DEVICE_PATH, pin); + g_gpio[pin].fd_direction = open(g_buffer, O_RDWR); + if (g_gpio[pin].fd_direction < 0) + Fatal("Couldn't open %s for GPIO pin %d - %s", g_buffer, pin, strerror(errno)); + + + // Setup value file descriptor + sprintf(g_buffer, "%s/gpio%d/value", GPIO_DEVICE_PATH, pin); + g_gpio[pin].fd_value = open(g_buffer, O_RDWR); + if (g_gpio[pin].fd_value < 0) + Fatal("Couldn't open %s for GPIO pin %d - %s", g_buffer, pin, strerror(errno)); +} + +/** + * Unexport a GPIO pin and close its' file descriptors + */ +void GPIO_Unexport(int pin) +{ + + if (pin < 0 || pin > GPIO_NUM_PINS) + Fatal("Invalid pin number %d", pin); + + // Close file descriptors + close(g_gpio[pin].fd_value); + close(g_gpio[pin].fd_direction); + + // Unexport the pin + + if (g_buffer[0] == '\0') + sprintf(g_buffer, "%s/unexport", GPIO_DEVICE_PATH); + FILE * export = fopen(g_buffer, "w"); + if (export == NULL) + Fatal("Couldn't open %s to export GPIO pin %d - %s", g_buffer, pin, strerror(errno)); + + fprintf(export, "%d", pin); + fclose(export); +} + + + + +/** + * Export all PWM pins and open file descriptors + * @param pin - The pin number + */ +void PWM_Export(int pin) +{ + if (pin < 0 || pin > PWM_NUM_PINS) + Fatal("Invalid pin number %d", pin); + + // Export the pin + sprintf(g_buffer, "%s/export", PWM_DEVICE_PATH); + FILE * export = fopen(g_buffer, "w"); + if (export == NULL) + Fatal("Couldn't open %s to export PWM pin %d - %s", g_buffer, pin, strerror(errno)); + + fprintf(export, "%d", pin); + fclose(export); + + // Open file descriptors + sprintf(g_buffer, "%s/pwm%d/run", PWM_DEVICE_PATH, pin); + g_pwm[pin].fd_run = open(g_buffer, O_WRONLY); + if (g_pwm[pin].fd_run < 0) + Fatal("Couldn't open %s for PWM pin %d - %s", g_buffer, pin, strerror(errno)); + + sprintf(g_buffer, "%s/pwm%d/polarity",PWM_DEVICE_PATH, pin); + g_pwm[pin].fd_polarity = open(g_buffer, O_WRONLY); + if (g_pwm[pin].fd_polarity < 0) + Fatal("Couldn't open %s for PWM pin %d - %s", g_buffer, pin, strerror(errno)); + + sprintf(g_buffer, "%s/pwm%d/period_ns",PWM_DEVICE_PATH, pin); + g_pwm[pin].file_period = fopen(g_buffer, "w"); + if (g_pwm[pin].file_period == NULL) + Fatal("Couldn't open %s for PWM pin %d - %s", g_buffer, pin, strerror(errno)); + + sprintf(g_buffer, "%s/pwm%d/duty_ns",PWM_DEVICE_PATH, pin); + g_pwm[pin].file_duty = fopen(g_buffer, "w"); + if (g_pwm[pin].file_duty == NULL) + Fatal("Couldn't open %s for PWM pin %d - %s", g_buffer, pin, strerror(errno)); + + // Don't buffer the streams + setbuf(g_pwm[pin].file_period, NULL); + setbuf(g_pwm[pin].file_duty, NULL); + + +} + +/** + * Unexport a PWM pin and close its file descriptors + * @param pin - The pin number + */ +void PWM_Unexport(int pin) +{ + if (pin < 0 || pin > PWM_NUM_PINS) + Fatal("Invalid pin number %d", pin); + + // Close the file descriptors + close(g_pwm[pin].fd_polarity); + close(g_pwm[pin].fd_run); + fclose(g_pwm[pin].file_period); + fclose(g_pwm[pin].file_duty); + + //Unexport the pin + sprintf(g_buffer, "%s/unexport", PWM_DEVICE_PATH); + FILE * export = fopen(g_buffer, "w"); + if (export == NULL) + Fatal("Couldn't open %s to unexport PWM pin %d - %s", g_buffer, pin, strerror(errno)); + + fprintf(export, "%d", pin); + fclose(export); + + +} + +/** + * Export ADC pins; http://beaglebone.cameon.net/home/reading-the-analog-inputs-adc + * Can't use sysfs like GPIO or PWM pins + * Bloody annoying how inconsistent stuff is on the Beaglebone + */ +void ADC_Export() +{ + + FILE * export = fopen(ADC_EXPORT_PATH, "w"); + if (export == NULL) + Fatal("Couldn't open %s to export ADCs - %s", ADC_EXPORT_PATH, strerror(errno)); + + fprintf(export, "cape-bone-iio"); + fclose(export); + + for (int i = 0; i < ADC_NUM_PINS; ++i) + { + sprintf(g_buffer, "%s/AIN%d", ADC_DEVICE_PATH, i); + g_adc[i].file_value = fopen(g_buffer, "r"); + if (g_adc[i].file_value == NULL) + Fatal("Couldn't open ADC %d device file %s - %s", i, g_buffer, strerror(errno)); + + setbuf(g_adc[i].file_value, NULL); + + } +} + +/** + * Unexport ADC pins + */ +void ADC_Unexport() +{ + for (int i = 0; i < ADC_NUM_PINS; ++i) + fclose(g_adc[i].file_value); +} + +/** + * Set a GPIO pin + * @param pin - The pin to set. MUST have been exported before calling this function. + */ +void GPIO_Set(int pin, bool value) +{ + if (pwrite(g_gpio[pin].fd_direction, "out", 3*sizeof(char), 0) != 3) + Fatal("Couldn't set GPIO %d direction - %s", pin, strerror(errno)); + + char c = '0' + (value); + if (pwrite(g_gpio[pin].fd_value, &c, 1*sizeof(char), 0) != 1) + Fatal("Couldn't read GPIO %d value - %s", pin, strerror(errno)); + +} + +/** + * Read from a GPIO Pin + * @param pin - The pin to read + */ +bool GPIO_Read(int pin) +{ + if (pwrite(g_gpio[pin].fd_direction, "in", 2*sizeof(char), 0) != 2) + Fatal("Couldn't set GPIO %d direction - %s", pin, strerror(errno)); + char c = '0'; + if (pread(g_gpio[pin].fd_value, &c, 1*sizeof(char), 0) != 1) + Fatal("Couldn't read GPIO %d value - %s", pin, strerror(errno)); + + return (c == '1'); + +} + +/** + * Activate a PWM pin + * @param pin - The pin to activate + * @param polarity - if true, pin is active high, else active low + * @param period - The period in ns + * @param duty - The time the pin is active in ns + */ +void PWM_Set(int pin, bool polarity, long period, long duty) +{ + // Have to stop PWM before changing it + if (pwrite(g_pwm[pin].fd_run, "0", 1*sizeof(char), 0) != 1) + Fatal("Couldn't stop PWM %d - %s", pin, strerror(errno)); + + char c = '0' + polarity; + if (pwrite(g_pwm[pin].fd_polarity, &c, 1*sizeof(char), 0) != 1) + Fatal("Couldn't set PWM %d polarity - %s", pin, strerror(errno)); + + + rewind(g_pwm[pin].file_period); + rewind(g_pwm[pin].file_duty); + + if (fprintf(g_pwm[pin].file_duty, "%lu", duty) == 0) + Fatal("Couldn't set duty cycle for PWM %d - %s", pin, strerror(errno)); + + if (fprintf(g_pwm[pin].file_period, "%lu", period) == 0) + Fatal("Couldn't set period for PWM %d - %s", pin, strerror(errno)); + + if (pwrite(g_pwm[pin].fd_run, "1", 1*sizeof(char), 0) != 1) + Fatal("Couldn't start PWM %d - %s", pin, strerror(errno)); + +} + +/** + * Deactivate a PWM pin + * @param pin - The pin to turn off + */ +void PWM_Stop(int pin) +{ + if (pwrite(g_pwm[pin].fd_run, "0", 1*sizeof(char), 0) != 1) + Fatal("Couldn't stop PWM %d - %s", pin, strerror(errno)); + +} + +/** + * Read an ADC value + * @param id - The ID of the ADC pin to read + * @returns - The reading of the ADC channel + */ +long ADC_Read(int id) +{ + + //Log(LOGDEBUG, "Called for pin %d", id); + char adc_val[ADC_DIGITS] = ""; + rewind(g_adc[id].file_value); + fgets(adc_val, sizeof(adc_val)/sizeof(char), g_adc[id].file_value); + for(int i = ADC_DIGITS-1; i > 0; --i) + { + if (adc_val[i] == '\n') + adc_val[i] = '\0'; + } + + char * end; + long val = strtol(adc_val, &end, 10); + if (*end != '\0') + { + Log(LOGERR, "Reading ADC%d gives %s - invalid!", id, adc_val); + } + //Log(LOGDEBUG, "Returns %lu", val); + return val; +} diff --git a/server/bbb_pin.h b/server/bbb_pin.h new file mode 100644 index 0000000..472a917 --- /dev/null +++ b/server/bbb_pin.h @@ -0,0 +1,36 @@ +/** + * @file bbb_pin.h + * @brief Definition of functions for controlling pins on the Beaglebone Black + */ + +#ifndef _BBB_PIN_H +#define _BBB_PIN_H + +#include "common.h" + +#include "bbb_pin_defines.h" + +// Initialise / Deinitialise functions +extern void GPIO_Export(int pin); +extern void GPIO_Unexport(int pin); + +extern void PWM_Export(int pin); +extern void PWM_Unexport(int pin); + +extern void ADC_Export(); +extern void ADC_Unexport(); + +// Pin reading/setting functions +extern bool GPIO_Read(int pin); +extern void GPIO_Set(int pin, bool value); + +extern long ADC_Read(int pin); + +extern void PWM_Set(int pin, bool polarity, long period, long duty); // period and duty are in ns +extern void PWM_Stop(int pin); + + + +#endif //_BBB_PIN_H + +//EOF diff --git a/server/bbb_pin_defines.h b/server/bbb_pin_defines.h new file mode 100644 index 0000000..dba2d5c --- /dev/null +++ b/server/bbb_pin_defines.h @@ -0,0 +1,154 @@ +/** + * @file bbb_pin_defines.h + * @brief Defines pins on Beaglebone Black + */ + +#ifndef _BBB_PIN_DEFINES_H +#define _BBB_PIN_DEFINES_H + +/** GPIO0 defines **/ + +#define GPIO0_1 1 +#define GPIO0_2 2 +//#define GPIO0_3 3 // Used for PWM +//#define GPIO0_4 4 // Used for PWM +#define GPIO0_5 5 +#define GPIO0_6 6 +#define GPIO0_7 7 +#define GPIO0_8 8 +#define GPIO0_9 9 +#define GPIO0_10 10 +#define GPIO0_11 11 +#define GPIO0_12 12 +#define GPIO0_13 13 +#define GPIO0_14 14 +#define GPIO0_15 15 +#define GPIO0_16 16 +#define GPIO0_17 17 +#define GPIO0_18 18 +#define GPIO0_19 19 +#define GPIO0_20 20 +#define GPIO0_21 21 +#define GPIO0_22 22 +#define GPIO0_23 23 +#define GPIO0_24 24 +#define GPIO0_25 25 +#define GPIO0_26 26 +#define GPIO0_27 27 +#define GPIO0_28 28 +#define GPIO0_29 29 +#define GPIO0_30 30 +#define GPIO0_31 31 +#define GPIO0_32 32 + +/** GPIO1 defines **/ + +#define GPIO1_1 33 +#define GPIO1_2 34 +#define GPIO1_3 35 +#define GPIO1_4 36 +#define GPIO1_5 37 +#define GPIO1_6 38 +#define GPIO1_7 39 +#define GPIO1_8 40 +#define GPIO1_9 41 +#define GPIO1_10 42 +#define GPIO1_11 43 +#define GPIO1_12 44 +#define GPIO1_13 45 +#define GPIO1_14 46 +#define GPIO1_15 47 +#define GPIO1_16 48 +#define GPIO1_17 49 +#define GPIO1_18 50 +#define GPIO1_19 51 +#define GPIO1_20 52 +#define GPIO1_21 53 +#define GPIO1_22 54 +#define GPIO1_23 55 +#define GPIO1_24 56 +#define GPIO1_25 57 +#define GPIO1_26 58 +#define GPIO1_27 59 +#define GPIO1_28 60 +#define GPIO1_29 61 +#define GPIO1_30 62 +#define GPIO1_31 63 +#define GPIO1_32 64 + +/** GPIO2 defines **/ + +#define GPIO2_1 65 +#define GPIO2_2 66 +#define GPIO2_3 67 +#define GPIO2_4 68 +#define GPIO2_5 69 +#define GPIO2_6 70 +#define GPIO2_7 71 +#define GPIO2_8 72 +#define GPIO2_9 73 +#define GPIO2_10 74 +#define GPIO2_11 75 +#define GPIO2_12 76 +#define GPIO2_13 77 +#define GPIO2_14 78 +#define GPIO2_15 79 +#define GPIO2_16 80 +#define GPIO2_17 81 +#define GPIO2_18 82 +#define GPIO2_19 83 +#define GPIO2_20 84 +#define GPIO2_21 85 +#define GPIO2_22 86 +#define GPIO2_23 87 +#define GPIO2_24 88 +#define GPIO2_25 89 +#define GPIO2_26 90 +#define GPIO2_27 91 +#define GPIO2_28 92 +#define GPIO2_29 93 +#define GPIO2_30 94 +#define GPIO2_31 95 +#define GPIO2_32 96 + +/** Number of GPIO pins **/ +#define GPIO_NUM_PINS 97 + +/** Export path **/ +#define GPIO_DEVICE_PATH "/sys/class/gpio" + +#define ADC_BITS 12 +#define ADC_DIGITS 5 +#define ADC0 0 +#define ADC1 1 +#define ADC2 2 +#define ADC3 3 +#define ADC4 4 +#define ADC5 5 +#define ADC6 6 +#define ADC7 7 + +/** Number of ADC pins **/ +#define ADC_NUM_PINS 8 + +/** Path to export ADCs with**/ +#define ADC_EXPORT_PATH "/sys/devices/bone_capemgr.9/slots" +/** Path at which ADCs appear **/ +#define ADC_DEVICE_PATH "/sys/devices/ocp.3/helper.16" + +/** PWM defines **/ +#define EHRPWM0A 0 +#define EHRPWM0B 1 +// No other PWM pins work! + +/** Number of PWM pins **/ +#define PWM_NUM_PINS 2 + +/** Path to PWM sysfs **/ +#define PWM_DEVICE_PATH "/sys/class/pwm" + + + +#endif //_BBB_PIN_DEFINES_H + + diff --git a/server/fastcgi.c b/server/fastcgi.c index a648ae8..67f7de3 100644 --- a/server/fastcgi.c +++ b/server/fastcgi.c @@ -447,15 +447,17 @@ void * FCGI_RequestLoop (void *data) { FCGIContext context = {0}; - Log(LOGDEBUG, "First request..."); + Log(LOGDEBUG, "Start loop"); while (FCGI_Accept() >= 0) { - Log(LOGDEBUG, "Got request #%d", context.response_number); + ModuleHandler module_handler = NULL; char module[BUFSIZ], params[BUFSIZ]; //strncpy doesn't zero-truncate properly snprintf(module, BUFSIZ, "%s", getenv("DOCUMENT_URI_LOCAL")); snprintf(params, BUFSIZ, "%s", getenv("QUERY_STRING")); + + Log(LOGDEBUG, "Got request #%d - Module %s, params %s", context.response_number, module, params); //Remove trailing slashes (if present) from module query size_t lastchar = strlen(module) - 1; @@ -489,7 +491,7 @@ void * FCGI_RequestLoop (void *data) } context.response_number++; - Log(LOGDEBUG, "Waiting for request #%d", context.response_number); + } Log(LOGDEBUG, "Thread exiting."); diff --git a/server/log.c b/server/log.c index d41021f..c23d158 100644 --- a/server/log.c +++ b/server/log.c @@ -22,10 +22,12 @@ static const char * unspecified_funct = "???"; If level is higher (less urgent) than the program's verbosity (see options.h) no message will be printed * @param funct - String indicating the function name from which this function was called. If this is NULL, Log will show the unspecified_funct string instead + * @param file - Source file containing the function + * @param line - Line in the source file at which Log is called * @param fmt - A format string * @param ... - Arguments to be printed according to the format string */ -void LogEx(int level, const char * funct, ...) +void LogEx(int level, const char * funct, const char * file, int line, ...) { //Todo: consider setlogmask(3) to filter messages const char *fmt; @@ -36,7 +38,7 @@ void LogEx(int level, const char * funct, ...) if (level > g_options.verbosity) return; - va_start(va, funct); + va_start(va, line); fmt = va_arg(va, const char*); if (fmt == NULL) // sanity check @@ -74,22 +76,24 @@ void LogEx(int level, const char * funct, ...) break; } - syslog(level, "%s: %s - %s", severity, funct, buffer); + syslog(level, "%s: %s (%s:%d) - %s", severity, funct, file, line, buffer); } /** * Handle a Fatal error in the program by printing a message and exiting the program * CALLING THIS FUNCTION WILL CAUSE THE PROGAM TO EXIT * @param funct - Name of the calling function + * @param file - Name of the source file containing the calling function + * @param line - Line in the source file at which Fatal is called * @param fmt - A format string * @param ... - Arguments to be printed according to the format string */ -void FatalEx(const char * funct, ...) +void FatalEx(const char * funct, const char * file, int line, ...) { const char *fmt; char buffer[BUFSIZ]; va_list va; - va_start(va, funct); + va_start(va, line); fmt = va_arg(va, const char*); if (fmt == NULL) @@ -106,7 +110,7 @@ void FatalEx(const char * funct, ...) if (funct == NULL) funct = unspecified_funct; - syslog(LOG_CRIT, "FATAL: %s - %s", funct, buffer); + syslog(LOG_CRIT, "FATAL: %s (%s:%d) - %s", funct, file, line, buffer); exit(EXIT_FAILURE); } diff --git a/server/log.h b/server/log.h index eec5e53..fd98190 100644 --- a/server/log.h +++ b/server/log.h @@ -7,14 +7,14 @@ #define _LOG_H //To get around a 'pedantic' C99 rule that you must have at least 1 variadic arg, combine fmt into that. -#define Log(level, ...) LogEx(level, __func__, __VA_ARGS__) -#define Fatal(...) FatalEx(__func__, __VA_ARGS__) +#define Log(level, ...) LogEx(level, __func__, __FILE__, __LINE__, __VA_ARGS__) +#define Fatal(...) FatalEx(__func__, __FILE__, __LINE__, __VA_ARGS__) // An enum to make the severity of log messages human readable in code enum {LOGERR=0, LOGWARN=1, LOGNOTE=2, LOGINFO=3,LOGDEBUG=4}; -extern void LogEx(int level, const char * funct, ...); // General function for printing log messages to stderr -extern void FatalEx(const char * funct, ...); // Function that deals with a fatal error (prints a message, then exits the program). +extern void LogEx(int level, const char * funct, const char * file, int line, ...); // General function for printing log messages to stderr +extern void FatalEx(const char * funct, const char * file, int line, ...); // Function that deals with a fatal error (prints a message, then exits the program). #endif //_LOG_H diff --git a/server/sensor.c b/server/sensor.c index 64c7aa9..e429958 100644 --- a/server/sensor.c +++ b/server/sensor.c @@ -7,6 +7,7 @@ #include "common.h" #include "sensor.h" #include "options.h" +#include "bbb_pin.h" #include /** Array of sensors, initialised by Sensor_Init **/ @@ -17,17 +18,20 @@ 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 }; /** Human readable names for the sensors **/ const char * g_sensor_names[NUMSENSORS] = { "analog_test0", "analog_test1", - "analog_fail0", "digital_test0", - "digital_test1", "digital_fail0" + "analog_realtest", "analog_fail0", + "digital_test0", "digital_test1", + "digital_realtest", "digital_fail0" }; /** @@ -40,6 +44,14 @@ void Sensor_Init() g_sensors[i].id = i; Data_Init(&(g_sensors[i].data_file)); } + + // Get the ADCs + ADC_Export(); + + // GPIO1_28 used as a pulse for sampling + GPIO_Export(GPIO1_28); + // GPIO0_30 toggled during sampling + GPIO_Export(GPIO0_30); } /** @@ -157,12 +169,37 @@ bool Sensor_Read(Sensor * s, DataPoint * d) gettimeofday(&t, NULL); d->time_stamp = TIMEVAL_DIFF(t, *Control_GetStartTime()); + static bool result = true; + + // Read value based on Sensor Id switch (s->id) { + case ANALOG_REALTEST: + { + static bool set = false; + + GPIO_Set(GPIO0_30, true); + d->value = (double)ADC_Read(ADC0); //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); + + break; + } + + default: + d->value = rand() % 2; + usleep(1000000); + break; + + case ANALOG_TEST0: + { d->value = (double)(rand() % 100) / 100; break; + } case ANALOG_TEST1: { static int count = 0; @@ -170,33 +207,43 @@ bool Sensor_Read(Sensor * s, DataPoint * d) d->value = count++; break; } + case ANALOG_FAIL0: - d->value = (double)(rand() % 6) * -( rand() % 2) / ( rand() % 100 + 1); + d->value = 0; + //d->value = (double)(rand() % 6) * -( rand() % 2) / ( rand() % 100 + 1); //Gives a value between -5 and 5 break; case DIGITAL_TEST0: d->value = t.tv_sec % 2; + break; case DIGITAL_TEST1: d->value = (t.tv_sec+1)%2; break; + case DIGITAL_REALTEST: + { + // 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 + 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 break; - default: - Fatal("Unknown sensor id: %d", s->id); - break; + //default: + // Fatal("Unknown sensor id: %d", s->id); + // break; } - usleep(100000); // simulate delay in sensor polling + // Perform sanity check based on Sensor's ID and the DataPoint Sensor_CheckData(s->id, d->value); // Update latest DataPoint if necessary - bool result = (d->value != s->newest_data.value); + if (result) { s->newest_data.time_stamp = d->time_stamp; @@ -270,6 +317,7 @@ void Sensor_BeginResponse(FCGIContext * context, SensorId id, DataFormat format) case JSON: FCGI_BeginJSON(context, STATUS_OK); FCGI_JSONLong("id", id); + FCGI_JSONPair("name", g_sensor_names[id]); break; default: FCGI_PrintRaw("Content-type: text/plain\r\n\r\n"); diff --git a/server/sensor.h b/server/sensor.h index 6c7abaa..182d8ae 100644 --- a/server/sensor.h +++ b/server/sensor.h @@ -9,16 +9,18 @@ #include "data.h" /** Number of sensors **/ -#define NUMSENSORS 6 +#define NUMSENSORS 8 /** 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 } SensorId; diff --git a/web/gui.js b/web/gui.js index da4e0d0..7d7a8fe 100644 --- a/web/gui.js +++ b/web/gui.js @@ -8,7 +8,7 @@ $(document).ready(function() { g_sensors = [] - g_numSensors = 2 + g_numSensors = 1 g_storeTime = [] g_key = null @@ -44,7 +44,7 @@ $(document).ready(function() $.fn.updateSensor = function(json) { //console.log(json.data) - var sensor = g_sensors[json.id] + var sensor = g_sensors[0] var most_recent = null if (sensor.length > 0) most_recent = sensor[sensor.length-1][0] @@ -62,7 +62,7 @@ $(document).ready(function() //console.log("Plot:") //console.log(g_sensors[json.id]) - $.plot("#sensor"+String(json.id)+"_plot", [g_sensors[json.id]]) + $.plot("#sensor"+String(0)+"_plot", [g_sensors[0]]) $.ajax({url : "/api/sensors", data : {id : json.id}, success : function(data) {$(this).updateSensor(data);}}); // @@ -127,7 +127,7 @@ $(document).ready(function() for (var i = 0; i < g_numSensors; ++i) { - // $.ajax({url : "/api/sensors", data : {id : i}, success : function(data) {$(this).updateSensor(data);}}) + $.ajax({url : "/api/sensors", data : {id : 2}, success : function(data) {$(this).updateSensor(data);}}) } });