1 //*****************************************************************************
2 //
3 //! @file am_util_ble.c
4 //!
5 //! @brief Useful BLE functions not covered by the HAL.
6 //!
7 //! This file contains functions for interacting with the BLE hardware
8 //! that are not already covered by the HAL. Most of these commands either
9 //! adjust RF settings or facilitate RF testing operations.
10 //!
11 //! @addtogroup ble BLE
12 //! @ingroup utils
13 //! @{
14 //
15 //*****************************************************************************
16
17 //*****************************************************************************
18 //
19 // Copyright (c) 2023, Ambiq Micro, Inc.
20 // All rights reserved.
21 //
22 // Redistribution and use in source and binary forms, with or without
23 // modification, are permitted provided that the following conditions are met:
24 //
25 // 1. Redistributions of source code must retain the above copyright notice,
26 // this list of conditions and the following disclaimer.
27 //
28 // 2. Redistributions in binary form must reproduce the above copyright
29 // notice, this list of conditions and the following disclaimer in the
30 // documentation and/or other materials provided with the distribution.
31 //
32 // 3. Neither the name of the copyright holder nor the names of its
33 // contributors may be used to endorse or promote products derived from this
34 // software without specific prior written permission.
35 //
36 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
37 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
40 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
41 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
42 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
43 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
44 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
45 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 // POSSIBILITY OF SUCH DAMAGE.
47 //
48 // This is part of revision release_sdk_4_4_0-3c5977e664 of the AmbiqSuite Development Package.
49 //
50 //*****************************************************************************
51
52 #include <stdint.h>
53 #include <stdbool.h>
54 #include <string.h>
55 #include "am_util_delay.h"
56 #include "am_mcu_apollo.h"
57
58 //*****************************************************************************
59 //
60 // Globals
61 //
62 //*****************************************************************************
63
64 //*****************************************************************************
65 //
66 // In DTM mode, set TX to constant trans mode for SRRC/FCC/CE
67 // set enable as 'true' to constant trans mode, 'false' back to normal
68 //
69 //*****************************************************************************
70 uint32_t
am_util_ble_set_constant_transmission(void * pHandle,bool enable)71 am_util_ble_set_constant_transmission(void *pHandle, bool enable)
72 {
73 am_hal_ble_state_t *pBLE = pHandle;
74
75 am_hal_ble_sleep_set(pBLE, false);
76 am_hal_ble_plf_reg_write(pBLE, 0x43000004, 0xFFFFFFFF);
77 if ( enable )
78 {
79 am_hal_ble_plf_reg_write(pBLE, 0x508000E0, 0x00008000);
80 }
81 else
82 {
83 am_hal_ble_plf_reg_write(pBLE, 0x508000E0, 0x00000000);
84 }
85
86 return AM_HAL_STATUS_SUCCESS;
87 }
88
89 //*****************************************************************************
90 //
91 // Manually enable/disable transmitter
92 // set ui8TxCtrl as 1 to manually enable transmitter, 0 back to default
93 //
94 //*****************************************************************************
95 uint32_t
am_util_ble_transmitter_control(void * pHandle,uint8_t ui8TxCtrl)96 am_util_ble_transmitter_control(void *pHandle, uint8_t ui8TxCtrl)
97 {
98 am_hal_ble_state_t *pBLE = pHandle;
99 uint32_t RegValueTRX;
100
101 am_hal_ble_sleep_set(pBLE, false);
102 if (ui8TxCtrl)
103 {
104 RegValueTRX = 0x2000A;
105 }
106 else
107 {
108 RegValueTRX = 0x8;
109 }
110
111 //
112 // Unlock the BLE registers.
113 //
114 am_hal_ble_plf_reg_write(pBLE, 0x43000004, 0xFFFFFFFF);
115 am_hal_ble_plf_reg_write(pBLE, 0x52400000, RegValueTRX);
116
117 return AM_HAL_STATUS_SUCCESS;
118 }
119
120 //*****************************************************************************
121 //
122 // to fix the channel 1 bug in DTM mode
123 //
124 //*****************************************************************************
125
126 uint32_t
am_util_ble_init_rf_channel(void * pHandle)127 am_util_ble_init_rf_channel(void *pHandle)
128 {
129 if (!APOLLO3_GE_B0)
130 {
131 am_hal_ble_buffer(16) sWriteCommand;
132 am_hal_ble_buffer(16) sResponse;
133 am_hal_ble_state_t *pBLE = pHandle;
134 uint32_t ui32IntEnable;
135
136 uint32_t ui32Module = pBLE->ui32Module;
137 am_hal_ble_sleep_set(pBLE, false);
138
139 //
140 //issue the HCI command with to init for the channel 1
141 //
142 sWriteCommand.bytes[0] = 0x01;
143 sWriteCommand.bytes[1] = 0x1d;
144 sWriteCommand.bytes[2] = 0x20;
145 sWriteCommand.bytes[3] = 0x01;
146 sWriteCommand.bytes[4] = 0x00;
147
148 //
149 // Temporarily disable BLE interrupts.
150 //
151 ui32IntEnable = BLEIFn(ui32Module)->INTEN;
152 BLEIFn(ui32Module)->INTEN = 0;
153
154 //
155 // reserved packet_payload
156 //
157 am_hal_ble_blocking_hci_write(pBLE,
158 AM_HAL_BLE_RAW,
159 sWriteCommand.words,
160 5);
161 BLEIFn(ui32Module)->BLEDBG_b.IOCLKON = 1;
162
163 //
164 // Wait for the response.
165 //
166 while ( BLEIFn(ui32Module)->BSTATUS_b.BLEIRQ == 0 );
167 am_hal_ble_blocking_hci_read(pBLE, sResponse.words, 0);
168
169 am_util_delay_ms(10);
170
171 //
172 // issue the HCI command with to stop test for the channel 1
173 //
174 sWriteCommand.bytes[0] = 0x01;
175 sWriteCommand.bytes[1] = 0x1f;
176 sWriteCommand.bytes[2] = 0x20;
177 sWriteCommand.bytes[3] = 0x00;
178
179 //
180 // reserved packet_payload
181 //
182 am_hal_ble_blocking_hci_write(pBLE,
183 AM_HAL_BLE_RAW,
184 sWriteCommand.words,
185 4);
186 BLEIFn(ui32Module)->BLEDBG_b.IOCLKON = 1;
187
188 //
189 // Wait for the response.
190 //
191 while ( BLEIFn(ui32Module)->BSTATUS_b.BLEIRQ == 0 );
192
193 am_hal_ble_blocking_hci_read(pBLE, sResponse.words, 0);
194
195 //
196 // Re-enable BLE interrupts.
197 //
198 BLEIFn(ui32Module)->INTCLR = ui32IntEnable;
199 BLEIFn(ui32Module)->INTEN = ui32IntEnable;
200 }
201
202 return AM_HAL_STATUS_SUCCESS;
203 }
204
205 //*****************************************************************************
206 //
207 // BLE init for BQB test
208 // set enable as 'true' to init as BQB test mode, 'false' back to default
209 //
210 //*****************************************************************************
211 uint32_t
am_util_ble_BQB_test_init(void * pHandle,bool enable)212 am_util_ble_BQB_test_init(void *pHandle, bool enable)
213 {
214 am_hal_ble_state_t *pBLE = pHandle;
215
216 am_hal_ble_sleep_set(pBLE, false);
217 am_hal_ble_plf_reg_write(pBLE, 0x43000004, 0xFFFFFFFF);
218
219 if ( enable )
220 {
221 am_hal_ble_plf_reg_write(pBLE, 0x51800028, 0x0000209c);
222 }
223 else
224 {
225 am_hal_ble_plf_reg_write(pBLE, 0x51800028, 0x00003ff6);
226 }
227
228 am_hal_ble_plf_reg_write(pBLE, 0x45800070, 0x100);
229 am_hal_ble_plf_reg_write(pBLE, 0x45800070, 0);
230
231 return AM_HAL_STATUS_SUCCESS;
232 }
233
234 //*****************************************************************************
235 //
236 // Set the 32M crystal frequency
237 // based on the tested values at customer side.
238 // set trim value smaller in case of negative frequency offset
239 // ui32TrimValue: default is 0x400
240 //
241 //*****************************************************************************
242 uint32_t
am_util_ble_crystal_trim_set(void * pHandle,uint32_t ui32TrimValue)243 am_util_ble_crystal_trim_set(void *pHandle, uint32_t ui32TrimValue)
244 {
245 am_hal_ble_state_t *pBLE = pHandle;
246 uint32_t RegValueMCGR;
247
248 ui32TrimValue &= 0x7FF;
249
250 am_hal_ble_plf_reg_read(pBLE, 0x43000004, &RegValueMCGR);
251
252 //
253 // Unlock the BLE registers.
254 //
255 am_hal_ble_plf_reg_write(pBLE, 0x43000004, 0xFFFFFFFF);
256 am_hal_ble_plf_reg_write(pBLE, 0x43800004, ui32TrimValue);
257 am_hal_ble_plf_reg_write(pBLE, 0x43000004, RegValueMCGR);
258
259 return AM_HAL_STATUS_SUCCESS;
260 }
261
262 //*****************************************************************************
263 //
264 // Manually enable/disable transmitter to output carrier signal
265 // set ui8TxChannel as 0 to 0x27 for each transmit channel, 0xFF back to normal
266 // modulate mode
267 //
268 //*****************************************************************************
269 uint32_t
am_util_ble_hci_reset(void * pHandle)270 am_util_ble_hci_reset(void *pHandle)
271 {
272 am_hal_ble_buffer(16) sWriteCommand;
273 am_hal_ble_buffer(16) sResponse;
274 am_hal_ble_state_t *pBLE = pHandle;
275 uint32_t ui32IntEnable;
276
277 am_hal_ble_sleep_set(pBLE, false);
278 uint32_t ui32Module = pBLE->ui32Module;
279
280 //
281 // issue the HCI command with to reset hci
282 //
283 sWriteCommand.bytes[0] = 0x01;
284 sWriteCommand.bytes[1] = 0x03;
285 sWriteCommand.bytes[2] = 0x0c;
286 sWriteCommand.bytes[3] = 0x00;
287
288 //
289 // Temporarily disable BLE interrupts.
290 //
291 ui32IntEnable = BLEIFn(ui32Module)->INTEN;
292 BLEIFn(ui32Module)->INTEN = 0;
293
294 am_hal_ble_blocking_hci_write(pBLE,
295 AM_HAL_BLE_RAW,
296 sWriteCommand.words,
297 4);
298 BLEIFn(ui32Module)->BLEDBG_b.IOCLKON = 1;
299
300 //
301 // Wait for the response.
302 //
303 for (uint32_t i = 0; i < 1000; i++)
304 {
305 if ( BLEIFn(ui32Module)->BSTATUS_b.BLEIRQ != 0 )
306 {
307 break;
308 }
309 else if (i == (1000 - 1))
310 {
311 return AM_HAL_BLE_NO_HCI_RESPONSE;
312 }
313 else
314 {
315 am_util_delay_ms(1);
316 }
317 }
318
319 am_hal_ble_blocking_hci_read(pBLE, sResponse.words, 0);
320
321 //
322 // Re-enable BLE interrupts.
323 //
324 BLEIFn(ui32Module)->INTCLR = ui32IntEnable;
325 BLEIFn(ui32Module)->INTEN = ui32IntEnable;
326
327 return AM_HAL_STATUS_SUCCESS;
328 }
329
330 //*****************************************************************************
331 //
332 // to do directly output modulation signal. change channel ranges from 0 to 0x27,
333 // pattern from 0 to 7.
334 //
335 //*****************************************************************************
336 uint32_t
am_util_ble_trasmitter_test_ex(void * pHandle,uint8_t channel,uint8_t pattern)337 am_util_ble_trasmitter_test_ex(void *pHandle, uint8_t channel, uint8_t pattern)
338 {
339 am_hal_ble_buffer(16) sWriteCommand;
340 am_hal_ble_buffer(16) sResponse;
341 am_hal_ble_state_t *pBLE = pHandle;
342 uint32_t ui32IntEnable;
343
344 am_hal_ble_sleep_set(pBLE, false);
345 uint32_t ui32Module = pBLE->ui32Module;
346
347 //
348 // issue the HCI command with to TX carrier wave
349 //
350 sWriteCommand.bytes[0] = 0x01;
351 sWriteCommand.bytes[1] = 0x1E;
352 sWriteCommand.bytes[2] = 0x20;
353 sWriteCommand.bytes[3] = 0x03;
354 sWriteCommand.bytes[4] = channel;
355 sWriteCommand.bytes[5] = 0x25;
356 sWriteCommand.bytes[6] = pattern;
357
358 //
359 // Temporarily disable BLE interrupts.
360 //
361 ui32IntEnable = BLEIFn(ui32Module)->INTEN;
362 BLEIFn(ui32Module)->INTEN = 0;
363
364 am_hal_ble_blocking_hci_write(pBLE,
365 AM_HAL_BLE_RAW,
366 sWriteCommand.words,
367 7);
368 BLEIFn(ui32Module)->BLEDBG_b.IOCLKON = 1;
369
370 //
371 // Wait for the response.
372 //
373 for (uint32_t i = 0; i < 100; i++)
374 {
375 if (BLEIFn(ui32Module)->BSTATUS_b.BLEIRQ != 0)
376 {
377 break;
378 }
379 else if (i == (100 - 1))
380 {
381 return AM_HAL_BLE_NO_HCI_RESPONSE;
382 }
383 else
384 {
385 am_util_delay_ms(1);
386 }
387 }
388
389 am_hal_ble_blocking_hci_read(pBLE, sResponse.words, 0);
390
391 //
392 // Re-enable BLE interrupts.
393 //
394 BLEIFn(ui32Module)->INTCLR = ui32IntEnable;
395 BLEIFn(ui32Module)->INTEN = ui32IntEnable;
396 return AM_HAL_STATUS_SUCCESS;
397 }
398
399 //*****************************************************************************
400 //
401 // to do directly receiver test. change channel ranges from 0 to 0x27, return
402 // received packets in 100ms.
403 //
404 //*****************************************************************************
405
406 uint32_t
am_util_ble_receiver_test_ex(void * pHandle,uint8_t channel,uint32_t * recvpackets)407 am_util_ble_receiver_test_ex(void *pHandle, uint8_t channel, uint32_t *recvpackets)
408 {
409 am_hal_ble_buffer(16) sWriteCommand;
410 am_hal_ble_buffer(16) sResponse;
411 am_hal_ble_state_t *pBLE = pHandle;
412 uint32_t ui32IntEnable;
413
414 uint32_t ui32Module = pBLE->ui32Module;
415 am_hal_ble_sleep_set(pBLE, false);
416
417 sWriteCommand.bytes[0] = 0x01;
418 sWriteCommand.bytes[1] = 0x1d;
419 sWriteCommand.bytes[2] = 0x20;
420 sWriteCommand.bytes[3] = 0x01;
421 sWriteCommand.bytes[4] = channel;
422
423 //
424 // Temporarily disable BLE interrupts.
425 //
426 ui32IntEnable = BLEIFn(ui32Module)->INTEN;
427 BLEIFn(ui32Module)->INTEN = 0;
428
429 //
430 // reserved packet_payload
431 //
432 am_hal_ble_blocking_hci_write(pBLE,
433 AM_HAL_BLE_RAW,
434 sWriteCommand.words,
435 5);
436 BLEIFn(ui32Module)->BLEDBG_b.IOCLKON = 1;
437
438 //
439 // Wait for the response.
440 //
441 while ( BLEIFn(ui32Module)->BSTATUS_b.BLEIRQ == 0 );
442 am_hal_ble_blocking_hci_read(pBLE, sResponse.words, 0);
443
444 am_util_delay_ms(100);
445
446 //
447 // issue the HCI command with to stop test for the channel 1
448 //
449 sWriteCommand.bytes[0] = 0x01;
450 sWriteCommand.bytes[1] = 0x1f;
451 sWriteCommand.bytes[2] = 0x20;
452 sWriteCommand.bytes[3] = 0x00;
453
454 //
455 // reserved packet_payload
456 //
457 am_hal_ble_blocking_hci_write(pBLE,
458 AM_HAL_BLE_RAW,
459 sWriteCommand.words,
460 4);
461 BLEIFn(ui32Module)->BLEDBG_b.IOCLKON = 1;
462
463 //
464 // Wait for the response.
465 //
466 while ( BLEIFn(ui32Module)->BSTATUS_b.BLEIRQ == 0 );
467
468 am_hal_ble_blocking_hci_read(pBLE, sResponse.words, 0);
469 *recvpackets = (sResponse.bytes[8] << 8) + sResponse.bytes[7];
470
471 //
472 // Re-enable BLE interrupts.
473 //
474 BLEIFn(ui32Module)->INTCLR = ui32IntEnable;
475 BLEIFn(ui32Module)->INTEN = ui32IntEnable;
476
477 return AM_HAL_STATUS_SUCCESS;
478 }
479
480 //*****************************************************************************
481 //
482 // to directly output carrier wave. change channel ranges from 0 to 0x27.
483 //
484 //*****************************************************************************
485 uint32_t
am_util_ble_set_carrier_wave_ex(void * pHandle,uint8_t channel)486 am_util_ble_set_carrier_wave_ex(void *pHandle, uint8_t channel)
487 {
488 am_hal_ble_buffer(16) sWriteCommand;
489 am_hal_ble_buffer(16) sResponse;
490 am_hal_ble_state_t *pBLE = pHandle;
491 uint32_t ui32IntEnable;
492
493 //
494 // channel 0xFF to disable the constant transmission
495 //
496 if ( channel == 0xFF )
497 {
498 am_util_ble_transmitter_control(pBLE, false);
499 return AM_HAL_STATUS_SUCCESS;
500 }
501
502 am_hal_ble_sleep_set(pBLE, false);
503 uint32_t ui32Module = pBLE->ui32Module;
504
505 //
506 // issue the HCI command with to TX carrier wave
507 //
508 sWriteCommand.bytes[0] = 0x01;
509 sWriteCommand.bytes[1] = 0x1E;
510 sWriteCommand.bytes[2] = 0x20;
511 sWriteCommand.bytes[3] = 0x03;
512 sWriteCommand.bytes[4] = channel;
513 sWriteCommand.bytes[5] = 0x25;
514 sWriteCommand.bytes[6] = 0x00;
515
516 //
517 // Temporarily disable BLE interrupts.
518 //
519 ui32IntEnable = BLEIFn(ui32Module)->INTEN;
520 BLEIFn(ui32Module)->INTEN = 0;
521
522 am_hal_ble_blocking_hci_write(pBLE,
523 AM_HAL_BLE_RAW,
524 sWriteCommand.words,
525 7);
526 BLEIFn(ui32Module)->BLEDBG_b.IOCLKON = 1;
527
528 //
529 // Wait for the response.
530 //
531 for (uint32_t i = 0; i < 100; i++)
532 {
533 if (BLEIFn(ui32Module)->BSTATUS_b.BLEIRQ != 0)
534 {
535 break;
536 }
537 else if (i == (100 - 1))
538 {
539 return AM_HAL_BLE_NO_HCI_RESPONSE;
540 }
541 else
542 {
543 am_util_delay_ms(1);
544 }
545 }
546
547 am_hal_ble_blocking_hci_read(pBLE, sResponse.words, 0);
548
549 //
550 // Re-enable BLE interrupts.
551 //
552 BLEIFn(ui32Module)->INTCLR = ui32IntEnable;
553 BLEIFn(ui32Module)->INTEN = ui32IntEnable;
554
555 am_util_ble_transmitter_control(pBLE, true);
556
557 return AM_HAL_STATUS_SUCCESS;
558 }
559
560 //*****************************************************************************
561 //
562 // Manually enable/disable transmitter to output carrier wave signal
563 // set ui8TxChannel as 0 to 0x27 for each transmit channel, 0xFF back to normal
564 // modulate mode
565 //
566 //*****************************************************************************
567 uint32_t
am_util_ble_transmitter_control_ex(void * pHandle,uint8_t ui8TxChannel)568 am_util_ble_transmitter_control_ex(void *pHandle, uint8_t ui8TxChannel)
569 {
570 return am_util_ble_set_carrier_wave_ex(pHandle, ui8TxChannel);
571 }
572
573 //*****************************************************************************
574 //
575 // to directly output constant modulation signal. change channel from 0 to 0x27.
576 //
577 //*****************************************************************************
578 uint32_t
am_util_ble_set_constant_transmission_ex(void * pHandle,uint8_t channel)579 am_util_ble_set_constant_transmission_ex(void *pHandle, uint8_t channel)
580 {
581 am_hal_ble_buffer(16) sWriteCommand;
582 am_hal_ble_buffer(16) sResponse;
583 am_hal_ble_state_t *pBLE = pHandle;
584 uint32_t ui32IntEnable;
585
586 //
587 // channel 0xFF to disable the constant transmission
588 //
589 if ( channel == 0xFF )
590 {
591 am_util_ble_set_constant_transmission(pBLE, false);
592 return AM_HAL_STATUS_SUCCESS;
593 }
594
595 uint32_t ui32Module = pBLE->ui32Module;
596 am_util_ble_set_constant_transmission(pBLE, true);
597
598 //
599 // issue the HCI command with to TX constant transmission
600 //
601 sWriteCommand.bytes[0] = 0x01;
602 sWriteCommand.bytes[1] = 0x1E;
603 sWriteCommand.bytes[2] = 0x20;
604 sWriteCommand.bytes[3] = 0x03;
605 sWriteCommand.bytes[4] = channel;
606 sWriteCommand.bytes[5] = 0x25;
607 sWriteCommand.bytes[6] = 0x00;
608
609 //
610 // Temporarily disable BLE interrupts.
611 //
612 ui32IntEnable = BLEIFn(ui32Module)->INTEN;
613 BLEIFn(ui32Module)->INTEN = 0;
614
615 am_hal_ble_blocking_hci_write(pBLE,
616 AM_HAL_BLE_RAW,
617 sWriteCommand.words,
618 7);
619 BLEIFn(ui32Module)->BLEDBG_b.IOCLKON = 1;
620
621 //
622 // Wait for the response.
623 //
624 for (uint32_t i = 0; i < 100; i++)
625 {
626 if (BLEIFn(ui32Module)->BSTATUS_b.BLEIRQ != 0)
627 {
628 break;
629 }
630 else if (i == (100 - 1))
631 {
632 return AM_HAL_BLE_NO_HCI_RESPONSE;
633 }
634 else
635 {
636 am_util_delay_ms(1);
637 }
638 }
639
640 am_hal_ble_blocking_hci_read(pBLE, sResponse.words, 0);
641
642 //
643 // Re-enable BLE interrupts.
644 //
645 BLEIFn(ui32Module)->INTCLR = ui32IntEnable;
646 BLEIFn(ui32Module)->INTEN = ui32IntEnable;
647
648 return AM_HAL_STATUS_SUCCESS;
649 }
650
651 //*****************************************************************************
652 //
653 // read current modex value from BLEIP
654 //
655 //*****************************************************************************
656 uint32_t
am_util_ble_read_modex_value(void * pHandle)657 am_util_ble_read_modex_value(void *pHandle)
658 {
659 am_hal_ble_state_t *pBLE = pHandle;
660 uint32_t temp = 0;
661 if (APOLLO3_GE_B0)
662 {
663 //
664 // for B0 Chip,the modex value address is changed to 0x20006874
665 //
666 am_hal_ble_plf_reg_read(pBLE, 0x20006874, &temp);
667 }
668 else
669 {
670 am_hal_ble_plf_reg_read(pBLE, 0x20006070, &temp);
671 }
672 return temp;
673 }
674
675 //*****************************************************************************
676 //
677 // End Doxygen group.
678 //! @}
679 //
680 //*****************************************************************************
681
682