//	Библиотека для работы с Trema-модулем джойстик, I2C-flash для Arduino: https://iarduino.ru/shop/Expansion-payments/dzhoystik-i2c---flash-trema-modul.html
//  Версия: 1.0.0
//  Последнюю версию библиотеки Вы можете скачать по ссылке: https://iarduino.ru/file/521.html
//  Подробное описание функций бибилиотеки доступно по ссылке: https://wiki.iarduino.ru/page/joystick-i2c/
//  Библиотека является собственностью интернет магазина iarduino.ru и может свободно использоваться и распространяться!
//  При публикации устройств или скетчей с использованием данной библиотеки, как целиком, так и её частей,
//  в том числе и в некоммерческих целях, просим Вас опубликовать ссылку: http://iarduino.ru
//  Автор библиотеки: Панькин Павел.
//  Если у Вас возникли технические вопросы, напишите нам: shop@iarduino.ru

#ifndef iarduino_I2C_Joystick_h																														//
#define iarduino_I2C_Joystick_h																														//
																																					//
#include		"iarduino_I2C_PI.h"																										//	Подключаем файл iarduino_I2C_Joystick_I2C.h - для работы с шиной I2C		(используя функции структуры iI2C)
																																					//
#define			DEF_CHIP_ID_FLASH		0x3C																										//	ID линейки чипов - константа для всех чипов серии Flash (позволяет идентифицировать принадлежность чипа к серии).
#define			DEF_CHIP_ID_METRO		0xC3																										//	ID линейки чипов - константа для всех чипов серии Metro (позволяет идентифицировать принадлежность чипа к серии).
#define			DEF_MODEL_JOY			0x11																										//	Идентификатор модели - константа.
//				Адреса регистров модуля:																											//
#define			REG_FLAGS_0				0x00																										//	Адрес регистра флагов управления для чтения.
#define			REG_BITS_0				0x01																										//	Адрес регистра битов  управления для чтения и записи.
#define			REG_FLAGS_1				0x02																										//	Адрес регистра флагов управления для чтения.
#define			REG_BITS_1				0x03																										//	Адрес регистра битов  управления для чтения и записи.
#define			REG_MODEL				0x04																										//	Адрес регистра содержащего номер типа модуля.
#define			REG_VERSION				0x05																										//	Адрес регистра содержащего версию прошивки.
#define			REG_ADDRESS				0x06																										//	Адрес регистра содержащего текущий адрес модуля на шине I2C. Если адрес указан с флагом IF-PIN-ADDRES то адрес установится (и запишется в регистр) только при наличии 1 на входе PIN_ADDRES.
#define			REG_CHIP_ID				0x07																										//	Адрес регистра содержащего ID линейки чипов «Flash». По данному ID можно определить принадлежность чипа к линейки «Flash».
#define			REG_JOY_AVERAGING		0x08																										//	Адрес регистра хранящего коэффициент усреднения показаний АЦП.
#define			REG_JOY_DEAD_ZONE		0x09																										//	Адрес регистра определяющего мёртвую зону возле центрального положения джойстика в десятых долях процентов от всего хода из центра к краю (значение от 00.0% до 25.5%).
#define			REG_JOY_KEY				0x10																										//	Адрес регистра статусных флагов кнопки.
#define			REG_JOY_KEY_TIM			0x11																										//	Адрес регистра времени удержания/простоя кнопки (в десятых долях секунд).
#define			REG_JOY_AXIS_X			0x12																										//	Адрес регистра положения джойстика по оси X, значение от -100 (крайнее левое  положение) до +100 (крайнее правое  положение).
#define			REG_JOY_AXIS_Y			0x13																										//	Адрес регистра положения джойстика по оси Y, значение от -100 (крайнее нижнее положение) до +100 (крайнее верхнее положение).
#define			REG_JOY_X_ADC_L			0x14																										//	Адрес регистра текущих показаний  АЦП (младший байт) для оси X.
#define			REG_JOY_Y_ADC_L			0x16																										//	Адрес регистра текущих показаний  АЦП (младший байт) для оси Y.
#define			REG_JOY_X_RIGHT_L		0x18																										//	Адрес регистра хранящего значение АЦП (младший байт) соответствующее крайнему правому  положению джойтика по оси X.
#define			REG_JOY_X_CEN_L			0x1A																										//	Адрес регистра хранящего значение АЦП (младший байт) соответствующее центральному      положению джойтика по оси X.
#define			REG_JOY_X_LEFT_L		0x1C																										//	Адрес регистра хранящего значение АЦП (младший байт) соответствующее крайнему левому   положению джойтика по оси X.
#define			REG_JOY_Y_UP_L			0x1E																										//	Адрес регистра хранящего значение АЦП (младший байт) соответствующее крайнему верхнему положению джойтика по оси Y.
#define			REG_JOY_Y_CEN_L			0x20																										//	Адрес регистра хранящего значение АЦП (младший байт) соответствующее центральному      положению джойтика по оси Y.
#define			REG_JOY_Y_DOWN_L		0x22																										//	Адрес регистра хранящего значение АЦП (младший байт) соответствующее крайнему нижнему  положению джойтика по оси Y.
//				Позиция битов и флагов:																												//
#define			JOY_KEY_PUSHED			0x80																										//	Флаг нажатия на кнопку.			Устанавливается в момент нажатия на кнопку и остаётся установленным пока не будет прочитан. Флаг сбрасывается самостоятельно после чтении регистра «REG_KEY».
#define			JOY_KEY_RELEASED		0x40																										//	Флаг отпускания кнопки.			Устанавливается в момент отпускания кнопки и остаётся установленным пока не будет прочитан. Флаг сбрасывается самостоятельно после чтении регистра «REG_KEY».
#define			JOY_KEY_PRESSED			0x20																										//	Флаг состояния кнопки.			Установлен пока кнопка нажата и сброшен если она отпущена.
#define			JOY_KEY_TRIGGER			0x10																										//	Флаг триггер.					Меняет своё состояние с каждым новым нажатием на кнопку (нажали - установился, нажали - сбросился, нажали - установился, ...).
#define			JOY_KEY_HOLD_05			0x08																										//	Флаг удержания кнопки.			Устанавливается если кнопка удерживается дольше времени указанного в регистре «REG_TIME_HOLD_3» и сбрасывается при отпускании кнопки.
#define			JOY_KEY_HOLD_10			0x04																										//	Флаг удержания кнопки.			Устанавливается если кнопка удерживается дольше времени указанного в регистре «REG_TIME_HOLD_2» и сбрасывается при отпускании кнопки.
#define			JOY_KEY_HOLD_20			0x02																										//	Флаг удержания кнопки.			Устанавливается если кнопка удерживается дольше времени указанного в регистре «REG_TIME_HOLD_1» и сбрасывается при отпускании кнопки.
#define			JOY_KEY_CHANGED			0x01																										//	Флаг смены состояния кнопки.	Устанавливается в момент нажатия или отпускания кнопки и остаётся установленным пока не будет прочитан. Флаг сбрасывается самостоятельно после чтении регистра «REG_KEY».
																																					//
#ifndef			KEY_PUSHED																															//
#define			KEY_PUSHED				1																											//	getButton( нажимается ).
#endif																																				//
																																					//
#ifndef			KEY_RELEASED																														//
#define			KEY_RELEASED			2																											//	getButton( отпускается ).
#endif																																				//
																																					//
#ifndef			KEY_PRESSED																															//
#define			KEY_PRESSED				3																											//	getButton( нажата ).
#endif																																				//
																																					//
#ifndef			KEY_TRIGGER																															//
#define			KEY_TRIGGER				4																											//	getButton( переключатель ).
#endif																																				//
																																					//
#ifndef			KEY_HOLD_05																															//
#define			KEY_HOLD_05				5																											//	getButton( удерживается дольше 0,5 секунд ).
#endif																																				//
																																					//
#ifndef			KEY_HOLD_10																															//
#define			KEY_HOLD_10				6																											//	getButton( удерживается дольше 1 секунды ).
#endif																																				//
																																					//
#ifndef			KEY_HOLD_20																															//
#define			KEY_HOLD_20				7																											//	getButton( удерживается дольше 2 секунд ).
#endif																																				//
																																					//
#ifndef			KEY_CHANGED																															//
#define			KEY_CHANGED				8																											//	getButton( состояние изменилось ).
#endif																																				//
																																					//
#ifndef			KEY_TIME_PRESSED																													//
#define			KEY_TIME_PRESSED		9																											//	getButton( текущее время удержания кнопки ).
#endif																																				//
																																					//
																																					//
class iarduino_I2C_Joystick{																														//
	public:																																			//
	/**	Конструктор класса **/																														//
		iarduino_I2C_Joystick						(uint8_t address=0) {																			//	Конструктор класса													(Параметр: адрес модуля на шине I2C, если не указан (=0), то адрес будет определён).
													if(address>0x7F){ address>>=1; }																//	Корректируем адрес, если он указан с учётом бита RW.
							valAddrTemp			=	address;																						//	Сохраняем переданный адрес модуля.
							objI2C				=	new iarduino_I2C;																				//	Переопределяем указатель objI2C на объект производного класса iarduino_I2C.
		}																																			//
	/**	Пользовательские функции **/																												//
		bool				begin					(void				);																			//	Объявляем  функцию инициализации модуля								(Параметр:  отсутствует).
		bool				reset					(void				);																			//	Объявляем  функцию перезагрузки модуля								(Параметр:  отсутствует).
		bool				changeAddress			(uint8_t			);																			//	Объявляем  функцию смены адреса модуля на шине I2C					(Параметр:  новый адрес модуля).
		uint8_t				getAddress				(void				){ return valAddr;	}														//	Определяем функцию возвращающую текущий адрес модуля на шине I2C	(Параметр:  отсутствует).
		uint8_t				getVersion				(void				){ return valVers;	}														//	Определяем функцию возвращающую текущую версию прошивки модуля		(Параметр:  отсутствует).
		bool				getPullI2C				(void				);																			//	Определяем функцию возвращающую флаг наличия подтяжки шины I2C		(Параметр:  отсутствует).
		bool				setPullI2C				(bool=true			);																			//	Определяем функцию установки подтяжки шины I2C						(Параметр:  флаг подтяжки).
		uint16_t			getButton				(uint8_t			);																			//	Объявляем  функцию получения состояний/событий кнопки				(Параметр:  тип получаемого состояния или собития).
		int					getPosition_X			(void				);																			//	Объявляем  функцию возвращающую координату джойстика по оси X		(Параметр:  отсутствует).
		int					getPosition_Y			(void				);																			//	Объявляем  функцию возвращающую координату джойстика по оси Y		(Параметр:  отсутствует).
template<typename T> bool	getPosition				(T &x, T &y			){int8_t a,b; bool f=_getPosition_XY(a,b); x=(T)a; y=(T)b;     return f;}	//	Определяем функцию меняющую значения аргументов на координаты		(Параметры: переменные для получения координат X и Y).
		int					getADC_X				(void				);																			//	Объявляем  функцию возвращающую значение АЦП джойстика по оси X		(Параметр:  отсутствует).
		int					getADC_Y				(void				);																			//	Объявляем  функцию возвращающую значение АЦП джойстика по оси Y		(Параметр:  отсутствует).
template<typename T> bool	getADC					(T &x, T &y			){int a,b;    bool f=_getADC_XY(a,b);  x=(T)a; y=(T)b;         return f;}	//	Определяем функцию меняющую значения аргументов на значения АЦП		(Параметры: переменные для получения значений АЦП снятых с потенциометров джойстика).
template<typename T> bool	getCalibration_X		(T &l, T &c, T &r	){int a,b,e;  bool f=_getCal_X(a,b,e); l=(T)a; c=(T)b; r=(T)e; return f;}	//	Определяем функцию получения текущий калибровочных значений оси X	(Параметры: АЦП крайнего левого  положения, АЦП центрального положения, АЦП крайнего правого  положения).
template<typename T> bool	getCalibration_Y		(T &d, T &c, T &u	){int a,b,e;  bool f=_getCal_Y(a,b,e); d=(T)a; c=(T)b; u=(T)e; return f;}	//	Определяем функцию получения текущий калибровочных значений оси Y	(Параметры: АЦП крайнего нижнего положения, АЦП центрального положения, АЦП крайнего верхнего положения).
		bool				setCalibration_X		(int, int, int		);																			//	Объявляем  функцию калибровки координат по оси X					(Параметры: АЦП крайнего левого  положения, АЦП центрального положения, АЦП крайнего правого  положения).
		bool				setCalibration_Y		(int, int, int		);																			//	Объявляем  функцию калибровки координат по оси Y					(Параметры: АЦП крайнего нижнего положения, АЦП центрального положения, АЦП крайнего верхнего положения).
		bool				setDeadZone				(float				);																			//	Объявляем  функцию установки мертвой зоны центрального положения	(Параметр:  значение от 0.0% до 25.5% от полоного хода джойстика из центра к любому краю).
		bool				setAveraging			(uint8_t			);																			//	Объявляем  функцию установки коэффициента усреднения показаний АЦП	(Параметр:  значение от 0 (без усреднений) до 255 (максимальное усреднение).
		bool updateCalX();
		bool updateCalY();
		int getMinX(void) { return temp_min_x; };
		int getCenX(void) { return temp_cen_x; };
		int getMaxX(void) { return temp_max_x; };
		int getMinY(void) { return temp_min_y; };
		int getCenY(void) { return temp_cen_y; };
		int getMaxY(void) { return temp_max_y; };

	private:																																		//
	/**	Внутренние переменные **/																													//
		uint8_t				valAddrTemp			=	0;																								//	Определяем переменную для хранения адреса модуля на шине I2C который был указан, но не был проверен.
		uint8_t				valAddr				=	0;																								//	Определяем переменную для хранения адреса модуля на шине I2C.
		uint8_t				valVers				=	0;																								//	Определяем переменную для хранения версии прошивки модуля.
		uint8_t				val_REG_JOY_KEY		=	0;																								//	Определяем переменную для хранения значения регистра статусных флагов кнопки «REG_JOY_KEY». Благодаря данной переменной реализован сброс флагов «KEY_PUSHED», «KEY_RELEASED» и «KEY_CHANGED» не по чтению регистра «REG_JOY_KEY», а по обращению к функции getButton(тип);
		uint8_t				data[6];																												//	Объявляем  массив     для хранения получаемых/передаваемых данных.
		int temp_min_x = 0;
		int temp_cen_x = 0;
		int temp_max_x = 0;
		int temp_min_y = 0;
		int temp_cen_y = 0;
		int temp_max_y = 0;
		iarduino_I2C_BASE*	objI2C;																													//	Объявляем  указатель  на  объект полиморфного класса iarduino_I2C_BASE, но в конструкторе данного класса этому указателю будет присвоена ссылка на производный класс iarduino_I2C.
	/**	Внутренние функции **/																														//
		bool				_getPosition_XY			(int8_t&, int8_t&				);																//	Объявляем  функцию меняющую значения аргументов на координаты		(Параметры: переменные для получения координат X и Y).
		bool				_getADC_XY				(int&,    int&					);																//	Объявляем  функцию меняющую значения аргументов на значения АЦП		(Параметры: переменные для получения значений АЦП снятых с потенциометров джойстика).
		bool				_getCal_X				(int&,    int&,    int&			);																//	Объявляем  функцию получения текущий калибровочных значений оси X	(Параметры: АЦП крайнего левого  положения, АЦП центрального положения, АЦП крайнего правого  положения).
		bool				_getCal_Y				(int&,    int&,    int&			);																//	Объявляем  функцию получения текущий калибровочных значений оси Y	(Параметры: АЦП крайнего нижнего положения, АЦП центрального положения, АЦП крайнего верхнего положения).
		bool				_readBytes				(uint8_t, uint8_t				);																//	Объявляем  функцию чтения данных в  массив  data					(Параметры: номер первого регистра, количество байт).
		bool				_writeBytes				(uint8_t, uint8_t, uint8_t=0	);																//	Объявляем  функцию записи данных из массива data					(Параметры: номер первого регистра, количество байт, номер первого элемента массива data).
};																																					//
																																					//
#endif																																				//
