async fn flash_firmware(api: &Api, addr: String, path: String, url: String) -> Result<()> {
    //  For Raspberry Pi:
    //  cd $HOME/pinetime-updater
    //  openocd-spi/bin/openocd \
    //    -c ' set filename "firmware.bin" ' \
    //    -c ' set address  "0x0" ' \
    //    -f scripts/swd-pi.ocd \
    //    -f scripts/flash-log.ocd
    #[cfg(target_arch = "arm")]  //  For Raspberry Pi
    let updater_path = "/pinetime-updater";

    //  For Mac with ST-Link:
    //  cd $HOME/pinetime/pinetime-updater
    //  xpack-openocd/bin/openocd \
    //    -c ' set filename "firmware.bin" ' \
    //    -c ' set address  "0x0" ' \
    //    -f scripts/swd-stlink.ocd \
    //    -f scripts/flash-log.ocd
    #[cfg(target_arch = "x86_64")]  //  For Mac with ST-Link
    let updater_path = "/pinetime/pinetime-updater";

    //  Get the path of PineTime Updater. Remember to run "./run.sh" to download xPack OpenOCD or OpenOCD SPI
    let updater_path = env::var("HOME").expect("HOME not set") + &updater_path;

    //  Spawn OpenOCD as a background process
    let mut cmd = Command
        //  ::new(updater_path.clone() + "/openocd-spi/bin/openocd");  //  Raspberry Pi SPI
        ::new(updater_path.clone() + "/xpack-openocd/bin/openocd");    //  ST-Link
    let cmd = cmd
        .current_dir(updater_path)
        .arg("-c")
        .arg("set filename \"".to_string() + &path + "\"")
        .arg("-c")
        .arg("set address \"".to_string() + &addr + "\"")
        .arg("-f")
        //  .arg("scripts/swd-pi.ocd")  //  Raspberry Pi SPI
        .arg("scripts/swd-stlink.ocd")  //  ST-Link
        .arg("-f")
        .arg("scripts/flash-log.ocd");

    //  let mut cmd = Command::new("cargo");
    //  let cmd = cmd.arg("test").arg("--").arg("--nocapture");
    //  let mut cmd = Command::new("bash");
    //  let cmd = cmd.arg(script);

    //  Specify that we want the command's standard output and standard error piped back to us.
    //  By default, standard input/output/error will be inherited from the current process 
    //  (for example, this means that standard input will come from the keyboard and 
    //  standard output/error will go directly to the terminal if this process is invoked from the command line).
    cmd.stderr(Stdio::piped());
    //  cmd.stdout(Stdio::piped());

    let mut child = cmd.spawn()
        .expect("failed to spawn command");

    let stderr = child.stderr.take()
        .expect("child did not have a handle to stderr");
    //  let stdout = child.stdout.take()
    //      .expect("child did not have a handle to stdout");

    //  TODO: In case of error, return the error log

    //  In the background, read the OpenOCD output line by line
    let mut reader = BufReader::new(stderr).lines();
    //  let mut reader = BufReader::new(stdout).lines();

    // Ensure the child process is spawned in the runtime so it can
    // make progress on its own while we await for any output.
    tokio::spawn(async {
        let status = child.await
            .expect("child process encountered an error");

        println!("child status was: {}", status);
    });

    //  Specify Telegram Channel to transmit OpenOCD output
    let channel = Channel {
        id:             ChannelId::new(-1001221686801), 
        title:          "Remote PineTime Log".to_string(), 
        username:       Some( "remotepinetimelog".to_string() ), 
        invite_link:    None
    };
    api.send(
        SendMessage::new(
            channel.clone(), 
            format!(
                "*** Flashing {} to PineTime at address {}...",
                url, addr
            )
        )
    )    
    .await ? ;

    //  Transmit each line of OpenOCD output to the Telegram Channel
    let mut start = Instant::now();
    let mut buf = "".to_string();
    while let Some(line) = reader.next_line().await? {
        if line.len() == 0 { continue }
        println!("Line: {}", line);
        buf.push_str(&line); buf.push_str("\n");

        //  Transmit in 5-second intervals, because Telegram server would return "Too Many Requests" error
        if start.elapsed() >= Duration::from_secs(5) ||
            line.contains("***") {  //  Also transmit messages like "*** Done"
            api.send(
                SendMessage::new(
                    channel.clone(), 
                    buf
                )
            )    
            .await ? ;    
            start = Instant::now();
            buf = "".to_string();
        }
    }

    //  Transmit remaining output
    if buf.len() > 0 {
        api.send(
            SendMessage::new(channel.clone(), 
            buf)
        )
        .await ? ;
    }

    //  TODO: Wait for "*** Done" and return the message, while continuing OpenOCD output processing in the background
    //  See https://rust-lang-nursery.github.io/rust-cookbook/concurrency/threads.html#maintain-global-mutable-state
    Ok(())
}
/// Spawn OpenOCD to flash the downloaded firmware to PineTime at the address.
/// Transmit the Semihosting Log from OpenOCD to Telegram Channel. Based on https://docs.rs/tokio/0.2.22/tokio/process/index.html
Spawn OpenOCD to flash the downloaded firmware to PineTime at the address.
Transmit the Semihosting Log from OpenOCD to Telegram Channel.
Spawn OpenOCD to flash the downloaded firmware to PineTime at the address . Transmit the Semihosting Log from OpenOCD to Telegram Channel .
async fn flash_firmware(api: &Api, addr: String, path: String, url: String) -> Result<()> {
    //  For Raspberry Pi:
    //  cd $HOME/pinetime-updater
    //  openocd-spi/bin/openocd \
    //    -c ' set filename "firmware.bin" ' \
    //    -c ' set address  "0x0" ' \
    //    -f scripts/swd-pi.ocd \
    //    -f scripts/flash-log.ocd
    #[cfg(target_arch = "arm")]  //  For Raspberry Pi
    let updater_path = "/pinetime-updater";
    //  For Mac with ST-Link:
    //  cd $HOME/pinetime/pinetime-updater
    //  xpack-openocd/bin/openocd \
    //    -c ' set filename "firmware.bin" ' \
    //    -c ' set address  "0x0" ' \
    //    -f scripts/swd-stlink.ocd \
    //    -f scripts/flash-log.ocd
    #[cfg(target_arch = "x86_64")]  //  For Mac with ST-Link
    let updater_path = "/pinetime/pinetime-updater";
    //  Get the path of PineTime Updater. Remember to run "./run.sh" to download xPack OpenOCD or OpenOCD SPI
    let updater_path = env::var("HOME").expect("HOME not set") + &updater_path;
    //  Spawn OpenOCD as a background process
    let mut cmd = Command
        //  ::new(updater_path.clone() + "/openocd-spi/bin/openocd");  //  Raspberry Pi SPI
        ::new(updater_path.clone() + "/xpack-openocd/bin/openocd");    //  ST-Link
    let cmd = cmd
        .current_dir(updater_path)
        .arg("-c")
        .arg("set filename \"".to_string() + &path + "\"")
        .arg("-c")
        .arg("set address \"".to_string() + &addr + "\"")
        .arg("-f")
        //  .arg("scripts/swd-pi.ocd")  //  Raspberry Pi SPI
        .arg("scripts/swd-stlink.ocd")  //  ST-Link
        .arg("-f")
        .arg("scripts/flash-log.ocd");
    //  let mut cmd = Command::new("cargo");
    //  let cmd = cmd.arg("test").arg("--").arg("--nocapture");
    //  let mut cmd = Command::new("bash");
    //  let cmd = cmd.arg(script);
    //  Specify that we want the command's standard output and standard error piped back to us.
    //  By default, standard input/output/error will be inherited from the current process 
    //  (for example, this means that standard input will come from the keyboard and 
    //  standard output/error will go directly to the terminal if this process is invoked from the command line).
    cmd.stderr(Stdio::piped());
    //  cmd.stdout(Stdio::piped());
    let mut child = cmd.spawn()
        .expect("failed to spawn command");
    let stderr = child.stderr.take()
        .expect("child did not have a handle to stderr");
    //  let stdout = child.stdout.take()
    //      .expect("child did not have a handle to stdout");
    //  TODO: In case of error, return the error log
    //  In the background, read the OpenOCD output line by line
    let mut reader = BufReader::new(stderr).lines();
    //  let mut reader = BufReader::new(stdout).lines();
    // Ensure the child process is spawned in the runtime so it can
    // make progress on its own while we await for any output.
    tokio::spawn(async {
        let status = child.await
            .expect("child process encountered an error");
        println!("child status was: {}", status);
    });
    //  Specify Telegram Channel to transmit OpenOCD output
    let channel = Channel {
        id:             ChannelId::new(-1001221686801), 
        title:          "Remote PineTime Log".to_string(), 
        username:       Some( "remotepinetimelog".to_string() ), 
        invite_link:    None
    };
    api.send(
        SendMessage::new(
            channel.clone(), 
            format!(
                "*** Flashing {} to PineTime at address {}...",
                url, addr
            )
        )
    )    
    .await ? ;
    //  Transmit each line of OpenOCD output to the Telegram Channel
    let mut start = Instant::now();
    let mut buf = "".to_string();
    while let Some(line) = reader.next_line().await? {
        if line.len() == 0 { continue }
        println!("Line: {}", line);
        buf.push_str(&line); buf.push_str("\n");
        //  Transmit in 5-second intervals, because Telegram server would return "Too Many Requests" error
        if start.elapsed() >= Duration::from_secs(5) ||
            line.contains("***") {  //  Also transmit messages like "*** Done"
            api.send(
                SendMessage::new(
                    channel.clone(), 
                    buf
                )
            )    
            .await ? ;    
            start = Instant::now();
            buf = "".to_string();
        }
    }
    //  Transmit remaining output
    if buf.len() > 0 {
        api.send(
            SendMessage::new(channel.clone(), 
            buf)
        )
        .await ? ;
    }
    //  TODO: Wait for "*** Done" and return the message, while continuing OpenOCD output processing in the background
    //  See https://rust-lang-nursery.github.io/rust-cookbook/concurrency/threads.html#maintain-global-mutable-state
    Ok(())
}
async fn flash_firmware ( api : & Api , addr : String , path : String , url : String ) -> Result < ( ) > { //  For Raspberry Pi: //  cd $HOME/pinetime-updater //  openocd-spi/bin/openocd \ //    -c ' set filename "firmware.bin" ' \ //    -c ' set address  "0x0" ' \ //    -f scripts/swd-pi.ocd \ //    -f scripts/flash-log.ocd # [ cfg ( target_arch " " ) ] //  For Raspberry Pi let updater_path = " " ; //  For Mac with ST-Link: //  cd $HOME/pinetime/pinetime-updater //  xpack-openocd/bin/openocd \ //    -c ' set filename "firmware.bin" ' \ //    -c ' set address  "0x0" ' \ //    -f scripts/swd-stlink.ocd \ //    -f scripts/flash-log.ocd # [ cfg ( target_arch " " ) ] //  For Mac with ST-Link let updater_path = " " ; //  Get the path of PineTime Updater. Remember to run "./run.sh" to download xPack OpenOCD or OpenOCD SPI let updater_path = env :: var ( " " ) . expect ( " " ) + & updater_path ; //  Spawn OpenOCD as a background process let mut cmd = Command //  ::new(updater_path.clone() + "/openocd-spi/bin/openocd");  //  Raspberry Pi SPI :: new ( updater_path . clone ( ) + " " ) ; //  ST-Link let cmd = cmd . current_dir ( updater_path ) . arg ( " " ) . arg ( " \" " . to_string ( ) + & path + " \" " ) . arg ( " " ) . arg ( " \" " . to_string ( ) + & addr + " \" " ) . arg ( " " ) //  .arg("scripts/swd-pi.ocd")  //  Raspberry Pi SPI . arg ( " " ) //  ST-Link . arg ( " " ) . arg ( " " ) ; //  let mut cmd = Command::new("cargo"); //  let cmd = cmd.arg("test").arg("--").arg("--nocapture"); //  let mut cmd = Command::new("bash"); //  let cmd = cmd.arg(script); //  Specify that we want the command's standard output and standard error piped back to us. //  By default, standard input/output/error will be inherited from the current process  //  (for example, this means that standard input will come from the keyboard and  //  standard output/error will go directly to the terminal if this process is invoked from the command line). cmd . stderr ( Stdio :: piped ( ) ) ; //  cmd.stdout(Stdio::piped()); let mut child = cmd . spawn ( ) . expect ( " " ) ; let stderr = child . stderr . take ( ) . expect ( " " ) ; //  let stdout = child.stdout.take() //      .expect("child did not have a handle to stdout"); //  TODO: In case of error, return the error log //  In the background, read the OpenOCD output line by line let mut reader = BufReader :: new ( stderr ) . lines ( ) ; //  let mut reader = BufReader::new(stdout).lines(); // Ensure the child process is spawned in the runtime so it can // make progress on its own while we await for any output. tokio :: spawn ( async { let status = child . await . expect ( " " ) ; println ! ( " " status ) ; } ) ; //  Specify Telegram Channel to transmit OpenOCD output let channel = Channel { id : ChannelId :: new ( - 1001221686801 ) , title : " " . to_string ( ) , username : Some ( " " . to_string ( ) ) , invite_link : None } ; api . send ( SendMessage :: new ( channel . clone ( ) , format ! ( " " url addr ) ) ) . await ? ; //  Transmit each line of OpenOCD output to the Telegram Channel let mut start = Instant :: now ( ) ; let mut buf = " " . to_string ( ) ; while let Some ( line ) = reader . next_line ( ) . await ? { if line . len ( ) == 0 { continue } println ! ( " " line ) ; buf . push_str ( & line ) ; buf . push_str ( " \n " ) ; //  Transmit in 5-second intervals, because Telegram server would return "Too Many Requests" error if start . elapsed ( ) >= Duration :: from_secs ( 5 ) || line . contains ( " " ) { //  Also transmit messages like "*** Done" api . send ( SendMessage :: new ( channel . clone ( ) , buf ) ) . await ? ; start = Instant :: now ( ) ; buf = " " . to_string ( ) ; } } //  Transmit remaining output if buf . len ( ) > 0 { api . send ( SendMessage :: new ( channel . clone ( ) , buf ) ) . await ? ; } //  TODO: Wait for "*** Done" and return the message, while continuing OpenOCD output processing in the background //  See https://rust-lang-nursery.github.io/rust-cookbook/concurrency/threads.html#maintain-global-mutable-state Ok ( ( ) ) }
Spawn OpenOCD to flash the downloaded firmware to PineTime at the address.
Spawn OpenOCD to flash the downloaded firmware to PineTime at the address .
api
&Api
addr
String
path
String
url
String
api
&Api
addr
String
path
String
url
String