PicoScope 7 Software
Available on Windows, Mac and Linux
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;
}