// USB_NIKKI_Sample_Code_CPP.cpp : This file contains the 'main' function. The program will begin and end execution here.
//

#include <iostream>
#include <vector>  
#include <wchar.h>   
#include "hidapi.h"
#include <iomanip>
#include <chrono>
#include <thread>
#include <cstdint>
#include <cstring>

#ifdef _WIN32
#pragma comment(lib, "hidapi.lib")
#endif
#define MAX_STR 255
hid_device* handle;
// Vendor ID
#define	VENDOR_ID			0x04D9
// Device ID
#define	DEVICE_ID			0xA31F
//Status
#define Status_Set			1
#define Status_Reset		2
#define Status_Get_Firmware 3
// Red LED Status
#define RLED_Mode0		0
#define RLED_Mode1		1
#define RLED_Mode2		2
#define RLED_Mode3		3
#define RLED_Mode4		4
#define RLED_Mode5		5
#define RLED_Mode6		6
#define RLED_Keep		7
// Yellow LED Status
#define YLED_Mode0		0
#define YLED_Mode1		1
#define YLED_Mode2		2
#define YLED_Mode3		3
#define YLED_Mode4		4
#define YLED_Mode5		5
#define YLED_Mode6		6
#define YLED_Keep		7
// Green LED Status
#define GLED_Mode0		0
#define GLED_Mode1		1
#define GLED_Mode2		2
#define GLED_Mode3		3
#define GLED_Mode4		4
#define GLED_Mode5		5
#define GLED_Mode6		6
#define GLED_Keep		7
// Blue LED Status
#define BLED_Mode0		0
#define BLED_Mode1		1
#define BLED_Mode2		2
#define BLED_Mode3		3
#define BLED_Mode4		4
#define BLED_Mode5		5
#define BLED_Mode6		6
#define BLED_Keep		7
// White LED Status
#define WLED_Mode0		0
#define WLED_Mode1		1
#define WLED_Mode2		2
#define WLED_Mode3		3
#define WLED_Mode4		4
#define WLED_Mode5		5
#define WLED_Mode6		6
#define WLED_Keep		7
// Buzzer Volume
#define Volume1			1
#define Volume2			2
#define Volume3			3
#define Volume4			4
#define Vol_Keep		5
// Buzzer Mode
#define Buz_Mode0		0
#define Buz_Mode1		1
#define Buz_Mode2		2
#define Buz_Mode3		3
#define Buz_Mode4		4
#define Buz_Mode5		5
#define Buz_Mode6		6
#define Buz_Keep		7
// Buzzer Frequency 1
#define Buz_F1_OFF		1 
#define Buz_F1_1760		2
#define Buz_F1_1864_7	3
#define Buz_F1_1975_5	4
#define Buz_F1_2093		5
#define Buz_F1_2217_5	6
#define Buz_F1_2349_3	7
#define Buz_F1_2489		8
#define Buz_F1_2637		9
#define Buz_F1_2793_8	10
#define Buz_F1_2960		11
#define Buz_F1_3136		12
#define Buz_F1_3322_4	13
#define Buz_F1_3520		14
#define Buz_F1_Keep		15
// Buzzer Frequency 2
#define Buz_F2_OFF		1
#define Buz_F2_1760		2
#define Buz_F2_1864_7	3
#define Buz_F2_1975_5	4
#define Buz_F2_2093		5
#define Buz_F2_2217_5	6
#define Buz_F2_2349_3	7
#define Buz_F2_2489		8
#define Buz_F2_2637		9
#define Buz_F2_2793_8	10
#define Buz_F2_2960		11
#define Buz_F2_3136		12
#define Buz_F2_3322_4	13
#define Buz_F2_3520		14
#define Buz_F2_Keep		15

std::vector<unsigned char> buf(9); 
wchar_t wstr[MAX_STR];
int res,set_LED,set_Buzzer,RLED,YLED,GLED,BLED,WLED,Set,Buzzer_Vol,Buzzer_Mode,Buzzer_F1,Buzzer_F2;
using BYTE = uint8_t;
using DWORD = uint32_t;


int Start_HID();
void Stop_HID();
int LED_Control(int R, int Y, int G, int B, int W);
int Led_All_Off();
int Buzzer_Control(int mode, int f1, int f2, int volume);
int Buzzer_Off();
int Reset_Device();
const char* Get_Firmware_Version(char* buffer, int buffer_size);

//main
int main()
{
	const char number = Start_HID();
	int choice;
	int end_function = 0;
	char succ;
	char fw_buffer[8] = { 0 };
	const char* version;
	std::cout << static_cast<int>(number) << std::endl;
	std::this_thread::sleep_for(std::chrono::seconds(3));
	if (number == 0)
	{
		while (true)
		{
			std::cout << "Mode Select:" << std::endl;
			std::cout << "1:LED_Control" << std::endl;
			std::cout << "2:LED_All_Off" << std::endl;
			std::cout << "3:Buzzer_Control" << std::endl;
			std::cout << "4:Buzzer_Off" << std::endl;
			std::cout << "5:Reset_device" << std::endl;
			std::cout << "6:Get_Firmware_Version" << std::endl;
			std::cout << "7:Stop_HID" << std::endl;
			std::cin >> choice;
			switch (choice)
			{
			case 1:
				succ = LED_Control(RLED_Mode1, YLED_Mode3, GLED_Mode3, BLED_Mode0, WLED_Mode4);
				std::cout << static_cast<int>(succ) << std::endl;
				break;
			case 2:
				succ = Led_All_Off();
				std::cout << static_cast<int>(succ) << std::endl;
				break;
			case 3:
				succ = Buzzer_Control(Buz_Mode2, Buz_F1_1760, Buz_F2_3520, Volume3);
				std::cout << static_cast<int>(succ) << std::endl;
				break;
			case 4:
				succ = Buzzer_Off();
				std::cout << static_cast<int>(succ) << std::endl;
				break;
			case 5:
				succ = Reset_Device();
				std::cout << static_cast<int>(succ) << std::endl;
				break;
			case 6:
				version = Get_Firmware_Version(fw_buffer, sizeof(fw_buffer));
				if (strcmp(version, "-1") == 0) {
					std::cout << "-1" << std::endl;
				}
				else {
					std::cout << "Firmware version (hex): " << std::endl;
					for (int i = 0; i < 8; i++) {
						std::cout << std::hex << std::uppercase << std::setw(2) << std::setfill('0')
							<< static_cast<int>(static_cast<unsigned char>(fw_buffer[i])) << " ";
					}
					std::cout << std::endl;
				}
				break;
			case 7:
				std::cout << "Stop_HID " << std::endl;
				Stop_HID();
				end_function = 1;
				break;
			default:
				std::cout << "錯誤參數 " << std::endl;
			}
			if (end_function)
			{
				break;
			}
		}
	}

	return 0;
}
//Enable HID Device Subroutine
int Start_HID()
{
	res = hid_init();
	if (res != 0)
	{
		std::cout << "HID init failed" << std::endl;
		return -1;
	}
	handle = hid_open(VENDOR_ID, DEVICE_ID, NULL);
	if (!handle) {
		std::cout << "Unable to open device" << std::endl;
		return -1;
	}
	return 0;
}
//Disable HID Subprogram
void Stop_HID()
{
	if (handle!=NULL)
	{
		hid_close(handle);
	}
}


//Transfer Data to Device
int Send_Data() {
	BYTE data[8] = { 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
	BYTE checksum = 0;
	data[1] += Set;	
	if (set_LED) {
		data[1] += RLED << 4;
		data[2] += YLED;
		data[2] += GLED << 4;
		data[3] += BLED;
		data[3] += WLED << 4;
		data[4] += Vol_Keep;
		data[5] += Buz_Keep;
		data[6] += Buz_F1_Keep;
		data[6] += Buz_F2_Keep << 4;
	}
	else if (set_Buzzer)
	{
		data[1] += RLED_Keep << 4;
		data[2] += YLED_Keep;
		data[2] += GLED_Keep << 4;
		data[3] += BLED_Keep;
		data[3] += WLED_Keep << 4;
		data[4] += Buzzer_Vol;
		data[5] += Buzzer_Mode;
		data[6] += Buzzer_F1;
		data[6] += Buzzer_F2 << 4;
	}
	if (Set == 2)
	{
		data[1] = Status_Reset;
		data[2] += YLED_Mode0;
		data[2] += GLED_Mode0 << 4;
		data[3] += BLED_Mode0;
		data[3] += WLED_Mode0 << 4;
		data[4] += Volume1;
		data[5] += Buz_Mode0;
		data[6] += Buz_F1_OFF;
		data[6] += Buz_F2_OFF << 4;
	}
	else if (Set == 3)
	{
		data[1] = Status_Get_Firmware;
		data[2] += YLED_Mode0;
		data[2] += GLED_Mode0 << 4;
		data[3] += BLED_Mode0;
		data[3] += WLED_Mode0 << 4;
		data[4] += Volume1;
		data[5] += Buz_Mode0;
		data[6] += Buz_F1_OFF;
		data[6] += Buz_F2_OFF << 4;
	}
	for (int i = 1; i <= 6; ++i)
	{
		checksum += data[i];
	}
	checksum &= 0xFF;
	data[7] += checksum;
	BYTE data1[9];
	data1[0] = 0x00;
	memcpy(&data1[1], data, 8);
	memcpy(buf.data(), data1, 9);
	int res = hid_write(handle, buf.data(), buf.size());
	if (res<0) {
		std::cout << "Fail to send" << std::endl;
		return -1;
	}
	return 0;
}
//Red, yellow, green, blue, and white LED control subprogram
int LED_Control(int R, int Y, int G, int B, int W) 
{
	if (R > 0xF || Y > 0xF || G > 0xF || B > 0xF || W > 0xF || R < 0 || Y < 0 || G < 0 || B < 0 || W < 0)
	{
		std::cout << "Out of range color" << std::endl;
		return -1;
	}
	RLED = R;
	YLED = Y;
	GLED = G;
	BLED = B;
	WLED = W;
	Set = Status_Set;
	set_LED = 1;
	set_Buzzer = 0;
	int succ = Send_Data();
	if (succ < 0)
	{
		return -1;
	}
	return 0;
}
//All LEDs turn off subroutine.
int Led_All_Off() 
{
	RLED = RLED_Mode0;
	YLED = YLED_Mode0;
	GLED = GLED_Mode0;
	BLED = BLED_Mode0;
	WLED = WLED_Mode0;
	Set = Status_Set;
	set_LED = 1;
	set_Buzzer = 0;
	int succ = Send_Data();
	if (succ < 0)
	{
		return -1;
	}
	return 0;
}
//Buzzer control (mode, audio 1, audio 2, volume) subroutine.
int Buzzer_Control(int mode, int f1, int f2, int volume)
{
	if (mode > 0xF || f1 > 0xE || f2 > 0xE || volume > 0xF || mode < 0 || f1 < 0 || f2 < 0 || volume < 0)
	{
		std::cout << "Out of range color" << std::endl;
		return -1;
	}
	Buzzer_Mode = mode;
	Buzzer_F1 = f1;
	Buzzer_F2 = f2;
	Buzzer_Vol = volume;
	Set = Status_Set;
	set_Buzzer = 1;
	set_LED = 0;
	int succ = Send_Data();
	if (succ < 0)
	{
		return -1;
	}
	return 0;
}
//Buzzer turn off subroutine
int Buzzer_Off() 
{
	Set = Status_Set;
	Buzzer_F1 = Buz_F1_OFF;
	Buzzer_F2 = Buz_F2_OFF;
	Buzzer_Mode = Buz_Mode0;
	Buzzer_Vol = Volume1;
	set_Buzzer = 1;
	set_LED = 0;
	int succ = Send_Data();
	if (succ < 0)
	{
		return -1;
	}
	return 0;
}
//Reset device subprogram
int Reset_Device() 
{
	
	Set = Status_Reset;
	set_Buzzer = 0;
	set_LED = 0;
	RLED = RLED_Mode0;
	YLED = YLED_Mode0;
	GLED = GLED_Mode0;
	BLED = BLED_Mode0;
	WLED = WLED_Mode0;
	Buzzer_Vol = Volume1;
	Buzzer_Mode = Buz_Mode0;
	Buzzer_F1 = Buz_F1_OFF;
	Buzzer_F2 = Buz_F2_OFF;
	int succ = Send_Data();
	if (succ < 0)
	{
		return -1;
	}
	return 0;
}
//Obtain firmware version subprogram
const char* Get_Firmware_Version(char* buffer, int buffer_size)
{
	const int read_size = 9;
	BYTE recv[read_size];
	memset(recv, 0xFF, sizeof(recv));

	Set = Status_Get_Firmware;
	set_LED = 0;
	set_Buzzer = 0;
	Send_Data();



	BYTE dummy[read_size];
	while (hid_read_timeout(handle, dummy, read_size, 0) > 0);


	int bytesRead = hid_read_timeout(handle, recv, read_size, 500);
	if (bytesRead <= 0) return "-1";


	bool changed = false;
	for (int i = 0; i < bytesRead; ++i) {
		if (recv[i] != 0xFF) {
			changed = true;
			break;
		}
	}
	if (!changed) return "-1";

	size_t data_len = bytesRead;
	if (data_len >= static_cast<size_t>(buffer_size)) data_len = buffer_size - 1;

	memcpy(buffer, &recv[0], data_len);
	buffer[data_len] = '\0';

	return buffer;
}



