/*
  SFBHWMisc.h Miscellaneous hardware-specific routines
  Copyright (C) 2009 The Regents of the University of New Mexico
 
  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
  USA

  $Id$
 */
/**
  \file SFBHWMisc.h Miscellaneous hardware-specific routines
  \author David H. Ackley.  
  \date (C) 2009 All rights reserved.
  \lgpl
 */

#ifndef SFBHWMISC_H
#define SFBHWMISC_H

#include "SFBTypes.h"

/**
   Print a timestamp to \a face.  The output depending on the context:
   In host programs the date and time are printed; in boards the
   equivalent of #seconds() is printed (along with three decimal
   places), so the printed timestamps will roll over after about 180
   years of uptime.
 */
extern void facePrintTimestamp(u8 face) ;

/**
   Estimate how much more space is currently available on the stack.
   Provides an estimate of the current stack depth, as of the call on
   this function.  

   See #getMinimumStackSpace().

   \returns an estimate of the number of bytes of available stack
            space when this function was called.

   \since 0.9.10

 */
extern u32 getCurrentStackSpace();

/**
   Estimate the minimum amount of stack space that has been available
   at any point during the running of the current sketch so far.  If
   this number ever gets 'too close' to zero, the sketch is risking a
   potential stack overflow condition.

   Note that if stack space \e does run out, all bets are off about
   the resulting sketch behavior.  If you are lucky, the sketch will
   die blinking with a #E_BUG_STACK_CORRUPT code, but that is by no
   means assured.  It might instead die with #E_HW_UNDEF, or
   #E_HW_DABT, or #E_HW_PABT, or some other blink code, or it may just
   hang rather than dying, etc. etc. etc.

   How close to zero is 'too close'?  Well, that's somewhat up to you,
   the nature of your sketch, and your tolerance for risk.  Be aware
   that the invocations of interrupt handlers \e do tie up space on
   the \e same \e system \e stack that regular functions use, and that
   is true both for user-written interrupt handlers -- e.g., as used
   with hardware timers -- as well as the core software interrupt
   handlers that deal with serial I/O and the main timer.
   
   If you feel you've manageg to run your sketch through pretty much
   all the worst (meaning: busiest, most heavily loaded, most complex
   execution path of the most complicated functions) you can
   reasonably expect, and #getMinimumStackSpace() is still returning a
   number in the 100's or more, you may \e probably be okay.  With a
   number in the 1000's you might probably feel pretty comforable.

   But, it all depends on the sketch!  For example, this sketch:
   \code
   void hugeFunction() {
     u32 buf[10000];   // buf is too big to fit in RAM..
     for (u32 i = 0; i < 10000; ++i) buf[i] = 0;
     println(buf[1]);  // keeps compiler from optimizing stuff away..
   }
   void setup() { }
   void loop() {
     if (random(1000000)==0) hugeFunction();
   }
   \endcode

   will \e probably be fine for hours.. but as soon as \c hugeFunction
   is \e actually called -- with its hopelessly oversized array -- bad
   things will ensue.

   \returns an estimate of the \e minimum number of bytes of stack
            space that have been available at any time during the
            current running of this sketch.

   \since 0.9.10

 */
extern u32 getMinimumStackSpace();

/** A special code stored in #stackCanary, used by
    #API_ASSERT_STACK_OK to help detect stack overflows. */
#define STACK_CANARY_VALUE 0x2c50904e

/** A variable placed at the end of sketch RAM usage, initialized with
    #STACK_CANARY_VALUE, and checked by #API_ASSERT_STACK_OK to help
    detect stack overflows. */
extern volatile u32 stackCanary;

static inline void init_stack_canary() { stackCanary = STACK_CANARY_VALUE; }

/** Assert that the #stackCanary variable still has its special value
    of #STACK_CANARY_VALUE, which is unlikely to be the case if the
    stack has overflowed into the sketch RAM area.
*/
#define API_ASSERT_STACK_OK() API_ASSERT(stackCanary==STACK_CANARY_VALUE,E_BUG_STACK_CORRUPT)

#ifdef HOST_MODE

#define disableInterrupts() /* empty */
#define enableInterrupts() /* empty */

#define suspendInterrupts(u32var) /* empty */
#define restoreInterrupts(u32var) ((u32var) = 0)   /* note that suspend w/o restore will warn! */

#else

#include "lpc/irq.h"

#endif /* HOST_MODE */

#endif /* HW_MISC_H */
