Issues with Certain Waveforms on 2206BMSO

Having problems ? let us know the details here
Post Reply
wjlillis
Newbie
Posts: 1
Joined: Wed Dec 15, 2021 8:00 pm

Issues with Certain Waveforms on 2206BMSO

Post by wjlillis »

Hello!

I am attempting to write a program that uses a 2206BMSO Scope to conduct some measurements for a physics project. My code is almost entirely based upon snippets taken out of the example found on the company's github page: (https://github.com/picotech/picosdk-c-e ... 2000aCon.c)

I know that the scope isn't faulty, because using the PicoScope 6 Software, I'm able to get a steady view of both the signal generator I'm using to test, as well as the output the plastic scintillating bar that this project is based on.
I am trying to use the CollectStreamingTriggered subroutine from that code to record the input from this input, but am running into issues. When attached to a signal generator, the scope performs perfectly, writing all the values it recorded to a file. However, when the scope is attached to the plastic scintillating bar, it writes all 0's to the file (both DAC and converted mV values), interspaced with random instances of a -306 DAC count paired with a -4mV reading. I'm not really sure where or how this discrepancy arises. I've done my best to try to find the source of the error and as far as I can tell the driverBuffers that the device writes to gets these values and they're not being distorted by some other operation once they're on the device. Is it possible there's an issue with the device drivers, or is there some subtle issue with my code that's causing it to not take in certain inputs the correct way? I attempted to attach my code file to this post as a file, but received an http error, so I'll just post the text below. Any help would be immensely appreciated.

I'm new here, so I apologize if I'm going about any of this the wrong way.

Code: Select all

#include  //outputting stuff 
#include "ps2000aApi.h" //device-specific API
#include  //outputting stuff, not sure if I need both this and iostream
#include  //string manipulation for file naming

/* (Author's) Headers for Windows */
#ifdef _WIN32
#include "windows.h"
#include 
#include "ps2000aApi.h"
#else
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#endif

#include 
#ifndef PICO_STATUS
#include  //should let us get more out of the error codes
#endif

#define Sleep(a) usleep(1000*a)
#define scanf_s scanf
#define fscanf_s fscanf
#define memcpy_s(a,b,c,d) memcpy(a,c,d)

//The author defines a number of C-style structs at the beginning of his file
//they seem like useful ways to manage data about the device or the data it's taking in
//so we'll just paste them here and use them as is
#define PREF4 __stdcall

#define		BUFFER_SIZE 	1024
#define		DUAL_SCOPE		2
#define		QUAD_SCOPE		4

#define		AWG_DAC_FREQUENCY      20e6
#define		AWG_DAC_FREQUENCY_MSO  2e6
#define		AWG_PHASE_ACCUMULATOR  4294967296.0

typedef enum
{
	ANALOGUE,
	DIGITAL,
	AGGREGATED,
	MIXED
}MODE;

typedef struct
{
	int16_t DCcoupled;
	int16_t range;
	int16_t enabled;
}CHANNEL_SETTINGS;

typedef struct tTriggerDirections
{
	PS2000A_THRESHOLD_DIRECTION channelA;
	PS2000A_THRESHOLD_DIRECTION channelB;
	PS2000A_THRESHOLD_DIRECTION channelC;
	PS2000A_THRESHOLD_DIRECTION channelD;
	PS2000A_THRESHOLD_DIRECTION ext;
	PS2000A_THRESHOLD_DIRECTION aux;
}TRIGGER_DIRECTIONS;

typedef struct tPwq
{
	PS2000A_PWQ_CONDITIONS* conditions;
	int16_t nConditions;
	PS2000A_THRESHOLD_DIRECTION direction;
	uint32_t lower;
	uint32_t upper;
	PS2000A_PULSE_WIDTH_TYPE type;
}PWQ;

typedef struct
{
	int16_t					handle;
	PS2000A_RANGE			firstRange;
	PS2000A_RANGE			lastRange;
	uint8_t					signalGenerator;
	uint8_t					ETS;
	int16_t                 channelCount;
	int16_t					maxValue;
	CHANNEL_SETTINGS		channelSettings[PS2000A_MAX_CHANNELS];
	int16_t					digitalPorts;
	int16_t					awgBufferSize;
	double					awgDACFrequency;
}UNIT;

typedef struct tBufferInfo
{
	UNIT* unit;
	MODE mode;
	int16_t** driverBuffers;
	int16_t** appBuffers;
	int16_t** driverDigBuffers;
	int16_t** appDigBuffers;

} BUFFER_INFO;



/*Some global variables*/
int32_t cycles = 0;
uint32_t	timebase = 0; //originally set to 8 up here
int16_t     oversample = 1;
BOOL		scaleVoltages = TRUE;

uint16_t inputRanges[PS2000A_MAX_RANGES] = { 10,
	20,
	50,
	100,
	200,
	500,
	1000,
	2000,
	5000,
	10000,
	20000,
	50000 };

BOOL     		g_ready = FALSE;
int32_t 		g_times[PS2000A_MAX_CHANNELS];
int16_t     	g_timeUnit;
int32_t      	g_sampleCount;
uint32_t		g_startIndex;
int16_t			g_autoStopped;
int16_t			g_trig = 0;
uint32_t		g_trigAt = 0;
int16_t			g_overflow = 0;

char BlockFile[20] = "block.txt";
char DigiBlockFile[20] = "digiblock.txt";
char StreamFile[20] = "stream.txt"; //replace this with time dependent file name


/****************************************************************************
* _kbhitinit
*
* Initializes the _kbhit routine by grabbing the current state of the `Q` key
*
****************************************************************************/
int16_t _kbhitinit()
{
	//GetKeyState returns a short int, which is 2 bytes
	//Looking at the windows documentation...
	//high-order bit is 1, the key is down; otherwise, it is up.
	//If the low - order bit is 1, the key is toggled
	//Q for quit?
	return (GetKeyState('Q') && 0x0001);
}

/****************************************************************************
* _kbhitpoll
*
* Checks if the Q key has been toggled from its inital value of init after 
* the _kbhitinit function has been called
*
****************************************************************************/
bool _kbhitpoll(int16_t init)
{
	//this should check if the key has been toggled since
		//can probably be fooled by quick double presses
	//just grab lowest order bit, then compare with initial state
	if ((GetKeyState('Q') && 0x0001) == init)
	{
		return false;
	}
	return true;
}

/****************************************************************************
* adc_to_mv
*
* Convert an 16-bit ADC count into millivolts
****************************************************************************/
int32_t adc_to_mv(int32_t raw, int32_t ch, UNIT* unit)
{
	return (raw * inputRanges[ch]) / unit->maxValue;
}

/****************************************************************************
* mv_to_adc
*
* Convert a millivolt value into a 16-bit ADC count
*
*  (useful for setting trigger thresholds)
****************************************************************************/
int16_t mv_to_adc(int16_t mv, int16_t ch, UNIT* unit)
{
	return (mv * unit->maxValue) / inputRanges[ch];
}

/****************************************************************************
* timeUnitsToString
*
* Converts PS2000A_TIME_UNITS enumeration to string (used for streaming mode)
*
****************************************************************************/
int8_t* timeUnitsToString(PS2000A_TIME_UNITS timeUnits)
{
	int8_t* timeUnitsStr = (int8_t*)"ns";

	switch (timeUnits)
	{
	case PS2000A_FS:

		timeUnitsStr = (int8_t*)"fs";
		break;

	case PS2000A_PS:

		timeUnitsStr = (int8_t*)"ps";
		break;

	case PS2000A_NS:

		timeUnitsStr = (int8_t*)"ns";
		break;

	case PS2000A_US:

		timeUnitsStr = (int8_t*)"us";
		break;

	case PS2000A_MS:

		timeUnitsStr = (int8_t*)"ms";
		break;

	case PS2000A_S:

		timeUnitsStr = (int8_t*)"s";
		break;

	default:

		timeUnitsStr = (int8_t*)"ns";
	}

	return timeUnitsStr;

}

/****************************************************************************
* Callback
* used by ps2000a data streaming collection calls, on receipt of data.
* used to set global flags etc checked by user routines
****************************************************************************/
void PREF4 CallBackStreaming(int16_t handle,
	int32_t noOfSamples,
	uint32_t	startIndex,
	int16_t overflow,
	uint32_t triggerAt,
	int16_t triggered,
	int16_t autoStop,
	void* pParameter)
{
	int32_t channel;
	int32_t digiPort;
	BUFFER_INFO* bufferInfo = NULL;

	if (pParameter != NULL)
	{
		bufferInfo = (BUFFER_INFO*)pParameter;
	}

	// used for streaming
	g_sampleCount = noOfSamples;
	g_startIndex = startIndex;
	g_autoStopped = autoStop;
	g_overflow = overflow;

	// flag to say done reading data
	g_ready = TRUE;

	// flags to show if & where a trigger has occurred
	g_trig = triggered;
	g_trigAt = triggerAt;

	if (bufferInfo != NULL && noOfSamples)
	{
		if (bufferInfo->mode == ANALOGUE)
		{
			for (channel = 0; channel < bufferInfo->unit->channelCount; channel++)
			{
				if (bufferInfo->unit->channelSettings[channel].enabled)
				{
					if (bufferInfo->appBuffers && bufferInfo->driverBuffers)
					{
						if (bufferInfo->appBuffers[channel * 2] && bufferInfo->driverBuffers[channel * 2])
						{
							/* Author redefines memcpy for some reason */
							/*
							memcpy_s(&bufferInfo->appBuffers[channel * 2][startIndex], noOfSamples * sizeof(int16_t),
								&bufferInfo->driverBuffers[channel * 2][startIndex], noOfSamples * sizeof(int16_t));
							*/
							memcpy(&bufferInfo->appBuffers[channel * 2][startIndex], &bufferInfo->driverBuffers[channel * 2][startIndex], noOfSamples * sizeof(int16_t));
						}
						/*
						if (bufferInfo->appBuffers[channel * 2 + 1] && bufferInfo->driverBuffers[channel * 2 + 1])
						{
							memcpy_s(&bufferInfo->appBuffers[channel * 2 + 1][startIndex], noOfSamples * sizeof(int16_t),
								&bufferInfo->driverBuffers[channel * 2 + 1][startIndex], noOfSamples * sizeof(int16_t));
						}
						*/
					}
				}
			}
		}
		/*
		else if (bufferInfo->mode == AGGREGATED)
		{
			for (channel = 0; channel < bufferInfo->unit->digitalPorts; channel++)
			{
				if (bufferInfo->appDigBuffers && bufferInfo->driverDigBuffers)
				{
					if (bufferInfo->appDigBuffers[channel * 2] && bufferInfo->driverDigBuffers[channel * 2])
					{
						memcpy_s(&bufferInfo->appDigBuffers[channel * 2][startIndex], noOfSamples * sizeof(int16_t),
							&bufferInfo->driverDigBuffers[channel * 2][startIndex], noOfSamples * sizeof(int16_t));
					}
					if (bufferInfo->appDigBuffers[channel * 2 + 1] && bufferInfo->driverDigBuffers[channel * 2 + 1])
					{
						memcpy_s(&bufferInfo->appDigBuffers[channel * 2 + 1][startIndex], noOfSamples * sizeof(int16_t),
							&bufferInfo->driverDigBuffers[channel * 2 + 1][startIndex], noOfSamples * sizeof(int16_t));
					}
				}
			}
		}
		*/
		/*
		else if (bufferInfo->mode == DIGITAL)
		{
			for (digiPort = 0; digiPort < bufferInfo->unit->digitalPorts; digiPort++)
			{
				if (bufferInfo->appDigBuffers && bufferInfo->driverDigBuffers)
				{
					if (bufferInfo->appDigBuffers[digiPort] && bufferInfo->driverDigBuffers[digiPort])
					{
						memcpy_s(&bufferInfo->appDigBuffers[digiPort][startIndex], noOfSamples * sizeof(int16_t),
							&bufferInfo->driverDigBuffers[digiPort][startIndex], noOfSamples * sizeof(int16_t));
					}
				}
			}
		}
		*/
	}
}


/****************************************************************************
* ClearDataBuffers
*
* stops GetData writing values to memory that has been released
****************************************************************************/
PICO_STATUS ClearDataBuffers(UNIT* unit)
{
	int32_t i;
	PICO_STATUS status;

	/*
	for (i = 0; i < unit->channelCount; i++)
	{
		if ((status = ps2000aSetDataBuffers(unit->handle, (int16_t)i, NULL, NULL, 0, 0, PS2000A_RATIO_MODE_NONE)) != PICO_OK)
		{
			printf("ClearDataBuffers:ps2000aSetDataBuffers(channel %d) ------ 0x%08lx \n", i, status);
		}
	}
	*/
	/*
	for (i = 0; i < unit->channelCount; i++)
	{
		if ((status = ps2000aSetDataBuffers(unit->handle, (PS2000A_CHANNEL)(i + PS2000A_CHANNEL_A), NULL, NULL, 0, 0, PS2000A_RATIO_MODE_NONE)) != PICO_OK)
		{
			printf("ClearDataBuffers:ps2000aSetDataBuffers(channel %d) ------ 0x%08lx \n", i, status);
		}
	}
	*/
	/*
	for (i = 0; i < unit->digitalPorts; i++)
	{
		if ((status = ps2000aSetDataBuffer(unit->handle, (PS2000A_CHANNEL)(i + PS2000A_DIGITAL_PORT0), NULL, 0, 0, PS2000A_RATIO_MODE_NONE)) != PICO_OK)
		{
			printf("ClearDataBuffers:ps2000aSetDataBuffer(port 0x%X) ------ 0x%08lx \n", i + PS2000A_DIGITAL_PORT0, status);
		}
	}
	*/
	for (i = 0; i < unit->channelCount; i++)
	{
		if((status = ps2000aSetDataBuffer(unit->handle, (PS2000A_CHANNEL)(i + PS2000A_CHANNEL_A), NULL, 0, 0, PS2000A_RATIO_MODE_NONE)) != PICO_OK)
		{
			printf("ClearDataBuffers:ps2000aSetDataBuffers(channel %d) ------ 0x%08lx \n", i, status);
		}
	}

	return status;
}

/****************************************************************************
* Stream Data Handler
* - Used by the two stream data examples - untriggered and triggered
* Inputs:
* - unit - the unit to sample on
* - preTrigger - the number of samples in the pre-trigger phase
*					(0 if no trigger has been set)
***************************************************************************/
void StreamDataHandler(UNIT* unit, uint32_t preTrigger, MODE mode)
{
	int8_t* timeUnitsStr;

	int16_t  autostop;
	uint16_t portValue, portValueOR, portValueAND;
	uint32_t segmentIndex = 0;

	//int16_t* buffers[PS2000A_MAX_CHANNEL_BUFFERS]; //PS2000A_MAX_CHANNEL_BUFFERS is 8 in this case
	//int16_t* appBuffers[PS2000A_MAX_CHANNEL_BUFFERS]; //since we're only using one buffer, I think we can change this
	//not going to mess with it for now tho
	//or maybe I will
	int16_t* buffers[1]; //PS2000A_MAX_CHANNEL_BUFFERS is 8 in this case
	int16_t* appBuffers[1]; //since we're only using one buffer, I think we can change this

	//int16_t* digiBuffers[PS2000A_MAX_DIGITAL_PORTS]; //don't need the digital
	//int16_t* appDigiBuffers[PS2000A_MAX_DIGITAL_PORTS];

	int32_t index = 0;
	int32_t totalSamples;
	int32_t bit;
	int32_t i, j;

	int32_t sampleCount = 40000; /*make sure buffer large enough??? */
	uint32_t postTrigger;
	uint32_t downsampleRatio = 1;
	uint32_t sampleInterval;
	uint32_t triggeredAt = 0;
	int16_t qinit = -1;

	BUFFER_INFO bufferInfo;
	FILE* fp = NULL;

	PICO_STATUS status;
	PS2000A_TIME_UNITS timeUnits;
	PS2000A_RATIO_MODE ratioMode;


	
	
	if (mode == ANALOGUE)		// Analogue 
	{
		/*
		for (i = 0; i < unit->channelCount; i++)
		{
			if (unit->channelSettings[i].enabled)
			{
				buffers[i * 2] = (int16_t*)malloc(sampleCount * sizeof(int16_t));
				buffers[i * 2 + 1] = (int16_t*)malloc(sampleCount * sizeof(int16_t)); //second buffer that we don't need
				//status = ps2000aSetDataBuffers(unit->handle, (int32_t)i, buffers[i * 2], buffers[i * 2 + 1], sampleCount, segmentIndex, PS2000A_RATIO_MODE_AGGREGATE);
				status = ps2000aSetDataBuffers(unit->handle, (int32_t)i, buffers[i * 2], buffers[i * 2 + 1], sampleCount, segmentIndex, PS2000A_RATIO_MODE_NONE);
				//call above is for multiple buffers, we only want one
				

				appBuffers[i * 2] = (int16_t*)malloc(sampleCount * sizeof(int16_t)); //might still need one of these
				appBuffers[i * 2 + 1] = (int16_t*)malloc(sampleCount * sizeof(int16_t));

				printf(status ? "StreamDataHandler:ps2000aSetDataBuffers(channel %ld) ------ 0x%08lx \n" : "", i, status);
			}
		}
		*/

		buffers[0] = (int16_t*)malloc(sampleCount * sizeof(int16_t));
		status = ps2000aSetDataBuffer(unit->handle, PS2000A_CHANNEL_A, buffers[0], sampleCount, segmentIndex, PS2000A_RATIO_MODE_NONE);
		appBuffers[0] = (int16_t*)malloc(sampleCount * sizeof(int16_t));

		printf(status ? "StreamDataHandler:ps2000aSetDataBuffers(channel %ld) ------ 0x%08lx \n" : "", 0, status);

		downsampleRatio = 1;
		//timeUnits = PS2000A_US;
		timeUnits = PS2000A_NS;
		sampleInterval = 200; //seems like the best it can do is 104
		//ratioMode = PS2000A_RATIO_MODE_AGGREGATE;
		ratioMode = PS2000A_RATIO_MODE_NONE;
		//ratioMode = PS2000A_RATIO_MODE_AVERAGE;
		postTrigger = 1000000 / 250; //????
		autostop = TRUE;
	}

	bufferInfo.unit = unit;
	bufferInfo.mode = mode;
	bufferInfo.driverBuffers = buffers;
	bufferInfo.appBuffers = appBuffers;
	//bufferInfo.driverDigBuffers = digiBuffers;
	//bufferInfo.appDigBuffers = appDigiBuffers;

	/*
	if (mode == AGGREGATED)		// (MSO Only) AGGREGATED
	{
		for (i = 0; i < unit->digitalPorts; i++)
		{

			digiBuffers[i * 2] = (int16_t*)malloc(sampleCount * sizeof(int16_t));
			digiBuffers[i * 2 + 1] = (int16_t*)malloc(sampleCount * sizeof(int16_t));
			status = ps2000aSetDataBuffers(unit->handle, (PS2000A_CHANNEL)(i + PS2000A_DIGITAL_PORT0), digiBuffers[i * 2], digiBuffers[i * 2 + 1], sampleCount, 0, PS2000A_RATIO_MODE_AGGREGATE);

			appDigiBuffers[i * 2] = (int16_t*)malloc(sampleCount * sizeof(int16_t));
			appDigiBuffers[i * 2 + 1] = (int16_t*)malloc(sampleCount * sizeof(int16_t));

			printf(status ? "StreamDataHandler:ps2000aSetDataBuffer(channel %ld) ------ 0x%08lx \n" : "", i, status);
		}

		downsampleRatio = 10;
		timeUnits = PS2000A_MS;
		sampleInterval = 10;
		ratioMode = PS2000A_RATIO_MODE_AGGREGATE;
		postTrigger = 10;
		autostop = FALSE;
	}
	*/
	/*
	if (mode == DIGITAL)		// (MSO Only) Digital 
	{
		for (i = 0; i < unit->digitalPorts; i++)
		{
			digiBuffers[i] = (int16_t*)malloc(sampleCount * sizeof(int16_t));
			status = ps2000aSetDataBuffer(unit->handle, (PS2000A_CHANNEL)(i + PS2000A_DIGITAL_PORT0), digiBuffers[i], sampleCount, 0, PS2000A_RATIO_MODE_NONE);

			appDigiBuffers[i] = (int16_t*)malloc(sampleCount * sizeof(int16_t));

			printf(status ? "StreamDataHandler:ps2000aSetDataBuffer(channel %ld) ------ 0x%08lx \n" : "", i, status);
		}

		downsampleRatio = 1;
		timeUnits = PS2000A_MS;
		sampleInterval = 10;
		ratioMode = PS2000A_RATIO_MODE_NONE;
		postTrigger = 10;
		autostop = FALSE;
	}
	*/

	if (autostop)
	{
		printf("\nStreaming Data for %lu samples", postTrigger / downsampleRatio);

		if (preTrigger)	// we pass 0 for preTrigger if we're not setting up a trigger
		{
			printf(" after the trigger occurs\nNote: %lu Pre Trigger samples before Trigger arms\n\n", preTrigger / downsampleRatio);
		}
		else
		{
			printf("\n\n");
		}
	}
	else
	{
		printf("\nStreaming Data continually\n\n");
	}

	g_autoStopped = FALSE;

	std::cout << "ps2000aRunStreaming params: " << std::endl;
	std::cout << "handle: " << unit->handle << std::endl;
	std::cout << "sampleInterval: " << sampleInterval << std::endl;
	std::cout << "timeUnits: " << timeUnitsToString(timeUnits) << std::endl;
	std::cout << "preTrigger: " << preTrigger << std::endl;
	std::cout << "postTrigger - preTrigger: " << postTrigger - preTrigger << std::endl;
	std::cout << "autostop: " << autostop << std::endl;
	std::cout << "downsampleRatio: " << downsampleRatio << std::endl;
	std::cout << "ratioMode: " << ratioMode << std::endl;
	std::cout << "(uint32_t)sampleCount: " << (uint32_t)sampleCount << std::endl;

	status = ps2000aRunStreaming(unit->handle, &sampleInterval, timeUnits, preTrigger, postTrigger - preTrigger,
		autostop, downsampleRatio, ratioMode, (uint32_t)sampleCount);

	if (status == PICO_OK)
	{
		timeUnitsStr = timeUnitsToString(timeUnits);
		printf("Streaming data... (interval: %d %s) Press a key to stop\n", sampleInterval, timeUnitsStr);
	}
	else
	{
		printf("StreamDataHandler:ps2000aRunStreaming ------ 0x%08lx \n", status);
	}

	if (mode == ANALOGUE)
	{
		fopen_s(&fp, StreamFile, "w");

		if (fp != NULL)
		{
			fprintf(fp, "For each of the %d Channels, results shown are....\n", unit->channelCount);
			fprintf(fp, "Maximum Aggregated value ADC Count & mV, Minimum Aggregated value ADC Count & mV\n\n");

			for (i = 0; i < unit->channelCount; i++)
			{
				if (unit->channelSettings[i].enabled)
				{
					//Fix This
					fprintf(fp, "Max ADC,   Max mV,   Min ADC,   Min mV,");
				}
			}

			fprintf(fp, "\n");
		}
	}

	totalSamples = 0;
	qinit = _kbhitinit();
	// Capture data unless the 'Q' key is pressed or the g_autoStopped flag is set in the streaming callback
	//while (!_kbhit() && !g_autoStopped)
	while(!_kbhitpoll(qinit) && !g_autoStopped)
	{
		/* Poll until data is received. Until then, GetStreamingLatestValues wont call the callback */
		g_ready = FALSE;

		status = ps2000aGetStreamingLatestValues(unit->handle, CallBackStreaming, &bufferInfo);
		if (!(status == PICO_OK || status == PICO_BUSY)) //might as well check
		{
			printf("Error when calling ps2000aGetStreamingLatestValues.\n");
			printf("Error code : %d\n", (int32_t)status);
			//printf("Error Code: %X\n", (PICO_STATUS)status);
			//should write a function to parse the header file that defines the error codes
			//get that to output to console 
			//while (!_kbhit());
			//qinit = _kbhitinit();
			printf("Press the \'Q\' key to exit the program.\n");
			while (!_kbhitpoll(qinit));
			exit(99); // exit program
		}
		index++;

		if (g_ready && g_sampleCount > 0) /* can be ready and have no data, if autoStop has fired */
		{
			if (g_trig)
			{
				triggeredAt = totalSamples + g_trigAt;		// calculate where the trigger occurred in the total samples collected
			}

			totalSamples += g_sampleCount;
			printf("\nCollected %3li samples, index = %5lu, Total: %6d samples ", g_sampleCount, g_startIndex, totalSamples);

			if (g_trig)
			{
				printf("Trig. at index %lu", triggeredAt);	// show where trigger occurred
			}

			for (i = g_startIndex; i < (int32_t)(g_startIndex + g_sampleCount); i++)
			{
				if (mode == ANALOGUE)
				{
					if (fp != NULL)
					{
						for (j = 0; j < unit->channelCount; j++)
						{
							if (unit->channelSettings[j].enabled)
							{
								fprintf(fp,
									"%d, %d,",
									appBuffers[j * 2][i],
									adc_to_mv(appBuffers[j * 2][i], unit->channelSettings[PS2000A_CHANNEL_A + j].range, unit));
							}
							/*
							if (unit->channelSettings[j].enabled)
							{
								fprintf(fp,
									"%d, %d, %d, %d, ",
									appBuffers[j * 2][i],
									adc_to_mv(appBuffers[j * 2][i], unit->channelSettings[PS2000A_CHANNEL_A + j].range, unit),
									appBuffers[j * 2 + 1][i],
									adc_to_mv(appBuffers[j * 2 + 1][i], unit->channelSettings[PS2000A_CHANNEL_A + j].range, unit));
							}
							*/
						}
						fprintf(fp, "\n");
					}
					else
					{
						printf("Cannot open the file stream.txt for writing.\n");
					}

				}

				/*
				if (mode == DIGITAL)
				{
					portValue = 0x00ff & appDigiBuffers[1][i];	// Mask Port 1 values to get lower 8 bits
					portValue <<= 8;							// Shift by 8 bits to place in upper 8 bits of 16-bit word
					portValue |= 0x00ff & appDigiBuffers[0][i];	// Mask Port 0 values to get lower 8 bits

					printf("\nIndex=%04lu: Value = 0x%04X  =  ", i, portValue);

					for (bit = 0; bit < 16; bit++)
					{
						// Shift value (32768 - binary 1000 0000 0000 0000), AND with value to get 1 or 0 for channel
						// Order will be D15 to D8, then D7 to D0
						printf((0x8000 >> bit) & portValue ? "1 " : "0 ");
					}
				}
				*/
				/*
				if (mode == AGGREGATED)
				{
					portValueOR = 0x00ff & appDigiBuffers[2][i];
					portValueOR <<= 8;
					portValueOR |= 0x00ff & appDigiBuffers[0][i];

					portValueAND = 0x00ff & appDigiBuffers[3][i];
					portValueAND <<= 8;
					portValueAND |= 0x00ff & appDigiBuffers[1][i];

					printf("\nIndex=%04lu: Bitwise  OR of last %ld readings = 0x%04X ", i, downsampleRatio, portValueOR);
					printf("\nIndex=%04lu: Bitwise AND of last %ld readings = 0x%04X ", i, downsampleRatio, portValueAND);
				}
				*/
			}
		}
	}

	ps2000aStop(unit->handle);

	if (!g_autoStopped)
	{
		printf("\nData collection aborted.\n");
		_getch();
	}

	if (g_overflow)
	{
		printf("Overflow on voltage range.\n");
	}

	if (fp != NULL)
	{
		fclose(fp);
	}

	if (mode == ANALOGUE)		// Only if we allocated these buffers
	{
		for (i = 0; i < unit->channelCount; i++)
		{
			if (unit->channelSettings[i].enabled)
			{
				free(buffers[i * 2]);
				//free(buffers[i * 2 + 1]);

				free(appBuffers[i * 2]);
				//free(appBuffers[i * 2 + 1]);
			}
		}
	}
	/*
	if (mode == DIGITAL) 		// Only if we allocated these buffers
	{
		for (i = 0; i < unit->digitalPorts; i++)
		{
			free(digiBuffers[i]);
			free(appDigiBuffers[i]);
		}

	}
	*/
	/*
	if (mode == AGGREGATED) 		// Only if we allocated these buffers
	{
		for (i = 0; i < unit->digitalPorts * 2; i++)
		{
			free(digiBuffers[i]);
			free(appDigiBuffers[i]);
		}
	}
	*/
	ClearDataBuffers(unit);
}

/****************************************************************************
* SetTrigger
*
* Parameters
* - *unit               - pointer to the UNIT structure
* - *channelProperties  - pointer to the PS2000A_TRIGGER_CHANNEL_PROPERTIES structure
* - nChannelProperties  - the number of PS2000A_TRIGGER_CHANNEL_PROPERTIES elements in channelProperties
* - *triggerConditions  - pointer to the PS2000A_TRIGGER_CONDITIONS structure
* - nTriggerConditions  - the number of PS2000A_TRIGGER_CONDITIONS elements in triggerConditions
* - *directions         - pointer to the TRIGGER_DIRECTIONS structure
* - *pwq                - pointer to the pwq (Pulse Width Qualifier) structure
* - delay               - Delay time between trigger & first sample
* - auxOutputEnable     - Not used
* - autoTriggerMs       - timeout period if no trigger occurrs
* - *digitalDirections  - pointer to the PS2000A_DIGITAL_CHANNEL_DIRECTIONS structure
* - nDigitalDirections  - the number of PS2000A_DIGITAL_CHANNEL_DIRECTIONS elements in digitalDirections
*
* Returns			    - PICO_STATUS - to show success or if an error occurred
*
***************************************************************************/
PICO_STATUS SetTrigger(UNIT* unit,
	PS2000A_TRIGGER_CHANNEL_PROPERTIES* channelProperties,
	int16_t nChannelProperties,
	PS2000A_TRIGGER_CONDITIONS* triggerConditions,
	int16_t nTriggerConditions,
	TRIGGER_DIRECTIONS* directions,
	PWQ* pwq,
	uint32_t delay,
	int16_t auxOutputEnabled,
	int32_t autoTriggerMs,
	PS2000A_DIGITAL_CHANNEL_DIRECTIONS* digitalDirections,
	int16_t nDigitalDirections)
{
	PICO_STATUS status;

	if ((status = ps2000aSetTriggerChannelProperties(unit->handle,
		channelProperties,
		nChannelProperties,
		auxOutputEnabled,
		autoTriggerMs)) != PICO_OK)
	{
		printf("SetTrigger:ps2000aSetTriggerChannelProperties ------ Ox%8lx \n", status);
		return status;
	}

	if ((status = ps2000aSetTriggerChannelConditions(unit->handle, triggerConditions, nTriggerConditions)) != PICO_OK)
	{
		printf("SetTrigger:ps2000aSetTriggerChannelConditions ------ 0x%8lx \n", status);
		return status;
	}

	if ((status = ps2000aSetTriggerChannelDirections(unit->handle,
		directions->channelA,
		directions->channelB,
		directions->channelC,
		directions->channelD,
		directions->ext,
		directions->aux)) != PICO_OK)
	{
		printf("SetTrigger:ps2000aSetTriggerChannelDirections ------ 0x%08lx \n", status);
		return status;
	}

	if ((status = ps2000aSetTriggerDelay(unit->handle, delay)) != PICO_OK)
	{
		printf("SetTrigger:ps2000aSetTriggerDelay ------ 0x%08lx \n", status);
		return status;
	}

	if ((status = ps2000aSetPulseWidthQualifier(unit->handle,
		pwq->conditions,
		pwq->nConditions,
		pwq->direction,
		pwq->lower,
		pwq->upper,
		pwq->type)) != PICO_OK)
	{
		printf("SetTrigger:ps2000aSetPulseWidthQualifier ------ 0x%08lx \n", status);
		return status;
	}

	if (unit->digitalPorts)					// ps2000aSetTriggerDigitalPortProperties function only applies to MSO	
	{
		if ((status = ps2000aSetTriggerDigitalPortProperties(unit->handle,
			digitalDirections,
			nDigitalDirections)) != PICO_OK)
		{
			printf("SetTrigger:ps2000aSetTriggerDigitalPortProperties ------ 0x%08lx \n", status);
			return status;
		}
	}
	return status;
}

/****************************************************************************
* SetDefaults - restore default settings
* We're going to hijack this slightly to
* enforce the non-default setting of an
* offset
****************************************************************************/
void SetDefaults(UNIT* unit)
{
	PICO_STATUS status;
	int32_t i;
	float analogOffset;

	status = ps2000aSetEts(unit->handle, PS2000A_ETS_OFF, 0, 0, NULL); // Turn off ETS

	for (i = 0; i < unit->channelCount; i++) // reset channels to most recent settings
	{
		status = ps2000aSetChannel(unit->handle, (PS2000A_CHANNEL)(PS2000A_CHANNEL_A + i),
			unit->channelSettings[PS2000A_CHANNEL_A + i].enabled,
			(PS2000A_COUPLING)unit->channelSettings[PS2000A_CHANNEL_A + i].DCcoupled,
			(PS2000A_RANGE)unit->channelSettings[PS2000A_CHANNEL_A + i].range, 0);
	}
}

/****************************************************************************
* CollectStreamingTriggered
*  this function demonstrates how to collect a stream of data
*  from the unit (start collecting on trigger)
***************************************************************************/
void CollectStreamingTriggered(UNIT* unit)
{
	int16_t triggerVoltage = mv_to_adc(-400, unit->channelSettings[PS2000A_CHANNEL_A].range, unit); // ChannelInfo stores ADC counts
	struct tPwq pulseWidth;
	int32_t status;
	int16_t qinit = -1;
	uint32_t preTrigger = 100;

	struct tPS2000ATriggerChannelProperties sourceDetails = { triggerVoltage,
		256 * 10,
		triggerVoltage,
		256 * 10,
		PS2000A_CHANNEL_A,
		PS2000A_LEVEL };

	struct tPS2000ATriggerConditions conditions = { PS2000A_CONDITION_TRUE,				// Channel A
		PS2000A_CONDITION_DONT_CARE,		// Channel B
		PS2000A_CONDITION_DONT_CARE,		// Channel C
		PS2000A_CONDITION_DONT_CARE,		// Channel D
		PS2000A_CONDITION_DONT_CARE,		// External
		PS2000A_CONDITION_DONT_CARE,		// aux
		PS2000A_CONDITION_DONT_CARE,		// PWQ
		PS2000A_CONDITION_DONT_CARE };		// digital

	struct tTriggerDirections directions = { PS2000A_FALLING_LOWER,			// Channel A
		PS2000A_NONE,			// Channel B
		PS2000A_NONE,			// Channel C
		PS2000A_NONE,			// Channel D
		PS2000A_NONE,			// External
		PS2000A_NONE };			// Aux

	memset(&pulseWidth, 0, sizeof(struct tPwq));

	printf("Collect streaming triggered...\n");
	printf("Data is written to disk file (%s)\n", StreamFile);
	printf("Indicates when value falls past %d", scaleVoltages ?
		adc_to_mv(sourceDetails.thresholdUpper, unit->channelSettings[PS2000A_CHANNEL_A].range, unit)	// If scaleVoltages, print mV value
		: sourceDetails.thresholdUpper);																// else print ADC Count
	printf(scaleVoltages ? "mV\n" : "ADC Counts\n");
	printf("Press a key to start...\n");
	_getch();

	SetDefaults(unit);

	/*
	* want to tweak trigger properties somewhere
	* around here
	*/
	/* Trigger enabled
	* Triggers depends on values above, as they're passed into the SetTrigger function
	* Currently falling lower than -400mV
	*/
	/****************************************************************************
	* SetTrigger
	*
	* Parameters
	* - *unit               - pointer to the UNIT structure
	* - *channelProperties  - pointer to the PS2000A_TRIGGER_CHANNEL_PROPERTIES structure
	* - nChannelProperties  - the number of PS2000A_TRIGGER_CHANNEL_PROPERTIES elements in channelProperties
	* - *triggerConditions  - pointer to the PS2000A_TRIGGER_CONDITIONS structure
	* - nTriggerConditions  - the number of PS2000A_TRIGGER_CONDITIONS elements in triggerConditions
	* - *directions         - pointer to the TRIGGER_DIRECTIONS structure
	* - *pwq                - pointer to the pwq (Pulse Width Qualifier) structure
	* - delay               - Delay time between trigger & first sample
	* - auxOutputEnable     - Not used
	* - autoTriggerMs       - timeout period if no trigger occurrs
	* - *digitalDirections  - pointer to the PS2000A_DIGITAL_CHANNEL_DIRECTIONS structure
	* - nDigitalDirections  - the number of PS2000A_DIGITAL_CHANNEL_DIRECTIONS elements in digitalDirections
	*
	* Returns			    - PICO_STATUS - to show success or if an error occurred
*
***************************************************************************/

	if ((status = SetTrigger(unit, &sourceDetails, 1, &conditions, 1, &directions, &pulseWidth, 0, 0, 0, 0, 0)) != PICO_OK)
	{
		printf("Unable to set device's trigger.\n");
		printf("Error code : %d\n", (int32_t)status);
		//printf("Error Code: %X\n", (PICO_STATUS)status);
		//should write a function to parse the header file that defines the error codes
		//get that to output to console 
		//while (!_kbhit());
		qinit = _kbhitinit();
		printf("Press the \'Q\' key to exit the program.\n");
		while (!_kbhitpoll(qinit));
		exit(99); // exit program
	}
	else
	{
		printf("Trigger set.\n");
	}

	StreamDataHandler(unit, preTrigger, ANALOGUE);
}

/****************************************************************************
* Initialise unit' structure with Variant specific defaults
****************************************************************************/
void get_info(UNIT* unit)
{
	int8_t description[11][25] = { "Driver Version",
									"USB Version",
									"Hardware Version",
									"Variant Info",
									"Serial",
									"Cal Date",
									"Kernel",
									"Digital H/W",
									"Analogue H/W",
									"Firmware 1",
									"Firmware 2" };

	int16_t i, r = 0;
	int8_t line[80];
	PICO_STATUS status = PICO_OK;
	int16_t numChannels = DUAL_SCOPE;
	int8_t channelNum = 0;
	int8_t character = 'A';

	unit->signalGenerator = TRUE;
	unit->ETS = FALSE;
	unit->firstRange = PS2000A_20MV; // This is for new PicoScope 220X B, B MSO, 2405A and 2205A MSO models, older devices will have a first range of 50 mV
	unit->lastRange = PS2000A_20V;
	unit->channelCount = DUAL_SCOPE;
	unit->digitalPorts = 0;
	unit->awgBufferSize = PS2000A_MAX_SIG_GEN_BUFFER_SIZE;

	if (unit->handle)
	{
		for (i = 0; i < 11; i++)
		{
			status = ps2000aGetUnitInfo(unit->handle, (int8_t*)line, sizeof(line), &r, i);

			if (i == PICO_VARIANT_INFO)
			{
				// Check if device has four channels
				/* 
				* have to do a little casting here because the way
				* the author wrote this doesn't work for some reason
				*/

				channelNum = line[1];
				numChannels = atoi((const char*) &channelNum);

				if (numChannels == QUAD_SCOPE)
				{
					unit->channelCount = QUAD_SCOPE;
				}

				// Set first range for voltage if device is a 2206/7/8, 2206/7/8A or 2205 MSO
				if (numChannels == DUAL_SCOPE)
				{
					/* 
					* visual studio doesn't like strcmpi function, using _strcmpi instead
					*/
					if (strlen((const char*) line) == 4 || (strlen((const char*) line) == 5 && _strcmpi((const char*) &line[4], "A") == 0) || (_strcmpi((const char*) line, "2205MSO")) == 0)
					{
						unit->firstRange = PS2000A_50MV;
					}
				}

				// Check if device is an MSO 
				if (strstr((const char*) line, "MSO"))
				{
					unit->digitalPorts = 2;
				}

			}
			printf("%s: %s\n", description[i], line);
		}
	}
}


/****************************************************************************
* OpenDevice
* Parameters
* - unit        pointer to the UNIT structure, where the handle will be stored
*
* Returns
* - PICO_STATUS to indicate success, or if an error occurred
***************************************************************************/
PICO_STATUS OpenDevice(UNIT* unit)
{
	int16_t value = 0;
	int32_t i;
	PWQ pulseWidth;
	TRIGGER_DIRECTIONS directions;
	int16_t qinit = -1;

	PICO_STATUS status = ps2000aOpenUnit(&(unit->handle), NULL);

	printf("Handle: %d\n", unit->handle);

	if (status != PICO_OK)
	{
		printf("Unable to open device\n");
		printf("Error code : %d\n", (int32_t)status);
		//printf("Error Code: %X\n", (PICO_STATUS)status);
		//should write a function to parse the header file that defines the error codes
		//get that to output to console 
		//while (!_kbhit());
		qinit = _kbhitinit();
		printf("Press the \'Q\' key to exit the program.\n");
		while (!_kbhitpoll(qinit));
		exit(99); // exit program
	}

	printf("Device opened successfully, cycle %d\n\n", ++cycles);

	// setup devices
	get_info(unit);
	timebase = 0; 

	printf("Flushing the data buffers...");
	ClearDataBuffers(unit); //flush the data buffers from the start just to be sure
	printf("done.\n");

	if (status != PICO_OK)
	{
		printf("Unable to flush device's buffers\n");
		printf("Error code : %d\n", (int32_t)status);
		//printf("Error Code: %X\n", (PICO_STATUS)status);
		//should write a function to parse the header file that defines the error codes
		//get that to output to console 
		//while (!_kbhit());
		qinit = _kbhitinit();
		printf("Press the \'Q\' key to exit the program.\n");
		while (!_kbhitpoll(qinit));
		exit(99); // exit program
	}

	ps2000aMaximumValue(unit->handle, &value);
	unit->maxValue = value;

	for (i = 0; i < unit->channelCount; i++)
	{
		if (i == 0) //only enable Channel A
		{
			unit->channelSettings[i].enabled = TRUE;
			unit->channelSettings[i].DCcoupled = TRUE;
			unit->channelSettings[i].range = PS2000A_500MV;
		}
		else
		{
			unit->channelSettings[i].enabled = FALSE;
			unit->channelSettings[i].DCcoupled = FALSE;
			unit->channelSettings[i].range = PS2000A_1V;
		}
	}

	memset(&directions, 0, sizeof(TRIGGER_DIRECTIONS));
	memset(&pulseWidth, 0, sizeof(PWQ));

	SetDefaults(unit);

	/* Trigger disabled	*/
	SetTrigger(unit, NULL, 0, NULL, 0, &directions, &pulseWidth, 0, 0, 0, 0, 0);

	return status;
}

int main()
{
	PICO_STATUS status;
	UNIT unit;

	status = OpenDevice(&unit);
	CollectStreamingTriggered(&unit);

	return 0;
}

Post Reply