/*                                             -*- mode:C++; fill-column:100 -*-
  SFBHWSerialBoard.h Low-level serial support for the board
  Copyright (C) 2009 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 SFBHWSerialBoard.h Low-level serial support for the board
  \author David H. Ackley.  
  \date (C) 2009 All rights reserved.
  \lgpl
 */

#ifdef SFBHWSERIALHOST_H
#error SFBHWSerialBoard.h and SFBHWSerialHost.h must not be #included together!
#endif

#ifndef SFBHWSERIALBOARD_H
#define SFBHWSERIALBOARD_H

#include "SFBFrame.h"
#include "lpc/LPC23xx.h" /* get the hardware definitions */

class SFBSerial; /* FORWARD DECLARATION */

#define CAN_WRITE(fd) (REGISTER_OFFSET(fd,UxLSR) & 0x20)
#define WRITE_BYTE(fd,byte) (REGISTER_OFFSET(fd,UxTHR) = (byte))
#define CAN_READ(fd) (REGISTER_OFFSET(fd,UxLSR) & 0x01)
#define READ_BYTE(fd) REGISTER_OFFSET(fd,UxRBR)

/**
 * The object supporting 'hardware level' serial operations on the SFB.  
 *
 * WARNING!  There are two classes _both_ named 'SFBHWSerial'; this one for SFB serial
 * communication, defined in SFBHWSerialBoard.h and SFBHWSerialBoard.cpp, and another one for
 * host-side communication, defined in SFBHWSerialHost.h and SFBHWSerialHost.cpp.  Only one
 * definition is seen on any particular compilation, due to conditional compilation in
 * SFBHWSerial.h.  This definition is used if HOST_MODE is _not_ defined.
 *
 * This is awkward, but was done to avoid inheritance, with its associated complexities and
 * additional vtable pointers.
 */
class SFBHWSerial {  /* Note we are defining 'SFBHWSerial', not 'SFBHWSerialBoard'! */

public:

  SFBHWSerial(int face) ;

  SFBFrame & getFrame() { return theFrame; }

  void putcBlocking(const u8 byte) ;

  static u32 getFirstFace() { return NORTH; }
  static bool moreFaces(u32 face) ;
  static u32 nextFace(u32 face) ;

  static SFBSerial & getFace(u32 face) ;

  bool getPreferOddParity() { return true; } // N(one) wins unless both sides say O(dd).  But we like odd for robustness.
  u8 getPreferredBaudCode() { return 4; } // Code 4 is SFBAUD115200.  Often 5==SFBAUD230400 is doable, tbough..
  u8 getLowBaudCode() { return 0; }
  u8 getHighBaudCode() { return 6; }

  void predispatch() { /* nothing to do */ }

  void start(u32 baud, bool oddParity = false);
  void stop() ;
  void setBaudRate(u32 baud, bool oddParity = false) ;
  void checkTx() ;
  u32 getFD();

private:

  void uartCommonHandler() ;    /* The interrupt routine */
  friend void Uart0Handler();   /* Which these guys can call*/ 
  friend void Uart1Handler();
  friend void Uart2Handler();
  friend void Uart3Handler();

  PacketBuffer & rxBuf;         /* Inbound packets are dispatched from here */
  SFBRxByteBuffer rxBytes;      /* Interrupt level writes raw inbound UART RX data to here */
  SFBTxByteBuffer txBytes;      /* Interrupt level reads raw outbound UART TX data from here */
  SFBFrame theFrame;            /* Packets are framed and deframed here */
  u32 lastInputActivity;        /* millis() of last char read */ 
  bool txActive;
  const u8 face;

  enum {
    FLAG_TX_ACTIVE = 0x02     /* Interrupt is TXing, we don't need to initiate it */
  };

public:
  //  static void startup_initialization() ;
};

#endif  /* SFBHWSERIALBOARD_H */

