/*******************************************************************************
* NXP Semiconductors
* ALL RIGHTS RESERVED.
********************************************************************************
Services performed by NXP in this matter are performed AS IS and without 
any warranty. CUSTOMER retains the final decision relative to the total design 
and functionality of the end product. NXP neither guarantees nor will be 
held liable by CUSTOMER for the success of this project.
NXP DISCLAIMS ALL WARRANTIES, EXPRESSED, IMPLIED OR STATUTORY INCLUDING, 
BUT NOT LIMITED TO, IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR 
A PARTICULAR PURPOSE ON ANY HARDWARE, SOFTWARE OR ADVISE SUPPLIED TO THE PROJECT
BY NXP, AND OR NAY PRODUCT RESULTING FROM NXP SERVICES. IN NO EVENT
SHALL NXP BE LIABLE FOR INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF
THIS AGREEMENT.

CUSTOMER agrees to hold NXP harmless against any and all claims demands or
actions by anyone on account of any damage, or injury, whether commercial, 
contractual, or tortuous, rising directly or indirectly as a result of an advise
or assistance supplied CUSTOMER in connection with product, services or goods 
supplied under this Agreement.
********************************************************************************
* File      main.c
* Owner     NXA19261
* Version   1.0
* Date      Aug-17-2017
* Classification   General Business Information
* Brief     S-record handler functions
********************************************************************************
* Detailed Description:
* S-record handler functions
* 
********************************************************************************
Revision History:
Version  Date         Author    Description of Changes
1.0      Aug-17-2017  NXA19261  Initial version
*******************************************************************************/
#include "Errors.h"
#include "Srec.h"
#include "SCI.h"

/*******************************************************************************
 Function Name : isdigit
 Engineer      : NXA19261
 Date          : Aug-17-2017
 Parameters    : NONE 
 Modifies      : NONE
 Returns       : TRUE/FALSE
 Notes         : check whether character is decimal number.
 Issues        : NONE
 *******************************************************************************/
#if BOOTLODER_REWRITABLE 
#pragma CODE_SEG DEFAULT_RAM
#endif /* BOOTLODER_REWRITABLE */
int isdigit(int ch)
{
  return ((ch >= '0') && (ch <= '9'));
} 
#if BOOTLODER_REWRITABLE 
#pragma CODE_SEG DEFAULT
#endif /* BOOTLODER_REWRITABLE */

/*******************************************************************************
 Function Name : isxdigit
 Engineer      : NXA19261
 Date          : Aug-17-2017
 Parameters    : NONE 
 Modifies      : NONE
 Returns       : TRUE/FALSE
 Notes         : check whether character is hexadecimal number.
 Issues        : NONE
 *******************************************************************************/
#if BOOTLODER_REWRITABLE 
#pragma CODE_SEG DEFAULT_RAM
#endif /* BOOTLODER_REWRITABLE */
int isxdigit (int ch)
{
  return (((ch >= '0') && (ch <= '9')) || ((ch >= 'a') && (ch <= 'f')) || ((ch >= 'A') && (ch <= 'F')));
}
#if BOOTLODER_REWRITABLE 
#pragma CODE_SEG DEFAULT
#endif /* BOOTLODER_REWRITABLE */ 

/*******************************************************************************
 Function Name : GetHexByte
 Engineer      : NXA19261
 Date          : Aug-17-2017
 Parameters    : NONE 
 Modifies      : NONE
 Returns       : error code
 Notes         : convert characters into hexadecimal byte.
 Issues        : NONE
 *******************************************************************************/
#if BOOTLODER_REWRITABLE 
#pragma CODE_SEG DEFAULT_RAM
#endif /* BOOTLODER_REWRITABLE */
static unsigned char GetHexByte(unsigned char *MemByte)
{
  unsigned char c;           //used to hold the received ASCII hex byte
  
  *MemByte = 0;
  
  c = getchar();    //get an ASCII hex byte from stdin (upper nybble of byte)
  if (!isxdigit(c))      //is it a valid hex digit
    return(BadHexData);  //no. return an error
    
  //convert the ASCII character to a binary hex nybble
  *MemByte = (isdigit(c) ? c - '0' : c - 'A' + 10) << 4;
  
  c = getchar();    //get an ASCII hex byte from stdin (lower nybble of byte)
  if (!isxdigit(c))      //is it a valid hex digit
    return(BadHexData);  //no. return an error
    
  //convert the ASCII character to a binary hex nybble
  *MemByte += (isdigit(c) ? c - '0' : c - 'A' + 10);
  
  return(noErr);         //return 'no error'
}
#if BOOTLODER_REWRITABLE 
#pragma CODE_SEG DEFAULT
#endif /* BOOTLODER_REWRITABLE */

/*******************************************************************************
 Function Name : RcvSRecord
 Engineer      : NXA19261
 Date          : Aug-17-2017
 Parameters    : NONE 
 Modifies      : NONE
 Returns       : error code
 Notes         : Parse S-record.
 Issues        : NONE
 *******************************************************************************/
#if BOOTLODER_REWRITABLE 
#pragma CODE_SEG DEFAULT_RAM
#endif /* BOOTLODER_REWRITABLE */
unsigned char RcvSRecord(SRecDataRec *SRecData)
{ 
  unsigned char Error;
    //used to hold the return error code
  unsigned char CheckSum;
    //used to hold calculated checksum value
  unsigned char SRecByte;
    //used to hold memory/address bytes received through GetHexByte()
  unsigned long int LoadAddress = 0;
    // holds the converted load address of S-Record
  unsigned char NumDataBytes;
    //holds the number of 'data' bytes in the received S-Record
  unsigned char x;
    //used as a loop counter when receiving 'data' field of the S-Record
  unsigned char AddrBytes;
    //number of bytes in the Srecord address
  unsigned char RecType;
    //holds the character received after the Start-of-Record character (S)


  for(;;)
  {
    while (getchar() != 'S'){}; //get a character. Start of record character?
    
    
    RecType = getchar();      //yes. get the next character
    
    if (RecType == '0')       //S0 record?
    {
      SRecData->RecType = HeaderRec;    //yes. mark as a header record
      AddrBytes = 2;          //with 2 address bytes
    }
    else if (RecType == '9')  //S9 record?
    {
      SRecData->RecType = EndRec;       //yes. mark as a end record
      AddrBytes = 2;          //with 2 address bytes
    }
    else if (RecType == '8')  //S8 record?
    {
      SRecData->RecType = EndRec;       //yes. mark as a end record
      AddrBytes = 3;          //with 3 address bytes
    }
    else if (RecType == '7')  //S7 record?
    {
      SRecData->RecType = EndRec;       //yes. mark as a end record
      AddrBytes = 4;          //with 4 address bytes
    }
    else if (RecType == '2')  //S2 record?
    {
      SRecData->RecType = DataRec;      //yes. mark as a data record
      AddrBytes = 3;          //with 3 address bytes
    }
    else
      continue;        //we only receive S0, S2, S7, S8 & S9 S-Records
      
    Error = GetHexByte(&SRecData->NumBytes);
    if (Error != noErr)       //get the record length field. valid hex byte?
      return(Error);          //no. return an error
      
    //initialize the checksum with the record length
    CheckSum = SRecData->NumBytes;
    
    //subtract number of bytes in the address+1 to get the length of data field
    NumDataBytes = (SRecData->NumBytes -= (AddrBytes +1));
    
    if (NumDataBytes > MaxSRecLen)  //is the S-Record longer than allowed?
      return(SRecTooLong);          //yes. report an error
      
    for (x = 0; x < AddrBytes; x++)
    {
      Error = GetHexByte(&SRecByte);
      if (Error != noErr)     //get a byte of the load address. valid hex byte?
        return(Error);        //no return an error
      CheckSum += SRecByte;   //add it into the checksum
      LoadAddress = (LoadAddress << 8) + SRecByte;
    }
    
    SRecData->LoadAddr = LoadAddress;
    
    for (x = 0; x < NumDataBytes; x++)  //receive the data field
    {
      Error = GetHexByte(&SRecByte);
      if (Error != noErr)     //get a data field byte. valid hex byte?
        return(Error);        //no return an error
      CheckSum += SRecByte;   //yes. add it in to the checksum
      
      SRecData->Data[x] = SRecByte;
    }
    
    Error = GetHexByte(&SRecByte);
    
    //get the record checksum (last byte of the record). valid hex byte?
    if (Error != noErr)
      return(Error);          //no. return an error
      
    CheckSum = ~CheckSum;     //take 1's compliment of calculated checksum
    if (CheckSum != SRecByte) //calculated checksum == received checksum ?
      return(CheckSumErr);    //no. return an error
    else
      return(noErr);

  }
}
#if BOOTLODER_REWRITABLE 
#pragma CODE_SEG DEFAULT
#endif /* BOOTLODER_REWRITABLE */
