/*
 * Copyright (c) 2016 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <stdio.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/sensor.h>
#include "max30001.h"
#include <zephyr/logging/log.h>

#define LOG_MODULE_NAME app
LOG_MODULE_REGISTER(LOG_MODULE_NAME);

/* 1000 msec = 1 sec */
#define SLEEP_TIME_MS   2000

/* The devicetree node identifier for the "led0" alias. */
#define LED0_NODE DT_ALIAS(led0)

/*
 * A build error on this line means your board is unsupported.
 * See the sample documentation for information on how to fix this.
 */
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);


#define THREAD_STACKSIZE        1024
#define THREAD_PRIORITY         7

K_THREAD_STACK_DEFINE(sensor_thread_stack, THREAD_STACKSIZE);
static struct k_thread sensor_thread;
K_MUTEX_DEFINE(sensor_mutex);
static int32_t sensor_value;

static void thread_entry(void *p1, void *p2, void *p3)
{
	int ret;
	struct sensor_value my_sensor_value;

	const struct device *dev = (const struct device *)p1;
	struct k_mutex *temp_mutex = (struct k_mutex *)p2;
	int32_t *temp = (int32_t *)p3;

	while (1) {
        LOG_INF("Attempting to fetch sample...");
		ret = sensor_sample_fetch(dev); // Try to get data

		if (ret != 0) {
			// Fetch failed, print error and DO NOT blink
			LOG_INF("sensor_sample_fetch FAILED (ret %d). Check wiring.\n", ret);
		} else {
			// Fetch was OK! Now get the channel data.
    		ret = sensor_channel_get(dev, SENSOR_CHAN_ECG_UV, &my_sensor_value);
    		if (ret != 0) {
    			LOG_INF("sensor_channel_get failed ret %d\n", ret);
    		} else {
                // SUCCESS! We got a value.
        		LOG_INF("Fetch SUCCESS! Toggling LED.");
				
				// 1. Update the global value
				if (k_mutex_lock(temp_mutex, K_MSEC(2000)) == 0) {
        			*temp = my_sensor_value.val1;
        			k_mutex_unlock(temp_mutex);
        		} else {
        			LOG_INF("Unable to lock mutex\n");
        		}
                
                // 2. Toggle the LED to signal success
                gpio_pin_toggle_dt(&led);
            }
        }
        
		// Wait 2 seconds before trying again
		k_sleep(K_MSEC(2000));
	}
}

void sensor_init(void)
{
	const struct device *dev = DEVICE_DT_GET(DT_NODELABEL(max30001));	    
    __ASSERT(dev != NULL, "Failed to get device binding");
	__ASSERT(device_is_ready(dev), "Device %s is not ready", dev->name);
	printk("device is %p, name is %s\n", dev, dev->name);
	
    k_thread_create(&sensor_thread, sensor_thread_stack,
			K_THREAD_STACK_SIZEOF(sensor_thread_stack),
			thread_entry, (void *)dev, (void *)&sensor_mutex, (void*)&sensor_value,
			THREAD_PRIORITY, 0, K_FOREVER);
	k_thread_start(&sensor_thread);
}

int32_t value_get(void)
{
	int32_t val = 0;

	if (k_mutex_lock(&sensor_mutex, K_MSEC(100)) == 0) {
		val = sensor_value;
		k_mutex_unlock(&sensor_mutex);
	}

	return val;
}

int main(void)
{
	int ret;
    int32_t current_sensor_value;
    sensor_init(); // This starts the sensor thread

	if (!gpio_is_ready_dt(&led)) {
		return 0;
	}

	ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
	if (ret < 0) {
		return 0;
	}

    // Set the LED to OFF at the start.
	// It will only turn on if the sensor thread is successful.
    gpio_pin_set_dt(&led, 0); 
	LOG_INF("LED set to OFF. Waiting for successful sensor read...");

	while (1) {
        // The main loop will now just print the sensor value
        current_sensor_value = value_get();
        LOG_INF("Current sensor value = %d", current_sensor_value);
		k_msleep(SLEEP_TIME_MS);
	}
	return 0;
}