1 /******************************************************************************
2  *
3  *  Copyright 2020, 2022-2023 NXP
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *  http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  ******************************************************************************/
18 
19 #define LOG_TAG "weaver-impl"
20 #include <weaver-impl.h>
21 #include <weaver_parser-impl.h>
22 #include <weaver_transport-impl.h>
23 #include <weaver_utils.h>
24 
25 WeaverImpl *WeaverImpl::s_instance = NULL;
26 std::once_flag WeaverImpl::s_instanceFlag;
27 
28 /**
29  * \brief static function to get the singleton instance of WeaverImpl class
30  *
31  * \retval instance of WeaverImpl.
32  */
getInstance()33 WeaverImpl *WeaverImpl::getInstance() {
34   /* call_once c++11 api which executes the passed function ptr exactly once,
35    * even if called concurrently, from several threads
36    */
37   std::call_once(s_instanceFlag, &WeaverImpl::createInstance);
38   return s_instance;
39 }
40 
41 /* Private function to create the instance of self class
42  * Same will be used for std::call_once
43  */
createInstance()44 void WeaverImpl::createInstance() {
45   LOG_D(TAG, "Entry");
46   s_instance = new WeaverImpl;
47 }
48 
49 /**
50  * \brief Function to initialize Weaver Interface
51  *
52  * \retval This function return Weaver_STATUS_OK (0) in case of success
53  *         In case of failure returns other Status_Weaver.
54  */
Init()55 Status_Weaver WeaverImpl::Init() {
56   LOG_D(TAG, "Entry");
57   mTransport = WeaverTransportImpl::getInstance();
58   mParser = WeaverParserImpl::getInstance();
59   RETURN_IF_NULL(mTransport, WEAVER_STATUS_FAILED, "Transport is NULL");
60   RETURN_IF_NULL(mParser, WEAVER_STATUS_FAILED, "Parser is NULL");
61   std::vector<std::vector<uint8_t>> aid;
62   mParser->getAppletId(aid);
63   if (!mTransport->Init(std::move(aid))) {
64     LOG_E(TAG, "Not able to Initialize Transport Interface");
65     LOG_D(TAG, "Exit : FAILED");
66     return WEAVER_STATUS_FAILED;
67   }
68   LOG_D(TAG, "Exit : SUCCESS");
69   return WEAVER_STATUS_OK;
70 }
71 
72 /**
73  * \brief Function to read slot information
74  * \param[out]   slotInfo - slot information values read out
75  *
76  * \retval This function return Weaver_STATUS_OK (0) in case of success
77  *         In case of failure returns other Status_Weaver errorcodes.
78  */
GetSlots(SlotInfo & slotInfo)79 Status_Weaver WeaverImpl::GetSlots(SlotInfo &slotInfo) {
80   LOG_D(TAG, "Entry");
81   RETURN_IF_NULL(mTransport, WEAVER_STATUS_FAILED, "Transport is NULL");
82   RETURN_IF_NULL(mParser, WEAVER_STATUS_FAILED, "Parser is NULL");
83   Status_Weaver status = WEAVER_STATUS_FAILED;
84   std::vector<uint8_t> getSlotCmd;
85   std::vector<uint8_t> resp;
86   /* transport library don't require open applet
87    * open will be done as part of send */
88   if (mParser->FrameGetSlotCmd(getSlotCmd) &&
89       mTransport->Send(getSlotCmd, resp)) {
90     status = WEAVER_STATUS_OK;
91   } else {
92     LOG_E(TAG, "Failed to perform getSlot Request");
93   }
94 #ifndef INTERVAL_TIMER
95   if (!close()) {
96     // Channel Close Failed
97     LOG_E(TAG, "Failed to Close Channel");
98   }
99 #endif
100   if (status == WEAVER_STATUS_OK) {
101     status = mParser->ParseSlotInfo(std::move(resp), slotInfo);
102     LOG_D(TAG, "Total Slots (%u) ", slotInfo.slots);
103   } else {
104     LOG_E(TAG, "Failed Parsing getSlot Response");
105   }
106   LOG_D(TAG, "Exit");
107   return status;
108 }
109 
110 /* Internal close api for transport close */
close()111 bool WeaverImpl::close() {
112   LOG_D(TAG, "Entry");
113   bool status = true;
114   RETURN_IF_NULL(mTransport, WEAVER_STATUS_FAILED, "Transport is NULL");
115   if (!mTransport->CloseApplet()) {
116     status = false;
117   }
118   LOG_D(TAG, "Exit");
119   return status;
120 }
121 
122 /**
123  * \brief Function to read value of specific key & slotId
124  * \param[in]    slotId -       input slotId which's information to be read
125  * \param[in]    key -          input key which's information to be read
126  * \param[out]   readRespInfo - read information values to be read out
127  *
128  * \retval This function return Weaver_STATUS_OK (0) in case of success
129  *         In case of failure returns other Status_Weaver errorcodes.
130  */
Read(uint32_t slotId,const std::vector<uint8_t> & key,ReadRespInfo & readRespInfo)131 Status_Weaver WeaverImpl::Read(uint32_t slotId, const std::vector<uint8_t> &key,
132                                ReadRespInfo &readRespInfo) {
133   LOG_D(TAG, "Entry");
134   RETURN_IF_NULL(mTransport, WEAVER_STATUS_FAILED, "Transport is NULL");
135   RETURN_IF_NULL(mParser, WEAVER_STATUS_FAILED, "Parser is NULL");
136   Status_Weaver status = WEAVER_STATUS_FAILED;
137   std::vector<uint8_t> cmd;
138   std::vector<uint8_t> resp;
139   std::vector<uint8_t> aid;
140   /* transport library don't require open applet
141    * open will be done as part of send */
142   LOG_D(TAG, "Read from Slot (%u)", slotId);
143   if (mParser->FrameReadCmd(slotId, key, cmd) &&
144       mTransport->Send(cmd, resp)) {
145     status = WEAVER_STATUS_OK;
146   }
147   if (status == WEAVER_STATUS_OK) {
148     status = mParser->ParseReadInfo(resp, readRespInfo);
149     if (status == WEAVER_STATUS_THROTTLE ||
150         status == WEAVER_STATUS_INCORRECT_KEY) {
151       cmd.clear();
152       resp.clear();
153       if (mParser->FrameGetDataCmd(WeaverParserImpl::sThrottleGetDataP1, (uint8_t)slotId, cmd) &&
154           (mTransport->Send(cmd, resp))) {
155         GetDataRespInfo getDataInfo;
156         if (mParser->ParseGetDataInfo(std::move(resp), getDataInfo) == WEAVER_STATUS_OK) {
157           /* convert timeout from getDataInfo sec to millisecond assign same to read response */
158           readRespInfo.timeout = (getDataInfo.timeout * 1000);
159           if (getDataInfo.timeout > 0) {
160             status = WEAVER_STATUS_THROTTLE;
161           }
162         }
163       }
164     }
165   } else {
166     LOG_E(TAG, "Failed to perform Read Request for slot (%u)", slotId);
167   }
168 #ifndef INTERVAL_TIMER
169   if (!close()) {
170     // Channel Close Failed
171     LOG_E(TAG, "Failed to Close Channel");
172   }
173 #endif
174   LOG_D(TAG, "Exit");
175   return status;
176 }
177 
178 /**
179  * \brief Function to write value to specific key & slotId
180  * \param[in]    slotId -       input slotId where value to be write
181  * \param[in]    key -          input key where value to be write
182  * \param[in]   value -        input value which will be written
183  *
184  * \retval This function return Weaver_STATUS_OK (0) in case of success
185  *         In case of failure returns other Status_Weaver.
186  */
Write(uint32_t slotId,const std::vector<uint8_t> & key,const std::vector<uint8_t> & value)187 Status_Weaver WeaverImpl::Write(uint32_t slotId,
188                                 const std::vector<uint8_t> &key,
189                                 const std::vector<uint8_t> &value) {
190   LOG_D(TAG, "Entry");
191   RETURN_IF_NULL(mTransport, WEAVER_STATUS_FAILED, "Transport is NULL");
192   RETURN_IF_NULL(mParser, WEAVER_STATUS_FAILED, "Parser is NULL");
193   Status_Weaver status = WEAVER_STATUS_FAILED;
194   std::vector<uint8_t> readCmd;
195   std::vector<uint8_t> resp;
196   std::vector<uint8_t> aid;
197   /* transport library don't require open applet
198    * open will be done as part of send */
199   LOG_D(TAG, "Write to Slot (%u)", slotId);
200   if (mParser->FrameWriteCmd(slotId, key, value, readCmd) &&
201       mTransport->Send(readCmd, resp)) {
202     status = WEAVER_STATUS_OK;
203   }
204 #ifndef INTERVAL_TIMER
205   if (!close()) {
206     LOG_E(TAG, "Failed to Close Channel");
207     // Channel Close Failed
208   }
209 #endif
210   if (status != WEAVER_STATUS_OK || (!mParser->isSuccess(std::move(resp)))) {
211     status = WEAVER_STATUS_FAILED;
212   }
213   LOG_D(TAG, "Exit");
214   return status;
215 }
216 
217 /**
218  * \brief Function to de-initialize Weaver Interface
219  *
220  * \retval This function return Weaver_STATUS_OK (0) in case of success
221  *         In case of failure returns other Status_Weaver.
222  */
DeInit()223 Status_Weaver WeaverImpl::DeInit() {
224   LOG_D(TAG, "Entry");
225   if (mTransport != NULL) {
226     mTransport->DeInit();
227   }
228   LOG_D(TAG, "Exit");
229   return WEAVER_STATUS_OK;
230 }
231