1 /*
2 * Copyright (c) 2021-2023, Texas Instruments Incorporated
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of Texas Instruments Incorporated nor the names of
17 * its contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 /*
33 * ======== LRF.c ========
34 */
35
36 #include <stdint.h>
37 #include <stdlib.h>
38
39 #include <ti/drivers/rcl/RCL_Command.h>
40 #include <ti/drivers/rcl/RCL_Debug.h>
41 #include <ti/drivers/rcl/LRF.h>
42 #include <ti/log/Log.h>
43
44 // #define LRF_DEBUG_TRACE
45
LRF_loadImage(const LRF_TOPsmImage * image,uint32_t destinationAddress)46 LRF_SetupResult LRF_loadImage(const LRF_TOPsmImage *image, uint32_t destinationAddress)
47 {
48 LRF_SetupResult result;
49
50 if (image == NULL)
51 {
52 /* OK, don't load image */
53 result = SetupResult_Ok;
54 }
55 else
56 {
57 const uint32_t *topsmSourcePointer = image->image;
58 uint32_t *ram = (uint32_t *) destinationAddress;
59 uint32_t length = image->imageLen;
60
61 if (length > (TOPSM_RAM_SZ / sizeof(uint32_t)))
62 {
63 /* Image too long */
64 result = SetupResult_ErrorImageLen;
65 }
66 else
67 {
68 uint32_t i = 0;
69 /* Check if the image is 128-bit aligned, and if not, read out 32-bit word(s) */
70 while ((((uintptr_t) topsmSourcePointer) & 0x0F) != 0)
71 {
72 *ram++ = *topsmSourcePointer++;
73 i++;
74 }
75 /* Load most of the image using aligned 128-bit reads */
76 #ifdef DeviceFamily_CC27XX
77 /* We don't need to use HWREG_READ_LRF every time, as the loop only writes to RAM without registers inbetween, but we should protect the first write */
78 ASM_4_NOPS();
79 #endif //DeviceFamily_CC27XX
80 while (i < length - 3)
81 {
82 #ifdef NO_INLINE_ASM
83 struct quadword {
84 uint32_t word[4];
85 };
86 *((struct quadword *) ram) = *((const struct quadword *) topsmSourcePointer);
87 topsmSourcePointer += 4;
88 ram += 4;
89 #else
90 __asm(
91 "LDMIA %0!, {r4, r5, r6, r7} \n"
92 "STMIA %1!, {r4, r5, r6, r7} \n"
93 : "+r" (topsmSourcePointer),
94 "+r" (ram) :
95 : "r4", "r5", "r6", "r7"
96 );
97 #endif
98 i += 4;
99 }
100
101 /* If one or more 32-bit word is left, read it here */
102 while (i < length)
103 {
104 *ram++ = *topsmSourcePointer++;
105 i++;
106 }
107 result = SetupResult_Ok;
108 }
109 }
110 return result;
111 }
112
LRF_initSettingsState(LRF_ApplySettingsState * state,LRF_ApplySettingsBase includeBase,uint16_t phyFeatures)113 void LRF_initSettingsState(LRF_ApplySettingsState *state,
114 LRF_ApplySettingsBase includeBase,
115 uint16_t phyFeatures)
116 {
117 LRF_resetSettingsState(state);
118 state->includeBase = includeBase;
119 state->phyFeatures = phyFeatures;
120 }
121
LRF_applySettings(LRF_ConfigWord * config,LRF_ApplySettingsState * state,int32_t bufferAvailWords)122 LRF_SetupResult LRF_applySettings(LRF_ConfigWord *config,
123 LRF_ApplySettingsState *state,
124 int32_t bufferAvailWords)
125 {
126 #ifdef BUFFER_SPLIT_SUPPORT
127 uint32_t totalLength = state->totalLength;
128 #else
129 (void)bufferAvailWords;
130 #endif
131 uint32_t segmentLength;
132 uint32_t regionLength;
133 LRF_RegionOperation operation = LRF_RegionOperation_Invalid;
134 uintptr_t address = 0;
135
136 /* If settings is NULL, ignore the entry */
137 if (config == NULL)
138 {
139 return SetupResult_Ok;
140 }
141
142 /* Use 32-bit pointer to read entries to ensure compailer doesn't insert
143 16-bit reads toward (possible) flash */
144 uint32_t *curEntry = &config->value32;
145
146 /* Initialize state if starting fresh */
147 #ifdef BUFFER_SPLIT_SUPPORT
148 if (totalLength == 0)
149 {
150 if (bufferAvailWords < 2)
151 {
152 return SetupResult_ErrorElemLen;
153 }
154 LRF_ConfigWord curWord;
155 curWord.value32 = *curEntry;
156 totalLength = curWord.segment.length; /* Total length is at least segment */
157
158 segmentLength = 0; /* Expect region header next */
159 regionLength = 0; /* Read segment next */
160 if (curWord.segment.compoundSegment != 0)
161 {
162 if (totalLength > MAX_REG_CONFIG_LEN || totalLength == 0)
163 {
164 /* Too long or non-existent entry */
165 return SetupResult_ErrorConfigLen;
166
167 }
168
169 #ifdef LRF_DEBUG_TRACE
170 Log_printf(RclCoreShort, Log_INFO, "New compound configration, length is %d", totalLength);
171 #endif
172
173 /* Get subsegment length from next word */
174 curEntry++;
175 bufferAvailWords--; /* Decrement available words */
176 }
177 else
178 {
179 totalLength += 1; /* Simulate a compound header */
180 #ifdef LRF_DEBUG_TRACE
181 Log_printf(RclCoreShort, Log_INFO, "New configration, length is %d", totalLength);
182 #endif
183 }
184
185 address = 0;
186 operation = LRF_RegionOperation_Invalid;
187
188 }
189 else
190 {
191 segmentLength = state->segmentLength;
192 regionLength = state->regionLength;
193 operation = state->operation;
194 address = state->address;
195
196 totalLength -= segmentLength;
197 /* Check if we have words left to skip from last round */
198 if (operation == LRF_RegionOperation_Skip)
199 {
200 bufferAvailWords -= regionLength;
201 curEntry += regionLength;
202 if (bufferAvailWords < 0)
203 {
204 /* Still more words to skip */
205 segmentLength = -bufferAvailWords; /* Number of words left of segment */
206 /* Add unprocessed part of segment back */
207 totalLength += segmentLength;
208 state->regionLength = -bufferAvailWords; /* Signal number of words to skip */
209 state->segmentLength = segmentLength;
210 state->totalLength = totalLength;
211 return SetupResult_Ok_Partial;
212 }
213 else
214 {
215 /* Start new segment */
216 segmentLength = 0;
217 operation = LRF_RegionOperation_Invalid;
218 }
219 }
220 #ifdef LRF_DEBUG_TRACE
221 Log_printf(RclCoreShort, Log_INFO, "Resuming, totalLength:%d, segmentLength:%d address:0x%04X", totalLength, segmentLength, address & 0xffff);
222 #endif
223 }
224 #endif
225
226 /* While entire segment not parsed, go on. Can abort in the middle if error or
227 * out of data */
228 #ifdef BUFFER_SPLIT_SUPPORT
229 while (totalLength + segmentLength > 0)
230 #endif
231 {
232 #ifdef BUFFER_SPLIT_SUPPORT
233 if (segmentLength == 0)
234 #endif
235 {
236 /* If segment length is 0, process new segment */
237 LRF_ConfigWord curWord;
238 curWord.value32 = *curEntry++;
239 uint16_t featureMask = curWord.segment.featureMask;
240 if ((curWord.segment.invertedFeatureMask == 0 &&
241 ((featureMask != 0 && (featureMask & state->phyFeatures) == 0) ||
242 (featureMask == 0 && !state->includeBase))) ||
243 (curWord.segment.invertedFeatureMask != 0 && (featureMask != (featureMask & ~state->phyFeatures))))
244 {
245 /* We skip it */
246 #ifdef LRF_DEBUG_TRACE
247 Log_printf(RclCoreShort, Log_INFO, "Skipping segment length %1d because invertedFeatureMask = %1d, phyFeatures is 0x%04X and segment's featureMask is 0x%04X", curWord.segment.length, curWord.segment.invertedFeatureMask, state->phyFeatures, featureMask);
248 #endif
249 #ifdef BUFFER_SPLIT_SUPPORT
250 uint32_t skipSegmentLength = curWord.segment.length;
251 bufferAvailWords -= skipSegmentLength + 1;
252 totalLength -= skipSegmentLength + 1;
253
254 if (bufferAvailWords < 0)
255 {
256 segmentLength = -bufferAvailWords; /* Signal number of words to skip */
257 regionLength = segmentLength;
258 operation = LRF_RegionOperation_Skip; /* Skip when resuming */
259 bufferAvailWords = 0;
260 }
261 else
262 {
263 curEntry += skipSegmentLength;
264 segmentLength = 0;
265 }
266 #else
267 segmentLength = 0;
268 return SetupResult_Ok;
269 #endif
270 }
271 else
272 {
273 segmentLength = curWord.segment.length;
274 #ifdef LRF_DEBUG_TRACE
275 Log_printf(RclCoreShort, Log_INFO, "New segment, segmentLength:%d", segmentLength);
276 #endif
277
278 #ifdef BUFFER_SPLIT_SUPPORT
279 if (segmentLength == 0 || segmentLength >= totalLength)
280 {
281 return SetupResult_ErrorConfigLen;
282 }
283 bufferAvailWords--;
284 totalLength -= segmentLength + 1;
285 #else
286 if (segmentLength == 0 || segmentLength >= MAX_REG_CONFIG_LEN)
287 {
288 return SetupResult_ErrorConfigLen;
289 }
290 #endif
291 regionLength = 0; /* Read segment next */
292 }
293 }
294 while (segmentLength > 0)
295 {
296 #ifdef BUFFER_SPLIT_SUPPORT
297 if (bufferAvailWords == 0)
298 {
299 /* Add unprocessed part of segment back */
300 totalLength += segmentLength;
301 state->totalLength = totalLength;
302 state->segmentLength = segmentLength;
303 state->regionLength = regionLength;
304 state->operation = operation;
305 state->address = address;
306
307 return SetupResult_Ok_Partial;
308 }
309 #endif
310 /* If regionLength is 0 we are expecting a region header */
311 if (regionLength == 0)
312 {
313 LRF_ConfigWord curWord;
314 curWord.value32 = *curEntry++;
315 regionLength = curWord.region.lengthMinus1 + 1;
316 operation = (LRF_RegionOperation) curWord.region.type;
317 uint32_t regionStart = curWord.region.startAddress;
318
319 /* Accounting. Parsed a region header, so consume+increment word and
320 * parsed count */
321 segmentLength--;
322 #ifdef BUFFER_SPLIT_SUPPORT
323 bufferAvailWords--;
324 #endif
325 /* Find correct region base address */
326 if (operation >= SW_Region_Clear && operation != HW_Write_16bit_masked)
327 {
328 if (operation >= Par_Region_Clear)
329 {
330 address = ((uintptr_t) &swParamList) + regionStart;
331 uint32_t regionActualLength = (operation == Par_Reference_32bit) ? 1 : regionLength;
332 if ((regionStart + (regionActualLength * sizeof(uint32_t))) > swParamListSz)
333 {
334 return SetupResult_ErrorParRange;
335 }
336 }
337 else
338 {
339 address = PBE_RAM_BASE_ADDR + regionStart;
340 }
341 }
342 else
343 {
344 address = LRF_BASE_ADDR + regionStart;
345 }
346 #ifdef LRF_DEBUG_TRACE
347 Log_printf(RclCoreShort, Log_INFO, "New region, regionLength:%d address:0x%04X, operation:%d", regionLength, address & 0xffff, operation);
348 #endif
349 }
350
351 /* Shuffle the data as requested */
352 uint32_t numWords;
353 switch (operation)
354 {
355 case HW_Region_Clear:
356 case Par_Region_Clear:
357 {
358 if ((address & 0x03) != 0)
359 {
360 return SetupResult_ErrorElemAddrAlign;
361 }
362 volatile uint32_t *clear32 = (uint32_t *) address;
363 for (uint32_t i = 0; i < regionLength; i++)
364 {
365 #ifdef DeviceFamily_CC27XX
366 HWREG_WRITE_LRF(clear32++) = 0;
367 #else
368 *clear32++ = 0;
369 #endif //DeviceFamily_CC27XX
370 }
371 regionLength = 0;
372 numWords = 0;
373 }
374 break;
375
376 case SW_Region_Clear:
377 {
378 if ((address & 0x01) != 0)
379 {
380 return SetupResult_ErrorElemAddrAlign;
381 }
382 volatile uint16_t *clear16 = (uint16_t *) address;
383 for (uint32_t i = 0; i < regionLength; i++)
384 {
385 #ifdef DeviceFamily_CC27XX
386 HWREGH_WRITE_LRF(clear16++) = 0;
387 #else
388 *clear16++ = 0;
389 #endif //DeviceFamily_CC27XX
390 }
391 regionLength = 0;
392 numWords = 0;
393 }
394 break;
395
396 case HW_Write_16bit:
397 case SW_Write_16bit:
398 /* Two output words per input words. If number of input
399 word is odd, last half-word is taken separately */
400 if ((address & 0x01) != 0)
401 {
402 return SetupResult_ErrorElemAddrAlign;
403 }
404 numWords = regionLength / 2;
405 break;
406
407 case HW_Write_16bit_masked:
408 if ((address & 0x01) != 0)
409 {
410 return SetupResult_ErrorElemAddrAlign;
411 }
412 numWords = regionLength;
413 break;
414
415 case Par_Reference_32bit:
416 case HW_Write_32bit:
417 case SW_Write_32bit:
418 case Par_Write_32bit:
419 case HW_Write_16bit_sparse:
420 case SW_Write_16bit_sparse:
421 if ((address & 0x03) != 0)
422 {
423 return SetupResult_ErrorElemAddrAlign;
424 }
425 numWords = regionLength;
426 break;
427
428 default:
429 return SetupResult_ErrorElemType;
430 }
431 if (numWords > segmentLength)
432 {
433 return SetupResult_ErrorElemLen;
434 }
435 #ifdef BUFFER_SPLIT_SUPPORT
436 if ((int32_t)numWords > bufferAvailWords)
437 {
438 numWords = bufferAvailWords;
439 }
440 #endif
441 if (numWords > 0)
442 {
443 /* Write as much as we can */
444 switch (operation)
445 {
446 case HW_Write_16bit:
447 {
448 volatile uint32_t *dst32 = (volatile uint32_t *) address;
449 for (uint32_t i = 0; i < numWords; i++)
450 {
451 LRF_ConfigWord curWord;
452 curWord.value32 = *curEntry++;
453 #ifdef LRF_DEBUG_TRACE
454 Log_printf(RclCore, Log_INFO1, "HW_Write_16bit: %04X = %08X, ", dst32&0xFFFF, curWord.value32);
455 #endif
456
457 #ifdef DeviceFamily_CC27XX
458 HWREG_WRITE_LRF(dst32++) = curWord.value16[0];
459 HWREG_WRITE_LRF(dst32++) = curWord.value16[1];
460 #else
461 *dst32++ = curWord.value16[0];
462 *dst32++ = curWord.value16[1];
463 #endif //DeviceFamily_CC27XX
464 }
465 regionLength -= 2 * numWords;
466 address = (uintptr_t) dst32;
467 }
468 break;
469
470 case HW_Write_16bit_masked:
471 {
472 volatile uint32_t *dst32 = (volatile uint32_t *) address;
473 for (uint32_t i = 0; i < numWords; i++)
474 {
475 LRF_ConfigWord curWord;
476 curWord.value32 = *curEntry++;
477 #ifdef LRF_DEBUG_TRACE
478 Log_printf(RclCoreShort, Log_INFO1, "HW_Write_16bit_Masked: %04X: mask %04X value %04X, ",
479 dst32&0xFFFF, curWord.masked.mask16, curWord.masked.value16);
480 #endif
481 /* On full setup, do not apply mask, as the register is assumed to start at 0 */
482 if (state->includeBase)
483 {
484 #ifdef DeviceFamily_CC27XX
485 HWREG_WRITE_LRF(dst32++) = curWord.masked.value16;
486 #else
487 *dst32++ = curWord.masked.value16;
488 #endif //DeviceFamily_CC27XX
489 }
490 else
491 {
492 /* The type is intended for 16-bit registers with 32-bit aperture */
493 /* If used on a true 32-bit register, the 16 most significant bits will not be changed */
494 #ifdef DeviceFamily_CC27XX
495 uint32_t oldValue = HWREG_READ_LRF(dst32);
496 HWREG_WRITE_LRF(dst32++) = (oldValue & ~curWord.masked.mask16) | curWord.masked.value16;
497 #else
498 uint32_t oldValue = *dst32;
499 *dst32++ = (oldValue & ~curWord.masked.mask16) | curWord.masked.value16;
500 #endif //DeviceFamily_CC27XX
501 }
502 }
503 regionLength -= numWords;
504 address = (uintptr_t) dst32;
505 }
506 break;
507
508 case SW_Write_16bit:
509 {
510 volatile uint16_t *dst16 = (volatile uint16_t *) address;
511 for (uint32_t i = 0; i < numWords; i++)
512 {
513 LRF_ConfigWord curWord;
514 curWord.value32 = *curEntry++;
515 #ifdef LRF_DEBUG_TRACE
516 Log_printf(RclCore, Log_INFO1, "SW_Write_16bit: %04X = %08X, ", dst16&0xFFFF, curWord.value32);
517 #endif
518
519 #ifdef DeviceFamily_CC27XX
520 HWREGH_WRITE_LRF(dst16++) = curWord.value16[0];
521 HWREGH_WRITE_LRF(dst16++) = curWord.value16[1];
522 #else
523 *dst16++ = curWord.value16[0];
524 *dst16++ = curWord.value16[1];
525 #endif //DeviceFamily_CC27XX
526 }
527 regionLength -= 2 * numWords;
528 address = (uintptr_t) dst16;
529 }
530 break;
531
532 case HW_Write_32bit:
533 case SW_Write_32bit:
534 case Par_Write_32bit:
535 {
536 volatile uint32_t *dst32 = (volatile uint32_t *) address;
537 for (uint32_t i = 0; i < numWords; i++)
538 {
539 #ifdef LRF_DEBUG_TRACE
540 switch(operation)
541 {
542 case HW_Write_32bit:
543 Log_printf(RclCore, Log_INFO1, "HW_Write_32bit: %04X = %08X", dst32&0xffff, *curEntry);
544 break;
545 case SW_Write_32bit:
546 Log_printf(RclCore, Log_INFO1, "SW_Write_32bit: %04X = %08X", dst32&0xffff, *curEntry);
547 break;
548 case Par_Write_32bit:
549 Log_printf(RclCore, Log_INFO1, "Par_Write_32bit: %04X = %08X", dst32&0xffff, *curEntry);
550 break;
551 default:
552 break;
553 }
554 #endif
555 #ifdef DeviceFamily_CC27XX
556 HWREG_WRITE_LRF(dst32++) = *curEntry++;
557 #else
558 *dst32++ = *curEntry++;
559 #endif //DeviceFamily_CC27XX
560 }
561 regionLength -= numWords;
562 address = (uintptr_t) dst32;
563 }
564 break;
565
566 case Par_Reference_32bit:
567 {
568 #ifdef BUFFER_SPLIT_SUPPORT
569 /* Embedded constants must be contiguous */
570 if ((int32_t)regionLength > bufferAvailWords)
571 {
572 return SetupResult_ErrorParRange;
573 }
574 #endif
575 volatile uint32_t **dst32 = (volatile uint32_t **) address;
576 *dst32 = curEntry;
577 regionLength -= numWords;
578 curEntry += numWords;
579 #ifdef LRF_DEBUG_TRACE
580 Log_printf(RclCore, Log_INFO1, "Par_Reference_32bit: %04X = %08X", address, *dst32);
581 #endif
582 }
583 break;
584
585 case HW_Write_16bit_sparse:
586 for (uint32_t i = 0; i < numWords; i++)
587 {
588 LRF_ConfigWord curWord;
589 curWord.value32 = *curEntry++;
590 uint32_t curAddress = curWord.sparse.address;
591 if ((curAddress & 3) == 0)
592 {
593 /* Word aligned access to hardware */
594 uint32_t *dst32 = (uint32_t *)(address + curAddress);
595 #ifdef DeviceFamily_CC27XX
596 HWREG_WRITE_LRF(dst32) = curWord.sparse.value16;
597 #else
598 *dst32 = curWord.sparse.value16;
599 #endif //DeviceFamily_CC27XX
600 }
601 else if ((curAddress & 1) == 0)
602 {
603 /* Halfword aligned */
604 uint16_t *dst16 = (uint16_t *)(address + curAddress);
605 #ifdef DeviceFamily_CC27XX
606 HWREGH_WRITE_LRF(dst16) = curWord.sparse.value16;
607 #else
608 *dst16 = curWord.sparse.value16;
609 #endif //DeviceFamily_CC27XX
610 }
611 else
612 {
613 return SetupResult_ErrorElemAddrAlign;
614 }
615 #ifdef LRF_DEBUG_TRACE
616 Log_printf(RclCoreShort, Log_INFO, "HW_Write_16bit_sparse: 0x%04X = 0x%04X", curAddress, curWord.sparse.value16);
617 #endif
618 }
619 regionLength -= numWords;
620 break;
621
622 case SW_Write_16bit_sparse:
623 for (uint32_t i = 0; i < numWords; i++)
624 {
625 LRF_ConfigWord curWord;
626 curWord.value32 = *curEntry++;
627 if ((curWord.sparse.address & 1) == 0)
628 {
629 /* Word aligned 16 bit access */
630 uint16_t *dst16 = (uint16_t *)(address + curWord.sparse.address);
631 #ifdef DeviceFamily_CC27XX
632 HWREGH_WRITE_LRF(dst16) = curWord.sparse.value16;
633 #else
634 *dst16 = curWord.sparse.value16;
635 #endif
636 }
637 else
638 {
639 return SetupResult_ErrorElemAddrAlign;
640 }
641 #ifdef LRF_DEBUG_TRACE
642 Log_printf(RclCoreShort, Log_INFO, "SW_Write_16bit_sparse: 0x%04X = 0x%04X", curWord.sparse.address, curWord.sparse.value16);
643 #endif
644 }
645 regionLength -= numWords;
646 break;
647
648 default:
649 break;
650 }
651 #ifdef BUFFER_SPLIT_SUPPORT
652 bufferAvailWords -= numWords;
653 #endif
654 segmentLength -= numWords;
655 }
656 /* Write straggler for 16-bit */
657 if (regionLength == 1 &&
658 #ifdef BUFFER_SPLIT_SUPPORT
659 bufferAvailWords > 0 &&
660 #endif
661 (operation == HW_Write_16bit || operation == SW_Write_16bit))
662 {
663 if (segmentLength < 1)
664 {
665 return SetupResult_ErrorElemLen;
666 }
667 if (operation == SW_Write_16bit)
668 {
669 volatile uint16_t *dst16 = (volatile uint16_t *) address;
670 LRF_ConfigWord curWord;
671 curWord.value32 = *curEntry++;
672 #ifdef DeviceFamily_CC27XX
673 HWREGH_WRITE_LRF(dst16) = curWord.value16[0];
674 #else
675 *dst16 = curWord.value16[0];
676 #endif //DeviceFamily_CC27XX
677 #ifdef LRF_DEBUG_TRACE
678 Log_printf(RclCoreShort, Log_INFO, "SW_Write_16bit: 0x%04X = 0x%04X, ", dst16&0xFFFF, curWord.value16[0]);
679 #endif
680 }
681 else
682 {
683 volatile uint32_t *dst32 = (volatile uint32_t *) address;
684 LRF_ConfigWord curWord;
685 curWord.value32 = *curEntry++;
686 #ifdef DeviceFamily_CC27XX
687 HWREG_WRITE_LRF(dst32) = curWord.value16[0];
688 #else
689 *dst32 = curWord.value16[0];
690 #endif //DeviceFamily_CC27XX
691 #ifdef LRF_DEBUG_TRACE
692 Log_printf(RclCoreShort, Log_INFO, "HW_Write_16bit: 0x%04X = 0x%04X, ", dst32&0xFFFF, curWord.value16[0]);
693 #endif
694 }
695 regionLength -= 1;
696 #ifdef BUFFER_SPLIT_SUPPORT
697 bufferAvailWords--;
698 #endif
699 segmentLength--;
700 }
701 }
702 /* Done with this segment and its header */
703 #ifdef BUFFER_SPLIT_SUPPORT
704 if (bufferAvailWords == 0 && totalLength > 0)
705 {
706 state->totalLength = totalLength;
707 state->segmentLength = 0;
708 state->regionLength = 0;
709 state->operation = operation;
710
711 return SetupResult_Ok_Partial;
712 }
713 #endif
714 }
715
716 #ifdef BUFFER_SPLIT_SUPPORT
717 RCL_Debug_assert(totalLength == 0);
718
719 state->totalLength = 0;
720 #endif
721
722 return SetupResult_Ok;
723 }
724
LRF_TxPowerTable_findValue(const LRF_TxPowerTable * table,LRF_TxPowerTable_Index powerLevel)725 LRF_TxPowerTable_Entry LRF_TxPowerTable_findValue(const LRF_TxPowerTable *table, LRF_TxPowerTable_Index powerLevel)
726 {
727 if (powerLevel.rawValue == LRF_TxPower_Use_Raw.rawValue)
728 {
729 /* Handle special input argument - return raw tx power setting if supported,
730 invalid value otherwise. */
731 return LRF_getRawTxPower();
732 }
733 else if (table != NULL && table->numEntries > 0 && powerLevel.rawValue <= LRF_TxPower_Use_Max.rawValue)
734 {
735 if (powerLevel.rawValue == LRF_TxPower_Use_Min.rawValue)
736 {
737 /* Handle special input argument - return lowest possible tx power. */
738 Log_printf(RclCore, Log_INFO, "Tx table search: lowest possible");
739 return table->powerTable[0];
740 }
741 else if (powerLevel.rawValue == LRF_TxPower_Use_Max.rawValue)
742 {
743 /* Handle special input argument - return highest possible tx power. */
744 Log_printf(RclCore, Log_INFO, "Tx table search: highest possible");
745 return table->powerTable[table->numEntries - 1];
746 }
747 else if (table->powerTable[0].power.rawValue > powerLevel.rawValue)
748 {
749 /* If the first entry is already larger, then the requested
750 power level is invalid. */
751 Log_printf(RclCore, Log_INFO, "Tx table search: %d too low", powerLevel.rawValue);
752 return LRF_TxPowerEntry_INVALID_VALUE;
753 }
754 else
755 {
756 for (size_t i = 1; i < table->numEntries; i++)
757 {
758 /* Search for the first entry higher than target power level. */
759 if (table->powerTable[i].power.rawValue > powerLevel.rawValue)
760 {
761 /* Return last entry that was not larger than target power level. */
762 return table->powerTable[i - 1];
763 }
764 }
765 if (table->powerTable[table->numEntries - 1].power.rawValue == powerLevel.rawValue)
766 {
767 /* Return highest value if it matches the requested power level. */
768 return table->powerTable[table->numEntries - 1];
769 }
770 else
771 {
772 /* If no entries are larger than target power level, then the requested
773 power level is invalid. */
774 Log_printf(RclCore, Log_INFO, "Tx table search: %d too high", powerLevel.rawValue);
775 return LRF_TxPowerEntry_INVALID_VALUE;
776 }
777 }
778 }
779 else
780 {
781 /* Return invalid value. This covers LRF_TxPower_Use_None. */
782 return LRF_TxPowerEntry_INVALID_VALUE;
783 }
784 }
785