1 /**
2  *\file mykonos.c
3  *
4  *\brief Contains Mykonos APIs for transceiver configuration and control
5  *
6  * Mykonos API version: 1.5.1.3565
7  */
8 
9 /**
10  * \mainpage Overview
11  *
12  * This document is intended for use by software engineering professionals and
13  * includes detailed information regarding the data types and function calls
14  * which comprise the Mykonos ANSI C API.
15  * References to "Mykonos" in the API refer to the Analog Devices development name for the AD9371 family of devices.
16  *
17  */
18 
19 /**
20  * \page Use Suggested Use
21  * The purpose of this API library is to add abstraction for the low level
22  * SPI control and calculations necessary to control the Mykonos family of transceiver devices
23  *
24  * Add the included source code as required to your baseband processor software build. Please reference the integration document
25  * as well for further instructions.
26  */
27 
28 /**
29 * \page Disclaimer Legal Disclaimer
30 * Copyright 2015-2017 Analog Devices Inc.
31 * Released under the AD9371 API license, for more information see the "LICENSE.txt" file in this zip file.
32 *
33 */
34 
35 #include <stdint.h>
36 #include <stddef.h>
37 #include "common.h"
38 #include "mykonos.h"
39 #include "mykonos_gpio.h"
40 #include "mykonos_macros.h"
41 #include "mykonos_user.h"
42 
43 /* Private helper functions local to this file */
44 static mykonosErr_t MYKONOS_calculateScaledDeviceClk_kHz(mykonosDevice_t *device, uint32_t *scaledRefClk_kHz, uint8_t *deviceClkDiv);
45 static mykonosErr_t MYKONOS_calculateDigitalClocks(mykonosDevice_t *device, uint32_t *hsDigClk_kHz, uint32_t *hsDigClkDiv4or5_kHz);
46 static mykonosErr_t enableDpdTracking(mykonosDevice_t *device, uint8_t tx1Enable, uint8_t tx2Enable);
47 static mykonosErr_t enableClgcTracking(mykonosDevice_t *device, uint8_t tx1Enable, uint8_t tx2Enable);
48 
49 /**
50  * \brief Verifies the Tx profile members are valid (in range) in the init structure
51  *
52  * If the Tx profile IQ data rate = 0, it is assumed that the Tx profile is
53  * not used.  If Tx IQ data rate > 0, and Tx profile members are out of range,
54  *
55  * \pre This function is private and is not called directly by the user.
56  *
57  * <B>Dependencies</B>
58  * - device->tx->txProfile
59  *
60  * \param device Structure pointer to Mykonos device data structure
61  * \param txProfile txProfile settings to be verified
62  * \param txHsDigClk_kHz Return value of the calculated HS Dig Clock required by the Tx profile
63  *
64  * \retval MYKONOS_ERR_TXPROFILE_IQRATE Profile IQ rate out of range
65  * \retval MYKONOS_ERR_TXPROFILE_RFBW Tx Profile RF bandwidth out of range
66  * \retval MYKONOS_ERR_TXPROFILE_FILTER_INTERPOLATION Filter interpolation not valid
67  * \retval MYKONOS_ERR_TXPROFILE_FIR_INT FIR filter not valid
68  * \retval MYKONOS_ERR_OK All profile members are valid
69  */
mykVerifyTxProfile(mykonosDevice_t * device,mykonosTxProfile_t * txProfile,uint32_t * txHsDigClk_kHz)70 static mykonosErr_t mykVerifyTxProfile(mykonosDevice_t *device, mykonosTxProfile_t *txProfile, uint32_t *txHsDigClk_kHz)
71 {
72     mykonosErr_t retVal = MYKONOS_ERR_OK;
73 
74     *txHsDigClk_kHz = 0;
75 
76     /********************************/
77     /* Check for a valid Tx profile */
78     /********************************/
79 
80     if ((txProfile->iqRate_kHz < MIN_TX_IQRATE_KHZ) || (txProfile->iqRate_kHz > MAX_TX_IQRATE_KHZ))
81     {
82         return MYKONOS_ERR_TXPROFILE_IQRATE;
83     }
84 
85     if ((txProfile->rfBandwidth_Hz < MIN_TX_RFBW_HZ) || (txProfile->rfBandwidth_Hz > MAX_TX_RFBW_HZ))
86     {
87         return MYKONOS_ERR_TXPROFILE_RFBW;
88     }
89 
90     if ((txProfile->thb1Interpolation != 1) && (txProfile->thb1Interpolation != 2))
91     {
92         return MYKONOS_ERR_TXPROFILE_FILTER_INTERPOLATION;
93     }
94 
95     if ((txProfile->thb2Interpolation != 1) && (txProfile->thb2Interpolation != 2))
96     {
97         return MYKONOS_ERR_TXPROFILE_FILTER_INTERPOLATION;
98     }
99 
100     if ((txProfile->txFirInterpolation != 1) && (txProfile->txFirInterpolation != 2) && (txProfile->txFirInterpolation != 4))
101     {
102         return MYKONOS_ERR_TXPROFILE_FILTER_INTERPOLATION;
103     }
104 
105     if ((txProfile->txFir->coefs == NULL) && (txProfile->txFirInterpolation != 1))
106     {
107         return MYKONOS_ERR_TXPROFILE_FIR_COEFS;
108     }
109 
110     if ((txProfile->dacDiv != DACDIV_2) && (txProfile->dacDiv != DACDIV_2p5) && (txProfile->dacDiv != DACDIV_4))
111     {
112         return MYKONOS_ERR_TXPROFILE_DACDIV;
113     }
114 
115     *txHsDigClk_kHz = (txProfile->iqRate_kHz * txProfile->txFirInterpolation * txProfile->thb1Interpolation * txProfile->thb2Interpolation * (uint32_t)txProfile->dacDiv);
116 
117     device->profilesValid |= TX_PROFILE_VALID;
118 
119     return retVal;
120 }
121 
122 /**
123  * \brief Verifies the Rx profile members are valid (in range) and calculates HS Dig Clock require for the Rx Profile
124  *
125  * Private helper function to verify the Rx profile members are valid (in range)
126  * and calculates HS Dig Clock require for the Rx Profile
127  * If the Rx profile IQ data rate = 0, it is assumed that the Rx profile is
128  * not used.  If Rx IQ data rate > 0, and Rx profile members are out of range.
129  *
130  * \pre This function is private and is not called directly by the user.
131  *
132  * <B>Dependencies</B>
133  * - device->rx->rxProfile
134  *
135  * \param device Structure pointer to Talise device data structure
136  * \param rxChannel receiver channel to be checked
137  * \param rxProfile rxProfile settings to be verified
138  * \param rxHsDigClk_kHz Return value of the calculated HS Dig Clock required by the Rx profile
139  *
140  * \retval MYKONOS_ERR_RXPROFILE_RXCHANNEL Rx channel is not valid.
141  * \retval MYKONOS_ERR_RXPROFILE_IQRATE out of range IQ rate
142  * \retval MYKONOS_ERR_RXPROFILE_RFBW out of range RF bandwidth
143  * \retval MYKONOS_ERR_RXPROFILE_FILTER_DECIMATION not valid filter decimation setting
144  * \retval MYKONOS_ERR_RXPROFILE_FIR_COEFS FIR filter not valid
145  * \retval MYKONOS_ERR_RXPROFILE_ADCDIV not valid ADC divider
146  * \retval MYKONOS_ERR_OK all profile members are valid
147  */
mykVerifyRxProfile(mykonosDevice_t * device,mykonosRxProfType_t rxChannel,mykonosRxProfile_t * rxProfile,uint32_t * rxHsDigClk_kHz)148 static mykonosErr_t mykVerifyRxProfile(mykonosDevice_t *device, mykonosRxProfType_t rxChannel, mykonosRxProfile_t *rxProfile, uint32_t *rxHsDigClk_kHz)
149 {
150     mykonosErr_t retVal = MYKONOS_ERR_OK;
151     uint32_t minBwHz = 0;
152     uint32_t maxBwHz = 0;
153 
154     *rxHsDigClk_kHz = 0;
155 
156     switch (rxChannel)
157     {
158         case MYK_RX_PROFILE:
159             minBwHz = MIN_RX_RFBW_HZ;
160             maxBwHz = MAX_RX_RFBW_HZ;
161             break;
162         case MYK_OBS_PROFILE:
163             minBwHz = MIN_ORX_RFBW_HZ;
164             maxBwHz = MAX_ORX_RFBW_HZ;
165             break;
166         case MYK_SNIFFER_PROFILE:
167             minBwHz = MIN_SNIFFER_RFBW_HZ;
168             maxBwHz = MAX_SNIFFER_RFBW_HZ;
169             break;
170 
171         default:
172             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RXPROFILE_RXCHANNEL,
173                     getMykonosErrorMessage(MYKONOS_ERR_RXPROFILE_RXCHANNEL));
174             return MYKONOS_ERR_RXPROFILE_RXCHANNEL;
175     }
176 
177     /********************************/
178     /* Check for a valid Rx profile */
179     /********************************/
180     if ((rxProfile->iqRate_kHz < MIN_RX_IQRATE_KHZ) || (rxProfile->iqRate_kHz > MAX_RX_IQRATE_KHZ))
181     {
182         return MYKONOS_ERR_RXPROFILE_IQRATE;
183     }
184 
185     /* check for Rx/Obs or Sniffer BW */
186     if ((rxProfile->rfBandwidth_Hz < minBwHz) || (rxProfile->rfBandwidth_Hz > maxBwHz))
187     {
188         return MYKONOS_ERR_RXPROFILE_RFBW;
189     }
190 
191     if ((rxProfile->rhb1Decimation != 1) && (rxProfile->rhb1Decimation != 2))
192     {
193         return MYKONOS_ERR_RXPROFILE_FILTER_DECIMATION;
194     }
195 
196     if ((rxProfile->rxDec5Decimation != 4) && (rxProfile->rxDec5Decimation != 5))
197     {
198         return MYKONOS_ERR_RXPROFILE_FILTER_DECIMATION;
199     }
200 
201     if ((rxProfile->rxFirDecimation != 1) && (rxProfile->rxFirDecimation != 2) && (rxProfile->rxFirDecimation != 4))
202     {
203         return MYKONOS_ERR_RXPROFILE_FILTER_DECIMATION;
204     }
205 
206     if ((rxProfile->rxFir->coefs == NULL) && (rxProfile->rxFirDecimation != 1))
207     {
208         return MYKONOS_ERR_RXPROFILE_FIR_COEFS;
209     }
210 
211     if ((rxProfile->adcDiv != 1) && (rxProfile->adcDiv != 2))
212     {
213         return MYKONOS_ERR_RXPROFILE_ADCDIV;
214     }
215 
216     *rxHsDigClk_kHz = (rxProfile->iqRate_kHz * rxProfile->rxFirDecimation * rxProfile->rhb1Decimation * rxProfile->rxDec5Decimation * rxProfile->adcDiv);
217 
218     switch (rxChannel)
219     {
220         case MYK_RX_PROFILE:
221             device->profilesValid |= RX_PROFILE_VALID;
222             break;
223         case MYK_OBS_PROFILE:
224             device->profilesValid |= ORX_PROFILE_VALID;
225             break;
226         /*case MYK_SNIFFER_PROFILE:*/
227         default:
228             device->profilesValid |= SNIFF_PROFILE_VALID;
229             break;
230     }
231 
232     return retVal;
233 }
234 
235 /**
236  * \brief Performs a hard reset on the MYKONOS DUT (Toggles RESETB pin on device)
237  *
238  * Toggles the Mykonos devices RESETB pin.  Only resets the device with
239  * the SPI chip select indicated in the device->spiSettings structure.
240  *
241  * <B>Dependencies</B>
242  * - device->spiSettings->chipSelectIndex
243  *
244  * \param device Pointer to Mykonos device data structure containing settings
245  *
246  * \return Returns enum mykonosErr_t, MYKONOS_ERR_OK=pass, !MYKONOS_ERR_OK=fail
247  */
MYKONOS_resetDevice(mykonosDevice_t * device)248 mykonosErr_t MYKONOS_resetDevice(mykonosDevice_t *device)
249 {
250 
251 #if (MYKONOS_VERBOSE == 1)
252     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_resetDevice()\n");
253 #endif
254 
255     /* toggle RESETB on device with matching spi chip select index */
256     CMB_hardReset(device->spiSettings->chipSelectIndex);
257     return MYKONOS_ERR_OK;
258 }
259 
260 /**
261  * \brief Reads back the silicon revision for the Mykonos Device
262  *
263  * <B>Dependencies</B>
264  * - device->spiSettings->chipSelectIndex
265  *
266  * \param device Pointer to Mykonos device data structure containing settings
267  * \param revision Return value of the Mykonos silicon revision
268  *
269  * \retval MYKONOS_ERR_OK Function completed successfully
270  */
MYKONOS_getDeviceRev(mykonosDevice_t * device,uint8_t * revision)271 mykonosErr_t MYKONOS_getDeviceRev(mykonosDevice_t *device, uint8_t *revision)
272 {
273 #if (MYKONOS_VERBOSE == 1)
274     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getDeviceRev()\n");
275 #endif
276 
277     CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_PRODUCT_ID, revision, 0x07, 0);
278 
279     return MYKONOS_ERR_OK;
280 }
281 
282 /**
283  * \brief Reads back the Product ID for the Mykonos Device
284  *
285  * <B>Dependencies</B>
286  * - device->spiSettings->chipSelectIndex
287  *
288  * \param device Pointer to Mykonos device data structure containing settings
289  * \param productId Return value of the Mykonos product Id
290  *
291  * \retval MYKONOS_ERR_GETPRODUCTID__NULL_PARAM recovery action for bad parameter check
292  * \retval MYKONOS_ERR_OK Function completed successfully
293  */
MYKONOS_getProductId(mykonosDevice_t * device,uint8_t * productId)294 mykonosErr_t MYKONOS_getProductId(mykonosDevice_t *device, uint8_t *productId)
295 {
296     mykonosErr_t retVal = MYKONOS_ERR_OK;
297 
298 #if (MYKONOS_VERBOSE == 1)
299     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getProductId()\n");
300 #endif
301 
302     if (productId == NULL)
303     {
304         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETPRODUCTID_NULL_PARAM,
305                 getMykonosErrorMessage(MYKONOS_ERR_GETPRODUCTID_NULL_PARAM));
306         return MYKONOS_ERR_GETPRODUCTID_NULL_PARAM;
307     }
308 
309     CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_PRODUCT_ID, productId, 0xF8, 3);
310 
311     return retVal;
312 }
313 
314 /**
315  * \brief Get API version number
316  *
317  * This function reads back the version number of the API
318  *
319  * \param device Pointer to the Mykonos data structure
320  * \param siVer A pointer to the current silicon version number.
321  * \param majorVer A pointer to the current major version number.
322  * \param minorVer A pointer to the current minor version number.
323  * \param buildVer A pointer to the current build version number.
324  *
325  * \retval MYKONOS_ERR_GET_API_VERSION_NULL_PARAM Null parameter passed to the function.
326  * \retval MYKONOS_ERR_OK Function completed successfully
327  */
MYKONOS_getApiVersion(mykonosDevice_t * device,uint32_t * siVer,uint32_t * majorVer,uint32_t * minorVer,uint32_t * buildVer)328 mykonosErr_t MYKONOS_getApiVersion(mykonosDevice_t *device, uint32_t *siVer, uint32_t *majorVer, uint32_t *minorVer, uint32_t *buildVer)
329 {
330     mykonosErr_t retVal = MYKONOS_ERR_OK;
331 
332 #if (MYKONOS_VERBOSE == 1)
333     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getApiVersion()\n");
334 #endif
335 
336     if ((siVer == NULL) || (majorVer == NULL) || (minorVer == NULL) || (buildVer == NULL))
337     {
338         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_API_VERSION_NULL_PARAM,
339                 getMykonosErrorMessage(MYKONOS_ERR_GET_API_VERSION_NULL_PARAM));
340         return MYKONOS_ERR_GET_API_VERSION_NULL_PARAM;
341     }
342 
343     *siVer = (uint32_t)MYKONOS_CURRENT_SI_VERSION;
344     *majorVer = (uint32_t)MYKONOS_CURRENT_MAJOR_VERSION;
345     *minorVer = (uint32_t)MYKONOS_CURRENT_MINOR_VERSION;
346     *buildVer = (uint32_t)MYKONOS_CURRENT_BUILD_VERSION;
347     return retVal;
348 }
349 
350 /**
351  * \brief Sets the Mykonos device SPI settings (3wire/4wire, MSBFirst, etc).
352  *
353  * This function will use the settings in the device->spiSettings structure
354  * to set SPI stream mode, address auto increment direction, MSBFirst/LSBfirst,
355  * and 3wire/4wire mode.  The Mykonos device always uses SPI MODE 0 (CPHA=0, CPOL=0).
356  * This function will update your device->spiSettings to set CHPA=0 and CPOL=0 and
357  * longInstructionWord =1 to use a 16bit instruction word.
358  *
359  * <B>Dependencies</B>
360  * - writes device->spiSettings->CPHA = 0
361  * - writes device->spiSettings->CPOL = 0
362  * - writes device->spiSettings->longInstructionWord = 1
363  *
364  * - device->spiSettings->MSBFirst
365  * - device->spiSettings->enSpiStreaming
366  * - device->spiSettings->autoIncAddrUp
367  * - device->spiSettings->fourWireMode
368  *
369  * \param device Pointer to Mykonos device data structure containing settings
370  *
371  * \return Returns enum mykonosErr_t, MYKONOS_ERR_OK=pass, !MYKONOS_ERR_OK=fail
372  */
MYKONOS_setSpiSettings(mykonosDevice_t * device)373 mykonosErr_t MYKONOS_setSpiSettings(mykonosDevice_t *device)
374 {
375     //device->spiSettings->enSpiStreaming
376     uint8_t spiReg = 0;
377 
378 #if (MYKONOS_VERBOSE == 1)
379     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setSpiSettings()\n");
380 #endif
381 
382     device->spiSettings->CPHA = 0;
383     device->spiSettings->CPOL = 0;
384     device->spiSettings->longInstructionWord = 1;
385 
386     if (device->spiSettings->MSBFirst == 0)
387     {
388         spiReg |= 0x42; /* SPI bit is 1=LSB first */
389     }
390 
391     if (device->spiSettings->autoIncAddrUp > 0)
392     {
393         spiReg |= 0x24;
394     }
395 
396     if (device->spiSettings->fourWireMode > 0)
397     {
398         spiReg |= 0x18;
399     }
400 
401     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CONFIGURATION_CONTROL_0, spiReg);
402 
403     if (device->spiSettings->enSpiStreaming > 0)
404     {
405         /* Allow SPI streaming mode: SPI message ends when chip select deasserts */
406         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_SPI_CONFIGURATION_CONTROL_1, 0x00);
407     }
408     else
409     {
410         /* Force single instruction mode */
411         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_SPI_CONFIGURATION_CONTROL_1, 0x80);
412     }
413 
414     return MYKONOS_ERR_OK;
415 }
416 
417 /**
418  * \brief Verifies the integrity of the Mykonos device data structure.
419  *
420  * The Mykonos device data structure has many pointers to other structures.  The
421  * main purpose of this function to verify that the necessary pointers within the
422  * device data structure have non zero pointers. The focus is on the Rx/Tx/ObsRx
423  * profiles and FIR filters where if a channel is disabled, it may be valid for
424  * some pointers to be NULL. This function updates device->profileValid to remember
425  * which profile pointers are valid.
426  * profileValid[3:0] = {SnifferProfileValid, ObsRxProfileValid, RxProfileValid, TxProfileValid};
427  *
428  * <B>Dependencies</B>
429  * - device (all variables)
430  *
431  * \param device Pointer to Mykonos device data structure containing settings
432  *
433  * \return Returns enum mykonosErr_t, MYKONOS_ERR_OK=pass, !MYKONOS_ERR_OK=fail
434  */
MYKONOS_verifyDeviceDataStructure(mykonosDevice_t * device)435 mykonosErr_t MYKONOS_verifyDeviceDataStructure(mykonosDevice_t *device)
436 {
437     if (device == NULL)
438     {
439         CMB_writeToLog(ADIHAL_LOG_ERROR, 0, MYKONOS_ERR_CHECKDEVSTRUCT_NULLDEVPOINTER, getMykonosErrorMessage(MYKONOS_ERR_CHECKDEVSTRUCT_NULLDEVPOINTER));
440         return MYKONOS_ERR_CHECKDEVSTRUCT_NULLDEVPOINTER;
441     }
442 
443     device->profilesValid = 0; /* Reset */
444 
445     if (device->spiSettings == NULL)
446     {
447         CMB_writeToLog(ADIHAL_LOG_ERROR, 0, MYKONOS_ERR_CHECKDEVSTRUCT_SPI, getMykonosErrorMessage(MYKONOS_ERR_CHECKDEVSTRUCT_SPI));
448         return MYKONOS_ERR_CHECKDEVSTRUCT_SPI;
449     }
450 
451     /* place this writeToLog after verifying the spiSettings structure is not NULL */
452 #if (MYKONOS_VERBOSE == 1)
453     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_verifyDeviceDataStructure()\n");
454 #endif
455 
456     /**************************************************************************
457      * Check Rx stucture pointers
458      **************************************************************************
459      */
460     if (device->rx == NULL)
461     {
462         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CHECKDEVSTRUCT_RX, getMykonosErrorMessage(MYKONOS_ERR_CHECKDEVSTRUCT_RX));
463         return MYKONOS_ERR_CHECKDEVSTRUCT_RX;
464     }
465     else
466     {
467         if (device->rx->rxChannels == RXOFF)
468         {/* If no Rx channel enabled, ok to have null pointers for rx gain control, framer, and Rx profile/Rx FIR Filter */
469         }
470         else
471         {
472             if ((device->rx->framer == NULL) || (device->rx->rxGainCtrl == NULL) || (device->rx->rxProfile == NULL))
473             {
474                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CHECKDEVSTRUCT_RXSUB,
475                         getMykonosErrorMessage(MYKONOS_ERR_CHECKDEVSTRUCT_RXSUB));
476                 return MYKONOS_ERR_CHECKDEVSTRUCT_RXSUB;
477             }
478 
479             if ((device->rx->rxProfile->rxFir == NULL) && (device->rx->rxProfile->rxFirDecimation != 1))
480             {
481                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CHECKDEVSTRUCT_RXFIR,
482                         getMykonosErrorMessage(MYKONOS_ERR_CHECKDEVSTRUCT_RXFIR));
483                 return MYKONOS_ERR_CHECKDEVSTRUCT_RXFIR;
484             }
485         }
486     }
487 
488     /**************************************************************************
489      * Check Tx stucture pointers
490      **************************************************************************
491      */
492     if (device->tx == NULL)
493     {
494         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CHECKDEVSTRUCT_TX, getMykonosErrorMessage(MYKONOS_ERR_CHECKDEVSTRUCT_TX));
495         return MYKONOS_ERR_CHECKDEVSTRUCT_TX;
496     }
497     else
498     {
499         if (device->tx->txChannels == TXOFF)
500         {/* If no Tx channel enabled, ok to have null pointers for deframer, and Tx profile/Tx FIR filter */
501         }
502         else
503         {
504             if ((device->tx->deframer == NULL) || (device->tx->txProfile == NULL))
505             {
506                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CHECKDEVSTRUCT_TXSUB,
507                         getMykonosErrorMessage(MYKONOS_ERR_CHECKDEVSTRUCT_TXSUB));
508                 return MYKONOS_ERR_CHECKDEVSTRUCT_TXSUB;
509             }
510 
511             if ((device->tx->txProfile->txFir == NULL) && (device->tx->txProfile->txFirInterpolation != 1))
512             {
513                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CHECKDEVSTRUCT_TXFIR,
514                         getMykonosErrorMessage(MYKONOS_ERR_CHECKDEVSTRUCT_TXFIR));
515                 return MYKONOS_ERR_CHECKDEVSTRUCT_TXFIR;
516             }
517         }
518     }
519 
520     /**************************************************************************
521      * Check ObsRx stucture pointers
522      **************************************************************************
523      */
524     if (device->obsRx == NULL)
525     {
526         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CHECKDEVSTRUCT_OBSRX,
527                 getMykonosErrorMessage(MYKONOS_ERR_CHECKDEVSTRUCT_OBSRX));
528         return MYKONOS_ERR_CHECKDEVSTRUCT_OBSRX;
529     }
530     else
531     {
532         if (device->obsRx->obsRxChannelsEnable == MYK_OBS_RXOFF)
533         {/* If no ObsRx channel enabled, ok to have null pointers for ObsRx gain control, framer, and ObsRx profile/FIR Filter */
534         }
535         else
536         {
537             if ((device->obsRx->framer == NULL))
538             {
539                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CHECKDEVSTRUCT_OBSRXFRAMER,
540                         getMykonosErrorMessage(MYKONOS_ERR_CHECKDEVSTRUCT_OBSRXFRAMER));
541                 return MYKONOS_ERR_CHECKDEVSTRUCT_OBSRXFRAMER;
542             }
543 
544             if (device->obsRx->snifferProfile != NULL)
545             {
546                 if (device->obsRx->snifferGainCtrl == NULL)
547                 {
548                     CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CHECKDEVSTRUCT_SNIFFERGAINCTRL,
549                             getMykonosErrorMessage(MYKONOS_ERR_CHECKDEVSTRUCT_SNIFFERGAINCTRL));
550                     return MYKONOS_ERR_CHECKDEVSTRUCT_SNIFFERGAINCTRL;
551                 }
552 
553                 if ((device->obsRx->snifferProfile->rxFir == NULL) && (device->obsRx->snifferProfile->rxFirDecimation != 1))
554                 {
555                     CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CHECKDEVSTRUCT_SNIFFERFIR,
556                             getMykonosErrorMessage(MYKONOS_ERR_CHECKDEVSTRUCT_SNIFFERFIR));
557                     return MYKONOS_ERR_CHECKDEVSTRUCT_SNIFFERFIR;
558                 }
559             }
560 
561             if (device->obsRx->orxProfile != NULL)
562             {
563                 if (device->obsRx->orxGainCtrl == NULL)
564                 {
565                     CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CHECKDEVSTRUCT_ORXGAINCTRL,
566                             getMykonosErrorMessage(MYKONOS_ERR_CHECKDEVSTRUCT_ORXGAINCTRL));
567                     return MYKONOS_ERR_CHECKDEVSTRUCT_ORXGAINCTRL;
568                 }
569 
570                 if ((device->obsRx->orxProfile->rxFir == NULL) && (device->obsRx->orxProfile->rxFirDecimation != 1))
571                 {
572                     CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CHECKDEVSTRUCT_ORXFIR,
573                             getMykonosErrorMessage(MYKONOS_ERR_CHECKDEVSTRUCT_ORXFIR));
574                     return MYKONOS_ERR_CHECKDEVSTRUCT_ORXFIR;
575                 }
576             }
577         }
578     }
579 
580     return MYKONOS_ERR_OK;
581 }
582 
583 /**
584  * \brief Initializes the Mykonos device based on the desired device settings.
585  *
586  * This function initializes the mykonos device, setting up the CLKPLL, digital clocks,
587  * JESD204b settings, FIR Filters, digital filtering.  It does not load the ARM
588  * or perform any of the ARM init calibrations. It also sets the Rx Manual gain indexes and
589  * TxAttenuation settings to the initial values found in the device data structure.  It leaves the
590  * Mykonos in a state ready for multichip sync (which can bring up the JESD204 links), the
591  * ARM to be loaded, and the init calibartions run.
592  *
593  * <B>Dependencies</B>
594  * - device (all variables)
595  *
596  * \param device Pointer to Mykonos device data structure containing settings
597  *
598  * \return Returns enum mykonosErr_t, MYKONOS_ERR_OK=pass, !MYKONOS_ERR_OK=fail
599  */
MYKONOS_initialize(mykonosDevice_t * device)600 mykonosErr_t MYKONOS_initialize(mykonosDevice_t *device)
601 {
602     uint8_t txChannelSettings = 0;
603     uint8_t rxChannelSettings = 0;
604     uint8_t orxChannelSettings = 0;
605     uint8_t sniffChannelSettings = 0;
606     uint8_t adcDacClockRateSelect = 0;
607     uint8_t enableDpd = 0;
608     uint8_t obsRxRealIf = 0;
609     uint8_t enRxHighRejDec5 = 0;
610     uint8_t rxRealIfData = 0;
611     uint8_t txSyncb = 0x00;
612     uint8_t rxSyncb = 0x00;
613     uint8_t orxSyncb = 0x00;
614     mykonosErr_t retVal = MYKONOS_ERR_OK;
615 
616 #if (MYKONOS_VERBOSE == 1)
617     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_initialize()\n");
618 #endif
619 
620     retVal = MYKONOS_verifyDeviceDataStructure(device);
621     if (retVal != MYKONOS_ERR_OK)
622     {
623         return retVal;
624     }
625 
626     /* Verify Rx/Tx and ObsRx profiles are valid combinations */
627     retVal = MYKONOS_verifyProfiles(device);
628     if (retVal != MYKONOS_ERR_OK)
629     {
630         return retVal;
631     }
632 
633     /* Set 3 or 4-wire SPI mode, MSBFirst/LSBfirst in device, pushes CPOL=0, CPHA=0, longInstWord=1 into device->spiSettings */
634     retVal = MYKONOS_setSpiSettings(device);
635     if (retVal != MYKONOS_ERR_OK)
636     {
637         return retVal;
638     }
639 
640     /* Increase SPI_DO drive strength */
641     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DIGITAL_IO_CONTROL, 0x10);
642 
643     /* Enable Reference clock - Set REFCLK pad common mode voltage */
644     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_REF_PAD_CONFIG2, 0x07);
645 
646     /* Set Mykonos IO pin settings, GPIO direction, enable relevant LVDS pads */
647     /* Enable SYSREF LVDS input pad + 100ohm internal termination */
648     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_SYSREF_PAD_CONFIG, 0x12); //Enable SYSREF input buffer
649 
650     if ((device->tx > 0) && (device->tx->txProfile > 0))
651     {
652         /* Check for LVDS/CMOS mode */
653         if (device->tx->deframer->txSyncbMode > 0)
654         {
655             txSyncb = 0xF0;
656         }
657         else
658         {
659             txSyncb = 0x02;
660         }
661 
662         /* Enable SYNCOUTB output buffer */
663         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX1_SYNC_PAD_CONFIG, txSyncb);
664     }
665 
666     /* Look at each framer and enable the RXSYNCB used for each framer.
667      * It is possible that they use the same RXSYNCB pin */
668     if ((device->rx > 0) && (device->rx->framer > 0))
669     {
670         /* Check for LVDS/CMOS mode */
671         if (device->rx->framer->rxSyncbMode > 0)
672         {
673             rxSyncb = 0x00;
674         }
675         else
676         {
677             rxSyncb = 0x12;
678         }
679 
680         if (device->rx->framer->obsRxSyncbSelect == 0)
681         {
682             /* Enable SYNCINB0 LVDS/CMOS input buffer */
683             CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX1_SYNC_CONFIG, rxSyncb);
684         }
685         else
686         {
687             /* Enable SYNCINB1 LVDS/CMOS input buffer */
688             CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX2_SYNC_CONFIG, rxSyncb);
689         }
690     }
691     if ((device->obsRx > 0) && (device->obsRx->framer > 0))
692     {
693         /* Check for LVDS/CMOS mode */
694         if (device->obsRx->framer->rxSyncbMode > 0)
695         {
696             orxSyncb = 0x00;
697         }
698         else
699         {
700             orxSyncb = 0x12;
701         }
702 
703         if (device->obsRx->framer->obsRxSyncbSelect == 0)
704         {
705             /* Check for rxSyncb and orxSyncb when using the same RXSYNCB */
706             if ((orxSyncb != rxSyncb) && (device->rx->framer->obsRxSyncbSelect == 0))
707             {
708                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_RXSYNCB_ORXSYNCB_MODE,
709                         getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_RXSYNCB_ORXSYNCB_MODE));
710                 return MYKONOS_ERR_INIT_INV_RXSYNCB_ORXSYNCB_MODE;
711             }
712 
713             /* Enable SYNCINB0 LVDS input buffer */
714             CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX1_SYNC_CONFIG, orxSyncb);
715         }
716         else
717         {
718             /* Check for rxSyncb and orxSyncb when using the same ORXSYNCB */
719             if ((orxSyncb != rxSyncb) && (device->rx->framer->obsRxSyncbSelect == 1))
720             {
721                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_RXSYNCB_ORXSYNCB_MODE,
722                         getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_RXSYNCB_ORXSYNCB_MODE));
723                 return MYKONOS_ERR_INIT_INV_RXSYNCB_ORXSYNCB_MODE;
724             }
725 
726             /* Enable SYNCINB1 LVDS input buffer */
727             CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX2_SYNC_CONFIG, orxSyncb);
728         }
729     }
730 
731     /* Set number of device clock cycles per microsecond [round(freq/2) - 1] */
732     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_REFERENCE_CLOCK_CYCLES, (uint8_t)((((device->clocks->deviceClock_kHz / 1000) + 1) >> 1) - 1));
733 
734     /* Set profile specific digital clock dividers */
735     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CONFIGURATION_CONTROL_1, 0x04); /* Negate Rx2 so phase matches Rx1 */
736 
737     if (device->profilesValid & TX_PROFILE_VALID)
738     {
739         txChannelSettings = (((uint8_t)device->tx->txChannels & 0x3) << 6);
740         switch (device->tx->txProfile->thb2Interpolation)
741         {
742             case 1:
743                 break; /* keep bit as 0 in bitfield */
744             case 2:
745                 txChannelSettings |= 0x20;
746                 break;
747             default:
748                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_TXHB2_INTERPOLATION,
749                         getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_TXHB2_INTERPOLATION));
750                 return MYKONOS_ERR_INIT_INV_TXHB2_INTERPOLATION;
751         }
752 
753         switch (device->tx->txProfile->thb1Interpolation)
754         {
755             case 1:
756                 break; /* keep bit as 0 in bitfield */
757             case 2:
758                 txChannelSettings |= 0x10;
759                 break;
760             default:
761                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_TXHB1_INTERPOLATION,
762                         getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_TXHB1_INTERPOLATION));
763                 return MYKONOS_ERR_INIT_INV_TXHB1_INTERPOLATION;
764         }
765 
766         if (device->tx->txProfile->txFir == NULL)
767         {
768             /* If invalid pointer to FIR filter, Bypass programmable FIR, keep txChannelSettings[1:0] == 0 */
769         }
770         else
771         {
772             switch (device->tx->txProfile->txFirInterpolation)
773             {
774                 case 1:
775                     txChannelSettings |= 0x01;
776                     break;
777                 case 2:
778                     txChannelSettings |= 0x02;
779                     break;
780                 case 4:
781                     txChannelSettings |= 0x03;
782                     break;
783                 default:
784                     CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_TXFIR_INTERPOLATION,
785                             getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_TXFIR_INTERPOLATION));
786                     return MYKONOS_ERR_INIT_INV_TXFIR_INTERPOLATION;
787             }
788         }
789 
790         switch (device->tx->txProfile->dacDiv)
791         {
792             case DACDIV_2:
793                 break; /* Keep bit [1]=0 */
794             case DACDIV_2p5:
795                 break; /* Keep bit [1]=0, div 2.5 is set when Rx DEC5 filter enabled*/
796             case DACDIV_4:
797                 adcDacClockRateSelect |= 2;
798                 break;
799             default:
800                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_DACDIV, getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_DACDIV));
801                 return MYKONOS_ERR_INIT_INV_DACDIV;
802         }
803     }
804 
805     if (device->profilesValid & RX_PROFILE_VALID)
806     {
807         rxChannelSettings = (((uint8_t)device->rx->rxChannels & 0x3) << 6);
808         switch (device->rx->rxProfile->rxDec5Decimation)
809         {
810             case 4:
811                 break; /* keep bit as 0 in bitfield */
812             case 5:
813                 rxChannelSettings |= 0x04;
814                 break;
815             default:
816                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_RXDEC5_DECIMATION,
817                         getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_RXDEC5_DECIMATION));
818                 return MYKONOS_ERR_INIT_INV_RXDEC5_DECIMATION;
819         }
820 
821         switch (device->rx->rxProfile->rhb1Decimation)
822         {
823             case 1:
824                 break; /* keep bit as 0 in bitfield */
825             case 2:
826                 rxChannelSettings |= 0x10;
827                 break;
828             default:
829                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_RXHB1_DECIMATION,
830                         getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_RXHB1_DECIMATION));
831                 return MYKONOS_ERR_INIT_INV_RXHB1_DECIMATION;
832         }
833 
834         if (device->rx->rxProfile->rxFir == NULL)
835         {
836             /* If invalid pointer to FIR filter, Bypass programmable FIR, keep rxChannelSettings[1:0] == 0 */
837         }
838         else
839         {
840             switch (device->rx->rxProfile->rxFirDecimation)
841             {
842                 case 1:
843                     rxChannelSettings |= 0x01;
844                     break;
845                 case 2:
846                     rxChannelSettings |= 0x02;
847                     break;
848                 case 4:
849                     rxChannelSettings |= 0x03;
850                     break;
851                 default:
852                     CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_RXFIR_DECIMATION,
853                             getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_RXFIR_DECIMATION));
854                     return MYKONOS_ERR_INIT_INV_RXFIR_DECIMATION;
855             }
856         }
857 
858         switch (device->rx->rxProfile->adcDiv)
859         {
860             case 1:
861                 adcDacClockRateSelect |= 0;
862                 break;
863             case 2:
864                 adcDacClockRateSelect |= 1;
865                 break;
866             default:
867                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_ADCDIV, getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_ADCDIV));
868                 return MYKONOS_ERR_INIT_INV_ADCDIV;
869         }
870 
871         rxRealIfData = (device->rx->realIfData > 0) ? 1 : 0;
872         enRxHighRejDec5 = (device->rx->rxProfile->enHighRejDec5 > 0) ? 1 : 0;
873     }
874     else if (device->profilesValid & ORX_PROFILE_VALID)
875     {
876         /* if Rx profile not valid, but ORX profile valid, set RX ADC divider and dec5 to match orx profile setting */
877         /* ARM clock is derived from Rx clocking, so Rx ADC div needs to be set */
878         switch (device->obsRx->orxProfile->rxDec5Decimation)
879         {
880             case 4:
881                 break; /* keep bit as 0 in bitfield */
882             case 5:
883                 rxChannelSettings |= 0x04;
884                 break;
885             default:
886                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_RXDEC5_DECIMATION,
887                         getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_RXDEC5_DECIMATION));
888                 return MYKONOS_ERR_INIT_INV_RXDEC5_DECIMATION;
889         }
890 
891         switch (device->obsRx->orxProfile->adcDiv)
892         {
893             case 1:
894                 adcDacClockRateSelect |= 0;
895                 break;
896             case 2:
897                 adcDacClockRateSelect |= 1;
898                 break;
899             default:
900                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_ADCDIV, getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_ADCDIV));
901                 return MYKONOS_ERR_INIT_INV_ADCDIV;
902         }
903     }
904     else if (device->profilesValid & SNIFF_PROFILE_VALID)
905     {
906         /* if Rx profile not valid, and ORX profile not valid, set RX ADC divider and dec5 to match sniffer profile setting */
907         /* ARM clock is derived from Rx clocking, so Rx ADC div needs to be set */
908         switch (device->obsRx->snifferProfile->rxDec5Decimation)
909         {
910             case 4:
911                 break; /* keep bit as 0 in bitfield */
912             case 5:
913                 rxChannelSettings |= 0x04;
914                 break;
915             default:
916                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_RXDEC5_DECIMATION,
917                         getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_RXDEC5_DECIMATION));
918                 return MYKONOS_ERR_INIT_INV_RXDEC5_DECIMATION;
919         }
920 
921         switch (device->obsRx->snifferProfile->adcDiv)
922         {
923             case 1:
924                 adcDacClockRateSelect |= 0;
925                 break;
926             case 2:
927                 adcDacClockRateSelect |= 1;
928                 break;
929             default:
930                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_ADCDIV, getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_ADCDIV));
931                 return MYKONOS_ERR_INIT_INV_ADCDIV;
932         }
933     }
934 
935     /* determine ObsRx ADC Div setting */
936     if (device->profilesValid & ORX_PROFILE_VALID)
937     {
938         switch (device->obsRx->orxProfile->adcDiv)
939         {
940             case 1:
941                 break; /* Keep bit[4]=0 */
942             case 2:
943                 adcDacClockRateSelect |= 0x10;
944                 break; /* Set bit[4]=1 */
945             default:
946                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_OBSRX_ADCDIV,
947                         getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_OBSRX_ADCDIV));
948                 return MYKONOS_ERR_INIT_INV_OBSRX_ADCDIV;
949         }
950     }
951     else if (device->profilesValid & SNIFF_PROFILE_VALID)
952     {
953         switch (device->obsRx->snifferProfile->adcDiv)
954         {
955             case 1:
956                 break; /* Keep bit[4]=0 */
957             case 2:
958                 adcDacClockRateSelect |= 0x10;
959                 break; /* Set bit[4]=1 */
960             default:
961                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_OBSRX_ADCDIV,
962                         getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_OBSRX_ADCDIV));
963                 return MYKONOS_ERR_INIT_INV_OBSRX_ADCDIV;
964         }
965     }
966     else if (device->profilesValid & RX_PROFILE_VALID)
967     { /* if OBSRX profiles are not valid, set obsRx ADC div to match Rx ADC divider */
968         switch (device->rx->rxProfile->adcDiv)
969         {
970             case 1:
971                 break; /* Keep bit[4]=0 */
972             case 2:
973                 adcDacClockRateSelect |= 0x10;
974                 break; /* Set bit[4]=1 */
975             default:
976                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_OBSRX_ADCDIV,
977                         getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_OBSRX_ADCDIV));
978                 return MYKONOS_ERR_INIT_INV_OBSRX_ADCDIV;
979         }
980     }
981 
982     /* Determine ORx and Sniffer channel settings */
983     if (device->obsRx != NULL)
984     {
985         /* verify pointers in data structure are valid (non-zero) */
986         if (device->profilesValid & (ORX_PROFILE_VALID | SNIFF_PROFILE_VALID))
987         {
988             if (device->obsRx->realIfData > 0)
989             {
990                 obsRxRealIf = 1;
991             }
992         }
993 
994         /* TODO: verify that the decimation matches the given IQ rate in the data structure */
995 
996         /* Set Sniffer profile (digital filter enables) if sniffer profile enabled (valid pointer) */
997         if (device->profilesValid & SNIFF_PROFILE_VALID)
998         {
999             sniffChannelSettings = 0;
1000             switch (device->obsRx->snifferProfile->rhb1Decimation)
1001             {
1002                 case 1:
1003                     break;
1004                 case 2:
1005                     sniffChannelSettings |= 0x10;
1006                     break;
1007                 default:
1008                     CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_SNIFFER_RHB1,
1009                             getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_SNIFFER_RHB1));
1010                     return MYKONOS_ERR_INIT_INV_SNIFFER_RHB1;
1011             }
1012 
1013             if (device->obsRx->snifferProfile->rxFir != NULL)
1014             {
1015 
1016                 switch (device->obsRx->snifferProfile->rxFirDecimation)
1017                 {
1018                     case 1:
1019                         sniffChannelSettings |= 0x01;
1020                         break;
1021                     case 2:
1022                         sniffChannelSettings |= 0x02;
1023                         break;
1024                     case 4:
1025                         sniffChannelSettings |= 0x03;
1026                         break;
1027                     default:
1028                         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_SNIFFER_RFIR_DEC,
1029                                 getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_SNIFFER_RFIR_DEC));
1030                         return MYKONOS_ERR_INIT_INV_SNIFFER_RFIR_DEC;
1031                 }
1032             }
1033         }
1034 
1035         /* Set ORx profile (digital filter enables) if ORx profile enabled (valid pointer) */
1036         if (device->profilesValid & ORX_PROFILE_VALID)
1037         {
1038             orxChannelSettings = 0;
1039             switch (device->obsRx->orxProfile->rhb1Decimation)
1040             {
1041                 case 1:
1042                     break;
1043                 case 2:
1044                     orxChannelSettings |= 0x10;
1045                     break;
1046                 default:
1047                     CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_ORX_RHB1,
1048                             getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_ORX_RHB1));
1049                     return MYKONOS_ERR_INIT_INV_ORX_RHB1;
1050             }
1051 
1052             if (device->obsRx->orxProfile->rxFir != NULL)
1053             {/* if pointer to orx rxFIR is valid */
1054 
1055                 switch (device->obsRx->orxProfile->rxFirDecimation)
1056                 {
1057                     case 1:
1058                         orxChannelSettings |= 0x01;
1059                         break;
1060                     case 2:
1061                         orxChannelSettings |= 0x02;
1062                         break;
1063                     case 4:
1064                         orxChannelSettings |= 0x03;
1065                         break;
1066                     default:
1067                         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_ORX_RFIR_DEC,
1068                                 getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_ORX_RFIR_DEC));
1069                         return MYKONOS_ERR_INIT_INV_ORX_RFIR_DEC;
1070                 }
1071             }
1072         }
1073     }
1074 
1075     /************************************************************************
1076      * Set channel config settings for Rx/Tx/oRx and Sniffer channels
1077      ***********************************************************************
1078      */
1079     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CONFIGURATION_CONTROL_2, txChannelSettings);
1080     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CONFIGURATION_CONTROL_4, rxChannelSettings);
1081 
1082     /* Set option to use new high rejection DEC5 filters in main Rx1/Rx2 path.  */
1083     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CONFIGURATION_CONTROL_5, ((uint8_t)(rxRealIfData << 2) | (enRxHighRejDec5 ? 3 : 0)));
1084 
1085     if (rxRealIfData > 0)
1086     {
1087         /* Set Rx1 NCO frequency */
1088         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX_NCO_CH1_FTW_BYTE_3, 0x40);
1089         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX_NCO_CH1_FTW_BYTE_2, 0x00);
1090         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX_NCO_CH1_FTW_BYTE_1, 0x01);
1091 
1092         /* Set Rx2 NCO frequency */
1093         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX_NCO_CH2_FTW_BYTE_3, 0x40);
1094         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX_NCO_CH2_FTW_BYTE_2, 0x00);
1095         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX_NCO_CH2_FTW_BYTE_1, 0x01);
1096 
1097         /* Enable NCO for Rx1 and Rx2 to shift data from zero IF to real IF */
1098         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_RX_NCO_CONTROL, 3, 0x03, 0);
1099     }
1100 
1101     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_DPD_SNIFFER_CONFIGURATION_CONTROL_2, obsRxRealIf, 0x40, 6);
1102 
1103     /* if sniffer profile disabled, Sniffer config reg is set to default = 0x80 */
1104     sniffChannelSettings |= 0x80; /* use PFIR coef set B = bit[7]=1*/
1105     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_SNIFFER_CONFIGURATION_CONTROL, sniffChannelSettings);
1106 
1107     /* if orx profile not valid, SPI reg for orx config is set to default = 0x00 */
1108     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DPD_CONFIGURATION_CONTROL, orxChannelSettings);
1109     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_LOOPBACK_CONFIGURATION_CONTROL, orxChannelSettings);
1110 
1111     /* Set ADC divider, DAC divider, and ObsRx/sniffer dividers */
1112     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_1, adcDacClockRateSelect, 0x13, 0);
1113 
1114     /* Disable ORx digital DC offset - bad default SPI setting for ObsRx DC offset */
1115     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DIGITAL_DC_OFFSET_CH3_DPD_M_SHIFT, 0x60);
1116 
1117     /* Necessary write for ARM init cals to work */
1118     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_SNIFF_RXLOGEN_BYTE1, 0x0E);
1119 
1120     /* Increase Sniffer LNA gain */
1121     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_SNRX_LNA_BIAS_C, 0x0F);
1122 
1123     /* Set the CLKPLL with the frequency from the device data structure */
1124     retVal = MYKONOS_initDigitalClocks(device);
1125     if (retVal != MYKONOS_ERR_OK)
1126     {
1127         return retVal;
1128     }
1129 
1130     /* Wait for CLKPLL CP Cal done and CLKPLL Lock  or throw error message */
1131     CMB_wait_ms(500);
1132     retVal = MYKONOS_waitForEvent(device, CLKPLLCP, 1000000);
1133     if (retVal != MYKONOS_ERR_OK)
1134     {
1135         return retVal;
1136     }
1137 
1138     retVal = MYKONOS_waitForEvent(device, CLKPLL_LOCK, 1000000);
1139     if (retVal != MYKONOS_ERR_OK)
1140     {
1141         return retVal;
1142     }
1143 
1144     /* Enable digital clocks - this is gated by the CLKPLL being locked */
1145     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_0, 0x14);
1146 
1147     /* Set the Tx PFIR synchronization clock */
1148     retVal = MYKONOS_setTxPfirSyncClk(device);
1149     if (retVal != MYKONOS_ERR_OK)
1150     {
1151         return retVal;
1152     }
1153 
1154     /* Set the Rx PFIR synchronization clock */
1155     retVal = MYKONOS_setRxPfirSyncClk(device);
1156     if (retVal != MYKONOS_ERR_OK)
1157     {
1158         return retVal;
1159     }
1160 
1161     if (device->profilesValid & TX_PROFILE_VALID)
1162     {
1163         /* Set pre TxPFIR Half band filter interpolation */
1164         if (device->tx->txProfile->txInputHbInterpolation == 1)
1165         {
1166             /* disable TX input half band ([3:2]=00) - but allow DPD to still be enabled for tx profiles with wide BW [1] */
1167             enableDpd = (device->tx->txProfile->enableDpdDataPath > 0) ? 1 : 0;
1168             CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_FILTER_CONFIGURATION, enableDpd, 0x0E, 1);
1169         }
1170         else if (device->tx->txProfile->txInputHbInterpolation == 2)
1171         {
1172             if (device->tx->txProfile->iqRate_kHz > 160000)
1173             {
1174                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_TXINPUTHB0_INV_RATE,
1175                         getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_TXINPUTHB0_INV_RATE));
1176                 return MYKONOS_ERR_INIT_INV_TXINPUTHB0_INV_RATE;
1177             }
1178 
1179             /* enable TX input half band[2]=1, and Enable DPD[1]=1*/
1180             CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_FILTER_CONFIGURATION, 3, 0x0E, 1);
1181         }
1182         else if (device->tx->txProfile->txInputHbInterpolation == 4)
1183         {
1184             if (device->tx->txProfile->iqRate_kHz > 80000)
1185             {
1186                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_TXINPUTHB_INV_RATE,
1187                         getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_TXINPUTHB_INV_RATE));
1188                 return MYKONOS_ERR_INIT_INV_TXINPUTHB_INV_RATE;
1189             }
1190 
1191             /* enable TX input HB0[3]=1 and Tx input HB[2]=1, and Enable DPD[1]=1*/
1192             CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_FILTER_CONFIGURATION, 7, 0x0E, 1);
1193         }
1194         else
1195         {
1196             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INIT_INV_TXINPUTHB_PARM,
1197                     getMykonosErrorMessage(MYKONOS_ERR_INIT_INV_TXINPUTHB_PARM));
1198             return MYKONOS_ERR_INIT_INV_TXINPUTHB_PARM;
1199         }
1200 
1201         /* Enable SPI Tx Atten mode */
1202         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_TPC_CONFIG, 0x01, 0x03, 0);
1203         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_TPC_CONFIG, 0x01, 0x0C, 2);
1204 
1205         /* Set Tx1 Atten step size */
1206         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_INCR_DECR_WORD, device->tx->txAttenStepSize, 0x60, 5);
1207 
1208         /* Set Tx2 Atten step size */
1209         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_TPC_CONFIG, device->tx->txAttenStepSize, 0x60, 5);
1210     }
1211     else
1212     {
1213         /* Power down DACs */
1214         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_PD_OVERIDE_7_0, 3, 0x0C, 2);
1215         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_PD_OVERRIDE_CONTROL_7_0, 3, 0x0C, 2);
1216     }
1217 
1218     /* Set RxFE LO Common mode */
1219     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RXFE1_LOCM, 0xF0);
1220     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RXFE2_LOCM, 0xF0);
1221 
1222     /* Set Rxloopback LO Common mode */
1223     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RXLOOPBACK1_CNTRL_1, 0xFF);
1224     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RXLOOPBACK2_CNTRL_1, 0xFF);
1225 
1226     /* Setup MGC or AGC Rx gain control */
1227     if ((retVal = MYKONOS_setupRxAgc(device)) != MYKONOS_ERR_OK)
1228     {
1229         return retVal;
1230     }
1231 
1232     /* Default Rx to use manual gain control until AGC enabled by user */
1233     if ((retVal = MYKONOS_setRxGainControlMode(device, MGC)) != MYKONOS_ERR_OK)
1234     {
1235         return retVal;
1236     }
1237 
1238 
1239     if ((retVal = MYKONOS_setupObsRxAgc(device)) != MYKONOS_ERR_OK)
1240     {
1241         return retVal;
1242     }
1243 
1244     /* Default ObsRx to use manual gain control until AGC enabled by user */
1245     if ((retVal = MYKONOS_setObsRxGainControlMode(device, MGC)) != MYKONOS_ERR_OK)
1246     {
1247         return retVal;
1248     }
1249 
1250     /* Disable GPIO select bits by setting to b11 */
1251     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_CONFIGURATION_CONTROL_1, 3, 0x30, 4);
1252 
1253     /* Extra settings for ARM calibrations */
1254     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DIGITAL_DC_OFFSET_SHIFT, 0x11);
1255     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX_LOOPBACK1_CNTRL_4, 0x04);
1256     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX_LOOPBACK2_CNTRL_4, 0x04);
1257     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_CFG_2, 0x20, 0x20, 0);
1258 
1259     /* Extra settings for ADC initialisation */
1260     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX_ADC_FLASH_DELAY, 0x28);
1261     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX_ADC_FLASH_CTRL, 0x0E);
1262     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ORX_ADC_FLASH_DELAY, 0x28);
1263     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ORX_ADC_FLASH_CTRL, 0x0E);
1264 
1265     /* Move to Alert ENSM state */
1266     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ENSM_CONFIG_7_0, 0x05);
1267 
1268     return MYKONOS_ERR_OK;
1269 }
1270 
1271 /**
1272  * \brief Verifies the init structure profiles are valid combinations
1273  *
1274  * This function checks that the Rx/Tx/ORx/Sniffer profiles have valid clock rates in
1275  * order to operate together.  Rx/Tx and ORx/Sniffer share a common high speed digital
1276  * clock. If an invalid combination of profiles is detected, an error will be
1277  * returned. If a profile in the init structure is unused, the user should zero
1278  * out all members of that particular profile structure.  If a Rx/Tx/ORx/Sniffer profile
1279  * has an IQ rate = 0, it is assumed that the profile is disabled.
1280  *
1281  * \pre This function is private and is not called directly by the user.
1282  *
1283  * This function uses mykVerifyTxProfile() and mykVerifyRxProfile() as helper functions.
1284  *
1285  * <B>Dependencies</B>
1286  * - device->spiSettings
1287  * - device->spiSettings->chipSelectIndex
1288  *
1289  * \param device Structure pointer to Mykonos device data structure
1290  *
1291  * \retval MYKONOS_ERR_PROFILES_HSDIGCLK profiles loaded are not valid
1292  * \retval MYKONOS_ERR_OK  Function completed successfully
1293  */
MYKONOS_verifyProfiles(mykonosDevice_t * device)1294 mykonosErr_t MYKONOS_verifyProfiles(mykonosDevice_t *device)
1295 {
1296     mykonosErr_t retVal = MYKONOS_ERR_OK;
1297 
1298     uint32_t rxHsDigClk_kHz = 0;
1299     uint32_t orxHsDigClk_kHz = 0;
1300     uint32_t snifferHsDigClk_kHz = 0;
1301     uint32_t txHsDigClk_kHz = 0;
1302 
1303     mykonosRxProfile_t *rxProfile = NULL;
1304     mykonosTxProfile_t *txProfile = NULL;
1305     mykonosRxProfile_t *orxProfile = NULL;
1306     mykonosRxProfile_t *snifferProfile = NULL;
1307 
1308 #if (MYKONOS_VERBOSE == 1)
1309     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_verifyProfiles()\n");
1310 #endif
1311 
1312     device->profilesValid = 0;
1313 
1314     /* Check all loaded profiles */
1315     if (device->tx->txChannels != TXOFF)
1316     {
1317         txProfile = device->tx->txProfile;
1318         retVal = mykVerifyTxProfile(device, txProfile, &txHsDigClk_kHz);
1319         if (retVal != MYKONOS_ERR_OK)
1320         {
1321             return retVal;
1322         }
1323     }
1324 
1325     if (device->rx->rxChannels != RXOFF)
1326     {
1327         rxProfile = device->rx->rxProfile;
1328         retVal = mykVerifyRxProfile(device, MYK_RX_PROFILE, rxProfile, &rxHsDigClk_kHz);
1329         if (retVal != MYKONOS_ERR_OK)
1330         {
1331             return retVal;
1332         }
1333     }
1334 
1335     if (device->obsRx->obsRxChannelsEnable != MYK_OBS_RXOFF)
1336     {
1337         if ((uint32_t)device->obsRx->obsRxChannelsEnable & (uint32_t)MYK_ORX1_ORX2)
1338         {
1339             orxProfile = device->obsRx->orxProfile;
1340             retVal = mykVerifyRxProfile(device, MYK_OBS_PROFILE, orxProfile, &orxHsDigClk_kHz);
1341             if (retVal != MYKONOS_ERR_OK)
1342             {
1343                 return retVal;
1344             }
1345         }
1346 
1347         if ((uint32_t)device->obsRx->obsRxChannelsEnable & (uint32_t)MYK_SNRXA_B_C)
1348         {
1349             snifferProfile = device->obsRx->snifferProfile;
1350             retVal = mykVerifyRxProfile(device, MYK_SNIFFER_PROFILE, snifferProfile, &snifferHsDigClk_kHz);
1351             if (retVal != MYKONOS_ERR_OK)
1352             {
1353                 return retVal;
1354             }
1355         }
1356     }
1357 
1358     return retVal;
1359 }
1360 
1361 /**
1362  * \brief Write indirect registers (Programmable FIRs, Rx gain tables, JESD204B settings).  Must be done after Multi Chip Sync
1363  *
1364  * The BBP should never need to call this function.  It is called automatically by the initArm function.
1365  * This function is a continuation of the MYKONOS_initialize() function.  This part of initialization must be done after
1366  * the BBP has completed Multi chip Sync.  These registers include FIR filters, Rx gain tables, and JESD204B framer/deframer
1367  * config registers.
1368  *
1369  * <B>Dependencies</B>
1370  * - device->spiSettings
1371  * - device->spiSettings->chipSelectIndex
1372  *
1373  * \param device Pointer to the Mykonos device data structure containing settings
1374  *                   an error.
1375  * \return Returns enum mykonosErr_t, MYKONOS_ERR_OK=pass, !MYKONOS_ERR_OK=fail
1376  */
MYKONOS_initSubRegisterTables(mykonosDevice_t * device)1377 mykonosErr_t MYKONOS_initSubRegisterTables(mykonosDevice_t *device)
1378 {
1379     mykonosErr_t retVal = MYKONOS_ERR_OK;
1380 
1381     /* ------------------------------------------------------------------------------------------- */
1382     /* Program submap register tables after digital clocks are up and running and Multi Chip Sync */
1383     /* has been completed by BBP */
1384     if (device->profilesValid & TX_PROFILE_VALID)
1385     {
1386         if (device->tx->txProfile->txFir != NULL)
1387         {
1388             retVal = MYKONOS_programFir(device, TX1TX2_FIR, device->tx->txProfile->txFir);
1389             if (retVal != MYKONOS_ERR_OK)
1390             {
1391                 return retVal;
1392             }
1393         }
1394     }
1395 
1396     if (device->profilesValid & RX_PROFILE_VALID)
1397     {
1398         if (device->rx->rxProfile->rxFir != NULL)
1399         {
1400             retVal = MYKONOS_programFir(device, RX1RX2_FIR, device->rx->rxProfile->rxFir);
1401             if (retVal != MYKONOS_ERR_OK)
1402             {
1403                 return retVal;
1404             }
1405 
1406             /* Load Rx gain table */
1407             retVal = MYKONOS_programRxGainTable(device, &RxGainTable[0][0], (sizeof(RxGainTable) >> 2), RX1_RX2_GT);
1408             if (retVal != MYKONOS_ERR_OK)
1409             {
1410                 return retVal;
1411             }
1412 
1413             retVal = MYKONOS_setRx1ManualGain(device, device->rx->rxGainCtrl->rx1GainIndex);
1414             if (retVal != MYKONOS_ERR_OK)
1415             {
1416                 return retVal;
1417             }
1418 
1419             retVal = MYKONOS_setRx2ManualGain(device, device->rx->rxGainCtrl->rx2GainIndex);
1420             if (retVal != MYKONOS_ERR_OK)
1421             {
1422                 return retVal;
1423             }
1424 
1425             /* Enable Digital gain for Rx and ObsRx gain tables */
1426             CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DIGITAL_GAIN_CONFIG, 0x80);
1427         }
1428     }
1429 
1430     if (device->profilesValid & SNIFF_PROFILE_VALID)
1431     {
1432         if (device->obsRx->snifferProfile->rxFir != NULL)
1433         {
1434             retVal = MYKONOS_programFir(device, OBSRX_B_FIR, device->obsRx->snifferProfile->rxFir);
1435             if (retVal != MYKONOS_ERR_OK)
1436             {
1437                 return retVal;
1438             }
1439 
1440             /* Load Sniffer Rx gain table */
1441             retVal = MYKONOS_programRxGainTable(device, &SnRxGainTable[0][0], (sizeof(SnRxGainTable) >> 2), SNRX_GT);
1442             if (retVal != MYKONOS_ERR_OK)
1443             {
1444                 return retVal;
1445             }
1446 
1447             retVal = MYKONOS_setObsRxManualGain(device, OBS_SNIFFER_A, device->obsRx->snifferGainCtrl->gainIndex);
1448             if (retVal != MYKONOS_ERR_OK)
1449             {
1450                 return retVal;
1451             }
1452         }
1453     }
1454 
1455     if (device->profilesValid & ORX_PROFILE_VALID)
1456     {
1457         if (device->obsRx->orxProfile->rxFir != NULL)
1458         {/* if pointer to orx rxFIR is valid */
1459             retVal = MYKONOS_programFir(device, OBSRX_A_FIR, device->obsRx->orxProfile->rxFir);
1460             if (retVal != MYKONOS_ERR_OK)
1461             {
1462                 return retVal;
1463             }
1464 
1465             /* Load ORx gain table */
1466             retVal = MYKONOS_programRxGainTable(device, &ORxGainTable[0][0], (sizeof(ORxGainTable) >> 2), ORX_GT);
1467             if (retVal != MYKONOS_ERR_OK)
1468             {
1469                 return retVal;
1470             }
1471 
1472             retVal = MYKONOS_setObsRxManualGain(device, OBS_RX1_TXLO, device->obsRx->orxGainCtrl->orx1GainIndex);
1473             if (retVal != MYKONOS_ERR_OK)
1474             {
1475                 return retVal;
1476             }
1477 
1478             retVal = MYKONOS_setObsRxManualGain(device, OBS_RX2_TXLO, device->obsRx->orxGainCtrl->orx2GainIndex);
1479             if (retVal != MYKONOS_ERR_OK)
1480             {
1481                 return retVal;
1482             }
1483         }
1484     }
1485 
1486     /* Load Loopback Gain Table for ARM calibrations */
1487     {
1488         uint8_t loopBackGainTable[6][4] = {
1489         /* Order: {FE table, External Ctl, Digital Gain/Atten, Enable Atten} */
1490         {0, 0, 0, 0}, /* Gain index 255 */
1491         {7, 0, 0, 0}, /* Gain index 254 */
1492         {13, 0, 1, 1}, /* Gain index 253 */
1493         {18, 0, 3, 1}, /* Gain index 252 */
1494         {23, 0, 3, 1}, /* Gain index 251 */
1495         {28, 0, 0, 0} /* Gain index 250 */
1496         };
1497         retVal = MYKONOS_programRxGainTable(device, &loopBackGainTable[0][0], (sizeof(loopBackGainTable) >> 2), LOOPBACK_GT);
1498     }
1499 
1500     /* Enable Digital gain for ORx/Sniffer/Loopback gain table */
1501     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DPD_SNIFFER_DIGITAL_GAIN_CONFIG, 0x80);
1502 
1503     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RCAL_CONTROL, 0x07);/* Set RCAL code to nominal */
1504 
1505     /* If Valid Rx Profile or valid ObsRx profile, setup serializers */
1506     if ((device->profilesValid & RX_PROFILE_VALID) || (device->profilesValid & (ORX_PROFILE_VALID | SNIFF_PROFILE_VALID)))
1507     {
1508         retVal = MYKONOS_setupSerializers(device);
1509         if (retVal != MYKONOS_ERR_OK)
1510         {
1511             return retVal;
1512         }
1513     }
1514 
1515     if ((device->rx->rxChannels != RXOFF) && (device->profilesValid & RX_PROFILE_VALID))
1516     {
1517         retVal = MYKONOS_setupJesd204bFramer(device);
1518         if (retVal != MYKONOS_ERR_OK)
1519         {
1520             return retVal;
1521         }
1522     }
1523 
1524     if ((device->obsRx->obsRxChannelsEnable != MYK_OBS_RXOFF) && (device->profilesValid & (ORX_PROFILE_VALID | SNIFF_PROFILE_VALID)))
1525     {
1526         retVal = MYKONOS_setupJesd204bObsRxFramer(device);
1527         if (retVal != MYKONOS_ERR_OK)
1528         {
1529             return retVal;
1530         }
1531     }
1532 
1533     if ((device->tx->txChannels != TXOFF) && (device->profilesValid & TX_PROFILE_VALID))
1534     {
1535         retVal = MYKONOS_setupDeserializers(device);
1536         if (retVal != MYKONOS_ERR_OK)
1537         {
1538             return retVal;
1539         }
1540 
1541         retVal = MYKONOS_setupJesd204bDeframer(device);
1542         if (retVal != MYKONOS_ERR_OK)
1543         {
1544             return retVal;
1545         }
1546 
1547         retVal = MYKONOS_setTx1Attenuation(device, device->tx->tx1Atten_mdB);
1548         if (retVal != MYKONOS_ERR_OK)
1549         {
1550             return retVal;
1551         }
1552 
1553         retVal = MYKONOS_setTx2Attenuation(device, device->tx->tx2Atten_mdB);
1554         if (retVal != MYKONOS_ERR_OK)
1555         {
1556             return retVal;
1557         }
1558     }
1559 
1560     return MYKONOS_ERR_OK;
1561 }
1562 
1563 /**
1564  * \brief Performs a blocking wait for a Mykonos calibration or Pll Lock
1565  *
1566  * <B>Dependencies</B>
1567  * - device->spiSettings
1568  * - device->spiSettings->chipSelectIndex
1569  *
1570  * \param device Pointer to the Mykonos device data structure containing settings
1571  * \param waitEvent the enum value of the event to wait for
1572  * \param timeout_us If timeout_us time has passed, function will return with
1573  *                   an error.
1574  * \return Returns enum mykonosErr_t, MYKONOS_ERR_OK=pass, !MYKONOS_ERR_OK=fail
1575  */
MYKONOS_waitForEvent(mykonosDevice_t * device,waitEvent_t waitEvent,uint32_t timeout_us)1576 mykonosErr_t MYKONOS_waitForEvent(mykonosDevice_t *device, waitEvent_t waitEvent, uint32_t timeout_us)
1577 {
1578     uint16_t spiAddr = 0;
1579     uint8_t spiBit = 0;
1580     uint8_t doneBitLevel = 0;
1581     uint8_t data = 0;
1582     mykonosErr_t errCode = MYKONOS_ERR_OK;
1583 
1584 #if (MYKONOS_VERBOSE == 1)
1585     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_waitForEvent()\n");
1586 #endif
1587 
1588     switch (waitEvent)
1589     {
1590         case CALPLL_LOCK:/* wait for x17F[7]=1 */
1591             spiAddr = MYKONOS_ADDR_CALPLL_SDM_CONTROL;
1592             spiBit = 7;
1593             doneBitLevel = 1;
1594             errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_CALPLL_LOCK;
1595             break;
1596         case CLKPLLCP: /* wait for x154[5]=1 */
1597             spiAddr = MYKONOS_ADDR_CLK_SYNTH_CAL_STAT;
1598             spiBit = 5;
1599             doneBitLevel = 1;
1600             errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_CLKPLLCP;
1601             break;
1602         case CLKPLL_LOCK: /* wait for x157[0]=1 */
1603             spiAddr = MYKONOS_ADDR_CLK_SYNTH_VCO_BAND_BYTE1;
1604             spiBit = 0;
1605             doneBitLevel = 1;
1606             errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_CLKPLL_LOCK;
1607             break;
1608         case RF_RXPLLCP:/* wait for x254[5]=1 */
1609             spiAddr = MYKONOS_ADDR_RXSYNTH_CP_CAL_STAT;
1610             spiBit = 5;
1611             doneBitLevel = 1;
1612             errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RXPLLCP;
1613             break;
1614         case RF_RXPLL_LOCK: /* wait for x257[0]=1 */
1615             spiAddr = MYKONOS_ADDR_RXSYNTH_VCO_BAND_BYTE1;
1616             spiBit = 0;
1617             doneBitLevel = 1;
1618             errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RXPLL_LOCK;
1619             break;
1620         case RF_TXPLLCP: /* wait for x2C4[5]=1 */
1621             spiAddr = MYKONOS_ADDR_TXSYNTH_CP_CAL_STAT;
1622             spiBit = 5;
1623             doneBitLevel = 1;
1624             errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_TXPLLCP;
1625             break;
1626         case RF_TXPLL_LOCK: /* wait for x2C7[0]=1 */
1627             spiAddr = MYKONOS_ADDR_TXSYNTH_VCO_BAND_BYTE1;
1628             spiBit = 0;
1629             doneBitLevel = 1;
1630             errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_TXPLL_LOCK;
1631             break;
1632         case RF_SNIFFERPLLCP: /* wait for x354[7]=1 */
1633             spiAddr = MYKONOS_ADDR_SNIFF_RXSYNTH_CP_CAL_STAT;
1634             spiBit = 5;
1635             doneBitLevel = 1;
1636             errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_SNIFFPLLCP;
1637             break;
1638         case RF_SNIFFERPLL_LOCK: /* wait for x357[0]=1 */
1639             spiAddr = MYKONOS_ADDR_SNIFF_RXSYNTH_VCO_BAND_BYTE1;
1640             spiBit = 0;
1641             doneBitLevel = 1;
1642             errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_SNIFFPLL_LOCK;
1643             break;
1644         case RXBBF_CALDONE: /* wait for x1B2[5]=0 */
1645             spiAddr = MYKONOS_ADDR_CALIBRATION_CONTROL;
1646             spiBit = 5;
1647             doneBitLevel = 0;
1648             errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RXBBFCALDONE;
1649             break;
1650         case TXBBF_CALDONE:/* wait for x1B2[0]=0 */
1651             spiAddr = MYKONOS_ADDR_CALIBRATION_CONTROL;
1652             spiBit = 0;
1653             doneBitLevel = 0;
1654             errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_TXBBFCALDONE;
1655             break;
1656         case RX_RFDC_CALDONE: /* wait for x1B2[1]=0 */
1657             spiAddr = MYKONOS_ADDR_CALIBRATION_CONTROL;
1658             spiBit = 1;
1659             doneBitLevel = 0;
1660             errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RFDCCALDONE;
1661             break;
1662         case RX_ADCTUNER_CALDONE:/* wait for x1B2[7]=0 */
1663             spiAddr = MYKONOS_ADDR_CALIBRATION_CONTROL;
1664             spiBit = 7;
1665             doneBitLevel = 0;
1666             errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_ADCTUNECALDONE;
1667             break;
1668         case RX1_ADCPROFILE:/* wait for x5DD[5]=0 */
1669             spiAddr = MYKONOS_ADDR_RX_ADC1_PRFL;
1670             spiBit = 5;
1671             doneBitLevel = 0;
1672             errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RX1ADCPROFILE;
1673             break;
1674         case RX2_ADCPROFILE:/* wait for x5DE[5]=0 */
1675             spiAddr = MYKONOS_ADDR_RX_ADC2_PRFL;
1676             spiBit = 5;
1677             doneBitLevel = 0;
1678             errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RX2ADCPROFILE;
1679             break;
1680         case ORX_ADCPROFILE:/* wait for x5DF[5]=0 */
1681             spiAddr = MYKONOS_ADDR_ORX_ADC_PRFL;
1682             spiBit = 5;
1683             doneBitLevel = 0;
1684             errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_ORXADCPROFILE;
1685             break;
1686         case RCAL_CALDONE: /* wait for x1B2[6]=0 */
1687             spiAddr = MYKONOS_ADDR_CALIBRATION_CONTROL;
1688             spiBit = 6;
1689             doneBitLevel = 0;
1690             errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RCALDONE;
1691             break;
1692         case ARMBUSY:/* wait for xD30[7]=0 */
1693             spiAddr = MYKONOS_ADDR_ARM_CMD;
1694             spiBit = 7;
1695             doneBitLevel = 0;
1696             errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_ARMBUSY;
1697             break;
1698         case INITARM_DONE:
1699             spiAddr = MYKONOS_ADDR_ARM_CMD;
1700             spiBit = 7;
1701             doneBitLevel = 0;
1702             errCode = MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_INITARMDONE;
1703             break;
1704         default:
1705             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_WAITFOREVENT_INV_PARM,
1706                     getMykonosErrorMessage(MYKONOS_ERR_WAITFOREVENT_INV_PARM));
1707             return MYKONOS_ERR_WAITFOREVENT_INV_PARM;
1708     }
1709 
1710     CMB_setTimeout_us(device->spiSettings, timeout_us); /* timeout after desired time */
1711 
1712     do
1713     {
1714         CMB_SPIReadByte(device->spiSettings, spiAddr, &data);
1715 
1716         /* For SW verification tests, allow API to think all cals are complete*/
1717 #ifdef MYK_CALS_DONE_SWDEBUG
1718         if (doneBitLevel == 0)
1719         {
1720             data = 0x00;
1721         }
1722         else
1723         {
1724             data = 0xFF;
1725         }
1726 #endif
1727 
1728         if ((uint32_t)CMB_hasTimeoutExpired(device->spiSettings) > 0)
1729         {
1730             CMB_writeToLog(ADIHAL_LOG_WARNING, device->spiSettings->chipSelectIndex, errCode, getMykonosErrorMessage(errCode));
1731             return errCode;
1732         }
1733     } while (((data >> spiBit) & 0x01) != doneBitLevel);
1734 
1735     return MYKONOS_ERR_OK;
1736 }
1737 
1738 /**
1739  * \brief Performs a readback with no wait for a Mykonos calibration or Pll Lock
1740  *
1741  * <B>Dependencies</B>
1742  * - device->spiSettings
1743  * - device->spiSettings->chipSelectIndex
1744  *
1745  * \param device Pointer to the Mykonos device data structure containing settings
1746  * \param waitEvent the enum value of the event to wait for
1747  * \param eventDone Return value: 1= calibration event is complete.  0 = Event is still pending
1748  * \return Returns enum mykonosErr_t, MYKONOS_ERR_OK=pass, !MYKONOS_ERR_OK=fail
1749  */
MYKONOS_readEventStatus(mykonosDevice_t * device,waitEvent_t waitEvent,uint8_t * eventDone)1750 mykonosErr_t MYKONOS_readEventStatus(mykonosDevice_t *device, waitEvent_t waitEvent, uint8_t *eventDone)
1751 {
1752     uint16_t spiAddr = 0;
1753     uint8_t data = 0;
1754     uint8_t spiBit = 0;
1755     uint8_t doneBitLevel = 0;
1756 
1757     switch (waitEvent)
1758     {
1759         case CALPLL_LOCK:/* wait for x17F[7]=1 */
1760             spiAddr = MYKONOS_ADDR_CALPLL_SDM_CONTROL;
1761             spiBit = 7;
1762             doneBitLevel = 1;
1763             break;
1764         case CLKPLLCP: /* wait for x154[5]=1 */
1765             spiAddr = MYKONOS_ADDR_CLK_SYNTH_CAL_STAT;
1766             spiBit = 5;
1767             doneBitLevel = 1;
1768             break;
1769         case CLKPLL_LOCK: /* wait for x157[0]=1 */
1770             spiAddr = MYKONOS_ADDR_CLK_SYNTH_VCO_BAND_BYTE1;
1771             spiBit = 0;
1772             doneBitLevel = 1;
1773             break;
1774         case RF_RXPLLCP:/* wait for x254[5]=1 */
1775             spiAddr = MYKONOS_ADDR_RXSYNTH_CP_CAL_STAT;
1776             spiBit = 5;
1777             doneBitLevel = 1;
1778             break;
1779         case RF_RXPLL_LOCK: /* wait for x257[0]=1 */
1780             spiAddr = MYKONOS_ADDR_RXSYNTH_VCO_BAND_BYTE1;
1781             spiBit = 0;
1782             doneBitLevel = 1;
1783             break;
1784         case RF_TXPLLCP: /* wait for x2C4[5]=1 */
1785             spiAddr = MYKONOS_ADDR_TXSYNTH_CP_CAL_STAT;
1786             spiBit = 5;
1787             doneBitLevel = 1;
1788             break;
1789         case RF_TXPLL_LOCK: /* wait for x2C7[0]=1 */
1790             spiAddr = MYKONOS_ADDR_TXSYNTH_VCO_BAND_BYTE1;
1791             spiBit = 0;
1792             doneBitLevel = 1;
1793             break;
1794         case RF_SNIFFERPLLCP: /* wait for x354[7]=1 */
1795             spiAddr = MYKONOS_ADDR_SNIFF_RXSYNTH_CP_CAL_STAT;
1796             spiBit = 5;
1797             doneBitLevel = 1;
1798             break;
1799         case RF_SNIFFERPLL_LOCK: /* wait for x357[0]=1 */
1800             spiAddr = MYKONOS_ADDR_SNIFF_RXSYNTH_VCO_BAND_BYTE1;
1801             spiBit = 0;
1802             doneBitLevel = 1;
1803             break;
1804         case RXBBF_CALDONE: /* wait for x1B2[5]=0 */
1805             spiAddr = MYKONOS_ADDR_CALIBRATION_CONTROL;
1806             spiBit = 5;
1807             doneBitLevel = 0;
1808             break;
1809         case TXBBF_CALDONE:/* wait for x1B2[0]=0 */
1810             spiAddr = MYKONOS_ADDR_CALIBRATION_CONTROL;
1811             spiBit = 0;
1812             doneBitLevel = 0;
1813             break;
1814         case RX_RFDC_CALDONE: /* wait for x1B2[1]=0 */
1815             spiAddr = MYKONOS_ADDR_CALIBRATION_CONTROL;
1816             spiBit = 1;
1817             doneBitLevel = 0;
1818             break;
1819         case RX_ADCTUNER_CALDONE:/* wait for x1B2[7]=0 */
1820             spiAddr = MYKONOS_ADDR_CALIBRATION_CONTROL;
1821             spiBit = 7;
1822             doneBitLevel = 0;
1823             break;
1824         case RX1_ADCPROFILE:/* wait for x5DD[5]=0 */
1825             spiAddr = MYKONOS_ADDR_RX_ADC1_PRFL;
1826             spiBit = 5;
1827             doneBitLevel = 0;
1828             break;
1829         case RX2_ADCPROFILE:/* wait for x5DE[5]=0 */
1830             spiAddr = MYKONOS_ADDR_RX_ADC2_PRFL;
1831             spiBit = 5;
1832             doneBitLevel = 0;
1833             break;
1834         case ORX_ADCPROFILE:/* wait for x5DF[5]=0 */
1835             spiAddr = MYKONOS_ADDR_ORX_ADC_PRFL;
1836             spiBit = 5;
1837             doneBitLevel = 0;
1838             break;
1839         case RCAL_CALDONE: /* wait for x1B2[6]=0 */
1840             spiAddr = MYKONOS_ADDR_CALIBRATION_CONTROL;
1841             spiBit = 6;
1842             doneBitLevel = 0;
1843             break;
1844         case ARMBUSY:/* wait for xD30[7]=0 */
1845             spiAddr = MYKONOS_ADDR_ARM_CMD;
1846             spiBit = 7;
1847             doneBitLevel = 0;
1848             break;
1849         default:
1850             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_WAITFOREVENT_INV_PARM,
1851                     getMykonosErrorMessage(MYKONOS_ERR_WAITFOREVENT_INV_PARM));
1852             return MYKONOS_ERR_WAITFOREVENT_INV_PARM;
1853     }
1854 
1855     CMB_SPIReadByte(device->spiSettings, spiAddr, &data);
1856 
1857     if (doneBitLevel)
1858     {
1859         *eventDone = (data >> spiBit) & 0x01;
1860     }
1861     else
1862     {
1863         *eventDone = (~(data >> spiBit)  & 0x01);
1864     }
1865 
1866     return MYKONOS_ERR_OK;
1867 }
1868 
1869 /**
1870  * \brief Sets the CLKPLL output frequency.
1871  *
1872  * This code updates the Synth and Loop filter settings based on a VCO
1873  * frequency LUT. The VCO frequency break points for the Synth LUT can be
1874  * found in an array called vcoFreqArrayMhz.
1875  *
1876  * <B>Dependencies</B>
1877  * - device->spiSettings->chipSelectIndex
1878  * - device->spiSettings
1879  * - device->deviceClock_kHz
1880  * - device->rxSettings->rxProfile->vcoFreq_kHz
1881  * - device->rxSettings->rxProfile->clkPllHsDiv
1882  * - device->rxSettings->rxProfile->clkPllVcoDiv
1883  *
1884  * \param device is structure pointer to the MYKONOS data structure containing settings
1885  *
1886  * \return Returns enum MYKONOS_ERR, MYKONOS_ERR_OK=pass, !MYKONOS_ERR_OK=fail
1887  */
MYKONOS_initDigitalClocks(mykonosDevice_t * device)1888 mykonosErr_t MYKONOS_initDigitalClocks(mykonosDevice_t *device)
1889 {
1890     /* RF Synth variables */
1891     /* pull Synth and Loop filter values from a Look Up Table */
1892     uint8_t vcoOutLvl;
1893     uint8_t vcoVaractor; /* [3:0] */
1894     uint8_t vcoBiasRef; /* [2:0] */
1895     uint8_t vcoBiasTcf; /* [1:0] */
1896     uint8_t vcoCalOffset; /* [3:0] */
1897     uint8_t vcoVaractorRef; /* [3:0] */
1898     uint8_t loopFilterIcp; /* Icp[5:0] */
1899     uint8_t loopFilterC2C1; /* C2[3:0],C1[3:0] */
1900     uint8_t loopFilterR1C3; /* R1[3:0],C3[3:0] */
1901     uint8_t loopFilterR3; /* R3[3:0] */
1902     uint8_t vcoIndex;
1903     uint8_t i;
1904 
1905     /* RF PLL variables */
1906     uint16_t integerWord;
1907     uint32_t fractionalWord;
1908     uint32_t fractionalRemainder;
1909     uint32_t scaledRefClk_Hz;
1910 
1911     /* common */
1912     uint64_t hsDigClk_Hz = 0;
1913     uint32_t scaledRefClk_kHz = 0;
1914     uint8_t deviceClkDiv = 0;
1915     mykonosErr_t retVal = MYKONOS_ERR_OK;
1916 
1917     uint8_t clockControl2 = 0;
1918     uint8_t sdmSettings = 0;
1919     uint8_t hsDiv = 4;
1920     uint8_t vcoDiv = 0;
1921     uint8_t vcoDivTimes10 = 10;
1922 
1923     /******************RF Synth Section************************/
1924     static const uint8_t icp_46p08[53] = {15, 15, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 27, 27, 28, 29, 30, 31, 32, 33, 32, 33, 32, 33, 33, 34, 27, 28, 29,
1925             29, 30, 39, 29, 30, 31, 31, 30, 31, 31, 32, 30, 31, 31, 32, 32, 31, 31, 32, 32, 33};
1926 
1927     static const uint8_t icp_61p44[53] = {13, 13, 13, 14, 15, 16, 16, 17, 18, 19, 20, 21, 22, 22, 23, 24, 24, 25, 25, 26, 27, 28, 29, 28, 29, 28, 29, 29, 30, 24, 25, 25,
1928             26, 26, 35, 33, 34, 35, 35, 26, 27, 27, 28, 27, 27, 27, 28, 28, 27, 27, 28, 28, 29};
1929 
1930     static const uint8_t icp_76p8[53] = {7, 7, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15, 16, 15, 16, 15, 16, 16, 17, 13, 14, 14, 14, 15,
1931             19, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 15, 15, 15, 16, 16};
1932 
1933     static const uint32_t vcoFreqArray_kHz[53] = {12605000UL, 12245000UL, 11906000UL, 11588000UL, 11288000UL, 11007000UL, 10742000UL, 10492000UL, 10258000UL, 10036000UL,
1934             9827800UL, 9631100UL, 9445300UL, 9269800UL, 9103600UL, 8946300UL, 8797000UL, 8655300UL, 8520600UL, 8392300UL, 8269900UL, 8153100UL, 8041400UL, 7934400UL,
1935             7831800UL, 7733200UL, 7638400UL, 7547100UL, 7459000UL, 7374000UL, 7291900UL, 7212400UL, 7135500UL, 7061000UL, 6988700UL, 6918600UL, 6850600UL, 6784600UL,
1936             6720500UL, 6658200UL, 6597800UL, 6539200UL, 6482300UL, 6427000UL, 6373400UL, 6321400UL, 6270900UL, 6222000UL, 6174500UL, 6128400UL, 6083600UL, 6040100UL,
1937             5997700UL};
1938 
1939 #if (MYKONOS_VERBOSE == 1)
1940     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_initDigitalClocks()\n");
1941 #endif
1942 
1943     retVal = MYKONOS_calculateScaledDeviceClk_kHz(device, &scaledRefClk_kHz, &deviceClkDiv);
1944     if (retVal != MYKONOS_ERR_OK)
1945     {
1946         return retVal;
1947     }
1948 
1949     hsDiv = device->clocks->clkPllHsDiv;
1950     vcoDiv = device->clocks->clkPllVcoDiv;
1951 
1952     switch (hsDiv)
1953     {
1954         case 4:
1955             hsDiv = 4; /* clockControl2[3:2] = 00 */
1956             break;
1957         case 5:
1958             hsDiv = 5;
1959             clockControl2 |= 0x04; /* Set bit[2]=1 */
1960             break;
1961         default:
1962             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CLKPLL_INV_HSDIV, getMykonosErrorMessage(MYKONOS_ERR_CLKPLL_INV_HSDIV));
1963             return MYKONOS_ERR_CLKPLL_INV_HSDIV;
1964     }
1965 
1966     switch (vcoDiv)
1967     {
1968         case VCODIV_1:
1969             vcoDivTimes10 = 10; /* clockControl2[1:0] = 00 */
1970             break;
1971         case VCODIV_1p5:
1972             vcoDivTimes10 = 15;
1973             clockControl2 |= 0x01;
1974             break;
1975         case VCODIV_2:
1976             vcoDivTimes10 = 20;
1977             clockControl2 |= 0x02;
1978             break;
1979         case VCODIV_3:
1980             vcoDivTimes10 = 30;
1981             clockControl2 |= 0x03;
1982             break;
1983         default:
1984             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CLKPLL_INV_VCODIV, getMykonosErrorMessage(MYKONOS_ERR_CLKPLL_INV_VCODIV));
1985             return MYKONOS_ERR_CLKPLL_INV_VCODIV;
1986     }
1987 
1988     clockControl2 |= ((deviceClkDiv & 3) << 4);
1989 
1990     /* find vco table index based on vco frequency */
1991     for (i = 0; device->clocks->clkPllVcoFreq_kHz < vcoFreqArray_kHz[i]; i++)
1992     {
1993         /* Intentionally blank, for loop exits when condition met, index i used below */
1994     }
1995     vcoIndex = i + 1;
1996 
1997     if (vcoIndex < 1 || vcoIndex > 53)
1998     {
1999         /* vco index out of range */
2000         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETCLKPLL_INV_VCOINDEX,
2001                 getMykonosErrorMessage(MYKONOS_ERR_SETCLKPLL_INV_VCOINDEX));
2002         return MYKONOS_ERR_SETCLKPLL_INV_VCOINDEX;
2003     }
2004 
2005     /* valid for all refclk frequencies */
2006     vcoOutLvl = (vcoIndex <= 16) ? 13 : (vcoIndex <= 23) ? 12 : (vcoIndex <= 25) ?
2007                 11 : (vcoIndex <= 35) ? 10 : (vcoIndex <= 39) ? 9 : (vcoIndex <= 43) ?
2008                 8 :  (vcoIndex <= 48) ? 7 : 6;
2009     vcoVaractor = (vcoIndex <= 29 || vcoIndex == 35) ?  1 : 2;
2010     vcoBiasRef = (vcoIndex <= 7 ) ?  4 : (vcoIndex <= 16) ? 6 : 7;
2011     vcoBiasTcf = (vcoIndex <= 25 || (vcoIndex > 26 && vcoIndex <= 29) ||
2012                  (vcoIndex > 37 && vcoIndex <= 39)) || (vcoIndex > 40 && vcoIndex <= 43) ?
2013                  2 : 3;
2014 
2015     vcoVaractorRef = (vcoIndex <= 29) ? 12 : (vcoIndex == 35) ? 14 :  13;
2016 
2017     if ((scaledRefClk_kHz >= 40000) && (scaledRefClk_kHz < 53760))
2018     { /* Settings designed for 46.08 MHz PLL REFCLK */
2019         vcoCalOffset   = (vcoIndex == 11 || (vcoIndex > 35 && vcoIndex <= 37) || (vcoIndex > 29 && vcoIndex <= 34)|| vcoIndex == 40 || vcoIndex == 44) ?
2020                          14 :(vcoIndex <= 10 || vcoIndex > 44) ?
2021                          15 : ((vcoIndex > 12 && vcoIndex <= 22) || (vcoIndex > 23 && vcoIndex <= 23) || (vcoIndex > 26 && vcoIndex <= 29) || (vcoIndex > 23 && vcoIndex <= 25) || vcoIndex == 35) ?
2022                          12 : 13;
2023 
2024         loopFilterIcp = icp_46p08[vcoIndex - 1];
2025         loopFilterC2C1 = 0xF9; /* C2=0xF0 */
2026         loopFilterR1C3 = 0xD5;
2027         loopFilterR3 = 0x0E;
2028     }
2029     else if ((scaledRefClk_kHz >= 53760) && (scaledRefClk_kHz < 69120))
2030     { /* Settings designed for 61.44 MHz PLL REFCLK */
2031         vcoCalOffset   = (vcoIndex == 11 || (vcoIndex > 29 && vcoIndex <= 34) || vcoIndex == 40 || vcoIndex == 44) ?
2032                          14 :(vcoIndex <= 10 || vcoIndex > 44) ?
2033                          15 : ((vcoIndex > 12 && vcoIndex <= 22) || (vcoIndex > 23 && vcoIndex <= 25) || (vcoIndex > 26 && vcoIndex <= 29) || (vcoIndex > 34 && vcoIndex <= 37)) ?
2034                          12 : (vcoIndex > 37 && vcoIndex <= 39) ? 11 : 13;
2035 
2036         vcoVaractor = (vcoIndex > 35 && vcoIndex <= 39) ? 1 : vcoVaractor;
2037         vcoBiasRef = (vcoIndex > 4 && vcoIndex <= 7) ? 5 : vcoBiasRef;
2038         vcoVaractorRef = (vcoIndex > 35 && vcoIndex <= 39) ? 14 : vcoVaractorRef;
2039         loopFilterIcp  = icp_61p44[vcoIndex-1];
2040         loopFilterC2C1 = ((vcoIndex > 2 && vcoIndex <= 6) || (vcoIndex > 8 && vcoIndex <= 13) || (vcoIndex > 14)) ? 0xFD : 0xFC; /* C2=0xF0 */
2041         loopFilterR1C3 = 0xC5;
2042         loopFilterR3   = (vcoIndex <= 2 || (vcoIndex > 6 && vcoIndex <= 8) || vcoIndex == 14) ? 14 : 13 ;
2043     }
2044     else if ((scaledRefClk_kHz >= 69120) && (scaledRefClk_kHz <= 80000))
2045     { /* Settings designed for 76.8 MHz PLL REFCLK */
2046         vcoCalOffset   = (vcoIndex == 11 || (vcoIndex > 35 && vcoIndex <= 37) || (vcoIndex > 29 && vcoIndex <= 34)|| vcoIndex == 40 || vcoIndex == 44) ?
2047                          14 :(vcoIndex <= 10 || vcoIndex > 44) ?
2048                          15 : ((vcoIndex > 12 && vcoIndex <= 22) || (vcoIndex > 23 && vcoIndex <= 23) || (vcoIndex > 26 && vcoIndex <= 29) || (vcoIndex > 23 && vcoIndex <= 25) || vcoIndex == 35) ?
2049                          12 : 13;
2050 
2051         loopFilterIcp  = icp_76p8[vcoIndex-1];
2052         loopFilterC2C1 = (vcoIndex == 20 ) ? 0xF7 : (vcoIndex == 4 || vcoIndex == 6 || vcoIndex == 8 ) ? 0xE6: 0xF6; /*C2=0xF0, C1=6 or 7 */
2053         loopFilterR1C3 = (vcoIndex == 4 ) ? 0xE4 : 0xD5;
2054         loopFilterR3   = 0x0E;
2055     }
2056     else
2057     {
2058         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETRFPLL_INV_REFCLK, getMykonosErrorMessage(MYKONOS_ERR_SETRFPLL_INV_REFCLK));
2059         return MYKONOS_ERR_SETRFPLL_INV_REFCLK; /* invalid ref clk */
2060     }
2061 
2062     /* Hold CLKPLL digital logic in reset */
2063     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_4, 0x00);
2064 
2065     /* Set reference clock scaler + HSdiv + VCOdiv */
2066     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_2, clockControl2);
2067 
2068     /*Set VCO cal time */
2069     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_CAL_CONTROL, 0x02);
2070 
2071     /* Write Synth Setting regs */
2072     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_F_VCOTN_BYTE1, ((vcoCalOffset & 0x0F) << 3)); /* Set VCO Cal offset[3:0] */
2073     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_BYTE1, (0xC0 | (vcoVaractor & 0x0F))); /* Init ALC[3:0], VCO varactor[3:0] */
2074     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_BYTE2, (0x40 | (vcoOutLvl & 0x0F))); /* VCO output level */
2075     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_BYTE9, (((vcoBiasTcf & 0x03) << 3) | (vcoBiasRef & 0x07))); /* Set VCO Bias Tcf[1:0] and VCO Bias Ref[2:0] */
2076     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_VCO_CAL_REF, 0x30); /* Set VCO cal time (compare length) + Set VCO Cal Ref Tcf[2:0]=0 */
2077     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_VCO_VAR_CTL1, 0x70); /* Set VCO Varactor Ref Tcf[2:0] and VCO Varactor Offset[3:0] */
2078     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_VCO_VAR_CTL2, (vcoVaractorRef & 0x0F)); /* Set VCO Varactor Reference[3:0] */
2079 
2080     /* Write Loop filter */
2081     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_BYTE3, (0x80 | (loopFilterIcp & 0x03F))); /* Set Loop Filter Icp[5:0] */
2082     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_BYTE6, loopFilterC2C1); /* Set Loop Filter C2[3:0] and C1[3:0] */
2083     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_BYTE7, loopFilterR1C3); /* Set Loop Filter R1[3:0] and C3[3:0] */
2084     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_LF_R3, (loopFilterR3 & 0x0F)); /*Set Loop Filter R3[3:0] */
2085 
2086     /* Calculate PLL integer and fractional words with integer math */
2087     scaledRefClk_Hz = scaledRefClk_kHz * 1000;
2088     hsDigClk_Hz = (((uint64_t)(device->clocks->clkPllVcoFreq_kHz) * 10000) / vcoDivTimes10) / hsDiv;
2089     integerWord = (uint16_t)(hsDigClk_Hz / scaledRefClk_Hz);
2090     fractionalRemainder = hsDigClk_Hz % scaledRefClk_Hz;
2091 
2092     /* +1 >> 1 is rounding (add .5) */
2093     fractionalWord = ((uint32_t)((((uint64_t)fractionalRemainder * 4177920) / (uint64_t)scaledRefClk_Hz) + 1) >> 1);
2094 
2095     /* if fractionalWord rounded up and == PLL modulus, fix it */
2096     if (fractionalWord == 2088960)
2097     {
2098         fractionalWord = 0;
2099         integerWord = integerWord + 1;
2100     }
2101 
2102     if (fractionalWord > 0)
2103     { /* in normal case, the fractional word should be zero and SDM bypassed */
2104         CMB_writeToLog(ADIHAL_LOG_WARNING, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETCLKPLL_INV_FRACWORD,
2105                 getMykonosErrorMessage(MYKONOS_ERR_SETCLKPLL_INV_FRACWORD));
2106         /* down graded to warning, do not return error code */
2107         //return MYKONOS_ERR_SETCLKPLL_INV_FRACWORD;
2108         sdmSettings = 0x20;
2109     }
2110     else
2111     {
2112         /* Bypass SDM */
2113         sdmSettings = 0xE0;
2114     }
2115 
2116     /* Set PLL fractional word[22:0] */
2117     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_DIVIDER_FRAC_BYTE0, (fractionalWord & 0xFF));
2118     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_DIVIDER_FRAC_BYTE1, ((fractionalWord >> 8) & 0xFF));
2119     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_DIVIDER_FRAC_BYTE2, ((fractionalWord >> 16) & 0x7F));
2120 
2121     /* Write PLL integer word [7:0] */
2122     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_DIVIDER_INT_BYTE1, (sdmSettings | ((integerWord >> 8) & 0x7)));
2123     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_DIVIDER_INT_BYTE0, (integerWord & 0xFF));
2124 
2125     /* Release PLL from reset, and set start VCO cal bit to 0 */
2126     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_4, 0x80);
2127 
2128     /* Power up CLKPLL */
2129     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_0, 0x00);
2130     CMB_wait_ms(200); /* Allow PLL time to power up */
2131 
2132     /* Enable Charge pump cal after Charge Pump current set (Icp[5:0]) */
2133     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_BYTE5, 0x84);
2134 
2135     /* Start VCO Cal */
2136     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_4, 0x81);
2137 
2138     return MYKONOS_ERR_OK;
2139 }
2140 
2141 /**
2142  * \brief Sets the RF PLL local oscillator frequency (RF carrier frequency).
2143  *
2144  * <B>Dependencies</B>
2145  * - device->spiSettings->chipSelectIndex
2146  * - device->spiSettings
2147  *
2148  * \param device is structure pointer to the MYKONOS data structure containing settings
2149  * \param pllName Name of the PLL to configure
2150  * \param rfPllLoFrequency_Hz Desired RF LO frequency
2151  *
2152  * \return MYKONOS_ERR_OK Function completed successfully
2153  * \return MYKONOS_ERR_SETRFPLL_ARMERROR ARM Command to set RF PLL frequency failed
2154  */
MYKONOS_setRfPllFrequency(mykonosDevice_t * device,mykonosRfPllName_t pllName,uint64_t rfPllLoFrequency_Hz)2155 mykonosErr_t MYKONOS_setRfPllFrequency(mykonosDevice_t *device, mykonosRfPllName_t pllName, uint64_t rfPllLoFrequency_Hz)
2156 {
2157     const uint8_t SETCMD_OPCODE = 0x0A;
2158     const uint8_t SET_PLL_FREQUENCY = 0x63;
2159 
2160     mykonosErr_t retVal = MYKONOS_ERR_OK;
2161     uint8_t armData[8] = {0};
2162     uint8_t extData[2] = {0};
2163     uint32_t timeoutMs = 0;
2164     uint8_t cmdStatusByte = 0;
2165 
2166     armData[0] = (uint8_t)(rfPllLoFrequency_Hz & 0xFF);
2167     armData[1] = (uint8_t)((rfPllLoFrequency_Hz >> 8) & 0xFF);
2168     armData[2] = (uint8_t)((rfPllLoFrequency_Hz >> 16) & 0xFF);
2169     armData[3] = (uint8_t)((rfPllLoFrequency_Hz >> 24) & 0xFF);
2170     armData[4] = (uint8_t)((rfPllLoFrequency_Hz >> 32) & 0xFF);
2171     armData[5] = (uint8_t)((rfPllLoFrequency_Hz >> 40) & 0xFF);
2172     armData[6] = (uint8_t)((rfPllLoFrequency_Hz >> 48) & 0xFF);
2173     armData[7] = (uint8_t)((rfPllLoFrequency_Hz >> 56) & 0xFF);
2174 
2175     /* write 64-bit frequency to ARM memory */
2176     retVal = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &armData[0], 8);
2177     if (retVal != MYKONOS_ERR_OK)
2178     {
2179         return retVal;
2180     }
2181 
2182     extData[0] = SET_PLL_FREQUENCY;
2183 
2184     switch (pllName)
2185     {
2186         case RX_PLL:
2187             extData[1] = 0x00;
2188             break;
2189         case TX_PLL:
2190             extData[1] = 0x01;
2191             break;
2192         case SNIFFER_PLL:
2193             extData[1] = 0x02;
2194             break;
2195         default:
2196         {
2197             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETRFPLL_INV_PLLNAME,
2198                     getMykonosErrorMessage(MYKONOS_ERR_SETRFPLL_INV_PLLNAME));
2199             return MYKONOS_ERR_SETRFPLL_INV_PLLNAME;
2200         }
2201     }
2202 
2203     retVal = MYKONOS_sendArmCommand(device, SETCMD_OPCODE, &extData[0], sizeof(extData));
2204     if (retVal != MYKONOS_ERR_OK)
2205     {
2206         return retVal;
2207     }
2208 
2209     timeoutMs = 1000;
2210     retVal = MYKONOS_waitArmCmdStatus(device, SETCMD_OPCODE, timeoutMs, &cmdStatusByte);
2211     if (retVal != MYKONOS_ERR_OK)
2212     {
2213         if (cmdStatusByte > 0)
2214         {
2215             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETRFPLL_ARMERROR, getMykonosErrorMessage(MYKONOS_ERR_SETRFPLL_ARMERROR));
2216             return MYKONOS_ERR_SETRFPLL_ARMERROR;
2217         }
2218 
2219         return retVal;
2220     }
2221 
2222     if (cmdStatusByte > 0)
2223     {
2224         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETRFPLL_ARMERROR, getMykonosErrorMessage(MYKONOS_ERR_SETRFPLL_ARMERROR));
2225         return MYKONOS_ERR_SETRFPLL_ARMERROR;
2226     }
2227 
2228     return MYKONOS_ERR_OK;
2229 }
2230 
2231 /**
2232  * \brief Gets the RF PLL local oscillator frequency (RF carrier frequency).
2233  *
2234  * This function is used to get the RF PLL's frequency.  It can get the RX PLL, TX PLL
2235  * Sniffer PLL, and CLKPLL.
2236  *
2237  * <B>Dependencies</B>
2238  * - device->spiSettings->chipSelectIndex
2239  * - device->spiSettings
2240  * - device->clocks->deviceClock_kHz
2241  *
2242  * \param device is structure pointer to the MYKONOS data structure containing settings
2243  * \param pllName Name of the PLL for which to read the frequency
2244  * \param rfPllLoFrequency_Hz RF LO frequency currently set for the PLL specified
2245  *
2246  * \retval MYKONOS_ERR_OK Function completed successfully
2247  * \retval MYKONOS_ERR_GET_PLLFREQ_INV_REFCLKDIV Invalid CLKPLL reference clock divider read from Mykonos device
2248  * \retval MYKONOS_ERR_GET_PLLFREQ_INV_HSDIV Invalid CLKPLL high speed clock divider read from Mykonos device
2249  * \retval MYKONOS_ERR_GETRFPLL_INV_PLLNAME Invalid PLL name, can not get PLL frequency.  Use PLL name ENUM.
2250  * \retval MYKONOS_ERR_GETRFPLL_ARMERROR ARM Command to get RF PLL frequency failed
2251  * \retval MYKONOS_ERR_GETRFPLL_NULLPARAM rfPllLoFrequency_Hz function parameter pointer is NULL
2252  */
MYKONOS_getRfPllFrequency(mykonosDevice_t * device,mykonosRfPllName_t pllName,uint64_t * rfPllLoFrequency_Hz)2253 mykonosErr_t MYKONOS_getRfPllFrequency(mykonosDevice_t *device, mykonosRfPllName_t pllName, uint64_t *rfPllLoFrequency_Hz)
2254 {
2255     const uint8_t RFPLL_LO_FREQUENCY = 0x63;
2256 
2257     mykonosErr_t retVal = MYKONOS_ERR_OK;
2258     uint8_t armData[8] = {0, 0, 0, 0, 0, 0, 0, 0};
2259     uint8_t extData[2] = {0, 0};
2260     uint32_t timeoutMs = 0;
2261     uint8_t cmdStatusByte = 0;
2262     uint8_t getClkPllFrequency = 0;
2263 
2264     uint32_t clkPllIntWord = 0;
2265     uint32_t clkPllFracWord = 0;
2266     uint8_t clkPllRefClkDiv = 0;
2267     uint8_t hsDiv = 0;
2268     uint8_t vcoDivTimes10 = 0;
2269     uint8_t hsDivReg = 0;
2270     uint8_t vcoDivReg = 0;
2271     uint8_t clkPllIntWord7_0 = 0;
2272     uint8_t clkPllIntWord10_8 = 0;
2273     uint8_t clkPllFracWord7_0 = 0;
2274     uint8_t clkPllFracWord15_8 = 0;
2275     uint8_t clkPllFracWord22_16 = 0;
2276     uint64_t refclk_Hz = 0;
2277 
2278     extData[0] = RFPLL_LO_FREQUENCY;
2279 
2280     switch (pllName)
2281     {
2282         case CLK_PLL:
2283             getClkPllFrequency = 1;
2284             break;
2285         case RX_PLL:
2286             extData[1] = 0x00;
2287             break;
2288         case TX_PLL:
2289             extData[1] = 0x01;
2290             break;
2291         case SNIFFER_PLL:
2292             extData[1] = 0x02;
2293             break;
2294         default:
2295         {
2296             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRFPLL_INV_PLLNAME,
2297                     getMykonosErrorMessage(MYKONOS_ERR_GETRFPLL_INV_PLLNAME));
2298             return MYKONOS_ERR_GETRFPLL_INV_PLLNAME;
2299         }
2300     }
2301 
2302     if (getClkPllFrequency > 0)
2303     {
2304         CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_2, &hsDivReg, 0x0C, 2);
2305         CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_2, &vcoDivReg, 0x03, 0);
2306         CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_2, &clkPllRefClkDiv, 0x70, 4);
2307 
2308         CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_DIVIDER_INT_BYTE0, &clkPllIntWord7_0);
2309         CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_DIVIDER_INT_BYTE1, &clkPllIntWord10_8);
2310         CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_DIVIDER_FRAC_BYTE0, &clkPllFracWord7_0);
2311         CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_DIVIDER_FRAC_BYTE1, &clkPllFracWord15_8);
2312         CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_DIVIDER_FRAC_BYTE2, &clkPllFracWord22_16);
2313 
2314         clkPllIntWord = (((uint32_t)(clkPllIntWord10_8 & 0x7) << 8) | clkPllIntWord7_0);
2315         clkPllFracWord = (((uint32_t)(clkPllFracWord22_16 & 0x7F) << 16) | ((uint32_t)(clkPllFracWord15_8) << 8) | clkPllFracWord7_0);
2316 
2317         switch (clkPllRefClkDiv)
2318         {
2319             case 0:
2320                 refclk_Hz = ((uint64_t)device->clocks->deviceClock_kHz * 1000);
2321                 break;
2322             case 1:
2323                 refclk_Hz = (((uint64_t)device->clocks->deviceClock_kHz * 1000) >> 1);
2324                 break; /* div 2 */
2325             case 2:
2326                 refclk_Hz = (((uint64_t)device->clocks->deviceClock_kHz * 1000) >> 2);
2327                 break; /* div 4 */
2328             case 3:
2329                 refclk_Hz = (((uint64_t)device->clocks->deviceClock_kHz * 1000) << 1);
2330                 break; /* times 2 */
2331             default:
2332             {
2333                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_PLLFREQ_INV_REFCLKDIV,
2334                         getMykonosErrorMessage(MYKONOS_ERR_GET_PLLFREQ_INV_REFCLKDIV));
2335                 return MYKONOS_ERR_GET_PLLFREQ_INV_REFCLKDIV;
2336             }
2337         }
2338 
2339         switch (vcoDivReg)
2340         {
2341             case 0:
2342                 vcoDivTimes10 = 10;
2343                 break;
2344             case 1:
2345                 vcoDivTimes10 = 15;
2346                 break;
2347             case 2:
2348                 vcoDivTimes10 = 20;
2349                 break;
2350             case 3:
2351                 vcoDivTimes10 = 30;
2352                 break;
2353             default:
2354             {
2355                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_PLLFREQ_INV_VCODIV,
2356                         getMykonosErrorMessage(MYKONOS_ERR_GET_PLLFREQ_INV_VCODIV));
2357                 return MYKONOS_ERR_GET_PLLFREQ_INV_VCODIV;
2358             }
2359         }
2360 
2361         switch (hsDivReg)
2362         {
2363             case 0:
2364                 hsDiv = 4;
2365                 break;
2366             case 1:
2367                 hsDiv = 5;
2368                 break;
2369             default:
2370             {
2371                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_PLLFREQ_INV_HSDIV,
2372                         getMykonosErrorMessage(MYKONOS_ERR_GET_PLLFREQ_INV_HSDIV));
2373                 return MYKONOS_ERR_GET_PLLFREQ_INV_HSDIV;
2374             }
2375         }
2376 
2377         /* round to nearest Hz for fractional word (fractional modulus = 2088960) */
2378         *rfPllLoFrequency_Hz = (uint64_t)(((refclk_Hz * clkPllIntWord) + (((refclk_Hz * clkPllFracWord / 1044480) + 1) >> 1)) * hsDiv * vcoDivTimes10 / 10);
2379     }
2380     else
2381     {
2382         retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &extData[0], sizeof(extData));
2383         if (retVal != MYKONOS_ERR_OK)
2384         {
2385             return retVal;
2386         }
2387 
2388         timeoutMs = 1000;
2389         retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte);
2390         if (retVal != MYKONOS_ERR_OK)
2391         {
2392             if (cmdStatusByte > 0)
2393             {
2394                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRFPLL_ARMERROR,
2395                         getMykonosErrorMessage(MYKONOS_ERR_GETRFPLL_ARMERROR));
2396                 return MYKONOS_ERR_GETRFPLL_ARMERROR;
2397             }
2398 
2399             return retVal;
2400         }
2401 
2402         /* read 64-bit frequency from ARM memory */
2403         retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &armData[0], 8, 1);
2404         if (retVal != MYKONOS_ERR_OK)
2405         {
2406             return retVal;
2407         }
2408 
2409         if (cmdStatusByte > 0)
2410         {
2411             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRFPLL_ARMERROR, getMykonosErrorMessage(MYKONOS_ERR_GETRFPLL_ARMERROR));
2412             return MYKONOS_ERR_GETRFPLL_ARMERROR;
2413         }
2414 
2415         if (rfPllLoFrequency_Hz == NULL)
2416         {
2417             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRFPLL_NULLPARAM,
2418                     getMykonosErrorMessage(MYKONOS_ERR_GETRFPLL_NULLPARAM));
2419             return MYKONOS_ERR_GETRFPLL_NULLPARAM;
2420         }
2421 
2422         *rfPllLoFrequency_Hz = (uint64_t)((uint64_t)(armData[0])) | ((uint64_t)(armData[1]) << 8) | ((uint64_t)(armData[2]) << 16) | ((uint64_t)(armData[3]) << 24)
2423                 | ((uint64_t)(armData[4]) << 32) | ((uint64_t)(armData[5]) << 40) | ((uint64_t)(armData[6]) << 48) | ((uint64_t)(armData[7]) << 56);
2424     }
2425     return MYKONOS_ERR_OK;
2426 }
2427 
2428 /**
2429  * \brief Checks if the PLLs are locked
2430  *
2431  * This function updates the pllLockStatus pointer with a lock status it per
2432  * PLL.
2433  * pllLockStatus[0] = CLKPLL Locked
2434  * pllLockStatus[1] = RX_PLL Locked
2435  * pllLockStatus[2] = TX_PLL Locked
2436  * pllLockStatus[3] = SNIFFER_PLL Locked
2437  * pllLockStatus[4] = CAL_PLL Locked
2438  *
2439  * \param device the Mykonos device data structure
2440  * \param pllLockStatus Lock status bit per PLL
2441  *
2442  * \return Returns enum MYKONOS_ERR, MYKONOS_ERR_OK=pass, !MYKONOS_ERR_OK=fail
2443  */
MYKONOS_checkPllsLockStatus(mykonosDevice_t * device,uint8_t * pllLockStatus)2444 mykonosErr_t MYKONOS_checkPllsLockStatus(mykonosDevice_t *device, uint8_t *pllLockStatus)
2445 {
2446     uint8_t readData = 0;
2447 
2448 #if (MYKONOS_VERBOSE == 1)
2449     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_checkPllsLockStatus()\n");
2450 #endif
2451 
2452     if (pllLockStatus == NULL)
2453     {
2454         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CHECK_PLL_LOCK_NULL_PARM,
2455                 getMykonosErrorMessage(MYKONOS_ERR_CHECK_PLL_LOCK_NULL_PARM));
2456         return MYKONOS_ERR_CHECK_PLL_LOCK_NULL_PARM;
2457     }
2458 
2459     *pllLockStatus = 0;
2460 
2461     CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_VCO_BAND_BYTE1, &readData, 0x01, 0);
2462     *pllLockStatus = readData;
2463 
2464     CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_RXSYNTH_VCO_BAND_BYTE1, &readData, 0x01, 0);
2465     *pllLockStatus = *pllLockStatus | (uint8_t)(readData << 1);
2466 
2467     CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_TXSYNTH_VCO_BAND_BYTE1, &readData, 0x01, 0);
2468     *pllLockStatus = *pllLockStatus | (uint8_t)(readData << 2);
2469 
2470     CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_SNIFF_RXSYNTH_VCO_BAND_BYTE1, &readData, 0x01, 0);
2471     *pllLockStatus = *pllLockStatus | (uint8_t)(readData << 3);
2472 
2473     CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_CALPLL_SDM_CONTROL, &readData, 0x80, 7);
2474     *pllLockStatus = *pllLockStatus | (uint8_t)(readData << 4);
2475 
2476     return MYKONOS_ERR_OK;
2477 }
2478 
2479 /*
2480  *****************************************************************************
2481  * Shared Data path functions
2482  *****************************************************************************
2483  */
2484 
2485 /**
2486  * \brief Sets the digital Tx PFIR SYNC clock divider.
2487  *
2488  * This function is a helper function.  It is called automatically in
2489  * MYKONOS_initialize() and should not need to be called by the BBIC.
2490  *
2491  * This function sets the digital clock divider that is used to synchronize the
2492  * Tx PFIR each time the Tx channel power up.  The Sync clock must
2493  * be set equal to or slower than the FIR processing clock.
2494  *
2495  * <B>Dependencies</B>
2496  * - device->spiSettings
2497  * - device->spiSettings->chipSelectIndex
2498  * - device->profilesValid
2499  * - device->tx->txProfile->txFir
2500  * - device->tx->txProfile->txFir->numFirCoefs
2501  * - device->tx->txProfile->txFirInterpolation
2502  * - device->tx->txProfile->iqRate_kHz
2503  *
2504  * \param device Pointer to the Mykonos data structure
2505  *
2506  * \retval MYKONOS_ERR_OK Function completed successfully
2507  * \retval MYKONOS_ERR_TXFIR_INV_NUMTAPS_PARM: Invalid number of Tx FIR coefficients
2508  * \retval MYKONOS_ERR_TXFIR_INV_NUMROWS Invalid number of PFIR coefficient rows
2509  * \retval MYKONOS_ERR_TXFIR_TAPSEXCEEDED Too many Tx PFIR taps for the IQ sample rate.  FIR processing clock can not run fast enough to handle the number of taps
2510  */
MYKONOS_setTxPfirSyncClk(mykonosDevice_t * device)2511 mykonosErr_t MYKONOS_setTxPfirSyncClk(mykonosDevice_t *device)
2512 {
2513     const uint8_t numTapMultiple = 16;
2514     const uint8_t maxNumTaps = 96;
2515     uint8_t effectiveRows = 0;
2516     uint8_t numRows = 0;
2517     uint32_t dpClk_kHz = 0;
2518     uint32_t syncClk_kHz = 0;
2519     uint32_t hsDigClkDiv4or5_kHz = 0;
2520     uint8_t syncDiv = 0;
2521     mykonosErr_t retval = MYKONOS_ERR_OK;
2522 
2523     if (((device->profilesValid & TX_PROFILE_VALID) > 0) && (device->tx->txProfile->txFir != NULL))
2524     {
2525         /* Calculate number of FIR rows for number of Taps */
2526         if ((device->tx->txProfile->txFir->numFirCoefs % numTapMultiple == 0) && (device->tx->txProfile->txFir->numFirCoefs > 0)
2527                 && (device->tx->txProfile->txFir->numFirCoefs <= maxNumTaps))
2528         {
2529             numRows = (device->tx->txProfile->txFir->numFirCoefs / numTapMultiple);
2530         }
2531         else
2532         {
2533             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_TXFIR_INV_NUMTAPS_PARM,
2534                     getMykonosErrorMessage(MYKONOS_ERR_TXFIR_INV_NUMTAPS_PARM));
2535             return MYKONOS_ERR_TXFIR_INV_NUMTAPS_PARM;
2536         }
2537 
2538         effectiveRows = ((numRows + (device->tx->txProfile->txFirInterpolation - 1)) / device->tx->txProfile->txFirInterpolation);
2539 
2540         /* round up to next power of 2 */
2541         switch (effectiveRows)
2542         {
2543             case 1:
2544                 effectiveRows = 1;
2545                 break;
2546             case 2:
2547                 effectiveRows = 2;
2548                 break;
2549             case 3: /* fall through */
2550             case 4:
2551                 effectiveRows = 4;
2552                 break;
2553             case 5: /* fall through */
2554             case 6: /* fall through */
2555             case 7: /* fall through */
2556             case 8:
2557                 effectiveRows = 8;
2558                 break;
2559             default:
2560             {
2561                 /* invalid number of FIR taps */
2562                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_TXFIR_INV_NUMROWS,
2563                         getMykonosErrorMessage(MYKONOS_ERR_TXFIR_INV_NUMROWS));
2564                 return MYKONOS_ERR_TXFIR_INV_NUMROWS;
2565             }
2566         }
2567 
2568         dpClk_kHz = (device->tx->txProfile->iqRate_kHz * device->tx->txProfile->txInputHbInterpolation * device->tx->txProfile->txFirInterpolation * effectiveRows);
2569 
2570         /* FIR DPCLK can only run at max of 500MHz */
2571         if (dpClk_kHz > 500000)
2572         {
2573             /* Max number of Tx PFIR taps exceeded for Tx Profile */
2574             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_TXFIR_TAPSEXCEEDED,
2575                     getMykonosErrorMessage(MYKONOS_ERR_TXFIR_TAPSEXCEEDED));
2576             return MYKONOS_ERR_TXFIR_TAPSEXCEEDED;
2577         }
2578 
2579         /* SYNC CLOCK is the PFIR output rate / 2 */
2580         syncClk_kHz = device->tx->txProfile->iqRate_kHz * device->tx->txProfile->txFirInterpolation / 2;
2581         if ((retval = MYKONOS_calculateDigitalClocks(device, NULL, &hsDigClkDiv4or5_kHz)) != MYKONOS_ERR_OK)
2582         {
2583             return retval;
2584         }
2585 
2586         /* Select correct divider setting for SYNCCLK - must be == syncClk_kHz or slower */
2587         for (syncDiv = 0; syncDiv < 5; syncDiv++)
2588         {
2589             if ((hsDigClkDiv4or5_kHz / (uint32_t)(4 << syncDiv)) <= syncClk_kHz)
2590             {
2591                 break;
2592             }
2593         }
2594 
2595         /* Write Tx PFIR SYNC Clock divider */
2596         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_5, syncDiv, 0x70, 4);
2597     }
2598 
2599     return MYKONOS_ERR_OK;
2600 }
2601 
2602 /**
2603  * \brief Sets the digital Rx PFIR SYNC clock divider.
2604  *
2605  * This function is a helper function.  It is called automatically in
2606  * MYKONOS_initialize() and should not need to be called by the BBIC.
2607  *
2608  * This function sets the digital clock divider that is used to synchronize the
2609  * Rx/ORx/Sniffer PFIRs each time the channels power up.  The Sync clock must
2610  * be set equal to or slower than the slowest Rx/ORx/Sniffer PFIR processing
2611  * clock.
2612  *
2613  * <B>Dependencies</B>
2614  * - device->spiSettings
2615  * - device->spiSettings->chipSelectIndex
2616  * - device->profilesValid
2617  * - device->rx->rxProfile->rxFir
2618  * - device->rx->rxProfile->rxFir->numFirCoefs
2619  * - device->rx->rxProfile->iqRate_kHz
2620  * - device->obsRx->orxProfile->rxFir
2621  * - device->obsRx->orxProfile->rxFir->numFirCoefs
2622  * - device->obsRx->orxProfile->iqRate_kHz
2623  * - device->obsRx->snifferProfile->rxFir
2624  * - device->obsRx->snifferProfile->rxFir->numFirCoefs
2625  * - device->obsRx->snifferProfile->iqRate_kHz
2626  *
2627  * \param device Pointer to the Mykonos data structure
2628  *
2629  * \retval MYKONOS_ERR_OK Function completed successfully
2630  * \retval MYKONOS_ERR_RXFIR_TAPSEXCEEDED ERROR: the number of Rx FIR taps exceeds the number of taps accommodated by the FIR processing clock
2631  * \retval MYKONOS_ERR_ORXFIR_TAPSEXCEEDED ERROR: the number of ORx FIR Taps exceeds the number of taps accommodated by the FIR processing clock
2632  * \retval MYKONOS_ERR_SNRXFIR_TAPSEXCEEDED ERROR: the number of sniffer FIR taps exceeds the number of taps accommodated by the FIR processing clock
2633  */
MYKONOS_setRxPfirSyncClk(mykonosDevice_t * device)2634 mykonosErr_t MYKONOS_setRxPfirSyncClk(mykonosDevice_t *device)
2635 {
2636     uint32_t rxDpClk_kHz = 0;
2637     uint32_t orxDpClk_kHz = 0;
2638     uint32_t snRxDpClk_kHz = 0;
2639     uint32_t slowestIqRate_kHz = 0;
2640     uint32_t syncClk_kHz = 0;
2641     uint8_t effectiveRxNumRows = 0;
2642     uint8_t effectiveOrxNumRows = 0;
2643     uint8_t effectiveSnrxNumRows = 0;
2644 
2645     uint32_t hsDigClkDiv4or5_kHz = 0;
2646     uint8_t syncDiv = 0;
2647     mykonosErr_t retval = MYKONOS_ERR_OK;
2648 
2649     /**
2650      * Calculate Rx SYNC Clock divider for Rx PFIR.  Same Rx SYNC Clock is used
2651      * for Rx, ORx, and Sniffer PFIRs, and must be slow enough to handle the slowest
2652      * PFIR rate.
2653      **/
2654 
2655     if (((device->profilesValid & RX_PROFILE_VALID) > 0) && (device->rx->rxProfile->rxFir != NULL))
2656     {
2657         switch (device->rx->rxProfile->rxFir->numFirCoefs)
2658         {
2659             case 24:
2660                 effectiveRxNumRows = 1;
2661                 break;
2662             case 48:
2663                 effectiveRxNumRows = 2;
2664                 break;
2665             case 72:
2666                 effectiveRxNumRows = 4;
2667                 break;
2668             default:
2669                 break;
2670         }
2671 
2672         rxDpClk_kHz = device->rx->rxProfile->iqRate_kHz * effectiveRxNumRows;
2673 
2674         if (rxDpClk_kHz > 500000)
2675         {
2676             /* Max number of Rx PFIR taps exceeded for Profile */
2677             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RXFIR_TAPSEXCEEDED,
2678                     getMykonosErrorMessage(MYKONOS_ERR_RXFIR_TAPSEXCEEDED));
2679             return MYKONOS_ERR_RXFIR_TAPSEXCEEDED;
2680         }
2681 
2682         slowestIqRate_kHz = device->rx->rxProfile->iqRate_kHz;
2683     }
2684 
2685     if (((device->profilesValid & ORX_PROFILE_VALID) > 0) && (device->obsRx->orxProfile->rxFir != NULL))
2686     {
2687         switch (device->obsRx->orxProfile->rxFir->numFirCoefs)
2688         {
2689             case 24:
2690                 effectiveOrxNumRows = 1;
2691                 break;
2692             case 48:
2693                 effectiveOrxNumRows = 2;
2694                 break;
2695             case 72:
2696                 effectiveOrxNumRows = 4;
2697                 break;
2698             default:
2699                 break;
2700         }
2701 
2702         orxDpClk_kHz = device->obsRx->orxProfile->iqRate_kHz * effectiveOrxNumRows;
2703 
2704         if (orxDpClk_kHz > 500000)
2705         {
2706             /* Max number of ORx PFIR taps exceeded for Profile */
2707             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ORXFIR_TAPSEXCEEDED,
2708                     getMykonosErrorMessage(MYKONOS_ERR_ORXFIR_TAPSEXCEEDED));
2709             return MYKONOS_ERR_ORXFIR_TAPSEXCEEDED;
2710         }
2711 
2712         if ((slowestIqRate_kHz == 0) || (slowestIqRate_kHz > device->obsRx->orxProfile->iqRate_kHz))
2713         {
2714             slowestIqRate_kHz = device->obsRx->orxProfile->iqRate_kHz;
2715 
2716         }
2717     }
2718 
2719     if (((device->profilesValid & SNIFF_PROFILE_VALID) > 0) && (device->obsRx->snifferProfile->rxFir != NULL))
2720     {
2721         switch (device->obsRx->snifferProfile->rxFir->numFirCoefs)
2722         {
2723             case 24:
2724                 effectiveSnrxNumRows = 1;
2725                 break;
2726             case 48:
2727                 effectiveSnrxNumRows = 2;
2728                 break;
2729             case 72:
2730                 effectiveSnrxNumRows = 4;
2731                 break;
2732             default:
2733                 break;
2734         }
2735 
2736         snRxDpClk_kHz = device->obsRx->snifferProfile->iqRate_kHz * effectiveSnrxNumRows;
2737 
2738         if (snRxDpClk_kHz > 500000)
2739         {
2740             /* Max number of ORx PFIR taps exceeded for Profile */
2741             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SNRXFIR_TAPSEXCEEDED,
2742                     getMykonosErrorMessage(MYKONOS_ERR_SNRXFIR_TAPSEXCEEDED));
2743             return MYKONOS_ERR_SNRXFIR_TAPSEXCEEDED;
2744         }
2745 
2746         if ((slowestIqRate_kHz == 0) || (slowestIqRate_kHz > device->obsRx->snifferProfile->iqRate_kHz))
2747         {
2748             slowestIqRate_kHz = device->obsRx->snifferProfile->iqRate_kHz;
2749         }
2750     }
2751 
2752     /* SYNC CLOCK should be FIR output rate / 2 */
2753     syncClk_kHz = (slowestIqRate_kHz / 2);
2754     if ((retval = MYKONOS_calculateDigitalClocks(device, NULL, &hsDigClkDiv4or5_kHz)) != MYKONOS_ERR_OK)
2755     {
2756         return retval;
2757     }
2758 
2759     /* Select correct divider setting for SYNCCLK - must be == syncClk_kHz or slower */
2760     for (syncDiv = 0; syncDiv < 5; syncDiv++)
2761     {
2762         if ((hsDigClkDiv4or5_kHz / (uint32_t)(4 << syncDiv)) <= syncClk_kHz)
2763         {
2764             break;
2765         }
2766     }
2767 
2768     /* Write Rx PFIR SYNC Clock divider */
2769     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_5, syncDiv, 0x07, 0);
2770 
2771     return MYKONOS_ERR_OK;
2772 }
2773 
2774 /**
2775  * \brief Configures one or more FIR filters in the device
2776  *
2777  * The device stores up to 6 FIR filters (2Rx, 2Obs Rx/Sniffer, and 2Tx).
2778  * Rx filters can have 24, 48, or 72 taps.  Tx filters can have 16, 32,
2779  * 48, 64, 80, or 96 taps.
2780  *
2781  * <B>Dependencies</B>
2782  * - device->spiSettings
2783  * - device->spiSettings->chipSelectIndex
2784  *
2785  * \param device Pointer to the Mykonos data structure
2786  * \param filterToProgram Name of the desired filter to program
2787  * \param firFilter Pointer to the filter to write into the device
2788  *
2789  * \retval MYKONOS_ERR_OK Function completed successfully
2790  * \retval MYKONOS_ERR_PROGRAMFIR_NULL_PARM ERROR: firFilter parameter is a NULL pointer
2791  * \retval MYKONOS_ERR_PROGRAMFIR_COEFS_NULL ERROR: firFilter->coefs is a NULL pointer
2792  * \retval MYKONOS_ERR_PROGRAMFIR_INV_FIRNAME_PARM ERROR: Invalid FIR filter name in filterToProgram parameter
2793  * \retval MYKONOS_ERR_PROGRAMFIR_INV_NUMTAPS_PARM ERROR: Invalid number of taps for the filter
2794  * \retval MYKONOS_ERR_RXFIR_INV_GAIN_PARM ERROR: Rx FIR filter has invalid gain setting
2795  * \retval MYKONOS_ERR_OBSRXFIR_INV_GAIN_PARM ERROR: OBSRX_A (ORX) FIR filter has invalid gain setting
2796  * \retval MYKONOS_ERR_SRXFIR_INV_GAIN_PARM ERROR: OBSRX_B (Sniffer) FIR filter has invalid gain setting
2797  * \retval MYKONOS_ERR_TXFIR_INV_GAIN_PARM ERROR: Tx FIR filter has invalid gain setting
2798  */
MYKONOS_programFir(mykonosDevice_t * device,mykonosfirName_t filterToProgram,mykonosFir_t * firFilter)2799 mykonosErr_t MYKONOS_programFir(mykonosDevice_t *device, mykonosfirName_t filterToProgram, mykonosFir_t *firFilter)
2800 {
2801     uint8_t filterSelect = 0;
2802     uint8_t i = 0;
2803     uint8_t numTapsReg = 0;
2804     uint8_t numTapMultiple = 24; /* Rx=24, Tx=16 */
2805     uint8_t maxNumTaps = 72; /* Rx=72, Tx=96 */
2806     uint8_t filterGain = 0;
2807 
2808 #if MYK_ENABLE_SPIWRITEARRAY == 1
2809     uint32_t addrIndex = 0;
2810     uint32_t dataIndex = 0;
2811     uint32_t spiBufferSize = ((MYK_SPIWRITEARRAY_BUFFERSIZE / 6) * 6); /* Make buffer size a multiple of 6 */
2812     uint16_t addrArray[MYK_SPIWRITEARRAY_BUFFERSIZE] = {0};
2813     uint8_t dataArray[MYK_SPIWRITEARRAY_BUFFERSIZE] = {0};
2814 #endif
2815 
2816     const uint8_t COEF_WRITE_EN = 0x40;
2817     const uint8_t PROGRAM_CLK_EN = 0x80;
2818 
2819 #if (MYKONOS_VERBOSE == 1)
2820     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_programFir()\n");
2821 #endif
2822 
2823     if (firFilter == NULL)
2824     {
2825         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_PROGRAMFIR_NULL_PARM,
2826                 getMykonosErrorMessage(MYKONOS_ERR_PROGRAMFIR_NULL_PARM));
2827         return MYKONOS_ERR_PROGRAMFIR_NULL_PARM;
2828     }
2829 
2830     if (firFilter->coefs == NULL)
2831     {
2832         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_PROGRAMFIR_COEFS_NULL,
2833                 getMykonosErrorMessage(MYKONOS_ERR_PROGRAMFIR_COEFS_NULL));
2834         return MYKONOS_ERR_PROGRAMFIR_COEFS_NULL;
2835     }
2836 
2837     switch (filterToProgram)
2838     {
2839         case TX1_FIR:
2840             filterSelect = 0x01;
2841             numTapMultiple = 16;
2842             maxNumTaps = 96;
2843             break;
2844         case TX2_FIR:
2845             filterSelect = 0x02;
2846             numTapMultiple = 16;
2847             maxNumTaps = 96;
2848             break;
2849         case TX1TX2_FIR:
2850             filterSelect = 0x03;
2851             numTapMultiple = 16;
2852             maxNumTaps = 96;
2853             break;
2854         case RX1_FIR:
2855             filterSelect = 0x04;
2856             numTapMultiple = 24;
2857             maxNumTaps = 72;
2858             break;
2859         case RX2_FIR:
2860             filterSelect = 0x08;
2861             numTapMultiple = 24;
2862             maxNumTaps = 72;
2863             break;
2864         case RX1RX2_FIR:
2865             filterSelect = 0x0C;
2866             numTapMultiple = 24;
2867             maxNumTaps = 72;
2868             break;
2869         case OBSRX_A_FIR:
2870             filterSelect = 0x10;
2871             numTapMultiple = 24;
2872             maxNumTaps = 72;
2873             break;
2874         case OBSRX_B_FIR:
2875             filterSelect = 0x20;
2876             numTapMultiple = 24;
2877             maxNumTaps = 72;
2878             break;
2879         default:
2880             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_PROGRAMFIR_INV_FIRNAME_PARM,
2881                     getMykonosErrorMessage(MYKONOS_ERR_PROGRAMFIR_INV_FIRNAME_PARM));
2882             return MYKONOS_ERR_PROGRAMFIR_INV_FIRNAME_PARM;
2883     }
2884 
2885     /* Calculate register value for number of Taps */
2886     if ((firFilter->numFirCoefs % numTapMultiple == 0) && (firFilter->numFirCoefs > 0) && (firFilter->numFirCoefs <= maxNumTaps))
2887     {
2888         numTapsReg = (firFilter->numFirCoefs / numTapMultiple) - 1;
2889     }
2890     else
2891     {
2892         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_PROGRAMFIR_INV_NUMTAPS_PARM,
2893                 getMykonosErrorMessage(MYKONOS_ERR_PROGRAMFIR_INV_NUMTAPS_PARM));
2894         return MYKONOS_ERR_PROGRAMFIR_INV_NUMTAPS_PARM;
2895     }
2896 
2897     /* Select which FIR filter to program coeffs for */
2898     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_CTL, (PROGRAM_CLK_EN | filterSelect)); //select filter and enable the programming clock
2899 
2900 #if (MYK_ENABLE_SPIWRITEARRAY == 0)
2901 
2902     /* write filter coefficients */
2903     for (i = 0; i < firFilter->numFirCoefs; i++)
2904     {
2905         /* Write Low byte of 16bit coefficient */
2906         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_ADDR, (i * 2));
2907         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_DATA, (firFilter->coefs[i] & 0xFF));
2908         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_CTL, (PROGRAM_CLK_EN | COEF_WRITE_EN | filterSelect)); /* write enable (self clearing) */
2909 
2910         /* Write High Byte of 16bit coefficient */
2911         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_ADDR, ((i * 2) + 1));
2912         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_DATA, ((firFilter->coefs[i] >> 8) & 0xFF));
2913         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_CTL, (PROGRAM_CLK_EN | COEF_WRITE_EN | filterSelect));/* write enable (self clearing) */
2914     }
2915 
2916 #elif (MYK_ENABLE_SPIWRITEARRAY == 1)
2917 
2918     addrIndex = 0;
2919     dataIndex = 0;
2920     for (i = 0; i < firFilter->numFirCoefs; i++)
2921     {
2922         addrArray[addrIndex++] = MYKONOS_ADDR_PFIR_COEFF_ADDR;
2923         addrArray[addrIndex++] = MYKONOS_ADDR_PFIR_COEFF_DATA;
2924         addrArray[addrIndex++] = MYKONOS_ADDR_PFIR_COEFF_CTL;
2925         addrArray[addrIndex++] = MYKONOS_ADDR_PFIR_COEFF_ADDR;
2926         addrArray[addrIndex++] = MYKONOS_ADDR_PFIR_COEFF_DATA;
2927         addrArray[addrIndex++] = MYKONOS_ADDR_PFIR_COEFF_CTL;
2928 
2929         dataArray[dataIndex++] = (uint8_t)(i * 2);
2930         dataArray[dataIndex++] = (firFilter->coefs[i] & 0xFF);
2931         dataArray[dataIndex++] = (PROGRAM_CLK_EN | COEF_WRITE_EN | filterSelect);
2932         dataArray[dataIndex++] = (uint8_t)((i * 2) + 1);
2933         dataArray[dataIndex++] = (((uint16_t)firFilter->coefs[i] >> 8) & 0xFF);
2934         dataArray[dataIndex++] = (PROGRAM_CLK_EN | COEF_WRITE_EN | filterSelect);
2935 
2936         /* Send full buffer size when possible */
2937         /* spiBufferSize set to multiple of 6 at top of function */
2938         if (addrIndex >= spiBufferSize)
2939         {
2940             CMB_SPIWriteBytes(device->spiSettings, &addrArray[0], &dataArray[0], addrIndex);
2941             dataIndex = 0;
2942             addrIndex = 0;
2943         }
2944     }
2945 
2946     if (addrIndex > 0)
2947     {
2948         CMB_SPIWriteBytes(device->spiSettings, &addrArray[0], &dataArray[0], addrIndex);
2949     }
2950 
2951 #endif
2952 
2953     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_CTL, filterSelect); /* clear Program clock enable */
2954     /* write filter gain and #taps */
2955     if (filterToProgram == RX1_FIR || filterToProgram == RX2_FIR || filterToProgram == RX1RX2_FIR)
2956     {
2957         /* Write Rx FIR #taps */
2958         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_RX_FILTER_CONFIGURATION, numTapsReg, 0x60, 5);
2959 
2960         /* Set Rx filter gain */
2961         switch (firFilter->gain_dB)
2962         {
2963             case -12:
2964                 filterGain = 0x00;
2965                 break;
2966             case -6:
2967                 filterGain = 0x01;
2968                 break;
2969             case 0:
2970                 filterGain = 0x02;
2971                 break;
2972             case 6:
2973                 filterGain = 0x03;
2974                 break;
2975             default:
2976                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RXFIR_INV_GAIN_PARM,
2977                         getMykonosErrorMessage(MYKONOS_ERR_RXFIR_INV_GAIN_PARM));
2978                 return MYKONOS_ERR_RXFIR_INV_GAIN_PARM;
2979         }
2980 
2981         /* Write Rx filter gain */
2982         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_RX_FILTER_GAIN, filterGain, 0x03, 0);
2983     }
2984     else if (filterToProgram == OBSRX_A_FIR)
2985     {
2986         /* Write Obs Rx FIR A #taps */
2987         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_RX_FILTER_CONFIGURATION, numTapsReg, 0x06, 1);
2988 
2989         /* Set Rx filter gain */
2990         switch (firFilter->gain_dB)
2991         {
2992             case -12:
2993                 filterGain = 0x00;
2994                 break;
2995             case -6:
2996                 filterGain = 0x01;
2997                 break;
2998             case 0:
2999                 filterGain = 0x02;
3000                 break;
3001             case 6:
3002                 filterGain = 0x03;
3003                 break;
3004             default:
3005                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBSRXFIR_INV_GAIN_PARM,
3006                         getMykonosErrorMessage(MYKONOS_ERR_OBSRXFIR_INV_GAIN_PARM));
3007                 return MYKONOS_ERR_OBSRXFIR_INV_GAIN_PARM;
3008         }
3009 
3010         /* Write Obs Rx filter gain */
3011         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_DPD_SNIFFER_RX_FILTER_GAIN, filterGain, 0x03, 0);
3012     }
3013     else if (filterToProgram == OBSRX_B_FIR)
3014     {
3015         /* Write Obs Rx FIR B #taps */
3016         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_RX_FILTER_CONFIGURATION, numTapsReg, 0x18, 3);
3017 
3018         /* Set Rx filter gain */
3019         switch (firFilter->gain_dB)
3020         {
3021             case -12:
3022                 filterGain = 0x00;
3023                 break;
3024             case -6:
3025                 filterGain = 0x01;
3026                 break;
3027             case 0:
3028                 filterGain = 0x02;
3029                 break;
3030             case 6:
3031                 filterGain = 0x03;
3032                 break;
3033             default:
3034                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SRXFIR_INV_GAIN_PARM,
3035                         getMykonosErrorMessage(MYKONOS_ERR_SRXFIR_INV_GAIN_PARM));
3036                 return MYKONOS_ERR_SRXFIR_INV_GAIN_PARM;
3037         }
3038 
3039         /* Write Obs Rx filter gain */
3040         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_DPD_SNIFFER_RX_FILTER_GAIN, filterGain, 0x60, 5);
3041     }
3042     else if (filterToProgram == TX1_FIR || filterToProgram == TX2_FIR || filterToProgram == TX1TX2_FIR)
3043     {
3044         /* Write number of Taps */
3045         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_FILTER_CONFIGURATION, numTapsReg, 0xE0, 5);
3046 
3047         switch (firFilter->gain_dB)
3048         {
3049             case 0:
3050                 filterGain = 0;
3051                 break;
3052             case 6:
3053                 filterGain = 1;
3054                 break;
3055             default:
3056                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_TXFIR_INV_GAIN_PARM,
3057                         getMykonosErrorMessage(MYKONOS_ERR_TXFIR_INV_GAIN_PARM));
3058                 return MYKONOS_ERR_TXFIR_INV_GAIN_PARM;
3059         }
3060 
3061         /* Write Tx Filter gain */
3062         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_FILTER_CONFIGURATION, filterGain, 0x01, 0);
3063 
3064     }
3065 
3066     return MYKONOS_ERR_OK;
3067 }
3068 
3069 /**
3070  * \brief Reads the FIR filter programmed into the device
3071  *
3072  * The device stores up to 6 FIR filters (2Rx, 2Obs Rx/Sniffer, and 2Tx).
3073  * Rx filters can have 24, 48, or 72 taps.  Tx filters can have 16, 32,
3074  * 48, 64, 80, or 96 taps.
3075  *
3076  * <B>Dependencies</B>
3077  * - device->spiSettings
3078  * - device->spiSettings->chipSelectIndex
3079  *
3080  * \param device Pointer to the Mykonos data structure
3081  * \param filterToRead Name of the desired filter to be read
3082  * \param firFilter Pointer to the filter to be read from the device
3083  *
3084  * \retval MYKONOS_ERR_OK Function completed successfully
3085  * \retval MYKONOS_ERR_READFIR_NULL_PARM ERROR: firFilter parameter is a NULL pointer
3086  * \retval MYKONOS_ERR_READFIR_COEFS_NULL ERROR: firFilter->coefs is a NULL pointer
3087  * \retval MYKONOS_ERR_READFIR_INV_FIRNAME_PARM ERROR: Invalid FIR filter name in filterToRead parameter
3088  * \retval MYKONOS_ERR_READFIR_INV_NUMTAPS_PARM ERROR: Invalid number of taps for the filter
3089  * \retval MYKONOS_ERR_RXFIR_INV_GAIN_PARM ERROR: Rx FIR filter has invalid gain setting
3090  * \retval MYKONOS_ERR_OBSRXFIR_INV_GAIN_PARM ERROR: OBSRX_A (ORX) FIR filter has invalid gain setting
3091  * \retval MYKONOS_ERR_SRXFIR_INV_GAIN_PARM ERROR: OBSRX_B (Sniffer) FIR filter has invalid gain setting
3092  * \retval MYKONOS_ERR_TXFIR_INV_GAIN_PARM ERROR: Tx FIR filter has invalid gain setting
3093  */
MYKONOS_readFir(mykonosDevice_t * device,mykonosfirName_t filterToRead,mykonosFir_t * firFilter)3094 mykonosErr_t MYKONOS_readFir(mykonosDevice_t *device, mykonosfirName_t filterToRead, mykonosFir_t *firFilter)
3095 {
3096     uint8_t filterSelect = 0;
3097     uint8_t i = 0;
3098     uint8_t numTapsReg = 0;
3099     uint8_t numTapMultiple = 24;
3100     uint8_t maxNumTaps = 72;
3101     uint8_t filterGain = 0;
3102     uint8_t msbRead = 0;
3103     uint8_t lsbRead = 0;
3104 
3105     const uint8_t PROGRAM_CLK_EN = 0x80;
3106 
3107 #if (MYKONOS_VERBOSE == 1)
3108     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_readFir()\n");
3109 #endif
3110 
3111     if (firFilter == NULL)
3112     {
3113         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READFIR_NULL_PARM, getMykonosErrorMessage(MYKONOS_ERR_READFIR_NULL_PARM));
3114         return MYKONOS_ERR_READFIR_NULL_PARM;
3115     }
3116 
3117     if (firFilter->coefs == NULL)
3118     {
3119         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READFIR_COEFS_NULL, getMykonosErrorMessage(MYKONOS_ERR_READFIR_COEFS_NULL));
3120         return MYKONOS_ERR_READFIR_COEFS_NULL;
3121     }
3122 
3123     switch (filterToRead)
3124     {
3125         case TX1_FIR:
3126             filterSelect = 0x01;
3127             numTapMultiple = 16;
3128             maxNumTaps = 96;
3129             break;
3130         case TX2_FIR:
3131             filterSelect = 0x02;
3132             numTapMultiple = 16;
3133             maxNumTaps = 96;
3134             break;
3135         case TX1TX2_FIR:
3136             filterSelect = 0x03;
3137             numTapMultiple = 16;
3138             maxNumTaps = 96;
3139             break;
3140         case RX1_FIR:
3141             filterSelect = 0x04;
3142             numTapMultiple = 24;
3143             maxNumTaps = 72;
3144             break;
3145         case RX2_FIR:
3146             filterSelect = 0x08;
3147             numTapMultiple = 24;
3148             maxNumTaps = 72;
3149             break;
3150         case RX1RX2_FIR:
3151             filterSelect = 0x0C;
3152             numTapMultiple = 24;
3153             maxNumTaps = 72;
3154             break;
3155         case OBSRX_A_FIR:
3156             filterSelect = 0x10;
3157             numTapMultiple = 24;
3158             maxNumTaps = 72;
3159             break;
3160         case OBSRX_B_FIR:
3161             filterSelect = 0x20;
3162             numTapMultiple = 24;
3163             maxNumTaps = 72;
3164             break;
3165         default:
3166             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READFIR_INV_FIRNAME_PARM,
3167                     getMykonosErrorMessage(MYKONOS_ERR_READFIR_INV_FIRNAME_PARM));
3168             return MYKONOS_ERR_READFIR_INV_FIRNAME_PARM;
3169     }
3170 
3171     /* clear Program clock enable */
3172     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_CTL, filterSelect);
3173 
3174     /* Read filter gain and #taps */
3175     if (filterToRead == RX1_FIR || filterToRead == RX2_FIR || filterToRead == RX1RX2_FIR)
3176     {
3177         /* Read Rx FIR #taps */
3178         CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_RX_FILTER_CONFIGURATION, &numTapsReg, 0x60, 5);
3179 
3180         firFilter->numFirCoefs = (uint8_t)((numTapsReg + 1) * numTapMultiple);
3181 
3182         /* Read Rx filter gain */
3183         CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_RX_FILTER_GAIN, &filterGain, 0x03, 0);
3184 
3185         switch (filterGain)
3186         {
3187             case 0x00:
3188                 firFilter->gain_dB = -12;
3189                 break;
3190             case 0x01:
3191                 firFilter->gain_dB = -6;
3192                 break;
3193             case 0x02:
3194                 firFilter->gain_dB = 0;
3195                 break;
3196             case 0x03:
3197                 firFilter->gain_dB = 6;
3198                 break;
3199             default:
3200                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RXFIR_INV_GAIN_PARM,
3201                         getMykonosErrorMessage(MYKONOS_ERR_RXFIR_INV_GAIN_PARM));
3202                 return MYKONOS_ERR_RXFIR_INV_GAIN_PARM;
3203         }
3204     }
3205     else if (filterToRead == OBSRX_A_FIR)
3206     {
3207         /* Read Obs Rx FIR A #taps */
3208         CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_RX_FILTER_CONFIGURATION, &numTapsReg, 0x60, 1);
3209 
3210         firFilter->numFirCoefs = (uint8_t)((numTapsReg + 1) * numTapMultiple);
3211 
3212         /* Read Obs Rx FIR A gain */
3213         CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_DPD_SNIFFER_RX_FILTER_GAIN, &filterGain, 0x03, 0);
3214 
3215         switch (filterGain)
3216         {
3217             case 0x00:
3218                 firFilter->gain_dB = -12;
3219                 break;
3220             case 0x01:
3221                 firFilter->gain_dB = -6;
3222                 break;
3223             case 0x02:
3224                 firFilter->gain_dB = 0;
3225                 break;
3226             case 0x03:
3227                 firFilter->gain_dB = 6;
3228                 break;
3229             default:
3230                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBSRXFIR_INV_GAIN_PARM,
3231                         getMykonosErrorMessage(MYKONOS_ERR_OBSRXFIR_INV_GAIN_PARM));
3232                 return MYKONOS_ERR_OBSRXFIR_INV_GAIN_PARM;
3233         }
3234     }
3235     else if (filterToRead == OBSRX_B_FIR)
3236     {
3237         /* Read Obs Rx FIR B #taps */
3238         CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_RX_FILTER_CONFIGURATION, &numTapsReg, 0x18, 3);
3239 
3240         firFilter->numFirCoefs = (uint8_t)((numTapsReg + 1) * numTapMultiple);
3241 
3242         /* Read Obs Rx FIR B gain */
3243         CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_DPD_SNIFFER_RX_FILTER_GAIN, &filterGain, 0x60, 5);
3244 
3245         switch (filterGain)
3246         {
3247             case 0x00:
3248                 firFilter->gain_dB = -12;
3249                 break;
3250             case 0x01:
3251                 firFilter->gain_dB = -6;
3252                 break;
3253             case 0x02:
3254                 firFilter->gain_dB = 0;
3255                 break;
3256             case 0x03:
3257                 firFilter->gain_dB = 6;
3258                 break;
3259             default:
3260                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SRXFIR_INV_GAIN_PARM,
3261                         getMykonosErrorMessage(MYKONOS_ERR_SRXFIR_INV_GAIN_PARM));
3262                 return MYKONOS_ERR_SRXFIR_INV_GAIN_PARM;
3263         }
3264     }
3265     else if (filterToRead == TX1_FIR || filterToRead == TX2_FIR || filterToRead == TX1TX2_FIR)
3266     {
3267         /* Read number of Taps */
3268         CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_TX_FILTER_CONFIGURATION, &numTapsReg, 0xE0, 5);
3269 
3270         firFilter->numFirCoefs = (uint8_t)((numTapsReg + 1) * numTapMultiple);
3271 
3272         /* Read Tx Filter gain */
3273         CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_TX_FILTER_CONFIGURATION, &filterGain, 0x01, 0);
3274 
3275         switch (filterGain)
3276         {
3277             case 0:
3278                 firFilter->gain_dB = 0;
3279                 break;
3280             case 1:
3281                 firFilter->gain_dB = 6;
3282                 break;
3283             default:
3284                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_TXFIR_INV_GAIN_PARM,
3285                         getMykonosErrorMessage(MYKONOS_ERR_TXFIR_INV_GAIN_PARM));
3286                 return MYKONOS_ERR_TXFIR_INV_GAIN_PARM;
3287         }
3288     }
3289 
3290     /* Select which FIR filter to read the coeffs for */
3291     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_CTL, (PROGRAM_CLK_EN | filterSelect)); //select filter and enable the programming clock
3292 
3293     if (firFilter->numFirCoefs > maxNumTaps)
3294     {
3295         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READFIR_INV_NUMTAPS_PARM,
3296                 getMykonosErrorMessage(MYKONOS_ERR_READFIR_INV_NUMTAPS_PARM));
3297         return MYKONOS_ERR_READFIR_INV_NUMTAPS_PARM;
3298     }
3299 
3300     /* write filter coefficients */
3301     for (i = 0; i < firFilter->numFirCoefs; i++)
3302     {
3303         /* Write Low byte of 16bit coefficient */
3304         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_ADDR, (uint8_t)(i * 2));
3305         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_CTL, (PROGRAM_CLK_EN | filterSelect)); /* write enable (self clearing) */
3306         CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_DATA, &lsbRead);
3307 
3308         /* Write High Byte of 16bit coefficient */
3309         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_ADDR, (uint8_t)((i * 2) + 1));
3310         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_CTL, (PROGRAM_CLK_EN | filterSelect));/* write enable (self clearing) */
3311         CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_PFIR_COEFF_DATA, &msbRead);
3312 
3313         firFilter->coefs[i] = (int16_t)((lsbRead & 0xFF) | ((msbRead << 8) & 0xFF00));
3314     }
3315 
3316     return MYKONOS_ERR_OK;
3317 }
3318 
3319 /*
3320  *****************************************************************************
3321  * Rx Data path functions
3322  *****************************************************************************
3323  */
3324 /*!
3325  * \brief Programs the gain table settings for either Rx1, Rx2, Rx1 + Rx2, ORx, or SnRx receiver types
3326  *
3327  * The gain table for a receiver type is set with the parameters passed by uint8_t gainTablePtr array.
3328  * gainTablePtr is a 4 x n array, where there are four (4) elements per index, and the array
3329  * length (n) is dependent upon receiver type. The (n) value is conveyed by numGainIndexesInTable.
3330  * All gain tables have a maximum index of 255 when used with this function. The minimum gain index is
3331  * application dependent.
3332  *
3333  * Where for Rx1, Rx2, and ObsRx:
3334  * [A, B, C, D]: A = Front End Gain, B = External Control, C = Digital Attenuation/Gain, D = Attenuation/Gain select
3335  *
3336  * Where for SnRx:
3337  * [A, B, C, D]: A = Front End Gain, B = LNA Bypass, C = Digital Attenuation/Gain, D = Attenuation/Gain select
3338  *
3339  * The gain table starting address changes with each receiver type. This function accounts for this change as well as the
3340  * difference between byte [B] for {Rx1, Rx2, ObsRx} and SnRx receiver array values and programs the correct registers.
3341  *
3342  * <B>Dependencies</B>
3343  * - device->spiSettings->chipSelectIndex
3344  *
3345  * \param device Pointer to the Mykonos data structure
3346  * \param gainTablePtr Pointer to 4 x n array containing gain table program values
3347  * \param numGainIndexesInTable The number of 'n' indices in 4 x n array.  A range check is performed to ensure the maximum is not exceeded.
3348  * \param rxChannel mykonosGainTable_t enum type to select either Rx1, Rx2, Rx1 + Rx2, ORx, or SnRx gain table for programming.  A
3349  * channel check is performed to ensure a valid selection.
3350  *
3351  * \return Returns enum MYKONOS_ERR, MYKONOS_ERR_OK if successful, MYKONOS_ERR_RXGAINTABLE_INV_CHANNEL if invalid channel is selected, MYKONOS_ERR_RXGAINTABLE_INV_GAIN_INDEX_RANGE
3352  * if numGainIndexesInTable exceeds range for selected receiver gain table
3353  */
MYKONOS_programRxGainTable(mykonosDevice_t * device,uint8_t * gainTablePtr,uint8_t numGainIndexesInTable,mykonosGainTable_t rxChannel)3354 mykonosErr_t MYKONOS_programRxGainTable(mykonosDevice_t *device, uint8_t *gainTablePtr, uint8_t numGainIndexesInTable, mykonosGainTable_t rxChannel)
3355 {
3356     uint8_t ctlReg = 0;
3357     uint8_t ch3CtlReg = 0;
3358     uint16_t rxFEGainAddr = 0;
3359     uint16_t rxExtCtlLnaAddr = 0;
3360     uint16_t rxDigGainAttenAddr = 0;
3361     uint16_t rx2FEGainAddr = 0;
3362     uint16_t rx2ExtCtlAddr = 0;
3363     uint16_t rx2DigGainAttenAddr = 0;
3364     uint8_t minGainIndex = 0;
3365     uint8_t startIndex = 0;
3366     int16_t i = 0;
3367     uint16_t tableRowIndex = 0;
3368     uint8_t retFlag = 0;
3369 
3370 #if MYK_ENABLE_SPIWRITEARRAY
3371     uint32_t addrIndex = 0;
3372     uint32_t dataIndex = 0;
3373     uint32_t spiBufferSize = (((MYK_SPIWRITEARRAY_BUFFERSIZE / 9) - 1) * 9);
3374     uint16_t addrArray[MYK_SPIWRITEARRAY_BUFFERSIZE] = {0};
3375     uint8_t dataArray[MYK_SPIWRITEARRAY_BUFFERSIZE] = {0};
3376 #endif
3377 
3378 #if (MYKONOS_VERBOSE == 1)
3379     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_programRxGainTable()\n");
3380 #endif
3381 
3382     if (gainTablePtr == NULL)
3383     {
3384         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_PROGRAM_RXGAIN_TABLE_NULL_PARM,
3385                 getMykonosErrorMessage(MYKONOS_ERR_PROGRAM_RXGAIN_TABLE_NULL_PARM));
3386         return MYKONOS_ERR_PROGRAM_RXGAIN_TABLE_NULL_PARM;
3387     }
3388 
3389     /* checking range of numGainIndexesInTable against maximums and for valid rxChannel selection */
3390     switch (rxChannel)
3391     {
3392         case RX1_GT:
3393             /* Rx1 max gain index = 255, check is out of range of uint8_t */
3394             break;
3395         case RX2_GT:
3396             /* Rx1 max gain index = 255, check is out of range of uint8_t */
3397             break;
3398         case RX1_RX2_GT:
3399             /* Rx1 max gain index = 255, check is out of range of uint8_t */
3400             break;
3401         case ORX_GT:
3402             if (numGainIndexesInTable > MAX_ORX_GAIN_TABLE_NUMINDEXES)
3403             {
3404                 retFlag = 1;
3405             }
3406             break;
3407         case SNRX_GT:
3408             if (numGainIndexesInTable > MAX_SNRX_GAIN_TABLE_NUMINDEXES)
3409             {
3410                 retFlag = 1;
3411             }
3412             break;
3413         case LOOPBACK_GT:
3414             if (numGainIndexesInTable > MAX_LOOPBACK_GAIN_TABLE_NUMINDEXES)
3415             {
3416                 retFlag = 1;
3417             }
3418             break;
3419         default:
3420             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RXGAINTABLE_INV_CHANNEL,
3421                     getMykonosErrorMessage(MYKONOS_ERR_RXGAINTABLE_INV_CHANNEL));
3422             return MYKONOS_ERR_RXGAINTABLE_INV_CHANNEL;
3423     }
3424 
3425     if (retFlag)
3426     {
3427         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RXGAINTABLE_INV_GAIN_INDEX_RANGE,
3428                 getMykonosErrorMessage(MYKONOS_ERR_RXGAINTABLE_INV_GAIN_INDEX_RANGE));
3429         return MYKONOS_ERR_RXGAINTABLE_INV_GAIN_INDEX_RANGE;
3430     }
3431     else
3432     {
3433         /* calculating minimum gain index value */
3434         minGainIndex = MAX_GAIN_TABLE_INDEX - numGainIndexesInTable + 1;
3435     }
3436 
3437     /* forming control register words based on channel select, assigning starting index, and register addressing, also updating max and min gain table indices in structure */
3438     switch (rxChannel)
3439     {
3440         case RX1_GT:
3441             ctlReg = ((uint8_t)rxChannel << 3) | 0x05;
3442             startIndex = START_RX_GAIN_INDEX;
3443             rxFEGainAddr = MYKONOS_ADDR_GAIN_TABLE_RX1_FE_GAIN;
3444             rxExtCtlLnaAddr = MYKONOS_ADDR_GAIN_TABLE_RX1_EXT_CTL;
3445             rxDigGainAttenAddr = MYKONOS_ADDR_GAIN_TABLE_RX1_DIG_GAIN;
3446             device->rx->rxGainCtrl->rx1MaxGainIndex = MAX_GAIN_TABLE_INDEX;
3447             device->rx->rxGainCtrl->rx1MinGainIndex = minGainIndex;
3448             break;
3449         case RX2_GT:
3450             ctlReg = ((uint8_t)rxChannel << 3) | 0x05;
3451             startIndex = START_RX_GAIN_INDEX;
3452             rxFEGainAddr = MYKONOS_ADDR_GAIN_TABLE_RX2_FE_GAIN;
3453             rxExtCtlLnaAddr = MYKONOS_ADDR_GAIN_TABLE_RX2_EXT_CTL;
3454             rxDigGainAttenAddr = MYKONOS_ADDR_GAIN_TABLE_RX2_DIG_GAIN;
3455             device->rx->rxGainCtrl->rx2MaxGainIndex = MAX_GAIN_TABLE_INDEX;
3456             device->rx->rxGainCtrl->rx2MinGainIndex = minGainIndex;
3457             break;
3458         case RX1_RX2_GT:
3459             ctlReg = ((uint8_t)rxChannel << 3) | 0x05;
3460             startIndex = START_RX_GAIN_INDEX;
3461             rxFEGainAddr = MYKONOS_ADDR_GAIN_TABLE_RX1_FE_GAIN;
3462             rx2FEGainAddr = MYKONOS_ADDR_GAIN_TABLE_RX2_FE_GAIN;
3463             rxExtCtlLnaAddr = MYKONOS_ADDR_GAIN_TABLE_RX1_EXT_CTL;
3464             rx2ExtCtlAddr = MYKONOS_ADDR_GAIN_TABLE_RX2_EXT_CTL;
3465             rxDigGainAttenAddr = MYKONOS_ADDR_GAIN_TABLE_RX1_DIG_GAIN;
3466             rx2DigGainAttenAddr = MYKONOS_ADDR_GAIN_TABLE_RX2_DIG_GAIN;
3467             device->rx->rxGainCtrl->rx1MaxGainIndex = MAX_GAIN_TABLE_INDEX;
3468             device->rx->rxGainCtrl->rx1MinGainIndex = minGainIndex;
3469             device->rx->rxGainCtrl->rx2MaxGainIndex = MAX_GAIN_TABLE_INDEX;
3470             device->rx->rxGainCtrl->rx2MinGainIndex = minGainIndex;
3471             break;
3472         case ORX_GT:
3473             ctlReg = 0x05;
3474             ch3CtlReg = 0x08;
3475             startIndex = START_ORX_GAIN_INDEX;
3476             rxFEGainAddr = MYKONOS_ADDR_GAIN_TABLE_RX3_FE_GAIN;
3477             rxExtCtlLnaAddr = MYKONOS_ADDR_GAIN_TABLE_RX3_LNA_ENAB;
3478             rxDigGainAttenAddr = MYKONOS_ADDR_GAIN_TABLE_RX3_DIG_GAIN;
3479             device->obsRx->orxGainCtrl->maxGainIndex = MAX_GAIN_TABLE_INDEX;
3480             device->obsRx->orxGainCtrl->minGainIndex = minGainIndex;
3481             break;
3482         case SNRX_GT:
3483             ctlReg = 0x05;
3484             ch3CtlReg = 0x00;
3485             startIndex = START_SNRX_GAIN_INDEX;
3486             rxFEGainAddr = MYKONOS_ADDR_GAIN_TABLE_RX3_FE_GAIN;
3487             rxExtCtlLnaAddr = MYKONOS_ADDR_GAIN_TABLE_RX3_LNA_ENAB;
3488             rxDigGainAttenAddr = MYKONOS_ADDR_GAIN_TABLE_RX3_DIG_GAIN;
3489             device->obsRx->snifferGainCtrl->maxGainIndex = MAX_GAIN_TABLE_INDEX;
3490             device->obsRx->snifferGainCtrl->minGainIndex = minGainIndex;
3491             break;
3492         /*case LOOPBACK_GT:  Loopback is only for ARM calibrations */
3493         default:
3494             ctlReg = 0x05;
3495             ch3CtlReg = 0x10;
3496             startIndex = START_LOOPBACK_GAIN_INDEX;
3497             rxFEGainAddr = MYKONOS_ADDR_GAIN_TABLE_RX3_FE_GAIN;
3498             rxExtCtlLnaAddr = MYKONOS_ADDR_GAIN_TABLE_RX3_LNA_ENAB;
3499             rxDigGainAttenAddr = MYKONOS_ADDR_GAIN_TABLE_RX3_DIG_GAIN;
3500             break;
3501     }
3502 
3503     /* starting the gain table clock and read from gain table address bits */
3504     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_GAIN_TABLE_CONFIGURATION, ctlReg);
3505 
3506     /* if ORx or Sniffer are selected also writing channel 3 readback bits for ObsRx or Sniffer selection */
3507     if (rxChannel > RX1_RX2_GT)
3508     {
3509         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CH3_GAIN_TABLE_CONFIGURATION, ch3CtlReg);
3510     }
3511 
3512     /* programming a table selected by rxChannel enum type */
3513 
3514 #if MYK_ENABLE_SPIWRITEARRAY == 0
3515 
3516     for(i = startIndex; i >= ((startIndex + 1) - numGainIndexesInTable); i--)
3517     {
3518         tableRowIndex = (uint16_t)(startIndex - i) << 2;
3519 
3520         /* set current gain table index (address) */
3521         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_GAIN_TABLE_ADDR, i);
3522 
3523         /* Set Rx Front End gain[5:0] */
3524         CMB_SPIWriteByte(device->spiSettings, rxFEGainAddr, gainTablePtr[tableRowIndex]);
3525 
3526         /* Set external control [5:0] OR LNA bypass if rxChannel == SNRX_GT */
3527         if (rxChannel == SNRX_GT)
3528         {
3529             CMB_SPIWriteByte(device->spiSettings, rxExtCtlLnaAddr, gainTablePtr[tableRowIndex + 1] << 4);
3530         }
3531         else
3532         {
3533             CMB_SPIWriteByte(device->spiSettings, rxExtCtlLnaAddr, gainTablePtr[tableRowIndex + 1]);
3534         }
3535 
3536         /* Set digital attenuation/gain[6:0] and set/clear attenuation bit */
3537         CMB_SPIWriteByte(device->spiSettings, rxDigGainAttenAddr, (gainTablePtr[tableRowIndex + 3] << 7) | gainTablePtr[tableRowIndex + 2]);
3538 
3539         /* repeating gain table settings if Rx1 and Rx2 are selected for Rx2 configuration */
3540         if (rxChannel == RX1_RX2_GT)
3541         {
3542             /* Set Rx Front End gain[5:0] */
3543             CMB_SPIWriteByte(device->spiSettings, rx2FEGainAddr, gainTablePtr[tableRowIndex]);
3544 
3545             /* Set external control [5:0] */
3546             CMB_SPIWriteByte(device->spiSettings, rx2ExtCtlAddr, gainTablePtr[tableRowIndex + 1]);
3547 
3548             /* Set digital attenuation/gain[6:0] */
3549             CMB_SPIWriteByte(device->spiSettings, rx2DigGainAttenAddr, (gainTablePtr[tableRowIndex + 3] << 7) | gainTablePtr[tableRowIndex + 2]);
3550         }
3551 
3552         /* setting the write enable depending on rxChannel choice */
3553         if (rxChannel == ORX_GT)
3554         {
3555             CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CH3_GAIN_TABLE_CONFIGURATION, ch3CtlReg | 0x02);
3556             CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_GAIN_TABLE_CONFIGURATION, ctlReg | 0x02);
3557         }
3558         else if (rxChannel == SNRX_GT)
3559         {
3560             CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CH3_GAIN_TABLE_CONFIGURATION, ch3CtlReg | 0x01);
3561             CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_GAIN_TABLE_CONFIGURATION, ctlReg | 0x02);
3562         }
3563         else if (rxChannel == LOOPBACK_GT)
3564         {
3565             CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CH3_GAIN_TABLE_CONFIGURATION, ch3CtlReg | 0x04);
3566             CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_GAIN_TABLE_CONFIGURATION, ctlReg | 0x02);
3567         }
3568         else
3569         {
3570             CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_GAIN_TABLE_CONFIGURATION, ctlReg | 0x02);
3571         }
3572     }
3573 
3574 #elif MYK_ENABLE_SPIWRITEARRAY == 1
3575 //#elif 0
3576 
3577     addrIndex = 0;
3578     dataIndex = 0;
3579     for(i = startIndex; i >= ((startIndex + 1) - numGainIndexesInTable); i--)
3580     {
3581         tableRowIndex = (uint16_t)(startIndex - (uint8_t)i) << 2;
3582 
3583         /* set current gain table index (address) */
3584         addrArray[addrIndex++] = MYKONOS_ADDR_GAIN_TABLE_ADDR;
3585         dataArray[dataIndex++] = (uint8_t)i;
3586 
3587         /* Set Rx Front End gain[5:0] */
3588         addrArray[addrIndex++] = rxFEGainAddr;
3589         dataArray[dataIndex++] = gainTablePtr[tableRowIndex];
3590 
3591         /* Set external control [5:0] OR LNA bypass if rxChannel == SNRX_GT */
3592         addrArray[addrIndex++] = rxExtCtlLnaAddr;
3593         dataArray[dataIndex++] = (rxChannel == SNRX_GT) ? (uint8_t)(gainTablePtr[tableRowIndex + 1] << 4) : (gainTablePtr[tableRowIndex + 1]);
3594 
3595         /* Set digital attenuation/gain[6:0] and set/clear attenuation bit */
3596         addrArray[addrIndex++] = rxDigGainAttenAddr;
3597         dataArray[dataIndex++] = ((uint8_t)(gainTablePtr[tableRowIndex + 3] << 7) | gainTablePtr[tableRowIndex + 2]);
3598 
3599         /* repeating gain table settings if Rx1 and Rx2 are selected for Rx2 configuration */
3600         if (rxChannel == RX1_RX2_GT)
3601         {
3602             /* Set Rx Front End gain[5:0] */
3603             addrArray[addrIndex++] = rx2FEGainAddr;
3604             dataArray[dataIndex++] = gainTablePtr[tableRowIndex];
3605 
3606             /* Set external control [5:0] */
3607             addrArray[addrIndex++] = rx2ExtCtlAddr;
3608             dataArray[dataIndex++] = gainTablePtr[tableRowIndex + 1];
3609 
3610             /* Set digital attenuation/gain[6:0] */
3611             addrArray[addrIndex++] = rx2DigGainAttenAddr;
3612             dataArray[dataIndex++] = ((uint8_t)(gainTablePtr[tableRowIndex + 3] << 7) | gainTablePtr[tableRowIndex + 2]);
3613         }
3614 
3615         /* setting the write enable depending on rxChannel choice */
3616         if (rxChannel == ORX_GT)
3617         {
3618             addrArray[addrIndex++] = MYKONOS_ADDR_CH3_GAIN_TABLE_CONFIGURATION;
3619             dataArray[dataIndex++] = (ch3CtlReg | 0x02);
3620             addrArray[addrIndex++] = MYKONOS_ADDR_GAIN_TABLE_CONFIGURATION;
3621             dataArray[dataIndex++] = (ctlReg | 0x02);
3622         }
3623         else if (rxChannel == SNRX_GT)
3624         {
3625             addrArray[addrIndex++] = MYKONOS_ADDR_CH3_GAIN_TABLE_CONFIGURATION;
3626             dataArray[dataIndex++] = (ch3CtlReg | 0x01);
3627             addrArray[addrIndex++] = MYKONOS_ADDR_GAIN_TABLE_CONFIGURATION;
3628             dataArray[dataIndex++] = (ctlReg | 0x02);
3629         }
3630         else if (rxChannel == LOOPBACK_GT)
3631         {
3632             addrArray[addrIndex++] = MYKONOS_ADDR_CH3_GAIN_TABLE_CONFIGURATION;
3633             dataArray[dataIndex++] = (ch3CtlReg | 0x04);
3634             addrArray[addrIndex++] = MYKONOS_ADDR_GAIN_TABLE_CONFIGURATION;
3635             dataArray[dataIndex++] = (ctlReg | 0x02);
3636         }
3637         else
3638         {
3639             addrArray[addrIndex++] = MYKONOS_ADDR_GAIN_TABLE_CONFIGURATION;
3640             dataArray[dataIndex++] = (ctlReg | 0x02);
3641         }
3642 
3643         if (addrIndex >= spiBufferSize)
3644         {
3645             CMB_SPIWriteBytes(device->spiSettings, &addrArray[0], &dataArray[0], addrIndex);
3646             dataIndex = 0;
3647             addrIndex = 0;
3648         }
3649     }
3650 
3651     if (addrIndex > 0)
3652     {
3653         CMB_SPIWriteBytes(device->spiSettings, &addrArray[0], &dataArray[0], addrIndex);
3654     }
3655 
3656 #endif
3657 
3658     /* clearing the channel 3 gain table configuration register if selected and stopping the gain table clock */
3659     if (rxChannel > RX1_RX2_GT)
3660     {
3661         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_CH3_GAIN_TABLE_CONFIGURATION, 0x00);
3662     }
3663     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_GAIN_TABLE_CONFIGURATION, 0x08);
3664 
3665     return MYKONOS_ERR_OK;
3666 }
3667 
3668 /**
3669  * \brief Sets the Rx1 Manual Gain Index
3670  *
3671  * If the value passed in the gainIndex parameter is within range of the gain table minimum and
3672  * maximum indexes, the Rx1 gain index will be updated in the device data structure
3673  * and written to the transceiver. Else, an error will be returned. The maximum index is 255
3674  * and the minimum index is application specific.
3675  *
3676  * <B>Dependencies</B>
3677  * - device->spiSettings
3678  * - device->rxSettings->rxGainControl->rx1GainIndex
3679  * - device->rxSettings->rxGainControl->rx1MaxGainIndex
3680  * - device->rxSettings->rxGainControl->rx1MinGainIndex
3681  *
3682  * \param device Pointer to the Mykonos data structure
3683  * \param gainIndex Desired Rx1 gain index
3684  *
3685  * \return Returns enum MYKONOS_ERR, MYKONOS_ERR_OK=pass, !MYKONOS_ERR_OK=fail
3686  */
MYKONOS_setRx1ManualGain(mykonosDevice_t * device,uint8_t gainIndex)3687 mykonosErr_t MYKONOS_setRx1ManualGain(mykonosDevice_t *device, uint8_t gainIndex)
3688 {
3689 
3690 #if (MYKONOS_VERBOSE == 1)
3691     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setRx1ManualGain()\n");
3692 #endif
3693 
3694     if ((gainIndex < device->rx->rxGainCtrl->rx1MinGainIndex) || (gainIndex > device->rx->rxGainCtrl->rx1MaxGainIndex))
3695     {
3696         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETRX1GAIN_INV_GAIN_PARM,
3697                 getMykonosErrorMessage(MYKONOS_ERR_SETRX1GAIN_INV_GAIN_PARM));
3698         return MYKONOS_ERR_SETRX1GAIN_INV_GAIN_PARM;
3699 
3700     }
3701     else
3702     {
3703         /* If the desired gain index is in range of the gain table, update the
3704          * value in the device data structure, and write to device.
3705          */
3706         device->rx->rxGainCtrl->rx1GainIndex = gainIndex;
3707 
3708         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_MANUAL_GAIN_INDEX_CH_1, gainIndex);
3709 
3710         return MYKONOS_ERR_OK;
3711     }
3712 }
3713 
3714 /**
3715  * \brief Sets the Rx2 Manual Gain index
3716  *
3717  * If the value passed in the gainIndex parameter is within range of the gain table minimum and
3718  * maximum indexes, the Rx2 gain index will be updated in the device data structure
3719  * and written to the transceiver. Else, an error will be returned. The maximum index is 255
3720  * and the minimum index is application specific.
3721  *
3722  * <B>Dependencies</B>
3723  * - device->spiSettings
3724  * - device->rxTxSettings->rxGainControl->rx2GainIndex
3725  * - device->rxTxSettings->rxGainControl->rx2MaxGainIndex
3726  * - device->rxTxSettings->rxGainControl->rx2MinGainIndex
3727  *
3728  * \param device Pointer to the Mykonos data structure
3729  * \param gainIndex Desired Rx2 gain index
3730  *
3731  * \return Returns enum MYKONOS_ERR, MYKONOS_ERR_OK=pass, !MYKONOS_ERR_OK=fail
3732  */
MYKONOS_setRx2ManualGain(mykonosDevice_t * device,uint8_t gainIndex)3733 mykonosErr_t MYKONOS_setRx2ManualGain(mykonosDevice_t *device, uint8_t gainIndex)
3734 {
3735 
3736 #if (MYKONOS_VERBOSE == 1)
3737     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setRx2ManualGain()\n");
3738 #endif
3739 
3740     if ((gainIndex < device->rx->rxGainCtrl->rx2MinGainIndex) || (gainIndex > device->rx->rxGainCtrl->rx2MaxGainIndex))
3741     {
3742         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETRX2GAIN_INV_GAIN_PARM,
3743                 getMykonosErrorMessage(MYKONOS_ERR_SETRX2GAIN_INV_GAIN_PARM));
3744         return MYKONOS_ERR_SETRX2GAIN_INV_GAIN_PARM;
3745 
3746     }
3747     else
3748     {
3749         /* If the desired gain index is in range of the gain table, update the
3750          * value in the device data structure, and write to device.
3751          */
3752         device->rx->rxGainCtrl->rx2GainIndex = gainIndex;
3753 
3754         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_MANUAL_GAIN_INDEX_CH_2, gainIndex);
3755 
3756         return MYKONOS_ERR_OK;
3757     }
3758 }
3759 
3760 /**
3761  * \brief Reads the Rx1 Gain Index for Manual or AGC gain control mode
3762  *
3763  * This function reads the Rx1 gain index for manual or AGC modes. If the
3764  * *rx1GainIndex pointer is nonzero, the read back gain index will
3765  * be returned in the parameter.  If the *rx1GainIndex pointer
3766  * is NULL, the device data structure will be updated with the new read back value
3767  *
3768  * <B>Dependencies</B>
3769  * - device->spiSettings
3770  * - device->rxTxSettings->rxGainControl->rx1GainIndex
3771  *
3772  * \param device Pointer to the Mykonos data structure
3773  * \param rx1GainIndex uint8_t Pointer to the Rx1 gain index value
3774  *
3775  * \return Returns enum MYKONOS_ERR, MYKONOS_ERR_OK=pass, !MYKONOS_ERR_OK=fail
3776  */
MYKONOS_getRx1Gain(mykonosDevice_t * device,uint8_t * rx1GainIndex)3777 mykonosErr_t MYKONOS_getRx1Gain(mykonosDevice_t *device, uint8_t *rx1GainIndex)
3778 {
3779     uint8_t readData = 0;
3780 
3781 #if (MYKONOS_VERBOSE == 1)
3782     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getRx1Gain()\n");
3783 #endif
3784 
3785     CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_GAIN_CTL_CHANNEL_1, &readData);
3786 
3787     /*
3788      * If rx1GainIndex address is not NULL, return the Rx1 gain index in the
3789      * rx1GainIndex function parameter
3790      */
3791     if (rx1GainIndex != NULL)
3792     {
3793         *rx1GainIndex = readData;
3794     }
3795 
3796     /*
3797      * set the current Rx1 gain in the device data structure
3798      */
3799     if (device->profilesValid & RX_PROFILE_VALID)
3800     {
3801         device->rx->rxGainCtrl->rx1GainIndex = readData;
3802     }
3803 
3804     return MYKONOS_ERR_OK;
3805 }
3806 
3807 /**
3808  * \brief Reads the Rx2 Gain Index for Manual or AGC gain control mode
3809  *
3810  * This function reads the Rx2 gain index for manual or AGC modes. If the
3811  * *rx1GainIndex pointer is nonzero, the read back gain index will
3812  * be returned in the parameter.  If the *rx1GainIndex pointer
3813  * is NULL, the device data structure will be updated with the new read back value
3814  *
3815  * <B>Dependencies</B>
3816  * - device->spiSettings
3817  * - device->rxTxSettings->rxGainControl->rx2GainIndex
3818  *
3819  * \param device Pointer to the Mykonos data structure
3820  * \param rx2GainIndex Desired Rx2 gain index
3821  *
3822  * \return Returns enum MYKONOS_ERR, MYKONOS_ERR_OK=pass, !MYKONOS_ERR_OK=fail
3823  */
MYKONOS_getRx2Gain(mykonosDevice_t * device,uint8_t * rx2GainIndex)3824 mykonosErr_t MYKONOS_getRx2Gain(mykonosDevice_t *device, uint8_t *rx2GainIndex)
3825 {
3826     uint8_t readData = 0;
3827 
3828 #if (MYKONOS_VERBOSE == 1)
3829     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getRx2Gain()\n");
3830 #endif
3831 
3832     CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_GAIN_CTL_CHANNEL_2, &readData);
3833 
3834     /*
3835      * If rx1GainIndex address is not NULL, return the Rx1 gain index in the
3836      * rx1GainIndex function parameter
3837      */
3838     if (rx2GainIndex != NULL)
3839     {
3840         *rx2GainIndex = readData;
3841     }
3842 
3843     /*
3844      * set the current Rx2 gain in the device data structure
3845      */
3846     if (device->profilesValid & RX_PROFILE_VALID)
3847     {
3848         device->rx->rxGainCtrl->rx2GainIndex = readData;
3849     }
3850 
3851     return MYKONOS_ERR_OK;
3852 }
3853 
3854 /**
3855  * \brief Sets up the device Rx Automatic Gain Control (AGC) registers.
3856  *
3857  * Three data structures (mykonosAgcCfg_t, mykonosPeakDetAgcCfg_t, mykonosPowerMeasAgcCfg_t)
3858  * must be instantiated prior to calling this function. Valid ranges for data structure members
3859  * must also be provided.
3860  *
3861  *
3862  * <B>Dependencies:</B>
3863  * - device->spiSettings
3864  * - device->spiSettings->chipSelectIndex
3865  * - device->rx->rxAgcCtrl->agcRx1MaxGainIndex
3866  * - device->rx->rxAgcCtrl->agcRx1MinGainIndex
3867  * - device->rx->rxAgcCtrl->agcRx2MaxGainIndex
3868  * - device->rx->rxAgcCtrl->agcRx2MinGainIndex
3869  * - device->rx->rxAgcCtrl->agcObsRxMaxGainIndex
3870  * - device->rx->rxAgcCtrl->agcObsRxMinGainIndex
3871  * - device->rx->rxAgcCtrl->agcObsRxSelect
3872  * - device->rx->rxAgcCtrl->agcPeakThresholdMode
3873  * - device->rx->rxAgcCtrl->agcLowThsPreventGainIncrease
3874  * - device->rx->rxAgcCtrl->agcGainUpdateCounter
3875  * - device->rx->rxAgcCtrl->agcSlowLoopSettlingDelay
3876  * - device->rx->rxAgcCtrl->agcPeakWaitTime
3877  * - device->rx->rxAgcCtrl->agcResetOnRxEnable
3878  * - device->rx->rxAgcCtrl->agcEnableSyncPulseForGainCounter
3879  * - device->rx->rxAgcCtrl->peakAgc->apdHighThresh
3880  * - device->rx->rxAgcCtrl->peakAgc->apdLowThresh
3881  * - device->rx->rxAgcCtrl->peakAgc->hb2HighThresh
3882  * - device->rx->rxAgcCtrl->peakAgc->hb2LowThresh
3883  * - device->rx->rxAgcCtrl->peakAgc->hb2VeryLowThresh
3884  * - device->rx->rxAgcCtrl->peakAgc->apdHighThreshExceededCnt
3885  * - device->rx->rxAgcCtrl->peakAgc->apdLowThreshExceededCnt
3886  * - device->rx->rxAgcCtrl->peakAgc->hb2HighThreshExceededCnt
3887  * - device->rx->rxAgcCtrl->peakAgc->hb2LowThreshExceededCnt
3888  * - device->rx->rxAgcCtrl->peakAgc->hb2VeryLowThreshExceededCnt
3889  * - device->rx->rxAgcCtrl->peakAgc->apdHighGainStepAttack
3890  * - device->rx->rxAgcCtrl->peakAgc->apdLowGainStepRecovery
3891  * - device->rx->rxAgcCtrl->peakAgc->hb2HighGainStepAttack
3892  * - device->rx->rxAgcCtrl->peakAgc->hb2LowGainStepRecovery
3893  * - device->rx->rxAgcCtrl->peakAgc->hb2VeryLowGainStepRecovery
3894  * - device->rx->rxAgcCtrl->peakAgc->apdFastAttack
3895  * - device->rx->rxAgcCtrl->peakAgc->hb2FastAttack
3896  * - device->rx->rxAgcCtrl->peakAgc->hb2OverloadDetectEnable
3897  * - device->rx->rxAgcCtrl->peakAgc->hb2OverloadDurationCnt
3898  * - device->rx->rxAgcCtrl->peakAgc->hb2OverloadThreshCnt
3899  * - device->rx->rxAgcCtrl->powerAgc->pmdUpperHighThresh
3900  * - device->rx->rxAgcCtrl->powerAgc->pmdUpperLowThresh
3901  * - device->rx->rxAgcCtrl->powerAgc->pmdLowerHighThresh
3902  * - device->rx->rxAgcCtrl->powerAgc->pmdLowerLowThresh
3903  * - device->rx->rxAgcCtrl->powerAgc->pmdUpperHighGainStepAttack
3904  * - device->rx->rxAgcCtrl->powerAgc->pmdUpperLowGainStepAttack
3905  * - device->rx->rxAgcCtrl->powerAgc->pmdLowerHighGainStepRecovery
3906  * - device->rx->rxAgcCtrl->powerAgc->pmdLowerLowGainStepRecovery
3907  * - device->rx->rxAgcCtrl->powerAgc->pmdMeasDuration
3908  * - device->rx->rxAgcCtrl->powerAgc->pmdMeasConfig
3909  *
3910  * \param device is structure pointer to the Mykonos data structure containing settings
3911  * The pointer to the Mykonos AGC data structure containing settings is checked for a null pointer
3912  * to ensure it has been initialized. If not an error is thrown.
3913  *
3914  * \retval Returns MYKONOS_ERR=pass, !MYKONOS_ERR=fail
3915  * \retval MYKONOS_ERR_INV_AGC_RX_STRUCT_INIT
3916  * \retval MYKONOS_ERR_INV_AGC_RX_PEAK_STRUCT_INIT
3917  * \retval MYKONOS_ERR_INV_AGC_RX_PWR_STRUCT_INIT
3918  * \retval MYKONOS_ERR_INV_AGC_RX1_MAX_GAIN_INDEX
3919  * \retval MYKONOS_ERR_INV_AGC_RX1_MIN_GAIN_INDEX
3920  * \retval MYKONOS_ERR_INV_AGC_RX2_MAX_GAIN_INDEX
3921  * \retval MYKONOS_ERR_INV_AGC_RX2_MIN_GAIN_INDEX
3922  * \retval MYKONOS_ERR_INV_AGC_RX_GAIN_UPDATE_TIME_PARM
3923  * \retval MYKONOS_ERR_INV_AGC_RX_PEAK_WAIT_TIME_PARM
3924  * \retval MYKONOS_ERR_INV_AGC_RX_SLOW_LOOP_SETTLING_DELAY
3925  * \retval MYKONOS_ERR_INV_AGC_PMD_MEAS_DURATION
3926  * \retval MYKONOS_ERR_INV_AGC_PMD_MEAS_CONFIG
3927  * \retval MYKONOS_ERR_INV_AGC_RX_LOW_THS_PREV_GAIN_INC
3928  * \retval MYKONOS_ERR_INV_AGC_RX_PEAK_THRESH_MODE
3929  * \retval MYKONOS_ERR_INV_AGC_RX_RESET_ON_RX_ENABLE
3930  * \retval MYKONOS_ERR_INV_AGC_RX_ENABLE_SYNC_PULSE_GAIN_COUNTER
3931  * \retval MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_HIGH_THRESH
3932  * \retval MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_LOW_THRESH
3933  * \retval MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_LOW_THRESH
3934  * \retval MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_HIGH_THRESH
3935  * \retval MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_HIGH_GAIN_STEP
3936  * \retval MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_LOW_GAIN_STEP
3937  * \retval MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_LOW_GAIN_STEP
3938  * \retval MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_LOW_GAIN_STEP
3939  * \retval MYKONOS_ERR_INV_AGC_RX_PKDET_FAST_ATTACK_VALUE
3940  * \retval MYKONOS_ERR_INV_AGC_RX_APD_HIGH_THRESH_PARM
3941  * \retval MYKONOS_ERR_INV_AGC_RX_APD_LOW_THRESH_PARM
3942  * \retval MYKONOS_ERR_INV_AGC_RX_HB2_HIGH_THRESH_PARM
3943  * \retval MYKONOS_ERR_INV_AGC_RX_HB2_LOW_THRESH_PARM
3944  * \retval MYKONOS_ERR_INV_AGC_RX_HB2_VERY_LOW_THRESH_PARM
3945  * \retval MYKONOS_ERR_INV_AGC_RX_APD_HIGH_GAIN_STEP_PARM
3946  * \retval MYKONOS_ERR_INV_AGC_RX_APD_LOW_GAIN_STEP_PARM
3947  * \retval MYKONOS_ERR_INV_AGC_RX_HB2_HIGH_GAIN_STEP_PARM
3948  * \retval MYKONOS_ERR_INV_AGC_RX_HB2_LOW_GAIN_STEP_PARM
3949  * \retval MYKONOS_ERR_INV_AGC_RX_HB2_VERY_LOW_GAIN_STEP_PARM
3950  * \retval MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_ENABLE
3951  * \retval MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_DUR_CNT
3952  * \retval MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_THRESH_CNT
3953  */
MYKONOS_setupRxAgc(mykonosDevice_t * device)3954 mykonosErr_t MYKONOS_setupRxAgc(mykonosDevice_t *device)
3955 {
3956     uint8_t decPowerConfig = 0;
3957     uint8_t lower1ThreshGainStepRegValue = 0;
3958     uint8_t powerThresholdsRegValue = 0;
3959     uint8_t hb2OvldCfgRegValue = 0;
3960     uint8_t agcGainUpdateCtr[3] = {0};
3961 
3962 #if (MYKONOS_VERBOSE == 1)
3963     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setRxAgc()\n");
3964 #endif
3965 
3966     /* Check mykonosAgcCfg_t device->rx->rxAgcCtrl pointer for initialization */
3967     if (device->rx->rxAgcCtrl == NULL)
3968     {
3969         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_STRUCT_INIT,
3970                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_STRUCT_INIT));
3971         return MYKONOS_ERR_INV_AGC_RX_STRUCT_INIT;
3972     }
3973 
3974     /* Check mykonosPeakDetAgcCfg_t device->rx->rxAgcCtrl->peakAgc pointer for initialization */
3975     if (device->rx->rxAgcCtrl->peakAgc == NULL)
3976     {
3977         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_PEAK_STRUCT_INIT,
3978                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_PEAK_STRUCT_INIT));
3979         return MYKONOS_ERR_INV_AGC_RX_PEAK_STRUCT_INIT;
3980     }
3981 
3982     /* Check mykonosPowerMeasAgcCfg_t device->rx->rxAgcCtrl->powerAgc pointer for initialization */
3983     if (device->rx->rxAgcCtrl->powerAgc == NULL)
3984     {
3985         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_PWR_STRUCT_INIT,
3986                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_PWR_STRUCT_INIT));
3987         return MYKONOS_ERR_INV_AGC_RX_PWR_STRUCT_INIT;
3988     }
3989 
3990     /* Range check agcRx1MaxGainIndex versus gain table limits */
3991     if ((device->rx->rxAgcCtrl->agcRx1MaxGainIndex > device->rx->rxGainCtrl->rx1MaxGainIndex)
3992             || (device->rx->rxAgcCtrl->agcRx1MaxGainIndex < device->rx->rxAgcCtrl->agcRx1MinGainIndex))
3993 
3994     {
3995         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX1_MAX_GAIN_INDEX,
3996                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX1_MAX_GAIN_INDEX));
3997         return MYKONOS_ERR_INV_AGC_RX1_MAX_GAIN_INDEX;
3998     }
3999     else
4000     {
4001         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_RX1_MAX_GAIN_INDEX, device->rx->rxAgcCtrl->agcRx1MaxGainIndex);
4002     }
4003 
4004     /* Range check agcRx1MinGainIndex versus gain table limits */
4005     if ((device->rx->rxAgcCtrl->agcRx1MinGainIndex < device->rx->rxGainCtrl->rx1MinGainIndex)
4006             || (device->rx->rxAgcCtrl->agcRx1MaxGainIndex < device->rx->rxAgcCtrl->agcRx1MinGainIndex))
4007     {
4008         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX1_MIN_GAIN_INDEX,
4009                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX1_MIN_GAIN_INDEX));
4010         return MYKONOS_ERR_INV_AGC_RX1_MIN_GAIN_INDEX;
4011     }
4012     else
4013     {
4014         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_RX1_MIN_GAIN_INDEX, device->rx->rxAgcCtrl->agcRx1MinGainIndex);
4015     }
4016 
4017     /* Range check agcRx2MaxGainIndex versus gain table limits */
4018     if ((device->rx->rxAgcCtrl->agcRx2MaxGainIndex > device->rx->rxGainCtrl->rx2MaxGainIndex)
4019             || (device->rx->rxAgcCtrl->agcRx2MaxGainIndex < device->rx->rxAgcCtrl->agcRx2MinGainIndex))
4020     {
4021         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX2_MAX_GAIN_INDEX,
4022                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX2_MAX_GAIN_INDEX));
4023         return MYKONOS_ERR_INV_AGC_RX2_MAX_GAIN_INDEX;
4024     }
4025     else
4026     {
4027         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_RX2_MAX_GAIN_INDEX, device->rx->rxAgcCtrl->agcRx2MaxGainIndex);
4028     }
4029 
4030     /* Range check agcRx2MinGainIndex versus gain table limits */
4031     if ((device->rx->rxAgcCtrl->agcRx2MinGainIndex < device->rx->rxGainCtrl->rx2MinGainIndex)
4032             || (device->rx->rxAgcCtrl->agcRx2MaxGainIndex < device->rx->rxAgcCtrl->agcRx2MinGainIndex))
4033     {
4034         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX2_MIN_GAIN_INDEX,
4035                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX2_MIN_GAIN_INDEX));
4036         return MYKONOS_ERR_INV_AGC_RX2_MIN_GAIN_INDEX;
4037     }
4038     else
4039     {
4040         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_RX2_MIN_GAIN_INDEX, device->rx->rxAgcCtrl->agcRx2MinGainIndex);
4041     }
4042 
4043     /* Range check for agcGainUpdateCounter (22-bit) */
4044     if ((device->rx->rxAgcCtrl->agcGainUpdateCounter > 0x3FFFFF) || (device->rx->rxAgcCtrl->agcGainUpdateCounter < 1))
4045     {
4046         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_GAIN_UPDATE_TIME_PARM,
4047                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_GAIN_UPDATE_TIME_PARM));
4048         return MYKONOS_ERR_INV_AGC_RX_GAIN_UPDATE_TIME_PARM;
4049     }
4050     else
4051     {
4052         /* Split agcGainUpdateCounter into three values */
4053         agcGainUpdateCtr[0] = (uint8_t)(device->rx->rxAgcCtrl->agcGainUpdateCounter);
4054         agcGainUpdateCtr[1] = (uint8_t)(device->rx->rxAgcCtrl->agcGainUpdateCounter >> 8);
4055         agcGainUpdateCtr[2] = (uint8_t)(device->rx->rxAgcCtrl->agcGainUpdateCounter >> 16);
4056 
4057         /* Write two bytes directly due. Third word has its upper two bits masked off.  */
4058         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_GAIN_UPDATE_CNT_1, agcGainUpdateCtr[0]);
4059         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_GAIN_UPDATE_CNT_2, agcGainUpdateCtr[1]);
4060         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_GAIN_UPDATE_CNT_3, agcGainUpdateCtr[2], 0x3F, 0);
4061     }
4062 
4063     /* Range check on agcPeakWaitTime (5-bit) */
4064     if (device->rx->rxAgcCtrl->agcPeakWaitTime > 0x1F || device->rx->rxAgcCtrl->agcPeakWaitTime < 0x02)
4065     {
4066         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_PEAK_WAIT_TIME_PARM,
4067                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_PEAK_WAIT_TIME_PARM));
4068         return MYKONOS_ERR_INV_AGC_RX_PEAK_WAIT_TIME_PARM;
4069     }
4070     else
4071     {
4072         /* Write agcPeakWaitTime */
4073         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_CFG_2, device->rx->rxAgcCtrl->agcPeakWaitTime, 0x1F, 0);
4074     }
4075 
4076     /* Set MYKONOS_ADDR_AGC_CFG_2 bits [6:5] = b11 to enable AGC counters for MGC mode - needed for ARM cals to work correctly */
4077     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_CFG_2, 3, 0x60, 5);
4078 
4079     /* Range check for agcSlowLoopSettlingDelay (7-bit) */
4080     if (device->rx->rxAgcCtrl->agcSlowLoopSettlingDelay > 0x7F)
4081     {
4082         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_SLOW_LOOP_SETTLING_DELAY,
4083                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_SLOW_LOOP_SETTLING_DELAY));
4084         return MYKONOS_ERR_INV_AGC_RX_SLOW_LOOP_SETTLING_DELAY;
4085     }
4086     else
4087     {
4088         /* Write agcSlowLoopSettlingDelay */
4089         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_LOOP_CFG, device->rx->rxAgcCtrl->agcSlowLoopSettlingDelay, 0x7F, 0);
4090     }
4091 
4092     /* Range check for pmdMeasDuration */
4093     if ((uint32_t)(1 << (3 + device->rx->rxAgcCtrl->powerAgc->pmdMeasDuration)) >= (device->rx->rxAgcCtrl->agcGainUpdateCounter))
4094     {
4095         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_PMD_MEAS_DURATION,
4096                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_PMD_MEAS_DURATION));
4097         return MYKONOS_ERR_INV_AGC_PMD_MEAS_DURATION;
4098     }
4099     else
4100     {
4101         /* Write pmdMeasDuration */
4102         CMB_SPIWriteField(device->spiSettings, MYKONOS_DEC_POWER_CONFIG_2, device->rx->rxAgcCtrl->powerAgc->pmdMeasDuration, 0x0F, 0);
4103     }
4104 
4105     /* Range check for pmdMeasConfig */
4106     if (device->rx->rxAgcCtrl->powerAgc->pmdMeasConfig > 0x3)
4107     {
4108         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_PMD_MEAS_CONFIG,
4109                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_PMD_MEAS_CONFIG));
4110         return MYKONOS_ERR_INV_AGC_PMD_MEAS_CONFIG;
4111     }
4112     else
4113     {
4114         if (device->rx->rxAgcCtrl->powerAgc->pmdMeasConfig == 0)
4115         {
4116             decPowerConfig = 0x0; /* Dec Pwr measurement disable */
4117         }
4118         else if (device->rx->rxAgcCtrl->powerAgc->pmdMeasConfig == 1)
4119         {
4120             decPowerConfig = 0x3; /* Dec Pwr measurement enable,  HB2 for decPwr measurement */
4121         }
4122         else if (device->rx->rxAgcCtrl->powerAgc->pmdMeasConfig == 2)
4123         {
4124             decPowerConfig = 0x5; /* Dec Pwr measurement enable, RFIR for decPwr measurement */
4125         }
4126         else if (device->rx->rxAgcCtrl->powerAgc->pmdMeasConfig == 3)
4127         {
4128             decPowerConfig = 0x11; /* Dec Pwr measurement enable, BBDC2 for decPwr measurement */
4129         }
4130         /* Write pmdMeasConfig */
4131         CMB_SPIWriteByte(device->spiSettings, MYKONOS_DEC_POWER_CONFIG_1, decPowerConfig);
4132     }
4133 
4134     /* Range check agcLowThsPreventGainIncrease (1-bit) */
4135     if (device->rx->rxAgcCtrl->agcLowThsPreventGainIncrease > 1)
4136     {
4137         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_LOW_THS_PREV_GAIN_INC,
4138                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_LOW_THS_PREV_GAIN_INC));
4139         return MYKONOS_ERR_INV_AGC_RX_LOW_THS_PREV_GAIN_INC;
4140     }
4141     else
4142     {
4143         /* Write agcLowThsPreventGainIncrease */
4144         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_LOCK_LEV_THRSH, device->rx->rxAgcCtrl->agcLowThsPreventGainIncrease, 0x80, 7);
4145     }
4146 
4147     /* Range check agcPeakThresholdMode (1-bit),  */
4148     if (device->rx->rxAgcCtrl->agcPeakThresholdMode > 1)
4149     {
4150         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_PEAK_THRESH_MODE,
4151                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_PEAK_THRESH_MODE));
4152         return MYKONOS_ERR_INV_AGC_RX_PEAK_THRESH_MODE;
4153     }
4154     else
4155     {
4156         /* Save to lower1ThreshGainStepRegValue register variable */
4157         lower1ThreshGainStepRegValue |= (uint8_t)(device->rx->rxAgcCtrl->agcPeakThresholdMode << 5);
4158     }
4159 
4160     /* Range check agcResetOnRxEnable (1-bit) */
4161     if (device->rx->rxAgcCtrl->agcResetOnRxEnable > 1)
4162     {
4163         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_LOW_THS_PREV_GAIN_INC,
4164                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_LOW_THS_PREV_GAIN_INC));
4165         return MYKONOS_ERR_INV_AGC_RX_RESET_ON_RX_ENABLE;
4166     }
4167     else
4168     {
4169         /* Write agcResetOnRxEnable */
4170         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_GAIN_UPDATE_CNT_3, (uint8_t)(device->rx->rxAgcCtrl->agcResetOnRxEnable << 7), 0x80, 0);
4171     }
4172 
4173     /* Range check agcEnableSyncPulseForGainCounter (1-bit) */
4174     if (device->rx->rxAgcCtrl->agcEnableSyncPulseForGainCounter > 1)
4175     {
4176         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_ENABLE_SYNC_PULSE_GAIN_COUNTER,
4177                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_ENABLE_SYNC_PULSE_GAIN_COUNTER));
4178         return MYKONOS_ERR_INV_AGC_RX_ENABLE_SYNC_PULSE_GAIN_COUNTER;
4179     }
4180     else
4181     {
4182         /* Write agcEnableSyncPulseForGainCounter */
4183         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_LOOP_CFG, (uint8_t)(device->rx->rxAgcCtrl->agcEnableSyncPulseForGainCounter << 7), 0x80, 0);
4184     }
4185 
4186     /* WRITE REGISTERS FOR THE AGC POWER MEASUREMENT DETECTOR (PMD) STRUCTURE */
4187 
4188     /* Range check pmdLowerHighThresh (7-bit) vs 0x7F and pmdUpperLowThresh */
4189     if ((device->rx->rxAgcCtrl->powerAgc->pmdLowerHighThresh <= device->rx->rxAgcCtrl->powerAgc->pmdUpperLowThresh)
4190             || device->rx->rxAgcCtrl->powerAgc->pmdLowerHighThresh > 0x7F)
4191     {
4192         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_HIGH_THRESH,
4193                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_HIGH_THRESH));
4194         return MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_HIGH_THRESH;
4195     }
4196     else
4197     {
4198         /* Write pmdLowerHighThresh */
4199         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_LOCK_LEV_THRSH, device->rx->rxAgcCtrl->powerAgc->pmdLowerHighThresh, 0x7F, 0);
4200     }
4201 
4202     /* Range check pmdUpperLowThresh (7-bit): Comparison to pmdLowerHigh done earlier */
4203     if (device->rx->rxAgcCtrl->powerAgc->pmdUpperLowThresh > 0x7F)
4204     {
4205         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_LOW_THRESH,
4206                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_LOW_THRESH));
4207         return MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_LOW_THRESH;
4208     }
4209     else
4210     {
4211         /* Write pmdUpperLowThresh */
4212         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_LOCK_LEVEL, device->rx->rxAgcCtrl->powerAgc->pmdUpperLowThresh);
4213     }
4214 
4215     /* Range check pmdLowerLowThresh (4-bit)  */
4216     if (device->rx->rxAgcCtrl->powerAgc->pmdLowerLowThresh > 0xF)
4217     {
4218         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_LOW_THRESH,
4219                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_LOW_THRESH));
4220         return MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_LOW_THRESH;
4221     }
4222     else
4223     {
4224         /* Write pmdUpperLowThresh to temp variable */
4225         powerThresholdsRegValue |= device->rx->rxAgcCtrl->powerAgc->pmdLowerLowThresh;
4226     }
4227 
4228     /* Range check pmdUpperHighThresh (4-bit)  */
4229     if (device->rx->rxAgcCtrl->powerAgc->pmdUpperHighThresh > 0xF)
4230     {
4231         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_HIGH_THRESH,
4232                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_HIGH_THRESH));
4233         return MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_HIGH_THRESH;
4234     }
4235     else
4236     {
4237         /* Write pmdUpperHighThresh to temp var, then to register */
4238         powerThresholdsRegValue |= (uint8_t)(device->rx->rxAgcCtrl->powerAgc->pmdUpperHighThresh << 4);
4239         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_POWER_THRSH, powerThresholdsRegValue);
4240     }
4241 
4242     /* Range check pmdUpperHighGainStepAttack (5-bit)  */
4243     if (device->rx->rxAgcCtrl->powerAgc->pmdUpperHighGainStepAttack > 0x1F)
4244     {
4245         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_HIGH_GAIN_STEP,
4246                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_HIGH_GAIN_STEP));
4247         return MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_HIGH_GAIN_STEP;
4248     }
4249     else
4250     {
4251         /* Write pmdUpperHighGainStepAttack */
4252         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_UPPER1_THRSH_GAIN_STEP, device->rx->rxAgcCtrl->powerAgc->pmdUpperHighGainStepAttack, 0x1F, 0);
4253     }
4254 
4255     /* Range check pmdLowerLowGainStepRecovery (5-bit)  */
4256     if (device->rx->rxAgcCtrl->powerAgc->pmdLowerLowGainStepRecovery > 0x1F)
4257     {
4258         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_LOW_GAIN_STEP,
4259                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_LOW_GAIN_STEP));
4260         return MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_LOW_GAIN_STEP;
4261     }
4262     else
4263     {
4264         /* Write pmdLowerLowGainStepRecovery to temp var, then to register */
4265         lower1ThreshGainStepRegValue |= (device->rx->rxAgcCtrl->powerAgc->pmdLowerLowGainStepRecovery);
4266     }
4267 
4268     /* Range check pmdUpperLowGainStepRecovery (5-bit)  */
4269     if (device->rx->rxAgcCtrl->powerAgc->pmdUpperLowGainStepAttack > 0x1F)
4270     {
4271         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_LOW_GAIN_STEP,
4272                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_LOW_GAIN_STEP));
4273         return MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_LOW_GAIN_STEP;
4274     }
4275     else
4276     {
4277         /* Write pmdLowerLowGainStepRecovery to temp var, then to register */
4278         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_UPPER0_THRSH_GAIN_STEP, device->rx->rxAgcCtrl->powerAgc->pmdUpperLowGainStepAttack);
4279     }
4280 
4281     /* Range check pmdLowerHighGainStepRecovery (5-bit)  */
4282     if (device->rx->rxAgcCtrl->powerAgc->pmdLowerHighGainStepRecovery > 0x1F)
4283     {
4284         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_HIGH_GAIN_STEP,
4285                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_HIGH_GAIN_STEP));
4286         return MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_HIGH_GAIN_STEP;
4287     }
4288     else
4289     {
4290         /* Write pmdLowerLowGainStepRecovery to temp var, then to register */
4291         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_LOWER0_THRSH_GAIN_STEP, device->rx->rxAgcCtrl->powerAgc->pmdLowerHighGainStepRecovery);
4292     }
4293 
4294     /* WRITE REGISTERS FOR THE AGC PEAK DETECTOR (APD/HB2) STRUCTURE */
4295 
4296     /* Range check apdFastAttack and hb2FastAttack (1-bit)  */
4297     if (device->rx->rxAgcCtrl->peakAgc->apdFastAttack > 0x1 || device->rx->rxAgcCtrl->peakAgc->hb2FastAttack > 0x1)
4298     {
4299         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_PKDET_FAST_ATTACK_VALUE,
4300                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_PKDET_FAST_ATTACK_VALUE));
4301         return MYKONOS_ERR_INV_AGC_RX_PKDET_FAST_ATTACK_VALUE;
4302     }
4303     else
4304     {
4305         /* Write pmdLowerLowGainStepRecovery to temp var, then to register */
4306         lower1ThreshGainStepRegValue |=  (uint8_t)(device->rx->rxAgcCtrl->peakAgc->apdFastAttack << 7);
4307         lower1ThreshGainStepRegValue |=  (uint8_t)(device->rx->rxAgcCtrl->peakAgc->hb2FastAttack << 6);
4308         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_LOWER1_THRSH_GAIN_STEP, lower1ThreshGainStepRegValue);
4309     }
4310 
4311     /* Range check apdHighThresh */
4312     if ((device->rx->rxAgcCtrl->peakAgc->apdHighThresh > 0x3F) || (device->rx->rxAgcCtrl->peakAgc->apdHighThresh <= device->rx->rxAgcCtrl->peakAgc->apdLowThresh))
4313     {
4314         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_APD_HIGH_THRESH_PARM,
4315                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_APD_HIGH_THRESH_PARM));
4316         return MYKONOS_ERR_INV_AGC_RX_APD_HIGH_THRESH_PARM;
4317     }
4318     else
4319     {
4320         /* Write apdHighThresh */
4321         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_ULB_THRSH, device->rx->rxAgcCtrl->peakAgc->apdHighThresh, 0X3F, 0);
4322     }
4323 
4324     /* Range check apdLowThresh */
4325     if ((device->rx->rxAgcCtrl->peakAgc->apdLowThresh > 0x3F) || (device->rx->rxAgcCtrl->peakAgc->apdHighThresh < device->rx->rxAgcCtrl->peakAgc->apdLowThresh))
4326     {
4327         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_APD_LOW_THRESH_PARM,
4328                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_APD_LOW_THRESH_PARM));
4329         return MYKONOS_ERR_INV_AGC_RX_APD_LOW_THRESH_PARM;
4330     }
4331     else
4332     {
4333         /* write apdLowThresh */
4334         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_LLB_THRSH, device->rx->rxAgcCtrl->peakAgc->apdLowThresh, 0x3F, 0);
4335     }
4336 
4337     /* Range check hb2HighThresh */
4338     if (device->rx->rxAgcCtrl->peakAgc->hb2HighThresh < device->rx->rxAgcCtrl->peakAgc->hb2LowThresh)
4339     {
4340         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_HB2_HIGH_THRESH_PARM,
4341                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_HB2_HIGH_THRESH_PARM));
4342         return MYKONOS_ERR_INV_AGC_RX_HB2_HIGH_THRESH_PARM;
4343     }
4344     else
4345     {
4346         /* write hb2HighThresh */
4347         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OVRLD_PD_DEC_OVRLD_UPPER_THRSH, device->rx->rxAgcCtrl->peakAgc->hb2HighThresh);
4348     }
4349 
4350     /* Range check hb2LowThresh */
4351     if (device->rx->rxAgcCtrl->peakAgc->hb2LowThresh > device->rx->rxAgcCtrl->peakAgc->hb2HighThresh)
4352     {
4353         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_HB2_LOW_THRESH_PARM,
4354                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_HB2_LOW_THRESH_PARM));
4355         return MYKONOS_ERR_INV_AGC_RX_HB2_LOW_THRESH_PARM;
4356     }
4357     else
4358     {
4359         /* write hb2LowThresh */
4360         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OVRLD_PD_DEC_OVRLD_LOWER_THRSH, device->rx->rxAgcCtrl->peakAgc->hb2LowThresh);
4361     }
4362 
4363     /* Range check hb2VeryLowThresh */
4364     if (device->rx->rxAgcCtrl->peakAgc->hb2VeryLowThresh > device->rx->rxAgcCtrl->peakAgc->hb2LowThresh)
4365     {
4366         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_HB2_VERY_LOW_THRESH_PARM,
4367                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_HB2_VERY_LOW_THRESH_PARM));
4368         return MYKONOS_ERR_INV_AGC_RX_HB2_VERY_LOW_THRESH_PARM;
4369     }
4370     else
4371     {
4372         /* write hb2VeryLowThresh */
4373         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OVRLD_PD_DEC_VERYLOW_THRSH, device->rx->rxAgcCtrl->peakAgc->hb2VeryLowThresh);
4374     }
4375 
4376     /* Write threshold counter values for apdHigh/apdLow/hb2High/hb2Low/hb2VeryLow */
4377     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ULB_CNT_THRSH, device->rx->rxAgcCtrl->peakAgc->apdHighThreshExceededCnt);
4378     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_LLB_CNT_THRSH, device->rx->rxAgcCtrl->peakAgc->apdLowThreshExceededCnt);
4379     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_HIGH_OVRG_CNT_THRSH, device->rx->rxAgcCtrl->peakAgc->hb2HighThreshExceededCnt);
4380     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_LOW_OVRG_CNT_THRSH, device->rx->rxAgcCtrl->peakAgc->hb2LowThreshExceededCnt);
4381     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_VERYLOW_OVRG_CNT_THRSH, device->rx->rxAgcCtrl->peakAgc->hb2VeryLowThreshExceededCnt);
4382 
4383     /* Range check on apdHighGainStepAttack (5-bit) */
4384     if (device->rx->rxAgcCtrl->peakAgc->apdHighGainStepAttack > 0x1F)
4385     {
4386         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_APD_HIGH_GAIN_STEP_PARM,
4387                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_APD_HIGH_GAIN_STEP_PARM));
4388         return MYKONOS_ERR_INV_AGC_RX_APD_HIGH_GAIN_STEP_PARM;
4389     }
4390     else
4391     {
4392         /* Write apdHighGainStepAttack */
4393         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_OVRG_GAIN_STEP_1, device->rx->rxAgcCtrl->peakAgc->apdHighGainStepAttack);
4394     }
4395 
4396     /* Range check on apdLowGainStepRecovery (5-bit) */
4397     if (device->rx->rxAgcCtrl->peakAgc->apdLowGainStepRecovery > 0x1F)
4398     {
4399         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_APD_LOW_GAIN_STEP_PARM,
4400                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_APD_LOW_GAIN_STEP_PARM));
4401         return MYKONOS_ERR_INV_AGC_RX_APD_LOW_GAIN_STEP_PARM;
4402     }
4403     else
4404     {
4405         /* Write apdLowGainStepRecovery */
4406         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_OVRG_GAIN_STEP_4, device->rx->rxAgcCtrl->peakAgc->apdLowGainStepRecovery);
4407     }
4408 
4409     /* Range check on hb2HighGainStepAttack (5-bit) */
4410     if (device->rx->rxAgcCtrl->peakAgc->hb2HighGainStepAttack > 0x1F)
4411     {
4412         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_HB2_HIGH_GAIN_STEP_PARM,
4413                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_HB2_HIGH_GAIN_STEP_PARM));
4414         return MYKONOS_ERR_INV_AGC_RX_HB2_HIGH_GAIN_STEP_PARM;
4415     }
4416     else
4417     {
4418         /* Write hb2HighGainStepAttack */
4419         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_OVRG_GAIN_STEP_2, device->rx->rxAgcCtrl->peakAgc->hb2HighGainStepAttack);
4420     }
4421 
4422     /* Range check on hb2LowGainStepRecovery (5-bit) */
4423     if (device->rx->rxAgcCtrl->peakAgc->hb2LowGainStepRecovery > 0x1F)
4424     {
4425         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_HB2_LOW_GAIN_STEP_PARM,
4426                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_HB2_LOW_GAIN_STEP_PARM));
4427         return MYKONOS_ERR_INV_AGC_RX_HB2_LOW_GAIN_STEP_PARM;
4428     }
4429     else
4430     {
4431         /* Write hb2LowGainStepRecovery */
4432         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_OVRG_GAIN_STEP_5, device->rx->rxAgcCtrl->peakAgc->hb2LowGainStepRecovery);
4433     }
4434 
4435     /* Range check on hb2VeryLowGainStepRecovery (5-bit) */
4436     if (device->rx->rxAgcCtrl->peakAgc->hb2VeryLowGainStepRecovery > 0x1F)
4437     {
4438         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_HB2_VERY_LOW_GAIN_STEP_PARM,
4439                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_HB2_VERY_LOW_GAIN_STEP_PARM));
4440         return MYKONOS_ERR_INV_AGC_RX_HB2_VERY_LOW_GAIN_STEP_PARM;
4441     }
4442     else
4443     {
4444         /* Write hb2VeryLowGainStepRecovery */
4445         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_OVRG_GAIN_STEP_6, device->rx->rxAgcCtrl->peakAgc->hb2VeryLowGainStepRecovery);
4446     }
4447 
4448     /* Range Check on hb2OverloadDetectEnable */
4449     if (device->rx->rxAgcCtrl->peakAgc->hb2OverloadDetectEnable > 0x1)
4450     {
4451         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_ENABLE,
4452                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_ENABLE));
4453         return MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_ENABLE;
4454     }
4455 
4456     /* Range Check on hb2OverloadDetectEnable */
4457     if (device->rx->rxAgcCtrl->peakAgc->hb2OverloadDurationCnt > 0x7)
4458     {
4459         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_DUR_CNT,
4460                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_DUR_CNT));
4461         return MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_DUR_CNT;
4462     }
4463 
4464     /* Range Check on hb2OverloadDetectEnable */
4465     if (device->rx->rxAgcCtrl->peakAgc->hb2OverloadThreshCnt > 0xF)
4466     {
4467         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_THRESH_CNT,
4468                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_THRESH_CNT));
4469         return MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_THRESH_CNT;
4470     }
4471     else
4472     {
4473         /* Write the hb2OvldCfgRegValue, the combination of hb2OverloadThreshCnt, hb2OverloadDurationCnt, and hb2OverloadDetectEnable */
4474         hb2OvldCfgRegValue = (device->rx->rxAgcCtrl->peakAgc->hb2OverloadThreshCnt) |(uint8_t)(device->rx->rxAgcCtrl->peakAgc->hb2OverloadDurationCnt << 4)
4475                              | (uint8_t)(device->rx->rxAgcCtrl->peakAgc->hb2OverloadDetectEnable << 7);
4476         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OVRLD_PD_DEC_OVRLD_CFG, hb2OvldCfgRegValue);
4477     }
4478 
4479     /* Hard-coded value for the ADC overload configuration. Sets the HB2 offset to -6dB.*/
4480     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OVRLD_ADC_OVRLD_CFG, 0x18);
4481     /* Hard-coded value for APD decay setting. Setting allows for the quickest settling time of peak detector */
4482     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_RX_BLOCK_DET_DECAY, 0x0);
4483 
4484     /* performing a soft reset */
4485     return MYKONOS_resetRxAgc(device);
4486 }
4487 
4488 /**
4489  * \brief This function resets the AGC state machine
4490  *
4491  * Calling this function resets all state machines within the gain control and maximum gain.
4492  *
4493  * <B>Dependencies:</B>
4494  * - device->spiSettings
4495  *
4496  * \param device is structure pointer to the Mykonos data structure containing the device SPI settings
4497  *
4498  * \retval MYKONOS_ERR_OK Function completed successfully
4499  */
MYKONOS_resetRxAgc(mykonosDevice_t * device)4500 mykonosErr_t MYKONOS_resetRxAgc(mykonosDevice_t *device)
4501 {
4502     const uint8_t AGC_RESET = 0x80;
4503 
4504 #if (MYKONOS_VERBOSE == 1)
4505     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_resetRxAgc()\n");
4506 #endif
4507 
4508     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_CFG_2, 1, AGC_RESET, 7);
4509     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_CFG_2, 0, AGC_RESET, 7);
4510 
4511     return MYKONOS_ERR_OK;
4512 
4513 }
4514 
4515 /**
4516  * \brief This function sets the min/max gain indexes for AGC in the main RX channel
4517  *
4518  * Allows to change min/max gain index on runtime.
4519  * If RX1_RX2 selected, then the maxGainIndex/minGainIndex value will be applied to both channels.
4520  * If only Rx1 selected, then only Rx1 min/max gain indices will be updated, along with their device data structure values.
4521  * If only Rx2 selected, then only Rx2 min/max gain indices will be updated, along with their device data structure values.
4522  *
4523  * <B>Dependencies:</B>
4524  * - device->spiSettings
4525  * - device->rx->rxAgcCtrl
4526  *
4527  * \param device is structure pointer to the Mykonos data structure containing the device SPI settings
4528  * \param rxChannelSelect RX channel for setting the max and min gain index settings
4529  * \param maxGainIndex Max gain index setting
4530  * \param minGainIndex Min gain index setting
4531  *
4532  * \retval MYKONOS_ERR_SET_RX_MAX_GAIN_INDEX Max gain index bigger than max gain index loaded table.
4533  * \retval MYKONOS_ERR_SET_RX_MIN_GAIN_INDEX Min gain index lower than min gain index loaded table.
4534  * \retval MYKONOS_ERR_AGC_MIN_MAX_CHANNEL Wrong RX channel selected
4535  * \retval MYKONOS_ERR_OK Function completed successfully
4536  */
MYKONOS_setRxAgcMinMaxGainIndex(mykonosDevice_t * device,mykonosRxChannels_t rxChannelSelect,uint8_t maxGainIndex,uint8_t minGainIndex)4537 mykonosErr_t MYKONOS_setRxAgcMinMaxGainIndex(mykonosDevice_t *device, mykonosRxChannels_t rxChannelSelect, uint8_t maxGainIndex, uint8_t minGainIndex)
4538 {
4539     const uint8_t MIN_GAIN_INDEX = 1 + MAX_GAIN_TABLE_INDEX - (sizeof(RxGainTable) / sizeof(RxGainTable[0]));
4540 
4541 #if (MYKONOS_VERBOSE == 1)
4542     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setRxAgcMinMaxGainIndex()\n");
4543 #endif
4544 
4545     /* Check for maxGainIndex */
4546     if (maxGainIndex > MAX_GAIN_TABLE_INDEX)
4547     {
4548         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_RX_MAX_GAIN_INDEX,
4549                 getMykonosErrorMessage(MYKONOS_ERR_SET_RX_MAX_GAIN_INDEX));
4550         return MYKONOS_ERR_SET_RX_MAX_GAIN_INDEX;
4551     }
4552 
4553     /* Check for minGainIndex */
4554     if (minGainIndex < MIN_GAIN_INDEX)
4555     {
4556         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_RX_MIN_GAIN_INDEX,
4557                 getMykonosErrorMessage(MYKONOS_ERR_SET_RX_MIN_GAIN_INDEX));
4558         return MYKONOS_ERR_SET_RX_MIN_GAIN_INDEX;
4559     }
4560 
4561     if ((uint32_t)rxChannelSelect & (uint32_t)RX1)
4562     {
4563         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_RX1_MAX_GAIN_INDEX, maxGainIndex);
4564         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_RX1_MIN_GAIN_INDEX, minGainIndex);
4565         device->rx->rxAgcCtrl->agcRx1MaxGainIndex = maxGainIndex;
4566         device->rx->rxAgcCtrl->agcRx1MinGainIndex = minGainIndex;
4567     }
4568 
4569     if ((uint32_t)rxChannelSelect & (uint32_t)RX2)
4570     {
4571         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_RX2_MAX_GAIN_INDEX, maxGainIndex);
4572         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_RX2_MIN_GAIN_INDEX, minGainIndex);
4573         device->rx->rxAgcCtrl->agcRx2MaxGainIndex = maxGainIndex;
4574         device->rx->rxAgcCtrl->agcRx2MinGainIndex = minGainIndex;
4575     }
4576 
4577     /* Check for invalid Rx channel */
4578     if (!((uint32_t)rxChannelSelect & (uint32_t)RX1_RX2))
4579     {
4580         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_AGC_MIN_MAX_RX_CHANNEL,
4581                 getMykonosErrorMessage(MYKONOS_ERR_AGC_MIN_MAX_RX_CHANNEL));
4582         return MYKONOS_ERR_AGC_MIN_MAX_RX_CHANNEL;
4583     }
4584 
4585     return MYKONOS_ERR_OK;
4586 }
4587 
4588 /**
4589  * \brief This function sets the min/max gain indexes for AGC in the observation channel
4590  *
4591  * Allows to change min/max gain index on runtime.
4592  *
4593  * <B>Dependencies:</B>
4594  * - device->spiSettings
4595  * - device->rx->rxAgcCtrl
4596  *
4597  * \param device is structure pointer to the Mykonos data structure containing the device SPI settings
4598  * \param obsRxChannelSelect Observation channel for setting the max and min gain index settings
4599  * \param maxGainIndex Max gain index setting
4600  * \param minGainIndex Min gain index setting
4601  *
4602  * \retval MYKONOS_ERR_SET_ORX_MAX_GAIN_INDEX_CHANNEL Wrong read back channel.
4603  * \retval MYKONOS_ERR_SET_ORX_MAX_GAIN_INDEX Max gain index bigger than max gain index loaded table.
4604  * \retval MYKONOS_ERR_SET_ORX_MIN_GAIN_INDEX Min gain index lower than min gain index loaded table.
4605  * \retval MYKONOS_ERR_AGC_MIN_MAX_ORX_CHANNEL Wrong observation channel selected
4606  * \retval MYKONOS_ERR_OK Function completed successfully
4607  */
MYKONOS_setObsRxAgcMinMaxGainIndex(mykonosDevice_t * device,mykonosObsRxChannels_t obsRxChannelSelect,uint8_t maxGainIndex,uint8_t minGainIndex)4608 mykonosErr_t MYKONOS_setObsRxAgcMinMaxGainIndex(mykonosDevice_t *device, mykonosObsRxChannels_t obsRxChannelSelect, uint8_t maxGainIndex, uint8_t minGainIndex)
4609 {
4610     uint8_t rdObsActive = 0x00;
4611     uint8_t obsActive = 0x00;
4612     uint8_t obsCheck = 0x00;
4613     uint8_t minGainIndexCheck = 0x00;
4614     uint8_t maxGainIndexCheck = 0x00;
4615 
4616 #if (MYKONOS_VERBOSE == 1)
4617     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setObsRxAgcMinMaxGainIndex()\n");
4618 #endif
4619 
4620     /* Read active channel */
4621     CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_ACTIVE, &rdObsActive, 0x03, 0);
4622 
4623     /* Check active channel and set min/max checks */
4624     switch (rdObsActive)
4625     {
4626         case 0x00:
4627         case 0x01:
4628             /*sniffer*/
4629             maxGainIndexCheck = MAX_GAIN_TABLE_INDEX;
4630             minGainIndexCheck = MAX_GAIN_TABLE_INDEX - (sizeof(SnRxGainTable) / sizeof(SnRxGainTable[0]));
4631             obsActive = (uint32_t)OBS_SNIFFER | (uint32_t)OBS_SNIFFER_A | (uint32_t)OBS_SNIFFER_B | (uint32_t)OBS_SNIFFER_C;
4632             break;
4633         case 0x02:
4634         case 0x03:
4635             /*observation 1*/
4636             maxGainIndexCheck = MAX_GAIN_TABLE_INDEX;
4637             minGainIndexCheck = MAX_GAIN_TABLE_INDEX - (sizeof(ORxGainTable) / sizeof(ORxGainTable[0]));
4638             obsActive = (uint32_t)OBS_RX1_TXLO | (uint32_t)OBS_RX1_SNIFFERLO | (uint32_t)OBS_RX2_TXLO | (uint32_t)OBS_RX2_SNIFFERLO;
4639             break;
4640 
4641         default:
4642             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_ORX_MAX_GAIN_INDEX_CHANNEL,
4643                     getMykonosErrorMessage(MYKONOS_ERR_SET_ORX_MAX_GAIN_INDEX_CHANNEL));
4644             return MYKONOS_ERR_SET_ORX_MAX_GAIN_INDEX_CHANNEL;
4645     }
4646 
4647     /* Check for maxGainIndex */
4648     if ((maxGainIndex > maxGainIndexCheck) || (maxGainIndex < minGainIndexCheck))
4649     {
4650         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_ORX_MAX_GAIN_INDEX,
4651                 getMykonosErrorMessage(MYKONOS_ERR_SET_ORX_MAX_GAIN_INDEX));
4652         return MYKONOS_ERR_SET_ORX_MAX_GAIN_INDEX;
4653     }
4654 
4655     /* Check for minGainIndex */
4656     if ((minGainIndex < minGainIndexCheck) || (minGainIndex > maxGainIndexCheck))
4657     {
4658         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_ORX_MIN_GAIN_INDEX,
4659                 getMykonosErrorMessage(MYKONOS_ERR_SET_ORX_MIN_GAIN_INDEX));
4660         return MYKONOS_ERR_SET_ORX_MIN_GAIN_INDEX;
4661     }
4662 
4663     device->obsRx->orxAgcCtrl->agcObsRxMaxGainIndex = maxGainIndex;
4664     device->obsRx->orxAgcCtrl->agcObsRxMinGainIndex = minGainIndex;
4665 
4666     switch (obsRxChannelSelect)
4667     {
4668         case OBS_SNIFFER:
4669         case OBS_SNIFFER_A:
4670         case OBS_SNIFFER_B:
4671         case OBS_SNIFFER_C:
4672             obsCheck = (uint32_t)OBS_SNIFFER | (uint32_t)OBS_SNIFFER_A | (uint32_t)OBS_SNIFFER_B | (uint32_t)OBS_SNIFFER_C;
4673             maxGainIndex = maxGainIndex - MAX_SNRX_GAIN_TABLE_NUMINDEXES;
4674             minGainIndex = minGainIndex - MAX_SNRX_GAIN_TABLE_NUMINDEXES;
4675             break;
4676 
4677         case OBS_RX1_TXLO:
4678         case OBS_RX2_TXLO:
4679         case OBS_RX1_SNIFFERLO:
4680         case OBS_RX2_SNIFFERLO:
4681             obsCheck = (uint32_t)OBS_RX1_TXLO | (uint32_t)OBS_RX1_SNIFFERLO | (uint32_t)OBS_RX2_TXLO | (uint32_t)OBS_RX2_SNIFFERLO;
4682             maxGainIndex = maxGainIndex - MAX_ORX_GAIN_TABLE_NUMINDEXES;
4683             minGainIndex = minGainIndex - MAX_ORX_GAIN_TABLE_NUMINDEXES;
4684             break;
4685 
4686         default:
4687             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_AGC_MIN_MAX_ORX_CHANNEL,
4688                     getMykonosErrorMessage(MYKONOS_ERR_AGC_MIN_MAX_ORX_CHANNEL));
4689             return MYKONOS_ERR_AGC_MIN_MAX_ORX_CHANNEL;
4690     }
4691 
4692     if (obsCheck == obsActive)
4693     {
4694         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_MAX_GAIN_INDEX, maxGainIndex);
4695         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_MIN_GAIN_INDEX, minGainIndex);
4696     }
4697     else
4698     {
4699         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_AGC_MIN_MAX_ORX_CHANNEL,
4700                 getMykonosErrorMessage(MYKONOS_ERR_AGC_MIN_MAX_ORX_CHANNEL));
4701         return MYKONOS_ERR_AGC_MIN_MAX_ORX_CHANNEL;
4702     }
4703 
4704     return MYKONOS_ERR_OK;
4705 }
4706 
4707 /**
4708  * \brief This function sets the Temperature gain compensation for Rx1 channel
4709  *
4710  * The temperature gain compensation control allow for a +3000mdB to -3000mdB digital gain
4711  * in the data path.
4712  * The resolution of the temperature compensation gain is 250mdB.
4713  *
4714  * <B>Dependencies:</B>
4715  * - device->spiSettings
4716  *
4717  * \param device is structure pointer to the Mykonos data structure containing the device SPI settings
4718  * \param rx1TempCompGain_mdB gain compensation for Rx1, the range is from -3000mdB to +3000mdB in steps of 250mdB
4719  *
4720  * \retval MYKONOS_ERR_RX1_TEMP_GAIN_COMP_RANGE The temp gain compensation is outside range (-3000mdB to 3000mdB)
4721  * \retval MYKONOS_ERR_RX1_TEMP_GAIN_COMP_STEP Not valid temp gain compensation, step size is 250mdB
4722  * \retval MYKONOS_ERR_OK Function completed successfully
4723  */
MYKONOS_setRx1TempGainComp(mykonosDevice_t * device,int16_t rx1TempCompGain_mdB)4724 mykonosErr_t MYKONOS_setRx1TempGainComp(mykonosDevice_t *device, int16_t rx1TempCompGain_mdB)
4725 {
4726     int8_t tempGainComp = 0x00;
4727 
4728     const int16_t LOW_LIMIT_GAIN_COMP = -3000;
4729     const int16_t HIGH_LIMIT_GAIN_COMP = 3000;
4730     const int16_t GAIN_COMP_STEP = 250;
4731 
4732 #if (MYKONOS_VERBOSE == 1)
4733     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setRx1TempGainComp()\n");
4734 #endif
4735 
4736     /* Check for Gain compensation range */
4737     if ((rx1TempCompGain_mdB > HIGH_LIMIT_GAIN_COMP) || (rx1TempCompGain_mdB < LOW_LIMIT_GAIN_COMP))
4738     {
4739         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RX1_TEMP_GAIN_COMP_RANGE,
4740                 getMykonosErrorMessage(MYKONOS_ERR_RX1_TEMP_GAIN_COMP_RANGE));
4741         return MYKONOS_ERR_RX1_TEMP_GAIN_COMP_RANGE;
4742     }
4743 
4744     /* Check for Gain compensation steps */
4745     if (rx1TempCompGain_mdB % GAIN_COMP_STEP)
4746     {
4747         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RX1_TEMP_GAIN_COMP_STEP,
4748                 getMykonosErrorMessage(MYKONOS_ERR_RX1_TEMP_GAIN_COMP_STEP));
4749         return MYKONOS_ERR_RX1_TEMP_GAIN_COMP_STEP;
4750     }
4751 
4752     /* Prepare register write */
4753     tempGainComp = (rx1TempCompGain_mdB / GAIN_COMP_STEP) & 0x1F;
4754     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX1_TEMP_GAIN_COMP, (uint8_t)tempGainComp);
4755 
4756     return MYKONOS_ERR_OK;
4757 }
4758 
4759 /**
4760  * \brief This function gets the Temperature gain compensation for Rx1
4761  *
4762  * <B>Dependencies:</B>
4763  * - device->spiSettings
4764  *
4765  * \param device is structure pointer to the Mykonos data structure containing the device SPI settings
4766  * \param rx1TempCompGain_mdB Which will be populated with the Temperature Gain Compensation in mdB value for Rx1 channel.
4767  *
4768  * \retval MYKONOS_ERR_RX1_TEMP_GAIN_COMP_NULL rx1TempCompGain_mdB pointer is null.
4769  * \retval MYKONOS_ERR_OK Function completed successfully
4770  */
MYKONOS_getRx1TempGainComp(mykonosDevice_t * device,int16_t * rx1TempCompGain_mdB)4771 mykonosErr_t MYKONOS_getRx1TempGainComp(mykonosDevice_t *device, int16_t *rx1TempCompGain_mdB)
4772 {
4773     uint8_t tempGainComp = 0x00;
4774     int8_t tempGainCompDB = 0x00;
4775 
4776     const int16_t GAIN_COMP_STEP = 250;
4777 
4778 #if (MYKONOS_VERBOSE == 1)
4779     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getRx1TempGainComp()\n");
4780 #endif
4781 
4782     /* Check for null passed parameter */
4783     if (rx1TempCompGain_mdB == NULL)
4784     {
4785         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RX1_TEMP_GAIN_COMP_NULL,
4786                 getMykonosErrorMessage(MYKONOS_ERR_RX1_TEMP_GAIN_COMP_NULL));
4787         return MYKONOS_ERR_RX1_TEMP_GAIN_COMP_NULL;
4788     }
4789 
4790     /* Read Temperature Gain Compensation */
4791     CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_RX1_TEMP_GAIN_COMP, &tempGainComp);
4792 
4793     /* Convert to dB and prepare the signed return */
4794     tempGainCompDB = tempGainComp & 0x1F;
4795     if (tempGainCompDB & 0x10)
4796     {
4797         tempGainCompDB = ((((~((uint8_t)tempGainCompDB)) & 0x0F) + 1) * (-1));
4798     }
4799 
4800     /* Assign value to the passed pointer */
4801     *rx1TempCompGain_mdB = tempGainCompDB * GAIN_COMP_STEP;
4802 
4803     return MYKONOS_ERR_OK;
4804 }
4805 
4806 /**
4807  * \brief This function sets the Temperature gain compensation for Rx2 channel
4808  *
4809  * The temperature gain compensation control allow for a +3000mdB to -3000mdB digital gain
4810  * in the data path.
4811  * The resolution of the temperature compensation gain is 250mdB.
4812  *
4813  * <B>Dependencies:</B>
4814  * - device->spiSettings
4815  *
4816  * \param device is structure pointer to the Mykonos data structure containing the device SPI settings
4817  * \param rx2TempCompGain_mdB gain compensation for Rx1,
4818  * the range is from -3000mdB to +3000mdB in steps of 250mdB
4819  *
4820  * \retval MYKONOS_ERR_RX2_TEMP_GAIN_COMP_RANGE The temp gain compensation is outside range (-3000mdB to 3000mdB)
4821  * \retval MYKONOS_ERR_RX2_TEMP_GAIN_COMP_STEP Not valid temp gain compensation, step size is 250mdB
4822  * \retval MYKONOS_ERR_OK Function completed successfully
4823  */
MYKONOS_setRx2TempGainComp(mykonosDevice_t * device,int16_t rx2TempCompGain_mdB)4824 mykonosErr_t MYKONOS_setRx2TempGainComp(mykonosDevice_t *device, int16_t rx2TempCompGain_mdB)
4825 {
4826     int8_t tempGainComp = 0x00;
4827 
4828     const int16_t LOW_LIMIT_GAIN_COMP = -3000;
4829     const int16_t HIGH_LIMIT_GAIN_COMP = 3000;
4830     const int16_t GAIN_COMP_STEP = 250;
4831 
4832 #if (MYKONOS_VERBOSE == 1)
4833     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setRx2TempGainComp()\n");
4834 #endif
4835 
4836     /* Check for Gain compensation range */
4837     if ((rx2TempCompGain_mdB > HIGH_LIMIT_GAIN_COMP) || (rx2TempCompGain_mdB < LOW_LIMIT_GAIN_COMP))
4838     {
4839         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RX2_TEMP_GAIN_COMP_RANGE,
4840                 getMykonosErrorMessage(MYKONOS_ERR_RX2_TEMP_GAIN_COMP_RANGE));
4841         return MYKONOS_ERR_RX2_TEMP_GAIN_COMP_RANGE;
4842     }
4843 
4844     /* Check for Gain compensation range */
4845     if (rx2TempCompGain_mdB % GAIN_COMP_STEP)
4846     {
4847         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RX2_TEMP_GAIN_COMP_STEP,
4848                 getMykonosErrorMessage(MYKONOS_ERR_RX2_TEMP_GAIN_COMP_STEP));
4849         return MYKONOS_ERR_RX2_TEMP_GAIN_COMP_STEP;
4850     }
4851 
4852     /* Prepare register write */
4853     tempGainComp = (rx2TempCompGain_mdB / GAIN_COMP_STEP) & 0x1F;
4854     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_RX2_TEMP_GAIN_COMP, (uint8_t)tempGainComp);
4855 
4856     return MYKONOS_ERR_OK;
4857 }
4858 
4859 /**
4860  * \brief This function gets the Temperature gain compensation for Rx2
4861  *
4862  * <B>Dependencies:</B>
4863  * - device->spiSettings
4864  *
4865  * \param device is structure pointer to the Mykonos data structure containing the device SPI settings
4866  * \param rx2TempCompGain_mdB Which will be populated with the Temperature Gain Compensation in mdB value for Rx2 channel.
4867  *
4868  * \retval MYKONOS_ERR_RX2_TEMP_GAIN_COMP_NULL rx2TempCompGain_mdB pointer is null.
4869  * \retval MYKONOS_ERR_OK Function completed successfully
4870  */
MYKONOS_getRx2TempGainComp(mykonosDevice_t * device,int16_t * rx2TempCompGain_mdB)4871 mykonosErr_t MYKONOS_getRx2TempGainComp(mykonosDevice_t *device, int16_t *rx2TempCompGain_mdB)
4872 {
4873     uint8_t tempGainComp = 0x00;
4874     int8_t tempGainCompDB = 0x00;
4875 
4876     const int16_t GAIN_COMP_STEP = 250;
4877 
4878 #if (MYKONOS_VERBOSE == 1)
4879     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getRx2TempGainComp()\n");
4880 #endif
4881 
4882     /* Check for null passed parameter */
4883     if (rx2TempCompGain_mdB == NULL)
4884     {
4885         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RX2_TEMP_GAIN_COMP_NULL,
4886                 getMykonosErrorMessage(MYKONOS_ERR_RX2_TEMP_GAIN_COMP_NULL));
4887         return MYKONOS_ERR_RX2_TEMP_GAIN_COMP_NULL;
4888     }
4889 
4890     /* Read programmed Temperature Gain Compensation */
4891     CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_RX2_TEMP_GAIN_COMP, &tempGainComp);
4892 
4893     /* Convert to dB and prepare the signed return */
4894     tempGainCompDB = tempGainComp & 0x1F;
4895     if (tempGainCompDB & 0x10)
4896     {
4897         tempGainCompDB = (((~((uint8_t)tempGainCompDB)) & 0x0F) + 1) * (-1);
4898     }
4899 
4900     /* Assign value to the passed pointer */
4901     *rx2TempCompGain_mdB = tempGainCompDB * GAIN_COMP_STEP;
4902 
4903     return MYKONOS_ERR_OK;
4904 }
4905 
4906 /**
4907  * \brief This function sets the Temperature gain compensation for the observation channel
4908  *
4909  * The temperature gain compensation control allow for a +3000mdB to -3000mdB digital gain
4910  * in the data path.
4911  * The resolution of the temperature compensation gain is 250mdB.
4912  *
4913  * <B>Dependencies:</B>
4914  * - device->spiSettings
4915  *
4916  * \param device is structure pointer to the Mykonos data structure containing the device SPI settings
4917  * \param obsRxTempCompGain_mdB gain compensation for observation channel,
4918  * the range is from -3000mdB to +3000mdB in steps of 250mdB
4919  *
4920  * \retval MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_RANGE The temp gain compensation is outside range (-3000mdB to 3000mdB)
4921  * \retval MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_STEP Not valid temp gain compensation, step size is 250mdB
4922  * \retval MYKONOS_ERR_OK Function completed successfully
4923  */
MYKONOS_setObsRxTempGainComp(mykonosDevice_t * device,int16_t obsRxTempCompGain_mdB)4924 mykonosErr_t MYKONOS_setObsRxTempGainComp(mykonosDevice_t *device, int16_t obsRxTempCompGain_mdB)
4925 {
4926     int8_t tempGainComp = 0x00;
4927 
4928     const int16_t LOW_LIMIT_GAIN_COMP = -3000;
4929     const int16_t HIGH_LIMIT_GAIN_COMP = 3000;
4930     const int16_t GAIN_COMP_STEP = 250;
4931 
4932 #if (MYKONOS_VERBOSE == 1)
4933     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setObsRxTempGainComp()\n");
4934 #endif
4935 
4936     /* Check for Gain compensation range */
4937     if ((obsRxTempCompGain_mdB > HIGH_LIMIT_GAIN_COMP) || (obsRxTempCompGain_mdB < LOW_LIMIT_GAIN_COMP))
4938     {
4939         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_RANGE,
4940                 getMykonosErrorMessage(MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_RANGE));
4941         return MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_RANGE;
4942     }
4943 
4944     /* Check for Gain compensation range */
4945     if (obsRxTempCompGain_mdB % GAIN_COMP_STEP)
4946     {
4947         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_STEP,
4948                 getMykonosErrorMessage(MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_STEP));
4949         return MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_STEP;
4950     }
4951 
4952     /* Prepare register write */
4953     tempGainComp = (obsRxTempCompGain_mdB / GAIN_COMP_STEP) & 0x1F;
4954     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_TEMP_GAIN_COMP, (uint8_t)tempGainComp);
4955 
4956     return MYKONOS_ERR_OK;
4957 }
4958 
4959 /**
4960  * \brief This function gets the Temperature gain compensation for the observation channel
4961  *
4962  *
4963  * <B>Dependencies:</B>
4964  * - device->spiSettings
4965  *
4966  * \param device is structure pointer to the Mykonos data structure containing the device SPI settings
4967  * \param obsRxTempCompGain_mdB Which will be populated with the Temperature Gain Compensation in mdB value for the observation channel.
4968  *
4969  * \retval MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_NULL obsRxTempCompGain_mdB pointer is null.
4970  * \retval MYKONOS_ERR_OK Function completed successfully
4971  */
MYKONOS_getObsRxTempGainComp(mykonosDevice_t * device,int16_t * obsRxTempCompGain_mdB)4972 mykonosErr_t MYKONOS_getObsRxTempGainComp(mykonosDevice_t *device, int16_t *obsRxTempCompGain_mdB)
4973 {
4974     uint8_t tempGainComp = 0x00;
4975     int8_t tempGainCompDB = 0x00;
4976 
4977     const int16_t GAIN_COMP_STEP = 250;
4978 
4979 #if (MYKONOS_VERBOSE == 1)
4980     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getObsRxTempGainComp()\n");
4981 #endif
4982 
4983     /* Check for null passed parameter */
4984     if (obsRxTempCompGain_mdB == NULL)
4985     {
4986         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_NULL,
4987                 getMykonosErrorMessage(MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_NULL));
4988         return MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_NULL;
4989     }
4990 
4991     CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_OBS_TEMP_GAIN_COMP, &tempGainComp);
4992 
4993     /* Convert to dB and prepare the signed return */
4994     tempGainCompDB = tempGainComp & 0x1F;
4995     if (tempGainCompDB & 0x10)
4996     {
4997         tempGainCompDB = (((~((uint8_t)tempGainCompDB)) & 0x0F) + 1) * (-1);
4998     }
4999 
5000     /* Assign value to the passed pointer */
5001     *obsRxTempCompGain_mdB = tempGainCompDB * GAIN_COMP_STEP;
5002 
5003     return MYKONOS_ERR_OK;
5004 }
5005 
5006 /**
5007  * \brief Enables or disables the Rx slow loop gain counter to use the sync pulse
5008  *
5009  * <B>Dependencies:</B>
5010  * - device->spiSettings
5011  *
5012  * \param device is structure pointer to the Mykonos data structure containing the device SPI settings
5013  * \param enable is a uint8_t data type where '0' = disable Rx gain counter from using sync pulse, '1' = enable Rx gain. All other values will throw an error.
5014  * counter to use the sync pulse. This value is written back to the device data structure for storage.
5015  *
5016  * \retval MYKONOS_ERR_OK Function completed successfully
5017  */
MYKONOS_enableRxGainCtrSyncPulse(mykonosDevice_t * device,uint8_t enable)5018 mykonosErr_t MYKONOS_enableRxGainCtrSyncPulse(mykonosDevice_t *device, uint8_t enable)
5019 {
5020     const uint8_t syncPulseBitMask = 0x80;
5021     uint8_t enableBit = 0;
5022 
5023 #if (MYKONOS_VERBOSE == 1)
5024     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setRxGainCtrSyncPulse()\n");
5025 #endif
5026 
5027     /* read, modify, write Rx gain counter sync pulse enable bit */
5028     enableBit = (enable > 0) ? 1 : 0;
5029     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_LOOP_CFG, enableBit, syncPulseBitMask, 7);
5030 
5031     return MYKONOS_ERR_OK;
5032 }
5033 
5034 /**
5035  * \brief Configures the Rx gain control mode
5036  *
5037  * <B>Dependencies:</B>
5038  * - device->spiSettings
5039  * - device->spiSettings->chipSelectIndex
5040  * - device->rx->rxGainCtrl->gainMode
5041  *
5042  * \param device is structure pointer to the Mykonos data structure containing settings
5043  * \param mode is a mykonosGainMode_t enumerated gain control mode type where:
5044  * Manual Gain = MGC, Automatic Gain Control = AGC, and hybrid mode = HYBRID
5045  *
5046  * When the mode enumerated type is passed, the Rx1 and Rx2 gain mode is set to this value and the
5047  * Rx gainMode structure member is updated with the new value
5048  *
5049  * \retval MYKONOS_ERR_OK Function completed successfully
5050  * \retval MYKONOS_ERR_INV_RX_GAIN_MODE_PARM Invalid AGC mode pass in function mode paramter
5051  */
MYKONOS_setRxGainControlMode(mykonosDevice_t * device,mykonosGainMode_t mode)5052 mykonosErr_t MYKONOS_setRxGainControlMode(mykonosDevice_t *device, mykonosGainMode_t mode)
5053 {
5054     uint8_t rxGainCfgReg = 0;
5055 
5056     const uint8_t RX_GAIN_TYPE_MASK = 0x1F;
5057     const uint8_t RX_GAIN_HYBRID_MASK = 0x10;
5058     const uint8_t RX_GAIN_TYPE_SHIFT = 0x02;
5059 
5060 #if (MYKONOS_VERBOSE == 1)
5061     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setRxGainControlMode()\n");
5062 #endif
5063 
5064     /* read AGC type for Rx1 and Rx2 for modify, write */
5065     CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_AGC_CFG_1, &rxGainCfgReg);
5066     rxGainCfgReg &= ~RX_GAIN_TYPE_MASK;
5067 
5068     /* performing AGC type check */
5069     switch (mode)
5070     {
5071         case MGC:
5072             rxGainCfgReg &= ~RX_GAIN_HYBRID_MASK;
5073             break;
5074         case AGC:
5075             rxGainCfgReg &= ~RX_GAIN_HYBRID_MASK;
5076             break;
5077         case HYBRID:
5078             rxGainCfgReg |= RX_GAIN_HYBRID_MASK;
5079             break;
5080         default:
5081             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_RX_GAIN_MODE_PARM,
5082                     getMykonosErrorMessage(MYKONOS_ERR_INV_RX_GAIN_MODE_PARM));
5083             return MYKONOS_ERR_INV_RX_GAIN_MODE_PARM;
5084     }
5085 
5086     /* modify, write AGC type for Rx1 and Rx2 */
5087     rxGainCfgReg |= (uint8_t)mode;
5088     rxGainCfgReg |= (uint8_t)((uint8_t)mode << RX_GAIN_TYPE_SHIFT);
5089     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_CFG_1, rxGainCfgReg);
5090 
5091     /* writing mode setting to data structure */
5092     if ((device->profilesValid & RX_PROFILE_VALID) > 0)
5093     {
5094         device->rx->rxGainCtrl->gainMode = mode;
5095     }
5096 
5097     return MYKONOS_ERR_OK;
5098 }
5099 
5100 /**
5101  * \brief Performs a power measurement in the Rx1 digital data path.
5102  *
5103  * Due to interdependencies between the AGC and power measurement the power measurement duration and
5104  * where the measurement is taken is variable.
5105  * The location of the power measurement is given by device->rx->rxAgcCtrl->rxPwrAgc->pmdMeasConfig
5106  * The number of samples the power measurement uses is given by 8*2^(device->rx->rxAgcCtrl->rxPwrAgc->pmdMeasDuration) at the IQ rate,
5107  * if measured at RFIR output. This number of samples must be less than the agcGainUpdateCounter.
5108  * If the receiver is disabled during the power measurement, this function returns a 0 value for rx1DecPower_mdBFS
5109  *
5110  * The resolution of this function is 0.25dB.
5111  * The dynamic range of this function is 40dB. Signals lower than 40dBFS may not be measured accurately.
5112  *
5113  * <B>Dependencies</B>
5114  * - device->spiSettings
5115  * - device->rx->rxAgcCtrl->rxPwrAgc->pmdMeasConfig
5116  * - device->rx->rxAgcCtrl->rxPwrAgc->pmdMeasDuration
5117  *
5118  * \param device Pointer to the Mykonos data structure
5119  * \param rx1DecPower_mdBFS Pointer to store the Rx1 decimated power return.  Value returned in mdBFS
5120  *
5121  * \retval MYKONOS_ERR_OK Function completed successfully
5122  */
MYKONOS_getRx1DecPower(mykonosDevice_t * device,uint16_t * rx1DecPower_mdBFS)5123 mykonosErr_t MYKONOS_getRx1DecPower(mykonosDevice_t *device, uint16_t *rx1DecPower_mdBFS)
5124 {
5125     uint8_t rx1DecPower_dBFS = 0;
5126 
5127 #if (MYKONOS_VERBOSE == 1)
5128     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getRx1DecPower()\n");
5129 #endif
5130 
5131     /* read Rx1 Dec Power Measurement */
5132     if (rx1DecPower_mdBFS != NULL)
5133     {
5134         CMB_SPIReadByte(device->spiSettings, MYKONOS_CH1_DECIMATED_PWR, &rx1DecPower_dBFS);
5135         *rx1DecPower_mdBFS = (uint16_t)(rx1DecPower_dBFS * 250); /* 250 = 1000 * 0.25dB */
5136     }
5137     else
5138     {
5139         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_RX1_DEC_POWER_NULL_PARM,
5140                 getMykonosErrorMessage(MYKONOS_ERR_GET_RX1_DEC_POWER_NULL_PARM));
5141         return MYKONOS_ERR_GET_RX1_DEC_POWER_NULL_PARM;
5142     }
5143 
5144     return MYKONOS_ERR_OK;
5145 }
5146 
5147 /**
5148  * \brief Performs a power measurement in the Rx2 digital data path.
5149  *
5150  * Due to interdependencies between the AGC and power measurement the power measurement duration and
5151  * where the measurement is taken is variable.
5152  * The location of the power measurement is given by device->rx->rxAgcCtrl->rxPwrAgc->pmdMeasConfig
5153  * The number of samples the power measurement uses is given by 8*2^(device->rx->rxAgcCtrl->rxPwrAgc->pmdMeasDuration) at the IQ rate,
5154  * if measured at RFIR output. This number of samples must be less than the agcGainUpdateCounter.
5155  * If the receiver is disabled during the power measurement, this function returns a 0 value for rx2DecPower_mdBFS
5156  *
5157  * The resolution of this function is 0.25dB.
5158  * The dynamic range of this function is 40dB. Signals lower than 40dBFS may not be measured accurately.
5159  *
5160  * <B>Dependencies</B>
5161  * - device->spiSettings
5162  *
5163  * \param device Pointer to the Mykonos data structure
5164  * \param rx2DecPower_mdBFS Pointer to store the Rx1 decimated power return.  Value returned in mdBFS
5165  *
5166  * \retval MYKONOS_ERR_OK Function completed successfully
5167  */
MYKONOS_getRx2DecPower(mykonosDevice_t * device,uint16_t * rx2DecPower_mdBFS)5168 mykonosErr_t MYKONOS_getRx2DecPower(mykonosDevice_t *device, uint16_t *rx2DecPower_mdBFS)
5169 {
5170     uint8_t rx2DecPower_dBFS = 0;
5171 
5172 #if (MYKONOS_VERBOSE == 1)
5173     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getRx2DecPower()\n");
5174 #endif
5175 
5176     /* read Rx2 Dec Power Measurement */
5177     if (rx2DecPower_mdBFS != NULL)
5178     {
5179         CMB_SPIReadByte(device->spiSettings, MYKONOS_CH2_DECIMATED_PWR, &rx2DecPower_dBFS);
5180         *rx2DecPower_mdBFS = (uint16_t)(rx2DecPower_dBFS * 250); /* 250 = 1000 * 0.25dB */
5181     }
5182     else
5183     {
5184         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_RX2_DEC_POWER_NULL_PARM,
5185                 getMykonosErrorMessage(MYKONOS_ERR_GET_RX2_DEC_POWER_NULL_PARM));
5186         return MYKONOS_ERR_GET_RX2_DEC_POWER_NULL_PARM;
5187     }
5188 
5189     return MYKONOS_ERR_OK;
5190 }
5191 
5192 /*
5193  *****************************************************************************
5194  * Observation Rx Data path functions
5195  *****************************************************************************
5196  */
5197 
5198 /**
5199  * \brief Sets the default Obs Rx channel to enter when device moves from
5200  *        radioOff to radioOn
5201  *
5202  * By default, the observation receiver remains powered down when the device
5203  * moves into the radioOn state.  If the BBIC prefers a particular ObsRx
5204  * channel to be enabled, this function can be called in radioOff to set
5205  * the default channel to power up when the device moves to radioOn.
5206  *
5207  * <B>Dependencies</B>
5208  * - device->spiSettings->chipSelectIndex
5209  * - device->obsRx->defaultObsRxChannel
5210  *
5211  * \param device is structure pointer to the Mykonos data structure containing settings
5212  * \param defaultObsRxCh is mykonosObsRxChannels_t enum type which selects the desired observation receive path to power up
5213  *
5214  * \retval MYKONOS_ERR_OK Function completed successfully
5215  * \retval MYKONOS_ERR_SETDEFOBSRXPATH_NULL_OBSRX_STRUCT Observation profile not valid, device->obsRx structure is NULL
5216  * \retval MYKONOS_ERR_SETDEFOBSRXPATH_NULL_DEF_OBSRX_STRUCT Invalid defaultObsRxCh function parameter
5217  */
MYKONOS_setDefaultObsRxPath(mykonosDevice_t * device,mykonosObsRxChannels_t defaultObsRxCh)5218 mykonosErr_t MYKONOS_setDefaultObsRxPath(mykonosDevice_t *device, mykonosObsRxChannels_t defaultObsRxCh)
5219 {
5220     uint8_t orxEntryMode[1] = {0};
5221     uint16_t byteOffset = 0;
5222     mykonosErr_t retVal = MYKONOS_ERR_OK;
5223 
5224 #if (MYKONOS_VERBOSE == 1)
5225     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setDefaultObsRxPath()\n");
5226 #endif
5227 
5228     if (device->obsRx == NULL)
5229     {
5230         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETDEFOBSRXPATH_NULL_DEF_OBSRX_STRUCT,
5231                 getMykonosErrorMessage(MYKONOS_ERR_SETDEFOBSRXPATH_NULL_DEF_OBSRX_STRUCT));
5232         return MYKONOS_ERR_SETDEFOBSRXPATH_NULL_DEF_OBSRX_STRUCT;
5233     }
5234 
5235     if (((defaultObsRxCh > OBS_RX2_SNIFFERLO) && (defaultObsRxCh != OBS_SNIFFER_A) && (defaultObsRxCh != OBS_SNIFFER_B) && (defaultObsRxCh != OBS_SNIFFER_C)))
5236     {
5237         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_PU_OBSRXPATH_INV_PARAM,
5238                 getMykonosErrorMessage(MYKONOS_ERR_PU_OBSRXPATH_INV_PARAM));
5239         return MYKONOS_ERR_PU_OBSRXPATH_INV_PARAM;
5240     }
5241 
5242     device->obsRx->defaultObsRxChannel = defaultObsRxCh;
5243     orxEntryMode[0] = ((uint8_t)device->obsRx->defaultObsRxChannel & 0xFF);
5244 
5245     byteOffset = 6;
5246     retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_RADIO_CONTROL, byteOffset, &orxEntryMode[0], 1);
5247     if (retVal != MYKONOS_ERR_OK)
5248     {
5249         return retVal;
5250     }
5251 
5252     return MYKONOS_ERR_OK;
5253 }
5254 
5255 /**
5256  * \brief Powers up or down the Observation Rx signal chain in the radioOn state
5257  *
5258  * When the ARM radio control is in ARM command mode, this
5259  * function allows the user to selectively power up or down the desired ObsRx
5260  * data path. If this function is called when the ARM is expecting GPIO pin
5261  * control of the ObsRx path source, an error will be returned.
5262  *
5263  * <B>Dependencies</B>
5264  * - device->spiSettings->chipSelectIndex
5265  *
5266  * \param device is structure pointer to the Mykonos data structure containing settings
5267  * \param obsRxCh is mykonosObsRxChannels_t enum type which selects the desired observation receive path to power up
5268  *
5269  * \retval MYKONOS_ERR_OK Function completed successfully
5270  * \retval MYKONOS_ERR_PU_OBSRXPATH_INV_PARAM Invalid obsRxCh function parameter
5271  * \retval MYKONOS_ERR_PU_OBSRXPATH_ARMERROR ARM returned an error while trying to set the ObsRx Path source
5272  */
MYKONOS_setObsRxPathSource(mykonosDevice_t * device,mykonosObsRxChannels_t obsRxCh)5273 mykonosErr_t MYKONOS_setObsRxPathSource(mykonosDevice_t *device, mykonosObsRxChannels_t obsRxCh)
5274 {
5275     uint8_t cmdStatByte = 0;
5276     uint32_t timeoutMs = 0;
5277     uint8_t payload[2] = {0, 0};
5278     mykonosErr_t retVal = MYKONOS_ERR_OK;
5279 
5280 #if (MYKONOS_VERBOSE == 1)
5281     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setObsRxPathSource()\n");
5282 #endif
5283 
5284     if (((obsRxCh > OBS_RX2_SNIFFERLO) && (obsRxCh != OBS_SNIFFER_A) && (obsRxCh != OBS_SNIFFER_B) && (obsRxCh != OBS_SNIFFER_C)))
5285     {
5286         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_PU_OBSRXPATH_INV_PARAM,
5287                 getMykonosErrorMessage(MYKONOS_ERR_PU_OBSRXPATH_INV_PARAM));
5288         return MYKONOS_ERR_PU_OBSRXPATH_INV_PARAM;
5289     }
5290 
5291     payload[0] = MYKONOS_ARM_OBJECTID_ORX_MODE;
5292     payload[1] = (uint8_t)(obsRxCh);
5293 
5294     retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_SET_OPCODE, &payload[0], sizeof(payload));
5295     if (retVal != MYKONOS_ERR_OK)
5296     {
5297         return retVal;
5298     }
5299 
5300     timeoutMs = 1000; /* wait max of 1sec for command to complete */
5301     retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_SET_OPCODE, timeoutMs, &cmdStatByte);
5302     if (retVal != MYKONOS_ERR_OK)
5303     {
5304         if (cmdStatByte > 0)
5305         {
5306             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_PU_OBSRXPATH_ARMERROR,
5307                     getMykonosErrorMessage(MYKONOS_ERR_PU_OBSRXPATH_ARMERROR));
5308             return MYKONOS_ERR_PU_OBSRXPATH_ARMERROR;
5309         }
5310 
5311         return retVal;
5312     }
5313 
5314     /* Verify ARM command did not return an error */
5315     if (cmdStatByte > 0)
5316     {
5317         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_PU_OBSRXPATH_ARMERROR,
5318                 getMykonosErrorMessage(MYKONOS_ERR_PU_OBSRXPATH_ARMERROR));
5319         return MYKONOS_ERR_PU_OBSRXPATH_ARMERROR;
5320     }
5321 
5322     return MYKONOS_ERR_OK;
5323 }
5324 
5325 /**
5326  * \brief Reads back the currently enabled Observation Rx channel in the
5327  *        radioOn state
5328  *
5329  * In pin mode, the pin could change asynchronous to reading back the
5330  * current enable ObsRx path.  Calling this function while in radioOff will
5331  * return OBS_RXOFF since all radio channels are powered down.
5332  *
5333  * <B>Dependencies</B>
5334  * - device->spiSettings->chipSelectIndex
5335  *
5336  * \param device is structure pointer to the Mykonos data structure containing settings
5337  * \param obsRxCh Parameter to return enum of the current observation receive
5338  *                path powered up
5339  *
5340  * \retval MYKONOS_ERR_OK Function completed successfully
5341  * \retval MYKONOS_ERR_PU_GETOBSRXPATH_ARMERROR ARM returned an error while trying to get the ObsRx Path source
5342  */
MYKONOS_getObsRxPathSource(mykonosDevice_t * device,mykonosObsRxChannels_t * obsRxCh)5343 mykonosErr_t MYKONOS_getObsRxPathSource(mykonosDevice_t *device, mykonosObsRxChannels_t *obsRxCh)
5344 {
5345     uint8_t extData[1] = {MYKONOS_ARM_OBJECTID_ORX_MODE};
5346     uint8_t cmdStatusByte = 0;
5347     uint8_t armData[1] = {0};
5348     uint32_t timeoutMs = 0;
5349     mykonosErr_t retVal = MYKONOS_ERR_OK;
5350 
5351 #if (MYKONOS_VERBOSE == 1)
5352     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getObsRxPathSource()\n");
5353 #endif
5354 
5355     retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &extData[0], sizeof(extData));
5356     if (retVal != MYKONOS_ERR_OK)
5357     {
5358         return retVal;
5359     }
5360 
5361     timeoutMs = 1000;
5362     retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte);
5363     if (retVal != MYKONOS_ERR_OK)
5364     {
5365         if (cmdStatusByte > 0)
5366         {
5367             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_PU_GETOBSRXPATH_ARMERROR,
5368                     getMykonosErrorMessage(MYKONOS_ERR_PU_GETOBSRXPATH_ARMERROR));
5369             return MYKONOS_ERR_PU_GETOBSRXPATH_ARMERROR;
5370         }
5371 
5372         return retVal;
5373     }
5374 
5375     /* read 64-bit frequency from ARM memory */
5376     retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &armData[0], 1, 1);
5377     if (retVal != MYKONOS_ERR_OK)
5378     {
5379         return retVal;
5380     }
5381 
5382     if (cmdStatusByte > 0)
5383     {
5384         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_PU_GETOBSRXPATH_ARMERROR,
5385                 getMykonosErrorMessage(MYKONOS_ERR_PU_GETOBSRXPATH_ARMERROR));
5386         return MYKONOS_ERR_PU_GETOBSRXPATH_ARMERROR;
5387     }
5388 
5389     *obsRxCh = (mykonosObsRxChannels_t)(armData[0]);
5390 
5391     return MYKONOS_ERR_OK;
5392 }
5393 
5394 /**
5395  * \brief Sets the Rx gain of the ObsRx channel
5396  *
5397  * The ObsRx channel can have different RF inputs (ORx1/ORx2/SnRx A,B,C)
5398  * This function sets the ObsRx gain index independently for ORx1/ORx2, or SnRx.
5399  * SnRx A, B, and C share the same gain index.  Please note that ORx1/ORx2 share a gain
5400  * table, as does SnRx A, B, and C. The maximum index is 255
5401  * and the minimum index is application specific.
5402  *
5403  * <B>Dependencies</B>
5404  * - device->spiSettings
5405  * - device->obsRx->orxGainCtrl->maxGainIndex
5406  * - device->obsRx->orxGainCtrl->minGainIndex
5407  * - device->obsRx->orxGainCtrl->orx1GainIndex
5408  * - device->obsRx->orxGainCtrl->orx2GainIndex
5409  * - device->obsRx->snifferGainCtrl->maxGainIndex
5410  * - device->obsRx->snifferGainCtrl->minGainIndex
5411  * - device->obsRx->snifferGainCtrl->gainIndex
5412  *
5413  * \param device Pointer to the Mykonos device data structure
5414  * \param obsRxCh is an enum type mykonosObsRxChannels_t to identify the desired RF input for gain change
5415  * \param gainIndex Desired manual gain table index to set
5416  *
5417  * \retval MYKONOS_ERR_OK Function completed successfully
5418  * \retval MYKONOS_ERR_SETORXGAIN_INV_ORX1GAIN Invalid gain requested for ORx1: outside gain table min/max index
5419  * \retval MYKONOS_ERR_SETORXGAIN_INV_ORX2GAIN Invalid gain requested for ORx2: outside gain table min/max index
5420  * \retval MYKONOS_ERR_SETORXGAIN_INV_SNRXGAIN Invalid gain requested for Sniffer: outside gain table min/max index
5421  * \retval MYKONOS_ERR_SETORXGAIN_INV_CHANNEL Function parameter obsRxCh has an invalid enum value
5422  */
MYKONOS_setObsRxManualGain(mykonosDevice_t * device,mykonosObsRxChannels_t obsRxCh,uint8_t gainIndex)5423 mykonosErr_t MYKONOS_setObsRxManualGain(mykonosDevice_t *device, mykonosObsRxChannels_t obsRxCh, uint8_t gainIndex)
5424 {
5425 
5426 #if (MYKONOS_VERBOSE == 1)
5427     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setObsRxManualGain()\n");
5428 #endif
5429 
5430     if ((obsRxCh == OBS_RX1_TXLO) || (obsRxCh == OBS_RX1_SNIFFERLO))
5431     {
5432         if (gainIndex <= device->obsRx->orxGainCtrl->maxGainIndex && gainIndex >= device->obsRx->orxGainCtrl->minGainIndex)
5433         {
5434             CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX1_MANUAL_GAIN_INDEX, (gainIndex - MIN_ORX_GAIN_TABLE_INDEX));
5435             device->obsRx->orxGainCtrl->orx1GainIndex = gainIndex;
5436         }
5437         else
5438         {
5439             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETORXGAIN_INV_ORX1GAIN,
5440                     getMykonosErrorMessage(MYKONOS_ERR_SETORXGAIN_INV_ORX1GAIN));
5441             return MYKONOS_ERR_SETORXGAIN_INV_ORX1GAIN;
5442         }
5443     }
5444     else if ((obsRxCh == OBS_RX2_TXLO) || (obsRxCh == OBS_RX2_SNIFFERLO))
5445     {
5446         if (gainIndex <= device->obsRx->orxGainCtrl->maxGainIndex && gainIndex >= device->obsRx->orxGainCtrl->minGainIndex)
5447         {
5448             CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX2_MANUAL_GAIN_INDEX, (gainIndex - MIN_ORX_GAIN_TABLE_INDEX));
5449             device->obsRx->orxGainCtrl->orx2GainIndex = gainIndex;
5450         }
5451         else
5452         {
5453             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETORXGAIN_INV_ORX2GAIN,
5454                     getMykonosErrorMessage(MYKONOS_ERR_SETORXGAIN_INV_ORX2GAIN));
5455             return MYKONOS_ERR_SETORXGAIN_INV_ORX2GAIN;
5456         }
5457 
5458     }
5459     else if (obsRxCh == OBS_SNIFFER_A || obsRxCh == OBS_SNIFFER_B || obsRxCh == OBS_SNIFFER_C || obsRxCh == OBS_SNIFFER)
5460     {
5461         if (gainIndex <= device->obsRx->snifferGainCtrl->maxGainIndex && gainIndex >= device->obsRx->snifferGainCtrl->minGainIndex)
5462         {
5463             CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SNRX_MANUAL_GAIN_INDEX, (gainIndex - MIN_SNRX_GAIN_TABLE_INDEX));
5464             device->obsRx->snifferGainCtrl->gainIndex = gainIndex;
5465         }
5466         else
5467         {
5468             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETORXGAIN_INV_SNRXGAIN,
5469                     getMykonosErrorMessage(MYKONOS_ERR_SETORXGAIN_INV_SNRXGAIN));
5470             return MYKONOS_ERR_SETORXGAIN_INV_SNRXGAIN;
5471         }
5472     }
5473     else
5474     {
5475         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETORXGAIN_INV_CHANNEL,
5476                 getMykonosErrorMessage(MYKONOS_ERR_SETORXGAIN_INV_CHANNEL));
5477         return MYKONOS_ERR_SETORXGAIN_INV_CHANNEL;
5478     }
5479 
5480     return MYKONOS_ERR_OK;
5481 }
5482 
5483 /**
5484  * \brief Gets the gain index of the currently enabled ObsRx channel
5485  *
5486  * The ObsRx data path can have multiple RF sources.  This function will
5487  * read back the gain index of the currently enabled RF source. If the ObsRx
5488  * data path is disabled, an error is returned.  If the functions uint8_t *gainIndex
5489  * parameter is a valid pointer, the gain index is returned at the pointers
5490  * address.  Else, if the uint8_t *gainIndex pointer is NULL, the gainIndex read back
5491  * is stored in the device data structure.
5492  *
5493  * NOTE: if the observation source is chosen by ORX_MODE pins, it is possible that
5494  * the readback value will be incorrect if the obsRx channel changes while this function
5495  * reads the gain.
5496  *
5497  * <B>Dependencies</B>
5498  * - device->spiSettings
5499  * - device->profilesValid
5500  * - device->obsRx->orxGainCtrl->orx1GainIndex
5501  * - device->obsRx->orxGainCtrl->orx2GainIndex
5502  * - device->obsRx->snifferGainCtrl->gainIndex
5503  *
5504  * \param device Pointer to the Mykonos device data structure
5505  * \param gainIndex Return value of the current gain index for the currently enabled ObsRx channel.
5506  *
5507  * \retval MYKONOS_ERR_OK Function completed successfully
5508  * \retval MYKONOS_ERR_GETORX1GAIN_INV_POINTER The ObsRx profile is not valid in the device data structure
5509  * \retval MYKONOS_ERR_GETORX2GAIN_INV_POINTER The ObsRx profile is not valid in the device data structure
5510  * \retval MYKONOS_ERR_GETSNIFFGAIN_INV_POINTER The sniffer profile is not valid in the device data structure
5511  * \retval MYKONOS_ERR_GETOBSRXGAIN_CH_DISABLED The observation receiver is currently disabled, can not read back gain index.
5512  */
MYKONOS_getObsRxGain(mykonosDevice_t * device,uint8_t * gainIndex)5513 mykonosErr_t MYKONOS_getObsRxGain(mykonosDevice_t *device, uint8_t *gainIndex)
5514 {
5515     /* Potential issue, if ARM is using loopback path when this function is called, it will likely readback loopback gain */
5516     uint8_t readObsRxPathEnabled = 0;
5517     uint8_t readObsRxGain = 0;
5518 
5519     const uint8_t ORX1_EN = 0x01;
5520     const uint8_t ORX2_EN = 0x02;
5521     const uint8_t SNRX_EN = 0x04;
5522 
5523 #if (MYKONOS_VERBOSE == 1)
5524     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getObsRxGain()\n");
5525 #endif
5526 
5527     CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_DPD_SNIFFER_CONFIGURATION_CONTROL_1, &readObsRxPathEnabled);
5528 
5529     /* If obsRx channel enabled, then read gain index */
5530     if (readObsRxPathEnabled > 0)
5531     {
5532         CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_GAIN_CTL_ORX_SNRX_GAIN, &readObsRxGain);
5533 
5534         switch (readObsRxPathEnabled)
5535         {
5536             case 0x01:
5537                 readObsRxGain += MIN_ORX_GAIN_TABLE_INDEX;
5538                 break;
5539             case 0x02:
5540                 readObsRxGain += MIN_ORX_GAIN_TABLE_INDEX;
5541                 break;
5542             case 0x04:
5543                 readObsRxGain += MIN_SNRX_GAIN_TABLE_INDEX;
5544                 break;
5545             default:
5546                 break;
5547         }
5548 
5549         if (gainIndex != NULL)
5550         {
5551             *gainIndex = readObsRxGain;
5552         }
5553 
5554         /* Store the gain index in the device's gain control data structure. */
5555 
5556         if (readObsRxPathEnabled == ORX1_EN)
5557         {
5558             /* verify valid data structure pointers */
5559             if (device->profilesValid & ORX_PROFILE_VALID)
5560             {
5561                 device->obsRx->orxGainCtrl->orx1GainIndex = readObsRxGain;
5562             }
5563             else
5564             {
5565                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETORX1GAIN_INV_POINTER,
5566                         getMykonosErrorMessage(MYKONOS_ERR_GETORX1GAIN_INV_POINTER));
5567                 return MYKONOS_ERR_GETORX1GAIN_INV_POINTER;
5568             }
5569 
5570         }
5571         else if (readObsRxPathEnabled == ORX2_EN)
5572         {
5573             /* verify valid pointers */
5574             if (device->profilesValid & ORX_PROFILE_VALID)
5575             {
5576                 device->obsRx->orxGainCtrl->orx2GainIndex = readObsRxGain;
5577             }
5578             else
5579             {
5580                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETORX2GAIN_INV_POINTER,
5581                         getMykonosErrorMessage(MYKONOS_ERR_GETORX2GAIN_INV_POINTER));
5582                 return MYKONOS_ERR_GETORX2GAIN_INV_POINTER;
5583             }
5584 
5585         }
5586         else if (readObsRxPathEnabled == SNRX_EN)
5587         {
5588             /* verify valid pointers */
5589             if (device->profilesValid & SNIFF_PROFILE_VALID)
5590             {
5591                 device->obsRx->snifferGainCtrl->gainIndex = readObsRxGain;
5592             }
5593             else
5594             {
5595                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETSNIFFGAIN_INV_POINTER,
5596                         getMykonosErrorMessage(MYKONOS_ERR_GETSNIFFGAIN_INV_POINTER));
5597                 return MYKONOS_ERR_GETSNIFFGAIN_INV_POINTER;
5598             }
5599         }
5600         else
5601         {
5602             /* ignore gain index for Tx loopback input into obsRx channel */
5603         }
5604     }
5605     else
5606     {
5607         CMB_writeToLog(ADIHAL_LOG_WARNING, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETOBSRXGAIN_CH_DISABLED,
5608                 getMykonosErrorMessage(MYKONOS_ERR_GETOBSRXGAIN_CH_DISABLED));
5609         return MYKONOS_ERR_GETOBSRXGAIN_CH_DISABLED;
5610     }
5611 
5612     return MYKONOS_ERR_OK;
5613 }
5614 
5615 /**
5616  * \brief Sets up the device ObsRx Automatic Gain Control (AGC) registers.
5617  *
5618  * Three data structures (of types mykonosAgcCfg_t, mykonosPeakDetAgcCfg_t, mykonosPowerMeasAgcCfg_t)
5619  * must be instantiated prior to calling this function. Valid ranges for data structure members
5620  * must also be provided.
5621  *
5622  *
5623  * <B>Dependencies:</B>
5624  * - device->spiSettings
5625  * - device->spiSettings->chipSelectIndex
5626  * - device->obsRx->orxAgcCtrl->agcRx1MaxGainIndex
5627  * - device->obsRx->orxAgcCtrl->agcRx1MinGainIndex
5628  * - device->obsRx->orxAgcCtrl->agcRx2MaxGainIndex
5629  * - device->obsRx->orxAgcCtrl->agcRx2MinGainIndex
5630  * - device->obsRx->orxAgcCtrl->agcObsRxMaxGainIndex
5631  * - device->obsRx->orxAgcCtrl->agcObsRxMinGainIndex
5632  * - device->obsRx->orxAgcCtrl->agcObsRxSelect
5633  * - device->obsRx->orxAgcCtrl->agcPeakThresholdMode
5634  * - device->obsRx->orxAgcCtrl->agcLowThsPreventGainIncrease
5635  * - device->obsRx->orxAgcCtrl->agcGainUpdateCounter
5636  * - device->obsRx->orxAgcCtrl->agcSlowLoopSettlingDelay
5637  * - device->obsRx->orxAgcCtrl->agcPeakWaitTime
5638  * - device->obsRx->orxAgcCtrl->agcResetOnRxEnable
5639  * - device->obsRx->orxAgcCtrl->agcEnableSyncPulseForGainCounter
5640  * - device->obsRx->orxAgcCtrl->peakAgc->apdHighThresh
5641  * - device->obsRx->orxAgcCtrl->peakAgc->apdLowThresh
5642  * - device->obsRx->orxAgcCtrl->peakAgc->hb2HighThresh
5643  * - device->obsRx->orxAgcCtrl->peakAgc->hb2LowThresh
5644  * - device->obsRx->orxAgcCtrl->peakAgc->hb2VeryLowThresh
5645  * - device->obsRx->orxAgcCtrl->peakAgc->apdHighThreshExceededCnt
5646  * - device->obsRx->orxAgcCtrl->peakAgc->apdLowThreshExceededCnt
5647  * - device->obsRx->orxAgcCtrl->peakAgc->hb2HighThreshExceededCnt
5648  * - device->obsRx->orxAgcCtrl->peakAgc->hb2LowThreshExceededCnt
5649  * - device->obsRx->orxAgcCtrl->peakAgc->hb2VeryLowThreshExceededCnt
5650  * - device->obsRx->orxAgcCtrl->peakAgc->apdHighGainStepAttack
5651  * - device->obsRx->orxAgcCtrl->peakAgc->apdLowGainStepRecovery
5652  * - device->obsRx->orxAgcCtrl->peakAgc->hb2HighGainStepAttack
5653  * - device->obsRx->orxAgcCtrl->peakAgc->hb2LowGainStepRecovery
5654  * - device->obsRx->orxAgcCtrl->peakAgc->hb2VeryLowGainStepRecovery
5655  * - device->obsRx->orxAgcCtrl->peakAgc->apdFastAttack
5656  * - device->obsRx->orxAgcCtrl->peakAgc->hb2FastAttack
5657  * - device->obsRx->orxAgcCtrl->peakAgc->hb2OverloadDetectEnable
5658  * - device->obsRx->orxAgcCtrl->peakAgc->hb2OverloadDurationCnt
5659  * - device->obsRx->orxAgcCtrl->peakAgc->hb2OverloadThreshCnt
5660  * - device->obsRx->orxAgcCtrl->powerAgc->pmdUpperHighThresh
5661  * - device->obsRx->orxAgcCtrl->powerAgc->pmdUpperLowThresh
5662  * - device->obsRx->orxAgcCtrl->powerAgc->pmdLowerHighThresh
5663  * - device->obsRx->orxAgcCtrl->powerAgc->pmdLowerLowThresh
5664  * - device->obsRx->orxAgcCtrl->powerAgc->pmdUpperHighGainStepAttack
5665  * - device->obsRx->orxAgcCtrl->powerAgc->pmdUpperLowGainStepAttack
5666  * - device->obsRx->orxAgcCtrl->powerAgc->pmdLowerHighGainStepRecovery
5667  * - device->obsRx->orxAgcCtrl->powerAgc->pmdLowerLowGainStepRecovery
5668  * - device->obsRx->orxAgcCtrl->powerAgc->pmdMeasDuration
5669  * - device->obsRx->orxAgcCtrl->powerAgc->pmdMeasConfig
5670  *
5671  * \param device is structure pointer to the Mykonos data structure containing settings
5672  * The pointer to the Mykonos AGC data structure containing settings is checked for a null pointer
5673  * to ensure it has been initialized. If not an error is thrown.
5674  *
5675  * \retval Returns MYKONOS_ERR=pass, !MYKONOS_ERR=fail
5676  * \retval MYKONOS_ERR_INV_AGC_OBSRX_STRUCT_INIT
5677  * \retval MYKONOS_ERR_INV_AGC_OBSRX_PEAK_STRUCT_INIT
5678  * \retval MYKONOS_ERR_INV_AGC_OBSRX_PWR_STRUCT_INIT
5679  * \retval MYKONOS_ERR_INV_AGC_OBSRX_MAX_GAIN_INDEX
5680  * \retval MYKONOS_ERR_INV_AGC_OBSRX_MIN_GAIN_INDEX
5681  * \retval MYKONOS_ERR_INV_AGC_OBSRX_SELECT
5682  * \retval MYKONOS_ERR_INV_AGC_OBSRX_GAIN_UPDATE_TIME_PARM
5683  * \retval MYKONOS_ERR_INV_AGC_OBSRX_PEAK_WAIT_TIME_PARM
5684  * \retval MYKONOS_ERR_INV_AGC_OBSRX_SLOW_LOOP_SETTLING_DELAY
5685  * \retval MYKONOS_ERR_INV_AGC_OBSRX_PMD_MEAS_DURATION
5686  * \retval MYKONOS_ERR_INV_AGC_OBSRX_PMD_MEAS_CONFIG
5687  * \retval MYKONOS_ERR_INV_AGC_OBSRX_LOW_THS_PREV_GAIN_INC
5688  * \retval MYKONOS_ERR_INV_AGC_OBSRX_PEAK_THRESH_MODE
5689  * \retval MYKONOS_ERR_INV_AGC_OBSRX_RESET_ON_RX_ENABLE
5690  * \retval MYKONOS_ERR_INV_AGC_OBSRX_ENABLE_SYNC_PULSE_GAIN_COUNTER
5691  * \retval MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_HIGH_THRESH
5692  * \retval MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_LOW_THRESH
5693  * \retval MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_LOW_THRESH
5694  * \retval MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_HIGH_THRESH
5695  * \retval MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_HIGH_GAIN_STEP
5696  * \retval MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_LOW_GAIN_STEP
5697  * \retval MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_LOW_GAIN_STEP
5698  * \retval MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_HIGH_GAIN_STEP
5699  * \retval MYKONOS_ERR_INV_AGC_OBSRX_PKDET_FAST_ATTACK_VALUE
5700  * \retval MYKONOS_ERR_INV_AGC_OBSRX_APD_HIGH_THRESH_PARM
5701  * \retval MYKONOS_ERR_INV_AGC_OBSRX_APD_LOW_THRESH_PARM
5702  * \retval MYKONOS_ERR_INV_AGC_OBSRX_HB2_HIGH_THRESH_PARM
5703  * \retval MYKONOS_ERR_INV_AGC_OBSRX_HB2_LOW_THRESH_PARM
5704  * \retval MYKONOS_ERR_INV_AGC_OBSRX_HB2_VERY_LOW_THRESH_PARM
5705  * \retval MYKONOS_ERR_INV_AGC_OBSRX_APD_HIGH_GAIN_STEP_PARM
5706  * \retval MYKONOS_ERR_INV_AGC_OBSRX_APD_LOW_GAIN_STEP_PARM
5707  * \retval MYKONOS_ERR_INV_AGC_OBSRX_HB2_HIGH_GAIN_STEP_PARM
5708  * \retval MYKONOS_ERR_INV_AGC_OBSRX_HB2_LOW_GAIN_STEP_PARM
5709  * \retval MYKONOS_ERR_INV_AGC_OBSRX_HB2_VERY_LOW_GAIN_STEP_PARM
5710  * \retval MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_ENABLE
5711  * \retval MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_DUR_CNT
5712  * \retval MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_THRESH_CNT
5713  */
MYKONOS_setupObsRxAgc(mykonosDevice_t * device)5714 mykonosErr_t MYKONOS_setupObsRxAgc(mykonosDevice_t *device)
5715 {
5716     /* Current configuration does not support AGC on ORx channel */
5717     uint8_t decPowerConfig = 0;
5718     uint8_t lower1ThreshGainStepRegValue = 0;
5719     uint8_t powerThresholdsRegValue = 0;
5720     uint8_t hb2OvldCfgRegValue = 0;
5721     uint8_t agcGainUpdateCtr[3] = {0};
5722 
5723 #if (MYKONOS_VERBOSE == 1)
5724     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setupObsRxAgc()\n");
5725 #endif
5726 
5727     /* Check mykonosAgcCfg_t device->obsRx->orxAgcCtrl pointer for initialization */
5728     if (device->obsRx->orxAgcCtrl == NULL)
5729     {
5730         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_STRUCT_INIT,
5731                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_STRUCT_INIT));
5732         return MYKONOS_ERR_INV_AGC_OBSRX_STRUCT_INIT;
5733     }
5734 
5735     /* Check mykonosPeakDetAgcCfg_t device->orx->orxAgcCtrl->peakAgc pointer for initialization */
5736     if (device->obsRx->orxAgcCtrl->peakAgc == NULL)
5737     {
5738         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PEAK_STRUCT_INIT,
5739                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PEAK_STRUCT_INIT));
5740         return MYKONOS_ERR_INV_AGC_OBSRX_PEAK_STRUCT_INIT;
5741     }
5742 
5743     /* Check mykonosPowerMeasAgcCfg_t device->obsRx->orxAgcCtrl->powerAgc pointer for initialization */
5744     if (device->obsRx->orxAgcCtrl->powerAgc == NULL)
5745     {
5746         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PWR_STRUCT_INIT,
5747                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PWR_STRUCT_INIT));
5748         return MYKONOS_ERR_INV_AGC_OBSRX_PWR_STRUCT_INIT;
5749     }
5750 
5751     /* Range check agcObsRxMaxGainIndex versus gain table limits and agcObsRxMinGainIndex */
5752     if ((device->obsRx->orxAgcCtrl->agcObsRxMaxGainIndex > device->obsRx->snifferGainCtrl->maxGainIndex) ||
5753         (device->obsRx->orxAgcCtrl->agcObsRxMaxGainIndex < device->obsRx->orxAgcCtrl->agcObsRxMinGainIndex))
5754     {
5755         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_MAX_GAIN_INDEX,
5756                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_MAX_GAIN_INDEX));
5757         return MYKONOS_ERR_INV_AGC_OBSRX_MAX_GAIN_INDEX;
5758     }
5759     else
5760     {
5761         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_MAX_GAIN_INDEX,
5762                 (device->obsRx->orxAgcCtrl->agcObsRxMaxGainIndex - MAX_SNRX_GAIN_TABLE_NUMINDEXES));
5763     }
5764 
5765     /* Range check agcObsRxMinGainIndex versus gain table limits and agcObsRxMaxGainIndex */
5766     if ((device->obsRx->orxAgcCtrl->agcObsRxMinGainIndex < device->obsRx->snifferGainCtrl->minGainIndex) ||
5767         (device->obsRx->orxAgcCtrl->agcObsRxMaxGainIndex < device->obsRx->orxAgcCtrl->agcObsRxMinGainIndex))
5768     {
5769         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_MIN_GAIN_INDEX,
5770                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_MIN_GAIN_INDEX));
5771         return MYKONOS_ERR_INV_AGC_OBSRX_MIN_GAIN_INDEX;
5772     }
5773     else
5774     {
5775         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_MIN_GAIN_INDEX,
5776                 (device->obsRx->orxAgcCtrl->agcObsRxMinGainIndex - MAX_SNRX_GAIN_TABLE_NUMINDEXES));
5777     }
5778 
5779     /* Range check agcObsRxSelect. Sniffer only support. Sniffer is selected if value is 0 or 1. 2 or 3 select ORx1/ORx2 respectively */
5780     if (device->obsRx->orxAgcCtrl->agcObsRxSelect > 1)
5781     {
5782         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_SELECT,
5783                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_SELECT));
5784         return MYKONOS_ERR_INV_AGC_OBSRX_SELECT;
5785     }
5786     else
5787     {
5788         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_ACTIVE, device->obsRx->orxAgcCtrl->agcObsRxSelect);
5789     }
5790 
5791     /* Range check for agcGainUpdateCounter (22-bit) */
5792     if ((device->obsRx->orxAgcCtrl->agcGainUpdateCounter > 0x3FFFFF) ||
5793         (device->obsRx->orxAgcCtrl->agcGainUpdateCounter < 1))
5794     {
5795         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_GAIN_UPDATE_TIME_PARM,
5796                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_GAIN_UPDATE_TIME_PARM));
5797         return MYKONOS_ERR_INV_AGC_OBSRX_GAIN_UPDATE_TIME_PARM;
5798     }
5799     else
5800     {
5801         /* Split agcGainUpdateCounter into three values */
5802         agcGainUpdateCtr[0] = (uint8_t)(device->obsRx->orxAgcCtrl->agcGainUpdateCounter);
5803         agcGainUpdateCtr[1] = (uint8_t)(device->obsRx->orxAgcCtrl->agcGainUpdateCounter >> 8);
5804         agcGainUpdateCtr[2] = (uint8_t)(device->obsRx->orxAgcCtrl->agcGainUpdateCounter >> 16);
5805 
5806         /* Write two bytes directly due. Third word has its upper two bits masked off.  */
5807         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_GAIN_UPDATE_CTR_1, agcGainUpdateCtr[0]);
5808         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_GAIN_UPDATE_CTR_2, agcGainUpdateCtr[1]);
5809         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_GAIN_UPDATE_CTR_3, agcGainUpdateCtr[2], 0x3F, 0);
5810     }
5811 
5812     /* Range check on agcPeakWaitTime (5-bit) */
5813     if ((device->obsRx->orxAgcCtrl->agcPeakWaitTime > 0x1F) ||
5814         (device->obsRx->orxAgcCtrl->agcPeakWaitTime < 0x02))
5815     {
5816         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PEAK_WAIT_TIME_PARM,
5817                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PEAK_WAIT_TIME_PARM));
5818         return MYKONOS_ERR_INV_AGC_OBSRX_PEAK_WAIT_TIME_PARM;
5819     }
5820     else
5821     {
5822         /* Write agcPeakWaitTime */
5823         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_CFG_2, device->obsRx->orxAgcCtrl->agcPeakWaitTime, 0x1F, 0);
5824     }
5825 
5826     /* Range check for agcSlowLoopSettlingDelay (7-bit) */
5827     if (device->obsRx->orxAgcCtrl->agcSlowLoopSettlingDelay > 0x7F)
5828     {
5829         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_SLOW_LOOP_SETTLING_DELAY,
5830                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_SLOW_LOOP_SETTLING_DELAY));
5831         return MYKONOS_ERR_INV_AGC_OBSRX_SLOW_LOOP_SETTLING_DELAY;
5832     }
5833     else
5834     {
5835         /* Write agcSlowLoopSettlingDelay */
5836         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_LOOP_CFG, device->obsRx->orxAgcCtrl->agcSlowLoopSettlingDelay, 0x7F, 0);
5837     }
5838 
5839     /* Range check for pmdMeasDuration */
5840     if ((uint32_t)(1 << (3 + device->obsRx->orxAgcCtrl->powerAgc->pmdMeasDuration)) >= (device->obsRx->orxAgcCtrl->agcGainUpdateCounter))
5841     {
5842         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PMD_MEAS_DURATION,
5843                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PMD_MEAS_DURATION));
5844         return MYKONOS_ERR_INV_AGC_OBSRX_PMD_MEAS_DURATION;
5845     }
5846     else
5847     {
5848         /* Write pmdMeasDuration */
5849         CMB_SPIWriteField(device->spiSettings, MYKONOS_SNIFFER_DEC_POWER_CONFIG_2, device->obsRx->orxAgcCtrl->powerAgc->pmdMeasDuration, 0x0F, 0);
5850     }
5851 
5852     /* Range check for pmdMeasConfig */
5853     if (device->obsRx->orxAgcCtrl->powerAgc->pmdMeasConfig > 0x3)
5854     {
5855         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PMD_MEAS_CONFIG,
5856                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PMD_MEAS_CONFIG));
5857         return MYKONOS_ERR_INV_AGC_OBSRX_PMD_MEAS_CONFIG;
5858     }
5859     else
5860     {
5861         if (device->obsRx->orxAgcCtrl->powerAgc->pmdMeasConfig == 0)
5862         {
5863             decPowerConfig = 0x0; /* Dec Pwr measurement disable */
5864         }
5865         else if (device->obsRx->orxAgcCtrl->powerAgc->pmdMeasConfig == 1)
5866         {
5867             decPowerConfig = 0x3; /* Dec Pwr measurement enable,  HB2 for decPwr measurement */
5868         }
5869         else if (device->obsRx->orxAgcCtrl->powerAgc->pmdMeasConfig == 2)
5870         {
5871             decPowerConfig = 0x5; /* Dec Pwr measurement enable, RFIR for decPwr measurement */
5872         }
5873         else if (device->obsRx->orxAgcCtrl->powerAgc->pmdMeasConfig == 3)
5874         {
5875             decPowerConfig = 0x11; /* Dec Pwr measurement enable, BBDC2 for decPwr measurement */
5876         }
5877         /* Write pmdMeasConfig */
5878         CMB_SPIWriteByte(device->spiSettings, MYKONOS_SNIFFER_DEC_POWER_CONFIG_1, decPowerConfig);
5879     }
5880 
5881     /* Range check agcLowThsPreventGainIncrease (1-bit) */
5882     if (device->obsRx->orxAgcCtrl->agcLowThsPreventGainIncrease > 1)
5883     {
5884         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_LOW_THS_PREV_GAIN_INC,
5885                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_LOW_THS_PREV_GAIN_INC));
5886         return MYKONOS_ERR_INV_AGC_OBSRX_LOW_THS_PREV_GAIN_INC;
5887     }
5888     else
5889     {
5890         /* Write agcLowThsPreventGainIncrease */
5891         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_LOCK_LEV_THRSH, device->obsRx->orxAgcCtrl->agcLowThsPreventGainIncrease, 0x80, 7);
5892     }
5893 
5894     /* Range check agcPeakThresholdMode (1-bit),  */
5895     if (device->obsRx->orxAgcCtrl->agcPeakThresholdMode > 1)
5896     {
5897         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PEAK_THRESH_MODE,
5898                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PEAK_THRESH_MODE));
5899         return MYKONOS_ERR_INV_AGC_OBSRX_PEAK_THRESH_MODE;
5900     }
5901     else
5902     {
5903         /* Save to lower1ThreshGainStepRegValue register variable */
5904         lower1ThreshGainStepRegValue |= (uint8_t)(device->obsRx->orxAgcCtrl->agcPeakThresholdMode << 5);
5905     }
5906 
5907     /* Range check agcResetOnRxEnable (1-bit) */
5908     if (device->obsRx->orxAgcCtrl->agcResetOnRxEnable > 1)
5909     {
5910         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_RESET_ON_RX_ENABLE,
5911                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_RESET_ON_RX_ENABLE));
5912         return MYKONOS_ERR_INV_AGC_OBSRX_RESET_ON_RX_ENABLE;
5913     }
5914     else
5915     {
5916         /* Write agcResetOnRxEnable */
5917         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_GAIN_UPDATE_CTR_3, (uint8_t)(device->obsRx->orxAgcCtrl->agcResetOnRxEnable << 7), 0x80, 0);
5918     }
5919 
5920     /* Range check agcEnableSyncPulseForGainCounter (1-bit) */
5921     if (device->obsRx->orxAgcCtrl->agcEnableSyncPulseForGainCounter > 1)
5922     {
5923         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_ENABLE_SYNC_PULSE_GAIN_COUNTER,
5924                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_ENABLE_SYNC_PULSE_GAIN_COUNTER));
5925         return MYKONOS_ERR_INV_AGC_OBSRX_ENABLE_SYNC_PULSE_GAIN_COUNTER;
5926     }
5927     else
5928     {
5929         /* Write agcEnableSyncPulseForGainCounter */
5930         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_LOOP_CFG, (uint8_t)(device->obsRx->orxAgcCtrl->agcEnableSyncPulseForGainCounter << 7), 0x80, 0);
5931     }
5932 
5933     /* WRITE REGISTERS FOR THE AGC POWER MEASUREMENT DETECTOR (PMD) STRUCTURE */
5934 
5935     /* Range check pmdLowerHighThresh (7-bit) vs 0x7F and pmdUpperLowThresh */
5936     if ((device->obsRx->orxAgcCtrl->powerAgc->pmdLowerHighThresh <= device->obsRx->orxAgcCtrl->powerAgc->pmdUpperLowThresh) ||
5937          device->obsRx->orxAgcCtrl->powerAgc->pmdLowerHighThresh > 0x7F)
5938     {
5939         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_HIGH_THRESH,
5940                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_HIGH_THRESH));
5941         return MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_HIGH_THRESH;
5942     }
5943     else
5944     {
5945         /* Write pmdLowerHighThresh */
5946         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_LOCK_LEV_THRSH, device->obsRx->orxAgcCtrl->powerAgc->pmdLowerHighThresh, 0x7F, 0);
5947     }
5948 
5949     /* Range check pmdUpperLowThresh (7-bit): Comparison to pmdLowerHigh done earlier */
5950     if (device->obsRx->orxAgcCtrl->powerAgc->pmdUpperLowThresh > 0x7F)
5951     {
5952         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_LOW_THRESH,
5953                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_LOW_THRESH));
5954         return MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_LOW_THRESH;
5955     }
5956     else
5957     {
5958         /* Write pmdUpperLowThresh */
5959         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_LOCK_LEVEL, device->obsRx->orxAgcCtrl->powerAgc->pmdUpperLowThresh);
5960     }
5961 
5962     /* Range check pmdLowerLowThresh (4-bit)  */
5963     if (device->obsRx->orxAgcCtrl->powerAgc->pmdLowerLowThresh > 0xF)
5964     {
5965         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_LOW_THRESH,
5966                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_LOW_THRESH));
5967         return MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_LOW_THRESH;
5968     }
5969     else
5970     {
5971         /* Write pmdUpperLowThresh to temp variable */
5972         powerThresholdsRegValue |= device->obsRx->orxAgcCtrl->powerAgc->pmdLowerLowThresh;
5973     }
5974 
5975     /* Range check pmdUpperHighThresh (4-bit)  */
5976     if (device->obsRx->orxAgcCtrl->powerAgc->pmdUpperHighThresh > 0xF)
5977     {
5978         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_HIGH_THRESH,
5979                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_HIGH_THRESH));
5980         return MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_HIGH_THRESH;
5981     }
5982     else
5983     {
5984         /* Write pmdUpperHighThresh to temp var, then to register */
5985         powerThresholdsRegValue |= (uint8_t)(device->obsRx->orxAgcCtrl->powerAgc->pmdUpperHighThresh << 4);
5986         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_POWER_THRSH, powerThresholdsRegValue);
5987     }
5988 
5989     /* Range check pmdUpperHighGainStepAttack (5-bit)  */
5990     if (device->obsRx->orxAgcCtrl->powerAgc->pmdUpperHighGainStepAttack > 0x1F)
5991     {
5992         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_HIGH_GAIN_STEP,
5993                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_HIGH_GAIN_STEP));
5994         return MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_HIGH_GAIN_STEP;
5995     }
5996     else
5997     {
5998         /* Write pmdUpperHighGainStepAttack */
5999         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_UPPER1_THRSH_GAIN_STEP, device->obsRx->orxAgcCtrl->powerAgc->pmdUpperHighGainStepAttack, 0x1F, 0);
6000     }
6001 
6002     /* Range check pmdLowerLowGainStepRecovery (5-bit)  */
6003     if (device->obsRx->orxAgcCtrl->powerAgc->pmdLowerLowGainStepRecovery > 0x1F)
6004     {
6005         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_LOW_GAIN_STEP,
6006                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_LOW_GAIN_STEP));
6007         return MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_LOW_GAIN_STEP;
6008     }
6009     else
6010     {
6011         /* Write pmdLowerLowGainStepRecovery to temp var, then to register */
6012         lower1ThreshGainStepRegValue |=  (uint8_t)(device->obsRx->orxAgcCtrl->powerAgc->pmdLowerLowGainStepRecovery);
6013     }
6014 
6015     /* Range check pmdUpperLowGainStepRecovery (5-bit)  */
6016     if (device->obsRx->orxAgcCtrl->powerAgc->pmdUpperLowGainStepAttack > 0x1F)
6017     {
6018         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_LOW_GAIN_STEP,
6019                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_LOW_GAIN_STEP));
6020         return MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_LOW_GAIN_STEP;
6021     }
6022     else
6023     {
6024         /* Write pmdUpperLowGainStepRecovery to register */
6025         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_UPPER0_THRSH_GAIN_STEP, device->obsRx->orxAgcCtrl->powerAgc->pmdUpperLowGainStepAttack);
6026     }
6027 
6028     /* Range check pmdLowerHighGainStepRecovery (5-bit)  */
6029     if (device->obsRx->orxAgcCtrl->powerAgc->pmdLowerHighGainStepRecovery > 0x1F)
6030     {
6031         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_HIGH_GAIN_STEP,
6032                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_HIGH_GAIN_STEP));
6033         return MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_HIGH_GAIN_STEP;
6034     }
6035     else
6036     {
6037         /* Write pmdLowerLowGainStepRecovery to temp var, then to register */
6038         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_LOWER0_THRSH_GAIN_STEP, device->obsRx->orxAgcCtrl->powerAgc->pmdLowerHighGainStepRecovery);
6039     }
6040 
6041     /* WRITE REGISTERS FOR THE AGC PEAK DETECTOR (APD/HB2) STRUCTURE */
6042 
6043     /* Range check apdFastAttack and hb2FastAttack (1-bit)  */
6044     if ((device->obsRx->orxAgcCtrl->peakAgc->apdFastAttack > 0x1) ||
6045         (device->obsRx->orxAgcCtrl->peakAgc->hb2FastAttack > 0x1))
6046     {
6047         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_PKDET_FAST_ATTACK_VALUE,
6048                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_PKDET_FAST_ATTACK_VALUE));
6049         return MYKONOS_ERR_INV_AGC_OBSRX_PKDET_FAST_ATTACK_VALUE;
6050     }
6051     else
6052     {
6053         /* Write pmdLowerLowGainStepRecovery to temp var, then to register */
6054         lower1ThreshGainStepRegValue |=  (uint8_t)(device->obsRx->orxAgcCtrl->peakAgc->apdFastAttack << 7);
6055         lower1ThreshGainStepRegValue |=  (uint8_t)(device->obsRx->orxAgcCtrl->peakAgc->hb2FastAttack << 6);
6056         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_LOWER1_THRSH_GAIN_STEP, lower1ThreshGainStepRegValue);
6057     }
6058 
6059     /* Range check apdHighThresh */
6060     if ((device->obsRx->orxAgcCtrl->peakAgc->apdHighThresh > 0x3F) ||
6061         (device->obsRx->orxAgcCtrl->peakAgc->apdHighThresh <= device->obsRx->orxAgcCtrl->peakAgc->apdLowThresh))
6062     {
6063         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_APD_HIGH_THRESH_PARM,
6064                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_APD_HIGH_THRESH_PARM));
6065         return MYKONOS_ERR_INV_AGC_OBSRX_APD_HIGH_THRESH_PARM;
6066     }
6067     else
6068     {
6069         /* Write apdHighThresh */
6070         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_ULB_THRSH, device->obsRx->orxAgcCtrl->peakAgc->apdHighThresh, 0X3F, 0);
6071     }
6072 
6073     /* Range check apdLowThresh */
6074     if ((device->obsRx->orxAgcCtrl->peakAgc->apdLowThresh > 0x3F) ||
6075         (device->obsRx->orxAgcCtrl->peakAgc->apdHighThresh < device->obsRx->orxAgcCtrl->peakAgc->apdLowThresh))
6076     {
6077         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_APD_LOW_THRESH_PARM,
6078                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_APD_LOW_THRESH_PARM));
6079         return MYKONOS_ERR_INV_AGC_OBSRX_APD_LOW_THRESH_PARM;
6080     }
6081     else
6082     {
6083         /* write apdLowThresh */
6084         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_LLB_THRSH, device->obsRx->orxAgcCtrl->peakAgc->apdLowThresh, 0x3F, 0);
6085     }
6086 
6087     /* Range check hb2HighThresh */
6088     if (device->obsRx->orxAgcCtrl->peakAgc->hb2HighThresh < device->obsRx->orxAgcCtrl->peakAgc->hb2LowThresh)
6089     {
6090         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_HB2_HIGH_THRESH_PARM,
6091                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_HB2_HIGH_THRESH_PARM));
6092         return MYKONOS_ERR_INV_AGC_OBSRX_HB2_HIGH_THRESH_PARM;
6093     }
6094     else
6095     {
6096         /* write hb2HighThresh */
6097         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ORX_SNRX_OVRLD_PD_DEC_OVRLD_UPPER_THRSH, device->obsRx->orxAgcCtrl->peakAgc->hb2HighThresh);
6098     }
6099 
6100     /* Range check hb2LowThresh */
6101     if (device->obsRx->orxAgcCtrl->peakAgc->hb2LowThresh > device->obsRx->orxAgcCtrl->peakAgc->hb2HighThresh)
6102     {
6103         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_HB2_LOW_THRESH_PARM,
6104                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_HB2_LOW_THRESH_PARM));
6105         return MYKONOS_ERR_INV_AGC_OBSRX_HB2_LOW_THRESH_PARM;
6106     }
6107     else
6108     {
6109         /* write hb2LowThresh */
6110         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ORX_SNRX_OVRLD_PD_DEC_OVRLD_LOWER_THRSH, device->obsRx->orxAgcCtrl->peakAgc->hb2LowThresh);
6111     }
6112 
6113     /* Range check hb2VeryLowThresh */
6114     if (device->obsRx->orxAgcCtrl->peakAgc->hb2VeryLowThresh > device->obsRx->orxAgcCtrl->peakAgc->hb2LowThresh)
6115     {
6116         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_HB2_VERY_LOW_THRESH_PARM,
6117                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_HB2_VERY_LOW_THRESH_PARM));
6118         return MYKONOS_ERR_INV_AGC_OBSRX_HB2_VERY_LOW_THRESH_PARM;
6119     }
6120     else
6121     {
6122         /* write hb2VeryLowThresh */
6123         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ORX_SNRX_OVRLD_PD_DEC_OVRLD_VERYLOW_THRSH, device->obsRx->orxAgcCtrl->peakAgc->hb2VeryLowThresh);
6124     }
6125 
6126     /* Write threshold counter values for apdHigh/apdLow/hb2High/hb2Low/hb2VeryLow */
6127     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_ULB_CNT_THRSH, device->obsRx->orxAgcCtrl->peakAgc->apdHighThreshExceededCnt);
6128     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_LLB_CNT_THRSH, device->obsRx->orxAgcCtrl->peakAgc->apdLowThreshExceededCnt);
6129     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_ADC_HIGH_OVRG_CNT_THRSH, device->obsRx->orxAgcCtrl->peakAgc->hb2HighThreshExceededCnt);
6130     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_ADC_LOW_OVRG_CNT_THRSH, device->obsRx->orxAgcCtrl->peakAgc->hb2LowThreshExceededCnt);
6131     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_ADC_VERYLOW_OVRG_CNT_THRSH, device->obsRx->orxAgcCtrl->peakAgc->hb2VeryLowThreshExceededCnt);
6132 
6133     /* Range check on apdHighGainStepAttack (5-bit) */
6134     if (device->obsRx->orxAgcCtrl->peakAgc->apdHighGainStepAttack > 0x1F)
6135     {
6136         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_APD_HIGH_GAIN_STEP_PARM,
6137                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_APD_HIGH_GAIN_STEP_PARM));
6138         return MYKONOS_ERR_INV_AGC_OBSRX_APD_HIGH_GAIN_STEP_PARM;
6139     }
6140     else
6141     {
6142         /* Write apdHighGainStepAttack */
6143         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_OVRG_GAIN_STEP_1, device->obsRx->orxAgcCtrl->peakAgc->apdHighGainStepAttack);
6144     }
6145 
6146     /* Range check on apdLowGainStepRecovery (5-bit) */
6147     if (device->obsRx->orxAgcCtrl->peakAgc->apdLowGainStepRecovery > 0x1F)
6148     {
6149         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_APD_LOW_GAIN_STEP_PARM,
6150                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_APD_LOW_GAIN_STEP_PARM));
6151         return MYKONOS_ERR_INV_AGC_OBSRX_APD_LOW_GAIN_STEP_PARM;
6152     }
6153     else
6154     {
6155         /* Write apdLowGainStepRecovery */
6156         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_OVRG_GAIN_STEP_4, device->obsRx->orxAgcCtrl->peakAgc->apdLowGainStepRecovery);
6157     }
6158 
6159     /* Range check on hb2HighGainStepAttack (5-bit) */
6160     if (device->obsRx->orxAgcCtrl->peakAgc->hb2HighGainStepAttack > 0x1F)
6161     {
6162         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_HB2_HIGH_GAIN_STEP_PARM,
6163                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_HB2_HIGH_GAIN_STEP_PARM));
6164         return MYKONOS_ERR_INV_AGC_OBSRX_HB2_HIGH_GAIN_STEP_PARM;
6165     }
6166     else
6167     {
6168         /* Write hb2HighGainStepAttack */
6169         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_OVRG_GAIN_STEP_2, device->obsRx->orxAgcCtrl->peakAgc->hb2HighGainStepAttack);
6170     }
6171 
6172     /* Range check on hb2LowGainStepRecovery (5-bit) */
6173     if (device->obsRx->orxAgcCtrl->peakAgc->hb2LowGainStepRecovery > 0x1F)
6174     {
6175         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_HB2_LOW_GAIN_STEP_PARM,
6176                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_HB2_LOW_GAIN_STEP_PARM));
6177         return MYKONOS_ERR_INV_AGC_OBSRX_HB2_LOW_GAIN_STEP_PARM;
6178     }
6179     else
6180     {
6181         /* Write hb2LowGainStepRecovery */
6182         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_OVRG_GAIN_STEP_5, device->obsRx->orxAgcCtrl->peakAgc->hb2LowGainStepRecovery);
6183     }
6184 
6185     /* Range check on hb2VeryLowGainStepRecovery (5-bit) */
6186     if (device->obsRx->orxAgcCtrl->peakAgc->hb2VeryLowGainStepRecovery > 0x1F)
6187     {
6188         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_HB2_VERY_LOW_GAIN_STEP_PARM,
6189                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_HB2_VERY_LOW_GAIN_STEP_PARM));
6190         return MYKONOS_ERR_INV_AGC_OBSRX_HB2_VERY_LOW_GAIN_STEP_PARM;
6191     }
6192     else
6193     {
6194         /* Write hb2VeryLowGainStepRecovery */
6195         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_OVRG_GAIN_STEP_6, device->obsRx->orxAgcCtrl->peakAgc->hb2VeryLowGainStepRecovery);
6196     }
6197 
6198     /* Range Check on hb2OverloadDetectEnable */
6199     if (device->obsRx->orxAgcCtrl->peakAgc->hb2OverloadDetectEnable > 0x1)
6200     {
6201         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_ENABLE,
6202                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_ENABLE));
6203         return MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_ENABLE;
6204     }
6205 
6206     /* Range Check on hb2OverloadDetectEnable */
6207     if (device->obsRx->orxAgcCtrl->peakAgc->hb2OverloadDurationCnt > 0x7)
6208     {
6209         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_DUR_CNT,
6210                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_DUR_CNT));
6211         return MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_DUR_CNT;
6212     }
6213 
6214     /* Range Check on hb2OverloadDetectEnable */
6215     if (device->obsRx->orxAgcCtrl->peakAgc->hb2OverloadThreshCnt > 0xF)
6216     {
6217         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_THRESH_CNT,
6218                 getMykonosErrorMessage(MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_THRESH_CNT));
6219         return MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_THRESH_CNT;
6220     }
6221     else
6222     {
6223         /* Write the hb2OvldCfgRegValue, the combination of hb2OverloadThreshCnt, hb2OverloadDurationCnt, and hb2OverloadDetectEnable */
6224         hb2OvldCfgRegValue = (device->obsRx->orxAgcCtrl->peakAgc->hb2OverloadThreshCnt) |
6225                              (uint8_t)(device->obsRx->orxAgcCtrl->peakAgc->hb2OverloadDurationCnt << 4) |
6226                              (uint8_t)(device->obsRx->orxAgcCtrl->peakAgc->hb2OverloadDetectEnable << 7);
6227         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ORX_SNRX_OVRLD_PD_DEC_OVRLD_CFG, hb2OvldCfgRegValue);
6228     }
6229 
6230     /* Hard-coded value for the ADC overload configuration. Sets the HB2 offset to -6dB.*/
6231     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ORX_SNRX_OVRLD_ADC_OVRLD_CFG, 0x18);
6232     /* Hard-coded value for APD decay setting. Setting allows for the quickest settling time of peak detector */
6233     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_BLOCK_DET_DECAY, 0x0);
6234 
6235     /* performing a soft reset */
6236     return MYKONOS_resetRxAgc(device);
6237 }
6238 
6239 /**
6240  * \brief Enables or disables the ObsRx slow loop gain counter to use the sync pulse
6241  *
6242  * <B>Dependencies:</B>
6243  * - device->spiSettings
6244  *
6245  * \param device is structure pointer to the Mykonos data structure containing the device SPI settings
6246  * \param enable is a uint8_t data type where '0' = disable ObsRx gain counter from using sync pulse, '1' = enable ObsRx gain. All other values will throw an error.
6247  *               counter to use the sync pulse. This value is written back to the device data structure for storage.
6248  *
6249  * \retval MYKONOS_ERR_OK Function completed successfully
6250  */
MYKONOS_enableObsRxGainCtrSyncPulse(mykonosDevice_t * device,uint8_t enable)6251 mykonosErr_t MYKONOS_enableObsRxGainCtrSyncPulse(mykonosDevice_t *device, uint8_t enable)
6252 {
6253     const uint8_t syncPulseBitMask = 0x80;
6254     uint8_t enableBit = 0;
6255 
6256 #if (MYKONOS_VERBOSE == 1)
6257     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enableObsRxGainCtrSyncPulse()\n");
6258 #endif
6259 
6260     enableBit = (enable > 0) ? 1 : 0;
6261 
6262     /* read, modify, write ObsRx gain counter sync pulse enable bit */
6263     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_SLOW_ORX_SNRX_LOOP_CFG, enableBit, syncPulseBitMask, 7);
6264 
6265     return MYKONOS_ERR_OK;
6266 }
6267 
6268 /**
6269  * \brief Configures the ObsRx gain control mode
6270  *
6271  * <B>Dependencies:</B>
6272  * - device->spiSettings
6273  * - device->obsRx->orxGainCtrl->gainMode
6274  *
6275  * \param device is structure pointer to the Mykonos data structure containing settings
6276  * \param mode is a mykonosGainMode_t enumerated gain control mode type
6277  *
6278  * When the mode enumerated type is passed, the ObsRx gain mode is set to this value and the
6279  * ObsRX agcType mykonosAgcCfg_t structure member is updated with the new value
6280  *
6281  * \retval MYKONOS_ERR_OK Function completed successfully
6282  * \retval MYKONOS_ERR_INV_ORX_GAIN_MODE_PARM Invalid Observation Rx Gain control mode selected (use mykonosGainMode_t ENUM values)
6283  */
MYKONOS_setObsRxGainControlMode(mykonosDevice_t * device,mykonosGainMode_t mode)6284 mykonosErr_t MYKONOS_setObsRxGainControlMode(mykonosDevice_t *device, mykonosGainMode_t mode)
6285 {
6286     const uint8_t ORX_GAIN_TYPE_MASK = 0x3;
6287 
6288 #if (MYKONOS_VERBOSE == 1)
6289     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setObsRxGainControlMode()\n");
6290 #endif
6291 
6292     /* performing gain type check */
6293     switch (mode)
6294     {
6295         case MGC:
6296             break;
6297         case AGC:
6298             break;
6299         case HYBRID:
6300             break;
6301         default:
6302             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_ORX_GAIN_MODE_PARM,
6303                     getMykonosErrorMessage(MYKONOS_ERR_INV_ORX_GAIN_MODE_PARM));
6304             return MYKONOS_ERR_INV_ORX_GAIN_MODE_PARM;
6305     }
6306 
6307     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_AGC_ORX_SNRX_CFG_1, mode, ORX_GAIN_TYPE_MASK, 0);
6308 
6309     /* writing mode setting to data structure */
6310     if ((device->profilesValid & ORX_PROFILE_VALID) > 0)
6311     {
6312         device->obsRx->orxGainCtrl->gainMode = mode;
6313     }
6314 
6315     return MYKONOS_ERR_OK;
6316 }
6317 
6318 /**
6319  * \brief Performs a power measurement in the ObsRx digital data path.
6320  *
6321  * Due to interdependencies between the AGC and power measurement the power measurement duration and
6322  * where the measurement is taken is variable.
6323  * The location of the power measurement is given by device->obsRx->obsRxAgcCtrl->obsRxPwrAgc->pmdMeasConfig
6324  * The number of samples the power measurement uses is given by 8*2^(device->obsRx->obsRxAgcCtrl->obsRxPwrAgc->pmdMeasConfig) at the IQ rate,
6325  * if measured at RFIR output. This number of samples must be less than the agcGainUpdateCounter.
6326  * If the receiver is disabled during the power measurement, this function returns a 0 value for rx2DecPower_mdBFS
6327  *
6328  * The resolution of this function is 0.25dB.
6329  * The dynamic range of this function is 40dB. Signals lower than 40dBFS may not be measured accurately.
6330  *
6331  * <B>Dependencies</B>
6332  * - device->spiSettings
6333  * - device->obsRx->obsRxAgcCtrl->obsRxPwrAgc->pmdMeasConfig
6334  * - device->obsRx->obsRxAgcCtrl->obsRxPwrAgc->pmdMeasConfig
6335  *
6336  * \param device Pointer to the Mykonos data structure
6337  * \param obsRxDecPower_mdBFS Pointer to store the Rx1 decimated power return.  Value returned in mdBFS
6338  *
6339  * \retval MYKONOS_ERR_OK Function completed successfully
6340  */
MYKONOS_getObsRxDecPower(mykonosDevice_t * device,uint16_t * obsRxDecPower_mdBFS)6341 mykonosErr_t MYKONOS_getObsRxDecPower(mykonosDevice_t *device, uint16_t *obsRxDecPower_mdBFS)
6342 {
6343     uint8_t obsRxDecPower_dBFS = 0;
6344 
6345 #if (MYKONOS_VERBOSE == 1)
6346     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getObsRxDecPower()\n");
6347 #endif
6348 
6349     /* read ObsRx Dec Power Measurement */
6350     if (obsRxDecPower_mdBFS != NULL)
6351     {
6352         CMB_SPIReadByte(device->spiSettings, MYKONOS_SNIFFER_DECIMATED_PWR, &obsRxDecPower_dBFS);
6353         *obsRxDecPower_mdBFS = (uint16_t)(obsRxDecPower_dBFS * 250); /* 250 = 1000 * 0.25dB */
6354     }
6355     else
6356     {
6357         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_OBSRX_DEC_POWER_NULL_PARM,
6358                 getMykonosErrorMessage(MYKONOS_ERR_GET_OBSRX_DEC_POWER_NULL_PARM));
6359         return MYKONOS_ERR_GET_OBSRX_DEC_POWER_NULL_PARM;
6360     }
6361 
6362     return MYKONOS_ERR_OK;
6363 }
6364 
6365 /*
6366  *****************************************************************************
6367  * Tx Data path functions
6368  *****************************************************************************
6369  */
6370 
6371 /**
6372  * \brief Sets the Tx1 RF output Attenuation
6373  *
6374  * <B>Dependencies</B>
6375  * - device->spiSettings
6376  * - device->spiSettings->chipSelectIndex
6377  * - device->tx->txAttenStepSize
6378  *
6379  * \param device Pointer to the Mykonos device's data structure
6380  * \param tx1Attenuation_mdB The desired TxAttenuation in milli-dB (Range: 0 to 41950 mdB)
6381  *
6382  * \retval MYKONOS_ERR_OK Function completed successfully
6383  * \retval MYKONOS_ERR_SETTX1ATTEN_INV_PARM tx1Attenuation_mdB parameter is out of range (0 - 41950)
6384  * \retval MYKONOS_ERR_SETTX1ATTEN_INV_STEPSIZE_PARM device->tx->txAttenStepSize is not a valid enum value
6385  */
MYKONOS_setTx1Attenuation(mykonosDevice_t * device,uint16_t tx1Attenuation_mdB)6386 mykonosErr_t MYKONOS_setTx1Attenuation(mykonosDevice_t *device, uint16_t tx1Attenuation_mdB)
6387 {
6388     uint16_t data = 0;
6389     uint16_t attenStepSizeDiv = 50;
6390 
6391 #if (MYKONOS_VERBOSE == 1)
6392     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setTx1Attenuation()\n");
6393 #endif
6394 
6395     /* check input parameter is in valid range */
6396     if (tx1Attenuation_mdB > 41950)
6397     {
6398         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETTX1ATTEN_INV_PARM,
6399                 getMykonosErrorMessage(MYKONOS_ERR_SETTX1ATTEN_INV_PARM));
6400         return MYKONOS_ERR_SETTX1ATTEN_INV_PARM;
6401     }
6402 
6403     switch (device->tx->txAttenStepSize)
6404     {
6405         case TXATTEN_0P05_DB:
6406             attenStepSizeDiv = 50;
6407             break;
6408         case TXATTEN_0P1_DB:
6409             attenStepSizeDiv = 100;
6410             break;
6411         case TXATTEN_0P2_DB:
6412             attenStepSizeDiv = 200;
6413             break;
6414         case TXATTEN_0P4_DB:
6415             attenStepSizeDiv = 400;
6416             break;
6417         default:
6418             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETTX1ATTEN_INV_STEPSIZE_PARM,
6419                     getMykonosErrorMessage(MYKONOS_ERR_SETTX1ATTEN_INV_STEPSIZE_PARM));
6420             return MYKONOS_ERR_SETTX1ATTEN_INV_STEPSIZE_PARM;
6421 
6422     }
6423 
6424     data = (tx1Attenuation_mdB / attenStepSizeDiv);
6425 
6426     /* Write MSB bits followed by LSB bits, TxAtten updates when [7:0] written */
6427     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX1_ATTENUATION_1, ((data >> 8) & 0x03));
6428     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX1_ATTENUATION_0, (data & 0xFF));
6429 
6430     return MYKONOS_ERR_OK;
6431 }
6432 
6433 /**
6434  * \brief Sets the Tx2 RF output Attenuation (Step size is 0.05dB.)
6435  *
6436  * <B>Dependencies</B>
6437  * - device->spiSettings
6438  * - device->spiSettings->chipSelectIndex
6439  * - device->tx->txAttenStepSize
6440  *
6441  * \param device Pointer to the Mykonos device's data structure
6442  * \param tx2Attenuation_mdB The desired TxAttenuation in milli-dB
6443  *                           (Range: 0 to 41950 mdB)
6444  *
6445  * \retval MYKONOS_ERR_OK Function completed successfully
6446  * \retval MYKONOS_ERR_SETTX2ATTEN_INV_PARM tx2Attenuation_mdB parameter is out of range (0 - 41950)
6447  * \retval MYKONOS_ERR_SETTX2ATTEN_INV_STEPSIZE_PARM device->tx->txAttenStepSize is not a valid enum value
6448  */
MYKONOS_setTx2Attenuation(mykonosDevice_t * device,uint16_t tx2Attenuation_mdB)6449 mykonosErr_t MYKONOS_setTx2Attenuation(mykonosDevice_t *device, uint16_t tx2Attenuation_mdB)
6450 {
6451     uint16_t attenStepSizeDiv = 50;
6452     uint16_t data = 0;
6453     //const uint8_t SPI_TXATTEN_MODE = 0x01;
6454 
6455 #if (MYKONOS_VERBOSE == 1)
6456     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setTx2Attenuation()\n");
6457 #endif
6458 
6459     /* check input parameter is in valid range */
6460     if (tx2Attenuation_mdB > 41950)
6461     {
6462         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETTX2ATTEN_INV_PARM,
6463                 getMykonosErrorMessage(MYKONOS_ERR_SETTX2ATTEN_INV_PARM));
6464         return MYKONOS_ERR_SETTX2ATTEN_INV_PARM;
6465     }
6466 
6467     switch (device->tx->txAttenStepSize)
6468     {
6469         case TXATTEN_0P05_DB:
6470             attenStepSizeDiv = 50;
6471             break;
6472         case TXATTEN_0P1_DB:
6473             attenStepSizeDiv = 100;
6474             break;
6475         case TXATTEN_0P2_DB:
6476             attenStepSizeDiv = 200;
6477             break;
6478         case TXATTEN_0P4_DB:
6479             attenStepSizeDiv = 400;
6480             break;
6481         default:
6482             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETTX2ATTEN_INV_STEPSIZE_PARM,
6483                     getMykonosErrorMessage(MYKONOS_ERR_SETTX2ATTEN_INV_STEPSIZE_PARM));
6484             return MYKONOS_ERR_SETTX2ATTEN_INV_STEPSIZE_PARM;
6485     }
6486 
6487     data = (tx2Attenuation_mdB / attenStepSizeDiv);
6488 
6489     /* Write MSB bits followed by LSB bits, TxAtten updates when [7:0] written */
6490     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX2_ATTENUATION_1, ((data >> 8) & 0x03));
6491     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX2_ATTENUATION_0, (data & 0xFF));
6492 
6493     return MYKONOS_ERR_OK;
6494 }
6495 
6496 /**
6497  * \brief Reads back the Tx1 RF output Attenuation
6498  *
6499  *  This function reads back the TxAttenuation setting currently applied to the transmit chain.
6500  *  The function will work with SPI mode or pin controlled TxAtten mode using the increment/decrement GPIO
6501  *  pins.  For the readback value to be valid the Tx data path must be powered up.  If the Tx data path
6502  *  is powered down or radioOff state, the last TxAtten setting while the Tx was powered up will be
6503  *  read back.
6504  *
6505  * <B>Dependencies</B>
6506  * - device->spiSettings
6507  * - device->spiSettings->chipSelectIndex
6508  *
6509  * \param device Pointer to the Mykonos device's data structure
6510  * \param tx1Attenuation_mdB The readback value of the Tx1 Attenuation in milli-dB (Range: 0 to 41950 mdB)
6511  *
6512  * \retval MYKONOS_ERR_OK Function completed successfully
6513  * \retval MYKONOS_ERR_GETTX1ATTEN_NULL_PARM tx1Attenuation_mdB return parameter has NULL pointer
6514  */
MYKONOS_getTx1Attenuation(mykonosDevice_t * device,uint16_t * tx1Attenuation_mdB)6515 mykonosErr_t MYKONOS_getTx1Attenuation(mykonosDevice_t *device, uint16_t *tx1Attenuation_mdB)
6516 {
6517     uint8_t txAttenLsb = 0;
6518     uint8_t txAttenMsb = 0;
6519     uint16_t attenStepSizeDiv = 50;
6520 
6521 #if (MYKONOS_VERBOSE == 1)
6522     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getTx1Attenuation()\n");
6523 #endif
6524 
6525     /* check return parameter pointer is not NULL pointer */
6526     if (tx1Attenuation_mdB == NULL)
6527     {
6528         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTX1ATTEN_NULL_PARM,
6529                 getMykonosErrorMessage(MYKONOS_ERR_GETTX1ATTEN_NULL_PARM));
6530         return MYKONOS_ERR_GETTX1ATTEN_NULL_PARM;
6531     }
6532 
6533     /* Write TxAtten read back reg to update readback values, then read Tx1Atten */
6534     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX1_ATTENUATION_1_READBACK, 0x00);
6535     CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_TX1_ATTENUATION_0_READBACK, &txAttenLsb, 0xFF, 0);
6536     CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_TX1_ATTENUATION_1_READBACK, &txAttenMsb, 0x03, 0);
6537 
6538     /* Readback word always reads back with 0.05dB resolution */
6539     *tx1Attenuation_mdB = (uint16_t)(((uint16_t)(txAttenLsb) | ((uint16_t)(txAttenMsb) << 8)) * attenStepSizeDiv);
6540 
6541     return MYKONOS_ERR_OK;
6542 }
6543 
6544 /**
6545  * \brief Reads back the Tx2 RF output Attenuation
6546  *
6547  *  This function reads back the TxAttenuation setting currently applied to the transmit chain.
6548  *  The function will work with SPI mode or pin controlled TxAtten mode using the increment/decrement GPIO
6549  *  pins.  For the readback value to be valid the Tx data path must be powered up.  If the Tx data path
6550  *  is powered down or radioOff state, the last TxAtten setting while the Tx was powered up will be
6551  *  read back.
6552  *
6553  * <B>Dependencies</B>
6554  * - device->spiSettings
6555  * - device->spiSettings->chipSelectIndex
6556  *
6557  * \param device Pointer to the Mykonos device's data structure
6558  * \param tx2Attenuation_mdB The readback value of the Tx2 Attenuation in milli-dB (Range: 0 to 41950 mdB)
6559  *
6560  * \retval MYKONOS_ERR_OK Function completed successfully
6561  * \retval MYKONOS_ERR_GETTX2ATTEN_NULL_PARM tx2Attenuation_mdB return parameter pointer is NULL
6562  */
MYKONOS_getTx2Attenuation(mykonosDevice_t * device,uint16_t * tx2Attenuation_mdB)6563 mykonosErr_t MYKONOS_getTx2Attenuation(mykonosDevice_t *device, uint16_t *tx2Attenuation_mdB)
6564 {
6565     uint8_t txAttenLsb = 0;
6566     uint8_t txAttenMsb = 0;
6567     uint16_t attenStepSizeDiv = 50;
6568 
6569 #if (MYKONOS_VERBOSE == 1)
6570     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getTx2Attenuation()\n");
6571 #endif
6572 
6573     /* check return parameter pointer is not NULL pointer */
6574     if (tx2Attenuation_mdB == NULL)
6575     {
6576         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTX2ATTEN_NULL_PARM,
6577                 getMykonosErrorMessage(MYKONOS_ERR_GETTX2ATTEN_NULL_PARM));
6578         return MYKONOS_ERR_GETTX2ATTEN_NULL_PARM;
6579     }
6580 
6581     /* Write TxAtten read back reg to update readback values, then read Tx1Atten */
6582     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX2_ATTENUATION_1_READBACK, 0x00);
6583     CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_TX2_ATTENUATION_0_READBACK, &txAttenLsb, 0xFF, 0);
6584     CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_TX2_ATTENUATION_1_READBACK, &txAttenMsb, 0x03, 0);
6585 
6586     /* Readback word always reads back with 0.05dB resolution */
6587     *tx2Attenuation_mdB = (uint16_t)(((uint16_t)(txAttenLsb) | ((uint16_t)(txAttenMsb) << 8)) * attenStepSizeDiv);
6588 
6589     return MYKONOS_ERR_OK;
6590 }
6591 
6592 /**
6593  * \brief Checks the Tx Filter over-range bit assignments for digital clipping in the Tx data path
6594  *
6595  * <B>Dependencies</B>
6596  * - device->spiSettings
6597  *
6598  * txFilterStatus bit-field assignments are:
6599  * txFilterStatus[0] = TFIR Ch1 Overflow
6600  * txFilterStatus[1] = HB1 Ch1 Overflow
6601  * txFilterStatus[2] = HB2 Ch1 Overflow
6602  * txFilterStatus[3] = QEC Ch1 Overflow
6603  * txFilterStatus[4] = TFIR Ch2 Overflow
6604  * txFilterStatus[5] = HB1 Ch2 Overflow
6605  * txFilterStatus[6] = HB2 Ch2 Overflow
6606  * txFilterStatus[7] = QEC Ch2 Overflow
6607  *
6608  * \param device Pointer to the Mykonos device's data structure
6609  * \param txFilterStatus is an 8-bit Tx filter over-range status bit-field
6610  *
6611  * \retval MYKONOS_ERR_OK Function completed successfully
6612  * \retval MYKONOS_ERR_GET_TXFILTEROVRG_NULL_PARM Function txFilterStatus parameter pointer is NULL
6613  */
MYKONOS_getTxFilterOverRangeStatus(mykonosDevice_t * device,uint8_t * txFilterStatus)6614 mykonosErr_t MYKONOS_getTxFilterOverRangeStatus(mykonosDevice_t *device, uint8_t *txFilterStatus)
6615 {
6616 
6617 #if (MYKONOS_VERBOSE == 1)
6618     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getTxFilterOverRangeStatus()\n");
6619 #endif
6620 
6621     if (txFilterStatus == NULL)
6622     {
6623         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_TXFILTEROVRG_NULL_PARM,
6624                 getMykonosErrorMessage(MYKONOS_ERR_GET_TXFILTEROVRG_NULL_PARM));
6625         return MYKONOS_ERR_GET_TXFILTEROVRG_NULL_PARM;
6626     }
6627 
6628     CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_TX_FILTER_OVERFLOW, txFilterStatus);
6629     return MYKONOS_ERR_OK;
6630 }
6631 
6632 /**
6633  * \brief Enables/Disables the Tx NCO test tone
6634  *
6635  *  This function enables/disables a digital numerically controlled oscillator
6636  *  in the Mykonos Digital to create a test CW tone on Tx1 and Tx2 RF outputs.
6637  *
6638  *  The TxAttenuation is forced in this function to max analog output power, but
6639  *  the digital attenuation is backed off 6dB to make sure the digital filter
6640  *  does not clip and cause spurs in the tx spectrum.
6641  *
6642  * <B>Dependencies</B>
6643  * - device->spiSettings
6644  * - device->profilesValid
6645  * - device->tx->txProfile->iqRate_kHz
6646  *
6647  * \param device Pointer to the Mykonos device's data structure
6648  * \param enable 0 = Disable Tx NCO, 1 = Enable Tx NCO on both transmitters
6649  * \param tx1ToneFreq_kHz Signed frequency in kHz of the desired Tx1 tone
6650  * \param tx2ToneFreq_kHz Signed frequency in kHz of the desired Tx2 tone
6651  *
6652  * \retval MYKONOS_ERR_OK Function completed successfully
6653  * \retval MYKONOS_ERR_ENTXNCO_TXPROFILE_INVALID Can not enable Tx NCO when Tx Profile is not enabled/valid
6654  * \retval MYKONOS_ERR_ENTXNCO_TX1_FREQ_INVALID Tx1 NCO Tone frequency out of range (-IQrate/2 to IQrate/2)
6655  * \retval MYKONOS_ERR_ENTXNCO_TX2_FREQ_INVALID Tx2 NCO Tone frequency out of range (-IQrate/2 to IQrate/2)
6656  */
MYKONOS_enableTxNco(mykonosDevice_t * device,uint8_t enable,int32_t tx1ToneFreq_kHz,int32_t tx2ToneFreq_kHz)6657 mykonosErr_t MYKONOS_enableTxNco(mykonosDevice_t *device, uint8_t enable, int32_t tx1ToneFreq_kHz, int32_t tx2ToneFreq_kHz)
6658 {
6659     int16_t tx1NcoTuneWord = 0;
6660     int16_t tx2NcoTuneWord = 0;
6661 
6662 #if (MYKONOS_VERBOSE == 1)
6663     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enableTxNco()\n");
6664 #endif
6665 
6666     if (enable > 0)
6667     {
6668         if ((device->profilesValid & TX_PROFILE_VALID) == 0)
6669         {
6670             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ENTXNCO_TXPROFILE_INVALID,
6671                     getMykonosErrorMessage(MYKONOS_ERR_ENTXNCO_TXPROFILE_INVALID));
6672             return MYKONOS_ERR_ENTXNCO_TXPROFILE_INVALID;
6673         }
6674 
6675         if ((tx1ToneFreq_kHz > ((int32_t)(device->tx->txProfile->iqRate_kHz) / 2)) || (tx1ToneFreq_kHz < ((int32_t)(device->tx->txProfile->iqRate_kHz) * -1 / 2)))
6676         {
6677             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ENTXNCO_TX1_FREQ_INVALID,
6678                     getMykonosErrorMessage(MYKONOS_ERR_ENTXNCO_TX1_FREQ_INVALID));
6679             return MYKONOS_ERR_ENTXNCO_TX1_FREQ_INVALID;
6680         }
6681 
6682         if ((tx2ToneFreq_kHz > ((int32_t)(device->tx->txProfile->iqRate_kHz) / 2)) || (tx2ToneFreq_kHz < ((int32_t)(device->tx->txProfile->iqRate_kHz) * -1 / 2)))
6683         {
6684             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ENTXNCO_TX2_FREQ_INVALID,
6685                     getMykonosErrorMessage(MYKONOS_ERR_ENTXNCO_TX2_FREQ_INVALID));
6686             return MYKONOS_ERR_ENTXNCO_TX2_FREQ_INVALID;
6687         }
6688 
6689         /* Force Tx output power to max analog output power, but 6dB digital */
6690         /* backoff to prevent the NCO from clipping the Tx PFIR filter */
6691         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX1_GAIN_0, 0x78);
6692         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX1_GAIN_1, 0x00, 0x3F, 0);
6693         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX1_GAIN_2, 0x0);
6694 
6695         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX2_GAIN_0, 0x78);
6696         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX2_GAIN_1, 0x00, 0x3F, 0);
6697         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX2_GAIN_2, 0x0);
6698 
6699         /* Enable manual Tx output power mode */
6700         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_TPC_CONFIG, 0x0A, 0x0F, 0);
6701 
6702         /* Set Tx NCO tuning words */
6703         tx1NcoTuneWord = (int16_t)(((int64_t)(tx1ToneFreq_kHz) << 16) / device->tx->txProfile->iqRate_kHz * -1);
6704         tx2NcoTuneWord = (int16_t)(((int64_t)(tx2ToneFreq_kHz) << 16) / device->tx->txProfile->iqRate_kHz * -1);
6705 
6706         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX_ABBF_FREQ_CAL_NCO_I_MSB, (uint8_t)((uint16_t)tx1NcoTuneWord >> 8));
6707         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX_ABBF_FREQ_CAL_NCO_I_LSB, (tx1NcoTuneWord & 0xFF));
6708 
6709         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX_ABBF_FREQ_CAL_NCO_Q_MSB, (uint8_t)((uint16_t)tx2NcoTuneWord >> 8));
6710         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_TX_ABBF_FREQ_CAL_NCO_Q_LSB, (tx2NcoTuneWord & 0xFF));
6711 
6712         /* Enable Tx NCO - set [7] = 1 */
6713         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_DIGITAL_TEST_BYTE_0, 1, 0x80, 7);
6714     }
6715     else
6716     {
6717         /* Disable Tx NCO - set [7] = 0 */
6718         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_DIGITAL_TEST_BYTE_0, 0, 0x80, 7);
6719 
6720         /* Enable normal Tx Atten table mode */
6721         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_TX_TPC_CONFIG, 0x05, 0x0F, 0);
6722     }
6723 
6724     return MYKONOS_ERR_OK;
6725 }
6726 
6727 /**
6728  * \brief Writes Mykonos device registers with settings for the PA Protection block.
6729  *
6730  * This function writes register settings for the Mykonos PA Protection Block.
6731  * This function does not enable the PA Protection functionality.
6732  * Note that independent control of PA protection for both Tx channels is not possible.
6733  * The PA Protection block allows for error flags to go high if the accumulated TX power in the data path
6734  * exceeds a programmable threshold level based on samples taken in a programmable duration.
6735  *
6736  * \post After calling this function the user will need to call MYKONOS_enablePaProtection(...)
6737  *
6738  * <B>Dependencies</B>
6739  * - device->spiSettings
6740  * - device->spiSettings->chipSelectIndex
6741  *
6742  * \param device Pointer to the Mykonos device's data structure
6743  * \param powerThreshold PA Protection Threshold sets the power level that, if detected in the TX data path, raises the PA error flags. The range is 0 to 4096.
6744  * To calculate the required setting for the power threshold:
6745  * powerThreshold = MAX_DAC_CODE * (10^((txPowerThresh_dBFS/10)))
6746  * For example: If the required dBFS for the threshold is -10 dBFS, then the powerThreshold passed should be 409.
6747  *
6748  * \param attenStepSize Attenuation Step Size sets the size of the attenuation step when Tx Atten Control is Enabled. The range is 0 to 128 with a resolution is 0.2dB/LSB.
6749  * \param avgDuration Averaging Duration for the TX data path power measurement. The range is 0 to 14 specified in number of cycles of the TX IQ Rate.
6750  * \param stickyFlagEnable "1" Enables the PA Error Flags to stay high after being triggered, even if the power decreases below threshold. "0" disables this functionality.
6751  * \param txAttenControlEnable "1" Enables autonomous attenuation changes in response to PA error flags. "0" disables this functionality.
6752  *
6753  * \retval MYKONOS_ERR_OK Function completed successfully
6754  * \retval MYKONOS_ERR_SETUP_PA_PROT_INV_AVG_DURATION avgDuration parameter invalid (valid 0-15)
6755  * \retval MYKONOS_ERR_SETUP_PA_PROT_INV_ATTEN_STEP attenStepSize function parameter invalid (valid 0-127)
6756  */
MYKONOS_setupPaProtection(mykonosDevice_t * device,uint16_t powerThreshold,uint8_t attenStepSize,uint8_t avgDuration,uint8_t stickyFlagEnable,uint8_t txAttenControlEnable)6757 mykonosErr_t MYKONOS_setupPaProtection(mykonosDevice_t *device, uint16_t powerThreshold, uint8_t attenStepSize, uint8_t avgDuration, uint8_t stickyFlagEnable, uint8_t txAttenControlEnable)
6758 {
6759     uint8_t paProtectConfig = 0;
6760     uint8_t paProtectAttenCntl = 0;
6761 
6762     const uint8_t PROTECT_AVG_DUR_MASK = 0x1E;
6763     const uint8_t STICKY_FLAG_EN_MASK = 0x40;
6764     const uint8_t ATT_STEP_MASK = 0xFE;
6765     const uint8_t PROTECT_ATT_EN_MASK = 0x01;
6766     const uint8_t AVG_DUR_MASK = 0x0F;
6767     const uint8_t ATT_STEP_SIZE = 0x7F;
6768 
6769 #if (MYKONOS_VERBOSE == 1)
6770     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setupPaProtection()\n");
6771 #endif
6772 
6773     /* Overwrite PA Protection Config register data with averaging duration and sticky flag. Also performing range check on stickyFlagEnable and avgDuration */
6774     if (avgDuration > AVG_DUR_MASK)
6775     {
6776         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETUP_PA_PROT_INV_AVG_DURATION,
6777                 getMykonosErrorMessage(MYKONOS_ERR_SETUP_PA_PROT_INV_AVG_DURATION));
6778         return MYKONOS_ERR_SETUP_PA_PROT_INV_AVG_DURATION;
6779     }
6780 
6781     if (attenStepSize > ATT_STEP_SIZE)
6782     {
6783         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETUP_PA_PROT_INV_ATTEN_STEP,
6784                 getMykonosErrorMessage(MYKONOS_ERR_SETUP_PA_PROT_INV_ATTEN_STEP));
6785         return MYKONOS_ERR_SETUP_PA_PROT_INV_ATTEN_STEP;
6786     }
6787 
6788     paProtectConfig = (PROTECT_AVG_DUR_MASK & (avgDuration << 1));
6789 
6790     if (stickyFlagEnable > 0)
6791     {
6792         paProtectConfig |= (STICKY_FLAG_EN_MASK);
6793     }
6794 
6795     paProtectAttenCntl = ATT_STEP_MASK & (attenStepSize << 1);
6796 
6797     if (txAttenControlEnable > 0)
6798     {
6799         paProtectAttenCntl |= (PROTECT_ATT_EN_MASK);
6800     }
6801 
6802     /* Clear and write all PA Protection setup registers */
6803     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_ATTEN_CONTROL, 0x00);
6804     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_CONFIGURATION, 0x00);
6805     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_THRESHOLD_LSB, 0x00);
6806     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_THRESHOLD_MSB, 0x00);
6807 
6808     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_ATTEN_CONTROL, paProtectAttenCntl);
6809     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_CONFIGURATION, paProtectConfig);
6810     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_THRESHOLD_LSB, (powerThreshold & 0xFF));
6811     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_THRESHOLD_MSB, ((powerThreshold >> 8) & 0x0F));
6812 
6813     return MYKONOS_ERR_OK;
6814 }
6815 
6816 /**
6817  * \brief Enables the Mykonos PA Protection block according to the parameters passed in MYKONOS_setupPaProtection(...).
6818  *
6819  * This function enables the PA Protection block according to the parameters passed in MYKONOS_setupPaProtection(...)
6820  * The paProtectEnable signal enables the PA Protection block, allowing usage of the PA protection functions.
6821  *
6822  * \pre Before calling this function the user needs to setup the PA protection by calling MYKONOS_setupPaProtection(...)
6823  *
6824  * <B>Dependencies</B>
6825  * - device->spiSettings
6826  * - device->spiSettings->chipSelectIndex
6827  *
6828  * \param device Pointer to the Mykonos device's data structure
6829  * \param paProtectEnable "1" Enables the PA Protection block. "0" Disables the PA Protection block
6830  *
6831  * \retval MYKONOS_ERR_OK Function completed successfully
6832  */
MYKONOS_enablePaProtection(mykonosDevice_t * device,uint8_t paProtectEnable)6833 mykonosErr_t MYKONOS_enablePaProtection(mykonosDevice_t *device, uint8_t paProtectEnable)
6834 {
6835     uint8_t paProtectEnableReg = 0;
6836 
6837 #if (MYKONOS_VERBOSE == 1)
6838     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enablePaProtection()\n");
6839 #endif
6840 
6841     paProtectEnableReg = (paProtectEnable > 0) ? 1 : 0;
6842     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_CONFIGURATION, paProtectEnableReg, 0x01, 0);
6843 
6844     return MYKONOS_ERR_OK;
6845 }
6846 
6847 /**
6848  * \brief Obtains an estimate of a TX channel's accumulated power over the sample duration provided in MYKONOS_setupPaProtection(...)
6849  *
6850  * This function uses the 'avgDuration' parameter provided in MYKONOS_setupPaProtection to set the number of samples to accumulate
6851  * to obtain an estimate for a TX channel specified by the 'channel' parameter.
6852  * A 12-bit field estimating the channel power is returned in the '*channelPower' pointer.
6853  * To obtain the dBFS value of the reading:
6854  * dBFS value = 10*log10(channelPower/MAX_DAC_CODE)
6855  * where MAX_DAC_CODE = 2^12 =  4096
6856  * For example: If channelPower is reading 409 then the channel power in dBFS is -10dBFS.
6857  *
6858  * <B>Dependencies</B>
6859  * - device->spiSettings
6860  * - device->spiSettings->chipSelectIndex
6861  *
6862  * \param device Point to the Mykonos device's data structure
6863  * \param channel Select the channel of interest. Only use TX1 (1) or TX2 (2) of mykonosTxChannels_t
6864  * \param *channelPower A pointer that stores the selected channels power. Read back is provided as a 12 bit value.
6865  *
6866  * \retval MYKONOS_ERR_OK Function completed successfully
6867  * \retval MYKONOS_ERR_GET_DAC_PWR_INV_POINTER Function channelPower parameter is a NULL pointer
6868  * \retval MYKONOS_ERR_SETUP_PA_PROT_INV_TX_CHANNEL Invalid Tx Channel passed in function channel parameter (TX1 or TX2)
6869  */
MYKONOS_getDacPower(mykonosDevice_t * device,mykonosTxChannels_t channel,uint16_t * channelPower)6870 mykonosErr_t MYKONOS_getDacPower(mykonosDevice_t *device, mykonosTxChannels_t channel, uint16_t *channelPower)
6871 {
6872     uint8_t channelPowerLsb = 0;
6873     uint8_t channelPowerMsb = 0;
6874 
6875     const uint8_t CHAN_POWER_MSB_MASK = 0xF;
6876 
6877 #if (MYKONOS_VERBOSE == 1)
6878     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getDacPower()\n");
6879 #endif
6880 
6881     if (channelPower == NULL)
6882     {
6883         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_DAC_PWR_INV_POINTER,
6884                 getMykonosErrorMessage(MYKONOS_ERR_GET_DAC_PWR_INV_POINTER));
6885         return MYKONOS_ERR_GET_DAC_PWR_INV_POINTER;
6886     }
6887 
6888     /* Set bit D5 to read the appropriate channel power */
6889     switch (channel)
6890     {
6891         case TX1:
6892             CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_CONFIGURATION, 0, 0x20, 5);
6893             break;
6894         case TX2:
6895             CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_CONFIGURATION, 1, 0x20, 5);
6896             break;
6897         default:
6898             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETUP_PA_PROT_INV_TX_CHANNEL,
6899                     getMykonosErrorMessage(MYKONOS_ERR_SETUP_PA_PROT_INV_TX_CHANNEL));
6900             return MYKONOS_ERR_SETUP_PA_PROT_INV_TX_CHANNEL;
6901     }
6902 
6903     /* SPI Write to register PA Protection power readback registers (write strobe) */
6904     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_POWER_READBACK_LSB, 0x00);
6905 
6906     /* SPI Read of the PA Protection power readback registers */
6907     CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_POWER_READBACK_LSB, &channelPowerLsb);
6908     CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_POWER_READBACK_MSB, &channelPowerMsb);
6909 
6910     *channelPower = (channelPowerLsb | (((uint16_t)(channelPowerMsb & CHAN_POWER_MSB_MASK)) << 8));
6911 
6912     return MYKONOS_ERR_OK;
6913 }
6914 
6915 /**
6916  * \brief Returns PA Protection Error Flag Status
6917  *
6918  * This function provides a readback of the PA protection Error Flag Status through the '*errorFlagStatus' pointer
6919  *
6920  * <B>Dependencies</B>
6921  * - device->spiSettings
6922  * - device->spiSettings->chipSelectIndex
6923  *
6924  * \param device Point to the Mykonos device's data structure
6925  * \param errorFlagStatus Pointer to store the error flag status.
6926  * errorFlagStatus  |  error
6927  * -----------------|------------
6928  *         0        |   indicates no PA Error Flags are high
6929  *         1        |   indicates TX1 Error Flag
6930  *         2        |   indicates TX2 Error Flag
6931  *         3        |   indicates TX1 and TX2 Error Flags are high
6932  *
6933  *
6934  * \retval MYKONOS_ERR_OK Function completed successfully
6935  * \retval MYKONOS_ERR_GET_PA_FLAG_STATUS_INV_POINTER Function errorFlagStatus parameter has NULL pointer
6936  */
MYKONOS_getPaProtectErrorFlagStatus(mykonosDevice_t * device,uint8_t * errorFlagStatus)6937 mykonosErr_t MYKONOS_getPaProtectErrorFlagStatus(mykonosDevice_t *device, uint8_t *errorFlagStatus)
6938 {
6939 
6940 #if (MYKONOS_VERBOSE == 1)
6941     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getPaProtectErrorFlagStatus()\n");
6942 #endif
6943 
6944     if (errorFlagStatus == NULL)
6945     {
6946         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_PA_FLAG_STATUS_INV_POINTER,
6947                 getMykonosErrorMessage(MYKONOS_ERR_GET_PA_FLAG_STATUS_INV_POINTER));
6948         return MYKONOS_ERR_GET_PA_FLAG_STATUS_INV_POINTER;
6949     }
6950 
6951     /* SPI Write to register PA Protection power readback registers (write strobe) */
6952     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_POWER_READBACK_LSB, 0x00);
6953 
6954     /* SPI Read of the PA Protection power readback registers */
6955     CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_POWER_READBACK_MSB, errorFlagStatus, 0x60, 5);
6956 
6957     return MYKONOS_ERR_OK;
6958 }
6959 
6960 /**
6961  * \brief Manually clears the PA Protection Error Flags.
6962  *
6963  * This function manually clears the PA Error Flags. The user must setup the PA Protection block to enable
6964  * sticky error flags. Sticky error flags require the user to clear the bit manually even if the accumulated power is
6965  * below the power threshold for the PA protection block.
6966  *
6967  * <B>Dependencies</B>
6968  * - device->spiSettings
6969  * - device->spiSettings->chipSelectIndex
6970  *
6971  * \param device Pointer to the Mykonos device's data structure
6972  *
6973  * \retval MYKONOS_ERR_OK Function completed successfully
6974  */
MYKONOS_clearPaErrorFlag(mykonosDevice_t * device)6975 mykonosErr_t MYKONOS_clearPaErrorFlag(mykonosDevice_t *device)
6976 {
6977     uint8_t paProtectConfig = 0;
6978 
6979     const uint8_t PA_ERROR_CLEAR_MASK = 0x80;
6980 
6981 #if (MYKONOS_VERBOSE == 1)
6982     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_clearPaErrorFlag()\n");
6983 #endif
6984 
6985     /* SPI Read of the PA Protection power readback registers */
6986     CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_CONFIGURATION, &paProtectConfig);
6987 
6988     /* SPI Write to self clear the PA Error Flags */
6989     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_PA_PROTECTION_CONFIGURATION, (paProtectConfig | PA_ERROR_CLEAR_MASK));
6990 
6991     return MYKONOS_ERR_OK;
6992 }
6993 
6994 /**
6995  * \brief Helper function for return of character string based on 32-bit mykonosErr_t enum value
6996  *
6997  * To save codespace, these error strings are ifdef'd out unless the user
6998  * adds a define MYKONOS_VERBOSE to their workspace.  This function can be
6999  * useful for debug.  Each function also returns unique error codes to
7000  * make it easier to determine where the code broke.
7001  *
7002  * \param errorCode is enumerated error code value
7003  *
7004  * \return Returns character string based on enumerated value
7005  */
getMykonosErrorMessage(mykonosErr_t errorCode)7006 const char* getMykonosErrorMessage(mykonosErr_t errorCode)
7007 {
7008 #ifndef MYKONOS_VERBOSE
7009     return "";
7010 
7011 #else
7012 
7013     switch (errorCode)
7014     {
7015         case MYKONOS_ERR_OK:
7016             return "";
7017         case MYKONOS_ERR_INV_PARM:
7018             return "Mykonos: Invalid parameter\n";
7019         case MYKONOS_ERR_FAILED:
7020             return "Mykonos: General Failure\n";
7021         case MYKONOS_ERR_WAITFOREVENT_INV_PARM:
7022             return "waitForEvent had invalid parameter.\n";
7023         case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT:
7024             return "waitForEvent timed out.\n";
7025         case MYKONOS_ERR_SETENSM_INVALID_NEWSTATE_WAIT:
7026             return "Requested new ENSM state is invalid from the WAIT state.\n";
7027         case MYKONOS_ERR_SETENSM_INVALID_NEWSTATE_ALERT:
7028             return "Requested new ENSM state is invalid from the ALERT state.\n";
7029         case MYKONOS_ERR_SETENSM_INVALID_NEWSTATE_TXRX:
7030             return "Requested new ENSM state is invalid from the TXRX state.\n";
7031         case MYKONOS_ERR_SETENSM_INVALIDSTATE:
7032             return "Current ENSM state is an invalid state or calibration state.\n";
7033         case MYKONOS_ERR_PU_RXPATH_INV_PARAM:
7034             return "Invalid Rx channel was requested to be powered up.\n";
7035         case MYKONOS_ERR_PU_TXPATH_INV_PARAM:
7036             return "Invalid Tx channel was requested to be powered up.\n";
7037         case MYKONOS_ERR_PU_OBSRXPATH_INV_PARAM:
7038             return "Invalid ObsRx channel was requested to be powered up.\n";
7039         case MYKONOS_ERR_SETDEFOBSRXPATH_NULL_DEF_OBSRX_STRUCT:
7040             return "Invalid default ObsRx channel was requested to be powered up.\n";
7041         case MYKONOS_ERR_INIT_INV_ORXCHAN:
7042             return "Invalid ObsRx channel requested during initialize().\n";
7043         case MYKONOS_ERR_INIT_INV_RXSYNCB_ORXSYNCB_MODE:
7044             return "Invalid combination for rxsyncb and orxsyncb, if shared syncb they should have the CMOS/LVDS mode\n";
7045         case MYKONOS_ERR_INIT_INV_TXFIR_INTERPOLATION:
7046             return "Invalid TxFIR interpolation value.(Valid: 1,2,4)\n";
7047         case MYKONOS_ERR_INIT_INV_TXHB2_INTERPOLATION:
7048             return "Invalid TXHB2 interpolation value.(Valid: 1 or 2)\n";
7049         case MYKONOS_ERR_INIT_INV_TXHB1_INTERPOLATION:
7050             return "Invalid TXHB1 interpolation value.(Valid: 1 or 2)\n";
7051         case MYKONOS_ERR_INIT_INV_RXFIR_DECIMATION:
7052             return "Invalid RxFIR decimation value.(Valid: 1,2,4)\n";
7053         case MYKONOS_ERR_INIT_INV_RXDEC5_DECIMATION:
7054             return "Invalid Rx DEC5 decimation value.(Valid: 4 or 5)\n";
7055         case MYKONOS_ERR_INIT_INV_RXHB1_DECIMATION:
7056             return "Invalid RxHB1 decimation value.(Valid: 1 or 2)\n";
7057         case MYKONOS_ERR_INIT_INV_SNIFFER_RHB1:
7058             return "Invalid Sniffer HB1 decimation value (Valid 1 or 2)\n";
7059         case MYKONOS_ERR_INIT_INV_SNIFFER_RFIR_DEC:
7060             return "Invalid Sniffer RFIR decimation value (Valid 1,2,4)\n";
7061         case MYKONOS_ERR_INIT_INV_ORX_RHB1:
7062             return "Invalid ORx HB1 decimation value (Valid 1 or 2)\n";
7063         case MYKONOS_ERR_INIT_INV_ORX_RFIR_DEC:
7064             return "Invalid ORx RFIR decimation value. (Valid 1,2,4)\n";
7065         case MYKONOS_ERR_INIT_INV_ADCDIV:
7066             return "Invalid Rx ADC divider. (Valid 1 or 2)\n";
7067         case MYKONOS_ERR_INIT_INV_DACDIV:
7068             return "Invalid Tx DAC divider. Use enum DACDIV_2, DACDIV_2p5 or DACDIV_4.\n";
7069         case MYKONOS_ERR_INIT_INV_OBSRX_ADCDIV:
7070             return "Invalid ObsRx ADC div. (Valid 1 or 2)\n";
7071         case MYKONOS_ERR_CLKPLL_INV_HSDIV:
7072             return "Invalid CLKPLL HSDIV. (Valid 4 or 5)\n";
7073         case MYKONOS_ERR_CLKPLL_INV_VCODIV:
7074             return "Invalid CLKPLL VCODIV. Use enum VCODIV_1, VCODIV_1p5, VCODIV_2, VCODIV_3\n";
7075         case MYKONOS_ERR_CLKPLL_INV_RXTXPROFILES:
7076             return "No Rx or Tx profile is specified.\n";
7077         case MYKONOS_ERR_SETCLKPLL_INV_VCOINDEX:
7078             return "CLKPLL VCO frequency out of range.\n";
7079         case MYKONOS_ERR_SETCLKPLL_INV_FRACWORD:
7080             return "CLKPLL fractional word is non zero.\n";
7081         case MYKONOS_ERR_SETRFPLL_INV_PLLNAME:
7082             return "Invalid pllName requested in setRfPllFreuquency()\n";
7083         case MYKONOS_ERR_SETRFPLL_INV_LO_PARM:
7084             return "RF PLL frequency out of range\n";
7085         case MYKONOS_ERR_GETRFPLL_INV_PLLNAME:
7086             return "Invalid pllName requested in getRfPllFrequency()\n";
7087         case MYKONOS_ERR_GETRFPLL_ARMERROR:
7088             return "ARM Command Error in MYKONOS_getRfPllFrequency()\n";
7089         case MYKONOS_ERR_GETRFPLL_NULLPARAM:
7090             return "NULL pointer in function parameter for MYKONOS_setRfPllFrequency()\n";
7091         case MYKONOS_ERR_INV_SCALEDDEVCLK_PARAM:
7092             return "Could not scale device clock into range 40MHz to 80Mhz.\n";
7093         case MYKONOS_ERR_SETRFPLL_INV_VCOINDEX:
7094             return "RFPLL VCO frequency out of range.\n";
7095         case MYKONOS_ERR_SETRFPLL_INV_REFCLK:
7096             return "Unsupported PLL reference clock or refclk out of range.\n";
7097         case MYKONOS_ERR_SETORXGAIN_INV_CHANNEL:
7098             return "Invalid ObsRx channel in setObsRxManualGain().\n";
7099         case MYKONOS_ERR_SETORXGAIN_INV_ORX1GAIN:
7100             return "Invalid gain requested in setObsRxManualGain() for ORX1\n";
7101         case MYKONOS_ERR_SETORXGAIN_INV_ORX2GAIN:
7102             return "Invalid gain requested in setObsRxManualGain() for ORX2\n";
7103         case MYKONOS_ERR_SETORXGAIN_INV_SNRXGAIN:
7104             return "Invalid gain requested in setObsRxManualGain() for Sniffer\n";
7105         case MYKONOS_ERR_GETORX1GAIN_INV_POINTER:
7106             return "Cannot return ORx1 gain to gain control data structure (invalid pointer).\n";
7107         case MYKONOS_ERR_GETORX2GAIN_INV_POINTER:
7108             return "Cannot return ORx2 gain to gain control data structure (invalid pointer).\n";
7109         case MYKONOS_ERR_GETSNIFFGAIN_INV_POINTER:
7110             return "Cannot return Sniffer gain to gain control data structure (invalid pointer).\n";
7111         case MYKONOS_ERR_GETOBSRXGAIN_CH_DISABLED:
7112             return "Cannot read ObsRx gain index. ObsRx Channel is disabled.\n";
7113         case MYKONOS_ERR_SETTX1ATTEN_INV_PARM:
7114             return "Tx1 attenuation is out of range (0 - 41950 mdB).\n";
7115         case MYKONOS_ERR_SETTX1ATTEN_INV_STEPSIZE_PARM:
7116             return "Invalid Tx1Atten stepsize. Use enum mykonosTxAttenStepSize_t\n";
7117         case MYKONOS_ERR_SETTX2ATTEN_INV_PARM:
7118             return "Tx2 attenuation is out of range (0 - 41950 mdB).\n";
7119         case MYKONOS_ERR_SETTX2ATTEN_INV_STEPSIZE_PARM:
7120             return "Invalid Tx2Atten stepsize. Use enum mykonosTxAttenStepSize_t\n";
7121         case MYKONOS_ERR_PROGRAMFIR_INV_NUMTAPS_PARM:
7122             return "Invalid number of FIR taps\n";
7123         case MYKONOS_ERR_READFIR_INV_NUMTAPS_PARM:
7124             return "Invalid number of FIR taps read for the selected Filter\n";
7125         case MYKONOS_ERR_PROGRAMFIR_INV_FIRNAME_PARM:
7126             return "Invalid FIR filter name requested. use enum mykonosfirName_t\n";
7127         case MYKONOS_ERR_RXFIR_INV_GAIN_PARM:
7128             return "Rx FIR filter has invalid gain setting\n";
7129         case MYKONOS_ERR_OBSRXFIR_INV_GAIN_PARM:
7130             return "ObsRx FIR filter A (ORx) has invalid gain setting\n";
7131         case MYKONOS_ERR_SRXFIR_INV_GAIN_PARM:
7132             return "ObsRx FIR filter B (Sniffer) has invalid gain setting\n";
7133         case MYKONOS_ERR_TXFIR_INV_GAIN_PARM:
7134             return "Tx FIR filter has invalid gain setting\n";
7135         case MYKONOS_ERR_READFIR_NULL_PARM:
7136             return "MYKONOS_readFir() has a null *firFilter parameter\n";
7137         case MYKONOS_ERR_READFIR_COEFS_NULL:
7138             return "MYKONOS_readFir() has a null coef array in *firFilter structure\n";
7139         case MYKONOS_ERR_READFIR_INV_FIRNAME_PARM:
7140             return "Invalid FIR filter name requested. use enum mykonosfirName_t\n";
7141         case MYKONOS_ERR_SETRX1GAIN_INV_GAIN_PARM:
7142             return "Rx1 manual gain index out of range of gain table\n";
7143         case MYKONOS_ERR_SETRX2GAIN_INV_GAIN_PARM:
7144             return "Rx2 manual gain index out of range of gain table\n";
7145         case MYKONOS_ERR_INITSER_INV_VCODIV_PARM:
7146             return "Found invalid VCO divider value during setupSerializers()\n";
7147         case MYKONOS_ERR_INITSER_INV_VCODIV1_HSCLK_PARM:
7148             return "CLKPLL VCO frequency exceeded max(8Ghz) in VCO divider /1 case ()\n";
7149         case MYKONOS_ERR_INITSER_INV_VCODIV1P5_HSCLK_PARM:
7150             return "CLKPLL VCO frequency exceeded max(9.216Ghz) in VCO divider /1.5 case ()\n";
7151         case MYKONOS_ERR_INITDES_INV_VCODIV_PARM:
7152             return "Found invalid VCO divider value during setupDeserializers()\n";
7153         case MYKONOS_ERR_SER_INV_M_PARM:
7154             return "Invalid JESD Framer M parameter during setupSerializers()\n";
7155         case MYKONOS_ERR_SER_INV_L_PARM:
7156             return "Invalid JESD Framer L parameter during setupSerializers()\n";
7157         case MYKONOS_ERR_SER_INV_LANERATE_PARM:
7158             return "Invalid Lanerate frequency in setupSerializer()\n";
7159         case MYKONOS_ERR_SER_INV_LANEEN_PARM:
7160             return "Invalid number of JESD204 lanes enabled.\n";
7161         case MYKONOS_ERR_SER_INV_AMP_PARM:
7162             return "Invalid JESD204 serializer amplitude\n";
7163         case MYKONOS_ERR_SER_INV_PREEMP_PARM:
7164             return "Invalid JESD204 serializer preemphasis setting\n";
7165         case MYKONOS_ERR_SER_INV_LANEPN_PARM:
7166             return "Invald JESD204 serializer PN invert setting\n";
7167         case MYKONOS_ERR_SER_LANE_CONFLICT_PARM:
7168             return "Rx framer and ObsRx framer are attempting to use the same physical lanes\n";
7169         case MYKONOS_ERR_SER_INV_TXSER_DIV_PARM:
7170             return "Invalid serializer lane clock divider\n";
7171         case MYKONOS_ERR_SER_LANE_RATE_CONFLICT_PARM:
7172             return "Rx lane and ObsRx lane rate must match\n";
7173         case MYKONOS_ERR_SER_INV_REAL_IF_DATA_PARM:
7174             return "Framer M can only =1 if Real IF data option is enabled\n";
7175         case MYKONOS_ERR_HS_AND_LANE_RATE_NOT_INTEGER_MULT:
7176             return "Serializer HSCLK and lane clock are not integer multiples\n";
7177         case MYKONOS_ERR_DES_HS_AND_LANE_RATE_NOT_INTEGER_MULT:
7178             return "Deserializer HSCLK and lane clock are not integer multiples\n";
7179         case MYKONOS_ERR_DESER_INV_M_PARM:
7180             return "Invalid deserializer M value. (Valid 2 or 4)\n";
7181         case MYKONOS_ERR_DESER_INV_L_PARM:
7182             return "Invalid deserializer L value. (Valid 1,2,4)\n";
7183         case MYKONOS_ERR_DESER_INV_HSCLK_PARM:
7184             return "Invalid HSCLK in setupDeserializer()\n";
7185         case MYKONOS_ERR_DESER_INV_LANERATE_PARM:
7186             return "Invalid deserializer lane rate\n";
7187         case MYKONOS_ERR_DESER_INV_LANEEN_PARM:
7188             return "Invalid number of deserializer lanes enabled\n";
7189         case MYKONOS_ERR_DESER_INV_EQ_PARM:
7190             return "Invalid deserializer EQ setting";
7191         case MYKONOS_ERR_DESER_INV_LANEPN_PARM:
7192             return "Invalid deserializer invert Lane PN setting\n";
7193         case MYKONOS_ERR_FRAMER_INV_M_PARM:
7194             return "Invalid Rx framer M setting\n";
7195         case MYKONOS_ERR_FRAMER_INV_BANKID_PARM:
7196             return "Invalid Rx framer Bank ID\n";
7197         case MYKONOS_ERR_FRAMER_INV_LANEID_PARM:
7198             return "Invalid Rx framer Lane ID\n";
7199         case MYKONOS_ERR_FRAMER_INV_K_OFFSET_PARAM:
7200             return "Invalid Rx framer LMFC offset\n";
7201         case MYKONOS_ERR_FRAMER_INV_REAL_IF_DATA_PARM:
7202             return "Invalid Rx framer Real IF setting\n";
7203         case MYKONOS_ERR_OBSRX_FRAMER_INV_M_PARM:
7204             return "Invalid ObsRx Framer M value\n";
7205         case MYKONOS_ERR_OBSRX_FRAMER_INV_BANKID_PARM:
7206             return "Invalid ObsRx Framer Bank ID\n";
7207         case MYKONOS_ERR_OBSRX_FRAMER_INV_LANEID_PARM:
7208             return "Invalid ObsRx framer Lane ID\n";
7209         case MYKONOS_ERR_OBSRX_FRAMER_INV_K_OFFSET_PARAM:
7210             return "Invalid ObsRx framer LMFC offset\n";
7211         case MYKONOS_ERR_OBSRX_FRAMER_INV_REAL_IF_DATA_PARM:
7212             return "Invalid ObsRx framer Real IF setting, M must =1\n";
7213         case MYKONOS_ERR_DEFRAMER_INV_M_PARM:
7214             return "Invalid Deframer M setting\n";
7215         case MYKONOS_ERR_DEFRAMER_INV_BANKID_PARM:
7216             return "Invalid Deframer Bank ID\n";
7217         case MYKONOS_ERR_ERR_DEFRAMER_INV_LANEID_PARM:
7218             return "Invalid Deframer Lane ID\n";
7219         case MYKONOS_ERR_DEFRAMER_INV_K_OFFSET_PARAM:
7220             return "Invalid Deframer LMFC offset";
7221         case MYKONOS_ERR_DEFRAMER_INV_K_PARAM:
7222             return "Invalid Deframer K setting\n";
7223         case MYKONOS_ERR_DEFRAMER_INV_FK_PARAM:
7224             return "Invalid Deframer F*K value\n";
7225         case MYKONOS_ERR_RX_FRAMER_INV_PRBS_POLYORDER_PARAM:
7226             return "Invalid polyOrder parameter in enableRxFramerPrbs()\n";
7227         case MYKONOS_ERR_OBSRX_FRAMER_INV_PRBS_POLYORDER_PARAM:
7228             return "Invalid polyOrder parameter in enableObsRxFramerPrbs()\n";
7229         case MYKONOS_ERR_DEFRAMER_INV_PRBS_ENABLE_PARAM:
7230             return "Invalid enable parameter value in enableDeframerPrbsChecker()\n";
7231         case MYKONOS_ERR_DEFRAMER_INV_PRBS_POLYORDER_PARAM:
7232             return "Invalid polyOrder parameter in enableDeframerPrbsChecker()\n";
7233         case MYKONOS_ERR_DEFRAMER_INV_PRBS_CNTR_SEL_PARAM:
7234             return "Invalid lane counter select in readDeframerPrbsCounters()\n";
7235         case MYKONOS_ERR_INITARM_INV_DATARATE_PARM:
7236             return 0;
7237         case MYKONOS_ERR_INITARM_INV_VCODIV:
7238             return "Invalid ARM VCO divider\n";
7239         case MYKONOS_ERR_INITARM_INV_REGCLK:
7240             return "Invalid ARM SPI register clock rate\n";
7241         case MYKONOS_ERR_INITARM_INV_ARMCLK_PARAM:
7242             return "Invalid ARM clock rate\n";
7243         case MYKONOS_ERR_LOADHEX_INV_CHARCOUNT:
7244             return "LoadHex() char count = 0\n";
7245         case MYKONOS_ERR_LOADHEX_INVALID_FIRSTCHAR:
7246             return "LoadHex() First char is not :\n";
7247         case MYKONOS_ERR_LOADHEX_INVALID_CHKSUM:
7248             return "LoadHex() line checksum is invalid\n";
7249         case MYKONOS_ERR_LOADBIN_INVALID_BYTECOUNT:
7250             return "Invalid byte count passed to function MYKONOS_loadArmFromBinary()";
7251         case MYKONOS_ERR_LOADARMCON_INVALID_BYTECOUNT:
7252             return "Invalid byte count passed to function MYKONOS_loadArmConcurrent()";
7253         case MYKONOS_ERR_ARM_INVALID_BUILDCHKSUM:
7254             return "Verify ARM checksum failed\n";
7255         case MYKONOS_ERR_READARMMEM_INV_ADDR_PARM:
7256             return "ReadArmMem() was given an invalid memory address\n";
7257         case MYKONOS_ERR_WRITEARMMEM_INV_ADDR_PARM:
7258             return "WriteArmMem() was given an invalid memory address\n";
7259         case MYKONOS_ERR_ARM_INV_ADDR_PARM:
7260             return "Invalid memory address in MYKONOS_loadArmConcurrent()";
7261         case MYKONOS_ERR_ARMCMD_INV_OPCODE_PARM:
7262             return "Invalid ARM opcode given to sendArmCommand()\n";
7263         case MYKONOS_ERR_ARMCMD_INV_NUMBYTES_PARM:
7264             return "Invalid number of extended data in sendArmCommand()\n";
7265         case MYKONOS_ERR_ARMCMDSTATUS_INV_OPCODE_PARM:
7266             return "Invalid opcode given to waitArmCmdStatus()\n";
7267         case MYKONOS_ERR_CHECKDEVSTRUCT_NULLDEVPOINTER:
7268             return "Pointer to Mykonos device data structure is NULL\n";
7269         case MYKONOS_ERR_CHECKDEVSTRUCT_SPI:
7270             return "Invalid spiSettings pointer in device data structure\n";
7271         case MYKONOS_ERR_CHECKDEVSTRUCT_RX:
7272             return "Invalid device->rx pointer in device data structure\n";
7273         case MYKONOS_ERR_CHECKDEVSTRUCT_RXSUB:
7274             return "Invalid pointer within device->rx data structure\n";
7275         case MYKONOS_ERR_CHECKDEVSTRUCT_RXFIR:
7276             return "Invalid RXFIR pointer in device data structure\n";
7277         case MYKONOS_ERR_CHECKDEVSTRUCT_TX:
7278             return "Invalid device->tx pointer in device data structure\n";
7279         case MYKONOS_ERR_CHECKDEVSTRUCT_TXSUB:
7280             return "Invalid pointer within device->tx data structure\n";
7281         case MYKONOS_ERR_CHECKDEVSTRUCT_TXFIR:
7282             return "Invalid TXFIR pointer in device data structure\n";
7283         case MYKONOS_ERR_CHECKDEVSTRUCT_OBSRX:
7284             return "Invalid device->obsRx pointer in device data structure\n";
7285         case MYKONOS_ERR_CHECKDEVSTRUCT_OBSRXSUB:
7286             return "Invalid pointer within device->obsRx data structure\n";
7287         case MYKONOS_ERR_CHECKDEVSTRUCT_SNIFFERFIR:
7288             return "Invalid Sniffer FIR pointer in device data structure\n";
7289         case MYKONOS_ERR_CHECKDEVSTRUCT_ORXFIR:
7290             return "Invalid ORX FIR pointer in device data structure\n";
7291         case MYKONOS_ERR_CHECKDEVSTRUCT_ORXGAINCTRL:
7292             return "Invalid Orx gain control pointer in device data structure\n";
7293         case MYKONOS_ERR_CHECKDEVSTRUCT_SNIFFERGAINCTRL:
7294             return "Invalid Sniffer gain control pointer in device data structure\n";
7295         case MYKONOS_ERR_CHECKDEVSTRUCT_OBSRXFRAMER:
7296             return "Invalid obsRx framer pointer in device data structure\n";
7297         case MYKONOS_ERR_INITSER_INV_PROFILE:
7298             return "Invalid RX profile within device data structure detected in MYKONOS_setupSerializers()\n";
7299         case MYKONOS_ERR_INITDES_INV_TXPROFILE:
7300             return "Invalid TX profile within device data structure detected in MYKONOS_setupDeserializers()\n";
7301         case MYKONOS_ERR_JESD204B_ILAS_MISMATCH:
7302             return "Mismatch detected in MYKONOS_jesd204bIlasCheck()\n";
7303         case MYKONOS_ERR_RXGAINTABLE_INV_CHANNEL:
7304             return "Invalid channel specified in MYKONOS_programRxGainTable()\n";
7305         case MYKONOS_ERR_RXGAINTABLE_INV_GAIN_INDEX_RANGE:
7306             return "Invalid numGainIndicesinTable greater than possible number of gain indices for channel. \n";
7307         case MYKONOS_ERR_WRITE_CFG_MEMORY_FAILED:
7308             return "Failed write to ARM memory in MYKONOS_writeArmProfile()\n";
7309         case MYKONOS_ERR_INV_RXFRAMER_PCLKDIV_PARM:
7310             return "Invalid PCLKDIV parameter detected in MYKONOS_setupSerializers()\n";
7311         case MYKONOS_ERR_RXFRAMER_INV_FK_PARAM:
7312             return "Invalid FK parameter detected in MYKONOS_setupJesd204bFramer()\n";
7313         case MYKONOS_ERR_OBSRXFRAMER_INV_FK_PARAM:
7314             return "Invalid FK paramter detected in MYKONOS_setupJesd204bObsRxFramer()\n";
7315         case MYKONOS_ERR_INV_OBSRXFRAMER_PCLKDIV_PARM:
7316             return "Invalid PCLKDIV paramter detected in MYKONOS_setupSerializers()\n";
7317         case MYKONOS_ERR_PU_OBSRXPATH_INV_LOSOURCE_PARAM:
7318             return "Invalid LO Source for OBSRX data path \n";
7319         case MYKONOS_ERR_ARM_RADIOON_FAILED:
7320             return "ARM command to move to radioOn state failed. \n";
7321         case MYKONOS_ERR_ARM_RADIOOFF_FAILED:
7322             return "ARM command to move to radioOff state failed. \n";
7323         case MYKONOS_ERR_INV_RX_GAIN_MODE_PARM:
7324             return "Invalid gain control mode detected in MYKONOS_setRxGainControlMode()\n";
7325         case MYKONOS_ERR_INV_ORX_GAIN_MODE_PARM:
7326             return "Invalid gain control mode detected in MYKONOS_setObsRxGainControlMode()\n";
7327         case MYKONOS_ERR_INV_AGC_RX_STRUCT_INIT:
7328             return "Invalid RX AGC structure detected at &device->rx->rxAgcCtrl in MYKONOS_setupRxAgc()\n";
7329         case MYKONOS_ERR_INV_AGC_RX_PEAK_WAIT_TIME_PARM:
7330             return "device->rx->rxAgcCtrl->agcPeakWaitTime out of range in MYKONOS_setupRxAgc()\n";
7331         case MYKONOS_ERR_INV_AGC_RX_GAIN_UPDATE_TIME_PARM:
7332             return "device->rx->rxAgcCtrl->agcGainUpdateTime_us out of range in MYKONOS_setupRxAgc()\n";
7333         case MYKONOS_ERR_INV_AGC_RX_APD_HIGH_THRESH_PARM:
7334             return "device->rx->rxAgcCtrl->apdHighThresh out of range in MYKONOS_setupRxAgc()\n";
7335         case MYKONOS_ERR_INV_AGC_RX_APD_LOW_THRESH_PARM:
7336             return "device->rx->rxAgcCtrl->apdLowThresh out of range in MYKONOS_setupRxAgc()\n";
7337         case MYKONOS_ERR_INV_AGC_RX_BLOCK_DET_DECAY_PARM:
7338             return "device->rx->rxAgcCtrl->apdDecay out of range in MYKONOS_setupRxAgc()\n";
7339         case MYKONOS_ERR_INV_AGC_RX_PEAK_STRUCT_INIT:
7340             return "Data structure for peakAgc not initialized when used in MYKONOS_setupRxAgc() \n";
7341         case MYKONOS_ERR_INV_AGC_RX_PWR_STRUCT_INIT:
7342             return "Data structure for powerAgc not initialized when used in MYKONOS_setupRxAgc() \n";
7343         case MYKONOS_ERR_INV_AGC_RX1_MAX_GAIN_INDEX:
7344             return "device->rx->rxAgcCtrl->agcRx1MaxGainIndex out of range in MYKONOS_setupRxAgc() \n";
7345         case MYKONOS_ERR_INV_AGC_RX1_MIN_GAIN_INDEX:
7346             return "device->rx->rxAgcCtrl->agcRx1MinGainIndex out of range in MYKONOS_setupRxAgc() \n";
7347         case MYKONOS_ERR_INV_AGC_RX2_MAX_GAIN_INDEX:
7348             return "device->rx->rxAgcCtrl->agcRx2MaxGainIndex out of range in MYKONOS_setupRxAgc() \n";
7349         case MYKONOS_ERR_INV_AGC_RX2_MIN_GAIN_INDEX:
7350             return "device->rx->rxAgcCtrl->agcRx2MinGainIndex out of range in MYKONOS_setupRxAgc() \n";
7351         case MYKONOS_ERR_INV_AGC_RX_SLOW_LOOP_SETTLING_DELAY:
7352             return "device->rx->rxAgcCtrl->agcSlowLoopSettlingDelay out of range in MYKONOS_setupRxAgc() \n";
7353         case MYKONOS_ERR_INV_AGC_PMD_MEAS_DURATION:
7354             return "device->rx->rxAgcCtrl->powerAgc->pmdMeasDuration out of range in MYKONOS_setupRxAgc() \n";
7355         case MYKONOS_ERR_INV_AGC_PMD_MEAS_CONFIG:
7356             return "device->rx->rxAgcCtrl->powerAgc->pmdMeasConfig out of range in MYKONOS_setupRxAgc() \n";
7357         case MYKONOS_ERR_INV_AGC_RX_LOW_THS_PREV_GAIN_INC:
7358             return "device->rx->rxAgcCtrl->agcLowThsPreventGainIncrease out of range in MYKONOS_setupRxAgc() \n";
7359         case MYKONOS_ERR_INV_AGC_RX_PEAK_THRESH_MODE:
7360             return "device->rx->rxAgcCtrl->agcPeakThresholdMode out of range in MYKONOS_setupRxAgc() \n";
7361         case MYKONOS_ERR_INV_AGC_RX_RESET_ON_RX_ENABLE:
7362             return "device->rx->rxAgcCtrl->agcResetOnRxEnable out of range in MYKONOS_setupRxAgc() \n";
7363         case MYKONOS_ERR_INV_AGC_RX_ENABLE_SYNC_PULSE_GAIN_COUNTER:
7364             return "device->rx->rxAgcCtrl->agcEnableSyncPulseForGainCounter out of range in MYKONOS_setupRxAgc() \n";
7365         case MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_HIGH_THRESH:
7366             return "device->rx->rxAgcCtrl->powerAgc->pmdLowerHighThresh out of range in MYKONOS_setupRxAgc() \n";
7367         case MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_LOW_THRESH:
7368             return "device->rx->rxAgcCtrl->powerAgc->pmdUpperLowThresh out of range in MYKONOS_setupRxAgc() \n";
7369         case MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_LOW_THRESH:
7370             return "device->rx->rxAgcCtrl->powerAgc->pmdLowerLowThresh out of range in MYKONOS_setupRxAgc() \n";
7371         case MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_HIGH_THRESH:
7372             return "device->rx->rxAgcCtrl->powerAgc->pmdUpperHighThresh out of range in MYKONOS_setupRxAgc() \n";
7373         case MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_HIGH_GAIN_STEP:
7374             return "device->rx->rxAgcCtrl->powerAgc->pmdUpperHighGainStepAttack out of range in MYKONOS_setupRxAgc() \n";
7375         case MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_LOW_GAIN_STEP:
7376             return "device->rx->rxAgcCtrl->powerAgc->pmdLowerLowGainStepRecovery out of range in MYKONOS_setupRxAgc() \n";
7377         case MYKONOS_ERR_INV_AGC_RX_PMD_LOWER_HIGH_GAIN_STEP:
7378             return "device->rx->rxAgcCtrl->powerAgc->pmdLowerHighGainStepRecovery out of range in MYKONOS_setupRxAgc() \n";
7379         case MYKONOS_ERR_INV_AGC_RX_PMD_UPPER_LOW_GAIN_STEP:
7380             return "device->rx->rxAgcCtrl->powerAgc->pmdUpperLowGainStepAttack out of range in MYKONOS_setupRxAgc() \n";
7381         case MYKONOS_ERR_INV_AGC_RX_PKDET_FAST_ATTACK_VALUE:
7382             return "device->rx->rxAgcCtrl->peakAgc->apdFastAttack or hb2FastAttack out of range in MYKONOS_setupRxAgc() \n";
7383         case MYKONOS_ERR_INV_AGC_RX_HB2_HIGH_THRESH_PARM:
7384             return "device->rx->rxAgcCtrl->peakAgc->hb2HighThresh out of range in MYKONOS_setupRxAgc() \n";
7385         case MYKONOS_ERR_INV_AGC_RX_HB2_LOW_THRESH_PARM:
7386             return "device->rx->rxAgcCtrl->peakAgc->hb2LowThresh out of range in MYKONOS_setupRxAgc() \n";
7387         case MYKONOS_ERR_INV_AGC_RX_HB2_VERY_LOW_THRESH_PARM:
7388             return "device->rx->rxAgcCtrl->peakAgc->hb2VeryLowThresh out of range in MYKONOS_setupRxAgc() \n";
7389         case MYKONOS_ERR_INV_AGC_RX_APD_HIGH_GAIN_STEP_PARM:
7390             return "device->rx->rxAgcCtrl->peakAgc->apdHighGainStepAttack out of range in MYKONOS_setupRxAgc() \n";
7391         case MYKONOS_ERR_INV_AGC_RX_APD_LOW_GAIN_STEP_PARM:
7392             return "device->rx->rxAgcCtrl->peakAgc->apdLowGainStepRecovery out of range in MYKONOS_setupRxAgc() \n";
7393         case MYKONOS_ERR_INV_AGC_RX_HB2_HIGH_GAIN_STEP_PARM:
7394             return "device->rx->rxAgcCtrl->peakAgc->hb2HighGainStepAttack out of range in MYKONOS_setupRxAgc() \n";
7395         case MYKONOS_ERR_INV_AGC_RX_HB2_LOW_GAIN_STEP_PARM:
7396             return "device->rx->rxAgcCtrl->peakAgc->hb2LowGainStepRecovery out of range in MYKONOS_setupRxAgc() \n";
7397         case MYKONOS_ERR_INV_AGC_RX_HB2_VERY_LOW_GAIN_STEP_PARM:
7398             return "device->rx->rxAgcCtrl->peakAgc->hb2VeryLowGainStepRecovery out of range in MYKONOS_setupRxAgc() \n";
7399         case MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_ENABLE:
7400             return "device->rx->rxAgcCtrl->peakAgc->hb2OverloadEnable out of range in MYKONOS_setupRxAgc() \n";
7401         case MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_THRESH_CNT:
7402             return "device->rx->rxAgcCtrl->peakAgc->hb2OverloadThreshCnt out of range in MYKONOS_setupRxAgc() \n";
7403         case MYKONOS_ERR_INV_AGC_RX_HB2_OVLD_DUR_CNT:
7404             return "device->rx->rxAgcCtrl->peakAgc->hb2OverloadDurationCnt out of range in MYKONOS_setupRxAgc() \n";
7405         case MYKONOS_ERR_INV_AGC_OBSRX_STRUCT_INIT:
7406             return "Invalid OBSRX AGC structure detected at &device->obsRx->orxAgcCtrl in MYKONOS_setupObsRxAgc()\n";
7407         case MYKONOS_ERR_INV_AGC_OBSRX_PEAK_STRUCT_INIT:
7408             return "Data structure for obsRx->orxAgcCtrl->peakAgc not initialized when used in MYKONOS_setupObsRxAgc() \n";
7409         case MYKONOS_ERR_INV_AGC_OBSRX_PWR_STRUCT_INIT:
7410             return "Data structure for obsRx->orxAgcCtrl->powerAgc not initialized when used in MYKONOS_setupObsRxAgc() \n";
7411         case MYKONOS_ERR_INV_AGC_OBSRX_MAX_GAIN_INDEX:
7412             return "device->obsRx->orxAgcCtrl->agcObsRxMaxGainIndex out of range in  MYKONOS_setupObsRxAgc() \n";
7413         case MYKONOS_ERR_INV_AGC_OBSRX_MIN_GAIN_INDEX:
7414             return "device->obsRx->orxAgcCtrl->agcObsRxMinGainIndex out of range in MYKONOS_setupObsRxAgc() \n";
7415         case MYKONOS_ERR_INV_AGC_OBSRX_SELECT:
7416             return "device->obsRx->orxAgcCtrl->agcObsRxSelect out of range in MYKONOS_setupObsRxAgc() \n";
7417         case MYKONOS_ERR_INV_AGC_OBSRX_GAIN_UPDATE_TIME_PARM:
7418             return "device->obsRx->orxAgcCtrl->agcGainUpdateTime_us out of range in MYKONOS_setupObsRxAgc()\n";
7419         case MYKONOS_ERR_INV_AGC_OBSRX_PEAK_WAIT_TIME_PARM:
7420             return "device->obsRx->orxAgcCtrl->agcPeakWaitTime out of range in MYKONOS_setupObsRxAgc()\n";
7421         case MYKONOS_ERR_INV_AGC_OBSRX_SLOW_LOOP_SETTLING_DELAY:
7422             return "device->obsRx->orxAgcCtrl->agcSlowLoopSettlingDelay out of range in MYKONOS_setupObsRxAgc() \n";
7423         case MYKONOS_ERR_INV_AGC_OBSRX_PMD_MEAS_DURATION:
7424             return "device->obsRx->orxAgcCtrl->powerAgc->pmdMeasDuration out of range in MYKONOS_setupObsRxAgc() \n";
7425         case MYKONOS_ERR_INV_AGC_OBSRX_PMD_MEAS_CONFIG:
7426             return "device->obsRx->orxAgcCtrl->powerAgc->pmdMeasConfig out of range in MYKONOS_setupObsRxAgc() \n";
7427         case MYKONOS_ERR_INV_AGC_OBSRX_LOW_THS_PREV_GAIN_INC:
7428             return "device->obsRx->orxAgcCtrl->agcLowThsPreventGainIncrease out of range in MYKONOS_setupObsRxAgc() \n";
7429         case MYKONOS_ERR_INV_AGC_OBSRX_PEAK_THRESH_MODE:
7430             return "device->obsRx->orxAgcCtrl->agcPeakThresholdMode out of range in MYKONOS_setupObsRxAgc() \n";
7431         case MYKONOS_ERR_INV_AGC_OBSRX_RESET_ON_RX_ENABLE:
7432             return "device->obsRx->orxAgcCtrl->agcResetOnRxEnable out of range in MYKONOS_setupObsRxAgc() \n";
7433         case MYKONOS_ERR_INV_AGC_OBSRX_ENABLE_SYNC_PULSE_GAIN_COUNTER:
7434             return "device->obsRx->orxAgcCtrl->agcEnableSyncPulseForGainCounter out of range in MYKONOS_setupObsRxAgc() \n";
7435         case MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_HIGH_THRESH:
7436             return "device->obsRx->orxAgcCtrl->powerAgc->pmdLowerHighThresh out of range in MYKONOS_setupObsRxAgc() \n";
7437         case MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_LOW_THRESH:
7438             return "device->obsRx->orxAgcCtrl->powerAgc->pmdUpperLowThresh out of range in MYKONOS_setupObsRxAgc() \n";
7439         case MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_LOW_THRESH:
7440             return "device->obsRx->orxAgcCtrl->powerAgc->pmdLowerLowThresh out of range in MYKONOS_setupObsRxAgc() \n";
7441         case MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_HIGH_THRESH:
7442             return "device->obsRx->orxAgcCtrl->powerAgc->pmdUpperHighThresh out of range in MYKONOS_setupObsRxAgc() \n";
7443         case MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_HIGH_GAIN_STEP:
7444             return "device->obsRx->orxAgcCtrl->powerAgc->pmdUpperHighGainStepAttack out of range in MYKONOS_setupObsRxAgc() \n";
7445         case MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_LOW_GAIN_STEP:
7446             return "device->obsRx->orxAgcCtrl->powerAgc->pmdLowerLowGainStepRecovery out of range in MYKONOS_setupObsRxAgc() \n";
7447         case MYKONOS_ERR_INV_AGC_OBSRX_PMD_UPPER_LOW_GAIN_STEP:
7448             return "device->obsRx->orxAgcCtrl->powerAgc->pmdUpperLowGainStepAttack out of range in MYKONOS_setupObsRxAgc() \n";
7449         case MYKONOS_ERR_INV_AGC_OBSRX_PKDET_FAST_ATTACK_VALUE:
7450             return "device->obsRx->orxAgcCtrl->peakAgc->apdFastAttack or hb2FastAttack out of range in MYKONOS_setupObsRxAgc() \n";
7451         case MYKONOS_ERR_INV_AGC_OBSRX_APD_HIGH_THRESH_PARM:
7452             return "device->obsRx->orxAgcCtrl->apdHighThresh out of range in MYKONOS_setupObsRxAgc()\n";
7453         case MYKONOS_ERR_INV_AGC_OBSRX_APD_LOW_THRESH_PARM:
7454             return "device->obsRx->orxAgcCtrl->apdLowThresh out of range in MYKONOS_setupObsRxAgc()\n";
7455         case MYKONOS_ERR_INV_AGC_OBSRX_HB2_HIGH_THRESH_PARM:
7456             return "device->obsRx->orxAgcCtrl->peakAgc->hb2HighThresh out of range in MYKONOS_setupObsRxAgc() \n";
7457         case MYKONOS_ERR_INV_AGC_OBSRX_HB2_LOW_THRESH_PARM:
7458             return "device->obsRx->orxAgcCtrl->peakAgc->hb2LowThresh out of range in MYKONOS_setupObsRxAgc() \n";
7459         case MYKONOS_ERR_INV_AGC_OBSRX_HB2_VERY_LOW_THRESH_PARM:
7460             return "device->obsRx->orxAgcCtrl->peakAgc->hb2VeryLowThresh out of range in MYKONOS_setupObsRxAgc() \n";
7461         case MYKONOS_ERR_INV_AGC_OBSRX_APD_HIGH_GAIN_STEP_PARM:
7462             return "device->obsRx->orxAgcCtrl->peakAgc->apdHighGainStepAttack out of range in MYKONOS_setupObsRxAgc() \n";
7463         case MYKONOS_ERR_INV_AGC_OBSRX_APD_LOW_GAIN_STEP_PARM:
7464             return "device->obsRx->orxAgcCtrl->peakAgc->apdLowGainStepRecovery out of range in MYKONOS_setupObsRxAgc() \n";
7465         case MYKONOS_ERR_INV_AGC_OBSRX_HB2_HIGH_GAIN_STEP_PARM:
7466             return "device->obsRx->orxAgcCtrl->peakAgc->hb2HighGainStepAttack out of range in MYKONOS_setupObsRxAgc() \n";
7467         case MYKONOS_ERR_INV_AGC_OBSRX_HB2_LOW_GAIN_STEP_PARM:
7468             return "device->obsRx->orxAgcCtrl->peakAgc->hb2LowGainStepRecovery out of range in MYKONOS_setupObsRxAgc() \n";
7469         case MYKONOS_ERR_INV_AGC_OBSRX_HB2_VERY_LOW_GAIN_STEP_PARM:
7470             return "device->obsRx->orxAgcCtrl->peakAgc->hb2VeryLowGainStepRecovery out of range in MYKONOS_setupObsRxAgc() \n";
7471         case MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_ENABLE:
7472             return "device->obsRx->orxAgcCtrl->peakAgc->hb2OverloadEnable out of range in MYKONOS_setupObsRxAgc() \n";
7473         case MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_DUR_CNT:
7474             return "device->obsRx->orxAgcCtrl->peakAgc->hb2OverloadDurationCnt out of range in MYKONOS_setupObsRxAgc() \n";
7475         case MYKONOS_ERR_INV_AGC_OBSRX_HB2_OVLD_THRESH_CNT:
7476             return "device->obsRx->orxAgcCtrl->peakAgc->hb2OverloadThresholdCnt out of range in MYKONOS_setupObsRxAgc() \n";
7477         case MYKONOS_ERR_INV_AGC_OBSRX_PMD_LOWER_HIGH_GAIN_STEP:
7478             return "device->obsRx->orxAgcCtrl->powerAgc->pmdLowerHighGainStepRecovery out of range in MYKONOS_setupObsRxAgc() \n";
7479         case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_CALPLL_LOCK:
7480             return "CAL PLL Lock event timed out in MYKONOS_waitForEvent()\n";
7481         case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_CLKPLLCP:
7482             return "Clock PLL Charge Pump Cal event timed out in MYKONOS_waitForEvent()\n";
7483         case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_CLKPLL_LOCK:
7484             return "Clock PLL Lock event timed out in MYKONOS_waitForEvent()\n";
7485         case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RXPLLCP:
7486             return "RX PLL Charge Pump Cal event timed out in MYKONOS_waitForEvent()\n";
7487         case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RXPLL_LOCK:
7488             return "RX PLL Lock event timed out in MYKONOS_waitForEvent()\n";
7489         case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_TXPLLCP:
7490             return "TX PLL Charge Pump Cal event timed out in MYKONOS_waitForEvent()\n";
7491         case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_TXPLL_LOCK:
7492             return "TX PLL Lock event timed out in MYKONOS_waitForEvent()\n";
7493         case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_SNIFFPLLCP:
7494             return "Sniffer PLL Charge Pump Cal event timed out in MYKONOS_waitForEvent()\n";
7495         case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_SNIFFPLL_LOCK:
7496             return "Sniffer PLL Lock event timed out in MYKONOS_waitForEvent()\n";
7497         case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RXBBFCALDONE:
7498             return "RX Baseband Filter Cal event timed out in MYKONOS_waitForEvent()\n";
7499         case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_TXBBFCALDONE:
7500             return "TX Baseband Filter Cal timed out in MYKONOS_waitForEvent()\n";
7501         case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RFDCCALDONE:
7502             return "RF DC Offset Cal event timed out in MYKONOS_waitForEvent()\n";
7503         case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_ADCTUNECALDONE:
7504             return "ADC Tuner Cal event timed out in MYKONOS_waitForEvent()\n";
7505         case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RX1ADCPROFILE:
7506             return "Rx1 ADC Profile Loading event timed out in MYKONOS_waitForEvent()\n";
7507         case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RX2ADCPROFILE:
7508             return "Rx2 ADC Profile Loading event timed out in MYKONOS_waitForEvent()\n";
7509         case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_ORXADCPROFILE:
7510             return "ObsRx ADC Profile Loading event timed out in MYKONOS_waitForEvent()\n";
7511         case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_RCALDONE:
7512             return "Resistor Cal event timed out in MYKONOS_waitForEvent()\n";
7513         case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_ARMBUSY:
7514             return "ARM Busy event timed out in MYKONOS_waitForEvent()\n";
7515         case MYKONOS_ERR_WAITFOREVENT_TIMEDOUT_INITARMDONE:
7516             return "Initialize ARM event timed out in MYKONOS_waitForEvent()\n";
7517         case MYKONOS_ERR_TIMEDOUT_ARMMAILBOXBUSY:
7518             return "ARM Mailbox Busy. Command not executed in MYKONOS_sendArmCommand()\n";
7519         case MYKONOS_ERR_PU_OBSRXPATH_ARMERROR:
7520             return "ARM Command Error in MYKONOS_setObsRxPathSource()\n";
7521         case MYKONOS_ERR_EN_TRACKING_CALS_ARMSTATE_ERROR:
7522             return "Device not in radioOff/IDLE state. Error in MYKONOS_enableTrackingCals()\n";
7523         case MYKONOS_ERR_SET_RADIOCTRL_PINS_ARMERROR:
7524             return "ARM command Error in MYKONOS_setRadioControlPinMode()\n";
7525         case MYKONOS_ERR_EN_TRACKING_CALS_ARMERROR:
7526             return "ARM Command Error in MYKONOS_enableTrackingCals()\n";
7527         case MYKONOS_ERR_SETRFPLL_ARMERROR:
7528             return "ARM Command Error in MYKONOS_setRfPllFrequency()\n";
7529         case MYKONOS_ERR_INIT_INV_TXINPUTHB_PARM:
7530             return "device->tx->txProfile->txInputHbInterpolation out of range in MYKONOS_initialize(): valid = 1,2 or 4\n";
7531         case MYKONOS_ERR_LOAD_ADCPROFILE_INV_VCODIV:
7532             return "device->clocks->clkPllVcoDiv value not supported in MYKONOS_loadAdcProfiles\n";
7533         case MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_RXREQUIRED:
7534             return "Custom RX ADC Profile required\n";
7535         case MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_ORXREQUIRED:
7536             return "Custom ORX ADC Profile required\n";
7537         case MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_SNRXREQUIRED:
7538             return "Custom SNRX ADC Profile required\n";
7539         case MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_LBREQUIRED:
7540             return "Custom Loopback ADC profile required\n";
7541         case MYKONOS_ERR_LOAD_LBADCPROFILE_ARMMEM_FAILED:
7542             return "WriteArmMemory call failed while writing the Loopback ADC profile into ARM memory\n";
7543         case MYKONOS_ERR_LOAD_SNRXADCPROFILE_ARMMEM_FAILED:
7544             return "WriteArmMemory call failed while writing the Sniffer ADC profile into ARM memory\n";
7545         case MYKONOS_ERR_LOAD_ORXADCPROFILE_ARMMEM_FAILED:
7546             return "WriteArmMemory call failed while writing the ObsRx ADC profile into ARM memory\n";
7547         case MYKONOS_ERR_LOAD_RXADCPROFILE_ARMMEM_FAILED:
7548             return "WriteArmMemory call failed while writing the RX ADC profile into ARM memory\n";
7549         case MYKONOS_ERR_LOAD_ADCPROFILE_SNRX_ADCDIV_ZERO:
7550             return "SnRx profile has invalid ADC divider of 0, causing a divide by zero\n";
7551         case MYKONOS_ERR_LOAD_ADCPROFILE_ORXADCDIV_ZERO:
7552             return "ORx profile has invalid ADC divider of 0, causing a divide by zero\n";
7553         case MYKONOS_ERR_LOAD_ADCPROFILE_RXADCDIV_ZERO:
7554             return "Rx profile has invalid ADC divider of 0, causing a divide by zero\n";
7555         case MYKONOS_ERR_LOAD_ADCPROFILE_MISSING_ORX_PROFILE:
7556             return "If Tx Profile is valid, a matching ORx profile must be provided to set ADC divider and digital filtering for loopback calibrations\n";
7557         case MYKONOS_ERR_SETUP_PA_PROT_INV_AVG_DURATION:
7558             return "Invalid setting for avgDuration in MYKONOS_setupPaProtection(...)\n";
7559         case MYKONOS_ERR_SETUP_PA_PROT_INV_ATTEN_STEP:
7560             return "Invalid setting for attenStepSize in MYKONOS_setupPaProtection(...)\n";
7561         case MYKONOS_ERR_SETUP_PA_PROT_INV_ATTEN_ENABLE:
7562             return "Invalid setting for txAttenControlEnable in MYKONOS_setupPaProtection(...)\n";
7563         case MYKONOS_ERR_SETUP_PA_PROT_INV_POWER_THRESH:
7564             return "Invalid setting for powerThreshold in MYKONOS_setupPaProtection(...)\n";
7565         case MYKONOS_ERR_SETUP_PA_PROT_INV_TX_CHANNEL:
7566             return "Invalid TX channel selected for MYKONOS_getDacPower(...)\n";
7567         case MYKONOS_ERR_GET_DAC_PWR_INV_POINTER:
7568             return "Cannot return DAC Power information (invalid pointer)\n";
7569         case MYKONOS_ERR_GET_PA_FLAG_STATUS_INV_POINTER:
7570             return "Cannot return PA Protection Flag Status information (invalid pointer)\n";
7571         case MYKONOS_ERR_GET_OBSRX_OVERLOADS_NULL_PARM:
7572             return "MYKONOS_getObsRxPathOverloads() has null *obsRxOverloads parameter\n";
7573         case MYKONOS_ERR_GET_RX1_OVERLOADS_NULL_PARM:
7574             return "MYKONOS_getRxPathOverloads() has null *rx1Overloads parameter\n";
7575         case MYKONOS_ERR_GET_RX2_OVERLOADS_NULL_PARM:
7576             return "MYKONOS_getRxPathOverloads() has null *rx2Overloads parameter\n";
7577         case MYKONOS_ERR_GETRADIOSTATE_NULL_PARAM:
7578             return "MYKONOS_getRadioState() has null *radioStatus parameter\n";
7579         case MYKONOS_ERR_ABORT_INITCALS_NULL_PARAM:
7580             return "MYKONOS_abortInitCals() has null *calsCompleted parameter\n";
7581         case MYKONOS_ERR_WAIT_INITCALS_ARMERROR:
7582             return "MYKONOS_waitInitCals() returned an ARM error\n";
7583         case MYKONOS_ERR_WAIT_INITCALS_NULL_PARAM:
7584             return "MYKONOS_waitInitCals() has one or more null parameters\n";
7585         case MYKONOS_ERR_CHECK_PLL_LOCK_NULL_PARM:
7586             return "MYKONOS_checkPllsLockStatus() has a null *pllLockStatus parameter\n";
7587         case MYKONOS_ERR_GET_TXFILTEROVRG_NULL_PARM:
7588             return "MYKONOS_getTxFilterOverRangeStatus() has a null *txFilterStatus parameter\n";
7589         case MYKONOS_ERR_PROGRAM_RXGAIN_TABLE_NULL_PARM:
7590             return "MYKONOS_programRxGainTable() has a null *gainTablePtr parameter\n";
7591         case MYKONOS_ERR_PROGRAMFIR_NULL_PARM:
7592             return "MYKONOS_programFir() has a null *firFilter parameter\n";
7593         case MYKONOS_ERR_PROGRAMFIR_COEFS_NULL:
7594             return "MYKONOS_programFir() has a null coef array in *firFilter structure\n";
7595         case MYKONOS_ERR_READ_DEFRAMERSTATUS_NULL_PARAM:
7596             return "MYKONOS_readDeframerStatus() has a null *deframerStatus parameter\n";
7597         case MYKONOS_ERR_READ_DEFRAMERPRBS_NULL_PARAM:
7598             return "MYKONOS_readDeframerPrbscounters() has a null *prbsErrorCount parameter\n";
7599         case MYKONOS_ERR_READ_ORXFRAMERSTATUS_NULL_PARAM:
7600             return "MYKONOS_readOrxFramerStatus() has a null *obsFramerStatus parameter\n";
7601         case MYKONOS_ERR_READ_RXFRAMERSTATUS_NULL_PARAM:
7602             return "MYKONOS_readRxFramerStatus() has a null *framerStatus parameter\n";
7603         case MYKONOS_ERR_ARMCMDSTATUS_NULL_PARM:
7604             return "MYKONOS_waitArmCmdStatus() has a null *cmdStatByte parameter\n";
7605         case MYKONOS_ERR_READARMCMDSTATUS_NULL_PARM:
7606             return "MYKONOS_readArmCmdStatus() has one or more null pointer parameters\n";
7607         case MYKONOS_ERR_READARMCMDSTATUS_INV_OPCODE_PARM:
7608             return "MYKONOS_readArmCmdStatusByte() has an invalid opcode parameter\n";
7609         case MYKONOS_ERR_READARMCMDSTATUSBYTE_NULL_PARM:
7610             return "MYKONOS_readArmCmdStatusByte() has a null *cmdStatByte parameter\n";
7611         case MYKONOS_ERR_ARMCMD_NULL_PARM:
7612             return "MYKONOS_sendArmCommand() has a null *extendedData parameter\n";
7613         case MYKONOS_ERR_WRITEARMMEM_NULL_PARM:
7614             return "MYKONOS_writeArmMem() has a null *data parameter\n";
7615         case MYKONOS_ERR_LOADBIN_NULL_PARAM:
7616             return "MYKONOS_loadArmFromBinary() has a null *binary parameter\n";
7617         case MYKONOS_ERR_LOADARMCON_NULL_PARAM:
7618             return "MYKONOS_loadArmConcurrent() has a null *binary parameter\n";
7619         case MYKONOS_ERR_GETTX1ATTEN_NULL_PARM:
7620             return "MYKONOS_getTx1Attenuation() has NULL tx1Attenuation_mdB parameter\n";
7621         case MYKONOS_ERR_GETTX2ATTEN_NULL_PARM:
7622             return "MYKONOS_getTx2Attenuation() has NULL tx2Attenuation_mdB parameter\n";
7623         case MYKONOS_ERR_ENFRAMERLINK_INV_LANESEN_PARM:
7624             return "Invalid serializer Lanes Enable parameter in Rx framer structure\n";
7625         case MYKONOS_ERR_ENOBSFRAMERLINK_INV_LANESEN_PARM:
7626             return "Invalid serializer Lanes Enable parameter in ObsRx framer structure\n";
7627         case MYKONOS_ERR_ENTXNCO_TXPROFILE_INVALID:
7628             return "Can not enable Tx NCO when Tx Profile is invalid\n";
7629         case MYKONOS_ERR_ENTXNCO_TX1_FREQ_INVALID:
7630             return "Invalid Tx1 NCO frequency\n";
7631         case MYKONOS_ERR_ENTXNCO_TX2_FREQ_INVALID:
7632             return "Invalid Tx2 NCO frequency\n";
7633         case MYKONOS_ERR_JESD204B_ILAS_MISMATCH_NULLPARAM:
7634             return "Function parameter has NULL pointer in MYKONOS_jesd204bIlasCheck()\n";
7635         case MYKONOS_ERR_GET_PLLFREQ_INV_REFCLKDIV:
7636             return "CLKPLL refclk divider was read back as an invalid setting in MYKONOS_getRfPllFrequency()\n";
7637         case MYKONOS_ERR_GET_PLLFREQ_INV_HSDIV:
7638             return "CLKPLL HSDIV divider was read back as an invalid setting in MYKONOS_getRfPllFrequency()\n";
7639         case MYKONOS_ERR_GET_PLLFREQ_INV_VCODIV:
7640             return "CLKPLL VCODIV divider was read back as an invalid setting in MYKONOS_getRfPllFrequency()\n";
7641         case MYKONOS_ERR_GET_RX1_DEC_POWER_NULL_PARM:
7642             return "MYKONOS_getRx1DecPower() has a null *rx1DecPower_mdBFS parameter\n";
7643         case MYKONOS_ERR_GET_RX1_DEC_POWER_NUM_SAMPLES:
7644             return "MYKONOS_getRx1DecPower() numSamples greater than agcGainUpdateCounter\n";
7645         case MYKONOS_ERR_GET_RX2_DEC_POWER_NULL_PARM:
7646             return "MYKONOS_getRx2DecPower() has a null *rx2DecPower_mdBFS parameter\n";
7647         case MYKONOS_ERR_GET_RX2_DEC_POWER_NUM_SAMPLES:
7648             return "MYKONOS_getRx2DecPower() numSamples greater than agcGainUpdateCounter\n";
7649         case MYKONOS_ERR_GET_OBSRX_DEC_POWER_NULL_PARM:
7650             return "MYKONOS_getObsRxDecPower() has a null *obsRxDecPower_mdBFS parameter\n";
7651         case MYKONOS_ERR_GET_OBSRX_DEC_POWER_NUM_SAMPLES:
7652             return "MYKONOS_getObsRxDecPower() numSamples greater than agcGainUpdateCounter\n";
7653         case MYKONOS_ERR_GETARMVER_NULL_PARM:
7654             return "MYKONOS_getArmVersion() has a NULL pointer in one of the function parameters\n";
7655         case MYKONOS_ERR_EN_DPDTRACKING_ARMSTATE_ERROR:
7656             return "ARM is not in the RadioOff state before MYKONOS_enableDpdTracking(), call MYKONOS_radioOff()\n";
7657         case MYKONOS_ERR_RESTDPDMOD_WRONGBUFFERSIZE:
7658             return "MYKONOS_restoreDpdModel() supplied DPD Model Data Buffer is incorrect size\n";
7659         case MYKONOS_ERR_RESTDPDMOD_ARMERRFLAG:
7660             return "The ARM reported a error while in MYKONOS_restoreDpdModel().\n";
7661         case MYKONOS_ERR_RESTDPDMOD_INVALID_TXCHANNEL:
7662             return "MYKONOS_restoreDpdModel() invalid txChannel specified\n";
7663         case MYKONOS_ERR_SAVDPDMOD_WRONGBUFFERSIZE:
7664             return "MYKONOS_saveDpdModel() supplied DPD Model Data Buffer is incorrect size\n";
7665         case MYKONOS_ERR_SAVDPDMOD_ARMSTATE:
7666             return "ARM is not in the RadioOff state before MYKONOS_saveDpdModel(), call MYKONOS_radioOff()\n";
7667         case MYKONOS_ERR_SAVDPDMOD_INVALID_TXCHANNEL:
7668             return "MYKONOS_saveDpdModel() invalid txChannel specified\n";
7669         case MYKONOS_ERR_EN_CLGCTRACKING_ARMSTATE_ERROR:
7670             return "ARM is not in the RadioOff state before MYKONOS_enableClgcTracking(), call MYKONOS_radioOff()\n";
7671         case MYKONOS_ERR_CFGDPD_TXORX_PROFILE_INV:
7672             return "Tx or ORx profile is not valid, both are necessary for DPD features in MYKONOS_configDpd()\n";
7673         case MYKONOS_ERR_CFGDPD_NULL_DPDCFGSTRUCT:
7674             return "device->tx->dpdConfig structure has NULL pointer in MYKONOS_configDpd()\n";
7675         case MYKONOS_ERR_WRITEARMCFG_ARMERRFLAG:
7676             return "The ARM reported a error while writing to an ARM config structure in MYKONOS_writeArmCfgStruct()\n";
7677         case MYKONOS_ERR_CFGDPD_INV_DPDDAMPING:
7678             return "ERROR: device->tx->dpdConfig->damping parameter is out of range (0-15)\n";
7679         case MYKONOS_ERR_CFGDPD_INV_DPDSAMPLES:
7680             return "ERROR: device->tx->dpdConfig->samples parameter is out of range (64 - 32768)\n";
7681         case MYKONOS_ERR_CFGDPD_INV_NUMWEIGHTS:
7682             return "ERROR: device->tx->dpdConfig->numWeights parameter is out of range (0-3)\n";
7683         case MYKONOS_ERR_CFGDPD_INV_DPDOUTLIERTHRESH:
7684             return "ERROR: device->tx->dpdConfig->outlierThreshold parameter is out of range\n";
7685         case MYKONOS_ERR_CFGDPD_INV_DPDPRIORWEIGHT:
7686             return "ERROR: device->tx->dpdConfig->modelPriorWeight parameter is out of range (Valid 0-32)\n";
7687         case MYKONOS_ERR_CFGCLGC_INV_DESIREDGAIN:
7688             return "ERROR: device->tx->clgcConfig->tx1DesiredGain or tx2DesiredGain parameter is out of range\n";
7689         case MYKONOS_ERR_CFGCLGC_INV_TXATTENLIMIT:
7690             return "ERROR: device->tx->clgcConfig->tx1AttenLimit or tx2AttenLimit parameter is out of range\n";
7691         case MYKONOS_ERR_CFGCLGC_INV_CLGC_CTRLRATIO:
7692             return "ERROR: device->tx->clgcConfig->tx1ControlRatio or tx2ControlRatio parameter is out of range\n";
7693         case MYKONOS_ERR_CFGDPD_INV_DPD_ADDDELAY:
7694             return "ERROR: device->tx->dpdConfig->additionalDelayOffset parameter is out of range\n";
7695         case MYKONOS_ERR_CFGDPD_INV_PNSEQLEVEL:
7696             return "ERROR: device->tx->dpdConfig->pathDelayPnSeqLevel parameter is out of range\n";
7697         case MYKONOS_ERR_CFGDPD_INV_MODELVERSION:
7698             return "ERROR: device->tx->dpdConfig->modelVersion parameter is out of range\n";
7699         case MYKONOS_ERR_READARMCFG_ARMERRFLAG:
7700             return "ERROR: MYKONOS_readArmConfig failed due to an ARM error\n";
7701         case MYKONOS_ERR_GETPENDTRKCALS_NULL_PARAM:
7702             return "MYKONOS_getPendingTrackingCals() has NULL function parameter\n";
7703         case MYKONOS_ERR_ARMCMDSTATUS_ARMERROR:
7704             return "MYKONOS_waitArmCmdStatus() exited due to ARM error for the desired ARM opcode\n";
7705         case MYKONOS_ERR_WAITARMCMDSTATUS_TIMEOUT:
7706             return "MYKONOS_waitArmCmdStatus() timed out waiting for the ARM to complete the requested command\n";
7707         case MYKONOS_ERR_PU_GETOBSRXPATH_ARMERROR:
7708             return "ARM returned an error while trying to get the ObsRx Path source in MYKONOS_getObsRxPathSource()\n";
7709         case MYKONOS_ERR_GETDPDCFG_NULL_DPDCFGSTRUCT:
7710             return "MYKONOS_getDpdConfig() could not complete due to a NULL pointer to device->tx->dpdConfig structure\n";
7711         case MYKONOS_ERR_GETDPDCFG_TXORX_PROFILE_INV:
7712             return "The Tx and ORx profiles must be valid for DPD related functions\n";
7713         case MYKONOS_ERR_GETDPDSTATUS_ARMERRFLAG:
7714             return "MYKONOS_getDpdStatus() reported an ARM error with the ARM Get command\n";
7715         case MYKONOS_ERR_GETDPDSTATUS_NULLPARAM:
7716             return "MYKONOS_getDpdStatus() has NULL pointer in the function parameter\n";
7717         case MYKONOS_ERR_SETDEFOBSRXPATH_NULL_OBSRX_STRUCT:
7718             return "Observation profile not valid, device->obsRx structure is NULL in MYKONOS_setDefaultObsRxPath()\n";
7719         case MYKONOS_ERR_GETCLGCSTATUS_NULLPARAM:
7720             return "MYKONOS_getClgcStatus() has NULL clgcStatus parameter\n";
7721         case MYKONOS_ERR_GETCLGCSTATUS_ARMERRFLAG:
7722             return "ARM reported an error with the ARM GET command during MYKONOS_getClgcStatus()\n";
7723         case MYKONOS_ERR_READ_DEFFIFODEPTH_NULL_PARAM:
7724             return "MYKONOS_getDeframerFifoDepth() function parameter fifoDepth is a NULL pointer\n";
7725         case MYKONOS_ERR_READ_DEFFIFODEPTH_LMFCCOUNT_NULL_PARAM:
7726             return "MYKONOS_getDeframerFifoDepth() function parameter readEnLmfcCount is a NULL pointer\n";
7727         case MYKONOS_ERR_GETDPDSTATUS_INV_CH:
7728             return "MYKONOS_getDpdStatus() txChannel parameter is not valid (TX1 and TX2 are the only valid options)\n";
7729         case MYKONOS_ERR_GETCLGCSTATUS_INV_CH:
7730             return "MYKONOS_getClgcStatus() txChannel parameter is not valid (TX1 and TX2 are the only valid options)\n";
7731         case MYKONOS_ERR_INIT_INV_TXINPUTHB_INV_RATE:
7732             return "Invalid Tx profile: When using Tx Input halfband, IQ rate must not exceed 160MSPS\n";
7733         case MYKONOS_ERR_INIT_INV_TXINPUTHB0_INV_RATE:
7734             return "Invalid Tx profile: When using Tx Input halfband 0, IQ rate must not exceed 80MSPS\n";
7735         case MYKONOS_ERR_RXFIR_TAPSEXCEEDED:
7736             return "Rx PFIR can not be clocked fast enough to handle the number of FIR coefficents provided\n";
7737         case MYKONOS_ERR_ORXFIR_TAPSEXCEEDED:
7738             return "ORx PFIR can not be clocked fast enough to handle the number of FIR coefficents provided\n";
7739         case MYKONOS_ERR_SNRXFIR_TAPSEXCEEDED:
7740             return "Sniffer Rx PFIR can not be clocked fast enough to handle the number of FIR coefficents provided\n";
7741         case MYKONOS_ERR_TXFIR_INV_NUMTAPS_PARM:
7742             return "Invalid number of Tx FIR coefficients\n";
7743         case MYKONOS_ERR_TXFIR_INV_NUMROWS:
7744             return "Invalid number of PFIR coefficient rows\n";
7745         case MYKONOS_ERR_TXFIR_TAPSEXCEEDED:
7746             return "Too many Tx PFIR taps for the IQ sample rate.  FIR processing clock can not run fast enough to handle the number of taps\n";
7747         case MYKONOS_ERR_GETINITCALSTATUS_NULL_PARAM:
7748             return "MYKONOS_getInitCalStatus() has a null pointer in parameter list\n";
7749         case MYKONOS_ERR_GETINITCALSTATUS_ARMERROR:
7750             return "MYKONOS_getInitCalStatus() returned an ARM error while getting the init cal status information";
7751         case MYKONOS_ERR_CFGCLGC_TXORX_PROFILE_INV:
7752             return "Tx and ObsRx profiles must be valid to use the CLGC feature in MYKONOS_configClgc()\n";
7753         case MYKONOS_ERR_CFGCLGC_NULL_CLGCCFGSTRUCT:
7754             return "CLGC config structure is NULL in device->tx->clgcConfig in MYKONOS_configClgc()\n";
7755         case MYKONOS_ERR_GETCLGCCFG_TXORX_PROFILE_INV:
7756             return "Could not read back CLGC status because Tx and ORx profiles are not valid\n";
7757         case MYKONOS_ERR_GETCLGCCFG_NULL_CFGSTRUCT:
7758             return "Could not read back CLGC status because return structure device->tx->clgcConfig pointer is NULL\n";
7759         case MYKONOS_ERR_CALCDIGCLK_NULLDEV_PARAM:
7760             return "device structure pointer is NULL in MYKONOS_calculateDigitalClocks()\n";
7761         case MYKONOS_ERR_CALCDIGCLK_NULL_CLKSTRUCT:
7762             return "device->clocks structure pointer is NULL in MYKONOS_calculateDigitalClocks()\n";
7763         case MYKONOS_ERR_NULL_DEVICE_PARAM:
7764             return "The device pointer in the calling function's parameter list is a NULL pointer\n";
7765         case MYKONOS_ERR_CALCDEVCLK_NULLPARAM:
7766             return "MYKONOS_calculateScaledDeviceClk_kHz() has a NULL pointer in one of the function parameters\n";
7767         case MYKONOS_ERR_CFGCLGC_INV_CLGC_ADDDELAY:
7768             return "CLGC Additional Delay parameter is out of range in MYKONOS_configClgc\n";
7769         case MYKONOS_ERR_CFGCLGC_INV_PNSEQLEVEL:
7770             return "CLGC PN Sequence level parameter is out of range in MYKONOS_configClgc\n";
7771         case MYKONOS_ERR_CFGVSWR_TXORX_PROFILE_INV:
7772             return "The Tx and ORx profiles must be valid to use the VSWR feature in MYKONOS_configVswr()\n";
7773         case MYKONOS_ERR_CFGVSWR_ARMSTATE_ERROR:
7774             return "ARM must be in radioOff state to configure the VSWR config parameters in MYKONOS_configVswr()\n";
7775         case MYKONOS_ERR_CFGVSWR_INV_3P3GPIOPIN:
7776             return "VSWR 3.3v GPIO pin selection is out of range (0-11) in MYKONOS_configVswr()\n";
7777         case MYKONOS_ERR_CFGVSWR_INV_PNSEQLEVEL:
7778             return "VSWR init PN sequence level is out of range in MYKONOS_configVswr()\n";
7779         case MYKONOS_ERR_CFGVSWR_INV_VSWR_ADDDELAY:
7780             return "VSWR additionalDelay member is out of range in MYKONOS_configVswr()\n";
7781         case MYKONOS_ERR_CFGVSWR_NULL_VSWRCFGSTRUCT:
7782             return "device->tx->vswrConfig pointer is null in MYKONOS_confgiVswr()\n";
7783         case MYKONOS_ERR_GETVSWRCFG_NULL_CFGSTRUCT:
7784             return "device->tx->vswrConfig pointer is null in MYKONOS_getVswrConfig()\n";
7785         case MYKONOS_ERR_GETVSWRCFG_TXORX_PROFILE_INV:
7786             return "Tx and ORx profiles must be valid in MYKONOS_getVswrConfig()\n";
7787         case MYKONOS_ERR_GETVSWRSTATUS_ARMERRFLAG:
7788             return "ARM returned an error while attempting to read the VSWR status structure\n";
7789         case MYKONOS_ERR_GETVSWRSTATUS_INV_CH:
7790             return "Invalid Tx channel parameter passed to MYKONOS_getVswrStatus()\n";
7791         case MYKONOS_ERR_GETVSWRSTATUS_NULLPARAM:
7792             return "vswrStatus function parameter is null in MYKONOS_getVswrStatus\n";
7793         case MYKONOS_ERR_SET_RX_MAX_GAIN_INDEX:
7794             return "Max gain index bigger than max gain index loaded table in MYKONOS_setRxAgcMinMaxGainIndex().\n";
7795         case MYKONOS_ERR_SET_RX_MIN_GAIN_INDEX:
7796             return "Min gain index lower than min gain index loaded table in MYKONOS_setRxAgcMinMaxGainIndex().\n";
7797         case MYKONOS_ERR_AGC_MIN_MAX_RX_CHANNEL:
7798             return "Wrong RX channel selected in MYKONOS_setRxAgcMinMaxGainIndex().\n";
7799         case MYKONOS_ERR_SET_ORX_MAX_GAIN_INDEX_CHANNEL:
7800             return "Wrong read back channel in MYKONOS_setObsRxAgcMinMaxGainIndex().\n";
7801         case MYKONOS_ERR_SET_ORX_MAX_GAIN_INDEX:
7802             return "Max gain index bigger than max gain index loaded table in MYKONOS_setObsRxAgcMinMaxGainIndex().\n";
7803         case MYKONOS_ERR_SET_ORX_MIN_GAIN_INDEX:
7804             return "Min gain index lower than min gain index loaded table in MYKONOS_setObsRxAgcMinMaxGainIndex().\n";
7805         case MYKONOS_ERR_AGC_MIN_MAX_ORX_CHANNEL:
7806             return "Wrong observation channel selected in MYKONOS_setObsRxAgcMinMaxGainIndex().\n";
7807         case MYKONOS_ERR_RX1_TEMP_GAIN_COMP_RANGE:
7808             return "The temp gain compensation is outside range (-3000mdB to 3000mdB) in MYKONOS_setRx1TempGainComp().\n";
7809         case MYKONOS_ERR_RX1_TEMP_GAIN_COMP_STEP:
7810             return "Not valid temp gain compensation, step size is 250mdB in MYKONOS_setRx1TempGainComp().\n";
7811         case MYKONOS_ERR_RX2_TEMP_GAIN_COMP_RANGE:
7812             return "The temp gain compensation is outside range (-3000mdB to 3000mdB) in MYKONOS_setRx2TempGainComp().\n";
7813         case MYKONOS_ERR_RX2_TEMP_GAIN_COMP_STEP:
7814             return "Not valid temp gain compensation, step size is 250mdB in MYKONOS_setRx2TempGainComp().\n";
7815         case MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_RANGE:
7816             return "The temp gain compensation is outside range (-3000mdB to 3000mdB) in MYKONOS_setObsRxTempGainComp().\n";
7817         case MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_STEP:
7818             return "Not valid temp gain compensation, step size is 250mdB in MYKONOS_setObsRxTempGainComp().\n";
7819         case MYKONOS_ERR_RX1_TEMP_GAIN_COMP_NULL:
7820             return "rx1TempCompGain_mdB pointer is null MYKONOS_getRx1TempGainComp().\n";
7821         case MYKONOS_ERR_RX2_TEMP_GAIN_COMP_NULL:
7822             return "rx2TempCompGain_mdB pointer is null MYKONOS_getRx2TempGainComp().\n";
7823         case MYKONOS_ERR_OBS_RX_TEMP_GAIN_COMP_NULL:
7824             return "obsRxTempCompGain_mdB pointer is null MYKONOS_getObsRxTempGainComp().\n";
7825         case MYKONOS_ERR_GETORXQECSTATUS_NULLPARAM:
7826             return "Function parameter mykonosOrxQecStatus_t is a NULL pointer in MYKONOS_getOrxQecStatus().\n";
7827         case MYKONOS_ERR_GETORXQECSTATUS_INV_CH:
7828             return "Channel selection not valid in MYKONOS_getOrxQecStatus().\n";
7829         case MYKONOS_ERR_GETORXQECSTATUS_ARMERRFLAG:
7830             return "ARM command error in MYKONOS_getOrxQecStatus().\n";
7831         case MYKONOS_ERR_GETRXQECSTATUS_NULLPARAM:
7832             return "Function parameter mykonosRxQecStatus_t is a NULL pointer in MYKONOS_getRxQecStatus().\n";
7833         case MYKONOS_ERR_GETRXQECSTATUS_INV_CH:
7834             return "Channel selection not valid in MYKONOS_getRxQecStatus().\n";
7835         case MYKONOS_ERR_GETRXQECSTATUS_ARMERRFLAG:
7836             return "ARM command error in MYKONOS_getRxQecStatus().\n";
7837         case MYKONOS_ERR_GETTXQECSTATUS_NULLPARAM:
7838             return "Function parameter mykonosTxQecStatus_t is a NULL pointer in MYKONOS_getRxQecStatus().\n";
7839         case MYKONOS_ERR_GETTXQECSTATUS_INV_CH:
7840             return "Channel selection not valid in MYKONOS_getTxQecStatus().\n";
7841         case MYKONOS_ERR_GETTXQECSTATUS_ARMERRFLAG:
7842             return "ARM command error in MYKONOS_getTxQecStatus().\n";
7843         case MYKONOS_ERR_GETTXLOLSTATUS_NULLPARAM:
7844             return "Function parameter mykonosTxLolStatus_t is a NULL pointer in MYKONOS_getTLolStatus().\n";
7845         case MYKONOS_ERR_GETTXLOLSTATUS_INV_CH:
7846             return "Channel selection not valid in MYKONOS_getTLolStatus().\n";
7847         case MYKONOS_ERR_GETTXLOLSTATUS_ARMERRFLAG:
7848             return "ARM command error in MYKONOS_getTLolStatus().\n";
7849         case MYKONOS_ERR_RESCHEDULE_TRACK_CAL_INV:
7850             return "Not valid calibration passed to MYKONOS_rescheduleTrackingCal().\n";
7851         case MYKONOS_ERR_RESCHEDULE_TRACK_ARMERRFLAG:
7852             return "ARM error in MYKONOS_rescheduleTrackingCal().\n";
7853         case MYKONOS_ERR_ARMSTATE_EXCEPTION:
7854             return "ARM system problem has been detected.\n";
7855         case MYKONOS_ERR_ARMSTATE_CAL_ERROR:
7856             return "ARM has detected an error in the tracking calibrations.\n";
7857         case MYKONOS_ERR_ARMSTATE_PROFILE_ERROR:
7858             return "ARM has detected an illegal profile.\n";
7859         case MYKONOS_ERR_WAITARMCSTATE_TIMEOUT:
7860             return "Timeout occurred in MYKONOS_checkArmState().\n";
7861         case MYKONOS_ERR_GET_API_VERSION_NULL_PARAM:
7862             return "Null parameter passed to the function MYKONOS_getApiVersion().\n";
7863         case MYKONOS_ERR_GETPRODUCTID_NULL_PARAM:
7864             return "Null parameter passed to the function MYKONOS_getProductId().\n";
7865         case MYKONOS_ERR_TXPROFILE_IQRATE:
7866             return "Tx Profile IQ rate out of range.\n";
7867         case MYKONOS_ERR_TXPROFILE_RFBW:
7868             return "Tx Profile RF bandwidth out of range.\n";
7869         case MYKONOS_ERR_TXPROFILE_FILTER_INTERPOLATION:
7870             return "Tx Filter interpolation not valid.\n";
7871         case MYKONOS_ERR_TXPROFILE_FIR_COEFS:
7872             return "Tx FIR filter not valid.\n";
7873         case MYKONOS_ERR_RXPROFILE_RXCHANNEL:
7874             return " Rx channel is not valid.\n";
7875         case MYKONOS_ERR_RXPROFILE_IQRATE:
7876             return "Receiver profile out of range IQ rate.\n";
7877         case MYKONOS_ERR_RXPROFILE_RFBW:
7878             return "Receiver profile out of range RF bandwidth.\n";
7879         case MYKONOS_ERR_RXPROFILE_FILTER_DECIMATION:
7880             return "Receiver profile not valid filter decimation setting.\n";
7881         case MYKONOS_ERR_RXPROFILE_FIR_COEFS:
7882             return "Receiver profile FIR filter not valid.\n";
7883         case MYKONOS_ERR_RXPROFILE_ADCDIV:
7884             return "Receiver profile not valid ADC divider.\n";
7885         case MYKONOS_ERR_PROFILES_HSDIGCLK:
7886             return "Profile combinations loaded are not valid.\n";
7887         case MYKONOS_ERR_RESET_TXLOL_INV_PARAM:
7888             return "Selected channel is not valid.\n";
7889         case MYKONOS_ERR_RESET_TXLOL_ARMERROR:
7890             return "ARM command error in MYKONOS_resetExtTxLolChannel().\n";
7891         case MYKONOS_ERR_SETSTATEALL_TRACK_CAL_INV:
7892             return "Not valid calibration mask passed for trackCals.\n";
7893         case MYKONOS_ERR_SETSTATEALL_TRACK_ARMERRFLAG:
7894             return "ARM error flag set.\n";
7895         case MYKONOS_ERR_GETSTATEALL_TRACK_ARMERRFLAG:
7896             return "ARM error flag set.\n";
7897         case MYKONOS_ERR_GETSTATEALL_TRACK_ARMERROR:
7898             return "ARM command error.\n";
7899         case MYKONOS_ERR_GETSTATEALL_TRACK_NULL_PARAM:
7900             return "Null parameter passed for trackCals.\n";
7901         case MYKONOS_ERR_SETSTATE_TRACK_CAL_INV:
7902             return "Not valid calibration passed.\n";
7903         case MYKONOS_ERR_SETSTATE_TRACK_ARMERRFLAG:
7904             return "ARM command error.\n";
7905         case MYKONOS_ERR_GETSTATE_TRACK_NULL_PARAM:
7906             return "Null parameter passed to trackCalState.\n";
7907         case MYKONOS_ERR_GETSTATE_TRACK_ARMERRFLAG:
7908             return "ARM command error flag set.\n";
7909         case MYKONOS_ERR_GETSTATE_TRACK_ARMERROR:
7910             return "ARM command error.\n";
7911         case MYKONOS_ERR_SETCLGCGAIN_INV_TXCHANNEL:
7912             return "Tx channel is not valid (Valid ENUM values: TX1 or TX2 only).\n";
7913         case MYKONOS_ERR_SETCLGCGAIN_TRACK_ARMERRFLAG:
7914             return "ARM command flag error set.\n";
7915         case MYKONOS_ERR_SETCLGCGAIN_INV_DESIREDGAIN:
7916             return "CLGC gain parameter is out of range, valid range is from -10000 to 10000.\n";
7917         case MYKONOS_ERR_SETDPDACT_INV_TXCHANNEL:
7918             return "Tx channel is not valid (Valid ENUM values: TX1, TX2 or TX1_TX2).\n";
7919         case MYKONOS_ERR_SETDPDACT_INV_STATE:
7920             return "Invalid Actuator state, valid states are 0-disable and 1-enable.\n";
7921         case MYKONOS_ERR_SETDPDACT_ARMERRFLAG:
7922             return "ARM command flag error set.\n";
7923         case MYKONOS_ERR_SETRFPLL_LF_PLLNAME:
7924         	return "Invalid pllName requested in MYKONOS_setRfPllLoopFilter()\n";
7925         case MYKONOS_ERR_SETRFPLL_LF_INV_STABILITY:
7926         	return "Invalid stability value requested in MYKONOS_setRfPllLoopFilter()\n";
7927         case MYKONOS_ERR_SETRFPLL_LF_ARMERROR:
7928         	return "ARM Command Error in MYKONOS_setRfPllLoopFilter()\n";
7929         case MYKONOS_ERR_SETRFPLL_LF_INV_TXRX_LOOPBANDWIDTH:
7930         	return "Invalid Tx/Rx value bandwith requested in MYKONOS_setRfPllLoopFilter()\n";
7931         case MYKONOS_ERR_SETRFPLL_LF_INV_SNF_LOOPBANDWIDTH:
7932         	return "Invalid Sniffer value bandwith in MYKONOS_setRfPllLoopFilter()\n";
7933         case MYKONOS_ERR_GETRFPLL_LF_INV_PLLNAME:
7934         	return "Invalid pllName requested in MYKONOS_getRfPllLoopFilter()\n";
7935         case MYKONOS_ERR_GETRFPLL_LF_ARMERROR:
7936         	return "ARM Command Error in MYKONOS_getRfPllLoopFilter()\n";
7937         case MYKONOS_ERR_GETRFPLL_LF_NULLPARAM:
7938         	return "NULL pointer in function parameter for MYKONOS_getRfPllLoopFilter()\n";
7939         case MYKONOS_ERR_SET_RF_DC_OFFSET_INV_MEASURECNT:
7940             return "Invalid value passed as parameter for measureCount to function MYKONOS_setRfDcOffsetCnt().\n";
7941         case MYKONOS_ERR_SET_RF_DC_OFFSET_MEASURECNT_MIN_LIMIT:
7942             return "The measureCount value passed to function MYKONOS_setRfDcOffsetCnt() is less than the minimum limit allowed.\n";
7943         case MYKONOS_ERR_DC_OFFSET_INV_CHAN:
7944             return "Invalid channel passed as parameter, for valid channel refer mykonosDcOffsetChannels_t enum.\n";
7945         case MYKONOS_ERR_GET_RF_DC_OFFSET_NULL_MEASURECNT:
7946             return "Null parameter passed for measureCount MYKONOS_getRfDcOffsetCnt().\n";
7947         case MYKONOS_ERR_SET_DIG_DC_OFFSET_INV_MSHIFT:
7948             return "Invalid MShift value passed as parameter to function MYKONOS_setDigDcOffsetMShift().\n";
7949         case MYKONOS_ERR_GET_DIG_DC_OFFSET_NULL_MSHIFT:
7950             return "MShift passed to the function MYKONOS_getDigDcOffsetMShift() is NULL.\n";
7951         case MYKONOS_ERR_DIG_DC_OFFSET_INV_ENABLE_MASK:
7952             return "Invalid enable mask passed to the function MYKONOS_setDigDcOffsetEn().\n";
7953         case MYKONOS_ERR_DIG_DC_OFFSET_NULL_ENABLE_MASK:
7954             return "Enable mask passed to the function MYKONOS_getDigDcOffsetEn() is NULL.\n";
7955         case MYKONOS_ERR_RESETDPD_WRONG_PARAM:
7956             return "reset parameter passed to function MYKONOS_resetDpd() is not valid, possible values are: MYK_DPD_RESET_FULL, MYK_DPD_RESET_PRIOR or MYK_DPD_RESET_CORRELATOR \n";
7957         case MYKONOS_ERR_RESETDPD_ARMERRFLAG:
7958             return "ARM command flag error set in function MYKONOS_resetDpd().\n";
7959         case  MYKONOS_ERR_CFGCLGC_INV_THRESHOLD:
7960             return "tx1RelThreshold or tx2RelThreshold parameter is out of range in function MYKONOS_configClgc().\n";
7961         case MYKONOS_ERR_RESETDPD_INV_TXCHANNEL:
7962             return "Tx channel is not valid (Valid ENUM values: TX1, TX2 or TX1_TX2 in function MYKONOS_resetDpd().\n";
7963         case MYKONOS_ERR_SET_PATH_DELAY_NULL_PARAM:
7964             return "pathDelay structure is null in function MYKONOS_setPathDelay().\n";
7965         case MYKONOS_ERR_SET_PATH_DELAY_PARAM_OUT_OF_RANGE:
7966             return "path delay not valid range in MYKONOS_setPathDelay(), valid ranges are from 0 to 4095 at 1/16 sample resolution of ORx sample rate.\n";
7967         case MYKONOS_ERR_GET_PATH_DELAY_NULL_PARAM:
7968             return "pathDelay structure is null in function MYKONOS_getPathDelay().\n";
7969         case MYKONOS_ERR_GET_PATH_DELAY_INVALID_SELECTION:
7970             return "invalid selection for getting the path delay, valid selections are given by mykonosPathDelaySel_t.\n";
7971         case MYKONOS_ERR_GET_PATH_DELAY_ARMERRFLAG:
7972             return "Arm error while reading path delay for the selected calibration status.\n";
7973         case MYKONOS_ERR_GETDPD_ERROR_CNT_NULLPARAM:
7974             return "dpdErrCnt is null in function MYKONOS_getDpdErrorCounters().\n";
7975         case MYKONOS_ERR_GETDPD_ERROR_CNT_INV_CH:
7976             return "invalid selection for getting the error counters tx channel in MYKONOS_getDpdErrorCounters().\n";
7977         case MYKONOS_ERR_GETDPD_ERROR_CNT_ARMERRFLAG:
7978             return "Arm error while reading the error counters for the DPD status MYKONOS_getDpdErrorCounters().\n";
7979         case MYKONOS_ERR_SETDPDACT_NULL_ACTSTRUCT:
7980             return "Passed structure is null in MYKONOS_setDpdBypassConfig().\n";
7981         case MYKONOS_ERR_SETDPDACT_INV_ACTMODE:
7982             return "Invalid mode passed detected in MYKONOS_setDpdBypassConfig(), actConfig->bypassActuatorMode for valid modes mykonosDpdResetMode_t.\n";
7983         case MYKONOS_ERR_SETDPDACT_INV_LEVEL:
7984             return "Passed actConfig->bypassActuatorLevel outside the range in MYKONOS_setDpdBypassConfig().\n";
7985         case MYKONOS_ERR_GETDPDACT_NULL_ACTSTRUCT:
7986             return "Passed structure is null in MYKONOS_getDpdBypassConfig().\n";
7987         case MYKONOS_ERR_SETDPDACTCHECK_NULL_ACTSTRUCT:
7988             return "Passed structure is null in MYKONOS_setDpdActuatorCheck().\n";
7989         case MYKONOS_ERR_SETDPDACTCHECK_INV_ACTMODE:
7990             return "Invalid mode detected in MYKONOS_setDpdActuatorCheck(), actCheck->actuatorGainCheckMode for valid modes mykonosDpdResetMode_t.\n";
7991         case MYKONOS_ERR_SETDPDACTCHECK_INV_LEVEL:
7992             return "Passed actCheck->actuatorGainCheckLevel outside the range in MYKONOS_setDpdActuatorCheck().\n";
7993         case MYKONOS_ERR_GETDPDACTCHECK_NULL_ACTSTRUCT:
7994             return "Passed structure is null in MYKONOS_getDpdActuatorCheck().\n";
7995         case MYKONOS_ERR_CLGCATTENTUNCFG_NULL_ATTRANGECFGSTRUCT:
7996             return "Passed structure is null in MYKONOS_setClgcAttenTuningConfig().\n";
7997         case MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_MODE:
7998             return "Invalid mode detected for attRangeCfg member in MYKONOS_getClgcAttenTuningConfig(), for valid modes ::mykonosClgcAttenTuningMode_t.\n";
7999         case MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_PRESET:
8000             return "Invalid AttenTuningPreset detected for attRangeCfg member in MYKONOS_getClgcAttenTuningConfig(), valid range is from 0 to 839 (0 to 41.95dB).\n";
8001         case MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_RANGE:
8002             return "Invalid AttenTuningRange detected for attRangeCfg member in MYKONOS_getClgcAttenTuningConfig(),  valid range is from 0 to 420 (0 to 21dB).\n";
8003         case MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_TX1_SETTINGS:
8004             return "Invalid Tx1 AttenTuningRange and AttenTuningPreset combination in MYKONOS_getClgcAttenTuningConfig().\n";
8005         case MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_TX2_SETTINGS:
8006             return "Invalid Tx2 AttenTuningRange and AttenTuningPreset combination in MYKONOS_getClgcAttenTuningConfig().\n";
8007         case MYKONOS_ERR_CLGCATTENTUNCFGGET_NULL_ATTRANGECFGSTRUCT:
8008             return "Passed structure is null in MYKONOS_getClgcAttenTuningConfig().\n";
8009 
8010         default:
8011             return "Unknown error was encountered.\n";
8012     }
8013 
8014 #endif
8015 }
8016 
8017 /**
8018  * \brief Calculates the scaled device clock frequency at the input of the
8019  *        CLKPLL or RFPLL
8020  *
8021  * Use this helper function any time the scaled device clock frequency is needed.
8022  *
8023  * <B>Dependencies</B>
8024  * - device->clocks->deviceClock_kHz
8025  * - device->spiSettings->chipSelectIndex
8026  *
8027  * \param device is structure pointer to the Mykonos data structure containing settings
8028  * \param scaledRefClk_kHz Output: The returned scaled reference clock for the device's PLLs
8029  * \param deviceClkDiv Output: The device clock divider setting that gets set in the devices SPI register.
8030  *
8031  * \retval MYKONOS_ERR_OK Function completed successfully
8032  * \retval MYKONOS_ERR_NULL_DEVICE_PARAM Function parameter device pointer is NULL
8033  * \retval MYKONOS_ERR_INV_SCALEDDEVCLK_PARAM The scaled PLL refclk frequency is out of range (40MHz to 80MHz)
8034  * \retval MYKONOS_ERR_CALCDEVCLK_NULLPARAM Function parameter scaledRefClk_kHz or deviceClkDiv has a NULL pointer
8035  */
MYKONOS_calculateScaledDeviceClk_kHz(mykonosDevice_t * device,uint32_t * scaledRefClk_kHz,uint8_t * deviceClkDiv)8036 static mykonosErr_t MYKONOS_calculateScaledDeviceClk_kHz(mykonosDevice_t *device, uint32_t *scaledRefClk_kHz, uint8_t *deviceClkDiv)
8037 {
8038     uint32_t deviceClock_kHz = 0;
8039 
8040     if ((device == NULL) || (device->clocks == NULL))
8041     {
8042         CMB_writeToLog(ADIHAL_LOG_ERROR, 0, MYKONOS_ERR_NULL_DEVICE_PARAM, getMykonosErrorMessage(MYKONOS_ERR_NULL_DEVICE_PARAM));
8043         return MYKONOS_ERR_NULL_DEVICE_PARAM;
8044     }
8045 
8046 #if (MYKONOS_VERBOSE == 1)
8047     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_calculateScaledDeviceClk_kHz()\n");
8048 #endif
8049 
8050     deviceClock_kHz = device->clocks->deviceClock_kHz;
8051 
8052     if ((scaledRefClk_kHz == NULL) || (deviceClkDiv == NULL))
8053     {
8054         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CALCDEVCLK_NULLPARAM,
8055                 getMykonosErrorMessage(MYKONOS_ERR_CALCDEVCLK_NULLPARAM));
8056         return MYKONOS_ERR_CALCDEVCLK_NULLPARAM;
8057     }
8058 
8059     /* scaled Ref Clock at input to CLKPLL must be in range 40-80MHz. */
8060     if (deviceClock_kHz > 20000 && deviceClock_kHz <= 40000)
8061     {
8062         *scaledRefClk_kHz = deviceClock_kHz << 1;
8063         *deviceClkDiv = 3;
8064     } /* x2 */
8065     else if (deviceClock_kHz > 40000 && deviceClock_kHz <= 80000)
8066     {
8067         *scaledRefClk_kHz = deviceClock_kHz;
8068         *deviceClkDiv = 0;
8069     } /* x1 */
8070     else if (deviceClock_kHz > 80000 && deviceClock_kHz <= 160000)
8071     {
8072         *scaledRefClk_kHz = deviceClock_kHz >> 1;
8073         *deviceClkDiv = 1;
8074     } /* div2 */
8075     else if (deviceClock_kHz > 160000 && deviceClock_kHz <= 320000)
8076     {
8077         *scaledRefClk_kHz = deviceClock_kHz >> 2;
8078         *deviceClkDiv = 2;
8079     } /* div4 */
8080     else
8081     {
8082         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_SCALEDDEVCLK_PARAM,
8083                 getMykonosErrorMessage(MYKONOS_ERR_INV_SCALEDDEVCLK_PARAM));
8084         return MYKONOS_ERR_INV_SCALEDDEVCLK_PARAM;
8085     }
8086     return MYKONOS_ERR_OK;
8087 }
8088 
8089 /**
8090  * \brief Resets the JESD204B Deframer
8091  *
8092  * <B>Dependencies</B>
8093  * - device->spiSettings
8094  *
8095  * \param device is a pointer to the device settings structure
8096  *
8097  * \retval MYKONOS_ERR_OK Function completed successfully
8098  */
MYKONOS_resetDeframer(mykonosDevice_t * device)8099 mykonosErr_t MYKONOS_resetDeframer(mykonosDevice_t *device)
8100 {
8101 
8102 #if (MYKONOS_VERBOSE == 1)
8103     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_resetDeframer()\n");
8104 #endif
8105 
8106     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_RESET, 0x03);
8107     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_RESET, 0x00);
8108 
8109     return MYKONOS_ERR_OK;
8110 }
8111 
8112 /**
8113  * \brief Sets up the JESD204B Serializers
8114  *
8115  * This function uses the Rx framer and ObsRx framer structures to setup the 4
8116  * serializer lanes that are shared between the two framers.  If the Rx profile is valid
8117  * the serializer amplitude and preEmphasis are used from the Rx framer.  If only the ObsRx
8118  * profile is valid, the obsRx framer settings are used.
8119  *
8120  * <B>Dependencies</B>
8121  * - device->spiSettings
8122  * - device->spiSettings->chipSelectIndex
8123  * - device->rx->framer->M
8124  * - device->rx->framer->serializerAmplitude
8125  * - device->rx->framer->preEmphasis
8126  * - device->rx->framer->serializerLanesEnabled
8127  * - device->rx->framer->invertLanePolarity
8128  * - device->obsRx->framer->serializerLanesEnabled
8129  * - device->obsRx->framer->invertLanePolarity
8130  * - device->obsRx->framer->M
8131  * - device->obsRx->framer->serializerLanesEnabled
8132  * - device->obsRx->framer->serializerAmplitude
8133  * - device->obsRx->framer->preEmphasis
8134  *
8135  * \param device Pointer to the device settings structure
8136  *
8137  * \retval MYKONOS_ERR_OK Function completed successfully
8138  * \retval MYKONOS_ERR_INITSER_INV_VCODIV_PARM Mykonos CLKPLL has invalid VCO divider, verify CLKPLL config
8139  * \retval MYKONOS_ERR_SER_LANE_CONFLICT_PARM When both Rx and ObsRx framers are enabled, framers can not share the same physical lane.
8140  * \retval MYKONOS_ERR_SER_INV_REAL_IF_DATA_PARM Rx Framer M can only = 1 when Real IF mode is enabled
8141  * \retval MYKONOS_ERR_SER_INV_M_PARM Invalid Rx Framer M (valid 1,2,4)
8142  * \retval MYKONOS_ERR_SER_INV_LANEEN_PARM Invalid Rx framer serializerLanesEnabled (valid 0-15)
8143  * \retval MYKONOS_ERR_SER_INV_AMP_PARM Invalid Rx serializer amplitude (valid 0-31)
8144  * \retval MYKONOS_ERR_SER_INV_PREEMP_PARM Invalid Rx serializer pre-emphesis (valid 0-7)
8145  * \retval MYKONOS_ERR_SER_INV_LANEPN_PARM Invalid Rx serializer PN invert setting (valid 0-15)
8146  * \retval MYKONOS_ERR_SER_INV_L_PARM Invalid Rx serializer lanes enabled (must use 1, 2 or 4 lanes)
8147  * \retval MYKONOS_ERR_SER_INV_LANERATE_PARM Invalid Rx serializer lane rate (valid 614.4Mbps - 6144Mbps)
8148  *
8149  * \retval MYKONOS_ERR_SER_INV_REAL_IF_DATA_PARM
8150  * \retval MYKONOS_ERR_SER_INV_LANEEN_PARM
8151  * \retval MYKONOS_ERR_SER_INV_AMP_PARM
8152  * \retval MYKONOS_ERR_SER_INV_PREEMP_PARM
8153  * \retval MYKONOS_ERR_SER_INV_LANEPN_PARM
8154  * \retval MYKONOS_ERR_SER_INV_L_PARM
8155  * \retval MYKONOS_ERR_SER_INV_LANERATE_PARM
8156  *
8157  * \retval MYKONOS_ERR_SER_LANE_RATE_CONFLICT_PARM Necessary lane rates for Rx and ObsRx framer can not be obtained with possible divider settings
8158  * \retval MYKONOS_ERR_HS_AND_LANE_RATE_NOT_INTEGER_MULT HSCLK is not an integer multiple of the lane clock rate
8159  * \retval MYKONOS_ERR_SER_INV_TXSER_DIV_PARM No valid Tx serializer divider to obtain desired lane rates
8160  * \retval MYKONOS_ERR_INITSER_INV_PROFILE Rx/ObsRx and sniffer profiles are not valid - can not config serializers
8161  * \retval MYKONOS_ERR_INV_RXFRAMER_PCLKDIV_PARM Invalid Rx framer PCLK divider
8162  * \retval MYKONOS_ERR_INV_OBSRXFRAMER_PCLKDIV_PARM Invalid ORx/Sniffer framer PCLK divider
8163  *
8164  */
MYKONOS_setupSerializers(mykonosDevice_t * device)8165 mykonosErr_t MYKONOS_setupSerializers(mykonosDevice_t *device)
8166 {
8167     uint8_t serializerHalfRateReg = 0;
8168     uint8_t txser_div = 0;
8169     uint8_t txser_div_reg = 0;
8170     uint32_t clkPllVcoFrequency_kHz = 0;
8171     uint32_t hsclkRate_kHz = 0;
8172     uint32_t rxLaneRate_kHz = 0;
8173     uint32_t obsRxLaneRate_kHz = 0;
8174     uint32_t fasterLaneRate_kHz = 0;
8175     uint32_t slowerLaneRate_kHz = 0;
8176     uint8_t modHsLaneRate = 0;
8177     uint8_t rxL = 0;
8178     uint8_t obsRxL = 0;
8179     uint8_t i = 0;
8180     uint8_t amplitudeEmphasis = 0;
8181     uint8_t lanePowerDown = 0x00;
8182     mykonosVcoDiv_t vcoDiv = VCODIV_1;
8183     uint8_t rxLanePn = 0;
8184     uint8_t obsRxLanePn = 0;
8185 
8186     uint32_t hsDigClkdiv4_5_kHz = 0;
8187     uint32_t rxPclkDiv = 0;
8188     uint32_t obsRxPclkDiv = 0;
8189     uint32_t tempPclkDiv = 0;
8190     uint32_t rxFramerPclk_kHz = 0;
8191     uint32_t obsRxFramerPclk_kHz = 0;
8192     uint8_t rxSyncbSelect = 0;
8193     uint8_t obsRxSyncbSelect = 0;
8194 
8195     static const uint32_t MAX_HSCLK_KHZ_IF_VCODIV1P5 = 6144000;  /* max VCO /1.5 output is 6144Mhz. This limits VCO to 9216MHz */
8196     static const uint32_t MAX_HSCLK_KHZ_IF_VCODIV1 = 8000000;    /* max VCO div1 output is 8000Mhz. This limits VCO to 8000MHz */
8197     static const uint32_t MIN_SERIALIZER_RATE_KHZ = 614400;      /* max serializer lane rate = 0.6144 Gbps */
8198     static const uint32_t MAX_SERIALIZER_RATE_KHZ = 6144000;     /* max serializer lane rate = 6.144 Gbps */
8199 #if (MYKONOS_VERBOSE == 1)
8200     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setupSerializers()\n");
8201 #endif
8202 
8203     vcoDiv = device->clocks->clkPllVcoDiv;
8204     clkPllVcoFrequency_kHz = device->clocks->clkPllVcoFreq_kHz;
8205 
8206     switch (vcoDiv)
8207     {
8208         case VCODIV_1:
8209             hsclkRate_kHz = clkPllVcoFrequency_kHz;
8210 
8211             /* max VCO /1 output is 8000Mhz. This limits VCO to 8000MHz */
8212             if (hsclkRate_kHz > MAX_HSCLK_KHZ_IF_VCODIV1)
8213             {
8214                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INITSER_INV_VCODIV1_HSCLK_PARM,
8215                         getMykonosErrorMessage(MYKONOS_ERR_INITSER_INV_VCODIV1_HSCLK_PARM));
8216                 return MYKONOS_ERR_INITSER_INV_VCODIV1_HSCLK_PARM;
8217             }
8218 
8219             break;
8220 
8221         case VCODIV_1p5:
8222             hsclkRate_kHz = (clkPllVcoFrequency_kHz / 15) * 10;
8223 
8224             /* max VCO /1.5 output is 6144Mhz. This limits VCO to 9216MHz */
8225             if (hsclkRate_kHz > MAX_HSCLK_KHZ_IF_VCODIV1P5)
8226             {
8227                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INITSER_INV_VCODIV1P5_HSCLK_PARM,
8228                         getMykonosErrorMessage(MYKONOS_ERR_INITSER_INV_VCODIV1P5_HSCLK_PARM));
8229                 return MYKONOS_ERR_INITSER_INV_VCODIV1P5_HSCLK_PARM;
8230             }
8231 
8232             break;
8233 
8234         case VCODIV_2:
8235             hsclkRate_kHz = clkPllVcoFrequency_kHz >> 1;
8236             break;
8237 
8238         case VCODIV_3:
8239             hsclkRate_kHz = (clkPllVcoFrequency_kHz / 30) * 10;
8240             break;
8241 
8242         default:
8243         {
8244             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INITSER_INV_VCODIV_PARM,
8245                     getMykonosErrorMessage(MYKONOS_ERR_INITSER_INV_VCODIV_PARM));
8246             return MYKONOS_ERR_INITSER_INV_VCODIV_PARM;
8247         }
8248     }
8249 
8250     if ((device->profilesValid & RX_PROFILE_VALID) && (device->profilesValid & (ORX_PROFILE_VALID | SNIFF_PROFILE_VALID)))
8251     {
8252         if (device->rx->framer->serializerLanesEnabled & device->obsRx->framer->serializerLanesEnabled)
8253         {
8254             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_LANE_CONFLICT_PARM,
8255                     getMykonosErrorMessage(MYKONOS_ERR_SER_LANE_CONFLICT_PARM));
8256             return MYKONOS_ERR_SER_LANE_CONFLICT_PARM;
8257         }
8258     }
8259 
8260     lanePowerDown = 0x9F;
8261     if (device->profilesValid & RX_PROFILE_VALID)
8262     {
8263         if (device->rx->framer->M == 1 && !(device->rx->realIfData))
8264         {
8265             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_REAL_IF_DATA_PARM,
8266                     getMykonosErrorMessage(MYKONOS_ERR_SER_INV_REAL_IF_DATA_PARM));
8267             return MYKONOS_ERR_SER_INV_REAL_IF_DATA_PARM;
8268         }
8269 
8270         if (device->rx->framer->M != 1 && device->rx->framer->M != 2 && device->rx->framer->M != 4)
8271         {
8272             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_M_PARM, getMykonosErrorMessage(MYKONOS_ERR_SER_INV_M_PARM));
8273             return MYKONOS_ERR_SER_INV_M_PARM;
8274         }
8275 
8276         for (i = 0; i < 4; i++)
8277         {
8278             rxL += ((device->rx->framer->serializerLanesEnabled >> i) & 0x01);
8279         }
8280 
8281         if (device->rx->framer->serializerLanesEnabled > 15)
8282         {
8283             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_LANEEN_PARM,
8284                     getMykonosErrorMessage(MYKONOS_ERR_SER_INV_LANEEN_PARM));
8285             return MYKONOS_ERR_SER_INV_LANEEN_PARM;
8286         }
8287 
8288         if (device->rx->framer->serializerAmplitude > 31)
8289         {
8290             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_AMP_PARM, getMykonosErrorMessage(MYKONOS_ERR_SER_INV_AMP_PARM));
8291             return MYKONOS_ERR_SER_INV_AMP_PARM;
8292         }
8293 
8294         if (device->rx->framer->preEmphasis > 7)
8295         {
8296             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_PREEMP_PARM,
8297                     getMykonosErrorMessage(MYKONOS_ERR_SER_INV_PREEMP_PARM));
8298             return MYKONOS_ERR_SER_INV_PREEMP_PARM;
8299         }
8300 
8301         if (device->rx->framer->invertLanePolarity > 15)
8302         {
8303             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_LANEPN_PARM,
8304                     getMykonosErrorMessage(MYKONOS_ERR_SER_INV_LANEPN_PARM));
8305             return MYKONOS_ERR_SER_INV_LANEPN_PARM;
8306         }
8307         if ((rxL != 1) && (rxL != 2) && (rxL != 4))
8308         {
8309             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_L_PARM, getMykonosErrorMessage(MYKONOS_ERR_SER_INV_L_PARM));
8310             return MYKONOS_ERR_SER_INV_L_PARM;
8311         }
8312 
8313         rxLaneRate_kHz = device->rx->rxProfile->iqRate_kHz * 20 * device->rx->framer->M / rxL;
8314         lanePowerDown &= (~(device->rx->framer->serializerLanesEnabled));
8315 
8316         if ((rxLaneRate_kHz < MIN_SERIALIZER_RATE_KHZ) || (rxLaneRate_kHz > MAX_SERIALIZER_RATE_KHZ))
8317         {
8318             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_LANERATE_PARM,
8319                     getMykonosErrorMessage(MYKONOS_ERR_SER_INV_LANERATE_PARM));
8320             return MYKONOS_ERR_SER_INV_LANERATE_PARM;
8321         }
8322     }
8323 
8324     if ((device->obsRx->framer != NULL) && (device->profilesValid & (ORX_PROFILE_VALID | SNIFF_PROFILE_VALID)))
8325     {
8326         if ((device->obsRx->framer->M == 1) && !(device->obsRx->realIfData))
8327         {
8328             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_REAL_IF_DATA_PARM,
8329                     getMykonosErrorMessage(MYKONOS_ERR_SER_INV_REAL_IF_DATA_PARM));
8330             return MYKONOS_ERR_SER_INV_REAL_IF_DATA_PARM;
8331         }
8332 
8333         for (i = 0; i < 4; i++)
8334         {
8335             obsRxL += ((device->obsRx->framer->serializerLanesEnabled >> i) & 0x01);
8336         }
8337 
8338         if (device->obsRx->framer->serializerLanesEnabled > 15)
8339         {
8340             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_LANEEN_PARM,
8341                     getMykonosErrorMessage(MYKONOS_ERR_SER_INV_LANEEN_PARM));
8342             return MYKONOS_ERR_SER_INV_LANEEN_PARM;
8343         }
8344 
8345         if (device->obsRx->framer->serializerAmplitude > 31)
8346         {
8347             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_AMP_PARM, getMykonosErrorMessage(MYKONOS_ERR_SER_INV_AMP_PARM));
8348             return MYKONOS_ERR_SER_INV_AMP_PARM;
8349         }
8350 
8351         if (device->obsRx->framer->preEmphasis > 7)
8352         {
8353             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_PREEMP_PARM,
8354                     getMykonosErrorMessage(MYKONOS_ERR_SER_INV_PREEMP_PARM));
8355             return MYKONOS_ERR_SER_INV_PREEMP_PARM;
8356         }
8357 
8358         if (device->obsRx->framer->invertLanePolarity > 15)
8359         {
8360             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_LANEPN_PARM,
8361                     getMykonosErrorMessage(MYKONOS_ERR_SER_INV_LANEPN_PARM));
8362             return MYKONOS_ERR_SER_INV_LANEPN_PARM;
8363         }
8364 
8365         if ((obsRxL != 0) && (obsRxL != 1) && (obsRxL != 2) && (obsRxL != 4))
8366         {
8367             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_L_PARM, getMykonosErrorMessage(MYKONOS_ERR_SER_INV_L_PARM));
8368             return MYKONOS_ERR_SER_INV_L_PARM;
8369         }
8370 
8371         /* check for valid pointer */
8372         if (obsRxL == 0)
8373         {
8374             /* Allow ORx receiver to work but disable Obs Rx framer link - valid on a DPD-enabled transceiver */
8375             obsRxLaneRate_kHz = 0;
8376         }
8377         else if (device->profilesValid & ORX_PROFILE_VALID)
8378         {
8379             obsRxLaneRate_kHz = device->obsRx->orxProfile->iqRate_kHz * 20 * device->obsRx->framer->M / obsRxL;
8380         }
8381         else if (device->profilesValid & SNIFF_PROFILE_VALID)
8382         {
8383             obsRxLaneRate_kHz = device->obsRx->snifferProfile->iqRate_kHz * 20 * device->obsRx->framer->M / obsRxL;
8384         }
8385 
8386         lanePowerDown &= (~(device->obsRx->framer->serializerLanesEnabled));
8387 
8388         if ((obsRxLaneRate_kHz != 0) && ((obsRxLaneRate_kHz < MIN_SERIALIZER_RATE_KHZ) || (obsRxLaneRate_kHz > MAX_SERIALIZER_RATE_KHZ)))
8389         {
8390             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_LANERATE_PARM,
8391                     getMykonosErrorMessage(MYKONOS_ERR_SER_INV_LANERATE_PARM));
8392             return MYKONOS_ERR_SER_INV_LANERATE_PARM;
8393         }
8394     }
8395 
8396     /* checking for RX and OBSRX effective lane rates match */
8397     /* Need to account for oversampling, verify that the 2 lane rate are integer related */
8398 
8399     if ((rxLaneRate_kHz > 0) && (obsRxLaneRate_kHz > 0))
8400     {
8401         fasterLaneRate_kHz = (rxLaneRate_kHz >= obsRxLaneRate_kHz) ? (rxLaneRate_kHz) : (obsRxLaneRate_kHz);
8402         slowerLaneRate_kHz = (rxLaneRate_kHz >= obsRxLaneRate_kHz) ? (obsRxLaneRate_kHz) : (rxLaneRate_kHz);
8403 
8404         /* Verify that lane rates are integer multiples of each other */
8405         if ((fasterLaneRate_kHz % slowerLaneRate_kHz) != 0)
8406         {
8407             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_LANE_RATE_CONFLICT_PARM,
8408                     getMykonosErrorMessage(MYKONOS_ERR_SER_LANE_RATE_CONFLICT_PARM));
8409             return MYKONOS_ERR_SER_LANE_RATE_CONFLICT_PARM;
8410         }
8411     }
8412     else
8413     {
8414         fasterLaneRate_kHz = (rxLaneRate_kHz >= obsRxLaneRate_kHz) ? (rxLaneRate_kHz) : (obsRxLaneRate_kHz);
8415     }
8416 
8417     /* performing integer multiple check on HS clock and lane rate clock */
8418     if (fasterLaneRate_kHz == 0)
8419     {
8420         /* All serializer lanes are disabled */
8421         txser_div = 1;
8422         txser_div_reg = 0;
8423         serializerHalfRateReg = 0;
8424     }
8425     else
8426     {
8427         if ((fasterLaneRate_kHz > hsclkRate_kHz) ||
8428             (fasterLaneRate_kHz > MAX_SERIALIZER_RATE_KHZ))
8429         {
8430             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_LANERATE_PARM,
8431                     getMykonosErrorMessage(MYKONOS_ERR_SER_INV_LANERATE_PARM));
8432             return MYKONOS_ERR_SER_INV_LANERATE_PARM;
8433         }
8434 
8435         modHsLaneRate = (uint8_t)(hsclkRate_kHz % fasterLaneRate_kHz);
8436         if (modHsLaneRate != 0)
8437         {
8438             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_HS_AND_LANE_RATE_NOT_INTEGER_MULT,
8439                     getMykonosErrorMessage(MYKONOS_ERR_HS_AND_LANE_RATE_NOT_INTEGER_MULT));
8440             return MYKONOS_ERR_HS_AND_LANE_RATE_NOT_INTEGER_MULT;
8441         }
8442 
8443         txser_div = (uint8_t)(hsclkRate_kHz / fasterLaneRate_kHz);  /* Total serializer Divider (1,2,4,8) */
8444         switch (txser_div)
8445         {
8446             case 1:
8447                 txser_div_reg = 0;           /* Divide hsclk by 1 */
8448                 serializerHalfRateReg = 0;   /* 0 = divide serializer clock by 1 */
8449                 break;
8450             case 2:
8451                 txser_div_reg = 1;           /* Divide hsclk by 2 */
8452                 serializerHalfRateReg = 0;   /* 0 = divide serializer clock by 1 */
8453                 break;
8454             case 4:
8455                 txser_div_reg = 2;           /* Divide hsclk by 4 */
8456                 serializerHalfRateReg = 0;   /* 0 = divide serializer clock by 1 */
8457                 break;
8458             case 8:
8459                 txser_div_reg = 2;           /* Divide hsclk by 4 */
8460                 serializerHalfRateReg = 1;   /* 1 = divide serializer clock by 2 */
8461                 break;
8462             default:
8463                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SER_INV_TXSER_DIV_PARM,
8464                         getMykonosErrorMessage(MYKONOS_ERR_SER_INV_TXSER_DIV_PARM));
8465                 return MYKONOS_ERR_SER_INV_TXSER_DIV_PARM;
8466         }
8467     }
8468 
8469     if (device->profilesValid & RX_PROFILE_VALID)
8470     {
8471         amplitudeEmphasis = ((device->rx->framer->serializerAmplitude & 0x1f) << 3) | (device->rx->framer->preEmphasis & 0x07);
8472     }
8473     else if (device->profilesValid & (ORX_PROFILE_VALID | SNIFF_PROFILE_VALID))
8474     {
8475         amplitudeEmphasis = ((device->obsRx->framer->serializerAmplitude & 0x1f) << 3) | (device->obsRx->framer->preEmphasis & 0x07);
8476     }
8477     else
8478     {
8479         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INITSER_INV_PROFILE, getMykonosErrorMessage(MYKONOS_ERR_INITSER_INV_PROFILE));
8480         return MYKONOS_ERR_INITSER_INV_PROFILE;
8481     }
8482 
8483     if (device->profilesValid & RX_PROFILE_VALID)
8484     {
8485         rxSyncbSelect = (device->rx->framer->obsRxSyncbSelect > 0) ? 1 : 0;
8486         rxLanePn = (uint8_t)(rxSyncbSelect << 7) | (device->rx->framer->invertLanePolarity & 0xF);
8487     }
8488 
8489     if (device->profilesValid & (ORX_PROFILE_VALID | SNIFF_PROFILE_VALID))
8490     {
8491         obsRxSyncbSelect = (device->obsRx->framer->obsRxSyncbSelect > 0) ? 1 : 0;
8492         obsRxLanePn = (uint8_t)(obsRxSyncbSelect << 7) | (device->obsRx->framer->invertLanePolarity & 0xF);
8493     }
8494 
8495     /* Serializer lane clock frequency */
8496     /* serLaneClock_kHz = fasterLaneRate_kHz / txser_div / 20; */
8497     if (device->profilesValid & RX_PROFILE_VALID)
8498     {
8499         /* calculate manual PCLK frequency for Rx framer  = Rx IQrate * F, where F = (2*M/L)  or PCLK = lanerate /10 */
8500         if (device->rx->framer->overSample)
8501         {
8502             rxFramerPclk_kHz = fasterLaneRate_kHz / 10;
8503         }
8504         else
8505         {
8506             rxFramerPclk_kHz = rxLaneRate_kHz / 10;
8507         }
8508 
8509         hsDigClkdiv4_5_kHz = hsclkRate_kHz / device->clocks->clkPllHsDiv / device->rx->rxProfile->rxDec5Decimation;
8510 
8511         /* PCLKDiv: 0=4x, 1=2x, 2=1x, 3=/2, 4=/4, 5=/8, 6=/16 */
8512         if (hsDigClkdiv4_5_kHz == rxFramerPclk_kHz)
8513         {
8514             rxPclkDiv = 2;
8515         }
8516         else if (hsDigClkdiv4_5_kHz > rxFramerPclk_kHz)
8517         {
8518             if (rxFramerPclk_kHz == 0)
8519             {
8520                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_RXFRAMER_PCLKDIV_PARM,
8521                         getMykonosErrorMessage(MYKONOS_ERR_INV_RXFRAMER_PCLKDIV_PARM));
8522                 return MYKONOS_ERR_INV_RXFRAMER_PCLKDIV_PARM;
8523             }
8524 
8525             tempPclkDiv = hsDigClkdiv4_5_kHz / rxFramerPclk_kHz;
8526             switch (tempPclkDiv)
8527             {
8528                 case 2:
8529                     rxPclkDiv = 3;
8530                     break;
8531                 case 4:
8532                     rxPclkDiv = 4;
8533                     break;
8534                 case 8:
8535                     rxPclkDiv = 5;
8536                     break;
8537                 case 16:
8538                     rxPclkDiv = 6;
8539                     break;
8540                 default:
8541                 {
8542                     CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_RXFRAMER_PCLKDIV_PARM,
8543                             getMykonosErrorMessage(MYKONOS_ERR_INV_RXFRAMER_PCLKDIV_PARM));
8544                     return MYKONOS_ERR_INV_RXFRAMER_PCLKDIV_PARM;
8545                 }
8546             }
8547         }
8548         else if (hsDigClkdiv4_5_kHz < rxFramerPclk_kHz)
8549         {
8550             tempPclkDiv = rxFramerPclk_kHz / hsDigClkdiv4_5_kHz;
8551             switch (tempPclkDiv)
8552             {
8553                 case 2:
8554                     rxPclkDiv = 1;
8555                     break;
8556                 case 4:
8557                     rxPclkDiv = 0;
8558                     break;
8559                 default:
8560                 {
8561                     CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_RXFRAMER_PCLKDIV_PARM,
8562                             getMykonosErrorMessage(MYKONOS_ERR_INV_RXFRAMER_PCLKDIV_PARM));
8563                     return MYKONOS_ERR_INV_RXFRAMER_PCLKDIV_PARM;
8564                 }
8565             }
8566         }
8567     }
8568 
8569     if (obsRxL == 0)
8570     {
8571         /* Make sure PCLK is set as low as possible because it interacts with Rx Framer logic, */
8572         /* even though ObsRx Framer disabled */
8573         obsRxPclkDiv = 6;
8574     }
8575     else if (device->profilesValid & (ORX_PROFILE_VALID | SNIFF_PROFILE_VALID))
8576     {
8577         /* calculate manual PCLK frequency for obsRx framer  = obsRx IQrate * F, where F = (2*M/L) */
8578         if (device->profilesValid & ORX_PROFILE_VALID)
8579         {
8580             if (device->obsRx->framer->overSample)
8581             {
8582                 obsRxFramerPclk_kHz = fasterLaneRate_kHz / 10;
8583             }
8584             else
8585             {
8586                 obsRxFramerPclk_kHz = obsRxLaneRate_kHz / 10;
8587             }
8588 
8589             hsDigClkdiv4_5_kHz = hsclkRate_kHz / device->clocks->clkPllHsDiv / device->obsRx->orxProfile->rxDec5Decimation;
8590         }
8591         else if (device->profilesValid & SNIFF_PROFILE_VALID)
8592         {
8593             if (device->obsRx->framer->overSample)
8594             {
8595                 obsRxFramerPclk_kHz = fasterLaneRate_kHz / 10;
8596             }
8597             else
8598             {
8599                 obsRxFramerPclk_kHz = obsRxLaneRate_kHz / 10;
8600             }
8601 
8602             hsDigClkdiv4_5_kHz = hsclkRate_kHz / device->clocks->clkPllHsDiv / device->obsRx->snifferProfile->rxDec5Decimation;
8603         }
8604 
8605         /* PCLKDiv: 0=4x, 1=2x, 2=1x, 3=/2, 4=/4, 5=/8, 6=/16 */
8606         if (hsDigClkdiv4_5_kHz == obsRxFramerPclk_kHz)
8607         {
8608             obsRxPclkDiv = 2;
8609         }
8610         else if ((hsDigClkdiv4_5_kHz > obsRxFramerPclk_kHz) && (obsRxFramerPclk_kHz != 0))
8611         {
8612             tempPclkDiv = hsDigClkdiv4_5_kHz / obsRxFramerPclk_kHz;
8613             switch (tempPclkDiv)
8614             {
8615                 case 2:
8616                     obsRxPclkDiv = 3;
8617                     break;
8618                 case 4:
8619                     obsRxPclkDiv = 4;
8620                     break;
8621                 case 8:
8622                     obsRxPclkDiv = 5;
8623                     break;
8624                 case 16:
8625                     obsRxPclkDiv = 6;
8626                     break;
8627                 default:
8628                 {
8629                     CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_OBSRXFRAMER_PCLKDIV_PARM,
8630                             getMykonosErrorMessage(MYKONOS_ERR_INV_OBSRXFRAMER_PCLKDIV_PARM));
8631                     return MYKONOS_ERR_INV_OBSRXFRAMER_PCLKDIV_PARM;
8632                 }
8633             }
8634         }
8635         else if (hsDigClkdiv4_5_kHz < obsRxFramerPclk_kHz)
8636         {
8637             if (hsDigClkdiv4_5_kHz == 0)
8638             {
8639                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_OBSRXFRAMER_PCLKDIV_PARM,
8640                         getMykonosErrorMessage(MYKONOS_ERR_INV_OBSRXFRAMER_PCLKDIV_PARM));
8641                 return MYKONOS_ERR_INV_OBSRXFRAMER_PCLKDIV_PARM;
8642             }
8643 
8644             tempPclkDiv = obsRxFramerPclk_kHz / hsDigClkdiv4_5_kHz;
8645             switch (tempPclkDiv)
8646             {
8647                 case 2:
8648                     obsRxPclkDiv = 1;
8649                     break;
8650                 case 4:
8651                     obsRxPclkDiv = 0;
8652                     break;
8653                 default:
8654                 {
8655                     CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INV_OBSRXFRAMER_PCLKDIV_PARM,
8656                             getMykonosErrorMessage(MYKONOS_ERR_INV_OBSRXFRAMER_PCLKDIV_PARM));
8657                     return MYKONOS_ERR_INV_OBSRXFRAMER_PCLKDIV_PARM;
8658                 }
8659             }
8660         }
8661     }
8662 
8663     /* set lane rate divide setting */
8664     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_3, txser_div_reg, 0x03, 0);
8665 
8666     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_SERIALIZER_CTL_2, amplitudeEmphasis);
8667 
8668     /* Serializer: Release Reset */
8669     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_SERIALIZER_SPECIAL, 0x03);
8670 
8671     /* Serializer: txser clk enable */
8672     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_SERIALIZER_HS_DIV_TXSER_CLK_EN, 0x01);
8673 
8674     /* Serializer: Enable 2 to 1 serializer */
8675     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_SERIALIZER_CTL_3, 0x20 | serializerHalfRateReg);
8676 
8677     /* power up desired serializer lanes */
8678     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_SERIALIZER_CTL_1, lanePowerDown);
8679 
8680     /* apply desired lane PN inversions to the TX and OBSRX framers */
8681     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_LANE_DATA_CTL, rxLanePn);
8682     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_LANE_DATA_CTL, obsRxLanePn);
8683 
8684     /* set Rx framer manual PCLK frequency based on lane rate of the serializers */
8685     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_FRAMER_CLK_EN, (uint8_t)rxPclkDiv, 0x70, 4);
8686 
8687     /* enable bit repeat mode in Rx framer - since manual PCLK, oversample will still work */
8688     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_FRAMER_CLK_EN, 0, 0x80, 7);
8689 
8690     /* enable manual PCLK mode in Rx framer */
8691     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_FRAMER_CLK_EN, 1, 0x04, 2);
8692 
8693     /* set obsRx framer manual PCLK frequency based on lane rate of the serializers */
8694     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_CLK_EN, (uint8_t)obsRxPclkDiv, 0x70, 4);
8695 
8696     /* enable bit repeat mode in ObsRx framer - since manual PCLK, oversample will still work */
8697     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_CLK_EN, 0, 0x80, 7);
8698 
8699     /* enable manual PCLK mode in ObsRx framer */
8700     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_CLK_EN, 1, 0x04, 2);
8701 
8702     return MYKONOS_ERR_OK;
8703 }
8704 
8705 /**
8706  * \brief Sets up the JESD204B Deserializers
8707  *
8708  * This function enables the necessary deserializer lanes, sets the deserializer clocks
8709  * PN inversion settings, and EQ settings based on the info found in the device data structure.
8710  *
8711  * <B>Dependencies</B>
8712  * - device->spiSettings
8713  * - device->spiSettings->chipSelectIndex
8714  * - device->tx->txProfile->clkPllVcoDiv
8715  * - device->tx->txProfile->vcoFreq_kHz
8716  * - device->tx->txProfile->txIqRate_kHz
8717  * - device->tx->deframer->M
8718  * - device->tx->deframer->deserializerLanesEnabled
8719  * - device->tx->deframer->invertLanePolarity
8720  * - device->tx->deframer->EQSetting
8721  *
8722  * \param device Pointer to the device settings structure
8723 
8724  * \retval MYKONOS_ERR_OK Function completed successfully
8725  * \retval MYKONOS_ERR_INITDES_INV_TXPROFILE Tx Profile is not valid in data structure - can not setup deserializer
8726  * \retval MYKONOS_ERR_INITDES_INV_VCODIV_PARM Mykonos CLKPLL VCO divider is invalid
8727  * \retval MYKONOS_ERR_DESER_INV_M_PARM Invalid M (valid 2 or 4)
8728  * \retval MYKONOS_ERR_DESER_INV_L_PARM Invalid L (valid 1,2,4)
8729  * \retval MYKONOS_ERR_DESER_INV_HSCLK_PARM Invalid HSCLK, must be 6.144G or less after CLKPLL VCO divider - verify CLKPLL config
8730  * \retval MYKONOS_ERR_DESER_INV_LANERATE_PARM Invalid lanerate, must be between 614.4 Mbps to 6144 Mbps
8731  * \retval MYKONOS_ERR_DESER_INV_LANEEN_PARM Invalid deserializerLanesEnabled (valid 0-15 in 1,2,4 lane combinations)
8732  * \retval MYKONOS_ERR_DESER_INV_EQ_PARM Invalid EQ parameter (valid 0-4)
8733  * \retval MYKONOS_ERR_DESER_INV_LANEPN_PARM Invalid PN invert setting, (valid 0-15, invert bit per lane)
8734  * \retval MYKONOS_ERR_DES_HS_AND_LANE_RATE_NOT_INTEGER_MULT Invalid clock settings, HSCLK is not an integer multiple of lane rate
8735  *
8736  */
MYKONOS_setupDeserializers(mykonosDevice_t * device)8737 mykonosErr_t MYKONOS_setupDeserializers(mykonosDevice_t *device)
8738 {
8739     uint8_t lanePowerDown = 0xF;
8740     uint8_t des_div = 0;
8741     uint8_t des_div_bitfield = 0;
8742     uint8_t rxcdr_div = 0;
8743     uint8_t rxcdr_div_bitfield = 0;
8744     uint32_t hsclkRate_kHz = 0;
8745     uint8_t i = 0;
8746     uint8_t L = 0;
8747     uint32_t laneRate_kHz = 0;
8748     uint8_t invertLanePolarity = 0;
8749     uint8_t modHsLaneRate = 0;
8750 
8751     const uint32_t MAX_HSCLKRATE_KHZ = 12288000;
8752 
8753 #if (MYKONOS_VERBOSE == 1)
8754     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setupDeserializers()\n");
8755 #endif
8756 
8757     if ((device->profilesValid & TX_PROFILE_VALID) == 0)
8758     {
8759         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INITDES_INV_TXPROFILE,
8760                 getMykonosErrorMessage(MYKONOS_ERR_INITDES_INV_TXPROFILE));
8761         return MYKONOS_ERR_INITDES_INV_TXPROFILE;
8762     }
8763 
8764     if (device->tx->deframer->M != 2 && device->tx->deframer->M != 4)
8765     {
8766         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DESER_INV_M_PARM, getMykonosErrorMessage(MYKONOS_ERR_DESER_INV_M_PARM));
8767         return MYKONOS_ERR_DESER_INV_M_PARM;
8768     }
8769 
8770     for (i = 0; i < 4; i++)
8771     {
8772         L += ((device->tx->deframer->deserializerLanesEnabled >> i) & 0x01);
8773     }
8774 
8775     if ((L == 0) || (L == 3) || (L > 4))
8776     {
8777         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DESER_INV_L_PARM, getMykonosErrorMessage(MYKONOS_ERR_DESER_INV_L_PARM));
8778         return MYKONOS_ERR_DESER_INV_L_PARM;
8779     }
8780 
8781     //laneRate_kHz calculation and checks
8782     laneRate_kHz = device->tx->txProfile->iqRate_kHz * 20 * device->tx->deframer->M / L;
8783 
8784     if ((laneRate_kHz < 614400) || (laneRate_kHz > 6144000))
8785     {
8786         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DESER_INV_LANERATE_PARM,
8787                 getMykonosErrorMessage(MYKONOS_ERR_DESER_INV_LANERATE_PARM));
8788         return MYKONOS_ERR_DESER_INV_LANERATE_PARM;
8789     }
8790 
8791     if (device->tx->deframer->deserializerLanesEnabled > 15)
8792     {
8793         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DESER_INV_LANEEN_PARM,
8794                 getMykonosErrorMessage(MYKONOS_ERR_DESER_INV_LANEEN_PARM));
8795         return MYKONOS_ERR_DESER_INV_LANEEN_PARM;
8796     }
8797 
8798     if ((device->tx->deframer->deserializerLanesEnabled == 0x7) || (device->tx->deframer->deserializerLanesEnabled == 0xB)
8799             || (device->tx->deframer->deserializerLanesEnabled == 0xD) || (device->tx->deframer->deserializerLanesEnabled == 0xE))
8800     {
8801         /* 3 lanes not valid, only 1,2, or 4 lanes */
8802         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DESER_INV_LANEEN_PARM,
8803                 getMykonosErrorMessage(MYKONOS_ERR_DESER_INV_LANEEN_PARM));
8804         return MYKONOS_ERR_DESER_INV_LANEEN_PARM;
8805     }
8806 
8807     if (device->tx->deframer->EQSetting > 4)
8808     {
8809         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DESER_INV_EQ_PARM, getMykonosErrorMessage(MYKONOS_ERR_DESER_INV_EQ_PARM));
8810         return MYKONOS_ERR_DESER_INV_EQ_PARM;
8811     }
8812 
8813     if (device->tx->deframer->invertLanePolarity > 15)
8814     {
8815         /* only lower 4 bits of parameter are valid */
8816         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DESER_INV_LANEPN_PARM,
8817                 getMykonosErrorMessage(MYKONOS_ERR_DESER_INV_LANEPN_PARM));
8818         return MYKONOS_ERR_DESER_INV_LANEPN_PARM;
8819     }
8820 
8821     //hsclkRate_kHz calculations
8822     switch (device->clocks->clkPllVcoDiv)
8823     {
8824         case VCODIV_1:
8825             hsclkRate_kHz = device->clocks->clkPllVcoFreq_kHz;
8826             break;
8827         case VCODIV_1p5:
8828             hsclkRate_kHz = (device->clocks->clkPllVcoFreq_kHz / 15) * 10;
8829             break;
8830         case VCODIV_2:
8831             hsclkRate_kHz = device->clocks->clkPllVcoFreq_kHz >> 1;
8832             break;
8833         case VCODIV_3:
8834             hsclkRate_kHz = (device->clocks->clkPllVcoFreq_kHz / 30) * 10;
8835             break;
8836         default:
8837             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INITDES_INV_VCODIV_PARM,
8838                     getMykonosErrorMessage(MYKONOS_ERR_INITDES_INV_VCODIV_PARM));
8839             return MYKONOS_ERR_INITDES_INV_VCODIV_PARM;
8840     }
8841 
8842     /* The deserializer clock needs to be in the range 3.8GHz to 6.144 GHz in reg x107.  The rest of the division is in xDD */
8843     if (hsclkRate_kHz <= 6144000)
8844     {
8845         rxcdr_div = 1;
8846     }
8847     else if ((hsclkRate_kHz > 6144000) && (hsclkRate_kHz <= MAX_HSCLKRATE_KHZ))
8848     {
8849         rxcdr_div = 2;
8850     }
8851     else if ((hsclkRate_kHz > MAX_HSCLKRATE_KHZ) && (hsclkRate_kHz < 24576000))
8852     {
8853         rxcdr_div = 4;
8854     }
8855     else
8856     {
8857         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DESER_INV_HSCLK_PARM,
8858                 getMykonosErrorMessage(MYKONOS_ERR_DESER_INV_HSCLK_PARM));
8859         return MYKONOS_ERR_DESER_INV_HSCLK_PARM;
8860     }
8861 
8862     switch (rxcdr_div)
8863     {
8864         case 1:
8865             rxcdr_div_bitfield = 0;
8866             break;
8867         case 2:
8868             rxcdr_div_bitfield = 1;
8869             break;
8870 
8871         default:
8872             /* Default case is when rxcdr_div == 4 */
8873             rxcdr_div_bitfield = 2;
8874             break;
8875     }
8876 
8877     /* performing integer multiple check on HS clock and lane rate clock */
8878     modHsLaneRate = (uint8_t)(hsclkRate_kHz % laneRate_kHz);
8879     if (modHsLaneRate)
8880     {
8881         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DES_HS_AND_LANE_RATE_NOT_INTEGER_MULT,
8882                 getMykonosErrorMessage(MYKONOS_ERR_DES_HS_AND_LANE_RATE_NOT_INTEGER_MULT));
8883         return MYKONOS_ERR_DES_HS_AND_LANE_RATE_NOT_INTEGER_MULT;
8884     }
8885 
8886     des_div = (uint8_t)(hsclkRate_kHz / laneRate_kHz / rxcdr_div);
8887 
8888     switch (des_div)
8889     {
8890         case 1:
8891             des_div_bitfield = 0;
8892             break;
8893         case 2:
8894             des_div_bitfield = 1;
8895             break;
8896         case 4:
8897             des_div_bitfield = 2;
8898             break;
8899         case 8:
8900             des_div_bitfield = 3;
8901             break;
8902         default:
8903             des_div_bitfield = 0;
8904             break;
8905     }
8906 
8907     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_3, rxcdr_div_bitfield, 0x0C, 0x02);
8908 
8909     invertLanePolarity = (device->tx->deframer->invertLanePolarity & 0xF);
8910 
8911     lanePowerDown = (~(device->tx->deframer->deserializerLanesEnabled)) & 0xF;
8912 
8913     /* Deserializer: PLL clock enable */
8914     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DESERIALIZER_HS_DIV_RXCDR_CLK_EN, 0x01);
8915 
8916     /* Deserializer: Set Pdet control */
8917     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DESERIALIZER_PDET_CTL, 0x09);
8918 
8919     /* Deserializer: Set Power down control */
8920     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DESERIALIZER_CTL_0, (0x80U | lanePowerDown | (uint8_t)(des_div_bitfield << 4)));
8921 
8922     /* Deserializer: Set Sine Shape */
8923     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DESERIALIZER_SIN_SHAPE_0, 0x00);
8924 
8925     /* Deserializer: Set ss gain and vga */
8926     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DESERIALIZER_SIN_SHAPE_1, 0x00);
8927 
8928     /* Deserializer: Enable EQ, AC coupled JESD204B lanes */
8929     /* TODO: add ability to set this for AC coupling or DC coupling */
8930     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DESERIALIZER_EQ_CTL_1, 0x07);
8931 
8932     /* Deserializer: Clear Data present at negedge, disable peak adjust */
8933     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DESERIALIZER_MISC_CTL, 0x04);
8934 
8935     /* Deserializer: Set Equalizer for lanes 1 and 0 */
8936     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DESERIALIZER_EQ_CTL_1_TO_0, ((uint8_t)(device->tx->deframer->EQSetting << 3) | device->tx->deframer->EQSetting));
8937 
8938     /* Deserializer: Set Equalizer for lanes 2 and 3 */
8939     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DESERIALIZER_EQ_CTL_3_TO_2, ((uint8_t)(device->tx->deframer->EQSetting << 3) | device->tx->deframer->EQSetting));
8940 
8941     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_LANE_DATA_CTL, invertLanePolarity);
8942 
8943     /* Reset Deserializers - toggle resetb bit in [0] */
8944     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DESERIALIZER_SPECIAL, 0x00);
8945     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DESERIALIZER_SPECIAL, 0x01);
8946 
8947     /* Start ALC cal */
8948     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DESERIALIZER_CDR_CAL_CTL, 0x02);
8949 
8950     /* Deframer: Enable clocks and lane clocks */
8951     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_CLK_EN, 0x03);
8952 
8953     return MYKONOS_ERR_OK;
8954 }
8955 
8956 /**
8957  * \brief Sets up the JESD204B Framer
8958  *
8959  * <B>Dependencies</B>
8960  * - device->spiSettings
8961  * - device->spiSettings->chipSelectIndex
8962  * - device->rx->framer->M
8963  * - device->rx->realIfData
8964  * - device->rx->framer->bankId
8965  * - device->rx->framer->lane0Id
8966  * - device->rx->framer->serializerLanesEnabled
8967  * - device->rx->framer->obsRxSyncbSelect
8968  * - device->rx->framer->K
8969  * - device->rx->framer->externalSysref
8970  * - device->rx->rxChannels
8971  * - device->rx->framer->newSysrefOnRelink
8972  * - device->rx->framer->enableAutoChanXbar
8973  * - device->rx->framer->lmfcOffset
8974  * - device->rx->framer->scramble
8975  *
8976  * \param device Pointer to the device settings structure
8977  *
8978  * \retval MYKONOS_ERR_OK Function completed successfully
8979  * \retval MYKONOS_ERR_FRAMER_INV_REAL_IF_DATA_PARM Invalid framer M, M can only = 1 in real IF mode
8980  * \retval MYKONOS_ERR_FRAMER_INV_M_PARM Invalid framer M (valid 1,2,4)
8981  * \retval MYKONOS_ERR_FRAMER_INV_BANKID_PARM Invalid BankId (valid 0-15)
8982  * \retval MYKONOS_ERR_FRAMER_INV_LANEID_PARM Invalid Lane0Id (valid 0-31)
8983  * \retval MYKONOS_ERR_RXFRAMER_INV_FK_PARAM
8984  * \retval MYKONOS_ERR_FRAMER_INV_K_OFFSET_PARAM
8985  */
MYKONOS_setupJesd204bFramer(mykonosDevice_t * device)8986 mykonosErr_t MYKONOS_setupJesd204bFramer(mykonosDevice_t *device)
8987 {
8988     uint8_t i = 0;
8989     uint8_t fifoLaneEnable = 0;
8990     uint8_t L = 0;
8991     uint8_t ML = 0;
8992     uint8_t framerConfigF = 0;
8993 
8994     uint8_t subaddr[29] = {0}; /* holds address to framer sub register map */
8995     uint8_t subdata[29] = {0}; /* holds data for framer sub register map */
8996 
8997     /* Setup submap registers */
8998     uint8_t SUBCLASSV = 1; /* JESD subclass 1 */
8999     uint8_t JESDV = 1; /* Version: JESD204B */
9000     uint8_t DID = 0;
9001     uint8_t BID = 0;
9002     uint8_t LID0 = 0;
9003     uint8_t LID1 = 1;
9004     uint8_t LID2 = 2;
9005     uint8_t LID3 = 3;
9006     uint8_t CS = 0;
9007     uint8_t N = 0x0F;
9008     uint8_t Np = 0x0F;
9009     uint8_t S = 0;
9010     uint8_t CF = 0;
9011     uint8_t K = 31;
9012     uint8_t HD = 0;
9013     uint8_t FramerL = 1;
9014     uint8_t FramerM = 2;
9015     uint8_t FramerF = 1;
9016     uint8_t framerADC_XBar = 0xE4;
9017     uint16_t FK = 0;
9018 
9019     uint8_t regE0 = 0;
9020     uint8_t regE2 = 0;
9021     uint8_t framerLaneXbar = 0xE4;
9022     uint16_t CheckSum = 0;
9023 
9024 #if (MYKONOS_VERBOSE == 1)
9025     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setupJesd204bFramer()\n");
9026 #endif
9027 
9028     if (device->rx->framer->M == 1 && !(device->rx->realIfData))
9029     {
9030         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_FRAMER_INV_REAL_IF_DATA_PARM,
9031                 getMykonosErrorMessage(MYKONOS_ERR_FRAMER_INV_REAL_IF_DATA_PARM));
9032         return MYKONOS_ERR_FRAMER_INV_REAL_IF_DATA_PARM;
9033     }
9034 
9035     if (device->rx->framer->M != 1 && device->rx->framer->M != 2 && device->rx->framer->M != 4)
9036     {
9037         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_FRAMER_INV_M_PARM, getMykonosErrorMessage(MYKONOS_ERR_FRAMER_INV_M_PARM));
9038         return MYKONOS_ERR_FRAMER_INV_M_PARM;
9039     }
9040 
9041     if (device->rx->framer->bankId > 15)
9042     {
9043         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_FRAMER_INV_BANKID_PARM,
9044                 getMykonosErrorMessage(MYKONOS_ERR_FRAMER_INV_BANKID_PARM));
9045         return MYKONOS_ERR_FRAMER_INV_BANKID_PARM;
9046     }
9047 
9048     /* no need to check deviceId, its range is full uint8_t range */
9049     if (device->rx->framer->lane0Id > 31)
9050     {
9051         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_FRAMER_INV_LANEID_PARM,
9052                 getMykonosErrorMessage(MYKONOS_ERR_FRAMER_INV_LANEID_PARM));
9053         return MYKONOS_ERR_FRAMER_INV_LANEID_PARM;
9054     }
9055 
9056     //count number of lanes
9057     L = 0;
9058     ML = 0;
9059 
9060     for (i = 0; i < 4; i++)
9061     {
9062         L += ((device->rx->framer->serializerLanesEnabled >> i) & 0x01);
9063     }
9064     ML = (uint8_t)(device->rx->framer->M * 10) + L;
9065 
9066     FK = (uint16_t)(device->rx->framer->K * 2 * device->rx->framer->M / L);
9067 
9068     if (FK < 20 || FK > 256 || FK % 4 != 0)
9069     {
9070         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RXFRAMER_INV_FK_PARAM,
9071                 getMykonosErrorMessage(MYKONOS_ERR_RXFRAMER_INV_FK_PARAM));
9072         return MYKONOS_ERR_RXFRAMER_INV_FK_PARAM;
9073     }
9074 
9075     if (device->rx->framer->externalSysref == 0)
9076     {
9077         /* Framer: Generate SYSREF internally */
9078         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_TEST_CNTR_CTL, 0x20);
9079     }
9080 
9081     framerADC_XBar = 0xB1;
9082     if (ML == 24)
9083     {
9084         if (device->rx->rxChannels == RX1)
9085         {
9086             /* adc 0 and 2 used */
9087             framerADC_XBar = ((framerADC_XBar & 0x0C) << 2) | (framerADC_XBar & 0x03);
9088         }
9089         else if (device->rx->rxChannels == RX2)
9090         {
9091             /* swap ADC xbar for Rx1 and Rx2 */
9092             framerADC_XBar = ((framerADC_XBar & 0xF) << 4) | ((framerADC_XBar & 0xF0) >> 4);
9093             /* adc 0 and 2 used */
9094             framerADC_XBar = ((framerADC_XBar & 0x0C) << 2) | (framerADC_XBar & 0x03);
9095         }
9096 
9097         /* Framer: Set ADC Crossbar */
9098         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_ADC_XBAR_SEL, framerADC_XBar);
9099     }
9100     else
9101     {
9102         /* Framer: Set ADC Crossbar */
9103         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_ADC_XBAR_SEL, framerADC_XBar);
9104     }
9105 
9106     if (device->rx->framer->enableManualLaneXbar == 1)
9107     {
9108         framerLaneXbar = device->rx->framer->serializerLaneCrossbar;
9109     }
9110     else
9111     {
9112         if (ML == 42)
9113         {
9114             /* uses framer outputs 0 and 2 instead of 0 and 1...fix framer lane XBar */
9115             /* only 2 lane cases here */
9116             switch ((device->rx->framer->serializerLanesEnabled & 0x0F))
9117             {
9118                 case 3:
9119                     framerLaneXbar = 0x08;
9120                     break;
9121                 case 5:
9122                     framerLaneXbar = 0x20;
9123                     break;
9124                 case 6:
9125                     framerLaneXbar = 0x20;
9126                     break;
9127                 case 9:
9128                     framerLaneXbar = 0x80;
9129                     break;
9130                 case 10:
9131                     framerLaneXbar = 0x80;
9132                     break;
9133                 case 12:
9134                     framerLaneXbar = 0x80;
9135                     break;
9136                 default:
9137                     /* default to valid setting for Lane 0 */
9138                     framerLaneXbar = 0x08;
9139                     break;
9140             }
9141         }
9142         else
9143         {
9144             switch ((device->rx->framer->serializerLanesEnabled & 0x0F))
9145             {
9146                 /* all 4 lanes get framer 0 output */
9147                 case 1:
9148                     framerLaneXbar = 0x00;
9149                     break;
9150                 case 2:
9151                     framerLaneXbar = 0x00;
9152                     break;
9153                 case 3:
9154                     framerLaneXbar = 0x04;
9155                     break;
9156                 case 4:
9157                     framerLaneXbar = 0x00;
9158                     break;
9159                 case 5:
9160                     framerLaneXbar = 0x10;
9161                     break;
9162                 case 6:
9163                     framerLaneXbar = 0x10;
9164                     break;
9165                 case 8:
9166                     framerLaneXbar = 0x00;
9167                     break;
9168                 case 9:
9169                     framerLaneXbar = 0x40;
9170                     break;
9171                 case 10:
9172                     framerLaneXbar = 0x40;
9173                     break;
9174                 case 12:
9175                     framerLaneXbar = 0x40;
9176                     break;
9177                 case 15:
9178                     framerLaneXbar = 0xE4;
9179                     break;
9180                 default:
9181                     /* default to valid setting for all Lanes */
9182                     framerLaneXbar = 0xE4;
9183                     break;
9184             }
9185         }
9186     }
9187 
9188     /* Framer: Set Lane Crossbar */
9189     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_LANE_XBAR_SEL, framerLaneXbar);
9190 
9191     if (ML == 24)
9192     {
9193         /* Framer: Clear ADC Xbar channel auto switch */
9194         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_CONFIG_LOOPBACK_XBAR_REV, 0x00);
9195     }
9196     else
9197     {
9198         /* Framer: Set ADC Xbar channel auto switch */
9199         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_CONFIG_LOOPBACK_XBAR_REV, 0x04);
9200     }
9201 
9202     /* enabling the SYSREF for relink if newSysrefOnRelink is set */
9203     if (device->rx->framer->newSysrefOnRelink)
9204     {
9205         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_FRAMER_SYSREF_FIFO_EN, 0x01, 0x40, 6);
9206     }
9207 
9208     /* enabling auto channel if the enableAutoChanXbar structure member is set */
9209     if (device->rx->framer->enableAutoChanXbar)
9210     {
9211         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_FRAMER_CONFIG_LOOPBACK_XBAR_REV, 0x01, 0x04, 2);
9212     }
9213 
9214     /* determining F octets per frame based on 2*M/L */
9215     framerConfigF = (uint8_t)(2 * (device->rx->framer->M / L));
9216 
9217     /* Framer: Soft Reset */
9218     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_RESET, 0x03);
9219 
9220     /* Framer: Clear Soft Reset */
9221     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_RESET, 0x00);
9222 
9223     /* Framer: Set F (Octets in Frame) */
9224     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_CONFIG_F, framerConfigF);
9225 
9226     /* Framer: Enable framer clock and lane clocks */
9227     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_FRAMER_CLK_EN, 0x03, 0x03, 0);
9228 
9229     /* Set Framer lane FIFO enable for each lane enabled */
9230     fifoLaneEnable = (((device->rx->framer->serializerLanesEnabled & 0x0F) << 4) | 0x01);
9231 
9232     /* Framer: Enable Lane FIFOs */
9233     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_LANE_CTL, fifoLaneEnable);
9234 
9235     /* Setup submap registers */
9236     SUBCLASSV = 1; /* JESD subclass 1 */
9237     JESDV = 1; /* Version: JESD204B */
9238     DID = device->rx->framer->deviceId;
9239     BID = device->rx->framer->bankId;
9240     LID0 = device->rx->framer->lane0Id;
9241     LID1 = device->rx->framer->lane0Id + 1;
9242     LID2 = device->rx->framer->lane0Id + 2;
9243     LID3 = device->rx->framer->lane0Id + 3;
9244 
9245     CS = 0;
9246     N = 0x0F;
9247     Np = 0x0F;
9248     S = 0;
9249     CF = 0;
9250     HD = 0;
9251     K = device->rx->framer->K - 1;
9252     FramerL = L - 1;
9253     FramerM = device->rx->framer->M - 1;
9254     FramerF = (uint8_t)(2 * device->rx->framer->M / L) - 1;
9255 
9256     if (ML == 11)
9257     {
9258         regE0 = 0x01;
9259         regE2 = 0x01;
9260     }
9261     else if (ML == 12)
9262     {
9263         regE0 = 0x01;
9264         regE2 = 0x03;
9265         HD = 0x01;
9266     }
9267     else if (ML == 21)
9268     {
9269         regE0 = 0x03;
9270         regE2 = 0x01;
9271     }
9272     else if (ML == 22)
9273     {
9274         regE0 = 0x03;
9275         regE2 = 0x03;
9276     }
9277     else if (ML == 24)
9278     {
9279         regE0 = 0x05;
9280         regE2 = 0x0F;
9281         HD = 0x01;
9282     }
9283     else if (ML == 41)
9284     {
9285         regE0 = 0x0F;
9286         regE2 = 0x01;
9287     }
9288     else if (ML == 42)
9289     {
9290         regE0 = 0x0F;
9291         regE2 = 0x05;
9292     }
9293     else if (ML == 44)
9294     {
9295         regE0 = 0x0F;
9296         regE2 = 0x0F;
9297     }
9298     else
9299     {
9300         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_FRAMER_INV_M_PARM, getMykonosErrorMessage(MYKONOS_ERR_FRAMER_INV_M_PARM));
9301         return MYKONOS_ERR_FRAMER_INV_M_PARM;
9302     }
9303 
9304     /* setting K offset for framer */
9305     if (device->rx->framer->lmfcOffset < device->rx->framer->K)
9306     {
9307         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_LMFC_K_OFFSET, device->rx->framer->lmfcOffset);
9308     }
9309     else
9310     {
9311         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_FRAMER_INV_K_OFFSET_PARAM,
9312                 getMykonosErrorMessage(MYKONOS_ERR_FRAMER_INV_K_OFFSET_PARAM));
9313         return MYKONOS_ERR_FRAMER_INV_K_OFFSET_PARAM;
9314     }
9315 
9316     subaddr[0] = 0x00;
9317     subdata[0] = (DID & 0xFF); /* Device ID */
9318     subaddr[1] = 0x01;
9319     subdata[1] = (BID & 0x0F); /* Bank ID */
9320     subaddr[2] = 0x02;
9321     subdata[2] = (LID0 & 0x1F); /* Lane 0 ID */
9322     subaddr[3] = 0x03;
9323     subdata[3] = (uint8_t)(device->rx->framer->scramble << 7) | (FramerL & 0x1F); /* [7] Scramble, #Lanes[4:0]-1 */
9324     subaddr[4] = 0x04;
9325     subdata[4] = (FramerF & 0xFF); /* F[7:0]-1 */
9326     subaddr[5] = 0x05;
9327     subdata[5] = (K & 0x1F); /* K[4:0]-1 */
9328     subaddr[6] = 0x06;
9329     subdata[6] = (FramerM & 0xFF); /* M[7:0]-1 */
9330     subaddr[7] = 0x07;
9331     subdata[7] = ((CS & 0x3) << 6) | (N & 0x1F); /* [7:6] = CS[1:0], N[4:0]-1 */
9332     subaddr[8] = 0x08;
9333     subdata[8] = ((SUBCLASSV & 7) << 5) | (Np & 0x1F); /* NP[4:0] -1 */
9334     subaddr[9] = 0x09;
9335     subdata[9] = ((JESDV & 7) << 5) | (S & 0x1F); /* S[4:0]-1 */
9336     subaddr[10] = 0x0A;
9337     subdata[10] = ((HD & 1) << 7) | (CF & 0x1F); /* [7] = HD, CF[4:0] */
9338     subaddr[11] = 0x0B;
9339     subdata[11] = 0x00; /* reserved */
9340     subaddr[12] = 0x0C;
9341     subdata[12] = 0x00; /* reserved */
9342 
9343     CheckSum = (DID & 0xFF) + (BID & 0xF) + (LID0 & 0x1F) + (device->rx->framer->scramble) + (FramerL & 0x1F) + (FramerF & 0xFF) + (K & 0x1F) + (FramerM & 0xFF)
9344             + (CS & 0x3) + (N & 0x1F) + (Np & 0x1F) + (S & 0x1F) + (HD & 1) + (CF & 0x1F) + (SUBCLASSV & 7) + (JESDV & 7);
9345 
9346     /* Checksum Lane 0 */
9347     subaddr[13] = 0x0D;
9348     subdata[13] = CheckSum & 0xFF;
9349 
9350     /* in JESD204B ML=42 case, framer ip lanes 0 and 2 are used, write lane 1 id and checksum to ip lane 2 regs */
9351     if (ML == 42)
9352     {
9353         /* Lane 1 ID */
9354         subaddr[14] = 0x1A;
9355         subdata[14] = LID1;
9356 
9357         CheckSum = (DID & 0xFF) + (BID & 0xF) + (LID1 & 0x1F) + (device->rx->framer->scramble) + (FramerL & 0x1F) + (FramerF & 0xFF) + (K & 0x1F) + (FramerM & 0xFF)
9358                 + (CS & 0x3) + (N & 0x1F) + (Np & 0x1F) + (S & 0x1F) + (HD & 1) + (CF & 0x1F) + (SUBCLASSV & 7) + (JESDV & 7);
9359 
9360         /* Checksum Lane 1 */
9361         subaddr[15] = 0x1D;
9362         subdata[15] = CheckSum & 0xFF;
9363     }
9364     else
9365     {
9366         /* Lane 1 ID */
9367         subaddr[14] = 0x12;
9368         subdata[14] = LID1;
9369 
9370         CheckSum = (DID & 0xFF) + (BID & 0xF) + (LID1 & 0x1F) + (device->rx->framer->scramble) + (FramerL & 0x1F) + (FramerF & 0xFF) + (K & 0x1F) + (FramerM & 0xFF)
9371                 + (CS & 0x3) + (N & 0x1F) + (Np & 0x1F) + (S & 0x1F) + (HD & 1) + (CF & 0x1F) + (SUBCLASSV & 7) + (JESDV & 7);
9372 
9373         /* Checksum Lane 1 */
9374         subaddr[15] = 0x15;
9375         subdata[15] = CheckSum & 0xFF;
9376 
9377         /* Lane 2 ID */
9378         subaddr[16] = 0x1A;
9379         subdata[16] = LID2;
9380 
9381         CheckSum = (DID & 0xFF) + (BID & 0xF) + (LID2 & 0x1F) + (device->rx->framer->scramble) + (FramerL & 0x1F) + (FramerF & 0xFF) + (K & 0x1F) + (FramerM & 0xFF)
9382                 + (CS & 0x3) + (N & 0x1F) + (Np & 0x1F) + (S & 0x1F) + (HD & 1) + (CF & 0x1F) + (SUBCLASSV & 7) + (JESDV & 7);
9383 
9384         /* Checksum Lane 2 */
9385         subaddr[17] = 0x1D;
9386         subdata[17] = CheckSum & 0xFF;
9387 
9388         /* Lane 3 ID */
9389         subaddr[18] = 0x22;
9390         subdata[18] = LID3;
9391 
9392         CheckSum = (DID & 0xFF) + (BID & 0xF) + (LID3 & 0x1F) + (device->rx->framer->scramble) + (FramerL & 0x1F) + (FramerF & 0xFF) + (K & 0x1F) + (FramerM & 0xFF)
9393                 + (CS & 0x3) + (N & 0x1F) + (Np & 0x1F) + (S & 0x1F) + (HD & 1) + (CF & 0x1F) + (SUBCLASSV & 7) + (JESDV & 7);
9394 
9395         subaddr[19] = 0x25;
9396         subdata[19] = CheckSum & 0xFF;
9397     }
9398 
9399     subaddr[20] = 0xE0;
9400     subdata[20] = regE0; /* Enable converter n logic */
9401     subaddr[21] = 0xE2;
9402     subdata[21] = regE2; /* Enable Lane n logic */
9403     subaddr[22] = 0xE4;
9404     subdata[22] = 0x00;
9405     subaddr[23] = 0xE6;
9406     subdata[23] = 0x00;
9407     subaddr[24] = 0xF0;
9408     subdata[24] = 0x00; /* #multiframes in ILAS */
9409     subaddr[25] = 0xF2;
9410     subdata[25] = 0x00;
9411     subaddr[26] = 0xF3;
9412     subdata[26] = 0x00;
9413     subaddr[27] = 0xF4;
9414     subdata[27] = 0x00;
9415     subaddr[28] = 0xC0;
9416     subdata[28] = 0x03; /* Framer enable, both sides perform lane sync */
9417 
9418     for (i = 0; i <= 28; i++)
9419     {
9420         /* Set framer sub register map address */
9421         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_ADDR, subaddr[i]);
9422 
9423         /* Set framer sub register map data word */
9424         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_DATA, subdata[i]);
9425 
9426         /* Write enable */
9427         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_WRITE_EN, 0x01);
9428     }
9429 
9430     if (device->rx->framer->externalSysref > 0)
9431     {
9432         /* Framer: Enable lane FIFO sync (Enable CGS) */
9433         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_SYSREF_FIFO_EN, 0x30);
9434     }
9435     else
9436     {
9437         /* Framer: Enable lane FIFO sync (Enable CGS) */
9438         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_SYSREF_FIFO_EN, 0x10);
9439     }
9440 
9441     return MYKONOS_ERR_OK;
9442 }
9443 
9444 /**
9445  * \brief Sets up the JESD204B OBSRX Framer
9446  *
9447  * <B>Dependencies</B>
9448  * - device->rxChannels
9449  * - device->spiSettings->chipSelectIndex
9450  * - device->obsRx->framer->bankId
9451  * - device->obsRx->framer->M
9452  * - device->obsRx->framer->serializerLanesEnabled
9453  * - device->obsRx->framer->externalSysref
9454  * - device->spiSettings
9455  * - device->obsRx->framer->deviceId
9456  * - device->obsRx->framer->lane0Id
9457  * - device->obsRx->framer->K
9458  * - device->obsRx->framer->lmfcOffset
9459  * - device->obsRx->framer->scramble
9460  * - device->obsRx->framer->obsRxSyncbSelect
9461  *
9462  * \param device Pointer to the device settings structure
9463  *
9464  * \retval MYKONOS_ERR_OK Function completed successfully
9465  * \retval MYKONOS_ERR_OBSRX_FRAMER_INV_REAL_IF_DATA_PARM M parameter can only be 1 when real IF data mode is enabled
9466  * \retval MYKONOS_ERR_OBSRX_FRAMER_INV_M_PARM ObsRx Framer M parameter can only be 1 or 2
9467  * \retval MYKONOS_ERR_OBSRX_FRAMER_INV_BANKID_PARM Invalid BankId (0-15)
9468  * \retval MYKONOS_ERR_OBSRX_FRAMER_INV_LANEID_PARM Invalid lane0Id (0-31)
9469  * \retval MYKONOS_ERR_OBSRXFRAMER_INV_FK_PARAM Invalid F*K value (F * K must be > 20 and divisible by 4)
9470  * \retval MYKONOS_ERR_OBSRX_FRAMER_INV_K_OFFSET_PARAM Invalid K offset, must be less than K
9471  */
MYKONOS_setupJesd204bObsRxFramer(mykonosDevice_t * device)9472 mykonosErr_t MYKONOS_setupJesd204bObsRxFramer(mykonosDevice_t *device)
9473 {
9474     uint8_t i = 0;
9475     uint8_t laneFifoEnable = 0;
9476     uint8_t L = 1;
9477     uint8_t ML = 2;
9478     uint8_t framerConfigF = 0;
9479 
9480     uint8_t subaddr[29] = {0}; /* holds address to framer sub register map */
9481     uint8_t subdata[29] = {0}; /* holds data for framer sub register map */
9482 
9483     /* Setup submap registers */
9484     uint8_t SUBCLASSV = 1; /* JESD subclass 1 */
9485     uint8_t JESDV = 1; /* Version: JESD204B */
9486     uint8_t DID = 0;
9487     uint8_t BID = 0;
9488     uint8_t LID0 = 0;
9489     uint8_t LID1 = 1;
9490     uint8_t LID2 = 2;
9491     uint8_t LID3 = 3;
9492     uint8_t CS = 0;
9493     uint8_t N = 0x0F;
9494     uint8_t Np = 0x0F;
9495     uint8_t S = 0;
9496     uint8_t CF = 0;
9497     uint8_t K = 31;
9498     uint8_t HD = 0;
9499     uint8_t FramerL = 1;
9500     uint8_t FramerM = 2;
9501     uint8_t FramerF = 1;
9502     uint8_t framerADC_XBar = 0xE4;
9503     uint8_t regE0 = 0;
9504     uint8_t regE2 = 0;
9505     uint8_t framerLaneXbar = 0xE4;
9506     uint16_t CheckSum = 0;
9507     uint16_t FK = 0;
9508 
9509 #if (MYKONOS_VERBOSE == 1)
9510     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setupJesd204bObsRxFramer()\n");
9511 #endif
9512 
9513     if (device->obsRx->framer->M == 1 && !(device->obsRx->realIfData))
9514     {
9515         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBSRX_FRAMER_INV_REAL_IF_DATA_PARM,
9516                 getMykonosErrorMessage(MYKONOS_ERR_OBSRX_FRAMER_INV_REAL_IF_DATA_PARM));
9517         return MYKONOS_ERR_OBSRX_FRAMER_INV_REAL_IF_DATA_PARM;
9518     }
9519 
9520     if (device->obsRx->framer->M != 1 && device->obsRx->framer->M != 2)
9521     {
9522         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBSRX_FRAMER_INV_M_PARM,
9523                 getMykonosErrorMessage(MYKONOS_ERR_OBSRX_FRAMER_INV_M_PARM));
9524         return MYKONOS_ERR_OBSRX_FRAMER_INV_M_PARM;
9525     }
9526 
9527     if (device->obsRx->framer->bankId > 15)
9528     {
9529         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBSRX_FRAMER_INV_BANKID_PARM,
9530                 getMykonosErrorMessage(MYKONOS_ERR_OBSRX_FRAMER_INV_BANKID_PARM));
9531         return MYKONOS_ERR_OBSRX_FRAMER_INV_BANKID_PARM;
9532     }
9533 
9534     /* no need to check deviceId, its range is full uint8_t range */
9535     if (device->obsRx->framer->lane0Id > 31)
9536     {
9537         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBSRX_FRAMER_INV_LANEID_PARM,
9538                 getMykonosErrorMessage(MYKONOS_ERR_OBSRX_FRAMER_INV_LANEID_PARM));
9539         return MYKONOS_ERR_OBSRX_FRAMER_INV_LANEID_PARM;
9540     }
9541 
9542     //count number of lanes
9543     L = 0;
9544     ML = 0;
9545 
9546     for (i = 0; i < 4; i++)
9547     {
9548         L += ((device->obsRx->framer->serializerLanesEnabled >> i) & 0x01);
9549     }
9550 
9551     ML = (uint8_t)(device->obsRx->framer->M * 10 + L);
9552 
9553     if (L == 0)
9554     {
9555         /* Disable framer and return successfully */
9556         /* Disable framer clock and lane clocks */
9557         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_CLK_EN, 0, 0x03, 0);
9558 
9559         /* Disable lane FIFO enables */
9560         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_LANE_CTL, 0, 0xF0, 4);
9561         return MYKONOS_ERR_OK;
9562     }
9563 
9564     FK = (uint16_t)(device->obsRx->framer->K * 2 * device->obsRx->framer->M / L);
9565     if (FK < 20 || FK > 256 || FK % 4 != 0)
9566     {
9567         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBSRXFRAMER_INV_FK_PARAM,
9568                 getMykonosErrorMessage(MYKONOS_ERR_OBSRXFRAMER_INV_FK_PARAM));
9569         return MYKONOS_ERR_OBSRXFRAMER_INV_FK_PARAM;
9570     }
9571 
9572     if (device->obsRx->framer->externalSysref == 0)
9573     {
9574         /* Framer: Generate SYSREF internally */
9575         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_TEST_CNTR_CTL, 0x20);
9576     }
9577 
9578     /* Framer: Set ADC Crossbar */
9579     framerADC_XBar = 0xB1;
9580     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_ADC_XBAR_SEL, framerADC_XBar);
9581 
9582     if (device->obsRx->framer->enableManualLaneXbar == 1)
9583     {
9584         framerLaneXbar = device->obsRx->framer->serializerLaneCrossbar;
9585     }
9586     else
9587     {
9588         if (ML == 42)
9589         {
9590             /* uses framer outputs 0 and 2 instead of 0 and 1...fix framer lane XBar */
9591             /* only 2 lane cases here */
9592             switch ((device->obsRx->framer->serializerLanesEnabled & 0x0F))
9593             {
9594                 case 3:
9595                     framerLaneXbar = 0x08;
9596                     break;
9597                 case 5:
9598                     framerLaneXbar = 0x20;
9599                     break;
9600                 case 6:
9601                     framerLaneXbar = 0x20;
9602                     break;
9603                 case 9:
9604                     framerLaneXbar = 0x80;
9605                     break;
9606                 case 10:
9607                     framerLaneXbar = 0x80;
9608                     break;
9609                 case 12:
9610                     framerLaneXbar = 0x80;
9611                     break;
9612                 default:
9613                     /* default to valid setting for Lane 0 */
9614                     framerLaneXbar = 0x08;
9615                     break;
9616             }
9617         }
9618         else
9619         {
9620             switch ((device->obsRx->framer->serializerLanesEnabled & 0x0F))
9621             {
9622                 /* all 4 lanes get framer 0 output */
9623                 case 1:
9624                     framerLaneXbar = 0x00;
9625                     break;
9626                 case 2:
9627                     framerLaneXbar = 0x00;
9628                     break;
9629                 case 3:
9630                     framerLaneXbar = 0x04;
9631                     break;
9632                 case 4:
9633                     framerLaneXbar = 0x00;
9634                     break;
9635                 case 5:
9636                     framerLaneXbar = 0x10;
9637                     break;
9638                 case 6:
9639                     framerLaneXbar = 0x10;
9640                     break;
9641                 case 8:
9642                     framerLaneXbar = 0x00;
9643                     break;
9644                 case 9:
9645                     framerLaneXbar = 0x40;
9646                     break;
9647                 case 10:
9648                     framerLaneXbar = 0x40;
9649                     break;
9650                 case 12:
9651                     framerLaneXbar = 0x40;
9652                     break;
9653                 case 15:
9654                     framerLaneXbar = 0xE4;
9655                     break;
9656                 default:
9657                     /* default to valid setting for all Lanes */
9658                     framerLaneXbar = 0xE4;
9659                     break;
9660             }
9661         }
9662     }
9663 
9664     /* Framer: set Lane Crossbar */
9665     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_LANE_XBAR_SEL, framerLaneXbar);
9666 
9667     /* Framer: determine the framerConfigF value (2*M/L) */
9668     framerConfigF = (uint8_t)(2 * (device->obsRx->framer->M/L));
9669 
9670     /* Framer: Soft Reset */
9671     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_RESET, 0x03);
9672 
9673     /* Framer: Clear Soft Reset */
9674     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_RESET, 0x00);
9675 
9676     /* Framer: Set F (Octets in Frame) */
9677     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_CONFIG_F, framerConfigF);
9678 
9679     /* Framer: Enable framer clock and lane clocks */
9680     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_CLK_EN, 0x03, 0x03, 0);
9681 
9682     /* Set Framer lane FIFO enable for each lane enabled */
9683     laneFifoEnable = (uint8_t)(((device->obsRx->framer->serializerLanesEnabled & 0x0F) << 4) | 0x01);
9684 
9685     /* Framer: Enable Lane FIFOs */
9686     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_LANE_CTL, laneFifoEnable);
9687 
9688     /* enabling the SYSREF for relink if newSysrefOnRelink is set */
9689     if (device->obsRx->framer->newSysrefOnRelink)
9690     {
9691         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_SYSREF_FIFO_EN, 0x01, 0x40, 6);
9692     }
9693 
9694     /* enabling auto channel if the enableAutoChanXbar structure member is set */
9695     if (device->obsRx->framer->enableAutoChanXbar)
9696     {
9697         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_CONFIG_LOOPBACK_XBAR_REV, 0x01, 0x04, 2);
9698     }
9699 
9700     /* Setup submap registers */
9701     SUBCLASSV = 1; /* JESD subclass 1 */
9702     JESDV = 1; /* Version: JESD204B */
9703     DID = device->obsRx->framer->deviceId;
9704     BID = device->obsRx->framer->bankId;
9705     LID0 = device->obsRx->framer->lane0Id;
9706     LID1 = device->obsRx->framer->lane0Id + 1;
9707     LID2 = device->obsRx->framer->lane0Id + 2;
9708     LID3 = device->obsRx->framer->lane0Id + 3;
9709 
9710     CS = 0;
9711     N = 0x0F;
9712     Np = 0x0F;
9713     S = 0;
9714     CF = 0;
9715     K = device->obsRx->framer->K - 1;
9716     HD = 0;
9717     FramerL = L - 1;
9718     FramerM = device->obsRx->framer->M - 1;
9719     FramerF = (uint8_t)((2*device->obsRx->framer->M/L) - 1);
9720 
9721     if (ML == 11)
9722     {
9723         regE0 = 0x1;
9724         regE2 = 0x1;
9725     }
9726     else if (ML == 12)
9727     {
9728         regE0 = 0x1;
9729         regE2 = 0x3;
9730         HD = 1;
9731     }
9732     else if (ML == 21)
9733     {
9734         regE0 = 0x3;
9735         regE2 = 0x1;
9736     }
9737     else if (ML == 22)
9738     {
9739         regE0 = 0x3;
9740         regE2 = 0x3;
9741     }
9742     else
9743     {
9744         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBSRX_FRAMER_INV_M_PARM,
9745                 getMykonosErrorMessage(MYKONOS_ERR_OBSRX_FRAMER_INV_M_PARM));
9746         return MYKONOS_ERR_OBSRX_FRAMER_INV_M_PARM;
9747     }
9748 
9749     /* setting K offset for framer */
9750     if (device->obsRx->framer->lmfcOffset < device->rx->framer->K)
9751     {
9752         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_LMFC_K_OFFSET, device->obsRx->framer->lmfcOffset);
9753     }
9754     else
9755     {
9756         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBSRX_FRAMER_INV_K_OFFSET_PARAM,
9757                 getMykonosErrorMessage(MYKONOS_ERR_OBSRX_FRAMER_INV_K_OFFSET_PARAM));
9758         return MYKONOS_ERR_OBSRX_FRAMER_INV_K_OFFSET_PARAM;
9759     }
9760 
9761     subaddr[0] = 0x00;
9762     subdata[0] = (DID & 0xFF); /* Device ID */
9763     subaddr[1] = 0x01;
9764     subdata[1] = (BID & 0x0F); /* Bank ID */
9765     subaddr[2] = 0x02;
9766     subdata[2] = (LID0 & 0x1F); /* Lane 0 ID */
9767     subaddr[3] = 0x03;
9768     subdata[3] = (uint8_t)(device->obsRx->framer->scramble << 7) | (FramerL & 0x1F); /* [7] Scramble, #Lanes[4:0]-1 */
9769     subaddr[4] = 0x04;
9770     subdata[4] = (FramerF & 0xFF); /* F[7:0]-1 */
9771     subaddr[5] = 0x05;
9772     subdata[5] = (K & 0x1F); /* K[4:0]-1 */
9773     subaddr[6] = 0x06;
9774     subdata[6] = (FramerM & 0xFF); /* M[7:0]-1 */
9775     subaddr[7] = 0x07;
9776     subdata[7] = ((CS & 0x3) << 6) | (N & 0x1F); /* [7:6] = CS[1:0], N[4:0]-1 */
9777     subaddr[8] = 0x08;
9778     subdata[8] = ((SUBCLASSV & 7) << 5) | (Np & 0x1F); /* NP[4:0] -1 */
9779     subaddr[9] = 0x09;
9780     subdata[9] = ((JESDV & 7) << 5) | (S & 0x1F); /* S[4:0]-1 */
9781     subaddr[10] = 0x0a;
9782     subdata[10] = ((HD & 1) << 7) | (CF & 0x1F); /* [7] = HD, CF[4:0] */
9783     subaddr[11] = 0x0b;
9784     subdata[11] = 0x00; /* reserved */
9785     subaddr[12] = 0x0c;
9786     subdata[12] = 0x00; /* reserved */
9787 
9788     CheckSum = (DID & 0xFF) + (BID & 0xF) + (LID0 & 0x1F) + (device->obsRx->framer->scramble) + (FramerL & 0x1F) + (FramerF & 0xFF) + (K & 0x1F) + (FramerM & 0xFF)
9789             + (CS & 0x3) + (N & 0x1F) + (Np & 0x1F) + (S & 0x1F) + (HD & 1) + (CF & 0x1F) + (SUBCLASSV & 7) + (JESDV & 7);
9790 
9791     /* Checksum Lane 0 */
9792     subaddr[13] = 0x0d;
9793     subdata[13] = CheckSum & 0xFF;
9794 
9795     /* Lane 1 ID */
9796     subaddr[14] = 0x12;
9797     subdata[14] = LID1;
9798 
9799     CheckSum = (DID & 0xFF) + (BID & 0xF) + (LID1 & 0x1F) + (device->obsRx->framer->scramble) + (FramerL & 0x1F) + (FramerF & 0xFF) + (K & 0x1F) + (FramerM & 0xFF)
9800             + (CS & 0x3) + (N & 0x1F) + (Np & 0x1F) + (S & 0x1F) + (HD & 1) + (CF & 0x1F) + (SUBCLASSV & 7) + (JESDV & 7);
9801 
9802     /* Checksum Lane 1 */
9803     subaddr[15] = 0x15;
9804     subdata[15] = CheckSum & 0xFF;
9805 
9806     /* Lane 2 ID */
9807     subaddr[16] = 0x1a;
9808     subdata[16] = LID2;
9809 
9810     CheckSum = (DID & 0xFF) + (BID & 0xF) + (LID2 & 0x1F) + (device->obsRx->framer->scramble) + (FramerL & 0x1F) + (FramerF & 0xFF) + (K & 0x1F) + (FramerM & 0xFF)
9811             + (CS & 0x3) + (N & 0x1F) + (Np & 0x1F) + (S & 0x1F) + (HD & 1) + (CF & 0x1F) + (SUBCLASSV & 7) + (JESDV & 7);
9812 
9813     /* Checksum Lane 2 */
9814     subaddr[17] = 0x1d;
9815     subdata[17] = CheckSum & 0xFF;
9816 
9817     /* Lane 3 ID */
9818     subaddr[18] = 0x22;
9819     subdata[18] = LID3;
9820 
9821     CheckSum = (DID & 0xFF) + (BID & 0xF) + (LID3 & 0x1F) + (device->obsRx->framer->scramble) + (FramerL & 0x1F) + (FramerF & 0xFF) + (K & 0x1F) + (FramerM & 0xFF)
9822             + (CS & 0x3) + (N & 0x1F) + (Np & 0x1F) + (S & 0x1F) + (HD & 1) + (CF & 0x1F) + (SUBCLASSV & 7) + (JESDV & 7);
9823 
9824     subaddr[19] = 0x25;
9825     subdata[19] = CheckSum & 0xFF;
9826 
9827     subaddr[20] = 0xe0;
9828     subdata[20] = regE0; /* Enable converter n logic */
9829     subaddr[21] = 0xe2;
9830     subdata[21] = regE2; /* Enable Lane n logic */
9831     subaddr[22] = 0xe4;
9832     subdata[22] = 0x00;
9833     subaddr[23] = 0xe6;
9834     subdata[23] = 0x00;
9835     subaddr[24] = 0xf0;
9836     subdata[24] = 0x00; /* #multiframes in ILAS */
9837     subaddr[25] = 0xf2;
9838     subdata[25] = 0x00;
9839     subaddr[26] = 0xf3;
9840     subdata[26] = 0x00;
9841     subaddr[27] = 0xf4;
9842     subdata[27] = 0x00;
9843     subaddr[28] = 0xc0;
9844     subdata[28] = 0x03; /* Framer enable, both sides perform lane sync */
9845 
9846     for (i = 0; i <= 28; i++)
9847     {
9848         /* Set framer sub register map address */
9849         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_ADDR, subaddr[i]);
9850 
9851         /* Set framer sub register map data word */
9852         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_DATA, subdata[i]);
9853 
9854         /* Write enable */
9855         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_WRITE_EN, 0x01);
9856     }
9857 
9858     if (device->obsRx->framer->externalSysref > 0)
9859     {
9860         /* Framer: Enable lane FIFO sync (Enable CGS) */
9861         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_SYSREF_FIFO_EN, 0x30);
9862     }
9863     else
9864     {
9865         /* Framer: Enable lane FIFO sync (Enable CGS) */
9866         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_SYSREF_FIFO_EN, 0x10);
9867     }
9868 
9869     return MYKONOS_ERR_OK;
9870 }
9871 
9872 /**
9873  * \brief Enables/Disables the JESD204B Rx Framer
9874  *
9875  * This function is normally not necessary.  In the event that the link needs to be reset, this
9876  * function allows the Rx framer to be disabled and re-enabled.
9877  *
9878  * <B>Dependencies</B>
9879  * - device->spiSettings
9880  * - device->rx->framer->serializerLanesEnabled
9881  *
9882  * \param device is a pointer to the device settings structure
9883  * \param enable 0 = Disable the selected framer, 1 = enable the selected framer link
9884  *
9885  * \retval MYKONOS_ERR_OK Function completed successfully
9886  * \retval MYKONOS_ERR_ENFRAMERLINK_INV_LANESEN_PARM Invalid serializerLanesEnabled parameter in device data structure
9887  */
MYKONOS_enableRxFramerLink(mykonosDevice_t * device,uint8_t enable)9888 mykonosErr_t MYKONOS_enableRxFramerLink(mykonosDevice_t *device, uint8_t enable)
9889 {
9890     uint8_t enableLink = 0;
9891 
9892 #if (MYKONOS_VERBOSE == 1)
9893     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enableFramerLink()\n");
9894 #endif
9895 
9896     enableLink = (enable > 0) ? 1 : 0;
9897 
9898     if (enableLink)
9899     {
9900         /* Power Up serializer lanes */
9901         if (device->rx->framer->serializerLanesEnabled > 15)
9902         {
9903             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ENFRAMERLINK_INV_LANESEN_PARM,
9904                     getMykonosErrorMessage(MYKONOS_ERR_ENFRAMERLINK_INV_LANESEN_PARM));
9905             return MYKONOS_ERR_ENFRAMERLINK_INV_LANESEN_PARM;
9906         }
9907 
9908         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_SERIALIZER_CTL_1, ((~device->rx->framer->serializerLanesEnabled) & 0x0F),
9909                 device->rx->framer->serializerLanesEnabled, 0);
9910 
9911         /* Enable Clocks to Framer */
9912         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_FRAMER_CLK_EN, 3, 0x03, 0);
9913 
9914         /* Release reset to framer and lane FIFOs */
9915         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_RESET, 0x00);
9916     }
9917     else
9918     {
9919         /* Disable Link */
9920         /* Hold Rx framer in reset */
9921         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_RESET, 0x03);
9922 
9923         /* Disable Clocks to Framer */
9924         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_FRAMER_CLK_EN, 0, 0x03, 0);
9925 
9926         /* Power down serializer lanes */
9927         if (device->rx->framer->serializerLanesEnabled > 15)
9928         {
9929             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ENFRAMERLINK_INV_LANESEN_PARM,
9930                     getMykonosErrorMessage(MYKONOS_ERR_ENFRAMERLINK_INV_LANESEN_PARM));
9931             return MYKONOS_ERR_ENFRAMERLINK_INV_LANESEN_PARM;
9932         }
9933 
9934         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_SERIALIZER_CTL_1, device->rx->framer->serializerLanesEnabled, device->rx->framer->serializerLanesEnabled, 0);
9935     }
9936 
9937     return MYKONOS_ERR_OK;
9938 }
9939 
9940 /**
9941  * \brief Enables/Disables the JESD204B ObsRx Framer
9942  *
9943  * This function is normally not necessary.  In the event that the link needs to be reset, this
9944  * function allows the ObsRx framer to be disabled and re-enabled.
9945  *
9946  * <B>Dependencies</B>
9947  * - device->spiSettings
9948  * - device->obsRx->framer->serializerLanesEnabled
9949  *
9950  * \param device is a pointer to the device settings structure
9951  * \param enable 0 = Disable the selected framer, 1 = enable the selected framer link
9952  *
9953  * \retval MYKONOS_ERR_OK Function completed successfully
9954  * \retval MYKONOS_ERR_ENFRAMERLINK_INV_LANESEN_PARM Invalid serializerLanesEnabled parameter in device data structure (Valid 0-15)
9955  */
MYKONOS_enableObsRxFramerLink(mykonosDevice_t * device,uint8_t enable)9956 mykonosErr_t MYKONOS_enableObsRxFramerLink(mykonosDevice_t *device, uint8_t enable)
9957 {
9958     uint8_t enableLink = 0;
9959 
9960 #if (MYKONOS_VERBOSE == 1)
9961     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enableObsRxFramerLink()\n");
9962 #endif
9963 
9964     enableLink = (enable > 0) ? 1 : 0;
9965 
9966     if (enableLink)
9967     {
9968         /* Power Up serializer lanes */
9969         if (device->rx->framer->serializerLanesEnabled > 15)
9970         {
9971             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ENOBSFRAMERLINK_INV_LANESEN_PARM,
9972                     getMykonosErrorMessage(MYKONOS_ERR_ENOBSFRAMERLINK_INV_LANESEN_PARM));
9973             return MYKONOS_ERR_ENOBSFRAMERLINK_INV_LANESEN_PARM;
9974         }
9975 
9976         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_SERIALIZER_CTL_1, ((~device->obsRx->framer->serializerLanesEnabled) & 0x0F),
9977                 device->obsRx->framer->serializerLanesEnabled, 0);
9978 
9979         /* Enable Clocks to Framer */
9980         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_CLK_EN, 3, 0x03, 0);
9981 
9982         /* Release reset to framer and lane FIFOs */
9983         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_RESET, 0x00);
9984     }
9985     else
9986     {
9987         /* Disable Link */
9988         /* Hold Rx framer in reset */
9989         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_RESET, 0x03);
9990 
9991         /* Disable Clocks to Framer */
9992         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_CLK_EN, 0, 0x03, 0);
9993 
9994         /* Power down serializer lanes */
9995         if (device->obsRx->framer->serializerLanesEnabled > 15)
9996         {
9997             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ENOBSFRAMERLINK_INV_LANESEN_PARM,
9998                     getMykonosErrorMessage(MYKONOS_ERR_ENOBSFRAMERLINK_INV_LANESEN_PARM));
9999             return MYKONOS_ERR_ENOBSFRAMERLINK_INV_LANESEN_PARM;
10000         }
10001 
10002         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_SERIALIZER_CTL_1, device->obsRx->framer->serializerLanesEnabled,
10003                 device->obsRx->framer->serializerLanesEnabled, 0);
10004     }
10005 
10006     return MYKONOS_ERR_OK;
10007 }
10008 
10009 /**
10010  * \brief Sets up the JESD204B Deframer
10011  *
10012  * <B>Dependencies</B>
10013  * - device->spiSettings->chipSelectIndex
10014  * - device->tx->deframer->M
10015  * - device->tx->deframer->bankId
10016  * - device->tx->deframer->lane0Id
10017  * - device->tx->deframer->K
10018  * - device->tx->deframer->deserializerLanesEnabled
10019  * - device->tx->deframer->externalSysref
10020  * - device->tx->deframer->newSysrefOnRelink
10021  * - device->tx->deframer->enableAutoChanXbar
10022  * - device->tx->deframer->lmfcOffset
10023  * - device->tx->deframer->scramble
10024  *
10025  * \param device Pointer to device settings structure
10026  *
10027  * \retval MYKONOS_ERR_OK Function completed successfully
10028  * \retval MYKONOS_ERR_DEFRAMER_INV_M_PARM Invalid M parameter in deframer structure
10029  * \retval MYKONOS_ERR_DEFRAMER_INV_BANKID_PARM Invalid BankId parameter in deframer structure (Valid 0-15)
10030  * \retval MYKONOS_ERR_ERR_DEFRAMER_INV_LANEID_PARM Invalid Lane0Id parameter in deframer structure (Valid 0-31)
10031  * \retval MYKONOS_ERR_DEFRAMER_INV_K_PARAM Invalid K parameter in deframer structure (valid 1-32 with other constraints)
10032  * \retval MYKONOS_ERR_DEFRAMER_INV_FK_PARAM Invalid F*K parameter (Valid F*K > 20, F*K must be divisible by 4), K must be <= 32
10033  * \retval MYKONOS_ERR_DEFRAMER_INV_K_OFFSET_PARAM Invalid K offset parameter in deframer structure (must be less than K)
10034  */
MYKONOS_setupJesd204bDeframer(mykonosDevice_t * device)10035 mykonosErr_t MYKONOS_setupJesd204bDeframer(mykonosDevice_t *device)
10036 {
10037     uint8_t i = 0;
10038     uint8_t temp = 0;
10039     uint8_t reg080 = 0;
10040     uint8_t laneXbar = 0;
10041     uint8_t L = 0;
10042     uint8_t ML = 0;
10043 
10044     /* Setup submap registers */
10045     uint8_t SUBCLASSV = 1;
10046     uint8_t JESDV = 1;
10047     uint8_t DID = 0;
10048     uint8_t BID = 0;
10049     uint8_t LID0 = 0;
10050     uint8_t CS = 2; /* 2 control bits */
10051     uint8_t N = 0x0D; /* 14 bits */
10052     uint8_t Np = 0x0F; /* 16 bits */
10053     uint8_t S = 0;
10054     uint8_t CF = 0;
10055     uint8_t K = 0x1F;
10056     uint16_t FK = 0;
10057     uint8_t HD = 0; /* only one case has HD == 1 */
10058     uint8_t CTRLREG0 = 0;
10059     uint8_t DeframerL = 1;
10060     uint8_t DeframerM = 2;
10061     uint8_t DeframerF = 0;
10062     uint8_t CTRLREG1 = 0;
10063     uint8_t CTRLREG2 = 0;
10064     uint8_t DeframerLaneEnable = 0x00;
10065     uint16_t CheckSum = 0;
10066     uint8_t subaddr[25] = {0};
10067     uint8_t subdata[25] = {0};
10068 
10069     uint8_t deframerInput = 0;
10070     uint8_t lane = 0;
10071 
10072 #if (MYKONOS_VERBOSE == 1)
10073     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setupJesd204bDeframer()\n");
10074 #endif
10075 
10076     if (device->tx->deframer->M != 0 && device->tx->deframer->M != 2 && device->tx->deframer->M != 4)
10077     {
10078         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DEFRAMER_INV_M_PARM, getMykonosErrorMessage(MYKONOS_ERR_DEFRAMER_INV_M_PARM));
10079         return MYKONOS_ERR_DEFRAMER_INV_M_PARM;
10080     }
10081 
10082     if (device->tx->deframer->bankId > 15)
10083     {
10084         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DEFRAMER_INV_BANKID_PARM,
10085                 getMykonosErrorMessage(MYKONOS_ERR_DEFRAMER_INV_BANKID_PARM));
10086         return MYKONOS_ERR_DEFRAMER_INV_BANKID_PARM;
10087     }
10088 
10089     if (device->tx->deframer->lane0Id > 31)
10090     {
10091         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ERR_DEFRAMER_INV_LANEID_PARM,
10092                 getMykonosErrorMessage(MYKONOS_ERR_ERR_DEFRAMER_INV_LANEID_PARM));
10093         return MYKONOS_ERR_ERR_DEFRAMER_INV_LANEID_PARM;
10094     }
10095 
10096     //count number of lanes
10097     L = 0;
10098     ML = 0;
10099 
10100     for (i = 0; i < 4; i++)
10101     {
10102         L += ((device->tx->deframer->deserializerLanesEnabled >> i) & 0x01);
10103     }
10104 
10105     ML = (uint8_t)(device->tx->deframer->M * 10 + L);
10106 
10107     if (device->tx->deframer->K > 32)
10108     {
10109         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DEFRAMER_INV_K_PARAM,
10110                 getMykonosErrorMessage(MYKONOS_ERR_DEFRAMER_INV_K_PARAM));
10111         return MYKONOS_ERR_DEFRAMER_INV_K_PARAM;
10112     }
10113 
10114     FK = (uint16_t)(device->tx->deframer->K * 2 * device->tx->deframer->M / L);
10115 
10116     if (FK < 20 || FK > 256 || FK % 4 != 0)
10117     {
10118         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DEFRAMER_INV_FK_PARAM,
10119                 getMykonosErrorMessage(MYKONOS_ERR_DEFRAMER_INV_FK_PARAM));
10120         return MYKONOS_ERR_DEFRAMER_INV_FK_PARAM;
10121     }
10122 
10123     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_DEFRAMER_SYNC_REQ_RETIME, (device->tx->deframer->K - 1), 0x1F, 0x00);
10124 
10125     if (!device->tx->deframer->externalSysref)
10126     {
10127         /* Deframer: Generate SYSREF internally */
10128         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_TEST, 0x02);
10129     }
10130 
10131     /* enabling the SYSREF for relink if newSysrefOnRelink is set */
10132     if (device->tx->deframer->newSysrefOnRelink)
10133     {
10134         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_DEFRAMER_SYSREF_FIFO_EN, 0x01, 0x40, 6);
10135     }
10136 
10137     /* enabling auto channel if the enableAutoChanXbar structure member is set */
10138     if (device->tx->deframer->enableAutoChanXbar)
10139     {
10140         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_DEFRAMER_DET_FIFO_WR_STRT_DAC_XBAR_REV, 0x01, 0x04, 2);
10141     }
10142 
10143     /* Fix bad default bit to allow deterministic latency on deframer (Clear bit 4)*/
10144     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_DEFRAMER_DET_FIFO_WR_STRT_DAC_XBAR_REV, 0x00, 0x10, 4);
10145 
10146     /* Deframer: Set DAC Crossbar */
10147     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_DAC_XBAR_SEL, 0xB1);
10148 
10149     if (device->tx->deframer->enableManualLaneXbar == 1)
10150     {
10151         laneXbar = device->tx->deframer->deserializerLaneCrossbar;
10152     }
10153     else
10154     {
10155         /* Lane crossbar  - Allow user to reorder lanes in deframer->deserializerLaneCrossbar, but this code still */
10156         /* maps used lanes to deframer inputs */
10157         deframerInput = 0;
10158         for (lane = 0; lane < 4; lane++)
10159         {
10160             if ((device->tx->deframer->deserializerLanesEnabled >> lane) & 1)
10161             {
10162                 laneXbar |= (uint8_t)(((device->tx->deframer->deserializerLaneCrossbar >> (lane << 1)) & 3) << (deframerInput << 1));
10163                 deframerInput += 1;
10164             }
10165         }
10166 
10167         if (ML == 42)
10168         {
10169             /* M4L2 uses internal deframer ports 0 and 2 */
10170             /* swap bits 3:2 and 5:4, keep 1:0 and 7:6 in place */
10171             laneXbar = (laneXbar & 0xC3U) | ((laneXbar & 0x30) >> 2) | ((laneXbar & 0x0C) << 2);
10172         }
10173     }
10174 
10175     /* Deframer: Set Lane Crossbar */
10176     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_LANE_XBAR_SEL, laneXbar);
10177 
10178     //Find value for Framer F depending on M and L
10179     switch (ML)
10180     {
10181         case 21:
10182             reg080 = 0x04;
10183             break;
10184         case 22:
10185             reg080 = 0x22;
10186             break;
10187         case 24:
10188             reg080 = 0x41;
10189             break;
10190         case 41:
10191             reg080 = 0x18;
10192             break;
10193         case 42:
10194             reg080 = 0x34;
10195             break;
10196         case 44:
10197             reg080 = 0x52;
10198             break;
10199         default:
10200             reg080 = 0x04;
10201             break;
10202     }
10203 
10204     /* Deframer: Set F (Octets in Frame) */
10205     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_CONFIG_F, reg080);
10206 
10207     /* Deframer: Enable clocks and lane clocks */
10208     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_CLK_EN, 0x03);
10209 
10210     /* Set deframer lane FIFO enable for each lane enabled */
10211     temp = (device->tx->deframer->deserializerLanesEnabled & 0x0F);
10212 
10213     /* Deframer: Enable Lane FIFOs */
10214     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_LANE_FIFO_CTL, temp);
10215 
10216     /* Setup submap registers */
10217     SUBCLASSV = 1; /* JESD subclass 1 */
10218     JESDV = 1; /* Version: JESD204B */
10219     DID = device->tx->deframer->deviceId;
10220     BID = device->tx->deframer->bankId;
10221     LID0 = device->tx->deframer->lane0Id;
10222     CS = 2; /* 2 control bits */
10223     N = 0x0D; /* 14 bits */
10224     Np = 0x0F;
10225     S = 0;
10226     CF = 0;
10227     K = device->tx->deframer->K - 1;
10228     HD = 0; /* only one case has HD = 1 */
10229     CTRLREG0 = 1;
10230     DeframerL = L - 1;
10231     DeframerM = device->tx->deframer->M - 1;
10232     DeframerF = (uint8_t)((2*device->tx->deframer->M/L) - 1);
10233     CheckSum = 0;
10234 
10235     if (ML == 21)
10236     {
10237         CTRLREG1 = 4;
10238         CTRLREG2 = 0x14;
10239         DeframerLaneEnable = 1;
10240     }
10241     else if (ML == 22)
10242     {
10243         CTRLREG1 = 2;
10244         CTRLREG2 = 4;
10245         DeframerLaneEnable = 3;
10246     }
10247     else if (ML == 24)
10248     {
10249         HD = 1;
10250         CTRLREG1 = 1;
10251         CTRLREG2 = 0;
10252         DeframerLaneEnable = 0x0F;
10253     }
10254     else if (ML == 41)
10255     {
10256         CTRLREG1 = 8;
10257         CTRLREG2 = 0;
10258         DeframerLaneEnable = 1;
10259     }
10260     else if (ML == 42)
10261     {
10262         CTRLREG1 = 4;
10263         CTRLREG2 = 0;
10264         DeframerLaneEnable = 5;
10265     }
10266     else if (ML == 44)
10267     {
10268         CTRLREG1 = 2;
10269         CTRLREG2 = 0;
10270         DeframerLaneEnable = 0x0F;
10271     }
10272     else
10273     {
10274         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DEFRAMER_INV_M_PARM, getMykonosErrorMessage(MYKONOS_ERR_DEFRAMER_INV_M_PARM));
10275         return MYKONOS_ERR_DEFRAMER_INV_M_PARM;
10276     }
10277 
10278     /* LMFC offset limit check */
10279     if (device->tx->deframer->lmfcOffset < device->tx->deframer->K)
10280     {
10281         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_LMFC_K_OFFSET, device->tx->deframer->lmfcOffset);
10282     }
10283     else
10284     {
10285         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DEFRAMER_INV_K_OFFSET_PARAM,
10286                 getMykonosErrorMessage(MYKONOS_ERR_DEFRAMER_INV_K_OFFSET_PARAM));
10287         return MYKONOS_ERR_DEFRAMER_INV_K_OFFSET_PARAM;
10288     }
10289 
10290     subaddr[0] = 0x50;
10291     subdata[0] = DID & 0xFFU; /* Device ID */
10292     subaddr[1] = 0x51;
10293     subdata[1] = BID & 0x0F; /* Bank ID */
10294     subaddr[2] = 0x52;
10295     subdata[2] = LID0 & 0x1F; /* Lane 0 ID */
10296     subaddr[3] = 0x53;
10297     subdata[3] = (uint8_t)(device->tx->deframer->scramble << 7) | (DeframerL & 0x1F); /* [7] = Scramble Enable, #Lanes[4:0] */
10298     subaddr[4] = 0x54;
10299     subdata[4] = DeframerF & 0xFFU; /* F[7:0] */
10300     subaddr[5] = 0x55;
10301     subdata[5] = K & 0x1F; /* K[4:0] */
10302     subaddr[6] = 0x56;
10303     subdata[6] = DeframerM & 0xFFU; /* M[7:0] */
10304     subaddr[7] = 0x57;
10305     subdata[7] = ((CS & 0x3) << 6) | (N & 0x1F); /* [7:6] = CS[1:0], N[4:0] */
10306     subaddr[8] = 0x58;
10307     subdata[8] = ((SUBCLASSV & 7) << 5) | (Np & 0x1F); /* Np[4:0] */
10308     subaddr[9] = 0x59;
10309     subdata[9] = ((JESDV & 7) << 5) | (S & 0x1F); /* S[4:0] */
10310     subaddr[10] = 0x5A;
10311     subdata[10] = ((HD & 1) << 7) | (CF & 0x1F); /* [7]=HD, CF[4:0] */
10312     subaddr[11] = 0x5B;
10313     subdata[11] = 0x00; /* reserved */
10314     subaddr[12] = 0x5C;
10315     subdata[12] = 0x00; /* reserved */
10316     CheckSum = (DID & 0xFF) + (BID & 0xF) + (LID0 & 0x1F) + (device->tx->deframer->scramble) + (DeframerL & 0x1F) + (DeframerF & 0xFF) + (K & 0x1F) + (DeframerM & 0xFF)
10317             + (CS & 0x3) + (N & 0x1F) + (Np & 0x1F) + (S & 0x1F) + (HD & 1) + (CF & 0x1F) + (SUBCLASSV & 7) + (JESDV & 7);
10318     subaddr[13] = 0x5D;
10319     subdata[13] = CheckSum & 0xFFU; /* Checksum Lane 0 */
10320     subaddr[14] = 0x6D;
10321     subdata[14] = 0xA0U; /* Bad Disparity setup */
10322     subaddr[15] = 0x6E;
10323     subdata[15] = 0xA0U; /* Not in Table setup */
10324     subaddr[16] = 0x6F;
10325     subdata[16] = 0xA0U; /* UnExpected K character setup */
10326     subaddr[17] = 0x75;
10327     subdata[17] = CTRLREG0; /* CTRLREG 0 */
10328     subaddr[18] = 0x76;
10329     subdata[18] = CTRLREG1; /* CTRLREG 1 (Bytes per frame) */
10330     subaddr[19] = 0x77;
10331     subdata[19] = CTRLREG2; /* CTRLREG 2 */
10332     subaddr[20] = 0x78;
10333     subdata[20] = 0x01; /* # 4*K multiframes during ILAS */
10334     subaddr[21] = 0x7A;
10335     subdata[21] = 0xE0U; /* Setup JESD interrupt sources */
10336     subaddr[22] = 0x7B;
10337     subdata[22] = 0x08U; /* Sync assertion setup */
10338     subaddr[23] = 0x7C;
10339     subdata[23] = 0xFFU; /* Error count threshold */
10340     subaddr[24] = 0x7D;
10341     subdata[24] = DeframerLaneEnable & 0xFFU; /* Lane enable */
10342 
10343     for (i = 0; i <= 24; i++)
10344     {
10345         /* Set deframer sub-register map address */
10346         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_ADDR, subaddr[i]);
10347 
10348         /* Set deframer sub-register map data word */
10349         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_DATA, subdata[i]);
10350 
10351         /* Set write enable to latch data into deframer sub register map */
10352         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_WR_EN, 0x01);
10353     }
10354 
10355     /* Deframer: Enable lane FIFO sync */
10356     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_DEFRAMER_SYSREF_FIFO_EN, 0x01, 0x10, 4);
10357 
10358     return MYKONOS_ERR_OK;
10359 }
10360 
10361 /**
10362  * \brief Sets up the chip for multichip sync, and cleans up after MCS.
10363  *
10364  *  When working with multiple transceivers or even only one transceiver that requires deterministic
10365  *  latency between the Tx and observation and or main Rx JESD204B data path, Multichip sync is
10366  *  necessary.  This function should be run after all transceivers are initialized.
10367  *
10368  *  After the SYSREF pulses have been sent, call the MYKONOS_enableMultichipSync() function again with the
10369  *  enableMcs parameter set to 0.  When enableMcs = 0, the MCS status will be returned in the mcsStatus
10370  *  parameter.
10371  *
10372  *  Typical sequence:
10373  *  1) Initialize all Mykonos devices in system using MYKONOS_initialize()
10374  *  2) Run MYKONOS_enableMultichipSync with enableMcs = 1
10375  *  3) Send at least 3 SYSREF pulses
10376  *  4) Run MYKONOS_enableMultichipSync with enableMcs = 0
10377  *  5) Load ARM, run ARM cals and continue to active Transmit/Receive
10378  *
10379  *  mcsStatus | bit Description
10380  * -----------|--------------------------------------------------------
10381  *       [0]  | MCS JESD SYSREF Status (1 = sync occurred)
10382  *       [1]  | MCS Digital Clocks Sync Status (1 = sync occurred)
10383  *       [2]  | MCS CLKPLL SDM Sync Status (1 = sync occurred)
10384  *       [3]  | MCS Device Clock divider Sync Status (1 = sync occurred)
10385  *
10386  * <B>Dependencies</B>
10387  * - device->spiSettings
10388  *
10389  * \param device is a pointer to the device settings structure
10390  * \param enableMcs =1 will enable the MCS state machine, =0 will allow reading back MCS status
10391  * \param mcsStatus optional parameter, if pointer is not null the function Which will be populated with the mcsStatus word described in the table above.
10392  *
10393  * \retval MYKONOS_ERR_OK Function completed successfully
10394  */
MYKONOS_enableMultichipSync(mykonosDevice_t * device,uint8_t enableMcs,uint8_t * mcsStatus)10395 mykonosErr_t MYKONOS_enableMultichipSync(mykonosDevice_t *device, uint8_t enableMcs, uint8_t *mcsStatus)
10396 {
10397     uint8_t clkPllSdmBypass = 0;
10398     uint8_t mcsEnable = 0x9B; /* [7] Keeps RF LO divider enabled, Enable MCS[4] and reset Device Clock divider[3], Digital clocks[1], and JESD204 SYSREF[0] */
10399 
10400 #if (MYKONOS_VERBOSE == 1)
10401     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enableMultichipSync()\n");
10402 #endif
10403 
10404     if (enableMcs)
10405     {
10406         /* If CLKPLL SDM not bypassed, reset CLKPLL SDM as well. */
10407         CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_CLK_SYNTH_DIVIDER_INT_BYTE1, &clkPllSdmBypass, 0x40, 6);
10408 
10409         if (clkPllSdmBypass == 0)
10410         {
10411             mcsEnable |= 0x04; /* enable MCS for CLKPLL SDM */
10412         }
10413 
10414         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_MCS_CONTROL, mcsEnable);
10415     }
10416 
10417     /* if mcsStatus is a valid pointer, return the MCS status */
10418     if (mcsStatus != NULL)
10419     {
10420         CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_MCS_STATUS, mcsStatus);
10421     }
10422 
10423     return MYKONOS_ERR_OK;
10424 }
10425 
10426 /**
10427  * \brief Enables or disables SYSREF to the transceiver's RX framer
10428  *
10429  * <B>Dependencies</B>
10430  * - device->spiSettings
10431  *
10432  * \param device is a pointer to the device settings structure
10433  * \param enable = '1' enables SYSREF to RX framer, '0' disables SYSREF to framer
10434  *
10435  * \retval MYKONOS_ERR_OK Function completed successfully
10436  */
MYKONOS_enableSysrefToRxFramer(mykonosDevice_t * device,uint8_t enable)10437 mykonosErr_t MYKONOS_enableSysrefToRxFramer(mykonosDevice_t *device, uint8_t enable)
10438 {
10439 
10440 #if (MYKONOS_VERBOSE == 1)
10441     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enableSysrefToRxFramer()\n");
10442 #endif
10443 
10444     if (enable)
10445     {
10446         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_FRAMER_SYSREF_FIFO_EN, 0x01, 0x01, 0);
10447     }
10448     else
10449     {
10450         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_FRAMER_SYSREF_FIFO_EN, 0x00, 0x01, 0);
10451     }
10452 
10453     return MYKONOS_ERR_OK;
10454 }
10455 
10456 /**
10457  * \brief Enables or disables SYSREF to the transceiver's Observation RX framer
10458  *
10459  * <B>Dependencies</B>
10460  * - device->spiSettings
10461  *
10462  * \param device is a pointer to the device settings structure
10463  * \param enable = '1' enables SYSREF to OBSRX framer, '0' disables SYSREF to framer
10464  *
10465  * \retval MYKONOS_ERR_OK Function completed successfully
10466  */
MYKONOS_enableSysrefToObsRxFramer(mykonosDevice_t * device,uint8_t enable)10467 mykonosErr_t MYKONOS_enableSysrefToObsRxFramer(mykonosDevice_t *device, uint8_t enable)
10468 {
10469 
10470 #if (MYKONOS_VERBOSE == 1)
10471     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enableSysrefToObsRxFramer()\n");
10472 #endif
10473 
10474     if (enable)
10475     {
10476         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_SYSREF_FIFO_EN, 0x01, 0x01, 0);
10477     }
10478     else
10479     {
10480         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_SYSREF_FIFO_EN, 0x00, 0x01, 0);
10481     }
10482 
10483     return MYKONOS_ERR_OK;
10484 }
10485 
10486 /**
10487  * \brief Enables or disables SYSREF to the transceiver's deframer
10488  *
10489  * <B>Dependencies</B>
10490  * - device->spiSettings
10491  *
10492  * \param device is a pointer to the device settings structure
10493  * \param enable = '1' enables SYSREF to deframer, '0' disables SYSREF to deframer
10494  *
10495  * \retval MYKONOS_ERR_OK Function completed successfully
10496  */
MYKONOS_enableSysrefToDeframer(mykonosDevice_t * device,uint8_t enable)10497 mykonosErr_t MYKONOS_enableSysrefToDeframer(mykonosDevice_t *device, uint8_t enable)
10498 {
10499 
10500 #if (MYKONOS_VERBOSE == 1)
10501     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enableSysrefToDeframer()\n");
10502 #endif
10503 
10504     if (enable)
10505     {
10506         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_DEFRAMER_SYSREF_FIFO_EN, 0x01, 0x01, 0);
10507     }
10508     else
10509     {
10510         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_DEFRAMER_SYSREF_FIFO_EN, 0x00, 0x01, 0);
10511     }
10512 
10513     return MYKONOS_ERR_OK;
10514 }
10515 
10516 /**
10517  * \brief Reads the transceiver's RX framer status
10518  *
10519  * <B>Dependencies</B>
10520  * - device->spiSettings
10521  *
10522  * framerStatus |  Description
10523  * -------------|-----------------------------------------------------------------------------
10524  *         [7]  | SYSREF phase error ? a new SYSREF had different timing than the first that set the LMFC timing.
10525  *         [6]  | Framer lane FIFO read/write pointer delta has changed.  Can help debug issues with deterministic latency.
10526  *         [5]  | Framer has received the SYSREF and has retimed its LMFC
10527  *       [4:2]  | Framer ILAS state: 0=CGS, 1= 1st Multframe, 2= 2nd Multiframe, 3= 3rd Multiframe, 4= 4th multiframe, 5= Last multiframe, 6=invalid, 7= ILAS complete
10528  *       [1:0]  | Framer Tx state: 0=CGS, 1= ILAS, 2 = ADC Data
10529  *
10530  * \param device is a pointer to the device settings structure
10531  * \param framerStatus is the RX framer status byte read
10532  *
10533  * \retval MYKONOS_ERR_OK Function completed successfully
10534  * \retval MYKONOS_ERR_READ_RXFRAMERSTATUS_NULL_PARAM Function parameter framerStatus has NULL pointer
10535  */
MYKONOS_readRxFramerStatus(mykonosDevice_t * device,uint8_t * framerStatus)10536 mykonosErr_t MYKONOS_readRxFramerStatus(mykonosDevice_t *device, uint8_t *framerStatus)
10537 {
10538 
10539 #if (MYKONOS_VERBOSE == 1)
10540     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_readRxFramerStatus()\n");
10541 #endif
10542 
10543     if (framerStatus == NULL)
10544     {
10545         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READ_RXFRAMERSTATUS_NULL_PARAM,
10546                 getMykonosErrorMessage(MYKONOS_ERR_READ_RXFRAMERSTATUS_NULL_PARAM));
10547         return MYKONOS_ERR_READ_RXFRAMERSTATUS_NULL_PARAM;
10548     }
10549 
10550     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_STATUS_STRB, 0x01);
10551     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_STATUS_STRB, 0x00);
10552     CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_FRAMER_STATUS, framerStatus);
10553 
10554     return MYKONOS_ERR_OK;
10555 }
10556 
10557 /**
10558  * \brief Reads the transceiver's Observation RX framer status
10559  *
10560  * <B>Dependencies</B>
10561  * * - device->spiSettings
10562  *
10563  * obsFramerStatus |  Description
10564  * ----------------|-----------------------------------------------------------------------------
10565  *            [7]  | SYSREF phase error ? a new SYSREF had different timing than the first that set the LMFC timing.
10566  *            [6]  | Framer lane FIFO read/write pointer delta has changed.  Can help debug issues with deterministic latency.
10567  *            [5]  | Framer has received the SYSREF and has retimed its LMFC
10568  *          [4:2]  | Framer ILAS state: 0=CGS, 1= 1st Multframe, 2= 2nd Multiframe, 3= 3rd Multiframe, 4= 4th multiframe, 5= Last multiframe, 6=invalid, 7= ILAS complete
10569  *          [1:0]  | Framer Tx state: 0=CGS, 1= ILAS, 2 = ADC Data
10570  *
10571  * \param device is a pointer to the device settings structure
10572  * \param obsFramerStatus is the OBSRX framer status byte read
10573  *
10574  * \retval MYKONOS_ERR_OK Function completed successfully
10575  * \retval MYKONOS_ERR_READ_ORXFRAMERSTATUS_NULL_PARAM Function parameter obsFramerStatus has NULL pointer
10576  */
MYKONOS_readOrxFramerStatus(mykonosDevice_t * device,uint8_t * obsFramerStatus)10577 mykonosErr_t MYKONOS_readOrxFramerStatus(mykonosDevice_t *device, uint8_t *obsFramerStatus)
10578 {
10579 
10580 #if (MYKONOS_VERBOSE == 1)
10581     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_readOrxFramerStatus()\n");
10582 #endif
10583 
10584     if (obsFramerStatus == NULL)
10585     {
10586         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READ_ORXFRAMERSTATUS_NULL_PARAM,
10587                 getMykonosErrorMessage(MYKONOS_ERR_READ_ORXFRAMERSTATUS_NULL_PARAM));
10588         return MYKONOS_ERR_READ_ORXFRAMERSTATUS_NULL_PARAM;
10589     }
10590 
10591     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_STATUS_STRB, 0x01);
10592     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_STATUS_STRB, 0x00);
10593     CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_STATUS, obsFramerStatus);
10594 
10595     return MYKONOS_ERR_OK;
10596 }
10597 
10598 /**
10599  * \brief Reads the transceiver's deframer status
10600  *
10601  * <B>Dependencies</B>
10602  * - device->spiSettings
10603  *
10604  *   deframerStatus  |  Bit Name                |  Description
10605  *   ----------------|--------------------------|---------------------------------------------
10606  *              [7]  | Unused                   | Unused
10607  *              [6]  | Deframer IRQ             | This bit indicates that the IRQ interrupt was asserted.
10608  *              [5]  | Deframer SYSREF Received | When this bit is set, it indicates that the SYSREF pulse was received by the deframer IP
10609  *              [4]  | Deframer Receiver Error  | This bit is set when PRBS has received an error.
10610  *              [3]  | Valid Checksum           | This bit is set when the received ILAS checksum is valid.
10611  *              [2]  | EOF Event                | This bit captures the internal status of the framer End of Frame event. Value =1 if framing error during ILAS
10612  *              [1]  | EOMF Event               | This bit captures the internal status of the framer End of Multi-Frame event. Value =1 if framing error during ILAS
10613  *              [0]  | FS Lost                  | This bit captures the internal status of the framer Frame Symbol event. Value =1 if framing error during ILAS or user data (invalid replacement characters)
10614  *
10615  *
10616  * \param device is a pointer to the device settings structure
10617  * \param deframerStatus is the deframer status byte read
10618  *
10619  * \retval MYKONOS_ERR_OK Function completed successfully
10620  * \retval MYKONOS_ERR_READ_DEFRAMERSTATUS_NULL_PARAM Function parameter deframerStatus has NULL pointer
10621  */
MYKONOS_readDeframerStatus(mykonosDevice_t * device,uint8_t * deframerStatus)10622 mykonosErr_t MYKONOS_readDeframerStatus(mykonosDevice_t *device, uint8_t *deframerStatus)
10623 {
10624 
10625 #if (MYKONOS_VERBOSE == 1)
10626     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_readDeframerStatus()\n");
10627 #endif
10628 
10629     if (deframerStatus == NULL)
10630     {
10631         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READ_DEFRAMERSTATUS_NULL_PARAM,
10632                 getMykonosErrorMessage(MYKONOS_ERR_READ_DEFRAMERSTATUS_NULL_PARAM));
10633         return MYKONOS_ERR_READ_DEFRAMERSTATUS_NULL_PARAM;
10634     }
10635 
10636     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_STAT_STRB, 0x01);
10637     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_STAT_STRB, 0x00);
10638     CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_STAT, deframerStatus);
10639 
10640     return MYKONOS_ERR_OK;
10641 }
10642 
10643 /**
10644  * \brief Reads the Mykonos JESD204b Deframer determinstic FIFO depth
10645  *
10646  * To verify that the deterministic latency FIFO is not close to a underflow or
10647  * overflow condition, it is recommended to check the FIFO depth. If the FIFO
10648  * is close to an overflow or underflow condition, it is possible that from
10649  * power up to powerup, deterministic latency may not be met.  If a underflow
10650  * or overflow occurred, the data would still be correct, but would possibly
10651  * slip by 1 multiframe (losing deterministic latency).  To correct for an
10652  * overflow/underflow, the BBIC would need to add delay from SYSREF until
10653  * the first symbol in a multiframe
10654  *
10655  * <B>Dependencies</B>
10656  * - device->spiSettings
10657  *
10658  * \param device is a pointer to the device settings structure
10659  * \param fifoDepth Return value that describes the depth of the Mykonos
10660  *                  deterministic latency deframer FIFO.
10661  * \param readEnLmfcCount Returns the LMFC count value when the deterministic FIFO read enable was asserted.
10662  *                        Counts at the Mykonos internal deframer PCLK frequency.
10663  *
10664  * \retval MYKONOS_ERR_OK Function completed successfully
10665  * \retval MYKONOS_ERR_READ_DEFFIFODEPTH_NULL_PARAM Error: function parameter fifoDepth is a NULL pointer
10666  * \retval MYKONOS_ERR_READ_DEFFIFODEPTH_LMFCCOUNT_NULL_PARAM Error: function parameter readEnLmfcCount is a NULL pointer
10667  *
10668  */
MYKONOS_getDeframerFifoDepth(mykonosDevice_t * device,uint8_t * fifoDepth,uint8_t * readEnLmfcCount)10669 mykonosErr_t MYKONOS_getDeframerFifoDepth(mykonosDevice_t *device, uint8_t *fifoDepth, uint8_t *readEnLmfcCount)
10670 {
10671     uint8_t fifoReadPtr = 0;
10672     uint8_t fifoWritePtr = 0;
10673 
10674 #if (MYKONOS_VERBOSE == 1)
10675     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getDeframerFifoDepth()\n");
10676 #endif
10677 
10678     if (fifoDepth == NULL)
10679     {
10680         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READ_DEFFIFODEPTH_NULL_PARAM,
10681                 getMykonosErrorMessage(MYKONOS_ERR_READ_DEFFIFODEPTH_NULL_PARAM));
10682         return MYKONOS_ERR_READ_DEFFIFODEPTH_NULL_PARAM;
10683     }
10684 
10685     if (readEnLmfcCount == NULL)
10686     {
10687         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READ_DEFFIFODEPTH_LMFCCOUNT_NULL_PARAM,
10688                 getMykonosErrorMessage(MYKONOS_ERR_READ_DEFFIFODEPTH_LMFCCOUNT_NULL_PARAM));
10689         return MYKONOS_ERR_READ_DEFFIFODEPTH_LMFCCOUNT_NULL_PARAM;
10690     }
10691 
10692     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_STAT_STRB, 0x01);
10693     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_STAT_STRB, 0x00);
10694 
10695     /* read/write pointers are 7 bits, (0 - 127) */
10696     CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_DEFRAMER_DET_FIFO_RD_ADDR, &fifoReadPtr, 0x7F, 0);
10697     CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_DEFRAMER_DET_FIFO_WR_ADDR, &fifoWritePtr, 0x7F, 0);
10698 
10699     /* Adding 128 and modulus 128 handle the wrap cases where the read pointer
10700      * is less than write pointer
10701      */
10702     *fifoDepth = (((fifoWritePtr + 128) - fifoReadPtr) % 128);
10703 
10704     CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_DET_FIFO_PHASE, readEnLmfcCount);
10705 
10706     return MYKONOS_ERR_OK;
10707 }
10708 
10709 /**
10710  * \brief Selects the PRBS type and enables or disables RX Framer PRBS20 generation
10711  *
10712  * <B>Dependencies</B>
10713  * - device->spiSettings
10714  *
10715  * \param device is a pointer to the device settings structure
10716  * \param polyOrder selects the PRBS type based on a two-bit value range from 0-3
10717  * \param enable '1' = enables PRBS RX framer PRBS generator, '0' = disables PRBS generator
10718  *
10719  * \retval MYKONOS_ERR_OK Function completed successfully
10720  * \retval MYKONOS_ERR_RX_FRAMER_INV_PRBS_POLYORDER_PARAM Invalid polyOrder parameter, use ENUM
10721  *
10722  */
MYKONOS_enableRxFramerPrbs(mykonosDevice_t * device,mykonosPrbsOrder_t polyOrder,uint8_t enable)10723 mykonosErr_t MYKONOS_enableRxFramerPrbs(mykonosDevice_t *device, mykonosPrbsOrder_t polyOrder, uint8_t enable)
10724 {
10725     uint8_t wrmask = 0;
10726     uint8_t enableBit = 0;
10727 
10728 #if (MYKONOS_VERBOSE == 1)
10729     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enableRxFramerPrbs()\n");
10730 #endif
10731 
10732     enableBit = (enable > 0) ? 1 : 0;
10733 
10734     if ((polyOrder == MYK_PRBS7) || (polyOrder == MYK_PRBS15) || (polyOrder == MYK_PRBS31))
10735     {
10736         wrmask = ((uint8_t)polyOrder << 1) | enableBit;
10737     }
10738     else
10739     {
10740         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RX_FRAMER_INV_PRBS_POLYORDER_PARAM,
10741                 getMykonosErrorMessage(MYKONOS_ERR_RX_FRAMER_INV_PRBS_POLYORDER_PARAM));
10742         return MYKONOS_ERR_RX_FRAMER_INV_PRBS_POLYORDER_PARAM;
10743     }
10744 
10745     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_PRBS20_CTL, wrmask);
10746 
10747     return MYKONOS_ERR_OK;
10748 }
10749 
10750 /**
10751  * \brief Selects the PRBS type and enables or disables OBSRX Framer PRBS20 generation
10752  *
10753  * <B>Dependencies</B>
10754  * - device->spiSettings
10755  *
10756  * \param device is a pointer to the device settings structure
10757  * \param polyOrder selects the PRBS type based on a two-bit value range from 0-3
10758  * \param enable '1' = enables PRBS OBSRX framer PRBS generator, '0' = disables PRBS generator
10759  *
10760  * \retval MYKONOS_ERR_OK Function completed successfully
10761  * \retval MYKONOS_ERR_OBSRX_FRAMER_INV_PRBS_POLYORDER_PARAM polyOrder parameter is not a valid value - use ENUM
10762  */
MYKONOS_enableObsRxFramerPrbs(mykonosDevice_t * device,mykonosPrbsOrder_t polyOrder,uint8_t enable)10763 mykonosErr_t MYKONOS_enableObsRxFramerPrbs(mykonosDevice_t *device, mykonosPrbsOrder_t polyOrder, uint8_t enable)
10764 {
10765     uint8_t wrmask = 0;
10766     uint8_t enableBit = 0;
10767 
10768 #if (MYKONOS_VERBOSE == 1)
10769     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enableObsRxFramerPrbs()\n");
10770 #endif
10771 
10772     enableBit = (enable > 0) ? 1 : 0;
10773 
10774     if ((polyOrder == MYK_PRBS7) || (polyOrder == MYK_PRBS15) || (polyOrder == MYK_PRBS31))
10775     {
10776         wrmask = ((uint8_t)polyOrder << 1) | enableBit;
10777     }
10778     else
10779     {
10780         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OBSRX_FRAMER_INV_PRBS_POLYORDER_PARAM,
10781                 getMykonosErrorMessage(MYKONOS_ERR_OBSRX_FRAMER_INV_PRBS_POLYORDER_PARAM));
10782         return MYKONOS_ERR_OBSRX_FRAMER_INV_PRBS_POLYORDER_PARAM;
10783     }
10784 
10785     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_PRBS20_CTL, wrmask);
10786 
10787     return MYKONOS_ERR_OK;
10788 }
10789 
10790 /**
10791  * \brief Injects a PRBS error into the RX data path
10792  *
10793  * <B>Dependencies</B>
10794  * - device->spiSettings
10795  *
10796  * \param device is a pointer to the device settings structure
10797  *
10798  * \retval MYKONOS_ERR_OK Function completed successfully
10799  */
MYKONOS_rxInjectPrbsError(mykonosDevice_t * device)10800 mykonosErr_t MYKONOS_rxInjectPrbsError(mykonosDevice_t *device)
10801 {
10802     uint8_t prbsControl = 0x00;
10803 
10804 #if (MYKONOS_VERBOSE == 1)
10805     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_rxInjectPrbsError()\n");
10806 #endif
10807 
10808     /* reading current PRBS20 control register contents */
10809     CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_FRAMER_PRBS20_CTL, &prbsControl);
10810 
10811     /* setting bit 4 in framer PRBS20 control register and then clearing it for error injection */
10812     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_PRBS20_CTL, prbsControl |= 0x10);
10813     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_FRAMER_PRBS20_CTL, prbsControl &= ~0x10);
10814 
10815     return MYKONOS_ERR_OK;
10816 }
10817 
10818 /**
10819  * \brief Initiates a PRBS error injection into the Observation RX data path
10820  *
10821  * <B>Dependencies</B>
10822  * - device->spiSettings
10823  *
10824  * \param device is a pointer to the device settings structure
10825  *
10826  * \retval MYKONOS_ERR_OK Function completed successfully
10827  */
MYKONOS_obsRxInjectPrbsError(mykonosDevice_t * device)10828 mykonosErr_t MYKONOS_obsRxInjectPrbsError(mykonosDevice_t *device)
10829 {
10830     uint8_t prbsControl = 0x00;
10831 
10832 #if (MYKONOS_VERBOSE == 1)
10833     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_obsRxInjectPrbsError()\n");
10834 #endif
10835 
10836     /* reading current PRBS20 control register contents */
10837     CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_PRBS20_CTL, &prbsControl);
10838 
10839     /* setting bit 4 in framer PRBS20 control register and then clearing it for error injection */
10840     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_PRBS20_CTL, prbsControl |= 0x10);
10841     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_PRBS20_CTL, prbsControl &= ~0x10);
10842 
10843     return MYKONOS_ERR_OK;
10844 }
10845 
10846 /**
10847  * \brief Configures and enables or disables the transceiver's deframer PRBS checker
10848  *
10849  * <B>Dependencies</B>
10850  * - device->spiSettings
10851  *
10852  * \param device is a pointer to the device settings structure
10853  * \param lanes selects the lane for PRBS checking based on a 4-bit mask, where each weighted bit
10854  * corresponds with a different lane selection as such: '1' = lane 0, '2' = lane 1, '4' = lane 2, '8' = lane 3
10855  * \param polyOrder selects the PRBS type based on enum values (MYK_PRBS7, MYK_PRBS15, MYK_PRBS31)
10856  * \param enable '1' = enables checking, '0' = disables checking
10857  *
10858  * \retval MYKONOS_ERR_OK Function completed successfully
10859  * \retval MYKONOS_ERR_DEFRAMER_INV_PRBS_POLYORDER_PARAM Invalid polyOrder parameter - use ENUM
10860  * \retval MYKONOS_ERR_DEFRAMER_INV_PRBS_ENABLE_PARAM Invalid enable (valid 0-1) or lanes (valid 0-15) parameter
10861  */
MYKONOS_enableDeframerPrbsChecker(mykonosDevice_t * device,uint8_t lanes,mykonosPrbsOrder_t polyOrder,uint8_t enable)10862 mykonosErr_t MYKONOS_enableDeframerPrbsChecker(mykonosDevice_t *device, uint8_t lanes, mykonosPrbsOrder_t polyOrder, uint8_t enable)
10863 {
10864     uint8_t wrmask = 0x00;
10865 
10866 #if (MYKONOS_VERBOSE == 1)
10867     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enableDeframerPrbsChecker()\n");
10868 #endif
10869 
10870     if ((enable <= 0x01) && (lanes <= 0x0F))
10871     {
10872         if ((polyOrder == MYK_PRBS7) || (polyOrder == MYK_PRBS15) || (polyOrder == MYK_PRBS31))
10873         {
10874             wrmask = ((lanes << 4) | ((uint8_t)polyOrder << 1) | enable);
10875         }
10876         else
10877         {
10878             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DEFRAMER_INV_PRBS_POLYORDER_PARAM,
10879                     getMykonosErrorMessage(MYKONOS_ERR_DEFRAMER_INV_PRBS_POLYORDER_PARAM));
10880             return MYKONOS_ERR_DEFRAMER_INV_PRBS_POLYORDER_PARAM;
10881         }
10882     }
10883     else
10884     {
10885         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DEFRAMER_INV_PRBS_ENABLE_PARAM,
10886                 getMykonosErrorMessage(MYKONOS_ERR_DEFRAMER_INV_PRBS_ENABLE_PARAM));
10887         return MYKONOS_ERR_DEFRAMER_INV_PRBS_ENABLE_PARAM;
10888     }
10889 
10890     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_PRBS20_CTL, wrmask);
10891 
10892     return MYKONOS_ERR_OK;
10893 }
10894 
10895 /**
10896  * \brief Reads the deframer PRBS counters
10897  *
10898  * <B>Dependencies</B>
10899  * - device->spiSettings
10900  *
10901  * \param device is a pointer to the device settings structure
10902  * \param counterSelect selects the PRBS error counter to be read based on values between 0-3
10903  *                      If counterSelect exceeds this value an error is thrown.
10904  *
10905  * \param prbsErrorCount is return value after reading the PRBS error count
10906  *
10907  * \retval MYKONOS_ERR_OK Function completed successfully
10908  * \retval MYKONOS_ERR_READ_DEFRAMERPRBS_NULL_PARAM Function parameter prbsErrorCount has NULL pointer
10909  * \retval MYKONOS_ERR_DEFRAMER_INV_PRBS_CNTR_SEL_PARAM if counterSelect is out of bounds
10910  */
MYKONOS_readDeframerPrbsCounters(mykonosDevice_t * device,uint8_t counterSelect,uint32_t * prbsErrorCount)10911 mykonosErr_t MYKONOS_readDeframerPrbsCounters(mykonosDevice_t *device, uint8_t counterSelect, uint32_t *prbsErrorCount)
10912 {
10913     uint8_t wrmask = 0x00;
10914     uint8_t errorCnt[3] = {0};
10915     const uint8_t COUNTER_SATURATE = 0x40;
10916 
10917 #if (MYKONOS_VERBOSE == 1)
10918     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_readDeframerPrbsCounters()\n");
10919 #endif
10920 
10921     if (prbsErrorCount == NULL)
10922     {
10923         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READ_DEFRAMERPRBS_NULL_PARAM,
10924                 getMykonosErrorMessage(MYKONOS_ERR_READ_DEFRAMERPRBS_NULL_PARAM));
10925         return MYKONOS_ERR_READ_DEFRAMERPRBS_NULL_PARAM;
10926     }
10927 
10928     if (counterSelect & ~0x03)
10929     {
10930         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DEFRAMER_INV_PRBS_CNTR_SEL_PARAM,
10931                 getMykonosErrorMessage(MYKONOS_ERR_DEFRAMER_INV_PRBS_CNTR_SEL_PARAM));
10932         return MYKONOS_ERR_DEFRAMER_INV_PRBS_CNTR_SEL_PARAM;
10933     }
10934     else
10935     {
10936         wrmask = (uint8_t)(COUNTER_SATURATE | (counterSelect << 4));
10937         *prbsErrorCount = 0x00000000;
10938     }
10939 
10940     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_PRBS20_STRB_CHKSUM_TYPE, wrmask);
10941     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_PRBS20_STRB_CHKSUM_TYPE, wrmask |= 0x01);
10942     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_PRBS20_STRB_CHKSUM_TYPE, wrmask &= ~0x01);
10943 
10944     CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_PRBS20_ERR_CNTR_7_TO_0, &errorCnt[0]);
10945     CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_PRBS20_ERR_CNTR_15_TO_8, &errorCnt[1]);
10946     CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_PRBS20_ERR_CNTR_23_TO_16, &errorCnt[2]);
10947 
10948     *prbsErrorCount = (uint32_t)(errorCnt[2] << 16) | (uint32_t)(errorCnt[1] << 8) | (uint32_t)(errorCnt[0]);
10949 
10950     return MYKONOS_ERR_OK;
10951 }
10952 
10953 /**
10954  * \brief Clears the deframer/deserializer PRBS counters
10955  *
10956  * <B>Dependencies</B>
10957  * - device->spiSettings
10958  *
10959  * \param device is a pointer to the device settings structure
10960  *
10961  * \retval MYKONOS_ERR_OK Function completed successfully
10962  */
MYKONOS_clearDeframerPrbsCounters(mykonosDevice_t * device)10963 mykonosErr_t MYKONOS_clearDeframerPrbsCounters(mykonosDevice_t *device)
10964 {
10965     uint8_t spiReg = 0;
10966 
10967 #if (MYKONOS_VERBOSE == 1)
10968     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_clearDeframerPrbsCounters()\n");
10969 #endif
10970 
10971     CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_PRBS20_CTL, &spiReg);
10972     spiReg &= ~0x08; //make sure PRBS clear bit is 0
10973 
10974     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_PRBS20_CTL, (spiReg | 0xF8)); //clear counters for all lanes
10975     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_PRBS20_CTL, spiReg); //set reg back to previous value
10976 
10977     return MYKONOS_ERR_OK;
10978 }
10979 
10980 /**
10981  * \brief Reads the lane 0 JESD204B deframer configuration and compares it against the ILAS received values
10982  *
10983  * <B>Dependencies</B>
10984  * - device->spiSettings->chipSelectIndex
10985  *
10986  * \param device is a pointer to the device settings structure
10987  * \param mismatch [15-0] is a bit-encoded word which for mismatch[15] = '0' = no mismatch, '1' = mismatch for one or more parameters
10988  * mismatch bits [14-0] are aligned with the mykonosJesd204bLane0Config_t structure members starting at '0' = DID.  The aligned bit is set to
10989  * '1' if the configuration parameter does not agree with its corresponding received ILAS value, otherwise '0' if they agree.
10990  *
10991  * The bit assignments for the 16-bit word are:
10992  *   mismatch | bit description
10993  * -----------|--------------------------------------------------------
10994  *      [0]   | JESD204B DID: device ID
10995  *      [1]   | JESD204B BID: bank ID
10996  *      [2]   | JESD204B LID0: lane ID
10997  *      [3]   | JESD204B L: lanes per data converter
10998  *      [4]   | JESD204B SCR: scramble setting
10999  *      [5]   | JESD204B F: octets per frame
11000  *      [6]   | JESD204B K: frames per multiframe
11001  *      [7]   | JESD204B M: number of data converters
11002  *      [8]   | JESD204B N: data converter sample resolution
11003  *      [9]   | JESD204B CS: number of control bits transferred per sample per frame
11004  *      [10]  | JESD204B NP: JESD204B word size based on the highest data converter resolution
11005  *      [11]  | JESD204B S: number of samples per converter per frame
11006  *      [12]  | JESD204B CF: '0' = control bits appended to each sample, '1' = control bits appended to end of frame
11007  *      [13]  | JESD204B HD: high density bit, where '0' = samples are contained with single lane, '1' = samples are divided over more than one lane
11008  *      [14]  | JESD204B FCHK0: configuration checksum OK bit. where '1' = fail, '0' = pass
11009  *      [15]  | MISMATCH DETECTED BIT: bits 0-14 are ored together to set this bit
11010  *
11011  * \retval MYKONOS_ERR_OK Function completed successfully
11012  * \retval MYKONOS_ERR_JESD204B_ILAS_MISMATCH_NULLPARAM Function parameter mismatch has NULL pointer
11013  */
MYKONOS_jesd204bIlasCheck(mykonosDevice_t * device,uint16_t * mismatch)11014 mykonosErr_t MYKONOS_jesd204bIlasCheck(mykonosDevice_t *device, uint16_t *mismatch)
11015 {
11016     uint8_t i = 0;
11017     uint8_t ilasdata[15] = {0};
11018     uint8_t cfgdata[15] = {0};
11019     mykonosJesd204bLane0Config_t lane0ILAS;
11020     mykonosJesd204bLane0Config_t lane0Cfg;
11021 
11022 #if (MYKONOS_VERBOSE == 1)
11023     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_jesd204bIlasCheck()\n");
11024 #endif
11025 
11026     if (mismatch == NULL)
11027     {
11028         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_JESD204B_ILAS_MISMATCH_NULLPARAM,
11029                 getMykonosErrorMessage(MYKONOS_ERR_JESD204B_ILAS_MISMATCH_NULLPARAM));
11030         return MYKONOS_ERR_JESD204B_ILAS_MISMATCH_NULLPARAM;
11031     }
11032 
11033     *mismatch = 0;
11034 
11035     /* setting deframer read received ILAS data */
11036     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_WR_EN, 0x00);
11037 
11038     /* reading deframer received ILAS register contents into array */
11039     for (i = 0; i < 15; i++)
11040     {
11041         /* setting the deframer sub-address for received ilas data */
11042         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_ADDR, MYKONOS_SUBADDR_DEFRAMER_LANE0_ILAS_RECVD + i);
11043 
11044         /* reading the received ILAS data into byte array */
11045         CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_DATA, &ilasdata[i]);
11046     }
11047 
11048     /* reading deframer config register contents into array */
11049     for (i = 0; i < 15; i++)
11050     {
11051         /* setting the deframer sub-address for received ilas data */
11052         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_ADDR, MYKONOS_SUBADDR_DEFRAMER_LANE0_ILAS_CFG + i);
11053 
11054         /* reading the received ILAS data into byte array */
11055         CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_DEFRAMER_DATA, &cfgdata[i]);
11056     }
11057 
11058     /* loading the structures with the read values for easier reading when doing compares */
11059     lane0ILAS.DID = ilasdata[0];
11060     lane0ILAS.BID = ilasdata[1] & 0x0F;
11061     lane0ILAS.LID0 = ilasdata[2] & 0x1F;
11062     lane0ILAS.L = ilasdata[3] & 0x1F;
11063     lane0ILAS.SCR = ilasdata[3] >> 7;
11064     lane0ILAS.F = ilasdata[4];
11065     lane0ILAS.K = ilasdata[5] & 0x1F;
11066     lane0ILAS.M = ilasdata[6];
11067     lane0ILAS.N = ilasdata[7] & 0x1F;
11068     lane0ILAS.CS = ilasdata[7] >> 6;
11069     lane0ILAS.NP = ilasdata[8] & 0x1F;
11070     lane0ILAS.S = ilasdata[9] & 0x1F;
11071     lane0ILAS.CF = ilasdata[10] & 0x1F;
11072     lane0ILAS.HD = ilasdata[10] >> 7;
11073     lane0ILAS.FCHK0 = ilasdata[13];
11074 
11075     lane0Cfg.DID = cfgdata[0];
11076     lane0Cfg.BID = cfgdata[1] & 0x0F;
11077     lane0Cfg.LID0 = cfgdata[2] & 0x0F;
11078     lane0Cfg.L = cfgdata[3] & 0x1F;
11079     lane0Cfg.SCR = cfgdata[3] >> 7;
11080     lane0Cfg.F = cfgdata[4];
11081     lane0Cfg.K = cfgdata[5] & 0x1F;
11082     lane0Cfg.M = cfgdata[6];
11083     lane0Cfg.N = cfgdata[7] & 0x1F;
11084     lane0Cfg.CS = cfgdata[7] >> 6;
11085     lane0Cfg.NP = cfgdata[8] & 0x1F;
11086     lane0Cfg.S = cfgdata[9] & 0x1F;
11087     lane0Cfg.CF = cfgdata[10] & 0x1F;
11088     lane0Cfg.HD = cfgdata[10] >> 7;
11089     lane0Cfg.FCHK0 = cfgdata[13];
11090 
11091     /* performing ILAS mismatch check */
11092     if (lane0ILAS.DID != lane0Cfg.DID)
11093     {
11094         *mismatch |= 0x0001;
11095     }
11096 
11097     if (lane0ILAS.BID != lane0Cfg.BID)
11098     {
11099         *mismatch |= 0x0002;
11100     }
11101 
11102     if (lane0ILAS.LID0 != lane0Cfg.LID0)
11103     {
11104         *mismatch |= 0x0004;
11105     }
11106 
11107     if (lane0ILAS.L != lane0Cfg.L)
11108     {
11109         *mismatch |= 0x0008;
11110     }
11111 
11112     if (lane0ILAS.SCR != lane0Cfg.SCR)
11113     {
11114         *mismatch |= 0x0010;
11115     }
11116 
11117     if (lane0ILAS.F != lane0Cfg.F)
11118     {
11119         *mismatch |= 0x0020;
11120     }
11121 
11122     if (lane0ILAS.K != lane0Cfg.K)
11123     {
11124         *mismatch |= 0x0040;
11125     }
11126 
11127     if (lane0ILAS.M != lane0Cfg.M)
11128     {
11129         *mismatch |= 0x0080;
11130     }
11131 
11132     if (lane0ILAS.N != lane0Cfg.N)
11133     {
11134         *mismatch |= 0x0100;
11135     }
11136 
11137     if (lane0ILAS.CS != lane0Cfg.CS)
11138     {
11139         *mismatch |= 0x0200;
11140     }
11141 
11142     if (lane0ILAS.NP != lane0Cfg.NP)
11143     {
11144         *mismatch |= 0x0400;
11145     }
11146 
11147     if (lane0ILAS.S != lane0Cfg.S)
11148     {
11149         *mismatch |= 0x0800;
11150     }
11151 
11152     if (lane0ILAS.CF != lane0Cfg.CF)
11153     {
11154         *mismatch |= 0x1000;
11155     }
11156 
11157     if (lane0ILAS.HD != lane0Cfg.HD)
11158     {
11159         *mismatch |= 0x2000;
11160     }
11161 
11162     if (lane0ILAS.FCHK0 != lane0Cfg.FCHK0)
11163     {
11164         *mismatch |= 0x4000;
11165     }
11166 
11167     if (*mismatch)
11168     {
11169         *mismatch |= 0x8000;
11170         CMB_writeToLog(ADIHAL_LOG_WARNING, device->spiSettings->chipSelectIndex, MYKONOS_ERR_JESD204B_ILAS_MISMATCH,
11171                 getMykonosErrorMessage(MYKONOS_ERR_JESD204B_ILAS_MISMATCH));
11172     }
11173 
11174     return MYKONOS_ERR_OK;
11175 }
11176 
11177 /**
11178  * \brief Select data to inject into the Rx framer input (ADC data or Loopback data from deframer output)
11179  *
11180  * This function allows inputting deframed data (IQ samples) from the Tx data path into the Rx framer.
11181  * For this to work correctly, the IQ data rate of the Tx data path must match the Rx IQ data rate.
11182  * Framer/Deframer JESD204 config parameters can vary as long as the Rx and Tx IQ rates match.
11183  *
11184  * <B>Dependencies</B>
11185  * - device->spiSettings->chipSelectIndex
11186  *
11187  * \param device A pointer to the device settings structure
11188  * \param dataSource 0 = ADC data at Rx Framer input, 1 = Deframed Tx JESD204 IQ samples input into Rx framer
11189  *
11190  * \retval MYKONOS_ERR_OK Function completed successfully
11191  */
MYKONOS_setRxFramerDataSource(mykonosDevice_t * device,uint8_t dataSource)11192 mykonosErr_t MYKONOS_setRxFramerDataSource(mykonosDevice_t *device, uint8_t dataSource)
11193 {
11194     uint8_t enableLoopBack = 0;
11195 
11196 #if (MYKONOS_VERBOSE == 1)
11197     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setRxFramerDataSource()\n");
11198 #endif
11199 
11200     enableLoopBack = (dataSource > 0) ? 1 : 0;
11201 
11202     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_FRAMER_CONFIG_LOOPBACK_XBAR_REV, enableLoopBack, 0x10, 4);
11203 
11204     return MYKONOS_ERR_OK;
11205 }
11206 
11207 /**
11208  * \brief Select data to inject into the ObsRx framer input (ADC data or Loopback data from deframer output)
11209  *
11210  * This function allows inputting deframed data (IQ samples) from the Tx data path into the Obs Rx framer.
11211  * For this to work correctly, the IQ data rate of the Tx data path must match the ORx IQ data rate.
11212  * Framer/Deframer JESD204 config parameters can vary as long as the Obs Rx and Tx IQ rates match.
11213  *
11214  * <B>Dependencies</B>
11215  * - device->spiSettings->chipSelectIndex
11216  *
11217  * \param device A pointer to the device settings structure
11218  * \param dataSource 0 = ADC data at ObsRx Framer input, 1 = Deframed Tx JESD204 IQ samples input into Obs Rx framer
11219  *
11220  * \retval MYKONOS_ERR_OK Function completed successfully
11221  */
MYKONOS_setObsRxFramerDataSource(mykonosDevice_t * device,uint8_t dataSource)11222 mykonosErr_t MYKONOS_setObsRxFramerDataSource(mykonosDevice_t *device, uint8_t dataSource)
11223 {
11224     uint8_t enableLoopBack = 0;
11225 
11226 #if (MYKONOS_VERBOSE == 1)
11227     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setObsRxFramerDataSource()\n");
11228 #endif
11229 
11230     enableLoopBack = (dataSource > 0) ? 1 : 0;
11231 
11232     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_OBS_FRAMER_CONFIG_LOOPBACK_XBAR_REV, enableLoopBack, 0x10, 4);
11233 
11234     return MYKONOS_ERR_OK;
11235 }
11236 
11237 /**
11238  * \brief Runs the Mykonos initialization calibrations
11239  *
11240  * <B>Dependencies</B>
11241  * - device->spiSettings->chipSelectIndex
11242  *
11243  * ENUM mykonosInitCalibrations_t can be used to OR together to generate the calMask parameter.
11244  *
11245  *  calMask Bit | Calibration
11246  *  ------------|----------------------
11247  *       0      | Tx BB Filter
11248  *       1      | ADC Tuner
11249  *       2      | TIA 3dB Corner
11250  *       3      | DC Offset
11251  *       4      | Tx Attenuation Delay
11252  *       5      | Rx Gain Delay
11253  *       6      | Flash Cal
11254  *       7      | Path Delay
11255  *       8      | Tx LO Leakage Internal
11256  *       9      | Tx LO Leakage External
11257  *       10     | Tx QEC Init
11258  *       11     | LoopBack Rx LO Delay
11259  *       12     | LoopBack Rx Rx QEC Init
11260  *       13     | Rx LO Delay
11261  *       14     | Rx QEC Init
11262  *       15     | DPD Init
11263  *       16     | Tx CLGC (Closed Loop Gain Control)
11264  *       17     | Tx VSWR Init
11265  *    [31-18]   | Ignored - Future space for new calibrations
11266  *
11267  * \param device A pointer to the device settings structure
11268  * \param calMask A bitmask that informs the Mykonos ARM processor which calibrations to run
11269  *
11270  * \retval MYKONOS_ERR_OK Function completed successfully
11271  */
MYKONOS_runInitCals(mykonosDevice_t * device,uint32_t calMask)11272 mykonosErr_t MYKONOS_runInitCals(mykonosDevice_t *device, uint32_t calMask)
11273 {
11274     mykonosErr_t retVal = MYKONOS_ERR_OK;
11275     const uint8_t RUNINITCALS_OPCODE = 0x02;
11276     uint8_t payload[4] = {0};
11277 
11278 #if (MYKONOS_VERBOSE == 1)
11279     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_runInitCals()\n");
11280 #endif
11281 
11282     payload[0] = (uint8_t)(calMask & 0xFF);
11283     payload[1] = (uint8_t)((calMask >> 8) & 0xFF);
11284     payload[2] = (uint8_t)((calMask >> 16) & 0xFF);
11285     payload[3] = (uint8_t)((calMask >> 24) & 0xFF);
11286 
11287     retVal = MYKONOS_sendArmCommand(device, RUNINITCALS_OPCODE, &payload[0], sizeof(payload));
11288     if (retVal != MYKONOS_ERR_OK)
11289     {
11290         return retVal;
11291     }
11292 
11293     return MYKONOS_ERR_OK;
11294 }
11295 
11296 /**
11297  * \brief Blocking waits for the Mykonos initialization calibrations to complete
11298  *
11299  * The *errorFlag and *errorCode parameters are optional.  If the pointers are
11300  * set to null, no values will be returned.  If the function returns an error
11301  * that the init calibration failed, use the MYKONOS_getInitCalStatus() function
11302  * to get more detailed information about why the init cal failed.
11303  *
11304  * <B>Dependencies</B>
11305  * - device->spiSettings->chipSelectIndex
11306  *
11307  * \param device A pointer to the device settings structure
11308  * \param timeoutMs A timeout value in Ms to wait for the calibrations to complete
11309  * \param errorFlag A 3bit error flag that helps identify what went wrong in the ARM.  0=No Error
11310  * \param errorCode The value represents the init calibration object ID that caused a failure.
11311  *
11312  * \retval MYKONOS_ERR_OK Function completed successfully
11313  * \retval MYKONOS_ERR_WAIT_INITCALS_ARMERROR ARM returned error unrelated to init cals
11314  */
MYKONOS_waitInitCals(mykonosDevice_t * device,uint32_t timeoutMs,uint8_t * errorFlag,uint8_t * errorCode)11315 mykonosErr_t MYKONOS_waitInitCals(mykonosDevice_t *device, uint32_t timeoutMs, uint8_t *errorFlag, uint8_t *errorCode)
11316 {
11317     mykonosErr_t retVal = MYKONOS_ERR_OK;
11318     mykonosErr_t retValCalStatus = MYKONOS_ERR_OK;
11319     uint8_t cmdStatusByte = 0;
11320     uint8_t _errorFlag = 0; /* Local version of parameter */
11321     mykonosInitCalStatus_t initCalStatus = {0};
11322 
11323     const uint8_t INITCALS_CAL_ERROR = 0x07;
11324 
11325 #if (MYKONOS_VERBOSE == 1)
11326     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_waitInitCals()\n");
11327 #endif
11328 
11329     /* Clear before making any calls that can throw errors */
11330     if (errorFlag != NULL)
11331     {
11332         *errorFlag = 0;
11333     }
11334 
11335     /* Clear before making any calls that can throw errors */
11336     if (errorCode != NULL)
11337     {
11338         *errorCode = 0;
11339     }
11340 
11341     retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_RUNINIT_OPCODE, timeoutMs, &cmdStatusByte);
11342     _errorFlag = cmdStatusByte >> 1; /* remove pending bit in [0], error flag is in bits [3:1] */
11343 
11344     if (errorFlag != NULL)
11345     {
11346         *errorFlag = _errorFlag;
11347     }
11348 
11349     if (retVal != MYKONOS_ERR_OK)
11350     {
11351         if (_errorFlag == INITCALS_CAL_ERROR)
11352         {
11353             /* return Error code if a calibration had an error */
11354             retValCalStatus = MYKONOS_getInitCalStatus(device, &initCalStatus);
11355             if (retValCalStatus == MYKONOS_ERR_OK)
11356             {
11357                 if (errorCode != NULL)
11358                 {
11359                     *errorCode = initCalStatus.initErrCal;
11360                 }
11361             }
11362 
11363             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_WAIT_INITCALS_CALFAILED,
11364                     getMykonosErrorMessage(MYKONOS_ERR_WAIT_INITCALS_CALFAILED));
11365             return MYKONOS_ERR_WAIT_INITCALS_CALFAILED;
11366         }
11367         else if (cmdStatusByte > 0)
11368         {
11369             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_WAIT_INITCALS_ARMERROR,
11370                     getMykonosErrorMessage(MYKONOS_ERR_WAIT_INITCALS_ARMERROR));
11371             return MYKONOS_ERR_WAIT_INITCALS_ARMERROR;
11372         }
11373     }
11374 
11375     /* Same logic if MYKONOS_waitArmCmdStatus() did not return an error, but cmdStatusByte shows an ARM error */
11376     if (_errorFlag == INITCALS_CAL_ERROR)
11377     {
11378         /* return Error code if a calibration had an error */
11379         retValCalStatus = MYKONOS_getInitCalStatus(device, &initCalStatus);
11380         if (retValCalStatus == MYKONOS_ERR_OK)
11381         {
11382             if (errorCode != NULL)
11383             {
11384                 *errorCode = initCalStatus.initErrCal;
11385             }
11386         }
11387 
11388         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_WAIT_INITCALS_CALFAILED,
11389                 getMykonosErrorMessage(MYKONOS_ERR_WAIT_INITCALS_CALFAILED));
11390         return MYKONOS_ERR_WAIT_INITCALS_CALFAILED;
11391     }
11392     else if (cmdStatusByte > 0)
11393     {
11394         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_WAIT_INITCALS_ARMERROR,
11395                 getMykonosErrorMessage(MYKONOS_ERR_WAIT_INITCALS_ARMERROR));
11396         return MYKONOS_ERR_WAIT_INITCALS_ARMERROR;
11397     }
11398 
11399     return MYKONOS_ERR_OK;
11400 }
11401 
11402 /**
11403  * \brief Aborts from an on going ARM init calibration operation.
11404  *
11405  *  The ARM init calibrations can take several seconds.  If for any reason the Baseband processor
11406  *  needs to stop the running ARM calibration sequence, call this function.  The *calsCompleted
11407  *  parameter is an option parameter that will return which cals completed before the abort
11408  *  command was received.  If *calsCompleted is a null pointer, no value will be returned.
11409  *
11410  * <B>Dependencies</B>
11411  * - device->spiSettings->chipSelectIndex
11412  *
11413  * \param device A pointer to the device settings structure
11414  * \param calsCompleted A bitmask is returned which describes which cals completed during the previous
11415  *                      MYKONOS_runInitCals() call.
11416  *
11417  * \retval MYKONOS_ERR_OK Function completed successfully
11418  * \retval MYKONOS_ERR_ABORT_INITCALS_NULL_PARAM Function parameter calsCompleted has NULL pointer
11419  */
MYKONOS_abortInitCals(mykonosDevice_t * device,uint32_t * calsCompleted)11420 mykonosErr_t MYKONOS_abortInitCals(mykonosDevice_t *device, uint32_t *calsCompleted)
11421 {
11422     mykonosErr_t retVal = MYKONOS_ERR_OK;
11423     uint32_t timeoutMs = 1000; //1 second timeout
11424     uint8_t cmdStatusByte = 0;
11425     uint8_t payload = 0x43; /* object ID to get INIT_CAL_DONE status */
11426     uint8_t calCompleteBitField[4] = {0, 0, 0, 0};
11427 
11428     retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_ABORT_OPCODE, 0, 0);
11429     if (retVal != MYKONOS_ERR_OK)
11430     {
11431         return retVal; /* Will return if mailbox busy bit is busy for more than 2 seconds */
11432     }
11433 
11434     retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_ABORT_OPCODE, timeoutMs, &cmdStatusByte);
11435     if (retVal != MYKONOS_ERR_OK)
11436     {
11437         return retVal; /* Will return if timeout occurred */
11438     }
11439 
11440     /* Read back Calibration Completion status */
11441     retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &payload, sizeof(payload));
11442     if (retVal != MYKONOS_ERR_OK)
11443     {
11444         return retVal; /* Will return if mailbox busy bit is busy for more than 2 seconds */
11445     }
11446 
11447     retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte);
11448     if (retVal != MYKONOS_ERR_OK)
11449     {
11450         return retVal; /* Will return if timeout occurred */
11451     }
11452 
11453     retVal = MYKONOS_readArmMem(device, (MYKONOS_ADDR_ARM_START_DATA_ADDR + 4), &calCompleteBitField[0], 4, 1);
11454     if (retVal != MYKONOS_ERR_OK)
11455     {
11456         return retVal;
11457     }
11458 
11459     if (calsCompleted != NULL)
11460     {
11461         *calsCompleted = ((uint32_t)(calCompleteBitField[3]) << 24) | ((uint32_t)(calCompleteBitField[2]) << 16) | ((uint32_t)(calCompleteBitField[1]) << 8)
11462                 | ((uint32_t)(calCompleteBitField[0]));
11463     }
11464     else
11465     {
11466         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ABORT_INITCALS_NULL_PARAM,
11467                 getMykonosErrorMessage(MYKONOS_ERR_ABORT_INITCALS_NULL_PARAM));
11468         return MYKONOS_ERR_ABORT_INITCALS_NULL_PARAM;
11469     }
11470 
11471     return MYKONOS_ERR_OK;
11472 }
11473 
11474 /**
11475  * \brief Gets the device initialization calibration status
11476  *
11477  * This function requests the init cal status information from the Mykonos ARM
11478  * processor.  The ARM returns information including a bitmask that describes
11479  * which calibrations have completed during the last cal of runInitCals, as
11480  * well as the init cals that have run successfully since loading the ARM.  If
11481  * an ARM error does occur during one of the init calibrations, the initErrCal
11482  * member returns the object ID of the failing calibration.  The initErrCode
11483  * returns the specific ARM error code that caused that calibration to fail.
11484  * The calsMinimum structure member describes the minimum set of init calibrations
11485  * required to complete by the ARM before it will allow the device to move to
11486  * the radioOn state.
11487  *
11488  * <B>Dependencies</B>
11489  * - device->spiSettings
11490  * - device->spiSettings->chipSelectIndex
11491  *
11492  * \param device A pointer to the device settings structure
11493  * \param initCalStatus Pointer to a structure that returns cal status information such as cals completed since last run, and init error codes
11494  *
11495  * \retval MYKONOS_ERR_OK Function completed successfully
11496  * \retval MYKONOS_ERR_GETINITCALSTATUS_NULL_PARAM if initCalStatus parameter is a NULL pointer
11497  * \retval MYKONOS_ERR_GETINITCALSTATUS_ARMERROR if ARM returned an error while requesting the init cal status information
11498  */
MYKONOS_getInitCalStatus(mykonosDevice_t * device,mykonosInitCalStatus_t * initCalStatus)11499 mykonosErr_t MYKONOS_getInitCalStatus(mykonosDevice_t *device, mykonosInitCalStatus_t *initCalStatus)
11500 {
11501     mykonosErr_t retVal = MYKONOS_ERR_OK;
11502     uint8_t cmdStatusByte = 0;
11503     uint8_t calStatusArray[14] = {0};
11504     uint8_t payload[1] = {MYKONOS_ARM_OBJECTID_INIT_CAL_DONE};
11505 
11506     uint32_t timeoutMs = 1000;
11507 
11508     /* Verify function parameter pointer is not NULL */
11509     if (initCalStatus == NULL)
11510     {
11511         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETINITCALSTATUS_NULL_PARAM,
11512                 getMykonosErrorMessage(MYKONOS_ERR_GETINITCALSTATUS_NULL_PARAM));
11513         return MYKONOS_ERR_GETINITCALSTATUS_NULL_PARAM;
11514     }
11515 
11516     retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &payload[0], sizeof(payload));
11517     if (retVal != MYKONOS_ERR_OK)
11518     {
11519         return retVal; /* Will return if mailbox busy bit is busy for more than 2 seconds */
11520     }
11521 
11522     retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte);
11523     if (retVal != MYKONOS_ERR_OK)
11524     {
11525         if (cmdStatusByte > 0)
11526         {
11527             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETINITCALSTATUS_ARMERROR,
11528                     getMykonosErrorMessage(MYKONOS_ERR_GETINITCALSTATUS_ARMERROR));
11529             return MYKONOS_ERR_GETINITCALSTATUS_ARMERROR;
11530         }
11531 
11532         return retVal; /* Will return if timeout occurred */
11533     }
11534 
11535     if (cmdStatusByte > 0)
11536     {
11537         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETINITCALSTATUS_ARMERROR,
11538                 getMykonosErrorMessage(MYKONOS_ERR_GETINITCALSTATUS_ARMERROR));
11539         return MYKONOS_ERR_GETINITCALSTATUS_ARMERROR;
11540     }
11541 
11542     retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &calStatusArray[0], sizeof(calStatusArray), 1);
11543     if (retVal != MYKONOS_ERR_OK)
11544     {
11545         return retVal;
11546     }
11547 
11548     initCalStatus->calsDoneLifetime = ((uint32_t)(calStatusArray[3]) << 24) | ((uint32_t)(calStatusArray[2]) << 16) | ((uint32_t)(calStatusArray[1]) << 8)
11549             | ((uint32_t)(calStatusArray[0]));
11550     initCalStatus->calsDoneLastRun = ((uint32_t)(calStatusArray[7]) << 24) | ((uint32_t)(calStatusArray[6]) << 16) | ((uint32_t)(calStatusArray[5]) << 8)
11551             | ((uint32_t)(calStatusArray[4]));
11552     initCalStatus->calsMinimum = ((uint32_t)(calStatusArray[11]) << 24) | ((uint32_t)(calStatusArray[10]) << 16) | ((uint32_t)(calStatusArray[9]) << 8)
11553             | ((uint32_t)(calStatusArray[8]));
11554     initCalStatus->initErrCal = calStatusArray[12];
11555     initCalStatus->initErrCode = calStatusArray[13];
11556 
11557     return MYKONOS_ERR_OK;
11558 }
11559 
11560 /**
11561  * \brief Instructs the ARM processor to move the radio state to the Radio ON state
11562  *
11563  * When the ARM to the Radio On state, the enabled Rx and Tx signal chains will power up,
11564  * and the ARM tracking calibrations will begin.  To exit this state back to a low power,
11565  * offline state, call the MYKONOS_radioOff() function.
11566  *
11567  * <B>Dependencies</B>
11568  * - device->spiSettings->chipSelectIndex
11569  *
11570  * \param device Pointer to the device settings structure
11571  *
11572  * \retval MYKONOS_ERR_OK Function completed successfully
11573  * \retval MYKONOS_ERR_ARM_RADIOON_FAILED ARM returned error running this command
11574  */
MYKONOS_radioOn(mykonosDevice_t * device)11575 mykonosErr_t MYKONOS_radioOn(mykonosDevice_t *device)
11576 {
11577     mykonosErr_t retVal = MYKONOS_ERR_OK;
11578     uint32_t timeoutMs = 1000; //1 second timeout
11579     uint8_t cmdStatusByte = 0;
11580 
11581     retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_RADIOON_OPCODE, 0, 0);
11582     if (retVal != MYKONOS_ERR_OK)
11583     {
11584         return retVal; /* Will return if mailbox busy bit is busy for more than 2 seconds */
11585     }
11586 
11587     retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_RADIOON_OPCODE, timeoutMs, &cmdStatusByte);
11588     if (retVal != MYKONOS_ERR_OK)
11589     {
11590         if (cmdStatusByte > 0)
11591         {
11592             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ARM_RADIOON_FAILED,
11593                     getMykonosErrorMessage(MYKONOS_ERR_ARM_RADIOON_FAILED));
11594             return MYKONOS_ERR_ARM_RADIOON_FAILED;
11595         }
11596 
11597         return retVal; /* Will return if timeout occurred */
11598     }
11599 
11600     /* If ARM command error flag is 2, the command was not accepted, RUN_INIT must complete first */
11601     if (cmdStatusByte > 0)
11602     {
11603         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ARM_RADIOON_FAILED, getMykonosErrorMessage(MYKONOS_ERR_ARM_RADIOON_FAILED));
11604         return MYKONOS_ERR_ARM_RADIOON_FAILED;
11605     }
11606 
11607     return MYKONOS_ERR_OK;
11608 }
11609 
11610 /**
11611  * \brief Instructs the ARM processor to move the radio state to the off state
11612  *
11613  * When the ARM moves from the Radio On state to Radio Off (Idle) the ARM tracking calibrations
11614  * are stopped and the TxEnable/RxEnable, etc GPIO control pins will be ignored.  This will also
11615  * keep the receive and transmit chains powered down until the MYKONOS_radioOn() function
11616  * is called again.
11617  *
11618  * <B>Dependencies</B>
11619  * - device->spiSettings->chipSelectIndex
11620  *
11621  * \param device Pointer to the device settings structure
11622  *
11623  * \retval MYKONOS_ERR_OK Function completed successfully
11624  * \retval MYKONOS_ERR_ARM_RADIOOFF_FAILED ARM returned error running this command
11625  */
MYKONOS_radioOff(mykonosDevice_t * device)11626 mykonosErr_t MYKONOS_radioOff(mykonosDevice_t *device)
11627 {
11628     mykonosErr_t retVal = MYKONOS_ERR_OK;
11629     const uint8_t ABORTCAL_OPCODE = 0x00;
11630     uint32_t timeoutMs = 1000; //1 second timeout
11631     uint8_t cmdStatusByte = 0;
11632 
11633     retVal = MYKONOS_sendArmCommand(device, ABORTCAL_OPCODE, 0, 0);
11634     if (retVal != MYKONOS_ERR_OK)
11635     {
11636         return retVal; /* Will return if mailbox busy bit is busy for more than 2 seconds */
11637     }
11638 
11639     retVal = MYKONOS_waitArmCmdStatus(device, ABORTCAL_OPCODE, timeoutMs, &cmdStatusByte);
11640     if (retVal != MYKONOS_ERR_OK)
11641     {
11642         if (cmdStatusByte > 0)
11643         {
11644             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ARM_RADIOOFF_FAILED,
11645                     getMykonosErrorMessage(MYKONOS_ERR_ARM_RADIOOFF_FAILED));
11646             return MYKONOS_ERR_ARM_RADIOOFF_FAILED;
11647         }
11648 
11649         return retVal; /* Will return if timeout occurred */
11650     }
11651 
11652     if (cmdStatusByte > 0)
11653     {
11654         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ARM_RADIOOFF_FAILED, getMykonosErrorMessage(MYKONOS_ERR_ARM_RADIOOFF_FAILED));
11655         return MYKONOS_ERR_ARM_RADIOOFF_FAILED;
11656     }
11657 
11658     return MYKONOS_ERR_OK;
11659 }
11660 
11661 /**
11662  * \brief Reads the current ARM radio state
11663  *
11664  * Currently, *radioStatus only returns data in the lower 8 bits, but
11665  * is defined as a 32bit status to allow for more information to be returned
11666  * in the future.
11667  *
11668  * radioStatus  |  Bitfield
11669  * -------------|------------------
11670  *        [1:0] | State[1:0], 0=POWERUP, 1=READY, 2=INIT, 3=RADIO ON
11671  *        [3:2] | unused
11672  *        [4]   | TDD_nFDD , 1= TDD, 0=FDD
11673  *        [7:5] | unused
11674  *
11675  * <B>Dependencies</B>
11676  * - device->spiSettings->chipSelectIndex
11677  *
11678  * \param device Pointer to the device settings structure
11679  * \param radioStatus The current ARM radio state is returned in this parameter
11680  *
11681  * \retval MYKONOS_ERR_OK Function completed successfully
11682  * \retval MYKONOS_ERR_GETRADIOSTATE_NULL_PARAM Function parameter radioStatus has a NULL pointer
11683  */
MYKONOS_getRadioState(mykonosDevice_t * device,uint32_t * radioStatus)11684 mykonosErr_t MYKONOS_getRadioState(mykonosDevice_t *device, uint32_t *radioStatus)
11685 {
11686     uint8_t status = 0;
11687 
11688     /* if radioStatus is not null */
11689     if (radioStatus != NULL)
11690     {
11691         CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_ARM_OPCODE_STATE_0, &status);
11692         *radioStatus = (uint32_t)status;
11693     }
11694     else
11695     {
11696         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRADIOSTATE_NULL_PARAM,
11697                 getMykonosErrorMessage(MYKONOS_ERR_GETRADIOSTATE_NULL_PARAM));
11698         return MYKONOS_ERR_GETRADIOSTATE_NULL_PARAM;
11699     }
11700 
11701     return MYKONOS_ERR_OK;
11702 }
11703 
11704 /**
11705  * \brief Sets which ARM tracking cals are enabled during the radioOn state.
11706  *
11707  * This command must be called during radioOff state.  If called during radioOn,
11708  * an error will be returned.  The enum mykonosTrackingCalibrations_t can be used to
11709  * OR together to form the enableMask parameter.
11710  *
11711  * enableMask  |  Bit description
11712  * ------------|------------
11713  *        [0]  | TRACK_RX1_QEC
11714  *        [1]  | TRACK_RX2_QEC
11715  *        [2]  | TRACK_ORX1_QEC
11716  *        [3]  | TRACK_ORX2_QEC
11717  *        [4]  | TRACK_TX1_LOL
11718  *        [5]  | TRACK_TX2_LOL
11719  *        [6]  | TRACK_TX1_QEC
11720  *        [7]  | TRACK_TX2_QEC
11721  *        [8]  | TRACK_TX1_DPD
11722  *        [9]  | TRACK_TX2_DPD
11723  *       [10]  | TRACK_TX1_CLGC
11724  *       [11]  | TRACK_TX2_CLGC
11725  *       [12]  | TRACK_TX1_VSWR
11726  *       [13]  | TRACK_TX2_VSWR
11727  *       [16]  | TRACK_ORX1_QEC_SNLO
11728  *       [17]  | TRACK_ORX2_QEC_SNLO
11729  *       [18]  | TRACK_SRX_QEC
11730  *
11731  *
11732  * <B>Dependencies</B>
11733  * - device->spiSettings->chipSelectIndex
11734  *
11735  * \param device Pointer to the device settings structure
11736  * \param enableMask A bitmask that selects which cals to run during radioOn state.
11737  *
11738  * \retval MYKONOS_ERR_OK Function completed successfully
11739  * \retval MYKONOS_ERR_EN_TRACKING_CALS_ARMSTATE_ERROR Error: Tracking cals can only be enabled in the radioOff state.
11740  * \retval MYKONOS_ERR_EN_TRACKING_CALS_ARMERROR ARM returned error when executing this command
11741  */
MYKONOS_enableTrackingCals(mykonosDevice_t * device,uint32_t enableMask)11742 mykonosErr_t MYKONOS_enableTrackingCals(mykonosDevice_t *device, uint32_t enableMask)
11743 {
11744     mykonosErr_t retVal = MYKONOS_ERR_OK;
11745     uint8_t armData[4] = {0, 0, 0, 0};
11746     uint8_t extData[4] = {MYKONOS_ARM_OBJECTID_CALSCHEDULER, 0x00, 0x00, 0x04}; //Target ARM Object ID, Offset LSB, Offset MSB, Length
11747     uint32_t timeoutMs = 0;
11748     uint8_t cmdStatusByte = 0;
11749     uint32_t radioStatus = 0;
11750     uint8_t allowTx1AttenUpdates = 0;
11751     uint8_t allowTx2AttenUpdates = 0;
11752 
11753 #if (MYKONOS_VERBOSE == 1)
11754     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enableTrackingCals()\n");
11755 #endif
11756 
11757     /* read radio state to make sure ARM is in radioOff /IDLE */
11758     retVal = MYKONOS_getRadioState(device, &radioStatus);
11759     if (retVal != MYKONOS_ERR_OK)
11760     {
11761         return retVal;
11762     }
11763 
11764     /* throw error if not in radioOff/IDLE state */
11765     if ((radioStatus & 0x03) != MYKONOS_ARM_SYSTEMSTATE_IDLE)
11766     {
11767         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_EN_TRACKING_CALS_ARMSTATE_ERROR,
11768                 getMykonosErrorMessage(MYKONOS_ERR_EN_TRACKING_CALS_ARMSTATE_ERROR));
11769         return MYKONOS_ERR_EN_TRACKING_CALS_ARMSTATE_ERROR;
11770     }
11771 
11772     /* In the ARM, DPD tracking and CLGC tracking share the same cal.  Must
11773      * set extra enable bits in ARM Memory to tell which cal to run. */
11774     retVal = enableDpdTracking(device, ((enableMask & (uint32_t)TRACK_TX1_DPD) ? 1 : 0), ((enableMask & (uint32_t)TRACK_TX2_DPD) ? 1 : 0));
11775     if (retVal != MYKONOS_ERR_OK)
11776     {
11777         return retVal;
11778     }
11779 
11780     if (((device->profilesValid & TX_PROFILE_VALID) > 0) && (device->tx->clgcConfig != NULL))
11781     {
11782         allowTx1AttenUpdates = device->tx->clgcConfig->allowTx1AttenUpdates;
11783         allowTx2AttenUpdates = device->tx->clgcConfig->allowTx2AttenUpdates;
11784     }
11785     else
11786     {
11787         allowTx1AttenUpdates = 0;
11788         allowTx2AttenUpdates = 0;
11789     }
11790 
11791     retVal = enableClgcTracking(device, ((allowTx1AttenUpdates > 0) ? 1 : 0), ((allowTx2AttenUpdates > 0) ? 1 : 0));
11792     if (retVal != MYKONOS_ERR_OK)
11793     {
11794         return retVal;
11795     }
11796 
11797     armData[0] = (uint8_t)(enableMask & 0xFF);
11798     armData[1] = (uint8_t)((enableMask >> 8) & 0xFF);
11799     armData[2] = (uint8_t)((enableMask >> 16) & 0xFF);
11800     armData[3] = (uint8_t)((enableMask >> 24) & 0xFF);
11801     retVal = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &armData[0], sizeof(armData));
11802     if (retVal != MYKONOS_ERR_OK)
11803     {
11804         return retVal;
11805     }
11806 
11807     retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_WRITECFG_OPCODE, &extData[0], sizeof(extData));
11808     if (retVal != MYKONOS_ERR_OK)
11809     {
11810         return retVal;
11811     }
11812 
11813     timeoutMs = 1000;
11814     retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_WRITECFG_OPCODE, timeoutMs, &cmdStatusByte);
11815     if (retVal != MYKONOS_ERR_OK)
11816     {
11817         if (cmdStatusByte > 0)
11818         {
11819             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_EN_TRACKING_CALS_ARMERROR,
11820                     getMykonosErrorMessage(MYKONOS_ERR_EN_TRACKING_CALS_ARMERROR));
11821             return MYKONOS_ERR_EN_TRACKING_CALS_ARMERROR;
11822         }
11823 
11824         return retVal;
11825     }
11826 
11827     if (cmdStatusByte > 0)
11828     {
11829         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_EN_TRACKING_CALS_ARMERROR,
11830                 getMykonosErrorMessage(MYKONOS_ERR_EN_TRACKING_CALS_ARMERROR));
11831         return MYKONOS_ERR_EN_TRACKING_CALS_ARMERROR;
11832     }
11833 
11834     return MYKONOS_ERR_OK;
11835 }
11836 
11837 /**
11838  * \brief Reschedules a tracking calibration to run. Can be used to
11839  * override the tracking calibration timer and force a tracking calibration to run.
11840  * Can be used to reschedule a tracking calibration after a tracking calibration
11841  * error has been detected.  Only one tracking calibration object can be scheduled
11842  * per channel per function call.
11843  *
11844  * \pre Command can be called in either Radio On or Radio Off state.  ARM must be
11845  * initialized.
11846  *
11847  * <B>Dependencies</B>
11848  * - device->spiSettings->chipSelectIndex
11849  *
11850  * \param device Pointer to the device settings structure
11851  * \param trackingCal Selects the tracking calibration to schedule.
11852  *
11853  * \retval MYKONOS_ERR_RESCHEDULE_TRACK_CAL_INV Not valid calibration passed
11854  * \retval MYKONOS_ERR_RESCHEDULE_TRACK_ARMERRFLAG ARM error
11855  * \retval MYKONOS_ERR_OK Function completed successfully
11856  */
MYKONOS_rescheduleTrackingCal(mykonosDevice_t * device,mykonosTrackingCalibrations_t trackingCal)11857 mykonosErr_t MYKONOS_rescheduleTrackingCal(mykonosDevice_t *device, mykonosTrackingCalibrations_t trackingCal)
11858 {
11859     mykonosErr_t retVal = MYKONOS_ERR_OK;
11860     uint8_t extData[3] = {0};
11861     uint8_t cmdStatusByte = 0;
11862     uint32_t timeoutMs = 1000;
11863 
11864 #if (MYKONOS_VERBOSE == 1)
11865     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_rescheduleTrackingCal()\n");
11866 #endif
11867 
11868     switch (trackingCal)
11869     {
11870         case TRACK_RX1_QEC:
11871             extData[1] = MYKONOS_ARM_OBJECTID_RXQEC_TRACKING;
11872             extData[2] = 0;
11873             break;
11874 
11875         case TRACK_RX2_QEC:
11876             extData[1] = MYKONOS_ARM_OBJECTID_RXQEC_TRACKING;
11877             extData[2] = 1;
11878             break;
11879 
11880         case TRACK_ORX1_QEC:
11881             extData[1] = MYKONOS_ARM_OBJECTID_ORXQEC_TRACKING;
11882             extData[2] = 0;
11883             break;
11884 
11885         case TRACK_ORX2_QEC:
11886             extData[1] = MYKONOS_ARM_OBJECTID_ORXQEC_TRACKING;
11887             extData[2] = 1;
11888             break;
11889 
11890         case TRACK_TX1_LOL:
11891             extData[1] = MYKONOS_ARM_OBJECTID_TXLOL_TRACKING;
11892             extData[2] = 0;
11893             break;
11894 
11895         case TRACK_TX2_LOL:
11896             extData[1] = MYKONOS_ARM_OBJECTID_TXLOL_TRACKING;
11897             extData[2] = 1;
11898             break;
11899 
11900         case TRACK_TX1_QEC:
11901             extData[1] = MYKONOS_ARM_OBJECTID_TXQEC_TRACKING;
11902             extData[2] = 0;
11903             break;
11904 
11905         case TRACK_TX2_QEC:
11906             extData[1] = MYKONOS_ARM_OBJECTID_TXQEC_TRACKING;
11907             extData[2] = 1;
11908             break;
11909 
11910         case TRACK_TX1_DPD:
11911             extData[1] = MYKONOS_ARM_OBJECTID_DPDCONFIG;
11912             extData[2] = 0;
11913             break;
11914 
11915         case TRACK_TX2_DPD:
11916             extData[1] = MYKONOS_ARM_OBJECTID_DPDCONFIG;
11917             extData[2] = 1;
11918             break;
11919 
11920         case TRACK_TX1_CLGC:
11921             extData[1] = MYKONOS_ARM_OBJECTID_CLGCCONFIG;
11922             extData[2] = 0;
11923             break;
11924 
11925         case TRACK_TX2_CLGC:
11926             extData[1] = MYKONOS_ARM_OBJECTID_CLGCCONFIG;
11927             extData[2] = 1;
11928             break;
11929 
11930         case TRACK_TX1_VSWR:
11931             extData[1] = MYKONOS_ARM_OBJECTID_VSWRCONFIG;
11932             extData[2] = 0;
11933             break;
11934 
11935         case TRACK_TX2_VSWR:
11936             extData[1] = MYKONOS_ARM_OBJECTID_VSWRCONFIG;
11937             extData[2] = 1;
11938             break;
11939 
11940         default:
11941             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RESCHEDULE_TRACK_CAL_INV,
11942                     getMykonosErrorMessage(MYKONOS_ERR_RESCHEDULE_TRACK_CAL_INV));
11943             return MYKONOS_ERR_RESCHEDULE_TRACK_CAL_INV;
11944     }
11945 
11946     extData[0] = MYKONOS_ARM_OBJECTID_TRACKING_CAL_PENDING;
11947 
11948     /* sending ARM command */
11949     retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_SET_OPCODE, &extData[0], sizeof(extData));
11950     if (retVal != MYKONOS_ERR_OK)
11951     {
11952         return retVal;
11953     }
11954 
11955     /* check for completion */
11956     retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_SET_OPCODE, timeoutMs, &cmdStatusByte);
11957     if (retVal != MYKONOS_ERR_OK)
11958     {
11959         if (cmdStatusByte > 0)
11960         {
11961             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RESCHEDULE_TRACK_ARMERRFLAG,
11962                     getMykonosErrorMessage(MYKONOS_ERR_RESCHEDULE_TRACK_ARMERRFLAG));
11963             return MYKONOS_ERR_RESCHEDULE_TRACK_ARMERRFLAG;
11964         }
11965 
11966         return retVal;
11967     }
11968 
11969     if (cmdStatusByte > 0)
11970     {
11971         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RESCHEDULE_TRACK_ARMERRFLAG,
11972                 getMykonosErrorMessage(MYKONOS_ERR_RESCHEDULE_TRACK_ARMERRFLAG));
11973         return MYKONOS_ERR_RESCHEDULE_TRACK_ARMERRFLAG;
11974     }
11975 
11976     return retVal;
11977 }
11978 
11979 /**
11980  * \brief Suspend or resume tracking calibrations in RADIO_ON.
11981  *
11982  * This function is used to suspend or resume active tracking calibrations based on the passed mask trackingCals.
11983  *
11984  * \pre Command can be called in Radio On.
11985  *
11986  * trackCals[bit]  |  Bit description
11987  * ----------------|------------
11988  *       [0]       | TRACK_RX1_QEC
11989  *       [1]       | TRACK_RX2_QEC
11990  *       [2]       | TRACK_ORX1_QEC
11991  *       [3]       | TRACK_ORX2_QEC
11992  *       [4]       | TRACK_TX1_LOL
11993  *       [5]       | TRACK_TX2_LOL
11994  *       [6]       | TRACK_TX1_QEC
11995  *       [7]       | TRACK_TX2_QEC
11996  *       [8]       | TRACK_TX1_DPD
11997  *       [9]       | TRACK_TX2_DPD
11998  *      [10]       | TRACK_TX1_CLGC
11999  *      [11]       | TRACK_TX2_CLGC
12000  *      [12]       | TRACK_TX1_VSWR
12001  *      [13]       | TRACK_TX2_VSWR
12002  *
12003  * <B>Dependencies</B>
12004  * - device->spiSettings->chipSelectIndex
12005  *
12006  * \param device Pointer to the device settings structure
12007  * \param trackCals Selects the tracking calibrations to suspend or resume during the radio ON state.
12008  * mykonosTrackingCalibrations_t enumerated types are or'd together to form the tracking calibration
12009  * mask word. If the bit is high the calibration will resume, if the bit is low the calibration will be suspended.
12010  *
12011  * \retval MYKONOS_ERR_SETSTATEALL_TRACK_CAL_INV Not valid calibration mask passed for trackCals
12012  * \retval MYKONOS_ERR_SETSTATEALL_TRACK_ARMERRFLAG ARM error
12013  * \retval MYKONOS_ERR_OK Function completed successfully
12014  */
MYKONOS_setAllTrackCalState(mykonosDevice_t * device,uint32_t trackCals)12015 mykonosErr_t MYKONOS_setAllTrackCalState(mykonosDevice_t *device, uint32_t trackCals)
12016 {
12017     mykonosErr_t retVal = MYKONOS_ERR_OK;
12018     uint8_t cfgData[4] = {0};
12019     uint8_t extData[3] = {MYKONOS_ARM_OBJECTID_TRACKING_CAL_SUSPEND_RESUME, 0x0F, 0};
12020     uint8_t cmdStatusByte = 0;
12021     uint32_t enTrackCal = 0x00;
12022     uint32_t timeoutMs = 1000;
12023 
12024     const uint32_t TRACKING_MASK = 0x3FFF;
12025 
12026 #if (MYKONOS_VERBOSE == 1)
12027     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setAllTrackCalState()\n");
12028 #endif
12029 
12030     /* reading enabled tracking calibrations */
12031     retVal = MYKONOS_getEnabledTrackingCals(device, &enTrackCal);
12032 
12033     /* trackingCalMask check */
12034     if (((trackCals | enTrackCal) > enTrackCal) || (trackCals > TRACKING_MASK))
12035     {
12036         /* invalid cal mask error return, tracking cal not enable so we can not resume it */
12037         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETSTATEALL_TRACK_CAL_INV,
12038                 getMykonosErrorMessage(MYKONOS_ERR_SETSTATEALL_TRACK_CAL_INV));
12039         return MYKONOS_ERR_SETSTATEALL_TRACK_CAL_INV;
12040     }
12041 
12042     /* convert tracking mask to array of uint8_t type */
12043     cfgData[0] = (uint8_t)(trackCals & 0xFF);
12044     cfgData[1] = (uint8_t)((trackCals >> 8) & 0xFF);
12045     cfgData[2] = (uint8_t)((trackCals >> 16) & 0x0FF);
12046     cfgData[3] = (uint8_t)((trackCals >> 24) & 0xFF);
12047 
12048     retVal = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &cfgData[0], sizeof(cfgData));
12049     if (retVal != MYKONOS_ERR_OK)
12050     {
12051         return retVal;
12052     }
12053 
12054     retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_SET_OPCODE, &extData[0], sizeof(extData));
12055     if (retVal != MYKONOS_ERR_OK)
12056     {
12057         return retVal;
12058     }
12059 
12060     /* check for completion */
12061     retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_SET_OPCODE, timeoutMs, &cmdStatusByte);
12062     if (retVal != MYKONOS_ERR_OK)
12063     {
12064         if (cmdStatusByte > 0)
12065         {
12066             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETSTATEALL_TRACK_ARMERRFLAG,
12067                     getMykonosErrorMessage(MYKONOS_ERR_SETSTATEALL_TRACK_ARMERRFLAG));
12068             return MYKONOS_ERR_SETSTATEALL_TRACK_ARMERRFLAG;
12069         }
12070 
12071         return retVal;
12072     }
12073 
12074     if (cmdStatusByte > 0)
12075     {
12076         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETSTATEALL_TRACK_ARMERRFLAG,
12077                 getMykonosErrorMessage(MYKONOS_ERR_SETSTATEALL_TRACK_ARMERRFLAG));
12078         return MYKONOS_ERR_SETSTATEALL_TRACK_ARMERRFLAG;
12079     }
12080 
12081     return retVal;
12082 }
12083 
12084 /**
12085  * \brief Get the Suspended or Resumed state for tracking calibrations
12086  *
12087  * This function is used to get the suspend or resume state of all active tracking calibrations and the state is stored in trackCals.
12088  *
12089  * \pre Command can be called in Radio On.
12090  *
12091  * <B>Dependencies</B>
12092  * - device->spiSettings->chipSelectIndex
12093  *
12094  * \param device Pointer to the device settings structure
12095  * \param trackCals pointer to store the tracking calibration state.
12096  * If the bit is set then the tracking calibration is resumed and if not set then the tracking cal is suspended, the bit field follows:
12097  *
12098  * trackCals[bit] |  Bit description
12099  * ---------------|------------
12100  *       [0]      | TRACK_RX1_QEC
12101  *       [1]      | TRACK_RX2_QEC
12102  *       [2]      | TRACK_ORX1_QEC
12103  *       [3]      | TRACK_ORX2_QEC
12104  *       [4]      | TRACK_TX1_LOL
12105  *       [5]      | TRACK_TX2_LOL
12106  *       [6]      | TRACK_TX1_QEC
12107  *       [7]      | TRACK_TX2_QEC
12108  *       [8]      | TRACK_TX1_DPD
12109  *       [9]      | TRACK_TX2_DPD
12110  *      [10]      | TRACK_TX1_CLGC
12111  *      [11]      | TRACK_TX2_CLGC
12112  *      [12]      | TRACK_TX1_VSWR
12113  *      [13]      | TRACK_TX2_VSWR
12114  *
12115  * \retval MYKONOS_ERR_GETSTATEALL_TRACK_NULL_PARAM Null parameter passed for trackCals
12116  * \retval MYKONOS_ERR_GETSTATEALL_TRACK_ARMERRFLAG ARM error flag set.
12117  * \retval MYKONOS_ERR_GETSTATEALL_TRACK_ARMERROR ARM command error.
12118  * \retval MYKONOS_ERR_OK Function completed successfully
12119  */
MYKONOS_getAllTrackCalState(mykonosDevice_t * device,uint32_t * trackCals)12120 mykonosErr_t MYKONOS_getAllTrackCalState(mykonosDevice_t *device, uint32_t *trackCals)
12121 {
12122     mykonosErr_t retVal = MYKONOS_ERR_OK;
12123     uint8_t extData = MYKONOS_ARM_OBJECTID_TRACKING_CAL_SUSPEND_RESUME;
12124     uint8_t armData[4] = {0};
12125     uint8_t cmdStatusByte = 0;
12126     uint32_t timeoutMs = 1000;
12127 
12128 #if (MYKONOS_VERBOSE == 1)
12129     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getAllTrackCalState()\n");
12130 #endif
12131 
12132     /* Check for passed parameter */
12133     if (trackCals == NULL)
12134     {
12135         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETSTATEALL_TRACK_NULL_PARAM,
12136                 getMykonosErrorMessage(MYKONOS_ERR_GETSTATEALL_TRACK_NULL_PARAM));
12137         return MYKONOS_ERR_GETSTATEALL_TRACK_NULL_PARAM;
12138     }
12139 
12140     /* sending ARM command */
12141     retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &extData, sizeof(extData));
12142     if (retVal != MYKONOS_ERR_OK)
12143     {
12144         return retVal;
12145     }
12146 
12147     /* check for completion */
12148     retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte);
12149     if (retVal != MYKONOS_ERR_OK)
12150     {
12151         if (cmdStatusByte > 0)
12152         {
12153             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETSTATEALL_TRACK_ARMERRFLAG,
12154                     getMykonosErrorMessage(MYKONOS_ERR_GETSTATEALL_TRACK_ARMERRFLAG));
12155             return MYKONOS_ERR_GETSTATEALL_TRACK_ARMERRFLAG;
12156         }
12157 
12158         return retVal;
12159     }
12160 
12161     if (cmdStatusByte > 0)
12162     {
12163         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETSTATEALL_TRACK_ARMERRFLAG,
12164                 getMykonosErrorMessage(MYKONOS_ERR_GETSTATEALL_TRACK_ARMERRFLAG));
12165         return MYKONOS_ERR_GETSTATEALL_TRACK_ARMERRFLAG;
12166     }
12167 
12168     /* read 32-bit tracking state from ARM memory */
12169     retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &armData[0], sizeof(armData), 1);
12170     if (retVal != MYKONOS_ERR_OK)
12171     {
12172         return retVal;
12173     }
12174 
12175     *trackCals = (uint32_t)armData[0] | ((uint32_t)armData[1] << 8) | ((uint32_t)armData[2] << 16) | ((uint32_t)armData[3] << 24);
12176 
12177     return retVal;
12178 }
12179 
12180 /**
12181  * \brief Suspend or resume individual tracking calibration
12182  *
12183  * \pre The tracking calibration must have been enabled with MYKONOS_enableTrackingCals(), this command can be called in Radio On.
12184  *
12185  * <B>Dependencies</B>
12186  * - device->spiSettings->chipSelectIndex
12187  *
12188  * \param device Pointer to the device settings structure
12189  * \param trackingCal Selects the tracking calibration to resume or suspend.
12190  * \param trackCalState if set then the selected tracking calibration will be resumed and if not set then the tracking cal will be suspended
12191  *
12192  * \retval MYKONOS_ERR_SETSTATE_TRACK_CAL_INV Not valid calibration passed
12193  * \retval MYKONOS_ERR_SETSTATE_TRACK_ARMERRFLAG ARM error
12194  * \retval MYKONOS_ERR_OK Function completed successfully
12195  */
MYKONOS_setTrackingCalState(mykonosDevice_t * device,mykonosTrackingCalibrations_t trackingCal,uint8_t trackCalState)12196 mykonosErr_t MYKONOS_setTrackingCalState(mykonosDevice_t *device, mykonosTrackingCalibrations_t trackingCal, uint8_t trackCalState)
12197 {
12198     mykonosErr_t retVal = MYKONOS_ERR_OK;
12199     uint8_t extData[2] = {0};
12200     uint8_t cmdStatusByte = 0;
12201     uint8_t suspendTrack = 0x0F;
12202     uint32_t timeoutMs = 1000;
12203     uint32_t enTrackCal = 0x00;
12204 
12205     const uint8_t CHANNEL_1 = 0x00;
12206     const uint8_t CHANNEL_2 = 0x10;
12207 
12208 #if (MYKONOS_VERBOSE == 1)
12209     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setTrackingCalState()\n");
12210 #endif
12211 
12212     if (trackCalState > 0)
12213     {
12214         suspendTrack = 0x2F;
12215     }
12216 
12217     /* reading enabled tracking calibrations */
12218     retVal = MYKONOS_getEnabledTrackingCals(device, &enTrackCal);
12219     if (retVal != MYKONOS_ERR_OK)
12220     {
12221         return retVal;
12222     }
12223 
12224     /* trackingCalMask check */
12225     if (((uint8_t)trackingCal & enTrackCal) != (uint8_t)trackingCal)
12226     {
12227         /* invalid cal mask error return, tracking cal not enable so we can not resume or suspend it */
12228         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETSTATE_TRACK_CAL_INV,
12229                 getMykonosErrorMessage(MYKONOS_ERR_SETSTATE_TRACK_CAL_INV));
12230         return MYKONOS_ERR_SETSTATE_TRACK_CAL_INV;
12231     }
12232 
12233     switch (trackingCal)
12234     {
12235         case TRACK_RX1_QEC:
12236             extData[1] = MYKONOS_ARM_OBJECTID_RXQEC_TRACKING & suspendTrack;
12237             extData[1] |= CHANNEL_1;
12238             break;
12239 
12240         case TRACK_RX2_QEC:
12241             extData[1] = MYKONOS_ARM_OBJECTID_RXQEC_TRACKING & suspendTrack;
12242             extData[1] |= CHANNEL_2;
12243             break;
12244 
12245         case TRACK_ORX1_QEC:
12246             extData[1] = MYKONOS_ARM_OBJECTID_ORXQEC_TRACKING & suspendTrack;
12247             extData[1] |= CHANNEL_1;
12248             break;
12249 
12250         case TRACK_ORX2_QEC:
12251             extData[1] = MYKONOS_ARM_OBJECTID_ORXQEC_TRACKING & suspendTrack;
12252             extData[1] |= CHANNEL_2;
12253             break;
12254 
12255         case TRACK_TX1_LOL:
12256             extData[1] = MYKONOS_ARM_OBJECTID_TXLOL_TRACKING & suspendTrack;
12257             extData[1] |= CHANNEL_1;
12258             break;
12259 
12260         case TRACK_TX2_LOL:
12261             extData[1] = MYKONOS_ARM_OBJECTID_TXLOL_TRACKING & suspendTrack;
12262             extData[1] |= CHANNEL_2;
12263             break;
12264 
12265         case TRACK_TX1_QEC:
12266             extData[1] = MYKONOS_ARM_OBJECTID_TXQEC_TRACKING & suspendTrack;
12267             extData[1] |= CHANNEL_1;
12268             break;
12269 
12270         case TRACK_TX2_QEC:
12271             extData[1] = MYKONOS_ARM_OBJECTID_TXQEC_TRACKING & suspendTrack;
12272             extData[1] |= CHANNEL_2;
12273             break;
12274 
12275         case TRACK_TX1_DPD:
12276             extData[1] = MYKONOS_ARM_OBJECTID_DPDCONFIG & suspendTrack;
12277             extData[1] |= CHANNEL_1;
12278             break;
12279 
12280         case TRACK_TX2_DPD:
12281             extData[1] = MYKONOS_ARM_OBJECTID_DPDCONFIG & suspendTrack;
12282             extData[1] |= CHANNEL_2;
12283             break;
12284 
12285         case TRACK_TX1_CLGC:
12286             extData[1] = MYKONOS_ARM_OBJECTID_CLGCCONFIG & suspendTrack;
12287             extData[1] |= CHANNEL_1;
12288             break;
12289 
12290         case TRACK_TX2_CLGC:
12291             extData[1] = MYKONOS_ARM_OBJECTID_CLGCCONFIG & suspendTrack;
12292             extData[1] |= CHANNEL_2;
12293             break;
12294 
12295         case TRACK_TX1_VSWR:
12296             extData[1] = MYKONOS_ARM_OBJECTID_VSWRCONFIG & suspendTrack;
12297             extData[1] |= CHANNEL_1;
12298             break;
12299 
12300         case TRACK_TX2_VSWR:
12301             extData[1] = MYKONOS_ARM_OBJECTID_VSWRCONFIG & suspendTrack;
12302             extData[1] |= CHANNEL_2;
12303             break;
12304 
12305         default:
12306             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETSTATE_TRACK_CAL_INV,
12307                     getMykonosErrorMessage(MYKONOS_ERR_SETSTATE_TRACK_CAL_INV));
12308             return MYKONOS_ERR_SETSTATE_TRACK_CAL_INV;
12309     }
12310 
12311     extData[0] = MYKONOS_ARM_OBJECTID_TRACKING_CAL_SUSPEND_RESUME;
12312 
12313     /* sending ARM command */
12314     retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_SET_OPCODE, &extData[0], sizeof(extData));
12315     if (retVal != MYKONOS_ERR_OK)
12316     {
12317         return retVal;
12318     }
12319 
12320     /* check for completion */
12321     retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_SET_OPCODE, timeoutMs, &cmdStatusByte);
12322     if (retVal != MYKONOS_ERR_OK)
12323     {
12324         if (cmdStatusByte > 0)
12325         {
12326             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETSTATE_TRACK_ARMERRFLAG,
12327                     getMykonosErrorMessage(MYKONOS_ERR_SETSTATE_TRACK_ARMERRFLAG));
12328             return MYKONOS_ERR_SETSTATE_TRACK_ARMERRFLAG;
12329         }
12330     }
12331 
12332     return retVal;
12333 }
12334 
12335 /**
12336  * \brief Get the Suspended or Resumed state for individual tracking calibration
12337  *
12338  * \pre Command can be called in Radio On.
12339  *
12340  * <B>Dependencies</B>
12341  * - device->spiSettings->chipSelectIndex
12342  *
12343  * \param device Pointer to the device settings structure
12344  * \param trackingCal Selects the tracking calibration to get the resumed or suspended state.
12345  * \param trackCalState pointer to store the tracking calibration state,
12346  * if set then the selected tracking calibration is resumed and if not set then the tracking cal is suspended
12347  *
12348  * \retval MYKONOS_ERR_GETSTATE_TRACK_NULL_PARAM Null parameter passed to trackCalState
12349  * \retval MYKONOS_ERR_GETSTATE_TRACK_ARMERRFLAG ARM command error flag set.
12350  * \retval MYKONOS_ERR_GETSTATE_TRACK_ARMERROR ARM command error.
12351  * \retval MYKONOS_ERR_OK Function completed successfully
12352  */
MYKONOS_getTrackingCalState(mykonosDevice_t * device,mykonosTrackingCalibrations_t trackingCal,uint8_t * trackCalState)12353 mykonosErr_t MYKONOS_getTrackingCalState(mykonosDevice_t *device, mykonosTrackingCalibrations_t trackingCal, uint8_t *trackCalState)
12354 {
12355     mykonosErr_t retVal = MYKONOS_ERR_OK;
12356     uint8_t extData = MYKONOS_ARM_OBJECTID_TRACKING_CAL_SUSPEND_RESUME;
12357     uint8_t armData[4] = {0};
12358     uint8_t cmdStatusByte = 0;
12359     uint32_t timeoutMs = 1000;
12360     uint32_t trackMask = 0x00;
12361 
12362 #if (MYKONOS_VERBOSE == 1)
12363     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getTrackingCalState()\n");
12364 #endif
12365 
12366     /* Check for passed parameter */
12367     if (trackCalState == NULL)
12368     {
12369         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETSTATE_TRACK_NULL_PARAM,
12370                 getMykonosErrorMessage(MYKONOS_ERR_GETSTATE_TRACK_NULL_PARAM));
12371         return MYKONOS_ERR_GETSTATE_TRACK_NULL_PARAM;
12372     }
12373 
12374     /* sending ARM command */
12375     retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &extData, sizeof(extData));
12376     if (retVal != MYKONOS_ERR_OK)
12377     {
12378         return retVal;
12379     }
12380 
12381     /* check for completion */
12382     retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte);
12383     if (retVal != MYKONOS_ERR_OK)
12384     {
12385         if (cmdStatusByte > 0)
12386         {
12387             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETSTATE_TRACK_ARMERRFLAG,
12388                     getMykonosErrorMessage(MYKONOS_ERR_GETSTATE_TRACK_ARMERRFLAG));
12389             return MYKONOS_ERR_GETSTATE_TRACK_ARMERRFLAG;
12390         }
12391 
12392         return retVal;
12393     }
12394 
12395     if (cmdStatusByte > 0)
12396     {
12397         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETSTATE_TRACK_ARMERRFLAG,
12398                 getMykonosErrorMessage(MYKONOS_ERR_GETSTATE_TRACK_ARMERRFLAG));
12399         return MYKONOS_ERR_GETSTATE_TRACK_ARMERRFLAG;
12400     }
12401 
12402     /* read 32-bit tracking state from ARM memory */
12403     retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &armData[0], sizeof(armData), 1);
12404     if (retVal != MYKONOS_ERR_OK)
12405     {
12406         return retVal;
12407     }
12408 
12409     trackMask = (uint32_t)armData[0] | ((uint32_t)armData[1] << 8) | ((uint32_t)armData[2] << 16) | ((uint32_t)armData[3] << 24);
12410 
12411     if (trackMask & (uint32_t)trackingCal)
12412     {
12413         *trackCalState = 1;
12414     }
12415     else
12416     {
12417         *trackCalState = 0;
12418     }
12419 
12420     return retVal;
12421 }
12422 
12423 /**
12424  * \brief Reads back which ARM tracking cals are enabled
12425  *
12426  * enableMask  |  Bit description
12427  * ------------|----------------------
12428  *        [0]  | TRACK_RX1_QEC
12429  *        [1]  | TRACK_RX2_QEC
12430  *        [2]  | TRACK_ORX1_QEC
12431  *        [3]  | TRACK_ORX2_QEC
12432  *        [4]  | TRACK_TX1_LOL
12433  *        [5]  | TRACK_TX2_LOL
12434  *        [6]  | TRACK_TX1_QEC
12435  *        [7]  | TRACK_TX2_QEC
12436  *        [8]  | TRACK_TX1_DPD
12437  *        [9]  | TRACK_TX2_DPD
12438  *       [10]  | TRACK_TX1_CLGC
12439  *       [11]  | TRACK_TX2_CLGC
12440  *       [12]  | TRACK_TX1_VSWR
12441  *       [13]  | TRACK_TX2_VSWR
12442  *       [16]  | TRACK_ORX1_QEC_SNLO
12443  *       [17]  | TRACK_ORX1_QEC_SNLO
12444  *       [18]  | TRACK_SRX_QEC
12445  *
12446  * <B>Dependencies</B>
12447  * - device->spiSettings->chipSelectIndex
12448  *
12449  * \param device Pointer to the device settings structure
12450  * \param enableMask Returned bitmask that shows which tracking cals are enabled
12451  *                   to run during radioOn state. See mykonosTrackingCalibrations_t enum of tracking cals.
12452  *
12453  * \retval MYKONOS_ERR_OK Function completed successfully
12454  */
MYKONOS_getEnabledTrackingCals(mykonosDevice_t * device,uint32_t * enableMask)12455 mykonosErr_t MYKONOS_getEnabledTrackingCals(mykonosDevice_t *device, uint32_t *enableMask)
12456 {
12457     mykonosErr_t retVal = MYKONOS_ERR_OK;
12458     uint8_t armData[4] = {0};
12459 
12460 #if (MYKONOS_VERBOSE == 1)
12461     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getEnabledTrackingCals()\n");
12462 #endif
12463 
12464     /* Ask ARM to read tracking cal enable bits and place in mailbox buffer memory */
12465     retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_CALSCHEDULER, 0, &armData[0], 4);
12466     if (retVal != MYKONOS_ERR_OK)
12467     {
12468         return retVal;
12469     }
12470 
12471     *enableMask = ((uint32_t)(armData[0]) | ((uint32_t)(armData[1]) << 8) | ((uint32_t)(armData[2]) << 16) | ((uint32_t)(armData[3]) << 24));
12472 
12473     return MYKONOS_ERR_OK;
12474 }
12475 
12476 /**
12477  * \brief Returns the tracking calibration pending and error status.
12478  *
12479  * When in radioOn state, the enabled tracking calibrations will set the pending
12480  * flag when the particular calibration is ready to be run, but has not completed
12481  * yet. For Tx tracking cals to complete, the BBIC must set the ObsRx path to
12482  * the INTERNAL CALS mode.  If a tracking calibration had an error, the corresponding
12483  * error flag will be asserted.
12484  *
12485  *  pendingCalMask | bit Description
12486  * ----------------|--------------------------------------------------------
12487  *            [0]  | Rx1 QEC tracking pending
12488  *            [1]  | Rx1 QEC tracking error
12489  *            [2]  | Rx2 QEC tracking pending
12490  *            [3]  | Rx2 QEC tracking error
12491  *            [4]  | ORx1 QEC tracking pending
12492  *            [5]  | ORx1 QEC tracking error
12493  *            [6]  | ORx2 QEC tracking pending
12494  *            [7]  | ORx2 QEC tracking error
12495  *            [8]  | Tx1 LOL tracking pending
12496  *            [9]  | Tx1 LOL tracking error
12497  *           [10]  | Tx2 LOL tracking pending
12498  *           [11]  | Tx2 LOL tracking error
12499  *           [12]  | Tx1 QEC tracking pending
12500  *           [13]  | Tx1 QEC tracking error
12501  *           [14]  | Tx2 QEC tracking pending
12502  *           [15]  | Tx2 QEC tracking error
12503  *           [16]  | Tx1 DPD tracking pending
12504  *           [17]  | Tx1 DPD tracking error
12505  *           [18]  | Tx2 DPD tracking pending
12506  *           [19]  | Tx2 DPD tracking error
12507  *           [20]  | Tx1 CLGC tracking pending
12508  *           [21]  | Tx1 CLGC tracking error
12509  *           [22]  | Tx2 CLGC tracking pending
12510  *           [23]  | Tx2 CLGC tracking error
12511  *           [24]  | Tx1 VSWR tracking pending
12512  *           [25]  | Tx1 VSWR tracking error
12513  *           [26]  | Tx2 VSWR tracking pending
12514  *           [27]  | Tx2 VSWR tracking error
12515  *
12516  * <B>Dependencies</B>
12517  * - device->spiSettings->chipSelectIndex
12518  *
12519  * \param device Pointer to the device settings structure
12520  * \param pendingCalMask Bit mask that describes which tracking cals are pending
12521  *                       or had errors
12522  *
12523  * \retval MYKONOS_ERR_OK Function completed successfully
12524  * \retval MYKONOS_ERR_GETPENDTRKCALS_NULL_PARAM Function parameter pendingCalMask is a NULL pointer
12525  */
MYKONOS_getPendingTrackingCals(mykonosDevice_t * device,uint32_t * pendingCalMask)12526 mykonosErr_t MYKONOS_getPendingTrackingCals(mykonosDevice_t *device, uint32_t *pendingCalMask)
12527 {
12528     uint8_t readData[4] = {0};
12529 
12530 #if (MYKONOS_VERBOSE == 1)
12531     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getPendingTrackingCals()\n");
12532 #endif
12533 
12534     if (pendingCalMask == NULL)
12535     {
12536         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETPENDTRKCALS_NULL_PARAM,
12537                 getMykonosErrorMessage(MYKONOS_ERR_GETPENDTRKCALS_NULL_PARAM));
12538         return MYKONOS_ERR_GETPENDTRKCALS_NULL_PARAM;
12539     }
12540 
12541     CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_ARM_OPCODE_STATE_3, &readData[0]);
12542     CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_ARM_OPCODE_STATE_4, &readData[1]);
12543     CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_ARM_OPCODE_STATE_5, &readData[2]);
12544     CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_ARM_OPCODE_STATE_6, &readData[3]);
12545     *pendingCalMask = ((uint32_t)readData[3] << 24) | ((uint32_t)readData[2] << 16) | ((uint32_t)readData[1] << 8) | ((uint32_t)readData[0]);
12546 
12547     return MYKONOS_ERR_OK;
12548 }
12549 
12550 /**
12551  * \brief Returns the status of the TxLOL external tracking calibration
12552  *
12553  * The Tx LOL external tracking calibration is run during the radioOn state.
12554  * The function can be called to read back the status of the TxLOL external
12555  * calibration including metrics like error codes, percentage of data
12556  * collected for current cal, the performance of the cal and the number of
12557  * times the cal has run and updated the hardware.
12558  *
12559  * \pre Before the function is called, the device must be initialized, the ARM
12560  * loaded, and init cals run.  These functions can be called in radioOff or
12561  * radioOn state.
12562  *
12563  * \param device Pointer to the device settings structure
12564  * \param txChannel The channel (Tx1/Tx2) whose status is to be read back
12565  * \param txLolStatus Status of the TxLOL external calibration, as a structure
12566  * of type mykonosTxLolStatus_t is returned to this pointer address
12567  *
12568  * \retval MYKONOS_ERR_GETTXLOLSTATUS_NULLPARAM Function parameter mykonosTxLolStatus_t is a NULL pointer
12569  * \retval MYKONOS_ERR_GETTXLOLSTATUS_INV_CH Channel selection not valid
12570  * \retval MYKONOS_ERR_GETTXLOLSTATUS_ARMERRFLAG ARM command error
12571  * \retval MYKONOS_ERR_OK  Function completed successfully
12572  */
MYKONOS_getTxLolStatus(mykonosDevice_t * device,mykonosTxChannels_t txChannel,mykonosTxLolStatus_t * txLolStatus)12573 mykonosErr_t MYKONOS_getTxLolStatus(mykonosDevice_t *device, mykonosTxChannels_t txChannel, mykonosTxLolStatus_t *txLolStatus)
12574 {
12575     uint8_t extData[3] = {MYKONOS_ARM_OBJECTID_CAL_STATUS, MYKONOS_ARM_OBJECTID_TXLOL_TRACKING, 0};
12576     uint8_t cmdStatusByte = 0;
12577     uint32_t offset = 0;
12578     uint32_t timeoutMs = 0;
12579     uint8_t armReadBack[20] = {0};
12580     mykonosErr_t retVal = MYKONOS_ERR_OK;
12581 
12582 #if (MYKONOS_VERBOSE == 1)
12583     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getTxLolStatus()\n");
12584 #endif
12585 
12586     if (txLolStatus == NULL)
12587     {
12588         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTXLOLSTATUS_NULLPARAM,
12589                 getMykonosErrorMessage(MYKONOS_ERR_GETTXLOLSTATUS_NULLPARAM));
12590         return MYKONOS_ERR_GETTXLOLSTATUS_NULLPARAM;
12591     }
12592 
12593     switch (txChannel)
12594     {
12595         case TX1:
12596             extData[2] = 0;
12597             break;
12598         case TX2:
12599             extData[2] = 1;
12600             break;
12601         default:
12602         {
12603             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTXLOLSTATUS_INV_CH,
12604                     getMykonosErrorMessage(MYKONOS_ERR_GETTXLOLSTATUS_INV_CH));
12605             return MYKONOS_ERR_GETTXLOLSTATUS_INV_CH;
12606         }
12607     }
12608 
12609     retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &extData[0], sizeof(extData));
12610     if (retVal != MYKONOS_ERR_OK)
12611     {
12612         return retVal;
12613     }
12614 
12615     timeoutMs = 1000;
12616     retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte);
12617     if (retVal != MYKONOS_ERR_OK)
12618     {
12619         if (cmdStatusByte > 0)
12620         {
12621             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTXLOLSTATUS_ARMERRFLAG,
12622                     getMykonosErrorMessage(MYKONOS_ERR_GETTXLOLSTATUS_ARMERRFLAG));
12623             return MYKONOS_ERR_GETTXLOLSTATUS_ARMERRFLAG;
12624         }
12625 
12626         return retVal;
12627     }
12628 
12629     if (cmdStatusByte > 0)
12630     {
12631         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTXLOLSTATUS_ARMERRFLAG,
12632                 getMykonosErrorMessage(MYKONOS_ERR_GETTXLOLSTATUS_ARMERRFLAG));
12633         return MYKONOS_ERR_GETTXLOLSTATUS_ARMERRFLAG;
12634     }
12635 
12636     /* read status from ARM memory */
12637     offset = 0;
12638     retVal = MYKONOS_readArmMem(device, (MYKONOS_ADDR_ARM_START_DATA_ADDR + offset), &armReadBack[0], sizeof(armReadBack), 1);
12639     if (retVal != MYKONOS_ERR_OK)
12640     {
12641         return retVal;
12642     }
12643 
12644     /* Assign to data structure */
12645     txLolStatus->errorCode = (((uint32_t)armReadBack[3]) << 24) | (((uint32_t)armReadBack[2]) << 16) | (((uint32_t)armReadBack[1]) << 8) | ((uint32_t)armReadBack[0]);
12646     txLolStatus->percentComplete = (((uint32_t)armReadBack[7]) << 24) | (((uint32_t)armReadBack[6]) << 16) | (((uint32_t)armReadBack[5]) << 8)
12647             | ((uint32_t)armReadBack[4]);
12648     txLolStatus->performanceMetric = (((uint32_t)armReadBack[11]) << 24) | (((uint32_t)armReadBack[10]) << 16) | (((uint32_t)armReadBack[9]) << 8)
12649             | ((uint32_t)armReadBack[8]);
12650     txLolStatus->iterCount = (((uint32_t)armReadBack[15]) << 24) | (((uint32_t)armReadBack[14]) << 16) | (((uint32_t)armReadBack[13]) << 8) | ((uint32_t)armReadBack[12]);
12651     txLolStatus->updateCount = (((uint32_t)armReadBack[19]) << 24) | (((uint32_t)armReadBack[18]) << 16) | (((uint32_t)armReadBack[17]) << 8)
12652             | ((uint32_t)armReadBack[16]);
12653 
12654     return MYKONOS_ERR_OK;
12655 }
12656 
12657 /**
12658  * \brief Returns the status of the TxQEC tracking calibration
12659  *
12660  * The Tx QEC tracking calibration is run during the radioOn state.
12661  * The function can be called to read back the status of the TxQEC
12662  * calibration including metrics like error codes, percentage of data
12663  * collected for current cal, the performance of the cal and the number of
12664  * times the cal has run and updated the hardware.
12665  *
12666  * \pre Before the function is called, the device must be initialized, the ARM
12667  * loaded, and init cals run.  These functions can be called in radioOff or
12668  * radioOn state.
12669  *
12670  * \param device Pointer to the device settings structure
12671  * \param txChannel The channel (Tx1/Tx2) whose status is to be read back
12672  * \param txQecStatus Status of the TxQEC external calibration, as a structure
12673  * of type mykonosTxQecStatus_t is returned to this pointer address
12674  *
12675  * \retval MYKONOS_ERR_GETTXQECSTATUS_NULLPARAM Function parameter txQecStatus is a NULL pointer
12676  * \retval MYKONOS_ERR_GETTXQECSTATUS_INV_CH Channel selection not valid
12677  * \retval MYKONOS_ERR_GETTXQECSTATUS_ARMERRFLAG ARM command error
12678  * \retval MYKONOS_ERR_OK  Function completed successfully
12679  */
MYKONOS_getTxQecStatus(mykonosDevice_t * device,mykonosTxChannels_t txChannel,mykonosTxQecStatus_t * txQecStatus)12680 mykonosErr_t MYKONOS_getTxQecStatus(mykonosDevice_t *device, mykonosTxChannels_t txChannel, mykonosTxQecStatus_t *txQecStatus)
12681 {
12682     uint8_t extData[3] = {MYKONOS_ARM_OBJECTID_CAL_STATUS, MYKONOS_ARM_OBJECTID_TXQEC_TRACKING, 0};
12683     uint8_t cmdStatusByte = 0;
12684     uint32_t offset = 0;
12685     uint32_t timeoutMs = 0;
12686     uint8_t armReadBack[20] = {0};
12687     mykonosErr_t retVal = MYKONOS_ERR_OK;
12688 
12689 #if (MYKONOS_VERBOSE == 1)
12690     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getTxQecStatus()\n");
12691 #endif
12692 
12693     if (txQecStatus == NULL)
12694     {
12695         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTXQECSTATUS_NULLPARAM,
12696                 getMykonosErrorMessage(MYKONOS_ERR_GETTXQECSTATUS_NULLPARAM));
12697         return MYKONOS_ERR_GETTXQECSTATUS_NULLPARAM;
12698     }
12699 
12700     switch (txChannel)
12701     {
12702         case TX1:
12703             extData[2] = 0;
12704             break;
12705         case TX2:
12706             extData[2] = 1;
12707             break;
12708         default:
12709         {
12710             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTXQECSTATUS_INV_CH,
12711                     getMykonosErrorMessage(MYKONOS_ERR_GETTXQECSTATUS_INV_CH));
12712             return MYKONOS_ERR_GETTXQECSTATUS_INV_CH;
12713         }
12714     }
12715 
12716     retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &extData[0], sizeof(extData));
12717     if (retVal != MYKONOS_ERR_OK)
12718     {
12719         return retVal;
12720     }
12721 
12722     timeoutMs = 1000;
12723     retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte);
12724     if (retVal != MYKONOS_ERR_OK)
12725     {
12726         if (cmdStatusByte > 0)
12727         {
12728             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTXQECSTATUS_ARMERRFLAG,
12729                     getMykonosErrorMessage(MYKONOS_ERR_GETTXQECSTATUS_ARMERRFLAG));
12730             return MYKONOS_ERR_GETTXQECSTATUS_ARMERRFLAG;
12731         }
12732 
12733         return retVal;
12734     }
12735 
12736     if (cmdStatusByte > 0)
12737     {
12738         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETTXQECSTATUS_ARMERRFLAG,
12739                 getMykonosErrorMessage(MYKONOS_ERR_GETTXQECSTATUS_ARMERRFLAG));
12740         return MYKONOS_ERR_GETTXQECSTATUS_ARMERRFLAG;
12741     }
12742 
12743     /* read status from ARM memory */
12744     offset = 0;
12745     retVal = MYKONOS_readArmMem(device, (MYKONOS_ADDR_ARM_START_DATA_ADDR + offset), &armReadBack[0], sizeof(armReadBack), 1);
12746     if (retVal != MYKONOS_ERR_OK)
12747     {
12748         return retVal;
12749     }
12750 
12751     /* Assign to data structure */
12752     txQecStatus->errorCode = (((uint32_t)armReadBack[3]) << 24) | (((uint32_t)armReadBack[2]) << 16) | (((uint32_t)armReadBack[1]) << 8) | ((uint32_t)armReadBack[0]);
12753     txQecStatus->percentComplete = (((uint32_t)armReadBack[7]) << 24) | (((uint32_t)armReadBack[6]) << 16) | (((uint32_t)armReadBack[5]) << 8)
12754             | ((uint32_t)armReadBack[4]);
12755     txQecStatus->performanceMetric = (((uint32_t)armReadBack[11]) << 24) | (((uint32_t)armReadBack[10]) << 16) | (((uint32_t)armReadBack[9]) << 8)
12756             | ((uint32_t)armReadBack[8]);
12757     txQecStatus->iterCount = (((uint32_t)armReadBack[15]) << 24) | (((uint32_t)armReadBack[14]) << 16) | (((uint32_t)armReadBack[13]) << 8) | ((uint32_t)armReadBack[12]);
12758     txQecStatus->updateCount = (((uint32_t)armReadBack[19]) << 24) | (((uint32_t)armReadBack[18]) << 16) | (((uint32_t)armReadBack[17]) << 8)
12759             | ((uint32_t)armReadBack[16]);
12760 
12761     return MYKONOS_ERR_OK;
12762 }
12763 
12764 /**
12765  * \brief Returns the status of the RxQEC tracking calibration
12766  *
12767  * The Rx QEC tracking calibration is run during the radioOn state.
12768  * The function can be called to read back the status of the RxQEC external
12769  * calibration including metrics like error codes, percentage of data
12770  * collected for current cal, the performance of the cal and the number of
12771  * times the cal has run and updated the hardware.
12772  *
12773  * \pre Before the function is called, the device must be initialized, the ARM
12774  * loaded, and init cals run.  These functions can be called in radioOff or
12775  * radioOn state.
12776  *
12777  * \param device Pointer to the device settings structure
12778  * \param rxChannel The channel (Rx1/Rx2) whose status is to be read back
12779  * \param rxQecStatus Status of the RxQEC calibration, as a structure
12780  * of type mykonosRxQecStatus_t is returned to this pointer address
12781  *
12782  * \retval MYKONOS_ERR_GETRXQECSTATUS_NULLPARAM Function parameter rxQecStatus is a NULL pointer
12783  * \retval MYKONOS_ERR_GETRXQECSTATUS_INV_CH Channel selection not valid
12784  * \retval MYKONOS_ERR_GETRXQECSTATUS_ARMERRFLAG ARM command error
12785  * \retval MYKONOS_ERR_OK  Function completed successfully
12786  */
MYKONOS_getRxQecStatus(mykonosDevice_t * device,mykonosRxChannels_t rxChannel,mykonosRxQecStatus_t * rxQecStatus)12787 mykonosErr_t MYKONOS_getRxQecStatus(mykonosDevice_t *device, mykonosRxChannels_t rxChannel, mykonosRxQecStatus_t *rxQecStatus)
12788 {
12789     uint8_t extData[3] = {MYKONOS_ARM_OBJECTID_CAL_STATUS, MYKONOS_ARM_OBJECTID_RXQEC_TRACKING, 0};
12790     uint8_t cmdStatusByte = 0;
12791     uint32_t offset = 0;
12792     uint32_t timeoutMs = 0;
12793     uint8_t armReadBack[20] = {0};
12794     mykonosErr_t retVal = MYKONOS_ERR_OK;
12795 
12796 #if (MYKONOS_VERBOSE == 1)
12797     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getRxQecStatus()\n");
12798 #endif
12799 
12800     if (rxQecStatus == NULL)
12801     {
12802         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRXQECSTATUS_NULLPARAM,
12803                 getMykonosErrorMessage(MYKONOS_ERR_GETRXQECSTATUS_NULLPARAM));
12804         return MYKONOS_ERR_GETRXQECSTATUS_NULLPARAM;
12805     }
12806 
12807     switch (rxChannel)
12808     {
12809         case RX1:
12810             extData[2] = 0;
12811             break;
12812         case RX2:
12813             extData[2] = 1;
12814             break;
12815         default:
12816         {
12817             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRXQECSTATUS_INV_CH,
12818                     getMykonosErrorMessage(MYKONOS_ERR_GETRXQECSTATUS_INV_CH));
12819             return MYKONOS_ERR_GETRXQECSTATUS_INV_CH;
12820         }
12821     }
12822 
12823     retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &extData[0], sizeof(extData));
12824     if (retVal != MYKONOS_ERR_OK)
12825     {
12826         return retVal;
12827     }
12828 
12829     timeoutMs = 1000;
12830     retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte);
12831     if (retVal != MYKONOS_ERR_OK)
12832     {
12833         if (cmdStatusByte > 0)
12834         {
12835             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRXQECSTATUS_ARMERRFLAG,
12836                     getMykonosErrorMessage(MYKONOS_ERR_GETRXQECSTATUS_ARMERRFLAG));
12837             return MYKONOS_ERR_GETRXQECSTATUS_ARMERRFLAG;
12838         }
12839 
12840         return retVal;
12841     }
12842 
12843     if (cmdStatusByte > 0)
12844     {
12845         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRXQECSTATUS_ARMERRFLAG,
12846                 getMykonosErrorMessage(MYKONOS_ERR_GETRXQECSTATUS_ARMERRFLAG));
12847         return MYKONOS_ERR_GETRXQECSTATUS_ARMERRFLAG;
12848     }
12849 
12850     /* read status from ARM memory */
12851     offset = 0;
12852     retVal = MYKONOS_readArmMem(device, (MYKONOS_ADDR_ARM_START_DATA_ADDR + offset), &armReadBack[0], sizeof(armReadBack), 1);
12853     if (retVal != MYKONOS_ERR_OK)
12854     {
12855         return retVal;
12856     }
12857 
12858     /* Assign to data structure */
12859     rxQecStatus->errorCode = (((uint32_t)armReadBack[3]) << 24) | (((uint32_t)armReadBack[2]) << 16) | (((uint32_t)armReadBack[1]) << 8) | ((uint32_t)armReadBack[0]);
12860     rxQecStatus->percentComplete = (((uint32_t)armReadBack[7]) << 24) | (((uint32_t)armReadBack[6]) << 16) | (((uint32_t)armReadBack[5]) << 8)
12861             | ((uint32_t)armReadBack[4]);
12862     rxQecStatus->selfcheckIrrDb = (((uint32_t)armReadBack[11]) << 24) | (((uint32_t)armReadBack[10]) << 16) | (((uint32_t)armReadBack[9]) << 8)
12863             | ((uint32_t)armReadBack[8]);
12864     rxQecStatus->iterCount = (((uint32_t)armReadBack[15]) << 24) | (((uint32_t)armReadBack[14]) << 16) | (((uint32_t)armReadBack[13]) << 8) | ((uint32_t)armReadBack[12]);
12865     rxQecStatus->updateCount = (((uint32_t)armReadBack[19]) << 24) | (((uint32_t)armReadBack[18]) << 16) | (((uint32_t)armReadBack[17]) << 8)
12866             | ((uint32_t)armReadBack[16]);
12867 
12868     return MYKONOS_ERR_OK;
12869 }
12870 
12871 /**
12872  * \brief Returns the status of the ORxQEC tracking calibration
12873  *
12874  * The ORx QEC tracking calibration is run during the radioOn state.
12875  * The function can be called to read back the status of the ORxQEC external
12876  * calibration including metrics like error codes, percentage of data
12877  * collected for current cal, the performance of the cal and the number of
12878  * times the cal has run and updated the hardware.
12879  *
12880  * \pre Before the function is called, the device must be initialized, the ARM
12881  * loaded, and init cals run.  These functions can be called in radioOff or
12882  * radioOn state.
12883  *
12884  * \param device Pointer to the device settings structure
12885  * \param orxChannel The channel whose status is to be read back
12886  * \param orxQecStatus Status of the ORxQEC external calibration, as a structure
12887  * of type mykonosOrxQecStatus_t is returned to this pointer address
12888  *
12889  * \retval MYKONOS_ERR_GETORXQECSTATUS_NULLPARAM Function parameter orxQecStatus is a NULL pointer
12890  * \retval MYKONOS_ERR_GETORXQECSTATUS_INV_CH Channel selection not valid
12891  * \retval MYKONOS_ERR_GETORXQECSTATUS_ARMERRFLAG ARM command error
12892  * \retval MYKONOS_ERR_OK  Function completed successfully
12893  */
MYKONOS_getOrxQecStatus(mykonosDevice_t * device,mykonosObsRxChannels_t orxChannel,mykonosOrxQecStatus_t * orxQecStatus)12894 mykonosErr_t MYKONOS_getOrxQecStatus(mykonosDevice_t *device, mykonosObsRxChannels_t orxChannel, mykonosOrxQecStatus_t *orxQecStatus)
12895 {
12896     uint8_t extData[3] = {MYKONOS_ARM_OBJECTID_CAL_STATUS, MYKONOS_ARM_OBJECTID_ORXQEC_TRACKING, 0};
12897     uint8_t cmdStatusByte = 0;
12898     uint32_t offset = 0;
12899     uint32_t timeoutMs = 0;
12900     uint8_t armReadBack[20] = {0};
12901     mykonosErr_t retVal = MYKONOS_ERR_OK;
12902 
12903 #if (MYKONOS_VERBOSE == 1)
12904     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getOrxQecStatus()\n");
12905 #endif
12906 
12907     if (orxQecStatus == NULL)
12908     {
12909         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETORXQECSTATUS_NULLPARAM,
12910                 getMykonosErrorMessage(MYKONOS_ERR_GETORXQECSTATUS_NULLPARAM));
12911         return MYKONOS_ERR_GETORXQECSTATUS_NULLPARAM;
12912     }
12913 
12914     switch (orxChannel)
12915     {
12916         case OBS_RX1_TXLO:
12917         case OBS_RX1_SNIFFERLO:
12918             extData[2] = 0;
12919             break;
12920         case OBS_RX2_TXLO:
12921         case OBS_RX2_SNIFFERLO:
12922             extData[2] = 1;
12923             break;
12924         default:
12925         {
12926             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETORXQECSTATUS_INV_CH,
12927                     getMykonosErrorMessage(MYKONOS_ERR_GETORXQECSTATUS_INV_CH));
12928             return MYKONOS_ERR_GETORXQECSTATUS_INV_CH;
12929         }
12930     }
12931 
12932     retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &extData[0], sizeof(extData));
12933     if (retVal != MYKONOS_ERR_OK)
12934     {
12935         return retVal;
12936     }
12937 
12938     timeoutMs = 1000;
12939     retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte);
12940     if (retVal != MYKONOS_ERR_OK)
12941     {
12942         if (cmdStatusByte > 0)
12943         {
12944             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETORXQECSTATUS_ARMERRFLAG,
12945                     getMykonosErrorMessage(MYKONOS_ERR_GETORXQECSTATUS_ARMERRFLAG));
12946             return MYKONOS_ERR_GETORXQECSTATUS_ARMERRFLAG;
12947         }
12948 
12949         return retVal;
12950     }
12951 
12952     if (cmdStatusByte > 0)
12953     {
12954         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETORXQECSTATUS_ARMERRFLAG,
12955                 getMykonosErrorMessage(MYKONOS_ERR_GETORXQECSTATUS_ARMERRFLAG));
12956         return MYKONOS_ERR_GETORXQECSTATUS_ARMERRFLAG;
12957     }
12958 
12959     /* read status from ARM memory */
12960     offset = 0;
12961     retVal = MYKONOS_readArmMem(device, (MYKONOS_ADDR_ARM_START_DATA_ADDR + offset), &armReadBack[0], sizeof(armReadBack), 1);
12962     if (retVal != MYKONOS_ERR_OK)
12963     {
12964         return retVal;
12965     }
12966 
12967     /* Assign to data structure */
12968     orxQecStatus->errorCode = (((uint32_t)armReadBack[3]) << 24) | (((uint32_t)armReadBack[2]) << 16) | (((uint32_t)armReadBack[1]) << 8) | ((uint32_t)armReadBack[0]);
12969     orxQecStatus->percentComplete = (((uint32_t)armReadBack[7]) << 24) | (((uint32_t)armReadBack[6]) << 16) | (((uint32_t)armReadBack[5]) << 8)
12970             | ((uint32_t)armReadBack[4]);
12971     orxQecStatus->selfcheckIrrDb = (((uint32_t)armReadBack[11]) << 24) | (((uint32_t)armReadBack[10]) << 16) | (((uint32_t)armReadBack[9]) << 8)
12972             | ((uint32_t)armReadBack[8]);
12973     orxQecStatus->iterCount = (((uint32_t)armReadBack[15]) << 24) | (((uint32_t)armReadBack[14]) << 16) | (((uint32_t)armReadBack[13]) << 8)
12974             | ((uint32_t)armReadBack[12]);
12975     orxQecStatus->updateCount = (((uint32_t)armReadBack[19]) << 24) | (((uint32_t)armReadBack[18]) << 16) | (((uint32_t)armReadBack[17]) << 8)
12976             | ((uint32_t)armReadBack[16]);
12977 
12978     return MYKONOS_ERR_OK;
12979 }
12980 
12981 /**
12982  * \brief Selects the Sniffer RF input to use for the observation receiver when in ObsRx pin mode and ORX_MODE = SNIFFER(4)
12983  *
12984  * This function is only valid when using the ObsRx Pin mode.  In pin mode, 3 GPIO pins select an Observation Rx source.
12985  * See mykonosObsRxChannels_t enum values less than 7.  When the ORX_MODE GPIO pins are set to 4 for Sniffer, Sniffer inputs
12986  * A, B, and C can be chosen by calling this function.  This function can be called any time after the ARM is loaded and running.
12987  * It can be called in radioOn or radioOff state.
12988  *
12989  * <B>Dependencies</B>
12990  * - device->spiSettings->chipSelectIndex
12991  *
12992  * \param device Pointer to the device settings structure
12993  * \param snifferChannel Desired channel to set.  This channel will be enabled when ORX_MODE = SNIFFER.
12994  *
12995  * \retval MYKONOS_ERR_OK Function completed successfully
12996  * \retval MYKONOS_ERR_SET_ARMGPIO_PINS_ARMERROR ARM returned an error
12997  */
MYKONOS_setSnifferChannel(mykonosDevice_t * device,mykonosSnifferChannel_t snifferChannel)12998 mykonosErr_t MYKONOS_setSnifferChannel(mykonosDevice_t *device, mykonosSnifferChannel_t snifferChannel)
12999 {
13000     uint8_t armData[2] = {0};
13001     uint32_t timeoutMs = 0;
13002     uint8_t cmdStatusByte = 0;
13003     mykonosErr_t retVal = MYKONOS_ERR_OK;
13004 
13005     armData[0] = 0x6A; /* SET SRX_SOURCE ARM object ID */
13006     armData[1] = (uint8_t)snifferChannel;
13007 
13008     retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_SET_OPCODE, &armData[0], sizeof(armData));
13009     if (retVal != MYKONOS_ERR_OK)
13010     {
13011         return retVal;
13012     }
13013 
13014     timeoutMs = 1000;
13015     retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_SET_OPCODE, timeoutMs, &cmdStatusByte);
13016     if (retVal != MYKONOS_ERR_OK)
13017     {
13018         if (cmdStatusByte > 0)
13019         {
13020             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_ARMGPIO_PINS_ARMERROR,
13021                     getGpioMykonosErrorMessage(MYKONOS_ERR_SET_ARMGPIO_PINS_ARMERROR));
13022             retVal = (mykonosErr_t)MYKONOS_ERR_SET_ARMGPIO_PINS_ARMERROR;
13023         }
13024 
13025         return retVal;
13026     }
13027 
13028     if (cmdStatusByte > 0)
13029     {
13030         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_ARMGPIO_PINS_ARMERROR,
13031                 getGpioMykonosErrorMessage(MYKONOS_ERR_SET_ARMGPIO_PINS_ARMERROR));
13032         return (mykonosErr_t)MYKONOS_ERR_SET_ARMGPIO_PINS_ARMERROR;
13033     }
13034 
13035     return MYKONOS_ERR_OK;
13036 }
13037 
13038 /**
13039  * \brief Resets the ARM processor and performs initialization
13040  *
13041  * Sets ARM Run = 0, Disables parity checks, sets ARM and SPI reg clock selects,
13042  * resets ARM, and enables ARM SPI register access
13043  *
13044  * <B>Dependencies</B>
13045  * - device->spiSettings->chipSelectIndex
13046  * - device->rx->rxProfile->iqRate_kHz
13047  * - device->deviceClock_kHz
13048  * - device->rx->rxProfile->rfBandwidth_Hz
13049  * - device->tx->txProfile->rfBandwidth_Hz
13050  * - device->rx->rxProfile->rxFirDecimation
13051  * - device->rx->rxProfile->rhb1Decimation
13052  * - device->spiSettings
13053  *
13054  * \param device Pointer to the device settings structure
13055  *
13056  * \retval MYKONOS_ERR_OK Function completed successfully
13057  * \retval MYKONOS_ERR_INITARM_INV_VCODIV
13058  * \retval MYKONOS_ERR_INITARM_INV_REGCLK Could not calculate a valid ARM Register clock divider
13059  * \retval MYKONOS_ERR_INITARM_INV_ARMCLK_PARAM Could not calculate a valid ARM clock divider
13060  */
MYKONOS_initArm(mykonosDevice_t * device)13061 mykonosErr_t MYKONOS_initArm(mykonosDevice_t *device)
13062 {
13063     uint8_t regClkSel = 0;
13064     uint8_t armClkSel = 0;
13065     uint32_t hsClkRateDiv4or5_Khz = 0;
13066     uint32_t hb1Clk = 0;
13067     uint32_t vcoDivTimes10 = 1;
13068     uint8_t adcDiv = 0;
13069     mykonosErr_t retVal = MYKONOS_ERR_OK;
13070 
13071 #if (MYKONOS_VERBOSE == 1)
13072     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_initArm()\n");
13073 #endif
13074 
13075     /* Finish init - this is part of init that must run after Multi Chip Sync */
13076     retVal = MYKONOS_initSubRegisterTables(device);
13077     if (retVal != MYKONOS_ERR_OK)
13078     {
13079         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, retVal, getMykonosErrorMessage(retVal));
13080         return retVal;
13081     }
13082 
13083     switch (device->clocks->clkPllVcoDiv)
13084     {
13085         case VCODIV_1:
13086             vcoDivTimes10 = 10;
13087             break;
13088         case VCODIV_1p5:
13089             vcoDivTimes10 = 15;
13090             break;
13091         case VCODIV_2:
13092             vcoDivTimes10 = 20;
13093             break;
13094         case VCODIV_3:
13095             vcoDivTimes10 = 30;
13096             break;
13097         default:
13098         {
13099             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INITARM_INV_VCODIV,
13100                     getMykonosErrorMessage(MYKONOS_ERR_INITARM_INV_VCODIV));
13101             return MYKONOS_ERR_INITARM_INV_VCODIV;
13102         }
13103     }
13104 
13105     hsClkRateDiv4or5_Khz = device->clocks->clkPllVcoFreq_kHz * 10 / vcoDivTimes10 / 20;
13106 
13107     /* If ADC divider is set, divide hsClkRateDiv4or5_kHz by 2 (ADC divider) */
13108     CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_CLOCK_CONTROL_1, &adcDiv, 0x01, 0);
13109     hb1Clk = (adcDiv == 1) ? (hsClkRateDiv4or5_Khz >> 1) : (hsClkRateDiv4or5_Khz);
13110 
13111     /* the ARM clock should not exceed 250 Mhz */
13112     if (hb1Clk <= 250000)
13113     {
13114         armClkSel = 0x00;
13115     }
13116     else if (hb1Clk > 250000 && hb1Clk <= 500000)
13117     {
13118         armClkSel = 0x02;
13119     }
13120     else if (hb1Clk > 500000 && hb1Clk <= 1000000)
13121     {
13122         armClkSel = 0x04;
13123     }
13124     else
13125     {
13126         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INITARM_INV_ARMCLK_PARAM,
13127                 getMykonosErrorMessage(MYKONOS_ERR_INITARM_INV_ARMCLK_PARAM));
13128         return MYKONOS_ERR_INITARM_INV_ARMCLK_PARAM;
13129     }
13130 
13131     /* the SPI read reg clock must be equal or less than 100MHz and the SPI write reg clock must be less equal or less than 200 Mhz*/
13132     if (hb1Clk <= 100000)
13133     {
13134         regClkSel = 0x00;
13135     }
13136     else if (hb1Clk > 100000 && hb1Clk <= 200000)
13137     {
13138         regClkSel = 0x04;
13139     }
13140     else if (hb1Clk > 200000 && hb1Clk <= 400000)
13141     {
13142         regClkSel = 0x09;
13143     }
13144     else if (hb1Clk > 400000 && hb1Clk <= 800000)
13145     {
13146         regClkSel = 0x0E;
13147     }
13148     else
13149     {
13150         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_INITARM_INV_REGCLK, getMykonosErrorMessage(MYKONOS_ERR_INITARM_INV_REGCLK));
13151         return MYKONOS_ERR_INITARM_INV_REGCLK;
13152     }
13153 
13154     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_CTL_1, 0x8C); /* arm_debug_enable[7]=1, mem_hresp_mask[3]=1, auto_incr[2]=1, arm_m3_run[0]=0 */
13155     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_CLK_CTL, armClkSel |= 0x41); /* setting the ARM clock rate, resetting the PC, and enabling the ARM clock */
13156     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_CLK_CTL, armClkSel &= ~0x40); /* maintaining the ARM clock rate, disabling the PC reset, and maintaining ARM clock enable */
13157     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_BRIDGE_CLK_CTL, regClkSel); /* setting the SPI read and write clock rates */
13158     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_AHB_SPI_BRIDGE, 0x13); /* blockout_window_size[4:1] = 9, ahb_spi_bridge_enable[0] = 1 */
13159 
13160     retVal = MYKONOS_writeArmProfile(device);
13161     if (retVal != MYKONOS_ERR_OK)
13162     {
13163         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, retVal, getMykonosErrorMessage(retVal));
13164         return retVal;
13165     }
13166 
13167     retVal = MYKONOS_loadAdcProfiles(device);
13168     if (retVal != MYKONOS_ERR_OK)
13169     {
13170         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, retVal, getMykonosErrorMessage(retVal));
13171         return retVal;
13172     }
13173 
13174     return MYKONOS_ERR_OK;
13175 }
13176 
13177 /**
13178  * \brief Loads binary byte array into ARM program memory
13179  *
13180  * This function assumes the ARM auto increment bit is set in 0x0D00[2]. Valid memory
13181  * addresses are: Program Memory (0x01000000 - 0x01017FFF)
13182  *
13183  * <B>Dependencies</B>
13184  * - device->spiSettings->chipSelectIndex
13185  * - device->spiSettings
13186  *
13187  * \param device is structure pointer to the Mykonos data structure containing settings
13188  * \param binary is a byte array containing ARM program memory data bytes (directly from .bin file)
13189  * \param count is the number of bytes in the byte array
13190  *
13191  * \retval MYKONOS_ERR_OK Function completed successfully
13192  * \retval MYKONOS_ERR_LOADBIN_NULL_PARAM Function parameter binary has a NULL pointer
13193  * \retval MYKONOS_ERR_LOADBIN_INVALID_BYTECOUNT Count parameter must be 98304 bytes
13194  */
MYKONOS_loadArmFromBinary(mykonosDevice_t * device,uint8_t * binary,uint32_t count)13195 mykonosErr_t MYKONOS_loadArmFromBinary(mykonosDevice_t *device, uint8_t *binary, uint32_t count)
13196 {
13197     mykonosErr_t retVal = MYKONOS_ERR_OK;
13198     uint8_t stackPtr[4] = {0};
13199     uint8_t bootAddr[4] = {0};
13200 
13201 #if (MYKONOS_VERBOSE == 1)
13202     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_loadArmFromBinary()\n");
13203 #endif
13204 
13205     if (binary == NULL)
13206     {
13207         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOADBIN_NULL_PARAM, getMykonosErrorMessage(MYKONOS_ERR_LOADBIN_NULL_PARAM));
13208         return MYKONOS_ERR_LOADBIN_NULL_PARAM;
13209     }
13210 
13211     if (count != 98304)
13212     {
13213         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOADBIN_INVALID_BYTECOUNT,
13214                 getMykonosErrorMessage(MYKONOS_ERR_LOADBIN_INVALID_BYTECOUNT));
13215         return MYKONOS_ERR_LOADBIN_INVALID_BYTECOUNT;
13216     }
13217     else
13218     {
13219         /* extraction of stack pointer and boot address from top of array */
13220         stackPtr[0] = binary[0];
13221         stackPtr[1] = binary[1];
13222         stackPtr[2] = binary[2];
13223         stackPtr[3] = binary[3];
13224 
13225         bootAddr[0] = binary[4];
13226         bootAddr[1] = binary[5];
13227         bootAddr[2] = binary[6];
13228         bootAddr[3] = binary[7];
13229 
13230         /* writing binary data to ARM memory */
13231         retVal = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_PROG_ADDR, &binary[0], count);
13232     }
13233 
13234     if (retVal != MYKONOS_ERR_OK)
13235     {
13236         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, retVal, getMykonosErrorMessage(retVal));
13237         return retVal;
13238     }
13239     else
13240     {
13241         /* writing the stack pointer address */
13242         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_STACK_PTR_BYTE_0, stackPtr[0]); /* stack pointer [7:0]     */
13243         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_STACK_PTR_BYTE_1, stackPtr[1]); /* stack pointer [15:8]  */
13244         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_STACK_PTR_BYTE_2, stackPtr[2]); /* stack pointer [23:16] */
13245         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_STACK_PTR_BYTE_3, stackPtr[3]); /* stack pointer [31:24] */
13246 
13247         /* writing the boot address */
13248         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_BOOT_ADDR_BYTE_0, bootAddr[0]); /* boot address [7:0]     */
13249         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_BOOT_ADDR_BYTE_1, bootAddr[1]); /* boot address [15:8]     */
13250         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_BOOT_ADDR_BYTE_2, bootAddr[2]); /* boot address [23:16]     */
13251         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_BOOT_ADDR_BYTE_3, bootAddr[3]); /* boot address [31:24]     */
13252 
13253         /* setting the ARM run bit */
13254         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_CTL_1, 0x8D); /* arm_debug_enable[7]=1, mem_hresp_mask[3]=1, auto_incr[2]=1, arm_m3_run[0]=1 */
13255     }
13256 
13257     /* verifying ARM checksum */
13258     if ((retVal = MYKONOS_verifyArmChecksum(device)) != MYKONOS_ERR_OK)
13259     {
13260         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, retVal, getMykonosErrorMessage(retVal));
13261         return retVal;
13262     }
13263 
13264     /* verifying ARM state is in MYKONOS_ARM_READY state, otherwise return error */
13265     if ((retVal = MYKONOS_checkArmState(device, MYK_ARM_READY)) != MYKONOS_ERR_OK)
13266     {
13267         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, retVal, getMykonosErrorMessage(retVal));
13268         return retVal;
13269     }
13270 
13271     /* Setup ARM GPIO pins and program ARMs radio control structure */
13272     if ((retVal = (mykonosErr_t)MYKONOS_setArmGpioPins(device)) != MYKONOS_ERR_OK)
13273     {
13274         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, retVal, getMykonosErrorMessage(retVal));
13275         return retVal;
13276     }
13277 
13278     if ((retVal = MYKONOS_setRadioControlPinMode(device)) != MYKONOS_ERR_OK)
13279     {
13280         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, retVal, getMykonosErrorMessage(retVal));
13281         return retVal;
13282     }
13283 
13284     /* Set the default ObsRx Path source for when the device moves to RadioOn */
13285     if ((retVal = MYKONOS_setDefaultObsRxPath(device, device->obsRx->defaultObsRxChannel)) != MYKONOS_ERR_OK)
13286     {
13287         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, retVal, getMykonosErrorMessage(retVal));
13288         return retVal;
13289     }
13290 
13291     return MYKONOS_ERR_OK;
13292 }
13293 
13294 /**
13295  * \brief Loads binary byte array into ARM program memory. This API function allows user to load the ARM concurrently.
13296  * This is specially to reduce the system initialization time.
13297  *
13298  * \pre MYKONOS_initArm() function must be called before calling this API.
13299  *
13300  * \post after calling this function the user must verify:
13301  * Arm Checksum using MYKONOS_verifyArmChecksum(mykonosDevice_t *device)
13302  * verify ARM state is in MYKONOS_ARM_READY state using MYKONOS_checkArmState(device, MYK_ARM_READY);
13303  *
13304  * <B>Dependencies</B>
13305  * - device->spiSettings->chipSelectIndex
13306  * - device->spiSettings
13307  *
13308  * \param device is structure pointer to the Mykonos data structure containing settings
13309  * \param binary is a byte array containing ARM program memory data bytes (directly from .bin file)
13310  * \param count is the number of bytes in the byte array
13311  *
13312  * \retval MYKONOS_ERR_OK Function completed successfully
13313  * \retval MYKONOS_ERR_LOADARMCON_NULL_PARAM Function parameter binary has a NULL pointer
13314  * \retval MYKONOS_ERR_LOADARMCON_INVALID_BYTECOUNT Count parameter must be 98304 bytes
13315  * \retval MYKONOS_ERR_ARM_INV_ADDR_PARM Invalid memory address
13316  */
MYKONOS_loadArmConcurrent(mykonosDevice_t * device,uint8_t * binary,uint32_t count)13317 mykonosErr_t MYKONOS_loadArmConcurrent(mykonosDevice_t *device, uint8_t *binary, uint32_t count)
13318 {
13319     uint8_t stackPtr[4] = {0};
13320     uint8_t bootAddr[4] = {0};
13321     uint32_t i;
13322     uint32_t address = MYKONOS_ADDR_ARM_START_PROG_ADDR;
13323 
13324 #if MYK_ENABLE_SPIWRITEARRAY == 1
13325     uint32_t addrIndex = 0;
13326     uint32_t dataIndex = 0;
13327     uint32_t spiBufferSize = MYK_SPIWRITEARRAY_BUFFERSIZE;
13328     uint16_t addrArray[MYK_SPIWRITEARRAY_BUFFERSIZE] = {0};
13329 #endif
13330 
13331 #if (MYKONOS_VERBOSE == 1)
13332     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_loadArmConcurrent()\n");
13333 #endif
13334 
13335     if (binary == NULL)
13336     {
13337         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOADARMCON_NULL_PARAM, getMykonosErrorMessage(MYKONOS_ERR_LOADARMCON_NULL_PARAM));
13338         return MYKONOS_ERR_LOADARMCON_NULL_PARAM;
13339     }
13340 
13341     if (count != 98304)
13342     {
13343         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOADARMCON_INVALID_BYTECOUNT,
13344                 getMykonosErrorMessage(MYKONOS_ERR_LOADARMCON_INVALID_BYTECOUNT));
13345         return MYKONOS_ERR_LOADARMCON_INVALID_BYTECOUNT;
13346     }
13347     else
13348     {
13349         /* extraction of stack pointer and boot address from top of array */
13350         stackPtr[0] = binary[0];
13351         stackPtr[1] = binary[1];
13352         stackPtr[2] = binary[2];
13353         stackPtr[3] = binary[3];
13354 
13355         bootAddr[0] = binary[4];
13356         bootAddr[1] = binary[5];
13357         bootAddr[2] = binary[6];
13358         bootAddr[3] = binary[7];
13359 
13360         /* set auto increment address bit */
13361         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_CTL_1, 0x8C);
13362 
13363         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_ADDR_BYTE_0, (uint8_t)((address) >> 2));
13364         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_ADDR_BYTE_1, (uint8_t)(address >> 10));
13365 
13366         /* start write at correct byte offset */
13367         /* write data is located at SPI address 0xD04=data[7:0], 0xD05=data[15:8], 0xD06=data[23:16], 0xD07=data[31:24] */
13368         /* with address auto increment set, after x407 is written, the address will automatically increment */
13369 
13370 #if (MYK_ENABLE_SPIWRITEARRAY == 0)
13371 
13372         for (i = 0; i < byteCount; i++)
13373         {
13374             CMB_SPIWriteByte(device->spiSettings, (MYKONOS_ADDR_ARM_DATA_BYTE_0 | (((address & 0x3) + i) % 4)), data[i]);
13375         }
13376 
13377 #elif (MYK_ENABLE_SPIWRITEARRAY == 1)
13378 
13379         addrIndex = 0;
13380         dataIndex = 0;
13381         for (i = 0; i < count; i++)
13382         {
13383             addrArray[addrIndex++] = (MYKONOS_ADDR_ARM_DATA_BYTE_0 | (((address & 0x3) + i) % 4));
13384 
13385             if (addrIndex == spiBufferSize)
13386             {
13387                 CMB_SPIWriteBytes(device->spiSettings, &addrArray[0], &binary[dataIndex], addrIndex);
13388                 dataIndex = dataIndex + addrIndex;
13389                 addrIndex = 0;
13390             }
13391         }
13392 
13393         if (addrIndex > 0)
13394         {
13395             CMB_SPIWriteBytes(device->spiSettings, &addrArray[0], &binary[dataIndex], addrIndex);
13396         }
13397 
13398 #endif
13399 
13400         /* writing the stack pointer address */
13401         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_STACK_PTR_BYTE_0, stackPtr[0]); /* stack pointer [7:0]       */
13402         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_STACK_PTR_BYTE_1, stackPtr[1]); /* stack pointer [15:8]      */
13403         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_STACK_PTR_BYTE_2, stackPtr[2]); /* stack pointer [23:16]     */
13404         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_STACK_PTR_BYTE_3, stackPtr[3]); /* stack pointer [31:24]     */
13405 
13406         /* writing the boot address */
13407         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_BOOT_ADDR_BYTE_0, bootAddr[0]); /* boot address [7:0]        */
13408         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_BOOT_ADDR_BYTE_1, bootAddr[1]); /* boot address [15:8]       */
13409         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_BOOT_ADDR_BYTE_2, bootAddr[2]); /* boot address [23:16]      */
13410         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_BOOT_ADDR_BYTE_3, bootAddr[3]); /* boot address [31:24]      */
13411 
13412         /* setting the ARM run bit */
13413         CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_CTL_1, 0x8D);
13414 
13415     }
13416 
13417     return MYKONOS_ERR_OK;
13418 }
13419 
13420 /**
13421  * \brief Verifies the ARM checksum value
13422  *
13423  * The checksum which is written into the .hex file is verified with the calculated checksum
13424  * in the Mykonos ARM after the hex file has been loaded
13425  *
13426  * <B>Dependencies</B>
13427  * - device->spiSettings->chipSelectIndex
13428  *
13429  * \param device is structure pointer to the Mykonos data structure containing settings
13430  *
13431  * \retval MYKONOS_ERR_OK Function completed successfully
13432  */
MYKONOS_verifyArmChecksum(mykonosDevice_t * device)13433 mykonosErr_t MYKONOS_verifyArmChecksum(mykonosDevice_t *device)
13434 {
13435     uint32_t buildTimeChecksum = 0x00000000;
13436     uint32_t calculatedChecksum = 0x00000000;
13437     uint8_t buildData[4] = {0};
13438     uint8_t calcData[4] = {0};
13439     mykonosErr_t retVal = MYKONOS_ERR_OK;
13440 
13441     const uint8_t CHECKSUM_BYTES = 0x4;
13442 
13443 #if (MYKONOS_VERBOSE == 1)
13444     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_verifyArmChecksum()\n");
13445 #endif
13446 
13447     /* disabling auto increment and reading four (4) bytes at ARM checksum memory location */
13448     retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_BUILD_CHKSUM_ADDR, buildData, CHECKSUM_BYTES, 0);
13449     if (retVal != MYKONOS_ERR_OK)
13450     {
13451         return retVal;
13452     }
13453     /* determining build time checksum */
13454     buildTimeChecksum = (((uint32_t)buildData[3] << 24) | ((uint32_t)buildData[2] << 16) | ((uint32_t)buildData[1] << 8) | (uint32_t)buildData[0]);
13455 
13456     /* using 200 msec timeout for exit out of while loop [maximum checksum calculation time = 5 ms] */
13457     CMB_setTimeout_ms(device->spiSettings, 200);
13458 
13459     /* determining calculated checksum */
13460     do
13461     {
13462         if ((retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_CALC_CHKSUM_ADDR, calcData, CHECKSUM_BYTES, 0)) != MYKONOS_ERR_OK)
13463         {
13464             return retVal;
13465         }
13466         calculatedChecksum = (((uint32_t)calcData[3] << 24) | ((uint32_t)calcData[2] << 16) | ((uint32_t)calcData[1] << 8) | (uint32_t)calcData[0]);
13467     } while ((!calculatedChecksum) && (!CMB_hasTimeoutExpired(device->spiSettings)));
13468 
13469     /* performing consistency check */
13470     if (buildTimeChecksum == calculatedChecksum)
13471     {
13472         return MYKONOS_ERR_OK;
13473     }
13474     else
13475     {
13476         return MYKONOS_ERR_ARM_INVALID_BUILDCHKSUM;
13477     }
13478 }
13479 
13480 /**
13481  * \brief Verifies the ARM status once it is start running
13482  *
13483  * Wait for ARM to go into radio state, if takes longer there is and ARM error
13484  * get error in Application layer calling MYKONOS_getRadioState()
13485  *
13486  * <B>Dependencies</B>
13487  * - device->spiSettings->chipSelectIndex
13488  *
13489  * \param device is structure pointer to the Mykonos data structure containing settings
13490  * \param armStateCheck if the ARM is not in this state it will return an error,
13491  *
13492  * \retval MYKONOS_ERR_ARMSTATE_EXCEPTION ARM system problem has been detected.
13493  * \retval MYKONOS_ERR_ARMSTATE_CAL_ERROR ARM has detected an error in the tracking calibrations.
13494  * \retval MYKONOS_ERR_ARMSTATE_EXCEPTION ARM has detected an illegal profile.
13495  * \retval MYKONOS_ERR_WAITARMCSTATE_TIMEOUT Timeout occurred in check ARM state.
13496  * \retval MYKONOS_ERR_OK Function completed successfully
13497  */
MYKONOS_checkArmState(mykonosDevice_t * device,mykonosArmState_t armStateCheck)13498 mykonosErr_t MYKONOS_checkArmState(mykonosDevice_t *device, mykonosArmState_t armStateCheck)
13499 {
13500     mykonosErr_t retVal = MYKONOS_ERR_OK;
13501     uint32_t armStatus = 0x00;
13502     uint32_t armStatusMapped = 0x00;
13503     uint32_t timeoutMs = 500; /* 500ms timeOut */
13504     uint8_t endCheck = 0x00;
13505 
13506 #if (MYKONOS_VERBOSE == 1)
13507     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_checkArmState()\n");
13508 #endif
13509 
13510     CMB_setTimeout_ms(device->spiSettings, timeoutMs);
13511 
13512     do
13513     {
13514         if ((retVal = MYKONOS_getRadioState(device, &armStatus)) != MYKONOS_ERR_OK)
13515         {
13516             return retVal;
13517         }
13518 
13519         /* Mapping of the armStatus bit to the enum value. */
13520         switch(armStatus)
13521         {
13522             case 0:
13523                 armStatusMapped = (uint32_t)MYK_ARM_POWERUP;
13524                 break;
13525             case 1:
13526                 armStatusMapped = (uint32_t)MYK_ARM_READY;
13527                 break;
13528             case 2:
13529                 armStatusMapped = (uint32_t)MYK_ARM_IDLE;
13530                 break;
13531             case 3:
13532                 armStatusMapped = (uint32_t)MYK_ARM_RADIO_ON;
13533                 break;
13534             case 4:
13535                 armStatusMapped = (uint32_t)MYK_ARM_PROFILE_ERROR;
13536                 break;
13537             default:
13538                 armStatusMapped = armStatus;
13539                 break;
13540         }
13541 
13542         if (armStateCheck && armStatusMapped)
13543         {
13544             retVal = MYKONOS_ERR_OK;
13545             break;
13546         }
13547 
13548         if (CMB_hasTimeoutExpired(device->spiSettings))
13549         {
13550             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_WAITARMCSTATE_TIMEOUT,
13551                     getMykonosErrorMessage(MYKONOS_ERR_WAITARMCSTATE_TIMEOUT));
13552             retVal = MYKONOS_ERR_WAITARMCSTATE_TIMEOUT;
13553             break;
13554         }
13555 
13556         switch (armStatusMapped)
13557         {
13558             /* this cases are not ARM errors */
13559             case MYK_ARM_POWERUP:
13560             case MYK_ARM_READY:
13561             case MYK_ARM_IDLE:
13562             case MYK_ARM_RADIO_ON:
13563                 break;
13564 
13565             case MYK_ARM_PROFILE_ERROR:
13566                 /* return error directly */
13567                 retVal = MYKONOS_ERR_ARMSTATE_PROFILE_ERROR;
13568                 endCheck = 1;
13569                 break;
13570 
13571             case MYK_ARM_CAL_ERROR:
13572                 /* return error directly */
13573                 retVal = MYKONOS_ERR_ARMSTATE_CAL_ERROR;
13574                 endCheck = 1;
13575                 break;
13576 
13577             case MYK_ARM_EXCEPTION:
13578                 /* return error directly */
13579                 retVal = MYKONOS_ERR_ARMSTATE_EXCEPTION;
13580                 endCheck = 1;
13581                 break;
13582 
13583             case (uint32_t)MYK_ARM_EXCEPTION | (uint32_t)MYK_ARM_PROFILE_ERROR:
13584                 /* return error directly */
13585                 retVal = MYKONOS_ERR_ARMSTATE_EXCEPTION;
13586                 endCheck = 1;
13587                 break;
13588 
13589             default:
13590                 endCheck = 0;
13591                 break;
13592         }
13593 
13594     } while (!endCheck);
13595 
13596     return retVal;
13597 }
13598 
13599 /**
13600  * \brief Reads back the version of the ARM binary loaded into the Mykonos ARM memory
13601  *
13602  * This function reads the ARM memory to read back the major.minor.releaseCandidate
13603  * version for the ARM binary loaded into ARM memory.
13604  *
13605  * <B>Dependencies</B>
13606  * - device->spiSettings->chipSelectIndex
13607  *
13608  * \param device is structure pointer to the Mykonos data structure containing settings
13609  * \param majorVer The Major version is returned in this parameter
13610  * \param minorVer The Minor version is returned in this parameter
13611  * \param rcVer The release candidate version (build number) is returned in this parameter
13612  * \param buildType The Type of the build [Debug / Test_Object / Release]
13613  *
13614  * \retval MYKONOS_ERR_OK Function completed successfully
13615  * \retval MYKONOS_ERR_GETARMVER_NULL_PARM One of the function parameters has a NULL pointer
13616  */
MYKONOS_getArmVersion(mykonosDevice_t * device,uint8_t * majorVer,uint8_t * minorVer,uint8_t * rcVer,mykonosBuild_t * buildType)13617 mykonosErr_t MYKONOS_getArmVersion(mykonosDevice_t *device, uint8_t *majorVer, uint8_t *minorVer, uint8_t *rcVer, mykonosBuild_t *buildType)
13618 {
13619     mykonosErr_t retVal = MYKONOS_ERR_OK;
13620     uint8_t ver[5] = {0};
13621     uint32_t fullVersion = 0;
13622     uint8_t validBuilds = 0x05;
13623 
13624 #if (MYKONOS_VERBOSE == 1)
13625     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getArmVersion()\n");
13626 #endif
13627 
13628     if ((majorVer == NULL) || (minorVer == NULL) || (rcVer == NULL))
13629     {
13630         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETARMVER_NULL_PARM, getMykonosErrorMessage(MYKONOS_ERR_GETARMVER_NULL_PARM));
13631         return MYKONOS_ERR_GETARMVER_NULL_PARM;
13632     }
13633 
13634     retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_VERSION, &ver[0], sizeof(ver), 1);
13635     if (retVal != MYKONOS_ERR_OK)
13636     {
13637         return retVal;
13638     }
13639 
13640     fullVersion = ((uint32_t)(ver[0]) | (uint32_t)((uint32_t)(ver[1]) << 8) | (uint32_t)((uint32_t)(ver[2]) << 16) | (uint32_t)((uint32_t)(ver[3]) << 24));
13641     *rcVer = (uint8_t)(fullVersion % 100);
13642     *minorVer = (uint8_t)((fullVersion / 100) % 100);
13643     *majorVer = (uint8_t)(fullVersion / 10000);
13644 
13645     switch (ver[4] & validBuilds)
13646     {
13647         case MYK_BUILD_DEBUG:
13648                 *buildType = MYK_BUILD_DEBUG;
13649                 break;
13650         case MYK_BUILD_TEST_OBJECT:
13651                 *buildType = MYK_BUILD_TEST_OBJECT;
13652                 break;
13653         default:
13654                 *buildType = MYK_BUILD_RELEASE;
13655                 break;
13656     }
13657 
13658     return MYKONOS_ERR_OK;
13659 }
13660 
13661 /**
13662  * \brief This function will configure DPD settings
13663  *
13664  *  A DPD-enabled transceiver is required for DPD to be enabled.  The DPD has several user
13665  *  adjustable settings that can be configured before running the runInitCals
13666  *  with the calMask set for the DPD init cal. Call this function with desired
13667  *  settings set before running the DPD init cal or enabling DPD tracking.
13668  *
13669  *  This function can be called in either Radio On or Off state.
13670  *
13671  * <B>Dependencies</B>
13672  * - device->spiSettings->chipSelectIndex
13673  * - device->profilesValid
13674  * - device->tx->dpdConfig (All members)
13675  *
13676  *
13677  * \retval MYKONOS_ERR_CFGDPD_TXORX_PROFILE_INV ERROR: to use these features, a valid Tx and ORx profile must exist in the device data structure
13678  * \retval MYKONOS_ERR_CFGDPD_NULL_DPDCFGSTRUCT ERROR: device->tx->dpdConfig is a NULL pointer
13679  * \retval MYKONOS_ERR_CFGDPD_INV_DPDDAMPING ERROR: damping parameter is out of range
13680  * \retval MYKONOS_ERR_CFGDPD_INV_DPDSAMPLES ERROR: samples parameter is out of range
13681  * \retval MYKONOS_ERR_CFGDPD_INV_NUMWEIGHTS ERROR: numWeights parameter is out of range (0-3)
13682  * \retval MYKONOS_ERR_CFGDPD_INV_MODELVERSION ERROR: modelVersion parameter is out of range (0-3)
13683  * \retval MYKONOS_ERR_CFGDPD_INV_DPDOUTLIERTHRESH ERROR: outlierThreshold parameter is out of range
13684  * \retval MYKONOS_ERR_CFGDPD_INV_DPD_ADDDELAY ERROR: additionalDelayOffset parameter is out of range
13685  * \retval MYKONOS_ERR_CFGDPD_INV_PNSEQLEVEL ERROR: pathDelayPnSeqLevel parameter is out of range
13686  * \retval MYKONOS_ERR_OK Function completed successfully
13687  */
MYKONOS_configDpd(mykonosDevice_t * device)13688 mykonosErr_t MYKONOS_configDpd(mykonosDevice_t *device)
13689 {
13690     mykonosErr_t retVal = MYKONOS_ERR_OK;
13691     uint8_t armFieldValue[6] = {0};
13692     uint8_t byteOffset = 0;
13693     uint16_t negPnLevel = 0;
13694     uint8_t highPowerModelUpdate = 0;
13695     uint8_t robustModeling = 0;
13696     uint32_t radioStatus = 0;
13697 
13698 #if (MYKONOS_VERBOSE == 1)
13699     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_configDpd()\n");
13700 #endif
13701 
13702     /* DPD requires Tx and ORx enabled, throw error if both are not enabled */
13703     if ((device->profilesValid & (TX_PROFILE_VALID | ORX_PROFILE_VALID)) != (TX_PROFILE_VALID | ORX_PROFILE_VALID))
13704     {
13705         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGDPD_TXORX_PROFILE_INV,
13706                 getMykonosErrorMessage(MYKONOS_ERR_CFGDPD_TXORX_PROFILE_INV));
13707         return MYKONOS_ERR_CFGDPD_TXORX_PROFILE_INV;
13708     }
13709 
13710     if (device->tx->dpdConfig == NULL)
13711     {
13712         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGDPD_NULL_DPDCFGSTRUCT,
13713                 getMykonosErrorMessage(MYKONOS_ERR_CFGDPD_NULL_DPDCFGSTRUCT));
13714         return MYKONOS_ERR_CFGDPD_NULL_DPDCFGSTRUCT;
13715     }
13716 
13717     /* check DPD damping and samples parameters */
13718     if (device->tx->dpdConfig->damping > 15)
13719     {
13720         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGDPD_INV_DPDDAMPING,
13721                 getMykonosErrorMessage(MYKONOS_ERR_CFGDPD_INV_DPDDAMPING));
13722         return MYKONOS_ERR_CFGDPD_INV_DPDDAMPING;
13723     }
13724 
13725     if ((device->tx->dpdConfig->samples < 64) || (device->tx->dpdConfig->samples > 32768))
13726     {
13727         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGDPD_INV_DPDSAMPLES,
13728                 getMykonosErrorMessage(MYKONOS_ERR_CFGDPD_INV_DPDSAMPLES));
13729         return MYKONOS_ERR_CFGDPD_INV_DPDSAMPLES;
13730     }
13731 
13732     if (device->tx->dpdConfig->numWeights > 3)
13733     {
13734         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGDPD_INV_NUMWEIGHTS,
13735                 getMykonosErrorMessage(MYKONOS_ERR_CFGDPD_INV_NUMWEIGHTS));
13736         return MYKONOS_ERR_CFGDPD_INV_NUMWEIGHTS;
13737     }
13738 
13739     if (device->tx->dpdConfig->modelVersion > 3)
13740     {
13741         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGDPD_INV_MODELVERSION,
13742                 getMykonosErrorMessage(MYKONOS_ERR_CFGDPD_INV_MODELVERSION));
13743         return MYKONOS_ERR_CFGDPD_INV_MODELVERSION;
13744     }
13745 
13746     highPowerModelUpdate = (device->tx->dpdConfig->highPowerModelUpdate > 0) ? 1 : 0;
13747     robustModeling = (device->tx->dpdConfig->robustModeling > 0) ? 1 : 0;
13748 
13749     armFieldValue[0] = (uint8_t)(((device->tx->dpdConfig->numWeights & 3) << 4) | (device->tx->dpdConfig->damping & 0xF));
13750     armFieldValue[1] = (uint8_t)((robustModeling << 3) | (highPowerModelUpdate << 2) | (device->tx->dpdConfig->modelVersion & 3));
13751     armFieldValue[2] = (device->tx->dpdConfig->samples & 0xFF);
13752     armFieldValue[3] = ((device->tx->dpdConfig->samples >> 8) & 0xFF);
13753     byteOffset = 0;
13754     retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_DPDCONFIG, byteOffset, &armFieldValue[0], 4);
13755     if (retVal != MYKONOS_ERR_OK)
13756     {
13757         return retVal;
13758     }
13759 
13760     /* set DPD outlier threshold parameter */
13761     if ((device->tx->dpdConfig->outlierThreshold < 1) || (device->tx->dpdConfig->outlierThreshold > 8192))
13762     {
13763         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGDPD_INV_DPDOUTLIERTHRESH,
13764                 getMykonosErrorMessage(MYKONOS_ERR_CFGDPD_INV_DPDOUTLIERTHRESH));
13765         return MYKONOS_ERR_CFGDPD_INV_DPDOUTLIERTHRESH;
13766     }
13767 
13768     armFieldValue[0] = (device->tx->dpdConfig->outlierThreshold & 0xFF);
13769     armFieldValue[1] = ((device->tx->dpdConfig->outlierThreshold >> 8) & 0xFF);
13770     byteOffset = 10;
13771     retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_DPDCONFIG, byteOffset, &armFieldValue[0], 2);
13772     if (retVal != MYKONOS_ERR_OK)
13773     {
13774         return retVal;
13775     }
13776 
13777     /* set DPD Model Prior Weight parameter */
13778     if (device->tx->dpdConfig->modelPriorWeight > 32)
13779     {
13780         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGDPD_INV_DPDPRIORWEIGHT,
13781                 getMykonosErrorMessage(MYKONOS_ERR_CFGDPD_INV_DPDPRIORWEIGHT));
13782         return MYKONOS_ERR_CFGDPD_INV_DPDPRIORWEIGHT;
13783     }
13784     armFieldValue[0] = (device->tx->dpdConfig->modelPriorWeight & 0xFF);
13785     armFieldValue[1] = 0;
13786     byteOffset = 12;
13787     retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_DPDCONFIG, byteOffset, &armFieldValue[0], 2);
13788     if (retVal != MYKONOS_ERR_OK)
13789     {
13790         return retVal;
13791     }
13792 
13793     /* no need to verify weights min/max as all int8 values are valid */
13794     armFieldValue[0] = (uint8_t)(device->tx->dpdConfig->weights[0].real);
13795     armFieldValue[1] = (uint8_t)(device->tx->dpdConfig->weights[0].imag);
13796     armFieldValue[2] = (uint8_t)(device->tx->dpdConfig->weights[1].real);
13797     armFieldValue[3] = (uint8_t)(device->tx->dpdConfig->weights[1].imag);
13798     armFieldValue[4] = (uint8_t)(device->tx->dpdConfig->weights[2].real);
13799     armFieldValue[5] = (uint8_t)(device->tx->dpdConfig->weights[2].imag);
13800 
13801     byteOffset = 14;
13802     retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_DPDCONFIG, byteOffset, &armFieldValue[0], 6);
13803     if (retVal != MYKONOS_ERR_OK)
13804     {
13805         return retVal;
13806     }
13807 
13808     /* set DPD additional delay offset parameter */
13809     if ((device->tx->dpdConfig->additionalDelayOffset < -64) || (device->tx->dpdConfig->additionalDelayOffset > 64))
13810     {
13811         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGDPD_INV_DPD_ADDDELAY,
13812                 getMykonosErrorMessage(MYKONOS_ERR_CFGDPD_INV_DPD_ADDDELAY));
13813         return MYKONOS_ERR_CFGDPD_INV_DPD_ADDDELAY;
13814     }
13815 
13816     /* read radio state to make sure ARM is in radioOff /IDLE */
13817     retVal = MYKONOS_getRadioState(device, &radioStatus);
13818     if (retVal != MYKONOS_ERR_OK)
13819     {
13820         return retVal;
13821     }
13822 
13823     /* Radio state check */
13824     if (((radioStatus & 0x03) == MYKONOS_ARM_SYSTEMSTATE_IDLE) || ((radioStatus & 0x03) == MYKONOS_ARM_SYSTEMSTATE_READY))
13825     {
13826         armFieldValue[0] = (uint8_t)(device->tx->dpdConfig->additionalDelayOffset & 0xFF);
13827         armFieldValue[1] = (uint8_t)(((uint16_t)device->tx->dpdConfig->additionalDelayOffset >> 8) & 0xFF);
13828         byteOffset = 2;
13829         retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_DPDINIT_CONFIG, byteOffset, &armFieldValue[0], 2);
13830         if (retVal != MYKONOS_ERR_OK)
13831         {
13832             return retVal;
13833         }
13834 
13835         if ((device->tx->dpdConfig->pathDelayPnSeqLevel < 1) || (device->tx->dpdConfig->pathDelayPnSeqLevel > 8191))
13836         {
13837             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGDPD_INV_PNSEQLEVEL,
13838                     getMykonosErrorMessage(MYKONOS_ERR_CFGDPD_INV_PNSEQLEVEL));
13839             return MYKONOS_ERR_CFGDPD_INV_PNSEQLEVEL;
13840         }
13841 
13842         /* Set Path Delay PN sequence amplitude - positive and negative */
13843         armFieldValue[0] = (uint8_t)(device->tx->dpdConfig->pathDelayPnSeqLevel & 0xFF);
13844         armFieldValue[1] = (uint8_t)((device->tx->dpdConfig->pathDelayPnSeqLevel >> 8) & 0xFF);
13845 
13846         negPnLevel = ((~device->tx->dpdConfig->pathDelayPnSeqLevel) + 1); /* times -1 */
13847         armFieldValue[2] = (uint8_t)(negPnLevel & 0xFF);
13848         armFieldValue[3] = (uint8_t)(((negPnLevel) >> 8) & 0xFF);
13849         byteOffset = 10;
13850         retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_DPDINIT_CONFIG, byteOffset, &armFieldValue[0], 4);
13851         if (retVal != MYKONOS_ERR_OK)
13852         {
13853             return retVal;
13854         }
13855     }
13856     else
13857     {
13858         /* record warning about not updated members */
13859         CMB_writeToLog(ADIHAL_LOG_WARNING, device->spiSettings->chipSelectIndex, MYKONOS_WRN_RADIO_ON_NOT_MODIFIABLE,
13860                            getMykonosErrorMessage(MYKONOS_WRN_RADIO_ON_NOT_MODIFIABLE));
13861     }
13862 
13863     return MYKONOS_ERR_OK;
13864 }
13865 
13866 /* \brief Reads the DPD config structure from ARM memory
13867  *
13868  *  This function reads the DPD structure
13869  *  from ARM memory and returns in the device->tx->dpdConfig structure.
13870  *
13871  *  A DPD-enabled transceiver is required for DPD to be enabled.
13872  *
13873  * <B>Dependencies</B>
13874  * - device->spiSettings->chipSelectIndex
13875  * - device->profilesValid
13876  * - device->tx->dpdConfig (All members)
13877  *
13878  * \param device is structure pointer to the Mykonos data structure containing settings
13879  *
13880  * \retval MYKONOS_ERR_OK Function completed successfully
13881  * \retval MYKONOS_ERR_GETDPDCFG_TXORX_PROFILE_INV Error: Tx and ORx profiles must be valid for DPD functions
13882  * \retval MYKONOS_ERR_GETDPDCFG_NULL_DPDCFGSTRUCT Error: NULL pointer to device->tx->dpdConfig structure
13883  */
MYKONOS_getDpdConfig(mykonosDevice_t * device)13884 mykonosErr_t MYKONOS_getDpdConfig(mykonosDevice_t *device)
13885 {
13886     uint16_t byteOffset = 0;
13887     uint8_t armMem[20] = {0};
13888     mykonosErr_t retVal = MYKONOS_ERR_OK;
13889 
13890 #if (MYKONOS_VERBOSE == 1)
13891     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getDpdConfig()\n");
13892 #endif
13893 
13894     /* DPD requires Tx and ORx enabled, throw error if both are not enabled */
13895     if ((device->profilesValid & (TX_PROFILE_VALID | ORX_PROFILE_VALID)) != (TX_PROFILE_VALID | ORX_PROFILE_VALID))
13896     {
13897         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETDPDCFG_TXORX_PROFILE_INV,
13898                 getMykonosErrorMessage(MYKONOS_ERR_GETDPDCFG_TXORX_PROFILE_INV));
13899         return MYKONOS_ERR_GETDPDCFG_TXORX_PROFILE_INV;
13900     }
13901 
13902     if (device->tx->dpdConfig == NULL)
13903     {
13904         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETDPDCFG_NULL_DPDCFGSTRUCT,
13905                 getMykonosErrorMessage(MYKONOS_ERR_GETDPDCFG_NULL_DPDCFGSTRUCT));
13906         return MYKONOS_ERR_GETDPDCFG_NULL_DPDCFGSTRUCT;
13907     }
13908 
13909     byteOffset = 0;
13910     retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_DPDCONFIG, byteOffset, &armMem[0], 20);
13911     if (retVal != MYKONOS_ERR_OK)
13912     {
13913         return retVal;
13914     }
13915 
13916     device->tx->dpdConfig->damping = (armMem[0] & 0x0F);
13917     device->tx->dpdConfig->numWeights = ((armMem[0] >> 4) & 0x03);
13918 
13919     device->tx->dpdConfig->modelVersion = (armMem[1] & 0x03);
13920     device->tx->dpdConfig->highPowerModelUpdate = ((armMem[1] >> 2) & 0x01);
13921     device->tx->dpdConfig->robustModeling = 0;
13922     device->tx->dpdConfig->samples = ((uint16_t)(armMem[3]) << 8) | (uint16_t)(armMem[2]);
13923 
13924     device->tx->dpdConfig->outlierThreshold = ((uint16_t)(armMem[11]) << 8) | (uint16_t)(armMem[10]);
13925     device->tx->dpdConfig->modelPriorWeight = armMem[12];
13926     device->tx->dpdConfig->weights[0].real = (int8_t)(armMem[14]);
13927     device->tx->dpdConfig->weights[0].imag = (int8_t)(armMem[15]);
13928     device->tx->dpdConfig->weights[1].real = (int8_t)(armMem[16]);
13929     device->tx->dpdConfig->weights[1].imag = (int8_t)(armMem[17]);
13930     device->tx->dpdConfig->weights[2].real = (int8_t)(armMem[18]);
13931     device->tx->dpdConfig->weights[2].imag = (int8_t)(armMem[19]);
13932 
13933     byteOffset = 2;
13934     retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_DPDINIT_CONFIG, byteOffset, &armMem[0], 2);
13935     if (retVal != MYKONOS_ERR_OK)
13936     {
13937         return retVal;
13938     }
13939 
13940     device->tx->dpdConfig->additionalDelayOffset = (int16_t)(((uint16_t)(armMem[1]) << 8) | (uint16_t)(armMem[0]));
13941 
13942     byteOffset = 10;
13943     retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_DPDINIT_CONFIG, byteOffset, &armMem[0], 2);
13944     if (retVal != MYKONOS_ERR_OK)
13945     {
13946         return retVal;
13947     }
13948 
13949     device->tx->dpdConfig->pathDelayPnSeqLevel = (((uint16_t)(armMem[1]) << 8) | (uint16_t)(armMem[0]));
13950 
13951     return MYKONOS_ERR_OK;
13952 }
13953 
13954 /**
13955  * \brief This function reads the DPD calibration status from the Mykonos ARM processor.
13956  *
13957  * The dpdStatus is read back from the ARM processor and returned in the function
13958  * parameter dpdStatus.
13959  *
13960  *  A DPD-enabled transceiver is required for this feature to be enabled.
13961  *
13962  * <B>Dependencies</B>
13963  * - device->spiSettings->chipSelectIndex
13964  *
13965  * \param device is structure pointer to the Mykonos data structure containing settings
13966  * \param txChannel Desired Transmit channel to read back DPD status for (Valid ENUM values: TX1 or TX2 only)
13967  * \param dpdStatus Pointer to a structure to return the status information to
13968  *
13969  * \retval MYKONOS_ERR_OK Function completed successfully
13970  * \retval MYKONOS_ERR_GETDPDSTATUS_NULLPARAM dpdStatus function parameter is a NULL pointer
13971  * \retval MYKONOS_ERR_GETDPDSTATUS_INV_CH txChannel parameter is a non-supported value.
13972  * \retval MYKONOS_ERR_GETDPDSTATUS_ARMERRFLAG ARM reported an error while processing the GET ARM command
13973  */
MYKONOS_getDpdStatus(mykonosDevice_t * device,mykonosTxChannels_t txChannel,mykonosDpdStatus_t * dpdStatus)13974 mykonosErr_t MYKONOS_getDpdStatus(mykonosDevice_t *device, mykonosTxChannels_t txChannel, mykonosDpdStatus_t *dpdStatus)
13975 {
13976     uint8_t extData[3] = {MYKONOS_ARM_OBJECTID_CAL_STATUS, MYKONOS_ARM_OBJECTID_DPDCONFIG, 0};
13977     uint8_t armData[64] = {0};
13978     uint32_t timeoutMs = 0;
13979     uint8_t cmdStatusByte = 0;
13980     uint8_t channelSelect = 0;
13981     mykonosErr_t retVal = MYKONOS_ERR_OK;
13982 
13983 #if (MYKONOS_VERBOSE == 1)
13984     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getDpdStatus()\n");
13985 #endif
13986 
13987     if (dpdStatus == NULL)
13988     {
13989         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETDPDSTATUS_NULLPARAM,
13990                 getMykonosErrorMessage(MYKONOS_ERR_GETDPDSTATUS_NULLPARAM));
13991         return MYKONOS_ERR_GETDPDSTATUS_NULLPARAM;
13992     }
13993 
13994     switch (txChannel)
13995     {
13996         case TX1:
13997             channelSelect = 0;
13998             break;
13999         case TX2:
14000             channelSelect = 1;
14001             break;
14002         default:
14003         {
14004             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETDPDSTATUS_INV_CH,
14005                     getMykonosErrorMessage(MYKONOS_ERR_GETDPDSTATUS_INV_CH));
14006             return MYKONOS_ERR_GETDPDSTATUS_INV_CH;
14007         }
14008     }
14009 
14010     extData[2] = channelSelect;
14011 
14012     retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &extData[0], sizeof(extData));
14013     if (retVal != MYKONOS_ERR_OK)
14014     {
14015         return retVal;
14016     }
14017 
14018     timeoutMs = 1000;
14019     retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte);
14020     if (retVal != MYKONOS_ERR_OK)
14021     {
14022         if (cmdStatusByte > 0)
14023         {
14024             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETDPDSTATUS_ARMERRFLAG,
14025                     getMykonosErrorMessage(MYKONOS_ERR_GETDPDSTATUS_ARMERRFLAG));
14026             return MYKONOS_ERR_GETDPDSTATUS_ARMERRFLAG;
14027         }
14028 
14029         return retVal;
14030     }
14031 
14032     if (cmdStatusByte > 0)
14033     {
14034         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETDPDSTATUS_ARMERRFLAG,
14035                 getMykonosErrorMessage(MYKONOS_ERR_GETDPDSTATUS_ARMERRFLAG));
14036         return MYKONOS_ERR_GETDPDSTATUS_ARMERRFLAG;
14037     }
14038 
14039     /* read status from ARM memory */
14040     retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &armData[0], sizeof(armData), 1);
14041     if (retVal != MYKONOS_ERR_OK)
14042     {
14043         return retVal;
14044     }
14045 
14046     dpdStatus->dpdErrorStatus = ((uint32_t)(armData[1]) << 8) | (uint32_t)(armData[0]); /* Only lower 16 bits */
14047     dpdStatus->dpdTrackCount = ((uint32_t)(armData[11]) << 24) | ((uint32_t)(armData[10]) << 16) | ((uint32_t)(armData[9]) << 8) | (uint32_t)(armData[8]);
14048     dpdStatus->dpdModelErrorPercent = ((uint32_t)(armData[15]) << 24) | ((uint32_t)(armData[14]) << 16) | ((uint32_t)(armData[13]) << 8) | (uint32_t)(armData[12]);
14049     dpdStatus->dpdExtPathDelay = ((uint32_t)(armData[26]) * 16) + (uint32_t)(armData[24]);
14050     dpdStatus->dpdMaxAdaptationCurrent = ((uint16_t)(armData[41]) << 8) + (uint16_t)(armData[40]);
14051     dpdStatus->dpdMaxAdaptation = ((uint16_t)(armData[43]) << 8) + (uint16_t)(armData[42]);
14052     dpdStatus->dpdIterCount = ((uint32_t)(armData[47]) << 24) | ((uint32_t)(armData[46]) << 16) | ((uint32_t)(armData[45]) << 8) | (uint32_t)(armData[44]);
14053 
14054     return MYKONOS_ERR_OK;
14055 }
14056 
14057 /**
14058  * \brief This private helper function called during RadioOff, will allow DPD tracking to be scheduled
14059  *        by the ARM when back in the RadioOn state.
14060  *
14061  *  This function sets a flag in the ARM memory that if the enableDpd tracking cal mask
14062  *  and this setting are both set, then the ARM will schedule DPD tracking to occur
14063  *  in the radioOn ARM state.
14064  *
14065  *  A DPD-enabled transceiver is required for DPD to be enabled.
14066  *
14067  * <B>Dependencies</B>
14068  * - device->spiSettings->chipSelectIndex
14069  * - device->tx->dpdConfig
14070  *
14071  * \param device is structure pointer to the Mykonos data structure containing settings
14072  * \param tx1Enable 0=disable DPD Tx1 tracking, 1= enable DPD Tx1 tracking
14073  * \param tx2Enable 0=disable DPD Tx2 tracking, 1= enable DPD Tx2 tracking
14074  *
14075  * \retval MYKONOS_ERR_OK Function completed successfully
14076  * \retval MYKONOS_ERR_EN_DPDTRACKING_ARMSTATE_ERROR ARM is not in the RadioOff state, call MYKONOS_radioOff()
14077  */
enableDpdTracking(mykonosDevice_t * device,uint8_t tx1Enable,uint8_t tx2Enable)14078 static mykonosErr_t enableDpdTracking(mykonosDevice_t *device, uint8_t tx1Enable, uint8_t tx2Enable)
14079 {
14080     uint32_t radioStatus = 0;
14081     mykonosErr_t retVal = MYKONOS_ERR_OK;
14082     uint8_t enableBit[4] = {0};
14083     uint8_t byteOffset = 20;
14084 
14085 #if (MYKONOS_VERBOSE == 1)
14086     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enableDpdTracking()\n");
14087 #endif
14088 
14089     /* read radio state to make sure ARM is in radioOff /IDLE */
14090     retVal = MYKONOS_getRadioState(device, &radioStatus);
14091     if (retVal != MYKONOS_ERR_OK)
14092     {
14093         return retVal;
14094     }
14095 
14096     /* throw error if not in radioOff/IDLE state */
14097     if (((radioStatus & 0x03) != MYKONOS_ARM_SYSTEMSTATE_IDLE) && ((radioStatus & 0x03) != MYKONOS_ARM_SYSTEMSTATE_READY))
14098     {
14099         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_EN_DPDTRACKING_ARMSTATE_ERROR,
14100                 getMykonosErrorMessage(MYKONOS_ERR_EN_DPDTRACKING_ARMSTATE_ERROR));
14101         return MYKONOS_ERR_EN_DPDTRACKING_ARMSTATE_ERROR;
14102     }
14103 
14104     enableBit[0] = (tx1Enable > 0) ? 1 : 0;
14105     enableBit[1] = 0;
14106     enableBit[2] = (tx2Enable > 0) ? 1 : 0;
14107     enableBit[3] = 0;
14108 
14109     retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_DPDCONFIG, byteOffset, &enableBit[0], 4);
14110     if (retVal != MYKONOS_ERR_OK)
14111     {
14112         return retVal;
14113     }
14114 
14115     return MYKONOS_ERR_OK;
14116 }
14117 
14118 /**
14119  * \brief This function will allow loading of the DPD model file.
14120  *
14121  *  This function writes a copy of the user's DPD model to ARM memory and instructs the ARM to install that DPD model
14122  *  into hardware.  Note that initializing the device will over write DPD model data.  Note that the DPD model being
14123  *  restored must match the PA for which it is configured.  Restoring a DPD model to a different PA than for which it
14124  *  is configured will not yield the desired performance.  The user is responsible to insure the DPD model matches the
14125  *  PA configuration.
14126  *
14127  * \param device Structure pointer to the Mykonos data structure containing settings
14128  * \param txChannel Desired transmit channel to which to write the DPD model file (Valid ENUM type mykonosTxChannels_t: TX1 or TX2 or TX1_TX2)
14129  * \param modelDataBuffer Pointer to the user buffer containing the history/model data to be loaded to a txChannel
14130  *        Valid sizes: 182 bytes for a single model load to either TX1 or TX2.
14131  *                     364 bytes for a dual model load to both TX1_TX2, where the TX1 model data will occupy the first 182 bytes
14132  *                     and TX2 model data will occupy the second 182 bytes.
14133  * \param modelNumberBytes Total buffer size of the user history/model data buffer. Allowed sizes are 182 bytes for TX1 or TX2 and
14134  *        364 bytes for TX1_TX2.
14135  *
14136  *
14137  * \retval MYKONOS_ERR_OK Function completed successfully
14138  * \retval MYKONOS_ERR_RESTDPDMOD_WRONGBUFFERSIZE User suppled modelNumberBytes size is incorrect. TX1 or TX2 = 182,  TX1_TX2 = 364
14139  * \retval MYKONOS_ERR_RESTDPDMOD_INVALID_TXCHANNEL User supplied txChannel does not match TX1 or TX2 or TX1_TX2
14140  * \retval MYKONOS_ERR_RESTDPDMOD_ARMERRFLAG ARM returned error for Set ARM Command
14141  */
MYKONOS_restoreDpdModel(mykonosDevice_t * device,mykonosTxChannels_t txChannel,uint8_t * modelDataBuffer,uint32_t modelNumberBytes)14142 mykonosErr_t MYKONOS_restoreDpdModel(mykonosDevice_t *device, mykonosTxChannels_t txChannel, uint8_t *modelDataBuffer, uint32_t modelNumberBytes)
14143 {
14144     uint32_t radioStatus = 0;
14145     mykonosErr_t retVal = MYKONOS_ERR_OK;
14146     uint8_t armData[4] = {0};
14147     uint32_t armBufferAddr = 0;
14148     uint8_t *bufferPtr = 0;
14149     uint8_t extendedData[4] = {0};
14150     uint8_t cmdStatusByte = 0;
14151 
14152     const uint8_t RESTORE = 0x08;
14153     const uint32_t timeoutMs = 1000;
14154     const uint32_t MODEL_SIZE = 182;
14155 
14156 #if (MYKONOS_VERBOSE == 1)
14157     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_restoreDpdModel()\n");
14158 #endif
14159 
14160     /* read radio state to make sure ARM is in radioOff /IDLE */
14161     retVal = MYKONOS_getRadioState(device, &radioStatus);
14162     if (retVal != MYKONOS_ERR_OK)
14163     {
14164         return retVal;
14165     }
14166 
14167     if (txChannel == TX1)
14168     {
14169         /* check for single valid provided buffer size */
14170         if (modelNumberBytes != MODEL_SIZE)
14171         {
14172             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RESTDPDMOD_WRONGBUFFERSIZE,
14173                     getMykonosErrorMessage(MYKONOS_ERR_RESTDPDMOD_WRONGBUFFERSIZE));
14174             return MYKONOS_ERR_RESTDPDMOD_WRONGBUFFERSIZE;
14175         }
14176 
14177         /* retrieve the arm TX1 model buffer address */
14178         retVal = MYKONOS_readArmMem(device, (MYKONOS_ADDR_ARM_START_PROG_ADDR + MYKONOS_ADDR_TX1_DPD_MODEL_INDIRECT_PTR), &armData[0], 4, 1);
14179         if (retVal != MYKONOS_ERR_OK)
14180         {
14181             return retVal;
14182         }
14183         armBufferAddr = (((uint32_t)armData[0]) | (((uint32_t)armData[1]) << 8) | (((uint32_t)armData[2]) << 16) | (((uint32_t)armData[3]) << 24));
14184 
14185         /* write the TX1 model */
14186         bufferPtr = modelDataBuffer;
14187         retVal = MYKONOS_writeArmMem(device, armBufferAddr, bufferPtr, MODEL_SIZE); /* write TX1 model */
14188         if (retVal != MYKONOS_ERR_OK)
14189         {
14190             return retVal;
14191         }
14192     }/*end TX1 */
14193 
14194     else if (txChannel == TX2)
14195     {
14196         /* check for single valid provided buffer size */
14197         if (modelNumberBytes != MODEL_SIZE)
14198         {
14199             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RESTDPDMOD_WRONGBUFFERSIZE,
14200                     getMykonosErrorMessage(MYKONOS_ERR_RESTDPDMOD_WRONGBUFFERSIZE));
14201             return MYKONOS_ERR_RESTDPDMOD_WRONGBUFFERSIZE;
14202         }
14203 
14204         /* retrieve the arm TX2 model buffer address */
14205         retVal = MYKONOS_readArmMem(device, (MYKONOS_ADDR_ARM_START_PROG_ADDR + MYKONOS_ADDR_TX2_DPD_MODEL_INDIRECT_PTR), &armData[0], 4, 1);
14206         if (retVal != MYKONOS_ERR_OK)
14207         {
14208             return retVal;
14209         }
14210         armBufferAddr = (((uint32_t)armData[0]) | (((uint32_t)armData[1]) << 8) | (((uint32_t)armData[2]) << 16) | (((uint32_t)armData[3]) << 24));
14211 
14212         /* write the TX2 model */
14213         bufferPtr = modelDataBuffer;
14214         retVal = MYKONOS_writeArmMem(device, armBufferAddr, bufferPtr, MODEL_SIZE);
14215         if (retVal != MYKONOS_ERR_OK)
14216         {
14217             return retVal;
14218         }
14219     }/* end TX2 */
14220 
14221     /* check for dual txChannel type */
14222     else if (txChannel == TX1_TX2)
14223     {
14224         /* check for single valid provided buffer size */
14225         if (modelNumberBytes != (2 * MODEL_SIZE))
14226         {
14227             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RESTDPDMOD_WRONGBUFFERSIZE,
14228                     getMykonosErrorMessage(MYKONOS_ERR_RESTDPDMOD_WRONGBUFFERSIZE));
14229             return MYKONOS_ERR_RESTDPDMOD_WRONGBUFFERSIZE;
14230         }
14231 
14232         /* retrieve the arm TX1 model buffer address */
14233         retVal = MYKONOS_readArmMem(device, (MYKONOS_ADDR_ARM_START_PROG_ADDR + MYKONOS_ADDR_TX1_DPD_MODEL_INDIRECT_PTR), &armData[0], 4, 1);
14234         if (retVal != MYKONOS_ERR_OK)
14235         {
14236             return retVal;
14237         }
14238         armBufferAddr = (((uint32_t)armData[0]) | (((uint32_t)armData[1]) << 8) | (((uint32_t)armData[2]) << 16) | (((uint32_t)armData[3]) << 24));
14239 
14240         /* write the TX1 model */
14241         bufferPtr = modelDataBuffer;
14242         retVal = MYKONOS_writeArmMem(device, armBufferAddr, bufferPtr, MODEL_SIZE); /* write TX1 model */
14243         if (retVal != MYKONOS_ERR_OK)
14244         {
14245             return retVal;
14246         }
14247         bufferPtr += MODEL_SIZE;
14248 
14249         /* retrieve the arm TX2 model buffer address */
14250         retVal = MYKONOS_readArmMem(device, (MYKONOS_ADDR_ARM_START_PROG_ADDR + MYKONOS_ADDR_TX2_DPD_MODEL_INDIRECT_PTR), &armData[0], 4, 1);
14251         if (retVal != MYKONOS_ERR_OK)
14252         {
14253             return retVal;
14254         }
14255         armBufferAddr = (((uint32_t)armData[0]) | (((uint32_t)armData[1]) << 8) | (((uint32_t)armData[2]) << 16) | (((uint32_t)armData[3]) << 24));
14256 
14257         /* write the TX2 model */
14258         retVal = MYKONOS_writeArmMem(device, armBufferAddr, bufferPtr, MODEL_SIZE); /* write TX2 model */
14259         if (retVal != MYKONOS_ERR_OK)
14260         {
14261             return retVal;
14262         }
14263     }/*end two txChannel model data load */
14264 
14265     /* invalid txChannel for this API command */
14266     else
14267     {
14268         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RESTDPDMOD_INVALID_TXCHANNEL,
14269                 getMykonosErrorMessage(MYKONOS_ERR_RESTDPDMOD_INVALID_TXCHANNEL));
14270         return MYKONOS_ERR_RESTDPDMOD_INVALID_TXCHANNEL;
14271     }/* end invalid txChannel check */
14272 
14273     /* instruct ARM to load DPD Model */
14274     extendedData[0] = MYKONOS_ARM_OBJECTID_GS_TRACKCALS;
14275     extendedData[1] = MYKONOS_ARM_DPD_RESET;
14276     extendedData[2] = (uint8_t)txChannel + RESTORE;
14277 
14278     retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_SET_OPCODE, &extendedData[0], sizeof(extendedData));
14279     if (retVal != MYKONOS_ERR_OK)
14280     {
14281         return retVal;
14282     }
14283 
14284     /* wait max of 1sec for command to complete */
14285     retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_SET_OPCODE, timeoutMs, &cmdStatusByte);
14286     if (retVal != MYKONOS_ERR_OK)
14287     {
14288         if (cmdStatusByte > 0)
14289         {
14290             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RESTDPDMOD_ARMERRFLAG,
14291                     getMykonosErrorMessage(MYKONOS_ERR_RESTDPDMOD_ARMERRFLAG));
14292             return MYKONOS_ERR_RESTDPDMOD_ARMERRFLAG;
14293         }
14294         return retVal;
14295     }
14296 
14297     return MYKONOS_ERR_OK;
14298 }
14299 
14300 
14301 /**
14302  * \brief This function called during RadioOff, will allow retrieval of the DPD model file.
14303  *
14304  *  This function reads a copy of the DPD model from ARM memory to user memory specified by the modelDataBuffer pointer.
14305  *  The user must provide the correct buffer size with the modelNumberBytes argument.
14306  *
14307  * \param device is structure pointer to the Mykonos data structure containing settings
14308  * \param txChannel Desired Transmit channel to read back DPD status for (Valid ENUM type mykonosTxChannels_t: TX1 or TX2 or TX1_TX2)
14309  * \param modelDataBuffer a pointer to the user buffer where the model data is to be written.
14310  *        Valid sizes: 182 bytes for a single model load to either TX1 or TX2.
14311  *                     364 bytes for a dual model load to both TX1_TX2, where the TX1 model data will occupy the first 182 bytes
14312  *                          and TX2 model data will occupy the second 182 bytes.
14313  * \param modelNumberBytes is the total buffer size of the user model data buffer. Allowed sizes are 182 bytes for TX1 or TX2 and
14314  *        364 bytes for TX1_TX2.
14315  *
14316  * \retval MYKONOS_ERR_OK Function completed successfully
14317  * \retval MYKONOS_ERR_SAVEDPDMODEL_ARMSTATE_ERROR ARM is not in the RadioOff state, call MYKONOS_radioOff()
14318  * \retval MYKONOS_ERR_SAVEDPDMODEL_BUFFERSIZE_ERROR suppled modelNumberBytes size is incorrect. TX1 or TX2 = 182,  TX1_TX2 = 364
14319  * \retval MYKONOS_ERR_SAVEDPDMODEL_INVALID_TXCHANNEL_ERROR supplied txChannel does not match TX1 or TX2 or TX1_TX2
14320  */
MYKONOS_saveDpdModel(mykonosDevice_t * device,mykonosTxChannels_t txChannel,uint8_t * modelDataBuffer,uint32_t modelNumberBytes)14321 mykonosErr_t MYKONOS_saveDpdModel(mykonosDevice_t *device, mykonosTxChannels_t txChannel, uint8_t *modelDataBuffer, uint32_t modelNumberBytes)
14322 {
14323     uint32_t radioStatus = 0;
14324     mykonosErr_t retVal = MYKONOS_ERR_OK;
14325     uint16_t modelSize = 0;
14326     uint8_t armData[4] = {0};
14327     uint32_t armBufferAddr = 0;
14328 
14329     const uint32_t MODEL_SIZE = 182;
14330 
14331 #if (MYKONOS_VERBOSE == 1)
14332     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_saveDpdModel()\n");
14333 #endif
14334 
14335     /* read radio state to make sure ARM is in radioOff /IDLE */
14336     retVal = MYKONOS_getRadioState(device, &radioStatus);
14337     if (retVal != MYKONOS_ERR_OK)
14338     {
14339         return retVal;
14340     }
14341 
14342     /* throw error if not in radioOff/IDLE state */
14343     if (((radioStatus & 0x03) != MYKONOS_ARM_SYSTEMSTATE_IDLE) && ((radioStatus & 0x03) != MYKONOS_ARM_SYSTEMSTATE_READY))
14344     {
14345         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SAVDPDMOD_ARMSTATE, getMykonosErrorMessage(MYKONOS_ERR_SAVDPDMOD_ARMSTATE)); /* radio not off or initialized */
14346         return MYKONOS_ERR_SAVDPDMOD_ARMSTATE;
14347     }
14348 
14349     if (txChannel == TX1)
14350     {
14351         /* check for single valid provided buffer size */
14352         if (modelNumberBytes != MODEL_SIZE)
14353         {
14354             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SAVDPDMOD_WRONGBUFFERSIZE,
14355                     getMykonosErrorMessage(MYKONOS_ERR_SAVDPDMOD_WRONGBUFFERSIZE));
14356             return MYKONOS_ERR_SAVDPDMOD_WRONGBUFFERSIZE; /* wrong buffer size */
14357         }
14358 
14359         /* retrieve the arm TX1 model buffer address */
14360         retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_START_PROG_ADDR + MYKONOS_ADDR_TX1_DPD_MODEL_WORKING_PTR, &armData[0], 4, 1);
14361         if (retVal != MYKONOS_ERR_OK)
14362         {
14363             return retVal;
14364         }
14365         armBufferAddr = (((uint32_t)armData[0]) | (((uint32_t)armData[1]) << 8) | (((uint32_t)armData[2]) << 16) | (((uint32_t)armData[3]) << 24));
14366 
14367         /* read the TX1 model */
14368         retVal = MYKONOS_readArmMem(device, armBufferAddr, modelDataBuffer, MODEL_SIZE, 1);
14369         if (retVal != MYKONOS_ERR_OK)
14370         {
14371             return retVal;
14372         }
14373         modelDataBuffer += modelSize;
14374     }/*end TX1 */
14375 
14376     else if (txChannel == TX2)
14377     {
14378         /* check for single valid provided buffer size */
14379         if (modelNumberBytes != MODEL_SIZE)
14380         {
14381             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SAVDPDMOD_WRONGBUFFERSIZE,
14382                     getMykonosErrorMessage(MYKONOS_ERR_SAVDPDMOD_WRONGBUFFERSIZE));
14383             return MYKONOS_ERR_SAVDPDMOD_WRONGBUFFERSIZE; /* wrong buffer size */
14384         }
14385 
14386         /* retrieve the arm TX2 model buffer address */
14387         retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_START_PROG_ADDR + MYKONOS_ADDR_TX2_DPD_MODEL_WORKING_PTR, &armData[0], 4, 1);
14388         if (retVal != MYKONOS_ERR_OK)
14389         {
14390             return retVal;
14391         }
14392         armBufferAddr = (((uint32_t)armData[0]) | (((uint32_t)armData[1]) << 8) | (((uint32_t)armData[2]) << 16) | (((uint32_t)armData[3]) << 24));
14393 
14394         /* read the TX2 model */
14395         retVal = MYKONOS_readArmMem(device, armBufferAddr, modelDataBuffer, MODEL_SIZE, 1);
14396         if (retVal != MYKONOS_ERR_OK)
14397         {
14398             return retVal;
14399         }
14400     }/*end TX2 */
14401 
14402     /* check for dual txChannel type */
14403     else if (txChannel == TX1_TX2)
14404     {
14405         /* check for single valid provided buffer size */
14406         if (modelNumberBytes != (2 * MODEL_SIZE))
14407         {
14408             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SAVDPDMOD_WRONGBUFFERSIZE,
14409                     getMykonosErrorMessage(MYKONOS_ERR_SAVDPDMOD_WRONGBUFFERSIZE));
14410             return MYKONOS_ERR_SAVDPDMOD_WRONGBUFFERSIZE; /* wrong buffer size */
14411         }
14412 
14413         /* retrieve the arm TX1 model buffer address */
14414         retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_START_PROG_ADDR + MYKONOS_ADDR_TX1_DPD_MODEL_WORKING_PTR, &armData[0], 4, 1);
14415         if (retVal != MYKONOS_ERR_OK)
14416         {
14417             return retVal;
14418         }
14419         armBufferAddr = (((uint32_t)armData[0]) | (((uint32_t)armData[1]) << 8) | (((uint32_t)armData[2]) << 16) | (((uint32_t)armData[3]) << 24));
14420 
14421         /* read the TX1 model */
14422         retVal = MYKONOS_readArmMem(device, armBufferAddr, modelDataBuffer, MODEL_SIZE, 1);
14423         if (retVal != MYKONOS_ERR_OK)
14424         {
14425             return retVal;
14426         }
14427         modelDataBuffer += MODEL_SIZE;
14428 
14429         /* retrieve the arm TX2 model buffer address */
14430         retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_START_PROG_ADDR + MYKONOS_ADDR_TX2_DPD_MODEL_WORKING_PTR, &armData[0], 4, 1);
14431         if (retVal != MYKONOS_ERR_OK)
14432         {
14433             return retVal;
14434         }
14435         armBufferAddr = (((uint32_t)armData[0]) | (((uint32_t)armData[1]) << 8) | (((uint32_t)armData[2]) << 16) | (((uint32_t)armData[3]) << 24));
14436 
14437         /* read the TX2 model */
14438         retVal = MYKONOS_readArmMem(device, armBufferAddr, modelDataBuffer, MODEL_SIZE, 1);
14439         if (retVal != MYKONOS_ERR_OK)
14440         {
14441             return retVal;
14442         }
14443     }/* end TX1_TX2 txChannel */
14444 
14445     /* invalid txChannel for this API command */
14446     else
14447     {
14448         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SAVDPDMOD_INVALID_TXCHANNEL,
14449                 getMykonosErrorMessage(MYKONOS_ERR_SAVDPDMOD_INVALID_TXCHANNEL));
14450         return MYKONOS_ERR_SAVDPDMOD_INVALID_TXCHANNEL; /* invalid txChannel */
14451     }/* end invalid txChannel check */
14452 
14453     return MYKONOS_ERR_OK;
14454 }
14455 
14456 /**
14457  * \brief This function sets the state of the DPD actuator.
14458  *
14459  *  This function can be called in either Radio On or Off state.
14460  *
14461  * \pre A DPD-enabled transceiver is required for DPD to be enabled. DPD init cal has been run and DPD tracking enable.
14462  *
14463  * <B>Dependencies</B>
14464  * - device->spiSettings->chipSelectIndex
14465  *
14466  * \param device is structure pointer to the Mykonos data structure containing settings
14467  * \param txChannel Desired Transmit channel to set the Actuator State (Valid ENUM values: TX1, TX2 or TX1_TX2)
14468  * \param actState Desired actuator state for the DPD, valid states are 0-disable and 1-enable
14469  *
14470  * \retval MYKONOS_ERR_SETDPDACT_INV_TXCHANNEL ERROR: Tx channel is not valid (Valid ENUM values: TX1, TX2 or TX1_TX2)
14471  * \retval MYKONOS_ERR_SETDPDACT_INV_STATE ERROR: Invalid Actuator state, valid states are 0-disable and 1-enable.
14472  * \retval MYKONOS_ERR_SETDPDACT_ARMERRFLAG ERROR: ARM command flag error set
14473  * \retval MYKONOS_ERR_OK Function completed successfully
14474  */
MYKONOS_setDpdActState(mykonosDevice_t * device,mykonosTxChannels_t txChannel,uint8_t actState)14475 mykonosErr_t MYKONOS_setDpdActState(mykonosDevice_t *device, mykonosTxChannels_t txChannel, uint8_t actState)
14476 {
14477     mykonosErr_t retVal = MYKONOS_ERR_OK;
14478     uint32_t timeoutMs = 1000;
14479     uint8_t extData[3] = {0};
14480     uint8_t actuatorSet = 0x00;
14481     uint8_t cmdStatusByte = 0;
14482 
14483 #if (MYKONOS_VERBOSE == 1)
14484     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setDpdActState()\n");
14485 #endif
14486 
14487     switch (txChannel)
14488     {
14489         case TX1:
14490             break;
14491         case TX2:
14492             break;
14493         case TX1_TX2:
14494             break;
14495 
14496         default:
14497             /* this function allow single channel gain only */
14498             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETDPDACT_INV_TXCHANNEL,
14499                     getMykonosErrorMessage(MYKONOS_ERR_SETDPDACT_INV_TXCHANNEL));
14500             return MYKONOS_ERR_SETDPDACT_INV_TXCHANNEL;
14501     }
14502     switch (actState)
14503     {
14504         case 0:
14505             actuatorSet = DISABLE_DPD_ACTUATOR;
14506             break;
14507         case 1:
14508             actuatorSet = ENABLE_DPD_ACTUATOR;
14509             break;
14510 
14511         default:
14512             /* this function allow single channel gain only */
14513             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETDPDACT_INV_STATE,
14514                     getMykonosErrorMessage(MYKONOS_ERR_SETDPDACT_INV_STATE));
14515             return MYKONOS_ERR_SETDPDACT_INV_STATE;
14516     }
14517 
14518     extData[0] = MYKONOS_ARM_OBJECTID_TRACKING_CAL_CONTROL;
14519     extData[1] = actuatorSet;
14520     extData[2] = (uint8_t)txChannel;
14521 
14522     retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_SET_OPCODE, &extData[0], sizeof(extData));
14523     if (retVal != MYKONOS_ERR_OK)
14524     {
14525         return retVal;
14526     }
14527 
14528     /* check for completion */
14529     retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_SET_OPCODE, timeoutMs, &cmdStatusByte);
14530     if (retVal != MYKONOS_ERR_OK)
14531     {
14532         if (cmdStatusByte > 0)
14533         {
14534             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETDPDACT_ARMERRFLAG,
14535                     getMykonosErrorMessage(MYKONOS_ERR_SETDPDACT_ARMERRFLAG));
14536             return MYKONOS_ERR_SETDPDACT_ARMERRFLAG;
14537         }
14538 
14539         return retVal;
14540     }
14541 
14542     if (cmdStatusByte > 0)
14543     {
14544         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETDPDACT_ARMERRFLAG,
14545                 getMykonosErrorMessage(MYKONOS_ERR_SETDPDACT_ARMERRFLAG));
14546         return MYKONOS_ERR_SETDPDACT_ARMERRFLAG;
14547     }
14548 
14549     return MYKONOS_ERR_OK;
14550 }
14551 
14552 /**
14553  * \brief This function resets the DPD model.
14554  *
14555  *  This function allows the user to reset the DPD actuator and prior model in radioOn or radioOff mode.
14556  *  The reset can restore prior model if the parameter passed is set to 2: this resets DPD first and then restores the previously loaded
14557  *  model into ARM memory for use with subsequent iterations of DPD.
14558  *
14559  *  If reset is 1 then the reset function just reset the DPD actuator and not use any model.
14560  *
14561  * \pre A DPD-enabled transceiver is required for DPD to be enabled. DPD init cal has been run and DPD tracking enable.
14562  *
14563  * <B>Dependencies</B>
14564  * - device->spiSettings->chipSelectIndex
14565  *
14566  * \param device is structure pointer to the Mykonos data structure containing settings
14567  * \param txChannel Desired Transmit channel to be reseted (Valid ENUM values: TX1, TX2 or TX1_TX2)
14568  * \param reset is the required reset condition that is needed, the available options are given by the enum
14569  * ::mykonosDpdResetMode_t
14570  *
14571  * \retval MYKONOS_ERR_RESETDPD_INV_TXCHANNEL: Tx channel is not valid (Valid ENUM values: TX1, TX2 or TX1_TX2)
14572  * \retval MYKONOS_ERR_RESETDPD_WRONG_PARAM ERROR: reset parameter is not valid (Valid values: MYK_DPD_RESET_FULL, MYK_DPD_RESET_PRIOR or MYK_DPD_RESET_CORRELATOR)
14573  * \retval MYKONOS_ERR_RESETDPD_ARMERRFLAG ERROR: ARM command flag error set
14574  * \retval MYKONOS_ERR_OK Function completed successfully
14575  */
MYKONOS_resetDpd(mykonosDevice_t * device,mykonosTxChannels_t txChannel,mykonosDpdResetMode_t reset)14576 mykonosErr_t MYKONOS_resetDpd(mykonosDevice_t *device,  mykonosTxChannels_t txChannel, mykonosDpdResetMode_t reset)
14577 {
14578     mykonosErr_t retVal = MYKONOS_ERR_OK;
14579     uint32_t timeoutMs = 1000;
14580     uint8_t extData[3] = {0};
14581     uint8_t cmdStatusByte = 0;
14582 
14583 #if (MYKONOS_VERBOSE == 1)
14584     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_resetDpd()\n");
14585 #endif
14586 
14587     switch (txChannel)
14588     {
14589         case TX1:
14590             break;
14591         case TX2:
14592             break;
14593         case TX1_TX2:
14594             break;
14595 
14596         default:
14597             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RESETDPD_INV_TXCHANNEL,
14598                     getMykonosErrorMessage(MYKONOS_ERR_RESETDPD_INV_TXCHANNEL));
14599             return MYKONOS_ERR_RESETDPD_INV_TXCHANNEL;
14600     }
14601 
14602     if ((reset >= MYK_DPD_RESET_END) || (reset == MYK_DPD_NO_ACTION))
14603     {
14604         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RESETDPD_WRONG_PARAM,
14605                 getMykonosErrorMessage(MYKONOS_ERR_RESETDPD_WRONG_PARAM));
14606         return MYKONOS_ERR_RESETDPD_WRONG_PARAM;
14607     }
14608 
14609     /* instruct ARM to reset DPD Model */
14610     extData[0] = MYKONOS_ARM_OBJECTID_GS_TRACKCALS;
14611     extData[1] = MYKONOS_ARM_DPD_RESET;
14612     extData[2] = (uint8_t)(reset << 2) + (uint8_t)txChannel;
14613 
14614     retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_SET_OPCODE, &extData[0], sizeof(extData));
14615     if (retVal != MYKONOS_ERR_OK)
14616     {
14617         return retVal;
14618     }
14619 
14620     /* wait max of 1sec for command to complete */
14621     retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_SET_OPCODE, timeoutMs, &cmdStatusByte);
14622     if (retVal != MYKONOS_ERR_OK)
14623     {
14624         if (cmdStatusByte > 0)
14625         {
14626             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RESETDPD_ARMERRFLAG,
14627                     getMykonosErrorMessage(MYKONOS_ERR_RESETDPD_ARMERRFLAG));
14628             return MYKONOS_ERR_RESETDPD_ARMERRFLAG;
14629         }
14630         return retVal;
14631     }
14632 
14633     return MYKONOS_ERR_OK;
14634 }
14635 /**
14636  * \brief This function will configure CLGC settings
14637  *
14638  *  A DPD-enabled transceiver is required for CLGC to be enabled.  The CLGC has several user
14639  *  adjustable settings that can be configured before running the runInitCals
14640  *  with the calMask set for the CLGC init cal. Call this function with desired
14641  *  settings set before running the CLGC init cal or enabling CLGC tracking.
14642  *
14643  *  This function can be called in either Radio On or Off state.
14644  *
14645  * <B>Dependencies</B>
14646  * - device->spiSettings->chipSelectIndex
14647  * - device->profilesValid
14648  * - device->tx->clgcConfig (All members)
14649  *
14650  * \retval MYKONOS_ERR_CFGCLGC_TXORX_PROFILE_INV ERROR: Tx and ObsRx profiles must be valid to use the CLGC feature
14651  * \retval MYKONOS_ERR_CFGCLGC_NULL_CLGCCFGSTRUCT ERROR: CLGC config structure pointer is null in device->tx->clgcConfig
14652  * \retval MYKONOS_ERR_CFGCLGC_INV_DESIREDGAIN ERROR: CLGC tx1DesiredGain or tx2DesiredGain parameter is out of range
14653  * \retval MYKONOS_ERR_CFGCLGC_INV_TXATTENLIMIT ERROR: CLGC tx1AttenLimit or tx2AttenLimit parameter is out of range
14654  * \retval MYKONOS_ERR_CFGCLGC_INV_CLGC_CTRLRATIO ERROR: clgcControlRatio parameter is out of range
14655  * \retval MYKONOS_ERR_CFGCLGC_INV_THRESHOLD Error: tx1RelThreshold or tx2RelThreshold parameter is out of range
14656  * \retval MYKONOS_ERR_OK Function completed successfully
14657  */
MYKONOS_configClgc(mykonosDevice_t * device)14658 mykonosErr_t MYKONOS_configClgc(mykonosDevice_t *device)
14659 {
14660     mykonosErr_t retVal = MYKONOS_ERR_OK;
14661     uint8_t armFieldValue[4] = {0};
14662     uint8_t byteOffset = 0;
14663     uint16_t negPnLevel = 0;
14664     uint32_t radioStatus = 0x00;
14665 
14666 #if (MYKONOS_VERBOSE == 1)
14667     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_configClgc()\n");
14668 #endif
14669 
14670     /* CLGC requires Tx and ORx enabled, throw error if both are not enabled */
14671     if ((device->profilesValid & (TX_PROFILE_VALID | ORX_PROFILE_VALID)) != (TX_PROFILE_VALID | ORX_PROFILE_VALID))
14672     {
14673         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGCLGC_TXORX_PROFILE_INV,
14674                 getMykonosErrorMessage(MYKONOS_ERR_CFGCLGC_TXORX_PROFILE_INV));
14675         return MYKONOS_ERR_CFGCLGC_TXORX_PROFILE_INV;
14676     }
14677 
14678     if (device->tx->clgcConfig == NULL)
14679     {
14680         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGCLGC_NULL_CLGCCFGSTRUCT,
14681                 getMykonosErrorMessage(MYKONOS_ERR_CFGCLGC_NULL_CLGCCFGSTRUCT));
14682         return MYKONOS_ERR_CFGCLGC_NULL_CLGCCFGSTRUCT;
14683     }
14684 
14685     /* set CLGC desired gain parameter */
14686     if ((device->tx->clgcConfig->tx1DesiredGain < -10000) || (device->tx->clgcConfig->tx1DesiredGain > 10000) || (device->tx->clgcConfig->tx2DesiredGain < -10000)
14687             || (device->tx->clgcConfig->tx2DesiredGain > 10000))
14688     {
14689         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGCLGC_INV_DESIREDGAIN,
14690                 getMykonosErrorMessage(MYKONOS_ERR_CFGCLGC_INV_DESIREDGAIN));
14691         return MYKONOS_ERR_CFGCLGC_INV_DESIREDGAIN;
14692     }
14693 
14694     armFieldValue[0] = (device->tx->clgcConfig->tx1DesiredGain & 0xFF);
14695     armFieldValue[1] = (((uint16_t)device->tx->clgcConfig->tx1DesiredGain >> 8) & 0xFF);
14696     armFieldValue[2] = (device->tx->clgcConfig->tx2DesiredGain & 0xFF);
14697     armFieldValue[3] = (((uint16_t)device->tx->clgcConfig->tx2DesiredGain >> 8) & 0xFF);
14698 
14699     byteOffset = 0;
14700     retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &armFieldValue[0], sizeof(armFieldValue));
14701     if (retVal != MYKONOS_ERR_OK)
14702     {
14703         return retVal;
14704     }
14705 
14706     /* set CLGC Tx Atten limit parameter */
14707     if ((device->tx->clgcConfig->tx1AttenLimit > 40) || (device->tx->clgcConfig->tx2AttenLimit > 40))
14708     {
14709         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGCLGC_INV_TXATTENLIMIT,
14710                 getMykonosErrorMessage(MYKONOS_ERR_CFGCLGC_INV_TXATTENLIMIT));
14711         return MYKONOS_ERR_CFGCLGC_INV_TXATTENLIMIT;
14712     }
14713 
14714     armFieldValue[0] = (device->tx->clgcConfig->tx1AttenLimit & 0xFF);
14715     armFieldValue[1] = ((device->tx->clgcConfig->tx1AttenLimit >> 8) & 0xFF);
14716     armFieldValue[2] = (device->tx->clgcConfig->tx2AttenLimit & 0xFF);
14717     armFieldValue[3] = ((device->tx->clgcConfig->tx2AttenLimit >> 8) & 0xFF);
14718 
14719     byteOffset = 8;
14720     retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &armFieldValue[0], sizeof(armFieldValue));
14721     if (retVal != MYKONOS_ERR_OK)
14722     {
14723         return retVal;
14724     }
14725 
14726     /* set CLGC Control Ratio parameter */
14727     if ((device->tx->clgcConfig->tx1ControlRatio < 1) || (device->tx->clgcConfig->tx1ControlRatio > 100) || (device->tx->clgcConfig->tx2ControlRatio < 1)
14728             || (device->tx->clgcConfig->tx2ControlRatio > 100))
14729     {
14730         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGCLGC_INV_CLGC_CTRLRATIO,
14731                 getMykonosErrorMessage(MYKONOS_ERR_CFGCLGC_INV_CLGC_CTRLRATIO));
14732         return MYKONOS_ERR_CFGCLGC_INV_CLGC_CTRLRATIO;
14733     }
14734 
14735     armFieldValue[0] = (device->tx->clgcConfig->tx1ControlRatio & 0xFF);
14736     armFieldValue[1] = ((device->tx->clgcConfig->tx1ControlRatio >> 8) & 0xFF);
14737     armFieldValue[2] = (device->tx->clgcConfig->tx2ControlRatio & 0xFF);
14738     armFieldValue[3] = ((device->tx->clgcConfig->tx2ControlRatio >> 8) & 0xFF);
14739 
14740     byteOffset = 12;
14741     retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &armFieldValue[0], sizeof(armFieldValue));
14742     if (retVal != MYKONOS_ERR_OK)
14743     {
14744         return retVal;
14745     }
14746 
14747     /* set enable threshold for channel 1 */
14748     armFieldValue[0] = (device->tx->clgcConfig->tx1RelThresholdEn > 0) ? 1 : 0;
14749     byteOffset = 0x24;
14750     retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &armFieldValue[0], 1);
14751     if (retVal != MYKONOS_ERR_OK)
14752     {
14753         return retVal;
14754     }
14755 
14756     /* set enable threshold for channel 2 */
14757     armFieldValue[0] = (device->tx->clgcConfig->tx2RelThresholdEn > 0) ? 1 : 0;
14758     byteOffset = 0x26;
14759     retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &armFieldValue[0], 1);
14760     if (retVal != MYKONOS_ERR_OK)
14761     {
14762         return retVal;
14763     }
14764 
14765     /* set thresholds */
14766     if ((device->tx->clgcConfig->tx1RelThreshold > 10000) || (device->tx->clgcConfig->tx2RelThreshold > 10000))
14767     {
14768         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGCLGC_INV_THRESHOLD,
14769                 getMykonosErrorMessage(MYKONOS_ERR_CFGCLGC_INV_THRESHOLD));
14770         return MYKONOS_ERR_CFGCLGC_INV_THRESHOLD;
14771     }
14772 
14773     /* set threshold for channel 1 */
14774     armFieldValue[0] = (device->tx->clgcConfig->tx1RelThreshold & 0xFF);
14775     armFieldValue[1] = ((device->tx->clgcConfig->tx1RelThreshold >> 8) & 0xFF);
14776     byteOffset = 0x28;
14777     retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &armFieldValue[0], 2);
14778     if (retVal != MYKONOS_ERR_OK)
14779     {
14780         return retVal;
14781     }
14782 
14783     /* set threshold for channel 2 */
14784     armFieldValue[0] = (device->tx->clgcConfig->tx2RelThreshold & 0xFF);
14785     armFieldValue[1] = ((device->tx->clgcConfig->tx2RelThreshold >> 8) & 0xFF);
14786     byteOffset = 0x2A;
14787     retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &armFieldValue[0], 2);
14788     if (retVal != MYKONOS_ERR_OK)
14789     {
14790         return retVal;
14791     }
14792 
14793     if ((device->tx->clgcConfig->pathDelayPnSeqLevel < 1) || (device->tx->clgcConfig->pathDelayPnSeqLevel > 8191))
14794     {
14795         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGCLGC_INV_PNSEQLEVEL,
14796                 getMykonosErrorMessage(MYKONOS_ERR_CFGCLGC_INV_PNSEQLEVEL));
14797         return MYKONOS_ERR_CFGCLGC_INV_PNSEQLEVEL;
14798     }
14799 
14800     /* read radio state to make sure ARM is in radioOff /IDLE */
14801     retVal = MYKONOS_getRadioState(device, &radioStatus);
14802     if (retVal != MYKONOS_ERR_OK)
14803     {
14804         return retVal;
14805     }
14806 
14807     /* Radio state check */
14808     if (((radioStatus & 0x03) == MYKONOS_ARM_SYSTEMSTATE_IDLE) || ((radioStatus & 0x03) == MYKONOS_ARM_SYSTEMSTATE_READY))
14809     {
14810         /* set CLGC additional delay offset parameter (init cal)*/
14811         if ((device->tx->clgcConfig->additionalDelayOffset < -64) || (device->tx->clgcConfig->additionalDelayOffset > 64))
14812         {
14813             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGCLGC_INV_CLGC_ADDDELAY,
14814                     getMykonosErrorMessage(MYKONOS_ERR_CFGCLGC_INV_CLGC_ADDDELAY));
14815             return MYKONOS_ERR_CFGCLGC_INV_CLGC_ADDDELAY;
14816         }
14817 
14818         armFieldValue[0] = (device->tx->clgcConfig->additionalDelayOffset & 0xFF);
14819         armFieldValue[1] = (((uint16_t)device->tx->clgcConfig->additionalDelayOffset >> 8) & 0xFF);
14820         byteOffset = 2;
14821         retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCINIT_CONFIG, byteOffset, &armFieldValue[0], 2);
14822         if (retVal != MYKONOS_ERR_OK)
14823         {
14824             return retVal;
14825         }
14826 
14827         if ((device->tx->clgcConfig->pathDelayPnSeqLevel < 1) || (device->tx->clgcConfig->pathDelayPnSeqLevel > 8191))
14828         {
14829             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGCLGC_INV_PNSEQLEVEL,
14830                     getMykonosErrorMessage(MYKONOS_ERR_CFGCLGC_INV_PNSEQLEVEL));
14831             return MYKONOS_ERR_CFGCLGC_INV_PNSEQLEVEL;
14832         }
14833 
14834         /* Can not be changed in radio on */
14835         /* Set Path Delay PN sequence amplitude - positive and negative (init cal)*/
14836         armFieldValue[0] = (device->tx->clgcConfig->pathDelayPnSeqLevel & 0xFF);
14837         armFieldValue[1] = ((device->tx->clgcConfig->pathDelayPnSeqLevel >> 8) & 0xFF);
14838 
14839         negPnLevel = ((~device->tx->clgcConfig->pathDelayPnSeqLevel) + 1); /* times -1 */
14840         armFieldValue[2] = (negPnLevel & 0xFF);
14841         armFieldValue[3] = (((negPnLevel) >> 8) & 0xFF);
14842         byteOffset = 10;
14843         retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCINIT_CONFIG, byteOffset, &armFieldValue[0], sizeof(armFieldValue));
14844         if (retVal != MYKONOS_ERR_OK)
14845         {
14846             return retVal;
14847         }
14848 
14849         retVal = enableClgcTracking(device, ((device->tx->clgcConfig->allowTx1AttenUpdates > 0) ? 1 : 0), ((device->tx->clgcConfig->allowTx2AttenUpdates > 0) ? 1 : 0));
14850         if (retVal != MYKONOS_ERR_OK)
14851         {
14852             return retVal;
14853         }
14854     }
14855     else
14856     {
14857         /* record warning about not updated members */
14858         CMB_writeToLog(ADIHAL_LOG_WARNING, device->spiSettings->chipSelectIndex, MYKONOS_WRN_RADIO_ON_NOT_MODIFIABLE,
14859                            getMykonosErrorMessage(MYKONOS_WRN_RADIO_ON_NOT_MODIFIABLE));
14860     }
14861 
14862     return MYKONOS_ERR_OK;
14863 }
14864 
14865 /* \brief Reads the CLGC config structure from ARM memory
14866  *
14867  *  This function reads the Closed Loop Gain Control structure
14868  *  from ARM memory and returns in the device->tx->clgcConfig structure.
14869  *
14870  *  A DPD-enabled transceiver is required for CLGC to be enabled.
14871  *
14872  * <B>Dependencies</B>
14873  * - device->spiSettings->chipSelectIndex
14874  * - device->profilesValid
14875  * - device->tx->clgcConfig (All members)
14876  *
14877  * \param device is structure pointer to the Mykonos data structure containing settings
14878  *
14879  * \retval MYKONOS_ERR_OK Function completed successfully
14880  * \retval MYKONOS_ERR_GETCLGCCFG_TXORX_PROFILE_INV Error: Tx and ORx profiles must be valid for CLGC functions
14881  * \retval MYKONOS_ERR_GETCLGCCFG_NULL_CFGSTRUCT Error: NULL pointer to device->tx->clgcConfig structure
14882  */
MYKONOS_getClgcConfig(mykonosDevice_t * device)14883 mykonosErr_t MYKONOS_getClgcConfig(mykonosDevice_t *device)
14884 {
14885     uint16_t byteOffset = 0;
14886     uint8_t armMem[16] = {0};
14887     mykonosErr_t retVal = MYKONOS_ERR_OK;
14888 
14889 #if (MYKONOS_VERBOSE == 1)
14890     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getClgcConfig()\n");
14891 #endif
14892 
14893     /* CLGC requires Tx and ORx enabled, throw error if both are not enabled */
14894     if ((device->profilesValid & (TX_PROFILE_VALID | ORX_PROFILE_VALID)) != (TX_PROFILE_VALID | ORX_PROFILE_VALID))
14895     {
14896         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETCLGCCFG_TXORX_PROFILE_INV,
14897                 getMykonosErrorMessage(MYKONOS_ERR_GETCLGCCFG_TXORX_PROFILE_INV));
14898         return MYKONOS_ERR_GETCLGCCFG_TXORX_PROFILE_INV;
14899     }
14900 
14901     if (device->tx->clgcConfig == NULL)
14902     {
14903         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETCLGCCFG_NULL_CFGSTRUCT,
14904                 getMykonosErrorMessage(MYKONOS_ERR_GETCLGCCFG_NULL_CFGSTRUCT));
14905         return MYKONOS_ERR_GETCLGCCFG_NULL_CFGSTRUCT;
14906     }
14907 
14908     byteOffset = 0;
14909     retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &armMem[0], sizeof(armMem));
14910     if (retVal != MYKONOS_ERR_OK)
14911     {
14912         return retVal;
14913     }
14914 
14915     device->tx->clgcConfig->tx1DesiredGain = (int16_t)(((uint16_t)(armMem[1]) << 8) | (uint16_t)(armMem[0]));
14916     device->tx->clgcConfig->tx2DesiredGain = (int16_t)(((uint16_t)(armMem[3]) << 8) | (uint16_t)(armMem[2]));
14917     device->tx->clgcConfig->tx1AttenLimit = (((uint16_t)(armMem[9]) << 8) | (uint16_t)(armMem[8]));
14918     device->tx->clgcConfig->tx2AttenLimit = (((uint16_t)(armMem[11]) << 8) | (uint16_t)(armMem[10]));
14919     device->tx->clgcConfig->tx1ControlRatio = (((uint16_t)(armMem[13]) << 8) | (uint16_t)(armMem[12]));
14920     device->tx->clgcConfig->tx2ControlRatio = (((uint16_t)(armMem[15]) << 8) | (uint16_t)(armMem[14]));
14921 
14922     byteOffset = 2;
14923     retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCINIT_CONFIG, byteOffset, &armMem[0], 2);
14924     if (retVal != MYKONOS_ERR_OK)
14925     {
14926         return retVal;
14927     }
14928 
14929     device->tx->clgcConfig->additionalDelayOffset = (int16_t)(((uint16_t)(armMem[1]) << 8) | (uint16_t)(armMem[0]));
14930 
14931     byteOffset = 10;
14932     retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCINIT_CONFIG, byteOffset, &armMem[0], 2);
14933     if (retVal != MYKONOS_ERR_OK)
14934     {
14935         return retVal;
14936     }
14937 
14938     device->tx->clgcConfig->pathDelayPnSeqLevel = (((uint16_t)(armMem[1]) << 8) | (uint16_t)(armMem[0]));
14939 
14940     /* need to figure out if this are the right addresses */
14941     byteOffset = 0x24;
14942     retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &armMem[0], 1);
14943     if (retVal != MYKONOS_ERR_OK)
14944     {
14945         return retVal;
14946     }
14947 
14948     device->tx->clgcConfig->tx1RelThresholdEn = (uint8_t)armMem[0];
14949 
14950     byteOffset = 0x26;
14951     retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &armMem[0], 1);
14952     if (retVal != MYKONOS_ERR_OK)
14953     {
14954         return retVal;
14955     }
14956 
14957     device->tx->clgcConfig->tx2RelThresholdEn = (uint8_t)armMem[0];
14958 
14959     byteOffset = 0x28;
14960     retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &armMem[0], 2);
14961     if (retVal != MYKONOS_ERR_OK)
14962     {
14963         return retVal;
14964     }
14965 
14966     device->tx->clgcConfig->tx1RelThreshold = (((uint16_t)(armMem[1]) << 8) | (uint16_t)(armMem[0]));
14967 
14968     byteOffset = 0x2A;
14969     retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &armMem[0], 2);
14970     if (retVal != MYKONOS_ERR_OK)
14971     {
14972         return retVal;
14973     }
14974 
14975     device->tx->clgcConfig->tx2RelThreshold = (((uint16_t)(armMem[1]) << 8) | (uint16_t)(armMem[0]));
14976 
14977     return MYKONOS_ERR_OK;
14978 }
14979 
14980 /**
14981  * \brief This function reads the CLGC calibration status from the Mykonos ARM processor.
14982  *
14983  * The Closed Loop Gain Control Status is read back from the ARM processor and
14984  * returned in the function parameter clgcStatus.
14985  *
14986  * A DPD-enabled transceiver is required for this feature to be enabled.
14987  *
14988  * <B>Dependencies</B>
14989  * - device->spiSettings->chipSelectIndex
14990  *
14991  * \param device is structure pointer to the Mykonos data structure containing settings
14992  * \param txChannel Desired Transmit channel to read back CLGC status for (Valid ENUM values: TX1 or TX2 only)
14993  * \param clgcStatus Pointer to a structure to return the status information to
14994  *
14995  * \retval MYKONOS_ERR_OK Function completed successfully
14996  * \retval MYKONOS_ERR_GETCLGCSTATUS_NULLPARAM clgcStatus function parameter is a NULL pointer
14997  * \retval MYKONOS_ERR_GETCLGCSTATUS_INV_CH txChannel parameter is a non supported value.
14998  * \retval MYKONOS_ERR_GETCLGCSTATUS_ARMERRFLAG ARM reported an error while processing the GET ARM command
14999  */
MYKONOS_getClgcStatus(mykonosDevice_t * device,mykonosTxChannels_t txChannel,mykonosClgcStatus_t * clgcStatus)15000 mykonosErr_t MYKONOS_getClgcStatus(mykonosDevice_t *device, mykonosTxChannels_t txChannel, mykonosClgcStatus_t *clgcStatus)
15001 {
15002     uint8_t extData[3] = {MYKONOS_ARM_OBJECTID_CAL_STATUS, MYKONOS_ARM_OBJECTID_CLGCCONFIG, 0};
15003     uint8_t armData[52] = {0};
15004     uint32_t timeoutMs = 0;
15005     uint8_t cmdStatusByte = 0;
15006     uint32_t offset = 0;
15007     mykonosErr_t retVal = MYKONOS_ERR_OK;
15008     uint8_t channelSelect = 0;
15009 
15010 #if (MYKONOS_VERBOSE == 1)
15011     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getClgcStatus()\n");
15012 #endif
15013 
15014     if (clgcStatus == NULL)
15015     {
15016         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETCLGCSTATUS_NULLPARAM,
15017                 getMykonosErrorMessage(MYKONOS_ERR_GETCLGCSTATUS_NULLPARAM));
15018         return MYKONOS_ERR_GETCLGCSTATUS_NULLPARAM;
15019     }
15020 
15021     switch (txChannel)
15022     {
15023         case TX1:
15024             channelSelect = 0;
15025             break;
15026         case TX2:
15027             channelSelect = 1;
15028             break;
15029         default:
15030         {
15031             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETCLGCSTATUS_INV_CH,
15032                     getMykonosErrorMessage(MYKONOS_ERR_GETCLGCSTATUS_INV_CH));
15033             return MYKONOS_ERR_GETCLGCSTATUS_INV_CH;
15034         }
15035     }
15036 
15037     extData[2] = channelSelect;
15038 
15039     retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &extData[0], sizeof(extData));
15040     if (retVal != MYKONOS_ERR_OK)
15041     {
15042         return retVal;
15043     }
15044 
15045     timeoutMs = 1000;
15046     retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte);
15047     if (retVal != MYKONOS_ERR_OK)
15048     {
15049         if (cmdStatusByte > 0)
15050         {
15051             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETCLGCSTATUS_ARMERRFLAG,
15052                     getMykonosErrorMessage(MYKONOS_ERR_GETCLGCSTATUS_ARMERRFLAG));
15053             return MYKONOS_ERR_GETCLGCSTATUS_ARMERRFLAG;
15054         }
15055 
15056         return retVal;
15057     }
15058 
15059     if (cmdStatusByte > 0)
15060     {
15061         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETCLGCSTATUS_ARMERRFLAG,
15062                 getMykonosErrorMessage(MYKONOS_ERR_GETCLGCSTATUS_ARMERRFLAG));
15063         return MYKONOS_ERR_GETCLGCSTATUS_ARMERRFLAG;
15064     }
15065 
15066     /* read status from ARM memory */
15067     offset = 0;
15068     retVal = MYKONOS_readArmMem(device, (MYKONOS_ADDR_ARM_START_DATA_ADDR + offset), &armData[0], sizeof(armData), 1);
15069     if (retVal != MYKONOS_ERR_OK)
15070     {
15071         return retVal;
15072     }
15073 
15074     clgcStatus->errorStatus = ((uint32_t)(armData[3]) << 24) | ((uint32_t)(armData[2]) << 16) | ((uint32_t)(armData[1]) << 8) | (uint32_t)(armData[0]);
15075     clgcStatus->desiredGain = (int32_t)(((uint32_t)(armData[23]) << 24) | ((uint32_t)(armData[22]) << 16) | ((uint32_t)(armData[21]) << 8) | (uint32_t)(armData[20]));
15076     clgcStatus->currentGain = (int32_t)(((uint32_t)(armData[27]) << 24) | ((uint32_t)(armData[26]) << 16) | ((uint32_t)(armData[25]) << 8) | (uint32_t)(armData[24]));
15077     clgcStatus->txGain = ((uint32_t)(armData[39]) << 24) | ((uint32_t)(armData[38]) << 16) | ((uint32_t)(armData[37]) << 8) | (uint32_t)(armData[36]);
15078     clgcStatus->txRms = (int32_t)(((uint32_t)(armData[43]) << 24) | ((uint32_t)(armData[42]) << 16) | ((uint32_t)(armData[41]) << 8) | (uint32_t)(armData[40]));
15079     clgcStatus->orxRms = (int32_t)(((uint32_t)(armData[47]) << 24) | ((uint32_t)(armData[46]) << 16) | ((uint32_t)(armData[45]) << 8) | (uint32_t)(armData[44]));
15080     clgcStatus->trackCount = ((uint32_t)(armData[51]) << 24) | ((uint32_t)(armData[50]) << 16) | ((uint32_t)(armData[49]) << 8) | (uint32_t)(armData[48]);
15081 
15082     return retVal;
15083 }
15084 
15085 /**
15086  * \brief This private helper function called during RadioOff, will allow CLGC tracking to be scheduled
15087  *        by the ARM when back in the RadioOn state.
15088  *
15089  *  This function sets a flag in the ARM memory that if the enableDpd tracking cal mask
15090  *  and this setting are both set, then the ARM will schedule closed loop gain control
15091  *  tracking to occur in the radioOn ARM state.
15092  *
15093  *  A DPD-enabled transceiver is required for this feature to be enabled.
15094  *
15095  * <B>Dependencies</B>
15096  * - device->spiSettings->chipSelectIndex
15097  * - device->tx->dpdConfig
15098  *
15099  * \param device is structure pointer to the Mykonos data structure containing settings
15100  * \param tx1Enable 0=disable CLGC Tx1 tracking, 1= enable CLGC Tx1 tracking
15101  * \param tx2Enable 0=disable CLGC Tx2 tracking, 1= enable CLGC Tx2 tracking
15102  *
15103  * \retval MYKONOS_ERR_OK Function completed successfully
15104  * \retval MYKONOS_ERR_EN_CLGCTRACKING_ARMSTATE_ERROR ARM is not in the RadioOff state, call MYKONOS_radioOff()
15105  */
enableClgcTracking(mykonosDevice_t * device,uint8_t tx1Enable,uint8_t tx2Enable)15106 static mykonosErr_t enableClgcTracking(mykonosDevice_t *device, uint8_t tx1Enable, uint8_t tx2Enable)
15107 {
15108     uint32_t radioStatus = 0;
15109     mykonosErr_t retVal = MYKONOS_ERR_OK;
15110     uint8_t enableBit[4] = {0};
15111     uint8_t byteOffset = 4;
15112 
15113 #if (MYKONOS_VERBOSE == 1)
15114     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_enableClgcTracking()\n");
15115 #endif
15116 
15117     /* read radio state to make sure ARM is in radioOff /IDLE */
15118     retVal = MYKONOS_getRadioState(device, &radioStatus);
15119     if (retVal != MYKONOS_ERR_OK)
15120     {
15121         return retVal;
15122     }
15123 
15124     /* throw error if not in radioOff/IDLE state */
15125     if (((radioStatus & 0x03) != MYKONOS_ARM_SYSTEMSTATE_IDLE) && ((radioStatus & 0x03) != MYKONOS_ARM_SYSTEMSTATE_READY))
15126     {
15127         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_EN_CLGCTRACKING_ARMSTATE_ERROR,
15128                 getMykonosErrorMessage(MYKONOS_ERR_EN_CLGCTRACKING_ARMSTATE_ERROR));
15129         return MYKONOS_ERR_EN_CLGCTRACKING_ARMSTATE_ERROR;
15130     }
15131 
15132     enableBit[0] = (tx1Enable > 0) ? 1 : 0;
15133     enableBit[1] = 0;
15134     enableBit[2] = (tx2Enable > 0) ? 1 : 0;
15135     enableBit[3] = 0;
15136 
15137     retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &enableBit[0], 4);
15138     if (retVal != MYKONOS_ERR_OK)
15139     {
15140         return retVal;
15141     }
15142 
15143     return MYKONOS_ERR_OK;
15144 }
15145 
15146 /**
15147  * \brief This function updates the CLGC desired gain parameter.
15148  *
15149  *  This function can be called in either Radio On or Off state.
15150  *
15151  * \pre A DPD-enabled transceiver is required for CLGC to be enabled. CLGC init cal has been run and CLGC tracking enable.
15152  *
15153  * <B>Dependencies</B>
15154  * - device->spiSettings->chipSelectIndex
15155  *
15156  * \param device is structure pointer to the Mykonos data structure containing settings
15157  *  \param txChannel Desired Transmit channel to set the (Valid ENUM values: TX1 or TX2 only)
15158  * \param gain Total gain and attenuation (dB * 100) for the selected channel txChannel
15159  *
15160  * \retval MYKONOS_ERR_SETCLGCGAIN_INV_TXCHANNEL ERROR: Tx channel is not valid (Valid ENUM values: TX1 or TX2 only)
15161  * \retval MYKONOS_ERR_SETCLGCGAIN_TRACK_ARMERRFLAG ERROR: ARM command flag error set
15162  * \retval MYKONOS_ERR_SETCLGCGAIN_INV_DESIREDGAIN ERROR: CLGC gain parameter is out of range, valid range is from -10000 to 10000.
15163  * \retval MYKONOS_ERR_OK Function completed successfully
15164  */
MYKONOS_setClgcGain(mykonosDevice_t * device,mykonosTxChannels_t txChannel,int16_t gain)15165 mykonosErr_t MYKONOS_setClgcGain(mykonosDevice_t *device, mykonosTxChannels_t txChannel, int16_t gain)
15166 {
15167     mykonosErr_t retVal = MYKONOS_ERR_OK;
15168     uint32_t timeoutMs = 1000;
15169     uint8_t extData[4] = {0};
15170     uint8_t clcgChannel = 0x00;
15171     uint8_t cmdStatusByte = 0;
15172 
15173 #if (MYKONOS_VERBOSE == 1)
15174     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setClgcGain()\n");
15175 #endif
15176 
15177     /* Range check for desired gain parameter */
15178     if ((gain < -10000) || (gain > 10000))
15179     {
15180         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETCLGCGAIN_INV_DESIREDGAIN,
15181                 getMykonosErrorMessage(MYKONOS_ERR_SETCLGCGAIN_INV_DESIREDGAIN));
15182         return MYKONOS_ERR_SETCLGCGAIN_INV_DESIREDGAIN;
15183     }
15184 
15185     switch (txChannel)
15186     {
15187         case TX1:
15188             clcgChannel = SET_CLGC_DESIRED_GAIN_1;
15189             break;
15190         case TX2:
15191             clcgChannel = SET_CLGC_DESIRED_GAIN_2;
15192             break;
15193 
15194         default:
15195             /* this function allow single channel gain only */
15196             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETCLGCGAIN_INV_TXCHANNEL,
15197                     getMykonosErrorMessage(MYKONOS_ERR_SETCLGCGAIN_INV_TXCHANNEL));
15198             return MYKONOS_ERR_SETCLGCGAIN_INV_TXCHANNEL;
15199     }
15200 
15201     extData[0] = MYKONOS_ARM_OBJECTID_TRACKING_CAL_CONTROL;
15202     extData[1] = clcgChannel;
15203     extData[2] = (gain & 0xFF);
15204     extData[3] = (((uint16_t)gain >> 8) & 0xFF);
15205 
15206     retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_SET_OPCODE, &extData[0], sizeof(extData));
15207     if (retVal != MYKONOS_ERR_OK)
15208     {
15209         return retVal;
15210     }
15211 
15212     /* check for completion */
15213     retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_SET_OPCODE, timeoutMs, &cmdStatusByte);
15214     if (retVal != MYKONOS_ERR_OK)
15215     {
15216         if (cmdStatusByte > 0)
15217         {
15218             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETCLGCGAIN_TRACK_ARMERRFLAG,
15219                     getMykonosErrorMessage(MYKONOS_ERR_SETCLGCGAIN_TRACK_ARMERRFLAG));
15220             return MYKONOS_ERR_SETCLGCGAIN_TRACK_ARMERRFLAG;
15221         }
15222 
15223         return retVal;
15224     }
15225 
15226     if (cmdStatusByte > 0)
15227     {
15228         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETCLGCGAIN_TRACK_ARMERRFLAG,
15229                 getMykonosErrorMessage(MYKONOS_ERR_SETCLGCGAIN_TRACK_ARMERRFLAG));
15230         return MYKONOS_ERR_SETCLGCGAIN_TRACK_ARMERRFLAG;
15231     }
15232 
15233     return MYKONOS_ERR_OK;
15234 }
15235 
15236 /**
15237  * \brief This function, when called during RadioOff, will configure VSWR settings
15238  *
15239  *  A DPD-enabled transceiver is required for VSWR to be enabled.  The VSWR has several user
15240  *  adjustable settings that can be configured before running the runInitCals
15241  *  with the calMask set for the VSWR init cal. Call this function with desired
15242  *  settings set before running the VSWR init cal or enabling VSWR tracking.
15243  *
15244  * <B>Dependencies</B>
15245  * - device->spiSettings->chipSelectIndex
15246  * - device->profilesValid
15247  * - device->tx->vswrConfig (All members)
15248  *
15249  * \retval MYKONOS_ERR_CFGVSWR_TXORX_PROFILE_INV ERROR: Tx and ObsRx profiles must be valid to use the VSWR feature
15250  * \retval MYKONOS_ERR_CFGVSWR_NULL_VSWRCFGSTRUCT ERROR: CLGC config structure pointer is null in device->tx->clgcConfig
15251  * \retval MYKONOS_ERR_CFGVSWR_ARMSTATE_ERROR ERROR: ARM is not in the IDLE(radioOff) or Ready state.
15252  */
MYKONOS_configVswr(mykonosDevice_t * device)15253 mykonosErr_t MYKONOS_configVswr(mykonosDevice_t *device)
15254 {
15255     uint32_t radioStatus = 0;
15256     mykonosErr_t retVal = MYKONOS_ERR_OK;
15257     uint8_t armFieldValue[16] = {0};
15258     uint8_t byteOffset = 0;
15259     uint16_t negPnLevel = 0;
15260 
15261     const uint8_t ENABLE_VSWR = 1;
15262 
15263 #if (MYKONOS_VERBOSE == 1)
15264     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_configVswr()\n");
15265 #endif
15266 
15267     /* VSWR requires Tx and ORx enabled, throw error if both are not enabled */
15268     if ((device->profilesValid & (TX_PROFILE_VALID | ORX_PROFILE_VALID)) != (TX_PROFILE_VALID | ORX_PROFILE_VALID))
15269     {
15270         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGVSWR_TXORX_PROFILE_INV,
15271                 getMykonosErrorMessage(MYKONOS_ERR_CFGVSWR_TXORX_PROFILE_INV));
15272         return MYKONOS_ERR_CFGVSWR_TXORX_PROFILE_INV;
15273     }
15274 
15275     if (device->tx->vswrConfig == NULL)
15276     {
15277         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGVSWR_NULL_VSWRCFGSTRUCT,
15278                 getMykonosErrorMessage(MYKONOS_ERR_CFGVSWR_NULL_VSWRCFGSTRUCT));
15279         return MYKONOS_ERR_CFGVSWR_NULL_VSWRCFGSTRUCT;
15280     }
15281 
15282     /* read radio state to make sure ARM is in radioOff /IDLE */
15283     retVal = MYKONOS_getRadioState(device, &radioStatus);
15284     if (retVal != MYKONOS_ERR_OK)
15285     {
15286         return retVal;
15287     }
15288 
15289     /* throw error if not in radioOff/IDLE state */
15290     if (((radioStatus & 0x03) != MYKONOS_ARM_SYSTEMSTATE_IDLE) && ((radioStatus & 0x03) != MYKONOS_ARM_SYSTEMSTATE_READY))
15291     {
15292         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGVSWR_ARMSTATE_ERROR,
15293                 getMykonosErrorMessage(MYKONOS_ERR_CFGVSWR_ARMSTATE_ERROR));
15294         return MYKONOS_ERR_CFGVSWR_ARMSTATE_ERROR;
15295     }
15296 
15297     /* range check valid 3p3 GPIO pin */
15298     if ((device->tx->vswrConfig->tx1VswrSwitchGpio3p3Pin > 11) || (device->tx->vswrConfig->tx2VswrSwitchGpio3p3Pin > 11))
15299     {
15300         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGVSWR_INV_3P3GPIOPIN,
15301                 getMykonosErrorMessage(MYKONOS_ERR_CFGVSWR_INV_3P3GPIOPIN));
15302         return MYKONOS_ERR_CFGVSWR_INV_3P3GPIOPIN;
15303     }
15304 
15305     armFieldValue[0] = ENABLE_VSWR;
15306     armFieldValue[1] = 0;
15307     armFieldValue[2] = ENABLE_VSWR;
15308     armFieldValue[3] = 0;
15309     armFieldValue[4] = (device->tx->vswrConfig->tx1VswrSwitchGpio3p3Pin & 0xFF);
15310     armFieldValue[5] = 0;
15311     armFieldValue[6] = (device->tx->vswrConfig->tx2VswrSwitchGpio3p3Pin & 0xFF);
15312     armFieldValue[7] = 0;
15313     armFieldValue[8] = (device->tx->vswrConfig->tx1VswrSwitchPolarity > 0) ? 1 : 0;
15314     armFieldValue[9] = 0;
15315     armFieldValue[10] = (device->tx->vswrConfig->tx2VswrSwitchPolarity > 0) ? 1 : 0;
15316     armFieldValue[11] = 0;
15317     armFieldValue[12] = device->tx->vswrConfig->tx1VswrSwitchDelay_us; /* support full 0 to 255 us range */
15318     armFieldValue[13] = 0;
15319     armFieldValue[14] = device->tx->vswrConfig->tx2VswrSwitchDelay_us; /* support full 0 to 255 us range */
15320     armFieldValue[15] = 0;
15321     byteOffset = 0;
15322     retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_VSWRCONFIG, byteOffset, &armFieldValue[0], 16);
15323     if (retVal != MYKONOS_ERR_OK)
15324     {
15325         return retVal;
15326     }
15327 
15328     /* set VSWR additional delay offset parameter (init cal)*/
15329     if ((device->tx->vswrConfig->additionalDelayOffset < -64) || (device->tx->vswrConfig->additionalDelayOffset > 64))
15330     {
15331         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGVSWR_INV_VSWR_ADDDELAY,
15332                 getMykonosErrorMessage(MYKONOS_ERR_CFGVSWR_INV_VSWR_ADDDELAY));
15333         return MYKONOS_ERR_CFGVSWR_INV_VSWR_ADDDELAY;
15334     }
15335 
15336     armFieldValue[0] = (device->tx->vswrConfig->additionalDelayOffset & 0xFF);
15337     armFieldValue[1] = (((uint16_t)device->tx->vswrConfig->additionalDelayOffset >> 8) & 0xFF);
15338     byteOffset = 2;
15339     retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_VSWRINIT_CONFIG, byteOffset, &armFieldValue[0], 2);
15340     if (retVal != MYKONOS_ERR_OK)
15341     {
15342         return retVal;
15343     }
15344 
15345     if ((device->tx->vswrConfig->pathDelayPnSeqLevel < 1) || (device->tx->vswrConfig->pathDelayPnSeqLevel > 8191))
15346     {
15347         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGVSWR_INV_PNSEQLEVEL,
15348                 getMykonosErrorMessage(MYKONOS_ERR_CFGVSWR_INV_PNSEQLEVEL));
15349         return MYKONOS_ERR_CFGVSWR_INV_PNSEQLEVEL;
15350     }
15351 
15352     /* Set Path Delay PN sequence amplitude - positive and negative (init cal)*/
15353     armFieldValue[0] = (device->tx->vswrConfig->pathDelayPnSeqLevel & 0xFF);
15354     armFieldValue[1] = ((device->tx->vswrConfig->pathDelayPnSeqLevel >> 8) & 0xFF);
15355 
15356     negPnLevel = ((~device->tx->vswrConfig->pathDelayPnSeqLevel) + 1); /* times -1 */
15357     armFieldValue[2] = (negPnLevel & 0xFF);
15358     armFieldValue[3] = (((negPnLevel) >> 8) & 0xFF);
15359     byteOffset = 10;
15360 
15361     /* Set for Tx1 channel */
15362     retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_VSWRINIT_CONFIG, byteOffset, &armFieldValue[0], 4);
15363     if (retVal != MYKONOS_ERR_OK)
15364     {
15365         return retVal;
15366     }
15367 
15368     /* Set for Tx2 channel */
15369     byteOffset = 30;
15370     retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_VSWRINIT_CONFIG, byteOffset, &armFieldValue[0], 4);
15371     if (retVal != MYKONOS_ERR_OK)
15372     {
15373         return retVal;
15374     }
15375 
15376     return MYKONOS_ERR_OK;
15377 }
15378 
15379 /* \brief Reads the VSWR config structure from ARM memory
15380  *
15381  *  This function reads the VSWR structure
15382  *  from ARM memory and returns in the device->tx->vswrConfig structure.
15383  *
15384  *  A DPD-enabled transceiver is required for VSWR to be enabled.
15385  *
15386  * <B>Dependencies</B>
15387  * - device->spiSettings->chipSelectIndex
15388  * - device->profilesValid
15389  * - device->tx->vswrConfig (All members)
15390  *
15391  * \param device is structure pointer to the Mykonos data structure containing settings
15392  *
15393  * \retval MYKONOS_ERR_OK Function completed successfully
15394  * \retval MYKONOS_ERR_GETVSWRCFG_TXORX_PROFILE_INV Error: Tx and ORx profiles must be valid for VSWR functions
15395  * \retval MYKONOS_ERR_GETVSWRCFG_NULL_CFGSTRUCT Error: NULL pointer to device->tx->vswrConfig structure
15396  */
MYKONOS_getVswrConfig(mykonosDevice_t * device)15397 mykonosErr_t MYKONOS_getVswrConfig(mykonosDevice_t *device)
15398 {
15399     uint16_t byteOffset = 0;
15400     uint8_t armMem[12] = {0};
15401     mykonosErr_t retVal = MYKONOS_ERR_OK;
15402 
15403 #if (MYKONOS_VERBOSE == 1)
15404     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getVswrConfig()\n");
15405 #endif
15406 
15407     /* VSWR requires Tx and ORx enabled, throw error if both are not enabled */
15408     if ((device->profilesValid & (TX_PROFILE_VALID | ORX_PROFILE_VALID)) != (TX_PROFILE_VALID | ORX_PROFILE_VALID))
15409     {
15410         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETVSWRCFG_TXORX_PROFILE_INV,
15411                 getMykonosErrorMessage(MYKONOS_ERR_GETVSWRCFG_TXORX_PROFILE_INV));
15412         return MYKONOS_ERR_GETVSWRCFG_TXORX_PROFILE_INV;
15413     }
15414 
15415     if (device->tx->vswrConfig == NULL)
15416     {
15417         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETVSWRCFG_NULL_CFGSTRUCT,
15418                 getMykonosErrorMessage(MYKONOS_ERR_GETVSWRCFG_NULL_CFGSTRUCT));
15419         return MYKONOS_ERR_GETVSWRCFG_NULL_CFGSTRUCT;
15420     }
15421 
15422     byteOffset = 4;
15423     retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_VSWRCONFIG, byteOffset, &armMem[0], sizeof(armMem));
15424     if (retVal != MYKONOS_ERR_OK)
15425     {
15426         return retVal;
15427     }
15428 
15429     device->tx->vswrConfig->tx1VswrSwitchGpio3p3Pin = armMem[0];
15430     device->tx->vswrConfig->tx2VswrSwitchGpio3p3Pin = armMem[2];
15431     device->tx->vswrConfig->tx1VswrSwitchPolarity = armMem[4];
15432     device->tx->vswrConfig->tx2VswrSwitchPolarity = armMem[6];
15433     device->tx->vswrConfig->tx1VswrSwitchDelay_us = armMem[8];
15434     device->tx->vswrConfig->tx2VswrSwitchDelay_us = armMem[10];
15435 
15436     byteOffset = 2;
15437     retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_VSWRINIT_CONFIG, byteOffset, &armMem[0], 2);
15438     if (retVal != MYKONOS_ERR_OK)
15439     {
15440         return retVal;
15441     }
15442 
15443     device->tx->vswrConfig->additionalDelayOffset = (int16_t)(((uint16_t)(armMem[1]) << 8) | (uint16_t)(armMem[0]));
15444 
15445     byteOffset = 10;
15446     retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_VSWRINIT_CONFIG, byteOffset, &armMem[0], 2);
15447     if (retVal != MYKONOS_ERR_OK)
15448     {
15449         return retVal;
15450     }
15451 
15452     device->tx->vswrConfig->pathDelayPnSeqLevel = (((uint16_t)(armMem[1]) << 8) | (uint16_t)(armMem[0]));
15453 
15454     return MYKONOS_ERR_OK;
15455 }
15456 
15457 /**
15458  * \brief This function reads the VSWR calibration status from the Mykonos ARM processor.
15459  *
15460  * The VSWR Status is read back from the ARM processor and
15461  * returned in the function parameter vswrStatus.
15462  *
15463  * A DPD-enabled transceiver is required for this feature to be enabled.
15464  *
15465  * <B>Dependencies</B>
15466  * - device->spiSettings->chipSelectIndex
15467  *
15468  * \param device is structure pointer to the Mykonos data structure containing settings
15469  * \param txChannel Desired Transmit channel to read back VSWR status for (Valid ENUM values: TX1 or TX2 only)
15470  * \param vswrStatus Pointer to a structure to return the status information to
15471  *
15472  * \retval MYKONOS_ERR_OK Function completed successfully
15473  * \retval MYKONOS_ERR_GETVSWRSTATUS_NULLPARAM vswrStatus function parameter is a NULL pointer
15474  * \retval MYKONOS_ERR_GETVSWRSTATUS_INV_CH txChannel parameter is a non supported value.
15475  * \retval MYKONOS_ERR_GETVSWRSTATUS_ARMERRFLAG ARM reported an error while processing the GET ARM command
15476  */
MYKONOS_getVswrStatus(mykonosDevice_t * device,mykonosTxChannels_t txChannel,mykonosVswrStatus_t * vswrStatus)15477 mykonosErr_t MYKONOS_getVswrStatus(mykonosDevice_t *device, mykonosTxChannels_t txChannel, mykonosVswrStatus_t *vswrStatus)
15478 {
15479     uint8_t extData[3] = {MYKONOS_ARM_OBJECTID_CAL_STATUS, MYKONOS_ARM_OBJECTID_VSWRCONFIG, 0};
15480     uint8_t armData[64] = {0};
15481     uint32_t timeoutMs = 0;
15482     uint8_t cmdStatusByte = 0;
15483     uint32_t offset = 0;
15484     mykonosErr_t retVal = MYKONOS_ERR_OK;
15485     uint8_t channelSelect = 0;
15486 
15487 #if (MYKONOS_VERBOSE == 1)
15488     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getVswrStatus()\n");
15489 #endif
15490 
15491     if (vswrStatus == NULL)
15492     {
15493         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETVSWRSTATUS_NULLPARAM,
15494                 getMykonosErrorMessage(MYKONOS_ERR_GETVSWRSTATUS_NULLPARAM));
15495         return MYKONOS_ERR_GETVSWRSTATUS_NULLPARAM;
15496     }
15497 
15498     switch (txChannel)
15499     {
15500         case TX1:
15501             channelSelect = 0;
15502             break;
15503         case TX2:
15504             channelSelect = 1;
15505             break;
15506         default:
15507         {
15508             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETVSWRSTATUS_INV_CH,
15509                     getMykonosErrorMessage(MYKONOS_ERR_GETVSWRSTATUS_INV_CH));
15510             return MYKONOS_ERR_GETVSWRSTATUS_INV_CH;
15511         }
15512     }
15513 
15514     extData[2] = channelSelect;
15515 
15516     retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &extData[0], sizeof(extData));
15517     if (retVal != MYKONOS_ERR_OK)
15518     {
15519         return retVal;
15520     }
15521 
15522     timeoutMs = 1000;
15523     retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte);
15524     if (retVal != MYKONOS_ERR_OK)
15525     {
15526         /* throw more specific error message instead of returning error code from waitArmCmdStatus */
15527         if (cmdStatusByte > 0)
15528         {
15529             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETVSWRSTATUS_ARMERRFLAG,
15530                     getMykonosErrorMessage(MYKONOS_ERR_GETVSWRSTATUS_ARMERRFLAG));
15531             return MYKONOS_ERR_GETVSWRSTATUS_ARMERRFLAG;
15532         }
15533 
15534         return retVal;
15535     }
15536 
15537     if (cmdStatusByte > 0)
15538     {
15539         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETVSWRSTATUS_ARMERRFLAG,
15540                 getMykonosErrorMessage(MYKONOS_ERR_GETVSWRSTATUS_ARMERRFLAG));
15541         return MYKONOS_ERR_GETVSWRSTATUS_ARMERRFLAG;
15542     }
15543 
15544     /* read status from ARM memory */
15545     offset = 0;
15546     retVal = MYKONOS_readArmMem(device, (MYKONOS_ADDR_ARM_START_DATA_ADDR + offset), &armData[0], sizeof(armData), 1);
15547     if (retVal != MYKONOS_ERR_OK)
15548     {
15549         return retVal;
15550     }
15551 
15552     vswrStatus->errorStatus = ((uint32_t)(armData[3]) << 24) | ((uint32_t)(armData[2]) << 16) | ((uint32_t)(armData[1]) << 8) | (uint32_t)(armData[0]);
15553     vswrStatus->forwardGainRms_dB = (int32_t)(((uint32_t)(armData[23]) << 24) | ((uint32_t)(armData[22]) << 16) | ((uint32_t)(armData[21]) << 8) | (uint32_t)(armData[20]));
15554     vswrStatus->forwardGainReal = (int32_t)(((uint32_t)(armData[27]) << 24) | ((uint32_t)(armData[26]) << 16) | ((uint32_t)(armData[25]) << 8) | (uint32_t)(armData[24]));
15555     vswrStatus->forwardGainImag = (int32_t)(((uint32_t)(armData[31]) << 24) | ((uint32_t)(armData[30]) << 16) | ((uint32_t)(armData[29]) << 8) | (uint32_t)(armData[28]));
15556     vswrStatus->reflectedGainRms_dB = (int32_t)(((uint32_t)(armData[35]) << 24) | ((uint32_t)(armData[34]) << 16) | ((uint32_t)(armData[33]) << 8) | (uint32_t)(armData[32]));
15557     vswrStatus->reflectedGainReal = (int32_t)(((uint32_t)(armData[39]) << 24) | ((uint32_t)(armData[38]) << 16) | ((uint32_t)(armData[37]) << 8) | (uint32_t)(armData[36]));
15558     vswrStatus->reflectedGainImag = (int32_t)(((uint32_t)(armData[43]) << 24) | ((uint32_t)(armData[42]) << 16) | ((uint32_t)(armData[41]) << 8) | (uint32_t)(armData[40]));
15559     vswrStatus->trackCount = ((uint32_t)(armData[63]) << 24) | ((uint32_t)(armData[62]) << 16) | ((uint32_t)(armData[61]) << 8) | (uint32_t)(armData[60]);
15560     vswrStatus->vswr_forward_tx_rms = (int32_t)(((uint32_t)(armData[47]) << 24) | ((uint32_t)(armData[46]) << 16) | ((uint32_t)(armData[45]) << 8) | (uint32_t)(armData[44]));
15561     vswrStatus->vswr_forward_orx_rms = (int32_t)(((uint32_t)(armData[51]) << 24) | ((uint32_t)(armData[50]) << 16) | ((uint32_t)(armData[49]) << 8) | (uint32_t)(armData[48]));
15562     vswrStatus->vswr_reflection_tx_rms = (int32_t)(((uint32_t)(armData[55]) << 24) | ((uint32_t)(armData[54]) << 16) | ((uint32_t)(armData[53]) << 8) | (uint32_t)(armData[52]));
15563     vswrStatus->vswr_reflection_orx_rms = (int32_t)(((uint32_t)(armData[59]) << 24) | ((uint32_t)(armData[58]) << 16) | ((uint32_t)(armData[57]) << 8) | (uint32_t)(armData[56]));
15564 
15565     return MYKONOS_ERR_OK;
15566 }
15567 
15568 /**
15569  * \brief Read from the Mykonos ARM program or data memory
15570  *
15571  * Valid memory addresses are: Program Memory (0x01000000 - 0x01017FFF),
15572  * Data Memory (0x20000000 - 0x2000FFFF)
15573  *
15574  * <B>Dependencies</B>
15575  * - device->spiSettings->chipSelectIndex
15576  * - device->spiSettings
15577  *
15578  * \param device is structure pointer to the Mykonos data structure containing settings
15579  * \param address The 32bit ARM address to read from.
15580  * \param returnData Byte(uint8_t) array containing the data read from the ARM memory.
15581  * \param bytesToRead Number of bytes in the returnData array.
15582  * \param autoIncrement is boolean flag to enable or disable autoincrement of ARM register address
15583  *
15584  * \retval MYKONOS_ERR_OK Function completed successfully
15585  * \retval MYKONOS_ERR_READARMMEM_INV_ADDR_PARM ARM memory address is out of range
15586  *
15587  */
MYKONOS_readArmMem(mykonosDevice_t * device,uint32_t address,uint8_t * returnData,uint32_t bytesToRead,uint8_t autoIncrement)15588 mykonosErr_t MYKONOS_readArmMem(mykonosDevice_t *device, uint32_t address, uint8_t *returnData, uint32_t bytesToRead, uint8_t autoIncrement)
15589 {
15590     uint8_t dataMem;
15591     uint32_t i;
15592 
15593 #if (MYKONOS_VERBOSE == 1)
15594     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_readArmMem()\n");
15595 #endif
15596 
15597     /* check that start and stop address are in valid range */
15598     if ((!(address >= MYKONOS_ADDR_ARM_START_PROG_ADDR && address <= MYKONOS_ADDR_ARM_END_PROG_ADDR))
15599             && !(address >= MYKONOS_ADDR_ARM_START_DATA_ADDR && address <= MYKONOS_ADDR_ARM_END_DATA_ADDR))
15600     {
15601         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READARMMEM_INV_ADDR_PARM,
15602                 getMykonosErrorMessage(MYKONOS_ERR_READARMMEM_INV_ADDR_PARM));
15603         return MYKONOS_ERR_READARMMEM_INV_ADDR_PARM;
15604     }
15605 
15606     if ((!(((address + bytesToRead - 1) >= MYKONOS_ADDR_ARM_START_PROG_ADDR) && (address + bytesToRead - 1) <= MYKONOS_ADDR_ARM_END_PROG_ADDR))
15607             && (!(((address + bytesToRead - 1) >= MYKONOS_ADDR_ARM_START_DATA_ADDR) && (address + bytesToRead - 1) <= MYKONOS_ADDR_ARM_END_DATA_ADDR)))
15608     {
15609         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READARMMEM_INV_ADDR_PARM,
15610                 getMykonosErrorMessage(MYKONOS_ERR_READARMMEM_INV_ADDR_PARM));
15611         return MYKONOS_ERR_READARMMEM_INV_ADDR_PARM;
15612     }
15613 
15614     if (address >= MYKONOS_ADDR_ARM_START_DATA_ADDR && address <= MYKONOS_ADDR_ARM_END_DATA_ADDR)
15615     {
15616         dataMem = 1;
15617     }
15618     else
15619     {
15620         dataMem = 0;
15621     }
15622 
15623     /* NOT assuming auto increment bit is already set from MYKONOS_initARM function call */
15624     /* setting auto increment address bit if autoIncrement evaluates true */
15625     if (autoIncrement)
15626     {
15627         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_ARM_CTL_1, 0x01, 0x04, 2);
15628     }
15629     else
15630     {
15631         CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_ARM_CTL_1, 0x00, 0x04, 2);
15632     }
15633 
15634     /* setting up for ARM read */
15635     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_ARM_CTL_1, 0x01, 0x20, 5);
15636     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_ADDR_BYTE_0, (uint8_t)((address) >> 2)); /* write address[9:2] */
15637     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_ADDR_BYTE_1, (uint8_t)(address >> 10) | (uint8_t)(dataMem << 7)); /* write address[15:10] */
15638 
15639     /* start read-back at correct byte offset */
15640     /* read data is located at SPI address 0xD04=data[7:0], 0xD05=data[15:8], 0xD06=data[23:16], 0xD07=data[31:24]. */
15641     /* with address auto increment set, after xD07 is read, the address will automatically increment */
15642     /* without address auto increment set, 0x4 must be added to the address for correct indexing */
15643     if (autoIncrement)
15644     {
15645         for (i = 0; i < bytesToRead; i++)
15646         {
15647             CMB_SPIReadByte(device->spiSettings, (MYKONOS_ADDR_ARM_DATA_BYTE_0 | (((address & 0x3) + i) % 4)), &returnData[i]);
15648         }
15649     }
15650     else
15651     {
15652         for (i = 0; i < bytesToRead; i++)
15653         {
15654             CMB_SPIReadByte(device->spiSettings, (MYKONOS_ADDR_ARM_DATA_BYTE_0 | (((address & 0x3) + i) % 4)), &returnData[i]);
15655 
15656             if ((MYKONOS_ADDR_ARM_DATA_BYTE_0 | (((address & 0x3) + i) % 4)) == MYKONOS_ADDR_ARM_DATA_BYTE_3)
15657             {
15658                 CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_ADDR_BYTE_0, (uint8_t)(((address + 0x4) & 0x3FF) >> 2));
15659                 CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_ADDR_BYTE_1, ((address + 0x4) & 0x1FC00U) >> 10 | (uint8_t)(dataMem << 7));
15660             }
15661         }
15662     }
15663 
15664     return MYKONOS_ERR_OK;
15665 }
15666 
15667 /**
15668  * \brief Write to the Mykonos ARM program or data memory
15669  *
15670  * Valid memory addresses are: Program Memory (0x01000000 - 0x01017FFF),
15671  * Data Memory (0x20000000 - 0x2000FFFF)
15672  *
15673  * <B>Dependencies</B>
15674  * - device->spiSettings->chipSelectIndex
15675  * - device->spiSettings
15676  *
15677  * \param device is structure pointer to the Mykonos data structure containing settings
15678  * \param address The 32bit ARM address to write to.
15679  * \param data Byte(uint8_t) array containing the data to write to the ARM memory.
15680  * \param byteCount Number of bytes in the data array.
15681  *
15682  * \retval MYKONOS_ERR_OK Function completed successfully
15683  * \retval MYKONOS_ERR_WRITEARMMEM_NULL_PARM Function parameter data has NULL pointer when byteCount is >0
15684  * \retval MYKONOS_ERR_WRITEARMMEM_INV_ADDR_PARM ARM memory address is out of range of valid ARM memory
15685  */
MYKONOS_writeArmMem(mykonosDevice_t * device,uint32_t address,uint8_t * data,uint32_t byteCount)15686 mykonosErr_t MYKONOS_writeArmMem(mykonosDevice_t *device, uint32_t address, uint8_t *data, uint32_t byteCount)
15687 {
15688     /* write address, then data with auto increment enabled. */
15689     uint8_t dataMem;
15690     uint32_t i;
15691 
15692 #if MYK_ENABLE_SPIWRITEARRAY == 1
15693     uint32_t addrIndex = 0;
15694     uint32_t dataIndex = 0;
15695     uint32_t spiBufferSize = MYK_SPIWRITEARRAY_BUFFERSIZE;
15696     uint16_t addrArray[MYK_SPIWRITEARRAY_BUFFERSIZE] = {0};
15697 #endif
15698 
15699 #if (MYKONOS_VERBOSE == 1)
15700     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_writeArmMem()\n");
15701 #endif
15702 
15703     if ((data == NULL) && (byteCount > 0))
15704     {
15705         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_WRITEARMMEM_NULL_PARM,
15706                 getMykonosErrorMessage(MYKONOS_ERR_WRITEARMMEM_NULL_PARM));
15707         return MYKONOS_ERR_WRITEARMMEM_NULL_PARM;
15708     }
15709 
15710     if ((!(address >= MYKONOS_ADDR_ARM_START_PROG_ADDR && address <= MYKONOS_ADDR_ARM_END_PROG_ADDR))
15711             && !(address >= MYKONOS_ADDR_ARM_START_DATA_ADDR && address <= MYKONOS_ADDR_ARM_END_DATA_ADDR))
15712     {
15713         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_WRITEARMMEM_INV_ADDR_PARM,
15714                 getMykonosErrorMessage(MYKONOS_ERR_WRITEARMMEM_INV_ADDR_PARM));
15715         return MYKONOS_ERR_WRITEARMMEM_INV_ADDR_PARM;
15716     }
15717 
15718     if ((!(((address + byteCount - 1) >= MYKONOS_ADDR_ARM_START_PROG_ADDR) && ((address + byteCount - 1) <= MYKONOS_ADDR_ARM_END_PROG_ADDR)))
15719             && (!(((address + byteCount - 1) >= MYKONOS_ADDR_ARM_START_DATA_ADDR) && ((address + byteCount - 1) <= MYKONOS_ADDR_ARM_END_DATA_ADDR))))
15720     {
15721         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_WRITEARMMEM_INV_ADDR_PARM,
15722                 getMykonosErrorMessage(MYKONOS_ERR_WRITEARMMEM_INV_ADDR_PARM));
15723         return MYKONOS_ERR_WRITEARMMEM_INV_ADDR_PARM;
15724     }
15725 
15726     if (address >= MYKONOS_ADDR_ARM_START_DATA_ADDR && address <= MYKONOS_ADDR_ARM_END_DATA_ADDR)
15727     {
15728         dataMem = 1;
15729     }
15730     else
15731     {
15732         dataMem = 0;
15733     }
15734 
15735     /* set auto increment address bit */
15736     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_ARM_CTL_1, 0x01, 0x04, 2);
15737 
15738     /* writing the address */
15739     CMB_SPIWriteField(device->spiSettings, MYKONOS_ADDR_ARM_CTL_1, 0x00, 0x20, 5);
15740     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_ADDR_BYTE_0, (uint8_t)((address) >> 2));
15741     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_ADDR_BYTE_1, (uint8_t)(address >> 10) | (uint8_t)(dataMem << 7));
15742 
15743     /* start write at correct byte offset */
15744     /* write data is located at SPI address 0xD04=data[7:0], 0xD05=data[15:8], 0xD06=data[23:16], 0xD07=data[31:24] */
15745     /* with address auto increment set, after x407 is written, the address will automatically increment */
15746 
15747 #if (MYK_ENABLE_SPIWRITEARRAY == 0)
15748 
15749     for (i = 0; i < byteCount; i++)
15750     {
15751         CMB_SPIWriteByte(device->spiSettings, (MYKONOS_ADDR_ARM_DATA_BYTE_0 | (((address & 0x3) + i) % 4)), data[i]);
15752     }
15753 
15754 #elif (MYK_ENABLE_SPIWRITEARRAY == 1)
15755 
15756     addrIndex = 0;
15757     dataIndex = 0;
15758     for (i = 0; i < byteCount; i++)
15759     {
15760         addrArray[addrIndex++] = (MYKONOS_ADDR_ARM_DATA_BYTE_0 | (((address & 0x3) + i) % 4));
15761 
15762         if (addrIndex == spiBufferSize)
15763         {
15764             CMB_SPIWriteBytes(device->spiSettings, &addrArray[0], &data[dataIndex], addrIndex);
15765             dataIndex = dataIndex + addrIndex;
15766             addrIndex = 0;
15767         }
15768     }
15769 
15770     if (addrIndex > 0)
15771     {
15772         CMB_SPIWriteBytes(device->spiSettings, &addrArray[0], &data[dataIndex], addrIndex);
15773     }
15774 
15775 #endif
15776 
15777     return MYKONOS_ERR_OK;
15778 }
15779 
15780 /**
15781  * \brief Low level helper function used by Mykonos API to write the ARM memory config structures
15782  *
15783  * Normally this function should not be required to be used directly by the BBIC.  This is a helper
15784  * function used by other Mykonos API commands to write settings into the ARM memory.
15785  *
15786  * <B>Dependencies</B>
15787  * - device->spiSettings->chipSelectIndex
15788  * - device->spiSettings
15789  *
15790  * \param device is structure pointer to the Mykonos data structure containing settings
15791  * \param objectId ARM id of a particular structure or setting in ARM memory
15792  * \param offset Byte offset from the start of the objectId's memory location in ARM memory
15793  * \param data A byte array containing data to write to the ARM memory buffer.
15794  * \param byteCount Number of bytes in the data array (Valid size = 1-255 bytes)
15795  *
15796  * \retval MYKONOS_ERR_OK Function completed successfully
15797  * \retval MYKONOS_ERR_WRITEARMCFG_ARMERRFLAG ARM write config command failed with a nonzero error code
15798  */
MYKONOS_writeArmConfig(mykonosDevice_t * device,uint8_t objectId,uint16_t offset,uint8_t * data,uint8_t byteCount)15799 mykonosErr_t MYKONOS_writeArmConfig(mykonosDevice_t *device, uint8_t objectId, uint16_t offset, uint8_t *data, uint8_t byteCount)
15800 {
15801     mykonosErr_t retVal = MYKONOS_ERR_OK;
15802     uint8_t extendedData[4] = {0}; /* ARM Object id, byte offset LSB, offset MSB = 0, copy 2 bytes */
15803     uint32_t timeoutMs = 1000;
15804     uint8_t cmdStatusByte = 0;
15805 
15806     retVal = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &data[0], byteCount);
15807     if (retVal != MYKONOS_ERR_OK)
15808     {
15809         return retVal;
15810     }
15811 
15812     extendedData[0] = objectId;
15813     extendedData[1] = (offset & 0xFF);
15814     extendedData[2] = ((offset >> 8) & 0xFF);
15815     extendedData[3] = byteCount;
15816     retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_WRITECFG_OPCODE, &extendedData[0], sizeof(extendedData));
15817     if (retVal != MYKONOS_ERR_OK)
15818     {
15819         return retVal;
15820     }
15821 
15822     retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_WRITECFG_OPCODE, timeoutMs, &cmdStatusByte);
15823     if (retVal != MYKONOS_ERR_OK)
15824     {
15825         if (cmdStatusByte > 0)
15826         {
15827             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_WRITEARMCFG_ARMERRFLAG,
15828                     getMykonosErrorMessage(MYKONOS_ERR_WRITEARMCFG_ARMERRFLAG));
15829             return MYKONOS_ERR_WRITEARMCFG_ARMERRFLAG;
15830         }
15831 
15832         return retVal;
15833     }
15834 
15835     if (cmdStatusByte > 0)
15836     {
15837         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_WRITEARMCFG_ARMERRFLAG,
15838                 getMykonosErrorMessage(MYKONOS_ERR_WRITEARMCFG_ARMERRFLAG));
15839         return MYKONOS_ERR_WRITEARMCFG_ARMERRFLAG;
15840     }
15841 
15842     return MYKONOS_ERR_OK;
15843 }
15844 
15845 /**
15846  * \brief Low level helper function used by Mykonos API to read the ARM memory config structures
15847  *
15848  * Normally this function should not be required to be used directly by the BBIC.  This is a helper
15849  * function used by other Mykonos API commands to read settings from the ARM memory.
15850  *
15851  * <B>Dependencies</B>
15852  * - device->spiSettings->chipSelectIndex
15853  * - device->spiSettings
15854  *
15855  * \param device is structure pointer to the Mykonos data structure containing settings
15856  * \param objectId ARM id of a particular structure or setting in ARM memory
15857  * \param offset Byte offset from the start of the objectId's memory location in ARM memory
15858  * \param data A byte array containing data to write to the ARM memory buffer.
15859  * \param byteCount Number of bytes in the data array (Valid size = 1-255 bytes)
15860  *
15861  * \retval MYKONOS_ERR_OK Function completed successfully
15862  * \retval MYKONOS_ERR_READARMCFG_ARMERRFLAG ARM read config command failed with a nonzero error code
15863  */
MYKONOS_readArmConfig(mykonosDevice_t * device,uint8_t objectId,uint16_t offset,uint8_t * data,uint8_t byteCount)15864 mykonosErr_t MYKONOS_readArmConfig(mykonosDevice_t *device, uint8_t objectId, uint16_t offset, uint8_t *data, uint8_t byteCount)
15865 {
15866     mykonosErr_t retVal = MYKONOS_ERR_OK;
15867     uint8_t extendedData[4] = {0}; /* ARM Object id, byte offset LSB, offset MSB = 0, copy 2 bytes */
15868     uint32_t timeoutMs = 1000;
15869     uint8_t cmdStatusByte = 0;
15870     const uint8_t AUTO_INCREMENT = 1;
15871     extendedData[0] = objectId;
15872     extendedData[1] = (offset & 0xFF);
15873     extendedData[2] = ((offset >> 8) & 0xFF);
15874     extendedData[3] = byteCount;
15875 
15876     retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_READCFG_OPCODE, &extendedData[0], sizeof(extendedData));
15877     if (retVal != MYKONOS_ERR_OK)
15878     {
15879         return retVal;
15880     }
15881 
15882     retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_READCFG_OPCODE, timeoutMs, &cmdStatusByte);
15883     if (retVal != MYKONOS_ERR_OK)
15884     {
15885         if (cmdStatusByte > 0)
15886         {
15887             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READARMCFG_ARMERRFLAG,
15888                     getMykonosErrorMessage(MYKONOS_ERR_READARMCFG_ARMERRFLAG));
15889             return MYKONOS_ERR_READARMCFG_ARMERRFLAG;
15890         }
15891 
15892         return retVal;
15893     }
15894 
15895     if (cmdStatusByte > 0)
15896     {
15897         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READARMCFG_ARMERRFLAG,
15898                 getMykonosErrorMessage(MYKONOS_ERR_READARMCFG_ARMERRFLAG));
15899         return MYKONOS_ERR_READARMCFG_ARMERRFLAG;
15900     }
15901 
15902     retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &data[0], byteCount, AUTO_INCREMENT);
15903 
15904     return retVal;
15905 }
15906 
15907 /**
15908  * \brief Sends a command to the Mykonos ARM processor
15909  *
15910  * <B>Dependencies</B>
15911  * - device->spiSettings->chipSelectIndex
15912  * - device->spiSettings
15913  *
15914  * \param device is structure pointer to the Mykonos data structure containing settings
15915  * \param opCode Value (0-30, even only) indicating the desired function to run in the ARM.
15916  * \param extendedData A byte array containing extended data to write to the ARM command interface.
15917  * \param extendedDataNumBytes Number of bytes in the extendedData array (Valid size = 0-4 bytes)
15918  *
15919  * \retval MYKONOS_ERR_OK Function completed successfully
15920  * \retval MYKONOS_ERR_ARMCMD_NULL_PARM Function parameter extendedData is NULL and extendedDataNumBytes is positive
15921  * \retval MYKONOS_ERR_ARMCMD_INV_OPCODE_PARM ARM opcode is out of range (valid 0-30, even only)
15922  * \retval MYKONOS_ERR_ARMCMD_INV_NUMBYTES_PARM Number of extended bytes parameter is out of range (valid 0-4)
15923  * \retval MYKONOS_ERR_TIMEDOUT_ARMMAILBOXBUSY ARM control interface is busy, command could not be executed by ARM
15924  */
MYKONOS_sendArmCommand(mykonosDevice_t * device,uint8_t opCode,uint8_t * extendedData,uint8_t extendedDataNumBytes)15925 mykonosErr_t MYKONOS_sendArmCommand(mykonosDevice_t *device, uint8_t opCode, uint8_t *extendedData, uint8_t extendedDataNumBytes)
15926 {
15927     uint8_t armCommandBusy = 0;
15928     uint8_t i = 0;
15929     uint16_t extCmdByteStartAddr = MYKONOS_ADDR_ARM_EXT_CMD_BYTE_1;
15930 
15931 #if (MYKONOS_VERBOSE == 1)
15932     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_sendArmCommand()\n");
15933 #endif
15934 
15935     if ((extendedData == NULL) && (extendedDataNumBytes > 0))
15936     {
15937         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ARMCMD_NULL_PARM, getMykonosErrorMessage(MYKONOS_ERR_ARMCMD_NULL_PARM));
15938         return MYKONOS_ERR_ARMCMD_NULL_PARM;
15939     }
15940 
15941     /* check for even-numbered opCodes only including opcode 0, but not must be greater than opCode 30 */
15942     if ((opCode != 0) && ((opCode % 2) || (opCode > 30)))
15943     {
15944         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ARMCMD_INV_OPCODE_PARM,
15945                 getMykonosErrorMessage(MYKONOS_ERR_ARMCMD_INV_OPCODE_PARM));
15946         return MYKONOS_ERR_ARMCMD_INV_OPCODE_PARM;
15947     }
15948 
15949     /* the number of valid extended data bytes is from 0-4 */
15950     if (extendedDataNumBytes > 4)
15951     {
15952         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ARMCMD_INV_NUMBYTES_PARM,
15953                 getMykonosErrorMessage(MYKONOS_ERR_ARMCMD_INV_NUMBYTES_PARM));
15954         return MYKONOS_ERR_ARMCMD_INV_NUMBYTES_PARM;
15955     }
15956 
15957     /* setting a 2 sec timeout for mailbox busy bit to be clear (can't send an arm mailbox command until mailbox is ready) */
15958     CMB_setTimeout_ms(device->spiSettings, 2000);
15959 
15960     do
15961     {
15962         CMB_SPIReadField(device->spiSettings, MYKONOS_ADDR_ARM_CMD, &armCommandBusy, 0x80, 7);
15963 
15964         if (CMB_hasTimeoutExpired(device->spiSettings))
15965         {
15966             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_TIMEDOUT_ARMMAILBOXBUSY,
15967                     getMykonosErrorMessage(MYKONOS_ERR_TIMEDOUT_ARMMAILBOXBUSY));
15968             return MYKONOS_ERR_TIMEDOUT_ARMMAILBOXBUSY;
15969         }
15970     } while (armCommandBusy);
15971 
15972     if (extendedDataNumBytes)
15973     {
15974         for (i = 0; i < extendedDataNumBytes; i++)
15975         {
15976             CMB_SPIWriteByte(device->spiSettings, extCmdByteStartAddr + i, extendedData[i]);
15977         }
15978     }
15979 
15980     CMB_SPIWriteByte(device->spiSettings, MYKONOS_ADDR_ARM_CMD, opCode);
15981 
15982     return MYKONOS_ERR_OK;
15983 }
15984 
15985 /**
15986  * \brief Reads the Mykonos ARM 64-bit command status register
15987  *
15988  * A 64-bit status register consisting of a pending bit and three-bit error type is read one byte at
15989  * a time for opcodes 0-30. The function parses the pending bits and error bits into
15990  * two (2) separate 16-bit words containing pending bits, and error bits if the error type > 0
15991  * The words are weighted according to each even-numbered opcode from 0-30,
15992  * where, 0x0001 = opcode '0', 0x0002 = opcode '2', 0x0004 = opcode '4', 0x0008 = opcode '6' and so on.
15993  *
15994  * <B>Dependencies</B>
15995  * - device->spiSettings->chipSelectIndex
15996  *
15997  * \param device is a pointer to the device settings structure
15998  * \param errorWord 16-bit error word comprised of weighted bits according to each opcode number
15999  * The weighted bit = '1' if error type > 0, '0' if OK
16000  * \param statusWord 16-bit pending bits word comprised of weighted bits according to each opcode number
16001  *
16002  * \retval MYKONOS_ERR_OK Function completed successfully
16003  * \retval MYKONOS_ERR_READARMCMDSTATUS_NULL_PARM Function parameters errorWord or statusWord have a NULL pointer
16004  */
MYKONOS_readArmCmdStatus(mykonosDevice_t * device,uint16_t * errorWord,uint16_t * statusWord)16005 mykonosErr_t MYKONOS_readArmCmdStatus(mykonosDevice_t *device, uint16_t *errorWord, uint16_t *statusWord)
16006 {
16007     uint8_t i = 0;
16008     uint8_t bytes[8] = {0};
16009 
16010 #if (MYKONOS_VERBOSE == 1)
16011     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_readArmCmdStatus()\n");
16012 #endif
16013 
16014     if (errorWord == NULL || statusWord == NULL)
16015     {
16016         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READARMCMDSTATUS_NULL_PARM,
16017                 getMykonosErrorMessage(MYKONOS_ERR_READARMCMDSTATUS_NULL_PARM));
16018         return MYKONOS_ERR_READARMCMDSTATUS_NULL_PARM;
16019     }
16020 
16021     /* making sure the errorWord and statusWord are clear */
16022     *errorWord = 0;
16023     *statusWord = 0;
16024 
16025     /* read in the entire 64-bit status register into a byte array for parsing */
16026     for (i = 0; i < 8; i++)
16027     {
16028         CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_ARM_CMD_STATUS_0 + i, &bytes[i]);
16029     }
16030 
16031     /* parse the byte array for pending bits and error types and generate statusWord and errorWord bits */
16032     for (i = 0; i < 8; i++)
16033     {
16034         *statusWord |= (uint16_t)((uint16_t)(((bytes[i] & 0x10) >> 3) | (bytes[i] & 0x01)) << (i * 2));
16035 
16036         if (bytes[i] & 0x0E)
16037         {
16038             *errorWord |= (uint16_t)(0x0001 << (i * 2));
16039         }
16040         else if (bytes[i] & 0xE0)
16041         {
16042             *errorWord |= (uint16_t)(0x0002 << (i * 2));
16043         }
16044     }
16045 
16046     return MYKONOS_ERR_OK;
16047 }
16048 
16049 /**
16050  * \brief Isolated byte read of the Mykonos ARM 64-bit command status register based on the opcode
16051  *
16052  * A single byte read is performed on the 64-bit command status register according to
16053  * the opcode of interest. The pending bit and the error type are extracted from the status
16054  * register and returned as a single byte in the lower nibble.
16055  *
16056  * <B>Dependencies</B>
16057  * - device->spiSettings->chipSelectIndex
16058  *
16059  * \param device is a pointer to the device settings structure
16060  * \param opCode Valid values are even increments from 0-30. The ARM opCode is used to determine which status register byte to read
16061  * \param cmdStatByte returns cmdStatByte[3:1] = error type, cmdStatByte[0] = pending flag for selected opCode
16062  *
16063  * \retval MYKONOS_ERR_OK Function completed successfully
16064  * \retval MYKONOS_ERR_READARMCMDSTATUSBYTE_NULL_PARM Function parameter cmdStatByte has NULL pointer
16065  * \retval MYKONOS_ERR_READARMCMDSTATUS_INV_OPCODE_PARM ARM opcode is out of range (valid 0-30, even only)
16066  */
MYKONOS_readArmCmdStatusByte(mykonosDevice_t * device,uint8_t opCode,uint8_t * cmdStatByte)16067 mykonosErr_t MYKONOS_readArmCmdStatusByte(mykonosDevice_t *device, uint8_t opCode, uint8_t *cmdStatByte)
16068 {
16069     uint8_t cmdByteIndex = 0;
16070     uint8_t cmdByte = 0;
16071 
16072 #if 0
16073 #if (MYKONOS_VERBOSE == 1)
16074     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_readArmCmdStatByte()\n");
16075 #endif
16076 #endif
16077 
16078     if (cmdStatByte == NULL)
16079     {
16080         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READARMCMDSTATUSBYTE_NULL_PARM,
16081                 getMykonosErrorMessage(MYKONOS_ERR_READARMCMDSTATUSBYTE_NULL_PARM));
16082         return MYKONOS_ERR_READARMCMDSTATUSBYTE_NULL_PARM;
16083     }
16084 
16085     /* check for even-numbered opCodes only including opcode 0, but not must be greater than opCode 30 */
16086     if ((opCode != 0) && ((opCode % 2) || (opCode > 30)))
16087     {
16088         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_READARMCMDSTATUS_INV_OPCODE_PARM,
16089                 getMykonosErrorMessage(MYKONOS_ERR_READARMCMDSTATUS_INV_OPCODE_PARM));
16090         return MYKONOS_ERR_READARMCMDSTATUS_INV_OPCODE_PARM;
16091     }
16092     else
16093     {
16094         cmdByteIndex = (opCode / 4);
16095 
16096         CMB_SPIReadByte(device->spiSettings, MYKONOS_ADDR_ARM_CMD_STATUS_0 + cmdByteIndex, &cmdByte);
16097 
16098         if ((opCode / 2) % 2)
16099         {
16100             *cmdStatByte = ((cmdByte >> 4) & 0x0F);
16101         }
16102         else
16103         {
16104             *cmdStatByte = (cmdByte & 0x0F);
16105         }
16106 
16107         return MYKONOS_ERR_OK;
16108     }
16109 }
16110 
16111 /**
16112  * \brief Mykonos ARM command status wait function polls command status until opcode completes
16113  *
16114  * <B>Dependencies</B>
16115  * - device->spiSettings->chipSelectIndex
16116  *
16117  * \param device is a pointer to the device settings structure
16118  * \param opCode Valid values are even increments from 0-30. The ARM opCode is used to determine which pending bit to wait for
16119  * \param timeoutMs conveys the time-out period in milliseconds
16120  * \param cmdStatByte returns cmdStatByte[3:1] = error type, cmdStatByte[0] = pending flag for selected opCode
16121  *
16122  * \retval MYKONOS_ERR_OK Function completed successfully
16123  * \retval MYKONOS_ERR_ARMCMDSTATUS_NULL_PARM Function parameter cmdStatByte has NULL pointer
16124  * \retval MYKONOS_ERR_ARMCMDSTATUS_INV_OPCODE_PARM Invalid ARM opcode (valid 0-30, even numbers only)
16125  * \retval MYKONOS_ERR_ARMCMDSTATUS_ARMERROR ARM Mailbox error flag for requested opcode returned a nonzero error flag
16126  * \retval MYKONOS_ERR_WAITARMCMDSTATUS_TIMEOUT Timeout occurred before ARM command completed
16127  */
MYKONOS_waitArmCmdStatus(mykonosDevice_t * device,uint8_t opCode,uint32_t timeoutMs,uint8_t * cmdStatByte)16128 mykonosErr_t MYKONOS_waitArmCmdStatus(mykonosDevice_t *device, uint8_t opCode, uint32_t timeoutMs, uint8_t *cmdStatByte)
16129 {
16130     mykonosErr_t retVal = MYKONOS_ERR_OK;
16131 
16132 #if (MYKONOS_VERBOSE == 1)
16133     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_waitArmCmdStatus()\n");
16134 #endif
16135 
16136     if (cmdStatByte == NULL)
16137     {
16138         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ARMCMDSTATUS_NULL_PARM,
16139                 getMykonosErrorMessage(MYKONOS_ERR_ARMCMDSTATUS_NULL_PARM));
16140         return MYKONOS_ERR_ARMCMDSTATUS_NULL_PARM;
16141     }
16142 
16143     /* check for even-numbered opCodes only including opcode 0, but not must be greater than opCode 30 */
16144     if ((opCode != 0) && ((opCode % 2) || (opCode > 30)))
16145     {
16146         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ARMCMDSTATUS_INV_OPCODE_PARM,
16147                 getMykonosErrorMessage(MYKONOS_ERR_ARMCMDSTATUS_INV_OPCODE_PARM));
16148         return MYKONOS_ERR_ARMCMDSTATUS_INV_OPCODE_PARM;
16149     }
16150 
16151     /* start wait */
16152     CMB_setTimeout_ms(device->spiSettings, timeoutMs);
16153 
16154     do
16155     {
16156         retVal = MYKONOS_readArmCmdStatusByte(device, opCode, cmdStatByte);
16157         if (retVal != MYKONOS_ERR_OK)
16158         {
16159             return retVal;
16160         }
16161 
16162         /* If error flag is non zero in [3:1], - return error */
16163         if ((*cmdStatByte & 0x0E) > 0)
16164         {
16165             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_ARMCMDSTATUS_ARMERROR,
16166                     getMykonosErrorMessage(MYKONOS_ERR_ARMCMDSTATUS_ARMERROR));
16167             return MYKONOS_ERR_ARMCMDSTATUS_ARMERROR;
16168         }
16169 
16170         if (CMB_hasTimeoutExpired(device->spiSettings))
16171         {
16172             return MYKONOS_ERR_WAITARMCMDSTATUS_TIMEOUT;
16173         }
16174     } while (*cmdStatByte & 0x01);
16175 
16176     return MYKONOS_ERR_OK;
16177 }
16178 
16179 /**
16180  * \brief Mykonos ARM configuration write
16181  *
16182  * <B>Dependencies</B>
16183  * - device->spiSettings->chipSelectIndex
16184  *
16185  * \param device is a pointer to the device settings structure
16186  *
16187  * \retval MYKONOS_ERR_OK Function completed successfully
16188  */
MYKONOS_writeArmProfile(mykonosDevice_t * device)16189 mykonosErr_t MYKONOS_writeArmProfile(mykonosDevice_t *device)
16190 {
16191     const uint8_t length = 100;
16192 
16193     int32_t i = 0;
16194     uint8_t vcoDiv = 0;
16195     uint8_t hsDiv = 0;
16196     uint16_t channelsEnabled = 0;
16197     uint8_t cfgData[100] = {0};
16198 
16199     mykonosErr_t retVal = MYKONOS_ERR_OK;
16200 
16201 #if (MYKONOS_VERBOSE == 1)
16202     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_writeArmConfig()\n");
16203 #endif
16204 
16205     /* reading in required mykonosDevice_t structure data into array - not pretty but it works */
16206     for (i = 0; i < 4; i++)
16207     {
16208         cfgData[i] = (uint8_t)(((device->clocks->deviceClock_kHz * 1000) >> (i * 8)) & 0x000000FF);
16209     }
16210 
16211     for (i = 4; i < 8; i++)
16212     {
16213         cfgData[i] = (uint8_t)(((device->clocks->clkPllVcoFreq_kHz) >> ((i - 4) * 8)) & 0x000000FF);
16214     }
16215 
16216     vcoDiv = (uint8_t)(device->clocks->clkPllVcoDiv);
16217     hsDiv = device->clocks->clkPllHsDiv;
16218 
16219     cfgData[8] = vcoDiv; /* uint8_t vco_div */
16220     cfgData[9] = hsDiv; /* uint8_t hs_div */
16221 
16222     channelsEnabled |= ((uint16_t)device->tx->txChannels & 0x03);
16223     channelsEnabled |= ((uint16_t)device->rx->rxChannels & 0x03) << 2;
16224     if (device->profilesValid & ORX_PROFILE_VALID)
16225     {
16226         channelsEnabled |= (((uint16_t)device->obsRx->obsRxChannelsEnable & 3) << 4);
16227     }
16228 
16229     if (device->profilesValid & SNIFF_PROFILE_VALID)
16230     {
16231         channelsEnabled |= ((((uint16_t)device->obsRx->obsRxChannelsEnable >> 2) & 7) << 6);
16232     }
16233 
16234     for (i = 10; i < 12; i++)
16235     {
16236         cfgData[i] = (uint8_t)((channelsEnabled >> ((i - 10) * 8)) & 0xFF);
16237     }
16238 
16239     cfgData[12] = ((device->rx->rxPllUseExternalLo & 0x01) << 1) | (device->tx->txPllUseExternalLo & 0x01);
16240     cfgData[13] = 0x00; /* Not used...padding */
16241     cfgData[14] = 0x00; /* Not used...padding */
16242     cfgData[15] = 0x00; /* Not used...padding */
16243 
16244     if (device->profilesValid & TX_PROFILE_VALID)
16245     {
16246         /* start of Tx profile data */
16247         cfgData[16] = (uint8_t)device->tx->txProfile->dacDiv;
16248         cfgData[17] = device->tx->txProfile->txFirInterpolation;
16249         cfgData[18] = device->tx->txProfile->thb1Interpolation;
16250         cfgData[19] = device->tx->txProfile->thb2Interpolation;
16251 
16252         for (i = 20; i < 24; i++)
16253         {
16254             cfgData[i] = (uint8_t)(((device->tx->txProfile->iqRate_kHz * 1000) >> ((i - 20) * 8)) & 0x000000FF);
16255         }
16256 
16257         for (i = 24; i < 28; i++)
16258         {
16259             cfgData[i] = (uint8_t)(((device->tx->txProfile->primarySigBandwidth_Hz) >> ((i - 24) * 8)) & 0x000000FF);
16260         }
16261 
16262         for (i = 28; i < 32; i++)
16263         {
16264             cfgData[i] = (uint8_t)(((device->tx->txProfile->rfBandwidth_Hz) >> ((i - 28) * 8)) & 0x000000FF);
16265         }
16266 
16267         for (i = 32; i < 36; i++)
16268         {
16269             cfgData[i] = (uint8_t)(((device->tx->txProfile->txDac3dBCorner_kHz) >> ((i - 32) * 8)) & 0x000000FF);
16270         }
16271 
16272         for (i = 36; i < 40; i++)
16273         {
16274             cfgData[i] = (uint8_t)(((device->tx->txProfile->txBbf3dBCorner_kHz * 1000) >> ((i - 36) * 8)) & 0x000000FF);
16275         }
16276     }
16277     else
16278     {
16279         cfgData[16] = 0;
16280         cfgData[17] = 0;
16281         cfgData[18] = 0;
16282         cfgData[19] = 0;
16283         cfgData[20] = 0;
16284         cfgData[21] = 0;
16285         cfgData[22] = 0;
16286         cfgData[23] = 0;
16287         cfgData[24] = 0;
16288         cfgData[25] = 0;
16289         cfgData[26] = 0;
16290         cfgData[27] = 0;
16291         cfgData[28] = 0;
16292         cfgData[29] = 0;
16293         cfgData[30] = 0;
16294         cfgData[31] = 0;
16295         cfgData[32] = 0;
16296         cfgData[33] = 0;
16297         cfgData[34] = 0;
16298         cfgData[35] = 0;
16299         cfgData[36] = 0;
16300         cfgData[37] = 0;
16301         cfgData[38] = 0;
16302         cfgData[39] = 0;
16303     }
16304 
16305     if (device->profilesValid & RX_PROFILE_VALID)
16306     {
16307         /* start of Rx profile data */
16308         cfgData[40] = device->rx->rxProfile->adcDiv;
16309         cfgData[41] = device->rx->rxProfile->rxFirDecimation;
16310         cfgData[42] = device->rx->rxProfile->rxDec5Decimation;
16311         cfgData[43] = device->rx->rxProfile->rhb1Decimation;
16312 
16313         for (i = 44; i < 48; i++)
16314         {
16315             cfgData[i] = (uint8_t)(((device->rx->rxProfile->iqRate_kHz * 1000) >> ((i - 44) * 8)) & 0x000000FF);
16316         }
16317 
16318         for (i = 48; i < 52; i++)
16319         {
16320             /* sig bw placeholder */
16321             cfgData[i] = (uint8_t)(((device->rx->rxProfile->rfBandwidth_Hz) >> ((i - 48) * 8)) & 0x000000FF);
16322         }
16323 
16324         for (i = 52; i < 56; i++)
16325         {
16326             cfgData[i] = (uint8_t)(((device->rx->rxProfile->rfBandwidth_Hz) >> ((i - 52) * 8)) & 0x000000FF);
16327         }
16328 
16329         for (i = 56; i < 60; i++)
16330         {
16331             cfgData[i] = (uint8_t)(((device->rx->rxProfile->rxBbf3dBCorner_kHz * 1000) >> ((i - 56) * 8)) & 0x000000FF);
16332         }
16333     }
16334     else
16335     {
16336         cfgData[40] = 0;
16337         cfgData[41] = 0;
16338         cfgData[42] = 0;
16339         cfgData[43] = 0;
16340         cfgData[44] = 0;
16341         cfgData[45] = 0;
16342         cfgData[46] = 0;
16343         cfgData[47] = 0;
16344         cfgData[48] = 0;
16345         cfgData[49] = 0;
16346         cfgData[50] = 0;
16347         cfgData[51] = 0;
16348         cfgData[52] = 0;
16349         cfgData[53] = 0;
16350         cfgData[54] = 0;
16351         cfgData[55] = 0;
16352         cfgData[56] = 0;
16353         cfgData[57] = 0;
16354         cfgData[58] = 0;
16355         cfgData[59] = 0;
16356     }
16357 
16358     if (device->profilesValid & ORX_PROFILE_VALID)
16359     {
16360         /* start of ObsRx profile data */
16361         cfgData[60] = device->obsRx->orxProfile->adcDiv;
16362         cfgData[61] = device->obsRx->orxProfile->rxFirDecimation;
16363         cfgData[62] = device->obsRx->orxProfile->rxDec5Decimation;
16364         cfgData[63] = device->obsRx->orxProfile->rhb1Decimation;
16365 
16366         for (i = 64; i < 68; i++)
16367         {
16368             cfgData[i] = (uint8_t)(((device->obsRx->orxProfile->iqRate_kHz * 1000) >> ((i - 64) * 8)) & 0x000000FF);
16369         }
16370 
16371         for (i = 68; i < 72; i++)
16372         {
16373             /* sig bw placeholder */
16374             cfgData[i] = (uint8_t)(((device->obsRx->orxProfile->rfBandwidth_Hz) >> ((i - 68) * 8)) & 0x000000FF);
16375         }
16376 
16377         for (i = 72; i < 76; i++)
16378         {
16379             cfgData[i] = (uint8_t)(((device->obsRx->orxProfile->rfBandwidth_Hz) >> ((i - 72) * 8)) & 0x000000FF);
16380         }
16381 
16382         for (i = 76; i < 80; i++)
16383         {
16384             cfgData[i] = (uint8_t)(((device->obsRx->orxProfile->rxBbf3dBCorner_kHz * 1000) >> ((i - 76) * 8)) & 0x000000FF);
16385         }
16386     }
16387     else
16388     {
16389         cfgData[60] = 0;
16390         cfgData[61] = 0;
16391         cfgData[62] = 0;
16392         cfgData[63] = 0;
16393         cfgData[64] = 0;
16394         cfgData[65] = 0;
16395         cfgData[66] = 0;
16396         cfgData[67] = 0;
16397         cfgData[68] = 0;
16398         cfgData[69] = 0;
16399         cfgData[70] = 0;
16400         cfgData[71] = 0;
16401         cfgData[72] = 0;
16402         cfgData[73] = 0;
16403         cfgData[74] = 0;
16404         cfgData[75] = 0;
16405         cfgData[76] = 0;
16406         cfgData[77] = 0;
16407         cfgData[78] = 0;
16408         cfgData[79] = 0;
16409     }
16410 
16411     if (device->profilesValid & SNIFF_PROFILE_VALID)
16412     {
16413         /* start of SnRx profile data */
16414         cfgData[80] = device->obsRx->snifferProfile->adcDiv;
16415         cfgData[81] = device->obsRx->snifferProfile->rxFirDecimation;
16416         cfgData[82] = device->obsRx->snifferProfile->rxDec5Decimation;
16417         cfgData[83] = device->obsRx->snifferProfile->rhb1Decimation;
16418 
16419         for (i = 84; i < 88; i++)
16420         {
16421             cfgData[i] = (uint8_t)(((device->obsRx->snifferProfile->iqRate_kHz * 1000) >> ((i - 84) * 8)) & 0x000000FF);
16422         }
16423 
16424         for (i = 88; i < 92; i++)
16425         {
16426             /* sig bw placeholder */
16427             cfgData[i] = (uint8_t)(((device->obsRx->snifferProfile->rfBandwidth_Hz) >> ((i - 88) * 8)) & 0x000000FF);
16428         }
16429 
16430         for (i = 92; i < 96; i++)
16431         {
16432             cfgData[i] = (uint8_t)(((device->obsRx->snifferProfile->rfBandwidth_Hz) >> ((i - 92) * 8)) & 0x000000FF);
16433         }
16434 
16435         for (i = 96; i < 100; i++)
16436         {
16437             cfgData[i] = (uint8_t)(((device->obsRx->snifferProfile->rxBbf3dBCorner_kHz * 1000) >> ((i - 96) * 8)) & 0x000000FF);
16438         }
16439     }
16440     else
16441     {
16442         cfgData[80] = 0;
16443         cfgData[81] = 0;
16444         cfgData[82] = 0;
16445         cfgData[83] = 0;
16446         cfgData[84] = 0;
16447         cfgData[85] = 0;
16448         cfgData[86] = 0;
16449         cfgData[87] = 0;
16450         cfgData[88] = 0;
16451         cfgData[89] = 0;
16452         cfgData[90] = 0;
16453         cfgData[91] = 0;
16454         cfgData[92] = 0;
16455         cfgData[93] = 0;
16456         cfgData[94] = 0;
16457         cfgData[95] = 0;
16458         cfgData[96] = 0;
16459         cfgData[97] = 0;
16460         cfgData[98] = 0;
16461         cfgData[99] = 0;
16462     }
16463 
16464     /* writing to the ARM memory with the array data */
16465     retVal = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &cfgData[0], length);
16466 
16467     return retVal;
16468 }
16469 
16470 /**
16471  * \brief Function called automatically that loads the ADC profiles into the ARM
16472  *
16473  * User should not need to call this function normally.  It is called automatically
16474  * during MYKONOS_initArm() to load the ADC profiles (tunes the ADC performance).
16475  *
16476  * Rx ADC profile is only loaded if the Rx Profile is valid, ORx ADC profile is
16477  * only loaded if the ORx Profile is valid. Sniffer ADC profile is only loaded
16478  * if the Sniffer profile is valid.  The Loopback ADC profile is always
16479  * loaded.  If Tx profile is valid, the loopback ADC profile is chosen based
16480  * on the Tx Primary Signal bandwidth.  If no valid Tx Profile, the Rx profile
16481  * is used to set the Loopback ADC profile.  Else, ORx, then sniffer profiles
16482  * are used to set the loopback ADC profile.
16483  *
16484  * <B>Dependencies</B>
16485  * - device->spiSettings->chipSelectIndex
16486  *
16487  * \param device Pointer to the device settings structure
16488  *
16489  * \retval MYKONOS_ERR_OK Function completed successfully
16490  * \retval MYKONOS_ERR_LOAD_ADCPROFILE_INV_VCODIV Mykonos CLKPLL has invalid VCO divider in the clocks structure
16491  * \retval MYKONOS_ERR_LOAD_ADCPROFILE_MISSING_ORX_PROFILE When Tx Profile used, a matching ORx Profile must be provided with a valid ADC divider.
16492  *                                                         The ORx digital filters and clock dividers are used with the Loopback Rx path for Tx calibrations.
16493  * \retval MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_RXREQUIRED ADC Profile Lookup table does not have a match
16494  *                                                       for current Rx Profile settings.  Custom ADC profile required
16495  * \retval MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_ORXREQUIRED ADC Profile Lookup table does not have a match
16496  *                                                        for current ORx Profile settings.  Custom ADC profile required
16497  * \retval MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_SNRXREQUIRED ADC Profile Lookup table does not have a match
16498  *                                                         for current Sniffer Rx Profile settings.  Custom ADC profile required
16499  * \retval MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_LBREQUIRED ADC Profile Lookup table does not have a match
16500  *                                                       for Loopback passband BW and ADC Clock frequency settings.  Custom ADC profile required
16501  * \retval MYKONOS_ERR_LOAD_ADCPROFILE_RXADCDIV_ZERO Rx Profile has invalid ADC divider = 0, causing a divide by zero error
16502  * \retval MYKONOS_ERR_LOAD_ADCPROFILE_ORXADCDIV_ZERO ORx profile has invalid ADC divider = 0, causing a divide by zero error
16503  * \retval MYKONOS_ERR_LOAD_ADCPROFILE_SNRX_ADCDIV_ZERO Sniffer profile has invalid ADC divider = 0, causing a divide by zero error
16504  * \retval MYKONOS_ERR_LOAD_RXADCPROFILE_ARMMEM_FAILED Error returned while trying to write Rx ADC profile to ARM memory
16505  * \retval MYKONOS_ERR_LOAD_ORXADCPROFILE_ARMMEM_FAILED Error returned while trying to write ORx ADC profile to ARM memory
16506  * \retval MYKONOS_ERR_LOAD_SNRXADCPROFILE_ARMMEM_FAILED Error returned while trying to write Sniffer ADC profile into ARM memory
16507  * \retval MYKONOS_ERR_LOAD_LBADCPROFILE_ARMMEM_FAILED Error returned while trying to write Loopback ADC profile into ARM memory
16508  */
MYKONOS_loadAdcProfiles(mykonosDevice_t * device)16509 mykonosErr_t MYKONOS_loadAdcProfiles(mykonosDevice_t *device)
16510 {
16511     uint8_t adcProfile[32] = {0};
16512     uint8_t i = 0;
16513     mykonosErr_t retVal = MYKONOS_ERR_OK;
16514     uint32_t hsDigClk_MHz = 0;
16515     uint32_t adcClk_MHz = 0;
16516     uint32_t vcoDiv = 0;
16517     uint32_t vcoDivTimes10 = 10;
16518     uint8_t profileIndex = 0;
16519     const uint8_t ARM_CONFIG_OFFSET = 100; /* number of bytes written in MYKONOS_writeArmProfile() to ARM memory */
16520 
16521     const uint8_t NUM_ADCPROFILE_COEFS = 16;
16522     const uint8_t NUM_ADC_PROFILES = 20;
16523     static const uint16_t adcProfileLut[20][18] = {
16524         /* Max RFBW, ADCCLK_MHz, adcProfile[16] */
16525         { 20,  491, 1494, 564, 201,  98, 1280, 134,  945,  40,  529,  10,  326, 39, 30, 16,  9, 201},
16526         { 60,  983,  712, 462, 201,  98, 1280, 291, 1541, 149, 1054,  46,  645, 34, 48, 32, 18, 193},
16527         { 75,  983,  680, 477, 201,  98, 1280, 438, 1577, 242, 1046,  73,  636, 30, 48, 31, 18, 192},
16528         {100,  983,  655, 446, 201,  98, 1280, 336, 1631, 334, 1152, 207,  733, 33, 48, 32, 21, 212},
16529         { 75, 1228,  569, 369, 201,  98, 1280, 291, 1541, 149, 1320,  58,  807, 34, 48, 40, 23, 189},
16530         {100, 1228,  534, 386, 201,  98, 1280, 491, 1591, 279, 1306, 104,  792, 28, 48, 39, 23, 187},
16531         {160, 1228,  491, 375, 201,  98, 1280, 514, 1728, 570, 1455, 443,  882, 27, 48, 39, 25, 205},
16532         {200, 1228,  450, 349, 201,  98, 1280, 730, 1626, 818, 1476, 732,  834, 20, 41, 36, 24, 200},
16533         { 80, 1250,  555, 365, 201,  98, 1280, 317, 1547, 165, 1341,  65,  819, 33, 48, 40, 24, 188},
16534         {102, 1250,  524, 379, 201,  98, 1280, 494, 1592, 281, 1328, 107,  805, 28, 48, 40, 23, 187},
16535         { 80, 1333,  526, 339, 201,  98, 1280, 281, 1539, 143, 1433,  60,  877, 35, 48, 43, 25, 188},
16536         {217, 1333,  414, 321, 201,  98, 1280, 730, 1626, 818, 1603, 794,  905, 20, 41, 40, 26, 199},
16537         { 75, 1474,  486, 302, 199,  98, 1280, 206, 1523, 101, 1578,  47,  977, 37, 48, 48, 28, 186},
16538         {100, 1474,  465, 311, 201,  98, 1280, 353, 1556, 187, 1581,  86,  964, 32, 48, 47, 28, 185},
16539         {150, 1474,  436, 296, 190,  98, 1280, 336, 1631, 334, 1638, 293, 1102, 33, 48, 46, 31, 205},
16540         { 40, 1536,  479, 285, 190,  98, 1280, 112, 1505,  53, 1574,  25, 1026, 40, 48, 48, 29, 186},
16541         {100, 1536,  450, 297, 193,  98, 1280, 328, 1550, 171, 1586,  79, 1006, 33, 48, 48, 29, 184},
16542         {150, 1536,  421, 283, 182,  98, 1280, 313, 1620, 306, 1638, 269, 1153, 34, 48, 46, 33, 204},
16543         {200, 1536,  392, 299, 180,  98, 1280, 514, 1728, 570, 1638, 498, 1104, 27, 48, 44, 32, 200},
16544         {240, 1536,  366, 301, 178,  98, 1280, 686, 1755, 818, 1638, 742, 1056, 22, 45, 41, 31, 196}};
16545 
16546 #if (MYKONOS_VERBOSE == 1)
16547     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_loadAdcProfiles\n");
16548 #endif
16549 
16550     vcoDiv = (uint32_t)device->clocks->clkPllVcoDiv;
16551     switch (vcoDiv)
16552     {
16553         case VCODIV_1:
16554             vcoDivTimes10 = 10;
16555             break;
16556         case VCODIV_1p5:
16557             vcoDivTimes10 = 15;
16558             break;
16559         case VCODIV_2:
16560             vcoDivTimes10 = 20;
16561             break;
16562         case VCODIV_3:
16563             vcoDivTimes10 = 30;
16564             break;
16565         default:
16566         {
16567             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_ADCPROFILE_INV_VCODIV,
16568                     getMykonosErrorMessage(MYKONOS_ERR_LOAD_ADCPROFILE_INV_VCODIV));
16569             return MYKONOS_ERR_LOAD_ADCPROFILE_INV_VCODIV;
16570         }
16571     }
16572 
16573     hsDigClk_MHz = device->clocks->clkPllVcoFreq_kHz / vcoDivTimes10 / 100 / device->clocks->clkPllHsDiv;
16574 
16575     /* If Tx Profile is valid, set loopback ADC profile based on Tx primary signal BW */
16576     if ((device->profilesValid & TX_PROFILE_VALID) > 0)
16577     {
16578         /* If custom profile, load it */
16579         if (device->obsRx->customLoopbackAdcProfile != NULL)
16580         {
16581             for (i = 0; i < NUM_ADCPROFILE_COEFS; i++)
16582             {
16583                 adcProfile[i * 2] = device->obsRx->customLoopbackAdcProfile[i] & 0xFF;
16584                 adcProfile[i * 2 + 1] = (device->obsRx->customLoopbackAdcProfile[i] >> 8) & 0xFF;
16585             }
16586         }
16587         else
16588         {
16589             /* Tx requires ORx profile is configured */
16590             if (((device->profilesValid & TX_PROFILE_VALID) > 0) && ((device->profilesValid & ORX_PROFILE_VALID) == 0))
16591             {
16592                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_ADCPROFILE_MISSING_ORX_PROFILE,
16593                         getMykonosErrorMessage(MYKONOS_ERR_LOAD_ADCPROFILE_MISSING_ORX_PROFILE));
16594                 return MYKONOS_ERR_LOAD_ADCPROFILE_MISSING_ORX_PROFILE;
16595             }
16596 
16597             if (device->obsRx->orxProfile->adcDiv == 0)
16598             {
16599                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_ADCPROFILE_ORXADCDIV_ZERO,
16600                         getMykonosErrorMessage(MYKONOS_ERR_LOAD_ADCPROFILE_ORXADCDIV_ZERO));
16601                 return MYKONOS_ERR_LOAD_ADCPROFILE_ORXADCDIV_ZERO;
16602             }
16603 
16604             adcClk_MHz = hsDigClk_MHz / device->obsRx->orxProfile->adcDiv;
16605 
16606             /* find correct ADC profile in the LUT */
16607             profileIndex = NUM_ADC_PROFILES;
16608             for (i = 0; i < NUM_ADC_PROFILES; i++)
16609             {
16610                 /* Find a row in the LUT that matches the ADC clock frequency */
16611                 if ((adcProfileLut[i][1] == adcClk_MHz) && (adcProfileLut[i][0] >= (device->tx->txProfile->primarySigBandwidth_Hz / 1000000)))
16612                 {
16613                     profileIndex = i;
16614                     break;
16615                 }
16616             }
16617 
16618             /* Verify that a profile was found in the LUT, if not return error */
16619             /* In this case a custom profile would need to be passed in */
16620             if (profileIndex >= NUM_ADC_PROFILES)
16621             {
16622                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_LBREQUIRED,
16623                         getMykonosErrorMessage(MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_LBREQUIRED));
16624                 return MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_LBREQUIRED;
16625             }
16626 
16627             for (i = 0; i < NUM_ADCPROFILE_COEFS; i++)
16628             {
16629                 adcProfile[i * 2] = adcProfileLut[profileIndex][i + 2] & 0xFF;
16630                 adcProfile[i * 2 + 1] = (adcProfileLut[profileIndex][i + 2] >> 8) & 0xFF;
16631             }
16632         }
16633 
16634         /* writing to the ARM memory: Set Loopback ADC Profile based on Tx Primary signal Bandwidth */
16635         retVal = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR + ARM_CONFIG_OFFSET + 96, &adcProfile[0], sizeof(adcProfile));
16636         if (retVal)
16637         {
16638             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_LBADCPROFILE_ARMMEM_FAILED,
16639                     getMykonosErrorMessage(MYKONOS_ERR_LOAD_LBADCPROFILE_ARMMEM_FAILED));
16640             return MYKONOS_ERR_LOAD_LBADCPROFILE_ARMMEM_FAILED;
16641         }
16642     }
16643 
16644     if ((device->profilesValid & RX_PROFILE_VALID) > 0)
16645     {
16646         /* If custom profile, load it */
16647         if (device->rx->rxProfile->customAdcProfile != NULL)
16648         {
16649             for (i = 0; i < NUM_ADCPROFILE_COEFS; i++)
16650             {
16651                 adcProfile[i * 2] = device->rx->rxProfile->customAdcProfile[i] & 0xFF;
16652                 adcProfile[i * 2 + 1] = (device->rx->rxProfile->customAdcProfile[i] >> 8) & 0xFF;
16653             }
16654         }
16655         else
16656         {
16657             if (device->rx->rxProfile->adcDiv == 0)
16658             {
16659                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_ADCPROFILE_RXADCDIV_ZERO,
16660                         getMykonosErrorMessage(MYKONOS_ERR_LOAD_ADCPROFILE_RXADCDIV_ZERO));
16661                 return MYKONOS_ERR_LOAD_ADCPROFILE_RXADCDIV_ZERO;
16662             }
16663 
16664             adcClk_MHz = hsDigClk_MHz / device->rx->rxProfile->adcDiv;
16665 
16666             /* find correct ADC profile in the LUT */
16667             profileIndex = NUM_ADC_PROFILES;
16668             for (i = 0; i < NUM_ADC_PROFILES; i++)
16669             {
16670                 /* Find a row in the LUT that matches the ADC clock frequency */
16671                 if ((adcProfileLut[i][1] == adcClk_MHz) && (adcProfileLut[i][0] >= (device->rx->rxProfile->rfBandwidth_Hz / 1000000)))
16672                 {
16673                     profileIndex = i;
16674                     break;
16675                 }
16676             }
16677 
16678             /* Verify that a profile was found in the LUT, if not return error */
16679             /* In this case a custom profile would need to be passed in */
16680             if (profileIndex >= NUM_ADC_PROFILES)
16681             {
16682                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_RXREQUIRED,
16683                         getMykonosErrorMessage(MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_RXREQUIRED));
16684                 return MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_RXREQUIRED;
16685             }
16686 
16687             for (i = 0; i < NUM_ADCPROFILE_COEFS; i++)
16688             {
16689                 adcProfile[i * 2] = adcProfileLut[profileIndex][i + 2] & 0xFF;
16690                 adcProfile[i * 2 + 1] = (adcProfileLut[profileIndex][i + 2] >> 8) & 0xFF;
16691             }
16692         }
16693 
16694         /* writing to the ARM memory with ADC Profile for Rx path */
16695         retVal = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR + ARM_CONFIG_OFFSET, &adcProfile[0], sizeof(adcProfile));
16696         if (retVal)
16697         {
16698             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_RXADCPROFILE_ARMMEM_FAILED,
16699                     getMykonosErrorMessage(MYKONOS_ERR_LOAD_RXADCPROFILE_ARMMEM_FAILED));
16700             return MYKONOS_ERR_LOAD_RXADCPROFILE_ARMMEM_FAILED;
16701         }
16702 
16703         /* writing to the ARM memory: Set Loopback ADC Profile = Rx ADC Profile ONLY if Tx profile is not valid */
16704         if ((device->profilesValid & TX_PROFILE_VALID) == 0)
16705         {
16706             retVal = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR + ARM_CONFIG_OFFSET + 96, &adcProfile[0], sizeof(adcProfile));
16707             if (retVal)
16708             {
16709                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_LBADCPROFILE_ARMMEM_FAILED,
16710                         getMykonosErrorMessage(MYKONOS_ERR_LOAD_LBADCPROFILE_ARMMEM_FAILED));
16711                 return MYKONOS_ERR_LOAD_LBADCPROFILE_ARMMEM_FAILED;
16712             }
16713         }
16714     }
16715 
16716     if ((device->profilesValid & ORX_PROFILE_VALID) > 0)
16717     {
16718         /* If custom profile, load it */
16719         if (device->obsRx->orxProfile->customAdcProfile != NULL)
16720         {
16721             for (i = 0; i < NUM_ADCPROFILE_COEFS; i++)
16722             {
16723                 adcProfile[i * 2] = device->obsRx->orxProfile->customAdcProfile[i] & 0xFF;
16724                 adcProfile[i * 2 + 1] = (device->obsRx->orxProfile->customAdcProfile[i] >> 8) & 0xFF;
16725             }
16726         }
16727         else
16728         {
16729             if (device->obsRx->orxProfile->adcDiv == 0)
16730             {
16731                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_ADCPROFILE_ORXADCDIV_ZERO,
16732                         getMykonosErrorMessage(MYKONOS_ERR_LOAD_ADCPROFILE_ORXADCDIV_ZERO));
16733                 return MYKONOS_ERR_LOAD_ADCPROFILE_ORXADCDIV_ZERO;
16734             }
16735 
16736             adcClk_MHz = hsDigClk_MHz / device->obsRx->orxProfile->adcDiv;
16737 
16738             /* find correct ADC profile in the LUT */
16739             profileIndex = NUM_ADC_PROFILES;
16740             for (i = 0; i < NUM_ADC_PROFILES; i++)
16741             {
16742                 /* Find a row in the LUT that matches the ADC clock frequency */
16743                 if ((adcProfileLut[i][1] == adcClk_MHz) && (adcProfileLut[i][0] >= (device->obsRx->orxProfile->rfBandwidth_Hz / 1000000)))
16744                 {
16745                     profileIndex = i;
16746                     break;
16747                 }
16748             }
16749 
16750             /* Verify that a profile was found in the LUT, if not return error */
16751             /* In this case a custom profile would need to be passed in */
16752             if (profileIndex >= NUM_ADC_PROFILES)
16753             {
16754                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_ORXREQUIRED,
16755                         getMykonosErrorMessage(MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_ORXREQUIRED));
16756                 return MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_ORXREQUIRED;
16757             }
16758 
16759             for (i = 0; i < NUM_ADCPROFILE_COEFS; i++)
16760             {
16761                 adcProfile[i * 2] = adcProfileLut[profileIndex][i + 2] & 0xFF;
16762                 adcProfile[i * 2 + 1] = (adcProfileLut[profileIndex][i + 2] >> 8) & 0xFF;
16763             }
16764         }
16765 
16766         /* writing to the ARM memory with ADC Profile for ORx path */
16767         retVal = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR + ARM_CONFIG_OFFSET + 32, &adcProfile[0], sizeof(adcProfile));
16768         if (retVal)
16769         {
16770             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_ORXADCPROFILE_ARMMEM_FAILED,
16771                     getMykonosErrorMessage(MYKONOS_ERR_LOAD_ORXADCPROFILE_ARMMEM_FAILED));
16772             return MYKONOS_ERR_LOAD_ORXADCPROFILE_ARMMEM_FAILED;
16773         }
16774 
16775         /* If Rx and Tx Profiles are not valid, set Loopback ADC profile to ORx ADC Profile */
16776         if (((device->profilesValid & TX_PROFILE_VALID) == 0) && ((device->profilesValid & RX_PROFILE_VALID) == 0))
16777         {
16778             retVal = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR + ARM_CONFIG_OFFSET + 96, &adcProfile[0], sizeof(adcProfile));
16779             if (retVal)
16780             {
16781                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_LBADCPROFILE_ARMMEM_FAILED,
16782                         getMykonosErrorMessage(MYKONOS_ERR_LOAD_LBADCPROFILE_ARMMEM_FAILED));
16783                 return MYKONOS_ERR_LOAD_LBADCPROFILE_ARMMEM_FAILED;
16784             }
16785         }
16786     }
16787 
16788     if ((device->profilesValid & SNIFF_PROFILE_VALID) > 0)
16789     {
16790         /* If custom profile, load it */
16791         if (device->obsRx->snifferProfile->customAdcProfile != NULL)
16792         {
16793             for (i = 0; i < NUM_ADCPROFILE_COEFS; i++)
16794             {
16795                 adcProfile[i * 2] = device->obsRx->snifferProfile->customAdcProfile[i] & 0xFF;
16796                 adcProfile[i * 2 + 1] = (device->obsRx->snifferProfile->customAdcProfile[i] >> 8) & 0xFF;
16797             }
16798         }
16799         else
16800         {
16801 
16802             if (device->obsRx->snifferProfile->adcDiv == 0)
16803             {
16804                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_ADCPROFILE_SNRX_ADCDIV_ZERO,
16805                         getMykonosErrorMessage(MYKONOS_ERR_LOAD_ADCPROFILE_SNRX_ADCDIV_ZERO));
16806                 return MYKONOS_ERR_LOAD_ADCPROFILE_SNRX_ADCDIV_ZERO;
16807             }
16808 
16809             adcClk_MHz = hsDigClk_MHz / device->obsRx->snifferProfile->adcDiv;
16810 
16811             /* find correct ADC profile in the LUT */
16812             profileIndex = NUM_ADC_PROFILES;
16813             for (i = 0; i < NUM_ADC_PROFILES; i++)
16814             {
16815                 /* Find a row in the LUT that matches the ADC clock frequency */
16816                 if ((adcProfileLut[i][1] == adcClk_MHz) && (adcProfileLut[i][0] >= (device->obsRx->snifferProfile->rfBandwidth_Hz / 1000000)))
16817                 {
16818                     profileIndex = i;
16819                     break;
16820                 }
16821             }
16822 
16823             /* Verify that a profile was found in the LUT, if not return error */
16824             /* In this case a custom profile would need to be passed in */
16825             if (profileIndex >= NUM_ADC_PROFILES)
16826             {
16827                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_SNRXREQUIRED,
16828                         getMykonosErrorMessage(MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_SNRXREQUIRED));
16829                 return MYKONOS_ERR_LOAD_ADCPROFILE_CUSTOM_SNRXREQUIRED;
16830             }
16831 
16832             for (i = 0; i < NUM_ADCPROFILE_COEFS; i++)
16833             {
16834                 adcProfile[i * 2] = adcProfileLut[profileIndex][i + 2] & 0xFF;
16835                 adcProfile[i * 2 + 1] = (adcProfileLut[profileIndex][i + 2] >> 8) & 0xFF;
16836             }
16837         }
16838 
16839         /* writing to the ARM memory with ADC Profile for sniffer Rx path */
16840         retVal = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR + ARM_CONFIG_OFFSET + 64, &adcProfile[0], sizeof(adcProfile));
16841         if (retVal)
16842         {
16843             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_SNRXADCPROFILE_ARMMEM_FAILED,
16844                     getMykonosErrorMessage(MYKONOS_ERR_LOAD_SNRXADCPROFILE_ARMMEM_FAILED));
16845             return MYKONOS_ERR_LOAD_SNRXADCPROFILE_ARMMEM_FAILED;
16846         }
16847 
16848         /* If Tx, Rx, and ORx Profiles are not valid, set Loopback ADC profile to Sniffer Rx ADC Profile */
16849         if (((device->profilesValid & TX_PROFILE_VALID) == 0) && ((device->profilesValid & RX_PROFILE_VALID) == 0) && ((device->profilesValid & ORX_PROFILE_VALID) == 0))
16850         {
16851             retVal = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR + ARM_CONFIG_OFFSET + 96, &adcProfile[0], sizeof(adcProfile));
16852             if (retVal)
16853             {
16854                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_LOAD_LBADCPROFILE_ARMMEM_FAILED,
16855                         getMykonosErrorMessage(MYKONOS_ERR_LOAD_LBADCPROFILE_ARMMEM_FAILED));
16856                 return MYKONOS_ERR_LOAD_LBADCPROFILE_ARMMEM_FAILED;
16857             }
16858         }
16859     }
16860 
16861     return MYKONOS_ERR_OK;
16862 }
16863 
16864 /**
16865  * \brief Helper function to calculate commonly used digital clock frequencies in the device
16866  *
16867  * User should not need to call this function normally.  It is called automatically
16868  * within other API functions to calculate the main digital clock.  If the pointers
16869  * to the return parameters are NULL, that calculation will be skipped and not
16870  * returned.
16871  *
16872  *
16873  * <B>Dependencies</B>
16874  * -device->clocks->clkPllVcoFreq_kHz;
16875  * -device->clocks->clkPllVcoDiv;
16876  * -device->clocks->clkPllHsDiv;
16877  *
16878  * \param device Pointer to the device settings structure
16879  * \param hsDigClk_kHz Return value for the calculated Mykonos high speed Digital clock at the output of the CLKPLL in kHz
16880  * \param hsDigClkDiv4or5_kHz Return value for the Mykonos high speed digital clock divided by 4 or 5 in kHz
16881  *
16882  * \retval MYKONOS_ERR_OK Function completed successfully
16883  * \retval MYKONOS_ERR_CALCDIGCLK_NULLDEV_PARAM device parameter is a NULL pointer
16884  * \retval MYKONOS_ERR_CALCDIGCLK_NULL_CLKSTRUCT device->clocks structure is a NULL pointer
16885  * \retval MYKONOS_ERR_CLKPLL_INV_VCODIV Invalid CLKPLL VCO divider in device->clocks->clkPllVcoDiv
16886  * \retval MYKONOS_ERR_CLKPLL_INV_HSDIV Invalid CLKPLL High speed divider in device->clocks->clkPllHsDiv
16887  */
MYKONOS_calculateDigitalClocks(mykonosDevice_t * device,uint32_t * hsDigClk_kHz,uint32_t * hsDigClkDiv4or5_kHz)16888 static mykonosErr_t MYKONOS_calculateDigitalClocks(mykonosDevice_t *device, uint32_t *hsDigClk_kHz, uint32_t *hsDigClkDiv4or5_kHz)
16889 {
16890     uint32_t hsclkRate_kHz = 0;
16891     uint32_t clkPllVcoFrequency_kHz = 0;
16892     mykonosVcoDiv_t vcoDiv = VCODIV_1;
16893     uint8_t hsDiv = 4;
16894 
16895     if (device == NULL)
16896     {
16897         CMB_writeToLog(ADIHAL_LOG_ERROR, 0, MYKONOS_ERR_CALCDIGCLK_NULLDEV_PARAM, getMykonosErrorMessage(MYKONOS_ERR_CALCDIGCLK_NULLDEV_PARAM));
16898         return MYKONOS_ERR_CALCDIGCLK_NULLDEV_PARAM;
16899     }
16900 
16901     if ((device->clocks == NULL))
16902     {
16903         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CALCDIGCLK_NULL_CLKSTRUCT,
16904                 getMykonosErrorMessage(MYKONOS_ERR_CALCDIGCLK_NULL_CLKSTRUCT));
16905         return MYKONOS_ERR_CALCDIGCLK_NULL_CLKSTRUCT;
16906     }
16907 
16908     clkPllVcoFrequency_kHz = device->clocks->clkPllVcoFreq_kHz;
16909     vcoDiv = device->clocks->clkPllVcoDiv;
16910     hsDiv = device->clocks->clkPllHsDiv;
16911 
16912     switch (vcoDiv)
16913     {
16914         case VCODIV_1:
16915             hsclkRate_kHz = clkPllVcoFrequency_kHz;
16916             break;
16917         case VCODIV_1p5:
16918             hsclkRate_kHz = (clkPllVcoFrequency_kHz / 15) * 10;
16919             break;
16920         case VCODIV_2:
16921             hsclkRate_kHz = clkPllVcoFrequency_kHz >> 1;
16922             break;
16923         case VCODIV_3:
16924             hsclkRate_kHz = (clkPllVcoFrequency_kHz / 30) * 10;
16925             break;
16926         default:
16927         {
16928             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CLKPLL_INV_VCODIV, getMykonosErrorMessage(MYKONOS_ERR_CLKPLL_INV_VCODIV));
16929             return MYKONOS_ERR_CLKPLL_INV_VCODIV;
16930         }
16931     }
16932 
16933     switch (hsDiv)
16934     {
16935         case 4:
16936             hsDiv = 4;
16937             break;
16938         case 5:
16939             hsDiv = 5;
16940             break;
16941         default:
16942         {
16943             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CLKPLL_INV_HSDIV, getMykonosErrorMessage(MYKONOS_ERR_CLKPLL_INV_HSDIV));
16944             return MYKONOS_ERR_CLKPLL_INV_HSDIV;
16945         }
16946     }
16947 
16948     if (hsDigClk_kHz != NULL)
16949     {
16950         *hsDigClk_kHz = hsclkRate_kHz / hsDiv;
16951     }
16952 
16953     if (hsDigClkDiv4or5_kHz != NULL)
16954     {
16955         /* This digital div 4 or 5 is always mutually exclusive with the HS Divider (4 or 5) to always
16956          * create a /20 from the hsclk.
16957          */
16958         *hsDigClkDiv4or5_kHz = hsclkRate_kHz / 20;
16959     }
16960 
16961     return MYKONOS_ERR_OK;
16962 }
16963 
16964 /**
16965  * \brief Performs reset to the External Tx LO Leakage tracking calibration channel estimate
16966  *
16967  * <B>Dependencies</B>
16968  * - device->spiSettings->chipSelectIndex
16969  *
16970  * \param device Pointer to the Mykonos device data structure containing settings
16971  * \param channelSel Enum selects the channel to reset
16972  *
16973  * \retval MYKONOS_ERR_RESET_TXLOL_INV_PARAM Selected channel is not valid
16974  * \retval MYKONOS_ERR_RESET_TXLOL_ARMERROR ARM error
16975  * \retval MYKONOS_ERR_OK Function completed successfully
16976  */
MYKONOS_resetExtTxLolChannel(mykonosDevice_t * device,mykonosTxChannels_t channelSel)16977 mykonosErr_t MYKONOS_resetExtTxLolChannel(mykonosDevice_t *device, mykonosTxChannels_t channelSel)
16978 {
16979     const uint8_t TXLOL_RESET_CHANNEL_ESTIMATE = 0x01;
16980     const uint32_t GETTXLOLSTATUS_TIMEOUT_MS = 1000;
16981 
16982     mykonosErr_t retVal = MYKONOS_ERR_OK;
16983     uint8_t extData[3] = {MYKONOS_ARM_OBJECTID_GS_TRACKCALS, TXLOL_RESET_CHANNEL_ESTIMATE, 0};
16984     uint8_t cmdStatusByte = 0;
16985     uint8_t armErrorFlag = 0;
16986 
16987 #if (MYKONOS_VERBOSE == 1)
16988     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_resetExtTxLolChannel()\n");
16989 #endif
16990 
16991     /* Check Channel */
16992     switch (channelSel)
16993     {
16994         case TX1:
16995             extData[2] = 0x01;
16996             break;
16997         case TX2:
16998             extData[2] = 0x02;
16999             break;
17000         case TX1_TX2:
17001             extData[2] = 0x03;
17002             break;
17003         default:
17004             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_RESET_TXLOL_INV_PARAM,
17005                     getMykonosErrorMessage(MYKONOS_ERR_RESET_TXLOL_INV_PARAM));
17006             return MYKONOS_ERR_RESET_TXLOL_INV_PARAM;
17007     }
17008 
17009     /* throw error if not in the right state */
17010     retVal = MYKONOS_checkArmState(device, (MYK_ARM_IDLE | MYK_ARM_RADIO_ON));
17011     if (retVal)
17012     {
17013         return retVal;
17014     }
17015 
17016     retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_SET_OPCODE, &extData[0], sizeof(extData));
17017     if (retVal)
17018     {
17019         return retVal;
17020     }
17021     retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_SET_OPCODE, GETTXLOLSTATUS_TIMEOUT_MS, &cmdStatusByte);
17022 
17023     /* Error check WaitArmCmdStatus return */
17024     armErrorFlag = (cmdStatusByte >> 1);
17025     if (armErrorFlag > 0)
17026     {
17027         return MYKONOS_ERR_RESET_TXLOL_ARMERROR;
17028     }
17029 
17030     return retVal;
17031 }
17032 
17033 /**
17034  * \brief Configures the Radio power up/down control for Rx and Tx paths to be controlled by pins
17035  *        (TX1/2_ENABLE, RX1/2_ENABLE, and GPIO pins) or an API function call.
17036  *
17037  * The BBP should not have to call this as it will automatically be setup at the end of the
17038  * MYKONOS_loadArmFromBinary() function call.  If the BBP wishes to change the radio power up/down
17039  * control method this function can be called again to change the configuration while
17040  * the ARM is in the radioOff state.
17041  *
17042  * <B>Dependencies</B>
17043  * - device->spiSettings->chipSelectIndex
17044  * - device->auxIo->armGpio->useRx2EnablePin
17045  * - device->auxIo->armGpio->useTx2EnablePin
17046  * - device->auxIo->armGpio->txRxPinMode
17047  * - device->auxIo->armGpio->orxPinMode
17048  *
17049  * \param device is a pointer to the device settings structure
17050  *
17051  * \retval MYKONOS_ERR_OK Function completed successfully
17052  * \retval MYKONOS_ERR_SET_RADIOCTRL_PINS_ARMERROR ARM returned an error and did not accept the command.
17053  */
MYKONOS_setRadioControlPinMode(mykonosDevice_t * device)17054 mykonosErr_t MYKONOS_setRadioControlPinMode(mykonosDevice_t *device)
17055 {
17056     uint8_t extData[4] = {0x81, 0, 0, 4}; /*Object ID 0x81 (radio control structure), offset lsb, offset msb, length*/
17057     uint8_t armRadioControlStruct[4] = {0};
17058     uint32_t timeoutMs = 0;
17059     uint8_t cmdStatusByte = 0;
17060     mykonosErr_t retval = MYKONOS_ERR_OK;
17061 
17062 #if MYKONOS_VERBOSE == 1
17063     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setRadioControlPinMode()\n");
17064 #endif
17065 
17066     /* write ARM radio control structure to enable pin mode/command mode */
17067     if (device->auxIo->armGpio->useRx2EnablePin > 0)
17068     {
17069         armRadioControlStruct[0] = 0x01;
17070     }
17071 
17072     if (device->auxIo->armGpio->useTx2EnablePin > 0)
17073     {
17074         armRadioControlStruct[1] = 0x01;
17075     }
17076 
17077     if (device->auxIo->armGpio->txRxPinMode > 0)
17078     {
17079         armRadioControlStruct[2] = 0x01;
17080     }
17081 
17082     if (device->auxIo->armGpio->orxPinMode > 0)
17083     {
17084         armRadioControlStruct[3] = 0x01;
17085     }
17086 
17087     retval = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &armRadioControlStruct[0], sizeof(armRadioControlStruct));
17088     if (retval != MYKONOS_ERR_OK)
17089     {
17090         return retval;
17091     }
17092 
17093     retval = MYKONOS_sendArmCommand(device, MYKONOS_ARM_WRITECFG_OPCODE, &extData[0], sizeof(extData));
17094     if (retval != MYKONOS_ERR_OK)
17095     {
17096         return retval;
17097     }
17098 
17099     timeoutMs = 1000;
17100     retval = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_WRITECFG_OPCODE, timeoutMs, &cmdStatusByte);
17101     if (retval != MYKONOS_ERR_OK)
17102     {
17103         return retval;
17104     }
17105 
17106     if (cmdStatusByte > 0)
17107     {
17108         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex,  MYKONOS_ERR_SET_RADIOCTRL_PINS_ARMERROR,
17109                 getMykonosErrorMessage(MYKONOS_ERR_SET_RADIOCTRL_PINS_ARMERROR));
17110         return MYKONOS_ERR_SET_RADIOCTRL_PINS_ARMERROR;
17111     }
17112 
17113     return MYKONOS_ERR_OK;
17114 }
17115 
17116 /**
17117  * \brief Sets the measure count which is the number of samples taken before DC offset correction is applied for the given Rf channel.
17118  *   This value cannot be changed after ARM initialization.
17119  *   channel can be one of the following ( ::mykonosDcOffsetChannels_t ).
17120  *
17121  *     Channel             |  Channel description
17122  * ------------------------|--------------------------------
17123  *  MYK_DC_OFFSET_RX_CHN   | Selects Rx channel
17124  *  MYK_DC_OFFSET_ORX_CHN  | Selects ORx channel
17125  *  MYK_DC_OFFSET_SNF_CHN  | Selects Sniffer channel
17126  *
17127  * The total duration 'tCount' is calculated as,
17128  * [tCount = (measureCount * 1024) / IQ data rate of the channel].
17129  * There is a minimum limit for the value of measureCount, the value passed should satisfy the condition 'tCount > 800us'.
17130  *
17131  * <B>Dependencies</B>
17132  * - device->spiSettings->chipSelectIndex
17133  *
17134  * \param device Pointer to the Mykonos device data structure containing settings
17135  * \param channel receive channel to be selected.
17136  * \param measureCount value to be configured for the selected channel which is the number of samples taken before DC offset correction is applied.
17137  *
17138  * \retval MYKONOS_ERR_DC_OFFSET_INV_CHAN channel passed to the function is invalid, refer mykonosDcOffsetChannels_t enum for valid channels.
17139  * \retval MYKONOS_ERR_SET_RF_DC_OFFSET_INV_MEASURECNT measurement count value passed is invalid
17140  * \retval MYKONOS_ERR_OK Function completed successfully
17141  * \retval MYKONOS_ERR_SET_RF_DC_OFFSET_MEASURECNT_MIN_LIMIT The measureCount value passed is less than the minimum limit allowed.
17142  */
MYKONOS_setRfDcOffsetCnt(mykonosDevice_t * device,mykonosDcOffsetChannels_t channel,uint16_t measureCount)17143 mykonosErr_t MYKONOS_setRfDcOffsetCnt(mykonosDevice_t *device, mykonosDcOffsetChannels_t channel, uint16_t measureCount)
17144 {
17145     mykonosErr_t retVal = MYKONOS_ERR_OK;
17146     uint16_t REG_ADDRESS_H = 0;                                         /* Address for Higher byte  */
17147     uint16_t REG_ADDRESS_L = 0;                                         /* Address for Lower byte  */
17148     uint16_t MEASURE_CNT_RANGE = 0xFFFF;                                /* Mask for measure count range checking */
17149 
17150     const uint8_t  MEASURE_CNT_H = (measureCount & 0xFF00) >> 8;         /* Higher byte of the measure count */
17151     const uint8_t  MEASURE_CNT_L = measureCount & 0x00FF;                /* Lower byte of the measure count */
17152 
17153     /* Calculation of Total Duration [ tCount = (measureCount * 0x400) / IQ data rate cycles ] */
17154     const uint8_t FACTOR = 10;
17155     uint32_t tCount = (measureCount << FACTOR);                          /* precalculations for Total duration in us */
17156     uint32_t IQ_RATE = 0;
17157 
17158 #if (MYKONOS_VERBOSE == 1)
17159     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setRfDcOffsetCnt()\n");
17160 #endif
17161 
17162     /* check for channel and update the appropriate register address */
17163     switch (channel)
17164     {
17165         case MYK_DC_OFFSET_RX_CHN:
17166             REG_ADDRESS_H = MYKONOS_ADDR_RFDC_MEASURE_COUNT_2;
17167             REG_ADDRESS_L = MYKONOS_ADDR_RFDC_MEASURE_COUNT_1;
17168             IQ_RATE = device->rx->rxProfile->iqRate_kHz / 1000;          /* IQ Rate to calculate total duration */
17169             break;
17170         case MYK_DC_OFFSET_ORX_CHN:
17171             REG_ADDRESS_H = MYKONOS_ADDR_RFDC_ORX_MEASURE_COUNT_2;
17172             REG_ADDRESS_L = MYKONOS_ADDR_RFDC_ORX_MEASURE_COUNT_1;
17173             IQ_RATE = device->obsRx->orxProfile->iqRate_kHz / 1000;      /* IQ Rate to calculate total duration */
17174             break;
17175         case MYK_DC_OFFSET_SNF_CHN:
17176             REG_ADDRESS_H = MYKONOS_ADDR_RFDC_SNF_MEASURE_COUNT_2;
17177             REG_ADDRESS_L = MYKONOS_ADDR_RFDC_SNF_MEASURE_COUNT_1;
17178             /* measureCount for Sniffer should be 10 bit */
17179             MEASURE_CNT_RANGE= 0x03FF;
17180             IQ_RATE = device->obsRx->snifferProfile->iqRate_kHz / 1000;  /* IQ Rate to calculate total duration */
17181             break;
17182 
17183         default:
17184             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DC_OFFSET_INV_CHAN,
17185                            getMykonosErrorMessage(MYKONOS_ERR_DC_OFFSET_INV_CHAN));
17186             return MYKONOS_ERR_DC_OFFSET_INV_CHAN;
17187     }
17188 
17189     tCount = (tCount / IQ_RATE);                                          /* Calculating total duration in us */
17190     if (tCount < 800)
17191     {
17192         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_RF_DC_OFFSET_MEASURECNT_MIN_LIMIT,
17193                        getMykonosErrorMessage(MYKONOS_ERR_SET_RF_DC_OFFSET_MEASURECNT_MIN_LIMIT));
17194         return MYKONOS_ERR_SET_RF_DC_OFFSET_MEASURECNT_MIN_LIMIT ;
17195     }
17196 
17197     if ((measureCount < 0x11) || (measureCount & ~MEASURE_CNT_RANGE))
17198     {
17199         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_RF_DC_OFFSET_INV_MEASURECNT,
17200                        getMykonosErrorMessage(MYKONOS_ERR_SET_RF_DC_OFFSET_INV_MEASURECNT));
17201         return MYKONOS_ERR_SET_RF_DC_OFFSET_INV_MEASURECNT ;
17202     }
17203 
17204     CMB_SPIWriteField(device->spiSettings, REG_ADDRESS_H, MEASURE_CNT_H, ((MEASURE_CNT_RANGE >>8) & 0xFF),0);
17205     CMB_SPIWriteByte(device->spiSettings, REG_ADDRESS_L, MEASURE_CNT_L);
17206 
17207     return retVal;
17208 }
17209 
17210 /**
17211  * \brief retrieves the measure count which is the number of samples taken before DC offset correction is applied for the given Rf channel.
17212  *   channel can be one of the following ( ::mykonosDcOffsetChannels_t ).
17213  *
17214  *     Channel             |  Channel description
17215  * ------------------------|--------------------------------
17216  *  MYK_DC_OFFSET_RX_CHN   | Selects Rx channel
17217  *  MYK_DC_OFFSET_ORX_CHN  | Selects ORx channel
17218  *  MYK_DC_OFFSET_SNF_CHN  | Selects Sniffer channel
17219  *
17220  * <B>Dependencies</B>
17221  * - device->spiSettings->chipSelectIndex
17222  *
17223  * \param device Pointer to the Mykonos device data structure containing settings
17224  * \param channel receive channel to be selected.
17225  * \param measureCount pointer to the variable to store the read value.
17226  *
17227  * \retval MYKONOS_ERR_DC_OFFSET_INV_CHAN channel passed to the function is invalid, refer mykonosDcOffsetChannels_t enum for valid channels.
17228  * \retval MYKONOS_ERR_SET_RF_DC_OFFSET_NULL_MEASURECNT passed pointer of measureCount is NULL
17229  * \retval MYKONOS_ERR_OK Function completed successfully
17230  */
MYKONOS_getRfDcOffsetCnt(mykonosDevice_t * device,mykonosDcOffsetChannels_t channel,uint16_t * measureCount)17231 mykonosErr_t MYKONOS_getRfDcOffsetCnt(mykonosDevice_t *device, mykonosDcOffsetChannels_t channel, uint16_t *measureCount)
17232 {
17233     mykonosErr_t retVal = MYKONOS_ERR_OK;
17234     uint16_t REG_ADDRESS_H = 0;                                                         /* Address for Higher byte  */
17235     uint16_t REG_ADDRESS_L = 0;                                                         /* Address for Lower byte  */
17236     uint16_t MEASURE_CNT_RANGE = 0xFFFF;                                                /* Mask for measure count range checking */
17237     uint16_t mCount = 0;                                                                /* Temporary variable to store readback from register. */
17238     uint8_t readbackData = 0;
17239 
17240 #if (MYKONOS_VERBOSE == 1)
17241     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getRfDcOffsetCnt()\n");
17242 #endif
17243 
17244     switch (channel)
17245     {
17246         case MYK_DC_OFFSET_RX_CHN:
17247             REG_ADDRESS_H = MYKONOS_ADDR_RFDC_MEASURE_COUNT_2;
17248             REG_ADDRESS_L = MYKONOS_ADDR_RFDC_MEASURE_COUNT_1;
17249             break;
17250         case MYK_DC_OFFSET_ORX_CHN:
17251             REG_ADDRESS_H = MYKONOS_ADDR_RFDC_ORX_MEASURE_COUNT_2;
17252             REG_ADDRESS_L = MYKONOS_ADDR_RFDC_ORX_MEASURE_COUNT_1;
17253             break;
17254         case MYK_DC_OFFSET_SNF_CHN:
17255             REG_ADDRESS_H = MYKONOS_ADDR_RFDC_SNF_MEASURE_COUNT_2;
17256             REG_ADDRESS_L = MYKONOS_ADDR_RFDC_SNF_MEASURE_COUNT_1;
17257             /* measureCount for Sniffer should be 10 bit */
17258             MEASURE_CNT_RANGE= 0x03FF;
17259             break;
17260 
17261         default:
17262             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DC_OFFSET_INV_CHAN,
17263                            getMykonosErrorMessage(MYKONOS_ERR_DC_OFFSET_INV_CHAN));
17264             return MYKONOS_ERR_DC_OFFSET_INV_CHAN;
17265     }
17266 
17267     if (measureCount == NULL)
17268     {
17269         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_RF_DC_OFFSET_NULL_MEASURECNT,
17270                 getMykonosErrorMessage(MYKONOS_ERR_GET_RF_DC_OFFSET_NULL_MEASURECNT));
17271         return MYKONOS_ERR_GET_RF_DC_OFFSET_NULL_MEASURECNT;
17272     }
17273 
17274     /* Store Higher byte of measureCount */
17275     CMB_SPIReadField(device->spiSettings, REG_ADDRESS_H, &readbackData, ((MEASURE_CNT_RANGE >>8) & 0xFF),0);
17276     mCount = readbackData;
17277     mCount = mCount << 8;
17278 
17279     /* Store Lower byte of measureCount */
17280     readbackData = 0;
17281     CMB_SPIReadByte(device->spiSettings, REG_ADDRESS_L, &readbackData);
17282     mCount = mCount | readbackData;
17283 
17284     *measureCount = mCount;
17285 
17286     return retVal;
17287 }
17288 
17289 /**
17290  * \brief Sets M-Shift value which is the Corner frequency of Rx notch filter for the given channel.
17291  *   channel can be one of the following ( ::mykonosDcOffsetChannels_t ).
17292  *
17293  *     Channel             |  Channel description
17294  * ------------------------|--------------------------------
17295  *  MYK_DC_OFFSET_RX_CHN   | Selects Rx channel
17296  *  MYK_DC_OFFSET_ORX_CHN  | Selects ORx channel
17297  *  MYK_DC_OFFSET_SNF_CHN  | Selects Sniffer channel
17298  *
17299  * <B>Dependencies</B>
17300  * - device->spiSettings->chipSelectIndex
17301  *
17302  * \param device Pointer to the Mykonos device data structure containing settings
17303  * \param channel receive channel to be selected.
17304  * \param mShift value to be configured for the given channel
17305  *
17306  * \retval MYKONOS_ERR_DC_OFFSET_INV_CHAN channel passed to the function is invalid, refer mykonosDcOffsetChannels_t enum for valid channels.
17307  * \retval MYKONOS_ERR_SET_DIG_DC_OFFSET_INV_MSHIFT mShift value passed is invalid.
17308  * \retval MYKONOS_ERR_OK Function completed successfully
17309  */
MYKONOS_setDigDcOffsetMShift(mykonosDevice_t * device,mykonosDcOffsetChannels_t channel,uint8_t mShift)17310 mykonosErr_t MYKONOS_setDigDcOffsetMShift(mykonosDevice_t *device, mykonosDcOffsetChannels_t channel, uint8_t mShift)
17311 {
17312     mykonosErr_t retVal = MYKONOS_ERR_OK;
17313     uint16_t REG_ADDRESS = 0;
17314 
17315     const uint8_t MSHIFT_MIN_RANGE= 0x08;
17316     const uint8_t MSHIFT_MAX_RANGE= 0x14;
17317 
17318 #if (MYKONOS_VERBOSE == 1)
17319     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setDigDcOffsetMShift()\n");
17320 #endif
17321 
17322     if ((mShift < MSHIFT_MIN_RANGE) || (mShift > MSHIFT_MAX_RANGE))
17323     {
17324         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_DIG_DC_OFFSET_INV_MSHIFT,
17325                        getMykonosErrorMessage(MYKONOS_ERR_SET_DIG_DC_OFFSET_INV_MSHIFT));
17326         return MYKONOS_ERR_SET_DIG_DC_OFFSET_INV_MSHIFT;
17327     }
17328 
17329     /* check channel and set the address */
17330     switch (channel)
17331     {
17332         case MYK_DC_OFFSET_RX_CHN:
17333             REG_ADDRESS = MYKONOS_ADDR_DIGITAL_DC_OFFSET_SHIFT;
17334             break;
17335         case MYK_DC_OFFSET_ORX_CHN:
17336             REG_ADDRESS = MYKONOS_ADDR_DIGITAL_DC_OFFSET_CH3_DPD_M_SHIFT;
17337             break;
17338         case MYK_DC_OFFSET_SNF_CHN:
17339             REG_ADDRESS = MYKONOS_ADDR_DIGITAL_DC_OFFSET_SNF;
17340             break;
17341 
17342         default:
17343             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DC_OFFSET_INV_CHAN,
17344                            getMykonosErrorMessage(MYKONOS_ERR_DC_OFFSET_INV_CHAN));
17345             return MYKONOS_ERR_DC_OFFSET_INV_CHAN;
17346     }
17347 
17348     CMB_SPIWriteField(device->spiSettings, REG_ADDRESS, mShift, 0x1F, 0);
17349 
17350     return retVal;
17351 }
17352 
17353 /**
17354  * \brief retrieves the M-Shift value which is the Corner frequency of Rx notch filter for the given channel.
17355  *   channel can be one of the following ( ::mykonosDcOffsetChannels_t ).
17356  *
17357  *     Channel             |  Channel description
17358  * ------------------------|--------------------------------
17359  *  MYK_DC_OFFSET_RX_CHN   | Selects Rx channel
17360  *  MYK_DC_OFFSET_ORX_CHN  | Selects ORx channel
17361  *  MYK_DC_OFFSET_SNF_CHN  | Selects Sniffer channel
17362  *
17363  * <B>Dependencies</B>
17364  * - device->spiSettings->chipSelectIndex
17365  *
17366  * \param device Pointer to the Mykonos device data structure containing settings
17367  * \param channel receive channel to be selected.
17368  * \param mShift Pointer to the variable to store mshift value of the given channel
17369  *
17370  * \retval MYKONOS_ERR_DC_OFFSET_INV_CHAN channel passed to the function is invalid, refer mykonosDcOffsetChannels_t enum for valid channels.
17371  * \retval MYKONOS_ERR_GET_DIG_DC_OFFSET_NULL_MSHIFT mShift pointer is NULL
17372  * \retval MYKONOS_ERR_OK Function completed successfully
17373  */
MYKONOS_getDigDcOffsetMShift(mykonosDevice_t * device,mykonosDcOffsetChannels_t channel,uint8_t * mShift)17374 mykonosErr_t MYKONOS_getDigDcOffsetMShift(mykonosDevice_t *device, mykonosDcOffsetChannels_t channel, uint8_t *mShift)
17375 {
17376     mykonosErr_t retVal = MYKONOS_ERR_OK;
17377     uint16_t REG_ADDRESS = 0x0;
17378     uint8_t readbackData = 0x0;
17379 
17380 #if (MYKONOS_VERBOSE == 1)
17381     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getDigDcOffsetMShift()\n");
17382 #endif
17383 
17384     if (mShift == NULL)
17385     {
17386         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_DIG_DC_OFFSET_NULL_MSHIFT,
17387                 getMykonosErrorMessage(MYKONOS_ERR_GET_DIG_DC_OFFSET_NULL_MSHIFT));
17388         return MYKONOS_ERR_GET_DIG_DC_OFFSET_NULL_MSHIFT;
17389     }
17390 
17391     /* check for the channel and set the address */
17392     switch (channel)
17393     {
17394         case MYK_DC_OFFSET_RX_CHN:
17395             REG_ADDRESS = MYKONOS_ADDR_DIGITAL_DC_OFFSET_SHIFT;
17396             break;
17397         case MYK_DC_OFFSET_ORX_CHN:
17398             REG_ADDRESS = MYKONOS_ADDR_DIGITAL_DC_OFFSET_CH3_DPD_M_SHIFT;
17399             break;
17400         case MYK_DC_OFFSET_SNF_CHN:
17401             REG_ADDRESS = MYKONOS_ADDR_DIGITAL_DC_OFFSET_SNF;
17402             break;
17403 
17404         default:
17405             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DC_OFFSET_INV_CHAN,
17406                            getMykonosErrorMessage(MYKONOS_ERR_DC_OFFSET_INV_CHAN));
17407             return MYKONOS_ERR_DC_OFFSET_INV_CHAN;
17408     }
17409 
17410     CMB_SPIReadField(device->spiSettings, REG_ADDRESS, &readbackData, 0x1F,0);
17411 
17412     *mShift = readbackData;
17413 
17414     return retVal;
17415 }
17416 
17417 /**
17418  * \brief Sets the RF PLL loop filter bandwith.
17419  *
17420  * \pre Command should be called in Radio Off state.  ARM must be  initialized.
17421  *
17422  * \post Loop filter should lock successfully
17423  *
17424  * <B>Dependencies</B>
17425  * - device->spiSettings->chipSelectIndex
17426  * - device->spiSettings
17427  *
17428  * \param device is structure pointer to the MYKONOS data structure containing settings
17429  * \param pllName Name of the PLL to configure.RX_PLL and TX_PLL can be configured.SNIFFER_PLL can not be configured.
17430  * \param loopBandwidth_kHz Desired RF pll bandwith to be set. The valid values range of loopBandwidth_kHz for Rx and Tx is 50 to 750.For SRX valid values lies from 500 to 750.
17431  * \param stability PLL Loop stability to be set.The valid values range of stability is from 3 to 15.
17432  *
17433  * \return MYKONOS_ERR_OK Function completed successfully
17434  * \return MYKONOS_ERR_SETRFPLL_LF_ARMERROR ARM Command to set RF PLL loop filter bandwidth failed
17435  * \return MYKONOS_ERR_SETRFPLL_LF_INV_TXRX_LOOPBANDWIDTH Invalid Tx/Rx value bandwith
17436  * \return MYKONOS_ERR_SETRFPLL_LF_PLLNAME Invalid pllName requested
17437  * \return MYKONOS_ERR_SETRFPLL_LF_INV_STABILITY Invalid stability range, valid range is 3-15
17438  */
MYKONOS_setRfPllLoopFilter(mykonosDevice_t * device,mykonosRfPllName_t pllName,uint16_t loopBandwidth_kHz,uint8_t stability)17439 mykonosErr_t MYKONOS_setRfPllLoopFilter(mykonosDevice_t *device, mykonosRfPllName_t pllName, uint16_t loopBandwidth_kHz, uint8_t stability)
17440 {
17441     const uint8_t SETCMD_OPCODE = 0x0A;
17442     const uint8_t SET_PLL_BANDWIDTH = 0x6D;
17443     const  uint16_t LOOP_BW_HIGH = 750;
17444 
17445     uint16_t LOOP_BW_LOW = 50;
17446     uint8_t extData[4] = {0};
17447     uint8_t cmdStatusByte = 0;
17448     mykonosErr_t retVal = MYKONOS_ERR_OK;
17449     mykonosErr_t errLoopBw = MYKONOS_ERR_OK;
17450     uint32_t timeoutMs = 1000;
17451 
17452 #if (MYKONOS_VERBOSE == 1)
17453     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex,  MYKONOS_ERR_OK, "MYKONOS_setRfPllLoopFilter()\n");
17454 #endif
17455 
17456     switch (pllName)
17457     {
17458         case RX_PLL:
17459         	extData[1] = 0x00;
17460         	LOOP_BW_LOW = 50;
17461         	errLoopBw = MYKONOS_ERR_SETRFPLL_LF_INV_TXRX_LOOPBANDWIDTH;
17462         	break;
17463         case TX_PLL:
17464         	extData[1] = 0x10;
17465         	LOOP_BW_LOW = 50;
17466         	errLoopBw = MYKONOS_ERR_SETRFPLL_LF_INV_TXRX_LOOPBANDWIDTH;
17467         	break;
17468         case SNIFFER_PLL:
17469 #if 0 /* Set for Sniffer PLL loop bandwidth is not supported */
17470         	extData[1] = 0x20;
17471         	LOOP_BW_LOW = 500;
17472         	errLoopBw = MYKONOS_ERR_SETRFPLL_LF_INV_SNF_LOOPBANDWIDTH;
17473         	break;
17474 #endif
17475         default:
17476         {
17477             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETRFPLL_LF_PLLNAME,
17478                     getMykonosErrorMessage(MYKONOS_ERR_SETRFPLL_LF_PLLNAME));
17479             return MYKONOS_ERR_SETRFPLL_LF_PLLNAME;
17480         }
17481     }
17482 
17483     /* Range check for loopBandwidth - Should be between 50kHz and 750kHz for TX/RX and between 500kHz and 750 for SRX*/
17484     if ((loopBandwidth_kHz< LOOP_BW_LOW) || (loopBandwidth_kHz >LOOP_BW_HIGH))
17485     {
17486         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, errLoopBw,
17487                 getMykonosErrorMessage(errLoopBw));
17488         return errLoopBw;
17489     }
17490 
17491     /* Range check for stability - Should be between 3 and 15 */
17492     if ((stability < 3) || (stability > 15))
17493     {
17494         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETRFPLL_LF_INV_STABILITY,
17495                 getMykonosErrorMessage(MYKONOS_ERR_SETRFPLL_LF_INV_STABILITY));
17496     	return MYKONOS_ERR_SETRFPLL_LF_INV_STABILITY;
17497     }
17498 
17499     /* Generate payload for SET command */
17500     extData[0] = SET_PLL_BANDWIDTH;
17501     /*left shift and truncate left side*/
17502     extData[1] |= stability;
17503     extData[2] = (uint8_t)(loopBandwidth_kHz & 0xFF);  //full first byte
17504     extData[3] = (uint8_t)(loopBandwidth_kHz >> 8); //two extra bits
17505 
17506     /* executing the SET command */
17507     retVal = MYKONOS_sendArmCommand(device, SETCMD_OPCODE, &extData[0], sizeof(extData));
17508     if (retVal != MYKONOS_ERR_OK)
17509     {
17510         return retVal;
17511     }
17512 
17513    /* waiting for command to complete */
17514     retVal = MYKONOS_waitArmCmdStatus(device, SETCMD_OPCODE, timeoutMs, &cmdStatusByte);
17515 
17516    /* performing command status check */
17517     if (retVal != MYKONOS_ERR_OK)
17518     {
17519         if (cmdStatusByte > 0)
17520         {
17521             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETRFPLL_LF_ARMERROR,
17522                     getMykonosErrorMessage(MYKONOS_ERR_SETRFPLL_LF_ARMERROR));
17523             return MYKONOS_ERR_SETRFPLL_LF_ARMERROR;
17524         }
17525 
17526         return retVal;
17527     }
17528 
17529     return retVal;
17530 }
17531 
17532 /**
17533  * \brief Gets the RF PLL loop filter bandwidth and stability.
17534  *
17535  * This function is used to get the RF PLL loop bandwidth.  It can get the RX PLL, TX PLL
17536  * Sniffer PLL.
17537  *
17538  * \pre Command can be called in Radio Off state or On state.  ARM must be  initialized.
17539  *
17540  * <B>Dependencies</B>
17541  * - device->spiSettings->chipSelectIndex
17542  * - device->spiSettings
17543  * - device->clocks->deviceClock_kHz
17544  *
17545  * \param device is structure pointer to the MYKONOS data structure containing settings
17546  * \param pllName Name of the PLL for which to read the frequency
17547  * \param loopBandwidth_kHz RF PLL loop bandwidth for the PLL specified
17548  * \param stability RF PLL loop stability
17549  *
17550  * \retval MYKONOS_ERR_OK Function completed successfully
17551  * \retval MYKONOS_ERR_GETRFPLL_LF_INV_PLLNAME Invalid PLL name, can not get PLL frequency.  Use PLL name ENUM.
17552  * \retval MYKONOS_ERR_GETRFPLL_LF_ARMERROR ARM Command to get RF PLL frequency failed
17553  * \retval MYKONOS_ERR_GETRFPLL_LF_NULLPARAM input parameter is NULL
17554  */
MYKONOS_getRfPllLoopFilter(mykonosDevice_t * device,mykonosRfPllName_t pllName,uint16_t * loopBandwidth_kHz,uint8_t * stability)17555 mykonosErr_t MYKONOS_getRfPllLoopFilter(mykonosDevice_t *device, mykonosRfPllName_t pllName, uint16_t *loopBandwidth_kHz, uint8_t *stability)
17556 {
17557     const uint8_t GET_PLL_BANDWIDTH = 0x6D;
17558 
17559     mykonosErr_t retVal = MYKONOS_ERR_OK;
17560     uint8_t armData[8] = {0, 0, 0, 0, 0, 0, 0, 0};
17561     uint8_t extData[2] = {GET_PLL_BANDWIDTH, 0};
17562     uint32_t timeoutMs = 0;
17563     uint8_t cmdStatusByte = 0;
17564 
17565 #if (MYKONOS_VERBOSE == 1)
17566     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex,  MYKONOS_ERR_OK, "MYKONOS_getRfPllLoopFilter()\n");
17567 #endif
17568 
17569     /* Check for NULL */
17570     if ((loopBandwidth_kHz == NULL)|| (stability == NULL))
17571     {
17572         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRFPLL_LF_NULLPARAM,
17573                        getMykonosErrorMessage(MYKONOS_ERR_GETRFPLL_LF_NULLPARAM));
17574         return MYKONOS_ERR_GETRFPLL_LF_NULLPARAM;
17575     }
17576 
17577     switch(pllName)
17578     {
17579         case RX_PLL:      extData[1] = 0x00; break;
17580         case TX_PLL:      extData[1] = 0x10; break;
17581         case SNIFFER_PLL: extData[1] = 0x20; break;
17582         default:
17583         {
17584             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRFPLL_LF_INV_PLLNAME,
17585                            getMykonosErrorMessage(MYKONOS_ERR_GETRFPLL_LF_INV_PLLNAME));
17586             return MYKONOS_ERR_GETRFPLL_LF_INV_PLLNAME;
17587         }
17588     }
17589 	/* executing the GET command */
17590 	retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &extData[0], sizeof(extData));
17591 	if (retVal != MYKONOS_ERR_OK)
17592 	{
17593 		return retVal;
17594 	}
17595 
17596 	timeoutMs = 1000;
17597 
17598     /* waiting for command to complete */
17599 	retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte);
17600 
17601     /* performing command status check */
17602 	if (retVal != MYKONOS_ERR_OK)
17603 	{
17604 		if (cmdStatusByte > 0)
17605 		{
17606 			CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETRFPLL_LF_ARMERROR,
17607 						   getMykonosErrorMessage(MYKONOS_ERR_GETRFPLL_LF_ARMERROR));
17608 			return MYKONOS_ERR_GETRFPLL_LF_ARMERROR;
17609 		}
17610 
17611 		return retVal;
17612 	}
17613 
17614     /* Read from ARM memory */
17615 	retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &armData[0], 8, 1);
17616 	if (retVal != MYKONOS_ERR_OK)
17617 	{
17618 		return retVal;
17619 	}
17620 
17621     /* Assign to variables */
17622     *stability = armData[3];
17623     *loopBandwidth_kHz = (((uint16_t)armData[1]) << 8) | ((uint16_t)armData[0]);
17624 
17625     return MYKONOS_ERR_OK;
17626 }
17627 
17628 /**
17629  * \brief Enable/ Disable Digital DC Offset channels using the channel mask.
17630  *  The mask can be a combination of the following channel values ( ::mykonosRxDcOffsettEn_t ).
17631  *
17632  *     Channel              |  Value  |  Channel description
17633  * -------------------------|---------|--------------------------
17634  *  MYK_DC_OFFSET_ALL_OFF   |   0x00  | Disable all the channels
17635  *  MYK_DC_OFFSET_RX1       |   0x01  | Enables Rx1
17636  *  MYK_DC_OFFSET_RX2       |   0x02  | Enables Rx1
17637  *  MYK_DC_OFFSET_SNF       |   0x04  | Enables Sniffer
17638  *  MYK_DC_OFFSET_ORX       |   0x08  | Enables ORx
17639  *  MYK_DC_OFFSET_AVAILABLE |   0x0F  | Enables all the channels
17640  *
17641  * <B>Dependencies</B>
17642  * - device->spiSettings->chipSelectIndex
17643  *
17644  * \param device Pointer to the Mykonos device data structure containing settings
17645  * \param enableMask with bits of channels to be enabled.
17646  *
17647  * \retval MYKONOS_ERR_DIG_DC_OFFSET_INV_ENABLE_MASK enable mask passed to the function is invalid, refer mykonosRxDcOffsettEn_t enum.
17648  * \retval MYKONOS_ERR_OK Function completed successfully
17649  */
MYKONOS_setDigDcOffsetEn(mykonosDevice_t * device,uint8_t enableMask)17650 mykonosErr_t MYKONOS_setDigDcOffsetEn(mykonosDevice_t *device, uint8_t enableMask)
17651 {
17652     mykonosErr_t retVal = MYKONOS_ERR_OK;
17653     uint16_t REG_ADDRESS = 0x00;
17654     uint8_t dataToWrite = 0x00;
17655 
17656 
17657 #if (MYKONOS_VERBOSE == 1)
17658     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setDigDcOffsetEn()\n");
17659 #endif
17660 
17661     if (enableMask & ~((uint8_t)MYK_DC_OFFSET_AVAILABLE))
17662     {
17663         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DIG_DC_OFFSET_INV_ENABLE_MASK,
17664                 getMykonosErrorMessage(MYKONOS_ERR_DIG_DC_OFFSET_INV_ENABLE_MASK));
17665         return MYKONOS_ERR_DIG_DC_OFFSET_INV_ENABLE_MASK;
17666     }
17667 
17668     REG_ADDRESS = MYKONOS_ADDR_DIGITAL_DC_OFFSET_CONFIG;                           /* Address for Rx Digital tracking Enable bits register */
17669     if (enableMask & ((uint8_t)MYK_DC_OFFSET_RX1 | (uint8_t)MYK_DC_OFFSET_RX2))                      /* Enable / Disable  Rx1 and/or Rx2 */
17670     {
17671         dataToWrite |= ((enableMask & ((uint8_t)MYK_DC_OFFSET_RX1 |(uint8_t) MYK_DC_OFFSET_RX2)) << 1 );
17672     }
17673     CMB_SPIWriteField(device->spiSettings, REG_ADDRESS, dataToWrite, 0x06,0);      /* Write RX enable bits to the register */
17674 
17675     dataToWrite = 0x0;                                                             /* Reset dataToWrite */
17676     REG_ADDRESS = MYKONOS_DIGITAL_DC_OFFSET_CH3_TRACKING;                          /* Address for ORx and Sniffer Digital trackingEnable bits register */
17677     if (enableMask & ((uint8_t)MYK_DC_OFFSET_SNF | (uint8_t)MYK_DC_OFFSET_ORX))                                                /* Check for channel  ORx and/or Sniffer */
17678     {
17679         dataToWrite |= ((enableMask & ((uint8_t)MYK_DC_OFFSET_SNF | (uint8_t)MYK_DC_OFFSET_ORX))>>2);
17680     }
17681     CMB_SPIWriteField(device->spiSettings, REG_ADDRESS, dataToWrite, 0x03,0);      /* Write Loopback, ORx and Sniffer enable bits to the register */
17682 
17683     return retVal;
17684 }
17685 
17686 /**
17687  * \brief reads Enable/ Disable channels Digital DC Offset and returns a mask of it.
17688  * The mask returned will be a combination of the following channel values ( ::mykonosRxDcOffsettEn_t ).
17689  *
17690  *    Channel               |  Value  |  Channel description
17691  * -------------------------|---------|--------------------------
17692  *  MYK_DC_OFFSET_ALL_OFF   |   0x00  | All channels are disabled
17693  *  MYK_DC_OFFSET_RX1       |   0x01  | Rx1 is enabled
17694  *  MYK_DC_OFFSET_RX2       |   0x02  | Rx2 is enabled
17695  *  MYK_DC_OFFSET_SNF       |   0x04  | Sniffer is enabled
17696  *  MYK_DC_OFFSET_ORX       |   0x08  | ORx is enabled
17697  *  MYK_DC_OFFSET_AVAILABLE |   0x0F  | All channels are enabled
17698  *
17699  * <B>Dependencies</B>
17700  * - device->spiSettings->chipSelectIndex
17701  *
17702  * \param device Pointer to the Mykonos device data structure containing settings
17703  * \param enableMask pointer to the variable to store Enable mask of channels
17704  *
17705  * \retval MYKONOS_ERR_DIG_DC_OFFSET_NULL_ENABLE_MASK enableMask is NULL
17706  * \retval MYKONOS_ERR_OK Function completed successfully
17707  */
MYKONOS_getDigDcOffsetEn(mykonosDevice_t * device,uint8_t * enableMask)17708 mykonosErr_t MYKONOS_getDigDcOffsetEn(mykonosDevice_t *device,uint8_t *enableMask)
17709 {
17710     mykonosErr_t retVal = MYKONOS_ERR_OK;
17711     uint16_t REG_ADDRESS = 0;
17712     uint8_t readbackData = 0;
17713     uint8_t enableMaskData = 0;
17714 
17715 #if (MYKONOS_VERBOSE == 1)
17716     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getDigDcOffsetEn()\n");
17717 #endif
17718 
17719     if (enableMask == NULL)
17720     {
17721         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_DIG_DC_OFFSET_NULL_ENABLE_MASK,
17722                 getMykonosErrorMessage(MYKONOS_ERR_DIG_DC_OFFSET_NULL_ENABLE_MASK));
17723         return MYKONOS_ERR_DIG_DC_OFFSET_NULL_ENABLE_MASK;
17724     }
17725 
17726     REG_ADDRESS = MYKONOS_ADDR_DIGITAL_DC_OFFSET_CONFIG;                            /* register address of Rx1 and Rx2 enable bits*/
17727     CMB_SPIReadField(device->spiSettings, REG_ADDRESS, &readbackData, 0x06,0);
17728     enableMaskData |= (readbackData>>1);                                            /* adjust bits to match channel :refer enum mykonosRfDcOffsettEn_t. */
17729 
17730     readbackData = 0x00;
17731     REG_ADDRESS = MYKONOS_DIGITAL_DC_OFFSET_CH3_TRACKING;                           /* register address of Orx and sniffer enable bits*/
17732     CMB_SPIReadField(device->spiSettings, REG_ADDRESS, &readbackData, 0x03,0);
17733     enableMaskData |= (uint8_t)(readbackData<<2);                                            /* adjust bits to match channel :refer enum mykonosRfDcOffsettEn_t. */
17734 
17735     *enableMask = enableMaskData;
17736 
17737     return retVal;
17738 }
17739 
17740 /**
17741  * \brief This function will configure the path delay settings for all the features:
17742  * DPD, VSWR and CLGC.
17743  *
17744  *  A DPD  device is required.
17745  *
17746  * <B>Dependencies</B>
17747  * - device->spiSettings->chipSelectIndex
17748  * - device->profilesValid
17749  *
17750  * \param device Pointer to the Mykonos device data structure containing settings
17751  * \param pathDelay pointer to structure of type ::mykonosPathdelay_t to be programmed
17752  *
17753  * \retval MYKONOS_ERR_SET_PATH_DELAY_NULL_PARAM pathDelay is null
17754  * \retval MYKONOS_ERR_SET_PATH_DELAY_PARAM_OUT_OF_RANGE path delay valid range is from 0 to 4095 at 1/16 sample resolution of ORx sample rate
17755  * \retval MYKONOS_ERR_OK Function completed successfully
17756  */
MYKONOS_setPathDelay(mykonosDevice_t * device,mykonosPathdelay_t * pathDelay)17757 mykonosErr_t MYKONOS_setPathDelay(mykonosDevice_t *device, mykonosPathdelay_t *pathDelay)
17758 {
17759     mykonosErr_t retVal = MYKONOS_ERR_OK;
17760     uint8_t armFieldValue[16] = {0};
17761     uint8_t extData[3] = {(uint8_t)MYKONOS_ARM_OBJECTID_TRACKING_CAL_CONTROL, (uint8_t)SET_PATH_DELAY, 0};
17762     uint8_t writeSize = 0;
17763     uint8_t fifoDel[4] = {0};
17764     uint8_t interpIndex[4] = {0};
17765     uint32_t *delPointer = &pathDelay->forwardPathDelayCh1;
17766     uint8_t i = 0;
17767 
17768     const uint32_t RANGE_PATH_DELAY = 4095;
17769     const uint8_t PATH_DELAY_SIZE = 4;
17770 
17771 #if (MYKONOS_VERBOSE == 1)
17772     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setPathDelay()\n");
17773 #endif
17774 
17775     if (pathDelay == NULL)
17776     {
17777         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_PATH_DELAY_NULL_PARAM,
17778                 getMykonosErrorMessage(MYKONOS_ERR_SET_PATH_DELAY_NULL_PARAM));
17779         return MYKONOS_ERR_SET_PATH_DELAY_NULL_PARAM;
17780     }
17781 
17782     /* Loop to set the ARM memory data */
17783     for (i = 0; i < PATH_DELAY_SIZE ; i++)
17784     {
17785         /* Verify all the data in the structure is in range */
17786         if (*delPointer > RANGE_PATH_DELAY)
17787         {
17788             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SET_PATH_DELAY_PARAM_OUT_OF_RANGE,
17789                     getMykonosErrorMessage(MYKONOS_ERR_SET_PATH_DELAY_PARAM_OUT_OF_RANGE));
17790             return MYKONOS_ERR_SET_PATH_DELAY_PARAM_OUT_OF_RANGE;
17791         }
17792 
17793         fifoDel[i] = (uint8_t)(*delPointer >> 4);
17794         interpIndex[i] = (uint8_t)(*delPointer - (fifoDel[i] * 16));
17795 
17796         delPointer++;
17797     }
17798 
17799     if ((device->tx->vswrConfig == NULL) || ((pathDelay->reversePathDelayCh1 == 0) && (pathDelay->reversePathDelayCh2 == 0)))
17800     {
17801         armFieldValue[0] = interpIndex[0];
17802         armFieldValue[1] = 0;
17803         armFieldValue[2] = fifoDel[0];
17804         armFieldValue[3] = 0;
17805         armFieldValue[4] = interpIndex[2];
17806         armFieldValue[5] = 0;
17807         armFieldValue[6] = fifoDel[2];
17808         armFieldValue[7] = 0;
17809         extData[2] = 0;
17810         writeSize = 8;
17811     }
17812     else
17813     {
17814         armFieldValue[0] = interpIndex[0];
17815         armFieldValue[1] = 0;
17816         armFieldValue[2] = fifoDel[0];
17817         armFieldValue[3] = 0;
17818         armFieldValue[4] = interpIndex[2];
17819         armFieldValue[5] = 0;
17820         armFieldValue[6] = fifoDel[2];
17821         armFieldValue[7] = 0;
17822         armFieldValue[8] = interpIndex[1];
17823         armFieldValue[9] = 0;
17824         armFieldValue[10] = fifoDel[1];
17825         armFieldValue[11] = 0;
17826         armFieldValue[12] = interpIndex[3];
17827         armFieldValue[13] = 0;
17828         armFieldValue[14] = fifoDel[3];
17829         armFieldValue[15] = 0;
17830         extData[2] = 1;
17831         writeSize = 16;
17832     }
17833 
17834     retVal = MYKONOS_writeArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &armFieldValue[0], writeSize);
17835     if (retVal != MYKONOS_ERR_OK)
17836     {
17837         return retVal;
17838     }
17839 
17840     retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_SET_OPCODE, &extData[0], sizeof(extData));
17841 
17842     return retVal;
17843 }
17844 
17845 /**
17846  * \brief This function will read the current path delay settings for the selected calibration.
17847  *
17848  *  A DPD-enabled transceiver is required
17849  *
17850  * <B>Dependencies</B>
17851  * - device->spiSettings->chipSelectIndex
17852  * - device->profilesValid
17853  *
17854  * \param device Pointer to the Mykonos device data structure containing settings
17855  * \param select path delay status selection from ::mykonosPathDelaySel_t
17856  * \param pathDelay pointer to structure of type ::mykonosPathdelay_t to store the read back path delay
17857  *
17858  * \retval MYKONOS_ERR_GET_PATH_DELAY_NULL_PARAM pathDelay is null
17859  * \retval MYKONOS_ERR_GET_PATH_DELAY_INVALID_SELECTION invalid selection for getting the path delay, valid selections are given by mykonosPathDelaySel_t
17860  * \retval MYKONOS_ERR_GET_PATH_DELAY_ARMERRFLAG Arm error while reading path delay for the selected calibration status
17861  * \retval MYKONOS_ERR_OK Function completed successfully
17862  */
MYKONOS_getPathDelay(mykonosDevice_t * device,mykonosPathDelaySel_t select,mykonosPathdelay_t * pathDelay)17863 mykonosErr_t MYKONOS_getPathDelay(mykonosDevice_t *device, mykonosPathDelaySel_t select, mykonosPathdelay_t *pathDelay)
17864 {
17865     uint8_t extData[3] = {(uint8_t)MYKONOS_ARM_OBJECTID_CAL_STATUS, (uint8_t)MYKONOS_ARM_OBJECTID_VSWRCONFIG, 0};
17866     uint8_t armData[80] = {0};
17867     uint32_t timeoutMs = 0;
17868     uint8_t cmdStatusByte = 0;
17869     uint32_t *delPointer = &pathDelay->forwardPathDelayCh1;
17870     uint8_t channel = 0;
17871     uint8_t addr[4] = {0};
17872     mykonosErr_t retVal = MYKONOS_ERR_OK;
17873 
17874 #if (MYKONOS_VERBOSE == 1)
17875     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getPathDelay()\n");
17876 #endif
17877 
17878     if (pathDelay == NULL)
17879     {
17880         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_PATH_DELAY_NULL_PARAM,
17881                 getMykonosErrorMessage(MYKONOS_ERR_GET_PATH_DELAY_NULL_PARAM));
17882         return MYKONOS_ERR_GET_PATH_DELAY_NULL_PARAM;
17883     }
17884 
17885     switch (select)
17886     {
17887         case MYK_DPD_PATH_DELAY:
17888             extData[1] = MYKONOS_ARM_OBJECTID_DPDCONFIG;
17889             addr[0] = 24;
17890             addr[1] = 26;
17891             addr[2] = 0;
17892             addr[3] = 0;
17893             break;
17894         case MYK_CLGC_PATH_DELAY:
17895             extData[1] = MYKONOS_ARM_OBJECTID_CLGCCONFIG;
17896             addr[0] = 60;
17897             addr[1] = 62;
17898             addr[2] = 0;
17899             addr[3] = 0;
17900             break;
17901         case MYK_VSWR_PATH_DELAY:
17902             extData[1] = MYKONOS_ARM_OBJECTID_VSWRCONFIG;
17903             addr[0] = 72;
17904             addr[1] = 74;
17905             addr[2] = 76;
17906             addr[3] = 78;
17907             break;
17908         default:
17909             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_PATH_DELAY_INVALID_SELECTION,
17910                     getMykonosErrorMessage(MYKONOS_ERR_GET_PATH_DELAY_INVALID_SELECTION));
17911             return MYKONOS_ERR_GET_PATH_DELAY_INVALID_SELECTION;
17912     }
17913 
17914     /* reading 2 channels, channel being the channel selector */
17915     for (channel = 0; channel < 2; channel++)
17916     {
17917         if (channel)
17918         {
17919             delPointer++;
17920         }
17921 
17922         extData[2] = channel;
17923 
17924         retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &extData[0], sizeof(extData));
17925         if (retVal != MYKONOS_ERR_OK)
17926         {
17927             return retVal;
17928         }
17929 
17930         timeoutMs = 1000;
17931         retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte);
17932         if (retVal != MYKONOS_ERR_OK)
17933         {
17934             /* throw more specific error message instead of returning error code from waitArmCmdStatus */
17935             if (cmdStatusByte > 0)
17936             {
17937                 CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_PATH_DELAY_ARMERRFLAG,
17938                         getMykonosErrorMessage(MYKONOS_ERR_GET_PATH_DELAY_ARMERRFLAG));
17939                 return MYKONOS_ERR_GET_PATH_DELAY_ARMERRFLAG;
17940             }
17941 
17942             return retVal;
17943         }
17944 
17945         if (cmdStatusByte > 0)
17946         {
17947             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GET_PATH_DELAY_ARMERRFLAG,
17948                     getMykonosErrorMessage(MYKONOS_ERR_GET_PATH_DELAY_ARMERRFLAG));
17949             return MYKONOS_ERR_GET_PATH_DELAY_ARMERRFLAG;
17950         }
17951 
17952         /* read status from ARM memory */
17953         retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &armData[0], sizeof(armData), 1);
17954         if (retVal != MYKONOS_ERR_OK)
17955         {
17956             return retVal;
17957         }
17958 
17959         *delPointer = ((uint32_t)(armData[addr[1]]) * 16) + (uint32_t)(armData[addr[0]]);
17960         delPointer++;
17961         if ((addr[2] != 0) && (addr[3] != 0))
17962         {
17963             /* reverse path delay only applies to VSWR */
17964             *delPointer = ((uint32_t)(armData[addr[3]]) * 16) + (uint32_t)(armData[addr[2]]);
17965         }
17966         else
17967         {
17968             /* the rest of path delays will not have a reverse delay value */
17969             *delPointer = 0;
17970         }
17971     }
17972 
17973     return retVal;
17974 }
17975 
17976 /**
17977  * \brief This function reads the current error counters for all the DPD error codes from ::mykonosDpdErrors_t.
17978  *
17979  *  A DPD-enabled transceiver is required
17980  *
17981  * <B>Dependencies</B>
17982  * - device->spiSettings->chipSelectIndex
17983  * - device->profilesValid
17984  *
17985  * \param device Pointer to the Mykonos device data structure containing settings
17986  * \param txChannel Tx channel selection from ::mykonosTxChannels_t
17987  * \param dpdErrCnt pointer to structure of type ::mykonosDpdErrorCounters_t to store the read back error counters
17988  *
17989  * \retval MYKONOS_ERR_GETDPD_ERROR_CNT_NULLPARAM dpdErrCnt is null
17990  * \retval MYKONOS_ERR_GETDPD_ERROR_CNT_INV_CH invalid selection for getting the error counters tx channel, only valid values are Tx1 and Tx2
17991  * \retval MYKONOS_ERR_GETDPD_ERROR_CNT_ARMERRFLAG Arm error while reading the error counters for the DPD status
17992  * \retval MYKONOS_ERR_OK Function completed successfully
17993  */
MYKONOS_getDpdErrorCounters(mykonosDevice_t * device,mykonosTxChannels_t txChannel,mykonosDpdErrorCounters_t * dpdErrCnt)17994 mykonosErr_t MYKONOS_getDpdErrorCounters(mykonosDevice_t *device,  mykonosTxChannels_t txChannel, mykonosDpdErrorCounters_t *dpdErrCnt)
17995 {
17996     uint8_t extData[3] = {MYKONOS_ARM_OBJECTID_CAL_STATUS, MYKONOS_ARM_OBJECTID_DPDCONFIG, 0};
17997     uint8_t armData[200] = {0};
17998     uint32_t timeoutMs = 0;
17999     uint8_t cmdStatusByte = 0;
18000     uint8_t loop = 0;
18001     uint8_t index = 0;
18002     uint8_t channelSelect = 0;
18003     mykonosErr_t retVal = MYKONOS_ERR_OK;
18004 
18005 #if (MYKONOS_VERBOSE == 1)
18006     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getDpdErrorCounters()\n");
18007 #endif
18008 
18009     if (dpdErrCnt == NULL)
18010     {
18011         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETDPD_ERROR_CNT_NULLPARAM,
18012                 getMykonosErrorMessage(MYKONOS_ERR_GETDPD_ERROR_CNT_NULLPARAM));
18013         return MYKONOS_ERR_GETDPD_ERROR_CNT_NULLPARAM;
18014     }
18015 
18016     switch (txChannel)
18017     {
18018         case TX1:
18019             channelSelect = 0;
18020             break;
18021         case TX2:
18022             channelSelect = 1;
18023             break;
18024         default:
18025         {
18026             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETDPD_ERROR_CNT_INV_CH,
18027                     getMykonosErrorMessage(MYKONOS_ERR_GETDPD_ERROR_CNT_INV_CH));
18028             return MYKONOS_ERR_GETDPD_ERROR_CNT_INV_CH;
18029         }
18030     }
18031 
18032     extData[2] = channelSelect;
18033 
18034     retVal = MYKONOS_sendArmCommand(device, MYKONOS_ARM_GET_OPCODE, &extData[0], sizeof(extData));
18035     if (retVal != MYKONOS_ERR_OK)
18036     {
18037         return retVal;
18038     }
18039 
18040     timeoutMs = 1000;
18041     retVal = MYKONOS_waitArmCmdStatus(device, MYKONOS_ARM_GET_OPCODE, timeoutMs, &cmdStatusByte);
18042     if (retVal != MYKONOS_ERR_OK)
18043     {
18044         if (cmdStatusByte > 0)
18045         {
18046             CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETDPD_ERROR_CNT_ARMERRFLAG,
18047                     getMykonosErrorMessage(MYKONOS_ERR_GETDPD_ERROR_CNT_ARMERRFLAG));
18048             return MYKONOS_ERR_GETDPD_ERROR_CNT_ARMERRFLAG;
18049         }
18050 
18051         return retVal;
18052     }
18053 
18054     if (cmdStatusByte > 0)
18055     {
18056         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETDPD_ERROR_CNT_ARMERRFLAG,
18057                 getMykonosErrorMessage(MYKONOS_ERR_GETDPD_ERROR_CNT_ARMERRFLAG));
18058         return MYKONOS_ERR_GETDPD_ERROR_CNT_ARMERRFLAG;
18059     }
18060 
18061     /* read status from ARM memory */
18062     retVal = MYKONOS_readArmMem(device, MYKONOS_ADDR_ARM_START_DATA_ADDR, &armData[0], sizeof(armData), 1);
18063     if (retVal != MYKONOS_ERR_OK)
18064     {
18065         return retVal;
18066     }
18067 
18068     dpdErrCnt->dpdErrorCount = ((uint32_t)(armData[67]) << 24) | ((uint32_t)(armData[66]) << 16) | ((uint32_t)(armData[65]) << 8) | (uint32_t)(armData[64]);
18069     index = 68;
18070     for (loop = 1; loop < (uint8_t)MYK_DPD_ERROR_END; loop++)
18071     {
18072         dpdErrCnt->errorCounter[loop] = ((uint32_t)(armData[index + 3]) << 24) | ((uint32_t)(armData[index + 2]) << 16) | ((uint32_t)(armData[index + 1]) << 8) | (uint32_t)(armData[index]);
18073         index +=4;
18074     }
18075 
18076     return MYKONOS_ERR_OK;
18077 }
18078 
18079 /**
18080  * \brief DPD feature to set the bypassing actuator when Tx signal power is below a programmable threshold given in
18081  * ::mykonosDpdBypassConfig_t lowPowerActuatorBypassLevel.
18082  *
18083  * <B>Dependencies</B>
18084  * - device->spiSettings->chipSelectIndex
18085  * - device->profilesValid
18086  *
18087  * \param device Pointer to the Mykonos device data structure containing settings
18088  * \param actConfig Pointer to actuator structure of type ::mykonosDpdBypassConfig_t which contains the settings to be programmed
18089  *
18090  * \retval MYKONOS_ERR_SETDPDACT_NULL_ACTSTRUCT passed structure is null
18091  * \retval MYKONOS_ERR_SETDPDACT_INV_ACTMODE invalid mode in actConfig->lowPowerActuatorBypassMode for valid modes ::mykonosDpdResetMode_t
18092  * \retval MYKONOS_ERR_SETDPDACT_INV_LEVEL actConfig->lowPowerActuatorBypassLevel outside the range, valid range is 0 to 6000 (0 to 60dB)
18093  * \retval MYKONOS_ERR_OK Function completed successfully
18094  */
MYKONOS_setDpdBypassConfig(mykonosDevice_t * device,mykonosDpdBypassConfig_t * actConfig)18095 mykonosErr_t MYKONOS_setDpdBypassConfig(mykonosDevice_t *device, mykonosDpdBypassConfig_t *actConfig)
18096 {
18097     mykonosErr_t retVal = MYKONOS_ERR_OK;
18098     uint8_t armFieldValue[4] = {0};
18099     uint8_t byteOffset = 62;
18100 
18101     const uint16_t LEVEL_RANGE_CHECK = 6000;
18102 
18103 #if (MYKONOS_VERBOSE == 1)
18104     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setDpdBypassConfig()\n");
18105 #endif
18106 
18107     if (actConfig == NULL)
18108     {
18109         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETDPDACT_NULL_ACTSTRUCT,
18110                 getMykonosErrorMessage(MYKONOS_ERR_SETDPDACT_NULL_ACTSTRUCT));
18111         return MYKONOS_ERR_SETDPDACT_NULL_ACTSTRUCT;
18112     }
18113 
18114     if (actConfig->bypassActuatorMode >= MYK_DPD_RESET_END)
18115     {
18116         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETDPDACT_INV_ACTMODE,
18117                 getMykonosErrorMessage(MYKONOS_ERR_SETDPDACT_INV_ACTMODE));
18118         return MYKONOS_ERR_SETDPDACT_INV_ACTMODE;
18119     }
18120 
18121     if (actConfig->bypassActuatorLevel > LEVEL_RANGE_CHECK)
18122     {
18123         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETDPDACT_INV_LEVEL,
18124                 getMykonosErrorMessage(MYKONOS_ERR_SETDPDACT_INV_LEVEL));
18125         return MYKONOS_ERR_SETDPDACT_INV_LEVEL;
18126     }
18127 
18128     armFieldValue[0] = (actConfig->bypassActuatorEn > 0) ? 1 : 0;
18129     armFieldValue[1] = (uint8_t)(actConfig->bypassActuatorMode);
18130     armFieldValue[2] = (uint8_t)(actConfig->bypassActuatorLevel & 0xFF);
18131     armFieldValue[3] = (uint8_t)((actConfig->bypassActuatorLevel >> 8) & 0xFF);
18132 
18133     retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_DPDCONFIG, byteOffset, &armFieldValue[0], sizeof(armFieldValue));
18134     if (retVal != MYKONOS_ERR_OK)
18135     {
18136         return retVal;
18137     }
18138 
18139     return MYKONOS_ERR_OK;
18140 }
18141 
18142 /**
18143  * \brief Get configuration for bypassing DPD actuator
18144  *
18145  * <B>Dependencies</B>
18146  * - device->spiSettings->chipSelectIndex
18147  * - device->profilesValid
18148  *
18149  * \param device Pointer to the Mykonos device data structure containing settings
18150  * \param actConfig actuator structure of type ::mykonosDpdBypassConfig_t
18151  *
18152  * \retval MYKONOS_ERR_GETDPDACT_NULL_ACTSTRUCT passed structure is null
18153  * \retval MYKONOS_ERR_OK Function completed successfully
18154  */
MYKONOS_getDpdBypassConfig(mykonosDevice_t * device,mykonosDpdBypassConfig_t * actConfig)18155 mykonosErr_t MYKONOS_getDpdBypassConfig(mykonosDevice_t *device, mykonosDpdBypassConfig_t *actConfig)
18156 {
18157     mykonosErr_t retVal = MYKONOS_ERR_OK;
18158     uint8_t armFieldValue[4] = {0};
18159     uint8_t byteOffset = 62;
18160 
18161 #if (MYKONOS_VERBOSE == 1)
18162     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getDpdBypassConfig()\n");
18163 #endif
18164 
18165     if (actConfig == NULL)
18166     {
18167         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETDPDACT_NULL_ACTSTRUCT,
18168                 getMykonosErrorMessage(MYKONOS_ERR_GETDPDACT_NULL_ACTSTRUCT));
18169         return MYKONOS_ERR_GETDPDACT_NULL_ACTSTRUCT;
18170     }
18171 
18172     retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_DPDCONFIG, byteOffset, &armFieldValue[0], sizeof(armFieldValue));
18173     if (retVal != MYKONOS_ERR_OK)
18174     {
18175         return retVal;
18176     }
18177 
18178     actConfig->bypassActuatorEn = armFieldValue[0];
18179     actConfig->bypassActuatorMode = (mykonosDpdResetMode_t)armFieldValue[1];
18180     actConfig->bypassActuatorLevel = (uint16_t)(((uint16_t)(armFieldValue[3]) << 8) | (uint16_t)(armFieldValue[2]));
18181 
18182     return MYKONOS_ERR_OK;
18183 }
18184 
18185 /**
18186  * \brief DPD feature to set the actuator gain difference check.
18187  * If the gain before and after the actuator exceeds the value actCheck->actuatorGainCheckLevel an error will be issued
18188  * and the actuator will reset depending on the actCheck->actuatorGainCheckMode.
18189  *
18190  * <B>Dependencies</B>
18191  * - device->spiSettings->chipSelectIndex
18192  * - device->profilesValid
18193  *
18194  * \param device Pointer to the Mykonos device data structure containing settings
18195  * \param actCheck Pointer to structure of type mykonosDpdActuatorCheck_t which contains the settings to be programmed
18196  *
18197  * \retval MYKONOS_ERR_SETDPDACTCHECK_NULL_ACTSTRUCT passed structure is null
18198  * \retval MYKONOS_ERR_SETDPDACTCHECK_INV_ACTMODE invalid mode in actCheck->actuatorGainCheckMode for valid modes ::mykonosDpdResetMode_t
18199  * \retval MYKONOS_ERR_SETDPDACTCHECK_INV_LEVEL actCheck->actuatorGainCheckLevel outside the range, valid range is from 0 to 3000 (0 to 30dB)
18200  * \retval MYKONOS_ERR_OK Function completed successfully
18201  */
MYKONOS_setDpdActuatorCheck(mykonosDevice_t * device,mykonosDpdActuatorCheck_t * actCheck)18202 mykonosErr_t MYKONOS_setDpdActuatorCheck(mykonosDevice_t *device, mykonosDpdActuatorCheck_t *actCheck)
18203 {
18204     mykonosErr_t retVal = MYKONOS_ERR_OK;
18205     uint8_t armFieldValue[4] = {0};
18206     uint8_t byteOffset = 58;
18207 
18208     const uint16_t LEVEL_RANGE_CHECK = 3000;
18209 
18210 #if (MYKONOS_VERBOSE == 1)
18211     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setDpdActuatorCheck()\n");
18212 #endif
18213 
18214     if (actCheck == NULL)
18215     {
18216         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETDPDACTCHECK_NULL_ACTSTRUCT,
18217                 getMykonosErrorMessage(MYKONOS_ERR_SETDPDACTCHECK_NULL_ACTSTRUCT));
18218         return MYKONOS_ERR_SETDPDACTCHECK_NULL_ACTSTRUCT;
18219     }
18220 
18221     if (actCheck->actuatorGainCheckMode >= MYK_DPD_RESET_END)
18222     {
18223         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETDPDACTCHECK_INV_ACTMODE,
18224                 getMykonosErrorMessage(MYKONOS_ERR_SETDPDACTCHECK_INV_ACTMODE));
18225         return MYKONOS_ERR_SETDPDACTCHECK_INV_ACTMODE;
18226     }
18227 
18228     if (actCheck->actuatorGainCheckLevel > LEVEL_RANGE_CHECK)
18229     {
18230         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_SETDPDACTCHECK_INV_LEVEL,
18231                 getMykonosErrorMessage(MYKONOS_ERR_SETDPDACTCHECK_INV_LEVEL));
18232         return MYKONOS_ERR_SETDPDACTCHECK_INV_LEVEL;
18233     }
18234 
18235     armFieldValue[0] = (actCheck->actuatorGainCheckEn > 0) ? 1 : 0;
18236     armFieldValue[1] = (uint8_t)(actCheck->actuatorGainCheckMode);
18237     armFieldValue[2] = (uint8_t)(actCheck->actuatorGainCheckLevel & 0xFF);
18238     armFieldValue[3] = (uint8_t)((actCheck->actuatorGainCheckLevel >> 8) & 0xFF);
18239 
18240     retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_DPDCONFIG, byteOffset, &armFieldValue[0], sizeof(armFieldValue));
18241     if (retVal != MYKONOS_ERR_OK)
18242     {
18243         return retVal;
18244     }
18245 
18246     return MYKONOS_ERR_OK;
18247 }
18248 
18249 
18250 /**
18251  * \brief Get configuration for DPD actuator check
18252  *
18253  * <B>Dependencies</B>
18254  * - device->spiSettings->chipSelectIndex
18255  * - device->profilesValid
18256  *
18257  * \param device Pointer to the Mykonos device data structure containing settings
18258  * \param actCheck Pointer to structure of type mykonosDpdActuatorCheck_t which will contain the programmed  settings
18259  *
18260  * \retval MYKONOS_ERR_GETDPDACTCHECK_NULL_ACTSTRUCT passed structure is null
18261  * \retval MYKONOS_ERR_OK Function completed successfully
18262  */
MYKONOS_getDpdActuatorCheck(mykonosDevice_t * device,mykonosDpdActuatorCheck_t * actCheck)18263 mykonosErr_t MYKONOS_getDpdActuatorCheck(mykonosDevice_t *device, mykonosDpdActuatorCheck_t *actCheck)
18264 {
18265     mykonosErr_t retVal = MYKONOS_ERR_OK;
18266     uint8_t armFieldValue[4] = {0};
18267     uint8_t byteOffset = 58;
18268 
18269 #if (MYKONOS_VERBOSE == 1)
18270     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getDpdActuatorCheck()\n");
18271 #endif
18272 
18273     if (actCheck == NULL)
18274     {
18275         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_GETDPDACTCHECK_NULL_ACTSTRUCT,
18276                 getMykonosErrorMessage(MYKONOS_ERR_GETDPDACTCHECK_NULL_ACTSTRUCT));
18277         return MYKONOS_ERR_GETDPDACTCHECK_NULL_ACTSTRUCT;
18278     }
18279 
18280     retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_DPDCONFIG, byteOffset, &armFieldValue[0], sizeof(armFieldValue));
18281     if (retVal != MYKONOS_ERR_OK)
18282     {
18283         return retVal;
18284     }
18285 
18286     actCheck->actuatorGainCheckEn = armFieldValue[0];
18287     actCheck->actuatorGainCheckMode = (mykonosDpdResetMode_t)armFieldValue[1];
18288     actCheck->actuatorGainCheckLevel = (uint16_t)(((uint16_t)(armFieldValue[3]) << 8) | (uint16_t)(armFieldValue[2]));
18289 
18290     return MYKONOS_ERR_OK;
18291 }
18292 
18293 
18294 /**
18295  * \brief CLGC feature to set the TX attenuation tuning range to a relative range around a nominal value
18296  *
18297  * <B>Dependencies</B>
18298  * - device->spiSettings->chipSelectIndex
18299  * - device->profilesValid
18300  *
18301  * \param device Pointer to the Mykonos device data structure containing settings
18302  * \param attRangeCfg Pointer to structure of type mykonosClgcAttenTuningConfig_t which contains the settings to be programmed
18303  *
18304  * \retval MYKONOS_ERR_CFGCLGC_TXORX_PROFILE_INV Tx and ObsRx profiles must be valid to use the CLGC feature
18305  * \retval MYKONOS_ERR_CLGCATTENTUNCFG_NULL_ATTRANGECFGSTRUCT Passed structure is null
18306  * \retval MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_MODE Invalid mode in attRangeCfg member, for valid modes ::mykonosClgcAttenTuningMode_t
18307  * \retval MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_PRESET Invalid AttenTuningPreset in attRangeCfg member, valid range is from 0 to 839 (0 to 41.95dB)
18308  * \retval MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_RANGE Invalid AttenTuningRange in attRangeCfg member, valid range is from 0 to 420 (0 to 21dB)
18309  * \retval MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_TX1_SETTINGS Invalid Tx1 AttenTuningRange and AttenTuningPreset combination
18310  * \retval MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_TX2_SETTINGS Invalid Tx2 AttenTuningRange and AttenTuningPreset combination
18311  * \retval MYKONOS_ERR_OK Function completed successfully
18312  */
MYKONOS_setClgcAttenTuningConfig(mykonosDevice_t * device,mykonosClgcAttenTuningConfig_t * attRangeCfg)18313 mykonosErr_t MYKONOS_setClgcAttenTuningConfig(mykonosDevice_t *device, mykonosClgcAttenTuningConfig_t *attRangeCfg)
18314 {
18315     mykonosErr_t retVal = MYKONOS_ERR_OK;
18316     uint8_t armFieldValue[10] = {0};
18317     uint8_t byteOffset = 0x2C;
18318 
18319     const uint16_t PRESET_CHECK = 840;
18320     const uint16_t RANGE_CHECK = 420;
18321 
18322 #if (MYKONOS_VERBOSE == 1)
18323     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_setClgcAttenTuningConfig()\n");
18324 #endif
18325 
18326     /* CLGC requires Tx and ORx enabled, throw error if both are not enabled */
18327     if ((device->profilesValid & (TX_PROFILE_VALID | ORX_PROFILE_VALID)) != (TX_PROFILE_VALID | ORX_PROFILE_VALID))
18328     {
18329         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CFGCLGC_TXORX_PROFILE_INV,
18330                 getMykonosErrorMessage(MYKONOS_ERR_CFGCLGC_TXORX_PROFILE_INV));
18331         return MYKONOS_ERR_CFGCLGC_TXORX_PROFILE_INV;
18332     }
18333 
18334     if (attRangeCfg == NULL)
18335     {
18336         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CLGCATTENTUNCFG_NULL_ATTRANGECFGSTRUCT,
18337                 getMykonosErrorMessage(MYKONOS_ERR_CLGCATTENTUNCFG_NULL_ATTRANGECFGSTRUCT));
18338         return MYKONOS_ERR_CLGCATTENTUNCFG_NULL_ATTRANGECFGSTRUCT;
18339     }
18340 
18341     /* Range checks */
18342     if ((attRangeCfg->tx1AttenTuningLimitMode >= MYK_CLGC_ATTEN_END) || (attRangeCfg->tx2AttenTuningLimitMode >= MYK_CLGC_ATTEN_END))
18343     {
18344         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_MODE,
18345                 getMykonosErrorMessage(MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_MODE));
18346         return MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_MODE;
18347     }
18348 
18349     if ((attRangeCfg->tx1AttenTuningPreset >= PRESET_CHECK) || (attRangeCfg->tx2AttenTuningPreset >= PRESET_CHECK))
18350     {
18351         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_PRESET,
18352                 getMykonosErrorMessage(MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_PRESET));
18353         return MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_PRESET;
18354     }
18355 
18356     if ((attRangeCfg->tx1AttenTuningRange > RANGE_CHECK) || (attRangeCfg->tx2AttenTuningRange > RANGE_CHECK))
18357     {
18358         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_RANGE,
18359                 getMykonosErrorMessage(MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_RANGE));
18360         return MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_RANGE;
18361     }
18362 
18363     if (((attRangeCfg->tx1AttenTuningPreset - attRangeCfg->tx1AttenTuningRange) < 0) ||
18364         ((attRangeCfg->tx1AttenTuningPreset + attRangeCfg->tx1AttenTuningRange) > PRESET_CHECK))
18365     {
18366         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_TX1_SETTINGS,
18367                 getMykonosErrorMessage(MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_TX1_SETTINGS));
18368         return MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_TX1_SETTINGS;
18369     }
18370 
18371     if (((attRangeCfg->tx2AttenTuningPreset - attRangeCfg->tx2AttenTuningRange) < 0) ||
18372         ((attRangeCfg->tx2AttenTuningPreset + attRangeCfg->tx2AttenTuningRange) > PRESET_CHECK))
18373     {
18374         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_TX2_SETTINGS,
18375                 getMykonosErrorMessage(MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_TX2_SETTINGS));
18376         return MYKONOS_ERR_CLGCATTENTUNCFG_INVALID_TX2_SETTINGS;
18377     }
18378 
18379     armFieldValue[0] = (uint8_t)(attRangeCfg->tx1AttenTuningLimitMode & 0xFF);
18380     armFieldValue[1] = (uint8_t)(attRangeCfg->tx2AttenTuningLimitMode & 0xFF);
18381     armFieldValue[2] = (uint8_t)(attRangeCfg->tx1AttenTuningPreset & 0xFF);
18382     armFieldValue[3] = (uint8_t)((attRangeCfg->tx1AttenTuningPreset >> 8) & 0xFF);
18383     armFieldValue[4] = (uint8_t)(attRangeCfg->tx2AttenTuningPreset & 0xFF);
18384     armFieldValue[5] = (uint8_t)((attRangeCfg->tx2AttenTuningPreset >> 8) & 0xFF);
18385     armFieldValue[6] = (uint8_t)(attRangeCfg->tx1AttenTuningRange & 0xFF);
18386     armFieldValue[7] = (uint8_t)((attRangeCfg->tx1AttenTuningRange >> 8) & 0xFF);
18387     armFieldValue[8] = (uint8_t)(attRangeCfg->tx2AttenTuningRange & 0xFF);
18388     armFieldValue[9] = (uint8_t)((attRangeCfg->tx2AttenTuningRange >> 8) & 0xFF);
18389 
18390     retVal = MYKONOS_writeArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &armFieldValue[0], sizeof(armFieldValue));
18391     if (retVal != MYKONOS_ERR_OK)
18392     {
18393         return retVal;
18394     }
18395 
18396     return MYKONOS_ERR_OK;
18397 }
18398 
18399 
18400 /**
18401  * \brief Get configuration for CLGC Tx attenuation tuning range.
18402  *
18403  * <B>Dependencies</B>
18404  * - device->spiSettings->chipSelectIndex
18405  * - device->profilesValid
18406  *
18407  * \param device Pointer to the Mykonos device data structure containing settings
18408  * \param attRangeCfg Pointer to structure of type mykonosClgcAttenTuningConfig_t which will contain the programmed  settings
18409  *
18410  * \retval MYKONOS_ERR_CLGCATTENTUNCFGGET_NULL_ATTRANGECFGSTRUCT passed structure is null
18411  * \retval MYKONOS_ERR_OK Function completed successfully
18412  */
MYKONOS_getClgcAttenTuningConfig(mykonosDevice_t * device,mykonosClgcAttenTuningConfig_t * attRangeCfg)18413 mykonosErr_t MYKONOS_getClgcAttenTuningConfig(mykonosDevice_t *device, mykonosClgcAttenTuningConfig_t *attRangeCfg)
18414 {
18415     mykonosErr_t retVal = MYKONOS_ERR_OK;
18416     uint8_t armFieldValue[10] = {0};
18417     uint8_t byteOffset = 0x2C;
18418 
18419 #if (MYKONOS_VERBOSE == 1)
18420     CMB_writeToLog(ADIHAL_LOG_MESSAGE, device->spiSettings->chipSelectIndex, MYKONOS_ERR_OK, "MYKONOS_getClgcAttenTuningConfig()\n");
18421 #endif
18422 
18423     if (attRangeCfg == NULL)
18424     {
18425         CMB_writeToLog(ADIHAL_LOG_ERROR, device->spiSettings->chipSelectIndex, MYKONOS_ERR_CLGCATTENTUNCFGGET_NULL_ATTRANGECFGSTRUCT,
18426                 getMykonosErrorMessage(MYKONOS_ERR_CLGCATTENTUNCFGGET_NULL_ATTRANGECFGSTRUCT));
18427         return MYKONOS_ERR_CLGCATTENTUNCFGGET_NULL_ATTRANGECFGSTRUCT;
18428     }
18429 
18430     retVal = MYKONOS_readArmConfig(device, MYKONOS_ARM_OBJECTID_CLGCCONFIG, byteOffset, &armFieldValue[0], sizeof(armFieldValue));
18431     if (retVal != MYKONOS_ERR_OK)
18432     {
18433         return retVal;
18434     }
18435 
18436     attRangeCfg->tx1AttenTuningLimitMode = (mykonosClgcAttenTuningMode_t)armFieldValue[0];
18437     attRangeCfg->tx2AttenTuningLimitMode = (mykonosClgcAttenTuningMode_t)armFieldValue[1];
18438     attRangeCfg->tx1AttenTuningPreset = (uint16_t)(((uint16_t)(armFieldValue[3]) << 8) | (uint16_t)(armFieldValue[2]));
18439     attRangeCfg->tx2AttenTuningPreset = (uint16_t)(((uint16_t)(armFieldValue[5]) << 8) | (uint16_t)(armFieldValue[4]));
18440     attRangeCfg->tx1AttenTuningRange = (uint16_t)(((uint16_t)(armFieldValue[7]) << 8) | (uint16_t)(armFieldValue[6]));
18441     attRangeCfg->tx2AttenTuningRange = (uint16_t)(((uint16_t)(armFieldValue[9]) << 8) | (uint16_t)(armFieldValue[8]));
18442 
18443     return MYKONOS_ERR_OK;
18444 }
18445