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 
145     // Add public/private methods or member variables
146 };
147 
148 static OT_DEFINE_ALIGNED_VAR(sNcpVendorRaw, sizeof(NcpVendorUart), uint64_t);
149 
otAppNcpInit(otInstance * aInstance)150 extern "C" void otAppNcpInit(otInstance *aInstance)
151 {
152     NcpVendorUart *ncpVendor = nullptr;
153     ot::Instance  *instance  = static_cast<ot::Instance *>(aInstance);
154 
155     ncpVendor = new (&sNcpVendorRaw) NcpVendorUart(instance);
156 
157     if (ncpVendor == nullptr || ncpVendor != ot::Ncp::NcpBase::GetNcpInstance())
158     {
159         // assert(false);
160     }
161 }
162 
163 #endif // #if OPENTHREAD_ENABLE_NCP_VENDOR_HOOK
164