aboutsummaryrefslogtreecommitdiff
path: root/recipes-demo/de10-nano-adxl-apps
diff options
context:
space:
mode:
Diffstat (limited to 'recipes-demo/de10-nano-adxl-apps')
-rw-r--r--recipes-demo/de10-nano-adxl-apps/de10-nano-adxl-apps.bb95
-rw-r--r--recipes-demo/de10-nano-adxl-apps/files/LICENSE22
-rw-r--r--recipes-demo/de10-nano-adxl-apps/files/README_SANDBOX.txt168
-rw-r--r--recipes-demo/de10-nano-adxl-apps/files/README_SRC.txt10
-rwxr-xr-xrecipes-demo/de10-nano-adxl-apps/files/adxl_calibrate.sh20
-rw-r--r--recipes-demo/de10-nano-adxl-apps/files/bubble_demo.c609
-rwxr-xr-xrecipes-demo/de10-nano-adxl-apps/files/build_bubble_demo.sh22
-rwxr-xr-xrecipes-demo/de10-nano-adxl-apps/files/build_tap_detect.sh22
-rwxr-xr-xrecipes-demo/de10-nano-adxl-apps/files/build_watch_adxl.sh22
-rw-r--r--recipes-demo/de10-nano-adxl-apps/files/tap_detect.c103
-rw-r--r--recipes-demo/de10-nano-adxl-apps/files/watch_adxl.c277
11 files changed, 1370 insertions, 0 deletions
diff --git a/recipes-demo/de10-nano-adxl-apps/de10-nano-adxl-apps.bb b/recipes-demo/de10-nano-adxl-apps/de10-nano-adxl-apps.bb
new file mode 100644
index 0000000..c301cfc
--- /dev/null
+++ b/recipes-demo/de10-nano-adxl-apps/de10-nano-adxl-apps.bb
@@ -0,0 +1,95 @@
+SUMMARY = "Example applications for DE10-Nano accelerometer"
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=d252b8b27e3e6ea89c9c6912b3c4373d"
+
+PACKAGE_ARCH = "${MACHINE_ARCH}"
+
+PR = "r0"
+
+SRC_URI = "\
+ file://adxl_calibrate.sh \
+ file://build_bubble_demo.sh \
+ file://build_tap_detect.sh \
+ file://build_watch_adxl.sh \
+ file://LICENSE \
+ file://bubble_demo.c \
+ file://README_SANDBOX.txt \
+ file://README_SRC.txt \
+ file://tap_detect.c \
+ file://watch_adxl.c \
+"
+
+ADXL_BIN_FILES = "bubble_demo"
+
+ADXL_SRC_FILES = "build_bubble_demo.sh"
+ADXL_SRC_FILES += "LICENSE"
+ADXL_SRC_FILES += "bubble_demo.c"
+ADXL_SRC_FILES += "README_SRC.txt"
+
+ADXL_SANDBOX_FILES = "adxl_calibrate.sh"
+ADXL_SANDBOX_FILES += "build_tap_detect.sh"
+ADXL_SANDBOX_FILES += "build_watch_adxl.sh"
+ADXL_SANDBOX_FILES += "LICENSE"
+ADXL_SANDBOX_FILES += "README_SANDBOX.txt"
+ADXL_SANDBOX_FILES += "tap_detect.c"
+ADXL_SANDBOX_FILES += "watch_adxl.c"
+
+S = "${WORKDIR}"
+
+do_configure () {
+
+ rm -f bubble_demo
+}
+do_compile () {
+
+ ${CC} \
+ -march=armv7-a \
+ -mfloat-abi=hard \
+ -mfpu=vfp3 \
+ -mthumb-interwork \
+ -mthumb \
+ -O2 -D_FORTIFY_SOURCE=2 \
+ -g \
+ -feliminate-unused-debug-types \
+ -std=gnu99 \
+ -W \
+ -Wall \
+ -Werror \
+ -Wc++-compat \
+ -Wwrite-strings \
+ -Wstrict-prototypes \
+ -Wformat -Wformat-security \
+ -pedantic \
+ -fstack-protector-strong \
+ -z noexecstack \
+ -z relro -z now \
+ -o "bubble_demo" \
+ "bubble_demo.c"
+}
+
+do_install () {
+
+ cd ${S}
+
+ install -d ${D}/examples/adxl/bin
+ cp -a ${ADXL_BIN_FILES} ${D}/examples/adxl/bin
+
+ install -d ${D}/examples/adxl/src
+ cp -a ${ADXL_SRC_FILES} ${D}/examples/adxl/src
+
+ install -d ${D}/examples/adxl/sandbox
+ cp -a ${ADXL_SANDBOX_FILES} ${D}/examples/adxl/sandbox
+
+ rm -f adxl_src.tgz
+ tar czf adxl_src.tgz -C ${D}/examples/adxl/src ${ADXL_SRC_FILES}
+ cp -a adxl_src.tgz ${D}/examples/adxl
+
+ rm -f adxl_sandbox.tgz
+ tar czf adxl_sandbox.tgz -C ${D}/examples/adxl/sandbox ${ADXL_SANDBOX_FILES}
+ cp -a adxl_sandbox.tgz ${D}/examples/adxl
+}
+
+INHIBIT_PACKAGE_DEBUG_SPLIT = "1"
+PACKAGES = "${PN}"
+FILES_${PN} += "examples/adxl/"
+
diff --git a/recipes-demo/de10-nano-adxl-apps/files/LICENSE b/recipes-demo/de10-nano-adxl-apps/files/LICENSE
new file mode 100644
index 0000000..ab84792
--- /dev/null
+++ b/recipes-demo/de10-nano-adxl-apps/files/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+Copyright (c) 2016 Intel Corporation
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+
diff --git a/recipes-demo/de10-nano-adxl-apps/files/README_SANDBOX.txt b/recipes-demo/de10-nano-adxl-apps/files/README_SANDBOX.txt
new file mode 100644
index 0000000..6ac13df
--- /dev/null
+++ b/recipes-demo/de10-nano-adxl-apps/files/README_SANDBOX.txt
@@ -0,0 +1,168 @@
+This readme describes how the Analog Devices ADXL345 Input 3-Axis Digital
+Accelerometer Linux Driver is deployed on the DE10 Nano target environment. You
+may find the following references useful for more information on this topic as
+well.
+
+<linux-source-tree>/drivers/input/misc/adxl34x.c
+<linux-source-tree>/drivers/input/misc/adxl34x.h
+<linux-source-tree>/drivers/input/misc/adxl34x-i2c.c
+<linux-source-tree>/drivers/input/misc/adxl34x-spi.c
+<linux-source-tree>/include/linux/input/adxl34x.h
+
+http://wiki.analog.com/resources/tools-software/linux-drivers/input-misc/adxl345
+
+If you cut and paste the following function into a console running on the DE10
+Nano target you can extract the useful information contained in the run time
+device tree maintained by the kernel in the procfs.
+################################################################################
+# find adxl34x in device tree
+################################################################################
+function find_adxl_dt () {
+for NEXT in $(find -L /proc/device-tree -name "compatible" | sort)
+do
+cat ${NEXT} | grep "adi,adxl345" > /dev/null && {
+ADXL_DIRNAME="$(dirname ${NEXT})"
+echo ${ADXL_DIRNAME}
+echo -e "\tcompatible = '$(cat ${ADXL_DIRNAME}/compatible)'"
+echo -e "\t name = '$(cat ${ADXL_DIRNAME}/name)'"
+REG_HEX="$(hexdump -v -e '"0x"' -e '4/1 "%02x"' "${ADXL_DIRNAME}/reg")"
+echo -e "\t reg = '${REG_HEX}'"
+}
+done
+}
+################################################################################
+
+When we run the function above on the DE10 Nano target it searches for nodes
+containing the 'compatible' string containing 'adi,adxl345' which is the
+identifier of the ADI accelerometer in our system. The function then prints the
+path to the node that it found and extracts the compatible string and 'name' and
+'reg' properties and prints those statistics out as well.
+
+root@de10-nano:~# find_adxl_dt
+/proc/device-tree/soc/i2c@ffc04000/adxl345@0
+ compatible = 'adi,adxl345'
+ name = 'adxl345'
+ reg = '0x00000053'
+root@de10-nano:~#
+
+We can tell from the above output that this accelerometer is attached to the
+I2C controller at 0xFFC04000, and the I2C address of the accelerometer is 0x53.
+
+There are a number of ways that we can now find the sysfs resources that refer
+to this hardware:
+
+root@de10-nano:~# ls /sys/bus/i2c
+devices drivers_autoprobe uevent
+drivers drivers_probe
+root@de10-nano:~# ls /sys/bus/i2c/devices/
+0-0053 i2c-0
+root@de10-nano:~# ls /sys/bus/i2c/drivers
+adxl34x dummy ltc2978 pmbus
+at24 lcd-comm max1619 rtc-ds1307
+root@de10-nano:~# ls /sys/bus/i2c/drivers/adxl34x/
+0-0053 bind uevent unbind
+root@de10-nano:~#
+
+In the '/sys/bus/i2c/' directory there is a 'devices' and 'drivers' directory.
+The 'devices' directory contains a link called '0-0053' which represents I2C bus
+0 device address 0x53. The 'drivers' directory contains a 'adxl34x' directory
+which in turn contains a link called '0-0053' as well. Both of these links
+point into the actual device entry:
+
+root@de10-nano:~# ls -l /sys/bus/i2c/devices/0-0053
+lrwxrwxrwx 1 root root 0 Jan 1 1970 /sys/bus/i2c/devices/0-0053 -> ../../../devices/platform/soc/ffc04000.i2c/i2c-0/0-0053
+root@de10-nano:~# ls -l /sys/bus/i2c/drivers/adxl34x/0-0053
+lrwxrwxrwx 1 root root 0 Jul 11 15:21 /sys/bus/i2c/drivers/adxl34x/0-0053 -> ../../../../devices/platform/soc/ffc04000.i2c/i2c-0/0-0053
+root@de10-nano:~#
+
+So if we look at the contents of the actual device directory we see the expected
+sysfs files provided by the adxl34x driver:
+
+root@de10-nano:~# ls /sys/devices/platform/soc/ffc04000.i2c/i2c-0/0-0053
+autosleep disable input name power subsystem
+calibrate driver modalias position rate uevent
+root@de10-nano:~#
+
+Some of these sysfs files are provided by the adxl34x driver to provide access
+from userspace into the configuration and settings of the driver. These files
+are 'autosleep', 'disable', 'calibrate', 'position', and 'rate'. Please see
+the adxl34x driver sources and documentation on how these files are used.
+
+The 'input' sysfs file provided in the device directory will tell us which input
+event device the adxl345 has been register as. If we follow this path we see:
+
+root@de10-nano:~# ls /sys/devices/platform/soc/ffc04000.i2c/i2c-0/0-0053/input/
+input0
+
+And following into 'input0' we see:
+
+root@de10-nano:~# ls /sys/devices/platform/soc/ffc04000.i2c/i2c-0/0-0053/input/input0/
+capabilities id name properties uniq
+device modalias phys subsystem
+event0 mouse0 power uevent
+root@de10-nano:~# cat /sys/devices/platform/soc/ffc04000.i2c/i2c-0/0-0053/input/input0/name
+ADXL34x accelerometer
+
+Now if we go into the 'event0' we can see the 'dev' entry that contains the
+device node details:
+
+root@de10-nano:~# ls /sys/devices/platform/soc/ffc04000.i2c/i2c-0/0-0053/input/input0/event0/
+dev device power subsystem uevent
+root@de10-nano:~# hexdump -Cv /sys/devices/platform/soc/ffc04000.i2c/i2c-0/0-0053/input/input0/event0/dev
+00000000 31 33 3a 36 34 0a |13:64.|
+00000006
+
+And if we then list '/dev/input/' looking for device major 13 and minor 64, we
+can see that indeed '/dev/input/event0' is our accelerometer input device.
+
+root@de10-nano:~# ls /dev/input/ -l
+total 0
+drwxr-xr-x 2 root root 80 Jul 9 16:25 by-path
+crw-rw---- 1 root input 13, 64 Jan 1 1970 event0
+crw-rw---- 1 root input 13, 65 Jul 9 16:25 event1
+crw-rw---- 1 root input 13, 63 Jul 9 16:25 mice
+crw-rw---- 1 root input 13, 32 Jan 1 1970 mouse0
+root@de10-nano:~#
+
+There is actually a very convenient way to discover the input device by using
+the 'by-path' directory like this:
+
+root@de10-nano:~# ls /dev/input/by-path/
+platform-ffc04000.i2c-event platform-soc:keys-event
+root@de10-nano:~# ls -l /dev/input/by-path/platform-ffc04000.i2c-event
+lrwxrwxrwx 1 root root 9 Jan 1 1970 /dev/input/by-path/platform-ffc04000.i2c-event -> ../event0
+root@de10-nano:~#
+
+--------------------------------------------------------------------------------
+Example programs and scripts
+--------------------------------------------------------------------------------
+This directory contains a few examples to demonstrate how to interact with the
+accelerometer on the DE10 Nano board. There is a shell script called
+'adxl_calibrate.sh' which shows how to calibrate the accelerometer. There is a
+C program called 'watch_adxl.c' that shows how to interact with the sysfs files
+and the input event node provided by the adxl34x driver. And there is a C
+program called 'tap_detect.c' which demonstrates how to detect the tap events
+that the accelerometer produces.
+
+To build the 'watch_adxl.c' application simply run the 'build_watch_adxl.sh'
+shell script. That will compile the 'watch_adxl.c' source file and produce the
+executable 'watch_adxl' application. Refer to the 'build_watch_adxl.sh' script
+to see how the application is actually compiled and refer to the C program
+source file for more details on how it actually works.
+
+To build the 'tap_detect.c' application simply run the 'build_tap_detect.sh'
+shell script. That will compile the 'tap_detect.c' source file and produce the
+executable 'tap_detect' application. Refer to the 'build_tap_detect.sh' script
+to see how the application is actually compiled and refer to the C program
+source file for more details on how it actually works.
+
+Refer to the 'adxl_calibrate.sh' source file for more details on how it
+actually works.
+
+Once you've built the applications, you can run both the script and the
+applications like this:
+
+./adxl_calibrate.sh <<< to run the script
+./watch_adxl <<< to run the program
+./tap_detect <<< to run the program
+
diff --git a/recipes-demo/de10-nano-adxl-apps/files/README_SRC.txt b/recipes-demo/de10-nano-adxl-apps/files/README_SRC.txt
new file mode 100644
index 0000000..bee2193
--- /dev/null
+++ b/recipes-demo/de10-nano-adxl-apps/files/README_SRC.txt
@@ -0,0 +1,10 @@
+To build the 'bubble_demo.c' application simply run the 'build_bubble_demo.sh'
+shell script. That will compile the 'bubble_demo.c' source file and produce the
+executable 'bubble_demo' application. Refer to the 'build_bubble_demo.sh'
+script to see how the application is actually compiled and refer to the C
+program source file for more details on how it actually works.
+
+Once you've built the application, you can run the applications like this:
+
+./bubble_demo
+
diff --git a/recipes-demo/de10-nano-adxl-apps/files/adxl_calibrate.sh b/recipes-demo/de10-nano-adxl-apps/files/adxl_calibrate.sh
new file mode 100755
index 0000000..3df7d36
--- /dev/null
+++ b/recipes-demo/de10-nano-adxl-apps/files/adxl_calibrate.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+SYSFS_DEVICE_DIR="/sys/devices/platform/soc/ffc04000.i2c/i2c-0/0-0053/"
+DEVFS_INPUT_EVENT_FILE="/dev/input/by-path/platform-ffc04000.i2c-event"
+
+# enabled adxl
+echo 0 > ${SYSFS_DEVICE_DIR}/disable
+
+# set the sample rate to maximum
+echo 15 > ${SYSFS_DEVICE_DIR}/rate
+
+# do not auto sleep
+echo 0 > ${SYSFS_DEVICE_DIR}/autosleep
+
+# read some samples
+hexdump -n 160 ${DEVFS_INPUT_EVENT_FILE} > /dev/null
+
+# store calibration
+echo 1 > ${SYSFS_DEVICE_DIR}/calibrate
+
diff --git a/recipes-demo/de10-nano-adxl-apps/files/bubble_demo.c b/recipes-demo/de10-nano-adxl-apps/files/bubble_demo.c
new file mode 100644
index 0000000..41b2019
--- /dev/null
+++ b/recipes-demo/de10-nano-adxl-apps/files/bubble_demo.c
@@ -0,0 +1,609 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <error.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include "linux/input.h"
+#include <dirent.h>
+#include <poll.h>
+#include <wait.h>
+
+#define INPUT_DEV_NODE "/dev/input/by-path/platform-ffc04000.i2c-event"
+#define SYSFS_DEVICE_DIR "/sys/devices/platform/soc/ffc04000.i2c/i2c-0/0-0053/"
+
+#define EV_CODE_X (0)
+#define EV_CODE_Y (1)
+#define EV_CODE_Z (2)
+
+int g_stop_running = 0;
+int g_termination_count = 0;
+
+void write_sysfs_cntl_file(const char *dir_name, const char *file_name,
+ const char *write_str);
+
+void poll_for_KEY0_press(void);
+
+void my_sig_child_handler(int signal_number) {
+ (void)signal_number;
+ g_stop_running = 1;
+}
+
+void my_termination_handler(int signal_number) {
+
+ int result;
+ pid_t child_pid;
+ int status;
+
+ if(g_termination_count > 0)
+ return;
+
+ g_termination_count++;
+
+ // enable heartbeat LED
+ write_sysfs_cntl_file("/sys/class/leds/hps_led0", "trigger",
+ "heartbeat");
+
+ // disable adxl
+ write_sysfs_cntl_file(SYSFS_DEVICE_DIR, "disable", "1");
+
+ result = kill(-(getpgrp()), SIGTERM);
+ if(result < 0) {
+ error(0, errno, "SIGTERM pgrp");
+ result = kill(-(getpgrp()), SIGKILL);
+ if(result < 0)
+ error(0, errno, "SIGKILL pgrp");
+ }
+
+ do {
+ child_pid = wait(&status);
+ if((child_pid == -1) && (errno != ECHILD))
+ error(1, errno, "wait");
+ } while(child_pid != -1);
+
+ // print termination signal that we received
+ if(signal_number == SIGTERM)
+ printf("Bubble level demo exiting due to SIGTERM signal...\n");
+ else if(signal_number == SIGINT)
+ printf("Bubble level demo exiting due to SIGINT signal...\n");
+ else if(signal_number == SIGQUIT)
+ printf("Bubble level demo exiting due to SIGQUIT signal...\n");
+ else
+ printf("Bubble level demo exiting due to unknown signal...\n");
+
+ exit(EXIT_SUCCESS);
+}
+
+int main(void) {
+ int i;
+ int result;
+ int event_dev_fd;
+ const char *input_dev_node = INPUT_DEV_NODE;
+ struct input_absinfo the_absinfo;
+ int led_fd[8];
+ int led_col;
+ int avg_array[10] = { 0 };
+ int avg_array_index = 0;
+ int avg_value;
+ pid_t key0_child_pid;
+ pid_t main_child_pid;
+ struct sigaction new_action, old_action;
+
+ const char *led_trigger[8] = {
+ "/sys/class/leds/fpga_led0/trigger",
+ "/sys/class/leds/fpga_led1/trigger",
+ "/sys/class/leds/fpga_led2/trigger",
+ "/sys/class/leds/fpga_led3/trigger",
+ "/sys/class/leds/fpga_led4/trigger",
+ "/sys/class/leds/fpga_led5/trigger",
+ "/sys/class/leds/fpga_led6/trigger",
+ "/sys/class/leds/fpga_led7/trigger" };
+
+ const char *led_trigger_str = "none";
+ int led_trigger_str_len = 4;
+
+ const char *led_brightness[8] = {
+ "/sys/class/leds/fpga_led0/brightness",
+ "/sys/class/leds/fpga_led1/brightness",
+ "/sys/class/leds/fpga_led2/brightness",
+ "/sys/class/leds/fpga_led3/brightness",
+ "/sys/class/leds/fpga_led4/brightness",
+ "/sys/class/leds/fpga_led5/brightness",
+ "/sys/class/leds/fpga_led6/brightness",
+ "/sys/class/leds/fpga_led7/brightness" };
+
+ const char *led_on_str = "1";
+ int led_on_str_len = 1;
+ const char *led_off_str = "0";
+ int led_off_str_len = 1;
+
+ // fork main to deal with heartbeat LED
+ main_child_pid = fork();
+ if(main_child_pid != 0) {
+ int int_result;
+
+ // disable heartbeat LED
+ write_sysfs_cntl_file("/sys/class/leds/hps_led0", "trigger",
+ "none");
+
+ // register a SIGTERM handler
+ new_action.sa_handler = my_termination_handler;
+ sigemptyset(&new_action.sa_mask);
+ new_action.sa_flags = 0;
+
+ result = sigaction(SIGTERM, NULL, &old_action);
+ if(result < 0)
+ error(1, errno, "sigaction");
+
+ if(old_action.sa_handler != SIG_IGN) {
+ result = sigaction(SIGTERM, &new_action, NULL);
+ if(result < 0)
+ error(1, errno, "sigaction");
+ }
+ else
+ error(1, 0, "SIGTERM handler already installed");
+
+ // register a SIGINT handler
+ result = sigaction(SIGINT, NULL, &old_action);
+ if(result < 0)
+ error(1, errno, "sigaction");
+
+ if(old_action.sa_handler != SIG_IGN) {
+ result = sigaction(SIGINT, &new_action, NULL);
+ if(result < 0)
+ error(1, errno, "sigaction");
+ }
+ else
+ error(1, 0, "SIGINT handler already installed");
+
+ // register a SIGQUIT handler
+ result = sigaction(SIGQUIT, NULL, &old_action);
+ if(result < 0)
+ error(1, errno, "sigaction");
+
+ if(old_action.sa_handler != SIG_IGN) {
+ result = sigaction(SIGQUIT, &new_action, NULL);
+ if(result < 0)
+ error(1, errno, "sigaction");
+ }
+ else
+ error(1, 0, "SIGINT handler already installed");
+
+ // wait for the main child to terminate
+ waitpid(main_child_pid, &int_result, 0);
+
+ // enable heartbeat LED
+ write_sysfs_cntl_file("/sys/class/leds/hps_led0", "trigger",
+ "heartbeat");
+
+ // disable adxl
+ write_sysfs_cntl_file(SYSFS_DEVICE_DIR, "disable", "1");
+
+ // return the status from the main child
+ if(WIFEXITED(int_result)) {
+ exit(WEXITSTATUS(int_result));
+ } else {
+ error(1, 0, "main child exited abnormally");
+ }
+ }
+
+
+ // initialize led triggers to "none"
+ for(i = 0 ; i < 8 ; i++) {
+ led_fd[i] = open(led_trigger[i], O_WRONLY | O_SYNC);
+ if(led_fd[i] < 0)
+ error(1, errno, "File: '%s'", led_trigger[i]);
+
+ result = write(led_fd[i], led_trigger_str, led_trigger_str_len);
+ if(result < 0)
+ error(1, errno, "File: '%s'", led_trigger[i]);
+ if(result != led_trigger_str_len)
+ error(1, 0, "File: '%s'", led_trigger[i]);
+
+ result = close(led_fd[i]);
+ if(result < 0)
+ error(1, errno, "could not close file '%s'",
+ led_trigger[i]);
+ }
+
+ // initialize led brightness to "off"
+ for(i = 0 ; i < 8 ; i++) {
+ led_fd[i] = open(led_brightness[i], O_WRONLY | O_SYNC);
+ if(led_fd[i] < 0)
+ error(1, errno, "File: '%s'", led_brightness[i]);
+
+ result = write(led_fd[i], led_off_str, led_off_str_len);
+ if(result < 0)
+ error(1, errno, "File: '%s'", led_brightness[i]);
+ if(result != led_off_str_len)
+ error(1, 0, "File: '%s'", led_brightness[i]);
+ }
+
+ // enable adxl
+ write_sysfs_cntl_file(SYSFS_DEVICE_DIR, "disable", "0");
+
+ // set the sample rate to maximum
+ write_sysfs_cntl_file(SYSFS_DEVICE_DIR, "rate", "15");
+
+ // do not auto sleep
+ write_sysfs_cntl_file(SYSFS_DEVICE_DIR, "autosleep", "0");
+
+ // open the event device node
+ event_dev_fd = open(input_dev_node, O_RDONLY | O_SYNC);
+ if(event_dev_fd < 0)
+ error(1, errno, "could not open file '%s'", input_dev_node);
+
+ printf("\
+\n\
+1 - Notice that the heartbeat LED has been stopped while this program executes.\
+\n\
+2 - Notice the 8 LEDs beside the Ethernet connector on the board, they should\n\
+ behave like a bubble level. As you tip your board from side to side on\n\
+ the short axis of the board, the leds will indicate the tilt as a bubble\n\
+ level would.\n\
+7 - Press the KEY0 push button located near the edge of the board in order to\n\
+ stop the bubble level demo program.\n\
+8 - When you successfully stop the program, the heartbeat LED will resume.\
+\n\
+\n\
+");
+
+ // register our SIGCHLD handler
+ new_action.sa_handler = my_sig_child_handler;
+ sigemptyset(&new_action.sa_mask);
+ new_action.sa_flags = 0;
+
+ result = sigaction(SIGCHLD, NULL, &old_action);
+ if(result < 0)
+ error(1, errno, "sigaction");
+
+ if(old_action.sa_handler != SIG_IGN) {
+ result = sigaction(SIGCHLD, &new_action, NULL);
+ if(result < 0)
+ error(1, errno, "sigaction");
+ }
+ else
+ error(1, 0, "SIGCHLD handler already installed");
+
+ // fork the KEY0 push button monitor process
+ key0_child_pid = fork();
+ if(key0_child_pid == 0) {
+ poll_for_KEY0_press();
+ exit(EXIT_SUCCESS);
+ }
+
+ // main bubble level loop
+ while (1) {
+
+ if(g_stop_running != 0)
+ break;
+
+ result = ioctl (event_dev_fd, EVIOCGABS(EV_CODE_X),
+ &the_absinfo);
+ if(result < 0)
+ error(1, errno, "ioctl from '%s'",
+ input_dev_node);
+
+ avg_array[avg_array_index++] = the_absinfo.value;
+ if(avg_array_index >= 10)
+ avg_array_index = 0;
+
+ avg_value = 0;
+ for(i = 0 ; i < 10 ; i++)
+ avg_value += avg_array[i];
+ avg_value /= 10;
+
+ if(avg_value < -40)
+ led_col = 0x01;
+ else if(avg_value < -30)
+ led_col = 0x02;
+ else if(avg_value < -20)
+ led_col = 0x04;
+ else if(avg_value < 0)
+ led_col = 0x08;
+ else if(avg_value > 40)
+ led_col = 0x80;
+ else if(avg_value > 30)
+ led_col = 0x40;
+ else if(avg_value > 20)
+ led_col = 0x20;
+ else if(avg_value >= 0)
+ led_col = 0x10;
+
+ // output each LED sequentially down the column
+ for(i = 0 ; i < 8 ; i++) {
+ int row_mask = 1 << i;
+ if((row_mask & led_col) == 0) {
+ result = write(led_fd[i], led_off_str,
+ led_off_str_len);
+ if(result < 0)
+ error(1, errno, "File: '%s'",
+ led_brightness[i]);
+ if(result != led_off_str_len)
+ error(1, 0, "File: '%s'",
+ led_brightness[i]);
+ } else {
+ result = write(led_fd[i], led_on_str,
+ led_on_str_len);
+ if(result < 0)
+ error(1, errno, "File: '%s'",
+ led_brightness[i]);
+ if(result != led_on_str_len)
+ error(1, 0, "File: '%s'",
+ led_brightness[i]);
+ }
+ }
+
+ usleep(10 * 1000);
+ }
+
+ // close the led brightness files after setting them to "off"
+ for(i = 0 ; i < 8 ; i++) {
+ result = write(led_fd[i], led_off_str, led_off_str_len);
+ if(result < 0)
+ error(1, errno, "File: '%s'", led_brightness[i]);
+ if(result != led_off_str_len)
+ error(1, 0, "File: '%s'", led_brightness[i]);
+
+ result = close(led_fd[i]);
+ if(result < 0)
+ error(1, errno, "could not close file '%s'",
+ led_brightness[i]);
+ }
+
+ // close the device node
+ result = close(event_dev_fd);
+ if(result < 0)
+ error(1, errno, "could not close file '%s'", input_dev_node);
+
+ printf("Bubble level demo exiting due to KEY0 push button press...\n");
+}
+
+void write_sysfs_cntl_file(const char *dir_name, const char *file_name,
+ const char *write_str) {
+
+ char path[PATH_MAX];
+ int path_length;
+ int file_fd;
+ int result;
+
+ // create the path to the file we need to open
+ path_length = snprintf(path, PATH_MAX, "%s/%s", dir_name, file_name);
+ if(path_length < 0)
+ error(1, 0, "path output error");
+ if(path_length >= PATH_MAX)
+ error(1, 0, "path length overflow");
+
+ // open the file
+ file_fd = open(path, O_WRONLY | O_SYNC);
+ if(file_fd < 0)
+ error(1, errno, "could not open file '%s'", path);
+
+ // write the string to the file
+ result = write(file_fd, write_str, strlen(write_str));
+ if(result < 0)
+ error(1, errno, "writing to '%s'", path);
+ if((size_t)(result) != strlen(write_str))
+ error(1, errno, "buffer underflow writing '%s'", path);
+
+ // close the file
+ result = close(file_fd);
+ if(result < 0)
+ error(1, errno, "could not close file '%s'", path);
+}
+
+void poll_for_KEY0_press(void) {
+ DIR *gpio_dir;
+ const char *gpio_dir_path = "/sys/class/gpio";
+ const char *gpiochip_str = "gpiochip";
+ const char *gpio_label = "gpio@0x100005000";
+ size_t gpiochip_str_len = strlen(gpiochip_str);
+ int result;
+ struct dirent *dir_entry;
+ char path[PATH_MAX+1];
+ int path_length;
+ int file_fd;
+ char buffer[PATH_MAX+1];
+ char gpio_number_buffer[PATH_MAX+1];
+ char *str_result = NULL;
+ char *newline_ptr;
+ struct pollfd pollfd_struct;
+
+ // open the sysfs gpio directory
+ gpio_dir = opendir(gpio_dir_path);
+ if(gpio_dir == NULL)
+ error(1, errno, "could not open directory '%s'", gpio_dir_path);
+
+ // find the gpio controller for the KEY0 push button 'gpio@0x100005000'
+ while(1) {
+ // read the next directory entry
+ errno = 0;
+ dir_entry = readdir(gpio_dir);
+ if(dir_entry == NULL) {
+ if(errno != 0) {
+ result = closedir(gpio_dir);
+ if(result < 0)
+ error(1, errno, "could not closedir");
+
+ error(1, errno, "reading directory '%s'",
+ gpio_dir_path);
+ }
+ else
+ break;
+ }
+
+ // check if this is a gpio controller entry
+ result = strncmp(dir_entry->d_name, gpiochip_str,
+ gpiochip_str_len);
+ if(result != 0)
+ continue;
+
+ // open the gpio controller label file and read label value
+ path_length = snprintf(path, PATH_MAX, "%s/%s/label",
+ gpio_dir_path, dir_entry->d_name);
+ if(path_length < 0)
+ error(1, 0, "path output error");
+ if(path_length >= PATH_MAX)
+ error(1, 0, "path length overflow");
+
+ file_fd = open(path, O_RDONLY | O_SYNC);
+ if(file_fd < 0)
+ error(1, errno, "could not open file '%s'", path);
+
+ result = read(file_fd, buffer, PATH_MAX);
+ if(result < 0)
+ error(1, errno, "reading from '%s'", path);
+ if(result == PATH_MAX)
+ error(1, errno, "buffer overflow reading '%s'", path);
+
+ buffer[PATH_MAX] = 0;
+
+ result = close(file_fd);
+ if(result < 0)
+ error(1, errno, "could not close file '%s'", path);
+
+ // test the gpio controller label value for our gpio controller
+ str_result = strstr(buffer, gpio_label);
+ if(str_result != NULL)
+ break;
+ }
+
+ closedir(gpio_dir);
+
+ if(str_result == NULL)
+ error(1, 0, "unable to locate gpio controller");
+
+ // open the gpio controller base file and read base value
+ path_length = snprintf(path, PATH_MAX, "%s/%s/base",
+ gpio_dir_path, dir_entry->d_name);
+ if(path_length < 0)
+ error(1, 0, "path output error");
+ if(path_length >= PATH_MAX)
+ error(1, 0, "path length overflow");
+
+ file_fd = open(path, O_RDONLY | O_SYNC);
+ if(file_fd < 0)
+ error(1, errno, "could not open file '%s'", path);
+
+ result = read(file_fd, gpio_number_buffer, PATH_MAX);
+ if(result < 0)
+ error(1, errno, "reading from '%s'", path);
+ if(result == PATH_MAX)
+ error(1, errno, "buffer overflow reading '%s'", path);
+
+ gpio_number_buffer[PATH_MAX] = 0;
+
+ result = close(file_fd);
+ if(result < 0)
+ error(1, errno, "could not close file '%s'", path);
+
+ // remove the newline at the end of the string
+ newline_ptr = strchr(gpio_number_buffer,'\n');
+ if(newline_ptr != NULL)
+ memset(newline_ptr, '\0', 1);
+
+ // open the gpio export file and write our gpio number
+ path_length = snprintf(path, PATH_MAX, "%s/export",
+ gpio_dir_path);
+ if(path_length < 0)
+ error(1, 0, "path output error");
+ if(path_length >= PATH_MAX)
+ error(1, 0, "path length overflow");
+
+ file_fd = open(path, O_WRONLY | O_SYNC);
+ if(file_fd < 0)
+ error(1, errno, "could not open file '%s'", path);
+
+ result = write(file_fd, gpio_number_buffer, strlen(gpio_number_buffer));
+ // NOTE: we don't bother checking for errors here because if this gpio
+ // has already been exported this write will receive a device busy error
+ // which is perfectly normal.
+
+ result = close(file_fd);
+ if(result < 0)
+ error(1, errno, "could not close file '%s'", path);
+
+ // open the gpio edge file and write 'falling' to it
+ path_length = snprintf(path, PATH_MAX, "%s/gpio%s/edge",
+ gpio_dir_path, gpio_number_buffer);
+ if(path_length < 0)
+ error(1, 0, "path output error");
+ if(path_length >= PATH_MAX)
+ error(1, 0, "path length overflow");
+
+ file_fd = open(path, O_WRONLY | O_SYNC);
+ if(file_fd < 0)
+ error(1, errno, "could not open file '%s'", path);
+
+ result = write(file_fd, "falling", 7);
+ if(result < 0)
+ error(1, errno, "writing to '%s'", path);
+ if(result != 7)
+ error(1, errno, "buffer underflow writing '%s'", path);
+
+ result = close(file_fd);
+ if(result < 0)
+ error(1, errno, "could not close file '%s'", path);
+
+ // open the gpio value file and poll the file
+ path_length = snprintf(path, PATH_MAX, "%s/gpio%s/value",
+ gpio_dir_path, gpio_number_buffer);
+ if(path_length < 0)
+ error(1, 0, "path output error");
+ if(path_length >= PATH_MAX)
+ error(1, 0, "path length overflow");
+
+ file_fd = open(path, O_RDONLY | O_SYNC);
+ if(file_fd < 0)
+ error(1, errno, "could not open file '%s'", path);
+
+ // we first need to read the file before we can poll it, otherwise poll
+ // will not block
+ result = read(file_fd, buffer, PATH_MAX);
+ if(result < 0)
+ error(1, errno, "reading from '%s'", path);
+ if(result == PATH_MAX)
+ error(1, errno, "buffer overflow reading '%s'", path);
+
+ buffer[PATH_MAX] = 0;
+
+ pollfd_struct.fd = file_fd;
+ pollfd_struct.events = POLLPRI | POLLERR;
+ pollfd_struct.revents = 0;
+
+ result = poll(&pollfd_struct, 1, -1);
+ if(result < 0)
+ error(1, errno, "poll returned error");
+
+ result = close(file_fd);
+ if(result < 0)
+ error(1, errno, "could not close file '%s'", path);
+
+ // open the gpio unexport file and write our gpio number
+ path_length = snprintf(path, PATH_MAX, "%s/unexport",
+ gpio_dir_path);
+ if(path_length < 0)
+ error(1, 0, "path output error");
+ if(path_length >= PATH_MAX)
+ error(1, 0, "path length overflow");
+
+ file_fd = open(path, O_WRONLY | O_SYNC);
+ if(file_fd < 0)
+ error(1, errno, "could not open file '%s'", path);
+
+ result = write(file_fd, gpio_number_buffer, strlen(gpio_number_buffer));
+ if(result < 0)
+ error(1, errno, "writing to '%s'", path);
+ if((size_t)(result) != strlen(gpio_number_buffer))
+ error(1, errno, "buffer underflow writing '%s'", path);
+
+ result = close(file_fd);
+ if(result < 0)
+ error(1, errno, "could not close file '%s'", path);
+}
+
diff --git a/recipes-demo/de10-nano-adxl-apps/files/build_bubble_demo.sh b/recipes-demo/de10-nano-adxl-apps/files/build_bubble_demo.sh
new file mode 100755
index 0000000..37d5cb7
--- /dev/null
+++ b/recipes-demo/de10-nano-adxl-apps/files/build_bubble_demo.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+gcc \
+ -march=armv7-a \
+ -mfloat-abi=hard \
+ -mfpu=vfp3 \
+ -mthumb-interwork \
+ -mthumb \
+ -O2 \
+ -g \
+ -feliminate-unused-debug-types \
+ -std=gnu99 \
+ -W \
+ -Wall