/******************************************************************************
MODULE      :   TraceLeUart.c
DESCRIPTION :   Traceging facility via LEUART
                Enable in trace.h globally and/or module basis
                TRACE messages are written out via LEUART

20101005 AB     Initial (derived from much older project)
20180808 AB     Adapted to CAN-Tester, every 1s alive character to retrigger
                STOP_FAST_START
20191107 AB     Adapted to EFM32JG1 (VC+ Ersatz), remove old references to DMA
                as it is all IRQ driven without DMA now, Baud rate changed from
                9600 to 115200 as JADE LFRCO has to much jitter so using HFRCO
******************************************************************************/
// --- Includes ---------------------------------------------------------------
#define LOGGING_TOKEN    TRA_LOGGING
#include "TraceLeUart.h"

#include <em_chip.h>
#include <efm32.h>
#include <em_cmu.h>
#include <em_emu.h>
#include <em_leuart.h>
#include <em_gpio.h>
#include <em_rtc.h>

#include <stdio.h>
#include <string.h>

#include "types.h"
#include "Hardware.h"
#include "Leds.h"

// --- Defines ----------------------------------------------------------------
#define BUF_MAX               7
#define WAKEUP_INTERVAL_MS    2000


#define LOG_MAX_MESSAGE_LEN     128     // max. lenght for a single TRACE message is FIXED here !!!!
// even when sprintf works with longer messages, additional character
// are not copied to the UART output buffer
#define LOG_TX_RING_BUF_SIZE     740    // logging transmit ring buffer size
#define LOG_RX_RING_BUF_SIZE      32    // logging receive ring buffer size (= max. input command len)

//#define   LOG_TEST_PIN_DIRECTION(value)   {Nop(); TRISCbits.TRISC12=(value);} // TEST PIN
//#define LOG_TEST_PIN_ON       _RC12 = 1;  // TEST PIN
//#define LOG_TEST_PIN_OFF  _RC12 = 0;  // TEST PIN

#define TESTPIN_INIT()          { GPIO_PinModeSet(gpioPortF, 7, gpioModePushPull, 0);}
#define TESTPIN( x )            { if ( x ) GPIO->P[gpioPortF].DOUT |= 1 << 7; else GPIO->P[gpioPortF].DOUT &= ~(1 << 7); }

#define TRACE_NEW_LINE          0x0001  // for trace_LowLevel()
#define TRACE_CARRIAGE_RETURN   0x0002

// --- Typedefs ---------------------------------------------------------------

// --- PUBLIC Variables -------------------------------------------------------

#ifndef NO_TRACE
  //int iTraceBufLen;                         // last log message actual lenght
  char szTraceBuf[LOG_MAX_MESSAGE_LEN];       // log message buffer for user space

  //static char szTraceInCommand[LOG_RX_RING_BUF_SIZE];   // command input via log interface for user space
#else

#endif  // NO_TRACE

// --- Variables --------------------------------------------------------------
static volatile int iTxIrqCount ;
static volatile int iRxIrqCount ;
static volatile int iGpioIrqCount;

#ifndef NO_TRACE
  static volatile char sTxRingBuf[LOG_TX_RING_BUF_SIZE];
  static volatile char sRxRingBuf[LOG_RX_RING_BUF_SIZE];

  static volatile int iNewCommands;

  static volatile int iTxBufWritePos ;
  static volatile int iTxBufReadPos ;
  static volatile int iRxBufWritePos ;
  static volatile int iRxBufReadPos ;

  static const char sAliveChars[] = "-\\|/";          // character which are logged every 1s if no user input (ALIVE)

  static volatile int iAliveCount;
  static int iCount10s;
  static int iSec;
  static int iMin;
  static int iHours;
  static int iDays;

  // counters for uptime write into NVM
  static int iSecToWriteUptime;       // time between two update write (increases dynamically)
  static int iCountUpdateWrite;       // count seconds till next update write

  static int iCurAliveChar;           // current alive character, changed about every second

  static volatile int iTxRunning = FALSE;         // indicates running transmission (needed for JADE)
  static volatile int iRxRunning = FALSE;         // indicates running reception (needed for JADE)
#else
#endif  // NO_TRACE

// startup time
struct
  {
  BYTE bNonValid;
  BYTE bSec;
  BYTE bMin;
  BYTE bHour;
  BYTE bDay0;
  BYTE bDay1;
  } sStartupTime;

// --- Macros -----------------------------------------------------------------
#define TX_INC_WRITE_POS();     {iTxBufWritePos++; if (iTxBufWritePos > LOG_TX_RING_BUF_SIZE - 1)  iTxBufWritePos = 0;  }
#define TX_INC_READ_POS();      {iTxBufReadPos++; if (iTxBufReadPos > LOG_TX_RING_BUF_SIZE - 1)  iTxBufReadPos = 0; }
#define RX_INC_WRITE_POS();     {iRxBufWritePos++; if (iRxBufWritePos > LOG_RX_RING_BUF_SIZE - 1)  iRxBufWritePos = 0;  }
#define RX_INC_READ_POS();      {iRxBufReadPos++; if (iRxBufReadPos > LOG_RX_RING_BUF_SIZE - 1)  iRxBufReadPos = 0; }

// --- Functionprototypes -----------------------------------------------------
void trace_LowLevel (int iLen, int iFlags);
void trace_NoLF     (int iLen);

// --- Code -------------------------------------------------------------------
#ifndef NO_TRACE

/**************************************************************************//**
 * @brief  Initialize Low Energy UART 1
 *
 * Here the LEUART is initialized with the chosen settings. It is then routed
 * to location xx. Finally the GPIO mode is set to push pull.
 *
 *****************************************************************************/
void initLeuart(void)
  {

  /* Start LFRCO, and use LFRCO for low-energy modules */
  //CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_LFRCO);
  //CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_LFRCO);  // 20191112 does not work good enough with JADE, to much jitter
                                                        // with 9600 baud. 2400 baud is okay but to slow

  // Enable LE (low energy) clocks
  CMU_ClockEnable(cmuClock_HFLE, true); // Necessary for accessing LE modules JADE
  CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_HFCLKLE);

  // Enable clocks for LEUART0
  CMU_ClockEnable(cmuClock_LEUART0, true);
  CMU_ClockDivSet(cmuClock_LEUART0, cmuClkDiv_1); // Don't prescale LEUART clock JADE

  // Initialize the LEUART0 module
  LEUART_Init_TypeDef init = LEUART_INIT_DEFAULT;
  init.baudrate = 115200;
  LEUART_Init(LEUART0, &init);

  // work around for -B errate - set divider to 270
  /* LF register about to be modified require sync. busy check */
  //while (LEUART0->SYNCBUSY & LEUART_SYNCBUSY_CLKDIV);  //LEUART_Sync(LEUART0, LEUART_SYNCBUSY_CLKDIV);
  //LEUART0->CLKDIV = 0x267;
  // work around end

  // Enable LEUART0 RX/TX pins on PF[4] PF[3]
  LEUART0->ROUTEPEN  = LEUART_ROUTEPEN_RXPEN | LEUART_ROUTEPEN_TXPEN;
  LEUART0->ROUTELOC0 = LEUART_ROUTELOC0_RXLOC_LOC27 | LEUART_ROUTELOC0_TXLOC_LOC27;

  /* Enable GPIO for LEUART0. TX is on PF3 */
  GPIO_PinModeSet(gpioPortF,                /* GPIO port */
                  3,                        /* GPIO port number */
                  gpioModePushPull,         /* Pin mode is set to push pull */
                  1);                       /* High idle state */

  /* Enable GPIO for LEUART0. RX is on PF4 */
  GPIO_PinModeSet(gpioPortF,            /* Port */
                  4,                    /* Port number */
                  gpioModeInputPull,    /* Pin mode is set to input only, with pull direction given bellow */
                  1);                   /* Pull direction is set to pull-up */

  // and generate IRQ on falling edge in addition to RX function
  // this is to wake up from EM2 on falling edge so LEUART can take over reception afterwards
  // Configure PF4 interrupt on falling edge
  GPIO_IntConfig(gpioPortF, 4, false, true, true);

  /* Enable GPIO_EVEN interrupt vector in NVIC and priority */
  NVIC_SetPriority(GPIO_EVEN_IRQn, 7);  // same priority as UART IRQ below, don't set different priority!
  NVIC_EnableIRQ(GPIO_EVEN_IRQn);

  // enable receive IRQ and TX buffer low and (JADE, HFCLK) TX completed
  LEUART_IntEnable(LEUART0, LEUART_IEN_RXDATAV | LEUART_IEN_TXBL | LEUART_IF_TXC);

  /* Enable LEUART0 interrupt vector and set priority */
  NVIC_SetPriority(LEUART0_IRQn, 7);  // same priority as GPIO IRQ above, don't set different priority!
  NVIC_EnableIRQ(LEUART0_IRQn);
  }

/******************************************************************************
void GPIO_EVEN_IRQHandler(void)
  Interrupt handler GPIO even numbered pins
******************************************************************************/
void GPIO_EVEN_IRQHandler(void)
  {

  LedOn(2);
  iRxRunning = TRUE;
  iGpioIrqCount++;
  /* clear flag for PF4 RX interrupt */
  if ( GPIO_IntGet() & (1 << 4) )
    {
    GPIO_IntClear( (1 << 4) );
    }
  NVIC_ClearPendingIRQ(GPIO_EVEN_IRQn);

  }

/**************************************************************************//**
* @brief  LEUART IRQ handler
*
* Called either when TX fifo is empty or RX buffer has data and transmission
* is over (JADE)
*
******************************************************************************/
void LEUART0_IRQHandler(void)
  {
  char c;
  LEUART_TypeDef *leuart;

  LedOn(2);
  leuart = LEUART0;

  if ( LEUART_IntGet(leuart) & LEUART_IF_TXC )
    { // JADE: trasmission completed, save to go into EM2
    iTxRunning = FALSE;
    TESTPIN(0);
    LEUART_IntClear(leuart, LEUART_IF_TXC);
    }


  if ( LEUART_IntGet(leuart) & LEUART_IF_TXBL )
    { // trasmitter buffer empty
    iTxIrqCount++;

    while ( (iTxBufReadPos != iTxBufWritePos) && (LEUART_StatusGet(leuart) & LEUART_STATUS_TXBL) )    // as long as char are in ring buffer and transmitter ready
      {
      iTxRunning = TRUE;
      TESTPIN(1);
      LEUART_Tx(leuart, sTxRingBuf[iTxBufReadPos]);
      TX_INC_READ_POS();
      }

    if ( iTxBufReadPos == iTxBufWritePos )
      { // transmission completed
      LEUART_IntDisable(leuart, LEUART_IF_TXBL);
      }

    LEUART_IntClear(leuart, LEUART_IF_TXBL);
    }


  if ( LEUART_IntGet(LEUART0) & LEUART_IF_RXDATAV )
    { // Read the receive buffer while a character is available
    iRxIrqCount++;
    while ( leuart->STATUS & LEUART_STATUS_RXDATAV )
      {
      c = (char)(leuart->RXDATAX);
      if ( c == '\r' || c == '\n' )
        {
        iNewCommands++;
        }
      sRxRingBuf[iRxBufWritePos] = c;
      RX_INC_WRITE_POS();
      }

    iAliveCount = -9;    // disable alive output for another 10s when characters are received
    iRxRunning = FALSE;
    LEUART_IntClear(leuart, LEUART_IF_RXDATAV);
    }

  // clear all LEUART IRQs
  //LEUART_IntClear(leuart, _LEUART_IFC_RESETVALUE);
  NVIC_ClearPendingIRQ(LEUART0_IRQn);
  }

/******************************************************************************
char * TraceGetBuildTime (void)
  Returns pointer to string which holds build time
******************************************************************************/
char * TraceGetBuildTime(void)
  {
  return __TIME__;
  }

/******************************************************************************
char * TraceGetBuildDate (void)
  Returns pointer to string which holds build time
******************************************************************************/
char * TraceGetBuildDate(void)
  {
  return __DATE__;
  }

/******************************************************************************
void TraceInit (void)
  Initializes UART and logging ring buffer counters and sends startup message.
******************************************************************************/

void TraceInit (void)
  {
  TESTPIN_INIT();

  // clear/set variables
  iAliveCount = 1;
  iCount10s = 1;
  iSec = 0;
  iMin = 0;
  iHours = 0;
  iDays = 0;

  // clear buffer position pointers
  iTxBufWritePos = 0;
  iTxBufReadPos = 0;
  iRxBufWritePos = 0;
  iRxBufReadPos = 0;
  iTxIrqCount = 0;
  iRxIrqCount = 0;
  iGpioIrqCount = 0;

  iCurAliveChar = 0;

  CMU_ClockEnable(cmuClock_GPIO, true);       /* Enable GPIO clock */

  /* Initialize LEUART */
  initLeuart();

  TRACE ("\n");   // 2 \n cause the pin maybe not in idle state so receiver would possibly ignore first char
                  //      and at least one new line is desired
  TRACE ("*************************************************");
  TracePrintFirmwareVersion();
  // ROWLEY Crossworks - __DEBUG__ is set in Project - Properties - DEBUG - PreProcessor... for debug builds
  // MPLAB - __DEBUG will be set with debug builds
  #if defined  (__DEBUG__) || defined (DEBUG) || defined (__DEBUG)
  TRACE (" DEBUG");
  #endif
  TracePrintHwInfo();
  TRACE ("*************************************************");

  // init counters for uptime write into NVM
  iSecToWriteUptime = 4;
  iCountUpdateWrite = 4;
  }

/******************************************************************************
void TraceInit2 (void)
  Initialization second part (uptime, startup time)
******************************************************************************/
void TraceInit2 (void)
  {
  // get uptime from EEPROM
  TRACE("TRA: init2");
/*  if (NvmGiveBootStatus() != NVM_INIT_CHECK_VIRGIN)// device started with valid NVM config
      {
      TraceReadUptimeFromNvm();
      }
  else                                                // NVM config not valid, clear time,
      {                                               // variables are initialized to 0, so
      TraceWriteUptimeToNvm();                        // Uptime can safely be written
      }


  TraceWriteStartupTimeToNvm();
  TracePrintStartTime();
*/  }

/******************************************************************************
void TraceTicker1s(void)
  Called every 1s (app.). Simple SW clock and alive signalling.
******************************************************************************/
void TraceTicker1s(void)
  {
  if ( TRA_LOGGING > 2 )
    {
    TracePrintIRQs();
    }
  iSec++;
  if ( iSec > 59 )
    {
    iSec = 0;
    iMin++;
    if ( iMin > 59 )
      {
      iMin = 0;
      iHours++;
      if ( iHours > 23 )
        {
        iHours = 0;
        iDays++;
        }
      }
    }
  iCount10s++;
  if ( iCount10s > 10 )
    {
    iCount10s = 1;
    }

  // alive signaling - if no logging input/output for more than 1s, send alive character (to retrigger STOP_FAST_START)
  iAliveCount++;
  if ( iAliveCount > 1 )       // every 1 seconds, but only when no character input on logging interface !!!!!!
    {
    iAliveCount = 1;
    if ( TRA_LOGGING > 1 )
      {
      TracePrintUptime();
      }
    else
      {
      TRACE_NOLF("%c", sAliveChars[iCurAliveChar]);       // alive
      iCurAliveChar++;
      if ( iCurAliveChar >= (int) strlen(sAliveChars) )
        {
        iCurAliveChar = 0;
        }
      TRACE_NOLF("%c", 0x08);       // backspace
      }
    }

  iCountUpdateWrite--;                    // check if uptime should be written
  if ( !iCountUpdateWrite )
    {
    TRACE_L2("TRA: write uptime to NVM");
    TraceWriteUptimeToNvm();
    if ( iSecToWriteUptime < 50000 )      // time between uptime write is dynamically increased till 50000sec (about 14h)
                                          // in steps of 1/16 of current time step. So at max. 1/16 time since bLogLevel will
                                          // be lost in case of power loss, but never more than 14h
      {
      iSecToWriteUptime += iSecToWriteUptime / 16 + 8;
      TRACE_L2("TRA: next uptime write in %us", iSecToWriteUptime);
      }
    iCountUpdateWrite = iSecToWriteUptime;
    }
  }
/******************************************************************************
void trace (int)
  Forwarder to trace_LowLevel with new line and carriage return
******************************************************************************/
void trace (int iLen)
  {
  trace_LowLevel(iLen, TRACE_NEW_LINE | TRACE_CARRIAGE_RETURN);
  }

/******************************************************************************
void trace_NoLF (int)
  Forwarder to trace_LowLevel without new line and carriage return
******************************************************************************/
void trace_NoLF (int iLen)
  {
  trace_LowLevel(iLen, 0);
  }

/******************************************************************************
void trace_LowLevel (int)
  Used with macro TRACE. Copies new output string to transmit buffer and
  appends \n\r
  !!!! CHARACTERS ARE LOST/OVERWRITTEN WHEN TOO MUCH NEW CHARs are filled in

iLen:   Lenght of string (excluding \n\r) as delivered by sprintf in macro
        definition, Message is in global var szTraceBuf[]
iFlags: TRACE_NEW_LINE or TRACE_CARRIAGE_RETURN are honored
******************************************************************************/
void trace_LowLevel (int iLen, int iFlags)
  {
  WORD i;
  BYTE bOverflow = FALSE;

  LEUART_IntDisable(LEUART0, LEUART_IF_TXBL);                             // disable TX IRQ while pointer increment
  for ( i = 0; i < iLen; i++ )
    {
    ITM_SendChar(szTraceBuf[i]);    // put it out at SWO too

    sTxRingBuf[iTxBufWritePos] = szTraceBuf[i]; // put char from TraceBuf to output ring buffer
    TX_INC_WRITE_POS();
    if ( iTxBufWritePos == iTxBufReadPos ) bOverflow = TRUE;
    }

  // append \r\n to trace messages if desired
  if ( iFlags & TRACE_NEW_LINE )
    {
    ITM_SendChar('\n');   // put it out at SWO too

    sTxRingBuf[iTxBufWritePos] = '\n';      // put \n in ring buffer
    TX_INC_WRITE_POS();
    if ( iTxBufWritePos == iTxBufReadPos ) bOverflow = TRUE;
    }

  if ( iFlags & TRACE_CARRIAGE_RETURN )
    {
    ITM_SendChar('\r');   // put it out at SWO too

    sTxRingBuf[iTxBufWritePos] = '\r';      // put \r in ring buffer
    TX_INC_WRITE_POS();
    if ( iTxBufWritePos == iTxBufReadPos ) bOverflow = TRUE;
    }


  if ( bOverflow )      // mark overflow in output stream with ***
    {
    sTxRingBuf[iTxBufWritePos] = '\n';      // put \n in ring buffer
    TX_INC_WRITE_POS();
    sTxRingBuf[iTxBufWritePos] = '\r';      // put \n in ring buffer
    TX_INC_WRITE_POS();
    sTxRingBuf[iTxBufWritePos] = '*';       // put \r in ring buffer
    TX_INC_WRITE_POS();
    sTxRingBuf[iTxBufWritePos] = '*';       // put \r in ring buffer
    TX_INC_WRITE_POS();
    sTxRingBuf[iTxBufWritePos] = '*';       // put \r in ring buffer
    TX_INC_WRITE_POS();
    sTxRingBuf[iTxBufWritePos] = '\n';      // put \r in ring buffer
    TX_INC_WRITE_POS();
    sTxRingBuf[iTxBufWritePos] = '\r';      // put \r in ring buffer
    TX_INC_WRITE_POS();
    }

  iTxRunning = TRUE;
  LEUART_IntSet(LEUART0, LEUART_IF_TXBL);         // activate TX IRQ
  LEUART_IntEnable(LEUART0, LEUART_IF_TXBL);;     // reenable TX IRQ

  iAliveCount = 1;    // disable alive character for another 1s //10s
  }


/******************************************************************************
char TraceGetKey (void)
  Returns next byte in logging input stream
******************************************************************************/
char TraceGetKey(void)
  {
  char c;

  LEUART_IntDisable(LEUART0, LEUART_IF_RXDATAV);  // disable RX IRQ while pointer increment
  if ( iRxBufReadPos != iRxBufWritePos )            // character available ?
    {
    c = sRxRingBuf[iRxBufReadPos];
    RX_INC_READ_POS();
    }
  else c = 0;                                     // indicate read error
  LEUART_IntEnable(LEUART0, LEUART_IF_RXDATAV);   // reenable RX IRQ
  return c;
  }

/******************************************************************************
void TracePrintUptime (void)
  Sends uptime string to logging interface
******************************************************************************/
void TracePrintUptime(void)
  {
  TRACE("TRA: uptime %5d days %02d:%02d:%02d", iDays, iHours, iMin, iSec);
  }

/******************************************************************************
void TracePrintStartTime (void)
  Sends start time string to logging interface
******************************************************************************/
void TracePrintStartTime(void)
  {
  WORD wD = 0;
  BYTE bS = 0, bM = 0, bH = 0;
  BYTE *pbPos;

  pbPos = &sStartupTime.bNonValid;

  // write time
  bS = *(pbPos + 1);
  bM = *(pbPos + 2);
  bH = *(pbPos + 3);
  wD = *(pbPos + 4);
  wD += *(pbPos + 5) * 256;

  TRACE("TRA: boot at%5d days %02d:%02d:%02d", wD, bH, bM, bS);
  }

/******************************************************************************
void TracePrintIRQs (void)
  Prints out number of uart IRQs at logging interface
******************************************************************************/
void TracePrintIRQs(void)
  {
  LEUART_IntDisable(LEUART0, LEUART_IF_TXBL | LEUART_IF_RXDATAV);
  TRACE("TRA: IRQs TX: %u, RX: %u, GPIO: %u", iTxIrqCount, iRxIrqCount, iGpioIrqCount);
  LEUART_IntEnable(LEUART0, LEUART_IF_TXBL | LEUART_IF_RXDATAV);
  }

/******************************************************************************
void TraceReadUptimeFromNvm (void)
  Reads uptime info from NVM to RAM. Uptime is stored in 2 arrays. A NONVALID
  flag indicates the valid array. If both are valid, last write was interrupted
  and set1 is used.
******************************************************************************/
void TraceReadUptimeFromNvm(void)
  {
/*  BYTE bPos = 0;


  // check which position is VALID
  if ( NvmGetChar(NVM_UPTIME1_NONVALID) == FALSE )
    {
    bPos = NVM_UPTIME1_NONVALID;
    }
  else
    {
    if ( NvmGetChar(NVM_UPTIME2_NONVALID) == FALSE )
      {
      bPos = NVM_UPTIME2_NONVALID;
      }
    }

  // read time from valid position, if both are invalid, clear time
  if ( bPos )   // at least on array is valid
    {
    iSec =   NvmGetChar(bPos + 1);
    iMin =   NvmGetChar(bPos + 2);
    iHours = NvmGetChar(bPos + 3);
    iDays =  NvmGetChar(bPos + 4);
    iDays += NvmGetChar(bPos + 5) * 256;
    TracePrintUptime();
    }
  else        // no valid array found, clear time
    {
    iSec =   0;
    iMin =   0;
    iHours = 0;
    iDays =  0;
    TraceWriteUptimeToNvm();        // write valid uptime to NVM
    TRACE("TRA: no valid uptime found in NVM");
    }
*/  }

/******************************************************************************
void TraceWriteUptimeToNvm (void)
  Stores uptime info to NVM. Uptime is stored in 2 arrays. A NONVALID flag is
  cleard after sucessful write. NOVALID flag of other set is set. So usually
  only one set is valid. If both are valid, last write was interrupted.
******************************************************************************/
void TraceWriteUptimeToNvm(void)
  {
/*  BYTE bPosNew, bPosOld;

  // check which position is NONVALID
  if ( NvmGetChar(NVM_UPTIME1_NONVALID) )
    {
    bPosNew = NVM_UPTIME1_NONVALID;
    bPosOld = NVM_UPTIME2_NONVALID;
    }
  else
    {
    bPosNew = NVM_UPTIME2_NONVALID;
    bPosOld = NVM_UPTIME1_NONVALID;
    }

  // write time to currently NONVALID position
  NvmStoreChar(bPosNew + 1, iSec);
  NvmStoreChar(bPosNew + 2, iMin);
  NvmStoreChar(bPosNew + 3, iHours);
  NvmStoreChar(bPosNew + 4, iDays & 0xFF);
  NvmStoreChar(bPosNew + 5, iDays >> 8);

  // set written array to valid, and older array to NONVALID
  NvmStoreChar(bPosNew, FALSE);
  NvmStoreChar(bPosOld, 0x55);    // for better readabiliy in EEProm list
  TRACE_L2("TRA: uptime written to NVM (pos: 0x%02X)", bPosNew);
*/  TRACE_L2("TRA: No NVM - no uptime");
  }

/******************************************************************************
void TraceWriteStartupTimeToNvm (void)
  Stores startup time info to NVM. NONVALID flag is not used here!
******************************************************************************/
void TraceWriteStartupTimeToNvm (void)
  {
  BYTE *pbPos;

  pbPos = &sStartupTime.bNonValid;

  // write time
  *(pbPos + 1) = iSec;
  *(pbPos + 2) = iMin;
  *(pbPos + 3) = iHours;
  *(pbPos + 4) = iDays & 0xFF;
  *(pbPos + 5) = iDays >> 8;

  //TRACE_L2("TRA: startup time written to NVM (pos: 0x%02X)", bPos);
  }


/******************************************************************************
void TracePrintHwInfo(void);
  Prints hardware info
******************************************************************************/
void TracePrintHwInfo(void)
  {
//  TRACE (" %s: %d, DIP-Switch: 0x%02X", HwGetType() == 0 ? "Master" : "Slave ", HwGetType(), HwGetType()); //, HwGetDescription() );
//  TRACE (" HW-Ver: %2d  Rev: %2d,        MAC-Address: 0x%04X", HwGetVersion(), HwGetRevision(), HwGetMacAddr() );
  TRACE (" HW-Ver: %2d  Rev: %2d", HwGetVersion(), HwGetRevision() );
  }

/******************************************************************************
void TracePrintFirmwareVersion(void);
  Prints info about firmware software version
******************************************************************************/
void TracePrintFirmwareVersion()
  {
  TRACE (" JADE ADC-Test     Build: "__DATE__"  "__TIME__"" );
  return;
  }

/******************************************************************************
int TraCommandAvail(void)
  Returns number of available commands in input buffer

ToDo: - interface to command.c should better be changed to TraGetCommand so no
TraceCommandAvailxxx would be needed anymore
******************************************************************************/
int TraceCommandAvail()
  {
  if ( iNewCommands < 0 ) iNewCommands = 0;
  return iNewCommands;
  }

/******************************************************************************
void TraceCommandAvailDec (void)
  Decreases number of available commands in input buffer

ToDo: - interface to command.c should better be changed to TraGetCommand so no
TraceCommandAvailxxx would be needed anymore
******************************************************************************/
void TraceCommandAvailDec(void)
  {
  if ( iNewCommands > 0 ) iNewCommands--;
  }

/******************************************************************************
int TraceTxIsRunning(void)
  Returns TRUE when data trasminssion is not finished until last bit is
  shifted out.
******************************************************************************/
__INLINE int TraceIsRunning(void)
  {
  return iTxRunning | iRxRunning;
  }

/******************************************************************************
__asm void hard_fault_handler_asm(void)
  Cortex-M3 fault handler
  Hard fault handler wrapper in assembly
  Extracts the location of stack frame and pass it to handler in C as pointer.
******************************************************************************/
void HardFault_Handler(void) __attribute__( ( naked ) );
void HardFault_Handler(void)
  {
  __ASM("TST LR, #4");
  __ASM("ITE EQ");
  __ASM("MRSEQ R0, MSP");
  __ASM("MRSNE R0, PSP");
  __ASM("B hard_fault_handler_c");
  }

/******************************************************************************
void hard_fault_handler_c(unsigned int * hardfault_args)
  Cortex-M3 fault handler
  The second part of the handler is in C. Here, we demonstrate how the stacked
  register contents and the Fault Status registers can be accessed.
  with stack frame location as input parameter

  The logging buffer is flushed with direct calls to UART IRQ service routine.
  As the systems crashed hard anyway, any dirty hacks can be done here. System
  restarts afterwards.
******************************************************************************/
void hard_fault_handler_c(unsigned int * hardfault_args)
  {
  unsigned int stacked_r0;
  unsigned int stacked_r1;
  unsigned int stacked_r2;
  unsigned int stacked_r3;
  unsigned int stacked_r12;
  unsigned int stacked_lr;
  unsigned int stacked_pc;
  unsigned int stacked_psr;

  stacked_r0  =  ((unsigned long) hardfault_args[0]);
  stacked_r1  =  ((unsigned long) hardfault_args[1]);
  stacked_r2  =  ((unsigned long) hardfault_args[2]);
  stacked_r3  =  ((unsigned long) hardfault_args[3]);
  stacked_r12 =  ((unsigned long) hardfault_args[4]);
  stacked_lr  =  ((unsigned long) hardfault_args[5]);
  stacked_pc  =  ((unsigned long) hardfault_args[6]);
  stacked_psr =  ((unsigned long) hardfault_args[7]);

  TRACE ("\n#####################################");
  TRACE ("[Cortex-M3 Hard fault handler]");
  TRACE (" R0 = 0x%08X", stacked_r0);
  TRACE (" R1 = 0x%08X", stacked_r1);
  TRACE (" R2 = 0x%08X", stacked_r2);
  TRACE (" R3 = 0x%08X", stacked_r3);
  TRACE (" R12= 0x%08X", stacked_r12);
  TRACE (" LR = 0x%08X - LinkRegister", stacked_lr);
  TRACE (" PC = 0x%08X", stacked_pc);
  TRACE ("\n");
  TRACE (" PSR = 0x%08X - ProgramStatus", stacked_psr);
  TRACE (" BFAR= 0x%08X - BusFaultAddress", (*((volatile unsigned long *)(0xE000ED38))));
  TRACE (" CFSR= 0x%08X - UsageFault1|UsageFault0|BusFault|MemManFault", (*((volatile unsigned long *)(0xE000ED28))));
  TRACE (" HFSR= 0x%08X - HardFaultStatus", (*((volatile unsigned long *)(0xE000ED2C))));
  TRACE (" DFSR= 0x%08X - DebugFaultStatus", (*((volatile unsigned long *)(0xE000ED30))));
  TRACE (" AFSR= 0x%08X - AuxFaultStatus", (*((volatile unsigned long *)(0xE000ED3C))));
  TRACE ("#####################################\n");

  while ( (iTxBufReadPos != iTxBufWritePos) )
    {
    LEUART0_IRQHandler();    // flush TX buffer to logging console
    }

  // restart system
  NVIC_SystemReset();
  return;
  }

//******************************************************************************
//******************************************************************************
// empty function definitions in case NO_TRACE is selected
#else
  void trace (int i) { return; };
  void TraceInit (void) { return; };
  void TraceInit2 (void) { return; };
  void TraceTicker1s() { return; };
  char TraceGetKey(void) { return 0; };
  void TracePrintUptime(void) { return; };
  void TracePrintStartTime(void) { return; };
  void TracePrintIRQs(void) { return; };
  void TracePrintHwInfo(void) { return; };
  void TracePrintKeypadInfo(void) { return; };
  void TracePrintFirmwareVersion(void) { return; };
#endif  // NO_TRACE
