#include "archinc.h"
#include "config.h"
#include "spimesg.h"
#include "spi.h"

#ifdef CONFIG_INCLUDE_SPIPROT

typedef enum { expectSync, expectFrameType, expectFrameArg, expectPayloadLen, expectPayload, expectCrc16Byte0, expectCrc16Byte1} receiveState;

static receiveState rcvState;

spiprotFrameValidatorType frameValidator = NULL;

int spiprotInit(void)
{
  rcvState = expectSync;
  frameValidator = NULL; // no frame validator to start

  return 0;
}

void spiprotSetFrameValidator(spiprotFrameValidatorType newFrameValidator)
{
  frameValidator = newFrameValidator;
  return;
}

static unsigned int bytesExpected = 0;

#ifdef CONFIG_TOOLCHAIN_IAR
#pragma inline
#endif
static void INLINE_KEYWORD updateReceiveState(char receivedData)
{
  if (rcvState == expectSync) {
    // when we are expecting sync, throw away all chars until sync is received
    if (receivedData == SPIPROT_SYNC_CHAR) {
      rcvState = expectFrameType;
      }
    }
  else if (rcvState == expectFrameArg) {
    rcvState = expectPayloadLen;
    }
    currentParamCount = (int)receivedData;
    if (currentParamCount == 0) {
      rcvState = expectTerm;
      }
    else {
      rcvState = expectParamTag;
      }
    }
  else if (rcvState == expectPayloadLen) {
    }
  else if (rcvState == expectParamData) {
    if (bytesExpected == 0) {
      if (--currentParamCount <= 0) {
        rcvState = expectTerm;
        }
      else {
        rcvState = expectParamTag;
        }
      }
    }    
  else if (rcvState == expectTerm) {
    if (receivedChar == SPIPROT_TERMINATOR) {
      // mark the frame as complete and pass to the upper layer
      // get another frame
      rcvState = expectSync;
      }
    else {
      // buffer the character in the current frame
      // TODO: update frame data checksum
      }
    }
  else {
    // unknown state -- toss packet and goto expectSync
    rcvState = expectSync;
    }
  }


void spiprotEventHandler(void)
{
  char ch;

#ifdef CONFIG_ARCH_MSP430
  while ((retVal = usart1RxOne(&ch)) != -1)
    updateReceiveState(ch);
#endif /* CONFIG_ARCH_MSP430 */

#ifdef CONFIG_ARCH_LPC2XXX
  while ((retVal = spiGet(&ch)) != -1)
    updateReceiveState(ch);
#endif /* CONFIG_ARCH_LPC2XXX */
}

#endif /* CONFIG_INCLUDE_SPIPROT */
