/*                                       -*- mode:C++; fill-column: 100 -*-
  SFBPins.h Definitions of the programmer visible 'pins' in SFB
  Copyright (C) 2008 The Regents of the University of New Mexico.  All rights reserved.

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

  This library 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
  Lesser General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
  USA

  $Id$
*/
/**
  \file SFBPins.h Definitions of the programmer visible 'pins' in SFB
  \author David H. Ackley.  
  \date (C) 2008 All rights reserved.
  \lgpl
 */

#ifndef SFBPINS_H
#define SFBPINS_H

#include "SFBTypes.h"  /* for u8, etc */
#include "SFBConstants.h"  /* for HIGH, LOW, etc */

#define NOT_A_PIN 99
#define NOT_A_PORT 99

/* Face pin offsets */
enum {
  FACE_D0_PIN = 0,              /**< GPIO pin 0 in face */
  FACE_D1_PIN = 1,              /**< GPIO pin 1 in face */
  FACE_D2_PIN = 2,              /**< GPIO pin 2 in face  */
  FACE_D3_PIN = 3,              /**< GPIO pin 3 in face  */
  FACE_RX_PIN = 4,              /**< Serial input or GPIO */
  FACE_TX_PIN = 5,              /**< Serial output or GPIO */
  FACE_VIN_ENABLE_PIN = 6,      /**< Power input enable  */
  FACE_VOUT_ENABLE_PIN = 7,     /**< Power output enable  */
  FACE_ISENSE_PIN = 8,          /**< Face voltage(?) sense  */
  FACE_LED_PIN = 9,             /**< Face LED  */
  FACE_SIDE_LED_PIN = 10,       /**< Face side 'headlight' LEDs (if mounted) */
  FACE_PIN_COUNT = 11
};

/* Virtual pin definitions.  Indices into the tables below.  First set
 * of values are aliases, forming a kind Arduino compatibility layer.
 * In SFBPins.c they are aliased to the 'real' SFB pins appearing later
 * in the table.
 */
enum {
  ARDUINO_RX = 0,               /**< Aliased to #NORTH_RX_PIN */
  ARDUINO_TX = 1,               /**< Aliased to #NORTH_TX_PIN */
  ARDUINO_DIGITAL_PIN2 = 2,     /**< Aliased to #NORTH_D0_PIN */
  ARDUINO_DIGITAL_PIN3 = 3,     /**< Aliased to #NORTH_D1_PIN */
  ARDUINO_DIGITAL_PIN4 = 4,     /**< Aliased to #NORTH_D2_PIN */
  ARDUINO_DIGITAL_PIN5 = 5,     /**< Aliased to #NORTH_D3_PIN */
  ARDUINO_DIGITAL_PIN6 = 6,     /**< Aliased to #SOUTH_D0_PIN */
  ARDUINO_DIGITAL_PIN7 = 7,     /**< Aliased to #SOUTH_D1_PIN */
  ARDUINO_DIGITAL_PIN8 = 8,     /**< Aliased to #SOUTH_D2_PIN */
  ARDUINO_DIGITAL_PIN9 = 9,     /**< Aliased to #SOUTH_D3_PIN */
  ARDUINO_DIGITAL_PIN10 = 10,   /**< Aliased to #EAST_D0_PIN */
  ARDUINO_DIGITAL_PIN11 = 11,   /**< Aliased to #EAST_D1_PIN */
  ARDUINO_DIGITAL_PIN12 = 12,   /**< Aliased to #EAST_D2_PIN */
  ARDUINO_DIGITAL_PIN13 = 13,   /**< Aliased to #BODY_RGB_RED_PIN */

  ARDUINO_ANALOG_PIN1 = 14,     /**< Aliased to #NORTH_ISENSE_PIN */
  ARDUINO_ANALOG_PIN2 = 15,     /**< Aliased to #SOUTH_ISENSE_PIN */
  ARDUINO_ANALOG_PIN3 = 16,     /**< Aliased to #EAST_ISENSE_PIN */
  ARDUINO_ANALOG_PIN4 = 17,     /**< Aliased to #WEST_ISENSE_PIN */
  ARDUINO_ANALOG_PIN5 = 18,
  ARDUINO_ANALOG_PIN6 = 19,

  NORTH_BASE_PIN = 20,
  NORTH_D0_PIN = NORTH_BASE_PIN+FACE_D0_PIN, /**< Pin 20: D0 on the North face */
  NORTH_D1_PIN = NORTH_BASE_PIN+FACE_D1_PIN, /**< Pin 21: D1 on the North face */
  NORTH_D2_PIN = NORTH_BASE_PIN+FACE_D2_PIN, /**< Pin 22: D2 on the North face */
  NORTH_D3_PIN = NORTH_BASE_PIN+FACE_D3_PIN, /**< Pin 23: D3 on the North face */
  NORTH_RX_PIN = NORTH_BASE_PIN+FACE_RX_PIN, /**< Pin 24: Serial Rx on the North face */
  NORTH_TX_PIN = NORTH_BASE_PIN+FACE_TX_PIN, /**< Pin 25: Serial Tx on the North face */
  NORTH_VIN_ENABLE_PIN = NORTH_BASE_PIN+FACE_VIN_ENABLE_PIN, /**< Pin 26: Power input enable on the North face */
  NORTH_VOUT_ENABLE_PIN = NORTH_BASE_PIN+FACE_VOUT_ENABLE_PIN, /**< Pin 27: Power output enable on the North face */
  NORTH_ISENSE_PIN = NORTH_BASE_PIN+FACE_ISENSE_PIN, /**< Pin 28: ADC current sense on the North face */
  NORTH_LED_PIN = NORTH_BASE_PIN+FACE_LED_PIN, /**< Pin 29: Active-low LED on the North face */
  NORTH_SIDE_LED_PIN = NORTH_BASE_PIN+FACE_SIDE_LED_PIN, /**< Pin 30: Active-low side LED on the North face */

  SOUTH_BASE_PIN = 31,
  SOUTH_D0_PIN = SOUTH_BASE_PIN+FACE_D0_PIN, /**< Pin 31: D0 on the South face */
  SOUTH_D1_PIN = SOUTH_BASE_PIN+FACE_D1_PIN, /**< Pin 32: D1 on the South face */
  SOUTH_D2_PIN = SOUTH_BASE_PIN+FACE_D2_PIN, /**< Pin 33: D2 on the South face */
  SOUTH_D3_PIN = SOUTH_BASE_PIN+FACE_D3_PIN, /**< Pin 34: D3 on the South face */
  SOUTH_RX_PIN = SOUTH_BASE_PIN+FACE_RX_PIN, /**< Pin 35: Serial Rx on the South face */
  SOUTH_TX_PIN = SOUTH_BASE_PIN+FACE_TX_PIN, /**< Pin 36: Serial Tx on the South face */
  SOUTH_VIN_ENABLE_PIN = SOUTH_BASE_PIN+FACE_VIN_ENABLE_PIN, /**< Pin 37: Power input enable on the South face */
  SOUTH_VOUT_ENABLE_PIN = SOUTH_BASE_PIN+FACE_VOUT_ENABLE_PIN, /**< Pin 38: Power output enable on the South face */
  SOUTH_ISENSE_PIN = SOUTH_BASE_PIN+FACE_ISENSE_PIN, /**< Pin 39: ADC current sense on the South face */
  SOUTH_LED_PIN = SOUTH_BASE_PIN+FACE_LED_PIN, /**< Pin 40: Active-low LED on the South face */
  SOUTH_SIDE_LED_PIN = SOUTH_BASE_PIN+FACE_SIDE_LED_PIN, /**< Pin 41: Active-low side LED on the South face */

  EAST_BASE_PIN = 42,
  EAST_D0_PIN = EAST_BASE_PIN+FACE_D0_PIN, /**< Pin 42: D0 on the East face */
  EAST_D1_PIN = EAST_BASE_PIN+FACE_D1_PIN, /**< Pin 43: D1 on the East face */
  EAST_D2_PIN = EAST_BASE_PIN+FACE_D2_PIN, /**< Pin 44: D2 on the East face */
  EAST_D3_PIN = EAST_BASE_PIN+FACE_D3_PIN, /**< Pin 45: D3 on the East face */
  EAST_RX_PIN = EAST_BASE_PIN+FACE_RX_PIN, /**< Pin 46: Serial Rx on the East face */
  EAST_TX_PIN = EAST_BASE_PIN+FACE_TX_PIN, /**< Pin 47: Serial Tx on the East face */
  EAST_VIN_ENABLE_PIN = EAST_BASE_PIN+FACE_VIN_ENABLE_PIN, /**< Pin 48: Power input enable on the East face */
  EAST_VOUT_ENABLE_PIN = EAST_BASE_PIN+FACE_VOUT_ENABLE_PIN, /**< Pin 49: Power output enable on the East face */
  EAST_ISENSE_PIN = EAST_BASE_PIN+FACE_ISENSE_PIN, /**< Pin 50: ADC current sense on the East face */
  EAST_LED_PIN = EAST_BASE_PIN+FACE_LED_PIN, /**< Pin 51: Active-low LED on the East face */
  EAST_SIDE_LED_PIN = EAST_BASE_PIN+FACE_SIDE_LED_PIN, /**< Pin 52: Active-low side LED on the East face */

  WEST_BASE_PIN = 53,
  WEST_D0_PIN = WEST_BASE_PIN+FACE_D0_PIN, /**< Pin 53: D0 on the West face */
  WEST_D1_PIN = WEST_BASE_PIN+FACE_D1_PIN, /**< Pin 54: D1 on the West face */
  WEST_D2_PIN = WEST_BASE_PIN+FACE_D2_PIN, /**< Pin 55: D2 on the West face */
  WEST_D3_PIN = WEST_BASE_PIN+FACE_D3_PIN, /**< Pin 56: D3 on the West face */
  WEST_RX_PIN = WEST_BASE_PIN+FACE_RX_PIN, /**< Pin 57: Serial Rx on the West face */
  WEST_TX_PIN = WEST_BASE_PIN+FACE_TX_PIN, /**< Pin 58: Serial Tx on the West face */
  WEST_VIN_ENABLE_PIN = WEST_BASE_PIN+FACE_VIN_ENABLE_PIN, /**< Pin 59: Power input enable on the West face */
  WEST_VOUT_ENABLE_PIN = WEST_BASE_PIN+FACE_VOUT_ENABLE_PIN, /**< Pin 60: Power output enable on the West face */
  WEST_ISENSE_PIN = WEST_BASE_PIN+FACE_ISENSE_PIN, /**< Pin 61: ADC current sense on the West face */
  WEST_LED_PIN = WEST_BASE_PIN+FACE_LED_PIN, /**< Pin 62: Active-low LED on the West face */
  WEST_SIDE_LED_PIN = WEST_BASE_PIN+FACE_SIDE_LED_PIN, /**< Pin 63: Active-low side LED on the West face */

  /* Non-face-specific pins */
  BODY_SWITCH0_PIN = 64,        /**< Pin 64: Active low button pressed */
  BODY_RGB_RED_PIN = 65,        /**< Pin 65: Active low center RGB red LED */ 
  BODY_RGB_GREEN_PIN = 66,      /**< Pin 66: Active low center RGB green LED */
  BODY_RGB_BLUE_PIN = 67,       /**< Pin 67: Active low center RGB blue LED */

  BODY_EEPROM_SSEL1_PIN = 68,   /**< Pin 68: EEPROM SSEL */ 
  BODY_EEPROM_SCK1_PIN = 69,    /**< Pin 69: EEPROM SCK */ 
  BODY_EEPROM_MISO1_PIN = 70,   /**< Pin 70: EEPROM MISO */ 
  BODY_EEPROM_MOSI1_PIN = 71,   /**< Pin 71: EEPROM MOSI */ 

  BODY_AMUX_READ_PIN = 72,      /**< Pin 72: Analog MUX Common read */ 
  BODY_AMUX_SELA_PIN = 73,      /**< Pin 73: Analog MUX Select A */ 
  BODY_AMUX_SELB_PIN = 74,      /**< Pin 74: Analog MUX Select B */ 
  BODY_AMUX_SELC_PIN = 75,      /**< Pin 75: Analog MUX Select C */ 

  VIRTUAL_PIN_COUNT = 76,

  /* Alternate names and structures on the pin numbers */
  ALIAS_COUNT=20,
  FIRST_SFB_PIN=20
};

/**
 * A description of a single SFB-programmer-visible hardware pin.
 *
 * The attribute is added to force word alignment without union shenanigans...
 */
struct PinInfo_s  {
  u8 portNumber;  /** The LPC2000 port number of the pin. 0..4. */
  u8 bitNumber;   /** The bit number within the port, 0..31. */
  u8 aliasMode;   /** If >= ALIAS_COUNT, provides alias (alternate index), else default mode */
  u8 flags;       /** Bitwise-OR of PinInfoFlags values of this pin */
} __attribute__ ((aligned (4)));

/**
 * Given a virtual pin 'sfbPin' (which may be an 'Arduino alias'), set
 * portVar to the port number and maskVar (u32) to the bit mask for
 * that virtual pin.  Will also UPDATE sfbPin if necessary, for it to
 * have a non-alias value!  infoVar (u32) is scratch storage.
 */
#define SFB_GET_PIN_PORT_AND_MASK(sfbPin,infoVar,portVar,maskVar) \
 do {                                                           \
   (infoVar) = pinInfoMap[sfbPin];                              \
   if ((infoVar).aliasMode >= ALIAS_COUNT) {                    \
     (sfbPin) = (infoVar).aliasMode;                            \
     (infoVar) = pinInfoMap[sfbPin];                            \
   }                                                            \
   (portVar) = (infoVar).portNumber;                            \
   (maskVar) = 1UL<<(infoVar).bitNumber;                        \
 } while (0)

typedef const struct PinInfo_s PinInfo_t;  /* We're putting the pin info into flash, so, const.. */
                  
extern PinInfo_t pinInfoMap[VIRTUAL_PIN_COUNT];  /* Read-only */

enum { PIN_SKETCH_MAP_WORDS = (VIRTUAL_PIN_COUNT+31)/32 };

#define GET_SKETCH_FLAG(sfbPin) \
  ((pinSketchMap[(sfbPin)>>5]>>((sfbPin)&31))&1)
#define SET_SKETCH_FLAG(sfbPin) \
  (pinSketchMap[(sfbPin)>>5] |= 1<<((sfbPin)&31))
#define CLR_SKETCH_FLAG(sfbPin) \
  (pinSketchMap[(sfbPin)>>5] &= ~(1<<((sfbPin)&31)))

extern u32 pinSketchMap[PIN_SKETCH_MAP_WORDS];   /* Bit mask of which pins the sketch is controlling */
      
extern int pinInFace(int facePin, int face);

extern void reflexDigitalWrite(int sfbPin, int value);
extern void implDigitalWrite(int sfbPin, int value);

static inline void reflexLedOn(int sfbPin) { reflexDigitalWrite(sfbPin,LOW); }
static inline void reflexLedOff(int sfbPin) { reflexDigitalWrite(sfbPin,HIGH); }
static inline void reflexLedSet(int sfbPin,int on) { reflexDigitalWrite(sfbPin,on?LOW:HIGH); }

extern int reflexDigitalRead(int sfbPin);
extern int implDigitalRead(int sfbPin);

extern void reflexPinMode(int sfbPin, int mode);
extern void implPinMode(int sfbPin, int mode);

extern void pins_startup_initialization();

/**
 * Manipulate pull-up and pull-down resistors on GPIO input pins
 *
 * @param sfbPin: The pin to configure
 * @param pullupDownCode: One of: 
 *           0 - enable pullup
 *           2 - enable neither pullup nor pulldown
 *           3 - enable pulldown
 */
#define PULLUP_ONLY 0
#define NEITHER_PULLUP_NOR_PULLDOWN 2
#define PULLDOWN_ONLY 3

extern void reflexSetPinResistor(int sfbPin, int pullupDownCode);
extern void implSetPinResistor(int sfbPin, int pullupDownCode);

#include "SFBHWPins.h"

#endif  /* SFBPINS_H */
