@@ -32,35 +32,36 @@ typedef struct _iodevices_PUPDevice_obj_t {
3232 uint8_t last_mode ;
3333 // ID of a passive device, if any.
3434 lego_device_type_id_t passive_id ;
35+ // Device port.
36+ pbio_port_t * port ;
3537} iodevices_PUPDevice_obj_t ;
3638
3739/**
3840 * Tests if the given device is a passive device and stores ID.
3941 *
4042 * @param [in] self The PUP device.
41- * @param [in] port_in The port.
4243 * @return True if passive device, false otherwise.
4344 */
44- static bool init_passive_pup_device (iodevices_PUPDevice_obj_t * self , mp_obj_t port_in ) {
45- pb_module_tools_assert_blocking ();
46-
47- pbio_port_id_t port_id = pb_type_enum_get_value (port_in , & pb_enum_type_Port );
45+ static bool init_passive_pup_device (iodevices_PUPDevice_obj_t * self ) {
4846
49- // Get the port instance.
50- pbio_port_t * port ;
51- pb_assert (pbio_port_get_port (port_id , & port ));
47+ // Check for custom devices that follow the Powered Up spec for simple
48+ // switches as touch sensors.
49+ uint32_t value ;
50+ pbio_error_t err = pbio_port_get_analog_value (self -> port , LEGO_DEVICE_TYPE_ID_LPF2_TOUCH , false, & value );
51+ if (err == PBIO_SUCCESS ) {
52+ self -> passive_id = LEGO_DEVICE_TYPE_ID_LPF2_TOUCH ;
53+ return true;
54+ }
5255
56+ // Check for DC motor or light.
5357 lego_device_type_id_t type_id = LEGO_DEVICE_TYPE_ID_ANY_DC_MOTOR ;
5458 pbio_dcmotor_t * dcmotor ;
55- pbio_error_t err = pbio_port_get_dcmotor (port , & type_id , & dcmotor );
56-
59+ err = pbio_port_get_dcmotor (self -> port , & type_id , & dcmotor );
5760 if (err == PBIO_SUCCESS ) {
5861 self -> passive_id = type_id ;
5962 return true;
6063 }
6164 return false;
62-
63- self -> passive_id = type_id ;
6465}
6566
6667// pybricks.iodevices.PUPDevice.__init__
@@ -70,8 +71,14 @@ static mp_obj_t iodevices_PUPDevice_make_new(const mp_obj_type_t *type, size_t n
7071
7172 iodevices_PUPDevice_obj_t * self = mp_obj_malloc (iodevices_PUPDevice_obj_t , type );
7273
74+ pb_module_tools_assert_blocking ();
75+
76+ // Get the port instance.
77+ pbio_port_id_t port_id = pb_type_enum_get_value (port_in , & pb_enum_type_Port );
78+ pb_assert (pbio_port_get_port (port_id , & self -> port ));
79+
7380 // For backwards compatibility, allow class to be used with passive devices.
74- if (init_passive_pup_device (self , port_in )) {
81+ if (init_passive_pup_device (self )) {
7582 return MP_OBJ_FROM_PTR (self );
7683 }
7784
@@ -158,13 +165,46 @@ static mp_obj_t get_pup_data_tuple(mp_obj_t self_in) {
158165 return mp_obj_new_tuple (mode_info [current_mode ].num_values , values );
159166}
160167
168+ static mp_obj_t iodevices_PUPDevice_touch_sensor_true (mp_obj_t self_in ) {
169+ return mp_const_true ;
170+ }
171+
172+ static mp_obj_t iodevices_PUPDevice_touch_sensor_false (mp_obj_t self_in ) {
173+ return mp_const_false ;
174+ }
175+
176+ static pbio_error_t iodevices_PUPDevice_touch_sensor_iter_once (pbio_os_state_t * state , mp_obj_t self_in ) {
177+ return PBIO_SUCCESS ;
178+ }
179+
161180// pybricks.iodevices.PUPDevice.read
162181static mp_obj_t iodevices_PUPDevice_read (size_t n_args , const mp_obj_t * pos_args , mp_map_t * kw_args ) {
163182 PB_PARSE_ARGS_METHOD (n_args , pos_args , kw_args ,
164183 iodevices_PUPDevice_obj_t , self ,
165184 PB_ARG_REQUIRED (mode ));
166185
167- // Passive devices don't support reading.
186+ // Allow reading from passive touch sensors as per the Powered Up spec.
187+ // These do not have modes. For this special case, alwyas return a bool,
188+ // even in async mode when other reads would return awaitables.
189+ if (self -> passive_id == LEGO_DEVICE_TYPE_ID_LPF2_TOUCH ) {
190+ uint32_t value ;
191+ pb_assert (pbio_port_get_analog_value (self -> port , self -> passive_id , false, & value ));
192+
193+ if (!pb_module_tools_run_loop_is_active ()) {
194+ return mp_obj_new_bool (value );
195+ }
196+
197+ // REVISIT: we could probably make something more efficient here.
198+ pb_type_async_t config = {
199+ .parent_obj = MP_OBJ_FROM_PTR (self ),
200+ .iter_once = iodevices_PUPDevice_touch_sensor_iter_once ,
201+ .return_map = value ? iodevices_PUPDevice_touch_sensor_true : iodevices_PUPDevice_touch_sensor_false ,
202+ };
203+
204+ return pb_type_async_wait_or_await (& config , & self -> device_base .last_awaitable , false);
205+ }
206+
207+ // Other passive devices don't support reading.
168208 if (self -> passive_id != LEGO_DEVICE_TYPE_ID_LPF2_UNKNOWN_UART ) {
169209 pb_assert (PBIO_ERROR_INVALID_OP );
170210 }
0 commit comments