📄 connectivitytest.c
字号:
// *******************************************************************
// connectivitytest.c
//
// Connectivity testing application.
//
// This example also provides some simple commands that can be sent to the
// node via the serial port. A brief explanation of the commands is
// provided below:
// ('?') prints the help menu
//
// Copyright 2006 by Ember Corporation. All rights reserved. *80*
// *******************************************************************
#include "connectivitytest.h"
// buffer for organizing data before we send a datagram
int8u buttonZeroPress, buttonOnePress;
int8u operationMode = RX_MODE; // receive, transmit
int8u rxPacketReceived = FALSE; // when a packet is received
EmberNodeId receiverNodeId;
// *******************************************************************
// Begin main application loop
int main(void)
{
EmberStatus status;
EmberResetType reset;
//Initialize the hal
halInit();
// allow interrupts
INTERRUPTS_ON();
reset = halGetResetInfo();
//
//---
// inititialize the serial port
// good to do this before emberInit, that way any errors that occur
// can be printed to the serial port.
if(emberSerialInit(APP_SERIAL, BAUD_115200, PARITY_NONE, 1)
!= EMBER_SUCCESS) {
emberSerialInit(APP_SERIAL, BAUD_19200, PARITY_NONE, 1);
}
#ifdef DEBUG
emberDebugInit(DEBUG_SERIAL);
#endif
// emberInit must be called before other EmberNet stack functions
status = emberInit(reset);
if (status != EMBER_SUCCESS) {
emberSerialGuaranteedPrintf(APP_SERIAL,
"ERROR: emberInit 0x%x\r\n", status);
// Not sure what to do here.
assert(FALSE);
} else {
emberSerialPrintf(APP_SERIAL, "EVENT: emberInit passed\r\n");
}
// TODO save the channel, customize it
forceNetworkJoin(APP_PANID, APP_CHANNEL);
// print a startup message
emberSerialWriteString(APP_SERIAL,
"\r\nINIT: connectivitytest\r\n");
emberSerialPrintf(APP_SERIAL, "\r\n");
emberSerialWaitSend(APP_SERIAL);
emberSerialWaitSend(APP_SERIAL);
// event loop
while(TRUE) {
halResetWatchdog();
applicationTick();
checkButtonEvents();
emberTick();
processSerialInput();
// only blink LEDs if app is joined
if (emberNetworkState() == EMBER_JOINED_NETWORK) {
}
#ifdef DEBUG
emberSerialBufferTick(); // Needed for debug which uses buffered serial
#endif
}
}
// end main application loop
// *******************************************************************
// *******************************************************************
// Begin Ember callback handlers
// Populate as needed
//
// Called when a message has completed transmission --
// status indicates whether the message was successfully
// transmitted or not.
void emberMessageSent(int8u bindingTableIndex,
int8u clusterId,
EmberMessageBuffer message,
EmberStatus status)
{
}
void emberIncomingMessageHandler(EmberIncomingMessageType type,
EmberApsFrame *apsFrame,
EmberMessageBuffer message)
{
// Called with an incoming message
int8u length;
length = emberMessageBufferLength(message);
if (type == EMBER_INCOMING_MULTICAST_LOOPBACK) {
// throw it out if it came from us
return;
}
// ********************************************
// handle the incoming message
// ********************************************
switch (apsFrame->clusterId) {
case TEST_PACKET_CLUSTER_ID:
// Received packet
rxPacketReceived = TRUE;
break;
case RECEIVER_REQUEST_CLUSTER_ID:
if (operationMode == RX_MODE) {
appSendApsUnicastDirect(emberGetSender(), RECEIVER_RESPONSE_CLUSTER_ID,
(int8u *)NULL, 0);
}
break;
case RECEIVER_RESPONSE_CLUSTER_ID:
if (operationMode == TX_LOCATE_RECEIVER_MODE) {
// Found our receiver
receiverNodeId = emberGetSender();
operationMode = TX_MODE;
}
break;
}
}
// this is called when the stack status changes
void emberStackStatusHandler(EmberStatus status)
{
}
// Called when a unicast has completed transmission --
// status indicates whether the message was successfully
// transmitted or not.
void emberUnicastSent(EmberNodeId destination,
EmberApsFrame *apsFrame,
EmberMessageBuffer message,
EmberStatus status)
{
}
// called when a remote device sends a message to add a binding
EmberStatus emberRemoteSetBindingHandler(EmberBindingTableEntry *entry)
{
// this application doesn't allow external provisioning
return EMBER_INVALID_BINDING_INDEX;
}
// called when a remote device sends a message to delete a binding
EmberStatus emberRemoteDeleteBindingHandler(int8u index)
{
// this application doesn't allow external provisioning
return EMBER_INVALID_BINDING_INDEX;
}
// end Ember callback handlers
// *******************************************************************
// *******************************************************************
// Functions that use EmberZNet
// applicationTick - called to check application timeouts, button events,
// and periodically flash LEDs
static void applicationTick(void) {
static int16u ledBlinkStart = 0;
static int16u lastTransmitTime = 0;
static int8u ledBlink = FALSE;
int16u time;
int8u led;
time = halCommonGetInt16uMillisecondTick();
if (operationMode == TX_MODE || operationMode == TX_LOCATE_RECEIVER_MODE) {
if (time - lastTransmitTime > TRANSMIT_INTERVAL) {
if (operationMode == TX_MODE) {
appSendApsUnicastDirect(receiverNodeId, TEST_PACKET_CLUSTER_ID,
(int8u *)NULL, 0);
} else {
appSendApsBroadcast(RECEIVER_REQUEST_CLUSTER_ID, (int8u *)NULL, 0);
}
ledBlink = TRUE;
ledBlinkStart = time;
lastTransmitTime = time;
}
halClearLed(RX_LED);
led = TX_LED;
} else { // if (operationMode == RX_MODE)
halClearLed(TX_LED);
led = RX_LED;
// Received a packet; blink
if (rxPacketReceived == TRUE) {
ledBlink = TRUE;
ledBlinkStart = time;
rxPacketReceived = FALSE;
}
}
// Logic: if the ledBlink is TRUE then the LED is *off*; if the interval
// has expired the LED should be turned back on. Default is ON.
if (ledBlink == TRUE && (time - ledBlinkStart < LED_BLINK_INTERVAL)) {
halClearLed(led);
} else {
ledBlink = FALSE;
halSetLed(led);
}
}
void checkButtonEvents(void) {
// **************************************
// button 0 is pressed -- change channel
// **************************************
if (buttonZeroPress) {
// TODO: Channel change
buttonZeroPress = FALSE;
}
// ***********************************************
// button 1 is pressed -- change to transmit mode
// ***********************************************
if (buttonOnePress) {
operationMode = TX_LOCATE_RECEIVER_MODE;
buttonOnePress = FALSE;
}
}
//
// *******************************************************************
// *******************************************************************
// Callback from the HAL when a button state changes
// WARNING: this callback is an ISR so the best approach is to set a
// flag here when an action should be taken and then perform the action
// somewhere else. In this case the actions are serviced in the
// applicationTick function
void halButtonIsr(int8u button, int8u state)
{
// button 0 (button 0 on the dev board) was pushed down
if (button == BUTTON0 && state == BUTTON_PRESSED) {
buttonZeroPress = TRUE;
}
// button 1 (button 1 on the dev board) was pushed down
if (button == BUTTON1 && state == BUTTON_PRESSED) {
buttonOnePress = TRUE;
}
}
//
// *******************************************************************
// *******************************************************************
// Utility functions
// *****************************
// for processing serial cmds
// *****************************
void processSerialInput(void) {
int8u cmd;
if(emberSerialReadByte(APP_SERIAL, &cmd) == 0) {
if (cmd != '\n') emberSerialPrintf(APP_SERIAL, "\r\n");
switch(cmd) {
// help
case '?':
printHelp();
break;
// bootloader
case 'b':
emberSerialPrintf(APP_SERIAL, "starting bootloader...\r\n");
emberSerialWaitSend(APP_SERIAL);
halLaunchStandaloneBootloader(STANDALONE_BOOTLOADER_NORMAL_MODE);
break;
// 0 and 1 mean button presses
case '0':
buttonZeroPress = TRUE;
break;
case '1':
buttonOnePress = TRUE;
break;
case '\n':
case '\r':
break;
default:
emberSerialPrintf(APP_SERIAL, "unknown cmd\r\n");
break;
}
if (cmd != '\n') emberSerialPrintf(APP_SERIAL, "\r\nconnectivitytest>");
}
}
// *********************************
// print help
// *********************************
#define PRINT(x) emberSerialPrintf(APP_SERIAL, x); emberSerialWaitSend(APP_SERIAL)
void printHelp(void)
{
PRINT("? = help\r\n");
PRINT("0 = simulate button 0\r\n");
PRINT("1 = simulate button 1\r\n");
}
void forceNetworkJoin(int16u panId, int8u channel)
{
// Note that this is not standard behavior, but is useful for this very
// small network test.
// Write channel, PAN-ID to FLASH tokens
{
tokTypeStackNodeData tokNode;
tokNode.panId = panId;
tokNode.radioFreqChannel = channel;
tokNode.stackProfile = 0;
tokNode.nodeType = EMBER_ROUTER;
tokNode.zigbeeNodeId = 0x0; // TODO: should be random
halCommonSetToken(TOKEN_STACK_NODE_DATA, &tokNode);
}
if (emberNetworkInit() != EMBER_SUCCESS)
{
// We have a large problem. Eject.
emberSerialGuaranteedPrintf(APP_SERIAL, "Failed to join pre-determined network. Abort.");
}
}
// End utility functions
// *******************************************************************
// *******************************************************************
//
EmberStatus appSendApsBroadcast(int8u clusterId, int8u *data, int8u length) {
EmberMessageBuffer message; // Used to hold the message
int8u afFrame[3]; // The Application Framework header (see ZB specification)
EmberApsFrame frame; // The APS frame structure
EmberStatus status; // EmberStatus for return values
// AF Frame: defined by the ZB specification:
// Byte 0, bits 0-3: EMBER_AF_FRAME_TYPE_MSG or EMBER_AF_FRAME_TYPE_KVP
// Byte 0, bits 4-7: Number of transactions contained in this message (1-7)
// Byte 1: Sequence number for this frame - managed by application
// Byte 2: Transaction sequence number - this message contains only one transaction.
afFrame[0] = EMBER_AF_FRAME_CONTROL(EMBER_AF_FRAME_TYPE_MSG, 1); // Assembly macro
afFrame[1] = 0; // Sequence Number: Managed by application
afFrame[2] = 1; // The sequence of the following transaction.
message = emberFillLinkedBuffers(NULL, length + 3);
if (message == EMBER_NULL_MESSAGE_BUFFER) {
return EMBER_NO_BUFFERS;
}
emberCopyToLinkedBuffers(afFrame, message, 0, 3);
if (length != 0) {
emberCopyToLinkedBuffers(data, message, 3, length);
}
frame.profileId = PROFILE_ID; // The application profile ID
frame.clusterId = clusterId; // The cluster ID for this message
frame.sourceEndpoint = ENDPOINT; // Transmission endpoint
frame.destinationEndpoint = ENDPOINT; // Destination endpoint
frame.options = 0; // Used only for unicast messages
status = emberSendBroadcast(&frame,
0, // Broadcast radius (0 is EMBER_MAX_HOPS)
message);
emberReleaseMessageBuffer(message);
if (status != EMBER_SUCCESS) {
emberSerialPrintf(APP_SERIAL, "[appSendApsBroadcast] failed: 0x%x\r\n", status);
}
return status;
}
EmberStatus appSendApsUnicastDirect(int16u destNodeId, int8u clusterId, int8u *data, int8u length) {
EmberMessageBuffer message; // Used to hold the message
int8u afFrame[3]; // The Application Framework header (see ZB specification)
EmberApsFrame frame; // The APS frame structure
EmberStatus status; // EmberStatus for return values
// AF Frame: defined by the ZB specification:
// Byte 0, bits 0-3: EMBER_AF_FRAME_TYPE_MSG or EMBER_AF_FRAME_TYPE_KVP
// Byte 0, bits 4-7: Number of transactions contained in this message (1-7)
// Byte 1: Sequence number for this frame - managed by application
// Byte 2: Transaction sequence number - this message contains only one transaction.
afFrame[0] = EMBER_AF_FRAME_CONTROL(EMBER_AF_FRAME_TYPE_MSG, 1); // Assembly macro
afFrame[1] = 0; // Sequence Number: Managed by application
afFrame[2] = 1; // The sequence of the following transaction.
message = emberFillLinkedBuffers(NULL, length + 3);
if (message == EMBER_NULL_MESSAGE_BUFFER) {
return EMBER_NO_BUFFERS;
}
emberCopyToLinkedBuffers(afFrame, message, 0, 3);
if (length != 0) {
emberCopyToLinkedBuffers(data, message, 3, length);
}
frame.profileId = PROFILE_ID; // The application profile ID
frame.clusterId = clusterId; // The cluster ID for this message
frame.sourceEndpoint = ENDPOINT; // Transmission endpoint
frame.destinationEndpoint = ENDPOINT; // Destination endpoint
// APS Frame options summary (see API guide for details)
//
// EMBER_UNICAST_OPTION_NONE
// EMBER_UNICAST_OPTION_APS_INDIRECT - used to send indirect APS messages
// EMBER_UNICAST_OPTION_APS_RETRY - resend if necessary using APS retry
// EMBER_UNICAST_OPTION_ENABLE_ROUTE_DISCOVERY - initiate route discovery if required
// EMBER_UNICAST_OPTION_FORCE_ROUTE_DISCOVERY - force route discovery even if known
// EMBER_UNICAST_OPTION_POLL_RESPONSE - If sent to an end device, this message will
// be sent immediately instead of being queued -
// Must be the only option if used.
frame.options = EMBER_UNICAST_OPTION_NONE;
status = emberSendUnicast(destNodeId, // 16-bit destination ID
&frame,
message);
emberReleaseMessageBuffer(message);
if (status != EMBER_SUCCESS) {
emberSerialPrintf(APP_SERIAL, "[appSendApsUnicastDirect] failed: 0x%x\r\n", status);
}
return status;
}
//
// *******************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -