/* CIN source file */

#include "extcode.h"
#include <windows.h>
#include <stdio.h>
#include "..\..\..\Include\wrRtusbapi.h"

/* Typedefs */

typedef struct {
	int32 dimSize;
	int16 BufferEl[1];
	} TD4;
typedef TD4 **TD4Hdl;

typedef struct {
	TD4Hdl Buffer;
	uInt32 ReadOv;
	uInt32 ReadEvent;
	} TD3;

typedef struct {
	int32 dimSize;
	TD3 ReadBufferPars[1];
	} TD2;
typedef TD2 **TD2Hdl;

typedef struct {
	TD4Hdl Buffer;
	uInt32 WriteOv;
	uInt32 WriteEvent;
	} TD6;

typedef struct {
	int32 dimSize;
	TD6 WriteBufferPars[1];
	} TD5;
typedef TD5 **TD5Hdl;

typedef struct {
	uInt32 DllVersion;
	uInt32 InterfaceType;
	uInt32 InterfaceInstance;
	uInt32 ModuleHandle;
	TD2Hdl ReadBuffersParsArray;
	TD5Hdl WriteBuffersParsArray;
	} TD1;

typedef struct {
	int32 dimSize;
	float32 AdcOffsetCoef[1];
	} TD8;
typedef TD8 **TD8Hdl;

typedef struct {
	int32 dimSize;
	float32 AdcScaleCoef[1];
	} TD9;
typedef TD9 **TD9Hdl;

typedef struct {
	int32 dimSize;
	float32 DacOffsetCoef[1];
	} TD10;
typedef TD10 **TD10Hdl;

typedef struct {
	int32 dimSize;
	float32 DacScaleCoef[1];
	} TD11;
typedef TD11 **TD11Hdl;

typedef struct {
	uInt16 VirtualSlot;
	LStrHandle ModuleName;
	LStrHandle SerialNumber;
	uInt8 UsbSpeed;
	LStrHandle AvrVersion;
	LStrHandle ModuleRevision;
	LStrHandle DspType;
	LVBoolean IsDacPresented;
	LVBoolean DspLoading;
	LStrHandle DspVersion;
	uInt32 DspClockout;
	TD8Hdl AdcOffsetCoefArray;
	TD9Hdl AdcScaleCoefArray;
	TD10Hdl DacOffsetCoefArray;
	TD11Hdl DacScaleCoefArray;
	} TD7;

typedef struct {
	LVBoolean Status;
	uInt32 ViErrorNumber;
	LStrHandle ViName;
	LStrHandle ViErrorString;
	LStrHandle CinName;
	LStrHandle CinErrorString;
	} TD12;

#define MODULE_NAME_STRING_LENGTH		(11)
#define MODULE_SERIAL_NUMBER_STRING_LENGTH	(11)
#define AVR_VERSION_STRING_LENGTH		(5)
#define MODULE_REVISION_STRING_LENGTH		(2)
#define DSP_TYPE_STRING_LENGTH			(17)
#define IS_DAC_PRESENTED_STRING_LENGTH		(4)
#define DSP_VERSION_STRING_LENGTH		(7)
#define ADC_CALIBRATION_COEF_ARRAY_LENGTH	(8)
#define DAC_CALIBRATION_COEF_ARRAY_LENGTH	(2)

enum {UNKNOWN_MODULE, USB2185_MODULE, USB3000_MODULE};

// объявления функций
CIN MgErr CINRun(TD1 *InterfaceInfo, TD7 *ModuleInfo, TD12 *ViStatus);
CIN MgErr CINProperties(int32 prop, void *data);

// ---------------------------------------------------------------
// 
// ---------------------------------------------------------------
MgErr CINRun(TD1 *InterfaceInfo, TD7 *ModuleInfo, TD12 *ViStatus)
{
	uInt16 i;
	// структура с информацией о драйвере DSP
	DSP_INFO_USB3000 di;
	// структура с информацией из ППЗУ модуля
	FLASH_USB3000 fi;
	// указатель на интерфейс модуля
	LPVOID pModule;
	// ошибка подпрограмм LabVIEW
	MgErr Error;

	// посмотрим была ли ошибка в предыдущих CIN		
	if(ViStatus->Status == LVFALSE) return noErr;

	// указатель на интерфейс модуля
	pModule = (LPVOID)InterfaceInfo->InterfaceInstance;

	// с каким модулем работаем?
	if(InterfaceInfo->InterfaceType == USB3000_MODULE)
	{
		// существует ли готовый интерфейс с модулем USB3000?
		if(pModule != NULL)
		{
			// мы уже выделяли место под строчку с названием модуля?
			if(LStrLen(*ModuleInfo->ModuleName) != MODULE_NAME_STRING_LENGTH)
			{
				// выделим место под под строчку с названием модуля
				Error = NumericArrayResize(uB, 1L, (UHandle*)&ModuleInfo->ModuleName, MODULE_NAME_STRING_LENGTH);
				if(Error != noErr) { ViStatus->Status= LVFALSE; return Error; }
				LStrLen(*ModuleInfo->ModuleName) = MODULE_NAME_STRING_LENGTH;
			}

			// мы уже выделяли место под строчку с серийным номером модуля?
			if(LStrLen(*ModuleInfo->SerialNumber) != MODULE_NAME_STRING_LENGTH)
			{
				// выделим место под строчку с серийным номером модуля
				Error = NumericArrayResize(uB, 1L, (UHandle*)&ModuleInfo->SerialNumber, MODULE_SERIAL_NUMBER_STRING_LENGTH);
				if(Error != noErr) { ViStatus->Status= LVFALSE; return Error; }
				LStrLen(*ModuleInfo->SerialNumber) = MODULE_SERIAL_NUMBER_STRING_LENGTH;
			}

			// мы уже выделяли место под строчку с версией драйвера AVR?
			if(LStrLen(*ModuleInfo->SerialNumber) != AVR_VERSION_STRING_LENGTH)
			{
				// выделим место под строчку с версией драйвера AVR
				Error = NumericArrayResize(uB, 1L, (UHandle*)&ModuleInfo->AvrVersion, AVR_VERSION_STRING_LENGTH);
				if(Error != noErr) { ViStatus->Status= LVFALSE; return Error; }
				LStrLen(*ModuleInfo->AvrVersion) = AVR_VERSION_STRING_LENGTH;
			}

			// мы уже выделяли место под строчку с ревизией модуля?
			if(LStrLen(*ModuleInfo->ModuleRevision) != MODULE_REVISION_STRING_LENGTH)
			{
				// выделим место под строчку с ревизией модуля
				Error = NumericArrayResize(uB, 1L, (UHandle*)&ModuleInfo->ModuleRevision, MODULE_REVISION_STRING_LENGTH);
				if(Error != noErr) { ViStatus->Status= LVFALSE; return Error; }
				LStrLen(*ModuleInfo->ModuleRevision) = MODULE_REVISION_STRING_LENGTH;
			}

			// мы уже выделяли место под строчку с типом DSP?
			if(LStrLen(*ModuleInfo->DspType) != DSP_TYPE_STRING_LENGTH)
			{
				// выделим место под строчку с ревизией модуля
				Error = NumericArrayResize(uB, 1L, (UHandle*)&ModuleInfo->DspType, DSP_TYPE_STRING_LENGTH);
				if(Error != noErr) { ViStatus->Status= LVFALSE; return Error; }
				LStrLen(*ModuleInfo->DspType) = DSP_TYPE_STRING_LENGTH;
			}

			// мы уже выделяли место под строчку с версией DSP?
			if(LStrLen(*ModuleInfo->DspVersion) != DSP_VERSION_STRING_LENGTH)
			{
				// выделим место под строчку с ревизией модуля
				Error = NumericArrayResize(uB, 1L, (UHandle*)&ModuleInfo->DspVersion, DSP_VERSION_STRING_LENGTH);
				if(Error != noErr) { ViStatus->Status= LVFALSE; return Error; }
				LStrLen(*ModuleInfo->DspVersion) = DSP_VERSION_STRING_LENGTH;
			}
			// массив с калибр. коэф. смещения нуля АЦП (всего восемь коэф.)
			if((*ModuleInfo->AdcOffsetCoefArray)->dimSize != ADC_CALIBRATION_COEF_ARRAY_LENGTH)
			{
				Error = NumericArrayResize(fS, 1L, (UHandle*)&ModuleInfo->AdcOffsetCoefArray, ADC_CALIBRATION_COEF_ARRAY_LENGTH);
				if(Error != noErr) { ViStatus->Status= LVFALSE; return Error; }
				(*ModuleInfo->AdcOffsetCoefArray)->dimSize = ADC_CALIBRATION_COEF_ARRAY_LENGTH;
			}
			// массив с калибр. коэф. масштаба АЦП (всего восемь коэф.)
			if((*ModuleInfo->AdcScaleCoefArray)->dimSize != ADC_CALIBRATION_COEF_ARRAY_LENGTH)
			{
				Error = NumericArrayResize(fS, 1L, (UHandle*)&ModuleInfo->AdcScaleCoefArray, ADC_CALIBRATION_COEF_ARRAY_LENGTH);
				if(Error != noErr) { ViStatus->Status= LVFALSE; return Error; }
				(*ModuleInfo->AdcScaleCoefArray)->dimSize = ADC_CALIBRATION_COEF_ARRAY_LENGTH;
			}
			// массив с калибр. коэф. смещения нуля ЦАП (всего два коэф.)
			if((*ModuleInfo->DacOffsetCoefArray)->dimSize != DAC_CALIBRATION_COEF_ARRAY_LENGTH)
			{
				Error = NumericArrayResize(fS, 1L, (UHandle*)&ModuleInfo->DacOffsetCoefArray, DAC_CALIBRATION_COEF_ARRAY_LENGTH);
				if(Error != noErr) { ViStatus->Status= LVFALSE; return Error; }
				(*ModuleInfo->DacOffsetCoefArray)->dimSize = DAC_CALIBRATION_COEF_ARRAY_LENGTH;
			}
			// массив с калибр. коэф. масштаба ЦАП (всего два коэф.)
			if((*ModuleInfo->DacScaleCoefArray)->dimSize != DAC_CALIBRATION_COEF_ARRAY_LENGTH)
			{
				Error = NumericArrayResize(fS, 1L, (UHandle*)&ModuleInfo->DacScaleCoefArray, DAC_CALIBRATION_COEF_ARRAY_LENGTH);
				if(Error != noErr) { ViStatus->Status= LVFALSE; return Error; }
				(*ModuleInfo->DacScaleCoefArray)->dimSize = DAC_CALIBRATION_COEF_ARRAY_LENGTH;
			}




			// обнуляем хэндл устройства
			InterfaceInfo->ModuleHandle = (DWORD)INVALID_HANDLE_VALUE;
			// попробуем открыть виртуальный слот для модуля USB3000
			if(!OpenDevice_Usb3000(pModule, ModuleInfo->VirtualSlot))
			{
				ViStatus->Status= LVFALSE; return noErr;
			}

			// попытаемся получить хэндл открытого устройства
			InterfaceInfo->ModuleHandle = (DWORD)GetModuleHandle_Usb3000(pModule);
			if((HANDLE)InterfaceInfo->ModuleHandle == INVALID_HANDLE_VALUE)
			{
				ViStatus->Status= LVFALSE; return noErr;
			}

			// прочитаем название модуля
			if(!GetModuleName_Usb3000(pModule, LStrBuf(*ModuleInfo->ModuleName)))
			{
				ViStatus->Status= LVFALSE; return noErr;
			}

			// прочитаем серийный номер модуля
			if(!GetModuleSerialNumber_Usb3000(pModule, LStrBuf(*ModuleInfo->SerialNumber)))
			{
				ViStatus->Status= LVFALSE; return noErr;
			}

			// поробуем выяснить скорость работы USB шины
			if(!GetUsbSpeed_Usb3000(pModule, &ModuleInfo->UsbSpeed))
			{
				ViStatus->Status= LVFALSE; return noErr;
			}

			// прочитаем версию драйвера AVR
			if(!GetAvrVersion_Usb3000(pModule, LStrBuf(*ModuleInfo->AvrVersion)))
			{
				ViStatus->Status= LVFALSE; return noErr;
			}

			// обязательно проинициализируем поле size структуры RTUSB3000::FLASH
			fi.size = sizeof(FLASH_USB3000);
			// получим информацию из ППЗУ модуля
			if(!GET_FLASH_Usb3000(pModule, &fi))
			{
				ViStatus->Status= LVFALSE; return noErr;
			}
			// копируем строчку с ревизией модуля
			LStrBuf(*ModuleInfo->ModuleRevision)[0] = fi.Revision;
			LStrBuf(*ModuleInfo->ModuleRevision)[1] = 0x0;
			// копируем строчку с типом DSP
			strcpy(LStrBuf(*ModuleInfo->DspType), fi.DspType);
			// есть ли ЦАП на борту модуля?
			if(fi.IsDacPresented) ModuleInfo->IsDacPresented = LVTRUE;
			else ModuleInfo->IsDacPresented = LVFALSE;
			// тактовая чатота работы DSP в кГц
			ModuleInfo->DspClockout = fi.DspClockout/1000;
			// копируем корректировочные коэффициенты для АЦП
			for(i = 0x0; i < ADC_CALIBRATION_COEF_ARRAY_LENGTH; i++)
			{
				(*ModuleInfo->AdcOffsetCoefArray)->AdcOffsetCoef[i] = fi.AdcOffsetCoef[i];
				(*ModuleInfo->AdcScaleCoefArray)->AdcScaleCoef[i] = fi.AdcScaleCoef[i];
			}
			// копируем корректировочные коэффициенты для ЦАП
			for(i = 0x0; i < DAC_CALIBRATION_COEF_ARRAY_LENGTH; i++)
			{
				(*ModuleInfo->DacOffsetCoefArray)->DacOffsetCoef[i] = fi.DacOffsetCoef[i];
				(*ModuleInfo->DacScaleCoefArray)->DacScaleCoef[i] = fi.DacScaleCoef[i];
			}

			// код драйвера DSP возьмём из соответствующего ресурса штатной DLL библиотеки
			if(!LOAD_DSP_Usb3000(pModule, NULL))
			{
				ViStatus->Status= LVFALSE; return noErr;
			}

			// проверим загрузку в модуль драйвера DSP
		 	if(!MODULE_TEST_Usb3000(pModule))
			{
				ModuleInfo->DspLoading = LVFALSE;
				ViStatus->Status= LVFALSE; return noErr;
			}
			else ModuleInfo->DspLoading = LVTRUE;

			// получим версию загруженного драйвера DSP
			if(!GET_DSP_INFO_Usb3000(pModule, &di))
			{
				ViStatus->Status= LVFALSE; return noErr;
			}
			// теперь отобразим версию загруженного драйвера DSP
			sprintf(LStrBuf(*ModuleInfo->DspVersion), "%1u.%1u\n", di.DspMajor, di.DspMinor);
		}       
		else
		{
			ViStatus->Status= LVFALSE;
		}
	}
	else 
	{ 
		ViStatus->Status= LVFALSE; 
	}

	return noErr;
}

// ---------------------------------------------------------------
// заявляем, что данный CIN - потокобезопасный
// ---------------------------------------------------------------
CIN MgErr CINProperties(int32 prop, void *data)
{
	switch (prop) 
	{
		case kCINIsReentrant:
		*(Bool32 *)data = TRUE;
		return noErr;
	}
	return mgNotSupported;
}
