view kk-data-provider.c @ 256:708de02ef948

Implement limit to frequency adjustment during recenter
author Daniele Nicolodi <daniele.nicolodi@obspm.fr>
date Fri, 05 Jun 2015 21:00:54 +0200
parents 9b35a2b2c759
children
line wrap: on
line source

/* FXAnalise data provider which directly interfaces with the KK FX80E counter */

#include <ansi_c.h>
#include <userint.h>
#include <formatio.h>
#include <utility.h>
#include <inifile.h>

#include "config.h"
#include "data-provider.h"
#include "KKFX80E.h"


#define FX_MODE_PI 0x02
#define FX_MODE_LAMBDA 0x03

#define DEFAULT_PORT "COM4:115200"
#define DEFAULT_NCHAN 4
#define DEFAULT_MODE FX_MODE_PI
#define TIMEOUT 1 /* seconds */
#define MAXRETRY 100

#define strneq(a, b, len) (strncmp((a), (b), (len)) == 0)


const char * FX_ModeString(int mode)
{
	const static char *modes[] = {
		[FX_MODE_PI] = "PI",
		[FX_MODE_LAMBDA] = "LAMBDA",
	};

	return modes[mode];
}


static char * FX_Command(unsigned char cmd, unsigned mask, unsigned value)
{
	char *resp;
	int rv, retry;
	unsigned int header;
	
	/* send command */
	rv = FX_Send(cmd);
	if (! rv)
		return NULL;
	
	/* wait successfull reply */
	for (retry = 0; retry < MAXRETRY; retry++) {
		rv = FX_Recv(&resp, TIMEOUT);
		if (! rv)
			return NULL;
		header = strtoul(resp, NULL, 16);
		if ((header & mask) == value)
			return resp;
	}
	
	/* max retry reached */
	return NULL;
}


int CVICALLBACK KKDataProvider (void *functionData)
{
	int main_thread_id;
	int rv;
	char *resp;
	int nchan = DEFAULT_NCHAN;
	int mode = DEFAULT_MODE;
	char port[256];
	char buffer[16];
	char header[16];
	struct event event;
	
	/* get main thread id to post messages to it */
	main_thread_id = CmtGetMainThreadID();
	
	/* configuration file path */ 
	char path[MAX_PATHNAME_LEN];
	GetIniFilePath(path); 

	/* load configuration file */ 
	IniText configuration = Ini_New(TRUE);
	Ini_ReadFromFile(configuration, path);

	/* serial port name */
	rv = Ini_GetStringIntoBuffer(configuration, "KK", "port", port, sizeof(port));
	if (rv < 1)
		strncpy(port, DEFAULT_PORT, sizeof(port));

	/* gate type */
	rv = Ini_GetStringIntoBuffer(configuration, "KK", "mode", buffer, sizeof(buffer));
	if (rv < 1)
		mode = DEFAULT_MODE;
	else if (stricmp(buffer, "PI") == 0)
		mode = FX_MODE_PI;
	else if (stricmp(buffer, "LAMBDA") == 0)
		mode = FX_MODE_LAMBDA;
	else
		send_message(main_thread_id, "KK Counter: unrecognised mode parameter '%s'", buffer);
	
	/* channel number */
	rv = Ini_GetInt(configuration, "KK", "nchan", &nchan);
	if (rv < 1)
		nchan = DEFAULT_NCHAN;
	
	/* free */ 
	Ini_Dispose(configuration);

	/* initialize library */
	FX_Init();
	
	/* connect to KK FX80E counter */
	rv = FX_Open(port);
	if (! rv) {
		send_message(main_thread_id, FX_Error());
		goto error;
	}

	/* get counter hardware version string */
	resp = FX_Command(0x81, 0xFFFF, 0x7001);
	if (! resp) {
		send_message(main_thread_id, FX_Error());
		goto error;
	}
	send_message(main_thread_id, "KK Counter: version %s", resp + 4);
	
	/* set report interval 1sec */
	resp = FX_Command(0x29, 0x0F00, 0x0900);
	if (! resp) {
		send_message(main_thread_id, FX_Error());
		goto error;
	}
	
	/* set mode */
	resp = FX_Command(0x40 + mode, 0x7000, (mode << 12));
	if (! resp) {
		send_message(main_thread_id, FX_Error());
		goto error;
	}
	send_message(main_thread_id, "KK Counter: set mode %s", FX_ModeString(mode));
	
	/* disable scrambler */
	resp = FX_Command(0x50, 0xFFFF, (mode << 12) + 0x0900);
	if (! resp) {
 		send_message(main_thread_id, FX_Error());
 		goto error;
 	}
	
	/* read nchan channels */
	resp = FX_Command(0x30 + nchan, 0xFFFF, (mode << 12) + 0x0900);
	if (! resp) {
		send_message(main_thread_id, FX_Error());
		goto error;
	}

	/* enable synchronization */
	resp = FX_Command(0x0F, 0x00, 0x00);
	if (! resp) {
		send_message(main_thread_id, FX_Error());
		goto error;
	}
	
	/* expected packet header */
	snprintf(header, sizeof(header), "%X", (mode << 12) + 0x0900);
	
	while (acquiring) {
		/* receive data from counter */
		FX_Recv(&resp, TIMEOUT);
		if (! resp) {
			send_message(main_thread_id, FX_Error());
			break;
		}
		
		/* data packets */
		if (strneq(resp, header, 4)) {
			
			/* timestamp */
			gettimeofday(&event.time, NULL);
			
			/* parse received data */
			rv = Scan(resp + 6, "%f; %f; %f; %f; %f; %f; %f; %f",
				&event.data[0], &event.data[1], &event.data[2], &event.data[3],
				&event.data[4], &event.data[5], &event.data[6], &event.data[7]);
			if (rv != nchan) {
				send_message(main_thread_id, "KK Counter: data conversion error: %d != %d", rv, nchan);
				goto error;
			}
			
			/* convert from kHz to Hz */
			for (int i = 0; i < nchan; i++)
				event.data[i] *= 1000.0;
			
			/* push data into the data queue */
			CmtWriteTSQData(dataQueue, &event, 1, TSQ_INFINITE_TIMEOUT, 0);
		
		} else if (strneq(resp, "7000", 4)) {
			/* ignore heart beat packet */
		} else if (strneq(resp, "7015", 4)) {
			/* ignore undocumented packet. it is sent by newer kk counters
			   for each data packet. it probably contains a sample count along
			   with some other information */
		} else if (strneq(resp, "7020", 4)) {
			/* undocumented packet. it probably reports the header for
			   subsequent data packets */
			send_message(main_thread_id, "KK Counter: packet header %s", resp + 7);
		} else if (strneq(resp, "7F51", 4)) {
			/* measurement interval synchronized */
			send_message(main_thread_id, "KK Counter: measurement interval synchronized");
		} else {
			/* send message to the main thread */
			send_message(main_thread_id, "KK Counter: %s", resp);
		}
	}
	
error:
	/* close serial port */
	FX_Close();
	/* free allocated resources */
	FX_Free();
	
	return 0;
}