/*
Copyright 2007, Freie Universitaet Berlin. All rights reserved.

These sources were developed at the Freie Universität Berlin, Computer
Systems and Telematics group.

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 Freie Universitaet Berlin (FUB) 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 FUB and the contributors on an "as is"
basis, without any representations or warranties of any kind, express
or implied including, but not limited to, representations or
warranties of non-infringement, merchantability or fitness for a
particular purpose. In no event shall FUB or 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.

This implementation was developed by the CST group at the FUB.

For documentation and questions please use the web site
http://scatterweb.mi.fu-berlin.de and the mailinglist
scatterweb@lists.spline.inf.fu-berlin.de (subscription via the Website).
Berlin, 2007
*/

/**
 * \defgroup	kernel		Kernel
 */

/**
 * @file	ScatterWeb.System.h
 * @brief	system kernel
 * @ingroup	kernel
 *
 * @since	1.0
 * @version	$Revision: 325 $
 *
 * @todo	Relocate to external file, review, sort and reformat
 *
This module contains two macros to control the hardware watchdog.
Furthermore it supports determining the reset source, a simple
stack checker to avoid stack overflows and a panic function.

\section system_wd	Hardware&Software Watchdog
<p>
The function System_startWatchdog() allows starting or resetting both watchdogs, System_stopWatchdog() stops it.
These macros are mostly for firmware internal use.
In the perfect case noone should call System_stopWatchdog() and the only place to
call System_startWatchdog() repeatedly would be the main loop.
However some software parts need a long time or must run exclusively (then also
disabling the interrupts together with System_stopWatchdog() )

<p>
 * Timer_A1 Interrupt was used to implement a software watchdog with a timer interrupt
 * running together with the built in hardware watchdog, because an interrupt
 * offers the possibility to receover the address where the watchdog timeout occured.
 * This address gets written in a panic message, when Timer_A1 Interrupt fires (what means watchdog timeout).
 * Putting the hardware watchdog into interrupt mode (what is possible with the MSP430)
 * is not a good idea, because then it can't recover the MCU in a case, where it
 * is not running at all (for example MSP430s known startup problems with a slow or noisy voltage rise
 * which lead to such a situation).
 * <p>
 * \section system_dac	DA-Converter
 * <p>
 * DAC, RF_POWER is on P67
 * The DAC12 outputs are multiplexed with the port P6 pins and ADC12 analog
 * inputs. When DAC12AMPx > 0, the DAC12 function is automatically selected
 * for the pin, regardless of the state of the associated P6SELx and P6DIRx bits.
 * <p>
 * DAC12AMP      typical/max current      calibration time
 *    0                OFF                      OFF
 *    1                OFF                      OFF
 *    2               50/110                    100
 *    3                 ?                        32
 *    4                 ?                         6
 *    5              200/440                     32
 *    6                 ?                         6
 *    7              700/1500                     6
 * <p>
 * Setup DAC:
 * SREF = 0  : VRef+
 * RES  = 0  : 12Bit
 * LSEL = 0  : latch loads when dat is written
 * IR   = 1  : full-scale = 1*refvoltage
 * AMP  = 7  : high speed / current
 * DF  = 0   : straight binary
 * IE  = 0   : interrupt disabled
 * IFG  = 0  : *dont care*
 * ENC  = 0  : disabled, not needed
 * GRP  = 0  : not grouped
 * <p>
 * IMPORTANT: For VRef+ REF_ON and REF2_5V must be enabled in ADC Unit!!!
 * VeREF+ is not connected?!
 * <p>
 * ADC12CTL0 |= REFON + REF2_5V; \
 * <p>
 * DAC12SREF_0 und DAC12SREF_1: Vref+
 * DAC12SREF_2 und DAC12SREF_3: VEref+
 * <p>
 \section system_reset	Reset & Watchdog control
 * <p>
 * High byte of WDTCTL must be written as 0x5A (WDTPW) to avoid a reset.
 * High byte of WDTCTL always reads as 0x69, so WDTCTL |= wont work and
 * generate resets!
 * <p>
 * use System_startWatchdog() to start the WDT and to keep the watchdog alive at least
 * 1000 ms after the last System_startWatchdog() call; or stop the Watchdog, else => reset
 * 1000ms, WDT is clocked by fACLK (assumed 32KHz)
 * <p>
 \section system_dco	Subroutine to set DCO to selected frequency
 * <p>
 * The DCO is set via BCSCTL[2..0] (nominal range) and DCOCTL[7..0] (fine tuning)
 * so minimum DCO is BCSCTL = 0, DCTOCTL = 0 and maximum is BCSCTL = 3, DCOCTL = FF
 * BCSCTL[7] = XT2Off must also be 1 to disable XT2 (not available on our boards)
 * the nominal ranges are overlapping, so 2,45768 Mhz reachable via
 * BCSCTL = 6, DCOCTL = A8 or BCSCTL = 7, DCOCTL = 16. Its accuracy
 * depends on temperature, voltage, device...
 * <p>
 * Initalizing & Controlling the DCO (Digitally Controlled Oscillator)
 * <p>
 * If ::FF_DCOCHECKER in config_t.firmwareFlags is set Timers_init will
 * add a timer every 100 ms for checkDCO and enable Timer_B1 interrupt.
 * <p>
 * The interrupt continually measures the ACLK with the DCO (like in System_setDCO)
 * and writes the result into dcoDiff.
 * checkDCO takes samples every 100 ms of dcoDiff and adjusts
 * the DCO if needed.
 * <p>
 * As the DCO is temperature-sensitive and both serial and radio
 * communication depend on the DCO calibrating the DCO continously
 * is recommended. Serial communication stops working at a temperature
 * difference of ~10°C.
 * <p>
 * A more low power option might be to not use checkDCO and just call
 * System_setDCO in long intervals (a minute or even longer).
 *
 * $Id: ScatterWeb.System.h 325 2007-12-04 11:53:41Z hutta@PCPOOL.MI.FU-BERLIN.DE $
 **/

/** \mainpage
 *
 * <p>
 * <h1>Welcome to ScatterWeb²</h1>
 * <p>
 * <br>
 * <p>
 * - <a href="group__guide.html">Installing of all needed Components</a><br>
 * - <a href="group__change_l_o_g.html">Changes of all MSB's software versions</a><br>
 * - <a href="group__guidedev.html">Documenting Code and Writing Libraries</a><br>
 * - <a href="group__jtag_t_i_n_y.html">Using the Tiny USB Flash Adapter</a><br>
 * - <a href="group__lessons.html">Learn how to write your own Applications</a>
 <p>
 \section firstmainsec	1. Overview
 * <p> 
 * As the name already implies, sensor networks need sensors, typically lots of
 * sensors, to collect data from their environment. All sensor nodes may form an
 * ad-hoc network with some nodes acting as data sources, some as relays, and
 * some as data sinks collecting data. Nodes may act in all three roles at the
 * same time. 
 * <p>
 * The MSBs developed by the CST Group forms a sound basis for research in
 * sensor networks, the development of university level courses in CS/EE based
 * on real hardware, and prototyping of sensor net applications. 
 * <p>
 * The MSBs are part of the scatterweb approach comprising a whole family of 
 * embedded web servers, sensors and actors. Typical communication scenarios of 
 * sensor networks based on the MSBs are:
 * <p>
 * - MSBs communicate via the serial port with a standard PC for application
 *   development.
 * - MSBs communicate with mobile phones via the serial port to connect to
 *   wide-area mobile phone networks. This enables remote configuration of MSBs
 *   via short messages (SMS) as well as reception of sensor data on arbitrary
 *   mobile phones world-wide.
 * - MSBs communicate via their radio interface with other MSBs to form a truly
 *   embedded, highly flexible sensor network solution.
 * <p>
 * Main components of the MSB are the sensors, a micro controller for processing
 * of all data, and a transceiver handling communication with other nodes. 
 * <p>
 * Software for the following features is already available for the MSB-430:
 * <p>
 * - Configuration and analysis of all sensor data: acceleration, temperature,
 *   and humidity,
 * - Control of peripherals: timer, transceiver, serial port, SD-Card, red LED,
 *   and several pins (IO-based and Interrupt-based).
 * - Sending and receiving of data packets via the radio interface, transmission
 *   of sensor data, communication with other systems using the same radio
 *   interface.
 * - Sending and receiving of short messages (SMS) via connected mobile phone
 *   (serial port). Just send the MSB an SMS triggering temperature monitoring
 *   every Tuesday morning from 7:00 a.m. until 11:43 a.m., if and only if
 *   there is acceleration in the room but no high humidity - it's possible
 *   with a single SMS!
 * - Periodic polling of sensor data and (depending on settings) automatic
 *   transmission via the radio interface, the serial port (terminal or mobile
 *   phone).
 * - Simple and easy configuration and control of the MSB via terminal commands
 *   over the serial interface or radio.
 * <p>
 \section secondmainsec	2. Software Documentation
 * <p> 
 * The software of the sensor nodes was first seperated into two parts (firmware
 * & application) to provide in-field programming via radio. This has recently
 * changed because that reprogramming strategy created several problems. Anyway
 * the seperation between firmware and application is kept because it prooved
 * good as hardware abstraction layer and to provide some os-like concepts.
 * <p>
 * The Firmware provides abstract functions to interface and use the hardware,
 * contains the main execution loop + interrupts and provides some os-like
 * concepts. The firmware supports the ScatterWeb MSP-430 device.
 * <p>
 * The application (userapp, program) is built on top of the firmware.
 * <p>
 * Firmware and userapp are not that strictly separated anymore. This made
 * reprogramming easier and all restrictions from the old firmware <-> userapp
 * seperation are gone.
 * <p>
 * The main superloop goes to sleep when everything is processed, all things
 * that need to be handled are interrupt driven (see main). Every interrupt
 * which needs processing from the superloop wakes the processor up with
 * WAKEUPLPM1, which also sets a flag in runModule. When all flags in runModule
 * are reset (after processing from superloop tasks) the loop goes to LPM1
 * again. If a function which needs calls as often as possible is added to the
 * superloop you have to comment out the lines about sleeping! 
 * <p>
 \section thirdmainsec	3. Important things to know
 * <p> 
 * - All routines should return fast. If a routine occupies the processor for a
 *   long time (for example outputting a long text which works with a blocking
 *   function) it should call System_startWatchdog() repeatedly (normally done
 *   in main()) to avoid a watchdog reset.
 * <p>
 * - You don't need to change the makefiles anymore. Makefiles in firmware and
 *   application automatically compile every .c file in the src directories and
 *   look into every .c and .h file for changes.
 * <p>
 * - No intialization of globals is done. You can write "uint16_t var = 49;"
 *   but var will never be initialized, do initialization in code!
 *  (Initialization may work again if the standard startup routine is used.)
 * <p>
 * Sometimes an embedded engineer said:
 * "Think small on MCUs. If you are planning to use dynamic memory allocation,
 * you are thinking much too BIG."
 */

/**
 * @addtogroup	kernel
 * @{
 */

#ifndef ScatterWeb_System
#define ScatterWeb_System

#include <stdarg.h>
#include <msp430x16x.h>
#include <io.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include "../libscatterweb.h"
#include <ScatterWeb.TypeDefs.h>

/*
ISR definitions for mspgcc are done through signal.h functions because
the interrupt keyword combines declaring a function as interrupt as well
as setting the service routine. The macros below provide
the neccessary abstraction.
*/
#if defined(__MSP430GCC__)
	#define SECTION(s)		__attribute__((section( s )))

	#define ISR(func)		interrupt(NOVECTOR) func()
#elif defined(__CCE__)
	#define SECTION(s)		_Pragma(DATA_SECTION( s ))

	#define ISR(func)		__interrupt void func()
#endif

/**
 @brief	Define WAKEUPLPM1

 @since	1.0
 */
#define WAKEUPLPM1(bit)  \
	do {     			\
    runModule |= bit;	\
    CACTL1 |= CAIFG;	\
    }while(0)

/**
 @brief	Define READ_PC

 @since	1.0
 */
#define READ_PC \
({				\
	uint16_t __x;		\
	__asm__ __volatile__(	\
	"mov	r0, %0"		\
	: "=r" ((uint16_t)__x)	\
	:);			\
	__x;			\
})

/**
 * @brief	Set virtual interrupt vector
 * @param[in]	isrvector	Number of interrupt vector
 * @param[in]	isrpointer	Function pointer to interrupt handler function
 *
 * @see GET_ISR, ISR
 * @since         1.0
 */
#define SET_ISR(isrvector, isrpointer)	\
	do{ InterruptVectors[isrvector/2] = isrpointer; }while(0)

/**
 * @brief	Get handler for virtual interrupt vector
 * @param[in]	isrvector	Number of interrupt vector
 * @return		Function pointer to interrupt handler function
 *
 * @see SET_ISR, ISR
 * @since         1.0
 */
#define GET_ISR(isrvector)	\
	({ InterruptVectors[isrvector/2]; })

/**
 @brief	Buffer size: Maximum size for normal terminal replies.

 @since	1.0
 */
#define TERM_BUFSIZE        (82)

/**
 @brief	Buffer size: Maximum size of a line received by uart, rest will be cut.

 @since	1.0
 */
#define SERIAL_BUFSIZE      (82)

/**
 @brief	Buffer size: Maximum number of timers, each timer requires 6 bytes of RAM (==sizeof(timerEntry)).

 @since	1.0
 */
#define MAX_TIMERS          (20)

/**
 @brief	Initial FCS value, use this as starting value for fcs. in ::crc_calc.

 @since	1.0
 */
#define INIT_FCS  0xffff

/**
 * @brief	Control which module is called in System_superloop
 */
enum module_flags {
	MF_RADIO_RX		= 0x0002u,	///< Net_rxHandler should be called
	MF_RADIO_TX		= 0x0004u,	///< Net_txHandler should be called
	MF_TIMER		= 0x0008u,	///< Timers_eventHandler should be called
	MF_SERIAL		= 0x0010u,	///< Set if a serial line is complete
	MF_SENSOR		= 0x0020u
};

/**
 * @see           #System_registerCallback()
 * @since         1.0
 */
enum callback_types {
	C_SERIAL,		///< Gets called everytime a whole line is received via serial port
	C_RADIO,		///< Gets called everytime a radio packet has been received
	C_SENSOR		///< Gets called for sensor values
};
/**
 @brief	The callbacks[] Array will get this size.

 @see	#callbacks[]

 @since	1.0
 */
#define NUMBER_CALLBACKS	  3

/**
 * @brief	Possible reasons for node start/restart
 * @since	1.1
 * @see		reset_reason
 *
 * This information is displayed during bootup.
 */
enum startup_reason {
	/// power on reset
	STARTUP_POR			= 0,
	/// intended software reset
	STARTUP_SWRESET		= 1,
	///	intended reset after reprogramming
	STARTUP_REPROGRAM	= 2,
	/// software reset after kernel panic
	STARTUP_KERNELPANIC	= 3,
	/// software reset after radio panic
	STARTUP_RADIOPANIC	= 4,
	/// deadlock, reset by watchdog
	STARTUP_WATCHDOG	= 5,
	///	flash key violation
	STARTUP_KEYV		= 6,
	/// whatever
	STARTUP_UNKNOWN		= 7
};

/**
 * @brief	Reason why a system reset is initiated
 * @since	1.1
 * @see startup_reason
 */
enum reset_reason {
	/// default state (do not use)
	WDS_RUNNING       	= 0xAB00,
	/// intended software reset
	WDS_SWRESET       	= 0xAB00 | STARTUP_SWRESET,
	/// software reset after reprogramming
	WDS_REPROGRAM     	= 0xAB00 | STARTUP_REPROGRAM,
	/// software reset after a kernel panic
	WDS_KERNELPANIC		= 0xAB00 | STARTUP_KERNELPANIC,
	/// software reset after a radio panic
	WDS_RADIOPANIC		= 0xAB00 | STARTUP_RADIOPANIC
};

/**
 @brief	Temperature type (built on a signed int).

 @since	1.0

 It's a signed (twos complement) fixed point value with 8 bits before comma and
 7 bits after. So Bit 15 is sign, Bit14-7 is before comma and Bit 6-0 after
 comma.
 */
typedef union { unsigned int u; signed int s; } temp_t;

extern int __infomem;

#define	LOADER_INSTALLED	(&__app_start > &__bld_start)

/**
 @brief	Controls which modules are run in the System_superloop

 @since	1.0
 */
extern volatile enum module_flags runModule;

/**
 * @brief	Table of interrupts
 *
 * See stdlib (signal.h)
 *
 * @since         1.1
 */
extern INTERRUPT_VECTORS;

/**
 @brief	Table where callbacks are hold

 @since	1.0
 */
extern fp_vp callbacks[];

/**
 * @brief	Startup information
 * @since 	1.1
 */
extern enum startup_reason	system_startupInfo;

/// mclock speed (Hz)
extern uint32_t mclock;

extern uint16_t system_reset_count;

/**
 @brief		Waits - A simple looping waiting function.

 @param[in]	w	ticks to wait
 @return		<code>True</code> always.

 @since		1.0

 Rough estimate at 2,4576 MHz: w=1 => 18us, w=10 => 62us, w=100 => 500us  w=400
 => 4ms. This method has two big disadvantages: it blocks and it's not
 accurate, timers are better.
 */
bool System_wait(uint32_t w);

/**
 @brief		Waits ms milliseconds with help of timer a (1024 ticks).

 @param[in]	ms	milliseconds to wait
 @return		<code>True</code> always.

 @since		1.0
 */
bool System_delay(unsigned int ms);

/**
 @brief		Sets DCO

 @return	<code>True</code> always.

 @since		1.0
 */
bool System_setDCO();

/**
 * @brief	Reset System
 * @since	1.0
 * @version	1.1
 * @see reset_reason
 *
 * Use the reset reasons with care. For a "normal" reset always use WDS_SWRESET.
 */
void System_reset(const enum reset_reason reason);

/**
 * @brief Set panic state
 * @since 1.0
 * @version 1.0
 * @param reset_reason Given panic reason
 * @param msg Message to be saved and printed after reboot
 *
 * Set the the system on purpose in panic state. This leads to a
 * stack dump and system reset.
 */
void System_panic(const enum reset_reason reason, char* msg);

/**
 * @brief Dump memory
 * @since 1.0
 * @version 1.0
 * @param from Start at this address
 * @param to Stop at this address
 *
 * Print the content of the memory in the given boundaries to stdout.
 */
void System_memoryDump(void* from, void* to);

/**
 * @brief	Return random value with variable seed
 */
int System_random();

/**
 * @brief	Get StartupInfo description
 * @since	1.1
 * @see		startupInfo
 * @return	string corresponding to startupInfo value
 */
const char* System_getStartupInfoString();

/**
 * @brief	Stack dump
 * @since 	1.0
 * @see 	System_memoryDump
 *
 * Dump the stack content to stdout.
 */
void System_printStack();

/**
 @brief		Registers callback

 @param[in]	type		type of callback
 @param[in]	fpcallback	function to call
 @return				pointer to callback function that was registered before

 @since		1.0
 */
fp_vp System_registerCallback(enum callback_types type, fp_vp fpcallback);

/**
 @brief		Starts watchdog

 @return	<code>True</code> always.

 @since		1.0
 */
bool System_startWatchdog();

/**
 @brief		Stops watchdog

 @return	<code>True</code> always.

 @since		1.0
 */
bool System_stopWatchdog();

/*
 @brief	This member supports the ScatterWeb infrastructure and is not intended to be used directly from your code.

 @since	1.0
 */
bool System_enableADC();

/*
 @brief	This member supports the ScatterWeb infrastructure and is not intended to be used directly from your code.

 @since	1.0
 */
bool System_disableADC();

/**
 @brief	Recompute the FCS with one more character appended.

 @since	1.0
 */
uint16_t System_ccittFcs(uint16_t fcs, uint8_t c);

// Include all headers here so other files only need to include this file.
#include "ScatterWeb.Net.h"
#include "ScatterWeb.Uart.h"
#include "ScatterWeb.Comm.h"
#include "ScatterWeb.Infomem.h"
#include "ScatterWeb.Configuration.h"
#include "ScatterWeb.Timers.h"
#include "ScatterWeb.Debuglog.h"
#include "ScatterWeb.Programming.h"
#include "ScatterWeb.Cmd.h"
#include "ScatterWeb.Cmd.Properties.h"
#include "ScatterWeb.String.h"
#include "ScatterWeb.Time.h"
#include "ScatterWeb.Data.h"

#include "ScatterWeb.CC1020.h"

/**
 * OS header.
 * Theses variables are defined by the linker script, they are needed in the software header
 *
 * @since         1.0
 */
extern const appHeader_t firmwareHeader;

#endif
/** @} */
