1 /*************************************************************************//**
2  * @file
3  * @brief       This file is part of the AFBR-S50 API.
4  * @details     Defines macros to work with pixel and ADC channel masks.
5  *
6  * @copyright
7  *
8  * Copyright (c) 2023, Broadcom Inc.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions are met:
13  *
14  * 1. Redistributions of source code must retain the above copyright notice, this
15  *    list of conditions and the following disclaimer.
16  *
17  * 2. Redistributions in binary form must reproduce the above copyright notice,
18  *    this list of conditions and the following disclaimer in the documentation
19  *    and/or other materials provided with the distribution.
20  *
21  * 3. Neither the name of the copyright holder nor the names of its
22  *    contributors may be used to endorse or promote products derived from
23  *    this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  *****************************************************************************/
36 
37 
38 #ifndef ARGUS_MAP_H
39 #define ARGUS_MAP_H
40 #ifdef __cplusplus
41 extern "C" {
42 #endif
43 
44 /*!***************************************************************************
45  * @defgroup    argus_map Pixel Channel Mapping
46  * @ingroup     argus_api
47  *
48  * @brief       Pixel Channel Mapping
49  *
50  * @details     The ADC Channels of each pixel or auxiliary channel on the device
51  *              are numbered in a way that is convenient on the chip architecture.
52  *              The macros in this module are defined in order to map between the
53  *              chip internal channel number (ch) to the two-dimensional
54  *              x-y-indices or one-dimensional n-index representation.
55  *
56  * @addtogroup  argus_map
57  * @{
58  *****************************************************************************/
59 
60 #include "utility/int_math.h"
61 #include <stdbool.h>
62 #include <assert.h>
63 
64 
65 /*!***************************************************************************
66  * @brief   The device pixel field size in x direction (long edge).
67  *****************************************************************************/
68 #define ARGUS_PIXELS_X  8
69 
70 /*!***************************************************************************
71  * @brief   The device pixel field size in y direction (short edge).
72  *****************************************************************************/
73 #define ARGUS_PIXELS_Y  4
74 
75 /*!***************************************************************************
76  * @brief   The total device pixel count.
77  *****************************************************************************/
78 #define ARGUS_PIXELS    ((ARGUS_PIXELS_X)*(ARGUS_PIXELS_Y))
79 
80 
81 /*!*****************************************************************************
82  * @brief   Macro to determine the pixel ADC channel number from the x-z-indices.
83  * @param   x The x-index of the pixel.
84  * @param   y The y-index of the pixel.
85  * @return  The ADC channel number of the pixel.
86  ******************************************************************************/
87 #define PIXEL_XY2CH(x, y) ((((y) << 3U) & 0x10U) | (((x) ^ 0x07U) << 1U) | ((y) & 0x01U))
88 
89 /*!*****************************************************************************
90  * @brief   Macro to determine the pixel x-index from the ADC channel number.
91  * @param   c The ADC channel number of the pixel.
92  * @return  The x-index of the pixel.
93  ******************************************************************************/
94 #define PIXEL_CH2X(c) ((((c) >> 1U) ^ 0x07U) & 0x07U)
95 
96 /*!*****************************************************************************
97  * @brief   Macro to determine the pixel y-index from the ADC channel number.
98  * @param   c The ADC channel number of the pixel.
99  * @return  The y-index of the pixel.
100  ******************************************************************************/
101 #define PIXEL_CH2Y(c) ((((c) >> 3U) & 0x02U) | ((c) & 0x01U))
102 
103 
104 /*!*****************************************************************************
105  * @brief   Macro to determine the n-index from the x-y-indices.
106  * @param   x The x-index of the pixel.
107  * @param   y The y-index of the pixel.
108  * @return  The n-index of the pixel.
109  ******************************************************************************/
110 #define PIXEL_XY2N(x, y) (((x) << 2U) | (y))
111 
112 /*!*****************************************************************************
113  * @brief   Macro to determine the pixel x-index from the n-index.
114  * @param   n The n-index of the pixel.
115  * @return  The x-index number of the pixel.
116  ******************************************************************************/
117 #define PIXEL_N2X(n) ((n) >> 2U)
118 
119 /*!*****************************************************************************
120  * @brief   Macro to determine the pixel y-index from the n-index.
121  * @param   n The n-index of the pixel.
122  * @return  The y-index number of the pixel.
123  ******************************************************************************/
124 #define PIXEL_N2Y(n) ((n) & 0x03U)
125 
126 
127 /*!*****************************************************************************
128  * @brief   Macro to determine the pixel n-index from the ADC channel number.
129  * @param   n The n-index of the pixel.
130  * @return  The ADC channel number of the pixel.
131  ******************************************************************************/
132 #define PIXEL_N2CH(n) ((((n) << 3U) & 0x10U) | ((((n) >> 1U) ^ 0x0EU) & 0x0EU) | ((n) & 0x01U))
133 
134 /*!*****************************************************************************
135  * @brief   Macro to determine the pixel
136  * @param   c The ADC channel number of the pixel.
137  * @return  The n-index of the pixel.
138  ******************************************************************************/
139 #define PIXEL_CH2N(c) (((((c) << 1U) ^ 0x1CU) & 0x1CU) | (((c) >> 3U) & 0x02U) | ((c) & 0x01U))
140 
141 
142 /*!*****************************************************************************
143  * @brief   Macro to create a pixel mask given by the pixels n-index.
144  * @param   n n-index of the pixel.
145  * @return  The pixel mask with only n-index pixel set.
146  ******************************************************************************/
147 #define PIXELN_MASK(n) (0x01U << (n))
148 
149 /*!*****************************************************************************
150  * @brief   Macro to determine if a pixel given by the n-index is enabled in a pixel mask.
151  * @param   msk 32-bit pixel mask
152  * @param   n n-index of the pixel.
153  * @return  True if the pixel (n) is enabled.
154  ******************************************************************************/
155 #define PIXELN_ISENABLED(msk, n) (((msk) >> (n)) & 0x01U)
156 
157 /*!*****************************************************************************
158  * @brief   Macro to enable a pixel given by the n-index in a pixel mask.
159  * @param   msk 32-bit pixel mask
160  * @param   n n-index of the pixel to enable.
161  ******************************************************************************/
162 #define PIXELN_ENABLE(msk, n) ((msk) |= (PIXELN_MASK(n)))
163 
164 /*!*****************************************************************************
165  * @brief   Macro disable a pixel given by the n-index in a pixel mask.
166  * @param   msk 32-bit pixel mask
167  * @param   n n-index of the pixel to disable.
168  ******************************************************************************/
169 #define PIXELN_DISABLE(msk, n) ((msk) &= (~PIXELN_MASK(n)))
170 
171 
172 /*!*****************************************************************************
173  * @brief   Macro to create a pixel mask given by the pixels ADC channel number.
174  * @param   c The ADC channel number of the pixel.
175  * @return  The 32-bit pixel mask with only pixel ADC channel set.
176  ******************************************************************************/
177 #define PIXELCH_MASK(c) (0x01U << (PIXEL_CH2N(c)))
178 
179 /*!*****************************************************************************
180  * @brief   Macro to determine if an ADC pixel channel is enabled from a pixel mask.
181  * @param   msk The 32-bit pixel mask
182  * @param   c The ADC channel number of the pixel.
183  * @return  True if the specified pixel ADC channel is enabled.
184  ******************************************************************************/
185 #define PIXELCH_ISENABLED(msk, c) (PIXELN_ISENABLED(msk, PIXEL_CH2N(c)))
186 
187 /*!*****************************************************************************
188  * @brief   Macro to enable an ADC pixel channel in a pixel mask.
189  * @param   msk The 32-bit pixel mask
190  * @param   c The pixel ADC channel number to enable.
191  ******************************************************************************/
192 #define PIXELCH_ENABLE(msk, c) (PIXELN_ENABLE(msk, PIXEL_CH2N(c)))
193 
194 /*!*****************************************************************************
195  * @brief   Macro to disable an ADC pixel channel in a pixel mask.
196  * @param   msk The 32-bit pixel mask
197  * @param   c The pixel ADC channel number to disable.
198  ******************************************************************************/
199 #define PIXELCH_DISABLE(msk, c) (PIXELN_DISABLE(msk, PIXEL_CH2N(c)))
200 
201 
202 /*!*****************************************************************************
203  * @brief   Macro to create a pixel mask given by the pixel x-y-indices.
204  * @param   x x-index of the pixel.
205  * @param   y y-index of the pixel.
206  * @return  The 32-bit pixel mask with only pixel ADC channel set.
207  ******************************************************************************/
208 #define PIXELXY_MASK(x, y) (0x01U << (PIXEL_XY2N(x, y)))
209 
210 /*!*****************************************************************************
211  * @brief   Macro to determine if a pixel given by the x-y-indices is enabled in a pixel mask.
212  * @param   msk 32-bit pixel mask
213  * @param   x x-index of the pixel.
214  * @param   y y-index of the pixel.
215  * @return  True if the pixel (x,y) is enabled.
216  ******************************************************************************/
217 #define PIXELXY_ISENABLED(msk, x, y) (PIXELN_ISENABLED(msk, PIXEL_XY2N(x, y)))
218 
219 /*!*****************************************************************************
220  * @brief   Macro to enable a pixel given by the x-y-indices in a pixel mask.
221  * @param   msk 32-bit pixel mask
222  * @param   x x-index of the pixel to enable.
223  * @param   y y-index of the pixel to enable.
224  ******************************************************************************/
225 #define PIXELXY_ENABLE(msk, x, y) (PIXELN_ENABLE(msk, PIXEL_XY2N(x, y)))
226 
227 /*!*****************************************************************************
228  * @brief   Macro disable a pixel given by the x-y-indices in a pixel mask.
229  * @param   msk 32-bit pixel mask
230  * @param   x x-index of the pixel to disable.
231  * @param   y y-index of the pixel to disable.
232  ******************************************************************************/
233 #define PIXELXY_DISABLE(msk, x, y) (PIXELN_DISABLE(msk, PIXEL_XY2N(x, y)))
234 
235 
236 /*!*****************************************************************************
237  * @brief   Macro to determine if an ADC channel is enabled in a channel mask.
238  * @param   msk 32-bit channel mask
239  * @param   ch channel number of the ADC channel.
240  * @return  True if the ADC channel is enabled.
241  ******************************************************************************/
242 #define CHANNELN_ISENABLED(msk, ch) (((msk) >> ((ch) - 32U)) & 0x01U)
243 
244 /*!*****************************************************************************
245  * @brief   Macro to determine if an ADC channel is enabled in a channel mask.
246  * @param   msk 32-bit channel mask
247  * @param   ch channel number of the ADC channel to enabled.
248  ******************************************************************************/
249 #define CHANNELN_ENABLE(msk, ch) ((msk) |= (0x01U << ((ch) - 32U)))
250 
251 /*!*****************************************************************************
252  * @brief   Macro to determine if an ADC channel is disabled in a channel mask.
253  * @param   msk 32-bit channel mask
254  * @param   ch channel number of the ADC channel to disable.
255  ******************************************************************************/
256 #define CHANNELN_DISABLE(msk, ch) ((msk) &= (~(0x01U << ((ch) - 32U))))
257 
258 
259 /*!*****************************************************************************
260  * @brief   Macro to determine the number of enabled pixel/channels in a mask
261  *          via a popcount algorithm.
262  * @param   pxmsk 32-bit pixel mask
263  * @return  The count of enabled pixel channels.
264  ******************************************************************************/
265 #define PIXEL_COUNT(pxmsk) popcount(pxmsk)
266 
267 /*!*****************************************************************************
268  * @brief   Macro to determine the number of enabled channels via a popcount
269  *          algorithm.
270  * @param   pxmsk 32-bit pixel mask
271  * @param   chmsk 32-bit channel mask
272  * @return  The count of enabled ADC channels.
273  ******************************************************************************/
274 #define CHANNEL_COUNT(pxmsk, chmsk) (popcount(pxmsk) + popcount(chmsk))
275 
276 /*!*****************************************************************************
277  * @brief   Converts a raw ADC channel mask to a x-y-sorted pixel mask.
278  * @param   msk The raw ADC channel mask to be converted.
279  * @return  The converted x-y-sorted pixel mask.
280  ******************************************************************************/
ChannelToPixelMask(uint32_t msk)281 static inline uint32_t ChannelToPixelMask(uint32_t msk)
282 {
283     uint32_t res = 0;
284     for (uint_fast8_t n = 0; n < 32; n += 2)
285     {
286         res |= ((msk >> PIXEL_N2CH(n)) & 0x3U) << n; // sets 2 bits at once
287     }
288     return res;
289 }
290 
291 /*!*****************************************************************************
292  * @brief   Converts a x-y-sorted pixel mask to a raw ADC channel mask.
293  * @param   msk The x-y-sorted pixel channel mask to be converted.
294  * @return  The converted raw ADC channel mask.
295  ******************************************************************************/
PixelToChannelMask(uint32_t msk)296 static inline uint32_t PixelToChannelMask(uint32_t msk)
297 {
298     uint32_t res = 0;
299     for (uint_fast8_t ch = 0; ch < 32; ch += 2)
300     {
301         res |= ((msk >> PIXEL_CH2N(ch)) & 0x3U) << ch; // sets 2 bits at once
302     }
303     return res;
304 }
305 
306 
307 /*!*****************************************************************************
308  * @brief   Shifts a pixel mask by a given offset.
309  *
310  * @details This moves the selected pixel pattern by a specified number of
311  *          pixels in x and y direction.
312  *          If the shift in y direction is odd (e.g +1), the pattern will be
313  *          shifted by +0.5 or -0.5 in x direction due to the hexagonal shape
314  *          of the pixel field. Thus, a center pixel (usually the Golden Pixel)
315  *          is determined that is used to determine if the pattern is shifted
316  *          by +0.5 or -0.5 pixels in x direction. The center pixel is then
317  *          always shifted without changing the x index and the surrounding
318  *          pixels are adopting its x index accordingly.
319  *
320  *          Example: Consider the flower pattern, i.e. the Golden Pixel (e.g.
321  *          5/2) is selected and all is direct neighbors (i.e. 5/1, 6/1, 6/2,
322  *          6/3, 5/3, 4/2). If the pattern is shifted by -1 in y direction, the
323  *          new Golden Pixel would be 5/1. Now all surrounding pixels are
324  *          selected, namely 4/0, 4/1, 4/2, 5/0, 5/2, 6/1). This yields again
325  *          the flower around the Golden Pixel.
326  *
327  *          Thus, the pixels can not all be shifted by the same dx/dy values due
328  *          to the hexagonal shape of the pixel field, e.g. the upper right
329  *          neighbor of 5/2 is 5/1 but the upper right neighbor of 5/1 is NOT
330  *          5/0 but 4/0!
331  *          This happens only if the shift in y direction is an odd number.
332  *          The algorithm to determine new indices is as follows:
333  *          - If the shift in y direction is even (e.g. +2, -2), no compensation
334  *            of the hexagonal shape is needed; skip compensation, simply
335  *            add/subtract indices.
336  *          - If the center pixel y index is even, pixels that will have even y
337  *            index after the shift will be additionally shifted by -1 in x
338  *            direction.
339  *          - If the center pixel y index is odd, pixel that will have odd y
340  *            index after the shift will be additionally shifted by +1 in x
341  *            direction.
342  *
343  * @see     Please also refer to the function #Argus_GetCalibrationGoldenPixel
344  *          to obtain the current Golden Pixel location.
345  *
346  * @param   pixel_mask The x-y-sorted pixel mask to be shifted.
347  * @param   dx The number of pixel to shift in x direction.
348  * @param   dy The number of pixel to shift in y direction.
349  * @param   center_y The center y index of the pattern that is shifted.
350  * @return  The shifted pixel mask.
351  ******************************************************************************/
ShiftSelectedPixels(const uint32_t pixel_mask,const int8_t dx,const int8_t dy,const uint8_t center_y)352 static inline uint32_t ShiftSelectedPixels(const uint32_t pixel_mask,
353                                            const int8_t dx,
354                                            const int8_t dy,
355                                            const uint8_t center_y)
356 {
357     if (dx == 0 && dy == 0) return pixel_mask;
358 
359     uint32_t shifted_mask = 0;
360 
361     for (int8_t x = 0; x < ARGUS_PIXELS_X; ++x)
362     {
363         for (int8_t y = 0; y < ARGUS_PIXELS_Y; ++y)
364         {
365             int8_t x_src = (int8_t)(x - dx);
366             int8_t y_src = (int8_t)(y - dy);
367 
368             if (dy & 0x1)
369             {
370                 /* Compensate for hexagonal pixel shape. */
371                 if ((center_y & 0x1) && (y & 0x1))
372                 {
373                     x_src--;
374                 }
375                 if (!(center_y & 0x1) && !(y & 0x1))
376                 {
377                     x_src++;
378                 }
379             }
380 
381             if (x_src < 0 || x_src >= ARGUS_PIXELS_X) continue;
382             if (y_src < 0 || y_src >= ARGUS_PIXELS_Y) continue;
383 
384             if (PIXELXY_ISENABLED(pixel_mask, x_src, y_src))
385             {
386                 PIXELXY_ENABLE(shifted_mask, x, y);
387             }
388         }
389     }
390 
391     return shifted_mask;
392 }
393 
394 /*!*****************************************************************************
395  * @brief   Fills a pixel mask to a specified number of pixels around a center pixel.
396  *
397  * @details The pixel mask is iteratively filled with the nearest pixel to a
398  *          specified center pixel until a specified number of pixels is achieved.
399  *          The distance between two pixel is determined via a quadratic metric,
400  *          i.e. dx^2 + dy^2. Pixels towards the lower x indices are preferred.
401  *
402  *          Note that the distance of only calculated approximately, e.g. the
403  *          y distance of pixels is considered to be 2 instead of cos(60)*2.
404  *
405  *          Nothing is done if the number of pixels already exceeds the specified
406  *          /p pixel_count parameter.
407  *
408  * @see     Please also refer to the function #Argus_GetCalibrationGoldenPixel
409  *          to obtain the current Golden Pixel location.
410  *
411  * @param   pixel_mask The x-y-sorted pixel mask to be filled with pixels.
412  * @param   pixel_count The final number of pixels in the pixel mask.
413  * @param   center_x The center pixel x-index.
414  * @param   center_y The center pixel y-index.
415  * @return  The filled pixel mask with at least /p pixel_count pixels selected.
416  ******************************************************************************/
FillPixelMask(uint32_t pixel_mask,const uint8_t pixel_count,const uint8_t center_x,const uint8_t center_y)417 static inline uint32_t FillPixelMask(uint32_t pixel_mask,
418                                      const uint8_t pixel_count,
419                                      const uint8_t center_x,
420                                      const uint8_t center_y)
421 {
422     assert(pixel_count <= ARGUS_PIXELS);
423     assert(center_x < ARGUS_PIXELS_X);
424     assert(center_y < ARGUS_PIXELS_Y);
425 
426     if (pixel_count == ARGUS_PIXELS) return 0xFFFFFFFFU;
427 
428     /* If the pattern was shifted towards boundaries, the pixel count may have
429      * decreased. In this case, the pixels closest to the reference pixel are
430      * selected. Pixel towards lower x index are prioritized. */
431     while (pixel_count > PIXEL_COUNT(pixel_mask))
432     {
433         int32_t min_dist = INT32_MAX;
434         int8_t min_x = -1;
435         int8_t min_y = -1;
436 
437         /* Find nearest not selected pixel. */
438         for(int8_t x = 0; x < ARGUS_PIXELS_X; ++x)
439         {
440             for (int8_t y = 0; y < ARGUS_PIXELS_Y; ++y)
441             {
442                 if (!PIXELXY_ISENABLED(pixel_mask, x, y))
443                 {
444                     int32_t distx = (x - center_x) << 1;
445                     if (!(y & 0x1)) distx++;
446                     if (!(center_y & 0x1)) distx--;
447 
448                     const int32_t disty = (y - center_y) << 1;
449                     int32_t dist = distx * distx + disty * disty;
450 
451                     if (dist < min_dist)
452                     {
453                         min_dist = dist;
454                         min_x = (int8_t)x;
455                         min_y = (int8_t)y;
456                     }
457                 }
458             }
459         }
460 
461         assert(min_x >= 0 && min_x < ARGUS_PIXELS_X);
462         assert(min_y >= 0 && min_y < ARGUS_PIXELS_Y);
463         assert(!PIXELXY_ISENABLED(pixel_mask, min_x, min_y));
464         PIXELXY_ENABLE(pixel_mask, min_x, min_y);
465     }
466 
467     return pixel_mask;
468 }
469 
470 /*!*****************************************************************************
471  * @brief   Fills a pixel mask with the direct neighboring pixels around a pixel.
472  *
473  * @details The pixel mask is iteratively filled with the direct neighbors of the
474  *          specified center pixel.
475  *
476  *          Note that the function is able to handle corner and edge pixels and
477  *          also to handle odd/even lines (which have different layouts)
478  *
479  * @param   x The selected pixel x-index.
480  * @param   y The selected pixel y-index.
481  * @return  The filled pixel mask with all direct neighbors of the selected pixel.
482  ******************************************************************************/
GetAdjacentPixelsMask(const uint_fast8_t x,const uint_fast8_t y)483 static inline uint32_t GetAdjacentPixelsMask(const uint_fast8_t x,
484                                              const uint_fast8_t y)
485 {
486     assert(x < ARGUS_PIXELS_X);
487     assert(y < ARGUS_PIXELS_Y);
488 
489     uint32_t mask = 0u;
490 
491     bool isXEdgeLow = (x == 0);
492     bool isXEdgeHigh = (x == (ARGUS_PIXELS_X - 1));
493     bool isYEdgeLow = (y == 0);
494     bool isYEdgeHigh = (y == (ARGUS_PIXELS_Y - 1));
495 
496     if (y % 2 == 0)
497     {
498         if (!isYEdgeLow)                        PIXELXY_ENABLE(mask, x,     y - 1);
499         if ((!isXEdgeHigh) && (!isYEdgeLow))    PIXELXY_ENABLE(mask, x + 1, y - 1);
500         if (!isXEdgeHigh)                       PIXELXY_ENABLE(mask, x + 1, y);
501         if ((!isXEdgeHigh) && (!isYEdgeHigh))   PIXELXY_ENABLE(mask, x + 1, y + 1);
502         if (!isYEdgeHigh)                       PIXELXY_ENABLE(mask, x,     y + 1);
503         if (!isXEdgeLow)                        PIXELXY_ENABLE(mask, x - 1, y);
504     }
505     else
506     {
507         if ((!isXEdgeLow) && (!isYEdgeLow))     PIXELXY_ENABLE(mask, x - 1, y - 1);
508         if (!isYEdgeLow)                        PIXELXY_ENABLE(mask, x,     y - 1);
509         if (!isXEdgeHigh)                       PIXELXY_ENABLE(mask, x + 1, y);
510         if (!isYEdgeHigh)                       PIXELXY_ENABLE(mask, x,     y + 1);
511         if ((!isXEdgeLow) && (!isYEdgeHigh))    PIXELXY_ENABLE(mask, x - 1, y + 1);
512         if (!isXEdgeLow)                        PIXELXY_ENABLE(mask, x - 1, y);
513     }
514 
515     return mask;
516 }
517 
518 
519 /*! @} */
520 #ifdef __cplusplus
521 } // extern "C"
522 #endif
523 #endif /* ARGUS_MAP_H */
524