/*
 * relay.c: A plugin for the Video Disk Recorder
 *
 * See the README file for copyright information and how to reach the author.
 *
 * $Id$
 */

#include <getopt.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>

#include <vdr/plugin.h>
#include <vdr/config.h>
#include <vdr/status.h>

static const char *VERSION        = "0.0.1";
static const char *DESCRIPTION    = "Power the output equipment on and off";

class cStatusRelay : public cStatus {
private:
  int relayFD;
  ///< Open file descriptor of the relay device
public:
  cStatusRelay(int RelayFD) : relayFD (RelayFD) {}
  ///< Constructor
  ///< @param RelayFD Open file descriptor of the relay device

protected:
  void SetSuspend(bool Suspend);
  ///< Receive a Suspend event
  ///< @param Suspend true=output suspended, false=output running
  };

void cStatusRelay::SetSuspend(bool Suspend)
{
  isyslog("[relay] SetSuspend(%s)", Suspend ? "true" : "false");

  if (ioctl(relayFD, Suspend ? TIOCCBRK : TIOCSBRK, 0))
     esyslog("[relay] ioctl(%s): %m", Suspend ? "TIOCCBRK" : "TIOCSBRK");
}

class cPluginRelay : public cPlugin {
private:
  cStatusRelay *statusRelay;
  ///< Status listener
  int relayFD;
  ///< Open file descriptor of the relay device
  bool suspend;
  ///< Flag: suspend the output
public:
  cPluginRelay(void);
  virtual ~cPluginRelay();
  virtual const char *Version(void) { return VERSION; }
  virtual const char *Description(void) { return DESCRIPTION; }
  virtual const char *CommandLineHelp(void);
  virtual bool ProcessArgs(int argc, char *argv[]);
  virtual bool Start(void);
  };

cPluginRelay::cPluginRelay(void) :
  statusRelay (0), relayFD (-1), suspend (false)
{
  // Initialize any member variables here.
  // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL
  // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT!
}

cPluginRelay::~cPluginRelay()
{
  delete statusRelay;
  if (relayFD >= 0 && close(relayFD))
     perror ("[relay] close");
}

const char *cPluginRelay::CommandLineHelp(void)
{
  // Return a string that describes all known command line options.
  return "  -r DEV,   --relay=DEV    control the TxD line of DEV, e.g., /dev/ttyS0\n"
         "  -s[B],    --suspend[=B]  set the Suspend flag [to B]\n";
}

bool cPluginRelay::ProcessArgs(int argc, char *argv[])
{
  // Implement command line argument processing here if applicable.
  static const struct option long_options[] = {
       { "relay",    required_argument, NULL, 'r' },
       { "suspend",  optional_argument, NULL, 's' },
       { NULL }
     };

  suspend = Setup.Suspend;

  int c;
  while ((c = getopt_long(argc, argv, "r:s::", long_options, NULL)) != -1) {
        switch (c) {
          case 'r': relayFD = open(optarg, O_RDWR | O_NOCTTY | O_NONBLOCK);
                    if (relayFD < 0) {
                       esyslog("[relay] open(\"%s\"): %m", optarg);
                       return false;
                       }
                    break;
          case 's': suspend = !optarg || atoi(optarg);
                    break;
          default:  return false;
          }
        }
  return true;
}

bool cPluginRelay::Start(void)
{
  // Start any background activities the plugin shall perform.
  if (relayFD < 0) {
     esyslog("[relay] FATAL: missing or invalid -r or --relay argument!");
     return false;
     }
  statusRelay = new cStatusRelay(relayFD);
  Setup.Suspend = suspend;
  cStatus::MsgSetSuspend(Setup.Suspend);
  return true;
}

VDRPLUGINCREATOR(cPluginRelay); // Don't touch this!
