liftof_lib/master_trigger/
control.rs

1//! Master trigger board control
2//!
3//! Set registers and enable/disable features,
4//! readout event and monitoring data
5//!
6//! Many control functions in this module can go
7//! away, since they can be replaced by the 
8//! calls on the register implementation directly.
9
10use std::error::Error;
11use tof_dataclasses::ipbus::{
12  IPBus,
13};
14
15use crate::master_trigger::registers::*;
16
17/// Read event counter register of MTB
18///
19/// This gives the number of events read 
20/// since the last counter reset
21pub fn read_event_cnt(bus : &mut IPBus) //,
22                      //buffer : &mut [u8;MT_MAX_PACKSIZE])
23  -> Result<u32, Box<dyn Error>> {
24  let event_count = bus.read(0xd)?;
25  trace!("Got event count! {} ", event_count);
26  Ok(event_count)
27}
28
29/// Set the RB readout mode - either 
30/// read out all channels all the time
31/// or use the MTB to indicate to the RBs
32/// which channels to read out 
33pub fn set_trace_suppression(bus : &mut IPBus,
34                             sup : bool) 
35  -> Result<(), Box<dyn Error>> {
36  info!("Setting MTB trace suppression {}!", sup);
37  let mut value = bus.read(0xf)?;
38  // bit 13 has to be 1 for read all channels
39  let read_all_ch = u32::pow(2, 13);
40  if sup { // sup means !read_all_ch
41    value = value & !read_all_ch;
42  }
43  else {
44    value = value | read_all_ch; 
45  }
46  bus.write(0xf, value)?;
47  Ok(())
48}
49
50/// Reset the state of the MTB DAQ buffer
51/// This can be safely issued without 
52/// resetting the event id
53pub fn reset_daq(bus : &mut IPBus) 
54  -> Result<(), Box<dyn Error>> {
55  info!("Resetting DAQ!");
56  bus.write(0x10, 1)?;
57  Ok(())
58}
59
60
61/// Retrieve the status of the TIU link
62///
63/// The TIU is the trigger interface unit
64/// and connects TOF and Tracker
65///
66/// # Returns:
67///
68///   bool : true if the link status is "good"
69///          which means TIU is connected and 
70///          link is ok
71pub fn tiu_link_is_good(bus : &mut IPBus)
72  -> Result<bool, Box<dyn Error>> {
73  let mut tiu_good = 0x1u32;
74  let value        = bus.read(0xf)?;
75  tiu_good         = tiu_good & ( value & 0x1);
76  Ok(tiu_good > 0)
77}
78
79/// The TIU emulation mode literally allows to emulate a TIU even if it 
80/// is not connected.
81///
82/// This will inject a certain deadtime into the MasterTrigger triggering
83/// system, as if a BUSY signal was received from an actual TIU
84pub fn set_tiu_emulation_mode(bus : &mut IPBus, set_emulation_mode : bool) 
85  -> Result<(), Box<dyn Error>> {
86    info!("Setting TIU Emulation mode {}", set_emulation_mode);
87    let mut value = bus.read(0xe)?;
88    let bitset : u32;
89    if set_emulation_mode {
90      bitset = 0x1;
91    } else {
92      bitset = 0x0;
93    }
94    value = value & 0xfffffffe;
95    value = value | bitset;
96    bus.write(0xe, value)?;
97    Ok(())
98}
99
100/// Set the busy count for the tiu emulation mode in 10ns clockcycles
101pub fn set_tiu_emulation_mode_bsy_cnt(bus : &mut IPBus, cycles : u32)
102  -> Result<(), Box<dyn Error>> {
103  info!("Setting TIU Emulation mode bsy cnt to {} clock cycles (10ns each)", cycles);
104  TIU_EMU_BUSY_CNT.set(bus, cycles)?;
105  Ok(()) 
106}
107
108/// Get the number of clock cycles (1=10ns) that the emulator will remain busy
109pub fn get_tiu_emu_busy_cnt(bus : &mut IPBus) 
110  -> Result<u32, Box<dyn Error>> {
111  TIU_EMU_BUSY_CNT.get(bus)
112}
113
114pub fn get_gaps_trigger_prescale(bus : &mut IPBus)
115  -> Result<f32, Box<dyn Error>> {
116    let prescale_bus = GAPS_TRIG_PRESCALE.get(bus)?;
117    let prescale_val = (prescale_bus as f32)/f32::MAX;
118    return Ok(prescale_val)
119  }
120
121pub fn set_gaps_trigger_prescale(bus : &mut IPBus, prescale : f32)
122  -> Result<(), Box<dyn Error>> {
123    let prescale_val = (u32::MAX as f32 * prescale).floor() as u32;
124    info!("Setting gaps trigger with prescale {};)", prescale);
125    bus.write(0x248, prescale_val)?;
126  Ok(())
127  }
128/// The readoutboard integration window
129///
130/// The default setting is "1" and currently 
131/// it should only be changed by experts for 
132/// a good reason.
133///
134/// The RB integration window affects the readout
135/// of RB pulses which are not part of the initial
136/// Trigger, but come later instead.
137/// This is reflected in the BOARD_MASKs/mtb_link_id
138/// mas of the MasterTriggerEvent. The larger the 
139/// number, the more boards we might expect. (?)
140pub fn set_rb_int_window(bus : &mut IPBus, wind : u8)
141  -> Result<(), Box<dyn Error>> {
142  info!("Setting RB_INT_WINDOW to {}!", wind);
143  let mut value  =  bus.read(0xf)?;
144  //println!("==> Retrieved {value} from register 0xf on MTB");
145  let mask   = 0xffffe0ff;
146  // switch the bins off
147  value          = value & mask;
148  let wind_bits  = (wind as u32) << 8;
149  value = value | wind_bits;
150  bus.write(0xf, value)?;
151  trace!("++ Writing to register ++");
152  value = bus.read(0xf)?;
153  trace!("==> Reading back value {value} from register 0xf on MTB after writing to it!");
154  Ok(())
155}
156
157/// Set the poisson trigger with a prescale
158pub fn set_poisson_trigger(bus : &mut IPBus, rate : u32) 
159  -> Result<(), Box<dyn Error>> {
160  //let clk_period = 1e8u32; 
161  let clk_period = 100000000;
162  let rate_val = (u32::MAX*rate)/clk_period;//(1.0/ clk_period)).floor() as u32;
163  
164  //let rate_val   = (rate as f32 * u32::MAX as f32/1.0e8) as u32; 
165  info!("Setting poisson trigger with rate {}!", rate);
166  bus.write(0x9, rate_val)?;
167  Ok(())
168}
169
170/// Set the any trigger with a prescale
171pub fn set_any_trigger(bus : &mut IPBus, prescale : f32) 
172  -> Result<(), Box<dyn Error>> {
173  let prescale_val = (u32::MAX as f32 * prescale).floor() as u32;
174  info!("Setting any trigger with prescale {}!", prescale);
175  bus.write(0x40, prescale_val)?;
176  Ok(())
177}
178
179/// Set the track trigger with a prescale
180pub fn set_track_trigger(bus : &mut IPBus, prescale : f32) 
181  -> Result<(), Box<dyn Error>> {
182  let prescale_val = (u32::MAX as f32 * prescale).floor() as u32;
183  info!("Setting track trigger with prescale {}!", prescale);
184  bus.write(0x41, prescale_val)?;
185  Ok(())
186}
187
188/// Set the CENTRAL track trigger with a prescale
189pub fn set_central_track_trigger(bus : &mut IPBus, prescale : f32) 
190  -> Result<(), Box<dyn Error>> {
191  let prescale_val = (u32::MAX as f32 * prescale).floor() as u32;
192  info!("Setting CENTRAL TRACK trigger with prescale {}!", prescale);
193  bus.write(0x42, prescale_val)?;
194  Ok(())
195}
196
197pub fn set_track_umb_central_trigger(bus : &mut IPBus, prescale : f32)
198    -> Result<(), Box<dyn Error>> {
199    let prescale_val = (u32::MAX as f32 * prescale).floor() as u32;
200    info!("Setting TRACK UMB CENTRAL trigger with prescale {}!", prescale);
201    bus.write(0x249, prescale_val)?;
202    Ok(())
203  }
204
205
206/// Disable all triggers
207pub fn unset_all_triggers(bus : &mut IPBus) 
208  -> Result<(), Box<dyn Error>> {
209  // first the GAPS trigger, whcih is a more 
210  // complicated register, where we only have
211  // to flip 1 bit
212  //zero_all_trigger_thresholds(bus)?;
213  let mut trig_settings = bus.read(0x14)?;
214  trig_settings         = trig_settings & !u32::pow(2,24);
215  bus.write(0x14, trig_settings)?;
216  set_poisson_trigger(bus, 0)?;
217  set_any_trigger    (bus, 0.0)?;
218  set_track_trigger  (bus, 0.0)?;
219  set_central_track_trigger(bus, 0.0)?;
220  set_configurable_trigger(bus, false)?;
221  TRACK_TRIG_IS_GLOBAL.set(bus, 0)?; 
222  ANY_TRIG_IS_GLOBAL.set(bus, 0)?;
223  TRACK_CENTRAL_IS_GLOBAL.set(bus, 0)?;
224  set_track_umb_central_trigger(bus, 0.0)?;
225  Ok(())
226}
227
228/// Set the gaps trigger with a prescale
229pub fn set_gaps_trigger(bus : &mut IPBus, use_beta : bool) 
230  -> Result<(), Box<dyn Error>> {
231  info!("Setting GAPS Antiparticle trigger, use beta {}!", use_beta);
232  set_inner_tof_threshold(bus,0x3)?;
233  set_outer_tof_threshold(bus,0x3)?;
234  set_total_tof_threshold(bus,0x8)?;
235  let mut trig_settings = bus.read(0x14)?;
236  trig_settings = trig_settings | u32::pow(2,24);
237  if use_beta {
238    trig_settings = trig_settings | u32::pow(2,25);
239  }
240  bus.write(0x14, trig_settings)?;
241  Ok(())
242}
243
244/// Set the gaps trigger with a prescale
245pub fn set_gaps1044_trigger(bus : &mut IPBus, use_beta : bool) 
246  -> Result<(), Box<dyn Error>> {
247  info!("Setting GAPS Antiparticle trigger, use beta {}!", use_beta);
248  set_inner_tof_threshold(bus,0x4)?;
249  set_outer_tof_threshold(bus,0x4)?;
250  set_total_tof_threshold(bus,0x10)?;
251  let mut trig_settings = bus.read(0x14)?;
252  trig_settings = trig_settings | u32::pow(2,24);
253  if use_beta {
254    trig_settings = trig_settings | u32::pow(2,25);
255  }
256  bus.write(0x14, trig_settings)?;
257  Ok(())
258}
259
260pub fn set_gaps_track_trigger(bus : &mut IPBus, prescale : f32, use_beta : bool) 
261  -> Result<(), Box<dyn Error>> {
262  info!("Setting GAPS + Track trigger combo");
263  TRACK_TRIG_IS_GLOBAL.set(bus, 1)?;
264  set_gaps_trigger(bus, use_beta)?;
265  set_track_trigger(bus, prescale)?;
266  Ok(())
267}
268
269pub fn set_gaps_any_trigger(bus : &mut IPBus, prescale : f32, use_beta : bool)
270  -> Result<(), Box<dyn Error>> {
271    info!("Setting GAPS + Any trigger combo");
272    ANY_TRIG_IS_GLOBAL.set(bus, 1)?;
273    set_gaps_trigger(bus, use_beta)?;
274    set_any_trigger(bus, prescale)?;
275    Ok(())
276  }
277
278pub fn set_gaps_central_track_trigger(bus : &mut IPBus, prescale : f32, use_beta : bool)
279  -> Result<(), Box<dyn Error>> {
280    info!("Setting GAPS + Central Track trigger combo");
281    TRACK_CENTRAL_IS_GLOBAL.set(bus, 1)?;
282    set_gaps_trigger(bus, use_beta)?;
283    set_central_track_trigger(bus, prescale)?;
284    Ok(())
285  }
286
287pub fn set_gaps422_central_track_trigger(bus : &mut IPBus, prescale : f32, use_beta : bool)
288  -> Result<(), Box<dyn Error>> {
289    info!("Setting GAPS + Central Track trigger combo");
290    TRACK_CENTRAL_IS_GLOBAL.set(bus, 1)?;
291    set_gaps422_trigger(bus, use_beta)?;
292    set_central_track_trigger(bus, prescale)?;
293    Ok(())
294  }
295
296pub fn set_gaps633_trigger(bus : &mut IPBus, use_beta : bool) 
297  -> Result<(), Box<dyn Error>> {
298  info!("Setting GAPS Antiparticle trigger, use beta {}!", use_beta);
299  set_inner_tof_threshold(bus,0x3)?;
300  set_outer_tof_threshold(bus,0x3)?;
301  set_total_tof_threshold(bus,0x6)?;
302  let mut trig_settings = bus.read(0x14)?;
303  trig_settings = trig_settings | u32::pow(2,24);
304  if use_beta {
305    trig_settings = trig_settings | u32::pow(2,25);
306  }
307  bus.write(0x14, trig_settings)?;
308  Ok(())
309}
310
311pub fn set_gaps422_trigger(bus : &mut IPBus, use_beta : bool) 
312  -> Result<(), Box<dyn Error>> {
313  info!("Setting GAPS Antiparticle trigger, use beta {}!", use_beta);
314  set_inner_tof_threshold(bus,0x2)?;
315  set_outer_tof_threshold(bus,0x2)?;
316  set_total_tof_threshold(bus,0x4)?;
317  let mut trig_settings = bus.read(0x14)?;
318  trig_settings = trig_settings | u32::pow(2,24);
319  if use_beta {
320    trig_settings = trig_settings | u32::pow(2,25);
321  }
322  bus.write(0x14, trig_settings)?;
323  Ok(())
324}
325
326pub fn set_gaps211_trigger(bus : &mut IPBus, use_beta : bool) 
327  -> Result<(), Box<dyn Error>> {
328  info!("Setting GAPS Antiparticle trigger, use beta {}!", use_beta);
329  set_inner_tof_threshold(bus,0x1)?;
330  set_outer_tof_threshold(bus,0x1)?;
331  set_total_tof_threshold(bus,0x2)?;
332  let mut trig_settings = bus.read(0x14)?;
333  trig_settings = trig_settings | u32::pow(2,24);
334  if use_beta {
335    trig_settings = trig_settings | u32::pow(2,25);
336  }
337  bus.write(0x14, trig_settings)?;
338  Ok(())
339}
340
341pub fn set_configurable_trigger(bus : &mut IPBus, enable : bool) 
342  -> Result<(), Box<dyn Error>> {
343  if enable {
344    info!("Enabling configurable trigger!");
345  } else {
346    info!("Disabling configurable trigger!");
347  }
348  let mut trig_settings = bus.read(0x14)?;
349  //println!("Got {} trig settings", trig_settings);
350  if enable {
351    trig_settings = trig_settings | u32::pow(2,31);
352  } else {
353    trig_settings = trig_settings & !(u32::pow(2,31));
354  }
355  //println!("Will write {} trig settings", trig_settings);
356  bus.write(0x14, trig_settings)?;
357  Ok(())
358}
359
360pub fn set_inner_tof_threshold(bus : &mut IPBus, thresh : u8)
361  -> Result<(), Box<dyn Error>> {
362  info!("Setting inner TOF threshold {}!", thresh);
363  let mut trig_settings = bus.read(0x14)?;
364  trig_settings = trig_settings & 0xffffff00;
365  trig_settings = trig_settings | thresh as u32;
366  bus.write(0x14, trig_settings)?;
367  Ok(())
368}
369
370pub fn set_outer_tof_threshold(bus : &mut IPBus, thresh : u8)
371  -> Result<(), Box<dyn Error>> {
372  info!("Setting outer TOF threshold {}!", thresh);
373  let mut trig_settings = bus.read(0x14)?;
374  trig_settings = trig_settings & 0xffff00ff;
375  trig_settings = trig_settings | ((thresh as u32) << 8);
376  bus.write(0x14, trig_settings)?;
377  Ok(())
378}
379
380pub fn set_total_tof_threshold(bus : &mut IPBus, thresh : u8)
381  -> Result<(), Box<dyn Error>> {
382  info!("Setting total TOF threshold {}!", thresh);
383  let mut trig_settings = bus.read(0x14)?;
384  trig_settings = trig_settings & 0xff00ffff;
385  trig_settings = trig_settings | ((thresh as u32) << 16);
386  bus.write(0x14, trig_settings)?;
387  Ok(())
388}
389
390pub fn set_cube_side_threshold(bus : &mut IPBus, thresh : u8)
391  -> Result<(), Box<dyn Error>> {
392  info!("Setting cube side threshold {}!", thresh);
393  let mut trig_settings = bus.read(0x15)?;
394  trig_settings = trig_settings & 0xffffff00;
395  trig_settings = trig_settings | thresh as u32;
396  bus.write(0x15, trig_settings)?;
397  Ok(())
398}
399
400pub fn set_cube_top_threshold(bus : &mut IPBus, thresh : u8)
401  -> Result<(), Box<dyn Error>> {
402  info!("Setting cube top threshold {}!", thresh);
403  let mut trig_settings = bus.read(0x15)?;
404  trig_settings = trig_settings & 0xffff00ff;
405  trig_settings = trig_settings | ((thresh as u32) << 8);
406  bus.write(0x15, trig_settings)?;
407  Ok(())
408}
409
410pub fn set_cube_bottom_threshold(bus : &mut IPBus, thresh : u8)
411  -> Result<(), Box<dyn Error>> {
412  info!("Setting cube bottom threshold {}!", thresh);
413  let mut trig_settings = bus.read(0x15)?;
414  trig_settings = trig_settings & 0xff00ffff;
415  trig_settings = trig_settings | ((thresh as u32) << 16);
416  bus.write(0x15, trig_settings)?;
417  Ok(())
418}
419
420pub fn set_cube_corner_threshold(bus : &mut IPBus, thresh : u8)
421  -> Result<(), Box<dyn Error>> {
422  info!("Setting cube corner threshold {}!", thresh);
423  let mut trig_settings = bus.read(0x15)?;
424  trig_settings = trig_settings & 0x00ffffff;
425  trig_settings = trig_settings | ((thresh as u32) << 24);
426  bus.write(0x15, trig_settings)?;
427  Ok(())
428}
429
430pub fn set_umbrella_threshold(bus : &mut IPBus, thresh : u8)
431  -> Result<(), Box<dyn Error>> {
432  info!("Setting umbrella threshold {}!", thresh);
433  let mut trig_settings = bus.read(0x16)?;
434  // first zero out all the bits
435  println!("Got trig settings {}", trig_settings);
436  trig_settings = trig_settings & 0xffffff00;
437  println!("Got trig settings {}", trig_settings);
438  trig_settings = trig_settings | thresh as u32;
439  println!("Got trig settings {}", trig_settings);
440  let dbg = trig_settings & 0x000000ff;
441  println!("The threshold is set to {}", dbg);
442  bus.write(0x16, trig_settings)?;
443  Ok(())
444}
445
446pub fn set_cortina_threshold(bus : &mut IPBus, thresh : u8)
447  -> Result<(), Box<dyn Error>> {
448  info!("Setting cortina threshold {}!", thresh);
449  let mut trig_settings = bus.read(0x16)?;
450  trig_settings = trig_settings & 0xff00ffff;
451  trig_settings = trig_settings | ((thresh as u32) << 16);
452  bus.write(0x16, trig_settings)?;
453  Ok(())
454}
455
456pub fn set_umbcenter_threshold(bus : &mut IPBus, thresh : u8)
457  -> Result<(), Box<dyn Error>> {
458  info!("Setting Umbrella center threshold {}!", thresh);
459  let mut trig_settings = bus.read(0x16)?;
460  trig_settings = trig_settings & 0xffff00ff;
461  trig_settings = trig_settings | ((thresh as u32) << 8);
462  bus.write(0x16, trig_settings)?;
463  Ok(())
464}
465
466
467/// 1 Hit on Umbrella && 1 Hit on Cube
468pub fn set_umbcube_trigger(bus : &mut IPBus) 
469  ->Result<(), Box<dyn Error>> {
470  zero_config_trigger_thresholds(bus)?;
471  // now set the deired thresholds,
472  // because we zero'd out everything, 
473  // we just need to enable here.
474  set_configurable_trigger(bus,true)?;
475  set_umbrella_threshold(bus,1)?;
476  set_inner_tof_threshold(bus,1)?;
477  Ok(())
478}
479
480/// 1 Hit on Umbrella + 1 Hit on cube top
481pub fn set_umbcubez_trigger(bus : &mut IPBus) 
482  ->Result<(), Box<dyn Error>> {
483  zero_config_trigger_thresholds(bus)?;
484  set_configurable_trigger(bus,true)?;
485  set_umbrella_threshold(bus,1)?;
486  set_cube_top_threshold(bus,1)?;
487  Ok(())
488}
489
490/// 1 Hit on Umbrella && 1 Hit on Cortina && 1 Hit on Cube
491pub fn set_umbcorcube_trigger(bus : &mut IPBus) 
492  ->Result<(), Box<dyn Error>> {
493  zero_config_trigger_thresholds(bus)?;
494  set_configurable_trigger(bus,true)?;
495  set_umbrella_threshold(bus,1)?;
496  set_cortina_threshold(bus, 1)?;
497  set_inner_tof_threshold(bus, 1)?;
498  Ok(())
499}
500
501/// 1 Hit in Cortina && 1 Hit in Cube side
502pub fn set_corcubeside_trigger(bus : &mut IPBus) 
503  ->Result<(), Box<dyn Error>> {
504  zero_config_trigger_thresholds(bus)?;
505  set_configurable_trigger(bus,true)?;
506  set_cortina_threshold(bus,1)?;
507  set_cube_side_threshold(bus,1)?;
508  Ok(())
509}
510
511/// 1 Hit in Umbrella && 3 Hits in Cube
512pub fn set_umb3cube_trigger(bus : &mut IPBus) 
513  ->Result<(), Box<dyn Error>> {
514  set_configurable_trigger(bus,true)?;
515  zero_config_trigger_thresholds(bus)?;
516  set_umbrella_threshold(bus,1)?;
517  set_inner_tof_threshold(bus,3)?;
518  Ok(())
519}
520
521/// Zero out the configurable trigger thresholds
522pub fn zero_config_trigger_thresholds(bus : &mut IPBus)
523  ->Result<() ,Box<dyn Error>> {
524  INNER_TOF_THRESH.set(bus,0)?;
525  OUTER_TOF_THRESH.set(bus,0)?;
526  TOTAL_TOF_THRESH.set(bus,0)?;
527  CUBE_SIDE_THRESH.set(bus,0)?; 	
528  CUBE_TOP_THRESH.set(bus, 0)?; 	
529  CUBE_BOT_THRESH.set(bus, 0)?; 	
530  CUBE_CORNER_THRESH.set(bus, 0)?; 	
531  UMBRELLA_THRESH.set(bus, 0)?; 	
532  UMBRELLA_CENTER_THRESH.set(bus, 0)?;
533  Ok(())
534}
535
536/// Force a single trigger (just once)
537pub fn force_trigger(bus : &mut IPBus)
538  -> Result<(), Box<dyn Error>> {
539  //println!("==> Generating trigger!");
540  bus.write(0x8, 0x1)?;
541  Ok(())
542}
543
544pub fn use_tiu_aux_link(bus :&mut IPBus, use_it : bool) 
545  -> Result<(), Box<dyn Error>> {
546  if use_it {
547    TIU_USE_AUX_LINK.set(bus, 1)?;
548  } else {
549    TIU_USE_AUX_LINK.set(bus, 0)?;
550  }
551  Ok(())
552}
553
554
555pub fn set_fire_bits(bus : &mut IPBus, channel : u8)
556  -> Result<(), Box<dyn Error>> {
557  if channel < 25 {
558    let mut ch = channel as u32;
559    ch = ch << channel;
560    bus.write(0x101,ch)?;
561  } else if channel < 50 {
562    let mut ch = channel as u32 - 25;
563    ch = ch << channel;
564    bus.write(0x102,ch)?;
565  } else if channel < 75 {
566    let mut ch = channel as u32 - 50;
567    ch = ch << channel;
568    bus.write(0x103,ch)?;
569  } else if channel < 100 {
570    let mut ch = channel as u32 - 75;
571    ch = ch << channel;
572    bus.write(0x104,ch)?;
573  } else if channel < 125 {
574    let mut ch = channel as u32 - 100;
575    ch = ch << channel;
576    bus.write(0x105,ch)?;
577  } else if channel < 150 {
578    let mut ch = channel as u32 - 125;
579    ch = ch << channel;
580    bus.write(0x106,ch)?;
581  } else if channel < 175 {
582    let mut ch = channel as u32 - 150;
583    ch = ch << channel;
584    bus.write(0x107,ch)?;
585  } else if channel < 200 {
586    let mut ch = channel as u32 - 175;
587    ch = ch << channel;
588    bus.write(0x107,ch)?;
589  }
590  Ok(())
591}
592
593pub fn fire_ltb(bus : &mut IPBus)
594  -> Result<(), Box<dyn Error>> {
595  bus.write(0x100,0x1)?;
596  Ok(())
597}
598