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

keypad.ShiftRegisterKeys has wrong key_count #9718

Closed
aseanwatson opened this issue Oct 14, 2024 · 6 comments · Fixed by #9719
Closed

keypad.ShiftRegisterKeys has wrong key_count #9718

aseanwatson opened this issue Oct 14, 2024 · 6 comments · Fixed by #9719
Assignees
Labels
Milestone

Comments

@aseanwatson
Copy link

aseanwatson commented Oct 14, 2024

CircuitPython version

Adafruit CircuitPython 9.1.2 on 2024-08-22; Raspberry Pi Pico W with rp2040
Board ID:raspberry_pi_pico_w

Code/REPL

import board
import keypad

keys = keypad.ShiftRegisterKeys(
    data               = board.GP0,
    clock              = board.GP1,
    latch              = board.GP2,
    key_count          = 8,
    value_when_pressed = True,
    value_to_latch     = True,
    )

print(f"There are a total of {keys.key_count} keys.")

currentEvent = keypad.Event()

while True:
    # this if could be a while loop; that would let you handle every keypress
    # even if it means you don't call update as frequently
    while keys.events.get_into(currentEvent):
        if currentEvent.pressed:
            # TODO: handle key press
            print(f'key {currentEvent.key_number} was pressed')
        elif currentEvent.released:
            # TODO: handle key release
            print(f'key {currentEvent.key_number} was released')

Behavior

Actual:

code.py output:
There are a total of 17 keys.

It looks like
image

Expected:

code.py output:
There are a total of 8 keys.

Description

See the original Adafruit Forum Post.

Just trying different values, it seems like the effective value of the key_count parameter is key_count * 2 + 1 (so 8 => 17; 1 => 3)

Additional information

I don't have a good way to step through this in the debugger, but I looked at the source. I don't see an obvious bug.

keypad_shiftregisterkeys_make_new does this:

    mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);

to populate args and, specifically, args[ARG_key_count].

Then it does:

    if (mp_obj_is_int(args[ARG_key_count].u_obj)) {
        num_key_counts = 1;
    } 

And this:

    if (mp_obj_is_int(args[ARG_key_count].u_obj)) {
        const size_t key_count = (size_t)mp_arg_validate_int_min(args[ARG_key_count].u_int, 1, MP_QSTR_key_count);
        key_count_array[0] = key_count;
    } 

And finally this:

    common_hal_keypad_shiftregisterkeys_construct(
        self, clock, num_data_pins, data_pins_array, latch, value_to_latch, num_key_counts, key_count_array, value_when_pressed, interval, max_events, debounce_threshold);

common_hal_keypad_shiftregisterkeys_construct does this:

    self->key_counts = (mp_uint_t *)m_malloc(sizeof(mp_uint_t) * num_key_counts);
    self->num_key_counts = num_key_counts;

    // copy to an m_malloc() and on the fly record pin with largest Shift register
    mp_uint_t max = 0;

    for (mp_uint_t i = 0; i < self->num_key_counts; i++) {
        mp_uint_t cnt = key_counts[i];

        if (cnt > max) {
            max = cnt;
        }

        self->key_counts[i] = cnt;
    }

    self->max_key_count = max;

Taken together, I expect self->num_key_counts to be 1 and self->key_counts[0] to be 8 and self->max_key_count to be 8.

But the logic analyzer seems to indicate max_key_count is 17.

@aseanwatson
Copy link
Author

For what it's worth, this test also fails the same way:

 import board
 import keypad
 
 keys = keypad.ShiftRegisterKeys(
-    data               = board.GP0,
+    data               = (board.GP0),
     clock              = board.GP1,
     latch              = board.GP2,
-    key_count          = 8,
+    key_count          = (8),
    value_when_pressed = True,
    value_to_latch     = True,
    )

@dhalbert
Copy link
Collaborator

+    key_count          = (8),

Try (board.GP0,) and (8,) to make these actual tuples. Just putting them in parentheses without the comma does not make a tuple (a syntactic trap of Python's).

@aseanwatson
Copy link
Author

Thanks! I confirmed the workaround works.

@dhalbert
Copy link
Collaborator

An aside: (8) is not a tuple; (8,) is a tuple; (8,8) without a trailing comma is also a tuple; (8, 8,) is also a tuple. The trailing comma is ignored, but it convenient when you have tuple members on multiple lines:

t = (
    8,
    9,
    10,
)

@dhalbert dhalbert added this to the 9.2.0 milestone Oct 15, 2024
@dhalbert dhalbert self-assigned this Oct 15, 2024
@dhalbert
Copy link
Collaborator

I have a fix for this in #9719. If you are interested in testing, the build artifacts are here:
https://github.com/adafruit/circuitpython/actions/runs/11337244998?pr=9719

@aseanwatson
Copy link
Author

aseanwatson commented Oct 15, 2024

The fix looks good.

Thank you for the quick turnaround.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants