From 1dcc358a756c1f56e15ac06da3964d573a575af2 Mon Sep 17 00:00:00 2001 From: Michael Spang Date: Thu, 5 Nov 2020 12:07:30 -0500 Subject: [PATCH 001/234] Bring back image referenced by nRF examples (#3655) This was deleted in #3605 but is still referenced by examples/{lighting,lock}-app/nrfconnect/README.md. Restore this file and move it to examples/platform/nrfconnect. --- examples/lighting-app/nrfconnect/README.md | 2 +- examples/lock-app/nrfconnect/README.md | 2 +- .../nrfconnect/doc/images/nrf52840-dk.jpg | Bin 0 -> 224065 bytes 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100755 examples/platform/nrfconnect/doc/images/nrf52840-dk.jpg diff --git a/examples/lighting-app/nrfconnect/README.md b/examples/lighting-app/nrfconnect/README.md index 20ddbde449605f..c8878b4f86b89f 100644 --- a/examples/lighting-app/nrfconnect/README.md +++ b/examples/lighting-app/nrfconnect/README.md @@ -22,7 +22,7 @@ An example application showing the use ## Introduction -![nrf52840 DK](../../platform/nrf528xx/doc/images/nrf52840-dk.jpg) +![nrf52840 DK](../../platform/nrfconnect/doc/images/nrf52840-dk.jpg) The nRF52840 lighting example application provides a working demonstration of a connected lighting device, built using CHIP, and the Nordic nRF Connect SDK. The diff --git a/examples/lock-app/nrfconnect/README.md b/examples/lock-app/nrfconnect/README.md index 246941b1140af5..fe137449a99923 100644 --- a/examples/lock-app/nrfconnect/README.md +++ b/examples/lock-app/nrfconnect/README.md @@ -22,7 +22,7 @@ An example application showing the use ## Introduction -![nrf52840 DK](../../platform/nrf528xx/doc/images/nrf52840-dk.jpg) +![nrf52840 DK](../../platform/nrfconnect/doc/images/nrf52840-dk.jpg) The nRF52840 lock example application provides a working demonstration of a connected door lock device, built using CHIP, and the Nordic nRF Connect. The diff --git a/examples/platform/nrfconnect/doc/images/nrf52840-dk.jpg b/examples/platform/nrfconnect/doc/images/nrf52840-dk.jpg new file mode 100755 index 0000000000000000000000000000000000000000..0231be503b48640a95be79570e679de56fe914bb GIT binary patch literal 224065 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�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 literal 0 HcmV?d00001 From d006b0a4ee21afa4943688d7ea54b3b9f73980d8 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Thu, 5 Nov 2020 13:12:09 -0500 Subject: [PATCH 002/234] Make various src/app code compile with -Wconversion (#3681) We don't actually enable -Wconversion for this code yet, because it's compiled directly into example apps, so we would need to enable -Wconversion for those, and they aren't quite there. --- .../server/esp32/main/gen/callback.h | 2 +- .../barrier-control-server.cpp | 21 +++---- .../color-control-server.cpp | 22 +++---- .../door-lock-server-logging.cpp | 2 +- .../door-lock-server-user.cpp | 2 +- .../door-lock-server/door-lock-server.h | 2 +- .../clusters/groups-server/groups-server.cpp | 4 +- .../ias-zone-server/ias-zone-server.cpp | 2 +- src/app/clusters/identify/identify.cpp | 2 +- .../clusters/level-control/level-control.cpp | 14 ++--- .../clusters/scenes-client/scenes-client.cpp | 15 ++--- src/app/clusters/scenes/scenes.cpp | 50 ++++++++-------- .../temperature-measurement-server.cpp | 6 +- src/app/reporting/reporting.cpp | 37 ++++++------ src/app/reporting/reporting.h | 3 + src/app/util/af-main-common.cpp | 8 ++- src/app/util/af-types.h | 4 +- src/app/util/attribute-size.cpp | 4 +- src/app/util/attribute-storage.cpp | 33 +++++------ src/app/util/attribute-storage.h | 2 +- src/app/util/attribute-table.cpp | 9 +-- src/app/util/chip-message-send.cpp | 7 ++- src/app/util/client-api.cpp | 10 ++-- src/app/util/esi-management.h | 2 +- src/app/util/message.cpp | 4 +- src/app/util/process-global-message.cpp | 57 +++++++++++-------- src/app/util/util.cpp | 49 ++++++++-------- 27 files changed, 202 insertions(+), 171 deletions(-) diff --git a/examples/wifi-echo/server/esp32/main/gen/callback.h b/examples/wifi-echo/server/esp32/main/gen/callback.h index aed4de67a17855..335ab321e29473 100644 --- a/examples/wifi-echo/server/esp32/main/gen/callback.h +++ b/examples/wifi-echo/server/esp32/main/gen/callback.h @@ -14601,7 +14601,7 @@ void emberAfIasZoneClusterServerManufacturerSpecificAttributeChangedCallback(uin * @param message The message that was sent Ver.: always * @param status The status of the sent message Ver.: always */ -void emberAfIasZoneClusterServerMessageSentCallback(EmberOutgoingMessageType type, uint16_t indexOrDestination, +void emberAfIasZoneClusterServerMessageSentCallback(EmberOutgoingMessageType type, uint64_t indexOrDestination, EmberApsFrame * apsFrame, uint16_t msgLen, uint8_t * message, EmberStatus status); /** @brief IAS Zone Cluster Server Pre Attribute Changed diff --git a/src/app/clusters/barrier-control-server/barrier-control-server.cpp b/src/app/clusters/barrier-control-server/barrier-control-server.cpp index 48502602cb1a7f..e1dd3a1038ceb4 100644 --- a/src/app/clusters/barrier-control-server/barrier-control-server.cpp +++ b/src/app/clusters/barrier-control-server/barrier-control-server.cpp @@ -172,7 +172,7 @@ void emAfPluginBarrierControlServerIncrementEvents(uint8_t endpoint, bool open, { if (READBIT(mask, bit)) { - EmberAfAttributeId attributeId = baseEventAttributeId + bit; + EmberAfAttributeId attributeId = static_cast(baseEventAttributeId + bit); uint16_t events; EmberAfStatus status = emberAfReadServerAttribute(endpoint, ZCL_BARRIER_CONTROL_CLUSTER_ID, attributeId, (uint8_t *) &events, sizeof(events)); @@ -203,15 +203,15 @@ static uint8_t getCurrentPosition(uint8_t endpoint) // open so that we don't leave the barrier open when it should be closed. uint8_t currentPositionFromAttribute = emAfPluginBarrierControlServerGetBarrierPosition(endpoint); return ((currentPositionFromAttribute == EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_UNKNOWN) - ? EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_OPEN + ? static_cast(EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_OPEN) : currentPositionFromAttribute); } static uint32_t calculateDelayMs(uint8_t endpoint, uint8_t targetPosition, bool * opening) { - uint8_t currentPosition = emAfPluginBarrierControlServerGetBarrierPosition(endpoint); - *opening = targetPosition > currentPosition; - uint8_t positionDelta = (*opening ? targetPosition - currentPosition : currentPosition - targetPosition); + uint8_t currentPosition = emAfPluginBarrierControlServerGetBarrierPosition(endpoint); + *opening = targetPosition > currentPosition; + uint8_t positionDelta = static_cast(*opening ? targetPosition - currentPosition : currentPosition - targetPosition); uint16_t openOrClosePeriodDs = getOpenOrClosePeriod(endpoint, *opening); uint32_t openOrClosePeriodMs = openOrClosePeriodDs * MILLISECOND_TICKS_PER_DECISECOND; @@ -228,7 +228,7 @@ static uint32_t calculateDelayMs(uint8_t endpoint, uint8_t targetPosition, bool } } -void emberAfBarrierControlClusterServerTickCallback(uint8_t endpoint) +void emberAfBarrierControlClusterServerTickCallback(CHIPEndpointId endpoint) { if (state.currentPosition == state.targetPosition) { @@ -254,10 +254,11 @@ void emberAfBarrierControlClusterServerTickCallback(uint8_t endpoint) emAfPluginBarrierControlServerIncrementEvents(endpoint, false, false); } } - emAfPluginBarrierControlServerSetBarrierPosition(endpoint, - (emAfPluginBarrierControlServerIsPartialBarrierSupported(endpoint) - ? state.currentPosition - : EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_UNKNOWN)); + emAfPluginBarrierControlServerSetBarrierPosition( + endpoint, + (emAfPluginBarrierControlServerIsPartialBarrierSupported(endpoint) + ? state.currentPosition + : static_cast(EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_UNKNOWN))); setMovingState( endpoint, (state.increasing ? EMBER_ZCL_BARRIER_CONTROL_MOVING_STATE_OPENING : EMBER_ZCL_BARRIER_CONTROL_MOVING_STATE_CLOSING)); diff --git a/src/app/clusters/color-control-server/color-control-server.cpp b/src/app/clusters/color-control-server/color-control-server.cpp index c161a4d9bee9f7..2fc6266c82b153 100644 --- a/src/app/clusters/color-control-server/color-control-server.cpp +++ b/src/app/clusters/color-control-server/color-control-server.cpp @@ -777,7 +777,7 @@ static uint8_t addSaturation(uint8_t saturation1, uint8_t saturation2) uint16_t saturation16; saturation16 = ((uint16_t) saturation1); - saturation16 += ((uint16_t) saturation2); + saturation16 = static_cast(saturation16 + static_cast(saturation2)); if (saturation16 > MAX_SATURATION_VALUE) { @@ -794,7 +794,7 @@ static uint8_t subtractSaturation(uint8_t saturation1, uint8_t saturation2) return 0; } - return saturation1 - saturation2; + return static_cast(saturation1 - saturation2); } // any time we call a hue or saturation transition, we need to assume certain @@ -1256,11 +1256,11 @@ bool emberAfColorControlClusterStepColorTemperatureCallback(uint8_t stepMode, ui colorTempTransitionState.currentValue = readColorTemperature(endpoint); if (stepMode == MOVE_MODE_UP) { - colorTempTransitionState.finalValue = readColorTemperature(endpoint) + stepSize; + colorTempTransitionState.finalValue = static_cast(readColorTemperature(endpoint) + stepSize); } else { - colorTempTransitionState.finalValue = readColorTemperature(endpoint) - stepSize; + colorTempTransitionState.finalValue = static_cast(readColorTemperature(endpoint) - stepSize); } colorTempTransitionState.stepsRemaining = transitionTime; colorTempTransitionState.stepsTotal = transitionTime; @@ -1395,7 +1395,7 @@ static void handleModeSwitch(uint8_t endpoint, uint8_t newColorMode) writeColorMode(endpoint, newColorMode); } - colorModeTransition = (newColorMode << 4) + oldColorMode; + colorModeTransition = static_cast((newColorMode << 4) + oldColorMode); // Note: It may be OK to not do anything here. switch (colorModeTransition) @@ -1433,11 +1433,11 @@ static uint8_t addHue(uint8_t hue1, uint8_t hue2) uint16_t hue16; hue16 = ((uint16_t) hue1); - hue16 += ((uint16_t) hue2); + hue16 = static_cast(hue16 + static_cast(hue2)); if (hue16 > MAX_HUE_VALUE) { - hue16 -= MAX_HUE_VALUE; + hue16 = static_cast(hue16 - MAX_HUE_VALUE); } return ((uint8_t) hue16); @@ -1450,10 +1450,10 @@ static uint8_t subtractHue(uint8_t hue1, uint8_t hue2) hue16 = ((uint16_t) hue1); if (hue2 > hue1) { - hue16 += MAX_HUE_VALUE; + hue16 = static_cast(hue16 + MAX_HUE_VALUE); } - hue16 -= ((uint16_t) hue2); + hue16 = static_cast(hue16 - static_cast(hue2)); return ((uint8_t) hue16); } @@ -1580,14 +1580,14 @@ static bool computeNewColor16uValue(Color16uTransitionState * p) newValue32u = ((uint32_t)(p->finalValue - p->initialValue)); newValue32u *= ((uint32_t)(p->stepsRemaining)); newValue32u /= ((uint32_t)(p->stepsTotal)); - p->currentValue = p->finalValue - ((uint16_t)(newValue32u)); + p->currentValue = static_cast(p->finalValue - static_cast(newValue32u)); } else { newValue32u = ((uint32_t)(p->initialValue - p->finalValue)); newValue32u *= ((uint32_t)(p->stepsRemaining)); newValue32u /= ((uint32_t)(p->stepsTotal)); - p->currentValue = p->finalValue + ((uint16_t)(newValue32u)); + p->currentValue = static_cast(p->finalValue + static_cast(newValue32u)); } if (p->stepsRemaining == 0) diff --git a/src/app/clusters/door-lock-server/door-lock-server-logging.cpp b/src/app/clusters/door-lock-server/door-lock-server-logging.cpp index 2f129d7c13314d..acacab409d81b2 100644 --- a/src/app/clusters/door-lock-server/door-lock-server-logging.cpp +++ b/src/app/clusters/door-lock-server/door-lock-server-logging.cpp @@ -101,7 +101,7 @@ bool emberAfPluginDoorLockServerGetLogEntry(uint16_t * entryId, EmberAfPluginDoo if (!ENTRY_ID_IS_VALID(*entryId)) { - *entryId = MOST_RECENT_ENTRY_ID(); + *entryId = static_cast(MOST_RECENT_ENTRY_ID()); } assert(ENTRY_ID_IS_VALID(*entryId)); diff --git a/src/app/clusters/door-lock-server/door-lock-server-user.cpp b/src/app/clusters/door-lock-server/door-lock-server-user.cpp index e9ec8294532787..f7a96743c1d593 100644 --- a/src/app/clusters/door-lock-server/door-lock-server-user.cpp +++ b/src/app/clusters/door-lock-server/door-lock-server-user.cpp @@ -55,7 +55,7 @@ static EmberAfPluginDoorLockServerUser rfidUserTable[EMBER_AF_PLUGIN_DOOR_LOCK_S // This is the current number of invalid PIN/RFID's in a row. static uint8_t wrongCodeEntryCount = 0; -bool emAfPluginDoorLockServerCheckForSufficientSpace(uint8_t spaceReq, uint8_t spaceAvail) +bool emAfPluginDoorLockServerCheckForSufficientSpace(uint16_t spaceReq, uint8_t spaceAvail) { if (spaceReq > spaceAvail) { diff --git a/src/app/clusters/door-lock-server/door-lock-server.h b/src/app/clusters/door-lock-server/door-lock-server.h index 9ecdb1efa7775d..ca147b1b239082 100644 --- a/src/app/clusters/door-lock-server/door-lock-server.h +++ b/src/app/clusters/door-lock-server/door-lock-server.h @@ -228,7 +228,7 @@ typedef struct // space available (spaceAvail) and if so it will send a DefaultResponse // command with the status of EMBER_ZCL_STATUS_INSUFFICIENT_SPACE and return // false. Otherwise, it will return true. -bool emAfPluginDoorLockServerCheckForSufficientSpace(uint8_t spaceReq, uint8_t spaceAvail); +bool emAfPluginDoorLockServerCheckForSufficientSpace(uint16_t spaceReq, uint8_t spaceAvail); #endif // Critical Message Queue diff --git a/src/app/clusters/groups-server/groups-server.cpp b/src/app/clusters/groups-server/groups-server.cpp index f850b29aa85245..d742659c52e057 100644 --- a/src/app/clusters/groups-server/groups-server.cpp +++ b/src/app/clusters/groups-server/groups-server.cpp @@ -225,7 +225,7 @@ bool emberAfGroupsClusterGetGroupMembershipCallback(uint8_t groupCount, uint8_t { list[listLen] = LOW_BYTE(entry.groupId); list[listLen + 1] = HIGH_BYTE(entry.groupId); - listLen += 2; + listLen = static_cast(listLen + 2); count++; } } @@ -245,7 +245,7 @@ bool emberAfGroupsClusterGetGroupMembershipCallback(uint8_t groupCount, uint8_t { list[listLen] = LOW_BYTE(groupId); list[listLen + 1] = HIGH_BYTE(groupId); - listLen += 2; + listLen = static_cast(listLen + 2); count++; } } diff --git a/src/app/clusters/ias-zone-server/ias-zone-server.cpp b/src/app/clusters/ias-zone-server/ias-zone-server.cpp index cbbe57c8bf9300..11a8822e70eec5 100644 --- a/src/app/clusters/ias-zone-server/ias-zone-server.cpp +++ b/src/app/clusters/ias-zone-server/ias-zone-server.cpp @@ -752,7 +752,7 @@ void emberAfPluginIasZoneServerPrintQueueConfig(void) // destination when the destination is the only router the node is joined to. // In that case, the command will never have been sent, as the device will have // had no router by which to send the command. -void emberAfIasZoneClusterServerMessageSentCallback(EmberOutgoingMessageType type, uint16_t indexOrDestination, +void emberAfIasZoneClusterServerMessageSentCallback(EmberOutgoingMessageType type, uint64_t indexOrDestination, EmberApsFrame * apsFrame, uint16_t msgLen, uint8_t * message, EmberStatus status) { diff --git a/src/app/clusters/identify/identify.cpp b/src/app/clusters/identify/identify.cpp index 7d72d41045b1ba..ec1f2c7b808f3c 100644 --- a/src/app/clusters/identify/identify.cpp +++ b/src/app/clusters/identify/identify.cpp @@ -83,7 +83,7 @@ void emberAfIdentifyClusterServerTickCallback(uint8_t endpoint) // This tick writes the new attribute, which will trigger the Attribute // Changed callback below, which in turn will schedule or cancel the tick. // Because of this, the tick does not have to be scheduled here. - writeIdentifyTime(endpoint, (identifyTime == 0 ? 0 : identifyTime - 1)); + writeIdentifyTime(endpoint, static_cast(identifyTime == 0 ? 0 : identifyTime - 1)); } } diff --git a/src/app/clusters/level-control/level-control.cpp b/src/app/clusters/level-control/level-control.cpp index 2e1e9695240e77..0216cf311b0d54 100644 --- a/src/app/clusters/level-control/level-control.cpp +++ b/src/app/clusters/level-control/level-control.cpp @@ -260,7 +260,7 @@ extern "C" void emberAfLevelControlClusterServerTickCallback(uint8_t endpoint) } else { - writeRemainingTime(endpoint, state->transitionTimeMs - state->elapsedTimeMs); + writeRemainingTime(endpoint, static_cast(state->transitionTimeMs - state->elapsedTimeMs)); schedule(endpoint, state->eventDurationMs); } } @@ -514,12 +514,12 @@ static void moveToLevelHandler(uint8_t commandId, uint8_t level, uint16_t transi goto send_default_response; } state->increasing = true; - actualStepSize = state->moveToLevel - currentLevel; + actualStepSize = static_cast(state->moveToLevel - currentLevel); } else { state->increasing = false; - actualStepSize = currentLevel - state->moveToLevel; + actualStepSize = static_cast(currentLevel - state->moveToLevel); } // If the Transition time field takes the value 0xFFFF, then the time taken @@ -623,7 +623,7 @@ static void moveHandler(uint8_t commandId, uint8_t moveMode, uint8_t rate, uint8 case EMBER_ZCL_MOVE_MODE_UP: state->increasing = true; state->moveToLevel = MAX_LEVEL; - difference = MAX_LEVEL - currentLevel; + difference = static_cast(MAX_LEVEL - currentLevel); break; case EMBER_ZCL_MOVE_MODE_DOWN: state->increasing = false; @@ -737,11 +737,11 @@ static void stepHandler(uint8_t commandId, uint8_t stepMode, uint8_t stepSize, u if (MAX_LEVEL - currentLevel < stepSize) { state->moveToLevel = MAX_LEVEL; - actualStepSize = (MAX_LEVEL - currentLevel); + actualStepSize = static_cast(MAX_LEVEL - currentLevel); } else { - state->moveToLevel = currentLevel + stepSize; + state->moveToLevel = static_cast(currentLevel + stepSize); } break; case EMBER_ZCL_STEP_MODE_DOWN: @@ -753,7 +753,7 @@ static void stepHandler(uint8_t commandId, uint8_t stepMode, uint8_t stepSize, u } else { - state->moveToLevel = currentLevel - stepSize; + state->moveToLevel = static_cast(currentLevel - stepSize); } break; default: diff --git a/src/app/clusters/scenes-client/scenes-client.cpp b/src/app/clusters/scenes-client/scenes-client.cpp index e6eb1f3d4c9625..8092983e267911 100644 --- a/src/app/clusters/scenes-client/scenes-client.cpp +++ b/src/app/clusters/scenes-client/scenes-client.cpp @@ -119,9 +119,10 @@ bool emberAfPluginScenesClientParseViewSceneResponse(const EmberAfClusterCommand // the payload if the status is SUCCESS. if (status == EMBER_ZCL_STATUS_SUCCESS) { - uint16_t extensionFieldSetsLen = (emberAfCurrentCommand()->bufLen - - (emberAfCurrentCommand()->payloadStartIndex + sizeof(status) + sizeof(groupId) + - sizeof(sceneId) + sizeof(transitionTime) + emberAfStringLength(sceneName) + 1)); + uint16_t extensionFieldSetsLen = + static_cast(emberAfCurrentCommand()->bufLen - + (emberAfCurrentCommand()->payloadStartIndex + sizeof(status) + sizeof(groupId) + sizeof(sceneId) + + sizeof(transitionTime) + emberAfStringLength(sceneName) + 1)); uint16_t extensionFieldSetsIndex = 0; emberAfScenesClusterPrint(", 0x%2x, \"", transitionTime); @@ -134,9 +135,9 @@ bool emberAfPluginScenesClientParseViewSceneResponse(const EmberAfClusterCommand { EmberAfClusterId clusterId; uint8_t length; - clusterId = emberAfGetInt16u(extensionFieldSets, extensionFieldSetsIndex, extensionFieldSetsLen); - extensionFieldSetsIndex += 2; - length = emberAfGetInt8u(extensionFieldSets, extensionFieldSetsIndex, extensionFieldSetsLen); + clusterId = emberAfGetInt16u(extensionFieldSets, extensionFieldSetsIndex, extensionFieldSetsLen); + extensionFieldSetsIndex = static_cast(extensionFieldSetsIndex + 2); + length = emberAfGetInt8u(extensionFieldSets, extensionFieldSetsIndex, extensionFieldSetsLen); extensionFieldSetsIndex++; emberAfScenesClusterPrint(" [0x%2x 0x%x ", clusterId, length); if (extensionFieldSetsIndex + length <= extensionFieldSetsLen) @@ -145,7 +146,7 @@ bool emberAfPluginScenesClientParseViewSceneResponse(const EmberAfClusterCommand } emberAfScenesClusterPrint("]"); emberAfScenesClusterFlush(); - extensionFieldSetsIndex += length; + extensionFieldSetsIndex = static_cast(extensionFieldSetsIndex + length); } } diff --git a/src/app/clusters/scenes/scenes.cpp b/src/app/clusters/scenes/scenes.cpp index d8c001308860f7..551702616400db 100644 --- a/src/app/clusters/scenes/scenes.cpp +++ b/src/app/clusters/scenes/scenes.cpp @@ -684,10 +684,10 @@ bool emberAfPluginScenesServerParseAddScene(const EmberAfClusterCommand * cmd, G EmberAfSceneTableEntry entry; EmberAfStatus status; EmberStatus sendStatus; - bool enhanced = (cmd->commandId == ZCL_ENHANCED_ADD_SCENE_COMMAND_ID); - uint16_t extensionFieldSetsLen = (cmd->bufLen - - (cmd->payloadStartIndex + sizeof(groupId) + sizeof(sceneId) + sizeof(transitionTime) + - emberAfStringLength(sceneName) + 1)); + bool enhanced = (cmd->commandId == ZCL_ENHANCED_ADD_SCENE_COMMAND_ID); + uint16_t extensionFieldSetsLen = static_cast( + cmd->bufLen - + (cmd->payloadStartIndex + sizeof(groupId) + sizeof(sceneId) + sizeof(transitionTime) + emberAfStringLength(sceneName) + 1)); uint16_t extensionFieldSetsIndex = 0; uint8_t endpoint = cmd->apsFrame->destinationEndpoint; uint8_t i, index = EMBER_AF_SCENE_TABLE_NULL_INDEX; @@ -793,9 +793,9 @@ bool emberAfPluginScenesServerParseAddScene(const EmberAfClusterCommand * cmd, G goto kickout; } - clusterId = emberAfGetInt16u(extensionFieldSets, extensionFieldSetsIndex, extensionFieldSetsLen); - extensionFieldSetsIndex += 2; - length = emberAfGetInt8u(extensionFieldSets, extensionFieldSetsIndex, extensionFieldSetsLen); + clusterId = emberAfGetInt16u(extensionFieldSets, extensionFieldSetsIndex, extensionFieldSetsLen); + extensionFieldSetsIndex = static_cast(extensionFieldSetsIndex + 2); + length = emberAfGetInt8u(extensionFieldSets, extensionFieldSetsIndex, extensionFieldSetsLen); extensionFieldSetsIndex++; // If the length is off, the command is also malformed. @@ -866,10 +866,10 @@ bool emberAfPluginScenesServerParseAddScene(const EmberAfClusterCommand * cmd, G { break; } - entry.hasCurrentXValue = true; - entry.currentXValue = emberAfGetInt16u(extensionFieldSets, extensionFieldSetsIndex, extensionFieldSetsLen); - extensionFieldSetsIndex += 2; - length -= 2; + entry.hasCurrentXValue = true; + entry.currentXValue = emberAfGetInt16u(extensionFieldSets, extensionFieldSetsIndex, extensionFieldSetsLen); + extensionFieldSetsIndex = static_cast(extensionFieldSetsIndex + 2); + length = static_cast(length - 2); if (length < 2) { break; @@ -878,8 +878,9 @@ bool emberAfPluginScenesServerParseAddScene(const EmberAfClusterCommand * cmd, G entry.currentYValue = emberAfGetInt16u(extensionFieldSets, extensionFieldSetsIndex, extensionFieldSetsLen); if (enhanced) { - extensionFieldSetsIndex += 2; - length -= 2; + extensionFieldSetsIndex = static_cast(extensionFieldSetsIndex + 2); + length = static_cast(length - 2); + ; if (length < 2) { break; @@ -887,8 +888,8 @@ bool emberAfPluginScenesServerParseAddScene(const EmberAfClusterCommand * cmd, G entry.hasEnhancedCurrentHueValue = true; entry.enhancedCurrentHueValue = emberAfGetInt16u(extensionFieldSets, extensionFieldSetsIndex, extensionFieldSetsLen); - extensionFieldSetsIndex += 2; - length -= 2; + extensionFieldSetsIndex = static_cast(extensionFieldSetsIndex + 2); + length = static_cast(length - 2); if (length < 1) { break; @@ -919,8 +920,8 @@ bool emberAfPluginScenesServerParseAddScene(const EmberAfClusterCommand * cmd, G } entry.hasColorLoopTimeValue = true; entry.colorLoopTimeValue = emberAfGetInt16u(extensionFieldSets, extensionFieldSetsIndex, extensionFieldSetsLen); - extensionFieldSetsIndex += 2; - length -= 2; + extensionFieldSetsIndex = static_cast(extensionFieldSetsIndex + 2); + length = static_cast(length - 2); if (length < 2) { break; @@ -967,7 +968,7 @@ bool emberAfPluginScenesServerParseAddScene(const EmberAfClusterCommand * cmd, G break; } - extensionFieldSetsIndex += length; + extensionFieldSetsIndex = static_cast(extensionFieldSetsIndex + length); } // If we got this far, we either added a new entry or updated an existing one. @@ -1042,7 +1043,8 @@ bool emberAfPluginScenesServerParseViewScene(const EmberAfClusterCommand * cmd, { // The transition time is returned in seconds in the regular version of the // command and tenths of a second in the enhanced version. - emberAfPutInt16uInResp(enhanced ? entry.transitionTime * 10 + entry.transitionTime100ms : entry.transitionTime); + emberAfPutInt16uInResp( + static_cast(enhanced ? entry.transitionTime * 10 + entry.transitionTime100ms : entry.transitionTime)); #ifdef EMBER_AF_PLUGIN_SCENES_NAME_SUPPORT emberAfPutStringInResp(entry.name); #else @@ -1093,17 +1095,17 @@ bool emberAfPluginScenesServerParseViewScene(const EmberAfClusterCommand * cmd, length = &appResponseData[appResponseLength]; emberAfPutInt8uInResp(0); // temporary length emberAfPutInt16uInResp(entry.currentXValue); - *length += 2; + *length = static_cast(*length + 2); if (entry.hasCurrentYValue) { emberAfPutInt16uInResp(entry.currentYValue); - *length += 2; + *length = static_cast(*length + 2); if (enhanced) { if (entry.hasEnhancedCurrentHueValue) { emberAfPutInt16uInResp(entry.enhancedCurrentHueValue); - *length += 2; + *length = static_cast(*length + 2); if (entry.hasCurrentSaturationValue) { emberAfPutInt8uInResp(entry.currentSaturationValue); @@ -1119,11 +1121,11 @@ bool emberAfPluginScenesServerParseViewScene(const EmberAfClusterCommand * cmd, if (entry.hasColorLoopTimeValue) { emberAfPutInt16uInResp(entry.colorLoopTimeValue); - *length += 2; + *length = static_cast(*length + 2); if (entry.hasColorTemperatureMiredsValue) { emberAfPutInt16uInResp(entry.colorTemperatureMiredsValue); - *length += 2; + *length = static_cast(*length + 2); } } } diff --git a/src/app/clusters/temperature-measurement-server/temperature-measurement-server.cpp b/src/app/clusters/temperature-measurement-server/temperature-measurement-server.cpp index b3808a052fa399..27668ba26cdeed 100644 --- a/src/app/clusters/temperature-measurement-server/temperature-measurement-server.cpp +++ b/src/app/clusters/temperature-measurement-server/temperature-measurement-server.cpp @@ -43,6 +43,8 @@ #include #include +using namespace chip; + EmberEventControl emberAfPluginTemperatureMeasurementServerReadEventControl; // TODO: There's no header that declares this event handler, and it's not 100% @@ -58,8 +60,8 @@ extern "C" void emberAfPluginTemperatureMeasurementServerInitCallback(void) EmberAfStatus status; // FIXME Use real values for the temperature sensor polling the sensor using the // EMBER_AF_PLUGIN_TEMPERATURE_MEASUREMENT_SERVER_MAX_MEASUREMENT_FREQUENCY_S macro - uint16_t endpointId = 1; // Hardcoded to 1 for now - int16_t newValue = 0x1234; + EndpointId endpointId = 1; // Hardcoded to 1 for now + int16_t newValue = 0x1234; status = emberAfWriteAttribute(endpointId, ZCL_TEMP_MEASUREMENT_CLUSTER_ID, ZCL_CURRENT_TEMPERATURE_ATTRIBUTE_ID, CLUSTER_MASK_SERVER, (uint8_t *) &newValue, ZCL_INT16S_ATTRIBUTE_TYPE); diff --git a/src/app/reporting/reporting.cpp b/src/app/reporting/reporting.cpp index 542c8b777f401a..fc007c5322cc1b 100644 --- a/src/app/reporting/reporting.cpp +++ b/src/app/reporting/reporting.cpp @@ -62,7 +62,7 @@ static void removeConfigurationAndScheduleTick(uint8_t index); static EmberAfStatus configureReceivedAttribute(const EmberAfClusterCommand * cmd, EmberAfAttributeId attributeId, uint8_t mask, uint16_t timeout); static void putReportableChangeInResp(const EmberAfPluginReportingEntry * entry, EmberAfAttributeType dataType); -static void retrySendReport(EmberOutgoingMessageType type, uint16_t indexOrDestination, EmberApsFrame * apsFrame, uint16_t msgLen, +static void retrySendReport(EmberOutgoingMessageType type, uint64_t indexOrDestination, EmberApsFrame * apsFrame, uint16_t msgLen, uint8_t * message, EmberStatus status); static uint32_t computeStringHash(uint8_t * data, uint8_t length); @@ -88,7 +88,7 @@ EmberAfStatus emberAfPluginReportingConfiguredCallback(const EmberAfPluginReport return EMBER_ZCL_STATUS_SUCCESS; } -static void retrySendReport(EmberOutgoingMessageType type, uint16_t indexOrDestination, EmberApsFrame * apsFrame, uint16_t msgLen, +static void retrySendReport(EmberOutgoingMessageType type, uint64_t indexOrDestination, EmberApsFrame * apsFrame, uint16_t msgLen, uint8_t * message, EmberStatus status) { // Retry once, and do so by unicasting without a pointer to this callback @@ -158,7 +158,7 @@ extern "C" void emberAfPluginReportingInitCallback(void) { // On device initialization, any attributes that have been set up to report // should generate an attribute report. - for (int i = 0; i < REPORT_TABLE_SIZE; i++) + for (uint8_t i = 0; i < REPORT_TABLE_SIZE; i++) { EmberAfPluginReportingEntry entry; emAfPluginReportingGetEntry(i, &entry); @@ -183,7 +183,10 @@ extern "C" void emberAfPluginReportingTickEventHandler(void) uint16_t dataSize; bool clientToServer = false; EmberBindingTableEntry bindingEntry; - uint8_t index, reportSize = 0, currentPayloadMaxLength = 0, smallestPayloadMaxLength = 0; + // reportSize needs to be able to fit a sum of dataSize and some other stuff + // without overflowing. + uint32_t reportSize; + uint8_t index, currentPayloadMaxLength = 0, smallestPayloadMaxLength = 0; for (i = 0; i < REPORT_TABLE_SIZE; i++) { @@ -306,15 +309,16 @@ extern "C" void emberAfPluginReportingTickEventHandler(void) // and changes. We only track changes for data types that are small enough // for us to compare. For CHAR and OCTET strings, we substitute a 32-bit hash. emAfPluginReportVolatileData[i].reportableChange = false; - emAfPluginReportVolatileData[i].lastReportTimeMs = chip::System::Layer::GetClock_MonotonicMS(); + emAfPluginReportVolatileData[i].lastReportTimeMs = static_cast(chip::System::Layer::GetClock_MonotonicMS()); uint32_t stringHash = 0; uint8_t * copyData = readData; - uint8_t copySize = dataSize; + uint16_t copySize = dataSize; if (dataType == ZCL_OCTET_STRING_ATTRIBUTE_TYPE || dataType == ZCL_CHAR_STRING_ATTRIBUTE_TYPE) { // dataSize was set above to count the string's length byte, in addition to string length. - // Compute hash on string value only. - stringHash = computeStringHash(readData + 1, dataSize - 1); + // Compute hash on string value only. Note that string length fits + // in one byte, so dataSize can't be larger than 256 right now. + stringHash = computeStringHash(readData + 1, static_cast(dataSize - 1)); copyData = (uint8_t *) &stringHash; copySize = sizeof(stringHash); } @@ -403,7 +407,7 @@ bool emberAfConfigureReportingCommandCallback(const EmberAfClusterCommand * cmd) direction = (EmberAfReportingDirection) emberAfGetInt8u(cmd->buffer, bufIndex, cmd->bufLen); bufIndex++; attributeId = (EmberAfAttributeId) emberAfGetInt16u(cmd->buffer, bufIndex, cmd->bufLen); - bufIndex += 2; + bufIndex = static_cast(bufIndex + 2); emberAfReportingPrintln(" - direction:%x, attr:%2x", direction, attributeId); @@ -419,9 +423,9 @@ bool emberAfConfigureReportingCommandCallback(const EmberAfClusterCommand * cmd) dataType = (EmberAfAttributeType) emberAfGetInt8u(cmd->buffer, bufIndex, cmd->bufLen); bufIndex++; minInterval = emberAfGetInt16u(cmd->buffer, bufIndex, cmd->bufLen); - bufIndex += 2; + bufIndex = static_cast(bufIndex + 2); maxInterval = emberAfGetInt16u(cmd->buffer, bufIndex, cmd->bufLen); - bufIndex += 2; + bufIndex = static_cast(bufIndex + 2); emberAfReportingPrintln(" type:%x, min:%2x, max:%2x", dataType, minInterval, maxInterval); emberAfReportingFlush(); @@ -435,7 +439,7 @@ bool emberAfConfigureReportingCommandCallback(const EmberAfClusterCommand * cmd) emberAfReportingPrintBuffer(cmd->buffer + bufIndex, dataSize, false); emberAfReportingPrintln(""); - bufIndex += dataSize; + bufIndex = static_cast(bufIndex + dataSize); } // emberAfPluginReportingConfigureReportedAttribute handles non- @@ -465,7 +469,7 @@ bool emberAfConfigureReportingCommandCallback(const EmberAfClusterCommand * cmd) } case EMBER_ZCL_REPORTING_DIRECTION_RECEIVED: { uint16_t timeout = emberAfGetInt16u(cmd->buffer, bufIndex, cmd->bufLen); - bufIndex += 2; + bufIndex = static_cast(bufIndex + 2); emberAfReportingPrintln(" timeout:%2x", timeout); @@ -555,7 +559,7 @@ bool emberAfReadReportingConfigurationCommandCallback(const EmberAfClusterComman direction = (EmberAfReportingDirection) emberAfGetInt8u(cmd->buffer, bufIndex, cmd->bufLen); bufIndex++; attributeId = (EmberAfAttributeId) emberAfGetInt16u(cmd->buffer, bufIndex, cmd->bufLen); - bufIndex += 2; + bufIndex = static_cast(bufIndex + 2); switch (direction) { @@ -909,8 +913,9 @@ EmberAfStatus emberAfPluginReportingConfigureReportedAttribute(const EmberAfPlug entry.manufacturerCode = newEntry->manufacturerCode; if (index < REPORT_TABLE_SIZE) { - emAfPluginReportVolatileData[index].lastReportTimeMs = chip::System::Layer::GetClock_MonotonicMS(); - emAfPluginReportVolatileData[index].lastReportValue = 0; + emAfPluginReportVolatileData[index].lastReportTimeMs = + static_cast(chip::System::Layer::GetClock_MonotonicMS()); + emAfPluginReportVolatileData[index].lastReportValue = 0; } } diff --git a/src/app/reporting/reporting.h b/src/app/reporting/reporting.h index 67b93ec6580157..aaba2f88401fb9 100644 --- a/src/app/reporting/reporting.h +++ b/src/app/reporting/reporting.h @@ -58,6 +58,9 @@ typedef struct { + // If the size of lastReportTimeMs changes (see + // https://github.com/project-chip/connectedhomeip/issues/3590) adjust the + // casts on assigning to it. uint32_t lastReportTimeMs; EmberAfDifferenceType lastReportValue; bool reportableChange; diff --git a/src/app/util/af-main-common.cpp b/src/app/util/af-main-common.cpp index 311f692b92e4b7..7b84350522e53c 100644 --- a/src/app/util/af-main-common.cpp +++ b/src/app/util/af-main-common.cpp @@ -479,7 +479,9 @@ EmberStatus emberAfSendUnicastWithCallback(EmberOutgoingMessageType type, uint64 // cluster in the binding is not used because bindings can be used to send // messages with any cluster id, not just the one set in the binding. EmberBindingTableEntry binding; - EmberStatus status = emberGetBinding(indexOrDestination, &binding); + // TODO: This cast should go away once + // https://github.com/project-chip/connectedhomeip/issues/3584 is fixed. + EmberStatus status = emberGetBinding(static_cast(indexOrDestination), &binding); if (status != EMBER_SUCCESS) { return status; @@ -678,7 +680,9 @@ EmberStatus emAfSend(EmberOutgoingMessageType type, uint64_t indexOrDestination, { case EMBER_OUTGOING_VIA_BINDING: { EmberBindingTableEntry binding; - status = emberGetBinding(indexOrDestination, &binding); + // TODO: This cast should go away once + // https://github.com/project-chip/connectedhomeip/issues/3584 is fixed. + status = emberGetBinding(static_cast(indexOrDestination), &binding); if (status != EMBER_SUCCESS) { break; diff --git a/src/app/util/af-types.h b/src/app/util/af-types.h index 80b9fdef9a5000..2fa736fda90a89 100644 --- a/src/app/util/af-types.h +++ b/src/app/util/af-types.h @@ -1106,7 +1106,7 @@ typedef struct struct { /** The node id of the source of the received reports. */ - EmberNodeId source; + ChipNodeId source; /** The remote endpoint from which the attribute is reported. */ uint8_t endpoint; /** The maximum expected time between reports, measured in seconds. */ @@ -1464,7 +1464,7 @@ typedef void (*EmberAfDefaultResponseFunction)(uint8_t endpoint, uint8_t command * * This function is called when a message is sent. */ -typedef void (*EmberAfMessageSentFunction)(EmberOutgoingMessageType type, uint16_t indexOrDestination, EmberApsFrame * apsFrame, +typedef void (*EmberAfMessageSentFunction)(EmberOutgoingMessageType type, uint64_t indexOrDestination, EmberApsFrame * apsFrame, uint16_t msgLen, uint8_t * message, EmberStatus status); /** diff --git a/src/app/util/attribute-size.cpp b/src/app/util/attribute-size.cpp index 82d814442cf191..1f900d21ce22c6 100644 --- a/src/app/util/attribute-size.cpp +++ b/src/app/util/attribute-size.cpp @@ -78,12 +78,12 @@ uint16_t emberAfAttributeValueSize(EmberAfAttributeType dataType, const uint8_t if (emberAfIsStringAttributeType(dataType)) { // size is string length plus 1-byte length prefix - dataSize = ((uint16_t) emberAfStringLength(buffer)) + 1u; + dataSize = static_cast(static_cast(emberAfStringLength(buffer)) + 1u); } else { // size is long string length plus 2-byte length prefix - dataSize = emberAfLongStringLength(buffer) + 2u; + dataSize = static_cast(emberAfLongStringLength(buffer) + 2u); } } } diff --git a/src/app/util/attribute-storage.cpp b/src/app/util/attribute-storage.cpp index 0fed0b59649323..30aea1bdc832cf 100644 --- a/src/app/util/attribute-storage.cpp +++ b/src/app/util/attribute-storage.cpp @@ -142,7 +142,7 @@ void emberAfEndpointConfigure(void) void emberAfSetEndpointCount(uint8_t dynamicEndpointCount) { - emberEndpointCount = FIXED_ENDPOINT_COUNT + dynamicEndpointCount; + emberEndpointCount = static_cast(FIXED_ENDPOINT_COUNT + dynamicEndpointCount); } uint8_t emberAfFixedEndpointCount(void) @@ -206,7 +206,7 @@ void emberAfClusterDefaultResponseCallback(uint8_t endpoint, EmberAfClusterId cl } // This function is used to call the per-cluster message sent callback -void emberAfClusterMessageSentWithMfgCodeCallback(EmberOutgoingMessageType type, uint16_t indexOrDestination, +void emberAfClusterMessageSentWithMfgCodeCallback(EmberOutgoingMessageType type, uint64_t indexOrDestination, EmberApsFrame * apsFrame, uint16_t msgLen, uint8_t * message, EmberStatus status, uint16_t mfgCode) { @@ -356,7 +356,7 @@ static uint8_t * singletonAttributeLocation(EmberAfAttributeMetadata * am) { if ((m->mask & ATTRIBUTE_MASK_SINGLETON) != 0U) { - index += m->size; + index = static_cast(index + m->size); } m++; } @@ -374,11 +374,11 @@ static EmberAfStatus typeSensitiveMemCopy(uint8_t * dest, uint8_t * src, EmberAf if (emberAfIsStringAttributeType(attributeType)) { - emberAfCopyString(dest, src, size - 1); + emberAfCopyString(dest, src, static_cast(size - 1)); } else if (emberAfIsLongStringAttributeType(attributeType)) { - emberAfCopyLongString(dest, src, size - 2); + emberAfCopyLongString(dest, src, static_cast(size - 2)); } else { @@ -419,7 +419,7 @@ static uint16_t getManufacturerCode(EmberAfManufacturerCodeEntry * codes, uint16 uint16_t emberAfGetMfgCode(EmberAfAttributeMetadata * metadata) { return getManufacturerCode((EmberAfManufacturerCodeEntry *) attributeManufacturerCodes, attributeManufacturerCodeCount, - (metadata - generatedAttributes)); + static_cast((metadata - generatedAttributes))); } uint16_t emAfGetManufacturerCodeForAttribute(EmberAfCluster * cluster, EmberAfAttributeMetadata * attMetaData) @@ -431,7 +431,7 @@ uint16_t emAfGetManufacturerCodeForAttribute(EmberAfCluster * cluster, EmberAfAt uint16_t emAfGetManufacturerCodeForCluster(EmberAfCluster * cluster) { return getManufacturerCode((EmberAfManufacturerCodeEntry *) clusterManufacturerCodes, clusterManufacturerCodeCount, - (cluster - generatedClusters)); + static_cast(cluster - generatedClusters)); } /** @@ -569,20 +569,20 @@ EmberAfStatus emAfReadOrWriteAttribute(EmberAfAttributeSearchRecord * attRecord, // Increase the index if attribute is not externally stored if (!(am->mask & ATTRIBUTE_MASK_EXTERNAL_STORAGE) && !(am->mask & ATTRIBUTE_MASK_SINGLETON)) { - attributeOffsetIndex += emberAfAttributeSize(am); + attributeOffsetIndex = static_cast(attributeOffsetIndex + emberAfAttributeSize(am)); } } } } else { // Not the cluster we are looking for - attributeOffsetIndex += cluster->clusterSize; + attributeOffsetIndex = static_cast(attributeOffsetIndex + cluster->clusterSize); } } } else { // Not the endpoint we are looking for - attributeOffsetIndex += emAfEndpoints[i].endpointType->endpointSize; + attributeOffsetIndex = static_cast(attributeOffsetIndex + emAfEndpoints[i].endpointType->endpointSize); } } return EMBER_ZCL_STATUS_UNSUPPORTED_ATTRIBUTE; // Sorry, attribute was not found. @@ -768,10 +768,11 @@ static uint8_t findClusterEndpointIndex(uint8_t endpoint, EmberAfClusterId clust { break; } - epi += (emberAfFindClusterIncludingDisabledEndpointsWithMfgCode(emAfEndpoints[i].endpoint, clusterId, mask, - manufacturerCode) != NULL) - ? 1 - : 0; + epi = static_cast(epi + + (emberAfFindClusterIncludingDisabledEndpointsWithMfgCode( + emAfEndpoints[i].endpoint, clusterId, mask, manufacturerCode) != NULL) + ? 1 + : 0); } return epi; @@ -1182,7 +1183,7 @@ EmberAfGenericClusterFunction emberAfFindClusterFunction(EmberAfCluster * cluste { functionIndex++; } - mask <<= 1; + mask = static_cast(mask << 1); } return cluster->functions[functionIndex]; } @@ -1192,7 +1193,7 @@ EmberAfGenericClusterFunction emberAfFindClusterFunction(EmberAfCluster * cluste uint16_t emAfGetManufacturerCodeForCommand(EmberAfCommandMetadata * command) { return getManufacturerCode((EmberAfManufacturerCodeEntry *) commandManufacturerCodes, commandManufacturerCodeCount, - (command - generatedCommands)); + static_cast(command - generatedCommands)); } /** diff --git a/src/app/util/attribute-storage.h b/src/app/util/attribute-storage.h index a18bf237674a21..783e34b72039d7 100644 --- a/src/app/util/attribute-storage.h +++ b/src/app/util/attribute-storage.h @@ -196,7 +196,7 @@ void emberAfClusterMessageSentCallback(EmberOutgoingMessageType type, uint16_t i uint16_t msgLen, uint8_t * message, EmberStatus status); // Calls the message sent callback for a specific cluster. -void emberAfClusterMessageSentWithMfgCodeCallback(EmberOutgoingMessageType type, uint16_t indexOrDestination, +void emberAfClusterMessageSentWithMfgCodeCallback(EmberOutgoingMessageType type, uint64_t indexOrDestination, EmberApsFrame * apsFrame, uint16_t msgLen, uint8_t * message, EmberStatus status, uint16_t manufacturerCode); diff --git a/src/app/util/attribute-table.cpp b/src/app/util/attribute-table.cpp index 9bdf1f7b2c016f..62c636f43be828 100644 --- a/src/app/util/attribute-table.cpp +++ b/src/app/util/attribute-table.cpp @@ -309,11 +309,11 @@ void emberAfPrintAttributeTable(void) uint16_t length; if (emberAfIsStringAttributeType(metaData->attributeType)) { - length = emberAfStringLength(data) + 1; + length = static_cast(emberAfStringLength(data) + 1); } else if (emberAfIsLongStringAttributeType(metaData->attributeType)) { - length = emberAfLongStringLength(data) + 2; + length = static_cast(emberAfLongStringLength(data) + 2); } else { @@ -399,7 +399,8 @@ void emberAfRetrieveAttributeAndCraftResponse(uint8_t endpoint, EmberAfClusterId #else //(BIGENDIAN_CPU) memmove(&(appResponseData[appResponseLength]), data, dataLen); #endif //(BIGENDIAN_CPU) - appResponseLength += dataLen; + // TODO: How do we know this does not overflow? + appResponseLength = static_cast(appResponseLength + dataLen); } emberAfAttributesPrintln("READ: clus %2x, attr %2x, dataLen: %x, OK", clusterId, attrId, dataLen); @@ -448,7 +449,7 @@ EmberAfStatus emberAfAppendAttributeReportFields(uint8_t endpoint, EmberAfCluste #else memmove(buffer + *bufIndex, data, size); #endif - *bufIndex += size; + *bufIndex = static_cast(*bufIndex + size); kickout: emberAfAttributesPrintln("REPORT: clus 0x%2x, attr 0x%2x: 0x%x", clusterId, attributeId, status); diff --git a/src/app/util/chip-message-send.cpp b/src/app/util/chip-message-send.cpp index c920d5536c1aa1..69ec6ead85670a 100644 --- a/src/app/util/chip-message-send.cpp +++ b/src/app/util/chip-message-send.cpp @@ -42,13 +42,14 @@ extern "C" { EmberStatus chipSendUnicast(NodeId destination, EmberApsFrame * apsFrame, uint16_t messageLength, uint8_t * message) { - uint16_t frameSize = encodeApsFrame(nullptr, 0, apsFrame); - uint32_t dataLength = uint32_t(frameSize) + uint32_t(messageLength); - if (dataLength > UINT16_MAX) + uint16_t frameSize = encodeApsFrame(nullptr, 0, apsFrame); + uint32_t dataLengthUnchecked = uint32_t(frameSize) + uint32_t(messageLength); + if (dataLengthUnchecked > UINT16_MAX) { // Definitely too long for a packet! return EMBER_MESSAGE_TOO_LONG; } + uint16_t dataLength = static_cast(dataLengthUnchecked); if (frameSize == 0) { diff --git a/src/app/util/client-api.cpp b/src/app/util/client-api.cpp index bf4bb928d73b6c..c229956d8109ab 100644 --- a/src/app/util/client-api.cpp +++ b/src/app/util/client-api.cpp @@ -136,19 +136,19 @@ static uint16_t vFillBuffer(uint8_t * buffer, uint16_t bufferLen, uint8_t frameC } else if (cmd == 'l') { - dataLen = emberAfLongStringLength(data) + 2; + dataLen = static_cast(emberAfLongStringLength(data) + 2); } else if (cmd == 's') { - dataLen = emberAfStringLength(data) + 1; + dataLen = static_cast(emberAfStringLength(data) + 1); } else if ('0' <= cmd && cmd <= '9') { - dataLen = cmd - '0'; + dataLen = static_cast(cmd - '0'); } else if ('A' <= cmd && cmd <= 'G') { - dataLen = cmd - 'A' + 10; + dataLen = static_cast(cmd - 'A' + 10); } else { @@ -217,7 +217,7 @@ static uint16_t vFillBuffer(uint8_t * buffer, uint16_t bufferLen, uint8_t frameC return 0; } memcpy(buffer + bytes, data, dataLen); - bytes += dataLen; + bytes = static_cast(bytes + dataLen); } } diff --git a/src/app/util/esi-management.h b/src/app/util/esi-management.h index fdf7dd22a13682..d2b102b3614af0 100644 --- a/src/app/util/esi-management.h +++ b/src/app/util/esi-management.h @@ -59,7 +59,7 @@ typedef struct { EmberEUI64 eui64; - EmberNodeId nodeId; + ChipNodeId nodeId; uint8_t networkIndex; uint8_t endpoint; uint8_t age; // The number of discovery cycles the ESI has not been discovered. diff --git a/src/app/util/message.cpp b/src/app/util/message.cpp index a8b70f314391f9..c5c196bb4084f1 100644 --- a/src/app/util/message.cpp +++ b/src/app/util/message.cpp @@ -143,7 +143,7 @@ uint8_t * emberAfPutBlockInResp(const uint8_t * data, uint16_t length) if ((appResponseLength + length) < EMBER_AF_RESPONSE_BUFFER_LEN) { memmove(appResponseData + appResponseLength, data, length); - appResponseLength += length; + appResponseLength = static_cast(appResponseLength + length); return &appResponseData[appResponseLength - length]; } else @@ -155,7 +155,7 @@ uint8_t * emberAfPutBlockInResp(const uint8_t * data, uint16_t length) uint8_t * emberAfPutStringInResp(const uint8_t * buffer) { uint8_t length = emberAfStringLength(buffer); - return emberAfPutBlockInResp(buffer, length + 1); + return emberAfPutBlockInResp(buffer, static_cast(length + 1)); } uint8_t * emberAfPutDateInResp(EmberAfDate * value) diff --git a/src/app/util/process-global-message.cpp b/src/app/util/process-global-message.cpp index e2c1748cfc32dd..c11a406534aabb 100644 --- a/src/app/util/process-global-message.cpp +++ b/src/app/util/process-global-message.cpp @@ -136,10 +136,10 @@ bool emAfProcessGlobalCommand(EmberAfClusterCommand * cmd) // Make the ZCL header for the response // note: cmd byte is set below - frameControl = (ZCL_GLOBAL_COMMAND | - (cmd->direction == ZCL_DIRECTION_CLIENT_TO_SERVER - ? ZCL_FRAME_CONTROL_SERVER_TO_CLIENT | EMBER_AF_DEFAULT_RESPONSE_POLICY_RESPONSES - : ZCL_FRAME_CONTROL_CLIENT_TO_SERVER | EMBER_AF_DEFAULT_RESPONSE_POLICY_RESPONSES)); + frameControl = static_cast(ZCL_GLOBAL_COMMAND | + (cmd->direction == ZCL_DIRECTION_CLIENT_TO_SERVER + ? ZCL_FRAME_CONTROL_SERVER_TO_CLIENT | EMBER_AF_DEFAULT_RESPONSE_POLICY_RESPONSES + : ZCL_FRAME_CONTROL_CLIENT_TO_SERVER | EMBER_AF_DEFAULT_RESPONSE_POLICY_RESPONSES)); if (cmd->mfgSpecific) { frameControl |= ZCL_MANUFACTURER_SPECIFIC_MASK; @@ -219,9 +219,10 @@ bool emAfProcessGlobalCommand(EmberAfClusterCommand * cmd) // This function reads the attribute and creates the correct response // in the response buffer emberAfRetrieveAttributeAndCraftResponse(cmd->apsFrame->destinationEndpoint, clusterId, attrId, clientServerMask, - cmd->mfgCode, (EMBER_AF_RESPONSE_BUFFER_LEN - appResponseLength)); + cmd->mfgCode, + static_cast(EMBER_AF_RESPONSE_BUFFER_LEN - appResponseLength)); // Go to next attrID - msgIndex += 2; + msgIndex = static_cast(msgIndex + 2); } } @@ -279,7 +280,7 @@ bool emAfProcessGlobalCommand(EmberAfClusterCommand * cmd) // Increment past the attribute id (two bytes), the type (one byte), and // the data (N bytes, including the length byte for strings). - msgIndex += 3 + dataSize; + msgIndex = static_cast(msgIndex + 3 + dataSize); } // If there are any failures, send the response and exit if (numFailures > 0) @@ -379,7 +380,7 @@ bool emAfProcessGlobalCommand(EmberAfClusterCommand * cmd) // Increment past the attribute id (two bytes), the type (one byte), and // the data (N bytes, including the length byte for strings). - msgIndex += 3 + dataSize; + msgIndex = static_cast(msgIndex + 3 + dataSize); } else { @@ -536,14 +537,16 @@ bool emAfProcessGlobalCommand(EmberAfClusterCommand * cmd) #endif #if defined(EMBER_AF_PLUGIN_IAS_ZONE_CLIENT) - emberAfPluginIasZoneClientReadAttributesResponseCallback(clusterId, message + msgIndex, msgLen - msgIndex); + emberAfPluginIasZoneClientReadAttributesResponseCallback(clusterId, message + msgIndex, + static_cast(msgLen - msgIndex)); #endif #if defined(EMBER_AF_PLUGIN_SIMPLE_METERING_SERVER) - emberAfPluginSimpleMeteringClusterReadAttributesResponseCallback(clusterId, message + msgIndex, msgLen - msgIndex); + emberAfPluginSimpleMeteringClusterReadAttributesResponseCallback(clusterId, message + msgIndex, + static_cast(msgLen - msgIndex)); #endif - if (!emberAfReadAttributesResponseCallback(clusterId, message + msgIndex, msgLen - msgIndex)) + if (!emberAfReadAttributesResponseCallback(clusterId, message + msgIndex, static_cast(msgLen - msgIndex))) { emberAfSendDefaultResponse(cmd, EMBER_ZCL_STATUS_SUCCESS); } @@ -553,14 +556,16 @@ bool emAfProcessGlobalCommand(EmberAfClusterCommand * cmd) case ZCL_WRITE_ATTRIBUTES_RESPONSE_COMMAND_ID: #if defined(EMBER_AF_PLUGIN_TEST_HARNESS) - emberAfPluginTestHarnessWriteAttributesResponseCallback(clusterId, message + msgIndex, msgLen - msgIndex); + emberAfPluginTestHarnessWriteAttributesResponseCallback(clusterId, message + msgIndex, + static_cast(msgLen - msgIndex)); #endif #if defined(EMBER_AF_PLUGIN_IAS_ZONE_CLIENT) - emberAfPluginIasZoneClientWriteAttributesResponseCallback(clusterId, message + msgIndex, msgLen - msgIndex); + emberAfPluginIasZoneClientWriteAttributesResponseCallback(clusterId, message + msgIndex, + static_cast(msgLen - msgIndex)); #endif - if (!emberAfWriteAttributesResponseCallback(clusterId, message + msgIndex, msgLen - msgIndex)) + if (!emberAfWriteAttributesResponseCallback(clusterId, message + msgIndex, static_cast(msgLen - msgIndex))) { emberAfSendDefaultResponse(cmd, EMBER_ZCL_STATUS_SUCCESS); } @@ -568,7 +573,7 @@ bool emAfProcessGlobalCommand(EmberAfClusterCommand * cmd) // ([status:1] [direction:1] [attribute id:2])+ case ZCL_CONFIGURE_REPORTING_RESPONSE_COMMAND_ID: - if (!emberAfConfigureReportingResponseCallback(clusterId, message + msgIndex, msgLen - msgIndex)) + if (!emberAfConfigureReportingResponseCallback(clusterId, message + msgIndex, static_cast(msgLen - msgIndex))) { emberAfSendDefaultResponse(cmd, EMBER_ZCL_STATUS_SUCCESS); } @@ -578,7 +583,8 @@ bool emAfProcessGlobalCommand(EmberAfClusterCommand * cmd) // ... [min interval:0/2] [max interval:0/2] [reportable change:0/V] ... // ... [timeout:0/2])+ case ZCL_READ_REPORTING_CONFIGURATION_RESPONSE_COMMAND_ID: - if (!emberAfReadReportingConfigurationResponseCallback(clusterId, message + msgIndex, msgLen - msgIndex)) + if (!emberAfReadReportingConfigurationResponseCallback(clusterId, message + msgIndex, + static_cast(msgLen - msgIndex))) { emberAfSendDefaultResponse(cmd, EMBER_ZCL_STATUS_SUCCESS); } @@ -586,7 +592,7 @@ bool emAfProcessGlobalCommand(EmberAfClusterCommand * cmd) // ([attribute id:2] [type:1] [data:V])+ case ZCL_REPORT_ATTRIBUTES_COMMAND_ID: - if (!emberAfReportAttributesCallback(clusterId, message + msgIndex, msgLen - msgIndex)) + if (!emberAfReportAttributesCallback(clusterId, message + msgIndex, static_cast(msgLen - msgIndex))) { emberAfSendDefaultResponse(cmd, EMBER_ZCL_STATUS_SUCCESS); } @@ -611,7 +617,8 @@ bool emAfProcessGlobalCommand(EmberAfClusterCommand * cmd) case ZCL_DISCOVER_ATTRIBUTES_EXTENDED_RESPONSE_COMMAND_ID: { bool discoveryComplete = emberAfGetInt8u(message, msgIndex, msgLen); msgIndex++; - if (!emberAfDiscoverAttributesResponseCallback(clusterId, discoveryComplete, message + msgIndex, msgLen - msgIndex, + if (!emberAfDiscoverAttributesResponseCallback(clusterId, discoveryComplete, message + msgIndex, + static_cast(msgLen - msgIndex), (zclCmd == ZCL_DISCOVER_ATTRIBUTES_EXTENDED_RESPONSE_COMMAND_ID))) { emberAfSendDefaultResponse(cmd, EMBER_ZCL_STATUS_SUCCESS); @@ -642,8 +649,8 @@ bool emAfProcessGlobalCommand(EmberAfClusterCommand * cmd) } savedIndex = appResponseLength; flag = emberAfExtractCommandIds(flag, cmd, clusterId, appResponseData + appResponseLength + 1, - EMBER_AF_RESPONSE_BUFFER_LEN - appResponseLength - 1, &appResponseLength, - startCommandIdentifier, maximumCommandIdentifiers); + static_cast(EMBER_AF_RESPONSE_BUFFER_LEN - appResponseLength - 1), + &appResponseLength, startCommandIdentifier, maximumCommandIdentifiers); appResponseData[savedIndex] = (flag ? 1 : 0); appResponseLength++; emberAfSendResponse(); @@ -655,9 +662,10 @@ bool emAfProcessGlobalCommand(EmberAfClusterCommand * cmd) if (msgIndex <= msgLen) { printDiscoverCommandsResponse(false, // is ZCL command generated? - clusterId, discoveryComplete, message + msgIndex, msgLen - msgIndex); + clusterId, discoveryComplete, message + msgIndex, + static_cast(msgLen - msgIndex)); if (!emberAfDiscoverCommandsReceivedResponseCallback(clusterId, cmd->mfgCode, discoveryComplete, message + msgIndex, - msgLen - msgIndex)) + static_cast(msgLen - msgIndex))) { emberAfSendDefaultResponse(cmd, EMBER_ZCL_STATUS_SUCCESS); } @@ -674,9 +682,10 @@ bool emAfProcessGlobalCommand(EmberAfClusterCommand * cmd) if (msgIndex <= msgLen) { printDiscoverCommandsResponse(true, // is ZCL command generated? - clusterId, discoveryComplete, message + msgIndex, msgLen - msgIndex); + clusterId, discoveryComplete, message + msgIndex, + static_cast(msgLen - msgIndex)); if (!emberAfDiscoverCommandsGeneratedResponseCallback(clusterId, cmd->mfgCode, discoveryComplete, message + msgIndex, - msgLen - msgIndex)) + static_cast(msgLen - msgIndex))) { emberAfSendDefaultResponse(cmd, EMBER_ZCL_STATUS_SUCCESS); } diff --git a/src/app/util/util.cpp b/src/app/util/util.cpp index 19281377b8b252..025bfef0d6793c 100644 --- a/src/app/util/util.cpp +++ b/src/app/util/util.cpp @@ -235,7 +235,7 @@ static void prepareForResponse(const EmberAfClusterCommand * cmd) if (cmd->interPanHeader == NULL) { emberAfResponseDestination = cmd->source; - emberAfResponseType &= ~ZCL_UTIL_RESP_INTERPAN; + emberAfResponseType = static_cast(emberAfResponseType & ~ZCL_UTIL_RESP_INTERPAN); } else { @@ -402,9 +402,9 @@ static void printIncomingZclMessage(const EmberAfClusterCommand * cmd) cmd->buffer[0], // frame control cmd->seqNum, cmd->commandId); emberAfAppFlush(); - emberAfAppPrintBuffer(cmd->buffer + cmd->payloadStartIndex, // message - cmd->bufLen - cmd->payloadStartIndex, // length - true); // spaces? + emberAfAppPrintBuffer(cmd->buffer + cmd->payloadStartIndex, // message + static_cast(cmd->bufLen - cmd->payloadStartIndex), // length + true); // spaces? emberAfAppFlush(); emberAfAppPrintln("]"); } @@ -480,8 +480,8 @@ bool emberAfProcessMessageIntoZclCmd(EmberApsFrame * apsFrame, EmberIncomingMess returnCmd->payloadStartIndex = 1; if (returnCmd->mfgSpecific) { - returnCmd->mfgCode = emberAfGetInt16u(message, returnCmd->payloadStartIndex, messageLength); - returnCmd->payloadStartIndex += 2; + returnCmd->mfgCode = emberAfGetInt16u(message, returnCmd->payloadStartIndex, messageLength); + returnCmd->payloadStartIndex = static_cast(returnCmd->payloadStartIndex + 2); } else { @@ -629,7 +629,7 @@ void emberAfSetNoReplyForNextMessage(bool set) } else { - emberAfResponseType &= ~ZCL_UTIL_RESP_NONE; + emberAfResponseType = static_cast(emberAfResponseType & ~ZCL_UTIL_RESP_NONE); } } @@ -655,7 +655,7 @@ void emAfApplyRetryOverride(EmberApsOption * options) } else if (emberAfApsRetryOverride == EMBER_AF_RETRY_OVERRIDE_UNSET) { - *options &= ~EMBER_APS_OPTION_RETRY; + *options = static_cast(*options & ~EMBER_APS_OPTION_RETRY); } else { @@ -747,9 +747,9 @@ EmberStatus emberAfSendResponseWithCallback(EmberAfMessageSentFunction callback) // the destination of the message. if ((emberAfResponseType & ZCL_UTIL_RESP_INTERPAN) != 0U) { - label = 'I'; - status = emberAfInterpanSendMessageCallback(&interpanResponseHeader, appResponseLength, appResponseData); - emberAfResponseType &= ~ZCL_UTIL_RESP_INTERPAN; + label = 'I'; + status = emberAfInterpanSendMessageCallback(&interpanResponseHeader, appResponseLength, appResponseData); + emberAfResponseType = static_cast(emberAfResponseType & ~ZCL_UTIL_RESP_INTERPAN); } else if (!isBroadcastDestination(emberAfResponseDestination)) { @@ -830,9 +830,9 @@ EmberStatus emberAfSendDefaultResponseWithCallback(const EmberAfClusterCommand * } appResponseLength = 0; - frameControl = (ZCL_GLOBAL_COMMAND | - (cmd->direction == ZCL_DIRECTION_CLIENT_TO_SERVER ? ZCL_FRAME_CONTROL_SERVER_TO_CLIENT - : ZCL_FRAME_CONTROL_CLIENT_TO_SERVER)); + frameControl = static_cast(ZCL_GLOBAL_COMMAND | + (cmd->direction == ZCL_DIRECTION_CLIENT_TO_SERVER ? ZCL_FRAME_CONTROL_SERVER_TO_CLIENT + : ZCL_FRAME_CONTROL_CLIENT_TO_SERVER)); if (!cmd->mfgSpecific) { @@ -964,24 +964,24 @@ bool emberAfDetermineIfLinkSecurityIsRequired(uint8_t commandId, bool incoming, uint8_t emberAfMaximumApsPayloadLength(EmberOutgoingMessageType type, uint64_t indexOrDestination, EmberApsFrame * apsFrame) { - EmberNodeId destination = EMBER_UNKNOWN_NODE_ID; - uint8_t max = EMBER_AF_MAXIMUM_APS_PAYLOAD_LENGTH; + ChipNodeId destination = EMBER_UNKNOWN_NODE_ID; + uint8_t max = EMBER_AF_MAXIMUM_APS_PAYLOAD_LENGTH; if ((apsFrame->options & EMBER_APS_OPTION_ENCRYPTION) != 0U) { - max -= EMBER_AF_APS_ENCRYPTION_OVERHEAD; + max = static_cast(max - EMBER_AF_APS_ENCRYPTION_OVERHEAD); } if ((apsFrame->options & EMBER_APS_OPTION_SOURCE_EUI64) != 0U) { - max -= EUI64_SIZE; + max = static_cast(max - EUI64_SIZE); } if ((apsFrame->options & EMBER_APS_OPTION_DESTINATION_EUI64) != 0U) { - max -= EUI64_SIZE; + max = static_cast(max - EUI64_SIZE); } if ((apsFrame->options & EMBER_APS_OPTION_FRAGMENT) != 0U) { - max -= EMBER_AF_APS_FRAGMENTATION_OVERHEAD; + max = static_cast(max - EMBER_AF_APS_FRAGMENTATION_OVERHEAD); } switch (type) @@ -1007,7 +1007,7 @@ uint8_t emberAfMaximumApsPayloadLength(EmberOutgoingMessageType type, uint64_t i break; } - max -= emberAfGetSourceRouteOverheadCallback(destination); + max = static_cast(max - emberAfGetSourceRouteOverheadCallback(destination)); return max; } @@ -1178,7 +1178,7 @@ int8_t emberAfCompareDates(EmberAfDate* date1, EmberAfDate* date2) // 2.15 from the ZCL spec 075123r02 uint8_t emberAfGetAttributeAnalogOrDiscreteType(uint8_t dataType) { - uint8_t index = 0; + unsigned index = 0; while (emberAfAnalogDiscreteThresholds[index] < dataType) { @@ -1240,12 +1240,13 @@ uint8_t emberAfAppendCharacters(uint8_t * zclString, uint8_t zclStringMaxLen, co return 0; } - freeChars = zclStringMaxLen - curLen; + freeChars = static_cast(zclStringMaxLen - curLen); charsToWrite = (freeChars > appendingCharsLen) ? appendingCharsLen : freeChars; memcpy(&zclString[1 + curLen], // 1 is to account for zcl's length byte appendingChars, charsToWrite); - zclString[0] = curLen + charsToWrite; + // Cast is safe, because the sum can't be bigger than zclStringMaxLen. + zclString[0] = static_cast(curLen + charsToWrite); return charsToWrite; } From e9f7524568aa8dc3ffce063f573cb4d5693d2040 Mon Sep 17 00:00:00 2001 From: Kamil Kasperczyk <66371704+kkasperczyk-no@users.noreply.github.com> Date: Thu, 5 Nov 2020 19:55:33 +0100 Subject: [PATCH 003/234] [examples/pigweed-app] Added README file to the nRF Connect example. (#3598) There is lack of information how to build pigweed-app example on the nRF Connect platform. * Added README file containing information how to build and use example. --- examples/lighting-app/nrfconnect/README.md | 13 +- examples/lock-app/nrfconnect/README.md | 13 +- examples/pigweed-app/{ => nrf5}/README.md | 0 examples/pigweed-app/nrfconnect/README.md | 232 +++++++++++++++++++++ 4 files changed, 256 insertions(+), 2 deletions(-) rename examples/pigweed-app/{ => nrf5}/README.md (100%) create mode 100644 examples/pigweed-app/nrfconnect/README.md diff --git a/examples/lighting-app/nrfconnect/README.md b/examples/lighting-app/nrfconnect/README.md index c8878b4f86b89f..c73231a36aa442 100644 --- a/examples/lighting-app/nrfconnect/README.md +++ b/examples/lighting-app/nrfconnect/README.md @@ -209,7 +209,18 @@ Docker image in case of doubt. Please refer to [this section](https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/gs_installing.html#updating-the-repositories) -in the user guide to learn how to update nRF Connect SDK repository. +in the user guide to learn how to update nRF Connect SDK repository. For example +to checkout given `83764f` revision the following commands should be called: + + # Phrase should be replaced with an absolute path to nRF Connect SDK source directory. + $ cd /nrf + + $ git fetch origin + + # Number `83764f` can be replaced with the desired revision number. + $ git checkout 83764f + + $ west update diff --git a/examples/lock-app/nrfconnect/README.md b/examples/lock-app/nrfconnect/README.md index fe137449a99923..7adb66ac84fe07 100644 --- a/examples/lock-app/nrfconnect/README.md +++ b/examples/lock-app/nrfconnect/README.md @@ -213,7 +213,18 @@ Docker image in case of doubt. Please refer to [this section](https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/gs_installing.html#updating-the-repositories) -in the user guide to learn how to update nRF Connect SDK repository. +in the user guide to learn how to update nRF Connect SDK repository. For example +to checkout given `83764f` revision the following commands should be called: + + # Phrase should be replaced with an absolute path to nRF Connect SDK source directory. + $ cd /nrf + + $ git fetch origin + + # Number `83764f` can be replaced with the desired revision number. + $ git checkout 83764f + + $ west update diff --git a/examples/pigweed-app/README.md b/examples/pigweed-app/nrf5/README.md similarity index 100% rename from examples/pigweed-app/README.md rename to examples/pigweed-app/nrf5/README.md diff --git a/examples/pigweed-app/nrfconnect/README.md b/examples/pigweed-app/nrfconnect/README.md new file mode 100644 index 00000000000000..ed9d0b0a04abef --- /dev/null +++ b/examples/pigweed-app/nrfconnect/README.md @@ -0,0 +1,232 @@ +# CHIP nRF Connect nRF52840 Pigweed Example Application + +An example application showing the use +[CHIP](https://github.com/project-chip/connectedhomeip) on the Nordic nRF52840. + +
+ +- [CHIP nRF52840 Pigweed Example Application](#chip-nrf52840-pigweed-example-application) + - [Introduction](#introduction) + - [Building](#building) + - [Using Docker container](#using-docker-container) + - [Using Native shell](#using-native-shell) + - [Supported nRF Connect SDK versions](#supported-nrf-connect-sdk-versions) + - [Configuring the example](#configuring-the-example) + - [Flashing and debugging](#flashing-and-debugging) + - [Currently implemented features](#currently-implemented-features) + +
+ + + +## Introduction + +![nrf52840 DK](../../platform/nrf528xx/doc/images/nrf52840-dk.jpg) + +The nRF52840 Pigweed example app exercises functionalities in +third_party/pigweed, to see what is needed for integrating Pigweed to CHIP, as +well as a precursor to CHIP functionalities like on-device testing. + +The example makes use of the CMake build system to generate the ninja build +script. The build system takes care of invoking the CHIP library build with all +necessary flags exported from the Zephyr environment. + + + +## Building + +### Using Docker container + +> **Important**: +> +> Due to +> [certain limitations of Docker for MacOS](https://docs.docker.com/docker-for-mac/faqs/#can-i-pass-through-a-usb-device-to-a-container) +> it is impossible to use the Docker container to communicate with a USB device +> such as nRF 52840 DK. Therefore, MacOS users are advised to follow the +> [Using Native shell](#using-native-shell) instruction. + +The easiest way to get started with the example is to use nRF Connect SDK Docker +image for CHIP applications. Run the following commands to start a Docker +container: + + $ mkdir ~/nrfconnect + $ mkdir ~/connectedhomeip + $ docker pull nordicsemi/nrfconnect-chip + $ docker run --rm -it -e RUNAS=$(id -u) -v ~/nrfconnect:/var/ncs -v ~/connectedhomeip:/var/chip \ + -v /dev/bus/usb:/dev/bus/usb --device-cgroup-rule "c 189:* rmw" nordicsemi/nrfconnect-chip + +> **Note**: +> +> - `~/nrfconnect` can be replaced with an absolute path to nRF Connect SDK +> source directory in case you have it already installed. +> - Likewise, `~/connectedhomeip` can be replaced with an absolute path to +> CHIP source directory. +> - `-v /dev/bus/usb:/dev/bus/usb --device-cgroup-rule 'c 189:* rmw` +> parameters can be omitted if you're not planning to flash the example onto +> hardware. The parameters give the container access to USB devices +> connected to your computer such as the nRF52840 DK. +> - `--rm` flag can be omitted if you don't want the container to be +> auto-removed when you exit the container shell session. +> - `-e RUNAS=$(id -u)` is needed to start the container session as the +> current user instead of root. + +If you use the container for the first time and you don't have nRF Connect SDK +and CHIP sources downloaded yet, run `setup` command in the container to pull +the sources into directories mounted as `/var/ncs` and `/var/chip`, +respectively: + + $ setup --ncs 83764f + /var/ncs repository is empty. Do you wish to check out nRF Connect SDK sources [83764f]? [Y/N] y + ... + /var/chip repository is empty. Do you wish to check out Project CHIP sources [master]? [Y/N] y + ... + +It is important to remember about running activate.sh script, as it is necessary +to build Pigweed library and it can be done, by typing following command: + + $ source scripts/activate.sh + +Now you may build the example by running the commands below in the Docker +container: + + $ cd /var/chip/examples/pigweed-app/nrfconnect + $ west build -b nrf52840dk_nrf52840 + +If the build succeeds, the binary will be available under +`/var/chip/examples/pigweed-app/nrfconnect/build/zephyr/zephyr.hex`. Note that +other operations described in this document like flashing or debugging can also +be done in the container. + +### Using native shell + +Before building the example, +[download the nRF Connect SDK and install all requirements](https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/gs_installing.html). +Please read the +[Supported nRF Connect SDK versions](#supported-nrf-connect-sdk-versions) +section to learn which version to use to avoid unexpected compatibility issues. + +If you don't want to use SEGGER Embedded Studio, you may skip the part about +installing and configuring it. + +Download and install the +[nRF Command Line Tools](https://www.nordicsemi.com/Software-and-Tools/Development-Tools/nRF-Command-Line-Tools). + +Download and install [GN meta-build system](https://gn.googlesource.com/gn/). + +Make sure that you source the following file: + + $ source /zephyr/zephyr-env.sh + +> **Note:** +> +> Ensure that `$ZEPHYR_BASE`, `$GNUARMEMB_TOOLCHAIN_PATH`, and +> `$ZEPHYR_TOOLCHAIN_VARIANT` environment variables are set in your current +> terminal before building. `$GNUARMEMB_TOOLCHAIN_PATH` and +> `$ZEPHYR_TOOLCHAIN_VARIANT` must be set manually. + +Make sure that you run activate.sh script, as it is necessary to build Pigweed +library and it can be done, by typing following command: + + $ source scripts/activate.sh + +After your environment is set up, you are ready to build the example. The +recommended tool for building and flashing the device is +[west](https://docs.zephyrproject.org/latest/guides/west/). + +The following commands will build the `pigweed-app` example: + + $ cd ~/connectedhomeip/examples/pigweed-app/nrfconnect + + # If this is a first time build or if `build` directory was deleted + $ west build -b nrf52840dk_nrf52840 + + # Any subsequent build + $ west build + +After a successful build, the binary will be available under +`/build/zephyr/zephyr.hex` + +### Supported nRF Connect SDK versions + +It is recommended to use the nRF Connect version which is being verified as a +part of CHIP Continuous Integration testing, which happens to be `83764f` at the +moment. You may verify that the revision is used in +[chip-build-nrf-platform](https://github.com/project-chip/connectedhomeip/blob/master/integrations/docker/images/chip-build-nrf-platform/Dockerfile) +Docker image in case of doubt. + +Please refer to +[this section](https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/gs_installing.html#updating-the-repositories) +in the user guide to learn how to update nRF Connect SDK repository. For example +to checkout given `83764f` revision the following commands should be called: + + # Phrase should be replaced with an absolute path to nRF Connect SDK source directory. + $ cd /nrf + + $ git fetch origin + + # Number `83764f` can be replaced with the desired revision number. + $ git checkout 83764f + + $ west update + + + +## Configuring the example + +The Zephyr ecosystem is higly configurable and allows the user to modify many +aspects of the application. The configuration system is based on `Kconfig` and +the settings can be modified using the `menuconfig` utility. + +To open the configuration menu, do the following: + + $ cd + # First time build + $ west build -b nrf52840dk_nrf52840 -t menuconfig + + # Any subsequent build + $ west build -t menuconfig + + # Running menuconfig with ninja + $ cd /build + $ ninja menuconfig + +Changes done with `menuconfig` will be lost, if the `build` directory is +deleted. To make them persistent, save the configuration options in `prj.conf` +file. + + + +## Flashing and debugging + +The example application is designed to run on the +[Nordic nRF52840 DK](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-DK) +development kit. + +To flash the application to the device, use the `west` tool: + + $ cd + $ west flash + +If you have multiple nRF52840 DK boards connected, `west` will prompt you to +pick the correct one. + +To debug the application on target: + + $ cd + $ west debug + + + +## Currently implemented features + +### Echo RPC: + +``` +python -m pw_hdlc_lite.rpc_console --device /dev/ttyACM0 -b 115200 $CHIP_ROOT/third_party/pigweed/repo/pw_rpc/pw_rpc_protos/echo.proto -o /tmp/pw_rpc.out +``` + +will start an interactive python shell where Echo RPC can be invoked as + +``` +rpcs.pw.rpc.EchoService.Echo(msg="hi") +``` From 52466a9b5c528432972a47ad69ece6fb3fda11f7 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas Date: Thu, 5 Nov 2020 20:07:27 +0100 Subject: [PATCH 004/234] Add ZCL reporting plugin to be compiled in various examples (#3608) --- examples/lighting-app/efr32/BUILD.gn | 2 + .../efr32/src/gen/callback-stub.c | 92 ------------------- .../lighting-app/lighting-common/BUILD.gn | 2 + .../lighting-common/gen/callback-stub.c | 92 ------------------- .../lighting-app/nrfconnect/CMakeLists.txt | 2 + examples/lock-app/efr32/BUILD.gn | 2 + .../lock-app/efr32/src/gen/callback-stub.c | 92 ------------------- examples/lock-app/lock-common/BUILD.gn | 2 + .../lock-app/lock-common/gen/callback-stub.c | 92 ------------------- examples/lock-app/nrfconnect/CMakeLists.txt | 2 + .../esp32/main/gen/callback-stub.c | 92 ------------------- .../server/esp32/main/gen/callback-stub.c | 34 ------- src/app/reporting/reporting.cpp | 21 ++++- src/app/reporting/reporting.h | 88 ++++++++++++++++++ 14 files changed, 116 insertions(+), 499 deletions(-) diff --git a/examples/lighting-app/efr32/BUILD.gn b/examples/lighting-app/efr32/BUILD.gn index b84c0da5cbab10..642e8840c7ee14 100644 --- a/examples/lighting-app/efr32/BUILD.gn +++ b/examples/lighting-app/efr32/BUILD.gn @@ -87,6 +87,8 @@ efr32_executable("lighting_app") { "${chip_root}/examples/common/QRCode/repo/c/qrcodegen.c", "${chip_root}/examples/common/chip-app-server/DataModelHandler.cpp", "${chip_root}/src/app/clusters/on-off-server/on-off.cpp", + "${chip_root}/src/app/reporting/reporting-default-configuration.cpp", + "${chip_root}/src/app/reporting/reporting.cpp", "${chip_root}/src/app/util/af-event.cpp", "${chip_root}/src/app/util/af-main-common.cpp", "${chip_root}/src/app/util/attribute-size.cpp", diff --git a/examples/lighting-app/efr32/src/gen/callback-stub.c b/examples/lighting-app/efr32/src/gen/callback-stub.c index 7d08f5cab34431..dd0e5638fb9c4c 100644 --- a/examples/lighting-app/efr32/src/gen/callback-stub.c +++ b/examples/lighting-app/efr32/src/gen/callback-stub.c @@ -137,17 +137,6 @@ bool emberAfAttributeWriteAccessCallback(uint8_t endpoint, EmberAfClusterId clus */ void emberAfGroupsClusterClearGroupTableCallback(uint8_t endpoint) {} -/** @brief Clear Report Table - * - * This function is called by the framework when the application should clear - * the report table. - * - */ -EmberStatus emberAfClearReportTableCallback(void) -{ - return EMBER_LIBRARY_NOT_PRESENT; -} - /** @brief Scenes Cluster ClearSceneTable * * This function is called by the framework when the application should clear @@ -202,38 +191,6 @@ bool emberAfClusterSecurityCustomCallback(EmberAfProfileId profileId, EmberAfClu return false; } -/** @brief Configure Reporting Command - * - * This function is called by the application framework when a Configure - * Reporting command is received from an external device. The Configure - * Reporting command contains a series of attribute reporting configuration - * records. The application should return true if the message was processed or - * false if it was not. - * - * @param cmd Ver.: always - */ -bool emberAfConfigureReportingCommandCallback(const EmberAfClusterCommand * cmd) -{ - return false; -} - -/** @brief Configure Reporting Response - * - * This function is called by the application framework when a Configure - * Reporting Response command is received from an external device. The - * application should return true if the message was processed or false if it - * was not. - * - * @param clusterId The cluster identifier of this response. Ver.: always - * @param buffer Buffer containing the list of attribute status records. Ver.: - * always - * @param bufLen The length in bytes of the list. Ver.: always - */ -bool emberAfConfigureReportingResponseCallback(EmberAfClusterId clusterId, uint8_t * buffer, uint16_t bufLen) -{ - return false; -} - /** @brief Default Response * * This function is called by the application framework when a Default Response @@ -1969,36 +1926,6 @@ bool emberAfReadAttributesResponseCallback(EmberAfClusterId clusterId, uint8_t * return false; } -/** @brief Read Reporting Configuration Command - * - * This function is called by the application framework when a Read Reporting - * Configuration command is received from an external device. The application - * should return true if the message was processed or false if it was not. - * - * @param cmd Ver.: always - */ -bool emberAfReadReportingConfigurationCommandCallback(const EmberAfClusterCommand * cmd) -{ - return false; -} - -/** @brief Read Reporting Configuration Response - * - * This function is called by the application framework when a Read Reporting - * Configuration Response command is received from an external device. The - * application should return true if the message was processed or false if it - * was not. - * - * @param clusterId The cluster identifier of this response. Ver.: always - * @param buffer Buffer containing the list of attribute reporting configuration - * records. Ver.: always - * @param bufLen The length in bytes of the list. Ver.: always - */ -bool emberAfReadReportingConfigurationResponseCallback(EmberAfClusterId clusterId, uint8_t * buffer, uint16_t bufLen) -{ - return false; -} - /** @brief Scenes Cluster Recall Saved Scene * * This function is called by the framework when the application should recall a @@ -2111,25 +2038,6 @@ bool emberAfReportAttributesCallback(EmberAfClusterId clusterId, uint8_t * buffe return false; } -/** @brief Reporting Attribute Change - * - * This function is called by the framework when an attribute managed by the - * framework changes. The application should call this function when an - * externally-managed attribute changes. The application should use the change - * notification to inform its reporting decisions. - * - * @param endpoint Ver.: always - * @param clusterId Ver.: always - * @param attributeId Ver.: always - * @param mask Ver.: always - * @param manufacturerCode Ver.: always - * @param type Ver.: always - * @param data Ver.: always - */ -void emberAfReportingAttributeChangeCallback(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attributeId, - uint8_t mask, uint16_t manufacturerCode, EmberAfAttributeType type, uint8_t * data) -{} - /** @brief Scan Error * * This is called by the framework on behalf of the form-and-join library to diff --git a/examples/lighting-app/lighting-common/BUILD.gn b/examples/lighting-app/lighting-common/BUILD.gn index 1186774b4b7a8f..6afe842e56ae06 100644 --- a/examples/lighting-app/lighting-common/BUILD.gn +++ b/examples/lighting-app/lighting-common/BUILD.gn @@ -25,6 +25,8 @@ source_set("lighting-common") { sources = [ "${chip_root}/examples/common/chip-app-server/DataModelHandler.cpp", "${chip_root}/src/app/clusters/on-off-server/on-off.cpp", + "${chip_root}/src/app/reporting/reporting-default-configuration.cpp", + "${chip_root}/src/app/reporting/reporting.cpp", "${chip_root}/src/app/util/af-event.cpp", "${chip_root}/src/app/util/af-main-common.cpp", "${chip_root}/src/app/util/attribute-size.cpp", diff --git a/examples/lighting-app/lighting-common/gen/callback-stub.c b/examples/lighting-app/lighting-common/gen/callback-stub.c index 855fd78a9ecf95..7b070c5b6b2c72 100644 --- a/examples/lighting-app/lighting-common/gen/callback-stub.c +++ b/examples/lighting-app/lighting-common/gen/callback-stub.c @@ -137,17 +137,6 @@ bool emberAfAttributeWriteAccessCallback(uint8_t endpoint, EmberAfClusterId clus */ void emberAfGroupsClusterClearGroupTableCallback(uint8_t endpoint) {} -/** @brief Clear Report Table - * - * This function is called by the framework when the application should clear - * the report table. - * - */ -EmberStatus emberAfClearReportTableCallback(void) -{ - return EMBER_LIBRARY_NOT_PRESENT; -} - /** @brief Scenes Cluster ClearSceneTable * * This function is called by the framework when the application should clear @@ -202,38 +191,6 @@ bool emberAfClusterSecurityCustomCallback(EmberAfProfileId profileId, EmberAfClu return false; } -/** @brief Configure Reporting Command - * - * This function is called by the application framework when a Configure - * Reporting command is received from an external device. The Configure - * Reporting command contains a series of attribute reporting configuration - * records. The application should return true if the message was processed or - * false if it was not. - * - * @param cmd Ver.: always - */ -bool emberAfConfigureReportingCommandCallback(const EmberAfClusterCommand * cmd) -{ - return false; -} - -/** @brief Configure Reporting Response - * - * This function is called by the application framework when a Configure - * Reporting Response command is received from an external device. The - * application should return true if the message was processed or false if it - * was not. - * - * @param clusterId The cluster identifier of this response. Ver.: always - * @param buffer Buffer containing the list of attribute status records. Ver.: - * always - * @param bufLen The length in bytes of the list. Ver.: always - */ -bool emberAfConfigureReportingResponseCallback(EmberAfClusterId clusterId, uint8_t * buffer, uint16_t bufLen) -{ - return false; -} - /** @brief Default Response * * This function is called by the application framework when a Default Response @@ -1969,36 +1926,6 @@ bool emberAfReadAttributesResponseCallback(EmberAfClusterId clusterId, uint8_t * return false; } -/** @brief Read Reporting Configuration Command - * - * This function is called by the application framework when a Read Reporting - * Configuration command is received from an external device. The application - * should return true if the message was processed or false if it was not. - * - * @param cmd Ver.: always - */ -bool emberAfReadReportingConfigurationCommandCallback(const EmberAfClusterCommand * cmd) -{ - return false; -} - -/** @brief Read Reporting Configuration Response - * - * This function is called by the application framework when a Read Reporting - * Configuration Response command is received from an external device. The - * application should return true if the message was processed or false if it - * was not. - * - * @param clusterId The cluster identifier of this response. Ver.: always - * @param buffer Buffer containing the list of attribute reporting configuration - * records. Ver.: always - * @param bufLen The length in bytes of the list. Ver.: always - */ -bool emberAfReadReportingConfigurationResponseCallback(EmberAfClusterId clusterId, uint8_t * buffer, uint16_t bufLen) -{ - return false; -} - /** @brief Scenes Cluster Recall Saved Scene * * This function is called by the framework when the application should recall a @@ -2111,25 +2038,6 @@ bool emberAfReportAttributesCallback(EmberAfClusterId clusterId, uint8_t * buffe return false; } -/** @brief Reporting Attribute Change - * - * This function is called by the framework when an attribute managed by the - * framework changes. The application should call this function when an - * externally-managed attribute changes. The application should use the change - * notification to inform its reporting decisions. - * - * @param endpoint Ver.: always - * @param clusterId Ver.: always - * @param attributeId Ver.: always - * @param mask Ver.: always - * @param manufacturerCode Ver.: always - * @param type Ver.: always - * @param data Ver.: always - */ -void emberAfReportingAttributeChangeCallback(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attributeId, - uint8_t mask, uint16_t manufacturerCode, EmberAfAttributeType type, uint8_t * data) -{} - /** @brief Scan Error * * This is called by the framework on behalf of the form-and-join library to diff --git a/examples/lighting-app/nrfconnect/CMakeLists.txt b/examples/lighting-app/nrfconnect/CMakeLists.txt index 6fadd56feeb430..56a2a2912c4bd9 100644 --- a/examples/lighting-app/nrfconnect/CMakeLists.txt +++ b/examples/lighting-app/nrfconnect/CMakeLists.txt @@ -42,6 +42,8 @@ target_sources(app PRIVATE ${CHIP_APP_SERVER}/Server.cpp ${CHIP_APP_SERVER}/QRCodeUtil.cpp ${CHIP_APP_SERVER}/RendezvousServer.cpp + ${CHIP_ROOT}/src/app/reporting/reporting-default-configuration.cpp + ${CHIP_ROOT}/src/app/reporting/reporting.cpp ${CHIP_ROOT}/src/app/util/af-event.cpp ${CHIP_ROOT}/src/app/util/af-main-common.cpp ${CHIP_ROOT}/src/app/util/attribute-size.cpp diff --git a/examples/lock-app/efr32/BUILD.gn b/examples/lock-app/efr32/BUILD.gn index efd58ca60e0f8b..f722de3ac9201c 100644 --- a/examples/lock-app/efr32/BUILD.gn +++ b/examples/lock-app/efr32/BUILD.gn @@ -87,6 +87,8 @@ efr32_executable("lock_app") { "${chip_root}/examples/common/QRCode/repo/c/qrcodegen.c", "${chip_root}/examples/common/chip-app-server/DataModelHandler.cpp", "${chip_root}/src/app/clusters/on-off-server/on-off.cpp", + "${chip_root}/src/app/reporting/reporting-default-configuration.cpp", + "${chip_root}/src/app/reporting/reporting.cpp", "${chip_root}/src/app/util/af-event.cpp", "${chip_root}/src/app/util/af-main-common.cpp", "${chip_root}/src/app/util/attribute-size.cpp", diff --git a/examples/lock-app/efr32/src/gen/callback-stub.c b/examples/lock-app/efr32/src/gen/callback-stub.c index f1d56bcbf370c8..44ed6b255a542a 100644 --- a/examples/lock-app/efr32/src/gen/callback-stub.c +++ b/examples/lock-app/efr32/src/gen/callback-stub.c @@ -137,17 +137,6 @@ bool emberAfAttributeWriteAccessCallback(uint8_t endpoint, EmberAfClusterId clus */ void emberAfGroupsClusterClearGroupTableCallback(uint8_t endpoint) {} -/** @brief Clear Report Table - * - * This function is called by the framework when the application should clear - * the report table. - * - */ -EmberStatus emberAfClearReportTableCallback(void) -{ - return EMBER_LIBRARY_NOT_PRESENT; -} - /** @brief Scenes Cluster ClearSceneTable * * This function is called by the framework when the application should clear @@ -202,38 +191,6 @@ bool emberAfClusterSecurityCustomCallback(EmberAfProfileId profileId, EmberAfClu return false; } -/** @brief Configure Reporting Command - * - * This function is called by the application framework when a Configure - * Reporting command is received from an external device. The Configure - * Reporting command contains a series of attribute reporting configuration - * records. The application should return true if the message was processed or - * false if it was not. - * - * @param cmd Ver.: always - */ -bool emberAfConfigureReportingCommandCallback(const EmberAfClusterCommand * cmd) -{ - return false; -} - -/** @brief Configure Reporting Response - * - * This function is called by the application framework when a Configure - * Reporting Response command is received from an external device. The - * application should return true if the message was processed or false if it - * was not. - * - * @param clusterId The cluster identifier of this response. Ver.: always - * @param buffer Buffer containing the list of attribute status records. Ver.: - * always - * @param bufLen The length in bytes of the list. Ver.: always - */ -bool emberAfConfigureReportingResponseCallback(EmberAfClusterId clusterId, uint8_t * buffer, uint16_t bufLen) -{ - return false; -} - /** @brief Default Response * * This function is called by the application framework when a Default Response @@ -1969,19 +1926,6 @@ bool emberAfReadAttributesResponseCallback(EmberAfClusterId clusterId, uint8_t * return false; } -/** @brief Read Reporting Configuration Command - * - * This function is called by the application framework when a Read Reporting - * Configuration command is received from an external device. The application - * should return true if the message was processed or false if it was not. - * - * @param cmd Ver.: always - */ -bool emberAfReadReportingConfigurationCommandCallback(const EmberAfClusterCommand * cmd) -{ - return false; -} - /** @brief Activate Door Lock Callback * This function is provided by the door lock server plugin. * @@ -1995,23 +1939,6 @@ bool emberAfPluginDoorLockServerActivateDoorLockCallback(bool activate) return false; }; -/** @brief Read Reporting Configuration Response - * - * This function is called by the application framework when a Read Reporting - * Configuration Response command is received from an external device. The - * application should return true if the message was processed or false if it - * was not. - * - * @param clusterId The cluster identifier of this response. Ver.: always - * @param buffer Buffer containing the list of attribute reporting configuration - * records. Ver.: always - * @param bufLen The length in bytes of the list. Ver.: always - */ -bool emberAfReadReportingConfigurationResponseCallback(EmberAfClusterId clusterId, uint8_t * buffer, uint16_t bufLen) -{ - return false; -} - /** @brief Scenes Cluster Recall Saved Scene * * This function is called by the framework when the application should recall a @@ -2124,25 +2051,6 @@ bool emberAfReportAttributesCallback(EmberAfClusterId clusterId, uint8_t * buffe return false; } -/** @brief Reporting Attribute Change - * - * This function is called by the framework when an attribute managed by the - * framework changes. The application should call this function when an - * externally-managed attribute changes. The application should use the change - * notification to inform its reporting decisions. - * - * @param endpoint Ver.: always - * @param clusterId Ver.: always - * @param attributeId Ver.: always - * @param mask Ver.: always - * @param manufacturerCode Ver.: always - * @param type Ver.: always - * @param data Ver.: always - */ -void emberAfReportingAttributeChangeCallback(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attributeId, - uint8_t mask, uint16_t manufacturerCode, EmberAfAttributeType type, uint8_t * data) -{} - /** @brief Scan Error * * This is called by the framework on behalf of the form-and-join library to diff --git a/examples/lock-app/lock-common/BUILD.gn b/examples/lock-app/lock-common/BUILD.gn index 55ef1f3228dba6..2b1d9d654bd1c9 100644 --- a/examples/lock-app/lock-common/BUILD.gn +++ b/examples/lock-app/lock-common/BUILD.gn @@ -26,6 +26,8 @@ source_set("lock-common") { sources = [ "${chip_root}/examples/common/chip-app-server/DataModelHandler.cpp", "${chip_root}/src/app/clusters/on-off-server/on-off.cpp", + "${chip_root}/src/app/reporting/reporting-default-configuration.cpp", + "${chip_root}/src/app/reporting/reporting.cpp", "${chip_root}/src/app/util/af-event.cpp", "${chip_root}/src/app/util/af-main-common.cpp", "${chip_root}/src/app/util/attribute-size.cpp", diff --git a/examples/lock-app/lock-common/gen/callback-stub.c b/examples/lock-app/lock-common/gen/callback-stub.c index 3bc85ee4ef736b..1589dd1a926edd 100644 --- a/examples/lock-app/lock-common/gen/callback-stub.c +++ b/examples/lock-app/lock-common/gen/callback-stub.c @@ -138,17 +138,6 @@ bool emberAfAttributeWriteAccessCallback(uint8_t endpoint, EmberAfClusterId clus */ void emberAfGroupsClusterClearGroupTableCallback(uint8_t endpoint) {} -/** @brief Clear Report Table - * - * This function is called by the framework when the application should clear - * the report table. - * - */ -EmberStatus emberAfClearReportTableCallback(void) -{ - return EMBER_LIBRARY_NOT_PRESENT; -} - /** @brief Scenes Cluster ClearSceneTable * * This function is called by the framework when the application should clear @@ -203,38 +192,6 @@ bool emberAfClusterSecurityCustomCallback(EmberAfProfileId profileId, EmberAfClu return false; } -/** @brief Configure Reporting Command - * - * This function is called by the application framework when a Configure - * Reporting command is received from an external device. The Configure - * Reporting command contains a series of attribute reporting configuration - * records. The application should return true if the message was processed or - * false if it was not. - * - * @param cmd Ver.: always - */ -bool emberAfConfigureReportingCommandCallback(const EmberAfClusterCommand * cmd) -{ - return false; -} - -/** @brief Configure Reporting Response - * - * This function is called by the application framework when a Configure - * Reporting Response command is received from an external device. The - * application should return true if the message was processed or false if it - * was not. - * - * @param clusterId The cluster identifier of this response. Ver.: always - * @param buffer Buffer containing the list of attribute status records. Ver.: - * always - * @param bufLen The length in bytes of the list. Ver.: always - */ -bool emberAfConfigureReportingResponseCallback(EmberAfClusterId clusterId, uint8_t * buffer, uint16_t bufLen) -{ - return false; -} - /** @brief Default Response * * This function is called by the application framework when a Default Response @@ -1970,19 +1927,6 @@ bool emberAfReadAttributesResponseCallback(EmberAfClusterId clusterId, uint8_t * return false; } -/** @brief Read Reporting Configuration Command - * - * This function is called by the application framework when a Read Reporting - * Configuration command is received from an external device. The application - * should return true if the message was processed or false if it was not. - * - * @param cmd Ver.: always - */ -bool emberAfReadReportingConfigurationCommandCallback(const EmberAfClusterCommand * cmd) -{ - return false; -} - /** @brief Activate Door Lock Callback * This function is provided by the door lock server plugin. * @@ -1996,23 +1940,6 @@ bool emberAfPluginDoorLockServerActivateDoorLockCallback(bool activate) return false; }; -/** @brief Read Reporting Configuration Response - * - * This function is called by the application framework when a Read Reporting - * Configuration Response command is received from an external device. The - * application should return true if the message was processed or false if it - * was not. - * - * @param clusterId The cluster identifier of this response. Ver.: always - * @param buffer Buffer containing the list of attribute reporting configuration - * records. Ver.: always - * @param bufLen The length in bytes of the list. Ver.: always - */ -bool emberAfReadReportingConfigurationResponseCallback(EmberAfClusterId clusterId, uint8_t * buffer, uint16_t bufLen) -{ - return false; -} - /** @brief Scenes Cluster Recall Saved Scene * * This function is called by the framework when the application should recall a @@ -2125,25 +2052,6 @@ bool emberAfReportAttributesCallback(EmberAfClusterId clusterId, uint8_t * buffe return false; } -/** @brief Reporting Attribute Change - * - * This function is called by the framework when an attribute managed by the - * framework changes. The application should call this function when an - * externally-managed attribute changes. The application should use the change - * notification to inform its reporting decisions. - * - * @param endpoint Ver.: always - * @param clusterId Ver.: always - * @param attributeId Ver.: always - * @param mask Ver.: always - * @param manufacturerCode Ver.: always - * @param type Ver.: always - * @param data Ver.: always - */ -void emberAfReportingAttributeChangeCallback(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attributeId, - uint8_t mask, uint16_t manufacturerCode, EmberAfAttributeType type, uint8_t * data) -{} - /** @brief Scan Error * * This is called by the framework on behalf of the form-and-join library to diff --git a/examples/lock-app/nrfconnect/CMakeLists.txt b/examples/lock-app/nrfconnect/CMakeLists.txt index 7c71e34343d7ab..2a840eefd7aa7c 100644 --- a/examples/lock-app/nrfconnect/CMakeLists.txt +++ b/examples/lock-app/nrfconnect/CMakeLists.txt @@ -42,6 +42,8 @@ target_sources(app PRIVATE ${CHIP_APP_SERVER}/Server.cpp ${CHIP_APP_SERVER}/QRCodeUtil.cpp ${CHIP_APP_SERVER}/RendezvousServer.cpp + ${CHIP_ROOT}/src/app/reporting/reporting-default-configuration.cpp + ${CHIP_ROOT}/src/app/reporting/reporting.cpp ${CHIP_ROOT}/src/app/util/af-event.cpp ${CHIP_ROOT}/src/app/util/af-main-common.cpp ${CHIP_ROOT}/src/app/util/attribute-size.cpp diff --git a/examples/temperature-measurement-app/esp32/main/gen/callback-stub.c b/examples/temperature-measurement-app/esp32/main/gen/callback-stub.c index 7f9c642dac6c23..3ef3ba55d8a5dd 100644 --- a/examples/temperature-measurement-app/esp32/main/gen/callback-stub.c +++ b/examples/temperature-measurement-app/esp32/main/gen/callback-stub.c @@ -119,17 +119,6 @@ bool emberAfAttributeWriteAccessCallback(uint8_t endpoint, EmberAfClusterId clus */ void emberAfGroupsClusterClearGroupTableCallback(uint8_t endpoint) {} -/** @brief Clear Report Table - * - * This function is called by the framework when the application should clear - * the report table. - * - */ -EmberStatus emberAfClearReportTableCallback(void) -{ - return EMBER_LIBRARY_NOT_PRESENT; -} - /** @brief Scenes Cluster ClearSceneTable * * This function is called by the framework when the application should clear @@ -184,38 +173,6 @@ bool emberAfClusterSecurityCustomCallback(EmberAfProfileId profileId, EmberAfClu return false; } -/** @brief Configure Reporting Command - * - * This function is called by the application framework when a Configure - * Reporting command is received from an external device. The Configure - * Reporting command contains a series of attribute reporting configuration - * records. The application should return true if the message was processed or - * false if it was not. - * - * @param cmd Ver.: always - */ -bool emberAfConfigureReportingCommandCallback(const EmberAfClusterCommand * cmd) -{ - return false; -} - -/** @brief Configure Reporting Response - * - * This function is called by the application framework when a Configure - * Reporting Response command is received from an external device. The - * application should return true if the message was processed or false if it - * was not. - * - * @param clusterId The cluster identifier of this response. Ver.: always - * @param buffer Buffer containing the list of attribute status records. Ver.: - * always - * @param bufLen The length in bytes of the list. Ver.: always - */ -bool emberAfConfigureReportingResponseCallback(EmberAfClusterId clusterId, uint8_t * buffer, uint16_t bufLen) -{ - return false; -} - /** @brief Default Response * * This function is called by the application framework when a Default Response @@ -1975,36 +1932,6 @@ bool emberAfReadAttributesResponseCallback(EmberAfClusterId clusterId, uint8_t * return false; } -/** @brief Read Reporting Configuration Command - * - * This function is called by the application framework when a Read Reporting - * Configuration command is received from an external device. The application - * should return true if the message was processed or false if it was not. - * - * @param cmd Ver.: always - */ -bool emberAfReadReportingConfigurationCommandCallback(const EmberAfClusterCommand * cmd) -{ - return false; -} - -/** @brief Read Reporting Configuration Response - * - * This function is called by the application framework when a Read Reporting - * Configuration Response command is received from an external device. The - * application should return true if the message was processed or false if it - * was not. - * - * @param clusterId The cluster identifier of this response. Ver.: always - * @param buffer Buffer containing the list of attribute reporting configuration - * records. Ver.: always - * @param bufLen The length in bytes of the list. Ver.: always - */ -bool emberAfReadReportingConfigurationResponseCallback(EmberAfClusterId clusterId, uint8_t * buffer, uint16_t bufLen) -{ - return false; -} - /** @brief Scenes Cluster Recall Saved Scene * * This function is called by the framework when the application should recall a @@ -2117,25 +2044,6 @@ bool emberAfReportAttributesCallback(EmberAfClusterId clusterId, uint8_t * buffe return false; } -/** @brief Reporting Attribute Change - * - * This function is called by the framework when an attribute managed by the - * framework changes. The application should call this function when an - * externally-managed attribute changes. The application should use the change - * notification to inform its reporting decisions. - * - * @param endpoint Ver.: always - * @param clusterId Ver.: always - * @param attributeId Ver.: always - * @param mask Ver.: always - * @param manufacturerCode Ver.: always - * @param type Ver.: always - * @param data Ver.: always - */ -void emberAfReportingAttributeChangeCallback(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attributeId, - uint8_t mask, uint16_t manufacturerCode, EmberAfAttributeType type, uint8_t * data) -{} - /** @brief Scan Complete * * This is called by the low-level stack code when an 802.15.4 active scan diff --git a/examples/wifi-echo/server/esp32/main/gen/callback-stub.c b/examples/wifi-echo/server/esp32/main/gen/callback-stub.c index ed5f77ca89525a..f477a63291d5ec 100644 --- a/examples/wifi-echo/server/esp32/main/gen/callback-stub.c +++ b/examples/wifi-echo/server/esp32/main/gen/callback-stub.c @@ -228,23 +228,6 @@ bool emberAfClusterSecurityCustomCallback(EmberAfProfileId profileId, EmberAfClu return false; } -/** @brief Configure Reporting Response - * - * This function is called by the application framework when a Configure - * Reporting Response command is received from an external device. The - * application should return true if the message was processed or false if it - * was not. - * - * @param clusterId The cluster identifier of this response. Ver.: always - * @param buffer Buffer containing the list of attribute status records. Ver.: - * always - * @param bufLen The length in bytes of the list. Ver.: always - */ -bool emberAfConfigureReportingResponseCallback(EmberAfClusterId clusterId, uint8_t * buffer, uint16_t bufLen) -{ - return false; -} - /** @brief Default Response * * This function is called by the application framework when a Default Response @@ -1926,23 +1909,6 @@ bool emberAfReadAttributesResponseCallback(EmberAfClusterId clusterId, uint8_t * return false; } -/** @brief Read Reporting Configuration Response - * - * This function is called by the application framework when a Read Reporting - * Configuration Response command is received from an external device. The - * application should return true if the message was processed or false if it - * was not. - * - * @param clusterId The cluster identifier of this response. Ver.: always - * @param buffer Buffer containing the list of attribute reporting configuration - * records. Ver.: always - * @param bufLen The length in bytes of the list. Ver.: always - */ -bool emberAfReadReportingConfigurationResponseCallback(EmberAfClusterId clusterId, uint8_t * buffer, uint16_t bufLen) -{ - return false; -} - /** @brief Registration Abort * * This callback is called when the device should abort the registration diff --git a/src/app/reporting/reporting.cpp b/src/app/reporting/reporting.cpp index fc007c5322cc1b..4b6731c89918e2 100644 --- a/src/app/reporting/reporting.cpp +++ b/src/app/reporting/reporting.cpp @@ -365,7 +365,7 @@ static void conditionallySendReport(uint8_t endpoint, EmberAfClusterId clusterId } } -bool emberAfConfigureReportingCommandCallback(const EmberAfClusterCommand * cmd) +extern "C" bool emberAfConfigureReportingCommandCallback(const EmberAfClusterCommand * cmd) { EmberStatus sendStatus; uint16_t bufIndex = cmd->payloadStartIndex; @@ -516,7 +516,7 @@ bool emberAfConfigureReportingCommandCallback(const EmberAfClusterCommand * cmd) return true; } -bool emberAfReadReportingConfigurationCommandCallback(const EmberAfClusterCommand * cmd) +extern "C" bool emberAfReadReportingConfigurationCommandCallback(const EmberAfClusterCommand * cmd) { EmberStatus sendStatus; uint16_t bufIndex = cmd->payloadStartIndex; @@ -645,7 +645,7 @@ bool emberAfReadReportingConfigurationCommandCallback(const EmberAfClusterComman return true; } -EmberStatus emberAfClearReportTableCallback(void) +extern "C" EmberStatus emberAfClearReportTableCallback(void) { uint8_t i; for (i = 0; i < REPORT_TABLE_SIZE; i++) @@ -667,8 +667,9 @@ EmberStatus emAfPluginReportingRemoveEntry(uint8_t index) return status; } -void emberAfReportingAttributeChangeCallback(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attributeId, - uint8_t mask, uint16_t manufacturerCode, EmberAfAttributeType type, uint8_t * data) +extern "C" void emberAfReportingAttributeChangeCallback(uint8_t endpoint, EmberAfClusterId clusterId, + EmberAfAttributeId attributeId, uint8_t mask, uint16_t manufacturerCode, + EmberAfAttributeType type, uint8_t * data) { uint8_t i; for (i = 0; i < REPORT_TABLE_SIZE; i++) @@ -1067,3 +1068,13 @@ uint8_t emAfPluginReportingConditionallyAddReportingEntry(EmberAfPluginReporting } return 0; } + +extern "C" bool emberAfConfigureReportingResponseCallback(EmberAfClusterId clusterId, uint8_t * buffer, uint16_t bufLen) +{ + return false; +} + +extern "C" bool emberAfReadReportingConfigurationResponseCallback(EmberAfClusterId clusterId, uint8_t * buffer, uint16_t bufLen) +{ + return false; +} diff --git a/src/app/reporting/reporting.h b/src/app/reporting/reporting.h index aaba2f88401fb9..643d2318bdd15e 100644 --- a/src/app/reporting/reporting.h +++ b/src/app/reporting/reporting.h @@ -48,6 +48,11 @@ // The default reporting will generate a table that is mandatory // but user may still allocate some table for adding more reporting over // the air or by cli as part of reporting plugin. + +#ifndef EMBER_AF_PLUGIN_REPORTING_TABLE_SIZE +#define EMBER_AF_PLUGIN_REPORTING_TABLE_SIZE 5 +#endif // EMBER_AF_PLUGIN_REPORTING_TABLE_SIZE + #ifndef REPORT_TABLE_SIZE #if defined EMBER_AF_GENERATED_REPORTING_CONFIG_DEFAULTS_TABLE_SIZE #define REPORT_TABLE_SIZE (EMBER_AF_GENERATED_REPORTING_CONFIG_DEFAULTS_TABLE_SIZE + EMBER_AF_PLUGIN_REPORTING_TABLE_SIZE) @@ -76,4 +81,87 @@ bool emAfPluginReportingDoEntriesMatch(const EmberAfPluginReportingEntry * const uint8_t emAfPluginReportingConditionallyAddReportingEntry(EmberAfPluginReportingEntry * newEntry); void emberAfPluginReportingLoadReportingConfigDefaults(void); bool emberAfPluginReportingGetReportingConfigDefaults(EmberAfPluginReportingEntry * defaultConfiguration); + +#ifdef __cplusplus +extern "C" { +#endif +/** @brief Configure Reporting Command + * + * This function is called by the application framework when a Configure + * Reporting command is received from an external device. The Configure + * Reporting command contains a series of attribute reporting configuration + * records. The application should return true if the message was processed or + * false if it was not. + * + * @param cmd Ver.: always + */ +bool emberAfConfigureReportingCommandCallback(const EmberAfClusterCommand * cmd); + +/** @brief Read Reporting Configuration Command + * + * This function is called by the application framework when a Read Reporting + * Configuration command is received from an external device. The application + * should return true if the message was processed or false if it was not. + * + * @param cmd Ver.: always + */ +bool emberAfReadReportingConfigurationCommandCallback(const EmberAfClusterCommand * cmd); + +/** @brief Clear Report Table + * + * This function is called by the framework when the application should clear + * the report table. + * + */ +EmberStatus emberAfClearReportTableCallback(void); + +/** @brief Configure Reporting Response + * + * This function is called by the application framework when a Configure + * Reporting Response command is received from an external device. The + * application should return true if the message was processed or false if it + * was not. + * + * @param clusterId The cluster identifier of this response. Ver.: always + * @param buffer Buffer containing the list of attribute status records. Ver.: + * always + * @param bufLen The length in bytes of the list. Ver.: always + */ +bool emberAfConfigureReportingResponseCallback(EmberAfClusterId clusterId, uint8_t * buffer, uint16_t bufLen); + +/** @brief Read Reporting Configuration Response + * + * This function is called by the application framework when a Read Reporting + * Configuration Response command is received from an external device. The + * application should return true if the message was processed or false if it + * was not. + * + * @param clusterId The cluster identifier of this response. Ver.: always + * @param buffer Buffer containing the list of attribute reporting configuration + * records. Ver.: always + * @param bufLen The length in bytes of the list. Ver.: always + */ +bool emberAfReadReportingConfigurationResponseCallback(EmberAfClusterId clusterId, uint8_t * buffer, uint16_t bufLen); + +/** @brief Reporting Attribute Change + * + * This function is called by the framework when an attribute managed by the + * framework changes. The application should call this function when an + * externally-managed attribute changes. The application should use the change + * notification to inform its reporting decisions. + * + * @param endpoint Ver.: always + * @param clusterId Ver.: always + * @param attributeId Ver.: always + * @param mask Ver.: always + * @param manufacturerCode Ver.: always + * @param type Ver.: always + * @param data Ver.: always + */ +void emberAfReportingAttributeChangeCallback(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attributeId, + uint8_t mask, uint16_t manufacturerCode, EmberAfAttributeType type, uint8_t * data); + +#ifdef __cplusplus +} +#endif #endif From 4b00a3316261c227821641e16292578a076e07bd Mon Sep 17 00:00:00 2001 From: Vivien Nicolas Date: Thu, 5 Nov 2020 20:31:32 +0100 Subject: [PATCH 005/234] Rename wifi-echo to all-clusters-app (#3653) --- .github/workflows/examples-esp32.yaml | 4 ++-- .vscode/tasks.json | 4 ++-- .../server => all-clusters-app}/esp32/.gitignore | 0 .../server => all-clusters-app}/esp32/Makefile | 8 ++++---- .../server => all-clusters-app}/esp32/README.md | 10 +++++----- .../server => all-clusters-app}/esp32/idf.sh | 0 .../esp32/main/BluetoothWidget.cpp | 0 .../server => all-clusters-app}/esp32/main/Button.cpp | 0 .../esp32/main/CHIPDeviceManager.cpp | 0 .../esp32/main/DeviceCallbacks.cpp | 0 .../esp32/main/EchoServer.cpp | 0 .../server => all-clusters-app}/esp32/main/Globals.cpp | 0 .../esp32/main/Kconfig.projbuild | 2 +- .../esp32/main/LEDWidget.cpp | 0 .../esp32/main/QRCodeScreen.cpp | 0 .../esp32/main/RendezvousDeviceDelegate.cpp | 0 .../esp32/main/WiFiWidget.cpp | 0 .../esp32/main/component.mk | 0 .../esp32/main/gen/af-gen-event.h | 0 .../esp32/main/gen/af-structs.h | 0 .../esp32/main/gen/att-storage.h | 0 .../esp32/main/gen/attribute-id.h | 0 .../esp32/main/gen/attribute-size.h | 0 .../esp32/main/gen/attribute-type.h | 0 .../esp32/main/gen/call-command-handler.c | 0 .../esp32/main/gen/call-command-handler.h | 0 .../esp32/main/gen/callback-stub.c | 0 .../esp32/main/gen/callback.h | 0 .../esp32/main/gen/cluster-id.h | 0 .../esp32/main/gen/clusters-callback-stubs.c | 0 .../esp32/main/gen/command-id.h | 0 .../esp32/main/gen/endpoint_config.h | 0 .../server => all-clusters-app}/esp32/main/gen/enums.h | 0 .../esp32/main/gen/gen_config.h | 0 .../esp32/main/gen/gen_tokens.h | 0 .../esp32/main/gen/print-cluster.h | 0 .../esp32/main/include/BluetoothWidget.h | 0 .../esp32/main/include/Button.h | 0 .../esp32/main/include/CHIPDeviceManager.h | 0 .../esp32/main/include/DeviceCallbacks.h | 0 .../esp32/main/include/Globals.h | 0 .../esp32/main/include/LEDWidget.h | 0 .../esp32/main/include/QRCodeScreen.h | 0 .../esp32/main/include/RendezvousDeviceDelegate.h | 0 .../esp32/main/include/WiFiWidget.h | 0 .../esp32/main/main.cpp} | 4 ++-- .../server => all-clusters-app}/esp32/partitions.csv | 0 .../esp32/sdkconfig.defaults | 0 .../esp32/sdkconfig_devkit.defaults | 0 .../esp32/sdkconfig_m5stack.defaults | 0 .../all-clusters-app/esp32/third_party/connectedhomeip | 1 + examples/chip-tool/README.md | 2 +- examples/temperature-measurement-app/esp32/Makefile | 2 +- .../esp32/main/Kconfig.projbuild | 2 +- .../esp32/main/{wifi-echo.cpp => main.cpp} | 2 +- .../wifi-echo/server/esp32/third_party/connectedhomeip | 1 - .../{build-wifi-echo.py => build-all-clusters-app.py} | 4 ++-- scripts/examples/esp_echo_app.sh | 2 +- 58 files changed, 24 insertions(+), 24 deletions(-) rename examples/{wifi-echo/server => all-clusters-app}/esp32/.gitignore (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/Makefile (89%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/README.md (95%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/idf.sh (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/BluetoothWidget.cpp (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/Button.cpp (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/CHIPDeviceManager.cpp (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/DeviceCallbacks.cpp (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/EchoServer.cpp (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/Globals.cpp (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/Kconfig.projbuild (99%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/LEDWidget.cpp (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/QRCodeScreen.cpp (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/RendezvousDeviceDelegate.cpp (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/WiFiWidget.cpp (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/component.mk (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/gen/af-gen-event.h (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/gen/af-structs.h (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/gen/att-storage.h (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/gen/attribute-id.h (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/gen/attribute-size.h (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/gen/attribute-type.h (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/gen/call-command-handler.c (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/gen/call-command-handler.h (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/gen/callback-stub.c (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/gen/callback.h (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/gen/cluster-id.h (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/gen/clusters-callback-stubs.c (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/gen/command-id.h (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/gen/endpoint_config.h (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/gen/enums.h (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/gen/gen_config.h (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/gen/gen_tokens.h (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/gen/print-cluster.h (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/include/BluetoothWidget.h (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/include/Button.h (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/include/CHIPDeviceManager.h (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/include/DeviceCallbacks.h (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/include/Globals.h (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/include/LEDWidget.h (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/include/QRCodeScreen.h (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/include/RendezvousDeviceDelegate.h (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/main/include/WiFiWidget.h (100%) rename examples/{wifi-echo/server/esp32/main/wifi-echo.cpp => all-clusters-app/esp32/main/main.cpp} (99%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/partitions.csv (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/sdkconfig.defaults (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/sdkconfig_devkit.defaults (100%) rename examples/{wifi-echo/server => all-clusters-app}/esp32/sdkconfig_m5stack.defaults (100%) create mode 120000 examples/all-clusters-app/esp32/third_party/connectedhomeip rename examples/temperature-measurement-app/esp32/main/{wifi-echo.cpp => main.cpp} (98%) delete mode 120000 examples/wifi-echo/server/esp32/third_party/connectedhomeip rename scripts/examples/{build-wifi-echo.py => build-all-clusters-app.py} (93%) diff --git a/.github/workflows/examples-esp32.yaml b/.github/workflows/examples-esp32.yaml index a1b92d77cd9ee9..cc51698bcd9436 100644 --- a/.github/workflows/examples-esp32.yaml +++ b/.github/workflows/examples-esp32.yaml @@ -51,8 +51,8 @@ jobs: - name: Copy aside build products run: | mkdir -p example_binaries/$BUILD_TYPE-build - cp examples/wifi-echo/server/esp32/build/chip-wifi-echo.elf \ - example_binaries/$BUILD_TYPE-build/chip-wifi-echo.elf + cp examples/all-clusters-app/esp32/build/chip-all-clusters-app.elf \ + example_binaries/$BUILD_TYPE-build/chip-all-clusters-app.elf - name: Binary artifact suffix id: outsuffix uses: haya14busa/action-cond@v1.0.0 diff --git a/.vscode/tasks.json b/.vscode/tasks.json index d9bce7888594dd..11619957ce5e65 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -128,9 +128,9 @@ } }, { - "label": "Build ESP32 Echo Example", + "label": "Build ESP32 all-clusters-app Example", "type": "shell", - "command": "scripts/examples/build-wifi-echo.py", + "command": "scripts/examples/build-all-clusters-app.py", "group": "build", "problemMatcher": ["$gcc"] }, diff --git a/examples/wifi-echo/server/esp32/.gitignore b/examples/all-clusters-app/esp32/.gitignore similarity index 100% rename from examples/wifi-echo/server/esp32/.gitignore rename to examples/all-clusters-app/esp32/.gitignore diff --git a/examples/wifi-echo/server/esp32/Makefile b/examples/all-clusters-app/esp32/Makefile similarity index 89% rename from examples/wifi-echo/server/esp32/Makefile rename to examples/all-clusters-app/esp32/Makefile index 4140c5ee5215f6..69689a82e692a1 100644 --- a/examples/wifi-echo/server/esp32/Makefile +++ b/examples/all-clusters-app/esp32/Makefile @@ -19,12 +19,12 @@ # project subdirectory. # -PROJECT_NAME := chip-wifi-echo +PROJECT_NAME := chip-all-clusters-app EXTRA_COMPONENT_DIRS += $(PROJECT_PATH)/third_party/connectedhomeip/config/esp32/components \ - $(PROJECT_PATH)/../../../common/m5stack-tft/repo/components \ - $(PROJECT_PATH)/../../../common/QRCode \ - $(PROJECT_PATH)/../../../common/screen-framework \ + $(PROJECT_PATH)/../../common/m5stack-tft/repo/components \ + $(PROJECT_PATH)/../../common/QRCode \ + $(PROJECT_PATH)/../../common/screen-framework \ CXXFLAGS += -std=c++11 -Os -DLWIP_IPV6_SCOPES=0 CPPFLAGS += -Os -DLWIP_IPV6_SCOPES=0 -DCHIP_HAVE_CONFIG_H diff --git a/examples/wifi-echo/server/esp32/README.md b/examples/all-clusters-app/esp32/README.md similarity index 95% rename from examples/wifi-echo/server/esp32/README.md rename to examples/all-clusters-app/esp32/README.md index a5340392fe4072..6bda2fb7310dac 100644 --- a/examples/wifi-echo/server/esp32/README.md +++ b/examples/all-clusters-app/esp32/README.md @@ -1,4 +1,4 @@ -# CHIP WiFi Echo Server Example +# CHIP All Clusters Example A prototype appplication that uses CHIP to setup WiFi on the ESP32 and runs an Echo Server. This example will evolve as more complex messaging is supported in @@ -6,7 +6,7 @@ CHIP. --- -- [CHIP WiFi Echo Server Example](#chip-wifi-echo-server-example) +- [CHIP App Server Example](#chip-app-server-example) - [Supported Devices](#supported-devices) - [Building the Example Application](#building-the-example-application) - [To build the application, follow these steps:](#to-build-the-application-follow-these-steps) @@ -65,13 +65,13 @@ make sure the IDF_PATH has been exported(See the manual setup steps above). $ idf make menuconfig - Select ESP32 based `Device Type` through `WiFi Echo Demo`->`Device Type`. + Select ESP32 based `Device Type` through `Demo`->`Device Type`. The device types that are currently supported include `ESP32-DevKitC` (default), `ESP32-WROVER-KIT_V4.1` and `M5Stack` If you are using `standalone chip-tool` to communicate with the ESP32, bypass the Rendezvous mode so that the device can communicate over an insecure channel. - This can be done through `WiFi Echo Demo`->`Rendezvous Mode`->`Bypass` + This can be done through `Demo`->`Rendezvous Mode`->`Bypass` To connect the ESP32 to your network, configure the Wi-Fi SSID and Passphrase through `Component config`->`CHIP Device Layer`->`WiFi Station Options`->`Default WiFi SSID` and @@ -163,7 +163,7 @@ Alternatively, you can connect to the ESP32's Soft-AP directly. In addition to the echo server, this demo also supports controlling OnOff cluster (Server) attributes of an endpoint. For `ESP32-DevKitC` and `ESP32-WROVER-KIT_V4.1`, a GPIO (configurable through `STATUS_LED_GPIO_NUM` in -`main/wifi-echo.cpp`) is updated through the on/off/toggle commands from the +`main/main.cpp`) is updated through the on/off/toggle commands from the `chip-tool`. For `M5Stack`, a virtual Green LED on the display is used for the same. diff --git a/examples/wifi-echo/server/esp32/idf.sh b/examples/all-clusters-app/esp32/idf.sh similarity index 100% rename from examples/wifi-echo/server/esp32/idf.sh rename to examples/all-clusters-app/esp32/idf.sh diff --git a/examples/wifi-echo/server/esp32/main/BluetoothWidget.cpp b/examples/all-clusters-app/esp32/main/BluetoothWidget.cpp similarity index 100% rename from examples/wifi-echo/server/esp32/main/BluetoothWidget.cpp rename to examples/all-clusters-app/esp32/main/BluetoothWidget.cpp diff --git a/examples/wifi-echo/server/esp32/main/Button.cpp b/examples/all-clusters-app/esp32/main/Button.cpp similarity index 100% rename from examples/wifi-echo/server/esp32/main/Button.cpp rename to examples/all-clusters-app/esp32/main/Button.cpp diff --git a/examples/wifi-echo/server/esp32/main/CHIPDeviceManager.cpp b/examples/all-clusters-app/esp32/main/CHIPDeviceManager.cpp similarity index 100% rename from examples/wifi-echo/server/esp32/main/CHIPDeviceManager.cpp rename to examples/all-clusters-app/esp32/main/CHIPDeviceManager.cpp diff --git a/examples/wifi-echo/server/esp32/main/DeviceCallbacks.cpp b/examples/all-clusters-app/esp32/main/DeviceCallbacks.cpp similarity index 100% rename from examples/wifi-echo/server/esp32/main/DeviceCallbacks.cpp rename to examples/all-clusters-app/esp32/main/DeviceCallbacks.cpp diff --git a/examples/wifi-echo/server/esp32/main/EchoServer.cpp b/examples/all-clusters-app/esp32/main/EchoServer.cpp similarity index 100% rename from examples/wifi-echo/server/esp32/main/EchoServer.cpp rename to examples/all-clusters-app/esp32/main/EchoServer.cpp diff --git a/examples/wifi-echo/server/esp32/main/Globals.cpp b/examples/all-clusters-app/esp32/main/Globals.cpp similarity index 100% rename from examples/wifi-echo/server/esp32/main/Globals.cpp rename to examples/all-clusters-app/esp32/main/Globals.cpp diff --git a/examples/wifi-echo/server/esp32/main/Kconfig.projbuild b/examples/all-clusters-app/esp32/main/Kconfig.projbuild similarity index 99% rename from examples/wifi-echo/server/esp32/main/Kconfig.projbuild rename to examples/all-clusters-app/esp32/main/Kconfig.projbuild index 549e8ebd594228..2577ddba2a66ec 100644 --- a/examples/wifi-echo/server/esp32/main/Kconfig.projbuild +++ b/examples/all-clusters-app/esp32/main/Kconfig.projbuild @@ -18,7 +18,7 @@ # Configuration options CHIP ESP32 demo application. # -menu "WiFi Echo Demo" +menu "Demo" choice prompt "Device Type" diff --git a/examples/wifi-echo/server/esp32/main/LEDWidget.cpp b/examples/all-clusters-app/esp32/main/LEDWidget.cpp similarity index 100% rename from examples/wifi-echo/server/esp32/main/LEDWidget.cpp rename to examples/all-clusters-app/esp32/main/LEDWidget.cpp diff --git a/examples/wifi-echo/server/esp32/main/QRCodeScreen.cpp b/examples/all-clusters-app/esp32/main/QRCodeScreen.cpp similarity index 100% rename from examples/wifi-echo/server/esp32/main/QRCodeScreen.cpp rename to examples/all-clusters-app/esp32/main/QRCodeScreen.cpp diff --git a/examples/wifi-echo/server/esp32/main/RendezvousDeviceDelegate.cpp b/examples/all-clusters-app/esp32/main/RendezvousDeviceDelegate.cpp similarity index 100% rename from examples/wifi-echo/server/esp32/main/RendezvousDeviceDelegate.cpp rename to examples/all-clusters-app/esp32/main/RendezvousDeviceDelegate.cpp diff --git a/examples/wifi-echo/server/esp32/main/WiFiWidget.cpp b/examples/all-clusters-app/esp32/main/WiFiWidget.cpp similarity index 100% rename from examples/wifi-echo/server/esp32/main/WiFiWidget.cpp rename to examples/all-clusters-app/esp32/main/WiFiWidget.cpp diff --git a/examples/wifi-echo/server/esp32/main/component.mk b/examples/all-clusters-app/esp32/main/component.mk similarity index 100% rename from examples/wifi-echo/server/esp32/main/component.mk rename to examples/all-clusters-app/esp32/main/component.mk diff --git a/examples/wifi-echo/server/esp32/main/gen/af-gen-event.h b/examples/all-clusters-app/esp32/main/gen/af-gen-event.h similarity index 100% rename from examples/wifi-echo/server/esp32/main/gen/af-gen-event.h rename to examples/all-clusters-app/esp32/main/gen/af-gen-event.h diff --git a/examples/wifi-echo/server/esp32/main/gen/af-structs.h b/examples/all-clusters-app/esp32/main/gen/af-structs.h similarity index 100% rename from examples/wifi-echo/server/esp32/main/gen/af-structs.h rename to examples/all-clusters-app/esp32/main/gen/af-structs.h diff --git a/examples/wifi-echo/server/esp32/main/gen/att-storage.h b/examples/all-clusters-app/esp32/main/gen/att-storage.h similarity index 100% rename from examples/wifi-echo/server/esp32/main/gen/att-storage.h rename to examples/all-clusters-app/esp32/main/gen/att-storage.h diff --git a/examples/wifi-echo/server/esp32/main/gen/attribute-id.h b/examples/all-clusters-app/esp32/main/gen/attribute-id.h similarity index 100% rename from examples/wifi-echo/server/esp32/main/gen/attribute-id.h rename to examples/all-clusters-app/esp32/main/gen/attribute-id.h diff --git a/examples/wifi-echo/server/esp32/main/gen/attribute-size.h b/examples/all-clusters-app/esp32/main/gen/attribute-size.h similarity index 100% rename from examples/wifi-echo/server/esp32/main/gen/attribute-size.h rename to examples/all-clusters-app/esp32/main/gen/attribute-size.h diff --git a/examples/wifi-echo/server/esp32/main/gen/attribute-type.h b/examples/all-clusters-app/esp32/main/gen/attribute-type.h similarity index 100% rename from examples/wifi-echo/server/esp32/main/gen/attribute-type.h rename to examples/all-clusters-app/esp32/main/gen/attribute-type.h diff --git a/examples/wifi-echo/server/esp32/main/gen/call-command-handler.c b/examples/all-clusters-app/esp32/main/gen/call-command-handler.c similarity index 100% rename from examples/wifi-echo/server/esp32/main/gen/call-command-handler.c rename to examples/all-clusters-app/esp32/main/gen/call-command-handler.c diff --git a/examples/wifi-echo/server/esp32/main/gen/call-command-handler.h b/examples/all-clusters-app/esp32/main/gen/call-command-handler.h similarity index 100% rename from examples/wifi-echo/server/esp32/main/gen/call-command-handler.h rename to examples/all-clusters-app/esp32/main/gen/call-command-handler.h diff --git a/examples/wifi-echo/server/esp32/main/gen/callback-stub.c b/examples/all-clusters-app/esp32/main/gen/callback-stub.c similarity index 100% rename from examples/wifi-echo/server/esp32/main/gen/callback-stub.c rename to examples/all-clusters-app/esp32/main/gen/callback-stub.c diff --git a/examples/wifi-echo/server/esp32/main/gen/callback.h b/examples/all-clusters-app/esp32/main/gen/callback.h similarity index 100% rename from examples/wifi-echo/server/esp32/main/gen/callback.h rename to examples/all-clusters-app/esp32/main/gen/callback.h diff --git a/examples/wifi-echo/server/esp32/main/gen/cluster-id.h b/examples/all-clusters-app/esp32/main/gen/cluster-id.h similarity index 100% rename from examples/wifi-echo/server/esp32/main/gen/cluster-id.h rename to examples/all-clusters-app/esp32/main/gen/cluster-id.h diff --git a/examples/wifi-echo/server/esp32/main/gen/clusters-callback-stubs.c b/examples/all-clusters-app/esp32/main/gen/clusters-callback-stubs.c similarity index 100% rename from examples/wifi-echo/server/esp32/main/gen/clusters-callback-stubs.c rename to examples/all-clusters-app/esp32/main/gen/clusters-callback-stubs.c diff --git a/examples/wifi-echo/server/esp32/main/gen/command-id.h b/examples/all-clusters-app/esp32/main/gen/command-id.h similarity index 100% rename from examples/wifi-echo/server/esp32/main/gen/command-id.h rename to examples/all-clusters-app/esp32/main/gen/command-id.h diff --git a/examples/wifi-echo/server/esp32/main/gen/endpoint_config.h b/examples/all-clusters-app/esp32/main/gen/endpoint_config.h similarity index 100% rename from examples/wifi-echo/server/esp32/main/gen/endpoint_config.h rename to examples/all-clusters-app/esp32/main/gen/endpoint_config.h diff --git a/examples/wifi-echo/server/esp32/main/gen/enums.h b/examples/all-clusters-app/esp32/main/gen/enums.h similarity index 100% rename from examples/wifi-echo/server/esp32/main/gen/enums.h rename to examples/all-clusters-app/esp32/main/gen/enums.h diff --git a/examples/wifi-echo/server/esp32/main/gen/gen_config.h b/examples/all-clusters-app/esp32/main/gen/gen_config.h similarity index 100% rename from examples/wifi-echo/server/esp32/main/gen/gen_config.h rename to examples/all-clusters-app/esp32/main/gen/gen_config.h diff --git a/examples/wifi-echo/server/esp32/main/gen/gen_tokens.h b/examples/all-clusters-app/esp32/main/gen/gen_tokens.h similarity index 100% rename from examples/wifi-echo/server/esp32/main/gen/gen_tokens.h rename to examples/all-clusters-app/esp32/main/gen/gen_tokens.h diff --git a/examples/wifi-echo/server/esp32/main/gen/print-cluster.h b/examples/all-clusters-app/esp32/main/gen/print-cluster.h similarity index 100% rename from examples/wifi-echo/server/esp32/main/gen/print-cluster.h rename to examples/all-clusters-app/esp32/main/gen/print-cluster.h diff --git a/examples/wifi-echo/server/esp32/main/include/BluetoothWidget.h b/examples/all-clusters-app/esp32/main/include/BluetoothWidget.h similarity index 100% rename from examples/wifi-echo/server/esp32/main/include/BluetoothWidget.h rename to examples/all-clusters-app/esp32/main/include/BluetoothWidget.h diff --git a/examples/wifi-echo/server/esp32/main/include/Button.h b/examples/all-clusters-app/esp32/main/include/Button.h similarity index 100% rename from examples/wifi-echo/server/esp32/main/include/Button.h rename to examples/all-clusters-app/esp32/main/include/Button.h diff --git a/examples/wifi-echo/server/esp32/main/include/CHIPDeviceManager.h b/examples/all-clusters-app/esp32/main/include/CHIPDeviceManager.h similarity index 100% rename from examples/wifi-echo/server/esp32/main/include/CHIPDeviceManager.h rename to examples/all-clusters-app/esp32/main/include/CHIPDeviceManager.h diff --git a/examples/wifi-echo/server/esp32/main/include/DeviceCallbacks.h b/examples/all-clusters-app/esp32/main/include/DeviceCallbacks.h similarity index 100% rename from examples/wifi-echo/server/esp32/main/include/DeviceCallbacks.h rename to examples/all-clusters-app/esp32/main/include/DeviceCallbacks.h diff --git a/examples/wifi-echo/server/esp32/main/include/Globals.h b/examples/all-clusters-app/esp32/main/include/Globals.h similarity index 100% rename from examples/wifi-echo/server/esp32/main/include/Globals.h rename to examples/all-clusters-app/esp32/main/include/Globals.h diff --git a/examples/wifi-echo/server/esp32/main/include/LEDWidget.h b/examples/all-clusters-app/esp32/main/include/LEDWidget.h similarity index 100% rename from examples/wifi-echo/server/esp32/main/include/LEDWidget.h rename to examples/all-clusters-app/esp32/main/include/LEDWidget.h diff --git a/examples/wifi-echo/server/esp32/main/include/QRCodeScreen.h b/examples/all-clusters-app/esp32/main/include/QRCodeScreen.h similarity index 100% rename from examples/wifi-echo/server/esp32/main/include/QRCodeScreen.h rename to examples/all-clusters-app/esp32/main/include/QRCodeScreen.h diff --git a/examples/wifi-echo/server/esp32/main/include/RendezvousDeviceDelegate.h b/examples/all-clusters-app/esp32/main/include/RendezvousDeviceDelegate.h similarity index 100% rename from examples/wifi-echo/server/esp32/main/include/RendezvousDeviceDelegate.h rename to examples/all-clusters-app/esp32/main/include/RendezvousDeviceDelegate.h diff --git a/examples/wifi-echo/server/esp32/main/include/WiFiWidget.h b/examples/all-clusters-app/esp32/main/include/WiFiWidget.h similarity index 100% rename from examples/wifi-echo/server/esp32/main/include/WiFiWidget.h rename to examples/all-clusters-app/esp32/main/include/WiFiWidget.h diff --git a/examples/wifi-echo/server/esp32/main/wifi-echo.cpp b/examples/all-clusters-app/esp32/main/main.cpp similarity index 99% rename from examples/wifi-echo/server/esp32/main/wifi-echo.cpp rename to examples/all-clusters-app/esp32/main/main.cpp index d8c0db4baf8ddb..0993e68e9cde57 100644 --- a/examples/wifi-echo/server/esp32/main/wifi-echo.cpp +++ b/examples/all-clusters-app/esp32/main/main.cpp @@ -87,7 +87,7 @@ extern void startServer(); extern void PairingComplete(SecurePairingSession * pairing); -const char * TAG = "wifi-echo-demo"; +const char * TAG = "all-clusters-app"; static DeviceCallbacks EchoCallbacks; RendezvousDeviceDelegate * rendezvousDelegate = nullptr; @@ -490,7 +490,7 @@ static SecurePairingUsingTestSecret gTestPairing; extern "C" void app_main() { - ESP_LOGI(TAG, "WiFi Echo Demo!"); + ESP_LOGI(TAG, "All Clusters Demo!"); /* Print chip information */ esp_chip_info_t chip_info; diff --git a/examples/wifi-echo/server/esp32/partitions.csv b/examples/all-clusters-app/esp32/partitions.csv similarity index 100% rename from examples/wifi-echo/server/esp32/partitions.csv rename to examples/all-clusters-app/esp32/partitions.csv diff --git a/examples/wifi-echo/server/esp32/sdkconfig.defaults b/examples/all-clusters-app/esp32/sdkconfig.defaults similarity index 100% rename from examples/wifi-echo/server/esp32/sdkconfig.defaults rename to examples/all-clusters-app/esp32/sdkconfig.defaults diff --git a/examples/wifi-echo/server/esp32/sdkconfig_devkit.defaults b/examples/all-clusters-app/esp32/sdkconfig_devkit.defaults similarity index 100% rename from examples/wifi-echo/server/esp32/sdkconfig_devkit.defaults rename to examples/all-clusters-app/esp32/sdkconfig_devkit.defaults diff --git a/examples/wifi-echo/server/esp32/sdkconfig_m5stack.defaults b/examples/all-clusters-app/esp32/sdkconfig_m5stack.defaults similarity index 100% rename from examples/wifi-echo/server/esp32/sdkconfig_m5stack.defaults rename to examples/all-clusters-app/esp32/sdkconfig_m5stack.defaults diff --git a/examples/all-clusters-app/esp32/third_party/connectedhomeip b/examples/all-clusters-app/esp32/third_party/connectedhomeip new file mode 120000 index 00000000000000..11a54ed360106c --- /dev/null +++ b/examples/all-clusters-app/esp32/third_party/connectedhomeip @@ -0,0 +1 @@ +../../../../ \ No newline at end of file diff --git a/examples/chip-tool/README.md b/examples/chip-tool/README.md index b200ec96f0c6b0..8f41c23fda8f86 100644 --- a/examples/chip-tool/README.md +++ b/examples/chip-tool/README.md @@ -34,7 +34,7 @@ ninja -C out/debug To initiate a client echo request to a BLE device, run the built executable and pass it the discriminator and pairing code of the remote device. The command below uses the default values hard-coded into the debug versions of the ESP32 -wifi-echo app: +all-clusters-app: $ chip-tool echo ble 12345678 3840 diff --git a/examples/temperature-measurement-app/esp32/Makefile b/examples/temperature-measurement-app/esp32/Makefile index 2444cc08f35ba9..88502c0f08b0c7 100644 --- a/examples/temperature-measurement-app/esp32/Makefile +++ b/examples/temperature-measurement-app/esp32/Makefile @@ -19,7 +19,7 @@ # project subdirectory. # -PROJECT_NAME := chip-wifi-echo +PROJECT_NAME := chip-temperature-measurement-app EXTRA_COMPONENT_DIRS += $(PROJECT_PATH)/third_party/connectedhomeip/config/esp32/components \ $(PROJECT_PATH)/../../common/m5stack-tft/repo/components \ diff --git a/examples/temperature-measurement-app/esp32/main/Kconfig.projbuild b/examples/temperature-measurement-app/esp32/main/Kconfig.projbuild index 29e80d2e94b9ae..4889800b5f3538 100644 --- a/examples/temperature-measurement-app/esp32/main/Kconfig.projbuild +++ b/examples/temperature-measurement-app/esp32/main/Kconfig.projbuild @@ -18,7 +18,7 @@ # Configuration options CHIP ESP32 demo application. # -menu "WiFi Echo Demo" +menu "Demo" choice prompt "Device Type" diff --git a/examples/temperature-measurement-app/esp32/main/wifi-echo.cpp b/examples/temperature-measurement-app/esp32/main/main.cpp similarity index 98% rename from examples/temperature-measurement-app/esp32/main/wifi-echo.cpp rename to examples/temperature-measurement-app/esp32/main/main.cpp index edae1b792efbcd..13999ed3637b61 100644 --- a/examples/temperature-measurement-app/esp32/main/wifi-echo.cpp +++ b/examples/temperature-measurement-app/esp32/main/main.cpp @@ -51,7 +51,7 @@ extern void startServer(); extern void PairingComplete(SecurePairingSession * pairing); -const char * TAG = "wifi-echo-demo"; +const char * TAG = "temperature-measurement-app"; static DeviceCallbacks EchoCallbacks; RendezvousDeviceDelegate * rendezvousDelegate = nullptr; diff --git a/examples/wifi-echo/server/esp32/third_party/connectedhomeip b/examples/wifi-echo/server/esp32/third_party/connectedhomeip deleted file mode 120000 index 3efed95be5dbe9..00000000000000 --- a/examples/wifi-echo/server/esp32/third_party/connectedhomeip +++ /dev/null @@ -1 +0,0 @@ -../../../../../ \ No newline at end of file diff --git a/scripts/examples/build-wifi-echo.py b/scripts/examples/build-all-clusters-app.py similarity index 93% rename from scripts/examples/build-wifi-echo.py rename to scripts/examples/build-all-clusters-app.py index eceae51844a640..bf0f73095f3a85 100755 --- a/scripts/examples/build-wifi-echo.py +++ b/scripts/examples/build-all-clusters-app.py @@ -8,7 +8,7 @@ _LOG = logging.getLogger(__name__) -ROOT = 'examples/wifi-echo/server/esp32' +ROOT = 'examples/all-clusters-app/esp32' class IDFExecutor: """Runs specified commands via an executor that activates the CHIP build environment.""" @@ -31,7 +31,7 @@ def execute(self, command): def main(): """Main task if executed standalone.""" - parser = argparse.ArgumentParser(description='Build wifi example app') + parser = argparse.ArgumentParser(description='Build all-clusters-app example') parser.add_argument( '--log-level', default=logging.INFO, diff --git a/scripts/examples/esp_echo_app.sh b/scripts/examples/esp_echo_app.sh index e957e0bed4c7a9..344d130e1b03c4 100755 --- a/scripts/examples/esp_echo_app.sh +++ b/scripts/examples/esp_echo_app.sh @@ -19,7 +19,7 @@ set -x env -root=examples/wifi-echo/server/esp32/ +root=examples/all-clusters-app/esp32/ # shellcheck source=/dev/null source "$root"/idf.sh From 4f757f71661e3c1d56670304a90828d445b7fa6c Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Thu, 5 Nov 2020 21:06:08 -0500 Subject: [PATCH 006/234] Use our EndpointId type in more places. (#3682) --- src/app/chip-zcl-zpro-codec.h | 7 +- .../barrier-control-server.cpp | 28 ++--- .../barrier-control-server.h | 12 +- .../color-control-server.cpp | 102 ++++++++--------- .../door-lock-server-logging.cpp | 4 +- .../door-lock-server-user.cpp | 4 +- .../clusters/groups-server/groups-server.cpp | 15 +-- .../ias-zone-server/ias-zone-server.cpp | 40 +++---- .../ias-zone-server/ias-zone-server.h | 9 +- src/app/clusters/identify/identify.cpp | 24 ++-- .../clusters/level-control/level-control.cpp | 44 ++++---- .../clusters/level-control/level-control.h | 4 +- .../messaging-server/messaging-server.cpp | 14 ++- .../messaging-server/messaging-server.h | 6 +- src/app/clusters/on-off-server/on-off.cpp | 10 +- src/app/clusters/scenes/scenes.cpp | 20 ++-- src/app/clusters/scenes/scenes.h | 4 +- src/app/encoder.cpp | 13 ++- src/app/reporting/reporting.cpp | 12 +- src/app/util/af-event.cpp | 22 ++-- src/app/util/af-main.h | 2 +- src/app/util/af-types.h | 54 ++++----- src/app/util/af.h | 103 +++++++++--------- src/app/util/attribute-storage.cpp | 89 ++++++++------- src/app/util/attribute-storage.h | 52 ++++----- src/app/util/attribute-table.cpp | 47 ++++---- src/app/util/attribute-table.h | 21 ++-- src/app/util/client-api.cpp | 4 +- src/app/util/esi-management.cpp | 6 +- src/app/util/esi-management.h | 7 +- src/app/util/types_stub.h | 6 +- src/app/util/util.cpp | 16 +-- 32 files changed, 426 insertions(+), 375 deletions(-) diff --git a/src/app/chip-zcl-zpro-codec.h b/src/app/chip-zcl-zpro-codec.h index 86d49f1f0ce03e..5794af26f2db96 100644 --- a/src/app/chip-zcl-zpro-codec.h +++ b/src/app/chip-zcl-zpro-codec.h @@ -19,6 +19,7 @@ #define CHIP_ZCL_ZPRO_CODEC_H #include "chip-zcl-zpro-codec-api.h" +#include typedef uint16_t EmberApsOption; @@ -30,11 +31,11 @@ typedef struct /** The application profile ID that describes the format of the message. */ uint16_t profileId; /** The cluster ID for this message. */ - uint16_t clusterId; + CHIPClusterId clusterId; /** The source endpoint. */ - uint8_t sourceEndpoint; + CHIPEndpointId sourceEndpoint; /** The destination endpoint. */ - uint8_t destinationEndpoint; + CHIPEndpointId destinationEndpoint; /** A bitmask of options from the enumeration above. */ EmberApsOption options; /** The group ID for this message, if it is multicast mode. */ diff --git a/src/app/clusters/barrier-control-server/barrier-control-server.cpp b/src/app/clusters/barrier-control-server/barrier-control-server.cpp index e1dd3a1038ceb4..77f2973375a592 100644 --- a/src/app/clusters/barrier-control-server/barrier-control-server.cpp +++ b/src/app/clusters/barrier-control-server/barrier-control-server.cpp @@ -46,6 +46,8 @@ // We need this for initializating default reporting configurations. #include +using namespace chip; + typedef struct { uint8_t currentPosition; @@ -75,7 +77,7 @@ extern "C" void emberAfPluginBarrierControlServerInitCallback(void) {} // ----------------------------------------------------------------------------- // Accessing attributes -uint8_t emAfPluginBarrierControlServerGetBarrierPosition(uint8_t endpoint) +uint8_t emAfPluginBarrierControlServerGetBarrierPosition(EndpointId endpoint) { uint8_t position; EmberAfStatus status = emberAfReadServerAttribute(endpoint, ZCL_BARRIER_CONTROL_CLUSTER_ID, ZCL_BARRIER_POSITION_ATTRIBUTE_ID, @@ -84,14 +86,14 @@ uint8_t emAfPluginBarrierControlServerGetBarrierPosition(uint8_t endpoint) return position; } -void emAfPluginBarrierControlServerSetBarrierPosition(uint8_t endpoint, uint8_t position) +void emAfPluginBarrierControlServerSetBarrierPosition(EndpointId endpoint, uint8_t position) { EmberAfStatus status = emberAfWriteServerAttribute(endpoint, ZCL_BARRIER_CONTROL_CLUSTER_ID, ZCL_BARRIER_POSITION_ATTRIBUTE_ID, &position, ZCL_INT8U_ATTRIBUTE_TYPE); assert(status == EMBER_ZCL_STATUS_SUCCESS); } -bool emAfPluginBarrierControlServerIsPartialBarrierSupported(uint8_t endpoint) +bool emAfPluginBarrierControlServerIsPartialBarrierSupported(EndpointId endpoint) { uint8_t bitmap; EmberAfStatus status = emberAfReadServerAttribute(endpoint, ZCL_BARRIER_CONTROL_CLUSTER_ID, @@ -100,7 +102,7 @@ bool emAfPluginBarrierControlServerIsPartialBarrierSupported(uint8_t endpoint) return READBITS(bitmap, EMBER_AF_BARRIER_CONTROL_CAPABILITIES_PARTIAL_BARRIER); } -static uint16_t getOpenOrClosePeriod(uint8_t endpoint, bool open) +static uint16_t getOpenOrClosePeriod(EndpointId endpoint, bool open) { uint16_t period = 0; EmberAfAttributeId attributeId = 0xFFFF; @@ -127,14 +129,14 @@ static uint16_t getOpenOrClosePeriod(uint8_t endpoint, bool open) return period; } -static void setMovingState(uint8_t endpoint, uint8_t state) +static void setMovingState(EndpointId endpoint, uint8_t state) { EmberAfStatus status = emberAfWriteServerAttribute(endpoint, ZCL_BARRIER_CONTROL_CLUSTER_ID, ZCL_BARRIER_MOVING_STATE_ATTRIBUTE_ID, &state, ZCL_ENUM8_ATTRIBUTE_TYPE); assert(status == EMBER_ZCL_STATUS_SUCCESS); } -uint16_t emAfPluginBarrierControlServerGetSafetyStatus(uint8_t endpoint) +uint16_t emAfPluginBarrierControlServerGetSafetyStatus(EndpointId endpoint) { uint16_t safetyStatus; EmberAfStatus status = @@ -144,13 +146,13 @@ uint16_t emAfPluginBarrierControlServerGetSafetyStatus(uint8_t endpoint) return safetyStatus; } -static bool isRemoteLockoutOn(uint8_t endpoint) +static bool isRemoteLockoutOn(EndpointId endpoint) { uint16_t safetyStatus = emAfPluginBarrierControlServerGetSafetyStatus(endpoint); return READBITS(safetyStatus, EMBER_AF_BARRIER_CONTROL_SAFETY_STATUS_REMOTE_LOCKOUT); } -void emAfPluginBarrierControlServerIncrementEvents(uint8_t endpoint, bool open, bool command) +void emAfPluginBarrierControlServerIncrementEvents(EndpointId endpoint, bool open, bool command) { uint8_t mask = (0 #if defined(ZCL_USING_BARRIER_CONTROL_CLUSTER_BARRIER_OPEN_EVENTS_ATTRIBUTE) @@ -195,7 +197,7 @@ void emAfPluginBarrierControlServerIncrementEvents(uint8_t endpoint, bool open, // ----------------------------------------------------------------------------- // Opening/closing barrier -static uint8_t getCurrentPosition(uint8_t endpoint) +static uint8_t getCurrentPosition(EndpointId endpoint) { // If the BarrierPosition attribute does not store the exact position of the // barrier, then it will be set to 0xFF. If this is the case, then we have no @@ -207,7 +209,7 @@ static uint8_t getCurrentPosition(uint8_t endpoint) : currentPositionFromAttribute); } -static uint32_t calculateDelayMs(uint8_t endpoint, uint8_t targetPosition, bool * opening) +static uint32_t calculateDelayMs(EndpointId endpoint, uint8_t targetPosition, bool * opening) { uint8_t currentPosition = emAfPluginBarrierControlServerGetBarrierPosition(endpoint); *opening = targetPosition > currentPosition; @@ -228,7 +230,7 @@ static uint32_t calculateDelayMs(uint8_t endpoint, uint8_t targetPosition, bool } } -void emberAfBarrierControlClusterServerTickCallback(CHIPEndpointId endpoint) +void emberAfBarrierControlClusterServerTickCallback(EndpointId endpoint) { if (state.currentPosition == state.targetPosition) { @@ -279,7 +281,7 @@ static void sendDefaultResponse(EmberAfStatus status) bool emberAfBarrierControlClusterBarrierControlGoToPercentCallback(uint8_t percentOpen) { - uint8_t endpoint = emberAfCurrentCommand()->apsFrame->destinationEndpoint; + EndpointId endpoint = emberAfCurrentCommand()->apsFrame->destinationEndpoint; EmberAfStatus status = EMBER_ZCL_STATUS_SUCCESS; emberAfBarrierControlClusterPrintln("RX: GoToPercentCallback p=%d", percentOpen); @@ -321,7 +323,7 @@ bool emberAfBarrierControlClusterBarrierControlGoToPercentCallback(uint8_t perce bool emberAfBarrierControlClusterBarrierControlStopCallback(void) { - uint8_t endpoint = emberAfCurrentCommand()->apsFrame->destinationEndpoint; + EndpointId endpoint = emberAfCurrentCommand()->apsFrame->destinationEndpoint; emberAfDeactivateServerTick(endpoint, ZCL_BARRIER_CONTROL_CLUSTER_ID); setMovingState(endpoint, EMBER_ZCL_BARRIER_CONTROL_MOVING_STATE_STOPPED); sendDefaultResponse(EMBER_ZCL_STATUS_SUCCESS); diff --git a/src/app/clusters/barrier-control-server/barrier-control-server.h b/src/app/clusters/barrier-control-server/barrier-control-server.h index 3cbc6d44c6ee71..c6e86b6a920927 100644 --- a/src/app/clusters/barrier-control-server/barrier-control-server.h +++ b/src/app/clusters/barrier-control-server/barrier-control-server.h @@ -43,29 +43,31 @@ #include #include +#include + #ifndef DOXYGEN_SHOULD_SKIP_THIS // There are helper getter/setting APIs that are shared between the core // implementation and the CLI code. They are private to the plugin. // This will always either return the current BarrierPosition attribute value // or assert. -uint8_t emAfPluginBarrierControlServerGetBarrierPosition(uint8_t endpoint); +uint8_t emAfPluginBarrierControlServerGetBarrierPosition(CHIPEndpointId endpoint); // This will always either set the current BarrierPosition attribute value or // assert. -void emAfPluginBarrierControlServerSetBarrierPosition(uint8_t endpoint, uint8_t barrierPosition); +void emAfPluginBarrierControlServerSetBarrierPosition(CHIPEndpointId endpoint, uint8_t barrierPosition); // This will either return whether or not the PartialBarrier bit is set in the // Capabilities attribute value, or it will assert. -bool emAfPluginBarrierControlServerIsPartialBarrierSupported(uint8_t endpoint); +bool emAfPluginBarrierControlServerIsPartialBarrierSupported(CHIPEndpointId endpoint); // This will increment the OpenEvents, CloseEvents, CommandOpenEvents, and // CommandCloseEvents attribute values depending on which combination of the // open and command arguments are passed, or assert. -void emAfPluginBarrierControlServerIncrementEvents(uint8_t endpoint, bool open, bool command); +void emAfPluginBarrierControlServerIncrementEvents(CHIPEndpointId endpoint, bool open, bool command); // This will read the SafetyStatus attribute and return the value, or assert. -uint16_t emAfPluginBarrierControlServerGetSafetyStatus(uint8_t endpoint); +uint16_t emAfPluginBarrierControlServerGetSafetyStatus(CHIPEndpointId endpoint); // We use a minimum delay so that our barrier changes position in a realistic // amount of time. diff --git a/src/app/clusters/color-control-server/color-control-server.cpp b/src/app/clusters/color-control-server/color-control-server.cpp index 2fc6266c82b153..c1d9ab6f385419 100644 --- a/src/app/clusters/color-control-server/color-control-server.cpp +++ b/src/app/clusters/color-control-server/color-control-server.cpp @@ -48,6 +48,8 @@ #include #endif +using namespace chip; + #define COLOR_TEMP_CONTROL emberAfPluginColorControlServerTempTransitionEventControl #define COLOR_XY_CONTROL emberAfPluginColorControlServerXyTransitionEventControl #define COLOR_HSV_CONTROL emberAfPluginColorControlServerHueSatTransitionEventControl @@ -109,7 +111,7 @@ typedef struct uint8_t finalHue; uint16_t stepsRemaining; uint16_t stepsTotal; - uint8_t endpoint; + EndpointId endpoint; bool up; bool repeat; } ColorHueTransitionState; @@ -125,7 +127,7 @@ typedef struct uint16_t stepsTotal; uint16_t lowLimit; uint16_t highLimit; - uint8_t endpoint; + EndpointId endpoint; } Color16uTransitionState; static Color16uTransitionState colorXTransitionState; @@ -138,29 +140,29 @@ static Color16uTransitionState colorSaturationTransitionState; // Forward declarations: static bool computeNewColor16uValue(Color16uTransitionState * p); static void stopAllColorTransitions(void); -static void handleModeSwitch(uint8_t endpoint, uint8_t newColorMode); -static bool shouldExecuteIfOff(uint8_t endpoint, uint8_t optionMask, uint8_t optionOverride); +static void handleModeSwitch(EndpointId endpoint, uint8_t newColorMode); +static bool shouldExecuteIfOff(EndpointId endpoint, uint8_t optionMask, uint8_t optionOverride); #ifdef EMBER_AF_PLUGIN_COLOR_CONTROL_SERVER_HSV static uint8_t addHue(uint8_t hue1, uint8_t hue2); static uint8_t subtractHue(uint8_t hue1, uint8_t hue2); static uint8_t addSaturation(uint8_t saturation1, uint8_t saturation2); static uint8_t subtractSaturation(uint8_t saturation1, uint8_t saturation2); -static void initHueSat(uint8_t endpoint); -static uint8_t readHue(uint8_t endpoint); -static uint8_t readSaturation(uint8_t endpoint); +static void initHueSat(EndpointId endpoint); +static uint8_t readHue(EndpointId endpoint); +static uint8_t readSaturation(EndpointId endpoint); #endif #ifdef EMBER_AF_PLUGIN_COLOR_CONTROL_SERVER_XY static uint16_t findNewColorValueFromStep(uint16_t oldValue, int16_t step); -static uint16_t readColorX(uint8_t endpoint); -static uint16_t readColorY(uint8_t endpoint); +static uint16_t readColorX(EndpointId endpoint); +static uint16_t readColorY(EndpointId endpoint); #endif static uint16_t computeTransitionTimeFromStateAndRate(Color16uTransitionState * p, uint16_t rate); // convenient token handling functions -static uint8_t readColorMode(uint8_t endpoint) +static uint8_t readColorMode(EndpointId endpoint) { uint8_t colorMode; @@ -171,7 +173,7 @@ static uint8_t readColorMode(uint8_t endpoint) return colorMode; } -static uint16_t readColorTemperature(uint8_t endpoint) +static uint16_t readColorTemperature(EndpointId endpoint) { uint16_t colorTemperature; @@ -182,7 +184,7 @@ static uint16_t readColorTemperature(uint8_t endpoint) return colorTemperature; } -static uint16_t readColorTemperatureMin(uint8_t endpoint) +static uint16_t readColorTemperatureMin(EndpointId endpoint) { uint16_t colorTemperatureMin; EmberStatus status; @@ -199,7 +201,7 @@ static uint16_t readColorTemperatureMin(uint8_t endpoint) return colorTemperatureMin; } -static uint16_t readColorTemperatureMax(uint8_t endpoint) +static uint16_t readColorTemperatureMax(EndpointId endpoint) { uint16_t colorTemperatureMax; EmberStatus status; @@ -216,7 +218,7 @@ static uint16_t readColorTemperatureMax(uint8_t endpoint) return colorTemperatureMax; } -static uint16_t readColorTemperatureCoupleToLevelMin(uint8_t endpoint) +static uint16_t readColorTemperatureCoupleToLevelMin(EndpointId endpoint) { uint16_t colorTemperatureCoupleToLevelMin; EmberStatus status; @@ -234,7 +236,7 @@ static uint16_t readColorTemperatureCoupleToLevelMin(uint8_t endpoint) return colorTemperatureCoupleToLevelMin; } -static uint8_t readLevelControlCurrentLevel(uint8_t endpoint) +static uint8_t readLevelControlCurrentLevel(EndpointId endpoint) { uint8_t currentLevel; EmberStatus status; @@ -250,14 +252,14 @@ static uint8_t readLevelControlCurrentLevel(uint8_t endpoint) return currentLevel; } -static void writeRemainingTime(uint8_t endpoint, uint16_t remainingTime) +static void writeRemainingTime(EndpointId endpoint, uint16_t remainingTime) { assert(EMBER_ZCL_STATUS_SUCCESS == emberAfWriteServerAttribute(endpoint, ZCL_COLOR_CONTROL_CLUSTER_ID, ZCL_COLOR_CONTROL_REMAINING_TIME_ATTRIBUTE_ID, (uint8_t *) &remainingTime, ZCL_INT16U_ATTRIBUTE_TYPE)); } -static void writeColorMode(uint8_t endpoint, uint8_t colorMode) +static void writeColorMode(EndpointId endpoint, uint8_t colorMode) { assert(EMBER_ZCL_STATUS_SUCCESS == emberAfWriteServerAttribute(endpoint, ZCL_COLOR_CONTROL_CLUSTER_ID, ZCL_COLOR_CONTROL_ENHANCED_COLOR_MODE_ATTRIBUTE_ID, @@ -268,35 +270,35 @@ static void writeColorMode(uint8_t endpoint, uint8_t colorMode) (uint8_t *) &colorMode, ZCL_INT8U_ATTRIBUTE_TYPE)); } -static void writeHue(uint8_t endpoint, uint8_t hue) +static void writeHue(EndpointId endpoint, uint8_t hue) { assert(EMBER_ZCL_STATUS_SUCCESS == emberAfWriteServerAttribute(endpoint, ZCL_COLOR_CONTROL_CLUSTER_ID, ZCL_COLOR_CONTROL_CURRENT_HUE_ATTRIBUTE_ID, (uint8_t *) &hue, ZCL_INT8U_ATTRIBUTE_TYPE)); } -static void writeSaturation(uint8_t endpoint, uint8_t saturation) +static void writeSaturation(EndpointId endpoint, uint8_t saturation) { assert(EMBER_ZCL_STATUS_SUCCESS == emberAfWriteServerAttribute(endpoint, ZCL_COLOR_CONTROL_CLUSTER_ID, ZCL_COLOR_CONTROL_CURRENT_SATURATION_ATTRIBUTE_ID, (uint8_t *) &saturation, ZCL_INT8U_ATTRIBUTE_TYPE)); } -static void writeColorX(uint8_t endpoint, uint16_t colorX) +static void writeColorX(EndpointId endpoint, uint16_t colorX) { assert(EMBER_ZCL_STATUS_SUCCESS == emberAfWriteServerAttribute(endpoint, ZCL_COLOR_CONTROL_CLUSTER_ID, ZCL_COLOR_CONTROL_CURRENT_X_ATTRIBUTE_ID, (uint8_t *) &colorX, ZCL_INT16U_ATTRIBUTE_TYPE)); } -static void writeColorY(uint8_t endpoint, uint16_t colorY) +static void writeColorY(EndpointId endpoint, uint16_t colorY) { assert(EMBER_ZCL_STATUS_SUCCESS == emberAfWriteServerAttribute(endpoint, ZCL_COLOR_CONTROL_CLUSTER_ID, ZCL_COLOR_CONTROL_CURRENT_Y_ATTRIBUTE_ID, (uint8_t *) &colorY, ZCL_INT16U_ATTRIBUTE_TYPE)); } -static void writeColorTemperature(uint8_t endpoint, uint16_t colorTemperature) +static void writeColorTemperature(EndpointId endpoint, uint16_t colorTemperature) { assert(EMBER_ZCL_STATUS_SUCCESS == emberAfWriteServerAttribute(endpoint, ZCL_COLOR_CONTROL_CLUSTER_ID, ZCL_COLOR_CONTROL_COLOR_TEMPERATURE_ATTRIBUTE_ID, @@ -318,8 +320,8 @@ static void writeColorTemperature(uint8_t endpoint, uint16_t colorTemperature) bool emberAfColorControlClusterMoveToHueAndSaturationCallback(uint8_t hue, uint8_t saturation, uint16_t transitionTime, uint8_t optionsMask, uint8_t optionsOverride) { - uint8_t endpoint = emberAfCurrentEndpoint(); - uint8_t currentHue = readHue(endpoint); + EndpointId endpoint = emberAfCurrentEndpoint(); + uint8_t currentHue = readHue(endpoint); bool moveUp; if (transitionTime == 0) @@ -389,7 +391,7 @@ bool emberAfColorControlClusterMoveToHueAndSaturationCallback(uint8_t hue, uint8 bool emberAfColorControlClusterMoveHueCallback(uint8_t moveMode, uint8_t rate, uint8_t optionsMask, uint8_t optionsOverride) { - uint8_t endpoint = emberAfCurrentEndpoint(); + EndpointId endpoint = emberAfCurrentEndpoint(); if (!shouldExecuteIfOff(endpoint, optionsMask, optionsOverride)) { @@ -448,7 +450,7 @@ bool emberAfColorControlClusterMoveHueCallback(uint8_t moveMode, uint8_t rate, u bool emberAfColorControlClusterMoveSaturationCallback(uint8_t moveMode, uint8_t rate, uint8_t optionsMask, uint8_t optionsOverride) { - uint8_t endpoint = emberAfCurrentEndpoint(); + EndpointId endpoint = emberAfCurrentEndpoint(); if (!shouldExecuteIfOff(endpoint, optionsMask, optionsOverride)) { @@ -506,7 +508,7 @@ bool emberAfColorControlClusterMoveSaturationCallback(uint8_t moveMode, uint8_t bool emberAfColorControlClusterMoveToHueCallback(uint8_t hue, uint8_t hueMoveMode, uint16_t transitionTime, uint8_t optionsMask, uint8_t optionsOverride) { - uint8_t endpoint = emberAfCurrentEndpoint(); + EndpointId endpoint = emberAfCurrentEndpoint(); if (!shouldExecuteIfOff(endpoint, optionsMask, optionsOverride)) { @@ -599,7 +601,7 @@ bool emberAfColorControlClusterMoveToHueCallback(uint8_t hue, uint8_t hueMoveMod bool emberAfColorControlClusterMoveToSaturationCallback(uint8_t saturation, uint16_t transitionTime, uint8_t optionsMask, uint8_t optionsOverride) { - uint8_t endpoint = emberAfCurrentEndpoint(); + EndpointId endpoint = emberAfCurrentEndpoint(); if (!shouldExecuteIfOff(endpoint, optionsMask, optionsOverride)) { @@ -652,7 +654,7 @@ bool emberAfColorControlClusterMoveToSaturationCallback(uint8_t saturation, uint bool emberAfColorControlClusterStepHueCallback(uint8_t stepMode, uint8_t stepSize, uint8_t transitionTime, uint8_t optionsMask, uint8_t optionsOverride) { - uint8_t endpoint = emberAfCurrentEndpoint(); + EndpointId endpoint = emberAfCurrentEndpoint(); if (!shouldExecuteIfOff(endpoint, optionsMask, optionsOverride)) { @@ -714,7 +716,7 @@ bool emberAfColorControlClusterStepHueCallback(uint8_t stepMode, uint8_t stepSiz bool emberAfColorControlClusterStepSaturationCallback(uint8_t stepMode, uint8_t stepSize, uint8_t transitionTime, uint8_t optionsMask, uint8_t optionsOverride) { - uint8_t endpoint = emberAfCurrentEndpoint(); + EndpointId endpoint = emberAfCurrentEndpoint(); if (!shouldExecuteIfOff(endpoint, optionsMask, optionsOverride)) { @@ -800,7 +802,7 @@ static uint8_t subtractSaturation(uint8_t saturation1, uint8_t saturation2) // any time we call a hue or saturation transition, we need to assume certain // things about the hue and saturation data structures. This function will // properly initialize them. -static void initHueSat(uint8_t endpoint) +static void initHueSat(EndpointId endpoint) { colorHueTransitionState.stepsRemaining = 0; colorHueTransitionState.currentHue = readHue(endpoint); @@ -811,7 +813,7 @@ static void initHueSat(uint8_t endpoint) colorSaturationTransitionState.endpoint = endpoint; } -static uint8_t readHue(uint8_t endpoint) +static uint8_t readHue(EndpointId endpoint) { uint8_t hue; @@ -822,7 +824,7 @@ static uint8_t readHue(uint8_t endpoint) return hue; } -static uint8_t readSaturation(uint8_t endpoint) +static uint8_t readSaturation(EndpointId endpoint) { uint8_t saturation; @@ -840,7 +842,7 @@ static uint8_t readSaturation(uint8_t endpoint) bool emberAfColorControlClusterMoveToColorCallback(uint16_t colorX, uint16_t colorY, uint16_t transitionTime, uint8_t optionsMask, uint8_t optionsOverride) { - uint8_t endpoint = emberAfCurrentEndpoint(); + EndpointId endpoint = emberAfCurrentEndpoint(); if (!shouldExecuteIfOff(endpoint, optionsMask, optionsOverride)) { @@ -889,7 +891,7 @@ bool emberAfColorControlClusterMoveToColorCallback(uint16_t colorX, uint16_t col bool emberAfColorControlClusterMoveColorCallback(int16_t rateX, int16_t rateY, uint8_t optionsMask, uint8_t optionsOverride) { - uint8_t endpoint = emberAfCurrentEndpoint(); + EndpointId endpoint = emberAfCurrentEndpoint(); if (!shouldExecuteIfOff(endpoint, optionsMask, optionsOverride)) { @@ -970,7 +972,7 @@ bool emberAfColorControlClusterMoveColorCallback(int16_t rateX, int16_t rateY, u bool emberAfColorControlClusterStepColorCallback(int16_t stepX, int16_t stepY, uint16_t transitionTime, uint8_t optionsMask, uint8_t optionsOverride) { - uint8_t endpoint = emberAfCurrentEndpoint(); + EndpointId endpoint = emberAfCurrentEndpoint(); if (!shouldExecuteIfOff(endpoint, optionsMask, optionsOverride)) { @@ -1043,7 +1045,7 @@ static uint16_t findNewColorValueFromStep(uint16_t oldValue, int16_t step) return newValue; } -static uint16_t readColorX(uint8_t endpoint) +static uint16_t readColorX(EndpointId endpoint) { uint16_t colorX; @@ -1054,7 +1056,7 @@ static uint16_t readColorX(uint8_t endpoint) return colorX; } -static uint16_t readColorY(uint8_t endpoint) +static uint16_t readColorY(EndpointId endpoint) { uint16_t colorY; @@ -1069,7 +1071,7 @@ static uint16_t readColorY(uint8_t endpoint) #ifdef EMBER_AF_PLUGIN_COLOR_CONTROL_SERVER_TEMP -static void moveToColorTemp(uint8_t endpoint, uint16_t colorTemperature, uint16_t transitionTime) +static void moveToColorTemp(EndpointId endpoint, uint16_t colorTemperature, uint16_t transitionTime) { uint16_t temperatureMin = readColorTemperatureMin(endpoint); uint16_t temperatureMax = readColorTemperatureMax(endpoint); @@ -1112,7 +1114,7 @@ static void moveToColorTemp(uint8_t endpoint, uint16_t colorTemperature, uint16_ bool emberAfColorControlClusterMoveToColorTemperatureCallback(uint16_t colorTemperature, uint16_t transitionTime, uint8_t optionsMask, uint8_t optionsOverride) { - uint8_t endpoint = emberAfCurrentEndpoint(); + EndpointId endpoint = emberAfCurrentEndpoint(); if (!shouldExecuteIfOff(endpoint, optionsMask, optionsOverride)) { @@ -1130,7 +1132,7 @@ bool emberAfColorControlClusterMoveColorTemperatureCallback(uint8_t moveMode, ui uint16_t colorTemperatureMaximum, uint8_t optionsMask, uint8_t optionsOverride) { - uint8_t endpoint = emberAfCurrentEndpoint(); + EndpointId endpoint = emberAfCurrentEndpoint(); if (!shouldExecuteIfOff(endpoint, optionsMask, optionsOverride)) { @@ -1214,7 +1216,7 @@ bool emberAfColorControlClusterStepColorTemperatureCallback(uint8_t stepMode, ui uint16_t colorTemperatureMinimum, uint16_t colorTemperatureMaximum, uint8_t optionsMask, uint8_t optionsOverride) { - uint8_t endpoint = emberAfCurrentEndpoint(); + EndpointId endpoint = emberAfCurrentEndpoint(); if (!shouldExecuteIfOff(endpoint, optionsMask, optionsOverride)) { @@ -1277,7 +1279,7 @@ bool emberAfColorControlClusterStepColorTemperatureCallback(uint8_t stepMode, ui return true; } -void emberAfPluginLevelControlCoupledColorTempChangeCallback(uint8_t endpoint) +void emberAfPluginLevelControlCoupledColorTempChangeCallback(EndpointId endpoint) { // ZCL 5.2.2.1.1 Coupling color temperature to Level Control // @@ -1350,7 +1352,7 @@ void emberAfPluginLevelControlCoupledColorTempChangeCallback(uint8_t endpoint) bool emberAfColorControlClusterStopMoveStepCallback(uint8_t optionsMask, uint8_t optionsOverride) { // Received a stop command. This is all we need to do. - uint8_t endpoint = emberAfCurrentEndpoint(); + EndpointId endpoint = emberAfCurrentEndpoint(); if (shouldExecuteIfOff(endpoint, optionsMask, optionsOverride)) { @@ -1381,7 +1383,7 @@ void emberAfPluginColorControlServerStopTransition(void) // the new mode, this must be avoided. // I am putting in this function to compute the new attributes based on the old // color mode. -static void handleModeSwitch(uint8_t endpoint, uint8_t newColorMode) +static void handleModeSwitch(EndpointId endpoint, uint8_t newColorMode) { uint8_t oldColorMode = readColorMode(endpoint); uint8_t colorModeTransition; @@ -1532,7 +1534,7 @@ static bool computeNewHueValue(ColorHueTransitionState * p) extern "C" void emberAfPluginColorControlServerHueSatTransitionEventHandler(void) { - uint8_t endpoint = colorHueTransitionState.endpoint; + EndpointId endpoint = colorHueTransitionState.endpoint; bool limitReached1, limitReached2; limitReached1 = computeNewHueValue(&colorHueTransitionState); @@ -1634,7 +1636,7 @@ static uint16_t computeTransitionTimeFromStateAndRate(Color16uTransitionState * extern "C" void emberAfPluginColorControlServerXyTransitionEventHandler(void) { - uint8_t endpoint = colorXTransitionState.endpoint; + EndpointId endpoint = colorXTransitionState.endpoint; bool limitReachedX, limitReachedY; // compute new values for X and Y. @@ -1663,7 +1665,7 @@ extern "C" void emberAfPluginColorControlServerXyTransitionEventHandler(void) extern "C" void emberAfPluginColorControlServerTempTransitionEventHandler(void) { - uint8_t endpoint = colorTempTransitionState.endpoint; + EndpointId endpoint = colorTempTransitionState.endpoint; bool limitReached; limitReached = computeNewColor16uValue(&colorTempTransitionState); @@ -1684,7 +1686,7 @@ extern "C" void emberAfPluginColorControlServerTempTransitionEventHandler(void) emberAfPluginColorControlServerComputePwmFromTempCallback(endpoint); } -static bool shouldExecuteIfOff(uint8_t endpoint, uint8_t optionMask, uint8_t optionOverride) +static bool shouldExecuteIfOff(EndpointId endpoint, uint8_t optionMask, uint8_t optionOverride) { // From 5.2.2.2.1.10 of ZCL7 document 14-0129-15f-zcl-ch-5-lighting.docx: // "Command execution SHALL NOT continue beyond the Options processing if @@ -1757,7 +1759,7 @@ static bool shouldExecuteIfOff(uint8_t endpoint, uint8_t optionMask, uint8_t opt return (READBITS(options, EMBER_ZCL_COLOR_CONTROL_OPTIONS_EXECUTE_IF_OFF)); } -void emberAfColorControlClusterServerInitCallback(uint8_t endpoint) +void emberAfColorControlClusterServerInitCallback(EndpointId endpoint) { #ifdef EMBER_AF_PLUGIN_COLOR_CONTROL_SERVER_TEMP // 07-5123-07 (i.e. ZCL 7) 5.2.2.2.1.22 StartUpColorTemperatureMireds Attribute diff --git a/src/app/clusters/door-lock-server/door-lock-server-logging.cpp b/src/app/clusters/door-lock-server/door-lock-server-logging.cpp index acacab409d81b2..464783590dd01e 100644 --- a/src/app/clusters/door-lock-server/door-lock-server-logging.cpp +++ b/src/app/clusters/door-lock-server/door-lock-server-logging.cpp @@ -44,6 +44,8 @@ #include +using namespace chip; + static EmberAfPluginDoorLockServerLogEntry entries[EMBER_AF_PLUGIN_DOOR_LOCK_SERVER_MAX_LOG_ENTRIES]; static uint8_t nextEntryId = 1; @@ -55,7 +57,7 @@ static uint8_t nextEntryId = 1; static bool loggingIsEnabled(void) { // This is hardcoded to endpoint 1 because...we need to add endpoint support... - uint8_t endpoint = 1; + EndpointId endpoint = 1; bool logging = false; EmberAfStatus status = emberAfReadServerAttribute(endpoint, ZCL_DOOR_LOCK_CLUSTER_ID, ZCL_ENABLE_LOGGING_ATTRIBUTE_ID, (uint8_t *) &logging, sizeof(logging)); diff --git a/src/app/clusters/door-lock-server/door-lock-server-user.cpp b/src/app/clusters/door-lock-server/door-lock-server-user.cpp index f7a96743c1d593..38c8d67ccb7308 100644 --- a/src/app/clusters/door-lock-server/door-lock-server-user.cpp +++ b/src/app/clusters/door-lock-server/door-lock-server-user.cpp @@ -45,6 +45,8 @@ #include +using namespace chip; + EmberEventControl emberAfPluginDoorLockServerLockoutEventControl; EmberEventControl emberAfPluginDoorLockServerRelockEventControl; @@ -722,7 +724,7 @@ extern "C" void emberAfPluginDoorLockServerRelockEventHandler(void) emberAfDoorLockClusterPrintln("Door automatically relocked: 0x%X", status); } -void emberAfDoorLockClusterServerAttributeChangedCallback(uint8_t endpoint, EmberAfAttributeId attributeId) +void emberAfDoorLockClusterServerAttributeChangedCallback(EndpointId endpoint, EmberAfAttributeId attributeId) { if (endpoint == DOOR_LOCK_SERVER_ENDPOINT && attributeId == ZCL_LOCK_STATE_ATTRIBUTE_ID) { diff --git a/src/app/clusters/groups-server/groups-server.cpp b/src/app/clusters/groups-server/groups-server.cpp index d742659c52e057..9e9bd6217d6490 100644 --- a/src/app/clusters/groups-server/groups-server.cpp +++ b/src/app/clusters/groups-server/groups-server.cpp @@ -50,13 +50,13 @@ using namespace chip; -static bool isGroupPresent(uint8_t endpoint, GroupId groupId); +static bool isGroupPresent(EndpointId endpoint, GroupId groupId); -static bool bindingGroupMatch(uint8_t endpoint, GroupId groupId, EmberBindingTableEntry * entry); +static bool bindingGroupMatch(EndpointId endpoint, GroupId groupId, EmberBindingTableEntry * entry); -static uint8_t findGroupIndex(uint8_t endpoint, GroupId groupId); +static uint8_t findGroupIndex(EndpointId endpoint, GroupId groupId); -void emberAfGroupsClusterServerInitCallback(uint8_t endpoint) +void emberAfGroupsClusterServerInitCallback(EndpointId endpoint) { // The high bit of Name Support indicates whether group names are supported. // Group names are not supported by this plugin. @@ -311,8 +311,9 @@ bool emberAfGroupsClusterRemoveGroupCallback(GroupId groupId) bool emberAfGroupsClusterRemoveAllGroupsCallback(void) { EmberStatus sendStatus; - uint8_t i, endpoint = emberAfCurrentEndpoint(); - bool success = true; + uint8_t i; + EndpointId endpoint = emberAfCurrentEndpoint(); + bool success = true; emberAfGroupsClusterPrintln("RX: RemoveAllGroups"); @@ -387,7 +388,7 @@ bool emberAfGroupsClusterEndpointInGroupCallback(EndpointId endpoint, GroupId gr return isGroupPresent(endpoint, groupId); } -void emberAfGroupsClusterClearGroupTableCallback(uint8_t endpoint) +void emberAfGroupsClusterClearGroupTableCallback(EndpointId endpoint) { uint8_t i, networkIndex = 0 /* emberGetCurrentNetwork() */; for (i = 0; i < EMBER_BINDING_TABLE_SIZE; i++) diff --git a/src/app/clusters/ias-zone-server/ias-zone-server.cpp b/src/app/clusters/ias-zone-server/ias-zone-server.cpp index 11a8822e70eec5..c28cfc4369a8c2 100644 --- a/src/app/clusters/ias-zone-server/ias-zone-server.cpp +++ b/src/app/clusters/ias-zone-server/ias-zone-server.cpp @@ -56,6 +56,8 @@ #include #include +using namespace chip; + #define UNDEFINED_ZONE_ID 0xFF #define DELAY_TIMER_MS (1 * MILLISECOND_TICKS_PER_SECOND) #define IAS_ZONE_SERVER_PAYLOAD_COMMAND_IDX 0x02 @@ -80,7 +82,7 @@ typedef struct { - uint8_t endpoint; + EndpointId endpoint; uint16_t status; uint32_t eventTimeMs; } IasZoneStatusQueueEntry; @@ -136,8 +138,8 @@ static void resetCurrentQueueRetryParams(void) //----------------------------------------------------------------------------- // Forward declarations -static void setZoneId(uint8_t endpoint, uint8_t zoneId); -static bool areZoneServerAttributesTokenized(uint8_t endpoint); +static void setZoneId(EndpointId endpoint, uint8_t zoneId); +static bool areZoneServerAttributesTokenized(EndpointId endpoint); static bool isValidEnrollmentMode(EmberAfIasZoneEnrollmentMode method); #if defined(EMBER_AF_PLUGIN_IAS_ZONE_SERVER_ENABLE_QUEUE) static uint16_t computeElapsedTimeQs(IasZoneStatusQueueEntry * entry); @@ -156,7 +158,7 @@ EmberNetworkStatus emberAfNetworkState(void) //----------------------------------------------------------------------------- // Functions -static EmberStatus sendToClient(uint8_t endpoint) +static EmberStatus sendToClient(EndpointId endpoint) { EmberStatus status; @@ -183,7 +185,7 @@ static EmberStatus sendToClient(uint8_t endpoint) return status; } -static void enrollWithClient(uint8_t endpoint) +static void enrollWithClient(EndpointId endpoint) { EmberStatus status; emberAfFillExternalBuffer((ZCL_CLUSTER_SPECIFIC_COMMAND | ZCL_FRAME_CONTROL_SERVER_TO_CLIENT), ZCL_IAS_ZONE_CLUSTER_ID, @@ -200,7 +202,7 @@ static void enrollWithClient(uint8_t endpoint) } } -EmberAfStatus emberAfIasZoneClusterServerPreAttributeChangedCallback(uint8_t endpoint, EmberAfAttributeId attributeId, +EmberAfStatus emberAfIasZoneClusterServerPreAttributeChangedCallback(EndpointId endpoint, AttributeId attributeId, EmberAfAttributeType attributeType, uint8_t size, uint8_t * value) { @@ -286,7 +288,7 @@ EmberAfStatus emberAfIasZoneClusterServerPreAttributeChangedCallback(uint8_t end return EMBER_ZCL_STATUS_SUCCESS; } -EmberAfStatus emberAfPluginIasZoneClusterSetEnrollmentMethod(uint8_t endpoint, EmberAfIasZoneEnrollmentMode method) +EmberAfStatus emberAfPluginIasZoneClusterSetEnrollmentMethod(EndpointId endpoint, EmberAfIasZoneEnrollmentMode method) { EmberAfStatus status; @@ -319,7 +321,7 @@ static bool isValidEnrollmentMode(EmberAfIasZoneEnrollmentMode method) (method == EMBER_ZCL_IAS_ZONE_ENROLLMENT_MODE_REQUEST)); } -bool emberAfIasZoneClusterAmIEnrolled(uint8_t endpoint) +bool emberAfIasZoneClusterAmIEnrolled(EndpointId endpoint) { EmberAfIasZoneState zoneState = EMBER_ZCL_IAS_ZONE_STATE_NOT_ENROLLED; // Clear this out completely. EmberAfStatus status; @@ -330,7 +332,7 @@ bool emberAfIasZoneClusterAmIEnrolled(uint8_t endpoint) return (status == EMBER_ZCL_STATUS_SUCCESS && zoneState == EMBER_ZCL_IAS_ZONE_STATE_ENROLLED); } -static void updateEnrollState(uint8_t endpoint, bool enrolled) +static void updateEnrollState(EndpointId endpoint, bool enrolled) { EmberAfIasZoneState zoneState = (enrolled ? EMBER_ZCL_IAS_ZONE_STATE_ENROLLED : EMBER_ZCL_IAS_ZONE_STATE_NOT_ENROLLED); @@ -341,7 +343,7 @@ static void updateEnrollState(uint8_t endpoint, bool enrolled) bool emberAfIasZoneClusterZoneEnrollResponseCallback(uint8_t enrollResponseCode, uint8_t zoneId) { - uint8_t endpoint; + EndpointId endpoint; uint8_t epZoneId; EmberAfStatus status; @@ -367,7 +369,7 @@ bool emberAfIasZoneClusterZoneEnrollResponseCallback(uint8_t enrollResponseCode, return true; } -static EmberStatus sendZoneUpdate(uint16_t zoneStatus, uint16_t timeSinceStatusOccurredQs, uint8_t endpoint) +static EmberStatus sendZoneUpdate(uint16_t zoneStatus, uint16_t timeSinceStatusOccurredQs, EndpointId endpoint) { EmberStatus status; @@ -392,7 +394,7 @@ static void addNewEntryToQueue(const IasZoneStatusQueueEntry * newEntry) } #endif -EmberStatus emberAfPluginIasZoneServerUpdateZoneStatus(uint8_t endpoint, uint16_t newStatus, uint16_t timeSinceStatusOccurredQs) +EmberStatus emberAfPluginIasZoneServerUpdateZoneStatus(EndpointId endpoint, uint16_t newStatus, uint16_t timeSinceStatusOccurredQs) { #if defined(EMBER_AF_PLUGIN_IAS_ZONE_SERVER_ENABLE_QUEUE) IasZoneStatusQueueEntry newBufferEntry; @@ -520,7 +522,7 @@ extern "C" void emberAfPluginIasZoneServerManageQueueEventHandler(void) #endif } -void emberAfIasZoneClusterServerInitCallback(uint8_t endpoint) +void emberAfIasZoneClusterServerInitCallback(EndpointId endpoint) { EmberAfIasZoneType zoneType; if (!areZoneServerAttributesTokenized(endpoint)) @@ -553,12 +555,12 @@ void emberAfIasZoneClusterServerInitCallback(uint8_t endpoint) 0); // time since status occurred } -void emberAfIasZoneClusterServerTickCallback(uint8_t endpoint) +void emberAfIasZoneClusterServerTickCallback(EndpointId endpoint) { enrollWithClient(endpoint); } -uint8_t emberAfPluginIasZoneServerGetZoneId(uint8_t endpoint) +uint8_t emberAfPluginIasZoneServerGetZoneId(EndpointId endpoint) { uint8_t zoneId = UNDEFINED_ZONE_ID; emberAfReadServerAttribute(endpoint, ZCL_IAS_ZONE_CLUSTER_ID, ZCL_ZONE_ID_ATTRIBUTE_ID, &zoneId, @@ -573,7 +575,7 @@ uint8_t emberAfPluginIasZoneServerGetZoneId(uint8_t endpoint) // tokenized. // //------------------------------------------------------------------------------ -static bool areZoneServerAttributesTokenized(uint8_t endpoint) +static bool areZoneServerAttributesTokenized(EndpointId endpoint) { EmberAfAttributeMetadata * metadata; @@ -608,13 +610,13 @@ static bool areZoneServerAttributesTokenized(uint8_t endpoint) return true; } -static void setZoneId(uint8_t endpoint, uint8_t zoneId) +static void setZoneId(EndpointId endpoint, uint8_t zoneId) { emberAfIasZoneClusterPrintln("IAS Zone Server Zone ID: 0x%X", zoneId); emberAfWriteServerAttribute(endpoint, ZCL_IAS_ZONE_CLUSTER_ID, ZCL_ZONE_ID_ATTRIBUTE_ID, &zoneId, ZCL_INT8U_ATTRIBUTE_TYPE); } -static void unenrollSecurityDevice(uint8_t endpoint) +static void unenrollSecurityDevice(EndpointId endpoint) { uint8_t ieeeAddress[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; uint16_t zoneType = EMBER_AF_PLUGIN_IAS_ZONE_SERVER_ZONE_TYPE; @@ -634,7 +636,7 @@ static void unenrollSecurityDevice(uint8_t endpoint) // If you leave the network, unenroll yourself. void emberAfPluginIasZoneServerStackStatusCallback(EmberStatus status) { - uint8_t endpoint; + EndpointId endpoint; uint8_t networkIndex; uint8_t i; diff --git a/src/app/clusters/ias-zone-server/ias-zone-server.h b/src/app/clusters/ias-zone-server/ias-zone-server.h index 9ebe59788a195a..a7a9b38bf4412d 100644 --- a/src/app/clusters/ias-zone-server/ias-zone-server.h +++ b/src/app/clusters/ias-zone-server/ias-zone-server.h @@ -85,7 +85,8 @@ typedef struct * @return EMBER_SUCCESS if the attribute update and notify succeeded, error * code otherwise. */ -EmberStatus emberAfPluginIasZoneServerUpdateZoneStatus(uint8_t endpoint, uint16_t newStatus, uint16_t timeSinceStatusOccurredQs); +EmberStatus emberAfPluginIasZoneServerUpdateZoneStatus(CHIPEndpointId endpoint, uint16_t newStatus, + uint16_t timeSinceStatusOccurredQs); /** @brief Gets the CIE assigned zone id of a given endpoint. * @@ -96,7 +97,7 @@ EmberStatus emberAfPluginIasZoneServerUpdateZoneStatus(uint8_t endpoint, uint16_ * * @return The zone ID assigned by the CIE at time of enrollment. */ -uint8_t emberAfPluginIasZoneServerGetZoneId(uint8_t endpoint); +uint8_t emberAfPluginIasZoneServerGetZoneId(CHIPEndpointId endpoint); /** @brief Determines the enrollment status of a given endpoint. * @@ -107,7 +108,7 @@ uint8_t emberAfPluginIasZoneServerGetZoneId(uint8_t endpoint); * * @return True if enrolled, false otherwise. */ -bool emberAfIasZoneClusterAmIEnrolled(uint8_t endpoint); +bool emberAfIasZoneClusterAmIEnrolled(CHIPEndpointId endpoint); /** @brief Set the enrollment status. * @@ -118,7 +119,7 @@ bool emberAfIasZoneClusterAmIEnrolled(uint8_t endpoint); * * @return An ::EmberAfStatus value indicating the status of the set action. */ -EmberAfStatus emberAfPluginIasZoneClusterSetEnrollmentMethod(uint8_t endpoint, EmberAfIasZoneEnrollmentMode method); +EmberAfStatus emberAfPluginIasZoneClusterSetEnrollmentMethod(CHIPEndpointId endpoint, EmberAfIasZoneEnrollmentMode method); /** @brief Configure the retry parameters of the status queue. * diff --git a/src/app/clusters/identify/identify.cpp b/src/app/clusters/identify/identify.cpp index ec1f2c7b808f3c..50c8e37d6f1dc6 100644 --- a/src/app/clusters/identify/identify.cpp +++ b/src/app/clusters/identify/identify.cpp @@ -50,6 +50,8 @@ #include "common.h" +using namespace chip; + typedef struct { bool identifying; @@ -58,24 +60,24 @@ typedef struct static EmAfIdentifyState stateTable[EMBER_AF_IDENTIFY_CLUSTER_SERVER_ENDPOINT_COUNT]; -static EmberAfStatus readIdentifyTime(uint8_t endpoint, uint16_t * identifyTime); -static EmberAfStatus writeIdentifyTime(uint8_t endpoint, uint16_t identifyTime); -static EmberStatus scheduleIdentifyTick(uint8_t endpoint); +static EmberAfStatus readIdentifyTime(EndpointId endpoint, uint16_t * identifyTime); +static EmberAfStatus writeIdentifyTime(EndpointId endpoint, uint16_t identifyTime); +static EmberStatus scheduleIdentifyTick(EndpointId endpoint); -static EmAfIdentifyState * getIdentifyState(uint8_t endpoint); +static EmAfIdentifyState * getIdentifyState(EndpointId endpoint); -static EmAfIdentifyState * getIdentifyState(uint8_t endpoint) +static EmAfIdentifyState * getIdentifyState(EndpointId endpoint) { uint8_t ep = emberAfFindClusterServerEndpointIndex(endpoint, ZCL_IDENTIFY_CLUSTER_ID); return (ep == 0xFF ? NULL : &stateTable[ep]); } -void emberAfIdentifyClusterServerInitCallback(uint8_t endpoint) +void emberAfIdentifyClusterServerInitCallback(EndpointId endpoint) { scheduleIdentifyTick(endpoint); } -void emberAfIdentifyClusterServerTickCallback(uint8_t endpoint) +void emberAfIdentifyClusterServerTickCallback(EndpointId endpoint) { uint16_t identifyTime; if (readIdentifyTime(endpoint, &identifyTime) == EMBER_ZCL_STATUS_SUCCESS) @@ -87,7 +89,7 @@ void emberAfIdentifyClusterServerTickCallback(uint8_t endpoint) } } -void emberAfIdentifyClusterServerAttributeChangedCallback(uint8_t endpoint, EmberAfAttributeId attributeId) +void emberAfIdentifyClusterServerAttributeChangedCallback(EndpointId endpoint, EmberAfAttributeId attributeId) { if (attributeId == ZCL_IDENTIFY_TIME_ATTRIBUTE_ID) { @@ -156,7 +158,7 @@ bool emberAfIdentifyClusterIdentifyQueryCallback(void) return true; } -EmberAfStatus readIdentifyTime(uint8_t endpoint, uint16_t * identifyTime) +EmberAfStatus readIdentifyTime(EndpointId endpoint, uint16_t * identifyTime) { EmberAfStatus status = emberAfReadAttribute(endpoint, ZCL_IDENTIFY_CLUSTER_ID, ZCL_IDENTIFY_TIME_ATTRIBUTE_ID, CLUSTER_MASK_SERVER, (uint8_t *) identifyTime, sizeof(*identifyTime), @@ -170,7 +172,7 @@ EmberAfStatus readIdentifyTime(uint8_t endpoint, uint16_t * identifyTime) return status; } -static EmberAfStatus writeIdentifyTime(uint8_t endpoint, uint16_t identifyTime) +static EmberAfStatus writeIdentifyTime(EndpointId endpoint, uint16_t identifyTime) { EmberAfStatus status = emberAfWriteAttribute(endpoint, ZCL_IDENTIFY_CLUSTER_ID, ZCL_IDENTIFY_TIME_ATTRIBUTE_ID, CLUSTER_MASK_SERVER, (uint8_t *) &identifyTime, ZCL_INT16U_ATTRIBUTE_TYPE); @@ -183,7 +185,7 @@ static EmberAfStatus writeIdentifyTime(uint8_t endpoint, uint16_t identifyTime) return status; } -static EmberStatus scheduleIdentifyTick(uint8_t endpoint) +static EmberStatus scheduleIdentifyTick(EndpointId endpoint) { EmberAfStatus status; EmAfIdentifyState * state = getIdentifyState(endpoint); diff --git a/src/app/clusters/level-control/level-control.cpp b/src/app/clusters/level-control/level-control.cpp index 0216cf311b0d54..22a9e8baafcca5 100644 --- a/src/app/clusters/level-control/level-control.cpp +++ b/src/app/clusters/level-control/level-control.cpp @@ -54,8 +54,10 @@ #include +using namespace chip; + #ifdef ZCL_USING_LEVEL_CONTROL_CLUSTER_START_UP_CURRENT_LEVEL_ATTRIBUTE -static bool areStartUpLevelControlServerAttributesTokenized(uint8_t endpoint); +static bool areStartUpLevelControlServerAttributesTokenized(EndpointId endpoint); #endif #if (EMBER_AF_PLUGIN_LEVEL_CONTROL_RATE == 0) @@ -92,7 +94,7 @@ typedef struct static EmberAfLevelControlState stateTable[EMBER_AF_LEVEL_CONTROL_CLUSTER_SERVER_ENDPOINT_COUNT]; -static EmberAfLevelControlState * getState(uint8_t endpoint); +static EmberAfLevelControlState * getState(EndpointId endpoint); static void moveToLevelHandler(uint8_t commandId, uint8_t level, uint16_t transitionTimeDs, uint8_t optionMask, uint8_t optionOverride, uint16_t storedLevel); @@ -101,35 +103,35 @@ static void stepHandler(uint8_t commandId, uint8_t stepMode, uint8_t stepSize, u uint8_t optionOverride); static void stopHandler(uint8_t commandId, uint8_t optionMask, uint8_t optionOverride); -static void setOnOffValue(uint8_t endpoint, bool onOff); -static void writeRemainingTime(uint8_t endpoint, uint16_t remainingTimeMs); -static bool shouldExecuteIfOff(uint8_t endpoint, uint8_t commandId, uint8_t optionMask, uint8_t optionOverride); +static void setOnOffValue(EndpointId endpoint, bool onOff); +static void writeRemainingTime(EndpointId endpoint, uint16_t remainingTimeMs); +static bool shouldExecuteIfOff(EndpointId endpoint, uint8_t commandId, uint8_t optionMask, uint8_t optionOverride); #if defined(ZCL_USING_LEVEL_CONTROL_CLUSTER_OPTIONS_ATTRIBUTE) && defined(EMBER_AF_PLUGIN_COLOR_CONTROL_SERVER_TEMP) -static void reallyUpdateCoupledColorTemp(uint8_t endpoint); +static void reallyUpdateCoupledColorTemp(EndpointId endpoint); #define updateCoupledColorTemp(endpoint) reallyUpdateCoupledColorTemp(endpoint) #else #define updateCoupledColorTemp(endpoint) #endif // LEVEL...OPTIONS_ATTRIBUTE && COLOR...SERVER_TEMP -static void schedule(uint8_t endpoint, uint32_t delayMs) +static void schedule(EndpointId endpoint, uint32_t delayMs) { emberAfScheduleServerTickExtended(endpoint, ZCL_LEVEL_CONTROL_CLUSTER_ID, delayMs, EMBER_AF_LONG_POLL, EMBER_AF_OK_TO_SLEEP); } -static void deactivate(uint8_t endpoint) +static void deactivate(EndpointId endpoint) { emberAfDeactivateServerTick(endpoint, ZCL_LEVEL_CONTROL_CLUSTER_ID); } -static EmberAfLevelControlState * getState(uint8_t endpoint) +static EmberAfLevelControlState * getState(EndpointId endpoint) { uint8_t ep = emberAfFindClusterServerEndpointIndex(endpoint, ZCL_LEVEL_CONTROL_CLUSTER_ID); return (ep == 0xFF ? NULL : &stateTable[ep]); } #if defined(ZCL_USING_LEVEL_CONTROL_CLUSTER_OPTIONS_ATTRIBUTE) && defined(EMBER_AF_PLUGIN_COLOR_CONTROL_SERVER_TEMP) -static void reallyUpdateCoupledColorTemp(uint8_t endpoint) +static void reallyUpdateCoupledColorTemp(EndpointId endpoint) { uint8_t options; EmberAfStatus status = @@ -147,7 +149,7 @@ static void reallyUpdateCoupledColorTemp(uint8_t endpoint) } #endif // LEVEL...OPTIONS_ATTRIBUTE && COLOR...SERVER_TEMP -extern "C" void emberAfLevelControlClusterServerTickCallback(uint8_t endpoint) +extern "C" void emberAfLevelControlClusterServerTickCallback(EndpointId endpoint) { EmberAfLevelControlState * state = getState(endpoint); EmberAfStatus status; @@ -265,7 +267,7 @@ extern "C" void emberAfLevelControlClusterServerTickCallback(uint8_t endpoint) } } -static void writeRemainingTime(uint8_t endpoint, uint16_t remainingTimeMs) +static void writeRemainingTime(EndpointId endpoint, uint16_t remainingTimeMs) { #ifdef ZCL_USING_LEVEL_CONTROL_CLUSTER_LEVEL_CONTROL_REMAINING_TIME_ATTRIBUTE // Convert milliseconds to tenths of a second, rounding any fractional value @@ -294,7 +296,7 @@ static void writeRemainingTime(uint8_t endpoint, uint16_t remainingTimeMs) #endif } -static void setOnOffValue(uint8_t endpoint, bool onOff) +static void setOnOffValue(EndpointId endpoint, bool onOff) { if (emberAfContainsServer(endpoint, ZCL_ON_OFF_CLUSTER_ID)) { @@ -303,7 +305,7 @@ static void setOnOffValue(uint8_t endpoint, bool onOff) } } -static bool shouldExecuteIfOff(uint8_t endpoint, uint8_t commandId, uint8_t optionMask, uint8_t optionOverride) +static bool shouldExecuteIfOff(EndpointId endpoint, uint8_t commandId, uint8_t optionMask, uint8_t optionOverride) { #ifdef ZCL_USING_LEVEL_CONTROL_CLUSTER_OPTIONS_ATTRIBUTE // From 3.10.2.2.8.1 of ZCL7 document 14-0127-20j-zcl-ch-3-general.docx: @@ -452,7 +454,7 @@ extern "C" bool emberAfLevelControlClusterStopWithOnOffCallback(void) static void moveToLevelHandler(uint8_t commandId, uint8_t level, uint16_t transitionTimeDs, uint8_t optionMask, uint8_t optionOverride, uint16_t storedLevel) { - uint8_t endpoint = emberAfCurrentEndpoint(); + EndpointId endpoint = emberAfCurrentEndpoint(); EmberAfLevelControlState * state = getState(endpoint); EmberAfStatus status; uint8_t currentLevel; @@ -585,7 +587,7 @@ static void moveToLevelHandler(uint8_t commandId, uint8_t level, uint16_t transi static void moveHandler(uint8_t commandId, uint8_t moveMode, uint8_t rate, uint8_t optionMask, uint8_t optionOverride) { - uint8_t endpoint = emberAfCurrentEndpoint(); + EndpointId endpoint = emberAfCurrentEndpoint(); EmberAfLevelControlState * state = getState(endpoint); EmberAfStatus status; uint8_t currentLevel; @@ -697,7 +699,7 @@ static void moveHandler(uint8_t commandId, uint8_t moveMode, uint8_t rate, uint8 static void stepHandler(uint8_t commandId, uint8_t stepMode, uint8_t stepSize, uint16_t transitionTimeDs, uint8_t optionMask, uint8_t optionOverride) { - uint8_t endpoint = emberAfCurrentEndpoint(); + EndpointId endpoint = emberAfCurrentEndpoint(); EmberAfLevelControlState * state = getState(endpoint); EmberAfStatus status; uint8_t currentLevel; @@ -816,7 +818,7 @@ static void stepHandler(uint8_t commandId, uint8_t stepMode, uint8_t stepSize, u static void stopHandler(uint8_t commandId, uint8_t optionMask, uint8_t optionOverride) { - uint8_t endpoint = emberAfCurrentEndpoint(); + EndpointId endpoint = emberAfCurrentEndpoint(); EmberAfLevelControlState * state = getState(endpoint); EmberAfStatus status; @@ -843,7 +845,7 @@ static void stopHandler(uint8_t commandId, uint8_t optionMask, uint8_t optionOve // Follows 07-5123-04 (ZigBee Cluster Library doc), section 3.10.2.1.1. // Quotes are from table 3.46. -void emberAfOnOffClusterLevelControlEffectCallback(uint8_t endpoint, bool newValue) +void emberAfOnOffClusterLevelControlEffectCallback(EndpointId endpoint, bool newValue) { uint8_t temporaryCurrentLevelCache; uint16_t currentOnOffTransitionTime; @@ -924,7 +926,7 @@ void emberAfOnOffClusterLevelControlEffectCallback(uint8_t endpoint, bool newVal } } -extern "C" void emberAfLevelControlClusterServerInitCallback(uint8_t endpoint) +extern "C" void emberAfLevelControlClusterServerInitCallback(EndpointId endpoint) { #ifdef ZCL_USING_LEVEL_CONTROL_CLUSTER_START_UP_CURRENT_LEVEL_ATTRIBUTE // StartUp behavior relies StartUpCurrentLevel attributes being tokenized. @@ -991,7 +993,7 @@ extern "C" void emberAfLevelControlClusterServerInitCallback(uint8_t endpoint) } #ifdef ZCL_USING_LEVEL_CONTROL_CLUSTER_START_UP_CURRENT_LEVEL_ATTRIBUTE -static bool areStartUpLevelControlServerAttributesTokenized(uint8_t endpoint) +static bool areStartUpLevelControlServerAttributesTokenized(EndpointId endpoint) { EmberAfAttributeMetadata * metadata; diff --git a/src/app/clusters/level-control/level-control.h b/src/app/clusters/level-control/level-control.h index 45bec394a1837d..25f500dc11f04b 100644 --- a/src/app/clusters/level-control/level-control.h +++ b/src/app/clusters/level-control/level-control.h @@ -48,6 +48,8 @@ #include +#include + #ifdef __cplusplus extern "C" { #endif // #ifdef __cplusplus @@ -58,7 +60,7 @@ extern "C" { * * @param endpoint Endpoint that is being initialized Ver.: always */ -void emberAfPluginLevelControlClusterServerPostInitCallback(uint8_t endpoint); +void emberAfPluginLevelControlClusterServerPostInitCallback(CHIPEndpointId endpoint); #ifdef __cplusplus } diff --git a/src/app/clusters/messaging-server/messaging-server.cpp b/src/app/clusters/messaging-server/messaging-server.cpp index 4cd4fe39058218..3d5bbfad5e741e 100644 --- a/src/app/clusters/messaging-server/messaging-server.cpp +++ b/src/app/clusters/messaging-server/messaging-server.cpp @@ -42,6 +42,8 @@ #include "messaging-server.h" #include "../../include/af.h" +using namespace chip; + // The internal message is stored in the same structure type that is defined // publicly. The internal state of the message is stored in the // messageStatusControl field @@ -57,7 +59,7 @@ static EmberAfPluginMessagingServerMessage msgTable[EMBER_AF_MESSAGING_CLUSTER_S #define messageIsActive(ep) (msgTable[ep].messageStatusControl & ACTIVE) #define messageIsNow(ep) (msgTable[ep].messageStatusControl & NOW) #define messageIsForever(ep) (msgTable[ep].durationInMinutes == ZCL_MESSAGING_CLUSTER_DURATION_UNTIL_CHANGED) -static bool messageIsCurrentOrScheduled(uint8_t endpoint) +static bool messageIsCurrentOrScheduled(EndpointId endpoint) { uint8_t ep = emberAfFindClusterServerEndpointIndex(endpoint, ZCL_MESSAGING_CLUSTER_ID); @@ -71,7 +73,7 @@ static bool messageIsCurrentOrScheduled(uint8_t endpoint) (emberAfGetCurrentTime() < msgTable[ep].startTime + (uint32_t) msgTable[ep].durationInMinutes * 60))); } -void emberAfMessagingClusterServerInitCallback(uint8_t endpoint) +void emberAfMessagingClusterServerInitCallback(EndpointId endpoint) { uint8_t ep = emberAfFindClusterServerEndpointIndex(endpoint, ZCL_MESSAGING_CLUSTER_ID); @@ -85,7 +87,7 @@ void emberAfMessagingClusterServerInitCallback(uint8_t endpoint) bool emberAfMessagingClusterGetLastMessageCallback(void) { - uint8_t endpoint = emberAfCurrentEndpoint(); + EndpointId endpoint = emberAfCurrentEndpoint(); EmberAfPluginMessagingServerMessage message; emberAfMessagingClusterPrintln("RX: GetLastMessage"); if (emberAfPluginMessagingServerGetMessage(endpoint, &message)) @@ -117,7 +119,7 @@ bool emberAfMessagingClusterMessageConfirmationCallback(uint32_t messageId, uint return true; } -bool emberAfPluginMessagingServerGetMessage(uint8_t endpoint, EmberAfPluginMessagingServerMessage * message) +bool emberAfPluginMessagingServerGetMessage(EndpointId endpoint, EmberAfPluginMessagingServerMessage * message) { uint8_t ep = emberAfFindClusterServerEndpointIndex(endpoint, ZCL_MESSAGING_CLUSTER_ID); @@ -147,7 +149,7 @@ bool emberAfPluginMessagingServerGetMessage(uint8_t endpoint, EmberAfPluginMessa return messageIsCurrentOrScheduled(endpoint); } -void emberAfPluginMessagingServerSetMessage(uint8_t endpoint, const EmberAfPluginMessagingServerMessage * message) +void emberAfPluginMessagingServerSetMessage(EndpointId endpoint, const EmberAfPluginMessagingServerMessage * message) { uint8_t ep = emberAfFindClusterServerEndpointIndex(endpoint, ZCL_MESSAGING_CLUSTER_ID); @@ -179,7 +181,7 @@ void emberAfPluginMessagingServerSetMessage(uint8_t endpoint, const EmberAfPlugi msgTable[ep].messageStatusControl |= (VALID | ACTIVE); } -void emAfPluginMessagingServerPrintInfo(uint8_t endpoint) +void emAfPluginMessagingServerPrintInfo(EndpointId endpoint) { uint8_t ep = emberAfFindClusterServerEndpointIndex(endpoint, ZCL_MESSAGING_CLUSTER_ID); diff --git a/src/app/clusters/messaging-server/messaging-server.h b/src/app/clusters/messaging-server/messaging-server.h index 742a1c45f1705f..276217f4a8cd03 100644 --- a/src/app/clusters/messaging-server/messaging-server.h +++ b/src/app/clusters/messaging-server/messaging-server.h @@ -93,7 +93,7 @@ typedef struct * @return True if the message is valid or false is the message does not exist * or is expired. */ -bool emberAfPluginMessagingServerGetMessage(uint8_t endpoint, EmberAfPluginMessagingServerMessage * message); +bool emberAfPluginMessagingServerGetMessage(CHIPEndpointId endpoint, EmberAfPluginMessagingServerMessage * message); /** * @brief Sets the message used by the Messaging server plugin. @@ -108,8 +108,8 @@ bool emberAfPluginMessagingServerGetMessage(uint8_t endpoint, EmberAfPluginMessa * @param message The ::EmberAfPluginMessagingServerMessage structure * describing the message. If NULL, the message is removed from the server. */ -void emberAfPluginMessagingServerSetMessage(uint8_t endpoint, const EmberAfPluginMessagingServerMessage * message); +void emberAfPluginMessagingServerSetMessage(CHIPEndpointId endpoint, const EmberAfPluginMessagingServerMessage * message); -void emAfPluginMessagingServerPrintInfo(uint8_t endpoint); +void emAfPluginMessagingServerPrintInfo(CHIPEndpointId endpoint); void emberAfPluginMessagingServerDisplayMessage(EmberNodeId nodeId, uint8_t srcEndpoint, uint8_t dstEndpoint); void emberAfPluginMessagingServerCancelMessage(EmberNodeId nodeId, uint8_t srcEndpoint, uint8_t dstEndpoint); diff --git a/src/app/clusters/on-off-server/on-off.cpp b/src/app/clusters/on-off-server/on-off.cpp index aae63bc7759fae..7f51a8960ea16c 100644 --- a/src/app/clusters/on-off-server/on-off.cpp +++ b/src/app/clusters/on-off-server/on-off.cpp @@ -57,11 +57,13 @@ #include "../zll-level-control-server/zll-level-control-server.h" #endif +using namespace chip; + #ifdef ZCL_USING_ON_OFF_CLUSTER_START_UP_ON_OFF_ATTRIBUTE -static bool areStartUpOnOffServerAttributesTokenized(uint8_t endpoint); +static bool areStartUpOnOffServerAttributesTokenized(EndpointId endpoint); #endif -EmberAfStatus emberAfOnOffClusterSetValueCallback(uint8_t endpoint, uint8_t command, bool initiatedByLevelChange) +EmberAfStatus emberAfOnOffClusterSetValueCallback(EndpointId endpoint, uint8_t command, bool initiatedByLevelChange) { EmberAfStatus status; bool currentValue, newValue; @@ -197,7 +199,7 @@ bool emberAfOnOffClusterToggleCallback(void) return true; } -void emberAfOnOffClusterServerInitCallback(uint8_t endpoint) +void emberAfOnOffClusterServerInitCallback(EndpointId endpoint) { #ifdef ZCL_USING_ON_OFF_CLUSTER_START_UP_ON_OFF_ATTRIBUTE // StartUp behavior relies on OnOff and StartUpOnOff attributes being tokenized. @@ -260,7 +262,7 @@ void emberAfOnOffClusterServerInitCallback(uint8_t endpoint) } #ifdef ZCL_USING_ON_OFF_CLUSTER_START_UP_ON_OFF_ATTRIBUTE -static bool areStartUpOnOffServerAttributesTokenized(uint8_t endpoint) +static bool areStartUpOnOffServerAttributesTokenized(EndpointId endpoint) { EmberAfAttributeMetadata * metadata; diff --git a/src/app/clusters/scenes/scenes.cpp b/src/app/clusters/scenes/scenes.cpp index 551702616400db..0c28915f5dce4a 100644 --- a/src/app/clusters/scenes/scenes.cpp +++ b/src/app/clusters/scenes/scenes.cpp @@ -53,7 +53,7 @@ uint8_t emberAfPluginScenesServerEntriesInUse = 0; EmberAfSceneTableEntry emberAfPluginScenesServerSceneTable[EMBER_AF_PLUGIN_SCENES_TABLE_SIZE]; #endif -static bool readServerAttribute(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attributeId, const char * name, +static bool readServerAttribute(EndpointId endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attributeId, const char * name, uint8_t * data, uint8_t size) { bool success = false; @@ -72,7 +72,7 @@ static bool readServerAttribute(uint8_t endpoint, EmberAfClusterId clusterId, Em return success; } -static EmberAfStatus writeServerAttribute(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attributeId, +static EmberAfStatus writeServerAttribute(EndpointId endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attributeId, const char * name, uint8_t * data, EmberAfAttributeType type) { EmberAfStatus status = emberAfWriteServerAttribute(endpoint, clusterId, attributeId, data, type); @@ -83,7 +83,7 @@ static EmberAfStatus writeServerAttribute(uint8_t endpoint, EmberAfClusterId clu return status; } -void emberAfScenesClusterServerInitCallback(uint8_t endpoint) +void emberAfScenesClusterServerInitCallback(EndpointId endpoint) { #ifdef EMBER_AF_PLUGIN_SCENES_NAME_SUPPORT { @@ -109,13 +109,13 @@ void emberAfScenesClusterServerInitCallback(uint8_t endpoint) emberAfScenesSetSceneCountAttribute(endpoint, emberAfPluginScenesServerNumSceneEntriesInUse()); } -EmberAfStatus emberAfScenesSetSceneCountAttribute(uint8_t endpoint, uint8_t newCount) +EmberAfStatus emberAfScenesSetSceneCountAttribute(EndpointId endpoint, uint8_t newCount) { return writeServerAttribute(endpoint, ZCL_SCENES_CLUSTER_ID, ZCL_SCENE_COUNT_ATTRIBUTE_ID, "scene count", (uint8_t *) &newCount, ZCL_INT8U_ATTRIBUTE_TYPE); } -EmberAfStatus emberAfScenesMakeValid(uint8_t endpoint, uint8_t sceneId, GroupId groupId) +EmberAfStatus emberAfScenesMakeValid(EndpointId endpoint, uint8_t sceneId, GroupId groupId) { EmberAfStatus status; bool valid = true; @@ -141,7 +141,7 @@ EmberAfStatus emberAfScenesMakeValid(uint8_t endpoint, uint8_t sceneId, GroupId return status; } -EmberAfStatus emberAfScenesClusterMakeInvalidCallback(uint8_t endpoint) +EmberAfStatus emberAfScenesClusterMakeInvalidCallback(EndpointId endpoint) { bool valid = false; return writeServerAttribute(endpoint, ZCL_SCENES_CLUSTER_ID, ZCL_SCENE_VALID_ATTRIBUTE_ID, "scene valid", (uint8_t *) &valid, @@ -646,7 +646,7 @@ EmberAfStatus emberAfScenesClusterRecallSavedSceneCallback(EndpointId endpoint, return EMBER_ZCL_STATUS_NOT_FOUND; } -void emberAfScenesClusterClearSceneTableCallback(uint8_t endpoint) +void emberAfScenesClusterClearSceneTableCallback(EndpointId endpoint) { uint8_t i, networkIndex = 0 /* emberGetCurrentNetwork() */; for (i = 0; i < EMBER_AF_PLUGIN_SCENES_TABLE_SIZE; i++) @@ -689,7 +689,7 @@ bool emberAfPluginScenesServerParseAddScene(const EmberAfClusterCommand * cmd, G cmd->bufLen - (cmd->payloadStartIndex + sizeof(groupId) + sizeof(sceneId) + sizeof(transitionTime) + emberAfStringLength(sceneName) + 1)); uint16_t extensionFieldSetsIndex = 0; - uint8_t endpoint = cmd->apsFrame->destinationEndpoint; + EndpointId endpoint = cmd->apsFrame->destinationEndpoint; uint8_t i, index = EMBER_AF_SCENE_TABLE_NULL_INDEX; emberAfScenesClusterPrint("RX: %pAddScene 0x%2x, 0x%x, 0x%2x, \"", (enhanced ? "Enhanced" : ""), groupId, sceneId, @@ -1008,8 +1008,8 @@ bool emberAfPluginScenesServerParseViewScene(const EmberAfClusterCommand * cmd, EmberAfSceneTableEntry entry = {}; EmberAfStatus status = EMBER_ZCL_STATUS_NOT_FOUND; EmberStatus sendStatus; - bool enhanced = (cmd->commandId == ZCL_ENHANCED_VIEW_SCENE_COMMAND_ID); - uint8_t endpoint = cmd->apsFrame->destinationEndpoint; + bool enhanced = (cmd->commandId == ZCL_ENHANCED_VIEW_SCENE_COMMAND_ID); + EndpointId endpoint = cmd->apsFrame->destinationEndpoint; emberAfScenesClusterPrintln("RX: %pViewScene 0x%2x, 0x%x", (enhanced ? "Enhanced" : ""), groupId, sceneId); diff --git a/src/app/clusters/scenes/scenes.h b/src/app/clusters/scenes/scenes.h index 8ce61322ab49f5..1a8ecba84f22f1 100644 --- a/src/app/clusters/scenes/scenes.h +++ b/src/app/clusters/scenes/scenes.h @@ -43,8 +43,8 @@ #include #include -EmberAfStatus emberAfScenesSetSceneCountAttribute(uint8_t endpoint, uint8_t newCount); -EmberAfStatus emberAfScenesMakeValid(uint8_t endpoint, uint8_t sceneId, CHIPGroupId groupId); +EmberAfStatus emberAfScenesSetSceneCountAttribute(CHIPEndpointId endpoint, uint8_t newCount); +EmberAfStatus emberAfScenesMakeValid(CHIPEndpointId endpoint, uint8_t sceneId, CHIPGroupId groupId); // DEPRECATED. #define emberAfScenesMakeInvalid emberAfScenesClusterMakeInvalidCallback diff --git a/src/app/encoder.cpp b/src/app/encoder.cpp index ed77188090b59b..eafe6a6bf1e4ae 100644 --- a/src/app/encoder.cpp +++ b/src/app/encoder.cpp @@ -24,6 +24,8 @@ #include #include +#include + using namespace chip; #define CHECK_FRAME_LENGTH(value, name) \ @@ -156,8 +158,8 @@ extern "C" { #define SCENES_CLUSTER_ID 0x0005 #define TEMPERATURE_MEASUREMENT_CLUSTER_ID 0x0402 -static uint16_t doEncodeApsFrame(BufBound & buf, uint16_t profileID, uint16_t clusterId, uint8_t sourceEndpoint, - uint8_t destinationEndpoint, EmberApsOption options, GroupId groupId, uint8_t sequence, +static uint16_t doEncodeApsFrame(BufBound & buf, uint16_t profileID, ClusterId clusterId, EndpointId sourceEndpoint, + EndpointId destinationEndpoint, EmberApsOption options, GroupId groupId, uint8_t sequence, uint8_t radius, bool isMeasuring) { @@ -200,7 +202,8 @@ uint16_t encodeApsFrame(uint8_t * buffer, uint16_t buf_length, EmberApsFrame * a apsFrame->options, apsFrame->groupId, apsFrame->sequence, apsFrame->radius, !buffer); } -uint16_t _encodeCommand(BufBound & buf, uint8_t destination_endpoint, uint16_t cluster_id, uint8_t command, uint8_t frame_control) +uint16_t _encodeCommand(BufBound & buf, EndpointId destination_endpoint, ClusterId cluster_id, uint8_t command, + uint8_t frame_control) { CHECK_FRAME_LENGTH(buf.Size(), "Buffer is empty"); @@ -219,7 +222,7 @@ uint16_t _encodeCommand(BufBound & buf, uint8_t destination_endpoint, uint16_t c return buf.Fit() && CanCastTo(buf.Written()) ? static_cast(buf.Written()) : 0; } -uint16_t _encodeClusterSpecificCommand(BufBound & buf, uint8_t destination_endpoint, uint16_t cluster_id, uint8_t command) +uint16_t _encodeClusterSpecificCommand(BufBound & buf, EndpointId destination_endpoint, ClusterId cluster_id, uint8_t command) { // This is a cluster-specific command so low two bits are 0b01. The command // is standard, so does not need a manufacturer code, and we're sending @@ -229,7 +232,7 @@ uint16_t _encodeClusterSpecificCommand(BufBound & buf, uint8_t destination_endpo return _encodeCommand(buf, destination_endpoint, cluster_id, command, frame_control); } -uint16_t _encodeGlobalCommand(BufBound & buf, uint8_t destination_endpoint, uint16_t cluster_id, uint8_t command) +uint16_t _encodeGlobalCommand(BufBound & buf, EndpointId destination_endpoint, ClusterId cluster_id, uint8_t command) { // This is a global command, so the low bits are 0b00. The command is // standard, so does not need a manufacturer code, and we're sending client diff --git a/src/app/reporting/reporting.cpp b/src/app/reporting/reporting.cpp index 4b6731c89918e2..c948224fde3b33 100644 --- a/src/app/reporting/reporting.cpp +++ b/src/app/reporting/reporting.cpp @@ -47,6 +47,8 @@ #include #include +using namespace chip; + #ifdef ATTRIBUTE_LARGEST #define READ_DATA_SIZE ATTRIBUTE_LARGEST #else @@ -55,7 +57,7 @@ #define NULL_INDEX 0xFF -static void conditionallySendReport(uint8_t endpoint, EmberAfClusterId clusterId); +static void conditionallySendReport(EndpointId endpoint, EmberAfClusterId clusterId); static void scheduleTick(void); static void removeConfiguration(uint8_t index); static void removeConfigurationAndScheduleTick(uint8_t index); @@ -342,7 +344,7 @@ extern "C" void emberAfPluginReportingTickEventHandler(void) scheduleTick(); } -static void conditionallySendReport(uint8_t endpoint, EmberAfClusterId clusterId) +static void conditionallySendReport(EndpointId endpoint, EmberAfClusterId clusterId) { EmberStatus status; if (emberAfIsDeviceEnabled(endpoint) || clusterId == ZCL_IDENTIFY_CLUSTER_ID) @@ -667,9 +669,9 @@ EmberStatus emAfPluginReportingRemoveEntry(uint8_t index) return status; } -extern "C" void emberAfReportingAttributeChangeCallback(uint8_t endpoint, EmberAfClusterId clusterId, - EmberAfAttributeId attributeId, uint8_t mask, uint16_t manufacturerCode, - EmberAfAttributeType type, uint8_t * data) +extern "C" void emberAfReportingAttributeChangeCallback(EndpointId endpoint, ClusterId clusterId, AttributeId attributeId, + uint8_t mask, uint16_t manufacturerCode, EmberAfAttributeType type, + uint8_t * data) { uint8_t i; for (i = 0; i < REPORT_TABLE_SIZE; i++) diff --git a/src/app/util/af-event.cpp b/src/app/util/af-event.cpp index e414c114d61739..252b1c13269871 100644 --- a/src/app/util/af-event.cpp +++ b/src/app/util/af-event.cpp @@ -52,6 +52,8 @@ #include "gen/af-gen-event.h" +using namespace chip; + struct EmberEventData { /** The control structure for the event. */ @@ -126,7 +128,7 @@ const char * emberAfGetEventString(uint8_t index) return (index == 0XFF ? emAfStackEventString : emAfEventStrings[index]); } -static EmberAfEventContext * findEventContext(uint8_t endpoint, EmberAfClusterId clusterId, bool isClient) +static EmberAfEventContext * findEventContext(EndpointId endpoint, EmberAfClusterId clusterId, bool isClient) { #if defined(EMBER_AF_GENERATED_EVENT_CONTEXT) uint16_t i; @@ -204,7 +206,7 @@ EmberStatus emberAfEventControlSetDelayMinutes(EmberEventControl * control, uint } } -EmberStatus emberAfScheduleTickExtended(uint8_t endpoint, EmberAfClusterId clusterId, bool isClient, uint32_t delayMs, +EmberStatus emberAfScheduleTickExtended(EndpointId endpoint, EmberAfClusterId clusterId, bool isClient, uint32_t delayMs, EmberAfEventPollControl pollControl, EmberAfEventSleepControl sleepControl) { EmberAfEventContext * context = findEventContext(endpoint, clusterId, isClient); @@ -223,7 +225,7 @@ EmberStatus emberAfScheduleTickExtended(uint8_t endpoint, EmberAfClusterId clust return EMBER_BAD_ARGUMENT; } -EmberStatus emberAfScheduleClusterTick(uint8_t endpoint, EmberAfClusterId clusterId, bool isClient, uint32_t delayMs, +EmberStatus emberAfScheduleClusterTick(EndpointId endpoint, EmberAfClusterId clusterId, bool isClient, uint32_t delayMs, EmberAfEventSleepControl sleepControl) { return emberAfScheduleTickExtended(endpoint, clusterId, isClient, delayMs, @@ -231,29 +233,29 @@ EmberStatus emberAfScheduleClusterTick(uint8_t endpoint, EmberAfClusterId cluste (sleepControl == EMBER_AF_STAY_AWAKE ? EMBER_AF_STAY_AWAKE : EMBER_AF_OK_TO_SLEEP)); } -EmberStatus emberAfScheduleClientTickExtended(uint8_t endpoint, EmberAfClusterId clusterId, uint32_t delayMs, +EmberStatus emberAfScheduleClientTickExtended(EndpointId endpoint, EmberAfClusterId clusterId, uint32_t delayMs, EmberAfEventPollControl pollControl, EmberAfEventSleepControl sleepControl) { return emberAfScheduleTickExtended(endpoint, clusterId, EMBER_AF_CLIENT_CLUSTER_TICK, delayMs, pollControl, sleepControl); } -EmberStatus emberAfScheduleClientTick(uint8_t endpoint, EmberAfClusterId clusterId, uint32_t delayMs) +EmberStatus emberAfScheduleClientTick(EndpointId endpoint, EmberAfClusterId clusterId, uint32_t delayMs) { return emberAfScheduleClientTickExtended(endpoint, clusterId, delayMs, EMBER_AF_LONG_POLL, EMBER_AF_OK_TO_SLEEP); } -EmberStatus emberAfScheduleServerTickExtended(uint8_t endpoint, EmberAfClusterId clusterId, uint32_t delayMs, +EmberStatus emberAfScheduleServerTickExtended(EndpointId endpoint, EmberAfClusterId clusterId, uint32_t delayMs, EmberAfEventPollControl pollControl, EmberAfEventSleepControl sleepControl) { return emberAfScheduleTickExtended(endpoint, clusterId, EMBER_AF_SERVER_CLUSTER_TICK, delayMs, pollControl, sleepControl); } -EmberStatus emberAfScheduleServerTick(uint8_t endpoint, EmberAfClusterId clusterId, uint32_t delayMs) +EmberStatus emberAfScheduleServerTick(EndpointId endpoint, EmberAfClusterId clusterId, uint32_t delayMs) { return emberAfScheduleServerTickExtended(endpoint, clusterId, delayMs, EMBER_AF_LONG_POLL, EMBER_AF_OK_TO_SLEEP); } -EmberStatus emberAfDeactivateClusterTick(uint8_t endpoint, EmberAfClusterId clusterId, bool isClient) +EmberStatus emberAfDeactivateClusterTick(EndpointId endpoint, EmberAfClusterId clusterId, bool isClient) { EmberAfEventContext * context = findEventContext(endpoint, clusterId, isClient); if (context != NULL) @@ -264,12 +266,12 @@ EmberStatus emberAfDeactivateClusterTick(uint8_t endpoint, EmberAfClusterId clus return EMBER_BAD_ARGUMENT; } -EmberStatus emberAfDeactivateClientTick(uint8_t endpoint, EmberAfClusterId clusterId) +EmberStatus emberAfDeactivateClientTick(EndpointId endpoint, EmberAfClusterId clusterId) { return emberAfDeactivateClusterTick(endpoint, clusterId, EMBER_AF_CLIENT_CLUSTER_TICK); } -EmberStatus emberAfDeactivateServerTick(uint8_t endpoint, EmberAfClusterId clusterId) +EmberStatus emberAfDeactivateServerTick(EndpointId endpoint, EmberAfClusterId clusterId) { return emberAfDeactivateClusterTick(endpoint, clusterId, EMBER_AF_SERVER_CLUSTER_TICK); } diff --git a/src/app/util/af-main.h b/src/app/util/af-main.h index 7c0cd8cd8b17b6..199f38db3ee91f 100644 --- a/src/app/util/af-main.h +++ b/src/app/util/af-main.h @@ -152,7 +152,7 @@ void emberAfFormatMfgString(uint8_t * mfgString); extern bool emberAfPrintReceivedMessages; void emAfParseAndPrintVersion(EmberVersion versionStruct); -void emAfPrintEzspEndpointFlags(uint8_t endpoint); +void emAfPrintEzspEndpointFlags(CHIPEndpointId endpoint); // Old names #define emberAfMoveInProgress() emberAfMoveInProgressCallback() diff --git a/src/app/util/af-types.h b/src/app/util/af-types.h index 2fa736fda90a89..3a396dd4e9ec94 100644 --- a/src/app/util/af-types.h +++ b/src/app/util/af-types.h @@ -248,7 +248,7 @@ typedef struct /** * Endpoint that the attribute is located on */ - uint8_t endpoint; + CHIPEndpointId endpoint; /** * Cluster that the attribute is located on. If the cluster @@ -546,7 +546,7 @@ typedef struct /** * Actual zigbee endpoint number. */ - uint8_t endpoint; + CHIPEndpointId endpoint; /** * Profile ID of the device on this endpoint. */ @@ -600,14 +600,14 @@ typedef struct uint32_t eventId; #ifdef EMBER_AF_PLUGIN_DRLC_SERVER EmberEUI64 source; - uint8_t sourceEndpoint; + CHIPEndpointId sourceEndpoint; #endif // EMBER_AF_PLUGIN_DRLC_SERVER #ifdef EMBER_AF_PLUGIN_DRLC EmberAfPluginEsiManagementBitmask esiBitmask; #endif // EMBER_AF_PLUGIN_DRLC - uint8_t destinationEndpoint; + CHIPEndpointId destinationEndpoint; uint16_t deviceClass; uint8_t utilityEnrollmentGroup; /** @@ -702,7 +702,7 @@ typedef struct typedef struct { uint8_t count; - const uint8_t * list; + const CHIPEndpointId * list; } EmberAfEndpointList; /** @@ -712,12 +712,12 @@ typedef struct typedef struct { uint8_t inClusterCount; - const uint16_t * inClusterList; + const CHIPClusterId * inClusterList; uint8_t outClusterCount; - const uint16_t * outClusterList; + const CHIPClusterId * outClusterList; EmberAfProfileId profileId; uint16_t deviceId; - uint8_t endpoint; + CHIPEndpointId endpoint; } EmberAfClusterList; /** @@ -839,7 +839,7 @@ typedef struct /** * The endpoint of the associated cluster event. */ - uint8_t endpoint; + CHIPEndpointId endpoint; /** * The cluster id of the associated cluster event. */ @@ -873,7 +873,7 @@ typedef void (*EmberAfNetworkEventHandler)(void); /** * @brief Type for referring to the handler for endpoint events. */ -typedef void (*EmberAfEndpointEventHandler)(uint8_t endpoint); +typedef void (*EmberAfEndpointEventHandler)(CHIPEndpointId endpoint); #ifdef EMBER_AF_PLUGIN_GROUPS_SERVER /** @@ -999,7 +999,7 @@ typedef struct bool valid; bool active; EmberAfPluginEsiManagementBitmask esiBitmask; - uint8_t clientEndpoint; + CHIPEndpointId clientEndpoint; uint32_t messageId; uint8_t messageControl; uint32_t startTime; @@ -1013,7 +1013,7 @@ typedef struct { bool valid; bool active; - uint8_t clientEndpoint; + CHIPEndpointId clientEndpoint; uint32_t providerId; uint8_t rateLabel[ZCL_PRICE_CLUSTER_MAXIMUM_RATE_LABEL_LENGTH + 1]; uint32_t issuerEventId; @@ -1074,7 +1074,7 @@ typedef struct * report is received. If ::EMBER_AF_PLUGIN_REPORTING_UNUSED_ENDPOINT_ID, * the entry is unused. */ - uint8_t endpoint; + CHIPEndpointId endpoint; /** The cluster where the attribute is located. */ EmberAfClusterId clusterId; /** The id of the attribute being reported or received. */ @@ -1108,7 +1108,7 @@ typedef struct /** The node id of the source of the received reports. */ ChipNodeId source; /** The remote endpoint from which the attribute is reported. */ - uint8_t endpoint; + CHIPEndpointId endpoint; /** The maximum expected time between reports, measured in seconds. */ uint16_t timeout; } received; @@ -1172,7 +1172,7 @@ typedef struct typedef struct { EmberNodeId networkAddress; - uint8_t endpointId; + CHIPEndpointId endpointId; uint16_t profileId; uint16_t deviceId; uint8_t version; @@ -1231,7 +1231,7 @@ typedef struct // treat this field with appropriate units (ms or sec) uint16_t minBlockRequestPeriod; // optionally present in messages uint8_t maxDataSize; - uint8_t clientEndpoint; + CHIPEndpointId clientEndpoint; EmberAfImageBlockRequestOptions bitmask; } EmberAfImageBlockRequestCallbackStruct; @@ -1416,7 +1416,7 @@ typedef enum * the cluster. The rate of tick is determined by the metadata of the * cluster. */ -typedef void (*EmberAfTickFunction)(uint8_t endpoint); +typedef void (*EmberAfTickFunction)(CHIPEndpointId endpoint); /** * @brief Type for referring to the init callback for cluster. @@ -1424,14 +1424,14 @@ typedef void (*EmberAfTickFunction)(uint8_t endpoint); * Init function is called when the application starts up, once for * each cluster/endpoint combination. */ -typedef void (*EmberAfInitFunction)(uint8_t endpoint); +typedef void (*EmberAfInitFunction)(CHIPEndpointId endpoint); /** * @brief Type for referring to the attribute changed callback function. * * This function is called just after an attribute changes. */ -typedef void (*EmberAfClusterAttributeChangedCallback)(uint8_t endpoint, EmberAfAttributeId attributeId); +typedef void (*EmberAfClusterAttributeChangedCallback)(CHIPEndpointId endpoint, EmberAfAttributeId attributeId); /** * @brief Type for referring to the manufacturer specific @@ -1439,7 +1439,7 @@ typedef void (*EmberAfClusterAttributeChangedCallback)(uint8_t endpoint, EmberAf * * This function is called just after a manufacturer specific attribute changes. */ -typedef void (*EmberAfManufacturerSpecificClusterAttributeChangedCallback)(uint8_t endpoint, EmberAfAttributeId attributeId, +typedef void (*EmberAfManufacturerSpecificClusterAttributeChangedCallback)(CHIPEndpointId endpoint, EmberAfAttributeId attributeId, uint16_t manufacturerCode); /** @@ -1447,7 +1447,7 @@ typedef void (*EmberAfManufacturerSpecificClusterAttributeChangedCallback)(uint8 * * This function is called before an attribute changes. */ -typedef EmberAfStatus (*EmberAfClusterPreAttributeChangedCallback)(uint8_t endpoint, EmberAfAttributeId attributeId, +typedef EmberAfStatus (*EmberAfClusterPreAttributeChangedCallback)(CHIPEndpointId endpoint, EmberAfAttributeId attributeId, EmberAfAttributeType attributeType, uint8_t size, uint8_t * value); @@ -1457,7 +1457,7 @@ typedef EmberAfStatus (*EmberAfClusterPreAttributeChangedCallback)(uint8_t endpo * This function is called when default response is received, before * the global callback. Global callback is called immediately afterwards. */ -typedef void (*EmberAfDefaultResponseFunction)(uint8_t endpoint, uint8_t commandId, EmberAfStatus status); +typedef void (*EmberAfDefaultResponseFunction)(CHIPEndpointId endpoint, uint8_t commandId, EmberAfStatus status); /** * @brief Type for referring to the message sent callback function. @@ -1857,7 +1857,7 @@ typedef struct EmberAfClusterId clusterId; EmberAfProfileId profileId; uint16_t deviceId; - uint8_t endpoint; + CHIPEndpointId endpoint; EmberAfRemoteClusterType type; } EmberAfRemoteClusterStruct; @@ -1867,9 +1867,9 @@ typedef struct typedef struct { EmberEUI64 targetEUI64; - uint8_t sourceEndpoint; - uint8_t destEndpoint; - uint16_t clusterId; + CHIPEndpointId sourceEndpoint; + CHIPEndpointId destEndpoint; + CHIPClusterId clusterId; EmberEUI64 destEUI64; EmberEUI64 sourceEUI64; } EmberAfRemoteBindingStruct; @@ -1892,7 +1892,7 @@ typedef struct EmberAfClusterInfo clusters[EMBER_AF_MAX_CLUSTERS_PER_ENDPOINT]; EmberAfProfileId profileId; uint16_t deviceId; - uint8_t endpoint; + CHIPEndpointId endpoint; uint8_t clusterCount; } EmberAfEndpointInfoStruct; diff --git a/src/app/util/af.h b/src/app/util/af.h index 961fe9f416d6ab..201afbf3d31a54 100644 --- a/src/app/util/af.h +++ b/src/app/util/af.h @@ -129,12 +129,12 @@ extern "C" { * * @return Returns pointer to the attribute metadata location. */ -EmberAfAttributeMetadata * emberAfLocateAttributeMetadata(uint8_t endpoint, EmberAfClusterId clusterId, +EmberAfAttributeMetadata * emberAfLocateAttributeMetadata(CHIPEndpointId endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attributeId, uint8_t mask, uint16_t manufacturerCode); #ifdef DOXYGEN_SHOULD_SKIP_THIS /** @brief Returns true if the attribute exists. */ -bool emberAfContainsAttribute(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attributeId, uint8_t mask, +bool emberAfContainsAttribute(CHIPEndpointId endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attributeId, uint8_t mask, uint16_t manufacturerCode); #else #define emberAfContainsAttribute(endpoint, clusterId, attributeId, mask, manufacturerCode) \ @@ -149,7 +149,7 @@ bool emberAfContainsAttribute(uint8_t endpoint, EmberAfClusterId clusterId, Embe * For standard libraries (when ClusterId < FC00), * the manufacturerCode is ignored. */ -bool emberAfContainsClusterWithMfgCode(uint8_t endpoint, EmberAfClusterId clusterId, uint16_t manufacturerCode); +bool emberAfContainsClusterWithMfgCode(CHIPEndpointId endpoint, EmberAfClusterId clusterId, uint16_t manufacturerCode); /** * @brief Returns true if endpoint contains the ZCL cluster with specified id. @@ -162,7 +162,7 @@ bool emberAfContainsClusterWithMfgCode(uint8_t endpoint, EmberAfClusterId cluste * then this will return the first cluster that it finds in the Cluster table. * and will not return any other clusters that share that id. */ -bool emberAfContainsCluster(uint8_t endpoint, EmberAfClusterId clusterId); +bool emberAfContainsCluster(CHIPEndpointId endpoint, EmberAfClusterId clusterId); /** * @brief Returns true if endpoint has cluster server, checking for mfg code. @@ -171,7 +171,7 @@ bool emberAfContainsCluster(uint8_t endpoint, EmberAfClusterId clusterId); * the endpoint contains server of a given cluster. * For standard librarys (when ClusterId < FC00), the manufacturerCode is ignored. */ -bool emberAfContainsServerWithMfgCode(uint8_t endpoint, EmberAfClusterId clusterId, uint16_t manufacturerCode); +bool emberAfContainsServerWithMfgCode(CHIPEndpointId endpoint, EmberAfClusterId clusterId, uint16_t manufacturerCode); /** * @brief Returns true if endpoint contains the ZCL server with specified id. @@ -184,7 +184,7 @@ bool emberAfContainsServerWithMfgCode(uint8_t endpoint, EmberAfClusterId cluster * then this will return the first cluster that it finds in the Cluster table. * and will not return any other clusters that share that id. */ -bool emberAfContainsServer(uint8_t endpoint, EmberAfClusterId clusterId); +bool emberAfContainsServer(CHIPEndpointId endpoint, EmberAfClusterId clusterId); /** * @brief Returns true if endpoint contains cluster client. @@ -194,7 +194,7 @@ bool emberAfContainsServer(uint8_t endpoint, EmberAfClusterId clusterId); * For standard library clusters (when ClusterId < FC00), * the manufacturerCode is ignored. */ -bool emberAfContainsClientWithMfgCode(uint8_t endpoint, EmberAfClusterId clusterId, uint16_t manufacturerCode); +bool emberAfContainsClientWithMfgCode(CHIPEndpointId endpoint, EmberAfClusterId clusterId, uint16_t manufacturerCode); /** * @brief Returns true if endpoint contains the ZCL client with specified id. @@ -207,7 +207,7 @@ bool emberAfContainsClientWithMfgCode(uint8_t endpoint, EmberAfClusterId cluster * then this will return the first cluster that it finds in the Cluster table. * and will not return any other clusters that share that id. */ -bool emberAfContainsClient(uint8_t endpoint, EmberAfClusterId clusterId); +bool emberAfContainsClient(CHIPEndpointId endpoint, EmberAfClusterId clusterId); /** * @brief write an attribute, performing all the checks. @@ -228,7 +228,7 @@ bool emberAfContainsClient(uint8_t endpoint, EmberAfClusterId clusterId); * emberAfWriteManufacturerSpecificClientAttribute, * emberAfWriteManufacturerSpecificServerAttribute */ -EmberAfStatus emberAfWriteAttribute(uint8_t endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint8_t mask, +EmberAfStatus emberAfWriteAttribute(CHIPEndpointId endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint8_t mask, uint8_t * dataPtr, EmberAfAttributeType dataType); /** @@ -243,7 +243,7 @@ EmberAfStatus emberAfWriteAttribute(uint8_t endpoint, EmberAfClusterId cluster, * emberAfWriteManufacturerSpecificClientAttribute, * emberAfWriteManufacturerSpecificServerAttribute */ -EmberAfStatus emberAfWriteServerAttribute(uint8_t endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, +EmberAfStatus emberAfWriteServerAttribute(CHIPEndpointId endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint8_t * dataPtr, EmberAfAttributeType dataType); /** @@ -258,7 +258,7 @@ EmberAfStatus emberAfWriteServerAttribute(uint8_t endpoint, EmberAfClusterId clu * emberAfWriteManufacturerSpecificClientAttribute, * emberAfWriteManufacturerSpecificServerAttribute */ -EmberAfStatus emberAfWriteClientAttribute(uint8_t endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, +EmberAfStatus emberAfWriteClientAttribute(CHIPEndpointId endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint8_t * dataPtr, EmberAfAttributeType dataType); /** @@ -273,7 +273,7 @@ EmberAfStatus emberAfWriteClientAttribute(uint8_t endpoint, EmberAfClusterId clu * @see emberAfWriteClientAttribute, emberAfWriteServerAttribute, * emberAfWriteManufacturerSpecificClientAttribute */ -EmberAfStatus emberAfWriteManufacturerSpecificServerAttribute(uint8_t endpoint, EmberAfClusterId cluster, +EmberAfStatus emberAfWriteManufacturerSpecificServerAttribute(CHIPEndpointId endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint16_t manufacturerCode, uint8_t * dataPtr, EmberAfAttributeType dataType); @@ -289,7 +289,7 @@ EmberAfStatus emberAfWriteManufacturerSpecificServerAttribute(uint8_t endpoint, * @see emberAfWriteClientAttribute, emberAfWriteServerAttribute, * emberAfWriteManufacturerSpecificServerAttribute */ -EmberAfStatus emberAfWriteManufacturerSpecificClientAttribute(uint8_t endpoint, EmberAfClusterId cluster, +EmberAfStatus emberAfWriteManufacturerSpecificClientAttribute(CHIPEndpointId endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint16_t manufacturerCode, uint8_t * dataPtr, EmberAfAttributeType dataType); @@ -307,8 +307,9 @@ EmberAfStatus emberAfWriteManufacturerSpecificClientAttribute(uint8_t endpoint, * @param buffer Location where attribute will be written from. * @param dataType ZCL attribute type. */ -EmberAfStatus emberAfVerifyAttributeWrite(uint8_t endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint8_t mask, - uint16_t manufacturerCode, uint8_t * dataPtr, EmberAfAttributeType dataType); +EmberAfStatus emberAfVerifyAttributeWrite(CHIPEndpointId endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, + uint8_t mask, uint16_t manufacturerCode, uint8_t * dataPtr, + EmberAfAttributeType dataType); /** * @brief Read the attribute value, performing all the checks. @@ -322,7 +323,7 @@ EmberAfStatus emberAfVerifyAttributeWrite(uint8_t endpoint, EmberAfClusterId clu * emberAfReadManufacturerSpecificClientAttribute, * emberAfReadManufacturerSpecificServerAttribute */ -EmberAfStatus emberAfReadAttribute(uint8_t endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint8_t mask, +EmberAfStatus emberAfReadAttribute(CHIPEndpointId endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint8_t mask, uint8_t * dataPtr, uint8_t readLength, EmberAfAttributeType * dataType); /** @@ -337,7 +338,7 @@ EmberAfStatus emberAfReadAttribute(uint8_t endpoint, EmberAfClusterId cluster, E * emberAfReadManufacturerSpecificClientAttribute, * emberAfReadManufacturerSpecificServerAttribute */ -EmberAfStatus emberAfReadServerAttribute(uint8_t endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, +EmberAfStatus emberAfReadServerAttribute(CHIPEndpointId endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint8_t * dataPtr, uint8_t readLength); /** @@ -352,7 +353,7 @@ EmberAfStatus emberAfReadServerAttribute(uint8_t endpoint, EmberAfClusterId clus * emberAfReadManufacturerSpecificClientAttribute, * emberAfReadManufacturerSpecificServerAttribute */ -EmberAfStatus emberAfReadClientAttribute(uint8_t endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, +EmberAfStatus emberAfReadClientAttribute(CHIPEndpointId endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint8_t * dataPtr, uint8_t readLength); /** @@ -366,7 +367,7 @@ EmberAfStatus emberAfReadClientAttribute(uint8_t endpoint, EmberAfClusterId clus * @see emberAfReadClientAttribute, emberAfReadServerAttribute, * emberAfReadManufacturerSpecificClientAttribute */ -EmberAfStatus emberAfReadManufacturerSpecificServerAttribute(uint8_t endpoint, EmberAfClusterId cluster, +EmberAfStatus emberAfReadManufacturerSpecificServerAttribute(CHIPEndpointId endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint16_t manufacturerCode, uint8_t * dataPtr, uint8_t readLength); @@ -381,7 +382,7 @@ EmberAfStatus emberAfReadManufacturerSpecificServerAttribute(uint8_t endpoint, E * @see emberAfReadClientAttribute, emberAfReadServerAttribute, * emberAfReadManufacturerSpecificServerAttribute */ -EmberAfStatus emberAfReadManufacturerSpecificClientAttribute(uint8_t endpoint, EmberAfClusterId cluster, +EmberAfStatus emberAfReadManufacturerSpecificClientAttribute(CHIPEndpointId endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint16_t manufacturerCode, uint8_t * dataPtr, uint8_t readLength); @@ -457,29 +458,29 @@ extern EmberAfDefinedEndpoint emAfEndpoints[]; /** * @brief Macro that takes index of endpoint, and returns Zigbee endpoint */ -uint8_t emberAfEndpointFromIndex(uint8_t index); +CHIPEndpointId emberAfEndpointFromIndex(uint8_t index); /** * Returns the index of a given endpoint */ -uint8_t emberAfIndexFromEndpoint(uint8_t endpoint); +uint8_t emberAfIndexFromEndpoint(CHIPEndpointId endpoint); /** * Returns the index of a given endpoint; Does not ignore disabled endpoints */ -uint8_t emberAfIndexFromEndpointIncludingDisabledEndpoints(uint8_t endpoint); +uint8_t emberAfIndexFromEndpointIncludingDisabledEndpoints(CHIPEndpointId endpoint); /** * Returns the endpoint index within a given cluster (Client-side), * looking only for standard clusters. */ -uint8_t emberAfFindClusterClientEndpointIndex(uint8_t endpoint, EmberAfClusterId clusterId); +uint8_t emberAfFindClusterClientEndpointIndex(CHIPEndpointId endpoint, EmberAfClusterId clusterId); /** * Returns the endpoint index within a given cluster (Server-side), * looking only for standard clusters. */ -uint8_t emberAfFindClusterServerEndpointIndex(uint8_t endpoint, EmberAfClusterId clusterId); +uint8_t emberAfFindClusterServerEndpointIndex(CHIPEndpointId endpoint, EmberAfClusterId clusterId); /** * @brief Macro that takes index of endpoint, and returns profile Id for it @@ -504,7 +505,7 @@ uint8_t emberAfFindClusterServerEndpointIndex(uint8_t endpoint, EmberAfClusterId /** * @brief Returns the network index of a given endpoint. */ -uint8_t emberAfNetworkIndexFromEndpoint(uint8_t endpoint); +uint8_t emberAfNetworkIndexFromEndpoint(CHIPEndpointId endpoint); /** * @brief Macro that returns primary profile ID. @@ -643,7 +644,7 @@ uint16_t emberAfAttributeValueSize(EmberAfAttributeType dataType, const uint8_t * * @param endpoint Zigbee endpoint number */ -bool emberAfIsDeviceEnabled(uint8_t endpoint); +bool emberAfIsDeviceEnabled(CHIPEndpointId endpoint); /** * @brief Function that checks if endpoint is identifying @@ -653,7 +654,7 @@ bool emberAfIsDeviceEnabled(uint8_t endpoint); * * @param endpoint Zigbee endpoint number */ -bool emberAfIsDeviceIdentifying(uint8_t endpoint); +bool emberAfIsDeviceIdentifying(CHIPEndpointId endpoint); /** * @brief Function that enables or disables an endpoint. @@ -663,7 +664,7 @@ bool emberAfIsDeviceIdentifying(uint8_t endpoint); * * @param endpoint Zigbee endpoint number */ -void emberAfSetDeviceEnabled(uint8_t endpoint, bool enabled); +void emberAfSetDeviceEnabled(CHIPEndpointId endpoint, bool enabled); /** @} END Device Control */ @@ -673,7 +674,7 @@ void emberAfSetDeviceEnabled(uint8_t endpoint, bool enabled); /** * @brief Enable/disable endpoints */ -bool emberAfEndpointEnableDisable(uint8_t endpoint, bool enable); +bool emberAfEndpointEnableDisable(CHIPEndpointId endpoint, bool enable); /** * @brief Determine if an endpoint at the specified index is enabled or disabled @@ -936,7 +937,7 @@ void emberAfRunEvents(void); * * @return EMBER_SUCCESS if the event was scheduled or an error otherwise. */ -EmberStatus emberAfScheduleTickExtended(uint8_t endpoint, EmberAfClusterId clusterId, bool isClient, uint32_t delayMs, +EmberStatus emberAfScheduleTickExtended(CHIPEndpointId endpoint, EmberAfClusterId clusterId, bool isClient, uint32_t delayMs, EmberAfEventPollControl pollControl, EmberAfEventSleepControl sleepControl); /** @@ -958,7 +959,7 @@ EmberStatus emberAfScheduleTickExtended(uint8_t endpoint, EmberAfClusterId clust * * @return EMBER_SUCCESS if the event was scheduled or an error otherwise. */ -EmberStatus emberAfScheduleClusterTick(uint8_t endpoint, EmberAfClusterId clusterId, bool isClient, uint32_t delayMs, +EmberStatus emberAfScheduleClusterTick(CHIPEndpointId endpoint, EmberAfClusterId clusterId, bool isClient, uint32_t delayMs, EmberAfEventSleepControl sleepControl); /** @@ -975,7 +976,7 @@ EmberStatus emberAfScheduleClusterTick(uint8_t endpoint, EmberAfClusterId cluste * * @return EMBER_SUCCESS if the event was scheduled or an error otherwise. */ -EmberStatus emberAfScheduleClientTickExtended(uint8_t endpoint, EmberAfClusterId clusterId, uint32_t delayMs, +EmberStatus emberAfScheduleClientTickExtended(CHIPEndpointId endpoint, EmberAfClusterId clusterId, uint32_t delayMs, EmberAfEventPollControl pollControl, EmberAfEventSleepControl sleepControl); /** @@ -989,7 +990,7 @@ EmberStatus emberAfScheduleClientTickExtended(uint8_t endpoint, EmberAfClusterId * * @return EMBER_SUCCESS if the event was scheduled or an error otherwise. */ -EmberStatus emberAfScheduleClientTick(uint8_t endpoint, EmberAfClusterId clusterId, uint32_t delayMs); +EmberStatus emberAfScheduleClientTick(CHIPEndpointId endpoint, EmberAfClusterId clusterId, uint32_t delayMs); /** * @brief A function used to schedule a cluster server event. This function @@ -1005,7 +1006,7 @@ EmberStatus emberAfScheduleClientTick(uint8_t endpoint, EmberAfClusterId cluster * * @return EMBER_SUCCESS if the event was scheduled or an error otherwise. */ -EmberStatus emberAfScheduleServerTickExtended(uint8_t endpoint, EmberAfClusterId clusterId, uint32_t delayMs, +EmberStatus emberAfScheduleServerTickExtended(CHIPEndpointId endpoint, EmberAfClusterId clusterId, uint32_t delayMs, EmberAfEventPollControl pollControl, EmberAfEventSleepControl sleepControl); /** @@ -1019,7 +1020,7 @@ EmberStatus emberAfScheduleServerTickExtended(uint8_t endpoint, EmberAfClusterId * * @return EMBER_SUCCESS if the event was scheduled or an error otherwise. */ -EmberStatus emberAfScheduleServerTick(uint8_t endpoint, EmberAfClusterId clusterId, uint32_t delayMs); +EmberStatus emberAfScheduleServerTick(CHIPEndpointId endpoint, EmberAfClusterId clusterId, uint32_t delayMs); /** * @brief A function used to deactivate a cluster-related event. This function @@ -1035,7 +1036,7 @@ EmberStatus emberAfScheduleServerTick(uint8_t endpoint, EmberAfClusterId cluster * * @return EMBER_SUCCESS if the event was deactivated or an error otherwise. */ -EmberStatus emberAfDeactivateClusterTick(uint8_t endpoint, EmberAfClusterId clusterId, bool isClient); +EmberStatus emberAfDeactivateClusterTick(CHIPEndpointId endpoint, EmberAfClusterId clusterId, bool isClient); /** * @brief A function used to deactivate a cluster client event. This function @@ -1046,7 +1047,7 @@ EmberStatus emberAfDeactivateClusterTick(uint8_t endpoint, EmberAfClusterId clus * * @return EMBER_SUCCESS if the event was deactivated or an error otherwise. */ -EmberStatus emberAfDeactivateClientTick(uint8_t endpoint, EmberAfClusterId clusterId); +EmberStatus emberAfDeactivateClientTick(CHIPEndpointId endpoint, EmberAfClusterId clusterId); /** * @brief A function used to deactivate a cluster server event. This function @@ -1057,7 +1058,7 @@ EmberStatus emberAfDeactivateClientTick(uint8_t endpoint, EmberAfClusterId clust * * @return EMBER_SUCCESS if the event was deactivated or an error otherwise. */ -EmberStatus emberAfDeactivateServerTick(uint8_t endpoint, EmberAfClusterId clusterId); +EmberStatus emberAfDeactivateServerTick(CHIPEndpointId endpoint, EmberAfClusterId clusterId); /** * @brief Sets the ::EmberEventControl to run "delayMs" milliseconds in the @@ -1155,28 +1156,28 @@ EmberStatus emberAfNetworkEventControlSetDelayMinutes(EmberEventControl * contro * @brief Sets the ::EmberEventControl for the specified endpoint as inactive. * See ::emberEventControlSetInactive. */ -EmberStatus emberAfEndpointEventControlSetInactive(EmberEventControl * controls, uint8_t endpoint); +EmberStatus emberAfEndpointEventControlSetInactive(EmberEventControl * controls, CHIPEndpointId endpoint); /** * @brief Returns true if the event for the current number is active. See * ::emberEventControlGetActive. */ -bool emberAfEndpointEventControlGetActive(EmberEventControl * controls, uint8_t endpoint); +bool emberAfEndpointEventControlGetActive(EmberEventControl * controls, CHIPEndpointId endpoint); /** * @brief Sets the ::EmberEventControl for the specified endpoint to run at the * next available opportunity. See ::emberEventControlSetActive. */ -EmberStatus emberAfEndpointEventControlSetActive(EmberEventControl * controls, uint8_t endpoint); +EmberStatus emberAfEndpointEventControlSetActive(EmberEventControl * controls, CHIPEndpointId endpoint); /** * @brief Sets the ::EmberEventControl for the specified endpoint to run * "delayMs" milliseconds in the future. See ::emberEventControlSetDelayMS. */ -EmberStatus emberAfEndpointEventControlSetDelayMS(EmberEventControl * controls, uint8_t endpoint, uint32_t delayMs); +EmberStatus emberAfEndpointEventControlSetDelayMS(EmberEventControl * controls, CHIPEndpointId endpoint, uint32_t delayMs); #ifdef DOXYGEN_SHOULD_SKIP_THIS /** * @brief Sets the ::EmberEventControl for the specified endpoint to run * "delayMs" milliseconds in the future. See ::emberEventControlSetDelayMS. */ -EmberStatus emberAfEndpointEventControlSetDelay(EmberEventControl * controls, uint8_t endpoint, uint32_t delayMs); +EmberStatus emberAfEndpointEventControlSetDelay(EmberEventControl * controls, CHIPEndpointId endpoint, uint32_t delayMs); #else #define emberAfEndpointEventControlSetDelay(controls, endpoint, delayMs) \ emberAfEndpointEventControlSetDelayMS(controls, endpoint, delayMs); @@ -1186,12 +1187,12 @@ EmberStatus emberAfEndpointEventControlSetDelay(EmberEventControl * controls, ui * "delayQs" quarter seconds in the future. See * ::emberAfEventControlSetDelayQS. */ -EmberStatus emberAfEndpointEventControlSetDelayQS(EmberEventControl * controls, uint8_t endpoint, uint32_t delayQs); +EmberStatus emberAfEndpointEventControlSetDelayQS(EmberEventControl * controls, CHIPEndpointId endpoint, uint32_t delayQs); /** * @brief Sets the ::EmberEventControl for the specified endpoint to run * "delayM" minutes in the future. See ::emberAfEventControlSetDelayMinutes. */ -EmberStatus emberAfEndpointEventControlSetDelayMinutes(EmberEventControl * controls, uint8_t endpoint, uint16_t delayM); +EmberStatus emberAfEndpointEventControlSetDelayMinutes(EmberEventControl * controls, CHIPEndpointId endpoint, uint16_t delayM); /** * @brief A function used to retrieve the number of milliseconds until @@ -1365,7 +1366,7 @@ EmberStatus emberAfSendInterPan(EmberPanId panId, const EmberEUI64 destinationLo /** * @brief Sends end device binding request. */ -EmberStatus emberAfSendEndDeviceBind(uint8_t endpoint); +EmberStatus emberAfSendEndDeviceBind(CHIPEndpointId endpoint); /** * @brief Sends the command prepared with emberAfFill.... macro. @@ -1535,7 +1536,7 @@ EmberApsFrame * emberAfGetCommandApsFrame(void); /** * @brief Set the source and destination endpoints in the client API APS frame. */ -void emberAfSetCommandEndpoints(uint8_t sourceEndpoint, uint8_t destinationEndpoint); +void emberAfSetCommandEndpoints(CHIPEndpointId sourceEndpoint, CHIPEndpointId destinationEndpoint); /** * @brief Friendly define for use in discovering client clusters with @@ -1698,7 +1699,7 @@ extern EmberAfClusterCommand * emAfCurrentCommand; * @param endpoint The endpoint on the remote device. * @return ::EMBER_SUCCESS if key establishment was initiated successfully */ -EmberStatus emberAfInitiateKeyEstablishment(EmberNodeId nodeId, uint8_t endpoint); +EmberStatus emberAfInitiateKeyEstablishment(EmberNodeId nodeId, CHIPEndpointId endpoint); /** @brief Use this function to initiate key establishment with a remote node on * a different PAN. ::emberAfInterPanKeyEstablishmentCallback will be called @@ -1727,7 +1728,7 @@ bool emberAfPerformingKeyEstablishment(void); * @return ::EMBER_SUCCESS if the partner link key exchange was initiated * successfully. */ -EmberStatus emberAfInitiatePartnerLinkKeyExchange(EmberNodeId target, uint8_t endpoint, +EmberStatus emberAfInitiatePartnerLinkKeyExchange(EmberNodeId target, CHIPEndpointId endpoint, EmberAfPartnerLinkKeyExchangeCallback * callback); #else #define emberAfInitiateKeyEstablishment(nodeId, endpoint) emberAfInitiateKeyEstablishmentCallback(nodeId, endpoint) @@ -1838,7 +1839,7 @@ EmberStatus emberAfPushCallbackNetworkIndex(void); * API must be paired with a subsequent call to ::emberAfPopNetworkIndex. */ -EmberStatus emberAfPushEndpointNetworkIndex(uint8_t endpoint); +EmberStatus emberAfPushEndpointNetworkIndex(CHIPEndpointId endpoint); /** @brief Removes the topmost network from the stack of networks maintained by * the framework and sets the current network to the new topmost network. * Every call to this API must be paired with a prior call to diff --git a/src/app/util/attribute-storage.cpp b/src/app/util/attribute-storage.cpp index 30aea1bdc832cf..3e6c712b5c6966 100644 --- a/src/app/util/attribute-storage.cpp +++ b/src/app/util/attribute-storage.cpp @@ -43,6 +43,8 @@ #include "af.h" #include "common.h" +using namespace chip; + //------------------------------------------------------------------------------ // Globals // This is not declared CONST in order to handle dynamic endpoint information @@ -109,7 +111,7 @@ const uint16_t attributeManufacturerCodeCount = GENERATED_ATTR // Forward declarations // Returns endpoint index within a given cluster -static uint8_t findClusterEndpointIndex(uint8_t endpoint, EmberAfClusterId clusterId, uint8_t mask, uint16_t manufacturerCode); +static uint8_t findClusterEndpointIndex(EndpointId endpoint, EmberAfClusterId clusterId, uint8_t mask, uint16_t manufacturerCode); //------------------------------------------------------------------------------ @@ -179,7 +181,7 @@ bool emberAfIsLongStringAttributeType(EmberAfAttributeType attributeType) } // This function is used to call the per-cluster default response callback -void emberAfClusterDefaultResponseWithMfgCodeCallback(uint8_t endpoint, EmberAfClusterId clusterId, uint8_t commandId, +void emberAfClusterDefaultResponseWithMfgCodeCallback(EndpointId endpoint, EmberAfClusterId clusterId, uint8_t commandId, EmberAfStatus status, uint8_t clientServerMask, uint16_t manufacturerCode) { EmberAfCluster * cluster = emberAfFindClusterWithMfgCode(endpoint, clusterId, clientServerMask, manufacturerCode); @@ -198,7 +200,7 @@ void emberAfClusterDefaultResponseWithMfgCodeCallback(uint8_t endpoint, EmberAfC // This function is used to call the per-cluster default response callback, and // wraps the emberAfClusterDefaultResponseWithMfgCodeCallback with a // EMBER_AF_NULL_MANUFACTURER_CODE. -void emberAfClusterDefaultResponseCallback(uint8_t endpoint, EmberAfClusterId clusterId, uint8_t commandId, EmberAfStatus status, +void emberAfClusterDefaultResponseCallback(EndpointId endpoint, EmberAfClusterId clusterId, uint8_t commandId, EmberAfStatus status, uint8_t clientServerMask) { emberAfClusterDefaultResponseWithMfgCodeCallback(endpoint, clusterId, commandId, status, clientServerMask, @@ -241,7 +243,7 @@ void emberAfClusterMessageSentCallback(EmberOutgoingMessageType type, uint16_t i } // This function is used to call the per-cluster attribute changed callback -void emAfClusterAttributeChangedCallback(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attributeId, +void emAfClusterAttributeChangedCallback(EndpointId endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attributeId, uint8_t clientServerMask, uint16_t manufacturerCode) { EmberAfCluster * cluster = emberAfFindClusterWithMfgCode(endpoint, clusterId, clientServerMask, manufacturerCode); @@ -272,9 +274,10 @@ void emAfClusterAttributeChangedCallback(uint8_t endpoint, EmberAfClusterId clus } // This function is used to call the per-cluster pre-attribute changed callback -EmberAfStatus emAfClusterPreAttributeChangedCallback(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attributeId, - uint8_t clientServerMask, uint16_t manufacturerCode, - EmberAfAttributeType attributeType, uint8_t size, uint8_t * value) +EmberAfStatus emAfClusterPreAttributeChangedCallback(EndpointId endpoint, EmberAfClusterId clusterId, + EmberAfAttributeId attributeId, uint8_t clientServerMask, + uint16_t manufacturerCode, EmberAfAttributeType attributeType, uint8_t size, + uint8_t * value) { EmberAfCluster * cluster = emberAfFindClusterWithMfgCode(endpoint, clusterId, clientServerMask, manufacturerCode); if (cluster == NULL) @@ -331,7 +334,7 @@ void emAfCallInits(void) } // Returns the pointer to metadata, or null if it is not found -EmberAfAttributeMetadata * emberAfLocateAttributeMetadata(uint8_t endpoint, EmberAfClusterId clusterId, +EmberAfAttributeMetadata * emberAfLocateAttributeMetadata(EndpointId endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attributeId, uint8_t mask, uint16_t manufacturerCode) { EmberAfAttributeMetadata * metadata = NULL; @@ -626,7 +629,7 @@ EmberAfCluster * emberAfFindClusterInType(EmberAfEndpointType * endpointType, Em // This code is used during unit tests for clusters that do not involve manufacturer code. // Should this code be used in other locations, manufacturerCode should be added. -uint8_t emberAfClusterIndex(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfClusterMask mask) +uint8_t emberAfClusterIndex(EndpointId endpoint, EmberAfClusterId clusterId, EmberAfClusterMask mask) { uint8_t ep; uint8_t index = 0xFF; @@ -646,46 +649,46 @@ uint8_t emberAfClusterIndex(uint8_t endpoint, EmberAfClusterId clusterId, EmberA } // Returns true uf endpoint contains passed cluster -bool emberAfContainsClusterWithMfgCode(uint8_t endpoint, EmberAfClusterId clusterId, uint16_t manufacturerCode) +bool emberAfContainsClusterWithMfgCode(EndpointId endpoint, EmberAfClusterId clusterId, uint16_t manufacturerCode) { return (emberAfFindClusterWithMfgCode(endpoint, clusterId, 0, manufacturerCode) != NULL); } // Returns true if endpoint contains passed cluster as a server -bool emberAfContainsServerWithMfgCode(uint8_t endpoint, EmberAfClusterId clusterId, uint16_t manufacturerCode) +bool emberAfContainsServerWithMfgCode(EndpointId endpoint, EmberAfClusterId clusterId, uint16_t manufacturerCode) { return (emberAfFindClusterWithMfgCode(endpoint, clusterId, CLUSTER_MASK_SERVER, manufacturerCode) != NULL); } // Returns true if endpoint contains passed cluster as a client -bool emberAfContainsClientWithMfgCode(uint8_t endpoint, EmberAfClusterId clusterId, uint16_t manufacturerCode) +bool emberAfContainsClientWithMfgCode(EndpointId endpoint, EmberAfClusterId clusterId, uint16_t manufacturerCode) { return (emberAfFindClusterWithMfgCode(endpoint, clusterId, CLUSTER_MASK_CLIENT, manufacturerCode) != NULL); } // Wraps emberAfContainsClusterWithMfgCode with EMBER_AF_NULL_MANUFACTURER_CODE // This will find the first cluster that has the clusterId given, regardless of mfgCode. -bool emberAfContainsCluster(uint8_t endpoint, EmberAfClusterId clusterId) +bool emberAfContainsCluster(EndpointId endpoint, EmberAfClusterId clusterId) { return (emberAfFindClusterWithMfgCode(endpoint, clusterId, 0, EMBER_AF_NULL_MANUFACTURER_CODE) != NULL); } // Wraps emberAfContainsServerWithMfgCode with EMBER_AF_NULL_MANUFACTURER_CODE // This will find the first server that has the clusterId given, regardless of mfgCode. -bool emberAfContainsServer(uint8_t endpoint, EmberAfClusterId clusterId) +bool emberAfContainsServer(EndpointId endpoint, EmberAfClusterId clusterId) { return (emberAfFindClusterWithMfgCode(endpoint, clusterId, CLUSTER_MASK_SERVER, EMBER_AF_NULL_MANUFACTURER_CODE) != NULL); } // Wraps emberAfContainsClientWithMfgCode with EMBER_AF_NULL_MANUFACTURER_CODE // This will find the first client that has the clusterId given, regardless of mfgCode. -bool emberAfContainsClient(uint8_t endpoint, EmberAfClusterId clusterId) +bool emberAfContainsClient(EndpointId endpoint, EmberAfClusterId clusterId) { return (emberAfFindClusterWithMfgCode(endpoint, clusterId, CLUSTER_MASK_CLIENT, EMBER_AF_NULL_MANUFACTURER_CODE) != NULL); } // Finds the cluster that matches endpoint, clusterId, direction, and manufacturerCode. -EmberAfCluster * emberAfFindClusterWithMfgCode(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfClusterMask mask, +EmberAfCluster * emberAfFindClusterWithMfgCode(EndpointId endpoint, EmberAfClusterId clusterId, EmberAfClusterMask mask, uint16_t manufacturerCode) { uint8_t ep = emberAfIndexFromEndpoint(endpoint); @@ -702,13 +705,13 @@ EmberAfCluster * emberAfFindClusterWithMfgCode(uint8_t endpoint, EmberAfClusterI // This function wraps emberAfFindClusterWithMfgCode with EMBER_AF_NULL_MANUFACTURER_CODE // and will ignore the manufacturerCode when trying to find clusters. // This will return the first cluster in the cluster table that matches the parameters given. -EmberAfCluster * emberAfFindCluster(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfClusterMask mask) +EmberAfCluster * emberAfFindCluster(EndpointId endpoint, EmberAfClusterId clusterId, EmberAfClusterMask mask) { return emberAfFindClusterWithMfgCode(endpoint, clusterId, mask, EMBER_AF_NULL_MANUFACTURER_CODE); } // Returns cluster within the endpoint; Does not ignore disabled endpoints -EmberAfCluster * emberAfFindClusterIncludingDisabledEndpointsWithMfgCode(uint8_t endpoint, EmberAfClusterId clusterId, +EmberAfCluster * emberAfFindClusterIncludingDisabledEndpointsWithMfgCode(EndpointId endpoint, EmberAfClusterId clusterId, EmberAfClusterMask mask, uint16_t manufacturerCode) { uint8_t ep = emberAfIndexFromEndpointIncludingDisabledEndpoints(endpoint); @@ -721,39 +724,41 @@ EmberAfCluster * emberAfFindClusterIncludingDisabledEndpointsWithMfgCode(uint8_t // Returns cluster within the endpoint; Does not ignore disabled endpoints // This will ignore manufacturerCode. -EmberAfCluster * emberAfFindClusterIncludingDisabledEndpoints(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfClusterMask mask) +EmberAfCluster * emberAfFindClusterIncludingDisabledEndpoints(EndpointId endpoint, EmberAfClusterId clusterId, + EmberAfClusterMask mask) { return emberAfFindClusterIncludingDisabledEndpointsWithMfgCode(endpoint, clusterId, mask, EMBER_AF_NULL_MANUFACTURER_CODE); } // Server wrapper for findClusterEndpointIndex. -uint8_t emberAfFindClusterServerEndpointIndexWithMfgCode(uint8_t endpoint, EmberAfClusterId clusterId, uint16_t manufacturerCode) +static uint8_t emberAfFindClusterServerEndpointIndexWithMfgCode(EndpointId endpoint, EmberAfClusterId clusterId, + uint16_t manufacturerCode) { return findClusterEndpointIndex(endpoint, clusterId, CLUSTER_MASK_SERVER, manufacturerCode); } // Client wrapper for findClusterEndpointIndex. -uint8_t emberAfFindClusterClientEndpointIndexWithMfgCode(uint8_t endpoint, EmberAfClusterId clusterId, uint16_t manufacturerCode) +uint8_t emberAfFindClusterClientEndpointIndexWithMfgCode(EndpointId endpoint, EmberAfClusterId clusterId, uint16_t manufacturerCode) { return findClusterEndpointIndex(endpoint, clusterId, CLUSTER_MASK_CLIENT, manufacturerCode); } // Server wrapper for findClusterEndpointIndex // This will ignore manufacturerCode, and return the index for the first server that matches on clusterId -uint8_t emberAfFindClusterServerEndpointIndex(uint8_t endpoint, EmberAfClusterId clusterId) +uint8_t emberAfFindClusterServerEndpointIndex(EndpointId endpoint, EmberAfClusterId clusterId) { return emberAfFindClusterServerEndpointIndexWithMfgCode(endpoint, clusterId, EMBER_AF_NULL_MANUFACTURER_CODE); } // Client wrapper for findClusterEndpointIndex // This will ignore manufacturerCode, and return the index for the first client that matches on clusterId -uint8_t emberAfFindClusterClientEndpointIndex(uint8_t endpoint, EmberAfClusterId clusterId) +uint8_t emberAfFindClusterClientEndpointIndex(EndpointId endpoint, EmberAfClusterId clusterId) { return emberAfFindClusterClientEndpointIndexWithMfgCode(endpoint, clusterId, EMBER_AF_NULL_MANUFACTURER_CODE); } // Returns the endpoint index within a given cluster -static uint8_t findClusterEndpointIndex(uint8_t endpoint, EmberAfClusterId clusterId, uint8_t mask, uint16_t manufacturerCode) +static uint8_t findClusterEndpointIndex(EndpointId endpoint, EmberAfClusterId clusterId, uint8_t mask, uint16_t manufacturerCode) { uint8_t i, epi = 0; @@ -778,7 +783,7 @@ static uint8_t findClusterEndpointIndex(uint8_t endpoint, EmberAfClusterId clust return epi; } -static uint8_t findIndexFromEndpoint(uint8_t endpoint, bool ignoreDisabledEndpoints) +static uint8_t findIndexFromEndpoint(EndpointId endpoint, bool ignoreDisabledEndpoints) { uint8_t epi; for (epi = 0; epi < emberAfEndpointCount(); epi++) @@ -792,7 +797,7 @@ static uint8_t findIndexFromEndpoint(uint8_t endpoint, bool ignoreDisabledEndpoi return 0xFF; } -bool emberAfEndpointIsEnabled(uint8_t endpoint) +bool emberAfEndpointIsEnabled(EndpointId endpoint) { uint8_t index = findIndexFromEndpoint(endpoint, false); // ignore disabled endpoints? @@ -807,7 +812,7 @@ bool emberAfEndpointIsEnabled(uint8_t endpoint) return emberAfEndpointIndexIsEnabled(index); } -// bool emberAfEndpointEnableDisable(uint8_t endpoint, bool enable) +// bool emberAfEndpointEnableDisable(EndpointId endpoint, bool enable) // { // uint8_t index = findIndexFromEndpoint(endpoint, // false); // ignore disabled endpoints? @@ -863,27 +868,27 @@ bool emberAfEndpointIsEnabled(uint8_t endpoint) // } // Returns the index of a given endpoint. Does not consider disabled endpoints. -uint8_t emberAfIndexFromEndpoint(uint8_t endpoint) +uint8_t emberAfIndexFromEndpoint(EndpointId endpoint) { return findIndexFromEndpoint(endpoint, true); // ignore disabled endpoints? } // Returns the index of a given endpoint. Considers disabled endpoints. -uint8_t emberAfIndexFromEndpointIncludingDisabledEndpoints(uint8_t endpoint) +uint8_t emberAfIndexFromEndpointIncludingDisabledEndpoints(EndpointId endpoint) { return findIndexFromEndpoint(endpoint, false); // ignore disabled endpoints? } -uint8_t emberAfEndpointFromIndex(uint8_t index) +EndpointId emberAfEndpointFromIndex(uint8_t index) { return emAfEndpoints[index].endpoint; } // If server == true, returns the number of server clusters, // otherwise number of client clusters on this endpoint -uint8_t emberAfClusterCount(uint8_t endpoint, bool server) +uint8_t emberAfClusterCount(EndpointId endpoint, bool server) { uint8_t index = emberAfIndexFromEndpoint(endpoint); uint8_t i, c = 0; @@ -914,7 +919,7 @@ uint8_t emberAfClusterCount(uint8_t endpoint, bool server) return c; } -uint8_t emberAfGetClusterCountForEndpoint(uint8_t endpoint) +uint8_t emberAfGetClusterCountForEndpoint(EndpointId endpoint) { uint8_t index = emberAfIndexFromEndpoint(endpoint); if (index == 0xFF) @@ -933,7 +938,7 @@ uint8_t emberAfGetClusterCountForEndpoint(uint8_t endpoint) // - Use emberAfGetClusterCountForEndpoint() with emberAfGetClusterByIndex() // // Don't mix them. -EmberAfCluster * emberAfGetClusterByIndex(uint8_t endpoint, uint8_t clusterIndex) +EmberAfCluster * emberAfGetClusterByIndex(EndpointId endpoint, uint8_t clusterIndex) { uint8_t endpointIndex = emberAfIndexFromEndpoint(endpoint); EmberAfDefinedEndpoint * definedEndpoint; @@ -951,7 +956,7 @@ EmberAfCluster * emberAfGetClusterByIndex(uint8_t endpoint, uint8_t clusterIndex return &(definedEndpoint->endpointType->cluster[clusterIndex]); } -EmberAfProfileId emberAfGetProfileIdForEndpoint(uint8_t endpoint) +EmberAfProfileId emberAfGetProfileIdForEndpoint(EndpointId endpoint) { uint8_t endpointIndex = emberAfIndexFromEndpoint(endpoint); if (endpointIndex == 0xFF) @@ -961,7 +966,7 @@ EmberAfProfileId emberAfGetProfileIdForEndpoint(uint8_t endpoint) return emAfEndpoints[endpointIndex].profileId; } -uint16_t emberAfGetDeviceIdForEndpoint(uint8_t endpoint) +uint16_t emberAfGetDeviceIdForEndpoint(EndpointId endpoint) { uint8_t endpointIndex = emberAfIndexFromEndpoint(endpoint); if (endpointIndex == 0xFF) @@ -973,7 +978,7 @@ uint16_t emberAfGetDeviceIdForEndpoint(uint8_t endpoint) // Returns the cluster of Nth server or client cluster, // depending on server toggle. -EmberAfCluster * emberAfGetNthCluster(uint8_t endpoint, uint8_t n, bool server) +EmberAfCluster * emberAfGetNthCluster(EndpointId endpoint, uint8_t n, bool server) { uint8_t index = emberAfIndexFromEndpoint(endpoint); EmberAfDefinedEndpoint * de; @@ -1004,7 +1009,7 @@ EmberAfCluster * emberAfGetNthCluster(uint8_t endpoint, uint8_t n, bool server) // Returns number of clusters put into the passed cluster list // for the given endpoint and client/server polarity -uint8_t emberAfGetClustersFromEndpoint(uint8_t endpoint, EmberAfClusterId * clusterList, uint8_t listLen, bool server) +uint8_t emberAfGetClustersFromEndpoint(EndpointId endpoint, EmberAfClusterId * clusterList, uint8_t listLen, bool server) { uint8_t clusterCount = emberAfClusterCount(endpoint, server); uint8_t i; @@ -1021,17 +1026,17 @@ uint8_t emberAfGetClustersFromEndpoint(uint8_t endpoint, EmberAfClusterId * clus return clusterCount; } -void emberAfInitializeAttributes(uint8_t endpoint) +void emberAfInitializeAttributes(EndpointId endpoint) { emAfLoadAttributeDefaults(endpoint, false); } -void emberAfResetAttributes(uint8_t endpoint) +void emberAfResetAttributes(EndpointId endpoint) { emAfLoadAttributeDefaults(endpoint, true); } -void emAfLoadAttributeDefaults(uint8_t endpoint, bool writeTokens) +void emAfLoadAttributeDefaults(EndpointId endpoint, bool writeTokens) { uint8_t ep, clusterI, curNetwork = 0 /* emberGetCurrentNetwork() */; uint16_t attr; @@ -1138,7 +1143,7 @@ void emAfLoadAttributeDefaults(uint8_t endpoint, bool writeTokens) } } -void emAfLoadAttributesFromTokens(uint8_t endpoint) +void emAfLoadAttributesFromTokens(EndpointId endpoint) { // On EZSP host we currently do not support this. We need to come up with some // callbacks. @@ -1150,7 +1155,7 @@ void emAfLoadAttributesFromTokens(uint8_t endpoint) // 'data' argument may be null, since we changed the ptrToDefaultValue // to be null instead of pointing to all zeroes. // This function has to be able to deal with that. -void emAfSaveAttributeToToken(uint8_t * data, uint8_t endpoint, EmberAfClusterId clusterId, EmberAfAttributeMetadata * metadata) +void emAfSaveAttributeToToken(uint8_t * data, EndpointId endpoint, EmberAfClusterId clusterId, EmberAfAttributeMetadata * metadata) { // Get out of here if this attribute doesn't have a token. if (!emberAfAttributeIsTokenized(metadata)) diff --git a/src/app/util/attribute-storage.h b/src/app/util/attribute-storage.h index 783e34b72039d7..bdeb7c5f9eb412 100644 --- a/src/app/util/attribute-storage.h +++ b/src/app/util/attribute-storage.h @@ -119,35 +119,35 @@ EmberAfCluster * emberAfFindClusterInType(EmberAfEndpointType * endpointType, Em // clusterIndex(Y,10,CLUSTER_MASK_SERVER) returns 0 // clusterIndex(Y,11,CLUSTER_MASK_SERVER) returns 0xFF // clusterIndex(Y,12,CLUSTER_MASK_SERVER) returns 0xFF -uint8_t emberAfClusterIndex(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfClusterMask mask); +uint8_t emberAfClusterIndex(CHIPEndpointId endpoint, EmberAfClusterId clusterId, EmberAfClusterMask mask); // If server == true, returns the number of server clusters, // otherwise number of client clusters on this endpoint -uint8_t emberAfClusterCount(uint8_t endpoint, bool server); +uint8_t emberAfClusterCount(CHIPEndpointId endpoint, bool server); // Returns the clusterId of Nth server or client cluster, // depending on server toggle. -EmberAfCluster * emberAfGetNthCluster(uint8_t endpoint, uint8_t n, bool server); +EmberAfCluster * emberAfGetNthCluster(CHIPEndpointId endpoint, uint8_t n, bool server); // Returns number of clusters put into the passed cluster list // for the given endpoint and client/server polarity -uint8_t emberAfGetClustersFromEndpoint(uint8_t endpoint, EmberAfClusterId * clusterList, uint8_t listLen, bool server); +uint8_t emberAfGetClustersFromEndpoint(CHIPEndpointId endpoint, EmberAfClusterId * clusterList, uint8_t listLen, bool server); // Returns cluster within the endpoint, or NULL if it isn't there -EmberAfCluster * emberAfFindClusterWithMfgCode(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfClusterMask mask, +EmberAfCluster * emberAfFindClusterWithMfgCode(CHIPEndpointId endpoint, EmberAfClusterId clusterId, EmberAfClusterMask mask, uint16_t manufacturerCode); // Returns cluster within the endpoint, or NULL if it isn't there // This wraps emberAfFindClusterWithMfgCode with EMBER_AF_NULL_MANUFACTURER_CODE -EmberAfCluster * emberAfFindCluster(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfClusterMask mask); +EmberAfCluster * emberAfFindCluster(CHIPEndpointId endpoint, EmberAfClusterId clusterId, EmberAfClusterMask mask); // Returns cluster within the endpoint; Does not ignore disabled endpoints -EmberAfCluster * emberAfFindClusterIncludingDisabledEndpointsWithMfgCode(uint8_t endpoint, EmberAfClusterId clusterId, +EmberAfCluster * emberAfFindClusterIncludingDisabledEndpointsWithMfgCode(CHIPEndpointId endpoint, EmberAfClusterId clusterId, EmberAfClusterMask mask, uint16_t manufacturerCode); // Returns cluster within the endpoint; Does not ignore disabled endpoints // This wraps emberAfFindClusterIncludingDisabledEndpointsWithMfgCode with EMBER_AF_NULL_MANUFACTURER_CODE -EmberAfCluster * emberAfFindClusterIncludingDisabledEndpoints(uint8_t endpoint, EmberAfClusterId clusterId, +EmberAfCluster * emberAfFindClusterIncludingDisabledEndpoints(CHIPEndpointId endpoint, EmberAfClusterId clusterId, EmberAfClusterMask mask); // Function mask must contain one of the CLUSTER_MASK function macros, @@ -157,38 +157,40 @@ EmberAfCluster * emberAfFindClusterIncludingDisabledEndpoints(uint8_t endpoint, EmberAfGenericClusterFunction emberAfFindClusterFunction(EmberAfCluster * cluster, EmberAfClusterMask functionMask); // Public APIs for loading attributes -void emberAfInitializeAttributes(uint8_t endpoint); -void emberAfResetAttributes(uint8_t endpoint); +void emberAfInitializeAttributes(CHIPEndpointId endpoint); +void emberAfResetAttributes(CHIPEndpointId endpoint); // Loads the attributes from built-in default and / or tokens -void emAfLoadAttributeDefaults(uint8_t endpoint, bool writeTokens); +void emAfLoadAttributeDefaults(CHIPEndpointId endpoint, bool writeTokens); // This function loads from tokens all the attributes that // are defined to be stored in tokens. -void emAfLoadAttributesFromTokens(uint8_t endpoint); +void emAfLoadAttributesFromTokens(CHIPEndpointId endpoint); // After the RAM value has changed, code should call this // function. If this attribute has been // tagged as stored-to-token, then code will store // the attribute to token. -void emAfSaveAttributeToToken(uint8_t * data, uint8_t endpoint, EmberAfClusterId clusterId, EmberAfAttributeMetadata * metadata); +void emAfSaveAttributeToToken(uint8_t * data, CHIPEndpointId endpoint, EmberAfClusterId clusterId, + EmberAfAttributeMetadata * metadata); // Calls the attribute changed callback -void emAfClusterAttributeChangedCallback(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attributeId, +void emAfClusterAttributeChangedCallback(CHIPEndpointId endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attributeId, uint8_t clientServerMask, uint16_t manufacturerCode); // Calls the attribute changed callback for a specific cluster. -EmberAfStatus emAfClusterPreAttributeChangedCallback(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attributeId, - uint8_t clientServerMask, uint16_t manufacturerCode, - EmberAfAttributeType attributeType, uint8_t size, uint8_t * value); +EmberAfStatus emAfClusterPreAttributeChangedCallback(CHIPEndpointId endpoint, EmberAfClusterId clusterId, + EmberAfAttributeId attributeId, uint8_t clientServerMask, + uint16_t manufacturerCode, EmberAfAttributeType attributeType, uint8_t size, + uint8_t * value); // Calls the default response callback for a specific cluster, and wraps emberAfClusterDefaultResponseWithMfgCodeCallback // with the EMBER_NULL_MANUFACTURER_CODE -void emberAfClusterDefaultResponseCallback(uint8_t endpoint, EmberAfClusterId clusterId, uint8_t commandId, EmberAfStatus status, - uint8_t clientServerMask); +void emberAfClusterDefaultResponseCallback(CHIPEndpointId endpoint, EmberAfClusterId clusterId, uint8_t commandId, + EmberAfStatus status, uint8_t clientServerMask); // Calls the default response callback for a specific cluster. -void emberAfClusterDefaultResponseWithMfgCodeCallback(uint8_t endpoint, EmberAfClusterId clusterId, uint8_t commandId, +void emberAfClusterDefaultResponseWithMfgCodeCallback(CHIPEndpointId endpoint, EmberAfClusterId clusterId, uint8_t commandId, EmberAfStatus status, uint8_t clientServerMask, uint16_t manufacturerCode); // Calls the message sent callback for a specific cluster, and wraps emberAfClusterMessageSentWithMfgCodeCallback @@ -208,7 +210,7 @@ uint16_t emAfGetManufacturerCodeForAttribute(EmberAfCluster * cluster, EmberAfAt // returns true if the mask matches a passed interval bool emberAfCheckTick(EmberAfClusterMask mask, uint8_t passedMask); -bool emberAfEndpointIsEnabled(uint8_t endpoint); +bool emberAfEndpointIsEnabled(CHIPEndpointId endpoint); // Note the difference in implementation from emberAfGetNthCluster(). // emberAfGetClusterByIndex() retrieves the cluster by index regardless of server/client @@ -219,11 +221,11 @@ bool emberAfEndpointIsEnabled(uint8_t endpoint); // - Use emberAfGetClusterCountForEndpoint() with emberAfGetClusterByIndex() // // Don't mix them. -uint8_t emberAfGetClusterCountForEndpoint(uint8_t endpoint); -EmberAfCluster * emberAfGetClusterByIndex(uint8_t endpoint, uint8_t clusterIndex); +uint8_t emberAfGetClusterCountForEndpoint(CHIPEndpointId endpoint); +EmberAfCluster * emberAfGetClusterByIndex(CHIPEndpointId endpoint, uint8_t clusterIndex); -EmberAfProfileId emberAfGetProfileIdForEndpoint(uint8_t endpoint); -uint16_t emberAfGetDeviceIdForEndpoint(uint8_t endpoint); +EmberAfProfileId emberAfGetProfileIdForEndpoint(CHIPEndpointId endpoint); +uint16_t emberAfGetDeviceIdForEndpoint(CHIPEndpointId endpoint); #ifdef __cplusplus } // extern "C" diff --git a/src/app/util/attribute-table.cpp b/src/app/util/attribute-table.cpp index 62c636f43be828..7de6bf0450a6ac 100644 --- a/src/app/util/attribute-table.cpp +++ b/src/app/util/attribute-table.cpp @@ -51,6 +51,8 @@ #include "gen/enums.h" +using namespace chip; + //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ @@ -62,7 +64,7 @@ //------------------------------------------------------------------------------ // Globals -EmberAfStatus emberAfWriteAttributeExternal(uint8_t endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, +EmberAfStatus emberAfWriteAttributeExternal(EndpointId endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint8_t mask, uint16_t manufacturerCode, uint8_t * dataPtr, EmberAfAttributeType dataType) { @@ -82,7 +84,7 @@ EmberAfStatus emberAfWriteAttributeExternal(uint8_t endpoint, EmberAfClusterId c } //@deprecated use emberAfWriteServerAttribute or emberAfWriteClientAttribute -EmberAfStatus emberAfWriteAttribute(uint8_t endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint8_t mask, +EmberAfStatus emberAfWriteAttribute(EndpointId endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint8_t mask, uint8_t * dataPtr, EmberAfAttributeType dataType) { return emAfWriteAttribute(endpoint, cluster, attributeID, mask, EMBER_AF_NULL_MANUFACTURER_CODE, dataPtr, dataType, @@ -90,7 +92,7 @@ EmberAfStatus emberAfWriteAttribute(uint8_t endpoint, EmberAfClusterId cluster, false); // just test? } -EmberAfStatus emberAfWriteClientAttribute(uint8_t endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, +EmberAfStatus emberAfWriteClientAttribute(EndpointId endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint8_t * dataPtr, EmberAfAttributeType dataType) { return emAfWriteAttribute(endpoint, cluster, attributeID, CLUSTER_MASK_CLIENT, EMBER_AF_NULL_MANUFACTURER_CODE, dataPtr, @@ -99,7 +101,7 @@ EmberAfStatus emberAfWriteClientAttribute(uint8_t endpoint, EmberAfClusterId clu false); // just test? } -EmberAfStatus emberAfWriteServerAttribute(uint8_t endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, +EmberAfStatus emberAfWriteServerAttribute(EndpointId endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint8_t * dataPtr, EmberAfAttributeType dataType) { return emAfWriteAttribute(endpoint, cluster, attributeID, CLUSTER_MASK_SERVER, EMBER_AF_NULL_MANUFACTURER_CODE, dataPtr, @@ -108,7 +110,7 @@ EmberAfStatus emberAfWriteServerAttribute(uint8_t endpoint, EmberAfClusterId clu false); // just test? } -EmberAfStatus emberAfWriteManufacturerSpecificClientAttribute(uint8_t endpoint, EmberAfClusterId cluster, +EmberAfStatus emberAfWriteManufacturerSpecificClientAttribute(EndpointId endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint16_t manufacturerCode, uint8_t * dataPtr, EmberAfAttributeType dataType) { @@ -117,7 +119,7 @@ EmberAfStatus emberAfWriteManufacturerSpecificClientAttribute(uint8_t endpoint, false); // just test? } -EmberAfStatus emberAfWriteManufacturerSpecificServerAttribute(uint8_t endpoint, EmberAfClusterId cluster, +EmberAfStatus emberAfWriteManufacturerSpecificServerAttribute(EndpointId endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint16_t manufacturerCode, uint8_t * dataPtr, EmberAfAttributeType dataType) { @@ -126,51 +128,51 @@ EmberAfStatus emberAfWriteManufacturerSpecificServerAttribute(uint8_t endpoint, false); // just test? } -EmberAfStatus emberAfVerifyAttributeWrite(uint8_t endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint8_t mask, - uint16_t manufacturerCode, uint8_t * dataPtr, EmberAfAttributeType dataType) +EmberAfStatus emberAfVerifyAttributeWrite(EndpointId endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, + uint8_t mask, uint16_t manufacturerCode, uint8_t * dataPtr, EmberAfAttributeType dataType) { return emAfWriteAttribute(endpoint, cluster, attributeID, mask, manufacturerCode, dataPtr, dataType, false, // override read-only? true); // just test? } -EmberAfStatus emberAfReadAttribute(uint8_t endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint8_t mask, +EmberAfStatus emberAfReadAttribute(EndpointId endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint8_t mask, uint8_t * dataPtr, uint8_t readLength, EmberAfAttributeType * dataType) { return emAfReadAttribute(endpoint, cluster, attributeID, mask, EMBER_AF_NULL_MANUFACTURER_CODE, dataPtr, readLength, dataType); } -EmberAfStatus emberAfReadServerAttribute(uint8_t endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, +EmberAfStatus emberAfReadServerAttribute(EndpointId endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint8_t * dataPtr, uint8_t readLength) { return emAfReadAttribute(endpoint, cluster, attributeID, CLUSTER_MASK_SERVER, EMBER_AF_NULL_MANUFACTURER_CODE, dataPtr, readLength, NULL); } -EmberAfStatus emberAfReadClientAttribute(uint8_t endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, +EmberAfStatus emberAfReadClientAttribute(EndpointId endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint8_t * dataPtr, uint8_t readLength) { return emAfReadAttribute(endpoint, cluster, attributeID, CLUSTER_MASK_CLIENT, EMBER_AF_NULL_MANUFACTURER_CODE, dataPtr, readLength, NULL); } -EmberAfStatus emberAfReadManufacturerSpecificServerAttribute(uint8_t endpoint, EmberAfClusterId cluster, +EmberAfStatus emberAfReadManufacturerSpecificServerAttribute(EndpointId endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint16_t manufacturerCode, uint8_t * dataPtr, uint8_t readLength) { return emAfReadAttribute(endpoint, cluster, attributeID, CLUSTER_MASK_SERVER, manufacturerCode, dataPtr, readLength, NULL); } -EmberAfStatus emberAfReadManufacturerSpecificClientAttribute(uint8_t endpoint, EmberAfClusterId cluster, +EmberAfStatus emberAfReadManufacturerSpecificClientAttribute(EndpointId endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint16_t manufacturerCode, uint8_t * dataPtr, uint8_t readLength) { return emAfReadAttribute(endpoint, cluster, attributeID, CLUSTER_MASK_CLIENT, manufacturerCode, dataPtr, readLength, NULL); } -bool emberAfReadSequentialAttributesAddToResponse(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfAttributeId startAttributeId, - uint8_t mask, uint16_t manufacturerCode, uint8_t maxAttributeIds, - bool includeAccessControl) +bool emberAfReadSequentialAttributesAddToResponse(EndpointId endpoint, EmberAfClusterId clusterId, + EmberAfAttributeId startAttributeId, uint8_t mask, uint16_t manufacturerCode, + uint8_t maxAttributeIds, bool includeAccessControl) { uint16_t i; uint16_t discovered = 0; @@ -257,7 +259,8 @@ static void emberAfAttributeDecodeAndPrintCluster(EmberAfClusterId cluster, uint void emberAfPrintAttributeTable(void) { uint8_t data[ATTRIBUTE_LARGEST]; - uint8_t endpointIndex, clusterIndex; + decltype(emberAfEndpointCount()) endpointIndex; + decltype(EmberAfEndpointType::clusterCount) clusterIndex; uint16_t attributeIndex; EmberAfStatus status; uint16_t mfgCode; @@ -335,8 +338,8 @@ void emberAfPrintAttributeTable(void) // 1) unsupported: [attrId:2] [status:1] // 2) supported: [attrId:2] [status:1] [type:1] [data:n] // -void emberAfRetrieveAttributeAndCraftResponse(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attrId, uint8_t mask, - uint16_t manufacturerCode, uint16_t readLength) +void emberAfRetrieveAttributeAndCraftResponse(EndpointId endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attrId, + uint8_t mask, uint16_t manufacturerCode, uint16_t readLength) { EmberAfStatus status; uint8_t data[ATTRIBUTE_LARGEST]; @@ -412,7 +415,7 @@ void emberAfRetrieveAttributeAndCraftResponse(uint8_t endpoint, EmberAfClusterId // insufficient space in the buffer or an error occurs, buffer and bufIndex will // remain unchanged. Otherwise, bufIndex will be incremented appropriately and // the fields will be written to the buffer. -EmberAfStatus emberAfAppendAttributeReportFields(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attributeId, +EmberAfStatus emberAfAppendAttributeReportFields(EndpointId endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attributeId, uint8_t mask, uint8_t * buffer, uint8_t bufLen, uint8_t * bufIndex) { EmberAfStatus status; @@ -482,7 +485,7 @@ EmberAfStatus emberAfAppendAttributeReportFields(uint8_t endpoint, EmberAfCluste // the table or the data is too large, returns true and writes to dataPtr // if the attribute is supported and the readLength specified is less than // the length of the data. -EmberAfStatus emAfWriteAttribute(uint8_t endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint8_t mask, +EmberAfStatus emAfWriteAttribute(EndpointId endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint8_t mask, uint16_t manufacturerCode, uint8_t * data, EmberAfAttributeType dataType, bool overrideReadOnlyAndDataType, bool justTest) { @@ -625,7 +628,7 @@ EmberAfStatus emAfWriteAttribute(uint8_t endpoint, EmberAfClusterId cluster, Emb // If dataPtr is NULL, no data is copied to the caller. // readLength should be 0 in that case. -EmberAfStatus emAfReadAttribute(uint8_t endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint8_t mask, +EmberAfStatus emAfReadAttribute(EndpointId endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint8_t mask, uint16_t manufacturerCode, uint8_t * dataPtr, uint16_t readLength, EmberAfAttributeType * dataType) { EmberAfAttributeMetadata * metadata = NULL; diff --git a/src/app/util/attribute-table.h b/src/app/util/attribute-table.h index c5eeec9aa2281a..8f8c63d10a2da1 100644 --- a/src/app/util/attribute-table.h +++ b/src/app/util/attribute-table.h @@ -51,25 +51,26 @@ extern "C" { #endif // __cplusplus // Remote devices writing attributes of local device -EmberAfStatus emberAfWriteAttributeExternal(uint8_t endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, +EmberAfStatus emberAfWriteAttributeExternal(CHIPEndpointId endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint8_t mask, uint16_t manufacturerCode, uint8_t * dataPtr, EmberAfAttributeType dataType); -void emberAfRetrieveAttributeAndCraftResponse(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attrId, uint8_t mask, - uint16_t manufacturerCode, uint16_t readLength); -EmberAfStatus emberAfAppendAttributeReportFields(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attributeId, - uint8_t mask, uint8_t * buffer, uint8_t bufLen, uint8_t * bufIndex); +void emberAfRetrieveAttributeAndCraftResponse(CHIPEndpointId endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attrId, + uint8_t mask, uint16_t manufacturerCode, uint16_t readLength); +EmberAfStatus emberAfAppendAttributeReportFields(CHIPEndpointId endpoint, EmberAfClusterId clusterId, + EmberAfAttributeId attributeId, uint8_t mask, uint8_t * buffer, uint8_t bufLen, + uint8_t * bufIndex); void emberAfPrintAttributeTable(void); -bool emberAfReadSequentialAttributesAddToResponse(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfAttributeId startAttributeId, - uint8_t mask, uint16_t manufacturerCode, uint8_t maxAttributeIds, - bool includeAccessControl); +bool emberAfReadSequentialAttributesAddToResponse(CHIPEndpointId endpoint, EmberAfClusterId clusterId, + EmberAfAttributeId startAttributeId, uint8_t mask, uint16_t manufacturerCode, + uint8_t maxAttributeIds, bool includeAccessControl); -EmberAfStatus emAfWriteAttribute(uint8_t endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint8_t mask, +EmberAfStatus emAfWriteAttribute(CHIPEndpointId endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint8_t mask, uint16_t manufacturerCode, uint8_t * data, EmberAfAttributeType dataType, bool overrideReadOnlyAndDataType, bool justTest); -EmberAfStatus emAfReadAttribute(uint8_t endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint8_t mask, +EmberAfStatus emAfReadAttribute(CHIPEndpointId endpoint, EmberAfClusterId cluster, EmberAfAttributeId attributeID, uint8_t mask, uint16_t manufacturerCode, uint8_t * dataPtr, uint16_t readLength, EmberAfAttributeType * dataType); #ifdef __cplusplus diff --git a/src/app/util/client-api.cpp b/src/app/util/client-api.cpp index c229956d8109ab..f53c10d785f6e4 100644 --- a/src/app/util/client-api.cpp +++ b/src/app/util/client-api.cpp @@ -43,6 +43,8 @@ #include "util.h" #include +using namespace chip; + uint8_t * emAfZclBuffer = NULL; uint16_t emAfZclBufferLen = 0; @@ -360,7 +362,7 @@ EmberApsFrame * emberAfGetCommandApsFrame(void) return emAfCommandApsFrame; } -void emberAfSetCommandEndpoints(uint8_t sourceEndpoint, uint8_t destinationEndpoint) +void emberAfSetCommandEndpoints(EndpointId sourceEndpoint, EndpointId destinationEndpoint) { emAfCommandApsFrame->sourceEndpoint = sourceEndpoint; emAfCommandApsFrame->destinationEndpoint = destinationEndpoint; diff --git a/src/app/util/esi-management.cpp b/src/app/util/esi-management.cpp index d5acfec9643f9a..250f81eef6ef8c 100644 --- a/src/app/util/esi-management.cpp +++ b/src/app/util/esi-management.cpp @@ -43,6 +43,8 @@ #include "af.h" #include +using namespace chip; + static EmberAfPluginEsiManagementEsiEntry esiTable[EMBER_AF_PLUGIN_ESI_MANAGEMENT_ESI_TABLE_SIZE]; static EmberAfEsiManagementDeletionCallback deletionCallbackTable[EMBER_AF_PLUGIN_ESI_MANAGEMENT_PLUGIN_CALLBACK_TABLE_SIZE]; static uint8_t deletionCallbackTableSize = 0; @@ -107,7 +109,7 @@ EmberAfPluginEsiManagementEsiEntry * emberAfPluginEsiManagementEsiLookUpByShortI } } -EmberAfPluginEsiManagementEsiEntry * emberAfPluginEsiManagementEsiLookUpByLongIdAndEndpoint(EmberEUI64 longId, uint8_t endpoint) +EmberAfPluginEsiManagementEsiEntry * emberAfPluginEsiManagementEsiLookUpByLongIdAndEndpoint(EmberEUI64 longId, EndpointId endpoint) { uint8_t index = emberAfPluginEsiManagementIndexLookUpByLongIdAndEndpoint(longId, endpoint); if (index < EMBER_AF_PLUGIN_ESI_MANAGEMENT_ESI_TABLE_SIZE) @@ -135,7 +137,7 @@ uint8_t emberAfPluginEsiManagementIndexLookUpByShortIdAndEndpoint(EmberNodeId sh return 0xFF; } -uint8_t emberAfPluginEsiManagementIndexLookUpByLongIdAndEndpoint(EmberEUI64 longId, uint8_t endpoint) +uint8_t emberAfPluginEsiManagementIndexLookUpByLongIdAndEndpoint(EmberEUI64 longId, EndpointId endpoint) { uint8_t i; for (i = 0; i < EMBER_AF_PLUGIN_ESI_MANAGEMENT_ESI_TABLE_SIZE; i++) diff --git a/src/app/util/esi-management.h b/src/app/util/esi-management.h index d2b102b3614af0..74bb2b704b6c50 100644 --- a/src/app/util/esi-management.h +++ b/src/app/util/esi-management.h @@ -61,7 +61,7 @@ typedef struct EmberEUI64 eui64; ChipNodeId nodeId; uint8_t networkIndex; - uint8_t endpoint; + CHIPEndpointId endpoint; uint8_t age; // The number of discovery cycles the ESI has not been discovered. } EmberAfPluginEsiManagementEsiEntry; @@ -81,7 +81,8 @@ EmberAfPluginEsiManagementEsiEntry * emberAfPluginEsiManagementEsiLookUpByShortI * Returns a pointer to the entry if a matching entry was found, otherwise it * returns NULL. */ -EmberAfPluginEsiManagementEsiEntry * emberAfPluginEsiManagementEsiLookUpByLongIdAndEndpoint(EmberEUI64 longId, uint8_t endpoint); +EmberAfPluginEsiManagementEsiEntry * emberAfPluginEsiManagementEsiLookUpByLongIdAndEndpoint(EmberEUI64 longId, + CHIPEndpointId endpoint); /** * Allows retrieving the index of an entry that matches the passed short ID @@ -99,7 +100,7 @@ uint8_t emberAfPluginEsiManagementIndexLookUpByShortIdAndEndpoint(EmberNodeId sh * It returns the index of the matching entry if a matching entry was found, * otherwise it returns 0xFF. */ -uint8_t emberAfPluginEsiManagementIndexLookUpByLongIdAndEndpoint(EmberEUI64 longId, uint8_t endpoint); +uint8_t emberAfPluginEsiManagementIndexLookUpByLongIdAndEndpoint(EmberEUI64 longId, CHIPEndpointId endpoint); /** * Searches in the ESI table by the table index. diff --git a/src/app/util/types_stub.h b/src/app/util/types_stub.h index 18769cf8c96145..537b919100f7c4 100644 --- a/src/app/util/types_stub.h +++ b/src/app/util/types_stub.h @@ -605,7 +605,7 @@ typedef struct /** The type of binding. */ EmberBindingType type; /** The endpoint on the local node. */ - uint8_t local; + CHIPEndpointId local; /** A cluster ID that matches one from the local endpoint's simple descriptor. * This cluster ID is set by the provisioning application to indicate which * part an endpoint's functionality is bound to this particular remote node @@ -613,9 +613,9 @@ typedef struct * that a binding can be used to to send messages with any cluster ID, not * just that listed in the binding. */ - uint16_t clusterId; + CHIPClusterId clusterId; /** The endpoint on the remote node (specified by \c identifier). */ - uint8_t remote; + CHIPEndpointId remote; /** A 64-bit destination identifier. This is either: * - The destination ChipNodeId, for unicasts. * - A multicast ChipGroupId, for multicasts. diff --git a/src/app/util/util.cpp b/src/app/util/util.cpp index 025bfef0d6793c..3c0706a4bb4409 100644 --- a/src/app/util/util.cpp +++ b/src/app/util/util.cpp @@ -48,6 +48,8 @@ //#include "app/framework/util/time-util.h" //#include "hal/micro/crc.h" +using namespace chip; + // TODO: Need to figure out what needs to happen wrt HAL tokens here, but for // now define ESZP_HOST to disable it. See // https://github.com/project-chip/connectedhomeip/issues/3275 @@ -128,7 +130,7 @@ EMBER_AF_GENERATED_PLUGIN_TICK_FUNCTION_DECLARATIONS //------------------------------------------------------------------------------ // Device enabled/disabled functions -bool emberAfIsDeviceEnabled(uint8_t endpoint) +bool emberAfIsDeviceEnabled(EndpointId endpoint) { uint8_t index; #ifdef ZCL_USING_BASIC_CLUSTER_DEVICE_ENABLED_ATTRIBUTE @@ -147,7 +149,7 @@ bool emberAfIsDeviceEnabled(uint8_t endpoint) return false; } -void emberAfSetDeviceEnabled(uint8_t endpoint, bool enabled) +void emberAfSetDeviceEnabled(EndpointId endpoint, bool enabled) { uint8_t index = emberAfIndexFromEndpoint(endpoint); if (index != 0xFF && index < sizeof(afDeviceEnabled)) @@ -161,7 +163,7 @@ void emberAfSetDeviceEnabled(uint8_t endpoint, bool enabled) } // Is the device identifying? -bool emberAfIsDeviceIdentifying(uint8_t endpoint) +bool emberAfIsDeviceIdentifying(EndpointId endpoint) { #ifdef ZCL_USING_IDENTIFY_CLUSTER_SERVER uint16_t identifyTime; @@ -572,7 +574,7 @@ bool emberAfProcessMessage(EmberApsFrame * apsFrame, EmberIncomingMessageType ty uint8_t i; for (i = 0; i < emberAfEndpointCount(); i++) { - uint8_t endpoint = emberAfEndpointFromIndex(i); + EndpointId endpoint = emberAfEndpointFromIndex(i); if (!emberAfEndpointIndexIsEnabled(i) || !emberAfContainsClusterWithMfgCode(endpoint, curCmd.apsFrame->clusterId, curCmd.mfgCode)) { @@ -1193,7 +1195,7 @@ bool emberAfIsTypeSigned(EmberAfAttributeType dataType) return (dataType >= ZCL_INT8S_ATTRIBUTE_TYPE && dataType <= ZCL_INT64S_ATTRIBUTE_TYPE); } -EmberStatus emberAfEndpointEventControlSetInactive(EmberEventControl * controls, uint8_t endpoint) +EmberStatus emberAfEndpointEventControlSetInactive(EmberEventControl * controls, EndpointId endpoint) { uint8_t index = emberAfIndexFromEndpoint(endpoint); if (index == 0xFF) @@ -1204,13 +1206,13 @@ EmberStatus emberAfEndpointEventControlSetInactive(EmberEventControl * controls, return EMBER_SUCCESS; } -bool emberAfEndpointEventControlGetActive(EmberEventControl * controls, uint8_t endpoint) +bool emberAfEndpointEventControlGetActive(EmberEventControl * controls, EndpointId endpoint) { uint8_t index = emberAfIndexFromEndpoint(endpoint); return (index != 0xFF && emberEventControlGetActive(&controls[index])); } -EmberStatus emberAfEndpointEventControlSetActive(EmberEventControl * controls, uint8_t endpoint) +EmberStatus emberAfEndpointEventControlSetActive(EmberEventControl * controls, EndpointId endpoint) { uint8_t index = emberAfIndexFromEndpoint(endpoint); if (index == 0xFF) From 56206eb16a898b935167a613b362fea4c7503602 Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Fri, 6 Nov 2020 11:22:44 -0500 Subject: [PATCH 007/234] Simplify Securepairing send message: (#3656) - do not encode and decode a header (pass in header as is) - SecureMessage sending is never used during the pairing flow - Code should be shorter, less encode/decode --- src/transport/RendezvousSession.cpp | 52 ++----------------- src/transport/RendezvousSession.h | 3 +- src/transport/SecurePairingSession.cpp | 19 +------ src/transport/SecurePairingSession.h | 9 +++- .../tests/TestSecurePairingSession.cpp | 14 +---- 5 files changed, 17 insertions(+), 80 deletions(-) diff --git a/src/transport/RendezvousSession.cpp b/src/transport/RendezvousSession.cpp index 502b4623e3c31b..838d4d0c5603a9 100644 --- a/src/transport/RendezvousSession.cpp +++ b/src/transport/RendezvousSession.cpp @@ -79,58 +79,16 @@ RendezvousSession::~RendezvousSession() mDelegate = nullptr; } -CHIP_ERROR RendezvousSession::SendMessage(System::PacketBuffer * msgBuf) +CHIP_ERROR RendezvousSession::SendPairingMessage(const PacketHeader & header, Header::Flags payloadFlags, + System::PacketBuffer * msgBuf) { - CHIP_ERROR err = CHIP_NO_ERROR; - - switch (mCurrentState) + if (mCurrentState != State::kSecurePairing) { - case State::kSecurePairing: - err = SendPairingMessage(msgBuf); - break; - - case State::kNetworkProvisioning: - err = SendSecureMessage(Protocols::kProtocol_NetworkProvisioning, NetworkProvisioning::MsgTypes::kWiFiAssociationRequest, - msgBuf); - break; - - default: System::PacketBuffer::Free(msgBuf); - err = CHIP_ERROR_INCORRECT_STATE; - break; - }; - - SuccessOrExit(err); - -exit: - if (err != CHIP_NO_ERROR) - { - OnRendezvousError(err); + return CHIP_ERROR_INCORRECT_STATE; } - return err; -} - -CHIP_ERROR RendezvousSession::SendPairingMessage(System::PacketBuffer * msgBuf) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - PacketHeader header; - uint16_t headerSize = 0; - VerifyOrExit(msgBuf != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(msgBuf->Next() == nullptr, err = CHIP_ERROR_INVALID_MESSAGE_LENGTH); - - err = header.Decode(msgBuf->Start(), msgBuf->DataLength(), &headerSize); - SuccessOrExit(err); - - msgBuf->ConsumeHead(headerSize); - err = mTransport->SendMessage(header, Header::Flags(), Transport::PeerAddress::BLE(), msgBuf); - msgBuf = nullptr; - SuccessOrExit(err); - -exit: - if (msgBuf) - System::PacketBuffer::Free(msgBuf); - return err; + return mTransport->SendMessage(header, payloadFlags, Transport::PeerAddress::BLE(), msgBuf); } CHIP_ERROR RendezvousSession::SendSecureMessage(Protocols::CHIPProtocolId protocol, uint8_t msgType, System::PacketBuffer * msgBuf) diff --git a/src/transport/RendezvousSession.h b/src/transport/RendezvousSession.h index 84ac11c7ab60ca..3a0b71870cb570 100644 --- a/src/transport/RendezvousSession.h +++ b/src/transport/RendezvousSession.h @@ -92,7 +92,7 @@ class RendezvousSession : public SecurePairingSessionDelegate, SecurePairingSession & GetPairingSession() { return mPairingSession; } //////////// SecurePairingSessionDelegate Implementation /////////////// - CHIP_ERROR SendMessage(System::PacketBuffer * msgBuf) override; + CHIP_ERROR SendPairingMessage(const PacketHeader & header, Header::Flags payloadFlags, System::PacketBuffer * msgBuf) override; void OnPairingError(CHIP_ERROR err) override; void OnPairingComplete() override; @@ -122,7 +122,6 @@ class RendezvousSession : public SecurePairingSessionDelegate, const Inet::IPAddress & GetIPAddress() const { return mNetworkProvision.GetIPAddress(); } private: - CHIP_ERROR SendPairingMessage(System::PacketBuffer * msgBug); CHIP_ERROR HandlePairingMessage(System::PacketBuffer * msgBug); CHIP_ERROR Pair(Optional nodeId, uint32_t setupPINCode); CHIP_ERROR WaitForPairing(Optional nodeId, uint32_t setupPINCode); diff --git a/src/transport/SecurePairingSession.cpp b/src/transport/SecurePairingSession.cpp index 3868da7a779fc0..be50e9f07b3056 100644 --- a/src/transport/SecurePairingSession.cpp +++ b/src/transport/SecurePairingSession.cpp @@ -173,13 +173,8 @@ CHIP_ERROR SecurePairingSession::AttachHeaderAndSend(uint8_t msgType, System::Pa { CHIP_ERROR err = CHIP_NO_ERROR; - PacketHeader packetHeader; PayloadHeader payloadHeader; - packetHeader - .SetSourceNodeId(mLocalNodeId) // - .SetEncryptionKeyID(mLocalKeyId); - payloadHeader .SetMessageType(msgType) // .SetProtocolID(Protocols::kProtocol_SecurityChannel); @@ -194,18 +189,8 @@ CHIP_ERROR SecurePairingSession::AttachHeaderAndSend(uint8_t msgType, System::Pa SuccessOrExit(err); VerifyOrExit(headerSize == actualEncodedHeaderSize, err = CHIP_ERROR_INTERNAL); - headerSize = packetHeader.EncodeSizeBytes(); - actualEncodedHeaderSize = 0; - - VerifyOrExit(msgBuf->EnsureReservedSize(headerSize), err = CHIP_ERROR_NO_MEMORY); - - msgBuf->SetStart(msgBuf->Start() - headerSize); - err = - packetHeader.Encode(msgBuf->Start(), msgBuf->DataLength(), &actualEncodedHeaderSize, payloadHeader.GetEncodePacketFlags()); - SuccessOrExit(err); - VerifyOrExit(headerSize == actualEncodedHeaderSize, err = CHIP_ERROR_INTERNAL); - - err = mDelegate->SendMessage(msgBuf); + err = mDelegate->SendPairingMessage(PacketHeader().SetSourceNodeId(mLocalNodeId).SetEncryptionKeyID(mLocalKeyId), + payloadHeader.GetEncodePacketFlags(), msgBuf); msgBuf = nullptr; SuccessOrExit(err); diff --git a/src/transport/SecurePairingSession.h b/src/transport/SecurePairingSession.h index 3e12ce250f5e16..dfe3857c5d6863 100644 --- a/src/transport/SecurePairingSession.h +++ b/src/transport/SecurePairingSession.h @@ -45,10 +45,15 @@ class DLL_EXPORT SecurePairingSessionDelegate * @brief * Called when pairing session generates a new message that should be sent to peer. * - * @param msgBuf the new message that should be sent to the peer + * @param header the message header for the sent message + * @param payloadFlags payload encoding flags + * @param msgBuf the raw data for the message being sent * @return CHIP_ERROR Error thrown when sending the message */ - virtual CHIP_ERROR SendMessage(System::PacketBuffer * msgBuf) { return CHIP_NO_ERROR; } + virtual CHIP_ERROR SendPairingMessage(const PacketHeader & header, Header::Flags payloadFlags, System::PacketBuffer * msgBuf) + { + return CHIP_ERROR_NOT_IMPLEMENTED; + } /** * @brief diff --git a/src/transport/tests/TestSecurePairingSession.cpp b/src/transport/tests/TestSecurePairingSession.cpp index 8cf8c16d542ff3..d50df175f8e164 100644 --- a/src/transport/tests/TestSecurePairingSession.cpp +++ b/src/transport/tests/TestSecurePairingSession.cpp @@ -39,20 +39,10 @@ using namespace chip; class TestSecurePairingDelegate : public SecurePairingSessionDelegate { public: - CHIP_ERROR SendMessage(System::PacketBuffer * msgBuf) override + CHIP_ERROR SendPairingMessage(const PacketHeader & header, Header::Flags payloadFlags, System::PacketBuffer * msgBuf) override { mNumMessageSend++; - if (peer != nullptr) - { - PacketHeader hdr; - uint16_t headerSize = 0; - - hdr.Decode(msgBuf->Start(), msgBuf->DataLength(), &headerSize); - msgBuf->ConsumeHead(headerSize); - - return peer->HandlePeerMessage(hdr, msgBuf); - } - return mMessageSendError; + return (peer != nullptr) ? peer->HandlePeerMessage(header, msgBuf) : mMessageSendError; } void OnPairingError(CHIP_ERROR error) override { mNumPairingErrors++; } From 73870e97b3c64234d3d797199498c875bcaac35c Mon Sep 17 00:00:00 2001 From: Hrishikesh Dhayagude Date: Fri, 6 Nov 2020 21:55:15 +0530 Subject: [PATCH 008/234] ESP32: Fix PluginBasicResetToFactoryDefaultsCallback to call the correct API (#3650) --- examples/all-clusters-app/esp32/main/DeviceCallbacks.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/all-clusters-app/esp32/main/DeviceCallbacks.cpp b/examples/all-clusters-app/esp32/main/DeviceCallbacks.cpp index 701c71c831089e..a8cf0c603f8a5b 100644 --- a/examples/all-clusters-app/esp32/main/DeviceCallbacks.cpp +++ b/examples/all-clusters-app/esp32/main/DeviceCallbacks.cpp @@ -170,7 +170,7 @@ void DeviceCallbacks::PluginBasicResetToFactoryDefaultsCallback(uint8_t endpoint VerifyOrExit(endpointId == 1, ESP_LOGE(TAG, "Unexpected EndPoint ID: `0x%02x'", endpointId)); - ConnectivityMgr().ClearWiFiStationProvision(); + ConfigurationMgr().InitiateFactoryReset(); exit: return; From 69dcdb548d4e3ac9f0f7f6777db34c65246c66f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20Kr=C3=B3lik?= <66667989+Damian-Nordic@users.noreply.github.com> Date: Fri, 6 Nov 2020 17:25:34 +0100 Subject: [PATCH 009/234] [nRF Connect] Update README - Building with Docker (#3629) The instruction for building nRF Connect examples using a Docker container was changed recently to use a non-root user for security and usability reasons. The Docker image, however, used a fixed user ID, 1000, which doesn't necessarily match the current user ID. As a result a user outside the container might still not be able to remove files created in the container. Pass the current user ID to the Docker container by an environmental variable handled in the container so that the container session is run as the current user. --- examples/lighting-app/nrfconnect/README.md | 5 ++++- examples/lock-app/nrfconnect/README.md | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/examples/lighting-app/nrfconnect/README.md b/examples/lighting-app/nrfconnect/README.md index c73231a36aa442..d9989983186983 100644 --- a/examples/lighting-app/nrfconnect/README.md +++ b/examples/lighting-app/nrfconnect/README.md @@ -118,7 +118,8 @@ container: $ mkdir ~/nrfconnect $ mkdir ~/connectedhomeip $ docker pull nordicsemi/nrfconnect-chip - $ docker run --rm -it -v ~/nrfconnect:/var/ncs -v ~/connectedhomeip:/var/chip -v /dev/bus/usb:/dev/bus/usb --device-cgroup-rule "c 189:* rmw" nordicsemi/nrfconnect-chip + $ docker run --rm -it -e RUNAS=$(id -u) -v ~/nrfconnect:/var/ncs -v ~/connectedhomeip:/var/chip \ + -v /dev/bus/usb:/dev/bus/usb --device-cgroup-rule "c 189:* rmw" nordicsemi/nrfconnect-chip > **Note**: > @@ -132,6 +133,8 @@ container: > connected to your computer such as the nRF52840 DK. > - `--rm` flag can be omitted if you don't want the container to be > auto-removed when you exit the container shell session. +> - `-e RUNAS=$(id -u)` is needed to start the container session as the +> current user instead of root. If you use the container for the first time and you don't have nRF Connect SDK and CHIP sources downloaded yet, run `setup` command in the container to pull diff --git a/examples/lock-app/nrfconnect/README.md b/examples/lock-app/nrfconnect/README.md index 7adb66ac84fe07..7555c1b10ad254 100644 --- a/examples/lock-app/nrfconnect/README.md +++ b/examples/lock-app/nrfconnect/README.md @@ -122,7 +122,8 @@ container: $ mkdir ~/nrfconnect $ mkdir ~/connectedhomeip $ docker pull nordicsemi/nrfconnect-chip - $ docker run --rm -it -v ~/nrfconnect:/var/ncs -v ~/connectedhomeip:/var/chip -v /dev/bus/usb:/dev/bus/usb --device-cgroup-rule "c 189:* rmw" nordicsemi/nrfconnect-chip + $ docker run --rm -it -e RUNAS=$(id -u) -v ~/nrfconnect:/var/ncs -v ~/connectedhomeip:/var/chip \ + -v /dev/bus/usb:/dev/bus/usb --device-cgroup-rule "c 189:* rmw" nordicsemi/nrfconnect-chip > **Note**: > @@ -136,6 +137,8 @@ container: > connected to your computer such as the nRF52840 DK. > - `--rm` flag can be omitted if you don't want the container to be > auto-removed when you exit the container shell session. +> - `-e RUNAS=$(id -u)` is needed to start the container session as the +> current user instead of root. If you use the container for the first time and you don't have nRF Connect SDK and CHIP sources downloaded yet, run `setup` command in the container to pull From 8ec55675cd4de58ac422f0c1e28fed38d567695d Mon Sep 17 00:00:00 2001 From: Michael Spang Date: Fri, 6 Nov 2020 12:10:29 -0500 Subject: [PATCH 010/234] Update docker images to 0.4.16 (#3710) Re-add JDK to chip-build. This is needed by VS code. --- .devcontainer/devcontainer.json | 2 +- .github/workflows/android.yaml | 2 +- .github/workflows/bloat_check.yaml | 2 +- .github/workflows/build.yaml | 2 +- .github/workflows/examples-efr32.yaml | 2 +- .github/workflows/examples-esp32.yaml | 2 +- .github/workflows/examples-linux-standalone.yaml | 2 +- .github/workflows/examples-nrfconnect.yaml | 2 +- .github/workflows/examples-qpg6100.yaml | 2 +- .github/workflows/qemu.yaml | 2 +- .github/workflows/unit_integration_test.yaml | 2 +- integrations/docker/images/chip-build-android/version | 2 +- integrations/docker/images/chip-build-cirque/version | 2 +- integrations/docker/images/chip-build/Dockerfile | 1 + integrations/docker/images/chip-build/version | 2 +- src/test_driver/happy/README.md | 2 +- 16 files changed, 16 insertions(+), 15 deletions(-) mode change 100644 => 120000 integrations/docker/images/chip-build-android/version mode change 100644 => 120000 integrations/docker/images/chip-build-cirque/version diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 44036a91d8abbe..fa20ae8e593951 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -13,7 +13,7 @@ "dockerfile": "Dockerfile", "args": { // "BUILD_VERSION": "$(cat integrations/docker/images/chip-build/version)" // trying to get this to work - "BUILD_VERSION": "0.4.11" + "BUILD_VERSION": "0.4.16" } }, "remoteUser": "vscode", diff --git a/.github/workflows/android.yaml b/.github/workflows/android.yaml index beb1bfc0c14ca4..9b4c27c8e3d887 100644 --- a/.github/workflows/android.yaml +++ b/.github/workflows/android.yaml @@ -34,7 +34,7 @@ jobs: runs-on: ubuntu-latest container: - image: connectedhomeip/chip-build-android:0.4.13 + image: connectedhomeip/chip-build-android:0.4.16 volumes: - "/tmp/log_output:/tmp/test_logs" diff --git a/.github/workflows/bloat_check.yaml b/.github/workflows/bloat_check.yaml index 5d989b22e6f560..a52a77fa04c5f5 100644 --- a/.github/workflows/bloat_check.yaml +++ b/.github/workflows/bloat_check.yaml @@ -24,7 +24,7 @@ jobs: runs-on: ubuntu-latest container: - image: connectedhomeip/chip-build:0.4.12 + image: connectedhomeip/chip-build:0.4.16 steps: - name: Checkout diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index fc56356b868a14..52cdfb408d3c05 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -34,7 +34,7 @@ jobs: runs-on: ubuntu-latest container: - image: connectedhomeip/chip-build:0.4.12 + image: connectedhomeip/chip-build:0.4.16 volumes: - "/tmp/log_output:/tmp/test_logs" options: diff --git a/.github/workflows/examples-efr32.yaml b/.github/workflows/examples-efr32.yaml index 276d6939f26420..0e554bbc67579e 100644 --- a/.github/workflows/examples-efr32.yaml +++ b/.github/workflows/examples-efr32.yaml @@ -29,7 +29,7 @@ jobs: runs-on: ubuntu-latest container: - image: connectedhomeip/chip-build-efr32:0.4.11 + image: connectedhomeip/chip-build-efr32:0.4.16 volumes: - "/tmp/bloat_reports:/tmp/bloat_reports" - "/tmp/output_binaries:/tmp/output_binaries" diff --git a/.github/workflows/examples-esp32.yaml b/.github/workflows/examples-esp32.yaml index cc51698bcd9436..c7cb3af772112d 100644 --- a/.github/workflows/examples-esp32.yaml +++ b/.github/workflows/examples-esp32.yaml @@ -29,7 +29,7 @@ jobs: runs-on: ubuntu-latest container: - image: connectedhomeip/chip-build-esp32:0.4.12 + image: connectedhomeip/chip-build-esp32:0.4.16 volumes: - "/tmp/bloat_reports:/tmp/bloat_reports" - "/tmp/output_binaries:/tmp/output_binaries" diff --git a/.github/workflows/examples-linux-standalone.yaml b/.github/workflows/examples-linux-standalone.yaml index ba885245dc1776..ed2382fd869949 100644 --- a/.github/workflows/examples-linux-standalone.yaml +++ b/.github/workflows/examples-linux-standalone.yaml @@ -31,7 +31,7 @@ jobs: runs-on: ubuntu-latest container: - image: connectedhomeip/chip-build:0.4.12 + image: connectedhomeip/chip-build:0.4.16 volumes: - "/tmp/bloat_reports:/tmp/bloat_reports" - "/tmp/output_binaries:/tmp/output_binaries" diff --git a/.github/workflows/examples-nrfconnect.yaml b/.github/workflows/examples-nrfconnect.yaml index afc34e33ba2d8c..dce9b2fda4e535 100644 --- a/.github/workflows/examples-nrfconnect.yaml +++ b/.github/workflows/examples-nrfconnect.yaml @@ -27,7 +27,7 @@ jobs: runs-on: ubuntu-latest container: - image: connectedhomeip/chip-build-nrf-platform:0.4.12 + image: connectedhomeip/chip-build-nrf-platform:0.4.16 volumes: - "/tmp/bloat_reports:/tmp/bloat_reports" - "/tmp/output_binaries:/tmp/output_binaries" diff --git a/.github/workflows/examples-qpg6100.yaml b/.github/workflows/examples-qpg6100.yaml index dc9532a29f180a..990f07b7fb4f9c 100644 --- a/.github/workflows/examples-qpg6100.yaml +++ b/.github/workflows/examples-qpg6100.yaml @@ -27,7 +27,7 @@ jobs: runs-on: ubuntu-latest container: - image: connectedhomeip/chip-build:0.4.12 + image: connectedhomeip/chip-build:0.4.16 volumes: - "/tmp/bloat_reports:/tmp/bloat_reports" - "/tmp/output_binaries:/tmp/output_binaries" diff --git a/.github/workflows/qemu.yaml b/.github/workflows/qemu.yaml index d299107880ffa3..b320f618544df2 100644 --- a/.github/workflows/qemu.yaml +++ b/.github/workflows/qemu.yaml @@ -28,7 +28,7 @@ jobs: runs-on: ubuntu-latest container: - image: connectedhomeip/chip-build-esp32-qemu:0.4.12 + image: connectedhomeip/chip-build-esp32-qemu:0.4.16 volumes: - "/tmp/log_output:/tmp/test_logs" diff --git a/.github/workflows/unit_integration_test.yaml b/.github/workflows/unit_integration_test.yaml index dd532dcb50d522..020fe8fba5e6c4 100644 --- a/.github/workflows/unit_integration_test.yaml +++ b/.github/workflows/unit_integration_test.yaml @@ -34,7 +34,7 @@ jobs: runs-on: ubuntu-latest container: - image: connectedhomeip/chip-build:0.4.12 + image: connectedhomeip/chip-build:0.4.16 volumes: - "/tmp/log_output:/tmp/test_logs" - "/tmp/happy_test_logs:/tmp/happy_test_logs" diff --git a/integrations/docker/images/chip-build-android/version b/integrations/docker/images/chip-build-android/version deleted file mode 100644 index 1f77169993b921..00000000000000 --- a/integrations/docker/images/chip-build-android/version +++ /dev/null @@ -1 +0,0 @@ -0.4.13 diff --git a/integrations/docker/images/chip-build-android/version b/integrations/docker/images/chip-build-android/version new file mode 120000 index 00000000000000..a4280acd348e7f --- /dev/null +++ b/integrations/docker/images/chip-build-android/version @@ -0,0 +1 @@ +../chip-build/version \ No newline at end of file diff --git a/integrations/docker/images/chip-build-cirque/version b/integrations/docker/images/chip-build-cirque/version deleted file mode 100644 index 75274d8329449c..00000000000000 --- a/integrations/docker/images/chip-build-cirque/version +++ /dev/null @@ -1 +0,0 @@ -0.4.12 diff --git a/integrations/docker/images/chip-build-cirque/version b/integrations/docker/images/chip-build-cirque/version new file mode 120000 index 00000000000000..a4280acd348e7f --- /dev/null +++ b/integrations/docker/images/chip-build-cirque/version @@ -0,0 +1 @@ +../chip-build/version \ No newline at end of file diff --git a/integrations/docker/images/chip-build/Dockerfile b/integrations/docker/images/chip-build/Dockerfile index 8cb8384dd132d5..91ba51183f4dd5 100644 --- a/integrations/docker/images/chip-build/Dockerfile +++ b/integrations/docker/images/chip-build/Dockerfile @@ -48,6 +48,7 @@ RUN set -x \ make \ net-tools \ ninja-build \ + openjdk-8-jdk \ pkg-config \ python3 \ python3-dev \ diff --git a/integrations/docker/images/chip-build/version b/integrations/docker/images/chip-build/version index 489c893e27810d..5745cc7b116c85 100644 --- a/integrations/docker/images/chip-build/version +++ b/integrations/docker/images/chip-build/version @@ -1 +1 @@ -0.4.14 +0.4.16 diff --git a/src/test_driver/happy/README.md b/src/test_driver/happy/README.md index 097890c66629c4..0142224d652a19 100644 --- a/src/test_driver/happy/README.md +++ b/src/test_driver/happy/README.md @@ -18,7 +18,7 @@ --entrypoint /bin/bash \ --sysctl "net.ipv6.conf.all.disable_ipv6=0 net.ipv4.conf.all.forwarding=1 net.ipv6.conf.all.forwarding=1" \ -it --mount type=bind,source=`pwd`,target=`pwd` \ - connectedhomeip/chip-build:0.4.11 + connectedhomeip/chip-build:0.4.16 Mount your checkout to the same path as your local path avoids errors during bootstrap. From a18d118d0a9f9d20a5c3ed548c11dcfdb8010744 Mon Sep 17 00:00:00 2001 From: Timothy Maes <63657433+tima-q@users.noreply.github.com> Date: Fri, 6 Nov 2020 20:41:45 +0100 Subject: [PATCH 011/234] * Moving CHIPProjectConfig.h to a /platform (#3632) * Adding qpg6100 streamer implementation ** Updating qpg_sdk submodule * Adding qpg6100 shell build files * Adding qpg6100 shell build to github workflow * fix flasher script - coping calling from different path --- .github/workflows/examples-qpg6100.yaml | 8 ++ examples/lock-app/qpg6100/BUILD.gn | 7 +- .../project_include}/CHIPProjectConfig.h | 0 .../util/streamer/streamer_qpg6100.cpp | 63 +++++++++++ examples/shell/qpg6100/.gn | 26 +++++ examples/shell/qpg6100/BUILD.gn | 85 +++++++++++++++ examples/shell/qpg6100/README.md | 9 ++ examples/shell/qpg6100/args.gni | 18 ++++ examples/shell/qpg6100/build | 1 + examples/shell/qpg6100/build_overrides | 1 + examples/shell/qpg6100/main.cpp | 100 ++++++++++++++++++ .../shell/qpg6100/third_party/connectedhomeip | 1 + scripts/flashing/qpg6100_firmware_utils.py | 2 +- third_party/qpg_sdk/repo | 2 +- 14 files changed, 317 insertions(+), 6 deletions(-) rename examples/{lock-app/qpg6100/include => platform/qpg6100/project_include}/CHIPProjectConfig.h (100%) create mode 100644 examples/platform/qpg6100/util/streamer/streamer_qpg6100.cpp create mode 100644 examples/shell/qpg6100/.gn create mode 100644 examples/shell/qpg6100/BUILD.gn create mode 100644 examples/shell/qpg6100/README.md create mode 100644 examples/shell/qpg6100/args.gni create mode 120000 examples/shell/qpg6100/build create mode 120000 examples/shell/qpg6100/build_overrides create mode 100644 examples/shell/qpg6100/main.cpp create mode 120000 examples/shell/qpg6100/third_party/connectedhomeip diff --git a/.github/workflows/examples-qpg6100.yaml b/.github/workflows/examples-qpg6100.yaml index 990f07b7fb4f9c..62c702b9690ced 100644 --- a/.github/workflows/examples-qpg6100.yaml +++ b/.github/workflows/examples-qpg6100.yaml @@ -46,6 +46,9 @@ jobs: - name: Build example QPG6100 Lock App run: scripts/examples/gn_build_example.sh examples/lock-app/qpg6100 out/lock_app_debug + - name: Build QPG6100 shell App + run: scripts/examples/gn_build_example.sh + examples/shell/qpg6100 out/shell_app - name: Binary artifact suffix id: outsuffix uses: haya14busa/action-cond@v1.0.0 @@ -61,6 +64,11 @@ jobs: steps.outsuffix.outputs.value }} path: | out/lock_app_debug/chip-qpg6100-lock-example.out + out/shell_app/shell-qpg6100.out + - name: Show tree + run: find . + - name: Remove third_party binaries for CodeQL Analysis + run: find out -type d -name "third_party" -exec rm -rf {} + - name: Perform CodeQL Analysis if: ${{ github.event_name == 'push' }} uses: github/codeql-action/analyze@v1 diff --git a/examples/lock-app/qpg6100/BUILD.gn b/examples/lock-app/qpg6100/BUILD.gn index 0989269b2a52c5..182867fe19df3d 100644 --- a/examples/lock-app/qpg6100/BUILD.gn +++ b/examples/lock-app/qpg6100/BUILD.gn @@ -26,11 +26,10 @@ examples_plat_dir = "${chip_root}/examples/platform/qpg6100" qpg6100_sdk("sdk") { include_dirs = [ "${chip_root}/src/platform/qpg6100", - "${qpg6100_project_dir}/include/", - "${qpg6100_project_dir}/src/", + "${examples_plat_dir}/project_include", ] - sources = [ "${qpg6100_project_dir}/include/CHIPProjectConfig.h" ] + sources = [ "${examples_plat_dir}/project_include/CHIPProjectConfig.h" ] defines = [] if (is_debug) { @@ -59,7 +58,7 @@ qpg6100_executable("lock_app") { ] include_dirs += [ - "${qpg6100_project_dir}/include/", + "${qpg6100_project_dir}/src/", "${chip_root}/src/app/util", "${examples_plat_dir}/", ] diff --git a/examples/lock-app/qpg6100/include/CHIPProjectConfig.h b/examples/platform/qpg6100/project_include/CHIPProjectConfig.h similarity index 100% rename from examples/lock-app/qpg6100/include/CHIPProjectConfig.h rename to examples/platform/qpg6100/project_include/CHIPProjectConfig.h diff --git a/examples/platform/qpg6100/util/streamer/streamer_qpg6100.cpp b/examples/platform/qpg6100/util/streamer/streamer_qpg6100.cpp new file mode 100644 index 00000000000000..7ac43152c00659 --- /dev/null +++ b/examples/platform/qpg6100/util/streamer/streamer_qpg6100.cpp @@ -0,0 +1,63 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Source implementation of an input / output stream for QPG6100 targets. + */ + +#include + +#ifdef QPG6100_SHELL_STREAMER + +#include "qvCHIP.h" + +namespace chip { +namespace Shell { + +int streamer_qpg6100_init(streamer_t * streamer) +{ + qvCHIP_UartInit(); + return 0; +} + +int streamer_qpg6100_read(streamer_t * streamer, char * buf, size_t len) +{ + return qvCHIP_UartReadRxData(len, buf); +} + +int streamer_qpg6100_write(streamer_t * streamer, const char * buf, size_t len) +{ + qvCHIP_UartTxData(len, buf); + return len; +} + +static streamer_t streamer_qpg6100 = { + .init_cb = streamer_qpg6100_init, + .read_cb = streamer_qpg6100_read, + .write_cb = streamer_qpg6100_write, +}; + +streamer_t * streamer_get(void) +{ + return &streamer_qpg6100; +} + +} // namespace Shell +} // namespace chip + +#endif //#ifdef QPG6100_SHELL_STREAMER diff --git a/examples/shell/qpg6100/.gn b/examples/shell/qpg6100/.gn new file mode 100644 index 00000000000000..89dc9a6fcb5f6c --- /dev/null +++ b/examples/shell/qpg6100/.gn @@ -0,0 +1,26 @@ +# Copyright (c) 2020 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# The location of the build configuration file. +buildconfig = "//build/config/BUILDCONFIG.gn" + +# CHIP uses angle bracket includes. +check_system_includes = true + +default_args = { + target_cpu = "arm" + target_os = "freertos" + + import("//args.gni") +} diff --git a/examples/shell/qpg6100/BUILD.gn b/examples/shell/qpg6100/BUILD.gn new file mode 100644 index 00000000000000..636a54591be83d --- /dev/null +++ b/examples/shell/qpg6100/BUILD.gn @@ -0,0 +1,85 @@ +# Copyright (c) 2020 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/config/defaults.gni") +import("//build_overrides/chip.gni") +import("//build_overrides/qpg6100_sdk.gni") +import("${qpg6100_sdk_build_root}/qpg6100_executable.gni") +import("${qpg6100_sdk_build_root}/qpg6100_sdk.gni") + +assert(current_os == "freertos") + +examples_plat_dir = "${chip_root}/examples/platform/qpg6100" +project_dir = "${chip_root}/examples/shell" + +qpg6100_sdk("sdk") { + include_dirs = [ + "${chip_root}/src/platform/qpg6100", + "${examples_plat_dir}/project_include", + "${chip_root}/src/app/util", + ] + + sources = [ "${examples_plat_dir}/project_include/CHIPProjectConfig.h" ] + + defines = [] + if (is_debug) { + defines += [ "BUILD_RELEASE=0" ] + } else { + defines += [ "BUILD_RELEASE=1" ] + } +} + +qpg6100_executable("shell_qpg6100") { + include_dirs = [] + defines = [] + output_name = "shell-qpg6100.out" + + public_deps = [ + ":sdk", + "${chip_root}/examples/shell/shell_common", + "${chip_root}/src/lib", + "${chip_root}/src/lib/shell", + "${chip_root}/src/setup_payload", + + # OpenThread to be enabled + # https://github.com/project-chip/connectedhomeip/issues/293 + ] + + include_dirs += [ "${chip_root}/src/app/util" ] + + sources = [ + "${examples_plat_dir}/project_include/CHIPProjectConfig.h", + "${examples_plat_dir}/util/streamer/streamer_qpg6100.cpp", + "${project_dir}/test_identity.cpp", + "main.cpp", + ] + + output_dir = root_out_dir + + ldscript = "${qpg6100_sdk_root}/qpg6100/ldscripts/chip-qpg6100-example.ld" + + ldflags = [ "-T" + rebase_path(ldscript, root_build_dir) ] + defines = [ + "QPG6100_SHELL_STREAMER", + "SHELL_STREAMER_APP_SPECIFIC", + ] +} + +group("qpg6100") { + deps = [ ":shell_qpg6100" ] +} + +group("default") { + deps = [ ":qpg6100" ] +} diff --git a/examples/shell/qpg6100/README.md b/examples/shell/qpg6100/README.md new file mode 100644 index 00000000000000..3519f4d0303885 --- /dev/null +++ b/examples/shell/qpg6100/README.md @@ -0,0 +1,9 @@ +# CHIP QPG6100 Shell Application + +A [chip-shell](../README.md) project for the Qorvo QPG6100 development kit. + +## Building + +The Shell Application builds and flashes like any other QPG6100 example +application. Further information can be found in +[this](../../lock-app/qpg6100/README.md) README. diff --git a/examples/shell/qpg6100/args.gni b/examples/shell/qpg6100/args.gni new file mode 100644 index 00000000000000..38f955bb59c89b --- /dev/null +++ b/examples/shell/qpg6100/args.gni @@ -0,0 +1,18 @@ +# Copyright (c) 2020 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/chip.gni") +import("${chip_root}/examples/platform/qpg6100/args.gni") + +qpg6100_sdk_target = get_label_info(":sdk", "label_no_toolchain") diff --git a/examples/shell/qpg6100/build b/examples/shell/qpg6100/build new file mode 120000 index 00000000000000..d56ed62ae4d1ff --- /dev/null +++ b/examples/shell/qpg6100/build @@ -0,0 +1 @@ +third_party/connectedhomeip/build \ No newline at end of file diff --git a/examples/shell/qpg6100/build_overrides b/examples/shell/qpg6100/build_overrides new file mode 120000 index 00000000000000..e578e73312ebd1 --- /dev/null +++ b/examples/shell/qpg6100/build_overrides @@ -0,0 +1 @@ +../../build_overrides \ No newline at end of file diff --git a/examples/shell/qpg6100/main.cpp b/examples/shell/qpg6100/main.cpp new file mode 100644 index 00000000000000..b11d5e5368fa62 --- /dev/null +++ b/examples/shell/qpg6100/main.cpp @@ -0,0 +1,100 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "FreeRTOS.h" +#include "task.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "qvCHIP.h" + +#if CHIP_ENABLE_OPENTHREAD +extern "C" { +#include +} +#endif // CHIP_ENABLE_OPENTHREAD + +using namespace chip; +using namespace chip::Shell; + +namespace { + +const size_t kShellTaskStackSize = 2048; +const int kShellTaskPriority = 1; +TaskHandle_t sShellTaskHandle; + +void ShellCLIMain(void * pvParameter) +{ + // Initialize the default streamer that was linked. + const int rc = streamer_init(streamer_get()); + + if (rc != 0) + { + ChipLogError(Shell, "Streamer initialization failed: %d", rc); + return; + } + + ChipLogDetail(Shell, "Initializing CHIP shell commands", rc); + + cmd_device_init(); + cmd_base64_init(); + cmd_misc_init(); + cmd_btp_init(); + cmd_otcli_init(); + + ChipLogDetail(Shell, "Run CHIP shell Task", rc); + + shell_task(nullptr); +} + +} // namespace + +int StartShellTask(void) +{ + int ret = 0; + + // Start Shell task. + if (xTaskCreate(ShellCLIMain, "SHELL", kShellTaskStackSize / sizeof(StackType_t), NULL, kShellTaskPriority, + &sShellTaskHandle) != pdPASS) + { + ret = -1; + } + + return ret; +} + +int main(void) +{ + /* Initialize platform */ + qvCHIP_init(); + + /* Launch shell task */ + StartShellTask(); + + /* Start FreeRTOS */ + vTaskStartScheduler(); + return 0; +} diff --git a/examples/shell/qpg6100/third_party/connectedhomeip b/examples/shell/qpg6100/third_party/connectedhomeip new file mode 120000 index 00000000000000..c866b86874994d --- /dev/null +++ b/examples/shell/qpg6100/third_party/connectedhomeip @@ -0,0 +1 @@ +../../../.. \ No newline at end of file diff --git a/scripts/flashing/qpg6100_firmware_utils.py b/scripts/flashing/qpg6100_firmware_utils.py index 821ccd892f693f..0d04baa61d49f4 100644 --- a/scripts/flashing/qpg6100_firmware_utils.py +++ b/scripts/flashing/qpg6100_firmware_utils.py @@ -91,7 +91,7 @@ def flash(self, image): self.err = 3 return self - shutil.copyfile(image, os.path.join(self.option.drive, image)) + shutil.copyfile(image, os.path.join(self.option.drive, os.path.basename(image))) return self def reset(self): diff --git a/third_party/qpg_sdk/repo b/third_party/qpg_sdk/repo index 675a0be77f5071..819615564704d9 160000 --- a/third_party/qpg_sdk/repo +++ b/third_party/qpg_sdk/repo @@ -1 +1 @@ -Subproject commit 675a0be77f5071b378e4980cb0c1642e5043e08e +Subproject commit 819615564704d98d656296214cdc63fbe47e2f20 From 4711189ff0fd327d9010a0da35646881d8d84a5c Mon Sep 17 00:00:00 2001 From: Vivien Nicolas Date: Fri, 6 Nov 2020 22:07:18 +0100 Subject: [PATCH 012/234] Remove *-cli.c files in src/app/clusters and some leftovers (#3688) --- .../ias-zone-client/ias-zone-client-cli.c | 97 -------- .../ias-zone-server/ias-zone-server-test.h | 64 ----- .../clusters/messaging-client/callbacks.info | 45 ---- src/app/clusters/messaging-client/cli.xml | 26 -- .../messaging-client/messaging-client-cli.c | 75 ------ .../messaging-client/plugin.properties | 34 --- src/app/clusters/messaging-server/cli.xml | 119 ---------- .../messaging-server/messaging-server-cli.c | 224 ------------------ .../messaging-server/plugin.properties | 32 --- src/app/clusters/scenes/scenes-cli.c | 57 ----- 10 files changed, 773 deletions(-) delete mode 100644 src/app/clusters/ias-zone-client/ias-zone-client-cli.c delete mode 100644 src/app/clusters/ias-zone-server/ias-zone-server-test.h delete mode 100644 src/app/clusters/messaging-client/callbacks.info delete mode 100644 src/app/clusters/messaging-client/cli.xml delete mode 100644 src/app/clusters/messaging-client/messaging-client-cli.c delete mode 100644 src/app/clusters/messaging-client/plugin.properties delete mode 100644 src/app/clusters/messaging-server/cli.xml delete mode 100644 src/app/clusters/messaging-server/messaging-server-cli.c delete mode 100644 src/app/clusters/messaging-server/plugin.properties delete mode 100644 src/app/clusters/scenes/scenes-cli.c diff --git a/src/app/clusters/ias-zone-client/ias-zone-client-cli.c b/src/app/clusters/ias-zone-client/ias-zone-client-cli.c deleted file mode 100644 index a18f084b7197c9..00000000000000 --- a/src/app/clusters/ias-zone-client/ias-zone-client-cli.c +++ /dev/null @@ -1,97 +0,0 @@ -/** - * - * Copyright (c) 2020 Project CHIP Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * - * Copyright (c) 2020 Silicon Labs - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/**************************************************************************** - * @file - * @brief CLI for the IAS Zone Client plugin. - ******************************************************************************* - ******************************************************************************/ - -#include "af.h" -#include "app/util/serial/command-interpreter2.h" -#include "ias-zone-client.h" - -//----------------------------------------------------------------------------- -// Globals - -void emAfPluginIasZoneClientPrintServersCommand(void); -void emAfPluginIasZoneClientClearAllServersCommand(void); - -#ifndef EMBER_AF_GENERATE_CLI -EmberCommandEntry emberAfPluginIasZoneClientCommands[] = { - emberCommandEntryAction("print-servers", emAfPluginIasZoneClientPrintServersCommand, "", "Print the known IAS Zone Servers"), - emberCommandEntryAction("clear-all", emAfPluginIasZoneClientClearAllServersCommand, "", - "Clear all known IAS Zone Servers from local device"), - emberCommandEntryTerminator(), -}; -#endif // EMBER_AF_GENERATE_CLI - -//----------------------------------------------------------------------------- -// Functions - -void emAfPluginIasZoneClientPrintServersCommand(void) -{ - uint8_t i; - emberAfIasZoneClusterPrintln("Index IEEE EP Type Status State ID"); - emberAfIasZoneClusterPrintln("---------------------------------------------------"); - for (i = 0; i < EMBER_AF_PLUGIN_IAS_ZONE_CLIENT_MAX_DEVICES; i++) - { - if (i < 10) - { - emberAfIasZoneClusterPrint(" "); - } - emberAfIasZoneClusterPrint( - "%d (>)%X%X%X%X%X%X%X%X ", i, emberAfIasZoneClientKnownServers[i].ieeeAddress[7], - emberAfIasZoneClientKnownServers[i].ieeeAddress[6], emberAfIasZoneClientKnownServers[i].ieeeAddress[5], - emberAfIasZoneClientKnownServers[i].ieeeAddress[4], emberAfIasZoneClientKnownServers[i].ieeeAddress[3], - emberAfIasZoneClientKnownServers[i].ieeeAddress[2], emberAfIasZoneClientKnownServers[i].ieeeAddress[1], - emberAfIasZoneClientKnownServers[i].ieeeAddress[0]); - if (emberAfIasZoneClientKnownServers[i].endpoint < 10) - { - emberAfIasZoneClusterPrint(" "); - } - if (emberAfIasZoneClientKnownServers[i].endpoint < 100) - { - emberAfIasZoneClusterPrint(" "); - } - emberAfIasZoneClusterPrint("%d ", emberAfIasZoneClientKnownServers[i].endpoint); - emberAfIasZoneClusterPrintln("0x%2X 0x%2X 0x%X 0x%X", emberAfIasZoneClientKnownServers[i].zoneType, - emberAfIasZoneClientKnownServers[i].zoneStatus, emberAfIasZoneClientKnownServers[i].zoneState, - emberAfIasZoneClientKnownServers[i].zoneId); - } -} - -void emAfPluginIasZoneClientClearAllServersCommand(void) -{ - emAfClearServers(); -} diff --git a/src/app/clusters/ias-zone-server/ias-zone-server-test.h b/src/app/clusters/ias-zone-server/ias-zone-server-test.h deleted file mode 100644 index 924e6d34b3c95d..00000000000000 --- a/src/app/clusters/ias-zone-server/ias-zone-server-test.h +++ /dev/null @@ -1,64 +0,0 @@ -/** - * - * Copyright (c) 2020 Project CHIP Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * - * Copyright (c) 2020 Silicon Labs - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/**************************************************************************** - * @file - * @brief Include file for ias zone server's unit - *tests - ******************************************************************************* - ******************************************************************************/ - -#ifndef SILABS_IAS_ZONE_SERVER_TEST_H -#define SILABS_IAS_ZONE_SERVER_TEST_H - -#ifdef EMBER_SCRIPTED_TEST -#define EMBER_AF_PLUGIN_IAS_ZONE_SERVER_ZONE_TYPE 21 -#define EMBER_AF_PLUGIN_IAS_ZONE_SERVER_QUEUE_DEPTH 5 -#define EMBER_AF_PLUGIN_IAS_ZONE_SERVER_ENABLE_QUEUE 1 -#define EMBER_AF_PLUGIN_IAS_ZONE_SERVER_MIN_OTA_TIME_MS (500u) -#define EMBER_AF_PLUGIN_IAS_ZONE_SERVER_FIRST_BACKOFF_TIME_SEC (3u) -#define EMBER_AF_PLUGIN_IAS_ZONE_SERVER_BACKOFF_SEQUENCE_COMMON_RATIO (2u) -#define EMBER_AF_PLUGIN_IAS_ZONE_SERVER_MAX_BACKOFF_TIME_SEC (12u) -// Studio does not generate value for BOOLEAN type plugin options. Making it aligned... -#define EMBER_AF_PLUGIN_IAS_ZONE_SERVER_UNLIMITED_RETRIES -#define EMBER_AF_PLUGIN_IAS_ZONE_SERVER_MAX_RETRY_ATTEMPTS (100) - -#endif - -#define TOKEN_PLUGIN_IAS_ZONE_SERVER_ENROLLMENT_METHOD 0 -#define TOKEN_PLUGIN_IAS_ZONE_SERVER_ENROLLMENT_METHOD_SIZE 1 - -#undef EMBER_BINDING_TABLE_SIZE -#define EMBER_BINDING_TABLE_SIZE 12 - -#endif // SILABS_IAS_ZONE_SERVER_TEST_H diff --git a/src/app/clusters/messaging-client/callbacks.info b/src/app/clusters/messaging-client/callbacks.info deleted file mode 100644 index 097206748ec121..00000000000000 --- a/src/app/clusters/messaging-client/callbacks.info +++ /dev/null @@ -1,45 +0,0 @@ -/** @brief Pre Display Message - * - * This function is called by the Messaging client plugin when a DisplayMessage - * command is received. If callback returns true, the plugin assumes the - * message have been handled and will not do anything with the message. - * Otherwise, the plugin will go through with its own implementation. - * - * @param messageId Ver.: always - * @param messageControl Ver.: always - * @param startTime Ver.: always - * @param durationInMinutes Ver.: always - * @param message Ver.: always - * @param optionalExtendedMessageControl Ver.: always - */ -bool emberAfPluginMessagingClientPreDisplayMessageCallback(uint32_t messageId, - uint8_t messageControl, - uint32_t startTime, - uint16_t durationInMinutes, - uint8_t *message, - uint8_t optionalExtendedMessageControl) -{ - return false; -} - -/** @brief Display Message - * - * This function is called by the Messaging client plugin whenever the - * application should display a message. - * - * @param message The message that should be displayed. Ver.: always - */ -void emberAfPluginMessagingClientDisplayMessageCallback(EmberAfPluginMessagingClientMessage *message) -{ -} - -/** @brief Cancel Message - * - * This function is called by the Messaging client plugin whenever the - * application should stop displaying a message. - * - * @param message The message that should no longer be displayed. Ver.: always - */ -void emberAfPluginMessagingClientCancelMessageCallback(EmberAfPluginMessagingClientMessage *message) -{ -} diff --git a/src/app/clusters/messaging-client/cli.xml b/src/app/clusters/messaging-client/cli.xml deleted file mode 100644 index 16f1c9fc0f5118..00000000000000 --- a/src/app/clusters/messaging-client/cli.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - The messaging-client plugin contributes CLI commands to the application framework to be used for manipulating messages in a client context. - - - - - Send the message confirmation. - - - - - - Print the message info. - - - - - - Clear the message. - - - - diff --git a/src/app/clusters/messaging-client/messaging-client-cli.c b/src/app/clusters/messaging-client/messaging-client-cli.c deleted file mode 100644 index 52238c837726a3..00000000000000 --- a/src/app/clusters/messaging-client/messaging-client-cli.c +++ /dev/null @@ -1,75 +0,0 @@ -/** - * - * Copyright (c) 2020 Project CHIP Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * - * Copyright (c) 2020 Silicon Labs - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/*************************************************************************** - * @file - * @brief CLI for the Messaging Client plugin. - ******************************************************************************* - ******************************************************************************/ - -#include "app/framework/include/af.h" -#include "app/framework/plugin/messaging-client/messaging-client.h" -#include "app/util/serial/command-interpreter2.h" - -void emAfMessagingClientCliConfirm(void); -void emAfMessagingClientCliPrint(void); - -#if !defined(EMBER_AF_GENERATE_CLI) -EmberCommandEntry emberAfPluginMessagingClientCommands[] = { - emberCommandEntryAction("confirm", emAfMessagingClientCliConfirm, "u", ""), - emberCommandEntryAction("print", emAfMessagingClientCliPrint, "u", ""), - emberCommandEntryTerminator(), -}; -#endif // EMBER_AF_GENERATE_CLI - -// plugin messaging-client confirm -void emAfMessagingClientCliConfirm(void) -{ - uint8_t endpoint = (uint8_t) emberUnsignedCommandArgument(0); - EmberAfStatus status = emberAfPluginMessagingClientConfirmMessage(endpoint); - emberAfMessagingClusterPrintln("%p 0x%x", "confirm", status); -} - -// plugin messaging-client print -void emAfMessagingClientCliPrint(void) -{ - uint8_t endpoint = (uint8_t) emberUnsignedCommandArgument(0); - emAfPluginMessagingClientPrintInfo(endpoint); -} - -// plugin messaging-client clear -void emAfMessagingClientCliClear(void) -{ - uint8_t endpoint = (uint8_t) emberUnsignedCommandArgument(0); - emAfPluginMessagingClientClearMessage(endpoint); -} diff --git a/src/app/clusters/messaging-client/plugin.properties b/src/app/clusters/messaging-client/plugin.properties deleted file mode 100644 index d4d23b65510348..00000000000000 --- a/src/app/clusters/messaging-client/plugin.properties +++ /dev/null @@ -1,34 +0,0 @@ -# Name of the plugin. -name=Messaging Client Cluster -category=Smart Energy - -# Any string is allowable here. Generally it is either: Production Ready, Test Tool, or Requires Extending -qualityString=Requires Extending (Certifiable) -# This must be one of the following: productionReady, testTool, extensionNeeded -quality=extend - -introducedIn=se-1.1-07-5356-16 - -# Description of the plugin. -description=Ember implementation of Messaging client cluster. It requires extending in order to display the message on the hardware display. - -# List of .c files that need to be compiled and linked in. -sourceFiles=messaging-client.c,messaging-client-cli.c - -# List of callbacks implemented by this plugin -implementedCallbacks=emberAfMessagingClusterClientInitCallback,emberAfMessagingClusterClientTickCallback,emberAfMessagingClusterDisplayMessageCallback,emberAfMessagingClusterCancelMessageCallback - -# Turn this on by default -includedByDefault=true - -# Which clusters does it depend on -dependsOnClusterClient=messaging - -requiredPlugins=esi-management - -options=messageSize - -messageSize.name=Message size -messageSize.description=Maximum size of messages -messageSize.type=NUMBER:0,254 -messageSize.default=16 diff --git a/src/app/clusters/messaging-server/cli.xml b/src/app/clusters/messaging-server/cli.xml deleted file mode 100644 index bb6cafd7c324cb..00000000000000 --- a/src/app/clusters/messaging-server/cli.xml +++ /dev/null @@ -1,119 +0,0 @@ - - - - - The messaging-server plugin contributes CLI commands to the application framework to be used for manipulating messages in a server context. - - - - - Set the message used by the message plugin. - - - - - - Append an additional string to the message contained in the message plugin - - - - - - Set the message id for the message contained in the messaging plugin - - - - - - Set the start time and duration for the message used by the message plugin. - - - - - - - Set the relative time on the message. - - - - - - - Sets the message control bit mask to normal transmission. - - - - - Set the message control bit mask in the message to anonymous. - - - - - Set the message control bit mask in the message to normal and anonymous. - - - - - Set the message importance to low. - - - - - Set the message importance to medium. - - - - - Set the message importance to high. - - - - - Set the message importance to critical. - - - - - Set the message confirmation to not used. - - - - - Set message confirmation to required. - - - - - Set the message validity to valid. - - - - - - Set the message validity to invalid. - - - - - - Display the message. - - - - - - - - Cancel the message. - - - - - - - - Print the message info. - - - - diff --git a/src/app/clusters/messaging-server/messaging-server-cli.c b/src/app/clusters/messaging-server/messaging-server-cli.c deleted file mode 100644 index b5a9ce195faf38..00000000000000 --- a/src/app/clusters/messaging-server/messaging-server-cli.c +++ /dev/null @@ -1,224 +0,0 @@ -/** - * - * Copyright (c) 2020 Project CHIP Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * - * Copyright (c) 2020 Silicon Labs - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/***************************************************************************/ /** - * @file - * @brief CLI for the Messaging Server plugin. - ******************************************************************************* - ******************************************************************************/ - -#include "app/framework/include/af.h" -#include "app/framework/plugin/messaging-server/messaging-server.h" -#include "app/util/serial/command-interpreter2.h" - -void emAfMessagingServerCliMsg(void); -void emAfMessagingServerCliAppend(void); -void emAfMessagingServerCliId(void); -void emAfMessagingServerCliTime(void); -void emAfMessagingServerCliRelativeTime(void); -void emAfMessagingServerCliTransmission(void); -void emAfMessagingServerCliImportance(void); -void emAfMessagingServerCliConfirm(void); -void emAfMessagingServerCliValid(void); -void emAfMessagingServerCliDisplay(void); -void emAfMessagingServerCliCancel(void); -void emAfMessagingServerCliPrint(void); - -static EmberAfPluginMessagingServerMessage message; - -#if !defined(EMBER_AF_GENERATE_CLI) -EmberCommandEntry emberAfPluginMessagingServerTransmissionCommands[] = { - emberCommandEntryAction("normal", emAfMessagingServerCliTransmission, "", ""), - emberCommandEntryAction("ipan", emAfMessagingServerCliTransmission, "", ""), - emberCommandEntryAction("both", emAfMessagingServerCliTransmission, "", ""), - emberCommandEntryTerminator(), -}; - -EmberCommandEntry emberAfPluginMessagingServerImportanceCommands[] = { - emberCommandEntryAction("low", emAfMessagingServerCliImportance, "", ""), - emberCommandEntryAction("medium", emAfMessagingServerCliImportance, "", ""), - emberCommandEntryAction("high", emAfMessagingServerCliImportance, "", ""), - emberCommandEntryAction("critical", emAfMessagingServerCliImportance, "", ""), - emberCommandEntryTerminator(), -}; - -EmberCommandEntry emberAfPluginMessagingServerConfirmCommands[] = { - emberCommandEntryAction("not", emAfMessagingServerCliConfirm, "", ""), - emberCommandEntryAction("req", emAfMessagingServerCliConfirm, "", ""), - emberCommandEntryTerminator(), -}; - -EmberCommandEntry emberAfPluginMessagingServerCommands[] = { - emberCommandEntryAction("message", emAfMessagingServerCliMsg, "b", ""), - emberCommandEntryAction("append", emAfMessagingServerCliAppend, "b", ""), - emberCommandEntryAction("id", emAfMessagingServerCliId, "w", ""), - emberCommandEntryAction("time", emAfMessagingServerCliTime, "wv", ""), - emberCommandEntryAction("relative-time", emAfMessagingServerCliRelativeTime, "sv", ""), - emberCommandEntryAction("transmission", NULL, (const char *) emberAfPluginMessagingServerTransmissionCommands, ""), - emberCommandEntryAction("importance", NULL, (const char *) emberAfPluginMessagingServerImportanceCommands, ""), - emberCommandEntryAction("confirm", NULL, (const char *) emberAfPluginMessagingServerConfirmCommands, ""), - emberCommandEntryAction("valid", emAfMessagingServerCliValid, "u", ""), - emberCommandEntryAction("invalid", emAfMessagingServerCliValid, "u", ""), - emberCommandEntryAction("display", emAfMessagingServerCliDisplay, "vuu", ""), - emberCommandEntryAction("cancel", emAfMessagingServerCliCancel, "vuu", ""), - emberCommandEntryAction("print", emAfMessagingServerCliPrint, "u", ""), - emberCommandEntryTerminator(), -}; -#endif // EMBER_AF_GENERATE_CLI - -// plugin messaging-server message -void emAfMessagingServerCliMsg(void) -{ - uint8_t length = emberCopyStringArgument(0, message.message + 1, EMBER_AF_PLUGIN_MESSAGING_SERVER_MESSAGE_SIZE, false); - message.message[0] = length; -} - -// plugin messaging-server append -void emAfMessagingServerCliAppend(void) -{ - uint8_t oldLength = message.message[0]; - uint8_t length = emberCopyStringArgument(0, message.message + oldLength + 1, - (EMBER_AF_PLUGIN_MESSAGING_SERVER_MESSAGE_SIZE - oldLength), false); - message.message[0] = oldLength + length; -} - -// plugin messaging-server id -void emAfMessagingServerCliId(void) -{ - message.messageId = emberUnsignedCommandArgument(0); -} - -// plugin messaging-server time -void emAfMessagingServerCliTime(void) -{ - message.startTime = emberUnsignedCommandArgument(0); - message.durationInMinutes = (uint16_t) emberUnsignedCommandArgument(1); -} - -// plugin messaging-server relative-time <+/-time> - -// Rather than use absolute time, this will set the start-time relative to the current time +/- -// the CLI parameter in MINUTES. -void emAfMessagingServerCliRelativeTime(void) -{ - message.startTime = (emberAfGetCurrentTime() + (emberSignedCommandArgument(0) * 60)); - message.durationInMinutes = (uint16_t) emberUnsignedCommandArgument(1); -} - -// plugin messaging-server transmission -void emAfMessagingServerCliTransmission(void) -{ - uint8_t commandChar = emberCurrentCommand->name[0]; - message.messageControl &= ~ZCL_MESSAGING_CLUSTER_TRANSMISSION_MASK; - if (commandChar == 'b') - { // both - message.messageControl |= EMBER_ZCL_MESSAGING_CONTROL_TRANSMISSION_NORMAL_AND_ANONYMOUS; - } - else if (commandChar == 'i') - { // inter pan - message.messageControl |= EMBER_ZCL_MESSAGING_CONTROL_TRANSMISSION_ANONYMOUS; - } - else - { - // Do nothing for 'normal'. - // MISRA requires ..else if.. to have terminating else. - } -} - -// plugin messaging-server importance -void emAfMessagingServerCliImportance(void) -{ - uint8_t commandChar = emberCurrentCommand->name[0]; - message.messageControl &= ~ZCL_MESSAGING_CLUSTER_IMPORTANCE_MASK; - if (commandChar == 'm') - { // medium - message.messageControl |= EMBER_ZCL_MESSAGING_CONTROL_IMPORTANCE_MEDIUM; - } - else if (commandChar == 'h') - { // high - message.messageControl |= EMBER_ZCL_MESSAGING_CONTROL_IMPORTANCE_HIGH; - } - else if (commandChar == 'c') - { // critical - message.messageControl |= EMBER_ZCL_MESSAGING_CONTROL_IMPORTANCE_CRITICAL; - } - else - { - // Do nothing for 'low' importance. - // MISRA requires ..else if.. to have terminating else. - } -} - -// plugin messaging-server confirm -void emAfMessagingServerCliConfirm(void) -{ - uint8_t commandChar = emberCurrentCommand->name[0]; - message.messageControl &= ~ZCL_MESSAGING_CLUSTER_CONFIRMATION_MASK; - if (commandChar == 'r') - { // required - message.messageControl |= EMBER_ZCL_MESSAGING_CONTROL_CONFIRMATION_REQUIRED; - } - // Do nothing for 'not' (not required). -} - -// plugin messaging-server -void emAfMessagingServerCliValid(void) -{ - uint8_t endpoint = (uint8_t) emberUnsignedCommandArgument(0); - emberAfPluginMessagingServerSetMessage(endpoint, emberCurrentCommand->name[0] == 'v' ? &message : NULL); -} - -// plugin messaging-server display -void emAfMessagingServerCliDisplay(void) -{ - EmberNodeId nodeId = (EmberNodeId) emberUnsignedCommandArgument(0); - uint8_t srcEndpoint = (uint8_t) emberUnsignedCommandArgument(1); - uint8_t dstEndpoint = (uint8_t) emberUnsignedCommandArgument(2); - emberAfPluginMessagingServerDisplayMessage(nodeId, srcEndpoint, dstEndpoint); -} - -// plugin messaging-server cancel -void emAfMessagingServerCliCancel(void) -{ - EmberNodeId nodeId = (EmberNodeId) emberUnsignedCommandArgument(0); - uint8_t srcEndpoint = (uint8_t) emberUnsignedCommandArgument(1); - uint8_t dstEndpoint = (uint8_t) emberUnsignedCommandArgument(2); - emberAfPluginMessagingServerCancelMessage(nodeId, srcEndpoint, dstEndpoint); -} - -// plugin messaging-server print -void emAfMessagingServerCliPrint(void) -{ - uint8_t endpoint = (uint8_t) emberUnsignedCommandArgument(0); - emAfPluginMessagingServerPrintInfo(endpoint); -} diff --git a/src/app/clusters/messaging-server/plugin.properties b/src/app/clusters/messaging-server/plugin.properties deleted file mode 100644 index 17f87f657ee3ef..00000000000000 --- a/src/app/clusters/messaging-server/plugin.properties +++ /dev/null @@ -1,32 +0,0 @@ -# Name of the plugin. -name=Messaging Server Cluster -category=Smart Energy - -# Any string is allowable here. Generally it is either: Production Ready, Test Tool, or Requires Extending -qualityString=Requires Extending (Certifiable) -# This must be one of the following: productionReady, testTool, extensionNeeded -quality=extend - -introducedIn=se-1.1-07-5356-16 - -# Description of the plugin. -description=Ember implementation of Messaging server cluster. It serves up messages in its table to clients that request them. It requires extending to populate the message table with messages. - -# List of .c files that need to be compiled and linked in. -sourceFiles=messaging-server.c,messaging-server-cli.c - -# List of callbacks implemented by this plugin -implementedCallbacks=emberAfMessagingClusterServerInitCallback,emberAfMessagingClusterGetLastMessageCallback,emberAfMessagingClusterMessageConfirmationCallback - -# Turn this on by default -includedByDefault=true - -# Which clusters does it depend on -dependsOnClusterServer=messaging - -options=messageSize - -messageSize.name=Message size -messageSize.description=Maximum size of messages -messageSize.type=NUMBER:0,254 -messageSize.default=16 diff --git a/src/app/clusters/scenes/scenes-cli.c b/src/app/clusters/scenes/scenes-cli.c deleted file mode 100644 index b09e37fbc69b87..00000000000000 --- a/src/app/clusters/scenes/scenes-cli.c +++ /dev/null @@ -1,57 +0,0 @@ -/** - * - * Copyright (c) 2020 Project CHIP Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * - * Copyright (c) 2020 Silicon Labs - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/**************************************************************************** - * @file - * @brief CLI for the Scenes plugin. - ******************************************************************************* - ******************************************************************************/ - -#include "scenes.h" -#include - -void emAfPluginScenesServerClear(void); - -#if !defined(EMBER_AF_GENERATE_CLI) -EmberCommandEntry emberAfPluginScenesCommands[] = { - emberCommandEntryAction("print", emAfPluginScenesServerPrintInfo, "", "Print the scenes table."), - emberCommandEntryAction("clear", emAfPluginScenesServerClear, "", "Clear the scenes table on every endpoint."), - emberCommandEntryTerminator(), -}; -#endif // EMBER_AF_GENERATE_CLI - -void emAfPluginScenesServerClear(void) -{ - emberAfCorePrintln("Clearing all scenes."); - emberAfScenesClusterClearSceneTableCallback(EMBER_BROADCAST_ENDPOINT); -} From 0188d2200cfe0b854937a4f7a25367146c713145 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 6 Nov 2020 16:12:06 -0500 Subject: [PATCH 013/234] Use ClusterId in some cases where uint16_t snuck in. (#3701) --- src/app/reporting/reporting.h | 8 ++++---- src/app/util/attribute-storage.cpp | 2 +- src/app/util/attribute-storage.h | 2 +- src/app/util/process-global-message.cpp | 4 +++- src/app/util/util.cpp | 10 ++++++---- src/app/util/util.h | 8 ++++---- 6 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/app/reporting/reporting.h b/src/app/reporting/reporting.h index 643d2318bdd15e..3675bb41c979e4 100644 --- a/src/app/reporting/reporting.h +++ b/src/app/reporting/reporting.h @@ -84,7 +84,7 @@ bool emberAfPluginReportingGetReportingConfigDefaults(EmberAfPluginReportingEntr #ifdef __cplusplus extern "C" { -#endif +#endif // __cplusplus /** @brief Configure Reporting Command * * This function is called by the application framework when a Configure @@ -158,10 +158,10 @@ bool emberAfReadReportingConfigurationResponseCallback(EmberAfClusterId clusterI * @param type Ver.: always * @param data Ver.: always */ -void emberAfReportingAttributeChangeCallback(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attributeId, +void emberAfReportingAttributeChangeCallback(CHIPEndpointId endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attributeId, uint8_t mask, uint16_t manufacturerCode, EmberAfAttributeType type, uint8_t * data); #ifdef __cplusplus -} -#endif +} // extern "C" +#endif // __cplusplus #endif diff --git a/src/app/util/attribute-storage.cpp b/src/app/util/attribute-storage.cpp index 3e6c712b5c6966..a4f293a55f5b13 100644 --- a/src/app/util/attribute-storage.cpp +++ b/src/app/util/attribute-storage.cpp @@ -1209,7 +1209,7 @@ uint16_t emAfGetManufacturerCodeForCommand(EmberAfCommandMetadata * command) * It returns false, if there were more commands, but were not populated * because of maxIdCount limitation. */ -bool emberAfExtractCommandIds(bool outgoing, EmberAfClusterCommand * cmd, uint16_t clusterId, uint8_t * buffer, +bool emberAfExtractCommandIds(bool outgoing, EmberAfClusterCommand * cmd, ClusterId clusterId, uint8_t * buffer, uint16_t bufferLength, uint16_t * bufferIndex, uint8_t startId, uint8_t maxIdCount) { uint16_t i, count = 0; diff --git a/src/app/util/attribute-storage.h b/src/app/util/attribute-storage.h index bdeb7c5f9eb412..44fc6d1cf0a58c 100644 --- a/src/app/util/attribute-storage.h +++ b/src/app/util/attribute-storage.h @@ -95,7 +95,7 @@ void emAfCallInits(void); // Initial configuration void emberAfEndpointConfigure(void); -bool emberAfExtractCommandIds(bool outgoing, EmberAfClusterCommand * cmd, uint16_t clusterId, uint8_t * buffer, +bool emberAfExtractCommandIds(bool outgoing, EmberAfClusterCommand * cmd, CHIPClusterId clusterId, uint8_t * buffer, uint16_t bufferLength, uint16_t * bufferIndex, uint8_t startId, uint8_t maxIdCount); EmberAfStatus emAfReadOrWriteAttribute(EmberAfAttributeSearchRecord * attRecord, EmberAfAttributeMetadata ** metadata, diff --git a/src/app/util/process-global-message.cpp b/src/app/util/process-global-message.cpp index c11a406534aabb..6e68769bf3d3ed 100644 --- a/src/app/util/process-global-message.cpp +++ b/src/app/util/process-global-message.cpp @@ -57,6 +57,8 @@ #include "app/framework/plugin/comms-hub-function-sub-ghz/comms-hub-function-sub-ghz.h" #endif +using namespace chip; + // flag to keep track of the fact that we just sent a read attr for time and // we should set our time to the result of the read attr response. bool emAfSyncingTime = false; @@ -82,7 +84,7 @@ bool emAfSyncingTime = false; % UINT8_MAX) /* make count fit in an 8 bit integer */ #if defined(EMBER_AF_SUPPORT_COMMAND_DISCOVERY) -static void printDiscoverCommandsResponse(bool generated, uint16_t clusterId, bool discoveryComplete, uint8_t * buffer, +static void printDiscoverCommandsResponse(bool generated, ClusterId clusterId, bool discoveryComplete, uint8_t * buffer, uint16_t length) { uint16_t i; diff --git a/src/app/util/util.cpp b/src/app/util/util.cpp index 3c0706a4bb4409..99127178b9628d 100644 --- a/src/app/util/util.cpp +++ b/src/app/util/util.cpp @@ -323,8 +323,9 @@ void emberAfStackDown(void) // Print out information about each cluster // **************************************** -uint16_t emberAfFindClusterNameIndexWithMfgCode(uint16_t cluster, uint16_t mfgCode) +uint16_t emberAfFindClusterNameIndexWithMfgCode(ClusterId cluster, uint16_t mfgCode) { + static_assert(sizeof(ClusterId) == 2, "May need to adjust our index type or somehow define it in terms of cluster id type"); uint16_t index = 0; while (zclClusterNames[index].id != ZCL_NULL_CLUSTER_ID) { @@ -344,18 +345,19 @@ uint16_t emberAfFindClusterNameIndexWithMfgCode(uint16_t cluster, uint16_t mfgCo return 0xFFFF; } -uint16_t emberAfFindClusterNameIndex(uint16_t cluster) +uint16_t emberAfFindClusterNameIndex(ClusterId cluster) { return emberAfFindClusterNameIndexWithMfgCode(cluster, EMBER_AF_NULL_MANUFACTURER_CODE); } // This function parses into the cluster name table, and tries to find // the index in the table that has the two keys: cluster + mfgcode. -void emberAfDecodeAndPrintClusterWithMfgCode(uint16_t cluster, uint16_t mfgCode) +void emberAfDecodeAndPrintClusterWithMfgCode(ClusterId cluster, uint16_t mfgCode) { uint16_t index = emberAfFindClusterNameIndexWithMfgCode(cluster, mfgCode); if (index == 0xFFFF) { + static_assert(sizeof(ClusterId) == 2, "Adjust the print formatting"); emberAfPrint(emberAfPrintActiveArea, "(Unknown clus. [0x%2x])", cluster); } else @@ -364,7 +366,7 @@ void emberAfDecodeAndPrintClusterWithMfgCode(uint16_t cluster, uint16_t mfgCode) } } -void emberAfDecodeAndPrintCluster(uint16_t cluster) +void emberAfDecodeAndPrintCluster(ClusterId cluster) { emberAfDecodeAndPrintClusterWithMfgCode(cluster, EMBER_AF_NULL_MANUFACTURER_CODE); } diff --git a/src/app/util/util.h b/src/app/util/util.h index e68ed8de18f9c0..c6f6d98cc3d92a 100644 --- a/src/app/util/util.h +++ b/src/app/util/util.h @@ -154,12 +154,12 @@ uint16_t emberAfGetMfgCodeFromCurrentCommand(void); void emberAfInit(void); void emberAfTick(void); -uint16_t emberAfFindClusterNameIndex(uint16_t cluster); -uint16_t emberAfFindClusterNameIndexWithMfgCode(uint16_t cluster, uint16_t mfgCode); +uint16_t emberAfFindClusterNameIndex(CHIPClusterId cluster); +uint16_t emberAfFindClusterNameIndexWithMfgCode(CHIPClusterId cluster, uint16_t mfgCode); void emberAfStackDown(void); -void emberAfDecodeAndPrintCluster(uint16_t cluster); -void emberAfDecodeAndPrintClusterWithMfgCode(uint16_t cluster, uint16_t mfgCode); +void emberAfDecodeAndPrintCluster(CHIPClusterId cluster); +void emberAfDecodeAndPrintClusterWithMfgCode(CHIPClusterId cluster, uint16_t mfgCode); bool emberAfProcessMessage(EmberApsFrame * apsFrame, EmberIncomingMessageType type, uint8_t * message, uint16_t msgLen, ChipNodeId source, InterPanHeader * interPanHeader); From 280d80f921628ff9b9c860f7de9cb13aa9550cdd Mon Sep 17 00:00:00 2001 From: Vivien Nicolas Date: Fri, 6 Nov 2020 22:56:40 +0100 Subject: [PATCH 014/234] Add a linux version of the all-clusters-app demo (#3678) * Add a linux version of the all-clusters-app demo * Remove a bunch of code related to OTA --- .../workflows/examples-linux-standalone.yaml | 4 + BUILD.gn | 15 + .../all-clusters-common/BUILD.gn | 69 ++ .../gen/af-gen-event.h | 0 .../gen/af-structs.h | 0 .../gen/att-storage.h | 0 .../gen/attribute-id.h | 0 .../gen/attribute-size.h | 0 .../gen/attribute-type.h | 0 .../gen/call-command-handler.c | 0 .../gen/call-command-handler.h | 0 .../gen/callback-stub.c | 642 ----------------- .../gen/callback.h | 378 ---------- .../gen/cluster-id.h | 0 .../gen/clusters-callback-stubs.c | 11 - .../gen/command-id.h | 0 .../gen/endpoint_config.h | 0 .../main => all-clusters-common}/gen/enums.h | 0 .../gen/gen_config.h | 0 .../gen/gen_tokens.h | 0 .../gen/print-cluster.h | 0 .../esp32/main/DeviceCallbacks.cpp | 4 +- .../all-clusters-app/esp32/main/component.mk | 7 +- examples/all-clusters-app/linux/.gn | 23 + examples/all-clusters-app/linux/BUILD.gn | 51 ++ examples/all-clusters-app/linux/Dockerfile | 23 + examples/all-clusters-app/linux/args.gni | 17 + examples/all-clusters-app/linux/build | 1 + .../all-clusters-app/linux/build_overrides | 1 + examples/all-clusters-app/linux/entrypoint.sh | 29 + examples/all-clusters-app/linux/main.cpp | 79 +++ .../linux/third_party/connectedhomeip | 1 + .../efr32/src/gen/callback-stub.c | 645 ----------------- .../lighting-app/efr32/src/gen/callback.h | 378 ---------- .../lighting-common/gen/callback-stub.c | 647 ------------------ .../lighting-common/gen/callback.h | 378 ---------- .../lock-app/efr32/src/gen/callback-stub.c | 645 ----------------- examples/lock-app/efr32/src/gen/callback.h | 378 ---------- .../lock-app/lock-common/gen/callback-stub.c | 645 ----------------- examples/lock-app/lock-common/gen/callback.h | 378 ---------- .../esp32/main/gen/callback-stub.c | 645 ----------------- .../esp32/main/gen/callback.h | 378 ---------- .../door-lock-server-logging.cpp | 2 +- src/app/clusters/scenes/scenes.cpp | 32 - src/app/util/af-types.h | 166 ----- src/app/util/af.h | 24 - src/app/util/attribute-storage.cpp | 8 +- 47 files changed, 324 insertions(+), 6380 deletions(-) create mode 100644 examples/all-clusters-app/all-clusters-common/BUILD.gn rename examples/all-clusters-app/{esp32/main => all-clusters-common}/gen/af-gen-event.h (100%) rename examples/all-clusters-app/{esp32/main => all-clusters-common}/gen/af-structs.h (100%) rename examples/all-clusters-app/{esp32/main => all-clusters-common}/gen/att-storage.h (100%) rename examples/all-clusters-app/{esp32/main => all-clusters-common}/gen/attribute-id.h (100%) rename examples/all-clusters-app/{esp32/main => all-clusters-common}/gen/attribute-size.h (100%) rename examples/all-clusters-app/{esp32/main => all-clusters-common}/gen/attribute-type.h (100%) rename examples/all-clusters-app/{esp32/main => all-clusters-common}/gen/call-command-handler.c (100%) rename examples/all-clusters-app/{esp32/main => all-clusters-common}/gen/call-command-handler.h (100%) rename examples/all-clusters-app/{esp32/main => all-clusters-common}/gen/callback-stub.c (72%) rename examples/all-clusters-app/{esp32/main => all-clusters-common}/gen/callback.h (98%) rename examples/all-clusters-app/{esp32/main => all-clusters-common}/gen/cluster-id.h (100%) rename examples/all-clusters-app/{esp32/main => all-clusters-common}/gen/clusters-callback-stubs.c (94%) rename examples/all-clusters-app/{esp32/main => all-clusters-common}/gen/command-id.h (100%) rename examples/all-clusters-app/{esp32/main => all-clusters-common}/gen/endpoint_config.h (100%) rename examples/all-clusters-app/{esp32/main => all-clusters-common}/gen/enums.h (100%) rename examples/all-clusters-app/{esp32/main => all-clusters-common}/gen/gen_config.h (100%) rename examples/all-clusters-app/{esp32/main => all-clusters-common}/gen/gen_tokens.h (100%) rename examples/all-clusters-app/{esp32/main => all-clusters-common}/gen/print-cluster.h (100%) create mode 100644 examples/all-clusters-app/linux/.gn create mode 100644 examples/all-clusters-app/linux/BUILD.gn create mode 100644 examples/all-clusters-app/linux/Dockerfile create mode 100644 examples/all-clusters-app/linux/args.gni create mode 120000 examples/all-clusters-app/linux/build create mode 120000 examples/all-clusters-app/linux/build_overrides create mode 100755 examples/all-clusters-app/linux/entrypoint.sh create mode 100644 examples/all-clusters-app/linux/main.cpp create mode 120000 examples/all-clusters-app/linux/third_party/connectedhomeip diff --git a/.github/workflows/examples-linux-standalone.yaml b/.github/workflows/examples-linux-standalone.yaml index ed2382fd869949..14ba47a4212bc0 100644 --- a/.github/workflows/examples-linux-standalone.yaml +++ b/.github/workflows/examples-linux-standalone.yaml @@ -58,6 +58,10 @@ jobs: run: scripts/examples/gn_build_example.sh examples/shell/standalone out/shell_debug + - name: Build example Standalone All Clusters Server + run: + scripts/examples/gn_build_example.sh examples/all-clusters-app/linux + out/all_clusters_debug bypass_rendezvous=true - name: Binary artifact suffix id: outsuffix uses: haya14busa/action-cond@v1.0.0 diff --git a/BUILD.gn b/BUILD.gn index 3a2e3733a4fb92..3da44630f2b2aa 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -133,6 +133,10 @@ if (current_toolchain != "${dir_pw_toolchain}/dummy:dummy") { # Build the shell example. enable_standalone_shell_build = enable_default_builds + # Build the Linux all clusters app example. + enable_linux_all_clusters_app_build = + enable_default_builds && host_os == "linux" + # Build the Linux lighting app example. enable_linux_lighting_app_build = enable_default_builds && host_os == "linux" @@ -201,6 +205,14 @@ if (current_toolchain != "${dir_pw_toolchain}/dummy:dummy") { } } + if (enable_linux_all_clusters_app_build) { + group("linux_all_clusters_app") { + deps = [ + "${chip_root}/examples/all-clusters-app/linux(${standalone_toolchain})", + ] + } + } + if (enable_linux_lighting_app_build) { group("linux_lighting_app") { deps = [ @@ -258,6 +270,9 @@ if (current_toolchain != "${dir_pw_toolchain}/dummy:dummy") { if (enable_standalone_shell_build) { deps += [ ":standalone_shell" ] } + if (enable_linux_all_clusters_app_build) { + deps += [ ":linux_all_clusters_app" ] + } if (enable_linux_lighting_app_build) { deps += [ ":linux_lighting_app" ] } diff --git a/examples/all-clusters-app/all-clusters-common/BUILD.gn b/examples/all-clusters-app/all-clusters-common/BUILD.gn new file mode 100644 index 00000000000000..5587b1d9a588f6 --- /dev/null +++ b/examples/all-clusters-app/all-clusters-common/BUILD.gn @@ -0,0 +1,69 @@ +# Copyright (c) 2020 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/chip.gni") + +config("includes") { + include_dirs = [ + ".", + "include", + ] +} + +source_set("all-clusters-common") { + sources = [ + "${chip_root}/examples/common/chip-app-server/DataModelHandler.cpp", + "${chip_root}/src/app/clusters/barrier-control-server/barrier-control-server.cpp", + "${chip_root}/src/app/clusters/basic/basic.cpp", + "${chip_root}/src/app/clusters/color-control-server/color-control-server.cpp", + "${chip_root}/src/app/clusters/door-lock-server/door-lock-server-core.cpp", + "${chip_root}/src/app/clusters/door-lock-server/door-lock-server-logging.cpp", + "${chip_root}/src/app/clusters/door-lock-server/door-lock-server-schedule.cpp", + "${chip_root}/src/app/clusters/door-lock-server/door-lock-server-user.cpp", + "${chip_root}/src/app/clusters/groups-client/groups-client.cpp", + "${chip_root}/src/app/clusters/groups-server/groups-server.cpp", + "${chip_root}/src/app/clusters/ias-zone-server/ias-zone-server.cpp", + "${chip_root}/src/app/clusters/identify/identify.cpp", + "${chip_root}/src/app/clusters/level-control/level-control.cpp", + "${chip_root}/src/app/clusters/on-off-server/on-off.cpp", + "${chip_root}/src/app/clusters/scenes-client/scenes-client.cpp", + "${chip_root}/src/app/clusters/scenes/scenes.cpp", + "${chip_root}/src/app/clusters/temperature-measurement-server/temperature-measurement-server.cpp", + "${chip_root}/src/app/reporting/reporting-default-configuration.cpp", + "${chip_root}/src/app/reporting/reporting.cpp", + "${chip_root}/src/app/util/af-event.cpp", + "${chip_root}/src/app/util/af-main-common.cpp", + "${chip_root}/src/app/util/attribute-size.cpp", + "${chip_root}/src/app/util/attribute-storage.cpp", + "${chip_root}/src/app/util/attribute-table.cpp", + "${chip_root}/src/app/util/binding-table.cpp", + "${chip_root}/src/app/util/chip-message-send.cpp", + "${chip_root}/src/app/util/client-api.cpp", + "${chip_root}/src/app/util/ember-print.cpp", + "${chip_root}/src/app/util/message.cpp", + "${chip_root}/src/app/util/process-cluster-message.cpp", + "${chip_root}/src/app/util/process-global-message.cpp", + "${chip_root}/src/app/util/util.cpp", + "gen/call-command-handler.c", + "gen/callback-stub.c", + "gen/clusters-callback-stubs.c", + ] + + deps = [ + "${chip_root}/examples/common/chip-app-server:chip-app-server", + "${chip_root}/src/lib", + ] + + public_configs = [ ":includes" ] +} diff --git a/examples/all-clusters-app/esp32/main/gen/af-gen-event.h b/examples/all-clusters-app/all-clusters-common/gen/af-gen-event.h similarity index 100% rename from examples/all-clusters-app/esp32/main/gen/af-gen-event.h rename to examples/all-clusters-app/all-clusters-common/gen/af-gen-event.h diff --git a/examples/all-clusters-app/esp32/main/gen/af-structs.h b/examples/all-clusters-app/all-clusters-common/gen/af-structs.h similarity index 100% rename from examples/all-clusters-app/esp32/main/gen/af-structs.h rename to examples/all-clusters-app/all-clusters-common/gen/af-structs.h diff --git a/examples/all-clusters-app/esp32/main/gen/att-storage.h b/examples/all-clusters-app/all-clusters-common/gen/att-storage.h similarity index 100% rename from examples/all-clusters-app/esp32/main/gen/att-storage.h rename to examples/all-clusters-app/all-clusters-common/gen/att-storage.h diff --git a/examples/all-clusters-app/esp32/main/gen/attribute-id.h b/examples/all-clusters-app/all-clusters-common/gen/attribute-id.h similarity index 100% rename from examples/all-clusters-app/esp32/main/gen/attribute-id.h rename to examples/all-clusters-app/all-clusters-common/gen/attribute-id.h diff --git a/examples/all-clusters-app/esp32/main/gen/attribute-size.h b/examples/all-clusters-app/all-clusters-common/gen/attribute-size.h similarity index 100% rename from examples/all-clusters-app/esp32/main/gen/attribute-size.h rename to examples/all-clusters-app/all-clusters-common/gen/attribute-size.h diff --git a/examples/all-clusters-app/esp32/main/gen/attribute-type.h b/examples/all-clusters-app/all-clusters-common/gen/attribute-type.h similarity index 100% rename from examples/all-clusters-app/esp32/main/gen/attribute-type.h rename to examples/all-clusters-app/all-clusters-common/gen/attribute-type.h diff --git a/examples/all-clusters-app/esp32/main/gen/call-command-handler.c b/examples/all-clusters-app/all-clusters-common/gen/call-command-handler.c similarity index 100% rename from examples/all-clusters-app/esp32/main/gen/call-command-handler.c rename to examples/all-clusters-app/all-clusters-common/gen/call-command-handler.c diff --git a/examples/all-clusters-app/esp32/main/gen/call-command-handler.h b/examples/all-clusters-app/all-clusters-common/gen/call-command-handler.h similarity index 100% rename from examples/all-clusters-app/esp32/main/gen/call-command-handler.h rename to examples/all-clusters-app/all-clusters-common/gen/call-command-handler.h diff --git a/examples/all-clusters-app/esp32/main/gen/callback-stub.c b/examples/all-clusters-app/all-clusters-common/gen/callback-stub.c similarity index 72% rename from examples/all-clusters-app/esp32/main/gen/callback-stub.c rename to examples/all-clusters-app/all-clusters-common/gen/callback-stub.c index f477a63291d5ec..eb76c8d92e4ad8 100644 --- a/examples/all-clusters-app/esp32/main/gen/callback-stub.c +++ b/examples/all-clusters-app/all-clusters-common/gen/callback-stub.c @@ -1000,648 +1000,6 @@ void emberAfNcpIsAwakeIsrCallback(void) {} */ void emberAfNetworkKeyUpdateCompleteCallback(EmberStatus status) {} -/** @brief Ota Bootload - * - * The platform specific routine to bootload the device from a ZigBee - * over-the-air upgrade file. - * - * @param id A pointer to the structure that contains the information about what - * OTA image to bootload. Ver.: always - * @param ncpUpgradeTagId The tag ID of the upgrade data that will be used to - * bootload the device. Ver.: always - */ -uint8_t emberAfOtaBootloadCallback(const EmberAfOtaImageId * id, uint16_t ncpUpgradeTagId) -{ - // Please implement me - emberAfCorePrintln("Not supported."); - return 1; -} - -/** @brief Ota Client Bootload - * - * This callback is fired when the OTA Client recevies a command to bootload the - * newly downloaded OTA image. This callback will perform the platform specific - * to bootload their device. - * - * @param id This is the identifier relating to the image that has been - * downloaded and is ready for bootload. Ver.: always - */ -void emberAfOtaClientBootloadCallback(const EmberAfOtaImageId * id) -{ - // Any final preperation prior to the bootload should be done here. - // It is assumed that the device will reset in most all cases. - // Please implement me. -} - -/** @brief Ota Client Custom Verify - * - * This callback is executed by the OTA client after the signature verification - * has successfully completed. It allows the device to do its own custom - * verification of the image (such as verifying that the EBL is intact). - * - * @param newVerification This indicates if a new verification should be - * started. Ver.: always - * @param id This is ID of the image to be verified. Ver.: always - */ -EmberAfImageVerifyStatus emberAfOtaClientCustomVerifyCallback(bool newVerification, const EmberAfOtaImageId * id) -{ - // Manufacturing specific checks can be made to the image in this function to - // determine if it is valid. This function is called AFTER cryptographic - // checks have passed. If the cryptographic checks failed, this function will - // never be called. - - // The function shall return one of the following based on its own - // verification process. - // 1) EMBER_AF_IMAGE_GOOD - the image has passed all checks - // 2) EMBER_AF_IMAGE_BAD - the image is not valid - // 3) EMBER_AF_IMAGE_VERIFY_IN_PROGRESS - the image is valid so far, but more - // checks are needed. This callback shall be re-executed later to - // continue verification. This allows other code in the framework to - // run. - return EMBER_AF_IMAGE_GOOD; -} - -/** @brief Ota Client Download Complete - * - * This callback indicates that the OTA client has completed the download of a - * file. If the file has been completely downloaded and cryptographic checks - * have been turned on, then those will be performed prior to this callback and - * that outcome included in the 'success' result. On failure, this callback is - * merely informative, and the return type is ignored. On succesful download, - * this callback allows the client to perform any additional verification of the - * downloaded image and return that result to the OTA server. - * - * @param success This indicates the success or failure of the download and - * cryptographic verification process (if applicable). Ver.: always - * @param id This is the image identifier information that corresponds to the - * download result. Ver.: always - */ -bool emberAfOtaClientDownloadCompleteCallback(EmberAfOtaDownloadResult success, const EmberAfOtaImageId * id) -{ - // At this point the image has been completely downloaded and cryptographic - // checks (if applicable) have been performed. - - if (!success) - { - emberAfOtaBootloadClusterPrintln("Download failed."); - return true; // return value is ignored - } - - // This is for any additional validation that needs to be performed - // on the image by the application. - - // The results of checks here will be returned back to the OTA server - // in the Upgrade End request. - return true; -} - -/** @brief Ota Client Incoming Message Raw - * - * This callback is for processing incoming messages for the Over-the-air - * bootload cluster client. ZCL will not process the message and instead hand - * the raw over the air data to the callback for its own processing. - * - * @param message A pointer to the structure containing the message buffer and - * other information about it. Ver.: always - */ -bool emberAfOtaClientIncomingMessageRawCallback(EmberAfClusterCommand * message) -{ - return false; -} - -/** @brief Ota Client Start - * - * This callback should be called when the profile specific registration has - * completed successfully. It will start the client's state machine that will - * find the OTA server, query it for the next image, download the image, wait - * for the bootload message, and kick off the bootload. - * - */ -void emberAfOtaClientStartCallback(void) {} - -/** @brief Ota Client Version Info - * - * This function is called by the OTA client when a new query will occur to the - * server asking what the next version of firmware is. The client can inform - * the cluster software as to what information to use in the query (and - * subsequent download). - * - * @param currentImageInfo This is the information to use in the next query by - * the client cluster code. It contains the manufacturer ID, image type ID, and - * the firmware version to be specified in the query message sent to the server. - * Ver.: always - * @param hardwareVersion This is a pointer to the hardware version to use in - * the query. If no hardware version should be used, then - * EMBER_AF_INVALID_HARDWARE_VERSION should be used. Ver.: always - */ -void emberAfOtaClientVersionInfoCallback(EmberAfOtaImageId * currentImageInfo, uint16_t * hardwareVersion) -{ - // Customer will fill in the image info with their manufacturer ID, - // image type ID, and current software version number. - // The deviceSpecificFileEui64 can be ignored. - - // It may be necessary to dynamically determine this by talking to - // another device, as is the case with a host talking to an NCP device. - - // However, this routine will be called repeatedly so it may be wise - // to cache the data! - - /* This is commented out since the #defines below are not defined. - - if (currentImageInfo != NULL) { - memset(currentImageInfo, 0, sizeof(EmberAfOtaImageId)); - currentImageInfo->manufacturerId = EMBER_AF_MANUFACTURER_CODE; - currentImageInfo->imageTypeId = EMBER_AF_IMAGE_TYPE_ID; - currentImageInfo->firmwareVersion = EMBER_AF_CUSTOM_FIRMWARE_VERSION; - } - - if (hardwareVersion != NULL) { - *hardwareVersion = EMBER_AF_INVALID_HARDWARE_VERSION; - } - - assert(false); - */ -} - -/** @brief Ota Page Request Server Policy - * - * This callback is called by the OTA server page request code when it wants to - * determine if it is allowed for an OTA client to make a page request. It is - * only called if page request support has been enabled on the server. It - * should return EMBER_ZCL_STATUS_SUCCESS if it allows the page request, and - * EMBER_ZCL_STATUS_UNSUP_CLUSTER_COMMAND if it does not want to allow it. - * - */ -uint8_t emberAfOtaPageRequestServerPolicyCallback(void) -{ - return EMBER_ZCL_STATUS_SUCCESS; -} - -/** @brief Ota Server Block Size - * - * This function provides a way for the server to adjust the block size of its - * response to an Image block request by a client. - * - * @param clientNodeId The node Id of OTA client making an image block request. - * Ver.: always - */ -uint8_t emberAfOtaServerBlockSizeCallback(EmberNodeId clientNodeId) -{ - // This function provides a way for the server to potentially - // adjust the block size based on the client who is requesting. - // In other words if we are using source routing we will limit - // data returned by enough to put a source route into the message. - - // Image Block Response Message Format - // Status Code: 1-byte - // Manuf Code: 2-bytes - // Image Type: 2-bytes - // File Ver: 4-bytes - // File Offset: 4-bytes - // Data Size: 1-byte - // Data: variable - const uint8_t IMAGE_BLOCK_RESPONSE_OVERHEAD = (EMBER_AF_ZCL_OVERHEAD + 14); - - EmberApsFrame apsFrame; - uint8_t maxSize; - apsFrame.options = EMBER_APS_OPTION_NONE; - - if (emberAfIsCurrentSecurityProfileSmartEnergy()) - { - apsFrame.options |= EMBER_APS_OPTION_ENCRYPTION; - } - - maxSize = emberAfMaximumApsPayloadLength(EMBER_OUTGOING_DIRECT, clientNodeId, &apsFrame); - maxSize -= IMAGE_BLOCK_RESPONSE_OVERHEAD; - return maxSize; -} - -/** @brief Ota Server Incoming Message Raw - * - * This callback is for processing incoming messages for the Over-the-air - * bootload cluster server. ZCL will not process the message and instead hand - * the raw over the air data to the callback for its own processing. - * - * @param message A pointer to the structure containing the message buffer and - * other information about it. Ver.: always - */ -bool emberAfOtaServerIncomingMessageRawCallback(EmberAfClusterCommand * message) -{ - return false; -} - -/** @brief Ota Server Query - * - * This callback is fired when the OTA server receives a query request by the - * client. The callback lets the server application indicate to the client what - * the 'next' version of software is for the device, or if there is not one - * available. - * - * @param currentImageId This is the current software image that the client - * hase. Ver.: always - * @param hardwareVersion If this value is non-NULL, it indicates the hardware - * version of the client device. If NULL, the client did not specify a hardware - * version. Ver.: always - * @param nextUpgradeImageId This is a pointer to a data structure containing - * the 'next' software version for the client to download. Ver.: always - */ -uint8_t emberAfOtaServerQueryCallback(const EmberAfOtaImageId * currentImageId, uint16_t * hardwareVersion, - EmberAfOtaImageId * nextUpgradeImageId) -{ - // If a new software image is available, this function should return - // EMBER_ZCL_STATUS_SUCCESS and populate the 'nextUpgradeImageId' structure - // with the appropriate values. If no new software image is available (i.e. - // the client should not download a firmware image) then the server should - // return EMBER_ZCL_STATUS_NO_IMAGE_AVAILABLE. - return EMBER_ZCL_STATUS_NO_IMAGE_AVAILABLE; -} - -/** @brief Ota Server Send Image Notify - * - * This callback is an indication to the OTA server that it should send out - * notification about an OTA file that is available for download. - * - * @param dest The destination of the image notify message. May be a broadcast - * address. Ver.: always - * @param endpoint The destination endpoint of the image notify message. May be - * a broadcast endpoint. Ver.: always - * @param payloadType The type of data the image notify message will contain. 0 - * = no data. 1 = Manufacturer ID. 2 = Manufacturer ID and the image type ID. - * 3 = Manufacturer ID, image type ID, and firmware version. Ver.: always - * @param queryJitter The percentage of nodes that should respond to this - * message, from 1-100. On receipt of this message, each recipient will - * randomly choose a percentage and only query the server if their percentage is - * below this value. Ver.: always - * @param id The image information that will be put in the message. The data - * within this struct that will be appended to the message is determined by the - * previous 'payloadType' argument. Ver.: always - */ -bool emberAfOtaServerSendImageNotifyCallback(EmberNodeId dest, uint8_t endpoint, uint8_t payloadType, uint8_t queryJitter, - const EmberAfOtaImageId * id) -{ - return false; -} - -/** @brief Ota Server Upgrade End Request - * - * This function is called when the OTA server receives a request an upgrade end - * request. If the request indicated a successful download by the client, the - * server must tell the client when and if to upgrade to the downloaded image. - * - * @param source The node ID of the device that sent the upgrade end request. - * Ver.: always - * @param status This is the ZCL status sent by the client indicating the result - * of its attempt to download the new upgrade image. If the status is not - * EMBER_ZCL_STATUS_SUCCESS then this callback is merely informative and no - * response mesasge will be generated by the server. Ver.: always - * @param returnValue If the server returns true indicating that the client - * should apply the upgrade, this time value indicates when in the future the - * client should apply the upgrade. Ver.: always - * @param imageId This variable indicates the software version that the client - * successfully downloaded and is asking to upgrade to. Ver.: always - */ -bool emberAfOtaServerUpgradeEndRequestCallback(EmberNodeId source, uint8_t status, uint32_t * returnValue, - const EmberAfOtaImageId * imageId) -{ - // If the status value is not EMBER_ZCL_STATUS_SUCCESS, then this callback is - // merely informative and no response message will be generated by the server. - // If the server wants the client to NOT apply the upgrade, then it should - // return false. - // If the server wants the client to apply the upgrade, it should return true - // and set the 'returnValue' parameter to when it wants the client to - // apply the upgrade. There are three possible values: - // 0 = Apply the upgrade now - // 0xFFFFFFFF = Don't apply yet, ask again later. - // (anything-else) = Apply the upgrade X minutes from now. - *returnValue = 0; - return true; -} - -/** @brief Ota Storage Check Temp Data - * - * This callback will validate temporary data in the storage device to determine - * whether it is a complete file, a partially downloaded file, or there is no - * file present. When a complete or partial file is found it will return - * EMBER_AF_OTA_STORAGE_SUCCESS or EMBER_AF_OTA_STORAGE_PARTIAL_FILE_FOUND, - * respectively. In that case, the currentOffset, totalImageSize, and - * newFileInfo will be populated with data. When EMBER_AF_OTA_STORAGE_ERROR is - * returned, no temporary data is present. - * - * @param currentOffset A pointer to a value that will be written with the - * offset within the total file size that has been successfully stored in the - * storage device. This will indicate how much data has been currently - * dowloaded. Ver.: always - * @param totalImageSize A pointer to a value that will be written with the - * total image size of the OTA file when a download has completed. This does - * not indicate how much data has actually been downloaded currently. Ver.: - * always - * @param newFileInfo This is the image id of the temporary file data stored in - * the storage device. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageCheckTempDataCallback(uint32_t * currentOffset, uint32_t * totalImageSize, - EmberAfOtaImageId * newFileInfo) -{ - // If the image data cannot be successfully verified, an error should be - // returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Clear Temp Data - * - * This function clears any existing temp data that was downloaed. It is used - * immediately prior to downloading a raw image over the air. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageClearTempDataCallback(void) -{ - // If the image data cannot be stored, an error should be returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Close - * - * This callback shuts down the ZigBee Over-the-air storage module. - * - */ -void emberAfOtaStorageCloseCallback(void) -{ - // Please implement me. - assert(false); -} - -/** @brief Ota Storage Driver Download Finish - * - * This callback defines the low-level means by which a device records the final - * offset value of the download image. - * - * @param offset The value of the final offset of the image download. Ver.: - * always - */ -void emberAfOtaStorageDriverDownloadFinishCallback(uint32_t offset) -{ - // The storage driver and the rest of the OTA bootload code will not function - // correctly unless it is implemnted. Please implement me. - assert(false); -} - -/** @brief Ota Storage Driver Init - * - * The initialization code for the OTA storage driver. - * - */ -bool emberAfOtaStorageDriverInitCallback(void) -{ - // The storage driver and the rest of the OTA bootload code will not function - // correctly unless it is implemnted. Please implement me. - assert(false); - return false; -} - -/** @brief Ota Storage Driver Invalidate Image - * - * This callback invalidates the image stored on disk so that it will not be - * bootloaded, and it will not be a valid image that is in the middle of - * downloading. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageDriverInvalidateImageCallback(void) -{ - // The storage driver and the rest of the OTA bootload code will not function - // correctly unless it is implemnted. Please implement me. - assert(false); - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Driver Prepare To Resume Download - * - * This callback allows the underlying storage driver to prepare to resume the - * OTA file download. For example, the driver may exceute a page erase to - * insure the next page is ready to be written to. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageDriverPrepareToResumeDownloadCallback(void) -{ - assert(false); - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Driver Read - * - * This callback defines the low-level means by which a device reads from the - * OTA storage device. - * - * @param offset The address offset from the start of the storage device where - * data is to be read. Ver.: always - * @param length The length of the data to be read from the storage device. - * Ver.: always - * @param returnData A pointer where the data read from the device should be - * written to. Ver.: always - */ -bool emberAfOtaStorageDriverReadCallback(uint32_t offset, uint32_t length, uint8_t * returnData) -{ - // The storage driver and the rest of the OTA bootload code will not function - // correctly unless it is implemnted. Please implement me. - assert(false); - return false; -} - -/** @brief Ota Storage Driver Retrieve Last Stored Offset - * - * This callback defines the low-level means by which a device retrieves the - * last persistently recorded download offset. This may be different than last - * actual download offset. - * - */ -uint32_t emberAfOtaStorageDriverRetrieveLastStoredOffsetCallback(void) -{ - // The storage driver and the rest of the OTA bootload code will not function - // correctly unless it is implemnted. Please implement me. - assert(false); - return 0; -} - -/** @brief Ota Storage Driver Write - * - * This callback defines the low-level means by which a device reads from the - * OTA storage device. - * - * @param dataToWrite A pointer to the data that will be written to the storage - * device. Ver.: always - * @param offset The address offset from the start of the storage device where - * data will be written. Ver.: always - * @param length The length of the data to be written to the storage device. - * Ver.: always - */ -bool emberAfOtaStorageDriverWriteCallback(const uint8_t * dataToWrite, uint32_t offset, uint32_t length) -{ - // The storage driver and the rest of the OTA bootload code will not function - // correctly unless it is implemnted. Please implement me. - assert(false); - return false; -} - -/** @brief Ota Storage Finish Download - * - * This function indicates to the storage module that the download has finished. - * - * @param offset The final offset of the downloaded file (i.e. the total size) - * Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageFinishDownloadCallback(uint32_t offset) -{ - return EMBER_AF_OTA_STORAGE_SUCCESS; -} - -/** @brief Ota Storage Get Count - * - * This callback returns the total number of ZigBee Over-the-air upgrade images - * stored in the storage module. - * - */ -uint8_t emberAfOtaStorageGetCountCallback(void) -{ - return 0; -} - -/** @brief Ota Storage Get Full Header - * - * This callback populates the EmberAfOtaHeader structure pointed to by the - * returnData with data about the OTA file stored in the storage module. - * - * @param id This is a pointer to the image id for the OTA file to retrieve - * information about. Ver.: always - * @param returnData This is a pointer to the location of the structure that - * will be populated with data. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageGetFullHeaderCallback(const EmberAfOtaImageId * id, EmberAfOtaHeader * returnData) -{ - // If the requested image cannot be found, then an error shouldb e returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Get Total Image Size - * - * This function returns the total size of the ZigBee Over-the-air file with the - * passed parameters. If no file is found with those parameters, 0 is returned. - * - * @param id A pointer to the image identifier for the OTA file to retrieve - * information for. Ver.: always - */ -uint32_t emberAfOtaStorageGetTotalImageSizeCallback(const EmberAfOtaImageId * id) -{ - // On failure this should return an image size of zero. - return 0; -} - -/** @brief Ota Storage Init - * - * This callback initializes the ZigBee Over-the-air storage module. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageInitCallback(void) -{ - return EMBER_AF_OTA_STORAGE_SUCCESS; -} - -/** @brief Ota Storage Iterator First - * - * This callback lets you walk through the list of all OTA files by jumping to - * the first file in the list maintained by the storage module. If there is no - * file then emberAfOtaInvalidImageId is returned. - * - */ -EmberAfOtaImageId emberAfOtaStorageIteratorFirstCallback(void) -{ - // It is expected that the storage module maintain its own internal iterator - // that the 'first' and 'next' functions will manipulate. - - // If there are no images at all, this function should return the invalid - // image id. - return emberAfInvalidImageId; -} - -/** @brief Ota Storage Iterator Next - * - * This callback lets you walk through the list of all OTA files by jumping to - * the next file in the list maintained by the storage module. If there is no - * next file then emberAfOtaInvalidImageId is returned. - * - */ -EmberAfOtaImageId emberAfOtaStorageIteratorNextCallback(void) -{ - // It is expected that the storage module maintain its own internal iterator - // that the 'first' and 'next' functions will manipulate. - - // If there are no more images, this function should return the invalid image - // id. - return emberAfInvalidImageId; -} - -/** @brief Ota Storage Read Image Data - * - * This callback reads data from the specified OTA file and returns that data to - * the caller. - * - * @param id This is a pointer to the image id for the OTA file to retrieve data - * from. Ver.: always - * @param offset This is the offset relative to the start of the image where the - * data should be read from. Ver.: always - * @param length This is the length of data that will be read. Ver.: always - * @param returnData This is a pointer to where the data read out of the file - * will be written to Ver.: always - * @param returnedLength This is a pointer to a variable where the actual length - * of data read will be written to. A short read may occur if the end of file - * was reached. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageReadImageDataCallback(const EmberAfOtaImageId * id, uint32_t offset, uint32_t length, - uint8_t * returnData, uint32_t * returnedLength) -{ - // If the requested image cannot be found, then an error should be returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Search - * - * This callback searches through the list of all images for one that matches - * the passed parameters. On success an image identifier is returned with a - * matching image. On failure emberAfInvalidImageId is returned. - * - * @param manufacturerId The ZigBee assigned identifier of the manufacturer - * contained in the OTA image being searched for. Ver.: always - * @param imageTypeId The image type identifier contained in the OTA image being - * searched for. Ver.: always - * @param hardwareVersion This is a pointer to the hardware version that will be - * used in the search. If the pointer is NULL, hardware version will not be - * considered when searching for matching images. If it points to a value, the - * search will only consider images where that value falls between the minimum - * and maxmimum hardware version specified in the OTA file. If no hardware - * version is present in an OTA file but the other parameters match, the file - * will be considered a match Ver.: always - */ -EmberAfOtaImageId emberAfOtaStorageSearchCallback(uint16_t manufacturerId, uint16_t imageTypeId, const uint16_t * hardwareVersion) -{ - // If no image is found that matches the search criteria, this function should - // return the invalid image id. - return emberAfInvalidImageId; -} - -/** @brief Ota Storage Write Temp Data - * - * This function writes to the temporary data in the storage device at the - * specified offset. It is used when downloading a raw image over the air. - * - * @param offset The location within the download image file where to write the - * data. Ver.: always - * @param length The length of data to write. Ver.: always - * @param data A pointer to the temporary data that will be written to the - * storage device. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageWriteTempDataCallback(uint32_t offset, uint32_t length, const uint8_t * data) -{ - // If the image data cannot be stored, an error should be returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - /** @brief Outgoing Packet Filter * * ** REQUIRES INCLUDING THE PACKET-HANDOFF PLUGIN ** diff --git a/examples/all-clusters-app/esp32/main/gen/callback.h b/examples/all-clusters-app/all-clusters-common/gen/callback.h similarity index 98% rename from examples/all-clusters-app/esp32/main/gen/callback.h rename to examples/all-clusters-app/all-clusters-common/gen/callback.h index 335ab321e29473..a76e9019ae2d80 100644 --- a/examples/all-clusters-app/esp32/main/gen/callback.h +++ b/examples/all-clusters-app/all-clusters-common/gen/callback.h @@ -818,384 +818,6 @@ void emberAfNetworkFoundCallback(EmberZigbeeNetwork * networkFound, uint8_t lqi, * @param status Ver.: always */ void emberAfNetworkKeyUpdateCompleteCallback(EmberStatus status); -/** @brief Ota Bootload - * - * The platform specific routine to bootload the device from a ZigBee - * over-the-air upgrade file. - * - * @param id A pointer to the structure that contains the information about what - * OTA image to bootload. Ver.: always - * @param ncpUpgradeTagId The tag ID of the upgrade data that will be used to - * bootload the device. Ver.: always - */ -uint8_t emberAfOtaBootloadCallback(const EmberAfOtaImageId * id, uint16_t ncpUpgradeTagId); -/** @brief Ota Client Bootload - * - * This callback is fired when the OTA Client recevies a command to bootload the - * newly downloaded OTA image. This callback will perform the platform specific - * to bootload their device. - * - * @param id This is the identifier relating to the image that has been - * downloaded and is ready for bootload. Ver.: always - */ -void emberAfOtaClientBootloadCallback(const EmberAfOtaImageId * id); -/** @brief Ota Client Custom Verify - * - * This callback is executed by the OTA client after the signature verification - * has successfully completed. It allows the device to do its own custom - * verification of the image (such as verifying that the EBL is intact). - * - * @param newVerification This indicates if a new verification should be - * started. Ver.: always - * @param id This is ID of the image to be verified. Ver.: always - */ -EmberAfImageVerifyStatus emberAfOtaClientCustomVerifyCallback(bool newVerification, const EmberAfOtaImageId * id); -/** @brief Ota Client Download Complete - * - * This callback indicates that the OTA client has completed the download of a - * file. If the file has been completely downloaded and cryptographic checks - * have been turned on, then those will be performed prior to this callback and - * that outcome included in the 'success' result. On failure, this callback is - * merely informative, and the return type is ignored. On succesful download, - * this callback allows the client to perform any additional verification of the - * downloaded image and return that result to the OTA server. - * - * @param success This indicates the success or failure of the download and - * cryptographic verification process (if applicable). Ver.: always - * @param id This is the image identifier information that corresponds to the - * download result. Ver.: always - */ -bool emberAfOtaClientDownloadCompleteCallback(EmberAfOtaDownloadResult success, const EmberAfOtaImageId * id); -/** @brief Ota Client Incoming Message Raw - * - * This callback is for processing incoming messages for the Over-the-air - * bootload cluster client. ZCL will not process the message and instead hand - * the raw over the air data to the callback for its own processing. - * - * @param message A pointer to the structure containing the message buffer and - * other information about it. Ver.: always - */ -bool emberAfOtaClientIncomingMessageRawCallback(EmberAfClusterCommand * message); -/** @brief Ota Client Start - * - * This callback should be called when the profile specific registration has - * completed successfully. It will start the client's state machine that will - * find the OTA server, query it for the next image, download the image, wait - * for the bootload message, and kick off the bootload. - * - */ -void emberAfOtaClientStartCallback(void); -/** @brief Ota Client Version Info - * - * This function is called by the OTA client when a new query will occur to the - * server asking what the next version of firmware is. The client can inform - * the cluster software as to what information to use in the query (and - * subsequent download). - * - * @param currentImageInfo This is the information to use in the next query by - * the client cluster code. It contains the manufacturer ID, image type ID, and - * the firmware version to be specified in the query message sent to the server. - * Ver.: always - * @param hardwareVersion This is a pointer to the hardware version to use in - * the query. If no hardware version should be used, then - * EMBER_AF_INVALID_HARDWARE_VERSION should be used. Ver.: always - */ -void emberAfOtaClientVersionInfoCallback(EmberAfOtaImageId * currentImageInfo, uint16_t * hardwareVersion); -/** @brief Ota Page Request Server Policy - * - * This callback is called by the OTA server page request code when it wants to - * determine if it is allowed for an OTA client to make a page request. It is - * only called if page request support has been enabled on the server. It - * should return EMBER_ZCL_STATUS_SUCCESS if it allows the page request, and - * EMBER_ZCL_STATUS_UNSUP_CLUSTER_COMMAND if it does not want to allow it. - * - */ -uint8_t emberAfOtaPageRequestServerPolicyCallback(void); -/** @brief Ota Server Block Size - * - * This function provides a way for the server to adjust the block size of its - * response to an Image block request by a client. - * - * @param clientNodeId The node Id of OTA client making an image block request. - * Ver.: always - */ -uint8_t emberAfOtaServerBlockSizeCallback(EmberNodeId clientNodeId); -/** @brief Ota Server Incoming Message Raw - * - * This callback is for processing incoming messages for the Over-the-air - * bootload cluster server. ZCL will not process the message and instead hand - * the raw over the air data to the callback for its own processing. - * - * @param message A pointer to the structure containing the message buffer and - * other information about it. Ver.: always - */ -bool emberAfOtaServerIncomingMessageRawCallback(EmberAfClusterCommand * message); -/** @brief Ota Server Query - * - * This callback is fired when the OTA server receives a query request by the - * client. The callback lets the server application indicate to the client what - * the 'next' version of software is for the device, or if there is not one - * available. - * - * @param currentImageId This is the current software image that the client - * hase. Ver.: always - * @param hardwareVersion If this value is non-NULL, it indicates the hardware - * version of the client device. If NULL, the client did not specify a hardware - * version. Ver.: always - * @param nextUpgradeImageId This is a pointer to a data structure containing - * the 'next' software version for the client to download. Ver.: always - */ -uint8_t emberAfOtaServerQueryCallback(const EmberAfOtaImageId * currentImageId, uint16_t * hardwareVersion, - EmberAfOtaImageId * nextUpgradeImageId); -/** @brief Ota Server Send Image Notify - * - * This callback is an indication to the OTA server that it should send out - * notification about an OTA file that is available for download. - * - * @param dest The destination of the image notify message. May be a broadcast - * address. Ver.: always - * @param endpoint The destination endpoint of the image notify message. May be - * a broadcast endpoint. Ver.: always - * @param payloadType The type of data the image notify message will contain. 0 - * = no data. 1 = Manufacturer ID. 2 = Manufacturer ID and the image type ID. - * 3 = Manufacturer ID, image type ID, and firmware version. Ver.: always - * @param queryJitter The percentage of nodes that should respond to this - * message, from 1-100. On receipt of this message, each recipient will - * randomly choose a percentage and only query the server if their percentage is - * below this value. Ver.: always - * @param id The image information that will be put in the message. The data - * within this struct that will be appended to the message is determined by the - * previous 'payloadType' argument. Ver.: always - */ -bool emberAfOtaServerSendImageNotifyCallback(EmberNodeId dest, uint8_t endpoint, uint8_t payloadType, uint8_t queryJitter, - const EmberAfOtaImageId * id); -/** @brief Ota Server Upgrade End Request - * - * This function is called when the OTA server receives a request an upgrade end - * request. If the request indicated a successful download by the client, the - * server must tell the client when and if to upgrade to the downloaded image. - * - * @param source The node ID of the device that sent the upgrade end request. - * Ver.: always - * @param status This is the ZCL status sent by the client indicating the result - * of its attempt to download the new upgrade image. If the status is not - * EMBER_ZCL_STATUS_SUCCESS then this callback is merely informative and no - * response mesasge will be generated by the server. Ver.: always - * @param returnValue If the server returns true indicating that the client - * should apply the upgrade, this time value indicates when in the future the - * client should apply the upgrade. Ver.: always - * @param imageId This variable indicates the software version that the client - * successfully downloaded and is asking to upgrade to. Ver.: always - */ -bool emberAfOtaServerUpgradeEndRequestCallback(EmberNodeId source, uint8_t status, uint32_t * returnValue, - const EmberAfOtaImageId * imageId); -/** @brief Ota Storage Check Temp Data - * - * This callback will validate temporary data in the storage device to determine - * whether it is a complete file, a partially downloaded file, or there is no - * file present. When a complete or partial file is found it will return - * EMBER_AF_OTA_STORAGE_SUCCESS or EMBER_AF_OTA_STORAGE_PARTIAL_FILE_FOUND, - * respectively. In that case, the currentOffset, totalImageSize, and - * newFileInfo will be populated with data. When EMBER_AF_OTA_STORAGE_ERROR is - * returned, no temporary data is present. - * - * @param currentOffset A pointer to a value that will be written with the - * offset within the total file size that has been successfully stored in the - * storage device. This will indicate how much data has been currently - * dowloaded. Ver.: always - * @param totalImageSize A pointer to a value that will be written with the - * total image size of the OTA file when a download has completed. This does - * not indicate how much data has actually been downloaded currently. Ver.: - * always - * @param newFileInfo This is the image id of the temporary file data stored in - * the storage device. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageCheckTempDataCallback(uint32_t * currentOffset, uint32_t * totalImageSize, - EmberAfOtaImageId * newFileInfo); -/** @brief Ota Storage Clear Temp Data - * - * This function clears any existing temp data that was downloaed. It is used - * immediately prior to downloading a raw image over the air. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageClearTempDataCallback(void); -/** @brief Ota Storage Close - * - * This callback shuts down the ZigBee Over-the-air storage module. - * - */ -void emberAfOtaStorageCloseCallback(void); -/** @brief Ota Storage Driver Download Finish - * - * This callback defines the low-level means by which a device records the final - * offset value of the download image. - * - * @param offset The value of the final offset of the image download. Ver.: - * always - */ -void emberAfOtaStorageDriverDownloadFinishCallback(uint32_t offset); -/** @brief Ota Storage Driver Init - * - * The initialization code for the OTA storage driver. - * - */ -bool emberAfOtaStorageDriverInitCallback(void); -/** @brief Ota Storage Driver Invalidate Image - * - * This callback invalidates the image stored on disk so that it will not be - * bootloaded, and it will not be a valid image that is in the middle of - * downloading. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageDriverInvalidateImageCallback(void); -/** @brief Ota Storage Driver Prepare To Resume Download - * - * This callback allows the underlying storage driver to prepare to resume the - * OTA file download. For example, the driver may exceute a page erase to - * insure the next page is ready to be written to. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageDriverPrepareToResumeDownloadCallback(void); -/** @brief Ota Storage Driver Read - * - * This callback defines the low-level means by which a device reads from the - * OTA storage device. - * - * @param offset The address offset from the start of the storage device where - * data is to be read. Ver.: always - * @param length The length of the data to be read from the storage device. - * Ver.: always - * @param returnData A pointer where the data read from the device should be - * written to. Ver.: always - */ -bool emberAfOtaStorageDriverReadCallback(uint32_t offset, uint32_t length, uint8_t * returnData); -/** @brief Ota Storage Driver Retrieve Last Stored Offset - * - * This callback defines the low-level means by which a device retrieves the - * last persistently recorded download offset. This may be different than last - * actual download offset. - * - */ -uint32_t emberAfOtaStorageDriverRetrieveLastStoredOffsetCallback(void); -/** @brief Ota Storage Driver Write - * - * This callback defines the low-level means by which a device reads from the - * OTA storage device. - * - * @param dataToWrite A pointer to the data that will be written to the storage - * device. Ver.: always - * @param offset The address offset from the start of the storage device where - * data will be written. Ver.: always - * @param length The length of the data to be written to the storage device. - * Ver.: always - */ -bool emberAfOtaStorageDriverWriteCallback(const uint8_t * dataToWrite, uint32_t offset, uint32_t length); -/** @brief Ota Storage Finish Download - * - * This function indicates to the storage module that the download has finished. - * - * @param offset The final offset of the downloaded file (i.e. the total size) - * Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageFinishDownloadCallback(uint32_t offset); -/** @brief Ota Storage Get Count - * - * This callback returns the total number of ZigBee Over-the-air upgrade images - * stored in the storage module. - * - */ -uint8_t emberAfOtaStorageGetCountCallback(void); -/** @brief Ota Storage Get Full Header - * - * This callback populates the EmberAfOtaHeader structure pointed to by the - * returnData with data about the OTA file stored in the storage module. - * - * @param id This is a pointer to the image id for the OTA file to retrieve - * information about. Ver.: always - * @param returnData This is a pointer to the location of the structure that - * will be populated with data. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageGetFullHeaderCallback(const EmberAfOtaImageId * id, EmberAfOtaHeader * returnData); -/** @brief Ota Storage Get Total Image Size - * - * This function returns the total size of the ZigBee Over-the-air file with the - * passed parameters. If no file is found with those parameters, 0 is returned. - * - * @param id A pointer to the image identifier for the OTA file to retrieve - * information for. Ver.: always - */ -uint32_t emberAfOtaStorageGetTotalImageSizeCallback(const EmberAfOtaImageId * id); -/** @brief Ota Storage Init - * - * This callback initializes the ZigBee Over-the-air storage module. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageInitCallback(void); -/** @brief Ota Storage Iterator First - * - * This callback lets you walk through the list of all OTA files by jumping to - * the first file in the list maintained by the storage module. If there is no - * file then emberAfOtaInvalidImageId is returned. - * - */ -EmberAfOtaImageId emberAfOtaStorageIteratorFirstCallback(void); -/** @brief Ota Storage Iterator Next - * - * This callback lets you walk through the list of all OTA files by jumping to - * the next file in the list maintained by the storage module. If there is no - * next file then emberAfOtaInvalidImageId is returned. - * - */ -EmberAfOtaImageId emberAfOtaStorageIteratorNextCallback(void); -/** @brief Ota Storage Read Image Data - * - * This callback reads data from the specified OTA file and returns that data to - * the caller. - * - * @param id This is a pointer to the image id for the OTA file to retrieve data - * from. Ver.: always - * @param offset This is the offset relative to the start of the image where the - * data should be read from. Ver.: always - * @param length This is the length of data that will be read. Ver.: always - * @param returnData This is a pointer to where the data read out of the file - * will be written to Ver.: always - * @param returnedLength This is a pointer to a variable where the actual length - * of data read will be written to. A short read may occur if the end of file - * was reached. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageReadImageDataCallback(const EmberAfOtaImageId * id, uint32_t offset, uint32_t length, - uint8_t * returnData, uint32_t * returnedLength); -/** @brief Ota Storage Search - * - * This callback searches through the list of all images for one that matches - * the passed parameters. On success an image identifier is returned with a - * matching image. On failure emberAfInvalidImageId is returned. - * - * @param manufacturerId The ZigBee assigned identifier of the manufacturer - * contained in the OTA image being searched for. Ver.: always - * @param imageTypeId The image type identifier contained in the OTA image being - * searched for. Ver.: always - * @param hardwareVersion This is a pointer to the hardware version that will be - * used in the search. If the pointer is NULL, hardware version will not be - * considered when searching for matching images. If it points to a value, the - * search will only consider images where that value falls between the minimum - * and maxmimum hardware version specified in the OTA file. If no hardware - * version is present in an OTA file but the other parameters match, the file - * will be considered a match Ver.: always - */ -EmberAfOtaImageId emberAfOtaStorageSearchCallback(uint16_t manufacturerId, uint16_t imageTypeId, const uint16_t * hardwareVersion); -/** @brief Ota Storage Write Temp Data - * - * This function writes to the temporary data in the storage device at the - * specified offset. It is used when downloading a raw image over the air. - * - * @param offset The location within the download image file where to write the - * data. Ver.: always - * @param length The length of data to write. Ver.: always - * @param data A pointer to the temporary data that will be written to the - * storage device. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageWriteTempDataCallback(uint32_t offset, uint32_t length, const uint8_t * data); /** @brief Outgoing Packet Filter * * ** REQUIRES INCLUDING THE PACKET-HANDOFF PLUGIN ** diff --git a/examples/all-clusters-app/esp32/main/gen/cluster-id.h b/examples/all-clusters-app/all-clusters-common/gen/cluster-id.h similarity index 100% rename from examples/all-clusters-app/esp32/main/gen/cluster-id.h rename to examples/all-clusters-app/all-clusters-common/gen/cluster-id.h diff --git a/examples/all-clusters-app/esp32/main/gen/clusters-callback-stubs.c b/examples/all-clusters-app/all-clusters-common/gen/clusters-callback-stubs.c similarity index 94% rename from examples/all-clusters-app/esp32/main/gen/clusters-callback-stubs.c rename to examples/all-clusters-app/all-clusters-common/gen/clusters-callback-stubs.c index 276f7dc8a76042..a18ea2f9302483 100644 --- a/examples/all-clusters-app/esp32/main/gen/clusters-callback-stubs.c +++ b/examples/all-clusters-app/all-clusters-common/gen/clusters-callback-stubs.c @@ -33,17 +33,6 @@ bool emberAfIdentifyClusterIdentifyQueryResponseCallback(uint16_t timeout) return false; } -/** @brief Door Lock Cluster Get Log Record - * - * - * - * @param logIndex Ver.: always - */ -bool emberAfDoorLockClusterGetLogRecordCallback(uint16_t logIndex) -{ - return false; -} - /** @brief IAS Zone Cluster Zone Enroll Request * * diff --git a/examples/all-clusters-app/esp32/main/gen/command-id.h b/examples/all-clusters-app/all-clusters-common/gen/command-id.h similarity index 100% rename from examples/all-clusters-app/esp32/main/gen/command-id.h rename to examples/all-clusters-app/all-clusters-common/gen/command-id.h diff --git a/examples/all-clusters-app/esp32/main/gen/endpoint_config.h b/examples/all-clusters-app/all-clusters-common/gen/endpoint_config.h similarity index 100% rename from examples/all-clusters-app/esp32/main/gen/endpoint_config.h rename to examples/all-clusters-app/all-clusters-common/gen/endpoint_config.h diff --git a/examples/all-clusters-app/esp32/main/gen/enums.h b/examples/all-clusters-app/all-clusters-common/gen/enums.h similarity index 100% rename from examples/all-clusters-app/esp32/main/gen/enums.h rename to examples/all-clusters-app/all-clusters-common/gen/enums.h diff --git a/examples/all-clusters-app/esp32/main/gen/gen_config.h b/examples/all-clusters-app/all-clusters-common/gen/gen_config.h similarity index 100% rename from examples/all-clusters-app/esp32/main/gen/gen_config.h rename to examples/all-clusters-app/all-clusters-common/gen/gen_config.h diff --git a/examples/all-clusters-app/esp32/main/gen/gen_tokens.h b/examples/all-clusters-app/all-clusters-common/gen/gen_tokens.h similarity index 100% rename from examples/all-clusters-app/esp32/main/gen/gen_tokens.h rename to examples/all-clusters-app/all-clusters-common/gen/gen_tokens.h diff --git a/examples/all-clusters-app/esp32/main/gen/print-cluster.h b/examples/all-clusters-app/all-clusters-common/gen/print-cluster.h similarity index 100% rename from examples/all-clusters-app/esp32/main/gen/print-cluster.h rename to examples/all-clusters-app/all-clusters-common/gen/print-cluster.h diff --git a/examples/all-clusters-app/esp32/main/DeviceCallbacks.cpp b/examples/all-clusters-app/esp32/main/DeviceCallbacks.cpp index a8cf0c603f8a5b..5be0d51eac6654 100644 --- a/examples/all-clusters-app/esp32/main/DeviceCallbacks.cpp +++ b/examples/all-clusters-app/esp32/main/DeviceCallbacks.cpp @@ -34,8 +34,8 @@ #include extern "C" { -#include "../gen/attribute-id.h" -#include "../gen/cluster-id.h" +#include "gen/attribute-id.h" +#include "gen/cluster-id.h" } // extern "C" static const char * TAG = "echo-devicecallbacks"; diff --git a/examples/all-clusters-app/esp32/main/component.mk b/examples/all-clusters-app/esp32/main/component.mk index 331c2a78590d8f..2a80b5dc535e42 100644 --- a/examples/all-clusters-app/esp32/main/component.mk +++ b/examples/all-clusters-app/esp32/main/component.mk @@ -23,8 +23,8 @@ COMPONENT_DEPENDS := chip QRCode tft spidriver COMPONENT_SRCDIRS := \ . \ - gen \ ../third_party/connectedhomeip/examples/common/chip-app-server \ + ../third_party/connectedhomeip/examples/all-clusters-app/all-clusters-common/gen \ ../third_party/connectedhomeip/src/app/util \ ../third_party/connectedhomeip/src/app/clusters/on-off-server \ ../third_party/connectedhomeip/src/app/clusters/level-control \ @@ -43,8 +43,9 @@ COMPONENT_SRCDIRS := # ../third_party/connectedhomeip/src/app/clusters/ias-zone-client \ -COMPONENT_EXTRA_INCLUDES := $(PROJECT_PATH)/third_party/connectedhomeip/src/app/util \ - $(PROJECT_PATH)/third_party/connectedhomeip/examples/common/chip-app-server/include \ +COMPONENT_EXTRA_INCLUDES := $(PROJECT_PATH)/third_party/connectedhomeip/src/app/util \ + $(PROJECT_PATH)/third_party/connectedhomeip/examples/common/chip-app-server/include \ + $(PROJECT_PATH)/third_party/connectedhomeip/examples/all-clusters-app/all-clusters-common \ $(PROJECT_PATH)/third_party/connectedhomeip/src # So "gen/*" files are found by the src/app bits. diff --git a/examples/all-clusters-app/linux/.gn b/examples/all-clusters-app/linux/.gn new file mode 100644 index 00000000000000..c3cfa5fd40318d --- /dev/null +++ b/examples/all-clusters-app/linux/.gn @@ -0,0 +1,23 @@ +# Copyright (c) 2020 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# The location of the build configuration file. +buildconfig = "//build/config/BUILDCONFIG.gn" + +# CHIP uses angle bracket includes. +check_system_includes = true + +default_args = { + import("//args.gni") +} diff --git a/examples/all-clusters-app/linux/BUILD.gn b/examples/all-clusters-app/linux/BUILD.gn new file mode 100644 index 00000000000000..01da5ec0b3b43d --- /dev/null +++ b/examples/all-clusters-app/linux/BUILD.gn @@ -0,0 +1,51 @@ +# Copyright (c) 2020 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/chip.gni") + +import("${chip_root}/build/chip/tools.gni") + +assert(chip_build_tools) + +config("includes") { + include_dirs = [ + ".", + "include", + "${chip_root}/src/app/util", + ] +} + +executable("all-clusters-server") { + sources = [ "main.cpp" ] + + if (is_debug) { + defines = [ "BUILD_RELEASE=0" ] + } else { + defines = [ "BUILD_RELEASE=1" ] + } + + public_configs = [ ":includes" ] + + deps = [ + "${chip_root}/examples/all-clusters-app/all-clusters-common", + "${chip_root}/examples/common/chip-app-server:chip-app-server", + "${chip_root}/src/lib", + ] + + output_dir = root_out_dir +} + +group("linux") { + deps = [ ":all-clusters-server" ] +} diff --git a/examples/all-clusters-app/linux/Dockerfile b/examples/all-clusters-app/linux/Dockerfile new file mode 100644 index 00000000000000..11630a808b0c19 --- /dev/null +++ b/examples/all-clusters-app/linux/Dockerfile @@ -0,0 +1,23 @@ +# +# Copyright (c) 2020 Project CHIP Authors +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from generic_node_image +RUN apt-get install -y libglib2.0 +COPY out/debug/chip-tool-all-clusters-server /usr/bin/ +COPY entrypoint.sh / + +ENTRYPOINT ["/entrypoint.sh", "server"] diff --git a/examples/all-clusters-app/linux/args.gni b/examples/all-clusters-app/linux/args.gni new file mode 100644 index 00000000000000..311ddab32d5fe5 --- /dev/null +++ b/examples/all-clusters-app/linux/args.gni @@ -0,0 +1,17 @@ +# Copyright (c) 2020 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/chip.gni") + +import("${chip_root}/config/standalone/args.gni") diff --git a/examples/all-clusters-app/linux/build b/examples/all-clusters-app/linux/build new file mode 120000 index 00000000000000..d56ed62ae4d1ff --- /dev/null +++ b/examples/all-clusters-app/linux/build @@ -0,0 +1 @@ +third_party/connectedhomeip/build \ No newline at end of file diff --git a/examples/all-clusters-app/linux/build_overrides b/examples/all-clusters-app/linux/build_overrides new file mode 120000 index 00000000000000..e578e73312ebd1 --- /dev/null +++ b/examples/all-clusters-app/linux/build_overrides @@ -0,0 +1 @@ +../../build_overrides \ No newline at end of file diff --git a/examples/all-clusters-app/linux/entrypoint.sh b/examples/all-clusters-app/linux/entrypoint.sh new file mode 100755 index 00000000000000..413f2d36b0799c --- /dev/null +++ b/examples/all-clusters-app/linux/entrypoint.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +# +# Copyright (c) 2020 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +set -ex + +service dbus start +sleep 1 +/usr/sbin/otbr-agent -I wpan0 spinel+hdlc+uart:///dev/ttyUSB0 & +sleep 1 +ot-ctl panid 0x1234 +ot-ctl ifconfig up +ot-ctl thread start + +chip-tool-all-clusters-server diff --git a/examples/all-clusters-app/linux/main.cpp b/examples/all-clusters-app/linux/main.cpp new file mode 100644 index 00000000000000..abf1f139cd8408 --- /dev/null +++ b/examples/all-clusters-app/linux/main.cpp @@ -0,0 +1,79 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "af.h" +#include "gen/attribute-id.h" +#include "gen/cluster-id.h" +#include +#include +#include +#include +#include +#include +#include + +#include "Server.h" + +#include +#include + +using namespace chip; +using namespace chip::Inet; +using namespace chip::Transport; +using namespace chip::DeviceLayer; + +extern "C" { +void emberAfPostAttributeChangeCallback(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attributeId, uint8_t mask, + uint16_t manufacturerCode, uint8_t type, uint8_t size, uint8_t * value) +{} + +void emberAfPluginBasicResetToFactoryDefaultsCallback(uint8_t endpointId) {} +bool emberAfPluginDoorLockServerActivateDoorLockCallback(bool activate) +{ + return true; +} + +} // extern "C" + +int main(int argc, char * argv[]) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + err = chip::Platform::MemoryInit(); + SuccessOrExit(err); + + err = chip::DeviceLayer::PlatformMgr().InitChipStack(); + SuccessOrExit(err); + + // Init ZCL Data Model and CHIP App Server + InitServer(); + + chip::DeviceLayer::PlatformMgr().RunEventLoop(); + +exit: + if (err != CHIP_NO_ERROR) + { + std::cerr << "Failed to run All Clusters App: " << ErrorStr(err) << std::endl; + // End the program with non zero error code to indicate a error. + return 1; + } + return 0; +} diff --git a/examples/all-clusters-app/linux/third_party/connectedhomeip b/examples/all-clusters-app/linux/third_party/connectedhomeip new file mode 120000 index 00000000000000..11a54ed360106c --- /dev/null +++ b/examples/all-clusters-app/linux/third_party/connectedhomeip @@ -0,0 +1 @@ +../../../../ \ No newline at end of file diff --git a/examples/lighting-app/efr32/src/gen/callback-stub.c b/examples/lighting-app/efr32/src/gen/callback-stub.c index dd0e5638fb9c4c..487ad8f0ed9182 100644 --- a/examples/lighting-app/efr32/src/gen/callback-stub.c +++ b/examples/lighting-app/efr32/src/gen/callback-stub.c @@ -137,15 +137,6 @@ bool emberAfAttributeWriteAccessCallback(uint8_t endpoint, EmberAfClusterId clus */ void emberAfGroupsClusterClearGroupTableCallback(uint8_t endpoint) {} -/** @brief Scenes Cluster ClearSceneTable - * - * This function is called by the framework when the application should clear - * the scene table. - * - * @param endpoint The endpoint. Ver.: always - */ -void emberAfScenesClusterClearSceneTableCallback(uint8_t endpoint) {} - /** @brief Key Establishment Cluster Client Command Received * * This function is called by the application framework when a server-to-client @@ -1000,642 +991,6 @@ void emberAfNcpIsAwakeIsrCallback(void) {} */ void emberAfNetworkKeyUpdateCompleteCallback(EmberStatus status) {} -/** @brief Ota Bootload - * - * The platform specific routine to bootload the device from a ZigBee - * over-the-air upgrade file. - * - * @param id A pointer to the structure that contains the information about what - * OTA image to bootload. Ver.: always - * @param ncpUpgradeTagId The tag ID of the upgrade data that will be used to - * bootload the device. Ver.: always - */ -uint8_t emberAfOtaBootloadCallback(const EmberAfOtaImageId * id, uint16_t ncpUpgradeTagId) -{ - // Please implement me - emberAfCorePrintln("Not supported."); - return 1; -} - -/** @brief Ota Client Bootload - * - * This callback is fired when the OTA Client recevies a command to bootload the - * newly downloaded OTA image. This callback will perform the platform specific - * to bootload their device. - * - * @param id This is the identifier relating to the image that has been - * downloaded and is ready for bootload. Ver.: always - */ -void emberAfOtaClientBootloadCallback(const EmberAfOtaImageId * id) -{ - // Any final preperation prior to the bootload should be done here. - // It is assumed that the device will reset in most all cases. - // Please implement me. -} - -/** @brief Ota Client Custom Verify - * - * This callback is executed by the OTA client after the signature verification - * has successfully completed. It allows the device to do its own custom - * verification of the image (such as verifying that the EBL is intact). - * - * @param newVerification This indicates if a new verification should be - * started. Ver.: always - * @param id This is ID of the image to be verified. Ver.: always - */ -EmberAfImageVerifyStatus emberAfOtaClientCustomVerifyCallback(bool newVerification, const EmberAfOtaImageId * id) -{ - // Manufacturing specific checks can be made to the image in this function to - // determine if it is valid. This function is called AFTER cryptographic - // checks have passed. If the cryptographic checks failed, this function will - // never be called. - - // The function shall return one of the following based on its own - // verification process. - // 1) EMBER_AF_IMAGE_GOOD - the image has passed all checks - // 2) EMBER_AF_IMAGE_BAD - the image is not valid - // 3) EMBER_AF_IMAGE_VERIFY_IN_PROGRESS - the image is valid so far, but more - // checks are needed. This callback shall be re-executed later to - // continue verification. This allows other code in the framework to run. - return EMBER_AF_IMAGE_GOOD; -} - -/** @brief Ota Client Download Complete - * - * This callback indicates that the OTA client has completed the download of a - * file. If the file has been completely downloaded and cryptographic checks - * have been turned on, then those will be performed prior to this callback and - * that outcome included in the 'success' result. On failure, this callback is - * merely informative, and the return type is ignored. On succesful download, - * this callback allows the client to perform any additional verification of the - * downloaded image and return that result to the OTA server. - * - * @param success This indicates the success or failure of the download and - * cryptographic verification process (if applicable). Ver.: always - * @param id This is the image identifier information that corresponds to the - * download result. Ver.: always - */ -bool emberAfOtaClientDownloadCompleteCallback(EmberAfOtaDownloadResult success, const EmberAfOtaImageId * id) -{ - // At this point the image has been completely downloaded and cryptographic - // checks (if applicable) have been performed. - - if (!success) - { - emberAfOtaBootloadClusterPrintln("Download failed."); - return true; // return value is ignored - } - - // This is for any additional validation that needs to be performed - // on the image by the application. - - // The results of checks here will be returned back to the OTA server - // in the Upgrade End request. - return true; -} - -/** @brief Ota Client Incoming Message Raw - * - * This callback is for processing incoming messages for the Over-the-air - * bootload cluster client. ZCL will not process the message and instead hand - * the raw over the air data to the callback for its own processing. - * - * @param message A pointer to the structure containing the message buffer and - * other information about it. Ver.: always - */ -bool emberAfOtaClientIncomingMessageRawCallback(EmberAfClusterCommand * message) -{ - return false; -} - -/** @brief Ota Client Start - * - * This callback should be called when the profile specific registration has - * completed successfully. It will start the client's state machine that will - * find the OTA server, query it for the next image, download the image, wait - * for the bootload message, and kick off the bootload. - * - */ -void emberAfOtaClientStartCallback(void) {} - -/** @brief Ota Client Version Info - * - * This function is called by the OTA client when a new query will occur to the - * server asking what the next version of firmware is. The client can inform - * the cluster software as to what information to use in the query (and - * subsequent download). - * - * @param currentImageInfo This is the information to use in the next query by - * the client cluster code. It contains the manufacturer ID, image type ID, and - * the firmware version to be specified in the query message sent to the server. - * Ver.: always - * @param hardwareVersion This is a pointer to the hardware version to use in - * the query. If no hardware version should be used, then - * EMBER_AF_INVALID_HARDWARE_VERSION should be used. Ver.: always - */ -void emberAfOtaClientVersionInfoCallback(EmberAfOtaImageId * currentImageInfo, uint16_t * hardwareVersion) -{ - // Customer will fill in the image info with their manufacturer ID, - // image type ID, and current software version number. - // The deviceSpecificFileEui64 can be ignored. - - // It may be necessary to dynamically determine this by talking to - // another device, as is the case with a host talking to an NCP device. - - // However, this routine will be called repeatedly so it may be wise - // to cache the data! - - /* This is commented out since the #defines below are not defined. - - if (currentImageInfo != NULL) { - MEMSET(currentImageInfo, 0, sizeof(EmberAfOtaImageId)); - currentImageInfo->manufacturerId = EMBER_AF_MANUFACTURER_CODE; - currentImageInfo->imageTypeId = EMBER_AF_IMAGE_TYPE_ID; - currentImageInfo->firmwareVersion = EMBER_AF_CUSTOM_FIRMWARE_VERSION; - } - - if (hardwareVersion != NULL) { - *hardwareVersion = EMBER_AF_INVALID_HARDWARE_VERSION; - } - - assert(false); - */ -} - -/** @brief Ota Page Request Server Policy - * - * This callback is called by the OTA server page request code when it wants to - * determine if it is allowed for an OTA client to make a page request. It is - * only called if page request support has been enabled on the server. It - * should return EMBER_ZCL_STATUS_SUCCESS if it allows the page request, and - * EMBER_ZCL_STATUS_UNSUP_CLUSTER_COMMAND if it does not want to allow it. - * - */ -uint8_t emberAfOtaPageRequestServerPolicyCallback(void) -{ - return EMBER_ZCL_STATUS_SUCCESS; -} - -/** @brief Ota Server Block Size - * - * This function provides a way for the server to adjust the block size of its - * response to an Image block request by a client. - * - * @param clientNodeId The node Id of OTA client making an image block request. - * Ver.: always - */ -uint8_t emberAfOtaServerBlockSizeCallback(EmberNodeId clientNodeId) -{ - // This function provides a way for the server to potentially - // adjust the block size based on the client who is requesting. - // In other words if we are using source routing we will limit - // data returned by enough to put a source route into the message. - - // Image Block Response Message Format - // Status Code: 1-byte - // Manuf Code: 2-bytes - // Image Type: 2-bytes - // File Ver: 4-bytes - // File Offset: 4-bytes - // Data Size: 1-byte - // Data: variable - const uint8_t IMAGE_BLOCK_RESPONSE_OVERHEAD = (EMBER_AF_ZCL_OVERHEAD + 14); - - EmberApsFrame apsFrame; - uint8_t maxSize; - apsFrame.options = EMBER_APS_OPTION_NONE; - - if (emberAfIsCurrentSecurityProfileSmartEnergy()) - { - apsFrame.options |= EMBER_APS_OPTION_ENCRYPTION; - } - - maxSize = emberAfMaximumApsPayloadLength(EMBER_OUTGOING_DIRECT, clientNodeId, &apsFrame); - maxSize -= IMAGE_BLOCK_RESPONSE_OVERHEAD; - return maxSize; -} - -/** @brief Ota Server Incoming Message Raw - * - * This callback is for processing incoming messages for the Over-the-air - * bootload cluster server. ZCL will not process the message and instead hand - * the raw over the air data to the callback for its own processing. - * - * @param message A pointer to the structure containing the message buffer and - * other information about it. Ver.: always - */ -bool emberAfOtaServerIncomingMessageRawCallback(EmberAfClusterCommand * message) -{ - return false; -} - -/** @brief Ota Server Query - * - * This callback is fired when the OTA server receives a query request by the - * client. The callback lets the server application indicate to the client what - * the 'next' version of software is for the device, or if there is not one - * available. - * - * @param currentImageId This is the current software image that the client - * hase. Ver.: always - * @param hardwareVersion If this value is non-NULL, it indicates the hardware - * version of the client device. If NULL, the client did not specify a hardware - * version. Ver.: always - * @param nextUpgradeImageId This is a pointer to a data structure containing - * the 'next' software version for the client to download. Ver.: always - */ -uint8_t emberAfOtaServerQueryCallback(const EmberAfOtaImageId * currentImageId, uint16_t * hardwareVersion, - EmberAfOtaImageId * nextUpgradeImageId) -{ - // If a new software image is available, this function should return EMBER_ZCL_STATUS_SUCCESS - // and populate the 'nextUpgradeImageId' structure with the appropriate values. - // If no new software image is available (i.e. the client should not download a firmware image) - // then the server should return EMBER_ZCL_STATUS_NO_IMAGE_AVAILABLE. - return EMBER_ZCL_STATUS_NO_IMAGE_AVAILABLE; -} - -/** @brief Ota Server Send Image Notify - * - * This callback is an indication to the OTA server that it should send out - * notification about an OTA file that is available for download. - * - * @param dest The destination of the image notify message. May be a broadcast - * address. Ver.: always - * @param endpoint The destination endpoint of the image notify message. May be - * a broadcast endpoint. Ver.: always - * @param payloadType The type of data the image notify message will contain. 0 - * = no data. 1 = Manufacturer ID. 2 = Manufacturer ID and the image type ID. - * 3 = Manufacturer ID, image type ID, and firmware version. Ver.: always - * @param queryJitter The percentage of nodes that should respond to this - * message, from 1-100. On receipt of this message, each recipient will - * randomly choose a percentage and only query the server if their percentage is - * below this value. Ver.: always - * @param id The image information that will be put in the message. The data - * within this struct that will be appended to the message is determined by the - * previous 'payloadType' argument. Ver.: always - */ -bool emberAfOtaServerSendImageNotifyCallback(EmberNodeId dest, uint8_t endpoint, uint8_t payloadType, uint8_t queryJitter, - const EmberAfOtaImageId * id) -{ - return false; -} - -/** @brief Ota Server Upgrade End Request - * - * This function is called when the OTA server receives a request an upgrade end - * request. If the request indicated a successful download by the client, the - * server must tell the client when and if to upgrade to the downloaded image. - * - * @param source The node ID of the device that sent the upgrade end request. - * Ver.: always - * @param status This is the ZCL status sent by the client indicating the result - * of its attempt to download the new upgrade image. If the status is not - * EMBER_ZCL_STATUS_SUCCESS then this callback is merely informative and no - * response mesasge will be generated by the server. Ver.: always - * @param returnValue If the server returns true indicating that the client - * should apply the upgrade, this time value indicates when in the future the - * client should apply the upgrade. Ver.: always - * @param imageId This variable indicates the software version that the client - * successfully downloaded and is asking to upgrade to. Ver.: always - */ -bool emberAfOtaServerUpgradeEndRequestCallback(EmberNodeId source, uint8_t status, uint32_t * returnValue, - const EmberAfOtaImageId * imageId) -{ - // If the status value is not EMBER_ZCL_STATUS_SUCCESS, then this callback is - // merely informative and no response message will be generated by the server. - // If the server wants the client to NOT apply the upgrade, then it should - // return false. - // If the server wants the client to apply the upgrade, it should return true - // and set the 'returnValue' parameter to when it wants the client to - // apply the upgrade. There are three possible values: - // 0 = Apply the upgrade now - // 0xFFFFFFFF = Don't apply yet, ask again later. - // (anything-else) = Apply the upgrade X minutes from now. - *returnValue = 0; - return true; -} - -/** @brief Ota Storage Check Temp Data - * - * This callback will validate temporary data in the storage device to determine - * whether it is a complete file, a partially downloaded file, or there is no - * file present. When a complete or partial file is found it will return - * EMBER_AF_OTA_STORAGE_SUCCESS or EMBER_AF_OTA_STORAGE_PARTIAL_FILE_FOUND, - * respectively. In that case, the currentOffset, totalImageSize, and - * newFileInfo will be populated with data. When EMBER_AF_OTA_STORAGE_ERROR is - * returned, no temporary data is present. - * - * @param currentOffset A pointer to a value that will be written with the - * offset within the total file size that has been successfully stored in the - * storage device. This will indicate how much data has been currently - * dowloaded. Ver.: always - * @param totalImageSize A pointer to a value that will be written with the - * total image size of the OTA file when a download has completed. This does - * not indicate how much data has actually been downloaded currently. Ver.: - * always - * @param newFileInfo This is the image id of the temporary file data stored in - * the storage device. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageCheckTempDataCallback(uint32_t * currentOffset, uint32_t * totalImageSize, - EmberAfOtaImageId * newFileInfo) -{ - // If the image data cannot be successfully verified, an error should be returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Clear Temp Data - * - * This function clears any existing temp data that was downloaed. It is used - * immediately prior to downloading a raw image over the air. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageClearTempDataCallback(void) -{ - // If the image data cannot be stored, an error should be returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Close - * - * This callback shuts down the ZigBee Over-the-air storage module. - * - */ -void emberAfOtaStorageCloseCallback(void) -{ - // Please implement me. - assert(false); -} - -/** @brief Ota Storage Driver Download Finish - * - * This callback defines the low-level means by which a device records the final - * offset value of the download image. - * - * @param offset The value of the final offset of the image download. Ver.: - * always - */ -void emberAfOtaStorageDriverDownloadFinishCallback(uint32_t offset) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); -} - -/** @brief Ota Storage Driver Init - * - * The initialization code for the OTA storage driver. - * - */ -bool emberAfOtaStorageDriverInitCallback(void) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); - return false; -} - -/** @brief Ota Storage Driver Invalidate Image - * - * This callback invalidates the image stored on disk so that it will not be - * bootloaded, and it will not be a valid image that is in the middle of - * downloading. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageDriverInvalidateImageCallback(void) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Driver Prepare To Resume Download - * - * This callback allows the underlying storage driver to prepare to resume the - * OTA file download. For example, the driver may exceute a page erase to - * insure the next page is ready to be written to. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageDriverPrepareToResumeDownloadCallback(void) -{ - assert(false); - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Driver Read - * - * This callback defines the low-level means by which a device reads from the - * OTA storage device. - * - * @param offset The address offset from the start of the storage device where - * data is to be read. Ver.: always - * @param length The length of the data to be read from the storage device. - * Ver.: always - * @param returnData A pointer where the data read from the device should be - * written to. Ver.: always - */ -bool emberAfOtaStorageDriverReadCallback(uint32_t offset, uint32_t length, uint8_t * returnData) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); - return false; -} - -/** @brief Ota Storage Driver Retrieve Last Stored Offset - * - * This callback defines the low-level means by which a device retrieves the - * last persistently recorded download offset. This may be different than last - * actual download offset. - * - */ -uint32_t emberAfOtaStorageDriverRetrieveLastStoredOffsetCallback(void) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); - return 0; -} - -/** @brief Ota Storage Driver Write - * - * This callback defines the low-level means by which a device reads from the - * OTA storage device. - * - * @param dataToWrite A pointer to the data that will be written to the storage - * device. Ver.: always - * @param offset The address offset from the start of the storage device where - * data will be written. Ver.: always - * @param length The length of the data to be written to the storage device. - * Ver.: always - */ -bool emberAfOtaStorageDriverWriteCallback(const uint8_t * dataToWrite, uint32_t offset, uint32_t length) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); - return false; -} - -/** @brief Ota Storage Finish Download - * - * This function indicates to the storage module that the download has finished. - * - * @param offset The final offset of the downloaded file (i.e. the total size) - * Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageFinishDownloadCallback(uint32_t offset) -{ - return EMBER_AF_OTA_STORAGE_SUCCESS; -} - -/** @brief Ota Storage Get Count - * - * This callback returns the total number of ZigBee Over-the-air upgrade images - * stored in the storage module. - * - */ -uint8_t emberAfOtaStorageGetCountCallback(void) -{ - return 0; -} - -/** @brief Ota Storage Get Full Header - * - * This callback populates the EmberAfOtaHeader structure pointed to by the - * returnData with data about the OTA file stored in the storage module. - * - * @param id This is a pointer to the image id for the OTA file to retrieve - * information about. Ver.: always - * @param returnData This is a pointer to the location of the structure that - * will be populated with data. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageGetFullHeaderCallback(const EmberAfOtaImageId * id, EmberAfOtaHeader * returnData) -{ - // If the requested image cannot be found, then an error shouldb e returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Get Total Image Size - * - * This function returns the total size of the ZigBee Over-the-air file with the - * passed parameters. If no file is found with those parameters, 0 is returned. - * - * @param id A pointer to the image identifier for the OTA file to retrieve - * information for. Ver.: always - */ -uint32_t emberAfOtaStorageGetTotalImageSizeCallback(const EmberAfOtaImageId * id) -{ - // On failure this should return an image size of zero. - return 0; -} - -/** @brief Ota Storage Init - * - * This callback initializes the ZigBee Over-the-air storage module. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageInitCallback(void) -{ - return EMBER_AF_OTA_STORAGE_SUCCESS; -} - -/** @brief Ota Storage Iterator First - * - * This callback lets you walk through the list of all OTA files by jumping to - * the first file in the list maintained by the storage module. If there is no - * file then emberAfOtaInvalidImageId is returned. - * - */ -EmberAfOtaImageId emberAfOtaStorageIteratorFirstCallback(void) -{ - // It is expected that the storage module maintain its own internal iterator that the 'first' and 'next' functions will - // manipulate. - - // If there are no images at all, this function should return the invalid image id. - return emberAfInvalidImageId; -} - -/** @brief Ota Storage Iterator Next - * - * This callback lets you walk through the list of all OTA files by jumping to - * the next file in the list maintained by the storage module. If there is no - * next file then emberAfOtaInvalidImageId is returned. - * - */ -EmberAfOtaImageId emberAfOtaStorageIteratorNextCallback(void) -{ - // It is expected that the storage module maintain its own internal iterator that the 'first' and 'next' functions will - // manipulate. - - // If there are no more images, this function should return the invalid image id. - return emberAfInvalidImageId; -} - -/** @brief Ota Storage Read Image Data - * - * This callback reads data from the specified OTA file and returns that data to - * the caller. - * - * @param id This is a pointer to the image id for the OTA file to retrieve data - * from. Ver.: always - * @param offset This is the offset relative to the start of the image where the - * data should be read from. Ver.: always - * @param length This is the length of data that will be read. Ver.: always - * @param returnData This is a pointer to where the data read out of the file - * will be written to Ver.: always - * @param returnedLength This is a pointer to a variable where the actual length - * of data read will be written to. A short read may occur if the end of file - * was reached. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageReadImageDataCallback(const EmberAfOtaImageId * id, uint32_t offset, uint32_t length, - uint8_t * returnData, uint32_t * returnedLength) -{ - // If the requested image cannot be found, then an error should be returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Search - * - * This callback searches through the list of all images for one that matches - * the passed parameters. On success an image identifier is returned with a - * matching image. On failure emberAfInvalidImageId is returned. - * - * @param manufacturerId The ZigBee assigned identifier of the manufacturer - * contained in the OTA image being searched for. Ver.: always - * @param imageTypeId The image type identifier contained in the OTA image being - * searched for. Ver.: always - * @param hardwareVersion This is a pointer to the hardware version that will be - * used in the search. If the pointer is NULL, hardware version will not be - * considered when searching for matching images. If it points to a value, the - * search will only consider images where that value falls between the minimum - * and maxmimum hardware version specified in the OTA file. If no hardware - * version is present in an OTA file but the other parameters match, the file - * will be considered a match Ver.: always - */ -EmberAfOtaImageId emberAfOtaStorageSearchCallback(uint16_t manufacturerId, uint16_t imageTypeId, const uint16_t * hardwareVersion) -{ - // If no image is found that matches the search criteria, this function should return the invalid image id. - return emberAfInvalidImageId; -} - -/** @brief Ota Storage Write Temp Data - * - * This function writes to the temporary data in the storage device at the - * specified offset. It is used when downloading a raw image over the air. - * - * @param offset The location within the download image file where to write the - * data. Ver.: always - * @param length The length of data to write. Ver.: always - * @param data A pointer to the temporary data that will be written to the - * storage device. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageWriteTempDataCallback(uint32_t offset, uint32_t length, const uint8_t * data) -{ - // If the image data cannot be stored, an error should be returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - /** @brief Outgoing Packet Filter * * ** REQUIRES INCLUDING THE PACKET-HANDOFF PLUGIN ** diff --git a/examples/lighting-app/efr32/src/gen/callback.h b/examples/lighting-app/efr32/src/gen/callback.h index 97a07d0e7dd08a..6747dfa91a1f43 100644 --- a/examples/lighting-app/efr32/src/gen/callback.h +++ b/examples/lighting-app/efr32/src/gen/callback.h @@ -814,384 +814,6 @@ void emberAfNetworkFoundCallback(EmberZigbeeNetwork * networkFound, uint8_t lqi, * @param status Ver.: always */ void emberAfNetworkKeyUpdateCompleteCallback(EmberStatus status); -/** @brief Ota Bootload - * - * The platform specific routine to bootload the device from a ZigBee - * over-the-air upgrade file. - * - * @param id A pointer to the structure that contains the information about what - * OTA image to bootload. Ver.: always - * @param ncpUpgradeTagId The tag ID of the upgrade data that will be used to - * bootload the device. Ver.: always - */ -uint8_t emberAfOtaBootloadCallback(const EmberAfOtaImageId * id, uint16_t ncpUpgradeTagId); -/** @brief Ota Client Bootload - * - * This callback is fired when the OTA Client recevies a command to bootload the - * newly downloaded OTA image. This callback will perform the platform specific - * to bootload their device. - * - * @param id This is the identifier relating to the image that has been - * downloaded and is ready for bootload. Ver.: always - */ -void emberAfOtaClientBootloadCallback(const EmberAfOtaImageId * id); -/** @brief Ota Client Custom Verify - * - * This callback is executed by the OTA client after the signature verification - * has successfully completed. It allows the device to do its own custom - * verification of the image (such as verifying that the EBL is intact). - * - * @param newVerification This indicates if a new verification should be - * started. Ver.: always - * @param id This is ID of the image to be verified. Ver.: always - */ -EmberAfImageVerifyStatus emberAfOtaClientCustomVerifyCallback(bool newVerification, const EmberAfOtaImageId * id); -/** @brief Ota Client Download Complete - * - * This callback indicates that the OTA client has completed the download of a - * file. If the file has been completely downloaded and cryptographic checks - * have been turned on, then those will be performed prior to this callback and - * that outcome included in the 'success' result. On failure, this callback is - * merely informative, and the return type is ignored. On succesful download, - * this callback allows the client to perform any additional verification of the - * downloaded image and return that result to the OTA server. - * - * @param success This indicates the success or failure of the download and - * cryptographic verification process (if applicable). Ver.: always - * @param id This is the image identifier information that corresponds to the - * download result. Ver.: always - */ -bool emberAfOtaClientDownloadCompleteCallback(EmberAfOtaDownloadResult success, const EmberAfOtaImageId * id); -/** @brief Ota Client Incoming Message Raw - * - * This callback is for processing incoming messages for the Over-the-air - * bootload cluster client. ZCL will not process the message and instead hand - * the raw over the air data to the callback for its own processing. - * - * @param message A pointer to the structure containing the message buffer and - * other information about it. Ver.: always - */ -bool emberAfOtaClientIncomingMessageRawCallback(EmberAfClusterCommand * message); -/** @brief Ota Client Start - * - * This callback should be called when the profile specific registration has - * completed successfully. It will start the client's state machine that will - * find the OTA server, query it for the next image, download the image, wait - * for the bootload message, and kick off the bootload. - * - */ -void emberAfOtaClientStartCallback(void); -/** @brief Ota Client Version Info - * - * This function is called by the OTA client when a new query will occur to the - * server asking what the next version of firmware is. The client can inform - * the cluster software as to what information to use in the query (and - * subsequent download). - * - * @param currentImageInfo This is the information to use in the next query by - * the client cluster code. It contains the manufacturer ID, image type ID, and - * the firmware version to be specified in the query message sent to the server. - * Ver.: always - * @param hardwareVersion This is a pointer to the hardware version to use in - * the query. If no hardware version should be used, then - * EMBER_AF_INVALID_HARDWARE_VERSION should be used. Ver.: always - */ -void emberAfOtaClientVersionInfoCallback(EmberAfOtaImageId * currentImageInfo, uint16_t * hardwareVersion); -/** @brief Ota Page Request Server Policy - * - * This callback is called by the OTA server page request code when it wants to - * determine if it is allowed for an OTA client to make a page request. It is - * only called if page request support has been enabled on the server. It - * should return EMBER_ZCL_STATUS_SUCCESS if it allows the page request, and - * EMBER_ZCL_STATUS_UNSUP_CLUSTER_COMMAND if it does not want to allow it. - * - */ -uint8_t emberAfOtaPageRequestServerPolicyCallback(void); -/** @brief Ota Server Block Size - * - * This function provides a way for the server to adjust the block size of its - * response to an Image block request by a client. - * - * @param clientNodeId The node Id of OTA client making an image block request. - * Ver.: always - */ -uint8_t emberAfOtaServerBlockSizeCallback(EmberNodeId clientNodeId); -/** @brief Ota Server Incoming Message Raw - * - * This callback is for processing incoming messages for the Over-the-air - * bootload cluster server. ZCL will not process the message and instead hand - * the raw over the air data to the callback for its own processing. - * - * @param message A pointer to the structure containing the message buffer and - * other information about it. Ver.: always - */ -bool emberAfOtaServerIncomingMessageRawCallback(EmberAfClusterCommand * message); -/** @brief Ota Server Query - * - * This callback is fired when the OTA server receives a query request by the - * client. The callback lets the server application indicate to the client what - * the 'next' version of software is for the device, or if there is not one - * available. - * - * @param currentImageId This is the current software image that the client - * hase. Ver.: always - * @param hardwareVersion If this value is non-NULL, it indicates the hardware - * version of the client device. If NULL, the client did not specify a hardware - * version. Ver.: always - * @param nextUpgradeImageId This is a pointer to a data structure containing - * the 'next' software version for the client to download. Ver.: always - */ -uint8_t emberAfOtaServerQueryCallback(const EmberAfOtaImageId * currentImageId, uint16_t * hardwareVersion, - EmberAfOtaImageId * nextUpgradeImageId); -/** @brief Ota Server Send Image Notify - * - * This callback is an indication to the OTA server that it should send out - * notification about an OTA file that is available for download. - * - * @param dest The destination of the image notify message. May be a broadcast - * address. Ver.: always - * @param endpoint The destination endpoint of the image notify message. May be - * a broadcast endpoint. Ver.: always - * @param payloadType The type of data the image notify message will contain. 0 - * = no data. 1 = Manufacturer ID. 2 = Manufacturer ID and the image type ID. - * 3 = Manufacturer ID, image type ID, and firmware version. Ver.: always - * @param queryJitter The percentage of nodes that should respond to this - * message, from 1-100. On receipt of this message, each recipient will - * randomly choose a percentage and only query the server if their percentage is - * below this value. Ver.: always - * @param id The image information that will be put in the message. The data - * within this struct that will be appended to the message is determined by the - * previous 'payloadType' argument. Ver.: always - */ -bool emberAfOtaServerSendImageNotifyCallback(EmberNodeId dest, uint8_t endpoint, uint8_t payloadType, uint8_t queryJitter, - const EmberAfOtaImageId * id); -/** @brief Ota Server Upgrade End Request - * - * This function is called when the OTA server receives a request an upgrade end - * request. If the request indicated a successful download by the client, the - * server must tell the client when and if to upgrade to the downloaded image. - * - * @param source The node ID of the device that sent the upgrade end request. - * Ver.: always - * @param status This is the ZCL status sent by the client indicating the result - * of its attempt to download the new upgrade image. If the status is not - * EMBER_ZCL_STATUS_SUCCESS then this callback is merely informative and no - * response mesasge will be generated by the server. Ver.: always - * @param returnValue If the server returns true indicating that the client - * should apply the upgrade, this time value indicates when in the future the - * client should apply the upgrade. Ver.: always - * @param imageId This variable indicates the software version that the client - * successfully downloaded and is asking to upgrade to. Ver.: always - */ -bool emberAfOtaServerUpgradeEndRequestCallback(EmberNodeId source, uint8_t status, uint32_t * returnValue, - const EmberAfOtaImageId * imageId); -/** @brief Ota Storage Check Temp Data - * - * This callback will validate temporary data in the storage device to determine - * whether it is a complete file, a partially downloaded file, or there is no - * file present. When a complete or partial file is found it will return - * EMBER_AF_OTA_STORAGE_SUCCESS or EMBER_AF_OTA_STORAGE_PARTIAL_FILE_FOUND, - * respectively. In that case, the currentOffset, totalImageSize, and - * newFileInfo will be populated with data. When EMBER_AF_OTA_STORAGE_ERROR is - * returned, no temporary data is present. - * - * @param currentOffset A pointer to a value that will be written with the - * offset within the total file size that has been successfully stored in the - * storage device. This will indicate how much data has been currently - * dowloaded. Ver.: always - * @param totalImageSize A pointer to a value that will be written with the - * total image size of the OTA file when a download has completed. This does - * not indicate how much data has actually been downloaded currently. Ver.: - * always - * @param newFileInfo This is the image id of the temporary file data stored in - * the storage device. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageCheckTempDataCallback(uint32_t * currentOffset, uint32_t * totalImageSize, - EmberAfOtaImageId * newFileInfo); -/** @brief Ota Storage Clear Temp Data - * - * This function clears any existing temp data that was downloaed. It is used - * immediately prior to downloading a raw image over the air. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageClearTempDataCallback(void); -/** @brief Ota Storage Close - * - * This callback shuts down the ZigBee Over-the-air storage module. - * - */ -void emberAfOtaStorageCloseCallback(void); -/** @brief Ota Storage Driver Download Finish - * - * This callback defines the low-level means by which a device records the final - * offset value of the download image. - * - * @param offset The value of the final offset of the image download. Ver.: - * always - */ -void emberAfOtaStorageDriverDownloadFinishCallback(uint32_t offset); -/** @brief Ota Storage Driver Init - * - * The initialization code for the OTA storage driver. - * - */ -bool emberAfOtaStorageDriverInitCallback(void); -/** @brief Ota Storage Driver Invalidate Image - * - * This callback invalidates the image stored on disk so that it will not be - * bootloaded, and it will not be a valid image that is in the middle of - * downloading. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageDriverInvalidateImageCallback(void); -/** @brief Ota Storage Driver Prepare To Resume Download - * - * This callback allows the underlying storage driver to prepare to resume the - * OTA file download. For example, the driver may exceute a page erase to - * insure the next page is ready to be written to. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageDriverPrepareToResumeDownloadCallback(void); -/** @brief Ota Storage Driver Read - * - * This callback defines the low-level means by which a device reads from the - * OTA storage device. - * - * @param offset The address offset from the start of the storage device where - * data is to be read. Ver.: always - * @param length The length of the data to be read from the storage device. - * Ver.: always - * @param returnData A pointer where the data read from the device should be - * written to. Ver.: always - */ -bool emberAfOtaStorageDriverReadCallback(uint32_t offset, uint32_t length, uint8_t * returnData); -/** @brief Ota Storage Driver Retrieve Last Stored Offset - * - * This callback defines the low-level means by which a device retrieves the - * last persistently recorded download offset. This may be different than last - * actual download offset. - * - */ -uint32_t emberAfOtaStorageDriverRetrieveLastStoredOffsetCallback(void); -/** @brief Ota Storage Driver Write - * - * This callback defines the low-level means by which a device reads from the - * OTA storage device. - * - * @param dataToWrite A pointer to the data that will be written to the storage - * device. Ver.: always - * @param offset The address offset from the start of the storage device where - * data will be written. Ver.: always - * @param length The length of the data to be written to the storage device. - * Ver.: always - */ -bool emberAfOtaStorageDriverWriteCallback(const uint8_t * dataToWrite, uint32_t offset, uint32_t length); -/** @brief Ota Storage Finish Download - * - * This function indicates to the storage module that the download has finished. - * - * @param offset The final offset of the downloaded file (i.e. the total size) - * Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageFinishDownloadCallback(uint32_t offset); -/** @brief Ota Storage Get Count - * - * This callback returns the total number of ZigBee Over-the-air upgrade images - * stored in the storage module. - * - */ -uint8_t emberAfOtaStorageGetCountCallback(void); -/** @brief Ota Storage Get Full Header - * - * This callback populates the EmberAfOtaHeader structure pointed to by the - * returnData with data about the OTA file stored in the storage module. - * - * @param id This is a pointer to the image id for the OTA file to retrieve - * information about. Ver.: always - * @param returnData This is a pointer to the location of the structure that - * will be populated with data. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageGetFullHeaderCallback(const EmberAfOtaImageId * id, EmberAfOtaHeader * returnData); -/** @brief Ota Storage Get Total Image Size - * - * This function returns the total size of the ZigBee Over-the-air file with the - * passed parameters. If no file is found with those parameters, 0 is returned. - * - * @param id A pointer to the image identifier for the OTA file to retrieve - * information for. Ver.: always - */ -uint32_t emberAfOtaStorageGetTotalImageSizeCallback(const EmberAfOtaImageId * id); -/** @brief Ota Storage Init - * - * This callback initializes the ZigBee Over-the-air storage module. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageInitCallback(void); -/** @brief Ota Storage Iterator First - * - * This callback lets you walk through the list of all OTA files by jumping to - * the first file in the list maintained by the storage module. If there is no - * file then emberAfOtaInvalidImageId is returned. - * - */ -EmberAfOtaImageId emberAfOtaStorageIteratorFirstCallback(void); -/** @brief Ota Storage Iterator Next - * - * This callback lets you walk through the list of all OTA files by jumping to - * the next file in the list maintained by the storage module. If there is no - * next file then emberAfOtaInvalidImageId is returned. - * - */ -EmberAfOtaImageId emberAfOtaStorageIteratorNextCallback(void); -/** @brief Ota Storage Read Image Data - * - * This callback reads data from the specified OTA file and returns that data to - * the caller. - * - * @param id This is a pointer to the image id for the OTA file to retrieve data - * from. Ver.: always - * @param offset This is the offset relative to the start of the image where the - * data should be read from. Ver.: always - * @param length This is the length of data that will be read. Ver.: always - * @param returnData This is a pointer to where the data read out of the file - * will be written to Ver.: always - * @param returnedLength This is a pointer to a variable where the actual length - * of data read will be written to. A short read may occur if the end of file - * was reached. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageReadImageDataCallback(const EmberAfOtaImageId * id, uint32_t offset, uint32_t length, - uint8_t * returnData, uint32_t * returnedLength); -/** @brief Ota Storage Search - * - * This callback searches through the list of all images for one that matches - * the passed parameters. On success an image identifier is returned with a - * matching image. On failure emberAfInvalidImageId is returned. - * - * @param manufacturerId The ZigBee assigned identifier of the manufacturer - * contained in the OTA image being searched for. Ver.: always - * @param imageTypeId The image type identifier contained in the OTA image being - * searched for. Ver.: always - * @param hardwareVersion This is a pointer to the hardware version that will be - * used in the search. If the pointer is NULL, hardware version will not be - * considered when searching for matching images. If it points to a value, the - * search will only consider images where that value falls between the minimum - * and maxmimum hardware version specified in the OTA file. If no hardware - * version is present in an OTA file but the other parameters match, the file - * will be considered a match Ver.: always - */ -EmberAfOtaImageId emberAfOtaStorageSearchCallback(uint16_t manufacturerId, uint16_t imageTypeId, const uint16_t * hardwareVersion); -/** @brief Ota Storage Write Temp Data - * - * This function writes to the temporary data in the storage device at the - * specified offset. It is used when downloading a raw image over the air. - * - * @param offset The location within the download image file where to write the - * data. Ver.: always - * @param length The length of data to write. Ver.: always - * @param data A pointer to the temporary data that will be written to the - * storage device. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageWriteTempDataCallback(uint32_t offset, uint32_t length, const uint8_t * data); /** @brief Outgoing Packet Filter * * ** REQUIRES INCLUDING THE PACKET-HANDOFF PLUGIN ** diff --git a/examples/lighting-app/lighting-common/gen/callback-stub.c b/examples/lighting-app/lighting-common/gen/callback-stub.c index 7b070c5b6b2c72..d9ce280618036c 100644 --- a/examples/lighting-app/lighting-common/gen/callback-stub.c +++ b/examples/lighting-app/lighting-common/gen/callback-stub.c @@ -137,15 +137,6 @@ bool emberAfAttributeWriteAccessCallback(uint8_t endpoint, EmberAfClusterId clus */ void emberAfGroupsClusterClearGroupTableCallback(uint8_t endpoint) {} -/** @brief Scenes Cluster ClearSceneTable - * - * This function is called by the framework when the application should clear - * the scene table. - * - * @param endpoint The endpoint. Ver.: always - */ -void emberAfScenesClusterClearSceneTableCallback(uint8_t endpoint) {} - /** @brief Key Establishment Cluster Client Command Received * * This function is called by the application framework when a server-to-client @@ -1000,642 +991,6 @@ void emberAfNcpIsAwakeIsrCallback(void) {} */ void emberAfNetworkKeyUpdateCompleteCallback(EmberStatus status) {} -/** @brief Ota Bootload - * - * The platform specific routine to bootload the device from a ZigBee - * over-the-air upgrade file. - * - * @param id A pointer to the structure that contains the information about what - * OTA image to bootload. Ver.: always - * @param ncpUpgradeTagId The tag ID of the upgrade data that will be used to - * bootload the device. Ver.: always - */ -uint8_t emberAfOtaBootloadCallback(const EmberAfOtaImageId * id, uint16_t ncpUpgradeTagId) -{ - // Please implement me - emberAfCorePrintln("Not supported."); - return 1; -} - -/** @brief Ota Client Bootload - * - * This callback is fired when the OTA Client recevies a command to bootload the - * newly downloaded OTA image. This callback will perform the platform specific - * to bootload their device. - * - * @param id This is the identifier relating to the image that has been - * downloaded and is ready for bootload. Ver.: always - */ -void emberAfOtaClientBootloadCallback(const EmberAfOtaImageId * id) -{ - // Any final preperation prior to the bootload should be done here. - // It is assumed that the device will reset in most all cases. - // Please implement me. -} - -/** @brief Ota Client Custom Verify - * - * This callback is executed by the OTA client after the signature verification - * has successfully completed. It allows the device to do its own custom - * verification of the image (such as verifying that the EBL is intact). - * - * @param newVerification This indicates if a new verification should be - * started. Ver.: always - * @param id This is ID of the image to be verified. Ver.: always - */ -EmberAfImageVerifyStatus emberAfOtaClientCustomVerifyCallback(bool newVerification, const EmberAfOtaImageId * id) -{ - // Manufacturing specific checks can be made to the image in this function to - // determine if it is valid. This function is called AFTER cryptographic - // checks have passed. If the cryptographic checks failed, this function will - // never be called. - - // The function shall return one of the following based on its own - // verification process. - // 1) EMBER_AF_IMAGE_GOOD - the image has passed all checks - // 2) EMBER_AF_IMAGE_BAD - the image is not valid - // 3) EMBER_AF_IMAGE_VERIFY_IN_PROGRESS - the image is valid so far, but more - // checks are needed. This callback shall be re-executed later to - // continue verification. This allows other code in the framework to run. - return EMBER_AF_IMAGE_GOOD; -} - -/** @brief Ota Client Download Complete - * - * This callback indicates that the OTA client has completed the download of a - * file. If the file has been completely downloaded and cryptographic checks - * have been turned on, then those will be performed prior to this callback and - * that outcome included in the 'success' result. On failure, this callback is - * merely informative, and the return type is ignored. On succesful download, - * this callback allows the client to perform any additional verification of the - * downloaded image and return that result to the OTA server. - * - * @param success This indicates the success or failure of the download and - * cryptographic verification process (if applicable). Ver.: always - * @param id This is the image identifier information that corresponds to the - * download result. Ver.: always - */ -bool emberAfOtaClientDownloadCompleteCallback(EmberAfOtaDownloadResult success, const EmberAfOtaImageId * id) -{ - // At this point the image has been completely downloaded and cryptographic - // checks (if applicable) have been performed. - - if (!success) - { - emberAfOtaBootloadClusterPrintln("Download failed."); - return true; // return value is ignored - } - - // This is for any additional validation that needs to be performed - // on the image by the application. - - // The results of checks here will be returned back to the OTA server - // in the Upgrade End request. - return true; -} - -/** @brief Ota Client Incoming Message Raw - * - * This callback is for processing incoming messages for the Over-the-air - * bootload cluster client. ZCL will not process the message and instead hand - * the raw over the air data to the callback for its own processing. - * - * @param message A pointer to the structure containing the message buffer and - * other information about it. Ver.: always - */ -bool emberAfOtaClientIncomingMessageRawCallback(EmberAfClusterCommand * message) -{ - return false; -} - -/** @brief Ota Client Start - * - * This callback should be called when the profile specific registration has - * completed successfully. It will start the client's state machine that will - * find the OTA server, query it for the next image, download the image, wait - * for the bootload message, and kick off the bootload. - * - */ -void emberAfOtaClientStartCallback(void) {} - -/** @brief Ota Client Version Info - * - * This function is called by the OTA client when a new query will occur to the - * server asking what the next version of firmware is. The client can inform - * the cluster software as to what information to use in the query (and - * subsequent download). - * - * @param currentImageInfo This is the information to use in the next query by - * the client cluster code. It contains the manufacturer ID, image type ID, and - * the firmware version to be specified in the query message sent to the server. - * Ver.: always - * @param hardwareVersion This is a pointer to the hardware version to use in - * the query. If no hardware version should be used, then - * EMBER_AF_INVALID_HARDWARE_VERSION should be used. Ver.: always - */ -void emberAfOtaClientVersionInfoCallback(EmberAfOtaImageId * currentImageInfo, uint16_t * hardwareVersion) -{ - // Customer will fill in the image info with their manufacturer ID, - // image type ID, and current software version number. - // The deviceSpecificFileEui64 can be ignored. - - // It may be necessary to dynamically determine this by talking to - // another device, as is the case with a host talking to an NCP device. - - // However, this routine will be called repeatedly so it may be wise - // to cache the data! - - /* This is commented out since the #defines below are not defined. - - if (currentImageInfo != NULL) { - memset(currentImageInfo, 0, sizeof(EmberAfOtaImageId)); - currentImageInfo->manufacturerId = EMBER_AF_MANUFACTURER_CODE; - currentImageInfo->imageTypeId = EMBER_AF_IMAGE_TYPE_ID; - currentImageInfo->firmwareVersion = EMBER_AF_CUSTOM_FIRMWARE_VERSION; - } - - if (hardwareVersion != NULL) { - *hardwareVersion = EMBER_AF_INVALID_HARDWARE_VERSION; - } - - assert(false); - */ -} - -/** @brief Ota Page Request Server Policy - * - * This callback is called by the OTA server page request code when it wants to - * determine if it is allowed for an OTA client to make a page request. It is - * only called if page request support has been enabled on the server. It - * should return EMBER_ZCL_STATUS_SUCCESS if it allows the page request, and - * EMBER_ZCL_STATUS_UNSUP_CLUSTER_COMMAND if it does not want to allow it. - * - */ -uint8_t emberAfOtaPageRequestServerPolicyCallback(void) -{ - return EMBER_ZCL_STATUS_SUCCESS; -} - -/** @brief Ota Server Block Size - * - * This function provides a way for the server to adjust the block size of its - * response to an Image block request by a client. - * - * @param clientNodeId The node Id of OTA client making an image block request. - * Ver.: always - */ -uint8_t emberAfOtaServerBlockSizeCallback(EmberNodeId clientNodeId) -{ - // This function provides a way for the server to potentially - // adjust the block size based on the client who is requesting. - // In other words if we are using source routing we will limit - // data returned by enough to put a source route into the message. - - // Image Block Response Message Format - // Status Code: 1-byte - // Manuf Code: 2-bytes - // Image Type: 2-bytes - // File Ver: 4-bytes - // File Offset: 4-bytes - // Data Size: 1-byte - // Data: variable - const uint8_t IMAGE_BLOCK_RESPONSE_OVERHEAD = (EMBER_AF_ZCL_OVERHEAD + 14); - - EmberApsFrame apsFrame; - uint8_t maxSize; - apsFrame.options = EMBER_APS_OPTION_NONE; - - if (emberAfIsCurrentSecurityProfileSmartEnergy()) - { - apsFrame.options |= EMBER_APS_OPTION_ENCRYPTION; - } - - maxSize = emberAfMaximumApsPayloadLength(EMBER_OUTGOING_DIRECT, clientNodeId, &apsFrame); - maxSize -= IMAGE_BLOCK_RESPONSE_OVERHEAD; - return maxSize; -} - -/** @brief Ota Server Incoming Message Raw - * - * This callback is for processing incoming messages for the Over-the-air - * bootload cluster server. ZCL will not process the message and instead hand - * the raw over the air data to the callback for its own processing. - * - * @param message A pointer to the structure containing the message buffer and - * other information about it. Ver.: always - */ -bool emberAfOtaServerIncomingMessageRawCallback(EmberAfClusterCommand * message) -{ - return false; -} - -/** @brief Ota Server Query - * - * This callback is fired when the OTA server receives a query request by the - * client. The callback lets the server application indicate to the client what - * the 'next' version of software is for the device, or if there is not one - * available. - * - * @param currentImageId This is the current software image that the client - * hase. Ver.: always - * @param hardwareVersion If this value is non-NULL, it indicates the hardware - * version of the client device. If NULL, the client did not specify a hardware - * version. Ver.: always - * @param nextUpgradeImageId This is a pointer to a data structure containing - * the 'next' software version for the client to download. Ver.: always - */ -uint8_t emberAfOtaServerQueryCallback(const EmberAfOtaImageId * currentImageId, uint16_t * hardwareVersion, - EmberAfOtaImageId * nextUpgradeImageId) -{ - // If a new software image is available, this function should return EMBER_ZCL_STATUS_SUCCESS - // and populate the 'nextUpgradeImageId' structure with the appropriate values. - // If no new software image is available (i.e. the client should not download a firmware image) - // then the server should return EMBER_ZCL_STATUS_NO_IMAGE_AVAILABLE. - return EMBER_ZCL_STATUS_NO_IMAGE_AVAILABLE; -} - -/** @brief Ota Server Send Image Notify - * - * This callback is an indication to the OTA server that it should send out - * notification about an OTA file that is available for download. - * - * @param dest The destination of the image notify message. May be a broadcast - * address. Ver.: always - * @param endpoint The destination endpoint of the image notify message. May be - * a broadcast endpoint. Ver.: always - * @param payloadType The type of data the image notify message will contain. 0 - * = no data. 1 = Manufacturer ID. 2 = Manufacturer ID and the image type ID. - * 3 = Manufacturer ID, image type ID, and firmware version. Ver.: always - * @param queryJitter The percentage of nodes that should respond to this - * message, from 1-100. On receipt of this message, each recipient will - * randomly choose a percentage and only query the server if their percentage is - * below this value. Ver.: always - * @param id The image information that will be put in the message. The data - * within this struct that will be appended to the message is determined by the - * previous 'payloadType' argument. Ver.: always - */ -bool emberAfOtaServerSendImageNotifyCallback(EmberNodeId dest, uint8_t endpoint, uint8_t payloadType, uint8_t queryJitter, - const EmberAfOtaImageId * id) -{ - return false; -} - -/** @brief Ota Server Upgrade End Request - * - * This function is called when the OTA server receives a request an upgrade end - * request. If the request indicated a successful download by the client, the - * server must tell the client when and if to upgrade to the downloaded image. - * - * @param source The node ID of the device that sent the upgrade end request. - * Ver.: always - * @param status This is the ZCL status sent by the client indicating the result - * of its attempt to download the new upgrade image. If the status is not - * EMBER_ZCL_STATUS_SUCCESS then this callback is merely informative and no - * response mesasge will be generated by the server. Ver.: always - * @param returnValue If the server returns true indicating that the client - * should apply the upgrade, this time value indicates when in the future the - * client should apply the upgrade. Ver.: always - * @param imageId This variable indicates the software version that the client - * successfully downloaded and is asking to upgrade to. Ver.: always - */ -bool emberAfOtaServerUpgradeEndRequestCallback(EmberNodeId source, uint8_t status, uint32_t * returnValue, - const EmberAfOtaImageId * imageId) -{ - // If the status value is not EMBER_ZCL_STATUS_SUCCESS, then this callback is - // merely informative and no response message will be generated by the server. - // If the server wants the client to NOT apply the upgrade, then it should - // return false. - // If the server wants the client to apply the upgrade, it should return true - // and set the 'returnValue' parameter to when it wants the client to - // apply the upgrade. There are three possible values: - // 0 = Apply the upgrade now - // 0xFFFFFFFF = Don't apply yet, ask again later. - // (anything-else) = Apply the upgrade X minutes from now. - *returnValue = 0; - return true; -} - -/** @brief Ota Storage Check Temp Data - * - * This callback will validate temporary data in the storage device to determine - * whether it is a complete file, a partially downloaded file, or there is no - * file present. When a complete or partial file is found it will return - * EMBER_AF_OTA_STORAGE_SUCCESS or EMBER_AF_OTA_STORAGE_PARTIAL_FILE_FOUND, - * respectively. In that case, the currentOffset, totalImageSize, and - * newFileInfo will be populated with data. When EMBER_AF_OTA_STORAGE_ERROR is - * returned, no temporary data is present. - * - * @param currentOffset A pointer to a value that will be written with the - * offset within the total file size that has been successfully stored in the - * storage device. This will indicate how much data has been currently - * dowloaded. Ver.: always - * @param totalImageSize A pointer to a value that will be written with the - * total image size of the OTA file when a download has completed. This does - * not indicate how much data has actually been downloaded currently. Ver.: - * always - * @param newFileInfo This is the image id of the temporary file data stored in - * the storage device. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageCheckTempDataCallback(uint32_t * currentOffset, uint32_t * totalImageSize, - EmberAfOtaImageId * newFileInfo) -{ - // If the image data cannot be successfully verified, an error should be returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Clear Temp Data - * - * This function clears any existing temp data that was downloaed. It is used - * immediately prior to downloading a raw image over the air. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageClearTempDataCallback(void) -{ - // If the image data cannot be stored, an error should be returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Close - * - * This callback shuts down the ZigBee Over-the-air storage module. - * - */ -void emberAfOtaStorageCloseCallback(void) -{ - // Please implement me. - assert(false); -} - -/** @brief Ota Storage Driver Download Finish - * - * This callback defines the low-level means by which a device records the final - * offset value of the download image. - * - * @param offset The value of the final offset of the image download. Ver.: - * always - */ -void emberAfOtaStorageDriverDownloadFinishCallback(uint32_t offset) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); -} - -/** @brief Ota Storage Driver Init - * - * The initialization code for the OTA storage driver. - * - */ -bool emberAfOtaStorageDriverInitCallback(void) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); - return false; -} - -/** @brief Ota Storage Driver Invalidate Image - * - * This callback invalidates the image stored on disk so that it will not be - * bootloaded, and it will not be a valid image that is in the middle of - * downloading. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageDriverInvalidateImageCallback(void) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Driver Prepare To Resume Download - * - * This callback allows the underlying storage driver to prepare to resume the - * OTA file download. For example, the driver may exceute a page erase to - * insure the next page is ready to be written to. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageDriverPrepareToResumeDownloadCallback(void) -{ - assert(false); - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Driver Read - * - * This callback defines the low-level means by which a device reads from the - * OTA storage device. - * - * @param offset The address offset from the start of the storage device where - * data is to be read. Ver.: always - * @param length The length of the data to be read from the storage device. - * Ver.: always - * @param returnData A pointer where the data read from the device should be - * written to. Ver.: always - */ -bool emberAfOtaStorageDriverReadCallback(uint32_t offset, uint32_t length, uint8_t * returnData) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); - return false; -} - -/** @brief Ota Storage Driver Retrieve Last Stored Offset - * - * This callback defines the low-level means by which a device retrieves the - * last persistently recorded download offset. This may be different than last - * actual download offset. - * - */ -uint32_t emberAfOtaStorageDriverRetrieveLastStoredOffsetCallback(void) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); - return 0; -} - -/** @brief Ota Storage Driver Write - * - * This callback defines the low-level means by which a device reads from the - * OTA storage device. - * - * @param dataToWrite A pointer to the data that will be written to the storage - * device. Ver.: always - * @param offset The address offset from the start of the storage device where - * data will be written. Ver.: always - * @param length The length of the data to be written to the storage device. - * Ver.: always - */ -bool emberAfOtaStorageDriverWriteCallback(const uint8_t * dataToWrite, uint32_t offset, uint32_t length) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); - return false; -} - -/** @brief Ota Storage Finish Download - * - * This function indicates to the storage module that the download has finished. - * - * @param offset The final offset of the downloaded file (i.e. the total size) - * Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageFinishDownloadCallback(uint32_t offset) -{ - return EMBER_AF_OTA_STORAGE_SUCCESS; -} - -/** @brief Ota Storage Get Count - * - * This callback returns the total number of ZigBee Over-the-air upgrade images - * stored in the storage module. - * - */ -uint8_t emberAfOtaStorageGetCountCallback(void) -{ - return 0; -} - -/** @brief Ota Storage Get Full Header - * - * This callback populates the EmberAfOtaHeader structure pointed to by the - * returnData with data about the OTA file stored in the storage module. - * - * @param id This is a pointer to the image id for the OTA file to retrieve - * information about. Ver.: always - * @param returnData This is a pointer to the location of the structure that - * will be populated with data. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageGetFullHeaderCallback(const EmberAfOtaImageId * id, EmberAfOtaHeader * returnData) -{ - // If the requested image cannot be found, then an error shouldb e returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Get Total Image Size - * - * This function returns the total size of the ZigBee Over-the-air file with the - * passed parameters. If no file is found with those parameters, 0 is returned. - * - * @param id A pointer to the image identifier for the OTA file to retrieve - * information for. Ver.: always - */ -uint32_t emberAfOtaStorageGetTotalImageSizeCallback(const EmberAfOtaImageId * id) -{ - // On failure this should return an image size of zero. - return 0; -} - -/** @brief Ota Storage Init - * - * This callback initializes the ZigBee Over-the-air storage module. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageInitCallback(void) -{ - return EMBER_AF_OTA_STORAGE_SUCCESS; -} - -/** @brief Ota Storage Iterator First - * - * This callback lets you walk through the list of all OTA files by jumping to - * the first file in the list maintained by the storage module. If there is no - * file then emberAfOtaInvalidImageId is returned. - * - */ -EmberAfOtaImageId emberAfOtaStorageIteratorFirstCallback(void) -{ - // It is expected that the storage module maintain its own internal iterator that the 'first' and 'next' functions will - // manipulate. - - // If there are no images at all, this function should return the invalid image id. - return emberAfInvalidImageId; -} - -/** @brief Ota Storage Iterator Next - * - * This callback lets you walk through the list of all OTA files by jumping to - * the next file in the list maintained by the storage module. If there is no - * next file then emberAfOtaInvalidImageId is returned. - * - */ -EmberAfOtaImageId emberAfOtaStorageIteratorNextCallback(void) -{ - // It is expected that the storage module maintain its own internal iterator that the 'first' and 'next' functions will - // manipulate. - - // If there are no more images, this function should return the invalid image id. - return emberAfInvalidImageId; -} - -/** @brief Ota Storage Read Image Data - * - * This callback reads data from the specified OTA file and returns that data to - * the caller. - * - * @param id This is a pointer to the image id for the OTA file to retrieve data - * from. Ver.: always - * @param offset This is the offset relative to the start of the image where the - * data should be read from. Ver.: always - * @param length This is the length of data that will be read. Ver.: always - * @param returnData This is a pointer to where the data read out of the file - * will be written to Ver.: always - * @param returnedLength This is a pointer to a variable where the actual length - * of data read will be written to. A short read may occur if the end of file - * was reached. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageReadImageDataCallback(const EmberAfOtaImageId * id, uint32_t offset, uint32_t length, - uint8_t * returnData, uint32_t * returnedLength) -{ - // If the requested image cannot be found, then an error should be returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Search - * - * This callback searches through the list of all images for one that matches - * the passed parameters. On success an image identifier is returned with a - * matching image. On failure emberAfInvalidImageId is returned. - * - * @param manufacturerId The ZigBee assigned identifier of the manufacturer - * contained in the OTA image being searched for. Ver.: always - * @param imageTypeId The image type identifier contained in the OTA image being - * searched for. Ver.: always - * @param hardwareVersion This is a pointer to the hardware version that will be - * used in the search. If the pointer is NULL, hardware version will not be - * considered when searching for matching images. If it points to a value, the - * search will only consider images where that value falls between the minimum - * and maxmimum hardware version specified in the OTA file. If no hardware - * version is present in an OTA file but the other parameters match, the file - * will be considered a match Ver.: always - */ -EmberAfOtaImageId emberAfOtaStorageSearchCallback(uint16_t manufacturerId, uint16_t imageTypeId, const uint16_t * hardwareVersion) -{ - // If no image is found that matches the search criteria, this function should return the invalid image id. - return emberAfInvalidImageId; -} - -/** @brief Ota Storage Write Temp Data - * - * This function writes to the temporary data in the storage device at the - * specified offset. It is used when downloading a raw image over the air. - * - * @param offset The location within the download image file where to write the - * data. Ver.: always - * @param length The length of data to write. Ver.: always - * @param data A pointer to the temporary data that will be written to the - * storage device. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageWriteTempDataCallback(uint32_t offset, uint32_t length, const uint8_t * data) -{ - // If the image data cannot be stored, an error should be returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - /** @brief Outgoing Packet Filter * * ** REQUIRES INCLUDING THE PACKET-HANDOFF PLUGIN ** @@ -2376,8 +1731,6 @@ bool emberAfIsCurrentSecurityProfileSmartEnergy(void) return false; } -const EmberAfOtaImageId emberAfInvalidImageId; - void emberAfPluginUpdateTcLinkKeyZigbeeKeyEstablishmentCallback(EmberEUI64 partner, EmberKeyStatus status) {} void emberAfPluginNetworkSteeringMarker(void) {} diff --git a/examples/lighting-app/lighting-common/gen/callback.h b/examples/lighting-app/lighting-common/gen/callback.h index 667d2dbdd048a9..6d2c89debdfd47 100644 --- a/examples/lighting-app/lighting-common/gen/callback.h +++ b/examples/lighting-app/lighting-common/gen/callback.h @@ -814,384 +814,6 @@ void emberAfNetworkFoundCallback(EmberZigbeeNetwork * networkFound, uint8_t lqi, * @param status Ver.: always */ void emberAfNetworkKeyUpdateCompleteCallback(EmberStatus status); -/** @brief Ota Bootload - * - * The platform specific routine to bootload the device from a ZigBee - * over-the-air upgrade file. - * - * @param id A pointer to the structure that contains the information about what - * OTA image to bootload. Ver.: always - * @param ncpUpgradeTagId The tag ID of the upgrade data that will be used to - * bootload the device. Ver.: always - */ -uint8_t emberAfOtaBootloadCallback(const EmberAfOtaImageId * id, uint16_t ncpUpgradeTagId); -/** @brief Ota Client Bootload - * - * This callback is fired when the OTA Client recevies a command to bootload the - * newly downloaded OTA image. This callback will perform the platform specific - * to bootload their device. - * - * @param id This is the identifier relating to the image that has been - * downloaded and is ready for bootload. Ver.: always - */ -void emberAfOtaClientBootloadCallback(const EmberAfOtaImageId * id); -/** @brief Ota Client Custom Verify - * - * This callback is executed by the OTA client after the signature verification - * has successfully completed. It allows the device to do its own custom - * verification of the image (such as verifying that the EBL is intact). - * - * @param newVerification This indicates if a new verification should be - * started. Ver.: always - * @param id This is ID of the image to be verified. Ver.: always - */ -EmberAfImageVerifyStatus emberAfOtaClientCustomVerifyCallback(bool newVerification, const EmberAfOtaImageId * id); -/** @brief Ota Client Download Complete - * - * This callback indicates that the OTA client has completed the download of a - * file. If the file has been completely downloaded and cryptographic checks - * have been turned on, then those will be performed prior to this callback and - * that outcome included in the 'success' result. On failure, this callback is - * merely informative, and the return type is ignored. On succesful download, - * this callback allows the client to perform any additional verification of the - * downloaded image and return that result to the OTA server. - * - * @param success This indicates the success or failure of the download and - * cryptographic verification process (if applicable). Ver.: always - * @param id This is the image identifier information that corresponds to the - * download result. Ver.: always - */ -bool emberAfOtaClientDownloadCompleteCallback(EmberAfOtaDownloadResult success, const EmberAfOtaImageId * id); -/** @brief Ota Client Incoming Message Raw - * - * This callback is for processing incoming messages for the Over-the-air - * bootload cluster client. ZCL will not process the message and instead hand - * the raw over the air data to the callback for its own processing. - * - * @param message A pointer to the structure containing the message buffer and - * other information about it. Ver.: always - */ -bool emberAfOtaClientIncomingMessageRawCallback(EmberAfClusterCommand * message); -/** @brief Ota Client Start - * - * This callback should be called when the profile specific registration has - * completed successfully. It will start the client's state machine that will - * find the OTA server, query it for the next image, download the image, wait - * for the bootload message, and kick off the bootload. - * - */ -void emberAfOtaClientStartCallback(void); -/** @brief Ota Client Version Info - * - * This function is called by the OTA client when a new query will occur to the - * server asking what the next version of firmware is. The client can inform - * the cluster software as to what information to use in the query (and - * subsequent download). - * - * @param currentImageInfo This is the information to use in the next query by - * the client cluster code. It contains the manufacturer ID, image type ID, and - * the firmware version to be specified in the query message sent to the server. - * Ver.: always - * @param hardwareVersion This is a pointer to the hardware version to use in - * the query. If no hardware version should be used, then - * EMBER_AF_INVALID_HARDWARE_VERSION should be used. Ver.: always - */ -void emberAfOtaClientVersionInfoCallback(EmberAfOtaImageId * currentImageInfo, uint16_t * hardwareVersion); -/** @brief Ota Page Request Server Policy - * - * This callback is called by the OTA server page request code when it wants to - * determine if it is allowed for an OTA client to make a page request. It is - * only called if page request support has been enabled on the server. It - * should return EMBER_ZCL_STATUS_SUCCESS if it allows the page request, and - * EMBER_ZCL_STATUS_UNSUP_CLUSTER_COMMAND if it does not want to allow it. - * - */ -uint8_t emberAfOtaPageRequestServerPolicyCallback(void); -/** @brief Ota Server Block Size - * - * This function provides a way for the server to adjust the block size of its - * response to an Image block request by a client. - * - * @param clientNodeId The node Id of OTA client making an image block request. - * Ver.: always - */ -uint8_t emberAfOtaServerBlockSizeCallback(EmberNodeId clientNodeId); -/** @brief Ota Server Incoming Message Raw - * - * This callback is for processing incoming messages for the Over-the-air - * bootload cluster server. ZCL will not process the message and instead hand - * the raw over the air data to the callback for its own processing. - * - * @param message A pointer to the structure containing the message buffer and - * other information about it. Ver.: always - */ -bool emberAfOtaServerIncomingMessageRawCallback(EmberAfClusterCommand * message); -/** @brief Ota Server Query - * - * This callback is fired when the OTA server receives a query request by the - * client. The callback lets the server application indicate to the client what - * the 'next' version of software is for the device, or if there is not one - * available. - * - * @param currentImageId This is the current software image that the client - * hase. Ver.: always - * @param hardwareVersion If this value is non-NULL, it indicates the hardware - * version of the client device. If NULL, the client did not specify a hardware - * version. Ver.: always - * @param nextUpgradeImageId This is a pointer to a data structure containing - * the 'next' software version for the client to download. Ver.: always - */ -uint8_t emberAfOtaServerQueryCallback(const EmberAfOtaImageId * currentImageId, uint16_t * hardwareVersion, - EmberAfOtaImageId * nextUpgradeImageId); -/** @brief Ota Server Send Image Notify - * - * This callback is an indication to the OTA server that it should send out - * notification about an OTA file that is available for download. - * - * @param dest The destination of the image notify message. May be a broadcast - * address. Ver.: always - * @param endpoint The destination endpoint of the image notify message. May be - * a broadcast endpoint. Ver.: always - * @param payloadType The type of data the image notify message will contain. 0 - * = no data. 1 = Manufacturer ID. 2 = Manufacturer ID and the image type ID. - * 3 = Manufacturer ID, image type ID, and firmware version. Ver.: always - * @param queryJitter The percentage of nodes that should respond to this - * message, from 1-100. On receipt of this message, each recipient will - * randomly choose a percentage and only query the server if their percentage is - * below this value. Ver.: always - * @param id The image information that will be put in the message. The data - * within this struct that will be appended to the message is determined by the - * previous 'payloadType' argument. Ver.: always - */ -bool emberAfOtaServerSendImageNotifyCallback(EmberNodeId dest, uint8_t endpoint, uint8_t payloadType, uint8_t queryJitter, - const EmberAfOtaImageId * id); -/** @brief Ota Server Upgrade End Request - * - * This function is called when the OTA server receives a request an upgrade end - * request. If the request indicated a successful download by the client, the - * server must tell the client when and if to upgrade to the downloaded image. - * - * @param source The node ID of the device that sent the upgrade end request. - * Ver.: always - * @param status This is the ZCL status sent by the client indicating the result - * of its attempt to download the new upgrade image. If the status is not - * EMBER_ZCL_STATUS_SUCCESS then this callback is merely informative and no - * response mesasge will be generated by the server. Ver.: always - * @param returnValue If the server returns true indicating that the client - * should apply the upgrade, this time value indicates when in the future the - * client should apply the upgrade. Ver.: always - * @param imageId This variable indicates the software version that the client - * successfully downloaded and is asking to upgrade to. Ver.: always - */ -bool emberAfOtaServerUpgradeEndRequestCallback(EmberNodeId source, uint8_t status, uint32_t * returnValue, - const EmberAfOtaImageId * imageId); -/** @brief Ota Storage Check Temp Data - * - * This callback will validate temporary data in the storage device to determine - * whether it is a complete file, a partially downloaded file, or there is no - * file present. When a complete or partial file is found it will return - * EMBER_AF_OTA_STORAGE_SUCCESS or EMBER_AF_OTA_STORAGE_PARTIAL_FILE_FOUND, - * respectively. In that case, the currentOffset, totalImageSize, and - * newFileInfo will be populated with data. When EMBER_AF_OTA_STORAGE_ERROR is - * returned, no temporary data is present. - * - * @param currentOffset A pointer to a value that will be written with the - * offset within the total file size that has been successfully stored in the - * storage device. This will indicate how much data has been currently - * dowloaded. Ver.: always - * @param totalImageSize A pointer to a value that will be written with the - * total image size of the OTA file when a download has completed. This does - * not indicate how much data has actually been downloaded currently. Ver.: - * always - * @param newFileInfo This is the image id of the temporary file data stored in - * the storage device. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageCheckTempDataCallback(uint32_t * currentOffset, uint32_t * totalImageSize, - EmberAfOtaImageId * newFileInfo); -/** @brief Ota Storage Clear Temp Data - * - * This function clears any existing temp data that was downloaed. It is used - * immediately prior to downloading a raw image over the air. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageClearTempDataCallback(void); -/** @brief Ota Storage Close - * - * This callback shuts down the ZigBee Over-the-air storage module. - * - */ -void emberAfOtaStorageCloseCallback(void); -/** @brief Ota Storage Driver Download Finish - * - * This callback defines the low-level means by which a device records the final - * offset value of the download image. - * - * @param offset The value of the final offset of the image download. Ver.: - * always - */ -void emberAfOtaStorageDriverDownloadFinishCallback(uint32_t offset); -/** @brief Ota Storage Driver Init - * - * The initialization code for the OTA storage driver. - * - */ -bool emberAfOtaStorageDriverInitCallback(void); -/** @brief Ota Storage Driver Invalidate Image - * - * This callback invalidates the image stored on disk so that it will not be - * bootloaded, and it will not be a valid image that is in the middle of - * downloading. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageDriverInvalidateImageCallback(void); -/** @brief Ota Storage Driver Prepare To Resume Download - * - * This callback allows the underlying storage driver to prepare to resume the - * OTA file download. For example, the driver may exceute a page erase to - * insure the next page is ready to be written to. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageDriverPrepareToResumeDownloadCallback(void); -/** @brief Ota Storage Driver Read - * - * This callback defines the low-level means by which a device reads from the - * OTA storage device. - * - * @param offset The address offset from the start of the storage device where - * data is to be read. Ver.: always - * @param length The length of the data to be read from the storage device. - * Ver.: always - * @param returnData A pointer where the data read from the device should be - * written to. Ver.: always - */ -bool emberAfOtaStorageDriverReadCallback(uint32_t offset, uint32_t length, uint8_t * returnData); -/** @brief Ota Storage Driver Retrieve Last Stored Offset - * - * This callback defines the low-level means by which a device retrieves the - * last persistently recorded download offset. This may be different than last - * actual download offset. - * - */ -uint32_t emberAfOtaStorageDriverRetrieveLastStoredOffsetCallback(void); -/** @brief Ota Storage Driver Write - * - * This callback defines the low-level means by which a device reads from the - * OTA storage device. - * - * @param dataToWrite A pointer to the data that will be written to the storage - * device. Ver.: always - * @param offset The address offset from the start of the storage device where - * data will be written. Ver.: always - * @param length The length of the data to be written to the storage device. - * Ver.: always - */ -bool emberAfOtaStorageDriverWriteCallback(const uint8_t * dataToWrite, uint32_t offset, uint32_t length); -/** @brief Ota Storage Finish Download - * - * This function indicates to the storage module that the download has finished. - * - * @param offset The final offset of the downloaded file (i.e. the total size) - * Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageFinishDownloadCallback(uint32_t offset); -/** @brief Ota Storage Get Count - * - * This callback returns the total number of ZigBee Over-the-air upgrade images - * stored in the storage module. - * - */ -uint8_t emberAfOtaStorageGetCountCallback(void); -/** @brief Ota Storage Get Full Header - * - * This callback populates the EmberAfOtaHeader structure pointed to by the - * returnData with data about the OTA file stored in the storage module. - * - * @param id This is a pointer to the image id for the OTA file to retrieve - * information about. Ver.: always - * @param returnData This is a pointer to the location of the structure that - * will be populated with data. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageGetFullHeaderCallback(const EmberAfOtaImageId * id, EmberAfOtaHeader * returnData); -/** @brief Ota Storage Get Total Image Size - * - * This function returns the total size of the ZigBee Over-the-air file with the - * passed parameters. If no file is found with those parameters, 0 is returned. - * - * @param id A pointer to the image identifier for the OTA file to retrieve - * information for. Ver.: always - */ -uint32_t emberAfOtaStorageGetTotalImageSizeCallback(const EmberAfOtaImageId * id); -/** @brief Ota Storage Init - * - * This callback initializes the ZigBee Over-the-air storage module. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageInitCallback(void); -/** @brief Ota Storage Iterator First - * - * This callback lets you walk through the list of all OTA files by jumping to - * the first file in the list maintained by the storage module. If there is no - * file then emberAfOtaInvalidImageId is returned. - * - */ -EmberAfOtaImageId emberAfOtaStorageIteratorFirstCallback(void); -/** @brief Ota Storage Iterator Next - * - * This callback lets you walk through the list of all OTA files by jumping to - * the next file in the list maintained by the storage module. If there is no - * next file then emberAfOtaInvalidImageId is returned. - * - */ -EmberAfOtaImageId emberAfOtaStorageIteratorNextCallback(void); -/** @brief Ota Storage Read Image Data - * - * This callback reads data from the specified OTA file and returns that data to - * the caller. - * - * @param id This is a pointer to the image id for the OTA file to retrieve data - * from. Ver.: always - * @param offset This is the offset relative to the start of the image where the - * data should be read from. Ver.: always - * @param length This is the length of data that will be read. Ver.: always - * @param returnData This is a pointer to where the data read out of the file - * will be written to Ver.: always - * @param returnedLength This is a pointer to a variable where the actual length - * of data read will be written to. A short read may occur if the end of file - * was reached. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageReadImageDataCallback(const EmberAfOtaImageId * id, uint32_t offset, uint32_t length, - uint8_t * returnData, uint32_t * returnedLength); -/** @brief Ota Storage Search - * - * This callback searches through the list of all images for one that matches - * the passed parameters. On success an image identifier is returned with a - * matching image. On failure emberAfInvalidImageId is returned. - * - * @param manufacturerId The ZigBee assigned identifier of the manufacturer - * contained in the OTA image being searched for. Ver.: always - * @param imageTypeId The image type identifier contained in the OTA image being - * searched for. Ver.: always - * @param hardwareVersion This is a pointer to the hardware version that will be - * used in the search. If the pointer is NULL, hardware version will not be - * considered when searching for matching images. If it points to a value, the - * search will only consider images where that value falls between the minimum - * and maxmimum hardware version specified in the OTA file. If no hardware - * version is present in an OTA file but the other parameters match, the file - * will be considered a match Ver.: always - */ -EmberAfOtaImageId emberAfOtaStorageSearchCallback(uint16_t manufacturerId, uint16_t imageTypeId, const uint16_t * hardwareVersion); -/** @brief Ota Storage Write Temp Data - * - * This function writes to the temporary data in the storage device at the - * specified offset. It is used when downloading a raw image over the air. - * - * @param offset The location within the download image file where to write the - * data. Ver.: always - * @param length The length of data to write. Ver.: always - * @param data A pointer to the temporary data that will be written to the - * storage device. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageWriteTempDataCallback(uint32_t offset, uint32_t length, const uint8_t * data); /** @brief Outgoing Packet Filter * * ** REQUIRES INCLUDING THE PACKET-HANDOFF PLUGIN ** diff --git a/examples/lock-app/efr32/src/gen/callback-stub.c b/examples/lock-app/efr32/src/gen/callback-stub.c index 44ed6b255a542a..79651ef23716c4 100644 --- a/examples/lock-app/efr32/src/gen/callback-stub.c +++ b/examples/lock-app/efr32/src/gen/callback-stub.c @@ -137,15 +137,6 @@ bool emberAfAttributeWriteAccessCallback(uint8_t endpoint, EmberAfClusterId clus */ void emberAfGroupsClusterClearGroupTableCallback(uint8_t endpoint) {} -/** @brief Scenes Cluster ClearSceneTable - * - * This function is called by the framework when the application should clear - * the scene table. - * - * @param endpoint The endpoint. Ver.: always - */ -void emberAfScenesClusterClearSceneTableCallback(uint8_t endpoint) {} - /** @brief Key Establishment Cluster Client Command Received * * This function is called by the application framework when a server-to-client @@ -1000,642 +991,6 @@ void emberAfNcpIsAwakeIsrCallback(void) {} */ void emberAfNetworkKeyUpdateCompleteCallback(EmberStatus status) {} -/** @brief Ota Bootload - * - * The platform specific routine to bootload the device from a ZigBee - * over-the-air upgrade file. - * - * @param id A pointer to the structure that contains the information about what - * OTA image to bootload. Ver.: always - * @param ncpUpgradeTagId The tag ID of the upgrade data that will be used to - * bootload the device. Ver.: always - */ -uint8_t emberAfOtaBootloadCallback(const EmberAfOtaImageId * id, uint16_t ncpUpgradeTagId) -{ - // Please implement me - emberAfCorePrintln("Not supported."); - return 1; -} - -/** @brief Ota Client Bootload - * - * This callback is fired when the OTA Client recevies a command to bootload the - * newly downloaded OTA image. This callback will perform the platform specific - * to bootload their device. - * - * @param id This is the identifier relating to the image that has been - * downloaded and is ready for bootload. Ver.: always - */ -void emberAfOtaClientBootloadCallback(const EmberAfOtaImageId * id) -{ - // Any final preperation prior to the bootload should be done here. - // It is assumed that the device will reset in most all cases. - // Please implement me. -} - -/** @brief Ota Client Custom Verify - * - * This callback is executed by the OTA client after the signature verification - * has successfully completed. It allows the device to do its own custom - * verification of the image (such as verifying that the EBL is intact). - * - * @param newVerification This indicates if a new verification should be - * started. Ver.: always - * @param id This is ID of the image to be verified. Ver.: always - */ -EmberAfImageVerifyStatus emberAfOtaClientCustomVerifyCallback(bool newVerification, const EmberAfOtaImageId * id) -{ - // Manufacturing specific checks can be made to the image in this function to - // determine if it is valid. This function is called AFTER cryptographic - // checks have passed. If the cryptographic checks failed, this function will - // never be called. - - // The function shall return one of the following based on its own - // verification process. - // 1) EMBER_AF_IMAGE_GOOD - the image has passed all checks - // 2) EMBER_AF_IMAGE_BAD - the image is not valid - // 3) EMBER_AF_IMAGE_VERIFY_IN_PROGRESS - the image is valid so far, but more - // checks are needed. This callback shall be re-executed later to - // continue verification. This allows other code in the framework to run. - return EMBER_AF_IMAGE_GOOD; -} - -/** @brief Ota Client Download Complete - * - * This callback indicates that the OTA client has completed the download of a - * file. If the file has been completely downloaded and cryptographic checks - * have been turned on, then those will be performed prior to this callback and - * that outcome included in the 'success' result. On failure, this callback is - * merely informative, and the return type is ignored. On succesful download, - * this callback allows the client to perform any additional verification of the - * downloaded image and return that result to the OTA server. - * - * @param success This indicates the success or failure of the download and - * cryptographic verification process (if applicable). Ver.: always - * @param id This is the image identifier information that corresponds to the - * download result. Ver.: always - */ -bool emberAfOtaClientDownloadCompleteCallback(EmberAfOtaDownloadResult success, const EmberAfOtaImageId * id) -{ - // At this point the image has been completely downloaded and cryptographic - // checks (if applicable) have been performed. - - if (!success) - { - emberAfOtaBootloadClusterPrintln("Download failed."); - return true; // return value is ignored - } - - // This is for any additional validation that needs to be performed - // on the image by the application. - - // The results of checks here will be returned back to the OTA server - // in the Upgrade End request. - return true; -} - -/** @brief Ota Client Incoming Message Raw - * - * This callback is for processing incoming messages for the Over-the-air - * bootload cluster client. ZCL will not process the message and instead hand - * the raw over the air data to the callback for its own processing. - * - * @param message A pointer to the structure containing the message buffer and - * other information about it. Ver.: always - */ -bool emberAfOtaClientIncomingMessageRawCallback(EmberAfClusterCommand * message) -{ - return false; -} - -/** @brief Ota Client Start - * - * This callback should be called when the profile specific registration has - * completed successfully. It will start the client's state machine that will - * find the OTA server, query it for the next image, download the image, wait - * for the bootload message, and kick off the bootload. - * - */ -void emberAfOtaClientStartCallback(void) {} - -/** @brief Ota Client Version Info - * - * This function is called by the OTA client when a new query will occur to the - * server asking what the next version of firmware is. The client can inform - * the cluster software as to what information to use in the query (and - * subsequent download). - * - * @param currentImageInfo This is the information to use in the next query by - * the client cluster code. It contains the manufacturer ID, image type ID, and - * the firmware version to be specified in the query message sent to the server. - * Ver.: always - * @param hardwareVersion This is a pointer to the hardware version to use in - * the query. If no hardware version should be used, then - * EMBER_AF_INVALID_HARDWARE_VERSION should be used. Ver.: always - */ -void emberAfOtaClientVersionInfoCallback(EmberAfOtaImageId * currentImageInfo, uint16_t * hardwareVersion) -{ - // Customer will fill in the image info with their manufacturer ID, - // image type ID, and current software version number. - // The deviceSpecificFileEui64 can be ignored. - - // It may be necessary to dynamically determine this by talking to - // another device, as is the case with a host talking to an NCP device. - - // However, this routine will be called repeatedly so it may be wise - // to cache the data! - - /* This is commented out since the #defines below are not defined. - - if (currentImageInfo != NULL) { - MEMSET(currentImageInfo, 0, sizeof(EmberAfOtaImageId)); - currentImageInfo->manufacturerId = EMBER_AF_MANUFACTURER_CODE; - currentImageInfo->imageTypeId = EMBER_AF_IMAGE_TYPE_ID; - currentImageInfo->firmwareVersion = EMBER_AF_CUSTOM_FIRMWARE_VERSION; - } - - if (hardwareVersion != NULL) { - *hardwareVersion = EMBER_AF_INVALID_HARDWARE_VERSION; - } - - assert(false); - */ -} - -/** @brief Ota Page Request Server Policy - * - * This callback is called by the OTA server page request code when it wants to - * determine if it is allowed for an OTA client to make a page request. It is - * only called if page request support has been enabled on the server. It - * should return EMBER_ZCL_STATUS_SUCCESS if it allows the page request, and - * EMBER_ZCL_STATUS_UNSUP_CLUSTER_COMMAND if it does not want to allow it. - * - */ -uint8_t emberAfOtaPageRequestServerPolicyCallback(void) -{ - return EMBER_ZCL_STATUS_SUCCESS; -} - -/** @brief Ota Server Block Size - * - * This function provides a way for the server to adjust the block size of its - * response to an Image block request by a client. - * - * @param clientNodeId The node Id of OTA client making an image block request. - * Ver.: always - */ -uint8_t emberAfOtaServerBlockSizeCallback(EmberNodeId clientNodeId) -{ - // This function provides a way for the server to potentially - // adjust the block size based on the client who is requesting. - // In other words if we are using source routing we will limit - // data returned by enough to put a source route into the message. - - // Image Block Response Message Format - // Status Code: 1-byte - // Manuf Code: 2-bytes - // Image Type: 2-bytes - // File Ver: 4-bytes - // File Offset: 4-bytes - // Data Size: 1-byte - // Data: variable - const uint8_t IMAGE_BLOCK_RESPONSE_OVERHEAD = (EMBER_AF_ZCL_OVERHEAD + 14); - - EmberApsFrame apsFrame; - uint8_t maxSize; - apsFrame.options = EMBER_APS_OPTION_NONE; - - if (emberAfIsCurrentSecurityProfileSmartEnergy()) - { - apsFrame.options |= EMBER_APS_OPTION_ENCRYPTION; - } - - maxSize = emberAfMaximumApsPayloadLength(EMBER_OUTGOING_DIRECT, clientNodeId, &apsFrame); - maxSize -= IMAGE_BLOCK_RESPONSE_OVERHEAD; - return maxSize; -} - -/** @brief Ota Server Incoming Message Raw - * - * This callback is for processing incoming messages for the Over-the-air - * bootload cluster server. ZCL will not process the message and instead hand - * the raw over the air data to the callback for its own processing. - * - * @param message A pointer to the structure containing the message buffer and - * other information about it. Ver.: always - */ -bool emberAfOtaServerIncomingMessageRawCallback(EmberAfClusterCommand * message) -{ - return false; -} - -/** @brief Ota Server Query - * - * This callback is fired when the OTA server receives a query request by the - * client. The callback lets the server application indicate to the client what - * the 'next' version of software is for the device, or if there is not one - * available. - * - * @param currentImageId This is the current software image that the client - * hase. Ver.: always - * @param hardwareVersion If this value is non-NULL, it indicates the hardware - * version of the client device. If NULL, the client did not specify a hardware - * version. Ver.: always - * @param nextUpgradeImageId This is a pointer to a data structure containing - * the 'next' software version for the client to download. Ver.: always - */ -uint8_t emberAfOtaServerQueryCallback(const EmberAfOtaImageId * currentImageId, uint16_t * hardwareVersion, - EmberAfOtaImageId * nextUpgradeImageId) -{ - // If a new software image is available, this function should return EMBER_ZCL_STATUS_SUCCESS - // and populate the 'nextUpgradeImageId' structure with the appropriate values. - // If no new software image is available (i.e. the client should not download a firmware image) - // then the server should return EMBER_ZCL_STATUS_NO_IMAGE_AVAILABLE. - return EMBER_ZCL_STATUS_NO_IMAGE_AVAILABLE; -} - -/** @brief Ota Server Send Image Notify - * - * This callback is an indication to the OTA server that it should send out - * notification about an OTA file that is available for download. - * - * @param dest The destination of the image notify message. May be a broadcast - * address. Ver.: always - * @param endpoint The destination endpoint of the image notify message. May be - * a broadcast endpoint. Ver.: always - * @param payloadType The type of data the image notify message will contain. 0 - * = no data. 1 = Manufacturer ID. 2 = Manufacturer ID and the image type ID. - * 3 = Manufacturer ID, image type ID, and firmware version. Ver.: always - * @param queryJitter The percentage of nodes that should respond to this - * message, from 1-100. On receipt of this message, each recipient will - * randomly choose a percentage and only query the server if their percentage is - * below this value. Ver.: always - * @param id The image information that will be put in the message. The data - * within this struct that will be appended to the message is determined by the - * previous 'payloadType' argument. Ver.: always - */ -bool emberAfOtaServerSendImageNotifyCallback(EmberNodeId dest, uint8_t endpoint, uint8_t payloadType, uint8_t queryJitter, - const EmberAfOtaImageId * id) -{ - return false; -} - -/** @brief Ota Server Upgrade End Request - * - * This function is called when the OTA server receives a request an upgrade end - * request. If the request indicated a successful download by the client, the - * server must tell the client when and if to upgrade to the downloaded image. - * - * @param source The node ID of the device that sent the upgrade end request. - * Ver.: always - * @param status This is the ZCL status sent by the client indicating the result - * of its attempt to download the new upgrade image. If the status is not - * EMBER_ZCL_STATUS_SUCCESS then this callback is merely informative and no - * response mesasge will be generated by the server. Ver.: always - * @param returnValue If the server returns true indicating that the client - * should apply the upgrade, this time value indicates when in the future the - * client should apply the upgrade. Ver.: always - * @param imageId This variable indicates the software version that the client - * successfully downloaded and is asking to upgrade to. Ver.: always - */ -bool emberAfOtaServerUpgradeEndRequestCallback(EmberNodeId source, uint8_t status, uint32_t * returnValue, - const EmberAfOtaImageId * imageId) -{ - // If the status value is not EMBER_ZCL_STATUS_SUCCESS, then this callback is - // merely informative and no response message will be generated by the server. - // If the server wants the client to NOT apply the upgrade, then it should - // return false. - // If the server wants the client to apply the upgrade, it should return true - // and set the 'returnValue' parameter to when it wants the client to - // apply the upgrade. There are three possible values: - // 0 = Apply the upgrade now - // 0xFFFFFFFF = Don't apply yet, ask again later. - // (anything-else) = Apply the upgrade X minutes from now. - *returnValue = 0; - return true; -} - -/** @brief Ota Storage Check Temp Data - * - * This callback will validate temporary data in the storage device to determine - * whether it is a complete file, a partially downloaded file, or there is no - * file present. When a complete or partial file is found it will return - * EMBER_AF_OTA_STORAGE_SUCCESS or EMBER_AF_OTA_STORAGE_PARTIAL_FILE_FOUND, - * respectively. In that case, the currentOffset, totalImageSize, and - * newFileInfo will be populated with data. When EMBER_AF_OTA_STORAGE_ERROR is - * returned, no temporary data is present. - * - * @param currentOffset A pointer to a value that will be written with the - * offset within the total file size that has been successfully stored in the - * storage device. This will indicate how much data has been currently - * dowloaded. Ver.: always - * @param totalImageSize A pointer to a value that will be written with the - * total image size of the OTA file when a download has completed. This does - * not indicate how much data has actually been downloaded currently. Ver.: - * always - * @param newFileInfo This is the image id of the temporary file data stored in - * the storage device. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageCheckTempDataCallback(uint32_t * currentOffset, uint32_t * totalImageSize, - EmberAfOtaImageId * newFileInfo) -{ - // If the image data cannot be successfully verified, an error should be returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Clear Temp Data - * - * This function clears any existing temp data that was downloaed. It is used - * immediately prior to downloading a raw image over the air. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageClearTempDataCallback(void) -{ - // If the image data cannot be stored, an error should be returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Close - * - * This callback shuts down the ZigBee Over-the-air storage module. - * - */ -void emberAfOtaStorageCloseCallback(void) -{ - // Please implement me. - assert(false); -} - -/** @brief Ota Storage Driver Download Finish - * - * This callback defines the low-level means by which a device records the final - * offset value of the download image. - * - * @param offset The value of the final offset of the image download. Ver.: - * always - */ -void emberAfOtaStorageDriverDownloadFinishCallback(uint32_t offset) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); -} - -/** @brief Ota Storage Driver Init - * - * The initialization code for the OTA storage driver. - * - */ -bool emberAfOtaStorageDriverInitCallback(void) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); - return false; -} - -/** @brief Ota Storage Driver Invalidate Image - * - * This callback invalidates the image stored on disk so that it will not be - * bootloaded, and it will not be a valid image that is in the middle of - * downloading. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageDriverInvalidateImageCallback(void) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Driver Prepare To Resume Download - * - * This callback allows the underlying storage driver to prepare to resume the - * OTA file download. For example, the driver may exceute a page erase to - * insure the next page is ready to be written to. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageDriverPrepareToResumeDownloadCallback(void) -{ - assert(false); - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Driver Read - * - * This callback defines the low-level means by which a device reads from the - * OTA storage device. - * - * @param offset The address offset from the start of the storage device where - * data is to be read. Ver.: always - * @param length The length of the data to be read from the storage device. - * Ver.: always - * @param returnData A pointer where the data read from the device should be - * written to. Ver.: always - */ -bool emberAfOtaStorageDriverReadCallback(uint32_t offset, uint32_t length, uint8_t * returnData) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); - return false; -} - -/** @brief Ota Storage Driver Retrieve Last Stored Offset - * - * This callback defines the low-level means by which a device retrieves the - * last persistently recorded download offset. This may be different than last - * actual download offset. - * - */ -uint32_t emberAfOtaStorageDriverRetrieveLastStoredOffsetCallback(void) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); - return 0; -} - -/** @brief Ota Storage Driver Write - * - * This callback defines the low-level means by which a device reads from the - * OTA storage device. - * - * @param dataToWrite A pointer to the data that will be written to the storage - * device. Ver.: always - * @param offset The address offset from the start of the storage device where - * data will be written. Ver.: always - * @param length The length of the data to be written to the storage device. - * Ver.: always - */ -bool emberAfOtaStorageDriverWriteCallback(const uint8_t * dataToWrite, uint32_t offset, uint32_t length) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); - return false; -} - -/** @brief Ota Storage Finish Download - * - * This function indicates to the storage module that the download has finished. - * - * @param offset The final offset of the downloaded file (i.e. the total size) - * Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageFinishDownloadCallback(uint32_t offset) -{ - return EMBER_AF_OTA_STORAGE_SUCCESS; -} - -/** @brief Ota Storage Get Count - * - * This callback returns the total number of ZigBee Over-the-air upgrade images - * stored in the storage module. - * - */ -uint8_t emberAfOtaStorageGetCountCallback(void) -{ - return 0; -} - -/** @brief Ota Storage Get Full Header - * - * This callback populates the EmberAfOtaHeader structure pointed to by the - * returnData with data about the OTA file stored in the storage module. - * - * @param id This is a pointer to the image id for the OTA file to retrieve - * information about. Ver.: always - * @param returnData This is a pointer to the location of the structure that - * will be populated with data. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageGetFullHeaderCallback(const EmberAfOtaImageId * id, EmberAfOtaHeader * returnData) -{ - // If the requested image cannot be found, then an error shouldb e returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Get Total Image Size - * - * This function returns the total size of the ZigBee Over-the-air file with the - * passed parameters. If no file is found with those parameters, 0 is returned. - * - * @param id A pointer to the image identifier for the OTA file to retrieve - * information for. Ver.: always - */ -uint32_t emberAfOtaStorageGetTotalImageSizeCallback(const EmberAfOtaImageId * id) -{ - // On failure this should return an image size of zero. - return 0; -} - -/** @brief Ota Storage Init - * - * This callback initializes the ZigBee Over-the-air storage module. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageInitCallback(void) -{ - return EMBER_AF_OTA_STORAGE_SUCCESS; -} - -/** @brief Ota Storage Iterator First - * - * This callback lets you walk through the list of all OTA files by jumping to - * the first file in the list maintained by the storage module. If there is no - * file then emberAfOtaInvalidImageId is returned. - * - */ -EmberAfOtaImageId emberAfOtaStorageIteratorFirstCallback(void) -{ - // It is expected that the storage module maintain its own internal iterator that the 'first' and 'next' functions will - // manipulate. - - // If there are no images at all, this function should return the invalid image id. - return emberAfInvalidImageId; -} - -/** @brief Ota Storage Iterator Next - * - * This callback lets you walk through the list of all OTA files by jumping to - * the next file in the list maintained by the storage module. If there is no - * next file then emberAfOtaInvalidImageId is returned. - * - */ -EmberAfOtaImageId emberAfOtaStorageIteratorNextCallback(void) -{ - // It is expected that the storage module maintain its own internal iterator that the 'first' and 'next' functions will - // manipulate. - - // If there are no more images, this function should return the invalid image id. - return emberAfInvalidImageId; -} - -/** @brief Ota Storage Read Image Data - * - * This callback reads data from the specified OTA file and returns that data to - * the caller. - * - * @param id This is a pointer to the image id for the OTA file to retrieve data - * from. Ver.: always - * @param offset This is the offset relative to the start of the image where the - * data should be read from. Ver.: always - * @param length This is the length of data that will be read. Ver.: always - * @param returnData This is a pointer to where the data read out of the file - * will be written to Ver.: always - * @param returnedLength This is a pointer to a variable where the actual length - * of data read will be written to. A short read may occur if the end of file - * was reached. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageReadImageDataCallback(const EmberAfOtaImageId * id, uint32_t offset, uint32_t length, - uint8_t * returnData, uint32_t * returnedLength) -{ - // If the requested image cannot be found, then an error should be returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Search - * - * This callback searches through the list of all images for one that matches - * the passed parameters. On success an image identifier is returned with a - * matching image. On failure emberAfInvalidImageId is returned. - * - * @param manufacturerId The ZigBee assigned identifier of the manufacturer - * contained in the OTA image being searched for. Ver.: always - * @param imageTypeId The image type identifier contained in the OTA image being - * searched for. Ver.: always - * @param hardwareVersion This is a pointer to the hardware version that will be - * used in the search. If the pointer is NULL, hardware version will not be - * considered when searching for matching images. If it points to a value, the - * search will only consider images where that value falls between the minimum - * and maxmimum hardware version specified in the OTA file. If no hardware - * version is present in an OTA file but the other parameters match, the file - * will be considered a match Ver.: always - */ -EmberAfOtaImageId emberAfOtaStorageSearchCallback(uint16_t manufacturerId, uint16_t imageTypeId, const uint16_t * hardwareVersion) -{ - // If no image is found that matches the search criteria, this function should return the invalid image id. - return emberAfInvalidImageId; -} - -/** @brief Ota Storage Write Temp Data - * - * This function writes to the temporary data in the storage device at the - * specified offset. It is used when downloading a raw image over the air. - * - * @param offset The location within the download image file where to write the - * data. Ver.: always - * @param length The length of data to write. Ver.: always - * @param data A pointer to the temporary data that will be written to the - * storage device. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageWriteTempDataCallback(uint32_t offset, uint32_t length, const uint8_t * data) -{ - // If the image data cannot be stored, an error should be returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - /** @brief Outgoing Packet Filter * * ** REQUIRES INCLUDING THE PACKET-HANDOFF PLUGIN ** diff --git a/examples/lock-app/efr32/src/gen/callback.h b/examples/lock-app/efr32/src/gen/callback.h index fa45f2bc9298b5..a7e9bdb2d323c8 100644 --- a/examples/lock-app/efr32/src/gen/callback.h +++ b/examples/lock-app/efr32/src/gen/callback.h @@ -814,384 +814,6 @@ void emberAfNetworkFoundCallback(EmberZigbeeNetwork * networkFound, uint8_t lqi, * @param status Ver.: always */ void emberAfNetworkKeyUpdateCompleteCallback(EmberStatus status); -/** @brief Ota Bootload - * - * The platform specific routine to bootload the device from a ZigBee - * over-the-air upgrade file. - * - * @param id A pointer to the structure that contains the information about what - * OTA image to bootload. Ver.: always - * @param ncpUpgradeTagId The tag ID of the upgrade data that will be used to - * bootload the device. Ver.: always - */ -uint8_t emberAfOtaBootloadCallback(const EmberAfOtaImageId * id, uint16_t ncpUpgradeTagId); -/** @brief Ota Client Bootload - * - * This callback is fired when the OTA Client recevies a command to bootload the - * newly downloaded OTA image. This callback will perform the platform specific - * to bootload their device. - * - * @param id This is the identifier relating to the image that has been - * downloaded and is ready for bootload. Ver.: always - */ -void emberAfOtaClientBootloadCallback(const EmberAfOtaImageId * id); -/** @brief Ota Client Custom Verify - * - * This callback is executed by the OTA client after the signature verification - * has successfully completed. It allows the device to do its own custom - * verification of the image (such as verifying that the EBL is intact). - * - * @param newVerification This indicates if a new verification should be - * started. Ver.: always - * @param id This is ID of the image to be verified. Ver.: always - */ -EmberAfImageVerifyStatus emberAfOtaClientCustomVerifyCallback(bool newVerification, const EmberAfOtaImageId * id); -/** @brief Ota Client Download Complete - * - * This callback indicates that the OTA client has completed the download of a - * file. If the file has been completely downloaded and cryptographic checks - * have been turned on, then those will be performed prior to this callback and - * that outcome included in the 'success' result. On failure, this callback is - * merely informative, and the return type is ignored. On succesful download, - * this callback allows the client to perform any additional verification of the - * downloaded image and return that result to the OTA server. - * - * @param success This indicates the success or failure of the download and - * cryptographic verification process (if applicable). Ver.: always - * @param id This is the image identifier information that corresponds to the - * download result. Ver.: always - */ -bool emberAfOtaClientDownloadCompleteCallback(EmberAfOtaDownloadResult success, const EmberAfOtaImageId * id); -/** @brief Ota Client Incoming Message Raw - * - * This callback is for processing incoming messages for the Over-the-air - * bootload cluster client. ZCL will not process the message and instead hand - * the raw over the air data to the callback for its own processing. - * - * @param message A pointer to the structure containing the message buffer and - * other information about it. Ver.: always - */ -bool emberAfOtaClientIncomingMessageRawCallback(EmberAfClusterCommand * message); -/** @brief Ota Client Start - * - * This callback should be called when the profile specific registration has - * completed successfully. It will start the client's state machine that will - * find the OTA server, query it for the next image, download the image, wait - * for the bootload message, and kick off the bootload. - * - */ -void emberAfOtaClientStartCallback(void); -/** @brief Ota Client Version Info - * - * This function is called by the OTA client when a new query will occur to the - * server asking what the next version of firmware is. The client can inform - * the cluster software as to what information to use in the query (and - * subsequent download). - * - * @param currentImageInfo This is the information to use in the next query by - * the client cluster code. It contains the manufacturer ID, image type ID, and - * the firmware version to be specified in the query message sent to the server. - * Ver.: always - * @param hardwareVersion This is a pointer to the hardware version to use in - * the query. If no hardware version should be used, then - * EMBER_AF_INVALID_HARDWARE_VERSION should be used. Ver.: always - */ -void emberAfOtaClientVersionInfoCallback(EmberAfOtaImageId * currentImageInfo, uint16_t * hardwareVersion); -/** @brief Ota Page Request Server Policy - * - * This callback is called by the OTA server page request code when it wants to - * determine if it is allowed for an OTA client to make a page request. It is - * only called if page request support has been enabled on the server. It - * should return EMBER_ZCL_STATUS_SUCCESS if it allows the page request, and - * EMBER_ZCL_STATUS_UNSUP_CLUSTER_COMMAND if it does not want to allow it. - * - */ -uint8_t emberAfOtaPageRequestServerPolicyCallback(void); -/** @brief Ota Server Block Size - * - * This function provides a way for the server to adjust the block size of its - * response to an Image block request by a client. - * - * @param clientNodeId The node Id of OTA client making an image block request. - * Ver.: always - */ -uint8_t emberAfOtaServerBlockSizeCallback(EmberNodeId clientNodeId); -/** @brief Ota Server Incoming Message Raw - * - * This callback is for processing incoming messages for the Over-the-air - * bootload cluster server. ZCL will not process the message and instead hand - * the raw over the air data to the callback for its own processing. - * - * @param message A pointer to the structure containing the message buffer and - * other information about it. Ver.: always - */ -bool emberAfOtaServerIncomingMessageRawCallback(EmberAfClusterCommand * message); -/** @brief Ota Server Query - * - * This callback is fired when the OTA server receives a query request by the - * client. The callback lets the server application indicate to the client what - * the 'next' version of software is for the device, or if there is not one - * available. - * - * @param currentImageId This is the current software image that the client - * hase. Ver.: always - * @param hardwareVersion If this value is non-NULL, it indicates the hardware - * version of the client device. If NULL, the client did not specify a hardware - * version. Ver.: always - * @param nextUpgradeImageId This is a pointer to a data structure containing - * the 'next' software version for the client to download. Ver.: always - */ -uint8_t emberAfOtaServerQueryCallback(const EmberAfOtaImageId * currentImageId, uint16_t * hardwareVersion, - EmberAfOtaImageId * nextUpgradeImageId); -/** @brief Ota Server Send Image Notify - * - * This callback is an indication to the OTA server that it should send out - * notification about an OTA file that is available for download. - * - * @param dest The destination of the image notify message. May be a broadcast - * address. Ver.: always - * @param endpoint The destination endpoint of the image notify message. May be - * a broadcast endpoint. Ver.: always - * @param payloadType The type of data the image notify message will contain. 0 - * = no data. 1 = Manufacturer ID. 2 = Manufacturer ID and the image type ID. - * 3 = Manufacturer ID, image type ID, and firmware version. Ver.: always - * @param queryJitter The percentage of nodes that should respond to this - * message, from 1-100. On receipt of this message, each recipient will - * randomly choose a percentage and only query the server if their percentage is - * below this value. Ver.: always - * @param id The image information that will be put in the message. The data - * within this struct that will be appended to the message is determined by the - * previous 'payloadType' argument. Ver.: always - */ -bool emberAfOtaServerSendImageNotifyCallback(EmberNodeId dest, uint8_t endpoint, uint8_t payloadType, uint8_t queryJitter, - const EmberAfOtaImageId * id); -/** @brief Ota Server Upgrade End Request - * - * This function is called when the OTA server receives a request an upgrade end - * request. If the request indicated a successful download by the client, the - * server must tell the client when and if to upgrade to the downloaded image. - * - * @param source The node ID of the device that sent the upgrade end request. - * Ver.: always - * @param status This is the ZCL status sent by the client indicating the result - * of its attempt to download the new upgrade image. If the status is not - * EMBER_ZCL_STATUS_SUCCESS then this callback is merely informative and no - * response mesasge will be generated by the server. Ver.: always - * @param returnValue If the server returns true indicating that the client - * should apply the upgrade, this time value indicates when in the future the - * client should apply the upgrade. Ver.: always - * @param imageId This variable indicates the software version that the client - * successfully downloaded and is asking to upgrade to. Ver.: always - */ -bool emberAfOtaServerUpgradeEndRequestCallback(EmberNodeId source, uint8_t status, uint32_t * returnValue, - const EmberAfOtaImageId * imageId); -/** @brief Ota Storage Check Temp Data - * - * This callback will validate temporary data in the storage device to determine - * whether it is a complete file, a partially downloaded file, or there is no - * file present. When a complete or partial file is found it will return - * EMBER_AF_OTA_STORAGE_SUCCESS or EMBER_AF_OTA_STORAGE_PARTIAL_FILE_FOUND, - * respectively. In that case, the currentOffset, totalImageSize, and - * newFileInfo will be populated with data. When EMBER_AF_OTA_STORAGE_ERROR is - * returned, no temporary data is present. - * - * @param currentOffset A pointer to a value that will be written with the - * offset within the total file size that has been successfully stored in the - * storage device. This will indicate how much data has been currently - * dowloaded. Ver.: always - * @param totalImageSize A pointer to a value that will be written with the - * total image size of the OTA file when a download has completed. This does - * not indicate how much data has actually been downloaded currently. Ver.: - * always - * @param newFileInfo This is the image id of the temporary file data stored in - * the storage device. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageCheckTempDataCallback(uint32_t * currentOffset, uint32_t * totalImageSize, - EmberAfOtaImageId * newFileInfo); -/** @brief Ota Storage Clear Temp Data - * - * This function clears any existing temp data that was downloaed. It is used - * immediately prior to downloading a raw image over the air. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageClearTempDataCallback(void); -/** @brief Ota Storage Close - * - * This callback shuts down the ZigBee Over-the-air storage module. - * - */ -void emberAfOtaStorageCloseCallback(void); -/** @brief Ota Storage Driver Download Finish - * - * This callback defines the low-level means by which a device records the final - * offset value of the download image. - * - * @param offset The value of the final offset of the image download. Ver.: - * always - */ -void emberAfOtaStorageDriverDownloadFinishCallback(uint32_t offset); -/** @brief Ota Storage Driver Init - * - * The initialization code for the OTA storage driver. - * - */ -bool emberAfOtaStorageDriverInitCallback(void); -/** @brief Ota Storage Driver Invalidate Image - * - * This callback invalidates the image stored on disk so that it will not be - * bootloaded, and it will not be a valid image that is in the middle of - * downloading. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageDriverInvalidateImageCallback(void); -/** @brief Ota Storage Driver Prepare To Resume Download - * - * This callback allows the underlying storage driver to prepare to resume the - * OTA file download. For example, the driver may exceute a page erase to - * insure the next page is ready to be written to. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageDriverPrepareToResumeDownloadCallback(void); -/** @brief Ota Storage Driver Read - * - * This callback defines the low-level means by which a device reads from the - * OTA storage device. - * - * @param offset The address offset from the start of the storage device where - * data is to be read. Ver.: always - * @param length The length of the data to be read from the storage device. - * Ver.: always - * @param returnData A pointer where the data read from the device should be - * written to. Ver.: always - */ -bool emberAfOtaStorageDriverReadCallback(uint32_t offset, uint32_t length, uint8_t * returnData); -/** @brief Ota Storage Driver Retrieve Last Stored Offset - * - * This callback defines the low-level means by which a device retrieves the - * last persistently recorded download offset. This may be different than last - * actual download offset. - * - */ -uint32_t emberAfOtaStorageDriverRetrieveLastStoredOffsetCallback(void); -/** @brief Ota Storage Driver Write - * - * This callback defines the low-level means by which a device reads from the - * OTA storage device. - * - * @param dataToWrite A pointer to the data that will be written to the storage - * device. Ver.: always - * @param offset The address offset from the start of the storage device where - * data will be written. Ver.: always - * @param length The length of the data to be written to the storage device. - * Ver.: always - */ -bool emberAfOtaStorageDriverWriteCallback(const uint8_t * dataToWrite, uint32_t offset, uint32_t length); -/** @brief Ota Storage Finish Download - * - * This function indicates to the storage module that the download has finished. - * - * @param offset The final offset of the downloaded file (i.e. the total size) - * Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageFinishDownloadCallback(uint32_t offset); -/** @brief Ota Storage Get Count - * - * This callback returns the total number of ZigBee Over-the-air upgrade images - * stored in the storage module. - * - */ -uint8_t emberAfOtaStorageGetCountCallback(void); -/** @brief Ota Storage Get Full Header - * - * This callback populates the EmberAfOtaHeader structure pointed to by the - * returnData with data about the OTA file stored in the storage module. - * - * @param id This is a pointer to the image id for the OTA file to retrieve - * information about. Ver.: always - * @param returnData This is a pointer to the location of the structure that - * will be populated with data. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageGetFullHeaderCallback(const EmberAfOtaImageId * id, EmberAfOtaHeader * returnData); -/** @brief Ota Storage Get Total Image Size - * - * This function returns the total size of the ZigBee Over-the-air file with the - * passed parameters. If no file is found with those parameters, 0 is returned. - * - * @param id A pointer to the image identifier for the OTA file to retrieve - * information for. Ver.: always - */ -uint32_t emberAfOtaStorageGetTotalImageSizeCallback(const EmberAfOtaImageId * id); -/** @brief Ota Storage Init - * - * This callback initializes the ZigBee Over-the-air storage module. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageInitCallback(void); -/** @brief Ota Storage Iterator First - * - * This callback lets you walk through the list of all OTA files by jumping to - * the first file in the list maintained by the storage module. If there is no - * file then emberAfOtaInvalidImageId is returned. - * - */ -EmberAfOtaImageId emberAfOtaStorageIteratorFirstCallback(void); -/** @brief Ota Storage Iterator Next - * - * This callback lets you walk through the list of all OTA files by jumping to - * the next file in the list maintained by the storage module. If there is no - * next file then emberAfOtaInvalidImageId is returned. - * - */ -EmberAfOtaImageId emberAfOtaStorageIteratorNextCallback(void); -/** @brief Ota Storage Read Image Data - * - * This callback reads data from the specified OTA file and returns that data to - * the caller. - * - * @param id This is a pointer to the image id for the OTA file to retrieve data - * from. Ver.: always - * @param offset This is the offset relative to the start of the image where the - * data should be read from. Ver.: always - * @param length This is the length of data that will be read. Ver.: always - * @param returnData This is a pointer to where the data read out of the file - * will be written to Ver.: always - * @param returnedLength This is a pointer to a variable where the actual length - * of data read will be written to. A short read may occur if the end of file - * was reached. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageReadImageDataCallback(const EmberAfOtaImageId * id, uint32_t offset, uint32_t length, - uint8_t * returnData, uint32_t * returnedLength); -/** @brief Ota Storage Search - * - * This callback searches through the list of all images for one that matches - * the passed parameters. On success an image identifier is returned with a - * matching image. On failure emberAfInvalidImageId is returned. - * - * @param manufacturerId The ZigBee assigned identifier of the manufacturer - * contained in the OTA image being searched for. Ver.: always - * @param imageTypeId The image type identifier contained in the OTA image being - * searched for. Ver.: always - * @param hardwareVersion This is a pointer to the hardware version that will be - * used in the search. If the pointer is NULL, hardware version will not be - * considered when searching for matching images. If it points to a value, the - * search will only consider images where that value falls between the minimum - * and maxmimum hardware version specified in the OTA file. If no hardware - * version is present in an OTA file but the other parameters match, the file - * will be considered a match Ver.: always - */ -EmberAfOtaImageId emberAfOtaStorageSearchCallback(uint16_t manufacturerId, uint16_t imageTypeId, const uint16_t * hardwareVersion); -/** @brief Ota Storage Write Temp Data - * - * This function writes to the temporary data in the storage device at the - * specified offset. It is used when downloading a raw image over the air. - * - * @param offset The location within the download image file where to write the - * data. Ver.: always - * @param length The length of data to write. Ver.: always - * @param data A pointer to the temporary data that will be written to the - * storage device. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageWriteTempDataCallback(uint32_t offset, uint32_t length, const uint8_t * data); /** @brief Outgoing Packet Filter * * ** REQUIRES INCLUDING THE PACKET-HANDOFF PLUGIN ** diff --git a/examples/lock-app/lock-common/gen/callback-stub.c b/examples/lock-app/lock-common/gen/callback-stub.c index 1589dd1a926edd..833efb9a85ec39 100644 --- a/examples/lock-app/lock-common/gen/callback-stub.c +++ b/examples/lock-app/lock-common/gen/callback-stub.c @@ -138,15 +138,6 @@ bool emberAfAttributeWriteAccessCallback(uint8_t endpoint, EmberAfClusterId clus */ void emberAfGroupsClusterClearGroupTableCallback(uint8_t endpoint) {} -/** @brief Scenes Cluster ClearSceneTable - * - * This function is called by the framework when the application should clear - * the scene table. - * - * @param endpoint The endpoint. Ver.: always - */ -void emberAfScenesClusterClearSceneTableCallback(uint8_t endpoint) {} - /** @brief Key Establishment Cluster Client Command Received * * This function is called by the application framework when a server-to-client @@ -1001,642 +992,6 @@ void emberAfNcpIsAwakeIsrCallback(void) {} */ void emberAfNetworkKeyUpdateCompleteCallback(EmberStatus status) {} -/** @brief Ota Bootload - * - * The platform specific routine to bootload the device from a ZigBee - * over-the-air upgrade file. - * - * @param id A pointer to the structure that contains the information about what - * OTA image to bootload. Ver.: always - * @param ncpUpgradeTagId The tag ID of the upgrade data that will be used to - * bootload the device. Ver.: always - */ -uint8_t emberAfOtaBootloadCallback(const EmberAfOtaImageId * id, uint16_t ncpUpgradeTagId) -{ - // Please implement me - emberAfCorePrintln("Not supported."); - return 1; -} - -/** @brief Ota Client Bootload - * - * This callback is fired when the OTA Client recevies a command to bootload the - * newly downloaded OTA image. This callback will perform the platform specific - * to bootload their device. - * - * @param id This is the identifier relating to the image that has been - * downloaded and is ready for bootload. Ver.: always - */ -void emberAfOtaClientBootloadCallback(const EmberAfOtaImageId * id) -{ - // Any final preperation prior to the bootload should be done here. - // It is assumed that the device will reset in most all cases. - // Please implement me. -} - -/** @brief Ota Client Custom Verify - * - * This callback is executed by the OTA client after the signature verification - * has successfully completed. It allows the device to do its own custom - * verification of the image (such as verifying that the EBL is intact). - * - * @param newVerification This indicates if a new verification should be - * started. Ver.: always - * @param id This is ID of the image to be verified. Ver.: always - */ -EmberAfImageVerifyStatus emberAfOtaClientCustomVerifyCallback(bool newVerification, const EmberAfOtaImageId * id) -{ - // Manufacturing specific checks can be made to the image in this function to - // determine if it is valid. This function is called AFTER cryptographic - // checks have passed. If the cryptographic checks failed, this function will - // never be called. - - // The function shall return one of the following based on its own - // verification process. - // 1) EMBER_AF_IMAGE_GOOD - the image has passed all checks - // 2) EMBER_AF_IMAGE_BAD - the image is not valid - // 3) EMBER_AF_IMAGE_VERIFY_IN_PROGRESS - the image is valid so far, but more - // checks are needed. This callback shall be re-executed later to - // continue verification. This allows other code in the framework to run. - return EMBER_AF_IMAGE_GOOD; -} - -/** @brief Ota Client Download Complete - * - * This callback indicates that the OTA client has completed the download of a - * file. If the file has been completely downloaded and cryptographic checks - * have been turned on, then those will be performed prior to this callback and - * that outcome included in the 'success' result. On failure, this callback is - * merely informative, and the return type is ignored. On succesful download, - * this callback allows the client to perform any additional verification of the - * downloaded image and return that result to the OTA server. - * - * @param success This indicates the success or failure of the download and - * cryptographic verification process (if applicable). Ver.: always - * @param id This is the image identifier information that corresponds to the - * download result. Ver.: always - */ -bool emberAfOtaClientDownloadCompleteCallback(EmberAfOtaDownloadResult success, const EmberAfOtaImageId * id) -{ - // At this point the image has been completely downloaded and cryptographic - // checks (if applicable) have been performed. - - if (!success) - { - emberAfOtaBootloadClusterPrintln("Download failed."); - return true; // return value is ignored - } - - // This is for any additional validation that needs to be performed - // on the image by the application. - - // The results of checks here will be returned back to the OTA server - // in the Upgrade End request. - return true; -} - -/** @brief Ota Client Incoming Message Raw - * - * This callback is for processing incoming messages for the Over-the-air - * bootload cluster client. ZCL will not process the message and instead hand - * the raw over the air data to the callback for its own processing. - * - * @param message A pointer to the structure containing the message buffer and - * other information about it. Ver.: always - */ -bool emberAfOtaClientIncomingMessageRawCallback(EmberAfClusterCommand * message) -{ - return false; -} - -/** @brief Ota Client Start - * - * This callback should be called when the profile specific registration has - * completed successfully. It will start the client's state machine that will - * find the OTA server, query it for the next image, download the image, wait - * for the bootload message, and kick off the bootload. - * - */ -void emberAfOtaClientStartCallback(void) {} - -/** @brief Ota Client Version Info - * - * This function is called by the OTA client when a new query will occur to the - * server asking what the next version of firmware is. The client can inform - * the cluster software as to what information to use in the query (and - * subsequent download). - * - * @param currentImageInfo This is the information to use in the next query by - * the client cluster code. It contains the manufacturer ID, image type ID, and - * the firmware version to be specified in the query message sent to the server. - * Ver.: always - * @param hardwareVersion This is a pointer to the hardware version to use in - * the query. If no hardware version should be used, then - * EMBER_AF_INVALID_HARDWARE_VERSION should be used. Ver.: always - */ -void emberAfOtaClientVersionInfoCallback(EmberAfOtaImageId * currentImageInfo, uint16_t * hardwareVersion) -{ - // Customer will fill in the image info with their manufacturer ID, - // image type ID, and current software version number. - // The deviceSpecificFileEui64 can be ignored. - - // It may be necessary to dynamically determine this by talking to - // another device, as is the case with a host talking to an NCP device. - - // However, this routine will be called repeatedly so it may be wise - // to cache the data! - - /* This is commented out since the #defines below are not defined. - - if (currentImageInfo != NULL) { - MEMSET(currentImageInfo, 0, sizeof(EmberAfOtaImageId)); - currentImageInfo->manufacturerId = EMBER_AF_MANUFACTURER_CODE; - currentImageInfo->imageTypeId = EMBER_AF_IMAGE_TYPE_ID; - currentImageInfo->firmwareVersion = EMBER_AF_CUSTOM_FIRMWARE_VERSION; - } - - if (hardwareVersion != NULL) { - *hardwareVersion = EMBER_AF_INVALID_HARDWARE_VERSION; - } - - assert(false); - */ -} - -/** @brief Ota Page Request Server Policy - * - * This callback is called by the OTA server page request code when it wants to - * determine if it is allowed for an OTA client to make a page request. It is - * only called if page request support has been enabled on the server. It - * should return EMBER_ZCL_STATUS_SUCCESS if it allows the page request, and - * EMBER_ZCL_STATUS_UNSUP_CLUSTER_COMMAND if it does not want to allow it. - * - */ -uint8_t emberAfOtaPageRequestServerPolicyCallback(void) -{ - return EMBER_ZCL_STATUS_SUCCESS; -} - -/** @brief Ota Server Block Size - * - * This function provides a way for the server to adjust the block size of its - * response to an Image block request by a client. - * - * @param clientNodeId The node Id of OTA client making an image block request. - * Ver.: always - */ -uint8_t emberAfOtaServerBlockSizeCallback(EmberNodeId clientNodeId) -{ - // This function provides a way for the server to potentially - // adjust the block size based on the client who is requesting. - // In other words if we are using source routing we will limit - // data returned by enough to put a source route into the message. - - // Image Block Response Message Format - // Status Code: 1-byte - // Manuf Code: 2-bytes - // Image Type: 2-bytes - // File Ver: 4-bytes - // File Offset: 4-bytes - // Data Size: 1-byte - // Data: variable - const uint8_t IMAGE_BLOCK_RESPONSE_OVERHEAD = (EMBER_AF_ZCL_OVERHEAD + 14); - - EmberApsFrame apsFrame; - uint8_t maxSize; - apsFrame.options = EMBER_APS_OPTION_NONE; - - if (emberAfIsCurrentSecurityProfileSmartEnergy()) - { - apsFrame.options |= EMBER_APS_OPTION_ENCRYPTION; - } - - maxSize = emberAfMaximumApsPayloadLength(EMBER_OUTGOING_DIRECT, clientNodeId, &apsFrame); - maxSize -= IMAGE_BLOCK_RESPONSE_OVERHEAD; - return maxSize; -} - -/** @brief Ota Server Incoming Message Raw - * - * This callback is for processing incoming messages for the Over-the-air - * bootload cluster server. ZCL will not process the message and instead hand - * the raw over the air data to the callback for its own processing. - * - * @param message A pointer to the structure containing the message buffer and - * other information about it. Ver.: always - */ -bool emberAfOtaServerIncomingMessageRawCallback(EmberAfClusterCommand * message) -{ - return false; -} - -/** @brief Ota Server Query - * - * This callback is fired when the OTA server receives a query request by the - * client. The callback lets the server application indicate to the client what - * the 'next' version of software is for the device, or if there is not one - * available. - * - * @param currentImageId This is the current software image that the client - * hase. Ver.: always - * @param hardwareVersion If this value is non-NULL, it indicates the hardware - * version of the client device. If NULL, the client did not specify a hardware - * version. Ver.: always - * @param nextUpgradeImageId This is a pointer to a data structure containing - * the 'next' software version for the client to download. Ver.: always - */ -uint8_t emberAfOtaServerQueryCallback(const EmberAfOtaImageId * currentImageId, uint16_t * hardwareVersion, - EmberAfOtaImageId * nextUpgradeImageId) -{ - // If a new software image is available, this function should return EMBER_ZCL_STATUS_SUCCESS - // and populate the 'nextUpgradeImageId' structure with the appropriate values. - // If no new software image is available (i.e. the client should not download a firmware image) - // then the server should return EMBER_ZCL_STATUS_NO_IMAGE_AVAILABLE. - return EMBER_ZCL_STATUS_NO_IMAGE_AVAILABLE; -} - -/** @brief Ota Server Send Image Notify - * - * This callback is an indication to the OTA server that it should send out - * notification about an OTA file that is available for download. - * - * @param dest The destination of the image notify message. May be a broadcast - * address. Ver.: always - * @param endpoint The destination endpoint of the image notify message. May be - * a broadcast endpoint. Ver.: always - * @param payloadType The type of data the image notify message will contain. 0 - * = no data. 1 = Manufacturer ID. 2 = Manufacturer ID and the image type ID. - * 3 = Manufacturer ID, image type ID, and firmware version. Ver.: always - * @param queryJitter The percentage of nodes that should respond to this - * message, from 1-100. On receipt of this message, each recipient will - * randomly choose a percentage and only query the server if their percentage is - * below this value. Ver.: always - * @param id The image information that will be put in the message. The data - * within this struct that will be appended to the message is determined by the - * previous 'payloadType' argument. Ver.: always - */ -bool emberAfOtaServerSendImageNotifyCallback(EmberNodeId dest, uint8_t endpoint, uint8_t payloadType, uint8_t queryJitter, - const EmberAfOtaImageId * id) -{ - return false; -} - -/** @brief Ota Server Upgrade End Request - * - * This function is called when the OTA server receives a request an upgrade end - * request. If the request indicated a successful download by the client, the - * server must tell the client when and if to upgrade to the downloaded image. - * - * @param source The node ID of the device that sent the upgrade end request. - * Ver.: always - * @param status This is the ZCL status sent by the client indicating the result - * of its attempt to download the new upgrade image. If the status is not - * EMBER_ZCL_STATUS_SUCCESS then this callback is merely informative and no - * response mesasge will be generated by the server. Ver.: always - * @param returnValue If the server returns true indicating that the client - * should apply the upgrade, this time value indicates when in the future the - * client should apply the upgrade. Ver.: always - * @param imageId This variable indicates the software version that the client - * successfully downloaded and is asking to upgrade to. Ver.: always - */ -bool emberAfOtaServerUpgradeEndRequestCallback(EmberNodeId source, uint8_t status, uint32_t * returnValue, - const EmberAfOtaImageId * imageId) -{ - // If the status value is not EMBER_ZCL_STATUS_SUCCESS, then this callback is - // merely informative and no response message will be generated by the server. - // If the server wants the client to NOT apply the upgrade, then it should - // return false. - // If the server wants the client to apply the upgrade, it should return true - // and set the 'returnValue' parameter to when it wants the client to - // apply the upgrade. There are three possible values: - // 0 = Apply the upgrade now - // 0xFFFFFFFF = Don't apply yet, ask again later. - // (anything-else) = Apply the upgrade X minutes from now. - *returnValue = 0; - return true; -} - -/** @brief Ota Storage Check Temp Data - * - * This callback will validate temporary data in the storage device to determine - * whether it is a complete file, a partially downloaded file, or there is no - * file present. When a complete or partial file is found it will return - * EMBER_AF_OTA_STORAGE_SUCCESS or EMBER_AF_OTA_STORAGE_PARTIAL_FILE_FOUND, - * respectively. In that case, the currentOffset, totalImageSize, and - * newFileInfo will be populated with data. When EMBER_AF_OTA_STORAGE_ERROR is - * returned, no temporary data is present. - * - * @param currentOffset A pointer to a value that will be written with the - * offset within the total file size that has been successfully stored in the - * storage device. This will indicate how much data has been currently - * dowloaded. Ver.: always - * @param totalImageSize A pointer to a value that will be written with the - * total image size of the OTA file when a download has completed. This does - * not indicate how much data has actually been downloaded currently. Ver.: - * always - * @param newFileInfo This is the image id of the temporary file data stored in - * the storage device. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageCheckTempDataCallback(uint32_t * currentOffset, uint32_t * totalImageSize, - EmberAfOtaImageId * newFileInfo) -{ - // If the image data cannot be successfully verified, an error should be returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Clear Temp Data - * - * This function clears any existing temp data that was downloaed. It is used - * immediately prior to downloading a raw image over the air. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageClearTempDataCallback(void) -{ - // If the image data cannot be stored, an error should be returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Close - * - * This callback shuts down the ZigBee Over-the-air storage module. - * - */ -void emberAfOtaStorageCloseCallback(void) -{ - // Please implement me. - assert(false); -} - -/** @brief Ota Storage Driver Download Finish - * - * This callback defines the low-level means by which a device records the final - * offset value of the download image. - * - * @param offset The value of the final offset of the image download. Ver.: - * always - */ -void emberAfOtaStorageDriverDownloadFinishCallback(uint32_t offset) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); -} - -/** @brief Ota Storage Driver Init - * - * The initialization code for the OTA storage driver. - * - */ -bool emberAfOtaStorageDriverInitCallback(void) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); - return false; -} - -/** @brief Ota Storage Driver Invalidate Image - * - * This callback invalidates the image stored on disk so that it will not be - * bootloaded, and it will not be a valid image that is in the middle of - * downloading. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageDriverInvalidateImageCallback(void) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Driver Prepare To Resume Download - * - * This callback allows the underlying storage driver to prepare to resume the - * OTA file download. For example, the driver may exceute a page erase to - * insure the next page is ready to be written to. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageDriverPrepareToResumeDownloadCallback(void) -{ - assert(false); - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Driver Read - * - * This callback defines the low-level means by which a device reads from the - * OTA storage device. - * - * @param offset The address offset from the start of the storage device where - * data is to be read. Ver.: always - * @param length The length of the data to be read from the storage device. - * Ver.: always - * @param returnData A pointer where the data read from the device should be - * written to. Ver.: always - */ -bool emberAfOtaStorageDriverReadCallback(uint32_t offset, uint32_t length, uint8_t * returnData) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); - return false; -} - -/** @brief Ota Storage Driver Retrieve Last Stored Offset - * - * This callback defines the low-level means by which a device retrieves the - * last persistently recorded download offset. This may be different than last - * actual download offset. - * - */ -uint32_t emberAfOtaStorageDriverRetrieveLastStoredOffsetCallback(void) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); - return 0; -} - -/** @brief Ota Storage Driver Write - * - * This callback defines the low-level means by which a device reads from the - * OTA storage device. - * - * @param dataToWrite A pointer to the data that will be written to the storage - * device. Ver.: always - * @param offset The address offset from the start of the storage device where - * data will be written. Ver.: always - * @param length The length of the data to be written to the storage device. - * Ver.: always - */ -bool emberAfOtaStorageDriverWriteCallback(const uint8_t * dataToWrite, uint32_t offset, uint32_t length) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); - return false; -} - -/** @brief Ota Storage Finish Download - * - * This function indicates to the storage module that the download has finished. - * - * @param offset The final offset of the downloaded file (i.e. the total size) - * Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageFinishDownloadCallback(uint32_t offset) -{ - return EMBER_AF_OTA_STORAGE_SUCCESS; -} - -/** @brief Ota Storage Get Count - * - * This callback returns the total number of ZigBee Over-the-air upgrade images - * stored in the storage module. - * - */ -uint8_t emberAfOtaStorageGetCountCallback(void) -{ - return 0; -} - -/** @brief Ota Storage Get Full Header - * - * This callback populates the EmberAfOtaHeader structure pointed to by the - * returnData with data about the OTA file stored in the storage module. - * - * @param id This is a pointer to the image id for the OTA file to retrieve - * information about. Ver.: always - * @param returnData This is a pointer to the location of the structure that - * will be populated with data. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageGetFullHeaderCallback(const EmberAfOtaImageId * id, EmberAfOtaHeader * returnData) -{ - // If the requested image cannot be found, then an error shouldb e returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Get Total Image Size - * - * This function returns the total size of the ZigBee Over-the-air file with the - * passed parameters. If no file is found with those parameters, 0 is returned. - * - * @param id A pointer to the image identifier for the OTA file to retrieve - * information for. Ver.: always - */ -uint32_t emberAfOtaStorageGetTotalImageSizeCallback(const EmberAfOtaImageId * id) -{ - // On failure this should return an image size of zero. - return 0; -} - -/** @brief Ota Storage Init - * - * This callback initializes the ZigBee Over-the-air storage module. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageInitCallback(void) -{ - return EMBER_AF_OTA_STORAGE_SUCCESS; -} - -/** @brief Ota Storage Iterator First - * - * This callback lets you walk through the list of all OTA files by jumping to - * the first file in the list maintained by the storage module. If there is no - * file then emberAfOtaInvalidImageId is returned. - * - */ -EmberAfOtaImageId emberAfOtaStorageIteratorFirstCallback(void) -{ - // It is expected that the storage module maintain its own internal iterator that the 'first' and 'next' functions will - // manipulate. - - // If there are no images at all, this function should return the invalid image id. - return emberAfInvalidImageId; -} - -/** @brief Ota Storage Iterator Next - * - * This callback lets you walk through the list of all OTA files by jumping to - * the next file in the list maintained by the storage module. If there is no - * next file then emberAfOtaInvalidImageId is returned. - * - */ -EmberAfOtaImageId emberAfOtaStorageIteratorNextCallback(void) -{ - // It is expected that the storage module maintain its own internal iterator that the 'first' and 'next' functions will - // manipulate. - - // If there are no more images, this function should return the invalid image id. - return emberAfInvalidImageId; -} - -/** @brief Ota Storage Read Image Data - * - * This callback reads data from the specified OTA file and returns that data to - * the caller. - * - * @param id This is a pointer to the image id for the OTA file to retrieve data - * from. Ver.: always - * @param offset This is the offset relative to the start of the image where the - * data should be read from. Ver.: always - * @param length This is the length of data that will be read. Ver.: always - * @param returnData This is a pointer to where the data read out of the file - * will be written to Ver.: always - * @param returnedLength This is a pointer to a variable where the actual length - * of data read will be written to. A short read may occur if the end of file - * was reached. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageReadImageDataCallback(const EmberAfOtaImageId * id, uint32_t offset, uint32_t length, - uint8_t * returnData, uint32_t * returnedLength) -{ - // If the requested image cannot be found, then an error should be returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Search - * - * This callback searches through the list of all images for one that matches - * the passed parameters. On success an image identifier is returned with a - * matching image. On failure emberAfInvalidImageId is returned. - * - * @param manufacturerId The ZigBee assigned identifier of the manufacturer - * contained in the OTA image being searched for. Ver.: always - * @param imageTypeId The image type identifier contained in the OTA image being - * searched for. Ver.: always - * @param hardwareVersion This is a pointer to the hardware version that will be - * used in the search. If the pointer is NULL, hardware version will not be - * considered when searching for matching images. If it points to a value, the - * search will only consider images where that value falls between the minimum - * and maxmimum hardware version specified in the OTA file. If no hardware - * version is present in an OTA file but the other parameters match, the file - * will be considered a match Ver.: always - */ -EmberAfOtaImageId emberAfOtaStorageSearchCallback(uint16_t manufacturerId, uint16_t imageTypeId, const uint16_t * hardwareVersion) -{ - // If no image is found that matches the search criteria, this function should return the invalid image id. - return emberAfInvalidImageId; -} - -/** @brief Ota Storage Write Temp Data - * - * This function writes to the temporary data in the storage device at the - * specified offset. It is used when downloading a raw image over the air. - * - * @param offset The location within the download image file where to write the - * data. Ver.: always - * @param length The length of data to write. Ver.: always - * @param data A pointer to the temporary data that will be written to the - * storage device. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageWriteTempDataCallback(uint32_t offset, uint32_t length, const uint8_t * data) -{ - // If the image data cannot be stored, an error should be returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - /** @brief Outgoing Packet Filter * * ** REQUIRES INCLUDING THE PACKET-HANDOFF PLUGIN ** diff --git a/examples/lock-app/lock-common/gen/callback.h b/examples/lock-app/lock-common/gen/callback.h index e64238dc7c91df..8c87346aea9715 100644 --- a/examples/lock-app/lock-common/gen/callback.h +++ b/examples/lock-app/lock-common/gen/callback.h @@ -814,384 +814,6 @@ void emberAfNetworkFoundCallback(EmberZigbeeNetwork * networkFound, uint8_t lqi, * @param status Ver.: always */ void emberAfNetworkKeyUpdateCompleteCallback(EmberStatus status); -/** @brief Ota Bootload - * - * The platform specific routine to bootload the device from a ZigBee - * over-the-air upgrade file. - * - * @param id A pointer to the structure that contains the information about what - * OTA image to bootload. Ver.: always - * @param ncpUpgradeTagId The tag ID of the upgrade data that will be used to - * bootload the device. Ver.: always - */ -uint8_t emberAfOtaBootloadCallback(const EmberAfOtaImageId * id, uint16_t ncpUpgradeTagId); -/** @brief Ota Client Bootload - * - * This callback is fired when the OTA Client recevies a command to bootload the - * newly downloaded OTA image. This callback will perform the platform specific - * to bootload their device. - * - * @param id This is the identifier relating to the image that has been - * downloaded and is ready for bootload. Ver.: always - */ -void emberAfOtaClientBootloadCallback(const EmberAfOtaImageId * id); -/** @brief Ota Client Custom Verify - * - * This callback is executed by the OTA client after the signature verification - * has successfully completed. It allows the device to do its own custom - * verification of the image (such as verifying that the EBL is intact). - * - * @param newVerification This indicates if a new verification should be - * started. Ver.: always - * @param id This is ID of the image to be verified. Ver.: always - */ -EmberAfImageVerifyStatus emberAfOtaClientCustomVerifyCallback(bool newVerification, const EmberAfOtaImageId * id); -/** @brief Ota Client Download Complete - * - * This callback indicates that the OTA client has completed the download of a - * file. If the file has been completely downloaded and cryptographic checks - * have been turned on, then those will be performed prior to this callback and - * that outcome included in the 'success' result. On failure, this callback is - * merely informative, and the return type is ignored. On succesful download, - * this callback allows the client to perform any additional verification of the - * downloaded image and return that result to the OTA server. - * - * @param success This indicates the success or failure of the download and - * cryptographic verification process (if applicable). Ver.: always - * @param id This is the image identifier information that corresponds to the - * download result. Ver.: always - */ -bool emberAfOtaClientDownloadCompleteCallback(EmberAfOtaDownloadResult success, const EmberAfOtaImageId * id); -/** @brief Ota Client Incoming Message Raw - * - * This callback is for processing incoming messages for the Over-the-air - * bootload cluster client. ZCL will not process the message and instead hand - * the raw over the air data to the callback for its own processing. - * - * @param message A pointer to the structure containing the message buffer and - * other information about it. Ver.: always - */ -bool emberAfOtaClientIncomingMessageRawCallback(EmberAfClusterCommand * message); -/** @brief Ota Client Start - * - * This callback should be called when the profile specific registration has - * completed successfully. It will start the client's state machine that will - * find the OTA server, query it for the next image, download the image, wait - * for the bootload message, and kick off the bootload. - * - */ -void emberAfOtaClientStartCallback(void); -/** @brief Ota Client Version Info - * - * This function is called by the OTA client when a new query will occur to the - * server asking what the next version of firmware is. The client can inform - * the cluster software as to what information to use in the query (and - * subsequent download). - * - * @param currentImageInfo This is the information to use in the next query by - * the client cluster code. It contains the manufacturer ID, image type ID, and - * the firmware version to be specified in the query message sent to the server. - * Ver.: always - * @param hardwareVersion This is a pointer to the hardware version to use in - * the query. If no hardware version should be used, then - * EMBER_AF_INVALID_HARDWARE_VERSION should be used. Ver.: always - */ -void emberAfOtaClientVersionInfoCallback(EmberAfOtaImageId * currentImageInfo, uint16_t * hardwareVersion); -/** @brief Ota Page Request Server Policy - * - * This callback is called by the OTA server page request code when it wants to - * determine if it is allowed for an OTA client to make a page request. It is - * only called if page request support has been enabled on the server. It - * should return EMBER_ZCL_STATUS_SUCCESS if it allows the page request, and - * EMBER_ZCL_STATUS_UNSUP_CLUSTER_COMMAND if it does not want to allow it. - * - */ -uint8_t emberAfOtaPageRequestServerPolicyCallback(void); -/** @brief Ota Server Block Size - * - * This function provides a way for the server to adjust the block size of its - * response to an Image block request by a client. - * - * @param clientNodeId The node Id of OTA client making an image block request. - * Ver.: always - */ -uint8_t emberAfOtaServerBlockSizeCallback(EmberNodeId clientNodeId); -/** @brief Ota Server Incoming Message Raw - * - * This callback is for processing incoming messages for the Over-the-air - * bootload cluster server. ZCL will not process the message and instead hand - * the raw over the air data to the callback for its own processing. - * - * @param message A pointer to the structure containing the message buffer and - * other information about it. Ver.: always - */ -bool emberAfOtaServerIncomingMessageRawCallback(EmberAfClusterCommand * message); -/** @brief Ota Server Query - * - * This callback is fired when the OTA server receives a query request by the - * client. The callback lets the server application indicate to the client what - * the 'next' version of software is for the device, or if there is not one - * available. - * - * @param currentImageId This is the current software image that the client - * hase. Ver.: always - * @param hardwareVersion If this value is non-NULL, it indicates the hardware - * version of the client device. If NULL, the client did not specify a hardware - * version. Ver.: always - * @param nextUpgradeImageId This is a pointer to a data structure containing - * the 'next' software version for the client to download. Ver.: always - */ -uint8_t emberAfOtaServerQueryCallback(const EmberAfOtaImageId * currentImageId, uint16_t * hardwareVersion, - EmberAfOtaImageId * nextUpgradeImageId); -/** @brief Ota Server Send Image Notify - * - * This callback is an indication to the OTA server that it should send out - * notification about an OTA file that is available for download. - * - * @param dest The destination of the image notify message. May be a broadcast - * address. Ver.: always - * @param endpoint The destination endpoint of the image notify message. May be - * a broadcast endpoint. Ver.: always - * @param payloadType The type of data the image notify message will contain. 0 - * = no data. 1 = Manufacturer ID. 2 = Manufacturer ID and the image type ID. - * 3 = Manufacturer ID, image type ID, and firmware version. Ver.: always - * @param queryJitter The percentage of nodes that should respond to this - * message, from 1-100. On receipt of this message, each recipient will - * randomly choose a percentage and only query the server if their percentage is - * below this value. Ver.: always - * @param id The image information that will be put in the message. The data - * within this struct that will be appended to the message is determined by the - * previous 'payloadType' argument. Ver.: always - */ -bool emberAfOtaServerSendImageNotifyCallback(EmberNodeId dest, uint8_t endpoint, uint8_t payloadType, uint8_t queryJitter, - const EmberAfOtaImageId * id); -/** @brief Ota Server Upgrade End Request - * - * This function is called when the OTA server receives a request an upgrade end - * request. If the request indicated a successful download by the client, the - * server must tell the client when and if to upgrade to the downloaded image. - * - * @param source The node ID of the device that sent the upgrade end request. - * Ver.: always - * @param status This is the ZCL status sent by the client indicating the result - * of its attempt to download the new upgrade image. If the status is not - * EMBER_ZCL_STATUS_SUCCESS then this callback is merely informative and no - * response mesasge will be generated by the server. Ver.: always - * @param returnValue If the server returns true indicating that the client - * should apply the upgrade, this time value indicates when in the future the - * client should apply the upgrade. Ver.: always - * @param imageId This variable indicates the software version that the client - * successfully downloaded and is asking to upgrade to. Ver.: always - */ -bool emberAfOtaServerUpgradeEndRequestCallback(EmberNodeId source, uint8_t status, uint32_t * returnValue, - const EmberAfOtaImageId * imageId); -/** @brief Ota Storage Check Temp Data - * - * This callback will validate temporary data in the storage device to determine - * whether it is a complete file, a partially downloaded file, or there is no - * file present. When a complete or partial file is found it will return - * EMBER_AF_OTA_STORAGE_SUCCESS or EMBER_AF_OTA_STORAGE_PARTIAL_FILE_FOUND, - * respectively. In that case, the currentOffset, totalImageSize, and - * newFileInfo will be populated with data. When EMBER_AF_OTA_STORAGE_ERROR is - * returned, no temporary data is present. - * - * @param currentOffset A pointer to a value that will be written with the - * offset within the total file size that has been successfully stored in the - * storage device. This will indicate how much data has been currently - * dowloaded. Ver.: always - * @param totalImageSize A pointer to a value that will be written with the - * total image size of the OTA file when a download has completed. This does - * not indicate how much data has actually been downloaded currently. Ver.: - * always - * @param newFileInfo This is the image id of the temporary file data stored in - * the storage device. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageCheckTempDataCallback(uint32_t * currentOffset, uint32_t * totalImageSize, - EmberAfOtaImageId * newFileInfo); -/** @brief Ota Storage Clear Temp Data - * - * This function clears any existing temp data that was downloaed. It is used - * immediately prior to downloading a raw image over the air. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageClearTempDataCallback(void); -/** @brief Ota Storage Close - * - * This callback shuts down the ZigBee Over-the-air storage module. - * - */ -void emberAfOtaStorageCloseCallback(void); -/** @brief Ota Storage Driver Download Finish - * - * This callback defines the low-level means by which a device records the final - * offset value of the download image. - * - * @param offset The value of the final offset of the image download. Ver.: - * always - */ -void emberAfOtaStorageDriverDownloadFinishCallback(uint32_t offset); -/** @brief Ota Storage Driver Init - * - * The initialization code for the OTA storage driver. - * - */ -bool emberAfOtaStorageDriverInitCallback(void); -/** @brief Ota Storage Driver Invalidate Image - * - * This callback invalidates the image stored on disk so that it will not be - * bootloaded, and it will not be a valid image that is in the middle of - * downloading. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageDriverInvalidateImageCallback(void); -/** @brief Ota Storage Driver Prepare To Resume Download - * - * This callback allows the underlying storage driver to prepare to resume the - * OTA file download. For example, the driver may exceute a page erase to - * insure the next page is ready to be written to. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageDriverPrepareToResumeDownloadCallback(void); -/** @brief Ota Storage Driver Read - * - * This callback defines the low-level means by which a device reads from the - * OTA storage device. - * - * @param offset The address offset from the start of the storage device where - * data is to be read. Ver.: always - * @param length The length of the data to be read from the storage device. - * Ver.: always - * @param returnData A pointer where the data read from the device should be - * written to. Ver.: always - */ -bool emberAfOtaStorageDriverReadCallback(uint32_t offset, uint32_t length, uint8_t * returnData); -/** @brief Ota Storage Driver Retrieve Last Stored Offset - * - * This callback defines the low-level means by which a device retrieves the - * last persistently recorded download offset. This may be different than last - * actual download offset. - * - */ -uint32_t emberAfOtaStorageDriverRetrieveLastStoredOffsetCallback(void); -/** @brief Ota Storage Driver Write - * - * This callback defines the low-level means by which a device reads from the - * OTA storage device. - * - * @param dataToWrite A pointer to the data that will be written to the storage - * device. Ver.: always - * @param offset The address offset from the start of the storage device where - * data will be written. Ver.: always - * @param length The length of the data to be written to the storage device. - * Ver.: always - */ -bool emberAfOtaStorageDriverWriteCallback(const uint8_t * dataToWrite, uint32_t offset, uint32_t length); -/** @brief Ota Storage Finish Download - * - * This function indicates to the storage module that the download has finished. - * - * @param offset The final offset of the downloaded file (i.e. the total size) - * Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageFinishDownloadCallback(uint32_t offset); -/** @brief Ota Storage Get Count - * - * This callback returns the total number of ZigBee Over-the-air upgrade images - * stored in the storage module. - * - */ -uint8_t emberAfOtaStorageGetCountCallback(void); -/** @brief Ota Storage Get Full Header - * - * This callback populates the EmberAfOtaHeader structure pointed to by the - * returnData with data about the OTA file stored in the storage module. - * - * @param id This is a pointer to the image id for the OTA file to retrieve - * information about. Ver.: always - * @param returnData This is a pointer to the location of the structure that - * will be populated with data. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageGetFullHeaderCallback(const EmberAfOtaImageId * id, EmberAfOtaHeader * returnData); -/** @brief Ota Storage Get Total Image Size - * - * This function returns the total size of the ZigBee Over-the-air file with the - * passed parameters. If no file is found with those parameters, 0 is returned. - * - * @param id A pointer to the image identifier for the OTA file to retrieve - * information for. Ver.: always - */ -uint32_t emberAfOtaStorageGetTotalImageSizeCallback(const EmberAfOtaImageId * id); -/** @brief Ota Storage Init - * - * This callback initializes the ZigBee Over-the-air storage module. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageInitCallback(void); -/** @brief Ota Storage Iterator First - * - * This callback lets you walk through the list of all OTA files by jumping to - * the first file in the list maintained by the storage module. If there is no - * file then emberAfOtaInvalidImageId is returned. - * - */ -EmberAfOtaImageId emberAfOtaStorageIteratorFirstCallback(void); -/** @brief Ota Storage Iterator Next - * - * This callback lets you walk through the list of all OTA files by jumping to - * the next file in the list maintained by the storage module. If there is no - * next file then emberAfOtaInvalidImageId is returned. - * - */ -EmberAfOtaImageId emberAfOtaStorageIteratorNextCallback(void); -/** @brief Ota Storage Read Image Data - * - * This callback reads data from the specified OTA file and returns that data to - * the caller. - * - * @param id This is a pointer to the image id for the OTA file to retrieve data - * from. Ver.: always - * @param offset This is the offset relative to the start of the image where the - * data should be read from. Ver.: always - * @param length This is the length of data that will be read. Ver.: always - * @param returnData This is a pointer to where the data read out of the file - * will be written to Ver.: always - * @param returnedLength This is a pointer to a variable where the actual length - * of data read will be written to. A short read may occur if the end of file - * was reached. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageReadImageDataCallback(const EmberAfOtaImageId * id, uint32_t offset, uint32_t length, - uint8_t * returnData, uint32_t * returnedLength); -/** @brief Ota Storage Search - * - * This callback searches through the list of all images for one that matches - * the passed parameters. On success an image identifier is returned with a - * matching image. On failure emberAfInvalidImageId is returned. - * - * @param manufacturerId The ZigBee assigned identifier of the manufacturer - * contained in the OTA image being searched for. Ver.: always - * @param imageTypeId The image type identifier contained in the OTA image being - * searched for. Ver.: always - * @param hardwareVersion This is a pointer to the hardware version that will be - * used in the search. If the pointer is NULL, hardware version will not be - * considered when searching for matching images. If it points to a value, the - * search will only consider images where that value falls between the minimum - * and maxmimum hardware version specified in the OTA file. If no hardware - * version is present in an OTA file but the other parameters match, the file - * will be considered a match Ver.: always - */ -EmberAfOtaImageId emberAfOtaStorageSearchCallback(uint16_t manufacturerId, uint16_t imageTypeId, const uint16_t * hardwareVersion); -/** @brief Ota Storage Write Temp Data - * - * This function writes to the temporary data in the storage device at the - * specified offset. It is used when downloading a raw image over the air. - * - * @param offset The location within the download image file where to write the - * data. Ver.: always - * @param length The length of data to write. Ver.: always - * @param data A pointer to the temporary data that will be written to the - * storage device. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageWriteTempDataCallback(uint32_t offset, uint32_t length, const uint8_t * data); /** @brief Outgoing Packet Filter * * ** REQUIRES INCLUDING THE PACKET-HANDOFF PLUGIN ** diff --git a/examples/temperature-measurement-app/esp32/main/gen/callback-stub.c b/examples/temperature-measurement-app/esp32/main/gen/callback-stub.c index 3ef3ba55d8a5dd..52ae5bf8852902 100644 --- a/examples/temperature-measurement-app/esp32/main/gen/callback-stub.c +++ b/examples/temperature-measurement-app/esp32/main/gen/callback-stub.c @@ -119,15 +119,6 @@ bool emberAfAttributeWriteAccessCallback(uint8_t endpoint, EmberAfClusterId clus */ void emberAfGroupsClusterClearGroupTableCallback(uint8_t endpoint) {} -/** @brief Scenes Cluster ClearSceneTable - * - * This function is called by the framework when the application should clear - * the scene table. - * - * @param endpoint The endpoint. Ver.: always - */ -void emberAfScenesClusterClearSceneTableCallback(uint8_t endpoint) {} - /** @brief Key Establishment Cluster Client Command Received * * This function is called by the application framework when a server-to-client @@ -1005,642 +996,6 @@ void emberAfNetworkFoundCallback(EmberZigbeeNetwork * networkFound, uint8_t lqi, */ void emberAfNetworkKeyUpdateCompleteCallback(EmberStatus status) {} -/** @brief Ota Bootload - * - * The platform specific routine to bootload the device from a ZigBee - * over-the-air upgrade file. - * - * @param id A pointer to the structure that contains the information about what - * OTA image to bootload. Ver.: always - * @param ncpUpgradeTagId The tag ID of the upgrade data that will be used to - * bootload the device. Ver.: always - */ -uint8_t emberAfOtaBootloadCallback(const EmberAfOtaImageId * id, uint16_t ncpUpgradeTagId) -{ - // Please implement me - emberAfCorePrintln("Not supported."); - return 1; -} - -/** @brief Ota Client Bootload - * - * This callback is fired when the OTA Client recevies a command to bootload the - * newly downloaded OTA image. This callback will perform the platform specific - * to bootload their device. - * - * @param id This is the identifier relating to the image that has been - * downloaded and is ready for bootload. Ver.: always - */ -void emberAfOtaClientBootloadCallback(const EmberAfOtaImageId * id) -{ - // Any final preperation prior to the bootload should be done here. - // It is assumed that the device will reset in most all cases. - // Please implement me. -} - -/** @brief Ota Client Custom Verify - * - * This callback is executed by the OTA client after the signature verification - * has successfully completed. It allows the device to do its own custom - * verification of the image (such as verifying that the EBL is intact). - * - * @param newVerification This indicates if a new verification should be - * started. Ver.: always - * @param id This is ID of the image to be verified. Ver.: always - */ -EmberAfImageVerifyStatus emberAfOtaClientCustomVerifyCallback(bool newVerification, const EmberAfOtaImageId * id) -{ - // Manufacturing specific checks can be made to the image in this function to - // determine if it is valid. This function is called AFTER cryptographic - // checks have passed. If the cryptographic checks failed, this function will - // never be called. - - // The function shall return one of the following based on its own - // verification process. - // 1) EMBER_AF_IMAGE_GOOD - the image has passed all checks - // 2) EMBER_AF_IMAGE_BAD - the image is not valid - // 3) EMBER_AF_IMAGE_VERIFY_IN_PROGRESS - the image is valid so far, but more - // checks are needed. This callback shall be re-executed later to - // continue verification. This allows other code in the framework to run. - return EMBER_AF_IMAGE_GOOD; -} - -/** @brief Ota Client Download Complete - * - * This callback indicates that the OTA client has completed the download of a - * file. If the file has been completely downloaded and cryptographic checks - * have been turned on, then those will be performed prior to this callback and - * that outcome included in the 'success' result. On failure, this callback is - * merely informative, and the return type is ignored. On succesful download, - * this callback allows the client to perform any additional verification of the - * downloaded image and return that result to the OTA server. - * - * @param success This indicates the success or failure of the download and - * cryptographic verification process (if applicable). Ver.: always - * @param id This is the image identifier information that corresponds to the - * download result. Ver.: always - */ -bool emberAfOtaClientDownloadCompleteCallback(EmberAfOtaDownloadResult success, const EmberAfOtaImageId * id) -{ - // At this point the image has been completely downloaded and cryptographic - // checks (if applicable) have been performed. - - if (!success) - { - emberAfOtaBootloadClusterPrintln("Download failed."); - return true; // return value is ignored - } - - // This is for any additional validation that needs to be performed - // on the image by the application. - - // The results of checks here will be returned back to the OTA server - // in the Upgrade End request. - return true; -} - -/** @brief Ota Client Incoming Message Raw - * - * This callback is for processing incoming messages for the Over-the-air - * bootload cluster client. ZCL will not process the message and instead hand - * the raw over the air data to the callback for its own processing. - * - * @param message A pointer to the structure containing the message buffer and - * other information about it. Ver.: always - */ -bool emberAfOtaClientIncomingMessageRawCallback(EmberAfClusterCommand * message) -{ - return false; -} - -/** @brief Ota Client Start - * - * This callback should be called when the profile specific registration has - * completed successfully. It will start the client's state machine that will - * find the OTA server, query it for the next image, download the image, wait - * for the bootload message, and kick off the bootload. - * - */ -void emberAfOtaClientStartCallback(void) {} - -/** @brief Ota Client Version Info - * - * This function is called by the OTA client when a new query will occur to the - * server asking what the next version of firmware is. The client can inform - * the cluster software as to what information to use in the query (and - * subsequent download). - * - * @param currentImageInfo This is the information to use in the next query by - * the client cluster code. It contains the manufacturer ID, image type ID, and - * the firmware version to be specified in the query message sent to the server. - * Ver.: always - * @param hardwareVersion This is a pointer to the hardware version to use in - * the query. If no hardware version should be used, then - * EMBER_AF_INVALID_HARDWARE_VERSION should be used. Ver.: always - */ -void emberAfOtaClientVersionInfoCallback(EmberAfOtaImageId * currentImageInfo, uint16_t * hardwareVersion) -{ - // Customer will fill in the image info with their manufacturer ID, - // image type ID, and current software version number. - // The deviceSpecificFileEui64 can be ignored. - - // It may be necessary to dynamically determine this by talking to - // another device, as is the case with a host talking to an NCP device. - - // However, this routine will be called repeatedly so it may be wise - // to cache the data! - - /* This is commented out since the #defines below are not defined. - - if (currentImageInfo != NULL) { - MEMSET(currentImageInfo, 0, sizeof(EmberAfOtaImageId)); - currentImageInfo->manufacturerId = EMBER_AF_MANUFACTURER_CODE; - currentImageInfo->imageTypeId = EMBER_AF_IMAGE_TYPE_ID; - currentImageInfo->firmwareVersion = EMBER_AF_CUSTOM_FIRMWARE_VERSION; - } - - if (hardwareVersion != NULL) { - *hardwareVersion = EMBER_AF_INVALID_HARDWARE_VERSION; - } - - assert(false); - */ -} - -/** @brief Ota Page Request Server Policy - * - * This callback is called by the OTA server page request code when it wants to - * determine if it is allowed for an OTA client to make a page request. It is - * only called if page request support has been enabled on the server. It - * should return EMBER_ZCL_STATUS_SUCCESS if it allows the page request, and - * EMBER_ZCL_STATUS_UNSUP_CLUSTER_COMMAND if it does not want to allow it. - * - */ -uint8_t emberAfOtaPageRequestServerPolicyCallback(void) -{ - return EMBER_ZCL_STATUS_SUCCESS; -} - -/** @brief Ota Server Block Size - * - * This function provides a way for the server to adjust the block size of its - * response to an Image block request by a client. - * - * @param clientNodeId The node Id of OTA client making an image block request. - * Ver.: always - */ -uint8_t emberAfOtaServerBlockSizeCallback(EmberNodeId clientNodeId) -{ - // This function provides a way for the server to potentially - // adjust the block size based on the client who is requesting. - // In other words if we are using source routing we will limit - // data returned by enough to put a source route into the message. - - // Image Block Response Message Format - // Status Code: 1-byte - // Manuf Code: 2-bytes - // Image Type: 2-bytes - // File Ver: 4-bytes - // File Offset: 4-bytes - // Data Size: 1-byte - // Data: variable - const uint8_t IMAGE_BLOCK_RESPONSE_OVERHEAD = (EMBER_AF_ZCL_OVERHEAD + 14); - - EmberApsFrame apsFrame; - uint8_t maxSize; - apsFrame.options = EMBER_APS_OPTION_NONE; - - if (emberAfIsCurrentSecurityProfileSmartEnergy()) - { - apsFrame.options |= EMBER_APS_OPTION_ENCRYPTION; - } - - maxSize = emberAfMaximumApsPayloadLength(EMBER_OUTGOING_DIRECT, clientNodeId, &apsFrame); - maxSize -= IMAGE_BLOCK_RESPONSE_OVERHEAD; - return maxSize; -} - -/** @brief Ota Server Incoming Message Raw - * - * This callback is for processing incoming messages for the Over-the-air - * bootload cluster server. ZCL will not process the message and instead hand - * the raw over the air data to the callback for its own processing. - * - * @param message A pointer to the structure containing the message buffer and - * other information about it. Ver.: always - */ -bool emberAfOtaServerIncomingMessageRawCallback(EmberAfClusterCommand * message) -{ - return false; -} - -/** @brief Ota Server Query - * - * This callback is fired when the OTA server receives a query request by the - * client. The callback lets the server application indicate to the client what - * the 'next' version of software is for the device, or if there is not one - * available. - * - * @param currentImageId This is the current software image that the client - * hase. Ver.: always - * @param hardwareVersion If this value is non-NULL, it indicates the hardware - * version of the client device. If NULL, the client did not specify a hardware - * version. Ver.: always - * @param nextUpgradeImageId This is a pointer to a data structure containing - * the 'next' software version for the client to download. Ver.: always - */ -uint8_t emberAfOtaServerQueryCallback(const EmberAfOtaImageId * currentImageId, uint16_t * hardwareVersion, - EmberAfOtaImageId * nextUpgradeImageId) -{ - // If a new software image is available, this function should return EMBER_ZCL_STATUS_SUCCESS - // and populate the 'nextUpgradeImageId' structure with the appropriate values. - // If no new software image is available (i.e. the client should not download a firmware image) - // then the server should return EMBER_ZCL_STATUS_NO_IMAGE_AVAILABLE. - return EMBER_ZCL_STATUS_NO_IMAGE_AVAILABLE; -} - -/** @brief Ota Server Send Image Notify - * - * This callback is an indication to the OTA server that it should send out - * notification about an OTA file that is available for download. - * - * @param dest The destination of the image notify message. May be a broadcast - * address. Ver.: always - * @param endpoint The destination endpoint of the image notify message. May be - * a broadcast endpoint. Ver.: always - * @param payloadType The type of data the image notify message will contain. 0 - * = no data. 1 = Manufacturer ID. 2 = Manufacturer ID and the image type ID. - * 3 = Manufacturer ID, image type ID, and firmware version. Ver.: always - * @param queryJitter The percentage of nodes that should respond to this - * message, from 1-100. On receipt of this message, each recipient will - * randomly choose a percentage and only query the server if their percentage is - * below this value. Ver.: always - * @param id The image information that will be put in the message. The data - * within this struct that will be appended to the message is determined by the - * previous 'payloadType' argument. Ver.: always - */ -bool emberAfOtaServerSendImageNotifyCallback(EmberNodeId dest, uint8_t endpoint, uint8_t payloadType, uint8_t queryJitter, - const EmberAfOtaImageId * id) -{ - return false; -} - -/** @brief Ota Server Upgrade End Request - * - * This function is called when the OTA server receives a request an upgrade end - * request. If the request indicated a successful download by the client, the - * server must tell the client when and if to upgrade to the downloaded image. - * - * @param source The node ID of the device that sent the upgrade end request. - * Ver.: always - * @param status This is the ZCL status sent by the client indicating the result - * of its attempt to download the new upgrade image. If the status is not - * EMBER_ZCL_STATUS_SUCCESS then this callback is merely informative and no - * response mesasge will be generated by the server. Ver.: always - * @param returnValue If the server returns true indicating that the client - * should apply the upgrade, this time value indicates when in the future the - * client should apply the upgrade. Ver.: always - * @param imageId This variable indicates the software version that the client - * successfully downloaded and is asking to upgrade to. Ver.: always - */ -bool emberAfOtaServerUpgradeEndRequestCallback(EmberNodeId source, uint8_t status, uint32_t * returnValue, - const EmberAfOtaImageId * imageId) -{ - // If the status value is not EMBER_ZCL_STATUS_SUCCESS, then this callback is - // merely informative and no response message will be generated by the server. - // If the server wants the client to NOT apply the upgrade, then it should - // return false. - // If the server wants the client to apply the upgrade, it should return true - // and set the 'returnValue' parameter to when it wants the client to - // apply the upgrade. There are three possible values: - // 0 = Apply the upgrade now - // 0xFFFFFFFF = Don't apply yet, ask again later. - // (anything-else) = Apply the upgrade X minutes from now. - *returnValue = 0; - return true; -} - -/** @brief Ota Storage Check Temp Data - * - * This callback will validate temporary data in the storage device to determine - * whether it is a complete file, a partially downloaded file, or there is no - * file present. When a complete or partial file is found it will return - * EMBER_AF_OTA_STORAGE_SUCCESS or EMBER_AF_OTA_STORAGE_PARTIAL_FILE_FOUND, - * respectively. In that case, the currentOffset, totalImageSize, and - * newFileInfo will be populated with data. When EMBER_AF_OTA_STORAGE_ERROR is - * returned, no temporary data is present. - * - * @param currentOffset A pointer to a value that will be written with the - * offset within the total file size that has been successfully stored in the - * storage device. This will indicate how much data has been currently - * dowloaded. Ver.: always - * @param totalImageSize A pointer to a value that will be written with the - * total image size of the OTA file when a download has completed. This does - * not indicate how much data has actually been downloaded currently. Ver.: - * always - * @param newFileInfo This is the image id of the temporary file data stored in - * the storage device. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageCheckTempDataCallback(uint32_t * currentOffset, uint32_t * totalImageSize, - EmberAfOtaImageId * newFileInfo) -{ - // If the image data cannot be successfully verified, an error should be returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Clear Temp Data - * - * This function clears any existing temp data that was downloaed. It is used - * immediately prior to downloading a raw image over the air. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageClearTempDataCallback(void) -{ - // If the image data cannot be stored, an error should be returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Close - * - * This callback shuts down the ZigBee Over-the-air storage module. - * - */ -void emberAfOtaStorageCloseCallback(void) -{ - // Please implement me. - assert(false); -} - -/** @brief Ota Storage Driver Download Finish - * - * This callback defines the low-level means by which a device records the final - * offset value of the download image. - * - * @param offset The value of the final offset of the image download. Ver.: - * always - */ -void emberAfOtaStorageDriverDownloadFinishCallback(uint32_t offset) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); -} - -/** @brief Ota Storage Driver Init - * - * The initialization code for the OTA storage driver. - * - */ -bool emberAfOtaStorageDriverInitCallback(void) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); - return false; -} - -/** @brief Ota Storage Driver Invalidate Image - * - * This callback invalidates the image stored on disk so that it will not be - * bootloaded, and it will not be a valid image that is in the middle of - * downloading. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageDriverInvalidateImageCallback(void) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Driver Prepare To Resume Download - * - * This callback allows the underlying storage driver to prepare to resume the - * OTA file download. For example, the driver may exceute a page erase to - * insure the next page is ready to be written to. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageDriverPrepareToResumeDownloadCallback(void) -{ - assert(false); - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Driver Read - * - * This callback defines the low-level means by which a device reads from the - * OTA storage device. - * - * @param offset The address offset from the start of the storage device where - * data is to be read. Ver.: always - * @param length The length of the data to be read from the storage device. - * Ver.: always - * @param returnData A pointer where the data read from the device should be - * written to. Ver.: always - */ -bool emberAfOtaStorageDriverReadCallback(uint32_t offset, uint32_t length, uint8_t * returnData) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); - return false; -} - -/** @brief Ota Storage Driver Retrieve Last Stored Offset - * - * This callback defines the low-level means by which a device retrieves the - * last persistently recorded download offset. This may be different than last - * actual download offset. - * - */ -uint32_t emberAfOtaStorageDriverRetrieveLastStoredOffsetCallback(void) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); - return 0; -} - -/** @brief Ota Storage Driver Write - * - * This callback defines the low-level means by which a device reads from the - * OTA storage device. - * - * @param dataToWrite A pointer to the data that will be written to the storage - * device. Ver.: always - * @param offset The address offset from the start of the storage device where - * data will be written. Ver.: always - * @param length The length of the data to be written to the storage device. - * Ver.: always - */ -bool emberAfOtaStorageDriverWriteCallback(const uint8_t * dataToWrite, uint32_t offset, uint32_t length) -{ - // The storage driver and the rest of the OTA bootload code will not function correctly unless it is implemnted. - // Please implement me. - assert(false); - return false; -} - -/** @brief Ota Storage Finish Download - * - * This function indicates to the storage module that the download has finished. - * - * @param offset The final offset of the downloaded file (i.e. the total size) - * Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageFinishDownloadCallback(uint32_t offset) -{ - return EMBER_AF_OTA_STORAGE_SUCCESS; -} - -/** @brief Ota Storage Get Count - * - * This callback returns the total number of ZigBee Over-the-air upgrade images - * stored in the storage module. - * - */ -uint8_t emberAfOtaStorageGetCountCallback(void) -{ - return 0; -} - -/** @brief Ota Storage Get Full Header - * - * This callback populates the EmberAfOtaHeader structure pointed to by the - * returnData with data about the OTA file stored in the storage module. - * - * @param id This is a pointer to the image id for the OTA file to retrieve - * information about. Ver.: always - * @param returnData This is a pointer to the location of the structure that - * will be populated with data. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageGetFullHeaderCallback(const EmberAfOtaImageId * id, EmberAfOtaHeader * returnData) -{ - // If the requested image cannot be found, then an error shouldb e returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Get Total Image Size - * - * This function returns the total size of the ZigBee Over-the-air file with the - * passed parameters. If no file is found with those parameters, 0 is returned. - * - * @param id A pointer to the image identifier for the OTA file to retrieve - * information for. Ver.: always - */ -uint32_t emberAfOtaStorageGetTotalImageSizeCallback(const EmberAfOtaImageId * id) -{ - // On failure this should return an image size of zero. - return 0; -} - -/** @brief Ota Storage Init - * - * This callback initializes the ZigBee Over-the-air storage module. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageInitCallback(void) -{ - return EMBER_AF_OTA_STORAGE_SUCCESS; -} - -/** @brief Ota Storage Iterator First - * - * This callback lets you walk through the list of all OTA files by jumping to - * the first file in the list maintained by the storage module. If there is no - * file then emberAfOtaInvalidImageId is returned. - * - */ -EmberAfOtaImageId emberAfOtaStorageIteratorFirstCallback(void) -{ - // It is expected that the storage module maintain its own internal iterator that the 'first' and 'next' functions will - // manipulate. - - // If there are no images at all, this function should return the invalid image id. - return emberAfInvalidImageId; -} - -/** @brief Ota Storage Iterator Next - * - * This callback lets you walk through the list of all OTA files by jumping to - * the next file in the list maintained by the storage module. If there is no - * next file then emberAfOtaInvalidImageId is returned. - * - */ -EmberAfOtaImageId emberAfOtaStorageIteratorNextCallback(void) -{ - // It is expected that the storage module maintain its own internal iterator that the 'first' and 'next' functions will - // manipulate. - - // If there are no more images, this function should return the invalid image id. - return emberAfInvalidImageId; -} - -/** @brief Ota Storage Read Image Data - * - * This callback reads data from the specified OTA file and returns that data to - * the caller. - * - * @param id This is a pointer to the image id for the OTA file to retrieve data - * from. Ver.: always - * @param offset This is the offset relative to the start of the image where the - * data should be read from. Ver.: always - * @param length This is the length of data that will be read. Ver.: always - * @param returnData This is a pointer to where the data read out of the file - * will be written to Ver.: always - * @param returnedLength This is a pointer to a variable where the actual length - * of data read will be written to. A short read may occur if the end of file - * was reached. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageReadImageDataCallback(const EmberAfOtaImageId * id, uint32_t offset, uint32_t length, - uint8_t * returnData, uint32_t * returnedLength) -{ - // If the requested image cannot be found, then an error should be returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - -/** @brief Ota Storage Search - * - * This callback searches through the list of all images for one that matches - * the passed parameters. On success an image identifier is returned with a - * matching image. On failure emberAfInvalidImageId is returned. - * - * @param manufacturerId The ZigBee assigned identifier of the manufacturer - * contained in the OTA image being searched for. Ver.: always - * @param imageTypeId The image type identifier contained in the OTA image being - * searched for. Ver.: always - * @param hardwareVersion This is a pointer to the hardware version that will be - * used in the search. If the pointer is NULL, hardware version will not be - * considered when searching for matching images. If it points to a value, the - * search will only consider images where that value falls between the minimum - * and maxmimum hardware version specified in the OTA file. If no hardware - * version is present in an OTA file but the other parameters match, the file - * will be considered a match Ver.: always - */ -EmberAfOtaImageId emberAfOtaStorageSearchCallback(uint16_t manufacturerId, uint16_t imageTypeId, const uint16_t * hardwareVersion) -{ - // If no image is found that matches the search criteria, this function should return the invalid image id. - return emberAfInvalidImageId; -} - -/** @brief Ota Storage Write Temp Data - * - * This function writes to the temporary data in the storage device at the - * specified offset. It is used when downloading a raw image over the air. - * - * @param offset The location within the download image file where to write the - * data. Ver.: always - * @param length The length of data to write. Ver.: always - * @param data A pointer to the temporary data that will be written to the - * storage device. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageWriteTempDataCallback(uint32_t offset, uint32_t length, const uint8_t * data) -{ - // If the image data cannot be stored, an error should be returned. - return EMBER_AF_OTA_STORAGE_ERROR; -} - /** @brief Outgoing Packet Filter * * ** REQUIRES INCLUDING THE PACKET-HANDOFF PLUGIN ** diff --git a/examples/temperature-measurement-app/esp32/main/gen/callback.h b/examples/temperature-measurement-app/esp32/main/gen/callback.h index 99002ce3c5c92e..a1e23147ec4858 100644 --- a/examples/temperature-measurement-app/esp32/main/gen/callback.h +++ b/examples/temperature-measurement-app/esp32/main/gen/callback.h @@ -799,384 +799,6 @@ void emberAfNetworkFoundCallback(EmberZigbeeNetwork * networkFound, uint8_t lqi, * @param status Ver.: always */ void emberAfNetworkKeyUpdateCompleteCallback(EmberStatus status); -/** @brief Ota Bootload - * - * The platform specific routine to bootload the device from a ZigBee - * over-the-air upgrade file. - * - * @param id A pointer to the structure that contains the information about what - * OTA image to bootload. Ver.: always - * @param ncpUpgradeTagId The tag ID of the upgrade data that will be used to - * bootload the device. Ver.: always - */ -uint8_t emberAfOtaBootloadCallback(const EmberAfOtaImageId * id, uint16_t ncpUpgradeTagId); -/** @brief Ota Client Bootload - * - * This callback is fired when the OTA Client recevies a command to bootload the - * newly downloaded OTA image. This callback will perform the platform specific - * to bootload their device. - * - * @param id This is the identifier relating to the image that has been - * downloaded and is ready for bootload. Ver.: always - */ -void emberAfOtaClientBootloadCallback(const EmberAfOtaImageId * id); -/** @brief Ota Client Custom Verify - * - * This callback is executed by the OTA client after the signature verification - * has successfully completed. It allows the device to do its own custom - * verification of the image (such as verifying that the EBL is intact). - * - * @param newVerification This indicates if a new verification should be - * started. Ver.: always - * @param id This is ID of the image to be verified. Ver.: always - */ -EmberAfImageVerifyStatus emberAfOtaClientCustomVerifyCallback(bool newVerification, const EmberAfOtaImageId * id); -/** @brief Ota Client Download Complete - * - * This callback indicates that the OTA client has completed the download of a - * file. If the file has been completely downloaded and cryptographic checks - * have been turned on, then those will be performed prior to this callback and - * that outcome included in the 'success' result. On failure, this callback is - * merely informative, and the return type is ignored. On succesful download, - * this callback allows the client to perform any additional verification of the - * downloaded image and return that result to the OTA server. - * - * @param success This indicates the success or failure of the download and - * cryptographic verification process (if applicable). Ver.: always - * @param id This is the image identifier information that corresponds to the - * download result. Ver.: always - */ -bool emberAfOtaClientDownloadCompleteCallback(EmberAfOtaDownloadResult success, const EmberAfOtaImageId * id); -/** @brief Ota Client Incoming Message Raw - * - * This callback is for processing incoming messages for the Over-the-air - * bootload cluster client. ZCL will not process the message and instead hand - * the raw over the air data to the callback for its own processing. - * - * @param message A pointer to the structure containing the message buffer and - * other information about it. Ver.: always - */ -bool emberAfOtaClientIncomingMessageRawCallback(EmberAfClusterCommand * message); -/** @brief Ota Client Start - * - * This callback should be called when the profile specific registration has - * completed successfully. It will start the client's state machine that will - * find the OTA server, query it for the next image, download the image, wait - * for the bootload message, and kick off the bootload. - * - */ -void emberAfOtaClientStartCallback(void); -/** @brief Ota Client Version Info - * - * This function is called by the OTA client when a new query will occur to the - * server asking what the next version of firmware is. The client can inform - * the cluster software as to what information to use in the query (and - * subsequent download). - * - * @param currentImageInfo This is the information to use in the next query by - * the client cluster code. It contains the manufacturer ID, image type ID, and - * the firmware version to be specified in the query message sent to the server. - * Ver.: always - * @param hardwareVersion This is a pointer to the hardware version to use in - * the query. If no hardware version should be used, then - * EMBER_AF_INVALID_HARDWARE_VERSION should be used. Ver.: always - */ -void emberAfOtaClientVersionInfoCallback(EmberAfOtaImageId * currentImageInfo, uint16_t * hardwareVersion); -/** @brief Ota Page Request Server Policy - * - * This callback is called by the OTA server page request code when it wants to - * determine if it is allowed for an OTA client to make a page request. It is - * only called if page request support has been enabled on the server. It - * should return EMBER_ZCL_STATUS_SUCCESS if it allows the page request, and - * EMBER_ZCL_STATUS_UNSUP_CLUSTER_COMMAND if it does not want to allow it. - * - */ -uint8_t emberAfOtaPageRequestServerPolicyCallback(void); -/** @brief Ota Server Block Size - * - * This function provides a way for the server to adjust the block size of its - * response to an Image block request by a client. - * - * @param clientNodeId The node Id of OTA client making an image block request. - * Ver.: always - */ -uint8_t emberAfOtaServerBlockSizeCallback(EmberNodeId clientNodeId); -/** @brief Ota Server Incoming Message Raw - * - * This callback is for processing incoming messages for the Over-the-air - * bootload cluster server. ZCL will not process the message and instead hand - * the raw over the air data to the callback for its own processing. - * - * @param message A pointer to the structure containing the message buffer and - * other information about it. Ver.: always - */ -bool emberAfOtaServerIncomingMessageRawCallback(EmberAfClusterCommand * message); -/** @brief Ota Server Query - * - * This callback is fired when the OTA server receives a query request by the - * client. The callback lets the server application indicate to the client what - * the 'next' version of software is for the device, or if there is not one - * available. - * - * @param currentImageId This is the current software image that the client - * hase. Ver.: always - * @param hardwareVersion If this value is non-NULL, it indicates the hardware - * version of the client device. If NULL, the client did not specify a hardware - * version. Ver.: always - * @param nextUpgradeImageId This is a pointer to a data structure containing - * the 'next' software version for the client to download. Ver.: always - */ -uint8_t emberAfOtaServerQueryCallback(const EmberAfOtaImageId * currentImageId, uint16_t * hardwareVersion, - EmberAfOtaImageId * nextUpgradeImageId); -/** @brief Ota Server Send Image Notify - * - * This callback is an indication to the OTA server that it should send out - * notification about an OTA file that is available for download. - * - * @param dest The destination of the image notify message. May be a broadcast - * address. Ver.: always - * @param endpoint The destination endpoint of the image notify message. May be - * a broadcast endpoint. Ver.: always - * @param payloadType The type of data the image notify message will contain. 0 - * = no data. 1 = Manufacturer ID. 2 = Manufacturer ID and the image type ID. - * 3 = Manufacturer ID, image type ID, and firmware version. Ver.: always - * @param queryJitter The percentage of nodes that should respond to this - * message, from 1-100. On receipt of this message, each recipient will - * randomly choose a percentage and only query the server if their percentage is - * below this value. Ver.: always - * @param id The image information that will be put in the message. The data - * within this struct that will be appended to the message is determined by the - * previous 'payloadType' argument. Ver.: always - */ -bool emberAfOtaServerSendImageNotifyCallback(EmberNodeId dest, uint8_t endpoint, uint8_t payloadType, uint8_t queryJitter, - const EmberAfOtaImageId * id); -/** @brief Ota Server Upgrade End Request - * - * This function is called when the OTA server receives a request an upgrade end - * request. If the request indicated a successful download by the client, the - * server must tell the client when and if to upgrade to the downloaded image. - * - * @param source The node ID of the device that sent the upgrade end request. - * Ver.: always - * @param status This is the ZCL status sent by the client indicating the result - * of its attempt to download the new upgrade image. If the status is not - * EMBER_ZCL_STATUS_SUCCESS then this callback is merely informative and no - * response mesasge will be generated by the server. Ver.: always - * @param returnValue If the server returns true indicating that the client - * should apply the upgrade, this time value indicates when in the future the - * client should apply the upgrade. Ver.: always - * @param imageId This variable indicates the software version that the client - * successfully downloaded and is asking to upgrade to. Ver.: always - */ -bool emberAfOtaServerUpgradeEndRequestCallback(EmberNodeId source, uint8_t status, uint32_t * returnValue, - const EmberAfOtaImageId * imageId); -/** @brief Ota Storage Check Temp Data - * - * This callback will validate temporary data in the storage device to determine - * whether it is a complete file, a partially downloaded file, or there is no - * file present. When a complete or partial file is found it will return - * EMBER_AF_OTA_STORAGE_SUCCESS or EMBER_AF_OTA_STORAGE_PARTIAL_FILE_FOUND, - * respectively. In that case, the currentOffset, totalImageSize, and - * newFileInfo will be populated with data. When EMBER_AF_OTA_STORAGE_ERROR is - * returned, no temporary data is present. - * - * @param currentOffset A pointer to a value that will be written with the - * offset within the total file size that has been successfully stored in the - * storage device. This will indicate how much data has been currently - * dowloaded. Ver.: always - * @param totalImageSize A pointer to a value that will be written with the - * total image size of the OTA file when a download has completed. This does - * not indicate how much data has actually been downloaded currently. Ver.: - * always - * @param newFileInfo This is the image id of the temporary file data stored in - * the storage device. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageCheckTempDataCallback(uint32_t * currentOffset, uint32_t * totalImageSize, - EmberAfOtaImageId * newFileInfo); -/** @brief Ota Storage Clear Temp Data - * - * This function clears any existing temp data that was downloaed. It is used - * immediately prior to downloading a raw image over the air. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageClearTempDataCallback(void); -/** @brief Ota Storage Close - * - * This callback shuts down the ZigBee Over-the-air storage module. - * - */ -void emberAfOtaStorageCloseCallback(void); -/** @brief Ota Storage Driver Download Finish - * - * This callback defines the low-level means by which a device records the final - * offset value of the download image. - * - * @param offset The value of the final offset of the image download. Ver.: - * always - */ -void emberAfOtaStorageDriverDownloadFinishCallback(uint32_t offset); -/** @brief Ota Storage Driver Init - * - * The initialization code for the OTA storage driver. - * - */ -bool emberAfOtaStorageDriverInitCallback(void); -/** @brief Ota Storage Driver Invalidate Image - * - * This callback invalidates the image stored on disk so that it will not be - * bootloaded, and it will not be a valid image that is in the middle of - * downloading. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageDriverInvalidateImageCallback(void); -/** @brief Ota Storage Driver Prepare To Resume Download - * - * This callback allows the underlying storage driver to prepare to resume the - * OTA file download. For example, the driver may exceute a page erase to - * insure the next page is ready to be written to. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageDriverPrepareToResumeDownloadCallback(void); -/** @brief Ota Storage Driver Read - * - * This callback defines the low-level means by which a device reads from the - * OTA storage device. - * - * @param offset The address offset from the start of the storage device where - * data is to be read. Ver.: always - * @param length The length of the data to be read from the storage device. - * Ver.: always - * @param returnData A pointer where the data read from the device should be - * written to. Ver.: always - */ -bool emberAfOtaStorageDriverReadCallback(uint32_t offset, uint32_t length, uint8_t * returnData); -/** @brief Ota Storage Driver Retrieve Last Stored Offset - * - * This callback defines the low-level means by which a device retrieves the - * last persistently recorded download offset. This may be different than last - * actual download offset. - * - */ -uint32_t emberAfOtaStorageDriverRetrieveLastStoredOffsetCallback(void); -/** @brief Ota Storage Driver Write - * - * This callback defines the low-level means by which a device reads from the - * OTA storage device. - * - * @param dataToWrite A pointer to the data that will be written to the storage - * device. Ver.: always - * @param offset The address offset from the start of the storage device where - * data will be written. Ver.: always - * @param length The length of the data to be written to the storage device. - * Ver.: always - */ -bool emberAfOtaStorageDriverWriteCallback(const uint8_t * dataToWrite, uint32_t offset, uint32_t length); -/** @brief Ota Storage Finish Download - * - * This function indicates to the storage module that the download has finished. - * - * @param offset The final offset of the downloaded file (i.e. the total size) - * Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageFinishDownloadCallback(uint32_t offset); -/** @brief Ota Storage Get Count - * - * This callback returns the total number of ZigBee Over-the-air upgrade images - * stored in the storage module. - * - */ -uint8_t emberAfOtaStorageGetCountCallback(void); -/** @brief Ota Storage Get Full Header - * - * This callback populates the EmberAfOtaHeader structure pointed to by the - * returnData with data about the OTA file stored in the storage module. - * - * @param id This is a pointer to the image id for the OTA file to retrieve - * information about. Ver.: always - * @param returnData This is a pointer to the location of the structure that - * will be populated with data. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageGetFullHeaderCallback(const EmberAfOtaImageId * id, EmberAfOtaHeader * returnData); -/** @brief Ota Storage Get Total Image Size - * - * This function returns the total size of the ZigBee Over-the-air file with the - * passed parameters. If no file is found with those parameters, 0 is returned. - * - * @param id A pointer to the image identifier for the OTA file to retrieve - * information for. Ver.: always - */ -uint32_t emberAfOtaStorageGetTotalImageSizeCallback(const EmberAfOtaImageId * id); -/** @brief Ota Storage Init - * - * This callback initializes the ZigBee Over-the-air storage module. - * - */ -EmberAfOtaStorageStatus emberAfOtaStorageInitCallback(void); -/** @brief Ota Storage Iterator First - * - * This callback lets you walk through the list of all OTA files by jumping to - * the first file in the list maintained by the storage module. If there is no - * file then emberAfOtaInvalidImageId is returned. - * - */ -EmberAfOtaImageId emberAfOtaStorageIteratorFirstCallback(void); -/** @brief Ota Storage Iterator Next - * - * This callback lets you walk through the list of all OTA files by jumping to - * the next file in the list maintained by the storage module. If there is no - * next file then emberAfOtaInvalidImageId is returned. - * - */ -EmberAfOtaImageId emberAfOtaStorageIteratorNextCallback(void); -/** @brief Ota Storage Read Image Data - * - * This callback reads data from the specified OTA file and returns that data to - * the caller. - * - * @param id This is a pointer to the image id for the OTA file to retrieve data - * from. Ver.: always - * @param offset This is the offset relative to the start of the image where the - * data should be read from. Ver.: always - * @param length This is the length of data that will be read. Ver.: always - * @param returnData This is a pointer to where the data read out of the file - * will be written to Ver.: always - * @param returnedLength This is a pointer to a variable where the actual length - * of data read will be written to. A short read may occur if the end of file - * was reached. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageReadImageDataCallback(const EmberAfOtaImageId * id, uint32_t offset, uint32_t length, - uint8_t * returnData, uint32_t * returnedLength); -/** @brief Ota Storage Search - * - * This callback searches through the list of all images for one that matches - * the passed parameters. On success an image identifier is returned with a - * matching image. On failure emberAfInvalidImageId is returned. - * - * @param manufacturerId The ZigBee assigned identifier of the manufacturer - * contained in the OTA image being searched for. Ver.: always - * @param imageTypeId The image type identifier contained in the OTA image being - * searched for. Ver.: always - * @param hardwareVersion This is a pointer to the hardware version that will be - * used in the search. If the pointer is NULL, hardware version will not be - * considered when searching for matching images. If it points to a value, the - * search will only consider images where that value falls between the minimum - * and maxmimum hardware version specified in the OTA file. If no hardware - * version is present in an OTA file but the other parameters match, the file - * will be considered a match Ver.: always - */ -EmberAfOtaImageId emberAfOtaStorageSearchCallback(uint16_t manufacturerId, uint16_t imageTypeId, const uint16_t * hardwareVersion); -/** @brief Ota Storage Write Temp Data - * - * This function writes to the temporary data in the storage device at the - * specified offset. It is used when downloading a raw image over the air. - * - * @param offset The location within the download image file where to write the - * data. Ver.: always - * @param length The length of data to write. Ver.: always - * @param data A pointer to the temporary data that will be written to the - * storage device. Ver.: always - */ -EmberAfOtaStorageStatus emberAfOtaStorageWriteTempDataCallback(uint32_t offset, uint32_t length, const uint8_t * data); /** @brief Outgoing Packet Filter * * ** REQUIRES INCLUDING THE PACKET-HANDOFF PLUGIN ** diff --git a/src/app/clusters/door-lock-server/door-lock-server-logging.cpp b/src/app/clusters/door-lock-server/door-lock-server-logging.cpp index 464783590dd01e..4f28768532f53a 100644 --- a/src/app/clusters/door-lock-server/door-lock-server-logging.cpp +++ b/src/app/clusters/door-lock-server/door-lock-server-logging.cpp @@ -49,7 +49,7 @@ using namespace chip; static EmberAfPluginDoorLockServerLogEntry entries[EMBER_AF_PLUGIN_DOOR_LOCK_SERVER_MAX_LOG_ENTRIES]; static uint8_t nextEntryId = 1; -#define ENTRY_ID_TO_INDEX(entryId) ((entryId) -1) +#define ENTRY_ID_TO_INDEX(entryId) static_cast((entryId) -1) #define ENTRY_ID_IS_VALID(entryId) ((entryId) > 0 && (entryId) < nextEntryId) #define MOST_RECENT_ENTRY_ID() (nextEntryId - 1) #define LOG_IS_EMPTY() (nextEntryId == 1) diff --git a/src/app/clusters/scenes/scenes.cpp b/src/app/clusters/scenes/scenes.cpp index 0c28915f5dce4a..556b3b903017d8 100644 --- a/src/app/clusters/scenes/scenes.cpp +++ b/src/app/clusters/scenes/scenes.cpp @@ -646,38 +646,6 @@ EmberAfStatus emberAfScenesClusterRecallSavedSceneCallback(EndpointId endpoint, return EMBER_ZCL_STATUS_NOT_FOUND; } -void emberAfScenesClusterClearSceneTableCallback(EndpointId endpoint) -{ - uint8_t i, networkIndex = 0 /* emberGetCurrentNetwork() */; - for (i = 0; i < EMBER_AF_PLUGIN_SCENES_TABLE_SIZE; i++) - { - EmberAfSceneTableEntry entry; - emberAfPluginScenesServerRetrieveSceneEntry(entry, i); - if (entry.endpoint != EMBER_AF_SCENE_TABLE_UNUSED_ENDPOINT_ID && - (endpoint == entry.endpoint || - (endpoint == EMBER_BROADCAST_ENDPOINT && (networkIndex == emberAfNetworkIndexFromEndpoint(entry.endpoint))))) - { - entry.endpoint = EMBER_AF_SCENE_TABLE_UNUSED_ENDPOINT_ID; - emberAfPluginScenesServerSaveSceneEntry(entry, i); - } - } - emberAfPluginScenesServerSetNumSceneEntriesInUse(0); - if (endpoint == EMBER_BROADCAST_ENDPOINT) - { - for (i = 0; i < emberAfEndpointCount(); i++) - { - if (emberAfNetworkIndexFromEndpointIndex(i) == networkIndex) - { - emberAfScenesSetSceneCountAttribute(emberAfEndpointFromIndex(i), 0); - } - } - } - else - { - emberAfScenesSetSceneCountAttribute(endpoint, 0); - } -} - bool emberAfPluginScenesServerParseAddScene(const EmberAfClusterCommand * cmd, GroupId groupId, uint8_t sceneId, uint16_t transitionTime, uint8_t * sceneName, uint8_t * extensionFieldSets) { diff --git a/src/app/util/af-types.h b/src/app/util/af-types.h index 3a396dd4e9ec94..ceec45081521df 100644 --- a/src/app/util/af-types.h +++ b/src/app/util/af-types.h @@ -1179,152 +1179,6 @@ typedef struct } EmberAfPluginZllCommissioningEndpointInformationRecord; #endif -/** - * @brief This is a unique identifier for referencing zigbee Over-the-air upgrade - * images. It is used by the OTA plugins when passing around information about - * an upgrade file. - */ -typedef struct -{ - uint16_t manufacturerId; - uint16_t imageTypeId; - uint32_t firmwareVersion; - - /** - * This is only used for device specific files. - * It will be set to all 0's when the image does not - * have an upgrade destination field in it. - * Little endian format. - */ - uint8_t deviceSpecificFileEui64[EUI64_SIZE]; -} EmberAfOtaImageId; - -/** - * @brief The list of options possible for the image block request/response. - */ -enum -{ - EMBER_AF_IMAGE_BLOCK_REQUEST_OPTIONS_NONE = 0x00, - // Client supports Min Block Request field - EMBER_AF_IMAGE_BLOCK_REQUEST_MIN_BLOCK_REQUEST_SUPPORTED_BY_CLIENT = 0x01, - // Server supports Min Block Request field - EMBER_AF_IMAGE_BLOCK_REQUEST_MIN_BLOCK_REQUEST_SUPPORTED_BY_SERVER = 0x02, - // The Image Block Request is actually simulated in place of an actually - // received Image Page Request - EMBER_AF_IMAGE_BLOCK_REQUEST_SIMULATED_FROM_PAGE_REQUEST = 0x04 -}; -typedef uint8_t EmberAfImageBlockRequestOptions; - -/** - * @brief This is the data structure that is passed to the - * emberAfImageBlockRequestCallback() to let the application decide what to do. - */ -typedef struct -{ - const EmberAfOtaImageId * id; - uint32_t offset; - uint32_t waitTimeSecondsResponse; - EmberNodeId source; - EmberEUI64 sourceEui; // optionally present in messages - // The minBlockRequestPeriod can be treated as milliseconds or seconds on the - // client. The OTA server plugin has optional support to probe clients and - // treat this field with appropriate units (ms or sec) - uint16_t minBlockRequestPeriod; // optionally present in messages - uint8_t maxDataSize; - CHIPEndpointId clientEndpoint; - EmberAfImageBlockRequestOptions bitmask; -} EmberAfImageBlockRequestCallbackStruct; - -/** - * @brief This status contains the success or error code of an OTA storage - * device operation. - */ -typedef enum -{ - EMBER_AF_OTA_STORAGE_SUCCESS = 0, - EMBER_AF_OTA_STORAGE_ERROR = 1, - EMBER_AF_OTA_STORAGE_RETURN_DATA_TOO_LONG = 2, - EMBER_AF_OTA_STORAGE_PARTIAL_FILE_FOUND = 3, - EMBER_AF_OTA_STORAGE_OPERATION_IN_PROGRESS = 4, -} EmberAfOtaStorageStatus; - -/** - * @brief This status contains the success or error code of an OTA download - * operation. - */ -enum -{ - EMBER_AF_OTA_DOWNLOAD_AND_VERIFY_SUCCESS = 0, - EMBER_AF_OTA_DOWNLOAD_TIME_OUT = 1, - EMBER_AF_OTA_VERIFY_FAILED = 2, - EMBER_AF_OTA_SERVER_ABORTED = 3, - EMBER_AF_OTA_CLIENT_ABORTED = 4, - EMBER_AF_OTA_ERASE_FAILED = 5, -}; -typedef uint8_t EmberAfOtaDownloadResult; - -/** - * @brief The maximum size of the string that is present in the header - * of the zigbee Over-the-air file format. - */ -#define EMBER_AF_OTA_MAX_HEADER_STRING_LENGTH 32 - -#define UID_SIZE 32 -/** - * @brief This structure is an in-memory representation of - * the Over-the-air header data that resides on disk. - * It is not a byte-for-byte copy. - */ -typedef struct -{ - // Magic Number omitted since it is always the same. - uint16_t headerVersion; - uint16_t headerLength; - uint16_t fieldControl; - uint16_t manufacturerId; - uint16_t imageTypeId; // a.k.a. Device ID - uint32_t firmwareVersion; - uint16_t zigbeeStackVersion; - - /** - * @brief The spec. does NOT require that the string be NULL terminated in the - * header stored on disk. Therefore we make sure we can support a - * 32-character string without a NULL terminator by adding +1 in the data - * structure. - */ - uint8_t headerString[EMBER_AF_OTA_MAX_HEADER_STRING_LENGTH + 1]; - - /** - * @brief When reading the header this will be the complete length of - * the file. When writing the header, this must be set to - * the length of the MFG image data portion including all tags. - */ - uint32_t imageSize; - - /** - * @brief The remaining four fields are optional. The field control should be checked - * to determine if their values are valid. - */ - uint8_t securityCredentials; - union - { - uint8_t EUI64[EUI64_SIZE]; - uint8_t UID[UID_SIZE]; - } upgradeFileDestination; - uint16_t minimumHardwareVersion; - uint16_t maximumHardwareVersion; -} EmberAfOtaHeader; - -/** - * @brief This structure contains information about a tag that resides - * within an Over-the-air bootload file. - */ -typedef struct -{ - uint16_t id; - uint32_t length; -} EmberAfTagData; - typedef enum { NO_APP_MESSAGE = 0, @@ -1389,26 +1243,6 @@ typedef enum "Bad cert issuer", "Key confirm failure", "Bad key est. suite", "Key table full", "Not allowed", "Invalid Key Usage", \ } -/** - * @brief This enumeration is used to indicate the state of an OTA bootload - * image undergoing verification. This is used both for cryptographic - * verification and manufacturer specific verification. - */ -typedef enum -{ - EMBER_AF_IMAGE_GOOD = 0, - EMBER_AF_IMAGE_BAD = 1, - EMBER_AF_IMAGE_VERIFY_IN_PROGRESS = 2, - -#ifndef DOXYGEN_SHOULD_SKIP_THIS - // Internal use only. - EMBER_AF_IMAGE_VERIFY_WAIT = 3, - EMBER_AF_IMAGE_VERIFY_ERROR = 4, - EMBER_AF_IMAGE_UNKNOWN = 5, - EMBER_AF_NO_IMAGE_VERIFY_SUPPORT = 6, -#endif -} EmberAfImageVerifyStatus; - /** * @brief Type for referring to the tick callback for cluster. * diff --git a/src/app/util/af.h b/src/app/util/af.h index 201afbf3d31a54..815808c9e862b4 100644 --- a/src/app/util/af.h +++ b/src/app/util/af.h @@ -502,11 +502,6 @@ uint8_t emberAfFindClusterServerEndpointIndex(CHIPEndpointId endpoint, EmberAfCl */ #define emberAfNetworkIndexFromEndpointIndex(index) (emAfEndpoints[(index)].networkIndex) -/** - * @brief Returns the network index of a given endpoint. - */ -uint8_t emberAfNetworkIndexFromEndpoint(CHIPEndpointId endpoint); - /** * @brief Macro that returns primary profile ID. * @@ -681,25 +676,6 @@ bool emberAfEndpointEnableDisable(CHIPEndpointId endpoint, bool enable); */ bool emberAfEndpointIndexIsEnabled(uint8_t index); -/** - * @brief This indicates a new image verification is taking place. - */ -#define EMBER_AF_NEW_IMAGE_VERIFICATION true - -/** - * @brief This indicates the continuation of an image verification already - * in progress. - */ -#define EMBER_AF_CONTINUE_IMAGE_VERIFY false - -/** - * @brief This variable defines an invalid image id. It is used - * to determine if a returned EmberAfOtaImageId is valid or not. - * This is done by passing the data to the function - * emberAfIsOtaImageIdValid(). - */ -extern const EmberAfOtaImageId emberAfInvalidImageId; - /** * @brief Returns true if a given ZCL data type is a string type. * diff --git a/src/app/util/attribute-storage.cpp b/src/app/util/attribute-storage.cpp index a4f293a55f5b13..ce6b863cfd6ca7 100644 --- a/src/app/util/attribute-storage.cpp +++ b/src/app/util/attribute-storage.cpp @@ -774,10 +774,10 @@ static uint8_t findClusterEndpointIndex(EndpointId endpoint, EmberAfClusterId cl break; } epi = static_cast(epi + - (emberAfFindClusterIncludingDisabledEndpointsWithMfgCode( - emAfEndpoints[i].endpoint, clusterId, mask, manufacturerCode) != NULL) - ? 1 - : 0); + ((emberAfFindClusterIncludingDisabledEndpointsWithMfgCode(emAfEndpoints[i].endpoint, clusterId, + mask, manufacturerCode) != NULL) + ? 1 + : 0)); } return epi; From 7e4986cc73bf1b2e2da3d9d7944b82880f41b2d2 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas Date: Fri, 6 Nov 2020 23:51:24 +0100 Subject: [PATCH 015/234] Use the exit value of chip-tool in test-on-off-cluster.py instead of checking the output string (#3692) --- .../linux-cirque/test-on-off-cluster.py | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/test_driver/linux-cirque/test-on-off-cluster.py b/src/test_driver/linux-cirque/test-on-off-cluster.py index 21f6e4f0b46694..341c1be6fc1594 100644 --- a/src/test_driver/linux-cirque/test-on-off-cluster.py +++ b/src/test_driver/linux-cirque/test-on-off-cluster.py @@ -77,25 +77,19 @@ def run_data_model_test(self): for device_id in server_ids: server_ip_address.add(self.get_device_thread_ip(device_id)) + command = "chip-tool onoff {} {} {} 1" + for ip in server_ip_address: - output = self.execute_device_cmd( - tool_device_id, "chip-tool onoff on {} {} 1".format(ip, CHIP_PORT)) - self.logger.info( - 'checking output does not contain "No response from device"') - self.assertFalse(self.sequenceMatch( - output['output'], ["No response from device."])) + ret = self.execute_device_cmd(tool_device_id, command.format("on", ip, CHIP_PORT)) + self.assertEqual(ret['return_code'], '0', "{} command failure: {}".format("on", ret['output'])) + + ret = self.execute_device_cmd(tool_device_id, command.format("off", ip, CHIP_PORT)) + self.assertEqual(ret['return_code'], '0', "{} command failure: {}".format("off", ret['output'])) + time.sleep(1) - for ip in server_ip_address: - output = self.execute_device_cmd( - tool_device_id, "chip-tool onoff off {} {} 1".format(ip, CHIP_PORT)) - self.logger.info( - 'checking output does not contain "No response from device"') - self.assertFalse(self.sequenceMatch( - output['output'], ["No response from device."])) for device_id in server_ids: - self.logger.info("checking device log for {}".format( - self.get_device_pretty_id(device_id))) + self.logger.info("checking device log for {}".format(self.get_device_pretty_id(device_id))) self.assertTrue(self.sequenceMatch(self.get_device_log(device_id).decode('utf-8'), ["LightingManager::InitiateAction(ON_ACTION)", "LightingManager::InitiateAction(OFF_ACTION)"]), "Datamodel test failed: cannot find matching string from device {}".format(device_id)) From aa2eb3e2f777233af418bebbeb9fb8bdd772a49a Mon Sep 17 00:00:00 2001 From: Vivien Nicolas Date: Sat, 7 Nov 2020 04:17:27 +0100 Subject: [PATCH 016/234] Add JavaScript to .clang-format (#3708) --- .clang-format | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.clang-format b/.clang-format index e4165cefbb4f1d..208a93c021cecb 100644 --- a/.clang-format +++ b/.clang-format @@ -230,4 +230,7 @@ StatementMacros: - QT_REQUIRE_VERSION TabWidth: 8 UseTab: Never +--- +Language: JavaScript +ColumnLimit: 132 ... From 39cbaf70848c3efc02888bc7041fadd9769cdf1a Mon Sep 17 00:00:00 2001 From: Timothy Maes <63657433+tima-q@users.noreply.github.com> Date: Sat, 7 Nov 2020 04:22:53 +0100 Subject: [PATCH 017/234] Enable BLE advertising start/stop command in shell application (#3714) --- examples/shell/shell_common/cmd_btp.cpp | 26 ++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/examples/shell/shell_common/cmd_btp.cpp b/examples/shell/shell_common/cmd_btp.cpp index 99952b1e3ed696..46789cf53440c0 100644 --- a/examples/shell/shell_common/cmd_btp.cpp +++ b/examples/shell/shell_common/cmd_btp.cpp @@ -55,21 +55,37 @@ int cmd_btp_adv(int argc, char ** argv) { CHIP_ERROR error = CHIP_NO_ERROR; streamer_t * sout = streamer_get(); + bool adv_enabled; if (argc == 0) { ExitNow(error = CHIP_ERROR_INVALID_ARGUMENT); } + adv_enabled = ConnectivityMgr().IsBLEAdvertisingEnabled(); if (strcmp(argv[0], "start") == 0) { - streamer_printf(sout, "Starting BLE advertising"); - // TODO: start advertising + if (adv_enabled) + { + streamer_printf(sout, "BLE advertising already enabled"); + } + else + { + streamer_printf(sout, "Starting BLE advertising"); + ConnectivityMgr().SetBLEAdvertisingEnabled(true); + } } else if (strcmp(argv[0], "stop") == 0) { - streamer_printf(sout, "Stopping BLE advertising"); - // TODO: stop advertising + if (adv_enabled) + { + streamer_printf(sout, "Stopping BLE advertising"); + ConnectivityMgr().SetBLEAdvertisingEnabled(false); + } + else + { + streamer_printf(sout, "BLE advertising already stopped"); + } } else { @@ -162,7 +178,7 @@ static const shell_command_t cmds_btp[] = { { &cmd_btp_help, "help", "Usage: btp " }, { &cmd_btp_scan, "scan", "Enable or disable scan. Usage: btp scan " }, { &cmd_btp_connect, "connect", "Connect or disconnect to a device. Usage: btp connect " }, - { &cmd_btp_adv, "adv", "Enable or disable advertisement. Usage: device dump" }, + { &cmd_btp_adv, "adv", "Enable or disable advertisement. Usage: btp adv " }, { &cmd_btp_send, "send", "Send binary data. Usage: device dump" }, }; From 7d522cdba8478ff3b078456872e02276cbc57782 Mon Sep 17 00:00:00 2001 From: Michael Spang Date: Fri, 6 Nov 2020 22:23:43 -0500 Subject: [PATCH 018/234] Update IntelliSense modes to correct architecture (#3713) VS Code is saying IntelliSense mode doesn't match what it probes. Update the IntelliSense modes to use the right compiler & architecture. I have no idea what this actually affects. --- .vscode/c_cpp_properties.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index e99e7d2e9dc4cd..ac95958b5edf39 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -40,7 +40,7 @@ "name": "Android x64 debug (GN)", "cStandard": "c11", "cppStandard": "c++11", - "intelliSenseMode": "gcc-x64", + "intelliSenseMode": "clang-x64", "compileCommands": "${workspaceFolder}/out/debug/compile_commands.android_x64.json", "compilerPath": "/opt/android/android-ndk-r21b/toolchains/llvm/prebuilt/linux-x86_64/bin/x86_64-linux-android24-clang", "browse": { @@ -52,7 +52,7 @@ "name": "Android arm64 debug (GN)", "cStandard": "c11", "cppStandard": "c++11", - "intelliSenseMode": "gcc-x64", + "intelliSenseMode": "clang-arm64", "compileCommands": "${workspaceFolder}/out/debug/compile_commands.android_arm64.json", "compilerPath": "/opt/android/android-ndk-r21b/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android24-clang", "browse": { @@ -64,7 +64,7 @@ "name": "EFR32 examples debug (GN)", "cStandard": "c11", "cppStandard": "c++11", - "intelliSenseMode": "gcc-x64", + "intelliSenseMode": "gcc-arm", "compileCommands": "${workspaceFolder}/out/debug/compile_commands.efr32.json", "compilerPath": "/opt/ARM-software/gcc-arm-none-eabi-9-2019-q4-major/bin/arm-none-eabi-gcc", "browse": { From c58b3057cdf0345fb5197019ff1b291fe24bdac7 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas Date: Sat, 7 Nov 2020 04:24:37 +0100 Subject: [PATCH 019/234] CodeQL: Comparison result is always the same in src/inet/tests/TestInetLayer.cpp and src/inet/tests/TestInetLayerMulticast.cpp (#3712) --- src/inet/tests/TestInetLayer.cpp | 2 +- src/inet/tests/TestInetLayerMulticast.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/inet/tests/TestInetLayer.cpp b/src/inet/tests/TestInetLayer.cpp index 81f6c653e52a7d..92ebd13bf47c0c 100644 --- a/src/inet/tests/TestInetLayer.cpp +++ b/src/inet/tests/TestInetLayer.cpp @@ -322,7 +322,7 @@ static bool HandleOption(const char * aProgram, OptionSet * aOptions, int aIdent { case kToolOptInterval: - if (!ParseInt(aValue, gSendIntervalMs) || gSendIntervalMs > UINT32_MAX) + if (!ParseInt(aValue, gSendIntervalMs)) { PrintArgError("%s: invalid value specified for send interval: %s\n", aProgram, aValue); retval = false; diff --git a/src/inet/tests/TestInetLayerMulticast.cpp b/src/inet/tests/TestInetLayerMulticast.cpp index 24eff1af75fe81..7dd76b8ea05d24 100644 --- a/src/inet/tests/TestInetLayerMulticast.cpp +++ b/src/inet/tests/TestInetLayerMulticast.cpp @@ -353,7 +353,7 @@ static bool HandleOption(const char * aProgram, OptionSet * aOptions, int aIdent { case kToolOptInterval: - if (!ParseInt(aValue, gSendIntervalMs) || gSendIntervalMs > UINT32_MAX) + if (!ParseInt(aValue, gSendIntervalMs)) { PrintArgError("%s: invalid value specified for send interval: %s\n", aProgram, aValue); retval = false; From 2d17edb5a8afc3cb7601a180dbd3e27bd2d09c37 Mon Sep 17 00:00:00 2001 From: Kevin Schoedel <67607049+kpschoedel@users.noreply.github.com> Date: Sat, 7 Nov 2020 00:04:01 -0500 Subject: [PATCH 020/234] Enable -Wstack-usage on device builds (#3683) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Enable -Wstack-usage on device builds #### Problem RAM on small devices is limited, so excesssive stack should not be used without good reason. Stack allocation is also not easily checked at run time so overflow is likely to cause crashes. #### Summary of Changes - Add a `-Wstack-usage` compiler flag on embedded builds. (For this purpose, an ‘embedded build’ is any that is not using a whitelisted non-embedded OS, so new platforms will have this enabled by default.) In this PR, the stack limit is set high enough that _only_ dynamically unbounded stack usage triggers it. The intent is to lower the limit in the future so that any unusually large stack requires whitelisting with justification in review. - Replace most uses of dynamically unbounded stack. - Filed separate issues for two remaining uses of dynamic stack: - #3662 emberAfPrintBuffer() - #3663 payloadBase41RepresentationWithTLV() fixes #3505 Use "-Wstack-usage" for device builds * Fix dynamic-sized stack array in CHIPDeviceController.cpp * Additional dynamic-stack-size fixes. * Revert ManualSetupPayloadGenerator.cpp --- build/config/compiler/BUILD.gn | 5 + .../chip-tool/commands/common/EchoCommand.cpp | 12 +- src/app/util/ember-print.cpp | 6 + src/controller/CHIPDeviceController.cpp | 7 +- src/crypto/tests/CHIPCryptoPALTest.cpp | 200 ++++++++++++------ src/inet/tests/TestInetCommon.cpp | 11 +- .../tests/TestSerializableIntegerSet.cpp | 11 +- .../ManualSetupPayloadGenerator.cpp | 6 + .../QRCodeSetupPayloadGenerator.cpp | 6 + src/transport/SecureSession.cpp | 3 +- 10 files changed, 187 insertions(+), 80 deletions(-) mode change 100755 => 100644 src/crypto/tests/CHIPCryptoPALTest.cpp diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn index f55fd280263b8c..c7a225e51c2cc8 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn @@ -186,6 +186,11 @@ config("warnings_default") { if (current_os != "mac" && current_os != "ios") { ldflags = [ "-Wl,--fatal-warnings" ] } + + if (current_os != "mac" && current_os != "ios" && current_os != "linux" && + current_os != "win") { + cflags = [ "-Wstack-usage=8192" ] + } } config("symbols_default") { diff --git a/examples/chip-tool/commands/common/EchoCommand.cpp b/examples/chip-tool/commands/common/EchoCommand.cpp index 10de3016edb082..064697be89385a 100644 --- a/examples/chip-tool/commands/common/EchoCommand.cpp +++ b/examples/chip-tool/commands/common/EchoCommand.cpp @@ -22,7 +22,7 @@ using namespace ::chip; using namespace ::chip::DeviceController; #define SEND_DELAY 5 -static const char * PAYLOAD = "Message from Standalone CHIP echo client!"; +static const char PAYLOAD[] = "Message from Standalone CHIP echo client!"; void EchoCommand::SendEcho() const { @@ -59,19 +59,15 @@ void EchoCommand::SendEcho() const void EchoCommand::ReceiveEcho(PacketBuffer * buffer) const { // attempt to print the incoming message - size_t data_len = buffer->DataLength(); - char msg_buffer[data_len]; - msg_buffer[data_len] = 0; // Null-terminate whatever we received and treat like a string... - memcpy(msg_buffer, buffer->Start(), data_len); - - bool isEchoIdenticalToMessage = strncmp(msg_buffer, PAYLOAD, data_len) == 0; + size_t data_len = buffer->DataLength(); + bool isEchoIdenticalToMessage = (data_len + 1 == sizeof PAYLOAD) && (memcmp(buffer->Start(), PAYLOAD, data_len) == 0); if (isEchoIdenticalToMessage) { ChipLogProgress(chipTool, "Echo (%s): Received expected message !", GetNetworkName()); } else { - ChipLogError(chipTool, "Echo: (%s): Error \nSend: %s \nRecv: %s", GetNetworkName(), PAYLOAD, msg_buffer); + ChipLogError(chipTool, "Echo: (%s): Error \nSend: %s \nRecv: %.*s", GetNetworkName(), PAYLOAD, data_len, buffer->Start()); } } diff --git a/src/app/util/ember-print.cpp b/src/app/util/ember-print.cpp index 9a2d2e1524977d..9cec38ab7cf80f 100644 --- a/src/app/util/ember-print.cpp +++ b/src/app/util/ember-print.cpp @@ -50,6 +50,10 @@ void emberAfPrintln(int category, const char * format, ...) } } +// TODO: issue #3662 - Unbounded stack in emberAfPrintBuffer() +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstack-usage=" + void emberAfPrintBuffer(int category, const uint8_t * buffer, uint16_t length, bool withSpace) { if (buffer != NULL && length > 0) @@ -73,6 +77,8 @@ void emberAfPrintBuffer(int category, const uint8_t * buffer, uint16_t length, b } } +#pragma GCC diagnostic pop // -Wstack-usage + void emberAfPrintString(int category, const uint8_t * string) { emberAfPrint(category, "%s", string); diff --git a/src/controller/CHIPDeviceController.cpp b/src/controller/CHIPDeviceController.cpp index ccb1e8ce14416d..45fb3192cde203 100644 --- a/src/controller/CHIPDeviceController.cpp +++ b/src/controller/CHIPDeviceController.cpp @@ -63,15 +63,16 @@ namespace DeviceController { using namespace chip::Encoding; -constexpr const char * kDeviceCredentialsKeyPrefix = "DeviceCredentials"; -constexpr const char * kDeviceAddressKeyPrefix = "DeviceAddress"; +constexpr const char kDeviceCredentialsKeyPrefix[] = "DeviceCredentials"; +constexpr const char kDeviceAddressKeyPrefix[] = "DeviceAddress"; // This macro generates a key using node ID an key prefix, and performs the given action // on that key. #define PERSISTENT_KEY_OP(node, keyPrefix, key, action) \ do \ { \ - const size_t len = strlen(keyPrefix); \ + constexpr size_t len = std::extent::value; \ + nlSTATIC_ASSERT_PRINT(len > 0, "keyPrefix length must be known at compile time"); \ /* 2 * sizeof(NodeId) to accomodate 2 character for each byte in Node Id */ \ char key[len + 2 * sizeof(NodeId) + 1]; \ nlSTATIC_ASSERT_PRINT(sizeof(node) <= sizeof(uint64_t), "Node ID size is greater than expected"); \ diff --git a/src/crypto/tests/CHIPCryptoPALTest.cpp b/src/crypto/tests/CHIPCryptoPALTest.cpp old mode 100755 new mode 100644 index 745798b03f510e..58338ae9d3fe34 --- a/src/crypto/tests/CHIPCryptoPALTest.cpp +++ b/src/crypto/tests/CHIPCryptoPALTest.cpp @@ -35,15 +35,17 @@ #include +#include #include #include +#include #include #include +#include +#include #include #include -#include -#include using namespace chip; using namespace chip::Crypto; @@ -66,13 +68,17 @@ static void TestAES_CCM_256EncryptTestVectors(nlTestSuite * inSuite, void * inCo if (vector->key_len == 32 && vector->pt_len > 0) { numOfTestsRan++; - uint8_t out_ct[vector->ct_len]; - uint8_t out_tag[vector->tag_len]; + chip::Platform::ScopedMemoryBuffer out_ct; + out_ct.Alloc(vector->ct_len); + NL_TEST_ASSERT(inSuite, out_ct); + chip::Platform::ScopedMemoryBuffer out_tag; + out_tag.Alloc(vector->tag_len); + NL_TEST_ASSERT(inSuite, out_tag); CHIP_ERROR err = AES_CCM_encrypt(vector->pt, vector->pt_len, vector->aad, vector->aad_len, vector->key, vector->key_len, - vector->iv, vector->iv_len, out_ct, out_tag, vector->tag_len); - bool areCTsEqual = memcmp(out_ct, vector->ct, vector->ct_len) == 0; - bool areTagsEqual = memcmp(out_tag, vector->tag, vector->tag_len) == 0; + vector->iv, vector->iv_len, out_ct.Get(), out_tag.Get(), vector->tag_len); + bool areCTsEqual = memcmp(out_ct.Get(), vector->ct, vector->ct_len) == 0; + bool areTagsEqual = memcmp(out_tag.Get(), vector->tag, vector->tag_len) == 0; NL_TEST_ASSERT(inSuite, areCTsEqual); NL_TEST_ASSERT(inSuite, areTagsEqual); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); @@ -100,11 +106,13 @@ static void TestAES_CCM_256DecryptTestVectors(nlTestSuite * inSuite, void * inCo if (vector->key_len == 32 && vector->pt_len > 0) { numOfTestsRan++; - uint8_t out_pt[vector->pt_len]; + chip::Platform::ScopedMemoryBuffer out_pt; + out_pt.Alloc(vector->pt_len); + NL_TEST_ASSERT(inSuite, out_pt); CHIP_ERROR err = AES_CCM_decrypt(vector->ct, vector->ct_len, vector->aad, vector->aad_len, vector->tag, vector->tag_len, - vector->key, vector->key_len, vector->iv, vector->iv_len, out_pt); + vector->key, vector->key_len, vector->iv, vector->iv_len, out_pt.Get()); - bool arePTsEqual = memcmp(vector->pt, out_pt, vector->pt_len) == 0; + bool arePTsEqual = memcmp(vector->pt, out_pt.Get(), vector->pt_len) == 0; NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); NL_TEST_ASSERT(inSuite, arePTsEqual); if (!arePTsEqual) @@ -126,11 +134,15 @@ static void TestAES_CCM_256EncryptInvalidPlainText(nlTestSuite * inSuite, void * if (vector->key_len == 32 && vector->pt_len > 0) { numOfTestsRan++; - uint8_t out_ct[vector->ct_len]; - uint8_t out_tag[vector->tag_len]; + chip::Platform::ScopedMemoryBuffer out_ct; + out_ct.Alloc(vector->ct_len); + NL_TEST_ASSERT(inSuite, out_ct); + chip::Platform::ScopedMemoryBuffer out_tag; + out_tag.Alloc(vector->tag_len); + NL_TEST_ASSERT(inSuite, out_tag); CHIP_ERROR err = AES_CCM_encrypt(vector->pt, 0, vector->aad, vector->aad_len, vector->key, vector->key_len, vector->iv, - vector->iv_len, out_ct, out_tag, vector->tag_len); + vector->iv_len, out_ct.Get(), out_tag.Get(), vector->tag_len); NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_INVALID_ARGUMENT); break; } @@ -148,11 +160,15 @@ static void TestAES_CCM_256EncryptNilKey(nlTestSuite * inSuite, void * inContext if (vector->key_len == 32 && vector->pt_len > 0) { numOfTestsRan++; - uint8_t out_ct[vector->ct_len]; - uint8_t out_tag[vector->tag_len]; + chip::Platform::ScopedMemoryBuffer out_ct; + out_ct.Alloc(vector->ct_len); + NL_TEST_ASSERT(inSuite, out_ct); + chip::Platform::ScopedMemoryBuffer out_tag; + out_tag.Alloc(vector->tag_len); + NL_TEST_ASSERT(inSuite, out_tag); CHIP_ERROR err = AES_CCM_encrypt(vector->pt, vector->pt_len, vector->aad, vector->aad_len, nullptr, 32, vector->iv, - vector->iv_len, out_ct, out_tag, vector->tag_len); + vector->iv_len, out_ct.Get(), out_tag.Get(), vector->tag_len); NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_INVALID_ARGUMENT); break; } @@ -170,11 +186,15 @@ static void TestAES_CCM_256EncryptInvalidIVLen(nlTestSuite * inSuite, void * inC if (vector->key_len == 32 && vector->pt_len > 0) { numOfTestsRan++; - uint8_t out_ct[vector->ct_len]; - uint8_t out_tag[vector->tag_len]; + chip::Platform::ScopedMemoryBuffer out_ct; + out_ct.Alloc(vector->ct_len); + NL_TEST_ASSERT(inSuite, out_ct); + chip::Platform::ScopedMemoryBuffer out_tag; + out_tag.Alloc(vector->tag_len); + NL_TEST_ASSERT(inSuite, out_tag); CHIP_ERROR err = AES_CCM_encrypt(vector->pt, vector->pt_len, vector->aad, vector->aad_len, vector->key, vector->key_len, - vector->iv, 0, out_ct, out_tag, vector->tag_len); + vector->iv, 0, out_ct.Get(), out_tag.Get(), vector->tag_len); NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_INVALID_ARGUMENT); break; } @@ -192,11 +212,15 @@ static void TestAES_CCM_256EncryptInvalidTagLen(nlTestSuite * inSuite, void * in if (vector->key_len == 32 && vector->pt_len > 0) { numOfTestsRan++; - uint8_t out_ct[vector->ct_len]; - uint8_t out_tag[vector->tag_len]; + chip::Platform::ScopedMemoryBuffer out_ct; + out_ct.Alloc(vector->ct_len); + NL_TEST_ASSERT(inSuite, out_ct); + chip::Platform::ScopedMemoryBuffer out_tag; + out_tag.Alloc(vector->tag_len); + NL_TEST_ASSERT(inSuite, out_tag); CHIP_ERROR err = AES_CCM_encrypt(vector->pt, vector->pt_len, vector->aad, vector->aad_len, vector->key, vector->key_len, - vector->iv, vector->iv_len, out_ct, out_tag, 13); + vector->iv, vector->iv_len, out_ct.Get(), out_tag.Get(), 13); NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_INVALID_ARGUMENT); break; } @@ -214,9 +238,11 @@ static void TestAES_CCM_256DecryptInvalidCipherText(nlTestSuite * inSuite, void if (vector->key_len == 32 && vector->pt_len > 0) { numOfTestsRan++; - uint8_t out_pt[vector->pt_len]; + chip::Platform::ScopedMemoryBuffer out_pt; + out_pt.Alloc(vector->pt_len); + NL_TEST_ASSERT(inSuite, out_pt); CHIP_ERROR err = AES_CCM_decrypt(vector->ct, 0, vector->aad, vector->aad_len, vector->tag, vector->tag_len, vector->key, - vector->key_len, vector->iv, vector->iv_len, out_pt); + vector->key_len, vector->iv, vector->iv_len, out_pt.Get()); NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_INVALID_ARGUMENT); break; } @@ -234,9 +260,11 @@ static void TestAES_CCM_256DecryptInvalidKey(nlTestSuite * inSuite, void * inCon if (vector->key_len == 32 && vector->pt_len > 0) { numOfTestsRan++; - uint8_t out_pt[vector->pt_len]; + chip::Platform::ScopedMemoryBuffer out_pt; + out_pt.Alloc(vector->pt_len); + NL_TEST_ASSERT(inSuite, out_pt); CHIP_ERROR err = AES_CCM_decrypt(vector->ct, vector->ct_len, vector->aad, vector->aad_len, vector->tag, vector->tag_len, - nullptr, 32, vector->iv, vector->iv_len, out_pt); + nullptr, 32, vector->iv, vector->iv_len, out_pt.Get()); NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_INVALID_ARGUMENT); break; } @@ -254,9 +282,11 @@ static void TestAES_CCM_256DecryptInvalidIVLen(nlTestSuite * inSuite, void * inC if (vector->key_len == 32 && vector->pt_len > 0) { numOfTestsRan++; - uint8_t out_pt[vector->pt_len]; + chip::Platform::ScopedMemoryBuffer out_pt; + out_pt.Alloc(vector->pt_len); + NL_TEST_ASSERT(inSuite, out_pt); CHIP_ERROR err = AES_CCM_decrypt(vector->ct, vector->ct_len, vector->aad, vector->aad_len, vector->tag, vector->tag_len, - vector->key, vector->key_len, vector->iv, 0, out_pt); + vector->key, vector->key_len, vector->iv, 0, out_pt.Get()); NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_INVALID_ARGUMENT); break; } @@ -274,11 +304,13 @@ static void TestAES_CCM_256DecryptInvalidTestVectors(nlTestSuite * inSuite, void if (vector->key_len == 32 && vector->pt_len > 0) { numOfTestsRan++; - uint8_t out_pt[vector->pt_len]; + chip::Platform::ScopedMemoryBuffer out_pt; + out_pt.Alloc(vector->pt_len); + NL_TEST_ASSERT(inSuite, out_pt); CHIP_ERROR err = AES_CCM_decrypt(vector->ct, vector->ct_len, vector->aad, vector->aad_len, vector->tag, vector->tag_len, - vector->key, vector->key_len, vector->iv, vector->iv_len, out_pt); + vector->key, vector->key_len, vector->iv, vector->iv_len, out_pt.Get()); - bool arePTsEqual = memcmp(vector->pt, out_pt, vector->pt_len) == 0; + bool arePTsEqual = memcmp(vector->pt, out_pt.Get(), vector->pt_len) == 0; NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_INTERNAL); NL_TEST_ASSERT(inSuite, arePTsEqual == false); } @@ -296,17 +328,21 @@ static void TestAES_CCM_128EncryptTestVectors(nlTestSuite * inSuite, void * inCo if (vector->pt_len > 0) { numOfTestsRan++; - uint8_t out_ct[vector->ct_len]; - uint8_t out_tag[vector->tag_len]; + chip::Platform::ScopedMemoryBuffer out_ct; + out_ct.Alloc(vector->ct_len); + NL_TEST_ASSERT(inSuite, out_ct); + chip::Platform::ScopedMemoryBuffer out_tag; + out_tag.Alloc(vector->tag_len); + NL_TEST_ASSERT(inSuite, out_tag); CHIP_ERROR err = AES_CCM_encrypt(vector->pt, vector->pt_len, vector->aad, vector->aad_len, vector->key, vector->key_len, - vector->iv, vector->iv_len, out_ct, out_tag, vector->tag_len); + vector->iv, vector->iv_len, out_ct.Get(), out_tag.Get(), vector->tag_len); NL_TEST_ASSERT(inSuite, err == vector->result); if (vector->result == CHIP_NO_ERROR) { - bool areCTsEqual = memcmp(out_ct, vector->ct, vector->ct_len) == 0; - bool areTagsEqual = memcmp(out_tag, vector->tag, vector->tag_len) == 0; + bool areCTsEqual = memcmp(out_ct.Get(), vector->ct, vector->ct_len) == 0; + bool areTagsEqual = memcmp(out_tag.Get(), vector->tag, vector->tag_len) == 0; NL_TEST_ASSERT(inSuite, areCTsEqual); NL_TEST_ASSERT(inSuite, areTagsEqual); if (!areCTsEqual) @@ -333,14 +369,16 @@ static void TestAES_CCM_128DecryptTestVectors(nlTestSuite * inSuite, void * inCo if (vector->pt_len > 0) { numOfTestsRan++; - uint8_t out_pt[vector->pt_len]; + chip::Platform::ScopedMemoryBuffer out_pt; + out_pt.Alloc(vector->pt_len); + NL_TEST_ASSERT(inSuite, out_pt); CHIP_ERROR err = AES_CCM_decrypt(vector->ct, vector->ct_len, vector->aad, vector->aad_len, vector->tag, vector->tag_len, - vector->key, vector->key_len, vector->iv, vector->iv_len, out_pt); + vector->key, vector->key_len, vector->iv, vector->iv_len, out_pt.Get()); NL_TEST_ASSERT(inSuite, err == vector->result); if (vector->result == CHIP_NO_ERROR) { - bool arePTsEqual = memcmp(vector->pt, out_pt, vector->pt_len) == 0; + bool arePTsEqual = memcmp(vector->pt, out_pt.Get(), vector->pt_len) == 0; NL_TEST_ASSERT(inSuite, arePTsEqual); if (!arePTsEqual) { @@ -362,11 +400,15 @@ static void TestAES_CCM_128EncryptInvalidPlainText(nlTestSuite * inSuite, void * if (vector->pt_len > 0) { numOfTestsRan++; - uint8_t out_ct[vector->ct_len]; - uint8_t out_tag[vector->tag_len]; + chip::Platform::ScopedMemoryBuffer out_ct; + out_ct.Alloc(vector->ct_len); + NL_TEST_ASSERT(inSuite, out_ct); + chip::Platform::ScopedMemoryBuffer out_tag; + out_tag.Alloc(vector->tag_len); + NL_TEST_ASSERT(inSuite, out_tag); CHIP_ERROR err = AES_CCM_encrypt(vector->pt, 0, vector->aad, vector->aad_len, vector->key, vector->key_len, vector->iv, - vector->iv_len, out_ct, out_tag, vector->tag_len); + vector->iv_len, out_ct.Get(), out_tag.Get(), vector->tag_len); NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_INVALID_ARGUMENT); break; } @@ -384,11 +426,15 @@ static void TestAES_CCM_128EncryptNilKey(nlTestSuite * inSuite, void * inContext if (vector->pt_len > 0) { numOfTestsRan++; - uint8_t out_ct[vector->ct_len]; - uint8_t out_tag[vector->tag_len]; + chip::Platform::ScopedMemoryBuffer out_ct; + out_ct.Alloc(vector->ct_len); + NL_TEST_ASSERT(inSuite, out_ct); + chip::Platform::ScopedMemoryBuffer out_tag; + out_tag.Alloc(vector->tag_len); + NL_TEST_ASSERT(inSuite, out_tag); CHIP_ERROR err = AES_CCM_encrypt(vector->pt, vector->pt_len, vector->aad, vector->aad_len, nullptr, 0, vector->iv, - vector->iv_len, out_ct, out_tag, vector->tag_len); + vector->iv_len, out_ct.Get(), out_tag.Get(), vector->tag_len); NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_INVALID_ARGUMENT); break; } @@ -406,11 +452,15 @@ static void TestAES_CCM_128EncryptInvalidIVLen(nlTestSuite * inSuite, void * inC if (vector->pt_len > 0) { numOfTestsRan++; - uint8_t out_ct[vector->ct_len]; - uint8_t out_tag[vector->tag_len]; + chip::Platform::ScopedMemoryBuffer out_ct; + out_ct.Alloc(vector->ct_len); + NL_TEST_ASSERT(inSuite, out_ct); + chip::Platform::ScopedMemoryBuffer out_tag; + out_tag.Alloc(vector->tag_len); + NL_TEST_ASSERT(inSuite, out_tag); CHIP_ERROR err = AES_CCM_encrypt(vector->pt, vector->pt_len, vector->aad, vector->aad_len, vector->key, vector->key_len, - vector->iv, 0, out_ct, out_tag, vector->tag_len); + vector->iv, 0, out_ct.Get(), out_tag.Get(), vector->tag_len); NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_INVALID_ARGUMENT); break; } @@ -428,11 +478,15 @@ static void TestAES_CCM_128EncryptInvalidTagLen(nlTestSuite * inSuite, void * in if (vector->pt_len > 0) { numOfTestsRan++; - uint8_t out_ct[vector->ct_len]; - uint8_t out_tag[vector->tag_len]; + chip::Platform::ScopedMemoryBuffer out_ct; + out_ct.Alloc(vector->ct_len); + NL_TEST_ASSERT(inSuite, out_ct); + chip::Platform::ScopedMemoryBuffer out_tag; + out_tag.Alloc(vector->tag_len); + NL_TEST_ASSERT(inSuite, out_tag); CHIP_ERROR err = AES_CCM_encrypt(vector->pt, vector->pt_len, vector->aad, vector->aad_len, vector->key, vector->key_len, - vector->iv, vector->iv_len, out_ct, out_tag, 13); + vector->iv, vector->iv_len, out_ct.Get(), out_tag.Get(), 13); NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_INVALID_ARGUMENT); break; } @@ -567,10 +621,12 @@ static void TestHKDF_SHA256(nlTestSuite * inSuite, void * inContext) { hkdf_sha256_vector v = hkdf_sha256_test_vectors[numOfTestsExecuted]; size_t out_length = v.output_key_material_length; - uint8_t out_buffer[out_length]; - HKDF_SHA256(v.initial_key_material, v.initial_key_material_length, v.salt, v.salt_length, v.info, v.info_length, out_buffer, - v.output_key_material_length); - bool success = memcmp(v.output_key_material, out_buffer, out_length) == 0; + chip::Platform::ScopedMemoryBuffer out_buffer; + out_buffer.Alloc(out_length); + NL_TEST_ASSERT(inSuite, out_buffer); + HKDF_SHA256(v.initial_key_material, v.initial_key_material_length, v.salt, v.salt_length, v.info, v.info_length, + out_buffer.Get(), v.output_key_material_length); + bool success = memcmp(v.output_key_material, out_buffer.Get(), out_length) == 0; NL_TEST_ASSERT(inSuite, success); } NL_TEST_ASSERT(inSuite, numOfTestsExecuted == 3); @@ -857,15 +913,17 @@ static void TestPBKDF2_SHA256_TestVectors(nlTestSuite * inSuite, void * inContex if (vector->plen > 0) { numOfTestsRan++; - uint8_t out_key[vector->key_len]; + chip::Platform::ScopedMemoryBuffer out_key; + out_key.Alloc(vector->key_len); + NL_TEST_ASSERT(inSuite, out_key); - CHIP_ERROR err = - pbkdf2_sha256(vector->password, vector->plen, vector->salt, vector->slen, vector->iter, vector->key_len, out_key); + CHIP_ERROR err = pbkdf2_sha256(vector->password, vector->plen, vector->salt, vector->slen, vector->iter, + vector->key_len, out_key.Get()); NL_TEST_ASSERT(inSuite, err == vector->result); if (vector->result == CHIP_NO_ERROR) { - NL_TEST_ASSERT(inSuite, memcmp(out_key, vector->key, vector->key_len) == 0); + NL_TEST_ASSERT(inSuite, memcmp(out_key.Get(), vector->key, vector->key_len) == 0); } } } @@ -1364,6 +1422,26 @@ static const nlTest sTests[] = { NL_TEST_SENTINEL() }; +/** + * Set up the test suite. + */ +int TestCHIPCryptoPAL_Setup(void * inContext) +{ + CHIP_ERROR error = chip::Platform::MemoryInit(); + if (error != CHIP_NO_ERROR) + return FAILURE; + return SUCCESS; +} + +/** + * Tear down the test suite. + */ +int TestCHIPCryptoPAL_Teardown(void * inContext) +{ + chip::Platform::MemoryShutdown(); + return SUCCESS; +} + int TestCHIPCryptoPAL(void) { // clang-format off @@ -1371,8 +1449,8 @@ int TestCHIPCryptoPAL(void) { "CHIP Crypto PAL tests", &sTests[0], - nullptr, - nullptr + TestCHIPCryptoPAL_Setup, + TestCHIPCryptoPAL_Teardown }; // clang-format on // Run test suit againt one context. diff --git a/src/inet/tests/TestInetCommon.cpp b/src/inet/tests/TestInetCommon.cpp index ef1176eff68801..ac9df92eaba6e8 100644 --- a/src/inet/tests/TestInetCommon.cpp +++ b/src/inet/tests/TestInetCommon.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -665,11 +666,17 @@ void DumpMemory(const uint8_t * mem, uint32_t len, const char * prefix) DumpMemory(mem, len, prefix, kRowWidth); } + static void RebootCallbackFn() { - char * lArgv[sRestartCallbackCtx.mArgc + 2]; int i; int j = 0; + chip::Platform::ScopedMemoryBuffer lArgv; + if (!lArgv.Alloc(sRestartCallbackCtx.mArgc + 2)) + { + printf("** failed to allocate memory **\n"); + ExitNow(); + } if (gSigusr1Received) { @@ -707,7 +714,7 @@ static void RebootCallbackFn() printf("********** Restarting *********\n"); fflush(stdout); - execvp(lArgv[0], lArgv); + execvp(lArgv[0], lArgv.Get()); exit: return; diff --git a/src/lib/support/tests/TestSerializableIntegerSet.cpp b/src/lib/support/tests/TestSerializableIntegerSet.cpp index f097f7bec44b1e..4956e65ba45f77 100644 --- a/src/lib/support/tests/TestSerializableIntegerSet.cpp +++ b/src/lib/support/tests/TestSerializableIntegerSet.cpp @@ -19,6 +19,7 @@ #include "TestSupport.h" #include +#include #include #include @@ -126,17 +127,17 @@ void TestSerializableIntegerSetSerialize(nlTestSuite * inSuite, void * inContext NL_TEST_ASSERT(inSuite, set.SerializeBase64(buf, size) == nullptr); NL_TEST_ASSERT(inSuite, size != 0); - char buf1[size]; - NL_TEST_ASSERT(inSuite, set.SerializeBase64(buf1, size) == buf1); + chip::Platform::ScopedMemoryString buf1("", size); + NL_TEST_ASSERT(inSuite, set.SerializeBase64(buf1.Get(), size) == buf1.Get()); NL_TEST_ASSERT(inSuite, size != 0); uint16_t size2 = static_cast(2 * size); - char buf2[size2]; - NL_TEST_ASSERT(inSuite, set.SerializeBase64(buf2, size2) == buf2); + chip::Platform::ScopedMemoryString buf2("", size2); + NL_TEST_ASSERT(inSuite, set.SerializeBase64(buf2.Get(), size2) == buf2.Get()); NL_TEST_ASSERT(inSuite, size2 == size); chip::SerializableU64Set<8> set2; - NL_TEST_ASSERT(inSuite, set2.DeserializeBase64(buf2, size2) == CHIP_NO_ERROR); + NL_TEST_ASSERT(inSuite, set2.DeserializeBase64(buf2.Get(), size2) == CHIP_NO_ERROR); for (uint64_t i = 1; i <= 6; i++) { diff --git a/src/setup_payload/ManualSetupPayloadGenerator.cpp b/src/setup_payload/ManualSetupPayloadGenerator.cpp index a7e5912903069b..5fa66d3fdcf10f 100644 --- a/src/setup_payload/ManualSetupPayloadGenerator.cpp +++ b/src/setup_payload/ManualSetupPayloadGenerator.cpp @@ -40,6 +40,10 @@ static uint32_t shortPayloadRepresentation(const SetupPayload & payload) return result; } +// TODO: issue #3663 - Unbounded stack in src/setup_payload +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstack-usage=" + static std::string decimalStringWithPadding(uint32_t number, int minLength) { char buf[minLength + 1]; @@ -47,6 +51,8 @@ static std::string decimalStringWithPadding(uint32_t number, int minLength) return std::string(buf); } +#pragma GCC diagnostic pop + CHIP_ERROR ManualSetupPayloadGenerator::payloadDecimalStringRepresentation(std::string & outDecimalString) { if (!mSetupPayload.isValidManualCode()) diff --git a/src/setup_payload/QRCodeSetupPayloadGenerator.cpp b/src/setup_payload/QRCodeSetupPayloadGenerator.cpp index 8f222fc926323a..923b0a2d0761cd 100644 --- a/src/setup_payload/QRCodeSetupPayloadGenerator.cpp +++ b/src/setup_payload/QRCodeSetupPayloadGenerator.cpp @@ -207,6 +207,10 @@ static CHIP_ERROR generateBitSet(SetupPayload & payload, uint8_t * bits, uint8_t return err; } +// TODO: issue #3663 - Unbounded stack in payloadBase41RepresentationWithTLV() +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstack-usage=" + static CHIP_ERROR payloadBase41RepresentationWithTLV(SetupPayload & setupPayload, string & base41Representation, size_t bitsetSize, uint8_t * tlvDataStart, size_t tlvDataLengthInBytes) { @@ -247,3 +251,5 @@ CHIP_ERROR QRCodeSetupPayloadGenerator::payloadBase41Representation(string & bas exit: return err; } + +#pragma GCC diagnostic pop // -Wstack-usage diff --git a/src/transport/SecureSession.cpp b/src/transport/SecureSession.cpp index b8c6a20cc9cd2e..a2a6933e4ec293 100644 --- a/src/transport/SecureSession.cpp +++ b/src/transport/SecureSession.cpp @@ -152,7 +152,8 @@ CHIP_ERROR SecureSession::Encrypt(const uint8_t * input, size_t input_length, ui constexpr Header::EncryptionType encType = Header::EncryptionType::kAESCCMTagLen16; const size_t taglen = MessageAuthenticationCode::TagLenForEncryptionType(encType); - uint8_t tag[taglen]; + assert(taglen <= kMaxTagLen); + uint8_t tag[kMaxTagLen]; VerifyOrExit(mKeyAvailable, error = CHIP_ERROR_INVALID_USE_OF_SESSION_KEY); VerifyOrExit(input != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); From bd63c51d1de74850488face9c63384055e8e572f Mon Sep 17 00:00:00 2001 From: Vidhi Shah Date: Fri, 6 Nov 2020 21:45:07 -0800 Subject: [PATCH 021/234] [Android] Save Wifi credentials to CHIP device (#3670) 1. Implement DevicePairingDelegate for Android in the JNI layer. 2. Send Wi-Fi credentials to CHIP device in the OnNetworkCredentialsRequestedCallback. --- .../CHIPTool/app/src/main/AndroidManifest.xml | 3 +- .../google/chip/chiptool/CHIPToolActivity.kt | 9 +- .../chiptool/GenericChipDeviceListener.kt | 45 +++++ .../clusterclient/OnOffClientFragment.kt | 35 ++-- .../chiptool/echoclient/EchoClientFragment.kt | 35 ++-- .../DeviceProvisioningFragment.kt | 151 ++++++++++++++ .../provisioning/EnterWifiNetworkFragment.kt | 44 ++++ .../CHIPDeviceDetailsFragment.kt | 84 ++------ .../layout/enter_wifi_network_fragment.xml | 45 +++++ .../res/layout/single_fragment_container.xml | 6 + .../app/src/main/res/values/strings.xml | 8 +- .../java/AndroidDeviceControllerWrapper.cpp | 188 +++++++++++++++++- .../java/AndroidDeviceControllerWrapper.h | 41 +++- .../java/AndroidDevicePairingDelegate.cpp | 53 ----- .../java/AndroidDevicePairingDelegate.h | 29 --- src/controller/java/BUILD.gn | 2 - .../java/CHIPDeviceController-JNI.cpp | 56 ++++-- .../ChipDeviceController.java | 53 +++++ 18 files changed, 668 insertions(+), 219 deletions(-) create mode 100644 src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/GenericChipDeviceListener.kt create mode 100644 src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/provisioning/DeviceProvisioningFragment.kt create mode 100644 src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/provisioning/EnterWifiNetworkFragment.kt create mode 100644 src/android/CHIPTool/app/src/main/res/layout/enter_wifi_network_fragment.xml create mode 100644 src/android/CHIPTool/app/src/main/res/layout/single_fragment_container.xml delete mode 100644 src/controller/java/AndroidDevicePairingDelegate.cpp delete mode 100644 src/controller/java/AndroidDevicePairingDelegate.h diff --git a/src/android/CHIPTool/app/src/main/AndroidManifest.xml b/src/android/CHIPTool/app/src/main/AndroidManifest.xml index f8f1c4d93156ca..b3ad31a0e4cbd6 100644 --- a/src/android/CHIPTool/app/src/main/AndroidManifest.xml +++ b/src/android/CHIPTool/app/src/main/AndroidManifest.xml @@ -19,7 +19,8 @@ android:theme="@style/AppTheme"> + android:label="@string/app_name" + android:windowSoftInputMode="adjustResize"> diff --git a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/CHIPToolActivity.kt b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/CHIPToolActivity.kt index 3ba12919843717..8e3cef1b0c84ae 100644 --- a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/CHIPToolActivity.kt +++ b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/CHIPToolActivity.kt @@ -28,6 +28,8 @@ import com.google.chip.chiptool.attestation.AttestationTestFragment import com.google.chip.chiptool.clusterclient.OnOffClientFragment import com.google.chip.chiptool.commissioner.CommissionerActivity import com.google.chip.chiptool.echoclient.EchoClientFragment +import com.google.chip.chiptool.provisioning.DeviceProvisioningFragment +import com.google.chip.chiptool.provisioning.EnterWifiNetworkFragment import com.google.chip.chiptool.setuppayloadscanner.BarcodeFragment import com.google.chip.chiptool.setuppayloadscanner.CHIPDeviceDetailsFragment import com.google.chip.chiptool.setuppayloadscanner.CHIPDeviceInfo @@ -36,7 +38,8 @@ import com.google.chip.chiptool.setuppayloadscanner.QrCodeInfo class CHIPToolActivity : AppCompatActivity(), BarcodeFragment.Callback, - SelectActionFragment.Callback { + SelectActionFragment.Callback, + CHIPDeviceDetailsFragment.Callback { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -54,6 +57,10 @@ class CHIPToolActivity : onNfcIntent(intent) } + override fun onStartRendezvousOverBle(deviceInfo: CHIPDeviceInfo) { + showFragment(DeviceProvisioningFragment.newInstance(deviceInfo)) + } + override fun onCHIPDeviceInfoReceived(deviceInfo: CHIPDeviceInfo) { showFragment(CHIPDeviceDetailsFragment.newInstance(deviceInfo)) } diff --git a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/GenericChipDeviceListener.kt b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/GenericChipDeviceListener.kt new file mode 100644 index 00000000000000..26a7d1740d1d21 --- /dev/null +++ b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/GenericChipDeviceListener.kt @@ -0,0 +1,45 @@ +package com.google.chip.chiptool + +import chip.devicecontroller.ChipDeviceController + +open class GenericChipDeviceListener : ChipDeviceController.CompletionListener { + override fun onConnectDeviceComplete() { + // No op + } + + override fun onSendMessageComplete(message: String?) { + // No op + } + + override fun onNetworkCredentialsRequested() { + // No op + } + + override fun onOperationalCredentialsRequested(opCreds: ByteArray?) { + // No op + } + + override fun onStatusUpdate(status: Int) { + // No op + } + + override fun onPairingComplete(code: Int) { + // No op + } + + override fun onPairingDeleted(code: Int) { + // No op + } + + override fun onNotifyChipConnectionClosed() { + // No op + } + + override fun onCloseBleComplete() { + // No op + } + + override fun onError(error: Throwable?) { + // No op + } +} diff --git a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OnOffClientFragment.kt b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OnOffClientFragment.kt index e528a39dcf6fb4..4da15ef00284f4 100644 --- a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OnOffClientFragment.kt +++ b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OnOffClientFragment.kt @@ -9,11 +9,12 @@ import androidx.fragment.app.Fragment import chip.devicecontroller.ChipCommandType import chip.devicecontroller.ChipDeviceController import com.google.chip.chiptool.ChipClient +import com.google.chip.chiptool.GenericChipDeviceListener import com.google.chip.chiptool.R import kotlinx.android.synthetic.main.on_off_client_fragment.* import kotlinx.android.synthetic.main.on_off_client_fragment.view.* -class OnOffClientFragment : Fragment(), ChipDeviceController.CompletionListener { +class OnOffClientFragment : Fragment() { private val deviceController: ChipDeviceController get() = ChipClient.getDeviceController() @@ -25,7 +26,7 @@ class OnOffClientFragment : Fragment(), ChipDeviceController.CompletionListener savedInstanceState: Bundle? ): View { return inflater.inflate(R.layout.on_off_client_fragment, container, false).apply { - deviceController.setCompletionListener(this@OnOffClientFragment) + deviceController.setCompletionListener(ChipControllerCallback()) onBtn.setOnClickListener { sendOnCommandClick() } offBtn.setOnClickListener { sendOffCommandClick() } @@ -38,24 +39,26 @@ class OnOffClientFragment : Fragment(), ChipDeviceController.CompletionListener ipAddressEd.setText(deviceController.ipAddress ?: requireContext().getString(R.string.enter_ip_address_hint_text)) } - override fun onConnectDeviceComplete() { - sendCommand() - } + inner class ChipControllerCallback : GenericChipDeviceListener() { + override fun onConnectDeviceComplete() { + sendCommand() + } - override fun onSendMessageComplete(message: String?) { - commandStatusTv.text = requireContext().getString(R.string.echo_status_response, message) - } + override fun onSendMessageComplete(message: String?) { + commandStatusTv.text = requireContext().getString(R.string.echo_status_response, message) + } - override fun onNotifyChipConnectionClosed() { - Log.d(TAG, "onNotifyChipConnectionClosed") - } + override fun onNotifyChipConnectionClosed() { + Log.d(TAG, "onNotifyChipConnectionClosed") + } - override fun onCloseBleComplete() { - Log.d(TAG, "onCloseBleComplete") - } + override fun onCloseBleComplete() { + Log.d(TAG, "onCloseBleComplete") + } - override fun onError(error: Throwable) { - Log.d(TAG, "onError: $error") + override fun onError(error: Throwable?) { + Log.d(TAG, "onError: $error") + } } private fun sendOnCommandClick() { diff --git a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/echoclient/EchoClientFragment.kt b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/echoclient/EchoClientFragment.kt index 09b5b1a37a33a0..93950819784fe3 100644 --- a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/echoclient/EchoClientFragment.kt +++ b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/echoclient/EchoClientFragment.kt @@ -25,12 +25,13 @@ import android.view.ViewGroup import androidx.fragment.app.Fragment import chip.devicecontroller.ChipDeviceController import com.google.chip.chiptool.ChipClient +import com.google.chip.chiptool.GenericChipDeviceListener import com.google.chip.chiptool.R import kotlinx.android.synthetic.main.echo_client_fragment.* import kotlinx.android.synthetic.main.echo_client_fragment.view.* /** Sends echo messages to the CHIP device. */ -class EchoClientFragment : Fragment(), ChipDeviceController.CompletionListener { +class EchoClientFragment : Fragment() { private val deviceController: ChipDeviceController get() = ChipClient.getDeviceController() @@ -41,7 +42,7 @@ class EchoClientFragment : Fragment(), ChipDeviceController.CompletionListener { savedInstanceState: Bundle? ): View { return inflater.inflate(R.layout.echo_client_fragment, container, false).apply { - deviceController.setCompletionListener(this@EchoClientFragment) + deviceController.setCompletionListener(ChipControllerCallback()) inputTextEd.hint = requireContext().getString(R.string.echo_input_hint_text) @@ -49,24 +50,26 @@ class EchoClientFragment : Fragment(), ChipDeviceController.CompletionListener { } } - override fun onConnectDeviceComplete() { - sendEcho() - } + inner class ChipControllerCallback : GenericChipDeviceListener() { + override fun onConnectDeviceComplete() { + sendEcho() + } - override fun onSendMessageComplete(message: String?) { - commandStatusTv.text = requireContext().getString(R.string.echo_status_response, message) - } + override fun onSendMessageComplete(message: String?) { + commandStatusTv.text = requireContext().getString(R.string.echo_status_response, message) + } - override fun onNotifyChipConnectionClosed() { - Log.d(TAG, "onNotifyChipConnectionClosed") - } + override fun onNotifyChipConnectionClosed() { + Log.d(TAG, "onNotifyChipConnectionClosed") + } - override fun onCloseBleComplete() { - Log.d(TAG, "onCloseBleComplete") - } + override fun onCloseBleComplete() { + Log.d(TAG, "onCloseBleComplete") + } - override fun onError(error: Throwable) { - Log.d(TAG, "onError: $error") + override fun onError(error: Throwable?) { + Log.d(TAG, "onError: $error") + } } private fun onSendCommandClick() { diff --git a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/provisioning/DeviceProvisioningFragment.kt b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/provisioning/DeviceProvisioningFragment.kt new file mode 100644 index 00000000000000..a884a7b435563c --- /dev/null +++ b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/provisioning/DeviceProvisioningFragment.kt @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.google.chip.chiptool.provisioning + +import android.bluetooth.BluetoothGatt +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import androidx.fragment.app.Fragment +import com.google.chip.chiptool.ChipClient +import com.google.chip.chiptool.GenericChipDeviceListener +import com.google.chip.chiptool.R +import com.google.chip.chiptool.bluetooth.BluetoothManager +import com.google.chip.chiptool.setuppayloadscanner.CHIPDeviceDetailsFragment +import com.google.chip.chiptool.setuppayloadscanner.CHIPDeviceInfo +import com.google.chip.chiptool.util.FragmentUtil +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.Job +import kotlinx.coroutines.cancel +import kotlinx.coroutines.launch + +@ExperimentalCoroutinesApi +class DeviceProvisioningFragment : Fragment() { + + private lateinit var deviceInfo: CHIPDeviceInfo + + private var gatt: BluetoothGatt? = null + + private val scope = CoroutineScope(Dispatchers.Main + Job()) + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + deviceInfo = checkNotNull(requireArguments().getParcelable(ARG_DEVICE_INFO)) + return inflater.inflate(R.layout.single_fragment_container, container, false).apply { + if (savedInstanceState == null) { + startConnectingToDevice() + } + } + } + + override fun onStop() { + super.onStop() + gatt = null + scope.cancel() + } + + private fun startConnectingToDevice() { + if (gatt != null) { + return + } + + scope.launch { + val deviceController = ChipClient.getDeviceController() + val bluetoothManager = BluetoothManager() + + showMessage( + R.string.rendezvous_over_ble_scanning_text, + deviceInfo.discriminator.toString() + ) + val device = bluetoothManager.getBluetoothDevice(deviceInfo.discriminator) ?: run { + showMessage(R.string.rendezvous_over_ble_scanning_failed_text) + return@launch + } + + showMessage( + R.string.rendezvous_over_ble_connecting_text, + device.name ?: device.address.toString() + ) + gatt = bluetoothManager.connect(requireContext(), device) + + showMessage(R.string.rendezvous_over_ble_pairing_text) + deviceController.setCompletionListener(ConnectionCallback()) + deviceController.beginConnectDeviceBle(gatt, deviceInfo.setupPinCode); + } + } + + private fun showMessage(msgResId: Int, stringArgs: String? = null) { + requireActivity().runOnUiThread { + val context = requireContext() + Toast.makeText(context, context.getString(msgResId, stringArgs), Toast.LENGTH_SHORT) + .show() + } + } + + inner class ConnectionCallback : GenericChipDeviceListener() { + override fun onConnectDeviceComplete() { + showMessage(R.string.rendezvous_over_ble_success_text) + } + + override fun onStatusUpdate(status: Int) { + Log.i(TAG, "Pairing status update: $status"); + } + + override fun onNetworkCredentialsRequested() { + childFragmentManager.beginTransaction() + .add(R.id.fragment_container, EnterWifiNetworkFragment.newInstance()) + .commit() + } + + override fun onPairingComplete(code: Int) { + Log.d(TAG, "onPairingComplete: $code") + } + + override fun onPairingDeleted(code: Int) { + Log.d(TAG, "onPairingDeleted: $code") + } + + override fun onCloseBleComplete() { + Log.d(TAG, "onCloseBleComplete") + } + + override fun onError(error: Throwable?) { + Log.d(TAG, "onError: $error") + } + } + + companion object { + private const val TAG = "DeviceProvisioningFragment" + private const val ARG_DEVICE_INFO = "device_info" + + fun newInstance(deviceInfo: CHIPDeviceInfo): DeviceProvisioningFragment { + return DeviceProvisioningFragment().apply { + arguments = Bundle(1).apply { putParcelable(ARG_DEVICE_INFO, deviceInfo) } + } + } + } +} \ No newline at end of file diff --git a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/provisioning/EnterWifiNetworkFragment.kt b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/provisioning/EnterWifiNetworkFragment.kt new file mode 100644 index 00000000000000..1c0f38ac60a770 --- /dev/null +++ b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/provisioning/EnterWifiNetworkFragment.kt @@ -0,0 +1,44 @@ +package com.google.chip.chiptool.provisioning + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import androidx.fragment.app.Fragment +import com.google.chip.chiptool.ChipClient +import com.google.chip.chiptool.R +import kotlinx.android.synthetic.main.enter_wifi_network_fragment.* +import kotlinx.android.synthetic.main.enter_wifi_network_fragment.view.* + +class EnterWifiNetworkFragment : Fragment() { + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + return inflater.inflate(R.layout.enter_wifi_network_fragment, container, false).apply { + saveNetworkBtn.setOnClickListener { onSaveNetworkClicked() } + } + } + + private fun onSaveNetworkClicked() { + val ssid = ssidEd.text + val pwd = pwdEd.text + + if (ssid.isNullOrBlank() || pwd.isNullOrBlank()) { + Toast.makeText(requireContext(), "Ssid and password required.", Toast.LENGTH_SHORT).show() + return + } + + ChipClient.getDeviceController().apply { + sendWiFiCredentials(ssid.toString(), pwd.toString()) + } + } + + companion object { + fun newInstance() = EnterWifiNetworkFragment() + } + +} \ No newline at end of file diff --git a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/CHIPDeviceDetailsFragment.kt b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/CHIPDeviceDetailsFragment.kt index 7c7ecdf06c74ff..0165651bc23259 100644 --- a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/CHIPDeviceDetailsFragment.kt +++ b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/CHIPDeviceDetailsFragment.kt @@ -18,32 +18,28 @@ package com.google.chip.chiptool.setuppayloadscanner -import android.bluetooth.BluetoothGatt import android.os.Bundle -import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.TextView -import android.widget.Toast import androidx.fragment.app.Fragment -import chip.devicecontroller.ChipDeviceController -import com.google.chip.chiptool.ChipClient import com.google.chip.chiptool.R -import com.google.chip.chiptool.bluetooth.BluetoothManager -import kotlinx.android.synthetic.main.chip_device_info_fragment.view.* -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job -import kotlinx.coroutines.cancel -import kotlinx.coroutines.launch +import com.google.chip.chiptool.util.FragmentUtil +import kotlinx.android.synthetic.main.chip_device_info_fragment.view.ble_rendezvous_btn +import kotlinx.android.synthetic.main.chip_device_info_fragment.view.discriminatorTv +import kotlinx.android.synthetic.main.chip_device_info_fragment.view.productIdTv +import kotlinx.android.synthetic.main.chip_device_info_fragment.view.setupCodeTv +import kotlinx.android.synthetic.main.chip_device_info_fragment.view.softap_rendezvous_btn +import kotlinx.android.synthetic.main.chip_device_info_fragment.view.vendorIdTv +import kotlinx.android.synthetic.main.chip_device_info_fragment.view.vendorTagsContainer +import kotlinx.android.synthetic.main.chip_device_info_fragment.view.vendorTagsLabelTv +import kotlinx.android.synthetic.main.chip_device_info_fragment.view.versionTv /** Show the [CHIPDeviceInfo]. */ -class CHIPDeviceDetailsFragment : Fragment(), ChipDeviceController.CompletionListener { +class CHIPDeviceDetailsFragment : Fragment() { private lateinit var deviceInfo: CHIPDeviceInfo - private var gatt: BluetoothGatt? = null - private val scope = CoroutineScope(Dispatchers.Main + Job()) override fun onCreateView( inflater: LayoutInflater, @@ -77,66 +73,20 @@ class CHIPDeviceDetailsFragment : Fragment(), ChipDeviceController.CompletionLis } ble_rendezvous_btn.setOnClickListener { onRendezvousBleClicked() } - softap_rendezvous_btn.setOnClickListener { onRendezvousSoftApClicked() } - } - } - - override fun onStop() { - super.onStop() - gatt = null - scope.cancel() - } - - private fun onRendezvousBleClicked() { - if (gatt == null) { - scope.launch { - val deviceController = ChipClient.getDeviceController() - val bluetoothManager = BluetoothManager() - - showMessage(requireContext().getString(R.string.rendezvous_over_ble_scanning_text) + " " + deviceInfo.discriminator.toString()) - val device = bluetoothManager.getBluetoothDevice(deviceInfo.discriminator) ?: run { - showMessage(requireContext().getString(R.string.rendezvous_over_ble_scanning_failed_text)) - return@launch - } - - showMessage(requireContext().getString(R.string.rendezvous_over_ble_connecting_text) + " " + (device.name ?: device.address.toString())) - gatt = bluetoothManager.connect(requireContext(), device) - showMessage(requireContext().getString(R.string.rendezvous_over_ble_pairing_text)) - deviceController.setCompletionListener(this@CHIPDeviceDetailsFragment) - deviceController.beginConnectDeviceBle(gatt, deviceInfo.setupPinCode); - } + // TODO: Until Rendezvous over hotspot is ready to implement + softap_rendezvous_btn.visibility = View.GONE } } - override fun onConnectDeviceComplete() { - showMessage(requireContext().getString(R.string.rendezvous_over_ble_success_text)) - } - override fun onCloseBleComplete() { - Log.d(TAG, "onCloseBleComplete") - } - - override fun onNotifyChipConnectionClosed() { - Log.d(TAG, "onNotifyChipConnectionClosed") - } - - override fun onSendMessageComplete(message: String?) { - Log.d(TAG, "Message received: $message") - } - override fun onError(error: Throwable?) { - Log.d(TAG, "onError: $error") - } - - private fun onRendezvousSoftApClicked() { - // TODO: once rendezvous over hotspot is ready in CHIP + private fun onRendezvousBleClicked() { + FragmentUtil.getHost(this, Callback::class.java)?.onStartRendezvousOverBle(deviceInfo) } - private fun showMessage(msg: String) { - requireActivity().runOnUiThread { - Toast.makeText(requireContext(), msg, Toast.LENGTH_SHORT).show() - } + interface Callback { + fun onStartRendezvousOverBle(deviceInfo: CHIPDeviceInfo) } companion object { diff --git a/src/android/CHIPTool/app/src/main/res/layout/enter_wifi_network_fragment.xml b/src/android/CHIPTool/app/src/main/res/layout/enter_wifi_network_fragment.xml new file mode 100644 index 00000000000000..58ae3a07a82403 --- /dev/null +++ b/src/android/CHIPTool/app/src/main/res/layout/enter_wifi_network_fragment.xml @@ -0,0 +1,45 @@ + + + + + + + + + +