/src/connectedhomeip/src/controller/InvokeInteraction.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * |
3 | | * Copyright (c) 2021 Project CHIP Authors |
4 | | * All rights reserved. |
5 | | * |
6 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
7 | | * you may not use this file except in compliance with the License. |
8 | | * You may obtain a copy of the License at |
9 | | * |
10 | | * http://www.apache.org/licenses/LICENSE-2.0 |
11 | | * |
12 | | * Unless required by applicable law or agreed to in writing, software |
13 | | * distributed under the License is distributed on an "AS IS" BASIS, |
14 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
15 | | * See the License for the specific language governing permissions and |
16 | | * limitations under the License. |
17 | | */ |
18 | | |
19 | | #pragma once |
20 | | |
21 | | #include <controller/TypedCommandCallback.h> |
22 | | #include <lib/core/Optional.h> |
23 | | |
24 | | #include <functional> |
25 | | |
26 | | namespace chip { |
27 | | namespace Controller { |
28 | | |
29 | | namespace Internal { |
30 | | // Cancellation functions on InvokeCommandRequest() are for internal use only. |
31 | | typedef std::function<void()> InvokeCancelFn; |
32 | | } // namespace Internal |
33 | | |
34 | | /* |
35 | | * A typed command invocation function that takes as input a cluster-object representation of a command request and |
36 | | * callbacks for success and failure and either returns a decoded cluster-object representation of the response through |
37 | | * the provided success callback or calls the provided failure callback. |
38 | | * |
39 | | * The RequestObjectT is generally expected to be a ClusterName::Commands::CommandName::Type struct, but any object |
40 | | * that can be encoded using the DataModel::Encode machinery and exposes the |
41 | | * GetClusterId() and GetCommandId() functions and a ResponseType type |
42 | | * is expected to work. |
43 | | * |
44 | | * The ResponseType is expected to be one of two things: |
45 | | * |
46 | | * - If a data response is expected on success, a struct type decodable via DataModel::Decode which has GetClusterId() and |
47 | | * GetCommandId() methods. A ClusterName::Commands::ResponseCommandName::DecodableType is typically used. |
48 | | * - If a status response is expected on success, DataModel::NullObjectType. |
49 | | * |
50 | | */ |
51 | | template <typename RequestObjectT> |
52 | | CHIP_ERROR |
53 | | InvokeCommandRequest(Messaging::ExchangeManager * aExchangeMgr, const SessionHandle & sessionHandle, chip::EndpointId endpointId, |
54 | | const RequestObjectT & requestCommandData, |
55 | | typename TypedCommandCallback<typename RequestObjectT::ResponseType>::OnSuccessCallbackType onSuccessCb, |
56 | | typename TypedCommandCallback<typename RequestObjectT::ResponseType>::OnErrorCallbackType onErrorCb, |
57 | | const Optional<uint16_t> & timedInvokeTimeoutMs, |
58 | | const Optional<System::Clock::Timeout> & responseTimeout = NullOptional, |
59 | | Internal::InvokeCancelFn * outCancelFn = nullptr) |
60 | 0 | { |
61 | | // InvokeCommandRequest expects responses, so cannot happen over a group session. |
62 | 0 | VerifyOrReturnError(!sessionHandle->IsGroupSession(), CHIP_ERROR_INVALID_ARGUMENT); |
63 | | |
64 | 0 | app::CommandPathParams commandPath = { endpointId, 0, RequestObjectT::GetClusterId(), RequestObjectT::GetCommandId(), |
65 | 0 | (app::CommandPathFlags::kEndpointIdValid) }; |
66 | | |
67 | | // |
68 | | // Let's create a handle version of the decoder to ensure we do correct clean-up of it if things go south at any point below |
69 | | // |
70 | 0 | auto decoder = chip::Platform::MakeUnique<TypedCommandCallback<typename RequestObjectT::ResponseType>>(onSuccessCb, onErrorCb); |
71 | 0 | VerifyOrReturnError(decoder != nullptr, CHIP_ERROR_NO_MEMORY); |
72 | | |
73 | | // |
74 | | // Upon successful completion of SendCommandRequest below, we're expected to free up the respective allocated objects |
75 | | // in the OnDone callback. |
76 | | // |
77 | 0 | auto onDone = [rawDecoderPtr = decoder.get()](app::CommandSender * commandSender) { |
78 | 0 | chip::Platform::Delete(commandSender); |
79 | 0 | chip::Platform::Delete(rawDecoderPtr); |
80 | 0 | }; Unexecuted instantiation: chip::Controller::InvokeCommandRequest<chip::app::Clusters::OnOff::Commands::On::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OnOff::Commands::On::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OnOff::Commands::On::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OnOff::Commands::On::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*)::{lambda(chip::app::CommandSender*)#1}::operator()(chip::app::CommandSender*) const Unexecuted instantiation: chip::Controller::InvokeCommandRequest<chip::app::Clusters::OnOff::Commands::Off::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OnOff::Commands::Off::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OnOff::Commands::Off::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OnOff::Commands::Off::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*)::{lambda(chip::app::CommandSender*)#1}::operator()(chip::app::CommandSender*) const Unexecuted instantiation: chip::Controller::InvokeCommandRequest<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImage::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImage::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImage::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImage::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*)::{lambda(chip::app::CommandSender*)#1}::operator()(chip::app::CommandSender*) const Unexecuted instantiation: chip::Controller::InvokeCommandRequest<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateRequest::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateRequest::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateRequest::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateRequest::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*)::{lambda(chip::app::CommandSender*)#1}::operator()(chip::app::CommandSender*) const Unexecuted instantiation: chip::Controller::InvokeCommandRequest<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*)::{lambda(chip::app::CommandSender*)#1}::operator()(chip::app::CommandSender*) const |
81 | |
|
82 | 0 | decoder->SetOnDoneCallback(onDone); |
83 | |
|
84 | 0 | auto commandSender = |
85 | 0 | chip::Platform::MakeUnique<app::CommandSender>(decoder.get(), aExchangeMgr, timedInvokeTimeoutMs.HasValue()); |
86 | 0 | VerifyOrReturnError(commandSender != nullptr, CHIP_ERROR_NO_MEMORY); |
87 | | |
88 | 0 | ReturnErrorOnFailure(commandSender->AddRequestData(commandPath, requestCommandData, timedInvokeTimeoutMs)); |
89 | 0 | ReturnErrorOnFailure(commandSender->SendCommandRequest(sessionHandle, responseTimeout)); |
90 | | |
91 | | // If requested by the caller, provide a way to cancel the invoke interaction. |
92 | 0 | if (outCancelFn != nullptr) |
93 | 0 | { |
94 | 0 | *outCancelFn = [rawDecoderPtr = decoder.get(), rawCommandSender = commandSender.get()]() { |
95 | 0 | chip::Platform::Delete(rawCommandSender); |
96 | 0 | chip::Platform::Delete(rawDecoderPtr); |
97 | 0 | }; Unexecuted instantiation: chip::Controller::InvokeCommandRequest<chip::app::Clusters::OnOff::Commands::On::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OnOff::Commands::On::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OnOff::Commands::On::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OnOff::Commands::On::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*)::{lambda()#1}::operator()() const Unexecuted instantiation: chip::Controller::InvokeCommandRequest<chip::app::Clusters::OnOff::Commands::Off::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OnOff::Commands::Off::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OnOff::Commands::Off::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OnOff::Commands::Off::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*)::{lambda()#1}::operator()() const Unexecuted instantiation: chip::Controller::InvokeCommandRequest<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImage::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImage::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImage::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImage::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*)::{lambda()#1}::operator()() const Unexecuted instantiation: chip::Controller::InvokeCommandRequest<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateRequest::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateRequest::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateRequest::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateRequest::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*)::{lambda()#1}::operator()() const Unexecuted instantiation: chip::Controller::InvokeCommandRequest<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*)::{lambda()#1}::operator()() const |
98 | 0 | } |
99 | | |
100 | | // |
101 | | // We've effectively transferred ownership of the above allocated objects to CommandSender, and we need to wait for it to call |
102 | | // us back when processing is completed (through OnDone) to eventually free up resources. |
103 | | // |
104 | | // So signal that by releasing the smart pointer. |
105 | | // |
106 | 0 | decoder.release(); |
107 | 0 | commandSender.release(); |
108 | |
|
109 | 0 | return CHIP_NO_ERROR; |
110 | 0 | } Unexecuted instantiation: chip::ChipError chip::Controller::InvokeCommandRequest<chip::app::Clusters::OnOff::Commands::On::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OnOff::Commands::On::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OnOff::Commands::On::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OnOff::Commands::On::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*) Unexecuted instantiation: chip::ChipError chip::Controller::InvokeCommandRequest<chip::app::Clusters::OnOff::Commands::Off::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OnOff::Commands::Off::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OnOff::Commands::Off::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OnOff::Commands::Off::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*) Unexecuted instantiation: chip::ChipError chip::Controller::InvokeCommandRequest<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImage::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImage::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImage::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImage::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*) Unexecuted instantiation: chip::ChipError chip::Controller::InvokeCommandRequest<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateRequest::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateRequest::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateRequest::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateRequest::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*) Unexecuted instantiation: chip::ChipError chip::Controller::InvokeCommandRequest<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*) |
111 | | |
112 | | /* |
113 | | * A typed group command invocation function that takes as input a cluster-object representation of a command request. |
114 | | * |
115 | | * The RequestObjectT is generally expected to be a ClusterName::Commands::CommandName::Type struct, but any object |
116 | | * that can be encoded using the DataModel::Encode machinery and exposes the GetClusterId() and GetCommandId() functions |
117 | | * and a ResponseType type is expected to work. |
118 | | * |
119 | | * Since this sends a group command, no response will be received and all allocated resources will be cleared before exiting this |
120 | | * function |
121 | | */ |
122 | | template <typename RequestObjectT> |
123 | | CHIP_ERROR InvokeGroupCommandRequest(Messaging::ExchangeManager * exchangeMgr, chip::FabricIndex fabric, chip::GroupId groupId, |
124 | | const RequestObjectT & requestCommandData) |
125 | | { |
126 | | app::CommandPathParams commandPath = { groupId, RequestObjectT::GetClusterId(), RequestObjectT::GetCommandId(), |
127 | | app::CommandPathFlags::kGroupIdValid }; |
128 | | Transport::OutgoingGroupSession session(groupId, fabric); |
129 | | |
130 | | auto commandSender = chip::Platform::MakeUnique<app::CommandSender>(nullptr, exchangeMgr); |
131 | | VerifyOrReturnError(commandSender != nullptr, CHIP_ERROR_NO_MEMORY); |
132 | | |
133 | | ReturnErrorOnFailure(commandSender->AddRequestData(commandPath, requestCommandData)); |
134 | | return commandSender->SendGroupCommandRequest(SessionHandle(session)); |
135 | | } |
136 | | |
137 | | template <typename RequestObjectT> |
138 | | CHIP_ERROR |
139 | | InvokeCommandRequest(Messaging::ExchangeManager * exchangeMgr, const SessionHandle & sessionHandle, chip::EndpointId endpointId, |
140 | | const RequestObjectT & requestCommandData, |
141 | | typename TypedCommandCallback<typename RequestObjectT::ResponseType>::OnSuccessCallbackType onSuccessCb, |
142 | | typename TypedCommandCallback<typename RequestObjectT::ResponseType>::OnErrorCallbackType onErrorCb, |
143 | | uint16_t timedInvokeTimeoutMs, const Optional<System::Clock::Timeout> & responseTimeout = NullOptional) |
144 | | { |
145 | | return InvokeCommandRequest(exchangeMgr, sessionHandle, endpointId, requestCommandData, onSuccessCb, onErrorCb, |
146 | | MakeOptional(timedInvokeTimeoutMs), responseTimeout); |
147 | | } |
148 | | |
149 | | template <typename RequestObjectT, typename std::enable_if_t<!RequestObjectT::MustUseTimedInvoke(), int> = 0> |
150 | | CHIP_ERROR |
151 | | InvokeCommandRequest(Messaging::ExchangeManager * exchangeMgr, const SessionHandle & sessionHandle, chip::EndpointId endpointId, |
152 | | const RequestObjectT & requestCommandData, |
153 | | typename TypedCommandCallback<typename RequestObjectT::ResponseType>::OnSuccessCallbackType onSuccessCb, |
154 | | typename TypedCommandCallback<typename RequestObjectT::ResponseType>::OnErrorCallbackType onErrorCb, |
155 | | const Optional<System::Clock::Timeout> & responseTimeout = NullOptional) |
156 | 0 | { |
157 | 0 | return InvokeCommandRequest(exchangeMgr, sessionHandle, endpointId, requestCommandData, onSuccessCb, onErrorCb, NullOptional, |
158 | 0 | responseTimeout); |
159 | 0 | } Unexecuted instantiation: _ZN4chip10Controller20InvokeCommandRequestINS_3app8Clusters5OnOff8Commands2On4TypeETnNSt3__19enable_ifIXntclsrT_18MustUseTimedInvokeEEiE4typeELi0EEENS_9ChipErrorEPNS_9Messaging15ExchangeManagerERKNS_13SessionHandleEtRKSA_NS0_20TypedCommandCallbackINSA_12ResponseTypeEE21OnSuccessCallbackTypeENSO_19OnErrorCallbackTypeERKNS_8OptionalINS8_6chrono8durationIjNS8_5ratioILl1ELl1000EEEEEEE Unexecuted instantiation: _ZN4chip10Controller20InvokeCommandRequestINS_3app8Clusters5OnOff8Commands3Off4TypeETnNSt3__19enable_ifIXntclsrT_18MustUseTimedInvokeEEiE4typeELi0EEENS_9ChipErrorEPNS_9Messaging15ExchangeManagerERKNS_13SessionHandleEtRKSA_NS0_20TypedCommandCallbackINSA_12ResponseTypeEE21OnSuccessCallbackTypeENSO_19OnErrorCallbackTypeERKNS_8OptionalINS8_6chrono8durationIjNS8_5ratioILl1ELl1000EEEEEEE |
160 | | |
161 | | } // namespace Controller |
162 | | } // namespace chip |