Problem in returning callback values in the Streaming handler

Post your C and C++ discussions here
Post Reply
vincenzo.vitale
Newbie
Posts: 0
Joined: Tue Sep 28, 2021 3:13 pm

Problem in returning callback values in the Streaming handler

Post by vincenzo.vitale »

Good day,
I'm programming a Visual C++17 code that use a Picoscope 4224 IEPE to obtain a stream of values for a range of time with minimum latency possible. My case limit is doing a stream of 60s at 1MS/s of sampling (60MS)
I've adapted your example of StreamingHandler and CallbackStreaming seen no Github to develop it.
Unfortunately I obtain a big latency (even 20-30s of wait from the shaking of the accelerometer to the change of the value, seen roughly with a printf call) but, even worse, I have 2 main problems:
1) the Callback function doesn't return the values that modifies after the copy (such as the flag g_ready and the value g_sampleCount), so the totalCount remains 0 and doesn't stop even after a complete sampling;
2) the initial values received to the buffer appears to be overcharged (starts with the minimum value -32764 and then tends to turn to value near 0) such as a sort of measurement discharge that I don't understand how is possible.

How I can resolve these problems?
I attach the code, sorry if the comments are in italian but I didn't had time to translate all of them.

Thank you for your help
Vincenzo

Code: Select all

void myStreamDataHandler(int sampling_duration, int sampling_freq, bool IsChannelAOpen, bool IsChannelBOpen, bool CouplingMode[2], int VoltageRange[2]) {
    int32_t i, j;
    int temp_Count = 0;
    uint32_t sampleCount = 50000; /* Make sure buffer large enough */
    FILE* fp = NULL;
    int16_t* buffers[PS4000_MAX_CHANNEL_BUFFERS/2];
    int16_t* appBuffers[PS4000_MAX_CHANNEL_BUFFERS/2];
    PICO_STATUS status;
    uint32_t sampleInterval = 1;
    int32_t index = 0;
    int32_t totalSamples = 0;
    uint32_t triggeredAt = 0;
    int16_t retry = 0;

    BUFFER_INFO bufferInfo;
    UNIT_MODEL* unit = new UNIT_MODEL;
        
        status = ps4000OpenUnit(&(unit->handle)); // Avvio la comunicazione con il Picoscope
                 

    // Avvio casi limiti
        if (unit->handle == 0) {
            status = ps4000CloseUnit(unit->handle);
            // MessageBox(NULL,(LPCTSTR)"ERRORE: Picoscope non trovato, assicurarsi che sia connesso al PC", NULL, 0x00000000L);
        }
        else if (unit->handle == -1) {
            status = ps4000CloseUnit(unit->handle);
            // MessageBox(NULL, (LPCTSTR)"ERRORE: Impossibile avviare il Picoscope, verificare lo stato d'integrità del dispositivo", NULL, 0x00000000L);
        }
        // Check dello status del Picoscope
        if ((status != PICO_OK) && (status == PICO_EEPROM_CORRUPT))
        {
            status = ps4000CloseUnit(unit->handle);
            // MessageBox(NULL, (LPCTSTR)"ERRORE: Picoscope danneggiato (EEPROM_CORRUPT), verificare lo stato d'integrità del dispositivo", NULL, 0x00000000L);
        }

              get_info(unit); //Setto la variabile unit con tutti i dati specifici del dispositivo
    // Calcolo numero di sample necessari al nostro caso, tramite OVERRIDE della variabile pre-dichiarata
              if (sampling_duration != 0 && sampling_freq!= 0) {
                  sampleCount = static_cast(sampling_duration * sampling_freq); // Durata/Periodo per MegaSamples => MS/s => MHz => AGGIUNGERE LIMITE DI 80 MS/s
              } // OVERRIDE DEL SAMPLING COUNT LIMITE = 80 MS/s in Real-Time per il nostro 4224 IEPE

    // Setto il buffer
        for (i = 0; i < unit->channelCount; i++) // create data buffers
        {
            buffers[i] = (int16_t*)calloc(sampleCount, sizeof(int16_t));
            // buffers[i * 2 + 1] = (int16_t*)calloc(sampleCount, sizeof(int16_t));

            status = ps4000SetDataBuffers(unit->handle, (PS4000_CHANNEL)i, buffers[i * 2], buffers[i * 2 + 1], sampleCount);
            if (status != PICO_OK) {
                status = ps4000CloseUnit(unit->handle);
                //  MessageBox(NULL, (LPCTSTR)"ERRORE: non è stato possibile allocare i buffer, controlla lo stato d'integrità del PC.", NULL, 0x00000000L);
                break;
            }
            // Application buffers to copy data into
            appBuffers[i] = (int16_t*)malloc(sampleCount * sizeof(int16_t));
            // appBuffers[i * 2 + 1] = (int16_t*)malloc(sampleCount * sizeof(int16_t));
        }

        bufferInfo.unit = unit;
        bufferInfo.driverBuffers = buffers;
        bufferInfo.appBuffers = appBuffers;

    // Setto i channel per il compito da svolgere
        if (IsChannelAOpen == true && IsChannelBOpen != true) { // Solo Channel A
            status = ps4000SetChannel(unit->handle, PS4000_CHANNEL_B, int16_t(false), int16_t(CouplingMode[1]), (PS4000_RANGE)VoltageRange[1]);
            status = ps4000SetChannel(unit->handle, PS4000_CHANNEL_A, int16_t(true), int16_t(CouplingMode[0]), (PS4000_RANGE)VoltageRange[0]);
            if (status != PICO_OK) {
                status = ps4000CloseUnit(unit->handle);
                //  MessageBox(NULL, (LPCTSTR)"ERRORE: non è stato possibile avviare il Channel A, verificare collegamenti e stato integrità dispositivo.", NULL, 0x00000000L);
            }
        }
        else if (IsChannelAOpen != true && IsChannelBOpen == true) { // Solo Channel B
            status = ps4000SetChannel(unit->handle, PS4000_CHANNEL_A, int16_t(false), int16_t(CouplingMode[0]), (PS4000_RANGE)VoltageRange[0]);
            status = ps4000SetChannel(unit->handle, PS4000_CHANNEL_B, int16_t(true), int16_t(CouplingMode[1]), (PS4000_RANGE)VoltageRange[1]);
            if (status != PICO_OK) {
                status = ps4000CloseUnit(unit->handle);
                //  MessageBox(NULL, (LPCTSTR)"ERRORE: non è stato possibile avviare il Channel B, verificare collegamenti e stato integrità dispositivo.", NULL, 0x00000000L);
            }
        }
        else if (IsChannelAOpen == true && IsChannelBOpen == true) { // Tutte due i channel attivi
            status = ps4000SetChannel(unit->handle, PS4000_CHANNEL_A, int16_t(true), int16_t(CouplingMode[0]), (PS4000_RANGE)VoltageRange[0]);
            if (status != PICO_OK) {
                status = ps4000CloseUnit(unit->handle); // Soluzione conservativa: il dispositivo non può volare fino a quando tutto funziona!
               // MessageBox(NULL, (LPCTSTR)"ERRORE: non è stato possibile avviare il Channel A, verificare collegamenti e stato integrità dispositivo.", NULL, 0x00000000L);
            }
            status = ps4000SetChannel(unit->handle, PS4000_CHANNEL_B, int16_t(true), int16_t(CouplingMode[1]), (PS4000_RANGE)VoltageRange[1]);
            if (status != PICO_OK) {
                status = ps4000CloseUnit(unit->handle);
                //   MessageBox(NULL, (LPCTSTR)"ERRORE: non è stato possibile avviare il Channel B, verificare collegamenti e stato integrità dispositivo.", NULL, 0x00000000L);
            }
        }
    

    //Setting dei trigger per l'avvio misurazione
        TRIGGER_CONDITIONS conditions;
        conditions.channelA = CONDITION_DONT_CARE;
        conditions.channelB = CONDITION_DONT_CARE;
        conditions.channelC = CONDITION_DONT_CARE;
        conditions.channelD = CONDITION_DONT_CARE;
        conditions.aux = CONDITION_DONT_CARE;
        conditions.pulseWidthQualifier = CONDITION_DONT_CARE;
        
        TRIGGER_CHANNEL_PROPERTIES properties;
        properties.thresholdLower = 0;
        properties.thresholdUpper = 0;
        properties.thresholdLowerHysteresis = 0;
        properties.thresholdUpperHysteresis = 300;
        properties.channel = PS4000_CHANNEL_A;
        properties.thresholdMode = LEVEL;

        if (ps4000SetTriggerChannelConditions(unit->handle, &conditions, 1) != PICO_OK) {
            status = ps4000CloseUnit(unit->handle);
            // MessageBox(NULL, (LPCTSTR)"ERRORE: è stato impossibile settare le condizioni di trigger. Controllare lo stato d'integrità del dispositivo.", NULL, 0x00000000L);
        }
        if (ps4000SetTriggerChannelDirections(unit->handle, NONE, RISING, NONE, NONE, NONE, NONE) != PICO_OK) {
            status = ps4000CloseUnit(unit->handle);
            // MessageBox(NULL, (LPCTSTR)"ERRORE: è stato impossibile settare le condizioni di trigger. Controllare lo stato d'integrità del dispositivo.", NULL, 0x00000000L);
        }
        if (ps4000SetTriggerChannelProperties(unit->handle, &properties, 1, 0, 0) != PICO_OK) {
            status = ps4000CloseUnit(unit->handle);
            // MessageBox(NULL, (LPCTSTR)"ERRORE: è stato impossibile settare le condizioni di trigger. Controllare lo stato d'integrità del dispositivo.", NULL, 0x00000000L);
        }

        // Avvio setting dello streaming
        float SamplingPeriod = sampling_duration / sampleCount;
        uint32_t UsedSamplingPeriod = sampling_freq; // Devo sfruttare un workaround per evitare la cancellazione numerica per rounding
        enPS4000TimeUnits SampleUnit;
        for (i = 0; i < 6; i++) {
            if (UsedSamplingPeriod < 1000 && UsedSamplingPeriod > 1) { // Come funziona: il check parte dallo studio della frequenza, divido sempre per 1000 per poter settare
                i++;                                                   // il giusto indice, trovato l'indice che permette di avere un valore di 1, questo invertito sarà
                UsedSamplingPeriod = 1000 / UsedSamplingPeriod;        // il formato del periodo effettivo. Il valore del periodo sarà comunque garantito perché 1/s => s.
                SampleUnit = (enPS4000TimeUnits)(5-i);                 // Qualora avvenga la presenza di ordini decimali non acquisibili dall' uint32_t, allora procedo a indicare
                break;                                                 // il sampling period di ordine inferiore dividendo 1000/Used Sampling Period ed addizionando l'indice.
            }                                                          // N.B. Questo workaround è testato per valori interi, non decimali di Sampling Period.
            else if (UsedSamplingPeriod == 1) {
                SampleUnit = (enPS4000TimeUnits)(5 - i);
                break;
            }
            else {
                UsedSamplingPeriod = UsedSamplingPeriod / 1000;
            }
        }
        int16_t Autostop_flag = false;
        int16_t StreamingDataReady_flag = false;
        int32_t *nMaxSample;
          
        status = ps4000FlashLed(unit->handle, -1);
        // status = ps4000MemorySegments(unit->handle, 8192, nMaxSample);
        status = ps4000RunStreaming(unit->handle, &UsedSamplingPeriod, SampleUnit, uint32_t(1), uint32_t(sampleCount), int16_t(true), uint32_t(1), sampleCount);
        if (status != PICO_OK) {
            status = ps4000CloseUnit(unit->handle);
            // MessageBox(NULL, (LPCTSTR)"ERRORE: è stato impossibile avviare lo streaming. Controlla connessioni e stato integrità dispositivo.", NULL, 0x00000000L);
        }
        // Streaming waiting loop
        while (Autostop_flag == false && totalSamples != sampleCount) {
            // Poll until data is received. Until then, GetStreamingLatestValues wont call the callback.
            StreamingDataReady_flag = false;
            status = ps4000GetStreamingLatestValues(unit->handle, (ps4000StreamingReady)DeviceFusion::CallBackStream, &bufferInfo); 
            Sleep(10); // sleep di 10 ms per evitare un sovraccarico di richiesta di dati
            index++;
            
            if (StreamingDataReady_flag && g_sampleCount > 0) /* can be ready and have no data, if autoStop has fired */
            {
                totalSamples += g_sampleCount;
            }
            
        }

        // Chiusura del dispositivo
        status = ps4000Stop(unit->handle);
        status = ps4000CloseUnit(unit->handle);

        // Libera il buffer
        for (i = 0; i < unit->channelCount * 2; i++){
            free(buffers[i]);
            free(appBuffers[i]);
        }

}
*************************************************************************************************************
// IN APPLICATION MAIN
inline void __stdcall CallBackStream(int16_t handle, int32_t noOfSamples, uint32_t startIndex, int16_t overflow, uint32_t triggerAt, int16_t triggered, int16_t autoStop, void* pParameter) {
		int32_t channel;
		BUFFER_INFO* bufferInfo = NULL;
		int32_t g_sampleCount;
		int32_t g_startIndex;
		int32_t stop_NOW = 0;
		int16_t Autostop_flag;
		int16_t StreamingDataReady_flag;

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

		// Copy data in callback
		if (bufferInfo != NULL && noOfSamples)
		{

			for (channel = 0; channel < bufferInfo->unit->channelCount; channel++)
			{
				if (bufferInfo->unit->channelSettings[channel].enabled)
				{
					if (bufferInfo->appBuffers && bufferInfo->driverBuffers)
					{
						// Max buffers
						if (bufferInfo->appBuffers[channel] && bufferInfo->driverBuffers[channel])
						{
							memcpy_s(&bufferInfo->appBuffers[channel][startIndex], noOfSamples * sizeof(int16_t),
								&bufferInfo->driverBuffers[channel][startIndex], noOfSamples * sizeof(int16_t));
						}

						// Min buffers
						/*if (bufferInfo->appBuffers[channel * 2 + 1] && bufferInfo->driverBuffers[channel * 2 + 1])
						{
							memcpy_s(&bufferInfo->appBuffers[channel * 2 + 1][startIndex], noOfSamples * sizeof(int16_t),
								&bufferInfo->driverBuffers[channel * 2 + 1][startIndex], noOfSamples * sizeof(int16_t));
						}*/
					}
				}
				
			}
						
		}
		g_sampleCount = noOfSamples;
		g_startIndex = startIndex;
		MyGraph dlg;
		dlg.drawchart(g_startIndex, g_sampleCount, bufferInfo->appBuffers[0]);
		Autostop_flag = true;
		StreamingDataReady_flag = true;
		
	}

Post Reply