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