1 /***************************************************************************//**
2 * \file cyhal_keyscan.h
3 *
4 * \brief
5 * Provides a high level interface for interacting with the Infineon KeyScan.
6 * This interface abstracts out the chip specific details. If any chip specific
7 * functionality is necessary, or performance is critical the low level functions
8 * can be used directly.
9 *
10 ********************************************************************************
11 * \copyright
12 * Copyright 2020-2021 Cypress Semiconductor Corporation (an Infineon company) or
13 * an affiliate of Cypress Semiconductor Corporation
14 *
15 * SPDX-License-Identifier: Apache-2.0
16 *
17 * Licensed under the Apache License, Version 2.0 (the "License");
18 * you may not use this file except in compliance with the License.
19 * You may obtain a copy of the License at
20 *
21 *     http://www.apache.org/licenses/LICENSE-2.0
22 *
23 * Unless required by applicable law or agreed to in writing, software
24 * distributed under the License is distributed on an "AS IS" BASIS,
25 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26 * See the License for the specific language governing permissions and
27 * limitations under the License.
28 *******************************************************************************/
29 
30 /**
31 * \addtogroup group_hal_keyscan Keyscan
32 * \ingroup group_hal
33 * \{
34 * High level interface for interacting with the KeyScan
35 *
36 * The KeyScan driver monitors a key matrix for actions and provides keycodes
37 * to the application for processing.
38 *
39 * \section section_keyscan_features Features
40 * * Configurable number of rows and columns
41 * * Detection of  press, double press, triple press, and release actions
42 * * Buffering of multiple key actions without application intervention
43 * * Configurable callback for event-driven response to key actions
44 *
45 * See the implementation-specific documentation for information about device-specific
46 * limits on row count, column count, and buffer depth.
47 *
48 * \section section_keyscan_quickstart Quick Start
49 * Initialize a KeyScan instance using @ref cyhal_keyscan_init, providing the pins that should
50 * be used for the rows and columns of the key matrix. Use @ref cyhal_keyscan_read to read
51 * key actions.
52 *
53 * See @ref subsection_keyscan_snippet_1 for an example initialization.
54 * \note The clock parameter (const \ref cyhal_clock_t *clk) is optional and can be set to
55 * NULL to automatically configure and use an available clock resource with a default frequency.
56 *
57 * \section section_keyscan_snippets Code Snippets
58 * \note Error handling is omitted for clarity
59 * \subsection subsection_keyscan_snippet_1 Snippet 1: KeyScan initialization
60 * This snippet initializes a KeyScan resource to scan a matrix of pins.
61 *
62 * \snippet hal_keyscan.c snippet_cyhal_keyscan_init
63 *
64 * \subsection subsection_keyscan_snippet_2 Snippet 2: Polling
65 * This snippet illustrates periodic polling for key actions
66 *
67 * \snippet hal_keyscan.c snippet_cyhal_keyscan_poll
68 *
69 * \subsection subsection_keyscan_snippet_3 Snippet 3: Event Handling
70 * This snippet shows how to register a callback which is invoked when a key action occurs.
71 *
72 * \snippet hal_keyscan.c snippet_cyhal_keyscan_event
73 */
74 
75 #pragma once
76 
77 #include "cyhal_hw_types.h"
78 #include "cyhal_gpio.h"
79 #include "cy_result.h"
80 #include "cyhal_clock.h"
81 
82 #if defined(__cplusplus)
83 extern "C" {
84 #endif
85 
86 /** An invalid pin location was specified */
87 #define CYHAL_KEYSCAN_RSLT_ERR_INVALID_PIN        \
88   (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_KEYSCAN, 0))
89 
90 /** An invalid argument was provided */
91 #define CYHAL_KEYSCAN_RSLT_ERR_INVALID_ARG        \
92   (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_KEYSCAN, 1))
93 
94 /** Initialization of the KeyScan hardware failed */
95 #define CYHAL_KEYSCAN_RSLT_ERR_INIT_FAILED        \
96   (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_KEYSCAN, 2))
97 
98 /** KeyScan events */
99 typedef enum {
100     CYHAL_KEYSCAN_EVENT_NONE            = 0, //!< No interrupt
101     CYHAL_KEYSCAN_EVENT_ACTION_DETECTED = 1 << 0, //!< Key action detected
102     CYHAL_KEYSCAN_EVENT_BUFFER_FULL     = 1 << 1, //!< Keycode buffer is full
103 } cyhal_keyscan_event_t;
104 
105 /** Key action types */
106 typedef enum {
107     CYHAL_KEYSCAN_ACTION_PRESS,        //<! The key was pressed
108     CYHAL_KEYSCAN_ACTION_RELEASE,      //<! The key was released
109 } cyhal_keyscan_action_type_t;
110 
111 /** Key action description */
112 typedef struct {
113     /** Code indicating which key the action applies to. Keycodes are assigned sequentially in column
114       * order. For example, in a key matrix with five rows and two columns, column 0 would be represented
115       * by keycode 0 - 4, and column 1 by keycode 5-9.
116       */
117     uint8_t keycode;
118     /** The type of key action that was performd */
119     cyhal_keyscan_action_type_t action;
120 } cyhal_keyscan_action_t;
121 
122 /** Handler for KeyScan event callbacks */
123 typedef void (*cyhal_keyscan_event_callback_t)(void *callback_arg, cyhal_keyscan_event_t event);
124 
125 /** Initialize the KeyScan peripheral.
126  *
127  * @param[out] obj          Pointer to a KeyScan object. The caller must allocate the memory
128  *                          for this object but the init function will initialize its contents.
129  * @param[in]  num_rows     The number of rows in the key matrix
130  * @param[in]  rows         Array of pins corresponding to the key matrix rows
131  * @param[in]  num_columns  The number of columns in the key matrix
132  * @param[in]  columns      Array of pins corresponding to the key matrix columns
133  * @param[in]  clock        Clock source to use for this instance. If NULL, a dedicated clock
134  *                          will be automatically allocated for this instance.
135  * @return The status of the init request
136  */
137 cy_rslt_t cyhal_keyscan_init(cyhal_keyscan_t *obj, uint8_t num_rows, const cyhal_gpio_t *rows,
138                                 uint8_t num_columns, const cyhal_gpio_t *columns, const cyhal_clock_t *clock);
139 
140 /** Deinitialize the KeyScan object and release the associated hardware resources.
141  *
142  * @param[in] obj  The KeyScan object
143  */
144 void cyhal_keyscan_free(cyhal_keyscan_t *obj);
145 
146 /** Reads up to the specified number of key actions.
147   *
148   * \note If an error code is returned, this function will contain partial information up to the number of keys read.
149   *
150   * @param[in]      obj     The KeyScan object
151   * @param[in,out]  count   The number of key action to read. Updated with the number of keys actually read.
152   * @param[out]     keys    The array into which key action descriptions should be written, starting from the
153   *                         least recent key action at index 0.
154   * @return The status of the read request
155   */
156 cy_rslt_t cyhal_keyscan_read(cyhal_keyscan_t *obj, uint8_t* count, cyhal_keyscan_action_t* keys);
157 
158 /** Register a keyscan callback handler.
159  *
160  * This function will be called when one of the events enabled by @ref cyhal_keyscan_enable_event occurs.
161  *
162  * @param[in] obj          The KeyScan object
163  * @param[in] callback     The callback handler which will be invoked when the event occurs
164  * @param[in] callback_arg Generic argument that will be provided to the callback when called
165  */
166 void cyhal_keyscan_register_callback(cyhal_keyscan_t *obj, cyhal_keyscan_event_callback_t callback, void *callback_arg);
167 
168 /** Configure KeyScan events.
169  *
170  * When an enabled event occurs, the function specified by \ref cyhal_keyscan_register_callback will be called.
171  *
172  * @param[in] obj            The KeyScan object
173  * @param[in] event          The KeyScan event type
174  * @param[in] intr_priority  The priority for NVIC interrupt events
175  * @param[in] enable         True to turn on the specified event, False to turn off
176  */
177 void cyhal_keyscan_enable_event(cyhal_keyscan_t *obj, cyhal_keyscan_event_t event, uint8_t intr_priority, bool enable);
178 
179 /** Initialize the KeyScan peripheral using a configurator generated configuration struct.
180  *
181  * @param[in]  obj                  Pointer to a KeyScan object. The caller must allocate the memory
182  *                                  for this object but the init function will initialize its contents.
183  * @param[in]  cfg                  Configuration structure generated by a configurator.
184  * @return The status of the operation
185  */
186 cy_rslt_t cyhal_keyscan_init_cfg(cyhal_keyscan_t *obj, const cyhal_keyscan_configurator_t *cfg);
187 
188 #if defined(__cplusplus)
189 }
190 #endif
191 
192 #ifdef CYHAL_KEYSCAN_IMPL_HEADER
193 #include CYHAL_KEYSCAN_IMPL_HEADER
194 #endif /* CYHAL_KEYSCAN_IMPL_HEADER */
195 
196 /** \} group_hal_keyscan */
197 
198