00:51 < sam_moore> Hell yes
00:51 < sam_moore> PWM controlled through web browser
00:51 < sam_moore> GPIO controlled through web browser
+01:19 < sam_moore> .... And ADC read through web browser
+01:19 < sam_moore> Blergh
+01:28 < sam_moore> I think I'll take the rest of today off from MCTX3420 :S
+11:53 < sam_moore> I've analysed the crap out of sampling rates for this ADC
+11:53 < sam_moore> At least as much as I can just using the timestamps according to gettimeofday
+11:54 < sam_moore> Contrary to my first email, reading the ADC is actually really slow. And also probably the greatest source of variation in sampling rate.
+11:56 < jtanx> wow
+11:56 < jtanx> only 100Hz?
+11:56 < sam_moore> Well it looks more like 1KHz on the oscilloscope, but there's a lot of variation, it has trouble getting a trigger
+11:57 < jtanx> the cpu datasheet rates it at 200kSPS
+11:57 < sam_moore> Hmm
+11:58 < sam_moore> Well judging by the control it is something about the ADC reading that makes it really slow
+11:58 < jtanx> That's annoyng
+11:58 < sam_moore> Yeah
+11:58 < sam_moore> Also annoying is that the ADC file is generally in a different place each time they're enabled
+11:59 < sam_moore> I ended up modifying the program to take the path to the ADC file as an argument
+11:59 < sam_moore> And making run.sh do the initialisation
+11:59 < sam_moore> I figured that was better than calling system()
+11:59 < jtanx> that makes sense
+11:59 < sam_moore> Yep, we might want to set other options that run.sh can pass to it anyway
+12:00 < sam_moore> Ok, I have to stop now, I'm spending way to much time on this
+12:00 < jtanx> Haha
+12:00 < sam_moore> It's getting to the point where I'm considering writing an ADC kernel module that doesn't suck :S
+12:01 < jtanx> :S let's hope it doesn't get to that stage
+20:12 < jtanx> the pressure regulator has a 1-5vdc analogue output
+20:12 < jtanx> is this considered one of the pressure sensors?
+20:14 < jtanx> or maybe it's just not used
+21:50 -!- jtanx [
[email protected]] has quit ["ChatZilla 0.9.90.1 [Firefox 24.0/20130910160258]"]
+--- Day changed Mon Sep 23 2013
+08:51 -!- jtanx [
[email protected]] has quit ["ChatZilla 0.9.90.1 [Firefox 24.0/20130910160258]"]
+20:55 -!- jtanx [
[email protected]] has quit ["ChatZilla 0.9.90.1 [Firefox 24.0/20130910160258]"]
+22:33 -!- Irssi: #mctxuwa_softdev: Total of 2 nicks [0 ops, 0 halfops, 0 voices, 2 normal]
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
// Initialise pins used
GPIO_Export(GPIO1_16);
PWM_Export(EHRPWM0A);
+ PWM_Export(EHRPWM0B);
}
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
+#include <ctype.h>
+#include "options.h"
/**
* Structure to represent a GPIO pin
*/
typedef struct
{
- FILE * file_value;
+ int fd_value;
} ADC_Pin;
/**
void GPIO_Export(int pin)
{
if (pin < 0 || pin > GPIO_NUM_PINS)
- Fatal("Invalid pin number %d", pin);
+ {
+ Abort("Invalid pin number %d", 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);
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);
}
/**
{
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);
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);
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", pin);
+ fprintf(export, "%d\n", 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));
+ {
+ 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);
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);
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);
*/
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));
+ 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)
+ {
+ Abort("Couldn't open ADC %d device file %s - %s", i, g_buffer, strerror(errno));
+ }
- setbuf(g_adc[i].file_value, NULL);
+ //setbuf(g_adc[i].file_value, NULL);
}
}
void ADC_Unexport()
{
for (int i = 0; i < ADC_NUM_PINS; ++i)
- fclose(g_adc[i].file_value);
+ close(g_adc[i].fd_value);
}
/**
*/
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));
+ if (pwrite(g_gpio[pin].fd_direction, "out", 3, 0) != 3)
+ {
+ Abort("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));
+ if (pwrite(g_gpio[pin].fd_value, &c, 1, 0) != 1)
+ {
+ Abort("Couldn't read GPIO %d value - %s", pin, strerror(errno));
+ }
}
*/
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));
+ if (pwrite(g_gpio[pin].fd_direction, "in", 2, 0) != 2)
+ Log(LOGERR,"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));
+ if (pread(g_gpio[pin].fd_value, &c, 1, 0) != 1)
+ Log(LOGERR,"Couldn't read GPIO %d value - %s", pin, strerror(errno));
return (c == '1');
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));
+ if (pwrite(g_pwm[pin].fd_run, "0", 1, 0) != 1)
+ {
+ Abort("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));
-
+ if (pwrite(g_pwm[pin].fd_polarity, &c, 1, 0) != 1)
+ {
+ 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));
-
- if (pwrite(g_pwm[pin].fd_run, "1", 1*sizeof(char), 0) != 1)
- Fatal("Couldn't start 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)
+ {
+ Abort("Couldn't start PWM %d - %s", pin, strerror(errno));
+ }
}
*/
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));
-
+ if (pwrite(g_pwm[pin].fd_run, "0", 1, 0) != 1)
+ {
+ Abort("Couldn't stop PWM %d - %s", pin, strerror(errno));
+ }
}
/**
* @param id - The ID of the ADC pin to read
* @returns - The reading of the ADC channel
*/
-long ADC_Read(int id)
+int 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)
+ char adc_str[ADC_DIGITS] = "";
+ lseek(g_adc[id].fd_value, 0, SEEK_SET);
+
+ int i = 0;
+ for (i = 0; i < ADC_DIGITS-1; ++i)
{
- if (adc_val[i] == '\n')
- adc_val[i] = '\0';
+ if (read(g_adc[id].fd_value, adc_str+i, 1) != 1)
+ break;
+ if (adc_str[i] == '\n')
+ {
+ adc_str[i] = '\0';
+ break;
+ }
}
char * end;
- long val = strtol(adc_val, &end, 10);
+ int val = strtol(adc_str, &end, 10);
if (*end != '\0')
{
- Log(LOGERR, "Reading ADC%d gives %s - invalid!", id, adc_val);
- }
- //Log(LOGDEBUG, "Returns %lu", val);
- return val;
+ Log(LOGERR, "Read non integer from ADC %d - %s", id, adc_str);
+ }
+ return val;
}
extern bool GPIO_Read(int pin);
extern void GPIO_Set(int pin, bool value);
-extern long ADC_Read(int pin);
+extern int 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);
#define TIMEVAL_DIFF(tv1, tv2) ((tv1).tv_sec - (tv2).tv_sec + 1e-6 * ((tv1).tv_usec - (tv2).tv_usec))
+
+
#endif //_COMMON_H
#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
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;
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.
funct = unspecified_funct;
syslog(LOG_CRIT, "FATAL: %s (%s:%d) - %s", funct, file, line, buffer);
+
exit(EXIT_FAILURE);
}
#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};
#include "sensor.h"
#include "actuator.h"
#include "control.h"
+#include "bbb_pin_defines.h"
// --- Standard headers --- //
#include <syslog.h> // for system logging
*/
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
+ g_options.adc_device_path = ADC_DEVICE_PATH;
Log(LOGDEBUG, "Called as %s with %d arguments.", g_options.program, argc);
+
+ for (int i = 1; i < argc; ++i)
+ {
+ if (argv[i][0] != '-')
+ Fatal("Unexpected argv[%d] - %s", i, argv[i]);
+
+ if (i+1 >= argc || argv[i+1][0] == '-')
+ Fatal("No argument following switch %s", argv[i]);
+
+ if (strlen(argv[i]) > 2)
+ Fatal("Human readable switches are not supported.");
+
+ switch (argv[i][1])
+ {
+ case 'a':
+ g_options.adc_device_path = argv[i+1];
+ Log(LOGINFO, "ADC Device Path: %s", argv[i+1]);
+ ++i;
+ break;
+ default:
+ Fatal("Unrecognised switch %s", argv[i]);
+ break;
+ }
+ }
}
/**
*/
int main(int argc, char ** argv)
{
+ // Open log before calling ParseArguments (since ParseArguments may call the Log functions)
+ openlog("mctxserv", LOG_PID | LOG_PERROR, LOG_USER);
+ Log(LOGINFO, "Server started");
+
ParseArguments(argc, argv);
//Open the system log
- openlog("mctxserv", LOG_PID | LOG_PERROR, LOG_USER);
- Log(LOGINFO, "Server started");
+
// signal handler
//TODO: Make this work
/*
*/
Sensor_Init();
Actuator_Init();
+ Pin_Init();
//Sensor_StartAll("test");
//Actuator_StartAll("test");
const char *ret;
//Sensor_StopAll();
//Actuator_StopAll();
+ Pin_Close();
+
Cleanup();
return 0;
}
/** Time at which program exits **/
struct timeval end_time;
+ /** 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 **/
--- /dev/null
+/**
+ * @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
--- /dev/null
+/**
+ * @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
#spawn-fcgi -p9005 -n ./valgrind.sh
# Use this to run the server normally
#./stream &
-spawn-fcgi -p9005 -n ./server
+
+# Check running as root
+if [ "$(whoami)" != "root" ]; then
+ (echo "Run $0 as root.") 1>&2
+ exit 1
+fi
+
+# Check existence of program
+if [ ! -e "server" ]; then
+ (echo "Rebuild server.") 1>&2;
+ exit 1
+fi
+
+# Identify cape-manager slots
+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
+# Find adc_device_path
+# NOTE: This has to be passed as a parameter, because it is not always the same. For some unfathomable reason. Hooray.
+adc_device_path=$(dirname $(find /sys -name *AIN0))
+
+
+# Run the program with parameters
+# TODO: Can tell spawn-fcgi to run the program as an unprivelaged user?
+# But first will have to work out how to set PWM/GPIO as unprivelaged user
+fails=0
+while [ $fails -lt 10 ]; do
+ spawn-fcgi -p9005 -n -- ./server -a "$adc_device_path"
+ if [ "$?" == "0" ]; then
+ exit 0
+ fi
+ fails=$(( $fails + 1 ))
+ (echo "Restarting server after Fatal Error #$fails") 1>&2
+
+done
+(echo "Server had too many Fatal Errors ($fails)") 1>&2
+exit $fails
+
}
// 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);
}
/**
{
if( value > thresholds[id].max_error || value < thresholds[id].min_error)
{
- Log(LOGERR, "Sensor %s is above or below its safety value of %f or %f\n", g_sensor_names[id],thresholds[id].max_error, thresholds[id].min_error);
+ Log(LOGERR, "Sensor %s at %f is above or below its safety value of %f or %f\n", value, g_sensor_names[id],thresholds[id].max_error, thresholds[id].min_error);
//new function that stops actuators?
//Control_SetMode(CONTROL_EMERGENCY, NULL)
}
else if( value > thresholds[id].max_warn || value < thresholds[id].min_warn)
{
- Log(LOGWARN, "Sensor %s is above or below its warning value of %f or %f\n", g_sensor_names[id],thresholds[id].max_warn, thresholds[id].min_warn);
+ Log(LOGWARN, "Sensor %s at %f is above or below its warning value of %f or %f\n", value, g_sensor_names[id],thresholds[id].max_warn, thresholds[id].min_warn);
}
}
// Read value based on Sensor Id
switch (s->id)
{
- case ANALOG_REALTEST:
+ case 2:
{
static bool set = false;
- GPIO_Set(GPIO0_30, true);
+ //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;
}
g_numSensors = 1
g_storeTime = []
g_key = null
+ g_led = 1
+
+ $.fn.ledFlash = function()
+ {
+ //alert("Flash LED");
+ if (g_led == 0)
+ {
+ $.ajax({url : "api/actuators", data : {id : 0, set : 1}})
+ g_led = 1
+ $("#led").html("LED On");
+ }
+ else
+ {
+ $.ajax({url : "api/actuators", data : {id : 0, set : 0}})
+ g_led = 0
+ $("#led").html("LED Off");
+ }
+ }
$.fn.pruneSensorData = function(id)
{
$("#plots").html(plotsHTML)
controlHTML = "<h2 id=control0>Controls</h2>\n"
- controlHTML += "<p> Pressure: <input type=text id=control0_value value=\"100\"/>"
- controlHTML += "<button id=actuator0 onclick=\"$(document).setPressure()\">SET</button> </p>"
+ controlHTML += "<button id=led onclick=\"$(document).ledFlash()\">LED On</button>"
$("#controls").html(controlHTML)