// Программа, включающая канал ЦАП устройства и отображающая значения указателя драйвера на текущий элемент заполнения буфера драйвера
// и указатель цикла обработки на текущий элемент заполнения буфера драйвера
// © ЗАО "ЭТМС" 1992-2011. Все права защищены

#include "stdafx.h"
#include <windows.h> 
#include <conio.h>
#include <stdio.h>
#include <math.h>

#include "zadc_int.h"						// Интерфейс библиотеки Zadc.dll

#define MAX_TYPE_DSP	20					// Максимальное поддерживаемое количество типов устройств
#define MAX_DEVICE_NAME	16					// Максимальное значение длины возвращаемого имени устройства

int main(int argc, char* argv[])
{
	long typeDevice;						// Тип устройства
	long numberDSP = 0;						// Порядковый номер сигнального процессора
	long Err;								// Код ошибки
	long enable;							// Флаг поддерживается / не поддерживается
	long numChannelsDAC;					// Количество включенных каналов ЦАП
	long numWordsDAC;						// Количество слов (по два байта) в одном отсчете ЦАП
	short *pBuffer16DAC = NULL;				// Указатель на начало буфера драйвера для ЦАП с разрядностью не более 16 бит
	long *pBuffer32DAC = NULL;				// Указатель на начало буфера драйвера для ЦАП с разрядностью более 16 бит 
	long sizeBufferDAC;						// Размер буфера драйвера в словах
	long sizeInterruptBufferDAC;			// Размер буфера прерывания в словах
	long sizePacketDAC;						// Количество отсчетов, обрабатываемых за один раз
	long sleepTime = 50;					// Время ожидания в цикле (мс)
	long responseTime = 250;				// Время реакции в цикле (мс). Должно быть больше времени ожидания
	long serial;							// Серийный номер устройства
	char deviceName[MAX_DEVICE_NAME];		// Имя устройства

	long size;								// Счетчик цикла
	long pointerDriverDAC = 0;				// Указатель драйвера на текущий элемент заполнения буфера драйвера
	long pointerDriverDAC_old = 0;			// Предыдущее значение указателя драйвера на буфер драйвера
	long pointerCycleDAC = 0;				// Указатель цикла обработки на текущий элемент заполнения буфера драйвера

	double freqDAC;							// Частота дискретизации ЦАП
	double attenDAC0 = 0.1;					// Коэффициент затухания по первому каналу ЦАП 
	double resolutionDAC;					// Вес младшего разряда ЦАП

	double currentSinusTime = 0.;				// Аргумент функции синус
	double deltaSinusTime;					// Значение инкремента аргумента функции синус
	double volt0;							// Мгновенное текущее значение, записываемое в ЦАП (код)
	double amplitudeSin = 0.1;				// Амплитуда синусоидального сигнала (В)
	double freqSin = 10;					// Частота синусоидального сигнала (Гц)
	
	// Цикл подключения к первому поддерживаемому устройству
	for(typeDevice = 0; typeDevice < MAX_TYPE_DSP; typeDevice++)
	{
		// Подключение к драйверу устройства
		Err = ZOpen(typeDevice, numberDSP);
		// Если подключение прошло без ошибок
		if(Err == 0)
		{
			// Проверка поддержки устройством ЦАП
			Err = ZGetEnableDAC(typeDevice, numberDSP, &enable);
			// Если устройство поддерживает ЦАП
			if(Err == 0 && enable != 0)
			{
				// Выход из цикла подключения
				break;
			}
			// Если устройство не поддерживает ЦАП
			else
			{
				// Вывод информации об ошибке
				printf("ZGetEnableDAC() return Error = 0x%X\n\r", Err);
				// Отключение от драйвера устройства
				Err = ZClose(typeDevice, numberDSP);
			}
		}
	}

	// Если не удалось подключиться к драйверу устройства
	if(typeDevice >= MAX_TYPE_DSP)
	{
		// Вывод информации об ошибке
		printf("Device not found! Error = 0x%X\n\r", Err);
		getch();
		return 0;
	}
	// Если удалось подключиться к драйверу устройства
	else
	{
		// Вывод информации о том, что произошло подключение к драйверу устройства
		printf("Device found...\n\r");
	}

	// Опрос имени устройства
	Err = ZGetNameDevice(typeDevice, numberDSP, deviceName, MAX_DEVICE_NAME);
	// Если опрос выполнился с ошибкой
	if(Err != 0)
	{
		// Вывод информации об ошибке
		printf("ZGetNameDevice() return Error = 0x%X\n\r", Err);
		// Отключение от драйвера устройства
		Err = ZClose(typeDevice, numberDSP);
		getch();
		return 0;
	}
	// Если опрос выполнился без ошибок
	else
	{
		// Вывод имени устройства
		printf("Device name: %s\n\r", deviceName);
	}

	// Опрос серийного номера устройства
	Err = ZGetSerialNumberDSP(typeDevice, numberDSP, &serial);
	// Если опрос выполнился с ошибкой
	if(Err != 0)
	{
		// Вывод информации об ошибке
		printf("ZGetNameDevice() return Error = 0x%X\n\r", Err);
		// Отключение от драйвера устройства
		Err = ZClose(typeDevice, numberDSP);
		getch();
		return 0;
	}
	// Если опрос выполнился без ошибок
	else
	{
		// Вывод серийного номера устройства
		printf("Serial number: %ld\n\r", serial);
	}

	// Запрос на включение первого канала ЦАП устройства
	Err = ZSetOutputDAC(typeDevice, numberDSP, 0, 1);
	// Если запрос выполнился с ошибкой
	if(Err != 0)
	{
		// Вывод информации об ошибке
		printf("ZSetOutputDAC() return Error = 0x%X\n\r", Err);
		// Отключение от драйвера устройства
		Err = ZClose(typeDevice, numberDSP);
		getch();
		return 0;
	}
	// Если запрос выполнился без ошибок
	else
	{
		// Вывод информации об успешном включении первого канала ЦАП устройства
		printf("First channel activation is successful...\n\r");
	}

	// Опрос количества включенных каналов ЦАП
	// Если включено каналов больше одного, то пример правильно работать не будет
	// (синус будет выдаваться на все каналы, причем его реальная частота разделится на количество включенных каналов)
	Err = ZGetNumberOutputDAC(typeDevice, numberDSP, &numChannelsDAC);
	// Если опрос выполнился с ошибкой
	if(Err != 0)
	{
		// Вывод информации об ошибке
		printf("Function ZGetNumberOutputDAC() return Error = 0x%X\n\r", Err);
		// Отключение от драйвера устройства
		Err = ZClose(typeDevice, numberDSP);
		getch();
		return 0;
	}
	// Если опрос выполнился без ошибок
	else
	{
		// Вывод количества включенных каналов ЦАП устройства
		printf("Quantity of activated DAC channel: %ld\n\r", numChannelsDAC);
	}

	// Опрос веса младшего разряда ЦАП первого канала устройства
	Err = ZGetDigitalResolChanDAC(typeDevice, numberDSP, 0, &resolutionDAC);
	// Если опрос выполнился с ошибкой
	if(Err != 0)
	{
		// Вывод информации об ошибке
		printf("ZGetDigitalResolutionDAC() return Error = 0x%X\n\r", Err);
		// Отключение от драйвера устройства
		Err = ZClose(typeDevice, numberDSP);
		getch();
		return 0;
	}
	// Если опрос выполнился без ошибок
	else
	{
		// Вывод веса младшего разряда ЦАП первого канала устройства
		printf("First channel digital resolution: %f\n\r", resolutionDAC);
	}

	// Опрос количества слов в одном отсчете ЦАП
	Err = ZGetWordsDAC(typeDevice, numberDSP, &numWordsDAC);
	// Если опрос выполнился с ошибкой
	if(Err != 0)
	{
		// Вывод информации об ошибке
		printf("ZGetWordsDAC() return Error = 0x%X\n\r", Err);
		// Отключение от драйвера устройства
		Err = ZClose(typeDevice, numberDSP);
		getch();
		return 0;
	}
	// Если опрос выполнился без ошибок
	else
	{
		// Вывод количества слов в одном отсчете ЦАП устройства
		printf("Quantity of words: %ld\n\r", numWordsDAC);
	}

	// Опрос частотs дискретизации ЦАП
	Err = ZGetFreqDAC(typeDevice, numberDSP, &freqDAC);
	// Если опрос выполнился с ошибкой
 	if(Err != 0)
	{
		// Вывод информации об ошибке
		printf("ZGetFreqDAC() return Error = 0x%X\n\r", Err);
		// Отключение от драйвера устройства
		Err = ZClose(typeDevice, numberDSP);
		getch();
		return 0;
	}
	// Если опрос выполнился без ошибок
	else
	{
		// Вывод частоты дискретизации ЦАП устройства
		printf("Frequency: %f\n\r", freqDAC);
	}

	// Опрос размера буфера прерывания ЦАП
	Err = ZGetInterruptDAC(typeDevice, numberDSP, &sizeInterruptBufferDAC);
	// Если опрос выполнился с ошибкой
	if(Err != 0)
	{
		// Вывод информации об ошибке
		printf("ZGetInterruptDAC() return Error = 0x%X\n\r", Err);
		// Отключение от драйвера устройства
		Err = ZClose(typeDevice, numberDSP);
		getch();
		return 0;
	}
	// Если опрос выполнился без ошибок
	else
	{
		// Вывод размера буфера прерывания ЦАП
		printf("Interrupt buffer size: %ld\n\r", sizeInterruptBufferDAC);
	}

	// Запрос на установку коэффициента затухания аттенюатора ЦАП по первому каналу
	Err = ZSetAttenDAC(typeDevice, numberDSP, 0, attenDAC0, &attenDAC0);
	// Если запрос выполнился с ошибкой
	if(Err != 0)
	{
		// Вывод информации об ошибке
		printf("ZSetAttenDAC() return Error = 0x%X\n\r", Err);
		// Отключение от драйвера устройства
		Err = ZClose(typeDevice, numberDSP);
		getch();
		return 0;
	}

	// Проверка переменных, чтобы избежать деления на ноль
	if(numWordsDAC < 1 || numWordsDAC > 2 || freqDAC < 1. || attenDAC0 == 0. || resolutionDAC == 0.)
	{
		// Вывод информации об ошибке
		printf("Error DAC parameters\n\r");
		// Отключение от драйвера устройства
		Err = ZClose(typeDevice, numberDSP);
		getch();
		return 0;
	}

	// Запрос буфера ЦАП
	Err = ZGetBufferDAC(typeDevice, numberDSP, (void**) &pBuffer16DAC, &sizeBufferDAC);
	// Если запрос выполнился с ошибкой
	if(Err != 0)
	{
		// Вывод информации об ошибке
		printf("Function ZGetBufferDAC() return Error = 0x%X\n\r", Err);
		// Отключение от драйвера устройства
		Err = ZClose(typeDevice, numberDSP);
		getch();
		return 0;
	}
	pBuffer32DAC = (long*) pBuffer16DAC;

	// Вычисление размера пакета согласно заданному времени реакции (опережения)
	sizePacketDAC = (long) freqDAC * responseTime / 1000;
	sizePacketDAC = numWordsDAC * sizePacketDAC;

	// Размер пакета должен быть не меньше двух размеров буфера прерывания и не больше половины буфера драйвера
	if(sizePacketDAC < 2 * sizeInterruptBufferDAC)
		sizePacketDAC = 2 * sizeInterruptBufferDAC;
	if(sizePacketDAC > sizeBufferDAC / 2)
		sizePacketDAC = sizeBufferDAC / 2;

	// Рассчет параметров для генерации синусоидального сигнала (число "Пи" = 4. * atan(1.))
	amplitudeSin = amplitudeSin / (resolutionDAC * attenDAC0);
	deltaSinusTime = 2. * (4. * atan(1.)) * freqSin / freqDAC;
	
	// Запись в буфер драйвера первых двух пакетов
	size = 2 * sizePacketDAC / numWordsDAC;
	// Для ЦАП с размерностью не более 16 бит
	if(numWordsDAC == 1)
	{
		for(long i = 0; i < size; i++)
		{
			volt0 = amplitudeSin * sin(currentSinusTime);
			pBuffer16DAC[i] = (short) volt0;
			currentSinusTime += deltaSinusTime;
		}
	}
	// Для ЦАП с разрядностью более 16 бит
	else
	{
		for(long i = 0; i < size; i++)
		{
			volt0 = amplitudeSin * sin(currentSinusTime);
			pBuffer32DAC[i] = (long) volt0;
			currentSinusTime += deltaSinusTime;
		}
	}
	pointerCycleDAC = 2 * sizePacketDAC;

	// Запрос на останов ЦАП
	Err = ZStopDAC(typeDevice, numberDSP);
	
	// Запрос на останов АЦП
	Err = ZStopADC(typeDevice, numberDSP);
	
	// Запрос на запуск ЦАП
	Err = ZStartDAC(typeDevice, numberDSP);
	
	// Запрос на запуск АЦП
	Err = ZStartADC(typeDevice, numberDSP);
	
	// Цикл генерации синусоидального сигнала и записи данных ЦАП
	while(!kbhit())
	{
		// Задержка обновления данных ЦАП для отображения
		Sleep(sleepTime);

		// Запрос указателя на текущий элемент буфера
		Err = ZGetPointerDAC(typeDevice, numberDSP, &pointerDriverDAC);
		// Если запрос выполнился с ошибкой
		if(Err != 0)
		{
			// Вывод информации об ошибке
			printf("Function ZGetPointerDAC() return Error = 0x%X\n\r", Err);
			// Выход из цикла
			break;
		}

		// Вывод информации об указателях
		printf("pointerCycleDAC = %ld, pointerDriverDAC = %ld\n", pointerCycleDAC, pointerDriverDAC);

		// Если опережение записи данных больше чем на один пакет, то перейти в начало цикла и подождать
		if(pointerCycleDAC - pointerDriverDAC > sizePacketDAC)
			continue;
		if((pointerDriverDAC > pointerCycleDAC) && (sizeBufferDAC - pointerDriverDAC + pointerCycleDAC > sizePacketDAC))
			continue;

		// Обновление предыдущего значения указателя драйвера
		pointerDriverDAC_old = pointerDriverDAC;

		// Запись в буфер драйвера очередного пакета данных
		size = sizePacketDAC;
        // Если пакет выходит за границы буфера драйвера, то его нужно разделить на две части
		if(pointerCycleDAC + sizePacketDAC > sizeBufferDAC)
			size = sizeBufferDAC - pointerCycleDAC;
		size = size / numWordsDAC;

		// Для ЦАП с размерностью не более 16 бит
		if(numWordsDAC == 1)
		{
			for(long i = 0; i < size; i++)
			{
				volt0 = amplitudeSin * sin(currentSinusTime);
				pBuffer16DAC[pointerCycleDAC + i] = (short) volt0;
				currentSinusTime += deltaSinusTime;
			}
		}
		// Для ЦАП с разрядностью более 16 бит
		else
		{
			for(long i = 0; i < size; i++)
			{
				volt0 = amplitudeSin * sin(currentSinusTime);
				pBuffer32DAC[pointerCycleDAC / numWordsDAC + i] = (long) volt0;
				currentSinusTime += deltaSinusTime;
			}
		}
			
		// Передвижение указателя на отсчет для следующей записи
		pointerCycleDAC += numWordsDAC * size;
		// Если подошли к концу буфера, то перейти в начало
		if(pointerCycleDAC >= sizeBufferDAC)
			pointerCycleDAC = 0;

		if(size < (sizePacketDAC / numWordsDAC))
		{
			// Запись в буфер драйвера второй части пакета данных, если пакет пришлось разорвать 
			size = (sizePacketDAC / numWordsDAC) - size;
			// Для ЦАП с размерностью не более 16 бит
			if(numWordsDAC == 1)
			{
				for(long i = 0; i < size; i++)
				{
					volt0 = amplitudeSin * sin(currentSinusTime);
					pBuffer16DAC[pointerCycleDAC + i] = (short) volt0;
					currentSinusTime += deltaSinusTime;
				}
			}
			// Для ЦАП с разрядностью более 16 бит
			else
			{
				for(long i = 0; i < size; i++)
				{
					volt0 = amplitudeSin * sin(currentSinusTime);
					pBuffer32DAC[pointerCycleDAC / numWordsDAC + i] = (long) volt0;
					currentSinusTime += deltaSinusTime;
				}
			}

			// Передвижение указателя на отсчет для следующей записи
			pointerCycleDAC += numWordsDAC * size;
		}
	}

	// Запрос на останов ЦАП
	Err = ZStopDAC(typeDevice, numberDSP);
	
	// Запрос на останов АЦП
	Err = ZStopADC(typeDevice, numberDSP);
	
	// Запрос на освобождение буфера ЦАП
	if(pBuffer16DAC != NULL)
	{
		Err = ZRemBufferDAC(typeDevice, numberDSP, (void**) &pBuffer16DAC);
		// Если запрос выполнился с ошибкой
		if(Err != 0)
		{
			// Вывод информации об ошибке
			printf("Function ZRemBufferDAC() return Error = 0x%X\n\r", Err);
		}
	}

	// Отключение от драйвера устройства
	Err = ZClose(typeDevice, numberDSP);
	// Если запрос выполнился с ошибкой
	if(Err != 0)
	{
		// Вывод информации об ошибке
		printf("Function ZClose() return Error = 0x%X\n\r", Err);
	}

	if(!kbhit())
		getch();

	printf("Press any key for exit...");
	getch();

 	return 0;
}
