1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103

use apigpio::*;
use apigpio::Level::*;
use tokio::time::{delay_for,Duration};
use tokio::{select,task};
use picollar::ledpins::{RGB,FLASH_SPECIAL,FLASH_NORMAL};
use picollar::local::{SEVERITIES,BUTTON_DEBOUNCE};
use std::result;
use anyhow::anyhow;
use std::fs::File;
use std::io::{BufWriter,Write};

fn level2rppal(l : Level) -> rppal::gpio::Level {
  if l==H { rppal::gpio::Level::High } else { rppal::gpio::Level::Low }
}

type Rppal = rppal::gpio::Gpio;

const PIN_SETTLE_DELAY : Duration = BUTTON_DEBOUNCE;

async fn read_initial(gpio : &Rppal) -> result::Result<bool, anyhow::Error> {
  let filename = std::env::args().nth(2)
    .ok_or_else(|| anyhow!("missing argument for initial pins path"))?;

  let pins : result::Result<Vec<_>, anyhow::Error> =
    SEVERITIES.iter().map(|s| s.0).flatten()
    .map(|&p| {
      let mut g = gpio
        .get(p as u8)
        .expect("get initial pin")
        .into_input_pullup();
      g.set_reset_on_drop(false);
      Ok((p, g))
    }).collect();
  let pins = pins?;

  delay_for(PIN_SETTLE_DELAY).await;

  let mut o = BufWriter::new(File::create(filename)?);

  let mut special = false;
  for (p, g) in &pins {
    let l = g.is_high();
    writeln!(o,"{} = {}", p, l as u8)?;
    if !l { special = true }
  }
  o.into_inner()?;

  Ok(special)
}

#[tokio::main]
async fn main(){
  println!("bootup: hello world"); 

  let pipepath = std::env::args().nth(1).expect("need pipe path argument");
  assert!(!pipepath.starts_with("-"));

  let mut lev = H;
  let gpio = Rppal::new().expect("rpal open");
  let mut pins : Vec<_> = RGB.iter().map(|&p| {
    let mut g = gpio
      .get(p as u8)
      .expect("get pin")
      .into_output();
    g.set_reset_on_drop(false);
    g
  }).collect();

  let openpipe = task::spawn_blocking(||{ File::create(pipepath) });
  pin_utils::pin_mut!(openpipe);

  let initial_special = read_initial(&gpio).await.or_else(|e|{
    println!("bootup: warning: could not read initial severities: {}", e);
    <result::Result<bool,()>>::Ok(false)
  }).unwrap();
  let flash_duration =
    if initial_special { FLASH_SPECIAL }
    else { FLASH_NORMAL };

  println!("bootup: in progress");

  pins[2].write(rppal::gpio::Level::Low);
  select! {
    _ = async {
      loop {
        /* flashing yellow */
        pins[0].write(level2rppal(lev));
        pins[1].write(level2rppal(lev));
        lev = !lev;
        delay_for(flash_duration).await;
      }
    } => panic!(),
    f = openpipe => {
      f.expect("open pipe task").expect("open pipe");
    }
  }
  println!("bootup: initial phase complete");

  /* set LED to red */
  pins[0].write(level2rppal(H));
  pins[1].write(level2rppal(L));
}