@@ -71,3 +71,154 @@ 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 = mp_obj_get_int (args [0 ]);
90
+ micropython_ringbuffer_obj_t * self = mp_obj_malloc (micropython_ringbuffer_obj_t , type );
91
+ // Add one extra to buff_size as ringbuf consumes one byte for tracking.
92
+ ringbuf_alloc (& (self -> ringbuffer ), buff_size + 1 );
93
+ if (n_args > 1 ) {
94
+ self -> timeout = mp_obj_get_int (args [1 ]);
95
+ }
96
+ return MP_OBJ_FROM_PTR (self );
97
+ }
98
+
99
+ STATIC mp_obj_t micropython_ringbuffer_settimeout (mp_obj_t self_in , mp_obj_t timeout_in ) {
100
+ micropython_ringbuffer_obj_t * self = MP_OBJ_TO_PTR (self_in );
101
+ self -> timeout = mp_obj_get_int (timeout_in );
102
+ return mp_const_none ;
103
+ }
104
+ STATIC MP_DEFINE_CONST_FUN_OBJ_2 (micropython_ringbuffer_settimeout_obj , micropython_ringbuffer_settimeout );
105
+
106
+
107
+ STATIC mp_uint_t micropython_ringbuffer_read (mp_obj_t self_in , void * buf_in , mp_uint_t size , int * errcode ) {
108
+ micropython_ringbuffer_obj_t * self = MP_OBJ_TO_PTR (self_in );
109
+ uint32_t t = mp_hal_ticks_ms () + self -> timeout ;
110
+ uint8_t * dest = buf_in ;
111
+
112
+ for (size_t i = 0 ; i < size ; i ++ ) {
113
+ // Wait for the first/next character.
114
+ while (ringbuf_avail (& self -> ringbuffer ) == 0 ) {
115
+ if (mp_hal_ticks_ms () > t ) { // timed out
116
+ if (i <= 0 ) {
117
+ * errcode = MP_EAGAIN ;
118
+ return MP_STREAM_ERROR ;
119
+ } else {
120
+ return i ;
121
+ }
122
+ }
123
+ MICROPY_EVENT_POLL_HOOK
124
+ }
125
+ * dest ++ = ringbuf_get (& (self -> ringbuffer ));
126
+ t = mp_hal_ticks_ms () + self -> timeout ;
127
+ }
128
+ return size ;
129
+ }
130
+
131
+ STATIC mp_uint_t micropython_ringbuffer_write (mp_obj_t self_in , const void * buf_in , mp_uint_t size , int * errcode ) {
132
+ micropython_ringbuffer_obj_t * self = MP_OBJ_TO_PTR (self_in );
133
+ uint32_t t = mp_hal_ticks_ms () + self -> timeout ;
134
+ const uint8_t * src = buf_in ;
135
+ size_t i = 0 ;
136
+
137
+ // Put as many bytes as possible into the transmit buffer.
138
+ while (i < size && ringbuf_free (& (self -> ringbuffer )) > 0 ) {
139
+ ringbuf_put (& (self -> ringbuffer ), * src ++ );
140
+ ++ i ;
141
+ }
142
+ // If ringbuf full, block until drained elsewhere (eg. irq) or timeout.
143
+ while (i < size ) {
144
+ while (ringbuf_free (& (self -> ringbuffer )) == 0 ) {
145
+ if (mp_hal_ticks_ms () > t ) { // timed out
146
+ if (i <= 0 ) {
147
+ * errcode = MP_EAGAIN ;
148
+ return MP_STREAM_ERROR ;
149
+ } else {
150
+ return i ;
151
+ }
152
+ }
153
+ MICROPY_EVENT_POLL_HOOK
154
+ }
155
+ ringbuf_put (& (self -> ringbuffer ), * src ++ );
156
+ ++ i ;
157
+ t = mp_hal_ticks_ms () + self -> timeout ;
158
+ }
159
+ // Just in case the fifo was drained during refill of the ringbuf.
160
+ return size ;
161
+ }
162
+
163
+ STATIC mp_uint_t micropython_ringbuffer_ioctl (mp_obj_t self_in , mp_uint_t request , mp_uint_t arg , int * errcode ) {
164
+ micropython_ringbuffer_obj_t * self = self_in ;
165
+ mp_uint_t ret ;
166
+ if (request == MP_STREAM_POLL ) {
167
+ uintptr_t flags = arg ;
168
+ ret = 0 ;
169
+ if ((flags & MP_STREAM_POLL_RD ) && ringbuf_avail (& self -> ringbuffer ) > 0 ) {
170
+ ret |= MP_STREAM_POLL_RD ;
171
+ }
172
+ if ((flags & MP_STREAM_POLL_WR ) && ringbuf_free (& self -> ringbuffer ) > 0 ) {
173
+ ret |= MP_STREAM_POLL_WR ;
174
+ }
175
+ } else if (request == MP_STREAM_FLUSH ) {
176
+ // Should we wait here until empty / timeout?
177
+ ret = 0 ;
178
+ } else if (request == MP_STREAM_CLOSE ) {
179
+ // Should we flush here?
180
+ ret = 0 ;
181
+ } else {
182
+ * errcode = MP_EINVAL ;
183
+ ret = MP_STREAM_ERROR ;
184
+ }
185
+ return ret ;
186
+ }
187
+
188
+ STATIC mp_obj_t micropython_ringbuffer_any (mp_obj_t self_in ) {
189
+ micropython_ringbuffer_obj_t * self = MP_OBJ_TO_PTR (self_in );
190
+ return MP_OBJ_NEW_SMALL_INT (ringbuf_avail (& self -> ringbuffer ));
191
+ }
192
+ STATIC MP_DEFINE_CONST_FUN_OBJ_1 (micropython_ringbuffer_any_obj , micropython_ringbuffer_any );
193
+
194
+
195
+ STATIC const mp_rom_map_elem_t micropython_ringbuffer_locals_dict_table [] = {
196
+ { MP_ROM_QSTR (MP_QSTR_any ), MP_ROM_PTR (& micropython_ringbuffer_any_obj ) },
197
+ { MP_ROM_QSTR (MP_QSTR_settimeout ), MP_ROM_PTR (& micropython_ringbuffer_settimeout_obj ) },
198
+ { MP_ROM_QSTR (MP_QSTR_flush ), MP_ROM_PTR (& mp_stream_flush_obj ) },
199
+ { MP_ROM_QSTR (MP_QSTR_read ), MP_ROM_PTR (& mp_stream_read_obj ) },
200
+ { MP_ROM_QSTR (MP_QSTR_readline ), MP_ROM_PTR (& mp_stream_unbuffered_readline_obj ) },
201
+ { MP_ROM_QSTR (MP_QSTR_readinto ), MP_ROM_PTR (& mp_stream_readinto_obj ) },
202
+ { MP_ROM_QSTR (MP_QSTR_write ), MP_ROM_PTR (& mp_stream_write_obj ) },
203
+ { MP_ROM_QSTR (MP_QSTR_close ), MP_ROM_PTR (& mp_stream_close_obj ) },
204
+
205
+ };
206
+ STATIC MP_DEFINE_CONST_DICT (micropython_ringbuffer_locals_dict , micropython_ringbuffer_locals_dict_table );
207
+
208
+ STATIC const mp_stream_p_t ringbuffer_stream_p = {
209
+ .read = micropython_ringbuffer_read ,
210
+ .write = micropython_ringbuffer_write ,
211
+ .ioctl = micropython_ringbuffer_ioctl ,
212
+ .is_text = false,
213
+ };
214
+
215
+ MP_DEFINE_CONST_OBJ_TYPE (
216
+ mp_type_micropython_ringbuffer ,
217
+ MP_QSTR_ringbuffer ,
218
+ MP_TYPE_FLAG_NONE ,
219
+ make_new , micropython_ringbuffer_make_new ,
220
+ protocol , & ringbuffer_stream_p ,
221
+ locals_dict , & micropython_ringbuffer_locals_dict
222
+ );
223
+
224
+ #endif
0 commit comments