//******************************************************************************
// Консольная программа для модуля USB3000 для ввода данных с АЦП с помощью
// интерфейсной функции READ_SAMPLE().
// Ввод осуществляется с первый двух каналов АЦП.
//******************************************************************************
#include <stdio.h>
#include <conio.h>
#include "Rtusbapi.h"

// аварийное завершение программы
void TerminateApplication(char *ErrorString, bool TerminationFlag = true);

// максимально возможное кол-во опрашиваемых виртуальных слотов
const WORD MaxVirtualSoltsQuantity = 127;

// текущая версия библиотеки Rtusbapi.dll
DWORD DllVersion;
// указатель на интерфейс модуля
IRTUSB3000 *pModule;
// название модуля
char ModuleName[10];
// скорость работы шины USB
BYTE UsbSpeed;
// серийный номер модуля
char ModuleSerialNumber[9];
// версия драйвера AVR
char AvrVersion[5];
// структура, содержащая информацию о версии драйвера DSP
RTUSB3000::DSP_INFO di;
// структура информации в ППЗУ модуля
RTUSB3000::FLASH fi;
// структура параметров работы АЦП
RTUSB3000::INPUT_PARS ip;

// кол-во опрашиваемых каналов модуля для потокового ввода данных
const WORD CHANNELS_QUANTITY = 0x4;
// частота  ввода данных
const double ReadRate = 3000.0;

// буфер данных
SHORT AdcSample1, AdcSample2;

//------------------------------------------------------------------------
// основная программа
//------------------------------------------------------------------------
void main(void)
{
	WORD i;

	// зачистим экран монитора
	clrscr();

	printf(" *****************************************\n");
	printf(" Console example for USB3000 READ_SAMPLE()\n");
	printf(" *****************************************\n\n");

	// проверим версию используемой библиотеки Rtusbapi.dll
	if((DllVersion = RtGetDllVersion()) != CURRENT_VERSION_RTUSBAPI)
	{
		char String[128];
		sprintf(String, " Rtusbapi.dll Version Error!!!\n   Current: %1u.%1u. Required: %1u.%1u",
											DllVersion >> 0x10, DllVersion & 0xFFFF,
											CURRENT_VERSION_RTUSBAPI >> 0x10, CURRENT_VERSION_RTUSBAPI & 0xFFFF);

		TerminateApplication(String);
	}
	else printf(" Rtusbapi.dll Version --> OK\n");

	// получим указатель на интерфейс модуля USB3000
	pModule = static_cast<IRTUSB3000 *>(RtCreateInstance("usb3000"));
	if(pModule == NULL)  TerminateApplication(" Module Interface --> Bad\n");
	else printf(" Module Interface --> OK\n");

	// попробуем обнаружить модуль USB3000 в первых 127 виртуальных слотах
	for(i = 0x0; i < MaxVirtualSoltsQuantity; i++) if(pModule->OpenDevice(i)) break;
	// что-нибудь обнаружили?
	if(i == MaxVirtualSoltsQuantity) TerminateApplication(" Can't find module USB3000 in first 127 virtual slots!\n");
	else printf(" OpenDevice(%u) --> OK\n", i);

	// прочитаем название модуля в нулевом виртуальном слоте
	if(!pModule->GetModuleName(ModuleName)) TerminateApplication(" GetModuleName() --> Bad\n");
	else printf(" GetModuleName() --> OK\n");
	// проверим, что это 'USB3000'
	if(strcmp(ModuleName, "USB3000")) TerminateApplication(" The module is not 'USB3000'\n");
	else printf(" The module is 'USB3000'\n");

	// узнаем текущую скорость работы шины USB20
	if(!pModule->GetUsbSpeed(&UsbSpeed)) { printf(" GetUsbSpeed() --> Bad\n"); exit(1); }
	else printf(" GetUsbSpeed() --> OK\n");
	// теперь отобразим версию драйвера AVR
	printf(" USB Speed is %s\n", UsbSpeed ? "HIGH (480 Mbit/s)" : "FULL (12 Mbit/s)");

	// прочитаем серийный номер модуля
	if(!pModule->GetModuleSerialNumber(ModuleSerialNumber)) TerminateApplication(" GetModuleSerialNumber() --> Bad\n");
	else printf(" GetModuleSerialNumber() --> OK\n");
	// теперь отобразим серийный номер модуля
	printf(" Module Serial Number is %s\n", ModuleSerialNumber);

	// прочитаем версию драйвера AVR
	if(!pModule->GetAvrVersion(AvrVersion)) TerminateApplication(" GetAvrVersion() --> Bad\n");
	else printf(" GetAvrVersion() --> OK\n");
	// теперь отобразим версию драйвера AVR
	printf(" Avr Driver Version is %s\n", AvrVersion);

	// код драйвера DSP возьмём из соответствующего ресурса штатной DLL библиотеки
	if(!pModule->LOAD_DSP()) TerminateApplication(" LOAD_DSP() --> Bad\n");
	else printf(" LOAD_DSP() --> OK\n");

	// проверим загрузку модуля
 	if(!pModule->MODULE_TEST()) TerminateApplication(" MODULE_TEST() --> Bad\n");
	else printf(" MODULE_TEST() --> OK\n");

	// получим версию загруженного драйвера DSP
	if(!pModule->GET_DSP_INFO(&di)) TerminateApplication(" GET_DSP_INFO() --> Bad\n");
	else printf(" GET_DSP_INFO() --> OK\n");
	// теперь отобразим версию загруженного драйвера DSP
	printf(" DSP Driver version is %1u.%1u\n", di.DspMajor, di.DspMinor);

	// обязательно проинициализируем поле size структуры RTUSB3000::FLASH
	fi.size = sizeof(RTUSB3000::FLASH);
	// получим информацию из ППЗУ модуля
	if(!pModule->GET_FLASH(&fi)) TerminateApplication(" GET_FLASH() --> Bad\n");
	else printf(" GET_FLASH() --> OK\n");

	// обязательно проинициализируем поле size структуры RTUSB3000::INPUT_PARS
	ip.size = sizeof(RTUSB3000::INPUT_PARS);
	// получим текущие параметры работы АЦП
	if(!pModule->GET_INPUT_PARS(&ip)) TerminateApplication(" GET_INPUT_PARS() --> Bad\n");
	else printf(" GET_INPUT_PARS() --> OK\n");

	// установим желаемые параметры ввода данных
	// !!! в данном примере для нас важна только передача в драйвер DSP
	// корректировочных коэффициентов, а остальные параметры устанавливаем
	// исключительно для порядка !!!
	ip.CorrectionEnabled = true;				  			// разрешим корректировку данных
	ip.InputClockSource = RTUSB3000::INTERNAL_INPUT_CLOCK;	// будем использовать внутренние тактовые испульсы для ввода данных
//	ip.InputClockSource = RTUSB3000::EXTERNAL_INPUT_CLOCK;	// будем использовать внешние тактовые испульсы для ввода данных
	ip.SynchroType = RTUSB3000::NO_SYNCHRO;			// не будем использовать никакую синхронизацию при вводе данных
//	ip.SynchroType = RTUSB3000::TTL_START_SYNCHRO;	// будем использовать цифровую синхронизацию старта при вводе данных
	ip.ChannelsQuantity = CHANNELS_QUANTITY; 			// четыре активных канала
	for(i = 0x0; i < CHANNELS_QUANTITY; i++) ip.ControlTable[i] = (WORD)(i);
	ip.InputRate = ReadRate;							 	// частота работы АЦП в кГц
	ip.InterKadrDelay = 0.0;
	// будем использовать фирменные калибровочные коэффициенты, которые храняться в ППЗУ модуля
	for(i = 0x0; i < 8; i++) { ip.AdcOffsetCoef[i] = fi.AdcOffsetCoef[i]; ip.AdcScaleCoef[i] = fi.AdcScaleCoef[i]; }
	// передадим требуемые параметры работы АЦП в модуль
	if(!pModule->SET_INPUT_PARS(&ip)) TerminateApplication(" SET_INPUT_PARS() --> Bad\n");
	else printf(" SET_INPUT_PARS() --> OK\n");

	// отобразим параметры модуля на экране монитора
	printf(" \n");
	printf(" Module USB3000 (S/N %s) is ready ... \n", fi.SerialNumber);
	printf("   Data Correction is %s\n", ip.CorrectionEnabled ? "enabled" : "disabled");

	printf("\n Press any key to terminate this program...\n");
	// цикл перманентного выполнения функции ADC_SAMPLE и
	// отображения полученных данных на экране диплея
	printf("\n\n");
	printf(" ADC Channel:                     1         2\n");
	while(!kbhit())
	{
		if(!pModule->READ_SAMPLE((WORD)(0x00), &AdcSample1)) TerminateApplication("\n\n  READ_SAMPLE(0,) --> Bad\n");
		else if(!pModule->READ_SAMPLE((WORD)(0x01), &AdcSample2)) TerminateApplication("\n\n  READ_SAMPLE(1,) --> Bad\n");

		printf(" AdcSample Data (ADC code):     %5d     %5d\r", AdcSample1, AdcSample2);
	}

	// освободим интерфейс модуля
	printf("\n");
	TerminateApplication("\n The program was completed successfully!!!\n", false);
}

//------------------------------------------------------------------------
// вывод сообщения и, если нужно, аварийный выход из программы
//------------------------------------------------------------------------
void TerminateApplication(char *ErrorString, bool TerminationFlag)
{
	// подчищаем интерфейс модуля
	if(pModule)
	{ 
		// освободим интерфейс модуля
		if(!pModule->ReleaseInstance()) printf(" ReleaseInstance() --> Bad\n"); 
		else printf(" ReleaseInstance() --> OK\n");
		// обнулим указатель на интерфейс модуля
		pModule = NULL; 
	}

	// выводим текст сообщения
	if(ErrorString) printf(ErrorString);

	// если нужно - аварийно завершаем программу
	if(TerminationFlag) exit(1);
	else return;
}

