mgmt/osdp: Add support for event delivery and notifications
The CP app sends PD a "command" and the PD responds to it. Some times, the PD has something that it wants to tell the PD which it does so in response to POLL command. Both CP and PD apps need a way to exchange these info over the OSDP bus. To archive this we will introduce what are called "events" that allow the PD app to enqueue and CP app to get notified. This is analogous to the incumbent "commands" abstraction where, the CP app enqueues a command and the PD app gets notified of it. Signed-off-by: Siddharth Chandrasekaran <sidcha.dev@gmail.com>
This commit is contained in:
parent
c7fec71193
commit
73809472f8
7 changed files with 462 additions and 236 deletions
|
@ -18,17 +18,7 @@ extern "C" {
|
||||||
|
|
||||||
#define OSDP_CMD_TEXT_MAX_LEN 32
|
#define OSDP_CMD_TEXT_MAX_LEN 32
|
||||||
#define OSDP_CMD_KEYSET_KEY_MAX_LEN 32
|
#define OSDP_CMD_KEYSET_KEY_MAX_LEN 32
|
||||||
|
#define OSDP_EVENT_MAX_DATALEN 64
|
||||||
/**
|
|
||||||
* @brief Various card formats that a PD can support. This is sent to CP
|
|
||||||
* when a PD must report a card read.
|
|
||||||
*/
|
|
||||||
enum osdp_card_formats_e {
|
|
||||||
OSDP_CARD_FMT_RAW_UNSPECIFIED,
|
|
||||||
OSDP_CARD_FMT_RAW_WIEGAND,
|
|
||||||
OSDP_CARD_FMT_ASCII,
|
|
||||||
OSDP_CARD_FMT_SENTINEL
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Command sent from CP to Control digital output of PD.
|
* @brief Command sent from CP to Control digital output of PD.
|
||||||
|
@ -211,24 +201,162 @@ struct osdp_cmd {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Various card formats that a PD can support. This is sent to CP
|
||||||
|
* when a PD must report a card read.
|
||||||
|
*/
|
||||||
|
enum osdp_event_cardread_format_e {
|
||||||
|
OSDP_CARD_FMT_RAW_UNSPECIFIED,
|
||||||
|
OSDP_CARD_FMT_RAW_WIEGAND,
|
||||||
|
OSDP_CARD_FMT_ASCII,
|
||||||
|
OSDP_CARD_FMT_SENTINEL
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief OSDP event cardread
|
||||||
|
*
|
||||||
|
* @param reader_no In context of readers attached to current PD, this number
|
||||||
|
* indicated this number. This is not supported by LibOSDP.
|
||||||
|
* @param format Format of the card being read.
|
||||||
|
* see `enum osdp_event_cardread_format_e`
|
||||||
|
* @param direction Card read direction of PD 0 - Forward; 1 - Backward
|
||||||
|
* @param length Length of card data in bytes or bits depending on `format`
|
||||||
|
* (see note).
|
||||||
|
* @param data Card data of `length` bytes or bits bits depending on `format`
|
||||||
|
* (see note).
|
||||||
|
*
|
||||||
|
* @note When `format` is set to OSDP_CARD_FMT_RAW_UNSPECIFIED or
|
||||||
|
* OSDP_CARD_FMT_RAW_WIEGAND, the length is expressed in bits. OTOH, when it is
|
||||||
|
* set to OSDP_CARD_FMT_ASCII, the length is in bytes. The number of bytes to
|
||||||
|
* read from the `data` field must be interpreted accordingly.
|
||||||
|
*/
|
||||||
|
struct osdp_event_cardread {
|
||||||
|
int reader_no;
|
||||||
|
enum osdp_event_cardread_format_e format;
|
||||||
|
int direction;
|
||||||
|
int length;
|
||||||
|
uint8_t data[OSDP_EVENT_MAX_DATALEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief OSDP Event Keypad
|
||||||
|
*
|
||||||
|
* @param reader_no In context of readers attached to current PD, this number
|
||||||
|
* indicated this number. This is not supported by LibOSDP.
|
||||||
|
* @param length Length of keypress data in bytes
|
||||||
|
* @param data keypress data of `length` bytes
|
||||||
|
*/
|
||||||
|
struct osdp_event_keypress {
|
||||||
|
int reader_no;
|
||||||
|
int length;
|
||||||
|
uint8_t data[OSDP_EVENT_MAX_DATALEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief OSDP PD Events
|
||||||
|
*/
|
||||||
|
enum osdp_event_type {
|
||||||
|
OSDP_EVENT_CARDREAD,
|
||||||
|
OSDP_EVENT_KEYPRESS,
|
||||||
|
OSDP_EVENT_SENTINEL
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief OSDP Event structure.
|
||||||
|
*
|
||||||
|
* @param type used to select specific event in union. See: enum osdp_event_type
|
||||||
|
* @param keypress keypress event structure
|
||||||
|
* @param cardread cardread event structure
|
||||||
|
*/
|
||||||
|
struct osdp_event {
|
||||||
|
sys_snode_t node;
|
||||||
|
enum osdp_event_type type;
|
||||||
|
union {
|
||||||
|
struct osdp_event_keypress keypress;
|
||||||
|
struct osdp_event_cardread cardread;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback for PD command notifications. After it has been registered
|
||||||
|
* with `osdp_pd_set_command_callback`, this method is invoked when the PD
|
||||||
|
* receives a command from the CP.
|
||||||
|
*
|
||||||
|
* @param arg pointer that will was passed to the arg param of
|
||||||
|
* `osdp_pd_set_command_callback`.
|
||||||
|
* @param cmd pointer to the received command.
|
||||||
|
*
|
||||||
|
* @retval 0 if LibOSDP must send a `osdp_ACK` response
|
||||||
|
* @retval -ve if LibOSDP must send a `osdp_NAK` response
|
||||||
|
* @retval +ve and modify the passed `struct osdp_cmd *cmd` if LibOSDP must send
|
||||||
|
* a specific response. This is useful for sending manufacturer specific
|
||||||
|
* reply ``osdp_MFGREP``.
|
||||||
|
*/
|
||||||
|
typedef int (*pd_command_callback_t)(void *arg, struct osdp_cmd *cmd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback for CP event notifications. After it has been registered with
|
||||||
|
* `osdp_cp_set_event_callback`, this method is invoked when the CP receives an
|
||||||
|
* event from the PD.
|
||||||
|
*
|
||||||
|
* @param arg Opaque pointer provided by the application during callback
|
||||||
|
* registration.
|
||||||
|
* @param pd the offset (0-indexed) of this PD in kconfig `OSDP_PD_ADDRESS_LIST`
|
||||||
|
* @param ev pointer to osdp_event struct (filled by libosdp).
|
||||||
|
*
|
||||||
|
* @retval 0 on handling the event successfully.
|
||||||
|
* @retval -ve on errors.
|
||||||
|
*/
|
||||||
|
typedef int (*cp_event_callback_t)(void *arg, int pd, struct osdp_event *ev);
|
||||||
|
|
||||||
#ifdef CONFIG_OSDP_MODE_PD
|
#ifdef CONFIG_OSDP_MODE_PD
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param cmd pointer to a command structure that was received by the driver.
|
* @brief Set callback method for PD command notification. This callback is
|
||||||
|
* invoked when the PD receives a command from the CP.
|
||||||
*
|
*
|
||||||
* @retval 0 on success.
|
* @param cb The callback function's pointer
|
||||||
* @retval -1 on failure.
|
* @param arg A pointer that will be passed as the first argument of `cb`
|
||||||
*/
|
*/
|
||||||
int osdp_pd_get_cmd(struct osdp_cmd *cmd);
|
void osdp_pd_set_command_callback(pd_command_callback_t cb, void *arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief API to notify PD events to CP. These events are sent to the CP as an
|
||||||
|
* alternate response to a POLL command.
|
||||||
|
*
|
||||||
|
* @param event pointer to event struct. Must be filled by application.
|
||||||
|
*
|
||||||
|
* @retval 0 on success
|
||||||
|
* @retval -1 on failure
|
||||||
|
*/
|
||||||
|
int osdp_pd_notify_event(const struct osdp_event *event);
|
||||||
|
|
||||||
#else /* CONFIG_OSDP_MODE_PD */
|
#else /* CONFIG_OSDP_MODE_PD */
|
||||||
|
|
||||||
int osdp_cp_set_callback_key_press(
|
/**
|
||||||
int (*cb)(int address, uint8_t key));
|
* @brief Generic command enqueue API.
|
||||||
int osdp_cp_set_callback_card_read(
|
*
|
||||||
int (*cb)(int address, int format, uint8_t *data, int len));
|
* @param pd the offset (0-indexed) of this PD in kconfig `OSDP_PD_ADDRESS_LIST`
|
||||||
|
* @param cmd command pointer. Must be filled by application.
|
||||||
|
*
|
||||||
|
* @retval 0 on success
|
||||||
|
* @retval -1 on failure
|
||||||
|
*
|
||||||
|
* @note This method only adds the command on to a particular PD's command
|
||||||
|
* queue. The command itself can fail due to various reasons.
|
||||||
|
*/
|
||||||
int osdp_cp_send_command(int pd, struct osdp_cmd *cmd);
|
int osdp_cp_send_command(int pd, struct osdp_cmd *cmd);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set callback method for CP event notification. This callback is
|
||||||
|
* invoked when the CP receives an event from the PD.
|
||||||
|
*
|
||||||
|
* @param cb The callback function's pointer
|
||||||
|
* @param arg A pointer that will be passed as the first argument of `cb`
|
||||||
|
*/
|
||||||
|
void osdp_cp_set_event_callback(cp_event_callback_t cb, void *arg);
|
||||||
|
|
||||||
#endif /* CONFIG_OSDP_MODE_PD */
|
#endif /* CONFIG_OSDP_MODE_PD */
|
||||||
|
|
||||||
#ifdef CONFIG_OSDP_SC_ENABLED
|
#ifdef CONFIG_OSDP_SC_ENABLED
|
||||||
|
|
|
@ -28,9 +28,9 @@ enum osdp_pd_e {
|
||||||
OSDP_PD_SENTINEL,
|
OSDP_PD_SENTINEL,
|
||||||
};
|
};
|
||||||
|
|
||||||
int key_press_callback(int pd, uint8_t key)
|
int key_press_callback(int pd, uint8_t *data, int len)
|
||||||
{
|
{
|
||||||
printk("CP PD[%d] key press - data: 0x%02x\n", pd, key);
|
printk("CP PD[%d] key press - data: 0x%02x\n", pd, data[0]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +49,22 @@ int card_read_callback(int pd, int format, uint8_t *data, int len)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int event_handler(void *unused, int pd, struct osdp_event *e)
|
||||||
|
{
|
||||||
|
switch (e->type) {
|
||||||
|
case OSDP_EVENT_CARDREAD:
|
||||||
|
card_read_callback(pd, e->cardread.format,
|
||||||
|
e->cardread.data, e->cardread.length);
|
||||||
|
break;
|
||||||
|
case OSDP_EVENT_KEYPRESS:
|
||||||
|
key_press_callback(pd, e->keypress.data, e->keypress.length);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
int ret, led_state;
|
int ret, led_state;
|
||||||
|
@ -71,8 +87,7 @@ void main(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
osdp_cp_set_callback_key_press(key_press_callback);
|
osdp_cp_set_event_callback(event_handler, NULL);
|
||||||
osdp_cp_set_callback_card_read(card_read_callback);
|
|
||||||
|
|
||||||
led_state = 0;
|
led_state = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
|
@ -21,7 +21,7 @@ static const struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET_OR(LED0_NODE, gpios, {0
|
||||||
#define SLEEP_TIME_MS (20)
|
#define SLEEP_TIME_MS (20)
|
||||||
#define CNT_PER_SEC (1000 / SLEEP_TIME_MS)
|
#define CNT_PER_SEC (1000 / SLEEP_TIME_MS)
|
||||||
|
|
||||||
int cmd_handler(struct osdp_cmd *p)
|
int cmd_handler(void *unused, struct osdp_cmd *p)
|
||||||
{
|
{
|
||||||
printk("App received command %d\n", p->id);
|
printk("App received command %d\n", p->id);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -31,7 +31,6 @@ void main(void)
|
||||||
{
|
{
|
||||||
int ret, led_state;
|
int ret, led_state;
|
||||||
uint32_t cnt = 0;
|
uint32_t cnt = 0;
|
||||||
struct osdp_cmd cmd;
|
|
||||||
|
|
||||||
if (!device_is_ready(led0.port)) {
|
if (!device_is_ready(led0.port)) {
|
||||||
printk("LED0 GPIO port %s is not ready\n", led0.port->name);
|
printk("LED0 GPIO port %s is not ready\n", led0.port->name);
|
||||||
|
@ -45,15 +44,14 @@ void main(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
osdp_pd_set_command_callback(cmd_handler, NULL);
|
||||||
|
|
||||||
led_state = 0;
|
led_state = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
if ((cnt & 0x7f) == 0x7f) {
|
if ((cnt & 0x7f) == 0x7f) {
|
||||||
/* show a sign of life */
|
/* show a sign of life */
|
||||||
led_state = !led_state;
|
led_state = !led_state;
|
||||||
}
|
}
|
||||||
if (osdp_pd_get_cmd(&cmd) == 0) {
|
|
||||||
cmd_handler(&cmd);
|
|
||||||
}
|
|
||||||
gpio_pin_set(led0.port, led0.pin, led_state);
|
gpio_pin_set(led0.port, led0.pin, led_state);
|
||||||
k_msleep(SLEEP_TIME_MS);
|
k_msleep(SLEEP_TIME_MS);
|
||||||
cnt++;
|
cnt++;
|
||||||
|
|
|
@ -41,45 +41,6 @@ int64_t osdp_millis_since(int64_t last)
|
||||||
return (int64_t) k_uptime_delta(&tmp);
|
return (int64_t) k_uptime_delta(&tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct osdp_cmd *osdp_cmd_alloc(struct osdp_pd *pd)
|
|
||||||
{
|
|
||||||
struct osdp_cmd *cmd = NULL;
|
|
||||||
|
|
||||||
if (k_mem_slab_alloc(&pd->cmd.slab, (void **)&cmd, K_MSEC(100))) {
|
|
||||||
LOG_ERR("Memory allocation time-out");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return cmd;
|
|
||||||
}
|
|
||||||
|
|
||||||
void osdp_cmd_free(struct osdp_pd *pd, struct osdp_cmd *cmd)
|
|
||||||
{
|
|
||||||
k_mem_slab_free(&pd->cmd.slab, (void **)&cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void osdp_cmd_enqueue(struct osdp_pd *pd, struct osdp_cmd *cmd)
|
|
||||||
{
|
|
||||||
sys_slist_append(&pd->cmd.queue, &cmd->node);
|
|
||||||
}
|
|
||||||
|
|
||||||
int osdp_cmd_dequeue(struct osdp_pd *pd, struct osdp_cmd **cmd)
|
|
||||||
{
|
|
||||||
sys_snode_t *node;
|
|
||||||
|
|
||||||
node = sys_slist_peek_head(&pd->cmd.queue);
|
|
||||||
if (node == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
sys_slist_remove(&pd->cmd.queue, NULL, node);
|
|
||||||
*cmd = CONTAINER_OF(node, struct osdp_cmd, node);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct osdp_cmd *osdp_cmd_get_last(struct osdp_pd *pd)
|
|
||||||
{
|
|
||||||
return (struct osdp_cmd *)sys_slist_peek_tail(&pd->cmd.queue);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_OSDP_SC_ENABLED
|
#ifdef CONFIG_OSDP_SC_ENABLED
|
||||||
|
|
||||||
void osdp_encrypt(uint8_t *key, uint8_t *iv, uint8_t *data, int len)
|
void osdp_encrypt(uint8_t *key, uint8_t *iv, uint8_t *data, int len)
|
||||||
|
|
|
@ -10,10 +10,12 @@
|
||||||
#include <zephyr/mgmt/osdp.h>
|
#include <zephyr/mgmt/osdp.h>
|
||||||
#include <zephyr/sys/__assert.h>
|
#include <zephyr/sys/__assert.h>
|
||||||
|
|
||||||
|
#define STR(x) #x
|
||||||
|
|
||||||
#define OSDP_RESP_TOUT_MS (200)
|
#define OSDP_RESP_TOUT_MS (200)
|
||||||
|
|
||||||
#define OSDP_CMD_SLAB_BUF_SIZE \
|
#define OSDP_QUEUE_SLAB_SIZE \
|
||||||
(sizeof(struct osdp_cmd) * CONFIG_OSDP_PD_COMMAND_QUEUE_SIZE)
|
(sizeof(union osdp_ephemeral_data) * CONFIG_OSDP_PD_COMMAND_QUEUE_SIZE)
|
||||||
|
|
||||||
#define ISSET_FLAG(p, f) (((p)->flags & (f)) == (f))
|
#define ISSET_FLAG(p, f) (((p)->flags & (f)) == (f))
|
||||||
#define SET_FLAG(p, f) ((p)->flags |= (f))
|
#define SET_FLAG(p, f) ((p)->flags |= (f))
|
||||||
|
@ -311,6 +313,12 @@ enum osdp_pd_cap_function_code_e {
|
||||||
OSDP_PD_CAP_SENTINEL
|
OSDP_PD_CAP_SENTINEL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Unused type only to estimate ephemeral_data size */
|
||||||
|
union osdp_ephemeral_data {
|
||||||
|
struct osdp_cmd cmd;
|
||||||
|
struct osdp_event event;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief PD capability structure. Each PD capability has a 3 byte
|
* @brief PD capability structure. Each PD capability has a 3 byte
|
||||||
* representation.
|
* representation.
|
||||||
|
@ -379,15 +387,10 @@ struct osdp_channel {
|
||||||
void (*flush)(void *data);
|
void (*flush)(void *data);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct osdp_cmd_queue {
|
struct osdp_queue {
|
||||||
sys_slist_t queue;
|
sys_slist_t queue;
|
||||||
struct k_mem_slab slab;
|
struct k_mem_slab slab;
|
||||||
uint8_t slab_buf[OSDP_CMD_SLAB_BUF_SIZE];
|
uint8_t slab_buf[OSDP_QUEUE_SLAB_SIZE];
|
||||||
};
|
|
||||||
|
|
||||||
struct osdp_notifiers {
|
|
||||||
int (*keypress)(int address, uint8_t key);
|
|
||||||
int (*cardread)(int address, int format, uint8_t *data, int len);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_OSDP_SC_ENABLED
|
#ifdef CONFIG_OSDP_SC_ENABLED
|
||||||
|
@ -435,7 +438,16 @@ struct osdp_pd {
|
||||||
uint8_t cmd_data[OSDP_COMMAND_DATA_MAX_LEN];
|
uint8_t cmd_data[OSDP_COMMAND_DATA_MAX_LEN];
|
||||||
|
|
||||||
struct osdp_channel channel;
|
struct osdp_channel channel;
|
||||||
struct osdp_cmd_queue cmd;
|
|
||||||
|
union {
|
||||||
|
struct osdp_queue cmd; /* Command queue (CP Mode only) */
|
||||||
|
struct osdp_queue event; /* Command queue (PD Mode only) */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* PD command callback to app with opaque arg pointer as passed by app */
|
||||||
|
void *command_callback_arg;
|
||||||
|
pd_command_callback_t command_callback;
|
||||||
|
|
||||||
#ifdef CONFIG_OSDP_SC_ENABLED
|
#ifdef CONFIG_OSDP_SC_ENABLED
|
||||||
int64_t sc_tstamp;
|
int64_t sc_tstamp;
|
||||||
struct osdp_secure_channel sc;
|
struct osdp_secure_channel sc;
|
||||||
|
@ -451,7 +463,9 @@ struct osdp {
|
||||||
#ifdef CONFIG_OSDP_SC_ENABLED
|
#ifdef CONFIG_OSDP_SC_ENABLED
|
||||||
uint8_t sc_master_key[16];
|
uint8_t sc_master_key[16];
|
||||||
#endif
|
#endif
|
||||||
struct osdp_notifiers notifier;
|
/* CP event callback to app with opaque arg pointer as passed by app */
|
||||||
|
void *event_callback_arg;
|
||||||
|
cp_event_callback_t event_callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* from osdp_phy.c */
|
/* from osdp_phy.c */
|
||||||
|
@ -468,11 +482,6 @@ int64_t osdp_millis_now(void);
|
||||||
int64_t osdp_millis_since(int64_t last);
|
int64_t osdp_millis_since(int64_t last);
|
||||||
void osdp_dump(const char *head, uint8_t *buf, int len);
|
void osdp_dump(const char *head, uint8_t *buf, int len);
|
||||||
uint16_t osdp_compute_crc16(const uint8_t *buf, size_t len);
|
uint16_t osdp_compute_crc16(const uint8_t *buf, size_t len);
|
||||||
struct osdp_cmd *osdp_cmd_alloc(struct osdp_pd *pd);
|
|
||||||
void osdp_cmd_free(struct osdp_pd *pd, struct osdp_cmd *cmd);
|
|
||||||
void osdp_cmd_enqueue(struct osdp_pd *pd, struct osdp_cmd *cmd);
|
|
||||||
int osdp_cmd_dequeue(struct osdp_pd *pd, struct osdp_cmd **cmd);
|
|
||||||
struct osdp_cmd *osdp_cmd_get_last(struct osdp_pd *pd);
|
|
||||||
|
|
||||||
/* from osdp.c */
|
/* from osdp.c */
|
||||||
struct osdp *osdp_get_ctx();
|
struct osdp *osdp_get_ctx();
|
||||||
|
|
|
@ -59,6 +59,40 @@ enum osdp_cp_error_e {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static struct osdp_cmd *cp_cmd_alloc(struct osdp_pd *pd)
|
||||||
|
{
|
||||||
|
struct osdp_cmd *cmd = NULL;
|
||||||
|
|
||||||
|
if (k_mem_slab_alloc(&pd->cmd.slab, (void **)&cmd, K_MSEC(100))) {
|
||||||
|
LOG_ERR("Memory allocation time-out");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cp_cmd_free(struct osdp_pd *pd, struct osdp_cmd *cmd)
|
||||||
|
{
|
||||||
|
k_mem_slab_free(&pd->cmd.slab, (void **)&cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cp_cmd_enqueue(struct osdp_pd *pd, struct osdp_cmd *cmd)
|
||||||
|
{
|
||||||
|
sys_slist_append(&pd->cmd.queue, &cmd->node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cp_cmd_dequeue(struct osdp_pd *pd, struct osdp_cmd **cmd)
|
||||||
|
{
|
||||||
|
sys_snode_t *node;
|
||||||
|
|
||||||
|
node = sys_slist_peek_head(&pd->cmd.queue);
|
||||||
|
if (node == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
sys_slist_remove(&pd->cmd.queue, NULL, node);
|
||||||
|
*cmd = CONTAINER_OF(node, struct osdp_cmd, node);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int osdp_extract_address(int *address)
|
int osdp_extract_address(int *address)
|
||||||
{
|
{
|
||||||
int pd_offset = 0;
|
int pd_offset = 0;
|
||||||
|
@ -288,6 +322,7 @@ static int cp_decode_response(struct osdp_pd *pd, uint8_t *buf, int len)
|
||||||
uint32_t temp32;
|
uint32_t temp32;
|
||||||
struct osdp *ctx = pd_to_osdp(pd);
|
struct osdp *ctx = pd_to_osdp(pd);
|
||||||
int i, ret = OSDP_CP_ERR_GENERIC, pos = 0, t1, t2;
|
int i, ret = OSDP_CP_ERR_GENERIC, pos = 0, t1, t2;
|
||||||
|
struct osdp_event event;
|
||||||
|
|
||||||
if (len < 1) {
|
if (len < 1) {
|
||||||
LOG_ERR("response must have at least one byte");
|
LOG_ERR("response must have at least one byte");
|
||||||
|
@ -399,52 +434,58 @@ static int cp_decode_response(struct osdp_pd *pd, uint8_t *buf, int len)
|
||||||
ret = OSDP_CP_ERR_NONE;
|
ret = OSDP_CP_ERR_NONE;
|
||||||
break;
|
break;
|
||||||
case REPLY_KEYPPAD:
|
case REPLY_KEYPPAD:
|
||||||
if (len < REPLY_KEYPPAD_DATA_LEN) {
|
if (len < REPLY_KEYPPAD_DATA_LEN || !ctx->event_callback) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pos++; /* reader number; skip */
|
event.type = OSDP_EVENT_KEYPRESS;
|
||||||
t1 = buf[pos++]; /* key length */
|
event.keypress.reader_no = buf[pos++];
|
||||||
if ((len - REPLY_KEYPPAD_DATA_LEN) != t1) {
|
event.keypress.length = buf[pos++];
|
||||||
|
if ((len - REPLY_KEYPPAD_DATA_LEN) != event.keypress.length) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (ctx->notifier.keypress) {
|
for (i = 0; i < event.keypress.length; i++) {
|
||||||
for (i = 0; i < t1; i++) {
|
event.keypress.data[i] = buf[pos + i];
|
||||||
t2 = buf[pos + i]; /* key data */
|
|
||||||
ctx->notifier.keypress(pd->idx, t2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
ctx->event_callback(ctx->event_callback_arg, pd->idx, &event);
|
||||||
ret = OSDP_CP_ERR_NONE;
|
ret = OSDP_CP_ERR_NONE;
|
||||||
break;
|
break;
|
||||||
case REPLY_RAW:
|
case REPLY_RAW:
|
||||||
if (len < REPLY_RAW_DATA_LEN) {
|
if (len < REPLY_RAW_DATA_LEN || !ctx->event_callback) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pos++; /* reader number; skip */
|
event.type = OSDP_EVENT_CARDREAD;
|
||||||
t1 = buf[pos++]; /* format */
|
event.cardread.reader_no = buf[pos++];
|
||||||
t2 = buf[pos++]; /* length LSB */
|
event.cardread.format = buf[pos++];
|
||||||
t2 |= buf[pos++] << 8; /* length MSB */
|
event.cardread.length = buf[pos++]; /* bits LSB */
|
||||||
if ((len - REPLY_RAW_DATA_LEN) != t2) {
|
event.cardread.length |= buf[pos++] << 8; /* bits MSB */
|
||||||
|
event.cardread.direction = 0; /* un-specified */
|
||||||
|
t1 = (event.cardread.length + 7) / 8; /* len: bytes */
|
||||||
|
if (t1 != (len - REPLY_RAW_DATA_LEN)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (ctx->notifier.cardread) {
|
for (i = 0; i < t1; i++) {
|
||||||
ctx->notifier.cardread(pd->idx, t1, buf + pos, t2);
|
event.cardread.data[i] = buf[pos + i];
|
||||||
}
|
}
|
||||||
|
ctx->event_callback(ctx->event_callback_arg, pd->idx, &event);
|
||||||
ret = OSDP_CP_ERR_NONE;
|
ret = OSDP_CP_ERR_NONE;
|
||||||
break;
|
break;
|
||||||
case REPLY_FMT:
|
case REPLY_FMT:
|
||||||
if (len < REPLY_FMT_DATA_LEN) {
|
if (len < REPLY_FMT_DATA_LEN || !ctx->event_callback) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pos++; /* reader number; skip */
|
event.type = OSDP_EVENT_CARDREAD;
|
||||||
pos++; /* skip one byte -- TODO: handle reader direction */
|
event.cardread.reader_no = buf[pos++];
|
||||||
t1 = buf[pos++]; /* Key length */
|
event.cardread.direction = buf[pos++];
|
||||||
if ((len - REPLY_FMT_DATA_LEN) != t1) {
|
event.cardread.length = buf[pos++];
|
||||||
|
event.cardread.format = OSDP_CARD_FMT_ASCII;
|
||||||
|
if (event.cardread.length != (len - REPLY_FMT_DATA_LEN) ||
|
||||||
|
event.cardread.length > OSDP_EVENT_MAX_DATALEN) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (ctx->notifier.cardread) {
|
for (i = 0; i < event.cardread.length; i++) {
|
||||||
ctx->notifier.cardread(pd->idx, OSDP_CARD_FMT_ASCII,
|
event.cardread.data[i] = buf[pos + i];
|
||||||
buf + pos, t1);
|
|
||||||
}
|
}
|
||||||
|
ctx->event_callback(ctx->event_callback_arg, pd->idx, &event);
|
||||||
ret = OSDP_CP_ERR_NONE;
|
ret = OSDP_CP_ERR_NONE;
|
||||||
break;
|
break;
|
||||||
case REPLY_BUSY:
|
case REPLY_BUSY:
|
||||||
|
@ -593,8 +634,8 @@ static void cp_flush_command_queue(struct osdp_pd *pd)
|
||||||
{
|
{
|
||||||
struct osdp_cmd *cmd;
|
struct osdp_cmd *cmd;
|
||||||
|
|
||||||
while (osdp_cmd_dequeue(pd, &cmd) == 0) {
|
while (cp_cmd_dequeue(pd, &cmd) == 0) {
|
||||||
osdp_cmd_free(pd, cmd);
|
cp_cmd_free(pd, cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -638,13 +679,13 @@ static int cp_phy_state_update(struct osdp_pd *pd)
|
||||||
ret = OSDP_CP_ERR_GENERIC;
|
ret = OSDP_CP_ERR_GENERIC;
|
||||||
break;
|
break;
|
||||||
case OSDP_CP_PHY_STATE_IDLE:
|
case OSDP_CP_PHY_STATE_IDLE:
|
||||||
if (osdp_cmd_dequeue(pd, &cmd)) {
|
if (cp_cmd_dequeue(pd, &cmd)) {
|
||||||
ret = OSDP_CP_ERR_NONE; /* command queue is empty */
|
ret = OSDP_CP_ERR_NONE; /* command queue is empty */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pd->cmd_id = cmd->id;
|
pd->cmd_id = cmd->id;
|
||||||
memcpy(pd->cmd_data, cmd, sizeof(struct osdp_cmd));
|
memcpy(pd->cmd_data, cmd, sizeof(struct osdp_cmd));
|
||||||
osdp_cmd_free(pd, cmd);
|
cp_cmd_free(pd, cmd);
|
||||||
/* fall-thru */
|
/* fall-thru */
|
||||||
case OSDP_CP_PHY_STATE_SEND_CMD:
|
case OSDP_CP_PHY_STATE_SEND_CMD:
|
||||||
if ((cp_send_command(pd)) < 0) {
|
if ((cp_send_command(pd)) < 0) {
|
||||||
|
@ -708,13 +749,13 @@ static int cp_cmd_dispatcher(struct osdp_pd *pd, int cmd)
|
||||||
return OSDP_CP_ERR_NONE; /* nothing to be done here */
|
return OSDP_CP_ERR_NONE; /* nothing to be done here */
|
||||||
}
|
}
|
||||||
|
|
||||||
c = osdp_cmd_alloc(pd);
|
c = cp_cmd_alloc(pd);
|
||||||
if (c == NULL) {
|
if (c == NULL) {
|
||||||
return OSDP_CP_ERR_GENERIC;
|
return OSDP_CP_ERR_GENERIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
c->id = cmd;
|
c->id = cmd;
|
||||||
osdp_cmd_enqueue(pd, c);
|
cp_cmd_enqueue(pd, c);
|
||||||
SET_FLAG(pd, PD_FLAG_AWAIT_RESP);
|
SET_FLAG(pd, PD_FLAG_AWAIT_RESP);
|
||||||
return OSDP_CP_ERR_INPROG;
|
return OSDP_CP_ERR_INPROG;
|
||||||
}
|
}
|
||||||
|
@ -885,13 +926,13 @@ static int osdp_cp_send_command_keyset(struct osdp_cmd_keyset *cmd)
|
||||||
|
|
||||||
for (i = 0; i < NUM_PD(ctx); i++) {
|
for (i = 0; i < NUM_PD(ctx); i++) {
|
||||||
pd = osdp_to_pd(ctx, i);
|
pd = osdp_to_pd(ctx, i);
|
||||||
p = osdp_cmd_alloc(pd);
|
p = cp_cmd_alloc(pd);
|
||||||
if (p == NULL) {
|
if (p == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
p->id = CMD_KEYSET;
|
p->id = CMD_KEYSET;
|
||||||
memcpy(&p->keyset, &cmd, sizeof(struct osdp_cmd_keyset));
|
memcpy(&p->keyset, &cmd, sizeof(struct osdp_cmd_keyset));
|
||||||
osdp_cmd_enqueue(pd, p);
|
cp_cmd_enqueue(pd, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -925,23 +966,12 @@ int osdp_setup(struct osdp *ctx, uint8_t *key)
|
||||||
|
|
||||||
/* --- Exported Methods --- */
|
/* --- Exported Methods --- */
|
||||||
|
|
||||||
int osdp_cp_set_callback_key_press(int (*cb)(int address, uint8_t key))
|
void osdp_cp_set_event_callback(cp_event_callback_t cb, void *arg)
|
||||||
{
|
{
|
||||||
struct osdp *ctx = osdp_get_ctx();
|
struct osdp *ctx = osdp_get_ctx();
|
||||||
|
|
||||||
ctx->notifier.keypress = cb;
|
ctx->event_callback = cb;
|
||||||
|
ctx->event_callback_arg = arg;
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int osdp_cp_set_callback_card_read(
|
|
||||||
int (*cb)(int address, int format, uint8_t *data, int len))
|
|
||||||
{
|
|
||||||
struct osdp *ctx = osdp_get_ctx();
|
|
||||||
|
|
||||||
ctx->notifier.cardread = cb;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int osdp_cp_send_command(int pd, struct osdp_cmd *cmd)
|
int osdp_cp_send_command(int pd, struct osdp_cmd *cmd)
|
||||||
|
@ -984,12 +1014,12 @@ int osdp_cp_send_command(int pd, struct osdp_cmd *cmd)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
p = osdp_cmd_alloc(osdp_to_pd(ctx, pd));
|
p = cp_cmd_alloc(osdp_to_pd(ctx, pd));
|
||||||
if (p == NULL) {
|
if (p == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
memcpy(p, cmd, sizeof(struct osdp_cmd));
|
memcpy(p, cmd, sizeof(struct osdp_cmd));
|
||||||
p->id = cmd_id; /* translate to internal */
|
p->id = cmd_id; /* translate to internal */
|
||||||
osdp_cmd_enqueue(osdp_to_pd(ctx, pd), p);
|
cp_cmd_enqueue(osdp_to_pd(ctx, pd), p);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,14 +111,93 @@ static struct osdp_pd_cap osdp_pd_cap[] = {
|
||||||
{ -1, 0, 0 } /* Sentinel */
|
{ -1, 0, 0 } /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct osdp_event *pd_event_alloc(struct osdp_pd *pd)
|
||||||
|
{
|
||||||
|
struct osdp_event *event = NULL;
|
||||||
|
|
||||||
|
if (k_mem_slab_alloc(&pd->event.slab, (void **)&event, K_MSEC(100))) {
|
||||||
|
LOG_ERR("Memory allocation time-out");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pd_event_free(struct osdp_pd *pd, struct osdp_event *event)
|
||||||
|
{
|
||||||
|
k_mem_slab_free(&pd->event.slab, (void **)&event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pd_event_enqueue(struct osdp_pd *pd, struct osdp_event *event)
|
||||||
|
{
|
||||||
|
sys_slist_append(&pd->event.queue, &event->node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pd_event_dequeue(struct osdp_pd *pd, struct osdp_event **event)
|
||||||
|
{
|
||||||
|
sys_snode_t *node;
|
||||||
|
|
||||||
|
node = sys_slist_peek_head(&pd->event.queue);
|
||||||
|
if (node == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
sys_slist_remove(&pd->event.queue, NULL, node);
|
||||||
|
*event = CONTAINER_OF(node, struct osdp_event, node);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pd_translate_event(struct osdp_pd *pd, struct osdp_event *event)
|
||||||
|
{
|
||||||
|
int reply_code = 0;
|
||||||
|
|
||||||
|
switch (event->type) {
|
||||||
|
case OSDP_EVENT_CARDREAD:
|
||||||
|
if (event->cardread.format == OSDP_CARD_FMT_RAW_UNSPECIFIED ||
|
||||||
|
event->cardread.format == OSDP_CARD_FMT_RAW_WIEGAND) {
|
||||||
|
reply_code = REPLY_RAW;
|
||||||
|
} else if (event->cardread.format == OSDP_CARD_FMT_ASCII) {
|
||||||
|
reply_code = REPLY_FMT;
|
||||||
|
} else {
|
||||||
|
LOG_ERR("Event: cardread; Error: unknown format");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OSDP_EVENT_KEYPRESS:
|
||||||
|
reply_code = REPLY_KEYPPAD;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_ERR("Unknown event type %d", event->type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (reply_code == 0) {
|
||||||
|
/* POLL command cannot fail even when there are errors here */
|
||||||
|
return REPLY_ACK;
|
||||||
|
}
|
||||||
|
memcpy(pd->cmd_data, event, sizeof(struct osdp_event));
|
||||||
|
return reply_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool do_command_callback(struct osdp_pd *pd, struct osdp_cmd *cmd)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = pd->command_callback(pd->command_callback_arg, cmd);
|
||||||
|
if (ret != 0) {
|
||||||
|
pd->reply_id = REPLY_NAK;
|
||||||
|
pd->cmd_data[0] = OSDP_PD_NAK_RECORD;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static int pd_decode_command(struct osdp_pd *pd, uint8_t *buf, int len)
|
static int pd_decode_command(struct osdp_pd *pd, uint8_t *buf, int len)
|
||||||
{
|
{
|
||||||
int ret = OSDP_PD_ERR_GENERIC;
|
int ret = OSDP_PD_ERR_GENERIC;
|
||||||
int i, pos = 0;
|
int i, pos = 0;
|
||||||
struct osdp_cmd *cmd;
|
struct osdp_cmd cmd;
|
||||||
|
struct osdp_event *event;
|
||||||
|
|
||||||
pd->reply_id = 0;
|
pd->reply_id = 0;
|
||||||
pd->cmd_id = buf[pos++];
|
pd->cmd_id = cmd.id = buf[pos++];
|
||||||
len--;
|
len--;
|
||||||
|
|
||||||
switch (pd->cmd_id) {
|
switch (pd->cmd_id) {
|
||||||
|
@ -126,7 +205,14 @@ static int pd_decode_command(struct osdp_pd *pd, uint8_t *buf, int len)
|
||||||
if (len != CMD_POLL_DATA_LEN) {
|
if (len != CMD_POLL_DATA_LEN) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pd->reply_id = REPLY_ACK;
|
/* Check if we have external events in the queue */
|
||||||
|
if (pd_event_dequeue(pd, &event) == 0) {
|
||||||
|
ret = pd_translate_event(pd, event);
|
||||||
|
pd->reply_id = ret;
|
||||||
|
pd_event_free(pd, event);
|
||||||
|
} else {
|
||||||
|
pd->reply_id = REPLY_ACK;
|
||||||
|
}
|
||||||
ret = OSDP_PD_ERR_NONE;
|
ret = OSDP_PD_ERR_NONE;
|
||||||
break;
|
break;
|
||||||
case CMD_LSTAT:
|
case CMD_LSTAT:
|
||||||
|
@ -174,125 +260,118 @@ static int pd_decode_command(struct osdp_pd *pd, uint8_t *buf, int len)
|
||||||
ret = OSDP_PD_ERR_NONE;
|
ret = OSDP_PD_ERR_NONE;
|
||||||
break;
|
break;
|
||||||
case CMD_OUT:
|
case CMD_OUT:
|
||||||
if (len != CMD_OUT_DATA_LEN) {
|
if (len != CMD_OUT_DATA_LEN || !pd->command_callback) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cmd = osdp_cmd_alloc(pd);
|
cmd.id = OSDP_CMD_OUTPUT;
|
||||||
if (cmd == NULL) {
|
cmd.output.output_no = buf[pos++];
|
||||||
LOG_ERR("cmd alloc error");
|
cmd.output.control_code = buf[pos++];
|
||||||
|
cmd.output.timer_count = buf[pos++];
|
||||||
|
cmd.output.timer_count |= buf[pos++] << 8;
|
||||||
|
ret = OSDP_PD_ERR_REPLY;
|
||||||
|
if (!do_command_callback(pd, &cmd)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cmd->id = OSDP_CMD_OUTPUT;
|
|
||||||
cmd->output.output_no = buf[pos++];
|
|
||||||
cmd->output.control_code = buf[pos++];
|
|
||||||
cmd->output.timer_count = buf[pos++];
|
|
||||||
cmd->output.timer_count |= buf[pos++] << 8;
|
|
||||||
osdp_cmd_enqueue(pd, cmd);
|
|
||||||
pd->reply_id = REPLY_ACK;
|
pd->reply_id = REPLY_ACK;
|
||||||
ret = OSDP_PD_ERR_NONE;
|
ret = OSDP_PD_ERR_NONE;
|
||||||
break;
|
break;
|
||||||
case CMD_LED:
|
case CMD_LED:
|
||||||
if (len != CMD_LED_DATA_LEN) {
|
if (len != CMD_LED_DATA_LEN || !pd->command_callback) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cmd = osdp_cmd_alloc(pd);
|
cmd.id = OSDP_CMD_LED;
|
||||||
if (cmd == NULL) {
|
cmd.led.reader = buf[pos++];
|
||||||
LOG_ERR("cmd alloc error");
|
cmd.led.led_number = buf[pos++];
|
||||||
|
|
||||||
|
cmd.led.temporary.control_code = buf[pos++];
|
||||||
|
cmd.led.temporary.on_count = buf[pos++];
|
||||||
|
cmd.led.temporary.off_count = buf[pos++];
|
||||||
|
cmd.led.temporary.on_color = buf[pos++];
|
||||||
|
cmd.led.temporary.off_color = buf[pos++];
|
||||||
|
cmd.led.temporary.timer_count = buf[pos++];
|
||||||
|
cmd.led.temporary.timer_count |= buf[pos++] << 8;
|
||||||
|
|
||||||
|
cmd.led.permanent.control_code = buf[pos++];
|
||||||
|
cmd.led.permanent.on_count = buf[pos++];
|
||||||
|
cmd.led.permanent.off_count = buf[pos++];
|
||||||
|
cmd.led.permanent.on_color = buf[pos++];
|
||||||
|
cmd.led.permanent.off_color = buf[pos++];
|
||||||
|
ret = OSDP_PD_ERR_REPLY;
|
||||||
|
if (!do_command_callback(pd, &cmd)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cmd->id = OSDP_CMD_LED;
|
|
||||||
cmd->led.reader = buf[pos++];
|
|
||||||
cmd->led.led_number = buf[pos++];
|
|
||||||
|
|
||||||
cmd->led.temporary.control_code = buf[pos++];
|
|
||||||
cmd->led.temporary.on_count = buf[pos++];
|
|
||||||
cmd->led.temporary.off_count = buf[pos++];
|
|
||||||
cmd->led.temporary.on_color = buf[pos++];
|
|
||||||
cmd->led.temporary.off_color = buf[pos++];
|
|
||||||
cmd->led.temporary.timer_count = buf[pos++];
|
|
||||||
cmd->led.temporary.timer_count |= buf[pos++] << 8;
|
|
||||||
|
|
||||||
cmd->led.permanent.control_code = buf[pos++];
|
|
||||||
cmd->led.permanent.on_count = buf[pos++];
|
|
||||||
cmd->led.permanent.off_count = buf[pos++];
|
|
||||||
cmd->led.permanent.on_color = buf[pos++];
|
|
||||||
cmd->led.permanent.off_color = buf[pos++];
|
|
||||||
osdp_cmd_enqueue(pd, cmd);
|
|
||||||
pd->reply_id = REPLY_ACK;
|
pd->reply_id = REPLY_ACK;
|
||||||
ret = OSDP_PD_ERR_NONE;
|
ret = OSDP_PD_ERR_NONE;
|
||||||
break;
|
break;
|
||||||
case CMD_BUZ:
|
case CMD_BUZ:
|
||||||
if (len != CMD_BUZ_DATA_LEN) {
|
if (len != CMD_BUZ_DATA_LEN || !pd->command_callback) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cmd = osdp_cmd_alloc(pd);
|
cmd.id = OSDP_CMD_BUZZER;
|
||||||
if (cmd == NULL) {
|
cmd.buzzer.reader = buf[pos++];
|
||||||
LOG_ERR("cmd alloc error");
|
cmd.buzzer.control_code = buf[pos++];
|
||||||
|
cmd.buzzer.on_count = buf[pos++];
|
||||||
|
cmd.buzzer.off_count = buf[pos++];
|
||||||
|
cmd.buzzer.rep_count = buf[pos++];
|
||||||
|
ret = OSDP_PD_ERR_REPLY;
|
||||||
|
if (!do_command_callback(pd, &cmd)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cmd->id = OSDP_CMD_BUZZER;
|
|
||||||
cmd->buzzer.reader = buf[pos++];
|
|
||||||
cmd->buzzer.control_code = buf[pos++];
|
|
||||||
cmd->buzzer.on_count = buf[pos++];
|
|
||||||
cmd->buzzer.off_count = buf[pos++];
|
|
||||||
cmd->buzzer.rep_count = buf[pos++];
|
|
||||||
osdp_cmd_enqueue(pd, cmd);
|
|
||||||
pd->reply_id = REPLY_ACK;
|
pd->reply_id = REPLY_ACK;
|
||||||
ret = OSDP_PD_ERR_NONE;
|
ret = OSDP_PD_ERR_NONE;
|
||||||
break;
|
break;
|
||||||
case CMD_TEXT:
|
case CMD_TEXT:
|
||||||
if (len < CMD_TEXT_DATA_LEN) {
|
if (len < CMD_TEXT_DATA_LEN || !pd->command_callback) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cmd = osdp_cmd_alloc(pd);
|
cmd.id = OSDP_CMD_TEXT;
|
||||||
if (cmd == NULL) {
|
cmd.text.reader = buf[pos++];
|
||||||
LOG_ERR("cmd alloc error");
|
cmd.text.control_code = buf[pos++];
|
||||||
|
cmd.text.temp_time = buf[pos++];
|
||||||
|
cmd.text.offset_row = buf[pos++];
|
||||||
|
cmd.text.offset_col = buf[pos++];
|
||||||
|
cmd.text.length = buf[pos++];
|
||||||
|
if (cmd.text.length > OSDP_CMD_TEXT_MAX_LEN ||
|
||||||
|
((len - CMD_TEXT_DATA_LEN) < cmd.text.length) ||
|
||||||
|
cmd.text.length > OSDP_CMD_TEXT_MAX_LEN) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cmd->id = OSDP_CMD_TEXT;
|
for (i = 0; i < cmd.text.length; i++) {
|
||||||
cmd->text.reader = buf[pos++];
|
cmd.text.data[i] = buf[pos++];
|
||||||
cmd->text.control_code = buf[pos++];
|
}
|
||||||
cmd->text.temp_time = buf[pos++];
|
ret = OSDP_PD_ERR_REPLY;
|
||||||
cmd->text.offset_row = buf[pos++];
|
if (!do_command_callback(pd, &cmd)) {
|
||||||
cmd->text.offset_col = buf[pos++];
|
|
||||||
cmd->text.length = buf[pos++];
|
|
||||||
if (cmd->text.length > OSDP_CMD_TEXT_MAX_LEN ||
|
|
||||||
((len - CMD_TEXT_DATA_LEN) < cmd->text.length) ||
|
|
||||||
cmd->text.length > OSDP_CMD_TEXT_MAX_LEN) {
|
|
||||||
osdp_cmd_free(pd, cmd);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
for (i = 0; i < cmd->text.length; i++) {
|
|
||||||
cmd->text.data[i] = buf[pos++];
|
|
||||||
}
|
|
||||||
osdp_cmd_enqueue(pd, cmd);
|
|
||||||
pd->reply_id = REPLY_ACK;
|
pd->reply_id = REPLY_ACK;
|
||||||
ret = OSDP_PD_ERR_NONE;
|
ret = OSDP_PD_ERR_NONE;
|
||||||
break;
|
break;
|
||||||
case CMD_COMSET:
|
case CMD_COMSET:
|
||||||
if (len != CMD_COMSET_DATA_LEN) {
|
if (len != CMD_COMSET_DATA_LEN || !pd->command_callback) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cmd = osdp_cmd_alloc(pd);
|
cmd.id = OSDP_CMD_COMSET;
|
||||||
if (cmd == NULL) {
|
cmd.comset.address = buf[pos++];
|
||||||
LOG_ERR("cmd alloc error");
|
cmd.comset.baud_rate = buf[pos++];
|
||||||
break;
|
cmd.comset.baud_rate |= buf[pos++] << 8;
|
||||||
}
|
cmd.comset.baud_rate |= buf[pos++] << 16;
|
||||||
cmd->id = OSDP_CMD_COMSET;
|
cmd.comset.baud_rate |= buf[pos++] << 24;
|
||||||
cmd->comset.address = buf[pos++];
|
if (cmd.comset.address >= 0x7F ||
|
||||||
cmd->comset.baud_rate = buf[pos++];
|
(cmd.comset.baud_rate != 9600 &&
|
||||||
cmd->comset.baud_rate |= buf[pos++] << 8;
|
cmd.comset.baud_rate != 19200 &&
|
||||||
cmd->comset.baud_rate |= buf[pos++] << 16;
|
cmd.comset.baud_rate != 38400 &&
|
||||||
cmd->comset.baud_rate |= buf[pos++] << 24;
|
cmd.comset.baud_rate != 115200 &&
|
||||||
if (cmd->comset.address >= 0x7F ||
|
cmd.comset.baud_rate != 230400)) {
|
||||||
(cmd->comset.baud_rate != 9600 &&
|
|
||||||
cmd->comset.baud_rate != 38400 &&
|
|
||||||
cmd->comset.baud_rate != 115200)) {
|
|
||||||
LOG_ERR("COMSET Failed! command discarded");
|
LOG_ERR("COMSET Failed! command discarded");
|
||||||
cmd->comset.address = pd->address;
|
cmd.comset.address = pd->address;
|
||||||
cmd->comset.baud_rate = pd->baud_rate;
|
cmd.comset.baud_rate = pd->baud_rate;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
osdp_cmd_enqueue(pd, cmd);
|
if (!do_command_callback(pd, &cmd)) {
|
||||||
|
ret = OSDP_PD_ERR_REPLY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
memcpy(pd->cmd_data, &cmd, sizeof(struct osdp_cmd));
|
||||||
pd->reply_id = REPLY_COM;
|
pd->reply_id = REPLY_COM;
|
||||||
ret = OSDP_PD_ERR_NONE;
|
ret = OSDP_PD_ERR_NONE;
|
||||||
break;
|
break;
|
||||||
|
@ -317,17 +396,18 @@ static int pd_decode_command(struct osdp_pd *pd, uint8_t *buf, int len)
|
||||||
buf[pos], buf[pos + 1]);
|
buf[pos], buf[pos + 1]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cmd = osdp_cmd_alloc(pd);
|
cmd.id = OSDP_CMD_KEYSET;
|
||||||
if (cmd == NULL) {
|
cmd.keyset.type = buf[pos++];
|
||||||
LOG_ERR("cmd alloc error");
|
cmd.keyset.length = buf[pos++];
|
||||||
|
memcpy(cmd.keyset.data, buf + pos, 16);
|
||||||
|
if (!pd->command_callback) {
|
||||||
|
LOG_ERR("Keyset without a command callback! The SC new "
|
||||||
|
"SCBK will be lost when the PD reboots.");
|
||||||
|
} else if (!do_command_callback(pd, &cmd)) {
|
||||||
|
ret = OSDP_PD_ERR_REPLY;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cmd->id = OSDP_CMD_KEYSET;
|
memcpy(pd->sc.scbk, cmd.keyset.data, 16);
|
||||||
cmd->keyset.type = buf[pos++];
|
|
||||||
cmd->keyset.length = buf[pos++];
|
|
||||||
memcpy(cmd->keyset.data, buf + pos, 16);
|
|
||||||
memcpy(pd->sc.scbk, buf + pos, 16);
|
|
||||||
osdp_cmd_enqueue(pd, cmd);
|
|
||||||
CLEAR_FLAG(pd, PD_FLAG_SC_USE_SCBKD);
|
CLEAR_FLAG(pd, PD_FLAG_SC_USE_SCBKD);
|
||||||
CLEAR_FLAG(pd, PD_FLAG_INSTALL_MODE);
|
CLEAR_FLAG(pd, PD_FLAG_INSTALL_MODE);
|
||||||
pd->reply_id = REPLY_ACK;
|
pd->reply_id = REPLY_ACK;
|
||||||
|
@ -479,12 +559,7 @@ static int pd_build_reply(struct osdp_pd *pd, uint8_t *buf, int max_len)
|
||||||
* TODO: Persist pd->address and pd->baud_rate via
|
* TODO: Persist pd->address and pd->baud_rate via
|
||||||
* subsys/settings
|
* subsys/settings
|
||||||
*/
|
*/
|
||||||
cmd = osdp_cmd_get_last(pd);
|
cmd = (struct osdp_cmd *)pd->cmd_data;
|
||||||
if (cmd == NULL || cmd->id != OSDP_CMD_COMSET) {
|
|
||||||
LOG_ERR("Failed to fetch queue tail for COMSET");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf[len++] = pd->reply_id;
|
buf[len++] = pd->reply_id;
|
||||||
buf[len++] = cmd->comset.address;
|
buf[len++] = cmd->comset.address;
|
||||||
buf[len++] = BYTE_0(cmd->comset.baud_rate);
|
buf[len++] = BYTE_0(cmd->comset.baud_rate);
|
||||||
|
@ -771,15 +846,25 @@ int osdp_setup(struct osdp *ctx, uint8_t *key)
|
||||||
|
|
||||||
/* --- Exported Methods --- */
|
/* --- Exported Methods --- */
|
||||||
|
|
||||||
int osdp_pd_get_cmd(struct osdp_cmd *cmd)
|
void osdp_pd_set_command_callback(pd_command_callback_t cb, void *arg)
|
||||||
{
|
{
|
||||||
struct osdp_cmd *c;
|
|
||||||
struct osdp_pd *pd = osdp_to_pd(osdp_get_ctx(), 0);
|
struct osdp_pd *pd = osdp_to_pd(osdp_get_ctx(), 0);
|
||||||
|
|
||||||
if (osdp_cmd_dequeue(pd, &c)) {
|
pd->command_callback_arg = arg;
|
||||||
|
pd->command_callback = cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
int osdp_pd_notify_event(const struct osdp_event *event)
|
||||||
|
{
|
||||||
|
struct osdp_event *ev;
|
||||||
|
struct osdp_pd *pd = osdp_to_pd(osdp_get_ctx(), 0);
|
||||||
|
|
||||||
|
ev = pd_event_alloc(pd);
|
||||||
|
if (ev == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
memcpy(cmd, c, sizeof(struct osdp_cmd));
|
|
||||||
osdp_cmd_free(pd, c);
|
memcpy(ev, event, sizeof(struct osdp_event));
|
||||||
|
pd_event_enqueue(pd, ev);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue