//! FP300KZ
/*!
Для принтеров: FP-300KZ, FP-1000 ФKZ
\author Иванов Игорь М.
\file FP300KZ.cpp
*/
//---------------------------------------------------------------------------
#pragma hdrstop

#include "stdafx.h"


#include "FP300KZ.h"
#include <stdTools.h>
#include <mathTools.h>
#include <sstream>

#include <iostream>
#include <fstream>
#include <locale>
//#include <string>
#include <vector>
#include <math.h>

#include <direct.h> //mkdir

//#include <unistd.h>
//#include <pthread.h>
//#include <stdlib.h>

#if defined( __WXMSW__ ) //Если кроссплатформкннное приложение 
	#include <wx/wx.h>
#endif // __WXMSW__
#include <windows.h> //Для Sleep функции
//---------------------------------------------------------------------------
//#pragma package(smart_init)
//---------------------------------------------------------------------------
//Добавил когда делал кросплатформеного кассирра
//typedef unsigned long       DWORD;
//---------------------------------------------------------------------------
//Сохранить лог в текстовый файл
/*bool saveLog(std::string FileName, std::string Text)
{
	try
	{
		for(uint4 i=0;i<Text.length();i++) 
		{	if(Text[i]=='\n') Text[i]=' '; //Чтоб в 1 строку было
		}
		Text="["+getDateTime()+"] "+Text; //Добавляем дату
		std::string path=getAppPathA()+std::string("logs\\"); //Путь к файлу

		_mkdir(path.c_str());
		path+=FileName+"_"+getStrDate()+".log";
#if defined( _BORLAND )
		std::ofstream file(path.c_str(),std::ios::app);
		file << Text.c_str() << std::endl;
		file.close();
#endif
#if defined( _VC )
		FILE* pfile = fopen ( path.c_str(), "a" ); //Для юникода _wfopen
		if(pfile!=NULL)
		{	fputs( Text.c_str() , pfile );
			fputs( "\n" , pfile );
			fclose( pfile );
		}
#endif
	}catch(...)
	{	return false;
	}
	return true;
}*/
//---------------------------------------------------------------------------
///Постройка CRC специального для этого принтера
//BufStart - С какого байта начинать подсчёт
//BufEnd - По какой байт считать (не длина)
unsigned int MakeCRC_FP300KZ(unsigned char* Buf, unsigned int BufStart, unsigned int BufEnd)
{
	unsigned int cs = 0;
	for (unsigned int i = BufStart; i<BufEnd; i++)
		cs += Buf[i];

	unsigned int result = 0;
	unsigned char *mas = (unsigned char *)&result;
	mas[0] = ((cs >> 0x0C) & 0x0F) + 0x30;
	mas[1] = ((cs >> 0x08) & 0x0F) + 0x30;
	mas[2] = ((cs >> 0x04) & 0x0F) + 0x30;
	mas[3] = ((cs >> 0x00) & 0x0F) + 0x30;
	return result;
}
//---------------------------------------------------------------------------
StatusFP300KZ::StatusFP300KZ()
{
	for(int i=0;i<8;i++)
		for(int j=0;j<6;j++) s[j][i]=false;
}
//---------------------------------------------------------------------------
void StatusFP300KZ::SetStatus(uint1* status)
{
	//переписываем статус в переменные для удобства
	//Байт 0: Общее предназначение
	s[0][7]=getBitVal(status[0],7); //0.7 Резерв.
	s[0][6]=getBitVal(status[0],6); //0.6 Открыт чек возврата.
	s[0][5]=getBitVal(status[0],5); //0.5 Признак ошибки (флаги, помеченные знаком # в байтах 0, 1, 2).
	s[0][4]=getBitVal(status[0],4); //0.4 # Печатающее устройство неисправно.
	s[0][3]=getBitVal(status[0],3); //0.3 Не подключен клиентский дисплей.
	s[0][2]=getBitVal(status[0],2); //0.2 Таймер не установлен.
	s[0][1]=getBitVal(status[0],1); //0.1 #	Неправильный код полученной команды.
	s[0][0]=getBitVal(status[0],0); //0.0 #	Синтаксическая ошибка в полученных данных.

	//Байт 1: Общее предназначение
	s[1][7]=getBitVal(status[1],7); //1.7 Резерв.
	s[1][6]=getBitVal(status[1],6); //1.6 Электронная контрольная лента напечатана.
	s[1][5]=getBitVal(status[1],5); //1.5 Крышка принтера открыта.
	s[1][4]=getBitVal(status[1],4); //1.4 # После включения принтера обнаружены нарушения данных в ОЗУ.
	s[1][3]=getBitVal(status[1],3); //1.3 # Батарея разряжена (Таймер реального времени в состоянии RESET).
	s[1][2]=getBitVal(status[1],2); //1.2 # ОЗУ обнулено.
	s[1][1]=getBitVal(status[1],1); //1.1 # Команда не может быть выполнена в данном фискальном режиме.
	s[1][0]=getBitVal(status[1],0); //1.0 Переполнение суммы. Статус 1.1 также будет установлен и команда не поменяет данные в принтере.

	//Байт 2: Общее предназначение
	s[2][7]=getBitVal(status[2],7); //2.7 Резерв.
	s[2][6]=getBitVal(status[2],6); //2.6 Электронная контрольная лента не пуста.
	s[2][5]=getBitVal(status[2],5); //2.5 Открыт служебный чек.
	s[2][4]=getBitVal(status[2],4); //2.4 Электронная контрольная лента заполнена на 90%.
	s[2][3]=getBitVal(status[2],3); //2.3 Открыт фискальный чек или чек возврата.
	s[2][2]=getBitVal(status[2],2); //2.2 Электронная контрольная лента заполнена.
	s[2][1]=getBitVal(status[2],1); //2.1 Недостаточно ленты.
	s[2][0]=getBitVal(status[2],0); //2.0 # Закончилась лента. Если флаг установлен во время выполнения команды печати, то выполнение команды будет остановлено и статус принтера не изменится.

	//Байт 3: Состояние конфигурационных переключателей
	s[3][7]=getBitVal(status[3],7); //3.7 Резерв.
	s[3][6]=getBitVal(status[3],6); //3.6 =1 Если переключатель Sw7 в положении ON. Скорость передачи данных в серийный порт.
	s[3][5]=getBitVal(status[3],5); //3.5 =1 Если переключатель Sw6 в положении ON. Скорость передачи данных в серийный порт.
	s[3][4]=getBitVal(status[3],4); //3.4 =1 Если переключатель Sw5 в положении ON. Не используется.
	s[3][3]=getBitVal(status[3],3); //3.3 =1 Если переключатель Sw4 в положении ON. Работа дисплея в кодовой таблице 1251 (Windows Cyrillic).
	s[3][2]=getBitVal(status[3],2); //3.2 =1 Если переключатель Sw3 в положении ON. Задает режим "прозрачный дисплей".
	s[3][1]=getBitVal(status[3],1); //3.1 =1 Если переключатель Sw2 в положении ON. Не используется.
	s[3][0]=getBitVal(status[3],0); //3.0 =1 Если переключатель Sw1 в положении ON. Разрешает автоматическую обрезку бумаги.

	//Байт 4: Фискальная память
	s[4][7]=getBitVal(status[4],7); //4.7 Резерв.
	s[4][6]=getBitVal(status[4],6); //4.6 Резерв.
	s[4][5]=getBitVal(status[4],5); //4.5 Признак ошибки (флаги, помеченные знаком * в байтах 4 и 5).
	s[4][4]=getBitVal(status[4],4); //4.4 * Фискальная память заполнена.
	s[4][3]=getBitVal(status[4],3); //4.3 В фискальной памяти осталось меньше 50 свободных полей.
	s[4][2]=getBitVal(status[4],2); //4.2 Запрограммирован заводской номер принтера.
	s[4][1]=getBitVal(status[4],1); //4.1 Запрограммированы налоговые номера.
	s[4][0]=getBitVal(status[4],0); //4.0 * Ошибка записи в фискальную память.

	//Байт 5: Фискальная память
	s[5][7]=getBitVal(status[5],7); //5.7 Резерв.
	s[5][6]=getBitVal(status[5],6); //5.6 Резерв.
	s[5][5]=getBitVal(status[5],5); //5.5 Не используется.
	s[5][4]=getBitVal(status[5],4); //5.4 Задана хотя бы одна налоговая ставка.
	s[5][3]=getBitVal(status[5],3); //5.3 Фискальный режим включен.
	s[5][2]=getBitVal(status[5],2); //5.2 * Последняя запись в фискальную память не успешна.
	s[5][1]=getBitVal(status[5],1); //5.1 Фискальная память отформатирована.
	s[5][0]=getBitVal(status[5],0); //5.0 * Фискальная память установлена в режим ТОЛЬКО ЧТЕНИЕ (заблокирована).
}
//---------------------------------------------------------------------------
//Получить статусы в виде строки
std::string StatusFP300KZ::getStatus()
{
	std::string str="";
	for(int i=0;i<8;i++)
		for(int j=0;j<6;j++)
			if(s[j][i]) str+="1"; else str+="0";
	return str;
}
//---------------------------------------------------------------------------
//Ошибки генерю сам по статусам
std::string FP300KZ::getErrorDesc(int ResultCode)
{
	std::string result="";
	switch( ResultCode )
	{
		//Ошибки взятые у штрихов
		case 0:   result="OK"; break;
		case 4:   result="Синтаксическая ошибка в полученных данных!"; break;
		case 5:   result="Нет запрошенных данных!"; break;
		case 78:  result="Смена превысила 24 часа!"; break;
		case 79:  result="Неверный пароль!"; break;
		case 103: result="Нет связи с ФП!"; break;
		case 192: result="Таймер не установлен!"; break;

		//Те ошибки которые я сам придумал
		case 500: result="Печатающее устройство неисправно!"; break;
		case 501: result="Неправильный код полученной команды!"; break;
		case 502: result="После включения принтера обнаружены нарушения данных в ОЗУ!"; break;
		case 503: result="Батарея разряжена (Таймер реального времени в состоянии RESET)!"; break;
		case 504: result="ОЗУ обнулено!"; break;
		case 505: result="Команда не может быть выполнена в данном фискальном режиме!"; break;
		case 506: result="Ошибка записи в фискальную память!"; break;
		case 507: result="Фискальная память заполнена!"; break;
		case 508: result="Закончилась лента!"; break;
		case 509: result="Уже открыт фискальный чек или чек возврата!"; break;
		case 510: result="Крышка принтера открыта!"; break;
		case 511: result="Не возможно закрыть чек доплатите денег!"; break;
		//При фискализации
		case 512: result="Не используется!"; break;
		case 513: result="Проведено максимальное количество перерегистраций!"; break;
		case 514: result="Не установлен заводской номер (фискализация) или не верный пароль налогового инспектора (перерегистрация)!"; break;
		case 515: result="Некорректный заводской номер!"; break;
		case 516: result="Открыт фискальный или нефискальный чек!"; break;
		case 517: result="Отпечатаны фискальные чеки после Z-отчета. Необходимо снять Z-отчет!"; break;
		case 518: result="Не установлены ставки НДС!"; break;
		case 519: result="Не включена ни одна группа НДС!"; break;
		case 520: result="Не установлены дата и время или фискальная память в режиме \"ТОЛЬКО ДЛЯ ЧТЕНИЯ\"!"; break;

		default:
			result="Нет описания ошибки!";
	}
	return result;
}
//---------------------------------------------------------------------------
std::string FP300KZ::getLastErrorDest()
{
	return getErrorDesc(ResultCode());
}
//---------------------------------------------------------------------------
//Генерим из статусов код ошибки в виде цифры
int FP300KZ::ResultCode()
{
	if(CommandName==fcCancelFiscalInv) return 0; //При отмене чека не выдавать ошибку хоть он и не был открыть

	if(CommandName==fcFiscalization)
	{
		if(m_ErrCode=="1") return 512; //'1' Не используется
		if(m_ErrCode=="2") return 513; //'2' Проведено максимальное количество перерегистраций.
		if(m_ErrCode=="3") return 514; //'3' Не установлен заводской номер (фискализация) или не верный пароль налогового инспектора (перерегистрация).
		if(m_ErrCode=="4") return 515; //'4' Некорректный заводской номер.
		if(m_ErrCode=="5") return 516; //'5' Открыт фискальный или нефискальный чек.
		if(m_ErrCode=="6") return 517; //'6' Отпечатаны фискальные чеки после Z-отчета. Необходимо снять Z-отчет.
		if(m_ErrCode=="7") return 518; //'7' Не установлены ставки НДС.
		if(m_ErrCode=="8") return 519; //'8' Не включена ни одна группа НДС.
		if(m_ErrCode=="9") return 520; //'9' Не установлены дата и время или фискальная память в режиме "ТОЛЬКО ДЛЯ ЧТЕНИЯ".
		m_ErrCode="";
	}

//1 1 Неисправен накопитель ФП 1, ФП 2 или часы
//2 2 Отсутствует ФП 1
//3 3 Отсутствует ФП 2
	if(Status->s[0][0]) return 4; //0x04 Некорректные параметры в команде обращения к ФП
/*5 5 Нет запрошенных данных
6 6 ФП в режиме вывода данных
7 7 Некорректные параметры в команде для данной реализации ФП
8 8 Команда не поддерживается в данной реализации ФП
9 9 Некорректная длина команды
0A 10 Формат данных не BCD
0B 11 Неисправна ячейка памяти ФП при записи итога
11 17 Не введена лицензия
12 18 Заводской номер уже введен
13 19 Текущая дата меньше даты последней записи в ФП
14 20 Область сменных итогов ФП переполнена
15 21 Смена уже открыта
16 22 Смена не открыта
17 23 Номер первой смены больше номера последней смены
18 24 Дата первой смены больше даты последней смены
19 25 Нет данных в ФП
1A 26 Область перерегистраций в ФП переполнена
1B 27 Заводской номер не введен
1C 28 В заданном диапазоне есть поврежденная запись
1D 29 Повреждена последняя запись сменных итогов
1F 31 Отсутствует память регистров
20 32 Переполнение денежного регистра при добавлении
21 33 Вычитаемая сумма больше содержимого денежного регистра
22 34 Неверная дата
23 35 Нет записи активизации
24 36 Область активизаций переполнена
25 37 Нет активизации с запрашиваемым номером
33 51 Некорректные параметры в команде
35 53 Некорректный параметр при данных настройках
36 54 Некорректные параметры в команде для данной реализации ФР
37 55 Команда не поддерживается в данной реализации ФР
38 56 Ошибка в ПЗУ +
39 57 Внутренняя ошибка ПО ФР
3A 58 Переполнение накопления по надбавкам в смене
3C 60 ЭКЛЗ: неверный регистрационный номер
3E 62 Переполнение накопления по секциям в смене
3F 63 Переполнение накопления по скидкам в смене
40 64 Переполнение диапазона скидок
41 65 Переполнение диапазона оплаты наличными
42 66 Переполнение диапазона оплаты типом 2
43 67 Переполнение диапазона оплаты типом 3
44 68 Переполнение диапазона оплаты типом 4
45 69 Cумма всех типов оплаты меньше итога чека
46 70 Не хватает наличности в кассе
47 71 Переполнение накопления по налогам в смене
48 72 Переполнение итога чека
4A 74 Открыт чек - операция невозможна
4B 75 Буфер чека переполнен
4C 76 Переполнение накопления по обороту налогов в смене
4D 77 Вносимая безналичной оплатой сумма больше суммы чека
4E 78 Смена превысила 24 часа
*/
	//if(CommandName==fcOpenFiscalInv && Password=="") return 79; //4F 79 Неверный пароль

/*50 80 Идет печать предыдущей команды
51 81 Переполнение накоплений наличными в смене
52 82 Переполнение накоплений по типу оплаты 2 в смене
53 83 Переполнение накоплений по типу оплаты 3 в смене
54 84 Переполнение накоплений по типу оплаты 4 в смене
56 86 Нет документа для повтора
57 87 ЭКЛЗ: количество закрытых смен не совпадает с ФП
58 88 Ожидание команды продолжения печати
59 89 Документ открыт другим оператором
5B 91 Переполнение диапазона надбавок
5C 92 Понижено напряжение 24В
5D 93 Таблица не определена
5E 94 Некорректная операция
5F 95 Отрицательный итог чека
60 96 Переполнение при умножении
61 97 Переполнение диапазона цены
62 98 Переполнение диапазона количества
63 99 Переполнение диапазона отдела
64 100 ФП отсутствует +
65 101 Не хватает денег в секции
66 102 Переполнение денег в секции*/
	if(!cPort->isOpen()) return 103; //0x67 Ошибка связи с ФП +
/*68 104 Не хватает денег по обороту налогов
69 105 Переполнение денег по обороту налогов
6A 106 Ошибка питания в момент ответа по I2C
6B 107 Нет чековой ленты
6C 108 Нет контрольной ленты
6D 109 Не хватает денег по налогу
6E 110 Переполнение денег по налогу
6F 111 Переполнение по выплате в смене
70 112 Переполнение ФП
71 113 Ошибка отрезчика +
72 114 Команда не поддерживается в данном подрежиме
73 115 Команда не поддерживается в данном режиме
74 116 Ошибка ОЗУ
75 117 Ошибка питания +
76 118 Ошибка принтера: нет импульсов с тахогенератора +
77 119 Ошибка принтера: нет сигнала с датчиков +
78 120 Замена ПО
79 121 Замена ФП
7A 122 Поле не редактируется
7B 123 Ошибка оборудования
7C 124 Не совпадает дата
7D 125 Неверный формат даты
7E 126 Неверное значение в поле длины
7F 127 Переполнение диапазона итога чека
80 128 Ошибка связи с ФП +
81 129 Ошибка связи с ФП +
82 130 Ошибка связи с ФП +
83 131 Ошибка связи с ФП +
84 132 Переполнение наличности
85 133 Переполнение по продажам в смене
86 134 Переполнение по покупкам в смене
87 135 Переполнение по возвратам продаж в смене
88 136 Переполнение по возвратам покупок в смене
89 137 Переполнение по внесению в смене
8A 138 Переполнение по надбавкам в чеке
8B 139 Переполнение по скидкам в чеке
8C 140 Отрицательный итог надбавки в чеке
8D 141 Отрицательный итог скидки в чеке
8E 142 Нулевой итог чека
8F 143 Касса не фискализирована
90 144 Поле превышает размер, установленный в настройках
91 145 Выход за границу поля печати при данных настройках шрифта
92 146 Наложение полей
93 147 Восстановление ОЗУ прошло успешно
94 148 Исчерпан лимит операций в чеке
A0 160 Ошибка связи с ЭКЛЗ +
A1 161 ЭКЛЗ отсутствует +
A2 162 ЭКЛЗ: Некорректный формат или параметр команды
A3 163 Некорректное состояние ЭКЛЗ
A4 164 Авария ЭКЛЗ
A5 165 Авария КС в составе ЭКЛЗ
A6 166 Исчерпан временной ресурс ЭКЛЗ
A7 167 ЭКЛЗ переполнена
A8 168 ЗКЛЗ: Неверные дата и время
A9 169 ЭКЛЗ: Нет запрошенных данных
AA 170 Переполнение ЭКЛЗ (отрицательный итог документа)
B0 176 ЭКЛЗ: Переполнение в параметре количество
B1 177 ЭКЛЗ: Переполнение в параметре сумма
B2 178 ЭКЛЗ: Уже активизирована*/
	if(Status->s[0][2]) return 192; //0xC0 Контроль даты и времени (подтвердите дату и время)
/*C1 193 ЭКЛЗ: суточный отчёт с гашением прервать нельзя
C2 194 Превышение напряжения в блоке питания
C3 195 Несовпадение итогов чека и ЭКЛЗ
C4 196 Несовпадение номеров смен
С5 197 Буфер подкладного документа пуст
C6 198 Подкладной докуемнт отсутствует
C7 199 Поле не редактируется в данном режиме*/

	//Свои коды ошибок потому что немогу найти в списке выше этого значения
	if(Status->s[0][4]) return 500; //Печатающее устройство неисправно.
	if(Status->s[0][1]) return 501; //Неправильный код полученной команды.
	if(Status->s[1][4]) return 502; //После включения принтера обнаружены нарушения данных в ОЗУ.
	if(Status->s[1][3]) return 503; //Батарея разряжена (Таймер реального времени в состоянии RESET).
	if(Status->s[1][2]) return 504; //ОЗУ обнулено.
	if(Status->s[1][1])
	{
		if(CommandName==fcOpenFiscalInv && Status->s[2][3]) return 509; else //Уже открыт фискальный чек или чек возврата.
		if(CommandName==fcCloseFiscalInv)
		{
			bool Open; int Items; double Amount=0,Tender=0;
			FiscalTransactionsStatus(Open,Items,Amount,Tender);
			CommandName=fcCloseFiscalInv; //Чтоб при следующем вызове не обнолилось
			Status->s[1][1]=true; //Чтоб по прежнему была ошибка
			if(Open && Amount-(Tender+0.002)>0) return 511; //"Не возможно закрыть чек доплатите денег!"
		}else
		if(CommandName==fcOpenFiscalInv)
		{
			//Проверяем сколько времени прошло с начала смены
			m_SaveLog=false;
			int sec;
			if(GetTimeZReport(sec).ErrorCode==0 && sec>24*60*60)
			{
				Status->s[1][1]=true;
				CommandName=fcOpenFiscalInv; //Чтоб не изменилось
				return 78;
			}
			m_SaveLog=true;
		}
		return 505; //Команда не может быть выполнена в данном фискальном режиме.
	}
	if(Status->s[4][0]) return 506; //Ошибка записи в фискальную память.
	if(Status->s[4][4]) return 507; //Фискальная память заполнена.
	if(Status->s[2][0]) return 508; //Закончилась лента.
	//509 занят "Уже открыт фискальный чек или чек возврата."
	if(Status->s[1][5]) return 510; //Крышка принтера открыта!
	//511 занят "Не возможно закрыть чек доплатите денег!"
	//512 Не используется
	//513 Проведено максимальное количество перерегистраций.
	//514 Не установлен заводской номер (фискализация) или не верный пароль налогового инспектора (перерегистрация).
	//515 Некорректный заводской номер.
	//516 Открыт фискальный или нефискальный чек.
	//517 Отпечатаны фискальные чеки после Z-отчета. Необходимо снять Z-отчет.
	//518 Не установлены ставки НДС.
	//519 Не включена ни одна группа НДС.
	//520 Не установлены дата и время или фискальная память в режиме "ТОЛЬКО ДЛЯ ЧТЕНИЯ".


	return 0;// m_ErrorCode;
}
//---------------------------------------------------------------------------
FP300KZ::FP300KZ()
{
	cPort=new ComPort();
	Status=new StatusFP300KZ();
	CheckCount=0;
	FrameSeqNumber=0x20;

	PrinterName="none";
	m_Dots=0;
	m_ErrCode="this";
	m_SaveLog=true;
}
//---------------------------------------------------------------------------
FP300KZ::~FP300KZ()
{
	delete cPort;
}
//---------------------------------------------------------------------------
//Получить следующий порядковый номер запроса.
uint1 FP300KZ::getNextSeq()
{
	FrameSeqNumber++;
	if(FrameSeqNumber == 0x20 + 30) FrameSeqNumber = 0x20;
	if(FrameSeqNumber < 0x20) FrameSeqNumber = 0x20;
	return FrameSeqNumber;
}
//---------------------------------------------------------------------------
//Задержка в миллисекундах
void FP300KZ::SleepMs(int ms) 
{
#ifdef __WXMSW__
	wxThread::Sleep(60);
#endif // __WXMSW__
#if defined(WIN32) || defined(_WINDOWS) || defined(_BORLAND)
	Sleep(60);
#endif
}
//---------------------------------------------------------------------------
/// Пакуем и отправляем сообщение на принтер потом ждём ответа
///\param msg Ссылка на первый символ массива символов
///\param size Размер массива
///\param answer Ответ в виде строки
///\Если результат true то всё ок
/*bool FP300KZ::SendPMessage(uint8_t* msg,uint32_t msize,std::string &answer)
{
	//m_ErrorCode=0; //Обнуляем код ошибки перед выполнением команды
	if(!cPort->isOpen()) { return false; }

	CommandName=msg[3]; //Сохраняем номер последней команды
	for(int i=0;i<sizeof(ReadAr);i++) ReadAr[i]=0; //Очищаем буфер ответа.

	bool result=false; //Хоть чтото получили
	getNextSeq();//Увеличим на 1
	if(cPort->isOpen())
	{
		for(int i=0;i<5;i++) //Если после 5 попыток нет ответа то принтер неисправен...
		{
			//Отправляю запрос на принтер
			msg[1]=0x20+msize-1; //Размер
			msg[2]=FrameSeqNumber;
			unsigned int crc=MakeCRC_FP300KZ(msg,1,msize);
			cPort->Write(msg,msize); //Отправляем данные
			cPort->Write(&crc,4); //Контрольная сумма
			cPort->WriteChar(0x03); //Признак конца сообщения

			//Пытаюсь принять ответ от принтера
			bool isOk=true;
			int j=0;
			while(j<9) //9*60=540 в цикле чтоб ждать ответа не более 500ms по документации
			{
				uint1 start=0;
				unsigned long BytesRead=cPort->Read(&start,sizeof(start)); //читаемм байт (ответ должен прити в течении 60 ms хост должен ждать 500 ms)
				if(BytesRead==0) //Ничего не прочитал
				{	
					SleepMs(60);
					isOk=false;
					//m_ErrorCode=103; //Код ошибки
					break;
				}else
				if(start==0x15) //NACK ошибка в контрольной сумме запрос заново отправить
				{
					SleepMs(60);
					isOk=false;
					break;
				}else
				if(start==0x16) //SYN комманда подождать данные посылается каждые 60ms
				{	
					SleepMs(60);
					j=0; //Начинаем ждать по новой (может зациклится)
				}else
				if(start==0x01) //Дочитываем
				{
					ReadAr[0]=start; //Для подсчёта CRC
					uint1 size=0;
					cPort->Read(&size,1); //Рзамер данных в байтах
					ReadAr[1]=size;
					size=ReadAr[1]-0x20 + 6; //Размер всего сообщения (+5 это 1 байт начало и CRC 4 байта и 1 байт конец)

					BytesRead=2; //Так как признак начала и размер уже прочитали
					for(int j=0;j<100;j++)
					{
						BytesRead+=cPort->Read(&ReadAr[BytesRead],size-BytesRead);
						if(BytesRead>=size)
							break;
					}

					//Проверяем ответ на CRC
					unsigned int crc0=MakeCRC_FP300KZ(ReadAr,1,size-5);
					unsigned int crc1=*((unsigned int*)&ReadAr[size-5]);
					if(crc0!=crc1) isOk=false; //Ошибка в контрольной сумме ответа
					else
					{
						Status->SetStatus(&ReadAr[size-12]); //читаем статус
						answer.assign((char*)&ReadAr[4],size-17); //Добавляем ответ в результат
						result=true;
					}
					if(result) break;
				}
				j++;
			}
			if(!isOk) continue; //Ошибка повторяем запрос
			break; //всё в порядке
		}
	}

	//if(!result) m_ErrorCode=5;
	return result;
}*/
bool FP300KZ::SendPMessage(uint8_t* msg,uint32_t msize,std::string &answer)
{
	//SleepMs(1000);

	bool rez = false; //Хоть чтото получили
	//Буфер под ответ
	unsigned char buffer[1024*100]; //буфер для чтения ответа
	memset(buffer, 0, sizeof(buffer)); //Очищаем буфер ответа.
	int bufferS = 0;

	if (msize > 3)
	{
		CommandName = msg[3]; //Сохраняем номер последней команды

		getNextSeq();//Увеличим на 1
		if (cPort->isOpen())
		{
			for (int i = 0; i < 6; i++) //Если после 5 попыток нет ответа то принтер неисправен...
			{
				//Если есть мусор в порте то читаю его
				int len = cPort->Read(buffer, sizeof(buffer));
				if (len>0)
				{
					std::cout << "WASTE! " + Utility::toHexString(buffer, len) << std::endl;
				}
				memset(buffer, 0, sizeof(buffer));

				if (i>0) std::cout << "REPEAT SEND!" << std::endl;

				//Отправляю запрос на принтер
				msg[1] = 0x20 + msize - 1; //Размер
				msg[2] = FrameSeqNumber;
				unsigned int crc = MakeCRC_FP300KZ(msg, 1, msize);
				cPort->Write(msg, msize); //Отправляем данные
				cPort->Write(&crc, 4); //Контрольная сумма
				cPort->WriteChar(0x03); //Признак конца сообщения

				//Пытаюсь принять ответ от принтера
				bufferS = 0;
				bool isOk = true;
				//int j = 0;
				//while (j < 9) //9*60=540 в цикле чтоб ждать ответа не более 500ms по документации
				for (int jj = 0; jj<10; jj++) //100мс * 10 = 1 секунды макс время макс время для ожидания данных
				{
					int BytesRead = cPort->Read(&buffer[bufferS], sizeof(buffer) - bufferS);
					if (BytesRead>0) jj = 0; //Чтобы начать ждать по новой

					//Проверяю есть ли во всём скаченом NACK ошибка CRC
					if (bufferS + BytesRead>1 && buffer[0] != 0x01)
					{
						bool NACK = false;
						for (int k = bufferS; k<bufferS + BytesRead; k++)
						{
							if (buffer[k] == 0x15)
							{
								std::cout << "NACK" << std::endl;
								SleepMs(60);
								NACK = true;
								break;
							}
						}
						if (NACK) break; //Выходим из цикла и повторяем запрос
					}

					bufferS += BytesRead;

					//Ищу первую позицию с 0x01 если она есть то сдвигаю массив
					int pos = -1;
					for (int k = 0; k<bufferS; k++)
					{
						pos = k;
						if (buffer[k] == 0x01) break; //Чтобы не затёрло данные
						if(buffer[k]==0x16) std::cout << "WAIT" << std::endl; //SYN комманда подождать данные посылается каждые 60ms
					}
					if (pos>0)
					{
						//Сдвигаю массив
						for (int k = 0; k<bufferS - pos; k++)
						{
							buffer[k] = buffer[k + pos];
						}
						bufferS -= pos; //Корректирую размер принятого
						SleepMs(60); //Так как мог попасться байт 0x16 SYN комманда подождать данные посылается каждые 60ms то немного жду...
					}

					//начало пакета
					if (bufferS >= 2 && buffer[0] == 0x01 && bufferS >= buffer[1] - 0x20 + 6) //Начало пакета
					{
						unsigned short size = buffer[1] - 0x20 + 6;
						//Проверяем ответ на CRC
						unsigned int crc0 = MakeCRC_FP300KZ(buffer, 1, size - 5);
						unsigned int crc1 = *((unsigned int*)&buffer[size - 5]);
						if (crc0 != crc1)
						{
							memset(buffer, 0, sizeof(buffer));
							pos = 0;
						}
						else
						{
							Status->SetStatus(&buffer[size - 12]); //читаем статус
							answer.assign((char*)&buffer[4], size - 17); //Добавляем ответ в результат
							rez = true;
						}
						break;
					}
				}
				if (!isOk) continue; //Ошибка повторяем запрос
				break; //всё в порядке
			}
		}
	}

	return rez;
}
//---------------------------------------------------------------------------
bool FP300KZ::CloseCOMPort()
{
	return cPort->Close();
}
//---------------------------------------------------------------------------
//bool FP300KZ::OpenCOMPort(std::string ComNumber,int BaudRate)
bool FP300KZ::OpenSerial(std::string ComNumber, int BaudRate)
{
	cPort->ComNumber=ComNumber;
	cPort->BaudRate=BaudRate;

	cPort->Close();
	
	if(cPort->Open(cPort->ComNumber))
	{
		if(!cPort->Setup(0))
			return false;

		if (!cPort->SetTimeout(300))
			return false;

	}else return false;
	return true;
}
//---------------------------------------------------------------------------
void FP300KZ::LoadSetup()
{
/*
	std::wstring path=getCommonAppPathW()+L"\\NewTon\\Setup.ini";

	TIniFile* ini=new TIniFile(ExtractFilePath(ParamStr(0))+"\\Setup.ini");
	cPort->port=ini->ReadString("Printer","Port","");
	cPort->BaudRate=ini->ReadInteger("Printer","BaudRate",0);
	CheckCount=ini->ReadInteger("Printer","CheckCount",0);
	delete ini;
*/
}
//---------------------------------------------------------------------------
void FP300KZ::SaveSetup()
{
/*
	std::wstring path=getCommonAppPathW()+L"\\NewTon\\Setup.ini";

	TIniFile* ini=new TIniFile(ExtractFilePath(ParamStr(0))+"\\Setup.ini");
	ini->WriteString("Printer","Port",cPort->port);
	ini->WriteInteger("Printer","BaudRate",cPort->BaudRate);
	ini->WriteInteger("Printer","CheckCount",CheckCount);
	delete ini;
*/
}
//---------------------------------------------------------------------------
bool FP300KZ::Print()
{
	return false;
}
//---------------------------------------------------------------------------
void FP300KZ::NewLine()
{

}
//---------------------------------------------------------------------------
/*public byte[] ReturnBCC(byte[] bytePacketData)
        {
            // <BCC> Контролна сума (0000H-FFFFH)
            // дължина:    4 байта
			// стойност:   30H - 3FH
            // Сумата включва от <01> без него до <05> вкл.
            // Всяка цифра от двата байта се предава като и се прибави 30H.
            // Например сумата 1AE3H се представя като 31H,3AH,3EH,33H.

            // IN HEX
            //    01 25 50 4C 54 05 30

            // In decimal
            //     1 37 80 76 84 5 48

            Int64 triset_HEX = 0x30;

            byte[] bRes = new byte[4];
            int i = 48;
            int iRes = 0;
            // int i = 0;
            int iCountB = 0;
            string hexval1 = String.Empty;
            string hexval2 = String.Empty;
            StringBuilder sb = new StringBuilder();
			foreach (byte n in bytePacketData)
            {
                if (n != (byte)01)
                {
                    if (iCountB == 0)
                    {
                        sb.Append(n.ToString("X2"));
                        string hexString = sb.ToString();
                        triset_HEX = triset_HEX + Convert.ToInt64(hexString, 16);
                    }
                    iCountB++;
                    if (iCountB > 1)
                       iCountB = 0;
                }
                if (n == (byte)05)
                    break;
            }
            return this.ConvertHexToByteArr(Convert.ToString( triset_HEX ));
        }
*/
//---------------------------------------------------------------------------
//Инициализация переменных PrinterName PrinterVersion PrinterNumber PrinterDecimal
//Без которых принтер не может работать...
MyError FP300KZ::PrinterInit()
{
	MyError err;
	err = DiagnosticInfo();
	if(err.ErrorCode == 0)
	{
		bool bA,bB,bC,bD;
		std::string Decimal,r,TaxA,TaxB,TaxC,TaxD;
		err = GetTaxRates(Decimal,r,bA,bB,bC,bD,TaxA,TaxB,TaxC,TaxD);
//		if(b) b=b && fp->GetStatusFP();
	}
	return err;
}
//---------------------------------------------------------------------------
///Получение байтов статуса принтера 4A
MyError FP300KZ::GetStatusFP()
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	unsigned char msg[5] = {0x01,0x24,0x20,fcGetStatusFP,0x05};
	std::string answer;
	bool b=SendPMessage(msg,sizeof(msg),answer);
	b=b && !Status->s[0][5]; //Признак ошибки

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber+".log",std::string("GetStatusFP(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
///Аннуляция (сторно) фискального чека
MyError FP300KZ::CancelFiscalInv()
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	unsigned char msg[5] = {0x01,0x24,0x20,fcCancelFiscalInv,0x05};
	std::string answer;
	bool b=SendPMessage(msg,sizeof(msg),answer);
	b=b && !Status->s[0][5]; //Признак ошибки

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("CancelFiscalInv(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
///Открытие фискального (клиентского) чека
///OpCode - Номер оператора 1..16
///OpPwd - Пароль оператора 4 - 6 цифр
///TillNmb - Номер кассового места целое число 1..99999
MyError FP300KZ::OpenFiscalInv(int OpCode,std::string OpPwd,int TillNmb)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcOpenFiscalInv;
	msg+= Utility::IntToStdStr(OpCode)+","+OpPwd+","+ Utility::IntToStdStr(TillNmb);
	msg+=(char)0x05;
	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	b=b && !Status->s[0][5]; //Признак ошибки
	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("OpenFiscalInv(OpCode="+ Utility::IntToStdStr(OpCode)+",OpPwd=****,TillNmb="+ Utility::IntToStdStr(TillNmb)+"); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
///Закрытие фискального чека
MyError FP300KZ::CloseFiscalInv()
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	unsigned char msg[5] = {0x01,0x24,0x20,fcCloseFiscalInv,0x05};
	std::string answer;
	bool b=SendPMessage(msg,sizeof(msg),answer);
	b=b && !Status->s[0][5]; //Признак ошибки
	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}
	if (m_SaveLog)
	{
		std::stringstream ss;
		ss << "CloseFiscalInv();";
		if (err.ErrorCode != 0) ss << " ErrorCode: " << err.ErrorCode << " ErrorDescription: " << err.ErrorMessage;
		Utility::logrotate(PrinterName + "_" + PrinterNumber + ".log", ss.str());
	}
	return err;
}
//---------------------------------------------------------------------------
///Открытие нефискального чека
MyError FP300KZ::OpenServiceInv()
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	unsigned char msg[5] = {0x01,0x24,0x20,fcOpenServiceInv,0x05};
	std::string answer;
	bool b=SendPMessage(msg,sizeof(msg),answer);
	b=b && !Status->s[0][5]; //Признак ошибки

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("OpenServiceInv(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
///Закрытие нефискального чека
///TODO ответ: Количество всех напечатанных чеков (фискальных и служебных) с момента последнего закрытия смены до текущего момента /4 байта/.
MyError FP300KZ::CloseServiceInv(int& count)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	count=0;
	unsigned char msg[5] = {0x01,0x24,0x20,fcCloseServiceInv,0x05};
	std::string str;
	bool b=SendPMessage(msg,sizeof(msg),str);
	b=b && !Status->s[0][5]; //Признак ошибки

	if (b)
	{
		count = Utility::StdStrToInt(str);
	}
	else
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("CloseServiceInv(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
///Открытие чека возврата
/**OpCode - Номер оператора 1..16
* OpPwd - 4 - 6 цифр
* TillNmb - Номер кассового места /целое число 1..99999/
*/
MyError FP300KZ::OpenBackInv(int OpCode,std::string OpPwd,int TillNmb)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcOpenBackInv;
	msg+= Utility::IntToStdStr(OpCode)+','+OpPwd+','+ Utility::IntToStdStr(TillNmb);
	msg+=(char)0x05;
	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}
	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("OpenBackInv(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
///Печать дубликата чека
MyError FP300KZ::PrintDuplicateInv()
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	unsigned char msg[6] = {0x01,0x25,0x20,fcPrintDuplicateInv,0x31,0x05};
	std::string answer;
	bool b=SendPMessage(msg,sizeof(msg),answer);

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("PrintDuplicateInv(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
/** Установка наименований дополнительных типов оплаты
Option - 1..4 номер типа оплаты
Name - Наименование типа оплаты (если name = '' то вернёт текущее)
*/
MyError FP300KZ::SetAddTypesOfPayment(char Option, std::wstring& Text)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcSetAddTypesOfPayment;
	switch(Option)
	{
	case 1:
		msg+='I';
		break;
	case 2:
		msg+='J';
		break;
	case 3:
		msg+='K';
		break;
	case 4:
		msg+='L';
		break;
	}
	if(Text.length()!=0)
	{
		msg+=',';
		msg.append(Utility::ws2s(Text),0,31); //В документации макс 31 байт
	}
	msg+=(char)0x05;
	std::string answer="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	b=b && !Status->s[0][5]; //Признак ошибки
	if(b && Text.length()!=0 && answer!="P") b=b && false;
	if(b && Text.length()==0) Text = Utility::StringToWString(answer, std::locale(""));

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("SetAddTypesOfPayment(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
//Печатать дневной отчёт с гашением
MyError FP300KZ::PrintZReport()
{
	/*MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";*/

	bool b=PrintEJ().ErrorCode==0; //печатаем контрольную ленту
	if(b) b=b && EJ("E").ErrorCode==0; //Отчищяяем контрольную ленту
	//if(b) b=b && ==0; //Сам Z отчёт
	Sleep(100);
	return DailyFinancialReport('1');
}
//---------------------------------------------------------------------------
//Печатать дневной отчёт без гашения
MyError FP300KZ::PrintXReport()
{
	return DailyFinancialReport('3');
}
//---------------------------------------------------------------------------
//Печатает строку текста (на служебном и на фискальном)
MyError FP300KZ::PrintLine(std::wstring line)
{
	MyError err;
	err = PrintFreeTextInFiscalInv(Utility::ws2s(line)); //TODO подправить на ru-ru.1251 роверить в интернете
	if(err.ErrorCode!=0) err=PrintFreeTextInServiceInv(Utility::ws2s(line)); //Печать свободного текста в нефискальном чеке
	return err;
}
//---------------------------------------------------------------------------
///Дневной финансовый отчет
///'0' - Z отчёт без регистров
///'1' - Z отчёт с регистрами
///'2' - X отчёт без регистров
///'3' - X отчёт с содержанием регистров
MyError FP300KZ::DailyFinancialReport(uint1 Option)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	//N на конце не сделал смотри документацию
	unsigned char msg[6] = {0x01,0x25,0x20,fcDailyFinancialReport,Option,0x05};
	std::string answer;
	bool b=SendPMessage(msg,sizeof(msg),answer);
	b=b && !Status->s[0][5]; //Признак ошибки

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("DailyFinancialReport(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
///Отчет по налоговым ставкам и положению десятичной точки за период
///Start - Дата начала периода – DDMMYY /6 байт/
///End - Дата окончания периода – DDMMYY /6 байт/
MyError FP300KZ::ReportOnTaxRates(std::string Start,std::string End) //Отчет по налоговым ставкам и положению десятичной точки за период
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcReportOnTaxRates;
	msg+=Start+','+End;
	msg+=(char)0x05;
	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	if(answer=="f") b=false; //Если не заданно налоговых ставок за период.
	b=b && !Status->s[0][5]; //Признак ошибки

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("ReportOnTaxRates(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
///Полный фискальный отчет за период заданный датами
///Password - Пароль налогового инспектора от 4 до 6 цифр.
///Receipts - Не обязательный параметр: один байт со значением 'X'. Если он присутствует, то в отчете печатается количество фискальных чеков за день.
///Start - Начальная дата периода. 6 байт DDMMYY.
///End - Конечная дата периода. 6 байт DDMMYY.
///Если второй параметр отсутствует, команда генерирует месячный или годовой отчет. Синтаксис в этом случае:
///Start Месяц - 4 байта (MMYY) для месячного отчета.
///Start Год - 2 байта (YY) для годового отчета.
MyError FP300KZ::FullFiscalReportByDate(std::string Password,std::string Receipts,std::string Start,std::string End)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcFullFiscalReportByDate;

	msg+=Password+',';
	msg+=Receipts;
	msg+=Start+','+End;

	msg+=(char)0x05;

	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	b=b && !Status->s[0][5]; //Признак ошибки

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("FullFiscalReportByDate(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
///Сокращёный фискальный отчет за период заданный датами
///Password - Пароль налогового инспектора от 4 до 6 цифр.
///Receipts - Не обязательный параметр: один байт со значением 'X'. Если он присутствует, то в отчете печатается количество фискальных чеков за день.
///Start - Начальная дата периода. 6 байт DDMMYY.
///End - Конечная дата периода. 6 байт DDMMYY.
///Если второй параметр отсутствует, команда генерирует месячный или годовой отчет. Синтаксис в этом случае:
///Start Месяц - 4 байта (MMYY) для месячного отчета.
///Start Год - 2 байта (YY) для годового отчета.
MyError FP300KZ::ReduceFiscalReportByDate(std::string Password,std::string Receipts,std::string Start,std::string End)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcReduceFiscalReportByDate;

	msg+=Password+',';
	msg+=Receipts;
	msg+=Start+','+End;

	msg+=(char)0x05;

	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	b=b && !Status->s[0][5]; //Признак ошибки

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("ReduceFiscalReportByDate(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
///Полный фискальный отчет за период заданный номерами смен
///Область данных:   <Password>, [[<Receipts>]<Start>,<End>]
///Password - Пароль налогового инспектора – от 4 до 6 цифр.
///Receipts - Не обязательный параметр: один байт со значением ‘X’. Если он присутствует, то в отчете печатается количество фискальных чеков за день.
///Start - Номер первой смены отчетного периода. 4 байта.
///End - Номер последней смены отчетного периода. 4 байта.
MyError FP300KZ::FullFiscalReportByNumber(std::string Password,std::string Receipts,int Start,int End)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcFullFiscalReportByNumber;

	msg+=Password+',';
	msg+=Receipts;
	msg+= Utility::IntToStdStr(Start)+','+ Utility::IntToStdStr(End);

	msg+=(char)0x05;

	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	b=b && !Status->s[0][5]; //Признак ошибки

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("FullFiscalReportByNumber(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
///Сокращёный фискальный отчет за период заданный номерами смен
///Область данных:   <Password>, [[<Receipts>]<Start>,<End>]
///Password - Пароль налогового инспектора – от 4 до 6 цифр.
///Receipts - Не обязательный параметр: один байт со значением ‘X’. Если он присутствует, то в отчете печатается количество фискальных чеков за день.
///Start - Номер первой смены отчетного периода. 4 байта.
///End - Номер последней смены отчетного периода. 4 байта.
MyError FP300KZ::ReduceFiscalReportByNumber(std::string Password,std::string Receipts,int Start,int End)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcReduceFiscalReportByNumber;

	msg+=Password+',';
	msg+=Receipts;
	msg+= Utility::IntToStdStr(Start)+','+ Utility::IntToStdStr(End);

	msg+=(char)0x05;

	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	b=b && !Status->s[0][5]; //Признак ошибки

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("ReduceFiscalReportByNumber(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
///Дневной отчет по типам оплаты
MyError FP300KZ::DailyReportByTypesOfPayment(std::string& Cash,std::string& Credit,std::string& Debit,std::string& Cheque,std::string& Pay1,std::string& Pay2,std::string& Pay3,std::string& Pay4,std::string& Closure,std::string& Receipt)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	unsigned char msg[5] = {0x01,0x24,0x20,fcDailyReportByTypesOfPayment,0x05};
	std::string answer;
	bool b=SendPMessage(msg,sizeof(msg),answer);
	b=b && !Status->s[0][5]; //Признак ошибки
	if(b)
	{
		Cash= Utility::CutBeforeFirst(answer,',');
		Credit= Utility::CutBeforeFirst(answer,',');
		Debit= Utility::CutBeforeFirst(answer,',');
		Cheque= Utility::CutBeforeFirst(answer,',');
		Pay1= Utility::CutBeforeFirst(answer,',');
		Pay2= Utility::CutBeforeFirst(answer,',');
		Pay3= Utility::CutBeforeFirst(answer,',');
		Pay4= Utility::CutBeforeFirst(answer,',');
		Closure= Utility::CutBeforeFirst(answer,',');
		Receipt= Utility::CutBeforeFirst(answer,',');
	}
	else
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("DailyReportByTypesOfPayment(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
///Отчет по артикулам
///'S' - Печатаются только данные артикулов по которым были продажи.
///'P' - Печатаются данные всех запрограммированных артикулов.
MyError FP300KZ::ReportByArticle(std::string Option) //#define fcReportByArticle 0x6F //(111)Отчет по артикулам
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcReportByArticle; msg+=Option; msg+=(char)0x05;
	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	b=b && !Status->s[0][5]; //Признак ошибки

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("ReportByArticle(Option="+Option+"); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
///Отчет по операторам
MyError FP300KZ::OperatorReport()
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	unsigned char msg[5] = {0x01,0x24,0x20,fcOperatorReport,0x05};
	std::string answer;
	bool b=SendPMessage(msg,sizeof(msg),answer);
	b=b && !Status->s[0][5]; //Признак ошибки

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("OperatorReport(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
///Протяжка ленты
///\param cnt Количество строк
MyError FP300KZ::FeedPaper(int cnt)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcFeedPaper;
	msg+= Utility::IntToStdStr(cnt);
	msg+=(char)0x05;
	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("FeedPaper(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
///Открытие денежного ящика
MyError FP300KZ::OpenCashDrawer(int mSec)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcOpenCashDrawer;
	if(mSec>0) msg+= Utility::IntToStdStr(mSec);
	msg+=(char)0x05;
	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("OpenCashDrawer(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
//<Dept>,<Line1>[<LF><Line2>]
///Задать наименование департамента (Секции)
MyError FP300KZ::SetDepartmentName(int dept,std::wstring line1,std::wstring line2)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcSetDepartmentName;
	msg+= Utility::IntToStdStr(dept);
	msg+=',';
	msg.append(Utility::ws2s(line1),0,36); //В документации макс 36 байт
	if(line2.length()>0)
	{
		msg+=(char)10;
		msg.append(Utility::ws2s(line2),0,46); //В документации макс 46 байт
	}
	msg+=(char)0x05;
	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("SetDepartmentName(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
///Получить информацию по секциям
MyError FP300KZ::GetDepartmentInfo(int dept,int &RecSales,float &RecSum,int &TotSales,float &TotSum,std::wstring &Line1,std::wstring &Line2)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcGetDepartmentInfo;
	msg+= Utility::IntToStdStr(dept);
	msg+=(char)0x05;

	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);
	if(b)
	{
		if(Utility::CutBeforeFirst(str,',')=="P") //Секция запрограммированна
		{
			std::string nstr;
			nstr= Utility::CutBeforeFirst(str,',');
			RecSales= Utility::StdStrToInt(nstr);
			RecSum= Utility::fromString<float>(Utility::CutBeforeFirst(str,',')); //Натуральное число в текстовом виде с 2 десятичными знаками
			nstr= Utility::CutBeforeFirst(str,',');
			TotSales= Utility::StdStrToInt(nstr);
			TotSum= Utility::fromString<float>(Utility::CutBeforeFirst(str,',')); //Натуральное число в текстовом виде с 2 десятичными знаками
			Line1= Utility::StringToWString(Utility::CutBeforeFirst(str, (char)10), std::locale(""));
			Line2= Utility::StringToWString(str, std::locale(""));
		}else
		{
			RecSales=0;
			RecSum=0;
			TotSales=0;
			TotSum=0;
			Line1=L' ';
			Line2=L' ';
		}
	}
	else
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}
	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("GetDepartmentInfo(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
///Обрезка ленты
MyError FP300KZ::CutPaper()
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcCutPaper; msg+=(char)0x05;
	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("CutPaper(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
///Печать диагностической информации
MyError FP300KZ::PrintDiagnostic()
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	unsigned char msg[5] = {0x01,0x20,0x20,fcPrintDiagnostic,0x05};
	std::string answer;
	int b=SendPMessage(msg,sizeof(msg),answer);
	b=b && !Status->s[0][5]; //Признак ошибки

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName + "_" + PrinterNumber + ".log", std::string("PrintDiagnostic(); //") + (b ? "OK=" : "ERROR=") + Utility::IntToStdStr(err.ErrorCode) + " " + err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
MyError FP300KZ::SetManufacturersSerialNumber(std::string Serial)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcSetManufacturersSerialNumber;
	msg+=Serial;
	msg+=(char)0x05;

	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	b=b && !Status->s[0][5]; //Признак ошибки
	if(b)
	{
		b=b && Utility::BeforeFirst(answer,',')=="P";
		//Вторая часть ддолжна быть "KAZAKHSTAN"
	}else
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}
	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("SetManufacturersSerialNumber(Serial="+Serial+"); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
std::string FP300KZ::GetStatusDescription(BYTE StatusCode)
{
	if (StatusCode == 0x00)
	{
		return "OK";
	}
	if (StatusCode == 0xFF)
	{
		return "Принтер недоступен!";
	}
	BYTE code = (BYTE)StatusCode & (BYTE)0x04;
	if (code > 0)
	{
		return "Бумага кончилась ";
	}
	code = (BYTE)StatusCode & (BYTE)0x01;
	if (code > 0)
	{
		return "Бумага скоро кончится ";
	}
	return "";
}
//---------------------------------------------------------------------------
///Чтение РНН и РНМ
MyError FP300KZ::GetRNNAndRNM(std::string &RNN,std::string &RNM)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	unsigned char msg[5] = {0x01,0x24,0x20,fcGetRNNAndRNM,0x05};
	std::string answer;
	bool b=SendPMessage(msg,sizeof(msg),answer);
	if (b)
	{
		RNN = Utility::BeforeFirst(answer, ',');
		RNM = Utility::AfterFirst(answer, ',');
	}else
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("GetRNNAndRNM("+RNN+","+RNM+"); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
//Установка РНН и РНМ
MyError FP300KZ::SetRNNAndRNM(std::string RNN,std::string RNM)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcSetRNNAndRNM;
	msg+=RNN+','+RNM;
	msg+=(char)0x05;
	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	b=b && !Status->s[0][5]; //Признак ошибки

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("SetRNNAndRNM(RNN="+RNN+",RNM="+RNM+"); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
///Установка пароля оператора
///\param OpCode Номер оператора
///\param OldPwd Старый пароль
///\param NewPwd Новый пароль
///\return Успех либо провал
MyError FP300KZ::SetOperatorPassword(std::string OpCode,std::string OldPwd,std::string NewPwd)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcSetOperatorPassword;
	msg+=OpCode+','+OldPwd+','+NewPwd;
	msg+=(char)0x05;
	std::string answer;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("SetOperatorPassword(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
///Установка наименования оператора
///\param OpCode Номер оператора. От 1 до 16 строка.
///\param Pwd Пароль (4 до 8 цифр).
///\param OpName Наименование оператора (до 30 символов).
///\return Успех либо провал
MyError FP300KZ::SetOperatorName(std::string OpCode,std::string Pwd,std::string OpName)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcSetOperatorName;
	msg+=OpCode+','+Pwd+','+OpName;
	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("SetOperatorName(OpCode="+OpCode+",OpName="+OpName+"); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
//Установка даты и времени
///\param date - Дата в формате "DD-MM-YY"
///\param time - врремя в формате "HH:MM[:SS]"
MyError FP300KZ::SetDateTime(std::string date, std::string time) //#define fcSetDateTime 0x3D //(61)Установка даты и времени
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcSetDateTime;
	msg+= Utility::trim(date)+' '+ Utility::trim(time);
	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);
	b=b && !Status->s[0][5]; //Признак ошибки

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("SetDateTime(\"")+date+std::string("\", \"")+time+std::string("\"); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
//Поолучение даты и времени
///\param date - Дата в формате "DD-MM-YY"
///\param time - врремя в формате "HH:MM:SS"
MyError FP300KZ::GetDateTime(unsigned short& De,unsigned short& Me,unsigned short& Ye,unsigned short& Ho,unsigned short& Mi,unsigned short& Se)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcGetDateTime; msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);
	if(b)
	{
		De= Utility::StdStrToInt(Utility::CutBeforeFirst(str,'-'));
		Me= Utility::StdStrToInt(Utility::CutBeforeFirst(str,'-'));
		Ye= Utility::StdStrToInt(Utility::CutBeforeFirst(str,' '));//+2000; закоментил чтоб было одинаково с тем что при установки времени

		Ho= Utility::StdStrToInt(Utility::CutBeforeFirst(str,':'));
		Mi= Utility::StdStrToInt(Utility::CutBeforeFirst(str,':'));
		Se= Utility::StdStrToInt(str);
	}else
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}
	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("GetDateTime(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
///Установка HEADER и FOOTER и опций печати
MyError FP300KZ::PrintSetup(std::string Item, std::string Text, std::string& Answer)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcPrintSetup;
	msg+=Item+Text;
	msg+=(char)0x05;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),Answer);

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("PrintSetup(Item="+Item+",Text="+Text+"); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
MyError FP300KZ::PrintFreeTextInServiceInv(std::string Text) //Печать свободного текста в нефискальном чеке
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcPrintFreeTextInServiceInv;
	msg+=Text;
	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);
	b=b && !Status->s[0][5]; //Признак ошибки

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("PrintFreeTextInServiceInv(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
//Печать свободного текста в фискальном чеке
MyError FP300KZ::PrintFreeTextInFiscalInv(std::string Text)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcPrintFreeTextInFiscalInv;
	msg+=Text;
	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);
	b=b && !Status->s[0][5]; //Признак ошибки

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("PrintFreeTextInFiscalInv(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
//Регистрация продажи
///[<L1>][<Lf><L2>]<Tab><TaxCd><[Sign]Price>[*<Qwan>][,Perc|;Abs]
///L1 - Первая строка описания продажи, до 36 байт текста
///L2 - Вторая строка описания продажи, до 36 байт текста
///dep - Департамент отдел (1..10)
///TaxCd - Один байт содержащий букву соответствующую налоговой группе (А, Б, В, Г, Д).
///Price - Цена единицы (до 8 значащих цифр).
///Qwan - Количество товара (Длина до 8 значащих цифр не более 3-х знаков после десятичной точки).
///Abs - абсолюбное ли значение в Perc иначе проценты
///Perc - Надбавка или скидка (в зависимости от знака) в процентах
MyError FP300KZ::RegisterSale(std::wstring L1,std::wstring L2,int dep, std::string TaxCd,double Price,double Qwan,bool Abs,double Perc)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	L1= Utility::replaceStrings(L1,L"\n",L" "); //Избавляемся от переходов на новую строку
	L2= Utility::replaceStrings(L2,L"\n",L" "); //Избавляемся от переходов на новую строку

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcRegisterSale;
	msg.append(Utility::ws2s(L1),0,36); //В документации макс 36 байт
	if(L2.length()>0)
	{
		msg+=(char)0x0A;
		msg.append(Utility::ws2s(L2),0,36); //В документации макс 36 байт
	}
	msg+=(char)0x09;
	if(dep>0)
	{
		msg+= Utility::IntToStdStr(dep); //Параметр департамент отдел в документации в строке команды пропущен!!!!
		msg+=(char)0x09;
	}
	msg+=TaxCd; //налоговой группа 1 байт
	msg+= Utility::FloatToStdStr(Price,m_Dots); //Учитываем знаки после запятой
	msg+='*'+ Utility::FloatToStdStr(Qwan,3);
	if(Perc!=0)
		if(Abs) msg+=';'+ Utility::FloatToStdStr(Perc,m_Dots); //В абсолютном значении
		else msg+=','+ Utility::FloatToStdStr(Perc,2); //Скидка или надбавка
	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);
	b=b && !Status->s[0][5]; //Признак ошибки

	if(!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
	{
		std::stringstream ss;
		ss << "RegisterSale(L1=\"" << Utility::WStringToString(L1,std::locale("")) << "\",L2=\"" << Utility::WStringToString(L2,std::locale("")) << "\",dep=" << Utility::IntToStdStr(dep) << ",TaxCd='" << TaxCd << "',Price=" << Utility::FloatToStdStr(Price, 2, '.') << ",Qwan=" << Utility::FloatToStdStr(Qwan, 3, '.') << ",Abs='" << Abs << "',Perc=" << Utility::FloatToStdStr(Perc, 2, '.') << ");";
		if(err.ErrorCode != 0) ss << " ErrorCode: " << err.ErrorCode << " ErrorDescription: " << err.ErrorMessage;
		Utility::logrotate(PrinterName + "_" + PrinterNumber + ".log", ss.str());
	}
	return err;
}
//---------------------------------------------------------------------------
//Регистрация продажи с выводом на дисплей
///     [Line]]<Tab><TaxCd><[Sign]Price>[*Qwan][,Perc|;Abs]
///Line - Строка до 20 байта содержащая текст описывающий продажу.
///TaxCd - Один байт содержащий букву соответствующую налоговой группе (А, Б, В, Г, Д).
///Price - Цена единицы (до 8 значащих цифр).
MyError FP300KZ::RegisterSaleDisp(std::string L1,int dep,std::string TaxCd,std::string Price)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcRegisterSaleDisp;

	msg+=L1;
	msg+=(char)0x09;
	if(dep>0)
	{
		msg+= Utility::IntToStdStr(dep); //Параметр департамент отдел в документации в строке команды пропущен!!!!
		msg+=(char)0x09;
	}
	msg+=TaxCd; //налоговой группа 1 байт
	msg+=Price;

	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);
	b=b && !Status->s[0][5]; //Признак ошибки

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("RegisterSaleDisp(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
//Подитог
//Print - Если ‘1’ – подитог печатается.
//Display - Если ‘1’ – сумма подитога выводится на дисплей.
//Abs - Абсолютное ли значчение false то Perc в процентах
//Perc - Скидка или надбавка в процентах (+-99.9) в зависимости от знака
//Sum - Сумма подитога в текущем фискальном чеке /до 10 байта/
MyError FP300KZ::Subtotal(std::string Print,std::string Display, bool Abs, double Perc,double& Sum)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcSubtotal;

	msg+=Print+Display;
	if(Perc!=0) //Скидка либо наценка
	{
		if(Abs) msg+=';'+ Utility::FloatToStdStr(Perc,2);
		else msg+=','+ Utility::FloatToStdStr(Perc,2);
	}

	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);
	b=b && !Status->s[0][5]; //Признак ошибки
	if(b)
	{
		Sum= Utility::fromString<double>(Utility::CutBeforeFirst(str,','))/M();
	}else
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}
	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("Subtotal(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
///Оплата (итог)
//Line1 - Первая строка текста до 36 байт
//Line2 - Вторая строка текста до 36 байт
//PaidMode - Тип оплаты: 'P' – Оплата наличными; 'N' – Оплата в кредит; 'C' – Оплата чеком; 'D' – Оплата дебитной картой 'I' - Программируемый тип оплаты 1 'J' - Программируемый тип оплаты 2 'K' - Программируемый тип оплаты 3 'L' - Программируемый тип оплаты 4
//Один байт со значением ‘+’, указывающий знак Amount (суммы оплаты).
//Amount - Сумма оплаты /до 10 значащих цифр/.
//Change - Сдача
MyError FP300KZ::Total(std::string Line1,std::string Line2,std::string PaidMode,double Amount, double& Change)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	Change = 0;

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcTotal;
	msg+=Line1;
	msg+=(char)0x0A;
	msg+=Line2;
	msg+=(char)0x09; //<Tab>
	msg+=PaidMode; //Тип оплаты
	if(Amount>0) msg+='+';
	msg+= Utility::FloatToStdStr(Amount,m_Dots);

	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);
	b=b && !Status->s[0][5]; //Признак ошибки
	if(b && str.length()>1)
	{
		if(str[0]=='F') b=false;
		std::string s="";
		s.append(str,1,str.length()-1);
		Change= Utility::StdStrToDouble(s) / M();
		if(str[0]=='D') Change=-fabs(Change);
	}
	else
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
	{
		std::stringstream ss;
		ss << "Total(Line1=\"" << Line1 << "\",Line2=\"" << Line2 << "\",PaidMode=" << PaidMode << ",Amount=" << Utility::FloatToStdStr(Amount, 2, '.') << ",Change=" << Utility::FloatToStdStr(Change, 3, '.') << ");";
		if (err.ErrorCode != 0) ss << " ErrorCode: " << err.ErrorCode << " ErrorDescription: " << err.ErrorMessage;
		Utility::logrotate(PrinterName + "_" + PrinterNumber + ".log", ss.str());
	}
	return err;
}
//---------------------------------------------------------------------------
//Служебный приход или расход
//Amount Сумма (до 10 значащих цифр). В зависимости от знака интерпретируется как приход или расход.
//strH - Заголовок  strF - последняя строка
//ExitCode ‘P’ Заявка исполнена. Если заявленная сумма  ненулевая, принтер печатает служебный чек  регистрирующий операцию. ‘F’   Заявка отклонена в случае если: Сумма наличности в кассе меньше суммы заявленного служебного расхода. Открыт фискальный или нефискальный чек.
//CashSum Сумма наличности в кассе. Сумма нарастающая после служебного прихода и после каждой оплаты наличными.
//ServIn Сумма всех команд  “Служебный приход”.
//ServOut Сумма всех команд  “Служебный расход”.
MyError FP300KZ::ParishOrConsumption(std::string Oper,std::string Password,double Amount,std::wstring strH,std::wstring strF,std::string& ExitCode,double& CashSum,double& ServIn,double& ServOut)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcParishOrConsumption;

	if(PrinterName.find("FP600")!=std::string::npos)
	{
		if(Amount!=0)
		{	msg+=Oper+","; //Для Беларусов
			msg+=Password+","; //Для Беларусов
			msg+= Utility::FloatToStdStr(Amount,2);
		}
	}else
	{
		if(Amount!=0)
		{
			msg+= Utility::FloatToStdStr(Amount,2);
			while(strH.length()>0)
			{
				std::wstring str = Utility::CutBeforeWFirst(strH,L'\n');
				msg+='\t'; msg+='h'; msg.append(Utility::ws2s(str),0,48);
			}
			while(strF.length()>0)
			{
				std::wstring str = Utility::CutBeforeWFirst(strF,L'\n');
				msg+='\t'; msg+='f'; msg.append(Utility::ws2s(str),0,48);
			}
		}
	}

	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);
	b=b && !Status->s[0][5]; //Признак ошибки
	if(b)
	{
		ExitCode= Utility::CutBeforeFirst(str,',');
		CashSum= Utility::fromString<double>(Utility::CutBeforeFirst(str,','))/M();
		ServIn= Utility::fromString<double>(Utility::CutBeforeFirst(str,','))/M();
		ServOut= Utility::fromString<double>(str)/M();
	}
	else
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("ParishOrConsumption(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
///Печать штрих-кода
///Type - Тип штрих кода от 1 до 5 (1-EAN8, 2-EAN13, 3-Code 128, 4-ITF, 5-ITF)
MyError FP300KZ::PrintBarCode(int Type,std::string Data)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcPrintBarCode;
	msg+= Utility::IntToStdStr(Type);
	msg+=',';
	msg+=Data;
	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);
	b=b && !Status->s[0][5]; //Признак ошибки
	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}
	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("PrintBarCode(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
//Звуковой сигнал
///\param Hz Частота звука
///\param mSec Милисекунд
MyError FP300KZ::Beep(int Hz,int mSec)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	if(Hz==0) Hz=294;
	if(mSec==0) mSec=1000/8;

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcBeep;
	msg+= Utility::IntToStdStr(Hz);
	msg+=',';
	msg+= Utility::IntToStdStr(mSec);
	msg+=(char)0x05;
	std::string str="";
	bool b = SendPMessage((uint1*)msg.c_str(),msg.size(),str);
	b = b && !Status->s[0][5]; //Признак ошибки
	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage=getErrorDesc(ResultCode());
	}
	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("Beep(); //")+((err.ErrorCode==0) ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
//Количество логических мест для фискальных записей
///\Logical Количество логических мест для фискальных записей
MyError FP300KZ::FreeFieldsByFiscalMemory(long& Logical)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcFreeFieldsByFiscalMemory;
	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);
	if(b)
	{
		Logical= Utility::StdStrToInt(Utility::CutBeforeFirst(str,',')); //
	}
	b=b && !Status->s[0][5]; //Признак ошибки
	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}
	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("FreeFieldsByFiscalMemory(Logical); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
//Программирование конфигурационных ключей
///Если update=false то команда записывает из ОЗУ во флэш-память графический логотип, высоту печати штрих-кода, плотность печати и длину импульса открывания денежного ящика. После обнуления ОЗУ значения этих параметров восстанавливаются из флэш-памяти.
///\param update Если false то значения конфигуразионных ключей не изменяются, а данные настроек принтера записываются во флэш-память
MyError FP300KZ::SwitchPrg(bool update)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg,key="";
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcSwitchPrg;
	if(update)
	{
		if(Sw8) key+='1'; else key+='0'; //Срокость
		if(Sw7) key+='1'; else key+='0'; //Срокость
		if(Sw6) key+='1'; else key+='0'; //Срокость
		if(Sw5) key+='1'; else key+='0'; //Не используется
		if(Sw4) key+='1'; else key+='0'; //Работа дисплея с кодовой таблицей Windows 1251
		if(Sw3) key+='1'; else key+='0'; //Режим прозрачного дисплея
		if(Sw2) key+='1'; else key+='0'; //Не используется
		if(Sw1) key+='1'; else key+='0'; //запись частичной информации на контрольную ленту(старое: Автоматическая обрезка ленты)
		msg+=key;
	}
	msg+=(char)0x05;
	std::string str="";

	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("SwitchPrg("+key+"); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
//Для сохранение сокращённой информации в ЭКЛ
bool FP300KZ::getSmallEJ(bool& val)
{	//val=Sw1;
        val=Sw2;
	return true;//Всегда true потому что значение берётся не здесь.
}
//---------------------------------------------------------------------------
//Для сохранение сокращённой информации в ЭКЛ
MyError FP300KZ::setSmallEJ(bool val)
{	//Sw1=val;
	Sw2=val;
	return SwitchPrg(true); //Сохраним переключатели
}
//---------------------------------------------------------------------------
//Режим прозрачного дисплея
bool FP300KZ::getDisplayTransparent(bool& val)
{	val=Sw3;
	return true;//Всегда true потому что значение берётся не здесь.
}
//---------------------------------------------------------------------------
//Режим прозрачного дисплея
MyError FP300KZ::setDisplayTransparent(bool val)
{	Sw3=val;
	return SwitchPrg(true);
}
//---------------------------------------------------------------------------
///<Работа дисплея с кодовой таблицей Windows 1251
bool FP300KZ::getDisplayWin1251(bool& val)
{
	val=Sw4;
	return true;//Всегда true потому что значение берётся не здесь.
}
//---------------------------------------------------------------------------
///<Работа дисплея с кодовой таблицей Windows 1251
MyError FP300KZ::setDisplayWin1251(bool val)
{	Sw4=val;
	return SwitchPrg(true);
}
//---------------------------------------------------------------------------
//Получить скорость порта из конфига "bps"
int FP300KZ::getComSpeed()
{
	int speed=0;
	if(!Sw6 && !Sw7 && !Sw8) speed=1200;
	if(!Sw6 && !Sw7 &&  Sw8) speed=2400;
	if(!Sw6 &&  Sw7 && !Sw8) speed=4800;
	if(!Sw6 &&  Sw7 &&  Sw8) speed=9600;
	if( Sw6 && !Sw7 && !Sw8) speed=19200;
	if( Sw6 && !Sw7 &&  Sw8) speed=38400;
	if( Sw6 &&  Sw7 && !Sw8) speed=57600;
	if( Sw6 &&  Sw7 &&  Sw8) speed=115200;
	return speed;
}
//---------------------------------------------------------------------------
//Установить скорость порта
bool FP300KZ::setComSpeed(int Speed)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	bool b=false;
	if(Speed==1200)   {Sw6=0; Sw7=0; Sw8=0; b=true;}
	if(Speed==2400)   {Sw6=0; Sw7=0; Sw8=1; b=true;}
	if(Speed==4800)   {Sw6=0; Sw7=1; Sw8=0; b=true;}
	if(Speed==9600)   {Sw6=0; Sw7=1; Sw8=1; b=true;}
	if(Speed==19200)  {Sw6=1; Sw7=0; Sw8=0; b=true;}
	if(Speed==38400)  {Sw6=1; Sw7=0; Sw8=1; b=true;}
	if(Speed==57600)  {Sw6=1; Sw7=1; Sw8=0; b=true;}
	if(Speed==115200) {Sw6=1; Sw7=1; Sw8=1; b=true;}

	if (b)
	{
		err = SwitchPrg(true); //Запишем
	}else
	{ 
		err.ErrorCode = 1;
		err.ErrorMessage = "Не та скорость!";
	}
	return b;
}
//---------------------------------------------------------------------------
///Команда очищает дисплей.
///Если открыт фискальный чек и Sw3 в положении OFF, очищается только нижняя строка.
MyError FP300KZ::DisplayClear()
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	unsigned char msg[5] = {0x01,0x24,0x20,fcDisplayClear,0x05};
	std::string answer;
	bool b=SendPMessage(msg,sizeof(msg),answer);

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("DisplayClear(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
//Вывод текста в нижнюю строку дисплея
//Text - До 20 символов текста
MyError FP300KZ::DispalyLower(std::string Text)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcDispalyLower;
	msg+=Text;
	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("DispalyLower(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
///Вывод текста в верхнюю строку дисплея
///Text - До 20 символов текста
MyError FP300KZ::DispalyUpper(std::string Text)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcDispalyUpper;
	msg+=Text;
	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("DispalyUpper(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
///Вывод на дисплей свободного текста
///Текст (до 40 символов), который выводится на дисплей. Если необходимо вывести символ ASCII меньше чем 20h (управляющие символы) то они увеличиваются на 40h и предваряются 10h.
MyError FP300KZ::DispalyFree(std::string Text)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcDispalyFree;
	msg+=Text;
	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("DispalyFree(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
///Чтение запрограммированных налоговых ставок
///\param Decimals Точек после  запятой 0,1 или 2
///\param bA,bB,bC,bD Означает разрешение налоговой группы
///\param TaxA Налоговая ставка А
///\param TaxB Налоговая ставка Б
///\param TaxC Налоговая ставка В
///\param TaxD Налоговая ставка Г
MyError FP300KZ::GetTaxRates(std::string &Decimals,std::string &Rounding,bool& bA,bool& bB,bool& bC,bool& bD, std::string &TaxA, std::string &TaxB, std::string &TaxC, std::string &TaxD)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcSetTaxRates;
	msg+=(char)0x05;
	std::string str="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),str);
	if(b)
	{
		Decimals= Utility::CutBeforeFirst(str,',');
		m_Dots= Utility::StdStrToInt(Decimals); //Заполняем глобальную переменную
		if(PrinterName.find("FP600")!=std::string::npos)
		{
			Rounding= Utility::CutBeforeFirst(str,','); //Для Беларусов округление
		}
		bA=str[0]=='1'; bB=str[1]=='1'; bC=str[2]=='1'; bD=str[3]=='1';
		Utility::CutBeforeFirst(str,',');
		TaxA= Utility::CutBeforeFirst(str,',');
		TaxB= Utility::CutBeforeFirst(str,',');
		TaxC= Utility::CutBeforeFirst(str,',');
		TaxD=str;
	}
	else
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}
	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("GetTaxRates(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
//Установка положения десятичной точки и налоговых ставок
///\param Decimal 0,1 или 2 знака после запятой
MyError FP300KZ::SetTaxRates(int Decimal,std::string Rounding,std::string TaxA, std::string TaxB, std::string TaxC, std::string TaxD)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg,str;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcSetTaxRates;
	str+= Utility::IntToStdStr(Decimal)+","; //0,1,2 знака после запятой
	if(PrinterName.find("FP600")!=std::string::npos) //Для белорусов округление
	{
		str+=Rounding+',';
	}
	if(TaxA!="") str+='1'; else str+='0'; //Разрешена или нет
	if(TaxB!="") str+='1'; else str+='0'; //Разрешена или нет
	if(TaxC!="") str+='1'; else str+='0'; //Разрешена или нет
	if(TaxD!="") str+='1'; else str+='0'; //Разрешена или нет
	str+=",";
	str+=TaxA+',';
	str+=TaxB+',';
	str+=TaxC+',';
	str+=TaxD;
	msg+=str;
	msg+=(char)0x05;
	std::string answer="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	b=b && !Status->s[0][5]; //Признак ошибки

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("SetTaxRates("+answer+"); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
//Статус фискальной транзакции
///\param Open Открыт фискальный или служебный чек
///\param Items Количество зарегистрированных продаж в текущем или последнем фискальном чеке.
///\param Amount Сумма последнего фискального чека
///\param Tender Сумма оплаты текущего или последнего чека.
MyError FP300KZ::FiscalTransactionsStatus(bool& Open,int& Items,double& Amount,double& Tender)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcFiscalTransactionsStatus;
	msg+='T';
	msg+=(char)0x05;
	std::string answer="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	if (b)
	{
		Open = Utility::CutBeforeFirst(answer, ',') == "1";
		Items = Utility::StdStrToInt(Utility::CutBeforeFirst(answer, ','));
		Amount = Utility::fromString<double>(Utility::CutBeforeFirst(answer, ',')) / M();
		Tender = Utility::fromString<double>(answer) / M();
	}else 
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("FiscalTransactionsStatus(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
//Диагностическая информация
MyError FP300KZ::DiagnosticInfo()
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	unsigned char msg[5] = {0x01,0x20,0x20,fcDiagnosticInfo,0x05};
	std::string answer="";
	bool b=SendPMessage(msg,sizeof(msg),answer);
	b=b && !Status->s[0][5]; //Признак ошибки
	if(b)
	{
		//<Name><FwRev><Sp><FwDate><Sp><FwTime>,<Chk>,<Sw>,<ZNM>
		PrinterName= Utility::CutBeforeFirst(answer,',');
		PrinterVersion= Utility::CutBeforeFirst(answer,','); //Версия дата время
		Utility::CutBeforeFirst(answer,','); //Контрольная сумма
		std::string Sw18 = Utility::CutBeforeFirst(answer,',');//Положение конфигурационных переключателей Sw1 до Sw8. Строка 4 байта состоящая из‘0’ и‘1’
		Sw8=Sw18[0]=='1';
		Sw7=Sw18[1]=='1';
		Sw6=Sw18[2]=='1';
		Sw5=Sw18[3]=='1';
		Sw4=Sw18[4]=='1';
		Sw3=Sw18[5]=='1';
		Sw2=Sw18[6]=='1';
		Sw1=Sw18[7]=='1';
		PrinterNumber=answer; //Заводской номер - 12 байт.
	}else
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (PrinterName == "FPG-350")
	{
		err.ErrorCode = 1;
		err.ErrorMessage = "Это драйвер для старых принтеров без отправки в ОФД а не для новых!";
	}


	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("DiagnosticInfo(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
//Получение времени с начала открытия смены.
MyError FP300KZ::GetTimeZReport(int & time)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	unsigned char msg[5] = { 0x01,0x20,0x20,fcGetTimeZReport,0x05 };
	std::string answer = "";
	bool b = SendPMessage(msg, sizeof(msg), answer);
	b = b && !Status->s[0][5]; //Признак ошибки
	if (b)
	{
		time = Utility::StdStrToInt(answer);
	}
	else
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName + "_" + PrinterNumber + ".log", std::string("DiagnosticInfo(); //") + (b ? "OK=" : "ERROR=") + Utility::IntToStdStr(err.ErrorCode) + " " + err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
//Работа с электронной контрольной лентой
MyError FP300KZ::EJ(std::string Cmd)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcEJ;
	msg+=Cmd;
	msg+=(char)0x05;
	std::string answer="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("EJ("+Cmd+"); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
///Печать электронной контрольной ленты с начала (первая строка) нормальным шрифтом. Не Не печатаются служебные чеки, чеки служебного прихода и расхода и Х-отчет. Поле Data пустое.
MyError FP300KZ::PrintEJ()
{
	return EJ("PL");
}
//---------------------------------------------------------------------------
///Сервисная очистка контрольной ленты
MyError FP300KZ::ServiceClearEJ()
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcServiceClearEJ;
	msg+='F';
	msg+=(char)0x05;
	std::string answer="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	if(b)
	{
		if(answer!="P") b=false; //'P' (успешно) или 'F' (грешка)
	}else
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}
	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("ServiceClearEJ(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
///Сервисное обнуление ОЗУ
MyError FP300KZ::ServiceClearRAM()
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcServiceClearRAM;
	msg+=(char)0x05;
	std::string answer="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("ServiceClearRAM(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
//Печатается ли графический логотип
///\param Enable Разрешено либо запрещено печатать графический логотип.
///\param Height Высота графического логотипа
MyError FP300KZ::getPrintLogo(bool& Enable,int& Height)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string str;
	err = PrintSetup("I", "L", str);
	if(err.ErrorCode==0)
	{
		Enable = Utility::CutBeforeFirst(str,',')=="1";
		Height = Utility::StdStrToInt(str);
	}
	return err;
}
//---------------------------------------------------------------------------
//Печатать ли графический логотип
///\param Enable Разрешено либо запрещено печатать графический логотип.
///\param Height Высота графического логотипа
MyError FP300KZ::setPrintLogo(bool Enable,int Height)
{
	std::string str="";
	if(Enable) str+="1,"; else str+="0,";
	str+= Utility::IntToStdStr(Height);

	std::string Answer="";
	return PrintSetup("L",str,Answer);
}
//---------------------------------------------------------------------------
//Программирование графического логотипа 576x96 точеек
//RowNum - номер линии
//Data - шестадцатеричная строка
MyError FP300KZ::PrgGraphicLogo(int RowNum, std::string Data)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcPrgGraphicLogo;

	msg+= Utility::IntToStdStr(RowNum);
	msg+=',';
	msg+=Data;

	msg+=(char)0x05;
	std::string answer="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);

	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("PrgGraphicLogo("+ Utility::IntToStdStr(RowNum)+"); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
//Программирование графического логотипа
///\param RowNum - Номер строки
///\param Data - Результат "01010101110"
MyError FP300KZ::getGraphicLogo(int RowNum, std::string &Data)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg,res;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcPrgGraphicLogo;
	msg+='R'+ Utility::IntToStdStr(RowNum);
	msg+=(char)0x05;
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),res);
	if(b)
	{
		Data="";
		for(uint4 i=0;i<res.size()/2;i++)
		{
			std::string sub=res.substr(i*2,2);
			int ch=0;
			#if defined( _VC )
				sscanf(sub.c_str(),"%X",&ch);
			#endif
			#if defined( _BORLAND )
				AnsiString str=sub.c_str();
				ch=StrToInt("0x"+str);
			#endif
			//Преобразуем в строку из 1 и 0
			if(getBitVal(ch,7)) Data+='0'; else Data+='1';
			if(getBitVal(ch,6)) Data+='0'; else Data+='1';
			if(getBitVal(ch,5)) Data+='0'; else Data+='1';
			if(getBitVal(ch,4)) Data+='0'; else Data+='1';
			if(getBitVal(ch,3)) Data+='0'; else Data+='1';
			if(getBitVal(ch,2)) Data+='0'; else Data+='1';
			if(getBitVal(ch,1)) Data+='0'; else Data+='1';
			if(getBitVal(ch,0)) Data+='0'; else Data+='1';
		}
	}
	else
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("getGraphicLogo("+ Utility::IntToStdStr(RowNum)+"); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
//Фискализация
//<Password>,<Serial>
MyError FP300KZ::Fiscalization(std::string Password,std::string Serial,std::string& ErrCode)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg,str;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcFiscalization;
	msg+=Password+","+Serial;
	msg+=(char)0x05;
	std::string answer="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	ErrCode=answer; //Код ошибки
	m_ErrCode=answer;

	b=b && !Status->s[0][5]; //Признак ошибки
	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}
	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("Fiscalization("+Password+","+Serial+"); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
//Перерегистрация
//<OldPwd>,<Password>,<RNN>,<RNM>
MyError FP300KZ::reFiscalization(std::string OldPwd,std::string Password,std::string RNN,std::string RNM,std::string& ErrCode)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg,str;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcFiscalization;
	msg+=Password+","+OldPwd+","+RNN+","+RNM; //Была ошибка в документации (старый и новый пароль поменял местами)
	msg+=(char)0x05;
	std::string answer="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	ErrCode=answer;
	m_ErrCode=answer;

	b=b && !Status->s[0][5]; //Признак ошибки
	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("reFiscalization("+OldPwd+","+Password+","+RNN+","+RNM+"); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
//Информация о сумме накоплений за день
MyError FP300KZ::AmountOfSavingsPerDay(double& TaxA,double& TaxB,double& TaxC,double& TaxD,double& TaxE)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg,str;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcAmountOfSavingsPerDay;
	msg+=(char)0x05;
	std::string answer="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	b=b && !Status->s[0][5]; //Признак ошибки
	if(b)
	{
		TaxA= Utility::fromString<double>(Utility::CutBeforeFirst(answer,','))/M();//TaxA
		TaxB= Utility::fromString<double>(Utility::CutBeforeFirst(answer,','))/M();//TaxB
		TaxC= Utility::fromString<double>(Utility::CutBeforeFirst(answer,','))/M();//TaxC
		TaxD= Utility::fromString<double>(Utility::CutBeforeFirst(answer,','))/M();//TaxD
		TaxE= Utility::fromString<double>(Utility::CutBeforeFirst(answer,','))/M();//TaxE
	}else
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("AmountOfSavingsPerDay(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
MyError FP300KZ::DepartmentReport()
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg,str;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcDepartmentReport;
	msg+=(char)0x05;
	std::string answer="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	b=b && !Status->s[0][5]; //Признак ошибки
	if (!b)
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}
	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("DepartmentReport(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
MyError FP300KZ::GetLastPrintedDocNumber(int& num)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	num = 0;

	std::string msg,str;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcGetLastPrintedDocNumber;
	msg+=(char)0x05;
	std::string answer="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	b=b && !Status->s[0][5]; //Признак ошибки
	if(b)
	{
		num = Utility::StdStrToInt(answer);
	}else 
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}

	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("GetLastPrintedDocNumber(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
//Информация о последней фискальной записи
///\param Clos Номер последней фискальной записи - 4 байта.
///\param Rec Количество фискальных чеков за день - 4 байта.
///\param Total Общая сумма продаж за день - 12  байт со знаком.
///\param VAT Общая сумма налогов за день - 12  байт со знаком.
///\param Date Дата последней фискальной записи - 6 байт /DDMMYY/.
MyError FP300KZ::LatestFiscalRecord(std::string& Clos,int& Rec, float& Total,float& VAT,std::string& Date)
{
	MyError err;
	err.ErrorCode = 0;
	err.ErrorMessage = "";

	std::string msg,str;
	msg+=(char)0x01; msg+=(char)0x20; msg+=(char)0x20; msg+=(char)fcLatestFiscalRecord;
	msg+=(char)0x05;
	std::string answer="";
	bool b=SendPMessage((uint1*)msg.c_str(),msg.size(),answer);
	b=b && !Status->s[0][5]; //Признак ошибки
	if(b)
	{
		Clos= Utility::CutBeforeFirst(answer,',');
		if(PrinterName.find("FP600")==std::string::npos)
			Rec= Utility::StdStrToInt(Utility::CutBeforeFirst(answer,','));
		else
			Rec=-1;
		Total= Utility::fromString<float>(Utility::CutBeforeFirst(answer,','));
		VAT= Utility::fromString<float>(Utility::CutBeforeFirst(answer,','));
		Date=answer;
	}else
	{
		err.ErrorCode = ResultCode();
		err.ErrorMessage = getErrorDesc(err.ErrorCode);
	}
	if (m_SaveLog)
		Utility::logrotate(PrinterName+"_"+PrinterNumber + ".log",std::string("GetLastPrintedDocNumber(); //")+(b ? "OK=" : "ERROR=")+ Utility::IntToStdStr(err.ErrorCode)+" "+ err.ErrorMessage);
	return err;
}
//---------------------------------------------------------------------------
