diff --git a/.gitignore b/.gitignore index 4dcdd91..99b618d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,6 @@ # The compiled executable /beep + +# The Makefile created by ./configure +Makefile diff --git a/Makefile b/Makefile.in similarity index 58% rename from Makefile rename to Makefile.in index 0f4f810..daf16c6 100644 --- a/Makefile +++ b/Makefile.in @@ -1,9 +1,10 @@ -CC=gcc -FLAGS=-Wall -O2 +CC=@CC@ +FLAGS=@FLAGS@ +LIBS=@LIBS@ EXEC_NAME=beep -INSTALL_DIR=/usr/bin +INSTALL_DIR=@PREFIX@/bin MAN_FILE=beep.1.gz -MAN_DIR=/usr/share/man/man1 +MAN_DIR=@PREFIX@/share/man/man1 default : beep @@ -11,7 +12,7 @@ clean : rm ${EXEC_NAME} beep : beep.c - ${CC} ${FLAGS} -o ${EXEC_NAME} beep.c + ${CC} ${FLAGS} -o ${EXEC_NAME} beep.c ${LIBS} install : cp ${EXEC_NAME} ${INSTALL_DIR} diff --git a/README b/README index f4db57b..cb67f1a 100644 --- a/README +++ b/README @@ -74,6 +74,14 @@ complex fix would be something like: and then add only beep-worthy users to the 'beep' group. +Raspberry Pi +------------ + +beep can be used on a Raspberry Pi by attaching an old BIOS speaker or piezo +buzzer to the PWM GPIO pin (BCM_GPIO 18). When not running as root, beep needs +use a workaround that is significantly slower. Read the above section on how +to run beep as suid root. + Playing Songs ------------- diff --git a/beep.c b/beep.c index 7da2e70..0c1145a 100644 --- a/beep.c +++ b/beep.c @@ -28,6 +28,10 @@ #include #include +#ifdef HAVE_WIRINGPI +#include +#endif + /* I don't know where this number comes from, I admit that freely. A wonderful human named Raine M. Ekman used it in a program that played a tune at the console, and apparently, it's how the kernel likes its @@ -88,14 +92,38 @@ typedef struct beep_parms_t { struct beep_parms_t *next; /* in case -n/--new is used. */ } beep_parms_t; -enum { BEEP_TYPE_CONSOLE, BEEP_TYPE_EVDEV }; +enum { BEEP_TYPE_CONSOLE, BEEP_TYPE_EVDEV, BEEP_TYPE_WIRINGPI }; /* Momma taught me never to use globals, but we need something the signal handlers can get at.*/ int console_fd = -1; int console_type = BEEP_TYPE_CONSOLE; char *console_device = NULL; +#ifdef HAVE_WIRINGPI +int gpio_pin = -1; + +int setup_gpio() +{ + if(gpio_pin == -1) + { + int err = -1; + + if(!geteuid()) + err = wiringPiSetupGpio(); + else if(!(err = system("gpio -v"))) + err = wiringPiSetupSys(); + + if(err) { + fprintf(stderr, "GPIO setup failed!\n"); + return 1; + } + gpio_pin = wpiPinToGpio(1); + } + + return 0; +} +#endif void do_beep(int freq) { int period = (freq != 0 ? (int)(CLOCK_TICK_RATE/freq) : freq); @@ -105,7 +133,7 @@ void do_beep(int freq) { putchar('\a'); /* Output the only beep we can, in an effort to fall back on usefulness */ perror("ioctl"); } - } else { + } else if(console_type == BEEP_TYPE_EVDEV) { /* BEEP_TYPE_EVDEV */ struct input_event e; @@ -118,6 +146,42 @@ void do_beep(int freq) { perror("write"); } } +#ifdef HAVE_WIRINGPI + else if(console_type == BEEP_TYPE_WIRINGPI) { + if(freq) { + int period = 600000/freq; + + if(!geteuid()) { + pinMode(gpio_pin, PWM_OUTPUT); + pwmSetRange(period); + pwmWrite(gpio_pin, period / 2); + pwmSetMode(PWM_MODE_MS); + } else { + char buffer[64]; + + snprintf(buffer, 64, "gpio -g mode %d pwm", gpio_pin); + system(buffer); + + snprintf(buffer, 64, "gpio pwmr %d", period); + system(buffer); + + snprintf(buffer, 64, "gpio -g pwm %d %d", gpio_pin, period / 2); + system(buffer); + + system("gpio pwm-ms"); + } + } else { + if(!geteuid()) { + pinMode(gpio_pin, INPUT); + } else { + char buffer[64]; + + snprintf(buffer, 64, "gpio -g mode %d in", gpio_pin); + system(buffer); + } + } + } +#endif } @@ -131,10 +195,15 @@ void handle_signal(int signum) { switch(signum) { case SIGINT: case SIGTERM: - if(console_fd >= 0) { + if(console_fd >= 0 +#ifdef HAVE_WIRINGPI + || gpio_pin >= 0 +#endif + ) { /* Kill the sound, quit gracefully */ do_beep(0); - close(console_fd); + if(console_fd >= 0) + close(console_fd); exit(signum); } else { /* Just quit gracefully */ @@ -279,22 +348,31 @@ void play_beep(beep_parms_t parms) { /* try to snag the console */ if(console_device) console_fd = open(console_device, O_WRONLY); +#ifdef HAVE_WIRINGPI + else if(setup_gpio() == 0) + console_type = BEEP_TYPE_WIRINGPI; +#endif else if((console_fd = open("/dev/tty0", O_WRONLY)) == -1) console_fd = open("/dev/vc/0", O_WRONLY); if(console_fd == -1) { - fprintf(stderr, "Could not open %s for writing\n", + if(console_type != BEEP_TYPE_WIRINGPI) { + fprintf(stderr, "Could not open %s for writing\n", console_device != NULL ? console_device : "/dev/tty0 or /dev/vc/0"); - printf("\a"); /* Output the only beep we can, in an effort to fall back on usefulness */ - perror("open"); - exit(1); + printf("\a"); /* Output the only beep we can, in an effort to fall back on usefulness */ + perror("open"); + exit(1); + } + } else { + if (ioctl(console_fd, EVIOCGSND(0)) != -1) + console_type = BEEP_TYPE_EVDEV; + else + console_type = BEEP_TYPE_CONSOLE; } - if (ioctl(console_fd, EVIOCGSND(0)) != -1) - console_type = BEEP_TYPE_EVDEV; - else - console_type = BEEP_TYPE_CONSOLE; + if(parms.verbose) + fprintf(stderr, "[DEBUG] console_type=%d\n", console_type); /* Beep */ for (i = 0; i < parms.reps; i++) { /* start beep */ diff --git a/configure b/configure new file mode 100755 index 0000000..6442795 --- /dev/null +++ b/configure @@ -0,0 +1,18 @@ +#!/bin/bash + +CC=gcc +PREFIX=/usr +FLAGS="-Wall -O2" +LIBS= + +if [[ -f /usr/include/wiringPi.h ]]; then + echo "Compiling with wiringPi support" + FLAGS+=" -DHAVE_WIRINGPI" + LIBS+=" -lwiringPi" +fi + +sed -e "s|@LIBS@|${LIBS}|" \ + -e "s|@FLAGS@|${FLAGS}|" \ + -e "s|@PREFIX@|${PREFIX}|" \ + -e "s|@CC@|${CC}|" \ + Makefile.in > Makefile