Российский производитель и разработчик сертифицированного измерительного оборудования с 1987 года


Форум

Вы не вошли.

 Поиск | Регистрация | Вход 

#1 Техническая поддержка » Простейший плагин для LGraph2, на один канал. » 23.10.2017 13:18:04

Hitakiri
Ответов: 0

Здравствуйте.
Столкнулся с необходимостью получать среднеквадратичное значение с одного канала приходящего с LTR-24.
Начал писать плагин, и честно говоря завяз. Нужна помощь.
Код писал под Builder 6. Возможно кто-то писал что-то подобное и подскажет где ошибка.
Спасибо.
Код получился приблизительно такой (естественно не рабочий пример):

//-----------------------------------------------------------------------------------
#include <windows.h>
#include <math.h>
#include <stdio.h>
#include "..\\include\\plugin.h"

// индексы визуальных элементов
#define	VISUAL_INDEX_GRAPH		    (0)			// график
#define	VISUAL_INDEX_X			    (1)			// значение канала X
#define	VISUAL_INDEX_Y			    (3)			// значение канала Y
#define	VISUAL_INDEX_N				(5)			// размер выборки

// индексы параметров
#define	PARM_DURATION_SCALE		    (0)			// масштаб времени
#define	PARM_DURATION				(1)			// продолжительность выборки
#define	PARM_PRECISION				(2)			// число знаков после запятой
#define	PARM_LINE					(3)			// тип линии
#define	MAX_SIZE					(100000)	// максимальное число кадров, которые можно обработать за один раз

double FindFRQ(double *TEMP, int N, double DFRQ);

static struct PluginDataInfoStr DataInfo;		        // структура с настройками АЦП
struct PluginVisualMainStr LgraphVisual;		        // структура с настройками LGraph2

static int device_index = 0x0;					        // работаем с первым модулем АЦП
static double *YData, *XData, *YNewData, *Yout, *Yfreq; // указатели на временные буфера
static int Points;
static int LineTypeArray[0x2] = { VAL_THIN_LINE, VAL_FAT_LINE }; // массив параметров отображения линии на самописце

//***********************************************************************************
// Функция вызываемая при загрузке - выгрузке DLL плагина
//***********************************************************************************
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
	switch(reason)
	{
		case DLL_PROCESS_ATTACH:
			break;

		case DLL_PROCESS_DETACH:
		{
			if(XData)		free(XData);
			if(YData)		free(YData);
			if(YNewData)	free(YNewData);
			if(Yout)		free(Yout);
			if(Yfreq)		free(Yfreq);
			break;
		}
	}
	return 0x1;
}

//-----------------------------------------------------------------------------------
// главная функция обмена данными
//-----------------------------------------------------------------------------------
void WINAPI PluginDataExchange(struct PluginDataStr *data_str)
{
	int i, chan, index, n;
	int chan1, nch;
	double *ptr;
	double dt, mx, dx, duration;

	chan1 = DataInfo.adc_channels[0];		    // запомним номер канала 1 плагина (от 0 до 31)(из массива содержащего число каналов передаём номер первого канала)

	n = data_str->n;				            // сколько кадров будем обрабатывать
	if(n & 1) n--;                              // сделаем n четным
	dt = 1000000./DataInfo.rate[device_index];	// интервал в микросекундах
	nch = DataInfo.nch[device_index];           // число включённых в настройках программы каналов (в 99% это - nch[0])
	// переложим в XData, YData данные АЦП
	index = DataInfo.chan_kadr_offset[device_index][chan1];
	ptr = YData;
	for(i = 0x0; i < n; i++, index += nch) *ptr++ = data_str->data_to_plugin[index];

		// найдем среднее и среднеквадратичное
		for(i = 0x0, mx = 0.0; i < n; i++) mx += ptr[i];
		mx /= n;
		for(i = 0x0, dx = 0.0; i < n; i++) dx += (ptr[i]-mx)*(ptr[i]-mx);
		dx=sqrt(dx/n);

	data_str->slow_data[VISUAL_INDEX_Y] = dx;        //выводим среднеквадратичное по оси Y
	data_str->slow_data[VISUAL_INDEX_X] = n*dt/1000; //выводим время по оси X

	data_str->data_from_graph[chan]		= YData;     // Массив указателей для данных по оси Y

	// сохраним данные для передачи в ЛГраф
	data_str->n_from_graph[chan]		= n;        //число точек для для вывода на графике для канала
	data_str->control_index[chan]		= chan;		// номер графического элемента, в котором будет нарисован график
	data_str->color[chan]			= VAL_RED;	// цвет графика
	data_str->line_type[chan]			= VAL_SOLID;// тип линии (сплошной, точки и т.п.)
	data_str->line_mode[chan]			= LineTypeArray[DataInfo.parameters_int[PARM_LINE]];
}

//-----------------------------------------------------------------------------------
// информационная функция
//-----------------------------------------------------------------------------------
void WINAPI PluginInfo(struct PluginInfoStr *p_info)
{
	// установим общие переменные
	strcpy(p_info->name, "Spektr3");        // название плагина
	p_info->version			= 0x00010000;	// версия 1.0
	p_info->lgraph_version	= 0x222;		// плагин разработан для версии 2.22
	p_info->max_nch=0x1;                    // максимальное число каналов, которые может обработать плагин 2
    p_info->min_nch=0x1;                    // минимальное число каналов 1

	// установим параметры входных каналов плагина
	strcpy(p_info->channel_names[0], "Канал 1");

	p_info->parameters = 0x7;				// всего 7 параметров

	// Масштаб временного интервала отображения
	strcpy(p_info->parameters_names[PARM_DURATION_SCALE], "Масштаб временного интервала отображения");
	p_info->parameters_type[PARM_DURATION_SCALE] = L_TYPE_RING;
	strncpy(p_info->ring_names[PARM_DURATION_SCALE][0], "Секунды", 63);
	strncpy(p_info->ring_names[PARM_DURATION_SCALE][1], "Миллисекунды", 63);
	strncpy(p_info->ring_names[PARM_DURATION_SCALE][2], "Микросекунды", 63);
	strncpy(p_info->ring_names[PARM_DURATION_SCALE][3], "Кадры", 63);
	p_info->default_parameters_int[PARM_DURATION_SCALE] = 0x0;

	// Временной интервал отображения
	strcpy(p_info->parameters_names[PARM_DURATION], "Временной интервал отображения");
	p_info->parameters_type[PARM_DURATION] = L_TYPE_DOUBLE;
	p_info->default_parameters_dbl[PARM_DURATION] = 0.1;

	// Число знаков после запятой
	strcpy(p_info->parameters_names[PARM_PRECISION], "Число знаков после запятой.");
	p_info->parameters_type[PARM_PRECISION] = L_TYPE_INT;
	p_info->default_parameters_int[PARM_PRECISION] = 3;
	p_info->min_parameters_int[PARM_PRECISION] = 1;
	p_info->max_parameters_int[PARM_PRECISION] = 10;

	// Тип линии
	strcpy(p_info->parameters_names[PARM_LINE], "Тип линии");
	p_info->parameters_type[PARM_LINE] = L_TYPE_RING;
	strncpy(p_info->ring_names[PARM_LINE][0], "Тонкая", 63);
	strncpy(p_info->ring_names[PARM_LINE][1], "Толстая", 63);

	if(!XData)
	{
		// выделим память
		XData = malloc(MAX_SIZE*sizeof(double));
		if(XData == NULL) { strcpy(p_info->error, "Не хватает памяти"); return; }

		YData = malloc(MAX_SIZE*sizeof(double));
		if(YData == NULL) { free(XData); XData = 0; strcpy(p_info->error, "Не хватает памяти"); return; }

		YNewData = malloc(MAX_SIZE*sizeof(double));
		if(YNewData == NULL) { free(XData); XData = 0; free(YData); strcpy(p_info->error, "Не хватает памяти"); return; }

		if(Yout == NULL) Yout = malloc(sizeof(double)*MAX_SIZE/2);
		if(Yout == NULL) { free(XData); XData = 0; strcpy(p_info->error, "Не хватает памяти"); return; }

		if(Yfreq == NULL) Yfreq = malloc(sizeof(double)*MAX_SIZE);
		if(Yfreq == NULL) { free(XData); XData = 0; strcpy(p_info->error, "Не хватает памяти"); return; }
	}
}

//-----------------------------------------------------------------------------------
// обработка данных о параметрах модулей АЦП от L-Graph II
//-----------------------------------------------------------------------------------
void __stdcall PluginDataInfo(struct PluginDataInfoStr *d_info)
{
	int chan_1;

	if(!d_info->devices) { strcpy(d_info->error, "Нет модуля АЦП"); return; }
	if(!d_info->nch[device_index]) { strcpy(d_info->error, "Не выбраны каналы АЦП"); return; }
	if(d_info->adc_nch < 0x1) { strcpy(d_info->error, "Не выбраны каналы АЦП"); return; }

	DataInfo = *d_info;							// запомним параметры АЦП
    chan_1 = d_info->adc_channels[0];			// запомним номер канала (от 0 до 31)


	// проверим включен ли канал
	if(!d_info->chan_on[device_index][chan_1]) { sprintf(d_info->error, "Не выбран канал 1"); return; }

	// определим сколько точек будем обрабатывать
	switch(d_info->parameters_int[PARM_DURATION_SCALE])
	{
		case 0x0:
			Points = d_info->parameters_dbl[PARM_DURATION]*d_info->rate[device_index]+0.5;
			break;

		case 0x1:
			Points = d_info->parameters_dbl[PARM_DURATION]*d_info->rate[device_index]/1000.+0.5;
			break;

		case 0x2:
			Points = d_info->parameters_dbl[PARM_DURATION]*d_info->rate[device_index]/1000000.+0.5;
			break;

		case 0x3:
			Points = d_info->parameters_dbl[PARM_DURATION];
			break;
	}

	if(Points < 0x3) { sprintf(d_info->error, "Слишком мало точек"); return; }
	if(Points > MAX_SIZE) { sprintf(d_info->error, "Слишком много точек"); return; }

	d_info->input_kadrs_min = d_info->input_kadrs_max=Points;
	d_info->no_omit_old_data = 0x1;
}

//-----------------------------------------------------------------------------------
// настройка визуальных элементов
//-----------------------------------------------------------------------------------
void WINAPI PluginVisualSetting(struct PluginVisualMainStr *main_visual_settings, struct PluginVisualStr p_visual[])//{}
{
	int graph_height, graph_width, m_top, m_left;
	char *duration_names[]={"T, секунды", "T, миллисекунды", "T, микросекукнды", "T, кадры"};

	LgraphVisual = *main_visual_settings;

	main_visual_settings->n = 0x7;					// создаем 8 визуальных элементов
	main_visual_settings->plugin_height = main_visual_settings->height*0.7;	// высота 0.7 экрана

	// -=== НАСТРОЙКИ ГРАФИКА ===-
	graph_height = main_visual_settings->plugin_height - 40;
	graph_width = main_visual_settings->width - 120;
	m_top = 25;
	m_left = graph_width + 20;
	p_visual[VISUAL_INDEX_GRAPH].type = L_VISUAL_GRAPH;    // указываем, что данные выводятся в виде графика

	// настроим графические координаты
	p_visual[VISUAL_INDEX_GRAPH].top = 20;					// координата по вертикали графика
	p_visual[VISUAL_INDEX_GRAPH].height = graph_height;	    // высота графика
	p_visual[VISUAL_INDEX_GRAPH].width = graph_width;		// ширина графика
	p_visual[VISUAL_INDEX_GRAPH].left = 10;					// горизонтальная координата

	// сконфигурируем ось X
	p_visual[VISUAL_INDEX_GRAPH].x_axis_mode = 0x1;			// по умолчанию включим автомасштаб по оси X

	// сконфигурируем ось Y
	p_visual[VISUAL_INDEX_GRAPH].y_axis_mode = 0x1;			// по умолчанию включим автомасштаб по оси X


	 //-=== настройка остальных визуальных элементов ===-

	p_visual[VISUAL_INDEX_X].type = L_VISUAL_NUMERIC;
	strcpy(p_visual[VISUAL_INDEX_X].label_text, "DX (X)");
	p_visual[VISUAL_INDEX_X].top = m_top+50;				// координата по вертикали
	p_visual[VISUAL_INDEX_X].left = m_left;				// координата по горизонтали
	p_visual[VISUAL_INDEX_X].y_precision = DataInfo.parameters_int[PARM_PRECISION];

	p_visual[VISUAL_INDEX_Y].type = L_VISUAL_NUMERIC;
	strcpy(p_visual[VISUAL_INDEX_Y].label_text, "DX (Y)");
	p_visual[VISUAL_INDEX_Y].top = m_top+50*4+20;		// координата по вертикали
	p_visual[VISUAL_INDEX_Y].left = m_left;				// координата по горизонтали
	p_visual[VISUAL_INDEX_Y].y_precision = DataInfo.parameters_int[PARM_PRECISION];
}

// Функция сообщает плагину, что начался/закончился сбор данных (в данном плагине не используем)
void WINAPI PluginStartInput(struct PluginDataStr *data_str)	{ };
void WINAPI PluginStopInput(struct PluginDataStr *data_str)		{ };