It is always a hassle to communicate with embedded device. I do manage one time solution e.g. through USB to UART converter but it is always too much interleaved with application code to later switch to integrated USB peripheral.
Sometimes in the past I got requests to provide new or additional way of communication for device. Another use case I wrote this library for is when I found myself repeating writing same code. I had point to point serial communication implemented on some project. On another project I used serial bus approach (with CAN physical drivers - not important) and the communication was identical with addition of the byte header for destination address at the beginning of each packet. Repetition also happened on client and host side.
In short, Comm library offers a way to make communication entities modular thus easily replaceable. It also makes them stackable to make the whole through communication extending easy. First library implementation is in C [Google Code repository].
Communication is meant to be of query - response from master (client) to slave (host). The use of library enforces a way of transmission and reception but the same design can be used on both sides of communication channel. This means that layer can have same implementation on client and host side if both running on the same hardware platform.
From library point of view the communication entity is self sufficient communication layer implementing a set of predefined functions i.e. implementing an interface. As it turned out layers are of two types. In one stack there are more data formatting layers and single physical layer.
Physical layers are in charge of data storage and thus having communication buffer. Example of a layer on top of physical would be an encryption layer. Application interacts with Comm library functions when transferring data. Library then calls Comm layer implementation as needed. All functions have C++ style “this” pointer parameter. In the application accessible library functions this is a predefined Comm stack type holding a pointer to array of another predefined type instances each describing single Comm layer implementation. Comm layer instance is used as the "this" pointer in layer implementation functions and in library functions used for data transfer between layers. Comm layer instance has 5 pointers:
- vague void pointer member to store reference to a custom type object for specific implementation
- pointer to predefined type object holding function pointers of layer implementation
- pointers to upper and lower layer if any
- pointer to Comm stack to which layer belongs.
Instance custom pointer and pointer to functions are initialized in extra initialization function call which is custom for each specific layer implementation and additionally exposed to the application together with a custom instance type. This initialization function is not to be mistaken with layer implementation initialization function.
Pointers to surrounding layers and pointer to parent stack are initialized in library initialization call which should result in established connection after return.
Or everything again in objective language words: main communication stack object has methods for communication and holds references to layer objects each implementing the defined interface and custom init method which is only method called by application directly.
Below is a general sequence and internal states of the objects after each initialization step:
|After first layer custom initialization call.|
|After last layer custom initialization call.|
|After Comm library initialization call.|
|Multiple calls to send data on client and host.|
|Multiple calls while transmitting data on client and host.|
|Repeatedly called on client while expecting a response from host; repeatedly called on host while waiting for new packet. OnPacketEnd behaves identically.|
|Repeatedly called on client while expecting a response from host; repeatedly called on host while waiting for new packet.|
For test implementation I did a pair of embedded STM32F4 project and Windows client application communicating over USB. Windows side uses WinUSB library for communication and firmware reports a OS USB descriptor associating device with WinUSB driver so drivers or .inf files are not needed. Firmware code is in C and Windows client application uses C++ in Windows only code.