USB is simple! Ha ha. This is what is commonly said once you figure something out and finally understand it. Many things are simple once you are "on the inside" -- this is a sort of "trap door function".
It is important to remember that our goal is learning; learning by doing. I do intend to use the final product, but arriving at a usable final product is more of a test of real learning than our goal.
We have only tackled the device side of USB. The host side has other complexities, more jargon (channels instead of endpoints). A host has to deal with multiple devices, hubs, and lots of other things. We also have been dealing only with USB 2.0 and "full speed", which keeps things simple.
Much like networking, USB has device specific issues and protocol issues. The main "protocol issue" for us is enumeration, which is its own microcosm. If we ignore the details of enumeration, it is just sending and receiving on endpoint zero.
If you ignore all the details, sending and receiving are pretty simple. You have several "endpoints", which are like mail baskets with numbers. To receive, you just set up a mail basket, flag it as ready (valid) and wait to be notified that something has shown up. To send, you again set up a mail basket, put something in it then flag that it is full (valid) and wait to be notified that the contents have been correctly sent.
All the detail about traffic on the USB cable can be ignored. It just works like magic. Not that those details aren't important and interesting, but they can be ignored and it can be trusted that they "just work".
Tom's Computer Info / tom@mmto.org