static CommissioningState_t SetBinding(void) { emberAfDebugPrintln("DEBUG: Set Binding"); MatchDescriptorReq_t *in_dev = GetTopInDeviceDescriptor(); assert(in_dev != NULL); // init clusters skip mask length for checking for duplicates in the binding // table InitRemoteSkipCluster(in_dev->source_cl_arr_len); // check the supported clusters list for existence in the binding table MarkDuplicateMatches(in_dev); // nothing to do if we unmarked all clusters if (GetRemoteSkipMask() == 0) { SetNextEvent(SC_EZEV_CHECK_QUEUE); emberEventControlSetActive(StateMachineEvent); } else if (CreateBindings(in_dev)) { // Create bindings for supported clusters SetNextEvent(SC_EZEV_BINDING_DONE); } else { SetNextEvent(SC_EZEV_CHECK_QUEUE); } PopInDeviceDescriptor(); emberAfDebugPrintln("DEBUG: Supported clusters mask 0x%X", skip_mask.skip_clusters); emberEventControlSetActive(StateMachineEvent); return SC_EZ_BIND; }
static CommissioningState_t CheckNetwork(void) { emberAfDebugPrintln("DEBUG: Check Network state"); EmberNetworkStatus nw_status = emberNetworkState(); emberAfDebugPrintln("DEBUG: network state 0x%X", nw_status); if (nw_status == EMBER_JOINING_NETWORK || nw_status == EMBER_LEAVING_NETWORK) { // Try to check again after 5 seconds emberEventControlSetDelayQS(StateMachineEvent, SIMPLE_COMMISSIONING_NETWORK_RETRY_DELAY); return SC_EZ_START; } if (nw_status == EMBER_JOINED_NETWORK) { SetNextEvent(SC_EZEV_BCAST_IDENT_QUERY); // Send Permit Join broadcast to the current network // in case of ZED nothing will happen // TODO: Make this hadrcoded value as plugin's option emberAfPermitJoin(SIMPLE_COMMISSIONING_PERMIT_JOIN_TIME, TRUE); } else if (nw_status == EMBER_NO_NETWORK && GetNetworkTries() < NETWORK_ACCESS_CONS_TRIES) { // Form or join available network SetNextEvent(SC_EZEV_FORM_JOIN_NETWORK); } else { SetNextEvent(SC_EZEV_NETWORK_FAILED); } // if the device is in the network continue commissioning // by sending Identify Query emberEventControlSetActive(StateMachineEvent); return SC_EZ_START; }
EmberStatus SimpleCommissioningStart(uint8_t endpoint, bool is_server, const uint16_t *clusters, uint8_t length) { if (!clusters || !length) { // meaningless call if ClusterID array was not passed or its length // is zero return EMBER_BAD_ARGUMENT; } emberAfDebugPrintln("DEBUG: Call for starting commissioning"); if (length > emberBindingTableSize) { // passed more clusters than the binding table may handle // TODO: may be it is worth to track available entries to write in // the binding table emberAfDebugPrint("Warning: ask for bind 0x%X clusters. ", length); emberAfDebugPrintln("Binding table size is 0x%X", emberBindingTableSize); } if (CommissioningStateMachineStatus() != SC_EZ_STOP) { // quite implicit, but if our state machine runs then network // probably busy return EMBER_NETWORK_BUSY; } InitDeviceCommissionInfo(&dev_comm_session, endpoint, is_server, clusters, length); // Wake up our state machine emberEventControlSetActive(StateMachineEvent); return EMBER_SUCCESS; }
/** @brief Identify Cluster Identify Query Response * * * * @param timeout Ver.: always */ boolean emberAfIdentifyClusterIdentifyQueryResponseCallback(int16u timeout) { // TODO: !!! IMPORTANT !!! add handling for several responses // now the state machine might be broken as we use only one global variable // for storing incoming connection information like Short ID and endpoint // // ignore broadcasts from yourself and from devices that are not // in the identifying state const EmberAfClusterCommand *const current_cmd = emberAfCurrentCommand(); if (emberAfGetNodeId() != current_cmd->source && timeout != 0) { emberAfDebugPrintln("DEBUG: Got ID Query response"); emberAfDebugPrintln("DEBUG: Sender 0x%2X", emberAfCurrentCommand()->source); // Queue is empty, so we can start commissioning process // otherwise we push it in the queue and will process later if (GetQueueSize() == 0) { // ID Query received -> go to the discover state for getting clusters info emberAfDebugPrintln("DEBUG: QUEUE IS EMPTY"); SetNextState(SC_EZ_DISCOVER); SetNextEvent(SC_EZEV_CHECK_CLUSTERS); emberEventControlSetActive(StateMachineEvent); } // Store information about endpoint and short ID of the incoming response // for further processing in the Matching (SC_EZ_MATCH) state SetInConnBaseInfo(current_cmd->source, current_cmd->apsFrame->sourceEndpoint); emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS); } return TRUE; }
static CommissioningState_t StopCommissioning(void) { emberAfDebugPrintln("DEBUG: Stop commissioning"); emberAfDebugPrintln("Current state is 0x%X", GetNextState()); SetNextEvent(SC_EZEV_IDLE); // clean up globals ClearNetworkTries(); return SC_EZ_STOP; }
/*! State Machine function */ void emberAfPluginSimpleCommissioningInitiatorStateMachineEventHandler(void) { emberEventControlSetInactive(StateMachineEvent); // That might happened that ZigBee state machine changed current network // So, it is important to switch to the proper network before commissioning // state machine might start EmberStatus status = emberAfPushNetworkIndex(dev_comm_session.network_index); if (status != EMBER_SUCCESS) { // TODO: Handle unavailability of switching network } emberAfDebugPrintln("DEBUG: State Machine"); // Get state previously set by some handler CommissioningState_t cur_state = GetNextState(); CommissioningEvent_t cur_event = GetNextEvent(); for (size_t i = 0; i < TRANSIT_TABLE_SIZE(); ++i) { if ((cur_state == sm_transition_table[i].state || SC_EZ_UNKNOWN == sm_transition_table[i].state) && ((cur_event == sm_transition_table[i].event) || SC_EZEV_UNKNOWN == sm_transition_table[i].event)) { // call handler which set the next_state on return and // next_event inside itself SetNextState((sm_transition_table[i].handler)()); break; } } // Don't forget to pop Network Index status = emberAfPopNetworkIndex(); // sanity check that network switched back properly EMBER_TEST_ASSERT(status == EMBER_SUCCESS); }
bool emAfPluginCommsHubFunctionTunnelDestroy(EmberEUI64 remoteDeviceId) { EmberAfStatus status = EMBER_ZCL_STATUS_NOT_FOUND; uint8_t tunnelIndex; emberAfDebugPrint("CHF: TunnelDestroy "); emberAfDebugDebugExec(emberAfPrintBigEndianEui64(remoteDeviceId)); emberAfDebugPrintln(""); tunnelIndex = findTunnelByDeviceId(remoteDeviceId); if (tunnelIndex < EMBER_AF_PLUGIN_COMMS_HUB_FUNCTION_TUNNEL_LIMIT) { status = (tunnels[tunnelIndex].type == CLIENT_TUNNEL) ? emberAfPluginTunnelingClientCloseTunnel(tunnels[tunnelIndex].tunnelId) : EMBER_ZCL_STATUS_SUCCESS; if (status == EMBER_ZCL_STATUS_SUCCESS) { tunnels[tunnelIndex].state = UNUSED_TUNNEL; if (tunnelIndex == responsePendingIndex) { responsePendingIndex = EM_AF_PLUGIN_COMMS_HUB_FUNCTION_NULL_TUNNEL_INDEX; // let the tunnel event handler retry any pending create requests emberEventControlSetActive(emberAfPluginCommsHubFunctionTunnelEventControl); } } } return (status == EMBER_ZCL_STATUS_SUCCESS); }
// This should be called from the Comms Hub Function Plugin Init callback. void emAfPluginCommsHubFunctionTunnelInit(uint8_t localEndpoint) { uint8_t i; emberAfDebugPrintln("CHF: TunnelInit"); localTunnelEndpoint = localEndpoint; for (i = 0; i < EMBER_AF_PLUGIN_COMMS_HUB_FUNCTION_TUNNEL_LIMIT; i++) { tunnels[i].state = UNUSED_TUNNEL; } // Per GBCS v0.8 section 10.2.2, Devices supporting the Tunneling Cluster // as a Server shall have a MaximumIncomingTransferSize set to 1500 octets, // in line with the ZSE default. All Devices supporting the Tunneling // Cluster shall use this value in any RequestTunnelResponse command and // any RequestTunnel command. // // If the tunneling client's configured maximumIncomingTransferSize // is less than 1500 we'll log a warning. // // See equivalent check in emberAfPluginTunnelingClientTunnelOpenedCallback() if (EMBER_AF_PLUGIN_TUNNELING_CLIENT_MAXIMUM_INCOMING_TRANSFER_SIZE < 1500) { emberAfPluginCommsHubFunctionPrintln("WARN: Tunneling Client MaximumIncomingTransferSize is %d but should be 1500", EMBER_AF_PLUGIN_TUNNELING_CLIENT_MAXIMUM_INCOMING_TRANSFER_SIZE); } }
static CommissioningState_t FormJoinNetwork(void) { emberAfDebugPrintln("DEBUG: Form/Join network"); // Form or join depends on the device type // Coordinator: form a network // Router/ZED/SED/MED: find a network EmberStatus status = EMBER_SUCCESS; if (emAfCurrentZigbeeProNetwork->nodeType == EMBER_COORDINATOR) { status = emberAfFindUnusedPanIdAndForm(); } else { status = emberAfStartSearchForJoinableNetwork(); } if (status != EMBER_SUCCESS) { SetNextEvent(SC_EZEV_UNKNOWN); } else { SetNextEvent(SC_EZEV_CHECK_NETWORK); } IncNetworkTries(); // run state machine again after 10 seconds emberEventControlSetDelayQS(StateMachineEvent, SIMPLE_COMMISSIONING_NETWORK_CHECK_RETRY_TIME); return SC_EZ_START; }
static CommissioningState_t CheckClusters(void) { emberAfDebugPrintln("DEBUG: Check Clusters handler"); // ask a responded device for providing with info about clusters and call // the callback MatchDescriptorReq_t *in_dev = GetTopInDeviceDescriptor(); assert(in_dev != NULL); emberAfDebugPrintln("DEBUG: short ID 0x%2X", in_dev->source); emberAfDebugPrintln("DEBUG: ep 0x%X", in_dev->source_ep); EmberStatus status = emberAfFindClustersByDeviceAndEndpoint( in_dev->source, in_dev->source_ep, ProcessServiceDiscovery); // Nothing to do here with states as the next event will become clear // during the ProcessServiceDiscovery callback call SetNextEvent(SC_EZEV_UNKNOWN); return (status != EMBER_SUCCESS) ? SC_EZ_UNKNOWN : SC_EZ_DISCOVER; }
static CommissioningState_t BindingDone(void) { emberAfDebugPrintln("DEBUG: Binding Done"); // as we've processed the current remote device delete it from the queue SetNextEvent(SC_EZEV_CHECK_QUEUE); emberEventControlSetActive(StateMachineEvent); return SC_EZ_BIND; }
static CommissioningState_t UnknownState(void) { emberAfDebugPrintln("DEBUG: Unknown operation requested on stage 0x%X", GetNextState()); // don't want to do anything here, just clean up to the initial state // {EZ_STOP, EZEV_IDLE} SetNextEvent(SC_EZEV_IDLE); return SC_EZ_STOP; }
/*! Helper inline function for setting an incoming connection info during the Identify Query Response */ static inline void SetInConnBaseInfo(const EmberNodeId short_id, const uint8_t endpoint) { // try to add the new remote device descriptor to the queue if (!AddInDeviceDescriptor(short_id, endpoint)) { // queue is probably full emberAfDebugPrintln( "DEBUG: WARNING: incoming device response will be missed"); } }
static void colorControlSetColorModeToZero(void) { #ifdef ZCL_USING_COLOR_CONTROL_CLUSTER_COLOR_CONTROL_COLOR_MODE_ATTRIBUTE // Set the optional Color Mode attribute to zero as per the spec. If an // error occurs, log it, but ignore it. uint8_t colorMode = 0; EmberAfStatus status = emberAfWriteServerAttribute(emberAfCurrentEndpoint(), ZCL_COLOR_CONTROL_CLUSTER_ID, ZCL_COLOR_CONTROL_COLOR_MODE_ATTRIBUTE_ID, &colorMode, ZCL_ENUM8_ATTRIBUTE_TYPE); if (status != EMBER_ZCL_STATUS_SUCCESS) { emberAfColorControlClusterPrintln("ERR: writing color mode%x", status); } emberAfDebugPrintln("colorMode=%x", colorMode); emberAfColorControlClusterFlush(); #else emberAfDebugPrintln("no color mode attribute"); emberAfColorControlClusterFlush(); #endif //ZCL_USING_COLOR_CONTROL_CLUSTER_COLOR_CONTROL_COLOR_MODE_ATTRIBUTE }
void emAfPluginCommsHubFunctionTunnelClose(EmberEUI64 remoteDeviceId) { uint8_t tunnelId; tunnelId = findTunnelByDeviceId(remoteDeviceId); emberAfDebugPrintln("CHF: TunnelClosed:0x%x", tunnelId); if (tunnelId != EM_AF_PLUGIN_COMMS_HUB_FUNCTION_NULL_TUNNEL_INDEX) { tunnels[tunnelId].state = CLOSED_TUNNEL; } }
/*! State Machine handlers implementation */ static CommissioningState_t StartCommissioning(void) { emberAfDebugPrintln("DEBUG: Commissioning Start"); // TODO: here we might add some sanity check like cluster existense // or something like that, but now just start commissioning process // init internal queue for processing several remote devices InitQueue(); SetNextEvent(SC_EZEV_CHECK_NETWORK); emberEventControlSetActive(StateMachineEvent); return SC_EZ_START; }
/** @brief Tunnel Closed * * This function is called by the Tunneling server plugin whenever a tunnel is * closed. Clients may close tunnels by sending a Close Tunnel command. The * server can preemptively close inactive tunnels after a timeout. * * @param tunnelId The identifier of the tunnel that has been closed. Ver.: * always * @param clientInitiated true if the client initiated the closing of the tunnel * or false if the server closed the tunnel due to inactivity. Ver.: always */ void emberAfPluginTunnelingServerTunnelClosedCallback(uint16_t tunnelId, bool clientInitiated) { uint8_t tunnelIndex; emberAfDebugPrintln("CHF: ServerTunnelClosed:0x%x", tunnelId); tunnelIndex = findTunnelByTunnelId(tunnelId, SERVER_TUNNEL); if (tunnelIndex != EM_AF_PLUGIN_COMMS_HUB_FUNCTION_NULL_TUNNEL_INDEX) { tunnels[tunnelIndex].state = CLOSED_TUNNEL; } }
/*! Callback for Simple Descriptor Request */ static void ProcessServiceDiscovery( const EmberAfServiceDiscoveryResult *result) { // if we get a matche or a default response handle it // otherwise stop commissioning or go to the next incoming device if (emberAfHaveDiscoveryResponseStatus(result->status)) { EmberAfClusterList *discovered_clusters = (EmberAfClusterList *)result->responseData; // if our device requested to bind to server clusters (is_server parameter // during the SimpleCommissioningStart was FALSE) -> use inClusterList of // the incoming device's response // otherwise -> outClusterList (as our device has server clusters) const uint16_t *inc_clusters_arr = (dev_comm_session.is_server) ? discovered_clusters->outClusterList : discovered_clusters->inClusterList; // get correct lenght of the incoming clusters array const uint8_t inc_clusters_arr_len = (dev_comm_session.is_server) ? discovered_clusters->outClusterCount : discovered_clusters->inClusterCount; // init clusters skip mask length for further using InitRemoteSkipCluster(inc_clusters_arr_len); // check how much clusters our device wants to bind to uint8_t supported_clusters = CheckSupportedClusters(inc_clusters_arr, inc_clusters_arr_len); emberAfDebugPrintln("DEBUG: Supported clusters %d", supported_clusters); if (supported_clusters == 0) { // we should not do anything with that, just wait maybe another response // would come SetNextEvent(SC_EZEV_TIMEOUT); SetNextState(SC_EZ_WAIT_IDENT_RESP); emberEventControlSetDelayMS( StateMachineEvent, SIMPLE_COMMISSIONING_IDENTIFY_RESPONSE_WAIT_TIME()); } else { // update our incoming device structure with information about clusters SetInDevicesClustersInfo(inc_clusters_arr, inc_clusters_arr_len, supported_clusters); // Now we have all information about responded device's clusters // Start matching procedure for checking how much of them fit for our // device SetNextEvent(SC_EZEV_CHECK_CLUSTERS); SetNextState(SC_EZ_MATCH); emberEventControlSetActive(StateMachineEvent); } } else { // we should not do anything with that, just wait maybe another response // would come SetNextEvent(SC_EZEV_TIMEOUT); SetNextState(SC_EZ_WAIT_IDENT_RESP); emberEventControlSetDelayMS( StateMachineEvent, SIMPLE_COMMISSIONING_IDENTIFY_RESPONSE_WAIT_TIME()); } }
// See if we can recover from tunnel creation issues. static bool handleRequestTunnelFailure(uint8_t tunnelIndex, EmberAfPluginTunnelingClientStatus status) { uint8_t i; emberAfDebugPrintln("CHF: handleRequestTunnelFailure 0x%x, 0x%x", tunnelIndex, status); if (status == EMBER_AF_PLUGIN_TUNNELING_CLIENT_BUSY) { // Per GBCS send another request 3 minutes from now tunnels[tunnelIndex].state = REQUEST_PENDING_TUNNEL; tunnels[tunnelIndex].timeoutMSec = halCommonGetInt32uMillisecondTick() + (MILLISECOND_TICKS_PER_SECOND * 180); emberEventControlSetActive(emberAfPluginCommsHubFunctionTunnelEventControl); emberAfPluginCommsHubFunctionPrintln("CHF: Busy status received from node ID 0x%2x",tunnels[tunnelIndex].remoteNodeId); return true; } else if (status == EMBER_AF_PLUGIN_TUNNELING_CLIENT_NO_MORE_TUNNEL_IDS) { // Per GBCS close any other tunnels we may have with the device // and once all responses are received try the RequestTunnel again bool retryRequest = false; for (i = 0; i < EMBER_AF_PLUGIN_COMMS_HUB_FUNCTION_TUNNEL_LIMIT; i++) { if (i != tunnelIndex && tunnels[i].remoteNodeId == tunnels[tunnelIndex].remoteNodeId) { retryRequest = true; emAfPluginCommsHubFunctionTunnelDestroy(tunnels[i].remoteDeviceId); } } if (retryRequest) { // We'll retry the request in the tunnel event handler so as to give the // tunnel(s) a chance to clean up. tunnels[tunnelIndex].state = REQUEST_PENDING_TUNNEL; tunnels[tunnelIndex].timeoutMSec = halCommonGetInt32uMillisecondTick() + (MILLISECOND_TICKS_PER_SECOND * 5); emberEventControlSetActive(emberAfPluginCommsHubFunctionTunnelEventControl); return true; } // no tunnels were closed so nothing more we can do emberAfPluginCommsHubFunctionPrintln("%p%p%p", "Error: ", "Tunnel Create failed: ", "No more tunnel ids"); tunnels[tunnelIndex].state = CLOSED_TUNNEL; return false; } // All other errors are either due to mis-configuration or errors that we // cannot recover from so print the error and return false. emberAfPluginCommsHubFunctionPrintln("%p%p%p0x%x", "Error: ", "Tunnel Create failed: ", "Tunneling Client Status: ", status); tunnels[tunnelIndex].state = CLOSED_TUNNEL; return false; }
/*! Callback for IEEE address Request */ static void ProcessEUI64Discovery(const EmberAfServiceDiscoveryResult *result) { if (emberAfHaveDiscoveryResponseStatus(result->status)) { MatchDescriptorReq_t *in_dev = GetTopInDeviceDescriptor(); assert(in_dev != NULL); SetInConnEUI64Address((const uint8_t *)result->responseData); emberAfDebugPrint("DEBUG: EUI64 "); emberAfPrintLittleEndianEui64(in_dev->source_eui64); emberAfDebugPrintln(""); SetNextEvent(SC_EZEV_BIND); } emberEventControlSetActive(StateMachineEvent); }
// Sets the hue attribute static void colorControlSetHue(uint8_t endpoint, uint8_t hue) { EmberAfStatus status = emberAfWriteServerAttribute(endpoint, ZCL_COLOR_CONTROL_CLUSTER_ID, ZCL_COLOR_CONTROL_CURRENT_HUE_ATTRIBUTE_ID, (uint8_t *)&hue, ZCL_INT8U_ATTRIBUTE_TYPE); if (status != EMBER_ZCL_STATUS_SUCCESS) { emberAfColorControlClusterPrintln("ERR: writing current hue %x", status); emberAfColorControlClusterFlush(); return; } emberAfDebugPrintln("hue=%x", hue); }
/** @brief Tunnel Closed * * This function is called by the Tunneling client plugin whenever a server * sends a notification that it preemptively closed an inactive tunnel. * Servers are not required to notify clients of tunnel closures, so * applications cannot rely on this callback being called for all tunnels. * * @param tunnelId The ID of the tunnel that has been closed. Ver.: * always */ void emberAfPluginTunnelingClientTunnelClosedCallback(uint8_t tunnelId) { uint8_t tunnelIndex; emberAfDebugPrintln("CHF: ClientTunnelClosed:0x%x", tunnelId); tunnelIndex = findTunnelByTunnelId(tunnelId, CLIENT_TUNNEL); if (tunnelIndex != EM_AF_PLUGIN_COMMS_HUB_FUNCTION_NULL_TUNNEL_INDEX) { tunnels[tunnelIndex].state = CLOSED_TUNNEL; if (tunnelIndex == responsePendingIndex) { responsePendingIndex = EM_AF_PLUGIN_COMMS_HUB_FUNCTION_NULL_TUNNEL_INDEX; emberEventControlSetActive(emberAfPluginCommsHubFunctionTunnelEventControl); } } }
// Sets the saturation attribute static void colorControlSetSaturation(uint8_t endpoint, uint8_t saturation) { EmberAfStatus status = emberAfWriteServerAttribute(endpoint, ZCL_COLOR_CONTROL_CLUSTER_ID, ZCL_COLOR_CONTROL_CURRENT_SATURATION_ATTRIBUTE_ID, (uint8_t *)&saturation, ZCL_INT8U_ATTRIBUTE_TYPE); if (status != EMBER_ZCL_STATUS_SUCCESS) { emberAfColorControlClusterPrintln("ERR: writing current saturation %x", status); return; } emberAfDebugPrintln("saturation=%x", saturation); }
bool emAfPluginCommsHubFunctionTunnelSendData(EmberEUI64 remoteDeviceId, uint16_t headerLen, uint8_t *header, uint16_t dataLen, uint8_t *data) { EmberAfStatus status = EMBER_ZCL_STATUS_FAILURE; bool success; uint8_t tunnelIndex; emberAfDebugPrint("CHF: TunnelSendData "); emberAfDebugDebugExec(emberAfPrintBigEndianEui64(remoteDeviceId)); emberAfDebugPrint(" ["); emberAfDebugPrintBuffer(header, headerLen, false); emberAfDebugPrintBuffer(data, dataLen, false); emberAfDebugPrintln("]"); tunnelIndex = findTunnelByDeviceId(remoteDeviceId); if (tunnelIndex != EM_AF_PLUGIN_COMMS_HUB_FUNCTION_NULL_TUNNEL_INDEX) { if (tunnels[tunnelIndex].state == ACTIVE_TUNNEL) { // Add the header to the output buffers to that we don't copy data twice if (headerLen > 0) { MEMCOPY(message, header, headerLen); MEMCOPY(message+headerLen, data, dataLen); data = message; dataLen += headerLen; } status = (tunnels[tunnelIndex].type == CLIENT_TUNNEL) ? emberAfPluginTunnelingClientTransferData(tunnels[tunnelIndex].tunnelId, data, dataLen) : emberAfPluginTunnelingServerTransferData(tunnels[tunnelIndex].tunnelId, data, dataLen); } else if (tunnels[tunnelIndex].state == CLOSED_TUNNEL) { // we'll return failure to this message but we'll start the process // of bring up the tunnel so that if the message is resent the tunnel // should be up. emberAfPluginCommsHubFunctionPrintln("Tunnel Closed: New tunnel is requested for the device."); requestTunnel(tunnelIndex); } } success = (status == EMBER_ZCL_STATUS_SUCCESS); if (!success) { emberAfPluginCommsHubFunctionPrintln("%p%p%p0x%x", "Error: ", "Tunnel SendData failed: ", "Tunneling Status: ", status); } return success; }
static bool CreateBindings(const MatchDescriptorReq_t *const in_dev) { // here we add bindings to the binding table EmberStatus status = EMBER_SUCCESS; for (size_t i = 0; i < in_dev->source_cl_arr_len; ++i) { if (!IsSkipCluster(i)) { uint8_t bindex = FindUnusedBindingIndex(); if (bindex == EMBER_APPLICATION_ERROR_0 || bindex == EMBER_APPLICATION_ERROR_1) { // error during finding an available binding table index for write to // Check query in that case // TODO: handle error return false; } EmberBindingTableEntry new_binding; InitBindingTableEntry(in_dev->source_eui64, in_dev->source_cl_arr[i], in_dev->source_ep, &new_binding); status = emberSetBinding(bindex, &new_binding); if (status == EMBER_SUCCESS) { // Set up the remote short ID for binding for avoiding ZDO broadcast emberSetBindingRemoteNodeId(bindex, in_dev->source); } // DEBUG emberGetBinding(bindex, &new_binding); emberAfDebugPrintln("DEBUG: remote ep 0x%X", new_binding.remote); emberAfDebugPrintln("DEBUG: cluster id 0x%X%X", HIGH_BYTE(new_binding.clusterId), LOW_BYTE(new_binding.clusterId)); } } // all bindings successfully added return true; }
/** @brief Data Received * * This function is called by the Tunneling server plugin whenever data is * received from a client through a tunnel. * * @param tunnelId The identifier of the tunnel through which the data was * received. Ver.: always * @param data Buffer containing the raw octets of the data. Ver.: always * @param dataLen The length in octets of the data. Ver.: always */ void emberAfPluginTunnelingServerDataReceivedCallback(uint16_t tunnelId, uint8_t * data, uint16_t dataLen) { uint8_t tunnelIndex; emberAfDebugPrint("CHF: ServerDataReceived:%x,[", tunnelId); emberAfDebugPrintBuffer(data, dataLen, false); emberAfDebugPrintln("]"); tunnelIndex = findTunnelByTunnelId(tunnelId, SERVER_TUNNEL); if (tunnelIndex != EM_AF_PLUGIN_COMMS_HUB_FUNCTION_NULL_TUNNEL_INDEX) { emAfPluginCommsHubFunctionTunnelDataReceivedCallback(tunnels[tunnelIndex].remoteDeviceId, dataLen, data); } }
static CommissioningState_t CheckQuery(void) { emberAfDebugPrintln("DEBUG: Check query"); CommissioningState_t next_st = SC_EZ_UNKNOWN; if (GetQueueSize() != 0) { SetNextEvent(SC_EZEV_CHECK_CLUSTERS); next_st = SC_EZ_DISCOVER; } else { SetNextEvent(SC_EZEV_QUEUE_EMPTY); next_st = SC_EZ_BIND; } emberEventControlSetActive(StateMachineEvent); return next_st; }
/** @brief Is Protocol Supported * * This function is called by the Tunneling server plugin whenever a Request * Tunnel command is received. The application should return true if the * protocol is supported and false otherwise. * * @param protocolId The identifier of the metering communication protocol for * which the tunnel is requested. Ver.: always * @param manufacturerCode The manufacturer code for manufacturer-defined * protocols or 0xFFFF in unused. Ver.: always */ bool emberAfPluginTunnelingServerIsProtocolSupportedCallback(uint8_t protocolId, uint16_t manufacturerCode) { EmberEUI64 remoteDeviceId; emberAfDebugPrintln("CHF: ServerIsProtocolSupported:0x%x 0x%2x", protocolId, manufacturerCode); // Since the tunneling cluster server code does not pass the EUI64 or the // node ID of the remote end of the tunnel so we need to look them up. // Luckily this callback is called in the context of the RequestTunnel // command processing and we look into the command for this info. emberLookupEui64ByNodeId(emberAfCurrentCommand()->source, remoteDeviceId); return (GBCS_TUNNELING_PROTOCOL_ID == protocolId && GBCS_TUNNELING_MANUFACTURER_CODE == manufacturerCode && emAfPluginCommsHubFunctionTunnelAcceptCallback(remoteDeviceId)); }
static CommissioningState_t MatchingCheck(void) { emberAfDebugPrintln("DEBUG: Matching Check"); MatchDescriptorReq_t *in_dev = GetTopInDeviceDescriptor(); assert(in_dev != NULL); EmberStatus status = emberAfFindIeeeAddress(in_dev->source, ProcessEUI64Discovery); if (status == EMBER_SUCCESS) { SetNextEvent(SC_EZEV_AWAIT_EUI64); } else { SetNextEvent(SC_EZEV_CHECK_QUEUE); } // await for EUI64 response emberEventControlSetDelayMS(StateMachineEvent, SIMPLE_COMMISSIONING_EUI64_RESPONSE_WAIT_TIME()); return SC_EZ_BIND; }
void emAfPluginCommsHubFunctionTunnelCleanup(EmberEUI64 remoteDeviceId) { uint8_t tunnelIndex; tunnelIndex = findTunnelByDeviceId(remoteDeviceId); if (tunnelIndex < EMBER_AF_PLUGIN_COMMS_HUB_FUNCTION_TUNNEL_LIMIT) { emberAfDebugPrint("CHF: TunnelCleanup "); emberAfDebugDebugExec(emberAfPrintBigEndianEui64(remoteDeviceId)); emberAfDebugPrintln(""); if (tunnels[tunnelIndex].type == CLIENT_TUNNEL) { emberAfPluginTunnelingClientCleanup(tunnels[tunnelIndex].tunnelId); } else { emberAfPluginTunnelingServerCleanup(tunnels[tunnelIndex].tunnelId); } tunnels[tunnelIndex].state = UNUSED_TUNNEL; } }