/**
* @file simple_api.c
*
* @brief Methods that implement the CC2530ZNP Simple Application Programming Interface (Simple API).
* 
* This Simple API is an easy-to-use interface to configure, send, and receive Zigbee data.
* This file acts as an interface between the user's application and the ZNP physical interface, either SPI or UART.
* Refer to Interface Specification for more information.
*
* @see http://processors.wiki.ti.com/index.php/Tutorial_on_the_Examples and http://e2e.ti.com/support/low_power_rf/default.aspx
*
* $Rev: 589 $
* $Author: dsmith, Morten & Suyash$
* $Date: 2010-06-11 15:32:36 -0700 (Fri, 11 Jun 2010) $
*
* YOU ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE PROVIDED “AS IS” WITHOUT WARRANTY 
* OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, 
* TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL TEXAS INSTRUMENTS 
* OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, 
* BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
* INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, 
* LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY 
* CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
*/

#include "../znp/simple_api.h"
#include "../znp/znp_interface.h"
#include "../znp/application_configuration.h"
#include "../HAL/hal.h"
#include <string.h> /*for memcpy()*/
#include "../znp/znp_interface_spi.h"


/* IAR EW C Compiler */
#ifdef __IAR_SYSTEMS_ICC__ 
uint16 ZNPEvtFlags;
uint16 ZNPIndFlags;
#else
uint16 ZNPEvtFlags = 0x0000;
uint16 ZNPIndFlags = 0x0000;
#endif

extern unsigned char znpBuf[100];

/** Incremented for each SEND_DATA_REQUEST, wraps around to 0. */
unsigned char sequenceNumber = 0;

extern signed int znpResult;                    

/** Configures the ZNP for our application.
Sets which endpoint, profileId, etc. we're using as well as binding information.
@note Simple API can only register one application.
@param the applicationConfiguration to register.
@pre ZNP was initialized and ZCD_NV_LOGICAL_TYPE has been set (either COORDINATOR/ROUTER/END_DEVICE).
@post can now use sapiStartApplication()
@post znpResult contains the error code, or ZNP_SUCCESS if success.
@see applicationConfiguration
*/
void sapiRegisterApplication(struct applicationConfiguration ac)
{
#ifdef __IAR_SYSTEMS_ICC__
#else
	int i = 0; 
#endif 	

    if (ac.endPoint == 0)
    {
        znpResult = -1;
        return;
    }
    if ((ac.numberOfBindingInputClusters > MAX_BINDING_CLUSTERS) || (ac.numberOfBindingOutputClusters > MAX_BINDING_CLUSTERS))
    {
        znpResult = -2;
        return;
    }
    
    unsigned char bufferIndex;
    
    /*znpBuf[0] (length) will be set later*/
    znpBuf[1] = MSB(ZB_APP_REGISTER_REQUEST);
    znpBuf[2] = LSB(ZB_APP_REGISTER_REQUEST); 
    
    znpBuf[3] = ac.endPoint;
    znpBuf[4] = LSB(ac.profileId); 
    znpBuf[5] = MSB(ac.profileId);
    znpBuf[6] = LSB(ac.deviceId);
    znpBuf[7] = MSB(ac.deviceId);
    znpBuf[8] = ac.deviceVersion;
    znpBuf[9] = 0x00;                     /*unused, set to zero*/
    znpBuf[10] = ac.numberOfBindingInputClusters;
    bufferIndex = 11;

#ifdef __IAR_SYSTEMS_ICC__     
    for(int i = 0; i < ac.numberOfBindingInputClusters; i++)
#else 
 	for(i = 0; i < ac.numberOfBindingInputClusters; i++)
#endif
    {
        znpBuf[bufferIndex++] = LSB(ac.bindingInputClusters[i]);
        znpBuf[bufferIndex++] = MSB(ac.bindingInputClusters[i]);
    }
    znpBuf[bufferIndex++] = ac.numberOfBindingOutputClusters;

#ifdef __IAR_SYSTEMS_ICC__  
    for(int i = 0; i<ac.numberOfBindingOutputClusters; i++)
#else 
	for(i = 0; i<ac.numberOfBindingOutputClusters; i++)
#endif
    {
        znpBuf[bufferIndex++] = LSB(ac.bindingOutputClusters[i]);
        znpBuf[bufferIndex++] = MSB(ac.bindingOutputClusters[i]);
    }
    znpBuf[0] = bufferIndex;
    znpResult = sendMessage(); 
}


/*sapiRegisterGenericApplication() Not used in Sensor Monitor Demo Application */
#define ZB_APP_REGISTER_REQUEST_PAYLOAD_LEN 9
/** Configures the ZNP for a "generic" application: one endpoint, no binding or fancy stuff. 
Sets which endpoint, profileId, etc. we're using as well as binding information
@post znpResult contains the error code, or ZNP_SUCCESS if success.
@see sapiRegisterApplication()
*/
void sapiRegisterGenericApplication()
{
    znpBuf[0] = ZB_APP_REGISTER_REQUEST_PAYLOAD_LEN;
    znpBuf[1] = MSB(ZB_APP_REGISTER_REQUEST);
    znpBuf[2] = LSB(ZB_APP_REGISTER_REQUEST); 
    
    znpBuf[3] = DEFAULT_ENDPOINT;
    znpBuf[4] = LSB(DEFAULT_PROFILE_ID);
    znpBuf[5] = MSB(DEFAULT_PROFILE_ID);
    znpBuf[6] = LSB(DEVICE_ID);
    znpBuf[7] = MSB(DEVICE_ID);
    znpBuf[8] = DEVICE_VERSION;
    znpBuf[9] = 0; /*unused*/
    znpBuf[10] = 0; /*number of binding input clusters*/
    znpBuf[11] = 0; /*number of binding output clusters*/
    znpResult = sendMessage();
}

#define ZB_START_CONFIRM_TIMEOUT 2
#define ZB_APP_START_REQUEST_PAYLOAD_LEN 0
/** Starts the Zigbee stack in the ZNP using the settings from a previous sapiRegisterApplication().
After this start request process completes, the device is ready to send, receive, and route network traffic.
@note On a coordinator in a trivial test setup, it takes approximately 300mSec between 
START_REQUEST and receiving START_REQUEST_SRSP and then another 200-1000mSec from when we receive 
START_REQUEST_SRSP to when we receive START_CONFIRM. 
@note Set START_CONFIRM_TIMEOUT based on size of your network.
@pre sapiRegisterApplication() was a success.
@post znpResult contains the error code, or ZNP_SUCCESS if success.
@note we will receive a START_CONFIRM if everything was ok. 
Should always receive a start confirm for a coordinator. 
Will only receive a start confirm on a router if we could join a zigbee network.
*/
void sapiStartApplication()
{
    znpBuf[0] = ZB_APP_START_REQUEST_PAYLOAD_LEN;
    znpBuf[1] = MSB(ZB_APP_START_REQUEST);
    znpBuf[2] = LSB(ZB_APP_START_REQUEST);     
    
    znpResult = sendMessage();  
    if (znpResult != 0) 
        return;
}

#define ZB_PERMIT_JOINING_REQUEST_PAYLOAD_LEN 3
/** Sets the Joining Permissions for this device or other devices. 
By default, after a setStartupOptions(CLEAR_CONFIG), joining is set to allow all devices, indefinitely.
@param destination which short address to set joining permissions for, or ALL_ROUTERS_AND_COORDINATORS 
to set joining permissions for all. 
@param timeout how long in seconds to allow permissions, or if set to NO_TIMEOUT then joining will be on indefinitely.
@post znpResult contains the error code, or ZNP_SUCCESS if success.
*/
void setJoiningPermissions(unsigned int destination, unsigned char timeout)
{
    znpBuf[0] = ZB_PERMIT_JOINING_REQUEST_PAYLOAD_LEN;
    znpBuf[1] = MSB(ZB_PERMIT_JOINING_REQUEST);
    znpBuf[2] = LSB(ZB_PERMIT_JOINING_REQUEST);   
    
    znpBuf[3] = LSB(destination);
    znpBuf[4] = MSB(destination);
    znpBuf[5] = timeout;
    znpResult = sendMessage();   
}


#define ZB_SEND_DATA_REQUEST_PAYLOAD_LEN 8
/** Sends a message to another device over the Zigbee network.
@note On a coordinator in a trivial test setup, it takes approximately 10mSec from sending 
ZB_SEND_DATA_REQUEST to when we receive ZB_SEND_DATA_CONFIRM.
@note   <code>handle</code> is an optional user-definable reference number to match SEND_DATA_CONFIRM messages 
with the SEND_DATA_REQUEST message. This can be used to determine which SEND_DATA_REQUEST generated an error.
@note   The ZNP will automatically require an ACK from the next device on the route when sending data. 
To require an ACK from the final destination, change MAC_ACK to APS_ACK. The downside is that this increases network traffic.
@note   The <code>radius</code> is the maximum number of hops that this packet can travel through before it will be dropped. 
Should be set to the maximum number of hops expected in the network.
@param  destinationShortAddress the short address of the destination, or ALL_DEVICES or ALL_ROUTERS_AND_COORDINATORS to broadcast the message.
@param  clusterId which cluster this message is for. User definable. Zigbee supports up to 2^16 clusters. 
A cluster is typically a particular command, e.g. "turn on lights" or "get temperature". 
If using a predefined Zigbee Alliance Application Profile then this cluster will follow the Zigbee Cluster Library.
@param  data is the data to send.
@param  dataLength is how many bytes of data to send. Must be less than MAXIMUM_PAYLOAD_LENGTH.
@pre    sapiStartApplication() was a success, START_CONFIRM received without any errors.
@pre    there is another device on the network with short address of <code>destinationShortAddress</code> 
and that device has successfully started its application using sapiStartApplication().
@post   srsp will contain a ZB_SEND_DATA_REQUEST_SRSP. We will receive a ZB_SEND_DATA_REQUEST_SRSP regardless of whether the message was successfully sent or not.
@post   we will receive a ZB_SEND_DATA_CONFIRM if the message was successfully sent which is handled in the callback function 
*/
void sendData(unsigned int destinationShortAddress, unsigned int clusterId, unsigned char* data, unsigned char dataLength)   
{
    if (dataLength > MAXIMUM_PAYLOAD_LENGTH)
    {
        znpResult = -1;
        return;
    }
    
    znpBuf[0] = ZB_SEND_DATA_REQUEST_PAYLOAD_LEN + dataLength;
    znpBuf[1] = MSB(ZB_SEND_DATA_REQUEST);
    znpBuf[2] = LSB(ZB_SEND_DATA_REQUEST);  
    
    znpBuf[3] = LSB(destinationShortAddress); 
    znpBuf[4] = MSB(destinationShortAddress); 
    znpBuf[5] = LSB(clusterId);   /*in the function scredata() clusterID is commandID for binding*/
    znpBuf[6] = MSB(clusterId);   /*in the function scredata() clusterID is commandID for binding*/
    znpBuf[7] = sequenceNumber++; /*handle aka Transaction Sequence Number*/
    if(APP_DATA_CNF == TRUE)
    {
         znpBuf[8] = AF_APS_ACK; /*If APS_ACK is required*/                 
    }
    else
    {
         znpBuf[8] = MAC_ACK;     /*IF only MAC acknowledgement is required*/             
    }
    znpBuf[9] = DEFAULT_RADIUS;
    znpBuf[10] = dataLength;  
    memcpy(znpBuf+ZB_SEND_DATA_REQUEST_PAYLOAD_LEN+3, data, dataLength);
    znpResult = sendMessage();
  
 }

#define ZB_ALLOW_BIND_PAYLOAD_LEN 1
/** This command puts the device into the Allow Binding Mode for a given period of time. 
@param Timeout – 1 byte – The number of seconds to remain in the allow binding mode. Valid values
range from 1 through 65. If 0, the Allow Bind mode will be set false without timeout. If greater than
64, the Allow Bind mode will be true indefinitely.
@post znpResult contains the error code, or ZNP_SUCCESS if success.
*/
void setallowbind(unsigned char timeout)
{
    /*send the allow bind msg*/
    znpBuf[0] = ZB_ALLOW_BIND_PAYLOAD_LEN ;
    znpBuf[1] = MSB(ZB_ALLOW_BIND);
    znpBuf[2] = LSB(ZB_ALLOW_BIND);   
    znpBuf[3] = timeout;
    znpResult = sendMessage();   
    if(znpResult != 0)
     {
       /*action when message was not sent properly*/
     }
}

#define ZB_BIND_DEVICE                  0x2601
#define ZB_BIND_DEVICE_PAYLOAD_LEN 11
/** This function creates or delete a ‘binding’ to another device on the network, based on the parameter create being 
TRU or FALSE, Once bound, an application can send messages to a device by referencing the commandId for the
binding. This command can also be issued with a NULL destination address (set to all zeros). In
that case, a binding will be established with another device that is in the Allow Bind mode
@param 
create – 1 byte – TRUE to create a binding, FALSE to remove a binding.
commandId – 2 bytes – The identifier of the binding.
*pDestination – Points to the 64-bit IEEE address of the device to bind to. Points to NULL if
the destination address is unknown and instead the destination device is set to Allow Bind mode.
@post znpResult contains the error code, or ZNP_SUCCESS if success.
*/
void binddevice(uint8 create, uint16 commandId, uint8 *pDestination)
{
    znpBuf[0] = ZB_BIND_DEVICE_PAYLOAD_LEN;
    znpBuf[1] = MSB(ZB_BIND_DEVICE);
    znpBuf[2] = LSB(ZB_BIND_DEVICE);   
    znpBuf[3] = create;
    znpBuf[4] = LSB(commandId);
    znpBuf[5] = MSB(commandId);
    znpBuf[6] = *pDestination;
    znpBuf[7] = *(pDestination+1);
    znpBuf[8] = *(pDestination+2);
    znpBuf[9] = *(pDestination+3);
    znpBuf[10] =*(pDestination+4);
    znpBuf[11] =*(pDestination+5);
    znpBuf[12] =*(pDestination+6);
    znpBuf[13] =*(pDestination+7);
    znpResult = sendMessage();
}

/*CallBack Functions*/
#define Bind_Confirm_Status 5
/*
This function is the callback function when ZB_BIND_CONFIRM is recieved 
from ZNP. This sets the ZNPIndFlags value.
*/
void BindConfirm()
{
    uint16 event;
    event = znpBuf[2]; 
    event += (uint16)(znpBuf[1]);  
  
  int status = znpBuf[Bind_Confirm_Status];
  if (status == ZNP_SUCCESS)
  {
    ZNPIndFlags |= ZNP_BIND_SUCCESS;
    ZNPEvtFlags|= ZNP_BIND_CNF;
  }
  else
  {
    ZNPIndFlags &= ~ZNP_BIND_SUCCESS;
  }
}

/*
This function is the callback function when ZB_ALLOW_BIND_CONFIRM is recieved 
from ZNP. Currently No action is taken. Implementation Left on Developer.
*/
void AllowBindConfirm(uint16 source)
{
    (void)source;
}


/*
This function is the callback function when ZB_SEND_DATA_CONFIRM is recieved 
from ZNP. This sets the ZNPIndFlags value.
*/
void SendDataConfirm(uint8 handle, uint8 status)
{
  (void)handle;

  if (status == ZNP_SUCCESS)
  {
     ZNPIndFlags |= ZNP_SEND_SUCCESS;
  }
  else
  {
     ZNPIndFlags &= ~ZNP_SEND_SUCCESS;
  }
}

/*
This function is the callback function when ZB_FIND_DEVICE_CONFIRM is recieved 
from ZNP. This sets the ZNPIndFlags value.
*/
void FindDeviceConfirm(uint8 searchType, uint8 searchKey, uint8 result)
{
  (void)searchType;  /* Currently only supports IEEE Addr Search.*/
  (void)searchKey;
  (void)result;
}

/*
The zb_ReceiveDataIndication callback function is called asynchronously 
by the ZigBee stack to notify the application when data is received from 
a peer device.
*/
void ReceiveDataIndication(uint16 source, uint16 command, uint16 len)
{
  uint8 cnt;

  (void)source;
  (void)command;
  if (len > ZNP_BUF_LEN)  /* If SAPI sent more than 255 bytes, we cannot currently handle.*/
  {
    ZNPDataLen = ZNP_BUF_LEN;
  }
  else
  {
    ZNPDataLen = len;
  }
  for (cnt = 0; cnt < ZNPDataLen; cnt++)
  {
    ZNPDataBuf[cnt] = znpBuf[9+cnt]; /*data starts at 9th position*/
  }
}

