/*                                             -*- mode:C++; fill-column:100 -*-
  SFBFrame.h - Packet de/framing methods
  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
*/

/**
  \file SFBFrame.h Class packet framing methods.
  \author David H. Ackley.  
  \date (C) 2009 All rights reserved.
  \lgpl
 */
#ifndef SFBFRAME_H_
#define SFBFRAME_H_

#include "SFBTypes.h"
#include "SFBByteBuffer.h"
#include "SFBAssert.h"
#include "SFBPacket.h"

/**
   Handles packet framing and deframing.  
 */
class SFBFrame {
public:
  SFBFrame(SFBRxByteBuffer & r, SFBTxByteBuffer & t, PacketBuffer & p, u8 face) ; 

  u8 * pollForRxPacket() ;
  
  bool txCanAddByte() ;         ///< Returns true if there's definitely room to store a byte now
  void txDataByte(u8 data) ;    ///< Add another data byte to current tx packet
  void txEndPacket();

  void reset() ;                ///< Performs a #resetRx() and a #resetTx()
  void resetRx() ;              ///< Reset the RX side of the frame.  Any pending inbound packets
                                ///  are discarded, and sync is lost.
  void resetTx() ;              ///< Reset the TX side of the frame.  Any pending outbound packets
                                ///  are discarded.

  enum FrameTypes {
    STANDARD_PACKET,
    BYTE_PER_PACKET,
    MAX_FRAME_TYPES
  };

  void setRxFrameType(u32 frameType) ;
  void setTxFrameType(u32 frameType) ;
  u32 getRxFrameType() { return rxFrameType; }
  u32 getTxFrameType() { return txFrameType; }
private:

  bool rxByte(int byteOrErrorVal); ///< Return true if a dispatchable packet was just completed 
  bool rxByteNonstandard(int byteVal); ///< Return true if a dispatchable packet was just completed (nonstandard packet framing)

  bool rxStoreRaw(u8 byte); ///< Stash data byte in packet buffer.  True if error lost sync
  void rxSetupError(u8 flags) ; ///< Format a broken packet header for dispatch, with given flags
  void rxSetupPacket() ; ///< Format a good packet header for dispatch

  void txDataByteNonstandard(u8 data); ///< Add another data byte to current tx packet (nonstandard packet framing)

  SFBRxByteBuffer & rxBuf;
  SFBTxByteBuffer & txBuf;
  PacketBuffer & deframeBuffer;
  int txCount;
  int rxCount;                  // ==-1 if lost sync due to error or frame overflow
  bool rxEscape;                // true if halfway through escape sequence
  u8 rxFrameType;
  u8 txFrameType;
  const u8 face;
};
#endif /* SFBFRAME_H_ */
