-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ESP32: OTA Requestor and OTA Provider example applications (#11320)
* Added OTA requester and provider app for esp32 * Apply suggestions from code review Co-authored-by: Boris Zbarsky <bzbarsky@apple.com> * Addressed review comments * Addressed review comments * Apply suggestions from code review Co-authored-by: Carol Yang <clyang@apple.com> * Restyled by clang-format * Addressed review comments * Added few words to spellcheck dictionary * Added .gitignore files to esp32 ota apps Co-authored-by: Boris Zbarsky <bzbarsky@apple.com> Co-authored-by: Carol Yang <clyang@apple.com> Co-authored-by: Restyled.io <commits@restyled.io>
- Loading branch information
Showing
36 changed files
with
2,946 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
*.vscode | ||
|
||
/build/ | ||
/sdkconfig | ||
/sdkconfig.old |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# | ||
# Copyright (c) 2021 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. | ||
|
||
# The following lines of boilerplate have to be in your project's | ||
# CMakeLists in this exact order for cmake to work correctly | ||
cmake_minimum_required(VERSION 3.5) | ||
|
||
include($ENV{IDF_PATH}/tools/cmake/project.cmake) | ||
include(${CMAKE_CURRENT_LIST_DIR}/../../common/cmake/idf_flashing.cmake) | ||
|
||
set(EXTRA_COMPONENT_DIRS | ||
"${CMAKE_CURRENT_LIST_DIR}/third_party/connectedhomeip/config/esp32/components" | ||
"${CMAKE_CURRENT_LIST_DIR}/../../common/QRCode" | ||
) | ||
|
||
project(chip-ota-provider-app) | ||
idf_build_set_property(CXX_COMPILE_OPTIONS "-std=gnu++14;-Os;-DLWIP_IPV6_SCOPES=0;-DCHIP_HAVE_CONFIG_H" APPEND) | ||
idf_build_set_property(C_COMPILE_OPTIONS "-Os;-DLWIP_IPV6_SCOPES=0" APPEND) | ||
|
||
flashing_script() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
# CHIP ESP32 OTA Provider Example | ||
|
||
A prototype application that demonstrates OTA provider capabilities. | ||
|
||
## Supported Devices | ||
|
||
- This example supports ESP32 and ESP32C3. For details please check | ||
[here](https://github.com/shubhamdp/connectedhomeip/tree/shubhamdp-patch-1/examples/all-clusters-app/esp32#supported-devices). | ||
|
||
## Building the Example Application | ||
|
||
- If you are building for the first time please check | ||
[Building the Example Application](https://github.com/shubhamdp/connectedhomeip/tree/shubhamdp-patch-1/examples/all-clusters-app/esp32#building-the-example-application) | ||
guide. | ||
- Otherwise, `idf.py build` works! | ||
|
||
## Flashing the Example Application | ||
|
||
``` | ||
idf.py -p <OTAProviderSerialPort> flash | ||
``` | ||
|
||
## Flashing the hello-world.bin OTA image | ||
|
||
Flash hello-world OTA image on OTA Provider's "ota_data" flash partition. Please | ||
find hello-world.bin | ||
[here](http://shubhamdp.github.io/esp_ota/esp32/hello-world-flash-in-ota-provider-partition.bin). | ||
This OTA image is built for ESP32, it will not work on other devices. This is | ||
the OTA upgrade image and will be sent to OTA requestor. | ||
|
||
``` | ||
esptool.py -p <OTAProviderSerialPort> write_flash 0x206400 hello-world-flash-in-ota-provider-partition.bin | ||
``` | ||
|
||
NOTE: This is a modified binary which contains the size of OTA image at first 4 | ||
bytes. | ||
|
||
Run the idf monitor | ||
|
||
``` | ||
idf.py -p <OTAProviderSerialPort> monitor | ||
``` | ||
|
||
## Commissioning over BLE using chip-tool | ||
|
||
- Please build the standalone chip-tool as described [here](../../chip-tool) | ||
- Commissioning the OTA Provider | ||
|
||
``` | ||
./out/debug/chip-tool pairing ble-wifi 12345 <ssid> <passphrase> 0 20202021 3841 | ||
``` | ||
|
||
--- | ||
|
||
Please note down the IP Address and Node ID of OTA Provider, these are required | ||
for [OTA Requestor Example](../../ota-requestor-app/esp32). Once OTA provider is | ||
commissioned then head over to | ||
[OTA Requestor Example](../../ota-requestor-app/esp32). | ||
|
||
--- | ||
|
||
## Features | ||
|
||
- Can complete full BDX transfer | ||
- Provide the full OTA image to Requestor | ||
|
||
## Limitations | ||
|
||
- Synchronous BDX transfer only | ||
- Does not check VID/PID | ||
- Only one transfer at a time | ||
- Does not check incoming UpdateTokens | ||
- Does not support the header defined in Matter Specification. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
/* | ||
* | ||
* Copyright (c) 2021 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 <BdxOtaSender.h> | ||
|
||
#include <lib/core/CHIPError.h> | ||
#include <lib/support/BitFlags.h> | ||
#include <lib/support/CHIPMemString.h> | ||
#include <messaging/ExchangeContext.h> | ||
#include <messaging/Flags.h> | ||
#include <protocols/bdx/BdxTransferSession.h> | ||
|
||
using chip::bdx::StatusCode; | ||
using chip::bdx::TransferControlFlags; | ||
using chip::bdx::TransferSession; | ||
|
||
void BdxOtaSender::SetCallbacks(BdxOtaSenderCallbacks callbacks) | ||
{ | ||
mOnBlockQueryCallback = callbacks.onBlockQuery; | ||
mOnTransferCompleteCallback = callbacks.onTransferComplete; | ||
mOnTransferFailedCallback = callbacks.onTransferFailed; | ||
} | ||
|
||
void BdxOtaSender::HandleTransferSessionOutput(TransferSession::OutputEvent & event) | ||
{ | ||
CHIP_ERROR err = CHIP_NO_ERROR; | ||
|
||
if (event.EventType != TransferSession::OutputEventType::kNone) | ||
{ | ||
ChipLogDetail(BDX, "OutputEvent type: %s", event.ToString(event.EventType)); | ||
} | ||
|
||
switch (event.EventType) | ||
{ | ||
case TransferSession::OutputEventType::kNone: | ||
break; | ||
case TransferSession::OutputEventType::kMsgToSend: { | ||
chip::Messaging::SendFlags sendFlags; | ||
if (!event.msgTypeData.HasMessageType(chip::Protocols::SecureChannel::MsgType::StatusReport)) | ||
{ | ||
// All messages sent from the Sender expect a response, except for a StatusReport which would indicate an error and the | ||
// end of the transfer. | ||
sendFlags.Set(chip::Messaging::SendMessageFlags::kExpectResponse); | ||
} | ||
VerifyOrReturn(mExchangeCtx != nullptr, ChipLogError(BDX, "%s: mExchangeCtx is null", __FUNCTION__)); | ||
err = mExchangeCtx->SendMessage(event.msgTypeData.ProtocolId, event.msgTypeData.MessageType, std::move(event.MsgData), | ||
sendFlags); | ||
if (err != CHIP_NO_ERROR) | ||
{ | ||
ChipLogError(BDX, "SendMessage failed: %s", chip::ErrorStr(err)); | ||
} | ||
break; | ||
} | ||
case TransferSession::OutputEventType::kInitReceived: { | ||
// TransferSession will automatically reject a transfer if there are no | ||
// common supported control modes. It will also default to the smaller | ||
// block size. | ||
TransferSession::TransferAcceptData acceptData; | ||
acceptData.ControlMode = TransferControlFlags::kReceiverDrive; // OTA must use receiver drive | ||
acceptData.MaxBlockSize = mTransfer.GetTransferBlockSize(); | ||
acceptData.StartOffset = mTransfer.GetStartOffset(); | ||
acceptData.Length = mTransfer.GetTransferLength(); | ||
VerifyOrReturn(mTransfer.AcceptTransfer(acceptData) == CHIP_NO_ERROR, | ||
ChipLogError(BDX, "%s: %s", __FUNCTION__, chip::ErrorStr(err))); | ||
break; | ||
} | ||
case TransferSession::OutputEventType::kQueryReceived: { | ||
TransferSession::BlockData blockData; | ||
uint16_t blockSize = mTransfer.GetTransferBlockSize(); | ||
uint16_t bytesToRead = blockSize; | ||
|
||
chip::System::PacketBufferHandle blockBuf = chip::System::PacketBufferHandle::New(bytesToRead); | ||
if (blockBuf.IsNull()) | ||
{ | ||
// TODO: AbortTransfer() needs to support GeneralStatusCode failures as well as BDX specific errors. | ||
mTransfer.AbortTransfer(StatusCode::kUnknown); | ||
return; | ||
} | ||
|
||
if (mOnBlockQueryCallback != nullptr && mOnBlockQueryCallback->mCall != nullptr) | ||
{ | ||
if (CHIP_NO_ERROR != | ||
mOnBlockQueryCallback->mCall(mOnBlockQueryCallback->mContext, blockBuf, blockData.Length, blockData.IsEof, | ||
mNumBytesSent)) | ||
{ | ||
ChipLogError(BDX, "onBlockQuery Callback failed"); | ||
mTransfer.AbortTransfer(StatusCode::kUnknown); | ||
return; | ||
} | ||
} | ||
else | ||
{ | ||
ChipLogError(BDX, "onBlockQuery Callback not set"); | ||
mTransfer.AbortTransfer(StatusCode::kUnknown); | ||
return; | ||
} | ||
|
||
blockData.Data = blockBuf->Start(); | ||
mNumBytesSent = static_cast<uint32_t>(mNumBytesSent + blockData.Length); | ||
|
||
VerifyOrReturn(CHIP_NO_ERROR == mTransfer.PrepareBlock(blockData), | ||
ChipLogError(BDX, "%s: PrepareBlock failed: %s", __FUNCTION__, chip::ErrorStr(err))); | ||
break; | ||
} | ||
case TransferSession::OutputEventType::kAckReceived: | ||
break; | ||
case TransferSession::OutputEventType::kAckEOFReceived: | ||
ChipLogDetail(BDX, "Transfer completed, got AckEOF"); | ||
if (mOnTransferCompleteCallback != nullptr && mOnTransferCompleteCallback->mCall != nullptr) | ||
{ | ||
mOnTransferCompleteCallback->mCall(mOnTransferCompleteCallback->mContext); | ||
} | ||
else | ||
{ | ||
ChipLogError(BDX, "onTransferComplete Callback not set"); | ||
} | ||
Reset(); | ||
break; | ||
case TransferSession::OutputEventType::kStatusReceived: | ||
ChipLogError(BDX, "Got StatusReport %x", static_cast<uint16_t>(event.statusData.statusCode)); | ||
if (mOnTransferFailedCallback != nullptr && mOnTransferFailedCallback->mCall != nullptr) | ||
{ | ||
mOnTransferFailedCallback->mCall(mOnTransferFailedCallback->mContext, kErrorBdxSenderStatusReceived); | ||
} | ||
else | ||
{ | ||
ChipLogError(BDX, "onTransferFailed Callback not set"); | ||
} | ||
Reset(); | ||
break; | ||
case TransferSession::OutputEventType::kInternalError: | ||
ChipLogError(BDX, "InternalError"); | ||
if (mOnTransferFailedCallback != nullptr && mOnTransferFailedCallback->mCall != nullptr) | ||
{ | ||
mOnTransferFailedCallback->mCall(mOnTransferFailedCallback->mContext, kErrorBdxSenderInternal); | ||
} | ||
{ | ||
ChipLogError(BDX, "onTransferFailed Callback not set"); | ||
} | ||
Reset(); | ||
break; | ||
case TransferSession::OutputEventType::kTransferTimeout: | ||
ChipLogError(BDX, "Transfer timed out"); | ||
if (mOnTransferFailedCallback != nullptr && mOnTransferFailedCallback->mCall != nullptr) | ||
{ | ||
mOnTransferFailedCallback->mCall(mOnTransferFailedCallback->mContext, kErrorBdxSenderTimeOut); | ||
} | ||
{ | ||
ChipLogError(BDX, "onTransferFailed Callback not set"); | ||
} | ||
Reset(); | ||
break; | ||
case TransferSession::OutputEventType::kAcceptReceived: | ||
case TransferSession::OutputEventType::kBlockReceived: | ||
default: | ||
// TransferSession should prevent this case from happening. | ||
ChipLogError(BDX, "%s: unsupported event type", __FUNCTION__); | ||
} | ||
} | ||
|
||
void BdxOtaSender::Reset() | ||
{ | ||
mTransfer.Reset(); | ||
if (mExchangeCtx != nullptr) | ||
{ | ||
mExchangeCtx->Close(); | ||
} | ||
mNumBytesSent = 0; | ||
} | ||
|
||
uint16_t BdxOtaSender::GetTransferBlockSize(void) | ||
{ | ||
return mTransfer.GetTransferBlockSize(); | ||
} | ||
|
||
uint64_t BdxOtaSender::GetTransferLength() | ||
{ | ||
return mTransfer.GetTransferLength(); | ||
} |
Oops, something went wrong.