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(IoTProfileKVT * kv)23 static cJSON *FormatProfileValue(IoTProfileKVT *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_FLOAT:
34 ret = cJSON_CreateNumber((double)(*(float *)kv->fvalue));
35 break;
36 case EN_IOT_DATATYPE_DOUBLE:
37 ret = cJSON_CreateNumber((*(double *)kv->dvalue));
38 break;
39 case EN_IOT_DATATYPE_STRING:
40 ret = cJSON_CreateString((const char *)kv->value);
41 break;
42 default:
43 break;
44 }
45 return ret;
46 }
47
MakeKvs(IoTProfileKVT * kvlst)48 static cJSON *MakeKvs(IoTProfileKVT *kvlst)
49 {
50 cJSON *root;
51 cJSON *kv;
52 IoTProfileKVT *kvInfo;
53
54 // build a root node
55 root = cJSON_CreateObject();
56 if (root == NULL) {
57 return root;
58 }
59
60 // add all the property to the properties
61 kvInfo = kvlst;
62 while (kvInfo != NULL) {
63 kv = FormatProfileValue(kvInfo);
64 if (kv == NULL) {
65 if (root != NULL) {
66 cJSON_Delete(root);
67 root = NULL;
68 }
69 return root;
70 }
71
72 cJSON_AddItemToObject(root, kvInfo->key, kv);
73 kvInfo = kvInfo->nxt;
74 }
75 // OK, now we return it
76 return root;
77 }
78
79 #define CN_PROFILE_SERVICE_KEY_SERVICEID "service_id"
80 #define CN_PROFILE_SERVICE_KEY_PROPERTIIES "properties"
81 #define CN_PROFILE_SERVICE_KEY_EVENTTIME "event_time"
82 #define CN_PROFILE_KEY_SERVICES "services"
MakeService(IoTProfileServiceT * serviceInfo)83 static cJSON *MakeService(IoTProfileServiceT *serviceInfo)
84 {
85 cJSON *root;
86 cJSON *serviceID;
87 cJSON *properties;
88 cJSON *eventTime;
89
90 // build a root node
91 root = cJSON_CreateObject();
92 if (root == NULL) {
93 return root;
94 }
95
96 // add the serviceID node to the root node
97 serviceID = cJSON_CreateString(serviceInfo->serviceID);
98 if (serviceID == NULL) {
99 if (root != NULL) {
100 cJSON_Delete(root);
101 root = NULL;
102 }
103 return root;
104 }
105 cJSON_AddItemToObjectCS(root, CN_PROFILE_SERVICE_KEY_SERVICEID, serviceID);
106
107 // add the properties node to the root
108 properties = MakeKvs(serviceInfo->serviceProperty);
109 if (properties == NULL) {
110 if (root != NULL) {
111 cJSON_Delete(root);
112 root = NULL;
113 }
114 return root;
115 }
116 cJSON_AddItemToObjectCS(root, CN_PROFILE_SERVICE_KEY_PROPERTIIES, properties);
117 // add the event time (optional) to the root
118 if (serviceInfo->eventTime != NULL) {
119 eventTime = cJSON_CreateString(serviceInfo->eventTime);
120 if (eventTime == NULL) {
121 if (root != NULL) {
122 cJSON_Delete(root);
123 root = NULL;
124 }
125 return root;
126 }
127 cJSON_AddItemToObjectCS(root, CN_PROFILE_SERVICE_KEY_EVENTTIME, eventTime);
128 }
129 // OK, now we return it
130 cJSON_Delete(properties);
131 return root;
132 }
133
MakeServices(IoTProfileServiceT * serviceInfo)134 static cJSON *MakeServices(IoTProfileServiceT *serviceInfo)
135 {
136 cJSON *services = NULL;
137 cJSON *service;
138 IoTProfileServiceT *serviceTmp;
139
140 // create the services array node
141 services = cJSON_CreateArray();
142 if (services == NULL) {
143 return services;
144 }
145
146 serviceTmp = serviceInfo;
147 while (serviceTmp != NULL) {
148 service = MakeService(serviceTmp);
149 if (service == NULL) {
150 return services;
151 }
152 cJSON_AddItemToArray(services, service);
153 serviceTmp = serviceTmp->nxt;
154 }
155
156 // now we return the services
157 return services;
158 }
159
160 // use this function to make a topic to publish
161 // if request_id is needed depends on the fmt
MakeTopic(const char * fmt,const char * deviceId,const char * requestID)162 static char *MakeTopic(const char *fmt, const char *deviceId, const char *requestID)
163 {
164 int len;
165 char *ret = NULL;
166
167 len = strlen(fmt) + strlen(deviceId);
168 if (requestID != NULL) {
169 len += strlen(requestID);
170 }
171 ret = hi_malloc(0, len);
172 if (ret != NULL) {
173 if (requestID != NULL) {
174 (void)snprintf_s(ret, len, len, fmt, deviceId, requestID);
175 } else {
176 (void)snprintf_s(ret, len, len, fmt, deviceId);
177 }
178 }
179 return ret;
180 }
181
182 #define CN_PROFILE_CMDRESP_KEY_RETCODE "result_code"
183 #define CN_PROFILE_CMDRESP_KEY_RESPNAME "response_name"
184 #define CN_PROFILE_CMDRESP_KEY_PARAS "paras"
MakeProfileCmdResp(IoTCmdRespT * payload)185 static char *MakeProfileCmdResp(IoTCmdRespT *payload)
186 {
187 char *ret = NULL;
188 cJSON *root;
189 cJSON *retCode;
190 cJSON *respName;
191 cJSON *paras;
192
193 // create the root node
194 root = cJSON_CreateObject();
195 if (root == NULL) {
196 return ret;
197 }
198
199 // create retcode and retdesc and add it to the root
200 retCode = cJSON_CreateNumber(payload->retCode);
201 if (retCode == NULL) {
202 if (root != NULL) {
203 cJSON_Delete(root);
204 }
205 return ret;
206 }
207 cJSON_AddItemToObjectCS(root, CN_PROFILE_CMDRESP_KEY_RETCODE, retCode);
208
209 if (payload->respName != NULL) {
210 respName = cJSON_CreateString(payload->respName);
211 if (respName == NULL) {
212 if (root != NULL) {
213 cJSON_Delete(root);
214 }
215 return ret;
216 }
217 cJSON_AddItemToObjectCS(root, CN_PROFILE_CMDRESP_KEY_RESPNAME, respName);
218 }
219
220 if (payload->paras != NULL) {
221 paras = MakeKvs(payload->paras);
222 if (paras == NULL) {
223 if (root != NULL) {
224 cJSON_Delete(root);
225 }
226 return ret;
227 }
228 cJSON_AddItemToObjectCS(root, CN_PROFILE_CMDRESP_KEY_PARAS, paras);
229 }
230
231 // OK, now we make it to a buffer
232 ret = cJSON_PrintUnformatted(root);
233 cJSON_Delete(root);
234 return ret;
235 }
236 #define CN_PROFILE_TOPICFMT_CMDRESP "$oc/devices/%s/sys/commands/response/request_id=%s"
IoTProfileCmdResp(const char * deviceID,IoTCmdRespT * payload)237 int IoTProfileCmdResp(const char *deviceID, IoTCmdRespT *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(IoTProfileServiceT * payload)261 static char *MakeProfilePropertyReport(IoTProfileServiceT *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,IoTProfileServiceT * payload)289 int IoTProfilePropertyReport(char *deviceID, IoTProfileServiceT *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 }