/*
For a detailed explanation of this code check out the associated blog post:
https://apollolabsblog.hashnode.dev/esp32-embedded-rust-at-the-hal-analog-temperature-sensing-using-the-adc

GitHub Repo containing source code and other examples:
https://github.com/apollolabsdev

For notifications on similar examples and more, subscribe to newsletter here:
https://www.theembeddedrustacean.com/subscribe
*/

#![no_std]
#![no_main]

use esp32c3_hal::{
    adc::{AdcConfig, Attenuation, ADC},
    clock::ClockControl,
    peripherals::Peripherals,
    prelude::*,
    timer::TimerGroup,
    Rtc, IO,
};
use esp_backtrace as _;
use esp_println::println;
use libm::log;

#[entry]
fn main() -> ! {
    // Take Peripherals, Initialize Clocks, and Create a Handle for Each
    let peripherals = Peripherals::take();
    let mut system = peripherals.SYSTEM.split();
    let clocks = ClockControl::boot_defaults(system.clock_control).freeze();

    // Instantiate and Create Handles for the RTC and TIMG watchdog timers
    let mut rtc = Rtc::new(peripherals.RTC_CNTL);
    let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
    let mut wdt0 = timer_group0.wdt;
    let timer_group1 = TimerGroup::new(peripherals.TIMG1, &clocks);
    let mut wdt1 = timer_group1.wdt;

    // Disable the RTC and TIMG watchdog timers
    rtc.swd.disable();
    rtc.rwdt.disable();
    wdt0.disable();
    wdt1.disable();

    // Instantiate and Create Handle for IO
    let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);

    // Create ADC Instance
    // Create handle for ADC configuration parameters
    let mut adc_config = AdcConfig::new();
    // Configure ADC pin
    let mut adc_pin =
        adc_config.enable_pin(io.pins.gpio1.into_analog(), Attenuation::Attenuation11dB);
    // Promote ADC peripheral to HAL-level Struct
    let analog = peripherals.APB_SARADC.split();
    // Create handle for ADC, configuring clock, and passing configuration handle
    let mut adc = ADC::adc(
        &mut system.peripheral_clock_control,
        analog.adc1,
        adc_config,
    )
    .unwrap();

    const B: f64 = 3950.0; // B value of the thermistor
    const R0: f64 = 10000.0; // Nominal NTC Value

    // Algorithm
    // 1) Get adc reading
    // 2) Convert to temperature
    // 3) Send over Serial
    // 4) Go Back to step 1

    // Application
    loop {
        // Get ADC reading
        let sample: u16 = adc.read(&mut adc_pin).unwrap();
        // For blocking read
        // let sample: u16 = nb::block!(adc.read(&mut adc_pin)).unwrap();

        //Convert to temperature
        let temperature = 1. / (log(1. / (4096. / sample as f64 - 1.)) / B + 1.0 / 298.15) - 273.15;

        // Print the temperature output
        println!("Temperature {:02} Celcius\r", temperature);
    }
}