#include "../../dll/qmx.h"
#include <shellapi.h>
#include <stdio.h>
#include <conio.h> 


#define QMS301_SLOT	0
#define QMS10_SLOT	1


HANDLE SD;                              // Дескриптор системы
QMX_CONFIG CFG;                         // Конфигурация системы
WORD QMS10Table[16];					// Таблица опроса каналов для QMS10
QMX_CC_F CC_Adc[3];						// Калибровочные коэффициенты QMS10
QMX_CC_F CC_QMS301[16];					// Калибровочные коэффициенты QMS30 


static unsigned int DataPtr, DataPtrOld, CurrentPtr, LengthDataBuf;
static unsigned short int *Data;

static unsigned int QMS_data[8][32], QMS_iter[8][32], time;

void CheckErr(void);
void quit(void);
void DisplayData(void);

//void main(void)
void main(int argc, char* argv[])
{
	char s_wrk[64];
	int i_wrk, mod, ch;


    ///////////////////////////////////////////////////////////////////////////////////////
	////////		Этап инициализации и конфигурации системы
	///////////////////////////////////////////////////////////////////////////////////////

	printf("Please wait....\r");
	
	// Запустим сервер
	ShellExecuteW(NULL, TEXT("open"), TEXT("qmbox_ds.exe"), TEXT("-p3"), NULL, SW_SHOWNORMAL);
	Sleep(500);

	// Получим дискриптор системы
	SD = 0;
	SD=QMX_CircBufAttach(0);
	if (SD == NULL) {
		printf("ERROR: No QMBox found.");
		quit(); 
	}

	// Проинициализуем систему
	QMX_InitModules(SD, QMX_LOG_NONE, NULL);
	CheckErr();

	// Фиктивный вызов QMX_Prepare - выясним конфигурацию устройства
	// т.е. из каких модулей оно состоит
	QMX_MOD_SetActive(SD, 0, QMX_ON);
	QMX_Prepare(SD, 100, &CFG);
	CheckErr();
	QMX_MOD_SetActive(SD, 0, QMX_OFF);
	
	// Убедимся, что модули в устройстве стоят в нужном порядке
	//////////////////////////////////////////////////////////////
	strncpy_s (s_wrk, CFG.ModName[QMS301_SLOT], 5); s_wrk[5] = 0;
	if (!_stricmp(s_wrk, "QMS30"))	printf("1 Module name OK\n");
	else{ printf("Module Name error\n");	quit();	}

	strncpy_s (s_wrk, CFG.ModName[QMS10_SLOT], 5); s_wrk[5] = 0;
	if (!_stricmp(s_wrk, "QMS10"))	printf("2 Module name OK\n");
	else{ printf("Module Name error\n");	quit();	}
	////////////////////////////////////////////////////////////////


	// Подготовка к работе QMS301
	// Считаем из ППЗУ модуля колибровочные коэффициенты
	for (i_wrk=0; i_wrk<16; i_wrk++) QMX_QMS301_ReadCC(SD, QMS301_SLOT, i_wrk, &CC_QMS301[i_wrk]);
	

	// Подготовка к работе QMS10
	// Считаем из ППЗУ модуля колибровочные коэффициенты
	// Для трех входных диапазонов - с усилением 1, 4 и 16
	for (i_wrk=0; i_wrk<3; i_wrk++) QMX_QMS10_ReadCC(SD, QMS10_SLOT, i_wrk, &CC_Adc[i_wrk]);

	// Заполним таблицу опроса модуля QMS10:
	// в сеансе сбора данных будут участвовать 3 первых каналов устройства - в дифференциальном режиме
	// с усилениями соответственно 1, 4, 16
	QMX_QMS10_BuildTableItem(SD, 0, QMX_QMS10_MODE_D, QMX_QMS10_GAIN_1,  &QMS10Table[0]);
	QMX_QMS10_BuildTableItem(SD, 1, QMX_QMS10_MODE_D, QMX_QMS10_GAIN_4,  &QMS10Table[1]);
	QMX_QMS10_BuildTableItem(SD, 2, QMX_QMS10_MODE_D, QMX_QMS10_GAIN_16, &QMS10Table[2]);

	// Запишем таблицу опроса в модуль
	QMX_QMS10_SetTable(SD, QMS10_SLOT, QMS10Table, 3);

	// Установим частоту сбора данных - 20 кГц (4 кГц на канал)
	QMX_QMS10_SetAdcRate(SD, QMS10_SLOT, 20000.0, NULL);




	// Объявим активными модули АЦП
	QMX_MOD_SetActive(SD, QMS301_SLOT, QMX_ON);
	QMX_MOD_SetActive(SD, QMS10_SLOT, QMX_ON);


	// Подготовимся к сбору данных
	QMX_Prepare(SD, 100, &CFG);
	CheckErr();
	
	LengthDataBuf = *CFG.CBInput.buf_size;						// размер кольцевого буфера данных, заполняемого сервером
	Data = (unsigned short int*)CFG.CBInput.buf_start;			// указатель на начало кольцевого буфера данных,
																// заполняемого сервером
	DataPtrOld = 0;
	time = 0;

	// Запустим сбор данных
	QMX_Start(SD);
	CheckErr();


    ///////////////////////////////////////////////////////////////////////////////////////
	////////		Сеанс передачи данных
	///////////////////////////////////////////////////////////////////////////////////////


	while (!_kbhit()){											// цикл непрерывного сбора данных
																// (до нажатия кнопки клавиатуры)

		DataPtr = *CFG.CBInput.buf_ptr;							//получим значение указателя на последний 
																// полученный элемент данных						
		for (CurrentPtr = DataPtrOld; CurrentPtr != DataPtr; CurrentPtr += 2) { // цикл считывания всех полученных элементов данных
			
			if(CurrentPtr >= *CFG.CBInput.buf_size)				// Проверки, необходимые
				CurrentPtr = 0;									// чтобы текущий указатель 
			if ((!CurrentPtr)&&(!DataPtr))break;				// не перескочил через границу буфера

			mod = (Data[CurrentPtr] >> 5) & 0x07;				// в четном (младшем) 16-ти битном слове элемента данных содержится 
			ch  = Data[CurrentPtr]  & 0x1f;						// информация о номерах канала (младщие 5-ть бит) и модуля (сл. 3-ри бита).
			QMS_data[mod][ch] += Data[CurrentPtr+1];			// в нечетном (старшем) 16-ти битном слове элемента данных содержится
																// в нечетном (старшем) 16-ти битном слове элемента данных содержится
																// информация о величине сигнала измеренного в данном канале данного модуля
																// (в кодах АЦП).
																// в настоящем примере измерения интегрируются в соответствующей ([модуль][канал])
																// ячейке массива накопления. В реальной программе пользователя измерения могут
																// перемещаться в поканальные массивы без усреднения, для дальнейшей обработки или
																// записи в выходные файлы.
	


			QMS_iter[mod][ch]++;								// счетчик количества суммирований для данного канала
	
		}

		DataPtrOld = DataPtr;						// запоминание предыдущего указателя на последний полученный
													// элемент данных

		time++;										// счетчик количества временных интервалов
		if (time >=5){								// если накопление длится более 5 интервалов,
			DisplayData();							// произвести отображение результатов измерений
			time = 0;								// обнуление счетчика количества  интервалов
		}

		Sleep(25);									// Ожидание следующей порции данных от сервера 
													// В реальной программе в этом месте вместо Sleep может производится
													// обработка полученных данных и их запись в файл
													// В данном случае мы будем включать/выключать реле в зависимости от показаний QMS70


 }

	quit();											// выход из программы
}


// Выход из программы
void quit(void){
	
	printf("\n\n Please wait....\r");
	QMX_Stop(SD, QMX_STOP_ALL);			// Остановим систему
	QMX_MOD_SetStartMode(SD, 0xFF, QMX_START_MODE_MANUAL); 									



	QMX_CircBufDetach(SD);              // Освободим виртуальный слот USB
										// Остановим сервер
	ShellExecute(NULL, TEXT("open"), TEXT("qmbox_ds.exe"), TEXT("-s0"), NULL, SW_SHOWNORMAL);
	printf("\n\n");
	ExitProcess(0);
}


// Проверка на ошибки
void CheckErr(void) {
char tmp_str[1024];

if (QMX_GetLastError(SD, tmp_str, sizeof(tmp_str))==QMX_OK){ return;}
else  {	printf("%s\n", tmp_str);	quit();}
}


// Отображение данных
void DisplayData(void){

	double d_wrk[16];
	int i, k;

	// вычисление усредненных значений результатов измерений, приведение их к физическим величинам при помощи
	// калибровочных коэффициентов:
	
	// Значение 14го канала QMS301 (Энкодер) 
	d_wrk[0] = ((double)QMS_data[QMS301_SLOT][14]) / ((double)QMS_iter[QMS301_SLOT][14]) * CC_QMS301[14].Scale + CC_QMS301[14].Offset;
	// Значение 15го канала QMS301 (Энкодер) 
	d_wrk[1] = ((double)QMS_data[QMS301_SLOT][15]) / ((double)QMS_iter[QMS301_SLOT][15]) * CC_QMS301[14].Scale + CC_QMS301[15].Offset;

	// Значение нулевого канала QMS10 в Вольтах
	d_wrk[2] = ((double)QMS_data[QMS10_SLOT][0]) / ((double)QMS_iter[QMS10_SLOT][0]) * CC_Adc[0].Scale + CC_Adc[0].Offset;
	// Значение первого канала QMS10 в Вольтах
	d_wrk[3] = ((double)QMS_data[QMS10_SLOT][1]) / ((double)QMS_iter[QMS10_SLOT][1]) * CC_Adc[1].Scale + CC_Adc[1].Offset;
	// Значение второго канала QMS10 в Вольтах
	d_wrk[4] = ((double)QMS_data[QMS10_SLOT][2]) / ((double)QMS_iter[QMS10_SLOT][2]) * CC_Adc[2].Scale + CC_Adc[2].Offset;

	
	// Печать на консоль
	printf("                                                                            \r");
	printf(" %3.3f    ", d_wrk[0]);
	printf(" %3.3f    ", d_wrk[1]);
	printf(" %3.3f %s ", d_wrk[2], CC_Adc[0].Units);
	printf(" %3.3f %s ", d_wrk[3], CC_Adc[1].Units);
	printf(" %3.3f %s   \r ", d_wrk[4], CC_Adc[2].Units);

	// обнуление рабочих ячеек усреднения результатов измерений :
	for (i = 0; i<8; i++)
		for (k = 0; k<16; k++)
		{QMS_data[i][k] = 0; QMS_iter[i][k] = 0;}


}





