summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Van Doorn <vandoorn.nick@gmail.com>2018-11-15 13:10:01 -0800
committerGitHub <noreply@github.com>2018-11-15 13:10:01 -0800
commit158fd00543e468675c83f9ad23a4ce47a716f94f (patch)
tree9f75c16e478a1518f7f84284678564823dc04e15
parent3da7cd6011d084fcb72b6f696319374ec59c2cd6 (diff)
parent4e379259292be2709834ee0d75e212f80b14e1b0 (diff)
Merge pull request #8 from brnkl/documentation
Documentation
-rw-r--r--.gitmodules0
-rw-r--r--Makefile6
-rw-r--r--motionMonitor/Component.cdef4
-rw-r--r--readme.md76
-rw-r--r--util/util.c366
-rw-r--r--util/util.h77
6 files changed, 527 insertions, 2 deletions
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.gitmodules
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..d15a379
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,6 @@
+wp85:
+ mkapp -t wp85 motionService.adef -b
+clean:
+ rm -r _build_* \
+ *.update \
+ *.app
diff --git a/motionMonitor/Component.cdef b/motionMonitor/Component.cdef
index 9627adf..ea17866 100644
--- a/motionMonitor/Component.cdef
+++ b/motionMonitor/Component.cdef
@@ -1,7 +1,7 @@
cflags:
{
-std=c99
- -I$BRNKL_ROOT/apps/util
+ -I$CURDIR/../util
}
requires:
@@ -23,5 +23,5 @@ provides:
sources:
{
motionMonitor.c
- $BRNKL_ROOT/apps/util/util.c
+ $CURDIR/../util/util.c
}
diff --git a/readme.md b/readme.md
index e69de29..3aa0175 100644
--- a/readme.md
+++ b/readme.md
@@ -0,0 +1,76 @@
+MangOH Motion Service
+======
+This application is designed to operate on a [MongOH Red](https://mangoh.io/mangoh-red-new) WP85 board. Using **general input output** this project uses pthreads to probe the onboard bmi160 chip intermittently in order to detect a significant motion on the board.
+
+## Prerequisites
+
+When cloning use ``git clone https://github.com/brnkl/motion-service.git``.
+
+
+## Building
+Compile the project using
+
+wp85: ``make wp85``
+
+## Setting Variables
+To change the sensitivity of impact detection you must edit the `motionMonitor/motionMonitor.c` file.
+The Accelerometer measures acceleration in 3 dimensions, X, Y, and Z. These dimensions of acceleration are recorded and the magnitude of their resulting vector is calculated using ``double impactMagnitude = sqrt(x * x + y * y + z * z);``. As visualized in the image below.
+
+![Magnitude](https://www.intmath.com/vectors/img/235-3D-vector.png)
+
+
+`#define DEFAULT_THRESHOLD_MS2 17` determines the magnitude of the resulting vector that will trigger the application to detect a sudden impact.
+
+If adjusting the value of `DEFAUTL_THRESHOLD_MS2` keep in mind that gravity implies a motionless magnitude of -9.8m/s^2.
+
+## Bindings
+App.adef
+```
+...
+bindings:
+{
+ myClientApp.myComponent.brnkl_motion -> motionService.brnkl_motion
+}
+...
+```
+Component.cdef
+```
+...
+requires:
+{
+ api:
+ {
+ brnkl_motion.api
+ }
+}
+...
+```
+
+## Example
+For getting the current acceleration
+```C
+struct Acceleration{
+ double x;
+ double y;
+ double z;
+};
+
+struct Acceleration v = value;
+
+le_result_t result = brnkl_motion_getCurrentAccleration(&v->x, &v->y, &v->z);
+```
+To get a list of all recent impacts.
+
+```
+ double xAcc[N_MAX_IMPACT_VALUES], yAcc[N_MAX_IMPACT_VALUES], zAcc[N_MAX_IMPACT_VALUES];
+
+ uint64_t timestamps[N_MAX_IMPACT_VALUES];
+
+ size_t xSize = N_MAX_IMPACT_VALUES, ySize = N_MAX_IMPACT_VALUES,
+ zSize = N_MAX_IMPACT_VALUES, timestampsSize = N_MAX_IMPACT_VALUES;
+
+ le_result_t r = brnkl_motion_getSuddenImpact(
+ xAcc, &xSize, yAcc, &ySize, zAcc, &zSize, timestamps, &timestampsSize);
+
+```
+
diff --git a/util/util.c b/util/util.c
new file mode 100644
index 0000000..3042c22
--- /dev/null
+++ b/util/util.c
@@ -0,0 +1,366 @@
+#include "util.h"
+#include "legato.h"
+#include <termios.h>
+
+le_result_t readFromFile(const char* path,
+ void* value,
+ int (*scanCallback)(FILE* f, void* val)) {
+ FILE* f = fopen(path, "r");
+ if (f == NULL) {
+ LE_WARN("Couldn't open '%s' - %m", path);
+ return LE_IO_ERROR;
+ }
+ int numScanned = scanCallback(f, value);
+ if (numScanned != 1)
+ return LE_FORMAT_ERROR;
+ fclose(f);
+ return LE_OK;
+}
+
+int scanIntCallback(FILE* f, void* value) {
+ int* val = value;
+ return fscanf(f, "%d", val);
+}
+
+int scanDoubleCallback(FILE* f, void* value) {
+ double* val = value;
+ return fscanf(f, "%lf", val);
+}
+
+le_result_t ioutil_readIntFromFile(const char* path, int* value) {
+ return readFromFile(path, value, scanIntCallback);
+}
+
+le_result_t ioutil_readDoubleFromFile(const char* path, double* value) {
+ return readFromFile(path, value, scanDoubleCallback);
+}
+
+le_result_t writeToFile(const char* path,
+ void* value,
+ size_t size,
+ size_t count,
+ const char* openMode) {
+ FILE* f = fopen(path, openMode);
+ if (f == NULL) {
+ LE_WARN("Failed to open %s for writing", path);
+ return LE_IO_ERROR;
+ }
+ fwrite(value, size, count, f);
+ fflush(f);
+ fclose(f);
+ return LE_OK;
+}
+
+le_result_t ioutil_writeToFile(const char* path,
+ void* value,
+ size_t size,
+ size_t count) {
+ return writeToFile(path, value, size, count, "w");
+}
+
+le_result_t ioutil_appendToFile(const char* path,
+ void* value,
+ size_t size,
+ size_t count) {
+ return writeToFile(path, value, size, count, "a");
+}
+
+le_result_t util_flattenRes(le_result_t* res, int nRes) {
+ for (int i = 0; i < nRes; i++) {
+ if (res[i] != LE_OK)
+ return res[i];
+ }
+ return LE_OK;
+}
+
+int util_getUnixDatetime() {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec;
+}
+
+/**
+ * Get the last modified datetime
+ * of the file at path
+ */
+time_t util_getMTime(char* path) {
+ struct stat st;
+ if (stat(path, &st) != 0)
+ return -1;
+ else
+ return st.st_mtime;
+}
+
+bool util_fileExists(const char* path) {
+ struct stat st;
+ return stat(path, &st) == 0;
+}
+
+bool util_alreadyMounted(const char* devPath) {
+ char content[2048];
+ FILE* f = fopen("/proc/mounts", "r");
+ if (f == NULL) {
+ return false;
+ }
+ fread(content, sizeof(char), sizeof(content), f);
+ // if this ref is non-null, we found a match
+ return strstr(content, devPath) != NULL;
+}
+
+uint64_t GetCurrentTimestamp(void) {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ uint64_t utcMilliSec =
+ (uint64_t)(tv.tv_sec) * 1000 + (uint64_t)(tv.tv_usec) / 1000;
+ return utcMilliSec;
+}
+
+// TODO verify this is working
+le_result_t gpio_exportPin(char* pin) {
+ int len = strlen(pin);
+ return ioutil_writeToFile("/sys/class/gpio/export", &pin, sizeof(char), len);
+}
+
+le_result_t gpio_unexportPin(char* pin) {
+ int len = strlen(pin);
+ return ioutil_writeToFile("/sys/class/gpio/unexport", &pin, sizeof(char),
+ len);
+}
+
+void getGpioPath(char* outputStr, char* pin, char* subDir) {
+ sprintf(outputStr, "/sys/class/gpio/gpio%s/%s", pin, subDir);
+}
+
+le_result_t gpio_setDirection(char* pin, char* direction) {
+ char path[100];
+ getGpioPath(path, pin, "direction");
+ return ioutil_writeToFile(path, direction, sizeof(char), strlen(direction));
+}
+
+le_result_t gpio_setPull(char* pin, char* pull) {
+ char path[100];
+ getGpioPath(path, pin, "pull");
+ return ioutil_writeToFile(path, pull, sizeof(char), strlen(pull));
+}
+
+le_result_t gpio_pullDown(char* pin) {
+ return gpio_setPull(pin, "down");
+}
+
+le_result_t gpio_pullUp(char* pin) {
+ return gpio_setPull(pin, "up");
+}
+
+le_result_t gpio_setInput(char* pin) {
+ return gpio_setDirection(pin, "in");
+}
+
+le_result_t gpio_setOutput(char* pin) {
+ return gpio_setDirection(pin, "out");
+}
+
+le_result_t gpio_setActiveState(char* pin, bool isActiveLow) {
+ // Any non zero value toggles the existing value
+ // so we must read the existing value first
+ char path[100];
+ int isActiveLowSet;
+ getGpioPath(path, pin, "active_low");
+ le_result_t readRes = ioutil_readIntFromFile(path, &isActiveLowSet);
+ le_result_t writeRes = LE_OK;
+ if (isActiveLow != isActiveLowSet) {
+ writeRes = ioutil_writeToFile(path, "1", sizeof(char), 1);
+ }
+ return readRes == LE_OK && writeRes == LE_OK ? LE_OK : LE_FAULT;
+}
+
+le_result_t gpio_isActive(char* pin, bool* isActive) {
+ char path[50];
+ getGpioPath(path, pin, "value");
+ int val;
+ le_result_t readRes = ioutil_readIntFromFile(path, &val);
+ *isActive = val;
+ return readRes;
+}
+
+le_result_t gpio_setValue(char* pin, bool state) {
+ char path[50];
+ getGpioPath(path, pin, "value");
+ char* strState = state ? "1" : "0";
+ return ioutil_writeToFile(path, &strState, sizeof(char), strlen(strState));
+}
+
+le_result_t gpio_setLow(char* pin) {
+ return gpio_setValue(pin, LOW);
+}
+
+le_result_t gpio_setHigh(char* pin) {
+ return gpio_setValue(pin, HIGH);
+}
+
+void* util_find(Functional* f) {
+ f->args.i = 0;
+ while (f->args.i < f->n) {
+ if (f->callback(&f->args)) {
+ return f->derefCallback(f->args.i, f->args.arr);
+ }
+ f->args.i++;
+ }
+ return NULL;
+}
+
+void util_listDir(const char* dir, char* dest, size_t size) {
+ struct dirent* de;
+ char toConcat[1024];
+ DIR* dr = opendir(dir);
+ if (dr == NULL)
+ return;
+ while ((de = readdir(dr)) != NULL) {
+ if (de->d_name[0] != '.') {
+ snprintf(toConcat, size, "%s,", de->d_name);
+ strncat(dest, toConcat, size);
+ }
+ }
+ closedir(dr);
+}
+
+/**
+ * Convert an integer baud rate to a speed_t
+ */
+speed_t fd_convertBaud(int baud) {
+ speed_t b;
+ switch (baud) {
+ case 50:
+ b = B50;
+ break;
+ case 75:
+ b = B75;
+ break;
+ case 110:
+ b = B110;
+ break;
+ case 134:
+ b = B134;
+ break;
+ case 150:
+ b = B150;
+ break;
+ case 200:
+ b = B200;
+ break;
+ case 300:
+ b = B300;
+ break;
+ case 600:
+ b = B600;
+ break;
+ case 1200:
+ b = B1200;
+ break;
+ case 1800:
+ b = B1800;
+ break;
+ case 2400:
+ b = B2400;
+ break;
+ case 9600:
+ b = B9600;
+ break;
+ case 19200:
+ b = B19200;
+ break;
+ case 38400:
+ b = B38400;
+ break;
+ case 57600:
+ b = B57600;
+ break;
+ case 115200:
+ b = B115200;
+ break;
+ case 230400:
+ b = B230400;
+ break;
+ case 921600:
+ b = B921600;
+ break;
+ default:
+ b = -2;
+ }
+ return b;
+}
+
+/**
+ * Open a serial connection on device
+ *
+ * Lifted from here
+ * https://github.com/WiringPi/WiringPi/blob/master/wiringPi/wiringSerial.c
+ */
+int fd_openSerial(const char* device, int baud) {
+ struct termios options;
+ speed_t binaryBaud = fd_convertBaud(baud);
+ int status, fd;
+ if ((fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK)) == -1)
+ return -1;
+ fcntl(fd, F_SETFL, O_RDWR);
+ tcgetattr(fd, &options);
+ cfmakeraw(&options);
+ cfsetispeed(&options, binaryBaud);
+ cfsetospeed(&options, binaryBaud);
+
+ options.c_cflag |= (CLOCAL | CREAD);
+ options.c_cflag &= ~PARENB;
+ options.c_cflag &= ~CSTOPB;
+ options.c_cflag &= ~CSIZE;
+ options.c_cflag |= CS8;
+ options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
+ options.c_oflag &= ~OPOST;
+
+ options.c_cc[VMIN] = 0;
+ options.c_cc[VTIME] = 10; // Ten seconds (100 deciseconds)
+
+ tcsetattr(fd, TCSANOW | TCSAFLUSH, &options);
+
+ ioctl(fd, TIOCMGET, &status);
+
+ status |= TIOCM_DTR;
+ status |= TIOCM_RTS;
+
+ ioctl(fd, TIOCMSET, &status);
+ usleep(10000); // 10mS
+ return fd;
+}
+
+int fd_puts(const int fd, const char* s) {
+ return write(fd, s, strlen(s));
+}
+
+int fd_getChar(const int fd) {
+ uint8_t x;
+
+ if (read(fd, &x, 1) != 1)
+ return -1;
+
+ return ((int)x) & 0xFF;
+}
+
+void fd_flush(const int fd) {
+ // tcflush(fd, TCIOFLUSH);
+ tcdrain(fd);
+}
+
+void fd_flushInput(const int fd) {
+ tcflush(fd, TCIFLUSH);
+}
+
+int fd_dataAvail(int fd, int* data) {
+ return ioctl(fd, FIONREAD, data);
+}
+
+double util_avgDouble(double* readings, int nReadings) {
+ double sum = 0;
+ for (int i = 0; i < nReadings; i++) {
+ sum += readings[i];
+ }
+
+ return sum / nReadings;
+}
diff --git a/util/util.h b/util/util.h
new file mode 100644
index 0000000..06ef2fb
--- /dev/null
+++ b/util/util.h
@@ -0,0 +1,77 @@
+#ifndef UTIL_H
+#define UTIL_H
+
+#include "legato.h"
+#include <termios.h>
+
+#define HIGH 1
+#define LOW 0
+
+typedef struct {
+ int i;
+ void* arr;
+ void* ctxp;
+} FunctionalArgs;
+
+typedef struct {
+ int n; // number of elements in array
+ bool (*callback)(FunctionalArgs* args); // callback applied to arr[i]
+ void* (*derefCallback)(int i, void* j); // callback used to deference arr[i]
+ FunctionalArgs args;
+} Functional;
+
+// ioutil
+le_result_t readFromFile(const char* path,
+ void* value,
+ int (*scanCallback)(FILE* f, void* val));
+int scanDoubleCallback(FILE* f, void* value);
+le_result_t ioutil_readIntFromFile(const char* path, int* value);
+le_result_t ioutil_readDoubleFromFile(const char* filePath, double* value);
+le_result_t ioutil_writeToFile(const char* path,
+ void* value,
+ size_t size,
+ size_t count);
+
+le_result_t ioutil_appendToFile(const char* path,
+ void* value,
+ size_t size,
+ size_t count);
+
+// TODO fix this name (no PascalCase)
+uint64_t GetCurrentTimestamp(void);
+time_t util_getMTime(char* path);
+int util_getUnixDatetime();
+le_result_t util_flattenRes(le_result_t* res, int nRes);
+bool util_fileExists(const char* path);
+bool util_alreadyMounted(const char* devPath);
+double util_avgDouble(double* readings, int nReadings);
+
+// TODO verify this is working
+le_result_t gpio_exportPin(char* pin);
+le_result_t gpio_unexportPin(char* pin);
+void getGpioPath(char* outputStr, char* pin, char* subDir);
+le_result_t gpio_setDirection(char* pin, char* direction);
+le_result_t gpio_setInput(char* pin);
+le_result_t gpio_setOutput(char* pin);
+le_result_t gpio_setActiveState(char* pin, bool isActiveLow);
+le_result_t gpio_isActive(char* pin, bool* isActive);
+le_result_t gpio_setValue(char* pin, bool state);
+le_result_t gpio_setLow(char* pin);
+le_result_t gpio_setHigh(char* pin);
+le_result_t gpio_setPull(char* pin, char* pull);
+le_result_t gpio_pullDown(char* pin);
+le_result_t gpio_pullUp(char* pin);
+
+void* util_find(Functional* f);
+
+void util_listDir(const char* dir, char* dest, size_t size);
+
+int fd_openSerial(const char* device, int baud);
+speed_t fd_convertBaud(int baud);
+int fd_puts(const int fd, const char* s);
+int fd_getChar(const int fd);
+void fd_flush(const int fd);
+int fd_dataAvail(int fd, int* data);
+void fd_flushInput(const int fd);
+
+#endif