11// SPDX-License-Identifier: MIT
2- // Copyright (c) 2025 The Pybricks Authors
2+ // Copyright (c) 2025-2026 The Pybricks Authors
33//
44// P5/6 IRQ config based on the ev3ninja/osek project:
55// SPDX-License-Identifier: MPL-1.0
@@ -123,43 +123,40 @@ pbio_error_t pbdrv_counter_get_dev(uint8_t id, pbdrv_counter_dev_t **dev) {
123123#define ADC_EV3_LARGE_0 (32)
124124#define ADC_EV3_LARGE_1 (917)
125125#define ADC_NXT_LARGE_1 (1014)
126- #define ADC_MINDSENSORS_GLIDEWHEEL_0 (0)
127- #define ADC_MINDSENSORS_GLIDEWHEEL_1 (1023)
128-
129- static bool adc_is_close (uint32_t adc , uint32_t reference ) {
130- uint32_t error = adc > reference ? adc - reference : reference - adc ;
131- return error <= 21 ;
132- }
133126
134127/**
135128 * Gets the LEGO device type ID for an EV3 motor based on the ADC value.
136129 *
137130 * Each motor has two values (low and high) depending on the quadrature encoder
138- * state. The large motor is 4000 in the high state but in the low state it
139- * is indistinguishable from the EV3 large motor.
131+ * state. The NXT motor in the high state is slightly different from the EV3
132+ * large motor but it is indistinguishable in the low state, so we treat them
133+ * the same.
140134 *
141135 * The original firmware uses a dynamic process to distinguish other non-motor
142136 * devices. This is not implemented here. It does not appear necessary for
143137 * motors.
144138 */
145- static lego_device_type_id_t pbdrv_counter_ev3_get_type (uint16_t adc ) {
139+ static lego_device_type_id_t pbdrv_counter_ev3_get_type (uint16_t adc , lego_device_type_id_t type_now ) {
146140
147- if (adc == ADC_MINDSENSORS_GLIDEWHEEL_0 || adc == ADC_MINDSENSORS_GLIDEWHEEL_1 ) {
148- return LEGO_DEVICE_TYPE_ID_EV3_LARGE_MOTOR ;
149- }
141+ uint32_t margin = 30 ;
150142
151- if (adc_is_close (adc , ADC_EV3_MEDIUM_0 ) || adc_is_close (adc , ADC_EV3_MEDIUM_1 )) {
152- return LEGO_DEVICE_TYPE_ID_EV3_MEDIUM_MOTOR ;
143+ // If currently connected, be strict about the exit condition, and don't
144+ // allow changing to another type.
145+ if (type_now != LEGO_DEVICE_TYPE_ID_NONE ) {
146+ return adc > ADC_EV3_NONE - margin && adc < ADC_EV3_NONE + margin ?
147+ LEGO_DEVICE_TYPE_ID_NONE : type_now ;
153148 }
154149
155- if (adc_is_close (adc , ADC_EV3_LARGE_0 ) || adc_is_close (adc , ADC_EV3_LARGE_1 ) || adc_is_close (adc , ADC_NXT_LARGE_1 )) {
156- // We can only detect the difference between NXT and EV3 motors 50% of
157- // the time, depending on the optical encoder state. So always return
158- // the same type for consistency. Their parameters are relatively close.
159- return LEGO_DEVICE_TYPE_ID_EV3_LARGE_MOTOR ;
150+ // Otherwise, if not connected, be strict about the entry condition. This
151+ // providing hysteresis to reduce the likelihood of false transitions.
152+ if (adc > ADC_EV3_MEDIUM_0 + margin && adc < ADC_EV3_MEDIUM_1 - margin ) {
153+ return LEGO_DEVICE_TYPE_ID_NONE ;
160154 }
161155
162- return LEGO_DEVICE_TYPE_ID_NONE ;
156+ // A medium or large motor was connected. Find out which one.
157+ return adc < (ADC_EV3_MEDIUM_0 + ADC_EV3_LARGE_0 ) / 2 || adc > (ADC_EV3_MEDIUM_1 + ADC_EV3_LARGE_1 ) / 2 ?
158+ LEGO_DEVICE_TYPE_ID_EV3_LARGE_MOTOR :
159+ LEGO_DEVICE_TYPE_ID_EV3_MEDIUM_MOTOR ;
163160}
164161
165162#define PBDRV_COUNTER_EV3_TYPE_LOOP_TIME (10)
@@ -173,7 +170,7 @@ static void pbdrv_counter_ev3_update_type(pbdrv_counter_dev_t *dev) {
173170 // Get type detected now.
174171 uint16_t adc = 0 ;
175172 pbdrv_adc_get_ch (dev -> adc_channel , & adc );
176- lego_device_type_id_t type_id = pbdrv_counter_ev3_get_type (adc );
173+ lego_device_type_id_t type_id = pbdrv_counter_ev3_get_type (adc , dev -> stable_type_id );
177174
178175 // Update number of consecutive identical detections.
179176 if (dev -> last_type_id == type_id && dev -> position == dev -> type_id_position ) {
@@ -187,6 +184,9 @@ static void pbdrv_counter_ev3_update_type(pbdrv_counter_dev_t *dev) {
187184 // Update stable type if we have seen enough identical detections,
188185 // including none detections.
189186 if (dev -> type_id_count >= PBDRV_COUNTER_EV3_TYPE_MIN_STABLE_COUNT ) {
187+ if (dev -> stable_type_id != type_id ) {
188+ DEBUG_PRINT ("Detected %d (was %d)\n" , type_id , dev -> stable_type_id );
189+ }
190190 dev -> stable_type_id = type_id ;
191191 }
192192}
@@ -212,7 +212,6 @@ static pbio_error_t pbdrv_counter_device_detect_process_thread(pbio_os_state_t *
212212 PBIO_OS_ASYNC_END (PBIO_SUCCESS );
213213}
214214
215-
216215pbio_error_t pbdrv_counter_assert_type (pbdrv_counter_dev_t * dev , lego_device_type_id_t * expected_type_id ) {
217216
218217 if (dev -> stable_type_id == LEGO_DEVICE_TYPE_ID_NONE ) {
0 commit comments