1 /*
2  * Copyright (c) 2020 Siddharth Chandrasekaran <siddharth@embedjournal.com>
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #ifndef _OSDP_H_
8 #define _OSDP_H_
9 
10 #include <zephyr/kernel.h>
11 #include <stdint.h>
12 
13 #include <zephyr/sys/slist.h>
14 
15 #ifdef __cplusplus
16 extern "C" {
17 #endif
18 
19 #define OSDP_CMD_TEXT_MAX_LEN          32
20 #define OSDP_CMD_KEYSET_KEY_MAX_LEN    32
21 #define OSDP_EVENT_MAX_DATALEN         64
22 
23 /**
24  * @brief Command sent from CP to Control digital output of PD.
25  *
26  * @param output_no 0 = First Output, 1 = Second Output, etc.
27  * @param control_code One of the following:
28  *   0 - NOP – do not alter this output
29  *   1 - set the permanent state to OFF, abort timed operation (if any)
30  *   2 - set the permanent state to ON, abort timed operation (if any)
31  *   3 - set the permanent state to OFF, allow timed operation to complete
32  *   4 - set the permanent state to ON, allow timed operation to complete
33  *   5 - set the temporary state to ON, resume perm state on timeout
34  *   6 - set the temporary state to OFF, resume permanent state on timeout
35  * @param timer_count Time in units of 100 ms
36  */
37 struct osdp_cmd_output {
38 	uint8_t output_no;
39 	uint8_t control_code;
40 	uint16_t timer_count;
41 };
42 
43 /**
44  * @brief LED Colors as specified in OSDP for the on_color/off_color parameters.
45  */
46 enum osdp_led_color_e {
47 	OSDP_LED_COLOR_NONE,
48 	OSDP_LED_COLOR_RED,
49 	OSDP_LED_COLOR_GREEN,
50 	OSDP_LED_COLOR_AMBER,
51 	OSDP_LED_COLOR_BLUE,
52 	OSDP_LED_COLOR_SENTINEL
53 };
54 
55 /**
56  * @brief LED params sub-structure. Part of LED command. See struct osdp_cmd_led
57  *
58  * @param control_code One of the following:
59  * Temporary Control Code:
60  *   0 - NOP - do not alter this LED's temporary settings
61  *   1 - Cancel any temporary operation and display this LED's permanent state
62  *       immediately
63  *   2 - Set the temporary state as given and start timer immediately
64  * Permanent Control Code:
65  *   0 - NOP - do not alter this LED's permanent settings
66  *   1 - Set the permanent state as given
67  * @param on_count The ON duration of the flash, in units of 100 ms
68  * @param off_count The OFF duration of the flash, in units of 100 ms
69  * @param on_color Color to set during the ON timer (enum osdp_led_color_e)
70  * @param off_color Color to set during the OFF timer (enum osdp_led_color_e)
71  * @param timer_count Time in units of 100 ms (only for temporary mode)
72  */
73 struct osdp_cmd_led_params {
74 	uint8_t control_code;
75 	uint8_t on_count;
76 	uint8_t off_count;
77 	uint8_t on_color;
78 	uint8_t off_color;
79 	uint16_t timer_count;
80 };
81 
82 /**
83  * @brief Sent from CP to PD to control the behaviour of it's on-board LEDs
84  *
85  * @param reader 0 = First Reader, 1 = Second Reader, etc.
86  * @param led_number 0 = first LED, 1 = second LED, etc.
87  * @param temporary ephemeral LED status descriptor
88  * @param permanent permanent LED status descriptor
89  */
90 struct osdp_cmd_led {
91 	uint8_t reader;
92 	uint8_t led_number;
93 	struct osdp_cmd_led_params temporary;
94 	struct osdp_cmd_led_params permanent;
95 };
96 
97 /**
98  * @brief Sent from CP to control the behaviour of a buzzer in the PD.
99  *
100  * @param reader 0 = First Reader, 1 = Second Reader, etc.
101  * @param control_code 0: no tone, 1: off, 2: default tone, 3+ is TBD.
102  * @param on_count The ON duration of the flash, in units of 100 ms
103  * @param off_count The OFF duration of the flash, in units of 100 ms
104  * @param rep_count The number of times to repeat the ON/OFF cycle; 0: forever
105  */
106 struct osdp_cmd_buzzer {
107 	uint8_t reader;
108 	uint8_t control_code;
109 	uint8_t on_count;
110 	uint8_t off_count;
111 	uint8_t rep_count;
112 };
113 
114 /**
115  * @brief Command to manipulate any display units that the PD supports.
116  *
117  * @param reader 0 = First Reader, 1 = Second Reader, etc.
118  * @param control_code One of the following:
119  *   1 - permanent text, no wrap
120  *   2 - permanent text, with wrap
121  *   3 - temp text, no wrap
122  *   4 - temp text, with wrap
123  * @param temp_time duration to display temporary text, in seconds
124  * @param offset_row row to display the first character (1 indexed)
125  * @param offset_col column to display the first character (1 indexed)
126  * @param length Number of characters in the string
127  * @param data The string to display
128  */
129 struct osdp_cmd_text {
130 	uint8_t reader;
131 	uint8_t control_code;
132 	uint8_t temp_time;
133 	uint8_t offset_row;
134 	uint8_t offset_col;
135 	uint8_t length;
136 	uint8_t data[OSDP_CMD_TEXT_MAX_LEN];
137 };
138 
139 /**
140  * @brief Sent in response to a COMSET command. Set communication parameters to
141  * PD. Must be stored in PD non-volatile memory.
142  *
143  * @param address Unit ID to which this PD will respond after the change takes
144  *             effect.
145  * @param baud_rate baud rate value 9600/38400/115200
146  */
147 struct osdp_cmd_comset {
148 	uint8_t address;
149 	uint32_t baud_rate;
150 };
151 
152 /**
153  * @brief This command transfers an encryption key from the CP to a PD.
154  *
155  * @param type Type of keys:
156  *   - 0x01 – Secure Channel Base Key
157  * @param length Number of bytes of key data - (Key Length in bits + 7) / 8
158  * @param data Key data
159  */
160 struct osdp_cmd_keyset {
161 	uint8_t type;
162 	uint8_t length;
163 	uint8_t data[OSDP_CMD_KEYSET_KEY_MAX_LEN];
164 };
165 
166 /**
167  * @brief OSDP application exposed commands
168  */
169 enum osdp_cmd_e {
170 	OSDP_CMD_OUTPUT = 1,
171 	OSDP_CMD_LED,
172 	OSDP_CMD_BUZZER,
173 	OSDP_CMD_TEXT,
174 	OSDP_CMD_KEYSET,
175 	OSDP_CMD_COMSET,
176 	OSDP_CMD_SENTINEL
177 };
178 
179 /**
180  * @brief OSDP Command Structure. This is a wrapper for all individual OSDP
181  * commands.
182  *
183  * @param id used to select specific commands in union. Type: enum osdp_cmd_e
184  * @param led LED command structure
185  * @param buzzer buzzer command structure
186  * @param text text command structure
187  * @param output output command structure
188  * @param comset comset command structure
189  * @param keyset keyset command structure
190  */
191 struct osdp_cmd {
192 	sys_snode_t node;
193 	enum osdp_cmd_e id;
194 	union {
195 		struct osdp_cmd_led    led;
196 		struct osdp_cmd_buzzer buzzer;
197 		struct osdp_cmd_text   text;
198 		struct osdp_cmd_output output;
199 		struct osdp_cmd_comset comset;
200 		struct osdp_cmd_keyset keyset;
201 	};
202 };
203 
204 /**
205  * @brief Various card formats that a PD can support. This is sent to CP
206  * when a PD must report a card read.
207  */
208 enum osdp_event_cardread_format_e {
209 	OSDP_CARD_FMT_RAW_UNSPECIFIED,
210 	OSDP_CARD_FMT_RAW_WIEGAND,
211 	OSDP_CARD_FMT_ASCII,
212 	OSDP_CARD_FMT_SENTINEL
213 };
214 
215 /**
216  * @brief OSDP event cardread
217  *
218  * @param reader_no In context of readers attached to current PD, this number
219  *        indicated this number. This is not supported by LibOSDP.
220  * @param format Format of the card being read.
221  *        see `enum osdp_event_cardread_format_e`
222  * @param direction Card read direction of PD 0 - Forward; 1 - Backward
223  * @param length Length of card data in bytes or bits depending on `format`
224  *        (see note).
225  * @param data Card data of `length` bytes or bits bits depending on `format`
226  *        (see note).
227  *
228  * @note When `format` is set to OSDP_CARD_FMT_RAW_UNSPECIFIED or
229  * OSDP_CARD_FMT_RAW_WIEGAND, the length is expressed in bits. OTOH, when it is
230  * set to OSDP_CARD_FMT_ASCII, the length is in bytes. The number of bytes to
231  * read from the `data` field must be interpreted accordingly.
232  */
233 struct osdp_event_cardread {
234 	int reader_no;
235 	enum osdp_event_cardread_format_e format;
236 	int direction;
237 	int length;
238 	uint8_t data[OSDP_EVENT_MAX_DATALEN];
239 };
240 
241 /**
242  * @brief OSDP Event Keypad
243  *
244  * @param reader_no In context of readers attached to current PD, this number
245  *                  indicated this number. This is not supported by LibOSDP.
246  * @param length Length of keypress data in bytes
247  * @param data keypress data of `length` bytes
248  */
249 struct osdp_event_keypress {
250 	int reader_no;
251 	int length;
252 	uint8_t data[OSDP_EVENT_MAX_DATALEN];
253 };
254 
255 /**
256  * @brief OSDP PD Events
257  */
258 enum osdp_event_type {
259 	OSDP_EVENT_CARDREAD,
260 	OSDP_EVENT_KEYPRESS,
261 	OSDP_EVENT_SENTINEL
262 };
263 
264 /**
265  * @brief OSDP Event structure.
266  *
267  * @param type used to select specific event in union. See: enum osdp_event_type
268  * @param keypress keypress event structure
269  * @param cardread cardread event structure
270  */
271 struct osdp_event {
272 	sys_snode_t node;
273 	enum osdp_event_type type;
274 	union {
275 		struct osdp_event_keypress keypress;
276 		struct osdp_event_cardread cardread;
277 	};
278 };
279 
280 /**
281  * @brief Callback for PD command notifications. After it has been registered
282  * with `osdp_pd_set_command_callback`, this method is invoked when the PD
283  * receives a command from the CP.
284  *
285  * @param arg pointer that will was passed to the arg param of
286  * `osdp_pd_set_command_callback`.
287  * @param cmd pointer to the received command.
288  *
289  * @retval 0 if LibOSDP must send a `osdp_ACK` response
290  * @retval -ve if LibOSDP must send a `osdp_NAK` response
291  * @retval +ve and modify the passed `struct osdp_cmd *cmd` if LibOSDP must send
292  * a specific response. This is useful for sending manufacturer specific
293  * reply ``osdp_MFGREP``.
294  */
295 typedef int (*pd_command_callback_t)(void *arg, struct osdp_cmd *cmd);
296 
297 /**
298  * @brief Callback for CP event notifications. After it has been registered with
299  * `osdp_cp_set_event_callback`, this method is invoked when the CP receives an
300  * event from the PD.
301  *
302  * @param arg Opaque pointer provided by the application during callback
303  *            registration.
304  * @param pd the offset (0-indexed) of this PD in kconfig `OSDP_PD_ADDRESS_LIST`
305  * @param ev pointer to osdp_event struct (filled by libosdp).
306  *
307  * @retval 0 on handling the event successfully.
308  * @retval -ve on errors.
309  */
310 typedef int (*cp_event_callback_t)(void *arg, int pd, struct osdp_event *ev);
311 
312 #ifdef CONFIG_OSDP_MODE_PD
313 
314 /**
315  * @brief Set callback method for PD command notification. This callback is
316  * invoked when the PD receives a command from the CP.
317  *
318  * @param cb The callback function's pointer
319  * @param arg A pointer that will be passed as the first argument of `cb`
320  */
321 void osdp_pd_set_command_callback(pd_command_callback_t cb, void *arg);
322 
323 /**
324  * @brief API to notify PD events to CP. These events are sent to the CP as an
325  * alternate response to a POLL command.
326  *
327  * @param event pointer to event struct. Must be filled by application.
328  *
329  * @retval 0 on success
330  * @retval -1 on failure
331  */
332 int osdp_pd_notify_event(const struct osdp_event *event);
333 
334 #else /* CONFIG_OSDP_MODE_PD */
335 
336 /**
337  * @brief Generic command enqueue API.
338  *
339  * @param pd the offset (0-indexed) of this PD in kconfig `OSDP_PD_ADDRESS_LIST`
340  * @param cmd command pointer. Must be filled by application.
341  *
342  * @retval 0 on success
343  * @retval -1 on failure
344  *
345  * @note This method only adds the command on to a particular PD's command
346  * queue. The command itself can fail due to various reasons.
347  */
348 int osdp_cp_send_command(int pd, struct osdp_cmd *cmd);
349 
350 
351 /**
352  * @brief Set callback method for CP event notification. This callback is
353  * invoked when the CP receives an event from the PD.
354  *
355  * @param cb The callback function's pointer
356  * @param arg A pointer that will be passed as the first argument of `cb`
357  */
358 void osdp_cp_set_event_callback(cp_event_callback_t cb, void *arg);
359 
360 #endif /* CONFIG_OSDP_MODE_PD */
361 
362 #ifdef CONFIG_OSDP_SC_ENABLED
363 
364 uint32_t osdp_get_sc_status_mask(void);
365 
366 #endif
367 
368 #ifdef __cplusplus
369 }
370 #endif
371 
372 #endif	/* _OSDP_H_ */
373