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