/*
*  Microchip ZigBee2006 Residential Stack
*
*  Demo Reduced Function Device
*
********************************************************************/

//******************************************************************************
// Header Files
//******************************************************************************

// Include the main ZigBee header file.
#include "zAPL.h"
#ifdef I_SUPPORT_SECURITY
#include "zSecurity.h"
#endif

// If you are going to send data to a terminal, include this file.
#include "Compiler.h"
#include "console.h"

#include "TCN75A.h"
#include "PIR.h"
#include "BSP.h"

//******************************************************************************
// Application Variables
//******************************************************************************

NETWORK_DESCRIPTOR *currentNetworkDescriptor;
ZIGBEE_PRIMITIVE currentPrimitive;
NETWORK_DESCRIPTOR *NetworkDescriptor;
BYTE orphanTries;
#ifdef I_SUPPORT_SECURITY
extern KEY_VAL KeyVal;
#ifdef USE_EXTERNAL_NVM
extern WORD trustCenterLongAddr;
extern NETWORK_KEY_INFO plainSecurityKey[2];
#else
extern ROM LONG_ADDR trustCenterLongAddr;
#endif
#endif
// enums to execute menu options.
SHORT_ADDR discoveredAddress;
BYTE routeDiscovery;

WORD_VAL MSGPacketCount;

//******************************************************************************
// Constants
//******************************************************************************
//#define PB_LEFT_SWITCH            	PORTBbits.RB5
//#define PB_RIGHT_SWITCH             PORTBbits.RB4
//#define GROUP_INDICATION        LATAbits.LATA0
//#define MESSAGE_INDICATION      LATAbits.LATA1

#define DEBOUNCE_TIME 0x00008FF

BYTE AllowJoin = 1;

//******************************************************************************
// Function Prototypes
//******************************************************************************
void HardwareInit(void);
void ProcessNONZigBeeTasks(void);
void ProcessZigBeePrimitives(void);

extern void RemoveAllGroups(void);
extern void RemoveAllBindings(SHORT_ADDR);

extern BYTE APSCounter;
extern NWK_STATUS nwkStatus;
extern BYTE SendingEDBRequest;
extern BYTE macLongAddrByte[8];

BYTE loopCount, byteMSB, byteLSB, i;
TICK transmitInterval, currentTime;

BOOL gettingAcks = FALSE;
BOOL toggle = TRUE;
BYTE temp2;

static TICK startPollingTime;

BOOL group_state_ID5 = TRUE;
BOOL group_state_ID4 = TRUE;
BYTE GROUP_ID4 = 0x04;

static BOOL btn1Lock, btn2Lock, pirLock;
static WORD pirInterval;

static union {

	struct {
		BYTE bBroadcastSwitchToggled : 1;
		BYTE bLightSwitchToggled : 1;
		BYTE bTryingToBind : 1;
		BYTE bIsBound : 1;
		BYTE bDestinationAddressKnown : 1;
		BYTE bBindSwitchToggled : 1;
	} bits;
	BYTE Val;
} myStatusFlags;

/* determines whether both the PIC and radio sleep, or just simulated in 
* order to debug and use the menus with the uart
*/
#define BOTH_MICRO_TRANSV_SLEEP

//******************************************************************************
//******************************************************************************
//******************************************************************************

void main(void) {
	/* Initialize both Hardware and Stack */
	CLRWDT();
	//    ENABLE_WDT();

	currentPrimitive = NO_PRIMITIVE;
	NetworkDescriptor = NULL;
	orphanTries = 3;

	// If you are going to send data to a terminal, initialize the UART.
	ConsoleInit();

	// Initialize the hardware - must be done before initializing ZigBee.
	HardwareInit();

	// Initialize the ZigBee Stack.
	ZigBeeInit();

	ConsolePutROMString((ROM char *) "\r\n\r\n\r\n********************************");
	ConsolePutROMString((ROM char *) "\r\nMOD-ZIGBEE-PIR - v2.0-2.6.0a\r\n\r\n");

	startPollingTime.Val = 0x00;

	// *************************************************************************
	// Perform any other initialization here
	// *************************************************************************
	NWKClearNeighborTable();
#if defined(I_SUPPORT_BINDING)
	ClearBindingTable();
#endif
	/* Clear the Group Table */
	RemoveAllGroups();

#if defined(I_SUPPORT_BINDING)
	RemoveAllBindings(macPIB.macShortAddress);
#endif

	discoveredAddress.Val = 0x0000;
	routeDiscovery = 0;

	// Enable interrupts to get everything going.
	RCONbits.IPEN = 1;
	INTCONbits.GIEH = 1;

	/* Initialize network status bits */
	nwkStatus.flags.Val = 0x00;
	ZigBeeStatus.flags.bits.bRadioIsSleeping = 0;

	btn1Lock = FALSE;
	pirLock = FALSE;
	pirInterval = 0;

	while (1) {
		CLRWDT();

		/* Determine which is the next ZigBee Primitive operate on*/
		ZigBeeTasks(&currentPrimitive);

		/* Process the next ZigBee Primitive */
		ProcessZigBeePrimitives();

		/* do any non ZigBee related tasks and then go back to ZigBee tasks */
		ProcessNONZigBeeTasks();
	}
}

void ProcessZigBeePrimitives(void) {
	switch (currentPrimitive) {
		case NLME_NETWORK_DISCOVERY_confirm:
			currentPrimitive = NO_PRIMITIVE;
			if (!params.NLME_NETWORK_DISCOVERY_confirm.Status) {
				if (!params.NLME_NETWORK_DISCOVERY_confirm.NetworkCount) {
					ConsolePutROMString((ROM char *) "No networks found.  Trying again...\r\n");
				} else {
					// Save the descriptor list pointer so we can destroy it later.
					NetworkDescriptor = params.NLME_NETWORK_DISCOVERY_confirm.NetworkDescriptor;

					// Select a network to try to join.  We're not going to be picky right now...
					currentNetworkDescriptor = NetworkDescriptor;

SubmitJoinRequest:
					params.NLME_JOIN_request.PANId = currentNetworkDescriptor->PanID;
					params.NLME_JOIN_request.JoinAsRouter = FALSE;
					params.NLME_JOIN_request.RejoinNetwork = FALSE;
					params.NLME_JOIN_request.PowerSource = NOT_MAINS_POWERED;
					params.NLME_JOIN_request.RxOnWhenIdle = FALSE;
					params.NLME_JOIN_request.MACSecurity = FALSE;
					currentPrimitive = NLME_JOIN_request;

					ConsolePutROMString((ROM char *) "Network(s) found. Trying to join ");
					PrintChar(params.NLME_JOIN_request.PANId.byte.MSB);
					PrintChar(params.NLME_JOIN_request.PANId.byte.LSB);
					ConsolePutROMString((ROM char *) ".\r\n");
				}
			} else {
				PrintChar(params.NLME_NETWORK_DISCOVERY_confirm.Status);
				ConsolePutROMString((ROM char *) " Error finding network.  Trying again...\r\n");
			}
			break;

		case NLME_JOIN_confirm:
			if (!params.NLME_JOIN_confirm.Status) {
				ConsolePutROMString((ROM char *) "Join successful!\r\n");

				// Free the network descriptor list, if it exists. If we joined as an orphan, it will be NULL.
				while (NetworkDescriptor) {
					currentNetworkDescriptor = NetworkDescriptor->next;
					nfree(NetworkDescriptor);
					NetworkDescriptor = currentNetworkDescriptor;
				}

				/* package and send an end device announcement */
				{
					LONG_ADDR myLongAddress;
					GetMACAddress(&myLongAddress);

					ConsolePutROMString((ROM char *) "Announcing I am on the network\r\n");

					ZigBeeBlockTx();
					TxBuffer[TxData++] = APSCounter++;

					TxBuffer[TxData++] = macPIB.macShortAddress.v[0];
					TxBuffer[TxData++] = macPIB.macShortAddress.v[1];

					TxBuffer[TxData++] = myLongAddress.v[0];
					TxBuffer[TxData++] = myLongAddress.v[1];
					TxBuffer[TxData++] = myLongAddress.v[2];
					TxBuffer[TxData++] = myLongAddress.v[3];
					TxBuffer[TxData++] = myLongAddress.v[4];
					TxBuffer[TxData++] = myLongAddress.v[5];
					TxBuffer[TxData++] = myLongAddress.v[6];
					TxBuffer[TxData++] = myLongAddress.v[7];

					TxBuffer[TxData++] = MY_CAPABILITY_INFO;

					params.APSDE_DATA_request.DstAddrMode = APS_ADDRESS_16_BIT;
					params.APSDE_DATA_request.DstEndpoint = EP_ZDO;
					params.APSDE_DATA_request.DstAddress.ShortAddr.Val = 0xFFFF; //destinationAddress;

					params.APSDE_DATA_request.ProfileId.Val = ZDO_PROFILE_ID;
					params.APSDE_DATA_request.RadiusCounter = DEFAULT_RADIUS;
					params.APSDE_DATA_request.DiscoverRoute = ROUTE_DISCOVERY_SUPPRESS;
					params.APSDE_DATA_request.TxOptions.Val = 0;
					params.APSDE_DATA_request.SrcEndpoint = EP_ZDO;
					params.APSDE_DATA_request.ClusterId.Val = END_DEVICE_annce;

					/* Set LEDs to the joined the network state */
					BSP_SetLED(LED1, LED_OFF);
					BSP_SetLED(LED2, LED_OFF);

					currentPrimitive = APSDE_DATA_request;
				}

			} else {
				currentPrimitive = NO_PRIMITIVE;
				PrintChar(params.NLME_JOIN_confirm.Status);

				// If we were trying as an orphan, see if we have some more orphan attempts.
				if (ZigBeeStatus.flags.bits.bTryOrphanJoin) {
					// If we tried to join as an orphan, we do not have NetworkDescriptor, so we do
					// not have to free it.

					ConsolePutROMString((ROM char *) " Could not join as orphan. ");
					orphanTries--;
					if (orphanTries == 0) {
						ConsolePutROMString((ROM char *) "Must try as new node...\r\n");
						ZigBeeStatus.flags.bits.bTryOrphanJoin = 0;
					} else {
						ConsolePutROMString((ROM char *) "Trying again...\r\n");
					}
				} else {
					ConsolePutROMString((ROM char *) " Could not join selected network. ");
					currentNetworkDescriptor = currentNetworkDescriptor->next;
					if (currentNetworkDescriptor) {
						ConsolePutROMString((ROM char *) "Trying next discovered network...\r\n");
						goto SubmitJoinRequest;
					} else {
						// We ran out of descriptors.  Free the network descriptor list, and fall
						// through to try discovery again.
						ConsolePutROMString((ROM char *) "Cleaning up and retrying discovery...\r\n");
						while (NetworkDescriptor) {
							currentNetworkDescriptor = NetworkDescriptor->next;
							nfree(NetworkDescriptor);
							NetworkDescriptor = currentNetworkDescriptor;
						}
					}
				}
			}
			break;

		case NLME_LEAVE_indication:
		{
#if defined(__C30__)
			LONG_ADDR myLongAddr;

			GetMACAddress(&myLongAddr);
			if (!memcmppgm2ram(&params.NLME_LEAVE_indication.DeviceAddress, &myLongAddr, 8))
#else
			if (!memcmppgm2ram(&params.NLME_LEAVE_indication.DeviceAddress, (ROM void *) &macLongAddr, 8))
#endif
			{
				ConsolePutROMString((ROM char *) "We have left the network.\r\n");
			} else {
				ConsolePutROMString((ROM char *) "Another node has left the network.\r\n");
			}
		}
			currentPrimitive = NO_PRIMITIVE;
			break;

		case NLME_RESET_confirm:
			ConsolePutROMString((ROM char *) "ZigBee Stack has been reset.\r\n");
			currentPrimitive = NO_PRIMITIVE;
			break;

		case NLME_START_ROUTER_confirm:
			if (!params.NLME_START_ROUTER_confirm.Status) {
				ConsolePutROMString((ROM char *) "Router Started!\r\n");
			} else {
				PrintChar(params.NLME_JOIN_confirm.Status);
				ConsolePutROMString((ROM char *) " Router start unsuccessful. We cannot route frames.\r\n");
			}

			// We are now ready to do ZigBee related tasks.
			currentPrimitive = NO_PRIMITIVE;

			break;

		case APSDE_DATA_indication:
		{
			WORD_VAL attributeId;
			BYTE command;
			BYTE data;

			BYTE frameHeader;
			BYTE sequenceNumber;
			BYTE transaction;
			BYTE transByte;

			BYTE frameHeaderIndex = TxData;
			currentPrimitive = NO_PRIMITIVE;

			switch (params.APSDE_DATA_indication.DstEndpoint) {
				case EP_ZDO:
#define dataLength command

					frameHeader = 1;
					for (transaction = 0; transaction < frameHeader; transaction++) {
						sequenceNumber = APLGet();
						transByte = 1; // Account for status byte

						switch (params.APSDE_DATA_indication.ClusterId.Val) {

								// ********************************************************
								// Put a case here to handle each ZDO response that we requested.
								// ********************************************************

							case NWK_ADDR_rsp:
								if (APLGet() == SUCCESS) {
									ConsolePutROMString((ROM char *) "  Receiving NWK_ADDR_rsp.\r\n");

									// Skip over the IEEE address of the responder.
									for (data = 0; data < 8; data++) {
										APLGet();
										transByte++;
									}
									discoveredAddress.byte.LSB = APLGet();
									discoveredAddress.byte.MSB = APLGet();
									transByte += 2;
								}
								break;


#ifdef SUPPORT_END_DEVICE_BINDING
							case END_DEVICE_BIND_rsp:
								switch (APLGet()) {
									case SUCCESS:
										ConsolePutROMString((ROM char *) "End device bind/unbind successful!\r\n");

										break;
									case ZDO_NOT_SUPPORTED:
										ConsolePutROMString((ROM char *) "End device bind/unbind not supported.\r\n");
										break;
									case END_DEVICE_BIND_TIMEOUT:
										ConsolePutROMString((ROM char *) "End device bind/unbind time out.\r\n");
										break;
									case END_DEVICE_BIND_NO_MATCH:
										ConsolePutROMString((ROM char *) "End device bind/unbind failed - no match.\r\n");
										break;
									default:
										ConsolePutROMString((ROM char *) "End device bind/unbind invalid response.\r\n");
										break;
								}

								/* Go back to slower poll rate */
								SendingEDBRequest = 0;
								currentPrimitive = NO_PRIMITIVE;
								break;
#endif     


							default:
								printf(" Got message on EndPoint zero ..");
								break;
						}


					}
#undef dataLength
					break;

					// ************************************************************************
					// Place a case for each user defined endpoint.
					// ************************************************************************

				default:
					break;
			}
			APLDiscardRx();
		}
			break;

		case APSDE_DATA_confirm:
			if (params.APSDE_DATA_confirm.Status) {
				ConsolePutROMString((ROM char *) "Error ");
				PrintChar(params.APSDE_DATA_confirm.Status);
				ConsolePutROMString((ROM char *) " sending message.\r\n");
			} else {
				ConsolePutROMString((ROM char *) " Message sent successfully.\r\n");
			}
			currentPrimitive = NO_PRIMITIVE;
			break;

		case APSME_ADD_GROUP_confirm:
		case APSME_REMOVE_GROUP_confirm:
		case APSME_REMOVE_ALL_GROUPS_confirm:
			//ConsolePutROMString( (ROM char *)" Performed Group Operation.\r\n" );
			currentPrimitive = NO_PRIMITIVE;
			break;

		case NO_PRIMITIVE:
			if (!ZigBeeStatus.flags.bits.bNetworkJoined) {
				BSP_SetLED(LED1, LED_ON);

				if (!ZigBeeStatus.flags.bits.bTryingToJoinNetwork) {
					if (ZigBeeStatus.flags.bits.bTryOrphanJoin) {
						ConsolePutROMString((ROM char *) "Trying to join network as an orphan...\r\n");
						params.NLME_JOIN_request.ScanDuration = 8;
						params.NLME_JOIN_request.ScanChannels.Val = ALLOWED_CHANNELS;
						params.NLME_JOIN_request.JoinAsRouter = FALSE;
						params.NLME_JOIN_request.RejoinNetwork = TRUE;
						params.NLME_JOIN_request.PowerSource = NOT_MAINS_POWERED;
						params.NLME_JOIN_request.RxOnWhenIdle = FALSE;
						params.NLME_JOIN_request.MACSecurity = FALSE;
						currentPrimitive = NLME_JOIN_request;
					} else {
						ConsolePutROMString((ROM char *) "Trying to join network as a new device...\r\n");
						params.NLME_NETWORK_DISCOVERY_request.ScanDuration = 8;
						params.NLME_NETWORK_DISCOVERY_request.ScanChannels.Val = ALLOWED_CHANNELS;
						currentPrimitive = NLME_NETWORK_DISCOVERY_request;
					}
				}
			} else {
				// Process the pushbutton interrupts
				if (BSP_GetButton(BUTTON1)) {
					if (!btn1Lock) {
						btn1Lock = TRUE;

						BSP_SetLED(LED2, LED_ON);

						/* Send group message to all the devices */
						ZigBeeBlockTx();
						TxBuffer[TxData++] = 0x0A; // this is the data

						// TODO: Send the current temperature
						{
							WORD_VAL tempr;

							TCN75A_StartSample();
							while (TCN75A_StartSample() != 0);

							tempr.Val = TCN75A_ReadTempr();

							TxBuffer[TxData++] = tempr.byte.MSB;
							TxBuffer[TxData++] = tempr.byte.LSB;
						}

						/* Use group addressing mode to send request */
						params.APSDE_DATA_request.DstAddrMode = APS_ADDRESS_GROUP;

						/* GroupID MSB is zero in this example  */
						params.APSDE_DATA_request.DstAddress.ShortAddr.v[1] = 0x00;
						params.APSDE_DATA_request.DstAddress.ShortAddr.v[0] = GROUP_ID4;

						params.APSDE_DATA_request.SrcEndpoint = GROUP_ID4;

						params.APSDE_DATA_request.RadiusCounter = DEFAULT_RADIUS;
						params.APSDE_DATA_request.DiscoverRoute = ROUTE_DISCOVERY_SUPPRESS;
#ifdef I_SUPPORT_SECURITY
						params.APSDE_DATA_request.TxOptions.Val = 1;
#else
						params.APSDE_DATA_request.TxOptions.Val = 0;
#endif

						/* no acknowledgement since this is a broadcast request */
						params.APSDE_DATA_request.TxOptions.bits.acknowledged = 0;
						params.APSDE_DATA_request.ProfileId.Val = 0x7f01;
						params.APSDE_DATA_request.ClusterId.Val = BUFFER_TEST_REQUEST_CLUSTER;
						currentPrimitive = APSDE_DATA_request;
					}
				} else {
					//BSP_SetLED(LED2, LED_OFF);
					btn1Lock = FALSE;
				}

				if (BSP_GetButton(BUTTON2)) {
					if (!btn2Lock) {
						btn2Lock = TRUE;

						BSP_SetLED(LED2, LED_ON);

						/* Send group message to all the devices */
						ZigBeeBlockTx();
						TxBuffer[TxData++] = 0x0B; // this is the data

						// TODO: Send device name
						{
							char i;
							for(i = 0; i < DEVICE_FRIENDLY_NAME_SIZE; i++)
							TxBuffer[TxData++] = deviceFriendlyName[i];
						}

						/* Use group addressing mode to send request */
						params.APSDE_DATA_request.DstAddrMode = APS_ADDRESS_GROUP;

						/* GroupID MSB is zero in this example  */
						params.APSDE_DATA_request.DstAddress.ShortAddr.v[1] = 0x00;
						params.APSDE_DATA_request.DstAddress.ShortAddr.v[0] = GROUP_ID4;

						params.APSDE_DATA_request.SrcEndpoint = GROUP_ID4;

						params.APSDE_DATA_request.RadiusCounter = DEFAULT_RADIUS;
						params.APSDE_DATA_request.DiscoverRoute = ROUTE_DISCOVERY_SUPPRESS;
#ifdef I_SUPPORT_SECURITY
						params.APSDE_DATA_request.TxOptions.Val = 1;
#else
						params.APSDE_DATA_request.TxOptions.Val = 0;
#endif

						/* no acknowledgement since this is a broadcast request */
						params.APSDE_DATA_request.TxOptions.bits.acknowledged = 0;
						params.APSDE_DATA_request.ProfileId.Val = 0x7f01;
						params.APSDE_DATA_request.ClusterId.Val = BUFFER_TEST_REQUEST_CLUSTER;
						currentPrimitive = APSDE_DATA_request;
					}
				} else {
					//BSP_SetLED(LED2, LED_OFF);
					btn2Lock = FALSE;
				}

				if (PIR_GetTrigger()) {
					if(!pirLock) {
						pirLock = TRUE;
						pirInterval = 0;
						
						BSP_SetLED(LED2, LED_ON);
						/* Send group message to all the devices */
						ZigBeeBlockTx();
						TxBuffer[TxData++] = 0x0C; // this is the data

						/* Use group addressing mode to send request */
						params.APSDE_DATA_request.DstAddrMode = APS_ADDRESS_GROUP;

						/* GroupID MSB is zero in this example  */
						params.APSDE_DATA_request.DstAddress.ShortAddr.v[1] = 0x00;
						params.APSDE_DATA_request.DstAddress.ShortAddr.v[0] = GROUP_ID4;

						params.APSDE_DATA_request.SrcEndpoint = GROUP_ID4;

						params.APSDE_DATA_request.RadiusCounter = DEFAULT_RADIUS;
						params.APSDE_DATA_request.DiscoverRoute = ROUTE_DISCOVERY_SUPPRESS;
#ifdef I_SUPPORT_SECURITY
						params.APSDE_DATA_request.TxOptions.Val = 1;
#else
						params.APSDE_DATA_request.TxOptions.Val = 0;
#endif

						/* no acknowledgement since this is a broadcast request */
						params.APSDE_DATA_request.TxOptions.bits.acknowledged = 0;
						params.APSDE_DATA_request.ProfileId.Val = 0x7f01;
						params.APSDE_DATA_request.ClusterId.Val = BUFFER_TEST_REQUEST_CLUSTER;
						currentPrimitive = APSDE_DATA_request;
					}
				} else {
					//BSP_SetLED(LED2, LED_OFF);
					pirLock = FALSE;
				}
			}
			/* Process when there are no primitives */
			if (currentPrimitive == NO_PRIMITIVE) {
				if (!ZigBeeStatus.flags.bits.bDataRequestComplete) {
					// We have not received all data from our parent.  If we are not waiting
					// for an answer from a data request, send a data request.
					if (!ZigBeeStatus.flags.bits.bRequestingData) {
						if (ZigBeeReady()) {
							// Our parent still may have data for us.
							params.NLME_SYNC_request.Track = FALSE;
							currentPrimitive = NLME_SYNC_request;
						}
					}
				} else {
					if (!ZigBeeStatus.flags.bits.bHasBackgroundTasks &&
							!BSP_GetButton(BUTTON1) &&
							!BSP_GetButton(BUTTON2) /*&&
							!pirLock*/) {

						BSP_SetLED(LED2, LED_OFF);

						// There is no primitive to execute,  all messages extracted
						// from parent, the stack has no background tasks,
						// and all application-specific processes are complete.  Now
						// go to sleep.  Make sure that the UART is finished, turn off the transceiver,

#if defined(BOTH_MICRO_TRANSV_SLEEP)       
						if (!ZigBeeStatus.flags.bits.bRadioIsSleeping) {
							BOOL skipSleep = FALSE;

							while (!ConsoleIsPutReady());

							// enable interrupts
							INTCONbits.RBIF = 0;
							INTCONbits.RBIE = 1;
							PIR_InterruptEnable(TRUE);

							MRF24J40Sleep();
							BSP_Standby(TRUE);

							// if pir has triggered we have to wait some time
							// to prevent multiple interrupts
							if(pirLock) {
								BYTE oscconVal = OSCCON;
							#define PIR_SLEEP_PERIOD 800
								if(pirInterval < PIR_SLEEP_PERIOD) {									
									OSCCONbits.IRCF = 0; // select the 31kHz source

									while(pirInterval++ < 800) {
										if(!BUTTON1_PORT || !BUTTON2_PORT) {
											skipSleep = TRUE;
											break;
										}
									}
										
									OSCCON = oscconVal;
								}

								PIR_ClearTrigger();
								pirLock = FALSE;
							}

							if(!skipSleep) {
								SLEEP();
								NOP();
							}

							/* Woken up by WDT, so request data from parent */
							MRF24J40Wake();
							params.NLME_SYNC_request.Track = FALSE;
							currentPrimitive = NLME_SYNC_request;

							BSP_Standby(FALSE);
						}
#else
						/* To enable menu system, while still polling use this block */
						/* During End Device Bind speed up Polling, else go back to reqular polling rate */
						{
							TICK currentTime;
							/*	Capture the current time for initiating end device polling	*/

							currentTime = TickGet();
							/*	if the diff between current and the start time is greater than
								polling rate than initiate sync request	*/
							/* Speed things up during EDB */
							if (SendingEDBRequest == 0) {
								if ((TickGetDiff(currentTime, startPollingTime)) > (RFD_POLL_RATE)) {
									params.NLME_SYNC_request.Track = FALSE;
									currentPrimitive = NLME_SYNC_request;

									/* Capture the start polling time for the next cycle	*/
									startPollingTime = TickGet();
								}

							} else {
								/* Speed things up during End Device Binding */
								if ((TickGetDiff(currentTime, startPollingTime)) > (ONE_SECOND) / 4) {
									params.NLME_SYNC_request.Track = FALSE;
									currentPrimitive = NLME_SYNC_request;

									/* Toggle LEDs at Polling rate: faster during Binding */
									BSP_SetLED(LED1, LED_TOGGLE);
									//BSP_SetLED(LED2, LED_TOGGLE);

									/*Capture the start polling time for the next cycle	*/
									startPollingTime = TickGet();
								}


							}


						}
#endif


					}
				}
			}

			/* end  block */

			//}
			break;

		default:
			//ConsolePutROMString( (ROM char *)" Unhandled primitive.\r\n" );
			currentPrimitive = NO_PRIMITIVE;
			break;
	}
}

void ProcessNONZigBeeTasks(void) {
	// *********************************************************************
	// Place any non-ZigBee related processing here.  Be sure that the code
	// will loop back and execute ZigBeeTasks() in a timely manner.
	// *********************************************************************
	BSP_UpdateButtons();
}

/*********************************************************************
* Function:        void HardwareInit(void)
*
* PreCondition:    None
*
* Input:           None
*
* Output:          None
*
*
* Overview:        This function initializes the ZigBee hardware and is required
*                  before any stack operations can be performed
********************************************************************
All port directioning and SPI must be initialized before calling ZigBeeInit().
*******************************************************************************/
void HardwareInit(void) {
	char result = 0;

	// configure INTERNAL oscillator, 16MHz
	OSCCON = 0b01110010;
	Nop();
	Nop();

	// turn off unused pins
#ifndef __DEBUG
	TRISA = 0b00011111; 
	LATA = 0x00;
	TRISB = 0b00111011; // when debugging PGC and PGD should not be configured as outputs
	LATB = 0x00;
	TRISC = 0b00111111;
	LATC = 0x00;
#endif
	

	SPIInit();

	// Start with MRF24J40 disabled and not selected
	PHY_CS = 1;
	PHY_RESETn = 1;

	// Set the directioning for the MRF24J40 pin connections.
	PHY_CS_TRIS = 0;
	PHY_RESETn_TRIS = 0;

	// Initialize the interrupt.
	INTCON2bits.INTEDG0 = 0;

	// Initialize the SPI pins and directions
	LATCbits.LATC3 = 0; // SCK
	LATCbits.LATC5 = 1; // SDO
	TRISCbits.TRISC3 = 0; // SCK
	TRISCbits.TRISC4 = 1; // SDI
	TRISCbits.TRISC5 = 0; // SDO

	SSPSTAT_REG = 0x40;
	SSPCON1_REG = 0x20;

	PHY_WAKE = 1;
	PHY_WAKE_TRIS = 0;

	//-------------------------------------------------------------------------
	// This section is required for application-specific hardware
	// initialization.
	//-------------------------------------------------------------------------
	ANSEL = 0x00;
	ANSELH = 0x02; // only AN9 is analogue input, this is the PIR_OUT

	// Clear the RBIF flag (INTCONbits.RBIF)
	INTCONbits.RBIF = 0;
	// enable interrupt on change
	IOCB |= 0x30;

	// init buttons and leds
	result |= BSP_InitializeThings();

	// initialze the temperature sensor
	result |= TCN75A_Initialize();

	// init the PIR sensor
	result |= PIR_Initialize();
	PIR_PowerEnable(TRUE);

	// check for errors
	while(result) {
		// get here if there was an initialization error(s)
		BSP_SetLED(LED1, LED_TOGGLE);
		BSP_SetLED(LED2, LED_TOGGLE);
		
		{
			DWORD delay = 12000;
			while(delay--);
		}
	}
}

/*******************************************************************************
User Interrupt Handler

The stack uses some interrupts for its internal processing.  Once it is done
checking for its interrupts, the stack calls this function to allow for any
additional interrupt processing.
*******************************************************************************/
void UserInterruptHandler(void) {

	// *************************************************************************
	// Place any application-specific interrupt processing here
	// *************************************************************************

	// Is this an interrupt-on-change interrupt?
	if (INTCONbits.RBIF == 1) {

		// Disable further RBIF until we process it
		//        INTCONbits.RBIE = 0;

		// Clear mis-match condition and reset the interrupt flag
		LATB = PORTB;

		INTCONbits.RBIF = 0;
	}

	PIR_Isr();
}
