@@ -235,25 +235,36 @@ class Analog_input(IO_object):
235
235
# streams data to computer. Optionally can generate framework events when voltage
236
236
# goes above / below specified value theshold.
237
237
238
- def __init__ (self , pin , name , sampling_rate , threshold = None , rising_event = None , falling_event = None , data_type = "H" ):
239
- if rising_event or falling_event :
240
- self .threshold = Analog_threshold (threshold , rising_event , falling_event )
241
- else :
242
- self .threshold = False
238
+ def __init__ (
239
+ self ,
240
+ pin ,
241
+ name ,
242
+ sampling_rate ,
243
+ threshold = None ,
244
+ rising_event = None ,
245
+ falling_event = None ,
246
+ data_type = "H" ,
247
+ triggers = None ,
248
+ ):
249
+ self .triggers = triggers if triggers is not None else []
250
+
251
+ if threshold is not None : # For backward compatibility
252
+ self .triggers .append (AnalogTrigger (threshold , rising_event , falling_event ))
253
+
243
254
self .timer = pyb .Timer (available_timers .pop ())
244
255
if pin : # pin argument can be None when Analog_input subclassed.
245
256
self .ADC = pyb .ADC (pin )
246
257
self .read_sample = self .ADC .read
247
258
self .name = name
248
- self .Analog_channel = Analog_channel (name , sampling_rate , data_type )
259
+ self .channel = Analog_channel (name , sampling_rate , data_type )
249
260
assign_ID (self )
250
261
251
262
def _run_start (self ):
252
263
# Start sampling timer, initialise threshold, aquire first sample.
253
- self .timer .init (freq = self .Analog_channel .sampling_rate )
264
+ self .timer .init (freq = self .channel .sampling_rate )
254
265
self .timer .callback (self ._timer_ISR )
255
- if self .threshold :
256
- self . threshold . run_start (self .read_sample () )
266
+ for trigger in self .triggers :
267
+ trigger . run_start (self .name )
257
268
self ._timer_ISR (0 )
258
269
259
270
def _run_stop (self ):
@@ -263,9 +274,10 @@ def _run_stop(self):
263
274
def _timer_ISR (self , t ):
264
275
# Read a sample to the buffer, update write index.
265
276
sample = self .read_sample ()
266
- self .Analog_channel .put (sample )
267
- if self .threshold :
268
- self .threshold .check (sample )
277
+ self .channel .put (sample )
278
+ if self .triggers :
279
+ for trigger in self .triggers :
280
+ trigger .check (sample )
269
281
270
282
def record (self ): # For backward compatibility.
271
283
pass
@@ -286,15 +298,21 @@ class Analog_channel(IO_object):
286
298
# data array bytes (variable)
287
299
288
300
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 ([name == io .name for io in IO_dict .values () if isinstance (io , Analog_channel )]), (
291
- "Analog signals must have unique names."
292
- )
301
+ if data_type not in ("b" , "B" , "h" , "H" , "i" , "I" ):
302
+ raise ValueError ("Invalid data_type." )
303
+ if any ([name == io .name for io in IO_dict .values () if isinstance (io , Analog_channel )]):
304
+ raise ValueError (
305
+ "Analog signals must have unique names.{} {}" .format (
306
+ name , [io .name for io in IO_dict .values () if isinstance (io , Analog_channel )]
307
+ )
308
+ )
309
+
293
310
self .name = name
294
311
assign_ID (self )
295
312
self .sampling_rate = sampling_rate
296
313
self .data_type = data_type
297
314
self .plot = plot
315
+
298
316
self .bytes_per_sample = {"b" : 1 , "B" : 1 , "h" : 2 , "H" : 2 , "i" : 4 , "I" : 4 }[data_type ]
299
317
self .buffer_size = max (4 , min (256 // self .bytes_per_sample , sampling_rate // 10 ))
300
318
self .buffers = (array (data_type , [0 ] * self .buffer_size ), array (data_type , [0 ] * self .buffer_size ))
@@ -344,16 +362,15 @@ def send_buffer(self, run_stop=False):
344
362
fw .usb_serial .send (self .buffers [buffer_n ])
345
363
346
364
347
- class Analog_threshold (IO_object ):
348
- # Generates framework events when an analog signal goes above or below specified threshold.
365
+ class AnalogTrigger (IO_object ):
366
+ # Generates framework events when an analog signal goes above or below specified threshold value .
349
367
350
- def __init__ (self , threshold = None , rising_event = None , falling_event = None ):
351
- assert isinstance (threshold , int ), (
352
- "Integer threshold must be specified if rising or falling events are defined."
353
- )
354
- self .threshold = threshold
368
+ def __init__ (self , threshold , rising_event = None , falling_event = None ):
369
+ if rising_event is None and falling_event is None :
370
+ raise ValueError ("Either rising_event or falling_event or both must be specified." )
355
371
self .rising_event = rising_event
356
372
self .falling_event = falling_event
373
+ self .threshold = threshold
357
374
self .timestamp = 0
358
375
self .crossing_direction = False
359
376
assign_ID (self )
@@ -364,8 +381,9 @@ def _initialise(self):
364
381
self .falling_event_ID = sm .events [self .falling_event ] if self .falling_event in sm .events else False
365
382
self .threshold_active = self .rising_event_ID or self .falling_event_ID
366
383
367
- def run_start (self , sample ):
368
- self .above_threshold = sample > self .threshold
384
+ def run_start (self , attached_to ):
385
+ self .attached_to = attached_to
386
+ self .set_threshold (self .threshold , run_start = True )
369
387
370
388
def _process_interrupt (self ):
371
389
# Put event generated by threshold crossing in event queue.
@@ -376,14 +394,40 @@ def _process_interrupt(self):
376
394
377
395
@micropython .native
378
396
def check (self , sample ):
397
+ if self .reset_above_threshold :
398
+ # this gets run when the first sample is taken and whenever the threshold is changed
399
+ self .reset_above_threshold = False
400
+ self .above_threshold = sample > self .threshold
401
+ return
379
402
new_above_threshold = sample > self .threshold
380
403
if new_above_threshold != self .above_threshold : # Threshold crossing.
381
404
self .above_threshold = new_above_threshold
382
405
if (self .above_threshold and self .rising_event_ID ) or (not self .above_threshold and self .falling_event_ID ):
383
406
self .timestamp = fw .current_time
384
407
self .crossing_direction = self .above_threshold
408
+
385
409
interrupt_queue .put (self .ID )
386
410
411
+ def set_threshold (self , threshold , run_start = False ):
412
+ if not isinstance (threshold , int ):
413
+ raise ValueError (f"Threshold must be an integer, got { type (threshold ).__name__ } ." )
414
+ self .threshold = threshold
415
+ self .reset_above_threshold = True
416
+
417
+ content = {"value" : self .threshold , "attached_to" : self .attached_to }
418
+ if self .rising_event is not None :
419
+ content ["rising_event" ] = self .rising_event
420
+ if self .falling_event is not None :
421
+ content ["falling_event" ] = self .falling_event
422
+ fw .data_output_queue .put (
423
+ fw .Datatuple (
424
+ fw .current_time ,
425
+ fw .THRSH_TYP ,
426
+ "s" if run_start else "t" ,
427
+ str (content ),
428
+ )
429
+ )
430
+
387
431
388
432
# Digital Output --------------------------------------------------------------
389
433
@@ -509,4 +553,3 @@ def _timer_callback(self):
509
553
fw .data_output_queue .put (fw .Datatuple (fw .current_time , fw .EVENT_TYP , "s" , self .event_ID ))
510
554
self .state = not self .state
511
555
self .sync_pin .value (self .state )
512
-
0 commit comments