From 00c5659557c54258f31da4c33c078c52f3d8feb6 Mon Sep 17 00:00:00 2001 From: Sam Moore Date: Tue, 24 Sep 2013 04:27:45 +0800 Subject: [PATCH] Added module for direct control over pins Will hopefully be useful for testing purposes. Usage: 1. GPIO Set http://192.168.1.10/api/pin?type=gpo&set=S&num=N - S is 0 or 1 and N is the pin number (1 to 96) 2. GPIO Read http://192.168.1.10/api/pin?type=gpi&num=N - N is pin number 3. ADC Read http://192.168.1.10/api/pin?type=adc&num=N - N is pin number (0 to 7) 4. PWM Set http://192.168.1.10/api/pin?type=pwm&num=N&set=1&freq=F&duty=D&pol=P - F in Hz, D as a multiplier (0 -> 1) P is 0 or 1 - N is pin number (0 to 7) 5. PWM Stop http://192.168.1.10/api/pin?type=pwm&num=N&set=0 Pin numbering according to http://beagleboard.org/static/images/cape-headers-pwm.png PWM pins are numbered as: EHRPWM0A = 0, EHRPWM0B = 1, EHRPWM1A = 2, etc Module code in pin_test.c and pin_test.h. Uses functions declared in bbb_pin.h and implemented in bbb_pin.c Note: - Also modified bbb_pin.c functions to not throw Fatal errors - Might want to change that back. It seemed like a good idea at 2am. BUG ALERT: - Doing the following: http://192.168.1.10/api/pin?type=gpo&num=13&set=0 Will give a FCGIRejectJSON (invalid Pin number). --- server/Makefile | 2 +- server/bbb_pin.c | 103 +++++++++++++++++++++--------- server/common.h | 2 + server/fastcgi.c | 3 + server/log.c | 2 + server/log.h | 3 + server/main.c | 7 +++ server/options.h | 5 ++ server/pin_test.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++ server/pin_test.h | 17 +++++ server/run.sh | 3 + server/sensor.c | 18 +++--- 12 files changed, 283 insertions(+), 38 deletions(-) create mode 100644 server/pin_test.c create mode 100644 server/pin_test.h diff --git a/server/Makefile b/server/Makefile index 1302544..f3ce6b4 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 bbb_pin.o +OBJ = log.o control.o data.o fastcgi.o main.o sensor.o actuator.o image.o bbb_pin.o pin_test.o RM = rm -f BIN = server diff --git a/server/bbb_pin.c b/server/bbb_pin.c index 39f6f1f..4569578 100644 --- a/server/bbb_pin.c +++ b/server/bbb_pin.c @@ -61,7 +61,9 @@ static char g_buffer[BUFSIZ] = ""; void GPIO_Export(int pin) { if (pin < 0 || pin > GPIO_NUM_PINS) - Fatal("Invalid pin number %d", pin); + { + Abort("Invalid pin number %d", pin); + } @@ -69,7 +71,9 @@ void GPIO_Export(int 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)); + { + Abort("Couldn't open %s to export GPIO pin %d - %s", g_buffer, pin, strerror(errno)); + } fprintf(export, "%d", pin); fclose(export); @@ -78,14 +82,21 @@ void GPIO_Export(int pin) 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)); + { + Abort("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)); + { + Abort("Couldn't open %s for GPIO pin %d - %s", g_buffer, pin, strerror(errno)); + } + + Log(LOGDEBUG, "Exported GPIO%d", pin); + //sleep(1); } /** @@ -95,7 +106,9 @@ void GPIO_Unexport(int pin) { if (pin < 0 || pin > GPIO_NUM_PINS) - Fatal("Invalid pin number %d", pin); + { + Abort("Invalid pin number %d", pin); + } // Close file descriptors close(g_gpio[pin].fd_value); @@ -107,7 +120,9 @@ void GPIO_Unexport(int pin) 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)); + { + Abort("Couldn't open %s to export GPIO pin %d - %s", g_buffer, pin, strerror(errno)); + } fprintf(export, "%d", pin); fclose(export); @@ -123,13 +138,17 @@ void GPIO_Unexport(int pin) void PWM_Export(int pin) { if (pin < 0 || pin > PWM_NUM_PINS) - Fatal("Invalid pin number %d", pin); + { + Abort("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)); + { + Abort("Couldn't open %s to export PWM pin %d - %s", g_buffer, pin, strerror(errno)); + } fprintf(export, "%d\n", pin); fclose(export); @@ -138,22 +157,30 @@ void PWM_Export(int pin) 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)); + { + Abort("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)); + { + Abort("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)); + { + Abort("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)); + { + Abort("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); @@ -169,7 +196,9 @@ void PWM_Export(int pin) void PWM_Unexport(int pin) { if (pin < 0 || pin > PWM_NUM_PINS) - Fatal("Invalid pin number %d", pin); + { + Abort("Invalid pin number %d", pin); + } // Close the file descriptors close(g_pwm[pin].fd_polarity); @@ -181,7 +210,9 @@ void PWM_Unexport(int 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)); + { + Abort("Couldn't open %s to unexport PWM pin %d - %s", g_buffer, pin, strerror(errno)); + } fprintf(export, "%d", pin); fclose(export); @@ -201,7 +232,9 @@ void ADC_Export() sprintf(g_buffer, "%s/AIN%d", g_options.adc_device_path, i); g_adc[i].fd_value = open(g_buffer, O_RDONLY); if (g_adc[i].fd_value < 0) - Fatal("Couldn't open ADC %d device file %s - %s", i, g_buffer, strerror(errno)); + { + Abort("Couldn't open ADC %d device file %s - %s", i, g_buffer, strerror(errno)); + } //setbuf(g_adc[i].file_value, NULL); @@ -224,11 +257,15 @@ void ADC_Unexport() void GPIO_Set(int pin, bool value) { if (pwrite(g_gpio[pin].fd_direction, "out", 3, 0) != 3) - Fatal("Couldn't set GPIO %d direction - %s", pin, strerror(errno)); + { + Abort("Couldn't set GPIO %d direction - %s", pin, strerror(errno)); + } char c = '0' + (value); if (pwrite(g_gpio[pin].fd_value, &c, 1, 0) != 1) - Fatal("Couldn't read GPIO %d value - %s", pin, strerror(errno)); + { + Abort("Couldn't read GPIO %d value - %s", pin, strerror(errno)); + } } @@ -239,10 +276,10 @@ void GPIO_Set(int pin, bool value) bool GPIO_Read(int pin) { if (pwrite(g_gpio[pin].fd_direction, "in", 2, 0) != 2) - Fatal("Couldn't set GPIO %d direction - %s", pin, strerror(errno)); + Log(LOGERR,"Couldn't set GPIO %d direction - %s", pin, strerror(errno)); char c = '0'; if (pread(g_gpio[pin].fd_value, &c, 1, 0) != 1) - Fatal("Couldn't read GPIO %d value - %s", pin, strerror(errno)); + Log(LOGERR,"Couldn't read GPIO %d value - %s", pin, strerror(errno)); return (c == '1'); @@ -259,24 +296,31 @@ 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, 0) != 1) - Fatal("Couldn't stop PWM %d - %s", pin, strerror(errno)); + { + Abort("Couldn't stop PWM %d - %s", pin, strerror(errno)); + } char c = '0' + polarity; if (pwrite(g_pwm[pin].fd_polarity, &c, 1, 0) != 1) - Fatal("Couldn't set PWM %d polarity - %s", pin, strerror(errno)); - + { + Abort("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)); - + { + Abort("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)); - + { + Abort("Couldn't set period for PWM %d - %s", pin, strerror(errno)); + } if (pwrite(g_pwm[pin].fd_run, "1", 1, 0) != 1) - Fatal("Couldn't start PWM %d - %s", pin, strerror(errno)); + { + Abort("Couldn't start PWM %d - %s", pin, strerror(errno)); + } } @@ -287,8 +331,9 @@ void PWM_Set(int pin, bool polarity, long period, long duty) void PWM_Stop(int pin) { if (pwrite(g_pwm[pin].fd_run, "0", 1, 0) != 1) - Fatal("Couldn't stop PWM %d - %s", pin, strerror(errno)); - + { + Abort("Couldn't stop PWM %d - %s", pin, strerror(errno)); + } } /** diff --git a/server/common.h b/server/common.h index 97290d2..43bb8bd 100644 --- a/server/common.h +++ b/server/common.h @@ -34,4 +34,6 @@ #define TIMEVAL_DIFF(tv1, tv2) ((tv1).tv_sec - (tv2).tv_sec + 1e-6 * ((tv1).tv_usec - (tv2).tv_usec)) + + #endif //_COMMON_H diff --git a/server/fastcgi.c b/server/fastcgi.c index 67f7de3..e7133e8 100644 --- a/server/fastcgi.c +++ b/server/fastcgi.c @@ -16,6 +16,7 @@ #include "control.h" #include "options.h" #include "image.h" +#include "pin_test.h" /**The time period (in seconds) before the control key expires */ #define CONTROL_TIMEOUT 180 @@ -481,6 +482,8 @@ void * FCGI_RequestLoop (void *data) module_handler = Actuator_Handler; } else if (!strcmp("image", module)) { module_handler = Image_Handler; + } else if (!strcmp("pin", module)) { + module_handler = Pin_Handler; // *Debug only* pin test module } context.current_module = module; diff --git a/server/log.c b/server/log.c index c23d158..bd210d8 100644 --- a/server/log.c +++ b/server/log.c @@ -15,6 +15,7 @@ static const char * unspecified_funct = "???"; + /** * Print a message to stderr and log it via syslog. The message must be * less than BUFSIZ characters long, or it will be truncated. @@ -111,6 +112,7 @@ void FatalEx(const char * funct, const char * file, int line, ...) funct = unspecified_funct; 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 fd98190..cc6a7e5 100644 --- a/server/log.h +++ b/server/log.h @@ -10,6 +10,9 @@ #define Log(level, ...) LogEx(level, __func__, __FILE__, __LINE__, __VA_ARGS__) #define Fatal(...) FatalEx(__func__, __FILE__, __LINE__, __VA_ARGS__) +/*** Macro to abort function ***/ +#define Abort(...) LogEx(LOGERR, __func__, __FILE__, __LINE__, __VA_ARGS__); return + // An enum to make the severity of log messages human readable in code enum {LOGERR=0, LOGWARN=1, LOGNOTE=2, LOGINFO=3,LOGDEBUG=4}; diff --git a/server/main.c b/server/main.c index 930b8b0..aff5b83 100644 --- a/server/main.c +++ b/server/main.c @@ -27,6 +27,10 @@ Options g_options; // options passed to program through command line arguments */ void ParseArguments(int argc, char ** argv) { + // horrible horrible hacks + g_options.argc = argc; + g_options.argv = argv; + g_options.program = argv[0]; // program name g_options.verbosity = LOGDEBUG; // default log level gettimeofday(&(g_options.start_time), NULL); // Start time @@ -112,6 +116,7 @@ int main(int argc, char ** argv) */ Sensor_Init(); Actuator_Init(); + Pin_Init(); //Sensor_StartAll("test"); //Actuator_StartAll("test"); const char *ret; @@ -126,6 +131,8 @@ int main(int argc, char ** argv) //Sensor_StopAll(); //Actuator_StopAll(); + Pin_Close(); + Cleanup(); return 0; } diff --git a/server/options.h b/server/options.h index 0416dd5..f702e01 100644 --- a/server/options.h +++ b/server/options.h @@ -22,6 +22,11 @@ typedef struct /** Path to ADC files **/ char * adc_device_path; + /*** Horrible horrible hack ***/ + int argc; + /*** Horrible horrible hack ***/ + char ** argv; + } Options; /** The only instance of the Options struct **/ diff --git a/server/pin_test.c b/server/pin_test.c new file mode 100644 index 0000000..cd8c307 --- /dev/null +++ b/server/pin_test.c @@ -0,0 +1,156 @@ +/** + * @file pin_test.c + * @purpose Implementations to allow direct control over pins through FastCGI + */ + +#include "pin_test.h" + +#include "bbb_pin.h" + +/** + * Export *ALL* pins for control + */ +void Pin_Init() +{ + for (int i = 0; i < GPIO_NUM_PINS; ++i) + GPIO_Export(i); + + for (int i = 0; i < ADC_NUM_PINS; ++i) + ADC_Export(); + + for (int i = 0; i < PWM_NUM_PINS; ++i) + PWM_Export(i); +} + +/** + * Unexport all pins + */ +void Pin_Close() +{ + for (int i = 0; i < GPIO_NUM_PINS; ++i) + GPIO_Unexport(i); + + for (int i = 0; i < ADC_NUM_PINS; ++i) + ADC_Unexport(i); + + for (int i = 0; i < PWM_NUM_PINS; ++i) + PWM_Unexport(i); +} + +/** + * Handle a request to the Pin test module + * @param context - The FastCGI context + * @param params - key/value pair parameters as a string + */ +void Pin_Handler(FCGIContext *context, char * params) +{ + + char * type = NULL; + int num = 0; + bool set = true; + bool pol = false; + double freq = 50; + double duty = 0.5; + + + // key/value pairs + FCGIValue values[] = { + {"type", &type, FCGI_REQUIRED(FCGI_STRING_T)}, + {"num", &num, FCGI_REQUIRED(FCGI_INT_T)}, + {"set", &set, FCGI_INT_T}, + {"pol", &pol, FCGI_INT_T}, + {"freq", &freq, FCGI_DOUBLE_T}, + {"duty", &duty, FCGI_DOUBLE_T} + }; + + // enum to avoid the use of magic numbers + typedef enum { + TYPE, + NUM, + SET, + FREQ, + DUTY + } SensorParams; + + // Fill values appropriately + if (!FCGI_ParseRequest(context, params, values, sizeof(values)/sizeof(FCGIValue))) + { + // Error occured; FCGI_RejectJSON already called + return; + } + + Log(LOGDEBUG, "Params: type = %s, num = %d, set = %d, pol = %d, freq = %f, duty = %f", type, num, set, pol, freq, duty); + + if (strcmp(type, "gpo") == 0) + { + if (num <= 0 || num > GPIO_NUM_PINS) + { + FCGI_RejectJSON(context, "Invalid GPIO pin"); + return; + } + + Log(LOGDEBUG, "Setting GPIO%d to %d", num, set); + GPIO_Set(num, set); + + FCGI_PrintRaw("Content-type: text/plain\r\n\r\n"); + FCGI_PrintRaw("GPIO%d set to %d\n", num, set); + } + else if (strcmp(type, "gpi") == 0) + { + if (num < 0 || num >= GPIO_NUM_PINS) + { + FCGI_RejectJSON(context, "Invalid GPIO pin"); + return; + } + Log(LOGDEBUG, "Reading GPIO%d", num); + FCGI_PrintRaw("Content-type: text/plain\r\n\r\n"); + FCGI_PrintRaw("GPIO%d reads %d\n", num, GPIO_Read(num)); + + } + else if (strcmp(type, "adc") == 0) + { + if (num < 0 || num >= ADC_NUM_PINS) + { + FCGI_RejectJSON(context, "Invalid ADC pin"); + return; + } + Log(LOGDEBUG, "Reading ADC%d", num, set); + FCGI_PrintRaw("Content-type: text/plain\r\n\r\n"); + FCGI_PrintRaw("ADC%d reads %d\n", num, ADC_Read(num)); + } + else if (strcmp(type, "pwm") == 0) + { + if (num < 0 || num >= PWM_NUM_PINS) + { + FCGI_RejectJSON(context, "Invalid PWM pin"); + return; + } + + FCGI_PrintRaw("Content-type: text/plain\r\n\r\n"); + + if (set) + { + Log(LOGDEBUG, "Setting PWM%d", num); + long period_ns = (long)(1e9 / freq); + long duty_ns = (long)(duty * period_ns); + PWM_Set(num, pol, period_ns, duty_ns); + FCGI_PrintRaw("PWM%d set to period_ns = %lu (%f Hz), duty_ns = %lu (%d), polarity = %d", num, period_ns, freq, duty_ns, duty*100, pol); + } + else + { + Log(LOGDEBUG, "Stopping PWM%d",num); + PWM_Stop(num); + FCGI_PrintRaw("PWM%d stopped",num); + } + } + else + { + Log(LOGDEBUG, "Invalid pin type %s", type); + FCGI_RejectJSON(context, "Invalid pin type"); + } + + + +} + +//EOF diff --git a/server/pin_test.h b/server/pin_test.h new file mode 100644 index 0000000..dd07fe1 --- /dev/null +++ b/server/pin_test.h @@ -0,0 +1,17 @@ +/** + * @file pin_test.h + * @purpose Declarations to allow direct control over pins through FastCGI + */ + +#ifndef _PIN_MODULE_H +#define _PIN_MODULE_H + +#include "common.h" + +extern void Pin_Init(); +extern void Pin_Close(); +extern void Pin_Handler(FCGIContext *context, char * params); + +#endif //_PIN_MODULE_H + +//EOF diff --git a/server/run.sh b/server/run.sh index 9bf9cc9..d9cb343 100755 --- a/server/run.sh +++ b/server/run.sh @@ -22,6 +22,9 @@ slot=$(echo /sys/devices/bone_capemgr.*/slots | awk '{print $1}') # Load PWM module modprobe pwm_test (echo am33xx_pwm > $slot) 1>&2 >> /dev/null +for port in P9_21 P9_22 P9_14 P9_16 P9_29 P9_31 P9_42 P8_13 P8_19 P8_34 P8_36 P8_45 P8_46; do + echo bone_pwm_$port > $slot +done # Load ADCs (echo cape-bone-iio > $slot) 1>&2 >> /dev/null diff --git a/server/sensor.c b/server/sensor.c index 98896e8..63e69d8 100644 --- a/server/sensor.c +++ b/server/sensor.c @@ -46,12 +46,12 @@ void Sensor_Init() } // Get the ADCs - ADC_Export(); + //ADC_Export(); // GPIO1_28 used as a pulse for sampling - GPIO_Export(GPIO1_28); + //GPIO_Export(GPIO1_28); // GPIO0_30 toggled during sampling - GPIO_Export(GPIO0_30); + //GPIO_Export(GPIO0_30); } /** @@ -175,16 +175,18 @@ bool Sensor_Read(Sensor * s, DataPoint * d) // Read value based on Sensor Id switch (s->id) { - case ANALOG_REALTEST: + case 2: { static bool set = false; - GPIO_Set(GPIO0_30, true); - d->value = 0;//(double)ADC_Read(ADC0); //ADC #0 on the Beaglebone + //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); + //GPIO_Set(GPIO0_30, false); set = !set; - GPIO_Set(GPIO1_28, set); + //GPIO_Set(GPIO1_28, set); + + usleep(100000); break; } -- 2.20.1