/*********************************************************************************************************************************************** * * Filename: PS2000Acon.c * * Copyright: Pico Technology Limited 2010 * * Author: RPM * * Description: * This is a console mode program that demonstrates how to use the * PicoScope 2000a series API. * * Examples: * Collect a block of samples immediately * Collect a block of samples when a trigger event occurs * Collect a stream of data immediately * Collect a stream of data when a trigger event occurs * Set Signal Generator, using standard or custom signals * * Digital Examples (MSO variants only): * Collect a block of digital samples immediately * Collect a block of digital samples when a trigger event occurs * Collect a block of analogue & digital samples when analogue AND digital trigger events occurs * Collect a block of analogue & digital samples when analogue OR digital trigger events occurs * Collect a stream of digital data immediately * Collect a stream of digital data and show aggregated values * * * * To build this application: * Set up a project for a 32-bit console mode application * Add this file to the project * Add PS2000A.lib to the project * Add ps2000aApi.h and picoStatus.h to the project * Build the project * ******************************************************************************************************************************************************/ #include /* Headers for Windows */ #ifdef _WIN32 #include "windows.h" #include #include "..\ps2000aApi.h" #else #include #include #include #include #include #include #include #include #ifndef PICO_STATUS #include #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) typedef enum enBOOL { FALSE, TRUE } BOOL; /* A function to detect a keyboard press on Linux */ int32_t _getch() { struct termios oldt, newt; int32_t ch; int32_t bytesWaiting; tcgetattr(STDIN_FILENO, &oldt); newt = oldt; newt.c_lflag &= ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, &newt); setbuf(stdin, NULL); do { ioctl(STDIN_FILENO, FIONREAD, &bytesWaiting); if (bytesWaiting) getchar(); } while (bytesWaiting); ch = getchar(); tcsetattr(STDIN_FILENO, TCSANOW, &oldt); return ch; } int32_t _kbhit() { struct termios oldt, newt; int32_t bytesWaiting; tcgetattr(STDIN_FILENO, &oldt); newt = oldt; newt.c_lflag &= ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, &newt); setbuf(stdin, NULL); ioctl(STDIN_FILENO, FIONREAD, &bytesWaiting); tcsetattr(STDIN_FILENO, TCSANOW, &oldt); return bytesWaiting; } int32_t fopen_s(FILE ** a, const char * b, const char * c) { FILE * fp = fopen(b, c); *a = fp; return (fp > 0) ? 0 : -1; } /* A function to get a single character on Linux */ #define max(a,b) ((a) > (b) ? a : b) #define min(a,b) ((a) < (b) ? a : b) #endif #define PREF4 __stdcall int32_t cycles = 0; #define BUFFER_SIZE 1024 #define QUAD_SCOPE 4 #define DUAL_SCOPE 2 typedef enum { ANALOGUE, DIGITAL, AGGREGATED, MIXED } MODE; typedef struct { int16_t DCcoupled; int16_t range; int16_t enabled; } CHANNEL_SETTINGS; typedef enum { MODEL_NONE = 0, MODEL_PS2205 = 0x2205, MODEL_PS2205MSO = 0xE205, MODEL_PS2206 = 0x2206, MODEL_PS2207 = 0x2207, MODEL_PS2208 = 0x2208, MODEL_PS2206A = 0xA206, MODEL_PS2207A = 0xA207, MODEL_PS2208A = 0xA208, } MODEL_TYPE; 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; MODEL_TYPE model; char modelString[8]; char serial[10]; int16_t complete; int16_t openStatus; int16_t openProgress; PS2000A_RANGE firstRange; PS2000A_RANGE lastRange; int16_t channelCount; int16_t maxValue; int16_t signalGenerator; int16_t ETS; int16_t AWGFileSize; CHANNEL_SETTINGS channelSettings [PS2000A_MAX_CHANNELS]; int16_t digitalPorts; }UNIT; // Global Variables uint32_t timebase = 8; 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; int64_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 StreamFile[20] = "stream.txt"; /**************************************************************************** * Callback * used by PS2000A data streaimng 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) { // used for streaming g_sampleCount = noOfSamples; g_startIndex = startIndex; g_autoStopped = autoStop; // flag to say done reading data g_ready = TRUE; // flags to show if & where a trigger has occurred g_trig = triggered; g_trigAt = triggerAt; } /**************************************************************************** * Callback * used by PS2000A data block collection calls, on receipt of data. * used to set global flags etc checked by user routines ****************************************************************************/ void PREF4 CallBackBlock(int16_t handle, PICO_STATUS status, void * pParameter) { if (status != PICO_CANCELLED) g_ready = TRUE; } /**************************************************************************** * CloseDevice ****************************************************************************/ void CloseDevice(UNIT *unit) { ps2000aCloseUnit(unit->handle); } /**************************************************************************** * SetDefaults - restore default settings ****************************************************************************/ void SetDefaults(UNIT * unit) { PICO_STATUS status; int32_t i; 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); } } /**************************************************************************** * SetDigitals - enable or disable Digital Channels ****************************************************************************/ PICO_STATUS SetDigitals(UNIT *unit, int16_t state) { PICO_STATUS status; int16_t logicLevel; float logicVoltage = 1.5; int16_t maxLogicVoltage = 5; int16_t timebase = 1; int16_t port; // Set logic threshold logicLevel = (int16_t) ((logicVoltage / maxLogicVoltage) * PS2000A_MAX_LOGIC_LEVEL); // Enable or Disable Digital ports for (port = PS2000A_DIGITAL_PORT0; port <= PS2000A_DIGITAL_PORT1; port++) { status = ps2000aSetDigitalPort(unit->handle, (PS2000A_DIGITAL_PORT) port, state, logicLevel); printf( status ? "SetDigitals:PS2000ASetDigitalPort(Port 0x%X) ------ 0x%08lx \n" : "", port, status); } return status; } /**************************************************************************** * DisableAnalogue - Disable Analogue Channels ****************************************************************************/ PICO_STATUS DisableAnalogue(UNIT *unit) { PICO_STATUS status; int16_t ch; // Turn off analogue channels for (ch = 0; ch < unit->channelCount; ch++) { if ((status = ps2000aSetChannel(unit->handle, (PS2000A_CHANNEL) ch, 0, PS2000A_DC, PS2000A_50MV, 0)) != PICO_OK) printf( "DisableAnalogue:ps2000aSetChannel(channel %d) ------ 0x%08lx \n", ch, status); } return status; } /**************************************************************************** * 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]; } /**************************************************************************** * 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->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); } return status; } /**************************************************************************** * BlockDataHandler * - Used by all block data routines * - acquires data (user sets trigger mode before calling), displays 10 items * and saves all to data.txt * Input : * - unit : the unit to use. * - text : the text to display before the display of data slice * - offset : the offset into the data buffer to start the display's slice. ****************************************************************************/ void BlockDataHandler(UNIT * unit, char * text, int32_t offset, MODE mode) { int32_t i, j; int32_t timeInterval; int32_t sampleCount = BUFFER_SIZE; FILE * fp = NULL; int32_t maxSamples; int16_t * buffers[PS2000A_MAX_CHANNEL_BUFFERS]; int16_t * digiBuffer[PS2000A_MAX_DIGITAL_PORTS]; int32_t timeIndisposed; uint16_t digiValue; PICO_STATUS status; if (mode == ANALOGUE || mode == MIXED) // Analogue or (MSO Only) MIXED { for (i = 0; i < unit->channelCount; i++) { buffers[i * 2] = (int16_t*) malloc(sampleCount * sizeof(int16_t)); buffers[i * 2 + 1] = (int16_t*) malloc(sampleCount * sizeof(int16_t)); status = ps2000aSetDataBuffers(unit->handle, (int16_t) i, buffers[i * 2], buffers[i * 2 + 1], sampleCount, 0, PS2000A_RATIO_MODE_NONE); printf( status ? "BlockDataHandler:ps2000aSetDataBuffers(channel %d) ------ 0x%08lx \n" : "", i, status); } } if (mode == DIGITAL || mode == MIXED) // (MSO Only) Digital or MIXED { for (i = 0; i < unit->digitalPorts; i++) { digiBuffer[i] = (int16_t*) malloc(sampleCount * sizeof(int16_t)); status = ps2000aSetDataBuffer(unit->handle, (PS2000A_CHANNEL) (i + PS2000A_DIGITAL_PORT0), digiBuffer[i], sampleCount, 0, PS2000A_RATIO_MODE_NONE); printf( status ? "BlockDataHandler:ps2000aSetDataBuffer(port 0x%X) ------ 0x%08lx \n" : "", i + PS2000A_DIGITAL_PORT0, status); } } /* find the maximum number of samples, the time interval (in timeUnits), * the most suitable time units, and the maximum oversample at the current timebase*/ while (ps2000aGetTimebase(unit->handle, timebase, sampleCount, &timeInterval, oversample, &maxSamples, 0)) { timebase++; } printf("\nTimebase: %lu SampleInterval: %ldnS oversample: %hd\n", timebase, timeInterval, oversample); /* Start it collecting, then wait for completion*/ g_ready = FALSE; status = ps2000aRunBlock(unit->handle, 0, sampleCount, timebase, oversample, &timeIndisposed, 0, CallBackBlock, NULL); printf(status ? "BlockDataHandler:ps2000aRunBlock ------ 0x%08lx \n" : "", status); printf("Waiting for trigger...Press a key to abort\n"); while (!g_ready && !_kbhit()) { Sleep(0); } if (g_ready) { status = ps2000aGetValues(unit->handle, 0, (uint32_t*) &sampleCount, 1, PS2000A_RATIO_MODE_NONE, 0, NULL); printf( status ? "BlockDataHandler:ps2000aGetValues ------ 0x%08lx \n" : "", status); /* Print out the first 10 readings, converting the readings to mV if required */ printf("%s\n", text); if (mode == ANALOGUE || mode == MIXED) // if we're doing analogue or MIXED { printf("Channels are in (%s)\n", (scaleVoltages) ? ("mV") : ("ADC Counts")); for (j = 0; j < unit->channelCount; j++) { if (unit->channelSettings[j].enabled) printf("Channel%c:\t", 'A' + j); } } if (mode == DIGITAL || mode == MIXED) // if we're doing digital or MIXED printf("Digital"); printf("\n"); for (i = offset; i < offset + 10; i++) { if (mode == ANALOGUE || mode == MIXED) // if we're doing analogue or MIXED { for (j = 0; j < unit->channelCount; j++) { if (unit->channelSettings[j].enabled) { printf(" %6d ", scaleVoltages ? adc_to_mv(buffers[j * 2][i], unit->channelSettings[PS2000A_CHANNEL_A + j].range, unit) // If scaleVoltages, print mV value : buffers[j * 2][i]); // else print ADC Count } } } if (mode == DIGITAL || mode == MIXED) // if we're doing digital or MIXED { digiValue = 0x00ff & digiBuffer[1][i]; digiValue <<= 8; digiValue |= digiBuffer[0][i]; printf("0x%04X", digiValue); } printf("\n"); } if (mode == ANALOGUE || mode == MIXED) // if we're doing analogue or MIXED { sampleCount = min(sampleCount, BUFFER_SIZE); fopen_s(&fp, BlockFile, "w"); if (fp != NULL) { fprintf(fp, "Block Data log\n\n"); fprintf( fp, "Results shown for each of the %d Channels are......\n", unit->channelCount); fprintf( fp, "Maximum Aggregated value ADC Count & mV, Minimum Aggregated value ADC Count & mV\n\n"); fprintf(fp, "Time "); for (i = 0; i < unit->channelCount; i++) fprintf(fp, " Ch Max ADC Max mV Min ADC Min mV "); fprintf(fp, "\n"); for (i = 0; i < sampleCount; i++) { fprintf(fp, "%5lld ", g_times[0] + (int64_t) (i * timeInterval)); for (j = 0; j < unit->channelCount; j++) { if (unit->channelSettings[j].enabled) { fprintf( fp, "Ch%C %5d = %+5dmV, %5d = %+5dmV ", (char) ('A' + j), buffers[j * 2][i], adc_to_mv( buffers[j * 2][i], unit->channelSettings[PS2000A_CHANNEL_A + j].range, unit), buffers[j * 2 + 1][i], adc_to_mv( buffers[j * 2 + 1][i], unit->channelSettings[PS2000A_CHANNEL_A + j].range, unit)); } } fprintf(fp, "\n"); } } else { printf("Cannot open the file block.txt for writing.\n" "Please ensure that you have permission to access.\n"); } } } else { printf("data collection aborted\n"); _getch(); } status = ps2000aStop(unit->handle); printf(status ? "BlockDataHandler:ps2000aStop ------ 0x%08lx \n" : "", status); if (fp != NULL) fclose(fp); if (mode == ANALOGUE || mode == MIXED) // Only if we allocated these buffers { for (i = 0; i < unit->channelCount * 2; i++) { free(buffers[i]); } } if (mode == DIGITAL || mode == MIXED) // Only if we allocated these buffers { for (i = 0; i < unit->digitalPorts; i++) { free(digiBuffer[i]); } } ClearDataBuffers(unit); } /**************************************************************************** * 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) { int64_t i, j; uint32_t sampleCount = BUFFER_SIZE * 10; /* *10 is to make sure buffer large enough */ FILE * fp = NULL; int16_t * buffers[PS2000A_MAX_CHANNEL_BUFFERS]; int16_t * digiBuffers[PS2000A_MAX_DIGITAL_PORTS]; PICO_STATUS status; uint32_t sampleInterval; int32_t index = 0; int32_t totalSamples; uint32_t postTrigger; int16_t autostop; uint32_t downsampleRatio; uint32_t triggeredAt = 0; int32_t bit; uint16_t portValue, portValueOR, portValueAND; PS2000A_TIME_UNITS timeUnits; PS2000A_RATIO_MODE ratioMode; if (mode == ANALOGUE) // Analogue { for (i = 0; i < unit->channelCount; i++) { buffers[i * 2] = (int16_t*) malloc(sampleCount * sizeof(int16_t)); buffers[i * 2 + 1] = (int16_t*) malloc(sampleCount * sizeof(int16_t)); status = ps2000aSetDataBuffers(unit->handle, (int16_t) i, buffers[i * 2], buffers[i * 2 + 1], sampleCount, 0, PS2000A_RATIO_MODE_AGGREGATE); printf( status ? "StreamDataHandler:ps2000aSetDataBuffers(channel %ld) ------ 0x%08lx \n" : "", i, status); } downsampleRatio = 1000; timeUnits = PS2000A_US; sampleInterval = 1; ratioMode = PS2000A_RATIO_MODE_AGGREGATE; postTrigger = 1000000; autostop = TRUE; } 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); 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); 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; status = ps2000aRunStreaming(unit->handle, &sampleInterval, timeUnits, preTrigger, postTrigger - preTrigger, autostop, downsampleRatio, ratioMode, sampleCount); printf("Streaming data...Press a key to stop\n"); 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++) fprintf(fp, " Max ADC Max mV Min ADC Min mV"); fprintf(fp, "\n"); } } totalSamples = 0; while (!_kbhit() && !g_autoStopped && !g_overflow) { /* Poll until data is received. Until then, GetStreamingLatestValues wont call the callback */ Sleep(100); g_ready = FALSE; status = ps2000aGetStreamingLatestValues(unit->handle, CallBackStreaming, NULL); 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 < (int64_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, "Ch%C %5d = %+5dmV, %5d = %+5dmV ", (char) ('A' + j), buffers[j * 2][i], adc_to_mv( buffers[j * 2][i], unit->channelSettings[PS2000A_CHANNEL_A + j].range, unit), buffers[j * 2 + 1][i], adc_to_mv( buffers[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 & digiBuffers[1][i]; portValue <<= 8; portValue |= 0x00ff & digiBuffers[0][i]; printf("\nIndex=%04lu: Value = 0x%04X = ", i, portValue); for (bit = 0; bit < 16; bit++) { printf((0x8000 >> bit) & portValue ? "1 " : "0 "); } } if (mode == AGGREGATED) { portValueOR = 0x00ff & digiBuffers[2][i]; portValueOR <<= 8; portValueOR |= 0x00ff & digiBuffers[0][i]; portValueAND = 0x00ff & digiBuffers[3][i]; portValueAND <<= 8; portValueAND |= 0x00ff & digiBuffers[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( "\nStreaming overflow. Not able to keep up with streaming data rate\n"); } if (fp != NULL) fclose(fp); if (mode == ANALOGUE) // Only if we allocated these buffers { for (i = 0; i < unit->channelCount * 2; i++) { free(buffers[i]); } } if (mode == DIGITAL) // Only if we allocated these buffers { for (i = 0; i < unit->digitalPorts; i++) { free(digiBuffers[i]); } } if (mode == AGGREGATED) // Only if we allocated these buffers { for (i = 0; i < unit->digitalPorts * 2; i++) { free(digiBuffers[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 occurs * - *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, int64_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; } /**************************************************************************** * CollectBlockImmediate * this function demonstrates how to collect a single block of data * from the unit (start collecting immediately) ****************************************************************************/ void CollectBlockImmediate(UNIT * unit) { PWQ pulseWidth; TRIGGER_DIRECTIONS directions; memset(&directions, 0, sizeof(TRIGGER_DIRECTIONS)); memset(&pulseWidth, 0, sizeof(PWQ)); printf("Collect block immediate\n"); printf("Data is written to disk file (%s)\n", BlockFile); printf("Press a key to start...\n"); _getch(); SetDefaults(unit); /* Trigger disabled */ SetTrigger(unit, NULL, 0, NULL, 0, &directions, &pulseWidth, 0, 0, 0, 0, 0); BlockDataHandler(unit, "First 10 readings\n", 0, ANALOGUE); } /**************************************************************************** * CollectBlockEts * this function demonstrates how to collect a block of * data using equivalent time sampling (ETS). ****************************************************************************/ void CollectBlockEts(UNIT * unit) { PICO_STATUS status; int64_t ets_sampletime; int16_t triggerVoltage = mv_to_adc(1000, unit->channelSettings[PS2000A_CHANNEL_A].range, unit); uint32_t delay = 0; struct tPwq pulseWidth; struct tTriggerDirections directions; PS2000A_TRIGGER_CHANNEL_PROPERTIES sourceDetails = { triggerVoltage, 256 * 10, triggerVoltage, 256 * 10, PS2000A_CHANNEL_A, PS2000A_LEVEL }; PS2000A_TRIGGER_CONDITIONS conditions = { PS2000A_CONDITION_TRUE, PS2000A_CONDITION_DONT_CARE, PS2000A_CONDITION_DONT_CARE, PS2000A_CONDITION_DONT_CARE, PS2000A_CONDITION_DONT_CARE, PS2000A_CONDITION_DONT_CARE, PS2000A_CONDITION_DONT_CARE, PS2000A_CONDITION_DONT_CARE }; memset(&pulseWidth, 0, sizeof(struct tPwq)); memset(&directions, 0, sizeof(struct tTriggerDirections)); directions.channelA = PS2000A_RISING; printf("Collect ETS block...\n"); printf("Collects when value rises 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); //Trigger enabled //Rising edge //Threshold = 1000mV status = SetTrigger(unit, &sourceDetails, 1, &conditions, 1, &directions, &pulseWidth, delay, 0, 0, 0, 0); if ((status = ps2000aSetEts(unit->handle, PS2000A_ETS_FAST, 20, 4, &ets_sampletime)) != PICO_OK) printf("CollectBlockEts:ps2000aSetEts ------ 0x%08lx \n", status); printf("ETS Sample Time is: %ld\n", ets_sampletime); BlockDataHandler(unit, "Ten readings after trigger\n", BUFFER_SIZE / 10 - 5, ANALOGUE); // 10% of data is pre-trigger } /**************************************************************************** * CollectBlockTriggered * this function demonstrates how to collect a single block of data from the * unit, when a trigger event occurs. ****************************************************************************/ void CollectBlockTriggered(UNIT * unit) { int16_t triggerVoltage = mv_to_adc(1000, unit->channelSettings[PS2000A_CHANNEL_A].range, unit); PS2000A_TRIGGER_CHANNEL_PROPERTIES sourceDetails = { triggerVoltage, 256 * 10, triggerVoltage, 256 * 10, PS2000A_CHANNEL_A, PS2000A_LEVEL }; PS2000A_TRIGGER_CONDITIONS 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 TRIGGER_DIRECTIONS directions = { PS2000A_RISING, // Channel A PS2000A_NONE, // Channel B PS2000A_NONE, // Channel C PS2000A_NONE, // Channel D PS2000A_NONE, // ext PS2000A_NONE }; // aux PWQ pulseWidth; memset(&pulseWidth, 0, sizeof(PWQ)); printf("Collect block triggered\n"); printf("Data is written to disk file (%s)\n", BlockFile); printf("Collects when value rises 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); /* Trigger enabled * Rising edge * Threshold = 1000mV */ SetTrigger(unit, &sourceDetails, 1, &conditions, 1, &directions, &pulseWidth, 0, 0, 0, 0, 0); BlockDataHandler(unit, "Ten readings after trigger\n", 0, ANALOGUE); } /**************************************************************************** * CollectRapidBlock * this function demonstrates how to collect a set of captures using * rapid block mode. ****************************************************************************/ void CollectRapidBlock(UNIT * unit) { uint16_t nCaptures; int64_t nMaxSamples; uint32_t nSamples = 1000; int64_t timeIndisposed; int16_t capture, channel; int16_t ***rapidBuffers; int16_t *overflow; PICO_STATUS status; int16_t i; uint32_t nCompletedCaptures; int16_t triggerVoltage = mv_to_adc(100, unit->channelSettings[PS2000A_CHANNEL_A].range, unit); 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 tPwq pulseWidth; struct tTriggerDirections directions = { PS2000A_RISING, // Channel A PS2000A_NONE, // Channel B PS2000A_NONE, // Channel C PS2000A_NONE, // Channel D PS2000A_NONE, // ext PS2000A_NONE }; // aux memset(&pulseWidth, 0, sizeof(struct tPwq)); printf("Collect rapid block triggered...\n"); printf("Collects when value rises 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 any key to abort\n"); SetDefaults(unit); // Trigger enabled SetTrigger(unit, &sourceDetails, 1, &conditions, 1, &directions, &pulseWidth, 0, 0, 0, 0, 0); //Set the number of captures nCaptures = 10; //Segment the memory status = ps2000aMemorySegments(unit->handle, nCaptures, &nMaxSamples); //Set the number of captures status = ps2000aSetNoOfCaptures(unit->handle, nCaptures); //Run timebase = 160; //1 MS/s status = ps2000aRunBlock(unit->handle, 0, nSamples, timebase, 1, &timeIndisposed, 0, CallBackBlock, NULL); //Wait until data ready g_ready = 0; while (!g_ready && !_kbhit()) { Sleep(0); } if (!g_ready) { _getch(); status = ps2000aStop(unit->handle); status = ps2000aGetNoOfCaptures(unit->handle, &nCompletedCaptures); printf("Rapid capture aborted. %lu complete blocks were captured\n", nCompletedCaptures); printf("\nPress any key...\n\n"); _getch(); if (nCompletedCaptures == 0) return; //Only display the blocks that were captured nCaptures = (uint16_t) nCompletedCaptures; } //Allocate memory rapidBuffers = calloc(unit->channelCount, sizeof(int16_t*)); overflow = calloc(unit->channelCount * nCaptures, sizeof(int16_t)); for (channel = 0; channel < unit->channelCount; channel++) { rapidBuffers[channel] = calloc(nCaptures, sizeof(int16_t*)); } for (channel = 0; channel < unit->channelCount; channel++) { if (unit->channelSettings[channel].enabled) { for (capture = 0; capture < nCaptures; capture++) { rapidBuffers[channel][capture] = calloc(nSamples, sizeof(int16_t)); } } } for (channel = 0; channel < unit->channelCount; channel++) { if (unit->channelSettings[channel].enabled) { for (capture = 0; capture < nCaptures; capture++) { status = ps2000aSetDataBuffer(unit->handle, channel, rapidBuffers[channel][capture], nSamples, capture, PS2000A_RATIO_MODE_NONE); } } } //Get data status = ps2000aGetValuesBulk(unit->handle, &nSamples, 0, nCaptures - 1, 1, PS2000A_RATIO_MODE_NONE, overflow); //Stop status = ps2000aStop(unit->handle); //print first 10 samples from each capture for (capture = 0; capture < nCaptures; capture++) { printf("\nCapture %d\n", capture + 1); for (channel = 0; channel < unit->channelCount; channel++) { printf("Channel %c\t", 'A' + channel); } printf("\n"); for (i = 0; i < 10; i++) { for (channel = 0; channel < unit->channelCount; channel++) { if (unit->channelSettings[channel].enabled) { printf("%d\t\t", rapidBuffers[channel][capture][i]); } } printf("\n"); } } //Free memory free(overflow); for (channel = 0; channel < unit->channelCount; channel++) { if (unit->channelSettings[channel].enabled) { for (capture = 0; capture < nCaptures; capture++) { free(rapidBuffers[channel][capture]); } } } for (channel = 0; channel < unit->channelCount; channel++) { free(rapidBuffers[channel]); } free(rapidBuffers); } /**************************************************************************** * Initialise unit' structure with Variant specific defaults ****************************************************************************/ void set_info(UNIT * unit) { int16_t r = 0; char line [8] = {0}; int32_t variant; PICO_STATUS status = PICO_OK; if (unit->handle) { // info = 3 - PICO_VARIANT_INFO ps2000aGetUnitInfo(unit->handle, line, sizeof (line), &r, 3); variant = atoi(line); memcpy(&(unit->modelString),line,sizeof(unit->modelString)==7?7:sizeof(unit->modelString)); //To identify variants..... if (strlen(line) == 5) // A variant unit { line[4] = toupper(line[4]); if (line[4] == 'A') // i.e 2207A -> 0xA207 variant += 0x9968; } else variant += 0x1968; // 2206 -> 0x2206 if (strlen(line) == 7) { line[4] = toupper(line[4]); line[5] = toupper(line[5]); line[6] = toupper(line[6]); if(strcmp(line+4, "MSO") == 0) variant += 0xC000; // 2205MSO -> 0xE205 } // info = 4 - PICO_BATCH_AND_SERIAL ps2000aGetUnitInfo(unit->handle, unit->serial, sizeof (unit->serial), &r, 4); } switch (variant) { case MODEL_PS2205MSO: unit->model = variant; unit->signalGenerator = TRUE; unit->ETS = FALSE; unit->firstRange = PS2000A_50MV; unit->lastRange = PS2000A_20V; unit->channelCount = DUAL_SCOPE; unit->digitalPorts = 2; break; case MODEL_PS2206: unit->model = variant; unit->signalGenerator = TRUE; unit->ETS = FALSE; unit->firstRange = PS2000A_50MV; unit->lastRange = PS2000A_20V; unit->channelCount = DUAL_SCOPE; unit->digitalPorts = 0; break; case MODEL_PS2207: unit->model = variant; unit->signalGenerator = TRUE; unit->ETS = FALSE; unit->firstRange = PS2000A_50MV; unit->lastRange = PS2000A_20V; unit->channelCount = DUAL_SCOPE; unit->digitalPorts = 0; break; case MODEL_PS2208: unit->model = variant; unit->signalGenerator = TRUE; unit->ETS = TRUE; unit->firstRange = PS2000A_50MV; unit->lastRange = PS2000A_20V; unit->channelCount = DUAL_SCOPE; unit->digitalPorts = 0; break; case MODEL_PS2206A: unit->model = variant; unit->signalGenerator = TRUE; unit->ETS = FALSE; unit->firstRange = PS2000A_50MV; unit->lastRange = PS2000A_20V; unit->channelCount = DUAL_SCOPE; unit->digitalPorts = 0; break; case MODEL_PS2207A: unit->model = variant; unit->signalGenerator = TRUE; unit->ETS = FALSE; unit->firstRange = PS2000A_50MV; unit->lastRange = PS2000A_20V; unit->channelCount = DUAL_SCOPE; unit->digitalPorts = 0; break; case MODEL_PS2208A: unit->model = variant; unit->signalGenerator = TRUE; unit->ETS = TRUE; unit->firstRange = PS2000A_50MV; unit->lastRange = PS2000A_20V; unit->channelCount = DUAL_SCOPE; unit->digitalPorts = 0; break; default: break; } } /**************************************************************************** * Select input voltage ranges for channels ****************************************************************************/ void SetVoltages(UNIT * unit) { int32_t i, ch; int32_t count = 0; /* See what ranges are available... */ for (i = unit->firstRange; i <= unit->lastRange; i++) { printf("%d -> %d mV\n", i, inputRanges[i]); } do { /* Ask the user to select a range */ printf("Specify voltage range (%d..%d)\n", unit->firstRange, unit->lastRange); printf("99 - switches channel off\n"); for (ch = 0; ch < unit->channelCount; ch++) { printf("\n"); do { printf("Channel %c: ", 'A' + ch); fflush(stdin); scanf_s("%hd", &unit->channelSettings[ch].range); } while (unit->channelSettings[ch].range != 99 && (unit->channelSettings[ch].range < unit->firstRange || unit->channelSettings[ch].range > unit->lastRange)); if (unit->channelSettings[ch].range != 99) { printf(" - %d mV\n", inputRanges[unit->channelSettings[ch].range]); unit->channelSettings[ch].enabled = TRUE; count++; } else { printf("Channel Switched off\n"); unit->channelSettings[ch].enabled = FALSE; unit->channelSettings[ch].range = PS2000A_MAX_RANGES - 1; } } printf(count == 0 ? "\n** At least 1 channel must be enabled **\n\n" : ""); } while (count == 0); // must have at least one channel enabled SetDefaults(unit); // Put these changes into effect } /**************************************************************************** * * Select timebase, set oversample to on and time units as nano seconds * ****************************************************************************/ void SetTimebase(UNIT *unit) { int64_t timeInterval; int64_t maxSamples; printf("Specify desired timebase: "); fflush(stdin); scanf_s("%lu", &timebase); while (ps2000aGetTimebase(unit->handle, timebase, BUFFER_SIZE, &timeInterval, 1, &maxSamples, 0)) { timebase++; // Increase timebase if the one specified can't be used. } printf("Timebase %lu used = %ld ns\n", timebase, timeInterval); oversample = TRUE; } /**************************************************************************** * Sets the signal generator * - allows user to set frequency and waveform * - allows for custom waveform (values -32768..32767) of up to 8192 samples int64_t ***************************************************************************/ void SetSignalGenerator(UNIT *unit) { PICO_STATUS status; int16_t waveform; int64_t frequency; char fileName[128]; FILE * fp = NULL; int16_t arbitraryWaveform[8192]; int16_t waveformSize = 0; uint32_t pkpk = 1000000; int64_t offset = 0; char ch; int16_t choice; memset(&arbitraryWaveform, 0, 8192); while (_kbhit()) // use up keypress _getch(); do { printf("\nSignal Generator\n================\n"); printf("0 - SINE 1 - SQUARE\n"); printf("2 - TRIANGLE 3 - DC VOLTAGE\n"); printf("4 - RAMP UP 5 - RAMP DOWN\n"); printf("6 - SINC 7 - GAUSSIAN\n"); printf("8 - HALF SINE A - AWG WAVEFORM\n"); printf("F - SigGen Off\n\n"); ch = _getch(); if (ch >= '0' && ch <= '9') choice = ch - '0'; else ch = toupper(ch); } while (ch != 'A' && ch != 'F' && (ch < '0' || ch > '8')); if (ch == 'F') // If we're going to turn off siggen { printf("Signal generator Off\n"); waveform = 8; // DC Voltage pkpk = 0; // 0V waveformSize = 0; } else if (ch == 'A') // Set the AWG { waveformSize = 0; printf("Select a waveform file to load: "); scanf_s("%s", fileName, 128); if (fopen_s(&fp, fileName, "r") == 0) { // Having opened file, read in data - one number per line (at most 8192 lines), with values in (-32768 to 32767) while (EOF != fscanf_s(fp, "%hi", (arbitraryWaveform + waveformSize)) && waveformSize++ < 8191) ; fclose(fp); printf("File successfully loaded\n"); } else { printf("Invalid filename\n"); return; } } else // Set one of the built in waveforms { switch (choice) { case 0: waveform = PS2000A_SINE; break; case 1: waveform = PS2000A_SQUARE; break; case 2: waveform = PS2000A_TRIANGLE; break; case 3: waveform = PS2000A_DC_VOLTAGE; do { printf("\nEnter offset in uV: (0 to 2500000)\n"); // Ask user to enter DC offset level; scanf_s("%llu", &offset); } while (offset < 0 || offset > 10000000); break; case 4: waveform = PS2000A_RAMP_UP; break; case 5: waveform = PS2000A_RAMP_DOWN; break; case 6: waveform = PS2000A_SINC; break; case 7: waveform = PS2000A_GAUSSIAN; break; case 8: waveform = PS2000A_HALF_SINE; break; default: waveform = PS2000A_SINE; break; } } if (waveform < 8 || ch == 'A') // Find out frequency if required { do { printf("\nEnter frequency in Hz: (1 to 1000000)\n"); // Ask user to enter signal frequency; scanf_s("%lu", &frequency); } while (frequency <= 0 || frequency > 1000000); } if (waveformSize > 0) { double delta = ((1.0 * frequency * waveformSize) / 8192.0) * 4294967296.0 * 5e-8; // delta >= 10 status = ps2000aSetSigGenArbitrary(unit->handle, 0, 1000000, (uint32_t) delta, (uint32_t) delta, 0, 0, arbitraryWaveform, waveformSize, 0, 0, PS2000A_SINGLE, 0, 0, PS2000A_SIGGEN_RISING, PS2000A_SIGGEN_NONE, 0); printf(status ? "\nps2000aSetSigGenArbitrary: Status Error 0x%x \n" : "", (uint32_t) status); // If status != 0, show the error } else { status = ps2000aSetSigGenBuiltIn(unit->handle, offset, pkpk, waveform, (float) frequency, (float) frequency, 0, 0, 0, 0, 0, 0, 0, 0, 0); printf(status ? "\nps2000aSetSigGenBuiltIn: Status Error 0x%x \n" : "", (uint32_t) status); // If status != 0, show the error } } /**************************************************************************** * CollectStreamingImmediate * this function demonstrates how to collect a stream of data * from the unit (start collecting immediately) ***************************************************************************/ void CollectStreamingImmediate(UNIT * unit) { struct tPwq pulseWidth; struct tTriggerDirections directions; memset(&pulseWidth, 0, sizeof(struct tPwq)); memset(&directions, 0, sizeof(struct tTriggerDirections)); SetDefaults(unit); printf("Collect streaming...\n"); printf("Data is written to disk file (%s)\n", StreamFile); printf("Press a key to start...\n"); _getch(); /* Trigger disabled */ SetTrigger(unit, NULL, 0, NULL, 0, &directions, &pulseWidth, 0, 0, 0, 0, 0); StreamDataHandler(unit, 0, ANALOGUE); } /**************************************************************************** * 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(1000, unit->channelSettings[PS2000A_CHANNEL_A].range, unit); // ChannelInfo stores ADC counts struct tPwq pulseWidth; 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, // Exteranl PS2000A_CONDITION_DONT_CARE, // aux PS2000A_CONDITION_DONT_CARE, // PWQ PS2000A_CONDITION_DONT_CARE }; // digital struct tTriggerDirections directions = { PS2000A_RISING, // 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 rises 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); /* Trigger enabled * Rising edge * Threshold = 1000mV */ SetTrigger(unit, &sourceDetails, 1, &conditions, 1, &directions, &pulseWidth, 0, 0, 0, 0, 0); StreamDataHandler(unit, 100000, ANALOGUE); } /**************************************************************************** * OpenDevice * Parameters * - unit pointer to the UNIT structure, where the handle will be stored * - serial pointer to the char array containing serial number * * Returns * - PICO_STATUS to indicate success, or if an error occurred ***************************************************************************/ PICO_STATUS OpenDevice(UNIT *unit, char *serial) { PICO_STATUS status; if (serial == NULL) status = ps2000aOpenUnit(&unit->handle, NULL); else status = ps2000aOpenUnit(&unit->handle, serial); unit->openStatus = status; unit->complete = 1; return status; } /**************************************************************************** * HandleDevice * 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 HandleDevice(UNIT * unit) { int16_t value = 0; int32_t i; struct tPwq pulseWidth; struct tTriggerDirections directions; printf("Handle: %d\n", unit->handle); if (unit->openStatus != PICO_OK) { printf("Unable to open device\n"); printf("Error code : 0x%08x\n", (uint32_t)unit->openStatus); while(!_kbhit()); exit(99); // exit program } printf("Device opened successfully, cycle %d\n\n", ++cycles); // setup device info - unless it's set already if (unit->model == MODEL_NONE) set_info(unit); timebase = 1; PICO_STATUS status = ps2000aMaximumValue(unit->handle, &value); unit->maxValue = value; for (i = 0; i < unit->channelCount; i++) { unit->channelSettings[i].enabled = TRUE; unit->channelSettings[i].DCcoupled = TRUE; unit->channelSettings[i].range = PS2000A_5V; } memset(&directions, 0, sizeof(struct tTriggerDirections)); memset(&pulseWidth, 0, sizeof(struct tPwq)); SetDefaults(unit); /* Trigger disabled */ SetTrigger(unit, NULL, 0, NULL, 0, &directions, &pulseWidth, 0, 0, 0, 0, 0); return status; } /**************************************************************************** * DisplaySettings * Displays information about the user configurable settings in this example * Parameters * - unit pointer to the UNIT structure * * Returns none ***************************************************************************/ void DisplaySettings(UNIT *unit) { int32_t ch; int32_t voltage; printf("\n\nReadings will be scaled in (%s)\n", (scaleVoltages) ? ("mV") : ("ADC counts")); for (ch = 0; ch < unit->channelCount; ch++) { if (!(unit->channelSettings[ch].enabled)) printf("Channel %c Voltage Range = Off\n", 'A' + ch); else { voltage = inputRanges[unit->channelSettings[ch].range]; printf("Channel %c Voltage Range = ", 'A' + ch); if (voltage < 1000) printf("%dmV\n", voltage); else printf("%dV\n", voltage / 1000); } } printf("\n"); } /**************************************************************************** * ANDAnalogueDigital * This function shows how to collect a block of data from the analogue * ports and the digital ports at the same time, triggering when the * digital conditions AND the analogue conditions are met * * Returns none ***************************************************************************/ void ANDAnalogueDigitalTriggered(UNIT * unit) { int16_t triggerVoltage = mv_to_adc(1000, unit->channelSettings[PS2000A_CHANNEL_A].range, unit); PS2000A_TRIGGER_CHANNEL_PROPERTIES sourceDetails = { triggerVoltage, // thresholdUpper 256 * 10, // thresholdUpper Hysteresis triggerVoltage, // thresholdLower 256 * 10, // thresholdLower Hysteresis PS2000A_CHANNEL_A, // channel PS2000A_LEVEL }; // mode PS2000A_TRIGGER_CONDITIONS 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_TRUE }; // digital TRIGGER_DIRECTIONS directions = { PS2000A_ABOVE, // Channel A PS2000A_NONE, // Channel B PS2000A_NONE, // Channel C PS2000A_NONE, // Channel D PS2000A_NONE, // external PS2000A_NONE }; // aux PS2000A_DIGITAL_CHANNEL_DIRECTIONS digDirections[2]; // Array size can be up to 16, an entry for each digital bit PWQ pulseWidth; memset(&pulseWidth, 0, sizeof(PWQ)); // Set the Digital trigger so it will trigger when bit 0 is Rising and bit 4 is HIGH // All non-declared bits are taken as PS2000A_DIGITAL_DONT_CARE // digDirections[0].channel = PS2000A_DIGITAL_CHANNEL_0; digDirections[0].direction = PS2000A_DIGITAL_DIRECTION_RISING; digDirections[1].channel = PS2000A_DIGITAL_CHANNEL_4; digDirections[1].direction = PS2000A_DIGITAL_DIRECTION_HIGH; printf("\nCombination Block Triggered\n"); printf("Collects when value is above %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("AND \n"); printf("Digital Channel 0 --- Rising\n"); printf("Digital Channel 4 --- High\n"); printf("Other Digital Channels - Don't Care\n"); printf("Press a key to start...\n"); _getch(); SetDefaults(unit); // Enable Analogue channels. /* Trigger enabled * Rising edge * Threshold = 100mV */ if (SetTrigger(unit, &sourceDetails, 1, &conditions, 1, &directions, &pulseWidth, 0, 0, 0, digDirections, 2) == PICO_OK) { BlockDataHandler(unit, "First 10 readings\n", 0, MIXED); } DisableAnalogue(unit); // Disable Analogue ports when finished; } /**************************************************************************** * ORAnalogueDigital * This function shows how to collect a block of data from the analogue * ports and the digital ports at the same time, triggering when either the * digital conditions OR the analogue conditions are met * * Returns none ***************************************************************************/ void ORAnalogueDigitalTriggered(UNIT * unit) { int16_t triggerVoltage = mv_to_adc(1000, unit->channelSettings[PS2000A_CHANNEL_A].range, unit); PS2000A_TRIGGER_CHANNEL_PROPERTIES sourceDetails = { triggerVoltage, // thresholdUpper 256 * 10, // thresholdUpper Hysteresis triggerVoltage, // thresholdLower 256 * 10, // thresholdLower Hysteresis PS2000A_CHANNEL_A, // channel PS2000A_LEVEL }; // mode PS2000A_TRIGGER_CONDITIONS conditions[2]; TRIGGER_DIRECTIONS directions = { PS2000A_RISING, // Channel A PS2000A_NONE, // Channel B PS2000A_NONE, // Channel C PS2000A_NONE, // Channel D PS2000A_NONE, // external PS2000A_NONE }; // aux PS2000A_DIGITAL_CHANNEL_DIRECTIONS digDirections[2]; // Array size can be up to 16, an entry for each digital bit PWQ pulseWidth; conditions[0].channelA = PS2000A_CONDITION_TRUE; // Channel A conditions[0].channelB = PS2000A_CONDITION_DONT_CARE; // Channel B conditions[0].channelC = PS2000A_CONDITION_DONT_CARE; // Channel C conditions[0].channelD = PS2000A_CONDITION_DONT_CARE; // Channel D conditions[0].external = PS2000A_CONDITION_DONT_CARE; // external conditions[0].aux = PS2000A_CONDITION_DONT_CARE; // aux conditions[0].pulseWidthQualifier = PS2000A_CONDITION_DONT_CARE; // pwq conditions[0].digital = PS2000A_CONDITION_DONT_CARE; // digital conditions[1].channelA = PS2000A_CONDITION_DONT_CARE; // Channel A conditions[1].channelB = PS2000A_CONDITION_DONT_CARE; // Channel B conditions[1].channelC = PS2000A_CONDITION_DONT_CARE; // Channel C conditions[1].channelD = PS2000A_CONDITION_DONT_CARE; // Channel D conditions[1].external = PS2000A_CONDITION_DONT_CARE; // external conditions[1].aux = PS2000A_CONDITION_DONT_CARE; // aux conditions[1].pulseWidthQualifier = PS2000A_CONDITION_DONT_CARE; // pwq conditions[1].digital = PS2000A_CONDITION_TRUE; // digital memset(&pulseWidth, 0, sizeof(PWQ)); // Set the Digital trigger so it will trigger when bit 0 is Rising and bit 4 is HIGH // All non-declared bits are taken as PS2000A_DIGITAL_DONT_CARE // digDirections[0].channel = PS2000A_DIGITAL_CHANNEL_0; digDirections[0].direction = PS2000A_DIGITAL_DIRECTION_RISING; digDirections[1].channel = PS2000A_DIGITAL_CHANNEL_4; digDirections[1].direction = PS2000A_DIGITAL_DIRECTION_HIGH; printf("\nCombination Block Triggered\n"); printf("Collects when value rises 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("OR \n"); printf("Digital Channel 0 --- Rising\n"); printf("Digital Channel 4 --- High\n"); printf("Other Digital Channels - Don't Care\n"); printf("Press a key to start...\n"); _getch(); SetDefaults(unit); // enable analogue ports /* Trigger enabled * Rising edge * Threshold = 1000mV */ if (SetTrigger(unit, &sourceDetails, 1, conditions, 2, &directions, &pulseWidth, 0, 0, 0, digDirections, 2) == PICO_OK) { BlockDataHandler(unit, "First 10 readings\n", 0, MIXED); } DisableAnalogue(unit); // Disable Analogue ports when finished; } /**************************************************************************** * DigitalBlockTriggered * This function shows how to collect a block of data from the digital ports * with triggering enabled * * Returns none ***************************************************************************/ void DigitalBlockTriggered(UNIT * unit) { PWQ pulseWidth; TRIGGER_DIRECTIONS directions; PS2000A_DIGITAL_CHANNEL_DIRECTIONS digDirections[2]; // Array size can be up to 16, an entry for each digital bit PS2000A_TRIGGER_CONDITIONS conditions = { PS2000A_CONDITION_DONT_CARE, // 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_TRUE }; // digital printf("\nDigital Block Triggered\n"); memset(&directions, 0, sizeof(TRIGGER_DIRECTIONS)); memset(&pulseWidth, 0, sizeof(PWQ)); printf("Collect block of data when the trigger occurs...\n"); printf("Digital Channel 0 --- Rising\n"); printf("Digital Channel 4 --- High\n"); printf("Other Digital Channels - Don't Care\n"); digDirections[0].channel = PS2000A_DIGITAL_CHANNEL_0; digDirections[0].direction = PS2000A_DIGITAL_DIRECTION_RISING; digDirections[1].channel = PS2000A_DIGITAL_CHANNEL_4; digDirections[1].direction = PS2000A_DIGITAL_DIRECTION_HIGH; if (SetTrigger(unit, NULL, 0, &conditions, 1, &directions, &pulseWidth, 0, 0, 0, digDirections, 2) == PICO_OK) { printf("Press a key to start...\n"); _getch(); BlockDataHandler(unit, "First 10 readings\n", 0, DIGITAL); } } /**************************************************************************** * DigitalBlockImmediate * This function shows how to collect a block of data from the digital ports * with triggering disabled * * Returns none ***************************************************************************/ void DigitalBlockImmediate(UNIT *unit) { PWQ pulseWidth; TRIGGER_DIRECTIONS directions; PS2000A_DIGITAL_CHANNEL_DIRECTIONS digDirections; printf("\nDigital Block Immediate\n"); memset(&directions, 0, sizeof(TRIGGER_DIRECTIONS)); memset(&pulseWidth, 0, sizeof(PWQ)); memset(&digDirections, 0, sizeof(PS2000A_DIGITAL_CHANNEL_DIRECTIONS)); SetTrigger(unit, NULL, 0, NULL, 0, &directions, &pulseWidth, 0, 0, 0, &digDirections, 0); printf("Press a key to start...\n"); _getch(); BlockDataHandler(unit, "First 10 readings\n", 0, DIGITAL); } /**************************************************************************** * DigitalStreamingAggregated * this function demonstrates how to collect a stream of Aggregated data * from the unit's Digital inputs (start collecting immediately) ***************************************************************************/ void DigitalStreamingAggregated(UNIT * unit) { struct tPwq pulseWidth; struct tTriggerDirections directions; memset(&pulseWidth, 0, sizeof(struct tPwq)); memset(&directions, 0, sizeof(struct tTriggerDirections)); printf("Digital streaming with Aggregation...\n"); printf("Press a key to start...\n"); _getch(); /* Trigger disabled */ SetTrigger(unit, NULL, 0, NULL, 0, &directions, &pulseWidth, 0, 0, 0, 0, 0); StreamDataHandler(unit, 0, AGGREGATED); } /**************************************************************************** * DigitalStreamingImmediate * this function demonstrates how to collect a stream of data * from the unit's Digital inputs (start collecting immediately) ***************************************************************************/ void DigitalStreamingImmediate(UNIT * unit) { struct tPwq pulseWidth; struct tTriggerDirections directions; memset(&pulseWidth, 0, sizeof(struct tPwq)); memset(&directions, 0, sizeof(struct tTriggerDirections)); printf("Digital streaming...\n"); printf("Press a key to start...\n"); _getch(); /* Trigger disabled */ SetTrigger(unit, NULL, 0, NULL, 0, &directions, &pulseWidth, 0, 0, 0, 0, 0); StreamDataHandler(unit, 0, DIGITAL); } /**************************************************************************** * DigitalMenu * Displays digital examples available * Parameters * - unit pointer to the UNIT structure * * Returns none ***************************************************************************/ void DigitalMenu(UNIT *unit) { char ch; int16_t enabled = TRUE; int16_t disabled = !enabled; DisableAnalogue(unit); // Disable Analogue ports; SetDigitals(unit, enabled); // Enable Digital ports ch = ' '; while (ch != 'X') { printf("\n"); printf("\nDigital Port Menu\n\n"); printf("B - Digital Block Immediate\n"); printf("T - Digital Block Triggered\n"); printf("A - Analogue 'AND' Digital Triggered Block\n"); printf("O - Analogue 'OR' Digital Triggered Block\n"); printf("S - Digital Streaming Mode\n"); printf("V - Digital Streaming Aggregated\n"); printf("X - Return to previous menu\n\n"); printf("Operation:"); ch = toupper(_getch()); printf("\n\n"); switch (ch) { case 'B': DigitalBlockImmediate(unit); break; case 'T': DigitalBlockTriggered(unit); break; case 'A': ANDAnalogueDigitalTriggered(unit); break; case 'O': ORAnalogueDigitalTriggered(unit); break; case 'S': DigitalStreamingImmediate(unit); break; case 'V': DigitalStreamingAggregated(unit); break; } } SetDigitals(unit, disabled); // Disable Digital ports when finished } /**************************************************************************** * MainMenu * Controls default functions of the seelected unit * Parameters * - unit pointer to the UNIT structure * * Returns none ***************************************************************************/ void MainMenu(UNIT *unit) { char ch = '.'; while (ch != 'X') { DisplaySettings(unit); printf("\n"); printf( "B - Immediate block V - Set voltages\n"); printf( "T - Triggered block I - Set timebase\n"); printf( "E - Collect a block of data using ETS A - ADC counts/mV\n"); printf( "R - Collect set of rapid captures G - Signal generator\n"); printf("S - Immediate streaming\n"); printf("W - Triggered streaming\n"); printf(unit->digitalPorts ? "D - Digital Ports menu\n" : ""); printf(" X - Exit\n\n"); printf("Operation:"); ch = toupper(_getch()); printf("\n\n"); switch (ch) { case 'B': CollectBlockImmediate(unit); break; case 'T': CollectBlockTriggered(unit); break; case 'R': CollectRapidBlock(unit); break; case 'S': CollectStreamingImmediate(unit); break; case 'W': CollectStreamingTriggered(unit); break; case 'E': if(unit->ETS == FALSE) { printf("This model does not support ETS\n\n"); break; } CollectBlockEts(unit); break; case 'G': if(unit->signalGenerator == FALSE) { printf("This model does not have a signal generator\n\n"); break; } SetSignalGenerator(unit); break; case 'V': SetVoltages(unit); break; case 'I': SetTimebase(unit); break; case 'A': scaleVoltages = !scaleVoltages; break; case 'D': if (unit->digitalPorts) DigitalMenu(unit); break; case 'X': break; default: printf("Invalid operation\n"); break; } } } /**************************************************************************** * main * ***************************************************************************/ int main(void) { #define MAX_PICO_DEVICES 64 #define TIMED_LOOP_STEP 500 char ch; uint16_t devCount = 0, listIter = 0, openIter = 0; //device indexer - 64 chars - 64 is maximum number of picoscope devices handled by driver char devChars[] = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#"; PICO_STATUS status = PICO_OK; UNIT allUnits[MAX_PICO_DEVICES]; printf("PS2000A driver example program\n"); printf("\nEnumerating Units...\n"); do { memset(&(allUnits[devCount]),0,sizeof (UNIT)); status = OpenDevice(&(allUnits[devCount]),NULL); if(status == PICO_OK || status == PICO_POWER_SUPPLY_NOT_CONNECTED || status == PICO_USB3_0_DEVICE_NON_USB3_0_PORT) { allUnits[devCount++].openStatus = status; } } while(status != PICO_NOT_FOUND); if (devCount == 0) { printf("Picoscope devices not found\n"); return 1; } // if there is only one device, open and handle it here if (devCount == 1) { printf("Found one device, opening...\n\n"); status = allUnits[0].openStatus; if (status == PICO_OK || status == PICO_POWER_SUPPLY_NOT_CONNECTED || status == PICO_USB3_0_DEVICE_NON_USB3_0_PORT) status = HandleDevice(&allUnits[0]); if (status != PICO_OK) { printf("Picoscope devices open failed, error code 0x%x\n",(uint32_t)status); return 1; } printf("Model\t: %7s\nS/N\t: %s\n", allUnits[0].modelString, allUnits[0].serial); MainMenu(&allUnits[0]); CloseDevice(&allUnits[0]); printf("Exit...\n"); return 0; } else { // more than one unit printf("Found %d devices, initializing...\n\n", devCount); for (listIter = 0; listIter < devCount; listIter++) { if ((allUnits[listIter].openStatus == PICO_OK || allUnits[listIter].openStatus == PICO_POWER_SUPPLY_NOT_CONNECTED || allUnits[listIter].openStatus == PICO_USB3_0_DEVICE_NON_USB3_0_PORT)) { set_info(&allUnits[listIter]); openIter++; } } } // None if (openIter == 0) { printf("Picoscope devices init failed\n"); return 1; } // Just one - handle it here if (openIter == 1) { for (listIter = 0; listIter < devCount; listIter++) { if (!(allUnits[listIter].openStatus == PICO_OK || allUnits[listIter].openStatus == PICO_POWER_SUPPLY_NOT_CONNECTED || allUnits[listIter].openStatus == PICO_USB3_0_DEVICE_NON_USB3_0_PORT)) break; } printf("One device openned successfuly\n"); printf("Model\t: %s\nS/N\t: %s\n", allUnits[listIter].modelString, allUnits[listIter].serial); status = HandleDevice(&allUnits[listIter]); if (status != PICO_OK) { printf("Picoscope device open failed, error code 0x%x\n", (uint32_t)status); return 1; } MainMenu(&allUnits[listIter]); CloseDevice(&allUnits[listIter]); printf("Exit...\n"); return 0; } printf("Found %d devices, pick one to open from the list:\n", devCount); for (listIter = 0; listIter < devCount; listIter++) { printf("%c) Picoscope %7s S/N: %s\n", devChars[listIter], allUnits[listIter].modelString, allUnits[listIter].serial); } printf("ESC) Cancel\n"); ch = '.'; //if escape while (ch != 27) { ch = _getch(); //if escape if (ch == 27) continue; for (listIter = 0; listIter < devCount; listIter++) { if (ch == devChars[listIter]) { printf("Option %c) selected, opening Picoscope %7s S/N: %s\n", devChars[listIter], allUnits[listIter].modelString, allUnits[listIter].serial); if ((allUnits[listIter].openStatus == PICO_OK || allUnits[listIter].openStatus == PICO_POWER_SUPPLY_NOT_CONNECTED || allUnits[listIter].openStatus == PICO_USB3_0_DEVICE_NON_USB3_0_PORT)) status = HandleDevice(&allUnits[listIter]); if (status != PICO_OK) { printf("Picoscope devices open failed, error code 0x%x\n", (uint32_t)status); return 1; } MainMenu(&allUnits[listIter]); printf("Found %d devices, pick one to open from the list:\n",devCount); for (listIter = 0; listIter < devCount; listIter++) { printf("%c) Picoscope %7s S/N: %s\n", devChars[listIter], allUnits[listIter].modelString, allUnits[listIter].serial); } printf("ESC) Cancel\n"); } } } for (listIter = 0; listIter < devCount; listIter++) { CloseDevice(&allUnits[listIter]); } printf("Exit...\n"); return 0; }