I'm writing this discussion to bring to light a bug in the printer class example code in the Kinetis SDK. Specifically in the demo app that is provided. The example is called "usb_device_printer_virtual_plain_text".
In "device_printer.c" in the "USB_DevicePrinterAppTask" function, it schedules a USB printer receive and then sets the state flag. The way it does this is not atomic and causes issues when sending print jobs.
Once the USB receive has been scheduled, USB interrupts are free to run. If it receives data before it sets the "printerState", the "USB_DevicePrinterAppCallback" does not handle this because the printerState is not "kPrinter_Receiving" yet.
If the printerState is not "kPrinter_Receiving", the printerState never changes to "kPrinter_Received" and therefore the data is ignored and missed and now the state machine is locked up and stuck in the "kPrinter_Receiving" state. It's locked up because the receive event already happened before the state changed to "kPrinter_Receiving".
The solution is to make the USB receive schedule fully atomic like so:
This way a USB receive can only happen AFTER the printerState is set.
This was a bug we have seen in our code for some time now and finally figured out what it was. This happens quite a bit if you send lots of print jobs. It may take a few 100 to a few 1000 print jobs to see it lock up, but it will happen. It seems to be more prominent when the received data is processed to introduce some delay. But either way it is a clear hole in the state machine.
On the Windows PC side, the print queue will be stuck and won't continue.
I think the state machine in the example app could use some clean up in the next SDK release.