@@ -27,23 +27,64 @@ typedef struct _iodevices_PUPDevice_obj_t {
2727 pb_type_device_obj_base_t device_base ;
2828 // Mode used when initiating awaitable read. REVISIT: This should be stored
2929 // on the awaitable instead, as extra context. For now, it is safe since
30- // concurrent reads with the same sensor are not permitten .
30+ // concurrent reads with the same sensor are not permitted .
3131 uint8_t last_mode ;
32+ // ID of a passive device, if any.
33+ pbdrv_legodev_type_id_t passive_id ;
3234} iodevices_PUPDevice_obj_t ;
3335
36+ /**
37+ * Tests if the given device is a passive device and stores ID.
38+ *
39+ * @param [in] self The PUP device.
40+ * @param [in] port_in The port.
41+ * @return True if passive device, false otherwise.
42+ */
43+ STATIC bool init_passive_pup_device (iodevices_PUPDevice_obj_t * self , mp_obj_t port_in ) {
44+ pb_module_tools_assert_blocking ();
45+ pbio_port_id_t port = pb_type_enum_get_value (port_in , & pb_enum_type_Port );
46+ pbdrv_legodev_type_id_t candidates [] = {
47+ PBDRV_LEGODEV_TYPE_ID_ANY_DC_MOTOR ,
48+ PBDRV_LEGODEV_TYPE_ID_LPF2_LIGHT ,
49+ };
50+ for (uint8_t i = 0 ; i < MP_ARRAY_SIZE (candidates ); i ++ ) {
51+ if (pbdrv_legodev_get_device (port , & candidates [i ], & self -> device_base .legodev ) == PBIO_SUCCESS ) {
52+ self -> passive_id = candidates [i ];
53+ return true;
54+ }
55+ }
56+ return false;
57+ }
58+
3459// pybricks.iodevices.PUPDevice.__init__
3560STATIC mp_obj_t iodevices_PUPDevice_make_new (const mp_obj_type_t * type , size_t n_args , size_t n_kw , const mp_obj_t * args ) {
3661 PB_PARSE_ARGS_CLASS (n_args , n_kw , args ,
3762 PB_ARG_REQUIRED (port ));
3863
3964 iodevices_PUPDevice_obj_t * self = mp_obj_malloc (iodevices_PUPDevice_obj_t , type );
65+
66+ // For backwards compatibility, allow class to be used with passive devices.
67+ if (init_passive_pup_device (self , port_in )) {
68+ return MP_OBJ_FROM_PTR (self );
69+ }
70+
71+ // Initialize any UART PUP device.
4072 pb_type_device_init_class (& self -> device_base , port_in , PBDRV_LEGODEV_TYPE_ID_ANY_LUMP_UART );
73+ self -> passive_id = PBDRV_LEGODEV_TYPE_ID_LPF2_UNKNOWN_UART ;
4174 return MP_OBJ_FROM_PTR (self );
4275}
4376
4477// pybricks.iodevices.PUPDevice.info
4578STATIC mp_obj_t iodevices_PUPDevice_info (mp_obj_t self_in ) {
4679 iodevices_PUPDevice_obj_t * self = MP_OBJ_TO_PTR (self_in );
80+
81+ // Passive devices only have an ID.
82+ if (self -> passive_id != PBDRV_LEGODEV_TYPE_ID_LPF2_UNKNOWN_UART ) {
83+ mp_obj_t info_dict = mp_obj_new_dict (1 );
84+ mp_obj_dict_store (info_dict , MP_ROM_QSTR (MP_QSTR_id ), MP_OBJ_NEW_SMALL_INT (self -> passive_id ));
85+ return info_dict ;
86+ }
87+
4788 pbdrv_legodev_info_t * info ;
4889 pb_assert (pbdrv_legodev_get_info (self -> device_base .legodev , & info ));
4990
@@ -107,6 +148,11 @@ STATIC mp_obj_t iodevices_PUPDevice_read(size_t n_args, const mp_obj_t *pos_args
107148 iodevices_PUPDevice_obj_t , self ,
108149 PB_ARG_REQUIRED (mode ));
109150
151+ // Passive devices don't support reading.
152+ if (self -> passive_id != PBDRV_LEGODEV_TYPE_ID_LPF2_UNKNOWN_UART ) {
153+ pb_assert (PBIO_ERROR_INVALID_OP );
154+ }
155+
110156 self -> last_mode = mp_obj_get_int (mode_in );
111157
112158 // We can re-use the same code as for specific sensor types, only the mode
@@ -127,6 +173,11 @@ STATIC mp_obj_t iodevices_PUPDevice_write(size_t n_args, const mp_obj_t *pos_arg
127173 PB_ARG_REQUIRED (mode ),
128174 PB_ARG_REQUIRED (data ));
129175
176+ // Passive devices don't support writing.
177+ if (self -> passive_id != PBDRV_LEGODEV_TYPE_ID_LPF2_UNKNOWN_UART ) {
178+ pb_assert (PBIO_ERROR_INVALID_OP );
179+ }
180+
130181 // Get requested mode.
131182 uint8_t mode = mp_obj_get_int (mode_in );
132183
0 commit comments