#include <stdlib.h>
#include <cmath>
#define PI M_PI
#include "iarduino_I2C_Motor.h"																									//
																																//
//		Инициализация модуля:																									//	Возвращаемое значение: результат инициализации.
bool	iarduino_I2C_Motor::begin			(void){																				//	Параметр: отсутствует
		//	Инициируем работу с шиной I2C:																						//
		iarduino_I2C::begin(100);																									//	Инициируем передачу данных по шине I2C на скорости 100 кГц.
		//	Если адрес не указан, то ищим модуль на шине I2C:																	//
			if(valAddrTemp==0){																									//
				for(int i=1; i<127; i++){																						//	Проходим по всем адресам на шине I2C
					if( checkAddress(i)											){	valAddr=i; delay(2);				//	Если на шине I2C есть устройство с адресом i, то используем этот адрес для проверки найденного модуля...
					if(_readBytes(REG_MODEL,4)											){										//	Читаем 4 байта начиная с регистра «REG_MODEL» в массив «data».
					if( data[0]     == DEF_MODEL_MOT									){										//	Если у модуля с адресом i в регистре «MODEL»   (data[0]) хранится значение DEF_MODEL_MOT, то ...
					if((data[2]>>1) == i                 || data[2] == 0xFF				){										//	Если у модуля с адресом i в регистре «ADDRESS» (data[2]) хранится значение i (адрес+младший бит) или 0xFF (адрес не задавался), то ...
					if( data[3]     == DEF_CHIP_ID_FLASH || data[3] == DEF_CHIP_ID_METRO){										//	Если у модуля с адресом i в регистре «CHIP_ID» (data[3]) хранится значение DEF_CHIP_ID_FLASH (идентификатор модулей Flash), или DEF_CHIP_ID_METRO (идентификатор модулей Metro), то ...
						valAddrTemp=i; i=128;																					//	Считаем что модуль обнаружен, сохраняем значение i как найденный адрес и выходим из цикла.
					}}}}}																										//
				}																												//
			}																													//
		//	Если модуль не найден, то возвращаем ошибку инициализации:															//
			if( valAddrTemp == 0														){	valAddr=0; return false;}			//
		//	Проверяем наличие модуля на шине I2C:																				//
			if( checkAddress(valAddrTemp) == false								){	valAddr=0; return false;}			//	Если на шине I2C нет устройств с адресом valAddrTemp, то возвращаем ошибку инициализации
			valAddr=valAddrTemp;																								//	Сохраняем адрес модуля на шине I2C.
		//	Проверяем значения регистров модуля:																				//
			if(_readBytes(REG_MODEL,4)==false											){	valAddr=0; return false;}			//	Если не удалось прочитать 4 байта в массив «data» из модуля начиная с регистра «REG_MODEL», то возвращаем ошибку инициализации.
			if( data[0]     != DEF_MODEL_MOT											){	valAddr=0; return false;}			//	Если значение  регистра «MODEL»   (data[0]) не совпадает со значением DEF_MODEL_MOT, то возвращаем ошибку инициализации.
			if((data[2]>>1) != valAddrTemp       && data[2] !=0xFF						){	valAddr=0; return false;}			//	Если значение  регистра «ADDRESS» (data[2]) не совпадает с адресом модуля и не совпадает со значением 0xFF, то возвращаем ошибку инициализации.
			if( data[3]     != DEF_CHIP_ID_FLASH && data[3] != DEF_CHIP_ID_METRO		){	valAddr=0; return false;}			//	Если значение  регистра «CHIP_ID» (data[3]) не совпадает со значением DEF_CHIP_ID_FLASH и DEF_CHIP_ID_METRO, то возвращаем ошибку инициализации.
			valVers=data[1];																									//	Сохраняем байт регистра «VERSION» (data[1]) в переменую «valVers».
		//	Перезагружаем модуль устанавливая его регистры в значение по умолчанию:												//
			reset();																											//	Выполняем программную перезагрузку.
			delay(5);																											//
			return true;																										//	Возвращаем флаг успешной инициализаии.
}																																//
																																//
//		Перезагрузка модуля:																									//	Возвращаемое значение:	результат перезагрузки.
bool	iarduino_I2C_Motor::reset			(void){																				//	Параметр:				отсутствует.
			if(valAddr){																										//	Если модуль был инициализирован, то ...
				timReset = millis();																							//	сохраняем текущее время.
			//	Устанавливаем бит перезагрузки:																					//
				if(_readBytes(REG_BITS_0,1)==false){return false;}																//	Читаем 1 байт регистра «BITS_0» в массив «data».
				data[0] |= 0b10000000;																							//	Устанавливаем бит «SET_RESET»
				if(_writeBytes(REG_BITS_0,1)==false){return false;}																//	Записываем 1 байт в регистр «BITS_0» из массива «data».
			//	Переинициируем шину в связи с программным отключением подтяжек шины I2C в модуле:								//
				delay(10); iarduino_I2C::begin(100);																						//	Ждём восстановление подтяжек линий SCL/SDA и переинициируем работу с шиной I2C.
			//	Ждём установки флага завершения перезагрузки:																	//
				do{ if(_readBytes(REG_FLAGS_0,1)==false){return false;} }														//	Читаем 1 байт регистра «REG_FLAGS_0» в массив «data».
				while( (data[0]&0b10000000) == 0);																				//	Повторяем чтение пока не установится флаг «FLG_RESET».
				return true;																									//
			}else{																												//	Иначе, если модуль не инициализирован, то ...
				return false;																									//	Возвращаем ошибку
			}																													//
}																																//
																																//
//		Смена адреса модуля:																									//	Возвращаемое значение:	резульат смены адреса.
bool	iarduino_I2C_Motor::changeAddress	(uint8_t newAddr){																	//	Параметр:				newAddr - новый адрес модуля (0x07 < адрес < 0x7F).
			if(valAddr){																										//	Если модуль был инициализирован, то ...
			//	Проверяем новый адрес:																							//
				if(newAddr>0x7F){newAddr>>=1;}																					//	Корректируем адрес, если он указан с учётом бита RW.
				if(newAddr==0x00 || newAddr==0x7F){return false;}																//	Запрещаем устанавливать адрес 0x00 и 0x7F.
			//	Записываем новый адрес:																							//
				if(_readBytes(REG_BITS_0,1)==false){return false;}																//	Читаем 1 байт регистра «BITS_0» в массив «data».
				data[0] &= 0b11110111;																							//	Сбрасываем    бит «BLOCK_ADR».
				data[0] |= 0b00000010;																							//	Устанавливаем бит «SAVE_ADR_EN»
				if(_writeBytes(REG_BITS_0,1)==false){return false;}																//	Записываем 1 байт в регистр «BITS_0» из массива «data».
				data[0] = (newAddr<<1)|0x01;																					//	Готовим новый адрес к записи в модуль, установив бит «SAVE_FLASH».
				if(_writeBytes(REG_ADDRESS,1)==false){return false;}															//	Записываем 1 байт в регистр «ADDRESS» из массива «data».
				delay(200);																										//	Даём более чем достаточное время для применения модулем нового адреса.
			//	Проверяем наличие модуля с новым адресом на шине I2C:															//
				if(checkAddress(newAddr)==false){return false;}															//	Если на шине I2C нет модуля с адресом newAddr, то возвращаем ошибку.
				valAddr     = newAddr;																							//	Сохраняем новый адрес как текущий.
				valAddrTemp = newAddr;																							//	Сохраняем новый адрес как указанный.
				return true;																									//	Возвращаем флаг успеха.
			}else{																												//	Иначе, если модуль не инициализирован, то ...
				return false;																									//	Возвращаем ошибку
			}																													//
}																																//
																																//
//		Получение флага наличия подтяжки линий шины I2C:																		//	Возвращаемое значение:	флаг наличия подтяжки линий шины I2C.
bool	iarduino_I2C_Motor::getPullI2C		(void){																				//	Параметр:				отсутствует.
			if(valAddr){																										//	Если модуль был инициализирован, то ...
			//	Считываем первые два регистра: регистр флагов и регистр битов:													//
				if(_readBytes(REG_FLAGS_0,2)==false ){ return false; }															//	Читаем 2 байта начиная с регистра «REG_FLAGS_0» в массив «data».
			//	Проверяем поддерживает ли модуль управление подтяжкой линий шины I2C:											//
				if( (data[0] & 0b00000100) == false ){ return false; }															//	Если флаг «FLG_I2C_UP» регистра «REG_FLAGS_0» сброшен, значит модуль не поддерживает управление подтяжкой линий шины I2C.
			//	Проверяем установлена ли подтяжка линий шины I2C:																//
				if( (data[1] & 0b00000100) == false ){ return false; }															//	Если бит  «SET_I2C_UP» регистра «REG_BITS_0»  сброшен, значит подтяжка линий шины I2C не установлена.
				return true;																									//	Возвращаем флаг успеха.
			}else{																												//	Иначе, если модуль не инициализирован, то ...
				return false;																									//	Возвращаем ошибку.
			}																													//
}																																//
																																//
//		Установка подтяжки линий шины I2C:																						//	Возвращаемое значение:	результат установки подтяжки линий шины I2C.
bool	iarduino_I2C_Motor::setPullI2C		(bool f){																			//	Параметр:				флаг подтяжки линий шины I2C.
			if(valAddr){																										//	Если модуль был инициализирован, то ...
			//	Считываем первые два регистра: регистр флагов и регистр битов:													//
				if(_readBytes(REG_FLAGS_0,2)==false ){ return false; }															//	Читаем 2 байта начиная с регистра «REG_FLAGS_0» в массив «data».
			//	Проверяем поддерживает ли модуль управление подтяжкой линий шины I2C:											//
				if( (data[0] & 0b00000100) == false ){ return false; }															//	Если флаг «FLG_I2C_UP» регистра «REG_FLAGS_0» сброшен, значит модуль не поддерживает управление подтяжкой линий шины I2C.
			//	Устанавливаем или сбрасываем бит включения подтяжки линий шины I2C:												//
				if(f){ data[0] = (data[1] |  0b00000100); }																		//	Если флаг «f» установлен, то копируем значение из 1 в 0 элемент массива «data» установив бит «SET_I2C_UP».
				else { data[0] = (data[1] & ~0b00000100); }																		//	Если флаг «f» сброшен   , то копируем значение из 1 в 0 элемент массива «data» сбросив   бит «SET_I2C_UP».
			//	Сохраняем получившееся значение в регистр «REG_BITS_0»:															//
				if(_writeBytes(REG_BITS_0,1)==false ){ return false; }															//	Записываем 1 байт в регистр «REG_BITS_0» из массива «data».
				delay(50);																										//	Даём время для сохранения данных в энергонезависимую память модуля.
				return true;																									//	Возвращаем флаг успеха.
			}else{																												//	Иначе, если модуль не инициализирован, то ...
				return false;																									//	Возвращаем ошибку
			}																													//
}																																//
																																//
//		Установка частоты ШИМ:																									//	Возвращаемое значение:	результат установки true/false.
bool	iarduino_I2C_Motor::setFreqPWM		(uint16_t frequency){																//	Параметр:				частота в Гц (1-1000).
			if(valAddr){																										//	Если модуль был инициализирован, то ...
				if( frequency<25   ){ return false; }																			//	Если частота указана некорректно, то возвращаем false.
				if( frequency>1000 ){ return false; }																			//	Если частота указана некорректно, то возвращаем false.
			//	Готовим два байта для записи:																					//
				data[0] = uint8_t(frequency & 0x00FF);																			//	Устанавливаем младший байт значения «frequency» для регистра «REG_MOT_FREQUENCY_L».
				data[1] = uint8_t(frequency >> 8);																				//	Устанавливаем старший байт значения «frequency» для регистра «REG_MOT_FREQUENCY_H».
			//	Отправляем подготовленные данные в модуль:																		//
				if(_writeBytes(REG_MOT_FREQUENCY_L, 2)==false){return false;}													//	Записываем 2 байта из массива «data» в модуль, начиная с регистра «REG_MOT_FREQUENCY_L».
			//	Возвращаем результат:																							//
				return true;																									//
			}	return false;																									//
}																																//
																																//
//		Установка количества магнитов у датчика Холла:																			//	Возвращаемое значение:	результат установки true/false.
bool	iarduino_I2C_Motor::setMagnet		(uint8_t sum){																		//	Параметр:				sum - количество магнитов от 1 до 63.
			if(valAddr){																										//	Если модуль был инициализирован, то ...
			//	Готовим данные для передачи:																					//
				data[0] = sum;																									//	Сохраняем указанное количество магнитов.
			//	Отправляем подготовленные данные в модуль:																		//
				if(_writeBytes(REG_MOT_MAGNET, 1)==false){return false;}														//	Записываем 1 байт из массива «data» в регистр «REG_MOT_MAGNET».
			//	Возвращаем результат:																							//
				return true;																									//
			}	return false;																									//
}																																//
																																//
//		Получение количества магнитов у датчика Холла:																			//	Возвращаемое значение:	количество магнитов от 1 до 63.
uint8_t	iarduino_I2C_Motor::getMagnet		(void){																				//	Параметр:				отсутствует.
			if(valAddr){																										//	Если модуль был инициализирован, то ...
			//	Читаем и возвращаем количество магнитов у датчика Холла:														//
				if(_readBytes(REG_MOT_MAGNET, 1)==false ){ return 0;}															//	Читаем 1 байт из регистра «REG_MOT_MAGNET» в массив «data».
				return data[0];																									//	Возвращаем количество магнитов у датчика Холла.
			}	return 0;																										//
}																																//
																																//
//		Установка передаточного отношения редуктора:																			//	Возвращаемое значение:	результат установки true/false.
bool	iarduino_I2C_Motor::setReducer		(float gear){																		//	Параметр:				gear - передаточное отношение редуктора от 0.01 до 167'772.15.
			if(valAddr){																										//	Если модуль был инициализирован, то ...
			//	Проверяем полученные данные:																					//
				if( gear <      0.01f ){ gear =      0.01f; }																	//	Передаточное отношение не может быть ниже 0,01.
				if( gear > 167772.15f ){ gear = 167772.15f; }																	//	Передаточное отношение не может превышать 167772,15.
			//	Готовим данные для передачи:																					//
				gear   *= 100;																									//
				data[0] = ((uint32_t)gear    ) & 0x000000FF;																	//	Байт для записи в регистр «REG_MOT_REDUCER_L».
				data[1] = ((uint32_t)gear>> 8) & 0x000000FF;																	//	Байт для записи в регистр «REG_MOT_REDUCER_C».
				data[2] = ((uint32_t)gear>>16) & 0x000000FF;																	//	Байт для записи в регистр «REG_MOT_REDUCER_H».
			//	Отправляем подготовленные данные в модуль:																		//
				if(_writeBytes(REG_MOT_REDUCER_L, 3)==false){return false;}														//	Записываем 3 байта из массива «data» в модуль, начиная с регистра «REG_MOT_REDUCER_L».
			//	Возвращаем результат:																							//
				return true;																									//
			}	return false;																									//
}																																//
																																//
//		Получение передаточного отношения редуктора:																			//	Возвращаемое значение:	передаточное отношение редуктора от 0.01 до 167'772.15.
float	iarduino_I2C_Motor::getReducer		(void){																				//	Параметр:				отсутствует.
			if(valAddr){																										//	Если модуль был инициализирован, то ...
			//	Читаем и возвращаем передаточное отношение редуктора:															//
				if(_readBytes(REG_MOT_REDUCER_L, 3)==false ){ return 0;}														//	Читаем 3 байта начиная с регистра «REG_MOT_REDUCER_L» в массив «data».
				return (float)( (int32_t)data[2]<<16 | (int32_t)data[1]<<8 | (int32_t)data[0] )/100;							//	Возвращаем прочитанное значение.
			}	return 0;																										//
}																																//
																																//
//		Установка процента отклонения скорости превышение которого приведёт к установке флага ошибки:							//	Возвращаемое значение:	результат установки true/false.
bool	iarduino_I2C_Motor::setError		(uint8_t deviation){																//	Параметр:				deviation - процент максимально допустимого отклонения реальной скорости от заданной, превышение которого приведёт к установке флага ошибки
			if(valAddr){																										//	Если модуль был инициализирован, то ...
			//	Проверяем полученные данные:																					//
				if( deviation > 100 ){ deviation = 100; }																		//	Отклонение не может превышать 100%.
			//	Готовим данные для передачи:																					//
				data[0] =  deviation;																							//	Байт для записи в регистр «REG_MOT_MAX_RPM_DEV».
			//	Отправляем подготовленные данные в модуль:																		//
				if(_writeBytes(REG_MOT_MAX_RPM_DEV, 1)==false){return false;}													//	Записываем 1 байт из массива «data» в регистр «REG_MOT_MAX_RPM_DEV».
			//	Возвращаем результат:																							//
				return true;																									//
			}	return false;																									//
}																																//
																																//
//		Получение флага ошибки скорости или драйвера:																			//	Возвращаемое значение:	флаг наличия ошибки: 0 / MOT_ERR_SPD / MOT_ERR_DRV.
uint8_t	iarduino_I2C_Motor::getError		(void){																				//	Параметр:				отсутствует.
			if(valAddr){																										//	Если модуль был инициализирован, то ...
			//	Считываем состояние регистра флагов:																			//
				if(_readBytes(REG_MOT_FLG,1)==false){return 0;}																	//	Читаем 1 байт регистра «REG_MOT_FLG» в массив «data».
			//	Возвращаем результат:																							//
				if( data[0] & MOT_FLG_RPM_ERR ){ return MOT_ERR_SPD; }															//	Если в прочитанном байте установлен флаг «MOT_FLG_RPM_ERR», то возвращаем ошибку «MOT_ERR_SPD».
				if( data[0] & MOT_FLG_DRV_ERR ){ return MOT_ERR_DRV; }															//	Если в прочитанном байте установлен флаг «MOT_FLG_DRV_ERR», то возвращаем ошибку «MOT_ERR_DRV».
			}	return 0;																										//
}																																//
																																//
//		Установка скорости и условия остановки:																					//	Возвращаемое значение:	результат установки true/false.
bool	iarduino_I2C_Motor::setSpeed		(float valSpeed, uint8_t typeSpeed, float valStop, uint8_t typeStop){				//	Параметры:				valSpeed - значение скорости, typeSpeed - тип значения скорости MOT_RPM / MOT_PWM / MOT_M_S, valStop - значение условия остановки, typeStop - тип условия остановки: MOT_MET / MOT_REV / MOT_SEC.
			if(valAddr){																										//	Если модуль был инициализирован, то ...
				uint8_t reg;																									//
			//	Передаём условие остановки:																						//
				if( typeStop==MOT_MET || typeStop==MOT_REV || typeStop==MOT_SEC ){												//	Если тип условия остановки задан верно, то ...
					if( !setStop(valStop, typeStop) ){ return false; }															//	Возвращаем false если условие остановки не принято.
				}																												//
			//	Проверяем полученные данные:																					//
				if( typeSpeed == MOT_RPM ){																						//
				//	Если скорость задана количеством оборотов в минуту:															//
					if( valSpeed > 32767.0f ){ valSpeed =  32767.0f; }															//	Количество оборотов не может быть выше значения +32'767.
					if( valSpeed <-32767.0f ){ valSpeed = -32767.0f; }															//	Количество оборотов не может быть ниже значения -32'767.
					reg = REG_MOT_SET_RPM_L;																					//	Определяем адрес регистра для записи данных.
				}else																											//
				if( typeSpeed == MOT_M_S ){																						//
				//	Если скорость задана в м/сек:																				//
					valSpeed *= 60000.0f;																						//	Преобразуем скорость из  м/сек в мм/мин.
					valSpeed /= (2.0f * PI * radius);																			//	Преобразуем скорость из мм/мин в об/мин.
					if( valSpeed > 32767.0f ){ valSpeed =  32767.0f; }															//	Количество оборотов не может быть выше значения +32'767.
					if( valSpeed <-32767.0f ){ valSpeed = -32767.0f; }															//	Количество оборотов не может быть ниже значения -32'767.
					reg = REG_MOT_SET_RPM_L;																					//	Определяем адрес регистра для записи данных.
				}else																											//
				if( typeSpeed == MOT_PWM ){																						//
				//	Если скорость задана коэффициентом заполнения ШИМ:															//
					valSpeed *= 4095.0f;																						//	Преобразуем скорость из % к абсолютному значению ШИМ
					valSpeed /= 100.0f;																							//
					if( valSpeed > 4095.0f ){ valSpeed =  4095.0f; }															//	Коэффициент заполнения ШИМ не может быть выше значения +4095.
					if( valSpeed <-4095.0f ){ valSpeed = -4095.0f; }															//	Коэффициент заполнения ШИМ не может быть ниже значения -4095.
					reg = REG_MOT_SET_PWM_L;																					//	Определяем адрес регистра для записи данных.
				}else																											//
				{//	Если тип скорости задан некорректно:																		//
					return false;																								//
				}																												//
			//	Готовим данные для передачи:																					//
				data[0] = (uint8_t)( (int16_t)(valSpeed)     & 0x00FF);															//	Младший байт для записи в модуль.
				data[1] = (uint8_t)(((int16_t)(valSpeed)>>8) & 0x00FF);															//	Старший байт для записи в модуль.
			//	Отправляем подготовленные данные в модуль:																		//
				if(_writeBytes(reg, 2)==false){return false;}																	//	Записываем 2 байта из массива «data» в модуль, начиная с регистра «reg».
			//	Возвращаем результат:																							//
				return true;																									//
			}	return false;																									//
}																																//
																																//
//		Получение реальной скорости или коэффициента заполнения ШИМ:															//	Возвращаемое значение:	реальная скорость от 0 до ±32'767 об/мин., или установленный
float	iarduino_I2C_Motor::getSpeed		(uint8_t type){																		//	Параметр:				type - тип возвращаемого значения: MOT_RPM / MOT_PWM / MOT_M_S
			float valSpeed=0.0f;																								//
			if(valAddr){																										//	Если модуль был инициализирован, то ...
				uint8_t reg;																									//
			//	Читаем реальную скорость из модуля:																				//
				switch(type){																									//
					case MOT_RPM: reg=REG_MOT_GET_RPM_L; break;																	//	Если запрошена реальная скорость в об/мин.
					case MOT_M_S: reg=REG_MOT_GET_RPM_L; break;																	//	Если запрошена реальная скорость в  м/сек.
					case MOT_PWM: reg=REG_MOT_SET_PWM_L; break;																	//	Если запрошен установленный коэффициент заполнения ШИМ.
					default: return 0;																							//
				}																												//
				if(_readBytes(reg,2)==false){return 0;}																			//	Читаем 2 байта начиная с регистра «reg» в массив «data».
				valSpeed = (float)((int16_t)data[1]<<8 | (int16_t)data[0]);														//	Получаем прочитанные данные в переменную «valSpeed».
			//	Преобразуем реальную скорость из об/мин в м/сек:																//
				if( type==MOT_M_S ){																							//	Если запрошена реальная скорость в  м/сек.
					valSpeed *= (2.0f * PI * radius);																			//	Преобразуем скорость из об/мин в мм/мин.
					valSpeed /= 60000.0f;																						//	Преобразуем скорость из мм/мин в  м/сек.
				}																												//
			//	Преобразуем реальную скорость из абсолютного ШИМ в %:															//
				if( type==MOT_PWM ){																							//	Если запрошена реальная скорость в  ШИМ.
					valSpeed *= 100.0f;																							//	Преобразуем скорость из абсолютного значения ШИМ в %.
					valSpeed /= 4095.0f;																						//
				}																												//
			}	return valSpeed;																								//	Возвращаем запрошенную скорость или коэффициент заполнения ШИМ.
}																																//
																																//
//		Остановка мотора с условием:																							//	Возвращаемое значение:	результат установки остановки true/false.
bool	iarduino_I2C_Motor::setStop			(float value, uint8_t type){														//	Параметры:				value - значение условия остановки, type - тип условия остановки: MOT_MET / MOT_REV / MOT_SEC.
			if(valAddr){																										//	Если модуль был инициализирован, то ...
			//	Выполняем действия в соответствии с типом условия остановки:													//
				switch(type){																									//
				//	Если условием остановки является немедленная остановка:														//
					case 0xFF:																									//
					//	Читаем состояние флага «MOT_FLG_NEUTRAL» из регистра флагов «REG_MOT_FLG»:								//
						if(_readBytes(REG_MOT_FLG,1)==false){return false;}														//	Читаем 1 байт регистра «REG_MOT_FLG» в массив «data».
					//	Записываем данные в регистр остановки «REG_MOT_STOP»:													//
						data[0] = MOT_BIT_STOP | ((data[0]&MOT_FLG_NEUTRAL)? MOT_BIT_NEUTRAL:0);								//	Устанавливаем бит «MOT_BIT_STOP», не меняя бит «MOT_BIT_NEUTRAL».
						if(_writeBytes(REG_MOT_STOP,1)==false){return false;}													//	Записываем 1 байт в регистр «REG_MOT_STOP» из массива «data».
					break;																										//
				//	Если условием остановки является пройденное расстояние:														//
					case MOT_MET:																								//
					//	Преобразуем расстояние до остановки (мм) в количество оборотов до остановки (об/мин):					//
						value *= 1000.0f;																						//	Преобразуем расстояние из м в мм.
						value /= (2.0f * PI * radius);																			//	Преобразуем расстояние в количество оборотов ( количество оборотов (об/мин) = расстояние (мм) / длина окружности (мм) ).
				//	Если условием остановки является количество совершённых оборотов:											//
					case MOT_REV:																								//
					//	Проверяем полученные данные:																			//
						if( value > 167772.15 ){ value = 167772.15; }															//	Количество оборотов до остановки не может превышать значение 167'772.15.
					//	Готовим данные для передачи:																			//
						value *= 100;																							//	Преобразуем обороты в сотые доли оборотов.
						data[0] =  (uint32_t)value      & 0x0000FF;																//	Байт для записи в регистр «REG_MOT_STOP_REV_L».
						data[1] = ((uint32_t)value>>8 ) & 0x0000FF;																//	Байт для записи в регистр «REG_MOT_STOP_REV_C».
						data[2] = ((uint32_t)value>>16) & 0x0000FF;																//	Байт для записи в регистр «REG_MOT_STOP_REV_H».
					//	Отправляем подготовленные данные в модуль:																//
						if(_writeBytes(REG_MOT_STOP_REV_L, 3)==false){return false;}											//	Записываем 3 байта из массива «data» в модуль, начиная с регистра «REG_MOT_SET_PWM_L».
					break;																										//
				//	Если условием остановки является пройденное время:															//
					case MOT_SEC:																								//
					//	Проверяем полученные данные:																			//
						if( value > 16777.215f ){ value = 16777.215f; }															//	Время до остановки не может превышать значение 16'777.215 сек.
					//	Готовим данные для передачи:																			//
						value *= 1000;																							//	Преобразуем время из сек в см.
						data[0] =  (uint32_t)value      & 0x0000FF;																//	Байт для записи в регистр «REG_MOT_STOP_TMR_L».
						data[1] = ((uint32_t)value>>8 ) & 0x0000FF;																//	Байт для записи в регистр «REG_MOT_STOP_TMR_C».
						data[2] = ((uint32_t)value>>16) & 0x0000FF;																//	Байт для записи в регистр «REG_MOT_STOP_TMR_H».
					//	Отправляем подготовленные данные в модуль:																//
						if(_writeBytes(REG_MOT_STOP_TMR_L, 3)==false){return false;}											//	Записываем 3 байта из массива «data» в модуль, начиная с регистра «REG_MOT_SET_PWM_L».
					break;																										//
				//	Если условие остановки является некорректным:																//
					default: return false; break;																				//
				}																												//
			//	Возвращаем результат:																							//
				return true;																									//
			}	return false;																									//
}																																//
																																//
//		Получение значения условия оставшегося до остановки:																	//	Возвращаемое значение:	значение условия оставшегося до остановки, тип условия зависит от параметра.
float	iarduino_I2C_Motor::getStop			(uint8_t type){																		//	Параметр:				type - тип запрашиваемого значения условия: MOT_MET / MOT_REV / MOT_SEC.
			float result = 0.0f, tmr, rev;																						//	Определяем переменную для хранения результата и переменные для получения данных из модуля.
			if(valAddr){																										//	Если модуль был инициализирован, то ...
			//	Читаем количество полных оборотов и время оставшееся до остановки:												//
				if(_readBytes(REG_MOT_STOP_REV_L,6)==false){return 0;}															//	Читаем 6 байт начиная с регистра «REG_MOT_STOP_REV_L» в массив «data».
				rev = (float)( (int32_t)data[2]<<16 | (int32_t)data[1]<<8 | (int32_t)data[0] ) / 100.0f;						//	Сохраняем количество оставшихся оборотов в переменную «rev».
				tmr = (float)( (int32_t)data[5]<<16 | (int32_t)data[4]<<8 | (int32_t)data[3] );									//	Сохраняем количество оставшегося времени в переменную «tmr».
			//	Читаем количество магнитов на роторе мотора:																	//
				if(_readBytes(REG_MOT_MAGNET,1)==false){return 0;}																//	Читаем 1 байт из регистра «REG_MOT_MAGNET» в массив «data».
				if(data[0]==0){ if(type!=MOT_SEC || !tmr ){return 0;} }															//	Если на роторе нет магнитов, то если запрошено не время до остановки или остановка задана не временем, то возвращаем 0.
			//	Возвращаем значение соответствующее указанному типу:															//
				switch(type){																									//
				//	Если запрошено расстояние оставшееся до остановки:															//
					case MOT_MET:																								//	Расстояние будет определено из радиуса и количества оставшихся оборотов.
				//	Если запрошено количество полных оборотов оставшихся до остановки:											//
					case MOT_REV:																								//
					//	Если условие остановки задано количеством оборотов:														//
						if(rev){result=rev;}																					//	Сохраняем количество оставшихся оборотов как результат «result».
					//	Если условие остановки задано временем:																	//
						else if(tmr){																							//
						//	Читаем текущую скорость:																			//
							if(_readBytes(REG_MOT_GET_RPM_L,2)==false){return 0;}												//	Читаем 2 байта начиная с регистра «REG_MOT_GET_RPM_L» в массив «data».
							result = (float) abs((int16_t)data[1]<<8 | (int16_t)data[0]); if( result==0 ){ result=1.0f; }		//	Сохраняем прочитанное значение в переменную «result» без знака.
						//	Вычисляем количество полных оборотов оставшихся до остановки:										//
							result = result * tmr / 60000.0f;																	//	Количество оборотов = скорость * время.
						}																										//
					//	Определяем расстояние по оставшемуся количеству оборотов:												//
						if( type==MOT_MET ){																					//
							result *= (2.0f * PI * radius); 																	//	Расстояние (мм) = Количество оборотов (об/мин) * длина окружности (мм).
							result /= 1000; 																					//	Преобразуем расстояние из мм в м.
						}																										//
					break;																										//
				//	Если запрошено время оставшееся до остановки:																//
					case MOT_SEC:																								//
					//	Если условие остановки задано временем:																	//
						if(tmr){result=tmr/1000;}																				//	Сохраняем оставшееся время как результат «result». Преобразовав время из мс в сек.
					//	Если условие остановки задано количеством оборотов:														//
						else if(rev){																							//
						//	Читаем текущую скорость:																			//
							if(_readBytes(REG_MOT_GET_RPM_L,2)==false){return 0;}												//	Читаем 2 байта начиная с регистра «REG_MOT_GET_RPM_L» в массив «data».
							result = (float) abs((int16_t)data[1]<<8 | (int16_t)data[0]); if( result==0 ){ result=1.0f; }		//	Сохраняем прочитанное значение в переменную «result» без знака.
						//	Вычисляем время оставшееся до остановки:															//
							result = rev * 60.0f / result;																		//	Время = количество оборотов / скорость. Так как скорость указана в об/мин, то преобразуем время в секунды, умножив результат на 60.
						}																										//
					break;																										//
				}																												//
			}																													//
		//	Возвращаем результат:																								//
			return result;																										//
}																																//
																																//
//		Установка нейтрального положения при остановке:																			//	Возвращаемое значение:	результат установки true/false.
bool	iarduino_I2C_Motor::setStopNeutral	(bool f){																			//	Параметр:				f - флаг true/false.
			if(valAddr){																										//	Если модуль был инициализирован, то ...
			//	Читаем состояние флага «MOT_FLG_STOP» из регистра флагов «REG_MOT_FLG»:											//
				if(_readBytes(REG_MOT_FLG,1)==false){return false;}																//	Читаем 1 байт регистра «REG_MOT_FLG» в массив «data».
			//	Записываем данные в регистр остановки «REG_MOT_STOP»:															//
				data[0] = (f?MOT_BIT_NEUTRAL:0) | ((data[0]&MOT_FLG_STOP)? MOT_BIT_STOP:0);										//	Устанавливаем бит «MOT_BIT_NEUTRAL», не меняя бит «MOT_BIT_STOP».
				if(_writeBytes(REG_MOT_STOP, 1)==false){return false;}															//	Записываем 1 байт из массива «data» в регистр «REG_MOT_STOP».
				delay(10);																										//	Ждём 10 мс.
			//	Возвращаем результат:																							//
				return true;																									//
			}	return false;																									//
}																																//
																																//
//		Получение флага установки нейтрального положения при остановке:															//	Возвращаемое значение:	флаг установки нейтрального положения при остановке true/false.
bool	iarduino_I2C_Motor::getStopNeutral	(void){																				//	Параметр:				отсутствует.
			if(valAddr){																										//	Если модуль был инициализирован, то ...
			//	Считываем состояние регистра флагов:																			//
				if(_readBytes(REG_MOT_FLG,1)==false){return 0;}																	//	Читаем 1 байт регистра «REG_MOT_FLG» в массив «data».
			//	Возвращаем результат:																							//
				if( data[0] & MOT_FLG_NEUTRAL ){ return true; }																	//	Если в прочитанном байте установлен флаг «MOT_FLG_NEUTRAL», то возвращаем true.
			}	return false;																									//
}																																//
																																//
//		Установка направления вращения вала:																					//	Возвращаемое значение:	результат установки true/false.
bool	iarduino_I2C_Motor::setDirection	(bool flgCKW){																		//	Параметры:				flgCKW - флаг вращения вала по ч.с. при положительной скорости.
			if(valAddr){																										//	Если модуль был инициализирован, то ...
			//	Готовим данные:																									//
				if(_readBytes(REG_BITS_2,1)==false){return 0;}																	//	Читаем 1 байт регистра «REG_BITS_2» в массив «data».
				data[0] = (flgCKW?MOT_BIT_DIR_CKW:0) | (data[0]&(~MOT_BIT_DIR_CKW));											//	Редактируем бит «MOT_BIT_DIR_CKW» оставив остальные биты без изменений.
			//	Отправляем подготовленные данные в модуль:																		//
				if(_writeBytes(REG_BITS_2, 1)==false){return false;}															//	Записываем 1 байт из массива «data» в регистр «REG_BITS_2».
			//	Возвращаем результат:																							//
				return true;																									//
			}	return false;																									//
}																																//
																																//
//		Получение направления вращения вала:																					//	Возвращаемое значение:	флаг вращения вала по ч.с. при положительной скорости true/false.
bool	iarduino_I2C_Motor::getDirection	(void){																				//	Параметр:				отсутствует.
			if(valAddr){																										//	Если модуль был инициализирован, то ...
			//	Считываем значение регистра битов:																				//
				if(_readBytes(REG_BITS_2,1)==false){return 0;}																	//	Читаем 1 байт регистра «REG_BITS_2» в массив «data».
			//	Возвращаем результат:																							//
				return (bool)( data[0] & MOT_BIT_DIR_CKW );																		//	Возвращаем состояние бита «MOT_BIT_DIR_CKW».
			}	return false;																									//
}																																//
																																//
//		Установка флагов инверсии механизма:																					//	Возвращаемое значение:	результат установки true/false.
bool	iarduino_I2C_Motor::setInvGear		(bool invRDR, bool invPIN){															//	Параметры:				invRDR - флаг инверсии вращения редуктора, invPIN - флаг инверсии полярности мотора.
			if(valAddr){																										//	Если модуль был инициализирован, то ...
			//	Готовим данные:																									//
				if(_readBytes(REG_BITS_2,1)==false){return 0;}																	//	Читаем 1 байт регистра «REG_BITS_2» в массив «data».
				data[0] = (invRDR?MOT_BIT_INV_RDR:0)|(invPIN?MOT_BIT_INV_PIN:0)|(data[0]&(~(MOT_BIT_INV_RDR|MOT_BIT_INV_PIN)));	//	Редактируем биты «MOT_BIT_INV_RDR» и «MOT_BIT_INV_PIN» оставив остальные биты без изменений.
			//	Отправляем подготовленные данные в модуль:																		//
				if(_writeBytes(REG_BITS_2, 1)==false){return false;}															//	Записываем 1 байт из массива «data» в регистр «REG_BITS_2».
			//	Возвращаем результат:																							//
				return true;																									//
			}	return false;																									//
}																																//
																																//
//		Получение флагов инверсии механизма:																					//	Возвращаемое значение:	байт с флагом инверсии вращения редуктора (1 бит байта) и флагом инверсии полярности мотора (0 бит байта).
uint8_t	iarduino_I2C_Motor::getInvGear	(void){																					//	Параметр:				отсутствует.
			if(valAddr){																										//	Если модуль был инициализирован, то ...
			//	Считываем значение регистра битов:																				//
				if(_readBytes(REG_BITS_2,1)==false){return 0;}																	//	Читаем 1 байт регистра «REG_BITS_2» в массив «data».
			//	Возвращаем результат:																							//
				return (( data[0] & MOT_BIT_INV_RDR )? bit(1):0) | (( data[0] & MOT_BIT_INV_PIN )? bit(0):0);					//	Возвращаем байт содержащий состояние битов «MOT_BIT_INV_RDR» (1 бит байта) и «MOT_BIT_INV_PIN» (0 бит байта).
			}	return false;																									//
}																																//
																																//
//		Получение пройденного пути или количества совершённых полных оборотов:													//	Возвращаемое значение:	значение пройденного пути или количества совершённых полных оборотов, тип значения зависит от параметра.
float	iarduino_I2C_Motor::getSum			(uint8_t type){																		//	Параметр:				type - тип запрашиваемого значения: MOT_MET / MOT_REV.
			float result = 0.0f;																								//	Определяем переменную для хранения результата.
			if(valAddr){																										//	Если модуль был инициализирован, то ...
			//	Проверяем запрошенный тип:																						//
				if( type==MOT_MET || type==MOT_REV ){																			//	Если запрошенный тип указан верно, то ...
				//	Читаем количество совершённых оборотов:																		//
					if(_readBytes(REG_MOT_GET_REV_L, 3)==false ){ return 0;}													//	Читаем 3 байта начиная с регистра «REG_MOT_GET_REV_L» в массив «data».
					result = (float)( (int32_t)data[2]<<16 | (int32_t)data[1]<<8 | (int32_t)data[0] )/100;						//	Получаем количество совершённых полных оборотов.
				//	Определяем расстояние по количеству оборотов:																//
					if( type==MOT_MET ){																						//
						result *= (2.0f * PI * radius); 																		//	Расстояние (мм) = Количество оборотов (об/мин) * длина окружности (мм).
						result /= 1000; 																						//	Преобразуем расстояние из мм в м.
					}																											//
				}																												//
			}																													//
		//	Возвращаем результат:																								//
			return result;																										//
}																																//
																																//
//		Установка номинального напряжения мотора:																				//	Возвращаемое значение:	результат установки true/false.
bool	iarduino_I2C_Motor::setVoltage		(float motVoltage){																	//	Параметр:				motVoltage - напряжение в В.
			if(valAddr){																										//	Если модуль был инициализирован, то ...
			//	Готовим данные:																									//
				if( motVoltage > 25.5 ){ motVoltage = 25.5; }																	//
				if( motVoltage < 0    ){ motVoltage = 0.0;  }																	//
				data[0] = (uint8_t)(motVoltage*10);																				//	Преобразуем значение в целое количество десятых долей Вольт.
			//	Отправляем подготовленные данные в модуль:																		//
				if(_writeBytes(REG_MOT_VOLTAGE, 1)==false){return false;}														//	Записываем 1 байт из массива «data» в регистр «REG_MOT_VOLTAGE».
			//	Возвращаем результат:																							//
				return true;																									//
			}	return false;																									//
}																																//
																																//
//		Получение номинального напряжения мотора:																				//	Возвращаемое значение:	напряжение в В.
float	iarduino_I2C_Motor::getVoltage		(void){																				//	Параметр:				отсутствует.
			if(valAddr){																										//	Если модуль был инициализирован, то ...
			//	Читаем напряжение из модуля:																					//
				if(_readBytes(REG_MOT_VOLTAGE,1)==false){return 0;}																//	Читаем 1 байт регистра «REG_MOT_VOLTAGE» в массив «data».
			//	Возвращаем результат:																							//
				return (float)data[0]/10.0f;																					//	Возвращаем напряжение получив его из целого количества десятых долей Вольт.
			}	return 0.0f;																									//
}																																//
																																//
//		Установка номинальной скорости вращения вала редуктора:																	//	Возвращаемое значение:	результат установки true/false.
bool	iarduino_I2C_Motor::setNominalRPM	(uint16_t value){																	//	Параметр:				value - скорость вращения вала редуктора от 0 до 65'535 об/мин.
			if(valAddr){																										//	Если модуль был инициализирован, то ...
			//	Готовим данные:																									//
				data[0] = (uint8_t)( value     & 0x00FF);																		//	Байт для записи в регистр «REG_MOT_NOMINAL_RPM_L».
				data[1] = (uint8_t)((value>>8) & 0x00FF);																		//	Байт для записи в регистр «REG_MOT_NOMINAL_RPM_H».
			//	Отправляем подготовленные данные в модуль:																		//
				if(_writeBytes(REG_MOT_NOMINAL_RPM_L, 2)==false){return false;}													//	Записываем 2 байта из массива «data» в модуль начиная с регистра «REG_MOT_NOMINAL_RPM_L».
			//	Возвращаем результат:																							//
				return true;																									//
			}	return false;																									//
}																																//
																																//
//		Получение номинальной скорости вращения вала редуктора:																	//	Возвращаемое значение:	скорость вращения вала редуктора от 0 до 65'535 об/мин.
uint16_t iarduino_I2C_Motor::getNominalRPM	(void){																				//	Параметр:				отсутствует.
			if(valAddr){																										//	Если модуль был инициализирован, то ...
			//	Читаем номинальную скорость вращения из модуля:																	//
				if(_readBytes(REG_MOT_NOMINAL_RPM_L,2)==false){return 0;}														//	Читаем 2 байта начиная с регистра «REG_MOT_NOMINAL_RPM_L» в массив «data».
			//	Возвращаем результат:																							//
				return (int16_t)data[1]<<8 | (int16_t)data[0];																	//	Возвращаем скорость вращения вала редуктора в об/мин.
			}	return 0;																										//
}																																//
																																//
//		Сохранение флагов инверсии механизма, количества магнитов и передаточного отношения в Flash память:						//	Возвращаемое значение:	результат сохранения true/false.
bool	iarduino_I2C_Motor::saveManufacturer(uint64_t code){																	//	Параметр:				code - код разработчика.
			if(valAddr){																										//	Если модуль был инициализирован, то ...
			//	Ждём:																											//
				while( (millis()>=timReset) && (millis()<(timReset+150)) ){;}													//	Заперщаем сохранять данные в FLASH в течении 150 мс после перезагрузки (в т.ч. инициализации) модуля.
			//	Готовим данные для передачи:																					//
				data[0] = (code    ) & 0xFFLL;																					//	Байт для записи в регистр «REG_MANUFACTURER».
				data[1] = (code>> 8) & 0xFFLL;																					//	Байт для записи в регистр «REG_MANUFACTURER».
				data[2] = (code>>16) & 0xFFLL;																					//	Байт для записи в регистр «REG_MANUFACTURER».
				data[3] = (code>>24) & 0xFFLL;																					//	Байт для записи в регистр «REG_MANUFACTURER».
				data[4] = (code>>32) & 0xFFLL;																					//	Байт для записи в регистр «REG_MANUFACTURER».
			//	Отправляем подготовленные данные в модуль:																		//
				if(_writeBytes(11,5)==false){return false;}																		//	Записываем 5 байт в регистр «REG_MANUFACTURER».
				delay(50);																										//	Ждём 10 мс.
			//	Возвращаем результат:																							//
				return true;																									//
			}	return false;																									//
}																																//
																																//
//		Чтение данных из регистров в массив data:																				//	Возвращаемое значение:	результат чтения (true/false).
bool	iarduino_I2C_Motor::_readBytes		(uint8_t reg, uint8_t sum){															//	Параметры:				reg - номер первого регистра, sum - количество читаемых байт.
			bool	result=false;																								//	Определяем флаг       для хранения результата чтения.
			uint8_t	sumtry=10;																									//	Определяем переменную для подсчёта количества оставшихся попыток чтения.
			do{	result = readBytes(valAddr, reg, data, sum);															//	Считываем из модуля valAddr, начиная с регистра reg, в массив data, sum байт.
				sumtry--;	if(!result){delay(1);}																				//	Уменьшаем количество попыток чтения и устанавливаем задержку при неудаче.
			}	while		(!result && sumtry>0);																				//	Повторяем чтение если оно завершилось неудачей, но не более sumtry попыток.
			delayMicroseconds(500);																								//	Между пакетами необходимо выдерживать паузу.
			return result;																										//	Возвращаем результат чтения (true/false).
}																																//
																																//
//		Запись данных в регистры из массива data:																				//	Возвращаемое значение:	результат записи (true/false).
bool	iarduino_I2C_Motor::_writeBytes	(uint8_t reg, uint8_t sum, uint8_t num){												//	Параметры:				reg - номер первого регистра, sum - количество записываемых байт, num - номер первого элемента массива data.
			bool	result=false;																								//	Определяем флаг       для хранения результата записи.
			uint8_t	sumtry=10;																									//	Определяем переменную для подсчёта количества оставшихся попыток записи.
			do{	result = writeBytes(valAddr, reg, &data[num], sum);														//	Записываем в модуль valAddr начиная с регистра reg, sum байи из массива data начиная с элемента num.
				sumtry--;	if(!result){delay(1);}																				//	Уменьшаем количество попыток записи и устанавливаем задержку при неудаче.
			}	while		(!result && sumtry>0);																				//	Повторяем запись если она завершилась неудачей, но не более sumtry попыток.
			delay(10);																											//	Ждём применения модулем записанных данных.
			return result;																										//	Возвращаем результат записи (true/false).
}																																//
																																//
void iarduino_I2C_Motor::changeBus(std::string bus)
{
		iarduino_I2C::changeBus(bus);
}
