Skip to main content
Topic: Extend timeouts, or eliminate them altogether? (Read 3521 times) previous topic - next topic

Extend timeouts, or eliminate them altogether?

I was reading in the other threads about the timeout in the PIC firmware waiting for command bytes which might span multiple USB buffers.  I also see that one suggested solution is to extend the timeouts to allow for very slow USB hosts.  My impression is that the firmware grabs bytes from the USB peripheral, but once a command is started, the firmware apparently enters a local, inner loop waiting for the number of bytes necessary to complete the command. The timeout is necessary to exit the inner loop so that the firmware does not lock up waiting for a command which may never be completed.

I'd like to suggest that you could eliminate the timeouts completely, rather than keep extending them.  This would require the following firmware elements:

1) command buffer (separate from the USB buffer)
2) command byte tail index (global variable)
3) command-parsing function

Each time the USB peripheral delivers a packet, the contained bytes should be added one by one to the tail of the command buffer. The command-parsing function would return quickly if a command is missing bytes, and this should be fine so long as the main loop continues appending bytes to the command buffer as they come in over USB. Otherwise, if the command buffer holds all bytes needed for a command, then the command-parsing function would immediately call the subroutine which implements the command, and upon return the command buffer would be cleared by setting the tail index variable to zero.

In other words, you would not need timeouts so long as the command-parsing function always either returns immediately for incomplete commands or calls the command subroutine immediately for whole commands.  There would only be the main outer loop which checks for incoming USB packets (I assume that you're using polled USB, but interrupt-based USB should also work with this algorithm).

Notes: The command-parsing can be very efficient, since the tail index could be quickly checked to see whether a command has all the bytes needed.  One tricky part would be to make sure that the 0x00 reset command clears the command buffer without losing any in-progress commands - I generally handle this by checking for 'reset' before appending to the buffer, and if there is an incoming reset, I will call the command-parsing function to execute any previous command so long as it is not missing bytes (i.e. so long as it is not incomplete). It may seem slow to call the command-parsing function multiple times, but this design makes sure that there are no local loops other than the main global loop. My understanding is that the longest command is 3 bytes (or maybe that's just the USB IR Toy subset of the SUMP command set), making the command buffer quite short. In any event, the command buffer would not have to be much longer than the longest command since the index is reset to 0 between each command. You could even have the command-parsing function return the number of outstanding bytes needed to complete a command, and this number might be used to make things more efficient so that the parsing doesn't have to happen for every byte added.

The one drawback is that you want to make sure that the code does not end up placing any command bytes into the buffer such that the start of the command is anywhere but index 0.  The trickiest thing is that 0x00 can either be a reset or a valid byte within a command.  That's why having the command-parsing function return the "number of outstanding bytes needed" would help.  If the incoming byte is 0x00 and the command buffer has no outstanding bytes needed, then the 0x00 is a 'reset' - otherwise the 0x00 fulfills an outstanding byte for the command in progress.

I hope that my description makes sense.  I've used this sort of design for a PIC-based USB-MIDI device which must accept commands from both the EUSART (MIDI) and USB, and although the EUSART provides only one byte at a time, the USB could easily break up a command due to the USB-MIDI requirement that there always be 4-byte packets.  Also, MIDI System Exclusive defines an EOX message byte, but that is optional, so the firmware cannot depend upon its reception to aid in parsing. I found this design to be very responsive without needing inner loops or timeouts.

P.S. I could not find a copy of the PIC firmware in the sources that I downloaded.

Re: Extend timeouts, or eliminate them altogether?

Reply #1
The PIC firmware just passes bytes, it doesn't care what they are. It has a 64byte buffer if it can't put something immediately in the USB peripheral. It is based on a microchip app-note example. It actually possible to overflow the buffer using MC's algo, I noticed when I was digging for solution to the 'some bitstreams don't work' problem.  I'm going to beef up the protection in the next release for SPI.
Got a question? Please ask in the forum for the fastest answers.

Re: Extend timeouts, or eliminate them altogether?

Reply #2
adding...it's the SUMP client that is sensitive to timeout. The java client uses a very short timeout that was giving problems with the Bus Pirate, and maybe some [s:]SUMP[/s:] OLS users.
Got a question? Please ask in the forum for the fastest answers.

Re: Extend timeouts, or eliminate them altogether?

Reply #3
[quote author="ian"]The PIC firmware just passes bytes, it doesn't care what they are.[/quote]Ah, so the FPGA parses command bytes, not the PIC.

Quote
It has a 64byte buffer if it can't put something immediately in the USB peripheral. It is based on a microchip app-note example. It actually possible to overflow the buffer using MC's algo, I noticed when I was digging for solution to the 'some bitstreams don't work' problem.  I'm going to beef up the protection in the next release for SPI.
I'm actually not surprised that the Microchip sample code is flawed. I made some serious fixes to their USB stack.

Re: Extend timeouts, or eliminate them altogether?

Reply #4
[quote author="ian"]it's the SUMP client that is sensitive to timeout. The java client uses a very short timeout that was giving problems with the Bus Pirate, and maybe some [s:]SUMP[/s:] OLS users.[/quote]This reminds me of another question I had: Would these USB devices function more reliably if they were changed from USB Serial to a Custom Class?  I suppose that would be a significant tradeoff, since having a standard serial driver for USB probably makes the front end easier to maintain in a cross platform manner.  However, if you could force USB to deliver whole commands in single transactions by defining your own class, that would possibly eliminate these timeout issues.

I've only written Mac OS X front ends for USB devices, though, so I may have a false sense of this being 'easy' to manage in user land (i.e. OSX does not require a kernel driver for custom class USB, and regular programs can send and receive raw USB commands easily).

Re: Extend timeouts, or eliminate them altogether?

Reply #5
Yup, the SUMP design in the FPGA has a UART, the PIC is just a USB->serial connection in normal mode. It's handier than an FT232 though because it can program the ROM chip (quickly), and we're in the process of implementing an SPI connection to the FPGA for faster-than-serial downloads.

One of the main benefits of starting with the serial class is so we don;t have to mess around with the Java software to get the project going, and we'll be able to increase the speed just by opening the serial port faster once the SPI connection is available. There's been a lot of discussion about moding SUMP, but it doesn't seem to be for the faint of heart.  Long term it's a great goal, but I have a feeling the Java goodness of SUMP will soon be left behind my most users for the shiny new cross-platform sigrok. Sigrok will be easier to MOD, and easier to add new USB transfer methods to.
Got a question? Please ask in the forum for the fastest answers.

Re: Extend timeouts, or eliminate them altogether?

Reply #6
Sorry, that didn't answer your question:

Quote
Would these USB devices function more reliably if they were changed from USB Serial to a Custom Class?

Sure, but it's much easier to increase the timeout or change how it's handled for the serial port. A new class needs new firmware, Java client, testing, PID, etc.
Got a question? Please ask in the forum for the fastest answers.

Re: Extend timeouts, or eliminate them altogether?

Reply #7
Quote
Would these USB devices function more reliably if they were changed from USB Serial to a Custom Class?
The pros for a custom USB class would be
  • The device has a dedicated VendorID and ProductID so it is easy to identify the OLS when the devices are enumerated. The current USB Serial interface has the little drawback that you can't tell the OLS apart from any other USB2Serial device that is created as a device type modem. For instance on Linux the OLS and my Atmel XPlain development board both create a device file /dev/ttyACM*, so you can't tell them apart unless communication fails because you spoke to the wrong device.
  • Libusb can handle custom class devices on all operating systems so there is no need to write a kernel driver
  • With libusb you have more control about what is going on on the USB-bus, so there is a chance for better error reporting. But an USB2Serial connection does not perform worse or is less reliable compared to a custom USB class device.The problems some of us have are either in the Java-client code or in the firmware/hardware of the OLS board.

but there are cons too
  • For every programming language and every operating system (I know) there is a library that can communicate with a serial port. Libusb is written in C/C++, so  wrappers for the libusb functions would have to be written from scratch. This makes it especially hard to develop a cross plattform application
  • Aquiring a custom VendorID from USB.org costs money. The cheapest offer is to have a dedicated VendorID lisenced to DangerousPrototypes for 2000$. (This sounds like a lot of money at first, but with a thousand items sold it would raise the price by only 2$.)

Eberhard

Re: Extend timeouts, or eliminate them altogether?

Reply #8
Quote
Aquiring a custom VendorID from USB.org costs money. The cheapest offer is to have a dedicated VendorID lisenced to DangerousPrototypes for 2000$. (This sounds like a lot of money at first, but with a thousand items sold it would raise the price by only 2$.)

The OLS has two custom VID/PIDs, sublicensed from Microchip for up to 10K units, after that we have some decisions to make :)
Got a question? Please ask in the forum for the fastest answers.

Re: Extend timeouts, or eliminate them altogether?

Reply #9
[quote author="wayoda"]
Aquiring a custom VendorID from USB.org costs money. The cheapest offer is to have a dedicated VendorID lisenced to DangerousPrototypes for 2000$. (This sounds like a lot of money at first, but with a thousand items sold it would raise the price by only 2$.)
[/quote]

According to this site http://www.dlpdesign.com/usb-prev/vid.shtml,  2k is just to enter the USB-IF forum, then another 1.5k to obtain VID for 2 years. But it seems that you don't need to register, unless you want the "USB Certified" logo. You could just say you are "USB compatible". :)

Re: Extend timeouts, or eliminate them altogether?

Reply #10
I'm pretty deep into the VHDL code that we are talking about here that processes the incoming commands right now. I was just thinking about this last night so it is nice to see a post about it.

It looks like the way its designed is that the uart module looks at every byte that comes in and checks if the top (bit 7) bit is a 0. All "short" commands have a zero in the top bit and are processed immediately. Long commands have a 1 in the top bit and that signals that it should expect 4 more bytes before the command is interpreted. So if at any time a short command, including "0x00" is sent then it should interpret it as a short command. Even if it is in the middle of receiving 4 bytes of data. That's how it looks like it works, but I could be missing something.

Jack.

Re: Extend timeouts, or eliminate them altogether?

Reply #11
[quote author="jack.gassett"]
So if at any time a short command, including "0x00" is sent then it should interpret it as a short command. Even if it is in the middle of receiving 4 bytes of data. That's how it looks like it works, but I could be missing something.
[/quote]
The destinction between a short and a long command (MSB not set vs. MSB set) is ok, but I don't understand the above sentence: Once a long command start byte (MSB is set) has been received, the next 4 bytes are the data for this command. There is no way to detect a short command in these 4 bytes.
I'm refereing to this page http://www.sump.org/projects/analyzer/protocol/ 
For instance the "Set Trigger Values (C1h, C5h, C9h, CDh)" command can have any kind of data in the next 4 bytes. There is now way to tell a Trigger argument value apart from a short command.

Eberhard

Re: Extend timeouts, or eliminate them altogether?

Reply #12
Eberhard, that's correct. That's why you should send the reset command (00h) 5 times:

Quote
quoted from SUMP Communication protocol:
Reset (00h)

Resets the device. Should be sent 5 times when the receiver status is unknown. (It could be waiting for up to four bytes of pending long command data.)

Jack has found the cause for the "intermittent communication problems" and it will be fixed soon - the timeout should be no issue after the UART interface of the SUMP engine has been fixed. Tweaking the timeout will not help with boards/FPGA chips affected, only a fix in the VHDL code and a new bitstream will solve the communication problem for boards/FPGA chips affected.

Re: Extend timeouts, or eliminate them altogether?

Reply #13
That's [glow=red,2,300]brilliant[/glow] news, and it will be interesting to hear exactly what the problem is

Re: Extend timeouts, or eliminate them altogether?

Reply #14
If Jack is right, then the problem is that the VHDL code does not use any kind of state machine.  When he says that it appears to look at every byte from the UART, it implies to me that the VHDL code will treat a 0x00 in the data exactly as if it were a 0x00 command - or any byte between 0x00 and 0x7F for that matter.

In other words, the VHDL needs to have a least two states (1 bit) so that it can switch between command mode and data mode. In data mode, any value of bit 7 should be allowed, but in command mode bit 7 will select between "short" 1-byte commands and "long" 5-byte commands.

What will really be interesting is the fix!