/*
 * Copyright (c) 2016 Intel Corporation.
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 */

#include <zephyr/zephyr.h>
#include <zephyr/sys/printk.h>
#include <zephyr/usb/usb_device.h>
#include <zephyr/drivers/uart.h>

#include <logging/log.h>
#include <zephyr/drivers/gpio.h>

#include "remote.h" //floder tự thêm vào

BUILD_ASSERT(DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_console), zephyr_cdc_acm_uart),
	     "Console device is not ACM CDC UART device");

#define LED0_NODE 	DT_ALIAS(led0)
#define SW0_NODE	DT_ALIAS(sw0)

static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
static const struct gpio_dt_spec led1_blue = GPIO_DT_SPEC_GET_OR(DT_ALIAS(led3), gpios, {0});

static const struct gpio_dt_spec button = GPIO_DT_SPEC_GET_OR(SW0_NODE, gpios, {0});
// static struct gpio_dt_spec button = GPIO_DT_SPEC_GET(DT_ALIAS(sw0), gpios); //OK
// static struct gpio_dt_spec button = GPIO_DT_SPEC_GET(DT_NODELABEL(button0), gpios); //OK

//nếu có 2 nút bấm, thì cần 2 gpio_callback
static struct gpio_callback button_cb_data;

uint8_t btn_count=0;
#define LOG_MODULE_NAME app
LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_DBG); //không chỉ thị LEVEL nên CONFIG_LOG_DEFAULT_LEVEL=3

struct bt_conn *current_conn;

void on_connected(struct bt_conn *conn, uint8_t err);
void on_disconnected(struct bt_conn *conn, uint8_t reason);
void on_notif_changed(enum bt_button_notifications_enabled status);
void on_data_received(struct bt_conn *conn, const uint8_t *const data, uint16_t len);

struct bt_conn_cb bluetooth_callbacks = {
	.connected		    = on_connected,
	.disconnected   	= on_disconnected,
	// .le_param_req		= le_param_req,
	// .le_param_updated	= le_param_updated
};

struct bt_remote_service_cb remote_callbacks = {
	// gán hàm on_notif_changed vào function poiter void (*notif_changed)
	.notif_changed = on_notif_changed,
	.data_received = on_data_received,
};

void on_connected(struct bt_conn *conn, uint8_t err){
	struct bt_conn_info info;

	if(err){
		LOG_INF("connection err %d", err);
		return;
	}

	LOG_INF("Connected OK");
	current_conn = bt_conn_ref(conn);
	// gpio_pin_set_dt(&led, 1); //on led
	gpio_pin_set(led.port, led.pin, 1); //OK
}

void on_disconnected (struct bt_conn *conn, uint8_t reason){
	LOG_INF("On disconnected, reason %d", reason);
	if (current_conn){
		bt_conn_unref(current_conn);
		current_conn = NULL; // cho bằng NULL để clear các thiết bị đã kết nối ???!!
	}
	gpio_pin_set_dt(&led, 0); //off led
}

void on_notif_changed(enum bt_button_notifications_enabled status){
	if (status == BT_BUTTON_NOTIFICATIONS_ENABLED){
		LOG_INF("Notification enabled");
	} else {
		LOG_INF("Notifications disable");
	}
}

void on_data_received(struct bt_conn *conn, const uint8_t *const data, uint16_t len)
{
	uint8_t temp_str[len+1];
	memcpy(temp_str, data, len);
	temp_str[len] = 0x00;

	LOG_INF("Received data on conn %p. Len: %d", (void *)conn, len);
	LOG_INF("Data: %s", temp_str);
}

void button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins) {
	int err=0;
	uint32_t bit_to_pin = 0;
	//thực hiện nhiều button
	for (int i = 0; i < 32; i++) {
		if ((pins >> i) == 1) {
			bit_to_pin = i;
			break;
		}
	}

	gpio_pin_toggle(led.port, led.pin); //OK
	btn_count++;
	LOG_INF("Button %d pressed %d", bit_to_pin, btn_count);
	set_button_value(btn_count);

	err = send_button_notification(current_conn, btn_count, 1);
	if (err){
		LOG_ERR("couldn't send notification, err: %d", err);
	}
}

void main(void)
{
	int ret, err;
	if (!device_is_ready(led.port)) return;
	if (!device_is_ready(led1_blue.port)) {
		return;
	}
	ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_INACTIVE); //init low
	if (ret < 0) return;
	gpio_pin_configure_dt(&led1_blue, GPIO_OUTPUT);

	/* USB CDC ACM */
	const struct device *dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_console));
	uint32_t dtr = 0;
	if (usb_enable(NULL)) {
		return;
	}
	/* Poll if the DTR flag was set, chỗ này sẽ đợi mở terminal mới thực hiện tiếp */
	while (!dtr) {
		uart_line_ctrl_get(dev, UART_LINE_CTRL_DTR, &dtr);
		/* Give CPU resources to low priority threads. */
		k_sleep(K_MSEC(100));
	}
	/*************** hết CDC ACM ***************/

	LOG_INF("Hello CDC ACM BLE from: %s\n", CONFIG_BOARD);

	/* cấu hình button là input cb */
	if (!device_is_ready(button.port)) {
		LOG_ERR("Error: button device %s is not ready\n",
		       button.port->name);
		k_sleep(K_MSEC(5000));
		return;
	}
	ret = gpio_pin_configure_dt(&button, GPIO_INPUT | GPIO_PULL_UP);
	ret = gpio_pin_interrupt_configure_dt(&button, GPIO_INT_EDGE_RISING);
	gpio_init_callback(&button_cb_data, button_pressed, BIT(button.pin)); //đưa hàm ngắt button_pressed vào stuct của ngắt
	gpio_add_callback(button.port, &button_cb_data); //đưa struct ngắt vào vector ngắt

	err = bluetooth_init(&bluetooth_callbacks, &remote_callbacks);
	if (err){
		LOG_ERR("Bluetooth returned %d", err);
	}

	LOG_INF("RUNNING");

	while (1) {
		// printk("Hello World! %s\n", CONFIG_ARCH);
		k_sleep(K_SECONDS(1));
		// k_sleep(K_MSEC(300));
		// btn_count++;
		// send_button_notification(current_conn, btn_count, 1);

		// ret = gpio_pin_toggle_dt(&led);
		gpio_pin_toggle_dt(&led1_blue);
	}
}
