blob: 00ea46c82d0e2f61e58a9b73e27e8d630454f874 [file] [log] [blame]
/*
*
* 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;
}