1 /*
2 * zbSocCmd.c
3 *
4 * This module contains the API for the zll SoC Host Interface.
5 *
6 * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
7 *
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the
19 * distribution.
20 *
21 * Neither the name of Texas Instruments Incorporated nor the names of
22 * its contributors may be used to endorse or promote products derived
23 * from this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 */
39 /*********************************************************************
40 * INCLUDES
41 */
42 #include <termios.h>
43 #include <string.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <unistd.h>
47 #include <fcntl.h>
48 #include <sys/ioctl.h>
50 #include <errno.h>
51 #include <string.h>
53 #include "zbSocCmd.h"
55 /*********************************************************************
56 * MACROS
57 */
59 #define APPCMDHEADER(len) \
60 0xFE, \
61 len, /*RPC payload Len */ \
62 0x29, /*MT_RPC_CMD_AREQ + MT_RPC_SYS_APP */ \
63 0x00, /*MT_APP_MSG */ \
64 0x0B, /*Application Endpoint */ \
65 0x02, /*short Addr 0x0002 */ \
66 0x00, /*short Addr 0x0002 */ \
67 0x0B, /*Dst EP */ \
68 0xFF, /*Cluster ID 0xFFFF invalid, used for key */ \
69 0xFF, /*Cluster ID 0xFFFF invalid, used for key */ \
71 #define BUILD_UINT16(loByte, hiByte) \
72 ((uint16_t)(((loByte) & 0x00FF) + (((hiByte) & 0x00FF) << 8)))
74 #define BUILD_UINT32(Byte0, Byte1, Byte2, Byte3) \
75 ((uint32_t)((uint32_t)((Byte0) & 0x00FF) \
76 + ((uint32_t)((Byte1) & 0x00FF) << 8) \
77 + ((uint32_t)((Byte2) & 0x00FF) << 16) \
78 + ((uint32_t)((Byte3) & 0x00FF) << 24)))
80 /*********************************************************************
81 * CONSTANTS
82 */
83 #define ZLL_MT_APP_RPC_CMD_TOUCHLINK 0x01
84 #define ZLL_MT_APP_RPC_CMD_RESET_TO_FN 0x02
85 #define ZLL_MT_APP_RPC_CMD_CH_CHANNEL 0x03
86 #define ZLL_MT_APP_RPC_CMD_JOIN_HA 0x04
87 #define ZLL_MT_APP_RPC_CMD_PERMIT_JOIN 0x05
88 #define ZLL_MT_APP_RPC_CMD_SEND_RESET_TO_FN 0x06
89 #define ZLL_MT_APP_RPC_CMD_START_DISTRIB_NWK 0x07
91 #define MT_APP_RSP 0x80
92 #define MT_APP_ZLL_TL_IND 0x81
93 #define MT_APP_ZLL_NEW_DEV_IND 0x82
95 #define MT_DEBUG_MSG 0x80
97 #define COMMAND_LIGHTING_MOVE_TO_HUE 0x00
98 #define COMMAND_LIGHTING_MOVE_TO_SATURATION 0x03
99 #define COMMAND_LEVEL_MOVE_TO_LEVEL 0x00
100 #define COMMAND_IDENTIFY 0x00
101 #define COMMAND_IDENTIFY_TRIGGER_EFFECT 0x40
103 /*** Foundation Command IDs ***/
104 #define ZCL_CMD_READ 0x00
105 #define ZCL_CMD_READ_RSP 0x01
106 #define ZCL_CMD_WRITE 0x02
107 #define ZCL_CMD_WRITE_UNDIVIDED 0x03
108 #define ZCL_CMD_WRITE_RSP 0x04
109 //ZDO
110 #define MT_ZDO_SIMPLE_DESC_RSP 0x84
111 #define MT_ZDO_ACTIVE_EP_RSP 0x85
112 #define MT_ZDO_END_DEVICE_ANNCE_IND 0xC1
113 #define MT_ZDO_LEAVE_IND 0xC9
115 //UTIL
116 #define MT_UTIL_GET_DEVICE_INFO 0x00
118 // General Clusters
119 #define ZCL_CLUSTER_ID_GEN_BASIC 0x0000
120 #define ZCL_CLUSTER_ID_GEN_IDENTIFY 0x0003
121 #define ZCL_CLUSTER_ID_GEN_GROUPS 0x0004
122 #define ZCL_CLUSTER_ID_GEN_SCENES 0x0005
123 #define ZCL_CLUSTER_ID_GEN_ON_OFF 0x0006
124 #define ZCL_CLUSTER_ID_GEN_LEVEL_CONTROL 0x0008
125 // Lighting Clusters
126 #define ZCL_CLUSTER_ID_LIGHTING_COLOR_CONTROL 0x0300
128 // Data Types
129 #define ZCL_DATATYPE_BOOLEAN 0x10
130 #define ZCL_DATATYPE_UINT8 0x20
131 #define ZCL_DATATYPE_INT16 0x29
132 #define ZCL_DATATYPE_INT24 0x2a
133 #define ZCL_DATATYPE_CHAR_STR 0x42
135 /*******************************/
136 /*** Generic Cluster ATTR's ***/
137 /*******************************/
138 #define ATTRID_BASIC_MODEL_ID 0x0005
139 #define ATTRID_ON_OFF 0x0000
140 #define ATTRID_LEVEL_CURRENT_LEVEL 0x0000
142 /*******************************/
143 /*** Lighting Cluster ATTR's ***/
144 /*******************************/
145 #define ATTRID_LIGHTING_COLOR_CONTROL_CURRENT_HUE 0x0000
146 #define ATTRID_LIGHTING_COLOR_CONTROL_CURRENT_SATURATION 0x0001
148 /*******************************/
149 /*** Scenes Cluster Commands ***/
150 /*******************************/
151 #define COMMAND_SCENE_STORE 0x04
152 #define COMMAND_SCENE_RECALL 0x05
154 /*******************************/
155 /*** Groups Cluster Commands ***/
156 /*******************************/
157 #define COMMAND_GROUP_ADD 0x00
159 /* The 3 MSB's of the 1st command field byte are for command type. */
160 #define MT_RPC_CMD_TYPE_MASK 0xE0
162 /* The 5 LSB's of the 1st command field byte are for the subsystem. */
163 #define MT_RPC_SUBSYSTEM_MASK 0x1F
165 #define MT_RPC_SOF 0xFE
167 /*******************************/
168 /*** Bootloader Commands ***/
169 /*******************************/
170 #define SB_FORCE_BOOT 0xF8
171 #define SB_FORCE_RUN (SB_FORCE_BOOT ^ 0xFF)
172 #define SB_FORCE_BOOT_1 0x10
173 #define SB_FORCE_RUN_1 (SB_FORCE_BOOT_1 ^ 0xFF)
176 typedef enum {
177 MT_RPC_CMD_POLL = 0x00,
178 MT_RPC_CMD_SREQ = 0x20,
179 MT_RPC_CMD_AREQ = 0x40,
180 MT_RPC_CMD_SRSP = 0x60,
181 MT_RPC_CMD_RES4 = 0x80,
182 MT_RPC_CMD_RES5 = 0xA0,
183 MT_RPC_CMD_RES6 = 0xC0,
184 MT_RPC_CMD_RES7 = 0xE0
185 } mtRpcCmdType_t;
187 typedef enum {
188 MT_RPC_SYS_RES0, /* Reserved. */
189 MT_RPC_SYS_SYS,
190 MT_RPC_SYS_MAC,
191 MT_RPC_SYS_NWK,
192 MT_RPC_SYS_AF,
193 MT_RPC_SYS_ZDO,
194 MT_RPC_SYS_SAPI, /* Simple API. */
195 MT_RPC_SYS_UTIL,
196 MT_RPC_SYS_DBG,
197 MT_RPC_SYS_APP,
198 MT_RPC_SYS_OTA,
199 MT_RPC_SYS_ZNP,
200 MT_RPC_SYS_SPARE_12,
201 MT_RPC_SYS_UBL = 13, // 13 to be compatible with existing RemoTI.
202 MT_RPC_SYS_MAX // Maximum value, must be last (so 14-32 available, not yet assigned).
203 } mtRpcSysType_t;
205 /************************************************************
206 * TYPEDEFS
207 */
209 /*********************************************************************
210 * GLOBAL VARIABLES
211 */
213 /*********************************************************************
214 * LOCAL VARIABLES
215 */
216 int serialPortFd = 0;
217 uint8_t transSeqNumber = 0;
219 zbSocCallbacks_t zbSocCb;
221 /*********************************************************************
222 * LOCAL FUNCTIONS
223 */
224 void calcFcs(uint8_t *msg, int size);
225 static void processRpcSysAppTlInd(uint8_t *TlIndBuff);
226 static void processRpcSysAppZcl(uint8_t *zclRspBuff);
227 static void processRpcSysAppZclFoundation(uint8_t *zclRspBuff,
228 uint8_t zclFrameLen, uint16_t clusterID, uint16_t nwkAddr, uint8_t endpoint);
229 static void processRpcSysApp(uint8_t *rpcBuff);
230 static void processRpcSysDbg(uint8_t *rpcBuff);
231 static void zbSocTransportWrite(uint8_t* buf, uint8_t len);
233 /*********************************************************************
234 * @fn calcFcs
235 *
236 * @brief populates the Frame Check Sequence of the RPC payload.
237 *
238 * @param msg - pointer to the RPC message
239 *
240 * @return none
241 */
242 void calcFcs(uint8_t *msg, int size)
243 {
244 uint8_t result = 0;
245 int idx = 1; //skip SOF
246 int len = (size - 1); // skip FCS
248 while ((len--) != 0)
249 {
250 result ^= msg[idx++];
251 }
253 msg[(size - 1)] = result;
254 }
256 /*********************************************************************
257 * API FUNCTIONS
258 */
260 /*********************************************************************
261 * @fn zbSocOpen
262 *
263 * @brief opens the serial port to the CC253x.
264 *
265 * @param devicePath - path to the UART device
266 *
267 * @return status
268 */
269 int32_t zbSocOpen(char *devicePath)
270 {
271 struct termios tio;
273 /* open the device to be non-blocking (read will return immediatly) */
274 serialPortFd = open(devicePath, O_RDWR | O_NOCTTY | O_NONBLOCK);
275 if (serialPortFd < 0)
276 {
277 perror(devicePath);
278 printf("%s open failed\n", devicePath);
279 return (-1);
280 }
282 //make the access exclusive so other instances will return -1 and exit
283 ioctl(serialPortFd, TIOCEXCL);
285 /* c-iflags
286 B115200 : set board rate to 115200
287 CRTSCTS : HW flow control (disabled below)
288 CS8 : 8n1 (8bit,no parity,1 stopbit)
289 CLOCAL : local connection, no modem contol
290 CREAD : enable receiving characters*/
291 tio.c_cflag = B38400 | CRTSCTS | CS8 | CLOCAL | CREAD;
292 /* c-iflags
293 ICRNL : maps 0xD (CR) to 0x10 (LR), we do not want this.
294 IGNPAR : ignore bits with parity erros, I guess it is
295 better to ignStateore an erronious bit then interprit it incorrectly. */
296 tio.c_iflag = IGNPAR & ~ICRNL;
297 tio.c_oflag = 0;
298 tio.c_lflag = 0;
300 tcflush(serialPortFd, TCIFLUSH);
301 tcsetattr(serialPortFd, TCSANOW, &tio);
303 //Send the bootloader force boot incase we have a bootloader that waits
304 uint8_t forceBoot[] = {SB_FORCE_RUN, SB_FORCE_RUN_1};
305 zbSocTransportWrite(forceBoot, 2);
307 return serialPortFd;
308 }
310 void zbSocClose(void)
311 {
312 tcflush(serialPortFd, TCOFLUSH);
313 close(serialPortFd);
315 return;
316 }
318 /*********************************************************************
319 * @fn zbSocTransportWrite
320 *
321 * @brief Write to the the serial port to the CC253x.
322 *
323 * @param fd - file descriptor of the UART device
324 *
325 * @return status
326 */
327 static void zbSocTransportWrite(uint8_t* buf, uint8_t len)
328 {
329 int remain = len;
330 int offset = 0;
331 #if 1
332 //printf("zbSocTransportWrite : len = %d\n", len);
334 while (remain > 0)
335 {
336 int sub = (remain >= 8 ? 8 : remain);
337 //printf("writing %d bytes (offset = %d, remain = %d)\n", sub, offset,
338 // remain);
339 write(serialPortFd, buf + offset, sub);
341 tcflush(serialPortFd, TCOFLUSH);
342 usleep(5000);
343 remain -= 8;
344 offset += 8;
345 }
346 #else
347 write (serialPortFd, buf, len);
348 tcflush(serialPortFd, TCOFLUSH);
350 #endif
351 return;
352 }
354 /*********************************************************************
355 * @fn zbSocRegisterCallbacks
356 *
357 * @brief opens the serial port to the CC253x.
358 *
359 * @param devicePath - path to the UART device
360 *
361 * @return status
362 */
363 void zbSocRegisterCallbacks(zbSocCallbacks_t zbSocCallbacks)
364 {
365 //copy the callback function pointers
366 memcpy(&zbSocCb, &zbSocCallbacks, sizeof(zbSocCallbacks_t));
367 return;
368 }
370 /*********************************************************************
371 * @fn zbSocTouchLink
372 *
373 * @brief Send the touchLink command to the CC253x.
374 *
375 * @param none
376 *
377 * @return none
378 */
379 void zbSocTouchLink(void)
380 {
381 uint8_t cmd[] =
382 { APPCMDHEADER(13) 0x06, //Data Len
383 0x02, //Address Mode
384 0x00,//2dummy bytes
385 0x00, ZLL_MT_APP_RPC_CMD_TOUCHLINK, 0x00, //
386 0x00, //
387 0x00 //FCS - fill in later
388 };
390 calcFcs(cmd, sizeof(cmd));
391 zbSocTransportWrite(cmd, sizeof(cmd));
392 }
394 /*********************************************************************
395 * @fn zbSocBridgeStartNwk
396 *
397 * @brief Send the start network command to the CC253x.
398 *
399 * @param none
400 *
401 * @return none
402 */
403 void zbSocBridgeStartNwk(void)
404 {
405 uint8_t cmd[] =
406 { APPCMDHEADER(13) 0x06, //Data Len
407 0x02, //Address Mode
408 0x00,//2dummy bytes
409 0x00, ZLL_MT_APP_RPC_CMD_START_DISTRIB_NWK, 0x00, //
410 0x00, //
411 0x00 //FCS - fill in later
412 };
414 calcFcs(cmd, sizeof(cmd));
415 zbSocTransportWrite(cmd, sizeof(cmd));
416 }
418 /*********************************************************************
419 * @fn zbSocResetToFn
420 *
421 * @brief Send the reset to factory new command to the CC253x.
422 *
423 * @param none
424 *
425 * @return none
426 */
427 void zbSocResetToFn(void)
428 {
429 uint8_t cmd[] =
430 { APPCMDHEADER(13) 0x06, //Data Len
431 0x02, //Address Mode
432 0x00,//2dummy bytes
433 0x00, ZLL_MT_APP_RPC_CMD_RESET_TO_FN, 0x00, //
434 0x00, //
435 0x00 //FCS - fill in later
436 };
438 calcFcs(cmd, sizeof(cmd));
439 zbSocTransportWrite(cmd, sizeof(cmd));
440 }
442 /*********************************************************************
443 * @fn zbSocSendResetToFn
444 *
445 * @brief Send the reset to factory new command to a ZLL device.
446 *
447 * @param none
448 *
449 * @return none
450 */
451 void zbSocSendResetToFn(void)
452 {
453 uint8_t cmd[] =
454 { APPCMDHEADER(13) 0x06, //Data Len
455 0x02, //Address Mode
456 0x00,//2dummy bytes
457 0x00, ZLL_MT_APP_RPC_CMD_SEND_RESET_TO_FN, 0x00, //
458 0x00, //
459 0x00 //FCS - fill in later
460 };
462 calcFcs(cmd, sizeof(cmd));
463 zbSocTransportWrite(cmd, sizeof(cmd));
464 }
466 /*********************************************************************
467 * @fn zbSocOpenNwk
468 *
469 * @brief Send the open network command to a ZLL device.
470 *
471 * @param none
472 *
473 * @return none
474 */
475 void zbSocOpenNwk(uint8_t duration)
476 {
477 uint16_t srcNwkAddr = 0xFFFD; //Everyone with RxOnWhenIdle == TRUE
479 uint8_t mgmtPermit[] =
480 { 0xFE, 5, /*RPC payload Len */
481 MT_RPC_CMD_SREQ | MT_RPC_SYS_ZDO,
482 0x36, /*MT_ZDO_MGMT_PERMIT_JOIN_REQ*/
483 afAddrBroadcast, //addr mode
484 (srcNwkAddr & 0x00ff), /*Src Nwk Addr - To send the bind message to*/
485 (srcNwkAddr & 0xff00) >> 8, /*Src Nwk Addr - To send the bind message to*/
486 duration, /*Dst endpoint for the binding*/
487 1, /*trust center significance set*/
488 0x00 //FCS - fill in later
489 };
491 uint8_t localPermit[] =
492 { APPCMDHEADER(13) 0x06, //Data Len
493 0x02, //Address Mode
494 0x00,//2dummy bytes
495 0x00, ZLL_MT_APP_RPC_CMD_PERMIT_JOIN,
496 duration, //
497 0x00, //
498 0x00 //FCS - fill in later
499 };
501 printf("zbSocOpenNwk: duration %ds\n", duration);
503 calcFcs(localPermit, sizeof(localPermit));
504 zbSocTransportWrite(localPermit, sizeof(localPermit));
506 //wait for message to be consumed
507 usleep(30);
509 calcFcs(mgmtPermit, sizeof(mgmtPermit));
510 zbSocTransportWrite(mgmtPermit, sizeof(mgmtPermit));
511 }
513 /*********************************************************************
514 * @fn zbSocSendIdentify
515 *
516 * @brief Send identify command to a ZLL light.
517 *
518 * @param identifyTime - in s.
519 * @param dstAddr - Nwk Addr or Group ID of the Light(s) to be controled.
520 * @param endpoint - endpoint of the Light.
521 * @param addrMode - Unicast or Group cast.
522 *
523 * @return none
524 */
525 void zbSocSendIdentify(uint16_t identifyTime, uint16_t dstAddr,
526 uint8_t endpoint, uint8_t addrMode)
527 {
528 uint8_t cmd[] =
529 { 0xFE,
530 13, //RPC payload Len
531 0x29, //MT_RPC_CMD_AREQ + MT_RPC_SYS_APP
532 0x00, //MT_APP_MSG
533 0x0B, //Application Endpoint
534 (dstAddr & 0x00ff), (dstAddr & 0xff00) >> 8,
535 endpoint, //Dst EP
536 (ZCL_CLUSTER_ID_GEN_IDENTIFY & 0x00ff),
537 (ZCL_CLUSTER_ID_GEN_IDENTIFY & 0xff00) >> 8, 0x06, //Data Len
538 addrMode, 0x01, //0x01 ZCL frame control field. (send to the light cluster only)
539 transSeqNumber++, COMMAND_IDENTIFY, (identifyTime
540 & 0xff), (identifyTime & 0xff00) >> 8, 0x00 //FCS - fill in later
541 };
543 calcFcs(cmd, sizeof(cmd));
545 zbSocTransportWrite(cmd, sizeof(cmd));
547 printf("zbSocSendIdentify: dstAddr=%x, endpoint=%x, addrMode=%x, identifyTime=%x\n",
548 dstAddr, endpoint, addrMode, identifyTime);
549 }
551 /*********************************************************************
552 * @fn COMMAND_IDENTIFY_TRIGGER_EFFECT
553 *
554 * @brief Send identify command to a ZLL light.
555 *
556 * @param effect - effect.
557 * @param dstAddr - Nwk Addr or Group ID of the Light(s) to be controled.
558 * @param endpoint - endpoint of the Light.
559 * @param addrMode - Unicast or Group cast.
560 *
561 * @return none
562 */
563 void zbSocSendIdentifyEffect(uint8_t effect, uint8_t effectVarient, uint16_t dstAddr,
564 uint8_t endpoint, uint8_t addrMode)
565 {
566 uint8_t cmd[] =
567 { 0xFE,
568 13, //RPC payload Len
569 0x29, //MT_RPC_CMD_AREQ + MT_RPC_SYS_APP
570 0x00, //MT_APP_MSG
571 0x0B, //Application Endpoint
572 (dstAddr & 0x00ff), (dstAddr & 0xff00) >> 8,
573 endpoint, //Dst EP
574 (ZCL_CLUSTER_ID_GEN_IDENTIFY & 0x00ff),
575 (ZCL_CLUSTER_ID_GEN_IDENTIFY & 0xff00) >> 8, 0x06, //Data Len
576 addrMode, 0x01, //0x01 ZCL frame control field. (send to the light cluster only)
577 transSeqNumber++, COMMAND_IDENTIFY_TRIGGER_EFFECT, effect,
578 effectVarient, 0x00 //FCS - fill in later
579 };
581 calcFcs(cmd, sizeof(cmd));
583 zbSocTransportWrite(cmd, sizeof(cmd));
585 printf("zbSocSendIdentify: dstAddr=%x, endpoint=%x, addrMode=%x, effect=%x\n",
586 dstAddr, endpoint, addrMode, effect);
587 }
589 /*********************************************************************
590 * @fn zbSocSetState
591 *
592 * @brief Send the on/off command to a ZLL light.
593 *
594 * @param state - 0: Off, 1: On.
595 * @param dstAddr - Nwk Addr or Group ID of the Light(s) to be controled.
596 * @param endpoint - endpoint of the Light.
597 * @param addrMode - Unicast or Group cast.
598 *
599 * @return none
600 */
601 void zbSocSetState(uint8_t state, uint16_t dstAddr, uint8_t endpoint,
602 uint8_t addrMode)
603 {
604 uint8_t cmd[] =
605 { 0xFE, 11, /*RPC payload Len */
606 0x29, /*MT_RPC_CMD_AREQ + MT_RPC_SYS_APP */
607 0x00, /*MT_APP_MSG */
608 0x0B, /*Application Endpoint */
609 (dstAddr & 0x00ff), (dstAddr & 0xff00) >> 8, endpoint, /*Dst EP */
610 (ZCL_CLUSTER_ID_GEN_ON_OFF & 0x00ff), (ZCL_CLUSTER_ID_GEN_ON_OFF & 0xff00)
611 >> 8, 0x04, //Data Len
612 addrMode, 0x01, //0x01 ZCL frame control field. (send to the light cluster only)
613 transSeqNumber++, (state ? 1 : 0), 0x00 //FCS - fill in later
614 };
616 calcFcs(cmd, sizeof(cmd));
617 zbSocTransportWrite(cmd, sizeof(cmd));
618 }
620 /*********************************************************************
621 * @fn zbSocSetLevel
622 *
623 * @brief Send the level command to a ZLL light.
624 *
625 * @param level - 0-128 = 0-100%
626 * @param dstAddr - Nwk Addr or Group ID of the Light(s) to be controled.
627 * @param endpoint - endpoint of the Light.
628 * @param addrMode - Unicast or Group cast.
629 *
630 * @return none
631 */
632 void zbSocSetLevel(uint8_t level, uint16_t time, uint16_t dstAddr,
633 uint8_t endpoint, uint8_t addrMode)
634 {
635 uint8_t cmd[] =
636 { 0xFE,
637 14, //RPC payload Len
638 0x29, //MT_RPC_CMD_AREQ + MT_RPC_SYS_APP
639 0x00, //MT_APP_MSG
640 0x0B, //Application Endpoint
641 (dstAddr & 0x00ff), (dstAddr & 0xff00) >> 8,
642 endpoint, //Dst EP
643 (ZCL_CLUSTER_ID_GEN_LEVEL_CONTROL & 0x00ff),
644 (ZCL_CLUSTER_ID_GEN_LEVEL_CONTROL & 0xff00) >> 8, 0x07, //Data Len
645 addrMode, 0x01, //0x01 ZCL frame control field. (send to the light cluster only)
646 transSeqNumber++, COMMAND_LEVEL_MOVE_TO_LEVEL, (level & 0xff), (time
647 & 0xff), (time & 0xff00) >> 8, 0x00 //FCS - fill in later
648 };
650 calcFcs(cmd, sizeof(cmd));
652 zbSocTransportWrite(cmd, sizeof(cmd));
654 printf("zbSocSetLevel: dstAddr=%x, endpoint=%x, addrMode=%x, level=%x\n",
655 dstAddr, endpoint, addrMode, level);
656 }
658 /*********************************************************************
659 * @fn zbSocSetHue
660 *
661 * @brief Send the hue command to a ZLL light.
662 *
663 * @param hue - 0-128 represent the 360Deg hue color wheel : 0=red, 42=blue, 85=green
664 * @param dstAddr - Nwk Addr or Group ID of the Light(s) to be controled.
665 * @param endpoint - endpoint of the Light.
666 * @param addrMode - Unicast or Group cast.
667 *
668 * @return none
669 */
670 void zbSocSetHue(uint8_t hue, uint16_t time, uint16_t dstAddr, uint8_t endpoint,
671 uint8_t addrMode)
672 {
673 uint8_t cmd[] =
674 { 0xFE,
675 15, //RPC payload Len
676 0x29, //MT_RPC_CMD_AREQ + MT_RPC_SYS_APP
677 0x00, //MT_APP_MSG
678 0x0B, //Application Endpoint
679 (dstAddr & 0x00ff), (dstAddr & 0xff00) >> 8,
680 endpoint, //Dst EP
681 (ZCL_CLUSTER_ID_LIGHTING_COLOR_CONTROL & 0x00ff),
682 (ZCL_CLUSTER_ID_LIGHTING_COLOR_CONTROL & 0xff00) >> 8, 0x08, //Data Len
683 addrMode, 0x01, //0x01 ZCL frame control field. (send to the light cluster only)
684 transSeqNumber++, COMMAND_LIGHTING_MOVE_TO_HUE, (hue & 0xff), 0x00, //Move with shortest distance
685 (time & 0xff), (time & 0xff00) >> 8, 0x00 //FCS - fill in later
686 };
688 calcFcs(cmd, sizeof(cmd));
689 zbSocTransportWrite(cmd, sizeof(cmd));
690 }
692 /*********************************************************************
693 * @fn zbSocSetSat
694 *
695 * @brief Send the satuartion command to a ZLL light.
696 *
697 * @param sat - 0-128 : 0=white, 128: fully saturated color
698 * @param dstAddr - Nwk Addr or Group ID of the Light(s) to be controled.
699 * @param endpoint - endpoint of the Light.
700 * @param addrMode - Unicast or Group cast.
701 *
702 * @return none
703 */
704 void zbSocSetSat(uint8_t sat, uint16_t time, uint16_t dstAddr, uint8_t endpoint,
705 uint8_t addrMode)
706 {
707 uint8_t cmd[] =
708 { 0xFE,
709 14, //RPC payload Len
710 0x29, //MT_RPC_CMD_AREQ + MT_RPC_SYS_APP
711 0x00, //MT_APP_MSG
712 0x0B, //Application Endpoint
713 (dstAddr & 0x00ff), (dstAddr & 0xff00) >> 8,
714 endpoint, //Dst EP
715 (ZCL_CLUSTER_ID_LIGHTING_COLOR_CONTROL & 0x00ff),
716 (ZCL_CLUSTER_ID_LIGHTING_COLOR_CONTROL & 0xff00) >> 8, 0x07, //Data Len
717 addrMode, 0x01, //0x01 ZCL frame control field. (send to the light cluster only)
718 transSeqNumber++, COMMAND_LIGHTING_MOVE_TO_SATURATION, (sat & 0xff), (time
719 & 0xff), (time & 0xff00) >> 8, 0x00 //FCS - fill in later
720 };
722 calcFcs(cmd, sizeof(cmd));
723 zbSocTransportWrite(cmd, sizeof(cmd));
724 }
726 /*********************************************************************
727 * @fn zbSocSetHueSat
728 *
729 * @brief Send the hue and satuartion command to a ZLL light.
730 *
731 * @param hue - 0-128 represent the 360Deg hue color wheel : 0=red, 42=blue, 85=green
732 * @param sat - 0-128 : 0=white, 128: fully saturated color
733 * @param dstAddr - Nwk Addr or Group ID of the Light(s) to be controled.
734 * @param endpoint - endpoint of the Light.
735 * @param addrMode - Unicast or Group cast.
736 *
737 * @return none
738 */
739 void zbSocSetHueSat(uint8_t hue, uint8_t sat, uint16_t time, uint16_t dstAddr,
740 uint8_t endpoint, uint8_t addrMode)
741 {
742 uint8_t cmd[] =
743 { 0xFE,
744 15, //RPC payload Len
745 0x29, //MT_RPC_CMD_AREQ + MT_RPC_SYS_APP
746 0x00, //MT_APP_MSG
747 0x0B, //Application Endpoint
748 (dstAddr & 0x00ff), (dstAddr & 0xff00) >> 8,
749 endpoint, //Dst EP
750 (ZCL_CLUSTER_ID_LIGHTING_COLOR_CONTROL & 0x00ff),
751 (ZCL_CLUSTER_ID_LIGHTING_COLOR_CONTROL & 0xff00) >> 8, 0x08, //Data Len
752 addrMode, 0x01, //ZCL Header Frame Control
753 transSeqNumber++, 0x06, //ZCL Header Frame Command (COMMAND_LEVEL_MOVE_TO_HUE_AND_SAT)
754 hue, //HUE - fill it in later
755 sat, //SAT - fill it in later
756 (time & 0xff), (time & 0xff00) >> 8, 0x00 //fcs
757 };
759 calcFcs(cmd, sizeof(cmd));
760 zbSocTransportWrite(cmd, sizeof(cmd));
761 }
763 /*********************************************************************
764 * @fn zbSocAddGroup
765 *
766 * @brief Add Group.
767 *
768 * @param groupId - Group ID of the Scene.
769 * @param dstAddr - Nwk Addr or Group ID of the Light(s) to be controled.
770 * @param endpoint - endpoint of the Light.
771 * @param addrMode - Unicast or Group cast.
772 *
773 * @return none
774 */
775 void zbSocAddGroup(uint16_t groupId, uint16_t dstAddr, uint8_t endpoint,
776 uint8_t addrMode)
777 {
778 uint8_t cmd[] =
779 { 0xFE, 14, /*RPC payload Len */
780 0x29, /*MT_RPC_CMD_AREQ + MT_RPC_SYS_APP */
781 0x00, /*MT_APP_MSG */
782 0x0B, /*Application Endpoint */
783 (dstAddr & 0x00ff), (dstAddr & 0xff00) >> 8, endpoint, /*Dst EP */
784 (ZCL_CLUSTER_ID_GEN_GROUPS & 0x00ff), (ZCL_CLUSTER_ID_GEN_GROUPS & 0xff00)
785 >> 8,
786 0x07, //Data Len
787 addrMode,
788 0x01, //0x01 ZCL frame control field. (send to the light cluster only)
789 transSeqNumber++, COMMAND_GROUP_ADD, (groupId & 0x00ff),
790 (groupId & 0xff00) >> 8, 0, //Null group name - Group Name not pushed to the devices
791 0x00 //FCS - fill in later
792 };
794 printf("zbSocAddGroup: dstAddr 0x%x\n", dstAddr);
796 calcFcs(cmd, sizeof(cmd));
797 zbSocTransportWrite(cmd, sizeof(cmd));
798 }
800 /*********************************************************************
801 * @fn zbSocStoreScene
802 *
803 * @brief Store Scene.
804 *
805 * @param groupId - Group ID of the Scene.
806 * @param sceneId - Scene ID of the Scene.
807 * @param dstAddr - Nwk Addr or Group ID of the Light(s) to be controled.
808 * @param endpoint - endpoint of the Light.
809 * @param addrMode - Unicast or Group cast.
810 *
811 * @return none
812 */
813 void zbSocStoreScene(uint16_t groupId, uint8_t sceneId, uint16_t dstAddr,
814 uint8_t endpoint, uint8_t addrMode)
815 {
816 uint8_t cmd[] =
817 { 0xFE, 14, /*RPC payload Len */
818 0x29, /*MT_RPC_CMD_AREQ + MT_RPC_SYS_APP */
819 0x00, /*MT_APP_MSG */
820 0x0B, /*Application Endpoint */
821 (dstAddr & 0x00ff), (dstAddr & 0xff00) >> 8, endpoint, /*Dst EP */
822 (ZCL_CLUSTER_ID_GEN_SCENES & 0x00ff), (ZCL_CLUSTER_ID_GEN_SCENES & 0xff00)
823 >> 8, 0x07, //Data Len
824 addrMode, 0x01, //0x01 ZCL frame control field. (send to the light cluster only)
825 transSeqNumber++, COMMAND_SCENE_STORE, (groupId & 0x00ff), (groupId
826 & 0xff00) >> 8, sceneId++, 0x00 //FCS - fill in later
827 };
829 calcFcs(cmd, sizeof(cmd));
830 zbSocTransportWrite(cmd, sizeof(cmd));
831 }
833 /*********************************************************************
834 * @fn zbSocRecallScene
835 *
836 * @brief Recall Scene.
837 *
838 * @param groupId - Group ID of the Scene.
839 * @param sceneId - Scene ID of the Scene.
840 * @param dstAddr - Nwk Addr or Group ID of the Light(s) to be controled.
841 * @param endpoint - endpoint of the Light.
842 * @param addrMode - Unicast or Group cast.
844 * @return none
845 */
846 void zbSocRecallScene(uint16_t groupId, uint8_t sceneId, uint16_t dstAddr,
847 uint8_t endpoint, uint8_t addrMode)
848 {
849 uint8_t cmd[] =
850 { 0xFE, 14, /*RPC payload Len */
851 0x29, /*MT_RPC_CMD_AREQ + MT_RPC_SYS_APP */
852 0x00, /*MT_APP_MSG */
853 0x0B, /*Application Endpoint */
854 (dstAddr & 0x00ff), (dstAddr & 0xff00) >> 8, endpoint, /*Dst EP */
855 (ZCL_CLUSTER_ID_GEN_SCENES & 0x00ff), (ZCL_CLUSTER_ID_GEN_SCENES & 0xff00)
856 >> 8, 0x07, //Data Len
857 addrMode, 0x01, //0x01 ZCL frame control field. (send to the light cluster only)
858 transSeqNumber++, COMMAND_SCENE_RECALL, (groupId & 0x00ff), (groupId
859 & 0xff00) >> 8, sceneId++, 0x00 //FCS - fill in later
860 };
862 calcFcs(cmd, sizeof(cmd));
863 zbSocTransportWrite(cmd, sizeof(cmd));
864 }
866 /*********************************************************************
867 * @fn zbSocBind
868 *
869 * @brief Recall Scene.
870 *
871 * @param
872 *
873 * @return none
874 */
875 void zbSocBind(uint16_t srcNwkAddr, uint8_t srcEndpoint, uint8_t srcIEEE[8],
876 uint8_t dstEndpoint, uint8_t dstIEEE[8], uint16_t clusterID)
877 {
878 uint8_t cmd[] =
879 { 0xFE, 23, /*RPC payload Len */
880 MT_RPC_CMD_SREQ | MT_RPC_SYS_ZDO,
881 0x21, /*MT_ZDO_BIND_REQ*/
882 (srcNwkAddr & 0x00ff), /*Src Nwk Addr - To send the bind message to*/
883 (srcNwkAddr & 0xff00) >> 8, /*Src Nwk Addr - To send the bind message to*/
884 srcIEEE[0], /*Src IEEE Addr for the binding*/
885 srcIEEE[1], /*Src IEEE Addr for the binding*/
886 srcIEEE[2], /*Src IEEE Addr for the binding*/
887 srcIEEE[3], /*Src IEEE Addr for the binding*/
888 srcIEEE[4], /*Src IEEE Addr for the binding*/
889 srcIEEE[5], /*Src IEEE Addr for the binding*/
890 srcIEEE[6], /*Src IEEE Addr for the binding*/
891 srcIEEE[7], /*Src IEEE Addr for the binding*/
892 srcEndpoint, /*Src endpoint for the binding*/
893 (clusterID & 0x00ff), /*cluster ID to bind*/
894 (clusterID & 0xff00) >> 8, /*cluster ID to bind*/
895 afAddr64Bit, /*Addr mode of the dst to bind*/
896 dstIEEE[0], /*Dst IEEE Addr for the binding*/
897 dstIEEE[1], /*Dst IEEE Addr for the binding*/
898 dstIEEE[2], /*Dst IEEE Addr for the binding*/
899 dstIEEE[3], /*Dst IEEE Addr for the binding*/
900 dstIEEE[4], /*Dst IEEE Addr for the binding*/
901 dstIEEE[5], /*Dst IEEE Addr for the binding*/
902 dstIEEE[6], /*Dst IEEE Addr for the binding*/
903 dstIEEE[7], /*Dst IEEE Addr for the binding*/
904 dstEndpoint, /*Dst endpoint for the binding*/
905 0x00 //FCS - fill in later
906 };
908 /*printf("zbSocBind: srcNwkAddr=0x%x, srcEndpoint=0x%x, srcIEEE=0x%x:%x:%x:%x:%x:%x:%x:%x, dstEndpoint=0x%x, dstIEEE=0x%x:%x:%x:%x:%x:%x:%x:%x, clusterID:%x\n",
909 srcNwkAddr, srcEndpoint, srcIEEE[0], srcIEEE[1], srcIEEE[2], srcIEEE[3], srcIEEE[4], srcIEEE[5], srcIEEE[6], srcIEEE[7],
910 srcEndpoint, dstIEEE[0], dstIEEE[1], dstIEEE[2], dstIEEE[3], dstIEEE[4], dstIEEE[5], dstIEEE[6], dstIEEE[7], clusterID);*/
912 calcFcs(cmd, sizeof(cmd));
913 zbSocTransportWrite(cmd, sizeof(cmd));
914 }
916 void zbSocGetInfo(void)
917 {
918 uint8_t cmd[] =
919 { 0xFE, 0, /*RPC payload Len */
920 MT_RPC_CMD_SREQ | MT_RPC_SYS_UTIL,
921 MT_UTIL_GET_DEVICE_INFO,
922 0x00 //FCS - fill in later
923 };
925 //printf("zbSocGetInfo++ \n");
927 calcFcs(cmd, sizeof(cmd));
928 zbSocTransportWrite(cmd, sizeof(cmd));
929 }
931 /*********************************************************************
932 * @fn zbSocGetState
933 *
934 * @brief Send the get state command to a ZLL light.
935 *
936 * @param dstAddr - Nwk Addr or Group ID of the Light(s) to be sent the command.
937 * @param endpoint - endpoint of the Light.
938 * @param addrMode - Unicast or Group cast.
939 *
940 * @return none
941 */
942 void zbSocGetState(uint16_t dstAddr, uint8_t endpoint, uint8_t addrMode)
943 {
944 uint8_t cmd[] =
945 { 0xFE, 13, /*RPC payload Len */
946 0x29, /*MT_RPC_CMD_AREQ + MT_RPC_SYS_APP */
947 0x00, /*MT_APP_MSG */
948 0x0B, /*Application Endpoint */
949 (dstAddr & 0x00ff), (dstAddr & 0xff00) >> 8, endpoint, /*Dst EP */
950 (ZCL_CLUSTER_ID_GEN_ON_OFF & 0x00ff), (ZCL_CLUSTER_ID_GEN_ON_OFF & 0xff00)
951 >> 8, 0x06, //Data Len
952 addrMode, 0x00, //0x00 ZCL frame control field. not specific to a cluster (i.e. a SCL founadation command)
953 transSeqNumber++, ZCL_CMD_READ, (ATTRID_ON_OFF & 0x00ff), (ATTRID_ON_OFF
954 & 0xff00) >> 8, 0x00 //FCS - fill in later
955 };
957 calcFcs(cmd, sizeof(cmd));
958 zbSocTransportWrite(cmd, sizeof(cmd));
959 }
961 /*********************************************************************
962 * @fn zbSocGetLevel
963 *
964 * @brief Send the get level command to a ZLL light.
965 *
966 * @param dstAddr - Nwk Addr or Group ID of the Light(s) to be sent the command.
967 * @param endpoint - endpoint of the Light.
968 * @param addrMode - Unicast or Group cast.
969 *
970 * @return none
971 */
972 void zbSocGetLevel(uint16_t dstAddr, uint8_t endpoint, uint8_t addrMode)
973 {
974 uint8_t cmd[] =
975 { 0xFE, 13, /*RPC payload Len */
976 0x29, /*MT_RPC_CMD_AREQ + MT_RPC_SYS_APP */
977 0x00, /*MT_APP_MSG */
978 0x0B, /*Application Endpoint */
979 (dstAddr & 0x00ff), (dstAddr & 0xff00) >> 8, endpoint, /*Dst EP */
980 (ZCL_CLUSTER_ID_GEN_LEVEL_CONTROL & 0x00ff), (ZCL_CLUSTER_ID_GEN_LEVEL_CONTROL
981 & 0xff00) >> 8,
982 0x06, //Data Len
983 addrMode,
984 0x00, //0x00 ZCL frame control field. not specific to a cluster (i.e. a SCL founadation command)
985 transSeqNumber++, ZCL_CMD_READ, (ATTRID_LEVEL_CURRENT_LEVEL & 0x00ff),
986 (ATTRID_LEVEL_CURRENT_LEVEL & 0xff00) >> 8, 0x00 //FCS - fill in later
987 };
989 calcFcs(cmd, sizeof(cmd));
990 zbSocTransportWrite(cmd, sizeof(cmd));
991 }
993 /*********************************************************************
994 * @fn zbSocGetHue
995 *
996 * @brief Send the get hue command to a ZLL light.
997 *
998 * @param dstAddr - Nwk Addr or Group ID of the Light(s) to be sent the command.
999 * @param endpoint - endpoint of the Light.
1000 * @param addrMode - Unicast or Group cast.
1001 *
1002 * @return none
1003 */
1004 void zbSocGetHue(uint16_t dstAddr, uint8_t endpoint, uint8_t addrMode)
1005 {
1006 uint8_t cmd[] =
1007 { 0xFE, 13, /*RPC payload Len */
1008 0x29, /*MT_RPC_CMD_AREQ + MT_RPC_SYS_APP */
1009 0x00, /*MT_APP_MSG */
1010 0x0B, /*Application Endpoint */
1011 (dstAddr & 0x00ff), (dstAddr & 0xff00) >> 8, endpoint, /*Dst EP */
1012 (ZCL_CLUSTER_ID_LIGHTING_COLOR_CONTROL & 0x00ff),
1013 (ZCL_CLUSTER_ID_LIGHTING_COLOR_CONTROL & 0xff00) >> 8,
1014 0x06, //Data Len
1015 addrMode,
1016 0x00, //0x00 ZCL frame control field. not specific to a cluster (i.e. a SCL founadation command)
1017 transSeqNumber++, ZCL_CMD_READ, (ATTRID_LIGHTING_COLOR_CONTROL_CURRENT_HUE
1018 & 0x00ff), (ATTRID_LIGHTING_COLOR_CONTROL_CURRENT_HUE & 0xff00) >> 8,
1019 0x00 //FCS - fill in later
1020 };
1022 calcFcs(cmd, sizeof(cmd));
1023 zbSocTransportWrite(cmd, sizeof(cmd));
1024 }
1026 /*********************************************************************
1027 * @fn zbSocGetSat
1028 *
1029 * @brief Send the get saturation command to a ZLL light.
1030 *
1031 * @param dstAddr - Nwk Addr or Group ID of the Light(s) to be sent the command.
1032 * @param endpoint - endpoint of the Light.
1033 * @param addrMode - Unicast or Group cast.
1034 *
1035 * @return none
1036 */
1037 void zbSocGetSat(uint16_t dstAddr, uint8_t endpoint, uint8_t addrMode)
1038 {
1039 uint8_t cmd[] =
1040 { 0xFE, 13, /*RPC payload Len */
1041 0x29, /*MT_RPC_CMD_AREQ + MT_RPC_SYS_APP */
1042 0x00, /*MT_APP_MSG */
1043 0x0B, /*Application Endpoint */
1044 (dstAddr & 0x00ff), (dstAddr & 0xff00) >> 8, endpoint, /*Dst EP */
1045 (ZCL_CLUSTER_ID_LIGHTING_COLOR_CONTROL & 0x00ff),
1046 (ZCL_CLUSTER_ID_LIGHTING_COLOR_CONTROL & 0xff00) >> 8,
1047 0x06, //Data Len
1048 addrMode,
1049 0x00, //0x00 ZCL frame control field. not specific to a cluster (i.e. a SCL founadation command)
1050 transSeqNumber++, ZCL_CMD_READ,
1051 (ATTRID_LIGHTING_COLOR_CONTROL_CURRENT_SATURATION & 0x00ff),
1052 (ATTRID_LIGHTING_COLOR_CONTROL_CURRENT_SATURATION & 0xff00) >> 8, 0x00 //FCS - fill in later
1053 };
1055 calcFcs(cmd, sizeof(cmd));
1056 zbSocTransportWrite(cmd, sizeof(cmd));
1057 }
1059 /*********************************************************************
1060 * @fn zbSocGetModel
1061 *
1062 * @brief Send the get saturation command to a ZLL light.
1063 *
1064 * @param dstAddr - Nwk Addr or Group ID of the Light(s) to be sent the command.
1065 * @param endpoint - endpoint of the Light.
1066 * @param addrMode - Unicast or Group cast.
1067 *
1068 * @return none
1069 */
1070 void zbSocGetModel(uint16_t dstAddr, uint8_t endpoint, uint8_t addrMode)
1071 {
1072 uint8_t cmd[] =
1073 { 0xFE, 13, /*RPC payload Len */
1074 0x29, /*MT_RPC_CMD_AREQ + MT_RPC_SYS_APP */
1075 0x00, /*MT_APP_MSG */
1076 0x0B, /*Application Endpoint */
1077 (dstAddr & 0x00ff), (dstAddr & 0xff00) >> 8, endpoint, /*Dst EP */
1078 (ZCL_CLUSTER_ID_GEN_BASIC & 0x00ff),
1079 (ZCL_CLUSTER_ID_GEN_BASIC & 0xff00) >> 8,
1080 0x06, //Data Len
1081 addrMode,
1082 0x00, //0x00 ZCL frame control field. not specific to a cluster (i.e. a SCL foundation command)
1083 transSeqNumber++, ZCL_CMD_READ,
1084 (ATTRID_BASIC_MODEL_ID & 0x00ff),
1085 (ATTRID_BASIC_MODEL_ID & 0xff00) >> 8,
1086 0x00 //FCS - fill in later
1087 };
1089 //printf("zbSocGetModel: dstAddr:%x, endpoint:%x, addrMode:%x\n", dstAddr, endpoint, addrMode);
1091 calcFcs(cmd, sizeof(cmd));
1092 zbSocTransportWrite(cmd, sizeof(cmd));
1093 }
1095 /*************************************************************************************************
1096 * @fn processRpcSysAppTlInd()
1097 *
1098 * @brief process the TL Indication from the ZLL controller
1099 *
1100 * @param none
1101 *
1102 * @return length of current Rx Buffer
1103 *************************************************************************************************/
1104 static void processRpcSysAppTlInd(uint8_t *TlIndBuff)
1105 {
1106 epInfo_t epInfo;
1108 epInfo.nwkAddr = BUILD_UINT16(TlIndBuff[0], TlIndBuff[1]);
1109 TlIndBuff += 2;
1110 epInfo.endpoint = *TlIndBuff++;
1111 epInfo.profileID = BUILD_UINT16(TlIndBuff[0], TlIndBuff[1]);
1112 TlIndBuff += 2;
1113 epInfo.deviceID = BUILD_UINT16(TlIndBuff[0], TlIndBuff[1]);
1114 TlIndBuff += 2;
1115 epInfo.version = *TlIndBuff++;
1116 epInfo.status = *TlIndBuff++;
1118 if (zbSocCb.pfnTlIndicationCb)
1119 {
1120 zbSocCb.pfnTlIndicationCb(&epInfo);
1121 }
1122 }
1124 /*************************************************************************************************
1125 * @fn processRpcSysAppZcl()
1126 *
1127 * @brief process the ZCL Rsp from the ZLL controller
1128 *
1129 * @param none
1130 *
1131 * @return length of current Rx Buffer
1132 *************************************************************************************************/
1133 static void processRpcSysAppZcl(uint8_t *zclRspBuff)
1134 {
1135 uint8_t zclHdrLen = 3;
1136 uint16_t nwkAddr, clusterID;
1137 uint8_t endpoint, zclFrameLen, zclFrameFrameControl;
1139 //printf("processRpcSysAppZcl++\n");
1141 //This is a ZCL response
1143 //Index past app EP
1144 zclRspBuff++;
1145 nwkAddr = BUILD_UINT16(zclRspBuff[0], zclRspBuff[1]);
1146 zclRspBuff += 2;
1148 endpoint = *zclRspBuff++;
1149 clusterID = BUILD_UINT16(zclRspBuff[0], zclRspBuff[1]);
1150 zclRspBuff += 2;
1152 zclFrameLen = *zclRspBuff++;
1153 zclFrameFrameControl = *zclRspBuff++;
1154 //is it manufacturer specific
1155 if (zclFrameFrameControl & (1 << 2))
1156 {
1157 //currently not supported shown for reference
1158 uint16_t ManSpecCode;
1159 //manu spec code
1160 ManSpecCode = BUILD_UINT16(zclRspBuff[0], zclRspBuff[1]);
1161 zclRspBuff += 2;
1162 //Manufacturer specif commands have 2 extra byte in te header
1163 zclHdrLen += 2;
1165 //supress warning
1166 (void)ManSpecCode;
1167 }
1169 //is this a foundation command
1170 if ((zclFrameFrameControl & 0x3) == 0)
1171 {
1172 //printf("processRpcSysAppZcl: Foundation messagex\n");
1173 processRpcSysAppZclFoundation(zclRspBuff, zclFrameLen, clusterID, nwkAddr,
1174 endpoint);
1175 }
1176 }
1178 /*************************************************************************************************
1179 * @fn processRpcSysAppZclFoundation()
1180 *
1181 * @brief process the ZCL Rsp from the ZLL controller
1182 *
1183 * @param none
1184 *
1185 * @return length of current Rx Buffer
1186 *************************************************************************************************/
1187 static void processRpcSysAppZclFoundation(uint8_t *zclRspBuff,
1188 uint8_t zclFrameLen, uint16_t clusterID, uint16_t nwkAddr, uint8_t endpoint)
1189 {
1190 uint8_t transSeqNum, commandID;
1192 transSeqNum = *zclRspBuff++;
1193 commandID = *zclRspBuff++;
1195 if (commandID == ZCL_CMD_READ_RSP)
1196 {
1197 uint16_t attrID;
1198 uint8_t status;
1199 uint8_t dataType;
1201 attrID = BUILD_UINT16(zclRspBuff[0], zclRspBuff[1]);
1202 zclRspBuff += 2;
1203 status = *zclRspBuff++;
1204 //get data type;
1205 dataType = *zclRspBuff++;
1207 //printf("processRpcSysAppZclFoundation: clusterID:%x, attrID:%x, dataType=%x\n", clusterID, attrID, dataType);
1208 if ((clusterID == ZCL_CLUSTER_ID_GEN_BASIC) && (attrID == ATTRID_BASIC_MODEL_ID)
1209 && (dataType == ZCL_DATATYPE_CHAR_STR))
1210 {
1211 if (zbSocCb.pfnZclGetModelCb)
1212 {
1213 zbSocCb.pfnZclGetModelCb(&zclRspBuff[0]);
1214 }
1215 }
1216 else if ((clusterID == ZCL_CLUSTER_ID_GEN_ON_OFF) && (attrID == ATTRID_ON_OFF)
1217 && (dataType == ZCL_DATATYPE_BOOLEAN))
1218 {
1219 if (zbSocCb.pfnZclGetStateCb)
1220 {
1221 uint8_t state = zclRspBuff[0];
1222 zbSocCb.pfnZclGetStateCb(state, nwkAddr, endpoint);
1223 }
1224 }
1225 else if ((clusterID == ZCL_CLUSTER_ID_GEN_LEVEL_CONTROL)
1226 && (attrID == ATTRID_LEVEL_CURRENT_LEVEL)
1227 && (dataType == ZCL_DATATYPE_UINT8))
1228 {
1229 if (zbSocCb.pfnZclGetLevelCb)
1230 {
1231 uint8_t level = zclRspBuff[0];
1232 zbSocCb.pfnZclGetLevelCb(level, nwkAddr, endpoint);
1233 }
1234 }
1235 else if ((clusterID == ZCL_CLUSTER_ID_LIGHTING_COLOR_CONTROL)
1236 && (attrID == ATTRID_LIGHTING_COLOR_CONTROL_CURRENT_HUE)
1237 && (dataType == ZCL_DATATYPE_UINT8))
1238 {
1239 if (zbSocCb.pfnZclGetHueCb)
1240 {
1241 uint8_t hue = zclRspBuff[0];
1242 zbSocCb.pfnZclGetHueCb(hue, nwkAddr, endpoint);
1243 }
1244 }
1245 else if ((clusterID == ZCL_CLUSTER_ID_LIGHTING_COLOR_CONTROL)
1246 && (attrID == ATTRID_LIGHTING_COLOR_CONTROL_CURRENT_SATURATION)
1247 && (dataType == ZCL_DATATYPE_UINT8))
1248 {
1249 if (zbSocCb.pfnZclGetSatCb)
1250 {
1251 uint8_t sat = zclRspBuff[0];
1252 zbSocCb.pfnZclGetSatCb(sat, nwkAddr, endpoint);
1253 }
1254 }
1255 else
1256 {
1257 //unsupported ZCL Read Rsp
1258 printf("processRpcSysAppZclFoundation: Unsupported ZCL Rsp\n");
1259 }
1260 }
1261 else
1262 {
1263 //unsupported ZCL Rsp
1264 printf("processRpcSysAppZclFoundation: Unsupported ZCL Rsp");
1265 ;
1266 }
1268 return;
1269 }
1271 /*************************************************************************************************
1272 * @fn processRpcSysZdoEndDeviceAnnceInd
1273 *
1274 * @brief read and process the RPC ZDO message from the ZLL controller
1275 *
1276 * @param none
1277 *
1278 * @return length of current Rx Buffer
1279 *************************************************************************************************/
1280 void processRpcSysZdoEndDeviceAnnceInd(uint8_t *EndDeviceAnnceIndBuff)
1281 {
1282 epInfo_t epInfo = { 0 };
1283 uint8_t i;
1285 EndDeviceAnnceIndBuff += 2;
1286 epInfo.nwkAddr =
1287 BUILD_UINT16(EndDeviceAnnceIndBuff[0], EndDeviceAnnceIndBuff[1]);
1288 EndDeviceAnnceIndBuff += 2;
1290 printf("processRpcSysZdoEndDeviceAnnceInd nwkAddr: %x, IEEE Addr: ",
1291 epInfo.nwkAddr);
1293 for (i = 0; i < 8; i++)
1294 {
1295 epInfo.IEEEAddr[i] = *EndDeviceAnnceIndBuff++;
1296 printf("%x", epInfo.IEEEAddr[i]);
1297 if (i < 7) printf(":");
1298 }
1299 printf("\n");
1301 if (zbSocCb.pfnNewDevIndicationCb)
1302 {
1303 zbSocCb.pfnNewDevIndicationCb(&epInfo);
1304 }
1306 }
1308 /*************************************************************************************************
1309 * @fn processRpcSysZdoActiveEPRsp
1310 *
1311 * @brief read and process the RPC ZDO message from the ZLL controller
1312 *
1313 * @param none
1314 *
1315 * @return length of current Rx Buffer
1316 *************************************************************************************************/
1317 void processRpcSysZdoActiveEPRsp(uint8_t *ActiveEPRspBuff)
1318 {
1319 uint16_t nwkAddr;
1320 uint8_t epCount;
1322 nwkAddr = BUILD_UINT16(ActiveEPRspBuff[0], ActiveEPRspBuff[1]);
1323 ActiveEPRspBuff += 2;
1324 epCount = *ActiveEPRspBuff;
1326 printf("processRpcSysZdoActiveEPRsp nwkAddr: %x, Num Ep's: %d\n", nwkAddr,
1327 epCount);
1329 //Can be used to check all Ep's have associated ZdoSimpleDesc.
1330 }
1332 /*************************************************************************************************
1333 * @fn processRpcSysZdoSimpleDescRsp
1334 *
1335 * @brief read and process the RPC ZDO message from the ZLL controller
1336 *
1337 * @param none
1338 *
1339 * @return length of current Rx Buffer
1340 *************************************************************************************************/
1341 void processRpcSysZdoSimpleDescRsp(uint8_t *SimpleDescRspBuff)
1342 {
1343 epInfo_t epInfo;
1344 uint8_t numInputClusters, numOutputClusters, clusterIdx;
1345 uint16_t *inClusters, *outClusters;
1347 SimpleDescRspBuff += 2; //src address
1348 epInfo.status = *SimpleDescRspBuff++; //status..offset 2
1349 epInfo.nwkAddr = BUILD_UINT16(SimpleDescRspBuff[0], SimpleDescRspBuff[1]); //network address
1350 SimpleDescRspBuff += 2; //increment
1351 //printf("processRpcSysZdoSimpleDescRsp: Length:%x \n",SimpleDescRspBuff[0] );
1352 SimpleDescRspBuff += 1;
1353 epInfo.endpoint = *SimpleDescRspBuff++; //end point
1354 epInfo.profileID = BUILD_UINT16(SimpleDescRspBuff[0], SimpleDescRspBuff[1]); //profile id
1355 SimpleDescRspBuff += 2;
1356 epInfo.deviceID = BUILD_UINT16(SimpleDescRspBuff[0], SimpleDescRspBuff[1]); //device id
1357 SimpleDescRspBuff += 2;
1358 epInfo.version = *SimpleDescRspBuff++;
1359 // epInfo.status = *TlIndBuff++;
1360 epInfo.deviceName = NULL;
1362 printf("processRpcSysZdoSimpleDescRsp: nwkAddr:%x endpoint:%x\n", epInfo.nwkAddr, epInfo.endpoint);
1364 numInputClusters = *SimpleDescRspBuff++;
1365 inClusters = (uint16_t*) malloc(2*numInputClusters);
1366 if(inClusters)
1367 {
1368 printf("processRpcSysZdoSimpleDescRsp: inClusters[%d]:\n", numInputClusters);
1369 for(clusterIdx = 0; clusterIdx < numInputClusters; clusterIdx++)
1370 {
1371 inClusters[clusterIdx] = BUILD_UINT16(SimpleDescRspBuff[0], SimpleDescRspBuff[1]); //profile id
1372 SimpleDescRspBuff += 2;
1373 printf("0x%x ", inClusters[clusterIdx]);
1374 }
1375 }
1376 printf("\n");
1378 numOutputClusters = *SimpleDescRspBuff++;
1379 outClusters = (uint16_t*) malloc(2*numOutputClusters);
1380 if(outClusters)
1381 {
1382 printf("processRpcSysZdoSimpleDescRsp: outClusters[%d]:\n", numOutputClusters);
1383 for(clusterIdx = 0; clusterIdx < numOutputClusters; clusterIdx++)
1384 {
1385 outClusters[clusterIdx] = BUILD_UINT16(SimpleDescRspBuff[0], SimpleDescRspBuff[1]); //profile id
1386 SimpleDescRspBuff += 2;
1387 printf("0x%x ", outClusters[clusterIdx]);
1388 }
1389 }
1390 printf("\n");
1392 //if this is the TL endpoint then ignore it
1393 if( !((numInputClusters == 1) && (numOutputClusters == 1) && (epInfo.profileID) == (0xC05E)) )
1394 {
1395 if (zbSocCb.pfnZdoSimpleDescRspCb)
1396 {
1397 zbSocCb.pfnZdoSimpleDescRspCb(&epInfo);
1398 }
1399 }
1401 if(inClusters)
1402 {
1403 free(inClusters);
1404 }
1405 if(outClusters)
1406 {
1407 free(outClusters);
1408 }
1409 }
1411 void processRpcSysZdoLeaveInd(uint8_t *LeaveIndRspBuff)
1412 {
1413 uint16_t nwkAddr;
1415 nwkAddr = BUILD_UINT16(LeaveIndRspBuff[0], LeaveIndRspBuff[1]);
1416 LeaveIndRspBuff += 2;
1418 printf("processRpcSysZdoLeaveInd nwkAddr: %x\n", nwkAddr);
1420 if (zbSocCb.pfnZdoLeaveIndCb)
1421 {
1422 zbSocCb.pfnZdoLeaveIndCb(nwkAddr);
1423 }
1424 }
1426 void processRpcUtilGetDevInfoRsp(uint8_t *GetDevInfoRsp)
1427 {
1428 uint8_t ieeeAddr[8], ieeeIdx, devType, devState, status;
1429 uint16_t nwkAddr;
1431 status = *GetDevInfoRsp++;
1433 if(status == 0)
1434 {
1435 for(ieeeIdx = 0; ieeeIdx < 8; ieeeIdx++)
1436 {
1437 ieeeAddr[ieeeIdx] = *GetDevInfoRsp++;
1438 }
1440 nwkAddr = BUILD_UINT16(GetDevInfoRsp[0], GetDevInfoRsp[1]);
1441 GetDevInfoRsp += 2;
1443 devType = *GetDevInfoRsp++;
1445 devState = *GetDevInfoRsp++;
1447 //printf("processRpcUtilGetDevInfoRsp: status:%x devState:%x, nwkAddr:%x ieeeIdx:%x:%x:%x:%x:%x:%x:%x:%x\n", status, devState, nwkAddr,
1448 // ieeeAddr[7], ieeeAddr[6], ieeeAddr[5], ieeeAddr[4], ieeeAddr[3], ieeeAddr[2], ieeeAddr[1], ieeeAddr[0]);
1449 }
1451 if (zbSocCb.pfnUtilGetDevInfoRsp)
1452 {
1453 zbSocCb.pfnUtilGetDevInfoRsp(status, nwkAddr, ieeeAddr, devType, devState);
1454 }
1455 }
1457 /*************************************************************************************************
1458 * @fn processRpcSysApp()
1459 *
1460 * @brief read and process the RPC App message from the ZLL controller
1461 *
1462 * @param none
1463 *
1464 * @return length of current Rx Buffer
1465 *************************************************************************************************/
1466 static void processRpcSysApp(uint8_t *rpcBuff)
1467 {
1468 if (rpcBuff[1] == MT_APP_ZLL_TL_IND)
1469 {
1470 processRpcSysAppTlInd(&rpcBuff[2]);
1471 }
1473 else if (rpcBuff[1] == MT_APP_RSP)
1474 {
1475 processRpcSysAppZcl(&rpcBuff[2]);
1476 }
1477 else if (rpcBuff[1] == 0)
1478 {
1479 if (rpcBuff[2] == 0)
1480 {
1481 //printf("processRpcSysApp: Command Received Successfully\n\n");
1482 }
1483 else
1484 {
1485 printf("processRpcSysApp: Command Error\n\n");
1486 }
1487 }
1488 else
1489 {
1490 printf("processRpcSysApp: Unsupported MT App Msg\n");
1491 }
1493 return;
1494 }
1496 /*************************************************************************************************
1497 * @fn processRpcSysZdo()
1498 *
1499 * @brief read and process the RPC ZDO messages from the ZLL controller
1500 *
1501 * @param none
1502 *
1503 * @return length of current Rx Buffer
1504 *************************************************************************************************/
1505 void processRpcSysZdo(uint8_t *rpcBuff)
1506 {
1507 if (rpcBuff[1] == MT_ZDO_END_DEVICE_ANNCE_IND)
1508 {
1509 processRpcSysZdoEndDeviceAnnceInd(&rpcBuff[2]);
1510 }
1511 else if (rpcBuff[1] == MT_ZDO_ACTIVE_EP_RSP)
1512 {
1513 processRpcSysZdoActiveEPRsp(&rpcBuff[2]);
1514 }
1515 else if (rpcBuff[1] == MT_ZDO_SIMPLE_DESC_RSP)
1516 {
1517 processRpcSysZdoSimpleDescRsp(&rpcBuff[2]);
1518 }
1519 else if (rpcBuff[1] == MT_ZDO_LEAVE_IND)
1520 {
1521 processRpcSysZdoLeaveInd(&rpcBuff[2]);
1522 }
1523 else
1524 {
1525 //printf("processRpcSysZdo: Unsupported MT ZDO Msg\n");
1526 }
1528 return;
1530 }
1532 /*************************************************************************************************
1533 * @fn processRpcSysUtil()
1534 *
1535 * @brief read and process the RPC UTIL messages from the ZLL controller
1536 *
1537 * @param none
1538 *
1539 * @return length of current Rx Buffer
1540 *************************************************************************************************/
1541 void processRpcSysUtil(uint8_t *rpcBuff)
1542 {
1543 if (rpcBuff[1] == MT_UTIL_GET_DEVICE_INFO)
1544 {
1545 processRpcUtilGetDevInfoRsp(&rpcBuff[2]);
1546 }
1547 else
1548 {
1549 printf("processRpcSysUtil: Unsupported MT UTIL Msg\n");
1550 }
1552 return;
1554 }
1556 /* @fn processRpcSysDbg()
1557 *
1558 * @brief read and process the RPC debug message from the ZLL controller
1559 *
1560 * @param none
1561 *
1562 * @return length of current Rx Buffer
1563 *************************************************************************************************/
1564 static void processRpcSysDbg(uint8_t *rpcBuff)
1565 {
1566 if (rpcBuff[1] == MT_DEBUG_MSG)
1567 {
1568 //we got a debug string
1569 printf("lcd_debug message from zll controller: %s\n",
1570 (char*) &(rpcBuff[2]));
1571 }
1572 else if (rpcBuff[1] == 0)
1573 {
1574 if (rpcBuff[2] == 0)
1575 {
1576 //printf("processRpcSysDbg: Command Received Successfully\n\n");
1577 }
1578 else
1579 {
1580 printf("processRpcSysDbg: Command Error\n\n");
1581 }
1582 }
1583 else
1584 {
1585 printf("processRpcSysDbg: Unsupported MT App Msg\n");
1586 }
1587 }
1589 /*************************************************************************************************
1590 * @fn zbSocProcessRpc()
1591 *
1592 * @brief read and process the RPC from the ZLL controller
1593 *
1594 * @param none
1595 *
1596 * @return length of current Rx Buffer
1597 *************************************************************************************************/
1598 void zbSocProcessRpc(void)
1599 {
1600 uint8_t rpcLen, bytesRead, sofByte, *rpcBuff, rpcBuffIdx;
1601 static uint8_t retryAttempts = 0;
1603 //read first byte and check it is a SOF
1604 read(serialPortFd, &sofByte, 1);
1605 if (sofByte == MT_RPC_SOF)
1606 {
1607 retryAttempts = 0;
1609 //read len
1610 bytesRead = read(serialPortFd, &rpcLen, 1);
1612 if (bytesRead == 1)
1613 {
1614 //allocating RPC payload (+ cmd0, cmd1 and fcs)
1615 rpcLen += 3;
1617 rpcBuff = malloc(rpcLen);
1619 //non blocking read, so we need to wait for the rpc to be read
1620 rpcBuffIdx = 0;
1621 while (rpcLen > 0)
1622 {
1623 //read rpc
1624 bytesRead = read(serialPortFd, &(rpcBuff[rpcBuffIdx]), rpcLen);
1626 //check for error
1627 if (bytesRead > rpcLen)
1628 {
1629 //there was an error
1630 printf("zbSocProcessRpc: read of %d bytes failed - %s\n", rpcLen,
1631 strerror(errno));
1633 if (retryAttempts++ < 5)
1634 {
1635 //sleep for 10ms
1636 usleep(10000);
1637 //try again
1638 bytesRead = 0;
1639 }
1640 else
1641 {
1642 //something went wrong.
1643 printf("zbSocProcessRpc: failed\n");
1644 free(rpcBuff);
1645 return;
1646 }
1647 }
1649 rpcLen -= bytesRead;
1650 rpcBuffIdx += bytesRead;
1651 }
1653 //printf("zbSocProcessRpc: Processing CMD0:%x, CMD1:%x\n", rpcBuff[0],
1654 // rpcBuff[1]);
1655 //Read CMD0
1656 switch (rpcBuff[0] & MT_RPC_SUBSYSTEM_MASK)
1657 {
1658 case MT_RPC_SYS_DBG:
1659 {
1660 processRpcSysDbg(rpcBuff);
1661 break;
1662 }
1663 case MT_RPC_SYS_APP:
1664 {
1665 processRpcSysApp(rpcBuff);
1666 break;
1667 }
1669 case MT_RPC_SYS_ZDO:
1670 {
1671 processRpcSysZdo(rpcBuff);
1672 break;
1673 }
1675 case MT_RPC_SYS_UTIL:
1676 {
1677 processRpcSysUtil(rpcBuff);
1678 break;
1679 }
1681 default:
1682 {
1683 //printf("zbSocProcessRpc: CMD0:%x, CMD1:%x, not handled\n", rpcBuff[0] , rpcBuff[1])
1684 break;
1685 }
1686 }
1688 free(rpcBuff);
1689 }
1690 else
1691 {
1692 printf("zbSocProcessRpc: No valid Start Of Frame found\n");
1693 }
1694 }
1696 return;
1697 }