OK, this post is tied to my original post about my dissatisfaction with the Signal class. The Signal class 'tries' to be helpful by providing what appears to look like a super-class of Pin with the ability to change the sense of the pins status, based on whether the pin is a PULL_UP or PULL_DOWN input pin, or on whether the pin is an output pin active as a source (HI) or as a sink (LOW). Yhe Signal class offers the capability of initializing the underlying Pin class, which I think is quite good.
So I tried using it, under the impression that a Signal class "is a" Pin class. As I tried to use the Signal class, I wanted to incorporate the notion of accessing the irq attribute of the Pin class through the Signal class, but for some reason, the Pin class' irq attribute is not accessible through the Signal class, even though it is accessible via the Pin class.
Then I read Shard's post about Signal not being a subclass of Pin, which it obviously is not. So I set about to make my own Signal class, which would incorporate all the features I wanted, and which seemed to be a rather simple thing to try. And two days later, I have been unable to get what I wanted as a SignalPin class.
My design for a signal class took on the name of SignalPin. The design of SignalPin class was to inherit SignalPin from the stock Pin class. Now I have done class design, including class design with C++ and C#, but I never expected how difficult this was to become.
One of the sticking points that my design has consists of the packing issues around the parameters of the Pin class.
The constructor for the Pin class has the following parameters:
Code: Select all
class machine.Pin(id, mode=- 1, pull=- 1, *, value=None, drive=0, alt=- 1)
From what I can gather, the asterisk in the parameter list indicates a separation between the preceding parameters, which are positional only, and the following parameters, which are keyword only.
I decided that the constructor of the SignalPin class I was designing should be:
Code: Select all
class SignalPin(id, mode = -1, pull = -1, invert = False, value = None)
Note that I dropped the drive and alt parameters, and I dropped the * designator in the parameter list. I only have one parameter in the keyword only parameter list of PinSignal because I don't expect to be using the the other parameters, and I have the expectation that these missing parameters will be handled by their defaults in the Pin class.
So here is my simple case code for testing PinSignal as an input:
Code: Select all
from machine import Pin
import time
class PinSignal(machine.Pin):
def __init__(self, id, mode = -1, pull = -1, invert = False, value = None):
Pin(id)
self.invert = invert
if (value == None):
Pin.init(mode, pull) # line 11 error location
else:
Pin.init(mode, pull, value if ~self.invert else ~value)
def value(self, val):
if (val == None):
if (self.invert):
return ~self.Pin.value()
else:
return self.Pin.value()
elif self.invert:
self.Pin.value(~val)
else:
self.Pin.value(val)
def on(self):
value(self, True)
def off(self):
value(self, False)
g_pin_k1 = PinSignal(id = 15, mode = Pin.IN, pull = Pin.PULL_UP, invert = True, value = None)
while True:
print (g_pin_k1)
time.sleep(1)
My problems right now consist of errors like this:
Code: Select all
Traceback (most recent call last):
File "<stdin>", line 35, in <module>
File "<stdin>", line 11, in __init__
TypeError: argument has wrong type
I have a few confusions.
1. Do the parameter packing hints cause problems between parameter locations in the super class
and the base class?
2. Am I correctly handling the transfer of the Pin parameters from the PinSignal parameters?
3. If I remove the packing information from parameters in the PinSignal class, does this cause
a problem in the Pin subclass?
4. How do I differentiate between call to value(), meaning return the value, and value(True) or
value(False).
5. How complex can it be to do something so seemingly simple?