/* *******************************************************
 * wlanbuttond, version 0.9				 *
 *                                                       *
 * WLAN control via RS232 :: button, status LED          *
 *                                                       *
 * Copyright(C) 2006 Leonhard Fellermayr <leo@slacky.de> *
 * All rights reserved.                                  *
 *                                                       *
 * Assumes that button is connected to TXD <-> CD, LED   *
 * connected to RTS <-> GND                              *
 *                                                       *
 * Invoke: wlanbuttond /dev/ttyS[0|1]                    *
 *                                                       *
 *********************************************************/

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>

#define WLAN_ON_CMD    "/var/www/cgi-bin/intra/wlan on manual"
#define WLAN_OFF_CMD   "/var/www/cgi-bin/intra/wlan off manual"
#define WLAN_FLAG_FILE "/tmp/wlan_active"

#define LOOP_DELAY 75000
#define WLAN_CHECK_MULTIPLIER 14

int fd = 0;

void set_initial (int code)
{

  int status = 0;
  ioctl (fd, TIOCMSET, &status);
  exit(0);

} // set_initial ()

void set_led_state (bool state, int fd, int currstat)
{

  if (state)
    currstat |= TIOCM_RTS;
  else
    currstat &= ~TIOCM_RTS;

  ioctl (fd, TIOCMSET, &currstat);

} // set_led_state ()

void set_wlan_state (bool state)
{

  if (state)
    system (WLAN_ON_CMD);
  else
    system (WLAN_OFF_CMD);

} // set_wlan_state ()

bool get_wlan_state ()
{
  FILE *f;

  f = fopen (WLAN_FLAG_FILE, "r");
  if (f != NULL)
  {
    fclose (f);
    return true;
  }
  else
    return false;

} // get_wlan_state ()

void poll_rs232 (int fd, int currstat)
{

  bool wlan_on, led_on, button_pressed, done = false;
  int cnt = 0;

  while (1)
  {
      /* loop delay */
      usleep (LOOP_DELAY);

      /* read from RS232 */
      ioctl (fd, TIOCMGET, &currstat);

      /* get button status */
      button_pressed = currstat & TIOCM_CAR;

      /* check WLAN state and set LED appropriately */
      if (++cnt == WLAN_CHECK_MULTIPLIER)
      {
        wlan_on = get_wlan_state ();
        led_on  = currstat & TIOCM_RTS;

        if ((wlan_on) && (!led_on))
          set_led_state (true, fd, currstat);

        if ((!wlan_on) && (led_on))
          set_led_state (false, fd, currstat);

        cnt = 0;
      }

      if ((button_pressed) && (!done))			/* do something */
      {
        /* change WLAN state */
        printf ("EVENT: Button was pressed, changing WLAN state.\n");
        set_wlan_state (!get_wlan_state ());		/* invert WLAN state */
        done = true;
      }
      
      if ((!button_pressed) && (done))			/* button released and done */
        /* button was released => new cycle */
        done = false;

  } // endwhile

} // poll_rs232 ()

int main (int argc, char** argv)
{

  int currstat = 0;

  if (argc != 2)
  {
      printf("Fehler: Ungültige Parameter-Anzahl.\n");
      printf("Aufruf:\n");
      printf("  wlanbuttond <device>\n");
      return 1;
  }

  if((fd = open(argv[1], O_RDWR | O_NDELAY)) < 0)
  {
      printf("Fehler: Device \"%s\" kann nicht geöffnet werden.\n", argv[1]);
      return 2;
  } 

  /* Signale INT und TERM abfangen */
  signal (SIGINT, set_initial);
  signal (SIGTERM, set_initial);

  /* set power on DTR to get power back on CD when button is pressed */

  currstat |= TIOCM_DTR;
  ioctl (fd, TIOCMSET, &currstat);

  /* poll RS232 forever */

  poll_rs232 (fd, currstat);

  return 0;

} // main ()

