32
32
#include "py/obj.h"
33
33
#include "py/nlr.h"
34
34
#include "py/runtime.h"
35
+ #include "py/stream.h"
36
+ #include "py/mperrno.h"
35
37
#include "py/mpprint.h"
36
38
37
39
#include "metal/sys.h"
44
46
#include "openamp/open_amp.h"
45
47
#include "openamp/remoteproc.h"
46
48
#include "openamp/remoteproc_loader.h"
49
+ #include "lib/rpmsg/rpmsg_internal.h"
47
50
#include "modopenamp.h"
48
51
49
52
#if !MICROPY_ENABLE_FINALISER
@@ -128,19 +131,52 @@ static MP_DEFINE_CONST_OBJ_TYPE(
128
131
) ;
129
132
130
133
// ###################### RPMsg Endpoint class ######################
134
+ // The number of RPMsg buffers to hold for an Endpoint. Note if this number matches
135
+ // the number of buffers per VRING, a full ring buffer/queue will cause the other
136
+ // side to block, because all buffers will be held by the application. If it's less
137
+ // than the number of buffers in a VRING, messages will be dropped if this side is not
138
+ // receiving messages.
139
+ #define ENDPOINT_RPMSG_RING_SIZE VRING_NUM_BUFFS
131
140
typedef struct _endpoint_obj_t {
132
141
mp_obj_base_t base ;
133
142
mp_obj_t name ;
134
143
mp_obj_t callback ;
135
144
struct rpmsg_endpoint ep ;
145
+ volatile uint32_t head ;
146
+ volatile uint32_t tail ;
147
+ void * rpmsg_buf [ENDPOINT_RPMSG_RING_SIZE ];
136
148
} endpoint_obj_t ;
137
149
138
150
static const mp_obj_type_t endpoint_type ;
139
151
152
+ static int endpoint_rpmsg_enqueue (endpoint_obj_t * ept , void * buf ) {
153
+ if (((ept -> tail + 1 ) % ENDPOINT_RPMSG_RING_SIZE ) != ept -> head ) {
154
+ ept -> rpmsg_buf [ept -> tail ] = buf ;
155
+ ept -> tail = (ept -> tail + 1 ) % ENDPOINT_RPMSG_RING_SIZE ;
156
+ rpmsg_hold_rx_buffer (& ept -> ep , buf );
157
+ return 0 ;
158
+ }
159
+ return -1 ;
160
+ }
161
+
162
+ static size_t endpoint_rpmsg_dequeue (endpoint_obj_t * ept , void * buf , size_t len ) {
163
+ size_t size = 0 ;
164
+ if (ept -> head != ept -> tail ) {
165
+ void * rpmsg = ept -> rpmsg_buf [ept -> head ];
166
+ size = MIN (RPMSG_LOCATE_HDR (rpmsg )-> len , len );
167
+ memcpy (buf , rpmsg , size );
168
+ ept -> head = (ept -> head + 1 ) % ENDPOINT_RPMSG_RING_SIZE ;
169
+ rpmsg_release_rx_buffer (& ept -> ep , rpmsg );
170
+ }
171
+ return size ;
172
+ }
173
+
140
174
static int endpoint_recv_callback (struct rpmsg_endpoint * ept , void * data , size_t len , uint32_t src , void * priv ) {
141
175
debug_printf ("endpoint_recv_callback() message received src: %lu msg len: %d\n" , src , len );
142
176
endpoint_obj_t * self = metal_container_of (ept , endpoint_obj_t , ep );
143
- if (self -> callback != mp_const_none ) {
177
+ if (self -> callback == mp_const_none ) {
178
+ endpoint_rpmsg_enqueue (self , data );
179
+ } else {
144
180
mp_call_function_2 (self -> callback , mp_obj_new_int (src ), mp_obj_new_bytearray_by_ref (len , data ));
145
181
}
146
182
return 0 ;
@@ -195,6 +231,40 @@ static mp_obj_t endpoint_send(uint n_args, const mp_obj_t *pos_args, mp_map_t *k
195
231
}
196
232
static MP_DEFINE_CONST_FUN_OBJ_KW (endpoint_send_obj , 2 , endpoint_send ) ;
197
233
234
+ static mp_obj_t endpoint_recv (uint n_args , const mp_obj_t * pos_args , mp_map_t * kw_args ) {
235
+ enum { ARG_timeout };
236
+ static const mp_arg_t allowed_args [] = {
237
+ { MP_QSTR_timeout , MP_ARG_INT | MP_ARG_KW_ONLY , {.u_int = 0 } },
238
+ };
239
+
240
+ // Parse args.
241
+ mp_arg_val_t args [MP_ARRAY_SIZE (allowed_args )];
242
+ mp_arg_parse_all (n_args - 2 , pos_args + 2 , kw_args , MP_ARRAY_SIZE (allowed_args ), allowed_args , args );
243
+
244
+ endpoint_obj_t * self = MP_OBJ_TO_PTR (pos_args [0 ]);
245
+ vstr_t vstr ;
246
+ size_t len = mp_obj_get_int (pos_args [1 ]);
247
+ vstr_init_len (& vstr , len );
248
+
249
+ mp_int_t timeout = args [ARG_timeout ].u_int ;
250
+ for (mp_uint_t start = mp_hal_ticks_ms (); ;) {
251
+ vstr .len = endpoint_rpmsg_dequeue (self , vstr .buf , len );
252
+ if (vstr .len > 0 ) {
253
+ break ;
254
+ }
255
+ if (timeout == 0 ) {
256
+ break ;
257
+ }
258
+ if (timeout > 0 && (mp_hal_ticks_ms () - start > timeout )) {
259
+ mp_raise_msg (& mp_type_OSError , MP_ERROR_TEXT ("timeout waiting for message" ));
260
+ }
261
+ MICROPY_EVENT_POLL_HOOK
262
+ }
263
+
264
+ return mp_obj_new_bytes_from_vstr (& vstr );
265
+ }
266
+ static MP_DEFINE_CONST_FUN_OBJ_KW (endpoint_recv_obj , 2 , endpoint_recv ) ;
267
+
198
268
static mp_obj_t endpoint_is_ready (mp_obj_t self_in ) {
199
269
endpoint_obj_t * self = MP_OBJ_TO_PTR (self_in );
200
270
return is_rpmsg_ept_ready (& self -> ep ) ? mp_const_true : mp_const_false ;
@@ -209,12 +279,13 @@ static mp_obj_t endpoint_deinit(mp_obj_t self_in) {
209
279
static MP_DEFINE_CONST_FUN_OBJ_1 (endpoint_deinit_obj , endpoint_deinit ) ;
210
280
211
281
static mp_obj_t endpoint_make_new (const mp_obj_type_t * type , size_t n_args , size_t n_kw , const mp_obj_t * all_args ) {
212
- enum { ARG_name , ARG_callback , ARG_src , ARG_dest };
282
+ enum { ARG_name , ARG_callback , ARG_src , ARG_dest , ARG_buf };
213
283
static const mp_arg_t allowed_args [] = {
214
- { MP_QSTR_name , MP_ARG_OBJ | MP_ARG_REQUIRED , {.u_rom_obj = MP_ROM_NONE } },
215
- { MP_QSTR_callback , MP_ARG_OBJ | MP_ARG_REQUIRED , {.u_rom_obj = MP_ROM_NONE } },
216
- { MP_QSTR_src , MP_ARG_INT | MP_ARG_KW_ONLY , {.u_int = RPMSG_ADDR_ANY } },
217
- { MP_QSTR_dest , MP_ARG_INT | MP_ARG_KW_ONLY , {.u_int = RPMSG_ADDR_ANY } },
284
+ { MP_QSTR_name , MP_ARG_OBJ | MP_ARG_REQUIRED , {.u_rom_obj = MP_ROM_NONE } },
285
+ { MP_QSTR_callback , MP_ARG_OBJ , {.u_rom_obj = MP_ROM_NONE } },
286
+ { MP_QSTR_src , MP_ARG_INT | MP_ARG_KW_ONLY , {.u_int = RPMSG_ADDR_ANY } },
287
+ { MP_QSTR_dest , MP_ARG_INT | MP_ARG_KW_ONLY , {.u_int = RPMSG_ADDR_ANY } },
288
+ { MP_QSTR_buf , MP_ARG_INT | MP_ARG_KW_ONLY , {.u_int = 2048 } },
218
289
};
219
290
220
291
// Parse args.
@@ -224,6 +295,7 @@ static mp_obj_t endpoint_make_new(const mp_obj_type_t *type, size_t n_args, size
224
295
endpoint_obj_t * self = mp_obj_malloc_with_finaliser (endpoint_obj_t , & endpoint_type );
225
296
self -> name = args [ARG_name ].u_obj ;
226
297
self -> callback = args [ARG_callback ].u_obj ;
298
+ self -> head = self -> tail = 0 ;
227
299
228
300
if (MP_STATE_PORT (virtio_device ) == NULL ) {
229
301
openamp_init ();
@@ -241,15 +313,66 @@ static const mp_rom_map_elem_t endpoint_locals_dict_table[] = {
241
313
{ MP_ROM_QSTR (MP_QSTR___name__ ), MP_ROM_QSTR (MP_QSTR_Endpoint ) },
242
314
{ MP_ROM_QSTR (MP_QSTR___del__ ), MP_ROM_PTR (& endpoint_deinit_obj ) },
243
315
{ MP_ROM_QSTR (MP_QSTR_send ), MP_ROM_PTR (& endpoint_send_obj ) },
316
+ { MP_ROM_QSTR (MP_QSTR_recv ), MP_ROM_PTR (& endpoint_recv_obj ) },
244
317
{ MP_ROM_QSTR (MP_QSTR_is_ready ), MP_ROM_PTR (& endpoint_is_ready_obj ) },
245
318
};
246
319
static MP_DEFINE_CONST_DICT (endpoint_locals_dict , endpoint_locals_dict_table ) ;
247
320
321
+ mp_uint_t endpoint_read (mp_obj_t self_in , void * buf , mp_uint_t size , int * errcode ) {
322
+ endpoint_obj_t * self = MP_OBJ_TO_PTR (self_in );
323
+ if (!is_rpmsg_ept_ready (& self -> ep )) {
324
+ return MP_STREAM_ERROR ;
325
+ }
326
+ return endpoint_rpmsg_dequeue (self , buf , size );
327
+ }
328
+
329
+ mp_uint_t endpoint_write (mp_obj_t self_in , const void * buf , mp_uint_t size , int * errcode ) {
330
+ endpoint_obj_t * self = MP_OBJ_TO_PTR (self_in );
331
+ int ret = 0 ;
332
+ if (!is_rpmsg_ept_ready (& self -> ep )) {
333
+ ret = MP_STREAM_ERROR ;
334
+ } else {
335
+ ret = rpmsg_send (& self -> ep , buf , size );
336
+ if (ret < 0 ) {
337
+ ret = MP_STREAM_ERROR ;
338
+ }
339
+ }
340
+ return ret ;
341
+ }
342
+
343
+ mp_uint_t endpoint_ioctl (mp_obj_t self_in , mp_uint_t request , uintptr_t arg , int * errcode ) {
344
+ endpoint_obj_t * self = MP_OBJ_TO_PTR (self_in );
345
+ mp_uint_t ret = 0 ;
346
+ if (request == MP_STREAM_CLOSE ) {
347
+ rpmsg_destroy_ept (& self -> ep );
348
+ } else if (request == MP_STREAM_POLL ) {
349
+ if ((arg & MP_STREAM_POLL_RD ) && self -> head != self -> tail ) {
350
+ ret |= MP_STREAM_POLL_RD ;
351
+ }
352
+
353
+ if ((arg & MP_STREAM_POLL_WR ) && is_rpmsg_ept_ready (& self -> ep )) {
354
+ ret |= MP_STREAM_POLL_WR ;
355
+ }
356
+ } else {
357
+ * errcode = MP_EINVAL ;
358
+ ret = MP_STREAM_ERROR ;
359
+ }
360
+ return ret ;
361
+ }
362
+
363
+ static const mp_stream_p_t endpoint_stream_p = {
364
+ .read = endpoint_read ,
365
+ .write = endpoint_write ,
366
+ .ioctl = endpoint_ioctl ,
367
+ .is_text = false,
368
+ };
369
+
248
370
static MP_DEFINE_CONST_OBJ_TYPE (
249
371
endpoint_type ,
250
372
MP_QSTR_Endpoint ,
251
373
MP_TYPE_FLAG_NONE ,
252
374
make_new , endpoint_make_new ,
375
+ protocol , & endpoint_stream_p ,
253
376
locals_dict , & endpoint_locals_dict
254
377
) ;
255
378
0 commit comments