Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Creating a platform neutral driver #383

Closed
raffaeler opened this issue Apr 23, 2019 · 10 comments
Closed

Creating a platform neutral driver #383

raffaeler opened this issue Apr 23, 2019 · 10 comments
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Device.Gpio Contains types for using general-purpose I/O (GPIO) pins Design Discussion Ongoing discussion about design without consensus enhancement New feature or request Priority:3 Work that is nice to have

Comments

@raffaeler
Copy link
Contributor

Not sure if this is already possible, but here is an idea.
Since the drivers already abstract different implementations of the local hardware peripherals such as Gpio, I2C and SPI, I find very valuable having an in-memory driver that lying below the existing drivers.

The goals for this proposal:

  • ability to mock all the devices for testing purposes without having to use Moq or similar frameworks
  • ability to log the sequence of I/O writes
  • ability to create a framework to replay a sequence to simulate a complete I/O handshake without any connected device
  • ability to run the application on a host which doesn't have any device connected. For example, this is useful to test the other parts of the application on Windows and later run the real one on the embedded board.

While it is possible to create a similar abstraction in the application, it would be less invasive at System.Devices.Gpio level.

Furthermore it would be useful to add this driver as an additional layer so that it would be possible to log all the I/Os for later evaluation.

I would opt for a memory only driver in order to avoid any latency.

@joperezr joperezr added area-System.Device.Gpio Contains types for using general-purpose I/O (GPIO) pins enhancement New feature or request labels Apr 23, 2019
@joperezr joperezr added this to the Future milestone Apr 23, 2019
@joperezr
Copy link
Member

I'm not 100% sure that adding a new layer would be a good idea. Today the layering model goes something like: YourApp -> GpioController.DoSomething -> GpioDriver.DoSomething. Because of that, if we wanted to just add this extra layer for logging pourposes, I would suggest to add those at the GpioController level instead, and I would also be inclined to have them be optional since we don't want to affect perf by logging every I/O operation. For your other proposal (using it as a Moq), we could always add test drivers in this case, that would be possible by adding a testGpioDriver that would get called by the GpioController and can serve to fake I/O interactions. I also may have not understand your proposal correctly, so please correct me if that is the case.

@raffaeler
Copy link
Contributor Author

Thank you @joperezr
I really didn't want to introduce a new layer for every operation. The proposal was to add an optional layer that you may want to plug-in only when desired.

One of the goals is interception that may need to either log or even patch a communication. There are times where the behavior is intermittently wrong. In these cases an intermediate driver can identify the problem better than the application.

The other goal is for testing purposes. All write-only devices can be tested this way and avoid developing a test driver. Reading-only devices would be very easy as well as you may load a sequence and then emulate the I/Os instead of the device. There are times where is not easy to reproduce the device behavior during the tests but you know from the datasheet how it can behave.

In any case I agree that this layer should be optional and plugged in only in specific case to avoid any overhead.

The GpioController level would be good if we wouldn't want the interception. What about adding the interceptor in the controllers constructors? When passing the interceptor it can either short-circuit the request by emulating the hardware peripheral or just log (or modify) it.

@joperezr joperezr added the Design Discussion Ongoing discussion about design without consensus label Apr 23, 2019
@joperezr
Copy link
Member

The GpioController level would be good if we wouldn't want the interception. What about adding the interceptor in the controllers constructors? When passing the interceptor it can either short-circuit the request by emulating the hardware peripheral or just log (or modify) it.

That sounds more interesting. Would you mind writing an API proposal so that we can take a better look at how the shape of this would look like and the use cases? You can update the main comment on this issue with the proposal, and just for reference, here is a good example of how proposals should look like: #135

@joperezr joperezr added the api-suggestion Early API idea and discussion, it is NOT ready for implementation label Apr 23, 2019
@krwq
Copy link
Member

krwq commented Apr 25, 2019

@raffaeler would introducing interfaces per device type (i.e. ITemperatureSensor) make any difference for testing? I.e. if you have a specific device implementing it you could easily plug some intermediate layer to write the same data to a file or intercept a call before passing it to a real sensor

@raffaeler
Copy link
Contributor Author

@krwq it would certainly help in some cases where you simulate the device like you normally do on mobile emulators.
While on temperature it can be pretty easy to abstract a device, I am not sure if you can find the right interface shape when dealing with stepping motors, 9-axis gyroscopes or other more complex devices.

On the other side, when you are putting your hands in the wires, there are many cases where you need to understand why the protocol is faulty. In these cases you typically diagnose the problem by:

  • using an oscilloscope as a logic state analyzer to see if the requests/responses happen. Going deeper you can match what you see on the datasheet to verify the communication graphs.
  • logging the handshake to verify that the code you wrote is correctly reacting to the device.
    In both cases you can either discover a fault in one of the hardware/wire/software areas.

In these cases, logging at a device level assume the underlying protocol is working correctly but if you can go down at controller level you can have a better representation of what's going on. Also, depending whether you are using a hardware or software-emulated perihperal (such as I2C) you can see very different results because of the timing problems.

Assuming to be able to correctly abstract all the device types, I would probably vote to have both abstractions.

@SemaphoreSlim1
Copy link

For the record I'm a big fan of interception/AOP-based architectures, and I don't want to discount the use cases that @raffaeler put forward, but If we're voting here, I vote not to include a interception/plugin layer at the framework level, and here's why:

Adding interception and aspect-oriented extensions is an advanced use-case - one can make the argument that if you're going to go forward and design an application to use it, you're probably familiar with the intricacies of how the happy-path architecture already works, intended instantiation patterns, and the consequences of not wiring things up as intended (please forgive the pun)

If you need to intercept at the lower levels, this can already be done with well established, and well documented frameworks (like fody and cecil), or by using a container and implementing interface interception (like with unity, autofac, and a few other containers), which are again, well documented and well established.

Again, if we're voting here, rather than spend effort on developing a plugin/extensibility layer for IOT, I'd much rather see effort spent on something like @krwq's suggestion, where the framework more closely codes to interfaces, and is more friendly to a factory/dependency injection type model of instantiation so that interception/AOP/memory-only scenarios are possible via established practices if the individual project requires it

@raffaeler
Copy link
Contributor Author

@matthewethomas my proposal is not about AOT interception but just a layer that can be added, as optional, between the app and the GpioController (or the others).
It can be done with interfaces of course, but they would be on a different layer in comparison to the ones proposed by @krwq which are very useful too.
Substantially, they play a different role and solve different use-cases.

I didn't have the time to write the proposal, but I will. I just need some time.

@Ellerbach
Copy link
Member

[Triage] Wed did introduce part of what is asked. Now, a lot of those elements are not part of the short term focus. Leaving this issue open. If anyone wants to make a solid proposal with concrete example or even a PR, that would really help boosting the development.

@raffaeler
Copy link
Contributor Author

Thank you @Ellerbach
I will take a look to the newly added support and see.

@krwq krwq removed this from the Future milestone Dec 15, 2022
@krwq krwq added the Priority:3 Work that is nice to have label Feb 9, 2023
@pgrawehr
Copy link
Contributor

pgrawehr commented Feb 9, 2023

Closing this as a dupe of #1828. The initial proposal there much closer resembles the current architecture and would not add any overhead to the "real" implementation.

@pgrawehr pgrawehr closed this as completed Feb 9, 2023
@ghost ghost locked as resolved and limited conversation to collaborators Mar 12, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Device.Gpio Contains types for using general-purpose I/O (GPIO) pins Design Discussion Ongoing discussion about design without consensus enhancement New feature or request Priority:3 Work that is nice to have
Projects
None yet
Development

No branches or pull requests

6 participants