zmac_cb.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  1. /**************************************************************************************************
  2. Filename: zmac_cb.c
  3. Revised: $Date: 2012-03-08 17:10:16 -0800 (Thu, 08 Mar 2012) $
  4. Revision: $Revision: 29685 $
  5. Description: This file contains the NWK functions that the ZMAC calls
  6. Copyright 2005-2012 Texas Instruments Incorporated. All rights reserved.
  7. IMPORTANT: Your use of this Software is limited to those specific rights
  8. granted under the terms of a software license agreement between the user
  9. who downloaded the software, his/her employer (which must be your employer)
  10. and Texas Instruments Incorporated (the "License"). You may not use this
  11. Software unless you agree to abide by the terms of the License. The License
  12. limits your use, and you acknowledge, that the Software may not be modified,
  13. copied or distributed unless embedded on a Texas Instruments microcontroller
  14. or used solely and exclusively in conjunction with a Texas Instruments radio
  15. frequency transceiver, which is integrated into your product. Other than for
  16. the foregoing purpose, you may not use, reproduce, copy, prepare derivative
  17. works of, modify, distribute, perform, display or sell this Software and/or
  18. its documentation for any purpose.
  19. YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
  20. PROVIDED “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
  21. INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
  22. NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
  23. TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,
  24. NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
  25. LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
  26. INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
  27. OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
  28. OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
  29. (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
  30. Should you have any questions regarding your right to use this Software,
  31. contact Texas Instruments Incorporated at www.TI.com.
  32. **************************************************************************************************/
  33. /********************************************************************************************************
  34. * INCLUDES
  35. ********************************************************************************************************/
  36. #include "ZComDef.h"
  37. #include "OSAL.h"
  38. #include "ZMAC.h"
  39. #include "MT_MAC.h"
  40. #include "hal_mcu.h"
  41. #if !defined NONWK
  42. #include "nwk.h"
  43. #include "nwk_bufs.h"
  44. #include "ZGlobals.h"
  45. #endif
  46. #if defined( MACSIM )
  47. #include "mac_sim.h"
  48. #endif
  49. #include "mac_security.h"
  50. #include "mac_main.h"
  51. extern void *ZMac_ScanBuf;
  52. /********************************************************************************************************
  53. * CONSTANTS
  54. ********************************************************************************************************/
  55. #if !defined NONWK
  56. /* Lookup table for size of structures. Must match with the order of MAC callback events */
  57. const uint8 CODE zmacCBSizeTable [] = {
  58. 0,
  59. sizeof(ZMacAssociateInd_t), // MAC_MLME_ASSOCIATE_IND 1 Associate indication
  60. sizeof(ZMacAssociateCnf_t), // MAC_MLME_ASSOCIATE_CNF 2 Associate confirm
  61. 0, // MAC_MLME_DISASSOCIATE_IND 3 Disassociate indication
  62. 0, // MAC_MLME_DISASSOCIATE_CNF 4 Disassociate confirm
  63. sizeof(macMlmeBeaconNotifyInd_t), // MAC_MLME_BEACON_NOTIFY_IND 5 con notify indication
  64. sizeof(ZMacOrphanInd_t), // MAC_MLME_ORPHAN_IND 6 Orphan indication
  65. sizeof(ZMacScanCnf_t), // MAC_MLME_SCAN_CNF 7 Scan confirm
  66. sizeof(ZMacStartCnf_t), // MAC_MLME_START_CNF 8 Start confirm
  67. 0, // MAC_MLME_SYNC_LOSS_IND 9 Sync loss indication
  68. sizeof(ZMacPollCnf_t), // MAC_MLME_POLL_CNF 10 Poll confirm
  69. sizeof(ZMacCommStatusInd_t), // MAC_MLME_COMM_STATUS_IND 11 Comm status indication
  70. sizeof(ZMacDataCnf_t), // MAC_MCPS_DATA_CNF 12 Data confirm
  71. sizeof(macMcpsDataInd_t), // MAC_MCPS_DATA_IND 13 Data indication
  72. 0, // MAC_MCPS_PURGE_CNF 14 Purge confirm
  73. 0, // MAC_PWR_ON_CNF 15 Power on confirm
  74. sizeof(ZMacPollInd_t) // MAC_MLME_POLL_IND 16 Poll indication
  75. };
  76. #endif /* !defined NONWK */
  77. /********************************************************************************************************
  78. * LOCALS
  79. ********************************************************************************************************/
  80. /* LQI Adjustment Mode */
  81. static ZMacLqiAdjust_t lqiAdjMode = LQI_ADJ_OFF;
  82. #if !defined NONWK
  83. /* LQI Adjustment Function */
  84. static void ZMacLqiAdjust( uint8 corr, uint8* lqi );
  85. #endif
  86. /*********************************************************************
  87. * ZMAC Function Pointers
  88. */
  89. /*
  90. * ZMac Application callback function. This function will be called
  91. * for every MAC message that is received over-the-air or generated
  92. * locally by MAC for the application.
  93. *
  94. * The callback function should return TRUE if it has handled the
  95. * MAC message and no further action should be taken with it. It
  96. * should return FALSE if it has not handled the MAC message and
  97. * normal processing should take place.
  98. *
  99. * NOTE: The processing in this function should be kept to the
  100. * minimum.
  101. */
  102. uint8 (*pZMac_AppCallback)( uint8 *msgPtr ) = (void*)NULL;
  103. /*********************************************************************
  104. * ZMAC Functions
  105. */
  106. /**************************************************************************************************
  107. * @fn MAC_CbackEvent()
  108. *
  109. * @brief convert MAC data confirm and indication to ZMac and send to NWK
  110. *
  111. * @param pData - pointer to macCbackEvent_t
  112. *
  113. * @return none
  114. *************************************************************************************************/
  115. void MAC_CbackEvent(macCbackEvent_t *pData)
  116. #ifndef MT_MAC_CB_FUNC
  117. {
  118. #if !defined NONWK
  119. uint8 event = pData->hdr.event;
  120. uint16 tmp = zmacCBSizeTable[event];
  121. macCbackEvent_t *msgPtr;
  122. /* If the Network layer will handle a new MAC callback, a non-zero value must be entered in the
  123. * corresponding location in the zmacCBSizeTable[] - thus the table acts as "should handle"?
  124. */
  125. if (tmp == 0)
  126. {
  127. return;
  128. }
  129. // MAC_MCPS_DATA_IND is very special - it is the only event where the MAC does not free *pData.
  130. if ( event == MAC_MCPS_DATA_IND )
  131. {
  132. MAC_MlmeGetReq( MAC_SHORT_ADDRESS, &tmp );
  133. if ((tmp == INVALID_NODE_ADDR) || (tmp == NWK_BROADCAST_SHORTADDR_DEVALL) ||
  134. (pData->dataInd.msdu.len == 0))
  135. {
  136. mac_msg_deallocate( (uint8 **)&pData );
  137. return;
  138. }
  139. msgPtr = pData;
  140. }
  141. else
  142. {
  143. if (event == MAC_MLME_BEACON_NOTIFY_IND )
  144. {
  145. tmp += sizeof(macPanDesc_t) + pData->beaconNotifyInd.sduLength;
  146. }
  147. else if (event == MAC_MLME_SCAN_CNF)
  148. {
  149. if (pData->scanCnf.scanType == ZMAC_ED_SCAN)
  150. {
  151. tmp += ZMAC_ED_SCAN_MAXCHANNELS;
  152. }
  153. else
  154. {
  155. tmp += sizeof( ZMacPanDesc_t ) * pData->scanCnf.resultListSize;
  156. }
  157. }
  158. if ( !(msgPtr = (macCbackEvent_t *)osal_msg_allocate(tmp)) )
  159. {
  160. // Not enough memory. If data confirm - try again
  161. if ((event == MAC_MCPS_DATA_CNF) && (pData->dataCnf.pDataReq != NULL))
  162. {
  163. halIntState_t intState;
  164. // This is not normally deallocated here because the pZMac_AppCallback()
  165. // application may need it.
  166. HAL_ENTER_CRITICAL_SECTION( intState ); // Hold off interrupts.
  167. mac_msg_deallocate( (uint8**)&(pData->dataCnf.pDataReq) );
  168. if ( !(msgPtr = (macCbackEvent_t *)osal_msg_allocate(tmp)) )
  169. {
  170. // Still no allocation, something is wrong
  171. HAL_EXIT_CRITICAL_SECTION( intState ); // Re-enable interrupts.
  172. return;
  173. }
  174. HAL_EXIT_CRITICAL_SECTION( intState ); // Re-enable interrupts.
  175. }
  176. else
  177. {
  178. // This message is dropped
  179. return;
  180. }
  181. }
  182. osal_memcpy(msgPtr, pData, zmacCBSizeTable[event]);
  183. }
  184. if ( event == MAC_MLME_BEACON_NOTIFY_IND )
  185. {
  186. macMlmeBeaconNotifyInd_t *pBeacon = (macMlmeBeaconNotifyInd_t*)msgPtr;
  187. osal_memcpy(pBeacon+1, pBeacon->pPanDesc, sizeof(macPanDesc_t));
  188. pBeacon->pPanDesc = (macPanDesc_t *)(pBeacon+1);
  189. osal_memcpy(pBeacon->pPanDesc+1, pBeacon->pSdu, pBeacon->sduLength);
  190. pBeacon->pSdu = (uint8 *)(pBeacon->pPanDesc+1);
  191. }
  192. else if (event == MAC_MLME_SCAN_CNF)
  193. {
  194. macMlmeScanCnf_t *pScan = (macMlmeScanCnf_t*)msgPtr;
  195. if (ZMac_ScanBuf != NULL)
  196. {
  197. void *pTmp = ZMac_ScanBuf;
  198. ZMac_ScanBuf = NULL;
  199. if (pScan->scanType == ZMAC_ED_SCAN)
  200. {
  201. pScan->result.pEnergyDetect = (uint8*) (pScan + 1);
  202. osal_memcpy(pScan->result.pEnergyDetect, pTmp, ZMAC_ED_SCAN_MAXCHANNELS);
  203. }
  204. else
  205. {
  206. pScan->result.pPanDescriptor = (macPanDesc_t*) (pScan + 1);
  207. osal_memcpy(pScan + 1, pTmp, sizeof( ZMacPanDesc_t ) * pScan->resultListSize);
  208. }
  209. osal_mem_free(pTmp);
  210. }
  211. }
  212. if ( ( pZMac_AppCallback == NULL ) || ( pZMac_AppCallback( (uint8 *)msgPtr ) == FALSE ) )
  213. {
  214. // Filter out non-zigbee packets
  215. if ( event == MAC_MCPS_DATA_IND )
  216. {
  217. uint8 fcFrameType = (pData->dataInd.msdu.p[0] & 0x03);
  218. uint8 fcProtoVer = ((pData->dataInd.msdu.p[0] >> 2) & 0x0F);
  219. uint8 fcReserve = (pData->dataInd.msdu.p[1] & 0xE0);
  220. if ( (fcFrameType > 0x01) || (fcProtoVer != _NIB.nwkProtocolVersion) || (fcReserve != 0)
  221. || (pData->dataInd.mac.srcAddr.addrMode != SADDR_MODE_SHORT) )
  222. {
  223. // Drop the message
  224. mac_msg_deallocate( (uint8 **)&pData );
  225. return;
  226. }
  227. else
  228. {
  229. macDataInd_t *pInd = &msgPtr->dataInd.mac;
  230. // See if LQI needs adjustment due to frame correlation
  231. ZMacLqiAdjust( pInd->correlation, &pInd->mpduLinkQuality );
  232. // Look for broadcast message that has a radius of greater 1
  233. if ( (pData->dataInd.mac.dstAddr.addr.shortAddr == 0xFFFF)
  234. && (pData->dataInd.msdu.p[6] > 1) )
  235. {
  236. // Send the messsage to a special broadcast queue
  237. if ( nwk_broadcastSend( (uint8 *)msgPtr ) != SUCCESS )
  238. {
  239. // Drop the message, too many broadcast messages to process
  240. mac_msg_deallocate( (uint8 **)&pData );
  241. }
  242. return;
  243. }
  244. }
  245. }
  246. else if ((event == MAC_MCPS_DATA_CNF) && (pData->hdr.status != MAC_NO_RESOURCES))
  247. {
  248. macMcpsDataCnf_t *pCnf = &msgPtr->dataCnf;
  249. if (pCnf->pDataReq->internal.txOptions & MAC_TXOPTION_ACK)
  250. {
  251. // See if LQI needs adjustment due to frame correlation
  252. ZMacLqiAdjust( pCnf->correlation, &pCnf->mpduLinkQuality );
  253. }
  254. }
  255. // Application hasn't already processed this message. Send it to NWK task.
  256. osal_msg_send( NWK_TaskID, (uint8 *)msgPtr );
  257. }
  258. if ((event == MAC_MCPS_DATA_CNF) && (pData->dataCnf.pDataReq != NULL))
  259. {
  260. // If the application needs 'pDataReq' then we cannot free it here.
  261. // The application must free it after using it. Note that 'pDataReq'
  262. // is of macMcpsDataReq_t (and not ZMacDataReq_t) type.
  263. mac_msg_deallocate( (uint8**)&(pData->dataCnf.pDataReq) );
  264. }
  265. #endif
  266. }
  267. #else // ifdef MT_MAC_CB_FUNC
  268. {
  269. /* Check if MT has subscribed for this callback If so, pass it as an event to MonitorTest */
  270. switch (pData->hdr.event)
  271. {
  272. case MAC_MLME_ASSOCIATE_IND:
  273. if ( _macCallbackSub & CB_ID_NWK_ASSOCIATE_IND )
  274. nwk_MTCallbackSubNwkAssociateInd ( (ZMacAssociateInd_t *)pData );
  275. break;
  276. case MAC_MLME_ASSOCIATE_CNF:
  277. if ( _macCallbackSub & CB_ID_NWK_ASSOCIATE_CNF )
  278. nwk_MTCallbackSubNwkAssociateCnf ( (ZMacAssociateCnf_t *)pData );
  279. break;
  280. case MAC_MLME_DISASSOCIATE_IND:
  281. if ( _macCallbackSub & CB_ID_NWK_DISASSOCIATE_IND )
  282. nwk_MTCallbackSubNwkDisassociateInd ( (ZMacDisassociateInd_t *)pData );
  283. break;
  284. case MAC_MLME_DISASSOCIATE_CNF:
  285. if ( _macCallbackSub & CB_ID_NWK_DISASSOCIATE_CNF )
  286. nwk_MTCallbackSubNwkDisassociateCnf ( (ZMacDisassociateCnf_t *)pData );
  287. break;
  288. case MAC_MLME_BEACON_NOTIFY_IND:
  289. if ( _macCallbackSub & CB_ID_NWK_BEACON_NOTIFY_IND )
  290. nwk_MTCallbackSubNwkBeaconNotifyInd( (ZMacBeaconNotifyInd_t *)pData );
  291. break;
  292. case MAC_MLME_ORPHAN_IND:
  293. if ( _macCallbackSub & CB_ID_NWK_ORPHAN_IND )
  294. nwk_MTCallbackSubNwkOrphanInd( (ZMacOrphanInd_t *) pData );
  295. break;
  296. case MAC_MLME_SCAN_CNF:
  297. if ( _macCallbackSub & CB_ID_NWK_SCAN_CNF )
  298. {
  299. pData->scanCnf.result.pEnergyDetect = ZMac_ScanBuf;
  300. nwk_MTCallbackSubNwkScanCnf ( (ZMacScanCnf_t *) pData );
  301. }
  302. if (ZMac_ScanBuf != NULL)
  303. {
  304. void *pTmp = ZMac_ScanBuf;
  305. ZMac_ScanBuf = NULL;
  306. osal_mem_free(pTmp);
  307. }
  308. break;
  309. case MAC_MLME_START_CNF:
  310. if ( _macCallbackSub & CB_ID_NWK_START_CNF )
  311. nwk_MTCallbackSubNwkStartCnf ( pData->hdr.status );
  312. break;
  313. case MAC_MLME_SYNC_LOSS_IND:
  314. if ( _macCallbackSub & CB_ID_NWK_SYNC_LOSS_IND )
  315. nwk_MTCallbackSubNwkSyncLossInd( (ZMacSyncLossInd_t *) pData );
  316. break;
  317. case MAC_MLME_POLL_CNF:
  318. if ( _macCallbackSub & CB_ID_NWK_POLL_CNF )
  319. nwk_MTCallbackSubNwkPollCnf( pData->hdr.status );
  320. break;
  321. case MAC_MLME_COMM_STATUS_IND:
  322. if ( _macCallbackSub & CB_ID_NWK_COMM_STATUS_IND )
  323. nwk_MTCallbackSubCommStatusInd ( (ZMacCommStatusInd_t *) pData );
  324. break;
  325. case MAC_MCPS_DATA_CNF:
  326. if (pData->dataCnf.pDataReq != NULL)
  327. mac_msg_deallocate((uint8**)&pData->dataCnf.pDataReq);
  328. if ( _macCallbackSub & CB_ID_NWK_DATA_CNF )
  329. nwk_MTCallbackSubNwkDataCnf( (ZMacDataCnf_t *) pData );
  330. break;
  331. case MAC_MCPS_DATA_IND:
  332. {
  333. /*
  334. Data Ind is unconventional: to save an alloc/copy, reuse the MAC
  335. buffer and re-organize the contents into ZMAC format.
  336. */
  337. ZMacDataInd_t *pDataInd = (ZMacDataInd_t *) pData;
  338. uint8 event, status, len, *msdu;
  339. /* Store parameters */
  340. event = pData->hdr.event;
  341. status = pData->hdr.status;
  342. len = pData->dataInd.msdu.len;
  343. msdu = pData->dataInd.msdu.p;
  344. /* Copy security fields */
  345. osal_memcpy(&pDataInd->Sec, &pData->dataInd.sec, sizeof(ZMacSec_t));
  346. /* Copy mac fields one by one since the two buffers overlap. */
  347. osal_memcpy(&pDataInd->SrcAddr, &pData->dataInd.mac.srcAddr, sizeof(zAddrType_t));
  348. osal_memcpy(&pDataInd->DstAddr, &pData->dataInd.mac.dstAddr, sizeof(zAddrType_t));
  349. pDataInd->Timestamp = pData->dataInd.mac.timestamp;
  350. pDataInd->Timestamp2 = pData->dataInd.mac.timestamp2;
  351. pDataInd->SrcPANId = pData->dataInd.mac.srcPanId;
  352. pDataInd->DstPANId = pData->dataInd.mac.dstPanId;
  353. pDataInd->mpduLinkQuality = pData->dataInd.mac.mpduLinkQuality;
  354. pDataInd->Correlation = pData->dataInd.mac.correlation;
  355. pDataInd->Rssi = pData->dataInd.mac.rssi;
  356. pDataInd->Dsn = pData->dataInd.mac.dsn;
  357. /* Restore parameters */
  358. pDataInd->hdr.Status = status;
  359. pDataInd->hdr.Event = event;
  360. pDataInd->msduLength = len;
  361. if (len)
  362. pDataInd->msdu = msdu;
  363. else
  364. pDataInd->msdu = NULL;
  365. if ( _macCallbackSub & CB_ID_NWK_DATA_IND )
  366. nwk_MTCallbackSubNwkDataInd ( pDataInd );
  367. }
  368. /* free buffer */
  369. mac_msg_deallocate( (uint8 **)&pData );
  370. break;
  371. case MAC_MCPS_PURGE_CNF:
  372. if ( _macCallbackSub & CB_ID_NWK_PURGE_CNF )
  373. nwk_MTCallbackSubNwkPurgeCnf( (ZMacPurgeCnf_t *) pData);
  374. break;
  375. default:
  376. break;
  377. }
  378. }
  379. #endif
  380. /********************************************************************************************************
  381. * @fn MAC_CbackCheckPending
  382. *
  383. * @brief Return number of pending indirect msg
  384. *
  385. * @param None
  386. *
  387. * @return Number of indirect msg holding
  388. ********************************************************************************************************/
  389. uint8 MAC_CbackCheckPending(void)
  390. {
  391. #if !defined (NONWK)
  392. if ( ZSTACK_ROUTER_BUILD )
  393. {
  394. return (nwkDB_ReturnIndirectHoldingCnt());
  395. }
  396. else
  397. {
  398. return (0);
  399. }
  400. #else
  401. return (0);
  402. #endif
  403. }
  404. /********************************************************************************************************
  405. * @fn ZMacLqiAdjustMode
  406. *
  407. * @brief Sets/return LQI adjust mode
  408. *
  409. * @param mode - LQI_ADJ_GET = return current mode only
  410. * LQI_ADJ_OFF = disable LQI adjusts
  411. * LQI_ADJ_MODEx = set to LQI adjust MODEx
  412. *
  413. * @return current LQI adjust mode
  414. ********************************************************************************************************/
  415. ZMacLqiAdjust_t ZMacLqiAdjustMode( ZMacLqiAdjust_t mode )
  416. {
  417. if ( mode != LQI_ADJ_GET )
  418. {
  419. lqiAdjMode = mode;
  420. }
  421. return ( lqiAdjMode );
  422. }
  423. #if !defined NONWK
  424. /********************************************************************************************************
  425. * @fn ZMacLqiAdjust
  426. *
  427. * @brief Adjust LQI according to correlation value
  428. *
  429. * @notes - the IEEE 802.15.4 specification provides some general statements on
  430. * the subject of LQI. Section 6.7.8: "The minimum and maximum LQI values
  431. * (0x00 and 0xFF) should be associated with the lowest and highest IEEE
  432. * 802.15.4 signals detectable by the receiver, and LQ values should be
  433. * uniformly distributed between these two limits." Section E.2.3: "The
  434. * LQI (see 6.7.8) measures the received energy and/or SNR for each
  435. * received packet. When energy level and SNR information are combined,
  436. * they can indicate whether a corrupt packet resulted from low signal
  437. * strength or from high signal strength plus interference."
  438. * - LQI Adjustment Mode1 provided below is a simple algorithm to use the
  439. * packet correlation value (related to SNR) to scale incoming LQI value
  440. * (related to signal strength) to 'derate' noisy packets.
  441. * - LQI Adjustment Mode2 provided below is a location for a developer to
  442. * implement their own proprietary LQI adjustment algorithm.
  443. *
  444. * @param corr - packet correlation value
  445. * @param lqi - ptr to link quality (scaled rssi)
  446. *
  447. * @return *lqi - adjusted link quality
  448. ********************************************************************************************************/
  449. static void ZMacLqiAdjust( uint8 corr, uint8 *lqi )
  450. {
  451. if ( lqiAdjMode != LQI_ADJ_OFF )
  452. {
  453. uint16 adjLqi = *lqi;
  454. // Keep correlation within theoretical limits
  455. if ( corr < LQI_CORR_MIN )
  456. {
  457. corr = LQI_CORR_MIN;
  458. }
  459. else if ( corr > LQI_CORR_MAX )
  460. {
  461. corr = LQI_CORR_MAX;
  462. }
  463. if ( lqiAdjMode == LQI_ADJ_MODE1 )
  464. {
  465. /* MODE1 - linear scaling of incoming LQI with a "correlation percentage"
  466. which is computed from the incoming correlation value between
  467. theorectical minimum/maximum values. This is a very simple way
  468. of 'derating' the incoming LQI as correlation value drops. */
  469. adjLqi = (adjLqi * (corr - LQI_CORR_MIN)) / (LQI_CORR_MAX - LQI_CORR_MIN);
  470. }
  471. else if ( lqiAdjMode == LQI_ADJ_MODE2 )
  472. {
  473. /* MODE2 - location for developer to implement a proprietary algorithm */
  474. }
  475. // Replace incoming LQI with scaled value
  476. *lqi = (adjLqi > 255) ? 255 : (uint8)adjLqi;
  477. }
  478. }
  479. #endif