@@ -118,3 +118,175 @@ int ringbuf_put_bytes(ringbuf_t *r, const uint8_t *data, size_t data_len) {
118
118
r -> iput = iput_a ;
119
119
return 0 ;
120
120
}
121
+
122
+ #if MICROPY_PY_MICROPYTHON_RINGBUFFER
123
+
124
+ #include "py/runtime.h"
125
+ #include "py/stream.h"
126
+ #include "py/mphal.h"
127
+
128
+ typedef struct _micropython_ringbuffer_obj_t {
129
+ mp_obj_base_t base ;
130
+ ringbuf_t ringbuffer ;
131
+ mp_int_t timeout ; // timeout waiting for first char (in ms)
132
+ } micropython_ringbuffer_obj_t ;
133
+
134
+ 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 ) {
135
+ mp_arg_check_num (n_args , n_kw , 1 , 2 , false);
136
+ mp_int_t buff_size = -1 ;
137
+ mp_buffer_info_t bufinfo = {NULL , 0 , 0 };
138
+
139
+ if (!mp_get_buffer (args [0 ], & bufinfo , MP_BUFFER_RW )) {
140
+ buff_size = mp_obj_get_int (args [0 ]);
141
+ }
142
+ micropython_ringbuffer_obj_t * self = mp_obj_malloc (micropython_ringbuffer_obj_t , type );
143
+ if (bufinfo .buf != NULL ) {
144
+ // buffer passed in, use it directly for ringbuffer
145
+ self -> ringbuffer .buf = bufinfo .buf ;
146
+ self -> ringbuffer .size = bufinfo .len ;
147
+ self -> ringbuffer .iget = self -> ringbuffer .iput = 0 ;
148
+ } else {
149
+ // Allocation buffer, add one extra to buff_size as ringbuf consumes one byte for tracking.
150
+ ringbuf_alloc (& (self -> ringbuffer ), buff_size + 1 );
151
+ }
152
+
153
+ if (n_args > 1 ) {
154
+ self -> timeout = mp_obj_get_int (args [1 ]);
155
+ } else {
156
+ self -> timeout = -1 ;
157
+ }
158
+ return MP_OBJ_FROM_PTR (self );
159
+ }
160
+
161
+ static mp_obj_t micropython_ringbuffer_settimeout (mp_obj_t self_in , mp_obj_t timeout_in ) {
162
+ micropython_ringbuffer_obj_t * self = MP_OBJ_TO_PTR (self_in );
163
+ self -> timeout = mp_obj_get_int (timeout_in );
164
+ return mp_const_none ;
165
+ }
166
+ static MP_DEFINE_CONST_FUN_OBJ_2 (micropython_ringbuffer_settimeout_obj , micropython_ringbuffer_settimeout ) ;
167
+
168
+
169
+ static mp_uint_t micropython_ringbuffer_read (mp_obj_t self_in , void * buf_in , mp_uint_t size , int * errcode ) {
170
+ micropython_ringbuffer_obj_t * self = MP_OBJ_TO_PTR (self_in );
171
+ mp_uint_t start = mp_hal_ticks_ms ();
172
+
173
+ size = MIN (size , ((mp_uint_t )self -> ringbuffer .size - 1 )); // limit size to ringbuffer length
174
+
175
+ while (ringbuf_get_bytes (& self -> ringbuffer , buf_in , size ) == -1 ) {
176
+ if (self -> timeout > -1 && (mp_hal_ticks_ms () - start > (mp_uint_t )self -> timeout )) {
177
+ // timed out
178
+ if ((size = MIN (size , ringbuf_avail (& self -> ringbuffer ))) > 0 ) {
179
+ // return available data
180
+ ringbuf_get_bytes (& self -> ringbuffer , buf_in , size );
181
+ * errcode = 0 ;
182
+ return size ;
183
+ }
184
+ // no data available
185
+ * errcode = MP_EAGAIN ;
186
+ return MP_STREAM_ERROR ;
187
+ }
188
+ mp_event_handle_nowait ();
189
+ }
190
+ * errcode = 0 ;
191
+ return size ;
192
+ }
193
+
194
+ static mp_uint_t micropython_ringbuffer_write (mp_obj_t self_in , const void * buf_in , mp_uint_t size , int * errcode ) {
195
+ micropython_ringbuffer_obj_t * self = MP_OBJ_TO_PTR (self_in );
196
+ mp_uint_t start = mp_hal_ticks_ms ();
197
+
198
+ size = MIN (size , ((mp_uint_t )self -> ringbuffer .size - 1 )); // limit size to ringbuffer length
199
+
200
+ while (ringbuf_put_bytes (& self -> ringbuffer , buf_in , size ) == -1 ) {
201
+ if (self -> timeout > -1 && (mp_hal_ticks_ms () - start > (mp_uint_t )self -> timeout )) {
202
+ // timed out
203
+ if ((size = MIN (size , ringbuf_free (& self -> ringbuffer ))) > 0 ) {
204
+ // write whatever can fit
205
+ ringbuf_put_bytes (& self -> ringbuffer , buf_in , size );
206
+ * errcode = 0 ;
207
+ return size ;
208
+ }
209
+ // no space available
210
+ * errcode = MP_EAGAIN ;
211
+ return MP_STREAM_ERROR ;
212
+ }
213
+ mp_event_handle_nowait ();
214
+ }
215
+ * errcode = 0 ;
216
+ return size ;
217
+
218
+ }
219
+
220
+ static mp_uint_t micropython_ringbuffer_ioctl (mp_obj_t self_in , mp_uint_t request , uintptr_t arg , int * errcode ) {
221
+ micropython_ringbuffer_obj_t * self = MP_OBJ_TO_PTR (self_in );
222
+ mp_uint_t ret ;
223
+ if (request == MP_STREAM_POLL ) {
224
+ ret = 0 ;
225
+ if ((arg & MP_STREAM_POLL_RD ) && ringbuf_avail (& self -> ringbuffer ) > 0 ) {
226
+ ret |= MP_STREAM_POLL_RD ;
227
+ }
228
+ if ((arg & MP_STREAM_POLL_WR ) && ringbuf_free (& self -> ringbuffer ) > 0 ) {
229
+ ret |= MP_STREAM_POLL_WR ;
230
+ }
231
+ } else if (request == MP_STREAM_FLUSH ) {
232
+ // Should we wait here until empty / timeout?
233
+ ret = 0 ;
234
+ } else if (request == MP_STREAM_CLOSE ) {
235
+ // We don't want to reset head/tail pointers as there might
236
+ // still be someone using it, eg. if ringbuffer is used instead of
237
+ // a socket, a "writer" might call close before the "reader" is
238
+ // finished.
239
+ // Should we flush here though?
240
+ ret = 0 ;
241
+ } else {
242
+ * errcode = MP_EINVAL ;
243
+ ret = MP_STREAM_ERROR ;
244
+ }
245
+ return ret ;
246
+ }
247
+
248
+ static mp_obj_t micropython_ringbuffer_any (mp_obj_t self_in ) {
249
+ micropython_ringbuffer_obj_t * self = MP_OBJ_TO_PTR (self_in );
250
+ return MP_OBJ_NEW_SMALL_INT (ringbuf_avail (& self -> ringbuffer ));
251
+ }
252
+ static MP_DEFINE_CONST_FUN_OBJ_1 (micropython_ringbuffer_any_obj , micropython_ringbuffer_any ) ;
253
+
254
+ static mp_obj_t micropython_ringbuffer_reset (mp_obj_t self_in ) {
255
+ micropython_ringbuffer_obj_t * self = MP_OBJ_TO_PTR (self_in );
256
+ self -> ringbuffer .iget = self -> ringbuffer .iput = 0 ;
257
+ return mp_const_none ;
258
+ }
259
+ static MP_DEFINE_CONST_FUN_OBJ_1 (micropython_ringbuffer_reset_obj , micropython_ringbuffer_reset ) ;
260
+
261
+
262
+ static const mp_rom_map_elem_t micropython_ringbuffer_locals_dict_table [] = {
263
+ { MP_ROM_QSTR (MP_QSTR_any ), MP_ROM_PTR (& micropython_ringbuffer_any_obj ) },
264
+ { MP_ROM_QSTR (MP_QSTR_settimeout ), MP_ROM_PTR (& micropython_ringbuffer_settimeout_obj ) },
265
+ { MP_ROM_QSTR (MP_QSTR_reset ), MP_ROM_PTR (& micropython_ringbuffer_reset_obj ) },
266
+ { MP_ROM_QSTR (MP_QSTR_flush ), MP_ROM_PTR (& mp_stream_flush_obj ) },
267
+ { MP_ROM_QSTR (MP_QSTR_read ), MP_ROM_PTR (& mp_stream_read_obj ) },
268
+ { MP_ROM_QSTR (MP_QSTR_readline ), MP_ROM_PTR (& mp_stream_unbuffered_readline_obj ) },
269
+ { MP_ROM_QSTR (MP_QSTR_readinto ), MP_ROM_PTR (& mp_stream_readinto_obj ) },
270
+ { MP_ROM_QSTR (MP_QSTR_write ), MP_ROM_PTR (& mp_stream_write_obj ) },
<
1241
/tr>
271
+ { MP_ROM_QSTR (MP_QSTR_close ), MP_ROM_PTR (& mp_stream_close_obj ) },
272
+
273
+ };
274
+ static MP_DEFINE_CONST_DICT (micropython_ringbuffer_locals_dict , micropython_ringbuffer_locals_dict_table ) ;
275
+
276
+ static const mp_stream_p_t ringbuffer_stream_p = {
277
+ .read = micropython_ringbuffer_read ,
278
+ .write = micropython_ringbuffer_write ,
279
+ .ioctl = micropython_ringbuffer_ioctl ,
280
+ .is_text = false,
281
+ };
282
+
283
+ MP_DEFINE_CONST_OBJ_TYPE (
284
+ mp_type_micropython_ringbuffer ,
285
+ MP_QSTR_ringbuffer ,
286
+ MP_TYPE_FLAG_NONE ,
287
+ make_new , micropython_ringbuffer_make_new ,
288
+ protocol , & ringbuffer_stream_p ,
289
+ locals_dict , & micropython_ringbuffer_locals_dict
290
+ );
291
+
292
+ #endif
0 commit comments