/*********************************  recode7.h  *******************************
 * $Source: /home/cvs/ESP/gen2/software/msp430/include/recode7.h,v $
 *  Copyright (C) 2003 MBARI
 *
 *  MBARI Proprietary Information. All rights reserved.
 * $Id: recode7.h,v 1.15 2004/05/19 06:11:47 brent Exp $
 *
 * Utilities for recoding 8-bit binary strings in 7-bit characters
 *
 *****************************************************************************/

#ifndef recode7_h
#define recode7_h

#include "types.h"

#ifndef shift7rt
#ifdef __ARCHELON__
#define shift7rt(word)  ((word) <<=1, (word) >>= 8)  //more efficient than >>=7
#else
#define shift7rt(word)  ((word)>>=7)
#endif
#endif

#ifndef shift7lf
#ifdef __ARCHELON__

static inline uint16 shiftnlf (register uint16 word, unsigned lfbits)
//optimized shift 16 bit word from 0..8 bits left
{ 
  register unsigned skip = 8;
  skip -= lfbits;
  skip += skip;
/$
  add @skip,pc
#rept 8
  rla @word
#endr
$/
  return word;
}

#else

#define shiftnlf(word,bits)   ((word)<<=(bits))

#endif
#endif

#ifndef EOF
#define EOF (-1)
#endif

/*
  Append the supplied octet to the stream of 7-bit characters
  bitsUnsent and leftovers must be declared as uint16 temporaries.
  putByte(octet) is a function that writes a byte to the stream.
  put7start begins the stream (initializes temporaries)
  put7end ends the stream.  Usage:
  
   uint16 leftovers, bitsUnsent;
   put7init();
   while (bytes remain) put7 (putByte, next byte);
   put7end(putByte);
*/
#define put7initFast(leftovers, bitsUnsent) ((leftovers) = 0, (bitsUnsent) = 0)
#define put7init()         put7initFast(leftovers, bitsUnsent)
#define put7end(putByte)   putByte (leftovers | 0x80)

#define put7(putByte, octet) { \
  if (bitsUnsent >= 7) {            \
    putByte (leftovers);            \
    put7init();                     \
  }                                 \
  leftovers |= shiftnlf((octet), bitsUnsent); \
  putByte (leftovers & 0x7f);       \
  shift7rt (leftovers);             \
  bitsUnsent++;                     \
}

/*
  Read an octet from a stream of 7-bit characters ended by
  a byte with its MSB set. int16 get7result is assigned the result.
  It is either an 8-bit byte or -1 for EOF. 
  Assumes getByte() returns the next 7-bit character in the stream.
  
  Usage:
  
   uint16 leftovers, bitsUnread;
   int16  get7result;
   get7init(getByte);
   for (;;) {
     get7(getByte);
     if (get7result == EOF) break;
     < do stuff with get7result >
   }
   if (get7null()) {
     byte trailingBits = get7extraBits();
     < do stuff with 7 bits that followed the null string >
   }   
*/

static const uint16 twoPower[] = {1,2,4,8,0x10,0x20,0x40,0x80};

// prime for subsequent get7() invocations
#define get7init(getByte)  (bitsUnread = 7, leftovers = getByte())

// true if all bytes have been returned from get7()
#define get7EOF()      (leftovers >= twoPower[bitsUnread])

// true if the stream consists of zero bytes
#define get7null()     (leftovers >= 0x80)

// any extra partial byte after the end of the stream
//  if get7null(), this will be a 7-bit quanity
#define get7extraBits()       (leftovers & (twoPower[bitsUnread]-1))
#define get7leftovers()       (leftovers & 0x7f)

#define get7fast(getByte, EOFexitOperation, empty) { \
  if (get7EOF()) EOFexitOperation;  \
  if (!bitsUnread) {      \
    {empty;}              \
    leftovers = getByte();\
    if (get7null()) EOFexitOperation; \
    bitsUnread = 7;       \
  }                       \
  {empty;}                \
  leftovers |= shiftnlf (getByte(), bitsUnread); \
  --bitsUnread;           \
  get7result = leftovers & 0xff; \
  leftovers >>= 8;        \
}

#define get7(get8) {do get7fast (get8,{get7result=EOF;break;},) while (false);}

#endif

