/**************************************************************************
*
* Filename:    ps2000aWrap.c
*
* Copyright:   Pico Technology Limited 2011 - 2014
*
* Author:      HSM et al.
*
* Description:
*   The source code in this release is for use with Pico products when 
*	interfaced with Microsoft Excel VBA, National Instruments LabVIEW and 
*	MathWorks MATLAB or any third-party programming language or application 
*	that is unable to support C-style callback functions or structures.
*
*	You may modify, copy and distribute the source code for the purpose of 
*	developing programs to collect data using Pico products to add new 
*	functionality. If you modify the standard functions provided, we cannot 
*	guarantee that they will work with the above-listed programming 
*	languages or third-party products.
*
*   Please refer to the PicoScope 2000 Series (A API) Programmer's Guide
*   for descriptions of the underlying functions where stated.
*
* History:
*
*	11Mar14 - Data types updated, data copied in streaming callback.
*	18Mar14 - Updated digital data copying in streaming callback.
*	19Mar14 - Use constants for analogue/digital channels from wrap header.
*	20Mar14 - Updated functions for setting channels/ports and buffers
*				to return PICO_STATUS values.
***************************************************************************/
#include <windows.h>
#include <stdio.h>
#include "ps2000aWrap.h"

int16_t		_ready;
int16_t		_autoStop;
int32_t		_numSamples;
uint32_t	_triggeredAt = 0;
int16_t		_triggered = FALSE;
uint32_t	_startIndex;		// Start index in driver buffer
int16_t		_overflow = 0;

// Parameters relating to channel and digital ports

int16_t _channelCount = 2;										// Should be set to 2 from the main application
int16_t _enabledChannels[MAX_ANALOGUE_CHANNELS] = {0, 0};		// Keep a record of the channels that are enabled

int16_t _digitalPortCount = 0;									// Should be set to 2 from the main application for the 2205 MSO
int16_t _enabledDigitalPorts[MAX_DIGITAL_PORTS] = {0, 0};		// Keep a record of the channels that are enabled

typedef struct tWrapBufferInfo
{
	// Analogue channels
	int16_t *driverBuffers[MAX_ANALOGUE_BUFFERS];		// The buffers registered with the driver
	int16_t *appBuffers[MAX_ANALOGUE_BUFFERS];			// Application buffers to copy the driver data into
	int32_t bufferLengths[MAX_ANALOGUE_CHANNELS];		// Buffer lengths

	// Digital ports
	int16_t *driverDigiBuffers[MAX_DIGITAL_BUFFERS];	// The buffers registered with the driver for the digital ports
	int16_t *appDigiBuffers[MAX_DIGITAL_BUFFERS];		// Application buffers to copy the driver digital data into
	int32_t digiBufferLengths[MAX_DIGITAL_PORTS];		// Buffer lengths for digital ports - only 2 ports.

} WRAP_BUFFER_INFO;

WRAP_BUFFER_INFO _wrapBufferInfo;

/////////////////////////////////
//
//	Function declarations
//
/////////////////////////////////

/****************************************************************************
* Streaming Callback
*
* See ps2000aStreamingReady (callback)
*
****************************************************************************/
void __stdcall StreamingCallback(
    int16_t handle,
	int32_t noOfSamples,
	uint32_t startIndex,
	int16_t overflow,
	uint32_t triggerAt,
	int16_t triggered,
	int16_t autoStop,
	void * pParameter)
{
	int16_t channel = 0;
	int16_t digitalPort = 0;
	WRAP_BUFFER_INFO * _wrapBufferInfo = NULL;
	
	if (pParameter != NULL)
	{
		_wrapBufferInfo = (WRAP_BUFFER_INFO *) pParameter;
	}

	_numSamples = noOfSamples;
	_autoStop = autoStop;
	_startIndex = startIndex;

	_triggered = triggered;
	_triggeredAt = triggerAt;
  
	_overflow = overflow;

	// Verify if wrapper buffer info set and data received
	if (_wrapBufferInfo != NULL && noOfSamples)
	{
		for (channel = (int16_t) PS2000A_CHANNEL_A; channel < _channelCount; channel++)
		{
			// Analogue channels
			if (_enabledChannels[channel])
			{

				// Copy data...
				if (_wrapBufferInfo->appBuffers && _wrapBufferInfo->driverBuffers)
				{
					// Max buffers
					if (_wrapBufferInfo->appBuffers[channel * 2]  && _wrapBufferInfo->driverBuffers[channel * 2])
					{
						memcpy_s (&_wrapBufferInfo->appBuffers[channel * 2][startIndex], noOfSamples * sizeof(int16_t),
							&_wrapBufferInfo->driverBuffers[channel * 2][startIndex], noOfSamples * sizeof(int16_t));
					}

					// Min buffers
					if (_wrapBufferInfo->appBuffers[channel * 2 + 1] && _wrapBufferInfo->driverBuffers[channel * 2 + 1])
					{
						memcpy_s (&_wrapBufferInfo->appBuffers[channel * 2 + 1][startIndex],  noOfSamples * sizeof(int16_t),
							&_wrapBufferInfo->driverBuffers[channel * 2 + 1][startIndex], noOfSamples * sizeof(int16_t));
					}
				}
			}
		}

		// Digital channels
		if(_digitalPortCount > 0)
		{
			// Use index 0 to indicate Digital Port 0
			for(digitalPort = (int16_t) PS2000A_WRAP_DIGITAL_PORT0; digitalPort < _digitalPortCount; digitalPort++)
			{
				if(_enabledDigitalPorts[digitalPort])
				{
					// Copy data...
					if(_wrapBufferInfo->appDigiBuffers && _wrapBufferInfo->driverDigiBuffers)
					{
						// Max digital buffers
						if (_wrapBufferInfo->appDigiBuffers[channel * 2]  && _wrapBufferInfo->driverDigiBuffers[channel * 2])
						{
							
							memcpy_s (&_wrapBufferInfo->appDigiBuffers[digitalPort * 2][startIndex], noOfSamples * sizeof(int16_t),
								&_wrapBufferInfo->driverDigiBuffers[digitalPort * 2][startIndex], noOfSamples * sizeof(int16_t));
						}

						// Min digital buffers
						if (_wrapBufferInfo->appDigiBuffers[channel * 2 + 1]  && _wrapBufferInfo->driverDigiBuffers[channel * 2 + 1])
						{
							// Min digital buffers
							memcpy_s (&_wrapBufferInfo->appDigiBuffers[digitalPort * 2 + 1][startIndex],  noOfSamples * sizeof(int16_t),
								&_wrapBufferInfo->driverDigiBuffers[digitalPort * 2 + 1][startIndex], noOfSamples * sizeof(int16_t));
						}
					}
				}
			}
		}

	}

	_ready = 1;
}

/****************************************************************************
* BlockCallback
*
* See ps2000aBlockReady (callback)
*
****************************************************************************/
void __stdcall BlockCallback(int16_t handle, PICO_STATUS status, void * pParameter)
{
	_ready = 1;
}

/****************************************************************************
* RunBlock
*
* This function starts collecting data in block mode without the requirement 
* for specifying callback functions. Use the IsReady function in conjunction 
* to poll the driver once this function has been called.
*
* Input Arguments:
*
* handle - the handle of the required device.
* preTriggerSamples  see noOfPreTriggerSamples in ps2000aRunBlock.
* postTriggerSamples  see noOfPreTriggerSamples in ps2000aRunBlock.
* timebase  see ps2000aRunBlock.
* segmentIndex  see ps2000aRunBlock.
*
* Returns:
*
* See ps2000aRunBlock return values.
*
****************************************************************************/
extern PICO_STATUS __declspec(dllexport) __stdcall RunBlock(int16_t handle, int32_t preTriggerSamples, int32_t postTriggerSamples, 
            uint32_t timebase, uint16_t segmentIndex)
{
	int16_t oversample = 0;
	_ready = 0;
	_numSamples = preTriggerSamples + postTriggerSamples;

	return ps2000aRunBlock(handle, preTriggerSamples, postTriggerSamples, timebase, oversample, 
    NULL, segmentIndex, BlockCallback, NULL);
}

/****************************************************************************
* GetStreamingLatestValues
*
* Facilitates communication with the driver to return the next block of 
* values to your application when capturing data in streaming mode. Use with 
* programming languages that do not support callback functions.
*
* Input Arguments:
*
* handle - the handle of the required device.
*
* Returns:
*
* See ps2000aGetStreamingLatestValues return values.
*
****************************************************************************/
extern PICO_STATUS __declspec(dllexport) __stdcall GetStreamingLatestValues(int16_t handle)
{
	_ready = 0;
	_numSamples = 0;
	_autoStop = 0;

	return ps2000aGetStreamingLatestValues(handle, StreamingCallback, &_wrapBufferInfo);
}

/****************************************************************************
* Available Data
*
* Returns the number of samples returned from the driver and shows the start 
* index of the data in the application buffer when collecting data in 
* streaming mode.
*
* Input Arguments:
*
* handle - the handle of the required device.
* startIndex - on exit, an index to the first valid sample in the buffer 
*				(When data is available).
*
* Returns:
*
* 0 - Data is not yet available.
* Non-zero - the number of samples returned from the driver.
*
****************************************************************************/
extern int32_t __declspec(dllexport) __stdcall AvailableData(int16_t handle, uint32_t *startIndex)
{
	if( _ready ) 
	{
		*startIndex = _startIndex;
		return _numSamples;
	}
	
	return (uint32_t) 0;
}

/****************************************************************************
* AutoStopped
*
* Indicates if the device has stopped on collection of the number of samples 
* specified in the call to the ps2000aRunStreaming function (if the 
* ps2000aRunStreaming functions autostop flag is set).
*
* Input Arguments:
*
* handle - the handle of the required device.
*
* Returns:
*
* Non-zero - if streaming has autostopped.
*
****************************************************************************/
extern int16_t __declspec(dllexport) __stdcall AutoStopped(int16_t handle)
{
	if( _ready) 
	{
		return _autoStop;
	}
	
	return 0;
}

/****************************************************************************
* IsReady
*
* This function is used to poll the driver to verify that data is ready to be 
* received. The RunBlock or GetStreamingLatestValues function must have been 
* called prior to calling this function.
*
* Input Arguments:
*
* handle - the handle of the required device.
*
* Returns:
*
* 0  Data is not yet available.
* Non-zero  Data is ready to be collected.
*
****************************************************************************/
extern int16_t __declspec(dllexport) __stdcall IsReady(int16_t handle)
{
	return _ready;
}

/****************************************************************************
* IsTriggerReady
*
* Indicates whether a trigger has occurred when collecting data in streaming 
* mode, and the location of the trigger point in the buffer.
*
* Input Arguments:
*
* handle - the handle of the required device.
* triggeredAt  on exit, the index of the sample in the buffer where the 
* trigger occurred.
*
* Returns:
*
* 0  The device has not triggered.
* Non-zero  The device has been triggered.
*
****************************************************************************/
extern int16_t __declspec(dllexport) __stdcall IsTriggerReady(int16_t handle, uint32_t *triggeredAt)
{
	if (_triggered)
	{
		*triggeredAt = _triggeredAt;
	}
	
	return _triggered;
}

/****************************************************************************
* ClearTriggerReady
*
* Clears the triggered and triggeredAt flags in relation to streaming mode 
* capture.
*
* Input Arguments:
*
* None
*
* Returns:
*
* 1
*
****************************************************************************/
extern PICO_STATUS __declspec(dllexport) __stdcall ClearTriggerReady(int16_t handle)
{
	_triggeredAt = 0;
	_triggered = FALSE;
	return PICO_OK;
}

/****************************************************************************
* SetTriggerConditions
*
* This function sets up trigger conditions on the scope's inputs. The 
* trigger is defined by one or more sets of integers corresponding to 
* PS2000A_TRIGGER_CONDITIONS structures which are then converted and passed 
* to the ps2000aSetTriggerChannelConditions function.
*
* Use this function with programming languages that do not support structs.
*
* Input Arguments:
*
* handle - the handle of the required device.
* conditionsArray  an array of integer values specifying the conditions 
*					for each channel.
* nConditions  the number that will be passed after the wrapper code has 
* created its structures. (i.e. the number of conditionsArray elements / 8)
*
* Returns:
*
* See ps2000aSetTriggerChannelConditions return values.
*
****************************************************************************/
extern PICO_STATUS __declspec(dllexport) __stdcall SetTriggerConditions(int16_t handle, uint32_t *conditionsArray, int16_t nConditions)
{
	PICO_STATUS status;
	int16_t i = 0;
	int16_t j = 0;

	PS2000A_TRIGGER_CONDITIONS *conditions = (PS2000A_TRIGGER_CONDITIONS *) calloc (nConditions, sizeof(PS2000A_TRIGGER_CONDITIONS));

	for (i = 0; i < nConditions; i++)
	{
		conditions[i].channelA	= (PS2000A_TRIGGER_STATE) conditionsArray[j];
		conditions[i].channelB	= (PS2000A_TRIGGER_STATE) conditionsArray[j + 1];
		conditions[i].channelC	= (PS2000A_TRIGGER_STATE) conditionsArray[j + 2];
		conditions[i].channelD	= (PS2000A_TRIGGER_STATE) conditionsArray[j + 3];
		conditions[i].external	= (PS2000A_TRIGGER_STATE) conditionsArray[j + 4];
		conditions[i].aux		= (PS2000A_TRIGGER_STATE) conditionsArray[j + 5];
		conditions[i].pulseWidthQualifier = (PS2000A_TRIGGER_STATE) conditionsArray[j + 6];
		conditions[i].digital = (PS2000A_TRIGGER_STATE) conditionsArray[j + 7];

		j = j + 8;
	}
	status = ps2000aSetTriggerChannelConditions(handle, conditions, nConditions);
	free (conditions);

	return status;
}

/****************************************************************************
* SetTriggerProperties
*
* This function is used to enable or disable triggering and set its 
* parameters by means of assigning the values from the propertiesArray to an 
* array of PS2000A_TRIGGER_CHANNEL_PROPERTIES structures which are then 
* passed to the ps2000aSetTriggerChannelProperties function with the other 
* parameters.
*
* Use this function with programming languages that do not support structs.
*
* Input Arguments:
*
* handle - the handle of the required device.
* propertiesArray  an array of sets of integers corresponding to 
*					PS2000A_TRIGGER_CHANNEL_PROPERTIES structures describing 
*					the required properties to be set. See also 
*					channelProperties in ps2000aSetTriggerChannelProperties.
*
* nProperties  the number that will be passed after the wrapper code has 
*				created its structures. (i.e. the number of propertiesArray 
*				elements / 6)
* autoTrig  see autoTriggerMilliseconds in ps6000SetTriggerChannelProperties.
*
*
* Returns:
*
* See ps2000aSetTriggerChannelProperties return values.
*
****************************************************************************/
extern PICO_STATUS __declspec(dllexport) __stdcall SetTriggerProperties(
	int16_t handle, 
	uint32_t *propertiesArray, 
	int16_t nProperties, 
	int32_t autoTrig)
{
	PS2000A_TRIGGER_CHANNEL_PROPERTIES *channelProperties = (PS2000A_TRIGGER_CHANNEL_PROPERTIES *) calloc(nProperties, sizeof(PS2000A_TRIGGER_CHANNEL_PROPERTIES));
	
	int16_t i;
	int16_t j = 0;
	int16_t auxEnable = 0;
	PICO_STATUS status;
	
	for (i = 0; i < nProperties; i++)
	{
		channelProperties[i].thresholdUpper				= propertiesArray[j];
		channelProperties[i].thresholdUpperHysteresis	= propertiesArray[j + 1];
		channelProperties[i].thresholdLower				= propertiesArray[j + 2];
		channelProperties[i].thresholdLowerHysteresis	= propertiesArray[j + 3];
		channelProperties[i].channel					= (PS2000A_CHANNEL) propertiesArray[j + 4];
		channelProperties[i].thresholdMode				= (PS2000A_THRESHOLD_MODE) propertiesArray[j + 5];

		j= j + 6;
	}
	status = ps2000aSetTriggerChannelProperties(handle, channelProperties, nProperties, auxEnable, autoTrig);
	free(channelProperties);
	return status;
}

/****************************************************************************
* SetPulseWidthQualifier
*
* This function is used to pulse-width triggering and set 
* its parameters by means of assigning the values from the pwqConditionsArray 
* to an array of PS2000A_PWQ_CONDITIONS structures which are then passed to 
* the ps2000aSetPulseWidthQualifier function with the other parameters.

* Use this function with programming languages that do not support structs.
*
* Input Arguments:
*
* handle - the handle of the required device.
* pwqConditionsArray  an array of sets of integers corresponding to 
*					PS2000A_PWQ_CONDITIONS structures describing the 
*					required conditions to be set. See also conditions
*					in ps2000aSetPulseWidthQualifier.
*
* nConditions  the number that will be passed after the wrapper code has 
*				created its structures. (i.e. the number of conditionsArray 
*				elements / 7)
*
* direction - the direction of the signal required for the pulse width
*				trigger to fire (See PS2000A_THRESHOLD_DIRECTION constants)
* lower - the lower limit of the pulse-width counter with relation to
			number of samples captured on the device.
* upper - the upper limit of the pulse-width counter with relation to
*			number of samples captured on the device.
* type - the pulse-width type (see ps2000aSetPulseWidthQualifier).
*
* Returns:
*
* See ps2000aSetPulseWidthQualifier return values.
*
****************************************************************************/
extern PICO_STATUS __declspec(dllexport) __stdcall SetPulseWidthQualifier(
	int16_t handle,
	uint32_t *pwqConditionsArray,
	int16_t nConditions,
	uint32_t direction,
	uint32_t lower,
	uint32_t upper,
	uint32_t type)
{
	// Allocate memory
	PS2000A_PWQ_CONDITIONS *pwqConditions = (PS2000A_PWQ_CONDITIONS *) calloc(nConditions, sizeof(PS2000A_PWQ_CONDITIONS));

	int16_t i;
	int16_t j = 0;

	PICO_STATUS status;

	for(i = 0; i < nConditions; i++)
	{
		pwqConditions[i].channelA = (PS2000A_TRIGGER_STATE) pwqConditionsArray[j];
		pwqConditions[i].channelB = (PS2000A_TRIGGER_STATE) pwqConditionsArray[j + 1];
		pwqConditions[i].channelC = (PS2000A_TRIGGER_STATE) pwqConditionsArray[j + 2];
		pwqConditions[i].channelD = (PS2000A_TRIGGER_STATE) pwqConditionsArray[j + 3];
		pwqConditions[i].external = (PS2000A_TRIGGER_STATE) pwqConditionsArray[j + 4];
		pwqConditions[i].aux      = (PS2000A_TRIGGER_STATE) pwqConditionsArray[j + 5];
		pwqConditions[i].digital  = (PS2000A_TRIGGER_STATE) pwqConditionsArray[j + 6];

		j = j + 7;
	}

	status = ps2000aSetPulseWidthQualifier(handle, pwqConditions, nConditions, (PS2000A_THRESHOLD_DIRECTION) direction, 
		lower, upper, (PS2000A_PULSE_WIDTH_TYPE) type);
	
	free(pwqConditions);
	return status;
}

/****************************************************************************
* setChannelCount
*
* Set the number of analogue channels on the device. This is used to assist 
* with copying data in the streaming callback.
*
* Input Arguments:
*
* handle - the device handle.
* channelCount - the number of channels on the device.
*
* Returns:
*
* PICO_OK, if successful
* PICO_INVALID_HANDLE, if handle is less than or equal to 0
* PICO_INVALID_PARAMETER, if channelCount is less than 0 or greater than
*	the number of analogue channels
****************************************************************************/
extern PICO_STATUS __declspec(dllexport) __stdcall setChannelCount(int16_t handle, int16_t channelCount)
{
	if(handle > 0)
	{
		if(channelCount > 0 || channelCount <= MAX_ANALOGUE_CHANNELS)
		{
			_channelCount = channelCount;

			return PICO_OK;
		}
		else
		{
			return PICO_INVALID_PARAMETER;
		}
	}
	else
	{
		return PICO_INVALID_HANDLE;
	}
}

/****************************************************************************
* setEnabledChannels
*
* Set the number of enabled analogue channels on the device. This is used to 
* assist with copying data in the streaming callback.
*
* setChannelCount should be called prior to calling this function.
*
* Input Arguments:
*
* handle - the device handle.
* enabledChannels - an array representing the channel states. This must be 
*					2 elements in size.
*
* Returns:
*
* PICO_OK, if successful
* PICO_INVALID_HANDLE, if handle is less than or equal to 0
* PICO_INVALID_PARAMETER, if _channelCount is invalid
****************************************************************************/
extern PICO_STATUS __declspec(dllexport) __stdcall setEnabledChannels(int16_t handle, int16_t * enabledChannels)
{
	if(handle > 0)
	{
		if(_channelCount > 0 && _channelCount <= MAX_ANALOGUE_CHANNELS)
		{
			memcpy_s((int16_t *)_enabledChannels, MAX_ANALOGUE_CHANNELS * sizeof(int16_t), 
				(int16_t *)enabledChannels, MAX_ANALOGUE_CHANNELS * sizeof(int16_t));

			return PICO_OK;
		}
		else
		{
			return PICO_INVALID_PARAMETER;
		}
	}
	else
	{
		return PICO_INVALID_HANDLE;
	}
}

/****************************************************************************
* setDigitalPortCount
*
* Set the number of digital ports on the device. This is used to assist 
* with copying data in the streaming callback.
*
* Input Arguments:
*
* handle - the device handle.
* digitalPortCount - the number of digital ports on the device. This should
*					be set to 2 for the PicoScope 2205 MSO and 0 for other 
*					models.
*
* Returns:
*
* PICO_OK, if successful
* PICO_INVALID_HANDLE, if handle is less than or equal to 0
* PICO_INVALID_PARAMETER, if digitalPortCount is not 0 or 2
****************************************************************************/
extern PICO_STATUS __declspec(dllexport) __stdcall setDigitalPortCount(int16_t handle, int16_t digitalPortCount)
{
	if(handle > 0)
	{
		if(digitalPortCount == 0 || digitalPortCount == MAX_DIGITAL_PORTS)
		{
			_digitalPortCount = digitalPortCount;

			return PICO_OK;
		}
		else
		{
			return PICO_INVALID_PARAMETER;
		}
	}
	else
	{
		return PICO_INVALID_HANDLE;
	}
}

/****************************************************************************
* setEnabledDigitalPorts
*
* Set the number of enabled digital ports on the device. This is used to 
* assist with copying data in the streaming callback.
*
* This function does not need to be called for non-MSO models.
*
* Input Arguments:
*
* handle - the device handle.
* enabledDigitalPorts - an array representing the digital port states. This 
*						must be 2 elements in size.
*
* Returns:
*
* PICO_OK, if successful
* PICO_INVALID_HANDLE, if handle is less than or equal to 0
* PICO_INVALID_PARAMETER, if _digitalPortCount is not 0 or 2
****************************************************************************/
extern PICO_STATUS __declspec(dllexport) __stdcall setEnabledDigitalPorts(int16_t handle, int16_t * enabledDigitalPorts)
{
	if(handle > 0)
	{
		if(_digitalPortCount == 0 || _digitalPortCount == MAX_DIGITAL_PORTS)
		{
			memcpy_s((int16_t *)_enabledDigitalPorts, MAX_DIGITAL_PORTS * sizeof(int16_t), 
				(int16_t *)enabledDigitalPorts, MAX_DIGITAL_PORTS * sizeof(int16_t));

			return PICO_OK;
		}
		else
		{
			return PICO_INVALID_PARAMETER;
		}
	}
	else
	{
		return PICO_INVALID_HANDLE;
	}
}

/****************************************************************************
* setAppAndDriverBuffers
*
* Set the application and corresponding driver buffer in order for the 
* streaming callback to copy the data for the analogue channel from the 
* driver buffer to the application buffer.
*
* Input Arguments:
*
* handle - the device handle.
* channel - the channel number (should be a numerical value corresponding to
			a PS2000A_CHANNEL enumeration value).
* appBuffer - the application buffer.
* driverBuffer - the buffer set by the driver.
* bufferLength - the length of the buffers (the length of the buffers must be
*				 equal).
*
* Returns:
*
* PICO_OK, if successful
* PICO_INVALID_HANDLE, if handle is invalid
* PICO_INVALID_CHANNEL, if channel is not 0 (A) or 1 (B)
****************************************************************************/
extern PICO_STATUS __declspec(dllexport) __stdcall setAppAndDriverBuffers(int16_t handle, int16_t channel, int16_t * appBuffer, int16_t * driverBuffer, int32_t bufferLength)
{
	if(handle > 0)
	{
		if(channel < PS2000A_CHANNEL_A || channel > PS2000A_CHANNEL_B)
		{
			return PICO_INVALID_CHANNEL;
		}
		else
		{
			_wrapBufferInfo.appBuffers[channel * 2] = appBuffer;
			_wrapBufferInfo.driverBuffers[channel * 2] = driverBuffer;
				
			_wrapBufferInfo.bufferLengths[channel] = bufferLength;

			return PICO_OK;
		}
	}
	else
	{
		return PICO_INVALID_HANDLE;
	}
}

/****************************************************************************
* setMaxMinAppAndDriverBuffers
*
* Set the application and corresponding driver buffers in order for the 
* streaming callback to copy the data for the analogue channel from the 
* driver max and min buffers to the respective application buffers for 
* aggregated data collection.
*
* Input Arguments:
*
* handle - the device handle.
* channel - the channel number (should be a numerical value corresponding to
			a PS2000A_CHANNEL enumeration value).
* appMaxBuffer - the application max buffer.
* appMinBuffer - the application min buffer.
* driverMaxBuffer - the max buffer set by the driver.
* driverMinBuffer - the min buffer set by the driver.
* bufferLength - the length of the buffers (the length of the buffers must be
*				 equal).
*
* Returns:
*
* PICO_OK, if successful
* PICO_INVALID_HANDLE, if handle is invalid
* PICO_INVALID_CHANNEL, if channel is not 0 (A) or 1 (B)
****************************************************************************/
extern PICO_STATUS __declspec(dllexport) __stdcall setMaxMinAppAndDriverBuffers(int16_t handle, int16_t channel, int16_t * appMaxBuffer, int16_t * appMinBuffer, int16_t * driverMaxBuffer, int16_t * driverMinBuffer, int32_t bufferLength)
{
	if(handle > 0)
	{
		if(channel < PS2000A_CHANNEL_A || channel > PS2000A_CHANNEL_B)
		{
			return PICO_INVALID_CHANNEL;
		}
		else
		{
			_wrapBufferInfo.appBuffers[channel * 2] = appMaxBuffer;
			_wrapBufferInfo.driverBuffers[channel * 2] = driverMaxBuffer;

			_wrapBufferInfo.appBuffers[channel * 2 + 1] = appMinBuffer;
			_wrapBufferInfo.driverBuffers[channel * 2 + 1] = driverMinBuffer;

			_wrapBufferInfo.bufferLengths[channel] = bufferLength;

			return PICO_OK;
		}
	}
	else
	{
		return PICO_INVALID_HANDLE;
	}
}

/****************************************************************************
* setAppAndDriverDigiBuffers
*
* Set the application and corresponding driver buffer in order for the 
* streaming callback to copy the data for the digital port from the 
* driver buffer to the application buffer.
*
* This function applies to the PicoScope 2205 MSO only.
*
* Input Arguments:
*
* handle - the device handle.
* digiPort - the digital port number (0 or 1).
* appDigiBuffer - the application buffer for the digital port.
* driverDigitalBuffer - the buffer for the digital port set by the driver.
* bufferLength - the length of the buffers (the length of the buffers must be
*				 equal).
*
* Returns:
*
* PICO_OK, if successful
* PICO_INVALID_HANDLE, if handle is invalid
* PICO_INVALID_DIGITAL_PORT, if digiPort is not 0 (Port 0) or 1 (Port 1)
****************************************************************************/
extern PICO_STATUS __declspec(dllexport) __stdcall setAppAndDriverDigiBuffers(int16_t handle, int16_t digiPort, int16_t * appDigiBuffer, int16_t * driverDigiBuffer, int32_t bufferLength)
{
	if(handle > 0)
	{
		if(digiPort < PS2000A_WRAP_DIGITAL_PORT0 || digiPort > PS2000A_WRAP_DIGITAL_PORT1)
		{
			return PICO_INVALID_DIGITAL_PORT;
		}
		else
		{
			_wrapBufferInfo.appDigiBuffers[digiPort * 2] = appDigiBuffer;
			_wrapBufferInfo.driverDigiBuffers[digiPort * 2] = driverDigiBuffer;
				
			_wrapBufferInfo.digiBufferLengths[digiPort] = bufferLength;

			return PICO_OK;
		}
	}
	else
	{
		return PICO_INVALID_HANDLE;
	}
}

/****************************************************************************
* setMaxMinAppAndDriverDigiBuffers
*
* Set the application and corresponding driver buffers in order for the 
* streaming callback to copy the data for the digital port from the 
* driver max and min buffers to the respective application buffers for 
* aggregated data collection.
*
* This function applies to the PicoScope 2205 MSO only.
*
* Input Arguments:
*
* handle - the device handle.
* digiPort - the digital port number (0 or 1).
* appMaxDigiBuffer - the application max buffer for the digital port.
* appMinDigiBuffer - the application min buffer for the digital port.
* driverMaxDigiBuffer - the max buffer set by the driver for the digital port.
* driverMinDigiBuffer - the min buffer set by the driver for the digital port.
* bufferLength - the length of the buffers (the length of the buffers must be
*				 equal).
*
* Returns:
*
* PICO_OK, if successful
* PICO_INVALID_HANDLE, if handle is invalid
* PICO_INVALID_DIGITAL_PORT, if digiPort is not 0 (Port 0) or 1 (Port 1)
****************************************************************************/
extern PICO_STATUS __declspec(dllexport) __stdcall setMaxMinAppAndDriverDigiBuffers(int16_t handle, int16_t digiPort, int16_t * appMaxDigiBuffer, int16_t * appMinDigiBuffer, int16_t * driverMaxDigiBuffer, int16_t * driverMinDigiBuffer, int32_t bufferLength)
{
	if(handle > 0)
	{
		if(digiPort < PS2000A_WRAP_DIGITAL_PORT0 || digiPort > PS2000A_WRAP_DIGITAL_PORT1)
		{
			return PICO_INVALID_DIGITAL_PORT;
		}
		else
		{
			_wrapBufferInfo.appDigiBuffers[digiPort * 2] = appMaxDigiBuffer;
			_wrapBufferInfo.driverDigiBuffers[digiPort * 2] = driverMaxDigiBuffer;

			_wrapBufferInfo.appDigiBuffers[digiPort * 2 + 1] = appMinDigiBuffer;
			_wrapBufferInfo.driverDigiBuffers[digiPort * 2 + 1] = driverMinDigiBuffer;

			_wrapBufferInfo.digiBufferLengths[digiPort] = bufferLength;

			return PICO_OK;
		}
	}
	else
	{
		return PICO_INVALID_HANDLE;
	}
}
