/*
 * SPDX-FileCopyrightText: Copyright (C) Frickly Systems GmbH
 * SPDX-FileCopyrightText: Copyright (C) MBition GmbH
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/*
 * Copyright (c) 2020 Libre Solar Technologies GmbH
 *
 * Copyright (C) MBition GmbH
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <inttypes.h>
#include <stddef.h>
#include <stdint.h>

#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/adc.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/util.h>

#if !DT_NODE_EXISTS(DT_PATH(zephyr_user)) || \
    !DT_NODE_HAS_PROP(DT_PATH(zephyr_user), io_channels)
#error "No suitable devicetree overlay specified"
#endif

#define DT_SPEC_AND_COMMA(node_id, prop, idx) \
  ADC_DT_SPEC_GET_BY_IDX(node_id, idx),

/* Data of ADC io-channels specified in devicetree. */
static const struct adc_dt_spec adc_channels[] = {
  DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), io_channels, DT_SPEC_AND_COMMA)};

static const struct device* vref = DEVICE_DT_GET(DT_ALIAS(volt_sensor0));

int main(void) {
  int err;
  uint32_t count = 0;
  uint16_t buf;
  struct adc_sequence sequence = {
    .buffer = &buf,
    /* buffer size in bytes, not number of samples */
    .buffer_size = sizeof(buf),
  };

  /* Configure channels individually prior to sampling. */
  for (size_t i = 0U; i < ARRAY_SIZE(adc_channels); i++) {
    if (!adc_is_ready_dt(&adc_channels[i])) {
      printk("ADC controller device %s not ready\n", adc_channels[i].dev->name);
      return 0;
    }

    err = adc_channel_setup_dt(&adc_channels[i]);
    if (err < 0) {
      printk("Could not setup channel #%d (%d)\n", i, err);
      return 0;
    }
  }

  if (!device_is_ready(vref)) {
    printk("VREF device not ready\n");
    return 0;
  }

  while (1) {
    printk("ADC reading[%u]:\n", count++);
    for (size_t i = 0U; i < ARRAY_SIZE(adc_channels); i++) {
      int32_t val_mv;

      printk("- %s, channel %d: ", adc_channels[i].dev->name,
             adc_channels[i].channel_id);

      (void)adc_sequence_init_dt(&adc_channels[i], &sequence);

      err = adc_read_dt(&adc_channels[i], &sequence);
      if (err < 0) {
        printk("Could not read (%d)\n", err);
        continue;
      }

      /*
       * If using differential mode, the 16 bit value
       * in the ADC sample buffer should be a signed 2's
       * complement value.
       */
      if (adc_channels[i].channel_cfg.differential) {
        val_mv = (int32_t)((int16_t)buf);
      } else {
        val_mv = (int32_t)buf;
      }
      printk("%" PRId32, val_mv);
      err = adc_raw_to_millivolts_dt(&adc_channels[i], &val_mv);
      /* conversion to mV may not be supported, skip if not */
      if (err < 0) {
        printk(" (value in mV not available)\n");
      } else {
        printk(" = %" PRId32 " mV\n", val_mv);
      }
    }

    struct sensor_value vref_val;
    err = sensor_sample_fetch_chan(vref, SENSOR_CHAN_VOLTAGE);
    if (err < 0) {
      printk("Could not fetch vref (%d)\n", err);
      continue;
    }
    err = sensor_channel_get(vref, SENSOR_CHAN_VOLTAGE, &vref_val);
    if (err < 0) {
      printk("Could not get vref (%d)\n", err);
      continue;
    }
    printk("VREF reading: %d.%06d V\n", vref_val.val1, vref_val.val2);
    printk("\n");

    k_sleep(K_MSEC(1000));
  }
  return 0;
}
