/*
 *  Copyright (c) 1996-2007 Digi International Inc., All Rights Reserved
 *
 *  This software contains proprietary and confidential information of Digi
 *  International Inc.  By accepting transfer of this copy, Recipient agrees
 *  to retain this software in confidence, to prevent disclosure to others,
 *  and to make no use of this software other than that for which it was
 *  delivered.  This is an unpublished copyrighted work of Digi International
 *  Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly
 *  prohibited.
 *
 *  Restricted Rights Legend
 *
 *  Use, duplication, or disclosure by the Government is subject to
 *  restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in
 *  Technical Data and Computer Software clause at DFARS 252.227-7031 or
 *  subparagraphs (c)(1) and (2) of the Commercial Computer Software -
 *  Restricted Rights at 48 CFR 52.227-19, as applicable.
 *
 *  Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
 *
 * =======================================================================
 * This file contains error handling routines.
 *
 *
 * Edit Date/Ver   Edit Description
 * ==============  =======================================================
 */

#include <stdio.h>
#include <string.h>
#include <Npttypes.h>
#include <tx_api.h>
#include <bsp_sys.h>
#include <bsp_api.h>
#include <appconf_api.h>
#include <narmled.h>
#include <gpio.h>
#include <ncc_init.h>
#include <errhndlr.h>
#include <nawait.h>

all_reg_at_crash  SavedRegs;  
void * _SavedRegPtr = &SavedRegs;

/*ad*
 * The NET+OS error handler is called whenever the software encounters a fatal
 * error.  The default error handler blinks the LED in a pattern that indicates
 * what error occurred.  In general, you must modify the error handler so that
 * it resets the board when a nonrecoverable error occurs.  This can be done
 * through a configuration setting in bsp.h.
 *
 * The NET+OS exception handler is called whenever an unexpected exception 
 * occurs.  The following events are treated as unexpected exceptions:
 *
 * <list type="unordered">
 *      <item>Prefetch Abort (Processor attempt to execute from an invalid address)</item>
 *      <item>Data Abort (Processor attempted to read or write to an invalid address)</item>
 *      <item>SWI (Software Interrupt)</item>
 *      <item>FIQ (Fast Interrupt reQuest)</item>
 *      <item>UNDEF (Process attempt to execute an undefined instruction)</item>
 * </list>
 *
 * The file netos/h/errhndlr.h contains a list of the error codes used by the
 * error handler.
 *
 *
 * @category error_handler
 * @since 3.0
 * @overview Error and Exception Handlers
 * @include <errhndlr.h>
 * @platform all
 * @library bsp
 * @external
*ad*/



/*ad*
 * Define a blink rate of 200 milliseconds between LED state changes.
 *
 * @category error_handler
 * @since 6.0
 * @include     <errhndlr.h>
 * @external
 *
*ad*/
#define BLINK_RATE              200

/*ad*
 * Fast blink rate used by unexpected exception handler.
 *
 * @category error_handler
 * @since 6.0
 * @include     <errhndlr.h>
 * @external
 *
*ad*/
#define FAST_BLINK_RATE         20

/*ad*
 * Delay 1 second between blink cycles.
 *
 * @category error_handler
 * @since 6.0
 * @include     <errhndlr.h>
 * @external
 *
*ad*/
#define DELAY_BETWEEN_CYCLES    (5 * NABspTicksPerSecond)

/*ad*
 * This variable will be set if customizeErrorHandler starts blinking LEDs to report
 * an error condition.  Set this variable to zero in the debugger to exit from the
 * loop and continue from where the error was reported.
 *
 * @category error_handler
 * @since 6.0
 * @include     <errhndlr.h>
 * @external
 *
*ad*/
volatile BOOLEAN naCustomizeErrorHandlerClearToContinue = 0;

/*ad*
 * This variable will be set if customizeExceptionHandler starts blinking LEDs to report
 * an error condition.  Set this variable to zero in the debugger to exit from the
 * loop and continue from where the error was reported.
 *
 * @category error_handler
 * @since 6.0
 * @include     <errhndlr.h>
 * @external
 *
*ad*/
volatile BOOLEAN naCustomizeExceptionHandlerClearToContinue = 0;


/*ad*
 * This routine is called by netosFatalError().  It is used to make it
 * easy to set breakpoints.
 *
 * @category error_handler
 * @since 6.0 
 * @include "netoserr.h"
 * @external
 *
 * @param    reason:    pointer to the error description
 *
*ad*/
void netosBreakpoint(char * reason)

{
    if (reason)
    {
#ifdef PLEASE_CUSTOMIZE_THIS_CODE
#error You need to customize this code
#endif
    }
}


/*ad*
 * This routine is called when a nonrecoverable error occurs.  If a user defined
 * error handler has been defined, then it is called.  Otherwise, it blinks the
 * LEDs in a pattern that indicates the error type.
 *
 * A user error handler is defined by setting APP_ERROR_HANDLER in app_conf.h to
 * the address of an error handling routine.  If no error handler is present, this
 * APP_ERROR_HANDLER should be set to 0.
 *
 * This error handler blinks the LEDs.  An alternative for a production device
 * might be to call NAReset() to restart the system.
 *
 * @external
 * @include "netoserr.h"
 * @category error_handler
 * @since 6.0 
 *
 * @param description     pointer to a string that contains a description of the problem
 * @param redBlinks       # of times to blink the red/yellow LED
 * @param greenBlinks     # of times to blink the green LED
 *
*ad*/
void netosFatalError(char * description, int redBlinks, int greenBlinks)

{
    userErrorHandlerType userErrorHandler = NAGetAppErrorHandler ();

    if (userErrorHandler)                           /* did user define their own error handler*/
    {                                               /* if so, call it*/
        userErrorHandler (description, redBlinks, greenBlinks);
    }
    else                                            /* if no user error handler*/
    {
        netosBreakpoint (description);              /* try to hit breakpoint in debugger*/
                                                    /* call fatal error handler*/
        customizeErrorHandler(redBlinks, greenBlinks);
    }
}

/*ad*
 * This routine will be called to handle fatal errors.  The way
 * it handles them is application specific.  In some cases it may
 * be desirable to report the error to the user through LEDs or
 * other means.  In other cases it may be necessary to reset the
 * board.
 *
 * This version of the code has been written to support the NET+OS
 * development board.  It is assumed that this version of the 
 * error handler will only be used during development.  If 
 * BSP_CRASH_RECOVERY_PROCEDURE has been set to BSP_RESET_UNIT and
 * no debugger was detected during startup, then the unit is
 * reset.  Otherwise, the routine blinks the LEDs in a pattern that
 * identifies the error that occurred.  The pattern is repeated in
 * a loop until the developer exits the loop by setting
 * customizeErrorHandlerClearToContinue to zero in the debugger.
 * The yellow LED will be blinked errorCode times, and the green
 * LED will be blinked subcode times if subcode is greater than
 * zero.
 *
 * @external
 * @include     <errhndlr.h>
 * @category error_handler
 * @since 6.0 
 *
 * @param errorCode    indicates the type of error that occurred
 * @param subcode      provides more specific information
 *
 * @note THIS CODE MUST BE CUSTOMIZED FOR YOUR BOARD.  The implementation
 *       below is for NET+OS development boards only.
 *
 *       Your application specific board may have different LEDs, or no
 *       LEDs.  You should customize the error reporting accordingly.
 *       You may also want to print an error message out one of the serial
 *       or parallel ports.
 * 
*ad*/
void customizeErrorHandler(int errorCode, int subcode)
{
/*
 * THIS CODE MUST BE CUSTOMIZED FOR YOUR BOARD.  This implementation
 * is for NET+OS development boards only.
 */

    if (   (BSP_HANDLE_FATAL_ERROR == BSP_ERROR_RESET_UNIT)
        && (!are_we_in_debugger()))
    {
        customizeReset();
    }
    else 
    {
        naCustomizeErrorHandlerClearToContinue = TRUE;
        while (naCustomizeErrorHandlerClearToContinue)
        {
            NALedBlink(LED_ERROR, errorCode, BLINK_RATE);
            if (subcode > 0)
            {
                NALedBlink(LED_OKAY, subcode, BLINK_RATE);
            }
            NAWait(DELAY_BETWEEN_CYCLES);
        }
    }
}

/*ad*
 * This routine will be called to handle unexpected exceptions.  
 * How they are handled depends upon the setting of 
 * BSP_HANDLE_UNEXPECTED_EXCEPTION in bsp_api.h.  The constant can
 * be set to one of the following values.
 *
 * BSP_ERROR_RESET_UNIT    Unit is reset unless a debugger ICE was detected during
 *                     initialization.  If an ICE was detected, then the LEDs
 *                     are blinked in a pattern that indicates the error
 *                     condition, and it is possible to continue execution in
 *                     the debugger.
 * BSP_ERROR_REPORT_ERROR  BSP blinks LEDs in a pattern that indicates the type of
 *                     exception that occurred.
 * BSP_ERROR_CONTINUE     the exception handler attempts to continue execution.  The
 *                     recovery procedure is to adjust the return address of the
 *                     exception to restart execution on the next instruction 
 *                     after the one that caused the exception.
 *
 * This version of the code has been written to support the NET+OS
 * development board.  It is assumed that this version of the 
 * exception handler will only be used during development.  
 *
 * @external
 * @include     <errhndlr.h>
 * @category error_handler
 * @since 6.0 
 *
 * @param exceptionType    indicates the type of exception handler
 *
 * @note  THIS CODE MUST BE CUSTOMIZED FOR YOUR BOARD.  The implementation
 *        below is for NET+OS development boards only.
 *
 *        Your application specific board may have different LEDs, or no
 *        LEDs.  You should customize the error reporting accordingly.
 *        You may also want to print an error message out one of the serial
 *        or parallel ports.
 * 
*ad*/
void customizeExceptionHandler(int exceptionType)
{
/*
 * THIS CODE MUST BE CUSTOMIZED FOR YOUR BOARD.  This implementation
 * is for NET+OS development boards only.
 */

    if (   (BSP_HANDLE_UNEXPECTED_EXCEPTION == BSP_ERROR_RESET_UNIT)
        && (!are_we_in_debugger()))
    {
        customizeReset();
    }
    else if (BSP_HANDLE_UNEXPECTED_EXCEPTION == BSP_ERROR_CONTINUE)
    {
        return;
    }
    else
    {
        naCustomizeExceptionHandlerClearToContinue = TRUE;
        NAWaitDisableSleep(); /* sleep disabled since we will be in exception context*/
        while (naCustomizeExceptionHandlerClearToContinue)
        {
            NALedBlink(LED_ERROR, exceptionType, BLINK_RATE);
            NAWait(DELAY_BETWEEN_CYCLES);
            NALedBlink(LED_ERROR, exceptionType, FAST_BLINK_RATE);
            NAWait(DELAY_BETWEEN_CYCLES);
        }
        NAWaitRestoreSleep();
    }
}


static char * hex2ascii(unsigned int value)
{
    int i;
    static char buff[12];

    buff[8] = '\0';     
    for(i=7; i>=0; i--)
        {
        buff[i] = (char)(value & 0xF);
        value = value >> 4;

        if(buff[i] <= 9)
            {
            buff[i] = buff[i] + '0';
            }
        else
            {
            buff[i] = buff[i] - 0xA + 'A';
            }
        }
    
    return buff;
}  


static void ExceptionSource(int source)
{
    switch(source)
    {
        case 1: bsp_printf("\nUndefined Exception\n");
        break;
        case 2: bsp_printf("\nSWI Exception\n");
        break;
        case 3: bsp_printf("\nPrefetch Exception\n");
        break;
        case 4: bsp_printf("\nAbort Exception\n");
        break;
        case 5: bsp_printf("\nAdress Error Exception\n");
        break;
        case 6: bsp_printf("\nFIQ Exception\n");
        break;
        default: bsp_printf("\nUnknown Exception\n ");
     }
}

#ifndef BOOT_LOADER
static void Show_Current_Thread_Data(void)
{ 
    TX_THREAD *my_thread_ptr;
   // static char temp_buf[64];   //char array declared 
    unsigned long temp;    
    //static char temp_buf[64];
    my_thread_ptr = tx_thread_identify();

    if( my_thread_ptr != NULL)
    {
        bsp_printf("CONTEXT: THREAD  ");
        
        /*Print Thread name*/
       // temp = (unsigned char)my_thread_ptr->tx_thread_name;
                          
        bsp_printf("\nThread Name: ");
                
        bsp_printf(my_thread_ptr->tx_thread_name);

        /*Print Thread ID*/
        temp = (unsigned int)my_thread_ptr->tx_thread_id;
                    
        bsp_printf("\nThread ID:");

        //temp_buf = hex2ascii(temp);

        bsp_printf(hex2ascii(temp));

    
        /*Print Thread stack Start Address*/
        temp = (unsigned int)my_thread_ptr->tx_stack_start;
                   
        bsp_printf("\nThread Stack Start Address:");

        bsp_printf(hex2ascii(temp));

        /*Print Thread stack end Address*/
        temp = (unsigned int)my_thread_ptr->tx_stack_end;
                    
        bsp_printf("\nThread Stack End Address:");

        bsp_printf(hex2ascii(temp));
    }

    else
    {
        bsp_printf(" CONTEXT: INTERRUPT \n");
    }

}
#endif

/************************************************************************************ 
 *  Arguments:       1. Pointer to the structure 
 *                   2. The source of the exception (int)
 *  Description:     The function calls another function get_register which returns 
 *                   the register values. The function further uses the simple serial 
 *                   application to print out the register values at the point of the 
 *                   crash and the exception source.  
 *************************************************************************************/
unsigned long CoreDump(all_reg_at_crash * data, int source)
{
    unsigned long temp;         // temporary variable declared 
   // static char temp_buf[64];   //char array declared 
    int i, count=1;
    char j = 0;

    ExceptionSource(source);

#ifndef BOOT_LOADER
    Show_Current_Thread_Data();
#endif

    /*The following lines of code uses the simple serial application to print out the data on hyperterminal*/

    /********* Link Register *************/
    temp = data -> lr;          // The pointer returns the value of LR and stores it into temp varable

    bsp_printf("\nProgram Counter :");

    bsp_printf(hex2ascii(temp));

    /********* Stack Pointer *************/
    temp = data -> sp; 

    bsp_printf("\nStack Pointer :");

    bsp_printf(hex2ascii(temp));

    /********* CPSR *************/
    temp = data -> cpsr; 

    bsp_printf("\nCurrent program status Register :");

    bsp_printf(hex2ascii(temp));

    /********* R0 - R12 *************/

    for (i=0;i<13;i++)
    {           
        temp = data -> r[i];

        if(count%2==0) {bsp_printf("\t");}
        else {bsp_printf("\n");}
         
         switch (j)
         {
         case 0: bsp_printf("R00:");
         break;
         case 1: bsp_printf("R01:");
         break;
         case 2: bsp_printf("R02:");
         break;
         case 3: bsp_printf("R03:");
         break;
         case 4: bsp_printf("R04:");
         break;
         case 5: bsp_printf("R05:");
         break;
         case 6: bsp_printf("R06:");
         break;
         case 7: bsp_printf("R07:");
         break;
         case 8: bsp_printf("R08:");
         break;
         case 9: bsp_printf("R09:");
         break;
         case 10: bsp_printf("R10:");
         break;
         case 11: bsp_printf("R11:");
         break;
         case 12: bsp_printf("R12:");
         break;
         }
                                  
                    
        bsp_printf(hex2ascii(temp));
       
        count++;
        j++;
    }
    j = 0;
    bsp_printf("\n");
    return temp;
}

/***************************************************************************
****************************************************************************/

