Watch 1 Star 0 Fork 0

leconiot / z-stackC

Join us
Explore and code with more than 2 million developers,Free private repositories !:)
Sign up
This repository doesn't specify license. Without author's permission, this code is only for learning and cannot be used for other purposes.
基于ti cc2530 的z-stack 协议栈,version 3.0.2,June 15, 2018。 spread retract

  • C 92.4%
  • C++ 6.4%
  • HTML 1.0%
  • JavaScript 0.1%
  • Batchfile 0.1%
Clone or download
zcl.c 158.65 KB
Copy Edit Raw Blame History
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591
/**************************************************************************************************
Filename: zcl.c
Revised: $Date: 2015-09-09 11:51:49 -0700 (Wed, 09 Sep 2015) $
Revision: $Revision: 44489 $
Description: This file contains the Zigbee Cluster Library Foundation functions.
Copyright 2006-2015 Texas Instruments Incorporated. All rights reserved.
IMPORTANT: Your use of this Software is limited to those specific rights
granted under the terms of a software license agreement between the user
who downloaded the software, his/her employer (which must be your employer)
and Texas Instruments Incorporated (the "License"). You may not use this
Software unless you agree to abide by the terms of the License. The License
limits your use, and you acknowledge, that the Software may not be modified,
copied or distributed unless embedded on a Texas Instruments microcontroller
or used solely and exclusively in conjunction with a Texas Instruments radio
frequency transceiver, which is integrated into your product. Other than for
the foregoing purpose, you may not use, reproduce, copy, prepare derivative
works of, modify, distribute, perform, display or sell this Software and/or
its documentation for any purpose.
YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,
NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
(INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
Should you have any questions regarding your right to use this Software,
contact Texas Instruments Incorporated at www.TI.com.
**************************************************************************************************/
/*********************************************************************
* INCLUDES
*/
#include "ZComDef.h"
#include "AF.h"
#include "APS.h"
#include "zcl.h"
#include "zcl_general.h"
#if defined ( INTER_PAN )
#include "stub_aps.h"
#endif
#ifdef BDB_REPORTING
#include "bdb_Reporting.h"
#endif
#include "bdb_interface.h"
#include "zcl_green_power.h"
/*********************************************************************
* MACROS
*/
/*** Frame Control ***/
#define zcl_FCType( a ) ( (a) & ZCL_FRAME_CONTROL_TYPE )
#define zcl_FCManuSpecific( a ) ( (a) & ZCL_FRAME_CONTROL_MANU_SPECIFIC )
#define zcl_FCDirection( a ) ( (a) & ZCL_FRAME_CONTROL_DIRECTION )
#define zcl_FCDisableDefaultRsp( a ) ( (a) & ZCL_FRAME_CONTROL_DISABLE_DEFAULT_RSP )
/*** Attribute Access Control ***/
#define zcl_AccessCtrlRead( a ) ( (a) & ACCESS_CONTROL_READ )
#define zcl_AccessCtrlWrite( a ) ( (a) & ACCESS_CONTROL_WRITE )
#define zcl_AccessCtrlCmd( a ) ( (a) & ACCESS_CONTROL_CMD )
#define zcl_AccessCtrlAuthRead( a ) ( (a) & ACCESS_CONTROL_AUTH_READ )
#define zcl_AccessCtrlAuthWrite( a ) ( (a) & ACCESS_CONTROL_AUTH_WRITE )
#define zcl_AccessClient( a ) ( (a) & ACCESS_CLIENT )
#define zclParseCmd( a, b ) zclCmdTable[(a)].pfnParseInProfile( (b) )
#define zclProcessCmd( a, b ) zclCmdTable[(a)].pfnProcessInProfile( (b) )
#define zcl_DefaultRspCmd( zclHdr ) ( zcl_ProfileCmd( (zclHdr).fc.type ) && \
(zclHdr).fc.manuSpecific == 0 && \
(zclHdr).commandID == ZCL_CMD_DEFAULT_RSP )
// Commands that have corresponding responses (ZCL_CMD_WRITE_NO_RSP, does not have response, but must not send default response)
#define CMD_HAS_RSP( cmd ) ( (cmd) == ZCL_CMD_READ || \
(cmd) == ZCL_CMD_WRITE || \
(cmd) == ZCL_CMD_WRITE_UNDIVIDED || \
(cmd) == ZCL_CMD_WRITE_NO_RSP || \
(cmd) == ZCL_CMD_CONFIG_REPORT || \
(cmd) == ZCL_CMD_READ_REPORT_CFG || \
(cmd) == ZCL_CMD_DISCOVER_ATTRS || \
(cmd) == ZCL_CMD_DISCOVER_CMDS_RECEIVED || \
(cmd) == ZCL_CMD_DISCOVER_CMDS_GEN || \
(cmd) == ZCL_CMD_DISCOVER_ATTRS_EXT || \
(cmd) == ZCL_CMD_DEFAULT_RSP ) // exception
#define ZCL_VALID_MIN_HEADER_LEN 3
/*********************************************************************
* CONSTANTS
*/
/*********************************************************************
* TYPEDEFS
*/
typedef struct zclLibPlugin {
struct zclLibPlugin *next;
uint16 startClusterID; // starting cluster ID
uint16 endClusterID; // ending cluster ID
zclInHdlr_t pfnIncomingHdlr; // function to handle incoming message
} zclLibPlugin_t;
// Command record list
typedef struct zclCmdRecsList {
struct zclCmdRecsList *pNext;
uint8 endpoint;
uint8 numCommands;
CONST zclCommandRec_t *pCmdRecs;
} zclCmdRecsList_t;
// Cluster option list item
typedef struct zclClusterOptionList {
struct zclClusterOptionList *next;
uint8 endpoint; // Used to link it into the endpoint descriptor
uint8 numOptions; // Number of the following records
zclOptionRec_t *options; // option records
} zclClusterOptionList;
typedef void *(*zclParseInProfileCmd_t)( zclParseCmd_t *pCmd );
typedef uint8 (*zclProcessInProfileCmd_t)( zclIncoming_t *pInMsg );
typedef struct {
zclParseInProfileCmd_t pfnParseInProfile;
zclProcessInProfileCmd_t pfnProcessInProfile;
} zclCmdItems_t;
// List record for external handler for unhandled ZCL Foundation commands/rsps
typedef struct zclExternalFoundationHandlerList {
struct zclExternalFoundationHandlerList *next;
uint8 zcl_ExternalTaskID;
uint8 zcl_ExternalEndPoint;
} zclExternalFoundationHandlerList;
/*********************************************************************
* GLOBAL VARIABLES
*/
#if !defined ( ZCL_STANDALONE )
uint8 zcl_TaskID;
#endif
// The Application should register its attribute data validation function
zclValidateAttrData_t zcl_ValidateAttrDataCB = (zclValidateAttrData_t)NULL;
// ZCL Sequence number
//uint8 zcl_SeqNum = 0x00; //Not longer used, refer to bdb_getZCLFrameCounter() in bdb_interface.h
uint8 zcl_InSeqNum = 0x00;
uint8 zcl_radius = AF_DEFAULT_RADIUS;
static uint8 savedZCLTransSeqNum = 0;
/*********************************************************************
* EXTERNAL VARIABLES
*/
/*********************************************************************
* EXTERNAL FUNCTIONS
*/
/*********************************************************************
* LOCAL VARIABLES
*/
static zclLibPlugin_t *plugins = (zclLibPlugin_t *)NULL;
#if defined ( ZCL_DISCOVER )
static zclCmdRecsList_t *gpCmdList = (zclCmdRecsList_t *)NULL;
#endif
static zclAttrRecsList *attrList = (zclAttrRecsList *)NULL;
static zclClusterOptionList *clusterOptionList = (zclClusterOptionList *)NULL;
static afIncomingMSGPacket_t *rawAFMsg = (afIncomingMSGPacket_t *)NULL;
#if !defined ( ZCL_STANDALONE )
static zclExternalFoundationHandlerList *externalEndPointHandlerList = (zclExternalFoundationHandlerList *)NULL;
#endif
/*********************************************************************
* LOCAL FUNCTIONS
*/
static uint8 *zclBuildHdr( zclFrameHdr_t *hdr, uint8 *pData );
static uint8 zclCalcHdrSize( zclFrameHdr_t *hdr );
static zclLibPlugin_t *zclFindPlugin( uint16 clusterID, uint16 profileID );
#if !defined ( ZCL_STANDALONE )
static uint8 zcl_addExternalFoundationHandler( uint8 taskId, uint8 endPointId );
static uint8 zcl_getExternalFoundationHandler( afIncomingMSGPacket_t *pInMsg );
#endif // !defined ( ZCL_STANDALONE )
#if defined ( ZCL_DISCOVER )
static zclCmdRecsList_t *zclFindCmdRecsList( uint8 endpoint );
#endif
zclAttrRecsList *zclFindAttrRecsList( uint8 endpoint );
static zclOptionRec_t *zclFindClusterOption( uint8 endpoint, uint16 clusterID );
static uint8 zclGetClusterOption( uint8 endpoint, uint16 clusterID );
static void zclSetSecurityOption( uint8 endpoint, uint16 clusterID, uint8 enable );
static uint8 zcl_DeviceOperational( uint8 srcEP, uint16 clusterID, uint8 frameType, uint8 cmd, uint16 profileID );
#if defined ( ZCL_READ ) || defined ( ZCL_WRITE )
static zclReadWriteCB_t zclGetReadWriteCB( uint8 endpoint );
static zclAuthorizeCB_t zclGetAuthorizeCB( uint8 endpoint );
#endif // ZCL_READ || ZCL_WRITE
#ifdef ZCL_READ
ZStatus_t zclReadAttrData( uint8 *pAttrData, zclAttrRec_t *pAttr, uint16 *pDataLen );
static uint16 zclGetAttrDataLengthUsingCB( uint8 endpoint, uint16 clusterID, uint16 attrId );
static ZStatus_t zclReadAttrDataUsingCB( uint8 endpoint, uint16 clusterId, uint16 attrId,
uint8 *pAttrData, uint16 *pDataLen );
static ZStatus_t zclAuthorizeRead( uint8 endpoint, afAddrType_t *srcAddr, zclAttrRec_t *pAttr );
static void *zclParseInReadRspCmd( zclParseCmd_t *pCmd );
static uint8 zclProcessInReadCmd( zclIncoming_t *pInMsg );
#endif // ZCL_READ
#ifdef ZCL_WRITE
static ZStatus_t zclWriteAttrData( uint8 endpoint, afAddrType_t *srcAddr,
zclAttrRec_t *pAttr, zclWriteRec_t *pWriteRec );
static ZStatus_t zclWriteAttrDataUsingCB( uint8 endpoint, afAddrType_t *srcAddr,
zclAttrRec_t *pAttr, uint8 *pAttrData );
static ZStatus_t zclAuthorizeWrite( uint8 endpoint, afAddrType_t *srcAddr, zclAttrRec_t *pAttr );
static void *zclParseInWriteRspCmd( zclParseCmd_t *pCmd );
static uint8 zclProcessInWriteCmd( zclIncoming_t *pInMsg );
static uint8 zclProcessInWriteUndividedCmd( zclIncoming_t *pInMsg );
#endif // ZCL_WRITE
#ifdef ZCL_REPORT_CONFIGURING_DEVICE
static void *zclParseInConfigReportRspCmd( zclParseCmd_t *pCmd );
static void *zclParseInReadReportCfgRspCmd( zclParseCmd_t *pCmd );
#endif
static void *zclParseInDefaultRspCmd( zclParseCmd_t *pCmd );
#ifdef ZCL_DISCOVER
static uint8 zclFindNextCmdRec( uint8 endpoint, uint16 clusterID, uint8 commandID, uint8 direction, uint8 *pCmdID, zclCommandRec_t *pCmd );
static uint8 zclFindNextAttrRec( uint8 endpoint, uint16 clusterID, uint8 direction, uint16 *attrId, zclAttrRec_t *pAttr );
static void *zclParseInDiscCmdsRspCmd( zclParseCmd_t *pCmd );
static void *zclParseInDiscAttrsRspCmd( zclParseCmd_t *pCmd );
static void *zclParseInDiscAttrsExtRspCmd( zclParseCmd_t *pCmd );
static uint8 zclProcessInDiscCmd( zclIncoming_t *pInMsg );
static uint8 zclProcessInDiscAttrs( zclIncoming_t *pInMsg );
static void zclProcessInDiscAttrsCmd( zclIncoming_t *pInMsg, zclDiscoverAttrsCmd_t *pDiscoverCmd, uint8 attrLenBuf );
static void zclProcessInDiscAttrsExtCmd( zclIncoming_t *pInMsg, zclDiscoverAttrsCmd_t *pDiscoverCmd, uint8 attrLenBuf );
#endif // ZCL_DISCOVER
/*********************************************************************
* Parse Profile Command Function Table
*/
static CONST zclCmdItems_t zclCmdTable[] = {
#ifdef ZCL_READ
/* ZCL_CMD_READ */ { zclParseInReadCmd, zclProcessInReadCmd },
/* ZCL_CMD_READ_RSP */ { zclParseInReadRspCmd, zcl_HandleExternal },
#else
/* ZCL_CMD_READ */ { (zclParseInProfileCmd_t)NULL, (zclProcessInProfileCmd_t)NULL },
/* ZCL_CMD_READ_RSP */ { (zclParseInProfileCmd_t)NULL, (zclProcessInProfileCmd_t)NULL },
#endif // ZCL_READ
#ifdef ZCL_WRITE
/* ZCL_CMD_WRITE */ { zclParseInWriteCmd, zclProcessInWriteCmd },
/* ZCL_CMD_WRITE_UNDIVIDED */ { zclParseInWriteCmd, zclProcessInWriteUndividedCmd },
/* ZCL_CMD_WRITE_RSP */ { zclParseInWriteRspCmd, zcl_HandleExternal },
/* ZCL_CMD_WRITE_NO_RSP */ { zclParseInWriteCmd, zclProcessInWriteCmd },
#else
/* ZCL_CMD_WRITE */ { (zclParseInProfileCmd_t)NULL, (zclProcessInProfileCmd_t)NULL },
/* ZCL_CMD_WRITE_UNDIVIDED */ { (zclParseInProfileCmd_t)NULL, (zclProcessInProfileCmd_t)NULL },
/* ZCL_CMD_WRITE_RSP */ { (zclParseInProfileCmd_t)NULL, (zclProcessInProfileCmd_t)NULL },
/* ZCL_CMD_WRITE_NO_RSP */ { (zclParseInProfileCmd_t)NULL, (zclProcessInProfileCmd_t)NULL },
#endif // ZCL_WRITE
#ifdef ZCL_REPORTING_DEVICE
/* ZCL_CMD_CONFIG_REPORT */ { zclParseInConfigReportCmd, zcl_HandleExternal },
#else
/* ZCL_CMD_CONFIG_REPORT */ { (zclParseInProfileCmd_t)NULL, (zclProcessInProfileCmd_t)NULL },
#endif
#ifdef ZCL_REPORT_CONFIGURING_DEVICE
/* ZCL_CMD_CONFIG_REPORT_RSP */ { zclParseInConfigReportRspCmd, zcl_HandleExternal },
#else
/* ZCL_CMD_CONFIG_REPORT_RSP */ { (zclParseInProfileCmd_t)NULL, (zclProcessInProfileCmd_t)NULL },
#endif
#ifdef ZCL_REPORTING_DEVICE
/* ZCL_CMD_READ_REPORT_CFG */ { zclParseInReadReportCfgCmd, zcl_HandleExternal },
#else
/* ZCL_CMD_READ_REPORT_CFG */ { (zclParseInProfileCmd_t)NULL, (zclProcessInProfileCmd_t)NULL },
#endif
#ifdef ZCL_REPORT_CONFIGURING_DEVICE
/* ZCL_CMD_READ_REPORT_CFG_RSP */ { zclParseInReadReportCfgRspCmd, zcl_HandleExternal },
#else
/* ZCL_CMD_READ_REPORT_CFG_RSP */ { (zclParseInProfileCmd_t)NULL, (zclProcessInProfileCmd_t)NULL },
#endif
#ifdef ZCL_REPORT_DESTINATION_DEVICE
/* ZCL_CMD_REPORT */ { zclParseInReportCmd, zcl_HandleExternal },
#else
/* ZCL_CMD_REPORT */ { (zclParseInProfileCmd_t)NULL, (zclProcessInProfileCmd_t)NULL },
#endif
/* ZCL_CMD_DEFAULT_RSP */ { zclParseInDefaultRspCmd, zcl_HandleExternal },
#ifdef ZCL_DISCOVER
/* ZCL_CMD_DISCOVER_ATTRS */ { zclParseInDiscAttrsCmd, zclProcessInDiscAttrs },
/* ZCL_CMD_DISCOVER_ATTRS_RSP */ { zclParseInDiscAttrsRspCmd, zcl_HandleExternal },
/* *not supported* READ_ATTRS_STRCT */ { NULL, (zclProcessInProfileCmd_t)NULL },
/* *not supported* WRITE_ATTRS_STRCT */ { NULL, (zclProcessInProfileCmd_t)NULL },
/* *not supported* WRITE_ATTRS_STRCT_RSP */ { NULL, (zclProcessInProfileCmd_t)NULL },
/* ZCL_CMD_DISCOVER_CMDS_RECEIVED */ { zclParseInDiscCmdsCmd, zclProcessInDiscCmd },
/* ZCL_CMD_DISCOVER_CMDS_RECEIVED_RSP */ { zclParseInDiscCmdsRspCmd, zcl_HandleExternal },
/* ZCL_CMD_DISCOVER_CMDS_GEN */ { zclParseInDiscCmdsCmd, zclProcessInDiscCmd },
/* ZCL_CMD_DISCOVER_CMDS_GEN_RSP */ { zclParseInDiscCmdsRspCmd, zcl_HandleExternal },
/* ZCL_CMD_DISCOVER_ATTRS_EXT */ { zclParseInDiscAttrsCmd, zclProcessInDiscAttrs },
/* ZCL_CMD_DISCOVER_ATTRS_EXT_RSP */ { zclParseInDiscAttrsExtRspCmd, zcl_HandleExternal },
#else
/* ZCL_CMD_DISCOVER_ATTRS */ { (zclParseInProfileCmd_t)NULL, (zclProcessInProfileCmd_t)NULL },
/* ZCL_CMD_DISCOVER_ATTRS_RSP */ { (zclParseInProfileCmd_t)NULL, (zclProcessInProfileCmd_t)NULL },
/* *not supported* READ_ATTRS_STRCT */ { (zclParseInProfileCmd_t)NULL, (zclProcessInProfileCmd_t)NULL },
/* *not supported* WRITE_ATTRS_STRCT */ { (zclParseInProfileCmd_t)NULL, (zclProcessInProfileCmd_t)NULL },
/* *not supported* WRITE_ATTRS_STRCT_RSP */ { (zclParseInProfileCmd_t)NULL, (zclProcessInProfileCmd_t)NULL },
/* ZCL_CMD_DISCOVER_CMDS_RECEIVED */ { (zclParseInProfileCmd_t)NULL, (zclProcessInProfileCmd_t)NULL },
/* ZCL_CMD_DISCOVER_CMDS_RECEIVED_RSP */ { (zclParseInProfileCmd_t)NULL, (zclProcessInProfileCmd_t)NULL },
/* ZCL_CMD_DISCOVER_CMDS_GEN */ { (zclParseInProfileCmd_t)NULL, (zclProcessInProfileCmd_t)NULL },
/* ZCL_CMD_DISCOVER_CMDS_GEN_RSP */ { (zclParseInProfileCmd_t)NULL, (zclProcessInProfileCmd_t)NULL },
/* ZCL_CMD_DISCOVER_ATTRS_EXT */ { (zclParseInProfileCmd_t)NULL, (zclProcessInProfileCmd_t)NULL },
/* ZCL_CMD_DISCOVER_ATTRS_EXT_RSP */ { (zclParseInProfileCmd_t)NULL, (zclProcessInProfileCmd_t)NULL },
#endif // ZCL_DISCOVER
};
/*********************************************************************
* PUBLIC FUNCTIONS
*********************************************************************/
#if !defined ( ZCL_STANDALONE )
/*********************************************************************
* @fn zcl_Init
*
* @brief Initialization function for the zcl layer.
*
* @param task_id - ZCL task id
*
* @return none
*/
void zcl_Init( uint8 task_id ) {
zcl_TaskID = task_id;
}
#endif
#if !defined ( ZCL_STANDALONE )
/*********************************************************************
* @fn zcl_event_loop
*
* @brief Event Loop Processor for zcl.
*
* @param task_id - task id
* @param events - event bitmap
*
* @return unprocessed events
*/
uint16 zcl_event_loop( uint8 task_id, uint16 events ) {
uint8 *msgPtr;
(void)task_id; // Intentionally unreferenced parameter
if ( events & SYS_EVENT_MSG ) {
msgPtr = osal_msg_receive( zcl_TaskID );
while ( msgPtr != NULL ) {
uint8 dealloc = TRUE;
if ( *msgPtr == AF_INCOMING_MSG_CMD ) {
zcl_ProcessMessageMSG( (afIncomingMSGPacket_t *)msgPtr );
} else {
uint8 taskID;
taskID = zcl_getExternalFoundationHandler( (afIncomingMSGPacket_t *)msgPtr );
if ( taskID != TASK_NO_TASK ) {
// send it to another task to process.
osal_msg_send( taskID, msgPtr );
dealloc = FALSE;
}
}
// Release the memory
if ( dealloc ) {
osal_msg_deallocate( msgPtr );
}
// Next
msgPtr = osal_msg_receive( zcl_TaskID );
}
// return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
#if !defined (DISABLE_GREENPOWER_BASIC_PROXY) && (ZG_BUILD_RTR_TYPE)
if ( events & ZCL_DATABUF_SEND ) {
gpNotificationMsg_t *gpNotification = NULL;
gpCmdPayloadMsg_t *pCmdPayloadMsgCurr = NULL;
gpd_ID_t gpd_ID;
uint8 *pgpdid;
uint8 entry[PROXY_TBL_ENTRY_LEN];
uint8 appId;
uint8 nwkSeqNum;
uint8 apsSecNum;
uint16 nwkAddr;
gpNotification = gp_GetHeadNotificationMsg( );
if ( gpNotification == NULL ) {
return 0;
}
pCmdPayloadMsgCurr = ( gpCmdPayloadMsg_t* ) gpNotification->pMsg ;
appId = PROXY_TBL_GET_APPLICTION_ID((uint16)*pCmdPayloadMsgCurr->pMsg);
// To save the NIB nwk sequense number and use the GP alias nwk sequence number
// for the GP notification
nwkSeqNum = _NIB.SequenceNum;
_NIB.SequenceNum = pCmdPayloadMsgCurr->secNum;
// To save the NIB nwk address and use the GP alias nwk address for the GP notification
nwkAddr = _NIB.nwkDevAddress;
if( appId == GP_OPT_APP_ID_GPD ) {
pgpdid = pCmdPayloadMsgCurr->pMsg + sizeof( uint16 );
osal_memcpy( &_NIB.nwkDevAddress, pgpdid, sizeof(uint16) );
gpd_ID.AppID = GP_OPT_APP_ID_GPD;
osal_memcpy( &gpd_ID.GPDId.SrcID, pgpdid, sizeof( uint32 ) );
} else if( appId == GP_OPT_APP_ID_IEEE ) {
pgpdid = pCmdPayloadMsgCurr->pMsg + Z_EXTADDR_LEN;
osal_revmemcpy( &_NIB.nwkDevAddress,(pCmdPayloadMsgCurr->pMsg + Z_EXTADDR_LEN), sizeof(uint16) );
gpd_ID.AppID = GP_OPT_APP_ID_IEEE;
pgpdid = pCmdPayloadMsgCurr->pMsg + sizeof( uint16 );
osal_memcpy( gpd_ID.GPDId.GPDExtAddr, pgpdid, Z_EXTADDR_LEN );
}
gp_getProxyTableByGpId(&gpd_ID, entry, NULL);
if ( PROXY_TBL_GET_ASSIGNED_ALIAS( entry[PROXY_TBL_ENTRY_OPT + 1] ) ) {
_NIB.nwkDevAddress = 0;
osal_memcpy( (uint8*)&_NIB.nwkDevAddress, &entry[PROXY_TBL_ENTRY_ALIAS], sizeof(uint16));
}
// save aps sequence number
apsSecNum = APS_Counter;
APS_Counter = pCmdPayloadMsgCurr->secNum;
// Set nwk radius for zcl frame
if ( entry[PROXY_TBL_ENTRY_GRP_RAD] != 0xFF) {
zcl_radius = entry[PROXY_TBL_ENTRY_GRP_RAD];
}
zcl_SendCommand( GREEN_POWER_INTERNAL_ENDPOINT, &gpNotification->addr, ZCL_CLUSTER_ID_GREEN_POWER,
COMMAND_GP_NOTIFICATION, TRUE, ZCL_FRAME_CLIENT_SERVER_DIR,
TRUE, 0, bdb_getZCLFrameCounter(), pCmdPayloadMsgCurr->lenght, pCmdPayloadMsgCurr->pMsg );
// restore nwk radius
zcl_radius = AF_DEFAULT_RADIUS;
// restore aps sequence number
APS_Counter = apsSecNum;
// Restore the NIB nwk sequence number
_NIB.SequenceNum = nwkSeqNum;
// Restore the NIB nwk address
_NIB.nwkDevAddress = nwkAddr;
gp_NotificationMsgClean( gp_GetPHeadNotification ( ) );
if ( gp_GetHeadNotificationMsg ( ) != NULL ) {
osal_start_timerEx( zcl_TaskID, ZCL_DATABUF_SEND, 50 );
}
}
#endif
// Discard unknown events
return 0;
}
#endif
#if !defined ( ZCL_STANDALONE )
/*********************************************************************
* @fn zcl_registerForMsg
*
* @brief The ZCL is setup to send all incoming Foundation Command/Response
* messages that aren't processed to one task (if a task is
* registered).
*
* @param taskId - task Id of the Application where commands will be sent to
*
* @return TRUE if task registeration successful, FALSE otherwise
*********************************************************************/
uint8 zcl_registerForMsg( uint8 taskId ) {
return zcl_addExternalFoundationHandler( taskId, AF_BROADCAST_ENDPOINT );
}
/*********************************************************************
* @fn zcl_registerForMsgExt
*
* @brief This function enables a Task to register to recieve all
* incoming Foundation Command/Response messages, for a particular
* End Point, that aren't processed by ZCL.
*
* NOTE: Any Task registered for a unique end point will take
* priority over any Task registered with the AF_BROADCAST_ENDPOINT
* value. ie. If task A registers for End Point 1, task B registers
* for AF_BROADCAST_ENDPOINT, commands addressed to End Point 1 will be
* sent to Task A and NOT Task B.
*
* @param taskId - task Id of the Application where commands will be sent to
* @param endPointId - end point Id of interest
*
* @return TRUE if task registeration successful, FALSE otherwise
*********************************************************************/
uint8 zcl_registerForMsgExt( uint8 taskId, uint8 endPointId ) {
return ( zcl_addExternalFoundationHandler( taskId, endPointId ) );
}
/*********************************************************************
* @fn zcl_addExternalFoundationHandler
*
* @brief This function adds a record to the internal list of external
* handlers of unhandled incoming Foundation Command/Response messages.
*
* @param taskId - task Id of the Application where commands will be sent to
* @param endPointId - end point Id of interest
*
* @return TRUE if task registeration successful, FALSE otherwise
*********************************************************************/
uint8 zcl_addExternalFoundationHandler( uint8 taskId, uint8 endPointId ) {
zclExternalFoundationHandlerList *pNewItem;
zclExternalFoundationHandlerList *pLoop;
zclExternalFoundationHandlerList *pLoopPrev;
// Fill in the new endpoint registrant list
pNewItem = zcl_mem_alloc( sizeof( zclExternalFoundationHandlerList ) );
if ( pNewItem == NULL ) {
return ( false );
}
pNewItem->zcl_ExternalEndPoint = endPointId;
pNewItem->zcl_ExternalTaskID = taskId;
pNewItem->next = NULL;
// Add to the list
if ( externalEndPointHandlerList == NULL ) {
externalEndPointHandlerList = pNewItem;
} else {
// make sure no one else tried to register for this endpoint
pLoop = externalEndPointHandlerList;
pLoopPrev = externalEndPointHandlerList;
while ( pLoop != NULL ) {
if ( ( pLoop->zcl_ExternalEndPoint ) == endPointId ) {
zcl_mem_free(pNewItem);
return ( false );
}
pLoopPrev = pLoop;
pLoop = pLoop->next;
}
if ( endPointId == AF_BROADCAST_ENDPOINT ) {
// put new registration at the end of the list
pLoopPrev->next = pNewItem;
pNewItem->next = NULL;
} else {
// put new registration at the front of the list
zclExternalFoundationHandlerList *temp = externalEndPointHandlerList;
externalEndPointHandlerList = pNewItem;
pNewItem->next = temp;
}
}
return ( true );
}
/*********************************************************************
* @fn zcl_getExternalFoundationHandler
*
* @brief This function retrieves the Task ID of the task registered
* to received unhandled incoming Foundation Command/Response messages
* for a particular End Point ID.
*
* @param pInMsg - recevied ZCL command
*
* @return TASK ID of registered task. If no task is reigistered, it returns
* TASK_NO_TASK.
*********************************************************************/
static uint8 zcl_getExternalFoundationHandler( afIncomingMSGPacket_t *pInMsg ) {
zclExternalFoundationHandlerList *pLoop;
uint8 addressedEndPointId = pInMsg->endPoint;
// make sure no one else tried to register for this endpoint
pLoop = externalEndPointHandlerList;
while ( pLoop != NULL ) {
if ( ( ( pLoop->zcl_ExternalEndPoint ) == addressedEndPointId ) ||
( ( pLoop->zcl_ExternalEndPoint ) == AF_BROADCAST_ENDPOINT ) ) {
return ( pLoop->zcl_ExternalTaskID );
}
pLoop = pLoop->next;
}
return ( TASK_NO_TASK );
}
#endif
#if !defined ( ZCL_STANDALONE )
/*********************************************************************
* @fn zcl_HandleExternal
*
* @brief
*
* @param pInMsg - incoming message to process
*
* @return TRUE
*/
uint8 zcl_HandleExternal( zclIncoming_t *pInMsg ) {
zclIncomingMsg_t *pCmd;
uint8 taskID;
taskID = zcl_getExternalFoundationHandler( pInMsg->msg );
if ( taskID == TASK_NO_TASK ) {
return ( TRUE );
}
pCmd = (zclIncomingMsg_t *)osal_msg_allocate( sizeof ( zclIncomingMsg_t ) );
if ( pCmd != NULL ) {
// fill in the message
pCmd->hdr.event = ZCL_INCOMING_MSG;
pCmd->zclHdr = pInMsg->hdr;
pCmd->clusterId = pInMsg->msg->clusterId;
pCmd->srcAddr = pInMsg->msg->srcAddr;
pCmd->endPoint = pInMsg->msg->endPoint;
pCmd->attrCmd = pInMsg->attrCmd;
#ifdef BDB_REPORTING
if(pCmd->zclHdr.commandID == ZCL_CMD_CONFIG_REPORT) {
bdb_ProcessInConfigReportCmd(pCmd);
osal_msg_deallocate((uint8*)pCmd);
return TRUE;
}
if(pCmd->zclHdr.commandID == ZCL_CMD_READ_REPORT_CFG) {
bdb_ProcessInReadReportCfgCmd(pCmd);
osal_msg_deallocate((uint8*)pCmd);
return TRUE;
}
#endif
// Application will free the attrCmd buffer
pInMsg->attrCmd = NULL;
/* send message through task message */
osal_msg_send( taskID, (uint8 *)pCmd );
}
return ( TRUE );
}
#endif
/*********************************************************************
* @fn zcl_getRawAFMsg
*
* @brief Call to get original unprocessed AF message
* (not parsed by ZCL).
*
* NOTE: This function can only be called during a ZCL callback function
* and the calling function must NOT change any data in the message.
*
* @param none
*
* @return pointer to original AF message, NULL if not processing
* AF message.
*/
afIncomingMSGPacket_t *zcl_getRawAFMsg( void ) {
return ( rawAFMsg );
}
/*********************************************************************
* @fn zcl_getParsedTransSeqNum
*
* @brief Call to the get the transaction sequence number from
* the incoming message.
*
* NOTE: This function can only be called during a ZCL callback function
* and the calling function must NOT change any data in the message.
*
* @param none
*
* @return transaction sequence number.
*/
uint8 zcl_getParsedTransSeqNum( void ) {
return ( savedZCLTransSeqNum );
}
/*********************************************************************
* @fn zcl_registerPlugin
*
* @brief Add a Cluster Library handler
*
* @param startClusterID - starting cluster ID
* @param endClusterID - ending cluster ID
* @param pfnHdlr - function pointer to incoming message handler
*
* @return ZSuccess if OK
*/
ZStatus_t zcl_registerPlugin( uint16 startClusterID,
uint16 endClusterID, zclInHdlr_t pfnIncomingHdlr ) {
zclLibPlugin_t *pNewItem;
zclLibPlugin_t *pLoop;
// Fill in the new profile list
pNewItem = zcl_mem_alloc( sizeof( zclLibPlugin_t ) );
if ( pNewItem == NULL ) {
return (ZMemError);
}
// Fill in the plugin record.
pNewItem->next = (zclLibPlugin_t *)NULL;
pNewItem->startClusterID = startClusterID;
pNewItem->endClusterID = endClusterID;
pNewItem->pfnIncomingHdlr = pfnIncomingHdlr;
// Find spot in list
if ( plugins == NULL ) {
plugins = pNewItem;
} else {
// Look for end of list
pLoop = plugins;
while ( pLoop->next != NULL ) {
pLoop = pLoop->next;
}
// Put new item at end of list
pLoop->next = pNewItem;
}
return ( ZSuccess );
}
#ifdef ZCL_DISCOVER
/*********************************************************************
* @fn zcl_registerCmdList
*
* @brief Register a Command List with ZCL Foundation
*
* @param endpoint - endpoint the attribute list belongs to
* @param newCmdList - array of command records
*
* @return ZSuccess if OK
*/
ZStatus_t zcl_registerCmdList( uint8 endpoint, CONST uint8 cmdListSize, CONST zclCommandRec_t newCmdList[] ) {
zclCmdRecsList_t *pNewItem;
zclCmdRecsList_t *pLoop;
// Fill in the new profile list
pNewItem = zcl_mem_alloc( sizeof( zclCmdRecsList_t ) );
if ( pNewItem == NULL ) {
return (ZMemError);
}
pNewItem->pNext = (zclCmdRecsList_t *)NULL;
pNewItem->endpoint = endpoint;
pNewItem->numCommands = cmdListSize;
pNewItem->pCmdRecs = newCmdList;
// Find spot in list
if ( gpCmdList == NULL ) {
gpCmdList = pNewItem;
} else {
// Look for end of list
pLoop = gpCmdList;
while ( pLoop->pNext != NULL ) {
pLoop = pLoop->pNext;
}
// Put new item at end of list
pLoop->pNext = pNewItem;
}
return ( ZSuccess );
}
#endif // ZCL_DISCOVER
/*********************************************************************
* @fn zcl_registerAttrList
*
* @brief Register an Attribute List with ZCL Foundation
*
* @param endpoint - endpoint the attribute list belongs to
* @param numAttr - number of attributes in list
* @param newAttrList - array of Attribute records.
* NOTE: THE ATTRIBUTE IDs (FOR A CLUSTER) MUST BE IN
* ASCENDING ORDER. OTHERWISE, THE DISCOVERY RESPONSE
* COMMAND WILL NOT HAVE THE RIGHT ATTRIBUTE INFO
*
* @return ZSuccess if OK
*/
ZStatus_t zcl_registerAttrList( uint8 endpoint, uint8 numAttr, CONST zclAttrRec_t newAttrList[] ) {
zclAttrRecsList *pNewItem;
zclAttrRecsList *pLoop;
// Fill in the new profile list
pNewItem = zcl_mem_alloc( sizeof( zclAttrRecsList ) );
if ( pNewItem == NULL ) {
return (ZMemError);
}
pNewItem->next = (zclAttrRecsList *)NULL;
pNewItem->endpoint = endpoint;
pNewItem->pfnReadWriteCB = NULL;
pNewItem->numAttributes = numAttr;
pNewItem->attrs = newAttrList;
// Find spot in list
if ( attrList == NULL ) {
attrList = pNewItem;
} else {
// Look for end of list
pLoop = attrList;
while ( pLoop->next != NULL ) {
pLoop = pLoop->next;
}
// Put new item at end of list
pLoop->next = pNewItem;
}
return ( ZSuccess );
}
/*********************************************************************
* @fn zcl_registerClusterOptionList
*
* @brief Register a Cluster Option List with ZCL Foundation
*
* @param endpoint - endpoint the option list belongs to
* @param numOption - number of options in list
* @param optionList - array of cluster option records.
*
* NOTE: This API should be called to enable 'Application
* Link Key' security and/or 'APS ACK' for a specific
* Cluster. The 'Application Link Key' is discarded
* if security isn't enabled on the device.
* The default behavior is 'Network Key' when security
* is enabled and no 'APS ACK' for the ZCL messages.
*
* @return ZSuccess if OK
*/
ZStatus_t zcl_registerClusterOptionList( uint8 endpoint, uint8 numOption, zclOptionRec_t optionList[] ) {
zclClusterOptionList *pNewItem;
zclClusterOptionList *pLoop;
// Fill in the new profile list
pNewItem = zcl_mem_alloc( sizeof( zclClusterOptionList ) );
if ( pNewItem == NULL ) {
return (ZMemError);
}
pNewItem->next = (zclClusterOptionList *)NULL;
pNewItem->endpoint = endpoint;
pNewItem->numOptions = numOption;
pNewItem->options = optionList;
// Find spot in list
if ( clusterOptionList == NULL ) {
clusterOptionList = pNewItem;
} else {
// Look for end of list
pLoop = clusterOptionList;
while ( pLoop->next != NULL ) {
pLoop = pLoop->next;
}
// Put new item at end of list
pLoop->next = pNewItem;
}
return ( ZSuccess );
}
/*********************************************************************
* @fn zcl_registerValidateAttrData
*
* @brief Add a validation function for attribute data
*
* @param pfnValidateAttrData - function pointer to validate routine
*
* @return ZSuccess if OK
*/
ZStatus_t zcl_registerValidateAttrData( zclValidateAttrData_t pfnValidateAttrData ) {
zcl_ValidateAttrDataCB = pfnValidateAttrData;
return ( ZSuccess );
}
/*********************************************************************
* @fn zcl_registerReadWriteCB
*
* @brief Register the application's callback function to read/write
* attribute data, and authorize read/write operation.
*
* Note: The pfnReadWriteCB callback function is only required
* when the attribute data format is unknown to ZCL. The
* callback function gets called when the pointer 'dataPtr'
* to the attribute value is NULL in the attribute database
* registered with the ZCL.
*
* Note: The pfnAuthorizeCB callback function is only required
* when the Read/Write operation on an attribute requires
* authorization (i.e., attributes with ACCESS_CONTROL_AUTH_READ
* or ACCESS_CONTROL_AUTH_WRITE access permissions).
*
* @param endpoint - application's endpoint
* @param pfnReadWriteCB - function pointer to read/write routine
* @param pfnAuthorizeCB - function pointer to authorize read/write operation
*
* @return ZSuccess if successful. ZFailure, otherwise.
*/
ZStatus_t zcl_registerReadWriteCB( uint8 endpoint, zclReadWriteCB_t pfnReadWriteCB,
zclAuthorizeCB_t pfnAuthorizeCB ) {
zclAttrRecsList *pRec = zclFindAttrRecsList( endpoint );
if ( pRec != NULL ) {
pRec->pfnReadWriteCB = pfnReadWriteCB;
pRec->pfnAuthorizeCB = pfnAuthorizeCB;
return ( ZSuccess );
}
return ( ZFailure );
}
/*********************************************************************
* @fn zcl_DeviceOperational
*
* @brief Used to see whether or not the device can send or respond
* to application level commands.
*
* @param srcEP - source endpoint
* @param clusterID - cluster ID
* @param frameType - command type
* @param cmd - command ID
*
* @return TRUE if device is operational, FALSE otherwise
*/
static uint8 zcl_DeviceOperational( uint8 srcEP, uint16 clusterID,
uint8 frameType, uint8 cmd, uint16 profileID ) {
zclAttrRec_t attrRec;
uint8 deviceEnabled = DEVICE_ENABLED; // default value
(void)profileID; // Intentionally unreferenced parameter
// If the device is Disabled (DeviceEnabled attribute is set to Disabled), it
// cannot send or respond to application level commands, other than commands
// to read or write attributes. Note that the Identify cluster cannot be
// disabled, and remains functional regardless of this setting.
if ( zcl_ProfileCmd( frameType ) && cmd <= ZCL_CMD_WRITE_NO_RSP ) {
return ( TRUE );
}
if ( clusterID == ZCL_CLUSTER_ID_GEN_IDENTIFY ) {
return ( TRUE );
}
// Is device enabled?
if ( zclFindAttrRec( srcEP, ZCL_CLUSTER_ID_GEN_BASIC,
ATTRID_BASIC_DEVICE_ENABLED, &attrRec ) ) {
#ifdef ZCL_READ
zclReadAttrData( &deviceEnabled, &attrRec, NULL );
#endif
}
return ( deviceEnabled == DEVICE_ENABLED ? TRUE : FALSE );
}
/*********************************************************************
* @fn zcl_SendCommand
*
* @brief Used to send Profile and Cluster Specific Command messages.
*
* NOTE: The calling application is responsible for incrementing
* the Sequence Number.
*
* @param srcEp - source endpoint
* @param destAddr - destination address
* @param clusterID - cluster ID
* @param cmd - command ID
* @param specific - whether the command is Cluster Specific
* @param direction - client/server direction of the command
* @param disableDefaultRsp - disable Default Response command
* @param manuCode - manufacturer code for proprietary extensions to a profile
* @param seqNumber - identification number for the transaction
* @param cmdFormatLen - length of the command to be sent
* @param cmdFormat - command to be sent
*
* @return ZSuccess if OK
*/
ZStatus_t zcl_SendCommand( uint8 srcEP, afAddrType_t *destAddr,
uint16 clusterID, uint8 cmd, uint8 specific, uint8 direction,
uint8 disableDefaultRsp, uint16 manuCode, uint8 seqNum,
uint16 cmdFormatLen, uint8 *cmdFormat ) {
endPointDesc_t *epDesc;
zclFrameHdr_t hdr;
uint8 *msgBuf;
uint16 msgLen;
uint8 *pBuf;
uint8 options;
ZStatus_t status;
epDesc = afFindEndPointDesc( srcEP );
if ( epDesc == NULL ) {
return ( ZInvalidParameter ); // EMBEDDED RETURN
}
#if defined ( INTER_PAN )
if ( StubAPS_InterPan( destAddr->panId, destAddr->endPoint ) ) {
options = AF_TX_OPTIONS_NONE;
} else
#endif
{
options = zclGetClusterOption( srcEP, clusterID );
// The cluster might not have been defined to use security but if this message
// is in response to another message that was using APS security this message
// will be sent with APS security
if ( !( options & AF_EN_SECURITY ) ) {
afIncomingMSGPacket_t *origPkt = zcl_getRawAFMsg();
if ( ( origPkt != NULL ) && ( origPkt->SecurityUse == TRUE ) ) {
options |= AF_EN_SECURITY;
}
}
}
zcl_memset( &hdr, 0, sizeof( zclFrameHdr_t ) );
// Not Profile wide command (like READ, WRITE)
if ( specific ) {
hdr.fc.type = ZCL_FRAME_TYPE_SPECIFIC_CMD;
} else {
hdr.fc.type = ZCL_FRAME_TYPE_PROFILE_CMD;
}
if ( ( epDesc->simpleDesc == NULL ) ||
( zcl_DeviceOperational( srcEP, clusterID, hdr.fc.type,
cmd, epDesc->simpleDesc->AppProfId ) == FALSE ) ) {
return ( ZFailure ); // EMBEDDED RETURN
}
// Fill in the Maufacturer Code
if ( manuCode != 0 ) {
hdr.fc.manuSpecific = 1;
hdr.manuCode = manuCode;
}
// Set the Command Direction
if ( direction ) {
hdr.fc.direction = ZCL_FRAME_SERVER_CLIENT_DIR;
} else {
hdr.fc.direction = ZCL_FRAME_CLIENT_SERVER_DIR;
}
// Set the Disable Default Response field
if ( disableDefaultRsp ) {
hdr.fc.disableDefaultRsp = 1;
} else {
hdr.fc.disableDefaultRsp = 0;
}
// Fill in the Transaction Sequence Number
hdr.transSeqNum = seqNum;
// Fill in the command
hdr.commandID = cmd;
// calculate the needed buffer size
msgLen = zclCalcHdrSize( &hdr );
msgLen += cmdFormatLen;
// Allocate the buffer needed
msgBuf = zcl_mem_alloc( msgLen );
if ( msgBuf != NULL ) {
// Fill in the ZCL Header
pBuf = zclBuildHdr( &hdr, msgBuf );
// Fill in the command frame
zcl_memcpy( pBuf, cmdFormat, cmdFormatLen );
status = AF_DataRequest( destAddr, epDesc, clusterID, msgLen, msgBuf,
&APS_Counter, options, zcl_radius );
zcl_mem_free ( msgBuf );
} else {
status = ZMemError;
}
return ( status );
}
#ifdef ZCL_READ
/*********************************************************************
* @fn zcl_SendRead
*
* @brief Send a Read command
*
* @param srcEP - Application's endpoint
* @param dstAddr - destination address
* @param clusterID - cluster ID
* @param readCmd - read command to be sent
* @param direction - direction of the command
* @param seqNum - transaction sequence number
*
* @return ZSuccess if OK
*/
ZStatus_t zcl_SendRead( uint8 srcEP, afAddrType_t *dstAddr,
uint16 clusterID, zclReadCmd_t *readCmd,
uint8 direction, uint8 disableDefaultRsp, uint8 seqNum) {
uint16 dataLen;
uint8 *buf;
uint8 *pBuf;
ZStatus_t status;
dataLen = readCmd->numAttr * 2; // Attribute ID
buf = zcl_mem_alloc( dataLen );
if ( buf != NULL ) {
uint8 i;
// Load the buffer - serially
pBuf = buf;
for (i = 0; i < readCmd->numAttr; i++) {
*pBuf++ = LO_UINT16( readCmd->attrID[i] );
*pBuf++ = HI_UINT16( readCmd->attrID[i] );
}
status = zcl_SendCommand( srcEP, dstAddr, clusterID, ZCL_CMD_READ, FALSE,
direction, disableDefaultRsp, 0, seqNum, dataLen, buf );
zcl_mem_free( buf );
} else {
status = ZMemError;
}
return ( status );
}
/*********************************************************************
* @fn zcl_SendReadRsp
*
* @brief Send a Read Response command.
*
* @param srcEP - Application's endpoint
* @param dstAddr - destination address
* @param clusterID - cluster ID
* @param readRspCmd - read response command to be sent
* @param direction - direction of the command
* @param seqNum - transaction sequence number
*
* @return ZSuccess if OK
*/
ZStatus_t zcl_SendReadRsp( uint8 srcEP, afAddrType_t *dstAddr,
uint16 clusterID, zclReadRspCmd_t *readRspCmd,
uint8 direction, uint8 disableDefaultRsp, uint8 seqNum ) {
uint8 *buf;
uint16 len = 0;
ZStatus_t status;
uint8 i;
// calculate the size of the command
for ( i = 0; i < readRspCmd->numAttr; i++ ) {
zclReadRspStatus_t *statusRec = &(readRspCmd->attrList[i]);
len += 2 + 1; // Attribute ID + Status
if ( statusRec->status == ZCL_STATUS_SUCCESS ) {
len++; // Attribute Data Type length
// Attribute Data length
if ( statusRec->data != NULL ) {
len += zclGetAttrDataLength( statusRec->dataType, statusRec->data );
} else {
len += zclGetAttrDataLengthUsingCB( srcEP, clusterID, statusRec->attrID );
}
}
}
buf = zcl_mem_alloc( len );
if ( buf != NULL ) {
// Load the buffer - serially
uint8 *pBuf = buf;
for ( i = 0; i < readRspCmd->numAttr; i++ ) {
zclReadRspStatus_t *statusRec = &(readRspCmd->attrList[i]);
*pBuf++ = LO_UINT16( statusRec->attrID );
*pBuf++ = HI_UINT16( statusRec->attrID );
*pBuf++ = statusRec->status;
if ( statusRec->status == ZCL_STATUS_SUCCESS ) {
*pBuf++ = statusRec->dataType;
if ( statusRec->data != NULL ) {
// Copy attribute data to the buffer to be sent out
pBuf = zclSerializeData( statusRec->dataType, statusRec->data, pBuf );
} else {
uint16 dataLen;
// Read attribute data directly into the buffer to be sent out
zclReadAttrDataUsingCB( srcEP, clusterID, statusRec->attrID, pBuf, &dataLen );
pBuf += dataLen;
}
}
} // for loop
status = zcl_SendCommand( srcEP, dstAddr, clusterID, ZCL_CMD_READ_RSP, FALSE,
direction, disableDefaultRsp, 0, seqNum, len, buf );
zcl_mem_free( buf );
} else {
status = ZMemError;
}
return ( status );
}
#endif // ZCL_READ
#ifdef ZCL_WRITE
/*********************************************************************
* @fn sendWriteRequest
*
* @brief Send a Write command
*
* @param dstAddr - destination address
* @param clusterID - cluster ID
* @param writeCmd - write command to be sent
* @param cmd - ZCL_CMD_WRITE, ZCL_CMD_WRITE_UNDIVIDED or ZCL_CMD_WRITE_NO_RSP
* @param direction - direction of the command
* @param seqNum - transaction sequence number
*
* @return ZSuccess if OK
*/
ZStatus_t zcl_SendWriteRequest( uint8 srcEP, afAddrType_t *dstAddr, uint16 clusterID,
zclWriteCmd_t *writeCmd, uint8 cmd, uint8 direction,
uint8 disableDefaultRsp, uint8 seqNum ) {
uint8 *buf;
uint16 dataLen = 0;
ZStatus_t status;
uint8 i;
for ( i = 0; i < writeCmd->numAttr; i++ ) {
zclWriteRec_t *statusRec = &(writeCmd->attrList[i]);
dataLen += 2 + 1; // Attribute ID + Attribute Type
// Attribute Data
dataLen += zclGetAttrDataLength( statusRec->dataType, statusRec->attrData );
}
buf = zcl_mem_alloc( dataLen );
if ( buf != NULL ) {
// Load the buffer - serially
uint8 *pBuf = buf;
for ( i = 0; i < writeCmd->numAttr; i++ ) {
zclWriteRec_t *statusRec = &(writeCmd->attrList[i]);
*pBuf++ = LO_UINT16( statusRec->attrID );
*pBuf++ = HI_UINT16( statusRec->attrID );
*pBuf++ = statusRec->dataType;
pBuf = zclSerializeData( statusRec->dataType, statusRec->attrData, pBuf );
}
status = zcl_SendCommand( srcEP, dstAddr, clusterID, cmd, FALSE,
direction, disableDefaultRsp, 0, seqNum, dataLen, buf );
zcl_mem_free( buf );
} else {
status = ZMemError;
}
return ( status);
}
/*********************************************************************
* @fn zcl_SendWriteRsp
*
* @brief Send a Write Response command
*
* @param dstAddr - destination address
* @param clusterID - cluster ID
* @param wrtieRspCmd - write response command to be sent
* @param direction - direction of the command
* @param seqNum - transaction sequence number
*
* @return ZSuccess if OK
*/
ZStatus_t zcl_SendWriteRsp( uint8 srcEP, afAddrType_t *dstAddr,
uint16 clusterID, zclWriteRspCmd_t *writeRspCmd,
uint8 direction, uint8 disableDefaultRsp, uint8 seqNum ) {
uint16 dataLen;
uint8 *buf;
ZStatus_t status;
dataLen = writeRspCmd->numAttr * ( 1 + 2 ); // status + attribute id
buf = zcl_mem_alloc( dataLen );
if ( buf != NULL ) {
// Load the buffer - serially
uint8 i;
uint8 *pBuf = buf;
for ( i = 0; i < writeRspCmd->numAttr; i++ ) {
*pBuf++ = writeRspCmd->attrList[i].status;
*pBuf++ = LO_UINT16( writeRspCmd->attrList[i].attrID );
*pBuf++ = HI_UINT16( writeRspCmd->attrList[i].attrID );
}
// If there's only a single status record and its status field is set to
// SUCCESS then omit the attribute ID field.
if ( writeRspCmd->numAttr == 1 && writeRspCmd->attrList[0].status == ZCL_STATUS_SUCCESS ) {
dataLen = 1;
}
status = zcl_SendCommand( srcEP, dstAddr, clusterID, ZCL_CMD_WRITE_RSP, FALSE,
direction, disableDefaultRsp, 0, seqNum, dataLen, buf );
zcl_mem_free( buf );
} else {
status = ZMemError;
}
return ( status );
}
#endif // ZCL_WRITE
#ifdef ZCL_REPORT_CONFIGURING_DEVICE
/*********************************************************************
* @fn zcl_SendConfigReportCmd
*
* @brief Send a Configure Reporting command
*
* @param dstAddr - destination address
* @param clusterID - cluster ID
* @param cfgReportCmd - configure reporting command to be sent
* @param direction - direction of the command
* @param seqNum - transaction sequence number
*
* @return ZSuccess if OK
*/
ZStatus_t zcl_SendConfigReportCmd( uint8 srcEP, afAddrType_t *dstAddr,
uint16 clusterID, zclCfgReportCmd_t *cfgReportCmd,
uint8 direction, uint8 disableDefaultRsp, uint8 seqNum ) {
uint8 *buf;
uint16 dataLen = 0;
ZStatus_t status;
uint8 i;
// Find out the data length
for ( i = 0; i < cfgReportCmd->numAttr; i++ ) {
zclCfgReportRec_t *reportRec = &(cfgReportCmd->attrList[i]);
dataLen += 1 + 2; // Direction + Attribute ID
if ( reportRec->direction == ZCL_SEND_ATTR_REPORTS ) {
dataLen += 1 + 2 + 2; // Data Type + Min + Max Reporting Intervals
// Find out the size of the Reportable Change field (for Analog data types)
if ( zclAnalogDataType( reportRec->dataType ) ) {
dataLen += zclGetDataTypeLength( reportRec->dataType );
}
} else {
dataLen += 2; // Timeout Period
}
}
buf = zcl_mem_alloc( dataLen );
if ( buf != NULL ) {
// Load the buffer - serially
uint8 *pBuf = buf;
for ( i = 0; i < cfgReportCmd->numAttr; i++ ) {
zclCfgReportRec_t *reportRec = &(cfgReportCmd->attrList[i]);
*pBuf++ = reportRec->direction;
*pBuf++ = LO_UINT16( reportRec->attrID );
*pBuf++ = HI_UINT16( reportRec->attrID );
if ( reportRec->direction == ZCL_SEND_ATTR_REPORTS ) {
*pBuf++ = reportRec->dataType;
*pBuf++ = LO_UINT16( reportRec->minReportInt );
*pBuf++ = HI_UINT16( reportRec->minReportInt );
*pBuf++ = LO_UINT16( reportRec->maxReportInt );
*pBuf++ = HI_UINT16( reportRec->maxReportInt );
if ( zclAnalogDataType( reportRec->dataType ) ) {
pBuf = zclSerializeData( reportRec->dataType, reportRec->reportableChange, pBuf );
}
} else {
*pBuf++ = LO_UINT16( reportRec->timeoutPeriod );
*pBuf++ = HI_UINT16( reportRec->timeoutPeriod );
}
} // for loop
status = zcl_SendCommand( srcEP, dstAddr, clusterID, ZCL_CMD_CONFIG_REPORT, FALSE,
direction, disableDefaultRsp, 0, seqNum, dataLen, buf );
zcl_mem_free( buf );
} else {
status = ZMemError;
}
return ( status );
}
#endif
#ifdef ZCL_REPORTING_DEVICE
/*********************************************************************
* @fn zcl_SendConfigReportRspCmd
*
* @brief Send a Configure Reporting Response command
*
* @param dstAddr - destination address
* @param clusterID - cluster ID
* @param cfgReportRspCmd - configure reporting response command to be sent
* @param direction - direction of the command
* @param seqNum - transaction sequence number
*
* @return ZSuccess if OK
*/
ZStatus_t zcl_SendConfigReportRspCmd( uint8 srcEP, afAddrType_t *dstAddr,
uint16 clusterID, zclCfgReportRspCmd_t *cfgReportRspCmd,
uint8 direction, uint8 disableDefaultRsp, uint8 seqNum ) {
uint16 dataLen;
uint8 *buf;
ZStatus_t status;
// Atrribute list (Status, Direction and Attribute ID)
dataLen = cfgReportRspCmd->numAttr * ( 1 + 1 + 2 );
buf = zcl_mem_alloc( dataLen );
if ( buf != NULL ) {
// Load the buffer - serially
uint8 *pBuf = buf;
uint8 i;
for ( i = 0; i < cfgReportRspCmd->numAttr; i++ ) {
*pBuf++ = cfgReportRspCmd->attrList[i].status;
*pBuf++ = cfgReportRspCmd->attrList[i].direction;
*pBuf++ = LO_UINT16( cfgReportRspCmd->attrList[i].attrID );
*pBuf++ = HI_UINT16( cfgReportRspCmd->attrList[i].attrID );
}
// If there's only a single status record and its status field is set to
// SUCCESS then omit the attribute ID field.
if ( cfgReportRspCmd->numAttr == 1 && cfgReportRspCmd->attrList[0].status == ZCL_STATUS_SUCCESS ) {
dataLen = 1;
}
status = zcl_SendCommand( srcEP, dstAddr, clusterID,
ZCL_CMD_CONFIG_REPORT_RSP, FALSE, direction,
disableDefaultRsp, 0, seqNum, dataLen, buf );
zcl_mem_free( buf );
} else {
status = ZMemError;
}
return ( status );
}
#endif
#ifdef ZCL_REPORT_CONFIGURING_DEVICE
/*********************************************************************
* @fn zcl_SendReadReportCfgCmd
*
* @brief Send a Read Reporting Configuration command
*
* @param dstAddr - destination address
* @param clusterID - cluster ID
* @param readReportCfgCmd - read reporting configuration command to be sent
* @param direction - direction of the command
* @param seqNum - transaction sequence number
*
* @return ZSuccess if OK
*/
ZStatus_t zcl_SendReadReportCfgCmd( uint8 srcEP, afAddrType_t *dstAddr,
uint16 clusterID, zclReadReportCfgCmd_t *readReportCfgCmd,
uint8 direction, uint8 disableDefaultRsp, uint8 seqNum ) {
uint16 dataLen;
uint8 *buf;
ZStatus_t status;
dataLen = readReportCfgCmd->numAttr * ( 1 + 2 ); // Direction + Atrribute ID
buf = zcl_mem_alloc( dataLen );
if ( buf != NULL ) {
// Load the buffer - serially
uint8 *pBuf = buf;
uint8 i;
for ( i = 0; i < readReportCfgCmd->numAttr; i++ ) {
*pBuf++ = readReportCfgCmd->attrList[i].direction;
*pBuf++ = LO_UINT16( readReportCfgCmd->attrList[i].attrID );
*pBuf++ = HI_UINT16( readReportCfgCmd->attrList[i].attrID );
}
status = zcl_SendCommand( srcEP, dstAddr, clusterID, ZCL_CMD_READ_REPORT_CFG, FALSE,
direction, disableDefaultRsp, 0, seqNum, dataLen, buf );
zcl_mem_free( buf );
} else {
status = ZMemError;
}
return ( status );
}
#endif
#ifdef ZCL_REPORTING_DEVICE
/*********************************************************************
* @fn zcl_SendReadReportCfgRspCmd
*
* @brief Send a Read Reporting Configuration Response command
*
* @param dstAddr - destination address
* @param clusterID - cluster ID
* @param readReportCfgRspCmd - read reporting configuration response command to be sent
* @param direction - direction of the command
* @param seqNum - transaction sequence number
*
* @return ZSuccess if OK
*/
ZStatus_t zcl_SendReadReportCfgRspCmd( uint8 srcEP, afAddrType_t *dstAddr,
uint16 clusterID, zclReadReportCfgRspCmd_t *readReportCfgRspCmd,
uint8 direction, uint8 disableDefaultRsp, uint8 seqNum ) {
uint8 *buf;
uint16 dataLen = 0;
ZStatus_t status;
uint8 i;
// Find out the data length
for ( i = 0; i < readReportCfgRspCmd->numAttr; i++ ) {
zclReportCfgRspRec_t *reportRspRec = &(readReportCfgRspCmd->attrList[i]);
dataLen += 1 + 1 + 2 ; // Status, Direction and Atrribute ID
if ( reportRspRec->status == ZCL_STATUS_SUCCESS ) {
if ( reportRspRec->direction == ZCL_SEND_ATTR_REPORTS ) {
dataLen += 1 + 2 + 2; // Data Type + Min + Max Reporting Intervals
// Find out the size of the Reportable Change field (for Analog data types)
if ( zclAnalogDataType( reportRspRec->dataType ) ) {
dataLen += zclGetDataTypeLength( reportRspRec->dataType );
}
} else {
dataLen += 2; // Timeout Period
}
}
}
buf = zcl_mem_alloc( dataLen );
if ( buf != NULL ) {
// Load the buffer - serially
uint8 *pBuf = buf;
for ( i = 0; i < readReportCfgRspCmd->numAttr; i++ ) {
zclReportCfgRspRec_t *reportRspRec = &(readReportCfgRspCmd->attrList[i]);
*pBuf++ = reportRspRec->status;
*pBuf++ = reportRspRec->direction;
*pBuf++ = LO_UINT16( reportRspRec->attrID );
*pBuf++ = HI_UINT16( reportRspRec->attrID );
if ( reportRspRec->status == ZCL_STATUS_SUCCESS ) {
if ( reportRspRec->direction == ZCL_SEND_ATTR_REPORTS ) {
*pBuf++ = reportRspRec->dataType;
*pBuf++ = LO_UINT16( reportRspRec->minReportInt );
*pBuf++ = HI_UINT16( reportRspRec->minReportInt );
*pBuf++ = LO_UINT16( reportRspRec->maxReportInt );
*pBuf++ = HI_UINT16( reportRspRec->maxReportInt );
if ( zclAnalogDataType( reportRspRec->dataType ) ) {
pBuf = zclSerializeData( reportRspRec->dataType,
reportRspRec->reportableChange, pBuf );
}
} else {
*pBuf++ = LO_UINT16( reportRspRec->timeoutPeriod );
*pBuf++ = HI_UINT16( reportRspRec->timeoutPeriod );
}
}
}
status = zcl_SendCommand( srcEP, dstAddr, clusterID,
ZCL_CMD_READ_REPORT_CFG_RSP, FALSE,
direction, disableDefaultRsp, 0, seqNum, dataLen, buf );
zcl_mem_free( buf );
} else {
status = ZMemError;
}
return ( status );
}
/*********************************************************************
* @fn zcl_SendReportCmd
*
* @brief Send a Report command
*
* @param dstAddr - destination address
* @param clusterID - cluster ID
* @param reportCmd - report command to be sent
* @param direction - direction of the command
* @param seqNum - transaction sequence number
*
* @return ZSuccess if OK
*/
ZStatus_t zcl_SendReportCmd( uint8 srcEP, afAddrType_t *dstAddr,
uint16 clusterID, zclReportCmd_t *reportCmd,
uint8 direction, uint8 disableDefaultRsp, uint8 seqNum ) {
uint16 dataLen = 0;
uint8 *buf;
ZStatus_t status;
uint8 i;
// calculate the size of the command
for ( i = 0; i < reportCmd->numAttr; i++ ) {
zclReport_t *reportRec = &(reportCmd->attrList[i]);
dataLen += 2 + 1; // Attribute ID + data type
// Attribute Data
dataLen += zclGetAttrDataLength( reportRec->dataType, reportRec->attrData );
}
buf = zcl_mem_alloc( dataLen );
if ( buf != NULL ) {
// Load the buffer - serially
uint8 *pBuf = buf;
for ( i = 0; i < reportCmd->numAttr; i++ ) {
zclReport_t *reportRec = &(reportCmd->attrList[i]);
*pBuf++ = LO_UINT16( reportRec->attrID );
*pBuf++ = HI_UINT16( reportRec->attrID );
*pBuf++ = reportRec->dataType;
pBuf = zclSerializeData( reportRec->dataType, reportRec->attrData, pBuf );
}
status = zcl_SendCommand( srcEP, dstAddr, clusterID, ZCL_CMD_REPORT, FALSE,
direction, disableDefaultRsp, 0, seqNum, dataLen, buf );
zcl_mem_free( buf );
} else {
status = ZMemError;
}
return ( status );
}
#endif
/*********************************************************************
* @fn zcl_SendDefaultRspCmd
*
* @brief Send a Default Response command
*
* Note: The manufacturer code field should be set if this
* command is being sent in response to a manufacturer specific
* command.
*
* @param dstAddr - destination address
* @param clusterID - cluster ID
* @param defaultRspCmd - default response command to be sent
* @param direction - direction of the command
* @param manuCode - manufacturer code for proprietary extensions to a profile
* @param seqNum - transaction sequence number
*
* @return ZSuccess if OK
*/
ZStatus_t zcl_SendDefaultRspCmd( uint8 srcEP, afAddrType_t *dstAddr, uint16 clusterID,
zclDefaultRspCmd_t *defaultRspCmd, uint8 direction,
uint8 disableDefaultRsp, uint16 manuCode, uint8 seqNum ) {
uint8 buf[2]; // Command ID and Status;
// Load the buffer - serially
buf[0] = defaultRspCmd->commandID;
buf[1] = defaultRspCmd->statusCode;
return ( zcl_SendCommand( srcEP, dstAddr, clusterID, ZCL_CMD_DEFAULT_RSP, FALSE,
direction, disableDefaultRsp, manuCode, seqNum, 2, buf ) );
}
#ifdef ZCL_DISCOVER
/*********************************************************************
* @fn zcl_SendDiscoverCmdsCmd
*
* @brief Send a Discover Commands command
*
* @param dstAddr - destination address
* @param clusterID - cluster ID
* @param cmdType - requesting command ID
* @param pDiscoverCmd - discover command to be sent
* @param direction - direction of the command
* @param seqNum - transaction sequence number
*
* @return ZSuccess if OK
*/
ZStatus_t zcl_SendDiscoverCmdsCmd( uint8 srcEP, afAddrType_t *dstAddr, uint16 clusterID,
uint8 cmdType, zclDiscoverCmdsCmd_t *pDiscoverCmd,
uint8 direction, uint8 disableDefaultRsp, uint8 seqNum ) {
uint8 payload[2]; // size of startCmdID and maxCmdID
ZStatus_t status;
payload[0] = pDiscoverCmd->startCmdID;
payload[1] = pDiscoverCmd->maxCmdID;
// Send message for either commands received or generated
if ( cmdType == ZCL_CMD_DISCOVER_CMDS_RECEIVED ) {
status = zcl_SendCommand( srcEP, dstAddr, clusterID, ZCL_CMD_DISCOVER_CMDS_RECEIVED, FALSE,
direction, disableDefaultRsp, 0, seqNum, sizeof(payload), payload );
} else { // generated
status = zcl_SendCommand( srcEP, dstAddr, clusterID, ZCL_CMD_DISCOVER_CMDS_GEN, FALSE,
direction, disableDefaultRsp, 0, seqNum, sizeof(payload), payload );
}
return ( status );
}
/*********************************************************************
* @fn zcl_SendDiscoverCmdsRspCmd
*
* @brief Send a Discover Commands Response command
*
* @param dstAddr - destination address
* @param clusterID - cluster ID
* @param pDiscoverRspCmd - response command to be sent
* @param direction - direction of the command
* @param seqNum - transaction sequence number
*
* @return ZSuccess if OK
*/
ZStatus_t zcl_SendDiscoverCmdsRspCmd( uint8 srcEP, afAddrType_t *dstAddr,
uint16 clusterID, zclDiscoverCmdsCmdRsp_t *pDiscoverRspCmd,
uint8 direction, uint8 disableDefaultRsp, uint8 seqNum ) {
uint8 payloadSize = ( 1 + pDiscoverRspCmd->numCmd ); // size of discovery complete field plus cmds
uint8 *pCmdBuf;
uint8 i;
ZStatus_t status = ZSuccess;
// allocate memory
pCmdBuf = zcl_mem_alloc( payloadSize );
if ( pCmdBuf != NULL ) {
uint8 *pBuf = pCmdBuf;
// Load the buffer - serially
*pBuf++ = pDiscoverRspCmd->discComplete;
for ( i = 0; i < pDiscoverRspCmd->numCmd; i++ ) {
*pBuf++ = pDiscoverRspCmd->pCmdID[i];
}
// Send response message for either commands received or generated
if( pDiscoverRspCmd->cmdType == ZCL_CMD_DISCOVER_CMDS_RECEIVED ) {
status = zcl_SendCommand( srcEP, dstAddr, clusterID, ZCL_CMD_DISCOVER_CMDS_RECEIVED_RSP, FALSE,
direction, disableDefaultRsp, 0, seqNum, payloadSize, pCmdBuf );
} else if ( pDiscoverRspCmd->cmdType == ZCL_CMD_DISCOVER_CMDS_GEN ) {
status = zcl_SendCommand( srcEP, dstAddr, clusterID, ZCL_CMD_DISCOVER_CMDS_GEN_RSP, FALSE,
direction, disableDefaultRsp, 0, seqNum, payloadSize, pCmdBuf );
}
zcl_mem_free( pCmdBuf );
} else {
status = ZMemError;
}
return ( status );
}
/*********************************************************************
* @fn zcl_SendDiscoverAttrsCmd
*
* @brief Send a Discover Attributes command
*
* @param dstAddr - destination address
* @param clusterID - cluster ID
* @param pDiscoverCmd - discover command to be sent
* @param direction - direction of the command
* @param seqNum - transaction sequence number
*
* @return ZSuccess if OK
*/
ZStatus_t zcl_SendDiscoverAttrsCmd( uint8 srcEP, afAddrType_t *dstAddr,
uint16 clusterID, zclDiscoverAttrsCmd_t *pDiscoverCmd,
uint8 direction, uint8 disableDefaultRsp, uint8 seqNum ) {
uint8 dataLen = 2 + 1; // Start Attribute ID and Max Attribute IDs
uint8 *buf;
ZStatus_t status;
buf = zcl_mem_alloc( dataLen );
if ( buf != NULL ) {
// Load the buffer - serially
uint8 *pBuf = buf;
*pBuf++ = LO_UINT16(pDiscoverCmd->startAttr);
*pBuf++ = HI_UINT16(pDiscoverCmd->startAttr);
*pBuf++ = pDiscoverCmd->maxAttrIDs;
status = zcl_SendCommand( srcEP, dstAddr, clusterID, ZCL_CMD_DISCOVER_ATTRS, FALSE,
direction, disableDefaultRsp, 0, seqNum, dataLen, buf );
zcl_mem_free( buf );
} else {
status = ZMemError;
}
return ( status );
}
/*********************************************************************
* @fn zcl_SendDiscoverAttrsRspCmd
*
* @brief Send a Discover Attributes Response command
*
* @param dstAddr - destination address
* @param clusterID - cluster ID
* @param reportRspCmd - report response command to be sent
* @param direction - direction of the command
* @param seqNum - transaction sequence number
*
* @return ZSuccess if OK
*/
ZStatus_t zcl_SendDiscoverAttrsRspCmd( uint8 srcEP, afAddrType_t *dstAddr,
uint16 clusterID, zclDiscoverAttrsRspCmd_t *pDiscoverRspCmd,
uint8 direction, uint8 disableDefaultRsp, uint8 seqNum ) {
uint16 dataLen = 1; // Discovery complete
uint8 *buf;
ZStatus_t status;
// calculate the size of the command
dataLen += pDiscoverRspCmd->numAttr * (2 + 1); // Attribute ID and Data Type
buf = zcl_mem_alloc( dataLen );
if ( buf != NULL ) {
// Load the buffer - serially
uint8 i;
uint8 *pBuf = buf;
*pBuf++ = pDiscoverRspCmd->discComplete;
for ( i = 0; i < pDiscoverRspCmd->numAttr; i++ ) {
*pBuf++ = LO_UINT16(pDiscoverRspCmd->attrList[i].attrID);
*pBuf++ = HI_UINT16(pDiscoverRspCmd->attrList[i].attrID);
*pBuf++ = pDiscoverRspCmd->attrList[i].dataType;
}
status = zcl_SendCommand( srcEP, dstAddr, clusterID, ZCL_CMD_DISCOVER_ATTRS_RSP, FALSE,
direction, disableDefaultRsp, 0, seqNum, dataLen, buf );
zcl_mem_free( buf );
} else {
status = ZMemError;
}
return ( status );
}
/*********************************************************************
* @fn zcl_SendDiscoverAttrsExt
*
* @brief Send a Discover Attributes Extended command
*
* @param dstAddr - destination address
* @param clusterID - cluster ID
* @param pDiscoverAttrsExt:
* - startAttrID: the first attribute to be selected
* - maxAttrIDs: maximum number of returned attributes
* @param direction - direction of the command
* @param seqNum - transaction sequence number
*
* @return ZSuccess if OK
*/
ZStatus_t zcl_SendDiscoverAttrsExt( uint8 srcEP, afAddrType_t *dstAddr,
uint16 clusterID, zclDiscoverAttrsCmd_t *pDiscoverAttrsExt,
uint8 direction, uint8 disableDefaultRsp, uint8 seqNum ) {
uint8 buf[3]; // Buffer size equal to Start Attribute ID and Max Attribute IDs
ZStatus_t status;
// Load the buffer - serially
buf[0] = LO_UINT16(pDiscoverAttrsExt->startAttr);
buf[1] = HI_UINT16(pDiscoverAttrsExt->startAttr);
buf[2] = pDiscoverAttrsExt->maxAttrIDs;
status = zcl_SendCommand( srcEP, dstAddr, clusterID, ZCL_CMD_DISCOVER_ATTRS_EXT, FALSE,
direction, disableDefaultRsp, 0, seqNum, sizeof( buf ), buf );
return ( status );
}
/*********************************************************************
* @fn zcl_SendDiscoverAttrsExtRsp
*
* @brief Send a Discover Attributes Extended Response command
*
* @param dstAddr - destination address
* @param clusterID - cluster ID
* @param pDiscoverRspCmd:
* - discComplete: indicates whether all requested attributes returned
* - attrID: attribute ID
* - attrDataType: data type of the given attribute
* - attrAccessControl: access control of the given attribute
* @param direction - direction of the command
* @param seqNum - transaction sequence number
*
* @return ZSuccess if OK
*/
ZStatus_t zcl_SendDiscoverAttrsExtRsp( uint8 srcEP, afAddrType_t *dstAddr,
uint16 clusterID, zclDiscoverAttrsExtRsp_t *pDiscoverRspCmd,
uint8 direction, uint8 disableDefaultRsp, uint8 seqNum ) {
uint8 *buf;
uint8 i;
uint16 dataLen = 1; // Discovery complete
ZStatus_t status;
// calculate the size of the command
dataLen += pDiscoverRspCmd->numAttr * (2 + 1 + 1); // Attribute ID, Data Type, and Access Control
buf = zcl_mem_alloc( dataLen );
if ( buf != NULL ) {
// Load the buffer - serially
uint8 *pBuf = buf;
*pBuf++ = pDiscoverRspCmd->discComplete;
for ( i = 0; i < pDiscoverRspCmd->numAttr; i++ ) {
*pBuf++ = LO_UINT16(pDiscoverRspCmd->aExtAttrInfo[i].attrID);
*pBuf++ = HI_UINT16(pDiscoverRspCmd->aExtAttrInfo[i].attrID);
*pBuf++ = pDiscoverRspCmd->aExtAttrInfo[i].attrDataType;
*pBuf++ = pDiscoverRspCmd->aExtAttrInfo[i].attrAccessControl;
}
status = zcl_SendCommand( srcEP, dstAddr, clusterID, ZCL_CMD_DISCOVER_ATTRS_EXT_RSP, FALSE,
direction, disableDefaultRsp, 0, seqNum, dataLen, buf );
zcl_mem_free( buf );
} else {
status = ZMemError;
}
return ( status );
}
#endif // ZCL_DISCOVER
/*********************************************************************
* @fn zcl_ProcessMessageMSG
*
* @brief Data message processor callback. This function processes
* any incoming data - probably from other devices. So, based
* on cluster ID, perform the intended action.
*
* @param pkt - incoming message
*
* @return zclProcMsgStatus_t
*/
zclProcMsgStatus_t zcl_ProcessMessageMSG( afIncomingMSGPacket_t *pkt ) {
endPointDesc_t *epDesc;
zclIncoming_t inMsg;
zclLibPlugin_t *pInPlugin;
zclDefaultRspCmd_t defautlRspCmd;
uint8 options;
uint8 securityEnable;
uint8 interPanMsg;
ZStatus_t status = ZFailure;
uint8 defaultResponseSent = FALSE;
if ( pkt->cmd.DataLength < ZCL_VALID_MIN_HEADER_LEN ) {
return ( ZCL_PROC_INVALID ); // Error, ignore the message
}
// Initialize
rawAFMsg = (afIncomingMSGPacket_t *)pkt;
inMsg.msg = pkt;
inMsg.attrCmd = NULL;
inMsg.pData = NULL;
inMsg.pDataLen = 0;
inMsg.pData = zclParseHdr( &(inMsg.hdr), pkt->cmd.Data );
inMsg.pDataLen = pkt->cmd.DataLength;
inMsg.pDataLen -= (uint16)(inMsg.pData - pkt->cmd.Data);
// Temporary workaround to allow callback functions access to the
// transaction sequence number. Callback functions will call
// zcl_getParsedTransSeqNum() to retrieve this number.
savedZCLTransSeqNum = inMsg.hdr.transSeqNum;
// Find the wanted endpoint
epDesc = afFindEndPointDesc( pkt->endPoint );
if ( epDesc == NULL ) {
rawAFMsg = NULL;
return ( ZCL_PROC_EP_NOT_FOUND ); // Error, ignore the message
}
if ( ( epDesc->simpleDesc == NULL ) ||
( zcl_DeviceOperational( pkt->endPoint, pkt->clusterId, inMsg.hdr.fc.type,
inMsg.hdr.commandID, epDesc->simpleDesc->AppProfId ) == FALSE ) ) {
rawAFMsg = NULL;
return ( ZCL_PROC_NOT_OPERATIONAL ); // Error, ignore the message
}
#if defined ( INTER_PAN )
if ( StubAPS_InterPan( pkt->srcAddr.panId, pkt->srcAddr.endPoint ) ) {
// No foundation command is supported thru Inter-PAN communication.
// But the Light Link cluster uses a different Frame Control format
// for it's Inter-PAN messages, where the messages could be confused
// with the foundation commands.
if ( zcl_ProfileCmd( inMsg.hdr.fc.type ) ) {
rawAFMsg = NULL;
return ( ZCL_PROC_INTERPAN_FOUNDATION_CMD );
}
interPanMsg = TRUE;
options = AF_TX_OPTIONS_NONE;
} else
#endif
{
interPanMsg = FALSE;
options = zclGetClusterOption( pkt->endPoint, pkt->clusterId );
}
// Find the appropriate plugin
pInPlugin = zclFindPlugin( pkt->clusterId, epDesc->simpleDesc->AppProfId );
// Local and remote Security options must match except for Default Response command
if ( ( pInPlugin != NULL ) && !zcl_DefaultRspCmd( inMsg.hdr ) ) {
securityEnable = ( options & AF_EN_SECURITY ) ? TRUE : FALSE;
// Make sure that Clusters specifically defined to use security are received secure,
// any other cluster that wants to use APS security will be allowed
if ( ( securityEnable == TRUE ) && ( pkt->SecurityUse == FALSE ) ) {
if ( UNICAST_MSG( inMsg.msg ) ) {
// Send a Default Response command back with no Application Link Key security
zclSetSecurityOption( pkt->endPoint, pkt->clusterId, FALSE );
defautlRspCmd.statusCode = status;
defautlRspCmd.commandID = inMsg.hdr.commandID;
zcl_SendDefaultRspCmd( inMsg.msg->endPoint, &(inMsg.msg->srcAddr),
inMsg.msg->clusterId, &defautlRspCmd,
!inMsg.hdr.fc.direction, true,
inMsg.hdr.manuCode, inMsg.hdr.transSeqNum );
zclSetSecurityOption( pkt->endPoint, pkt->clusterId, TRUE );
}
rawAFMsg = NULL;
return ( ZCL_PROC_NOT_SECURE ); // Error, ignore the message
}
}
// Is this a foundation type message
if ( !interPanMsg && zcl_ProfileCmd( inMsg.hdr.fc.type ) ) {
if ( inMsg.hdr.fc.manuSpecific ) {
// We don't support any manufacturer specific command
status = ZCL_STATUS_UNSUP_MANU_GENERAL_COMMAND;
} else if ( ( inMsg.hdr.commandID <= ZCL_CMD_MAX ) &&
( zclCmdTable[inMsg.hdr.commandID].pfnParseInProfile != NULL ) ) {
zclParseCmd_t parseCmd;
parseCmd.endpoint = pkt->endPoint;
parseCmd.dataLen = inMsg.pDataLen;
parseCmd.pData = inMsg.pData;
// Parse the command, remember that the return value is a pointer to allocated memory
inMsg.attrCmd = zclParseCmd( inMsg.hdr.commandID, &parseCmd );
if ( (inMsg.attrCmd != NULL) && (zclCmdTable[inMsg.hdr.commandID].pfnProcessInProfile != NULL) ) {
// Process the command
if ( zclProcessCmd( inMsg.hdr.commandID, &inMsg ) == FALSE ) {
// Couldn't find attribute in the table.
}
}
// Free the buffer
if ( inMsg.attrCmd ) {
zcl_mem_free( inMsg.attrCmd );
}
if ( CMD_HAS_RSP( inMsg.hdr.commandID ) ) {
rawAFMsg = NULL;
return ( ZCL_PROC_SUCCESS ); // We're done
}
status = ZSuccess;
} else {
// Unsupported message
status = ZCL_STATUS_UNSUP_GENERAL_COMMAND;
}
} else { // Not a foundation type message, so it must be specific to the cluster ID.
if ( pInPlugin && pInPlugin->pfnIncomingHdlr ) {
// The return value of the plugin function will be
// ZSuccess - Supported and need default response
// ZFailure - Unsupported
// ZCL_STATUS_CMD_HAS_RSP - Supported and do not need default rsp
// ZCL_STATUS_INVALID_FIELD - Supported, but the incoming msg is wrong formatted
// ZCL_STATUS_INVALID_VALUE - Supported, but the request not achievable by the h/w
// ZCL_STATUS_SOFTWARE_FAILURE - Supported but ZStack memory allocation fails
status = pInPlugin->pfnIncomingHdlr( &inMsg );
if ( status == ZCL_STATUS_CMD_HAS_RSP || ( interPanMsg && status == ZSuccess ) ) {
rawAFMsg = NULL;
return ( ZCL_PROC_SUCCESS ); // We're done
}
}
if ( status == ZFailure ) {
// Unsupported message
if ( inMsg.hdr.fc.manuSpecific ) {
status = ZCL_STATUS_UNSUP_MANU_CLUSTER_COMMAND;
} else {
status = ZCL_STATUS_UNSUP_CLUSTER_COMMAND;
}
}
}
if ( UNICAST_MSG( inMsg.msg ) && inMsg.hdr.fc.disableDefaultRsp == 0 ) {
// Send a Default Response command back
defautlRspCmd.statusCode = status;
defautlRspCmd.commandID = inMsg.hdr.commandID;
zcl_SendDefaultRspCmd( inMsg.msg->endPoint, &(inMsg.msg->srcAddr),
inMsg.msg->clusterId, &defautlRspCmd,
!inMsg.hdr.fc.direction, true,
inMsg.hdr.manuCode, inMsg.hdr.transSeqNum );
defaultResponseSent = TRUE;
}
rawAFMsg = NULL;
if ( status == ZSuccess ) {
return ( ZCL_PROC_SUCCESS );
} else if ( status == ZCL_STATUS_UNSUP_MANU_GENERAL_COMMAND ) {
if ( defaultResponseSent ) {
return ( ZCL_PROC_MANUFACTURER_SPECIFIC_DR );
} else {
return ( ZCL_PROC_MANUFACTURER_SPECIFIC );
}
} else {
if ( defaultResponseSent ) {
return ( ZCL_PROC_NOT_HANDLED_DR );
} else {
return ( ZCL_PROC_NOT_HANDLED );
}
}
}
/*********************************************************************
* PRIVATE FUNCTIONS
*********************************************************************/
/*********************************************************************
* @fn zclParseHdr
*
* @brief Parse header of the ZCL format
*
* @param hdr - place to put the frame control information
* @param pData - incoming buffer to parse
*
* @return pointer past the header
*/
uint8 *zclParseHdr( zclFrameHdr_t *hdr, uint8 *pData ) {
// Clear the header
zcl_memset( (uint8 *)hdr, 0, sizeof ( zclFrameHdr_t ) );
// Parse the Frame Control
hdr->fc.type = zcl_FCType( *pData );
hdr->fc.manuSpecific = zcl_FCManuSpecific( *pData ) ? 1 : 0;
if ( zcl_FCDirection( *pData ) ) {
hdr->fc.direction = ZCL_FRAME_SERVER_CLIENT_DIR;
} else {
hdr->fc.direction = ZCL_FRAME_CLIENT_SERVER_DIR;
}
hdr->fc.disableDefaultRsp = zcl_FCDisableDefaultRsp( *pData ) ? 1 : 0;
pData++; // move past the frame control field
// parse the manfacturer code
if ( hdr->fc.manuSpecific ) {
hdr->manuCode = BUILD_UINT16( pData[0], pData[1] );
pData += 2;
}
// parse the Transaction Sequence Number
hdr->transSeqNum = *pData++;
// parse the Cluster's command ID
hdr->commandID = *pData++;
// Should point to the frame payload
return ( pData );
}
/*********************************************************************
* @fn zclBuildHdr
*
* @brief Build header of the ZCL format
*
* @param hdr - outgoing header information
* @param pData - outgoing header space
*
* @return pointer past the header
*/
static uint8 *zclBuildHdr( zclFrameHdr_t *hdr, uint8 *pData ) {
// Build the Frame Control byte
*pData = hdr->fc.type;
*pData |= hdr->fc.manuSpecific << 2;
*pData |= hdr->fc.direction << 3;
*pData |= hdr->fc.disableDefaultRsp << 4;
pData++; // move past the frame control field
// Add the manfacturer code
if ( hdr->fc.manuSpecific ) {
*pData++ = LO_UINT16( hdr->manuCode );
*pData++ = HI_UINT16( hdr->manuCode );
}
// Add the Transaction Sequence Number
*pData++ = hdr->transSeqNum;
// Add the Cluster's command ID
*pData++ = hdr->commandID;
// Should point to the frame payload
return ( pData );
}
/*********************************************************************
* @fn zclCalcHdrSize
*
* @brief Calculate the number of bytes needed for an outgoing
* ZCL header.
*
* @param hdr - outgoing header information
*
* @return returns the number of bytes needed
*/
static uint8 zclCalcHdrSize( zclFrameHdr_t *hdr ) {
uint8 needed = (1 + 1 + 1); // frame control + transaction seq num + cmd ID
// Add the manfacturer code
if ( hdr->fc.manuSpecific ) {
needed += 2;
}
return ( needed );
}
/*********************************************************************
* @fn zclFindPlugin
*
* @brief Find the right plugin for a cluster ID
*
* @param clusterID - cluster ID to look for
* @param profileID - profile ID
*
* @return pointer to plugin, NULL if not found
*/
static zclLibPlugin_t *zclFindPlugin( uint16 clusterID, uint16 profileID ) {
zclLibPlugin_t *pLoop = plugins;
(void)profileID; // Intentionally unreferenced parameter
while ( pLoop != NULL ) {
if ( ( clusterID >= pLoop->startClusterID ) && ( clusterID <= pLoop->endClusterID ) ) {
return ( pLoop );
}
pLoop = pLoop->next;
}
return ( (zclLibPlugin_t *)NULL );
}
#ifdef ZCL_DISCOVER
/*********************************************************************
* @fn zclFindCmdRecsList
*
* @brief Find the right command record list for an endpoint
*
* @param endpoint - endpoint to look for
*
* @return pointer to record list, NULL if not found
*/
static zclCmdRecsList_t *zclFindCmdRecsList( uint8 endpoint ) {
zclCmdRecsList_t *pLoop = gpCmdList;
while ( pLoop != NULL ) {
if ( pLoop->endpoint == endpoint ) {
return ( pLoop );
}
pLoop = pLoop->pNext;
}
return ( NULL );
}
/*********************************************************************
* @fn zclFindCmdRec
*
* @brief Find the command record that matchs the parameters
*
* @param endpoint - Application's endpoint
* @param clusterID - cluster ID
* @param attrId - attribute looking for
* @param pAttr - attribute record to be returned
*
* @return TRUE if record found. FALSE, otherwise.
*/
uint8 zclFindCmdRec( uint8 endpoint, uint16 clusterID, uint8 cmdID, zclCommandRec_t *pCmd ) {
uint8 i;
zclCmdRecsList_t *pRec = zclFindCmdRecsList( endpoint );
if ( pRec != NULL ) {
for ( i = 0; i < pRec->numCommands; i++ ) {
if ( pRec->pCmdRecs[i].clusterID == clusterID && pRec->pCmdRecs[i].cmdID == cmdID ) {
*pCmd = pRec->pCmdRecs[i];
return ( TRUE ); // EMBEDDED RETURN
}
}
}
return ( FALSE );
}
#endif // ZCL_DISCOVER
/*********************************************************************
* @fn zclFindAttrRecsList
*
* @brief Find the right attribute record list for an endpoint
*
* @param clusterID - endpointto look for
*
* @return pointer to record list, NULL if not found
*/
zclAttrRecsList *zclFindAttrRecsList( uint8 endpoint ) {
zclAttrRecsList *pLoop = attrList;
while ( pLoop != NULL ) {
if ( pLoop->endpoint == endpoint ) {
return ( pLoop );
}
pLoop = pLoop->next;
}
return ( NULL );
}
/*********************************************************************
* @fn zclFindAttrRec
*
* @brief Find the attribute record that matchs the parameters
*
* @param endpoint - Application's endpoint
* @param clusterID - cluster ID
* @param attrId - attribute looking for
* @param pAttr - attribute record to be returned
*
* @return TRUE if record found. FALSE, otherwise.
*/
uint8 zclFindAttrRec( uint8 endpoint, uint16 clusterID, uint16 attrId, zclAttrRec_t *pAttr ) {
uint8 x;
zclAttrRecsList *pRec = zclFindAttrRecsList( endpoint );
if ( pRec != NULL ) {
for ( x = 0; x < pRec->numAttributes; x++ ) {
if ( pRec->attrs[x].clusterID == clusterID && pRec->attrs[x].attr.attrId == attrId ) {
*pAttr = pRec->attrs[x];
return ( TRUE ); // EMBEDDED RETURN
}
}
}
return ( FALSE );
}
#if defined ( ZCL_STANDALONE )
/*********************************************************************
* @fn zclSetAttrRecList
*
* @brief Set attribute record list for end point
*
* @param endpoint - endpoint the attribute list belongs to
* @param numAttr - number of attributes in list
* @param attrList - array of attribute records.
* NOTE: THE ATTRIBUTE IDs (FOR A CLUSTER) MUST BE
* IN ASCENDING ORDER. OTHERWISE, THE DISCOVERY
* RESPONSE COMMAND WILL NOT HAVE THE RIGHT
* ATTRIBUTE INFO
*
* @return TRUE if successful, FALSE otherwise.
*/
uint8 zclSetAttrRecList( uint8 endpoint, uint8 numAttr, CONST zclAttrRec_t attrList[] ) {
zclAttrRecsList *pRecsList = zclFindAttrRecsList( endpoint );
if ( pRecsList != NULL ) {
pRecsList->numAttributes = numAttr;
pRecsList->attrs = attrList;
return ( TRUE );
}
return ( FALSE );
}
#endif // ZCL_STANDALONE
#if defined ( ZCL_READ ) || defined ( ZCL_WRITE )
/*********************************************************************
* @fn zclGetReadWriteCB
*
* @brief Get the Read/Write callback function pointer for a given endpoint.
*
* @param endpoint - Application's endpoint
*
* @return Read/Write CB, NULL if not found
*/
static zclReadWriteCB_t zclGetReadWriteCB( uint8 endpoint ) {
zclAttrRecsList *pRec = zclFindAttrRecsList( endpoint );
if ( pRec != NULL ) {
return ( pRec->pfnReadWriteCB );
}
return ( NULL );
}
/*********************************************************************
* @fn zclGetAuthorizeCB
*
* @brief Get the Read/Write Authorization callback function pointer
* for a given endpoint.
*
* @param endpoint - Application's endpoint
*
* @return Authorization CB, NULL if not found
*/
static zclAuthorizeCB_t zclGetAuthorizeCB( uint8 endpoint ) {
zclAttrRecsList *pRec = zclFindAttrRecsList( endpoint );
if ( pRec != NULL ) {
return ( pRec->pfnAuthorizeCB );
}
return ( NULL );
}
#endif // ZCL_READ || ZCL_WRITE
/*********************************************************************
* @fn zclFindClusterOption
*
* @brief Find the option record that matchs the cluster id
*
* @param endpoint - Application's endpoint
* @param clusterID - cluster ID looking for
*
* @return pointer to clutser option, NULL if not found
*/
static zclOptionRec_t *zclFindClusterOption( uint8 endpoint, uint16 clusterID ) {
zclClusterOptionList *pLoop;
pLoop = clusterOptionList;
while ( pLoop != NULL ) {
if ( pLoop->endpoint == endpoint ) {
uint8 x;
for ( x = 0; x < pLoop->numOptions; x++ ) {
if ( pLoop->options[x].clusterID == clusterID ) {
return ( &(pLoop->options[x]) ); // EMBEDDED RETURN
}
}
}
pLoop = pLoop->next;
}
return ( NULL );
}
/*********************************************************************
* @fn zclGetClusterOption
*
* @brief Get the option record that matchs the cluster id
*
* @param endpoint - Application's endpoint
* @param clusterID - cluster ID looking for
*
* @return clutser option, AF_TX_OPTIONS_NONE if not found
*/
static uint8 zclGetClusterOption( uint8 endpoint, uint16 clusterID ) {
uint8 option;
zclOptionRec_t *pOption;
pOption = zclFindClusterOption( endpoint, clusterID );
if ( pOption != NULL ) {
option = pOption->option;
if ( !ZG_SECURE_ENABLED ) {
option &= (AF_EN_SECURITY ^ 0xFF); // make sure Application Link Key security is off
}
return ( option ); // EMBEDDED RETURN
}
return ( AF_TX_OPTIONS_NONE );
}
/*********************************************************************
* @fn zclSetSecurityOption
*
* @brief Set the security option for the cluster id
*
* @param endpoint - Application's endpoint
* @param clusterID - cluster ID looking for
* @param enable - whether to enable (TRUE) or disable (FALSE) security option
*
* @return none
*/
static void zclSetSecurityOption( uint8 endpoint, uint16 clusterID, uint8 enable ) {
zclOptionRec_t *pOption;
pOption = zclFindClusterOption( endpoint, clusterID );
if ( pOption != NULL ) {
if ( enable ) {
pOption->option |= AF_EN_SECURITY;
} else {
pOption->option &= (AF_EN_SECURITY ^ 0xFF);
}
}
}
#ifdef ZCL_DISCOVER
/*********************************************************************
* @fn zclFindNextCmdRec
*
* @brief Find the command (or next) record that matchs the parameters
*
* @param endpoint - Application's endpoint
* @param clusterID - cluster ID
* @param commandID - command ID from requesting command
* @param direction- direction of received command
* @param pCmdID - command looking for
* @param pCmd - command information within command record list
*
* @return pointer to command record, NULL no more records of this cluster
*/
static uint8 zclFindNextCmdRec( uint8 endpoint, uint16 clusterID, uint8 commandID,
uint8 direction, uint8 *pCmdID, zclCommandRec_t *pCmd ) {
zclCmdRecsList_t *pRec = zclFindCmdRecsList( endpoint );
uint8 i;
if ( pRec != NULL ) {
for ( i = 0; i < pRec->numCommands; i++ ) {
if ( ( pRec->pCmdRecs[i].clusterID == clusterID ) &&
( pRec->pCmdRecs[i].cmdID >= *pCmdID ) ) {
if ( commandID == ZCL_CMD_DISCOVER_CMDS_RECEIVED ) {
if ( ( direction == ZCL_FRAME_SERVER_CLIENT_DIR ) && ( pRec->pCmdRecs[i].flag & CMD_DIR_CLIENT_RECEIVED ) ) {
*pCmd = pRec->pCmdRecs[i];
// Update command ID
*pCmdID = pCmd->cmdID;
return ( TRUE ); // EMBEDDED RETURN
} else if ( ( direction == ZCL_FRAME_CLIENT_SERVER_DIR ) && ( pRec->pCmdRecs[i].flag & CMD_DIR_SERVER_RECEIVED ) ) {
*pCmd = pRec->pCmdRecs[i];
// Update command ID
*pCmdID = pCmd->cmdID;
return ( TRUE ); // EMBEDDED RETURN
}
} else if ( commandID == ZCL_CMD_DISCOVER_CMDS_GEN ) {
if ( ( direction == ZCL_FRAME_CLIENT_SERVER_DIR ) && ( pRec->pCmdRecs[i].flag & CMD_DIR_SERVER_GENERATED ) ) {
*pCmd = pRec->pCmdRecs[i];
// Update command ID
*pCmdID = pCmd->cmdID;
return ( TRUE ); // EMBEDDED RETURN
} else if ( ( direction == ZCL_FRAME_SERVER_CLIENT_DIR ) && ( pRec->pCmdRecs[i].flag & CMD_DIR_CLIENT_GENERATED ) ) {
*pCmd = pRec->pCmdRecs[i];
// Update command ID
*pCmdID = pCmd->cmdID;
return ( TRUE ); // EMBEDDED RETURN
}
} else {
return ( FALSE ); // Incorrect Command ID
}
}
}
}
return ( FALSE );
}
/*********************************************************************
* @fn zclFindNextAttrRec
*
* @brief Find the attribute (or next) record that matchs the parameters
*
* @param endpoint - Application's endpoint
* @param clusterID - cluster ID
* @param attr - attribute looking for
*
* @return pointer to attribute record, NULL if not found
*/
static uint8 zclFindNextAttrRec( uint8 endpoint, uint16 clusterID, uint8 direction,
uint16 *attrId, zclAttrRec_t *pAttr ) {
zclAttrRecsList *pRec = zclFindAttrRecsList( endpoint );
uint8 attrDir;
if ( pRec != NULL ) {
uint16 x;
for ( x = 0; x < pRec->numAttributes; x++ ) {
if ( ( pRec->attrs[x].clusterID == clusterID ) &&
( pRec->attrs[x].attr.attrId >= *attrId ) ) {
// also make sure direction is right
attrDir = (pRec->attrs[x].attr.accessControl & ACCESS_CLIENT) ? 1 : 0;
if ( (attrDir == direction) || (pRec->attrs[x].attr.accessControl & ACCESS_GLOBAL)) {
// return attribute and found attribute ID
*pAttr = pRec->attrs[x];
*attrId = pAttr->attr.attrId;
return ( TRUE ); // EMBEDDED RETURN
}
}
}
}
return ( FALSE );
}
#endif // ZCL_DISCOVER
/*********************************************************************
* @fn zclSerializeData
*
* @brief Builds a buffer from the attribute data to sent out over
* the air.
* NOTE - Not compatible with application's attributes callbacks.
*
* @param dataType - data types defined in zcl.h
* @param attrData - pointer to the attribute data
* @param buf - where to put the serialized data
*
* @return pointer to end of destination buffer
*/
uint8 *zclSerializeData( uint8 dataType, void *attrData, uint8 *buf ) {
uint8 *pStr;
uint16 len;
if ( attrData == NULL ) {
return ( buf );
}
switch ( dataType ) {
case ZCL_DATATYPE_DATA8:
case ZCL_DATATYPE_BOOLEAN:
case ZCL_DATATYPE_BITMAP8:
case ZCL_DATATYPE_INT8:
case ZCL_DATATYPE_UINT8:
case ZCL_DATATYPE_ENUM8:
*buf++ = *((uint8 *)attrData);
break;
case ZCL_DATATYPE_DATA16:
case ZCL_DATATYPE_BITMAP16:
case ZCL_DATATYPE_UINT16:
case ZCL_DATATYPE_INT16:
case ZCL_DATATYPE_ENUM16:
case ZCL_DATATYPE_SEMI_PREC:
case ZCL_DATATYPE_CLUSTER_ID:
case ZCL_DATATYPE_ATTR_ID:
*buf++ = LO_UINT16( *((uint16*)attrData) );
*buf++ = HI_UINT16( *((uint16*)attrData) );
break;
case ZCL_DATATYPE_DATA24:
case ZCL_DATATYPE_BITMAP24:
case ZCL_DATATYPE_UINT24:
case ZCL_DATATYPE_INT24:
*buf++ = BREAK_UINT32( *((uint32*)attrData), 0 );
*buf++ = BREAK_UINT32( *((uint32*)attrData), 1 );
*buf++ = BREAK_UINT32( *((uint32*)attrData), 2 );
break;
case ZCL_DATATYPE_DATA32:
case ZCL_DATATYPE_BITMAP32:
case ZCL_DATATYPE_UINT32:
case ZCL_DATATYPE_INT32:
case ZCL_DATATYPE_SINGLE_PREC:
case ZCL_DATATYPE_TOD:
case ZCL_DATATYPE_DATE:
case ZCL_DATATYPE_UTC:
case ZCL_DATATYPE_BAC_OID:
buf = zcl_buffer_uint32( buf, *((uint32*)attrData) );
break;
case ZCL_DATATYPE_BITMAP40:
case ZCL_DATATYPE_UINT40:
case ZCL_DATATYPE_INT40:
pStr = (uint8*)attrData;
buf = zcl_memcpy( buf, pStr, 5 );
break;
case ZCL_DATATYPE_BITMAP48:
case ZCL_DATATYPE_UINT48:
case ZCL_DATATYPE_INT48:
pStr = (uint8*)attrData;
buf = zcl_memcpy( buf, pStr, 6 );
break;
case ZCL_DATATYPE_BITMAP56:
case ZCL_DATATYPE_UINT56:
case ZCL_DATATYPE_INT56:
pStr = (uint8*)attrData;
buf = zcl_memcpy( buf, pStr, 7 );
break;
case ZCL_DATATYPE_BITMAP64:
case ZCL_DATATYPE_DOUBLE_PREC:
case ZCL_DATATYPE_IEEE_ADDR:
case ZCL_DATATYPE_UINT64:
case ZCL_DATATYPE_INT64:
pStr = (uint8*)attrData;
buf = zcl_memcpy( buf, pStr, 8 );
break;
case ZCL_DATATYPE_CHAR_STR:
case ZCL_DATATYPE_OCTET_STR:
pStr = (uint8*)attrData;
len = *pStr;
buf = zcl_memcpy( buf, pStr, len+1 ); // Including length field
break;
case ZCL_DATATYPE_LONG_CHAR_STR:
case ZCL_DATATYPE_LONG_OCTET_STR:
pStr = (uint8*)attrData;
len = BUILD_UINT16( pStr[0], pStr[1] );
buf = zcl_memcpy( buf, pStr, len+2 ); // Including length field
break;
case ZCL_DATATYPE_128_BIT_SEC_KEY:
pStr = (uint8*)attrData;
buf = zcl_memcpy( buf, pStr, SEC_KEY_LEN );
break;
case ZCL_DATATYPE_NO_DATA:
case ZCL_DATATYPE_UNKNOWN:
// Fall through
default:
break;
}
return ( buf );
}
#if defined ZCL_REPORTING_DEVICE || defined ZCL_REPORT_CONFIGURING_DEVICE
/*********************************************************************
* @fn zclAnalogDataType
*
* @brief Checks to see if Data Type is Analog
*
* @param dataType - data type
*
* @return TRUE if data type is analog
*/
uint8 zclAnalogDataType( uint8 dataType ) {
uint8 analog;
switch ( dataType ) {
case ZCL_DATATYPE_UINT8:
case ZCL_DATATYPE_UINT16:
case ZCL_DATATYPE_UINT24:
case ZCL_DATATYPE_UINT32:
case ZCL_DATATYPE_UINT40:
case ZCL_DATATYPE_UINT48:
case ZCL_DATATYPE_UINT56:
case ZCL_DATATYPE_UINT64:
case ZCL_DATATYPE_INT8:
case ZCL_DATATYPE_INT16:
case ZCL_DATATYPE_INT24:
case ZCL_DATATYPE_INT32:
case ZCL_DATATYPE_INT40:
case ZCL_DATATYPE_INT48:
case ZCL_DATATYPE_INT56:
case ZCL_DATATYPE_INT64:
case ZCL_DATATYPE_SEMI_PREC:
case ZCL_DATATYPE_SINGLE_PREC:
case ZCL_DATATYPE_DOUBLE_PREC:
case ZCL_DATATYPE_TOD:
case ZCL_DATATYPE_DATE:
case ZCL_DATATYPE_UTC:
analog = TRUE;
break;
default:
analog = FALSE;
break;
}
return ( analog );
}
/*********************************************************************
* @fn zclIsLittleEndianMachine
*
* @brief Verifies endianness in system.
*
* @param none
*
* @return MSB-00 or LSB-01 depending on endianness in the system
*/
static int zclIsLittleEndianMachine(void) {
uint16 test = 0x0001;
return (*((uint8 *)(&test)));
}
/*********************************************************************
* @fn zcl_BuildAnalogData
*
* @brief Build an analog arribute out of sequential bytes.
*
* @param dataType - type of data
* @param pData - pointer to data
* @param pBuf - where to put the data
*
* @return none
*/
static void zcl_BuildAnalogData( uint8 dataType, uint8 *pData, uint8 *pBuf ) {
int current_byte_index;
int remaining_bytes;
int step;
remaining_bytes = zclGetAttrDataLength(dataType, pData);
// decide if move forward or backwards to copy data
if ( zclIsLittleEndianMachine() ) {
step = 1;
current_byte_index = 0;
} else {
step = -1;
current_byte_index = remaining_bytes - 1;
}
while ( remaining_bytes-- ) {
pData[current_byte_index] = *(pBuf++);
current_byte_index += step;
}
}
#endif
/*********************************************************************
* @fn zclGetDataTypeLength
*
* @brief Return the length of the datatype in octet.
*
* NOTE: Should not be called for ZCL_DATATYPE_OCTECT_STR or
* ZCL_DATATYPE_CHAR_STR data types.
*
* @param dataType - data type
*
* @return length of data
*/
uint8 zclGetDataTypeLength( uint8 dataType ) {
uint8 len;
switch ( dataType ) {
case ZCL_DATATYPE_DATA8:
case ZCL_DATATYPE_BOOLEAN:
case ZCL_DATATYPE_BITMAP8:
case ZCL_DATATYPE_INT8:
case ZCL_DATATYPE_UINT8:
case ZCL_DATATYPE_ENUM8:
len = 1;
break;
case ZCL_DATATYPE_DATA16:
case ZCL_DATATYPE_BITMAP16:
case ZCL_DATATYPE_UINT16:
case ZCL_DATATYPE_INT16:
case ZCL_DATATYPE_ENUM16:
case ZCL_DATATYPE_SEMI_PREC:
case ZCL_DATATYPE_CLUSTER_ID:
case ZCL_DATATYPE_ATTR_ID:
len = 2;
break;
case ZCL_DATATYPE_DATA24:
case ZCL_DATATYPE_BITMAP24:
case ZCL_DATATYPE_UINT24:
case ZCL_DATATYPE_INT24:
len = 3;
break;
case ZCL_DATATYPE_DATA32:
case ZCL_DATATYPE_BITMAP32:
case ZCL_DATATYPE_UINT32:
case ZCL_DATATYPE_INT32:
case ZCL_DATATYPE_SINGLE_PREC:
case ZCL_DATATYPE_TOD:
case ZCL_DATATYPE_DATE:
case ZCL_DATATYPE_UTC:
case ZCL_DATATYPE_BAC_OID:
len = 4;
break;
case ZCL_DATATYPE_UINT40:
case ZCL_DATATYPE_INT40:
len = 5;
break;
case ZCL_DATATYPE_UINT48:
case ZCL_DATATYPE_INT48:
len = 6;
break;
case ZCL_DATATYPE_UINT56:
case ZCL_DATATYPE_INT56:
len = 7;
break;
case ZCL_DATATYPE_DOUBLE_PREC:
case ZCL_DATATYPE_IEEE_ADDR:
case ZCL_DATATYPE_UINT64:
case ZCL_DATATYPE_INT64:
len = 8;
break;
case ZCL_DATATYPE_128_BIT_SEC_KEY:
len = SEC_KEY_LEN;
break;
case ZCL_DATATYPE_NO_DATA:
case ZCL_DATATYPE_UNKNOWN:
// Fall through
default:
len = 0;
break;
}
return ( len );
}
/*********************************************************************
* @fn zclGetAttrDataLength
*
* @brief Return the length of the attribute.
*
* @param dataType - data type
* @param pData - pointer to data
*
* @return returns atrribute length
*/
uint16 zclGetAttrDataLength( uint8 dataType, uint8 *pData ) {
uint16 dataLen = 0;
if ( dataType == ZCL_DATATYPE_LONG_CHAR_STR || dataType == ZCL_DATATYPE_LONG_OCTET_STR ) {
dataLen = BUILD_UINT16( pData[0], pData[1] ) + 2; // long string length + 2 for length field
} else if ( dataType == ZCL_DATATYPE_CHAR_STR || dataType == ZCL_DATATYPE_OCTET_STR ) {
dataLen = *pData + 1; // string length + 1 for length field
} else {
dataLen = zclGetDataTypeLength( dataType );
}
return ( dataLen );
}
#ifdef ZCL_READ
/*********************************************************************
* @fn zclReadAttrData
*
* @brief Read the attribute's current value into pAttrData.
* NOTE - Not compatible with application's attributes callbacks.
*
* @param pAttrData - where to put attribute data
* @param pAttr - pointer to attribute
* @param pDataLen - where to put attribute data length
*
* @return Success
*/
ZStatus_t zclReadAttrData( uint8 *pAttrData, zclAttrRec_t *pAttr, uint16 *pDataLen ) {
uint16 dataLen;
if ( pAttr->attr.dataPtr == NULL ) {
return ( ZCL_STATUS_FAILURE );
}
dataLen = zclGetAttrDataLength( pAttr->attr.dataType, (uint8*)(pAttr->attr.dataPtr) );
zcl_memcpy( pAttrData, pAttr->attr.dataPtr, dataLen );
if ( pDataLen != NULL ) {
*pDataLen = dataLen;
}
return ( ZCL_STATUS_SUCCESS );
}
/*********************************************************************
* @fn zcl_ReadAttrData
*
* @brief Read the attribute's current value into pAttrData.
* Use application's callback function if assigned to this attribute.
*
* @param endpoint - application's endpoint
* @param clusterId - cluster that attribute belongs to
* @param attrId - attribute id
* @param pAttrData - where to put attribute data
* @param pDataLen - where to put attribute data length
*
* @return Successful if data was read
*/
ZStatus_t zcl_ReadAttrData( uint8 endpoint, uint16 clusterId, uint16 attrId,
uint8 *pAttrData, uint16 *pDataLen ) {
zclAttrRec_t attrRec;
if ( zclFindAttrRec( endpoint, clusterId, attrId, &attrRec ) == FALSE ) {
return ( ZCL_STATUS_FAILURE );
}
if ( attrRec.attr.dataPtr != NULL ) {
return zclReadAttrData( pAttrData, &attrRec, pDataLen );
} else {
return zclReadAttrDataUsingCB( endpoint, clusterId, attrId, pAttrData, pDataLen );
}
}
/*********************************************************************
* @fn zclGetAttrDataLengthUsingCB
*
* @brief Use application's callback to get the length of the attribute's
* current value stored in the database.
*
* @param endpoint - application's endpoint
* @param clusterId - cluster that attribute belongs to
* @param attrId - attribute id
*
* @return returns attribute length
*/
static uint16 zclGetAttrDataLengthUsingCB( uint8 endpoint, uint16 clusterId, uint16 attrId ) {
uint16 dataLen = 0;
zclReadWriteCB_t pfnReadWriteCB = zclGetReadWriteCB( endpoint );
if ( pfnReadWriteCB != NULL ) {
// Only get the attribute length
(*pfnReadWriteCB)( clusterId, attrId, ZCL_OPER_LEN, NULL, &dataLen );
}
return ( dataLen );
}
/*********************************************************************
* @fn zclReadAttrDataUsingCB
*
* @brief Use application's callback to read the attribute's current
* value stored in the database.
*
* @param endpoint - application's endpoint
* @param clusterId - cluster that attribute belongs to
* @param attrId - attribute id
* @param pAttrData - where to put attribute data
* @param pDataLen - where to put attribute data length
*
* @return Successful if data was read
*/
static ZStatus_t zclReadAttrDataUsingCB( uint8 endpoint, uint16 clusterId, uint16 attrId,
uint8 *pAttrData, uint16 *pDataLen ) {
zclReadWriteCB_t pfnReadWriteCB = zclGetReadWriteCB( endpoint );
if ( pDataLen != NULL ) {
*pDataLen = 0; // Always initialize it to 0
}
if ( pfnReadWriteCB != NULL ) {
// Read the attribute value and its length
return ( (*pfnReadWriteCB)( clusterId, attrId, ZCL_OPER_READ, pAttrData, pDataLen ) );
}
return ( ZCL_STATUS_SOFTWARE_FAILURE );
}
/*********************************************************************
* @fn zclAuthorizeRead
*
* @brief Use application's callback to authorize a Read operation
* on a given attribute.
*
* @param endpoint - application's endpoint
* @param srcAddr - source Address
* @param pAttr - pointer to attribute
*
* @return ZCL_STATUS_SUCCESS: Operation authorized
* ZCL_STATUS_NOT_AUTHORIZED: Operation not authorized
*/
static ZStatus_t zclAuthorizeRead( uint8 endpoint, afAddrType_t *srcAddr, zclAttrRec_t *pAttr ) {
if ( zcl_AccessCtrlAuthRead( pAttr->attr.accessControl ) ) {
zclAuthorizeCB_t pfnAuthorizeCB = zclGetAuthorizeCB( endpoint );
if ( pfnAuthorizeCB != NULL ) {
return ( (*pfnAuthorizeCB)( srcAddr, pAttr, ZCL_OPER_READ ) );
}
}
return ( ZCL_STATUS_SUCCESS );
}
#endif // ZCL_READ
#ifdef ZCL_WRITE
/*********************************************************************
* @fn zclWriteAttrData
*
* @brief Write the received data.
*
* @param endpoint - application's endpoint
* @param pAttr - where to write data to
* @param pWriteRec - data to be written
*
* @return Successful if data was written
*/
static ZStatus_t zclWriteAttrData( uint8 endpoint, afAddrType_t *srcAddr,
zclAttrRec_t *pAttr, zclWriteRec_t *pWriteRec ) {
uint8 status;
if ( zcl_AccessCtrlWrite( pAttr->attr.accessControl ) ) {
status = zclAuthorizeWrite( endpoint, srcAddr, pAttr );
if ( status == ZCL_STATUS_SUCCESS ) {
if ( ( zcl_ValidateAttrDataCB == NULL ) || zcl_ValidateAttrDataCB( pAttr, pWriteRec ) ) {
// Write the attribute value
uint16 len = zclGetAttrDataLength( pAttr->attr.dataType, pWriteRec->attrData );
zcl_memcpy( pAttr->attr.dataPtr, pWriteRec->attrData, len );
status = ZCL_STATUS_SUCCESS;
} else {
status = ZCL_STATUS_INVALID_VALUE;
}
}
} else {
status = ZCL_STATUS_READ_ONLY;
}
return ( status );
}
/*********************************************************************
* @fn zclWriteAttrDataUsingCB
*
* @brief Use application's callback to write the attribute's current
* value stored in the database.
*
* @param endpoint - application's endpoint
* @param pAttr - where to write data to
* @param pAttrData - data to be written
*
* @return Successful if data was written
*/
static ZStatus_t zclWriteAttrDataUsingCB( uint8 endpoint, afAddrType_t *srcAddr,
zclAttrRec_t *pAttr, uint8 *pAttrData ) {
uint8 status;
if ( zcl_AccessCtrlWrite( pAttr->attr.accessControl ) ) {
status = zclAuthorizeWrite( endpoint, srcAddr, pAttr );
if ( status == ZCL_STATUS_SUCCESS ) {
zclReadWriteCB_t pfnReadWriteCB = zclGetReadWriteCB( endpoint );
if ( pfnReadWriteCB != NULL ) {
// Write the attribute value
status = (*pfnReadWriteCB)( pAttr->clusterID, pAttr->attr.attrId,
ZCL_OPER_WRITE, pAttrData, NULL );
} else {
status = ZCL_STATUS_SOFTWARE_FAILURE;
}
}
} else {
status = ZCL_STATUS_READ_ONLY;
}
return ( status );
}
/*********************************************************************
* @fn zclAuthorizeWrite
*
* @brief Use application's callback to authorize a Write operation
* on a given attribute.
*
* @param endpoint - application's endpoint
* @param srcAddr - source Address
* @param pAttr - pointer to attribute
*
* @return ZCL_STATUS_SUCCESS: Operation authorized
* ZCL_STATUS_NOT_AUTHORIZED: Operation not authorized
*/
static ZStatus_t zclAuthorizeWrite( uint8 endpoint, afAddrType_t *srcAddr, zclAttrRec_t *pAttr ) {
if ( zcl_AccessCtrlAuthWrite( pAttr->attr.accessControl ) ) {
zclAuthorizeCB_t pfnAuthorizeCB = zclGetAuthorizeCB( endpoint );
if ( pfnAuthorizeCB != NULL ) {
return ( (*pfnAuthorizeCB)( srcAddr, pAttr, ZCL_OPER_WRITE ) );
}
}
return ( ZCL_STATUS_SUCCESS );
}
#endif // ZCL_WRITE
#ifdef ZCL_READ
/*********************************************************************
* @fn zclParseInReadCmd
*
* @brief Parse the "Profile" Read Commands
*
* NOTE: THIS FUNCTION ALLOCATES THE RETURN BUFFER, SO THE CALLING
* FUNCTION IS RESPONSIBLE TO FREE THE MEMORY.
*
* @param pCmd - pointer to incoming data to parse
*
* @return pointer to the parsed command structure
*/
void *zclParseInReadCmd( zclParseCmd_t *pCmd ) {
zclReadCmd_t *readCmd;
uint8 *pBuf = pCmd->pData;
readCmd = (zclReadCmd_t *)zcl_mem_alloc( sizeof ( zclReadCmd_t ) + pCmd->dataLen );
if ( readCmd != NULL ) {
uint8 i;
readCmd->numAttr = pCmd->dataLen / 2; // Atrribute ID
for ( i = 0; i < readCmd->numAttr; i++ ) {
readCmd->attrID[i] = BUILD_UINT16( pBuf[0], pBuf[1] );
pBuf += 2;
}
}
return ( (void *)readCmd );
}
/*********************************************************************
* @fn zclParseInReadRspCmd
*
* @brief Parse the "Profile" Read Response Commands
*
* NOTE: THIS FUNCTION ALLOCATES THE RETURN BUFFER, SO THE CALLING
* FUNCTION IS RESPONSIBLE TO FREE THE MEMORY.
*
* @param pCmd - pointer to incoming data to parse
*
* @return pointer to the parsed command structure
*/
static void *zclParseInReadRspCmd( zclParseCmd_t *pCmd ) {
zclReadRspCmd_t *readRspCmd;
uint8 *pBuf = pCmd->pData;
uint8 *dataPtr;
uint8 numAttr = 0;
uint8 hdrLen;
uint16 dataLen = 0;
uint16 attrDataLen;
// find out the number of attributes and the length of attribute data
while ( pBuf < ( pCmd->pData + pCmd->dataLen ) ) {
uint8 status;
numAttr++;
pBuf += 2; // move pass attribute id
status = *pBuf++;
if ( status == ZCL_STATUS_SUCCESS ) {
uint8 dataType = *pBuf++;
attrDataLen = zclGetAttrDataLength( dataType, pBuf );
pBuf += attrDataLen; // move pass attribute data
// add padding if needed
if ( PADDING_NEEDED( attrDataLen ) ) {
attrDataLen++;
}
dataLen += attrDataLen;
}
}
// calculate the length of the response header
hdrLen = sizeof( zclReadRspCmd_t ) + ( numAttr * sizeof( zclReadRspStatus_t ) );
readRspCmd = (zclReadRspCmd_t *)zcl_mem_alloc( hdrLen + dataLen );
if ( readRspCmd != NULL ) {
uint8 i;
pBuf = pCmd->pData;
dataPtr = (uint8 *)( (uint8 *)readRspCmd + hdrLen );
readRspCmd->numAttr = numAttr;
for ( i = 0; i < numAttr; i++ ) {
zclReadRspStatus_t *statusRec = &(readRspCmd->attrList[i]);
statusRec->attrID = BUILD_UINT16( pBuf[0], pBuf[1] );
pBuf += 2;
statusRec->status = *pBuf++;
if ( statusRec->status == ZCL_STATUS_SUCCESS ) {
statusRec->dataType = *pBuf++;
attrDataLen = zclGetAttrDataLength( statusRec->dataType, pBuf );
zcl_memcpy( dataPtr, pBuf, attrDataLen);
statusRec->data = dataPtr;
pBuf += attrDataLen; // move pass attribute data
// advance attribute data pointer
if ( PADDING_NEEDED( attrDataLen ) ) {
attrDataLen++;
}
dataPtr += attrDataLen;
}
}
}
return ( (void *)readRspCmd );
}
#endif // ZCL_READ
#ifdef ZCL_WRITE
/*********************************************************************
* @fn zclParseInWriteCmd
*
* @brief Parse the "Profile" Write, Write Undivided and Write No
* Response Commands
*
* NOTE: THIS FUNCTION ALLOCATES THE RETURN BUFFER, SO THE CALLING
* FUNCTION IS RESPONSIBLE TO FREE THE MEMORY.
*
* @param pCmd - pointer to incoming data to parse
*
* @return pointer to the parsed command structure
*/
void *zclParseInWriteCmd( zclParseCmd_t *pCmd ) {
zclWriteCmd_t *writeCmd;
uint8 *pBuf = pCmd->pData;
uint16 attrDataLen;
uint8 *dataPtr;
uint8 numAttr = 0;
uint8 hdrLen;
uint16 dataLen = 0;
// find out the number of attributes and the length of attribute data
while ( pBuf < ( pCmd->pData + pCmd->dataLen ) ) {
uint8 dataType;
numAttr++;
pBuf += 2; // move pass attribute id
dataType = *pBuf++;
attrDataLen = zclGetAttrDataLength( dataType, pBuf );
pBuf += attrDataLen; // move pass attribute data
// add padding if needed
if ( PADDING_NEEDED( attrDataLen ) ) {
attrDataLen++;
}
dataLen += attrDataLen;
}
// calculate the length of the response header
hdrLen = sizeof( zclWriteCmd_t ) + ( numAttr * sizeof( zclWriteRec_t ) );
writeCmd = (zclWriteCmd_t *)zcl_mem_alloc( hdrLen + dataLen );
if ( writeCmd != NULL ) {
uint8 i;
pBuf = pCmd->pData;
dataPtr = (uint8 *)( (uint8 *)writeCmd + hdrLen );
writeCmd->numAttr = numAttr;
for ( i = 0; i < numAttr; i++ ) {
zclWriteRec_t *statusRec = &(writeCmd->attrList[i]);
statusRec->attrID = BUILD_UINT16( pBuf[0], pBuf[1] );
pBuf += 2;
statusRec->dataType = *pBuf++;
attrDataLen = zclGetAttrDataLength( statusRec->dataType, pBuf );
zcl_memcpy( dataPtr, pBuf, attrDataLen);
statusRec->attrData = dataPtr;
pBuf += attrDataLen; // move pass attribute data
// advance attribute data pointer
if ( PADDING_NEEDED( attrDataLen ) ) {
attrDataLen++;
}
dataPtr += attrDataLen;
}
}
return ( (void *)writeCmd );
}
/*********************************************************************
* @fn zclParseInWriteRspCmd
*
* @brief Parse the "Profile" Write Response Commands
*
* NOTE: THIS FUNCTION ALLOCATES THE RETURN BUFFER, SO THE CALLING
* FUNCTION IS RESPONSIBLE TO FREE THE MEMORY.
*
* @param pCmd - pointer to incoming data to parse
*
* @return pointer to the parsed command structure
*/
static void *zclParseInWriteRspCmd( zclParseCmd_t *pCmd ) {
zclWriteRspCmd_t *writeRspCmd;
uint8 *pBuf = pCmd->pData;
uint8 i = 0;
writeRspCmd = (zclWriteRspCmd_t *)zcl_mem_alloc( sizeof ( zclWriteRspCmd_t ) + pCmd->dataLen );
if ( writeRspCmd != NULL ) {
if ( pCmd->dataLen == 1 ) {
// special case when all writes were successfull
writeRspCmd->attrList[i++].status = *pBuf;
} else {
while ( pBuf < ( pCmd->pData + pCmd->dataLen ) ) {
writeRspCmd->attrList[i].status = *pBuf++;
writeRspCmd->attrList[i++].attrID = BUILD_UINT16( pBuf[0], pBuf[1] );
pBuf += 2;
}
}
writeRspCmd->numAttr = i;
}
return ( (void *)writeRspCmd );
}
#endif // ZCL_WRITE
#ifdef ZCL_REPORTING_DEVICE
/*********************************************************************
* @fn zclParseInConfigReportCmd
*
* @brief Parse the "Profile" Configure Reporting Command
*
* NOTE: THIS FUNCTION ALLOCATES THE RETURN BUFFER, SO THE CALLING
* FUNCTION IS RESPONSIBLE TO FREE THE MEMORY.
*
* @param pCmd - pointer to incoming data to parse
*
* @return pointer to the parsed command structure
*/
void *zclParseInConfigReportCmd( zclParseCmd_t *pCmd ) {
zclCfgReportCmd_t *cfgReportCmd;
uint8 *pBuf = pCmd->pData;
uint8 *dataPtr;
uint8 numAttr = 0;
uint8 dataType;
uint8 hdrLen;
uint16 dataLen = 0;
uint8 reportChangeLen; // length of Reportable Change field
// Calculate the length of the Request command
while ( pBuf < ( pCmd->pData + pCmd->dataLen ) ) {
uint8 direction;
numAttr++;
direction = *pBuf++;
pBuf += 2; // move pass the attribute ID
// Is there a Reportable Change field?
if ( direction == ZCL_SEND_ATTR_REPORTS ) {
dataType = *pBuf++;
pBuf += 4; // move pass the Min and Max Reporting Intervals
// For attributes of 'discrete' data types this field is omitted
if ( zclAnalogDataType( dataType ) ) {
reportChangeLen = zclGetDataTypeLength( dataType );
pBuf += reportChangeLen;
// add padding if needed
if ( PADDING_NEEDED( reportChangeLen ) ) {
reportChangeLen++;
}
dataLen += reportChangeLen;
} else {
pBuf++; // move past reportable change field
}
} else {
pBuf += 2; // move pass the Timeout Period
}
} // while loop
hdrLen = sizeof( zclCfgReportCmd_t ) + ( numAttr * sizeof( zclCfgReportRec_t ) );
cfgReportCmd = (zclCfgReportCmd_t *)zcl_mem_alloc( hdrLen + dataLen );
if ( cfgReportCmd != NULL ) {
uint8 i;
pBuf = pCmd->pData;
dataPtr = (uint8 *)( (uint8 *)cfgReportCmd + hdrLen );
cfgReportCmd->numAttr = numAttr;
for ( i = 0; i < numAttr; i++ ) {
zclCfgReportRec_t *reportRec = &(cfgReportCmd->attrList[i]);
zcl_memset( reportRec, 0, sizeof( zclCfgReportRec_t ) );
reportRec->direction = *pBuf++;
reportRec->attrID = BUILD_UINT16( pBuf[0], pBuf[1] );
pBuf += 2;
if ( reportRec->direction == ZCL_SEND_ATTR_REPORTS ) {
// Attribute to be reported
reportRec->dataType = *pBuf++;
reportRec->minReportInt = BUILD_UINT16( pBuf[0], pBuf[1] );
pBuf += 2;
reportRec->maxReportInt = BUILD_UINT16( pBuf[0], pBuf[1] );
pBuf += 2;
// For attributes of 'discrete' data types this field is omitted
if ( zclAnalogDataType( reportRec->dataType ) ) {
zcl_BuildAnalogData( reportRec->dataType, dataPtr, pBuf);
reportRec->reportableChange = dataPtr;
reportChangeLen = zclGetDataTypeLength( reportRec->dataType );
pBuf += reportChangeLen;
// advance attribute data pointer
if ( PADDING_NEEDED( reportChangeLen ) ) {
reportChangeLen++;
}
dataPtr += reportChangeLen;
}
} else {
// Attribute reports to be received
reportRec->timeoutPeriod = BUILD_UINT16( pBuf[0], pBuf[1] );
pBuf += 2;
}
} // while loop
}
return ( (void *)cfgReportCmd );
}
#endif
#ifdef ZCL_REPORT_CONFIGURING_DEVICE
/*********************************************************************
* @fn zclParseInConfigReportRspCmd
*
* @brief Parse the "Profile" Configure Reporting Response Command
*
* NOTE: THIS FUNCTION ALLOCATES THE RETURN BUFFER, SO THE CALLING
* FUNCTION IS RESPONSIBLE TO FREE THE MEMORY.
*
* @param pCmd - pointer to incoming data to parse
*
* @return pointer to the parsed command structure
*/
static void *zclParseInConfigReportRspCmd( zclParseCmd_t *pCmd ) {
zclCfgReportRspCmd_t *cfgReportRspCmd;
uint8 *pBuf = pCmd->pData;
uint8 numAttr;
numAttr = pCmd->dataLen / ( 1 + 1 + 2 ); // Status + Direction + Attribute ID
cfgReportRspCmd = (zclCfgReportRspCmd_t *)zcl_mem_alloc( sizeof( zclCfgReportRspCmd_t )
+ ( numAttr * sizeof( zclCfgReportStatus_t ) ) );
if ( cfgReportRspCmd != NULL ) {
uint8 i;
cfgReportRspCmd->numAttr = numAttr;
for ( i = 0; i < cfgReportRspCmd->numAttr; i++ ) {
cfgReportRspCmd->attrList[i].status = *pBuf++;
cfgReportRspCmd->attrList[i].direction = *pBuf++;
cfgReportRspCmd->attrList[i].attrID = BUILD_UINT16( pBuf[0], pBuf[1] );
pBuf += 2;
}
}
return ( (void *)cfgReportRspCmd );
}
#endif
#ifdef ZCL_REPORTING_DEVICE
/*********************************************************************
* @fn zclParseInReadReportCfgCmd
*
* @brief Parse the "Profile" Read Reporting Configuration Command
*
* NOTE: THIS FUNCTION ALLOCATES THE RETURN BUFFER, SO THE CALLING
* FUNCTION IS RESPONSIBLE TO FREE THE MEMORY.
*
* @param pCmd - pointer to incoming data to parse
*
* @return pointer to the parsed command structure
*/
void *zclParseInReadReportCfgCmd( zclParseCmd_t *pCmd ) {
zclReadReportCfgCmd_t *readReportCfgCmd;
uint8 *pBuf = pCmd->pData;
uint8 numAttr;
numAttr = pCmd->dataLen / ( 1 + 2 ); // Direction + Attribute ID
readReportCfgCmd = (zclReadReportCfgCmd_t *)zcl_mem_alloc( sizeof( zclReadReportCfgCmd_t )
+ ( numAttr * sizeof( zclReadReportCfgRec_t ) ) );
if ( readReportCfgCmd != NULL ) {
uint8 i;
readReportCfgCmd->numAttr = numAttr;
for ( i = 0; i < readReportCfgCmd->numAttr; i++) {
readReportCfgCmd->attrList[i].direction = *pBuf++;;
readReportCfgCmd->attrList[i].attrID = BUILD_UINT16( pBuf[0], pBuf[1] );
pBuf += 2;
}
}
return ( (void *)readReportCfgCmd );
}
#endif
#ifdef ZCL_REPORT_CONFIGURING_DEVICE
/*********************************************************************
* @fn zclParseInReadReportCfgRspCmd
*
* @brief Parse the "Profile" Read Reporting Configuration Response Command
*
* NOTE: THIS FUNCTION ALLOCATES THE RETURN BUFFER, SO THE CALLING
* FUNCTION IS RESPONSIBLE TO FREE THE MEMORY.
*
* @param pCmd - pointer to incoming data to parse
*
* @return pointer to the parsed command structure
*/
static void *zclParseInReadReportCfgRspCmd( zclParseCmd_t *pCmd ) {
zclReadReportCfgRspCmd_t *readReportCfgRspCmd;
uint8 reportChangeLen;
uint8 *pBuf = pCmd->pData;
uint8 *dataPtr;
uint8 numAttr = 0;
uint8 hdrLen;
uint16 dataLen = 0;
// Calculate the length of the response command
while ( pBuf < ( pCmd->pData + pCmd->dataLen ) ) {
uint8 status;
uint8 direction;
numAttr++;
status = *pBuf++;
direction = *pBuf++;
pBuf += 2; // move pass the attribute ID
if ( status == ZCL_STATUS_SUCCESS ) {
if ( direction == ZCL_SEND_ATTR_REPORTS ) {
uint8 dataType = *pBuf++;
pBuf += 4; // move pass the Min and Max Reporting Intervals
// For attributes of 'discrete' data types this field is omitted
if ( zclAnalogDataType( dataType ) ) {
reportChangeLen = zclGetDataTypeLength( dataType );
pBuf += reportChangeLen;
// add padding if needed
if ( PADDING_NEEDED( reportChangeLen ) ) {
reportChangeLen++;
}
dataLen += reportChangeLen;
}
} else {
pBuf += 2; // move pass the Timeout field
}
}
} // while loop
hdrLen = sizeof( zclReadReportCfgRspCmd_t ) + ( numAttr * sizeof( zclReportCfgRspRec_t ) );
readReportCfgRspCmd = (zclReadReportCfgRspCmd_t *)zcl_mem_alloc( hdrLen + dataLen );
if ( readReportCfgRspCmd != NULL ) {
uint8 i;
pBuf = pCmd->pData;
dataPtr = (uint8 *)( (uint8 *)readReportCfgRspCmd + hdrLen );
readReportCfgRspCmd->numAttr = numAttr;
for ( i = 0; i < numAttr; i++ ) {
zclReportCfgRspRec_t *reportRspRec = &(readReportCfgRspCmd->attrList[i]);
reportRspRec->status = *pBuf++;
reportRspRec->direction = *pBuf++;
reportRspRec->attrID = BUILD_UINT16( pBuf[0], pBuf[1] );
pBuf += 2;
if ( reportRspRec->status == ZCL_STATUS_SUCCESS ) {
if ( reportRspRec->direction == ZCL_SEND_ATTR_REPORTS ) {
reportRspRec->dataType = *pBuf++;
reportRspRec->minReportInt = BUILD_UINT16( pBuf[0], pBuf[1] );
pBuf += 2;
reportRspRec->maxReportInt = BUILD_UINT16( pBuf[0], pBuf[1] );
pBuf += 2;
if ( zclAnalogDataType( reportRspRec->dataType ) ) {
zcl_BuildAnalogData( reportRspRec->dataType, dataPtr, pBuf);
reportRspRec->reportableChange = dataPtr;
reportChangeLen = zclGetDataTypeLength( reportRspRec->dataType );
pBuf += reportChangeLen;
// advance attribute data pointer
if ( PADDING_NEEDED( reportChangeLen ) ) {
reportChangeLen++;
}
dataPtr += reportChangeLen;
}
} else {
reportRspRec->timeoutPeriod = BUILD_UINT16( pBuf[0], pBuf[1] );
pBuf += 2;
}
}
}
}
return ( (void *)readReportCfgRspCmd );
}
#endif
#ifdef ZCL_REPORT_DESTINATION_DEVICE
/*********************************************************************
* @fn zclParseInReportCmd
*
* @brief Parse the "Profile" Report Command
*
* NOTE: THIS FUNCTION ALLOCATES THE RETURN BUFFER, SO THE CALLING
* FUNCTION IS RESPONSIBLE TO FREE THE MEMORY.
*
* @param pCmd - pointer to incoming data to parse
*
* @return pointer to the parsed command structure
*/
void *zclParseInReportCmd( zclParseCmd_t *pCmd ) {
zclReportCmd_t *reportCmd;
uint8 *pBuf = pCmd->pData;
uint16 attrDataLen;
uint8 *dataPtr;
uint8 numAttr = 0;
uint8 hdrLen;
uint16 dataLen = 0;
// find out the number of attributes and the length of attribute data
while ( pBuf < ( pCmd->pData + pCmd->dataLen ) ) {
uint8 dataType;
numAttr++;
pBuf += 2; // move pass attribute id
dataType = *pBuf++;
attrDataLen = zclGetAttrDataLength( dataType, pBuf );
pBuf += attrDataLen; // move pass attribute data
// add padding if needed
if ( PADDING_NEEDED( attrDataLen ) ) {
attrDataLen++;
}
dataLen += attrDataLen;
}
hdrLen = sizeof( zclReportCmd_t ) + ( numAttr * sizeof( zclReport_t ) );
reportCmd = (zclReportCmd_t *)zcl_mem_alloc( hdrLen + dataLen );
if (reportCmd != NULL ) {
uint8 i;
pBuf = pCmd->pData;
dataPtr = (uint8 *)( (uint8 *)reportCmd + hdrLen );
reportCmd->numAttr = numAttr;
for ( i = 0; i < numAttr; i++ ) {
zclReport_t *reportRec = &(reportCmd->attrList[i]);
reportRec->attrID = BUILD_UINT16( pBuf[0], pBuf[1] );
pBuf += 2;
reportRec->dataType = *pBuf++;
attrDataLen = zclGetAttrDataLength( reportRec->dataType, pBuf );
zcl_memcpy( dataPtr, pBuf, attrDataLen );
reportRec->attrData = dataPtr;
pBuf += attrDataLen; // move pass attribute data
// advance attribute data pointer
if ( PADDING_NEEDED( attrDataLen ) ) {
attrDataLen++;
}
dataPtr += attrDataLen;
}
}
return ( (void *)reportCmd );
}
#endif
/*********************************************************************
* @fn zclParseInDefaultRspCmd
*
* @brief Parse the "Profile" Default Response Command
*
* NOTE: THIS FUNCTION ALLOCATES THE RETURN BUFFER, SO THE CALLING
* FUNCTION IS RESPONSIBLE TO FREE THE MEMORY.
*
* @param pCmd - pointer to incoming data to parse
*
* @return pointer to the parsed command structure
*/
static void *zclParseInDefaultRspCmd( zclParseCmd_t *pCmd ) {
zclDefaultRspCmd_t *defaultRspCmd;
uint8 *pBuf = pCmd->pData;
defaultRspCmd = (zclDefaultRspCmd_t *)zcl_mem_alloc( sizeof ( zclDefaultRspCmd_t ) );
if ( defaultRspCmd != NULL ) {
defaultRspCmd->commandID = *pBuf++;
defaultRspCmd->statusCode = *pBuf;
}
return ( (void *)defaultRspCmd );
}
#ifdef ZCL_DISCOVER
/*********************************************************************
* @fn zclParseInDiscAttrsCmd
*
* @brief Parse the "Profile" Discovery Attributes and Attributes Extended Commands
*
* NOTE: THIS FUNCTION ALLOCATES THE RETURN BUFFER, SO THE CALLING
* FUNCTION IS RESPONSIBLE TO FREE THE MEMORY.
*
* @param pCmd - pointer to incoming data to parse
*
* @return pointer to the parsed command structure
*/
void *zclParseInDiscAttrsCmd( zclParseCmd_t *pCmd ) {
zclDiscoverAttrsCmd_t *pDiscoverCmd;
uint8 *pBuf = pCmd->pData;
pDiscoverCmd = (zclDiscoverAttrsCmd_t *)zcl_mem_alloc( sizeof ( zclDiscoverAttrsCmd_t ) );
if ( pDiscoverCmd != NULL ) {
pDiscoverCmd->startAttr = BUILD_UINT16( pBuf[0], pBuf[1] );
pBuf += 2;
pDiscoverCmd->maxAttrIDs = *pBuf;
}
return ( (void *)pDiscoverCmd );
}
/*********************************************************************
* @fn zclParseInDiscAttrsRspCmd
*
* @brief Parse the "Profile" Discovery Response Commands
*
* NOTE: THIS FUNCTION ALLOCATES THE RETURN BUFFER, SO THE CALLING
* FUNCTION IS RESPONSIBLE TO FREE THE MEMORY.
*
* @param pCmd - pointer to incoming data to parse
*
* @return pointer to the parsed command structure
*/
#define ZCLDISCRSPCMD_DATALEN(a) ((a)-1) // data len - Discovery Complete
static void *zclParseInDiscAttrsRspCmd( zclParseCmd_t *pCmd ) {
zclDiscoverAttrsRspCmd_t *pDiscoverRspCmd;
uint8 *pBuf = pCmd->pData;
uint8 numAttr = ZCLDISCRSPCMD_DATALEN(pCmd->dataLen) / ( 2 + 1 ); // Attr ID + Data Type
pDiscoverRspCmd = (zclDiscoverAttrsRspCmd_t *)zcl_mem_alloc( sizeof ( zclDiscoverAttrsRspCmd_t ) +
( numAttr * sizeof(zclDiscoverAttrInfo_t) ) );
if ( pDiscoverRspCmd != NULL ) {
uint8 i;
pDiscoverRspCmd->discComplete = *pBuf++;
pDiscoverRspCmd->numAttr = numAttr;
for ( i = 0; i < numAttr; i++ ) {
pDiscoverRspCmd->attrList[i].attrID = BUILD_UINT16( pBuf[0], pBuf[1] );
pBuf += 2;
pDiscoverRspCmd->attrList[i].dataType = *pBuf++;
}
}
return ( (void *)pDiscoverRspCmd );
}
/*********************************************************************
* @fn zclParseInDiscCmdsCmd
*
* @brief Parse the "Profile" Discovery Commands
*
* NOTE: THIS FUNCTION ALLOCATES THE RETURN BUFFER, SO THE CALLING
* FUNCTION IS RESPONSIBLE TO FREE THE MEMORY.
*
* @param pCmd - pointer to incoming data to parse
*
* @return pointer to the parsed command structure
*/
void *zclParseInDiscCmdsCmd( zclParseCmd_t *pCmd ) {
zclDiscoverCmdsCmd_t *pDiscoverCmd;
uint8 *pBuf = pCmd->pData;
pDiscoverCmd = (zclDiscoverCmdsCmd_t *)zcl_mem_alloc( sizeof ( zclDiscoverCmdsCmd_t ) );
if ( pDiscoverCmd != NULL ) {
pDiscoverCmd->startCmdID = *pBuf++;
pDiscoverCmd->maxCmdID = *pBuf++;
}
return ( (void *)pDiscoverCmd );
}
/*********************************************************************
* @fn zclParseInDiscCmdsRspCmd
*
* @brief Parse the Discover Commands Response Command
*
* NOTE: THIS FUNCTION ALLOCATES THE RETURN BUFFER, SO THE CALLING
* FUNCTION IS RESPONSIBLE TO FREE THE MEMORY.
*
* @param pCmd - pointer to incoming data to parse
*
* @return pointer to the parsed command structure
*/
#define ZCLDISCRSPCMD_DATALEN(a) ((a)-1) // data len - Discovery Complete
static void *zclParseInDiscCmdsRspCmd( zclParseCmd_t *pCmd ) {
zclDiscoverCmdsCmdRsp_t *pDiscoverRspCmd;
uint8 *pBuf = pCmd->pData;
uint8 numCmds = ZCLDISCRSPCMD_DATALEN(pCmd->dataLen); // length of command ID variable array
// allocate memory for size of structure plus variable array
pDiscoverRspCmd = (zclDiscoverCmdsCmdRsp_t *)zcl_mem_alloc( sizeof ( zclDiscoverCmdsCmdRsp_t ) +
( numCmds * sizeof(uint8) ) );
if ( pDiscoverRspCmd != NULL ) {
uint8 i;
pDiscoverRspCmd->discComplete = *pBuf++;
pDiscoverRspCmd->numCmd = numCmds;
for ( i = 0; i < numCmds; i++ ) {
pDiscoverRspCmd->pCmdID[i] = *pBuf++;
}
}
return ( (void *)pDiscoverRspCmd );
}
/*********************************************************************
* @fn zclParseInDiscAttrsExtRspCmd
*
* @brief Parse the "Profile" Discovery Extended Attributes Response Commands
*&#x