@@ -237,23 +237,26 @@ class Analog_input(IO_object):
237
237
238
238
def __init__ (self , pin , name , sampling_rate , threshold = None , rising_event = None , falling_event = None , data_type = "H" ):
239
239
if rising_event or falling_event :
240
- self .threshold = Analog_threshold (threshold , rising_event , falling_event )
240
+ if threshold is None :
241
+ raise ValueError ("A threshold must be specified if rising or falling events are defined." )
242
+ self .threshold_watcher = Analog_threshold_watcher (threshold , rising_event , falling_event )
241
243
else :
242
- self .threshold = False
244
+ self .threshold_watcher = False
245
+
243
246
self .timer = pyb .Timer (available_timers .pop ())
244
247
if pin : # pin argument can be None when Analog_input subclassed.
245
248
self .ADC = pyb .ADC (pin )
246
249
self .read_sample = self .ADC .read
247
250
self .name = name
248
- self .Analog_channel = Analog_channel (name , sampling_rate , data_type )
251
+ self .channel = Analog_channel (name , sampling_rate , data_type )
249
252
assign_ID (self )
250
253
251
254
def _run_start (self ):
252
255
# Start sampling timer, initialise threshold, aquire first sample.
253
- self .timer .init (freq = self .Analog_channel .sampling_rate )
256
+ self .timer .init (freq = self .channel .sampling_rate )
254
257
self .timer .callback (self ._timer_ISR )
255
- if self .threshold :
256
- self .threshold .run_start (self .read_sample ())
258
+ if self .threshold_watcher :
259
+ self .threshold_watcher .run_start (self .read_sample ())
257
260
self ._timer_ISR (0 )
258
261
259
262
def _run_stop (self ):
@@ -263,9 +266,12 @@ def _run_stop(self):
263
266
def _timer_ISR (self , t ):
264
267
# Read a sample to the buffer, update write index.
265
268
sample = self .read_sample ()
266
- self .Analog_channel .put (sample )
267
- if self .threshold :
268
- self .threshold .check (sample )
269
+ self .channel .put (sample )
270
+ if self .threshold_watcher :
271
+ self .threshold_watcher .check (sample )
272
+
273
+ def change_threshold (self , new_threshold ):
274
+ self .threshold_watcher .set_threshold (new_threshold )
269
275
270
276
def record (self ): # For backward compatibility.
271
277
pass
@@ -286,15 +292,21 @@ class Analog_channel(IO_object):
286
292
# data array bytes (variable)
287
293
288
294
def __init__ (self , name , sampling_rate , data_type , plot = True ):
289
- assert data_type in ("b" , "B" , "h" , "H" , "i" , "I" ), "Invalid data_type."
290
- assert not any (
291
- [name == io .name for io in IO_dict .values () if isinstance (io , Analog_channel )]
292
- ), "Analog signals must have unique names."
295
+ if data_type not in ("b" , "B" , "h" , "H" , "i" , "I" ):
296
+ raise ValueError ("Invalid data_type." )
297
+ if any ([name == io .name for io in IO_dict .values () if isinstance (io , Analog_channel )]):
298
+ raise ValueError (
299
+ "Analog signals must have unique names.{} {}" .format (
300
+ name , [io .name for io in IO_dict .values () if isinstance (io , Analog_channel )]
301
+ )
302
+ )
303
+
293
304
self .name = name
294
305
assign_ID (self )
295
306
self .sampling_rate = sampling_rate
296
307
self .data_type = data_type
297
308
self .plot = plot
309
+
298
310
self .bytes_per_sample = {"b" : 1 , "B" : 1 , "h" : 2 , "H" : 2 , "i" : 4 , "I" : 4 }[data_type ]
299
311
self .buffer_size = max (4 , min (256 // self .bytes_per_sample , sampling_rate // 10 ))
300
312
self .buffers = (array (data_type , [0 ] * self .buffer_size ), array (data_type , [0 ] * self .buffer_size ))
@@ -344,45 +356,81 @@ def send_buffer(self, run_stop=False):
344
356
fw .usb_serial .send (self .buffers [buffer_n ])
345
357
346
358
347
- class Analog_threshold (IO_object ):
348
- # Generates framework events when an analog signal goes above or below specified threshold.
359
+ class Crossing :
360
+ above = "above"
361
+ below = "below"
362
+ none = "none"
363
+
364
+
365
+ class Analog_threshold_watcher (IO_object ):
366
+ """
367
+ Generates framework events when an analog signal goes above or below specified threshold.
368
+ If given single threshold value, rising event is triggered when signal > threshold, falling event is triggered when signal <= threshold.
369
+ If given tuple of two threshold values, rising event is triggered when signal > upper bound, falling event is triggered when signal < lower bound.
370
+ """
349
371
350
- def __init__ (self , threshold = None , rising_event = None , falling_event = None ):
351
- assert isinstance (
352
- threshold , int
353
- ), "Integer threshold must be specified if rising or falling events are defined."
354
- self .threshold = threshold
372
+ def __init__ (self , threshold , rising_event = None , falling_event = None ):
373
+ self .set_threshold (threshold )
355
374
self .rising_event = rising_event
356
375
self .falling_event = falling_event
357
376
self .timestamp = 0
358
- self .crossing_direction = False
377
+ self .last_crossing = Crossing . none
359
378
assign_ID (self )
360
379
380
+ def set_threshold (self , threshold ):
381
+ if isinstance (threshold , int ): # single threshold value
382
+ self .upper_threshold = threshold
383
+ self .lower_threshold = threshold + 1 # +1 so falling event is triggered when crossing into <= threshold
384
+ elif isinstance (threshold , tuple ):
385
+ threshold_requirements_str = "The threshold must be a single integer or a tuple of two integers (lower_bound, upper_bound) where lower_bound <= upper_bound."
386
+ if len (threshold ) != 2 :
387
+ raise ValueError ("{} is not a valid threshold. {}" .format (threshold , threshold_requirements_str ))
388
+ lower , upper = threshold
389
+ if not upper >= lower :
390
+ raise ValueError (
391
+ "{} is not a valid threshold because the lower bound {} is greater than the upper bound {}. {}" .format (
392
+ threshold , lower , upper , threshold_requirements_str
393
+ )
394
+ )
395
+ self .upper_threshold = upper
396
+ self .lower_threshold = lower
397
+ else :
398
+ raise ValueError ("{} is not a valid threshold. {}" .format (threshold , threshold_requirements_str ))
399
+
361
400
def _initialise (self ):
362
401
# Set event codes for rising and falling events.
363
402
self .rising_event_ID = sm .events [self .rising_event ] if self .rising_event in sm .events else False
364
403
self .falling_event_ID = sm .events [self .falling_event ] if self .falling_event in sm .events else False
365
404
self .threshold_active = self .rising_event_ID or self .falling_event_ID
366
405
367
406
def run_start (self , sample ):
368
- self .above_threshold = sample > self .threshold
407
+ self .was_above = sample > self .upper_threshold
408
+ self .was_below = sample < self .lower_threshold
369
409
370
410
def _process_interrupt (self ):
371
411
# Put event generated by threshold crossing in event queue.
372
- if self .crossing_direction :
412
+ if self .was_above :
373
413
fw .event_queue .put (fw .Datatuple (self .timestamp , fw .EVENT_TYP , "i" , self .rising_event_ID ))
374
414
else :
375
415
fw .event_queue .put (fw .Datatuple (self .timestamp , fw .EVENT_TYP , "i" , self .falling_event_ID ))
376
416
377
417
@micropython .native
378
418
def check (self , sample ):
379
- new_above_threshold = sample > self .threshold
380
- if new_above_threshold != self .above_threshold : # Threshold crossing.
381
- self .above_threshold = new_above_threshold
382
- if (self .above_threshold and self .rising_event_ID ) or (not self .above_threshold and self .falling_event_ID ):
383
- self .timestamp = fw .current_time
384
- self .crossing_direction = self .above_threshold
419
+ is_above_threshold = sample > self .upper_threshold
420
+ is_below_threshold = sample < self .lower_threshold
421
+
422
+ if is_above_threshold and not self .was_above and self .last_crossing != Crossing .above :
423
+ self .timestamp = fw .current_time
424
+ self .last_crossing = Crossing .above
425
+ if self .rising_event_ID :
385
426
interrupt_queue .put (self .ID )
427
+ elif is_below_threshold and not self .was_below and self .last_crossing != Crossing .below :
428
+ self .timestamp = fw .current_time
429
+ self .last_crossing = Crossing .below
430
+ if self .falling_event_ID :
431
+ interrupt_queue .put (self .ID )
432
+
433
+ self .was_above , self .was_below = is_above_threshold , is_below_threshold
386
434
387
435
388
436
# Digital Output --------------------------------------------------------------
0 commit comments