(..) contains more complexity and formality than I'm used to...
The library we are talking about is made so that for bidirectional communication you only provide three parts:
1. Descriptors (const arrays of some 0xnumbers)
2. Function that is called by USB IRQ when some data was received via USB endpoint (OUT)
3. Function that is called by USB IRQ when some data was sent via USB endpoint (IN)
Descriptors say how much current STM32F103 draws, how many endpoints it has, the USB class, endpoints directions, speed etc.
As for functions, for bidirectional endpoint #1:
void EP1_OUT_Callback(void)
{
//your code for receiving comes here
}
void EP1_IN_Callback(void)
{
//your code for sending comes here
}
Not very sophisticated. Once the code does the job (reads or writes to USB shared memory, respectively) you have to flip a designated register bit to tell USB hardware that now it can take care of that shared memory (overwrite it with new incoming data or push the content to the host, respectively).
Not sure about details but I think STM32F103 does up to 8 endpoints, all of them are independent, have their own memories, flip bits, etc.
Interesting feature for these uCs is that they have a configurable IRQ that triggers on several USB errors. For example framing or some bit stuffing anomalities etc. That is how I found out that my clock tree used an internal RC instead of the quartz
