/*
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
*/

/**
 * @file		ScatterWeb.Net.h
 * @ingroup		radio
 * @brief		ScatterWeb Radio API
 * @version		$Revision: 507 $
 * 
 * $Id$
 */

#ifndef SCATTERWEB_NET_H_
#define SCATTERWEB_NET_H_

#include "ScatterWeb.Net.PacketTypes.h"

/**
 * @brief	Network Address
 */
typedef uint8_t		netaddr_t;

/**
 * @brief	Predefined network addresses
 */
enum netaddr_predef {
	NETADDR_UNDEFINED	= 0x00,		///< reserved for undefined (not set) or to address "this" node if a node is addressed through a wire connection
	NETADDR_MIN		 	= 0x01,		///< smallest possible node address
	NETADDR_MAX		 	= 0xFE,		///< largest possible node address
	NETADDR_BROADCAST	= 0xFF		///< broadcast address
};

/**
 * @brief	Network Header Flags
 */ 
enum netheader_flags {
	NET_TLFLAG_NOCRC	= 0x01,	///< do no error checking
	NET_TLFLAG_ACKREQ	= 0x02	///< request ack for this packet	
};

/**
 * @brief Net_CompareAddress result type
 */
enum netaddr_compareresult {
	ADRCOMP_ERROR      = 0,		///< address is undefined
	ADRCOMP_THIS	   = 0x01,	///< this node
	ADRCOMP_BROADCAST  = 0x02,	///< local broadcast
	ADRCOMP_OTHER      = 0x80	///< other node in this network
};

enum net_txmode {
	/// Define that enables CSMA/random backoff.
	NET_TXMODE_BACKOFF = 0x01,

	/// Define that turns the Radio off when nothing more is to sent.
	NET_TXMODE_LP      = 0x02
};

/**
 * @brief	Network header
 * 
 * @note	First two fields (size and destination) conform to CC1100
 * 			MAC packet format.
 */
#if defined(__CCE__)
	#pragma pack(1)
#elif defined(__MSP430GCC__)
	__attribute__((packed))
#endif
typedef struct netheader {
	uint8_t		size;			///< size of packet	
	netaddr_t	to;				///< delivery addres
	uint8_t		flags;			///< flags (see netheader_flags)
	netaddr_t	from;			///< source address
	uint8_t		_num;			///< packet number (set automatically before sending)
	uint8_t		type;			///< protocol id
	uint8_t		txpower;		///< transmit power of sender
	uint8_t		reserved;		///< unused (16-bit alignment)
} netheader_t;
#if defined(__CCE__)
	#pragma pack()
#endif

/**
 * @brief	Radio packet handler arguments
 */
struct netpacket_handler_args {
	const netheader_t (*const			netheader);		///< pointer to received packet's network layer header
	const void (*const					payload);		///< pointer to received packet's payload
	const uint16_t						payload_size;	///< received packet's payload size
	const uint8_t						rssi;			///< rssi value for this packet's transmission
	const enum netaddr_compareresult	cpaResult;		///< result of to-address comparison
};

/**
 * @brief	Pointer to network packet handler function
 */
typedef bool(*fp_net_handler)(struct netpacket_handler_args* args);

/**
 * @brief	Net_send callback function arguments
 */
struct netpacket_callback_args {
	const netheader_t (*const			netheader);		///< pointer to received packet's network layer header
	uint16_t							timesRepeated;	///< number of retries (if ack flag set)
	bool								success;		///< transmission succeeded
};

/**
 * @brief	Net_send callback function arguments
 */
typedef void(*fp_net_cb)(struct netpacket_callback_args* args);

struct netpacket_send_buffer {
	void*	buffer;		///< pointer to first byte of data
	size_t	size;		///< number of bytes to read
};

#if NETPACKET_SEND_BUFFER_COUNT < 2
#warning "NETPACKET_SEND_BUFFER_COUNT too small (min 2)"
#endif

/**
 * @brief	Net_send arguments
 * @see	Net_send
 * 
 * @note	This replaces the packet_t type from ScatterWeb 1.0
 */
typedef struct netpacket_send_args {
	/// network header
	netheader_t							netheader;
	/// optional payload blocks that are sent in consecutive order
	struct netpacket_send_buffer		payload[NETPACKET_SEND_BUFFER_COUNT];
	/// optional pointer to callback function that is called after a packet has been sent or sending failed
	fp_net_cb							fpcallback;
} netpacket_send_args_t;

/**
 @brief		Initializes the radio.

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

 @since		1.0
 */
bool Net_init();

/**
 * @brief		Enables the radio.
 *
 * @param[in]	mode	Initial tx mode (see Net_changeMode)
 * @return	<code>True</code> always.
 */
bool Net_on(enum net_txmode mode);

/**
 @brief		Disables the radio.

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

 @since		1.0
 */
bool Net_off();

/**
 * @brief Compare network address with this node's address
 * @param[in]	adr					Address to compare with #config_t:id
 * @param[in]	directConnection	Indicates that the address request comes from a directly
 * 									connected source (e.g. serial cable)
 * @return		one of enum netaddr_compareresult
 * In addition the node can be addressed by network and or node id set to zero
 * if the addressing party is directly connected. This will be the case if a
 * directly conntected PC want's to address this node without knowing it's address.
 */
enum netaddr_compareresult Net_compareAddress(
	const netaddr_t (*const adr),
	const bool directConnection
);

bool Net_changeMode(enum net_txmode);

/**
 * @brief Sends a packet over radio
 *
 * @param[in]	args	pointer to arguments
 * @return		<code>True</code> if packet was successfully buffered;
 *              <code>False</code> otherwise.
 * 
 * Example:
 * @code
 * netpacket_send_args_t npsargs;
 * 
 * // fill structure with default values
 * Net_sendArgsInit( &npsargs );
 * 
 * // fill network header custom values
 * npsargs.netheader.to = 42;						// receiver's address
 * npsargs.netheader.type = PING_REQUEST_PACKET;	// application protocol
 *
 * // queue packet for sending
 * Net_send( &npsargs );
 * @endcode
 * 
 * @see Net_sendArgsInit, netpacket_send_args
 */
bool Net_send(netpacket_send_args_t* args);

bool Net_sendPing(netaddr_t node);

bool Net_sendPong(netaddr_t node);

/**
 * @brief	Initialise Net_send argument structure
 * @param[in]	args	argument structure to initialise
 * @since	1.1
 * 
 * Resets all values to defaults and must be called
 * to initialise every netpacket_send_args structure before
 * passing to Net_send.
 * <p>
 * Sets all values to zero, the sender's address to this node's address and
 * the flags to NET_TLFLAG_ACKREQ. This may change in later versions.
 */
void Net_sendArgsInit(netpacket_send_args_t* args);

/**
 * @name	Radio abstraction interface
 * @brief	To be implemented by radio driver
 * @{
 */
typedef bool(*fpRadio_selectChannel)(uint8_t channel);

struct radio_interface {
	uint8_t					NumChannels;
	uint8_t(*SelectChannel)(uint8_t channel);
	uint8_t(*SetTxPower)(uint8_t power);
};
extern struct radio_interface Radio;
/** @} */

#endif /*SCATTERWEB_NET_H_*/
