nLabs-nScope / nScopeAPI

39 stars 9 forks source link

Unable to take >255 readings #16

Closed sa-battle closed 4 years ago

sa-battle commented 4 years ago

I'm trying to sample a circuit in 'real-time' one reading at a time, but readData() blocks after 255 successive reads. I have a simple circuit with the analogue output A1 is connected to Ch1, it takes 255 readings correctly then blocks. Digging into readCh1() it appears that requestTransferHasCompleted() is False so readData() blocks, but I cannot find a way to unblock it. Code follows. Data is correctly received for i = 0 to 254, at which point it blocks:

try: import nscopeapi as nsapi ns = nsapi.nScope() except Exception as e: print("Unable to communicate with nScope: {}".format(e)) else:

Unipolar 1Hz sinusoidal A1

ns.setAXOn(1,True)
ns.setAXAmplitude(1,5)
ns.setAXWaveType(1,0)
ns.setAXUnipolar(1,True)
ns.setAXFrequencyInHz(1,1.0)

# CH1 connected to A1
ns.setChannelGain(1,1.0)

# Collect data
for i in range(300):
    print(i, ns.readCh1(1,0.1))
sa-battle commented 4 years ago

I found a workaround, which is simply to close and recreate the ns object every 255 readings. To close the ns object I had to expose the close method at the Python interface by adding the following to init.py

def close(self):
    lib.nScope_close(byref(self.handle))

It would be better to be able to reset the buffer in a less destructive way, as the above incurs a bit of a time overhead.

davidjmeyer commented 4 years ago

I'm not sure I can replicate the 255 limit, but it does sound like you're hitting some kind of library limitation.

However, I think it's better to set up just one request and read the data with a slightly different interface.

Does something like this solve your problem?

try:
    import nscopeapi as nsapi
    ns = nsapi.nScope()
except Exception as e:
    print("Unable to communicate with nScope: {}".format(e))
else:
    # Unipolar 1Hz sinusoidal A1
    ns.setAXOn(1,True)
    ns.setAXAmplitude(1,5)
    ns.setAXWaveType(1,0)
    ns.setAXUnipolar(1,True)
    ns.setAXFrequencyInHz(1,1.0)

    # CH1 connected to A1
    ns.setChannelGain(1,1.0)

    # Turn on Channel 1 only
    ns.setChannelsOn(True,False,False,False)

    # sample rate is 10 Hz
    ns.setSampleRateInHz(10)

    # request 300 samples
    ns.requestData(300)

    # Collect data
    i = 0
    while ns.requestHasData():
        print(i, ns.readData(1))
        i += 1
davidjmeyer commented 4 years ago

Regardless, I think this is a failure in API documentation and design. I'm working on version 1.0 of the API right now, and I'm completely rewriting the back-end to address some of the design failures with the original version. Would love to know any additional feedback.

sa-battle commented 4 years ago

Your solution above allows me to take 300 samples, however the issue is not so much the 255 limit as that the API has a fixed limit, be it 255 or 300. I guess I'm abusing the API in that instead of taking a time-bounded snapshot for analysis, I need to stream data continuously in real-time. It looks like the nsapi.nScope() object is limited in the number of requests it can handle.

This is my current working solution:

import nscopeapi as nsapi

SINE_WAVE = 0 TRIANGLE_WAVE = 1

while True: try: ns = nsapi.nScope()

Unipolar 1Hz sinusoidal A1

    ns.setAXOn(1,True)
    ns.setAXAmplitude(1,5)
    ns.setAXWaveType(1,SINE_WAVE)
    ns.setAXUnipolar(1,False)
    ns.setAXFrequencyInHz(1,1)

    # Collect data
    ns.setChannelOn(1,True)
    ns.setChannelGain(1,1.0)

    for i in range(255):
        ns.requestData(1)
        print(i, ns.readData(1))

    ns.close()

except KeyboardInterrupt:
    ns.close()
    break

except Exception as e:
    print("Unable to communicate with nScope: {}".format(e))
    break
davidjmeyer commented 4 years ago

Ah, I understand your problem. Yes, the api has a limitation that it can't indefinitely stream data. If you notice the nScope GUI has the "roll" mode greyed out, this is why. Also, this reason is among many that I'm rewriting the backend of the API.

For now, you've discovered another bug though, which is that the API seems to be limited to 255 samples. I'll take a look and see if I can patch that.

As for the indefinite sampling feature, I'll make my new API public and open source soon, and would welcome any early feedback. Right now it doesn't do much other than find connected nScopes, but I hope to round out some functionality and publish it soon.

davidjmeyer commented 4 years ago

Ok, this was quick.

What's happening is that we're creating requests and not freeing them in the backend. Each request is labeled with a 1-byte ID, and when there are no more to create, then something blocks.

In theory, this 1-byte ID isn't much of a limitation because it's meant to identify requests that are in transit. However, the backend doesn't release the request automatically because it cannot be sure that the user has read the data.

To fix your issue, you can do this to release each request after you've read the data.

   # Collect data
    for i in range(300):
        print(i, ns.readCh1(1,0.1))
        ns.releaseRequest()
sa-battle commented 4 years ago

Brilliant - releaseRequest() is exactly what I need and works perfectly. I get a nice steady stream of readings now. I'm a big fan of the nScope and hope to see it back on sale someday.. in case I blow up my current one. I wouldn't start a breadboard project without it. Thanks for your help.

chuckuntulis commented 4 years ago

I just unburied my nscope and am looking for information for how to use it and some starter projects. Where can I find information about it's use. I would like to use it with a Circuit Playground Express but I want to make sure that I don't want to blow either of them up. Specifically with a ultrasound sensor and then other sensors.

Thanks Chuck

On Sat, May 16, 2020, 5:44 AM sa-battle notifications@github.com wrote:

Brilliant - releaseRequest() is exactly what I need and works perfectly. I get a nice steady stream of readings now. I'm a big fan of the nScope and hope to see it back on sale someday.. in case I blow up my current one. I wouldn't start a breadboard project without it. Thanks for your help.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/nLabs-nScope/nScopeAPI/issues/16#issuecomment-629640160, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABOKBZAJR67VBGB4LS2ZO3LRR2DBJANCNFSM4M7RIWXQ .

davidjmeyer commented 4 years ago

@chuckuntulis opened #17 to discuss

chuckuntulis commented 4 years ago

Hi David,

Thanks. That was what I thought, but I just wanted to make sure.

Chuck

On Tue, May 19, 2020 at 6:49 PM David Meyer notifications@github.com wrote:

@chuckuntulis https://github.com/chuckuntulis opened #17 https://github.com/nLabs-nScope/nScopeAPI/issues/17 to discuss

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/nLabs-nScope/nScopeAPI/issues/16#issuecomment-631184978, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABOKBZESXODNP65LBK5MA33RSMZLDANCNFSM4M7RIWXQ .