Sure but my original idea I was getting at was to split Pin as direct IO from Pin as a resource for a peripheral. Doesn't it make sense to split the class that does raw IO to a pin from the object that other's use as a reference? Whether there is a single DigitalIO or one for in and one for out matters less to me.deshipu wrote:@tannewt Actually, after a moment of thought, you already have your DigitalIO objects in the current machine API -- they are called Pin.
RFC: Hardware API: finalising machine.Pin
Re: RFC: Hardware API: finalising machine.Pin
Re: RFC: Hardware API: finalising machine.Pin
Sorry, I don't agree - majority of things were well enough though out, and there're only few things which are worth revisiting.deshipu wrote:I like how you have here answered your own question about why we need to revisit the hardware api spec.pfalcon wrote: So, how do we want to deal with it? The current answer is "oops, we didn't think about it!"
So MicroPython has always been about being able to write portable apps, i.e. portability of user apps among devices it runs on. Hardware API has the same goal. And without supporting inverted signals it's more or less hard, definitely not elegant. So, consider that we want to write an application which will light an LED for 0.1s, and then turn off for 0.9. The main, portable application would look like:I have never really had a problem that would require me to use a pin with an inverted signal. A simple "not" usually solved any issues. So I don't feel like there is enough information gathered to make a decision about this at the moment.
Code: Select all
import time
import app_config
while true:
LED.value(1)
time.sleep_ms(100)
LED.value(0)
time.sleep_ms(900)
For one board, it would look like:
Code: Select all
from machine import Pin
LED = Pin("LED0", Pin.OUT)
Code: Select all
import machine
from machine import Pin
LED = Pin((machine.PORT_Z, 5), Pin.OUT)
Code: Select all
LED = Pin((machine.PORT_Z, 5), Pin.OUT, inverted=True)
Code: Select all
LED = Signal(Pin((machine.PORT_Z, 5), Pin.OUT), inverted=True)
Also some other points:
- I'm +0 on this idea, because accepting it will kill my loved idea of "close to hardware" Pins. So, I hope there will be enough other votes. But if there won't be enough, some time later I'll likely regret that I didn't +1 it.
- I strongly dislike idea of merging "unrelated" functionality into one entity. My proposal above is an exceptional case, driven by the idea of making MicroPython friendly to users and not fall behind the competition. (To illustrate my dislike for merging "unrelated" things, I'll be minus something on the idea of turning I2C.start() into I2C.start(addr, rw)).
Awesome MicroPython list
Pycopy - A better MicroPython https://github.com/pfalcon/micropython
MicroPython standard library for all ports and forks - https://github.com/pfalcon/micropython-lib
More up to date docs - http://pycopy.readthedocs.io/
Pycopy - A better MicroPython https://github.com/pfalcon/micropython
MicroPython standard library for all ports and forks - https://github.com/pfalcon/micropython-lib
More up to date docs - http://pycopy.readthedocs.io/
Re: RFC: Hardware API: finalising machine.Pin
I think we have a completely different approach to working on requirements for the API. For me it's "obvious" that the way to go about it is to write some code for a real use case, or take existing code for real use cases, analyze it, and see what is missing or could be improved. I like it, because it leads to clean and readable code in practice without too much overhead for "purity" sake. The down side is that you first need to collect the data for real use cases, so you can't do that with the initial design -- and that it inevitably leads to changing the design once you have the data. Like those pesky scientists without any backbone, who change their mind as soon as they see new data.
Your approach, of first setting some design rules, and then growing the API according to those rules by covering all the possible use cases that you can imagine is much more comfortable, because it doesn't require any real world data. It results in a pure and consistent API, and once you learn the rules used, you can easily guess any part of the API that you don't know yet. However, it depends heavily on setting just the right design rules at the start, and on imagining just the right use cases later. Even a very small error can (and will) lead to API that is either bloated or not useful. The solution to it is to have the rules set by a single very experienced person who will take all responsibility.
This is a fundamental difference in the approach, and I doubt we can reconcile it. As you can probably tell from the biased descriptions above, I prefer the first one, even though it is more work and more burden for the community. I have seen it used it the Python community many times, however, and I like the results. (Although there are also some pretty bad examples out there too.)
I'm not sure the two points of view can be easily reconciled, but I will certainly try.
As for your use case for inverted signals, I find it artificial for two reasons -- but this may be just because I have never actually stumbled upon this particular problem. The first reason is, for a LED that is built-in into the board itself, you would probably have a driver, similar to what pyb has for the LEDs and buttons and accelerometer, separate from the machine API, and the inversion would be handled there. Yes, there would be an additional object, but how many LEDs can a board have? In addition, this allows you support boards that have an RGB LED, or boards that have PWM available on their LEDs, in a transparent manner. Second, if you connect a lot of LEDs to the board externally (for instance, as a LED-based display similar to the micro:bit), you will want to create an object for handling them anyways -- not 40 objects for each of the LEDs separately, but a single "Display" object. That object can easily handle inverting the signal if you need that in some setups. I now remember, that I actually had this problem before, and this is exactly the solution I used -- but not for LEDs and ON/OFF signal, but instead for hobby servos and PWM signal.
Your approach, of first setting some design rules, and then growing the API according to those rules by covering all the possible use cases that you can imagine is much more comfortable, because it doesn't require any real world data. It results in a pure and consistent API, and once you learn the rules used, you can easily guess any part of the API that you don't know yet. However, it depends heavily on setting just the right design rules at the start, and on imagining just the right use cases later. Even a very small error can (and will) lead to API that is either bloated or not useful. The solution to it is to have the rules set by a single very experienced person who will take all responsibility.
This is a fundamental difference in the approach, and I doubt we can reconcile it. As you can probably tell from the biased descriptions above, I prefer the first one, even though it is more work and more burden for the community. I have seen it used it the Python community many times, however, and I like the results. (Although there are also some pretty bad examples out there too.)
I'm not sure the two points of view can be easily reconciled, but I will certainly try.
As for your use case for inverted signals, I find it artificial for two reasons -- but this may be just because I have never actually stumbled upon this particular problem. The first reason is, for a LED that is built-in into the board itself, you would probably have a driver, similar to what pyb has for the LEDs and buttons and accelerometer, separate from the machine API, and the inversion would be handled there. Yes, there would be an additional object, but how many LEDs can a board have? In addition, this allows you support boards that have an RGB LED, or boards that have PWM available on their LEDs, in a transparent manner. Second, if you connect a lot of LEDs to the board externally (for instance, as a LED-based display similar to the micro:bit), you will want to create an object for handling them anyways -- not 40 objects for each of the LEDs separately, but a single "Display" object. That object can easily handle inverting the signal if you need that in some setups. I now remember, that I actually had this problem before, and this is exactly the solution I used -- but not for LEDs and ON/OFF signal, but instead for hobby servos and PWM signal.
-
- Posts: 288
- Joined: Sun May 04, 2014 8:54 am
Re: RFC: Hardware API: finalising machine.Pin
Trying to conclude on inverting Pins:
@deshipu: -1
@pfalcon: +0
@marfis: -1
@chrismas9: -1
Pro: you can simply invert a Pin when porting from one board to another where i.e. a LED is pulled up or down
Con: it's not actually a function that the Hardware has
Way I see it: machine implements the Hardware. On top of that, i.e. the LED module can provide the 'inverted' flag.
On the other hand, it literally costs us nothing and would in some cases obliterate the need for a i.e. LED module, because you'd only need what's already implemented in Pin.
I'd say when in doubt, stick to machine = Hardware, if the discussed functionality can be delivered by a Python module.
@deshipu: -1
@pfalcon: +0
@marfis: -1
@chrismas9: -1
Pro: you can simply invert a Pin when porting from one board to another where i.e. a LED is pulled up or down
Con: it's not actually a function that the Hardware has
Way I see it: machine implements the Hardware. On top of that, i.e. the LED module can provide the 'inverted' flag.
On the other hand, it literally costs us nothing and would in some cases obliterate the need for a i.e. LED module, because you'd only need what's already implemented in Pin.
I'd say when in doubt, stick to machine = Hardware, if the discussed functionality can be delivered by a Python module.
Re: RFC: Hardware API: finalising machine.Pin
@deshipu, you're hard to communicate with. When there's an abstract choice in discussion, and one choice is obviously productive, and another obviously unproductive (such obvious that a productively oriented person wouldn't even considered the latter), you select the unproductive (you did it twice today on github). Here, the moment I posted a real example, you started to talk about need to consider real examples. The real example has been posted, please consider it.deshipu wrote:I think we have a completely different approach to working on requirements for the API. For me it's "obvious" that the way to go about it is to write some code for a real use case, or take existing code for real use cases, analyze it, and see what is missing or could be improved.
That's no how design works. It starts with initial requirements, then specification based on that requirements, implementation, then adjustments based on that implements, then many more implementations and further adjustments. You talk about the same things, but I'm not sure you pay enough attention to ordering and meaning of the different stages. For example, initial requirements are hard requirements, serving as Occam's razor for this project, and adjustments are adjustment, not "everything is wrong, let's do everything differently", and "many more implementations" is non-similar, widely spaced implementations, not just "8 ports". Practical testing is very important part of it, and your detailed feedback is much appreciated (I especially appreciate detailed write-up, beyond just "many things feel wrong". To bad I didn't have a chance to review and reply to them before this thread popped up). But please don't underestimate need for stick to the requirements and proper ordering and scoping of the project.Your approach, of first setting some design rules, and then growing the API according to those rules by covering all the possible use cases that you can imagine is much more comfortable, because it doesn't require any real world data. It results in a pure and consistent API, and once you learn the rules used, you can easily guess any part of the API that you don't know yet. However, it depends heavily on setting just the right design rules at the start, and on imagining just the right use cases later. Even a very small error can (and will) lead to API that is either bloated or not useful. The solution to it is to have the rules set by a single very experienced person who will take all responsibility.
If so, you may volunteer to write Hardware API for unix port, to serve as a usual foundation for further development of MicroPython and testing.As you can probably tell from the biased descriptions above, I prefer the first one, even though it is more work and more burden for the community.
That's really great, because "theoretical" and "practical" approaches should go hand in hand and intertwine, not be opposed to each other.I'm not sure the two points of view can be easily reconciled, but I will certainly try.
MicroPython (and its apps) being portable across boards is the hard initial requirement. (With a usual disclaimer that if BDFL suddenly denounce it, I'll find myself in the "oops" position of "what project did I work on for last 3 years?")As for your use case for inverted signals, I find it artificial for two reasons -- but this may be just because I have never actually stumbled upon this particular problem.
No, no drivers. MicroPython mandates only machine API, and who want to write drivers anyway? Where are you people, why you still haven't written *mandatory* machine API for unix port? Where're drivers for LEDs of my TV, fridge, and washing machine?The first reason is, for a LED that is built-in into the board itself, you would probably have a driver, similar to what pyb has for the LEDs and buttons and accelerometer, separate from the machine API, and the inversion would be handled there.
Sorry, but this argument can be reduced to "no matter what hardware API is there, users will be able to what they need - indeed, they simple will have no choice than to hack and mock something". That's indeed true, but the whole talk about Hardware API is how to give as much as possible cleanliness and power into users hands with the minimal size of this API and maximal portability across hardware. If you write that you have faced that issue, then you understand it. And good API allows to do simple things in a simple way, while still allow complex things, and extensibility, to allow to add even more complex and or more convenience on top of it. The above presented is the usecase which can be simple if inversion is supported on Pin level, and no longer simple if a user needs to deal with it (consider if user is a kid or novice; or purist, yeah; or pragmatic, who knows that elsewhere this issue resolved without his need to for him to keep it in mind each time he does something with a Pin).Yes, there would be an additional object, but how many LEDs can a board have? In addition, this allows you support boards that have an RGB LED, or boards that have PWM available on their LEDs, in a transparent manner. Second ...
Awesome MicroPython list
Pycopy - A better MicroPython https://github.com/pfalcon/micropython
MicroPython standard library for all ports and forks - https://github.com/pfalcon/micropython-lib
More up to date docs - http://pycopy.readthedocs.io/
Pycopy - A better MicroPython https://github.com/pfalcon/micropython
MicroPython standard library for all ports and forks - https://github.com/pfalcon/micropython-lib
More up to date docs - http://pycopy.readthedocs.io/
-
- Posts: 288
- Joined: Sun May 04, 2014 8:54 am
Re: RFC: Hardware API: finalising machine.Pin
Three pages of discussion for one simple flag - API design is _hard_
Re: RFC: Hardware API: finalising machine.Pin
Are you trying to define a HW API for a chip or a board?
If the former (which is better for portability) then there should be no assumptions made about what individual pins are connected to. Chips don't have LEDs or buttons.
If the latter (which arguably makes things simpler for a limited set of use cases) then you shouldn't be too concerned about portability: applications that assume specific peripherals are present and talk to them directly aren't portable anyway.
"Code" may be portable so long as it doesn't touch hardware, but whole applications are unlikely to be. How many ESP8622 apps run on a pyboard? My guess would be next to none because if it was implemented on an ESP8622 it probably has a hard dependency on networking.
If the former (which is better for portability) then there should be no assumptions made about what individual pins are connected to. Chips don't have LEDs or buttons.
If the latter (which arguably makes things simpler for a limited set of use cases) then you shouldn't be too concerned about portability: applications that assume specific peripherals are present and talk to them directly aren't portable anyway.
"Code" may be portable so long as it doesn't touch hardware, but whole applications are unlikely to be. How many ESP8622 apps run on a pyboard? My guess would be next to none because if it was implemented on an ESP8622 it probably has a hard dependency on networking.
-
- Posts: 288
- Joined: Sun May 04, 2014 8:54 am
Re: RFC: Hardware API: finalising machine.Pin
Don't think about apps, think about drivers. When I implement a module for i.e. a sensor I want that to be usable to people across all ports.How many ESP8622 apps run on a pyboard? My guess would be next to none because if it was implemented on an ESP8622 it probably has a hard dependency on networking.
I think the consensus is that 'machine' is the microcontrollers API.
Re: RFC: Hardware API: finalising machine.Pin
Here is a very practical reason for the signal inversion not being put on the pin objects: pin objects are singletons. That pretty much makes their state global. If you put anything application-specific in there, you will get conflicts between two parts of your code using a shared resource.
Consider the following (a bit artificial, but simple) example. You have a LED on an ESP8266 board on pin gpio2, which is active low. You decide to wrap your whole program in a try-except cause that upon error sets the pin low to make the LED shine and signal a problem. So far so good. Next, you use in you program a library for, say, transmitting files. That library is written in a portable way, and as one of the configuration parameters it takes a pin for a LED on which it will indicate activity -- but it expects it to be active high. No problem, you just invert the pin's signal and pass it to the library like that. Your error handler just stopped working.
Consider the following (a bit artificial, but simple) example. You have a LED on an ESP8266 board on pin gpio2, which is active low. You decide to wrap your whole program in a try-except cause that upon error sets the pin low to make the LED shine and signal a problem. So far so good. Next, you use in you program a library for, say, transmitting files. That library is written in a portable way, and as one of the configuration parameters it takes a pin for a LED on which it will indicate activity -- but it expects it to be active high. No problem, you just invert the pin's signal and pass it to the library like that. Your error handler just stopped working.
Re: RFC: Hardware API: finalising machine.Pin
I was referring to this:Turbinenreiter wrote: Don't think about apps, think about drivers. When I implement a module for i.e. a sensor I want that to be usable to people across all ports.
I think the consensus is that 'machine' is the microcontrollers API.
"MicroPython (and its apps) being portable across boards is the hard initial requirement."
...comment earlier in the thread.
machine from the WiPy docs is pretty close to a chip API, but pyb is clearly a board API and bundles in things (the LCD) that aren't even part of the board. I was attempting to clarify which model was being pursued here.