/*
    digipanel.c - A user-space program to write to the ASUS DigiMatrix
                  front panel.
    Copyright (c) 2005 Richard Taylor <richard@artaylor.co.uk>
                  2006 Andrew Calkin <calkina@geexbox.org> and
                       Ben Potter <linux@bpuk.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <unistd.h>
#include <time.h>
#include "digitools.h"
#include "i2c-dev.h"
#include "it8705.h"
#include "oz263.h"
#include "digipanel.h"
#include "sndctrl.h"

static struct option digipanel_longopts[] = {
    { "display",     1, 0, 'd' },
    { "reinit",      1, 0, 'D' },
    { "temp",        0, 0, 't' },
    { "volume",      0, 0, 'l' },
    { "time",        0, 0, 's' },
    { "kill",        0, 0, 'k' },
    { "version",     0, 0, 'v' },
    { "help",        0, 0, 'h' },
    { NULL,          0, 0,  0  }
};

static struct option digiradio_longopts[] = {
    { "radio",       0, 0, 'r' },
    { "control",     1, 0, 'c' },
    { "version",     0, 0, 'v' },
    { "help",        0, 0, 'h' },
    { NULL,          0, 0,  0  }
};

static void digipanel_help(char *argv0)
{
#ifndef SILENT
  printf(
"\n"
"Usage: %s [OPTIONS]\n"
"\n"
"  WARNING: If you are using this on a system other than the ASUS\n"
"  DigiMatrix, then there is a chance that you may destroy an EEPROM.\n"
"  This program needs to be run as root.\n"
"\n"
"  -s, --time             Display the local time.\n"
"  -t, --temp             Display the temperature.\n"
"  -l, --volume           Display (any changes of) the volume control.\n"
"  -k, --kill             Stop the daemon (if running) and exit.\n"
"\n"
"  -d, --display [\"xxxxxx\"]   Set the display to the numbers specified.\n"
"  -D, --reinit [\"xxxxxx\"]  As above, but re-initilises the display first.\n"
"\n"
"  -v, --version          Print version number.\n"
"  -h, --help             Display this help message.\n"
"\n", argv0);
#endif
}

static void digiradio_help(char *argv0)
{
#ifndef SILENT
  printf(
"\n"
"Usage: %s [OPTIONS]\n"
"\n"
"  WARNING: If you are using this on a system other than the ASUS\n"
"  DigiMatrix, then there is a chance that you may destroy an EEPROM.\n"
"  This program needs to be run as root.\n"
"\n"
"  -r, --radio [am | fm | off]  Set the radio to am, fm or off.\n"
"  -c, --control [seek-|seek+|fine-|fine+|ch-|ch+|prog|cancel|store]\n"
"      Control the radio, where:\n"
"          seek+/-      seeks to the next station\n"
"          fine+/-      manually increases / decreases frequency\n"
"          ch+/-        selects a stored presets\n"
"          prog         begins storing the current frequency\n"
"                       (use ch+/- to choose preset location)\n"
"          cancel       aborts the store\n"
"          store        commits the frequency to the flashing preset\n"
"\n"
"  -v, --version          Print version number.\n"
"  -h, --help             Display this help message.\n"
"\n", argv0);
#endif
}

int digipanel_main(int argc, char *argv[])
{
  extern char digits[7];
  extern int file;
  int ch, longindex = 0;

  BOOL b_update_temp = FALSE;
  BOOL b_update_time = FALSE;
  BOOL b_update_volume = FALSE;

  extern LED led;
  extern PP pp;
  extern DOTS dots;

  time_t current_time;
  struct tm *time_date;
  /* default displays are set to '    ' and '  ' respectively */
  char ascii_time[5] = {0x0f, 0x0f, 0x0f, 0x0f,'\0'};
  char current_temp[3] = {0x0f, 0x0f,'\0'};

  char volume;
  long vol_current;
  long vol_min, vol_max;
  getvolrange(&vol_min, &vol_max);
  int vol_step=1;

  if ( (int)getuid() != 0)
  {
#ifndef SILENT
    fprintf(stderr,"Must be root to run this program!\n");
#endif
    return -1;
  }

  if (argc == 1)
  {
#ifndef SILENT
    printf("\nPlease supply some parameters.\n"
             "Use %s -h for list.\n\n", argv[0]);
#endif
    return 1;
  }

  /* Parse input params */
  for (;;)
  {
    if ((ch = getopt_long(argc, argv, "d:D:tlskvh",
                digipanel_longopts, &longindex)) == -1)
      break;


    switch (ch)
    {
      case 'd':
      case 'D':
        if (!file)
          file=oz263_I2C_init();

        strncpy(digits, optarg, 6);
        digits[6]='\0';
#ifndef SILENT
        printf("Args = %s\n", optarg);
        printf("Setting display to: %s", digits);
#endif
        if (strstr(optarg, " play"))
        {
          pp = PP_PLAY;
#ifndef SILENT
          printf(" play");
#endif
        }
        else if (strstr(optarg, " pause"))
        {
          pp = PP_PAUSE;
#ifndef SILENT
          printf(" pause");
#endif
        }

        if (strstr(optarg, " am"))
        {
          led = LED_AM;
#ifndef SILENT
          printf(" am");
#endif
        }
        else if (strstr(optarg, " fm"))
        {
          led = LED_FM;
#ifndef SILENT
          printf(" fm");
#endif
        }
        else if (strstr(optarg, " cd"))
        {
          led = LED_CD;
#ifndef SILENT
          printf(" cd");
#endif
        }
        else if (strstr(optarg, " hd"))
        {
          led = LED_HD;
#ifndef SILENT
          printf(" hd");
#endif
        }

        if (strstr(optarg, "both"))
        {
          dots = DOTS_BOTH;
#ifndef SILENT
          printf(" :");
#endif
        }
        else if (strstr(optarg, "middle"))
        {
          dots = DOTS_MIDDLE;
#ifndef SILENT
          printf(" -");
#endif
        }
        else if (strstr(optarg, "bottom"))
        {
          dots = DOTS_BOTTOM;
#ifndef SILENT
          printf(" .");
#endif
        }
        printf("\n");
        if (ch == 'D')
          oz263_display(file, digits, led, pp, dots, (BOOL)1);
        else
          oz263_display(file, digits, led, pp, dots, (BOOL)0);
        break;

      case 't':
        it87_open();
        (void)it87_ec_port_open();
        b_update_temp = TRUE;
        break;

      case 'l':
        b_update_volume = TRUE;
        break;

      case 's':
        b_update_time = TRUE;
        break;

      case 'v':
#ifndef SILENT
        printf("ASUS DigiMatrix Panel Control, from DigiTools "
               "Version %s\n", DIGI_VER);
#endif
        break;

      case 'k':
#ifndef SILENT
        printf("Stopping the %s daemon\n",argv[0]);
#endif
        daemon_kill();
        exit(0);

      case 'h':
        digipanel_help(argv[0]);
        return 0;
        break;

      default:
        digipanel_help(argv[0]);
        return 0;
        break;
    }
  }

  if (b_update_temp || b_update_time || b_update_volume)
  {
    if (!file)
      file=oz263_I2C_init();
    daemon_kill();
    /* Attempt to enter daemon mode, return control to terminal */
    daemon_init();
  }
  else
    exit(0);

  /* Begin daemon loop */
  unsigned int temp_counter = 0;

  while (1)
  {
    if (temp_counter >=
           (TEMP_UPDATE_INTERVAL_MS / VOL_UPDATE_INTERVAL_MS))
    {
      temp_counter = 0;

      if (b_update_temp)
        sprintf(current_temp, "%02X", it87_get_temp());

      if (b_update_time)
      {
        /* Make the dots flash */
        if (dots == DOTS_NONE)
          dots = DOTS_BOTH;
        else
          dots = DOTS_NONE;
        time(&current_time);
        time_date = localtime(&current_time);
        strftime(ascii_time, 5, "%H%M", time_date);
      }

      if (b_update_time || b_update_temp)
      {
        sprintf(digits, "%s%s", current_temp, ascii_time);
        oz263_display(file, digits, led, pp, dots, (BOOL)0);
      }

    }

    if (b_update_volume)
    {
      oz263_write_byte(file, 0x24);
      volume = oz263_read_byte(file);

      if (volume != -120 && volume != 0)
      {
        /* Set delay time to hold display */
        for (temp_counter=12; temp_counter > 0; temp_counter--)
        {
          getvolume(&vol_current);
          if (volume > 0) /*use vol_max-1 so never 100 (3digits)*/
          {
            if (vol_current+vol_step < vol_max-1)
              vol_current=vol_current+vol_step;
            else
              vol_current=vol_max-1;
          }
          if (volume < 0)
          {
            if (vol_current-vol_step > vol_min)
              vol_current=vol_current-vol_step;
            else
              vol_current=vol_min;
          }
          setvolume(vol_current);

          dots = DOTS_NONE;
          sprintf(digits, "%02ld    ",
             (100*(vol_current-vol_min))/(vol_max-vol_min));
          oz263_display(file, digits, led, pp, dots, (BOOL)0);

          usleep(VOL_UPDATE_INTERVAL_MS * 1000); /* Delay of 500ms*/
          oz263_write_byte(file, 0x24);
          volume = oz263_read_byte(file);
        }
      }
    }

    usleep(VOL_UPDATE_INTERVAL_MS * 1000); /* Delay of 500ms*/
    temp_counter++;
  }
}

int digiradio_main(int argc, char *argv[])
{
  int file=0;
  int ch, longindex = 0;

  if ( (int)getuid() != 0)
  {
#ifndef SILENT
    fprintf(stderr,"Must be root to run this program!\n");
#endif
    return -1;
  }

  if (argc == 1)
  {
#ifndef SILENT
    printf("\nPlease supply some parameters.\n"
             "Use %s -h for list.\n\n", argv[0]);
#endif
    return 1;
  }

  /* Parse input params */
  for (;;)
  {
    if ((ch = getopt_long(argc, argv, "r:c:vh",
                          digiradio_longopts, &longindex)) == -1)
      break;

    switch (ch)
    {
      case 'r':
        if (!file)
          file=oz263_I2C_init();
#ifndef SILENT
        printf("Setting radio ");
#endif
        if (!strcmp(optarg, "fm"))
        {
#ifndef SILENT
          printf("ON  - FM\n");
#endif
          oz263_radio_mode(file, FM_RADIO);
        }
        else if (!strcmp(optarg, "am"))
        {
#ifndef SILENT
          printf("ON - AM\n");
#endif
          oz263_radio_mode(file, AM_RADIO);
        }
        else
        {
#ifndef SILENT
          printf("OFF \n");
#endif
          oz263_radio_mode(file, OFF_MODE);
        }
        break;

      case 'c':
        if (!file)
          file=oz263_I2C_init();
#ifndef SILENT
        printf("Controlling radio: ");
#endif
        if (!strcmp(optarg, "seek-"))
        {
#ifndef SILENT
          printf("Seeking down\n");
#endif
          oz263_radio_control(file, SEEK_DOWN);
        }
        else if (!strcmp(optarg, "seek+"))
        {
#ifndef SILENT
          printf("Seeking up\n");
#endif
          oz263_radio_control(file, SEEK_UP);
        }
        else if (!strcmp(optarg, "fine-"))
        {
#ifndef SILENT
          printf("Fine tuning down\n");
#endif
          oz263_radio_control(file, FINE_TUNE_DOWN);
        }
        else if (!strcmp(optarg, "fine+"))
        {
#ifndef SILENT
          printf("Fine tuning up\n");
#endif
          oz263_radio_control(file, FINE_TUNE_UP);
        }
        else if (!strcmp(optarg, "ch-"))
        {
#ifndef SILENT
          printf("Previous preset\n");
#endif
          oz263_radio_control(file, CHANNEL_PREV);
        }
        else if (!strcmp(optarg, "ch+"))
        {
#ifndef SILENT
          printf("Next preset\n");
#endif
          oz263_radio_control(file, CHANNEL_NEXT);
        }
        else if (!strcmp(optarg, "prog"))
        {
#ifndef SILENT
          printf("Program preset - now select preset with ch+/-\n");
#endif
          oz263_radio_control(file, STORE_START);
        }
        else if (!strcmp(optarg, "cancel"))
        {
#ifndef SILENT
          printf("Program store cancelled\n");
#endif
          oz263_radio_control(file, STORE_CANCEL);
        }
        else if (!strcmp(optarg, "store"))
        {
#ifndef SILENT
          printf("Preset stored\n");
#endif
          oz263_radio_control(file, STORE_COMMIT);
        }
        break;

      case 'v':
#ifndef SILENT
        printf("ASUS DigiMatrix Radio Control, from DigiTools "
               "Version %s\n", DIGI_VER);
#endif
        break;

      case 'h':
        digiradio_help(argv[0]);
        return 0;
        break;

      default:
        digiradio_help(argv[0]);
        return 0;
        break;
    }
  }

  exit(0);
}

