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