Newer
Older
mpd-beat / main.c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <wiringPi.h>
#include <mpd/client.h>
#include <unistd.h>
#include <stdbool.h>
#include <signal.h>

pthread_cond_t isr_cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t isr_mtx = PTHREAD_MUTEX_INITIALIZER;
unsigned int pin_pressed= 0;
unsigned int last_pressed_time = 0;

#define FASTFORWARD_PIN 5
#define PLAYPAUSE_PIN 6
#define REWIND_PIN 13
#define VOLUMEDOWN_PIN 26
#define ONOFF_PIN 12
#define VOLUMEUP_PIN 16

void serviceInterrupt(int pin)
{
  pthread_mutex_lock(&isr_mtx);
  unsigned int now = millis();
  if ((last_pressed_time + 250) < now) {
    pin_pressed = pin;
    last_pressed_time = now;
  } else {
    pin_pressed = 0;
  }
  pthread_cond_signal(&isr_cond);
  pthread_mutex_unlock(&isr_mtx);
}

void fastForwardInterrupt() { serviceInterrupt(FASTFORWARD_PIN); }
void playPauseInterrupt() { serviceInterrupt(PLAYPAUSE_PIN); }
void rewindInterrupt() { serviceInterrupt(REWIND_PIN); }
void volumeDownInterrupt() { serviceInterrupt(VOLUMEDOWN_PIN); }
void onOffInterrupt() { serviceInterrupt(ONOFF_PIN); }
void volumeUpInterrupt() { serviceInterrupt(VOLUMEUP_PIN); }

int main()
{
  struct mpd_connection *conn;
  unsigned int tries = 0;
  signal(SIGPIPE, SIG_IGN); // don't die on connection issues
  conn = mpd_connection_new("/run/mpd.socket", 0, 0);
  while ((mpd_connection_get_error(conn) != MPD_ERROR_SUCCESS) && (tries < 60)) {
    mpd_connection_free(conn);
    conn = mpd_connection_new("/run/mpd.socket", 0, 0);
    tries++;
    sleep(1);
  }
  if (mpd_connection_get_error(conn) != MPD_ERROR_SUCCESS) {
    mpd_connection_free(conn);
    return EXIT_FAILURE;
  }

  mpd_connection_set_keepalive(conn, true);
  wiringPiSetupGpio();
  pullUpDnControl(FASTFORWARD_PIN, PUD_UP);
  pullUpDnControl(PLAYPAUSE_PIN, PUD_UP);
  pullUpDnControl(REWIND_PIN, PUD_UP);
  pullUpDnControl(VOLUMEDOWN_PIN, PUD_UP);
  pullUpDnControl(ONOFF_PIN, PUD_UP);
  pullUpDnControl(VOLUMEUP_PIN, PUD_UP);
  wiringPiISR(FASTFORWARD_PIN, INT_EDGE_FALLING, &fastForwardInterrupt);
  wiringPiISR(PLAYPAUSE_PIN, INT_EDGE_FALLING, &playPauseInterrupt);
  wiringPiISR(REWIND_PIN, INT_EDGE_FALLING, &rewindInterrupt);
  wiringPiISR(VOLUMEDOWN_PIN, INT_EDGE_FALLING, &volumeDownInterrupt);
  wiringPiISR(ONOFF_PIN, INT_EDGE_FALLING, &onOffInterrupt);
  wiringPiISR(VOLUMEUP_PIN, INT_EDGE_FALLING, &volumeUpInterrupt);

  bool playing = true;
  for(;;) {
    int last_pin_pressed = 0;
    pthread_mutex_lock(&isr_mtx);
    while (pin_pressed == 0) {
      pthread_cond_wait(&isr_cond, &isr_mtx);
    }
    last_pin_pressed = pin_pressed;
    pin_pressed = 0;
    pthread_mutex_unlock(&isr_mtx);
    bool success = false;
    while(!success) {
      switch(last_pin_pressed) {
      case PLAYPAUSE_PIN:
        success = mpd_run_toggle_pause(conn);
        printf("play/pause %d\n", success);
        break;
      case ONOFF_PIN:
        if (playing) {
          success = mpd_run_stop(conn);
          printf("stop %d\n", success);
        } else {
          success = mpd_run_play(conn);
          printf("start %d\n", success);
        }
        if (success) {
          playing = !playing;
        }
        break;
      case FASTFORWARD_PIN:
        success = mpd_run_next(conn);
        printf("ff %d\n", success);
        break;
      case REWIND_PIN:
        success = mpd_run_previous(conn);
        printf("rw %d\n", success);
        break;
      case VOLUMEDOWN_PIN:
        success = mpd_run_change_volume(conn, -10);
        printf("vol- %d\n", success);
        break;
      case VOLUMEUP_PIN:
        success = mpd_run_change_volume(conn, 10);
        printf("vol+ %d\n", success);
        break;
      default:
        success = true;
        break;
      }
      if (!success) {
        switch(mpd_connection_get_error(conn)) {
        case MPD_ERROR_SERVER:
        case MPD_ERROR_ARGUMENT:
        case MPD_ERROR_STATE:
        case MPD_ERROR_MALFORMED:
          mpd_connection_clear_error(conn);
          printf("Clear error, don't try again.\n");
          success = true;
          break;
        default:
          printf("Error code %d\n", mpd_connection_get_error(conn));
          mpd_connection_free(conn);
          conn = mpd_connection_new("/run/mpd.socket", 0, 0);
          if (mpd_connection_get_error(conn) != MPD_ERROR_SUCCESS) {
            mpd_connection_free(conn);
            return EXIT_FAILURE;
          }
          printf("Reconnected, try again.\n");
          break;
        }
      }
    }
  }

  mpd_connection_free(conn);
  return 0;
}