-
Notifications
You must be signed in to change notification settings - Fork 0
/
at_utils.h
958 lines (788 loc) · 36.2 KB
/
at_utils.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
/****************************************************************************
** R@P PROJECT
*****************************************************************************
** AT_UTILS
** Useful Atmel configuration macros
*****************************************************************************
** Author: Orso Eric
** Creation Date: 21/05/09
** Last Edit Date:
** Revision: 4
** Version: 1.3
****************************************************************************/
/****************************************************************************
** HYSTORY VERSION
*****************************************************************************
** R1V1.0:
** >implemented generic macro
** >implemented port configuration macro
** >implemented UART module macro
** R2V1.1:
** >added NOP macro
** >added MASK macro
** >added TOGGLE_BIT macro
** >removed SET_2BIT macro (useless)
** >removed SET_PORT_VALUE macro (useless)
** >renamed SET_PORT macro to SET_VAR
** >renamed CLEAR_PORT macro to CLEAR_VAR
** >updated PORT_CONFIG macro
** >updated USART macro handling
** >added USART enviroment variablile to avoid those annoying warning
** >comment updated
** >code reformatted
** R3V1.2
** >Removed Shift Macro
** >Removed Clear and SEt variabile macros
** >Added conditional creation of PORT MACROS
** >Added Saturated Math MACROS
** >Added Fixed point MUL macros
** >Added 8 bit Fixed point mul macros
** >Added 8 bit fixed point rounded toward even mul macro
** >Added 16 bit Fixed point mul macros
** X>Added 16 bit fixed point rounded toward even mul macro
** R4V1.3
** >added circular buffer structure and handling macros
** >added circular buffer with semaphor, allow for safe buffer push and kick
** use in ISR and concurrent code
** >added 8 bit exact logarithm macros
** >added IS_NUMBR macro
****************************************************************************/
#ifndef AT_UTILS //gestisco inclusioni multiple
#define AT_UTILS //costante di libreria
/****************************************************************************
** ENVROIMENT VARIABILE
****************************************************************************/
/****************************************************************************
** USEFUL DEFINE
****************************************************************************/
#ifndef _At_bool
enum _At_bool
{
FALSE = 0,
TRUE = 1
};
typedef enum _At_bool At_bool;
#endif
///--------------------------------------------------------------------------
/// NULL POINTER
///--------------------------------------------------------------------------
#ifndef NULL
#define NULL (void *)0
#endif
///--------------------------------------------------------------------------
/// DATA TYPE RANGE
///--------------------------------------------------------------------------
typedef uint8_t U8;
typedef int8_t S8;
typedef uint16_t U16;
typedef int16_t S16;
typedef uint32_t U32;
typedef int32_t S32;
typedef uint64_t U64;
typedef int64_t S64;
#define MAX_U8 +255
#define MAX_U16 +65535
#define MIN_S8 -128
#define MAX_S8 +127
#define MIN_S16 -32768
#define MAX_S16 +32767
/****************************************************************************
** GENERAL PURPOSE MACRO
****************************************************************************/
//do nothing for one clock cycle
#define NOP() __asm__ __volatile__("nop")
//generate a mask whith '1' in position shift value
#define MASK( shift_value ) \
( 0x01 << (shift_value) )
//generate invrted mask '0' in position shiftvalue
#define INV_MASK( shift_value ) \
(~MASK(shift_value))
//set a single bit inside a variable leaving the other bit untouched
#define SET_BIT( var, shift_value ) \
( (var) |= MASK( shift_value ) )
//clear a single bit inside a variable leaving the other bit untouched
#define CLEAR_BIT( var, shift_value ) \
( (var) &= (INV_MASK( shift_value ) ) )
//toggle a single bit inside a variable leaving the other bit untouched
#define TOGGLE_BIT( var, shift_value ) \
( (var) ^= MASK( shift_value ) )
//TRUE if a bit in position shift value is '1'
#define IS_BIT_ONE( var, shift_value ) \
( ( (var) & MASK( shift_value ) ) == MASK( shift_value ) )
//TRUE if a bit in position shift value is '0'
#define IS_BIT_ZERO( var, shift_value ) \
( ( (var) & MASK( shift_value ) ) == 0x00 )
//Get bit [shift_value] and put it on position 0
#define GET_BIT( var, shift_value ) \
((var & MASK( shift_value )) >> shift_value)
//Extract H part of U16
#define U16H( data ) \
(U8)((U16)data >> 8)
//Extract L part of U16
#define U16L( data ) \
(U8)((U16)data & (U16)0x00ff)
//Extract the h part of a s16 data
#define S16H( x ) \
(S8)((U16)((x)>>8))
//Extract L part of S16. The result is an unsigned number
#define S16L( x ) \
(U8)((U16)(x) & (U16)0x00ff)
#define IS_SIGN( x ) \
(((x) == '+') || ((x) == '-'))
//x is a number?
#define IS_NUMBER( x ) \
(((x) >= '0') && ((x) <= '9'))
#define IS_LOWCASE_LETTER( x ) \
(((x) >= 'a') && ((x) <= 'z'))
#define IS_HIGHCASE_LETTER( x ) \
(((x) >= 'A') && ((x) <= 'Z'))
#define IS_LETTER( x ) \
(IS_LOWCASE_LETTER( x ) || IS_HIGHCASE_LETTER( x ))
/****************************************************************************
** SHIFT MACROS
*****************************************************************************
** All flavour of shift and rotation, signed and unsigned,
** with residual and runding and sign extension
****************************************************************************/
///--------------------------------------------------------------------------------
/// SHL - SHift Left, Multiply by 2^n
///--------------------------------------------------------------------------------
// example
// in: 7 6 5 4 3 2 1 0 shift: <<3
// shl: 4 3 2 1 0 / / / shift
// res: / / / / / 7 6 5 residual of the shift
//SHift Left
#define SHL( x, s ) \
((x) << (s))
//RESidual from a SHift Left. Needs to know the width of the input
#define SHL_RES( x, s, w ) \
(SHR(x,(w-s)))
///--------------------------------------------------------------------------------
/// SHR - SHift Right, Divide by 2^n
///--------------------------------------------------------------------------------
// example
// in: 7 6 5 4 3 2 1 0 shift: >>3
// shr: / / / 7 6 5 4 3
// res: / / / / / 2 1 0 residual of the shift
//SHift Right
#define SHR( x, s ) \
((x) >> (s))
//Residual from a Right SHift
#define SHR_RES( x, s ) \
((x) & (MASK(s)-1))
//Signed Right SHift
#define SSHR8( x, s ) \
((IS_BIT_ONE(x,7))?(SHR(x,s)|(SHL((U8)0xff,(8-s)))):(SHR(x,s)))
//Signed Right SHift
#define SSHR16( x, s ) \
((IS_BIT_ONE(x,15))?(SHR(x,s)|(SHL((U16)0xffff,(16-s)))):(SHR(x,s)))
//Signed Right SHift
#define SSHR32( x, s ) \
((IS_BIT_ONE(x,31))?(SHR(x,s)|(SHL((U32)0xffffffff,(32-s)))):(SHR(x,s)))
//signed right shift with RTO rounding
#define SHR_RTO(x, s) \
(((s >= 1)&&(IS_BIT_ONE(x,s-1)))?((((s>=2)&&(SHR_RES( x, s-1 ))>0))?(SHR(x,s)+1):(SHR(x,s)|1)):(SHR(x,s)))
//signd right shift with rounding
#define SSHR8_RTO(x,s) \
(((s >= 1)&&(IS_BIT_ONE(x,s-1)))?((((s>=2)&&(SHR_RES( x, s-1 ))>0))?(SSHR8(x,s)+1):(SSHR8(x,s)|1)):(SSHR8(x,s)))
#define SSHR16_RTO(x,s) \
(((s >= 1)&&(IS_BIT_ONE(x,s-1)))?((((s>=2)&&(SHR_RES( x, s-1 ))>0))?(SSHR16(x,s)+1):(SSHR16(x,s)|1)):(SSHR16(x,s)))
#define SSHR32_RTO(x,s) \
(((s >= 1)&&(IS_BIT_ONE(x,s-1)))?((((s>=2)&&(SHR_RES( x, s-1 ))>0))?(SSHR32(x,s)+1):(SSHR32(x,s)|1)):(SSHR32(x,s)))
///--------------------------------------------------------------------------------
/// ROR - Right ROtation
///--------------------------------------------------------------------------------
// example
// in: 7 6 5 4 3 2 1 0 shift: >>3
// ror: 2 1 0 7 6 5 4 3
#define ROR( x, s, w ) \
( (SHR(x,s)) | (SHL(x, (w-s))) )
#define ROR8( x, s ) \
ROR( x, s, 8 )
#define ROR16( x, s ) \
ROR( x, s, 16 )
#define ROR32( x, s ) \
ROR( x, s, 32 )
///--------------------------------------------------------------------------------
/// ROL - Left ROtation
///--------------------------------------------------------------------------------
// example
// in: 7 6 5 4 3 2 1 0 shift: >>3
// ror: 4 3 2 1 0 7 6 5
#define ROL( x, s, w ) \
( (SHR(x,s)) | (SHL(x, (w-s))) )
///********************************************************************************
/// DEBUG MACROS
///********************************************************************************
//powerful macros that add debug functionality (require printf)
//If txt logger is active
#ifdef DEBUG_FILE
#include <stdio.h>
extern FILE *fdebug;
extern U8 min_dlevel, dindent, show_dlevel[];
#endif
#ifdef DEBUG_PRINTF
//maximum numver of nested functions
#define MAX_DINDENT 32
#define DPRINTF_VARS_PROTOTYPES() \
extern U8 min_dlevel, dindent, show_dlevel[]
#define DPRINTF_VARS() \
U8 min_dlevel = 0, show_dlevel[MAX_DINDENT], dindent = 0
#define DSTART( dlevel ) \
min_dlevel = dlevel, show_dlevel[0]=254 , printf("Start Debug!\n")
#define DSTOP() \
printf("Debug has Ended!\n")
//enter and increase indent
#define DENTER( dlevel, ... ) \
(dindent<MAX_DINDENT)?(++dindent):(0), show_dlevel[dindent] = dlevel, DTAB(dindent -1), DPRINTF_NOTAB( "Enter: " ), DPRINTF_NOTAB( __VA_ARGS__ )
//show_dlevel = dlevel, DPRINTF(254, "ENTER: "), DPRINTF(254, __VA_ARGS__ ), dindent++
#define DEXIT( ... ) \
DTAB(dindent -1), DPRINTF_NOTAB("Exit: "), DPRINTF_NOTAB( __VA_ARGS__ ),(dindent>0)?(dindent--):(0)
#define SET_SHOW_DLEVEL( dlevel ) \
show_dlevel = dlevel
#define DTAB(n) \
(((show_dlevel[dindent] >= min_dlevel))?printf("%.*s", n, "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"):(0))
#define DPRINTF_NOTAB( ... ) \
(((show_dlevel[dindent] >= min_dlevel))?printf( __VA_ARGS__ ):(0))
#define DPRINTF( ... ) \
(((show_dlevel[dindent] >= min_dlevel))?DTAB(dindent),printf( __VA_ARGS__ ):(0))
#warning "debug printf active"
#else
#ifdef DEBUG_FILE
#define _DEBUG_MAX_INDENT_LEVEL 12
///----------------------------------------------------------------
/// GLOBAL VARIABLES
///----------------------------------------------------------------
//Variable prototypes for debug
#define DEBUG_VARS_PROTOTYPES() \
extern FILE *_debug_file; \
extern int _debug_indent_level, _debug_show_level
//Global variables for debug
#define DEBUG_VARS() \
FILE *_debug_file = NULL; \
int _debug_indent_level = 0, _debug_show_level = 0
//Change the show level
#define DSHOW( level ) \
_debug_show_level = (level)
///----------------------------------------------------------------
/// DEBUG FILE MACROS
///----------------------------------------------------------------
//Open file and start debugging
#define DSTART( user__debug_show_level ) \
_debug_file = fopen( "debug.log", "w+"), _debug_indent_level = 0, _debug_show_level = user__debug_show_level , fprintf(_debug_file, "Start Debug!\n")
//Stop debugging and close file
#define DSTOP() \
((_debug_file != NULL)?fprintf(_debug_file, "\nDebug has Ended!\n"), fflush(_debug_file), fclose(_debug_file), _debug_file = NULL:(0))
///----------------------------------------------------------------
/// DEBUG PRINT MACROS
///----------------------------------------------------------------
//Print a given number of tab characters
#define DTAB(n) \
(((_debug_file != NULL) && (_debug_indent_level >= _debug_show_level))?(fprintf(_debug_file,"%.*s", n, "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")):(0));
//Print a number of tab equal to indent level than print user defined string
#define DPRINT( ... ) \
(((_debug_file != NULL) && (_debug_indent_level >= _debug_show_level))?(fprintf(_debug_file,"%.*s", _debug_indent_level, "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"), fprintf(_debug_file, __VA_ARGS__ )):(0))
//print user defined string
#define DPRINT_NOTAB( ... ) \
(((_debug_file != NULL) && (_debug_indent_level >= _debug_show_level))?(fprintf(_debug_file, __VA_ARGS__ )):(0))
///----------------------------------------------------------------
/// FUNCTION TRACE MACROS
///----------------------------------------------------------------
//Enter Function and increase indent level. No argument print version
#define DENTER() \
DPRINT( "-->> \"%s\" |\n", __FUNCTION__), (_debug_indent_level<_DEBUG_MAX_INDENT_LEVEL)?(++_debug_indent_level):(_DEBUG_MAX_INDENT_LEVEL)
//Return from function and decrease indent level. No argument version
#define DRETURN() \
(_debug_indent_level>0)?(--_debug_indent_level):(0), DPRINT( "<<-- \"%s\" |\n", __FUNCTION__)
//Enter Function and increase indent level. No argument print version
#define DENTER_ARG( ... ) \
DPRINT( "-->> \"%s\" | ", __FUNCTION__), DPRINT_NOTAB( __VA_ARGS__ ), (_debug_indent_level<_DEBUG_MAX_INDENT_LEVEL)?(++_debug_indent_level):(_DEBUG_MAX_INDENT_LEVEL)
//Return from function and decrease indent level. No argument version
#define DRETURN_ARG( ... ) \
(_debug_indent_level>0)?(--_debug_indent_level):(0), DPRINT( "<<-- \"%s\" | ", __FUNCTION__), DPRINT_NOTAB( __VA_ARGS__ )
#warning "debug file active"
#else
#define DEBUG_VARS_PROTOTYPES()
#define DEBUG_VARS()
#define DSHOW( ... )
#define DSTART( ... )
#define DSTOP()
#define DTAB( ... )
#define DPRINT( ... )
#define DPRINT_NOTAB( ... )
#define DENTER( ... )
#define DRETURN( ... )
#define DENTER_ARG( ... )
#define DRETURN_ARG( ... )
#endif
#endif
/****************************************************************************
** CIRCULAR BUFFER MACROS
*****************************************************************************
** Very useful set of macros to handle circular buffers
** i use them all the time, making it in macro form is very efficient
** Actually, the macro are very generic, i can easily make many types of buffer
** probably void * ones too
****************************************************************************/
///--------------------------------------------------------------------------
/// BUFFER STRUCTURE PROTOTYPE
///--------------------------------------------------------------------------
// the data type can be anything as long as the field name stay the same
//Status byte of an At buf structure
typedef struct _At_buf_status At_buf_status;
//Circular buffer structure (maximum size 255 element)
typedef struct _At_buf8 At_buf8;
//Circular buffer structure with semaphore (maximum size 255 element)
typedef struct _At_buf8_safe At_buf8_safe;
///--------------------------------------------------------------------------
/// BUFFER STRUCTURE DEFINITIONS
///--------------------------------------------------------------------------
// the data type can be anything as long as the field name stay the same
//Status byte of an At buf structure
struct _At_buf_status
{
uint8_t push_flag : 1; //Is someone pushing into this buffer?
uint8_t kick_flag : 1; //Is someone kicking from this buffer?
uint8_t : 6; //Future use
};
//Circular buffer structure (maximum size 255 element)
struct _At_buf8
{
//size of the buffer
uint8_t size;
//pointer to the top element
uint8_t bot;
//pointer to the bot element
uint8_t top;
//Pointer to the content (can be anything)
uint8_t *ptr;
};
//Circular buffer structure with semaphore, handle exception caused by ISR
struct _At_buf8_safe
{
//size of the buffer
uint8_t size;
//pointer to the top element
uint8_t bot;
//pointer to the bot element
uint8_t top;
//Pointer to the content (can be anything)
uint8_t *ptr;
//Status of the
At_buf_status status;
};
///--------------------------------------------------------------------------
/// AT_BUF_ATTACH
///--------------------------------------------------------------------------
/// Attach an existing vector to an existing At_buf structure
#define AT_BUF_ATTACH( buf, ptr_in, size_in ) \
( ((buf).ptr = ptr_in), ((buf).size = size_in) )
///--------------------------------------------------------------------------
/// AT_BUF_FLUSH
///--------------------------------------------------------------------------
/// Flush a buffer, return 0
#define AT_BUF_FLUSH( buf ) \
( ((buf).top = 0), ((buf).bot = 0) )
///--------------------------------------------------------------------------
/// AT_BUF_FLUSH_SAFER
///--------------------------------------------------------------------------
/// Flush a buffer, clear status flags,return 0
/// Operate only on safe structure
#define AT_BUF_FLUSH_SAFE( buf ) \
( ((buf).top = 0), ((buf).bot = 0), (buf).status.push_flag = 0, (buf).status.kick_flag = 0, (0) )
///--------------------------------------------------------------------------
/// AT_BUF_EMPTY
///--------------------------------------------------------------------------
// Often user need to know only if empty or not empty.
#define AT_BUF_NOTEMPTY( buf ) \
((buf).top != (buf).bot)
#define AT_BUF_EMPTY( buf ) \
((buf).top == (buf).bot)
///--------------------------------------------------------------------------
/// AT_BUF_NUMELEM
///--------------------------------------------------------------------------
/// Return the number of elements in a buffer
#define AT_BUF_NUMELEM( buf ) \
( ((buf).top >= (buf).bot) ? ((buf).top - (buf).bot) : ( (buf).size +(buf).top -(buf).bot ) )
///--------------------------------------------------------------------------
/// AT_BUF_SIZE
///--------------------------------------------------------------------------
/// Return the size of the buffer
#define AT_BUF_SIZE( buf ) \
( (buf).size )
///--------------------------------------------------------------------------
/// AT_BUF_PUSH
///--------------------------------------------------------------------------
/// Push a data into a buffer
/// Load data
/// If: top < size
/// top++
/// Else:
/// top = 0
/// RETURN 0
#define AT_BUF_PUSH( buf, data ) \
( ( (buf).ptr[ (buf).top ] = data ), ( ( (buf).top < ((buf).size -1) ) ? ((buf).top++) : ((buf).top = 0) ) )
///--------------------------------------------------------------------------
/// AT_BUF_PUSH_SAFE
///--------------------------------------------------------------------------
/// Push a data into a buffer, checking that the buffer won't overflow,
/// return 1 if th data could not be pushed
/// If: current element < size
/// AT_BUF_PUSH
/// RETURN 0
/// Else:
/// RETURN 1
#define AT_BUF_PUSH_SAFE( buf, data ) \
( (AT_BUF_NUMELEM(buf) < ((buf).size-1)) ? (AT_BUF_PUSH(buf,data)) : (1) )
///--------------------------------------------------------------------------
/// AT_BUF_PUSH_SAFEER
///--------------------------------------------------------------------------
/// Operate on safe structure, return 1 if buf is full, return 2 if buf is busy
/// because of other operations
/// If: busy pushing?
/// return 2
/// Else:
/// busy = 1
/// ret = AT_BUF_PUSH_SAFE
/// busy = 0
/// return ret
#define AT_BUF_PUSH_SAFER( buf, data ) \
( ((buf).status.push_flag == 1) ? (2) : ( (((buf).status.push_flag = 1), (AT_BUF_NUMELEM(buf) < ((buf).size-1))) ? ((AT_BUF_PUSH(buf,data)), ((buf).status.push_flag = 0), (0)) : (((buf).status.push_flag = 0), (1)) ) )
///--------------------------------------------------------------------------
/// AT_BUF_PEEK
///--------------------------------------------------------------------------
/// Return the oldest element of the buffer, the user should check if there are
/// element in the buffer
#define AT_BUF_PEEK( buf ) \
( (buf).ptr[ (buf).bot ] )
///--------------------------------------------------------------------------
/// AT_BUF_KICK
///--------------------------------------------------------------------------
/// Kick out the oldest element of the buffer, the user should check that there is
/// at least 1 element in the buffer, return bot
/// If: bot < size
/// bot++
/// Else:
/// bot = 0
#define AT_BUF_KICK( buf ) \
( (((buf).bot < ((buf).size -1)) ? ((buf).bot++) : ((buf).bot = 0)))
///--------------------------------------------------------------------------
/// AT_BUF_KICK_SAFE
///--------------------------------------------------------------------------
/// kick the oldest element if there is at least one element in the buffer
/// return 1 if fail
/// If: num_elem > 0
/// AT_BUF_KICK
/// RETURN 0
/// Else
/// RETURN 1
#define AT_BUF_KICK_SAFE( buf ) \
(( AT_BUF_NUMELEM( buf ) > 0 ) ? (AT_BUF_KICK( buf )) : (1))
///--------------------------------------------------------------------------
/// AT_BUF_KICK_SAFER
///--------------------------------------------------------------------------
/// Kick the oldest element, if another kick operation is rnning, return 2 instead
/// Work only on safe structure
/// If: busy == 1
/// RETURN 2
/// Else:
/// busy = 1
/// ret = AT_BUF_KICK_SAFE
/// busy = 0
/// RETURN ret
#define AT_BUF_KICK_SAFER( buf ) \
( ((buf).status.kick_flag == 1) ? (2) : ( (((buf).status.kick_flag = 1), ( AT_BUF_NUMELEM( buf ) > 0 )) ? ((AT_BUF_KICK( buf )), ((buf).status.kick_flag = 0), (0)) : (((buf).status.kick_flag = 0), (1)) ) )
/****************************************************************************
** PRESCALER CALCULATION MACROS
****************************************************************************/
/*******************************************
** AT_OCR
********************************************
** Setup a counter to obtain a given fout
**
** fout [Hz] = output frequency
** fin [Hz] = input frequency
** N [1] = prescaler
** K [1] = 0 or 1, depend if use UP or UPDOWN mode
**
** fout = fin / (2^N * (M+1) * 2^K)
**
** M = fin / (fout * 2^(N+K)) -1
*******************************************/
#define AT_OCR( fin, fout, n, k) \
(( ((fin) / (fout)) >> ((n)+(k)) ) -1)
/*******************************************
** AT_OCR_ROUND
********************************************
** choose the correct M between M and M+1
** >M' = f(2*fout)
** >M' even?
** >M = f(fout)
** >else
** >M = f(fout) +1
*******************************************/
#define AT_OCR_ROUND( fin, fout, n, k) \
(( AT_OCR((fin),(fout)*2,(n),(k)) & 1 )?( 1 +AT_OCR((fin),(fout),(n),(k)) ):(AT_OCR((fin),(fout),(n),(k))))
///********************************************************************************
/// AT_ABS
///********************************************************************************
// negative/positive -> positive
//Absolute value
#define AT_ABS( x ) \
((x>=0)?(x):(-(x)))
/****************************************************************************
** FIXED POINT ARITH MACROS
*****************************************************************************
** Those macros handle operation with fixed point variabile
** The SUM macros are variabile type indipendent and handle saturation limit
** ex.
** 0111.0001 + // +7.0625
** 0001.1000 = // +1.5
** -----------
** 0111.1111 // +7.9375
**
** The MUL macros handle the renormalisation and the saturation
** The rounded toward even version of the macro has PROS and CONS:
** PROS:
** -1 Order of Magnitude reduction for the mean error
** CONS:
** -2 Sligth increase of the rms error
** -3 Increased computational cost (1 additionale heavy brench)
**
** ex.
** 0000.1000 * // +0.5
** 0000.1000 * // +0.5
** -----------
** 0000.0100 // +0.25
**
** ex. same number with different point position yeld to different result
** 00001.000 * // +1.0
** 00001.000 * // +1.0
** -----------
** 00001.000 // +1.0
****************************************************************************/
///--------------------------------------------------------------------------
/// SATURATION HANDLING
///--------------------------------------------------------------------------
/// Handle up and low bound of variabile
#define AT_SAT( x, up_bound, low_bound ) \
( ((x)>(up_bound))?(up_bound):(((x)<(low_bound))?(low_bound):(x)) )
///--------------------------------------------------------------------------
/// TWO WAY SATURATED SUM
///--------------------------------------------------------------------------
/// AT_FP_SAT_SUM( x, y, up_bound, low_bound )
/// x, y : Fixed Point Operand
/// up_bound, low_bound : Bound for the operation (can be lower than the variabile range)
//This macro handle the sum between two number handling the saturation
//Algorithm:
// (x > 0) && (y >= up_bound - x) ? //X > 0 and Y > positive overflow treshold
// Yes
// up_bound //Positive Overflow
// No
// (x < 0) && (y <= low_bound - x) ? //X < 0 and Y < negative overflow treshold
// Yes
// low_bound //Negative Overflow
// No
// x + y //No overflow
#define AT_SAT_SUM( x, y, up_bound, low_bound ) \
( ( (x) > 0 ) && ( (y) >= ((up_bound) - (x)) ) )? (up_bound) : ( ( ( (x) < 0 ) && ( (y) <= ((low_bound) - (x)) ) )? (low_bound) : ((x) + (y)) )
///--------------------------------------------------------------------------
/// THREE WAY SATURATED SUM
///--------------------------------------------------------------------------
/// AT_FP_SAT_SUM( x, y, z, up_bound, low_bound )
/// x, y, z : Fixed Point Operand
/// up_bound, low_bound : Bound for the operation (can be lower than the variabile range)
//This macro solve an issue when i have to sum three element in a saturated way
//The problem happen when the first partial result saturate (discarding something) and
//the next operation would subtract from the first one
//es
// a = 127, b = 60, c = -128: (expected result = 59)
// 127 + 60 = 127, 127 - 128 = -1 (wrong result = -1)
//Algorithm:
// (a + b == up_bound AND c < 0 ) OR (a + b == low_bound AND c > 0 )
// YES
// (a + c) + b
// NO
// (a + b) + c
#define AT_SAT_3SUM( x, y, z, up_bound, low_bound ) \
( ( (AT_SAT_SUM( (x), (y), (up_bound), (low_bound) ) == (up_bound)) && ((z) < 0) ) || ( (AT_SAT_SUM( (x), (y), (up_bound), (low_bound) ) == (low_bound)) && ((z) > 0) ) )?AT_SAT_SUM( AT_SAT_SUM( (x), (z), (up_bound), (low_bound) ), (y), (up_bound), (low_bound) ):AT_SAT_SUM( AT_SAT_SUM( (x), (y), (up_bound), (low_bound) ), (z), (up_bound), (low_bound) )
///********************************************************************************
/// AT_TOP_INC
///********************************************************************************
// Increment. If increment would exceed top -> reset
// Ex. top = 7
// cnt = 0, 1, 2, 3, 4, 5, 6, 7, 0, ...
#define AT_TOP_INC( cnt, top ) \
(((cnt) == (top))?(0):((cnt)+1))
///********************************************************************************
/// CIRCULAR SUM
///********************************************************************************
// This function allow sum to work like an 8bit var would start again from 0 once a sum overflow
// sometime this is useful
// TODO: I can handle the case when i go around max multiple times
#define AT_CIRCULAR_SUM( x, y, max ) \
( ((x +y) >= (max))?(x +y -max):(x +y) )
///--------------------------------------------------------------------------
/// DIVISION HANDLING
///--------------------------------------------------------------------------
/// This macro handle division by power of 2, no rounding at all
/// Algorithm:
/// out = x / (1<<fp)
#define AT_DIVIDE( x, fp ) \
( (x) / (1 << (fp) ) )
///--------------------------------------------------------------------------
/// DIVISION HANDLING (ROUND TOWARD NEGATIVE)
///--------------------------------------------------------------------------
/// This macro handle division by power of 2, no rounding at all
/// The 0.5 case is always rounded down
/// Algorithm:
/// >The first bit masked away is '1'?
/// Y:
/// out+1
/// N:
/// out
#define AT_DIVIDE_RTN( x, fp ) \
( ((x)&(MASK(fp-1)))?(((x)/MASK(fp))+1):((x)/MASK(fp)) )
///--------------------------------------------------------------------------
/// DIVISION HANDLING (ROUND TOWARD ODD)
///--------------------------------------------------------------------------
/// This macro handle division by power of 2, the result is renormalised and rounded
/// toward the nearest even number, allow for minimal error if the data have non 0 mean value
/// I round toward odd because is simpler to handle the rounding, i just have to OR the
/// result with '1'
///
/// Algorithm:
/// The first bit masked away is '1'?
/// Y:
/// The other masked bit are not exactly 0?
/// Y:
/// out+1
/// N:
/// out | 1
/// N:
/// out
#define AT_DIVIDE_RTO( x, fp ) \
( ((x)&(MASK(fp-1)))?(((x)&(MASK(fp-1)-1))?(((x)/MASK(fp))+1):(((x)/MASK(fp))|1)):((x)/MASK(fp)) )
///--------------------------------------------------------------------------
/// GENERAL PORPOUSE SATURATED FIXED POINT MUL
///--------------------------------------------------------------------------
/// This macro handle the multiplication and renormalization between two number
/// x, y : Fixed Point Operand
/// fp : Fixed point position
/// up_bound, low_bound : Bound for the operation (can be lower than the variabile range)
/// op_type : Type of the operand
/// mul_type : Type of the mul result (es. if the operand is int16, this is int32
/// mul mask : Mask the useless bit of the result it es for int16 operand is 32 bit 0x0000ffff
// x, y = Number
// fp = position of the point
// Algorithm:
// x * y >= up bound * (1 << fp)?
// Yes
// up bound
// No
// x * y <= low bound * (1 << fp)?
// Yes
// low_bound
// No
// x * y / (1 << fp)
#define AT_FP_SAT_MUL( x, y, fp, up_bound, low_bound, op_type, mul_type, mul_mask ) \
( ((mul_type)((x)*(y))>=(mul_type)((up_bound)*(1<<(fp))))?((op_type)(up_bound)):( ((mul_type)((x)*(y))<=(mul_type)((low_bound)*(1<<(fp))))?((op_type)(low_bound)):((op_type)((mul_type)(mul_mask)&(mul_type)((x)*(y)/(1<<(fp)))))) )
///--------------------------------------------------------------------------
/// SATURATED RENORMALISED FIXED POINT 8BIT MUL
///--------------------------------------------------------------------------
/// Wrapper for the 8 bit fixed point saturated multiplication
//Setting the parameter for the 8 bit mul macro
#define AT_FP_SAT_MUL8( x, y, fp ) \
AT_FP_SAT_MUL( x, y, fp, MAX_INT8, MIN_INT8, int8_t, int16_t, 0x00ff ) \
///--------------------------------------------------------------------------
/// SATURATED, RENORMALISED FIXED POINT 16BIT MUL
///--------------------------------------------------------------------------
/// Wrapper for the 16 bit fixed point saturated multiplication
//Setting the parameter for the 16 bit mul macro
#define AT_FP_SAT_MUL16( x, y, fp ) \
AT_FP_SAT_MUL( x, y, fp, MAX_S16, MIN_S16, int16_t, int32_t, 0x0000ffff ) \
//( ((int32_t)((x)*(y))>=(int32_t)(MAX_INT16*(1<<(fp))))?((int16_t)MAX_INT16):( ((int32_t)((x)*(y))<=(int32_t)(MIN_INT16*(1<<(fp))))?((int16_t)MIN_INT16):((int16_t)((int32_t)0x0000ffff&(int32_t)((x)*(y)/(1<<(fp)))))) )
///--------------------------------------------------------------------------
/// SATURATED, ROUNDED TOWARD EVEN, RENORMALISED FIXED POINT 8BIT MUL
///--------------------------------------------------------------------------
/// This macros handle the multiplication and renormalization and the rounding toward even
/// es.
/// 3.0 * 0.6 = 1.8 -> = 2.0 //resto > 0.5 => arrotondato per eccesso
/// 3.0 * 0.5 = 1.5 -> = 2.0 //resto = 0.5 => arrotondato al pari piu' vicino
/// 5.0 * 0.5 = 2.5 -> = 2.0 //resto = 0.5 => arrotondato al pari piu' vicino
/// 3.0 * 0.4 = 1.2 -> = 1.0 //resto < 0.5 => arrotondato per difetto
/// x * y >= up bound * (1 << fp)? //Result Higher than the upper bound?
/// Yes
/// up bound //Return Up bound
/// No
/// x * y <= low bound * (1 << fp)? //Result lower than Low bound?
/// Yes
/// low_bound //Return Low Bound
/// No
/// //Result would be exactly x.5 and x is even OR result is lower than x.5
/// YES
/// //X
/// NO
/// //X +1
#define SAT_ROUND_MUL8( x, y, fp ) \
((int16_t)((x) * (y) / (1 << (fp))) >= (int16_t)MAX_INT8)?(int8_t)MAX_INT8:( ((int16_t)((x) * (y) / (1 << (fp))) <= (int16_t)MIN_INT8)?(int8_t)MIN_INT8:(((fp>0) && ((x*y)&(1<<(fp-1))))?(((x*y)>0)?((int8_t)( (int16_t)0x00ff & (int16_t)((x) * (y) / (1 << (fp))+1))):((int8_t)( (int16_t)0x00ff & (int16_t)((x) * (y) / (1 << (fp))-1)))):(int8_t)( (int16_t)0x00ff & (int16_t)((x) * (y) / (1 << (fp))))) )
///********************************************************************************
/// AT_MUL_ONE Multiply a number by a frection m/2^n Rounded Toward Odd
///********************************************************************************
/// This function execute a*m/2^n where m/2^n must be <1. It's a very common operation
/// I start by subtracting (a) with its remainder (a/2^n)*2^n
/// Then I multiply that by m, and divide by 2^n with the RTO function
/// Then I sum the unrounded division. If I do this part first, i would need 2a maximum (bad)
#define AT_MUL_ONE( a, m, n ) \
( AT_DIVIDE_RTO( ((a-((a/MASK(n))*MASK(n)))*m) , n ) +((a/MASK(n))*m) )
#define AT_MUL_NEG_ONE( a, m, n) \
((a<0)?(-AT_MUL_ONE( (-(a)), m, n )):AT_MUL_ONE( a, m, n ))
///********************************************************************************
/// RTE, RTO ROUND CONDITION
///********************************************************************************
// true if round UP
//Algorithm:
//r > d/2 //>0.5?
// y++ //round UP
//r == d/2 //==0.5?
// d odd //d was odd, it's actually >0.5
// y++ //round UP
// y odd //Spread rounding error. round to even
// y++ //round up
#define ROUND_RTE( y, r, d ) \
((r>(d/2))?(1):((r==(d/2))?(IS_BIT_ONE(d,0))?(1):((IS_BIT_ONE(y,0))?(1):(0)):(0)))
#define ROUND_RTO( y, r, d ) \
((r > d/2)?(1):((r == d/2)?((IS_BIT_ONE(d,0))?(1):((IS_BIT_ZERO(y,0))?(1):(0))):(0)))
/****************************************************************************
** OVERFLOW CONDITIONS
****************************************************************************/
//will an unsigned sum overflow?
#define WILL_U_OVF( a, b , top ) \
(a > (top -b))
//will a signed sum overflow?
//can be used for all cases U+S, S+S, S+U and ->S, -> U. just cast everything and use appropriate bounds
#define WILL_S_OVF( a, b, bot, top ) \
((b>=0)?(WILL_U_OVF(a,b,top)):(a < (bot-b)))
///********************************************************************************
/// LOGARITHM
///********************************************************************************
// Basically count the weight+1 of the MSB '1'
// Implemented with a binary bisection tree. 4 r 3 comparisons needed for result.
// the case x=0,x=1 ar the only that needs 4. because 0 is a special case
//4bit logarithm [0, 15] -> [0, 4]
// x | 0 1 2 3 4 ... 7 8 ... 15
// log2 | 0 1 2 2 3 ... 3 4 ... 4
#define AT_LOG24( x ) \
((x<4)?((x<2)?((x<1)?(0):(1)):(2)):((x<(8))?(3):(4)))
//8bit logarithm [0, 255] -> [0, 8]
// x | 0 1 2 3 4 .. 7 8 .. 15 16 .. 31 32 .. 63 64 .. 127 128 .. 255
// log2 | 0 1 2 2 3 .. 3 4 .. 4 5 .. 5 6 .. 6 7 .. 7 8 .. 8
#define AT_LOG28( x ) \
((x<16)?(AT_LOG24(x)):((x<64)?(((x<32)?(5):(6))):(((x<128)?(7):(8)))))
#define AT_LOG216( x ) \
((x<256)?(AT_LOG28(x)):(8+AT_LOG28(((x)>>8))))
#define AT_LOG2S16( x ) \
((x>=0)?(AT_LOG216(x)):(-AT_LOG216((-x))))
#else
#warning "multiple inclusion of at_utils.h"
#endif