Ember's Application Framework V2 (AFV2) software architecture generally takes care of setting table sizes (for things like bindings, link keys and source route entries) on the EZSP NCP automatically during emAfResetAndInitNCP() based on the values defined in your top-level configuration header file (usually populated by your GUI selections in AppBuilder). However, as the NCP firmware already has a default (non-zero) amount of packet buffers configured upon boot-up, host applications that require lots of memory allocation for table storage on the NCP may need more RAM than what remains after the default amount of packet buffer usage (at 32 bytes per buffer) has been subtracted from the configurable RAM area. This can result in an EZSP_ERROR_OUT_OF_MEMORY (0x35) error code when certain configuration values are being set.
This problem is more likely to occur after updating to EmberZNet 4.6, since that version allows for much larger link key and binding table sizes than in the past.
The workaround for this problem is to use the emberAfNcpInitCallback() to lower the setting for EZSP_CONFIG_PACKET_BUFFER_COUNT to some minimum threshold that your application can live with and then explicitly configure any memory allocation values for the NCP. Since the AF already maximizes the NCP's RAM usage by occupying any remaining space with packet buffers, your host application will most likely end up with significantly more packet buffers configured than the minimum threshold chosen during the callback.
The code below is a sample implementation of emberAfNcpInitCallback() that illustrates this workaround and explains the design considerations associated with it:
#ifdef EZSP_HOST
#include "app/framework/util/af-main.h"
#endif //EZSP_HOST
void emberAfNcpInitCallback(boolean memoryAllocation) {
if (memoryAllocation) {
// For EM35x NCPs, this is pre-allocated to 150, which is too large for
// many applications that need large key/binding/child tables,
// so we set it to a low threshold for now to give plenty of room for
// other allocations.
//
// Applications that require a lot of endpoints or support many clusters
// on each endpoint may need something larger here since the packet buffers
// are used to store endpoint configuration data on the NCP as well as
// any packets routing to, from, or through this node.
// Packet buffers are 32 bytes each, and each endpoint configured on the NCP
// requires 9 plus 2*X plus 2*Y bytes of RAM, where X is the # of client-side
// clusters that endpoint supports, and Y is the # of server-side clusters
// that endpoint supports.
//
// Note that disabling a defined endpoint (using emberAfSetEzspValue() on
// EZSP_VALUE_ENDPOINT_FLAGS) at runtime doesn't change RAM allocation,
// just which endpoints are reported by the NCP when auto-responding to
// ZDO requests.
//
// The framework will scale the packet buffer count up to whatever fits in
// the remaining RAM after this callback completes (before it is called
// again with memoryAllocation=FALSE), so the value below is just the worst-
// case minimum your application can live, not necessarily what you end up
// using.
ezspSetConfigurationValue(EZSP_CONFIG_PACKET_BUFFER_COUNT, 24);
// These are probably the two most important items to re-size early,
// since they can be the largest tables (up to 100 entries each).
// The "(2)" in the debug string is a reminder that this is the 2nd time
// these values are being set during the init process (overriding the first
// setting done by emAfResetAndInitNCP() prior to this callback).
emberAfSetEzspConfigValue(EZSP_CONFIG_BINDING_TABLE_SIZE,
EMBER_BINDING_TABLE_SIZE,
"binding table size (2)");
emberAfSetEzspConfigValue(EZSP_CONFIG_KEY_TABLE_SIZE,
EMBER_KEY_TABLE_SIZE,
"key table size (2)");
// Also want to resize EZSP_CONFIG_MAX_END_DEVICE_CHILDREN here as well,
// since that has RAM implications (4 bytes per child).
// Note that this config value isn't explicitly configured by the AF's NCP
// init code, so if we don't set it here, it defaults to 6 on the NCP.
emberAfSetEzspConfigValue(EZSP_CONFIG_MAX_END_DEVICE_CHILDREN,
EMBER_MAX_END_DEVICE_CHILDREN,
"max end device children");
// These are other items from af-main-host.c/emAfResetAndInitNCP()
// that you may want to make sure work here, as they may fail during
// that function.
emberAfSetEzspConfigValue(EZSP_CONFIG_SOURCE_ROUTE_TABLE_SIZE,
EMBER_SOURCE_ROUTE_TABLE_SIZE,
"source route table size (2)");
emberAfSetEzspConfigValue(EZSP_CONFIG_ADDRESS_TABLE_SIZE,
EMBER_ADDRESS_TABLE_SIZE,
"address table size (2)");
emberAfSetEzspConfigValue(EZSP_CONFIG_TRUST_CENTER_ADDRESS_CACHE_SIZE,
EMBER_AF_TRUST_CENTER_ADDRESS_CACHE_SIZE,
"trust center address cache (2)");
} else {
// Last chance to add any emberAfSetEzspConfigValue() calls for things that
// don't affect memory allocation, like timeouts or flags.
// Also add any emberAfSetEzspValue() or emberAfSetEzspPolicy() calls here.
// You may also want to use ezspGetConfigurationValue() on
// EZSP_CONFIG_PACKET_BUFFER_COUNT here to see how many packet buffers the
// AF was able to allocate with the available RAM on the NCP.
}
}