EmberNodeId ezspDecodeAddressResponse(uint8_t *response, EmberEUI64 eui64Return) { uint8_t *payload = response + ZDO_MESSAGE_OVERHEAD; if (payload[0] == EMBER_ZDP_SUCCESS) { MEMMOVE(eui64Return, payload + 1, EUI64_SIZE); return HIGH_LOW_TO_INT(payload[10], payload[9]); } else return EMBER_NULL_NODE_ID; }
static FibStatus fibFlashWrite(int32u address, int8u *data, int32u length, int32u dummy) { int32u i; int16u *ptr; FibStatus status = FIB_SUCCESS; // Address and length must be half-word aligned. if ((address & 1) || (length & 1)) { return FIB_ERR_UNALIGNED; } // Start and end address must be in MFB or CIB. if (!((address >= MFB_BOTTOM && address + length <= MFB_TOP + 1) || (address >= CIB_BOTTOM && address + length <= CIB_TOP + 1))) { return FIB_ERR_INVALID_ADDRESS; } enableFlitf(); ptr = (int16u *)address; for (i = 0; i < length; i += 2) { int16u currentData = *ptr; int16u newData = HIGH_LOW_TO_INT(data[i + 1], data[i]); // Only program the data if it makes sense to do so. if (currentData == newData) { // If the new data matches the flash, don't bother doing anything. } else if (currentData == 0xFFFF || newData == 0x0000) { // If the flash is 0xFFFF we're allowed to write anything. // If the new data is 0x0000 it doesn't matter what the flash is. // OPTWREN must stay set to keep CIB unlocked. if ((CIB_OB_BOTTOM <= (int32u)ptr) && ((int32u)ptr <= CIB_OB_TOP)) { FLASH_CTRL = (FLASH_CTRL_OPTWREN | FLASH_CTRL_OPTPROG); } else { FLASH_CTRL = (FLASH_CTRL_OPTWREN | FLASH_CTRL_PROG); } // Assigning data to the address performs the actual write. (*ptr) = newData; // Wait for the busy bit to clear, indicating operation is done. while ((FLASH_STATUS & FLASH_STATUS_FLA_BSY) != 0) {} // Reset the operation complete flag. FLASH_STATUS = FLASH_STATUS_EOP; // Check if any error bits have been tripped, and if so, exit. // The bit PAGE_PROG_ERR is not relevant in this programming mode. if (FLASH_STATUS & (FLASH_STATUS_WRP_ERR | FLASH_STATUS_PROG_ERR)) { if (FLASH_STATUS & FLASH_STATUS_WRP_ERR) { status = FIB_ERR_WRITE_PROTECTED; } else { status = FIB_ERR_WRITE_FAILED; } FLASH_STATUS = FLASH_STATUS_WRP_ERR; FLASH_STATUS = FLASH_STATUS_PROG_ERR; break; } } else { status = FIB_ERR_ERASE_REQUIRED; break; } ptr++; } disableFlitf(); return status; }
// A pairing index value of 0xFF means "local attributes". void emAfRf4ceZrcReadOrWriteAttribute(uint8_t pairingIndex, uint8_t attrId, uint16_t entryIdOrValueLength, bool isRead, uint8_t *val) { bool localAttributes = (pairingIndex == 0xFF); EmAfRf4ceZrcAttributes *attributes = (localAttributes) ? &emAfRf4ceZrcLocalNodeAttributes : &emAfRf4ceZrcRemoteNodeAttributes; if (isRead) { switch (attrId) { case EMBER_AF_RF4CE_ZRC_ATTRIBUTE_VERSION: val[0] = LOW_BYTE(attributes->zrcProfileVersion); val[1] = HIGH_BYTE(attributes->zrcProfileVersion); break; case EMBER_AF_RF4CE_ZRC_ATTRIBUTE_CAPABILITIES: { uint32_t cababilities = ((pairingIndex == 0xFF) ? emAfRf4ceZrcGetLocalNodeCapabilities() : emAfRf4ceZrcGetRemoteNodeCapabilities(pairingIndex)); val[0] = BYTE_0(cababilities); val[1] = BYTE_1(cababilities); val[2] = BYTE_2(cababilities); val[3] = BYTE_3(cababilities); } break; case EMBER_AF_RF4CE_ZRC_ATTRIBUTE_ACTION_BANKS_SUPPORTED_RX: MEMCOPY(val, attributes->actionBanksSupportedRx->contents, ZRC_BITMASK_SIZE); break; case EMBER_AF_RF4CE_ZRC_ATTRIBUTE_ACTION_BANKS_SUPPORTED_TX: MEMCOPY(val, attributes->actionBanksSupportedTx->contents, ZRC_BITMASK_SIZE); break; #if (defined(EMBER_AF_PLUGIN_RF4CE_ZRC20_LOCAL_IRDB_VENDOR_ATTRIBUTE_SUPPORT) \ || defined(EMBER_AF_PLUGIN_RF4CE_ZRC20_REMOTE_IRDB_VENDOR_ATTRIBUTES_SUPPORT) \ || defined(EMBER_SCRIPTED_TEST)) case EMBER_AF_RF4CE_ZRC_ATTRIBUTE_IRDB_VENDOR_SUPPORT: { // Can't just perform a MEMCOPY, endianness matters. uint8_t i; uint8_t entriesNum = (localAttributes ? EMBER_AF_RF4CE_ZRC_IRDB_VENDOR_ID_COUNT : EMBER_AF_PLUGIN_RF4CE_ZRC20_REMOTE_IRDB_VENDORS_SUPPORTED_TABLE_SIZE); // Non-valid entries are set to EMBER_RF4CE_NULL_VENDOR_ID. for(i=0; (i<entriesNum && attributes->IRDBVendorSupport[i] != EMBER_RF4CE_NULL_VENDOR_ID); i++) { val[2*i] = LOW_BYTE(attributes->IRDBVendorSupport[i]); val[2*i+1] = HIGH_BYTE(attributes->IRDBVendorSupport[i]); } } break; #endif // EMBER_AF_PLUGIN_RF4CE_ZRC20_LOCAL_IRDB_VENDOR_ATTRIBUTE_SUPPORT || EMBER_AF_PLUGIN_RF4CE_ZRC20_REMOTE_IRDB_VENDOR_ATTRIBUTES_SUPPORT case EMBER_AF_RF4CE_ZRC_ATTRIBUTE_ACTION_BANKS_VERSION: val[0] = LOW_BYTE(attributes->zrcActionBanksVersion); val[1] = HIGH_BYTE(attributes->zrcActionBanksVersion); break; case EMBER_AF_RF4CE_ZRC_ATTRIBUTE_ACTION_CODES_SUPPORTED_RX: #if (defined (EMBER_AF_RF4CE_ZRC_IS_HA_ACTIONS_RECIPIENT) || defined(EMBER_SCRIPTED_TEST)) // RX action codes related to HA action banks should be all 0xFF if the // node is an HA actions recipient. if (entryIdOrValueLength >= EMBER_AF_RF4CE_ZRC_ACTION_BANK_HOME_AUTOMATION_INSTANCE_0 && entryIdOrValueLength <= EMBER_AF_RF4CE_ZRC_ACTION_BANK_HOME_AUTOMATION_INSTANCE_31) { MEMSET(val, 0xFF, ZRC_BITMASK_SIZE); break; } // Fall-through here #endif // EMBER_AF_RF4CE_ZRC_IS_HA_ACTIONS_RECIPIENT case EMBER_AF_RF4CE_ZRC_ATTRIBUTE_ACTION_CODES_SUPPORTED_TX: { uint8_t *attrPtr = emAfRf4ceZrcGetActionCodesAttributePointer(attrId, entryIdOrValueLength, pairingIndex); assert(attrPtr != NULL); MEMCOPY(val, attrPtr, ZRC_BITMASK_SIZE); break; } #if defined(EMBER_AF_PLUGIN_RF4CE_ZRC20_ACTION_MAPPING_SUPPORT) || defined(EMBER_SCRIPTED_TEST) case EMBER_AF_RF4CE_ZRC_ATTRIBUTE_MAPPABLE_ACTIONS: { EmberAfRf4ceZrcMappableAction mappableAction; assert (emberAfPluginRf4ceZrc20GetMappableActionCallback(pairingIndex, entryIdOrValueLength, &mappableAction) == EMBER_SUCCESS); val[MAPPABLE_ACTION_ACTION_DEVICE_TYPE_OFFSET] = mappableAction.actionDeviceType; val[MAPPABLE_ACTION_ACTION_BANK_OFFSET] = mappableAction.actionBank; val[MAPPABLE_ACTION_ACTION_CODE_OFFSET] = mappableAction.actionCode; } break; case EMBER_AF_RF4CE_ZRC_ATTRIBUTE_ACTION_MAPPINGS: { EmberAfRf4ceZrcActionMapping actionMapping; assert (emberAfPluginRf4ceZrc20GetActionMappingCallback(pairingIndex, entryIdOrValueLength, &actionMapping) == EMBER_SUCCESS); *val++ = actionMapping.mappingFlags; if (READBITS(actionMapping.mappingFlags, (EMBER_AF_RF4CE_ZRC_ACTION_MAPPING_MAPPING_FLAGS_RF_SPECIFIED_BIT | EMBER_AF_RF4CE_ZRC_ACTION_MAPPING_MAPPING_FLAGS_USE_DEFAULT_BIT)) == EMBER_AF_RF4CE_ZRC_ACTION_MAPPING_MAPPING_FLAGS_RF_SPECIFIED_BIT) { *val++ = actionMapping.rfConfig; *val++ = actionMapping.rf4ceTxOptions; *val++ = actionMapping.actionDataLength; assert(actionMapping.actionData != NULL); MEMCOPY(val, actionMapping.actionData, actionMapping.actionDataLength); val += actionMapping.actionDataLength; } if (READBITS(actionMapping.mappingFlags, (EMBER_AF_RF4CE_ZRC_ACTION_MAPPING_MAPPING_FLAGS_IR_SPECIFIED_BIT | EMBER_AF_RF4CE_ZRC_ACTION_MAPPING_MAPPING_FLAGS_USE_DEFAULT_BIT)) == EMBER_AF_RF4CE_ZRC_ACTION_MAPPING_MAPPING_FLAGS_IR_SPECIFIED_BIT) { *val++ = actionMapping.irConfig; if (actionMapping.irConfig & ACTION_MAPPING_IR_CONFIG_VENDOR_SPECIFIC_BIT) { *val++ = LOW_BYTE(actionMapping.irVendorId); *val++ = HIGH_BYTE(actionMapping.irVendorId); } *val++ = actionMapping.irCodeLength; assert(actionMapping.irCode != NULL); MEMCOPY(val, actionMapping.irCode, actionMapping.irCodeLength); } } break; #endif // EMBER_AF_PLUGIN_RF4CE_ZRC20_ACTION_MAPPING_SUPPORT #if (defined(EMBER_AF_RF4CE_ZRC_IS_HA_ACTIONS_ORIGINATOR) \ || defined (EMBER_AF_RF4CE_ZRC_IS_HA_ACTIONS_RECIPIENT) \ || defined(EMBER_SCRIPTED_TEST)) case EMBER_AF_RF4CE_ZRC_ATTRIBUTE_HOME_AUTOMATION: // This attribute can only be pulled and is stored at the application. // This plugin can only access this attribute via callback. As result, // we will get here only after having called (and it returns 'success') // emAfRf4ceZrcIsArrayedAttributeSupported() in the pullAttributes() // handler function. emAfRf4ceZrcIsArrayedAttributeSupported() saves the // contents in the static object tempHaAttribute. So we just copy it // here. assert(tempHaAttribute.contentsLength < (MAX_ZRC_ATTRIBUTE_SIZE - 1)); *val++ = HA_ATTRIBUTE_STATUS_VALUE_AVAILABLE_FLAG; MEMCOPY(val, tempHaAttribute.contents, tempHaAttribute.contentsLength); break; case EMBER_AF_RF4CE_ZRC_ATTRIBUTE_HOME_AUTOMATION_SUPPORTED: emberAfPluginRf4ceZrc20GetHomeAutomationSupportedCallback(pairingIndex, entryIdOrValueLength, (EmberAfRf4ceZrcHomeAutomationSupported*)val); break; #endif // EMBER_AF_RF4CE_ZRC_IS_HA_ACTIONS_ORIGINATOR || EMBER_AF_RF4CE_ZRC_IS_HA_ACTIONS_RECIPIENT } } else { // !isRead switch (attrId) { case EMBER_AF_RF4CE_ZRC_ATTRIBUTE_VERSION: attributes->zrcProfileVersion = HIGH_LOW_TO_INT(val[1], val[0]); break; case EMBER_AF_RF4CE_ZRC_ATTRIBUTE_CAPABILITIES: // We only allow setting remote nodes capabilities. if (pairingIndex < 0xFF) { emAfRf4ceZrcSetRemoteNodeCapabilities(pairingIndex, emberFetchLowHighInt32u(val)); } break; case EMBER_AF_RF4CE_ZRC_ATTRIBUTE_ACTION_BANKS_SUPPORTED_RX: MEMCOPY(attributes->actionBanksSupportedRx->contents, val, ZRC_BITMASK_SIZE); break; case EMBER_AF_RF4CE_ZRC_ATTRIBUTE_ACTION_BANKS_SUPPORTED_TX: MEMCOPY(attributes->actionBanksSupportedTx->contents, val, ZRC_BITMASK_SIZE); break; #if defined(EMBER_AF_PLUGIN_RF4CE_ZRC20_REMOTE_IRDB_VENDOR_ATTRIBUTES_SUPPORT) || defined(EMBER_SCRIPTED_TEST) case EMBER_AF_RF4CE_ZRC_ATTRIBUTE_IRDB_VENDOR_SUPPORT: { // Only remote IRDB vendor support attributes can written. uint8_t i; for (i=0; i < EMBER_AF_PLUGIN_RF4CE_ZRC20_REMOTE_IRDB_VENDORS_SUPPORTED_TABLE_SIZE; i++) { uint16_t vendorId; if (i < entryIdOrValueLength / 2) { vendorId = HIGH_LOW_TO_INT(val[2*i+1], val[2*i]); } else { // The rest of the entries are set to NULL_VENDOR_ID. vendorId = EMBER_RF4CE_NULL_VENDOR_ID; } attributes->IRDBVendorSupport[i] = vendorId; #if defined(EMBER_SCRIPTED_TEST) simpleScriptCheck("", "Remote IRDB attribute, entry set", "ii", i, vendorId); #endif // EMBER_SCRIPTED_TEST } } break; #endif // EMBER_AF_PLUGIN_RF4CE_ZRC20_REMOTE_IRDB_VENDOR_ATTRIBUTES_SUPPORT case EMBER_AF_RF4CE_ZRC_ATTRIBUTE_ACTION_BANKS_VERSION: attributes->zrcActionBanksVersion = HIGH_LOW_TO_INT(val[1], val[0]); break; case EMBER_AF_RF4CE_ZRC_ATTRIBUTE_ACTION_CODES_SUPPORTED_RX: case EMBER_AF_RF4CE_ZRC_ATTRIBUTE_ACTION_CODES_SUPPORTED_TX: { uint8_t *attrPtr = emAfRf4ceZrcGetActionCodesAttributePointer(attrId, entryIdOrValueLength, pairingIndex); assert(attrPtr != NULL); MEMCOPY(attrPtr, val, ZRC_BITMASK_SIZE); break; } #if defined(EMBER_AF_PLUGIN_RF4CE_ZRC20_ACTION_MAPPING_SUPPORT) || defined(EMBER_SCRIPTED_TEST) case EMBER_AF_RF4CE_ZRC_ATTRIBUTE_MAPPABLE_ACTIONS: { EmberAfRf4ceZrcMappableAction mappableAction; mappableAction.actionDeviceType = val[0]; mappableAction.actionBank = val[1]; mappableAction.actionCode = val[2]; emberAfPluginRf4ceZrc20IncomingMappableActionCallback(emberAfRf4ceGetPairingIndex(), entryIdOrValueLength, &mappableAction); } break; case EMBER_AF_RF4CE_ZRC_ATTRIBUTE_ACTION_MAPPINGS: { EmberAfRf4ceZrcActionMapping actionMapping; uint8_t *finger = val; actionMapping.actionData = NULL; actionMapping.irCode = NULL; // Mapping flags actionMapping.mappingFlags = *finger++; // RF descriptor if (READBITS(actionMapping.mappingFlags, (EMBER_AF_RF4CE_ZRC_ACTION_MAPPING_MAPPING_FLAGS_RF_SPECIFIED_BIT | EMBER_AF_RF4CE_ZRC_ACTION_MAPPING_MAPPING_FLAGS_USE_DEFAULT_BIT)) == EMBER_AF_RF4CE_ZRC_ACTION_MAPPING_MAPPING_FLAGS_RF_SPECIFIED_BIT) { actionMapping.rfConfig = *finger++; actionMapping.rf4ceTxOptions = *finger++; actionMapping.actionDataLength = *finger++; actionMapping.actionData = finger; finger += actionMapping.actionDataLength; } // IR descriptor if (READBITS(actionMapping.mappingFlags, (EMBER_AF_RF4CE_ZRC_ACTION_MAPPING_MAPPING_FLAGS_IR_SPECIFIED_BIT | EMBER_AF_RF4CE_ZRC_ACTION_MAPPING_MAPPING_FLAGS_USE_DEFAULT_BIT)) == EMBER_AF_RF4CE_ZRC_ACTION_MAPPING_MAPPING_FLAGS_IR_SPECIFIED_BIT) { actionMapping.irConfig = *finger++; if (actionMapping.irConfig & ACTION_MAPPING_IR_CONFIG_VENDOR_SPECIFIC_BIT) { actionMapping.irVendorId = HIGH_LOW_TO_INT(finger[1], finger[0]); finger += 2; } actionMapping.irCodeLength = *finger++; actionMapping.irCode = finger; } emberAfPluginRf4ceZrc20IncomingActionMappingCallback(emberAfRf4ceGetPairingIndex(), entryIdOrValueLength, &actionMapping); } break; #endif // EMBER_AF_PLUGIN_RF4CE_ZRC20_ACTION_MAPPING_SUPPORT #if (defined(EMBER_AF_RF4CE_ZRC_IS_HA_ACTIONS_ORIGINATOR) \ || defined (EMBER_AF_RF4CE_ZRC_IS_HA_ACTIONS_RECIPIENT) \ || defined(EMBER_SCRIPTED_TEST)) // EMBER_AF_RF4CE_ZRC_ATTRIBUTE_HOME_AUTOMATION attributes sets are handled // in the HA action code. case EMBER_AF_RF4CE_ZRC_ATTRIBUTE_HOME_AUTOMATION_SUPPORTED: emberAfPluginRf4ceZrc20IncomingHomeAutomationSupportedCallback(emberAfRf4ceGetPairingIndex(), entryIdOrValueLength, (EmberAfRf4ceZrcHomeAutomationSupported*)val); break; #endif // EMBER_AF_RF4CE_ZRC_IS_HA_ACTIONS_ORIGINATOR || EMBER_AF_RF4CE_ZRC_IS_HA_ACTIONS_RECIPIENT } } }