#ifndef _CORE_GPIO_H_
#define _CORE_GPIO_H_

#include <core/types.h>
#include <core/sidekick-pins.h>
#include <core/gpiobits.h>

/****************************************************************************************************************/
//
// CONTROLLING GENERAL PURPOSE IO PINS
//
// A GPIO pin can have two states, OFF or ON.
// Whatever these states mean in the physical world depends on the type of GPIO.
//
// A relay driver is obviously ON if the relay is energized.
// An optocoupler input reports ON if there is current flowing through it's LED.
// For a TTL pin, the mapping between OFF/ON -> LO/HI depends on the actual hardware.
//
// To post a request to the kernel, set up a gpio_request structure and use:
//
// - write()
//    Good if no result code is needed.
//    Allows passing a number of requests in one go.
//    By using GPIO_PAUSE, it is possible to generate definite pulse patterns.
//
// - ioctl(fd, GPIO_REQUEST, &request)
//    Can return a result inside the request structure.
//    Can return an error code.
//
// PIN STATE CHANGE NOTIFICATION
//
// If pin state change notification has been configured, state changes are available for
// reading from the file descriptor.
//
// A falling edge is reported as GPIO_OFF, with <value> indicating the number of falling edges seen since
// system reset. The same is true for rising edges, which uses GPIO_ON.
//
/****************************************************************************************************************/
//
// Structure used for controlling gpio pins
//
// 8   ?   8    8
// grp.fd.addr.pin
//
struct gpio_request {
  uint8  gpio_type;			// Type of request
  uint8  gpio_pin;			// Pin accessed
  uint16 gpio_group;			// Pin group

  union {
    // Generic
    uint32 gpio_value;			// Control value

    // GPIO_RISING, GPIO_FALLING, GPIO_EDGE
    struct {
      uint16 edge_rising;		// Edge counters
      uint16 edge_falling;
    } gpio_edge;

    // GPIO_PAY
    struct {
      uint16 pay_count;			// Number of coins
      uint16 pay_timeout;		// Timeout in milliseconds
    } gpio_pay;

    // GPIO_LIMIT
    struct {
      uint16 limit_dummy;
      uint16 limit_timeout;		// Timeout in milliseconds
    } gpio_limit;

    // GPIO_PAYING, GPIO_PAID, GPIO_PAYFAIL
    struct {
      uint16 paid_total;		// Total number of coins requested
      uint16 paid_paid;			// Number of coins paid
    } gpio_paid;

    // GPIO_OUT_PWM
    struct {
      uint16 pwm_value;			// PWM output value
      uint8 pwm_limit;			// Current limit value (0 = no limit)
      uint8 pwm_reserved;
    } gpio_pwm;

  };

};

/****************************************************************************************************************/

struct gpio_node_identifier {
  uint gpni_group;			// Registered group
  uint gpni_parent_group;		// Parent group
  uint gpni_addr;			// Address, for bus protocols
  char gpni_device[128];		// Device this group is connected to
};

/****************************************************************************************************************/

struct gpio_node_remove {
  uint gpnr_group;                     // Registered group
  int  gpnr_flags;                     // Additional flags
};

/****************************************************************************************************************/

struct gpio_node_info {
  uint gpni_group;			// Registered group
  uint gpni_parent_group;		// Parent group
  uint gpni_addr;			// Address, for bus protocols
  char gpni_device[128];		// Device this group is connected to
  uint gpni_state;			// Working state of node
  uint gpni_type;			// Node type
  uint gpni_capabilities;		// Capability bits
  uint gpni_version[3];			// Version number
  char gpni_name[64];			// Node type name
};

struct gpio_node_info2 {
  uint gpni_structsize;
  uint gpni_group;			// Registered group
  uint gpni_parent_group;		// Parent group
  uint gpni_addr;			// Address, for bus protocols
  char gpni_device[128];		// Device this group is connected to
  uint gpni_state;			// Working state of node
  uint gpni_type;			// Node type
  uint gpni_capabilities;		// Capability bits
  uint gpni_version[3];			// Version number
  char gpni_name[64];			// Node type name
  uint gpni_tty_count;                  // Number of tunneled GPIOs
};

#define MUPPCAP_MUPPE		0x20
#define MUPPCAP_DISPLAY		0x40
#define MUPPCAP_KEYPAD		0x80

#define MUPPCAP_FASTPOLL	0x10000
#define MUPPCAP_STREAM          0x20000

/****************************************************************************************************************/

#define GPIO_EXEC_WRITE		0x80
#define GPIO_EXEC_AND		0x90
#define GPIO_EXEC_OR		0xA0
#define GPIO_EXEC_READ		0xF0

struct gpio_exec {
  uint gpe_group;
  uint gpe_cmd;
  uint gpe_addr;
  uint gpe_len;
  void *gpe_data;
};

/****************************************************************************************************************/
//
// ioctl commands
//
#define GPIO_REQUEST		0x4752

#define GPIO_REGISTER		0x4700	// Register a node ID
#define GPIO_UNREGISTER		0x4701	// Remove a node ID
#define GPIO_INFO		0x4702	// Query node info
#define GPIO_EXEC		0x4703	// Execute a command on a node
#define GPIO_INFO2		0x4704	// Query node info, larger structure
#define GPIO_UNREGISTER2        0x4705  // Remove a node and optionally its registered VFS device entries

/****************************************************************************************************************/
#endif
