1 /*
2 * Copyright (c) 2016-2017, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 /**
29 * @file
30 * This file shows how to implement the NCP vendor hook.
31 */
32
33 #if OPENTHREAD_ENABLE_NCP_VENDOR_HOOK
34
35 #include "ncp_base.hpp"
36
37 namespace ot {
38 namespace Ncp {
39
VendorCommandHandler(uint8_t aHeader,unsigned int aCommand)40 otError NcpBase::VendorCommandHandler(uint8_t aHeader, unsigned int aCommand)
41 {
42 otError error = OT_ERROR_NONE;
43
44 switch (aCommand)
45 {
46 // TODO: Implement your command handlers here.
47
48 default:
49 error = PrepareLastStatusResponse(aHeader, SPINEL_STATUS_INVALID_COMMAND);
50 }
51
52 return error;
53 }
54
VendorHandleFrameRemovedFromNcpBuffer(Spinel::Buffer::FrameTag aFrameTag)55 void NcpBase::VendorHandleFrameRemovedFromNcpBuffer(Spinel::Buffer::FrameTag aFrameTag)
56 {
57 // This method is a callback which mirrors `NcpBase::HandleFrameRemovedFromNcpBuffer()`.
58 // It is called when a spinel frame is sent and removed from NCP buffer.
59 //
60 // (a) This can be used to track and verify that a vendor spinel frame response is
61 // delivered to the host (tracking the frame using its tag).
62 //
63 // (b) It indicates that NCP buffer space is now available (since a spinel frame is
64 // removed). This can be used to implement reliability mechanisms to re-send
65 // a failed spinel command response (or an async spinel frame) transmission
66 // (failed earlier due to NCP buffer being full).
67
68 OT_UNUSED_VARIABLE(aFrameTag);
69 }
70
VendorGetPropertyHandler(spinel_prop_key_t aPropKey)71 otError NcpBase::VendorGetPropertyHandler(spinel_prop_key_t aPropKey)
72 {
73 otError error = OT_ERROR_NONE;
74
75 switch (aPropKey)
76 {
77 // TODO: Implement your property get handlers here.
78 //
79 // Get handler should retrieve the property value and then encode and write the
80 // value into the NCP buffer. If the "get" operation itself fails, handler should
81 // write a `LAST_STATUS` with the error status into the NCP buffer. `OT_ERROR_NO_BUFS`
82 // should be returned if NCP buffer is full and response cannot be written.
83
84 default:
85 error = OT_ERROR_NOT_FOUND;
86 break;
87 }
88
89 return error;
90 }
91
VendorSetPropertyHandler(spinel_prop_key_t aPropKey)92 otError NcpBase::VendorSetPropertyHandler(spinel_prop_key_t aPropKey)
93 {
94 otError error = OT_ERROR_NONE;
95
96 switch (aPropKey)
97 {
98 // TODO: Implement your property set handlers here.
99 //
100 // Set handler should first decode the value from the input Spinel frame and then
101 // perform the corresponding set operation. The handler should not prepare the
102 // spinel response and therefore should not write anything to the NCP buffer.
103 // The error returned from handler (other than `OT_ERROR_NOT_FOUND`) indicates the
104 // error in either parsing of the input or the error of the set operation. In case
105 // of a successful "set", `NcpBase` set command handler will invoke the
106 // `VendorGetPropertyHandler()` for the same property key to prepare the response.
107
108 default:
109 error = OT_ERROR_NOT_FOUND;
110 break;
111 }
112
113 return error;
114 }
115
116 } // namespace Ncp
117 } // namespace ot
118
119 //-------------------------------------------------------------------------------------------------------------------
120 // When OPENTHREAD_ENABLE_NCP_VENDOR_HOOK is enabled, vendor code is
121 // expected to provide the `otAppNcpInit()` function. The reason behind
122 // this is to enable vendor code to define its own sub-class of
123 // `NcpBase` or `NcpHdlc`/`NcpSpi`.
124 //
125 // Example below show how to add a vendor sub-class over `NcpHdlc`.
126
127 #include "ncp_hdlc.hpp"
128 #include "common/new.hpp"
129
130 class NcpVendorUart : public ot::Ncp::NcpHdlc
131 {
SendHdlc(const uint8_t * aBuf,uint16_t aBufLength)132 static int SendHdlc(const uint8_t *aBuf, uint16_t aBufLength)
133 {
134 OT_UNUSED_VARIABLE(aBuf);
135 OT_UNUSED_VARIABLE(aBufLength);
136 return 0;
137 }
138
139 public:
NcpVendorUart(ot::Instance * aInstance)140 NcpVendorUart(ot::Instance *aInstance)
141 : ot::Ncp::NcpHdlc(aInstance, &NcpVendorUart::SendHdlc)
142 {
143 }
144 #if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE && OPENTHREAD_RADIO
NcpVendorUart(ot::Instance ** aInstances,uint8_t count)145 NcpVendorUart(ot::Instance **aInstances, uint8_t count)
146 : ot::Ncp::NcpHdlc(aInstances, count, &NcpVendorUart::SendHdlc)
147 {
148 }
149 #endif // OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE && OPENTHREAD_RADIO
150
151 // Add public/private methods or member variables
152 };
153
154 static OT_DEFINE_ALIGNED_VAR(sNcpVendorRaw, sizeof(NcpVendorUart), uint64_t);
155
otAppNcpInit(otInstance * aInstance)156 extern "C" void otAppNcpInit(otInstance *aInstance)
157 {
158 NcpVendorUart *ncpVendor = nullptr;
159 ot::Instance *instance = static_cast<ot::Instance *>(aInstance);
160
161 ncpVendor = new (&sNcpVendorRaw) NcpVendorUart(instance);
162
163 if (ncpVendor == nullptr || ncpVendor != ot::Ncp::NcpBase::GetNcpInstance())
164 {
165 // assert(false);
166 }
167 }
168 #if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE && OPENTHREAD_RADIO
otAppNcpInitMulti(otInstance ** aInstances,uint8_t count)169 extern "C" void otAppNcpInitMulti(otInstance **aInstances, uint8_t count)
170 {
171 NcpVendorUart *ncpVendor = nullptr;
172 ot::Instance *instances[SPINEL_HEADER_IID_MAX];
173
174 OT_ASSERT(count < SPINEL_HEADER_IID_MAX);
175 OT_ASSERT(count > 0);
176 OT_ASSERT(aInstances[0] != nullptr);
177
178 for (int i = 0; i < count; i++)
179 {
180 instances[i] = static_cast<ot::Instance *>(aInstances[i]);
181 }
182
183 ncpVendor = new (&sNcpVendorRaw) NcpVendorUart(instances, count);
184
185 if (ncpVendor == nullptr || ncpVendor != ot::Ncp::NcpBase::GetNcpInstance())
186 {
187 OT_ASSERT(false);
188 }
189 }
190 #endif // OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE && OPENTHREAD_RADIO
191
192 #endif // #if OPENTHREAD_ENABLE_NCP_VENDOR_HOOK
193