//------------------------------------------------------------------------------
// File:          xon_xoff.c
// Function:      Implementation of the XON/XOFF flow control protocol
// Supported chip(s):
//    - AT91SAM7XC128
//    - AT91SAM7XC256
// Supported toolchain(s):
//    - IAR Embedded Workbench
// Date created:  03 May 2006
// Created by:    JJo
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------

#include "xon_xoff.h"

#ifdef USE_XON_XOFF

//------------------------------------------------------------------------------
// Functions
//------------------------------------------------------------------------------

/**
 * Name:      communication_init
 * Purpose:   Initializes the XON/XOFF protocol
 */
void communication_init(void) {

  debug_printf("XON/XOFF: Initializing ...\nXON/XOFF: Initialization done.\n");
}

/**
 * Name:      communication_cleanup
 * Purpose:   Cleans-up the XON/XOFF protocol
 */
void communication_cleanup(void) {

  debug_printf("XON/XOFF: Cleaning up ...\nXON/XOFF: Cleanup done.\n");
}

/**
 * Name:      communication_ready
 * Purpose:   Notifies the host that the device is ready to receive the firmware
 */
void communication_ready() {

  debug_printf("XON/XOFF: Device ready for firmware.\n");
  
  // Waits for first bytes
  while (media_poll() == 0);
}

/**
 * Name:      communication_receive
 * Purpose:   Waits for a page of firmware code and returns it
 * Inputs:
 *  - Buffer in which to store the received page
 * Output:    Size (in bytes) of the page received
 */
unsigned int communication_receive(void * vAddress) {

  // Local variables
  unsigned int bytes;
  unsigned int remaining;
  unsigned int endOfFirmware;

  // Restart transfer
  media_writeChar(XON);

  // Wait for data, monitoring activity to detect the end of the firmware
  endOfFirmware = FALSE;
  bytes = 0;

  while (!endOfFirmware && (bytes < MEMORY_PAGE_SIZE)) {

    bytes = media_poll();
    endOfFirmware = TRUE;

    for (unsigned int i=0; i < XON_XOFF_WAIT_COUNT; i++) {

      if (bytes != media_poll()) {

        endOfFirmware = FALSE;
        break;
      }
    }
  }

  if (bytes != 0) {

    // Read page
    if (bytes > MEMORY_PAGE_SIZE) {

      bytes = MEMORY_PAGE_SIZE;
    }
    bytes = media_read(vAddress, bytes);

    // Send XOFF control character and wait for remaining characters
    media_writeChar(XOFF);
    remaining = media_poll();
    
    for (unsigned int i=0; i < XON_XOFF_WAIT_COUNT; i++) {

      if (remaining != media_poll()) {

        remaining = media_poll();
        i = 0;
      }
    }
  }

  return bytes;
}

#endif // USE_XON_XOFF

