#include <array>
#include <utility>
#include <cstddef>
#include <math.h>


// Our lookup table function. No more implementation needed!
// https://joelfilho.com/blog/2020/compile_time_lookup_tables_in_cpp/
template<std::size_t Length, typename Generator>
constexpr auto lut(Generator&& f){
    using content_type = decltype(f(std::size_t{0}));
    std::array<content_type, Length> arr {};

    for(std::size_t i = 0; i < Length; i++){
        arr[i] = f(i);
    }

    return arr;
}

//------------------------------------------------
// Usage, with inline variable templates requires C++17
//------------------------------------------------

template<signed minTemp,std::size_t Length>
inline constexpr auto thermistor_lut = lut<Length>([](std::size_t n){
    const unsigned beta = 3435;
    const unsigned R_at25C = 10000;
    const unsigned R_Pullup = 22000;
    const unsigned adcValAtPullupVoltage = 57600;

    unsigned NtcResVal = R_at25C * exp(beta*((1/(273.15+n+minTemp)) - (1/298.15)));
    unsigned AdcValAtnTempC = (NtcResVal*adcValAtPullupVoltage)/(NtcResVal+R_Pullup);

    return AdcValAtnTempC;
});


void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);

}

void loop() {
  delay(10); // this speeds up the simulation
  
  const signed minTemp = -20;
  auto my_lut = thermistor_lut<minTemp, 120>;
  int32_t baseTemp, fineTemp = 0;
  double floatTemp = minTemp; 

  static uint64_t rawAdcCount = 30000;
  rawAdcCount++;

  auto it = std::lower_bound(my_lut.begin(), my_lut.end(), rawAdcCount, std::greater_equal());
  if(it != my_lut.begin())
  {
    baseTemp = std::distance(my_lut.begin(), (it-1)) + minTemp;
    fineTemp = (100*(*(it-1)-rawAdcCount))/(*(it-1) - *it);
    floatTemp = baseTemp + (fineTemp/100.0);
  }
  Serial.printf("Temperature is: %.2f for ADC value: %d \n", floatTemp, rawAdcCount);  
}

//See compiler output at https://godbolt.org/z/eacf9MPeY