| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349 |
- /**************************************************************************************************
- Filename: zcl.c
- Revised: $Date: 2009-04-06 09:08:36 -0700 (Mon, 06 Apr 2009) $
- Revision: $Revision: 19702 $
- Description: This file contains the Zigbee Cluster Library Foundation functions.
- Copyright 2006-2009 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 "OSAL.h"
- #include "OSAL_Tasks.h"
- #include "AF.h"
- #include "ZDConfig.h"
- #include "zcl.h"
- #include "zcl_general.h"
- #if defined ( INTER_PAN )
- #include "stub_aps.h"
- #endif
- /*********************************************************************
- * 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 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
- #define CMD_HAS_RSP( cmd ) ( (cmd) == ZCL_CMD_READ || \
- (cmd) == ZCL_CMD_WRITE || \
- (cmd) == ZCL_CMD_WRITE_UNDIVIDED || \
- (cmd) == ZCL_CMD_CONFIG_REPORT || \
- (cmd) == ZCL_CMD_READ_REPORT_CFG || \
- (cmd) == ZCL_CMD_DISCOVER || \
- (cmd) == ZCL_CMD_DEFAULT_RSP ) // exception
- /*********************************************************************
- * 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;
- // Attribute record list item
- typedef struct zclAttrRecsList
- {
- struct zclAttrRecsList *next;
- uint8 endpoint; // Used to link it into the endpoint descriptor
- uint8 numAttributes; // Number of the following records
- CONST zclAttrRec_t *attrs; // attribute records
- } zclAttrRecsList;
- // 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;
- /*********************************************************************
- * GLOBAL VARIABLES
- */
- uint8 zcl_TaskID;
- // The task Id of the Application where the unprocessed Foundation
- // Command/Response messages will be sent to.
- uint8 zcl_RegisteredMsgTaskID = TASK_NO_TASK;
- // The Application should register its attribute data validation function
- zclValidateAttrData_t zcl_ValidateAttrDataCB = NULL;
- // ZCL Sequence number
- uint8 zcl_SeqNum = 0x00;
-
- /*********************************************************************
- * EXTERNAL VARIABLES
- */
- /*********************************************************************
- * EXTERNAL FUNCTIONS
- */
- /*********************************************************************
- * LOCAL VARIABLES
- */
- static zclLibPlugin_t *plugins;
- static zclAttrRecsList *attrList;
- static zclClusterOptionList *clusterOptionList;
- static uint8 zcl_TransID = 0; // This is the unique message ID (counter)
- /*********************************************************************
- * LOCAL FUNCTIONS
- */
- static void zclProcessMessageMSG( afIncomingMSGPacket_t *pkt );
- static uint8 *zclBuildHdr( zclFrameHdr_t *hdr, uint8 *pData );
- static uint8 zclCalcHdrSize( zclFrameHdr_t *hdr );
- static zclLibPlugin_t *zclFindPlugin( uint16 clusterID, uint16 profileID );
- 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) || defined(ZCL_REPORT)
- static void zclSerializeData( uint8 dataType, void *attrData, uint8 *buf );
- #endif // ZCL_READ || ZCL_WRITE || ZCL_REPORT
- #ifdef ZCL_READ
- static void *zclParseInReadRspCmd( zclParseCmd_t *pCmd );
- static uint8 zclProcessInReadCmd( zclIncoming_t *pInMsg );
- #endif // ZCL_READ
- #ifdef ZCL_WRITE
- static uint8 zclWriteAttrData( zclAttrRec_t *pAttr, zclWriteRec_t *pWriteRec );
- static void *zclParseInWriteRspCmd( zclParseCmd_t *pCmd );
- static uint8 zclProcessInWriteCmd( zclIncoming_t *pInMsg );
- static uint8 zclProcessInWriteUndividedCmd( zclIncoming_t *pInMsg );
- #endif // ZCL_WRITE
- #ifdef ZCL_REPORT
- static void *zclParseInConfigReportRspCmd( zclParseCmd_t *pCmd );
- static void *zclParseInReadReportCfgRspCmd( zclParseCmd_t *pCmd );
- #endif // ZCL_REPORT
- static void *zclParseInDefaultRspCmd( zclParseCmd_t *pCmd );
- #ifdef ZCL_DISCOVER
- static uint8 zclFindNextAttrRec( uint8 endpoint, uint16 clusterID, uint16 *attrId, zclAttrRec_t *pAttr );
- static void *zclParseInDiscRspCmd( zclParseCmd_t *pCmd );
- static uint8 zclProcessInDiscCmd( zclIncoming_t *pInMsg );
- #endif // ZCL_DISCOVER
- static uint8 zclSendMsg( zclIncoming_t *pInMsg );
- /*********************************************************************
- * Parse Profile Command Function Table
- */
- static CONST zclCmdItems_t zclCmdTable[] =
- {
- #ifdef ZCL_READ
- /* ZCL_CMD_READ */ { zclParseInReadCmd, zclProcessInReadCmd },
- /* ZCL_CMD_READ_RSP */ { zclParseInReadRspCmd, zclSendMsg },
- #else
- /* ZCL_CMD_READ */ { NULL, NULL },
- /* ZCL_CMD_READ_RSP */ { NULL, NULL },
- #endif // ZCL_READ
- #ifdef ZCL_WRITE
- /* ZCL_CMD_WRITE */ { zclParseInWriteCmd, zclProcessInWriteCmd },
- /* ZCL_CMD_WRITE_UNDIVIDED */ { zclParseInWriteCmd, zclProcessInWriteUndividedCmd },
- /* ZCL_CMD_WRITE_RSP */ { zclParseInWriteRspCmd, zclSendMsg },
- /* ZCL_CMD_WRITE_NO_RSP */ { zclParseInWriteCmd, zclProcessInWriteCmd },
- #else
- /* ZCL_CMD_WRITE */ { NULL, NULL },
- /* ZCL_CMD_WRITE_UNDIVIDED */ { NULL, NULL },
- /* ZCL_CMD_WRITE_RSP */ { NULL, NULL },
- /* ZCL_CMD_WRITE_NO_RSP */ { NULL, NULL },
- #endif // ZCL_WRITE
- #ifdef ZCL_REPORT
- /* ZCL_CMD_CONFIG_REPORT */ { zclParseInConfigReportCmd, zclSendMsg },
- /* ZCL_CMD_CONFIG_REPORT_RSP */ { zclParseInConfigReportRspCmd, zclSendMsg },
- /* ZCL_CMD_READ_REPORT_CFG */ { zclParseInReadReportCfgCmd, zclSendMsg },
- /* ZCL_CMD_READ_REPORT_CFG_RSP */ { zclParseInReadReportCfgRspCmd, zclSendMsg },
- /* ZCL_CMD_REPORT */ { zclParseInReportCmd, zclSendMsg },
- #else
- /* ZCL_CMD_CONFIG_REPORT */ { NULL, NULL },
- /* ZCL_CMD_CONFIG_REPORT_RSP */ { NULL, NULL },
- /* ZCL_CMD_READ_REPORT_CFG */ { NULL, NULL },
- /* ZCL_CMD_READ_REPORT_CFG_RSP */ { NULL, NULL },
- /* ZCL_CMD_REPORT */ { NULL, NULL },
- #endif // ZCL_REPORT
- /* ZCL_CMD_DEFAULT_RSP */ { zclParseInDefaultRspCmd, zclSendMsg },
-
- #ifdef ZCL_DISCOVER
- /* ZCL_CMD_DISCOVER */ { zclParseInDiscCmd, zclProcessInDiscCmd },
- /* ZCL_CMD_DISCOVER_RSP */ { zclParseInDiscRspCmd, zclSendMsg }
- #else
- /* ZCL_CMD_DISCOVER */ { NULL, NULL },
- /* ZCL_CMD_DISCOVER_RSP */ { NULL, NULL }
- #endif // ZCL_DISCOVER
- };
- /*********************************************************************
- * PUBLIC FUNCTIONS
- *********************************************************************/
- /*********************************************************************
- * @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;
- plugins = (zclLibPlugin_t *)NULL;
- attrList = (zclAttrRecsList *)NULL;
- clusterOptionList = (zclClusterOptionList *)NULL;
- }
- /*********************************************************************
- * @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 )
- {
- zclProcessMessageMSG( (afIncomingMSGPacket_t *)msgPtr );
- }
- else if ( zcl_RegisteredMsgTaskID != TASK_NO_TASK )
- {
- // send it to another task to process.
- osal_msg_send( zcl_RegisteredMsgTaskID, 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);
- }
- // Discard unknown events
- return 0;
- }
- /*********************************************************************
- * @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 = osal_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 );
- }
- /*********************************************************************
- * @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 = osal_mem_alloc( sizeof( zclAttrRecsList ) );
- if ( pNewItem == NULL )
- return (ZMemError);
- pNewItem->next = (zclAttrRecsList *)NULL;
- pNewItem->endpoint = endpoint;
- 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 = osal_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_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 )
- {
- // Allow only the first task
- if ( zcl_RegisteredMsgTaskID == TASK_NO_TASK )
- {
- zcl_RegisteredMsgTaskID = taskId;
-
- return ( true );
- }
-
- return ( false );
- }
- /*********************************************************************
- * @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 ) )
- zclReadAttrData( &deviceEnabled, &attrRec );
-
- 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,
- uint8 cmdFormatLen, uint8 *cmdFormat )
- {
- endPointDesc_t *epDesc;
- zclFrameHdr_t hdr;
- uint8 *msgBuf;
- uint8 msgLen;
- uint8 *pBuf;
- afAddrType_t dstAddr;
- uint8 options;
- ZStatus_t status;
- osal_memcpy( &dstAddr, destAddr, sizeof ( afAddrType_t ) );
- epDesc = afFindEndPointDesc( srcEP );
- if ( epDesc == NULL )
- return ( ZInvalidParameter ); // EMBEDDED RETURN
- if ( clusterID == ZCL_INVALID_CLUSTER_ID )
- 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 );
-
- osal_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 ( 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 = osal_mem_alloc( msgLen );
- if ( msgBuf != NULL )
- {
- // Fill in the ZCL Header
- pBuf = zclBuildHdr( &hdr, msgBuf );
- // Fill in the command frame
- osal_memcpy( pBuf, cmdFormat, cmdFormatLen );
- status = AF_DataRequest( &dstAddr, epDesc, clusterID, msgLen, msgBuf,
- &zcl_TransID, options, AF_DEFAULT_RADIUS );
- osal_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)
- {
- uint8 dataLen;
- uint8 *buf;
- uint8 *pBuf;
- ZStatus_t status;
- dataLen = readCmd->numAttr * 2; // Attribute ID
- buf = osal_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 );
- osal_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;
- uint8 *pBuf;
- zclReadRspStatus_t *statusRec;
- uint8 len = 0;
- uint8 i;
- ZStatus_t status;
-
- // calculate the size of the command
- for ( i = 0; i < readRspCmd->numAttr; i++ )
- {
- statusRec = &(readRspCmd->attrList[i]);
-
- len += 2 + 1; // Attribute ID + Status
- if ( statusRec->status == ZCL_STATUS_SUCCESS )
- {
- len++; // Attribute Data Type
- len += zclGetAttrDataLength( statusRec->dataType, statusRec->data); // Attribute Data
- }
- }
- buf = osal_mem_alloc( len );
- if ( buf != NULL )
- {
- // Load the buffer - serially
- pBuf = buf;
- for ( i = 0; i < readRspCmd->numAttr; i++ )
- {
- 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;
- zclSerializeData( statusRec->dataType, statusRec->data, pBuf );
-
- // move pass attribute data
- pBuf += zclGetAttrDataLength( statusRec->dataType, statusRec->data );
- }
- } // for loop
- status = zcl_SendCommand( srcEP, dstAddr, clusterID, ZCL_CMD_READ_RSP, FALSE,
- direction, disableDefaultRsp, 0, seqNum, len, buf );
- osal_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;
- uint8 *pBuf;
- zclWriteRec_t *statusRec;
- uint8 attrDataLen;
- uint8 dataLen = 0;
- uint8 i;
- ZStatus_t status;
-
- for ( i = 0; i < writeCmd->numAttr; i++ )
- {
- statusRec = &(writeCmd->attrList[i]);
-
- attrDataLen = zclGetAttrDataLength( statusRec->dataType, statusRec->attrData );
- dataLen += 2 + 1 + attrDataLen; // Attribute ID + Attribute Type + Attribute Data
- }
- buf = osal_mem_alloc( dataLen );
- if ( buf != NULL )
- {
- // Load the buffer - serially
- pBuf = buf;
- for ( i = 0; i < writeCmd->numAttr; i++ )
- {
- statusRec = &(writeCmd->attrList[i]);
-
- *pBuf++ = LO_UINT16( statusRec->attrID );
- *pBuf++ = HI_UINT16( statusRec->attrID );
- *pBuf++ = statusRec->dataType;
-
- zclSerializeData( statusRec->dataType, statusRec->attrData, pBuf );
-
- attrDataLen = zclGetAttrDataLength( statusRec->dataType, statusRec->attrData );
- pBuf += attrDataLen; // move pass attribute data
- }
- status = zcl_SendCommand( srcEP, dstAddr, clusterID, cmd, FALSE,
- direction, disableDefaultRsp, 0, seqNum, dataLen, buf );
- osal_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 )
- {
- uint8 dataLen;
- uint8 *buf;
- uint8 *pBuf;
- uint8 i;
- ZStatus_t status;
-
- dataLen = writeRspCmd->numAttr * ( 1 + 2 ); // status + attribute id
- buf = osal_mem_alloc( dataLen );
- if ( buf != NULL )
- {
- // Load the buffer - serially
- 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 );
- osal_mem_free( buf );
- }
- else
- status = ZMemError;
- return ( status );
- }
- #endif // ZCL_WRITE
- #ifdef ZCL_REPORT
- /*********************************************************************
- * @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;
- uint8 *pBuf;
- uint8 dataLen = 0;
- zclCfgReportRec_t *reportRec;
- uint8 reportChangeLen; // length of Reportable Change field
- uint8 i;
- ZStatus_t status;
-
- // Find out the data length
- for ( i = 0; i < cfgReportCmd->numAttr; i++ )
- {
- reportRec = &(cfgReportCmd->attrList[i]);
-
- dataLen += 1 + 2; // Direction + Attribute ID
- reportChangeLen = 0;
-
- 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 ) )
- {
- reportChangeLen = zclGetDataTypeLength( reportRec->dataType );
- dataLen += reportChangeLen;
- }
- }
- else
- {
- dataLen += 2; // Timeout Period
- }
- }
-
- buf = osal_mem_alloc( dataLen );
- if ( buf != NULL )
- {
- // Load the buffer - serially
- pBuf = buf;
- for ( i = 0; i < cfgReportCmd->numAttr; i++ )
- {
- 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 ) )
- {
- zclSerializeData( reportRec->dataType, reportRec->reportableChange, pBuf );
- reportChangeLen = zclGetDataTypeLength( reportRec->dataType );
- pBuf += reportChangeLen;
- }
- }
- 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 );
- osal_mem_free( buf );
- }
- else
- status = ZMemError;
-
- return ( status );
- }
- /*********************************************************************
- * @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 )
- {
- uint8 dataLen;
- uint8 *buf;
- uint8 *pBuf;
- uint8 i;
- ZStatus_t status;
-
- // Atrribute list (Status, Direction and Attribute ID)
- dataLen = cfgReportRspCmd->numAttr * ( 1 + 1 + 2 );
-
- buf = osal_mem_alloc( dataLen );
- if ( buf != NULL )
- {
- // Load the buffer - serially
- pBuf = buf;
- 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 );
- osal_mem_free( buf );
- }
- else
- status = ZMemError;
-
- return ( status );
- }
- /*********************************************************************
- * @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 )
- {
- uint8 dataLen;
- uint8 *buf;
- uint8 *pBuf;
- uint8 i;
- ZStatus_t status;
-
- dataLen = readReportCfgCmd->numAttr * ( 1 + 2 ); // Direction + Atrribute ID
-
- buf = osal_mem_alloc( dataLen );
- if ( buf != NULL )
- {
- // Load the buffer - serially
- pBuf = buf;
- 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 );
- osal_mem_free( buf );
- }
- else
- status = ZMemError;
-
- return ( status );
- }
- /*********************************************************************
- * @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;
- uint8 *pBuf;
- uint8 dataLen = 0;
- zclReportCfgRspRec_t *reportRspRec;
- uint8 reportChangeLen;
- uint8 i;
- ZStatus_t status;
- // Find out the data length
- for ( i = 0; i < readReportCfgRspCmd->numAttr; i++ )
- {
- 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
-
- if ( zclAnalogDataType( reportRspRec->dataType ) )
- {
- reportChangeLen = zclGetDataTypeLength( reportRspRec->dataType );
- dataLen += reportChangeLen; // Reportable Change field
- }
- }
- else
- {
- dataLen += 2; // Timeout Period
- }
- }
- }
-
- buf = osal_mem_alloc( dataLen );
- if ( buf != NULL )
- {
- // Load the buffer - serially
- pBuf = buf;
- for ( i = 0; i < readReportCfgRspCmd->numAttr; i++ )
- {
- 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 ) )
- {
- zclSerializeData( reportRspRec->dataType,
- reportRspRec->reportableChange, pBuf );
- reportChangeLen = zclGetDataTypeLength( reportRspRec->dataType );
- pBuf += reportChangeLen;
- }
- }
- 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 );
- osal_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 )
- {
- zclReport_t *reportRec;
- uint8 attrDataLen;
- uint8 dataLen = 0;
- uint8 *buf;
- uint8 *pBuf;
- uint8 i;
- ZStatus_t status;
-
- // calculate the size of the command
- for ( i = 0; i < reportCmd->numAttr; i++ )
- {
- reportRec = &(reportCmd->attrList[i]);
-
- dataLen += 2 + 1; // Attribute ID + data type
- attrDataLen = zclGetAttrDataLength( reportRec->dataType, reportRec->attrData );
- dataLen += attrDataLen; // Attribute Data
- }
-
- buf = osal_mem_alloc( dataLen );
- if ( buf != NULL )
- {
- // Load the buffer - serially
- pBuf = buf;
- for ( i = 0; i < reportCmd->numAttr; i++ )
- {
- reportRec = &(reportCmd->attrList[i]);
-
- *pBuf++ = LO_UINT16( reportRec->attrID );
- *pBuf++ = HI_UINT16( reportRec->attrID );
- *pBuf++ = reportRec->dataType;
- zclSerializeData( reportRec->dataType, reportRec->attrData, pBuf );
- attrDataLen = zclGetAttrDataLength( reportRec->dataType, reportRec->attrData );
- pBuf += attrDataLen; // move pass attribute data
- }
-
- status = zcl_SendCommand( srcEP, dstAddr, clusterID, ZCL_CMD_REPORT, FALSE,
- direction, disableDefaultRsp, 0, seqNum, dataLen, buf );
- osal_mem_free( buf );
- }
- else
- status = ZMemError;
-
- return ( status );
- }
- #endif // ZCL_REPORT
-
- /*********************************************************************
- * @fn zcl_SendDefaultRspCmd
- *
- * @brief Send a Default Response command
- *
- * @param dstAddr - destination address
- * @param clusterID - cluster ID
- * @param defaultRspCmd - default response command to be sent
- * @param direction - direction of the command
- * @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, 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, 0, seqNum, 2, buf ) );
- }
- #ifdef ZCL_DISCOVER
- /*********************************************************************
- * @fn zcl_SendDiscoverCmd
- *
- * @brief Send a Discover command
- *
- * @param dstAddr - destination address
- * @param clusterID - cluster ID
- * @param discoverCmd - discover command to be sent
- * @param direction - direction of the command
- * @param seqNum - transaction sequence number
- *
- * @return ZSuccess if OK
- */
- ZStatus_t zcl_SendDiscoverCmd( uint8 srcEP, afAddrType_t *dstAddr,
- uint16 clusterID, zclDiscoverCmd_t *discoverCmd,
- uint8 direction, uint8 disableDefaultRsp, uint8 seqNum )
- {
- uint8 dataLen = 2 + 1; // Start Attribute ID and Max Attribute IDs
- uint8 *buf;
- uint8 *pBuf;
- ZStatus_t status;
-
- buf = osal_mem_alloc( dataLen );
- if ( buf != NULL )
- {
- // Load the buffer - serially
- pBuf = buf;
- *pBuf++ = LO_UINT16(discoverCmd->startAttr);
- *pBuf++ = HI_UINT16(discoverCmd->startAttr);
- *pBuf++ = discoverCmd->maxAttrIDs;
-
- status = zcl_SendCommand( srcEP, dstAddr, clusterID, ZCL_CMD_DISCOVER, FALSE,
- direction, disableDefaultRsp, 0, seqNum, dataLen, buf );
- osal_mem_free( buf );
- }
- else
- status = ZMemError;
-
- return ( status );
- }
- /*********************************************************************
- * @fn zcl_SendDiscoverRspCmd
- *
- * @brief Send a Discover 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_SendDiscoverRspCmd( uint8 srcEP, afAddrType_t *dstAddr,
- uint16 clusterID, zclDiscoverRspCmd_t *discoverRspCmd,
- uint8 direction, uint8 disableDefaultRsp, uint8 seqNum )
- {
- uint8 dataLen = 1; // Discovery complete
- uint8 *buf;
- uint8 *pBuf;
- uint8 i;
- ZStatus_t status;
-
- // calculate the size of the command
- dataLen += discoverRspCmd->numAttr * (2 + 1); // Attribute ID and Data Type
-
- buf = osal_mem_alloc( dataLen );
- if ( buf != NULL )
- {
- // Load the buffer - serially
- pBuf = buf;
- *pBuf++ = discoverRspCmd->discComplete;
- for ( i = 0; i < discoverRspCmd->numAttr; i++ )
- {
- *pBuf++ = LO_UINT16(discoverRspCmd->attrList[i].attrID);
- *pBuf++ = HI_UINT16(discoverRspCmd->attrList[i].attrID);
- *pBuf++ = discoverRspCmd->attrList[i].dataType;
- }
-
- status = zcl_SendCommand( srcEP, dstAddr, clusterID, ZCL_CMD_DISCOVER_RSP, FALSE,
- direction, disableDefaultRsp, 0, seqNum, dataLen, buf );
- osal_mem_free( buf );
- }
- else
- status = ZMemError;
-
- return ( status );
- }
- #endif // ZCL_DISCOVER
- /*********************************************************************
- * PRIVATE FUNCTIONS
- *********************************************************************/
- /*********************************************************************
- * @fn zclProcessMessageMSG
- *
- * @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 none
- */
- static void zclProcessMessageMSG( 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;
- if ( pkt->cmd.DataLength == 0 )
- return; // Error, ignore the message
- // Initialize
- 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 -= (uint8)(inMsg.pData - pkt->cmd.Data);
- // Find the wanted endpoint
- epDesc = afFindEndPointDesc( pkt->endPoint );
- if ( epDesc == NULL )
- return; // Error, ignore the message
- if ( pkt->clusterId == ZCL_INVALID_CLUSTER_ID )
- return; // Error, ignore the message
-
- if ( zcl_DeviceOperational( pkt->endPoint, pkt->clusterId,
- inMsg.hdr.fc.type, inMsg.hdr.commandID, epDesc->simpleDesc->AppProfId ) == FALSE )
- {
- return; // 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
- if ( zcl_ProfileCmd( inMsg.hdr.fc.type ) )
- return;
- interPanMsg = TRUE;
- options = AF_TX_OPTIONS_NONE;
- }
- else
- #endif
- {
- interPanMsg = FALSE;
- options = zclGetClusterOption( pkt->endPoint, pkt->clusterId );
- }
-
- // Local and remote Security options must match except for Default Response command
- if ( !zcl_DefaultRspCmd( inMsg.hdr ) )
- {
- securityEnable = ( options & AF_EN_SECURITY ) ? TRUE : FALSE;
- if ( pkt->SecurityUse != securityEnable )
- {
- if ( UNICAST_MSG( inMsg.msg ) )
- {
- // Send a Default Response command back with no Application Link Key security
- if ( securityEnable )
- 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,
- ZCL_FRAME_SERVER_CLIENT_DIR, true, inMsg.hdr.transSeqNum );
- if ( securityEnable )
- zclSetSecurityOption( pkt->endPoint, pkt->clusterId, TRUE );
- }
-
- return; // Error, ignore the message
- }
- }
-
- // Is this a foundation type message
- if ( 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 )
- osal_mem_free( inMsg.attrCmd );
-
- if ( CMD_HAS_RSP( inMsg.hdr.commandID ) )
- return; // We're done
-
- status = ZSuccess;
- }
- else
- {
- // Unsupported message
- status = ZCL_STATUS_UNSUP_GENERAL_COMMAND;
- }
- }
- else
- {
- // Nope, must be specific to the cluster ID
- // Find the appropriate plugin
- pInPlugin = zclFindPlugin( pkt->clusterId, epDesc->simpleDesc->AppProfId );
- 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 ) )
- return; // 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,
- ZCL_FRAME_SERVER_CLIENT_DIR, true, inMsg.hdr.transSeqNum );
- }
- }
- /*********************************************************************
- * @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
- osal_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;
-
- (void)profileID; // Intentionally unreferenced parameter
- if ( clusterID != ZCL_INVALID_CLUSTER_ID )
- {
- pLoop = plugins;
- while ( pLoop != NULL )
- {
- if ( clusterID >= pLoop->startClusterID && clusterID <= pLoop->endClusterID )
- return ( pLoop );
- pLoop = pLoop->next;
- }
- }
- return ( (zclLibPlugin_t *)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
- *
- * @return TRUE if record found. FALSE, otherwise.
- */
- uint8 zclFindAttrRec( uint8 endpoint, uint16 clusterID, uint16 attrId, zclAttrRec_t *pAttr )
- {
- uint8 x;
- zclAttrRecsList *pLoop;
- pLoop = attrList;
- while ( pLoop != NULL )
- {
- if ( pLoop->endpoint == endpoint )
- {
- for ( x = 0; x < pLoop->numAttributes; x++ )
- {
- if ( pLoop->attrs[x].clusterID == clusterID && pLoop->attrs[x].attr.attrId == attrId )
- {
- *pAttr = pLoop->attrs[x];
- return ( TRUE ); // EMBEDDED RETURN
- }
- }
- }
- pLoop = pLoop->next;
- }
- return ( FALSE );
- }
- /*********************************************************************
- * @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 )
- {
- uint8 x;
- zclClusterOptionList *pLoop;
- pLoop = clusterOptionList;
- while ( pLoop != NULL )
- {
- if ( pLoop->endpoint == endpoint )
- {
- 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 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,
- uint16 *attrId, zclAttrRec_t *pAttr )
- {
- uint16 x;
- zclAttrRecsList *pLoop;
- pLoop = attrList;
- while ( pLoop != NULL )
- {
- if ( pLoop->endpoint == endpoint )
- {
- for ( x = 0; x < pLoop->numAttributes; x++ )
- {
- if ( pLoop->attrs[x].clusterID == clusterID && pLoop->attrs[x].attr.attrId >= *attrId )
- {
- *pAttr = pLoop->attrs[x];
-
- // Update attribute ID
- *attrId = pAttr->attr.attrId;
- return ( TRUE ); // EMBEDDED RETURN
- }
- }
- }
- pLoop = pLoop->next;
- }
- return ( FALSE );
- }
- #endif // ZCL_DISCOVER
- #if defined(ZCL_READ) || defined(ZCL_WRITE) || defined(ZCL_REPORT)
- /*********************************************************************
- * @fn zclSerializeData
- *
- * @brief Builds a buffer from the attribute data to sent out over
- * the air.
- *
- * @param dataType - data types defined in zcl.h
- * @param attrData - pointer to the attribute data
- * @param buf - where to put the serialized data
- *
- * @return none
- */
- static void zclSerializeData( uint8 dataType, void *attrData, uint8 *buf )
- {
- uint8 *pStr;
- 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:
- *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 = osal_buffer_uint32( buf, *((uint32*)attrData) );
- break;
-
- case ZCL_DATATYPE_UINT40:
- pStr = (uint8*)attrData;
- osal_memcpy( buf, pStr, 5 );
- break;
-
- case ZCL_DATATYPE_UINT48:
- pStr = (uint8*)attrData;
- osal_memcpy( buf, pStr, 6 );
- break;
-
- case ZCL_DATATYPE_IEEE_ADDR:
- pStr = (uint8*)attrData;
- osal_memcpy( buf, pStr, 8 );
- break;
-
- case ZCL_DATATYPE_CHAR_STR:
- case ZCL_DATATYPE_OCTET_STR:
- pStr = (uint8*)attrData;
- len = *pStr++;
- *buf++ = len;
- osal_memcpy( buf, pStr, len );
- break;
-
- case ZCL_DATATYPE_NO_DATA:
- case ZCL_DATATYPE_UNKNOWN:
- // Fall through
- default:
- break;
- }
- }
- #endif // ZCL_READ || ZCL_WRITE || ZCL_REPORT
- #ifdef ZCL_REPORT
- /*********************************************************************
- * @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_INT8:
- case ZCL_DATATYPE_INT16:
- case ZCL_DATATYPE_INT24:
- case ZCL_DATATYPE_INT32:
- 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 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)
- {
- switch ( dataType )
- {
- case ZCL_DATATYPE_UINT8:
- case ZCL_DATATYPE_INT8:
- *pData = *pBuf;
- break;
- case ZCL_DATATYPE_UINT16:
- case ZCL_DATATYPE_INT16:
- case ZCL_DATATYPE_SEMI_PREC:
- *((uint16*)pData) = BUILD_UINT16( pBuf[0], pBuf[1] );
- break;
-
- case ZCL_DATATYPE_UINT24:
- case ZCL_DATATYPE_INT24:
- *((uint32*)pData) = osal_build_uint32( pBuf, 3 );
- break;
-
- 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:
- *((uint32*)pData) = osal_build_uint32( pBuf, 4 );
- break;
-
- case ZCL_DATATYPE_DOUBLE_PREC:
- *pData = 0;
- break;
-
- default:
- break;
- }
- }
- #endif // ZCL_REPORT
- /*********************************************************************
- * @fn zclGetDataTypeLength
- *
- * @brief Return the length of the datatype in length.
- * 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:
- len = 5;
- break;
-
- case ZCL_DATATYPE_UINT48:
- len = 6;
- break;
-
- case ZCL_DATATYPE_DOUBLE_PREC:
- case ZCL_DATATYPE_IEEE_ADDR:
- len = 8;
- 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 lentgh
- */
- uint8 zclGetAttrDataLength( uint8 dataType, uint8 *pData)
- {
- uint8 dataLen = 0;
-
- 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 );
- }
- /*********************************************************************
- * @fn zclReadAttrData
- *
- * @brief Read the attribute's current value into pAttrData.
- *
- * @param pAttrData - where to put attribute data
- * @param pAttr - pointer to attribute
- *
- * @return Success
- */
- uint8 zclReadAttrData( uint8 *pAttrData, zclAttrRec_t *pAttr )
- {
- uint8 dataLen;
-
- dataLen = zclGetAttrDataLength( pAttr->attr.dataType, (uint8*)(pAttr->attr.dataPtr) );
- osal_memcpy( pAttrData, pAttr->attr.dataPtr, dataLen );
-
- return ( ZCL_STATUS_SUCCESS );
- }
- #ifdef ZCL_WRITE
- /*********************************************************************
- * @fn zclWriteAttrData
- *
- * @brief Write the received data.
- *
- * @param pAttr - where to write data to
- * @param pWriteRec - data to be written
- *
- * @return Successful if data was written
- */
- static uint8 zclWriteAttrData( zclAttrRec_t *pAttr, zclWriteRec_t *pWriteRec )
- {
- uint8 len;
- if ( zcl_AccessCtrlWrite( pAttr->attr.accessControl ) )
- {
- if ( zcl_ValidateAttrDataCB && !zcl_ValidateAttrDataCB( pAttr, pWriteRec ) )
- return ( ZCL_STATUS_INVALID_VALUE );
-
- len = zclGetAttrDataLength( pAttr->attr.dataType, pWriteRec->attrData );
- osal_memcpy( pAttr->attr.dataPtr, pWriteRec->attrData, len );
- return ( ZCL_STATUS_SUCCESS );
- }
-
- return ( ZCL_STATUS_READ_ONLY );
- }
- #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 *)osal_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;
- zclReadRspStatus_t *statusRec;
- uint8 *pBuf = pCmd->pData;
- uint8 *dataPtr;
- uint8 numAttr = 0;
- uint8 hdrLen;
- uint8 dataLen = 0;
- uint8 attrDataLen;
- uint8 dataType;
- uint8 status;
- uint8 i;
-
- // find out the number of attributes and the length of attribute data
- while ( pBuf < ( pCmd->pData + pCmd->dataLen ) )
- {
- numAttr++;
- pBuf += 2; // move pass attribute id
-
- status = *pBuf++;
- if ( status == ZCL_STATUS_SUCCESS )
- {
- 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 *)osal_mem_alloc( hdrLen + dataLen );
- if ( readRspCmd != NULL )
- {
- pBuf = pCmd->pData;
- dataPtr = (uint8 *)( (uint8 *)readRspCmd + hdrLen );
-
- readRspCmd->numAttr = numAttr;
- for ( i = 0; i < numAttr; i++ )
- {
- 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 );
- osal_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;
- zclWriteRec_t *statusRec;
- uint8 *pBuf = pCmd->pData;
- uint8 attrDataLen;
- uint8 *dataPtr;
- uint8 numAttr = 0;
- uint8 hdrLen;
- uint8 dataLen = 0;
- uint8 dataType;
- uint8 i;
- // find out the number of attributes and the length of attribute data
- while ( pBuf < ( pCmd->pData + pCmd->dataLen ) )
- {
- 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 *)osal_mem_alloc( hdrLen + dataLen );
- if ( writeCmd != NULL )
- {
- pBuf = pCmd->pData;
- dataPtr = (uint8 *)( (uint8 *)writeCmd + hdrLen );
- writeCmd->numAttr = numAttr;
- for ( i = 0; i < numAttr; i++ )
- {
- statusRec = &(writeCmd->attrList[i]);
-
- statusRec->attrID = BUILD_UINT16( pBuf[0], pBuf[1] );
- pBuf += 2;
- statusRec->dataType = *pBuf++;
- attrDataLen = zclGetAttrDataLength( statusRec->dataType, pBuf );
- osal_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 *)osal_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_REPORT
- /*********************************************************************
- * @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;
- zclCfgReportRec_t *reportRec;
- uint8 *pBuf = pCmd->pData;
- uint8 *dataPtr;
- uint8 numAttr = 0;
- uint8 direction;
- uint8 dataType;
- uint8 hdrLen;
- uint8 dataLen = 0;
- uint8 reportChangeLen; // length of Reportable Change field
- uint8 i;
-
- // Calculate the length of the Request command
- while ( pBuf < ( pCmd->pData + pCmd->dataLen ) )
- {
- 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 += 2; // move pass the Timeout Period
- }
- } // while loop
- hdrLen = sizeof( zclCfgReportCmd_t ) + ( numAttr * sizeof( zclCfgReportRec_t ) );
-
- cfgReportCmd = (zclCfgReportCmd_t *)osal_mem_alloc( hdrLen + dataLen );
- if ( cfgReportCmd != NULL )
- {
- pBuf = pCmd->pData;
- dataPtr = (uint8 *)( (uint8 *)cfgReportCmd + hdrLen );
-
- cfgReportCmd->numAttr = numAttr;
- for ( i = 0; i < numAttr; i++ )
- {
- reportRec = &(cfgReportCmd->attrList[i]);
-
- osal_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 );
- }
- /*********************************************************************
- * @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;
- uint8 i;
-
- numAttr = pCmd->dataLen / ( 1 + 1 + 2 ); // Status + Direction + Attribute ID
-
- cfgReportRspCmd = (zclCfgReportRspCmd_t *)osal_mem_alloc( sizeof( zclCfgReportRspCmd_t )
- + ( numAttr * sizeof( zclCfgReportStatus_t ) ) );
- if ( cfgReportRspCmd != NULL )
- {
- 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 );
- }
- /*********************************************************************
- * @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;
- uint8 i;
-
- numAttr = pCmd->dataLen / ( 1 + 2 ); // Direction + Attribute ID
-
- readReportCfgCmd = (zclReadReportCfgCmd_t *)osal_mem_alloc( sizeof( zclReadReportCfgCmd_t )
- + ( numAttr * sizeof( zclReadReportCfgRec_t ) ) );
- if ( readReportCfgCmd != NULL )
- {
- 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 );
- }
- /*********************************************************************
- * @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;
- zclReportCfgRspRec_t *reportRspRec;
- uint8 reportChangeLen;
- uint8 *pBuf = pCmd->pData;
- uint8 *dataPtr;
- uint8 numAttr = 0;
- uint8 hdrLen;
- uint8 dataLen = 0;
- uint8 status;
- uint8 direction;
- uint8 dataType;
- uint8 i;
-
- // Calculate the length of the response command
- while ( pBuf < ( pCmd->pData + pCmd->dataLen ) )
- {
- numAttr++;
-
- status = *pBuf++;
- direction = *pBuf++;
- pBuf += 2; // move pass the attribute ID
-
- if ( status == ZCL_STATUS_SUCCESS )
- {
- 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 += 2; // move pass the Timeout field
- }
- }
- } // while loop
-
- hdrLen = sizeof( zclReadReportCfgRspCmd_t ) + ( numAttr * sizeof( zclReportCfgRspRec_t ) );
-
- readReportCfgRspCmd = (zclReadReportCfgRspCmd_t *)osal_mem_alloc( hdrLen + dataLen );
- if ( readReportCfgRspCmd != NULL )
- {
- pBuf = pCmd->pData;
- dataPtr = (uint8 *)( (uint8 *)readReportCfgRspCmd + hdrLen );
-
- readReportCfgRspCmd->numAttr = numAttr;
- for ( i = 0; i < numAttr; i++ )
- {
- 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 );
- }
- /*********************************************************************
- * @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;
- zclReport_t *reportRec;
- uint8 *pBuf = pCmd->pData;
- uint8 attrDataLen;
- uint8 *dataPtr;
- uint8 numAttr = 0;
- uint8 hdrLen;
- uint8 dataLen = 0;
- uint8 dataType;
- uint8 i;
- // find out the number of attributes and the length of attribute data
- while ( pBuf < ( pCmd->pData + pCmd->dataLen ) )
- {
- 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 *)osal_mem_alloc( hdrLen + dataLen );
- if (reportCmd != NULL )
- {
- pBuf = pCmd->pData;
- dataPtr = (uint8 *)( (uint8 *)reportCmd + hdrLen );
-
- reportCmd->numAttr = numAttr;
- for ( i = 0; i < numAttr; i++ )
- {
- reportRec = &(reportCmd->attrList[i]);
-
- reportRec->attrID = BUILD_UINT16( pBuf[0], pBuf[1] );
- pBuf += 2;
- reportRec->dataType = *pBuf++;
- attrDataLen = zclGetAttrDataLength( reportRec->dataType, pBuf );
- osal_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 // ZCL_REPORT
- /*********************************************************************
- * @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 *)osal_mem_alloc( sizeof ( zclDefaultRspCmd_t ) );
- if ( defaultRspCmd != NULL )
- {
- defaultRspCmd->commandID = *pBuf++;
- defaultRspCmd->statusCode = *pBuf;
- }
- return ( (void *)defaultRspCmd );
- }
- #ifdef ZCL_DISCOVER
- /*********************************************************************
- * @fn zclParseInDiscCmd
- *
- * @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 *zclParseInDiscCmd( zclParseCmd_t *pCmd )
- {
- zclDiscoverCmd_t *discoverCmd;
- uint8 *pBuf = pCmd->pData;
- discoverCmd = (zclDiscoverCmd_t *)osal_mem_alloc( sizeof ( zclDiscoverCmd_t ) );
- if ( discoverCmd != NULL )
- {
- discoverCmd->startAttr = BUILD_UINT16( pBuf[0], pBuf[1] );
- pBuf += 2;
- discoverCmd->maxAttrIDs = *pBuf;
- }
- return ( (void *)discoverCmd );
- }
- /*********************************************************************
- * @fn zclParseInDiscRspCmd
- *
- * @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 *zclParseInDiscRspCmd( zclParseCmd_t *pCmd )
- {
- zclDiscoverRspCmd_t *discoverRspCmd;
- uint8 *pBuf = pCmd->pData;
- uint8 numAttr = ZCLDISCRSPCMD_DATALEN(pCmd->dataLen) / ( 2 + 1 ); // Attr ID + Data Type
- uint8 i;
- discoverRspCmd = (zclDiscoverRspCmd_t *)osal_mem_alloc( sizeof ( zclDiscoverRspCmd_t )
- + ( numAttr * sizeof(zclDiscoverInfo_t) ) );
- if ( discoverRspCmd != NULL )
- {
- discoverRspCmd->discComplete = *pBuf++;
- discoverRspCmd->numAttr = numAttr;
-
- for ( i = 0; i < numAttr; i++ )
- {
- discoverRspCmd->attrList[i].attrID = BUILD_UINT16( pBuf[0], pBuf[1] );
- pBuf += 2;
- discoverRspCmd->attrList[i].dataType = *pBuf++;;
- }
- }
- return ( (void *)discoverRspCmd );
- }
- #endif // ZCL_DISCOVER
- #ifdef ZCL_READ
- /*********************************************************************
- * @fn zclProcessInReadCmd
- *
- * @brief Process the "Profile" Read Command
- *
- * @param pInMsg - incoming message to process
- *
- * @return TRUE if command processed. FALSE, otherwise.
- */
- static uint8 zclProcessInReadCmd( zclIncoming_t *pInMsg )
- {
- zclReadCmd_t *readCmd;
- zclReadRspCmd_t *readRspCmd;
- zclReadRspStatus_t *statusRec;
- zclAttrRec_t attrRec;
- uint8 len;
- uint8 i;
-
- readCmd = (zclReadCmd_t *)pInMsg->attrCmd;
-
- // calculate the length of the response status record
- len = sizeof( zclReadRspCmd_t ) + (readCmd->numAttr * sizeof( zclReadRspStatus_t ));
-
- readRspCmd = osal_mem_alloc( len );
- if ( readRspCmd == NULL )
- return FALSE; // EMBEDDED RETURN
- readRspCmd->numAttr = readCmd->numAttr;
- for (i = 0; i < readCmd->numAttr; i++)
- {
- statusRec = &(readRspCmd->attrList[i]);
-
- statusRec->attrID = readCmd->attrID[i];
-
- if ( zclFindAttrRec( pInMsg->msg->endPoint, pInMsg->msg->clusterId, readCmd->attrID[i], &attrRec ) )
- {
- statusRec->data = attrRec.attr.dataPtr;
- statusRec->status = ZCL_STATUS_SUCCESS;
- statusRec->dataType = attrRec.attr.dataType;
- }
- else
- {
- statusRec->status = ZCL_STATUS_UNSUPPORTED_ATTRIBUTE;
- }
- }
-
- // Build and send Read Response command
- zcl_SendReadRsp( pInMsg->msg->endPoint, &(pInMsg->msg->srcAddr), pInMsg->msg->clusterId,
- readRspCmd, ZCL_FRAME_SERVER_CLIENT_DIR,
- true, pInMsg->hdr.transSeqNum );
- osal_mem_free( readRspCmd );
-
- return TRUE;
- }
- #endif // ZCL_READ
- #ifdef ZCL_WRITE
- /*********************************************************************
- * @fn processInWriteCmd
- *
- * @brief Process the "Profile" Write and Write No Response Commands
- *
- * @param pInMsg - incoming message to process
- *
- * @return TRUE if command processed. FALSE, otherwise.
- */
- static uint8 zclProcessInWriteCmd( zclIncoming_t *pInMsg )
- {
- zclWriteCmd_t *writeCmd;
- zclWriteRec_t *statusRec;
- zclWriteRspCmd_t *writeRspCmd;
- zclAttrRec_t attrRec;
- uint8 sendRsp = FALSE;
- uint8 status;
- uint8 i, j = 0;
- writeCmd = (zclWriteCmd_t *)pInMsg->attrCmd;
- if ( pInMsg->hdr.commandID == ZCL_CMD_WRITE )
- {
- // We need to send a response back - allocate space for it
- writeRspCmd = (zclWriteRspCmd_t *)osal_mem_alloc( sizeof( zclWriteRspCmd_t )
- + sizeof( zclWriteRspStatus_t ) * writeCmd->numAttr );
- if ( writeRspCmd == NULL )
- return FALSE; // EMBEDDED RETURN
- sendRsp = TRUE;
- }
-
- for (i = 0; i < writeCmd->numAttr; i++)
- {
- statusRec = &(writeCmd->attrList[i]);
-
- if ( zclFindAttrRec( pInMsg->msg->endPoint, pInMsg->msg->clusterId, statusRec->attrID, &attrRec ) )
- {
- if ( statusRec->dataType == attrRec.attr.dataType )
- {
- status = zclWriteAttrData( &attrRec, statusRec );
- // If successful, a write attribute status record shall NOT be generated
- if ( sendRsp && status != ZCL_STATUS_SUCCESS )
- {
- // Attribute is read only - move on to the next write attribute record
- writeRspCmd->attrList[j].status = status;
- writeRspCmd->attrList[j++].attrID = statusRec->attrID;
- }
- }
- else
- {
- // Attribute data type is incorrect - move on to the next write attribute record
- if ( sendRsp )
- {
- writeRspCmd->attrList[j].status = ZCL_STATUS_INVALID_DATA_TYPE;
- writeRspCmd->attrList[j++].attrID = statusRec->attrID;
- }
- }
- }
- else
- {
- // Attribute is not supported - move on to the next write attribute record
- if ( sendRsp )
- {
- writeRspCmd->attrList[j].status = ZCL_STATUS_UNSUPPORTED_ATTRIBUTE;
- writeRspCmd->attrList[j++].attrID = statusRec->attrID;
- }
- }
- } // for loop
- if ( sendRsp )
- {
- writeRspCmd->numAttr = j;
- if ( writeRspCmd->numAttr == 0 )
- {
- // Since all records were written successful, include a single status record
- // in the resonse command with the status field set to SUCCESS and the
- // attribute ID field omitted.
- writeRspCmd->attrList[0].status = ZCL_STATUS_SUCCESS;
- writeRspCmd->numAttr = 1;
- }
-
- zcl_SendWriteRsp( pInMsg->msg->endPoint, &(pInMsg->msg->srcAddr),
- pInMsg->msg->clusterId, writeRspCmd, ZCL_FRAME_SERVER_CLIENT_DIR,
- true, pInMsg->hdr.transSeqNum );
- osal_mem_free( writeRspCmd );
- }
-
- return TRUE;
- }
- /*********************************************************************
- * @fn zclRevertWriteUndividedCmd
- *
- * @brief Revert the "Profile" Write Undevided Command
- *
- * @param pInMsg - incoming message to process
- * @param curWriteRec - old data
- * @param numAttr - number of attributes to be reverted
- *
- * @return none
- */
- static void zclRevertWriteUndividedCmd( zclIncoming_t *pInMsg,
- zclWriteRec_t *curWriteRec, uint16 numAttr )
- {
- zclWriteRec_t *statusRec;
- zclAttrRec_t attrRec;
- uint8 dataLen;
- uint8 i;
- statusRec = curWriteRec;
- for (i = 0; i < numAttr; i++)
- {
- statusRec = &(curWriteRec[i]);
-
- if ( !zclFindAttrRec( pInMsg->msg->endPoint, pInMsg->msg->clusterId, statusRec->attrID, &attrRec ) )
- break; // should never happen
-
- // Just copy the old data back - no need to validate the data
- dataLen = zclGetAttrDataLength( attrRec.attr.dataType, statusRec->attrData );
- osal_memcpy( attrRec.attr.dataPtr, statusRec->attrData, dataLen );
- } // for loop
- }
- /*********************************************************************
- * @fn zclProcessInWriteUndividedCmd
- *
- * @brief Process the "Profile" Write Undivided Command
- *
- * @param pInMsg - incoming message to process
- *
- * @return TRUE if command processed. FALSE, otherwise.
- */
- static uint8 zclProcessInWriteUndividedCmd( zclIncoming_t *pInMsg )
- {
- zclWriteCmd_t *writeCmd;
- zclWriteRec_t *statusRec;
- zclWriteRec_t *curWriteRec;
- zclWriteRec_t *curStatusRec;
- zclWriteRspCmd_t *writeRspCmd;
- zclAttrRec_t attrRec;
- uint8 *curDataPtr;
- uint8 hdrLen;
- uint8 dataLen;
- uint8 curLen = 0;
- uint8 status;
- uint8 i, j = 0;
- writeCmd = (zclWriteCmd_t *)pInMsg->attrCmd;
-
- // Allocate space for Write Response Command
- writeRspCmd = (zclWriteRspCmd_t *)osal_mem_alloc( sizeof( zclWriteRspCmd_t )
- + sizeof( zclWriteRspStatus_t )* writeCmd->numAttr );
- if ( writeRspCmd == NULL )
- return FALSE; // EMBEDDED RETURN
-
- // If any attribute cannot be written, no attribute values are changed. Hence,
- // make sure all the attributes are supported and writable
- for (i = 0; i < writeCmd->numAttr; i++)
- {
- statusRec = &(writeCmd->attrList[i]);
-
- if ( !zclFindAttrRec( pInMsg->msg->endPoint, pInMsg->msg->clusterId, statusRec->attrID, &attrRec ) )
- {
- // Attribute is not supported - stop here
- writeRspCmd->attrList[j].status = ZCL_STATUS_UNSUPPORTED_ATTRIBUTE;
- writeRspCmd->attrList[j++].attrID = statusRec->attrID;
- break;
- }
-
- if ( statusRec->dataType != attrRec.attr.dataType )
- {
- // Attribute data type is incorrect - stope here
- writeRspCmd->attrList[j].status = ZCL_STATUS_INVALID_DATA_TYPE;
- writeRspCmd->attrList[j++].attrID = statusRec->attrID;
- break;
- }
-
- if ( !zcl_AccessCtrlWrite( attrRec.attr.accessControl ) )
- {
- // Attribute is not writable - stop here
- writeRspCmd->attrList[j].status = ZCL_STATUS_READ_ONLY;
- writeRspCmd->attrList[j++].attrID = statusRec->attrID;
- break;
- }
-
- dataLen = zclGetAttrDataLength( statusRec->dataType, statusRec->attrData );
-
- // add padding if needed
- if ( PADDING_NEEDED( dataLen ) )
- dataLen++;
- curLen += dataLen;
- } // for loop
-
- writeRspCmd->numAttr = j;
- if ( writeRspCmd->numAttr == 0 ) // All attributes can be written
- {
- // calculate the length of the current data header
- hdrLen = j * sizeof( zclWriteRec_t );
-
- // Allocate space to keep a copy of the current data
- curWriteRec = (zclWriteRec_t *) osal_mem_alloc( hdrLen + curLen );
- if ( curWriteRec == NULL )
- {
- osal_mem_free(writeRspCmd );
- return FALSE; // EMBEDDED RETURN
- }
- curDataPtr = (uint8 *)((uint8 *)curWriteRec + hdrLen);
-
- // Write the new data over
- for (i = 0; i < writeCmd->numAttr; i++)
- {
- statusRec = &(writeCmd->attrList[i]);
- curStatusRec = &(curWriteRec[i]);
-
- if ( !zclFindAttrRec( pInMsg->msg->endPoint, pInMsg->msg->clusterId, statusRec->attrID, &attrRec ) )
- break; // should never happen
- // Keep a copy of the current data before before writing the new data over
- curStatusRec->attrID = statusRec->attrID;
- zclReadAttrData( curDataPtr, &attrRec );
- curStatusRec->attrData = curDataPtr;
-
- status = zclWriteAttrData( &attrRec, statusRec );
-
- // If successful, a write attribute status record shall NOT be generated
- if ( status != ZCL_STATUS_SUCCESS )
- {
- writeRspCmd->attrList[j].status = status;
- writeRspCmd->attrList[j++].attrID = statusRec->attrID;
-
- // Since this write failed, we need to revert all the pervious writes
- zclRevertWriteUndividedCmd( pInMsg, curWriteRec, i);
- break;
- }
-
- dataLen = zclGetAttrDataLength( statusRec->dataType, statusRec->attrData );
-
- // add padding if needed
- if ( PADDING_NEEDED( dataLen ) )
- dataLen++;
- curDataPtr += dataLen;
- } // for loop
-
- writeRspCmd->numAttr = j;
- if ( writeRspCmd->numAttr == 0 )
- {
- // Since all records were written successful, include a single status record
- // in the resonse command with the status field set to SUCCESS and the
- // attribute ID field omitted.
- writeRspCmd->attrList[0].status = ZCL_STATUS_SUCCESS;
- writeRspCmd->numAttr = 1;
- }
- osal_mem_free( curWriteRec );
- }
-
- zcl_SendWriteRsp( pInMsg->msg->endPoint, &(pInMsg->msg->srcAddr),
- pInMsg->msg->clusterId, writeRspCmd, ZCL_FRAME_SERVER_CLIENT_DIR,
- true, pInMsg->hdr.transSeqNum );
- osal_mem_free( writeRspCmd );
-
- return TRUE;
- }
- #endif // ZCL_WRITE
- #ifdef ZCL_DISCOVER
- /*********************************************************************
- * @fn zclProcessInDiscCmd
- *
- * @brief Process the "Profile" Discover Command
- *
- * @param pInMsg - incoming message to process
- *
- * @return TRUE if command processed. FALSE, otherwise.
- */
- static uint8 zclProcessInDiscCmd( zclIncoming_t *pInMsg )
- {
- zclDiscoverCmd_t *discoverCmd;
- zclDiscoverRspCmd_t *discoverRspCmd;
- uint8 discComplete = TRUE;
- zclAttrRec_t attrRec;
- uint16 attrID;
- uint8 i;
-
- discoverCmd = (zclDiscoverCmd_t *)pInMsg->attrCmd;
-
- // Find out the number of attributes supported within the specified range
- for ( i = 0, attrID = discoverCmd->startAttr; i < discoverCmd->maxAttrIDs; i++, attrID++ )
- {
- if ( !zclFindNextAttrRec( pInMsg->msg->endPoint, pInMsg->msg->clusterId, &attrID, &attrRec ) )
- break;
- }
-
- // Allocate space for the response command
- discoverRspCmd = (zclDiscoverRspCmd_t *)osal_mem_alloc( sizeof (zclDiscoverRspCmd_t)
- + sizeof ( zclDiscoverInfo_t ) * i );
- if ( discoverRspCmd == NULL )
- return FALSE; // EMEDDED RETURN
-
- discoverRspCmd->numAttr = i;
- if ( discoverRspCmd->numAttr != 0 )
- {
- for ( i = 0, attrID = discoverCmd->startAttr; i < discoverRspCmd->numAttr; i++, attrID++ )
- {
- if ( !zclFindNextAttrRec( pInMsg->msg->endPoint, pInMsg->msg->clusterId, &attrID, &attrRec ) )
- break; // Attribute not supported
-
- discoverRspCmd->attrList[i].attrID = attrRec.attr.attrId;
- discoverRspCmd->attrList[i].dataType = attrRec.attr.dataType;
- }
-
- // Are there more attributes to be discovered?
- if ( zclFindNextAttrRec( pInMsg->msg->endPoint, pInMsg->msg->clusterId, &attrID, &attrRec ) )
- discComplete = FALSE;
- }
-
- discoverRspCmd->discComplete = discComplete;
- zcl_SendDiscoverRspCmd( pInMsg->msg->endPoint, &pInMsg->msg->srcAddr,
- pInMsg->msg->clusterId, discoverRspCmd, ZCL_FRAME_SERVER_CLIENT_DIR,
- true, pInMsg->hdr.transSeqNum );
- osal_mem_free( discoverRspCmd );
-
- return TRUE;
- }
- #endif // ZCL_DISCOVER
- /*********************************************************************
- * @fn zclSendMsg
- *
- * @brief Send an incoming message to the Application
- *
- * @param pInMsg - incoming message to process
- *
- * @return TRUE
- */
- static uint8 zclSendMsg( zclIncoming_t *pInMsg )
- {
- zclIncomingMsg_t *pCmd;
-
- if ( zcl_RegisteredMsgTaskID == 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->attrCmd = pInMsg->attrCmd;
-
- // Application will free the attrCmd buffer
- pInMsg->attrCmd = NULL;
-
- /* send message through task message */
- osal_msg_send( zcl_RegisteredMsgTaskID, (uint8 *)pCmd );
- }
-
- return ( TRUE );
- }
- /*********************************************************************
- *********************************************************************/
|