3 * Copyright (c) 2020 Project CHIP Authors
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
20 * Copyright (c) 2020 Silicon Labs
22 * Licensed under the Apache License, Version 2.0 (the "License");
23 * you may not use this file except in compliance with the License.
24 * You may obtain a copy of the License at
26 * http://www.apache.org/licenses/LICENSE-2.0
28 * Unless required by applicable law or agreed to in writing, software
29 * distributed under the License is distributed on an "AS IS" BASIS,
30 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31 * See the License for the specific language governing permissions and
32 * limitations under the License.
34 /***************************************************************************/
37 * @brief It implements and manages the ESI table. The
38 *ESI table is shared among other plugins.
39 *******************************************************************************
40 ******************************************************************************/
42 #include "esi-management.h"
48 static EmberAfPluginEsiManagementEsiEntry esiTable[EMBER_AF_PLUGIN_ESI_MANAGEMENT_ESI_TABLE_SIZE];
49 static EmberAfEsiManagementDeletionCallback deletionCallbackTable[EMBER_AF_PLUGIN_ESI_MANAGEMENT_PLUGIN_CALLBACK_TABLE_SIZE];
50 static uint8_t deletionCallbackTableSize = 0;
52 static void performDeletionAnnouncement(uint8_t index)
56 // Notify all the subscribed plugins about this deletion.
57 for (i = 0; i < deletionCallbackTableSize; i++)
59 (deletionCallbackTable[i])(index);
63 EmberAfPluginEsiManagementEsiEntry * emberAfPluginEsiManagementGetFreeEntry(void)
65 EmberAfPluginEsiManagementEsiEntry * entry = NULL;
66 uint8_t networkIndex = 0; /*emberGetCurrentNetwork(); #2552*/
67 uint8_t deletedEsiIndex = 0;
70 // Look for a free entry first.
71 for (i = 0; i < EMBER_AF_PLUGIN_ESI_MANAGEMENT_ESI_TABLE_SIZE; i++)
73 if (esiTable[i].nodeId == EMBER_NULL_NODE_ID)
75 return &(esiTable[i]);
79 // No free entry found, we look for the oldest entry among those that
81 for (i = 0; i < EMBER_AF_PLUGIN_ESI_MANAGEMENT_ESI_TABLE_SIZE; i++)
83 if (esiTable[i].networkIndex == networkIndex && esiTable[i].age >= EMBER_AF_PLUGIN_ESI_MANAGEMENT_MIN_ERASING_AGE &&
84 (entry == NULL || esiTable[i].age > entry->age))
86 entry = &(esiTable[i]);
93 performDeletionAnnouncement(deletedEsiIndex);
99 EmberAfPluginEsiManagementEsiEntry * emberAfPluginEsiManagementEsiLookUpByShortIdAndEndpoint(EmberNodeId shortId,
102 uint8_t index = emberAfPluginEsiManagementIndexLookUpByShortIdAndEndpoint(shortId, endpoint);
103 if (index < EMBER_AF_PLUGIN_ESI_MANAGEMENT_ESI_TABLE_SIZE)
105 return &(esiTable[index]);
113 EmberAfPluginEsiManagementEsiEntry * emberAfPluginEsiManagementEsiLookUpByLongIdAndEndpoint(EmberEUI64 longId, EndpointId endpoint)
115 uint8_t index = emberAfPluginEsiManagementIndexLookUpByLongIdAndEndpoint(longId, endpoint);
116 if (index < EMBER_AF_PLUGIN_ESI_MANAGEMENT_ESI_TABLE_SIZE)
118 return &(esiTable[index]);
126 uint8_t emberAfPluginEsiManagementIndexLookUpByShortIdAndEndpoint(EmberNodeId shortId, EndpointId endpoint)
128 uint8_t networkIndex = 0; /*emberGetCurrentNetwork(); #2552*/
130 for (i = 0; i < EMBER_AF_PLUGIN_ESI_MANAGEMENT_ESI_TABLE_SIZE; i++)
132 if (esiTable[i].networkIndex == networkIndex && esiTable[i].nodeId == shortId && esiTable[i].endpoint == endpoint)
141 uint8_t emberAfPluginEsiManagementIndexLookUpByLongIdAndEndpoint(EmberEUI64 longId, EndpointId endpoint)
144 for (i = 0; i < EMBER_AF_PLUGIN_ESI_MANAGEMENT_ESI_TABLE_SIZE; i++)
146 if (memcmp(longId, esiTable[i].eui64, EUI64_SIZE) == 0 && esiTable[i].endpoint == endpoint)
155 EmberAfPluginEsiManagementEsiEntry * emberAfPluginEsiManagementEsiLookUpByIndex(uint8_t index)
157 if (index < EMBER_AF_PLUGIN_ESI_MANAGEMENT_ESI_TABLE_SIZE && esiTable[index].nodeId != EMBER_NULL_NODE_ID)
159 return &(esiTable[index]);
167 EmberAfPluginEsiManagementEsiEntry * emberAfPluginEsiManagementGetNextEntry(EmberAfPluginEsiManagementEsiEntry * entry, uint8_t age)
169 uint8_t networkIndex = 0; /*emberGetCurrentNetwork(); #2552*/
171 bool entryFound = false;
173 for (i = 0; i < EMBER_AF_PLUGIN_ESI_MANAGEMENT_ESI_TABLE_SIZE; i++)
175 // If the passed entry is NULL we return the first active entry (if any).
176 // If we already encountered the passed entry, we return the next active
178 if ((entry == NULL || entryFound) && esiTable[i].networkIndex == networkIndex && esiTable[i].nodeId != EMBER_NULL_NODE_ID &&
179 esiTable[i].age <= age)
181 return &(esiTable[i]);
183 // We found the passed entry in the table.
184 if (&(esiTable[i]) == entry)
193 void emberAfPluginEsiManagementDeleteEntry(uint8_t index)
195 assert(index < EMBER_AF_PLUGIN_ESI_MANAGEMENT_ESI_TABLE_SIZE);
197 esiTable[index].nodeId = EMBER_NULL_NODE_ID;
198 performDeletionAnnouncement(index);
201 void emberAfPluginEsiManagementAgeAllEntries(void)
203 uint8_t networkIndex = 0; /*emberGetCurrentNetwork(); #2552*/
205 for (i = 0; i < EMBER_AF_PLUGIN_ESI_MANAGEMENT_ESI_TABLE_SIZE; i++)
207 if (esiTable[i].networkIndex == networkIndex && esiTable[i].nodeId != EMBER_NULL_NODE_ID && esiTable[i].age < 0xFF)
214 void emberAfPluginEsiManagementClearTable(void)
217 for (i = 0; i < EMBER_AF_PLUGIN_ESI_MANAGEMENT_ESI_TABLE_SIZE; i++)
219 emberAfPluginEsiManagementDeleteEntry(i);
223 bool emberAfPluginEsiManagementSubscribeToDeletionAnnouncements(EmberAfEsiManagementDeletionCallback callback)
225 if (deletionCallbackTableSize < EMBER_AF_PLUGIN_ESI_MANAGEMENT_PLUGIN_CALLBACK_TABLE_SIZE)
227 deletionCallbackTable[deletionCallbackTableSize++] = callback;
236 uint8_t emberAfPluginEsiManagementUpdateEsiAndGetIndex(const EmberAfClusterCommand * cmd)
239 EmberAfPluginEsiManagementEsiEntry * esiEntry;
242 // Replace assert with equivalent conditional to quiet CSTAT complaint about
243 // possible dereference of null pointer. The 'return 0' is never executed.
244 // This approach satisfies all code lines where 'cmd' is dereferenced.
245 // assert(cmd != NULL);
252 emberAfPushNetworkIndex(cmd->networkIndex);
254 /*emberLookupEui64ByNodeId(cmd->source, esiEui64); #2552*/
255 esiEntry = emberAfPluginEsiManagementEsiLookUpByLongIdAndEndpoint(esiEui64, cmd->apsFrame->sourceEndpoint);
256 // The source ESI is not in the ESI table.
257 if (esiEntry == NULL)
259 emberAfDebugPrintln("source ESI 0x%x not found in table", cmd->source);
260 // We add the ESI to the table.
261 esiEntry = emberAfPluginEsiManagementGetFreeEntry();
262 if (esiEntry != NULL)
264 esiEntry->nodeId = cmd->source;
265 esiEntry->networkIndex = cmd->networkIndex;
266 esiEntry->endpoint = cmd->apsFrame->sourceEndpoint;
268 memmove(esiEntry->eui64, esiEui64, EUI64_SIZE);
272 emberAfDebugPrintln("No free entry available");
277 // Check that the short ID is still the one we stored in the ESI table.
278 // If not, update it.
279 if (esiEntry->nodeId != cmd->source)
281 emberAfDebugPrintln("ESI short ID changed, updating it");
282 esiEntry->nodeId = cmd->source;
286 index = emberAfPluginEsiManagementIndexLookUpByLongIdAndEndpoint(esiEui64, cmd->apsFrame->sourceEndpoint);
287 emberAfPopNetworkIndex();
291 void emberAfPluginEsiManagementInitCallback(void)
293 emberAfPluginEsiManagementClearTable();