#include "archinc.h"
#include "config.h"
#include "spiframe.h"
#include "spi.h"

#ifdef CONFIG_INCLUDE_SPIPROT

typedef enum { expectSync, expectFrameType, expectFrameArg, expectPayloadLen, expectPayload, expectCrc16Byte0, expectCrc16Byte1} receiveState;

static receiveState rcvState;
static int unexpectedFrameTypeCount;
static int currentFrameType;

#define CONFIG_SPIPROT_NUM_RECV_FRAMES (4)
#define CONFIG_SPIPROT_RECV_FRAME_SIZE (128)

static char receivedFrames[CONFIG_SPIPROT_NUM_RECV_FRAMES][CONFIG_SPIPROT_RECV_FRAME_SIZE];

// bit = frame number, 0 = frame free, 1 = frame in use
static int receivedFrameStatus[CONFIG_SPIPROT_NUM_RECV_FRAMES];

int spiprotInit(void)
{
  rcvState = expectSync;

  /*
   * Since we are a slave, load a sync character right away. This character will get sent back to the 
   * master while we are (hopefully) receiving the sync character from the master. Since we have configured
   * the interface as a slave, it should not begin a transaction
   */

  spiSendOne(SPIPROT_SYNC_CHAR);  
  return 0;
}

// release a message frame sent to the upper layer
int spiprotReleaseFrame(int frameNumber)
{
}

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 == expectFrameType) {
    // call frame type validator
    if (frameValidator != NULL) {
      switch((*frameValidator)(receivedData)) {
        case SPIPROT_FRAME_TYPE_INVALID:
          // reset the receive state machine
          rcvState = expectSync;
          break;
        case SPIPROT_FRAME_TYPE_VALID_NO_PARAM_COUNT:
          rcvState = expectTerm;
          break;
        case SPIPROT_FRAME_TYPE_VALID:
          rcvState = expectParamCount;
          break;
        default:
          break;
        } // switch
      } // if (validator)
    }
  else if (rcvState == expectParamCount) {
    // get 
    currentParamCount = (int)receivedData;
    if (currentParamCount == 0) {
      rcvState = expectTerm;
      }
    else {
      rcvState = expectParamTag;
      }
    }
  else if (rcvState == expectParamTag) {
    if (sizeofParam != NULL) {
      }
    }
  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 */
