1 /*
2 * Copyright (c) 2022 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <string.h>
17 #include <hi_mem.h>
18 #include <cJSON.h>
19 #include "iot_log.h"
20 #include "iot_profile.h"
21
22 // format the report data to json string mode
FormatProfileValue(IoTProfileKV * kv)23 static cJSON *FormatProfileValue(IoTProfileKV *kv)
24 {
25 cJSON *ret = NULL;
26 switch (kv->type) {
27 case EN_IOT_DATATYPE_INT:
28 ret = cJSON_CreateNumber(kv->iValue);
29 break;
30 case EN_IOT_DATATYPE_LONG:
31 ret = cJSON_CreateNumber((double)(*(long *)kv->value));
32 break;
33 case EN_IOT_DATATYPE_STRING:
34 ret = cJSON_CreateString((const char *)kv->value);
35 break;
36 default:
37 break;
38 }
39 return ret;
40 }
41
MakeKvs(IoTProfileKV * kvlst)42 static cJSON *MakeKvs(IoTProfileKV *kvlst)
43 {
44 cJSON *root;
45 cJSON *kv;
46 IoTProfileKV *kvInfo;
47
48 // build a root node
49 root = cJSON_CreateObject();
50 if (root == NULL) {
51 return root;
52 }
53
54 // add all the property to the properties
55 kvInfo = kvlst;
56 while (kvInfo != NULL) {
57 kv = FormatProfileValue(kvInfo);
58 if (kv == NULL) {
59 if (root != NULL) {
60 cJSON_Delete(root);
61 root = NULL;
62 }
63 return root;
64 }
65
66 cJSON_AddItemToObject(root, kvInfo->key, kv);
67 kvInfo = kvInfo->nxt;
68 }
69 // OK, now we return it
70 return root;
71 }
72
73 #define CN_PROFILE_SERVICE_KEY_SERVICEID "service_id"
74 #define CN_PROFILE_SERVICE_KEY_PROPERTIIES "properties"
75 #define CN_PROFILE_SERVICE_KEY_EVENTTIME "event_time"
76 #define CN_PROFILE_KEY_SERVICES "services"
MakeService(IoTProfileService * serviceInfo)77 static cJSON *MakeService(IoTProfileService *serviceInfo)
78 {
79 cJSON *root;
80 cJSON *serviceID;
81 cJSON *properties;
82 cJSON *eventTime;
83
84 // build a root node
85 root = cJSON_CreateObject();
86 if (root == NULL) {
87 return root;
88 }
89
90 // add the serviceID node to the root node
91 serviceID = cJSON_CreateString(serviceInfo->serviceID);
92 if (serviceID == NULL) {
93 if (root != NULL) {
94 cJSON_Delete(root);
95 root = NULL;
96 }
97 return root;
98 }
99 cJSON_AddItemToObjectCS(root, CN_PROFILE_SERVICE_KEY_SERVICEID, serviceID);
100
101 // add the properties node to the root
102 properties = MakeKvs(serviceInfo->serviceProperty);
103 if (properties == NULL) {
104 if (root != NULL) {
105 cJSON_Delete(root);
106 cJSON_Delete(properties);
107 root = NULL;
108 }
109 return root;
110 }
111 cJSON_AddItemToObjectCS(root, CN_PROFILE_SERVICE_KEY_PROPERTIIES, properties);
112 // add the event time (optional) to the root
113 if (serviceInfo->eventTime != NULL) {
114 eventTime = cJSON_CreateString(serviceInfo->eventTime);
115 if (eventTime == NULL) {
116 if (root != NULL) {
117 cJSON_Delete(root);
118 root = NULL;
119 }
120 return root;
121 }
122 cJSON_AddItemToObjectCS(root, CN_PROFILE_SERVICE_KEY_EVENTTIME, eventTime);
123 }
124 // OK, now we return it
125 return root;
126 }
127
MakeServices(IoTProfileService * serviceInfo)128 static cJSON *MakeServices(IoTProfileService *serviceInfo)
129 {
130 cJSON *services = NULL;
131 cJSON *service;
132 IoTProfileService *serviceTmp;
133
134 // create the services array node
135 services = cJSON_CreateArray();
136 if (services == NULL) {
137 return services;
138 }
139
140 serviceTmp = serviceInfo;
141 while (serviceTmp != NULL) {
142 service = MakeService(serviceTmp);
143 if (service == NULL) {
144 return services;
145 }
146 cJSON_AddItemToArray(services, service);
147 serviceTmp = serviceTmp->nxt;
148 }
149
150 // now we return the services
151 return services;
152 }
153
154 // use this function to make a topic to publish
155 // if request_id is needed depends on the fmt
MakeTopic(const char * fmt,const char * deviceId,const char * requestID)156 static char *MakeTopic(const char *fmt, const char *deviceId, const char *requestID)
157 {
158 int len;
159 char *ret = NULL;
160
161 len = strlen(fmt) + strlen(deviceId);
162 if (requestID != NULL) {
163 len += strlen(requestID);
164 }
165
166 ret = hi_malloc(0, len);
167 if (ret != NULL) {
168 if (requestID != NULL) {
169 if (snprintf_s(ret, len + 1, len, fmt, deviceId, requestID) < 0) {
170 printf("string is null\r\n");
171 }
172 } else {
173 if (snprintf_s(ret, len + 1, len, fmt, deviceId) < 0) {
174 printf("string is null\r\n");
175 }
176 }
177 }
178 return ret;
179 }
180
181 #define CN_PROFILE_CMDRESP_KEY_RETCODE "result_code"
182 #define CN_PROFILE_CMDRESP_KEY_RESPNAME "response_name"
183 #define CN_PROFILE_CMDRESP_KEY_PARAS "paras"
MakeProfileCmdResp(IoTCmdResp * payload)184 static char *MakeProfileCmdResp(IoTCmdResp *payload)
185 {
186 char *ret = NULL;
187 cJSON *root;
188 cJSON *retCode;
189 cJSON *respName;
190 cJSON *paras;
191
192 // create the root node
193 root = cJSON_CreateObject();
194 if (root == NULL) {
195 return ret;
196 }
197
198 // create retcode and retdesc and add it to the root
199 retCode = cJSON_CreateNumber(payload->retCode);
200 if (retCode == NULL) {
201 if (root != NULL) {
202 cJSON_Delete(root);
203 }
204 return ret;
205 }
206 cJSON_AddItemToObjectCS(root, CN_PROFILE_CMDRESP_KEY_RETCODE, retCode);
207
208 if (payload->respName != NULL) {
209 respName = cJSON_CreateString(payload->respName);
210 if (respName == NULL) {
211 if (root != NULL) {
212 cJSON_Delete(root);
213 }
214 return ret;
215 }
216 cJSON_AddItemToObjectCS(root, CN_PROFILE_CMDRESP_KEY_RESPNAME, respName);
217 }
218
219 if (payload->paras != NULL) {
220 paras = MakeKvs(payload->paras);
221 if (paras == NULL) {
222 if (root != NULL) {
223 cJSON_Delete(root);
224 }
225 return ret;
226 }
227 cJSON_AddItemToObjectCS(root, CN_PROFILE_CMDRESP_KEY_PARAS, paras);
228 }
229
230 // OK, now we make it to a buffer
231 ret = cJSON_PrintUnformatted(root);
232 cJSON_Delete(root);
233 return ret;
234 }
235
236 #define CN_PROFILE_TOPICFMT_CMDRESP "$oc/devices/%s/sys/commands/response/request_id=%s"
IoTProfileCmdResp(char * deviceID,IoTCmdResp * payload)237 int IoTProfileCmdResp(char *deviceID, IoTCmdResp *payload)
238 {
239 int ret = -1;
240 const char *topic;
241 const char *msg;
242
243 if ((deviceID == NULL) || (payload == NULL) || (payload->requestID == NULL)) {
244 return ret;
245 }
246
247 topic = MakeTopic(CN_PROFILE_TOPICFMT_CMDRESP, deviceID, payload->requestID);
248 if (topic == NULL) {
249 return;
250 }
251 msg = MakeProfileCmdResp(payload);
252 if ((topic != NULL) && (msg != NULL)) {
253 ret = IotSendMsg(0, topic, msg);
254 }
255
256 hi_free(0, topic);
257 cJSON_free(msg);
258 return ret;
259 }
260
MakeProfilePropertyReport(IoTProfileService * payload)261 static char *MakeProfilePropertyReport(IoTProfileService *payload)
262 {
263 char *ret = NULL;
264 cJSON *root;
265 cJSON *services;
266
267 // create the root node
268 root = cJSON_CreateObject();
269 if (root == NULL) {
270 return ret;
271 }
272
273 // create the services array node to the root
274 services = MakeServices(payload);
275 if (services == NULL) {
276 if (root != NULL) {
277 cJSON_Delete(root);
278 }
279 return ret;
280 }
281 cJSON_AddItemToObjectCS(root, CN_PROFILE_KEY_SERVICES, services);
282
283 // OK, now we make it to a buffer
284 ret = cJSON_PrintUnformatted(root);
285 cJSON_Delete(root);
286 return ret;
287 }
288 #define CN_PROFILE_TOPICFMT_PROPERTYREPORT "$oc/devices/%s/sys/properties/report"
IoTProfilePropertyReport(char * deviceID,IoTProfileService * payload)289 int IoTProfilePropertyReport(char *deviceID, IoTProfileService *payload)
290 {
291 int ret = -1;
292 char *topic;
293 char *msg;
294
295 if ((deviceID == NULL) || (payload == NULL) || (payload->serviceID == NULL) || (payload->serviceProperty == NULL)) {
296 return ret;
297 }
298 topic = MakeTopic(CN_PROFILE_TOPICFMT_PROPERTYREPORT, deviceID, NULL);
299 if (topic == NULL) {
300 return;
301 }
302 msg = MakeProfilePropertyReport(payload);
303 if ((topic != NULL) && (msg != NULL)) {
304 ret = IotSendMsg(0, topic, msg);
305 }
306
307 hi_free(0, topic);
308 cJSON_free(msg);
309 return ret;
310 }