Skip to content

Check for duplicate pins in rows and columns #5123

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

Merged
merged 5 commits into from
Aug 20, 2021

Conversation

gamblor21
Copy link
Member

@gamblor21 gamblor21 commented Aug 10, 2021

Closes: #5034

KeyMatrix will check all the pins used for any duplicate against the rows and columns.

jepler
jepler previously approved these changes Aug 11, 2021
Copy link

@jepler jepler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like very plausible code. Didn't test.

Copy link
Collaborator

@dhalbert dhalbert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have looked at the best way to fix this bug, and even started to code it a bit, but only very briefly. It was more complicated than I liked.

It could be done by using a Python set in shared-bindings, adding all the pins to the set, and making sure the set length is correct. Or it might be done in the shared-module implementation, but it's really something that should be done as arg validation in shared-bindings.

Right now the pin-claiming logic checks some actual hardware state, so you can't see if the pin is claimed until you go to allocate it.

All the keypad classes should check for duplicate pins in the pin lists, not just KeyMatrix, so you might want to write a general duplicate object or duplicate pin checker which can be used in other cases as well. But KeyMatrix is special because it has two lists of pins, not just one.

@gamblor21
Copy link
Member Author

I was looking at this more tonight after the discussions on discord. I did implement a argcheck.c methods mp_arg_validate_no_duplicates. This checked one array for any duplicates, returning an error if so.

For test purposes I made a mp_arg_validate_no_duplicates2 which checked two arrays against each other. I think modified KeyMatrix.c to run these checks against rows, columns and then the second function for rows+columns. It works.

A couple of thoughts:

  • I haven't checked this to validate the objects are subscriptable (or if it is required) just did this to test
  • This seems like the simplest way to due a duplicate item check and reusable in the future if it is required again
  • This does not depend on any hardware pin checking/setting so it keeps the validation of arguments in shared-bindings

Let me know the thoughts. I can also try to be there on Monday and discuss this more during in the weeds, have to check if I am free at that time.

Code for mp_arg_validate_no_duplicates:

mp_obj_t mp_arg_validate_no_duplicates(mp_obj_t obj, qstr arg_name) {
    const size_t num_objects = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(obj));

    for (size_t object_cnt = 0; object_cnt < num_objects; object_cnt++) {
        mp_obj_t obj1 = mp_obj_subscr(obj, MP_OBJ_NEW_SMALL_INT(object_cnt), MP_OBJ_SENTINEL);

        for (size_t object_cnt_2 = object_cnt+1; object_cnt_2 < num_objects; object_cnt_2++) {
            mp_obj_t obj2 = mp_obj_subscr(obj, MP_OBJ_NEW_SMALL_INT(object_cnt_2), MP_OBJ_SENTINEL);
            if (obj1 == obj2)
                mp_raise_TypeError_varg(translate("%q contains duplicate objects"), arg_name);
        }
    }

    return obj;
}

@dhalbert
Copy link
Collaborator

I found a use for non-pin duplicate checking: in usb_hid the Device constructor will be passed a list of int report_ids which must not be duplicates. This is a pretty minor piece of validation to do, because there are other things that aren't validated, such as the whole HID report descriptor that is passed in. But it is another use for dupe checking.

@gamblor21
Copy link
Member Author

The build failed for one board on one translation, running out of space. Any thoughts on what to do here?

jepler
jepler previously approved these changes Aug 18, 2021
Copy link

@jepler jepler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks perfectly straightforward. No testing done.

@gamblor21 gamblor21 requested a review from dhalbert August 18, 2021 21:11
@jepler jepler mentioned this pull request Aug 19, 2021
mp_obj_t pin2_obj = mp_obj_subscr(seq2, MP_OBJ_NEW_SMALL_INT(pin_cnt_2), MP_OBJ_SENTINEL);
mcu_pin_obj_t *pin2 = validate_obj_is_pin(pin2_obj);
if (pin1 == pin2) {
mp_raise_TypeError_varg(translate("%q and %q contain duplicate objects"), arg_name1, arg_name2);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this only checks pins, we can say "pins" instead of "objects"

Suggested change
mp_raise_TypeError_varg(translate("%q and %q contain duplicate objects"), arg_name1, arg_name2);
mp_raise_TypeError_varg(translate("%q and %q contain duplicate pins"), arg_name1, arg_name2);

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, missed it the second time.

Copy link
Collaborator

@dhalbert dhalbert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, great, thanks for all the discussion and your patience with this!

@gamblor21 gamblor21 merged commit f9f106b into adafruit:main Aug 20, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Invalid row+column pins should be rejected
3 participants