From 0c55febb46bf3bfacaeefda0a2e422b42c18710c Mon Sep 17 00:00:00 2001 From: Sam Moore Date: Sun, 22 Sep 2013 01:25:22 +0800 Subject: [PATCH] Get BBB pin control working Thank god it finally works. --- server/Makefile | 8 +- server/actuator.c | 40 ++--- server/bbb_pin.c | 326 +++++++++++++++++++++++++++++++++++++++ server/bbb_pin.h | 36 +++++ server/bbb_pin_defines.h | 154 ++++++++++++++++++ server/fastcgi.c | 8 +- server/gpio.c | 138 ----------------- server/gpio.h | 26 ---- server/pwm.c | 83 ---------- server/pwm.h | 26 ---- server/sensor.c | 55 +++++-- web/gui.js | 8 +- 12 files changed, 581 insertions(+), 327 deletions(-) create mode 100644 server/bbb_pin.c create mode 100644 server/bbb_pin.h create mode 100644 server/bbb_pin_defines.h delete mode 100644 server/gpio.c delete mode 100644 server/gpio.h delete mode 100644 server/pwm.c delete mode 100644 server/pwm.h diff --git a/server/Makefile b/server/Makefile index fd4d7ec..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 gpio.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 4df06bc..50a27de 100644 --- a/server/actuator.c +++ b/server/actuator.c @@ -6,7 +6,7 @@ #include "actuator.h" #include "options.h" // Files containing GPIO and PWM definitions -#include "gpio.h" +#include "bbb_pin.h" /** Array of Actuators (global to this file) initialised by Actuator_Init **/ @@ -14,7 +14,7 @@ static Actuator g_actuators[NUMACTUATORS]; /** Human readable names for the Actuators **/ const char * g_actuator_names[NUMACTUATORS] = { - "actuator_test0", "actuator_test1", "actuator_test2" + "actuator_test0", "gpio1_16", "EHRPWM0A_duty@60Hz" }; /** @@ -28,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); + } /** @@ -192,35 +197,15 @@ 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 - // Modify this to only export on first run, only unexport on shutdown - pinExport(60); - pinDirection(60, 1); - pinSet(value, 60); - pinUnexport(60); - } + GPIO_Set(GPIO1_16, (bool)(value)); 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%) - } - } - */ + 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); @@ -243,6 +228,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/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 b7a3e6b..e391fcd 100644 --- a/server/fastcgi.c +++ b/server/fastcgi.c @@ -446,15 +446,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; @@ -488,7 +490,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/gpio.c b/server/gpio.c deleted file mode 100644 index 6370df6..0000000 --- a/server/gpio.c +++ /dev/null @@ -1,138 +0,0 @@ -#include "gpio.h" - -void pinExport(int GPIOPin) { - - char GPIOString[4]; - char setValue[4]; - sprintf(GPIOString, "%d", GPIOPin); - - FILE * myOutputHandle = fopen(exportPath, "ab"); - if (myOutputHandle == 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 r = read(sensor, buffer, sizeof(buffer)); - if (r != -1) { - buffer[r] = '\0'; - 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(pin, 0, SEEK_SET); - int r = read(pin, &ch, sizeof(ch)); - if (r != -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); -} diff --git a/server/gpio.h b/server/gpio.h deleted file mode 100644 index b4ded0c..0000000 --- a/server/gpio.h +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "common.h" - -#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); diff --git a/server/pwm.c b/server/pwm.c deleted file mode 100644 index b86b07e..0000000 --- a/server/pwm.c +++ /dev/null @@ -1,83 +0,0 @@ -#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 deleted file mode 100644 index 2c9411b..0000000 --- a/server/pwm.h +++ /dev/null @@ -1,26 +0,0 @@ -#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 a3580b7..9d0b33c 100644 --- a/server/sensor.c +++ b/server/sensor.c @@ -7,7 +7,7 @@ #include "common.h" #include "sensor.h" #include "options.h" -#include "gpio.h" +#include "bbb_pin.h" #include /** Array of sensors, initialised by Sensor_Init **/ @@ -18,8 +18,8 @@ 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 - {500,0,499,0}, // ANALOG_REALTEST {1,0,1,0}, // DIGITAL_TEST0 {1,0,1,0}, // DIGITAL_TEST1 {1,0,1,0}, // DIGITAL_REALTEST @@ -45,6 +45,14 @@ void Sensor_Init() Data_Init(&(g_sensors[i].data_file)); g_sensors[i].record_data = false; } + + // 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); } /** @@ -154,9 +162,32 @@ 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; @@ -169,18 +200,15 @@ 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 = 250; + 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; @@ -198,17 +226,17 @@ bool Sensor_Read(Sensor * s, DataPoint * d) 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; @@ -290,6 +318,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/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);}}) } }); -- 2.20.1