Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NAK errors #7

Open
analog-io opened this issue Oct 30, 2015 · 24 comments
Open

NAK errors #7

analog-io opened this issue Oct 30, 2015 · 24 comments

Comments

@analog-io
Copy link

It looks like this is partially working but I'm getting some NAK Errors and the program crashes when the analyzer starts to capture data.

Using Python 3.5.0

saleae.demo()
Running Saleae connection demo.

Saleae connected.
Press Enter to continue...

Set performance to full.
Press Enter to continue...

Connected devices:
<saleae.ConnectedDevice #1 LOGIC_PRO_8_DEVICE Logic Pro 8 (ffcda53224bbb23a) ACTIVE>
Only one Saleae device. Skipping device selection
Press Enter to continue...

Setting active channels (digital=[0, 1, 2, 3, 4], analog=[0, 1])
Press Enter to continue...

Reading back active channels:
digital=[0, 1, 2, 3, 4]
analog=[0, 1]
Press Enter to continue...

Setting to capture 2e6 samples
Press Enter to continue...

Setting to sample rate to at least digitial 4 MS/s, analog 100 S/s
Set to (100000000, 100)
Press Enter to continue...

Starting a capture
Traceback (most recent call last):
File "", line 1, in
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/saleae/saleae.py", line 546, in demo
while not s.is_processing_complete():
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/saleae/saleae.py", line 360, in is_processing_complete
resp = self._cmd('IS_PROCESSING_COMPLETE')
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/saleae/saleae.py", line 116, in _cmd
ret = self._recv()
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/saleae/saleae.py", line 107, in _recv
raise self.CommandNAKedError
saleae.saleae.CommandNAKedError

s = saleae.Saleae()
s.capture_to_file('~/Desktop/test.logicdata')
Traceback (most recent call last):
File "", line 1, in
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/saleae/saleae.py", line 354, in capture_to_file
self._cmd('CAPTURE_TO_FILE, ' + file_path_on_target_machine)
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/saleae/saleae.py", line 116, in _cmd
ret = self._recv()
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/saleae/saleae.py", line 107, in _recv
raise self.CommandNAKedError
saleae.saleae.CommandNAKedError

@ppannuto
Copy link
Owner

It looks like it is failing when it tries to open the file to save to:
s.capture_to_file('~/Desktop/test.logicdata')

Does that path exist on the machine that the Logic software is running on
and does Logic have permission to write that file? The ~ path likely won't
work on a Windows machine.

There's no good way for the script to do platform detection of the remote
machine. It could be modified to prompt / ask though.

On Fri, Oct 30, 2015 at 14:26 AnalogIO [email protected] wrote:

It looks like this is partially working but I'm getting some NAK Errors
and the program crashes when the analyzer starts to capture data.

Using Python 3.5.0

saleae.demo()
Running Saleae connection demo.

Saleae connected.
Press Enter to continue...

Set performance to full.
Press Enter to continue...

Connected devices:

Only one Saleae device. Skipping device selection
Press Enter to continue...

Setting active channels (digital=[0, 1, 2, 3, 4], analog=[0, 1])
Press Enter to continue...

Reading back active channels:
digital=[0, 1, 2, 3, 4]
analog=[0, 1]
Press Enter to continue...

Setting to capture 2e6 samples
Press Enter to continue...

Setting to sample rate to at least digitial 4 MS/s, analog 100 S/s
Set to (100000000, 100)
Press Enter to continue...

Starting a capture
Traceback (most recent call last):
File "", line 1, in
File
"/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/saleae/saleae.py",
line 546, in demo
while not s.is_processing_complete():
File
"/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/saleae/saleae.py",
line 360, in is_processing_complete
resp = self._cmd('IS_PROCESSING_COMPLETE')
File
"/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/saleae/saleae.py",
line 116, in _cmd
ret = self._recv()
File
"/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/saleae/saleae.py",
line 107, in _recv
raise self.CommandNAKedError
saleae.saleae.CommandNAKedError

s = saleae.Saleae()
s.capture_to_file('~/Desktop/test.logicdata')
Traceback (most recent call last):
File "", line 1, in
File
"/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/saleae/saleae.py",
line 354, in capture_to_file
self._cmd('CAPTURE_TO_FILE, ' + file_path_on_target_machine)
File
"/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/saleae/saleae.py",
line 116, in _cmd
ret = self._recv()
File
"/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/saleae/saleae.py",
line 107, in _recv
raise self.CommandNAKedError
saleae.saleae.CommandNAKedError


Reply to this email directly or view it on GitHub
#7.

@analog-io
Copy link
Author

I'm testing on a Mac so the '~/Desktop/' folder does exist. I don't have a file already called test.logicdata at this path but I assume that is ok.

@analog-io
Copy link
Author

I'm testing this some more, here is the latest output

Setting to sample rate to at least digitial 4 MS/s, analog 100 S/s
Set to (100000000, 100)
Press Enter to continue...

Starting a capture
Traceback (most recent call last):
File "", line 1, in
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/saleae/saleae.py", line 546, in demo
while not s.is_processing_complete():
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/saleae/saleae.py", line 360, in is_processing_complete
resp = self._cmd('IS_PROCESSING_COMPLETE')
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/saleae/saleae.py", line 116, in _cmd
ret = self._recv()
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/saleae/saleae.py", line 107, in _recv
raise self.CommandNAKedError
saleae.saleae.CommandNAKedError

It looks to me like the 'IS_PROCESSING_COMPLETE' cmd is resulting in a NAK error. Is it possible that if processing is not complete it returns a NAK?

@Marcus10110
Copy link
Collaborator

Internally, the Saleae software has some (previously not documented) requirements:
The path needs to be absolute.
The target directory needs to exist.
I've just updated the documentation, which you can find here:
https://github.com/saleae/SaleaeSocketApi/tree/master/Doc
We've moved the Saleae examples and documentation to GitHub when we released 1.2.5:
https://github.com/saleae/SaleaeSocketApi

The IS_PROCESSING_COMPLETE command is supposed to NAK when capture processing is not complete, this is in the documentation too. Generally you should wait in a loop until the function returns ACK.

@analog-io
Copy link
Author

ok so now I am able to start captures via python but I am unable to export the data as csv.

I am using the following code:

import saleae
s = saleae.Saleae()
s.capture_start_and_wait_until_finished()
s.export_data('/Users/lgbeno/Documents/logic_captures/test.csv')

The logic captures folder does exist, test.csv does not. The commands execute just fine but no file can be found after execution.

@Marcus10110
Copy link
Collaborator

Pipe the output of the Logic binary to a file when you launch it, and then run the script. After the script completes, post a copy of the log file. That might contain useful information about the export process. Make sure you're using 1.2.5, it prints out much more detailed debug data when socket based export commands are not properly formed.

Also, the data export command is crazy complicated. I created a new command, EXPORT_DATA2, which formally covers all possible export combinations, where the original EXPORT_DATA command didn't actually handle all possible export options properly.

Here is the C# source for the export_data2 wrapper:
https://github.com/saleae/SaleaeSocketApi/blob/master/SaleaeSocketApi/SocketApi.cs#L389

Here are the tests we scripted to test all significant export option variants:
https://github.com/saleae/SaleaeSocketApi/blob/master/SaleaeSocketApiUnitTests/ExportUnitTests.cs

The API is a 1 to 1 direct mapping to the internal settings struct that is configured with the normal socket GUI. unfortunately it's not possible to use the GUI to create a socket command, but at least you can see what settings need to be set from the GUI based on your capture settings, and then try to replicated then in the API.

The socket export command is very sensitive to the type of data you captured. Like this:

Even if you're just exporting digital, it still matters if you capture analog or not.

If you tell me what analog and digital channels you had active, and what kind of file you want (CSV, just digital, etc) I can help form the correct command.

You can also use the examples from the ExportUnitTests.cs file to find an export mode that closest matches your situation.

@analog-io
Copy link
Author

So I've been trying to pipe out that data, this is what I put into the terminal to launch but not having any luck:

open /Applications/Logic.app/ > ~/Desktop/logic_log_dump.txt

@Marcus10110
Copy link
Collaborator

I've never tried this using open before. Here is how I normally capture the log on OSX:
cd /
./Applications/Logic.app/Contents/MacOS/Logic > ~/log.txt

@analog-io
Copy link
Author

That worked much better...

exe File path is /Applications/Logic.app/Contents/MacOS/Logic  [ /Users/build/ob_logic/Source/Environment.cpp; Environment; 260 ]
exe folder path is /Applications/Logic.app/Contents/MacOS  [ /Users/build/ob_logic/Source/Environment.cpp; Environment; 261 ]
Release Mode; analyzer path is /Applications/Logic.app/Contents/Resources/Analyzers  [ /Users/build/ob_logic/Source/Environment.cpp; Environment; 283 ]
Release Mode; exe path is /Applications/Logic.app/Contents/MacOS; user path is /Users/lgbeno  [ /Users/build/ob_logic/Source/Environment.cpp; Environment; 318 ]
Found log directory at Library//Logs//DiagnosticReports  [ /Users/build/ob_logic/Source/Environment.cpp; Environment; 327 ]
  [ /Users/build/ob_logic/Source/OsxDevicesManager.cpp; InitializeUsbDevices; 73 ]
First device connected. Creating Primary Display.  [ /Users/build/ob_logic/Source/LogicWindow_Devices.cpp; AttachedDevicesChangedSlot; 70 ]
GeneratePixmapEllipses: 1.302356 seconds  [ /Users/build/ob_logic/Source/AnalogDisplayEngine.cpp; AnalogDisplayEngine; 38 ]
device change has triggered sprucing up the empty capture tab.  [ /Users/build/ob_logic/Source/LogicWindow_Controller.cpp; ActiveDeviceChanged; 454 ]
setting PrimaryDisplay's Session to NULL.  [ /Users/build/ob_logic/Source/PrimaryDisplay.cpp; SetSession; 562 ]
New Socket Connection, port: 10429  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; NewConnectionSlot; 61 ]
Received command on port 10429: CAPTURE  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; SocketReadyReadSlot; 129 ]
changing active tab to: 0  [ /Users/build/ob_logic/Source/LogicWindow_Controller.cpp; ActiveTabChangedSlot; 58 ]
Setting API Session to 0. Previous id: 0  [ /Users/build/ob_logic/Source/ApiServer.cpp; SetActiveSession; 685 ]
setting PrimaryDisplay's Session to NULL.  [ /Users/build/ob_logic/Source/PrimaryDisplay.cpp; SetSession; 562 ]
Starting capture with device ID: 1964999605, Type: 4  [ /Users/build/ob_logic/Source/LogicWindow_Collection.cpp; startSlot; 52 ]
Creating and Starting API capture session 1  [ /Users/build/ob_logic/Source/ApiServer.cpp; CreateNewCaptureSession; 506 ]
Starting capture. LCM: 12000000, Digital:12000000, Analog:6000000, Digital Multiplier:1, Analog Multipler:2, Device Type:4  [ /Users/build/ob_logic/Source/DataFacade.cpp; StartCollection; 260 ]
Received command on port 10429: IS_PROCESSING_COMPLETE  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; SocketReadyReadSlot; 129 ]
Could not understand command  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; SocketReply; 3902 ]
Successfull collection complete with id: 1  [ /Users/build/ob_logic/Source/LogicWindow_Collection.cpp; CollectionCompleteSlot; 427 ]
setting PrimaryDisplay's Session to a valid session, 1  [ /Users/build/ob_logic/Source/PrimaryDisplay.cpp; SetSession; 564 ]
Success  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; SocketReply; 3904 ]
Received command on port 10429: IS_PROCESSING_COMPLETE  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; SocketReadyReadSlot; 129 ]
Success  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; SocketReply; 3904 ]
Received command on port 10429: IS_PROCESSING_COMPLETE  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; SocketReadyReadSlot; 129 ]
Success  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; SocketReply; 3904 ]
Received command on port 10429: IS_PROCESSING_COMPLETE  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; SocketReadyReadSlot; 129 ]
Success  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; SocketReply; 3904 ]
Received command on port 10429: EXPORT_DATA, /Users/lgbeno/Doc  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; SocketReadyReadSlot; 129 ]
Exporting data  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; SocketExportData; 1508 ]
export command error: save directory does not exist  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; SocketExportData; 1559 ]
Could not understand command  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; SocketReply; 3902 ]
Received command on port 10429: IS_PROCESSING_COMPLETE  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; SocketReadyReadSlot; 129 ]
Success  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; SocketReply; 3904 ]
Received command on port 10429: IS_PROCESSING_COMPLETE  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; SocketReadyReadSlot; 129 ]
Success  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; SocketReply; 3904 ]
Received command on port 10429: EXPORT_DATA, /Users/lgbeno/Doc  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; SocketReadyReadSlot; 129 ]
Exporting data  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; SocketExportData; 1508 ]
export command error: save directory does not exist  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; SocketExportData; 1559 ]
Could not understand command  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; SocketReply; 3902 ]
Received command on port 10429: IS_PROCESSING_COMPLETE  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; SocketReadyReadSlot; 129 ]
Success  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; SocketReply; 3904 ]
Received command on port 10429: IS_PROCESSING_COMPLETE  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; SocketReadyReadSlot; 129 ]
Success  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; SocketReply; 3904 ]
Received command on port 10429: EXPORT_DATA, /Users/lgbeno/Doc  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; SocketReadyReadSlot; 129 ]
Exporting data  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; SocketExportData; 1508 ]
Could not understand command  [ /Users/build/ob_logic/Source/LogicWindow_Automation.cpp; SocketReply; 3902 ]

What I am trying to export is digtal only channels 0,1,2

    s.export_data('/Users/lgbeno/Documents/test.csv',[0,1,2])

@Marcus10110
Copy link
Collaborator

Thanks for the log. Unfortunately, it looks like there isn't any more information about the cause of the issue here.

What would really help is a copy of the text string that the python code sent to the Logic application. It looks like the python code is already logging it. Right before the message is sent to the socket, this is called:
log.debug("Send >{}<".format(s))
from the _send function. If you can grab that string from the log file, and tell me exactly which channels you had active in your capture, I can reproduce the issue over here.

Also, from your log, I can see that you captured both digital and analog channels, but only selected digital channels for export. There are special requirements for this, and I think it's one of the edge cases that caused us to write EXPORT_DATA2 to replace EXPORT_DATA, which this python wrapper is currently using.

As soon as I have the log from the python script and which channels were active in the capture, I can figure out what's going wrong.

@analog-io
Copy link
Author

Here's the latest log: https://gist.github.com/analog-io/bd1a52474cd68fddb371

I was not able to grab the log from python but I did step debug the code in pyCharm and extracted this string that was constructed from:

import saleae
s = saleae.Saleae()
s.capture_start()
s.export_data('/Users/lgbeno/Desktop/test.csv',[4,5,6,7])

'EXPORT_DATA, /Users/lgbeno/Desktop/test.csv, digital_channels, 4, 5, 6, 7, all_time, csv, headers, comma, time_stamp, combined, row_per_change, hex'

@ppannuto
Copy link
Owner

For the future, the library uses the standard Python logging facility. Before calling saleae.demo()

import logging, saleae
logging.basicConfig(level=logging.DEBUG)
saleae.demo()

I can also add something to pick up a DEBUG environment variable.

@Marcus10110
Copy link
Collaborator

@analog-io, which analog and digital channels were enabled when the capture was taken? I'll need that to reproduce your capture settings correctly, as that information is not in the software output.

@analog-io
Copy link
Author

Thanks, just those channels were open in Logic.

@LeonardMH
Copy link
Contributor

@Marcus10110 has there been an update on this?

@Marcus10110
Copy link
Collaborator

Sorry for the long delay on this! I did find a bug in the Logic software - the EXPORT_DATA function only checks for the "ROW_PER_CHANGE"/"ROW_PER_SAMPLE" parameter if "SEPARATE" is specified instead of "COMBINED".

Then, also incorrectly, the software still requires the display radix, even if "SEPARATE" is specified.

Basically, the correct behavior is that the display radix parameter (hex/dec/bin/etc) should only be required if "COMBINED" is specified.
However, the conditionals are messed up in the code, and instead what it actually does is the density parameter ("ROW_PER_CHANGE"/"ROW_PER_SAMPLE") is only parsed if the "SEPARATE" parameter is specified, which is of course unrelated.

The good news is that when the density parameter ("ROW_PER_CHANGE"/"ROW_PER_SAMPLE") is not parsed, it uses the previously specified value, so you can set this manually once in the export settings in the GUI, and then it should get preserved. Plus ROW_PER_CHANGE is the default mode in the software.

The command that works:
"EXPORT_DATA, C:\QuickShare\test_py_support.csv, digital_channels, 4, 5, 6, 7, all_time, csv, headers, comma, time_stamp, combined, hex"
(I changed the save path because I'm on windows)

Because we've deprecated the EXPORT_DATA command, I'm not sure if I should fix it in the Saleae software.

The good news is that this is not broken in EXPORT_DATA2, which replaced EXPORT_DATA. Unfortunately, EXPORT_DATA2 hasn't been ported from our C# example application to this Python library, and I won't have the time to take care of this.

The ideal solution would be to update this library to no longer use the EXPORT_DATA function, and use the new one, but unfortunately I don't have the time right now to do that. A short term solution would be to work around this my supporting the bug above.

@analog-io
Copy link
Author

Thanks for the update and looking into this. Really appreciate it and understand theres a million things to do. Knowing this issue I'll either hack my local code to work or attempt to port the C# version to Python and do a pull request. Thanks again!

@LeonardMH
Copy link
Contributor

Yes thanks @Marcus10110 that's very helpful for the EXPORT_DATA command. Hopefully someone will find time to get EXPORT_DATA2 ported soon.

Unfortunately I'm also seeing an NAK error when running the demo(). This doesn't ever call export_data() as far as I can tell.

I'm getting the following failure:

Traceback (most recent call last):
  File "saleae.py", line 640, in <module>
    demo()
  File "saleae.py", line 630, in demo
    while not s.is_processing_complete():
  File "saleae.py", line 417, in is_processing_complete
    resp = self._cmd('IS_PROCESSING_COMPLETE')
  File "saleae.py", line 126, in _cmd
    ret = self._recv()
  File "saleae.py", line 117, in _recv
    raise self.CommandNAKedError
__main__.CommandNAKedError

So it seems there is some problem with "IS_PROCESSING_COMPLETE"?

Additionally, one of my colleagues is getting the error below when calling capture_to_file() which also doesn't call EXPORT_DATA as far as I can tell.

s = saleae.Saleae()
s.capture_to_file("<user_path>\saleae.logicdata")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "build\bdist.win-amd64\egg\saleae\saleae.py", line 411, in capture_to_file
  File "build\bdist.win-amd64\egg\saleae\saleae.py", line 126, in _cmd
  File "build\bdist.win-amd64\egg\saleae\saleae.py", line 117, in _recv
saleae.saleae.CommandNAKedError

Has the API for CAPTURE_TO_FILE changed as well?

@Marcus10110
Copy link
Collaborator

First "IS_PROCESSING_COMPLETE"
I think this is a race condition in the Logic software. Try adding a 100 ms wait after the capture command, before calling IS_PROCESSING_COMPLETE.

Basically, the capture command ACKs right after the capture is complete, but the software is still running some housekeeping to get the capture data to the screen and the UI state updated.
"IS_PROCESSING_COMPLETE" checks the UI state to make sure that the capture tab is active and has data, but this won't happen until a split second after the capture completes.

Alternatively, instead of adding the wait statement, the first NAK exception could just be ignored.

About the second issue "CAPTURE_TO_FILE": does the capture still start in the software? It will NAK if there is a problem with the command, or if a capture error occurred and no data was recorded.

Also, is the <user_path> path mentioned here absolute? It can't start with ~, our software doesn't support that. I really should fix that.

I've gone through the source and added console print statements for the different conditions that cause NAKs in several of the common commands. 1.2.6 comes out this Friday, and when it does, we can check the console output for more information.

@swirhun
Copy link

swirhun commented Jan 13, 2016

cc: @Marcus10110 from Saleae

These race conditions / CommandNAKedErrors are widespread throughout python-saleae and/or the Saleae Logic software.

For example, if I repeatedly run get_active_channels(), I get errors the first several times, and then it happens to succeed on the 4th or 5th try. Here's an example:

>>> sal.get_active_channels()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "<...>/saleae.py", line 368, in get_active_channels
    channels = self._cmd('GET_ACTIVE_CHANNELS')
  File "<...>/saleae.py", line 131, in _cmd
    ret = self._recv()
  File "<...>/saleae.py", line 122, in _recv
    raise self.CommandNAKedError
CommandNAKedError
>>> sal.get_active_channels()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "<...>/saleae.py", line 370, in get_active_channels
    assert msg.pop(0) == 'digital_channels'
AssertionError
>>> sal.get_active_channels()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "<...>/saleae.py", line 370, in get_active_channels
    assert msg.pop(0) == 'digital_channels'
AssertionError
>>> sal.get_active_channels()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "<...>/saleae.py", line 370, in get_active_channels
    assert msg.pop(0) == 'digital_channels'
AssertionError
>>> sal.get_active_channels()
([7], [])

SUDDENLY IT WORKS! Maybe I just got lucky and the race condition didn't occur the 5th time!

I've worked around this in the capture and data-export by replacing occurrences of is_processing_complete() with the following from (#9) @bacaj1

    def wait_for_processing_complete(self, timeout=5):
        """Wraps self.is_processing_complete with more lenient waiting.

        There is some race condition in the Saleae software!

        Args:
            timeout: (int) seconds before timeout
        Raises:
            IOError: if timed out
        """
        tic = time.time()
        time.sleep(0.2)
        done = False
        while not done:
            try:
                # Check for timeout in outer loop
                if time.time() - tic > timeout:
                    self.capture_stop()
                    raise IOError('Saleae timeout = {}sec reached.'.format(timeout))

                while not self.is_processing_complete():
                    # Check for timeout in inner loop
                    if time.time() - tic > timeout:
                        self.capture_stop()
                        raise IOError('Saleae timeout = {}sec reached!'.format(timeout))
                    time.sleep(0.2)
                done = True
            except self.CommandNAKedError:
                # This exception is raised if processing of capture is not complete on the
                # side of the analyzer. This is expected for the first few calls, so we
                # simply ignore it until is_processing_complete returns true
                pass

And for file export, I use 'os' to poll for the output file existing and having the same size in two successive samples, using a similar timeout scheme.

It would be nice if sal.is_processing_complete() actually worked, and someone cleaned up what I'm assuming are race conditions / bugs in the Saleae backend. I contacted Saleae support about the issue and they suggested I cc @Marcus10110 from Saleae on this report.

@swirhun
Copy link

swirhun commented Jan 13, 2016

A similar workaround seems to work for _recv(...):

    def _recv(self, timeout=1):
        tic = time.time()
        done = False
        while not done:
            try:
                if time.time() - tic > timeout:
                    raise IOError('Saleae timeout = {}sec reached.'.format(timeout))

                while 'ACK' not in self._rxbuf:
                    if time.time() - tic > timeout:
                        raise IOError('Saleae timeout = {}sec reached.'.format(timeout))

                    self._rxbuf += self._s.recv(1024).decode('UTF-8')
                    log.debug("Recv >{}<".format(self._rxbuf))
                    if 'NAK' == self._rxbuf[0:3]:
                        self._rxbuf = self._rxbuf[3:]
                        raise self.CommandNAKedError
                ret, self._rxbuf = self._rxbuf.split('ACK', 1)
                done = True
            except self.CommandNAKedError:
                pass
        return ret

@Marcus10110
Copy link
Collaborator

get_active_channels NAKs for 2 reasons:

  1. Logic (original unit) is the active device. This is the only device that does not support any channel configuration changes.
  2. The active channels list contains no elements. We seem to have special case code to handle this case, which would lead me to believe that at some point we had a problem with it. The software is designed to make it impossible to have no channels selected. My guess is that there are intermediate states where this could be the case. I know that the vector is initialized empty, so it's possible that the list is empty after starting the software and waiting for the attached device to initialize.

@manuelgodoy
Copy link

@analog-io Were you able to hack your local code? Do you have any partial solution at least?

@manuelgodoy
Copy link

@Marcus10110 Could you be more specific on how we are supposed to change the parameters in the GUI to make it work? Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants