Getting 1MB of ASCII Cognex image with Java sockets and TCP ZeroWindow issue

Looking for some advice in trying to get 1MB of ASCII using Java sockets and display with Paintable Canvas.

Scenario: Cognex cameras support Native Mode communication which is a telnet-like interface where you can login and send commands and receive data back. You can request the most recent acquired image by sending “RI” and the camera will send back a bitmap BMP image in ASCII hexadecimal format with 80 characters per line followed by a terminator which appears to be CR/LF (see below trimmed output). Image size is 939KB and has 12027 lines of ASCII hex in our case.

RI

RI_end

We initially accomplished this with python telnetlib but it was very slow (5+ seconds). @pturmel has posted many times about issues and performance with python sockets so I thought I would try his suggestion to use Java sockets. But I’m not a developer so it took a few days to get anywhere but here’s what I came up with:

from java.net import Socket
from java.io import PrintWriter,InputStreamReader,BufferedReader

strMessage1 = ("admin" + '\r\n')  
strMessage2 = ("password" + '\r\n')
strMessage3 = ("PUT XML 1" + '\r\n')
strMessage4 = ("RI" + '\r\n')

strOut = strMessage1+strMessage2+strMessage3+strMessage4

deviceIP="1.1.1.1"
port=23
 
try:
  # Open Socket Connection
  clientSocket=Socket(deviceIP,port)
  clientSocket.setSoTimeout(5000)
  #Open data output stream
  outToDevice=PrintWriter(clientSocket.getOutputStream())
  #Open data input stream
  inFromDevice=BufferedReader(InputStreamReader(clientSocket.getInputStream()))
  #Send Data to Device
  outToDevice.write(strOut + '\r\n')
  outToDevice.flush()
  #Receive Data from Device
  line = inFromDevice.readLine()
  while line != "</Data>":
  	print line
  	line = inFromDevice.readLine()

  #close data stream and socket
  outToDevice.close();
  inFromDevice.close();
  clientSocket.close();

except IOError:
  print "Error Connecting"

This works for small amounts of data and issuing other Cognex Native Mode commands and it’s lightning fast. But I’m having an issue trying to read all 12027 lines. The code above reads about 1837 lines and hangs up in the Designer Script Console.

I verified with Wireshark and everything seems ok until a TCP ZeroWindow packet shows up. Presumably because the Designer Script Console can’t handle the stream and gets overloaded. And maybe the Designer Script Console isn’t the best place to test this but decided to post this to see if anyone had any advice working when working with large input character streams over java sockets.

I do realize that Cognex cameras can FTP images and we can use that method to read file byte streams and display with paintable canvas. We need these pictures displayed very quickly and the FTP process is too slow for our application. Also note that when using Putty with a RAW socket on port 23, I can receive the entire image ASCII hex string in less than 200 milliseconds.

Can you share the capture for reference?

Drop the print statement while you’re rolling. The Designer’s output console is not good at buffering large amounts of text; it’s a big bottleneck.

1 Like

Some notes:

  • Create the socket with just Socket(). Then set your socket options. Then use .connect(ip,port) to make the connection. I recommend including .tcpNoDelay = True.
  • Don’t mash together the pseudo-interactive responses. Handle them separately.
  • Don’t read lines. Read gobs of bytes forecast using the InputStream’s .available() method. Stuff them into a ByteArrayOutputStream for later parsing.
  • While reading the imput stream, compare the last several bytes against a byte array with the expected tail, to know when to switch from capturing bytes to parsing them. Possibly with a timeout.
  • Once you have a response as XML bytes, push it through a SAX parser that will pluck Status, Data, and CRC for you. The handler for the Data can convert the hex to bytes and push into another BAOS.
  • Once you have the image bytes, just feed them to ImageIO. It will notice that it is a bitmap and handle it for you.

If you are feeling ambitious, after implementing the sax parser, you could implement an InputStream filter that looks for a prompt/delimiter to end the stream, passing through until that point. Then you could feed the socket’s input stream to the filter and to the sax parser on the fly (rather efficient).

1 Like

Maybe I just need to add Cognex to my Image Streamer driver. This is exactly what I currently do with Keyence vision systems.

2 Likes

Dropped the print statement and added a timer and it completed in 4.9 milliseconds in Script Console!

1 Like

Converted to bytes and passed to ImageIO for the paintable canvas and it displays almost immediately!

@pturmel - I will re-read your suggestions a million times and start researching. I think I understand at a high level what you’re suggesting but just not sure my experience with programming will get me there in a reasonable amount of time. Since we’re seeing this repaint a 939KB image in 5 milliseconds I’m not too concerned with performance. But I will definitely look at adding some checks during the interactive process. I got lucky with mashing it up but I understand TCP and the camera CPU may not always be that predictable. And as always–we would definitely be interested in your Image Streamer Driver if you added support for Cognex.

Thanks again

Psst! I need hardware or a sponsor…