Arm-2D  
2D Image Processing Library for Cortex-M Processors
arm_2d_helper.h
1/*
2 * Copyright (C) 2022 Arm Limited or its affiliates. All rights reserved.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Licensed under the Apache License, Version 2.0 (the License); you may
7 * not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
14 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19/* ----------------------------------------------------------------------
20 * Project: Arm-2D Library
21 * Title: #include "arm_2d_helper.h"
22 * Description: Public header file for the all helper services
23 *
24 * $Date: 04. April 2024
25 * $Revision: V.1.7.8
26 *
27 * Target Processor: Cortex-M cores
28 * -------------------------------------------------------------------- */
29
30#ifndef __ARM_2D_HELPER_H__
31#define __ARM_2D_HELPER_H__
32
33/*============================ INCLUDES ======================================*/
34#include "arm_2d.h"
35#include "./__arm_2d_helper_common.h"
36#include "./arm_2d_helper_pfb.h"
37#include "./arm_2d_helper_scene.h"
38#include "./arm_2d_disp_adapters.h"
39#include "./arm_2d_helper_list.h"
40//#include "./arm_2d_helper_map.h"
41
42#include <stdlib.h>
43#include <assert.h>
44
45#ifdef __cplusplus
46extern "C" {
47#endif
48
49#if defined(__clang__)
50# pragma clang diagnostic push
51# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
52# pragma clang diagnostic ignored "-Wunused-function"
53# pragma clang diagnostic ignored "-Wmissing-declarations"
54# pragma clang diagnostic ignored "-Wpadded"
55#elif defined(__IS_COMPILER_ARM_COMPILER_5__)
56# pragma diag_suppress 64
57#endif
58
59
60/* OOC header, please DO NOT modify */
61#ifdef __ARM_2D_HELPER_IMPLEMENT__
62# define __ARM_2D_IMPL__
63#elif defined(__ARM_2D_HELPER_INHERIT__)
64# undef __ARM_2D_HELPER_INHERIT__
65# define __ARM_2D_INHERIT__
66#endif
67#include "arm_2d_utils.h"
68
69/*!
70 * \addtogroup Deprecated
71 * @{
72 */
73#define arm_2d_draw_box arm_2d_helper_draw_box
74/*! @} */
75
76/*!
77 * \addtogroup gHelper 8 Helper Services
78 * @{
79 */
80/*============================ MACROS ========================================*/
81/*============================ MACROFIED FUNCTIONS ===========================*/
82
83/*!
84 * \brief set an alarm with given period and check the status
85 *
86 * \param[in] __ms a time period in millisecond
87 * \param[in] ... an optional timestamp holder
88 *
89 * \return bool whether it is timeout
90 */
91#define arm_2d_helper_is_time_out(__ms, ...) \
92 ({ static int64_t arm_2d_safe_name(s_lTimestamp); \
93 __arm_2d_helper_is_time_out(arm_2d_helper_convert_ms_to_ticks(__ms), \
94 (&arm_2d_safe_name(s_lTimestamp),##__VA_ARGS__));})
95
96
97#define arm_2d_helper_time_elapsed(__timestamp_ptr) \
98 arm_2d_helper_convert_ticks_to_ms( \
99 __arm_2d_helper_time_elapsed(__timestamp_ptr))
100
101/*!
102 * \brief calculate the stroke of a liner slider based on time
103 *
104 * \param[in] __from the start of the slider
105 * \param[in] __to the end of the slider
106 * \param[in] __ms a given period (ms) in which the slider should finish the
107 * whole stroke
108 * \param[out] __stroke_ptr the address of an int32_t stroke variable
109 * \param[in] ... an optional address of a timestamp variable, if you omit it,
110 * NULL will be passed, and the code that call this funtion will not
111 * be reentrant.
112 * \retval true the slider has finished the whole stroke
113 * \retval false the slider hasn't reach the target end
114 */
115#define arm_2d_helper_time_liner_slider( __from, \
116 __to, \
117 __ms, \
118 __stroke_ptr, \
119 ...) \
120 ({static int64_t arm_2d_safe_name(s_lTimestamp); \
121 __arm_2d_helper_time_liner_slider((__from), \
122 (__to), \
123 arm_2d_helper_convert_ms_to_ticks(__ms), \
124 (__stroke_ptr), \
125 (&arm_2d_safe_name(s_lTimestamp),##__VA_ARGS__));})
126
127/*!
128 * \brief calculate the stroke of a cosine slider based on time
129 *
130 * \param[in] __from the start of the slider
131 * \param[in] __to the end of the slider
132 * \param[in] __ms a given period (ms) in which the slider should finish the
133 * whole stroke
134 * \param[in] __phase the phase offset
135 * \param[out] __stroke_ptr the address of an int32_t stroke variable
136 * \param[in] ... an optional address of a timestamp variable, if you omit it,
137 * NULL will be passed, and the code that call this funtion will not
138 * be reentrant.
139 * \retval true the slider has finished the whole stroke
140 * \retval false the slider hasn't reach the target end
141 */
142#define arm_2d_helper_time_cos_slider( __from, \
143 __to, \
144 __ms, \
145 __phase, \
146 __stroke_ptr, \
147 ...) \
148 ({static int64_t arm_2d_safe_name(s_lTimestamp); \
149 __arm_2d_helper_time_cos_slider((__from), \
150 (__to), \
151 arm_2d_helper_convert_ms_to_ticks(__ms), \
152 (__phase), \
153 (__stroke_ptr), \
154 (&arm_2d_safe_name(s_lTimestamp),##__VA_ARGS__));})
155
156/*!
157 * \brief calculate the stroke of a cosine slider(0~pi) based on time
158 *
159 * \param[in] __from the start of the slider
160 * \param[in] __to the end of the slider
161 * \param[in] __ms a given period (ms) in which the slider should finish the
162 * whole stroke
163 * \param[out] __stroke_ptr the address of an int32_t stroke variable
164 * \param[in] ... an optional address of a timestamp variable, if you omit it,
165 * NULL will be passed, and the code that call this funtion will not
166 * be reentrant.
167 * \retval true the slider has finished the whole stroke
168 * \retval false the slider hasn't reach the target end
169 */
170#define arm_2d_helper_time_half_cos_slider( __from, \
171 __to, \
172 __ms, \
173 __stroke_ptr, \
174 ...) \
175 ({static int64_t arm_2d_safe_name(s_lTimestamp); \
176 __arm_2d_helper_time_half_cos_slider((__from), \
177 (__to), \
178 arm_2d_helper_convert_ms_to_ticks(__ms), \
179 (__stroke_ptr), \
180 (&arm_2d_safe_name(s_lTimestamp),##__VA_ARGS__));})
181
182
183/*!
184 * \brief initialize/implement a given film (arm_2d_helper_file_t) object
185 * at compile-time.
186 * \param[in] __sprites_tile the sprites tile
187 * \param[in] __width the width of each frame
188 * \param[in] __height the height of each frame
189 * \param[in] __column the number of frames per row in the sprite tile
190 * \param[in] __frame_count the total number of frames in the sprite tile
191 * \param[in] __period the period per-frame
192 * \note __period is used as a reference for applications. The helper service
193 * doesn't use it at all.
194 */
195#define impl_film( __sprites_tile, \
196 __width, \
197 __height, \
198 __column, \
199 __frame_count, \
200 __period) \
201 { \
202 .use_as__arm_2d_tile_t = \
203 impl_child_tile((__sprites_tile), 0, 0, (__width), (__height)), \
204 .hwColumn = (__column), \
205 .hwFrameNum = (__frame_count), \
206 .hwPeriodPerFrame = (__period), \
207 }
208
209#define IMPL_FONT_DRAW_CHAR(__NAME) \
210 arm_fsm_rt_t __NAME(const arm_2d_tile_t *ptTile, \
211 const arm_2d_region_t *ptRegion, \
212 arm_2d_tile_t *ptileChar, \
213 COLOUR_INT tForeColour, \
214 uint_fast8_t chOpacity, \
215 float fScale)
216
217#define IMPL_FONT_GET_CHAR_DESCRIPTOR(__NAME) \
218 arm_2d_char_descriptor_t *__NAME( \
219 const arm_2d_font_t *ptFont, \
220 arm_2d_char_descriptor_t *ptDescriptor, \
221 uint8_t *pchCharCode)
222
223/*============================ TYPES =========================================*/
224
225/*!
226 * \brief a helper class to represent a GIF-like resource
227 */
228typedef struct arm_2d_helper_film_t {
229 implement(arm_2d_tile_t); /*!< derived from arm_2d_tile_t */
230 uint16_t hwColumn; /*!< number of frames per row in a sprite tile */
231 uint16_t hwFrameNum; /*!< the total number of frames */
232 uint16_t hwPeriodPerFrame; /*!< the period per frame (optional, used as a reference) */
233 uint16_t hwFrameIndex; /*!< the frame index used at runtime */
235
236/*!
237 * \brief the configuration structure for the Proportional-Integral Control
238 *
239 */
241 int32_t nInterval;
242 float fProportion;
243 float fIntegration;
245
246/*!
247 * \brief a helper class for Proportional-Integral Control
248 */
250
251ARM_PRIVATE (
253 int64_t lTimestamp;
254 int32_t nTimeResidual;
255 int32_t iCurrent;
256 float fOP;
259
261 uint16_t hwPointer;
262 uint16_t hwDataAvailable;
263};
264
265typedef struct arm_2d_byte_fifo_t {
266ARM_PROTECTED (
267 uint8_t *pchBuffer;
268 uint16_t hwSize;
269 uint16_t hwTail;
270
271 struct __arm_2d_fifo_reader_pointer tHead;
272 struct __arm_2d_fifo_reader_pointer tPeek;
273)
275
276typedef struct {
277 arm_2d_tile_t tileChar;
278 int16_t iAdvance;
279 int16_t iBearingX;
280 int16_t iBearingY;
281 int8_t chCodeLength;
282 int8_t : 8;
284
285typedef struct arm_2d_font_t arm_2d_font_t;
286
287typedef arm_2d_char_descriptor_t *arm_2d_font_get_char_descriptor_handler_t(
288 const arm_2d_font_t *ptFont,
289 arm_2d_char_descriptor_t *ptDescriptor,
290 uint8_t *pchCharCode);
291
292typedef arm_fsm_rt_t arm_2d_font_draw_char_handler_t(
293 const arm_2d_tile_t *ptTile,
294 const arm_2d_region_t *ptRegion,
295 arm_2d_tile_t *ptileChar,
296 COLOUR_INT tForeColour,
297 uint_fast8_t chOpacity,
298 float fScale);
299
300/* Font definitions */
302 arm_2d_tile_t tileFont;
304 uint32_t nCount; //!< Character count
305
306 arm_2d_font_get_char_descriptor_handler_t *fnGetCharDescriptor; //!< On-Get-Char-Descriptor event handler
307 arm_2d_font_draw_char_handler_t *fnDrawChar; //!< On-Draw-Char event handler
308};
309
310typedef struct arm_2d_char_idx_t {
311 uint8_t chStartCode[4];
312 uint16_t hwCount;
313 uint16_t hwOffset;
315
316typedef struct arm_2d_user_font_t {
317 implement(arm_2d_font_t);
318 uint16_t hwCount;
319 uint16_t hwDefaultCharIndex;
320 arm_2d_char_idx_t tLookUpTable[];
322
323/*============================ GLOBAL VARIABLES ==============================*/
324/*============================ LOCAL VARIABLES ===============================*/
325/*============================ PROTOTYPES ====================================*/
326
327/*!
328 * \brief initialize helper services
329 */
330extern
332
333/*!
334 * \brief backend task for asynchronose mode
335 */
336extern
338
339/*!
340 * \brief convert ticks of a reference timer to millisecond
341 *
342 * \param[in] lTick the tick count
343 * \return int64_t the millisecond
344 */
345extern
347
348/*!
349 * \brief convert millisecond into ticks of the reference timer
350 *
351 * \param[in] wMS the target time in millisecond
352 * \return int64_t the ticks
353 */
354extern
356
357/*!
358 * \brief get the reference clock frequency
359 * \return uint32_t the frequency
360 */
361extern
363
364/*!
365 * \brief get the current system stamp from the reference clock
366 *
367 * \return int64_t the timestamp in ticks
368 * \note you have to call arm_2d_helper_convert_ticks_to_ms() to convert the
369 * the timestamp into milliseconds when required.
370 */
371extern
373
374/*!
375 * \brief get the elapsed time since a reference timestamp
376 * \param[in] plTimestamp the reference timestamp
377 * \return int64_t the timestamp in ticks
378 */
379extern
380ARM_NONNULL(1)
381int64_t __arm_2d_helper_time_elapsed(int64_t *plTimestamp);
382
383/*!
384 * \brief set an alarm with given period and check the status
385 *
386 * \param[in] lPeriod a time period in ticks
387 * \param[in] plTimestamp a pointer points to an int64_t integer, if NULL is
388 * passed, an static local variable inside the function will be used
389 * \return bool whether it is timeout or not
390 */
391ARM_NONNULL(2)
392extern
393bool __arm_2d_helper_is_time_out(int64_t lPeriod, int64_t *plTimestamp);
394
395/*!
396 * \brief get a new semaphore from host RTOS
397 * \return uintptr_t a handler for the semaphore
398 */
399extern
401
402/*!
403 * \brief free a semaphore
404 * \param[in] pSemaphore the target semaphore
405 */
406extern
407void arm_2d_port_free_semaphore(uintptr_t pSemaphore);
408
409/*!
410 * \brief wait for a semaphore
411 * \param[in] pSemaphore the target semaphore
412 * \retval true we get the semaphore
413 * \retval false we haven't get the sempahore
414 */
415extern
416bool arm_2d_port_wait_for_semaphore(uintptr_t pSemaphore);
417
418/*!
419 * \brief set a semaphore
420 * \param[in] pSemaphore the target semaphore
421 */
422extern
423void arm_2d_port_set_semaphore(uintptr_t pSemaphore);
424
425/*!
426 * \brief calculate the stroke of a liner slider based on time
427 *
428 * \param[in] nFrom the start of the slider
429 * \param[in] nTo the end of the slider
430 * \param[in] lPeriod a given period in which the slider should finish the whole
431 * stroke
432 * \param[out] pnStroke the address of an int32_t stroke variable
433 * \param[in] plTimestamp the address of a timestamp variable, if you pass NULL
434 * the code that call this funtion will not be reentrant.
435 * \retval true the slider has finished the whole stroke
436 * \retval false the slider hasn't reach the target end
437 */
438ARM_NONNULL(4,5)
439extern
441 int32_t nTo,
442 int64_t lPeriod,
443 int32_t *pnStroke,
444 int64_t *plTimestamp);
445
446/*!
447 * \brief calculate the stroke of a cosine slider (0~pi) based on time
448 *
449 * \param[in] nFrom the start of the slider
450 * \param[in] nTo the end of the slider
451 * \param[in] lPeriod a given period in which the slider should finish the whole
452 * stroke
453 * \param[out] pnStroke the address of an int32_t stroke variable
454 * \param[in] plTimestamp the address of a timestamp variable, if you pass NULL
455 * the code that call this funtion will not be reentrant.
456 * \retval true the slider has finished the whole stroke
457 * \retval false the slider hasn't reach the target end
458 */
459ARM_NONNULL(4,5)
460extern
462 int32_t nTo,
463 int64_t lPeriod,
464 int32_t *pnStroke,
465 int64_t *plTimestamp);
466
467/*!
468 * \brief calculate the stroke of a consine slider (0~2pi) based on time
469 *
470 * \param[in] nFrom the start of the slider
471 * \param[in] nTo the end of the slider
472 * \param[in] lPeriod a given period in which the slider should finish the whole
473 * stroke
474 * \param[in] lPhase the phase offset
475 * \param[out] pnStroke the address of an int32_t stroke variable
476 * \param[in] plTimestamp the address of a timestamp variable, if you pass NULL
477 * the code that call this funtion will not be reentrant.
478 * \retval true the slider has finished the whole stroke
479 * \retval false the slider hasn't reach the target end
480 */
481ARM_NONNULL(5,6)
482extern
484 int32_t nTo,
485 int64_t lPeriod,
486 float fPhase,
487 int32_t *pnStroke,
488 int64_t *plTimestamp);
489
490/*!
491 * \brier colour intrapolation
492 * \param[in] wFrom a 32bit colour (4 8bit colour channels) on the start
493 * \param[in] wTo a 32bit colour (4 8bit colour channels) on the end
494 * \param[in] nDistance the reference full distance between two end points
495 * \param[in] nOffset the offset from the start
496 * \return uint32_t 32bit colour
497 */
498extern
499uint32_t __arm_2d_helper_colour_slider( uint32_t wFrom,
500 uint32_t wTo,
501 int32_t nDistance,
502 int32_t nOffset);
503
504/*!
505 * \brief initialize the Proportional-Integral Control helper
506 * \param[in] the target helper control block
507 * \param[in] the configuration structure, NULL means using the default
508 * parameters, i.e P = 5.0f, I = 3.0f and Interval = 20ms
509 * \param[in] nStartPosition the start postion
510 * \return arm_2d_helper_pi_slider_t* the control block
511 */
512extern
513ARM_NONNULL(1)
517 int32_t nStartPosition);
518
519/*!
520 * \brief A helper function for Proportional-Integral Control
521 * \param[in] ptThis the control block (arm_2d_helper_pi_slider_t)
522 * \param[in] nTargetPosition the new target position
523 * \param[in] pnResult a int32_t buffer for reading the current postion
524 * \retval true the slider has reached the target postion
525 * \retval false the slider is still moving
526 */
527extern
528ARM_NONNULL( 1, 3 )
530 int32_t nTargetPosition,
531 int32_t *pnResult);
532
533/*!
534 * \brier draw a box with specified colour, border width and opacity
535 * \param[in] ptTarget the target tile
536 * \param[in] ptRegion the target region
537 * \param[in] iBorderWidth the border width
538 * \param[in] tColour the target colour
539 * \param[in] chOpacity the opacity
540 */
541extern
543 const arm_2d_region_t *ptRegion,
544 int16_t iBorderWidth,
545 COLOUR_INT tColour,
546 uint8_t chOpacity);
547
548/*!
549 * \brier move to the next frame of a given film
550 * \param[in] ptThis the target film
551 */
552extern
553ARM_NONNULL(1)
555
556/*!
557 * \brier reset the frame index to zero
558 * \param[in] ptThis the target film
559 */
560extern
561ARM_NONNULL(1)
563
564/*!
565 * \brier reset the frame index to a specified value and wrap around if the
566 * index number is out of range.
567 * \param[in] ptThis the target film
568 * \param[in] nIndex the given index
569 */
570extern
571ARM_NONNULL(1)
573
574/*----------------------------------------------------------------------------*
575 * FIFO Helper Service *
576 *----------------------------------------------------------------------------*/
577
578/*!
579 * \brief initialize a given byte fifo
580 * \param[in] ptThis the target FIFO control block
581 * \param[in] pBuffer a buffer for storing the data
582 * \param[in] hwSize the buffer size
583 * \retval false Illegal parameters
584 * \retval true the target FIFO is initialized
585 */
586extern
587ARM_NONNULL(1,2)
589 void *pBuffer,
590 uint16_t hwSize);
591
592/*!
593 * \brief Empty a given byte fifo
594 * \param[in] ptThis the target byte fifo
595 */
596extern
597ARM_NONNULL(1)
599
600/*!
601 * \brief write a byte to a given fifo
602 * \param[in] ptThis the target FIFO control block
603 * \param[in] chChar the target byte
604 * \retval false the FIFO is FULL
605 * \retval true operation is successful
606 */
607extern
608ARM_NONNULL(1)
609bool arm_2d_byte_fifo_enqueue(arm_2d_byte_fifo_t *ptThis, uint8_t chChar);
610
611/*!
612 * \brief read a byte from a given fifo
613 * \param[in] ptThis the target FIFO control block
614 * \param[in] pchChar a buffer to store the byte, NULL means drop a byte
615 * \retval false the FIFO is EMPTY
616 * \retval true operation is successful
617 */
618extern
619ARM_NONNULL(1)
620bool arm_2d_byte_fifo_dequeue(arm_2d_byte_fifo_t *ptThis, uint8_t *pchChar);
621
622/*!
623 * \brief peek a byte continuously from a given fifo
624 * \param[in] ptThis the target FIFO control block
625 * \param[in] pchChar a buffer to store the byte, NULL means drop a byte
626 * \retval false the FIFO is EMPTY
627 * \retval true operation is successful
628 */
629extern
630ARM_NONNULL(1)
632 uint8_t *pchChar,
633 bool bMovePointer);
634
635/*!
636 * \brief drop all peeked byte from a given fifo
637 * \param[in] ptThis the target FIFO control block
638 * \return none
639 */
640extern
641ARM_NONNULL(1)
643
644/*!
645 * \brief reset the peek pointer, so you can restart from the beginning to peek.
646 * \param[in] ptThis the target FIFO control block
647 * \return none
648 */
649ARM_NONNULL(1)
651
652/*----------------------------------------------------------------------------*
653 * Misc *
654 *----------------------------------------------------------------------------*/
655
656/*!
657 * \brief swap the high and low bytes for each rgb16 pixel
658 *
659 * \param[in] phwBuffer the pixel buffer
660 * \note the phwBuffer MUST aligned to half-word addresses
661 *
662 * \param[in] wSize the number of pixels
663 */
664extern
665void arm_2d_helper_swap_rgb16(uint16_t *phwBuffer, uint32_t wCount);
666
667/*!
668 * \brief return a valid code length of a given UTF8 char
669 * \param[in] pchChar the start address of an UTF8 char
670 * \retval -1 this isn't a legal UTF8 char
671 * \retval >0 the UTF8 char length
672 */
673ARM_NONNULL(1)
674int8_t arm_2d_helper_get_utf8_byte_valid_length(const uint8_t *pchChar);
675
676/*!
677 * \brief return the code length based on the first byte of a given UTF8 char
678 * \param[in] pchChar the start address of an UTF8 char
679 * \retval -1 this isn't a legal UTF8 char
680 * \retval >0 the UTF8 char length
681 */
682ARM_NONNULL(1)
683int8_t arm_2d_helper_get_utf8_byte_length(const uint8_t *pchChar);
684
685
686/*!
687 * \brief convert an UTF8 char into unicode char
688 *
689 * \param[in] pchUTF8
690 * \return uint32_t generated unicode
691 */
692ARM_NONNULL(1)
693extern
694uint32_t arm_2d_helper_utf8_to_unicode(const uint8_t *pchUTF8);
695
696/*!
697 * \brief get char descriptor
698 * \param[in] ptFont the target font
699 * \param[in] ptDescriptor a buffer to store a char descriptor
700 * \param[in] pchCharCode an UTF8 Char
701 * \return arm_2d_char_descriptor_t * the descriptor
702 */
703ARM_NONNULL(1,2,3)
706 arm_2d_char_descriptor_t *ptDescriptor,
707 uint8_t *pchCharCode);
708
709extern
710ARM_NONNULL(1)
711/*!
712 * \brief fill the target tile with a specified colour
713 *
714 * \param[in] ptTile the target tile
715 * \param[in] tColourFormat the colour format of the target tile
716 * \param[in] tColour the target colour
717 */
719 arm_2d_color_info_t tColourFormat,
720 arm_2d_colour_t tColour);
721
722#if __ARM_2D_HELPER_CFG_LAYOUT_DEBUG_MODE__
723extern
724ARM_NONNULL(1)
725void __arm_2d_helper_layout_debug_print_label(const arm_2d_tile_t *ptTile,
726 arm_2d_region_t *ptRegion,
727 const char *pchString);
728#endif
729
730/*! @} */
731
732#if defined(__clang__)
733# pragma clang diagnostic pop
734#elif __IS_COMPILER_ARM_COMPILER_5__
735#pragma diag_warning 64
736#endif
737
738#undef __ARM_2D_HELPER_IMPLEMENT__
739#undef __ARM_2D_HELPER_INHERIT__
740
741
742#ifdef __cplusplus
743}
744#endif
745
746#endif