AFBR-S50 API Reference Manual  v1.6.5
AFBR-S50 Time-of-Flight Sensor SDK for Embedded Software
argus_map.h
Go to the documentation of this file.
1 /*************************************************************************/
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  ******************************************************************************/
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  ******************************************************************************/
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  ******************************************************************************/
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  ******************************************************************************/
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  ******************************************************************************/
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 
520 #ifdef __cplusplus
521 } // extern "C"
522 #endif
523 #endif /* ARGUS_MAP_H */
ARGUS_PIXELS
#define ARGUS_PIXELS
The total device pixel count.
Definition: argus_map.h:78
int_math.h
This file is part of the AFBR-S50 API.
ARGUS_PIXELS_X
#define ARGUS_PIXELS_X
The device pixel field size in x direction (long edge).
Definition: argus_map.h:68
ShiftSelectedPixels
static uint32_t ShiftSelectedPixels(const uint32_t pixel_mask, const int8_t dx, const int8_t dy, const uint8_t center_y)
Shifts a pixel mask by a given offset.
Definition: argus_map.h:352
PIXELXY_ENABLE
#define PIXELXY_ENABLE(msk, x, y)
Macro to enable a pixel given by the x-y-indices in a pixel mask.
Definition: argus_map.h:225
PIXELXY_ISENABLED
#define PIXELXY_ISENABLED(msk, x, y)
Macro to determine if a pixel given by the x-y-indices is enabled in a pixel mask.
Definition: argus_map.h:217
PIXEL_COUNT
#define PIXEL_COUNT(pxmsk)
Macro to determine the number of enabled pixel/channels in a mask via a popcount algorithm.
Definition: argus_map.h:265
PIXEL_N2CH
#define PIXEL_N2CH(n)
Macro to determine the pixel n-index from the ADC channel number.
Definition: argus_map.h:132
ARGUS_PIXELS_Y
#define ARGUS_PIXELS_Y
The device pixel field size in y direction (short edge).
Definition: argus_map.h:73
FillPixelMask
static uint32_t FillPixelMask(uint32_t pixel_mask, const uint8_t pixel_count, const uint8_t center_x, const uint8_t center_y)
Fills a pixel mask to a specified number of pixels around a center pixel.
Definition: argus_map.h:417
GetAdjacentPixelsMask
static uint32_t GetAdjacentPixelsMask(const uint_fast8_t x, const uint_fast8_t y)
Fills a pixel mask with the direct neighboring pixels around a pixel.
Definition: argus_map.h:483
PixelToChannelMask
static uint32_t PixelToChannelMask(uint32_t msk)
Converts a x-y-sorted pixel mask to a raw ADC channel mask.
Definition: argus_map.h:296
PIXEL_CH2N
#define PIXEL_CH2N(c)
Macro to determine the pixel.
Definition: argus_map.h:139
ChannelToPixelMask
static uint32_t ChannelToPixelMask(uint32_t msk)
Converts a raw ADC channel mask to a x-y-sorted pixel mask.
Definition: argus_map.h:281