/* * * Copyright (c) 2024 Project CHIP Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "zephyr_key_matrix.h" /* Key matrix scanning period */ #define KEY_MATRIX_SCAN_PERIOD_MS 100 /* Poll key matrix and rise event on key change */ static void key_matrix_poll(struct key_matrix_data * key_matrix, bool init) { for (size_t i = 0; i < key_matrix->col_len; i++) { gpio_pin_configure_dt(&key_matrix->col[i], GPIO_OUTPUT_ACTIVE); for (size_t j = 0; j < key_matrix->row_len; j++) { size_t button_num = i * key_matrix->col_len + j; bool pin = gpio_pin_get_dt(&key_matrix->row[j]); if (pin != (bool) (key_matrix->buttons[button_num / 8] & BIT(button_num % 8))) { WRITE_BIT(key_matrix->buttons[button_num / 8], button_num % 8, pin); if (!init && key_matrix->on_button_change) { key_matrix->on_button_change(button_num, pin, key_matrix->context); } } } gpio_pin_configure_dt(&key_matrix->col[i], GPIO_INPUT); } } /* Key matrix scan worker */ static void key_matrix_scan_work(struct k_work * item) { struct key_matrix_data * key_matrix = CONTAINER_OF(item, struct key_matrix_data, work); (void) k_work_schedule(&key_matrix->work, K_MSEC(KEY_MATRIX_SCAN_PERIOD_MS)); key_matrix_poll(key_matrix, false); } /* Public APIs */ bool key_matrix_init(struct key_matrix_data * key_matrix) { bool result = true; do { if (!key_matrix->col_len || !key_matrix->row_len) { result = false; break; } /* check if all GPIOs are ready */ for (size_t i = 0; i < key_matrix->col_len; i++) { if (!gpio_is_ready_dt(&key_matrix->col[i])) { result = false; break; } } if (!result) { break; } for (size_t i = 0; i < key_matrix->row_len; i++) { if (!gpio_is_ready_dt(&key_matrix->row[i])) { result = false; break; } } if (!result) { break; } /* init all GPIOs are ready */ for (size_t i = 0; i < key_matrix->col_len; i++) { if (gpio_pin_configure_dt(&key_matrix->col[i], GPIO_INPUT)) { result = false; break; } } if (!result) { break; } for (size_t i = 0; i < key_matrix->row_len; i++) { if (gpio_pin_configure_dt(&key_matrix->row[i], GPIO_INPUT)) { result = false; break; } } if (!result) { break; } /* set all keys to current state */ key_matrix_poll(key_matrix, true); key_matrix->on_button_change = NULL; key_matrix->context = NULL; /* work init */ k_work_init_delayable(&key_matrix->work, key_matrix_scan_work); while (k_work_schedule(&key_matrix->work, K_NO_WAIT) == -EBUSY) { k_usleep(10); /* Let other stuffs run */ } /* all done */ } while (0); return result; } void key_matrix_set_callback(struct key_matrix_data * key_matrix, key_matrix_on_button_change_t on_button_change, void * context) { key_matrix->on_button_change = on_button_change; key_matrix->context = context; }