[Tinyos-contrib-commits] CVS: tinyos-1.x/contrib/imote2/tools/src/bootloader/src AttrAccess.c, NONE, 1.1 BinImageHandler.c, NONE, 1.1 BootLoader.c, NONE, 1.1 Crc.c, NONE, 1.1 FlashAccess.c, NONE, 1.1 HPLInit.c, NONE, 1.1 Leds.c, NONE, 1.1 Makefile, NONE, 1.1 PMIC.c, NONE, 1.1 PXA27XClock.c, NONE, 1.1 PXA27XGPIOInt.c, NONE, 1.1 PXA27XHardware.c, NONE, 1.1 PXA27XInterrupt.c, NONE, 1.1 PXA27Xdynqueue.c, NONE, 1.1 TOSSched.c, NONE, 1.1 USBClient.c, NONE, 1.1 bare.x, NONE, 1.1 barecrt.s, NONE, 1.1 binarymover.s, NONE, 1.1 flash.s, NONE, 1.1 main.c, NONE, 1.1 mmu_table.s, NONE, 1.1 util.s, NONE, 1.1

Lama Nachman lnachman at users.sourceforge.net
Tue Oct 10 15:34:08 PDT 2006


Update of /cvsroot/tinyos/tinyos-1.x/contrib/imote2/tools/src/bootloader/src
In directory sc8-pr-cvs10.sourceforge.net:/tmp/cvs-serv22490

Added Files:
	AttrAccess.c BinImageHandler.c BootLoader.c Crc.c 
	FlashAccess.c HPLInit.c Leds.c Makefile PMIC.c PXA27XClock.c 
	PXA27XGPIOInt.c PXA27XHardware.c PXA27XInterrupt.c 
	PXA27Xdynqueue.c TOSSched.c USBClient.c bare.x barecrt.s 
	binarymover.s flash.s main.c mmu_table.s util.s 
Log Message:
Pushed out new release OCT 2006


--- NEW FILE: AttrAccess.c ---
//$Id: AttrAccess.c,v 1.1 2006/10/10 22:34:06 lnachman Exp $
/*									tab:4
 * "Copyright (c) 2000-2003 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 * Copyright (c) 2002-2003 Intel Corporation
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE     
 * file. If you do not find these files, copies can be found by writing to
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
 * 94704.  Attention:  Intel License Inquiry.
 */

/**
 * @file AttrAccess.c
 * @author Junaith Ahemed Shahabdeen
 *
 * Attributes are parameters that is used by the system to make it
 * flexible and configurable with out recompiling the source, few
 * examples will be <I>Number of Retries on a command failure</I> and
 * <I>timeout values for a response</I> etc.
 *
 * This file provides functions for getting and setting atrributes together
 * with helper functions for locating the position of an attribute or a
 * table that contains a particular attribute. The attributes, length, and
 * its table size is defined in <I>BLAttrDefines</I>.
 */
#include <AttrAccess.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <BinImageHandler.h>
#include <Leds.h>

/*** To be included only in the source*/
#include <BLAttributeVal.h>

/**
 * Read_Attribute_Data
 *
 * Read the attribute from the flash. 
 * The function copies only the whole attribute to the buffer.
 *
 * <B>
 * NOTE:
 *    NEVER PASS A BUFFER POINTER WHICH CANNOT ACCOMODATA A
 *    LENGTH OF (sizeof (Attribute) + length of Attribute).
 * </B>
 *
 * @param attr Id of the Attribute which has to be retrived.
 * @parma data Buffer to which the entire attribute struct will be copied to.
 *
 * @return SUCCESS | FAIL
 */
result_t Read_Attribute (uint16_t attr, void* data)
{
  Attribute* attPtr;
  ATTR_Address_Table table = Get_Attribute_TableID (attr);
  uint8_t length = Get_Attribute_Length (attr);
  uint8_t AttributeBuff [sizeof (Attribute) + length];
  uint32_t AttrPos = 1;
  attPtr = (Attribute*) AttributeBuff; 
  uint8_t errbuff [60];
  uint8_t ErrVal = 0;

  if ((table == FAIL) || (length == FAIL))
    return FAIL;
  
  /** 
   * Load the address table to find the current address.
   */
  AttrPos = (uint32_t) Get_Attr_Flash_Address (table, attr);
  if (AttrPos == FAIL)
  {
    return FAIL;
  }
  if(Flash_Read(AttrPos, (sizeof (Attribute) + length), AttributeBuff) == FAIL)
  {
    Send_USB_Error_Packet (ERR_FLASH_READ, 0, NULL);
    return FAIL;
  }
  /**FIXME i think for loop might be better*/
  /*Check if the attribute value is valid in the current location*/
  if (attPtr->AttrValidity == BL_INVALID_ATTR)
  {
    /* If we add exactly the table size then we can get to the right position
     * of the attribute.
     */
    AttrPos += BL_TABLE_SIZE;
    if(Flash_Read(AttrPos, sizeof (Attribute) + length, AttributeBuff) == FAIL)
    {
      Send_USB_Error_Packet (ERR_FLASH_READ, 0, NULL);
      return FAIL;
    }
  }
  /* Check the validity of the data.*/
  attPtr = (Attribute*) AttributeBuff; 
  if (attPtr->AttrType == attr)
  {
   /**
    * We might have attributes that are not integers and could be
    * an array. So its better to check it byte by byte.
    */
    for (ErrVal = 0; ErrVal < attPtr->AttrLength; ErrVal++)  
      if (attPtr->AttrValue [ErrVal] != 0xFF)
         break;
    if (ErrVal <= (attPtr->AttrLength - 1))
    {
      memcpy (data, AttributeBuff, (sizeof (Attribute) + length));
      return SUCCESS;
    }
    else
      sprintf (errbuff, "Attribute contains invalid value.\n");
  }
  else
    sprintf (errbuff, "Error Reading Attribute Location.\n");
  
  Send_USB_Error_Packet (ERR_FATAL_ERROR_ABORT, 60, errbuff);  
  return FAIL;
}


/**
 * Read_Attribute_Value
 *
 * Read the attribute data of a particular attribute from the flash. 
 * The function copies only the value of the attribute to the parameter
 * passed. As a precondition the user has to get the length of the
 * attribute and create a buffer which can hold that value, before
 * passing the buffer as a parameter to this fucntion.
 *
 * NOTE:
 *    NEVER PASS A BUFFER POINTER WHICH CANNOT ACCOMODATA THE
 *    ATTRIBUTE VALUE.
 *
 * @param attr The Attribute Id.
 * @param data Pointer to the buffer to which the value will be copied to.
 *
 * @return SUCCESS | FAIL
 */
result_t Read_Attribute_Value (uint16_t attr, void* data)
{
  Attribute* attPtr;
  ATTR_Address_Table table = Get_Attribute_TableID (attr);
  uint8_t length = Get_Attribute_Length (attr);
  uint8_t AttributeBuff [sizeof (Attribute) + length];
  uint32_t AttrPos = 1;
  attPtr = (Attribute*) AttributeBuff; 
  uint8_t errbuff [60];
  uint8_t ErrVal = 0;

  if ((table == FAIL) || (length == FAIL))
    return FAIL;

  /** 
   * Load the address table to find the current address.
   */
  AttrPos = (uint32_t) Get_Attr_Flash_Address (table, attr);
  if (AttrPos == FAIL)
    return FAIL;

  if(Flash_Read(AttrPos, sizeof (Attribute) + length, AttributeBuff) == FAIL)
  {
    Send_USB_Error_Packet (ERR_FLASH_READ, 0, NULL);
    return FAIL;
  }
  attPtr = (Attribute*) AttributeBuff; 
  /**FIXME i think for loop might be better*/
  /*Check if the attribute value is valid in the current location*/
  if (attPtr->AttrValidity == BL_INVALID_ATTR)
  {
    /**
     * If we add exactly the table size then we can get to the right position
     * of the attribute.
     */
    AttrPos += BL_TABLE_SIZE;
    if(Flash_Read(AttrPos, sizeof (Attribute) + length, AttributeBuff) == FAIL)
    {
      Send_USB_Error_Packet (ERR_FLASH_READ, 0, NULL);
      return FAIL;
    }
    attPtr = (Attribute*) AttributeBuff; 
  }

  if (attPtr->AttrType == attr)
  {
   /**
    * We might have attributes that are not integers and could be
    * an array. So its better to check it byte by byte.
    */
    for (ErrVal = 0; ErrVal < attPtr->AttrLength; ErrVal++)  
      if (attPtr->AttrValue [ErrVal] != 0xFF)
         break;
    if (ErrVal <= (attPtr->AttrLength - 1))
    {
      memcpy (data, attPtr->AttrValue, length);
      return SUCCESS;
    }
    else
      sprintf (errbuff, "Attribute contains invalid value.\n");
  }
  else
    sprintf (errbuff, "Error Reading Attribute Location.\n");

  Send_USB_Error_Packet (ERR_FATAL_ERROR_ABORT, 60, errbuff);
  return FAIL;
}

/**
 * Recover_Default_Table
 *
 * Reset a table to its default state. Usually performed during disaster
 * recovery.
 * @param table The table to be reset.
 * @return SUCCESS | FAIL
 */
result_t Recover_Default_Table (ATTR_Address_Table table)
{
  uint8_t* AttrBuff;
  uint32_t DefBaseAddress = 1;
  uint32_t BaseAddress = 1;
  uint32_t TblSize = 0;
  result_t res = SUCCESS;
  switch (table)
  {
    case BL_ATTR_TYP_ADDRESS_TABLE:
      /*FIXME Send an error stating that its write protected*/
      return FAIL;
    break;
    case BL_ATTR_TYP_DEF_BOOTLOADER:
    case BL_ATTR_TYP_BOOTLOADER:
      DefBaseAddress = BL_ATTR_DEF_BOOTLOADER;
      BaseAddress = BL_ATTR_BOOTLOADER;
      TblSize = BOOTLOADER_TABLE_SIZE;
    break;
    case BL_ATTR_TYP_DEF_SHARED:
    case BL_ATTR_TYP_SHARED:
      DefBaseAddress = BL_ATTR_DEF_SHARED;
      BaseAddress = BL_ATTR_SHARED;
      TblSize = SHARED_TABLE_SIZE;
    break;
    default:
    return FAIL;
  }
  AttrBuff = (uint8_t*) malloc (TblSize * sizeof(uint8_t));
  if (AttrBuff == NULL)
    return FAIL;
  
  if(Flash_Read(DefBaseAddress, TblSize, AttrBuff) == FAIL)
  {
    free (AttrBuff);
    Send_USB_Error_Packet (ERR_FLASH_READ, 0, NULL);
    return FAIL;
  }
  
  if (Flash_Erase (BaseAddress) == FAIL)
    res = FAIL;
  
  if (Flash_Write (BaseAddress, AttrBuff, TblSize) == FAIL)
    res = FAIL;

  free (AttrBuff);
  return res;
}

/**
 * Read_Attribute_Table
 *
 * The function copies the entire attribute table in to the
 * second parameter. The higher level is responsible for
 * allocating the data and passing the required length.
 *
 * @param TblAddr Starting Address of the table has to be read.
 * @param length  Length of the table.
 * @param data	  RAM location to copy the table to.
 *
 * @return SUCCESS | FAIL
 */
result_t Read_Attribute_Table (uint32_t TblAddr, uint32_t length, void* data)
{
  if(Flash_Read(TblAddr, length, data) == FAIL)
  {
    Send_USB_Error_Packet (ERR_FLASH_READ, 0, NULL);
    return FAIL;
  }  
  return SUCCESS;
}

/**
 * Write_Attribute_Table
 * 
 * Write the entire table back to the flash memory. The entire flash
 * block will be erase and the table will be rewritten.
 *
 * @param TblAddr Starting Address of the table.
 * @param length  Length of the table.
 * @param data    Pointer to the table in memory.
 *
 * @return SUCCESS | ERROR
 */ 
result_t Write_Attribute_Table (uint32_t TblAddr, uint32_t length, void* data)
{
  /* cannot fail. If we do then we should replace the attr */
  if (Flash_Erase (TblAddr) == FAIL)
    return FAIL;
  if (Flash_Write (TblAddr, data, length) == FAIL)
    return FAIL; /*FIXME Bad. Load the default attr back*/
  return SUCCESS;
}

/**
 * Write_Attribute_Value
 *
 * This function will update an attribute with a new value. The
 * attribute id and the value of the attribute is passed as
 * parameter.
 *
 * @param AttrID ID of the Attribute that is updated.
 * @param Val    new Value to be updated.
 *
 * @return SUCCESS | ERROR
 */
result_t Write_Attribute_Value (uint16_t AttrID, uint32_t Val)
{
  Attribute* attPtr;
  ATTR_Address_Table table = Get_Attribute_TableID (AttrID);
  uint8_t length = Get_Attribute_Length (AttrID);
  uint8_t AttributeBuff [sizeof (Attribute) + length];
  uint32_t InValidAttrPos = 1;
  uint32_t ValidAttrReadPos = 1;
  uint32_t ValidAttrWritePos = 1;
  uint32_t BaseAddress = 1;
  uint32_t TblSize = 0;
  uint8_t* AttrBuff;
  uint8_t Invalid = BL_INVALID_ATTR;
  attPtr = (Attribute*) AttributeBuff; 

  /* If its some thing like 0xFFFFFFFF then its not allowed*/
  if (Val == 0xFFFFFFFF)
    return FAIL;

  if ((table == FAIL) || (length == FAIL))
    return FAIL;

  switch (table)
  {
    case BL_ATTR_TYP_ADDRESS_TABLE:
    case BL_ATTR_TYP_DEF_BOOTLOADER:
    case BL_ATTR_TYP_DEF_SHARED:
      /*FIXME Send an error stating that its write protected*/
      return FAIL;
    break;
    case BL_ATTR_TYP_BOOTLOADER:
      BaseAddress = BL_ATTR_BOOTLOADER;
      TblSize = BOOTLOADER_TABLE_SIZE;
    break;
    case BL_ATTR_TYP_SHARED:
      BaseAddress = BL_ATTR_SHARED;
      TblSize = SHARED_TABLE_SIZE;
    break;
    default:
    return FAIL;
  }

  AttrBuff = (uint8_t*) malloc (TblSize * sizeof(uint8_t));
  if (AttrBuff == NULL)
    return FAIL;  /*FIXME fatal error, requires more handling*/

  {
    ValidAttrReadPos = (uint32_t) Get_Attr_Flash_Address (table, AttrID);
    if(Flash_Read(ValidAttrReadPos, sizeof (Attribute) + length, AttributeBuff) == FAIL)
    {
      free (AttrBuff);
      Send_USB_Error_Packet (ERR_FLASH_READ, 0, NULL);
      return FAIL;
    }

    /*Check if the attribute value is valid in the current location*/
    if (attPtr->AttrValidity == BL_VALID_ATTR)
    {
      InValidAttrPos = ValidAttrReadPos + 2; /* Add size of type */
      //ValidAttrReadPos = BaseAddress;
      ValidAttrWritePos = BaseAddress + BL_TABLE_SIZE;
    }
    else
    {
      InValidAttrPos = ValidAttrReadPos + BL_TABLE_SIZE + 2; /* Add size of type */
      //ValidAttrReadPos = BaseAddress + BL_TABLE_SIZE;
      ValidAttrWritePos = BaseAddress;
    }

    if(Flash_Read(ValidAttrWritePos, TblSize, AttrBuff) == FAIL)
    {
      free (AttrBuff);
      Send_USB_Error_Packet (ERR_FLASH_READ, 0, NULL);
      return FAIL;
    }
    else
    {
      uint32_t offset = (ValidAttrReadPos - BaseAddress);
      attPtr = (Attribute*) (AttrBuff + offset);
      attPtr->AttrValidity = BL_VALID_ATTR; /* Make it valid*/
      memcpy (attPtr->AttrValue, &Val, 4);     /* Assign the new value*/
    }

    /* cannot fail. If we do then we should replace the attr */
    if (Flash_Erase (ValidAttrWritePos) == FAIL)
    {
      free (AttrBuff);
      return FAIL;
    }
    if (Flash_Write (ValidAttrWritePos, AttrBuff, TblSize) == FAIL)
    {
      free (AttrBuff);
      return FAIL; /*FIXME Bad. Load the default attr back*/
    }
    if (Flash_Write (InValidAttrPos, &Invalid, 1) == FAIL)
    {
      free (AttrBuff);
      return FAIL;
    }
  }
  free (AttrBuff);
  return SUCCESS;
}

/**
 * Write_Attribute_Set
 *
 * The function provides an efficiently updating a list of 
 * attributes that belong to the same table in a single pass. The
 * AttrSet values must be set before it is passed to the function and
 * the number of attributes in the set cannot exceed ATTR_SET_LIMIT (20).
 * <B>It is absolutely required that the attributes must belong to 
 * the same table. </B>
 *
 * As a <I>precondition</I> the AttrSet has to be populated with
 * the required information and the table id of the attributes has
 * to be obtained.
 * 
 * @param table Table Id for the set.
 * @param aset	Attribute set with the list of attr and its values.
 *
 * @return SUCCESS | ERROR
 */
result_t Write_Attribute_Set (ATTR_Address_Table table, AttrSet* aset)
{
  Attribute* attPtr;
  Attribute* attPtr2;
  uint32_t BaseAddress = 1;
  uint32_t TblSize = 0;
  uint8_t AttrBuff1 [0x2000];
  uint8_t AttrBuff2 [0x2000];
  uint16_t acnt = 0;
  uint16_t oall = 0;
  uint16_t mlen = 0;
  uint16_t NumAttr = 0;

  if (table == FAIL)
    return FAIL;
  /**
   * We are currently restricting the number of attributes in
   * a set.
   */
  if (aset->NumAttributes > ATTR_SET_LIMIT)
    return FAIL;

  switch (table)
  {
    case BL_ATTR_TYP_ADDRESS_TABLE:
    case BL_ATTR_TYP_DEF_BOOTLOADER:
    case BL_ATTR_TYP_DEF_SHARED:
      /*FIXME Send an error stating that its write protected*/
      return FAIL;
    break;
    case BL_ATTR_TYP_BOOTLOADER:
      BaseAddress = BL_ATTR_BOOTLOADER;
      TblSize = BOOTLOADER_TABLE_SIZE;
      NumAttr = BL_ATTR_BOOTLOADER_TABLE_NUM;
    break;
    case BL_ATTR_TYP_SHARED:
      BaseAddress = BL_ATTR_SHARED;
      TblSize = SHARED_TABLE_SIZE;
      NumAttr = ATTR_SHARED_TABLE_NUM;
    break;
    default:
    return FAIL;
  }

  /* Read first Location */
  if(Flash_Read(BaseAddress, TblSize, AttrBuff1) == FAIL)
  {
    Send_USB_Error_Packet (ERR_FLASH_READ, 0, NULL);
    return FAIL;
  }
  
  /* Read secondary Location (BaseAddress + table size)*/
  if(Flash_Read((BaseAddress + BL_TABLE_SIZE), TblSize, AttrBuff2) == FAIL)
  {
    Send_USB_Error_Packet (ERR_FLASH_READ, 0, NULL);
    return FAIL;
  }

  for (oall = 0; oall < aset->NumAttributes; oall ++)
  {
    mlen = 0;
    for (acnt = 0; acnt < NumAttr; acnt ++)
    {
      attPtr = (Attribute*) (AttrBuff1 + mlen);
      if (attPtr->AttrType == aset->AttrId [oall])
      {
        if (attPtr->AttrValidity == BL_VALID_ATTR)
        {
          /*FIXME check that the length is same as the current */
          memcpy (attPtr->AttrValue, &aset->AttrVal [oall], attPtr->AttrLength);
          //memcpy ((AttrBuff1 + mlen + sizeof (Attribute)), &aset->AttrVal [oall], 4);
        }
        else
        {
          attPtr2 = (Attribute*) (AttrBuff2 + mlen);
          if (attPtr2->AttrValidity == BL_VALID_ATTR)
          {
            memcpy (attPtr2->AttrValue, &aset->AttrVal [oall], attPtr2->AttrLength);
            //memcpy ((AttrBuff2 + mlen + sizeof (Attribute)), &aset->AttrVal [oall], 4);
          }
          else
          {
            /*FIXME this is actually a bug, both locations cannot be invalid.
             * Right now we are just fixing it and adding a new value.
             */
            attPtr2->AttrValidity = BL_VALID_ATTR;
            memcpy (attPtr2->AttrValue, &aset->AttrVal [oall], attPtr2->AttrLength);
            //memcpy ((AttrBuff2 + mlen + sizeof (Attribute)), &aset->AttrVal [oall], 4);
          }
        }
        acnt = NumAttr; /* Get out of the inner FOR LOOP*/
      }
      /*Move to the begining to next attribute*/
      mlen += sizeof (Attribute) + 4; //attPtr->AttrLength;
    }
  }
  
  /**
   * Write the frist table back with all the modification
   */
  if (Flash_Erase (BaseAddress) == FAIL)
  {
    return FAIL;
  }
  if (Flash_Write (BaseAddress, AttrBuff1, TblSize) == FAIL)
  {
    return FAIL; /*FIXME Bad. Load the default attr back*/
  }

  /**
   * Write the second table back with all the modification
   */
  if (Flash_Erase (BaseAddress + BL_TABLE_SIZE) == FAIL)
  {
    return FAIL;
  }
  if (Flash_Write ((BaseAddress + BL_TABLE_SIZE), AttrBuff2, TblSize) == FAIL)
  {
    return FAIL; /*FIXME Bad. Load the default attr back*/
  }
  return SUCCESS;
}


/**
 * Get_Attribute_TableID
 * 
 * Returns a table ID for a particular attribute type. The BLAttrDefines.h
 * file defines the attribute type ranges.
 *
 * @param attr Attribute Type for which the table name is required.
 * @return TABLE ID | 0 on error
 */
ATTR_Address_Table Get_Attribute_TableID (uint16_t attr)
{
  if ((attr < 25) && (attr > 0))
    return BL_ATTR_TYP_ADDRESS_TABLE;
  else if ((attr < 351) && (attr > 49))
    return BL_ATTR_TYP_BOOTLOADER;
  else if ((attr < 800) && (attr > 350))
    return BL_ATTR_TYP_SHARED;
    
  return 0;
}

/**
 * Get_Attribute_Length
 *
 * Get the length of the attribute by passing the attribute type.
 * 
 * @param attr Attribute Type for which to find the Length.
 * @return Length | 0 on error
 */
uint8_t Get_Attribute_Length (uint16_t attr)
{
  ATTR_Address_Table table = Get_Attribute_TableID(attr);
  uint16_t NumItem = 0;
  uint16_t* tblPtr;
  uint16_t i = 0;

  switch (table)
  {
    case BL_ATTR_TYP_ADDRESS_TABLE:
      NumItem = BL_ATTR_ADDRESS_TABLE_NUM*2;
      tblPtr = (uint16_t*) Gen_ATTR_Addr_Table[0];
    break;
    case BL_ATTR_TYP_DEF_BOOTLOADER:
      NumItem = BL_ATTR_BOOTLOADER_TABLE_NUM*2;
      tblPtr = (uint16_t*) Gen_ATTR_Bootloader_Table[0];
    break;
    case BL_ATTR_TYP_BOOTLOADER:
      NumItem = BL_ATTR_BOOTLOADER_TABLE_NUM*2;
      tblPtr = (uint16_t*) Gen_ATTR_Bootloader_Table[0];
    break;
    case BL_ATTR_TYP_DEF_SHARED:
      NumItem = ATTR_SHARED_TABLE_NUM*2;
      tblPtr = (uint16_t*) Gen_ATTR_Shared_Table[0];
    break;
    case BL_ATTR_TYP_SHARED:
      NumItem = ATTR_SHARED_TABLE_NUM*2;
      tblPtr = (uint16_t*) Gen_ATTR_Shared_Table[0];
    break;
    default:
    return FAIL;
  }

  for (i = 0;i < NumItem; i+=2)
  {
    if (tblPtr [i] == attr)
      return tblPtr [i+1];
  }

  return FAIL;
}

/**
 * Get_Attr_Flash_Address
 *
 * Given the table name and the attribute id the function will
 * calculate the current flash address location of the attribute.
 * 
 * @param TblID The table Id in which the attribute belongs.
 * @param AttrID  The ID of the attribute.
 *
 * @return Addr Address of the attribute.
 */
uint32_t Get_Attr_Flash_Address (ATTR_Address_Table TblID, uint16_t AttrID)
{
  uint32_t Addr = 0;
  uint8_t Length = sizeof (Attribute);
  uint16_t NumItem = 0;
  uint16_t* tblPtr;
  uint16_t i = 0;
  
  switch (TblID)
  {
    case BL_ATTR_TYP_ADDRESS_TABLE:
      Addr = BL_ATTR_ADDRESS_TABLE;
      NumItem = BL_ATTR_ADDRESS_TABLE_NUM * 2;
      tblPtr = (uint16_t*) Gen_ATTR_Addr_Table[0];
    break;
    case BL_ATTR_TYP_DEF_BOOTLOADER:
      Addr = BL_ATTR_DEF_BOOTLOADER;
      NumItem = BL_ATTR_BOOTLOADER_TABLE_NUM * 2;
      tblPtr = (uint16_t*) Gen_ATTR_Bootloader_Table[0];
    break;
    case BL_ATTR_TYP_BOOTLOADER:
      Addr = BL_ATTR_BOOTLOADER;
      NumItem = BL_ATTR_BOOTLOADER_TABLE_NUM * 2;
      tblPtr = (uint16_t*) Gen_ATTR_Bootloader_Table[0];
    break;
    case BL_ATTR_TYP_DEF_SHARED:
      Addr = BL_ATTR_DEF_SHARED;
      NumItem = ATTR_SHARED_TABLE_NUM*2;
      tblPtr = (uint16_t*) Gen_ATTR_Shared_Table[0];
    break;
    case BL_ATTR_TYP_SHARED:
      Addr = BL_ATTR_SHARED;
      NumItem = ATTR_SHARED_TABLE_NUM*2;
      tblPtr = (uint16_t*) Gen_ATTR_Shared_Table[0];
    break;
    default:
    return FAIL;
  }

  for (i = 0;i < NumItem; i+=2)
  {
    if (tblPtr [i] == AttrID)
      return Addr;
    else
      Addr += (Length + tblPtr [i + 1]);
  }
  return FAIL;
}

--- NEW FILE: BinImageHandler.c ---
/*									tab:4
 * "Copyright (c) 2000-2003 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 * Copyright (c) 2002-2003 Intel Corporation
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE     
 * file. If you do not find these files, copies can be found by writing to
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
 * 94704.  Attention:  Intel License Inquiry.
 */

/**
 * @file BinImageHandler.c
 * @author Junaith Ahemed Shahabdeen
 *
 * This file serves as a layer above the <I>USB driver</I>. It 
 * receives a the USB Packet and parses the data part to
 * identify a command or binary data. The <B>boot loader state
 * machine</B> is directly controlled by this file based on the
 * current download context or error conditions.
 */
#include <string.h>
#include <stdio.h>
#include <hardware.h>
#include <BinImageHandler.h>
#include <FlashAccess.h>
#include <Leds.h>
#include <BootLoader.h>
#include <stdlib.h>
#include <Crc.h>
#include <AttrAccess.h>
#include <PXA27XClock.h>
#include <TOSSched.h>

/**
 * We are handling the code download in this file for now,
 * may be this has to move to a different location. - js
 */
static uint8_t rcvBuffer [BIN_DATA_WINDOW_SIZE * IMOTE_HID_SHORT_MAXPACKETDATA];
uint16_t NumPckReceived = 0;   /* number of packets received per window*/
uint32_t TotalPckReceived = 0; /* Total number of packets received during download*/ 
uint32_t NumPckExpected = 0;   /* Total Number of packet expected */
uint32_t ImageSize = 0;        /* Total Size of the image being downloaded*/
uint32_t ValidBuffSize = 0;    /* Total Size received for the current buffer*/
uint8_t WindowCount = 0;       /* Number of chunks received currently*/
bool SelfTestImage = FALSE;    /* Identifies if we are loading a self test image*/

uint32_t NumCrcRetries = 0;     /* Number of CRC Retries from attributes*/
uint8_t CrcRetries = 0;         /* Number of CRC Retries*/
uint32_t CmdRetries = 0;        /* Number of CRC Retries*/
uint32_t CmdTimeOut = 0;        /* Timeout Value for commands*/
uint32_t BinTimeOut = 0;        /* Timeout value for binary data*/

/* Variables used for flash dump */
uint8_t DmpWindowCount = 0; /* Number of chunks sent to the PC application*/
uint32_t TotalPckSent = 0;  /* Total number of packets uploaded during dump*/ 

uint32_t CurrLoadAddr = 0;
bool FlashDumpMode = FALSE;

uint16_t dbg_curr_crc = 0;
uint16_t dbg_rcv_crc = 0;

TimeoutDetail toutdetail;

/**
 * Binary_Image_Packet_Received
 *
 * The function is a signal from the USB Driver when a binary 
 * data packet is received. The function stores the binary data in 
 * the RAM Buffer till the BIN_DATA_WINDOW_SIZE is reached. If the 
 * sequence number matches with the windown size then the function 
 * changes the <B>boot loader internal state</B> to <B>VERIFY_CURRENT_BUFFER</B>.
 * The state change indicates that the current buffer is completely
 * downloaded and the next command from the PC app (CRC Check) can 
 * be executed on the RAM Buffer.
 * 
 * @param data Buffer with binary data.
 * @param length Length of the valid part of buffer.
 * @param seq Sequence number of the packet.
 */
void Binary_Image_Packet_Received (uint8_t* data, uint8_t length, uint32_t seq)
{
  memcpy (rcvBuffer + (NumPckReceived * IMOTE_HID_SHORT_MAXPACKETDATA), data, length);
  ++ NumPckReceived;
  ValidBuffSize += length;

#ifdef MMU_ENABLE  
  ++ TotalPckReceived;
  if (TotalPckReceived >= NumPckExpected)
  {
    Check_Timeout_Disable (1, 0);
    Change_Internal_CodeLoad_State (VERIFY_CURRENT_BUFFER);
  }
  else
  {
    if (NumPckReceived >= (BIN_DATA_WINDOW_SIZE))
    {
      Check_Timeout_Disable (1, 0);
      Change_Internal_CodeLoad_State (VERIFY_CURRENT_BUFFER);
    }
  }
  //Check_Timeout_Disable (1, 0);
#else
  ++ TotalPckReceived;
  if (TotalPckReceived >= NumPckExpected)
    Change_Internal_CodeLoad_State (VERIFY_CURRENT_BUFFER);
  else
  {
    if (NumPckReceived < (BIN_DATA_WINDOW_SIZE))
      BootLoader_State_Machine ();
    else
      Change_Internal_CodeLoad_State (VERIFY_CURRENT_BUFFER);
  }
#endif
}

/**
 * Check_Buffer_Crc 
 *
 * Check the CRC of the current RAM buffer and return the
 * result.
 * 
 * @param start  Current Start packet.
 * @param numpck number of packets downloaded in to the current buffer.
 * @param crc    CRC of the current buffer.
 *
 * @return SUCCESS| FAIL
 */
result_t Check_Buffer_Crc (uint32_t start, uint32_t numpck, uint16_t crc)
{
  uint16_t CurrentCRC = 0;
  CurrentCRC = Crc_Buffer (rcvBuffer, 
                    ValidBuffSize,
                    CurrentCRC);
  dbg_curr_crc = CurrentCRC;
  if (CurrentCRC == crc)
    return SUCCESS;
  else
    return FAIL;
  return FAIL;
}


/**
 * Request_Next_Binary_Chunk
 *
 * The function requests the next binary chunk of size 
 * <I>BIN_DATA_WINDOW_SIZE</I> from the PC app. This function is 
 * invoked from the boot loader state machine when the current state 
 * is <I>REQUEST_USB_PACKETS</I>.
 * It also sets the time out value for the buffer download.
 *
 * @return SUCCESS | FAIL
 */
result_t Request_Next_Binary_Chunk ()
{
  uint8_t buff [62];
  USBCommand* cmd;
  CmdReqBinData req;

  int len = sizeof (USBCommand) + sizeof (CmdReqBinData);
  cmd = (USBCommand*) buff;
  cmd->type = CMD_REQUEST_BIN_DATA;
  req.PckStart = (WindowCount * BIN_DATA_WINDOW_SIZE);
  /* The case where we wont need the full window (we dont have enough packets)*/
  if ((NumPckExpected - TotalPckReceived) < BIN_DATA_WINDOW_SIZE)
    req.NumUSBPck = (NumPckExpected - TotalPckReceived);
  else
    req.NumUSBPck = (BIN_DATA_WINDOW_SIZE);
  req.ChunkSize = TotalPckReceived;
  Prepare_Buffer_Download (TotalPckReceived, NumPckExpected);
  memcpy (cmd->data, &req, sizeof (CmdReqBinData));
  Send_Command_Packet (cmd, len);

  toutdetail.TimeoutMS = BinTimeOut;
  toutdetail.MsgId = 1; /*Indicates Binary Packet*/
  toutdetail.Type = CMD_REQUEST_BIN_DATA;
  toutdetail.ExpectedType = 0; /*No specific type*/
  toutdetail.NumRetries = CmdRetries;
  toutdetail.NotifyFunc = &Command_Timeout;
  Enable_Timeout (&toutdetail);
  return SUCCESS;
}


/**
 * Request_Next_Binary_Packet
 *
 * While in the MMU Disabled mode it is impossible to receive chunks
 * of data from the PC app, because the processing is not fast enough to
 * keep up with the data rate. It is easier to switch to request
 * each packet.
 *
 * @return SUCCESS | FAIL
 * 
 */
result_t Request_Next_Binary_Packet ()
{
  CmdReqBinData req;
  int len = sizeof (CmdReqBinData);

  /* We want the seq number to start from 1*/
  req.PckStart = (NumPckReceived + 1);/* Seq number will be the same as this*/
  req.NumUSBPck = 1;                  /* We are requesting one at a time */
  req.ChunkSize = TotalPckReceived;   /* For diag purposes */

  Send_USB_Command_Packet (CMD_REQUEST_BIN_PCK, len, &req);
  return SUCCESS;
}

/**
 * Command_Timeout
 * 
 * The function is a signal from the timer module to indicate
 * that timeout value has reached for a particular operation.
 * The action required for the signal is determined by the
 * message type and the number of retires.
 * 
 * NOTE:
 *   If the number of retries expired then it usually indicates
 * a fatal comminucation error in the current code, the board 
 * will send a fata error message and will reboot.
 *
 * @param MsgId Message Type (command, or binary etc)
 * @parma Typ Type of command or any other message.
 * @param retries Number of retries left. (usually reducing).
 *
 */
void Command_Timeout (uint8_t MsgId, uint8_t Typ, uint8_t retries)
{
  bool SendErr = FALSE;
  uint8_t buff [61];

  switch (Typ)
  {
    case CMD_GET_IMAGE_DETAILS:
      if (retries)
      {
        Change_BootLoader_State (CODE_LOAD);
        TOS_post (&BootLoader_State_Machine);
      }
      else
      {
        sprintf (buff, "No Image Details. Aborting.");
        SendErr = TRUE;
      }
    break;
    case CMD_REQUEST_BIN_DATA:
      if (retries)
      {
        if (Get_BootLoader_State () == CODE_LOAD)
          Change_Internal_CodeLoad_State (REQUEST_USB_PACKETS);
        TOS_post (&BootLoader_State_Machine);
      }
      else
      {
        sprintf (buff, "Did not receive binary data. Aborting");
        SendErr = TRUE;
      }
    break;
    default:
      TOGGLE_LED (RED);
    break;
  }

  /**
   * Right now we are only sending a fatal errors but not all
   * failures are fatal, FIXME needs to handle the errors
   */
  if (SendErr)
  {
    Send_USB_Error_Packet (ERR_FATAL_ERROR_ABORT, sizeof buff, buff);
    Reboot_Device ();
  }

  return;
}

/**
 * Command_Packet_Received
 * 
 * Signal from the USB Driver when a command packet is received.
 * The payload is parsed to identify the command type and based
 * on the command type the rest of the data is handled.
 * The commands and the data structure for each command is
 * defined in <B>MessageDefines.h</B>.
 *
 * @param data Data Payload of the USB Packet.
 * @param length Length of the payload.
 *
 * @return SUCCESS | FAIL
 */
result_t Command_Packet_Received (uint8_t* data, uint8_t length)
{
  USBCommand* cmd = (USBCommand*) data;
  Check_Timeout_Disable (0, cmd->type);
  switch (cmd->type)
  {
    case RSP_REBOOT:
      OSMR3 = OSCR0 + 9000;
      OWER = 1;
      while(1);
    break;
    case RSP_USB_CODE_LOAD:
    {
      result_t ret = FAIL;
      if (cmd->data [0] == SELFTEST)
      {
        ret = Read_Attribute_Value (BL_ATTR_TYP_DEF_SELF_TEST_IMG_LOC,
                                    (void*)&CurrLoadAddr);
	SelfTestImage = TRUE;
      }
      else if (cmd->data [0] == APPLICATION)
      {
        ret = Read_Attribute_Value (BL_ATTR_TYP_SECONDARY_IMG_LOCATION,
                                    (void*)&CurrLoadAddr);
      }

      if (ret == SUCCESS)
      {
        if (Read_Attribute_Value (BL_ATTR_TYP_CMD_FAIL_RETRY,
                                     &CmdRetries) == FAIL)
          CmdRetries = 3; /* Dont make a big deal, just do it thrice*/
        if (Read_Attribute_Value (BL_ATTR_TYP_CRC_FAIL_RETRY,
                                     (void*)&NumCrcRetries) == FAIL)
          NumCrcRetries = 3; /* Dont make a big deal, just do it thrice*/
        if (Read_Attribute_Value (BL_ATTR_TYP_CMD_TIMEOUT,
                                     &CmdTimeOut) == FAIL)
          CmdTimeOut = CMD_TIMEOUT_VAL;
        if (Read_Attribute_Value (BL_ATTR_TYP_BIN_TIMEOUT,
                                     &BinTimeOut) == FAIL)
         BinTimeOut = BIN_TIMEOUT_VAL;
	
        toutdetail.TimeoutMS = CmdTimeOut;
        toutdetail.MsgId = 0;
        toutdetail.Type = CMD_GET_IMAGE_DETAILS;
        toutdetail.ExpectedType = RSP_GET_IMAGE_DETAILS;
        toutdetail.NumRetries = CmdRetries;
        toutdetail.NotifyFunc = &Command_Timeout;
        Enable_Timeout (&toutdetail);

        Change_BootLoader_State (CODE_LOAD);
        BootLoader_State_Machine ();
      }
      else
      {
        /*If we cannot read the image location then its impossible to continue*/
        uint8_t errbuff [60];
        Change_BootLoader_State (NORMAL);
        sprintf (errbuff, "Could not read Loading Location Attribute\n");
        Send_USB_Error_Packet (ERR_FATAL_ERROR_ABORT, 60, errbuff);
      }
    }
    break;
    case RSP_GET_IMAGE_DETAILS:
    if ((Get_BootLoader_State () == CODE_LOAD))
    {
      result_t ret = FAIL;
      RspImageDetail imgdetail;
      memcpy (&imgdetail, cmd->data, sizeof (RspImageDetail));
      ImageSize = imgdetail.ImageSize;
      NumPckExpected = imgdetail.NumUSBPck;
      if (SelfTestImage)
        if (ImageSize < 0x40000)
          ret = Write_Attribute_Value (BL_ATTR_TYP_DEF_SELF_TEST_IMG_SIZE,
                                                              ImageSize);
        else
        {
          uint8_t errbuff [60];
          sprintf (errbuff,"Image Size too big for Self Test. Should be less than 256K.");
          Send_USB_Error_Packet (ERR_FATAL_ERROR_ABORT, 60, errbuff);
          Reboot_Device ();
        }	
      else
        ret = Write_Attribute_Value (BL_ATTR_TYP_SECONDARY_IMG_SIZE,
                                                             ImageSize);
      if (ret == SUCCESS)
      {
        if (Get_BootLoader_State () == CODE_LOAD)
          Change_Internal_CodeLoad_State (REQUEST_USB_PACKETS);
        //else
          //FIXME this cannot happen, Send an error.
        BootLoader_State_Machine ();
      }
      else
      {
        uint8_t errbuff [60];
        Change_BootLoader_State (NORMAL);
        sprintf (errbuff, "Could not write ImageSize to Attribute\n");
        Send_USB_Error_Packet (ERR_FATAL_ERROR_ABORT, 60, errbuff);
      }
    }
    else
    {
      uint8_t errbuff [60];
      Change_BootLoader_State (NORMAL);
      sprintf (errbuff, "Wrong State. Cannot continue upload.\n");
      Send_USB_Error_Packet (ERR_FATAL_ERROR_ABORT, 60, errbuff);
    }
    break;
    case RSP_CRC_CHECK:
      if (Get_Internal_CodeLoad_State() == VERIFY_CURRENT_BUFFER)
      {
        CmdCrcData chkcrc;
        bool Abort = FALSE;
        memcpy (&chkcrc, cmd->data, sizeof(CmdCrcData));
        if (Handle_Cmd_Verify_Buffer_Crc (&chkcrc) == FAIL)
        {
          /* For what ever reason, if we fail we have to get the chunk back*/
          TotalPckReceived = TotalPckReceived - NumPckReceived;
          ++ CrcRetries;
          if (CrcRetries > NumCrcRetries)
            Abort = TRUE;
        }
        NumPckReceived = 0; /* Reset and prepare for next download*/
        ValidBuffSize = 0;
        /**
         * Determine if the download is complete and send appropriate
         * command to the PC.
         */
        if (!Abort)
        {
          if (TotalPckReceived < NumPckExpected)
            Change_Internal_CodeLoad_State (REQUEST_USB_PACKETS);
          else
            Change_Internal_CodeLoad_State (VERIFY_CURRENT_IMAGE);
          BootLoader_State_Machine ();
        }
        else
        {
          uint8_t errbuff [60];
          Change_BootLoader_State (NORMAL);
          sprintf (errbuff, "Too Many Crc Errors. Aborting \n");
          Send_USB_Error_Packet (ERR_FATAL_ERROR_ABORT, 60, errbuff);
        }
      }
      else if (Get_Internal_CodeLoad_State() == VERIFY_CURRENT_IMAGE)
      {
        CmdCrcData chkcrc;
        memcpy (&chkcrc, cmd->data, sizeof(CmdCrcData));
        /* FIXME Change the start address to point to the right attribute*/
        if (Handle_Cmd_Verify_Image_Crc (CurrLoadAddr, 
                 (uint32_t)(ImageSize),
                 chkcrc.ChunkCRC) == SUCCESS)
        {
      	  if (!(SelfTestImage))
          {
            if (Write_Attribute_Value (BL_ATTR_TYP_SECONDARY_IMG_CRC, 
                                           chkcrc.ChunkCRC) == FAIL)
              ; /*FIXME Actually This is serious, Incase if we crash we cant recover*/
            Set_Image_Details (ImageSize, CurrLoadAddr, chkcrc.ChunkCRC);
            Change_BootLoader_State_Attribute (CPY_TO_BOOT);
            Send_USB_Command_Packet (CMD_IMG_VERIFY_COMPLETE, 0, NULL);
            TOSH_SET_GREEN_LED_PIN();
            TOSH_SET_YELLOW_LED_PIN();
            TOS_post (&BootLoader_State_Machine);
          }
          else
          {
            if (Write_Attribute_Value (BL_ATTR_TYP_DEF_SELF_TEST_IMG_CRC, 
                                           chkcrc.ChunkCRC) == FAIL)
              ; /*FIXME Actually This is serious, Handle*/
            Reboot_Device ();
	  }
        }
        else
        {
          unsigned char buff [10];
          memset (buff, 0, 10);
          memcpy (buff, &ImageSize, 4);
          memcpy (buff + 4, &chkcrc.ChunkCRC, 2);
          memcpy (buff + 8, &dbg_curr_crc, 2);
          Send_USB_Error_Packet (TEST_CRC_FAILURE, 10, buff);
        }
      }
      else
      {
        uint8_t errbuff [60];
        sprintf (errbuff, "Invalid Buffer.\n");
        Send_USB_Error_Packet (ERR_FATAL_ERROR_ABORT, 60, errbuff);
      }
    break;
    case RSP_GET_ATTRIBUTE:
    {
      uint8_t buffer [62];
      uint16_t tsttyp;
      tsttyp = ((cmd->data [1] & 0xFF) << 8);
      tsttyp |= (cmd->data [0] & 0xFF);
      memset (buffer, 0, 62);
      if (Read_Attribute (tsttyp,
                     buffer) == SUCCESS)
      {
        Send_USB_Command_Packet (CMD_RSP_GET_ATTRIBUTE, 
                               61, buffer);
      }
      else
      {
        Send_USB_Error_Packet (ERR_COMMAND_FAILED, 0, NULL);
      }
    }
    break;
    case RSP_SET_ATTRIBUTE:
    {
      uint16_t tsttyp;
      uint32_t value = 0;
      Attribute attrTyp;
      tsttyp = ((cmd->data [1] & 0xFF) << 8);
      tsttyp |= (cmd->data [0] & 0xFF);
      memcpy (&attrTyp, cmd->data, sizeof (Attribute));
      memcpy (&attrTyp.AttrValue, cmd->data + sizeof (Attribute), attrTyp.AttrLength);
      memcpy (&value, &attrTyp.AttrValue, attrTyp.AttrLength);
      if (Write_Attribute_Value (tsttyp, value) == SUCCESS)
        Send_USB_Command_Packet (CMD_RSP_SET_ATTRIBUTE, 0, NULL); 
      else
        Send_USB_Error_Packet (ERR_COMMAND_FAILED, 0, NULL);
    }
    break;
    case RSP_TEST_GET_BUFFER_DATA:
    {
      uint16_t tstseq = 0;
      tstseq = ((cmd->data [1] & 0xFF) << 8);
      tstseq |= (cmd->data [0] & 0xFF);
      if (FlashDumpMode)
        Handle_Cmd_Get_Buffer_Data (tstseq);
      //else
        /*FIXME send an error*/
    }
    break;
    case RSP_DUMP_FLASH_DATA:
      DmpWindowCount = 0;
      TotalPckSent = 0;
      if (!FlashDumpMode)
        FlashDumpMode = TRUE;
      Handle_Cmd_Flash_Dump ();
    break;
    case RSP_FLASH_MEM_TEST:
      Send_USB_Error_Packet (ERR_COMMAND_FAILED, 0, NULL);    
    break;
    case RSP_SET_BOOTLOADER_STATE:
    {
      uint8_t st = cmd->data [0];
      Change_BootLoader_State (st);
    }
    break;
    default:
      Send_USB_Error_Packet (ERR_COMMAND_FAILED, 0, NULL);    
    break;
  }
  return SUCCESS;
}

/**
 * Handle_Cmd_Verify_Buffer_Crc
 * 
 * The function caluculates the crc of a given buffer
 * and compares it with the crc passed. If the data in
 * the buffer is determined valid through the crc check the
 * buffer data is transfered to the current load location.
 * 
 * @parma chkcrc Data structure contaning number of packets 
 *               and the crc of the current buffer.
 *
 * @return SUCCESS | FAIL
 */
result_t Handle_Cmd_Verify_Buffer_Crc (CmdCrcData* chkcrc)
{
  result_t res = SUCCESS;
  uint32_t BuffSize = (BIN_DATA_WINDOW_SIZE * IMOTE_HID_SHORT_MAXPACKETDATA);
  uint32_t flashaddr = 0;
  uint32_t endaddr = 0;
  flashaddr = CurrLoadAddr + (WindowCount * BuffSize);
  endaddr = flashaddr + BuffSize;
  
  if (Check_Buffer_Crc (0, chkcrc->NumUSBPck, chkcrc->ChunkCRC) == SUCCESS)
  {
    bool EraseFail = FALSE;
    /**
     * Now Write this chunk to the flash and start downloading
     * the next chunk.
     *
     * NOTE: We will have to find out if we have to erase the block.
     * If we are in multipes of 128k then we are good to go. Since we
     * are allowing variable block sizes, we have to check if the
     * data we are writing to can get past the current block.
     */
    if ((flashaddr % FLASH_BLOCK_SIZE) == 0)
    {
      if (Flash_Erase (flashaddr) == FAIL)
      {
        Send_USB_Error_Packet (ERR_FLASH_ERASE, 4, &flashaddr);
        EraseFail = TRUE;
        res = FAIL;
      }
    }
    else if ((endaddr % FLASH_BLOCK_SIZE) < BuffSize)
    {
      if (Flash_Erase (endaddr) == FAIL)
      {
        Send_USB_Error_Packet (ERR_FLASH_ERASE, 4, &flashaddr);
        EraseFail = TRUE;
        res = FAIL;
      }
    }
    

    if (!EraseFail)
    {
      if (Flash_Write (flashaddr, rcvBuffer, 
                       ValidBuffSize)
                       == SUCCESS)
      {
        ++ WindowCount;
      }
      else
      {
        Send_USB_Error_Packet (ERR_FLASH_WRITE, 0, NULL);
        res = FAIL;
      }
    }
    else
    {
      //Send_USB_Error_Packet (ERR_FATAL_ERROR_ABORT, 0, NULL);
      res = FAIL;
    }
  }
  else
  {
    unsigned char buff [10];
    memset (buff, 0, 10);
    memcpy (buff, &chkcrc->chunkStart, 4);
    //memcpy (buff + 4, &tstCrc, 2);	
    memcpy (buff + 4, &chkcrc->ChunkCRC, 2);	
    memcpy (buff + 8, &dbg_curr_crc, 2);
    res = FAIL;
    Send_USB_Error_Packet (TEST_CRC_FAILURE, 10, buff);
  }
  return res;
}

/**
 * Handle_Cmd_Verify_Image_Crc
 *
 * After the download is completed the bootloader verifies
 * the CRC of the image by reading the Image from the
 * flash. The current load location has to be specified
 * to the boot loader through CURRENT_LOAD_LOCATION attribute.
 * This function starts reading chunks of size DATA_WINDOW_SIZE
 * from the address passed as the first parameter from the flash and
 * calculates a cumulative crc of the chunks up to the
 * specified size (numpck number of ).
 *
 * @param StartAddr Starting address of the image.
 * @param Size The total size of the image.
 * @param rcvCRC The crc received or to be verified.
 *
 * @return SUCCESS | FAIL
 */
result_t Handle_Cmd_Verify_Image_Crc (uint32_t StartAddr, uint32_t Size, 
                                                        uint16_t rcvCrc)
{
  uint32_t ImgFlashAddr = StartAddr;
  uint32_t CSize=(uint32_t)(BIN_DATA_WINDOW_SIZE * IMOTE_HID_SHORT_MAXPACKETDATA);
  uint32_t RSize = 0;
  uint32_t CurSize = 0;
  uint16_t cumulative_crc = 0;
  while (CurSize < Size)
  {
    RSize = ((Size - CurSize) > CSize)? CSize : (Size - CurSize);
    memset (rcvBuffer, 0x0, CSize);
    if (Flash_Read (ImgFlashAddr, RSize, rcvBuffer) == FAIL)
    {
      Send_USB_Error_Packet (ERR_FLASH_READ, 0, NULL);
    }
    cumulative_crc = Crc_Buffer (rcvBuffer, RSize, cumulative_crc);
    CurSize += RSize;
    ImgFlashAddr += RSize;
  }
  dbg_curr_crc = cumulative_crc;
  if (cumulative_crc == rcvCrc)
    return SUCCESS;
  return FAIL;
}


/**
 * Handle_Cmd_Get_Buffer_Data
 *
 * This command enables the PC application to request the data from
 * the current internal buffer (rcvBuffer). This command is usally preceded by a
 * DUMP_FLASH_DATA command.
 *
 * @param sequence Sequence number of the packet requested.
 */
void Handle_Cmd_Get_Buffer_Data (uint16_t sequence)
{
  if (Send_USB_Binary_Packet (rcvBuffer + (sequence * IMOTE_HID_SHORT_MAXPACKETDATA), 
             IMOTE_HID_SHORT_MAXPACKETDATA) == SUCCESS)
  {
    ++ TotalPckSent;
    if (TotalPckSent >= NumPckExpected)
    {
      Send_USB_Command_Packet (CMD_TEST_IMG_DUMP, 0, NULL);
      FlashDumpMode = FALSE;
      DmpWindowCount = 0;
      TotalPckSent = 0;
    }
    else
    {
      if (sequence >= (BIN_DATA_WINDOW_SIZE - 1))
      {
        /**
         * If we are in flash dump mode then lets just start the next cycle
         */
        if ((FlashDumpMode) && (TotalPckSent < NumPckExpected))
        {
          ++ DmpWindowCount;
          Handle_Cmd_Flash_Dump ();
        }
      }
    }
  }
}

/**
 * Handle_Cmd_Flash_Dump
 *
 * The verification mechanism of flash programming requires a flash dump of the
 * currently programmed location. The PC application can request a flash
 * dump of either the primary or the secondary flash image. 
 * The function expects the CurrentAddress to be set to the address where
 * the chunk has to be read. The chunk size is same as the download 
 * (BIN_DATA_WINDOW_SIZE).
 * 
 */ 
void Handle_Cmd_Flash_Dump ()
{
  uint32_t CurrentAddress = CurrLoadAddr + 
          (DmpWindowCount * (BIN_DATA_WINDOW_SIZE * IMOTE_HID_SHORT_MAXPACKETDATA));
  memset (rcvBuffer, 0, (BIN_DATA_WINDOW_SIZE * IMOTE_HID_SHORT_MAXPACKETDATA));
  if (Flash_Read (CurrentAddress,
            ((BIN_DATA_WINDOW_SIZE) * IMOTE_HID_SHORT_MAXPACKETDATA),
            rcvBuffer) == FAIL)
  {
    Send_USB_Error_Packet (ERR_FLASH_READ, 0, NULL);
  }
  else
  {
    ++ TotalPckSent;
    Send_USB_Binary_Packet (rcvBuffer, IMOTE_HID_SHORT_MAXPACKETDATA);
  }
}

/**
 * Send_Command_Packet
 *
 * The abstraction function which takes a command and converts it in to
 * byte array and calls the lower level send function in USBClient.
 *
 * @param cmd Command to be send.
 * @param length Size of the struct pointed by cmd.
 *
 * @return SUCCESS | FAIL
 */
result_t Send_Command_Packet (USBCommand* cmd, int length)
{
  uint8_t data [62];
  memcpy (&data, cmd, length);
  USBMsg_Send (data, length, IMOTE_HID_TYPE_MSC_COMMAND);
  return SUCCESS;
}


/**
 * Send_USB_Command_Packet
 *
 * Send a command message to the PC.
 *
 * @param cmd Command type defined in the enum (see MessageDefines.h).
 * @param clen Length of the command data.
 * @param cdata Command data in array format.
 */
result_t Send_USB_Command_Packet (Commands cmd, uint8_t clen, void* cdata)
{
  USBCommand* ucmd;
  result_t ret = FAIL;
  int len = sizeof (USBCommand) + clen;
  uint8_t data [len];
  memset (data, 0, len);
  ucmd = (USBCommand*)data;
  ucmd->type = cmd;
  if (clen > 0)
  {
    memcpy (ucmd->data, cdata, clen);
  }
  ret = USBMsg_Send (data, len, IMOTE_HID_TYPE_MSC_COMMAND);
  
  return ret;
}


/**
 * Send_USB_Error_Packet
 *
 * Send an error message and a description about the error to the
 * PC application.
 *
 * @param err Error codes defined in the enum (see MessageDefines.h).
 * @param dlen Length of the descriptor string.
 * @param desc A description about the error.
 */
result_t Send_USB_Error_Packet (Errors err, uint8_t dlen, void* desc)
{
  result_t ret = SUCCESS;
  USBError* uerr;
  int len = sizeof (USBError) + dlen;
  uint8_t data [len];
  memset (data, 0, len);
  uerr = (USBError*)data;
  uerr->type = err;
  uerr->desclen = dlen;
  if (dlen > 0)
  {
    memcpy (uerr->description, desc, dlen);
  }
  ret = USBMsg_Send (data, len, IMOTE_HID_TYPE_MSC_ERROR);
  return ret;
}


/**
 * Send_USB_Binary_Packet
 *
 * Send Binary data to the pc application. This function is used mainly
 * to dump data from flash or the internal buffer to the pc applicaiton for
 * image verification purposes.
 *
 * The function currently follows the JTPacket format which means that
 * every packet can transmit a length of IMOTE_HID_SHORT_MAXPACKETDATA and
 * packet will contain the sequence number.
 *
 * @param data Data to be transmitted.
 * @return SUCCESS | FAIL
 */
result_t Send_USB_Binary_Packet (uint8_t* data, uint32_t length)
{
  result_t ret = SUCCESS;
  ret = USBMsg_Send (data, length, IMOTE_HID_TYPE_MSC_BINARY);
  return ret;
}

--- NEW FILE: BootLoader.c ---
/*									tab:4
 * "Copyright (c) 2000-2003 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 * Copyright (c) 2002-2003 Intel Corporation
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE     
 * file. If you do not find these files, copies can be found by writing to
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
 * 94704.  Attention:  Intel License Inquiry.
 */

/**
 * @file BootLoader.c
 * @author Junaith Ahemed Shahabdeen
 *
 * Boot loader state machine, recovery mechanism and
 * the application test mechanisms like SELF_TEST and
 * Image verify are implemented in this file.
 */

#include <BootLoader.h>
#include <USBClient.h>
#include <Leds.h>
#include <BinImageHandler.h>
#include <AttrAccess.h>
#include <stdlib.h>
#include <Flash.h>
#include <stdio.h>
#include <TOSSched.h>

extern void handle_jump ();
extern int __Binary_Mover (uint32_t, uint32_t, void*);
extern int __Binary_Erase (uint32_t, uint32_t, void*);

/* Default boot loader state is normal */
BootLoaderState CurrentState = NORMAL;
CodeLoadState CLoaderState = REQUEST_IMAGE_DETAIL;
bool REBOOT_DEVICE = FALSE;
bool MMU_ENABLED = FALSE;

static uint8_t vecbuffer [32];
static uint8_t cpybuffer [0x8000];

/*Attributes of the Golden Image used if we have to recover*/
uint32_t GImgSize = 0;
uint32_t GImgAddr = 0;
uint32_t GImgCrc = 0;

/*Attributes of the newly loaded image*/
uint32_t CurrImageSize = 0;
uint32_t CurrImageAddr = 0;
uint32_t CurrImageCrc = 0;

void Set_Image_Details (uint32_t isize, uint32_t iaddr, uint32_t icrc)
{
  CurrImageSize = isize;
  CurrImageAddr = iaddr;
  CurrImageCrc = icrc;
}

/**
 * Change_BootLoader_State_Attribute
 *
 * Change the current boot loader state attribute to the value of first parameter,
 * together with the local variable. The value of the parameter passed must be 
 * one of the values in the BootLoaderState enumerated list.
 *
 * @param state	The new state of the boot loader.
 * @return SUCCESS | FAIL
 */
uint8_t Change_BootLoader_State_Attribute (BootLoaderState state)
{
  result_t ret = FAIL;
  ret = Write_Attribute_Value (BL_ATTR_TYP_BOOTLOADER_STATE, (uint32_t)state);
  CurrentState = state;
  return SUCCESS;
}

/**
 * Change_BootLoader_State
 *
 * Change the current boot loader state to the value of first parameter.
 * The value of the parameter passed must be one of the values in
 * the BootLoaderState enumerated list.
 *
 * @param state	The new state of the boot loader.
 * @return SUCCESS | FAIL
 */
uint8_t Change_BootLoader_State (BootLoaderState state)
{
  CurrentState = state;
  return SUCCESS;
}

/**
 * Get_BootLoader_State
 *
 * Get the current boot loader state, The function returns the current
 * state of the boot loader.
 *
 * @return CurrentState of the boot loader.
 */
BootLoaderState Get_BootLoader_State ()
{
  return CurrentState;
}


/**
 * Change_Internal_CodeLoad_State
 *
 * The code load state is internally maintained by the bootloader after the
 * PC application places it in CodeLoad state. Currently there are
 * two states in which the boot loader requests the image details to be
 * loaded and requests the usb packets.
 *
 * @param cls	The new internal state of Code_Load.
 * @return SUCCESS | FAIL
 */
uint8_t Change_Internal_CodeLoad_State (CodeLoadState cls)
{
  CLoaderState = cls;
  return SUCCESS;
}

/**
 * Get_Internal_CodeLoad_State
 *
 * The funciton returns the CLoaderState variable, which is the
 * current internal state of Code_Loader.
 *
 * @return CLoaderState Current state of Code_Loader.
 */
CodeLoadState Get_Internal_CodeLoad_State ()
{
  return CLoaderState;
}

/**
 * Reboot_Device
 *
 * Set the watch dog and the OSMR3 registers and wait till
 * the board reboots.
 */
inline void Reboot_Device ()
{
  OSMR3 = OSCR0 + 0x2000;
  OWER = 1;
  while(1);
}

/**
 * Prepare_Self_Test
 *
 * If the application requests a self test for the newly
 * downloaded image, then the new image will be copied to
 * the boot location temporarily. The watch dog timer is
 * set to ensure that the app will reboot for the second
 * verification phase.
 * After the reboot the boot loader verifies the test result
 * and decides if the image has to be made golden or not.
 *
 * @return SUCCESS | ERROR
 */
result_t Prepare_Self_Test ()
{
  //uint8_t buffer [61];
  /**
   * first change the state so that in case if we crash then we 
   * can recover.
   */
  Flash_Read (0x0, 32, vecbuffer);

  /* Load the Image details so that we can move the contents to
   * boot location
   */
  if (Read_Attribute_Value(BL_ATTR_TYP_SECONDARY_IMG_LOCATION, &GImgAddr) 
                                                              == SUCCESS)
  {
    if (Read_Attribute_Value(BL_ATTR_TYP_SECONDARY_IMG_SIZE, &GImgSize)
                                                            == SUCCESS)
    {
      /**
       * First check if the image is worth performing selftest on. Calculate
       * the crc and try to match it with the crc attribute.
       */
      if (Read_Attribute_Value(BL_ATTR_TYP_SECONDARY_IMG_CRC, &GImgCrc)
                                                                == SUCCESS)
      {
        if ((GImgSize == 0) || (GImgCrc == 0))
          return FAIL;
        if (Handle_Cmd_Verify_Image_Crc (GImgAddr, GImgSize, 
                             GImgCrc) == SUCCESS)
        {
          uint32_t WDTimeout;
          if (Change_BootLoader_State_Attribute (VERIFY_SELF_TEST) == FAIL)
            return FAIL;
          if (Read_Attribute_Value(BL_ATTR_TYP_SELF_TEST_TIMEOUT, &WDTimeout)
                                                              == SUCCESS)
            WDTimeout = BL_SELF_TEST_TIMEOUT; /*Not a biggie if we fail set it default*/
          __Binary_Mover (GImgAddr, GImgSize, vecbuffer);
	  //Move_Image_To_Boot_Loc (GImgAddr, GImgSize);
          /* set the watchdog to wait for long time to allow the
           * app to finish the self test
           */
          OSMR3 = OSCR0 + WDTimeout;
          OWER = 1;
          handle_jump ();
        }
      }
    }
  }
  return FAIL;
}

/**
 * Verify_Image_And_Make_Golden
 *
 * The application can download an image and store it in the 
 * secondary location and requests the boot loader to validate (CRC)
 * the make and convert it to bootable image.
 * If the CRC Check passed then the image is made bootable and
 * copied to the primary location.
 * 
 * @return SUCCESS | FAIL
 */
result_t Verify_Image_And_Make_Golden ()
{
  /* Load the Image details so that we can move the contents to
   * boot location
   */
  if (Read_Attribute_Value(BL_ATTR_TYP_SECONDARY_IMG_LOCATION, &CurrImageAddr) 
                                                               == SUCCESS)
  {
    if (Read_Attribute_Value(BL_ATTR_TYP_SECONDARY_IMG_SIZE, &CurrImageSize)
                                                              == SUCCESS)
    {
      /*Verify the crc of the image.*/
      if (Read_Attribute_Value(BL_ATTR_TYP_SECONDARY_IMG_CRC, &CurrImageCrc)
                                                              == SUCCESS)
      {
        if ((CurrImageSize == 0) || (CurrImageCrc == 0))
          return FAIL;
        if (Handle_Cmd_Verify_Image_Crc(CurrImageAddr, CurrImageSize, CurrImageCrc)
                                                              == SUCCESS)
        {
          //__Binary_Mover (GImgAddr, GImgSize, vecbuffer);
          if(Change_BootLoader_State_Attribute (CPY_TO_BOOT) == SUCCESS)
	  {
            BootLoader_State_Machine ();
            return SUCCESS;
          }
        }
      }
    }
  }
  return FAIL;
}


/**
 * Self_Test_Failed
 *
 * If the self test fails then the boot loader has to recover the
 * previous golden image and replace the current boot image (self test image).
 *
 * @return SUCCESS | FAIL 
 */
result_t Self_Test_Failed ()
{
  /**
   * first change the state so that in case if we crash then we 
   * can recover.
   */
  Flash_Read (0x0, 32, vecbuffer);

  /* Load the Image details so that we can move the contents to
   * boot location
   */
  if (Read_Attribute_Value(BL_ATTR_TYP_PRIMARY_IMG_LOCATION, &GImgAddr) 
                                                             == SUCCESS)
  {
    if (Read_Attribute_Value(BL_ATTR_TYP_PRIMARY_IMG_SIZE, &GImgSize) 
                                                             == SUCCESS)
    {
      if (Read_Attribute_Value(BL_ATTR_TYP_PRIMARY_IMG_CRC, &GImgCrc) 
                                                             == SUCCESS)
      {
        /* Just in case, make sure that CRC matches before loading it*/
        if (Handle_Cmd_Verify_Image_Crc(GImgAddr, GImgSize, GImgCrc)
                                                             == SUCCESS)
        {
          __Binary_Mover (GImgAddr, GImgSize, vecbuffer);
          //Move_Image_To_Boot_Loc (GImgAddr, GImgSize);
          /*Reset the Crc boot address.*/
          //Write_Attribute_Value(BL_ATTR_TYP_BOOT_IMG_CRC, GImgCrc);
          //handle_jump ();
          return SUCCESS;
	}
      }
    }
  }
  return FAIL;
}

/**
 * Self_Test_Succeeded
 * 
 * Self test succeeded so make the current image as golden image
 * and set the right attributes.
 *
 * @return SUCCESS | ERROR
 */
result_t Self_Test_Succeeded ()
{
  result_t ret; 
  /* Load the Image details and prepare to make the secondary 
   * image as golden
   */
  /* FIXME the assumption is that non of these values could be changed by the
   * app. Not sure if its good enough.
   */
  ret = Read_Attribute_Value(BL_ATTR_TYP_SECONDARY_IMG_LOCATION, &CurrImageAddr);
  ret = Read_Attribute_Value(BL_ATTR_TYP_SECONDARY_IMG_SIZE, &CurrImageSize);
  ret = Read_Attribute_Value(BL_ATTR_TYP_SECONDARY_IMG_CRC, &CurrImageCrc);
  ret = Read_Attribute_Value(BL_ATTR_TYP_PRIMARY_IMG_LOCATION, &GImgAddr);
  ret = Read_Attribute_Value(BL_ATTR_TYP_PRIMARY_IMG_CRC, &GImgCrc);
  ret = Read_Attribute_Value(BL_ATTR_TYP_PRIMARY_IMG_SIZE, &GImgSize);

  if (ret == SUCCESS)
  {
    if(Change_BootLoader_State_Attribute (SET_LOADED_TO_GOLDEN) == SUCCESS)
    {
      BootLoader_State_Machine ();
      return SUCCESS;
    }
  }
  return FAIL;
}

/**
 * Validate_Self_Test_Image
 *
 * Validate the CRC of the self test image and determine if the
 * self test passed or failed.
 *
 * @return SUCCESS | FAIL
 */
result_t Validate_Self_Test_Image ()
{
  uint32_t AttrLoc = 0;
  uint32_t AttrSize = 0;
  uint32_t DefAttrCrc = 0;
  
  if(Change_BootLoader_State_Attribute (NORMAL) == SUCCESS)
  {
    if (Read_Attribute_Value(BL_ATTR_TYP_DEF_SELF_TEST_IMG_CRC, &DefAttrCrc)
                                                               == SUCCESS)
    {
      if (DefAttrCrc == 0)
      {
        return FAIL;
      }
    }

    if (Read_Attribute_Value(ATTR_SELF_TEST_IMG_LOC, &AttrLoc) 
                                                      == SUCCESS)
    {
      if (Read_Attribute_Value(ATTR_SELF_TEST_IMG_SIZE, &AttrSize) 
                                                        == SUCCESS)
      {
        if (Handle_Cmd_Verify_Image_Crc(AttrLoc, AttrSize, DefAttrCrc)
                                                            == SUCCESS)
        {
          return SUCCESS;
        }
      }
    }
  }
  else
  {
    ; /* Fatal, We cant revert back to the old image*/
  }
  return FAIL;
}


/**
 * Map_Loaded_To_Golden
 *
 * This function swaps the attribute values of the current golden image
 * with the secondary image attribute. The assumption is that the 
 * secondary image is already validated and copied to the boot location,
 * as a final step this function is called to mark the secondary as
 * golden so that the successive reboots can boot the newly loaded image.
 *
 * @return SUCCESS | FAIL
 */
result_t Map_Loaded_To_Golden ()
{
  result_t ret = FAIL;
  AttrSet attset;
  
  attset.NumAttributes = 9;
  attset.AttrId [0] = BL_ATTR_TYP_BOOTLOADER_STATE;
  attset.AttrVal [0] = NORMAL;
  attset.AttrId [1] = BL_ATTR_TYP_PRIMARY_IMG_LOCATION;
  attset.AttrVal [1] = CurrImageAddr;
  attset.AttrId [2] = BL_ATTR_TYP_PRIMARY_IMG_CRC;
  attset.AttrVal [2] = CurrImageCrc;
  attset.AttrId [3] = BL_ATTR_TYP_PRIMARY_IMG_SIZE;
  attset.AttrVal [3] = CurrImageSize;
  attset.AttrId [4] = BL_ATTR_TYP_SECONDARY_IMG_LOCATION;
  attset.AttrVal [4] = GImgAddr;
  attset.AttrId [5] = BL_ATTR_TYP_SECONDARY_IMG_CRC;
  attset.AttrVal [5] = GImgCrc;
  attset.AttrId [6] = BL_ATTR_TYP_SECONDARY_IMG_SIZE;
  attset.AttrVal [6] = GImgSize;
  attset.AttrId [7] = BL_ATTR_TYP_BOOT_IMG_CRC;
  attset.AttrVal [7] = CurrImageCrc;
  attset.AttrId [8] = BL_ATTR_TYP_BOOT_IMG_SIZE;
  attset.AttrVal [8] = CurrImageSize;

  ret = Write_Attribute_Set (BL_ATTR_TYP_BOOTLOADER, &attset);
  return ret;
}


result_t ReMap_Golden ()
{
  result_t ret = FAIL;

  ret = Write_Attribute_Value(BL_ATTR_TYP_PRIMARY_IMG_LOCATION, GImgAddr);
  ret = Write_Attribute_Value(BL_ATTR_TYP_PRIMARY_IMG_CRC, GImgCrc);
  ret = Write_Attribute_Value(BL_ATTR_TYP_PRIMARY_IMG_SIZE, GImgSize);
  //ret = Write_Attribute_Value(BL_ATTR_TYP_PRIMARY_IMG_VALIDITY, &PrimaryVal);
  ret = Write_Attribute_Value(BL_ATTR_TYP_SECONDARY_IMG_LOCATION, CurrImageAddr);
  ret = Write_Attribute_Value(BL_ATTR_TYP_SECONDARY_IMG_CRC, CurrImageCrc);
  ret = Write_Attribute_Value(BL_ATTR_TYP_SECONDARY_IMG_SIZE, CurrImageSize);
  //ret = Write_Attribute_Value(BL_ATTR_TYP_SECONDARY_IMG_VALIDITY, &PrimaryVal);

  return ret;
}


/*result_t Map_Boot_To_Golden ()
{
  return SUCCESS;
}*/


/**
 * BootLoader_Recovery_State_Machine
 *
 * State machine that is invoked while we are recovering from
 * a crash. The actions that has to be taken after a crash differs
 * from the normal one, just to prevent an infinite loop.
 * Also there are only few states in which the boot loader
 * crash could crash.
 * NOTE:
 * if the function doesnt recognize the crash state or if there is a 
 * possibility of an infinite loop then stall.
 */
void BootLoader_Recovery_State_Machine ()
{
  result_t ret = FAIL;
  switch (CurrentState)
  {
    case CPY_TO_BOOT:
      ret = Read_Attribute_Value(BL_ATTR_TYP_PRIMARY_IMG_LOCATION, &GImgAddr);
      ret = Read_Attribute_Value(BL_ATTR_TYP_PRIMARY_IMG_CRC, &GImgCrc);
      ret = Read_Attribute_Value(BL_ATTR_TYP_PRIMARY_IMG_SIZE, &GImgSize);
      ret = Read_Attribute_Value(BL_ATTR_TYP_SECONDARY_IMG_LOCATION, &CurrImageAddr);
      ret = Read_Attribute_Value(BL_ATTR_TYP_SECONDARY_IMG_CRC, &CurrImageCrc);
      ret = Read_Attribute_Value(BL_ATTR_TYP_SECONDARY_IMG_SIZE, &CurrImageSize);
      if (ret == SUCCESS)
      {
        if (Move_Image_To_Boot_Loc (CurrImageAddr, CurrImageSize) == SUCCESS)
        {
          if (Map_Loaded_To_Golden () == FAIL)
          {
            /*Prepare for the second pass*/
            if (Change_BootLoader_State_Attribute (SET_LOADED_TO_GOLDEN) == FAIL)
            {
              TOGGLE_LED (RED);
              while (1); /* Thats a stall case, dont go back*/
            }
          }
        }
      }

      if (Change_BootLoader_State_Attribute (NORMAL) == FAIL)
      {
        TOGGLE_LED (RED);
        while (1); /* Thats a stall case, dont go back*/
      }
      Reboot_Device ();
    break;
    case SET_LOADED_TO_GOLDEN:
    {
      ret = Read_Attribute_Value(BL_ATTR_TYP_PRIMARY_IMG_LOCATION, &GImgAddr);
      ret = Read_Attribute_Value(BL_ATTR_TYP_PRIMARY_IMG_CRC, &GImgCrc);
      ret = Read_Attribute_Value(BL_ATTR_TYP_PRIMARY_IMG_SIZE, &GImgSize);
      if (ret == SUCCESS)
      {
        ret = Read_Attribute_Value(BL_ATTR_TYP_SECONDARY_IMG_LOCATION, &CurrImageAddr);
        ret = Read_Attribute_Value(BL_ATTR_TYP_SECONDARY_IMG_CRC, &CurrImageCrc);
        ret = Read_Attribute_Value(BL_ATTR_TYP_SECONDARY_IMG_SIZE, &CurrImageSize);

        if (ret == SUCCESS)
        {
          Map_Loaded_To_Golden ();
        }
        else
        {
          /* We know that we have a good PIMG. so lets replace it and boot the old app
	   */
          Move_Image_To_Boot_Loc (GImgAddr, GImgSize);
          if ((CurrImageAddr != BL_PRIMARY_IMAGE_LOCATION) && 
                       (CurrImageAddr != BL_SECONDARY_IMAGE_LOCATION))
          {
            /* Find where the current primary location is to determine
             * the secondary location.
             */
            if ((GImgAddr - BL_PRIMARY_IMAGE_LOCATION) > 0)
              ret = Write_Attribute_Value(BL_ATTR_TYP_SECONDARY_IMG_LOCATION, 
                                              BL_PRIMARY_IMAGE_LOCATION);
            else
              ret = Write_Attribute_Value(BL_ATTR_TYP_SECONDARY_IMG_LOCATION, 
                                              BL_SECONDARY_IMAGE_LOCATION);

            ret = Write_Attribute_Value(BL_ATTR_TYP_SECONDARY_IMG_LOCATION, 0);
            ret = Write_Attribute_Value(BL_ATTR_TYP_SECONDARY_IMG_LOCATION, 0);
          }
        }
      }
      else
      {
        /* We might have busted the whole table, just replace the default*/
        Recover_Default_Table (BL_ATTR_TYP_BOOTLOADER);
      }
      if (Change_BootLoader_State_Attribute (NORMAL) == FAIL)
      {
        TOGGLE_LED (RED);
        while (1); /* Thats a stall case, dont go back, Will lead to a loop*/
      }
      Reboot_Device ();
    }
    break;
    case SET_BOOT_TO_GOLDEN:
      if (Change_BootLoader_State_Attribute (NORMAL) == FAIL)
      {
        TOGGLE_LED (RED);
        while (1); /* Thats a stall case, dont go back*/
      }
      Reboot_Device ();
    break;
    case VERIFY_SELF_TEST:
      if (Validate_Self_Test_Image () == SUCCESS)
      {
        if (Self_Test_Succeeded () == FAIL)
          ; /* Serious, we need to some how save the vector table*/ 
      }
      else
      {
        Self_Test_Failed ();
        Reboot_Device ();      
      }
    break;
    default:
      Recover_Default_Table (BL_ATTR_TYP_BOOTLOADER);
      Reboot_Device ();
    break;
  }
}

/**
 * Move_Image_To_Boot_Loc
 *
 * Move the image at imgAddr to the boot location. This
 * function holds a copy of the vector table. If incase there is
 * a failure then it will try to replace the vector table to
 * save the boot loader.
 *
 * @param imgAddr Starting address of the image to be moved.
 * @param imgSiz  Size of the image at imgAddr.
 *
 * @return SUCCESS | FAIL
 */
result_t Move_Image_To_Boot_Loc (uint32_t imgAddr, uint32_t imgSiz)
{
  result_t ret;
  uint32_t ImgFlashAddr = imgAddr + 32; /*Drop the vec table*/
  uint32_t CSize= 0x8000;
  uint32_t RSize = 0;
  uint32_t CurSize = 0x20;
  uint32_t BootAddr = 0x0;
  uint32_t AddVec = 0x0;
  
  Flash_Read (0x0, 32, vecbuffer); /* Keep this for recovery purpose*/
  if (Flash_Param_Partition_Erase (BootAddr) == SUCCESS)
  {
    if (Flash_Write (BootAddr, vecbuffer, 0x20) == FAIL)
    {
      memcpy (cpybuffer, vecbuffer, 0x20);
      AddVec = 0x20;
    }
    else
      BootAddr = 0x20;
  }
  
  ret = __Binary_Erase (CurrImageAddr, CurrImageSize, vecbuffer);

  if (Flash_Read (ImgFlashAddr, (CSize - CurSize), (cpybuffer + AddVec)) == SUCCESS)
  {
    if (Flash_Write (BootAddr, cpybuffer, (0x7FE0 + AddVec)) == SUCCESS)
    {
      CurSize += (0x8000 - 0x20);
      ImgFlashAddr += (0x8000 - 0x20);
      BootAddr += (0x8000 - 0x20);
    }
    else
    {
      if (Flash_Write (BootAddr, vecbuffer, 0x20) == FAIL)
      {
        TOGGLE_LED (RED);
        while (1);
      }
      else
        return FAIL;
    }
  }
      
  while (CurSize < imgSiz)
  {
    RSize = ((imgSiz - CurSize) > CSize)? CSize : (imgSiz - CurSize);
    if (Flash_Read (ImgFlashAddr, RSize, cpybuffer) == SUCCESS)
    {
      if (Flash_Write (BootAddr, cpybuffer, 0x8000) == SUCCESS)
      {
        CurSize += RSize;
        ImgFlashAddr += RSize;
        BootAddr += RSize;
      }
      else
        return FAIL;
    }
  }
  return SUCCESS;
}



/**
 * BootLoader_State_Machine
 *
 * The state machine for the boot loader which performs certain tasks
 * based on the current state of the boot loader. The current state must
 * be changed appropriately before calling this fuction.
 *
 */
void BootLoader_State_Machine ()
{
  switch (CurrentState)
  {
    case NORMAL:
      /*FIXME Move the code from main and post the state machine*/
    break;
    case CPY_TO_BOOT:
    {
      uint8_t buffer [61];
      Read_Attribute_Value(BL_ATTR_TYP_PRIMARY_IMG_LOCATION, &GImgAddr);
      Read_Attribute_Value(BL_ATTR_TYP_PRIMARY_IMG_CRC, &GImgCrc);
      Read_Attribute_Value(BL_ATTR_TYP_PRIMARY_IMG_SIZE, &GImgSize);
      __nesc_atomic_t atomic = __nesc_atomic_start();
      if (Move_Image_To_Boot_Loc (CurrImageAddr, CurrImageSize) == FAIL)
        Reboot_Device (); 
      __nesc_atomic_end (atomic);

      TOGGLE_LED (YELLOW);

      if(Change_BootLoader_State_Attribute (SET_LOADED_TO_GOLDEN) == SUCCESS)
      {
        sprintf (buffer, "Successfully copied image to boot location.\n");
        Send_USB_Command_Packet (CMD_BOOTLOADER_MSG, 61, buffer);
        TOS_post (&BootLoader_State_Machine);
      }
      else
      {
        /**
         * If we cant switch state then its hard to determine the problem
         * So let reboot and try to recover.
         */
        sprintf (buffer, "Could not switch to SET_LOADED_TO_GOLDEN. Rebooting\n");
        Send_USB_Error_Packet (ERR_FATAL_ERROR_ABORT, 60, buffer);	   
        Reboot_Device ();
      }
    }
    break;
    case SET_LOADED_TO_GOLDEN:
    {
      uint8_t buffer [61];
      result_t ret = SUCCESS;
      /*It may not be required, but still we dont want an interrupt to stop us*/
      TOGGLE_LED (GREEN);
      __nesc_atomic_t atomic = __nesc_atomic_start();
        ret = Map_Loaded_To_Golden ();
      __nesc_atomic_end (atomic);
      TOGGLE_LED (GREEN);
      if (ret == SUCCESS)
      {
        sprintf (buffer, "Mapped Boot Image to golden. Booting New Image.\n");
        Send_USB_Command_Packet (CMD_CREATED_GOLDEN_IMG, 61, buffer);
        Reboot_Device ();
      }
      else
      {
        /* Very Bad, We dont know exactly where we failed. I Guess the
         * best way is reset the whole primary to secondary switch and
         * reboot.
         */
        sprintf (buffer, "Mark loaded to golden failed. Trying to recover\n");
        Send_USB_Error_Packet (ERR_FATAL_ERROR_ABORT, 60, buffer);
        Reboot_Device ();
      }
    }
    break;
    case SET_BOOT_TO_GOLDEN:
    {
      Change_BootLoader_State_Attribute (NORMAL);
      Reboot_Device ();
    }
    break;
    case BOOT_IMAGE:
    break;
    case CODE_LOAD:
      switch (CLoaderState)
      {
        case REQUEST_IMAGE_DETAIL:
        {
          USBCommand cmd;
          if (!MMU_ENABLED)
          {
            MMU_ENABLED = TRUE;
      	    Enable_MMU ();
          }
          cmd.type = CMD_GET_IMAGE_DETAILS;
          Send_Command_Packet (&cmd, sizeof (USBCommand));
        }
        break;
        case REQUEST_USB_PACKETS:
#ifdef MMU_ENABLE
          Request_Next_Binary_Chunk ();
#else
          Request_Next_Binary_Packet ();
#endif
          break;
        case VERIFY_CURRENT_BUFFER:
          break;
        case VERIFY_CURRENT_IMAGE:
          Send_USB_Command_Packet (CMD_IMG_UPLOAD_COMPLETE, 0, NULL);
          break;
        default:
          break;
      }
    break;
    case VERIFY_IMAGE:
    break;
    case VERIFY_SELF_TEST:
      /*Implemented in Recovery State Machine*/
    break;
    default:
      /* This is fatal, It is very essential to investigate why
       * this might have happened but at the same time we dont
       * want to panic. The best is to go back and try normal
       * operation.
       */
      CurrentState = NORMAL;
    break;
  }
}

--- NEW FILE: Crc.c ---
/*									tab:4
 * "Copyright (c) 2000-2003 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 * Copyright (c) 2002-2003 Intel Corporation
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE     
 * file. If you do not find these files, copies can be found by writing to
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
 * 94704.  Attention:  Intel License Inquiry.
 */

/**
 * @file Crc.c
 * @author Junaith Ahemed Shahabdeen
 *
 * Module which provides various CRC calculation functions, based
 * on the requirements. The CRC is calculated based on a static
 * table, which reduces the calculation cost.
 * 
 * CAUTION:
 * 	This file is included in the PC application for compatibility
 * 	with the bootloader. <B>NEVER EVER CHANGE THIS FILE FOR ANY REASON
 * 	with out considering the cases in either sides.</B>
 * 	It could easily lead to an incompatible code, please use caution.
 */

#include <Crc.h>
/**
 * How to generate this table ?
 *     It is basically calculating CRC of numbers from 0-255. The code used
 *   was derived from the TinyOS crc calculation in "crc.h".
 *
 *   for (i = 0; i < 256; ++i) {
 *     int crc = 0 ^ (i << 8);
 *     for (int k = 0; k < 8; ++k) {
 *       if ((crc & 0x8000) != 0)
 *         crc = (crc<<1) ^ 0x1021;
 *       else
 *         crc = crc << 1;
 *     }
 *     Crc_Table[i] = (uint16_t)(crc & 0xFFFF);
 *   }
 *   
 */
static const uint16_t Crc_Table [256] = {0x0000, 0x1021, 0x2042, 
                  0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 
                  0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 
                  0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 
                  0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 
                  0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 
                  0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 
                  0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 
                  0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 0x6886, 
                  0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 
                  0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 
                  0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 
                  0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4, 
                  0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 
                  0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 
                  0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 
                  0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 
                  0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 
                  0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83b9, 0x9398, 0xa3fb, 
                  0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 
                  0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 
                  0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 
                  0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 
                  0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 
                  0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 
                  0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 
                  0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 
                  0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 
                  0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 
                  0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 
                  0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 0xef1f, 0xff3e, 0xcf5d, 
                  0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 
                  0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 };

/**
 * Crc_Buffer
 *
 * Calculate 16-bit CRC of the buffer pointed to by buff and return the value.
 * For cumulative CRC Calculation of various buffers the old crc could be sent
 * as the last parameter.
 *
 * @param buff A pointer to the buffer for which the CRC is calculated.
 * @param len  Length of the buffer.
 * @param oldCRC Append the current calculation to a previous buffer.
 *
 * @return crc CRC of the buffer appended to the old Buffer.
 */
uint16_t Crc_Buffer (uint8_t* buff, uint32_t len, uint16_t oldCRC) 
{
  uint16_t crc = oldCRC;
  uint16_t table;
  int i = 0;
  
  for (i=0;i<len;++i)
  {
    table = ((crc >> 8) ^ buff[i]) & 0xFF;
    crc = (crc << 8) ^ Crc_Table [table];
  }

  return(crc & 0xFFFF);
}

--- NEW FILE: FlashAccess.c ---
/*									tab:4
 * "Copyright (c) 2000-2003 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 * Copyright (c) 2002-2003 Intel Corporation
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE     
 * file. If you do not find these files, copies can be found by writing to
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
 * 94704.  Attention:  Intel License Inquiry.
 */

/**
 * @file FlashAccess.h
 * @Author Josh Herbach
 *
 * Ported by: Junaith Ahemed Shahabdeen
 *
 * Higher level functions for Flash Access. The file provides a C 
 * abstraction for the assembly code in the flash.s file.
 * <I>The implementation is ported from the flash write module of
 * tinyos repository.</I>
 */
#include <pxa27xhardware.h>
#include <HPLInit.h>
#include <FlashAccess.h>
#include <string.h>
#include <Leds.h>

uint8_t FlashPartitionState[FLASH_PARTITION_COUNT];
uint8_t init = 0, programBufferSupported = 2, currBlock = 0;

/**
 * FlashAccess_Init
 *
 * Intialize the internal states of the blocks and the partitions.
 * The fuction also defines the global variables for the
 * inline assembly codes of certain functions.
 *
 * @return SUCCESS | FAIL
 */
result_t FlashAccess_Init() 
{
  int i = 0;
  if(init != 0)
    return SUCCESS;
  init = 1;
  for(i = 0; i < FLASH_PARTITION_COUNT; i++)
    FlashPartitionState[i] = FLASH_STATE_READ_INACTIVE;
    
  asm volatile(
       ".equ FLASH_READARRAY,(0x00FF);           \
        .equ FLASH_CFIQUERY,(0x0098);            \
        .equ FLASH_READSTATUS,(0x0070);	         \
        .equ FLASH_CLEARSTATUS,(0x0050);         \
        .equ FLASH_PROGRAMWORD,(0x0040);         \
        .equ FLASH_PROGRAMBUFFER,(0x00E8);       \
        .equ FLASH_ERASEBLOCK,(0x0020);          \
        .equ FLASH_DLOCKBLOCK,(0x0060);          \
        .equ FLASH_PROGRAMBUFFERCONF,(0x00D0);	 \
        .equ FLASH_LOCKCONF,(0x0001);	         \
        .equ FLASH_UNLOCKCONF,(0x00D0);          \
        .equ FLASH_ERASECONF,(0x00D0);	         \
        .equ FLASH_OP_NOT_SUPPORTED,(0x10);");
  //flash_op_not_supported needs to be LSL 1 to be the correct value of 0x100
  return SUCCESS;
}

/**
 * Write_Helper
 *
 * This function is actually a continuation of the Flash_Write. It
 * picks up the data gathered by the Flash_Write function like if
 * a buffered write is possible in a given address location and
 * compeltes the flash write request.
 *
 * @parma addr Flash Address in which the data has to be written.
 * @param data The Data that has to be written to the flash.
 * @param numBytes Length of the data.
 * 
 * @return status The status register value.
 */
uint16_t Write_Helper(uint32_t addr, uint8_t* data, uint32_t numBytes,
		uint8_t prebyte, uint8_t postbyte)
{
  uint32_t i = 0, j = 0, k = 0;
  uint16_t status;
  uint16_t buffer[FLASH_PROGRAM_BUFFER_SIZE];
    
  if(numBytes == 0)
    return FAIL;
    
  if(addr % 2 == 1)
  {
    status = __Flash_Program_Word(addr - 1, prebyte | (data[i] << 8));
    i++;
    if(status != 0x80)
      return FAIL;
  }
    
  if(addr % 2 == numBytes % 2)
  {
    if(programBufferSupported == 1)
    {
      for(; i < numBytes; i = k)
      {
        for(j = 0, k = i; k < numBytes && j < FLASH_PROGRAM_BUFFER_SIZE; j++, k+=2)
          buffer[j] = data[k] | (data[k + 1] << 8);
        status = __Flash_Program_Buffer(addr + i, buffer, j - 1);
        if(status != 0x80)
          return FAIL;
      }
    }
    else
    {
      for(; i < numBytes; i+=2)
      {
        status = __Flash_Program_Word(addr + i, (data[i + 1] << 8) | data[i]);
        if(status != 0x80)
          return FAIL;
      }
    }
  }
  else
  {
    if(programBufferSupported == 1)
    {
      for(; i < numBytes - 1; i = k)
      {
        for(j = 0, k = i; k < numBytes - 1 && j < FLASH_PROGRAM_BUFFER_SIZE; 
                         j++, k+=2)
          buffer[j] = data[k] | (data[k + 1] << 8);
        status = __Flash_Program_Buffer(addr + i, buffer, j - 1);
        if(status != 0x80)
          return FAIL;
      }
    }
    else
    {
      for(; i < numBytes - 1; i+=2)
      {
        status = __Flash_Program_Word(addr + i, (data[i + 1] << 8) | data[i]);
        if(status != 0x80)
          return FAIL;
      }
    }
    status = __Flash_Program_Word(addr + i, data[i] | (postbyte << 8));
    if(status != 0x80)
      return FAIL;
  }
  return SUCCESS;
}


/**
 * Write_Exit_Helper
 * 
 * The funciton completes Flash_Write by changing all the internal
 * states of the affected blocks by Flash_Write to READ_INACTIVE.
 * This state change is puerly driver specific and not a HW
 * requirement.
 *
 * @parma addr Flash Address in which the data has to be written.
 * @param numBytes Length of the data.
 * 
 */
void Write_Exit_Helper(uint32_t addr, uint32_t numBytes)
{
  uint32_t i = 0;
  for(i = addr / FLASH_PARTITION_SIZE; 
            i < (numBytes + addr) / FLASH_PARTITION_SIZE; i++)
    FlashPartitionState[i] = FLASH_STATE_READ_INACTIVE;
}

/**
 * Flash_Write
 * 
 * The function provides a wrapper for the actual write word or
 * write buffer functions in flash.s. At the higher level the
 * function determines if a buffer write is possible in the 
 * given address, and falls back to word writes. The control
 * is passed to the write helper function after the above
 * test for placing the rest of the data in flash.
 *
 * @param addr Starting address to which the buffer has to be written.
 * @param data Pointer to the buffer that has to be written to the flash.
 * @param numBytes Length of the buffer.
 *
 * @return SUCCESS | FAIL
 */
result_t Flash_Write(uint32_t addr, uint8_t* data, uint32_t numBytes)
{
  uint32_t i;
  uint16_t status;
  uint8_t blocklen;
  uint32_t blockAddr = (addr / FLASH_BLOCK_SIZE) * FLASH_BLOCK_SIZE;

  if (addr + numBytes > 0x02000000) //not in the flash memory space
    return FAIL;

  for (i = 0; i < FLASH_PARTITION_COUNT; i++)
    if (i != addr / FLASH_PARTITION_SIZE && 
               FlashPartitionState[i] != FLASH_STATE_READ_INACTIVE && 
               FlashPartitionState[i] != FLASH_STATE_READ_ACTIVE)
      return FAIL;

  for(i = addr / FLASH_PARTITION_SIZE;
       	    i < (numBytes + addr) / FLASH_PARTITION_SIZE; i++)
    if(FlashPartitionState[i] != FLASH_STATE_READ_INACTIVE)
      return FAIL;

  for(i = addr / FLASH_PARTITION_SIZE; 
            i < (numBytes + addr) / FLASH_PARTITION_SIZE; i++)
    FlashPartitionState[i] = FLASH_STATE_PROGRAM;

  {
  __nesc_atomic_t atomic = __nesc_atomic_start();
    for(blocklen = 0, i = blockAddr; i < addr + numBytes; 
                              i += FLASH_BLOCK_SIZE, blocklen++)
      Flash_Unlock(i);

    if(programBufferSupported == 2)
    {
      uint16_t testBuf[1];
      if(addr % 2 == 0)
      {
        testBuf[0] = data[0] | ((*((uint8_t *)(addr + 1))) << 8);
        status = __Flash_Program_Buffer(addr, testBuf, 1 - 1);
      }
      else
      {
        testBuf[0] = *((uint8_t *)(addr - 1)) | (data[0] << 8);
        status = __Flash_Program_Buffer(addr - 1, testBuf, 1 - 1);
      }      
      if(status == FLASH_NOT_SUPPORTED)
        programBufferSupported = 0;
      else 
        programBufferSupported = 1;
    }
  __nesc_atomic_end (atomic);
  }

  if(blocklen == 1)
  {
    /*atomic*/ status = Write_Helper(addr,data,numBytes,0xFF,0xFF);
    if(status == FAIL)
    {
      Write_Exit_Helper(addr, numBytes);
      return FAIL;
    }
  }
  else
  {
    uint32_t bytesLeft = numBytes;
    /*atomic*/ status = Write_Helper(addr,data, 
                    blockAddr + FLASH_BLOCK_SIZE - addr,0xFF,0xFF);
    if(status == FAIL)
    {
      Write_Exit_Helper (addr, numBytes);
      return FAIL;
    }
    bytesLeft = numBytes - (FLASH_BLOCK_SIZE - (addr - blockAddr));
    for(i = 1; i < blocklen - 1; i++)
    {
      /*atomic*/ status = Write_Helper(blockAddr + i * FLASH_BLOCK_SIZE, 
                      (uint8_t *)(data + numBytes - bytesLeft), 
                      FLASH_BLOCK_SIZE,0xFF,0xFF);
      bytesLeft -= FLASH_BLOCK_SIZE;
      if(status == FAIL)
      {
        Write_Exit_Helper(addr, numBytes);
        return FAIL;
      }
    }
    /*atomic*/ status = Write_Helper(blockAddr + i * FLASH_BLOCK_SIZE, data + 
                             (numBytes - bytesLeft), bytesLeft, 0xFF,0xFF);
    if(status == FAIL)
    {
      Write_Exit_Helper(addr, numBytes);
      return FAIL;
    }
  }
    
  Write_Exit_Helper(addr, numBytes);
  return SUCCESS;
}

/**
 * Flash_Param_Partition_Erase
 *
 * The top most partition of the flash is configured as
 * parameter partition.
 *
 * @param addr Starting address of a block that has to be erased.
 * @return SUCCESS | FAIL
 */
result_t Flash_Param_Partition_Erase (uint32_t addr)
{
  uint16_t status;
  if(addr > 0x02000000) //not in the flash memory space
    return FAIL;
  //addr = (addr / FLASH_BLOCK_SIZE) * FLASH_BLOCK_SIZE;

  {
  __nesc_atomic_t atomic = __nesc_atomic_start();	
    Flash_Unlock(addr);
    status = __Flash_Erase(addr);
  __nesc_atomic_end (atomic);
  }
  if(status != 0x80)
    return FAIL;

  return SUCCESS;
}

/**
 * Flash_Erase
 *
 * Erase the entire block in which the first parameter is located.
 * 
 * @param addr Starting Address of a flash block.
 * @return SUCCESS | FAIL
 */
result_t Flash_Erase (uint32_t addr)
{
  uint16_t status, i;
  uint32_t j;
  if(addr > 0x02000000) //not in the flash memory space
    return FAIL;

  addr = (addr / FLASH_BLOCK_SIZE) * FLASH_BLOCK_SIZE;

  for(i = 0; i < FLASH_PARTITION_COUNT; i++)
    if(i != addr / FLASH_PARTITION_SIZE && 
             FlashPartitionState[i] != FLASH_STATE_READ_INACTIVE && 
             FlashPartitionState[i] != FLASH_STATE_READ_ACTIVE)
      return FAIL;
    
  if(FlashPartitionState[addr / FLASH_PARTITION_SIZE] != 
                                     FLASH_STATE_READ_INACTIVE)
    return FAIL;
    
  FlashPartitionState[addr / FLASH_PARTITION_SIZE] = FLASH_STATE_ERASE;
    
  for(j = 0; j < FLASH_BLOCK_SIZE; j++)
  {
    uint32_t tempCheck = *(uint32_t *)(addr + j);
    if(tempCheck != 0xFFFFFFFF)
      break;
    if(j == FLASH_BLOCK_SIZE - 1)
    {
      FlashPartitionState[addr / FLASH_PARTITION_SIZE] = FLASH_STATE_READ_INACTIVE;
      return SUCCESS;
    }
  }

  {
  __nesc_atomic_t atomic = __nesc_atomic_start();	
    Flash_Unlock(addr);
    //      status = eraseFlash(addr);
    status = __Flash_Erase(addr);
  __nesc_atomic_end (atomic);
  }
  FlashPartitionState[addr / FLASH_PARTITION_SIZE] = FLASH_STATE_READ_INACTIVE;
  if(status != 0x80)
    return FAIL;

  return SUCCESS;
}

/**
 * Flash_Unlock
 *
 * The function performs all the steps required to
 * unlock a flash block. The commands and steps are defined
 * in the memory subsystem data sheet for the processor.
 * The Block address has to be passed as a parameter to the
 * function.
 * 
 * @param addr Address of the block that has to be unlocked.
 *
 * @return status The status register value.
 */
uint16_t Flash_Unlock(uint32_t addr)
{
  addr = (addr / FLASH_BLOCK_SIZE) * FLASH_BLOCK_SIZE;

  asm volatile(
       "ldr r1,=FLASH_DLOCKBLOCK;     \
        ldr r2,=FLASH_READARRAY;      \
        ldr r3,=FLASH_UNLOCKCONF;     \
        ldr r4,=FLASH_CLEARSTATUS;    \
        b _goUnlockCacheLine;	      \
       .align 5;		      \
        _goUnlockCacheLine:	      \
        strh r4,[r3];		      \
        strh r1,[%0];		      \
        strh r3,[%0];		      \
        strh r2,[%0];		      \
        ldrh r2,[%0];		      \
        nop;			      \
        nop;			      \
        nop;"
        :/*no output info*/
        :"r"(addr)
        : "r1", "r2", "r3", "r4", "memory");
        return SUCCESS;
}

/**
 * Program_Buffer
 *
 * The function performs all the steps required to
 * write a buffer to flash. The commands and steps are defined
 * in the memory subsystem data sheet for the processor.
 *
 * <B>
 * NOTE;
 *   The address has to be aligned in 32 byte boundary for the
 *   buffered write to work.
 * </B>
 * 
 * @parma addr Flash Address in which the word has to be written.
 * @param data The Data that has to be written to the flash.
 * @param datalen Length of the data.
 *
 * @return status The status register value.
 */
uint16_t Program_Buffer(uint32_t addr, uint16_t data[], 
		uint8_t datalen)
{
  uint16_t status;

  datalen -= 1;
  asm volatile("mov r1, %1;                 \
                mov r2, %2;                 \
                 mov r3, %3;                \
		 bl __Flash_Program_Buffer; \
		 mov %0, r0;"		 
		 :"=r"(status)
		 :"r"(addr), "r"(data),"r"(datalen)//, "r"(programBufferCommands)
		 : "r0", "r1", "r2", "r3", "r14", "memory");
	return status;
}

/**
 * Program_Word
 *
 * The function performs all the steps required to
 * write a word to flash. The commands and steps are defined
 * in the memory subsystem data sheet for the processor.
 *
 * @parma addr Flash Address in which the word has to be written.
 * @param data The Data that has to be written to the flash.
 *
 * @return status The status register value.
 */
uint16_t Program_Word(uint32_t addr, uint16_t data)
{
  uint16_t status;

  asm volatile(
   "mov r1, %1;                    \
    mov r2, %2;			\
    bl __Flash_Program_Word;        \
    mov %0, r0;"
    :"=r"(status)
    :"r"(addr), "r"(data)//,"r"(temp)
    : "r0", "r1", "r2", "r3", "memory");
  return status;
}
  
/**
 * Erase_Flash
 *
 * The function performs all the steps required to
 * erase a flash block. The commands and steps are defined
 * in the memory subsystem data sheet for the processor.
 * The Block address has to be passed as a parameter to the
 * function.
 * 
 * @param addr Address of the block that has to be erased.
 *
 * @return status The status register value.
 * 
 */
uint16_t Erase_Flash(uint32_t addr)
{
	uint16_t status;
	asm volatile (
		"mov r1, %1;                   \
		bl __Flash_Erase;              \
		mov %0, r0;"
		:"=r"(status)
		:"r"(addr)//, "r"(temp)
		: "r0", "r1", "r2", "memory");
	return status;
}

/**
 * Flash_Read
 *
 * The function will read from a flash location and store
 * it in a buffer. The function does 16 bit reads till length.
 *
 * @param Addr Starting Flash Address to read from.
 * @param Length Number of bytes to read.
 * @param buff Pointer to the buffer where the data is stored.
 *
 * @return SUCCESS | FAIL
 */
result_t Flash_Read (uint32_t Addr, uint32_t Length, uint8_t* buff)
{
  uint32_t curPtr = 0;
  uint32_t address = Addr;
  uint32_t data = 0;
  while (curPtr < Length)
  {
    data = (*((uint32_t *)address));
    memcpy ((buff + curPtr), &data, 2);
    curPtr = curPtr + 2;
    address += 2;
  }
  return SUCCESS;
}

--- NEW FILE: HPLInit.c ---
/*									tab:4
 * "Copyright (c) 2000-2003 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 * Copyright (c) 2002-2003 Intel Corporation
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE     
 * file. If you do not find these files, copies can be found by writing to
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
 * 94704.  Attention:  Intel License Inquiry.
 */

/**
 * @file HPLInit.h
 * @author
 * 
 * The file provides various hardware initialization routines.
 * Ported from TinyOS repository - Junaith
 *
 */

#include <hardware.h>
#include <HPLInit.h>
#include <MMU.h>
#include <FlashAccess.h>

/**
 * TOSH_SET_PIN_DIRECTIONS
 *
 * Set the pin directions in the processor as a part of
 * the hardware initialization process.
 *
 */
void TOSH_SET_PIN_DIRECTIONS(void)
{
  PSSR = (PSSR_RDH | PSSR_PH);   // Reenable the GPIO buffers (needed out of reset)
  TOSH_CLR_CC_RSTN_PIN();
  TOSH_MAKE_CC_RSTN_OUTPUT();
  TOSH_CLR_CC_VREN_PIN();
  TOSH_MAKE_CC_VREN_OUTPUT();
  TOSH_SET_CC_CSN_PIN();
  TOSH_MAKE_CC_CSN_OUTPUT();
  TOSH_MAKE_CC_FIFOP_INPUT();
  TOSH_MAKE_CC_FIFO_INPUT();
  TOSH_MAKE_CC_SFD_INPUT();
  TOSH_MAKE_RADIO_CCA_INPUT();
}

/**
 * This function is ported from DVFS TinyOS Module.
 * Set the Frequency of the clock.
 *
 * NOTE:
 *   If the Frequency has to be incremented about 104Mhz then
 *   the CoreVoltage has to be increased accordingly. Refer to
 *   http://download.intel.com/design/pca/applicationsprocessors/datashts/28000304.pdf
 *
 * @param coreFreq Clock frequency to be set.
 * @param sysBusFreq Bus Frequency.
 *
 * @return SUCCESS | FAIL
 */
result_t SetCoreFreq (uint32_t coreFreq, uint32_t sysBusFreq)
{
  /*
   * TODO : add all supported frequencies, for now support 13 & 104 only
   *        add core voltage switching to min value based on freq
   */
  switch (coreFreq) 
  {
    case 13:
      if (sysBusFreq != 13) {
        return FAIL;
      }
      {__nesc_atomic_t atomic = __nesc_atomic_start();
        CCCR = CCCR_CPDIS | CCCR_A;
        asm volatile (
	         "mcr p14,0,%0,c6,c0,0\n\t"
	         :
	         : "r" (0x2)
	         );
        // check that core PLL was disabled
        while ((CCSR & CCSR_CPDIS_S) == 0);
      __nesc_atomic_end (atomic);
      }
        return SUCCESS;

      case 104:
        if (sysBusFreq != 104)
           return FAIL;

        {
        __nesc_atomic_t atomic = __nesc_atomic_start();
          CCCR = CCCR_L(8) | CCCR_2N(2) | CCCR_A ; 
          asm volatile (
		         "mcr p14,0,%0,c6,c0,0\n\t"
		         :
		         : "r" (0xb)           
		         );
	  // "r" (0xb)
           // wait until core pll locks
          while ((CCSR & CCSR_CPLCK) == 0);
        __nesc_atomic_end (atomic);
        }
        return SUCCESS;
      case 312:
        if (sysBusFreq != 312)
           return FAIL;

        {
        __nesc_atomic_t atomic = __nesc_atomic_start();
          CCCR = CCCR_L(16) | CCCR_2N(3) | CCCR_A; 
          asm volatile (
		         "mcr p14,0,%0,c6,c0,0\n\t"
		         :
		         : "r" (0xb)
		         );
	  // "r" (0xb)
           // wait until core pll locks
          while ((CCSR & CCSR_CPLCK) == 0);
        __nesc_atomic_end (atomic);
        }
        return SUCCESS;
      default:
        return FAIL;
  }
  return FAIL;
}

/**
 * HPLInit
 *
 * Intialize the hardware clock, set clock frequency and set
 * pin directions.
 *
 * @return SUCCESS | FAIL
 */
result_t HPLInit() 
{
  CKEN = (CKEN22_MEMC | CKEN20_IMEM | CKEN15_PMI2C | CKEN9_OST);
  OSCC = (OSCC_OON);

  while ((OSCC & OSCC_OOK) == 0);
    
  TOSH_SET_PIN_DIRECTIONS();
  SetCoreFreq(13, 13);
  return SUCCESS;
}


/**
 * Enable_MMU
 *
 * The function enables the MMU, ICache and
 * DCache. The clock frequency is set to 104Mhz for
 * fast execution and improves performance.
 *
 * @return SUCCESS | FAIL
 */
result_t Enable_MMU ()
{
  SetCoreFreq(104, 104);

#ifdef MMU_ENABLE

  /* Every thing is still happy even if we dont set these fields, 
   * just do it for correctness
   */
  SA1110 = SA1110_SXSTACK(1);  
  //MSC0 = MSC0 | (1<<19) | (1<<31) | (2 << 16) ;
  MSC0 = MSC0 | (1<<3) | (1<<15) | 2 ;
  //MSC0 = 0xFFFA7FF8;
  MSC1 = MSC1 | (1<<3);
  MSC2 = MSC2 | (1<<3);

  //PXA27x MemController 2nd tier initialization.See 6.4.10 for details
  MECR =0; //no PC Card is present and 1 card slot
     
  //PXA27x MemController 3rd tier initialization.See 6.4.10 for details
  //FLYCNFG
     
  //PXA27x MemController 4th tier initialization.See 6.4.10 for details
  MDCNFG = 0x0B002BCC; //should be 0x0B002BCD, but we want it disabled.

  //PXA27x MemController 5th tier initialization.See 6.4.10 for details
  //SXCNFG = SXCNFG_SXEN0 | SXCNFG_SXCL0(4) | SXCNFG_SXTP0(3);

  //initialize the MMU
  initMMU();
  enableICache();
  enableDCache();
#endif

  return SUCCESS;
}

--- NEW FILE: Leds.c ---
/*									tab:4
 * "Copyright (c) 2000-2003 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 * Copyright (c) 2002-2003 Intel Corporation
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE     
 * file. If you do not find these files, copies can be found by writing to
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
 * 94704.  Attention:  Intel License Inquiry.
 */

/**
 * @file Leds.c
 * @author Junaith Ahemed
 *
 * This file Initialize the LED's and provides
 * functions to toggle the each individual LED's.
 */
#include <Leds.h>

uint8_t STATE_RED_LED = TRUE;
uint8_t STATE_GREEN_LED = TRUE;
uint8_t STATE_YELLOW_LED = TRUE;

/**
 * Leds_Init
 *
 * Intialize the Leds and create macros for
 * controlling the LED pins.
 */
result_t Leds_Init ()
{
  TOSH_MAKE_RED_LED_OUTPUT();
  TOSH_MAKE_GREEN_LED_OUTPUT();
  TOSH_MAKE_YELLOW_LED_OUTPUT();
  TOSH_SET_RED_LED_PIN ();
  TOSH_SET_GREEN_LED_PIN ();
  TOSH_SET_YELLOW_LED_PIN ();
  return SUCCESS;
}


--- NEW FILE: Makefile ---
#
#
#
#
INCLUDES = -I../include -I../blinclude

#	-static -nostdlib 

CC = xscale-elf-gcc
CFLAGS = -c -g -Wall -DMMU_ENABLE
AS = xscale-elf-as -mcpu=iwmmxt -mfpu=softfpa -W -I../include -I../blinclude
BUILD_DIR=build

#	init.c
BL_SOURCES = 			\
	TOSSched.c		\
	main.c			\
	PXA27XHardware.c	\
	HPLInit.c 		\
	Leds.c			\
	PXA27Xdynqueue.c	\
	PXA27XInterrupt.c	\
	PXA27XGPIOInt.c		\
	PXA27XClock.c		\
	USBClient.c		\
	PMIC.c			\
	FlashAccess.c		\
	BinImageHandler.c	\
	BootLoader.c		\
	Crc.c			\
	AttrAccess.c            \
       	
BL_ASM_SRC =		\
	barecrt.s	\
	util.s 		\
	mmu_table.s 	\
	binarymover.s 	\
	flash.s
   	
BL_LDFLAGS	= 			\
	-static -nostartfiles		\
	-Wl,-T,bare.x -Wl,--stats	\
	-Wl,-Map,bl-elf32.map	

EXEC=$(BUILD_DIR)/out.exe
OBIN=$(BUILD_DIR)/out.bin
VECBIN=$(BUILD_DIR)/Vector.bin
TXTBIN=$(BUILD_DIR)/txtdata.bin
DISASSEM=$(BUILD_DIR)/disassemble.S

CLEANFILES = *~ 	\
	*.o 		\
	*.map		\

BL_OBJS = $(BL_SOURCES:.c=.o)
BL_ASM_OBJS = $(BL_ASM_SRC:.s=.o)

all: $(BUILD_DIR) $(BL_ASM_SRC) $(BL_SOURCES) $(EXEC) $(TXTBIN) $(VECBIN)

$(VECBIN): $(EXEC)
	xscale-elf-objcopy --output-target=binary --rename-section .init=.text,alloc,load,readonly,data,content $(EXEC) $(OBIN)
	dd ibs=32 count=1 if=build/out.bin of=build/vector.bin

$(TXTBIN): $(EXEC)
	xscale-elf-objcopy --output-target=binary -j .text -j .data $(EXEC) $(TXTBIN)
	xscale-elf-objdump -D $(EXEC) > $(DISASSEM)

$(BUILD_DIR):
	mkdir -p $(BUILD_DIR)

$(EXEC): $(BL_ASM_OBJS) $(BL_OBJS)
	$(CC) -v $(BL_LDFLAGS) $(INCLUDES) $(BL_ASM_OBJS) $(BL_OBJS) -o $@
	mv -f *.o *.map $(BUILD_DIR)

.c.o:
	$(CC) $(CFLAGS) $(INCLUDES) $< -o $@

.S.o:
	$(AS) -o $@ $<

clean:
	rm -f $(CLEANFILES)
	rm -rf $(BUILD_DIR)

#install:
#	c:/nordheim/xflash/xflash.exe -p imote2 -tt "JTAG CPU" $(VECBIN)
#	c:/nordheim/xflash/xflash.exe -p imote2 -tt "JTAG CPU" -fb 0x200000 $(TXTBIN)

install:
	c:/nordheim/xflash/xflash.exe -p imote2 -tt "JTAG CPU" $(VECBIN)
	c:/nordheim/xflash/xflash.exe -p imote2 -tt "JTAG CPU" -fb 0x200000 $(TXTBIN)
#INTEL(R) JTAG CABLE
#	c:/nordheim/xflash/xflash.exe -p imote2 -tt "INTEL(R) JTAG CABLE" $(VECBIN)
#	c:/nordheim/xflash/xflash.exe -p imote2 -tt "INTEL(R) JTAG CABLE" -fb 0x200000 $(TXTBIN)

--- NEW FILE: PMIC.c ---
/*									tab:4
 * "Copyright (c) 2000-2003 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 * Copyright (c) 2002-2003 Intel Corporation
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE     
 * file. If you do not find these files, copies can be found by writing to
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
 * 94704.  Attention:  Intel License Inquiry.
 */

/**
 * @file PMIC.c
 * @author Lama Nachman, Robbie Adler
 *
 * The file provices PMIC intialization and settings together with
 * the interrupts from the PMIC.
 */
#include <PMIC.h>
#include <PXA27XInterrupt.h>
#include <PXA27XGPIOInt.h>
#include <HPLInit.h>


bool gotReset = FALSE;
TOSH_ASSIGN_PIN(PMIC_TXON, A, 108);

#define PMI_GPIO 1

/**
 * PMIC_Init
 *
 * Setup the I2C to talk to the PMIC and allocate the I2C interrupt.
 * This code is ported from the tinyos repository and combines both
 * the init and the start routine of the tinyos version.
 *
 * @return SUCCESS | ERROR
 */
void PMIC_Init()
{
  uint8_t val[3];

  CKEN |= CKEN15_PMI2C;
  PCFR |= PCFR_PI2C_EN;
  PICR = ICR_IUE | ICR_SCLE;
    
  TOSH_MAKE_PMIC_TXON_OUTPUT();
  TOSH_CLR_PMIC_TXON_PIN();
    
  gotReset=FALSE;
  
  PXA27XIrq_Allocate (PPID_PWR_I2C);

  //irq is apparently active low...however trigger on both for now
  //call PMICInterrupt.enable(TOSH_FALLING_EDGE);
  PXA27XGPIOInt_Enable (PMI_GPIO, TOSH_FALLING_EDGE);
  PXA27XIrq_Enable (PPID_PWR_I2C);
  
  /*
   * Reset the watchdog, switch it to an interrupt, so we can disable it
   * Ignore SLEEP_N pin, enable H/W reset via button
   */
  writePMIC(PMIC_SYS_CONTROL_A,
         SCA_RESET_WDOG | SCA_WDOG_ACTION | SCA_HWRES_EN);

  // Disable all interrupts from PMIC except for ONKEY button
  writePMIC(PMIC_IRQ_MASK_A, ~IMA_ONKEY_N);
  writePMIC(PMIC_IRQ_MASK_B, 0xFF);
  writePMIC(PMIC_IRQ_MASK_C, 0xFF);

  //read out the EVENT registers so that we can receive interrupts
  readPMIC(PMIC_EVENTS, val, 3);

  // Set default core voltage to 0.85 V
  //call PMIC.setCoreVoltage(B2R1_TRIM_P85_V);
  PMIC_SetCoreVoltage (B2R1_TRIM_P95_V);

  //startLDOs ();
}

/**
 * PMIC_Stop
 *
 * Disable the interrupts related to the PMIC and undo
 * all the register settings.
 *
 * @return SUCCESS | FAIL
 */
result_t PMIC_Stop()
{
  PXA27XIrq_Disable (PPID_PWR_I2C);
  PXA27XGPIOInt_Disable (PMI_GPIO);
  CKEN &= ~CKEN15_PMI2C;
  PICR = 0;
    
  return SUCCESS;
}


/**
 * readPMIC
 *
 * The function reads data from the PMIC using the I2C
 * and stores it in a buffer ("value")
 *
 * @param address Address to read from.
 * @param value The data will be stored in this buffer.
 * @param numBytes Number of bytes to be read.
 *
 * @return SUCCESS | FAIL
 */
result_t readPMIC (uint8_t address, uint8_t *value, uint8_t numBytes)
{
  //send the PMIC the address that we want to read
  if(numBytes > 0)
  {
    PIDBR = PMIC_SLAVE_ADDR<<1; 
    PICR |= ICR_START;
    PICR |= ICR_TB;
    while(PICR & ICR_TB);
      
    //actually send the address terminated with a STOP
    PIDBR = address;
    PICR &= ~ICR_START;
    PICR |= ICR_STOP;
    PICR |= ICR_TB;
    while(PICR & ICR_TB);
    PICR &= ~ICR_STOP;
         
    //actually request the read of the data
    PIDBR = PMIC_SLAVE_ADDR<<1 | 1; 
    PICR |= ICR_START;
    PICR |= ICR_TB;
    while(PICR & ICR_TB);
    PICR &= ~ICR_START;
      
    //using Page Read Mode
    while (numBytes > 1)
    {
      PICR |= ICR_TB;
      while(PICR & ICR_TB);
      *value = PIDBR;
      value++;
      numBytes--;
    }
      
    PICR |= ICR_STOP;
    PICR |= ICR_ACKNAK;
    PICR |= ICR_TB;
    while(PICR & ICR_TB);
    *value = PIDBR;
    PICR &= ~ICR_STOP;
    PICR &= ~ICR_ACKNAK;
      
    return SUCCESS;
  }
  else
  {
    return FAIL;
  }
}

/**
 * writePMIC
 * 
 * Write a byte value to a particular address using I2C. The value and
 * the address has to be passed as parameter to the function.
 *
 * @param address
 * @param value
 *
 * @return SUCCESS | FAIL
 */
result_t writePMIC (uint8_t address, uint8_t value)
{
  PIDBR = PMIC_SLAVE_ADDR<<1;
  PICR |= ICR_START;
  PICR |= ICR_TB;
  while(PICR & ICR_TB);

  PIDBR = address;
  PICR &= ~ICR_START;
  PICR |= ICR_TB;
  while(PICR & ICR_TB);

  PIDBR = value;
  PICR |= ICR_STOP;
  PICR |= ICR_TB;
  while(PICR & ICR_TB);
  PICR &= ~ICR_STOP;

  return SUCCESS;
}

/**
 * startLDOs
 *
 * Code ported from TinyOS,
 *
 * @@@@FIXME I am not sure which of the LDOs we will need and
 * which ones we dont care about. need to fix it.
 */
void startLDOs() 
{
  uint8_t oldVal, newVal;

#if START_SENSOR_BOARD_LDO 
  // TODO : Need to move out of here to sensor board functions
  readPMIC(PMIC_A_REG_CONTROL_1, &oldVal, 1);
  newVal = oldVal | ARC1_LDO10_EN | ARC1_LDO11_EN;	// sensor board
  writePMIC(PMIC_A_REG_CONTROL_1, newVal);

  readPMIC(PMIC_B_REG_CONTROL_2, &oldVal, 1);
  newVal = oldVal | BRC2_LDO10_EN | BRC2_LDO11_EN;
  writePMIC(PMIC_B_REG_CONTROL_2, newVal);
#endif

#if START_RADIO_LDO
  // TODO : Move to radio start
  readPMIC(PMIC_B_REG_CONTROL_1, &oldVal, 1);
  newVal = oldVal | BRC1_LDO5_EN; 
  writePMIC(PMIC_B_REG_CONTROL_1, newVal);
#endif

#if (!ENABLE_BUCK2)  // Disable BUCK2 if VCC_MEM is not configured to use BUCK2
  readPMIC(PMIC_B_REG_CONTROL_1, &oldVal, 1);
  newVal = oldVal & ~BRC1_BUCK_EN;
  writePMIC(PMIC_B_REG_CONTROL_1, newVal);
#endif

}

/**
 * PMIC_SetCoreVoltage
 * 
 * The Buck2 controls the core voltage, set to appropriate trim value
 *
 * @param trimValue
 *
 * @return SUCCESS | FAIL
 */
result_t PMIC_SetCoreVoltage(uint8_t trimValue) 
{
  writePMIC(PMIC_BUCK2_REG1, (trimValue & B2R1_TRIM_MASK) | B2R1_GO);
  return SUCCESS;
}

/**
 * PMICInterrupt_Fired
 *
 * The init routine enables only the reset interrupt and
 * all the other interrupts are explicitly disabled. So
 * the function is invoked only when the reset button is
 * activated.
 *
 */
void PMICInterrupt_Fired()
{
  WDReset (RESET_DELAY);
}

/**
 * PI2CInterrupt_Fired
 *
 * The settings to the PMIC chip is through the
 * I2C. The interrupt indicates either a write
 * or read done from the I2C bus.
 */
void PI2CInterrupt_Fired()
{
  uint32_t status, update=0;
  status = PISR;
  if(status & ISR_ITE)
  {
    update |= ISR_ITE;
#if DEBUG
    trace(DBG_USR1,"sent data");
#endif
  }

  if(status & ISR_BED)
  {
    update |= ISR_BED;
#if DEBUG
    trace(DBG_USR1,"bus error");
#endif
  }
  PISR = update;
}

/**
 * WDReset
 * 
 * Enables the watchdog and sets the compare register
 * with the value of the first parameter and waits till
 * the timeout occurs. The processor reboots once a
 * timeout.
 *
 * @parm delay Value for a compare register.
 */
void WDReset (int delay) 
{
  // Set to short timeout and block to ensure reset
  OSMR3 = OSCR0 + delay;
  OWER = 1;
  while(1);
}

--- NEW FILE: PXA27XClock.c ---
/*									tab:4
 *
 *
 * "Copyright (c) 2000-2002 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 */
/*									tab:4
 *  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.  By
 *  downloading, copying, installing or using the software you agree to
 *  this license.  If you do not agree to this license, do not download,
 *  install, copy or use the software.
 *
 *  Intel Open Source License 
 *
 *  Copyright (c) 2002 Intel Corporation 
 *  All rights reserved. 
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 * 
 *	Redistributions of source code must retain the above copyright
 *  notice, this list of conditions and the following disclaimer.
 *	Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *      Neither the name of the Intel Corporation nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 *  PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE INTEL OR ITS
 *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * 
 */
/* @file PXA27XClock.c
 * @author Phil Buonadonna
 * @author Robbie Adler   
 */
/**
 * Ported to the boot loader from tinyos tree. - Junaith
 */
#include <PXA27XClock.h>
#include <PXA27XInterrupt.h>
#include <string.h>

bool Clock_Timeout_Started = FALSE;
TimeoutDetail todetail;

/**
 * Disable_Timeout
 *
 * 
 */
void Disable_Timeout ()
{
  Clock_Timeout_Started = FALSE;
  todetail.TimeoutMS = 0;
  todetail.MsgId = 0;
  todetail.Type = 0;
  todetail.ExpectedType = 0;
  todetail.NumRetries = 0;
  todetail.NotifyFunc = NULL;
}

/**
 * Clock_Fire
 *
 * Indicates that it is time to signal the requestor
 * about the time out. The functions calls the respective
 * call back function from the struct.
 */
void Clock_Fire ()
{
  /* We dont want the interrupt till we finish
   * all the required actions at the higher level.
   * Lets disable the timer and reenable if required.
   */
  PXA27XClock_Stop ();
  
  /* Invoke the call back function to signal the
   * componenet that requested a timeout.
   */
  if (todetail.NotifyFunc != NULL)
  {
    todetail.NotifyFunc (todetail.MsgId, todetail.Type, todetail.NumRetries);
    if (todetail.NumRetries > 0)
    {
      PXA27XClock_Start(todetail.TimeoutMS);
      -- todetail.NumRetries;
    }
    else
      Disable_Timeout ();
  }
  else
    Disable_Timeout ();
}

/**
 * OSTIrq_Fired
 * 
 * This method is called from the IRQ handler when ever there is a
 * clock interrupt. The higher level Clock_Fire function maintains
 * the higher resolution.
 *
 */
void OSTIrq_Fired() 
{
  if (OSSR & OIER_E5) 
  {
    OSSR = (OIER_E5);  // Reset the Status register bit.
    
    if (Clock_Timeout_Started)
      Clock_Fire();
    else
      /* We should not have received this interrupt, Just Ignore.*/
      PXA27XClock_Stop ();
  }
}

/**
 * PXA27XClock_Start
 *
 * Initializes the required regiesters and enables the clock interrupt.
 * Currently an interrupt will occur every 1ms.
 *
 * @return SUCESS | FAIL
 */
result_t PXA27XClock_Start(uint32_t interval)
{
  result_t res = FAIL;
  res = PXA27XIrq_Allocate (PPID_OST_4_11);
  Clock_Timeout_Started = TRUE; 
  //we want a simple match based timer...i.e. Not periodic, interrupt at match
  // Resolution = 1 ms...should change in the future to be 1/32768
  OMCR5 = (OMCR_C | OMCR_CRES(0x2)); 

  {
  __nesc_atomic_t atomic = __nesc_atomic_start();
    OIER |= (OIER_E5); // Enable the channel 5 interrupt
    OSMR5 = interval;
    OSCR5 = 0x0;  // start the  counter 
  __nesc_atomic_end (atomic);
  }
  PXA27XIrq_Enable (PPID_OST_4_11); //enable the main interrupt  
  return res;
}

/**
 * PXA27XClock_Stop
 *
 * Disable the OMCR5 match interrupt and disable the counter.
 *
 * @return SUCESS | FAIL
 */
result_t PXA27XClock_Stop() 
{
  {
  __nesc_atomic_t atomic = __nesc_atomic_start();
    OIER &= ~(OIER_E5); // Disable interrupts on channel 5
  __nesc_atomic_end (atomic);
  }
  PXA27XIrq_Disable(PPID_OST_4_11);
  OMCR5 = 0x0UL;  // Disable the counter..
  Clock_Timeout_Started = FALSE;
  return SUCCESS;
}

void PXA27XClock_SetInterval (uint32_t interval)
{
  //In the future, we probably set to some number of microseconds 
  //based on val and how long it typically take to config...multiply 
  //by 32 for now
  OSMR5 = interval;
  OSCR5 = 0x0;  // start the  counter 
}

/**
 * Enable_Timeout
 *
 * Function will enable the timeout mechanism for a particular
 * command or other message types. The struct passed as parameter
 * will contain the details of timeout value and call back
 * functions etc.
 *
 * @param tout Structure which contains the time out details. The
 * 		function requesting the timeout must provide all the
 * 		required details.
 *
 * @return SUCCESS | FAIL
 */
result_t Enable_Timeout (TimeoutDetail* tout)
{
  result_t res = FAIL;
  if (Clock_Timeout_Started)
  {
    /* Currently we are allowing only one time out request.*/
    /* FIXME, if we port the timer then its easier to add more
     * but im not sure if we really have to.
     */
    return FAIL;
  }
  memcpy (&todetail, tout, sizeof (TimeoutDetail));
  if (todetail.TimeoutMS > 0)
    res = PXA27XClock_Start(todetail.TimeoutMS);
  else
    res = FAIL;
  return res;
}

/**
 * Check_Timeout_Disable
 *
 * This function is called whenever a message
 * is received, If the received message type matches
 * with the 'ExpectedType' then the time out
 * mechanism is not required anymore. So the timer
 * will be disabled.
 *
 * @param msgId Message Id
 * @param type Type of the message received (eg a particular command)
 *
 * @return SUCCESS | FAIL
 */
result_t Check_Timeout_Disable (uint8_t msgId, uint8_t type)
{
  if (todetail.MsgId == SYNC_TIMEOUT)
  {
    Disable_Timeout ();
  }
  else if ((msgId == todetail.MsgId) && (type == todetail.ExpectedType))
  {
    Disable_Timeout ();
  }
  return SUCCESS;
}

--- NEW FILE: PXA27XGPIOInt.c ---
/*									tab:4
 * "Copyright (c) 2000-2003 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 * Copyright (c) 2002-2003 Intel Corporation
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE     
 * file. If you do not find these files, copies can be found by writing to
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
 * 94704.  Attention:  Intel License Inquiry.
 */

/**
 * @file PXA27XGPIOInt.c
 * @author Phil Buonadonna
 *
 * NOTE- Ported from TinyOS repository. Jan 16.2006.
 */
#include <HPLInit.h>
#include <PXA27XGPIOInt.h>
#include <PXA27XI