From fefafcd16b32e2431b3501e7a30b96b78c41a220 Mon Sep 17 00:00:00 2001 From: Justin Kruger <20767264@student.uwa.edu.au> Date: Wed, 18 Sep 2013 20:37:25 +0800 Subject: [PATCH] Added Beaglebone code to sensors.c & actuators.c So I've probably broken something here with my half-remembered CITS1002 code, but hopefully it works. I have added real analog/digital sensor tests to sensors.c and real digital/pwm actuators to actuators.c. These reference GPIO.c and pwm.c for functions. --- BBB code/Actuator_SetValue_real.c | 3 +- BBB code/Actuator_SetValue_real2.c | 55 +++++++++++++ BBB code/GetData_real.c | 70 ++-------------- BBB code/gpio.c | 128 +++++++++++++++++++++++++++++ BBB code/gpio.h | 24 ++++++ BBB code/pwm.c | 35 ++++---- BBB code/pwm.h | 12 ++- server/actuator.c | 33 +++++++- server/actuator.h | 5 +- server/gpio.c | 128 +++++++++++++++++++++++++++++ server/gpio.h | 24 ++++++ server/pwm.c | 83 +++++++++++++++++++ server/pwm.h | 26 ++++++ server/sensor.c | 22 ++++- server/sensor.h | 4 +- 15 files changed, 557 insertions(+), 95 deletions(-) create mode 100644 BBB code/Actuator_SetValue_real2.c create mode 100644 BBB code/gpio.c create mode 100644 BBB code/gpio.h create mode 100644 server/gpio.c create mode 100644 server/gpio.h create mode 100644 server/pwm.c create mode 100644 server/pwm.h 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/server/actuator.c b/server/actuator.c index 9d2ad13..1abaa97 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 "gpio.h" +#include "pwm.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", "actuator_test1", "actuator_test2" }; /** @@ -166,6 +169,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]; @@ -188,6 +192,33 @@ void Actuator_SetValue(Actuator * a, double value) } break; case ACTUATOR_TEST1: + // GPIO pin digital actuator + { + // Quick actuator function for testing pins + // GPIOPin can be passed as argument, but is just defined here for testing purposes + int GPIOPin = 13; + // Modify this to only export on first run, only unexport on shutdown + pinExport(setValue, GPIOString); + pinDirection(GPIODirection, setValue); + pinSet(value, GPIOValue, setValue); + pinUnexport(setValue, GPIOString); + } + break; + case ACTUATOR_TEST2: + // PWM analogue actuator (currently generates one PWM signal with first PWM module) + { + if (pwminit == 0) { // If inactive, start the pwm module + pwm_init(); + } + if (pwmstart == 0) { + pwm_start(); + pwm_set_period(FREQ); // Frequency is 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 (0-100%) + } + } break; } diff --git a/server/actuator.h b/server/actuator.h index 81150e8..c2a229d 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/gpio.c b/server/gpio.c new file mode 100644 index 0000000..65f1a51 --- /dev/null +++ b/server/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/server/gpio.h b/server/gpio.h new file mode 100644 index 0000000..1da8470 --- /dev/null +++ b/server/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/server/pwm.c b/server/pwm.c new file mode 100644 index 0000000..b86b07e --- /dev/null +++ b/server/pwm.c @@ -0,0 +1,83 @@ +#include "pwm.h" + +/* Initialize PWM : +1/ mmap /dev/mem to have write access to system clock +2/ enable system clock (0x0 = disabled, 0x02 = enabled) +3/ set correct pin MUX + +can modify pwm variables through virtual filesystem: +"/sys/class/pwm/ehrpwm.1:0/..." + +pwm drivers reference: +http://processors.wiki.ti.com/index.php/AM335x_PWM_Driver%27s_Guide */ + +static int pwminit = 0; +static int pwmstart = 0; + +void pwm_init(void) { + FILE *pwm_mux; + int i; + volatile uint32_t *epwmss1; + + int fd = open("/dev/mem", O_RDWR); + + if(fd < 0) + { + printf("Can't open /dev/mem\n"); + exit(1); + } + + epwmss1 = (volatile uint32_t *) mmap(NULL, LENGTH, PROT_READ|PROT_WRITE, MAP_SHARED, fd, START); + if(epwmss1 == NULL) + { + printf("Can't mmap\n"); + exit(1); + } + else + { + epwmss1[OFFSET_1 / sizeof(uint32_t)] = 0x2; + } + close(fd); + pwminit = 1; + pwm_mux = fopen(PWMMuxPath, "w"); + fprintf(pwm_mux, "6"); // pwm is mux mode 6 + fclose(pwm_mux); +} + +//can change filepath of pwm module "/ehrpwm.%d:0/" by passing %d as argument +//depends how many pwm modules we have to run +//TODO: + +void pwm_start(void) { + FILE *pwm_run; + pwm_run = fopen(PWMRunPath, "w"); + fprintf(pwm_run, "1"); + fclose(pwm_run); + pwmstart = 1; +} + +void pwm_stop(void) { + FILE *pwm_run; + 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) { + FILE *pwm_duty; + 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) { + FILE *pwm_period; + pwm_period = fopen(PWMFreqPath, "w"); + fprintf(pwm_period, "%d", freq); + fclose(pwm_period); +} \ No newline at end of file diff --git a/server/pwm.h b/server/pwm.h new file mode 100644 index 0000000..2c9411b --- /dev/null +++ b/server/pwm.h @@ -0,0 +1,26 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 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); +void pwm_stop(void); +void pwm_set_duty(int duty_percent); +void pwm_set_period(int freq); \ No newline at end of file diff --git a/server/sensor.c b/server/sensor.c index 5115f99..3f84ed0 100644 --- a/server/sensor.c +++ b/server/sensor.c @@ -7,6 +7,7 @@ #include "common.h" #include "sensor.h" #include "options.h" +#include "gpio.h" #include /** Array of sensors, initialised by Sensor_Init **/ @@ -18,16 +19,19 @@ const SensorThreshold thresholds[NUMSENSORS]= { {1,-1,1,-1}, // ANALOG_TEST0 {500,0,499,0}, // ANALOG_TEST1 {5,-5,4,-4}, // ANALOG_FAIL0 + {500,0,499,0}, // ANALOG_REALTEST {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" }; /** @@ -154,8 +158,10 @@ bool Sensor_Read(Sensor * s, DataPoint * d) switch (s->id) { case ANALOG_TEST0: + { d->value = (double)(rand() % 100) / 100; break; + } case ANALOG_TEST1: { static int count = 0; @@ -163,6 +169,11 @@ bool Sensor_Read(Sensor * s, DataPoint * d) d->value = count++; break; } + case ANALOG_REALTEST: + { + d->value = ADCRead(0); //ADC #0 on the Beaglebone + break; + } case ANALOG_FAIL0: d->value = (double)(rand() % 6) * -( rand() % 2) / ( rand() % 100 + 1); //Gives a value between -5 and 5 @@ -173,6 +184,13 @@ bool Sensor_Read(Sensor * s, DataPoint * d) 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; diff --git a/server/sensor.h b/server/sensor.h index bdab0f9..eeb6da1 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; -- 2.20.1