@@ -71,3 +71,170 @@ int ringbuf_put16(ringbuf_t *r, uint16_t v) {
71
71
r -> iput = iput_b ;
72
72
return 0 ;
73
73
}
74
+
75
+ #if MICROPY_PY_MICROPYTHON_RINGBUFFER
76
+
77
+ #include "py/runtime.h"
78
+ #include "py/stream.h"
79
+ #include "py/mphal.h"
80
+
81
+ typedef struct _micropython_ringbuffer_obj_t {
82
+ mp_obj_base_t base ;
83
+ ringbuf_t ringbuffer ;
84
+ uint16_t timeout ; // timeout waiting for first char (in ms)
85
+ } micropython_ringbuffer_obj_t ;
86
+
87
+ STATIC mp_obj_t micropython_ringbuffer_make_new (const mp_obj_type_t * type , size_t n_args , size_t n_kw , const mp_obj_t * args ) {
88
+ mp_arg_check_num (n_args , n_kw , 1 , 2 , false);
89
+ mp_int_t buff_size = -1 ;
90
+ mp_buffer_info_t bufinfo = {NULL , 0 , 0 };
91
+
92
+ if (!mp_get_buffer (args [0 ], & bufinfo , MP_BUFFER_RW )) {
93
+ buff_size = mp_obj_get_int (args [0 ]);
94
+ }
95
+ micropython_ringbuffer_obj_t * self = mp_obj_malloc (micropython_ringbuffer_obj_t , type );
96
+ if (bufinfo .buf != NULL ) {
97
+ // buffer passed in, use it directly for ringbuffer
98
+ self -> ringbuffer .buf = bufinfo .buf ;
99
+ self -> ringbuffer .size = bufinfo .len ;
100
+ self -> ringbuffer .iget = self -> ringbuffer .iput = 0 ;
101
+ } else {
102
+ // Allocation buffer, sdd one extra to buff_size as ringbuf consumes one byte for tracking.
103
+ ringbuf_alloc (& (self -> ringbuffer ), buff_size + 1 );
104
+ }
105
+
106
+ if (n_args > 1 ) {
107
+ self -> timeout = mp_obj_get_int (args [1 ]);
108
+ }
109
+ return MP_OBJ_FROM_PTR (self );
110
+ }
111
+
112
+ STATIC mp_obj_t micropython_ringbuffer_settimeout (mp_obj_t self_in , mp_obj_t timeout_in ) {
113
+ micropython_ringbuffer_obj_t * self = MP_OBJ_TO_PTR (self_in );
114
+ self -> timeout = mp_obj_get_int (timeout_in );
115
+ return mp_const_none ;
116
+ }
117
+ STATIC MP_DEFINE_CONST_FUN_OBJ_2 (micropython_ringbuffer_settimeout_obj , micropython_ringbuffer_settimeout );
118
+
119
+
120
+ STATIC mp_uint_t micropython_ringbuffer_read (mp_obj_t self_in , void * buf_in , mp_uint_t size , int * errcode ) {
121
+ micropython_ringbuffer_obj_t * self = MP_OBJ_TO_PTR (self_in );
122
+ uint32_t t = mp_hal_ticks_ms () + self -> timeout ;
123
+ uint8_t * dest = buf_in ;
124
+
125
+ for (size_t i = 0 ; i < size ; i ++ ) {
126
+ // Wait for the first/next character.
127
+ while (ringbuf_avail (& self -> ringbuffer ) == 0 ) {
128
+ if (mp_hal_ticks_ms () > t ) { // timed out
129
+ if (i <= 0 ) {
130
+ * errcode = MP_EAGAIN ;
131
+ return MP_STREAM_ERROR ;
132
+ } else {
133
+ return i ;
134
+ }
135
+ }
136
+ MICROPY_EVENT_POLL_HOOK
137
+ }
138
+ * dest ++ = ringbuf_get (& (self -> ringbuffer ));
139
+ t = mp_hal_ticks_ms () + self -> timeout ;
140
+ }
141
+ return size ;
142
+ }
143
+
144
+ STATIC mp_uint_t micropython_ringbuffer_write (mp_obj_t self_in , const void * buf_in , mp_uint_t size , int * errcode ) {
145
+ micropython_ringbuffer_obj_t * self = MP_OBJ_TO_PTR (self_in );
146
+ uint32_t t = mp_hal_ticks_ms () + self -> timeout ;
147
+ const uint8_t * src = buf_in ;
148
+ size_t i = 0 ;
149
+
150
+ // Put as many bytes as possible into the transmit buffer.
151
+ while (i < size && ringbuf_free (& (self -> ringbuffer )) > 0 ) {
152
+ ringbuf_put (& (self -> ringbuffer ), * src ++ );
153
+ ++ i ;
154
+ }
155
+ // If ringbuf full, block until drained elsewhere (eg. irq) or timeout.
156
+ while (i < size ) {
157
+ while (ringbuf_free (& (self -> ringbuffer )) == 0 ) {
158
+ if (mp_hal_ticks_ms () > t ) { // timed out
159
+ if (i <= 0 ) {
160
+ * errcode = MP_EAGAIN ;
161
+ return MP_STREAM_ERROR ;
162
+ } else {
163
+ return i ;
164
+ }
165
+ }
166
+ MICROPY_EVENT_POLL_HOOK
167
+ }
168
+ ringbuf_put (& (self -> ringbuffer ), * src ++ );
169
+ ++ i ;
170
+ t = mp_hal_ticks_ms () + self -> timeout ;
171
+ }
172
+ // Just in case the fifo was drained during refill of the ringbuf.
173
+ return size ;
174
+ }
175
+
176
+ STATIC mp_uint_t micropython_ringbuffer_ioctl (mp_obj_t self_in , mp_uint_t request , uintptr_t arg , int * errcode ) {
177
+ micropython_ringbuffer_obj_t * self = MP_OBJ_TO_PTR (self_in );
178
+ mp_uint_t ret ;
179
+ if (request == MP_STREAM_POLL ) {
180
+ ret = 0 ;
181
+ if ((arg & MP_STREAM_POLL_RD ) && ringbuf_avail (& self -> ringbuffer ) > 0 ) {
182
+ ret |= MP_STREAM_POLL_RD ;
183
+ }
184
+ if ((arg & MP_STREAM_POLL_WR ) && ringbuf_free (& self -> ringbuffer ) > 0 ) {
185
+ ret |= MP_STREAM_POLL_WR ;
186
+ }
187
+ } else if (request == MP_STREAM_FLUSH ) {
188
+ // Should we wait here until empty / timeout?
189
+ ret = 0 ;
190
+ } else if (request == MP_STREAM_CLOSE ) {
191
+ // We don't want to reset head/tail pointers as there might
192
+ // still be someone using it, eg. if ringbuffer is used instead of
193
+ // a socket, a "writer" might call close before the "reader" is
194
+ // finished.
195
+ // Should we flush here though?
196
+ ret = 0 ;
197
+ } else {
198
+ * errcode = MP_EINVAL ;
199
+ ret = MP_STREAM_ERROR ;
200
+ }
201
+ return ret ;
202
+ }
203
+
204
+ STATIC mp_obj_t micropython_ringbuffer_any (mp_obj_t self_in ) {
205
+ micropython_ringbuffer_obj_t * self = MP_OBJ_TO_PTR (self_in );
206
+ return MP_OBJ_NEW_SMALL_INT (ringbuf_avail (& self -> ringbuffer ));
207
+ }
208
+ STATIC MP_DEFINE_CONST_FUN_OBJ_1 (micropython_ringbuffer_any_obj , micropython_ringbuffer_any );
209
+
210
+
211
+ STATIC const mp_rom_map_elem_t micropython_ringbuffer_locals_dict_table [] = {
212
+ { MP_ROM_QSTR (MP_QSTR_any ), MP_ROM_PTR (& micropython_ringbuffer_any_obj ) },
213
+ { MP_ROM_QSTR (MP_QSTR_settimeout ), MP_ROM_PTR (& micropython_ringbuffer_settimeout_obj ) },
214
+ { MP_ROM_QSTR (MP_QSTR_flush ), MP_ROM_PTR (& mp_stream_flush_obj ) },
215
+ { MP_ROM_QSTR (MP_QSTR_read ), MP_ROM_PTR (& mp_stream_read_obj ) },
216
+ { MP_ROM_QSTR (MP_QSTR_readline ), MP_ROM_PTR (& mp_stream_unbuffered_readline_obj ) },
217
+ { MP_ROM_QSTR (MP_QSTR_readinto ), MP_ROM_PTR (& mp_stream_readinto_obj ) },
218
+ { MP_ROM_QSTR (MP_QSTR_write ), MP_ROM_PTR (& mp_stream_write_obj ) },
219
+ { MP_ROM_QSTR (MP_QSTR_close ), MP_ROM_PTR (& mp_stream_close_obj ) },
220
+
221
+ };
222
+ STATIC MP_DEFINE_CONST_DICT (micropython_ringbuffer_locals_dict , micropython_ringbuffer_locals_dict_table );
223
+
224
+ STATIC const mp_stream_p_t ringbuffer_stream_p = {
225
+ .read = micropython_ringbuffer_read ,
226
+ .write = micropython_ringbuffer_write ,
227
+ .ioctl = micropython_ringbuffer_ioctl ,
228
+ .is_text = false,
229
+ };
230
+
231
+ MP_DEFINE_CONST_OBJ_TYPE (
232
+ mp_type_micropython_ringbuffer ,
233
+ MP_QSTR_ringbuffer ,
234
+ MP_TYPE_FLAG_NONE ,
235
+ make_new , micropython_ringbuffer_make_new ,
236
+ protocol , & ringbuffer_stream_p ,
237
+ locals_dict , & micropython_ringbuffer_locals_dict
238
+ );
239
+
240
+ #endif
0 commit comments