-
Notifications
You must be signed in to change notification settings - Fork 200
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
applet.interface.i2c_master: add "scan" command #166
Conversation
Should we maybe have a single |
would also be an option. I'm indifferent, both ways are a reasonable interface IMO. |
Let's do that instead. Would you adjust the PR please? |
will do |
b150081
to
a1ab8c3
Compare
|
||
p_scan.add_argument( | ||
"--readwrite", "-rw", action="store_true", default=False, | ||
help="scan read and write addresses") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't the combination of -r
and -w
already work as -rw
with no additional effort? Or does argparse not provide that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, you are right. I didn't give argparse enough credit, it can do it.
Will fix it in the next rev.
self._logger.log(self._level, "I2C scan: found write address %s", | ||
"{:#09b}".format(addr)) | ||
found.append(addr) | ||
return found |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This currently returns the exact same result if the device at addr
can read and if it can write, right? I think this interface is not good enough to be in our public API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This currently returns the exact same result if the device at addr can read and if it can
write, right?
correct.
I think this interface is not good enough to be in our public API.
I actually thought a bit about the interface and this is the one I liked best.
I thought how would one use the scan function. I think the most common use case will
be getting all addresses that answer somehow (read or write) and then iterate over
the result, maybe probing the devices in more detail.
The case were it is relevant to distinguish between read ack and write ack is a valid
use case, but I think it will be used less often. So the interface is easy to use
for the common case and if you want read vs. write, you just call it twice to get separate
lists.
Another idea would be to add methods like scan_read_addr(self, i2c_addr) and scan_write_addr(self, i2c_addr)
which you could use to probe an address in more details when iterating the result list.
The runtime is dominated by the i2c transaction. The scan function in read/write mode
will skip scanning the write addr if it found a read addr, saving time.
Another interface would be to return something like
{
"0x40" : {
"read": True,
"write" : False
},
"0x41" : {
"read": True,
"write" : True
}
}
but I'm not sure it is worth to add that complexity for the not-so-common case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK.
The scan function in read/write mode will skip scanning the write addr if it found a read addr, saving time.
I actually feel like it's interesting to discover both read and write addresses (as printed in the log), in case some peripheral answers to reads but not writes. What about making found
a set()
and changing this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another useful improvement I think would be to restrict scanning to a few addresses. E.g. I know some peripheral can only be at 0b1000000..0b1000111
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what kind of structure do you want to return exactly? The one I posted above under "Another interface would be" or something else?
A simple set will not convey if a device answered read or write.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the current interface (one function) is sufficient.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another useful improvement I think would be to restrict scanning to a few addresses. E.g. I know some peripheral can only be at
0b1000000..0b1000111
.
how about
scan(self, *, read_addrs=True, write_addrs=True, scan_from=0b0001_000, scan_to=0b1111_000)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd do something like scan(self, range=range(0b0001_000, 0b1111_000), *, read=True, write=True)
, personally
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, but I'd use scan(self, address_sequence=range(0b0001_000, 0b1111_000),... then, because the parameter is a sequence that is just filled with a range by default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just addresses
is fine then. "Sequence" means a different thing in Python (what you'd call an array in C, strangely enough), and this is an "iterable".
@@ -233,6 +233,24 @@ def __init__(self, interface, logger): | |||
revision = device_id[2] & 0x7 | |||
return (manufacturer, part_ident, revision) | |||
|
|||
async def scan(self, read_addrs=True, write_addrs=True): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should mark any boolean flags as keyword-only arguments, like async def scan(self, *, read_addrs=True, write_addrs=True):
. (I should add a CONTRIBUTING.md file that explains these things...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right, I wasn't thinking pythonic enough. Will fix that in the next rev.
…mands with "scan" "-r", "-w" and "-rw" allow to select which type of addresses to scan. "-rw" is the default. Some devices only ACK one of the addresses, so scanning both gives a better overview of the bus.
…sterInterface Allows to use it from other applets or the repl interface
a1ab8c3
to
a7a5bf1
Compare
Thanks! |
Do you think side effects are more likely with read scanning than write scanning? |
In case of read scanning you're reading one byte, in case of write scanning you're aborting the transaction after the address, which is why I thought it's more likely. |
I remember reading a datasheet where the interrupt line was reset when reading out the irq register or something like that. That would match your line of thought. |
Let's. |
grmpf. additions to a branch aren't possible in github once it's merged. |
"scan" scans for i2c devices on read and write addresses in one go.
Some devices only ACK one of the addresses, so scanning both gives
a better overview of the bus. With this command you don't need to
do a "scan-read" and then a "scan-write" to get the result.