What kinds of token writes does the EmberZNet stack perform?
As you may be aware, both stack-controlled and application-controlled non-volatile data ('stack tokens' and 'application tokens') reside in NVM3 area of flash that uses special wear-leveling techniques to prevent excessive write/erase wear on that portion of memory. (Note that older devices may use Simulated EEPROM instead of NVM3) In attempting to approximate one’s token system lifetime, it is useful not only to model expected token writes by your application directly but also by the EmberZNet stack architecture since it is the overall quantity of writes (and the amounts of data being written) that determine the lifetime of the token system. The following guidelines are provided to help describe what kinds of stack events will cause token data (TOKEN_STACK_xxx values) to be written, allowing you to more accurately model your wear-leveling based on the expected frequency of these events.
The following is a list of events that affect the stack’s tokens (See stack/config/token-stack.h) in the EmberZNet releases for token declarations and typedefs. These guidelines are applicable for network coprocessors [NCPs] as well as the host side. The host may not have as much visibility into when these stack events are taking place, and certain handlers (such as emberRadioNeedsCalibratingHandler() and halStackProcessBootCount()) may be implemented already by the EZSP firmware, precluding any customization of stack behavior where the related tokens are concerned.
•When any device joins, rejoins, or forms a PAN, TOKEN_STACK_NODE_DATA is written with the current EmberNetworkParameters information and TOKEN_STACK_NETWORK_MANAGEMENT is written with current Network Manager information.
•When a PAN ID change is announced by the Network Manager (as a result of a PAN ID conflict detection) or Channel Change is announced by the Network Manager (per the application's request), nodes in the affected PAN will write TOKEN_STACK_NODE_DATA and TOKEN_STACK_NETWORK_MANAGEMENT as they change to the updated PAN ID or channel.
•When a node receives the Network Key after joining a secure network, TOKEN_STACK_KEYS and TOKEN_STACK_NONCE_COUNTER will be written if the key is different than the Network Key already saved in that token.
•When a node receives a Trust Center Link Key (soon after joining or as part of a new link key establishment process later on), TOKEN_STACK_TRUST_CENTER is written.
•When a node receives a notification of a new Network Key (announced by the Trust Center as part of emberBroadcastNextNetworkKey()), TOKEN_STACK_ALTERNATE_KEY is written.
•When a new network key takes effect (as a result of Trust Center calling emberBroadcastNetworkKeySwitch()), TOKEN_STACK_ALTERNATE_KEY, TOKEN_STACK_KEYS, and TOKEN_STACK_NONCE_COUNTER are all written.
•When emberSetInitialSecurityState() is called successfully, TOKEN_STACK_KEYS is written at least once and TOKEN_STACK_TRUST_CENTER is written twice. If EMBER_HAVE_NETWORK_KEY bit is set, TOKEN_STACK_KEYS is written a second time. TOKEN_STACK_APS_FRAME_COUNTER and TOKEN_STACK_NONCE_COUNTER are both written (full writes, not increments) once.
•If the network begins operation in Distributed Trust Center Mode (per coordinator's initial security bitmask) but later switches to a centralized Trust Center mode of operation (via emberBecomeTrustCenter() or the delivery of a network key from some node assumed to be the Trust Center), TOKEN_STACK_TRUST_CENTER will be written.
•If a device's node ID changes (due to node ID conflict), TOKEN_STACK_NODE_DATA is written.
•If the Network Manager identity is changed (through a Network Update announcement by the new manager node), TOKEN_STACK_NETWORK_MANAGEMENT is written.
•When a node leaves the network (as a result of an emberLeaveNetwork() call or a Leave Request from another device), TOKEN_STACK_NODE_DATA and TOKEN_STACK_TRUST_CENTER are written.
•When a node fails to join the network (association fails or node fails to authenticate after association), TOKEN_STACK_NODE_DATA is written.
•When a node resumes prior network operation via emberNetworkInit(), TOKEN_STACK_NONCE_COUNTER and TOKEN_STACK_APS_FRAME_COUNTER are incremented (not a full write, just an increment mark towards the counter).
•For every 4096 outgoing frames that a node transmits with the current network key, TOKEN_STACK_NONCE_COUNTER is incremented.
•For every 4096 outgoing frames that a node transmits with the current network key, TOKEN_STACK_APS_FRAME_COUNTER is incremented.
•If using unique, per-device link keys (aps-keys-full library), each time a key table entry is set/modified/erased, one indexed write to TOKEN_STACK_KEY_TABLE is written.
•If using certificate-based key establishment (CBKE-library-core), each time key establishment completes, and a partner link key becomes authorized, one indexed write to TOKEN_STACK_KEY_TABLE is written.
•If using bindings (binding-table-library), each successful call to emberSetBinding() or emberDeleteBinding() will result in a write to TOKEN_STACK_BINDING_TABLE for that indexed entry. If calling emberClearBindingTable(), several indexed writes equal to EMBER_BINDING_TABLE_SIZE will be performed against TOKEN_STACK_BINDING_TABLE.
•Each time a new end device (not already in the child table) successfully joins or rejoins to a node, that parent node performs an indexed write of TOKEN_STACK_CHILD_TABLE. (Note that routers joining the network affect other device tokens as well.)
•Each time a parent node erases a child table entry, an indexed write to TOKEN_STACK_CHILD_TABLE is performed. Possible scenarios are, entry times out after End Device Poll Timeout, a child leaves or is asked to leave by some other device [including the parent], a child rejoins the network at some other parent, and a child begins to rejoin current parent but fails association or authentication.
•Each time a node calls emberFormNetwork() or emberJoinNetwork() with EMBER_SUCCESS result, the node's child table will be initialized, causing between 0 and EMBER_CHILD_TABLE_SIZE indexed writes to occur to TOKEN_STACK_CHILD_TABLE. (Only those entries previously containing child table data will be written.)
•Each time a node performs radio calibration for a certain channel and the calibration parameters change, an indexed write to TOKEN_STACK_CAL_DATA occurs). Calibration occurs automatically the first time a given radio channel is used in the device's lifetime (or when calibration token data for that channel has been erased). It also occurs whenever emberCalibrateCurrentChannel() is called; this function is usually called automatically as part of the default emberRadioNeedsCalibratingHandler(), which is invoked whenever the analog parameters of the radio have drifted out of calibration, usually due to a significant shift in ambient temperature or power supply (affecting the VCO stability).
•Each time the stack initializes after reboot (emberInit() call), TOKEN_STACK_BOOT_COUNTER is incremented (as per default implementation of halStackProcessBootCount() ).
Additionally, the following token write conditions apply only to EZSP firmware:
•If EZSP_SET_VALUE command is invoked successfully with valueId of EZSP_VALUE_TOKEN_STACK_NODE_DATA, a write to TOKEN_STACK_NODE_DATA will be performed.
•If EZSP_SET_TOKEN command is invoked successfully, an indexed write to TOKEN_EZSP_STORAGE will be performed.
Note that tokens can only be written in blocks as small as their intrinsic token type, meaning that the typedef used in the TOKEN_DEF macro (even if it is a 50-byte struct) is the amount of data that will be written each time halCommonSetToken() is called, regardless of how much (if at all) the new data value differs from the existing data value. For indexed tokens, every write command only impacts a single index's entry worth of data (not the entire table).
Note that the presence and size of application-defined tokens (from an APPLICATION_TOKEN_HEADER file) as well as the amount of application token writes (calls to halCommonSetToken(), halCommonSetIndexedToken() or halCommonIncrementCounterToken()) also impact the token system's lifetime, as these share space in NVM3 with stack tokens.
The above information should help to model the token system a bit better. However, you should be sure to consult Application Note 1135 ('Using Third Generation NonVolatile Memory (NVM3) Data Storage ') for some equations to help model the wear-leveling algorithm.