[sx/simavr.git] /
1 /*
2 fido_declare.h
3 Copyright (C) 2003-2012 Michel Pollet <buserror@gmail.com>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 /*
21 * FIFO helpers, aka circular buffers
22 *
23 * these macros define accessories for FIFOs of any name, type and
24 * any (power of two) size
25 */
26
27 #ifndef __FIFO_DECLARE__
28 #define __FIFO_DECLARE__
29
30 #ifdef __cplusplus
31 extern "C" {
32 #endif
33
34 /*
35 doing a :
36 DECLARE_FIFO(uint8_t, myfifo, 128);
37
38 will declare :
39 enum : myfifo_overflow_f
40 type : myfifo_t
41 functions:
42 // write a byte into the fifo, return 1 if there was room, 0 if there wasn't
43 int myfifo_write(myfifo_t *c, uint8_t b);
44 // reads a byte from the fifo, return 0 if empty. Use myfifo_isempty() to check beforehand
45 uint8_t myfifo_read(myfifo_t *c);
46 int myfifo_isfull(myfifo_t *c);
47 int myfifo_isempty(myfifo_t *c);
48 // returns number of items to read now
49 uint16_t myfifo_get_read_size(myfifo_t *c);
50 // read item at offset o from read cursor, no cursor advance
51 uint8_t myfifo_read_at(myfifo_t *c, uint16_t o);
52 // write b at offset o compared to current write cursor, no cursor advance
53 void myfifo_write_at(myfifo_t *c, uint16_t o, uint8_t b);
54
55 In your .c you need to 'implement' the fifo:
56 DEFINE_FIFO(uint8_t, myfifo)
57
58 To use the fifo, you must declare at least one :
59 myfifo_t fifo = FIFO_NULL;
60
61 while (!myfifo_isfull(&fifo))
62 myfifo_write(&fifo, 0xaa);
63 ....
64 while (!myfifo_isempty(&fifo))
65 b = myfifo_read(&fifo);
66 */
67
68 #include <stdint.h>
69
70 #if __AVR__
71 #define FIFO_CURSOR_TYPE uint8_t
72 #define FIFO_BOOL_TYPE char
73 #define FIFO_INLINE
74 #define FIFO_SYNC
75 #endif
76
77 #ifndef FIFO_CURSOR_TYPE
78 #define FIFO_CURSOR_TYPE uint16_t
79 #endif
80 #ifndef FIFO_BOOL_TYPE
81 #define FIFO_BOOL_TYPE int
82 #endif
83 #ifndef FIFO_INLINE
84 #define FIFO_INLINE inline
85 #endif
86
87 /* We should not need volatile */
88 #ifndef FIFO_VOLATILE
89 #define FIFO_VOLATILE
90 #endif
91 #ifndef FIFO_SYNC
92 #define FIFO_SYNC __sync_synchronize()
93 #endif
94
95 #ifndef FIFO_ZERO_INIT
96 #define FIFO_ZERO_INIT {0}
97 #endif
98 #define FIFO_NULL { FIFO_ZERO_INIT, 0, 0, 0 }
99
100 /* New compilers don't like unused static functions. However,
101 * we do like 'static inlines' for these small accessors,
102 * so we mark them as 'unused'. It stops it complaining */
103 #ifdef __GNUC__
104 #define FIFO_DECL static __attribute__ ((unused))
105 #else
106 #define FIFO_DECL static
107 #endif
108
109 #define DECLARE_FIFO(__type, __name, __size) \
110 enum { __name##_overflow_f = (1 << 0) }; \
111 enum { __name##_fifo_size = (__size) }; \
112 typedef struct __name##_t { \
113 __type buffer[__name##_fifo_size]; \
114 FIFO_VOLATILE FIFO_CURSOR_TYPE read; \
115 FIFO_VOLATILE FIFO_CURSOR_TYPE write; \
116 FIFO_VOLATILE uint8_t flags; \
117 } __name##_t
118
119 #define DEFINE_FIFO(__type, __name) \
120 FIFO_DECL FIFO_INLINE FIFO_BOOL_TYPE __name##_write(__name##_t * c, __type b)\
121 {\
122 FIFO_CURSOR_TYPE now = c->write;\
123 FIFO_CURSOR_TYPE next = (now + 1) & (__name##_fifo_size-1);\
124 if (c->read != next) { \
125 c->buffer[now] = b;\
126 FIFO_SYNC; \
127 c->write = next;\
128 return 1;\
129 }\
130 return 0;\
131 }\
132 FIFO_DECL FIFO_INLINE FIFO_BOOL_TYPE __name##_isfull(__name##_t *c)\
133 {\
134 FIFO_CURSOR_TYPE next = (c->write + 1) & (__name##_fifo_size-1);\
135 return c->read == next;\
136 }\
137 FIFO_DECL FIFO_INLINE FIFO_BOOL_TYPE __name##_isempty(__name##_t * c)\
138 {\
139 return c->read == c->write;\
140 }\
141 FIFO_DECL FIFO_INLINE __type __name##_read(__name##_t * c)\
142 {\
143 __type res = FIFO_ZERO_INIT; \
144 FIFO_CURSOR_TYPE read = c->read;\
145 if (read == c->write)\
146 return res;\
147 res = c->buffer[read];\
148 FIFO_SYNC; \
149 c->read = (read + 1) & (__name##_fifo_size-1);\
150 return res;\
151 }\
152 FIFO_DECL FIFO_INLINE FIFO_CURSOR_TYPE __name##_get_read_size(__name##_t *c)\
153 {\
154 return ((c->write + __name##_fifo_size) - c->read) & (__name##_fifo_size-1);\
155 }\
156 FIFO_DECL FIFO_INLINE FIFO_CURSOR_TYPE __name##_get_write_size(__name##_t *c)\
157 {\
158 return (__name##_fifo_size-1) - __name##_get_read_size(c);\
159 }\
160 FIFO_DECL FIFO_INLINE void __name##_read_offset(__name##_t *c, FIFO_CURSOR_TYPE o)\
161 {\
162 FIFO_SYNC; \
163 c->read = (c->read + o) & (__name##_fifo_size-1);\
164 }\
165 FIFO_DECL FIFO_INLINE __type __name##_read_at(__name##_t *c, FIFO_CURSOR_TYPE o)\
166 {\
167 return c->buffer[(c->read + o) & (__name##_fifo_size-1)];\
168 }\
169 FIFO_DECL FIFO_INLINE void __name##_write_at(__name##_t *c, FIFO_CURSOR_TYPE o, __type b)\
170 {\
171 c->buffer[(c->write + o) & (__name##_fifo_size-1)] = b;\
172 }\
173 FIFO_DECL FIFO_INLINE void __name##_write_offset(__name##_t *c, FIFO_CURSOR_TYPE o)\
174 {\
175 FIFO_SYNC; \
176 c->write = (c->write + o) & (__name##_fifo_size-1);\
177 }\
178 FIFO_DECL FIFO_INLINE void __name##_reset(__name##_t *c)\
179 {\
180 FIFO_SYNC; \
181 c->read = c->write = c->flags = 0;\
182 }\
183 struct __name##_t
184
185 #ifdef __cplusplus
186 };
187 #endif
188
189 #endif