1. Создаю объект класса E20-10:
TE20_10::TE20_10(string logFileName)
{
LUnknown* pIUnknown;
ULONG Err = L_SUCCESS,Err1;
PLATA_DESCR_U2 pd;
SLOT_PAR sl;
ULONG slot=0;
FILE *fplogFileName;
Process_Init = true;
fdata = NULL;
MSegmentSize = DEFAULT_SEGMENT_SIZE;//=25000000
MappedFileName = DEFAULT_MAPPEDFILENAME;
//Открываем Log file
out.open(logFileName.c_str());
if (!out) throw "Can//'t open file " + logFileName;
//Загружаем dll библиотеку
CallCreateInstance("lcomp.dll");
//Сканируем порты ввода вывода и находим на одном из них необходимый модуль
while(1)
{
pIUnknown = CreateInstance(slot); // slot 0
if(pIUnknown == NULL) {Err = GetLastError(); break;}
HRESULT hr = pIUnknown->QueryInterface(IID_ILDEV,(void**)&pI);
if(!SUCCEEDED(hr)) { Err1 = 1; break;}
pIUnknown->Release();
Err1 = (ULONG)pI->OpenLDevice();
pI->GetSlotParam(&sl);
if(sl.BoardType == E2010)
{
E20_10BiosFile = "E2010";
Err1 =0; break;
}
else if(sl.BoardType == E2010B)
{
E20_10BiosFile = "e2010m";
Err1 =0; break;
}
pI->CloseLDevice();
slot++;
}
if(Err)
{
MessageBox(NULL,MES_E2010_SEARCHLCARDFALED,MES_ERROR,MB_OK|MB_ICONERROR);
out << "No L-Card boards on this computer" << endl;
Process_Init = false;
}
if(Err1)
{
if(Err1==1)
{
MessageBox(NULL,MES_E2010_GETINTERFASEFALED,MES_ERROR,MB_OK|MB_ICONERROR);
out << "Failed get interface." << endl;
}
if(Err1==2)
{
MessageBox(NULL,MES_E2010_SEARCHE2010FALED,MES_ERROR,MB_OK|MB_ICONERROR);
out << "No E2010 boards on this computer" << endl;
}
Process_Init = false;
}
else
out << "Found first E2010 board at LDev" << slot << "..." << endl;
//Получаем интерфейс модуля
if(Process_Init)
{ pI->CloseLDevice();
out << "Get IDaqLDevice interface" << endl;
Err = pIUnknown->QueryInterface(IID_ILDEV,(void**)&pI);
if(!SUCCEEDED(Err))
{
out << "Get IDaqLDevice failed" << endl;
Process_Init = false;
}
}
//Получаем доступ к устройству
if(Process_Init)
{
Err = (ULONG) pI->OpenLDevice();
out << "OpenLDevice Handle " << hex << Err << endl;
if(Err==ULONG(INVALID_HANDLE_VALUE))
{
Process_Init = false;
out << "OpenLDevice faled" << endl;
}
}
//Загружаем прошивку ДСП
if(Process_Init)
{
Err = pI->LoadBios(E20_10BiosFile.c_str());
out << "LoadBios status " << L_RESULT(Err).c_str() << endl;
if(Err==L_ERROR)
{
Process_Init = false;
out << "LoadBios faled" << endl;
}
}
//Тестируем плату
if(Process_Init)
{
Err = pI->PlataTest();
out << "Plata test " << L_RESULT(Err).c_str() << endl;
if(Err==L_ERROR)
{
Process_Init = false;
out << "PlataTest faled" << endl;
}
}
//Получаем все данные модуля
if(Process_Init)
{
out << endl << "Slot parameters" << endl;
Err = pI->GetSlotParam(&sl);
if(Err==L_ERROR)
{
Process_Init = false;
out << "GetSlotParams faled" << endl;
}
else
{
out << "Base " << hex << sl.Base << endl;
out << "BaseL " << sl.BaseL << endl;
out << "Mem " << sl.Mem << endl;
out << "MemL " << sl.MemL << endl;
out << "Type " << sl.BoardType << endl;
out << "DSPType " << sl.DSPType << endl;
out << "Irq " << sl.Irq << endl;
}
}
//Считываем данные из flash-памяти
if(Process_Init)
{
out << endl << "Read FLASH" << endl;
Err = pI->ReadPlataDescr(&pd); // fill up properties
if(Err==L_ERROR)
{
Process_Init = false;
out << "ReadPlataDescr faled" << endl;
}
else
{
out << "SerNum " << pd.t6.SerNum << endl;
out << "BrdName " << pd.t6.BrdName << endl;
out << "Rev " << pd.t6.Rev << endl;
out << "DspType " << pd.t6.DspType << endl;
out << "IsDacPresent " << pd.t6.IsDacPresent << endl;
out << "Quartz " << dec << pd.t1.Quartz << endl;
//Заполняем массив калибровочных коэффициентов
for(int i=0;i<=4;i++)
for(int j=0;j<=3;j++)
{
ZeroOffsetCoeff[i][j] = pd.t6.KoefADC[i*3+j];
ScaleCoeff[i][j] = pd.t6.KoefADC[12+i*3+j];
}
out << "Offset coefficients:" << endl;
out << ZeroOffsetCoeff[0][0] << "//t" << ZeroOffsetCoeff[1][0] << "//t" << ZeroOffsetCoeff[2][0] << "//t" << ZeroOffsetCoeff[3][0] << endl;
out << ZeroOffsetCoeff[0][1] << "//t" << ZeroOffsetCoeff[1][1] << "//t" << ZeroOffsetCoeff[2][1] << "//t" << ZeroOffsetCoeff[3][1] << endl;
out << ZeroOffsetCoeff[0][2] << "//t" << ZeroOffsetCoeff[1][2] << "//t" << ZeroOffsetCoeff[2][2] << "//t" << ZeroOffsetCoeff[3][2] << endl;
out << "Scale coefficients:" << endl;
out << ScaleCoeff[0][0] << "//t" << ScaleCoeff[1][0] << "//t" << ScaleCoeff[2][0] << "//t" << ScaleCoeff[3][0] << endl;
out << ScaleCoeff[0][1] << "//t" << ScaleCoeff[1][1] << "//t" << ScaleCoeff[2][1] << "//t" << ScaleCoeff[3][1] << endl;
out << ScaleCoeff[0][2] << "//t" << ScaleCoeff[1][2] << "//t" << ScaleCoeff[2][2] << "//t" << ScaleCoeff[3][2] << endl << endl;
}
}
//Если что-то не получилось, то говорим об этом
if(!Process_Init)
MessageBox(NULL,MES_E2010_OPENFALED,MES_ERROR,MB_OK | MB_ICONERROR);
}
все нормально проходит.
Далее запускаем измерения:
bool TE20_10::Oscilloscope(void)
{
AnalyseConstLevel = false;
//Проверяем что инициализация прошла успешно
if(!Process_Init)
{
MessageBox(NULL,MES_E2010_DEVICENOTREADY,MES_ERROR,MB_OK | MB_ICONERROR);
return false;
}
//Считаем сколько каналов мы используем
int NumChanel = GetNumberOfChanel();
/*Вычисляем сколько отсчетом мы хотим
int Multiplier = GetMultiplier();
ULONG Err;
//Рассчитваем параметры сбора данных
//Общее количество точек, которое мы хотим получить
unsigned long TotalNumberOfPoints = BlockSize*Multiplier*NumChanel*NumberOfBlocks;
unsigned long TotalNumberOfPages;
ADC_PAR adcPar;
DWORD tm;
int MaxNumOfPages = 129;
do{
//Расcчитваем количество страниц, требующихся для получения такого количества точек
TotalNumberOfPages = TotalNumberOfPoints/IrqStep + (TotalNumberOfPoints%IrqStep==0?0:1);
//Теперь стремимся минимизировать количество лишних точек путем оптимального выбора числа страниц
//Ищем количество страниц в буффере при котором количество лишних точек минимально
UINT AdditionalMinimum = TotalNumberOfPages,NumOfPages = 32;
for(int i=32;i<MaxNumOfPages;i++)
{
if(AdditionalMinimum>=(TotalNumberOfPages/i + (TotalNumberOfPages%i==0?0:1))*i-TotalNumberOfPages)
{
AdditionalMinimum = (TotalNumberOfPages/i + (TotalNumberOfPages%i==0?0:1))*i-TotalNumberOfPages;
NumOfPages = i;
}
}
pages = NumOfPages;
multi = (TotalNumberOfPages + AdditionalMinimum)/pages*2;
if(multi<2) multi=1;
tm = 512000; // сколько отсчетов мы хотим (размер буффера ПК)
Err = pI->RequestBufferStream(&tm,L_STREAM_ADC);
if(Err==L_ERROR)
{
out << "Can//'t allocate memory! " << endl;
return false;
}
out << "Allocated memory size(word): " << tm << endl;
// настроили параметрыы сбора
adcPar.t2.s_Type = L_ADC_PARAM;
adcPar.t2.AutoInit = 1;
adcPar.t2.dRate = ADCFrequency;
adcPar.t2.dKadr = 0.0;
adcPar.t2.SynchroType = 0x01;
adcPar.t2.AdcIMask = SIG_0|SIG_1|SIG_2|SIG_3;
adcPar.t2.NCh = NumChanel;
NumChanel=0;
for(int i=0;i<TOTAL_NUMBER_CHANEL;i++)
if(Chanels[i])
{
adcPar.t2.Chn[NumChanel] = i;
NumChanel++;
//Дальше устанавливаем необходимый диапазон входного сигнала
if(i==0 && ChanelsAmplification[i])//<-- 1-й канал
adcPar.t2.AdcIMask |= (ChanelsAmplification[i]==1?V10_0:V03_0);
if(i==1 && ChanelsAmplification[i])//<-- 2-й канал
adcPar.t2.AdcIMask |= (ChanelsAmplification[i]==1?V10_1:V03_1);
if(i==2 && ChanelsAmplification[i])//<-- 3-й канал
adcPar.t2.AdcIMask |= (ChanelsAmplification[i]==1?V10_2:V03_2);
if(i==3 && ChanelsAmplification[i])//<-- 4-й канал
adcPar.t2.AdcIMask |= (ChanelsAmplification[i]==1?V10_3:V03_3);
}
adcPar.t2.FIFO = FIFO;
adcPar.t2.IrqStep = IrqStep;
adcPar.t2.Pages = pages;
adcPar.t2.IrqEna = 1;
adcPar.t2.AdcEna = 1;
//Заполняем параметры ввода
Err = pI->FillDAQparameters(&adcPar.t2);
if(Err==L_ERROR)
{
out << "FillDAQparameters error! " << endl;
return false;
}
//Записываем параметры ввода в память АЦП
Err = pI->SetParametersStream(&adcPar.t2, &tm, (void **)&data, (void **)&sync,L_STREAM_ADC);
if(Err==L_ERROR)
{
out << "SetParametersStream error! " << endl;
return false;
}
MaxNumOfPages = pages;
} while(adcPar.t2.Pages < pages);
out << "Buffer size(word): " << tm << endl;
out << "Pages: " << adcPar.t2.Pages << endl;
out << "IrqStep: " << adcPar.t2.IrqStep << endl;
out << "FIFO: " << adcPar.t2.FIFO << endl;
out << "Rate: " << adcPar.t2.dRate << endl;
DataStep = adcPar.t2.dRate/(Multiplier*NumChanel);
IrqStep = adcPar.t2.IrqStep;
pages = adcPar.t2.Pages;
out << "Started ..." << endl;
// Запоминаем размер половинки буффера
HalfBuffer = pages*IrqStep/2;
// Создаем файл (для того чтобы не возникало переполнения виртуальной памяти процесса будем выделять
//максимум 500 мегабайт памяти)
fsize = multi*pages*IrqStep/2; // размер файла, деленный на 2 потому что собираем половинками буффера
hFile=CreateFile(MappedFileName.c_str(),GENERIC_READ|GENERIC_WRITE,FILE_SHARE_WRITE,
NULL,CREATE_ALWAYS,FILE_FLAG_RANDOM_ACCESS,NULL);
if(hFile==INVALID_HANDLE_VALUE)
{
MessageBox(0,MES_FILEOPENERROR,MES_ERROR,MB_OK|MB_ICONERROR);
out << "File open error" << endl;
return false;
}
//Выделяем область памяти
hMap=CreateFileMapping(hFile,NULL,PAGE_READWRITE,0,(fsize>MainForm->E20_10->MSegmentSize?2*MainForm->E20_10->MSegmentSize:fsize*2),NULL);
if(hMap==NULL)
{
MessageBox(0,MES_FILEMAPERROR,MES_ERROR,MB_OK|MB_ICONERROR);
out << "File mapping error" << endl;
return false;
}
else
out << "Mapped file size (word):" << fsize<< endl;
//Проецируем файл на выделенную область памяти
fdata=(WORD *)MapViewOfFile(hMap,FILE_MAP_WRITE,0,0,0);
if(!fdata)
ShowMessage(SysErrorMessage(GetLastError()));
complete=0;
pI->EnableCorrection();
// Инициализируем внутренние переменные драйвера
Err = pI->InitStartLDevice();
if(Err==L_ERROR)
{
out << "InitStartLDevice error! " << endl;
return false;
}//*/
// Запускаем сбор в драйвере
Err = status=pI->StartLDevice();
if(Err==L_ERROR)
{
out << "StartLDevice error! " << endl;
return false;
}
// Создаем и запускаем поток сбора данных
hThread=CreateThread(0,0x2000,ServiceThread,0,0,&Tid);
return true;//Закончили
}
Поток сбора данных имеет следующий вид:
// Поток в котором осуществляется сбор данных
#pragma optimize ("", off)
ULONG WINAPI ServiceThread(PVOID)
{
ULONG halfbuffer = MainForm->E20_10->HalfBuffer; // Собираем половинками кольцевого буфера
ULONG fl2,fl1 = fl2 = (*sync<=halfbuffer)? 0:1; // Настроили флаги
USHORT *tmp, *tmp1;
MainForm->E20_10->MSegmentSizeUsage = 0;
MainForm->E20_10->MSegment = 0;
for (currMeasure = 0;currMeasure < MainForm->E20_10->multi;currMeasure++)// Цикл по необходимомму количеству половинок
{
//Следим за сегментированием памяти
if(halfbuffer*(currMeasure+1) - MainForm->E20_10->MSegment*MainForm->E20_10->MSegmentSizeUsage > MainForm->E20_10->MSegmentSize)
{ if(MainForm->E20_10->MSegment==0) MainForm->E20_10->MSegmentSizeUsage = halfbuffer*currMeasure;
MainForm->E20_10->MSegment++;
}
//WaitForSingleObject(hEventData,INFINITE);
while(fl2==fl1) fl2=(*sync<=halfbuffer)? 0:1; // Ждем заполнения половинки буфера
tmp=MainForm->E20_10->fdata+(halfbuffer*currMeasure -MainForm->E20_10->MSegment*MainForm->E20_10->MSegmentSizeUsage); // Настраиваем указатель в файле
tmp1=data+(halfbuffer*fl1); // Настраиваем указатель в кольцевом буфере
memcpy(tmp,tmp1,halfbuffer*sizeof(USHORT));// Записываем данные в файл
fl1=(*sync<=halfbuffer)? 0:1; // Обновляем флаг
Sleep(2); // если собираем медленно то можно и спать больше
if(StopMeasurement)
break;
}
//Sleep(300);
complete=1; // Мы завершили сбор данных
return 0; // Вышли
}
#pragma optimize ("", on)
если я запускаю сбор большой партии данных, то все нормально работает при любом соcтоянии входов и вопросов нет.
Проблема возникает, если я запускаю по таймеру например раз в 1 секунду сбор небольших партий данных например реализация длительностью 0.2 сек с частотой АЦП 1000кГц. В этом случае, если на АЦП не подключен никакой сигнал, то все тоже нормально работает и данные идут, в случае же если сигнал подключен то получаю 1-2 измерения и связьс АЦП пропадает (поток сбора данных никак не может дождаться прихода очередной партии данных). Аналогичный алгоритм с той же последней версией драйверов (конец мая 2010 г.) с платой L780 прекрасно работает в любом режиме. Данная проблема наблюдалась на нескольких E20-10 на разных компьютерах как под управлением Windows7, так и Windows XP.
Функция запускающая измерения по таймеру:
void __fastcall TOscilloscopeForm::OscilloscopeTimerTimer(TObject *Sender)
{
if(AllowTimerUpdate)
{
AllowTimerUpdate = false;
bool OscilloscopeResult;
OscilloscopeResult = Device->Oscilloscope();
//Проверяем что не было сбоев оборудования
if(!OscilloscopeResult)
{
OscilloscopeForm->Close();
return;
}
// Получаем необходимые данные и создаем необходимые массивы
//Если все нормально, то ждем пока закончатся измерения
while(!complete){};
Device->StopDevice();
/*перенос данных во временные массивы для обработки
....
*/
Device->FreeBuffers();
/*отображение данных
....
*/
AllowTimerUpdate = true;
}
}
// Еще два метода класса E20-10==Device
void TE20_10::FreeBuffers(void)
{
if(fdata) UnmapViewOfFile(fdata);
if(hMap)
if(CloseHandle(hMap)) hMap = NULL;
// освободим идентификатор файла данных
if(hFile)
if(CloseHandle(hFile)) hFile = NULL;
}
void TE20_10::StopDevice(void)
{
ULONG Err;
if(Process_Init)
{
Err = pI->StopLDevice(); // Остановили сбор
if(Err==L_ERROR)
out << "StopLDevice error!" << endl;
if(hEventData) CloseHandle(hEventData);
}
CloseHandle(hThread);
// out << "StartLDevice returned " << (status ? "TRUE":"FALSE") << endl;
}