Imported Upstream version 1.1.0
[platform/upstream/iotivity.git] / plugins / zigbee_wrapper / telegesis_wrapper / src / telegesis_wrapper.c
1 //******************************************************************
2 //
3 // Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21
22 #include <stdio.h>
23 #include <fcntl.h>
24 #include <stdlib.h>
25 #include <inttypes.h>
26
27 #include <unistd.h>
28 #include <sys/stat.h>
29
30 #include <termios.h>
31 #include <string.h>
32 #include <errno.h>
33
34 #include "oic_string.h"
35 #include "oic_malloc.h"
36 #include "logger.h"
37
38 #include "twtypes.h"
39 #include "telegesis_socket.h"
40 #include "telegesis_wrapper.h"
41 #include "twsocketlist.h"
42
43
44 #define TAG PCF("telegesiswrapper")     // Module Name
45
46 #define ARRAY_LENGTH    100
47
48 #define RESPONSE_PARAMS_COUNT_NETWORK_INFO_1                (1)
49 #define RESPONSE_PARAMS_COUNT_NETWORK_INFO_5                (5)
50 #define RESPONSE_PARAMS_COUNT_JPAN                          (3)
51 #define RESPONSE_PARAMS_COUNT_DEVICE_JOINED                 (2)
52 #define RESPONSE_PARAMS_COUNT_MATCH_DESC                    (3)
53 #define RESPONSE_PARAMS_COUNT_SIMPLE_DESC                   (2)
54 #define RESPONSE_PARAMS_COUNT_SIMPLE_DESC_IN_CLUSTER_MIN    (1)
55 #define RESPONSE_PARAMS_COUNT_WRITE_ATTR_4                  (4)
56 #define RESPONSE_PARAMS_COUNT_WRITE_ATTR_5                  (5)
57 #define RESPONSE_PARAMS_COUNT_TEMPERATURE                   (5)
58 #define RESPONSE_PARAMS_COUNT_RESPATTR                      (6)
59 #define RESPONSE_PARAMS_COUNT_ADDRESS_RESPONSE              (3)
60 #define RESPONSE_PARAMS_COUNT_DFTREP                        (5)
61 #define RESPONSE_PARAMS_COUNT_DRLOCKUNLOCKRSP               (3)
62 #define RESPONSE_PARAMS_COUNT_ZENROLLREQ                    (4)
63 #define RESPONSE_PARAMS_COUNT_ENROLLED                      (3)
64 #define RESPONSE_PARAMS_COUNT_ZONESTATUS_4                  (4)
65 #define RESPONSE_PARAMS_COUNT_ZONESTATUS_6                  (6)
66
67 #define IN_CLUSTER_COUNT_STRING    "05"
68 #define OUT_CLUSTER_COUNT_STRING   "00"
69
70 #define TOKEN_ADDRRESP_STATUS_CODE                  (0)
71 #define TOKEN_ADDRRESP_NODEID                       (1)
72 #define TOKEN_ADDRRESP_EUI                          (2)
73
74 #define TOKEN_PLUS_N_DEVICE_TYPE                    (0)
75 #define TOKEN_PLUS_N_PANID                          (3)
76 #define TOKEN_PLUS_N_PANID_EXTENDED                 (4)
77
78 #define TOKEN_JPAN_PANID                            (1)
79 #define TOKEN_JPAN_PANID_EXTENDED                   (2)
80
81 #define TOKEN_PJOIN_RESPONSE_IEEE_ADDRESS           (0)
82 #define TOKEN_PJOIN_RESPONSE_NODEID                 (1)
83
84 #define TOKEN_MATCHDESC_NODEID                      (0)
85 #define TOKEN_MATCHDESC_STATUS_CODE                 (1)
86 #define TOKEN_MATCHDESC_ENDPOINTID                  (2)
87
88 #define TOKEN_SIMPLEDESC_SIMPLEDESC_NODEID          (0)
89 #define TOKEN_SIMPLEDESC_SIMPLEDESC_STATUS_CODE     (1)
90 #define TOKEN_SIMPLEDESC_INCLUSTER_STRING           (0)
91
92 #define TOKEN_WRITEATTR_STATUS_CODE                 (3)
93 #define TOKEN_WRITEATTR_STATUS_CODE_ALTERNATIVE     (4)
94
95 #define TOKEN_TEMPERATURE_STATUS_CODE               (3)
96 #define TOKEN_TEMPERATURE_VALUE                     (4)
97
98 #define TOKEN_RESPATTR_STATUS_CODE                  (4)
99 #define TOKEN_RESPATTR_ATTRIBUTE_VALUE              (5)
100
101 #define TOKEN_DFTREP_NODEID                         (0)
102 #define TOKEN_DFTREP_ENDPOINTID                     (1)
103 #define TOKEN_DFTREP_CLUSTERID                      (2)
104 #define TOKEN_DFTREP_COMMANDID                      (3)
105 #define TOKEN_DFTREP_STATUS_CODE                    (4)
106
107 #define TOKEN_DRLOCKRSP_NODEID                      (0)
108 #define TOKEN_DRLOCKRSP_ENDPOINTID                  (1)
109 #define TOKEN_DRLOCKRSP_STATUS_CODE                 (2)
110
111 #define TOKEN_ZENROLLREQ_NODEID                     (0)
112 #define TOKEN_ZENROLLREQ_ENDPOINTID                 (1)
113 #define TOKEN_ZENROLLREQ_ZONETYPE                   (2)
114 #define TOKEN_ZENROLLREQ_MANUFACTURE_CODE           (3)
115 #define TOKEN_ENROLLED_ZONEID                       (0)
116 #define TOKEN_ENROLLED_ZONETYPE                     (1)
117 #define TOKEN_ENROLLED_EUI                          (2)
118
119 #define TOKEN_ZONESTATUS_NODEID                     (0)
120 #define TOKEN_ZONESTATUS_ENDPOINTID                 (1)
121 #define TOKEN_ZONESTATUS_ZONESTATUS                 (2)
122 #define TOKEN_ZONESTATUS_ZONESTATUS_EXTENDED        (3)
123 #define TOKEN_ZONESTATUS_ZONEID                     (4)
124 #define TOKEN_ZONESTATUS_DELAY                      (5)
125
126
127 typedef struct TWContext{
128     PIPlugin_Zigbee* g_plugin;
129     const char* g_port;
130
131     char g_LocalEUI[SIZE_EUI];
132     char g_WIPRemoteEUI[SIZE_EUI];
133     char g_WIPRemoteNodeId[SIZE_NODEID];
134
135     TWStatus g_ZigBeeStatus;
136     TWDeviceList* g_FoundMatchedDeviceList;
137     TWDevice* g_WIPDevice;
138
139     TWDeviceFoundCallback g_DeviceFoundCallback;
140     TWEnrollmentSucceedCallback g_EnrollmentSucceedCallback;
141     TWDeviceStatusUpdateCallback g_DeviceStatusUpdateCallback;
142     TWDeviceNodeIdChangedCallback g_EndDeviceNodeIdChangedCallback;
143
144     struct TWContext* next;
145 } TWContext;
146
147 typedef TWResultCode (*TWATResultHandler)(int count, char** tokens, TWContext* ctx);
148
149 typedef struct
150 {
151     const char *resultTxt;
152     TWATResultHandler handler;
153 } TWATResultHandlerPair;
154
155
156 //-----------------------------------------------------------------------------
157 // Private internal function prototypes
158 //-----------------------------------------------------------------------------
159
160 static TWResultCode HandleATResponse(TWEntry* entry, TWContext* ctx);
161
162 static TWResultCode processEntry(TWEntry* entry, TWContext* ctx);
163 static TWResultCode processEntryNETWORK_INFO(TWEntry* entry, TWContext* ctx);
164 static TWResultCode processEntryJPAN(TWEntry* entry, TWContext* ctx);
165 static TWResultCode processEntryEndDevice(TWEntry* entry, TWContext* ctx);
166 static TWResultCode processEntryMatchDesc(TWEntry* entry, TWContext* ctx);
167 static TWResultCode processEntrySimpleDesc(TWEntry* entry, TWContext* ctx);
168 static TWResultCode processEntryWriteAttr(TWEntry* entry, TWContext* ctx);
169 static TWResultCode processEntryReadAttr(TWEntry* entry, TWContext* ctx);
170 static TWResultCode processEntryTemperature(TWEntry* entry, TWContext* ctx);
171 static TWResultCode processEntrySwitchDoorLockState(TWEntry* entry, TWContext* ctx);
172 static TWResultCode processEntryZCLDefaultResponse(TWEntry* entry, TWContext* ctx);
173 static TWResultCode processEntryZoneEnrollRequest(TWEntry* entry, TWContext* ctx);
174 static TWResultCode processEntryEnrolled(TWEntry* entry, TWContext* ctx);
175 static TWResultCode processEntryZoneStatus(TWEntry* entry, TWContext* ctx);
176 static TWResultCode processEntryAddressResponse(TWEntry* entry, TWContext* ctx);
177
178 static TWResultCode Reset(TWContext* ctx);
179 static TWResultCode GetRemoteEUI(char *nodeId, char* outRemoteEUI, TWContext* ctx);
180 static TWResultCode CreatePAN(TWContext* ctx);
181 static TWResultCode EnableJoin(bool isKeyEncrypted, TWContext* ctx);
182 static TWResultCode FindMatchNodes(TWContext* ctx);
183 static TWResultCode FindClusters(char nodeId[], char endpoint[], TWContext* ctx);
184
185 static TWResultCode TelNetworkInfoHandler(int count, char* tokens[], TWContext* ctx);
186 static TWResultCode TelJpanHandler(int count, char* tokens[], TWContext* ctx);
187 static TWResultCode TelEndDeviceJoinHandler(int count, char* tokens[], TWContext* ctx);
188 static TWResultCode TelMatchDescHandler(int count, char* tokens[], TWContext* ctx);
189 static TWResultCode TelAddressResponseHandler(int count, char* tokens[], TWContext* ctx);
190 static TWResultCode TelSimpleDescHandler(int count, char* tokens[], TWContext* ctx);
191 static TWResultCode TelSimpleDescInClusterHandler(int count, char* tokens[], TWContext* ctx);
192 static TWResultCode TelWriteAttrHandler(int count, char* tokens[], TWContext* ctx);
193 static TWResultCode TelReadAttrHandler(int count, char* tokens[], TWContext* ctx);
194 static TWResultCode TelReadAttrHandlerTemperature(int count, char* tokens[], TWContext* ctx);
195 static TWResultCode TelZCLDefaultResponseHandler(int count, char* tokens[], TWContext* ctx);
196 static TWResultCode TelSwitchDoorLockStateHandler(int count, char* tokens[], TWContext* ctx);
197 static TWResultCode TelZoneEnrollRequestHandler(int count, char* tokens[], TWContext* ctx);
198 static TWResultCode TelEnrolledHandler(int count, char* tokens[], TWContext* ctx);
199 static TWResultCode TelZoneStatusHandler(int count, char* tokens[], TWContext* ctx);
200
201 static TWResultCode AsciiHexToValue(char* hexString, int length, uint64_t* value);
202 static int AsciiToHex(char c);
203 static int Tokenize(const char *input, const char* delimiters, char* output[]);
204
205 static void DeallocateTWDeviceList(TWContext* ctx);
206 static TWContext* GetTWContext(PIPlugin_Zigbee * plugin);
207
208 //-----------------------------------------------------------------------------
209 // Private variables
210 //-----------------------------------------------------------------------------
211
212 static TWATResultHandlerPair g_TWATResultHandlerPairArray[] =
213 {
214     {"+N=",         TelNetworkInfoHandler},
215     {"JPAN:",       TelJpanHandler},
216     {"RFD:",        TelEndDeviceJoinHandler},       //e.g SmartThings Open/Closed Sensor
217     {"FFD:",        TelEndDeviceJoinHandler},       //e.g SmartThings Plug
218     {"SED:",        TelEndDeviceJoinHandler},
219     {"ZED:",        TelEndDeviceJoinHandler},
220     {"MatchDesc:",  TelMatchDescHandler},
221     {"SimpleDesc:", TelSimpleDescHandler},
222     {"InCluster:",  TelSimpleDescInClusterHandler},
223     {"WRITEATTR:",  TelWriteAttrHandler},
224     {"RESPATTR:",   TelReadAttrHandler},
225     {"TEMPERATURE:",TelReadAttrHandlerTemperature},
226     {"DFTREP",      TelZCLDefaultResponseHandler},
227     {"DRLOCRSP:",   TelSwitchDoorLockStateHandler},
228     {"DRUNLOCKRSP:",TelSwitchDoorLockStateHandler},
229     {"ZENROLLREQ:", TelZoneEnrollRequestHandler},
230     {"ENROLLED:",   TelEnrolledHandler},
231     {"ZONESTATUS:", TelZoneStatusHandler},
232     {"AddrResp:",   TelAddressResponseHandler},
233     {"Unknown:",    TelNetworkInfoHandler}
234 };
235
236 static TWContext* g_twContextList = NULL;
237
238 void InitializeContext(TWContext* context)
239 {
240     context->g_port = NULL;
241     memset(context->g_LocalEUI, '\0', sizeof(context->g_LocalEUI));
242     memset(context->g_WIPRemoteEUI, '\0', sizeof(context->g_WIPRemoteEUI));
243     memset(context->g_WIPRemoteNodeId, '\0', sizeof(context->g_WIPRemoteNodeId));
244
245     context->g_ZigBeeStatus.state = ZB_STATE_UNKNOWN;
246     context->g_ZigBeeStatus.panId = 0;
247     context->g_ZigBeeStatus.extPanId = 0;
248     context->g_ZigBeeStatus.remoteAttributeValueRead = NULL;
249     context->g_ZigBeeStatus.remoteAtrributeValueReadLength = 0;
250
251     context->g_FoundMatchedDeviceList = NULL;
252     context->g_WIPDevice = NULL;
253
254     context->g_DeviceFoundCallback = NULL;
255     context->g_EnrollmentSucceedCallback = NULL;
256     context->g_DeviceStatusUpdateCallback = NULL;
257     context->g_EndDeviceNodeIdChangedCallback = NULL;
258 }
259
260 /*****************************************************************************/
261 /*                                                                           */
262 /* Public functions                                                          */
263 /*                                                                           */
264 /*****************************************************************************/
265 OCStackResult TWInitialize(PIPlugin_Zigbee* plugin, const char* deviceDevPath)
266 {
267     OIC_LOG(INFO, TAG, "Enter TWInitialize()");
268
269     TWResultCode twCode = TW_RESULT_ERROR;
270
271     if ((plugin == NULL) || (deviceDevPath == NULL))
272     {
273         return OC_STACK_INVALID_PARAM;
274     }
275
276     if (g_twContextList != NULL)
277     {
278         TWContext* out = NULL;
279         TWContext* temp = NULL;
280         LL_FOREACH_SAFE(g_twContextList, out, temp)
281         {
282             if (out->g_plugin == plugin)
283             {
284                 //Ignore because it's already in the list.
285                 return TW_RESULT_OK;
286             }
287         }
288     }
289
290     TWContext* ctx = (TWContext*)OICCalloc(1, sizeof(*ctx));
291     if (ctx == NULL)
292     {
293         return OC_STACK_NO_MEMORY;
294     }
295     InitializeContext(ctx);
296     ctx->g_plugin = plugin;
297     ctx->g_port = deviceDevPath;
298
299     OIC_LOG_V(INFO, TAG, "Attempt to open %s", deviceDevPath);
300
301     twCode = TWStartSock(ctx->g_plugin, deviceDevPath);  //TODO:
302     if (twCode != TW_RESULT_OK)
303     {
304         OIC_LOG_V(ERROR, TAG, "Failed to open %s because of error: %d", deviceDevPath, twCode);
305         OICFree(ctx);
306         return OC_STACK_ERROR;
307     }
308
309     char* eui = NULL;
310     twCode = TWGetEUI(ctx->g_plugin, &eui);
311     if (twCode != TW_RESULT_OK)
312     {
313         OIC_LOG_V(ERROR, TAG, "Failed to get EUI because of error: %d", twCode);
314         OICFree(ctx);
315         return OC_STACK_ERROR;
316     }
317     OICStrcpy(ctx->g_LocalEUI, sizeof(ctx->g_LocalEUI), eui);
318     OIC_LOG_V(INFO, TAG, "LocalEUI=%s", ctx->g_LocalEUI);
319     OICFree(eui);
320
321     bool wantReset = false;     //TODO:
322     if (wantReset)
323     {
324         twCode = Reset(ctx);
325         if (twCode != TW_RESULT_OK)
326         {
327             OIC_LOG(ERROR, TAG, "ZigBee Initialization - Reset");
328             OICFree(ctx);
329             return OC_STACK_ERROR;
330         }
331     }
332
333     twCode = CreatePAN(ctx);
334     if (twCode != TW_RESULT_OK)
335     {
336         OIC_LOG(ERROR, TAG, "CreatePan Failed");
337         OIC_LOG(ERROR, TAG, "TWInitialize() - MUST STOP NOW");
338         ctx->g_ZigBeeStatus.state = ZB_STATE_UNKNOWN;
339         OICFree(ctx);
340         return OC_STACK_ERROR;
341     }
342     else
343     {
344         OIC_LOG(INFO, TAG, "CreatePan Succeed");
345         OIC_LOG(INFO, TAG, "TWInitialize() Succeed");
346         ctx->g_ZigBeeStatus.state = ZB_STATE_INIT;
347         LL_APPEND(g_twContextList, ctx);
348         return OC_STACK_OK;
349     }
350 }
351
352 OCStackResult TWDiscover(PIPlugin_Zigbee* plugin)
353 {
354     OIC_LOG(INFO, TAG, "Enter TWDiscover()");
355
356     OCStackResult ret = OC_STACK_ERROR;
357     TWResultCode twRet = TW_RESULT_ERROR;
358
359     TWContext* ctx = GetTWContext(plugin);
360     if (ctx == NULL)
361     {
362         OIC_LOG(ERROR, TAG, "Invalid Param");
363         return OC_STACK_INVALID_PARAM;
364     }
365
366     if (ctx->g_DeviceFoundCallback == NULL)
367     {
368         OIC_LOG(INFO, TAG, "Required TWDeviceFoundCallback.");
369         return OC_STACK_ERROR;
370     }
371
372     twRet = EnableJoin(false, ctx);
373     if (twRet != TW_RESULT_OK)
374     {
375         OIC_LOG(ERROR, TAG, "EnableJoin");
376         return OC_STACK_ERROR;
377     }
378
379     twRet = FindMatchNodes(ctx);
380     if (twRet == TW_RESULT_OK)
381     {
382         OIC_LOG(INFO, TAG, "FindMatchNodes");
383         ret = OC_STACK_OK;
384     }
385     else
386     {
387         OIC_LOG(ERROR, TAG, "FindMatchNodes");
388         ret = OC_STACK_ERROR;
389     }
390
391     OIC_LOG_V(INFO, TAG, "Leave TWDiscover() with ret=%d", ret);
392     return ret;
393 }
394
395 OCStackResult TWSetAttribute(char* extendedUniqueId, char* nodeId, char* endpointId,
396                              char* clusterId, char* attributeId, char* attributeType,
397                              char* newValue, PIPlugin_Zigbee* plugin)
398 {
399     //Ask:  AT+WRITEATR:5DA7,01,0,0003,0000,21,01
400
401     OIC_LOG(INFO, TAG, "Enter TWSetAttribute()");
402
403     TWContext* ctx = GetTWContext(plugin);
404     if (ctx == NULL)
405     {
406         OIC_LOG(ERROR, TAG, "Invalid Param");
407         return OC_STACK_INVALID_PARAM;
408     }
409
410     (void)extendedUniqueId;
411
412     OCStackResult ret = OC_STACK_ERROR;
413     TWResultCode twRet = TW_RESULT_ERROR;
414
415     int size =  strlen(AT_CMD_WRITE_ATR) + strlen(nodeId) +
416                 SEPARATOR_LENGTH + strlen(endpointId) +
417                 SEPARATOR_LENGTH + strlen(SENDMODE) +
418                 SEPARATOR_LENGTH + strlen(clusterId) +
419                 SEPARATOR_LENGTH + strlen(attributeId) +
420                 SEPARATOR_LENGTH + strlen(attributeType) +
421                 SEPARATOR_LENGTH + strlen(newValue) + 1;
422
423     char* cmdString = (char*)OICMalloc(size * sizeof(char));
424     if (cmdString == NULL)
425     {
426         OIC_LOG(ERROR, TAG, "No Memory");
427         ret = OC_STACK_ERROR;
428         goto exit;
429     }
430     snprintf(cmdString, size, "%s%s,%s,%s,%s,%s,%s,%s",
431              AT_CMD_WRITE_ATR, nodeId, endpointId, SENDMODE,
432              clusterId, attributeId, attributeType, newValue);
433
434     twRet = TWIssueATCommand(ctx->g_plugin, cmdString);
435     if (twRet != TW_RESULT_OK)
436     {
437         OIC_LOG_V(ERROR, TAG, "Write %s", cmdString);
438         ret = OC_STACK_ERROR;
439         goto exit;
440     }
441     OIC_LOG_V(INFO, TAG, "Write %s", cmdString);
442
443     TWEntry* entry = NULL;
444     twRet = TWDequeueEntry(ctx->g_plugin, &entry, TW_WRITEATTR);
445     if (twRet != TW_RESULT_OK)
446     {
447         OIC_LOG(ERROR, TAG, "TWDequeueEntry");
448         ret = OC_STACK_ERROR;
449         goto exit;
450     }
451     if (entry == NULL)
452     {
453         OIC_LOG(INFO, TAG, "TWEntry is NULL.");
454         ret = OC_STACK_ERROR;
455         goto exit;
456     }
457
458     twRet = processEntry(entry, ctx);
459     if (twRet == TW_RESULT_ERROR_INVALID_OP)
460     {
461         OIC_LOG_V(INFO, TAG, "Write %s - Invalid Operation", cmdString);
462         ret = OC_STACK_INVALID_OPTION;
463         goto exit;
464     }
465     if (twRet != TW_RESULT_OK)
466     {
467         OIC_LOG(ERROR, TAG, "processEntry");
468         ret = OC_STACK_ERROR;
469         goto exit;
470     }
471
472     ret = OC_STACK_OK;
473
474 exit:
475     TWDeleteEntry(ctx->g_plugin, entry);
476     OICFree(cmdString);
477     OIC_LOG_V(INFO, TAG, "Leave TWSetAttribute() with ret=%d", ret);
478     return ret;
479 }
480
481 OCStackResult TWGetAttribute(char* extendedUniqueId, char* nodeId, char* endpointId,
482                              char* clusterId, char* attributeId,
483                              char** outValue, uint8_t* outValueLength,
484                              PIPlugin_Zigbee* plugin)
485 {
486     //Ask:  AT+READATR:FE5A,01,0,0402,0002
487
488     OIC_LOG(INFO, TAG, "Enter TWGetAttribute()");
489
490     TWContext* ctx = GetTWContext(plugin);
491     if (ctx == NULL)
492     {
493         return OC_STACK_INVALID_PARAM;
494     }
495
496     (void)extendedUniqueId;
497
498     OCStackResult ret = OC_STACK_ERROR;
499     TWResultCode twRet = TW_RESULT_ERROR;
500
501     int size =  strlen(AT_CMD_READ_ATR) + strlen(nodeId) +
502                 SEPARATOR_LENGTH + strlen(endpointId) +
503                 SEPARATOR_LENGTH + strlen(SENDMODE) +
504                 SEPARATOR_LENGTH + strlen(clusterId) +
505                 SEPARATOR_LENGTH + strlen(attributeId) + 1;
506
507     char* cmdString = (char*)OICMalloc(size * sizeof(char));
508     if (cmdString == NULL)
509     {
510         OIC_LOG(ERROR, TAG, "No Memory");
511         ret = OC_STACK_NO_MEMORY;
512         goto exit;
513     }
514     int stringRet = snprintf(cmdString, size, "%s%s%s%s%s%s%s%s%s%s",
515                              AT_CMD_READ_ATR, nodeId,
516                              SEPARATOR, endpointId,
517                              SEPARATOR, SENDMODE,
518                              SEPARATOR, clusterId,
519                              SEPARATOR, attributeId);
520     if(stringRet <= 0)
521     {
522         OIC_LOG(ERROR, TAG, "Build command error.");
523         ret = OC_STACK_ERROR;
524         goto exit;
525     }
526     twRet = TWIssueATCommand(ctx->g_plugin, cmdString);
527     if (twRet != TW_RESULT_OK)
528     {
529         OIC_LOG_V(ERROR, TAG, "Write %s", cmdString);
530         ret = OC_STACK_ERROR;
531         goto exit;
532     }
533     OIC_LOG_V(INFO, TAG, "Write %s", cmdString);
534
535     TWEntry* entry = NULL;
536     twRet = TWDequeueEntry(ctx->g_plugin, &entry, TW_RESPATTR);
537     if (twRet != TW_RESULT_OK)
538     {
539         OIC_LOG(ERROR, TAG, "TWDequeueEntry");
540         ret = OC_STACK_ERROR;
541         goto exit;
542     }
543     if (entry == NULL)
544     {
545         OIC_LOG(INFO, TAG, "TWEntry is NULL");
546         ret = OC_STACK_ERROR;
547         goto exit;
548     }
549
550     twRet = processEntry(entry, ctx);
551     if (twRet != TW_RESULT_REMOTE_ATTR_HAS_VALUE)
552     {
553         OIC_LOG(ERROR, TAG, "processEntry.");
554         ret = OC_STACK_ERROR;
555         goto exit;
556     }
557
558     size = strlen(ctx->g_ZigBeeStatus.remoteAttributeValueRead) + 1;
559     *outValue = (char*)OICMalloc(sizeof(char) * size);
560     if (*outValue == NULL)
561     {
562         OIC_LOG(ERROR, TAG, "No Memory");
563         ret = OC_STACK_NO_MEMORY;
564         goto exit;
565     }
566
567     OICStrcpy(*outValue, size, ctx->g_ZigBeeStatus.remoteAttributeValueRead);
568     *outValueLength = ctx->g_ZigBeeStatus.remoteAtrributeValueReadLength;
569     OICFree(ctx->g_ZigBeeStatus.remoteAttributeValueRead);
570     ctx->g_ZigBeeStatus.remoteAttributeValueRead = NULL;
571     ctx->g_ZigBeeStatus.remoteAtrributeValueReadLength = 0;
572     OIC_LOG(INFO, TAG, "TWGetAttribute() gets an attribute value.");
573     ret = OC_STACK_OK;
574
575 exit:
576     TWDeleteEntry(ctx->g_plugin, entry);
577     OICFree(cmdString);
578     OIC_LOG_V(INFO, TAG, "Leave TWGetAttribute() with ret=%d", ret);
579     return ret;
580 }
581
582 OCStackResult TWSwitchOnOff(char* nodeId, char* endpointId, char* newState,
583                             PIPlugin_Zigbee* plugin)
584 {
585     //AT+RONOFF:<Address>,<EP>,<SendMode>[,<ON/OFF>]
586     //AT+RONOFF:9E2B,01,0,1
587     //      OK
588     //      DFTREP:9E2B,01,0006,01,00
589
590     OIC_LOG(INFO, TAG, "Enter TWSwitchOnOff()");
591
592     TWContext* ctx = GetTWContext(plugin);
593     if (ctx == NULL)
594     {
595         OIC_LOG(ERROR, TAG, "Invalid Param");
596         return OC_STACK_INVALID_PARAM;
597     }
598
599     OCStackResult ret = OC_STACK_ERROR;
600     TWResultCode twRet = TW_RESULT_UNKNOWN;
601
602     int size = 0;
603     if (newState == NULL)
604     {
605         size =  strlen(AT_CMD_RUN_ON_OFF) + strlen(nodeId) +
606                 SEPARATOR_LENGTH + strlen(endpointId) +
607                 SEPARATOR_LENGTH + strlen(SENDMODE) + 1;
608     }
609     else
610     {
611         size =  strlen(AT_CMD_RUN_ON_OFF) + strlen(nodeId) +
612                 SEPARATOR_LENGTH + strlen(endpointId) +
613                 SEPARATOR_LENGTH + strlen(SENDMODE) +
614                 SEPARATOR_LENGTH + strlen(newState) + 1;
615     }
616
617     char* cmdString = (char*)OICMalloc(size * sizeof(char));
618     if (cmdString == NULL)
619     {
620         OIC_LOG(ERROR, TAG, "No Memory");
621         ret = OC_STACK_NO_MEMORY;
622         goto exit;
623     }
624
625     int stringRet = snprintf(cmdString, size, "%s%s%s%s%s%s",
626                              AT_CMD_RUN_ON_OFF, nodeId, SEPARATOR,
627                              endpointId, SEPARATOR, SENDMODE);
628     if(stringRet <= 0)
629     {
630         OIC_LOG(ERROR, TAG, "Build command error.");
631         ret = OC_STACK_ERROR;
632         goto exit;
633     }
634     if (newState != NULL)
635     {
636         OICStrcat(cmdString, size, SEPARATOR);
637         OICStrcat(cmdString, size, newState);
638     }
639
640     twRet = TWIssueATCommand(ctx->g_plugin, cmdString);
641     if (twRet != TW_RESULT_OK)
642     {
643         OIC_LOG_V(ERROR, TAG, "Write %s", cmdString);
644         ret = OC_STACK_ERROR;
645         goto exit;
646     }
647     OIC_LOG_V(INFO, TAG, "Write %s", cmdString);
648
649     TWEntry* entry = NULL;
650     twRet = TWDequeueEntry(ctx->g_plugin, &entry, TW_DFTREP);
651     if (twRet != TW_RESULT_OK)
652     {
653         OIC_LOG(ERROR, TAG, "TWDequeueEntry");
654         ret = OC_STACK_ERROR;
655         goto exit;
656     }
657     if (entry == NULL)
658     {
659         OIC_LOG(ERROR, TAG, "TWEntry is NULL");
660         ret = OC_STACK_ERROR;
661         goto exit;
662     }
663
664     twRet = processEntry(entry, ctx);
665     if (twRet != TW_RESULT_OK)
666     {
667         OIC_LOG_V(ERROR, TAG, "processEntry - %s", cmdString);
668         ret = OC_STACK_ERROR;
669         goto exit;
670     }
671
672     ret = OC_STACK_OK;
673
674 exit:
675     TWDeleteEntry(ctx->g_plugin, entry);
676     OICFree(cmdString);
677     OIC_LOG_V(INFO, TAG, "Leave TWSwitchOnOff() with ret=%d", ret);
678     return ret;
679 }
680
681 OCStackResult TWMoveToLevel(char* nodeId, char* endpointId,
682                             char* onOffState, char* level, char* transTime,
683                             PIPlugin_Zigbee* plugin)
684 {
685     //AT+LCMVTOLEV:<Address>,<EP>,<SendMode>,<ON/OFF>,<LevelValue>,<TransTime>
686
687     OIC_LOG(INFO, TAG, "Enter TWMoveToLevel()");
688
689     TWContext* ctx = GetTWContext(plugin);
690     if (ctx == NULL)
691     {
692         OIC_LOG(ERROR, TAG, "Invalid Param");
693         return OC_STACK_INVALID_PARAM;
694     }
695
696     OCStackResult ret = OC_STACK_ERROR;
697     TWResultCode twRet = TW_RESULT_UNKNOWN;
698
699     int size = 0;
700     size =  strlen(AT_CMD_MOVE_TO_LEVEL) + strlen(nodeId) +
701             SEPARATOR_LENGTH + strlen(endpointId) +
702             SEPARATOR_LENGTH + strlen(SENDMODE) +
703             SEPARATOR_LENGTH + strlen(onOffState) +
704             SEPARATOR_LENGTH + strlen(level) +
705             SEPARATOR_LENGTH + strlen(transTime) + 1;
706
707     char* cmdString = (char*)OICMalloc(size * sizeof(char));
708     if (cmdString == NULL)
709     {
710         OIC_LOG(ERROR, TAG, "No Memory");
711         ret = OC_STACK_NO_MEMORY;
712         goto exit;
713     }
714
715     int stringRet = snprintf(cmdString, size, "%s%s%s%s%s%s%s%s%s%s%s%s",
716                              AT_CMD_MOVE_TO_LEVEL, nodeId,
717                              SEPARATOR, endpointId,
718                              SEPARATOR, SENDMODE,
719                              SEPARATOR, onOffState,
720                              SEPARATOR, level,
721                              SEPARATOR, transTime);
722     if(stringRet <= 0)
723     {
724         OIC_LOG(ERROR, TAG, "Build command error.");
725         ret = OC_STACK_ERROR;
726         goto exit;
727     }
728
729     twRet = TWIssueATCommand(ctx->g_plugin, cmdString);
730     if (twRet != TW_RESULT_OK)
731     {
732         OIC_LOG_V(ERROR, TAG, "Write %s", cmdString);
733         ret = OC_STACK_ERROR;
734         goto exit;
735     }
736
737     OIC_LOG_V(INFO, TAG, "Write %s", cmdString);
738
739     TWEntry* entry = NULL;
740     twRet = TWDequeueEntry(ctx->g_plugin, &entry, TW_DFTREP);
741     if (twRet != TW_RESULT_OK)
742     {
743         OIC_LOG(ERROR, TAG, "TWDequeueEntry");
744         ret = OC_STACK_ERROR;
745         goto exit;
746     }
747     if (entry == NULL)
748     {
749         OIC_LOG(ERROR, TAG, "TWEntry is NULL");
750         ret = OC_STACK_ERROR;
751         goto exit;
752     }
753
754     twRet = processEntry(entry, ctx);
755     if (twRet != TW_RESULT_OK)
756     {
757         OIC_LOG_V(ERROR, TAG, "processEntry - %s", cmdString);
758         ret = OC_STACK_ERROR;
759         goto exit;
760     }
761
762     ret = OC_STACK_OK;
763
764 exit:
765     TWDeleteEntry(ctx->g_plugin, entry);
766     OICFree(cmdString);
767     OIC_LOG_V(INFO, TAG, "Leave TWMoveToLevel() with ret=%d", ret);
768     return ret;
769 }
770
771 OCStackResult TWSwitchDoorLockState(char* nodeId, char* endpointId, char* newState,
772                                     PIPlugin_Zigbee* plugin)
773 {
774     //AT+DRLOCK:<Address>,<EP>,<SendMode>,<Lock/Unlock>
775
776     OIC_LOG(INFO, TAG, "Enter TWSwitchDoorLockState()");
777
778     TWContext* ctx = GetTWContext(plugin);
779     if (ctx == NULL)
780     {
781         OIC_LOG(ERROR, TAG, "Invalid Param");
782         return OC_STACK_INVALID_PARAM;
783     }
784
785     OCStackResult ret = OC_STACK_ERROR;
786     TWResultCode twRet = TW_RESULT_UNKNOWN;
787
788     int size = 0;
789     size =  strlen(AT_CMD_DOOR_LOCK) + strlen(nodeId) +
790             SEPARATOR_LENGTH + strlen(endpointId) +
791             SEPARATOR_LENGTH + strlen(SENDMODE) +
792             SEPARATOR_LENGTH + strlen(newState) + 1;
793
794     char* cmdString = (char*)OICMalloc(size * sizeof(char));
795     if (cmdString == NULL)
796     {
797         OIC_LOG(ERROR, TAG, "No Memory");
798         ret = OC_STACK_NO_MEMORY;
799         goto exit;
800     }
801
802     int stringRet = snprintf(cmdString, size, "%s%s%s%s%s%s%s%s",
803                              AT_CMD_DOOR_LOCK, nodeId,
804                              SEPARATOR, endpointId,
805                              SEPARATOR, SENDMODE,
806                              SEPARATOR, newState);
807     if(stringRet <= 0)
808     {
809         OIC_LOG(ERROR, TAG, "Build command error.");
810         ret = OC_STACK_ERROR;
811         goto exit;
812     }
813
814     twRet = TWIssueATCommand(ctx->g_plugin, cmdString);
815     if (twRet != TW_RESULT_OK)
816     {
817         OIC_LOG_V(ERROR, TAG, "Write %s", cmdString);
818         ret = OC_STACK_ERROR;
819         goto exit;
820     }
821
822     OIC_LOG_V(INFO, TAG, "Write %s", cmdString);
823
824     TWEntry* entry = NULL;
825     twRet = TWDequeueEntry(ctx->g_plugin, &entry, TW_DFTREP);
826     if (twRet != TW_RESULT_OK)
827     {
828         OIC_LOG(ERROR, TAG, "TWDequeueEntry");
829         ret = OC_STACK_ERROR;
830         goto exit;
831     }
832
833     if (entry == NULL)
834     {
835         OIC_LOG(ERROR, TAG, "TWEntry is NULL");
836         ret = OC_STACK_ERROR;
837         goto exit;
838     }
839
840     twRet = processEntry(entry, ctx);
841     if (twRet != TW_RESULT_OK)
842     {
843         OIC_LOG_V(ERROR, TAG, "processEntry - %s", cmdString);
844         ret = OC_STACK_ERROR;
845         goto exit;
846     }
847
848     ret = OC_STACK_OK;
849
850 exit:
851     TWDeleteEntry(ctx->g_plugin, entry);
852     OICFree(cmdString);
853     OIC_LOG_V(INFO, TAG, "Leave TWSwitchDoorLockState() with ret=%d", ret);
854     return ret;
855 }
856
857 OCStackResult TWColorMoveToColorTemperature(char* nodeId, char* endpointId,
858                                             char* colorTemperature, char* transTime,
859                                             PIPlugin_Zigbee* plugin)
860 {
861
862     //AT+CCMVTOCT:<Address>,<EP>,<SendMode>,<ColorTemperature>,<TransTime>
863     //  OK
864     //  ERROR:<errorcode>
865
866     OIC_LOG(INFO, TAG, "Enter TWColorMoveToColorTemperature()");
867
868     TWContext* ctx = GetTWContext(plugin);
869     if (ctx == NULL)
870     {
871         OIC_LOG(ERROR, TAG, "Invalid Param");
872         return OC_STACK_INVALID_PARAM;
873     }
874
875     OCStackResult ret = OC_STACK_ERROR;
876     TWResultCode twRet = TW_RESULT_UNKNOWN;
877
878     int size = 0;
879     size =  strlen(AT_CMD_COLOR_CTRL_MOVE_TO_COLOR_TEMPERATURE) + strlen(nodeId) +
880             SEPARATOR_LENGTH + strlen(endpointId) +
881             SEPARATOR_LENGTH + strlen(SENDMODE) +
882             SEPARATOR_LENGTH + strlen(colorTemperature) +
883             SEPARATOR_LENGTH + strlen(transTime) + 1;
884
885     char* cmdString = (char*)OICMalloc(size * sizeof(char));
886     if (cmdString == NULL)
887     {
888         OIC_LOG(ERROR, TAG, "No Memory");
889         ret = OC_STACK_NO_MEMORY;
890         goto exit;
891     }
892
893     int stringRet = snprintf(cmdString, size, "%s%s%s%s%s%s%s%s%s%s",
894                              AT_CMD_COLOR_CTRL_MOVE_TO_COLOR_TEMPERATURE, nodeId,
895                              SEPARATOR, endpointId,
896                              SEPARATOR, SENDMODE,
897                              SEPARATOR, colorTemperature,
898                              SEPARATOR, transTime);
899     if(stringRet <= 0)
900     {
901         OIC_LOG(ERROR, TAG, "Build command error.");
902         ret = OC_STACK_ERROR;
903         goto exit;
904     }
905     twRet = TWIssueATCommand(ctx->g_plugin, cmdString);
906     if (twRet != TW_RESULT_OK)
907     {
908         OIC_LOG_V(ERROR, TAG, "Write %s", cmdString);
909         ret = OC_STACK_ERROR;
910         goto exit;
911     }
912     OIC_LOG_V(INFO, TAG, "Write %s", cmdString);
913
914     TWEntry* entry = NULL;
915     twRet = TWDequeueEntry(ctx->g_plugin, &entry, TW_DFTREP);
916     if (twRet != TW_RESULT_OK)
917     {
918         OIC_LOG_V(ERROR, TAG, "TWDequeueEntry - %s", cmdString);
919         ret = OC_STACK_ERROR;
920         goto exit;
921     }
922     if (entry == NULL)
923     {
924         OIC_LOG_V(ERROR, TAG, "TWEntry is NULL - %s", cmdString);
925         ret = OC_STACK_ERROR;
926         goto exit;
927     }
928
929     twRet = processEntry(entry, ctx);
930     if (twRet != TW_RESULT_OK)
931     {
932         OIC_LOG_V(ERROR, TAG, "processEntry - %s", cmdString);
933         ret = OC_STACK_ERROR;
934         goto exit;
935     }
936
937     ret = OC_STACK_OK;
938
939 exit:
940     TWDeleteEntry(ctx->g_plugin, entry);
941     OICFree(cmdString);
942     OIC_LOG_V(INFO, TAG, "Leave TWColorMoveToColorTemperature() with ret=%d", ret);
943     return ret;
944 }
945
946 OCStackResult TWSetDiscoveryCallback(const TWDeviceFoundCallback callback, PIPlugin_Zigbee* plugin)
947 {
948     OIC_LOG(INFO, TAG, "Enter TWSetDiscoveryCallback()");
949
950     OCStackResult ret = OC_STACK_OK;
951
952     TWContext* ctx = GetTWContext(plugin);
953     if (ctx == NULL)
954     {
955         ret = OC_STACK_INVALID_PARAM;
956     }
957     else
958     {
959         if (callback != NULL)
960         {
961             ctx->g_DeviceFoundCallback= callback;
962         }
963         else
964         {
965             ctx->g_DeviceFoundCallback = NULL;
966         }
967     }
968
969     OIC_LOG_V(INFO, TAG, "Leave TWSetDiscoveryCallback() with ret=%d", ret);
970     return ret;
971 }
972
973 OCStackResult TWSetEndDeviceNodeIdChangedCallback(TWDeviceNodeIdChangedCallback callback,
974                                                   PIPlugin_Zigbee* plugin)
975 {
976     OIC_LOG(INFO, TAG, "Enter TWSetEndDeviceNodeIdChangedCallback()");
977
978     OCStackResult ret = OC_STACK_OK;
979
980     TWContext* ctx = GetTWContext(plugin);
981     if (ctx == NULL)
982     {
983         ret = OC_STACK_INVALID_PARAM;
984     }
985     else
986     {
987         if (callback != NULL)
988         {
989             ctx->g_EndDeviceNodeIdChangedCallback= callback;
990         }
991         else
992         {
993             ctx->g_EndDeviceNodeIdChangedCallback = NULL;
994         }
995     }
996     OIC_LOG_V(INFO, TAG, "Leave TWSetEndDeviceNodeIdChangedCallback() with ret=%d", ret);
997     return ret;
998 }
999
1000 OCStackResult TWSetStatusUpdateCallback(TWDeviceStatusUpdateCallback callback,
1001                                         PIPlugin_Zigbee* plugin)
1002 {
1003     OIC_LOG(INFO, TAG, "Enter TWSetStatusUpdateCallback()");
1004
1005     OCStackResult ret = OC_STACK_OK;
1006
1007     TWContext* ctx = GetTWContext(plugin);
1008     if (ctx == NULL)
1009     {
1010         ret = OC_STACK_INVALID_PARAM;
1011     }
1012     else
1013     {
1014         if (callback != NULL)
1015         {
1016             ctx->g_DeviceStatusUpdateCallback= callback;
1017         }
1018         else
1019         {
1020             ctx->g_DeviceStatusUpdateCallback = NULL;
1021         }
1022     }
1023
1024     OIC_LOG_V(INFO, TAG, "Leave TWSetStatusUpdateCallback() with ret=%d", ret);
1025     return ret;
1026 }
1027
1028 OCStackResult TWListenForStatusUpdates(char* nodeId, char* endpointId, PIPlugin_Zigbee* plugin)
1029 {
1030     OIC_LOG(INFO, TAG, "Enter TWListenForStatusUpdates()");
1031
1032     OCStackResult ret = OC_STACK_OK;
1033
1034     TWContext* ctx = GetTWContext(plugin);
1035     if (ctx == NULL)
1036     {
1037         ret = OC_STACK_INVALID_PARAM;
1038     }
1039     else
1040     {
1041         char* zoneClusterID = "0500";
1042         char* zoneAttributeID = "0010";
1043         char* attributeDateType = "F0";
1044
1045         ret = TWSetAttribute(NULL, nodeId, endpointId,
1046                              zoneClusterID, zoneAttributeID, attributeDateType,
1047                              ctx->g_LocalEUI, ctx->g_plugin);
1048
1049         if (ret == OC_STACK_INVALID_OPTION)
1050         {
1051             OIC_LOG(INFO, TAG, "Already registered for ZoneStatusUpdate");
1052             ret = OC_STACK_OK;
1053         }
1054     }
1055     OIC_LOG_V(INFO, TAG, "Leave TWListenForStatusUpdates() with ret=%d", ret);
1056     return ret;
1057 }
1058
1059 OCStackResult TWProcess(PIPlugin_Zigbee* plugin)
1060 {
1061     if (plugin == NULL)
1062     {
1063         return OC_STACK_INVALID_PARAM;
1064     }
1065     TWContext* ctx = GetTWContext(plugin);
1066     if (ctx == NULL)
1067     {
1068         return OC_STACK_INVALID_PARAM;
1069     }
1070
1071     TWResultCode ret = TW_RESULT_UNKNOWN;
1072
1073     while (true)
1074     {
1075         TWEntry* entry = NULL;
1076         ret = TWDequeueEntry(ctx->g_plugin, &entry, TW_NONE);
1077         if (ret != TW_RESULT_OK)
1078         {
1079             OIC_LOG(ERROR, TAG, "TWDequeueEntry");
1080             ret = OC_STACK_ERROR;
1081             break;
1082         }
1083         if (entry == NULL)
1084         {
1085             ret = OC_STACK_OK;
1086             break;
1087         }
1088
1089         ret = processEntry(entry, ctx);
1090         if (ret != TW_RESULT_OK)
1091         {
1092             OIC_LOG(ERROR, TAG, "processEntry");
1093             ret = TWDeleteEntry(ctx->g_plugin, entry);
1094             if(ret != TW_RESULT_OK)
1095             {
1096                 OIC_LOG(ERROR, TAG, "Failed to delete entry.");
1097                 ret = OC_STACK_ERROR;
1098                 break;
1099             }
1100         }
1101         else
1102         {
1103             OIC_LOG(INFO, TAG, "processEntry");
1104             ret = TWDeleteEntry(ctx->g_plugin, entry);
1105             if(ret != TW_RESULT_OK)
1106             {
1107                 OIC_LOG(ERROR, TAG, "Failed to delete entry.");
1108                 ret = OC_STACK_ERROR;
1109                 break;
1110             }
1111         }
1112     }
1113
1114     return ret;
1115 }
1116
1117 OCStackResult TWUninitialize(PIPlugin_Zigbee* plugin)
1118 {
1119     OIC_LOG(INFO, TAG, "Enter TWUninitializeZigBee()");
1120     OCStackResult ret = OC_STACK_ERROR;
1121
1122     TWContext* ctx = GetTWContext(plugin);
1123     if (ctx == NULL)
1124     {
1125         ret = OC_STACK_INVALID_PARAM;
1126     }
1127     else
1128     {
1129         TWResultCode twRet = TWStopSock(ctx->g_plugin);
1130         if (twRet == TW_RESULT_OK)
1131         {
1132             OIC_LOG(INFO, TAG, "TWStopSock");
1133             ret = OC_STACK_OK;
1134         }
1135         else
1136         {
1137             OIC_LOG(ERROR, TAG, "TWStopSock");
1138             ret = OC_STACK_ERROR;
1139         }
1140         DeallocateTWDeviceList(ctx);
1141
1142         LL_DELETE(g_twContextList, ctx);
1143         OICFree(ctx);
1144     }
1145
1146     OIC_LOG_V(INFO, TAG, "Leave TWUninitializeZigBee() with ret=%d", ret);
1147     return ret;
1148 }
1149
1150 //-----------------------------------------------------------------------------
1151 // Internal functions
1152 //-----------------------------------------------------------------------------
1153
1154 TWResultCode processEntry(TWEntry *entry, TWContext* ctx)
1155 {
1156     OIC_LOG(INFO, TAG, "Enter processEntry()");
1157
1158     TWResultCode ret = TW_RESULT_UNKNOWN;
1159     switch(entry->type)
1160     {
1161         case TW_NETWORK_INFO:
1162             ret = processEntryNETWORK_INFO(entry, ctx);
1163             if ((ret != TW_RESULT_NO_LOCAL_PAN) &&
1164                 (ret != TW_RESULT_HAS_LOCAL_PAN))
1165             {
1166                 OIC_LOG(ERROR, TAG, "processEntryNETWORK_INFO.");
1167             }
1168             break;
1169         case TW_JPAN:
1170             ret = processEntryJPAN(entry, ctx);
1171             if (ret != TW_RESULT_OK)
1172             {
1173                 OIC_LOG(ERROR, TAG, "processEntryJPAN.");
1174             }
1175             break;
1176         case TW_SED:
1177             ret = processEntryEndDevice(entry, ctx);
1178             if (ret != TW_RESULT_OK)
1179             {
1180                 OIC_LOG(ERROR, TAG, "processEntrySED.");
1181             }
1182             break;
1183         case TW_RFD:
1184             ret = processEntryEndDevice(entry, ctx);
1185             if (ret != TW_RESULT_OK)
1186             {
1187                 OIC_LOG(ERROR, TAG, "processEntryRFD.");
1188             }
1189             break;
1190         case TW_FFD:
1191             ret = processEntryEndDevice(entry, ctx);
1192             if (ret != TW_RESULT_OK)
1193             {
1194                 OIC_LOG(ERROR, TAG, "processEntryFFD.");
1195             }
1196             break;
1197         case TW_ZED:
1198             ret = processEntryEndDevice(entry, ctx);
1199             if (ret != TW_RESULT_OK)
1200             {
1201                 OIC_LOG(ERROR, TAG, "processEntryZED.");
1202             }
1203             break;
1204         case TW_MATCHDESC:
1205             ret = processEntryMatchDesc(entry, ctx);
1206             if (ret != TW_RESULT_OK)
1207             {
1208                 OIC_LOG(ERROR, TAG, "processEntryMatchDesc.");
1209             }
1210             break;
1211         case TW_SIMPLEDESC:
1212             ret = processEntrySimpleDesc(entry, ctx);
1213             if (ret != TW_RESULT_OK)
1214             {
1215                 OIC_LOG(ERROR, TAG, "processEntrySimpleDesc.");
1216             }
1217             break;
1218         case TW_WRITEATTR:
1219             ret = processEntryWriteAttr(entry, ctx);
1220             if (ret == TW_RESULT_ERROR_INVALID_OP)
1221             {
1222                OIC_LOG_V(INFO, TAG, "processEntryWriteAttr - ret=%d", TW_RESULT_ERROR_INVALID_OP);
1223             }
1224             else if (ret != TW_RESULT_OK)
1225             {
1226                 OIC_LOG(ERROR, TAG, "processEntryWriteAttr.");
1227             }
1228             break;
1229         case TW_RESPATTR:
1230             ret = processEntryReadAttr(entry, ctx);
1231             if (ret != TW_RESULT_REMOTE_ATTR_HAS_VALUE)
1232             {
1233                 OIC_LOG(ERROR, TAG, "processEntryReadAttr.");
1234             }
1235             break;
1236         case TW_TEMPERATURE:
1237             ret = processEntryTemperature(entry, ctx);
1238             if (ret != TW_RESULT_REMOTE_ATTR_HAS_VALUE)
1239             {
1240                 OIC_LOG(ERROR, TAG, "processEntryTemperature.");
1241             }
1242             break;
1243         case TW_DRLOCRSP:
1244             ret = processEntrySwitchDoorLockState(entry, ctx);
1245             if (ret != TW_RESULT_OK)
1246             {
1247                 OIC_LOG(ERROR, TAG, "processEntrySwitchDoorLockState.");
1248             }
1249             break;
1250         case TW_DRUNLOCKRSP:
1251             ret = processEntrySwitchDoorLockState(entry, ctx);
1252             if (ret != TW_RESULT_OK)
1253             {
1254                 OIC_LOG(ERROR, TAG, "processEntrySwitchDoorLockState.");
1255             }
1256             break;
1257         case TW_DFTREP:
1258             ret = processEntryZCLDefaultResponse(entry, ctx);
1259             if (ret != TW_RESULT_OK)
1260             {
1261                 OIC_LOG(ERROR, TAG, "processEntryZCLDefaultResponse.");
1262             }
1263             break;
1264         case TW_ZENROLLREQ:
1265             ret = processEntryZoneEnrollRequest(entry, ctx);
1266             if (ret != TW_RESULT_OK)
1267             {
1268                 OIC_LOG(ERROR, TAG, "processEntryZoneEnrollRequest.");
1269             }
1270             break;
1271         case TW_ENROLLED:
1272             ret = processEntryEnrolled(entry, ctx);
1273             if (ret != TW_RESULT_OK)
1274             {
1275                 OIC_LOG(ERROR, TAG, "processEntryEnrolled.");
1276             }
1277             break;
1278         case TW_ZONESTATUS:
1279             ret = processEntryZoneStatus(entry, ctx);
1280             if (ret != TW_RESULT_OK)
1281             {
1282                 OIC_LOG(ERROR, TAG, "processEntryZoneStatus.");
1283             }
1284             break;
1285         case TW_ADDRESS_RESPONSE:
1286             ret = processEntryAddressResponse(entry, ctx);
1287             if (ret != TW_RESULT_OK)
1288             {
1289                 OIC_LOG(ERROR, TAG, "processEntryAddressResponse.");
1290             }
1291             break;
1292         default:
1293             OIC_LOG(ERROR, TAG, "processEntry() doesn't receive an valid entry.");
1294             ret = TW_RESULT_ERROR;
1295             break;
1296     }
1297
1298     OIC_LOG_V(INFO, TAG, "Leave processEntry() with ret=%d", ret);
1299     return ret;
1300 }
1301
1302 TWResultCode processEntryNETWORK_INFO(TWEntry* entry, TWContext* ctx)
1303 {
1304     /*
1305     //at+n
1306     //      +N=NoPAN
1307     //      OK
1308
1309     //at+n
1310     //      +N=COO,26,-6,7306,133F04EA669C6B24
1311     //      OK
1312     */
1313
1314     OIC_LOG(INFO, TAG, "Enter processEntryNETWORK_INFO()");
1315
1316     TWResultCode ret = TW_RESULT_UNKNOWN;
1317
1318     if (strcmp(entry->atErrorCode, AT_STR_ERROR_EVERYTHING_OK) != 0)
1319     {
1320         OIC_LOG_V(ERROR, TAG, "TWEntry contains AT_ERROR: %s", entry->atErrorCode);
1321         ret = TW_RESULT_ERROR;
1322         goto exit;
1323     }
1324
1325     ret = HandleATResponse(entry,ctx);
1326
1327 exit:
1328     OIC_LOG_V(INFO, TAG, "Leave processEntryNETWORK_INFO() with ret=%d", ret);
1329     return ret;
1330 }
1331
1332 TWResultCode processEntryJPAN(TWEntry* entry, TWContext* ctx)
1333 {
1334     /*
1335     //at+en
1336     //      OK
1337     //      JPAN:26,7306,133F04EA669C6B24
1338
1339     //at+en
1340     //      ERROR:28
1341     */
1342
1343     OIC_LOG(INFO, TAG, "Enter processEntryJPAN()");
1344
1345     TWResultCode ret = TW_RESULT_UNKNOWN;
1346     if (strcmp(entry->atErrorCode, AT_STR_ERROR_EVERYTHING_OK) == 0)
1347     {
1348         ret = HandleATResponse(entry,ctx);
1349         if (ret == TW_RESULT_NEW_LOCAL_PAN_ESTABLISHED)
1350         {
1351             OIC_LOG(INFO, TAG, "New Local PAN established.");
1352             ret =  TW_RESULT_OK;
1353         }
1354         else
1355         {
1356             ret = TW_RESULT_ERROR;
1357         }
1358     }
1359     else if (strcmp(entry->atErrorCode, AT_STR_ERROR_NODE_IS_PART_OF_PAN) == 0)
1360     {
1361         OIC_LOG(INFO, TAG, "Already Established PAN.");
1362         ret = TW_RESULT_OK;
1363     }
1364     else
1365     {
1366         OIC_LOG_V(ERROR, TAG, "TWEntry contains AT_ERROR: %s", entry->atErrorCode);
1367         ret = TW_RESULT_ERROR;
1368     }
1369
1370     OIC_LOG_V(INFO, TAG, "Leave processEntryJPAN() with ret=%d", ret);
1371     return ret;
1372 }
1373
1374 TWResultCode processEntryEndDevice(TWEntry* entry, TWContext* ctx)
1375 {
1376     OIC_LOG(INFO, TAG, "Enter processEntryEndDevice()");
1377
1378     TWResultCode ret = TW_RESULT_UNKNOWN;
1379     ret = HandleATResponse(entry,ctx);
1380     if (ret != TW_RESULT_OK)
1381     {
1382         OIC_LOG(ERROR, TAG, "HandleATResponse");
1383     }
1384
1385     OIC_LOG_V(INFO, TAG, "Leave processEntryEndDevice() with ret=%d", ret);
1386     return ret;
1387 }
1388
1389 TWResultCode processEntryMatchDesc(TWEntry* entry, TWContext* ctx)
1390 {
1391     //MatchDesc:0B4A,00,01
1392
1393     OIC_LOG(INFO, TAG, "Enter processEntryMatchDesc()");
1394     TWResultCode ret = TW_RESULT_UNKNOWN;
1395
1396     if (strcmp(entry->atErrorCode, AT_STR_ERROR_EVERYTHING_OK) != 0)
1397     {
1398         OIC_LOG_V(ERROR, TAG, "TWEntry contains AT_ERROR = %s", entry->atErrorCode);
1399         ret = TW_RESULT_ERROR;
1400     }
1401     else
1402     {
1403         ret = HandleATResponse(entry,ctx);
1404         if (ret == TW_RESULT_OK)
1405         {
1406             OIC_LOG(INFO, TAG, "HandleATResponse");
1407             ret = FindClusters(ctx->g_WIPDevice->nodeId,
1408                                ctx->g_WIPDevice->endpointOfInterest->endpointId,
1409                                ctx);
1410             if (ret == TW_RESULT_OK)
1411             {
1412                 OIC_LOG(INFO, TAG, "FindClusters - Found a match node");
1413                 if (ctx->g_DeviceFoundCallback != NULL)
1414                 {
1415                     OIC_LOG(INFO, TAG, "Found a match node -- invoke callback");
1416                     ctx->g_DeviceFoundCallback(ctx->g_WIPDevice, ctx->g_plugin);
1417                 }
1418                 ret =  TW_RESULT_OK;
1419             }
1420             else
1421             {
1422                 OIC_LOG(ERROR, TAG, "FindClusters");
1423                 ret = TW_RESULT_ERROR;
1424             }
1425         }
1426         else
1427         {
1428             OIC_LOG(ERROR, TAG, "HandleATResponse");
1429             ret = TW_RESULT_ERROR;
1430         }
1431
1432         ctx->g_WIPDevice = NULL; //reset and do not deallocate it
1433     }
1434
1435     OIC_LOG_V(INFO, TAG, "Leave processEntryMatchDesc() with ret=%d", ret);
1436     return ret;
1437 }
1438
1439 TWResultCode processEntrySimpleDesc(TWEntry* entry, TWContext* ctx)
1440 {
1441     /*
1442     //AT+SIMPLEDESC:3746,3746,01
1443     //      SEQ:97
1444     //      OK
1445     //
1446     //      SimpleDesc:3746,00
1447     //      EP:01
1448     //      ProfileID:0104
1449     //      DeviceID:0402v00
1450     //      InCluster:0000,0001,0003,0402,0500,0020,0B05
1451     //      OutCluster:0019
1452     //
1453     //      ACK:97
1454     */
1455     OIC_LOG(INFO, TAG, "Enter processEntrySimpleDesc()");
1456
1457     TWResultCode ret = TW_RESULT_UNKNOWN;
1458
1459     if (strcmp((entry->atErrorCode), AT_STR_ERROR_EVERYTHING_OK) != 0)
1460     {
1461         OIC_LOG_V(ERROR, TAG, "TWEntry contains AT_ERROR = %s", (entry->atErrorCode));
1462         ret = TW_RESULT_ERROR;
1463     }
1464     else
1465     {
1466         if (entry->count == 6)   //must be 6 as it is the number of lines to expect
1467         {
1468             ret = HandleATResponse(entry,ctx);
1469             if (ret == TW_RESULT_HAS_CLUSTERS)
1470             {
1471                 OIC_LOG(INFO, TAG, "has clusters.");
1472                 ret = TW_RESULT_OK;
1473             }
1474         }
1475         else
1476         {
1477             OIC_LOG(INFO, TAG, "Received an invalid Simple Descriptor.");
1478             ret = TW_RESULT_ERROR;
1479         }
1480     }
1481
1482     OIC_LOG_V(INFO, TAG, "Leave processEntrySimpleDesc() returns with ret=%d", ret);
1483     return ret;
1484 }
1485
1486 TWResultCode processEntryWriteAttr(TWEntry* entry, TWContext* ctx)
1487 {
1488     //AT+WRITEATR:3A3D,01,0,0003,0000,21,00
1489     //      OK
1490     //      WRITEATTR:3A3D,01,0003,,00
1491
1492     OIC_LOG(INFO, TAG, "Enter processEntryWriteAttr()");
1493
1494     TWResultCode ret = TW_RESULT_UNKNOWN;
1495
1496     if (strcmp((entry->atErrorCode), AT_STR_ERROR_EVERYTHING_OK) != 0)
1497     {
1498         OIC_LOG_V(ERROR, TAG, "TWEntry contains AT_ERROR = %s", entry->atErrorCode);
1499         ret = TW_RESULT_ERROR;
1500     }
1501     else
1502     {
1503         ret = HandleATResponse(entry,ctx);
1504     }
1505
1506     OIC_LOG_V(INFO, TAG, "Leave processEntryWriteAttr() returns with ret=%d", ret);
1507     return ret;
1508 }
1509
1510 TWResultCode processEntryReadAttr(TWEntry* entry, TWContext* ctx)
1511 {
1512     OIC_LOG(INFO, TAG, "Enter processEntryReadAttr()");
1513
1514     TWResultCode ret = TW_RESULT_UNKNOWN;
1515
1516     if (strcmp((entry->atErrorCode), AT_STR_ERROR_EVERYTHING_OK) != 0)
1517     {
1518         OIC_LOG_V(ERROR, TAG, "TWEntry contains AT_ERROR = %s", entry->atErrorCode);
1519         ret = TW_RESULT_ERROR;
1520     }
1521     else
1522     {
1523         ret = HandleATResponse(entry,ctx);
1524     }
1525
1526     OIC_LOG_V(INFO, TAG, "Leave processEntryReadAttr() returns with ret=%d", ret);
1527     return ret;
1528 }
1529
1530 TWResultCode processEntryTemperature(TWEntry* entry, TWContext* ctx)
1531 {
1532     OIC_LOG(INFO, TAG, "Enter processEntryTemperature()");
1533
1534     TWResultCode ret = TW_RESULT_UNKNOWN;
1535
1536     if (strcmp((entry->atErrorCode), AT_STR_ERROR_EVERYTHING_OK) != 0)
1537     {
1538         OIC_LOG_V(ERROR, TAG, "TWEntry contains AT_ERROR = %s", entry->atErrorCode);
1539         ret = TW_RESULT_ERROR;
1540     }
1541     else
1542     {
1543         ret = HandleATResponse(entry,ctx);
1544     }
1545
1546     OIC_LOG_V(INFO, TAG, "Leave processEntryTemperature() returns with ret=%d", ret);
1547     return ret;
1548 }
1549
1550 TWResultCode processEntrySwitchDoorLockState(TWEntry* entry, TWContext* ctx)
1551 {
1552     OIC_LOG(INFO, TAG, "Enter processEntrySwitchDoorLockState()");
1553
1554     TWResultCode ret = TW_RESULT_UNKNOWN;
1555
1556     if (strcmp((entry->atErrorCode), AT_STR_ERROR_EVERYTHING_OK) != 0)
1557     {
1558         OIC_LOG_V(ERROR, TAG, "TWEntry contains AT_ERROR = %s", entry->atErrorCode);
1559         ret = TW_RESULT_ERROR;
1560     }
1561     else
1562     {
1563         ret = HandleATResponse(entry,ctx);
1564     }
1565
1566     OIC_LOG_V(INFO, TAG, "Leave processEntrySwitchDoorLockState() returns with ret=%d", ret);
1567     return ret;
1568 }
1569
1570 TWResultCode processEntryZCLDefaultResponse(TWEntry* entry, TWContext* ctx)
1571 {
1572     OIC_LOG(INFO, TAG, "Enter processEntryZCLDefaultResponse()");
1573
1574     TWResultCode ret = TW_RESULT_UNKNOWN;
1575
1576     if (strcmp((entry->atErrorCode), AT_STR_ERROR_EVERYTHING_OK) != 0)
1577     {
1578         if (strcmp(entry->atErrorCode, AT_STR_ERROR_MESSAGE_NOT_SENT_TO_TARGET_SUCCESSFULLY) == 0)
1579         {
1580             OIC_LOG(ERROR, TAG, "Send to the target not succeed.");
1581             ret = TW_RESULT_ERROR;
1582         }
1583         else
1584         {
1585             OIC_LOG_V(ERROR, TAG, "TWEntry contains AT_ERROR = %s", entry->atErrorCode);
1586             ret = TW_RESULT_ERROR;
1587         }
1588     }
1589     else
1590     {
1591         ret = HandleATResponse(entry,ctx);
1592     }
1593
1594     OIC_LOG_V(INFO, TAG, "Leave processEntryZCLDefaultResponse() returns with ret=%d", ret);
1595     return ret;
1596 }
1597
1598 TWResultCode processEntryZoneEnrollRequest(TWEntry* entry, TWContext* ctx)
1599 {
1600     OIC_LOG(INFO, TAG, "Enter processEntryZoneEnrollRequest()");
1601
1602     TWResultCode ret = TW_RESULT_UNKNOWN;
1603     if (strcmp(entry->atErrorCode, AT_STR_ERROR_EVERYTHING_OK) != 0)
1604     {
1605         OIC_LOG_V(ERROR, TAG, "TWEntry contains AT_ERROR: %s", entry->atErrorCode);
1606         ret = TW_RESULT_ERROR;
1607     }
1608     else
1609     {
1610         ret = HandleATResponse(entry,ctx);
1611     }
1612
1613     OIC_LOG_V(INFO, TAG, "Leave processEntryZoneEnrollRequest() with ret=%d", ret);
1614     return ret;
1615 }
1616
1617 TWResultCode processEntryEnrolled(TWEntry* entry, TWContext* ctx)
1618 {
1619     OIC_LOG(INFO, TAG, "Enter processEntryEnrolled()");
1620
1621     TWResultCode ret = TW_RESULT_UNKNOWN;
1622     if (strcmp(entry->atErrorCode, AT_STR_ERROR_EVERYTHING_OK) != 0)
1623     {
1624         OIC_LOG_V(ERROR, TAG, "TWEntry contains AT_ERROR: %s", entry->atErrorCode);
1625         ret = TW_RESULT_ERROR;
1626     }
1627     else
1628     {
1629         ret = HandleATResponse(entry,ctx);
1630     }
1631
1632     OIC_LOG_V(INFO, TAG, "Leave processEntryEnrolled() with ret=%d", ret);
1633     return ret;
1634 }
1635
1636 TWResultCode processEntryZoneStatus(TWEntry* entry, TWContext* ctx)
1637 {
1638     OIC_LOG(INFO, TAG, "Enter processEntryZoneStatus()");
1639
1640     TWResultCode ret = TW_RESULT_UNKNOWN;
1641     if (strcmp(entry->atErrorCode, AT_STR_ERROR_EVERYTHING_OK) != 0)
1642     {
1643         OIC_LOG_V(ERROR, TAG, "TWEntry contains AT_ERROR: %s", entry->atErrorCode);
1644         ret = TW_RESULT_ERROR;
1645     }
1646     else
1647     {
1648         ret = HandleATResponse(entry,ctx);
1649     }
1650
1651     OIC_LOG_V(INFO, TAG, "Leave processEntryZoneStatus() with ret=%d", ret);
1652     return ret;
1653 }
1654
1655 TWResultCode processEntryAddressResponse(TWEntry* entry, TWContext* ctx)
1656 {
1657     OIC_LOG(INFO, TAG, "Enter processEntryAddressResponse()");
1658
1659     TWResultCode ret = TW_RESULT_UNKNOWN;
1660     if (strcmp(entry->atErrorCode, AT_STR_ERROR_EVERYTHING_OK) != 0)
1661     {
1662         OIC_LOG_V(ERROR, TAG, "TWEntry contains AT_ERROR: %s", entry->atErrorCode);
1663         ret = TW_RESULT_ERROR;
1664     }
1665     else
1666     {
1667         ret = HandleATResponse(entry,ctx);
1668     }
1669
1670     OIC_LOG_V(INFO, TAG, "Leave processEntryAddressResponse() with ret=%d", ret);
1671     return ret;
1672 }
1673
1674 TWResultCode Reset(TWContext* ctx)
1675 {
1676     OIC_LOG(INFO, TAG, "Enter Reset()");
1677
1678     TWResultCode ret = TW_RESULT_ERROR;
1679     ret = TWIssueATCommand(ctx->g_plugin, AT_CMD_RESET);
1680     if (ret == TW_RESULT_OK)
1681     {
1682         OIC_LOG_V(INFO, TAG, "Write %s", AT_CMD_RESET);
1683     }
1684     else
1685     {
1686         OIC_LOG_V(ERROR, TAG, "Write %s", AT_CMD_RESET);
1687     }
1688     OIC_LOG_V(INFO, TAG, "Leave Reset() with ret=%d", ret);
1689     return ret;
1690 }
1691
1692 TWResultCode CreatePAN(TWContext* ctx)
1693 {
1694     /*
1695     //at+n
1696     //      +N=NoPAN
1697     //      OK
1698
1699     //at+n
1700     //      +N=COO,26,-6,7306,133F04EA669C6B24
1701     //      OK
1702
1703     //at+en
1704     //      OK
1705     //      JPAN:26,7306,133F04EA669C6B24
1706
1707     //at+en
1708     //      ERROR:28
1709     */
1710
1711     OIC_LOG(INFO, TAG, "Enter CreatePAN()");
1712
1713     TWResultCode twRet1 = TW_RESULT_UNKNOWN;
1714     TWResultCode twRet2 = TW_RESULT_UNKNOWN;
1715     TWResultCode ret = TW_RESULT_UNKNOWN;
1716     ret = TWIssueATCommand(ctx->g_plugin, AT_CMD_GET_NETWORK_INFO);
1717     if (ret != TW_RESULT_OK)
1718     {
1719         OIC_LOG_V(ERROR, TAG, "Write %s", AT_CMD_GET_NETWORK_INFO);
1720         goto exit;
1721     }
1722     OIC_LOG_V(INFO, TAG, "Write %s", AT_CMD_GET_NETWORK_INFO);
1723     TWEntry* entry = NULL;
1724     TWEntry* entry2 = NULL;
1725     ret = TWDequeueEntry(ctx->g_plugin, &entry, TW_NETWORK_INFO);
1726     if (ret != TW_RESULT_OK)
1727     {
1728         OIC_LOG_V(ERROR, TAG, "TWDequeueEntry - %s", AT_CMD_GET_NETWORK_INFO);
1729         goto exit;
1730     }
1731     if (entry == NULL)
1732     {
1733         OIC_LOG_V(ERROR, TAG, "TWEntry is NULL - %s", AT_CMD_GET_NETWORK_INFO);
1734         ret = TW_RESULT_ERROR;
1735         goto exit;
1736     }
1737     ret = processEntry(entry, ctx);
1738     if (ret == TW_RESULT_HAS_LOCAL_PAN)
1739     {
1740         OIC_LOG(INFO, TAG, "Has local PAN.");
1741         ret = TW_RESULT_OK;
1742     }
1743     else if (ret == TW_RESULT_NO_LOCAL_PAN)
1744     {
1745         OIC_LOG(INFO, TAG, "Has no local PAN.");
1746         ret = TWIssueATCommand(ctx->g_plugin, AT_CMD_ESTABLISH_NETWORK);
1747         if (ret != TW_RESULT_OK)
1748         {
1749             OIC_LOG_V(ERROR, TAG, "Write %s", AT_CMD_ESTABLISH_NETWORK);
1750             goto exit;
1751         }
1752         OIC_LOG_V(INFO, TAG, "Write %s", AT_CMD_ESTABLISH_NETWORK);
1753
1754         ret = TWDequeueEntry(ctx->g_plugin, &entry2, TW_JPAN);
1755         if (ret != TW_RESULT_OK)
1756         {
1757             OIC_LOG_V(ERROR, TAG, "TWDequeueEntry - %s", AT_CMD_ESTABLISH_NETWORK);
1758             goto exit;
1759         }
1760         if (entry2 == NULL)
1761         {
1762             OIC_LOG_V(ERROR, TAG, "TWEntry is NULL - %s", AT_CMD_ESTABLISH_NETWORK);
1763             ret = TW_RESULT_ERROR;
1764             goto exit;
1765         }
1766         ret = processEntry(entry2, ctx);
1767         if (ret == TW_RESULT_OK)
1768         {
1769             OIC_LOG_V(INFO, TAG, "processEntry - %s", AT_CMD_ESTABLISH_NETWORK);
1770             ret = TW_RESULT_OK;
1771         }
1772         else
1773         {
1774             OIC_LOG_V(ERROR, TAG, "processEntry - %s", AT_CMD_ESTABLISH_NETWORK);
1775             ret = TW_RESULT_ERROR;
1776         }
1777     }
1778     else
1779     {
1780         OIC_LOG_V(ERROR, TAG, "processEntry - unexpected return code: %d", ret);
1781         ret = TW_RESULT_ERROR;
1782     }
1783
1784 exit:
1785     if (entry)
1786     {
1787         twRet1 = TWDeleteEntry(ctx->g_plugin, entry);
1788         if(twRet1 != TW_RESULT_OK)
1789         {
1790             OIC_LOG_V(ERROR, TAG, "TWDeleteEntry 1 - ret=%d", twRet1);
1791         }
1792     }
1793     if (entry2)
1794     {
1795         twRet2 = TWDeleteEntry(ctx->g_plugin, entry2);
1796         if(twRet2 != TW_RESULT_OK)
1797         {
1798             OIC_LOG_V(ERROR, TAG, "TWDeleteEntry 2 - ret=%d", twRet2);
1799         }
1800     }
1801
1802     OIC_LOG_V(INFO, TAG, "Leave CreatePan with ret=%d", ret);
1803     return ret;
1804 }
1805
1806 TWContext * GetTWContext(PIPlugin_Zigbee* plugin)
1807 {
1808     if(!plugin)
1809     {
1810         return NULL;
1811     }
1812     TWContext * out = NULL;
1813     TWContext * tmp = NULL;
1814     LL_FOREACH_SAFE(g_twContextList, out, tmp)
1815     {
1816         if(out->g_plugin == plugin)
1817         {
1818             return out;
1819         }
1820     }
1821     return NULL;
1822 }
1823
1824 TWResultCode EnableJoin(bool isKeyEncrypted, TWContext* ctx)
1825 {
1826     //Ask:          AT+PJOIN
1827     //Response:     OK
1828
1829     //Ask:          AT+PJOIN
1830     //Response:     ERROR:70
1831
1832     (void)isKeyEncrypted;
1833     isKeyEncrypted = false;         //TODO: for now - don't encrypt
1834
1835     TWResultCode ret = TW_RESULT_ERROR;
1836     char* joinTimeHex = "0F";       //TODO: for now - 15 seconds
1837     char* broadcast = "FFFC";
1838
1839     int size =  strlen(AT_CMD_PERMIT_JOIN) + strlen(joinTimeHex) +
1840                 SEPARATOR_LENGTH + strlen(broadcast) + 1;
1841     char* cmdString = (char*)OICMalloc(size * sizeof(char));
1842     if (cmdString == NULL)
1843     {
1844         OIC_LOG(ERROR, TAG, "No Memory");
1845         ret = TW_RESULT_ERROR_NO_MEMORY;
1846         goto exit;
1847     }
1848     snprintf(cmdString, size, "%s%s%s%s",
1849              AT_CMD_PERMIT_JOIN, joinTimeHex, SEPARATOR, broadcast);
1850     ret = TWIssueATCommand(ctx->g_plugin, cmdString);
1851     if (ret != TW_RESULT_OK)
1852     {
1853         OIC_LOG_V(ERROR, TAG, "Write %s", cmdString);
1854         ret = TW_RESULT_ERROR;
1855         goto exit;
1856     }
1857     OIC_LOG_V(INFO, TAG, "Write %s", cmdString);
1858
1859     sleep(15);  //must sleep here to permit joining for 15 seconds
1860
1861 exit:
1862     OICFree(cmdString);
1863     OIC_LOG_V(INFO, TAG, "Leave EnableJoin() with ret=%d", ret);
1864     return ret;
1865 }
1866
1867 TWResultCode FindMatchNodes(TWContext* ctx)
1868 {
1869     //AT+MATCHREQ:0104,03,0003,0006,0402,00
1870     //      OK
1871     //      MatchDesc:0B4A,00,01
1872
1873     //AT+MATCHREQ:0104,03,0999,0999,0999,00
1874     //      OK
1875
1876     OIC_LOG(INFO, TAG, "Enter FindMatchNodes()");
1877
1878     TWResultCode ret = TW_RESULT_UNKNOWN;
1879
1880     //TODO: add more clusters if needed
1881
1882     int size = strlen(AT_CMD_MATCH_REQUEST) + strlen(ZB_PROFILE_ID_HOME_AUTOMATION) +
1883                SEPARATOR_LENGTH + strlen(IN_CLUSTER_COUNT_STRING) +
1884                SEPARATOR_LENGTH + strlen(ZB_CLUSTER_IDENTIFY) +
1885                SEPARATOR_LENGTH + strlen(ZB_CLUSTER_ON_OFF) +
1886                SEPARATOR_LENGTH + strlen(ZB_CLUSTER_TEMPERATURE_MEASUREMENT) +
1887                SEPARATOR_LENGTH + strlen(ZB_CLUSTER_IAS_ZONE) +
1888                SEPARATOR_LENGTH + strlen(ZB_CLUSTER_COLOR_CONTROL) +
1889                SEPARATOR_LENGTH + strlen(OUT_CLUSTER_COUNT_STRING) + 1;
1890
1891     char* cmdString = (char*)OICMalloc(size * sizeof(char));
1892     if (cmdString == NULL)
1893     {
1894         OIC_LOG(ERROR, TAG, "No Memory");
1895         ret = TW_RESULT_ERROR_NO_MEMORY;
1896         goto exit;
1897     }
1898
1899     int stringRet = snprintf(cmdString, size, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
1900                              AT_CMD_MATCH_REQUEST, ZB_PROFILE_ID_HOME_AUTOMATION,
1901                              SEPARATOR, IN_CLUSTER_COUNT_STRING,
1902                              SEPARATOR, ZB_CLUSTER_IDENTIFY,
1903                              SEPARATOR, ZB_CLUSTER_ON_OFF,
1904                              SEPARATOR, ZB_CLUSTER_TEMPERATURE_MEASUREMENT,
1905                              SEPARATOR, ZB_CLUSTER_IAS_ZONE,
1906                              SEPARATOR, ZB_CLUSTER_COLOR_CONTROL,
1907                              SEPARATOR, OUT_CLUSTER_COUNT_STRING);
1908     if(stringRet <= 0)
1909     {
1910         OIC_LOG(ERROR, TAG, "Build command error.");
1911         ret = OC_STACK_ERROR;
1912         goto exit;
1913     }
1914     ret = TWIssueATCommand(ctx->g_plugin, cmdString);
1915     if (ret != TW_RESULT_OK)
1916     {
1917         OIC_LOG_V(ERROR, TAG, "Write %s.", cmdString);
1918         goto exit;
1919     }
1920     OIC_LOG_V(INFO, TAG, "Write %s.", cmdString);
1921
1922 exit:
1923     OICFree(cmdString);
1924     OIC_LOG_V(INFO, TAG, "Leave FindMatchNodes() with ret=%d", ret);
1925     return ret;
1926 }
1927
1928 TWResultCode FindClusters(char nodeId[], char endpoint[], TWContext* ctx)
1929 {
1930     /*
1931     //AT+SIMPLEDESC:3746,3746,01
1932     //      SEQ:97
1933     //      OK
1934     //
1935     //      SimpleDesc:3746,00
1936     //      EP:01
1937     //      ProfileID:0104
1938     //      DeviceID:0402v00
1939     //      InCluster:0000,0001,0003,0402,0500,0020,0B05
1940     //      OutCluster:0019
1941     //
1942     //      ACK:97
1943     */
1944
1945     OIC_LOG(INFO, TAG, "Enter FindClusters()");
1946
1947     TWResultCode ret = TW_RESULT_UNKNOWN;
1948
1949     int size = strlen(AT_CMD_SIMPLE_DESC) + strlen(nodeId) +
1950                SEPARATOR_LENGTH + strlen(nodeId) +
1951                SEPARATOR_LENGTH + strlen(endpoint) + 1;
1952
1953     char* cmdString = (char*)OICMalloc(size * sizeof(char));
1954     if (cmdString == NULL)
1955     {
1956         OIC_LOG(ERROR, TAG, "No Memory");
1957         ret = TW_RESULT_ERROR_NO_MEMORY;
1958         goto exit;
1959     }
1960
1961     int stringRet = snprintf(cmdString, size, "%s%s%s%s%s%s",
1962                              AT_CMD_SIMPLE_DESC, nodeId,
1963                              SEPARATOR, nodeId,
1964                              SEPARATOR, endpoint);
1965     if(stringRet <= 0)
1966     {
1967         OIC_LOG(ERROR, TAG, "Build command error.");
1968         ret = OC_STACK_ERROR;
1969         goto exit;
1970     }
1971     ret = TWIssueATCommand(ctx->g_plugin, cmdString);
1972     if (ret != TW_RESULT_OK)
1973     {
1974         OIC_LOG_V(ERROR, TAG, "Write %s", cmdString);
1975         ret = TW_RESULT_ERROR;
1976         goto exit;
1977     }
1978     OIC_LOG_V(INFO, TAG, "Write %s", cmdString);
1979
1980     TWEntry* entry = NULL;
1981     ret = TWDequeueEntry(ctx->g_plugin, &entry, TW_SIMPLEDESC);
1982     if (ret != TW_RESULT_OK)
1983     {
1984         OIC_LOG_V(ERROR, TAG, "TWDequeueEntry - %s", cmdString);
1985         goto exit;
1986     }
1987     if (entry == NULL)
1988     {
1989         OIC_LOG_V(ERROR, TAG, "TWEntry is NULL - %s", cmdString);
1990         ret = TW_RESULT_ERROR;
1991         goto exit;
1992     }
1993
1994     ret = processEntry(entry, ctx);
1995     if (ret == TW_RESULT_OK)
1996     {
1997         OIC_LOG_V(INFO, TAG, "processEntry - %s", cmdString);
1998     }
1999     else
2000     {
2001         OIC_LOG_V(ERROR, TAG, "processEntry - %s", cmdString);
2002     }
2003
2004 exit:
2005     TWDeleteEntry(ctx->g_plugin, entry);
2006     OICFree(cmdString);
2007     OIC_LOG_V(INFO, TAG, "Leave FindClusters() with ret=%d", ret);
2008     return ret;
2009 }
2010
2011 TWResultCode GetRemoteEUI(char *nodeId, char* outRemoteEUI, TWContext* ctx)
2012 {
2013     //AT+EUIREQ:< Address>,<NodeID>[,XX]
2014     //  AddrResp:<errorcode>[,<NodeID>,<EUI64>]
2015     //  AddrResp:00,15ED,000D6F00040574B8
2016
2017     OIC_LOG(INFO, TAG, "Enter GetRemoteEUI()");
2018     TWResultCode ret = TW_RESULT_UNKNOWN;
2019
2020     int size = strlen(AT_CMD_REMOTE_EUI_REQUEST) + strlen(nodeId) +
2021                SEPARATOR_LENGTH + strlen(nodeId) + 1;
2022     char* cmdString = (char*)OICMalloc(size * sizeof(char));
2023     if (cmdString == NULL)
2024     {
2025         OIC_LOG(ERROR, TAG, "No Memory");
2026         ret = TW_RESULT_ERROR_NO_MEMORY;
2027         goto exit;
2028     }
2029
2030     int stringRet = snprintf(cmdString, size, "%s%s%s%s",
2031                          AT_CMD_REMOTE_EUI_REQUEST, nodeId,
2032                          SEPARATOR, nodeId);
2033     if(stringRet <= 0)
2034     {
2035         OIC_LOG(ERROR, TAG, "Build command error.");
2036         ret = OC_STACK_ERROR;
2037         goto exit;
2038     }
2039     ret = TWIssueATCommand(ctx->g_plugin, cmdString);
2040     if (ret != TW_RESULT_OK)
2041     {
2042         OIC_LOG_V(ERROR, TAG, "Write %s", cmdString);
2043         ret = TW_RESULT_ERROR;
2044         goto exit;
2045     }
2046     OIC_LOG_V(INFO, TAG, "Write %s", cmdString);
2047
2048     TWEntry* entry = NULL;
2049     ret = TWDequeueEntry(ctx->g_plugin, &entry, TW_ADDRESS_RESPONSE);
2050     if (ret != TW_RESULT_OK)
2051     {
2052         OIC_LOG_V(ERROR, TAG, "TWDequeueEntry - %s", cmdString);
2053         ret = TW_RESULT_ERROR;
2054         goto exit;
2055     }
2056     if (entry == NULL)
2057     {
2058         OIC_LOG_V(ERROR, TAG, "TWEntry is NULL - %s", cmdString);
2059         ret = TW_RESULT_ERROR;
2060         goto exit;
2061     }
2062
2063     ret = processEntry(entry, ctx);
2064     if (ret != TW_RESULT_OK)
2065     {
2066         OIC_LOG_V(ERROR, TAG, "processEntry - %s", cmdString);
2067         ret = TW_RESULT_ERROR;
2068         goto exit;
2069     }
2070     OIC_LOG_V(INFO, TAG, "Wanted   eui of NodeID=%s ", nodeId);
2071     OIC_LOG_V(INFO, TAG, "Received eui of g_WIPRemoteNodeId=%s ", ctx->g_WIPRemoteNodeId);
2072     if (strcmp(nodeId, ctx->g_WIPRemoteNodeId) != 0)
2073     {
2074         OIC_LOG(ERROR, TAG, "Received eui for an unexpected remote node id.");
2075         ret = TW_RESULT_ERROR;
2076         goto exit;
2077     }
2078
2079     OIC_LOG_V(INFO, TAG, "Remote NodeId:%s has EUI: %s \n",
2080                         ctx->g_WIPRemoteNodeId, ctx->g_WIPRemoteEUI);
2081     OICStrcpy(outRemoteEUI, sizeof(ctx->g_WIPRemoteEUI), ctx->g_WIPRemoteEUI);
2082
2083     ret = TW_RESULT_OK;
2084
2085 exit:
2086     memset(ctx->g_WIPRemoteEUI, '\0', sizeof(ctx->g_WIPRemoteEUI));
2087     memset(ctx->g_WIPRemoteNodeId, '\0', sizeof(ctx->g_WIPRemoteNodeId));
2088     TWDeleteEntry(ctx->g_plugin, entry);
2089     OICFree(cmdString);
2090     OIC_LOG_V(INFO, TAG, "Leave GetRemoteEUI() with ret=%d", ret);
2091     return ret;
2092 }
2093
2094 TWResultCode HandleATResponse(TWEntry* entry, TWContext* ctx)
2095 {
2096     OIC_LOG(INFO, TAG, "Enter HandleATResponse()");
2097
2098     TWResultCode ret = TW_RESULT_ERROR;
2099
2100     int32_t i = 0;
2101     for (; i < entry->count; i++)
2102     {
2103         uint32_t k = 0;
2104         for (; k < sizeof(g_TWATResultHandlerPairArray)/sizeof(TWATResultHandlerPair); ++k)
2105         {
2106             const char* line = (entry)->lines[i].line;
2107             if (strncmp(line,
2108                         g_TWATResultHandlerPairArray[k].resultTxt,
2109                         strlen(g_TWATResultHandlerPairArray[k].resultTxt)
2110                         ) == 0)
2111             {
2112                 char* tokens[ARRAY_LENGTH] = {};
2113                 const char* delimiters = ",\r\n";
2114                 int paramCount = Tokenize((entry)->lines[i].line +
2115                                            strlen(g_TWATResultHandlerPairArray[k].resultTxt),
2116                                            delimiters, tokens);
2117                 if (paramCount > 0)
2118                 {
2119                     ret = g_TWATResultHandlerPairArray[k].handler(paramCount, tokens, ctx);
2120                 }
2121
2122                 int n = 0;
2123                 for (; n < paramCount; n++)
2124                 {
2125                     OICFree(tokens[n]);
2126                 }
2127
2128                 break;
2129             }
2130         }
2131     }
2132
2133     OIC_LOG_V(INFO, TAG, "Leave HandleATResponse() with ret=%d", ret);
2134     return ret;
2135 }
2136
2137 //-----------------------------------------------------------------------------
2138 // Internal functions - AT Response/Prompt Handlers
2139 //-----------------------------------------------------------------------------
2140
2141 TWResultCode TelAddressResponseHandler(int count, char* tokens[], TWContext* ctx)
2142 {
2143     //AT+EUIREQ:< Address>,<NodeID>[,XX]
2144     //  AddrResp:<errorcode>[,<NodeID>,<EUI64>]
2145     //  AddrResp:00,15ED,000D6F00040574B8
2146
2147     OIC_LOG(INFO, TAG, "Enter TelAddressResponseHandler()");
2148
2149     TWResultCode ret = TW_RESULT_UNKNOWN;
2150
2151     if(!tokens || count != RESPONSE_PARAMS_COUNT_ADDRESS_RESPONSE)
2152     {
2153         ret = TW_RESULT_ERROR_INVALID_PARAMS;
2154     }
2155     else
2156     {
2157         if (strcmp(tokens[TOKEN_ADDRRESP_STATUS_CODE], AT_STR_ERROR_OK) != 0)
2158         {
2159             OIC_LOG(ERROR, TAG, "AddrResp prompt contained error status.");
2160             ret = TW_RESULT_ERROR;
2161         }
2162         else
2163         {
2164             OICStrcpy(ctx->g_WIPRemoteNodeId, SIZE_NODEID, tokens[TOKEN_ADDRRESP_NODEID]);
2165             OICStrcpy(ctx->g_WIPRemoteEUI, SIZE_EUI, tokens[TOKEN_ADDRRESP_EUI]);
2166             OIC_LOG_V(INFO, TAG, "Received eui %s for g_WIPRemoteNodeId=%s ",
2167                      ctx->g_WIPRemoteEUI,
2168                      ctx->g_WIPRemoteNodeId);
2169             ret = TW_RESULT_OK;
2170         }
2171     }
2172
2173     OIC_LOG_V(INFO, TAG, "Leave TelAddressResponseHandler() with ret=%d", ret);
2174     return ret;
2175 }
2176
2177 TWResultCode TelNetworkInfoHandler(int count, char* tokens[], TWContext* ctx)
2178 {
2179     // Ask:         AT+N
2180     // Response:    +N=COO,24,-6,9726,12BB200F073AB573
2181     //                          or
2182     //              +N=NoPAN
2183     //
2184     //              +N=<devicetype>,<channel>,<power>,<PANID>,<EPANID>
2185
2186     OIC_LOG(INFO, TAG, "Enter TelNetworkInfoHandler()");
2187
2188     TWResultCode ret = TW_RESULT_UNKNOWN;
2189
2190     if(!tokens ||
2191        ((count != RESPONSE_PARAMS_COUNT_NETWORK_INFO_1) &&
2192         (count != RESPONSE_PARAMS_COUNT_NETWORK_INFO_5)))
2193     {
2194         ret = TW_RESULT_ERROR_INVALID_PARAMS;
2195         goto exit;
2196     }
2197
2198     int i = 0;
2199     for (; i < count; ++i)
2200     {
2201         if (tokens[i] != NULL)
2202         {
2203             OIC_LOG_V(INFO, TAG, "Token[%d] = %s", i, tokens[i]);
2204         }
2205     }
2206
2207     char* temp = tokens[TOKEN_PLUS_N_DEVICE_TYPE];
2208     if (strcmp(temp, "NoPAN") == 0)
2209     {
2210         OIC_LOG(INFO, TAG, "It is NoPan.");
2211         ret = TW_RESULT_NO_LOCAL_PAN;
2212         goto exit;
2213     }
2214
2215     OIC_LOG(INFO, TAG, "Already have an established network.");
2216     ret = AsciiHexToValue(tokens[TOKEN_PLUS_N_PANID],
2217                           strlen(tokens[TOKEN_PLUS_N_PANID]),
2218                           &(ctx->g_ZigBeeStatus.panId));
2219     if(ret != TW_RESULT_OK)
2220     {
2221         OIC_LOG(ERROR, TAG, "AsciiHexToValue - panId");
2222         goto exit;
2223     }
2224
2225     ret = AsciiHexToValue(tokens[TOKEN_PLUS_N_PANID_EXTENDED],
2226                           strlen(tokens[TOKEN_PLUS_N_PANID_EXTENDED]),
2227                           &(ctx->g_ZigBeeStatus.extPanId));
2228     if(ret != TW_RESULT_OK)
2229     {
2230         OIC_LOG(ERROR, TAG, "AsciiHexToValue - extPanId");
2231         goto exit;
2232     }
2233     OIC_LOG_V(INFO, TAG, "PanId=%" PRId64 , ctx->g_ZigBeeStatus.panId);
2234     OIC_LOG_V(INFO, TAG, "ExtPanId=%" PRId64 , ctx->g_ZigBeeStatus.extPanId);
2235     OIC_LOG_V(INFO, TAG, "PanId=%s", tokens[TOKEN_PLUS_N_PANID]);
2236     OIC_LOG_V(INFO, TAG, "ExtPanId=%s", tokens[TOKEN_PLUS_N_PANID_EXTENDED]);
2237
2238     OIC_LOG_V(INFO, TAG, "TelNetworkInfoHandler set ExtPanId to %08X%08X",
2239              (unsigned int)(ctx->g_ZigBeeStatus.extPanId >> 32),
2240              (unsigned int)(ctx->g_ZigBeeStatus.extPanId & 0xFFFFFFFF));
2241
2242     ret = TW_RESULT_HAS_LOCAL_PAN;
2243
2244 exit:
2245     OIC_LOG_V(INFO, TAG, "Leave TelNetworkInfoHandler() with ret=%d", ret);
2246     return ret;
2247 }
2248
2249 TWResultCode TelJpanHandler(int count, char* tokens[], TWContext* ctx)
2250 {
2251     //Ask:        AT+EN:[<channel>],[<POWER>],[<PANID>]
2252     //Response:   JPAN:<channel>,<PANID>,<EPANID>
2253
2254     OIC_LOG(INFO, TAG, "Enter TelJpanHandler()");
2255
2256     TWResultCode ret = TW_RESULT_UNKNOWN;
2257
2258     if(!tokens || count != RESPONSE_PARAMS_COUNT_JPAN)
2259     {
2260         ret = TW_RESULT_ERROR_INVALID_PARAMS;
2261         goto exit;
2262     }
2263
2264     ret = AsciiHexToValue(tokens[TOKEN_JPAN_PANID],
2265                           strlen(tokens[TOKEN_JPAN_PANID]),
2266                           &(ctx->g_ZigBeeStatus.panId));
2267
2268     if(ret != TW_RESULT_OK)
2269     {
2270         OIC_LOG(ERROR, TAG, "AsciiHexToValue - panId");
2271         goto exit;
2272     }
2273
2274     ret = AsciiHexToValue(tokens[TOKEN_JPAN_PANID_EXTENDED],
2275                           strlen(tokens[TOKEN_JPAN_PANID_EXTENDED]),
2276                           &(ctx->g_ZigBeeStatus.extPanId));
2277     if(ret != TW_RESULT_OK)
2278     {
2279         OIC_LOG(ERROR, TAG, "AsciiHexToValue - extPanId");
2280         goto exit;
2281     }
2282     OIC_LOG_V(INFO, TAG, "PanId = %" PRId64 "\n", ctx->g_ZigBeeStatus.panId);
2283     OIC_LOG_V(INFO, TAG, "ExtPanId = %" PRId64 "\n", ctx->g_ZigBeeStatus.extPanId);
2284     ret = TW_RESULT_NEW_LOCAL_PAN_ESTABLISHED;
2285
2286 exit:
2287     OIC_LOG_V(INFO, TAG, "Leave TelJpanHandler() with ret=%d", ret);
2288     return ret;
2289 }
2290
2291 TWResultCode TelEndDeviceJoinHandler(int count, char* tokens[], TWContext* ctx)
2292 {
2293     //Ask:      AT+PJOIN
2294     //
2295     //Prompt:   RFD:<IEEE Address>,<NodeID>
2296     //Prompt:   FFD:<IEEE Address>,<NodeID>
2297     //Prompt:   SED:<IEEE Address>,<NodeID>
2298     //Prompt:   ZED:<IEEE Address>,<NodeID>
2299
2300     OIC_LOG(INFO, TAG, "Enter TelEndDeviceJoinHandler()");
2301     TWResultCode ret = TW_RESULT_UNKNOWN;
2302
2303     if(!tokens || count != RESPONSE_PARAMS_COUNT_DEVICE_JOINED)
2304     {
2305         ret = TW_RESULT_ERROR_INVALID_PARAMS;
2306         goto exit;
2307     }
2308
2309     //TODO: Might need to add into the list if needed - log it for now.
2310     OIC_LOG_V(INFO, TAG, "Received RFD/FFD/SED/ZED - EUI:%s; NodeID:%s.\n",
2311             tokens[TOKEN_PJOIN_RESPONSE_IEEE_ADDRESS],
2312             tokens[TOKEN_PJOIN_RESPONSE_NODEID]);
2313
2314     if (ctx->g_EndDeviceNodeIdChangedCallback != NULL)
2315     {
2316         ctx->g_EndDeviceNodeIdChangedCallback(tokens[TOKEN_PJOIN_RESPONSE_IEEE_ADDRESS],
2317                                               tokens[TOKEN_PJOIN_RESPONSE_NODEID],
2318                                               ctx->g_plugin);
2319     }
2320
2321     ret = TW_RESULT_OK;
2322
2323 exit:
2324     OIC_LOG_V(INFO, TAG, "Leave TelEndDeviceJoinHandler() with ret=%d", ret);
2325     return ret;
2326 }
2327
2328 TWResultCode TelMatchDescHandler(int count, char* tokens[], TWContext* ctx)
2329 {
2330     //Prompt:       MatchDesc:0B4A,00,01
2331
2332     OIC_LOG(INFO, TAG, "Enter TelMatchDescHandler()");
2333     TWResultCode ret = TW_RESULT_ERROR;
2334
2335     if(!tokens || count != RESPONSE_PARAMS_COUNT_MATCH_DESC)
2336     {
2337         ret = TW_RESULT_ERROR_INVALID_PARAMS;
2338         goto exit;
2339     }
2340
2341     if (strcmp(tokens[TOKEN_MATCHDESC_STATUS_CODE], AT_STR_ERROR_OK) != 0)
2342     {
2343         OIC_LOG(INFO, TAG, "MatchDesc prompt contained error status.");
2344         ret = TW_RESULT_ERROR;
2345         goto exit;
2346     }
2347     else
2348     {
2349         char remoteEUI[SIZE_EUI];
2350         ret = GetRemoteEUI(tokens[TOKEN_MATCHDESC_NODEID], remoteEUI, ctx);
2351         if (ret != TW_RESULT_OK)
2352         {
2353             OIC_LOG(ERROR, TAG, "GetRemoteEUI()");
2354             goto exit;
2355         }
2356         else
2357         {
2358             //Step 1: Create TWDevice
2359             TWDevice* device = (TWDevice*)OICCalloc(1, sizeof(TWDevice));
2360             if (device == NULL)
2361             {
2362                 ret = TW_RESULT_ERROR_NO_MEMORY;
2363                 goto exit;
2364             }
2365             else
2366             {
2367                 device->endpointOfInterest = (TWEndpoint*)OICCalloc(1, sizeof(TWEndpoint));
2368                 if (device->endpointOfInterest == NULL)
2369                 {
2370                     OICFree(device);
2371                     ret = TW_RESULT_ERROR_NO_MEMORY;
2372                 }
2373                 else
2374                 {
2375                     OICStrcpy(device->eui, SIZE_EUI, remoteEUI);
2376                     OICStrcpy(device->nodeId, SIZE_NODEID, tokens[TOKEN_MATCHDESC_NODEID]);
2377                     OICStrcpy(device->endpointOfInterest->endpointId,
2378                               SIZE_ENDPOINTID,
2379                               tokens[TOKEN_MATCHDESC_ENDPOINTID]);
2380                     ctx->g_WIPDevice = device;
2381
2382                     //Step 2: Add to list
2383                     if (ctx->g_FoundMatchedDeviceList == NULL)
2384                     {
2385                         //Create a list of promptCount entries
2386                         ctx->g_FoundMatchedDeviceList =
2387                                 (TWDeviceList*)OICMalloc(sizeof(TWDeviceList));
2388                         if (ctx->g_FoundMatchedDeviceList == NULL)
2389                         {
2390                             OICFree(device->endpointOfInterest);
2391                             OICFree(device);
2392                             ret = TW_RESULT_ERROR_NO_MEMORY;
2393                         }
2394                         else
2395                         {
2396                             ctx->g_FoundMatchedDeviceList->count = 1;
2397                             ctx->g_FoundMatchedDeviceList->deviceList =
2398                                     (TWDevice*)OICMalloc(sizeof(TWDevice));
2399                             if (ctx->g_FoundMatchedDeviceList->deviceList == NULL)
2400                             {
2401                                 OICFree(device->endpointOfInterest);
2402                                 OICFree(device);
2403                                 ret = TW_RESULT_ERROR_NO_MEMORY;
2404                             }
2405                             else
2406                             {
2407                                 memcpy(ctx->g_FoundMatchedDeviceList->deviceList,
2408                                        device,
2409                                        sizeof(TWDevice));
2410                                 ret = TW_RESULT_OK;
2411                             }
2412                         }
2413                     }
2414                     else
2415                     {
2416                         //Expand the list
2417                         int newSize = sizeof(TWDevice)*(ctx->g_FoundMatchedDeviceList->count + 1);
2418                         TWDevice* temp =
2419                                 (TWDevice*)realloc(ctx->g_FoundMatchedDeviceList->deviceList,
2420                                                    newSize);
2421                         if (temp == NULL)
2422                         {
2423                             OICFree(device->endpointOfInterest);
2424                             OICFree(device);
2425                             ret =TW_RESULT_ERROR_NO_MEMORY;
2426                         }
2427                         else
2428                         {
2429                             ctx->g_FoundMatchedDeviceList->deviceList = temp;
2430
2431                             //Add to the end of list
2432                             int count = ctx->g_FoundMatchedDeviceList->count;
2433                             memcpy(&(ctx->g_FoundMatchedDeviceList->deviceList[count]),
2434                                    device,
2435                                    sizeof(TWDevice));
2436
2437                             //Increase the count
2438                             ctx->g_FoundMatchedDeviceList->count++;
2439
2440                             ret = TW_RESULT_OK;
2441                         }
2442                     }
2443                 }
2444             }
2445         }
2446     }
2447
2448 exit:
2449     OIC_LOG_V(INFO, TAG, "Leave TelMatchDescHandler() with ret=%d", ret);
2450     return ret;
2451 }
2452
2453 TWResultCode TelSimpleDescHandler(int count, char* tokens[], TWContext* ctx)
2454 {
2455     //AT+SIMPLEDESC:3746,3746,01
2456     //      SEQ:97
2457     //      OK
2458     //
2459     //      SimpleDesc:3746,00              <<<<<<<---------------------
2460     //      EP:01
2461     //      ProfileID:0104
2462     //      DeviceID:0402v00
2463     //      InCluster:0000,0001,0003,0402,0500,0020,0B05
2464     //      OutCluster:0019
2465     //      ACK:97
2466
2467     OIC_LOG(INFO, TAG, "Enter TelSimpleDescHandler().");
2468     TWResultCode ret = TW_RESULT_UNKNOWN;
2469
2470     if(!tokens || count != RESPONSE_PARAMS_COUNT_SIMPLE_DESC)
2471     {
2472         ret = TW_RESULT_ERROR_INVALID_PARAMS;
2473         goto exit;
2474     }
2475
2476     if (ctx->g_WIPDevice == NULL)
2477     {
2478         OIC_LOG_V(ERROR, TAG,
2479                  "Receive simple descriptor unexpectedly - %s",
2480                  tokens[TOKEN_SIMPLEDESC_SIMPLEDESC_NODEID]);
2481         ret = TW_RESULT_ERROR;
2482         goto exit;
2483     }
2484
2485     if (strcmp(tokens[TOKEN_SIMPLEDESC_SIMPLEDESC_STATUS_CODE], AT_STR_ERROR_OK) != 0)
2486     {
2487         OIC_LOG_V(ERROR,
2488                  TAG,
2489                  "SimpleDesc: prompt contained error status %s.",
2490                  tokens[TOKEN_SIMPLEDESC_SIMPLEDESC_STATUS_CODE]);
2491         ret = TW_RESULT_ERROR;
2492     }
2493     else
2494     {
2495         if (strcmp(tokens[TOKEN_SIMPLEDESC_SIMPLEDESC_NODEID],
2496                    ctx->g_WIPDevice->nodeId) == 0)
2497         {
2498             OIC_LOG_V(INFO,
2499                      TAG,
2500                      "Got simple descriptor for nodeid %s",
2501                      tokens[TOKEN_SIMPLEDESC_SIMPLEDESC_NODEID]);
2502             ret = TW_RESULT_OK;
2503         }
2504         else
2505         {
2506             OIC_LOG_V(ERROR,
2507                      TAG,
2508                      "Finding simple descriptor for non existing nodeid %s.",
2509                      tokens[TOKEN_SIMPLEDESC_SIMPLEDESC_NODEID]);
2510             ret = TW_RESULT_ERROR;
2511         }
2512     }
2513
2514 exit:
2515     OIC_LOG_V(INFO, TAG, "Leave TelSimpleDescHandler() with ret=%d", ret);
2516     return ret;
2517 }
2518
2519 TWResultCode TelSimpleDescInClusterHandler(int count, char* tokens[], TWContext* ctx)
2520 {
2521     //AT+SIMPLEDESC:3746,3746,01
2522     //      SEQ:97
2523     //      OK
2524     //
2525     //      SimpleDesc:3746,00
2526     //      EP:01
2527     //      ProfileID:0104
2528     //      DeviceID:0402v00
2529     //      InCluster:0000,0001,0003,0402,0500,0020,0B05        <<<<<<<<--------------
2530     //      OutCluster:0019
2531     //      ACK:97
2532
2533     OIC_LOG(INFO, TAG, "Enter TelSimpleDescInClusterHandler()");
2534     TWResultCode ret = TW_RESULT_ERROR;
2535
2536     if (!tokens || count < RESPONSE_PARAMS_COUNT_SIMPLE_DESC_IN_CLUSTER_MIN )
2537     {
2538         OIC_LOG(ERROR, TAG, "Invalid Params");
2539         ret = TW_RESULT_ERROR_INVALID_PARAMS;
2540                 goto exit;
2541     }
2542
2543     if (ctx->g_WIPDevice == NULL)
2544     {
2545         OIC_LOG_V(ERROR, TAG,
2546                  "Receive simple descriptor unexpectedly - %s",
2547                  tokens[TOKEN_SIMPLEDESC_INCLUSTER_STRING]);
2548         ret = TW_RESULT_ERROR;
2549         goto exit;
2550     }
2551
2552     if (ctx->g_WIPDevice->endpointOfInterest->clusterList != NULL)
2553     {
2554         OIC_LOG(ERROR, TAG, "Expected an empty cluster list.");
2555         ret = TW_RESULT_ERROR;
2556         goto exit;
2557     }
2558
2559     //Add found clusters for the node.
2560     ctx->g_WIPDevice->endpointOfInterest->clusterList =
2561             (TWClusterList*)OICMalloc(sizeof(TWClusterList));
2562     if (ctx->g_WIPDevice->endpointOfInterest->clusterList == NULL)
2563     {
2564         OIC_LOG(ERROR, TAG, "No Memory - clusterList");
2565         ret = TW_RESULT_ERROR_NO_MEMORY;
2566         goto exit;
2567     }
2568
2569     ctx->g_WIPDevice->endpointOfInterest->clusterList->clusterIds =
2570             (TWClusterId*)OICMalloc(sizeof(TWClusterId) * count);
2571     if (ctx->g_WIPDevice->endpointOfInterest->clusterList->clusterIds == NULL)
2572     {
2573         OICFree(ctx->g_WIPDevice->endpointOfInterest->clusterList);
2574         OIC_LOG(ERROR, TAG, "No Memory - clusterIds");
2575         ret = TW_RESULT_ERROR_NO_MEMORY;
2576         goto exit;
2577     }
2578
2579     int i = 0;
2580     for (; i < count; i++)
2581     {
2582         OICStrcpy(ctx->g_WIPDevice->endpointOfInterest->clusterList->clusterIds[i].clusterId,
2583                   SIZE_CLUSTERID,
2584                   tokens[i]);
2585
2586         OIC_LOG_V(INFO, TAG, "ClusterIds[%d]=%s",
2587                  i,
2588                  ctx->g_WIPDevice->endpointOfInterest->clusterList->clusterIds[i].clusterId);
2589     }
2590     ctx->g_WIPDevice->endpointOfInterest->clusterList->count = count;
2591     ret = TW_RESULT_HAS_CLUSTERS;
2592
2593 exit:
2594     OIC_LOG_V(INFO, TAG, "Leave TelSimpleDescInClusterHandler() with ret=%d", ret);
2595     return ret;
2596 }
2597
2598 TWResultCode TelWriteAttrHandler(int count, char* tokens[], TWContext* ctx)
2599 {
2600     //AT+WRITEATR:3A3D,01,0,0003,0000,21,00
2601     //      OK
2602     //      WRITEATTR:3A3D,01,0003,,00
2603     //
2604     //AT+WRITEATR:B826,01,0,0500,0010,F0,000D6F0000D59E92
2605     //      OK
2606     //      WRITEATTR:B826,01,0500,0010,70
2607
2608     OIC_LOG(INFO, TAG, "Enter TelWriteAttrHandler()");
2609     (void)ctx;
2610
2611     TWResultCode ret = TW_RESULT_ERROR;
2612
2613     if(!tokens ||
2614        (count < RESPONSE_PARAMS_COUNT_WRITE_ATTR_4) ||
2615        (count > RESPONSE_PARAMS_COUNT_WRITE_ATTR_5))
2616     {
2617         ret = TW_RESULT_ERROR_INVALID_PARAMS;
2618         goto exit;
2619     }
2620
2621     if (count == RESPONSE_PARAMS_COUNT_WRITE_ATTR_4)
2622     {
2623         if (strcmp(tokens[TOKEN_WRITEATTR_STATUS_CODE], AT_STR_ERROR_OK) == 0)
2624         {
2625             ret = TW_RESULT_OK;
2626         }
2627         else if (strcmp(tokens[TOKEN_WRITEATTR_STATUS_CODE], AT_STR_ERROR_INVALID_OP) == 0)
2628         {
2629             ret = TW_RESULT_ERROR_INVALID_OP;
2630         }
2631     }
2632     else if (count == RESPONSE_PARAMS_COUNT_WRITE_ATTR_5)
2633     {
2634         if (strcmp(tokens[TOKEN_WRITEATTR_STATUS_CODE_ALTERNATIVE], AT_STR_ERROR_OK) == 0)
2635         {
2636             ret = TW_RESULT_OK;
2637         }
2638         else if (strcmp(tokens[TOKEN_WRITEATTR_STATUS_CODE_ALTERNATIVE],
2639                         AT_STR_ERROR_INVALID_OP) == 0)
2640         {
2641             ret = TW_RESULT_ERROR_INVALID_OP;
2642         }
2643     }
2644
2645 exit:
2646     OIC_LOG_V(INFO, TAG, "Leave TelWriteAttrHandler() with ret=%d", ret);
2647     return ret;
2648 }
2649
2650 TWResultCode TelReadAttrHandlerTemperature(int count, char* tokens[], TWContext* ctx)
2651 {
2652     //AT+READATR:F2D7,01,0,0402,0002
2653     //      OK
2654     //      TEMPERATURE:F2D7,01,0002,00,1770
2655     //
2656     //AT+READATR:F2D7,01,0,0402,0002
2657     //      OK
2658     //      ERROR:66
2659
2660     OIC_LOG(INFO, TAG, "Enter TelReadAttrHandlerTemperature().");
2661     TWResultCode ret = TW_RESULT_UNKNOWN;
2662
2663     if(!tokens || count != RESPONSE_PARAMS_COUNT_TEMPERATURE)
2664     {
2665         OIC_LOG(ERROR, TAG, "Invalid Params");
2666         ret = TW_RESULT_ERROR_INVALID_PARAMS;
2667         goto exit;
2668     }
2669
2670     if (strcmp(tokens[TOKEN_TEMPERATURE_STATUS_CODE], AT_STR_ERROR_OK) != 0)
2671     {
2672         OIC_LOG(ERROR, TAG, "TEMPERATURE prompt contained error status.");
2673         ret = TW_RESULT_ERROR;
2674         goto exit;
2675     }
2676
2677     // AttrInfo is 16-bit value representing (100 * Degrees Celsius)
2678     // so 0x812 = 20.66 C = 69.188 F
2679     if (ctx->g_ZigBeeStatus.remoteAttributeValueRead != NULL)
2680     {
2681         OICFree(ctx->g_ZigBeeStatus.remoteAttributeValueRead);
2682         ctx->g_ZigBeeStatus.remoteAttributeValueRead = NULL;
2683     }
2684     OIC_LOG_V(INFO, TAG, "Read Attribute Value: %s", tokens[TOKEN_TEMPERATURE_VALUE]);
2685     ctx->g_ZigBeeStatus.remoteAttributeValueRead =
2686             (char*)OICMalloc(sizeof(char) * strlen(tokens[TOKEN_TEMPERATURE_VALUE]));
2687     if (ctx->g_ZigBeeStatus.remoteAttributeValueRead == NULL)
2688     {
2689         OIC_LOG_V(ERROR, TAG, "No Memory");
2690         ret = TW_RESULT_ERROR_NO_MEMORY;
2691     }
2692     else
2693     {
2694         strcpy(ctx->g_ZigBeeStatus.remoteAttributeValueRead,
2695                tokens[TOKEN_TEMPERATURE_VALUE]);
2696         ctx->g_ZigBeeStatus.remoteAtrributeValueReadLength =
2697                      strlen(tokens[TOKEN_TEMPERATURE_VALUE]);
2698         ret = TW_RESULT_REMOTE_ATTR_HAS_VALUE;
2699     }
2700
2701 exit:
2702     OIC_LOG_V(INFO, TAG, "Leave TelReadAttrHandlerTemperature() with ret=%d", ret);
2703     return ret;
2704 }
2705
2706 TWResultCode TelReadAttrHandler(int count, char* tokens[], TWContext* ctx)
2707 {
2708     //AT+READATR:F2D7,01,0,0402,0002
2709     //      OK
2710     //      RESPATTR:<NodeID>,<EP>,<ClusterID>,<AttrID>,<Status>,<AttrInfo>
2711     //
2712     //AT+READATR:F2D7,01,0,0402,0002
2713     //      OK
2714     //      ERROR:66
2715
2716     OIC_LOG(INFO, TAG, "Enter TelReadAttrHandler()");
2717     TWResultCode ret = TW_RESULT_UNKNOWN;
2718
2719     if(!tokens || count != RESPONSE_PARAMS_COUNT_RESPATTR)
2720     {
2721         OIC_LOG(ERROR, TAG, "Invalid Params");
2722         ret = TW_RESULT_ERROR_INVALID_PARAMS;
2723         goto exit;
2724     }
2725
2726     if (strcmp(tokens[TOKEN_RESPATTR_STATUS_CODE], AT_STR_ERROR_OK) != 0)
2727     {
2728         OIC_LOG(INFO, TAG, "READATTR prompt contained error status.");
2729         ret = TW_RESULT_ERROR;
2730         goto exit;
2731     }
2732
2733     if (ctx->g_ZigBeeStatus.remoteAttributeValueRead != NULL)
2734     {
2735         OICFree(ctx->g_ZigBeeStatus.remoteAttributeValueRead);
2736     }
2737     OIC_LOG_V(INFO, TAG, "Read Attribute Value: %s.", tokens[TOKEN_RESPATTR_ATTRIBUTE_VALUE]);
2738     ctx->g_ZigBeeStatus.remoteAttributeValueRead =
2739             (char*)OICMalloc(sizeof(char) * strlen(tokens[TOKEN_RESPATTR_ATTRIBUTE_VALUE]));
2740     if (ctx->g_ZigBeeStatus.remoteAttributeValueRead != NULL)
2741     {
2742         strcpy(ctx->g_ZigBeeStatus.remoteAttributeValueRead,
2743                tokens[TOKEN_RESPATTR_ATTRIBUTE_VALUE]);
2744         ctx->g_ZigBeeStatus.remoteAtrributeValueReadLength =
2745                      strlen(tokens[TOKEN_RESPATTR_ATTRIBUTE_VALUE]);
2746         ret = TW_RESULT_REMOTE_ATTR_HAS_VALUE;
2747     }
2748     else
2749     {
2750         OIC_LOG(ERROR, TAG, "No Memory");
2751         ret = TW_RESULT_ERROR_NO_MEMORY;
2752     }
2753
2754 exit:
2755     OIC_LOG(INFO, TAG, "Leave TelReadAttrHandler()");
2756     return ret;
2757 }
2758
2759 TWResultCode TelZCLDefaultResponseHandler(int count, char* tokens[], TWContext* ctx)
2760 {
2761     //AT+RONOFF:<Address>,<EP>,<SendMode>[,<ON/OFF>]
2762     //      DFTREP:<NodeID>,<EP>,<ClusterID>,<CMD>,<Status>
2763     //
2764     //AT+DRLOCK:<Address>,<EP>,<SendMode>,<Lock/Unlock>
2765     //      DFTREP:<NodeID>,<EP>,<ClusterID>,<CMD>,<Status>
2766     //
2767     //AT+LCMVTOLEV:<Address>,<EP>,<SendMode>,<ON/OFF>,<LevelValue>,<TransTime>
2768     //      DFTREP:<NodeID>,<EP>,<ClusterID>,<CMD>,<Status>
2769
2770     OIC_LOG(INFO, TAG, "Enter TelZCLDefaultResponseHandler()");
2771     (void)ctx;
2772     TWResultCode ret = TW_RESULT_UNKNOWN;
2773
2774     if(!tokens || count != RESPONSE_PARAMS_COUNT_DFTREP)
2775     {
2776         OIC_LOG(ERROR, TAG, "Invalid Params");
2777         ret = TW_RESULT_ERROR_INVALID_PARAMS;
2778         goto exit;
2779     }
2780
2781     OIC_LOG_V(INFO, TAG,
2782              "DFTREP prompt succeed for NodeId:%s, EP:%s, ClusterId:%s, CMD:%s.\n",
2783              tokens[TOKEN_DFTREP_NODEID],
2784              tokens[TOKEN_DFTREP_ENDPOINTID],
2785              tokens[TOKEN_DFTREP_CLUSTERID],
2786              tokens[TOKEN_DFTREP_COMMANDID]);
2787
2788     if (strcmp(tokens[TOKEN_DFTREP_STATUS_CODE], AT_STR_ERROR_OK) != 0)
2789     {
2790         ret = TW_RESULT_ERROR;
2791     }
2792     else
2793     {
2794         ret = TW_RESULT_OK;
2795     }
2796
2797 exit:
2798     OIC_LOG(INFO, TAG, "Leave TelZCLDefaultResponseHandler()");
2799     return ret;
2800 }
2801
2802 TWResultCode TelSwitchDoorLockStateHandler(int count, char* tokens[], TWContext* ctx)
2803 {
2804     //AT+DRLOCK:<Address>,<EP>,<SendMode>,<Lock/Unlock>
2805     //      DRLOCRSP:<nodeID>,<ep>,<status>
2806     //      or
2807     //      DRUNLOCKRSP:<nodeID>,<ep>,<status>
2808
2809     OIC_LOG(INFO, TAG, "Enter TelSwitchDoorLockStateHandler()");
2810     (void)ctx;
2811     TWResultCode ret = TW_RESULT_UNKNOWN;
2812
2813     if(!tokens || count != RESPONSE_PARAMS_COUNT_DRLOCKUNLOCKRSP)
2814     {
2815         OIC_LOG(ERROR, TAG, "Invalid Params");
2816         ret = TW_RESULT_ERROR_INVALID_PARAMS;
2817         goto exit;
2818     }
2819
2820     if (strcmp(tokens[TOKEN_DRLOCKRSP_STATUS_CODE], AT_STR_ERROR_OK) != 0)
2821     {
2822         OIC_LOG_V(INFO,
2823                  TAG,
2824                  "DRLOCRSP/DRUNLOCKRSP prompt contained error status %s.",
2825                  tokens[TOKEN_DRLOCKRSP_STATUS_CODE]);
2826         ret = TW_RESULT_ERROR;
2827     }
2828     else
2829     {
2830         OIC_LOG_V(INFO, TAG, "DRLOCRSP/DRUNLOCKRSP prompt succeed for nodeId:%s, ep:%s.",
2831                  tokens[TOKEN_DRLOCKRSP_NODEID],
2832                  tokens[TOKEN_DRLOCKRSP_ENDPOINTID]);
2833         ret = TW_RESULT_OK;
2834     }
2835
2836 exit:
2837     OIC_LOG_V(INFO, TAG, "Leave TelSwitchDoorLockStateHandler() with ret=%d", ret);
2838     return ret;
2839 }
2840
2841 TWResultCode TelZoneEnrollRequestHandler(int count, char* tokens[], TWContext* ctx)
2842 {
2843     //ZENROLLREQ:<NodeID>,<EndPoint>,<ZoneType>,<ManufactureCode>
2844
2845     OIC_LOG(INFO, TAG, "Enter TelZoneEnrollRequestHandler()");
2846     (void)ctx;
2847     TWResultCode ret = TW_RESULT_UNKNOWN;
2848
2849     if(!tokens || count != RESPONSE_PARAMS_COUNT_ZENROLLREQ)
2850     {
2851         OIC_LOG(ERROR, TAG, "Invalid Params");
2852         ret = TW_RESULT_ERROR_INVALID_PARAMS;
2853         goto exit;
2854     }
2855
2856     OIC_LOG(INFO, TAG, "Received zone request from:");
2857     OIC_LOG_V(INFO, TAG, "Node:%s", tokens[TOKEN_ZENROLLREQ_NODEID]);
2858     OIC_LOG_V(INFO, TAG, "EP:%s", tokens[TOKEN_ZENROLLREQ_ENDPOINTID]);
2859     OIC_LOG_V(INFO, TAG, "ZoneType:%s", tokens[TOKEN_ZENROLLREQ_ZONETYPE]);
2860     OIC_LOG_V(INFO, TAG, "ManufactureCode:%s", tokens[TOKEN_ZENROLLREQ_MANUFACTURE_CODE]);
2861     ret = TW_RESULT_OK;
2862
2863 exit:
2864     OIC_LOG_V(INFO, TAG, "Leave TelZoneEnrollRequestHandler() with ret=%d", ret);
2865     return ret;
2866 }
2867
2868 TWResultCode TelEnrolledHandler(int count, char* tokens[], TWContext* ctx)
2869 {
2870     //ENROLLED:<ZID>,<ZoneType>,<EUI>
2871
2872     OIC_LOG(INFO, TAG, "Enter TelEnrolledHandler()");
2873     TWResultCode ret = TW_RESULT_OK;
2874
2875     if(!tokens || count != RESPONSE_PARAMS_COUNT_ENROLLED)
2876     {
2877         OIC_LOG(ERROR, TAG, "Invalid Params");
2878         ret = TW_RESULT_ERROR_INVALID_PARAMS;
2879         goto exit;
2880     }
2881
2882     OIC_LOG(INFO, TAG, "Received zone enrollment for:");
2883     OIC_LOG_V(INFO, TAG, "ZID:%s", tokens[TOKEN_ENROLLED_ZONEID]);
2884     OIC_LOG_V(INFO, TAG, "ZoneType:%s", tokens[TOKEN_ENROLLED_ZONETYPE]);
2885     OIC_LOG_V(INFO, TAG, "EUI:%s", tokens[TOKEN_ENROLLED_EUI]);
2886
2887     TWEnrollee enrollee;
2888     OICStrcpy(enrollee.zoneId, SIZE_ZONEID, tokens[TOKEN_ENROLLED_ZONEID]);
2889     OICStrcpy(enrollee.zoneType, SIZE_ZONETYPE, tokens[TOKEN_ENROLLED_ZONETYPE]);
2890     OICStrcpy(enrollee.eui, SIZE_EUI, tokens[TOKEN_ENROLLED_EUI]);
2891
2892     if (ctx->g_EnrollmentSucceedCallback != NULL)
2893     {
2894         OIC_LOG_V(INFO, TAG, "Enrolled - Invoke callback");
2895         ctx->g_EnrollmentSucceedCallback(&enrollee, ctx->g_plugin);
2896     }
2897     ret = TW_RESULT_OK;
2898
2899 exit:
2900     OIC_LOG_V(INFO, TAG, "Leave TelEnrolledHandler() with ret=%d", ret);
2901     return ret;
2902 }
2903
2904 TWResultCode TelZoneStatusHandler(int count, char* tokens[], TWContext* ctx)
2905 {
2906     //ZONESTATUS:<NodeID>,<EP>,<ZoneStatus>,<ExtendStatus>[,<ZoneID>,<Delay>]
2907     //ZONESTATUS:5FBA,01,0021,00,01,00AF
2908
2909     OIC_LOG(INFO, TAG, "Enter TelZoneStatusHandler()");
2910     TWResultCode ret = TW_RESULT_UNKNOWN;
2911     if(!tokens ||
2912        ((count != RESPONSE_PARAMS_COUNT_ZONESTATUS_4) &&
2913         (count != RESPONSE_PARAMS_COUNT_ZONESTATUS_6)))
2914     {
2915         OIC_LOG(ERROR, TAG, "Invalid Params");
2916         ret = TW_RESULT_ERROR_INVALID_PARAMS;
2917         goto exit;
2918     }
2919
2920     TWUpdate update;
2921     OICStrcpy(update.nodeId, SIZE_NODEID, tokens[TOKEN_ZONESTATUS_NODEID]);
2922     OICStrcpy(update.endpoint, SIZE_NODEID, tokens[TOKEN_ZONESTATUS_ENDPOINTID]);
2923     OICStrcpy(update.status, SIZE_NODEID, tokens[TOKEN_ZONESTATUS_ZONESTATUS]);
2924     OICStrcpy(update.extendedStatus, SIZE_NODEID, tokens[TOKEN_ZONESTATUS_ZONESTATUS_EXTENDED]);
2925
2926     if (count == RESPONSE_PARAMS_COUNT_ZONESTATUS_6)
2927     {
2928         OICStrcpy(update.zoneId, SIZE_NODEID, tokens[TOKEN_ZONESTATUS_ZONEID]);
2929         OICStrcpy(update.delay, SIZE_NODEID, tokens[TOKEN_ZONESTATUS_DELAY]);
2930     }
2931
2932     if (ctx->g_DeviceStatusUpdateCallback != NULL)
2933     {
2934         OIC_LOG(INFO, TAG, "device status update - invoke callback");
2935         ctx->g_DeviceStatusUpdateCallback(&update, ctx->g_plugin);
2936         OIC_LOG(INFO, TAG, "device status update - callback done");
2937     }
2938     ret = TW_RESULT_OK;
2939
2940 exit:
2941     OIC_LOG_V(INFO, TAG, "Leave TelZoneStatusHandler() with ret=%d", ret);
2942     return ret;
2943 }
2944
2945 //-----------------------------------------------------------------------------
2946 // Internal functions - Helpers
2947 //-----------------------------------------------------------------------------
2948
2949 /**
2950  *
2951  * Tokenize 'input' parameter by 'delimiters' into 'output' array.
2952  *
2953  */
2954 int Tokenize(const char *input, const char* delimiters, char* output[])
2955 {
2956     OIC_LOG_V(INFO, TAG, "Enter Tokenize() - %s", input);
2957
2958     if (output == NULL)
2959     {
2960         OIC_LOG(INFO, TAG, "Invalid parameter.");
2961         return -1;
2962     }
2963
2964     int length = strlen(input);
2965     char * str = (char *) OICCalloc(1, length + 1);
2966     OICStrcpy(str, length+1, input);
2967
2968     char* savePtr = NULL;
2969     char* p   = strtok_r(str, delimiters, &savePtr);
2970     int index = 0;
2971     while (p && index <= ARRAY_LENGTH)
2972     {
2973         int size = strlen(p) + 1;   //for null char
2974         output[index] = (char*)OICCalloc(size, sizeof(char));
2975         OICStrcpy(output[index], size, p);
2976         OIC_LOG_V(INFO, TAG, "Token[%d]=%s", index, output[index]);
2977         p = strtok_r (NULL, delimiters, &savePtr);
2978         index++;
2979     }
2980
2981     OICFree(str);
2982     OIC_LOG(INFO, TAG, "Leave Tokenize()");
2983     return index;
2984 }
2985
2986 int AsciiToHex(char c)
2987 {
2988     int num = (int) c;
2989     if(c >= '0' && c <= '9')
2990     {
2991         return num - '0';
2992     }
2993
2994     if(num >= 'A' && num <= 'F')
2995     {
2996         return num - 'A' + 10;
2997     }
2998     return -1;
2999 }
3000
3001 TWResultCode AsciiHexToValue(char* hexString, int length, uint64_t* value)
3002 {
3003     if(!hexString || !value || length < 0)
3004     {
3005         return TW_RESULT_ERROR_INVALID_PARAMS;
3006     }
3007     int retVal = AsciiToHex(hexString[0]);
3008     if(retVal == -1)
3009     {
3010         OIC_LOG(ERROR, TAG, "Bad conversion from ASCII To Hex.");
3011         return TW_RESULT_ERROR;
3012     }
3013     *value = (uint64_t)retVal;
3014     for (int i = 1; i < length; ++i)
3015     {
3016         if (sizeof(hexString) > (uint32_t)i)
3017         {
3018             *value <<= 4;
3019             retVal = AsciiToHex(hexString[i]);
3020             if(retVal == -1)
3021             {
3022                 OIC_LOG(ERROR, TAG, "Bad conversion from ASCII To Hex.");
3023                 return TW_RESULT_ERROR;
3024             }
3025             *value |= (uint64_t)retVal;
3026         }
3027     }
3028     return TW_RESULT_OK;
3029 }
3030
3031 /**
3032  *
3033  * Deallocate device list.
3034  *
3035  */
3036 void DeallocateTWDeviceList(TWContext* ctx)
3037 {
3038     if (ctx->g_FoundMatchedDeviceList == NULL)
3039     {
3040         return;
3041     }
3042
3043     if (ctx->g_FoundMatchedDeviceList->deviceList == NULL)
3044     {
3045         OICFree(ctx->g_FoundMatchedDeviceList);
3046         ctx->g_FoundMatchedDeviceList = NULL;
3047         return;
3048     }
3049
3050     if (ctx->g_FoundMatchedDeviceList->deviceList->endpointOfInterest == NULL)
3051     {
3052         OICFree(ctx->g_FoundMatchedDeviceList->deviceList);
3053         ctx->g_FoundMatchedDeviceList->deviceList = NULL;
3054
3055         OICFree(ctx->g_FoundMatchedDeviceList);
3056         ctx->g_FoundMatchedDeviceList = NULL;
3057         return;
3058     }
3059
3060     if (ctx->g_FoundMatchedDeviceList->deviceList->endpointOfInterest->clusterList == NULL)
3061     {
3062         OICFree(ctx->g_FoundMatchedDeviceList->deviceList->endpointOfInterest);
3063         ctx->g_FoundMatchedDeviceList->deviceList->endpointOfInterest = NULL;
3064
3065         OICFree(ctx->g_FoundMatchedDeviceList->deviceList);
3066         ctx->g_FoundMatchedDeviceList->deviceList = NULL;
3067
3068         OICFree(ctx->g_FoundMatchedDeviceList);
3069         ctx->g_FoundMatchedDeviceList = NULL;
3070         return;
3071     }
3072
3073     if (ctx->g_FoundMatchedDeviceList->deviceList->endpointOfInterest->clusterList->clusterIds
3074             == NULL)
3075     {
3076         OICFree(ctx->g_FoundMatchedDeviceList->deviceList->endpointOfInterest->clusterList);
3077         ctx->g_FoundMatchedDeviceList->deviceList->endpointOfInterest->clusterList = NULL;
3078
3079         OICFree(ctx->g_FoundMatchedDeviceList->deviceList->endpointOfInterest);
3080         ctx->g_FoundMatchedDeviceList->deviceList->endpointOfInterest = NULL;
3081
3082         OICFree(ctx->g_FoundMatchedDeviceList->deviceList);
3083         ctx->g_FoundMatchedDeviceList->deviceList = NULL;
3084
3085         OICFree(ctx->g_FoundMatchedDeviceList);
3086         ctx->g_FoundMatchedDeviceList = NULL;
3087         return;
3088     }
3089
3090     OICFree(ctx->g_FoundMatchedDeviceList->deviceList->
3091             endpointOfInterest->clusterList->clusterIds);
3092     ctx->g_FoundMatchedDeviceList->deviceList->endpointOfInterest->clusterList->clusterIds = NULL;
3093
3094     OICFree(ctx->g_FoundMatchedDeviceList->deviceList->endpointOfInterest->clusterList);
3095     ctx->g_FoundMatchedDeviceList->deviceList->endpointOfInterest->clusterList = NULL;
3096
3097     OICFree(ctx->g_FoundMatchedDeviceList->deviceList->endpointOfInterest);
3098     ctx->g_FoundMatchedDeviceList->deviceList->endpointOfInterest = NULL;
3099
3100     OICFree(ctx->g_FoundMatchedDeviceList->deviceList);
3101     ctx->g_FoundMatchedDeviceList->deviceList = NULL;
3102
3103     OICFree(ctx->g_FoundMatchedDeviceList);
3104     ctx->g_FoundMatchedDeviceList = NULL;
3105 }