/*                                       -*- 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, /* 20 */
  NORTH_D1_PIN = NORTH_BASE_PIN+FACE_D1_PIN, /* 21 */
  NORTH_D2_PIN = NORTH_BASE_PIN+FACE_D2_PIN, /* 22 */
  NORTH_D3_PIN = NORTH_BASE_PIN+FACE_D3_PIN, /* 23 */
  NORTH_RX_PIN = NORTH_BASE_PIN+FACE_RX_PIN, /* 24 */
  NORTH_TX_PIN = NORTH_BASE_PIN+FACE_TX_PIN, /* 25 */
  NORTH_VIN_ENABLE_PIN = NORTH_BASE_PIN+FACE_VIN_ENABLE_PIN, /* 26 */
  NORTH_VOUT_ENABLE_PIN = NORTH_BASE_PIN+FACE_VOUT_ENABLE_PIN, /* 27 */
  NORTH_ISENSE_PIN = NORTH_BASE_PIN+FACE_ISENSE_PIN, /* 28 */
  NORTH_LED_PIN = NORTH_BASE_PIN+FACE_LED_PIN, /* 29 */
  NORTH_SIDE_LED_PIN = NORTH_BASE_PIN+FACE_SIDE_LED_PIN, /* 30 */

  SOUTH_BASE_PIN = 31,
  SOUTH_D0_PIN = SOUTH_BASE_PIN+FACE_D0_PIN, /* 31 */
  SOUTH_D1_PIN = SOUTH_BASE_PIN+FACE_D1_PIN, /* 32 */
  SOUTH_D2_PIN = SOUTH_BASE_PIN+FACE_D2_PIN, /* 33 */
  SOUTH_D3_PIN = SOUTH_BASE_PIN+FACE_D3_PIN, /* 34 */
  SOUTH_RX_PIN = SOUTH_BASE_PIN+FACE_RX_PIN, /* 35 */
  SOUTH_TX_PIN = SOUTH_BASE_PIN+FACE_TX_PIN, /* 36 */
  SOUTH_VIN_ENABLE_PIN = SOUTH_BASE_PIN+FACE_VIN_ENABLE_PIN, /* 37 */
  SOUTH_VOUT_ENABLE_PIN = SOUTH_BASE_PIN+FACE_VOUT_ENABLE_PIN, /* 38 */
  SOUTH_ISENSE_PIN = SOUTH_BASE_PIN+FACE_ISENSE_PIN, /* 39 */
  SOUTH_LED_PIN = SOUTH_BASE_PIN+FACE_LED_PIN, /* 40 */
  SOUTH_SIDE_LED_PIN = SOUTH_BASE_PIN+FACE_SIDE_LED_PIN, /* 41 */

  EAST_BASE_PIN = 42,
  EAST_D0_PIN = EAST_BASE_PIN+FACE_D0_PIN, /* 42 */
  EAST_D1_PIN = EAST_BASE_PIN+FACE_D1_PIN, /* 43 */
  EAST_D2_PIN = EAST_BASE_PIN+FACE_D2_PIN, /* 44 */
  EAST_D3_PIN = EAST_BASE_PIN+FACE_D3_PIN, /* 45 */
  EAST_RX_PIN = EAST_BASE_PIN+FACE_RX_PIN, /* 46 */
  EAST_TX_PIN = EAST_BASE_PIN+FACE_TX_PIN, /* 47 */
  EAST_VIN_ENABLE_PIN = EAST_BASE_PIN+FACE_VIN_ENABLE_PIN, /* 48 */
  EAST_VOUT_ENABLE_PIN = EAST_BASE_PIN+FACE_VOUT_ENABLE_PIN, /* 49 */
  EAST_ISENSE_PIN = EAST_BASE_PIN+FACE_ISENSE_PIN, /* 50 */
  EAST_LED_PIN = EAST_BASE_PIN+FACE_LED_PIN, /* 51 */
  EAST_SIDE_LED_PIN = EAST_BASE_PIN+FACE_SIDE_LED_PIN, /* 52 */

  WEST_BASE_PIN = 53,
  WEST_D0_PIN = WEST_BASE_PIN+FACE_D0_PIN, /* 53 */
  WEST_D1_PIN = WEST_BASE_PIN+FACE_D1_PIN, /* 54 */
  WEST_D2_PIN = WEST_BASE_PIN+FACE_D2_PIN, /* 55 */
  WEST_D3_PIN = WEST_BASE_PIN+FACE_D3_PIN, /* 56 */
  WEST_RX_PIN = WEST_BASE_PIN+FACE_RX_PIN, /* 57 */
  WEST_TX_PIN = WEST_BASE_PIN+FACE_TX_PIN, /* 58 */
  WEST_VIN_ENABLE_PIN = WEST_BASE_PIN+FACE_VIN_ENABLE_PIN, /* 59 */
  WEST_VOUT_ENABLE_PIN = WEST_BASE_PIN+FACE_VOUT_ENABLE_PIN, /* 60 */
  WEST_ISENSE_PIN = WEST_BASE_PIN+FACE_ISENSE_PIN, /* 61 */
  WEST_LED_PIN = WEST_BASE_PIN+FACE_LED_PIN, /* 62 */
  WEST_SIDE_LED_PIN = WEST_BASE_PIN+FACE_SIDE_LED_PIN, /* 63 */

  /* Non-face-specific pins */
  BODY_SWITCH0_PIN = 64,
  BODY_RGB_RED_PIN = 65,
  BODY_RGB_GREEN_PIN = 66,
  BODY_RGB_BLUE_PIN = 67,

  BODY_EEPROM_SSEL1_PIN = 68,
  BODY_EEPROM_SCK1_PIN = 69,
  BODY_EEPROM_MISO1_PIN = 70,
  BODY_EEPROM_MOSI1_PIN = 71,

  VIRTUAL_PIN_COUNT = 72,

  /* 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 */
