Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ESP32: OTA Requestor and OTA Provider example applications #11320

Merged
merged 9 commits into from
Nov 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/.wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ AppConfig
ApplicationBasic
ApplicationIdentifier
ApplicationLauncher
ApplyUpdateRequest
approver
appspot
aps
Expand Down Expand Up @@ -340,6 +341,7 @@ env
esd
ESPPORT
Espressif
esptool
eth
EthernetNetworkDiagnostics
ethernets
Expand Down Expand Up @@ -690,6 +692,11 @@ optionsMask
optionsOverride
orgs
OTA
OTAProviderIpAddress
OTAProviderNodeId
OTAProviderSerialPort
OTARequesterImpl
OTARequestorSerialPort
OTBR
otcli
PAA
Expand Down Expand Up @@ -848,6 +855,7 @@ SetpointRaiseLower
SetUpPINCode
SetupQRCode
sexualized
shubhamdp
SIGINT
SiLabs
SiliconLabs
Expand Down
5 changes: 5 additions & 0 deletions examples/ota-provider-app/esp32/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*.vscode

/build/
/sdkconfig
/sdkconfig.old
33 changes: 33 additions & 0 deletions examples/ota-provider-app/esp32/CMakeLists.txt
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()
73 changes: 73 additions & 0 deletions examples/ota-provider-app/esp32/README.md
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
shubhamdp marked this conversation as resolved.
Show resolved Hide resolved

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

dhrishi marked this conversation as resolved.
Show resolved Hide resolved
- 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.
193 changes: 193 additions & 0 deletions examples/ota-provider-app/esp32/main/BdxOtaSender.cpp
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.
*/

shubhamdp marked this conversation as resolved.
Show resolved Hide resolved
#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();
}
Loading