VolumeChangeWithAccelerometer

From Chumby Wiki
Jump to: navigation, search

Changing Chumby Volume using Accelerometer

(original trick created by zapp on the forum http://forum.chumby.com/viewtopic.php?id=2459)

Note: Using this trick will disable accelerometer access for the control panel / widgets

The chumby comes with this nice 3D motion sensor. Unfortunately it is "blocked" by the control panel. (The control panel keeps the handle open so any further attempt to read it gets a device busy). The workaround for this is to rename the device file to /dev/real_accel and link /dev/zero to /dev/accel. Note: since the control panel won't work without the /dev/accel file, it hangs.

Attached is a small application that dumps the acceleration data to stdout. There is also a shell script that checks the data every second or so and triggers different things according to the motions, you do with the chumby.

At the moment the following things are implemented:

  • rotate clockwise -> Volume Up
  • rotate counter clockwise -> Volume Down
  • slight punch -> Mute/Unmute

Archive with all files including the .c file compiled for chumby available at: http://www.bluesata.com/chumby_volume_accel.zip (BROKEN)

debugchumby:

#!/bin/sh
mv /dev/accel /dev/real_accel
cd /dev
ln -s zero accel

/mnt/usb/acceld.sh > /dev/null 2>&1 &

acceld.sh:

#!/bin/sh

AVPRG="/mnt/usb/accelvals"
ACCEL_DEVICE="/dev/real_accel"


[ -x "${AVPRG}" ]        || { echo "[ERROR] \"accelvals\" prg. not found." ;  exit 1 ; }
[ -e "${ACCEL_DEVICE}" ] || { echo "[ERROR] Invalid acceleration device!" ; exit 1 ; }

delta_x=100
vol_steps=10

# calibration
${AVPRG} ${ACCEL_DEVICE} > /tmp/acceldata.$$
read ver ts x y z avgx avgy avgz impx impy impz imptime imphint grange < /tmp/acceldata.$$
cal_x=${x}
cal_y=${y}
cal_z=${z}

mute="$(cat /proc/chumby/audio/mixer/left-speaker/mute)"
current_volume="$(cat /proc/chumby/audio/mixer/left-speaker/volume)"

last_impact=${imptime}

echo "Calibrated! (${cal_x}, ${cal_y}, ${cal_z}, ${last_impact})"


while [ 1 ]; do
        ${AVPRG} ${ACCEL_DEVICE} > /tmp/acceldata.$$
        read ver ts x y z avgx avgy avgz impx impy impz imptime imphint grange < /tmp/acceldata.$$
        if [ "${imptime}" != "${last_impact}" ]; then
                echo -n "[IMPACT] -> "
                if [ "${mute}" = "0" ]; then
                        mute=1
                        echo "Mute"
                else
                        mute=0
                        echo "Unmute"
                fi
                echo ${mute} > /proc/chumby/audio/mixer/both-speakers/mute
                last_impact=${imptime}
        fi

        if [ "${x}" -gt "$((${cal_x} + ${delta_x}))" ]; then
                echo "[ROLL] Right"
                current_volume=$((${current_volume} + ${vol_steps}))
                if [ "${current_volume}" -gt "100" ]; then
                        current_volume=100
                fi
                echo ${current_volume} > /proc/chumby/audio/mixer/both-speakers/volume
        fi
        if [ "${x}" -lt "$((${cal_x} - ${delta_x}))" ]; then
                echo "[ROLL] Left"
                current_volume=$((${current_volume} - ${vol_steps}))
                if [ "${current_volume}" -lt "0" ]; then
                        current_volume=0
                fi
                echo ${current_volume} > /proc/chumby/audio/mixer/both-speakers/volume
        fi
        sleep 1
done

accelvals.c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

static int accel_fd;

struct accelReadData {
  unsigned int version;
  unsigned int timestamp;
  unsigned int inst[3];  // x, y, z
  unsigned int avg[3];
  unsigned int impact[3]; // values for the last impact peak acceleration
  unsigned int impactTime;
  unsigned int impactHint;
  unsigned int gRange;    // g range in milli-g's
};

int getAccelData(struct accelReadData *ac)
{
        int rc = read(accel_fd, ac, sizeof(*ac));

        if (rc != sizeof(*ac))
                return -1;

        return 0;
}

int main(int argc, char*argv[])
{
        int rc;
        struct accelReadData ac;


        if (argc != 2) {
                fprintf(stderr, "Usage: %s accel-device\n", argv[0]);
                return -1;
        }

        accel_fd = open(argv[1], O_RDONLY);
        if (accel_fd == -1) {
                perror("open");
                return -1;
        }

        rc = getAccelData(&ac);
        printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
                ac.version,
                ac.timestamp,
                ac.inst[0],
                ac.inst[1],
                ac.inst[2],
                ac.avg[0],
                ac.avg[1],
                ac.avg[2],
                ac.impact[0],
                ac.impact[1],
                ac.impact[3],
                ac.impactTime,
                ac.impactHint,
                ac.gRange);

        return 0;
}