/*                                             -*- mode:C++; fill-column:100 -*-
  SFBPacket.h - Packet structure and access 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 SFBPacket.h Packet structure and access methods
  \author David H. Ackley.  
  \date (C) 2009 All rights reserved.
  \lgpl
 */
#ifndef SFBPACKET_H_
#define SFBPACKET_H_

#include "SFBTypes.h"
#include "SFBAssert.h"

/**
   The information associated with a packet, when it is stored in memory only -- there is no
   preestablished packet header on the wire.  Normally these fields are never accessed directly,
   instead, see #packetSource(), #packetFlags(), #packetCursor(), and #packetLength().
 */
struct PacketHeader {
  u8 source;                
  u8 flags;  /* PK_OVERRUN|PK_PARITY|PK_FRAMING|PK_BREAK|PK_BUFFER|PK_BAD_ESCAPE */
  u8 cursor;
  u8 length;
};

/** \cond */
struct PacketBuffer {
  union {
    u32 wh;
    PacketHeader ph;
  } h;
  u8 bbuf[SINGLE_PACKET_BUFFER_SIZE_BYTES];
};
/** \endcond */

/* SFB packet framing special character codes */
#define PFSC_END  ((u8) '\012')  /* End of packet. AKA 'newline', ^J, 0x0a, NOT carriage return */
#define PFSC_ESC  ((u8) '\333')  /* Indicates escaped byte code follows, 0xdb */
#define PFSC_EEND ((u8) '\334')  /* ESC EEND means END data byte, 0xdc */
#define PFSC_EESC ((u8) '\335')  /* ESC EESC means ESC data byte, 0xdd */

#define CHECK_BYTE_INIT_VALUE (0xF0)
#define CHECK_BYTE_UPDATE(v,d) ((v) =  ((v<<1)|((v>>7)&1))^d)

/** Low-level packet handling methods 
    @{
*/

inline const PacketHeader & packetHeaderInternalUnsafeConst(const u8 * packet) {
  return *(const PacketHeader *) (packet-4);
}

inline PacketHeader & packetHeaderInternalUnsafe(u8 * packet) {
  return *(PacketHeader *) (packet-4);
}

extern u8 packetLength(const u8 * packet);

extern u8 packetReadLength(const u8 * packet);

extern u8 packetFlags(const u8 * packet);

extern u8 packetSource(const u8 * packet);

extern u8 packetCursor(const u8 * packet);

extern bool packetCheckByteValid(const u8 * packet);

#define API_ASSERT_VALID_PACKET(u8ptr) API_ASSERT(validPacket(u8ptr),E_API_INVALID_PACKET)

extern bool validPacket(const u8 * packet) ;

extern void packetReread(u8 * packet, u32 newIndex = 0) ;

extern bool packetRead(u8 * packet, int &result, int code = DEC, u32 maxLen = MAX_PACKET_LENGTH) ;

extern bool packetRead(u8 * packet, u32 &result, int code = DEC, u32 maxLen = MAX_PACKET_LENGTH) ;

extern bool packetReadCheckByte(u8 * packet) ;

extern bool packetReadEOF(u8 * packet) ;

extern bool packetReadPacket(u8 * packet, u8 *& subpacket) ;

extern bool zpacketPrefix(u8 * packet, const char * to);

extern u8 * makePacket(u8 * buffer, u32 bufferLength, u8 face, const char * packetData);

extern u8 * makePacket(u8 * buffer, u32 bufferLength, u8 face, const u8 * packetData, u32 packetDataLength);

/** 
    @}
*/

#endif /* SFBPACKET_H_ */
